@iebh/tera-fy 2.0.21 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/api.md +68 -66
- package/dist/lib/projectFile.d.ts +182 -0
- package/dist/lib/projectFile.js +157 -0
- package/dist/lib/projectFile.js.map +1 -0
- package/dist/lib/syncro/entities.d.ts +28 -0
- package/dist/lib/syncro/entities.js +203 -0
- package/dist/lib/syncro/entities.js.map +1 -0
- package/dist/lib/syncro/keyed.d.ts +95 -0
- package/dist/lib/syncro/keyed.js +286 -0
- package/dist/lib/syncro/keyed.js.map +1 -0
- package/dist/lib/syncro/syncro.d.ts +328 -0
- package/dist/lib/syncro/syncro.js +633 -0
- package/dist/lib/syncro/syncro.js.map +1 -0
- package/dist/lib/terafy.bootstrapper.d.ts +42 -0
- package/dist/lib/terafy.bootstrapper.js +130 -0
- package/dist/lib/terafy.bootstrapper.js.map +1 -0
- package/dist/lib/terafy.client.d.ts +532 -0
- package/dist/lib/terafy.client.js +1110 -0
- package/dist/lib/terafy.client.js.map +1 -0
- package/dist/lib/terafy.proxy.d.ts +66 -0
- package/dist/lib/terafy.proxy.js +123 -0
- package/dist/lib/terafy.proxy.js.map +1 -0
- package/dist/lib/terafy.server.d.ts +607 -0
- package/dist/lib/terafy.server.js +1774 -0
- package/dist/lib/terafy.server.js.map +1 -0
- package/dist/plugin.vue2.es2019.js +30 -13
- package/dist/plugins/base.d.ts +20 -0
- package/dist/plugins/base.js +21 -0
- package/dist/plugins/base.js.map +1 -0
- package/dist/plugins/firebase.d.ts +62 -0
- package/dist/plugins/firebase.js +111 -0
- package/dist/plugins/firebase.js.map +1 -0
- package/dist/plugins/vite.d.ts +12 -0
- package/dist/plugins/vite.js +22 -0
- package/dist/plugins/vite.js.map +1 -0
- package/dist/plugins/vue2.d.ts +68 -0
- package/dist/plugins/vue2.js +96 -0
- package/dist/plugins/vue2.js.map +1 -0
- package/dist/plugins/vue3.d.ts +64 -0
- package/dist/plugins/vue3.js +96 -0
- package/dist/plugins/vue3.js.map +1 -0
- package/dist/terafy.bootstrapper.es2019.js +2 -2
- package/dist/terafy.bootstrapper.js +2 -2
- package/dist/terafy.es2019.js +2 -2
- package/dist/terafy.js +1 -1
- package/dist/utils/mixin.d.ts +11 -0
- package/dist/utils/mixin.js +15 -0
- package/dist/utils/mixin.js.map +1 -0
- package/dist/utils/pDefer.d.ts +12 -0
- package/dist/utils/pDefer.js +14 -0
- package/dist/utils/pDefer.js.map +1 -0
- package/dist/utils/pathTools.d.ts +70 -0
- package/dist/utils/pathTools.js +120 -0
- package/dist/utils/pathTools.js.map +1 -0
- package/eslint.config.js +44 -8
- package/lib/{projectFile.js → projectFile.ts} +83 -40
- package/lib/syncro/entities.ts +288 -0
- package/lib/syncro/{keyed.js → keyed.ts} +114 -57
- package/lib/syncro/{syncro.js → syncro.ts} +204 -169
- package/lib/{terafy.bootstrapper.js → terafy.bootstrapper.ts} +49 -31
- package/lib/{terafy.client.js → terafy.client.ts} +94 -86
- package/lib/{terafy.proxy.js → terafy.proxy.ts} +43 -16
- package/lib/{terafy.server.js → terafy.server.ts} +364 -223
- package/package.json +65 -26
- package/plugins/{base.js → base.ts} +3 -1
- package/plugins/{firebase.js → firebase.ts} +34 -16
- package/plugins/{vite.js → vite.ts} +3 -3
- package/plugins/{vue2.js → vue2.ts} +17 -10
- package/plugins/{vue3.js → vue3.ts} +11 -9
- package/tsconfig.json +30 -0
- package/utils/{mixin.js → mixin.ts} +1 -1
- package/utils/{pDefer.js → pDefer.ts} +10 -3
- package/utils/{pathTools.js → pathTools.ts} +11 -9
- package/lib/syncro/entities.js +0 -232
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { DocumentReference, Firestore } from 'firebase/firestore';
|
|
2
|
+
import { FirebaseApp } from 'firebase/app';
|
|
3
|
+
import { BoundSupabaseyFunction } from '@iebh/supabasey';
|
|
4
|
+
interface ReactiveWrapper<T = any> {
|
|
5
|
+
doc: T;
|
|
6
|
+
setState: (newState: T) => void;
|
|
7
|
+
getState: () => T;
|
|
8
|
+
watch: (cb: (newState: T) => void) => void;
|
|
9
|
+
}
|
|
10
|
+
interface PathSplitResult {
|
|
11
|
+
fsCollection: string;
|
|
12
|
+
fsId: string;
|
|
13
|
+
entity: string;
|
|
14
|
+
id: string;
|
|
15
|
+
relation?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* @class Syncro
|
|
19
|
+
* TERA Isomorphic Syncro class
|
|
20
|
+
* Slurp an entity from Supabase and hold it in Firebase/Firestore as a "floating" entity which periodically gets flushed back to Supabase and eventually completely cleaned up
|
|
21
|
+
* This class tries to be as independent as possible to help with adapting it to various front-end TERA-fy plugin frameworks
|
|
22
|
+
*/
|
|
23
|
+
export default class Syncro {
|
|
24
|
+
/**
|
|
25
|
+
* Firebase instance in use
|
|
26
|
+
*
|
|
27
|
+
* @type {FirebaseApp}
|
|
28
|
+
*/
|
|
29
|
+
static firebase: FirebaseApp;
|
|
30
|
+
/**
|
|
31
|
+
* Firestore instance in use
|
|
32
|
+
*
|
|
33
|
+
* @type {Firestore}
|
|
34
|
+
*/
|
|
35
|
+
static firestore: Firestore;
|
|
36
|
+
/**
|
|
37
|
+
* Supabasey instance in use
|
|
38
|
+
*
|
|
39
|
+
* @type {Supabasey}
|
|
40
|
+
*/
|
|
41
|
+
static supabasey: BoundSupabaseyFunction;
|
|
42
|
+
/**
|
|
43
|
+
* The current user session, should be unique for the user + browser tab
|
|
44
|
+
* Used by the heartbeat system
|
|
45
|
+
*
|
|
46
|
+
* @type {String}
|
|
47
|
+
*/
|
|
48
|
+
static session: string | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* OPTIONAL SyncroEntiries from './entiries.js' if its required
|
|
51
|
+
* This only gets populated if `config.forceLocalInit` is truthy and we've mounted at least one Syncro
|
|
52
|
+
*
|
|
53
|
+
* @type {Record<string, any>}
|
|
54
|
+
*/
|
|
55
|
+
static SyncroEntities: Record<string, any>;
|
|
56
|
+
/**
|
|
57
|
+
* This instances fully formed string path
|
|
58
|
+
*
|
|
59
|
+
* @type {String}
|
|
60
|
+
*/
|
|
61
|
+
path: string;
|
|
62
|
+
/**
|
|
63
|
+
* The Firestore docHandle when calling various Firestore functions
|
|
64
|
+
*
|
|
65
|
+
* @type {DocumentReference | undefined}
|
|
66
|
+
*/
|
|
67
|
+
docRef: DocumentReference | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* The reactive object managed by this Syncro instance
|
|
70
|
+
* The nature of this varies by framework and what `getReactive()` provides
|
|
71
|
+
*
|
|
72
|
+
* @type {any}
|
|
73
|
+
*/
|
|
74
|
+
value: any;
|
|
75
|
+
/**
|
|
76
|
+
* Default throttle to apply for writes
|
|
77
|
+
*
|
|
78
|
+
* @type {Number} Throttle time in milliseconds
|
|
79
|
+
*/
|
|
80
|
+
throttle: number;
|
|
81
|
+
/**
|
|
82
|
+
* Various Misc config for the Syncro instance
|
|
83
|
+
*
|
|
84
|
+
* @type {Object}
|
|
85
|
+
* @property {Number} heartbeatinterval Time in milliseconds between heartbeat beacons
|
|
86
|
+
* @property {String} syncroRegistryUrl The prefix Sync worker URL, used to populate Syncros and determine their active status
|
|
87
|
+
* @property {Object} context Additional named parameters to pass to callbacks like initState
|
|
88
|
+
*/
|
|
89
|
+
config: {
|
|
90
|
+
heartbeatInterval: number;
|
|
91
|
+
syncroRegistryUrl: string;
|
|
92
|
+
context: Record<string, any>;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Whether the next heartbeat should be marked as 'dirty'
|
|
96
|
+
* This indicates that at least one change has occured since the last hearbeat and the server should perform a flush (but not a clean)
|
|
97
|
+
* This flag is only transmitted once in the next heartbeat before being reset
|
|
98
|
+
*
|
|
99
|
+
* @see markDirty()
|
|
100
|
+
* @type {Boolean}
|
|
101
|
+
*/
|
|
102
|
+
isDirty: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* @interface
|
|
105
|
+
* Debugging printer for this instance
|
|
106
|
+
* Defaults to doing nothing
|
|
107
|
+
*
|
|
108
|
+
* @param {*...} [msg] The message to output
|
|
109
|
+
*/
|
|
110
|
+
debug(...msg: any[]): void;
|
|
111
|
+
/**
|
|
112
|
+
* @interface
|
|
113
|
+
* Debugging printer specifically for error messages
|
|
114
|
+
* Defaults to using console.log()
|
|
115
|
+
*
|
|
116
|
+
* @param {*...} [msg] The message to output
|
|
117
|
+
*/
|
|
118
|
+
debugError(...msg: any[]): void;
|
|
119
|
+
/**
|
|
120
|
+
* Instance constructor
|
|
121
|
+
*
|
|
122
|
+
* @param {String} path Mount path for the Syncro. Should be in the form `${ENTITY}::${ID}(::${RELATION})?`
|
|
123
|
+
* @param {Object} [options] Additional instance setters (mutates instance directly), note that the `config` subkey is merged with the existing config rather than assigned
|
|
124
|
+
*/
|
|
125
|
+
constructor(path: string, options?: any);
|
|
126
|
+
/**
|
|
127
|
+
* Instance destruction trigger
|
|
128
|
+
* This will unsubscribe from various facilities and release the object for cleanup
|
|
129
|
+
*
|
|
130
|
+
* @returns {Promise} A promise which resolves when the operation has completed
|
|
131
|
+
*/
|
|
132
|
+
destroy(): Promise<any[]>;
|
|
133
|
+
/**
|
|
134
|
+
* Actions to preform when we are destroying this instance
|
|
135
|
+
* This is an array of function callbacks to execute in parallel when `destroy()` is called
|
|
136
|
+
*
|
|
137
|
+
* @type {Array<() => void>}
|
|
138
|
+
*/
|
|
139
|
+
_destroyActions: Array<() => void>;
|
|
140
|
+
/**
|
|
141
|
+
* Function to return whatever the local framework uses as a reactive object
|
|
142
|
+
* This should respond with an object of mandatory functions to watch for changes and remerge them
|
|
143
|
+
*
|
|
144
|
+
* @param {Object} value Initial value of the reactive
|
|
145
|
+
*
|
|
146
|
+
* @returns {ReactiveWrapper} A reactive object prototype
|
|
147
|
+
* @property {Object} doc The reactive object
|
|
148
|
+
* @property {Function} setState Function used to overwrite the default state, called as `(newState:Object)`
|
|
149
|
+
* @property {Function} getState Function used to fetch the current snapshot state, called as `()`
|
|
150
|
+
* @property {Function} watch Function used to set up state watchers, should call its callback when a change is detected, called as `(cb:Function)`
|
|
151
|
+
*/
|
|
152
|
+
getReactive(value: any): ReactiveWrapper;
|
|
153
|
+
/**
|
|
154
|
+
* Returns the split entity + ID relationship from a given session path
|
|
155
|
+
* This funciton checks for valid UUID format strings + that the entity is a known/supported entity (see `knownEntities`)
|
|
156
|
+
* NOTE: When used by itself (i.e. ignoring response) this function can also act as a guard that a path is valid
|
|
157
|
+
*
|
|
158
|
+
* INPUT: `widgets::UUID` -> `{entity:'widgets', id:UUID}`
|
|
159
|
+
* INPUT: `widgets::UUID::thing` -> `{entity:'widgets', id:UUID, relation:'thing'}`
|
|
160
|
+
*
|
|
161
|
+
* @param {String} path The input session path of the form `${ENTITY}::${ID}`
|
|
162
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
163
|
+
* @param {Boolean} [options.allowAsterisk=false] Whether to allow the meta asterisk character when recognising paths, this is used by the SyncroKeyed class
|
|
164
|
+
*
|
|
165
|
+
* @returns {PathSplitResult} An object composed of the session path components
|
|
166
|
+
*/
|
|
167
|
+
static pathSplit(path: string, options?: any): PathSplitResult;
|
|
168
|
+
/**
|
|
169
|
+
* Convert local POJO -> Firestore compatible object
|
|
170
|
+
* This applies the following mutations to the incoming object:
|
|
171
|
+
*
|
|
172
|
+
* 1. Arrays are converted to Objects (Firestore cannot store nested arrays)
|
|
173
|
+
* 2. All non-POJO objects (e.g. Dates) to a symetric object
|
|
174
|
+
*
|
|
175
|
+
* @param {Object} snapshot The current state to convert
|
|
176
|
+
* @returns {Object} A Firebase compatible object
|
|
177
|
+
*/
|
|
178
|
+
static toFirestore(snapshot?: any): any;
|
|
179
|
+
/**
|
|
180
|
+
* Convert local Firestore compatible object -> local POJO
|
|
181
|
+
* This reverses the mutations listed in `toFirestore()`
|
|
182
|
+
*
|
|
183
|
+
* @param {Object} snapshot The raw Firebase state to convert
|
|
184
|
+
* @returns {Object} A JavaScript POJO representing the converted state
|
|
185
|
+
*/
|
|
186
|
+
static fromFirestore(snapshot?: any): any;
|
|
187
|
+
/**
|
|
188
|
+
* Convert a raw POJO into Firestore field layout
|
|
189
|
+
* Field structures are usually consumed by the Firestore ReST API and need converting before being used
|
|
190
|
+
* NOTE: This does not serialize the incoming data so you likely want to use this as `toFirestoreFields(toFirestore(data))`
|
|
191
|
+
*
|
|
192
|
+
* @see https://stackoverflow.com/a/62304377
|
|
193
|
+
* @param {Object} data The raw value to convert
|
|
194
|
+
* @returns {Object} A Firestore compatible, typed data structure
|
|
195
|
+
*/
|
|
196
|
+
static toFirestoreFields(data: any): Record<string, any>;
|
|
197
|
+
/**
|
|
198
|
+
* Convert a Firestore field dump into a native POJO
|
|
199
|
+
* Field structures are usually provided by the Firestore ReST API and need de-typing back into a native document
|
|
200
|
+
* NOTE: This does not deserialize the result so you likely want to use this as `fromFirestore(fromFirestoreFields(response.fields))`
|
|
201
|
+
*
|
|
202
|
+
* @see https://stackoverflow.com/a/62304377
|
|
203
|
+
* @param {Object} fields The raw Snapshot to convert
|
|
204
|
+
* @returns {Object} A JavaScript POJO representing the converted state
|
|
205
|
+
*/
|
|
206
|
+
static fromFirestoreFields(fields?: any): any;
|
|
207
|
+
/**
|
|
208
|
+
* Perform a one-off fetch of a given Syncro path
|
|
209
|
+
*
|
|
210
|
+
* @param {String} path The Syncro entity + ID path. Takes the form `ENTITY::ID`
|
|
211
|
+
*
|
|
212
|
+
* @returns {Promise<Object|Null>} An eventual snapshot of the given path, if the entity doesn't exist null is returned
|
|
213
|
+
*/
|
|
214
|
+
static getSnapshot(path: string): Promise<any | null>;
|
|
215
|
+
/**
|
|
216
|
+
* Perform a one-off set/merge operation against
|
|
217
|
+
*
|
|
218
|
+
* @param {String} path The Syncro entity + ID path. Takes the form `ENTITY::ID`
|
|
219
|
+
* @param {Object} state The new state to set/merge
|
|
220
|
+
*
|
|
221
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
222
|
+
* @param {'merge'|'set'} [options.method='merge'] How to apply the new state. 'merge' (merge in partial data to an existing Syncro), 'set' (overwrite the entire Syncro state)
|
|
223
|
+
*
|
|
224
|
+
* @returns {Promise<*>} The state object after it has been applied
|
|
225
|
+
*/
|
|
226
|
+
static setSnapshot(path: string, state: any, options?: {
|
|
227
|
+
method?: 'merge' | 'set';
|
|
228
|
+
}): Promise<any>;
|
|
229
|
+
/**
|
|
230
|
+
* Mount the remote Firestore document against this Syncro instance
|
|
231
|
+
*
|
|
232
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
233
|
+
* @param {Object} [options.initalState] State to use if no state is already loaded, overrides the entities own `initState` function fetcher
|
|
234
|
+
* @param {Number} [options.retries=3] Number of times to retry if a mounted Syncro fails its sanity checks
|
|
235
|
+
* @returns {Promise<Syncro>} A promise which resolves as this syncro instance when completed
|
|
236
|
+
*/
|
|
237
|
+
mount(options?: any): Promise<Syncro>;
|
|
238
|
+
/**
|
|
239
|
+
* Merge a single or multiple values into a Syncro data object
|
|
240
|
+
* NOTE: Default behaviour is to flush (if any changes apply), use direct object mutation or disable with `flush:false` to disable
|
|
241
|
+
*
|
|
242
|
+
* @param {String|Object} key Either the single named key to set OR the object to merge
|
|
243
|
+
* @param {*} [value] The value to set if `key` is a string
|
|
244
|
+
*
|
|
245
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
246
|
+
* @param {Boolean} [options.delta=true] Only merge keys that differ, skipping flush if no changes are made
|
|
247
|
+
* @param {Boolean} [options.flush=true] Send a flush signal that Firebase should sync to Supabase on changes
|
|
248
|
+
* @param {Boolean} [options.forceFlush=false] Flush even if no changes were made
|
|
249
|
+
* @param {Boolean} [options.flushDestroy=false] Destroy the Syncro after flushing
|
|
250
|
+
*
|
|
251
|
+
* @returns {Promise<Syncro>} A promise which resolves with this Syncro instance on completion
|
|
252
|
+
*/
|
|
253
|
+
set(key: string | object, value: any, options: {
|
|
254
|
+
delta?: boolean;
|
|
255
|
+
flush?: boolean;
|
|
256
|
+
forceFlush?: boolean;
|
|
257
|
+
flushDestroy?: boolean;
|
|
258
|
+
}): Promise<this>;
|
|
259
|
+
/**
|
|
260
|
+
* Schedule Syncro heartbeats
|
|
261
|
+
* This populates the `sync` presence meta-information
|
|
262
|
+
*
|
|
263
|
+
* @param {Boolean} [enable=true] Whether to enable heartbeating
|
|
264
|
+
*
|
|
265
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
266
|
+
* @param {Boolean} [options.immediate=false] Fire a heartbeat as soon as this function is called, this is only really useful on mount
|
|
267
|
+
*/
|
|
268
|
+
setHeartbeat(enable?: boolean, options?: any): Promise<void> | void;
|
|
269
|
+
/**
|
|
270
|
+
* Perform one heartbeat pulse to the server to indicate presense within this Syncro
|
|
271
|
+
* This function is automatically called by a timer if `setHeartbeat(true)` (the default behaviour)
|
|
272
|
+
*
|
|
273
|
+
* @returns {Promise} A promise which resolves when the operation has completed
|
|
274
|
+
*/
|
|
275
|
+
heartbeat(): Promise<void>;
|
|
276
|
+
/**
|
|
277
|
+
* Utility function to directly set this documents firestore state
|
|
278
|
+
*
|
|
279
|
+
* @param {Object} state The state to set / merge
|
|
280
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
281
|
+
* @param {'merge'|'set'} [options.method='merge'] How to apply the new state. 'merge' (merge in partial data to an existing Syncro), 'set' (overwrite the entire Syncro state)
|
|
282
|
+
*
|
|
283
|
+
* @returns {Promise} A promise which resolves when the operation has completed
|
|
284
|
+
*/
|
|
285
|
+
setFirestoreState(state: any, options?: {
|
|
286
|
+
method?: 'merge' | 'set';
|
|
287
|
+
}): Promise<void>;
|
|
288
|
+
/**
|
|
289
|
+
* Utility method to fetch the Firestore state for this Syncro
|
|
290
|
+
* NOTE: This directly extracts the state of the Firestore, not its wrapping doc object returned by `FirestoreGetDoc`
|
|
291
|
+
*
|
|
292
|
+
* @returns {Promise<Object>} A promise which resolves to the Firestore state
|
|
293
|
+
*/
|
|
294
|
+
getFirestoreState(): Promise<any>;
|
|
295
|
+
/**
|
|
296
|
+
* Set the Syncro dirty flag which gets passed to the server on the next heartbeat
|
|
297
|
+
*
|
|
298
|
+
* @see isDirty
|
|
299
|
+
* @returns {Syncro} This chainable Syncro instance
|
|
300
|
+
*/
|
|
301
|
+
markDirty(): this;
|
|
302
|
+
/**
|
|
303
|
+
* Force the server to flush state
|
|
304
|
+
* This is only really useful for debugging as this happens automatically anyway
|
|
305
|
+
*
|
|
306
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
307
|
+
* @param {Boolean} [options.destroy=false] Instruct the server to also dispose of the Syncro state
|
|
308
|
+
*
|
|
309
|
+
* @returns {Promise} A promise which resolves when the operation has completed
|
|
310
|
+
*/
|
|
311
|
+
flush(options?: any): Promise<void | null>;
|
|
312
|
+
/**
|
|
313
|
+
* Timer handle for heartbeats
|
|
314
|
+
*
|
|
315
|
+
* @type {any}
|
|
316
|
+
*/
|
|
317
|
+
_heartbeatTimer: any;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Build a chaotic random tree structure based on dice rolls
|
|
321
|
+
* This funciton is mainly used for sync testing
|
|
322
|
+
*
|
|
323
|
+
* @param {Number} [depth=0] The current depth we are starting at, changes the nature of branches based on probability
|
|
324
|
+
*
|
|
325
|
+
* @returns {*} The current branch conotents
|
|
326
|
+
*/
|
|
327
|
+
export declare function randomBranch(depth?: number): any;
|
|
328
|
+
export {};
|