@qbix/q 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +678 -0
  3. package/dist/Metrics.js +2873 -0
  4. package/dist/Metrics.min.js +95 -0
  5. package/dist/Q.js +15677 -0
  6. package/dist/Q.min.js +385 -0
  7. package/dist/Q.minimal.js +11594 -0
  8. package/dist/Q.minimal.min.js +286 -0
  9. package/dist/handlebars-v4.0.10.min.js +29 -0
  10. package/dist/handlebars.minimal.min.js +1 -0
  11. package/dist/img/hints/rotate-left.gif +0 -0
  12. package/dist/img/hints/swipe-down.gif +0 -0
  13. package/dist/img/hints/swipe-up.gif +0 -0
  14. package/dist/img/hints/tap.gif +0 -0
  15. package/dist/img/throbbers/loading.gif +0 -0
  16. package/dist/jquery.minimal.min.js +18 -0
  17. package/dist/methods/Q/Audio/load.js +29 -0
  18. package/dist/methods/Q/Audio/loadVoices.js +36 -0
  19. package/dist/methods/Q/Audio/play.js +47 -0
  20. package/dist/methods/Q/Audio/speak.js +149 -0
  21. package/dist/methods/Q/Crypto/delegate.js +186 -0
  22. package/dist/methods/Q/Crypto/internalKeypair.js +170 -0
  23. package/dist/methods/Q/Crypto/sign.js +200 -0
  24. package/dist/methods/Q/Crypto/verify.js +212 -0
  25. package/dist/methods/Q/Crypto/verifyDelegated.js +214 -0
  26. package/dist/methods/Q/Data/Bloom/_internal.js +163 -0
  27. package/dist/methods/Q/Data/Bloom/create.js +23 -0
  28. package/dist/methods/Q/Data/Bloom/fromBase64.js +21 -0
  29. package/dist/methods/Q/Data/Bloom/fromBytes.js +15 -0
  30. package/dist/methods/Q/Data/Bloom/fromElements.js +33 -0
  31. package/dist/methods/Q/Data/Merkle/_internal.js +68 -0
  32. package/dist/methods/Q/Data/Merkle/build.js +29 -0
  33. package/dist/methods/Q/Data/Merkle/proof.js +50 -0
  34. package/dist/methods/Q/Data/Merkle/verify.js +32 -0
  35. package/dist/methods/Q/Data/Prolly/_internal.js +190 -0
  36. package/dist/methods/Q/Data/Prolly/build.js +28 -0
  37. package/dist/methods/Q/Data/Prolly/delete.js +28 -0
  38. package/dist/methods/Q/Data/Prolly/diff.js +70 -0
  39. package/dist/methods/Q/Data/Prolly/get.js +38 -0
  40. package/dist/methods/Q/Data/Prolly/set.js +32 -0
  41. package/dist/methods/Q/Data/compress.js +45 -0
  42. package/dist/methods/Q/Data/decompress.js +35 -0
  43. package/dist/methods/Q/Data/decrypt.js +55 -0
  44. package/dist/methods/Q/Data/derive.js +76 -0
  45. package/dist/methods/Q/Data/digest.js +29 -0
  46. package/dist/methods/Q/Data/encrypt.js +61 -0
  47. package/dist/methods/Q/Data/generateKey.js +40 -0
  48. package/dist/methods/Q/Data/hkdf.js +44 -0
  49. package/dist/methods/Q/Data/importKey.js +34 -0
  50. package/dist/methods/Q/Data/sign.js +42 -0
  51. package/dist/methods/Q/Data/verify.js +45 -0
  52. package/dist/methods/Q/Onboarding/handle.js +50 -0
  53. package/dist/methods/Q/Onboarding/start.js +165 -0
  54. package/dist/methods/Q/Onboarding/stop.js +21 -0
  55. package/dist/methods/Q/Sandbox/run.js +392 -0
  56. package/dist/methods/Q/Tool/define/component.js +218 -0
  57. package/dist/methods/Q/globalMemoryWalk.js +82 -0
  58. package/dist/methods/Q/leaves.js +34 -0
  59. package/dist/methods/Q/registerWebComponent.js +0 -0
  60. package/dist/methods/Q/sanitize.js +142 -0
  61. package/dist/test.html +6 -0
  62. package/dist/tools/Q/lazyload.js +433 -0
  63. package/package.json +26 -0
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Shared structural helpers for Q.Data.Merkle method files.
3
+ * Loaded once via options.require and passed as _ to each method file.
4
+ * Crypto (SHA-256) is done via Q.Data.digest, available in closure as Q.
5
+ *
6
+ * Exports a plain object (sync) — no async setup needed here.
7
+ */
8
+ Q.exports(function (Q) {
9
+
10
+ var _ = {
11
+
12
+ /**
13
+ * SHA-256 arbitrary bytes. Returns Promise<Uint8Array(32)>.
14
+ * payload may be Uint8Array or ArrayBuffer.
15
+ */
16
+ sha256: function (payload) {
17
+ return Q.Data.digest('SHA-256', payload);
18
+ },
19
+
20
+ /**
21
+ * Concatenate two Uint8Arrays.
22
+ */
23
+ concat: function (a, b) {
24
+ var out = new Uint8Array(a.length + b.length);
25
+ out.set(a, 0);
26
+ out.set(b, a.length);
27
+ return out;
28
+ },
29
+
30
+ /**
31
+ * Encode Uint8Array to lowercase hex string.
32
+ */
33
+ toHex: function (bytes) {
34
+ return Q.Data.toHex(bytes);
35
+ },
36
+
37
+ /**
38
+ * Hash one level of the tree: pair up nodes, hash each pair.
39
+ * Odd node at end is promoted (paired with itself).
40
+ * nodes: Array<Uint8Array>
41
+ * Returns Promise<Array<Uint8Array>>.
42
+ */
43
+ hashLevel: function (nodes) {
44
+ var pairs = [];
45
+ for (var i = 0; i < nodes.length; i += 2) {
46
+ var left = nodes[i];
47
+ var right = (i + 1 < nodes.length) ? nodes[i + 1] : left;
48
+ pairs.push(_.sha256(_.concat(left, right)));
49
+ }
50
+ return Promise.all(pairs);
51
+ },
52
+
53
+ /**
54
+ * Reduce an array of hash nodes to a single root hash.
55
+ * Returns Promise<Uint8Array(32)>.
56
+ */
57
+ reduce: function (nodes) {
58
+ if (nodes.length === 1) {
59
+ return Promise.resolve(nodes[0]);
60
+ }
61
+ return _.hashLevel(nodes).then(_.reduce);
62
+ }
63
+
64
+ };
65
+
66
+ return _;
67
+
68
+ });
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Q.Data.Merkle.build
3
+ * Build a Merkle tree from an ordered array of leaf values.
4
+ * Each leaf is hashed with SHA-256 first.
5
+ * Returns the root as a hex string.
6
+ *
7
+ * @param {Array<Uint8Array|String>} leaves
8
+ * If strings are passed they are UTF-8 encoded before hashing.
9
+ * @param {Function} [callback] (err, rootHex)
10
+ * @return {Q.Promise<String>}
11
+ */
12
+ Q.exports(function (Q, _) {
13
+
14
+ return Q.promisify(function (leaves, callback) {
15
+ if (!leaves || !leaves.length) {
16
+ return callback(new Error('Q.Data.Merkle.build: no leaves provided'));
17
+ }
18
+
19
+ var enc = new TextEncoder();
20
+
21
+ Promise.all(leaves.map(function (leaf) {
22
+ var bytes = (typeof leaf === 'string') ? enc.encode(leaf) : leaf;
23
+ return _.sha256(bytes);
24
+ })).then(_.reduce).then(function (rootBytes) {
25
+ callback(null, _.toHex(rootBytes));
26
+ }).catch(callback);
27
+ }, false, 1);
28
+
29
+ });
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Q.Data.Merkle.proof
3
+ * Generate a Merkle proof for the leaf at index.
4
+ *
5
+ * @param {Array<Uint8Array|String>} leaves Full ordered leaf array
6
+ * @param {Number} index Leaf index to prove
7
+ * @param {Function} [callback] (err, { proof: Array, rootHex: String })
8
+ * proof is Array<{ hex: String, side: 'left'|'right' }>
9
+ * @return {Q.Promise}
10
+ */
11
+ Q.exports(function (Q, _) {
12
+
13
+ return Q.promisify(function (leaves, index, callback) {
14
+ if (index < 0 || index >= leaves.length) {
15
+ return callback(new Error('Q.Data.Merkle.proof: index out of range'));
16
+ }
17
+
18
+ var enc = new TextEncoder();
19
+
20
+ Promise.all(leaves.map(function (leaf) {
21
+ var bytes = (typeof leaf === 'string') ? enc.encode(leaf) : leaf;
22
+ return _.sha256(bytes);
23
+ })).then(function (hashes) {
24
+ var steps = [];
25
+ var idx = index;
26
+
27
+ function _step(nodes) {
28
+ if (nodes.length === 1) {
29
+ return Promise.resolve(_.toHex(nodes[0]));
30
+ }
31
+ var sibling, side;
32
+ if (idx % 2 === 0) {
33
+ sibling = (idx + 1 < nodes.length) ? nodes[idx + 1] : nodes[idx];
34
+ side = 'right';
35
+ } else {
36
+ sibling = nodes[idx - 1];
37
+ side = 'left';
38
+ }
39
+ steps.push({ hex: _.toHex(sibling), side: side });
40
+ idx = Math.floor(idx / 2);
41
+ return _.hashLevel(nodes).then(_step);
42
+ }
43
+
44
+ return _step(hashes).then(function (rootHex) {
45
+ callback(null, { proof: steps, rootHex: rootHex });
46
+ });
47
+ }).catch(callback);
48
+ }, false, 2);
49
+
50
+ });
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Q.Data.Merkle.verify
3
+ * Verify a Merkle proof for a leaf against a known root.
4
+ *
5
+ * @param {Uint8Array|String} leaf The leaf being verified
6
+ * @param {Array} proof Array<{ hex: String, side: 'left'|'right' }>
7
+ * @param {String} rootHex Expected root as hex string
8
+ * @param {Function} [callback] (err, Boolean)
9
+ * @return {Q.Promise<Boolean>}
10
+ */
11
+ Q.exports(function (Q, _) {
12
+
13
+ return Q.promisify(function (leaf, proof, rootHex, callback) {
14
+ var enc = new TextEncoder();
15
+ var bytes = (typeof leaf === 'string') ? enc.encode(leaf) : leaf;
16
+
17
+ _.sha256(bytes).then(function (current) {
18
+ return proof.reduce(function (chain, step) {
19
+ return chain.then(function (cur) {
20
+ var sibling = Q.Data.fromHex(step.hex);
21
+ var pair = (step.side === 'left')
22
+ ? _.concat(sibling, cur)
23
+ : _.concat(cur, sibling);
24
+ return _.sha256(pair);
25
+ });
26
+ }, Promise.resolve(current));
27
+ }).then(function (computedRoot) {
28
+ callback(null, _.toHex(computedRoot) === rootHex);
29
+ }).catch(callback);
30
+ }, false, 3);
31
+
32
+ });
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Shared structural helpers for Q.Data.Prolly method files.
3
+ * Loaded once via options.require and passed as _ to each method file.
4
+ *
5
+ * Also sets Q.Data.Prolly.defaultStore once loaded.
6
+ *
7
+ * Exports a plain object (sync).
8
+ */
9
+ Q.exports(function (Q) {
10
+
11
+ // -------------------------------------------------------------------------
12
+ // Constants
13
+ // -------------------------------------------------------------------------
14
+
15
+ // Average ~16 keys per node. Boundary when SHA-256(key)[0] < 256/16 = 16.
16
+ var BRANCHING_FACTOR = 16;
17
+ var BOUNDARY_BYTE = Math.floor(256 / BRANCHING_FACTOR); // 16
18
+
19
+ // -------------------------------------------------------------------------
20
+ // In-memory default store
21
+ // -------------------------------------------------------------------------
22
+
23
+ var _mem = {};
24
+ var defaultStore = {
25
+ get: function (hash) { return Promise.resolve(_mem[hash] || null); },
26
+ put: function (hash, node) { _mem[hash] = node; return Promise.resolve(); }
27
+ };
28
+
29
+ // -------------------------------------------------------------------------
30
+ // Helpers
31
+ // -------------------------------------------------------------------------
32
+
33
+ var _ = {
34
+
35
+ BOUNDARY_BYTE: BOUNDARY_BYTE,
36
+ defaultStore: defaultStore,
37
+
38
+ /**
39
+ * SHA-256 arbitrary bytes. Returns Promise<Uint8Array(32)>.
40
+ */
41
+ sha256: function (payload) {
42
+ return Q.Data.digest('SHA-256', payload);
43
+ },
44
+
45
+ /**
46
+ * Hex-encode a Uint8Array.
47
+ */
48
+ toHex: function (bytes) {
49
+ return Q.Data.toHex(bytes);
50
+ },
51
+
52
+ /**
53
+ * A key is a chunk boundary when SHA-256(key)[0] < BOUNDARY_BYTE.
54
+ * Returns Promise<Boolean>.
55
+ */
56
+ isBoundary: function (key) {
57
+ return _.sha256(new TextEncoder().encode(key)).then(function (digest) {
58
+ return digest[0] < BOUNDARY_BYTE;
59
+ });
60
+ },
61
+
62
+ /**
63
+ * Sort entries by key, lexicographic.
64
+ */
65
+ sortEntries: function (entries) {
66
+ return entries.slice().sort(function (a, b) {
67
+ return a.key < b.key ? -1 : (a.key > b.key ? 1 : 0);
68
+ });
69
+ },
70
+
71
+ /**
72
+ * Serialise a node to JSON, SHA-256 it, return hex hash.
73
+ * Returns Promise<String>.
74
+ */
75
+ nodeHash: function (node) {
76
+ var bytes = new TextEncoder().encode(JSON.stringify(node));
77
+ return _.sha256(bytes).then(_.toHex);
78
+ },
79
+
80
+ /**
81
+ * Store a node and return { hash, node }.
82
+ */
83
+ storeNode: function (store, node) {
84
+ return _.nodeHash(node).then(function (hash) {
85
+ return store.put(hash, node).then(function () {
86
+ return { hash: hash, node: node };
87
+ });
88
+ });
89
+ },
90
+
91
+ /**
92
+ * Build leaf nodes from sorted entries, splitting at boundary keys.
93
+ * Returns Promise<Array<{ hash, node }>>.
94
+ */
95
+ buildLeaves: function (entries, store) {
96
+ return Promise.all(entries.map(function (e) {
97
+ return _.isBoundary(e.key);
98
+ })).then(function (boundaries) {
99
+ var nodes = [];
100
+ var current = { keys: [], values: [], isLeaf: true };
101
+ for (var i = 0; i < entries.length; i++) {
102
+ current.keys.push(entries[i].key);
103
+ current.values.push(entries[i].value);
104
+ var isLast = (i === entries.length - 1);
105
+ if ((boundaries[i] && current.keys.length > 1) || isLast) {
106
+ nodes.push(Q.copy(current));
107
+ current = { keys: [], values: [], isLeaf: true };
108
+ }
109
+ }
110
+ return Promise.all(nodes.map(function (node) {
111
+ return _.storeNode(store, node);
112
+ }));
113
+ });
114
+ },
115
+
116
+ /**
117
+ * Build one internal level from child { hash, node } pairs.
118
+ * Returns Promise<Array<{ hash, node }>>.
119
+ */
120
+ buildInternal: function (children, store) {
121
+ return Promise.all(children.map(function (child) {
122
+ var lastKey = child.node.keys[child.node.keys.length - 1];
123
+ return _.isBoundary(lastKey).then(function (b) {
124
+ return { child: child, isBoundary: b };
125
+ });
126
+ })).then(function (items) {
127
+ var nodes = [];
128
+ var current = { keys: [], children: [], isLeaf: false };
129
+ for (var i = 0; i < items.length; i++) {
130
+ var lastKey = items[i].child.node.keys[items[i].child.node.keys.length - 1];
131
+ current.keys.push(lastKey);
132
+ current.children.push(items[i].child.hash);
133
+ var isLast = (i === items.length - 1);
134
+ if ((items[i].isBoundary && current.keys.length > 1) || isLast) {
135
+ nodes.push(Q.copy(current));
136
+ current = { keys: [], children: [], isLeaf: false };
137
+ }
138
+ }
139
+ return Promise.all(nodes.map(function (node) {
140
+ return _.storeNode(store, node);
141
+ }));
142
+ });
143
+ },
144
+
145
+ /**
146
+ * Reduce levels to a single root hash.
147
+ * Returns Promise<String>.
148
+ */
149
+ reduceLevel: function (nodes, store) {
150
+ if (nodes.length === 1) {
151
+ return Promise.resolve(nodes[0].hash);
152
+ }
153
+ return _.buildInternal(nodes, store).then(function (level) {
154
+ return _.reduceLevel(level, store);
155
+ });
156
+ },
157
+
158
+ /**
159
+ * Collect all { key, value } entries from a subtree.
160
+ * Returns Promise<Array<{ key, value }>>.
161
+ */
162
+ collectAll: function (hash, store) {
163
+ if (!hash) {
164
+ return Promise.resolve([]);
165
+ }
166
+ return store.get(hash).then(function (node) {
167
+ if (!node) {
168
+ return [];
169
+ }
170
+ if (node.isLeaf) {
171
+ return node.keys.map(function (k, i) {
172
+ return { key: k, value: node.values[i] };
173
+ });
174
+ }
175
+ return Promise.all(node.children.map(function (childHash) {
176
+ return _.collectAll(childHash, store);
177
+ })).then(function (sets) {
178
+ return [].concat.apply([], sets);
179
+ });
180
+ });
181
+ }
182
+
183
+ };
184
+
185
+ // Expose defaultStore on Q.Data.Prolly once this is loaded
186
+ Q.Data.Prolly.defaultStore = defaultStore;
187
+
188
+ return _;
189
+
190
+ });
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Q.Data.Prolly.build
3
+ * Build a Prolly tree from an array of { key, value } entries.
4
+ * Entries are sorted by key before insertion.
5
+ * Returns the root hash as a hex string.
6
+ *
7
+ * @param {Array} entries [{ key: String, value: String }]
8
+ * @param {Object} [store] { get(hash), put(hash, node) } -> Promise
9
+ * @param {Function} [callback] (err, rootHex)
10
+ * @return {Q.Promise<String>}
11
+ */
12
+ Q.exports(function (Q, _) {
13
+
14
+ return Q.promisify(function (entries, store, callback) {
15
+ if (typeof store === 'function') { callback = store; store = null; }
16
+ store = store || _.defaultStore;
17
+
18
+ if (!entries || !entries.length) {
19
+ return callback(new Error('Q.Data.Prolly.build: no entries provided'));
20
+ }
21
+
22
+ _.buildLeaves(_.sortEntries(entries), store)
23
+ .then(function (level) { return _.reduceLevel(level, store); })
24
+ .then(function (rootHash) { callback(null, rootHash); })
25
+ .catch(callback);
26
+ }, false, 2);
27
+
28
+ });
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Q.Data.Prolly.delete
3
+ * Remove a key. Returns new root hash, or null for an empty tree.
4
+ *
5
+ * @param {String} rootHash
6
+ * @param {String} key
7
+ * @param {Object} [store]
8
+ * @param {Function} [callback] (err, newRootHash|null)
9
+ * @return {Q.Promise<String|null>}
10
+ */
11
+ Q.exports(function (Q, _) {
12
+
13
+ return Q.promisify(function (rootHash, key, store, callback) {
14
+ if (typeof store === 'function') { callback = store; store = null; }
15
+ store = store || _.defaultStore;
16
+
17
+ _.collectAll(rootHash, store).then(function (entries) {
18
+ var filtered = entries.filter(function (e) { return e.key !== key; });
19
+ if (!filtered.length) {
20
+ return Promise.resolve(null);
21
+ }
22
+ return Q.Data.Prolly.build(filtered, store);
23
+ }).then(function (newRootHash) {
24
+ callback(null, newRootHash);
25
+ }).catch(callback);
26
+ }, false, 3);
27
+
28
+ });
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Q.Data.Prolly.diff
3
+ * Compute the diff between two trees.
4
+ * Subtrees with equal hashes are skipped entirely (structural sharing).
5
+ * Returns [{ key, before: value|null, after: value|null }] sorted by key.
6
+ *
7
+ * @param {String} rootHashA "Before" tree
8
+ * @param {String} rootHashB "After" tree
9
+ * @param {Object} [store]
10
+ * @param {Function} [callback] (err, Array)
11
+ * @return {Q.Promise}
12
+ */
13
+ Q.exports(function (Q, _) {
14
+
15
+ return Q.promisify(function (rootHashA, rootHashB, store, callback) {
16
+ if (typeof store === 'function') { callback = store; store = null; }
17
+ store = store || _.defaultStore;
18
+
19
+ var changes = [];
20
+
21
+ function _diffMaps(mapA, mapB) {
22
+ Object.keys(Q.extend({}, mapA, mapB)).forEach(function (k) {
23
+ if (mapA[k] !== mapB[k]) {
24
+ changes.push({
25
+ key: k,
26
+ before: mapA[k] !== undefined ? mapA[k] : null,
27
+ after: mapB[k] !== undefined ? mapB[k] : null
28
+ });
29
+ }
30
+ });
31
+ }
32
+
33
+ function _compare(hashA, hashB) {
34
+ if (hashA === hashB) { return Promise.resolve(); }
35
+
36
+ return Promise.all([
37
+ hashA ? store.get(hashA) : Promise.resolve(null),
38
+ hashB ? store.get(hashB) : Promise.resolve(null)
39
+ ]).then(function (nodes) {
40
+ var nodeA = nodes[0];
41
+ var nodeB = nodes[1];
42
+
43
+ if ((!nodeA || nodeA.isLeaf) && (!nodeB || nodeB.isLeaf)) {
44
+ var mapA = {}, mapB = {};
45
+ if (nodeA) { nodeA.keys.forEach(function (k, i) { mapA[k] = nodeA.values[i]; }); }
46
+ if (nodeB) { nodeB.keys.forEach(function (k, i) { mapB[k] = nodeB.values[i]; }); }
47
+ _diffMaps(mapA, mapB);
48
+ return;
49
+ }
50
+
51
+ // Mixed levels or both internal — fall back to full leaf collection
52
+ return Promise.all([
53
+ _.collectAll(hashA, store),
54
+ _.collectAll(hashB, store)
55
+ ]).then(function (sets) {
56
+ var mapA = {}, mapB = {};
57
+ sets[0].forEach(function (e) { mapA[e.key] = e.value; });
58
+ sets[1].forEach(function (e) { mapB[e.key] = e.value; });
59
+ _diffMaps(mapA, mapB);
60
+ });
61
+ });
62
+ }
63
+
64
+ _compare(rootHashA, rootHashB).then(function () {
65
+ changes.sort(function (a, b) { return a.key < b.key ? -1 : 1; });
66
+ callback(null, changes);
67
+ }).catch(callback);
68
+ }, false, 3);
69
+
70
+ });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Q.Data.Prolly.get
3
+ * Look up a key in the tree. Returns value string or null if not found.
4
+ *
5
+ * @param {String} rootHash
6
+ * @param {String} key
7
+ * @param {Object} [store]
8
+ * @param {Function} [callback] (err, String|null)
9
+ * @return {Q.Promise<String|null>}
10
+ */
11
+ Q.exports(function (Q, _) {
12
+
13
+ return Q.promisify(function (rootHash, key, store, callback) {
14
+ if (typeof store === 'function') { callback = store; store = null; }
15
+ store = store || _.defaultStore;
16
+
17
+ function _search(hash) {
18
+ return store.get(hash).then(function (node) {
19
+ if (!node) { return null; }
20
+ if (node.isLeaf) {
21
+ var idx = node.keys.indexOf(key);
22
+ return idx >= 0 ? node.values[idx] : null;
23
+ }
24
+ // First separator key >= search key -> descend into that child
25
+ var childIdx = node.keys.length - 1;
26
+ for (var i = 0; i < node.keys.length; i++) {
27
+ if (key <= node.keys[i]) { childIdx = i; break; }
28
+ }
29
+ return _search(node.children[childIdx]);
30
+ });
31
+ }
32
+
33
+ _search(rootHash)
34
+ .then(function (value) { callback(null, value); })
35
+ .catch(callback);
36
+ }, false, 3);
37
+
38
+ });
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Q.Data.Prolly.set
3
+ * Insert or update a key-value pair. Returns new root hash.
4
+ * v1: full rebuild. TODO v2: path-only O(log n).
5
+ *
6
+ * @param {String} rootHash
7
+ * @param {String} key
8
+ * @param {String} value
9
+ * @param {Object} [store]
10
+ * @param {Function} [callback] (err, newRootHash)
11
+ * @return {Q.Promise<String>}
12
+ */
13
+ Q.exports(function (Q, _) {
14
+
15
+ return Q.promisify(function (rootHash, key, value, store, callback) {
16
+ if (typeof store === 'function') { callback = store; store = null; }
17
+ store = store || _.defaultStore;
18
+
19
+ _.collectAll(rootHash, store).then(function (entries) {
20
+ var found = false;
21
+ var updated = entries.map(function (e) {
22
+ if (e.key === key) { found = true; return { key: key, value: value }; }
23
+ return e;
24
+ });
25
+ if (!found) { updated.push({ key: key, value: value }); }
26
+ return Q.Data.Prolly.build(updated, store);
27
+ }).then(function (newRootHash) {
28
+ callback(null, newRootHash);
29
+ }).catch(callback);
30
+ }, false, 4);
31
+
32
+ });
@@ -0,0 +1,45 @@
1
+ Q.exports(function (Q) {
2
+ /**
3
+ * Q plugin's front end code
4
+ *
5
+ * @module Q
6
+ * @class Q.Data
7
+ */
8
+
9
+ /**
10
+ * Compress data with an algorithm.
11
+ * If the data is not a string, then it's stringified as JSON
12
+ * and mimeType is set as application/json.
13
+ * Use it like this: Q.Data.compress(data).then(Q.Data.toBase64);
14
+ * @static
15
+ * @method compress
16
+ * @param {String} data
17
+ * @param {Function} callback
18
+ * @param {Object} options
19
+ * @param {String} [options.algorithm='gzip']
20
+ * @param {String} [options.mimeType] If data was not a string, then it's encoded with
21
+ * @return {Q.Promise} that resolves to an ArrayBuffer
22
+ */
23
+ return function Q_Data_compress(data, callback, options) {
24
+ var algorithm = (options && options.algorithm) || 'gzip';
25
+ var mimeType = (options && options.mimeType);
26
+ return new Q.Promise(function (res) {
27
+ if (typeof data !== 'string') {
28
+ data = JSON.stringify(data);
29
+ mimeType = 'application/json';
30
+ }
31
+ var stream = new Blob([data], {type: mimeType}).stream();
32
+ var compressedReadableStream = stream.pipeThrough(
33
+ new CompressionStream(algorithm)
34
+ );
35
+ var compressedResponse = new Response(compressedReadableStream);
36
+ compressedResponse.blob().then(function (blob) {
37
+ return blob.arrayBuffer();
38
+ }).then(function (buffer) {
39
+ callback && callback(buffer);
40
+ res(buffer);
41
+ });
42
+ });
43
+ };
44
+
45
+ });
@@ -0,0 +1,35 @@
1
+ Q.exports(function (Q) {
2
+ /**
3
+ * Q plugin's front end code
4
+ *
5
+ * @module Q
6
+ * @class Q.Data
7
+ */
8
+
9
+ /**
10
+ * Uncompress a blob that was compressed with an algorithm.
11
+ * @static
12
+ * @method decompress
13
+ * @param {ArrayBuffer} buffer
14
+ * @param {Function} callback
15
+ * @param {Object} options
16
+ * @param {String} [options.algorithm='gzip']
17
+ * @return {Q.Promise}
18
+ */
19
+ return function Q_Data_decompress(buffer, callback, options) {
20
+ var algorithm = (options && options.algorithm) || 'gzip';
21
+ return new Q.Promise(function (res) {
22
+ var ds = new DecompressionStream(algorithm);
23
+ var blob = new Blob([buffer]);
24
+ var decompressedStream = blob.stream().pipeThrough(ds);
25
+ var decompressedResponse = new Response(decompressedStream);
26
+ decompressedResponse.blob().then(function (blob) {
27
+ return blob.text();
28
+ }).then(function (text) {
29
+ callback && callback(text);
30
+ res(text);
31
+ });
32
+ });
33
+ };
34
+
35
+ });