@iebh/tera-fy 2.3.1 → 2.3.2
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.
- package/.vscode/settings.json +5 -0
- package/CHANGELOG.md +15 -0
- package/api.md +34 -35
- package/dist/lib/projectFile.d.ts +3 -3
- package/dist/lib/projectFile.js +4 -3
- package/dist/lib/projectFile.js.map +1 -1
- package/dist/lib/syncro/entities.js +11 -10
- package/dist/lib/syncro/entities.js.map +1 -1
- package/dist/lib/syncro/keyed.d.ts +2 -2
- package/dist/lib/syncro/keyed.js +23 -23
- package/dist/lib/syncro/keyed.js.map +1 -1
- package/dist/lib/syncro/syncro.d.ts +15 -13
- package/dist/lib/syncro/syncro.js +84 -59
- package/dist/lib/syncro/syncro.js.map +1 -1
- package/dist/lib/terafy.bootstrapper.d.ts +2 -2
- package/dist/lib/terafy.bootstrapper.js +15 -16
- package/dist/lib/terafy.bootstrapper.js.map +1 -1
- package/dist/lib/terafy.client.d.ts +24 -25
- package/dist/lib/terafy.client.js +50 -48
- package/dist/lib/terafy.client.js.map +1 -1
- package/dist/lib/terafy.proxy.js +4 -2
- package/dist/lib/terafy.proxy.js.map +1 -1
- package/dist/lib/terafy.server.d.ts +21 -7
- package/dist/lib/terafy.server.js +51 -53
- package/dist/lib/terafy.server.js.map +1 -1
- package/dist/plugin.vue2.es2019.js +210 -1224
- package/dist/plugins/base.d.ts +2 -2
- package/dist/plugins/base.js +1 -0
- package/dist/plugins/base.js.map +1 -1
- package/dist/plugins/firebase.d.ts +4 -4
- package/dist/plugins/firebase.js +7 -7
- package/dist/plugins/firebase.js.map +1 -1
- package/dist/plugins/vue2.d.ts +1 -1
- package/dist/plugins/vue2.js +6 -5
- package/dist/plugins/vue2.js.map +1 -1
- package/dist/plugins/vue3.js +6 -5
- package/dist/plugins/vue3.js.map +1 -1
- package/dist/terafy.bootstrapper.es2019.js +2 -2
- package/dist/terafy.bootstrapper.js +2 -2
- package/dist/terafy.es2019.js +2 -2
- package/dist/terafy.js +2 -2
- package/dist/utils/mixin.js +1 -1
- package/dist/utils/mixin.js.map +1 -1
- package/dist/utils/pDefer.d.ts +5 -1
- package/dist/utils/pDefer.js +6 -1
- package/dist/utils/pDefer.js.map +1 -1
- package/dist/utils/pathTools.d.ts +1 -1
- package/dist/utils/pathTools.js +2 -2
- package/dist/utils/pathTools.js.map +1 -1
- package/eslint.config.js +21 -7
- package/lib/projectFile.ts +5 -4
- package/lib/syncro/entities.ts +11 -10
- package/lib/syncro/keyed.ts +24 -24
- package/lib/syncro/syncro.ts +97 -60
- package/lib/terafy.bootstrapper.ts +15 -16
- package/lib/terafy.client.ts +61 -61
- package/lib/terafy.proxy.ts +8 -5
- package/lib/terafy.server.ts +72 -57
- package/package.json +5 -3
- package/plugins/base.ts +3 -2
- package/plugins/firebase.ts +12 -11
- package/plugins/vue2.ts +7 -6
- package/plugins/vue3.ts +6 -5
- package/utils/mixin.ts +1 -1
- package/utils/pDefer.ts +7 -2
- package/utils/pathTools.ts +3 -3
|
@@ -10,7 +10,7 @@ export default class TeraFy {
|
|
|
10
10
|
*
|
|
11
11
|
* @type {Object}
|
|
12
12
|
* @property {String} session Unique session signature for this instance of TeraFy, used to sign server messages, if falsy `getEntropicString(16)` is used to populate
|
|
13
|
-
* @property {Boolean} devMode Operate in Dev-Mode - i.e. force outer refresh when encountering an existing TeraFy instance + be more
|
|
13
|
+
* @property {Boolean} devMode Operate in Dev-Mode - i.e. force outer refresh when encountering an existing TeraFy instance + be more tolerant of weird iframe origins
|
|
14
14
|
* @property {Number} verbosity Verbosity level, the higher the more chatty TeraFY will be. Set to zero to disable all `debug()` call output
|
|
15
15
|
* @property {'detect'|'parent'|'child'|'popup'} mode How to communicate with TERA. 'parent' assumes that the parent of the current document is TERA, 'child' spawns an iFrame and uses TERA there, 'detect' tries parent and switches to `modeFallback` if communication fails
|
|
16
16
|
* @property {String} modeFallback Method to use when all method detection fails
|
|
@@ -19,7 +19,7 @@ export default class TeraFy {
|
|
|
19
19
|
* @property {String} siteUrl The TERA URL to connect to
|
|
20
20
|
* @property {String} restrictOrigin URL to restrict communications to
|
|
21
21
|
* @property {Array<String>} List of sandbox allowables for the embedded if in embed mode
|
|
22
|
-
* @property {Number} handshakeInterval Interval in milliseconds when
|
|
22
|
+
* @property {Number} handshakeInterval Interval in milliseconds when scanning for a handshake
|
|
23
23
|
* @property {Number} handshakeTimeout Interval in milliseconds for when to give up trying to handshake
|
|
24
24
|
* @property {Array<String|Array<String>>} [debugPaths] List of paths (in either dotted or array notation) to enter debugging mode if a change is detected in dev mode e.g. `{debugPaths: ['foo.bar.baz']}`. This really slows down state writes so should only be used for debugging
|
|
25
25
|
*/
|
|
@@ -74,7 +74,7 @@ export default class TeraFy {
|
|
|
74
74
|
plugins: any[];
|
|
75
75
|
/**
|
|
76
76
|
* Active namespaces we are subscribed to
|
|
77
|
-
* Each key is the namespace name with the value as the local reactive \ observer \ object
|
|
77
|
+
* Each key is the namespace name with the value as the local reactive \ observer \ object equivalent
|
|
78
78
|
* The key string is always of the form `${ENTITY}::${ID}` e.g. `projects:1234`
|
|
79
79
|
*
|
|
80
80
|
* @type {Object<Object>}
|
|
@@ -131,7 +131,7 @@ export default class TeraFy {
|
|
|
131
131
|
mountNamespace(name: any): Promise<any>;
|
|
132
132
|
/**
|
|
133
133
|
* @interface
|
|
134
|
-
* Actual namespace mounting function designed to be
|
|
134
|
+
* Actual namespace mounting function designed to be overridden by plugins
|
|
135
135
|
*
|
|
136
136
|
* @param {String} name The alias of the namespace, this should be alphanumeric + hyphens + underscores
|
|
137
137
|
*
|
|
@@ -151,7 +151,7 @@ export default class TeraFy {
|
|
|
151
151
|
unmountNamespace(name: any): void | Promise<void>;
|
|
152
152
|
/**
|
|
153
153
|
* @interface
|
|
154
|
-
* Actual namespace unmounting function designed to be
|
|
154
|
+
* Actual namespace unmounting function designed to be overridden by plugins
|
|
155
155
|
*
|
|
156
156
|
* @param {String} name The name of the namespace to unmount
|
|
157
157
|
*
|
|
@@ -166,11 +166,11 @@ export default class TeraFy {
|
|
|
166
166
|
constructor(options?: any);
|
|
167
167
|
private initPromise;
|
|
168
168
|
/**
|
|
169
|
-
*
|
|
170
|
-
* This function can only be called once and will return the existing init() worker Promise if its called
|
|
169
|
+
* Initialize the TERA client singleton
|
|
170
|
+
* This function can only be called once and will return the existing init() worker Promise if its called against
|
|
171
171
|
*
|
|
172
172
|
* @param {Object} [options] Additional options to merge into `settings` via `set`
|
|
173
|
-
* @returns {Promise<TeraFy>} An eventual promise which will
|
|
173
|
+
* @returns {Promise<TeraFy>} An eventual promise which will resolve with this terafy instance
|
|
174
174
|
*/
|
|
175
175
|
init(options?: any): Promise<TeraFy>;
|
|
176
176
|
/**
|
|
@@ -181,16 +181,16 @@ export default class TeraFy {
|
|
|
181
181
|
*/
|
|
182
182
|
detectMode(): Promise<'parent' | 'child' | 'popup'>;
|
|
183
183
|
/**
|
|
184
|
-
* Find an existing active TERA server OR
|
|
184
|
+
* Find an existing active TERA server OR initialize one
|
|
185
185
|
*
|
|
186
|
-
* @returns {Promise} A promise which will resolve when the loading has completed and we have found a parent TERA instance or
|
|
186
|
+
* @returns {Promise} A promise which will resolve when the loading has completed and we have found a parent TERA instance or initialized a child
|
|
187
187
|
*/
|
|
188
188
|
injectComms(): Promise<void>;
|
|
189
189
|
/**
|
|
190
190
|
* Keep trying to handshake until the target responds
|
|
191
191
|
*
|
|
192
192
|
* @param {Object} [options] Additional options to mutate behaviour
|
|
193
|
-
* @property {Number} [handshakeInterval] Interval in milliseconds when
|
|
193
|
+
* @property {Number} [handshakeInterval] Interval in milliseconds when scanning for a handshake, defaults to global setting
|
|
194
194
|
* @property {Number} [handshakeTimeout] Interval in milliseconds for when to give up trying to handshake, defaults to global setting
|
|
195
195
|
*
|
|
196
196
|
* @returns {Promise} A promise which will either resolve when the handshake is successful OR fail with 'TIMEOUT'
|
|
@@ -199,7 +199,7 @@ export default class TeraFy {
|
|
|
199
199
|
/**
|
|
200
200
|
* Inject a local stylesheet to handle TERA server functionality
|
|
201
201
|
*
|
|
202
|
-
* @returns {Promise} A promise which will resolve when the loading has completed and we have found a parent TERA instance or
|
|
202
|
+
* @returns {Promise} A promise which will resolve when the loading has completed and we have found a parent TERA instance or initialized a child
|
|
203
203
|
*/
|
|
204
204
|
injectStylesheet(): Promise<void>;
|
|
205
205
|
/**
|
|
@@ -245,7 +245,7 @@ export default class TeraFy {
|
|
|
245
245
|
* Include a TeraFy client plugin
|
|
246
246
|
*
|
|
247
247
|
* @param {Function|Object|String} source Either the JS module class, singleton object or URL to fetch it from. Eventually constructed as invoked as `(teraClient:TeraFy, options:Object)`
|
|
248
|
-
* @param {Object} [options] Additional options to mutate behaviour during construction (pass options to init() to
|
|
248
|
+
* @param {Object} [options] Additional options to mutate behaviour during construction (pass options to init() to initialize later options)
|
|
249
249
|
*
|
|
250
250
|
* @returns {TeraFy} This chainable terafy instance
|
|
251
251
|
*/
|
|
@@ -253,8 +253,8 @@ export default class TeraFy {
|
|
|
253
253
|
/**
|
|
254
254
|
* Internal function used by use() to merge an external declared singleton against this object
|
|
255
255
|
*
|
|
256
|
-
* @param {Object} target
|
|
257
|
-
* @param {Object} source
|
|
256
|
+
* @param {Object} target Installed class instance to extend
|
|
257
|
+
* @param {Object} source Initialized source object to extend from
|
|
258
258
|
*/
|
|
259
259
|
mixin(target: any, source: any): void;
|
|
260
260
|
/**
|
|
@@ -279,7 +279,7 @@ export default class TeraFy {
|
|
|
279
279
|
/**
|
|
280
280
|
* Generate random entropic character string in Base64
|
|
281
281
|
*
|
|
282
|
-
* @param {Number} [maxLength=32] Maximum
|
|
282
|
+
* @param {Number} [maxLength=32] Maximum length of the generated string
|
|
283
283
|
* @returns {String}
|
|
284
284
|
*/
|
|
285
285
|
getEntropicString(maxLength?: number): string;
|
|
@@ -291,7 +291,7 @@ export default class TeraFy {
|
|
|
291
291
|
* @property {Date} date Server date
|
|
292
292
|
*/
|
|
293
293
|
/**
|
|
294
|
-
* RPC callback to set the server
|
|
294
|
+
* RPC callback to set the server verbosity level
|
|
295
295
|
*
|
|
296
296
|
* @function setServerVerbosity
|
|
297
297
|
* @param {Number} verbosity The desired server verbosity level
|
|
@@ -309,7 +309,7 @@ export default class TeraFy {
|
|
|
309
309
|
* Fetch the current session user
|
|
310
310
|
*
|
|
311
311
|
* @function getUser
|
|
312
|
-
* @param {Boolean} [options.forceRetry=false]
|
|
312
|
+
* @param {Boolean} [options.forceRetry=false] Forcibly try to refresh the user state
|
|
313
313
|
* @param {Boolean} [options.waitPromises=true] Wait for $auth + $subscriptions to resolve before fetching the user (mainly internal use)
|
|
314
314
|
* @returns {Promise<User>} The current logged in user or null if none
|
|
315
315
|
*/
|
|
@@ -327,7 +327,7 @@ export default class TeraFy {
|
|
|
327
327
|
* @function requireUser
|
|
328
328
|
*
|
|
329
329
|
* @param {Object} [options] Additional options to mutate behaviour
|
|
330
|
-
* @param {Boolean} [options.forceRetry=false]
|
|
330
|
+
* @param {Boolean} [options.forceRetry=false] Forcibly try to refresh the user state
|
|
331
331
|
*
|
|
332
332
|
* @returns {Promise<User>} The current logged in user or null if none
|
|
333
333
|
*/
|
|
@@ -364,7 +364,7 @@ export default class TeraFy {
|
|
|
364
364
|
*/
|
|
365
365
|
/**
|
|
366
366
|
* Ask the user to select a project from those available - if one isn't already active
|
|
367
|
-
* Note that this function will
|
|
367
|
+
* Note that this function will persist in asking the user even if they try to cancel
|
|
368
368
|
*
|
|
369
369
|
* @function requireProject
|
|
370
370
|
* @param {Object} [options] Additional options to mutate behaviour
|
|
@@ -388,7 +388,7 @@ export default class TeraFy {
|
|
|
388
388
|
*/
|
|
389
389
|
/**
|
|
390
390
|
* Get a one-off snapshot of a namespace without mounting it
|
|
391
|
-
* This can be used for simpler apps which don't have their own reactive / observer
|
|
391
|
+
* This can be used for simpler apps which don't have their own reactive / observer equivalent
|
|
392
392
|
*
|
|
393
393
|
* @function getNamespace
|
|
394
394
|
* @param {String} name The alias of the namespace, this should be alphanumeric + hyphens + underscores
|
|
@@ -397,7 +397,7 @@ export default class TeraFy {
|
|
|
397
397
|
*/
|
|
398
398
|
/**
|
|
399
399
|
* Set (or merge by default) a one-off snapshot over an existing namespace
|
|
400
|
-
* This can be used for simpler apps which don't have their own reactive / observer
|
|
400
|
+
* This can be used for simpler apps which don't have their own reactive / observer equivalent and just want to quickly set something
|
|
401
401
|
*
|
|
402
402
|
* @function setNamespace
|
|
403
403
|
* @param {String} name The name of the namespace
|
|
@@ -480,10 +480,9 @@ export default class TeraFy {
|
|
|
480
480
|
* @param {Boolean} [options.allowUpload=true] Allow uploading new files
|
|
481
481
|
* @param {Boolean} [options.allowRefresh=true] Allow the user to manually refresh the file list
|
|
482
482
|
* @param {Boolean} [options.allowDownloadZip=true] Allow the user to download a Zip of all files
|
|
483
|
-
* @param {Boolean} [options.allowCancel=true] Allow cancelling the operation. Will throw `'CANCEL'` as the promise rejection if
|
|
483
|
+
* @param {Boolean} [options.allowCancel=true] Allow cancelling the operation. Will throw `'CANCEL'` as the promise rejection if actioned
|
|
484
484
|
* @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing
|
|
485
485
|
* @param {Boolean} [options.showHiddenFiles=false] Whether hidden data.json files should be shown
|
|
486
|
-
* @param {FileFilters} [options.filter] Optional file filters
|
|
487
486
|
*
|
|
488
487
|
* @returns {Promise<ProjectFile>} The eventually selected file, if in save mode new files are created as stubs
|
|
489
488
|
*/
|
|
@@ -505,7 +504,7 @@ export default class TeraFy {
|
|
|
505
504
|
*
|
|
506
505
|
* @function getProjectFileContents
|
|
507
506
|
* @param {String} [id] File ID to retrieve the contents of
|
|
508
|
-
* @param {Object} [options]
|
|
507
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
509
508
|
* @param {'blob'|'json'} [options.format='blob'] The format to retrieve the file in
|
|
510
509
|
*
|
|
511
510
|
* @returns {*} The file contents in the requested format
|
|
@@ -2,7 +2,6 @@ import { cloneDeep } from 'lodash-es';
|
|
|
2
2
|
import Mitt from 'mitt';
|
|
3
3
|
import { nanoid } from 'nanoid';
|
|
4
4
|
import ProjectFile from './projectFile.js';
|
|
5
|
-
/* globals window, document */
|
|
6
5
|
/**
|
|
7
6
|
* Main Tera-Fy Client (class singleton) to be used in a frontend browser
|
|
8
7
|
*
|
|
@@ -17,7 +16,7 @@ export default class TeraFy {
|
|
|
17
16
|
* @returns {Promise<*>} A promise which resolves when the operation has completed with the remote reply
|
|
18
17
|
*/
|
|
19
18
|
send(message) {
|
|
20
|
-
|
|
19
|
+
const id = nanoid();
|
|
21
20
|
this.acceptPostboxes[id] = {}; // Stub for the deferred promise
|
|
22
21
|
this.acceptPostboxes[id].promise = new Promise((resolve, reject) => {
|
|
23
22
|
Object.assign(this.acceptPostboxes[id], {
|
|
@@ -57,6 +56,7 @@ export default class TeraFy {
|
|
|
57
56
|
throw new Error('Call init() or detectMode() before trying to send data to determine the mode');
|
|
58
57
|
}
|
|
59
58
|
else {
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
60
60
|
throw new Error(`Unknown TERA communication mode "${this.settings.mode}"`);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -91,10 +91,10 @@ export default class TeraFy {
|
|
|
91
91
|
acceptMessage(rawMessage) {
|
|
92
92
|
if (rawMessage.origin == window.location.origin)
|
|
93
93
|
return Promise.resolve(); // Message came from us
|
|
94
|
-
|
|
94
|
+
const message = rawMessage.data;
|
|
95
95
|
if (!message.TERA || !message.id)
|
|
96
96
|
return Promise.resolve(); // Ignore non-TERA signed messages
|
|
97
|
-
this.debug('INFO', 3, '
|
|
97
|
+
this.debug('INFO', 3, 'Received message', message);
|
|
98
98
|
if (message?.action == 'response' && this.acceptPostboxes[message.id]) { // Postbox waiting for reply
|
|
99
99
|
if (message.isError === true) {
|
|
100
100
|
this.acceptPostboxes[message.id].reject(message.response);
|
|
@@ -161,14 +161,14 @@ export default class TeraFy {
|
|
|
161
161
|
}
|
|
162
162
|
/**
|
|
163
163
|
* @interface
|
|
164
|
-
* Actual namespace mounting function designed to be
|
|
164
|
+
* Actual namespace mounting function designed to be overridden by plugins
|
|
165
165
|
*
|
|
166
166
|
* @param {String} name The alias of the namespace, this should be alphanumeric + hyphens + underscores
|
|
167
167
|
*
|
|
168
168
|
* @returns {Promise} A promise which resolves when the mount operation has completed
|
|
169
169
|
*/
|
|
170
170
|
_mountNamespace(name) {
|
|
171
|
-
console.warn(
|
|
171
|
+
console.warn(`teraFy._mountNamespace() for ${name} has not been overridden by a TERA-fy plugin, load one to add this functionality for your preferred framework`);
|
|
172
172
|
throw new Error('teraFy._mountNamespace() is not supported');
|
|
173
173
|
}
|
|
174
174
|
/**
|
|
@@ -188,14 +188,14 @@ export default class TeraFy {
|
|
|
188
188
|
}
|
|
189
189
|
/**
|
|
190
190
|
* @interface
|
|
191
|
-
* Actual namespace unmounting function designed to be
|
|
191
|
+
* Actual namespace unmounting function designed to be overridden by plugins
|
|
192
192
|
*
|
|
193
193
|
* @param {String} name The name of the namespace to unmount
|
|
194
194
|
*
|
|
195
195
|
* @returns {Promise} A promise which resolves when the operation has completed
|
|
196
196
|
*/
|
|
197
197
|
_unmountNamespace(name) {
|
|
198
|
-
console.warn(
|
|
198
|
+
console.warn(`teraFy.unbindNamespace() for ${name} has not been overridden by a TERA-fy plugin, load one to add this functionality for your preferred framework`);
|
|
199
199
|
}
|
|
200
200
|
// }}}
|
|
201
201
|
// Init - constructor(), init(), inject*() {{{
|
|
@@ -210,7 +210,7 @@ export default class TeraFy {
|
|
|
210
210
|
*
|
|
211
211
|
* @type {Object}
|
|
212
212
|
* @property {String} session Unique session signature for this instance of TeraFy, used to sign server messages, if falsy `getEntropicString(16)` is used to populate
|
|
213
|
-
* @property {Boolean} devMode Operate in Dev-Mode - i.e. force outer refresh when encountering an existing TeraFy instance + be more
|
|
213
|
+
* @property {Boolean} devMode Operate in Dev-Mode - i.e. force outer refresh when encountering an existing TeraFy instance + be more tolerant of weird iframe origins
|
|
214
214
|
* @property {Number} verbosity Verbosity level, the higher the more chatty TeraFY will be. Set to zero to disable all `debug()` call output
|
|
215
215
|
* @property {'detect'|'parent'|'child'|'popup'} mode How to communicate with TERA. 'parent' assumes that the parent of the current document is TERA, 'child' spawns an iFrame and uses TERA there, 'detect' tries parent and switches to `modeFallback` if communication fails
|
|
216
216
|
* @property {String} modeFallback Method to use when all method detection fails
|
|
@@ -219,7 +219,7 @@ export default class TeraFy {
|
|
|
219
219
|
* @property {String} siteUrl The TERA URL to connect to
|
|
220
220
|
* @property {String} restrictOrigin URL to restrict communications to
|
|
221
221
|
* @property {Array<String>} List of sandbox allowables for the embedded if in embed mode
|
|
222
|
-
* @property {Number} handshakeInterval Interval in milliseconds when
|
|
222
|
+
* @property {Number} handshakeInterval Interval in milliseconds when scanning for a handshake
|
|
223
223
|
* @property {Number} handshakeTimeout Interval in milliseconds for when to give up trying to handshake
|
|
224
224
|
* @property {Array<String|Array<String>>} [debugPaths] List of paths (in either dotted or array notation) to enter debugging mode if a change is detected in dev mode e.g. `{debugPaths: ['foo.bar.baz']}`. This really slows down state writes so should only be used for debugging
|
|
225
225
|
*/
|
|
@@ -238,6 +238,7 @@ export default class TeraFy {
|
|
|
238
238
|
config.siteUrl = 'https://dev.tera-tools.com/embed'; // Repoint URL to dev site
|
|
239
239
|
}
|
|
240
240
|
},
|
|
241
|
+
// eslint-disable-next-line no-unused-vars
|
|
241
242
|
},
|
|
242
243
|
siteUrl: 'https://tera-tools.com/embed',
|
|
243
244
|
restrictOrigin: '*',
|
|
@@ -261,7 +262,7 @@ export default class TeraFy {
|
|
|
261
262
|
* Event emitter subscription endpoint
|
|
262
263
|
* @type {Mitt}
|
|
263
264
|
*/
|
|
264
|
-
// @ts-
|
|
265
|
+
// @ts-expect-error Because mitt is exported as cjs typescript has trouble resolving default export
|
|
265
266
|
this.events = Mitt();
|
|
266
267
|
/**
|
|
267
268
|
* DOMElements for this TeraFy instance
|
|
@@ -349,7 +350,7 @@ export default class TeraFy {
|
|
|
349
350
|
this.plugins = [];
|
|
350
351
|
/**
|
|
351
352
|
* Active namespaces we are subscribed to
|
|
352
|
-
* Each key is the namespace name with the value as the local reactive \ observer \ object
|
|
353
|
+
* Each key is the namespace name with the value as the local reactive \ observer \ object equivalent
|
|
353
354
|
* The key string is always of the form `${ENTITY}::${ID}` e.g. `projects:1234`
|
|
354
355
|
*
|
|
355
356
|
* @type {Object<Object>}
|
|
@@ -364,18 +365,20 @@ export default class TeraFy {
|
|
|
364
365
|
this.set(options);
|
|
365
366
|
}
|
|
366
367
|
/**
|
|
367
|
-
*
|
|
368
|
-
* This function can only be called once and will return the existing init() worker Promise if its called
|
|
368
|
+
* Initialize the TERA client singleton
|
|
369
|
+
* This function can only be called once and will return the existing init() worker Promise if its called against
|
|
369
370
|
*
|
|
370
371
|
* @param {Object} [options] Additional options to merge into `settings` via `set`
|
|
371
|
-
* @returns {Promise<TeraFy>} An eventual promise which will
|
|
372
|
+
* @returns {Promise<TeraFy>} An eventual promise which will resolve with this terafy instance
|
|
372
373
|
*/
|
|
373
374
|
init(options) {
|
|
374
375
|
if (options)
|
|
375
376
|
this.set(options);
|
|
376
377
|
if (this.initPromise)
|
|
377
|
-
return this.initPromise; //
|
|
378
|
+
return this.initPromise; // Already been called - return init promise
|
|
379
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
378
380
|
window.addEventListener('message', this.acceptMessage.bind(this));
|
|
381
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
379
382
|
const context = this;
|
|
380
383
|
this.initPromise = Promise.resolve()
|
|
381
384
|
.then(() => { var _a; return (_a = this.settings).session || (_a.session = 'tfy-' + this.getEntropicString(16)); })
|
|
@@ -424,7 +427,7 @@ export default class TeraFy {
|
|
|
424
427
|
this.settings.mode == 'child' ? 'embedded'
|
|
425
428
|
: this.settings.mode == 'parent' ? 'frame'
|
|
426
429
|
: this.settings.mode == 'popup' ? 'popup'
|
|
427
|
-
: (() => { throw (`Unknown server mode "${this.settings.mode}"`); })()))
|
|
430
|
+
: (() => { throw new Error(`Unknown server mode "${this.settings.mode}"`); })()))
|
|
428
431
|
.then(() => this.debug('INFO', 4, '[5/6] Run client plugins'))
|
|
429
432
|
.then(() => Promise.all(// Init all plugins (with this outer module as the context)
|
|
430
433
|
this.plugins.map(plugin => plugin.init.call(context, this.settings))))
|
|
@@ -455,7 +458,7 @@ export default class TeraFy {
|
|
|
455
458
|
return Promise.resolve()
|
|
456
459
|
.then(() => this.settings.mode = 'parent') // Switch to parent mode...
|
|
457
460
|
.then(() => new Promise((resolve, reject) => {
|
|
458
|
-
|
|
461
|
+
const timeoutHandle = setTimeout(() => reject('TIMEOUT'), this.settings.modeTimeout);
|
|
459
462
|
this.rpc('handshake')
|
|
460
463
|
.then(() => clearTimeout(timeoutHandle))
|
|
461
464
|
.then(() => resolve())
|
|
@@ -466,9 +469,9 @@ export default class TeraFy {
|
|
|
466
469
|
}
|
|
467
470
|
}
|
|
468
471
|
/**
|
|
469
|
-
* Find an existing active TERA server OR
|
|
472
|
+
* Find an existing active TERA server OR initialize one
|
|
470
473
|
*
|
|
471
|
-
* @returns {Promise} A promise which will resolve when the loading has completed and we have found a parent TERA instance or
|
|
474
|
+
* @returns {Promise} A promise which will resolve when the loading has completed and we have found a parent TERA instance or initialized a child
|
|
472
475
|
*/
|
|
473
476
|
injectComms() {
|
|
474
477
|
switch (this.settings.mode) {
|
|
@@ -485,7 +488,7 @@ export default class TeraFy {
|
|
|
485
488
|
// Queue up event chain when document loads
|
|
486
489
|
this.dom.iframe.setAttribute('sandbox', this.settings.frameSandbox.join(' '));
|
|
487
490
|
this.dom.iframe.addEventListener('load', () => {
|
|
488
|
-
this.debug('INFO', 3, '
|
|
491
|
+
this.debug('INFO', 3, 'Embedded iframe ready');
|
|
489
492
|
resolve();
|
|
490
493
|
});
|
|
491
494
|
// Start document load sequence + append to DOM
|
|
@@ -509,13 +512,13 @@ export default class TeraFy {
|
|
|
509
512
|
* Keep trying to handshake until the target responds
|
|
510
513
|
*
|
|
511
514
|
* @param {Object} [options] Additional options to mutate behaviour
|
|
512
|
-
* @property {Number} [handshakeInterval] Interval in milliseconds when
|
|
515
|
+
* @property {Number} [handshakeInterval] Interval in milliseconds when scanning for a handshake, defaults to global setting
|
|
513
516
|
* @property {Number} [handshakeTimeout] Interval in milliseconds for when to give up trying to handshake, defaults to global setting
|
|
514
517
|
*
|
|
515
518
|
* @returns {Promise} A promise which will either resolve when the handshake is successful OR fail with 'TIMEOUT'
|
|
516
519
|
*/
|
|
517
520
|
handshakeLoop(options) {
|
|
518
|
-
|
|
521
|
+
const settings = {
|
|
519
522
|
handshakeInterval: this.settings.handshakeInterval,
|
|
520
523
|
handshakeTimeout: this.settings.handshakeTimeout,
|
|
521
524
|
...options,
|
|
@@ -524,7 +527,7 @@ export default class TeraFy {
|
|
|
524
527
|
return new Promise((resolve, reject) => {
|
|
525
528
|
let handshakeCount = 0;
|
|
526
529
|
let handshakeTimer;
|
|
527
|
-
|
|
530
|
+
const handshakeTimeout = setTimeout(() => {
|
|
528
531
|
clearTimeout(handshakeTimer);
|
|
529
532
|
reject('TIMEOUT');
|
|
530
533
|
}, settings.handshakeTimeout);
|
|
@@ -546,7 +549,7 @@ export default class TeraFy {
|
|
|
546
549
|
/**
|
|
547
550
|
* Inject a local stylesheet to handle TERA server functionality
|
|
548
551
|
*
|
|
549
|
-
* @returns {Promise} A promise which will resolve when the loading has completed and we have found a parent TERA instance or
|
|
552
|
+
* @returns {Promise} A promise which will resolve when the loading has completed and we have found a parent TERA instance or initialized a child
|
|
550
553
|
*/
|
|
551
554
|
injectStylesheet() {
|
|
552
555
|
switch (this.settings.mode) {
|
|
@@ -645,7 +648,7 @@ export default class TeraFy {
|
|
|
645
648
|
'}',
|
|
646
649
|
// }}}
|
|
647
650
|
].join('\n');
|
|
648
|
-
document.head.
|
|
651
|
+
document.head.append(this.dom.stylesheet);
|
|
649
652
|
break;
|
|
650
653
|
case 'parent':
|
|
651
654
|
case 'popup':
|
|
@@ -704,7 +707,7 @@ export default class TeraFy {
|
|
|
704
707
|
* @returns {TeraFy} This chainable terafy instance
|
|
705
708
|
*/
|
|
706
709
|
set(key, value, options) {
|
|
707
|
-
|
|
710
|
+
const settings = {
|
|
708
711
|
ignoreNullish: true,
|
|
709
712
|
...options,
|
|
710
713
|
};
|
|
@@ -736,15 +739,15 @@ export default class TeraFy {
|
|
|
736
739
|
* Include a TeraFy client plugin
|
|
737
740
|
*
|
|
738
741
|
* @param {Function|Object|String} source Either the JS module class, singleton object or URL to fetch it from. Eventually constructed as invoked as `(teraClient:TeraFy, options:Object)`
|
|
739
|
-
* @param {Object} [options] Additional options to mutate behaviour during construction (pass options to init() to
|
|
742
|
+
* @param {Object} [options] Additional options to mutate behaviour during construction (pass options to init() to initialize later options)
|
|
740
743
|
*
|
|
741
744
|
* @returns {TeraFy} This chainable terafy instance
|
|
742
745
|
*/
|
|
743
746
|
use(source, options) {
|
|
744
|
-
|
|
747
|
+
const mod = typeof source == 'function' ? new source(this, options)
|
|
745
748
|
: typeof source == 'object' ? source
|
|
746
749
|
: typeof source == 'string' ? (() => { throw new Error('use(String) is not yet supported'); })()
|
|
747
|
-
: (() => { throw new Error('Expected use() call to be provided with a class
|
|
750
|
+
: (() => { throw new Error('Expected use() call to be provided with a class initializer'); })();
|
|
748
751
|
this.mixin(this, mod);
|
|
749
752
|
this.plugins.push(mod);
|
|
750
753
|
return this;
|
|
@@ -752,30 +755,30 @@ export default class TeraFy {
|
|
|
752
755
|
/**
|
|
753
756
|
* Internal function used by use() to merge an external declared singleton against this object
|
|
754
757
|
*
|
|
755
|
-
* @param {Object} target
|
|
756
|
-
* @param {Object} source
|
|
758
|
+
* @param {Object} target Installed class instance to extend
|
|
759
|
+
* @param {Object} source Initialized source object to extend from
|
|
757
760
|
*/
|
|
758
761
|
mixin(target, source) {
|
|
759
762
|
// Iterate through the source object upwards extracting each prototype
|
|
760
|
-
|
|
763
|
+
const prototypeStack = [];
|
|
761
764
|
let node = source;
|
|
762
765
|
do {
|
|
763
766
|
prototypeStack.unshift(node);
|
|
764
|
-
} while (node = Object.getPrototypeOf(node)); // Walk upwards until we hit null (no more inherited classes)
|
|
767
|
+
} while ((node = Object.getPrototypeOf(node))); // Walk upwards until we hit null (no more inherited classes)
|
|
765
768
|
// Iterate through stacks inheriting each prop into the target
|
|
766
769
|
prototypeStack.forEach(stack => Object.getOwnPropertyNames(stack)
|
|
767
770
|
.filter(prop => !['constructor', 'init', 'prototype', 'name'].includes(prop) // Ignore forbidden properties
|
|
768
771
|
&& !prop.startsWith('__') // Ignore double underscore meta properties
|
|
769
772
|
)
|
|
770
773
|
.forEach(prop => {
|
|
771
|
-
if (typeof source[prop] == 'function') { // Inheriting function - glue onto object as non-editable, non-enumerable property
|
|
774
|
+
if (typeof (source)[prop] == 'function') { // Inheriting function - glue onto object as non-editable, non-enumerable property
|
|
772
775
|
Object.defineProperty(target, prop, {
|
|
773
776
|
enumerable: false,
|
|
774
|
-
value: source[prop].bind(target), // Rebind functions
|
|
777
|
+
value: (source)[prop].bind(target), // Rebind functions
|
|
775
778
|
});
|
|
776
779
|
}
|
|
777
780
|
else { // Everything else, just glue onto the object
|
|
778
|
-
target[prop] = source[prop];
|
|
781
|
+
target[prop] = (source)[prop];
|
|
779
782
|
}
|
|
780
783
|
}));
|
|
781
784
|
}
|
|
@@ -823,13 +826,13 @@ export default class TeraFy {
|
|
|
823
826
|
/**
|
|
824
827
|
* Generate random entropic character string in Base64
|
|
825
828
|
*
|
|
826
|
-
* @param {Number} [maxLength=32] Maximum
|
|
829
|
+
* @param {Number} [maxLength=32] Maximum length of the generated string
|
|
827
830
|
* @returns {String}
|
|
828
831
|
*/
|
|
829
832
|
getEntropicString(maxLength = 32) {
|
|
830
833
|
const array = new Uint32Array(4);
|
|
831
834
|
window.crypto.getRandomValues(array);
|
|
832
|
-
return btoa(String.
|
|
835
|
+
return btoa(String.fromCodePoint(...new Uint8Array(array.buffer)))
|
|
833
836
|
.replace(/[+/]/g, '') // Remove + and / characters
|
|
834
837
|
.slice(0, maxLength); // Trim
|
|
835
838
|
}
|
|
@@ -843,7 +846,7 @@ export default class TeraFy {
|
|
|
843
846
|
* @property {Date} date Server date
|
|
844
847
|
*/
|
|
845
848
|
/**
|
|
846
|
-
* RPC callback to set the server
|
|
849
|
+
* RPC callback to set the server verbosity level
|
|
847
850
|
*
|
|
848
851
|
* @function setServerVerbosity
|
|
849
852
|
* @param {Number} verbosity The desired server verbosity level
|
|
@@ -861,7 +864,7 @@ export default class TeraFy {
|
|
|
861
864
|
* Fetch the current session user
|
|
862
865
|
*
|
|
863
866
|
* @function getUser
|
|
864
|
-
* @param {Boolean} [options.forceRetry=false]
|
|
867
|
+
* @param {Boolean} [options.forceRetry=false] Forcibly try to refresh the user state
|
|
865
868
|
* @param {Boolean} [options.waitPromises=true] Wait for $auth + $subscriptions to resolve before fetching the user (mainly internal use)
|
|
866
869
|
* @returns {Promise<User>} The current logged in user or null if none
|
|
867
870
|
*/
|
|
@@ -879,7 +882,7 @@ export default class TeraFy {
|
|
|
879
882
|
* @function requireUser
|
|
880
883
|
*
|
|
881
884
|
* @param {Object} [options] Additional options to mutate behaviour
|
|
882
|
-
* @param {Boolean} [options.forceRetry=false]
|
|
885
|
+
* @param {Boolean} [options.forceRetry=false] Forcibly try to refresh the user state
|
|
883
886
|
*
|
|
884
887
|
* @returns {Promise<User>} The current logged in user or null if none
|
|
885
888
|
*/
|
|
@@ -916,7 +919,7 @@ export default class TeraFy {
|
|
|
916
919
|
*/
|
|
917
920
|
/**
|
|
918
921
|
* Ask the user to select a project from those available - if one isn't already active
|
|
919
|
-
* Note that this function will
|
|
922
|
+
* Note that this function will persist in asking the user even if they try to cancel
|
|
920
923
|
*
|
|
921
924
|
* @function requireProject
|
|
922
925
|
* @param {Object} [options] Additional options to mutate behaviour
|
|
@@ -940,7 +943,7 @@ export default class TeraFy {
|
|
|
940
943
|
*/
|
|
941
944
|
/**
|
|
942
945
|
* Get a one-off snapshot of a namespace without mounting it
|
|
943
|
-
* This can be used for simpler apps which don't have their own reactive / observer
|
|
946
|
+
* This can be used for simpler apps which don't have their own reactive / observer equivalent
|
|
944
947
|
*
|
|
945
948
|
* @function getNamespace
|
|
946
949
|
* @param {String} name The alias of the namespace, this should be alphanumeric + hyphens + underscores
|
|
@@ -949,7 +952,7 @@ export default class TeraFy {
|
|
|
949
952
|
*/
|
|
950
953
|
/**
|
|
951
954
|
* Set (or merge by default) a one-off snapshot over an existing namespace
|
|
952
|
-
* This can be used for simpler apps which don't have their own reactive / observer
|
|
955
|
+
* This can be used for simpler apps which don't have their own reactive / observer equivalent and just want to quickly set something
|
|
953
956
|
*
|
|
954
957
|
* @function setNamespace
|
|
955
958
|
* @param {String} name The name of the namespace
|
|
@@ -1032,10 +1035,9 @@ export default class TeraFy {
|
|
|
1032
1035
|
* @param {Boolean} [options.allowUpload=true] Allow uploading new files
|
|
1033
1036
|
* @param {Boolean} [options.allowRefresh=true] Allow the user to manually refresh the file list
|
|
1034
1037
|
* @param {Boolean} [options.allowDownloadZip=true] Allow the user to download a Zip of all files
|
|
1035
|
-
* @param {Boolean} [options.allowCancel=true] Allow cancelling the operation. Will throw `'CANCEL'` as the promise rejection if
|
|
1038
|
+
* @param {Boolean} [options.allowCancel=true] Allow cancelling the operation. Will throw `'CANCEL'` as the promise rejection if actioned
|
|
1036
1039
|
* @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing
|
|
1037
1040
|
* @param {Boolean} [options.showHiddenFiles=false] Whether hidden data.json files should be shown
|
|
1038
|
-
* @param {FileFilters} [options.filter] Optional file filters
|
|
1039
1041
|
*
|
|
1040
1042
|
* @returns {Promise<ProjectFile>} The eventually selected file, if in save mode new files are created as stubs
|
|
1041
1043
|
*/
|
|
@@ -1071,7 +1073,7 @@ export default class TeraFy {
|
|
|
1071
1073
|
*
|
|
1072
1074
|
* @function getProjectFileContents
|
|
1073
1075
|
* @param {String} [id] File ID to retrieve the contents of
|
|
1074
|
-
* @param {Object} [options]
|
|
1076
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
1075
1077
|
* @param {'blob'|'json'} [options.format='blob'] The format to retrieve the file in
|
|
1076
1078
|
*
|
|
1077
1079
|
* @returns {*} The file contents in the requested format
|