@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,182 @@
|
|
|
1
|
+
import type TeraFy from './terafy.client.ts';
|
|
2
|
+
interface TeraClient extends TeraFy {
|
|
3
|
+
getProjectFileContents: (id: any, options?: any) => any;
|
|
4
|
+
setProjectFileContents: (id: any, contents: any, options?: any) => any;
|
|
5
|
+
getProjectLibrary: (id: any, options?: any) => any;
|
|
6
|
+
setProjectLibrary: (id: any, refs: any, options?: any) => any;
|
|
7
|
+
}
|
|
8
|
+
type SupabaseFile = any;
|
|
9
|
+
type RefLibRef = any;
|
|
10
|
+
/**
|
|
11
|
+
* A project file fetched from TERA
|
|
12
|
+
* @class ProjectFile
|
|
13
|
+
*/
|
|
14
|
+
export default class ProjectFile {
|
|
15
|
+
/**
|
|
16
|
+
* Parent TeraClient instance used by all helper functions
|
|
17
|
+
* @type {TeraClient}
|
|
18
|
+
* @private
|
|
19
|
+
*/
|
|
20
|
+
_tera: TeraClient;
|
|
21
|
+
/**
|
|
22
|
+
* The TERA compatible unique ID of the file
|
|
23
|
+
* NOTE: This is computed each time from the Base64 of the file path
|
|
24
|
+
* @type {String}
|
|
25
|
+
*/
|
|
26
|
+
id: string;
|
|
27
|
+
/**
|
|
28
|
+
* The raw Supabase UUID of the file
|
|
29
|
+
* @type {String}
|
|
30
|
+
*/
|
|
31
|
+
sbId: string;
|
|
32
|
+
/**
|
|
33
|
+
* Relative name path (can contain prefix directories) for the human readable file name
|
|
34
|
+
* @type {String}
|
|
35
|
+
*/
|
|
36
|
+
name: string;
|
|
37
|
+
/**
|
|
38
|
+
* CSS class to use as the file icon
|
|
39
|
+
* @type {String}
|
|
40
|
+
*/
|
|
41
|
+
icon: string;
|
|
42
|
+
/**
|
|
43
|
+
* Full path to the file
|
|
44
|
+
* This is also used as the unique identifier within the project
|
|
45
|
+
* @type {String}
|
|
46
|
+
*/
|
|
47
|
+
path: string;
|
|
48
|
+
/**
|
|
49
|
+
* Fully qualified URL to view / access / download the file from TERA
|
|
50
|
+
* This will usually open an edit UI within the TERA site
|
|
51
|
+
* @type {String}
|
|
52
|
+
*/
|
|
53
|
+
url: string;
|
|
54
|
+
/**
|
|
55
|
+
* Rewrite of the URL where the absolute URL has been removed in place of a relative path, assuming the owner project is active
|
|
56
|
+
* This is used to direct to the edit/view/download UI when the files project is active and is usually used in place of URL for TERA related operations
|
|
57
|
+
* @type {String}
|
|
58
|
+
*/
|
|
59
|
+
teraUrl: string;
|
|
60
|
+
/**
|
|
61
|
+
* An object representing meta file parts of a file name
|
|
62
|
+
* @type {Object}
|
|
63
|
+
* @property {String} basename The filename + extention (i.e. everything without directory name)
|
|
64
|
+
* @property {String} filename The file portion of the name (basename without the extension)
|
|
65
|
+
* @property {String} ext The extension portion of the name (always lower case)
|
|
66
|
+
* @property {String} dirName The directory path portion of the name
|
|
67
|
+
*/
|
|
68
|
+
parsedName: any;
|
|
69
|
+
/**
|
|
70
|
+
* A date representing when the file was created
|
|
71
|
+
* @type {Date}
|
|
72
|
+
*/
|
|
73
|
+
created: Date | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* A human readable, formatted version of "created"
|
|
76
|
+
* @type {String}
|
|
77
|
+
*/
|
|
78
|
+
createdFormatted: string;
|
|
79
|
+
/**
|
|
80
|
+
* A date representing when the file was created
|
|
81
|
+
* @type {Date}
|
|
82
|
+
*/
|
|
83
|
+
modified: Date | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* A human readable, formatted version of "modified"
|
|
86
|
+
* @type {String}
|
|
87
|
+
*/
|
|
88
|
+
modifiedFormatted: string;
|
|
89
|
+
/**
|
|
90
|
+
* A date representing when the file was last accessed
|
|
91
|
+
* @type {Date}
|
|
92
|
+
*/
|
|
93
|
+
accessed: Date | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* A human readable, formatted version of "accessed"
|
|
96
|
+
* @type {String}
|
|
97
|
+
*/
|
|
98
|
+
accessedFormatted: string;
|
|
99
|
+
/**
|
|
100
|
+
* Size, in bytes, of the file
|
|
101
|
+
* @type {Number}
|
|
102
|
+
*/
|
|
103
|
+
size: number | undefined;
|
|
104
|
+
/**
|
|
105
|
+
* A human readable, formatted version of the file size
|
|
106
|
+
* @type {String}
|
|
107
|
+
*/
|
|
108
|
+
sizeFormatted: string;
|
|
109
|
+
/**
|
|
110
|
+
* The associated mime type for the file
|
|
111
|
+
* @type {String}
|
|
112
|
+
*/
|
|
113
|
+
mime: string;
|
|
114
|
+
/**
|
|
115
|
+
* Additional meta information for the file
|
|
116
|
+
* @type {Object}
|
|
117
|
+
*/
|
|
118
|
+
meta: Record<string, any>;
|
|
119
|
+
/**
|
|
120
|
+
* ProjectFile constructor
|
|
121
|
+
* Takes the input basic file type from Supabase and adds additional formatted fields
|
|
122
|
+
* @param {SupabaseFile} baseFile The basic Supabase file to extend
|
|
123
|
+
* @param {TeraFyClient} baseFile.tera The associated TeraFyClient instance to use for some file methods
|
|
124
|
+
*/
|
|
125
|
+
constructor(baseFile: SupabaseFile);
|
|
126
|
+
/**
|
|
127
|
+
* Fetch the raw file contents as a Blob
|
|
128
|
+
*
|
|
129
|
+
* @param {Object} [options] Additioanl options to mutate behaviour
|
|
130
|
+
*
|
|
131
|
+
* @returns {Promise<Blob>} The eventual raw file contents as a Blob
|
|
132
|
+
*
|
|
133
|
+
* @see getProjectFile()
|
|
134
|
+
*/
|
|
135
|
+
getContents(options?: any): Promise<Blob>;
|
|
136
|
+
/**
|
|
137
|
+
* Overwrite the contents of a file with new content
|
|
138
|
+
*
|
|
139
|
+
* @param {File|Blob|FormData|Object|Array} contents The new file contents
|
|
140
|
+
*
|
|
141
|
+
* @returns {Promise<void>} A promise which resolves when the operation has completed
|
|
142
|
+
*
|
|
143
|
+
* @see setProjectFileContents()
|
|
144
|
+
*/
|
|
145
|
+
setContents(contents: File | Blob | FormData | object | any[]): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Fetch the file contents as an array of Reflib refs
|
|
148
|
+
*
|
|
149
|
+
* @returns {Promise<Array<RefLibRef>>} An eventual array of RefLib references
|
|
150
|
+
*
|
|
151
|
+
* @see getProjectLibrary()
|
|
152
|
+
*/
|
|
153
|
+
getRefs(): Promise<Array<RefLibRef>>;
|
|
154
|
+
/**
|
|
155
|
+
* Overwrite the contents of a file with a new collection of Reflib refs
|
|
156
|
+
*
|
|
157
|
+
* @param {Array<RefLibRef>} refs Collection of references for the selected library
|
|
158
|
+
*
|
|
159
|
+
* @returns {Promise<void>} A promise which resolves when the operation has completed
|
|
160
|
+
*
|
|
161
|
+
* @see setProjectLibrary()
|
|
162
|
+
*/
|
|
163
|
+
setRefs(refs: Array<RefLibRef>): Promise<void>;
|
|
164
|
+
/**
|
|
165
|
+
* Compress a file state down into a serializable entity
|
|
166
|
+
* By default this computes a Structured Clone which can be stringified
|
|
167
|
+
*
|
|
168
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
|
|
169
|
+
* @returns {Object} A Structured Clone compatible representation of this ProjectFile instance
|
|
170
|
+
*/
|
|
171
|
+
serialize(): Partial<ProjectFile>;
|
|
172
|
+
/**
|
|
173
|
+
* Restore an entity created with serialize
|
|
174
|
+
* NOTE: This requires the 'tera' instance to be manually added to the 'data' object before calling deserialize,
|
|
175
|
+
* as it's not included in the serialized output.
|
|
176
|
+
*
|
|
177
|
+
* @param {Object} data An input object created via `ProjectFiles.serialize()` (MUST include a 'tera' property added manually)
|
|
178
|
+
* @returns {ProjectFile} A ProjectFile instance setup against the deserializzed data
|
|
179
|
+
*/
|
|
180
|
+
static deserialize(data: any): ProjectFile;
|
|
181
|
+
}
|
|
182
|
+
export {};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { filesize } from 'filesize';
|
|
2
|
+
import { pick } from 'lodash-es';
|
|
3
|
+
;
|
|
4
|
+
/**
|
|
5
|
+
* A project file fetched from TERA
|
|
6
|
+
* @class ProjectFile
|
|
7
|
+
*/
|
|
8
|
+
export default class ProjectFile {
|
|
9
|
+
/**
|
|
10
|
+
* ProjectFile constructor
|
|
11
|
+
* Takes the input basic file type from Supabase and adds additional formatted fields
|
|
12
|
+
* @param {SupabaseFile} baseFile The basic Supabase file to extend
|
|
13
|
+
* @param {TeraFyClient} baseFile.tera The associated TeraFyClient instance to use for some file methods
|
|
14
|
+
*/
|
|
15
|
+
constructor(baseFile) {
|
|
16
|
+
/**
|
|
17
|
+
* Additional meta information for the file
|
|
18
|
+
* @type {Object}
|
|
19
|
+
*/
|
|
20
|
+
// Using Record<string, any> for a generic object, adjust if meta has a known structure
|
|
21
|
+
this.meta = {};
|
|
22
|
+
// Note: baseFile.tera is assumed to exist based on the check below and the SupabaseFile type definition above
|
|
23
|
+
if (!baseFile.tera)
|
|
24
|
+
throw new Error('Basic file requires a `tera` key to access the Tera instance');
|
|
25
|
+
Object.assign(this, baseFile);
|
|
26
|
+
// Translate baseFile.tera -> this._tera (non-enumerable, non-configurable)
|
|
27
|
+
const tera = this.tera;
|
|
28
|
+
Object.defineProperty(this, '_tera', {
|
|
29
|
+
enumerable: false,
|
|
30
|
+
configurable: false,
|
|
31
|
+
get() {
|
|
32
|
+
// NOTE: We can't just set {value:tera} as it upsets how Vue uses proxies
|
|
33
|
+
return tera;
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
delete this.tera; // Remove original ref we merged above
|
|
37
|
+
// Calculate `teraUrl` from URL
|
|
38
|
+
// Assuming this.url is always defined after Object.assign
|
|
39
|
+
this.teraUrl = this.url.replace(/^https?:\/\/(?:.+?)\/projects\/(?:.+?)\/project\/(.+)$/, '/project/$1');
|
|
40
|
+
// Set all `*Formatted` fields
|
|
41
|
+
this.sizeFormatted = filesize(this.size || 0, { spacer: '' });
|
|
42
|
+
this.createdFormatted = this.created ? this.created.toLocaleDateString() : 'Unknown created date';
|
|
43
|
+
this.modifiedFormatted = this.modified ? this.modified.toLocaleDateString() : 'Unknown modified date';
|
|
44
|
+
this.accessedFormatted = this.accessed ? this.accessed.toLocaleDateString() : 'Unknown access date';
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Fetch the raw file contents as a Blob
|
|
48
|
+
*
|
|
49
|
+
* @param {Object} [options] Additioanl options to mutate behaviour
|
|
50
|
+
*
|
|
51
|
+
* @returns {Promise<Blob>} The eventual raw file contents as a Blob
|
|
52
|
+
*
|
|
53
|
+
* @see getProjectFile()
|
|
54
|
+
*/
|
|
55
|
+
getContents(options) {
|
|
56
|
+
// Assuming _tera has this method and it returns Promise<Blob>
|
|
57
|
+
return this._tera.getProjectFileContents(this.id, options);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Overwrite the contents of a file with new content
|
|
61
|
+
*
|
|
62
|
+
* @param {File|Blob|FormData|Object|Array} contents The new file contents
|
|
63
|
+
*
|
|
64
|
+
* @returns {Promise<void>} A promise which resolves when the operation has completed
|
|
65
|
+
*
|
|
66
|
+
* @see setProjectFileContents()
|
|
67
|
+
*/
|
|
68
|
+
setContents(contents) {
|
|
69
|
+
// Assuming _tera has this method and it returns Promise<void> or similar
|
|
70
|
+
return this._tera.setProjectFileContents(this.id, contents, {});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Fetch the file contents as an array of Reflib refs
|
|
74
|
+
*
|
|
75
|
+
* @returns {Promise<Array<RefLibRef>>} An eventual array of RefLib references
|
|
76
|
+
*
|
|
77
|
+
* @see getProjectLibrary()
|
|
78
|
+
*/
|
|
79
|
+
getRefs() {
|
|
80
|
+
// Assuming _tera has this method and it returns Promise<Array<RefLibRef>>
|
|
81
|
+
return this._tera.getProjectLibrary(this.id);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Overwrite the contents of a file with a new collection of Reflib refs
|
|
85
|
+
*
|
|
86
|
+
* @param {Array<RefLibRef>} refs Collection of references for the selected library
|
|
87
|
+
*
|
|
88
|
+
* @returns {Promise<void>} A promise which resolves when the operation has completed
|
|
89
|
+
*
|
|
90
|
+
* @see setProjectLibrary()
|
|
91
|
+
*/
|
|
92
|
+
setRefs(refs) {
|
|
93
|
+
// Assuming _tera has this method and it returns Promise<void> or similar
|
|
94
|
+
return this._tera.setProjectLibrary(this.id, refs);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Compress a file state down into a serializable entity
|
|
98
|
+
* By default this computes a Structured Clone which can be stringified
|
|
99
|
+
*
|
|
100
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
|
|
101
|
+
* @returns {Object} A Structured Clone compatible representation of this ProjectFile instance
|
|
102
|
+
*/
|
|
103
|
+
serialize() {
|
|
104
|
+
return pick(this, [
|
|
105
|
+
'id',
|
|
106
|
+
'sbId',
|
|
107
|
+
'name',
|
|
108
|
+
'icon',
|
|
109
|
+
'path',
|
|
110
|
+
'url',
|
|
111
|
+
'parsedName',
|
|
112
|
+
'created',
|
|
113
|
+
'modified',
|
|
114
|
+
'accessed',
|
|
115
|
+
'size',
|
|
116
|
+
'mime',
|
|
117
|
+
'meta',
|
|
118
|
+
// Note that computed values such as `*Formatted` are omitted as they can be computed during the constructor stage
|
|
119
|
+
]);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Restore an entity created with serialize
|
|
123
|
+
* NOTE: This requires the 'tera' instance to be manually added to the 'data' object before calling deserialize,
|
|
124
|
+
* as it's not included in the serialized output.
|
|
125
|
+
*
|
|
126
|
+
* @param {Object} data An input object created via `ProjectFiles.serialize()` (MUST include a 'tera' property added manually)
|
|
127
|
+
* @returns {ProjectFile} A ProjectFile instance setup against the deserializzed data
|
|
128
|
+
*/
|
|
129
|
+
static deserialize(data) {
|
|
130
|
+
// TODO: Check the below
|
|
131
|
+
// WARNING: The original 'serialize' method does NOT include 'tera'.
|
|
132
|
+
// The caller of 'deserialize' MUST add the correct 'tera' instance to the 'data' object
|
|
133
|
+
// before passing it here, otherwise the constructor will fail.
|
|
134
|
+
// e.g., const serializedData = file.serialize();
|
|
135
|
+
// serializedData.tera = myTeraClientInstance;
|
|
136
|
+
// const restoredFile = ProjectFile.deserialize(serializedData);
|
|
137
|
+
// This pick includes 'tera', assuming it was added to 'data' externally.
|
|
138
|
+
const constructorArg = pick(data, [
|
|
139
|
+
'tera', // Assumes 'tera' exists on the input 'data' object
|
|
140
|
+
'id',
|
|
141
|
+
'sbId',
|
|
142
|
+
'name',
|
|
143
|
+
'icon',
|
|
144
|
+
'path',
|
|
145
|
+
'url',
|
|
146
|
+
'parsedName',
|
|
147
|
+
'created',
|
|
148
|
+
'modified',
|
|
149
|
+
'accessed',
|
|
150
|
+
'size',
|
|
151
|
+
'mime',
|
|
152
|
+
'meta',
|
|
153
|
+
]);
|
|
154
|
+
return new ProjectFile(constructorArg);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=projectFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectFile.js","sourceRoot":"","sources":["../../lib/projectFile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { BoundSupabaseyFunction } from '@iebh/supabasey';
|
|
2
|
+
interface SyncroEntityConfig {
|
|
3
|
+
singular: string;
|
|
4
|
+
initState: (args: {
|
|
5
|
+
supabasey: BoundSupabaseyFunction;
|
|
6
|
+
id: string;
|
|
7
|
+
relation?: string;
|
|
8
|
+
}) => Promise<any>;
|
|
9
|
+
flushState: (args: {
|
|
10
|
+
supabasey: BoundSupabaseyFunction;
|
|
11
|
+
state: any;
|
|
12
|
+
id?: string;
|
|
13
|
+
fsId?: string;
|
|
14
|
+
relation?: string;
|
|
15
|
+
}) => Promise<any>;
|
|
16
|
+
}
|
|
17
|
+
type SyncroConfig = Record<string, SyncroEntityConfig>;
|
|
18
|
+
/**
|
|
19
|
+
* Entities we support Syncro paths for, each should correspond directly with a Firebase/Firestore collection name
|
|
20
|
+
*
|
|
21
|
+
* @type {Object} An object lookup of entities
|
|
22
|
+
*
|
|
23
|
+
* @property {String} singular The singular noun for the item
|
|
24
|
+
* @property {Function} initState Function called to initialize state when Firestore has no existing document. Called as `({supabase:BoundSupabaseyFunction, entity:String, id:String, relation?:string})` and expected to return the initial data object state
|
|
25
|
+
* @property {Function} flushState Function called to flush state from Firebase to Supabase. Called the same as `initState` + `{state:Object}`
|
|
26
|
+
*/
|
|
27
|
+
declare const syncroConfig: SyncroConfig;
|
|
28
|
+
export default syncroConfig;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import Reflib from '@iebh/reflib';
|
|
3
|
+
import { v4 as uuid4 } from 'uuid';
|
|
4
|
+
import { nanoid } from 'nanoid';
|
|
5
|
+
/**
|
|
6
|
+
* Entities we support Syncro paths for, each should correspond directly with a Firebase/Firestore collection name
|
|
7
|
+
*
|
|
8
|
+
* @type {Object} An object lookup of entities
|
|
9
|
+
*
|
|
10
|
+
* @property {String} singular The singular noun for the item
|
|
11
|
+
* @property {Function} initState Function called to initialize state when Firestore has no existing document. Called as `({supabase:BoundSupabaseyFunction, entity:String, id:String, relation?:string})` and expected to return the initial data object state
|
|
12
|
+
* @property {Function} flushState Function called to flush state from Firebase to Supabase. Called the same as `initState` + `{state:Object}`
|
|
13
|
+
*/
|
|
14
|
+
const syncroConfig = {
|
|
15
|
+
projects: {
|
|
16
|
+
singular: 'project',
|
|
17
|
+
async initState({ supabasey, id }) {
|
|
18
|
+
let projectData = await supabasey((supabase) => supabase
|
|
19
|
+
.from('projects')
|
|
20
|
+
.select('data')
|
|
21
|
+
.eq('id', id)
|
|
22
|
+
.maybeSingle());
|
|
23
|
+
if (!projectData)
|
|
24
|
+
throw new Error(`Syncro project "${id}" not found`);
|
|
25
|
+
let data = projectData.data;
|
|
26
|
+
// MIGRATION - Move data.temp{} into Supabase files + add pointer to filename {{{
|
|
27
|
+
if (data.temp // Project contains temp subkey
|
|
28
|
+
&& Object.values(data.temp).some((t) => typeof t == 'object') // Some of the temp keys are objects
|
|
29
|
+
) {
|
|
30
|
+
console.log('[MIGRATION] tera-fy project v1 -> v2', data.temp);
|
|
31
|
+
const tempObject = data.temp;
|
|
32
|
+
await Promise.all(Object.entries(data.temp)
|
|
33
|
+
.filter(([, branch]) => typeof branch == 'object')
|
|
34
|
+
.map(([toolKey,]) => {
|
|
35
|
+
console.log(`[MIGRATION] Converting data.temp[${toolKey}]...`);
|
|
36
|
+
const toolName = toolKey.split('-')[0];
|
|
37
|
+
const fileName = `data-${toolName}-${nanoid()}.json`;
|
|
38
|
+
console.log('[MIGRATION] Creating filename:', fileName);
|
|
39
|
+
return Promise.resolve()
|
|
40
|
+
.then(() => supabasey((supabase) => supabase // Split data.temp[toolKey] -> file {{{
|
|
41
|
+
.storage
|
|
42
|
+
.from('projects')
|
|
43
|
+
.upload(`${id}/${fileName}`, new File([
|
|
44
|
+
new Blob([
|
|
45
|
+
JSON.stringify(tempObject[toolKey], null, '\t'),
|
|
46
|
+
], {
|
|
47
|
+
type: 'application/json',
|
|
48
|
+
}),
|
|
49
|
+
], fileName, {
|
|
50
|
+
type: 'application/json',
|
|
51
|
+
}), {
|
|
52
|
+
cacheControl: '3600',
|
|
53
|
+
upsert: true,
|
|
54
|
+
}))) // }}}
|
|
55
|
+
.then(() => tempObject[toolKey] = fileName) // Replace data.temp[toolKey] with new filename
|
|
56
|
+
.catch(e => {
|
|
57
|
+
console.warn('[MIGRATION] Failed to create file', fileName, '-', e);
|
|
58
|
+
throw e;
|
|
59
|
+
});
|
|
60
|
+
}));
|
|
61
|
+
} // }}}
|
|
62
|
+
return data;
|
|
63
|
+
},
|
|
64
|
+
flushState({ supabasey, state, fsId }) {
|
|
65
|
+
// Import Supabasey because 'supabasey' lowercase is just a function
|
|
66
|
+
return supabasey(supabase => supabase.rpc('syncro_merge_data', {
|
|
67
|
+
table_name: 'projects',
|
|
68
|
+
entity_id: fsId,
|
|
69
|
+
new_data: state,
|
|
70
|
+
}));
|
|
71
|
+
},
|
|
72
|
+
}, // }}}
|
|
73
|
+
project_libraries: {
|
|
74
|
+
singular: 'project library',
|
|
75
|
+
async initState({ supabasey, id, relation }) {
|
|
76
|
+
if (!relation || !/_\*$/.test(relation))
|
|
77
|
+
throw new Error('Project library relation missing, path should resemble "project_library::${PROJECT}::${LIBRARY_FILE_ID}_*"');
|
|
78
|
+
let fileId = relation.replace(/_\*$/, '');
|
|
79
|
+
const files = await supabasey((supabase) => supabase
|
|
80
|
+
.storage
|
|
81
|
+
.from('projects')
|
|
82
|
+
.list(id));
|
|
83
|
+
const file = files?.find((f) => f.id == fileId);
|
|
84
|
+
if (!file)
|
|
85
|
+
return Promise.reject(`Invalid file ID "${fileId}"`);
|
|
86
|
+
const blob = await supabasey((supabase) => supabase
|
|
87
|
+
.storage
|
|
88
|
+
.from('projects')
|
|
89
|
+
.download(`${id}/${file.name}`));
|
|
90
|
+
if (!blob)
|
|
91
|
+
throw new Error('Failed to download file blob');
|
|
92
|
+
const refs = await Reflib.uploadFile({
|
|
93
|
+
file: new File([blob], file.name.replace(/^.*[/\\]/, '')),
|
|
94
|
+
});
|
|
95
|
+
return Object.fromEntries(refs // Transform Reflib Ref array into a keyed UUID object
|
|
96
|
+
.map((ref) => [
|
|
97
|
+
uuid4(), // TODO: This should really be using V5 with some-kind of namespacing but I can't get my head around the documentation - MC 2025-02-21
|
|
98
|
+
ref, // The actual ref payload
|
|
99
|
+
]));
|
|
100
|
+
},
|
|
101
|
+
flushState() {
|
|
102
|
+
throw new Error('Flushing project_libraries::* namespace is not yet supported');
|
|
103
|
+
},
|
|
104
|
+
}, // }}}
|
|
105
|
+
project_namespaces: {
|
|
106
|
+
singular: 'project namespace',
|
|
107
|
+
async initState({ supabasey, id, relation }) {
|
|
108
|
+
if (!relation)
|
|
109
|
+
throw new Error('Project namespace relation missing, path should resemble "project_namespaces::${PROJECT}::${RELATION}"');
|
|
110
|
+
let rows = await supabasey((supabase) => supabase
|
|
111
|
+
.from('project_namespaces')
|
|
112
|
+
.select('data')
|
|
113
|
+
.eq('project', id)
|
|
114
|
+
.eq('name', relation)
|
|
115
|
+
.limit(1));
|
|
116
|
+
if (rows && rows.length == 1) {
|
|
117
|
+
return rows[0].data;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const newItem = await supabasey((supabase) => supabase
|
|
121
|
+
.from('project_namespaces') // Doesn't exist - create it
|
|
122
|
+
.insert({
|
|
123
|
+
project: id,
|
|
124
|
+
name: relation,
|
|
125
|
+
data: {},
|
|
126
|
+
})
|
|
127
|
+
.select('data')
|
|
128
|
+
.single() // Assuming insert returns the single inserted row
|
|
129
|
+
);
|
|
130
|
+
if (!newItem)
|
|
131
|
+
throw new Error('Failed to create project namespace');
|
|
132
|
+
return newItem.data;
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
flushState({ supabasey, state, id, relation }) {
|
|
136
|
+
return supabasey((supabase) => supabase
|
|
137
|
+
.from('project_namespaces')
|
|
138
|
+
.update({
|
|
139
|
+
edited_at: new Date().toISOString(),
|
|
140
|
+
data: state,
|
|
141
|
+
})
|
|
142
|
+
.eq('project', id)
|
|
143
|
+
.eq('name', relation));
|
|
144
|
+
},
|
|
145
|
+
}, // }}}
|
|
146
|
+
test: {
|
|
147
|
+
singular: 'test',
|
|
148
|
+
async initState({ supabasey, id }) {
|
|
149
|
+
let rows = await supabasey((supabase) => supabase
|
|
150
|
+
.from('test')
|
|
151
|
+
.select('data')
|
|
152
|
+
.eq('id', id)
|
|
153
|
+
.limit(1));
|
|
154
|
+
if (!rows || rows.length !== 1)
|
|
155
|
+
return Promise.reject(`Syncro test item "${id}" not found`);
|
|
156
|
+
return rows[0].data;
|
|
157
|
+
},
|
|
158
|
+
flushState({ supabasey, state, fsId }) {
|
|
159
|
+
return supabasey(supabase => supabase.rpc('syncro_merge_data', {
|
|
160
|
+
table_name: 'test',
|
|
161
|
+
entity_id: fsId,
|
|
162
|
+
new_data: state,
|
|
163
|
+
}));
|
|
164
|
+
},
|
|
165
|
+
}, // }}}
|
|
166
|
+
users: {
|
|
167
|
+
singular: 'user',
|
|
168
|
+
async initState({ supabasey, id }) {
|
|
169
|
+
let user = await supabasey((supabase) => supabase
|
|
170
|
+
.from('users')
|
|
171
|
+
.select('data')
|
|
172
|
+
.eq('id', id)
|
|
173
|
+
.maybeSingle());
|
|
174
|
+
if (user)
|
|
175
|
+
return user.data; // User is valid and already exists
|
|
176
|
+
// User row doesn't already exist - need to create stub
|
|
177
|
+
let newUser = await supabasey((supabase) => supabase
|
|
178
|
+
.from('users')
|
|
179
|
+
.insert({
|
|
180
|
+
id,
|
|
181
|
+
data: {
|
|
182
|
+
id,
|
|
183
|
+
credits: 1000,
|
|
184
|
+
},
|
|
185
|
+
})
|
|
186
|
+
.select('data')
|
|
187
|
+
.single() // Assuming insert returns the single inserted row
|
|
188
|
+
);
|
|
189
|
+
if (!newUser)
|
|
190
|
+
throw new Error('Failed to create user');
|
|
191
|
+
return newUser.data; // Return back the data that eventually got created - allowing for database triggers, default field values etc.
|
|
192
|
+
},
|
|
193
|
+
flushState({ supabasey, state, fsId }) {
|
|
194
|
+
return supabasey(supabase => supabase.rpc('syncro_merge_data', {
|
|
195
|
+
table_name: 'users',
|
|
196
|
+
entity_id: fsId,
|
|
197
|
+
new_data: state,
|
|
198
|
+
}));
|
|
199
|
+
},
|
|
200
|
+
}, // }}}
|
|
201
|
+
};
|
|
202
|
+
export default syncroConfig;
|
|
203
|
+
//# sourceMappingURL=entities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entities.js","sourceRoot":"","sources":["../../../lib/syncro/entities.ts"],"names":[],"mappings":"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"}
|