@zveltio/sdk 3.0.0-beta.5 → 3.0.0-beta.68
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/dist/client/Auth.d.ts.map +1 -1
- package/dist/client/Auth.js +3 -0
- package/dist/client/QueryBuilder.d.ts.map +1 -1
- package/dist/client/QueryBuilder.js +4 -0
- package/dist/client/ZveltioClient.d.ts.map +1 -1
- package/dist/client/ZveltioClient.js +5 -0
- package/dist/client.d.ts +4 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +30 -13
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +21 -3
- package/dist/crdt.d.ts.map +1 -1
- package/dist/crdt.js +11 -2
- package/dist/ddl/index.d.ts.map +1 -1
- package/dist/errors.d.ts +58 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +124 -0
- package/dist/extension/index.d.ts +419 -19
- package/dist/extension/index.d.ts.map +1 -1
- package/dist/extension/index.js +3 -0
- package/dist/extension/jsonb.d.ts +62 -0
- package/dist/extension/jsonb.d.ts.map +1 -0
- package/dist/extension/jsonb.js +64 -0
- package/dist/extension/multipart.d.ts +58 -0
- package/dist/extension/multipart.d.ts.map +1 -0
- package/dist/extension/multipart.js +61 -0
- package/dist/extension/numeric.d.ts +94 -0
- package/dist/extension/numeric.d.ts.map +1 -0
- package/dist/extension/numeric.js +162 -0
- package/dist/extension/permission-gate.d.ts +15 -0
- package/dist/extension/permission-gate.d.ts.map +1 -1
- package/dist/extension/permission-gate.js +33 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/local-store.d.ts +5 -0
- package/dist/local-store.d.ts.map +1 -1
- package/dist/local-store.js +62 -10
- package/dist/offline/index.d.ts +3 -3
- package/dist/offline/index.js +51 -15
- package/dist/publish/index.d.ts.map +1 -1
- package/dist/publish/index.js +6 -1
- package/dist/realtime.d.ts +9 -1
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +15 -2
- package/dist/rpc/index.d.ts.map +1 -1
- package/dist/rpc/index.js +2 -0
- package/dist/schema-codegen.d.ts +3 -1
- package/dist/schema-codegen.d.ts.map +1 -1
- package/dist/schema-codegen.js +41 -7
- package/dist/schema-watcher.d.ts +1 -1
- package/dist/schema-watcher.js +1 -1
- package/dist/studio/index.d.ts +1 -0
- package/dist/studio/index.d.ts.map +1 -1
- package/dist/studio/index.js +3 -0
- package/dist/studio/slot-owner-registry.d.ts +13 -0
- package/dist/studio/slot-owner-registry.d.ts.map +1 -0
- package/dist/studio/slot-owner-registry.js +21 -0
- package/dist/svelte.d.ts +1 -1
- package/dist/svelte.d.ts.map +1 -1
- package/dist/svelte.js +4 -2
- package/dist/sync-manager.d.ts +30 -4
- package/dist/sync-manager.d.ts.map +1 -1
- package/dist/sync-manager.js +101 -15
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +23 -1
- package/dist/testing/with-test-db.d.ts.map +1 -1
- package/dist/testing/with-test-db.js +21 -14
- package/dist/tests/client.test.d.ts +2 -0
- package/dist/tests/client.test.d.ts.map +1 -0
- package/dist/tests/client.test.js +55 -0
- package/dist/tests/crdt-orset.test.d.ts +2 -0
- package/dist/tests/crdt-orset.test.d.ts.map +1 -0
- package/dist/tests/crdt-orset.test.js +23 -0
- package/dist/tests/local-store.test.js +44 -0
- package/dist/tests/multipart.test.d.ts +2 -0
- package/dist/tests/multipart.test.d.ts.map +1 -0
- package/dist/tests/multipart.test.js +37 -0
- package/dist/tests/offline-provider-crdt.test.d.ts +2 -0
- package/dist/tests/offline-provider-crdt.test.d.ts.map +1 -0
- package/dist/tests/offline-provider-crdt.test.js +119 -0
- package/dist/tests/realtime.test.d.ts +2 -0
- package/dist/tests/realtime.test.d.ts.map +1 -0
- package/dist/tests/realtime.test.js +39 -0
- package/dist/tests/sync-manager.test.d.ts +2 -0
- package/dist/tests/sync-manager.test.d.ts.map +1 -0
- package/dist/tests/sync-manager.test.js +65 -0
- package/dist/tests/with-test-db.test.d.ts +2 -0
- package/dist/tests/with-test-db.test.d.ts.map +1 -0
- package/dist/tests/with-test-db.test.js +57 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/validate/index.d.ts +49 -0
- package/dist/validate/index.d.ts.map +1 -1
- package/dist/validate/index.js +494 -7
- package/dist/validate/shared-message-keys.d.ts +16 -0
- package/dist/validate/shared-message-keys.d.ts.map +1 -0
- package/dist/validate/shared-message-keys.js +227 -0
- package/package.json +7 -7
- package/dist/generate-types.d.ts +0 -37
- package/dist/generate-types.d.ts.map +0 -1
- package/dist/generate-types.js +0 -157
package/dist/local-store.js
CHANGED
|
@@ -46,6 +46,7 @@ export class LocalStore {
|
|
|
46
46
|
await this.db.put('meta', { key: 'crdt_lamport', value: this.clock.current });
|
|
47
47
|
}
|
|
48
48
|
/** Write a local record and add to sync queue */
|
|
49
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
49
50
|
async put(collection, id, data) {
|
|
50
51
|
if (!this.db)
|
|
51
52
|
throw new Error('LocalStore not opened');
|
|
@@ -155,14 +156,33 @@ export class LocalStore {
|
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
/** Apply data from server (via WebSocket or pull) */
|
|
158
|
-
async applyServerUpdate(collection, id,
|
|
159
|
+
async applyServerUpdate(collection, id,
|
|
160
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
161
|
+
data, serverVersion) {
|
|
159
162
|
if (!this.db)
|
|
160
163
|
throw new Error('LocalStore not opened');
|
|
161
164
|
const existing = (await this.db.get('records', [collection, id]));
|
|
162
|
-
// Conflict detection: local has changes not yet confirmed by server
|
|
163
|
-
|
|
165
|
+
// Conflict detection: local has changes not yet confirmed by server.
|
|
166
|
+
//
|
|
167
|
+
// `_syncStatus` is the signal that survives contact with the SyncManager.
|
|
168
|
+
// The version comparison alone does not: `syncNow()` and `pull()` both pass
|
|
169
|
+
// `Date.now()` as the server version, because the collections API returns no
|
|
170
|
+
// version column — so after the first ACK `_serverVersion` is an epoch
|
|
171
|
+
// millisecond count while `_localVersion` is still a small counter, and
|
|
172
|
+
// `2 > 1790144009198` is false forever. Every local edit made after that
|
|
173
|
+
// first sync was overwritten in silence: status `synced`, no `_conflictData`,
|
|
174
|
+
// nothing in `getConflicts()`. The unit tests missed it because they hand
|
|
175
|
+
// this method versions on the same scale as the counter (1, 2, 3, 5).
|
|
176
|
+
//
|
|
177
|
+
// The version comparison is kept as a second signal: it still catches the
|
|
178
|
+
// race where an ACK for an earlier operation marks the record synced while a
|
|
179
|
+
// later one is queued.
|
|
180
|
+
if (existing &&
|
|
181
|
+
(existing._syncStatus !== 'synced' || existing._localVersion > existing._serverVersion)) {
|
|
164
182
|
// CRDT field-level merge if both sides have CRDT docs
|
|
183
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
165
184
|
if (existing._crdtDoc && data.__crdt) {
|
|
185
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
166
186
|
const remoteCrdtDoc = data.__crdt;
|
|
167
187
|
const merged = mergeLWW(existing._crdtDoc, remoteCrdtDoc);
|
|
168
188
|
const mergedData = fromDocument(merged);
|
|
@@ -192,9 +212,22 @@ export class LocalStore {
|
|
|
192
212
|
_serverVersion: serverVersion,
|
|
193
213
|
_syncStatus: 'synced',
|
|
194
214
|
_updatedAt: Date.now(),
|
|
215
|
+
// Carried over: rebuilding the record from scratch dropped the CRDT
|
|
216
|
+
// document, so the next merge had nothing on the local side to merge with
|
|
217
|
+
// and fell through to the manual-conflict branch.
|
|
218
|
+
...(existing?._crdtDoc ? { _crdtDoc: existing._crdtDoc } : {}),
|
|
195
219
|
};
|
|
196
220
|
await this.db.put('records', record);
|
|
197
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* The server deleted a record: drop the local copy WITHOUT queueing a delete.
|
|
224
|
+
* `delete()` would queue one, echoing the server's own deletion back at it.
|
|
225
|
+
*/
|
|
226
|
+
async applyServerDelete(collection, id) {
|
|
227
|
+
if (!this.db)
|
|
228
|
+
throw new Error('LocalStore not opened');
|
|
229
|
+
await this.db.delete('records', [collection, id]);
|
|
230
|
+
}
|
|
198
231
|
/** Get records with conflicts for UI resolution */
|
|
199
232
|
async getConflicts(collection) {
|
|
200
233
|
if (!this.db)
|
|
@@ -205,16 +238,35 @@ export class LocalStore {
|
|
|
205
238
|
return all;
|
|
206
239
|
}
|
|
207
240
|
/** Resolve a conflict (user decides which version wins) */
|
|
208
|
-
async resolveConflict(collection, id,
|
|
241
|
+
async resolveConflict(collection, id,
|
|
242
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
243
|
+
resolvedData) {
|
|
209
244
|
if (!this.db)
|
|
210
245
|
throw new Error('LocalStore not opened');
|
|
211
246
|
const record = (await this.db.get('records', [collection, id]));
|
|
212
|
-
if (record)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
247
|
+
if (!record)
|
|
248
|
+
return;
|
|
249
|
+
record.data = resolvedData;
|
|
250
|
+
record._syncStatus = 'pending'; // Re-sync with server
|
|
251
|
+
record._localVersion += 1;
|
|
252
|
+
record._conflictData = undefined;
|
|
253
|
+
// Nothing re-synced it. The status said `pending` and the queue held no
|
|
254
|
+
// operation carrying the resolved data, so a resolution — whether a person
|
|
255
|
+
// chose it in the UI or the CRDT merge produced it — stayed on the device.
|
|
256
|
+
// The only operation for this record was the one the server had already
|
|
257
|
+
// rejected.
|
|
258
|
+
const tx = this.db.transaction(['records', 'sync_queue'], 'readwrite');
|
|
259
|
+
await tx.objectStore('records').put(record);
|
|
260
|
+
await tx.objectStore('sync_queue').add({
|
|
261
|
+
id: `${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
262
|
+
collection,
|
|
263
|
+
recordId: id,
|
|
264
|
+
operation: 'update',
|
|
265
|
+
payload: resolvedData,
|
|
266
|
+
attempts: 0,
|
|
267
|
+
createdAt: Date.now(),
|
|
268
|
+
});
|
|
269
|
+
await tx.done;
|
|
218
270
|
}
|
|
219
271
|
/** Save an offline blob — returns a temporary ID 'local_blob_<UUID>' */
|
|
220
272
|
async saveBlob(blob, collection, recordId, field) {
|
package/dist/offline/index.d.ts
CHANGED
|
@@ -69,9 +69,9 @@ export interface OfflineProviderConfig {
|
|
|
69
69
|
websocket?: typeof WebSocket;
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
|
-
* Public interface every provider implements.
|
|
73
|
-
*
|
|
74
|
-
*
|
|
72
|
+
* Public interface every provider implements. The CRDT provider wraps
|
|
73
|
+
* `SyncManager`; the Electric provider wraps a websocket. Both expose the same
|
|
74
|
+
* surface.
|
|
75
75
|
*/
|
|
76
76
|
export interface OfflineProvider {
|
|
77
77
|
readonly kind: OfflineProviderKind;
|
package/dist/offline/index.js
CHANGED
|
@@ -45,7 +45,7 @@ export class ElectricNotConfigured extends Error {
|
|
|
45
45
|
constructor(reason) {
|
|
46
46
|
super(`Electric SQL provider is not configured: ${reason}. ` +
|
|
47
47
|
`Set provider: 'crdt' for the default sync path, or stand up an Electric ` +
|
|
48
|
-
`service and pass electricUrl. See docs/
|
|
48
|
+
`service and pass electricUrl. See docs/engine/offline-sync.md.`);
|
|
49
49
|
this.name = 'ElectricNotConfigured';
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -76,27 +76,63 @@ export async function createOfflineProvider(config) {
|
|
|
76
76
|
return makeCrdtAdapter(config);
|
|
77
77
|
}
|
|
78
78
|
// ── CRDT adapter (today's working path) ─────────────────────────────────────
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
/**
|
|
80
|
+
* The CRDT provider, wrapping `SyncManager`.
|
|
81
|
+
*
|
|
82
|
+
* It did not wrap anything. `pull()` was an empty body, `subscribe()` returned
|
|
83
|
+
* an unsubscribe that unsubscribed from nothing, and `push()` returned `0` —
|
|
84
|
+
* which is the worst of the four, because `0` reads as "there was nothing to
|
|
85
|
+
* send" rather than "I did not look". `SyncManager` was imported and then
|
|
86
|
+
* discarded with `void SyncManager`, and the interface docs a few lines up said
|
|
87
|
+
* "Today the CRDT provider wraps SyncManager" while it did not.
|
|
88
|
+
*
|
|
89
|
+
* This is the DEFAULT provider (`config.provider ?? 'crdt'`), so an application
|
|
90
|
+
* that called `createOfflineProvider({ engineUrl })` and pushed on a timer got a
|
|
91
|
+
* clean run and an empty server, forever, with nothing in any log.
|
|
92
|
+
*
|
|
93
|
+
* The store is opened but background sync is NOT started: this interface is
|
|
94
|
+
* explicitly pull/push, and a timer firing `syncNow()` underneath would make the
|
|
95
|
+
* number `push()` returns meaningless.
|
|
96
|
+
*/
|
|
97
|
+
async function makeCrdtAdapter(config) {
|
|
98
|
+
// Lazy imports keep the bundle tree-shakeable for consumers who only want the
|
|
99
|
+
// type definitions.
|
|
100
|
+
const [{ SyncManager }, { ZveltioClient }] = await Promise.all([
|
|
101
|
+
import('../sync-manager.js'),
|
|
102
|
+
import('../client.js'),
|
|
103
|
+
]);
|
|
104
|
+
const client = new ZveltioClient({ baseUrl: config.engineUrl });
|
|
105
|
+
const sync = new SyncManager(client);
|
|
106
|
+
await sync.open();
|
|
107
|
+
const tables = config.tables ?? [];
|
|
85
108
|
return {
|
|
86
109
|
kind: 'crdt',
|
|
87
110
|
async pull() {
|
|
88
|
-
|
|
111
|
+
// Silence here is what the old implementation was. A provider asked to
|
|
112
|
+
// pull with nothing to pull from is a configuration mistake, and saying so
|
|
113
|
+
// costs one throw; not saying so costs an empty local database that looks
|
|
114
|
+
// like an empty server.
|
|
115
|
+
if (tables.length === 0) {
|
|
116
|
+
throw new Error('createOfflineProvider: `tables` is empty, so there is nothing to pull. ' +
|
|
117
|
+
'List the collections to replicate, e.g. { tables: ["orders", "customers"] }.');
|
|
118
|
+
}
|
|
119
|
+
await sync.pull(tables);
|
|
89
120
|
},
|
|
90
121
|
async push() {
|
|
91
|
-
|
|
122
|
+
// The count is the drop in pending operations across the sync. Operations
|
|
123
|
+
// that failed stay pending and are therefore not counted, which is what
|
|
124
|
+
// "the number of ops sent" has to mean if the number is to be worth
|
|
125
|
+
// anything.
|
|
126
|
+
const before = await sync.getStatus();
|
|
127
|
+
await sync.syncNow();
|
|
128
|
+
const after = await sync.getStatus();
|
|
129
|
+
return Math.max(0, before.pending - after.pending);
|
|
92
130
|
},
|
|
93
|
-
subscribe(
|
|
94
|
-
return () =>
|
|
95
|
-
/* */
|
|
96
|
-
};
|
|
131
|
+
subscribe(table, cb) {
|
|
132
|
+
return sync.collection(table).subscribe((rows) => cb(rows));
|
|
97
133
|
},
|
|
98
134
|
async close() {
|
|
99
|
-
|
|
135
|
+
await sync.stop();
|
|
100
136
|
},
|
|
101
137
|
};
|
|
102
138
|
}
|
|
@@ -131,7 +167,7 @@ async function makeElectricProvider(config) {
|
|
|
131
167
|
return (await res.json());
|
|
132
168
|
}
|
|
133
169
|
let auth = await mintToken();
|
|
134
|
-
|
|
170
|
+
const electricUrl = config.electricUrl ?? auth.electricUrl;
|
|
135
171
|
// Per-table subscription registry.
|
|
136
172
|
const subscribers = new Map();
|
|
137
173
|
// Token refresh — fire-and-forget background timer that mints a fresh
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/publish/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,SAAS,EAAE,UAAU,CAAC;IACtB,oDAAoD;IACpD,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,qFAAqF;AACrF,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,SAAS,CAAC;IACrB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;CACf;AAED,iBAAS,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,CAK3D;AAED,iBAAS,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAKhD;AAED,iBAAS,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAO9C;AAED,6CAA6C;AAC7C,wBAAsB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAGlE;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAY7E;AAQD,qEAAqE;AACrE,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAE1E;AAED,yEAAyE;AACzE,wBAAsB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAEzE;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,kBAAkB,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/publish/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,SAAS,EAAE,UAAU,CAAC;IACtB,oDAAoD;IACpD,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,qFAAqF;AACrF,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,SAAS,CAAC;IACrB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;CACf;AAED,iBAAS,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,CAK3D;AAED,iBAAS,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAKhD;AAED,iBAAS,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAO9C;AAED,6CAA6C;AAC7C,wBAAsB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAGlE;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAY7E;AAQD,qEAAqE;AACrE,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAE1E;AAED,yEAAyE;AACzE,wBAAsB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAEzE;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,kBAAkB,CAAC,CAa7B;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,UAAU,EACnB,SAAS,EAAE,kBAAkB,EAC7B,SAAS,EAAE,UAAU,GACpB,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA+BvD;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,UAAU,GACpB,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CASlD;AAGD,eAAO,MAAM,MAAM;;;;CAA+C,CAAC"}
|
package/dist/publish/index.js
CHANGED
|
@@ -86,6 +86,7 @@ export async function signBundle(archive, keypair) {
|
|
|
86
86
|
const bundleSha256 = await sha256Hex(archive);
|
|
87
87
|
const key = await importPrivateKey(keypair.privateJwk);
|
|
88
88
|
const dataBytes = new TextEncoder().encode(bundleSha256.toLowerCase());
|
|
89
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
89
90
|
const sigBuf = await crypto.subtle.sign({ name: 'Ed25519' }, key, dataBytes);
|
|
90
91
|
return {
|
|
91
92
|
algorithm: 'ed25519',
|
|
@@ -123,7 +124,11 @@ export async function verifyBundle(archive, signature, publicJwk) {
|
|
|
123
124
|
}
|
|
124
125
|
const key = await importPublicKey(publicJwk);
|
|
125
126
|
const dataBytes = new TextEncoder().encode(signature.bundleSha256.toLowerCase());
|
|
126
|
-
const ok = await crypto.subtle.verify({ name: 'Ed25519' }, key,
|
|
127
|
+
const ok = await crypto.subtle.verify({ name: 'Ed25519' }, key,
|
|
128
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
129
|
+
sigBytes,
|
|
130
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
131
|
+
dataBytes);
|
|
127
132
|
return ok ? { ok: true } : { ok: false, reason: 'Ed25519 verification failed' };
|
|
128
133
|
}
|
|
129
134
|
/**
|
package/dist/realtime.d.ts
CHANGED
|
@@ -5,7 +5,15 @@ export declare class ZveltioRealtime {
|
|
|
5
5
|
private reconnectAttempts;
|
|
6
6
|
private maxReconnectAttempts;
|
|
7
7
|
private reconnectTimer;
|
|
8
|
-
|
|
8
|
+
private headers;
|
|
9
|
+
/**
|
|
10
|
+
* @param options.headers Sent with the upgrade — e.g. `{ 'X-API-Key': key }`
|
|
11
|
+
* for a server-side client. Bun and Node (undici) accept them; a browser
|
|
12
|
+
* cannot set headers on a WebSocket and authenticates by session cookie.
|
|
13
|
+
*/
|
|
14
|
+
constructor(baseUrl: string, options?: {
|
|
15
|
+
headers?: Record<string, string>;
|
|
16
|
+
});
|
|
9
17
|
connect(): void;
|
|
10
18
|
private attemptReconnect;
|
|
11
19
|
subscribe(collection: string, callback: (data: any) => void): () => void;
|
package/dist/realtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../src/realtime.ts"],"names":[],"mappings":"AAAA,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAA0B;
|
|
1
|
+
{"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../src/realtime.ts"],"names":[],"mappings":"AAAA,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAA0B;IAEpC,OAAO,CAAC,SAAS,CAAoD;IACrE,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,oBAAoB,CAAM;IAClC,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,OAAO,CAAqC;IAEpD;;;;OAIG;gBACS,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAO;IAM/E,OAAO,IAAI,IAAI;IA6Cf,OAAO,CAAC,gBAAgB;IASxB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,GAAG,MAAM,IAAI;IAqBxE,UAAU,IAAI,IAAI;CAQnB"}
|
package/dist/realtime.js
CHANGED
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
export class ZveltioRealtime {
|
|
2
2
|
ws = null;
|
|
3
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
3
4
|
listeners = new Map();
|
|
4
5
|
baseUrl;
|
|
5
6
|
reconnectAttempts = 0;
|
|
6
7
|
maxReconnectAttempts = 10;
|
|
7
8
|
reconnectTimer = null;
|
|
8
|
-
|
|
9
|
+
headers;
|
|
10
|
+
/**
|
|
11
|
+
* @param options.headers Sent with the upgrade — e.g. `{ 'X-API-Key': key }`
|
|
12
|
+
* for a server-side client. Bun and Node (undici) accept them; a browser
|
|
13
|
+
* cannot set headers on a WebSocket and authenticates by session cookie.
|
|
14
|
+
*/
|
|
15
|
+
constructor(baseUrl, options = {}) {
|
|
9
16
|
// Convert http(s) to ws(s)
|
|
10
17
|
this.baseUrl = baseUrl.replace(/^http/, 'ws');
|
|
18
|
+
this.headers = options.headers;
|
|
11
19
|
}
|
|
12
20
|
connect() {
|
|
13
21
|
const wsUrl = `${this.baseUrl}/api/ws`;
|
|
14
|
-
|
|
22
|
+
// The two-argument form with `{ headers }` is the Bun/undici extension; the
|
|
23
|
+
// standard constructor stays in use when there is nothing to send.
|
|
24
|
+
this.ws = this.headers
|
|
25
|
+
? new WebSocket(wsUrl, { headers: this.headers })
|
|
26
|
+
: new WebSocket(wsUrl);
|
|
15
27
|
this.ws.onopen = () => {
|
|
16
28
|
this.reconnectAttempts = 0;
|
|
17
29
|
// Re-subscribe to all existing collections using the server's expected protocol
|
|
@@ -55,6 +67,7 @@ export class ZveltioRealtime {
|
|
|
55
67
|
this.reconnectAttempts++;
|
|
56
68
|
this.reconnectTimer = setTimeout(() => this.connect(), delay);
|
|
57
69
|
}
|
|
70
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
58
71
|
subscribe(collection, callback) {
|
|
59
72
|
if (!this.listeners.has(collection))
|
|
60
73
|
this.listeners.set(collection, new Set());
|
package/dist/rpc/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rpc/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5E;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rpc/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5E;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED;;;;;;GAMG;AAGH,wBAAgB,eAAe,CAAC,CAAC,SAAS,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAC3D,IAAI,EAAE,gBAAgB,GACrB,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAqB1B;AAID,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/rpc/index.js
CHANGED
|
@@ -38,9 +38,11 @@ import { hc } from 'hono/client';
|
|
|
38
38
|
* `ZveltioApi` from `@zveltio/engine/api-types`. For an
|
|
39
39
|
* extension's own routes, pass `typeof yourApp`.
|
|
40
40
|
*/
|
|
41
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
41
42
|
export function createRpcClient(opts) {
|
|
42
43
|
const baseUrl = opts.baseUrl.replace(/\/$/, '');
|
|
43
44
|
const includeCredentials = opts.includeCredentials !== false;
|
|
45
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
44
46
|
const customFetch = (async (input, init) => {
|
|
45
47
|
const dynHeaders = opts.getHeaders ? await opts.getHeaders() : {};
|
|
46
48
|
const merged = new Headers(init?.headers ?? {});
|
package/dist/schema-codegen.d.ts
CHANGED
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* column names in editors and `tsc` catches typos.
|
|
9
9
|
*
|
|
10
10
|
* Scope intentionally narrow:
|
|
11
|
-
* -
|
|
11
|
+
* - Reads only the UP half of each file (everything before `-- DOWN`).
|
|
12
|
+
* - Handles `CREATE TABLE [IF NOT EXISTS]`, `ALTER TABLE … ADD COLUMN`
|
|
13
|
+
* and `ALTER TABLE … DROP COLUMN`.
|
|
12
14
|
* - Maps the common Postgres types we see in extension migrations to TS.
|
|
13
15
|
* - Ignores constraint-only ALTER TABLE statements (PRIMARY KEY, FK).
|
|
14
16
|
* - Ignores CREATE INDEX, CREATE TYPE, CREATE FUNCTION, etc.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-codegen.d.ts","sourceRoot":"","sources":["../src/schema-codegen.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"schema-codegen.d.ts","sourceRoot":"","sources":["../src/schema-codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAoND;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA+BtD;AA6BD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,YAAY,CAoE7D;AAID,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,GAAE,cAAmB,GAAG,MAAM,CA0BtF"}
|
package/dist/schema-codegen.js
CHANGED
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* column names in editors and `tsc` catches typos.
|
|
9
9
|
*
|
|
10
10
|
* Scope intentionally narrow:
|
|
11
|
-
* -
|
|
11
|
+
* - Reads only the UP half of each file (everything before `-- DOWN`).
|
|
12
|
+
* - Handles `CREATE TABLE [IF NOT EXISTS]`, `ALTER TABLE … ADD COLUMN`
|
|
13
|
+
* and `ALTER TABLE … DROP COLUMN`.
|
|
12
14
|
* - Maps the common Postgres types we see in extension migrations to TS.
|
|
13
15
|
* - Ignores constraint-only ALTER TABLE statements (PRIMARY KEY, FK).
|
|
14
16
|
* - Ignores CREATE INDEX, CREATE TYPE, CREATE FUNCTION, etc.
|
|
@@ -90,6 +92,19 @@ function mapPgTypeToTs(pgType) {
|
|
|
90
92
|
return isArray ? `${tsBase}[]` : tsBase;
|
|
91
93
|
}
|
|
92
94
|
// ─── SQL parsing ───────────────────────────────────────────────────────────
|
|
95
|
+
/**
|
|
96
|
+
* Keep only the UP half of a migration file. Extension migrations carry their
|
|
97
|
+
* rollback in the same file, after a line that is exactly `-- DOWN`; the
|
|
98
|
+
* engine's runner (`parseMigrationSql`) splits on that marker and only ever
|
|
99
|
+
* executes the UP half. Codegen read both halves, so a `DROP TABLE` /
|
|
100
|
+
* `ADD COLUMN` written for rollback described the generated types as much as
|
|
101
|
+
* the real schema did. Same anchored regex as the runner — a loose `-- DOWN`
|
|
102
|
+
* prefix match once cost the engine half a schema.
|
|
103
|
+
*/
|
|
104
|
+
function upSection(sql) {
|
|
105
|
+
const i = sql.search(/^--\s*DOWN\s*$/im);
|
|
106
|
+
return i < 0 ? sql : sql.slice(0, i);
|
|
107
|
+
}
|
|
93
108
|
/**
|
|
94
109
|
* Strip line comments (`-- …`) and block comments (`/* … * /`) so they don't
|
|
95
110
|
* confuse the table/column regexes. Dollar-quoted blocks are preserved
|
|
@@ -301,13 +316,18 @@ export function parseSchema(sqlChunks) {
|
|
|
301
316
|
}
|
|
302
317
|
return tables.get(name);
|
|
303
318
|
};
|
|
304
|
-
const allSql = sqlChunks.map(stripComments).join('\n');
|
|
319
|
+
const allSql = sqlChunks.map(upSection).map(stripComments).join('\n');
|
|
305
320
|
// CREATE TABLE [IF NOT EXISTS] <name> ( <body> )
|
|
306
321
|
const createRe = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:"([^"]+)"|([a-zA-Z_][a-zA-Z0-9_]*))\s*\(/gi;
|
|
307
|
-
|
|
308
|
-
while ((m = createRe.exec(allSql)) !== null) {
|
|
322
|
+
for (const m of allSql.matchAll(createRe)) {
|
|
309
323
|
const tableName = m[1] ?? m[2];
|
|
310
|
-
|
|
324
|
+
// From the MATCH, not from the regex's `lastIndex`.
|
|
325
|
+
//
|
|
326
|
+
// `matchAll` clones the regex internally, so `createRe.lastIndex` stays 0
|
|
327
|
+
// here — it is only advanced by `exec`. Converting this loop from
|
|
328
|
+
// `while ((m = createRe.exec(...)))` and keeping `lastIndex` silently made
|
|
329
|
+
// every table body start at the top of the file; five tests caught it.
|
|
330
|
+
const openIdx = m.index + m[0].length - 1; // position of '('
|
|
311
331
|
const closeIdx = findMatchingParen(allSql, openIdx);
|
|
312
332
|
if (closeIdx < 0)
|
|
313
333
|
continue; // unbalanced — skip
|
|
@@ -316,11 +336,10 @@ export function parseSchema(sqlChunks) {
|
|
|
316
336
|
const tableCols = ensureTable(tableName);
|
|
317
337
|
for (const c of columns)
|
|
318
338
|
tableCols.set(c.name, c);
|
|
319
|
-
createRe.lastIndex = closeIdx + 1;
|
|
320
339
|
}
|
|
321
340
|
// ALTER TABLE <name> ADD COLUMN [IF NOT EXISTS] <col> <type> <rest>
|
|
322
341
|
const alterRe = /ALTER\s+TABLE\s+(?:"([^"]+)"|([a-zA-Z_][a-zA-Z0-9_]*))\s+ADD\s+COLUMN\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:"([^"]+)"|([a-zA-Z_][a-zA-Z0-9_]*))\s+([^;]+?)(?=;|$)/gi;
|
|
323
|
-
|
|
342
|
+
for (const m of allSql.matchAll(alterRe)) {
|
|
324
343
|
const tableName = m[1] ?? m[2];
|
|
325
344
|
const colName = m[3] ?? m[4];
|
|
326
345
|
const tail = m[5];
|
|
@@ -330,6 +349,21 @@ export function parseSchema(sqlChunks) {
|
|
|
330
349
|
tableCols.set(col.name, col);
|
|
331
350
|
}
|
|
332
351
|
}
|
|
352
|
+
// ALTER TABLE <name> DROP COLUMN [IF EXISTS] <col>
|
|
353
|
+
//
|
|
354
|
+
// Run last, after every CREATE and ADD COLUMN: a column the migrations
|
|
355
|
+
// removed used to stay in the generated types, so `ctx.db` promised a
|
|
356
|
+
// column Postgres no longer has — the silent runtime failure this module
|
|
357
|
+
// exists to prevent.
|
|
358
|
+
//
|
|
359
|
+
// ponytail: a third pass, not an ordered walk of the statements. A column
|
|
360
|
+
// dropped and then re-added by a later migration would be lost; no
|
|
361
|
+
// extension does that today. Make the parser statement-ordered if one does.
|
|
362
|
+
const dropRe = /ALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?(?:"([^"]+)"|([a-zA-Z_][a-zA-Z0-9_]*))\s+DROP\s+COLUMN\s+(?:IF\s+EXISTS\s+)?(?:"([^"]+)"|([a-zA-Z_][a-zA-Z0-9_]*))/gi;
|
|
363
|
+
for (const m of allSql.matchAll(dropRe)) {
|
|
364
|
+
// Never `ensureTable` here — a DROP alone must not invent a table.
|
|
365
|
+
tables.get(m[1] ?? m[2])?.delete(m[3] ?? m[4]);
|
|
366
|
+
}
|
|
333
367
|
return {
|
|
334
368
|
tables: order.map((name) => ({ name, columns: [...tables.get(name).values()] })),
|
|
335
369
|
};
|
package/dist/schema-watcher.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* updated, or deleted.
|
|
7
7
|
*
|
|
8
8
|
* Usage (in `zveltio dev --watch`):
|
|
9
|
-
* import { watchSchema } from '@zveltio/sdk
|
|
9
|
+
* import { watchSchema } from '@zveltio/sdk';
|
|
10
10
|
* await watchSchema('http://localhost:3000', './src/zveltio-types.d.ts');
|
|
11
11
|
*/
|
|
12
12
|
export interface CollectionField {
|
package/dist/schema-watcher.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* updated, or deleted.
|
|
7
7
|
*
|
|
8
8
|
* Usage (in `zveltio dev --watch`):
|
|
9
|
-
* import { watchSchema } from '@zveltio/sdk
|
|
9
|
+
* import { watchSchema } from '@zveltio/sdk';
|
|
10
10
|
* await watchSchema('http://localhost:3000', './src/zveltio-types.d.ts');
|
|
11
11
|
*/
|
|
12
12
|
const TYPE_MAP = {
|
package/dist/studio/index.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ export declare function applyFormAlterHooks(hooks: FormAlterHook[], schema: Form
|
|
|
35
35
|
export declare function sortSlotContributions<T extends {
|
|
36
36
|
priority?: number;
|
|
37
37
|
}>(items: T[]): T[];
|
|
38
|
+
export { removeOwnerFromSlots, registerOwnedOnSlot, type OwnedSlotContribution, } from './slot-owner-registry.js';
|
|
38
39
|
/** Register a top-level Studio page contributed by this extension. */
|
|
39
40
|
export declare function registerRoute(route: StudioRoute): void;
|
|
40
41
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/studio/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,UAAU,EAEV,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAE/B,UAAU,SAAU,SAAQ,YAAY;IACtC,qDAAqD;IACrD,MAAM,IAAI,UAAU,CAAC;CACtB;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,CAoE5D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,aAAa,EAAE,EACtB,MAAM,EAAE,UAAU,EAClB,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAChC,UAAU,CAWZ;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAGtF;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/studio/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,UAAU,EAEV,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAE/B,UAAU,SAAU,SAAQ,YAAY;IACtC,qDAAqD;IACrD,MAAM,IAAI,UAAU,CAAC;CACtB;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,CAoE5D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,aAAa,EAAE,EACtB,MAAM,EAAE,UAAU,EAClB,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAChC,UAAU,CAWZ;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAGtF;AAED,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,qBAAqB,GAC3B,MAAM,0BAA0B,CAAC;AAqClC,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAEtD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAE/E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAE3E;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,eAAe,GAAG,IAAI,CAE3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAEvE;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,IAAI,MAAM,CAIrC;AAID,YAAY,EACV,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,UAAU,EACV,SAAS,GACV,MAAM,uBAAuB,CAAC"}
|
package/dist/studio/index.js
CHANGED
|
@@ -109,9 +109,11 @@ export function sortSlotContributions(items) {
|
|
|
109
109
|
// We rely on Array.prototype.sort being stable (TC39 since 2019).
|
|
110
110
|
return items.slice().sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
|
|
111
111
|
}
|
|
112
|
+
export { removeOwnerFromSlots, registerOwnedOnSlot, } from './slot-owner-registry.js';
|
|
112
113
|
function getStudioGlobal() {
|
|
113
114
|
if (typeof window === 'undefined')
|
|
114
115
|
return null;
|
|
116
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
115
117
|
const g = window.__zveltio;
|
|
116
118
|
if (!g) {
|
|
117
119
|
console.warn('[zveltio/sdk/studio] window.__zveltio is not installed. Is the bundle running inside Studio?');
|
|
@@ -176,5 +178,6 @@ export function registerAssetPreview(handler) {
|
|
|
176
178
|
export function getEngineUrl() {
|
|
177
179
|
if (typeof window === 'undefined')
|
|
178
180
|
return '';
|
|
181
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
179
182
|
return window.__ZVELTIO_ENGINE_URL__ || getStudioGlobal()?.engineUrl || '';
|
|
180
183
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SlotContribution } from '../extension/index.js';
|
|
2
|
+
/** Owner tag set by compile-time `contribute.ts` modules; absent on legacy window.__zveltio calls. */
|
|
3
|
+
export type OwnedSlotContribution = SlotContribution & {
|
|
4
|
+
owner?: string;
|
|
5
|
+
};
|
|
6
|
+
/** Remove every contribution registered by `owner` across all slot names. */
|
|
7
|
+
export declare function removeOwnerFromSlots(slots: Record<string, OwnedSlotContribution[]>, owner: string): Record<string, OwnedSlotContribution[]>;
|
|
8
|
+
/**
|
|
9
|
+
* Register (or replace) a single owner's contribution on one slot.
|
|
10
|
+
* Prior entries from the same owner on that slot are dropped first.
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerOwnedOnSlot(slots: Record<string, OwnedSlotContribution[]>, owner: string, slotName: string, contribution: SlotContribution): Record<string, OwnedSlotContribution[]>;
|
|
13
|
+
//# sourceMappingURL=slot-owner-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-owner-registry.d.ts","sourceRoot":"","sources":["../../src/studio/slot-owner-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,sGAAsG;AACtG,MAAM,MAAM,qBAAqB,GAAG,gBAAgB,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1E,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,EAAE,CAAC,EAC9C,KAAK,EAAE,MAAM,GACZ,MAAM,CAAC,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAOzC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,EAAE,CAAC,EAC9C,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,gBAAgB,GAC7B,MAAM,CAAC,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAMzC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Remove every contribution registered by `owner` across all slot names. */
|
|
2
|
+
export function removeOwnerFromSlots(slots, owner) {
|
|
3
|
+
const out = {};
|
|
4
|
+
for (const [name, list] of Object.entries(slots)) {
|
|
5
|
+
const kept = list.filter((c) => c.owner !== owner);
|
|
6
|
+
if (kept.length > 0)
|
|
7
|
+
out[name] = kept;
|
|
8
|
+
}
|
|
9
|
+
return out;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Register (or replace) a single owner's contribution on one slot.
|
|
13
|
+
* Prior entries from the same owner on that slot are dropped first.
|
|
14
|
+
*/
|
|
15
|
+
export function registerOwnedOnSlot(slots, owner, slotName, contribution) {
|
|
16
|
+
const out = { ...slots };
|
|
17
|
+
const prev = out[slotName] ?? [];
|
|
18
|
+
const kept = prev.filter((c) => c.owner !== owner);
|
|
19
|
+
out[slotName] = [...kept, { ...contribution, owner }];
|
|
20
|
+
return out;
|
|
21
|
+
}
|
package/dist/svelte.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* ```svelte
|
|
7
7
|
* <script lang="ts">
|
|
8
8
|
* import { SyncManager } from '@zveltio/sdk';
|
|
9
|
-
* import { useSyncCollection, useSyncStatus } from '@zveltio/sdk
|
|
9
|
+
* import { useSyncCollection, useSyncStatus } from '@zveltio/sdk';
|
|
10
10
|
*
|
|
11
11
|
* let todos = $state<any[]>([]);
|
|
12
12
|
* const unsub = useSyncCollection(sync, 'todos', (records) => { todos = records; });
|
package/dist/svelte.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"svelte.d.ts","sourceRoot":"","sources":["../src/svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"svelte.d.ts","sourceRoot":"","sources":["../src/svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,MAAM,EAElB,MAAM,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,IAAI,GAC/B,MAAM,IAAI,CAGZ;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,KAAK,IAAI,EACnF,UAAU,SAAO,GAChB,MAAM,IAAI,CAeZ"}
|
package/dist/svelte.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* ```svelte
|
|
7
7
|
* <script lang="ts">
|
|
8
8
|
* import { SyncManager } from '@zveltio/sdk';
|
|
9
|
-
* import { useSyncCollection, useSyncStatus } from '@zveltio/sdk
|
|
9
|
+
* import { useSyncCollection, useSyncStatus } from '@zveltio/sdk';
|
|
10
10
|
*
|
|
11
11
|
* let todos = $state<any[]>([]);
|
|
12
12
|
* const unsub = useSyncCollection(sync, 'todos', (records) => { todos = records; });
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
* Calls `setter` immediately with current state and on each update.
|
|
24
24
|
* Returns the unsubscribe function.
|
|
25
25
|
*/
|
|
26
|
-
export function useSyncCollection(sync, collection,
|
|
26
|
+
export function useSyncCollection(sync, collection,
|
|
27
|
+
// biome-ignore lint/suspicious/noExplicitAny: legacy any; tracked in hardening plan item H-01
|
|
28
|
+
setter) {
|
|
27
29
|
const col = sync.collection(collection);
|
|
28
30
|
return col.subscribe(setter);
|
|
29
31
|
}
|