@iebh/tera-fy 2.3.0 → 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 +22 -0
- package/api.md +35 -36
- 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 +22 -8
- package/dist/lib/terafy.server.js +54 -58
- 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 +62 -62
- package/lib/terafy.proxy.ts +8 -5
- package/lib/terafy.server.ts +75 -64
- 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
package/lib/terafy.server.ts
CHANGED
|
@@ -1,19 +1,36 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-redundant-type-constituents */
|
|
1
2
|
// Global 'app' declaration
|
|
2
|
-
declare
|
|
3
|
+
declare let app: any;
|
|
3
4
|
|
|
4
5
|
// Global window augmentation
|
|
5
6
|
declare global {
|
|
6
7
|
interface Window {
|
|
8
|
+
// eslint-disable-next-line no-unused-vars
|
|
7
9
|
panic(text: any): void;
|
|
8
10
|
}
|
|
9
11
|
}
|
|
10
12
|
|
|
13
|
+
interface UiWindowPermissions {
|
|
14
|
+
popup?: boolean;
|
|
15
|
+
location?: boolean;
|
|
16
|
+
menubar?: boolean;
|
|
17
|
+
status?: boolean;
|
|
18
|
+
scrollbars?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface UiWindowOptions {
|
|
22
|
+
width?: number;
|
|
23
|
+
height?: number;
|
|
24
|
+
center?: boolean;
|
|
25
|
+
permissions?: UiWindowPermissions;
|
|
26
|
+
}
|
|
27
|
+
|
|
11
28
|
import {cloneDeep} from 'lodash-es';
|
|
12
29
|
import mixin from '#utils/mixin';
|
|
13
30
|
import {nanoid} from 'nanoid';
|
|
14
31
|
import pathTools from '#utils/pathTools';
|
|
15
32
|
import promiseDefer from '#utils/pDefer';
|
|
16
|
-
// @ts-
|
|
33
|
+
// @ts-expect-error TODO: Remove when reflib gets declaration file
|
|
17
34
|
import Reflib from '@iebh/reflib';
|
|
18
35
|
import {reactive} from 'vue';
|
|
19
36
|
|
|
@@ -23,7 +40,6 @@ import {reactive} from 'vue';
|
|
|
23
40
|
* @class TeraFyServer
|
|
24
41
|
*/
|
|
25
42
|
|
|
26
|
-
/* globals globalThis, app */
|
|
27
43
|
export default class TeraFyServer {
|
|
28
44
|
|
|
29
45
|
/**
|
|
@@ -120,7 +136,7 @@ export default class TeraFyServer {
|
|
|
120
136
|
case TeraFyServer.SERVERMODE_TERA:
|
|
121
137
|
case TeraFyServer.SERVERMODE_FRAME: {
|
|
122
138
|
// Server is the top-level window so we need to send messages to an embedded iFrame
|
|
123
|
-
|
|
139
|
+
const iFrame = document.querySelector<HTMLIFrameElement>('iframe#external');
|
|
124
140
|
if (!iFrame) {
|
|
125
141
|
this.debug('INFO', 2, 'Cannot locate TERA-FY top-level->iFrame#external - maybe there is none');
|
|
126
142
|
return mixin(this, {
|
|
@@ -211,7 +227,7 @@ export default class TeraFyServer {
|
|
|
211
227
|
send(message: any): Promise<any> {
|
|
212
228
|
if (!this.messageEvent?.source) throw new Error('send() requires a messageEvent with a source');
|
|
213
229
|
|
|
214
|
-
|
|
230
|
+
const id = nanoid();
|
|
215
231
|
|
|
216
232
|
this.acceptPostboxes[id] = {}; // Stub for the deferred promise
|
|
217
233
|
this.acceptPostboxes[id].promise = new Promise((resolve, reject) => {
|
|
@@ -289,7 +305,7 @@ export default class TeraFyServer {
|
|
|
289
305
|
// Ignore messages from the same origin (potential loops)
|
|
290
306
|
if (typeof window !== 'undefined' && rawMessage.origin === window.location.origin) return;
|
|
291
307
|
|
|
292
|
-
|
|
308
|
+
const message = rawMessage.data;
|
|
293
309
|
// Ensure message is an object and has TERA property
|
|
294
310
|
if (typeof message !== 'object' || message === null || !message.TERA) return;
|
|
295
311
|
this.debug('INFO', 3, 'Recieved message', message);
|
|
@@ -432,14 +448,14 @@ export default class TeraFyServer {
|
|
|
432
448
|
* @returns {Promise<User>} The current logged in user or null if none
|
|
433
449
|
*/
|
|
434
450
|
getUser(options?: any): Promise<any | null> {
|
|
435
|
-
|
|
451
|
+
const settings = {
|
|
436
452
|
forceRetry: false,
|
|
437
453
|
waitPromises: true,
|
|
438
454
|
...options,
|
|
439
455
|
};
|
|
440
456
|
|
|
441
|
-
|
|
442
|
-
|
|
457
|
+
const $auth = app.service('$auth');
|
|
458
|
+
const $subscriptions = app.service('$subscriptions');
|
|
443
459
|
|
|
444
460
|
return Promise.resolve()
|
|
445
461
|
.then(()=> settings.waitPromises && Promise.all([
|
|
@@ -584,7 +600,7 @@ export default class TeraFyServer {
|
|
|
584
600
|
try {
|
|
585
601
|
lsState = JSON.parse(lsState);
|
|
586
602
|
|
|
587
|
-
|
|
603
|
+
const $auth = app.service('$auth');
|
|
588
604
|
$auth.state = 'user';
|
|
589
605
|
$auth.ready = true;
|
|
590
606
|
$auth.isLoggedIn = true;
|
|
@@ -605,7 +621,7 @@ export default class TeraFyServer {
|
|
|
605
621
|
|
|
606
622
|
this.debug('INFO', 4, 'localStorage failed - using popup auth instead');
|
|
607
623
|
|
|
608
|
-
|
|
624
|
+
const focusContent = document.createElement('div');
|
|
609
625
|
focusContent.innerHTML = '<div>Authenticate with <a href="https://tera-tools.com" target="_blank">TERA-tools.com</a></div>'
|
|
610
626
|
+ '<div class="mt-2"><a class="btn btn-light">Open Popup...</a></div>';
|
|
611
627
|
|
|
@@ -615,13 +631,13 @@ export default class TeraFyServer {
|
|
|
615
631
|
);
|
|
616
632
|
|
|
617
633
|
// Create a deferred promise which will (eventually) resolve when the downstream window signals its ready
|
|
618
|
-
|
|
634
|
+
const waitOnWindowAuth = promiseDefer();
|
|
619
635
|
|
|
620
636
|
// Create a listener for the message from the downstream window to resolve the promise
|
|
621
|
-
|
|
637
|
+
const listenMessages = ({data}: {data: any}) => {
|
|
622
638
|
this.debug('INFO', 3, 'Recieved message from popup window', {data});
|
|
623
639
|
if (data.TERA && data.action == 'popupUserState' && data.user) { // Signal sent from landing page - we're logged in, yey!
|
|
624
|
-
|
|
640
|
+
const $auth = app.service('$auth');
|
|
625
641
|
|
|
626
642
|
// Accept user polyfill from opener
|
|
627
643
|
$auth.state = 'user';
|
|
@@ -686,7 +702,7 @@ export default class TeraFyServer {
|
|
|
686
702
|
* @returns {Promise<Project|null>} The currently active project, if any
|
|
687
703
|
*/
|
|
688
704
|
getProject(): Promise<any | null> {
|
|
689
|
-
|
|
705
|
+
const $projects = app.service('$projects');
|
|
690
706
|
|
|
691
707
|
return $projects.promise()
|
|
692
708
|
.then(()=> $projects.active
|
|
@@ -707,7 +723,7 @@ export default class TeraFyServer {
|
|
|
707
723
|
* @returns {Promise<Array<Project>>} Collection of projects the user has access to
|
|
708
724
|
*/
|
|
709
725
|
getProjects(): Promise<any[]> {
|
|
710
|
-
|
|
726
|
+
const $projects = app.service('$projects');
|
|
711
727
|
|
|
712
728
|
return $projects.promise()
|
|
713
729
|
.then(()=> $projects.list.map((project: any) => ({
|
|
@@ -744,7 +760,7 @@ export default class TeraFyServer {
|
|
|
744
760
|
* @returns {Promise<Project>} The active project
|
|
745
761
|
*/
|
|
746
762
|
requireProject(options?: any): Promise<any> {
|
|
747
|
-
|
|
763
|
+
const settings = {
|
|
748
764
|
autoRequireUser: true,
|
|
749
765
|
autoSetActiveProject: true,
|
|
750
766
|
title: 'Select a project to work with',
|
|
@@ -760,7 +776,7 @@ export default class TeraFyServer {
|
|
|
760
776
|
if (active) return active; // Use active project
|
|
761
777
|
|
|
762
778
|
return new Promise((resolve, reject) => {
|
|
763
|
-
|
|
779
|
+
const askProject = (): Promise<any> => Promise.resolve()
|
|
764
780
|
.then(()=> this.selectProject({
|
|
765
781
|
allowCancel: false,
|
|
766
782
|
}))
|
|
@@ -801,7 +817,7 @@ export default class TeraFyServer {
|
|
|
801
817
|
* @returns {Promise<Project>} The active project
|
|
802
818
|
*/
|
|
803
819
|
selectProject(options?: any): Promise<any> {
|
|
804
|
-
|
|
820
|
+
const settings = {
|
|
805
821
|
title: 'Select a project to work with',
|
|
806
822
|
allowCancel: true,
|
|
807
823
|
setActive: false,
|
|
@@ -886,7 +902,7 @@ export default class TeraFyServer {
|
|
|
886
902
|
* @returns {Promise<Object>} The current project state snapshot
|
|
887
903
|
*/
|
|
888
904
|
getProjectState(options?: any): Promise<any> {
|
|
889
|
-
|
|
905
|
+
const settings = {
|
|
890
906
|
autoRequire: true,
|
|
891
907
|
paths: null,
|
|
892
908
|
...options,
|
|
@@ -919,7 +935,7 @@ export default class TeraFyServer {
|
|
|
919
935
|
* @returns {Promise<*>} A promise which resolves to `value` when the operation has been dispatched to the server and saved
|
|
920
936
|
*/
|
|
921
937
|
setProjectState(path: string | string[], value: any, options?: any): Promise<any> {
|
|
922
|
-
|
|
938
|
+
const settings = {
|
|
923
939
|
strategy: 'set',
|
|
924
940
|
...options,
|
|
925
941
|
};
|
|
@@ -962,7 +978,7 @@ export default class TeraFyServer {
|
|
|
962
978
|
let settings = { ...options }; // Initialize settings from the third argument if present
|
|
963
979
|
if (!app.service('$projects').active) throw new Error('No active project');
|
|
964
980
|
|
|
965
|
-
|
|
981
|
+
const target = app.service('$projects').active;
|
|
966
982
|
let actualValue: any;
|
|
967
983
|
|
|
968
984
|
if (typeof path == 'string' || Array.isArray(path)) { // Called as (path, value, options?) Set sub-object
|
|
@@ -1049,12 +1065,11 @@ export default class TeraFyServer {
|
|
|
1049
1065
|
* @param {Boolean} [options.allowCancel=true] Allow cancelling the operation. Will throw `'CANCEL'` as the promise rejection if acationed
|
|
1050
1066
|
* @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing
|
|
1051
1067
|
* @param {Boolean} [options.showHiddenFiles=false] Whether hidden data.json files should be shown
|
|
1052
|
-
* @param {FileFilters} [options.filter] Optional file filters
|
|
1053
1068
|
*
|
|
1054
1069
|
* @returns {Promise<ProjectFile>} The eventually selected file, if in save mode new files are created as stubs
|
|
1055
1070
|
*/
|
|
1056
1071
|
selectProjectFile(options?: any): Promise<any> {
|
|
1057
|
-
|
|
1072
|
+
const settings = {
|
|
1058
1073
|
title: 'Select a file',
|
|
1059
1074
|
hint: null,
|
|
1060
1075
|
save: false,
|
|
@@ -1114,7 +1129,7 @@ export default class TeraFyServer {
|
|
|
1114
1129
|
* @returns {Promise<Array<ProjectFile>>} A collection of project files for the given project
|
|
1115
1130
|
*/
|
|
1116
1131
|
getProjectFiles(options?: any): Promise<any[]> {
|
|
1117
|
-
|
|
1132
|
+
const settings = {
|
|
1118
1133
|
autoRequire: true,
|
|
1119
1134
|
lazy: true,
|
|
1120
1135
|
meta: true,
|
|
@@ -1147,7 +1162,7 @@ export default class TeraFyServer {
|
|
|
1147
1162
|
* @returns {Promise<ProjectFile>} The eventual fetched ProjectFile (or requested subkey)
|
|
1148
1163
|
*/
|
|
1149
1164
|
getProjectFile(name: string, options?: any): Promise<any> {
|
|
1150
|
-
|
|
1165
|
+
const settings = {
|
|
1151
1166
|
subkey: null,
|
|
1152
1167
|
cache: true,
|
|
1153
1168
|
...(typeof options == 'string' ? {subkey: options} : options),
|
|
@@ -1190,7 +1205,7 @@ export default class TeraFyServer {
|
|
|
1190
1205
|
// Recursively search for the file to handle searching folders
|
|
1191
1206
|
return findFileRecursively(files, name);
|
|
1192
1207
|
})
|
|
1193
|
-
.then((file: any) => file && settings.subkey ? (file
|
|
1208
|
+
.then((file: any) => file && settings.subkey ? (file)[settings.subkey] : file)
|
|
1194
1209
|
}
|
|
1195
1210
|
|
|
1196
1211
|
/**
|
|
@@ -1204,7 +1219,7 @@ export default class TeraFyServer {
|
|
|
1204
1219
|
* @returns {*} The file contents in the requested format
|
|
1205
1220
|
*/
|
|
1206
1221
|
getProjectFileContents(id: string, options?: any): Promise<any> {
|
|
1207
|
-
|
|
1222
|
+
const settings = {
|
|
1208
1223
|
format: 'blob',
|
|
1209
1224
|
...options,
|
|
1210
1225
|
};
|
|
@@ -1397,7 +1412,7 @@ export default class TeraFyServer {
|
|
|
1397
1412
|
|
|
1398
1413
|
if (fileContents === undefined) throw new Error('setProjectFileContents requires contents to save.');
|
|
1399
1414
|
|
|
1400
|
-
|
|
1415
|
+
const settings = {
|
|
1401
1416
|
id: fileId,
|
|
1402
1417
|
autoRequire: true,
|
|
1403
1418
|
hint: null,
|
|
@@ -1474,7 +1489,7 @@ export default class TeraFyServer {
|
|
|
1474
1489
|
|
|
1475
1490
|
let cleanFolderPath = folderPath.trim();
|
|
1476
1491
|
if (cleanFolderPath.startsWith('/')) {
|
|
1477
|
-
cleanFolderPath = cleanFolderPath.
|
|
1492
|
+
cleanFolderPath = cleanFolderPath.slice(1);
|
|
1478
1493
|
}
|
|
1479
1494
|
if (cleanFolderPath.endsWith('/')) {
|
|
1480
1495
|
cleanFolderPath = cleanFolderPath.slice(0, -1);
|
|
@@ -1536,7 +1551,7 @@ export default class TeraFyServer {
|
|
|
1536
1551
|
|
|
1537
1552
|
let cleanFolderPath = folderPath.trim();
|
|
1538
1553
|
if (cleanFolderPath.startsWith('/')) {
|
|
1539
|
-
cleanFolderPath = cleanFolderPath.
|
|
1554
|
+
cleanFolderPath = cleanFolderPath.slice(1);
|
|
1540
1555
|
}
|
|
1541
1556
|
if (cleanFolderPath.endsWith('/')) {
|
|
1542
1557
|
cleanFolderPath = cleanFolderPath.slice(0, -1);
|
|
@@ -1603,7 +1618,7 @@ export default class TeraFyServer {
|
|
|
1603
1618
|
* @returns {Promise<Array<Ref>>} A collection of references from the selected file
|
|
1604
1619
|
*/
|
|
1605
1620
|
selectProjectLibrary(options?: any): Promise<any[]> {
|
|
1606
|
-
|
|
1621
|
+
const settings = {
|
|
1607
1622
|
title: 'Select a citation library',
|
|
1608
1623
|
hint: null,
|
|
1609
1624
|
allowUpload: true,
|
|
@@ -1613,7 +1628,7 @@ export default class TeraFyServer {
|
|
|
1613
1628
|
autoRequire: true,
|
|
1614
1629
|
filters: {
|
|
1615
1630
|
library: true,
|
|
1616
|
-
...
|
|
1631
|
+
...options?.filters, // Use filters from options if provided
|
|
1617
1632
|
},
|
|
1618
1633
|
...options,
|
|
1619
1634
|
};
|
|
@@ -1643,16 +1658,16 @@ export default class TeraFyServer {
|
|
|
1643
1658
|
* @returns {Promise<Array<Ref>>|Promise<*>} A collection of references (default bevahiour) or a whatever format was requested
|
|
1644
1659
|
*/
|
|
1645
1660
|
getProjectLibrary(id: string, options?: any): Promise<any> {
|
|
1646
|
-
|
|
1661
|
+
const settings = {
|
|
1647
1662
|
format: 'pojo',
|
|
1648
1663
|
autoRequire: true,
|
|
1664
|
+
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
|
|
1649
1665
|
filter: (file: any) => true, // Default filter
|
|
1650
|
-
//
|
|
1651
|
-
find: (files: any[]) => files.at(0), // Default find
|
|
1666
|
+
find: (files: any[]) => files[0], // Default find
|
|
1652
1667
|
...options,
|
|
1653
1668
|
};
|
|
1654
1669
|
|
|
1655
|
-
|
|
1670
|
+
const filePath: string = app.service('$projects').decodeFilePath(id);
|
|
1656
1671
|
|
|
1657
1672
|
return Promise.resolve()
|
|
1658
1673
|
.then(()=> settings.autoRequire && this.requireProject())
|
|
@@ -1727,7 +1742,7 @@ export default class TeraFyServer {
|
|
|
1727
1742
|
|
|
1728
1743
|
if (libraryRefs === undefined) throw new Error('setProjectLibrary requires refs to save.');
|
|
1729
1744
|
|
|
1730
|
-
|
|
1745
|
+
const settings = {
|
|
1731
1746
|
id: fileId,
|
|
1732
1747
|
refs: libraryRefs,
|
|
1733
1748
|
format: 'auto',
|
|
@@ -1877,7 +1892,7 @@ export default class TeraFyServer {
|
|
|
1877
1892
|
* @returns {Promise} A promise which resolves when the alert has been dismissed
|
|
1878
1893
|
*/
|
|
1879
1894
|
uiAlert(text: string | any, options?: any): Promise<void> {
|
|
1880
|
-
|
|
1895
|
+
const settings = {
|
|
1881
1896
|
body: 'Alert!',
|
|
1882
1897
|
isHtml: false,
|
|
1883
1898
|
title: 'TERA',
|
|
@@ -1917,7 +1932,7 @@ export default class TeraFyServer {
|
|
|
1917
1932
|
* @returns {Promise} A promise which resolves with `Promise.resolve('OK')` or rejects with `Promise.reject('CANCEL')`
|
|
1918
1933
|
*/
|
|
1919
1934
|
uiConfirm(text: string | any, options?: any): Promise<'OK'> {
|
|
1920
|
-
|
|
1935
|
+
const settings = {
|
|
1921
1936
|
body: 'Confirm?',
|
|
1922
1937
|
isHtml: false,
|
|
1923
1938
|
title: 'TERA',
|
|
@@ -1946,7 +1961,7 @@ export default class TeraFyServer {
|
|
|
1946
1961
|
},
|
|
1947
1962
|
],
|
|
1948
1963
|
})
|
|
1949
|
-
.then(()=> 'OK' as
|
|
1964
|
+
.then(()=> 'OK' as const) // Resolve with 'OK' if OK button clicked
|
|
1950
1965
|
.catch(()=> Promise.reject('CANCEL')) // Reject with 'CANCEL' if Cancel button clicked or closed
|
|
1951
1966
|
);
|
|
1952
1967
|
}
|
|
@@ -1956,7 +1971,7 @@ export default class TeraFyServer {
|
|
|
1956
1971
|
* Present some JSON to the user
|
|
1957
1972
|
*
|
|
1958
1973
|
* @function uiJson
|
|
1959
|
-
* @param {String|Object}
|
|
1974
|
+
* @param {String|Object} data Data to display
|
|
1960
1975
|
*
|
|
1961
1976
|
* @param {Object} [options] Additional options to mutate behaviour
|
|
1962
1977
|
* @param {String} [options.body=""] The body text to display above the JSON
|
|
@@ -1967,15 +1982,11 @@ export default class TeraFyServer {
|
|
|
1967
1982
|
* @returns {Promise} A promise which resolves with `Promise.resolve('OK')`
|
|
1968
1983
|
*/
|
|
1969
1984
|
uiJson(data: any, options?: any): Promise<'OK'> {
|
|
1970
|
-
|
|
1985
|
+
const settings = {
|
|
1971
1986
|
body: '',
|
|
1972
1987
|
isHtml: false,
|
|
1973
1988
|
title: 'TERA',
|
|
1974
|
-
...
|
|
1975
|
-
typeof data == 'string' ? {data: JSON.parse(data), ...options}
|
|
1976
|
-
: typeof data == 'object' && !data.body && !data.title ? {data, ...options}
|
|
1977
|
-
: options
|
|
1978
|
-
),
|
|
1989
|
+
...options,
|
|
1979
1990
|
};
|
|
1980
1991
|
|
|
1981
1992
|
return this.requestFocus(()=>
|
|
@@ -1986,10 +1997,10 @@ export default class TeraFyServer {
|
|
|
1986
1997
|
componentProps: {
|
|
1987
1998
|
body: settings.body,
|
|
1988
1999
|
isHtml: settings.isHtml,
|
|
1989
|
-
data:
|
|
2000
|
+
data: data,
|
|
1990
2001
|
},
|
|
1991
2002
|
})
|
|
1992
|
-
.then(()=> 'OK' as
|
|
2003
|
+
.then(()=> 'OK' as const) // Resolve with 'OK' if OK button clicked
|
|
1993
2004
|
.catch(()=> Promise.reject('CANCEL')) // Reject with 'CANCEL' if Cancel button clicked or closed
|
|
1994
2005
|
);
|
|
1995
2006
|
}
|
|
@@ -2028,7 +2039,7 @@ export default class TeraFyServer {
|
|
|
2028
2039
|
* @returns {Promise} A promise which resolves when the dialog has been updated
|
|
2029
2040
|
*/
|
|
2030
2041
|
uiProgress(options?: any): Promise<void> {
|
|
2031
|
-
|
|
2042
|
+
const currentOptions = options === false ? {close: true} : options || {};
|
|
2032
2043
|
|
|
2033
2044
|
if (currentOptions.close) { // Asked to close the dialog
|
|
2034
2045
|
const closePromise = this._uiProgress.promise
|
|
@@ -2093,7 +2104,7 @@ export default class TeraFyServer {
|
|
|
2093
2104
|
* @returns {Promise<*>} Either the eventual user value or a throw with `Promise.reject('CANCEL')`
|
|
2094
2105
|
*/
|
|
2095
2106
|
uiPrompt(text: string | any, options?: any): Promise<any> {
|
|
2096
|
-
|
|
2107
|
+
const settings = {
|
|
2097
2108
|
body: '',
|
|
2098
2109
|
isHtml: false,
|
|
2099
2110
|
title: 'Input required',
|
|
@@ -2174,11 +2185,11 @@ export default class TeraFyServer {
|
|
|
2174
2185
|
*
|
|
2175
2186
|
* @returns {WindowProxy} The opened window object (if `noopener` is not set in permissions)
|
|
2176
2187
|
*/
|
|
2177
|
-
uiWindow(url: string | URL, options?:
|
|
2188
|
+
uiWindow(url: string | URL, options?: UiWindowOptions): WindowProxy | null {
|
|
2178
2189
|
// Ensure this runs only in browser context
|
|
2179
2190
|
if (typeof window === 'undefined' || typeof screen === 'undefined') return null;
|
|
2180
2191
|
|
|
2181
|
-
|
|
2192
|
+
const settings = {
|
|
2182
2193
|
width: 500,
|
|
2183
2194
|
height: 600,
|
|
2184
2195
|
center: true,
|
|
@@ -2223,7 +2234,7 @@ export default class TeraFyServer {
|
|
|
2223
2234
|
// Ensure this runs only in browser context
|
|
2224
2235
|
if (typeof window === 'undefined' || typeof document === 'undefined') return;
|
|
2225
2236
|
|
|
2226
|
-
|
|
2237
|
+
const settings = {
|
|
2227
2238
|
logo: false,
|
|
2228
2239
|
...options,
|
|
2229
2240
|
};
|
|
@@ -2240,7 +2251,7 @@ export default class TeraFyServer {
|
|
|
2240
2251
|
|
|
2241
2252
|
let compiledContent: Element;
|
|
2242
2253
|
if (typeof content == 'string') {
|
|
2243
|
-
|
|
2254
|
+
const el = document.createElement('div')
|
|
2244
2255
|
el.innerHTML = content;
|
|
2245
2256
|
// If the string contained multiple top-level elements, wrap them
|
|
2246
2257
|
compiledContent = el.children.length === 1 ? el.firstElementChild! : el;
|
|
@@ -2252,7 +2263,7 @@ export default class TeraFyServer {
|
|
|
2252
2263
|
compiledContent.classList.add('tera-fy-uiSplat');
|
|
2253
2264
|
|
|
2254
2265
|
if (settings.logo) {
|
|
2255
|
-
|
|
2266
|
+
const logoEl = document.createElement('div');
|
|
2256
2267
|
logoEl.innerHTML = `<img src="${typeof settings.logo == 'string' ? settings.logo : '/assets/logo/logo.svg'}" class="img-logo"/>`;
|
|
2257
2268
|
// Prepend logo within the content element
|
|
2258
2269
|
compiledContent.prepend(logoEl);
|
|
@@ -2264,14 +2275,14 @@ export default class TeraFyServer {
|
|
|
2264
2275
|
|
|
2265
2276
|
// Utility - debug() {{{
|
|
2266
2277
|
|
|
2267
|
-
/* eslint-disable jsdoc/check-param-names */
|
|
2268
2278
|
/**
|
|
2269
|
-
* Debugging output function
|
|
2270
|
-
* This function will only act if `settings.devMode` is truthy
|
|
2279
|
+
* Debugging output function.
|
|
2280
|
+
* This function will only act if `settings.devMode` is truthy.
|
|
2271
2281
|
*
|
|
2272
|
-
* @param {
|
|
2273
|
-
*
|
|
2274
|
-
*
|
|
2282
|
+
* @param {...any} inputArgs The arguments to process for debugging. The function signature is flexible: `debug([method], [verboseLevel], ...msg)`.
|
|
2283
|
+
* - The first argument can optionally be a logging method string: 'INFO', 'LOG', 'WARN', or 'ERROR'. Defaults to 'LOG'.
|
|
2284
|
+
* - The next argument can optionally be a numeric verbosity level. The message is ignored if `settings.verbosity` is lower than this level. Defaults to 1.
|
|
2285
|
+
* - All subsequent arguments are passed to the console as the log message.
|
|
2275
2286
|
*/
|
|
2276
2287
|
debug(...inputArgs: any[]): void {
|
|
2277
2288
|
// Ensure console exists
|
|
@@ -2280,7 +2291,7 @@ export default class TeraFyServer {
|
|
|
2280
2291
|
|
|
2281
2292
|
let method: keyof Console = 'log'; // Default method
|
|
2282
2293
|
let verboseLevel = 1;
|
|
2283
|
-
|
|
2294
|
+
const msgArgs = [...inputArgs]; // Copy args to modify
|
|
2284
2295
|
|
|
2285
2296
|
// Argument mangling for prefix method + verbosity level {{{
|
|
2286
2297
|
if (typeof msgArgs[0] == 'string' && ['INFO', 'LOG', 'WARN', 'ERROR'].includes(msgArgs[0].toUpperCase())) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iebh/tera-fy",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2",
|
|
4
4
|
"description": "TERA website worker",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "esbuild --platform=browser --format=esm --bundle lib/terafy.client.ts --outfile=dist/terafy.js --minify --serve --servedir=.",
|
|
@@ -113,12 +113,12 @@
|
|
|
113
113
|
"mitt": "^3.0.1",
|
|
114
114
|
"nanoid": "^5.1.2",
|
|
115
115
|
"p-retry": "^6.2.1",
|
|
116
|
-
"release-it": "^
|
|
116
|
+
"release-it": "^19.2.4",
|
|
117
117
|
"uuid": "^11.1.0"
|
|
118
118
|
},
|
|
119
119
|
"devDependencies": {
|
|
120
120
|
"@momsfriendlydevco/eslint-config": "^2.3.1",
|
|
121
|
-
"@release-it/conventional-changelog": "^10.0.
|
|
121
|
+
"@release-it/conventional-changelog": "^10.0.5",
|
|
122
122
|
"@types/detect-port": "^2.0.0",
|
|
123
123
|
"@types/http-proxy": "^1.17.16",
|
|
124
124
|
"@types/lodash-es": "^4.17.12",
|
|
@@ -127,10 +127,12 @@
|
|
|
127
127
|
"@typescript-eslint/eslint-plugin": "^8.41.0",
|
|
128
128
|
"@typescript-eslint/parser": "^8.41.0",
|
|
129
129
|
"concurrently": "^9.1.2",
|
|
130
|
+
"conventional-changelog-eslint": "^6.0.0",
|
|
130
131
|
"documentation": "^14.0.3",
|
|
131
132
|
"esbuild": "^0.25.0",
|
|
132
133
|
"eslint": "^9.34.0",
|
|
133
134
|
"eslint-plugin": "^1.0.1",
|
|
135
|
+
"globals": "^16.5.0",
|
|
134
136
|
"nodemon": "^3.1.9",
|
|
135
137
|
"typescript": "^5.9.2",
|
|
136
138
|
"typescript-eslint": "^8.41.0"
|
package/plugins/base.ts
CHANGED
|
@@ -11,7 +11,7 @@ export default class TeraFyPlugin {
|
|
|
11
11
|
/**
|
|
12
12
|
* Optional function to be included when the main TeraFyClient is initalized
|
|
13
13
|
*/
|
|
14
|
-
init() {}
|
|
14
|
+
init(): any {}
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -20,6 +20,7 @@ export default class TeraFyPlugin {
|
|
|
20
20
|
* @param {TeraFy} terafy The TeraFy client this plugin is being initalized against
|
|
21
21
|
* @param {Object} [options] Additional options to mutate behaviour
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
24
|
+
constructor(terafy: TeraFy, options: object) { // eslint-disable-line no-unused-vars
|
|
24
25
|
}
|
|
25
26
|
}
|
package/plugins/firebase.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {initializeApp as Firebase
|
|
2
|
-
import {getFirestore as Firestore
|
|
1
|
+
import {initializeApp as Firebase} from 'firebase/app';
|
|
2
|
+
import {getFirestore as Firestore} from 'firebase/firestore';
|
|
3
3
|
import Supabasey from '@iebh/supabasey';
|
|
4
4
|
import Syncro from '../lib/syncro/syncro.js';
|
|
5
5
|
import TeraFyPluginBase from './base.js';
|
|
@@ -23,24 +23,25 @@ export default class TeraFyPluginFirebase extends TeraFyPluginBase {
|
|
|
23
23
|
// Declare properties expected by the class methods or potentially inherited
|
|
24
24
|
getCredentials!: () => Promise<Record<string, any>>;
|
|
25
25
|
requireProject!: () => Promise<{ id: string }>;
|
|
26
|
+
// eslint-disable-next-line no-unused-vars
|
|
26
27
|
debug!: (...args: any[]) => void;
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* @interface
|
|
31
32
|
* The Syncro#reactive option to use when creating new Syncro instances
|
|
32
|
-
* This is expected to be
|
|
33
|
+
* This is expected to be overridden by other plugins
|
|
33
34
|
* If falsy the Syncro module will fall back to its internal (POJO only) getReactive() function
|
|
34
35
|
*
|
|
35
36
|
* @name getReactive
|
|
36
37
|
* @type {Function} A reactive function as defined in Syncro
|
|
37
38
|
*/
|
|
38
|
-
getReactive?:
|
|
39
|
+
getReactive?: () => any;
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
43
|
* Setup Firebase + Firestore + Supabase
|
|
43
|
-
* Default credentials (Firebase + Supabase) will be retrieved from `getCredentials()` unless
|
|
44
|
+
* Default credentials (Firebase + Supabase) will be retrieved from `getCredentials()` unless overridden here
|
|
44
45
|
*
|
|
45
46
|
* @param {Object} options Additional options to mutate behaviour (defaults to the main teraFy settings)
|
|
46
47
|
* @param {String} [options.firebaseApiKey] Firebase API key
|
|
@@ -53,7 +54,7 @@ export default class TeraFyPluginFirebase extends TeraFyPluginBase {
|
|
|
53
54
|
* @returns {Promise} A Promise which will resolve when the init process has completed
|
|
54
55
|
*/
|
|
55
56
|
async init(options?: any): Promise<void> { // Add optional '?' and type 'any', keep async Promise<void>
|
|
56
|
-
|
|
57
|
+
const settings = {
|
|
57
58
|
firebaseApiKey: null,
|
|
58
59
|
firebaseAuthDomain: null,
|
|
59
60
|
firebaseProjectId: null,
|
|
@@ -64,7 +65,7 @@ export default class TeraFyPluginFirebase extends TeraFyPluginBase {
|
|
|
64
65
|
...options,
|
|
65
66
|
};
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
const emptyValues = Object.keys(settings).filter(k => k === null);
|
|
68
69
|
if (emptyValues.length > 0)
|
|
69
70
|
throw new Error('Firebase plugin requires mandatory options: ' + emptyValues.join(', '));
|
|
70
71
|
|
|
@@ -88,7 +89,7 @@ export default class TeraFyPluginFirebase extends TeraFyPluginBase {
|
|
|
88
89
|
/**
|
|
89
90
|
* Mount the given namespace against `namespaces[name]`
|
|
90
91
|
*
|
|
91
|
-
* @param {'_PROJECT'|String} name The name/Syncro path of the namespace to mount (or '_PROJECT' for the project
|
|
92
|
+
* @param {'_PROJECT'|String} name The name/Syncro path of the namespace to mount (or '_PROJECT' for the project mount-point)
|
|
92
93
|
*
|
|
93
94
|
* @returns {Promise} A promise which resolves when the operation has completed
|
|
94
95
|
*/
|
|
@@ -98,7 +99,7 @@ export default class TeraFyPluginFirebase extends TeraFyPluginBase {
|
|
|
98
99
|
return Promise.resolve()
|
|
99
100
|
.then(()=> this.requireProject())
|
|
100
101
|
.then(project => {
|
|
101
|
-
|
|
102
|
+
const path = name == '_PROJECT'
|
|
102
103
|
? `projects::${project.id}`
|
|
103
104
|
: `project_namespaces::${project.id}::${name}`;
|
|
104
105
|
|
|
@@ -124,7 +125,7 @@ export default class TeraFyPluginFirebase extends TeraFyPluginBase {
|
|
|
124
125
|
* @returns {Promise} A promise which resolves when the operation has completed
|
|
125
126
|
*/
|
|
126
127
|
_unmountNamespace(name: string): Promise<void | any[]> { // Add type 'string'
|
|
127
|
-
|
|
128
|
+
const syncro = this.syncros[name]; // Create local alias for Syncro before we detach it
|
|
128
129
|
|
|
129
130
|
// Detach local state
|
|
130
131
|
delete this.namespaces[name];
|
|
@@ -132,7 +133,7 @@ export default class TeraFyPluginFirebase extends TeraFyPluginBase {
|
|
|
132
133
|
|
|
133
134
|
// Check if syncro exists before calling destroy
|
|
134
135
|
if (syncro) {
|
|
135
|
-
return syncro.destroy(); // Trigger Syncro
|
|
136
|
+
return syncro.destroy(); // Trigger Syncro destruction
|
|
136
137
|
} else {
|
|
137
138
|
return Promise.resolve(); // Or handle the case where syncro doesn't exist
|
|
138
139
|
}
|
package/plugins/vue2.ts
CHANGED
|
@@ -27,7 +27,7 @@ import TeraFyPluginFirebase from './firebase.js';
|
|
|
27
27
|
export default class TeraFyPluginVue2 extends TeraFyPluginFirebase {
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Local Vue@2 library to use, set during
|
|
30
|
+
* Local Vue@2 library to use, set during constructor
|
|
31
31
|
*
|
|
32
32
|
* @type {Vue}
|
|
33
33
|
*/
|
|
@@ -68,7 +68,7 @@ export default class TeraFyPluginVue2 extends TeraFyPluginFirebase {
|
|
|
68
68
|
* @returns {Promise} A Promise which will resolve when the init process has completed
|
|
69
69
|
*/
|
|
70
70
|
async init(options: any) {
|
|
71
|
-
|
|
71
|
+
const settings = {
|
|
72
72
|
app: null,
|
|
73
73
|
Vue: null,
|
|
74
74
|
globalName: '$tera',
|
|
@@ -86,17 +86,17 @@ export default class TeraFyPluginVue2 extends TeraFyPluginFirebase {
|
|
|
86
86
|
this.Vue.prototype[settings.globalName] = this;
|
|
87
87
|
|
|
88
88
|
await super.init(settings); // Initalize parent class Firebase functionality
|
|
89
|
-
// @ts-
|
|
89
|
+
// @ts-expect-error TODO: Track down why eslint throws error
|
|
90
90
|
this.project = await this.mountNamespace('_PROJECT');
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
|
|
94
94
|
/** @override */
|
|
95
|
-
// @ts-
|
|
95
|
+
// @ts-expect-error TODO: Work out why TS doesn't like overrides
|
|
96
96
|
getReactive(value: any) {
|
|
97
|
-
|
|
97
|
+
const doc = this.Vue.observable(value);
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
const watcherPath = `_teraFy_${this.reactiveId++}`;
|
|
100
100
|
this.app[watcherPath] = doc; // Attach onto app so we can use $watch later on
|
|
101
101
|
|
|
102
102
|
return {
|
|
@@ -110,6 +110,7 @@ export default class TeraFyPluginVue2 extends TeraFyPluginFirebase {
|
|
|
110
110
|
getState: () => {
|
|
111
111
|
return cloneDeep(doc);
|
|
112
112
|
},
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
113
114
|
watch: (cb: Function) => {
|
|
114
115
|
this.app.$watch(watcherPath, cb, {deep: true});
|
|
115
116
|
},
|