@iebh/tera-fy 2.3.8 → 2.3.10
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 +21 -0
- package/dist/lib/syncro/entities.d.ts +9 -3
- package/dist/lib/syncro/entities.js +103 -115
- package/dist/lib/syncro/entities.js.map +1 -1
- package/dist/lib/syncro/keyed (Rhino's conflicted copy 2026-05-10).js +287 -0
- package/dist/lib/syncro/keyed.js +1 -0
- package/dist/lib/syncro/keyed.js (Rhino's conflicted copy 2026-05-10).map +1 -0
- package/dist/lib/syncro/keyed.js.map +1 -1
- package/dist/lib/syncro/syncro (Rhino's conflicted copy 2026-05-10).js +765 -0
- package/dist/lib/syncro/syncro.d (Rhino's conflicted copy 2026-05-10).ts +336 -0
- package/dist/lib/syncro/syncro.d.ts +7 -0
- package/dist/lib/syncro/syncro.js +6 -0
- package/dist/lib/syncro/syncro.js (Rhino's conflicted copy 2026-05-10).map +1 -0
- package/dist/lib/syncro/syncro.js.map +1 -1
- package/dist/plugin.vue2.es2019 (Rhino's conflicted copy 2026-05-10).js +1271 -0
- package/dist/plugin.vue2.es2019.js +1 -1
- package/lib/syncro/entities.ts +126 -131
- package/lib/syncro/keyed.ts +1 -0
- package/lib/syncro/syncro.ts +9 -0
- package/package.json +1 -1
package/lib/syncro/entities.ts
CHANGED
|
@@ -1,21 +1,29 @@
|
|
|
1
|
-
/* eslint-disable no-unused-vars */
|
|
1
|
+
/* eslint-disable jsdoc/reject-function-type, no-unused-vars */
|
|
2
2
|
// @ts-expect-error TODO: Remove when reflib gets declaration file
|
|
3
3
|
import Reflib from '@iebh/reflib';
|
|
4
4
|
import {v4 as uuid4} from 'uuid';
|
|
5
5
|
import {nanoid} from 'nanoid';
|
|
6
|
-
import {
|
|
6
|
+
import {BoundSupabaseyFunction} from '@iebh/supabasey';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
// Minimal interface for a postgres-npm Sql instance (HYPERDRIVE is injected by the Cloudflare Worker runtime)
|
|
10
|
+
export interface PostgresSql {
|
|
11
|
+
(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>;
|
|
12
|
+
json(value: any): any;
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
|
|
8
16
|
// DATABASE TABLE TYPE DEFINITIONS {{{
|
|
9
17
|
interface ProjectRow {
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
data: {
|
|
19
|
+
id: string;
|
|
12
20
|
// TODO: add other properties in project data
|
|
13
21
|
};
|
|
14
22
|
// TODO: Define other columns in project table
|
|
15
23
|
}
|
|
16
24
|
|
|
17
25
|
interface InstituteRow {
|
|
18
|
-
|
|
26
|
+
data: any;
|
|
19
27
|
}
|
|
20
28
|
|
|
21
29
|
interface UserRow {
|
|
@@ -36,71 +44,81 @@ interface NamespaceRow {
|
|
|
36
44
|
[key: string]: any;
|
|
37
45
|
// TODO: add other properties in namespace data
|
|
38
46
|
};
|
|
39
|
-
// TODO: Define other
|
|
47
|
+
// TODO: Define other columns in namespace table
|
|
40
48
|
}
|
|
41
49
|
// }}}
|
|
42
50
|
|
|
43
|
-
|
|
51
|
+
|
|
52
|
+
// Interface for each syncro entity config
|
|
44
53
|
interface SyncroEntityConfig {
|
|
45
54
|
singular: string;
|
|
46
55
|
initState: (args: {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
HYPERDRIVE: PostgresSql;
|
|
57
|
+
supabasey: BoundSupabaseyFunction;
|
|
58
|
+
id: string; // Primary ID for the entity
|
|
59
|
+
relation?: string; // Optional relation identifier (for namespaces, libraries)
|
|
50
60
|
}) => Promise<any>;
|
|
51
|
-
|
|
52
61
|
flushState: (args: {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
HYPERDRIVE: PostgresSql;
|
|
63
|
+
supabasey?: BoundSupabaseyFunction;
|
|
64
|
+
state: any; // The state object to flush
|
|
65
|
+
id?: string; // Primary ID (used in some lookups like namespaces)
|
|
66
|
+
fsId?: string; // ID often passed to Supabase RPCs (might be same as 'id')
|
|
67
|
+
relation?: string; // Optional relation identifier
|
|
58
68
|
}) => Promise<any>; // Return type signifies completion/result of flush
|
|
59
69
|
}
|
|
60
70
|
|
|
71
|
+
|
|
61
72
|
type SyncroConfig = Record<string, SyncroEntityConfig>;
|
|
62
73
|
|
|
74
|
+
|
|
63
75
|
/**
|
|
64
76
|
* Entities we support Syncro paths for, each should correspond directly with a Firebase/Firestore collection name
|
|
65
77
|
*
|
|
66
78
|
* @type {Object} An object lookup of entities
|
|
67
79
|
*
|
|
68
80
|
* @property {String} singular The singular noun for the item
|
|
69
|
-
* @property {Function} initState Function called to initialize state when Firestore has no existing document. Called as `({
|
|
70
|
-
* @property {Function} flushState Function called to flush state from Firebase to
|
|
81
|
+
* @property {Function} initState Function called to initialize state when Firestore has no existing document. Called as `({HYPERDRIVE:PostgresSql, supabasey:BoundSupabaseyFunction, id:String, relation?:string})` and expected to return the initial data object state
|
|
82
|
+
* @property {Function} flushState Function called to flush state from Firebase to Postgres. Called the same as `initState` + `{state:Object}`
|
|
71
83
|
*/
|
|
72
84
|
const syncroConfig: SyncroConfig = {
|
|
73
85
|
institutes: { // {{{
|
|
74
86
|
singular: 'institute',
|
|
75
|
-
async initState({
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (
|
|
87
|
+
async initState({HYPERDRIVE, id}: {HYPERDRIVE: PostgresSql, id: string}) {
|
|
88
|
+
let rows = await HYPERDRIVE`
|
|
89
|
+
SELECT data
|
|
90
|
+
FROM institutes
|
|
91
|
+
WHERE id = ${id}
|
|
92
|
+
LIMIT 1
|
|
93
|
+
`;
|
|
94
|
+
if (rows.length > 0) {
|
|
95
|
+
return rows[0].data; // institute is valid and already exists
|
|
96
|
+
} else {
|
|
97
|
+
throw new Error(`Syncro institute "${id}" not found`);
|
|
98
|
+
}
|
|
83
99
|
},
|
|
84
|
-
flushState({
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
100
|
+
flushState({HYPERDRIVE, state, id}) {
|
|
101
|
+
return HYPERDRIVE`
|
|
102
|
+
SELECT syncro_merge_data(
|
|
103
|
+
table_name => 'institutes',
|
|
104
|
+
entity_id => ${id}::UUID,
|
|
105
|
+
new_data => ${HYPERDRIVE.json(state)}::JSONB
|
|
106
|
+
)
|
|
107
|
+
`;
|
|
91
108
|
},
|
|
92
109
|
}, // }}}
|
|
93
110
|
projects: { // {{{
|
|
94
111
|
singular: 'project',
|
|
95
|
-
async initState({supabasey, id}) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (
|
|
103
|
-
|
|
112
|
+
async initState({HYPERDRIVE, supabasey, id}: {HYPERDRIVE: PostgresSql, supabasey: BoundSupabaseyFunction, id: string}) {
|
|
113
|
+
let rows = await HYPERDRIVE`
|
|
114
|
+
SELECT data
|
|
115
|
+
FROM projects
|
|
116
|
+
WHERE id = ${id}
|
|
117
|
+
LIMIT 1
|
|
118
|
+
`;
|
|
119
|
+
if (rows.length == 0) throw new Error(`Syncro project "${id}" not found`);
|
|
120
|
+
|
|
121
|
+
const data = rows[0].data;
|
|
104
122
|
|
|
105
123
|
// MIGRATION - Move data.temp{} into Supabase files + add pointer to filename {{{
|
|
106
124
|
if (
|
|
@@ -113,7 +131,7 @@ const syncroConfig: SyncroConfig = {
|
|
|
113
131
|
await Promise.all(
|
|
114
132
|
Object.entries(data.temp)
|
|
115
133
|
.filter(([, branch]) => typeof branch == 'object')
|
|
116
|
-
.map(([toolKey
|
|
134
|
+
.map(([toolKey]) => {
|
|
117
135
|
console.log(`[MIGRATION] Converting data.temp[${toolKey}]...`);
|
|
118
136
|
|
|
119
137
|
const toolName = toolKey.split('-')[0];
|
|
@@ -160,18 +178,19 @@ const syncroConfig: SyncroConfig = {
|
|
|
160
178
|
|
|
161
179
|
return data;
|
|
162
180
|
},
|
|
163
|
-
flushState({
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
181
|
+
flushState({HYPERDRIVE, state, fsId}) {
|
|
182
|
+
return HYPERDRIVE`
|
|
183
|
+
SELECT syncro_merge_data(
|
|
184
|
+
table_name => 'projects',
|
|
185
|
+
entity_id => ${fsId}::UUID,
|
|
186
|
+
new_data => ${HYPERDRIVE.json(state)}::JSONB
|
|
187
|
+
)
|
|
188
|
+
`;
|
|
170
189
|
},
|
|
171
190
|
}, // }}}
|
|
172
191
|
project_libraries: { // {{{
|
|
173
192
|
singular: 'project library',
|
|
174
|
-
async initState({supabasey, id, relation}) {
|
|
193
|
+
async initState({id, relation, supabasey}: {HYPERDRIVE: PostgresSql, id: string, relation?: string, supabasey: BoundSupabaseyFunction}) {
|
|
175
194
|
if (!relation || !/_\*$/.test(relation)) throw new Error('Project library relation missing, path should resemble "project_library::${PROJECT}::${LIBRARY_FILE_ID}_*"');
|
|
176
195
|
|
|
177
196
|
const fileId = relation.replace(/_\*$/, '');
|
|
@@ -209,103 +228,79 @@ const syncroConfig: SyncroConfig = {
|
|
|
209
228
|
throw new Error('Flushing project_libraries::* namespace is not yet supported');
|
|
210
229
|
},
|
|
211
230
|
}, // }}}
|
|
212
|
-
project_namespaces: { // {{{
|
|
231
|
+
project_namespaces: { // NOT YET SUPPORTED {{{
|
|
213
232
|
singular: 'project namespace',
|
|
214
|
-
async initState(
|
|
215
|
-
|
|
216
|
-
const rows = await supabasey((supabase) => supabase
|
|
217
|
-
.from('project_namespaces')
|
|
218
|
-
.select('data')
|
|
219
|
-
.eq('project', id)
|
|
220
|
-
.eq('name', relation)
|
|
221
|
-
.limit(1)
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
if (rows && rows.length == 1) {
|
|
225
|
-
return rows[0].data;
|
|
226
|
-
} else {
|
|
227
|
-
const newItem = await supabasey((supabase) => supabase
|
|
228
|
-
.from('project_namespaces') // Doesn't exist - create it
|
|
229
|
-
.insert<NamespaceRow>({
|
|
230
|
-
project: id,
|
|
231
|
-
name: relation,
|
|
232
|
-
data: {},
|
|
233
|
-
})
|
|
234
|
-
.select('data')
|
|
235
|
-
.single<NamespaceRow>() // Assuming insert returns the single inserted row
|
|
236
|
-
);
|
|
237
|
-
|
|
238
|
-
if (!newItem) throw new Error('Failed to create project namespace');
|
|
239
|
-
return newItem.data;
|
|
240
|
-
}
|
|
233
|
+
async initState() {
|
|
234
|
+
throw new Error('Updating project_namespaces is not yet supported');
|
|
241
235
|
},
|
|
242
|
-
flushState(
|
|
243
|
-
|
|
244
|
-
.from('project_namespaces')
|
|
245
|
-
.update({
|
|
246
|
-
edited_at: new Date().toISOString(),
|
|
247
|
-
data: state,
|
|
248
|
-
})
|
|
249
|
-
.eq('project', id)
|
|
250
|
-
.eq('name', relation)
|
|
251
|
-
);
|
|
236
|
+
async flushState() {
|
|
237
|
+
throw new Error('Updating project_namespaces is not yet supported');
|
|
252
238
|
},
|
|
253
239
|
}, // }}}
|
|
254
240
|
test: { // {{{
|
|
255
241
|
singular: 'test',
|
|
256
|
-
async initState({
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
242
|
+
async initState({HYPERDRIVE, id}: {HYPERDRIVE: PostgresSql, id: string}) {
|
|
243
|
+
let rows = await HYPERDRIVE`
|
|
244
|
+
SELECT data
|
|
245
|
+
FROM test
|
|
246
|
+
WHERE id = ${id}
|
|
247
|
+
LIMIT 1
|
|
248
|
+
`;
|
|
249
|
+
if (rows.length > 0) {
|
|
250
|
+
return rows[0].data; // User is valid and already exists
|
|
251
|
+
} else {
|
|
252
|
+
throw new Error(`Syncro test "${id}" not found`);
|
|
253
|
+
}
|
|
266
254
|
},
|
|
267
|
-
flushState({
|
|
268
|
-
return
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
255
|
+
flushState({HYPERDRIVE, state, fsId}) {
|
|
256
|
+
return HYPERDRIVE`
|
|
257
|
+
SELECT syncro_merge_data(
|
|
258
|
+
table_name => 'test',
|
|
259
|
+
entity_id => ${fsId}::UUID,
|
|
260
|
+
new_data => ${HYPERDRIVE.json(state)}::JSONB
|
|
261
|
+
)
|
|
262
|
+
`;
|
|
273
263
|
},
|
|
274
264
|
}, // }}}
|
|
275
265
|
users: { // {{{
|
|
276
266
|
singular: 'user',
|
|
277
|
-
async initState({
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
if (
|
|
267
|
+
async initState({HYPERDRIVE, id}: {HYPERDRIVE: PostgresSql, id: string}) {
|
|
268
|
+
let rows = await HYPERDRIVE`
|
|
269
|
+
SELECT data
|
|
270
|
+
FROM users
|
|
271
|
+
WHERE id = ${id}
|
|
272
|
+
LIMIT 1
|
|
273
|
+
`;
|
|
274
|
+
if (rows.length > 0) return rows[0].data; // User is valid and already exists
|
|
285
275
|
|
|
286
|
-
// User row doesn't already exist -
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
276
|
+
// User row doesn't already exist - this shouldn't happen if the user has correctly gone through the onboarding process
|
|
277
|
+
// but... *shrugs*, who knows
|
|
278
|
+
let newUser = await HYPERDRIVE`
|
|
279
|
+
INSERT INTO users
|
|
280
|
+
(
|
|
290
281
|
id,
|
|
291
|
-
data
|
|
282
|
+
data
|
|
283
|
+
)
|
|
284
|
+
VALUES (
|
|
285
|
+
${id},
|
|
286
|
+
${HYPERDRIVE.json({
|
|
292
287
|
id,
|
|
293
288
|
credits: 1000,
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if (!newUser) throw new Error('Failed to create user');
|
|
300
|
-
return newUser.data; // Return back the data that eventually got created - allowing for database triggers, default field values etc.
|
|
289
|
+
})}::JSONB
|
|
290
|
+
)
|
|
291
|
+
`;
|
|
292
|
+
if (!newUser?.length) throw new Error(`Failed to create new user "${id}"`);
|
|
293
|
+
return newUser[0].data; // Return back the data that eventually got created - allowing for database triggers, default field values etc.
|
|
301
294
|
|
|
302
295
|
},
|
|
303
|
-
flushState({
|
|
304
|
-
return
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
296
|
+
flushState({HYPERDRIVE, state, fsId}) {
|
|
297
|
+
return HYPERDRIVE`
|
|
298
|
+
SELECT syncro_merge_data(
|
|
299
|
+
table_name => 'users',
|
|
300
|
+
entity_id => ${fsId}::UUID,
|
|
301
|
+
new_data => ${HYPERDRIVE.json(state)}::JSONB
|
|
302
|
+
)
|
|
303
|
+
`;
|
|
309
304
|
},
|
|
310
305
|
}, // }}}
|
|
311
306
|
};
|
package/lib/syncro/keyed.ts
CHANGED
package/lib/syncro/syncro.ts
CHANGED
|
@@ -25,6 +25,7 @@ import PromiseThrottle from 'p-throttle';
|
|
|
25
25
|
import PromiseRetry from 'p-retry';
|
|
26
26
|
import {FirebaseApp, FirebaseError} from 'firebase/app';
|
|
27
27
|
import { BoundSupabaseyFunction } from '@iebh/supabasey';
|
|
28
|
+
import type { PostgresSql } from './entities.js';
|
|
28
29
|
|
|
29
30
|
interface ThrottleOptions<T = any> {
|
|
30
31
|
limit: number,
|
|
@@ -81,6 +82,14 @@ export default class Syncro {
|
|
|
81
82
|
static supabasey: BoundSupabaseyFunction;
|
|
82
83
|
|
|
83
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Postgres SQL instance in use (injected by the Cloudflare Worker runtime via Hyperdrive)
|
|
87
|
+
*
|
|
88
|
+
* @type {PostgresSql}
|
|
89
|
+
*/
|
|
90
|
+
static db: PostgresSql;
|
|
91
|
+
|
|
92
|
+
|
|
84
93
|
/**
|
|
85
94
|
* The current user session, should be unique for the user + browser tab
|
|
86
95
|
* Used by the heartbeat system
|
package/package.json
CHANGED