@iebh/tera-fy 2.0.21 → 2.2.0
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/CHANGELOG.md +38 -0
- package/api.md +68 -66
- package/dist/lib/projectFile.d.ts +182 -0
- package/dist/lib/projectFile.js +157 -0
- package/dist/lib/projectFile.js.map +1 -0
- package/dist/lib/syncro/entities.d.ts +28 -0
- package/dist/lib/syncro/entities.js +203 -0
- package/dist/lib/syncro/entities.js.map +1 -0
- package/dist/lib/syncro/keyed.d.ts +95 -0
- package/dist/lib/syncro/keyed.js +286 -0
- package/dist/lib/syncro/keyed.js.map +1 -0
- package/dist/lib/syncro/syncro.d.ts +328 -0
- package/dist/lib/syncro/syncro.js +633 -0
- package/dist/lib/syncro/syncro.js.map +1 -0
- package/dist/lib/terafy.bootstrapper.d.ts +42 -0
- package/dist/lib/terafy.bootstrapper.js +130 -0
- package/dist/lib/terafy.bootstrapper.js.map +1 -0
- package/dist/lib/terafy.client.d.ts +532 -0
- package/dist/lib/terafy.client.js +1110 -0
- package/dist/lib/terafy.client.js.map +1 -0
- package/dist/lib/terafy.proxy.d.ts +66 -0
- package/dist/lib/terafy.proxy.js +123 -0
- package/dist/lib/terafy.proxy.js.map +1 -0
- package/dist/lib/terafy.server.d.ts +607 -0
- package/dist/lib/terafy.server.js +1774 -0
- package/dist/lib/terafy.server.js.map +1 -0
- package/dist/plugin.vue2.es2019.js +30 -13
- package/dist/plugins/base.d.ts +20 -0
- package/dist/plugins/base.js +21 -0
- package/dist/plugins/base.js.map +1 -0
- package/dist/plugins/firebase.d.ts +62 -0
- package/dist/plugins/firebase.js +111 -0
- package/dist/plugins/firebase.js.map +1 -0
- package/dist/plugins/vite.d.ts +12 -0
- package/dist/plugins/vite.js +22 -0
- package/dist/plugins/vite.js.map +1 -0
- package/dist/plugins/vue2.d.ts +68 -0
- package/dist/plugins/vue2.js +96 -0
- package/dist/plugins/vue2.js.map +1 -0
- package/dist/plugins/vue3.d.ts +64 -0
- package/dist/plugins/vue3.js +96 -0
- package/dist/plugins/vue3.js.map +1 -0
- 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 +1 -1
- package/dist/utils/mixin.d.ts +11 -0
- package/dist/utils/mixin.js +15 -0
- package/dist/utils/mixin.js.map +1 -0
- package/dist/utils/pDefer.d.ts +12 -0
- package/dist/utils/pDefer.js +14 -0
- package/dist/utils/pDefer.js.map +1 -0
- package/dist/utils/pathTools.d.ts +70 -0
- package/dist/utils/pathTools.js +120 -0
- package/dist/utils/pathTools.js.map +1 -0
- package/eslint.config.js +44 -8
- package/lib/{projectFile.js → projectFile.ts} +83 -40
- package/lib/syncro/entities.ts +288 -0
- package/lib/syncro/{keyed.js → keyed.ts} +114 -57
- package/lib/syncro/{syncro.js → syncro.ts} +204 -169
- package/lib/{terafy.bootstrapper.js → terafy.bootstrapper.ts} +49 -31
- package/lib/{terafy.client.js → terafy.client.ts} +94 -86
- package/lib/{terafy.proxy.js → terafy.proxy.ts} +43 -16
- package/lib/{terafy.server.js → terafy.server.ts} +364 -223
- package/package.json +65 -26
- package/plugins/{base.js → base.ts} +3 -1
- package/plugins/{firebase.js → firebase.ts} +34 -16
- package/plugins/{vite.js → vite.ts} +3 -3
- package/plugins/{vue2.js → vue2.ts} +17 -10
- package/plugins/{vue3.js → vue3.ts} +11 -9
- package/tsconfig.json +30 -0
- package/utils/{mixin.js → mixin.ts} +1 -1
- package/utils/{pDefer.js → pDefer.ts} +10 -3
- package/utils/{pathTools.js → pathTools.ts} +11 -9
- package/lib/syncro/entities.js +0 -232
|
@@ -31,21 +31,21 @@ export default class TeraFy {
|
|
|
31
31
|
* @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
|
|
32
32
|
*/
|
|
33
33
|
settings = {
|
|
34
|
-
session: null,
|
|
34
|
+
session: null as string | null,
|
|
35
35
|
// client: 'tera-fy', // Reserved by terafy.bootstrapper.js
|
|
36
36
|
// clientType: 'esm', // Reserved by terafy.bootstrapper.js
|
|
37
37
|
devMode: false,
|
|
38
38
|
verbosity: 1,
|
|
39
|
-
mode: 'detect',
|
|
39
|
+
mode: 'detect' as 'detect' | 'parent' | 'child' | 'popup',
|
|
40
40
|
modeTimeout: 300,
|
|
41
41
|
modeFallback: 'child', // ENUM: 'child' (use iframes), 'popup' (use popup windows)
|
|
42
42
|
modeOverrides: {
|
|
43
|
-
child(config) { // When we're in child mode assume a local dev environment and use the dev.tera-tools.com site instead to work around CORS restrictions
|
|
43
|
+
child(config: any) { // When we're in child mode assume a local dev environment and use the dev.tera-tools.com site instead to work around CORS restrictions
|
|
44
44
|
if (config.siteUrl == 'https://tera-tools.com/embed') { // Only if we're using the default URL...
|
|
45
45
|
config.siteUrl = 'https://dev.tera-tools.com/embed'; // Repoint URL to dev site
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
|
-
},
|
|
48
|
+
} as { [key: string]: (config: any) => void },
|
|
49
49
|
siteUrl: 'https://tera-tools.com/embed',
|
|
50
50
|
restrictOrigin: '*',
|
|
51
51
|
frameSandbox: [
|
|
@@ -62,7 +62,7 @@ export default class TeraFy {
|
|
|
62
62
|
],
|
|
63
63
|
handshakeInterval: 1_000, // ~1s
|
|
64
64
|
handshakeTimeout: 10_000, // ~10s
|
|
65
|
-
debugPaths: null, // Transformed into a Array<String> (in Lodash dotted notation) on init()
|
|
65
|
+
debugPaths: null as Array<string | Array<string>> | null, // Transformed into a Array<String> (in Lodash dotted notation) on init()
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
|
|
@@ -70,6 +70,7 @@ export default class TeraFy {
|
|
|
70
70
|
* Event emitter subscription endpoint
|
|
71
71
|
* @type {Mitt}
|
|
72
72
|
*/
|
|
73
|
+
// @ts-ignore
|
|
73
74
|
events = Mitt();
|
|
74
75
|
|
|
75
76
|
|
|
@@ -83,10 +84,10 @@ export default class TeraFy {
|
|
|
83
84
|
* @property {DOMElement} stylesheet The corresponding stylesheet
|
|
84
85
|
*/
|
|
85
86
|
dom = {
|
|
86
|
-
el: null,
|
|
87
|
-
iframe: null,
|
|
88
|
-
popup: null,
|
|
89
|
-
stylesheet: null,
|
|
87
|
+
el: null as HTMLDivElement | null,
|
|
88
|
+
iframe: null as HTMLIFrameElement | null,
|
|
89
|
+
popup: null as Window | null,
|
|
90
|
+
stylesheet: null as HTMLStyleElement | null,
|
|
90
91
|
};
|
|
91
92
|
|
|
92
93
|
|
|
@@ -156,14 +157,14 @@ export default class TeraFy {
|
|
|
156
157
|
'uiThrow',
|
|
157
158
|
'uiSplat',
|
|
158
159
|
'uiWindow',
|
|
159
|
-
];
|
|
160
|
+
] as const;
|
|
160
161
|
|
|
161
162
|
|
|
162
163
|
/**
|
|
163
164
|
* Loaded plugins via Use()
|
|
164
165
|
* @type {Array<TeraFyPlugin>}
|
|
165
166
|
*/
|
|
166
|
-
plugins = [];
|
|
167
|
+
plugins: any[] = [];
|
|
167
168
|
|
|
168
169
|
|
|
169
170
|
/**
|
|
@@ -173,7 +174,7 @@ export default class TeraFy {
|
|
|
173
174
|
*
|
|
174
175
|
* @type {Object<Object>}
|
|
175
176
|
*/
|
|
176
|
-
namespaces = {};
|
|
177
|
+
namespaces: { [key: string]: any } = {};
|
|
177
178
|
|
|
178
179
|
|
|
179
180
|
// Messages - send(), sendRaw(), rpc(), acceptMessage() {{{
|
|
@@ -184,7 +185,7 @@ export default class TeraFy {
|
|
|
184
185
|
* @param {Object} message Message object to send
|
|
185
186
|
* @returns {Promise<*>} A promise which resolves when the operation has completed with the remote reply
|
|
186
187
|
*/
|
|
187
|
-
send(message) {
|
|
188
|
+
send(message: any) {
|
|
188
189
|
let id = nanoid();
|
|
189
190
|
|
|
190
191
|
this.acceptPostboxes[id] = {}; // Stub for the deferred promise
|
|
@@ -208,8 +209,8 @@ export default class TeraFy {
|
|
|
208
209
|
*
|
|
209
210
|
* @param {Object} message Message object to send
|
|
210
211
|
*/
|
|
211
|
-
sendRaw(message) {
|
|
212
|
-
let payload;
|
|
212
|
+
sendRaw(message: any) {
|
|
213
|
+
let payload: any;
|
|
213
214
|
try {
|
|
214
215
|
payload = {
|
|
215
216
|
TERA: 1,
|
|
@@ -220,9 +221,9 @@ export default class TeraFy {
|
|
|
220
221
|
if (this.settings.mode == 'parent') {
|
|
221
222
|
window.parent.postMessage(payload, this.settings.restrictOrigin);
|
|
222
223
|
} else if (this.settings.mode == 'child') {
|
|
223
|
-
this.dom.iframe
|
|
224
|
+
this.dom.iframe!.contentWindow!.postMessage(payload, this.settings.restrictOrigin);
|
|
224
225
|
} else if (this.settings.mode == 'popup') {
|
|
225
|
-
this.dom.popup
|
|
226
|
+
this.dom.popup!.postMessage(payload, this.settings.restrictOrigin);
|
|
226
227
|
} else if (this.settings.mode == 'detect') {
|
|
227
228
|
throw new Error('Call init() or detectMode() before trying to send data to determine the mode');
|
|
228
229
|
} else {
|
|
@@ -244,7 +245,7 @@ export default class TeraFy {
|
|
|
244
245
|
*
|
|
245
246
|
* @returns {Promise<*>} The resolved output of the server function
|
|
246
247
|
*/
|
|
247
|
-
rpc(method, ...args) {
|
|
248
|
+
rpc(method: any, ...args: any[]) {
|
|
248
249
|
return this.send({
|
|
249
250
|
action: 'rpc',
|
|
250
251
|
method,
|
|
@@ -260,7 +261,7 @@ export default class TeraFy {
|
|
|
260
261
|
*
|
|
261
262
|
* @returns {Promise} A promise which will resolve when the message has been processed
|
|
262
263
|
*/
|
|
263
|
-
acceptMessage(rawMessage) {
|
|
264
|
+
acceptMessage(rawMessage: any) {
|
|
264
265
|
if (rawMessage.origin == window.location.origin) return Promise.resolve(); // Message came from us
|
|
265
266
|
|
|
266
267
|
let message = rawMessage.data;
|
|
@@ -276,7 +277,7 @@ export default class TeraFy {
|
|
|
276
277
|
return Promise.resolve();
|
|
277
278
|
} else if (message?.action == 'rpc') {
|
|
278
279
|
return Promise.resolve()
|
|
279
|
-
.then(()=> this[message.method].apply(this, message.args))
|
|
280
|
+
.then(()=> (this as any)[message.method].apply(this, message.args as any[]))
|
|
280
281
|
.then(res => this.sendRaw({
|
|
281
282
|
id: message.id,
|
|
282
283
|
action: 'response',
|
|
@@ -293,7 +294,7 @@ export default class TeraFy {
|
|
|
293
294
|
})
|
|
294
295
|
} else if (message?.action == 'event') {
|
|
295
296
|
return Promise.resolve()
|
|
296
|
-
.then(()=> this.events.emit(message.event, ...message.payload))
|
|
297
|
+
.then(()=> this.events.emit(message.event, ...(message.payload as [])))
|
|
297
298
|
.catch(e => {
|
|
298
299
|
console.warn(`TERA-FY client threw while handling emitted event "${message.event}"`, {message});
|
|
299
300
|
throw e;
|
|
@@ -311,7 +312,7 @@ export default class TeraFy {
|
|
|
311
312
|
/**
|
|
312
313
|
* Listening postboxes, these correspond to outgoing message IDs that expect a response
|
|
313
314
|
*/
|
|
314
|
-
acceptPostboxes = {};
|
|
315
|
+
acceptPostboxes: { [key: string]: any } = {};
|
|
315
316
|
|
|
316
317
|
// }}}
|
|
317
318
|
|
|
@@ -325,7 +326,7 @@ export default class TeraFy {
|
|
|
325
326
|
*
|
|
326
327
|
* @returns {Promise<Reactive>} A promise which resolves to the reactive object
|
|
327
328
|
*/
|
|
328
|
-
mountNamespace(name) {
|
|
329
|
+
mountNamespace(name: any) {
|
|
329
330
|
if (!/^[\w-]+$/.test(name)) throw new Error('Namespaces must be alphanumeric + hyphens + underscores');
|
|
330
331
|
if (this.namespaces[name]) return Promise.resolve(this.namespaces[name]); // Already mounted
|
|
331
332
|
|
|
@@ -343,7 +344,7 @@ export default class TeraFy {
|
|
|
343
344
|
*
|
|
344
345
|
* @returns {Promise} A promise which resolves when the mount operation has completed
|
|
345
346
|
*/
|
|
346
|
-
_mountNamespace(name) { // eslint-disable-line no-unused-vars
|
|
347
|
+
_mountNamespace(name: any) { // eslint-disable-line no-unused-vars
|
|
347
348
|
console.warn('teraFy._mountNamespace() has not been overriden by a TERA-fy plugin, load one to add this functionality for your preferred framework');
|
|
348
349
|
throw new Error('teraFy._mountNamespace() is not supported');
|
|
349
350
|
}
|
|
@@ -359,7 +360,7 @@ export default class TeraFy {
|
|
|
359
360
|
*
|
|
360
361
|
* @returns {Promise} A promise which resolves when the operation has completed
|
|
361
362
|
*/
|
|
362
|
-
unmountNamespace(name) {
|
|
363
|
+
unmountNamespace(name: any) {
|
|
363
364
|
if (!this.namespaces[name]) return Promise.resolve(); // Already unmounted
|
|
364
365
|
return this._unmountNamespace(name);
|
|
365
366
|
}
|
|
@@ -373,7 +374,7 @@ export default class TeraFy {
|
|
|
373
374
|
*
|
|
374
375
|
* @returns {Promise} A promise which resolves when the operation has completed
|
|
375
376
|
*/
|
|
376
|
-
_unmountNamespace(name) { // eslint-disable-line no-unused-vars
|
|
377
|
+
_unmountNamespace(name: any) { // eslint-disable-line no-unused-vars
|
|
377
378
|
console.warn('teraFy.unbindNamespace() has not been overriden by a TERA-fy plugin, load one to add this functionality for your preferred framework');
|
|
378
379
|
}
|
|
379
380
|
// }}}
|
|
@@ -385,10 +386,11 @@ export default class TeraFy {
|
|
|
385
386
|
*
|
|
386
387
|
* @param {Object} [options] Additional options to merge into `settings` via `set`
|
|
387
388
|
*/
|
|
388
|
-
constructor(options) {
|
|
389
|
+
constructor(options?: any) {
|
|
389
390
|
if (options) this.set(options);
|
|
390
391
|
}
|
|
391
392
|
|
|
393
|
+
private initPromise: Promise<TeraFy> | null = null;
|
|
392
394
|
|
|
393
395
|
/**
|
|
394
396
|
* Initalize the TERA client singleton
|
|
@@ -397,26 +399,27 @@ export default class TeraFy {
|
|
|
397
399
|
* @param {Object} [options] Additional options to merge into `settings` via `set`
|
|
398
400
|
* @returns {Promise<TeraFy>} An eventual promise which will resovle with this terafy instance
|
|
399
401
|
*/
|
|
400
|
-
init(options) {
|
|
402
|
+
init(options?: any): Promise<TeraFy> {
|
|
401
403
|
if (options) this.set(options);
|
|
402
|
-
if (this.
|
|
404
|
+
if (this.initPromise) return this.initPromise; // Aleady been called - return init promise
|
|
403
405
|
|
|
404
406
|
window.addEventListener('message', this.acceptMessage.bind(this));
|
|
405
407
|
|
|
406
408
|
const context = this;
|
|
407
|
-
|
|
409
|
+
this.initPromise = Promise.resolve()
|
|
408
410
|
.then(()=> this.settings.session ||= 'tfy-' + this.getEntropicString(16))
|
|
409
411
|
.then(()=> this.debug('INFO', 4, '[0/6] Init', 'Session', this.settings.session, 'against', this.settings.siteUrl))
|
|
410
412
|
.then(()=> { // Init various options for optimized access
|
|
411
413
|
if (!this.settings.devMode) return; // Not in dev mode
|
|
412
|
-
this.settings.debugPaths
|
|
413
|
-
|
|
414
|
-
: Array.isArray(this.settings.debugPaths) ? this.settings.debugPaths.map(path =>
|
|
414
|
+
if (this.settings.debugPaths) {
|
|
415
|
+
this.settings.debugPaths = (this.settings.debugPaths as any[]).map((path: any) =>
|
|
415
416
|
Array.isArray(path) ? path.join('.') // Transform arrays into dotted notation
|
|
416
417
|
: typeof path == 'string' ? path // Assume already in dotted notation
|
|
417
418
|
: (()=> { throw new Error('Unknown path type - should be an array or string in dotted notation') })()
|
|
418
419
|
)
|
|
419
|
-
|
|
420
|
+
} else {
|
|
421
|
+
this.settings.debugPaths = null;
|
|
422
|
+
}
|
|
420
423
|
|
|
421
424
|
this.debug('INFO', 0, 'Watching state paths', this.settings.debugPaths);
|
|
422
425
|
})
|
|
@@ -459,12 +462,16 @@ export default class TeraFy {
|
|
|
459
462
|
plugin.init.call(context, this.settings)
|
|
460
463
|
)
|
|
461
464
|
))
|
|
462
|
-
.then(()=>
|
|
463
|
-
|
|
465
|
+
.then(()=> {
|
|
466
|
+
this.debug('INFO', 4, '[6/6] Init complete');
|
|
467
|
+
return context; // Resolve with the instance
|
|
468
|
+
})
|
|
464
469
|
.catch(e => {
|
|
465
470
|
this.debug('WARN', 0, 'Init process fault', e);
|
|
466
|
-
|
|
467
|
-
})
|
|
471
|
+
throw e; // Re-throw
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
return this.initPromise;
|
|
468
475
|
}
|
|
469
476
|
|
|
470
477
|
|
|
@@ -475,23 +482,24 @@ export default class TeraFy {
|
|
|
475
482
|
*
|
|
476
483
|
* @returns {Promise<String>} A promise which will resolve with the detected mode to use
|
|
477
484
|
*/
|
|
478
|
-
detectMode() {
|
|
485
|
+
detectMode(): Promise<'parent' | 'child' | 'popup'> {
|
|
479
486
|
if (this.settings.mode != 'detect') { // Dev has specified a forced mode to use
|
|
480
487
|
return Promise.resolve(this.settings.mode);
|
|
481
488
|
} else if (window.self === window.parent) { // This frame is already at the top
|
|
482
|
-
return Promise.resolve(this.settings.modeFallback);
|
|
489
|
+
return Promise.resolve(this.settings.modeFallback as 'child' | 'popup');
|
|
483
490
|
} else { // No idea - try messaging
|
|
484
491
|
return Promise.resolve()
|
|
485
492
|
.then(()=> this.settings.mode = 'parent') // Switch to parent mode...
|
|
486
|
-
.then(()=> new Promise((resolve, reject) => { // And try messaging with a timeout
|
|
493
|
+
.then(()=> new Promise<void>((resolve, reject) => { // And try messaging with a timeout
|
|
487
494
|
let timeoutHandle = setTimeout(()=> reject('TIMEOUT'), this.settings.modeTimeout);
|
|
488
495
|
|
|
489
496
|
this.rpc('handshake')
|
|
490
497
|
.then(()=> clearTimeout(timeoutHandle))
|
|
491
|
-
.then(()=> resolve())
|
|
498
|
+
.then(()=> resolve(undefined))
|
|
499
|
+
.catch(reject); // Propagate RPC errors
|
|
492
500
|
}))
|
|
493
|
-
.then(()=> 'parent')
|
|
494
|
-
.catch(()=> this.settings.modeFallback)
|
|
501
|
+
.then(()=> 'parent' as 'parent')
|
|
502
|
+
.catch(()=> this.settings.modeFallback as 'child' | 'popup')
|
|
495
503
|
}
|
|
496
504
|
}
|
|
497
505
|
|
|
@@ -504,29 +512,29 @@ export default class TeraFy {
|
|
|
504
512
|
injectComms() {
|
|
505
513
|
switch (this.settings.mode) {
|
|
506
514
|
case 'child': return Promise.resolve()
|
|
507
|
-
.then(()=> new Promise(resolve => {
|
|
515
|
+
.then(()=> new Promise<void>(resolve => {
|
|
508
516
|
this.debug('INFO', 2, 'Injecting TERA site as iFrame child');
|
|
509
517
|
|
|
510
518
|
this.dom.el = document.createElement('div')
|
|
511
519
|
this.dom.el.id = 'tera-fy';
|
|
512
|
-
this.dom.el
|
|
513
|
-
this.dom.el
|
|
514
|
-
document.body.append(this.dom.el);
|
|
520
|
+
this.dom.el!.classList.toggle('dev-mode', this.settings.devMode);
|
|
521
|
+
this.dom.el!.classList.add('minimized');
|
|
522
|
+
document.body.append(this.dom.el!);
|
|
515
523
|
|
|
516
|
-
this.dom.el
|
|
524
|
+
this.dom.el!.addEventListener('click', ()=> this.dom.el!.classList.toggle('minimized'));
|
|
517
525
|
|
|
518
526
|
this.dom.iframe = document.createElement('iframe')
|
|
519
527
|
|
|
520
528
|
// Queue up event chain when document loads
|
|
521
|
-
this.dom.iframe
|
|
522
|
-
this.dom.iframe
|
|
529
|
+
this.dom.iframe!.setAttribute('sandbox', this.settings.frameSandbox.join(' '));
|
|
530
|
+
this.dom.iframe!.addEventListener('load', ()=> {
|
|
523
531
|
this.debug('INFO', 3, 'Embeded iframe ready');
|
|
524
|
-
resolve();
|
|
532
|
+
resolve(undefined);
|
|
525
533
|
});
|
|
526
534
|
|
|
527
535
|
// Start document load sequence + append to DOM
|
|
528
|
-
this.dom.iframe
|
|
529
|
-
this.dom.el
|
|
536
|
+
this.dom.iframe!.src = this.settings.siteUrl;
|
|
537
|
+
this.dom.el!.append(this.dom.iframe!);
|
|
530
538
|
}))
|
|
531
539
|
.then(()=> this.handshakeLoop())
|
|
532
540
|
|
|
@@ -556,7 +564,7 @@ export default class TeraFy {
|
|
|
556
564
|
*
|
|
557
565
|
* @returns {Promise} A promise which will either resolve when the handshake is successful OR fail with 'TIMEOUT'
|
|
558
566
|
*/
|
|
559
|
-
handshakeLoop(options) {
|
|
567
|
+
handshakeLoop(options?: any) {
|
|
560
568
|
let settings = {
|
|
561
569
|
handshakeInterval: this.settings.handshakeInterval,
|
|
562
570
|
handshakeTimeout: this.settings.handshakeTimeout,
|
|
@@ -564,9 +572,9 @@ export default class TeraFy {
|
|
|
564
572
|
};
|
|
565
573
|
|
|
566
574
|
// Loop until the window context returns a handshake
|
|
567
|
-
return new Promise((resolve, reject) => {
|
|
575
|
+
return new Promise<void>((resolve, reject) => {
|
|
568
576
|
let handshakeCount = 0;
|
|
569
|
-
let handshakeTimer;
|
|
577
|
+
let handshakeTimer: any;
|
|
570
578
|
|
|
571
579
|
let handshakeTimeout = setTimeout(()=> {
|
|
572
580
|
clearTimeout(handshakeTimer);
|
|
@@ -584,8 +592,8 @@ export default class TeraFy {
|
|
|
584
592
|
clearTimeout(handshakeTimeout);
|
|
585
593
|
clearTimeout(handshakeTimer);
|
|
586
594
|
})
|
|
587
|
-
.then(()=> resolve())
|
|
588
|
-
.catch(reject)
|
|
595
|
+
.then(()=> resolve(undefined))
|
|
596
|
+
.catch(reject) // Let RPC errors propagate
|
|
589
597
|
};
|
|
590
598
|
tryHandshake(); // Kick off initial handshake
|
|
591
599
|
});
|
|
@@ -601,7 +609,7 @@ export default class TeraFy {
|
|
|
601
609
|
switch (this.settings.mode) {
|
|
602
610
|
case 'child':
|
|
603
611
|
this.dom.stylesheet = document.createElement('style');
|
|
604
|
-
this.dom.stylesheet
|
|
612
|
+
this.dom.stylesheet!.innerHTML = [
|
|
605
613
|
':root {',
|
|
606
614
|
'--TERA-accent: #4d659c;',
|
|
607
615
|
'}',
|
|
@@ -714,7 +722,7 @@ export default class TeraFy {
|
|
|
714
722
|
'}',
|
|
715
723
|
// }}}
|
|
716
724
|
].join('\n');
|
|
717
|
-
document.head.appendChild(this.dom.stylesheet);
|
|
725
|
+
document.head.appendChild(this.dom.stylesheet!);
|
|
718
726
|
break;
|
|
719
727
|
case 'parent':
|
|
720
728
|
case 'popup':
|
|
@@ -732,7 +740,7 @@ export default class TeraFy {
|
|
|
732
740
|
*/
|
|
733
741
|
injectMethods() {
|
|
734
742
|
this.methods.forEach(method =>
|
|
735
|
-
this[method] = this.rpc.bind(this, method)
|
|
743
|
+
(this as any)[method] = this.rpc.bind(this, method)
|
|
736
744
|
);
|
|
737
745
|
}
|
|
738
746
|
// }}}
|
|
@@ -748,7 +756,7 @@ export default class TeraFy {
|
|
|
748
756
|
* @param {Number} [verboseLevel=1] The verbosity level to trigger at. If `settings.verbosity` is lower than this, the message is ignored
|
|
749
757
|
* @param {...*} [msg] Output to show
|
|
750
758
|
*/
|
|
751
|
-
debug(...msg) {
|
|
759
|
+
debug(...msg: any[]) {
|
|
752
760
|
if (!this.settings.devMode || this.settings.verbosity < 1) return; // Debugging is disabled
|
|
753
761
|
let method = 'log';
|
|
754
762
|
let verboseLevel = 1;
|
|
@@ -765,7 +773,7 @@ export default class TeraFy {
|
|
|
765
773
|
|
|
766
774
|
if (this.settings.verbosity < verboseLevel) return; // Called but this output is too verbose for our settings - skip
|
|
767
775
|
|
|
768
|
-
console[method](
|
|
776
|
+
(console as any)[method](
|
|
769
777
|
'%c[TERA-FY CLIENT]',
|
|
770
778
|
'font-weight: bold; color: #ff5722;',
|
|
771
779
|
...msg,
|
|
@@ -786,7 +794,7 @@ export default class TeraFy {
|
|
|
786
794
|
*
|
|
787
795
|
* @returns {TeraFy} This chainable terafy instance
|
|
788
796
|
*/
|
|
789
|
-
set(key, value, options) {
|
|
797
|
+
set(key: string | object, value?: any, options?: { ignoreNullish?: boolean }) {
|
|
790
798
|
let settings = {
|
|
791
799
|
ignoreNullish: true,
|
|
792
800
|
...options,
|
|
@@ -794,12 +802,12 @@ export default class TeraFy {
|
|
|
794
802
|
|
|
795
803
|
if (typeof key == 'string') {
|
|
796
804
|
if (!settings.ignoreNullish || (value !== null && value !== undefined))
|
|
797
|
-
this.settings[key] = value;
|
|
805
|
+
(this.settings as any)[key] = value;
|
|
798
806
|
} else {
|
|
799
807
|
Object.assign(this.settings, key);
|
|
800
808
|
}
|
|
801
809
|
|
|
802
|
-
return this.toggleDevMode(this.settings.devMode);
|
|
810
|
+
return this.toggleDevMode(this.settings.devMode as boolean);
|
|
803
811
|
}
|
|
804
812
|
|
|
805
813
|
|
|
@@ -813,7 +821,7 @@ export default class TeraFy {
|
|
|
813
821
|
*
|
|
814
822
|
* @returns {TeraFy} This chainable terafy instance
|
|
815
823
|
*/
|
|
816
|
-
setIfDev(key, value, options) {
|
|
824
|
+
setIfDev(key: any, value: any, options?: any) {
|
|
817
825
|
if (!this.settings.devMode || value === undefined) return this;
|
|
818
826
|
return this.set(key, value, options);
|
|
819
827
|
}
|
|
@@ -827,8 +835,8 @@ export default class TeraFy {
|
|
|
827
835
|
*
|
|
828
836
|
* @returns {TeraFy} This chainable terafy instance
|
|
829
837
|
*/
|
|
830
|
-
use(source, options) {
|
|
831
|
-
let mod =
|
|
838
|
+
use(source: any, options?: any) {
|
|
839
|
+
let mod: any =
|
|
832
840
|
typeof source == 'function' ? new source(this, options)
|
|
833
841
|
: typeof source == 'object' ? source
|
|
834
842
|
: typeof source == 'string' ? (()=> { throw new Error('use(String) is not yet supported') })()
|
|
@@ -847,7 +855,7 @@ export default class TeraFy {
|
|
|
847
855
|
* @param {Object} target Initalied class instance to extend
|
|
848
856
|
* @param {Object} source Initalized source object to extend from
|
|
849
857
|
*/
|
|
850
|
-
mixin(target, source) {
|
|
858
|
+
mixin(target: any, source: any) {
|
|
851
859
|
// Iterate through the source object upwards extracting each prototype
|
|
852
860
|
let prototypeStack = [];
|
|
853
861
|
let node = source;
|
|
@@ -863,17 +871,17 @@ export default class TeraFy {
|
|
|
863
871
|
&& !prop.startsWith('__') // Ignore double underscore meta properties
|
|
864
872
|
)
|
|
865
873
|
.forEach(prop => {
|
|
866
|
-
if (typeof source[prop] == 'function') { // Inheriting function - glue onto object as non-editable, non-enumerable property
|
|
874
|
+
if (typeof (source as any)[prop] == 'function') { // Inheriting function - glue onto object as non-editable, non-enumerable property
|
|
867
875
|
Object.defineProperty(
|
|
868
876
|
target,
|
|
869
877
|
prop,
|
|
870
878
|
{
|
|
871
879
|
enumerable: false,
|
|
872
|
-
value: source[prop].bind(target), // Rebind functions
|
|
880
|
+
value: (source as any)[prop].bind(target), // Rebind functions
|
|
873
881
|
},
|
|
874
882
|
);
|
|
875
883
|
} else { // Everything else, just glue onto the object
|
|
876
|
-
target[prop] = source[prop];
|
|
884
|
+
target[prop] = (source as any)[prop];
|
|
877
885
|
}
|
|
878
886
|
})
|
|
879
887
|
)
|
|
@@ -891,7 +899,7 @@ export default class TeraFy {
|
|
|
891
899
|
*
|
|
892
900
|
* @returns {TeraFy} This chainable terafy instance
|
|
893
901
|
*/
|
|
894
|
-
toggleDevMode(devModeEnabled = 'toggle') {
|
|
902
|
+
toggleDevMode(devModeEnabled: 'toggle' | 'proxy' | boolean = 'toggle') {
|
|
895
903
|
if (devModeEnabled === 'toggle') {
|
|
896
904
|
this.settings.devMode = !this.settings.devMode;
|
|
897
905
|
} else if (devModeEnabled === 'proxy') {
|
|
@@ -908,7 +916,7 @@ export default class TeraFy {
|
|
|
908
916
|
this.settings.restrictOrigin = '*'; // Allow all upstream iframes
|
|
909
917
|
|
|
910
918
|
if (this.dom?.el) // Have we actually set up yet?
|
|
911
|
-
this.dom.el
|
|
919
|
+
this.dom.el!.classList.toggle('dev-mode', this.settings.devMode);
|
|
912
920
|
|
|
913
921
|
return this;
|
|
914
922
|
}
|
|
@@ -920,7 +928,7 @@ export default class TeraFy {
|
|
|
920
928
|
*
|
|
921
929
|
* @param {String|Boolean} [isFocused='toggle'] Whether to fullscreen the embedded component
|
|
922
930
|
*/
|
|
923
|
-
toggleFocus(isFocused = 'toggle') {
|
|
931
|
+
toggleFocus(isFocused: boolean | 'toggle' = 'toggle') {
|
|
924
932
|
this.debug('INFO', 2, 'Request focus', {isFocused});
|
|
925
933
|
globalThis.document.body.classList.toggle('tera-fy-focus', isFocused === 'toggle' ? undefined : isFocused);
|
|
926
934
|
}
|
|
@@ -1187,9 +1195,9 @@ export default class TeraFy {
|
|
|
1187
1195
|
*
|
|
1188
1196
|
* @returns {Promise<ProjectFile>} The eventually selected file, if in save mode new files are created as stubs
|
|
1189
1197
|
*/
|
|
1190
|
-
selectProjectFile(options) {
|
|
1198
|
+
selectProjectFile(options?: any) {
|
|
1191
1199
|
return this.rpc('selectProjectFile', options)
|
|
1192
|
-
.then(file => file
|
|
1200
|
+
.then((file: any) => file
|
|
1193
1201
|
? new ProjectFile({
|
|
1194
1202
|
tera: this,
|
|
1195
1203
|
...file,
|
|
@@ -1210,9 +1218,9 @@ export default class TeraFy {
|
|
|
1210
1218
|
*
|
|
1211
1219
|
* @returns {Promise<Array<ProjectFile>>} A collection of project files for the given project
|
|
1212
1220
|
*/
|
|
1213
|
-
getProjectFiles(options) {
|
|
1221
|
+
getProjectFiles(options?: any) {
|
|
1214
1222
|
return this.rpc('getProjectFiles', options)
|
|
1215
|
-
.then(files => files.map(file =>
|
|
1223
|
+
.then((files: any) => files.map((file: any) =>
|
|
1216
1224
|
new ProjectFile({
|
|
1217
1225
|
tera: this,
|
|
1218
1226
|
...file,
|
|
@@ -1245,9 +1253,9 @@ export default class TeraFy {
|
|
|
1245
1253
|
*
|
|
1246
1254
|
* @returns {Promise<ProjectFile>} The eventual fetched ProjectFile (or requested subkey)
|
|
1247
1255
|
*/
|
|
1248
|
-
getProjectFile(id, options) {
|
|
1256
|
+
getProjectFile(id: any, options?: any) {
|
|
1249
1257
|
return this.rpc('getProjectFile', id, options)
|
|
1250
|
-
.then(file => file
|
|
1258
|
+
.then((file: any) => file
|
|
1251
1259
|
? new ProjectFile({
|
|
1252
1260
|
tera: this,
|
|
1253
1261
|
...file,
|
|
@@ -1265,9 +1273,9 @@ export default class TeraFy {
|
|
|
1265
1273
|
* @param {String} name The name + relative directory path component
|
|
1266
1274
|
* @returns {Promise<ProjectFile>} The eventual ProjectFile created
|
|
1267
1275
|
*/
|
|
1268
|
-
createProjectFile(name) {
|
|
1276
|
+
createProjectFile(name: any) {
|
|
1269
1277
|
return this.rpc('createProjectFile', name)
|
|
1270
|
-
.then(file => file
|
|
1278
|
+
.then((file: any) => file
|
|
1271
1279
|
? new ProjectFile({
|
|
1272
1280
|
tera: this,
|
|
1273
1281
|
...file,
|
|
@@ -1498,4 +1506,4 @@ export default class TeraFy {
|
|
|
1498
1506
|
*/
|
|
1499
1507
|
|
|
1500
1508
|
// }}}
|
|
1501
|
-
}
|
|
1509
|
+
}
|
|
@@ -2,6 +2,19 @@ import {create as createDomain} from 'node:domain';
|
|
|
2
2
|
import detectPort from 'detect-port';
|
|
3
3
|
import Proxy from 'http-proxy';
|
|
4
4
|
|
|
5
|
+
// Define options interface based on JSDoc and settings
|
|
6
|
+
interface TeraProxyOptions {
|
|
7
|
+
force?: boolean;
|
|
8
|
+
autoStart?: boolean;
|
|
9
|
+
host?: string;
|
|
10
|
+
port?: number;
|
|
11
|
+
targetProtocol?: string;
|
|
12
|
+
targetHost?: string;
|
|
13
|
+
targetPort?: number;
|
|
14
|
+
portConflict?: 'ignore' | 'throw';
|
|
15
|
+
onLog?: (level: 'INFO' | 'WARN', ...msg: any[]) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
5
18
|
export class TeraProxy {
|
|
6
19
|
/**
|
|
7
20
|
* Setup a local loopback proxy for TERA-tools.com
|
|
@@ -27,8 +40,8 @@ export class TeraProxy {
|
|
|
27
40
|
targetProtocol: 'https',
|
|
28
41
|
targetHost: 'dev.tera-tools.com',
|
|
29
42
|
targetPort: 443,
|
|
30
|
-
portConflict: 'ignore',
|
|
31
|
-
onLog: (level, ...msg) => console.log(...msg),
|
|
43
|
+
portConflict: 'ignore' as 'ignore' | 'throw', // Add type assertion for stricter checking if needed elsewhere
|
|
44
|
+
onLog: (level: 'INFO' | 'WARN', ...msg: any[]) => console.log(...msg),
|
|
32
45
|
}
|
|
33
46
|
|
|
34
47
|
|
|
@@ -36,7 +49,7 @@ export class TeraProxy {
|
|
|
36
49
|
* Eventual proxy server when the plugin has booted
|
|
37
50
|
* @type {ProxyServer}
|
|
38
51
|
*/
|
|
39
|
-
proxyServer;
|
|
52
|
+
proxyServer: Proxy | undefined;
|
|
40
53
|
|
|
41
54
|
|
|
42
55
|
/**
|
|
@@ -49,7 +62,12 @@ export class TeraProxy {
|
|
|
49
62
|
|
|
50
63
|
return Promise.resolve()
|
|
51
64
|
.then(()=> detectPort(this.settings.port))
|
|
52
|
-
.then(gotPort =>
|
|
65
|
+
.then(gotPort => {
|
|
66
|
+
if (gotPort != this.settings.port) {
|
|
67
|
+
return Promise.reject('PORT-CONFLICT');
|
|
68
|
+
}
|
|
69
|
+
// Only return void if the port is available
|
|
70
|
+
})
|
|
53
71
|
.then(() => this.proxyServer = Proxy.createProxyServer({ // Create proxy pass-thru
|
|
54
72
|
changeOrigin: true,
|
|
55
73
|
target: {
|
|
@@ -58,20 +76,29 @@ export class TeraProxy {
|
|
|
58
76
|
port: this.settings.targetPort,
|
|
59
77
|
},
|
|
60
78
|
}))
|
|
61
|
-
.then(()=> new Promise((resolve, reject) => {
|
|
79
|
+
.then(()=> new Promise<void>((resolve, reject) => {
|
|
62
80
|
// Wrap listener in a domain so we can correctly catch EADDRINUSE
|
|
63
81
|
let domain = createDomain();
|
|
64
|
-
domain.on('error', err => {
|
|
82
|
+
domain.on('error', (err: NodeJS.ErrnoException) => { // Add type to err
|
|
65
83
|
if (err.code == 'EADDRINUSE') {
|
|
66
84
|
reject('PORT-CONFLICT');
|
|
67
85
|
} else {
|
|
68
86
|
reject(err);
|
|
69
87
|
}
|
|
70
88
|
});
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
89
|
+
// Run the server creation and listening within the domain
|
|
90
|
+
domain.run(() => {
|
|
91
|
+
if (!this.proxyServer) return reject(new Error('Proxy server not initialized')); // Guard against undefined proxyServer
|
|
92
|
+
this.proxyServer.listen(this.settings.port, this.settings.host)
|
|
93
|
+
// Handle errors on the proxy server itself, although domain should catch listen errors
|
|
94
|
+
this.proxyServer.on('error', (err: NodeJS.ErrnoException) => {
|
|
95
|
+
if (err.code == 'EADDRINUSE') {
|
|
96
|
+
reject('PORT-CONFLICT');
|
|
97
|
+
} else {
|
|
98
|
+
reject(err);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
});
|
|
75
102
|
}))
|
|
76
103
|
.catch(e => {
|
|
77
104
|
if (e === 'PORT-CONFLICT') {
|
|
@@ -79,7 +106,7 @@ export class TeraProxy {
|
|
|
79
106
|
this.settings.onLog('WARN', 'Port', this.settings.port, 'is already allocated - assuming TERA is already running locally and skipping proxy');
|
|
80
107
|
return false; // Do nothing
|
|
81
108
|
} else {
|
|
82
|
-
throw
|
|
109
|
+
throw e; // Throw the 'PORT-CONFLICT' string or a new Error
|
|
83
110
|
}
|
|
84
111
|
} else {
|
|
85
112
|
throw e; // Re-throw everything else
|
|
@@ -94,15 +121,15 @@ export class TeraProxy {
|
|
|
94
121
|
*/
|
|
95
122
|
stop() {
|
|
96
123
|
return Promise.resolve()
|
|
97
|
-
.then(()=> this.proxyServer && new Promise(resolve => this.proxyServer
|
|
124
|
+
.then(()=> this.proxyServer && new Promise<void>(resolve => this.proxyServer!.close(()=> resolve()))) // Use non-null assertion if sure it exists here
|
|
98
125
|
}
|
|
99
126
|
|
|
100
127
|
|
|
101
|
-
constructor(options) {
|
|
128
|
+
constructor(options?: TeraProxyOptions) { // Add type annotation and make optional
|
|
102
129
|
if (options) Object.assign(this.settings, options);
|
|
103
130
|
|
|
104
131
|
// Auto start?
|
|
105
|
-
if (
|
|
132
|
+
if (this.settings.autoStart) this.start(); // Use resolved settings.autoStart
|
|
106
133
|
}
|
|
107
134
|
}
|
|
108
135
|
|
|
@@ -113,6 +140,6 @@ export class TeraProxy {
|
|
|
113
140
|
* @param {Object} [options] Options to pass to the Proxy module
|
|
114
141
|
* @returns {TeraProxy} A TeraProxy instance
|
|
115
142
|
*/
|
|
116
|
-
export default function(options) {
|
|
143
|
+
export default function(options?: TeraProxyOptions) { // Add type annotation and make optional
|
|
117
144
|
return new TeraProxy(options);
|
|
118
|
-
}
|
|
145
|
+
}
|