-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
147 lines (126 loc) · 3.94 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
'use strict';
var has = Object.prototype.hasOwnProperty
, qs = require('querystringify')
, destroy = require('demolish');
/**
* Handshake handler.
*
* Options:
*
* - `sync` The properties of the handshake that should be synced in the store.
* Defaults to `id`
* - `store` Storage system which will hold all the things. Defaults to
* sessionStorage
* - `prefix` Prefix for the keys that are stored to prevent possible
* collisions. Defaults to `unshift`
* - `parse` First phase response parser function. Defaults to `qs.parse`.
*
* @constructor
* @param {Mixed} context Context for the handshakes
* @param {Object} options Configuration.
* @api public
*/
function Handshaking(context, options) {
var unshift = this
, prefix
, store
, sync;
if (!(unshift instanceof Handshaking)) return new Handshaking(context, options);
options = options || {};
sync = unshift.sync = (options.sync || 'id').split(/[\,|\s]+/);
store = unshift.store = options.store || Handshaking.store;
prefix = unshift.prefix = options.prefix || 'unshift';
unshift.parser = options.parse || qs.parse;
unshift.context = context || unshift;
unshift.configuration = {};
unshift.data = {};
for (var i = 0; i < sync.length; i++) {
unshift.data[sync[i]] = store.getItem(prefix +':'+ sync[i]);
}
}
/**
* Add a new value parser for the handshake response.
*
* @param {String} key Property that we need to parse.
* @param {Function} parser
* @returns {Handshaking}
* @api public
*/
Handshaking.prototype.set = function set(key, parser) {
this.configuration[key] = parser;
return this;
};
/**
* Return the data from a previous handshake.
*
* @param {String} key The property that should be returned.
* @returns {Mixed}
* @api public
*/
Handshaking.prototype.get = function get(key) {
return this.data[key];
};
/**
* Parse the data from the handshake.
*
* @param {String} data Data that needs to be parsed.
* @param {Function} fn Parser completion function.
* @returns {Handshaking}
* @api public
*/
Handshaking.prototype.parse = function parse(data, fn) {
var key
, unshift = this
, sync = unshift.sync
, store = unshift.store
, prefix = unshift.prefix;
try { data = unshift.parser(data); }
catch (e) { return fn.call(unshift.context, e), unshift; }
for (key in data) {
if (!has.call(unshift.configuration, key)) continue;
data[key] = unshift.configuration[key].call(unshift.context, data[key], data);
}
//
// Always remove the id we will re-set it with a new id if needed.
//
unshift.store.removeItem(prefix +':id');
if ('error' in data) {
return fn.call(unshift.context, new Error(data.error)), unshift;
}
for (var i = 0; i < sync.length; i++) {
if (has.call(data, sync[i])) {
store.setItem(prefix +':'+ sync[i], data[sync[i]]);
}
}
unshift.data = data;
fn.call(unshift.context, undefined, data);
return unshift;
};
/**
* Destroy the complete handshaking instance so we can be reclaimed by garbage
* collection.
*
* @type {Function}
* @returns {Boolean}
* @api public
*/
Handshaking.prototype.destroy = destroy('sync store prefix parse context configuration data');
/**
* The storage layer where we need to store the session id in. Ideally this is
* stored on the client side until the user closes the window. So we don't
* introduce pointless bandwidth that needs to be transfered on every request.
* The sessionStorage API is ideal for this but is not support in every browser
* and can be disabled in private browsing mode or when cookies are disabled.
* When this is the case we want to use the `window.name` hack and store data in
* there. If this is unavailable for some reason we can store it in a cookie or
* when we run on Node.js where all these methods are unavailable we fallback to
* an empty object.
*
* @type {Object}
* @private
*/
Handshaking.store = require('sessionstorage');
//
// Expose the handshaking interface
//
module.exports = Handshaking;