@iebh/tera-fy 2.3.10 → 2.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/api.md +8 -11
  3. package/dist/plugin.vue2.es2019.js +28 -27
  4. package/dist/terafy.bootstrapper.es2019.js +2 -2
  5. package/dist/terafy.bootstrapper.js +2 -2
  6. package/dist/terafy.es2019.js +5 -5
  7. package/dist/terafy.js +5 -5
  8. package/eslint.config.js +4 -66
  9. package/lib/{projectFile.ts → projectFile.js} +52 -76
  10. package/lib/syncro/{entities.ts → entities.js} +14 -83
  11. package/lib/syncro/{keyed.ts → keyed.js} +46 -68
  12. package/lib/syncro/{syncro.ts → syncro.js} +104 -136
  13. package/lib/{terafy.bootstrapper.ts → terafy.bootstrapper.js} +20 -30
  14. package/lib/{terafy.client.ts → terafy.client.js} +85 -84
  15. package/lib/{terafy.proxy.ts → terafy.proxy.js} +12 -26
  16. package/lib/{terafy.server.ts → terafy.server.js} +204 -229
  17. package/package.json +20 -39
  18. package/plugins/{base.ts → base.js} +3 -5
  19. package/plugins/{firebase.ts → firebase.js} +22 -21
  20. package/plugins/{vite.ts → vite.js} +3 -3
  21. package/plugins/{vue2.ts → vue2.js} +8 -10
  22. package/plugins/{vue3.ts → vue3.js} +7 -10
  23. package/utils/mixin.js +15 -0
  24. package/utils/{pathTools.ts → pathTools.js} +8 -9
  25. package/widgets/tera-file-select.vue +1 -1
  26. package/dist/lib/projectFile.d.ts +0 -190
  27. package/dist/lib/projectFile.js +0 -305
  28. package/dist/lib/projectFile.js.map +0 -1
  29. package/dist/lib/syncro/entities.d.ts +0 -34
  30. package/dist/lib/syncro/entities.js +0 -212
  31. package/dist/lib/syncro/entities.js.map +0 -1
  32. package/dist/lib/syncro/keyed (Rhino's conflicted copy 2026-05-10).js +0 -287
  33. package/dist/lib/syncro/keyed.d.ts +0 -95
  34. package/dist/lib/syncro/keyed.js +0 -288
  35. package/dist/lib/syncro/keyed.js (Rhino's conflicted copy 2026-05-10).map +0 -1
  36. package/dist/lib/syncro/keyed.js.map +0 -1
  37. package/dist/lib/syncro/syncro (Rhino's conflicted copy 2026-05-10).js +0 -765
  38. package/dist/lib/syncro/syncro.d (Rhino's conflicted copy 2026-05-10).ts +0 -336
  39. package/dist/lib/syncro/syncro.d.ts +0 -343
  40. package/dist/lib/syncro/syncro.js +0 -771
  41. package/dist/lib/syncro/syncro.js (Rhino's conflicted copy 2026-05-10).map +0 -1
  42. package/dist/lib/syncro/syncro.js.map +0 -1
  43. package/dist/lib/terafy.bootstrapper.d.ts +0 -42
  44. package/dist/lib/terafy.bootstrapper.js +0 -129
  45. package/dist/lib/terafy.bootstrapper.js.map +0 -1
  46. package/dist/lib/terafy.client.d.ts +0 -555
  47. package/dist/lib/terafy.client.js +0 -1153
  48. package/dist/lib/terafy.client.js.map +0 -1
  49. package/dist/lib/terafy.proxy.d.ts +0 -66
  50. package/dist/lib/terafy.proxy.js +0 -130
  51. package/dist/lib/terafy.proxy.js.map +0 -1
  52. package/dist/lib/terafy.server.d.ts +0 -697
  53. package/dist/lib/terafy.server.js +0 -2062
  54. package/dist/lib/terafy.server.js.map +0 -1
  55. package/dist/plugin.vue2.es2019 (Rhino's conflicted copy 2026-05-10).js +0 -1271
  56. package/dist/plugins/base.d.ts +0 -20
  57. package/dist/plugins/base.js +0 -22
  58. package/dist/plugins/base.js.map +0 -1
  59. package/dist/plugins/firebase.d.ts +0 -62
  60. package/dist/plugins/firebase.js +0 -123
  61. package/dist/plugins/firebase.js.map +0 -1
  62. package/dist/plugins/vite.d.ts +0 -12
  63. package/dist/plugins/vite.js +0 -22
  64. package/dist/plugins/vite.js.map +0 -1
  65. package/dist/plugins/vue2.d.ts +0 -67
  66. package/dist/plugins/vue2.js +0 -104
  67. package/dist/plugins/vue2.js.map +0 -1
  68. package/dist/plugins/vue3.d.ts +0 -63
  69. package/dist/plugins/vue3.js +0 -93
  70. package/dist/plugins/vue3.js.map +0 -1
  71. package/dist/utils/mixin.d.ts +0 -11
  72. package/dist/utils/mixin.js +0 -15
  73. package/dist/utils/mixin.js.map +0 -1
  74. package/dist/utils/pDefer.d.ts +0 -16
  75. package/dist/utils/pDefer.js +0 -19
  76. package/dist/utils/pDefer.js.map +0 -1
  77. package/dist/utils/pathTools.d.ts +0 -70
  78. package/dist/utils/pathTools.js +0 -120
  79. package/dist/utils/pathTools.js.map +0 -1
  80. package/tsconfig.json +0 -30
  81. package/utils/mixin.ts +0 -18
  82. package/utils/pDefer.ts +0 -27
@@ -1,45 +1,18 @@
1
- /* eslint-disable @typescript-eslint/no-redundant-type-constituents */
2
- // Global 'app' declaration
3
- declare let app: any;
4
-
5
- // Global window augmentation
6
- declare global {
7
- interface Window {
8
- // eslint-disable-next-line no-unused-vars
9
- panic(text: any): void;
10
- }
11
- }
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
-
28
1
  import {cloneDeep} from 'lodash-es';
29
- import mixin from '#utils/mixin';
30
2
  import {nanoid} from 'nanoid';
3
+ import {mixin} from '#utils/mixin';
31
4
  import pathTools from '#utils/pathTools';
32
- import promiseDefer from '#utils/pDefer';
33
- // @ts-expect-error TODO: Remove when reflib gets declaration file
34
5
  import Reflib from '@iebh/reflib';
35
6
  import {reactive} from 'vue';
36
7
 
8
+ /* globals app */
9
+
10
+
37
11
  /**
38
12
  * Server-side functions available to the Tera-Fy client library
39
13
  *
40
14
  * @class TeraFyServer
41
15
  */
42
-
43
16
  export default class TeraFyServer {
44
17
 
45
18
  /**
@@ -55,8 +28,9 @@ export default class TeraFyServer {
55
28
  * @property {String} siteUrl The main site absolute URL
56
29
  * @property {String} sitePathLogin Either an absolute URL or the relative path (taken from `siteUrl`) when trying to log in the user
57
30
  * @property {Boolean} embedWorkaround Try to use `getUserViaEmbedWorkaround()` to force a login via popup if the user is running in local mode (see function docs for more details). This is toggled to false after the first run
31
+ * @property {String} ioUrl entrypoint for the TERA-io worker (used to get/set various TERA entities such as files)
58
32
  */
59
- settings: any = {
33
+ settings = {
60
34
  devMode: false,
61
35
  verbosity: 9,
62
36
  restrictOrigin: '*',
@@ -66,6 +40,7 @@ export default class TeraFyServer {
66
40
  siteUrl: window.location.href,
67
41
  sitePathLogin: '/login',
68
42
  embedWorkaround: true,
43
+ ioUrl: app.service('$infra').workerUrls.io,
69
44
  };
70
45
 
71
46
  static SERVERMODE_NONE = 0;
@@ -84,20 +59,19 @@ export default class TeraFyServer {
84
59
  *
85
60
  * @returns {Object} A context, which is this instance extended with additional properties
86
61
  */
87
- createContext(e: MessageEvent): any {
62
+ createContext(e) {
88
63
  // Construct wrapper for sendRaw for this client
89
64
  return mixin(this, {
90
65
  messageEvent: e,
91
- sendRaw(message: any) {
66
+ sendRaw(message) {
92
67
  let payload;
93
68
  try {
94
69
  payload = {
95
70
  TERA: 1,
96
71
  ...cloneDeep(message), // Need to clone to resolve promise nasties
97
72
  };
98
- // Use type assertion assuming e.source is a WindowProxy or similar
99
- (e.source as WindowProxy).postMessage(payload, this.settings.restrictOrigin);
100
- } catch (err: any) { // Changed variable name e -> err
73
+ e.source.postMessage(payload, this.settings.restrictOrigin);
74
+ } catch (err) {
101
75
  this.debug('ERROR', 1, 'Attempted to dispatch payload server(via reply)->client', {payload, e: err});
102
76
  throw err;
103
77
  }
@@ -112,14 +86,14 @@ export default class TeraFyServer {
112
86
  *
113
87
  * @returns {Object} A context, which is this instance extended with additional properties
114
88
  */
115
- getClientContext(): any {
89
+ getClientContext() {
116
90
  switch (this.settings.serverMode) {
117
91
  case TeraFyServer.SERVERMODE_NONE:
118
92
  throw new Error('Client has not yet initiated communication');
119
93
  case TeraFyServer.SERVERMODE_EMBEDDED:
120
94
  // Server is inside an iFrame so we need to send messages to the window parent
121
95
  return mixin(this, {
122
- sendRaw(message: any) {
96
+ sendRaw(message) {
123
97
  let payload;
124
98
  try {
125
99
  payload = {
@@ -127,7 +101,7 @@ export default class TeraFyServer {
127
101
  ...cloneDeep(message), // Need to clone to resolve promise nasties
128
102
  };
129
103
  window.parent.postMessage(payload, this.settings.restrictOrigin);
130
- } catch (e: any) {
104
+ } catch (e) {
131
105
  this.debug('ERROR', 1, 'Attempted to dispatch payload server(iframe)->cient(top level window)', {payload, e});
132
106
  throw e;
133
107
  }
@@ -136,27 +110,26 @@ export default class TeraFyServer {
136
110
  case TeraFyServer.SERVERMODE_TERA:
137
111
  case TeraFyServer.SERVERMODE_FRAME: {
138
112
  // Server is the top-level window so we need to send messages to an embedded iFrame
139
- const iFrame = document.querySelector<HTMLIFrameElement>('iframe#external');
113
+ const iFrame = document.querySelector('iframe#external');
140
114
  if (!iFrame) {
141
115
  this.debug('INFO', 2, 'Cannot locate TERA-FY top-level->iFrame#external - maybe there is none');
142
116
  return mixin(this, {
143
- sendRaw(message: any) {
117
+ sendRaw(message) {
144
118
  this.debug('INFO', 2, 'Sending broadcast to zero listening clients', {message});
145
119
  },
146
120
  });
147
121
  }
148
122
 
149
123
  return mixin(this, {
150
- sendRaw(message: any) {
124
+ sendRaw(message) {
151
125
  let payload;
152
126
  try {
153
127
  payload = {
154
128
  TERA: 1,
155
129
  ...cloneDeep(message), // Need to clone to resolve promise nasties
156
130
  };
157
- // Check if contentWindow exists before posting
158
131
  iFrame.contentWindow?.postMessage(payload, this.settings.restrictOrigin);
159
- } catch (e: any) {
132
+ } catch (e) {
160
133
  this.debug('ERROR', 1, 'Attempted to dispatch payload server(top level window)->cient(iframe)', {payload, e});
161
134
  throw e;
162
135
  }
@@ -176,7 +149,7 @@ export default class TeraFyServer {
176
149
  *
177
150
  * @type {MessageEvent}
178
151
  */
179
- messageEvent: MessageEvent | null = null;
152
+ messageEvent = null;
180
153
 
181
154
 
182
155
  /**
@@ -188,7 +161,7 @@ export default class TeraFyServer {
188
161
  *
189
162
  * @returns {Promise<*>} The resolved output of the server function
190
163
  */
191
- senderRpc(method: string, ...args: any[]): Promise<any> {
164
+ senderRpc(method, ...args) {
192
165
  if (!this.messageEvent) throw new Error('senderRpc() can only be used if given a context from `createContext()`');
193
166
 
194
167
  // Create a context specific to this event to use its sendRaw
@@ -209,7 +182,7 @@ export default class TeraFyServer {
209
182
  * @returns {Promise<Object>} Basic promise result
210
183
  * @property {Date} date Server date
211
184
  */
212
- handshake(): Promise<any> {
185
+ handshake() {
213
186
  return Promise.resolve({
214
187
  date: new Date(),
215
188
  });
@@ -224,7 +197,7 @@ export default class TeraFyServer {
224
197
  * @param {Object} message Message object to send
225
198
  * @returns {Promise<*>} A promise which resolves when the operation has completed with the remote reply
226
199
  */
227
- send(message: any): Promise<any> {
200
+ send(message) {
228
201
  if (!this.messageEvent?.source) throw new Error('send() requires a messageEvent with a source');
229
202
 
230
203
  const id = nanoid();
@@ -252,7 +225,7 @@ export default class TeraFyServer {
252
225
  * @param {Object} message Message object to send
253
226
  * @param {Window} sendVia Window context to dispatch the message via if its not the same as the regular window
254
227
  */
255
- sendRaw(message: any, sendVia?: any): void {
228
+ sendRaw(message, sendVia) {
256
229
  let payload;
257
230
  try {
258
231
  payload = {
@@ -267,7 +240,7 @@ export default class TeraFyServer {
267
240
  } else {
268
241
  this.debug('WARN', 1, 'Cannot sendRaw, no target window (sendVia or parent) found.');
269
242
  }
270
- } catch (e: any) {
243
+ } catch (e) {
271
244
  this.debug('ERROR', 2, 'Attempted to dispatch response server->client', payload);
272
245
  this.debug('ERROR', 2, 'Message compose server->client:', e);
273
246
  }
@@ -279,7 +252,7 @@ export default class TeraFyServer {
279
252
  *
280
253
  * @param {String} mode The server mode to set to
281
254
  */
282
- setServerMode(mode: string): void {
255
+ setServerMode(mode) {
283
256
  switch (mode) {
284
257
  case 'embedded':
285
258
  this.settings.serverMode = TeraFyServer.SERVERMODE_EMBEDDED;
@@ -301,7 +274,7 @@ export default class TeraFyServer {
301
274
  *
302
275
  * @param {MessageEvent} rawMessage Raw message event to process
303
276
  */
304
- acceptMessage(rawMessage: MessageEvent): void {
277
+ acceptMessage(rawMessage) {
305
278
  // Ignore messages from the same origin (potential loops)
306
279
  if (typeof window !== 'undefined' && rawMessage.origin === window.location.origin) return;
307
280
 
@@ -320,21 +293,18 @@ export default class TeraFyServer {
320
293
  }
321
294
  delete this.acceptPostboxes[message.id]; // Clean up postbox
322
295
  } else if (message.action == 'rpc' && typeof message.method === 'string') { // Relay RPC calls
323
- const method = message.method as string;
324
- // Use type assertion for dynamic method call
325
- if (typeof (this as any)[method] === 'function') {
296
+ const method = message.method;
297
+ if (typeof this[method] === 'function') {
326
298
  // Create context for this specific message event
327
299
  const context = this.createContext(rawMessage);
328
300
  // Store the event temporarily for potential use in send() called by the RPC method
329
301
  context.messageEvent = rawMessage;
330
- return (this as any)[method].apply(context, message.args || []);
302
+ return this[method].apply(context, message.args || []);
331
303
  } else {
332
304
  throw new Error(`Unknown RPC method "${method}"`);
333
305
  }
334
306
  } else {
335
307
  this.debug('ERROR', 2, 'Unexpected incoming TERA-FY SERVER message', {message});
336
- // Don't throw, just ignore unknown formats silently? Or throw?
337
- // throw new Error('Unknown message format');
338
308
  }
339
309
  })
340
310
  .then(response => {
@@ -367,7 +337,7 @@ export default class TeraFyServer {
367
337
  /**
368
338
  * Listening postboxes, these correspond to outgoing message IDs that expect a response
369
339
  */
370
- acceptPostboxes: Record<string, any> = {};
340
+ acceptPostboxes = {};
371
341
 
372
342
 
373
343
  /**
@@ -379,7 +349,7 @@ export default class TeraFyServer {
379
349
  *
380
350
  * @returns {Promise<*>} A promise which resolves with the resulting inner callback payload
381
351
  */
382
- requestFocus(cb: () => Promise<any>): Promise<any> {
352
+ requestFocus(cb) {
383
353
  // Ensure messageEvent is set before calling senderRpc
384
354
  if (!this.messageEvent && this.settings.serverMode != TeraFyServer.SERVERMODE_TERA) {
385
355
  console.warn("requestFocus called without a messageEvent context. Cannot toggle focus.");
@@ -404,7 +374,7 @@ export default class TeraFyServer {
404
374
  * @param {...*} [args] Optional event payload to send
405
375
  * @returns {Promise} A promise which resolves when the transmission has completed
406
376
  */
407
- emitClients(event: string, ...args: any[]): Promise<void> {
377
+ emitClients(event, ...args) {
408
378
  // Use getClientContext to get the appropriate sendRaw method
409
379
  const context = this.getClientContext();
410
380
  return context.sendRaw({
@@ -421,7 +391,7 @@ export default class TeraFyServer {
421
391
  *
422
392
  * @param {Number} verbosity The desired server verbosity level
423
393
  */
424
- setServerVerbosity(verbosity: number): void {
394
+ setServerVerbosity(verbosity) {
425
395
  this.settings.verbosity = +verbosity;
426
396
  this.debug('INFO', 1, 'Server verbosity set to', this.settings.verbosity);
427
397
  }
@@ -447,7 +417,7 @@ export default class TeraFyServer {
447
417
  *
448
418
  * @returns {Promise<User>} The current logged in user or null if none
449
419
  */
450
- getUser(options?: any): Promise<any | null> {
420
+ getUser(options) {
451
421
  const settings = {
452
422
  forceRetry: false,
453
423
  waitPromises: true,
@@ -479,7 +449,7 @@ export default class TeraFyServer {
479
449
  }
480
450
  : null
481
451
  )
482
- .catch((e: any) => {
452
+ .catch(e => {
483
453
  console.warn('getUser() catch', e);
484
454
  return null; // Return null on error
485
455
  })
@@ -493,9 +463,8 @@ export default class TeraFyServer {
493
463
  *
494
464
  * @returns {Promise<User>} A promise which will resolve if the there is a user and they are logged in
495
465
  */
496
- requireUser(): Promise<any> {
497
- /* eslint-disable @typescript-eslint/only-throw-error */
498
- let user: any; // Last getUser() response
466
+ requireUser() {
467
+ let user; // Last getUser() response
499
468
  return Promise.resolve() // NOTE: This promise is upside down, it only continues down the chain if the user is NOT valid, otherwise it throws to exit
500
469
  .then(()=> this.getUser())
501
470
  .then(res => user = res)
@@ -554,31 +523,23 @@ export default class TeraFyServer {
554
523
  /**
555
524
  * Provide an object of credentials for 3rd party services like Firebase/Supabase
556
525
  *
557
- * @returns An object containing 3rd party service credentials
526
+ * @returns {Object} An object containing 3rd party service credentials
558
527
  */
559
- getCredentials(): {
560
- firebaseApiKey: string;
561
- firebaseAppId: string;
562
- firebaseAuthDomain: string;
563
- firebaseProjectId: string;
564
- kindeClientId: string;
565
- kindeDomain: string;
566
- logrocketProject: string;
567
- supabaseKey: string;
568
- supabaseUrl: string;
569
- } {
528
+ getCredentials() {
570
529
  return app.service('$auth').credentials;
571
530
  }
572
531
 
532
+
573
533
  /**
574
- * Get auth credentials for kinde
575
- * @returns The kinde auth token
576
- */
577
- getKindeToken(): Promise<string> {
534
+ * Get auth credentials for kinde
535
+ * @returns {Promise<String>} The kinde auth token
536
+ */
537
+ getKindeToken() {
578
538
  const $auth = app.service('$auth');
579
539
  return $auth.kinde.getToken();
580
540
  }
581
541
 
542
+
582
543
  /**
583
544
  * In embed mode only - create a popup window and try to auth via that
584
545
  *
@@ -595,10 +556,10 @@ export default class TeraFyServer {
595
556
  *
596
557
  * @returns {Promise} A promise which resolves when the operation has completed
597
558
  */
598
- async getUserViaEmbedWorkaround(): Promise<void> {
559
+ async getUserViaEmbedWorkaround() {
599
560
  this.debug('INFO', 4, 'Attempting to use getUserViaEmbedWorkaround()');
600
561
 
601
- let lsState: any = window.localStorage.getItem('tera.embedUser');
562
+ let lsState = window.localStorage.getItem('tera.embedUser');
602
563
  if (lsState) {
603
564
  this.debug('INFO', 4, 'Using localStorage state');
604
565
  try {
@@ -618,7 +579,7 @@ export default class TeraFyServer {
618
579
  // Force refresh projects against the new user
619
580
  await app.service('$projects').refresh();
620
581
  return;
621
- } catch (e: any) {
582
+ } catch (e) {
622
583
  throw new Error(`Failed to decode local dev state - ${e.toString()}`, {cause: e});
623
584
  }
624
585
  }
@@ -635,10 +596,10 @@ export default class TeraFyServer {
635
596
  );
636
597
 
637
598
  // Create a deferred promise which will (eventually) resolve when the downstream window signals its ready
638
- const waitOnWindowAuth = promiseDefer();
599
+ const waitOnWindowAuth = Promise.withResolvers();
639
600
 
640
601
  // Create a listener for the message from the downstream window to resolve the promise
641
- const listenMessages = ({data}: {data: any}) => {
602
+ const listenMessages = ({data}) => {
642
603
  this.debug('INFO', 3, 'Recieved message from popup window', {data});
643
604
  if (data.TERA && data.action == 'popupUserState' && data.user) { // Signal sent from landing page - we're logged in, yey!
644
605
  const $auth = app.service('$auth');
@@ -652,7 +613,7 @@ export default class TeraFyServer {
652
613
  this.debug('INFO', 3, 'Received user auth from popup window', {'$auth.user': $auth.user});
653
614
 
654
615
  // Store local copy of user image - this only applies to dev mode (localhost connecting to embed) so we can ignore the security implications here
655
- Promise.resolve() // eslint-disable-line @typescript-eslint/no-floating-promises
616
+ Promise.resolve()
656
617
  .then(()=> this.getUser({
657
618
  forceRetry: false, // Avoid loops
658
619
  waitPromises: false, // We have a partially resolved state so we don't care about outer promises resolving
@@ -705,7 +666,7 @@ export default class TeraFyServer {
705
666
  *
706
667
  * @returns {Promise<Project|null>} The currently active project, if any
707
668
  */
708
- getProject(): Promise<any | null> {
669
+ getProject() {
709
670
  const $projects = app.service('$projects');
710
671
 
711
672
  return $projects.promise()
@@ -726,11 +687,11 @@ export default class TeraFyServer {
726
687
  *
727
688
  * @returns {Promise<Array<Project>>} Collection of projects the user has access to
728
689
  */
729
- getProjects(): Promise<any[]> {
690
+ getProjects() {
730
691
  const $projects = app.service('$projects');
731
692
 
732
693
  return $projects.promise()
733
- .then(()=> $projects.list.map((project: any) => ({
694
+ .then(()=> $projects.list.map(project => ({
734
695
  id: project.id,
735
696
  name: project.name,
736
697
  created: project.created,
@@ -745,7 +706,7 @@ export default class TeraFyServer {
745
706
  * @param {Object|String} project The project to set as active - either the full Project object or its ID
746
707
  * @returns {Promise} A promise which resolves when the operation has completed
747
708
  */
748
- setActiveProject(project: any): Promise<void> {
709
+ setActiveProject(project) {
749
710
  return app.service('$projects').setActive(project);
750
711
  }
751
712
 
@@ -763,7 +724,7 @@ export default class TeraFyServer {
763
724
  *
764
725
  * @returns {Promise<Project>} The active project
765
726
  */
766
- requireProject(options?: any): Promise<any> {
727
+ requireProject(options) {
767
728
  const settings = {
768
729
  autoRequireUser: true,
769
730
  autoSetActiveProject: true,
@@ -779,35 +740,36 @@ export default class TeraFyServer {
779
740
  .then(active => {
780
741
  if (active) return active; // Use active project
781
742
 
782
- return new Promise((resolve, reject) => {
783
- const askProject = (): Promise<any> => Promise.resolve()
784
- .then(()=> this.selectProject({
785
- allowCancel: false,
786
- }))
787
- .then(project => resolve(project))
788
- .catch(e => {
789
- if (e == 'cancel' || e === 'CANCEL') { // Handle string 'cancel' or rejected 'CANCEL'
790
- return this.requestFocus(()=>
791
- app.service('$prompt').dialog({
792
- title: settings.noSelectTitle,
793
- body: settings.noSelectBody,
794
- buttons: ['ok'],
795
- })
796
- )
797
- .then(()=> askProject())
798
- .catch(reject)
799
- } else {
800
- reject(e);
801
- }
802
- })
743
+ return Promise.resolve()
744
+ .then(()=> new Promise((resolve, reject) => {
745
+ const askProject = () => Promise.resolve()
746
+ .then(()=> this.selectProject({
747
+ allowCancel: false,
748
+ }))
749
+ .then(project => resolve(project))
750
+ .catch(e => {
751
+ if (e == 'cancel' || e === 'CANCEL') { // Handle string 'cancel' or rejected 'CANCEL'
752
+ return Promise.resolve()
753
+ .then(()=> this.requestFocus(()=>
754
+ app.service('$prompt').dialog({
755
+ title: settings.noSelectTitle,
756
+ body: settings.noSelectBody,
757
+ buttons: ['ok'],
758
+ })
759
+ ))
760
+ .then(()=> askProject())
761
+ .catch(reject)
762
+ } else {
763
+ reject(e);
764
+ }
765
+ })
803
766
 
804
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
805
- askProject(); // Kick off intial project loop
806
- })
807
- .then(async (project: any) => {
808
- if (settings.autoSetActiveProject) await this.setActiveProject(project);
809
- return project;
810
- })
767
+ askProject(); // Kick off intial project loop
768
+ }))
769
+ .then(async project => {
770
+ if (settings.autoSetActiveProject) await this.setActiveProject(project);
771
+ return project;
772
+ })
811
773
  })
812
774
  }
813
775
 
@@ -822,7 +784,7 @@ export default class TeraFyServer {
822
784
  *
823
785
  * @returns {Promise<Project>} The active project
824
786
  */
825
- selectProject(options?: any): Promise<any> {
787
+ selectProject(options) {
826
788
  const settings = {
827
789
  title: 'Select a project to work with',
828
790
  allowCancel: true,
@@ -838,7 +800,7 @@ export default class TeraFyServer {
838
800
  buttons: settings.allowCancel ? ['cancel'] : [],
839
801
  })
840
802
  ))
841
- .then((project: any) => settings.setActive
803
+ .then(project => settings.setActive
842
804
  ? this.setActiveProject(project)
843
805
  .then(()=> project)
844
806
  : project
@@ -857,7 +819,7 @@ export default class TeraFyServer {
857
819
  *
858
820
  * @returns {Promise<Object>} A promise which resolves to the namespace POJO state
859
821
  */
860
- getNamespace(name: string): Promise<any> {
822
+ getNamespace(name) {
861
823
  if (!/^[\w-]+$/.test(name)) throw new Error('Namespaces must be alphanumeric + hyphens + underscores');
862
824
 
863
825
  return app.service('$sync').getSnapshot(`project_namespaces::${app.service('$projects').active.id}::${name}`);
@@ -875,7 +837,7 @@ export default class TeraFyServer {
875
837
  *
876
838
  * @returns {Promise<Object>} A promise which resolves to the namespace POJO state
877
839
  */
878
- setNamespace(name: string, state: any, options?: any): Promise<any> {
840
+ setNamespace(name, state, options) {
879
841
  if (!/^[\w-]+$/.test(name)) throw new Error('Namespaces must be alphanumeric + hyphens + underscores');
880
842
  if (typeof state != 'object') throw new Error('State must be an object');
881
843
 
@@ -891,7 +853,7 @@ export default class TeraFyServer {
891
853
  * @returns {Promise<Array<Object>>} Collection of available namespaces for the current project
892
854
  * @property {String} name The name of the namespace
893
855
  */
894
- listNamespaces(): Promise<any[]> {
856
+ listNamespaces() {
895
857
  return app.service('$projects').listNamespaces();
896
858
  }
897
859
  // }}}
@@ -907,7 +869,7 @@ export default class TeraFyServer {
907
869
  *
908
870
  * @returns {Promise<Object>} The current project state snapshot
909
871
  */
910
- getProjectState(options?: any): Promise<any> {
872
+ getProjectState(options) {
911
873
  const settings = {
912
874
  autoRequire: true,
913
875
  paths: null,
@@ -940,7 +902,7 @@ export default class TeraFyServer {
940
902
  *
941
903
  * @returns {Promise<*>} A promise which resolves to `value` when the operation has been dispatched to the server and saved
942
904
  */
943
- setProjectState(path: string | string[], value: any, options?: any): Promise<any> {
905
+ setProjectState(path, value, options) {
944
906
  const settings = {
945
907
  strategy: 'set',
946
908
  ...options,
@@ -980,12 +942,12 @@ export default class TeraFyServer {
980
942
  *
981
943
  * @returns {Promise<*>} A promise which resolves to the eventual input value after defaults have been applied
982
944
  */
983
- setProjectStateDefaults(path: string | string[] | any, value?: any, options?: any): Promise<any> {
984
- let settings = { ...options }; // Initialize settings from the third argument if present
945
+ setProjectStateDefaults(path, value, options) {
946
+ let settings = {...options}; // Initialize settings from the third argument if present
985
947
  if (!app.service('$projects').active) throw new Error('No active project');
986
948
 
987
949
  const target = app.service('$projects').active;
988
- let actualValue: any;
950
+ let actualValue;
989
951
 
990
952
  if (typeof path == 'string' || Array.isArray(path)) { // Called as (path, value, options?) Set sub-object
991
953
  actualValue = value;
@@ -1015,7 +977,7 @@ export default class TeraFyServer {
1015
977
  *
1016
978
  * @returns {Promise} A promise which resolves when the operation has completed
1017
979
  */
1018
- setProjectStateRefresh(): Promise<null> {
980
+ setProjectStateRefresh() {
1019
981
  this.debug('INFO', 1, 'Force project state refresh!');
1020
982
  if (!app.service('$projects').active) throw new Error('No active project');
1021
983
  return app.service('$projects').active.$read({force: true})
@@ -1045,6 +1007,7 @@ export default class TeraFyServer {
1045
1007
  * @property {String} mime The associated mime type for the file
1046
1008
  */
1047
1009
 
1010
+
1048
1011
  /**
1049
1012
  * Data structure for a file filter
1050
1013
  * @class FileFilters
@@ -1055,6 +1018,7 @@ export default class TeraFyServer {
1055
1018
  * @property {String} [ext] CSV of @momsfriendlydevco/match expressions to filter the file extension by
1056
1019
  */
1057
1020
 
1021
+
1058
1022
  /**
1059
1023
  * Prompt the user to select a library to operate on
1060
1024
  *
@@ -1073,7 +1037,7 @@ export default class TeraFyServer {
1073
1037
  *
1074
1038
  * @returns {Promise<ProjectFile>} The eventually selected file, if in save mode new files are created as stubs
1075
1039
  */
1076
- selectProjectFile(options?: any): Promise<any> {
1040
+ selectProjectFile(options) {
1077
1041
  const settings = {
1078
1042
  title: 'Select a file',
1079
1043
  hint: null,
@@ -1109,10 +1073,10 @@ export default class TeraFyServer {
1109
1073
  showHiddenFilesProp: settings.showHiddenFiles,
1110
1074
  },
1111
1075
  componentEvents: {
1112
- fileSave(file: any) {
1076
+ fileSave(file) {
1113
1077
  app.service('$prompt').close(true, file);
1114
1078
  },
1115
- fileSelect(file: any) {
1079
+ fileSelect(file) {
1116
1080
  app.service('$prompt').close(true, file);
1117
1081
  },
1118
1082
  },
@@ -1133,7 +1097,7 @@ export default class TeraFyServer {
1133
1097
  *
1134
1098
  * @returns {Promise<Array<ProjectFile>>} A collection of project files for the given project
1135
1099
  */
1136
- getProjectFiles(options?: any): Promise<any[]> {
1100
+ getProjectFiles(options) {
1137
1101
  const settings = {
1138
1102
  autoRequire: true,
1139
1103
  lazy: true,
@@ -1144,7 +1108,7 @@ export default class TeraFyServer {
1144
1108
  return Promise.resolve()
1145
1109
  .then(()=> app.service('$projects').promise())
1146
1110
  .then(()=> settings.autoRequire && this.requireProject())
1147
- .then(()=>
1111
+ .then(()=> /* eslint-disable @stylistic/indent */
1148
1112
  !app.service('$projects').activeFiles // List of project files not ready yet
1149
1113
  || app.service('$projects').activeFiles.length == 0 // OR if we have no files in the cache
1150
1114
  || !settings.lazy // OR lazy/cache use is disabled
@@ -1167,7 +1131,7 @@ export default class TeraFyServer {
1167
1131
  *
1168
1132
  * @returns {Promise<ProjectFile>} The eventual fetched ProjectFile (or requested subkey)
1169
1133
  */
1170
- getProjectFile(name: string, options?: any): Promise<any> {
1134
+ getProjectFile(name, options) {
1171
1135
  const settings = {
1172
1136
  subkey: null,
1173
1137
  cache: true,
@@ -1175,7 +1139,7 @@ export default class TeraFyServer {
1175
1139
  };
1176
1140
 
1177
1141
  // This helper function performs a depth-first search on the file tree.
1178
- const findFileRecursively = (items: any[], path: string): any | undefined => {
1142
+ const findFileRecursively = (items, path) => {
1179
1143
  // Iterate over each item at the current level (files or folders)
1180
1144
  for (const item of items) {
1181
1145
  console.log(item);
@@ -1194,7 +1158,7 @@ export default class TeraFyServer {
1194
1158
  }
1195
1159
  }
1196
1160
  // If the loop completes, the file was not found at this level or any sub-levels.
1197
- return undefined;
1161
+ return;
1198
1162
  };
1199
1163
 
1200
1164
  return Promise.resolve()
@@ -1207,13 +1171,14 @@ export default class TeraFyServer {
1207
1171
  })
1208
1172
  : app.service('$projects').activeFiles // Otherwise use file cache
1209
1173
  )
1210
- .then((files: any[]) => {
1174
+ .then(files => {
1211
1175
  // Recursively search for the file to handle searching folders
1212
1176
  return findFileRecursively(files, name);
1213
1177
  })
1214
- .then((file: any) => file && settings.subkey ? (file)[settings.subkey] : file)
1178
+ .then(file => file && settings.subkey ? file[settings.subkey] : file)
1215
1179
  }
1216
1180
 
1181
+
1217
1182
  /**
1218
1183
  * Fetch the raw contents of a file by its ID
1219
1184
  *
@@ -1224,7 +1189,7 @@ export default class TeraFyServer {
1224
1189
  *
1225
1190
  * @returns {*} The file contents in the requested format
1226
1191
  */
1227
- getProjectFileContents(id: string, options?: any): Promise<any> {
1192
+ getProjectFileContents(id, options) {
1228
1193
  const settings = {
1229
1194
  format: 'blob',
1230
1195
  ...options,
@@ -1245,7 +1210,7 @@ export default class TeraFyServer {
1245
1210
  * @param {String} name The name + relative directory path component
1246
1211
  * @returns {Promise<ProjectFile>} The eventual ProjectFile created
1247
1212
  */
1248
- createProjectFile(name: string): Promise<any> {
1213
+ createProjectFile(name) {
1249
1214
  return Promise.resolve()
1250
1215
  .then(()=> app.service('$supabase').fileUpload(app.service('$projects').convertRelativePath(name), {
1251
1216
  file: new Blob([''], {type: 'text/plain'}),
@@ -1258,9 +1223,10 @@ export default class TeraFyServer {
1258
1223
  .then(()=> this.getProjectFile(name, {
1259
1224
  cache: false, // Force cache to update, as this is a new file
1260
1225
  }))
1261
- .then((file: any) => file || Promise.reject(`Could not create new file "${name}"`))
1226
+ .then(file => file || Promise.reject(`Could not create new file "${name}"`))
1262
1227
  }
1263
1228
 
1229
+
1264
1230
  /**
1265
1231
  * Moves a project file to a new name/path.
1266
1232
  * The file's unique ID (UUID) remains the same, but its 'name' (relative path) and associated properties will be updated.
@@ -1271,14 +1237,11 @@ export default class TeraFyServer {
1271
1237
  *
1272
1238
  * @param {Object} [options] Additional options to mutate behaviour.
1273
1239
  * @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing.
1274
- * @param {Boolean} [options.overwrite=true] If true (default), moving a file to a `newName` that already exists will overwrite the existing file.
1275
- * This aligns with the default behavior of the underlying Supabase storage `move` operation.
1276
- * If set to false, the function would ideally check and prevent overwrite, but current implementation relies on underlying storage behavior.
1240
+ * @param {Boolean} [options.overwrite=true] If true (default), moving a file to a `newName` that already exists will overwrite the existing file. This aligns with the default behavior of the underlying Supabase storage `move` operation. If set to false, the function would ideally check and prevent overwrite, but current implementation relies on underlying storage behavior.
1277
1241
  *
1278
- * @returns {Promise<ProjectFile | null>} A promise which resolves to the updated ProjectFile object for the moved file if found after the operation,
1279
- * or null if the file could not be located post-move (e.g., if its ID changed unexpectedly or it was deleted).
1242
+ * @returns {Promise<ProjectFile|null>} A promise which resolves to the updated ProjectFile object for the moved file if found after the operation, or null if the file could not be located post-move (e.g., if its ID changed unexpectedly or it was deleted).
1280
1243
  */
1281
- async moveProjectFile(sourceId: string, newName: string, options?: any): Promise<any | null> {
1244
+ async moveProjectFile(sourceId, newName, options) {
1282
1245
  const settings = {
1283
1246
  autoRequire: true,
1284
1247
  overwrite: true, // Matches Supabase client's default behavior for move.
@@ -1320,7 +1283,7 @@ export default class TeraFyServer {
1320
1283
  if (sourceStoragePath === targetStoragePath) {
1321
1284
  this.debug('INFO', 2, `moveProjectFile: Source path "${sourceStoragePath}" and target path "${targetStoragePath}" are identical. No move operation needed.`);
1322
1285
  // Attempt to find the file by ID, as its name should match newName if paths are identical.
1323
- const currentFile = projectService.activeFiles?.find((f: any) => f.id === sourceId);
1286
+ const currentFile = projectService.activeFiles?.find(f => f.id === sourceId);
1324
1287
  return currentFile || null;
1325
1288
  }
1326
1289
 
@@ -1332,18 +1295,18 @@ export default class TeraFyServer {
1332
1295
  // The standard Supabase `move` overwrites by default. If settings.overwrite is false,
1333
1296
  // a more complex $supabase.fileMove or a pre-check here would be needed.
1334
1297
  // For now, we pass the conceptual overwrite intent, but actual behavior depends on $supabase.fileMove.
1335
- await supabaseService.fileMove(sourceStoragePath, targetStoragePath, { overwrite: settings.overwrite });
1298
+ await supabaseService.fileMove(sourceStoragePath, targetStoragePath, {overwrite: settings.overwrite});
1336
1299
 
1337
1300
  this.debug('INFO', 2, `Project file successfully moved from "${sourceStoragePath}" to "${targetStoragePath}".`);
1338
1301
 
1339
1302
  // After a successful move, refresh the local cache of project files.
1340
- await projectService.refreshFiles({ lazy: false });
1303
+ await projectService.refreshFiles({lazy: false});
1341
1304
  this.debug('INFO', 3, 'Project files list refreshed after move operation.');
1342
1305
 
1343
1306
  // The file's unique ID (UUID) should remain the same.
1344
1307
  // Find the updated ProjectFile entry in the refreshed cache using the original sourceId.
1345
- const refreshedFiles = projectService.activeFiles as any[]; // Assuming activeFiles is Array<ProjectFile>
1346
- const movedFileEntry = refreshedFiles?.find((file: any) => file.id === sourceId);
1308
+ const refreshedFiles = projectService.activeFiles;
1309
+ const movedFileEntry = refreshedFiles?.find(file => file.id === sourceId);
1347
1310
 
1348
1311
  if (movedFileEntry) {
1349
1312
  if (movedFileEntry.name !== newName) {
@@ -1356,13 +1319,14 @@ export default class TeraFyServer {
1356
1319
  this.debug('ERROR', 1, `moveProjectFile: Failed to find file with original ID "${sourceId}" in the refreshed list after the move. The file might have been deleted or its ID changed unexpectedly.`);
1357
1320
  return null;
1358
1321
  }
1359
- } catch (error: any) {
1322
+ } catch (error) {
1360
1323
  this.debug('ERROR', 1, `Error during project file move from "${sourceStoragePath}" to "${targetStoragePath}":`, error);
1361
1324
  // Re-throw a more specific error or the original error for the caller to handle.
1362
1325
  throw new Error(`Failed to move project file "${sourceId}" to "${newName}": ${error.message || String(error)}`, {cause: error});
1363
1326
  }
1364
1327
  }
1365
1328
 
1329
+
1366
1330
  /**
1367
1331
  * Remove a project file by its ID
1368
1332
  *
@@ -1370,7 +1334,7 @@ export default class TeraFyServer {
1370
1334
  *
1371
1335
  * @returns {Promise} A promise which resolves when the operation has completed
1372
1336
  */
1373
- deleteProjectFile(id: string): Promise<null> {
1337
+ deleteProjectFile(id) {
1374
1338
  return app.service('$supabase').fileRemove(app.service('$projects').decodeFilePath(id))
1375
1339
  .then(()=> app.service('$projects').refreshFiles({ // Force a local file list update
1376
1340
  lazy: false,
@@ -1394,26 +1358,26 @@ export default class TeraFyServer {
1394
1358
  *
1395
1359
  * @returns {Promise} A promise which will resolve when the write operation has completed
1396
1360
  */
1397
- setProjectFileContents(id: string | any | null, contents: any, options?: any): Promise<null> {
1361
+ setProjectFileContents(id, contents, options) {
1398
1362
  // Argument Mangling Logic (Simplified)
1399
- let fileId: string | null = null; // eslint-disable-line no-useless-assignment
1400
- let fileContents: any;
1401
- let mergedOptions: any;
1363
+ let fileId = null; // eslint-disable-line no-useless-assignment
1364
+ let fileContents;
1365
+ let mergedOptions;
1402
1366
 
1403
1367
  if (typeof id === 'string') {
1404
1368
  fileId = id;
1405
1369
  fileContents = contents;
1406
- mergedOptions = { ...options };
1370
+ mergedOptions = {...options};
1407
1371
  } else if (id !== null && typeof id === 'object' && !(id instanceof Blob) && !(id instanceof File) && !(id instanceof FormData) && !Array.isArray(id)) {
1408
1372
  // Assuming called as (optionsObject)
1409
- mergedOptions = { ...id };
1373
+ mergedOptions = {...id};
1410
1374
  fileId = mergedOptions.id ?? null;
1411
1375
  fileContents = mergedOptions.contents;
1412
1376
  } else {
1413
1377
  // Assuming called as (contents, options)
1414
1378
  fileId = options?.id ?? null; // Check options for id if provided
1415
1379
  fileContents = id; // First arg is contents
1416
- mergedOptions = { ...contents }; // Second arg is options
1380
+ mergedOptions = {...contents}; // Second arg is options
1417
1381
  }
1418
1382
 
1419
1383
  if (fileContents === undefined) throw new Error('setProjectFileContents requires contents to save.');
@@ -1434,7 +1398,7 @@ export default class TeraFyServer {
1434
1398
  if (settings.autoRequire)
1435
1399
  return this.requireProject();
1436
1400
  })
1437
- .then((): Promise<string> => { // Ensure the promise returns a string (fileId)
1401
+ .then(()=> {
1438
1402
  if (settings.id) {
1439
1403
  // Validate the provided ID exists? Optional, but good practice.
1440
1404
  // For now, just return it assuming it's valid.
@@ -1448,12 +1412,12 @@ export default class TeraFyServer {
1448
1412
  saveFilename: settings.filename,
1449
1413
  autoRequire: false, // Handled above anyway
1450
1414
  })
1451
- .then((file: any) => {
1415
+ .then(file => {
1452
1416
  if (!file || !file.id) throw new Error('File selection cancelled or failed.');
1453
1417
  return file.id; // Return the selected file ID
1454
1418
  });
1455
1419
  })
1456
- .then((resolvedFileId: string) => {
1420
+ .then(resolvedFileId => {
1457
1421
  settings.id = resolvedFileId; // Update settings.id with the resolved/validated ID
1458
1422
  if (!settings.id) throw new Error("Could not determine file ID to save to."); // Final check
1459
1423
  return app.service('$supabase').fileSet(app.service('$projects').decodeFilePath(settings.id), fileContents, {
@@ -1478,7 +1442,7 @@ export default class TeraFyServer {
1478
1442
  * @returns {Promise<void>} A promise that resolves when the folder is created or ensured.
1479
1443
  * @throws {Error} If no project is active (and autoRequire is false), or if folderPath is invalid, or if the creation fails.
1480
1444
  */
1481
- async createProjectFolder(folderPath: string, options?: { autoRequire?: boolean }): Promise<void> {
1445
+ async createProjectFolder(folderPath, options) {
1482
1446
  const settings = {
1483
1447
  autoRequire: true,
1484
1448
  ...options,
@@ -1514,7 +1478,7 @@ export default class TeraFyServer {
1514
1478
 
1515
1479
  try {
1516
1480
  await app.service('$supabase').fileUpload(supabasePath, {
1517
- file: new Blob([''], { type: 'text/plain' }), // Consistent with createProjectFile
1481
+ file: new Blob([''], {type: 'text/plain'}), // Consistent with createProjectFile
1518
1482
  mode: 'encoded',
1519
1483
  overwrite: true, // Makes the operation idempotent
1520
1484
  toast: false,
@@ -1522,14 +1486,15 @@ export default class TeraFyServer {
1522
1486
  });
1523
1487
 
1524
1488
  // Refresh the local file list cache to include the new placeholder/folder
1525
- await app.service('$projects').refreshFiles({ lazy: false });
1489
+ await app.service('$projects').refreshFiles({lazy: false});
1526
1490
  this.debug('INFO', 2, `Project folder "${cleanFolderPath}" ensured/created via placeholder at "${relativePlaceholderPath}".`);
1527
- } catch (error: any) {
1491
+ } catch (error) {
1528
1492
  this.debug('ERROR', 1, `Failed to create/ensure project folder "${cleanFolderPath}" via placeholder "${relativePlaceholderPath}"`, error);
1529
1493
  throw new Error(`Failed to create project folder "${cleanFolderPath}": ${error.message || String(error)}`, {cause: error});
1530
1494
  }
1531
1495
  }
1532
1496
 
1497
+
1533
1498
  /**
1534
1499
  * Deletes a "folder" and all its contents from the project's file storage.
1535
1500
  * This involves listing all files under the given folder path (prefix) and removing them.
@@ -1540,7 +1505,7 @@ export default class TeraFyServer {
1540
1505
  * @returns {Promise<null>} A promise that resolves with null when the folder and its contents are deleted.
1541
1506
  * @throws {Error} If no project is active (and autoRequire is false), or if folderPath is invalid, or if deletion fails.
1542
1507
  */
1543
- async deleteProjectFolder(folderPath: string, options?: { autoRequire?: boolean }): Promise<null> {
1508
+ async deleteProjectFolder(folderPath, options) {
1544
1509
  const settings = {
1545
1510
  autoRequire: true,
1546
1511
  ...options,
@@ -1571,7 +1536,11 @@ export default class TeraFyServer {
1571
1536
  const pathPrefix = cleanFolderPath + '/'; // Files inside the folder will start with this prefix
1572
1537
 
1573
1538
  // Fetch all files, ensuring the list is up-to-date
1574
- const allFiles = await this.getProjectFiles({ autoRequire: false, lazy: false, meta: true });
1539
+ const allFiles = await this.getProjectFiles({
1540
+ autoRequire: false,
1541
+ lazy: false,
1542
+ meta: true,
1543
+ });
1575
1544
 
1576
1545
  const filesToDelete = allFiles.filter(file => {
1577
1546
  // file.name is the relative path like "documents/report.pdf" or "documents/archive/old.zip"
@@ -1583,7 +1552,7 @@ export default class TeraFyServer {
1583
1552
  this.debug('INFO', 2, `No files found under project folder prefix "${pathPrefix}". The folder might be empty or not exist.`);
1584
1553
  // It's possible the folder was already empty or never existed.
1585
1554
  // Refresh files just in case, though `getProjectFiles` with `lazy: false` should be current.
1586
- await app.service('$projects').refreshFiles({ lazy: false });
1555
+ await app.service('$projects').refreshFiles({lazy: false});
1587
1556
  return null;
1588
1557
  }
1589
1558
 
@@ -1597,9 +1566,9 @@ export default class TeraFyServer {
1597
1566
  await app.service('$supabase').fileRemove(supabasePathsToDelete);
1598
1567
 
1599
1568
  // Refresh the local file list cache
1600
- await app.service('$projects').refreshFiles({ lazy: false });
1569
+ await app.service('$projects').refreshFiles({lazy: false});
1601
1570
  this.debug('INFO', 2, `Project folder "${cleanFolderPath}" (prefix "${pathPrefix}") and its ${filesToDelete.length} contents deleted.`);
1602
- } catch (error: any) {
1571
+ } catch (error) {
1603
1572
  this.debug('ERROR', 1, `Failed to delete contents of project folder "${cleanFolderPath}" (prefix "${pathPrefix}")`, error);
1604
1573
  throw new Error(`Failed to delete project folder "${cleanFolderPath}": ${error.message || String(error)}`, {cause: error});
1605
1574
  }
@@ -1624,7 +1593,7 @@ export default class TeraFyServer {
1624
1593
  *
1625
1594
  * @returns {Promise<Array<Ref>>} A collection of references from the selected file
1626
1595
  */
1627
- selectProjectLibrary(options?: any): Promise<any[]> {
1596
+ selectProjectLibrary(options) {
1628
1597
  const settings = {
1629
1598
  title: 'Select a citation library',
1630
1599
  hint: null,
@@ -1643,7 +1612,7 @@ export default class TeraFyServer {
1643
1612
 
1644
1613
  return app.service('$projects').promise()
1645
1614
  .then(()=> this.selectProjectFile(settings)) // Pass merged settings
1646
- .then((selectedFile: any) => {
1615
+ .then(selectedFile => {
1647
1616
  if (!selectedFile || !selectedFile.id) throw new Error('Library selection failed or was cancelled.');
1648
1617
  // Pass relevant options down to getProjectLibrary
1649
1618
  return this.getProjectLibrary(selectedFile.id, settings);
@@ -1664,17 +1633,17 @@ export default class TeraFyServer {
1664
1633
  *
1665
1634
  * @returns {Promise<Array<Ref>>|Promise<*>} A collection of references (default bevahiour) or a whatever format was requested
1666
1635
  */
1667
- getProjectLibrary(id: string, options?: any): Promise<any> {
1636
+ getProjectLibrary(id, options) {
1668
1637
  const settings = {
1669
1638
  format: 'pojo',
1670
1639
  autoRequire: true,
1671
- // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
1672
- filter: (file: any) => true, // Default filter
1673
- find: (files: any[]) => files[0], // Default find
1640
+ // eslint-disable-next-line no-unused-vars
1641
+ filter: file => true, // Default filter
1642
+ find: files => files[0], // Default find
1674
1643
  ...options,
1675
1644
  };
1676
1645
 
1677
- const filePath: string = app.service('$projects').decodeFilePath(id);
1646
+ const filePath = app.service('$projects').decodeFilePath(id);
1678
1647
 
1679
1648
  return Promise.resolve()
1680
1649
  .then(()=> settings.autoRequire && this.requireProject())
@@ -1710,11 +1679,11 @@ export default class TeraFyServer {
1710
1679
  * Save back a citation library from some input
1711
1680
  *
1712
1681
  * @param {String} [id] File ID to save back to, if omitted a file will be prompted for
1713
- * @param {Array<RefLibRef>|Blob|File} [refs] Collection of references for the selected library or the raw Blob/File
1682
+ * @param {Array<Object>|Blob|File} [refs] Collection of references for the selected library or the raw Blob/File
1714
1683
  *
1715
1684
  * @param {Object} [options] Additional options to mutate behaviour
1716
1685
  * @param {String} [options.id] Alternate method to specify the file ID to save as, if omitted one will be prompted for
1717
- * @param {Array<RefLibRef>|Blob|File} [options.refs] Alternate method to specify the refs to save as an array or raw Blob/File
1686
+ * @param {Array<Object>|Blob|File} [options.refs] Alternate method to specify the refs to save as an array or raw Blob/File
1718
1687
  * @param {String} [options.format='auto'] Input format used. ENUM: 'auto' (try to figure it out from context), 'pojo' (JS array of RefLib references), 'blob' (raw JS Blob object), 'file' (named JS File object)
1719
1688
  * @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing
1720
1689
  * @param {String|Array<String>} [options.hint] Hint(s) to store against the library. Generally corresponds to the current operation being performed - e.g. 'deduped'
@@ -1725,26 +1694,26 @@ export default class TeraFyServer {
1725
1694
  *
1726
1695
  * @returns {Promise} A promise which resolves when the save operation has completed
1727
1696
  */
1728
- setProjectLibrary(id: string | any | null, refs?: any, options?: any): Promise<null> {
1697
+ setProjectLibrary(id, refs, options) {
1729
1698
  // Argument Mangling Logic (Simplified)
1730
- let fileId: string | null = null; // eslint-disable-line no-useless-assignment
1731
- let libraryRefs: any;
1732
- let mergedOptions: any;
1699
+ let fileId = null; // eslint-disable-line no-useless-assignment
1700
+ let libraryRefs;
1701
+ let mergedOptions;
1733
1702
 
1734
1703
  if (typeof id === 'string') {
1735
1704
  fileId = id;
1736
1705
  libraryRefs = refs;
1737
- mergedOptions = { ...options };
1706
+ mergedOptions = {...options};
1738
1707
  } else if (id !== null && typeof id === 'object' && !(id instanceof Blob) && !(id instanceof File) && !Array.isArray(id)) {
1739
1708
  // Assuming called as (optionsObject)
1740
- mergedOptions = { ...id };
1709
+ mergedOptions = {...id};
1741
1710
  fileId = mergedOptions.id ?? null;
1742
1711
  libraryRefs = mergedOptions.refs;
1743
1712
  } else {
1744
1713
  // Assuming called as (refs, options)
1745
1714
  fileId = options?.id ?? null; // Check options for id if provided
1746
1715
  libraryRefs = id; // First arg is refs
1747
- mergedOptions = { ...refs }; // Second arg is options
1716
+ mergedOptions = {...refs}; // Second arg is options
1748
1717
  }
1749
1718
 
1750
1719
  if (libraryRefs === undefined) throw new Error('setProjectLibrary requires refs to save.');
@@ -1762,10 +1731,10 @@ export default class TeraFyServer {
1762
1731
  ...mergedOptions // Apply options derived from mangling
1763
1732
  };
1764
1733
 
1765
- let filePath: any; // Eventual Supabase path to use
1734
+ let filePath; // Eventual Supabase path to use
1766
1735
  return Promise.resolve()
1767
1736
  .then(()=> settings.autoRequire && this.requireProject())
1768
- .then((): Promise<string> => { // Ensure promise returns string (fileId)
1737
+ .then(()=> {
1769
1738
  if (settings.id) {
1770
1739
  // Optional: Validate settings.id exists?
1771
1740
  return Promise.resolve(settings.id);
@@ -1781,12 +1750,12 @@ export default class TeraFyServer {
1781
1750
  },
1782
1751
  autoRequire: false, // Handled above anyway
1783
1752
  })
1784
- .then((file: any) => {
1753
+ .then(file => {
1785
1754
  if (!file || !file.id) throw new Error('File selection cancelled or failed.');
1786
1755
  return file.id; // Return selected file ID
1787
1756
  });
1788
1757
  })
1789
- .then((resolvedFileId: string)=> { // Compute filePath
1758
+ .then(resolvedFileId => { // Compute filePath
1790
1759
  settings.id = resolvedFileId; // Update settings.id
1791
1760
  if (!settings.id) throw new Error("Could not determine file ID to save library to.");
1792
1761
  filePath = app.service('$projects').decodeFilePath(settings.id);
@@ -1821,7 +1790,7 @@ export default class TeraFyServer {
1821
1790
  throw new Error(`Unsupported library format "${settings.format}"`);
1822
1791
  }
1823
1792
  })
1824
- .then((fileBlob: File) => app.service('$supabase').fileUpload(filePath, { // Expect File type
1793
+ .then(fileBlob => app.service('$supabase').fileUpload(filePath, {
1825
1794
  file: fileBlob,
1826
1795
  overwrite: settings.overwrite,
1827
1796
  mode: 'encoded',
@@ -1841,7 +1810,7 @@ export default class TeraFyServer {
1841
1810
  * @param {Object} log The log entry to create
1842
1811
  * @returns {Promise} A promise which resolves when the operation has completed
1843
1812
  */
1844
- projectLog(log: any): Promise<void> {
1813
+ projectLog(log) {
1845
1814
  return app.service('$projects').log(log);
1846
1815
  }
1847
1816
  // }}}
@@ -1855,7 +1824,7 @@ export default class TeraFyServer {
1855
1824
  * @param {String} [options.path] The URL path segment to restore on next refresh
1856
1825
  * @param {String} [options.title] The page title associated with the path
1857
1826
  */
1858
- setPage(options: any): void {
1827
+ setPage(options) {
1859
1828
  app.service('$projects').setPage(options);
1860
1829
  }
1861
1830
  // }}}
@@ -1867,7 +1836,7 @@ export default class TeraFyServer {
1867
1836
  *
1868
1837
  * @param {Object} [options] Additional options to merge into `settings`
1869
1838
  */
1870
- constructor(options?: any) {
1839
+ constructor(options) {
1871
1840
  Object.assign(this.settings, options);
1872
1841
  }
1873
1842
 
@@ -1875,7 +1844,7 @@ export default class TeraFyServer {
1875
1844
  /**
1876
1845
  * Initialize the browser listener
1877
1846
  */
1878
- init(): void {
1847
+ init() {
1879
1848
  // Ensure this only runs in a browser context
1880
1849
  if (typeof window !== 'undefined' && typeof globalThis !== 'undefined') {
1881
1850
  globalThis.addEventListener('message', this.acceptMessage.bind(this));
@@ -1898,7 +1867,7 @@ export default class TeraFyServer {
1898
1867
  *
1899
1868
  * @returns {Promise} A promise which resolves when the alert has been dismissed
1900
1869
  */
1901
- uiAlert(text: string | any, options?: any): Promise<void> {
1870
+ uiAlert(text, options) {
1902
1871
  const settings = {
1903
1872
  body: 'Alert!',
1904
1873
  isHtml: false,
@@ -1938,7 +1907,7 @@ export default class TeraFyServer {
1938
1907
  *
1939
1908
  * @returns {Promise} A promise which resolves with `Promise.resolve('OK')` or rejects with `Promise.reject('CANCEL')`
1940
1909
  */
1941
- uiConfirm(text: string | any, options?: any): Promise<'OK'> {
1910
+ uiConfirm(text, options) {
1942
1911
  const settings = {
1943
1912
  body: 'Confirm?',
1944
1913
  isHtml: false,
@@ -1968,7 +1937,7 @@ export default class TeraFyServer {
1968
1937
  },
1969
1938
  ],
1970
1939
  })
1971
- .then(()=> 'OK' as const) // Resolve with 'OK' if OK button clicked
1940
+ .then(()=> 'OK') // Resolve with 'OK' if OK button clicked
1972
1941
  .catch(()=> Promise.reject('CANCEL')) // Reject with 'CANCEL' if Cancel button clicked or closed
1973
1942
  );
1974
1943
  }
@@ -1988,7 +1957,7 @@ export default class TeraFyServer {
1988
1957
  *
1989
1958
  * @returns {Promise} A promise which resolves with `Promise.resolve('OK')`
1990
1959
  */
1991
- uiJson(data: any, options?: any): Promise<'OK'> {
1960
+ uiJson(data, options) {
1992
1961
  const settings = {
1993
1962
  body: '',
1994
1963
  isHtml: false,
@@ -2007,7 +1976,7 @@ export default class TeraFyServer {
2007
1976
  data: data,
2008
1977
  },
2009
1978
  })
2010
- .then(()=> 'OK' as const) // Resolve with 'OK' if OK button clicked
1979
+ .then(()=> 'OK') // Resolve with 'OK' if OK button clicked
2011
1980
  .catch(()=> Promise.reject('CANCEL')) // Reject with 'CANCEL' if Cancel button clicked or closed
2012
1981
  );
2013
1982
  }
@@ -2019,14 +1988,14 @@ export default class TeraFyServer {
2019
1988
  * @function uiPanic
2020
1989
  * @param {String} [text] Text to display
2021
1990
  */
2022
- uiPanic(text: any): void {
1991
+ uiPanic(text) {
2023
1992
  // Ensure window context exists
2024
1993
  if (typeof window !== 'undefined' && typeof window.panic === 'function') {
2025
1994
  window.panic(text);
2026
1995
  } else {
2027
1996
  console.error("PANIC (window.panic not available):", text);
2028
1997
  // Fallback behavior if window.panic doesn't exist
2029
- alert(`PANIC: ${text}`);
1998
+ window.alert(`PANIC: ${text}`);
2030
1999
  }
2031
2000
  }
2032
2001
 
@@ -2045,7 +2014,7 @@ export default class TeraFyServer {
2045
2014
  *
2046
2015
  * @returns {Promise} A promise which resolves when the dialog has been updated
2047
2016
  */
2048
- uiProgress(options?: any): Promise<void> {
2017
+ uiProgress(options) {
2049
2018
  const currentOptions = options === false ? {close: true} : options || {};
2050
2019
 
2051
2020
  if (currentOptions.close) { // Asked to close the dialog
@@ -2089,7 +2058,15 @@ export default class TeraFyServer {
2089
2058
  }
2090
2059
  }
2091
2060
 
2092
- _uiProgress: { options: any | null, promise: Promise<any> | null } = {
2061
+
2062
+ /**
2063
+ * State storage for the uiProgress() function
2064
+ *
2065
+ * @type {Object}
2066
+ * @property {Object} options Options object used to setup the initial uiProgress() call
2067
+ * @property {Promise} promise The promise used to manage the uiProgress dialog
2068
+ */
2069
+ _uiProgress = {
2093
2070
  options: null,
2094
2071
  promise: null,
2095
2072
  };
@@ -2110,7 +2087,7 @@ export default class TeraFyServer {
2110
2087
  *
2111
2088
  * @returns {Promise<*>} Either the eventual user value or a throw with `Promise.reject('CANCEL')`
2112
2089
  */
2113
- uiPrompt(text: string | any, options?: any): Promise<any> {
2090
+ uiPrompt(text, options) {
2114
2091
  const settings = {
2115
2092
  body: '',
2116
2093
  isHtml: false,
@@ -2141,19 +2118,19 @@ export default class TeraFyServer {
2141
2118
  class: 'btn btn-success',
2142
2119
  icon: 'fas fa-check',
2143
2120
  title: 'Ok',
2144
- click(): any {
2121
+ click() {
2145
2122
  // Assuming 'this' is the component instance with 'newValue' property
2146
2123
  // And $prompt service is available globally via 'app'
2147
- app.service('$prompt').close(true, (this as any).newValue); // Use app.$prompt.close
2124
+ app.service('$prompt').close(true, this.newValue); // Use app.$prompt.close
2148
2125
  },
2149
2126
  },
2150
2127
  'cancel', // Standard cancel button that rejects
2151
2128
  ],
2152
2129
  })
2153
2130
  )
2154
- .then((answer: any) => {
2131
+ .then(answer => {
2155
2132
  // Check if the answer is non-empty or if required is false
2156
- if (answer || !settings.required) {
2133
+ if (answer || !settings.required) { // eslint-disable-line unicorn/prefer-ternary
2157
2134
  return answer;
2158
2135
  } else {
2159
2136
  // If required and answer is empty/nullish, treat as cancel
@@ -2172,7 +2149,7 @@ export default class TeraFyServer {
2172
2149
  *
2173
2150
  * @returns {Void} This function is fatal
2174
2151
  */
2175
- uiThrow(error: any): Promise<void> {
2152
+ uiThrow(error) {
2176
2153
  return this.requestFocus(()=>
2177
2154
  app.service('$errors').catch(error)
2178
2155
  );
@@ -2192,7 +2169,7 @@ export default class TeraFyServer {
2192
2169
  *
2193
2170
  * @returns {WindowProxy} The opened window object (if `noopener` is not set in permissions)
2194
2171
  */
2195
- uiWindow(url: string | URL, options?: UiWindowOptions): WindowProxy | null {
2172
+ uiWindow(url, options) {
2196
2173
  // Ensure this runs only in browser context
2197
2174
  if (typeof window === 'undefined' || typeof screen === 'undefined') return null;
2198
2175
 
@@ -2237,7 +2214,7 @@ export default class TeraFyServer {
2237
2214
  * @param {Object} [options] Additional options to mutate behaviour
2238
2215
  * @param {Boolean|String} [options.logo=false] Add a logo to the output, if boolean true the Tera-tools logo is used otherwise specify a path or URL
2239
2216
  */
2240
- uiSplat(content: Element | string | false, options?: any): void {
2217
+ uiSplat(content, options) {
2241
2218
  // Ensure this runs only in browser context
2242
2219
  if (typeof window === 'undefined' || typeof document === 'undefined') return;
2243
2220
 
@@ -2256,12 +2233,12 @@ export default class TeraFyServer {
2256
2233
  return;
2257
2234
  }
2258
2235
 
2259
- let compiledContent: Element;
2236
+ let compiledContent;
2260
2237
  if (typeof content == 'string') {
2261
2238
  const el = document.createElement('div')
2262
2239
  el.innerHTML = content;
2263
2240
  // If the string contained multiple top-level elements, wrap them
2264
- compiledContent = el.children.length === 1 ? el.firstElementChild! : el;
2241
+ compiledContent = el.children.length === 1 ? el.firstElementChild : el;
2265
2242
  } else {
2266
2243
  compiledContent = content;
2267
2244
  }
@@ -2291,18 +2268,18 @@ export default class TeraFyServer {
2291
2268
  * - 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.
2292
2269
  * - All subsequent arguments are passed to the console as the log message.
2293
2270
  */
2294
- debug(...inputArgs: any[]): void {
2271
+ debug(...inputArgs) {
2295
2272
  // Ensure console exists
2296
2273
  if (typeof console === 'undefined') return;
2297
2274
  if (!this.settings.devMode || this.settings.verbosity < 1) return; // Debugging is disabled
2298
2275
 
2299
- let method: keyof Console = 'log'; // Default method
2276
+ let method = 'log'; // Default method
2300
2277
  let verboseLevel = 1;
2301
2278
  const msgArgs = [...inputArgs]; // Copy args to modify
2302
2279
 
2303
2280
  // Argument mangling for prefix method + verbosity level {{{
2304
2281
  if (typeof msgArgs[0] == 'string' && ['INFO', 'LOG', 'WARN', 'ERROR'].includes(msgArgs[0].toUpperCase())) {
2305
- const potentialMethod = msgArgs.shift().toLowerCase() as keyof Console;
2282
+ const potentialMethod = msgArgs.shift().toLowerCase();
2306
2283
  // Check if it's a valid console method
2307
2284
  if (potentialMethod in console) {
2308
2285
  method = potentialMethod;
@@ -2318,13 +2295,11 @@ export default class TeraFyServer {
2318
2295
 
2319
2296
  if (this.settings.verbosity < verboseLevel) return; // Called but this output is too verbose for our settings - skip
2320
2297
 
2321
- // Use type assertion for dynamic console method call
2322
- (console as any)[method](
2298
+ console[method](
2323
2299
  '%c[TERA-FY SERVER]',
2324
2300
  'font-weight: bold; color: #4d659c;',
2325
2301
  ...msgArgs,
2326
2302
  );
2327
2303
  }
2328
- /* eslint-enable */
2329
2304
  // }}}
2330
2305
  }