js-bao 0.5.1 → 0.6.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/README.md +128 -30
- package/dist/browser.cjs +4759 -719
- package/dist/browser.d.cts +2290 -50
- package/dist/browser.d.ts +2290 -50
- package/dist/browser.js +4766 -722
- package/dist/client.cjs +383 -6
- package/dist/client.d.cts +810 -12
- package/dist/client.d.ts +810 -12
- package/dist/client.js +378 -4
- package/dist/cloudflare-do.cjs +1307 -219
- package/dist/cloudflare-do.d.cts +1195 -13
- package/dist/cloudflare-do.d.ts +1195 -13
- package/dist/cloudflare-do.js +1303 -217
- package/dist/cloudflare.cjs +619 -23
- package/dist/cloudflare.d.cts +1026 -13
- package/dist/cloudflare.d.ts +1026 -13
- package/dist/cloudflare.js +614 -21
- package/dist/codegen-v2.cjs +393 -19
- package/dist/codegen.cjs +2 -1
- package/dist/index.cjs +4830 -679
- package/dist/index.d.cts +2343 -52
- package/dist/index.d.ts +2343 -52
- package/dist/index.js +4746 -650
- package/dist/node.cjs +5016 -724
- package/dist/node.d.cts +2458 -58
- package/dist/node.d.ts +2458 -58
- package/dist/node.js +4906 -676
- package/package.json +2 -1
package/dist/codegen-v2.cjs
CHANGED
|
@@ -89,37 +89,391 @@ var init_yjsValues = __esm({
|
|
|
89
89
|
}
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
+
// src/models/writeLifecycle.ts
|
|
93
|
+
function registerFunctionDefaultGenerator(name, fn) {
|
|
94
|
+
FUNCTION_DEFAULT_GENERATORS.set(name, fn);
|
|
95
|
+
}
|
|
96
|
+
var Y2, import_ulid, KNOWN_FIELD_TYPE_MAP, KNOWN_FIELD_TYPES, FUNCTION_DEFAULT_GENERATORS;
|
|
97
|
+
var init_writeLifecycle = __esm({
|
|
98
|
+
"src/models/writeLifecycle.ts"() {
|
|
99
|
+
"use strict";
|
|
100
|
+
Y2 = __toESM(require("yjs"), 1);
|
|
101
|
+
import_ulid = require("ulid");
|
|
102
|
+
KNOWN_FIELD_TYPE_MAP = {
|
|
103
|
+
string: true,
|
|
104
|
+
number: true,
|
|
105
|
+
boolean: true,
|
|
106
|
+
date: true,
|
|
107
|
+
id: true,
|
|
108
|
+
stringset: true
|
|
109
|
+
};
|
|
110
|
+
KNOWN_FIELD_TYPES = new Set(Object.keys(KNOWN_FIELD_TYPE_MAP));
|
|
111
|
+
FUNCTION_DEFAULT_GENERATORS = /* @__PURE__ */ new Map();
|
|
112
|
+
registerFunctionDefaultGenerator("generate_ulid", () => (0, import_ulid.ulid)());
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
92
116
|
// src/models/metaSync.ts
|
|
93
117
|
function registerFunctionDefault(fn, name) {
|
|
94
118
|
KNOWN_FUNCTION_DEFAULTS.set(fn, name);
|
|
95
119
|
}
|
|
96
|
-
var
|
|
120
|
+
var Y3, KNOWN_FUNCTION_DEFAULTS;
|
|
97
121
|
var init_metaSync = __esm({
|
|
98
122
|
"src/models/metaSync.ts"() {
|
|
99
123
|
"use strict";
|
|
100
|
-
|
|
124
|
+
Y3 = __toESM(require("yjs"), 1);
|
|
101
125
|
init_yjsValues();
|
|
126
|
+
init_writeLifecycle();
|
|
102
127
|
KNOWN_FUNCTION_DEFAULTS = /* @__PURE__ */ new WeakMap();
|
|
103
128
|
}
|
|
104
129
|
});
|
|
105
130
|
|
|
131
|
+
// src/utils/uniqueIndex.ts
|
|
132
|
+
function fieldUniqueConstraintName(modelName, fieldName) {
|
|
133
|
+
return `${modelName}_${fieldName}_unique`;
|
|
134
|
+
}
|
|
135
|
+
var Y4;
|
|
136
|
+
var init_uniqueIndex = __esm({
|
|
137
|
+
"src/utils/uniqueIndex.ts"() {
|
|
138
|
+
"use strict";
|
|
139
|
+
Y4 = __toESM(require("yjs"), 1);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// src/utils/largeDocuments.ts
|
|
144
|
+
var Y5;
|
|
145
|
+
var init_largeDocuments = __esm({
|
|
146
|
+
"src/utils/largeDocuments.ts"() {
|
|
147
|
+
"use strict";
|
|
148
|
+
Y5 = __toESM(require("yjs"), 1);
|
|
149
|
+
init_yjsValues();
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// src/models/OrmContext.ts
|
|
154
|
+
var OrmContext, defaultOrmContext, liveOrmContexts;
|
|
155
|
+
var init_OrmContext = __esm({
|
|
156
|
+
"src/models/OrmContext.ts"() {
|
|
157
|
+
"use strict";
|
|
158
|
+
OrmContext = class _OrmContext {
|
|
159
|
+
/** Declared before the field that reads it: static initialization is ordered. */
|
|
160
|
+
static instanceCounter = 0;
|
|
161
|
+
/**
|
|
162
|
+
* Which instance this is, for diagnostics. A process holding several clients
|
|
163
|
+
* needs a way to say WHICH one a warning is about, so every context takes the
|
|
164
|
+
* next number as it is created and keeps it for its lifetime.
|
|
165
|
+
*/
|
|
166
|
+
instanceId = ++_OrmContext.instanceCounter;
|
|
167
|
+
/** The engine this instance's models read and write through. */
|
|
168
|
+
dbEngine = null;
|
|
169
|
+
connectedDocuments = /* @__PURE__ */ new Map();
|
|
170
|
+
/** `docId_modelName` → the Y.Map that document holds for that model. */
|
|
171
|
+
documentYMaps = /* @__PURE__ */ new Map();
|
|
172
|
+
/** `subscribe()` callbacks, by model name. */
|
|
173
|
+
listenersMap = /* @__PURE__ */ new Map();
|
|
174
|
+
// Default-document resolution
|
|
175
|
+
modelNameToDefaultDocId = /* @__PURE__ */ new Map();
|
|
176
|
+
globalDefaultDocId = void 0;
|
|
177
|
+
defaultDocChangedListeners = /* @__PURE__ */ new Set();
|
|
178
|
+
modelDocMappingChangedListeners = /* @__PURE__ */ new Set();
|
|
179
|
+
/** Format-2 ("large document", #2816) record stores by document id. */
|
|
180
|
+
format2Documents = /* @__PURE__ */ new Map();
|
|
181
|
+
/** Format-2 epoch moves in flight (#2816). */
|
|
182
|
+
format2Transitions = /* @__PURE__ */ new Map();
|
|
183
|
+
/**
|
|
184
|
+
* Nested-Y.Map stringset fields this context has already observed. Per
|
|
185
|
+
* context, not global: a Y.Doc reconnected to a fresh instance has to be
|
|
186
|
+
* observed again by that instance, and a global guard would silently
|
|
187
|
+
* suppress it.
|
|
188
|
+
*/
|
|
189
|
+
observedStringSetMaps = /* @__PURE__ */ new WeakSet();
|
|
190
|
+
/**
|
|
191
|
+
* The registry this instance's schema lookups use. `null` on the standing
|
|
192
|
+
* default context, where callers fall back to the global singleton.
|
|
193
|
+
*/
|
|
194
|
+
modelRegistry = null;
|
|
195
|
+
/** Model classes routed to this context. */
|
|
196
|
+
boundModels = /* @__PURE__ */ new Set();
|
|
197
|
+
/** True once {@link destroy} has run; bound classes keep pointing here. */
|
|
198
|
+
destroyed = false;
|
|
199
|
+
/** Yjs `unobserve` thunks by owning document id. */
|
|
200
|
+
observerDisposers = /* @__PURE__ */ new Map();
|
|
201
|
+
/** Teardown the owner (the document manager) registers for `destroy()`. */
|
|
202
|
+
teardownHooks = /* @__PURE__ */ new Set();
|
|
203
|
+
static NO_DOCUMENT_KEY = "__no_document__";
|
|
204
|
+
/**
|
|
205
|
+
* Record how to remove an observer this context installed. Every `observe()`
|
|
206
|
+
* in the ORM pairs with one of these: without it a torn-down instance's
|
|
207
|
+
* callbacks keep firing on a Y.Doc that outlives it.
|
|
208
|
+
*/
|
|
209
|
+
registerObserverDisposer(docId, dispose) {
|
|
210
|
+
const key = docId ?? _OrmContext.NO_DOCUMENT_KEY;
|
|
211
|
+
const list = this.observerDisposers.get(key);
|
|
212
|
+
if (list) list.push(dispose);
|
|
213
|
+
else this.observerDisposers.set(key, [dispose]);
|
|
214
|
+
}
|
|
215
|
+
/** Remove every observer this context installed for `docId`. */
|
|
216
|
+
disposeObserversForDocument(docId) {
|
|
217
|
+
const list = this.observerDisposers.get(docId);
|
|
218
|
+
if (!list) return;
|
|
219
|
+
this.observerDisposers.delete(docId);
|
|
220
|
+
for (const dispose of list) {
|
|
221
|
+
try {
|
|
222
|
+
dispose();
|
|
223
|
+
} catch {
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
disposeAllObservers() {
|
|
228
|
+
const buckets = Array.from(this.observerDisposers.values());
|
|
229
|
+
this.observerDisposers.clear();
|
|
230
|
+
for (const list of buckets) {
|
|
231
|
+
for (const dispose of list) {
|
|
232
|
+
try {
|
|
233
|
+
dispose();
|
|
234
|
+
} catch {
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/** Run `hook` as part of `destroy()` (the format-2 binding registers here). */
|
|
240
|
+
onDestroy(hook) {
|
|
241
|
+
this.teardownHooks.add(hook);
|
|
242
|
+
}
|
|
243
|
+
/** The record store for `docId`, or `null` when the document is format 1. */
|
|
244
|
+
getFormat2Store(docId) {
|
|
245
|
+
if (!docId) return null;
|
|
246
|
+
return this.format2Documents.get(docId) ?? null;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* The epoch move a write to `docId` has to wait out (#2816, behavior 10), or
|
|
250
|
+
* `null` when none is in flight.
|
|
251
|
+
*/
|
|
252
|
+
format2WritesHeld(docId) {
|
|
253
|
+
if (!docId) return null;
|
|
254
|
+
return this.format2Transitions.get(docId) ?? null;
|
|
255
|
+
}
|
|
256
|
+
/** Run an epoch move with `docId`'s local writes held back (#2816). */
|
|
257
|
+
async holdFormat2Writes(docId, run) {
|
|
258
|
+
const inFlight = this.format2Transitions.get(docId);
|
|
259
|
+
if (inFlight) await inFlight.catch(() => {
|
|
260
|
+
});
|
|
261
|
+
let release;
|
|
262
|
+
const held = new Promise((resolve4) => {
|
|
263
|
+
release = resolve4;
|
|
264
|
+
});
|
|
265
|
+
this.format2Transitions.set(docId, held);
|
|
266
|
+
try {
|
|
267
|
+
return await run();
|
|
268
|
+
} finally {
|
|
269
|
+
if (this.format2Transitions.get(docId) === held) {
|
|
270
|
+
this.format2Transitions.delete(docId);
|
|
271
|
+
}
|
|
272
|
+
release();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/** Notify `subscribe()` callbacks registered on this context for `modelName`. */
|
|
276
|
+
notifyListeners(modelName, log, onError) {
|
|
277
|
+
const listeners = this.listenersMap.get(modelName);
|
|
278
|
+
if (!listeners) return;
|
|
279
|
+
log?.(`Notifying ${listeners.size} listeners for ${modelName}`);
|
|
280
|
+
listeners.forEach((callback) => {
|
|
281
|
+
try {
|
|
282
|
+
callback();
|
|
283
|
+
} catch (e) {
|
|
284
|
+
onError?.(e);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
// ---- Default-document resolution (the `BaseModel` statics delegate here) ----
|
|
289
|
+
setModelDefaultDocumentId(modelName, docId) {
|
|
290
|
+
const previous = this.modelNameToDefaultDocId.get(modelName);
|
|
291
|
+
this.modelNameToDefaultDocId.set(modelName, docId);
|
|
292
|
+
this.announceModelDocMapping(modelName, previous, docId);
|
|
293
|
+
}
|
|
294
|
+
removeModelDefaultDocumentId(modelName) {
|
|
295
|
+
const previous = this.modelNameToDefaultDocId.get(modelName);
|
|
296
|
+
this.modelNameToDefaultDocId.delete(modelName);
|
|
297
|
+
this.announceModelDocMapping(modelName, previous, void 0);
|
|
298
|
+
}
|
|
299
|
+
clearModelDefaultDocumentIds() {
|
|
300
|
+
const entries = Array.from(this.modelNameToDefaultDocId.entries());
|
|
301
|
+
this.modelNameToDefaultDocId.clear();
|
|
302
|
+
for (const [modelName, previous] of entries) {
|
|
303
|
+
this.announceModelDocMapping(modelName, previous, void 0);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
setGlobalDefaultDocumentId(docId) {
|
|
307
|
+
const previous = this.globalDefaultDocId;
|
|
308
|
+
this.globalDefaultDocId = docId;
|
|
309
|
+
this.announceDefaultDoc(previous, docId);
|
|
310
|
+
}
|
|
311
|
+
clearGlobalDefaultDocumentId() {
|
|
312
|
+
const previous = this.globalDefaultDocId;
|
|
313
|
+
this.globalDefaultDocId = void 0;
|
|
314
|
+
this.announceDefaultDoc(previous, void 0);
|
|
315
|
+
}
|
|
316
|
+
getModelDefaultDocumentMapping() {
|
|
317
|
+
return Object.fromEntries(this.modelNameToDefaultDocId.entries());
|
|
318
|
+
}
|
|
319
|
+
getDocumentIdForModel(modelName) {
|
|
320
|
+
return this.modelNameToDefaultDocId.get(modelName);
|
|
321
|
+
}
|
|
322
|
+
getGlobalDefaultDocumentId() {
|
|
323
|
+
return this.globalDefaultDocId;
|
|
324
|
+
}
|
|
325
|
+
onDefaultDocChanged(listener) {
|
|
326
|
+
this.defaultDocChangedListeners.add(listener);
|
|
327
|
+
return () => this.defaultDocChangedListeners.delete(listener);
|
|
328
|
+
}
|
|
329
|
+
onModelDocMappingChanged(listener) {
|
|
330
|
+
this.modelDocMappingChangedListeners.add(listener);
|
|
331
|
+
return () => this.modelDocMappingChangedListeners.delete(listener);
|
|
332
|
+
}
|
|
333
|
+
/** Drop the model→document defaults that point at a disconnected document. */
|
|
334
|
+
clearMappingsForDocId(docId) {
|
|
335
|
+
const toRemove = [];
|
|
336
|
+
for (const [modelName, mappedDocId] of this.modelNameToDefaultDocId) {
|
|
337
|
+
if (mappedDocId === docId) toRemove.push(modelName);
|
|
338
|
+
}
|
|
339
|
+
for (const modelName of toRemove) {
|
|
340
|
+
this.removeModelDefaultDocumentId(modelName);
|
|
341
|
+
}
|
|
342
|
+
if (this.globalDefaultDocId === docId) {
|
|
343
|
+
this.clearGlobalDefaultDocumentId();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
announceDefaultDoc(previous, current) {
|
|
347
|
+
for (const listener of this.defaultDocChangedListeners) {
|
|
348
|
+
try {
|
|
349
|
+
listener({ previous, current });
|
|
350
|
+
} catch {
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
announceModelDocMapping(modelName, previous, current) {
|
|
355
|
+
for (const listener of this.modelDocMappingChangedListeners) {
|
|
356
|
+
try {
|
|
357
|
+
listener({ modelName, previous, current });
|
|
358
|
+
} catch {
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Tear this instance down: observers off, engine destroyed, state cleared.
|
|
364
|
+
*
|
|
365
|
+
* Deliberately does NOT unbind its model classes. They keep resolving this
|
|
366
|
+
* context, whose engine is now null, so an operation through them throws the
|
|
367
|
+
* ordinary not-initialized error instead of silently landing on whatever
|
|
368
|
+
* other instance happens to be live (#3039, behavior 7). Only a later
|
|
369
|
+
* `initJsBao` may rebind a class whose context is destroyed.
|
|
370
|
+
*/
|
|
371
|
+
async destroy() {
|
|
372
|
+
if (this.destroyed) return;
|
|
373
|
+
this.destroyed = true;
|
|
374
|
+
this.disposeAllObservers();
|
|
375
|
+
const hooks = Array.from(this.teardownHooks);
|
|
376
|
+
this.teardownHooks.clear();
|
|
377
|
+
for (const hook of hooks) {
|
|
378
|
+
try {
|
|
379
|
+
await hook();
|
|
380
|
+
} catch {
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
const engine = this.dbEngine;
|
|
384
|
+
this.dbEngine = null;
|
|
385
|
+
if (engine) {
|
|
386
|
+
try {
|
|
387
|
+
await engine.destroy();
|
|
388
|
+
} catch {
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
this.connectedDocuments.clear();
|
|
392
|
+
this.documentYMaps.clear();
|
|
393
|
+
this.listenersMap.clear();
|
|
394
|
+
this.modelNameToDefaultDocId.clear();
|
|
395
|
+
this.globalDefaultDocId = void 0;
|
|
396
|
+
this.defaultDocChangedListeners.clear();
|
|
397
|
+
this.modelDocMappingChangedListeners.clear();
|
|
398
|
+
this.format2Documents.clear();
|
|
399
|
+
this.format2Transitions.clear();
|
|
400
|
+
this.observedStringSetMaps = /* @__PURE__ */ new WeakSet();
|
|
401
|
+
liveOrmContexts.delete(this);
|
|
402
|
+
if (defaultOrmContext === this) {
|
|
403
|
+
defaultOrmContext = new _OrmContext();
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
defaultOrmContext = new OrmContext();
|
|
408
|
+
liveOrmContexts = /* @__PURE__ */ new Set();
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// src/models/format2QueryProjection.ts
|
|
413
|
+
var FORMAT2_QUERY_PROJECTION_DDL;
|
|
414
|
+
var init_format2QueryProjection = __esm({
|
|
415
|
+
"src/models/format2QueryProjection.ts"() {
|
|
416
|
+
"use strict";
|
|
417
|
+
FORMAT2_QUERY_PROJECTION_DDL = `
|
|
418
|
+
CREATE TABLE IF NOT EXISTS _query_projection (
|
|
419
|
+
doc_id TEXT NOT NULL,
|
|
420
|
+
model TEXT NOT NULL,
|
|
421
|
+
PRIMARY KEY (doc_id, model)
|
|
422
|
+
)`.trim();
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
// src/models/format2Observer.ts
|
|
427
|
+
var Y6;
|
|
428
|
+
var init_format2Observer = __esm({
|
|
429
|
+
"src/models/format2Observer.ts"() {
|
|
430
|
+
"use strict";
|
|
431
|
+
Y6 = __toESM(require("yjs"), 1);
|
|
432
|
+
init_largeDocuments();
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// src/models/format2ClientWrite.ts
|
|
437
|
+
var init_format2ClientWrite = __esm({
|
|
438
|
+
"src/models/format2ClientWrite.ts"() {
|
|
439
|
+
"use strict";
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
// src/models/format2OfflineWindow.ts
|
|
444
|
+
var DAY_MS;
|
|
445
|
+
var init_format2OfflineWindow = __esm({
|
|
446
|
+
"src/models/format2OfflineWindow.ts"() {
|
|
447
|
+
"use strict";
|
|
448
|
+
DAY_MS = 24 * 60 * 60 * 1e3;
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
|
|
106
452
|
// src/models/BaseModel.ts
|
|
107
453
|
function generateULID() {
|
|
108
|
-
return (0,
|
|
454
|
+
return (0, import_ulid2.ulid)();
|
|
109
455
|
}
|
|
110
|
-
var
|
|
456
|
+
var Y7, import_ulid2;
|
|
111
457
|
var init_BaseModel = __esm({
|
|
112
458
|
"src/models/BaseModel.ts"() {
|
|
113
459
|
"use strict";
|
|
114
|
-
|
|
115
|
-
|
|
460
|
+
Y7 = __toESM(require("yjs"), 1);
|
|
461
|
+
import_ulid2 = require("ulid");
|
|
116
462
|
init_StringSet();
|
|
117
463
|
init_documentTypes();
|
|
118
464
|
init_DocumentQueryTranslator();
|
|
119
465
|
init_CursorManager();
|
|
120
466
|
init_sql();
|
|
121
467
|
init_metaSync();
|
|
468
|
+
init_writeLifecycle();
|
|
122
469
|
init_yjsValues();
|
|
470
|
+
init_uniqueIndex();
|
|
471
|
+
init_largeDocuments();
|
|
472
|
+
init_OrmContext();
|
|
473
|
+
init_format2QueryProjection();
|
|
474
|
+
init_format2Observer();
|
|
475
|
+
init_format2ClientWrite();
|
|
476
|
+
init_format2OfflineWindow();
|
|
123
477
|
registerFunctionDefault(generateULID, "generate_ulid");
|
|
124
478
|
}
|
|
125
479
|
});
|
|
@@ -138,6 +492,7 @@ var init_ModelRegistry = __esm({
|
|
|
138
492
|
"use strict";
|
|
139
493
|
init_BaseModel();
|
|
140
494
|
init_relationshipManager();
|
|
495
|
+
init_format2QueryProjection();
|
|
141
496
|
}
|
|
142
497
|
});
|
|
143
498
|
|
|
@@ -155,6 +510,7 @@ var import_smol_toml = require("smol-toml");
|
|
|
155
510
|
// src/models/schema.ts
|
|
156
511
|
init_BaseModel();
|
|
157
512
|
init_ModelRegistry();
|
|
513
|
+
init_uniqueIndex();
|
|
158
514
|
function defineModelSchema(input) {
|
|
159
515
|
const { name, fields } = input;
|
|
160
516
|
const options = {
|
|
@@ -197,7 +553,7 @@ function resolveUniqueConstraints(modelName, fields, customConstraints) {
|
|
|
197
553
|
for (const [fieldName, options] of fields.entries()) {
|
|
198
554
|
if (options.unique) {
|
|
199
555
|
resolved.push({
|
|
200
|
-
name:
|
|
556
|
+
name: fieldUniqueConstraintName(modelName, fieldName),
|
|
201
557
|
fields: [fieldName]
|
|
202
558
|
});
|
|
203
559
|
}
|
|
@@ -616,14 +972,12 @@ function renderModelFile(input) {
|
|
|
616
972
|
lines.push("");
|
|
617
973
|
lines.push(`export class ${className} extends BaseModelImpl {}`);
|
|
618
974
|
lines.push("");
|
|
619
|
-
lines.push(
|
|
620
|
-
`export const ${className}_modelName: "${escapeStringLiteral(modelName)}" = ${JSON.stringify(modelName)};`
|
|
621
|
-
);
|
|
975
|
+
lines.push(`export const ${className}_modelName = ${JSON.stringify(modelName)} as const;`);
|
|
622
976
|
lines.push("");
|
|
623
977
|
return lines.join("\n");
|
|
624
978
|
}
|
|
625
979
|
function renderBarrel(input) {
|
|
626
|
-
const { fingerprint,
|
|
980
|
+
const { fingerprint, tomlImportPath, entries } = input;
|
|
627
981
|
const lines = [];
|
|
628
982
|
lines.push(HEADER_BANNER);
|
|
629
983
|
lines.push(REGEN_INSTRUCTION);
|
|
@@ -644,7 +998,7 @@ function renderBarrel(input) {
|
|
|
644
998
|
lines.push(
|
|
645
999
|
`import { attachAndRegisterModel, loadSchemaFromTomlString } from "js-bao";`
|
|
646
1000
|
);
|
|
647
|
-
lines.push(`import modelsToml from
|
|
1001
|
+
lines.push(`import modelsToml from ${JSON.stringify(`${tomlImportPath}?raw`)};`);
|
|
648
1002
|
for (const { className } of entries) {
|
|
649
1003
|
lines.push(`import { ${className} } from "./${className}.generated";`);
|
|
650
1004
|
}
|
|
@@ -697,11 +1051,18 @@ function renderBarrel(input) {
|
|
|
697
1051
|
lines.push("");
|
|
698
1052
|
return lines.join("\n");
|
|
699
1053
|
}
|
|
700
|
-
function escapeStringLiteral(s) {
|
|
701
|
-
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
702
|
-
}
|
|
703
1054
|
|
|
704
1055
|
// src/cli/v2/generator.ts
|
|
1056
|
+
function computeSchemaImportSpecifier(outputDirAbs, inputTomlAbs, pathImpl = path) {
|
|
1057
|
+
const relative2 = pathImpl.relative(outputDirAbs, inputTomlAbs);
|
|
1058
|
+
if (pathImpl.isAbsolute(relative2)) {
|
|
1059
|
+
throw new Error(
|
|
1060
|
+
`Cannot build a relative import from the output directory ${outputDirAbs} to the schema ${inputTomlAbs} \u2014 they share no common root. Pass --schema-import <specifier> to name the runtime schema path explicitly.`
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
const posix = relative2.split(pathImpl.sep).join("/");
|
|
1064
|
+
return posix.startsWith("./") || posix.startsWith("../") ? posix : `./${posix}`;
|
|
1065
|
+
}
|
|
705
1066
|
var GENERATED_FILE_SUFFIX = ".generated.ts";
|
|
706
1067
|
var BARREL_FILENAME = "index.ts";
|
|
707
1068
|
async function generate(options) {
|
|
@@ -733,7 +1094,7 @@ async function generate(options) {
|
|
|
733
1094
|
modelName: s.name,
|
|
734
1095
|
className: classNamesByModelName[s.name]
|
|
735
1096
|
})).sort((a, b) => a.className.localeCompare(b.className));
|
|
736
|
-
const
|
|
1097
|
+
const tomlImportPath = options.schemaImportPath !== void 0 && options.schemaImportPath.trim() !== "" ? options.schemaImportPath : computeSchemaImportSpecifier(outAbs, inputAbs);
|
|
737
1098
|
const filesToWrite = /* @__PURE__ */ new Map();
|
|
738
1099
|
for (const schema of schemas) {
|
|
739
1100
|
const className = classNamesByModelName[schema.name];
|
|
@@ -755,7 +1116,7 @@ async function generate(options) {
|
|
|
755
1116
|
barrelPath,
|
|
756
1117
|
renderBarrel({
|
|
757
1118
|
fingerprint,
|
|
758
|
-
|
|
1119
|
+
tomlImportPath,
|
|
759
1120
|
entries
|
|
760
1121
|
})
|
|
761
1122
|
);
|
|
@@ -1548,7 +1909,7 @@ var Logger2 = class _Logger {
|
|
|
1548
1909
|
// package.json
|
|
1549
1910
|
var package_default = {
|
|
1550
1911
|
name: "js-bao",
|
|
1551
|
-
version: "0.
|
|
1912
|
+
version: "0.6.0",
|
|
1552
1913
|
description: "A library providing data modeling capabilities which support live updates and queries.",
|
|
1553
1914
|
types: "dist/index.d.ts",
|
|
1554
1915
|
type: "module",
|
|
@@ -1604,6 +1965,7 @@ var package_default = {
|
|
|
1604
1965
|
"jsbao-codegen-v2": "./dist/codegen-v2.cjs"
|
|
1605
1966
|
},
|
|
1606
1967
|
scripts: {
|
|
1968
|
+
typecheck: "tsc --noEmit -p tsconfig.json",
|
|
1607
1969
|
build: "pnpm build:cli && pnpm build:cli-v2 && pnpm codegen && rm -f dist/index.* dist/node.* dist/browser.* dist/cloudflare.* dist/cloudflare-do.* dist/client.* && pnpm build:main",
|
|
1608
1970
|
"build:main": "pnpm build:browser && pnpm build:node && pnpm build:universal && pnpm build:cloudflare && pnpm build:cloudflare-do && pnpm build:client",
|
|
1609
1971
|
"build:browser": "tsup src/browser.ts --format esm,cjs --dts --platform browser --external better-sqlite3 --external sql.js --external async-mutex --external ulid --external yjs --external fs --no-splitting",
|
|
@@ -1686,6 +2048,9 @@ var CodegenV2CLI = class {
|
|
|
1686
2048
|
).requiredOption("-i, --input <file>", "Path to models.toml").requiredOption(
|
|
1687
2049
|
"-o, --output <dir>",
|
|
1688
2050
|
"Output directory for *.generated.ts and index.ts"
|
|
2051
|
+
).option(
|
|
2052
|
+
"--schema-import <specifier>",
|
|
2053
|
+
"Import specifier for the schema in the generated barrel (default: path from --output to --input, e.g. ./models.toml)"
|
|
1689
2054
|
).option(
|
|
1690
2055
|
"--check",
|
|
1691
2056
|
"Exit non-zero if generated output would change (CI-friendly)",
|
|
@@ -1726,6 +2091,14 @@ var CodegenV2CLI = class {
|
|
|
1726
2091
|
const outputAbs = path3.resolve(options.output);
|
|
1727
2092
|
Logger2.verbose(`Input: ${inputAbs}`, "js-bao-codegen-v2");
|
|
1728
2093
|
Logger2.verbose(`Output: ${outputAbs}`, "js-bao-codegen-v2");
|
|
2094
|
+
if (options.schemaImport !== void 0 && options.schemaImport.trim() === "") {
|
|
2095
|
+
Logger2.error(
|
|
2096
|
+
"--schema-import was empty. Pass a module specifier (e.g. @shared/models.toml), or omit the flag to import the schema relative to --output.",
|
|
2097
|
+
"js-bao-codegen-v2"
|
|
2098
|
+
);
|
|
2099
|
+
process.exit(1);
|
|
2100
|
+
return;
|
|
2101
|
+
}
|
|
1729
2102
|
let result;
|
|
1730
2103
|
try {
|
|
1731
2104
|
result = await generate({
|
|
@@ -1735,7 +2108,8 @@ var CodegenV2CLI = class {
|
|
|
1735
2108
|
// commander turns `--no-strict` into `strict: false`; otherwise
|
|
1736
2109
|
// `options.strict` is `true` by default (its negation-flag
|
|
1737
2110
|
// behavior — see the option declaration above).
|
|
1738
|
-
strict: options.strict !== false
|
|
2111
|
+
strict: options.strict !== false,
|
|
2112
|
+
schemaImportPath: options.schemaImport
|
|
1739
2113
|
});
|
|
1740
2114
|
} catch (err) {
|
|
1741
2115
|
Logger2.error(String(err instanceof Error ? err.message : err), "js-bao-codegen-v2");
|
package/dist/codegen.cjs
CHANGED
|
@@ -1186,7 +1186,7 @@ var SchemaExtractor = class {
|
|
|
1186
1186
|
// package.json
|
|
1187
1187
|
var package_default = {
|
|
1188
1188
|
name: "js-bao",
|
|
1189
|
-
version: "0.
|
|
1189
|
+
version: "0.6.0",
|
|
1190
1190
|
description: "A library providing data modeling capabilities which support live updates and queries.",
|
|
1191
1191
|
types: "dist/index.d.ts",
|
|
1192
1192
|
type: "module",
|
|
@@ -1242,6 +1242,7 @@ var package_default = {
|
|
|
1242
1242
|
"jsbao-codegen-v2": "./dist/codegen-v2.cjs"
|
|
1243
1243
|
},
|
|
1244
1244
|
scripts: {
|
|
1245
|
+
typecheck: "tsc --noEmit -p tsconfig.json",
|
|
1245
1246
|
build: "pnpm build:cli && pnpm build:cli-v2 && pnpm codegen && rm -f dist/index.* dist/node.* dist/browser.* dist/cloudflare.* dist/cloudflare-do.* dist/client.* && pnpm build:main",
|
|
1246
1247
|
"build:main": "pnpm build:browser && pnpm build:node && pnpm build:universal && pnpm build:cloudflare && pnpm build:cloudflare-do && pnpm build:client",
|
|
1247
1248
|
"build:browser": "tsup src/browser.ts --format esm,cjs --dts --platform browser --external better-sqlite3 --external sql.js --external async-mutex --external ulid --external yjs --external fs --no-splitting",
|