@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.
Files changed (66) hide show
  1. package/.vscode/settings.json +5 -0
  2. package/CHANGELOG.md +22 -0
  3. package/api.md +35 -36
  4. package/dist/lib/projectFile.d.ts +3 -3
  5. package/dist/lib/projectFile.js +4 -3
  6. package/dist/lib/projectFile.js.map +1 -1
  7. package/dist/lib/syncro/entities.js +11 -10
  8. package/dist/lib/syncro/entities.js.map +1 -1
  9. package/dist/lib/syncro/keyed.d.ts +2 -2
  10. package/dist/lib/syncro/keyed.js +23 -23
  11. package/dist/lib/syncro/keyed.js.map +1 -1
  12. package/dist/lib/syncro/syncro.d.ts +15 -13
  13. package/dist/lib/syncro/syncro.js +84 -59
  14. package/dist/lib/syncro/syncro.js.map +1 -1
  15. package/dist/lib/terafy.bootstrapper.d.ts +2 -2
  16. package/dist/lib/terafy.bootstrapper.js +15 -16
  17. package/dist/lib/terafy.bootstrapper.js.map +1 -1
  18. package/dist/lib/terafy.client.d.ts +24 -25
  19. package/dist/lib/terafy.client.js +50 -48
  20. package/dist/lib/terafy.client.js.map +1 -1
  21. package/dist/lib/terafy.proxy.js +4 -2
  22. package/dist/lib/terafy.proxy.js.map +1 -1
  23. package/dist/lib/terafy.server.d.ts +22 -8
  24. package/dist/lib/terafy.server.js +54 -58
  25. package/dist/lib/terafy.server.js.map +1 -1
  26. package/dist/plugin.vue2.es2019.js +210 -1224
  27. package/dist/plugins/base.d.ts +2 -2
  28. package/dist/plugins/base.js +1 -0
  29. package/dist/plugins/base.js.map +1 -1
  30. package/dist/plugins/firebase.d.ts +4 -4
  31. package/dist/plugins/firebase.js +7 -7
  32. package/dist/plugins/firebase.js.map +1 -1
  33. package/dist/plugins/vue2.d.ts +1 -1
  34. package/dist/plugins/vue2.js +6 -5
  35. package/dist/plugins/vue2.js.map +1 -1
  36. package/dist/plugins/vue3.js +6 -5
  37. package/dist/plugins/vue3.js.map +1 -1
  38. package/dist/terafy.bootstrapper.es2019.js +2 -2
  39. package/dist/terafy.bootstrapper.js +2 -2
  40. package/dist/terafy.es2019.js +2 -2
  41. package/dist/terafy.js +2 -2
  42. package/dist/utils/mixin.js +1 -1
  43. package/dist/utils/mixin.js.map +1 -1
  44. package/dist/utils/pDefer.d.ts +5 -1
  45. package/dist/utils/pDefer.js +6 -1
  46. package/dist/utils/pDefer.js.map +1 -1
  47. package/dist/utils/pathTools.d.ts +1 -1
  48. package/dist/utils/pathTools.js +2 -2
  49. package/dist/utils/pathTools.js.map +1 -1
  50. package/eslint.config.js +21 -7
  51. package/lib/projectFile.ts +5 -4
  52. package/lib/syncro/entities.ts +11 -10
  53. package/lib/syncro/keyed.ts +24 -24
  54. package/lib/syncro/syncro.ts +97 -60
  55. package/lib/terafy.bootstrapper.ts +15 -16
  56. package/lib/terafy.client.ts +62 -62
  57. package/lib/terafy.proxy.ts +8 -5
  58. package/lib/terafy.server.ts +75 -64
  59. package/package.json +5 -3
  60. package/plugins/base.ts +3 -2
  61. package/plugins/firebase.ts +12 -11
  62. package/plugins/vue2.ts +7 -6
  63. package/plugins/vue3.ts +6 -5
  64. package/utils/mixin.ts +1 -1
  65. package/utils/pDefer.ts +7 -2
  66. package/utils/pathTools.ts +3 -3
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-unused-vars */
1
2
  import { filesize } from 'filesize';
2
3
  import { pick, omit } from 'lodash-es';
3
4
  import type TeraFy from './terafy.client.js';
@@ -82,7 +83,7 @@ export default class ProjectFile {
82
83
  /**
83
84
  * An object representing meta file parts of a file name
84
85
  * @type {Object}
85
- * @property {String} basename The filename + extention (i.e. everything without directory name)
86
+ * @property {String} basename The filename + extension (i.e. everything without directory name)
86
87
  * @property {String} filename The file portion of the name (basename without the extension)
87
88
  * @property {String} ext The extension portion of the name (always lower case)
88
89
  * @property {String} dirName The directory path portion of the name
@@ -220,7 +221,7 @@ export default class ProjectFile {
220
221
  if (this.isFolder) {
221
222
  // Process all files in the folder
222
223
  this.files = this.files?.map(file => {
223
- let path = file.path.split(/\//).slice(3).join('/');
224
+ const path = file.path.split(/\//).slice(3).join('/');
224
225
  let url = this.url + '/' + file.name // Add file name to url
225
226
  // Parse url to show library instead of download if reflib file
226
227
  if (file.meta.reflib) {
@@ -253,7 +254,7 @@ export default class ProjectFile {
253
254
  /**
254
255
  * Fetch the raw file contents as a Blob
255
256
  *
256
- * @param {Object} [options] Additioanl options to mutate behaviour
257
+ * @param {Object} [options] Additional options to mutate behaviour
257
258
  *
258
259
  * @returns {Promise<Blob>} The eventual raw file contents as a Blob
259
260
  *
@@ -346,7 +347,7 @@ export default class ProjectFile {
346
347
  * as it's not included in the serialized output.
347
348
  *
348
349
  * @param {Object} data An input object created via `ProjectFiles.serialize()` (MUST include a 'tera' property added manually)
349
- * @returns {ProjectFile} A ProjectFile instance setup against the deserializzed data
350
+ * @returns {ProjectFile} A ProjectFile instance setup against the deserialized data
350
351
  */
351
352
 
352
353
  static deserialize(data: any): ProjectFile {
@@ -1,4 +1,5 @@
1
- // @ts-ignore
1
+ /* eslint-disable no-unused-vars */
2
+ // @ts-expect-error TODO: Remove when reflib gets declaration file
2
3
  import Reflib from '@iebh/reflib';
3
4
  import {v4 as uuid4} from 'uuid';
4
5
  import {nanoid} from 'nanoid';
@@ -72,7 +73,7 @@ const syncroConfig: SyncroConfig = {
72
73
  institutes: { // {{{
73
74
  singular: 'institute',
74
75
  async initState({supabasey, id}: {supabasey: BoundSupabaseyFunction, id: string}) {
75
- let institute = await supabasey((supabase) => supabase
76
+ const institute = await supabasey((supabase) => supabase
76
77
  .from('institutes')
77
78
  .select('data')
78
79
  .eq('id', id)
@@ -81,7 +82,7 @@ const syncroConfig: SyncroConfig = {
81
82
  if (institute) return institute.data; // institute is valid and already exists
82
83
  },
83
84
  flushState({supabasey, state, id}) {
84
- // @ts-ignore
85
+ // @ts-expect-error Typescript struggles to resolve supabasey import correctly
85
86
  return supabasey.rpc('syncro_merge_data', {
86
87
  table_name: 'institutes',
87
88
  entity_id: id,
@@ -92,14 +93,14 @@ const syncroConfig: SyncroConfig = {
92
93
  projects: { // {{{
93
94
  singular: 'project',
94
95
  async initState({supabasey, id}) {
95
- let projectData = await supabasey((supabase) => supabase
96
+ const projectData = await supabasey((supabase) => supabase
96
97
  .from('projects')
97
98
  .select('data')
98
99
  .eq('id', id)
99
100
  .maybeSingle<ProjectRow>()
100
101
  );
101
102
  if (!projectData) throw new Error(`Syncro project "${id}" not found`);
102
- let data = projectData.data;
103
+ const data = projectData.data;
103
104
 
104
105
  // MIGRATION - Move data.temp{} into Supabase files + add pointer to filename {{{
105
106
  if (
@@ -173,7 +174,7 @@ const syncroConfig: SyncroConfig = {
173
174
  async initState({supabasey, id, relation}) {
174
175
  if (!relation || !/_\*$/.test(relation)) throw new Error('Project library relation missing, path should resemble "project_library::${PROJECT}::${LIBRARY_FILE_ID}_*"');
175
176
 
176
- let fileId = relation.replace(/_\*$/, '');
177
+ const fileId = relation.replace(/_\*$/, '');
177
178
 
178
179
  const files = await supabasey((supabase) => supabase
179
180
  .storage
@@ -212,7 +213,7 @@ const syncroConfig: SyncroConfig = {
212
213
  singular: 'project namespace',
213
214
  async initState({supabasey, id, relation}) {
214
215
  if (!relation) throw new Error('Project namespace relation missing, path should resemble "project_namespaces::${PROJECT}::${RELATION}"');
215
- let rows = await supabasey((supabase) => supabase
216
+ const rows = await supabasey((supabase) => supabase
216
217
  .from('project_namespaces')
217
218
  .select('data')
218
219
  .eq('project', id)
@@ -253,7 +254,7 @@ const syncroConfig: SyncroConfig = {
253
254
  test: { // {{{
254
255
  singular: 'test',
255
256
  async initState({supabasey, id}: {supabasey: BoundSupabaseyFunction, id: string}) {
256
- let rows = await supabasey((supabase) => supabase
257
+ const rows = await supabasey((supabase) => supabase
257
258
  .from('test')
258
259
  .select('data')
259
260
  .eq('id', id)
@@ -274,7 +275,7 @@ const syncroConfig: SyncroConfig = {
274
275
  users: { // {{{
275
276
  singular: 'user',
276
277
  async initState({supabasey, id}: {supabasey: BoundSupabaseyFunction, id: string}) {
277
- let user = await supabasey((supabase) => supabase
278
+ const user = await supabasey((supabase) => supabase
278
279
  .from('users')
279
280
  .select('data')
280
281
  .eq('id', id)
@@ -283,7 +284,7 @@ const syncroConfig: SyncroConfig = {
283
284
  if (user) return user.data; // User is valid and already exists
284
285
 
285
286
  // User row doesn't already exist - need to create stub
286
- let newUser = await supabasey((supabase) => supabase
287
+ const newUser = await supabasey((supabase) => supabase
287
288
  .from('users')
288
289
  .insert<UserRow>({
289
290
  id,
@@ -20,7 +20,7 @@ interface FlushOptions {
20
20
  /**
21
21
  * @class SyncroKeyed
22
22
  * TERA Isomorphic SyncroKeyed class
23
- * Collate a single (potencially very large) single Syncro object by spltting it acrtoss multiple Syncros
23
+ * Collate a single (potentially very large) single Syncro object by splitting it across multiple Syncros
24
24
  * This makes the assumption that the Syncro content is a large object collection of objects - a keyed map collection
25
25
  * The original impetus is to allow TERA citation libraries to be held in a Syncro object and flushed back to Supabase when editing has completed
26
26
  */
@@ -66,7 +66,7 @@ export default class SyncroKeyed extends Syncro {
66
66
 
67
67
  if (!/\*/.test(path)) throw new Error('SyncroKeyed paths must contain at least one asterisk as an object pagination indicator');
68
68
 
69
- let {prefix, suffix} = /^(?<prefix>.+)\*(?<suffix>.*)$/.exec(path)!.groups!;
69
+ const {prefix, suffix} = /^(?<prefix>.+)\*(?<suffix>.*)$/.exec(path)!.groups!;
70
70
  this.keyedPath.getKey = (path: string, index: number): string => `${prefix}${index}${suffix}`;
71
71
  }
72
72
 
@@ -97,19 +97,19 @@ export default class SyncroKeyed extends Syncro {
97
97
  */
98
98
  mount(): Promise<Syncro> {
99
99
  // Cast the result to the expected interface
100
- let {entity, id, relation, fsCollection, fsId} = Syncro.pathSplit(this.path, {allowAsterisk: true}) as PathSplitResult;
100
+ const {entity, id, relation, fsCollection, fsId} = Syncro.pathSplit(this.path, {allowAsterisk: true}) as PathSplitResult;
101
101
 
102
102
  return Promise.resolve()
103
103
  .then(()=> new Promise<void>(resolve => { // Mount all members by looking for similar keys
104
104
  this.members = []; // Reset member list
105
105
 
106
- let seekMember = async (index: number) => {
107
- let memberId = fsId.replace('*', ''+index);
106
+ const seekMember = async (index: number) => {
107
+ const memberId = fsId.replace('*', ''+index);
108
108
  this.debug('Seek keyedMember', fsCollection, '#', memberId);
109
109
 
110
- let docRef = FirestoreDocRef(Syncro.firestore, fsCollection, memberId);
110
+ const docRef = FirestoreDocRef(Syncro.firestore, fsCollection, memberId);
111
111
 
112
- let doc = await FirestoreGetDoc(docRef);
112
+ const doc = await FirestoreGetDoc(docRef);
113
113
  if (doc.exists()) { // Found a matching entry
114
114
  // Expand member lookup with the new member by its numeric index
115
115
  await this.keyedMembersExpand(index);
@@ -132,11 +132,11 @@ export default class SyncroKeyed extends Syncro {
132
132
  this.debug('Populate initial SyncroKeyed state');
133
133
 
134
134
  // Extract base data + add document and return new hook
135
- const entityKey = entity as keyof typeof SyncroEntities;
135
+ const entityKey = entity;
136
136
  if (!SyncroEntities[entityKey]) throw new Error(`Unknown Sync entity "${entity}"`);
137
137
 
138
138
  // Go fetch the initial state object
139
- let state = await SyncroEntities[entityKey].initState({
139
+ const state = await SyncroEntities[entityKey].initState({
140
140
  supabasey: Syncro.supabasey,
141
141
  id, relation,
142
142
  });
@@ -144,7 +144,7 @@ export default class SyncroKeyed extends Syncro {
144
144
  await this.keyedAssign(state);
145
145
  })
146
146
  .then(()=> { // Create the reactive
147
- let reactive = this.getReactive(this.proxy());
147
+ const reactive = this.getReactive(this.proxy());
148
148
  // Assuming this.value should hold the reactive proxy
149
149
  // If this.value is inherited and has a specific type, this might need adjustment
150
150
  this.value = reactive.doc;
@@ -173,14 +173,14 @@ export default class SyncroKeyed extends Syncro {
173
173
 
174
174
  // Scope through members until we get a hit on the key
175
175
  get(target: SyncroKeyed, prop: string | symbol): any {
176
- let targetMember = target.members.find(m => m.value && prop in m.value);
176
+ const targetMember = target.members.find(m => m.value && prop in m.value);
177
177
  // Access value via targetMember.value if found
178
178
  return targetMember ? targetMember.value[prop] : undefined;
179
179
  },
180
180
 
181
181
  // Set the member key if one already exists, otherwise overflow onto the next member
182
182
  set(target: SyncroKeyed, prop: string | symbol, value: any): boolean {
183
- let targetMember = target.members.find(m => m.value && prop in m.value);
183
+ const targetMember = target.members.find(m => m.value && prop in m.value);
184
184
  if (targetMember && targetMember.value) {
185
185
  targetMember.value[prop] = value;
186
186
  } else {
@@ -192,7 +192,7 @@ export default class SyncroKeyed extends Syncro {
192
192
 
193
193
  // Remove a key
194
194
  deleteProperty(target: SyncroKeyed, prop: string | symbol): boolean {
195
- let targetMember = target.members.find(m => m.value && prop in m.value);
195
+ const targetMember = target.members.find(m => m.value && prop in m.value);
196
196
  if (targetMember && targetMember.value) {
197
197
  delete targetMember.value[prop];
198
198
  return true; // Indicate success
@@ -212,7 +212,7 @@ export default class SyncroKeyed extends Syncro {
212
212
  * @returns {Promise} A promise which resolves when the operation has completed
213
213
  */
214
214
  async flush(options?: FlushOptions): Promise<void> { // Match base class signature
215
- let settings: FlushOptions = {
215
+ const settings: FlushOptions = {
216
216
  destroy: false,
217
217
  ...options,
218
218
  };
@@ -240,7 +240,7 @@ export default class SyncroKeyed extends Syncro {
240
240
  * @returns {Promise<*>} A promise which resolves when the operation has completed with the set value
241
241
  */
242
242
  async keyedSet(key: string, value: any): Promise<any> {
243
- let candidateMember = this.members.find(m => m.value && Object.keys(m.value).length < this.keyedConfig.maxKeys);
243
+ const candidateMember = this.members.find(m => m.value && Object.keys(m.value).length < this.keyedConfig.maxKeys);
244
244
  if (candidateMember?.value) {
245
245
  candidateMember.value[key] = value;
246
246
  return value;
@@ -249,8 +249,8 @@ export default class SyncroKeyed extends Syncro {
249
249
  await this.keyedMembersExpand(); // Call without index to append
250
250
 
251
251
  // Get the newly added member
252
- // @ts-ignore
253
- let newMember = this.members.at(-1);
252
+ // eslint-disable-next-line unicorn/prefer-at
253
+ const newMember = this.members[this.members.length - 1];
254
254
  if (!newMember || !newMember.value) {
255
255
  throw new Error('Failed to expand members or new member has no value object');
256
256
  }
@@ -268,7 +268,7 @@ export default class SyncroKeyed extends Syncro {
268
268
 
269
269
  /**
270
270
  * Assign an entire in-memory object to members
271
- * This can be thought of as the optimized equivelent of Object.assign()
271
+ * This can be thought of as the optimized equivalent of Object.assign()
272
272
  * Use this when merging large objects as it can make optimizations
273
273
  *
274
274
  * @param {Object} state The value to merge
@@ -276,10 +276,10 @@ export default class SyncroKeyed extends Syncro {
276
276
  async keyedAssign(state: Record<string, any>): Promise<void> {
277
277
  // Can we assume we have a blank state - this speeds up existing key checks significantly
278
278
  // Ensure members[0] and its value exist
279
- let isBlank = this.members.length === 1 && this.members[0]?.value && Object.keys(this.members[0].value).length === 0;
279
+ const isBlank = this.members.length === 1 && this.members[0]?.value && Object.keys(this.members[0].value).length === 0;
280
280
 
281
281
  if (isBlank) {
282
- let chunks = chunk(Object.entries(state), this.keyedConfig.maxKeys)
282
+ const chunks = chunk(Object.entries(state), this.keyedConfig.maxKeys)
283
283
  .map(chunk => Object.fromEntries(chunk));
284
284
 
285
285
  await Promise.all(
@@ -327,20 +327,20 @@ export default class SyncroKeyed extends Syncro {
327
327
  return; // Exit if member already exists
328
328
  }
329
329
 
330
- let syncroPath = this.keyedPath.getKey(this.path, index);
330
+ const syncroPath = this.keyedPath.getKey(this.path, index);
331
331
  // Pass empty options object {} or specify allowAsterisk: false if needed
332
- let {fsCollection, fsId} = Syncro.pathSplit(syncroPath, {}) as PathSplitResult;
332
+ const {fsCollection, fsId} = Syncro.pathSplit(syncroPath, {}) as PathSplitResult;
333
333
  this.debug('Expand SyncroKeyed size to index=', index);
334
334
 
335
335
  // Create a new Syncro member, inheriteing some details from this parent item
336
- let syncro = new Syncro(`${fsCollection}::${fsId}`, {
336
+ const syncro = new Syncro(`${fsCollection}::${fsId}`, {
337
337
  debug: this.debug,
338
338
  getReactive: this.getReactive,
339
339
  });
340
340
 
341
341
  // Wait for mount to complete
342
342
  await syncro.mount({
343
- initialState: {}, // Force intital state to empty object so we don't get stuck in a loop
343
+ initialState: {}, // Force initial state to empty object so we don't get stuck in a loop
344
344
  });
345
345
 
346
346
  // Insert at the correct index if specified, otherwise push