js-bao 0.5.1 → 0.5.2
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 +124 -30
- package/dist/browser.cjs +586 -265
- package/dist/browser.d.cts +21 -0
- package/dist/browser.d.ts +21 -0
- package/dist/browser.js +588 -263
- package/dist/client.cjs +42 -6
- package/dist/client.d.cts +71 -0
- package/dist/client.d.ts +71 -0
- package/dist/client.js +39 -4
- package/dist/cloudflare-do.cjs +462 -215
- package/dist/cloudflare-do.d.cts +111 -1
- package/dist/cloudflare-do.d.ts +111 -1
- package/dist/cloudflare-do.js +459 -213
- package/dist/cloudflare.cjs +270 -23
- package/dist/cloudflare.d.cts +276 -1
- package/dist/cloudflare.d.ts +276 -1
- package/dist/cloudflare.js +267 -21
- package/dist/codegen-v2.cjs +77 -19
- package/dist/codegen.cjs +2 -1
- package/dist/index.cjs +551 -224
- package/dist/index.d.cts +57 -1
- package/dist/index.d.ts +57 -1
- package/dist/index.js +549 -221
- package/dist/node.cjs +775 -291
- package/dist/node.d.cts +179 -1
- package/dist/node.d.ts +179 -1
- package/dist/node.js +762 -288
- package/package.json +2 -1
package/dist/cloudflare.js
CHANGED
|
@@ -72,8 +72,203 @@ var init_yjsValues = __esm({
|
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
// src/models/
|
|
75
|
+
// src/models/writeLifecycle.ts
|
|
76
76
|
import * as Y2 from "yjs";
|
|
77
|
+
import { ulid } from "ulid";
|
|
78
|
+
function assertNever(x) {
|
|
79
|
+
throw new Error(`Unhandled field type: ${String(x)}`);
|
|
80
|
+
}
|
|
81
|
+
function fieldWriteKind(type) {
|
|
82
|
+
switch (type) {
|
|
83
|
+
case "string":
|
|
84
|
+
case "number":
|
|
85
|
+
case "boolean":
|
|
86
|
+
case "date":
|
|
87
|
+
case "id":
|
|
88
|
+
return "scalar";
|
|
89
|
+
case "stringset":
|
|
90
|
+
return "stringset";
|
|
91
|
+
default:
|
|
92
|
+
return assertNever(type);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function isKnownFieldType(type) {
|
|
96
|
+
return KNOWN_FIELD_TYPES.has(type);
|
|
97
|
+
}
|
|
98
|
+
function ensureStringSetYMap(rm, fieldName) {
|
|
99
|
+
const nested = rm.get(fieldName);
|
|
100
|
+
if (nested instanceof Y2.Map) return nested;
|
|
101
|
+
const fresh = new Y2.Map();
|
|
102
|
+
if (nested && typeof nested === "object") {
|
|
103
|
+
for (const [member, marker] of Object.entries(
|
|
104
|
+
nested
|
|
105
|
+
)) {
|
|
106
|
+
if (Boolean(marker)) fresh.set(member, true);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
rm.set(fieldName, fresh);
|
|
110
|
+
return fresh;
|
|
111
|
+
}
|
|
112
|
+
function applyStringSetDelta(target, delta) {
|
|
113
|
+
if (delta.clear) {
|
|
114
|
+
for (const member of Array.from(target.keys())) target.delete(member);
|
|
115
|
+
}
|
|
116
|
+
if (delta.remove) {
|
|
117
|
+
for (const member of delta.remove) target.delete(String(member));
|
|
118
|
+
}
|
|
119
|
+
if (delta.add) {
|
|
120
|
+
for (const member of delta.add) {
|
|
121
|
+
const key = String(member);
|
|
122
|
+
if (target.get(key) !== true) target.set(key, true);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function replaceStringSet(rm, fieldName, members) {
|
|
127
|
+
const target = ensureStringSetYMap(rm, fieldName);
|
|
128
|
+
const desired = /* @__PURE__ */ new Set();
|
|
129
|
+
for (const member of members) desired.add(String(member));
|
|
130
|
+
for (const existing of Array.from(target.keys())) {
|
|
131
|
+
if (!desired.has(existing)) target.delete(existing);
|
|
132
|
+
}
|
|
133
|
+
for (const member of desired) {
|
|
134
|
+
if (target.get(member) !== true) target.set(member, true);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function applyStringSetChange(recordYMap, fieldName, change) {
|
|
138
|
+
const target = ensureStringSetYMap(recordYMap, fieldName);
|
|
139
|
+
applyStringSetDelta(target, {
|
|
140
|
+
add: change.additions,
|
|
141
|
+
remove: change.removals
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function parseStringSetOp(value) {
|
|
145
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Y2.AbstractType) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
const keys = Object.keys(value);
|
|
149
|
+
const opKeys = keys.filter((k) => k.startsWith("$"));
|
|
150
|
+
if (opKeys.length === 0) return null;
|
|
151
|
+
const known = /* @__PURE__ */ new Set(["$add", "$remove", "$clear"]);
|
|
152
|
+
const unknown = keys.filter((k) => !known.has(k));
|
|
153
|
+
if (unknown.length > 0) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
`Invalid stringset op: unexpected key(s) [${unknown.join(", ")}]. Only $add, $remove and $clear are supported.`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
const obj = value;
|
|
159
|
+
const toMembers = (raw, opName) => {
|
|
160
|
+
if (raw === void 0) return [];
|
|
161
|
+
if (!Array.isArray(raw)) {
|
|
162
|
+
throw new Error(`Invalid stringset op: ${opName} must be an array.`);
|
|
163
|
+
}
|
|
164
|
+
return raw.map((m) => String(m));
|
|
165
|
+
};
|
|
166
|
+
return {
|
|
167
|
+
add: toMembers(obj.$add, "$add"),
|
|
168
|
+
remove: toMembers(obj.$remove, "$remove"),
|
|
169
|
+
clear: obj.$clear === true
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function writeField(rm, declaredType, key, value, modelName) {
|
|
173
|
+
const kind = declaredType && isKnownFieldType(declaredType) ? fieldWriteKind(declaredType) : "scalar";
|
|
174
|
+
if (Array.isArray(value)) {
|
|
175
|
+
if (kind !== "stringset") {
|
|
176
|
+
throw new Error(
|
|
177
|
+
`Cannot write array value to field "${key}" on model "${modelName}": its declared type could not be resolved to a collection (stringset). Collection fields require schema metadata in the document (_meta_${modelName}); the model must be saved by a client at least once before a workflow writes one of its collection fields.`
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
replaceStringSet(rm, key, value);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const op = parseStringSetOp(value);
|
|
184
|
+
if (op) {
|
|
185
|
+
if (kind !== "stringset") {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`Cannot apply a stringset op ({ $add/$remove/$clear }) to field "${key}" on model "${modelName}": its declared type is ${declaredType ? `"${declaredType}"` : "unresolved"}, not a collection (stringset). Op-objects are only valid for stringset / refersToMany fields with schema metadata (_meta_${modelName}).`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
applyStringSetDelta(ensureStringSetYMap(rm, key), op);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (kind === "stringset") {
|
|
194
|
+
throw new Error(
|
|
195
|
+
`Field "${key}" on model "${modelName}" is a stringset and requires an array (replace) or { $add/$remove/$clear } (delta) value; received ${value === null ? "null" : typeof value}.`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
rm.set(key, value);
|
|
199
|
+
}
|
|
200
|
+
function registerFunctionDefaultGenerator(name, fn) {
|
|
201
|
+
FUNCTION_DEFAULT_GENERATORS.set(name, fn);
|
|
202
|
+
}
|
|
203
|
+
function decodeFunctionDefault(name) {
|
|
204
|
+
return FUNCTION_DEFAULT_GENERATORS.get(name);
|
|
205
|
+
}
|
|
206
|
+
function resolveDefaultValue(rawDefault, opts = {}) {
|
|
207
|
+
if (typeof rawDefault === "function") return rawDefault();
|
|
208
|
+
if (typeof rawDefault === "string" && rawDefault.startsWith("$")) {
|
|
209
|
+
if (rawDefault.startsWith("$$")) return rawDefault.slice(1);
|
|
210
|
+
const name = rawDefault.slice(1);
|
|
211
|
+
const gen = opts.decode?.(name) ?? decodeFunctionDefault(name);
|
|
212
|
+
if (!gen) {
|
|
213
|
+
throw new Error(
|
|
214
|
+
`Unknown function default "${rawDefault}" for field "${opts.fieldName ?? "?"}"${opts.modelName ? ` on model "${opts.modelName}"` : ""}: no generator is registered for "${name}". Register it via registerFunctionDefaultGenerator("${name}", fn) so the server can populate the field the same way the client does.`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
return gen();
|
|
218
|
+
}
|
|
219
|
+
return rawDefault;
|
|
220
|
+
}
|
|
221
|
+
function applyDefaultsFromSchema(fields, data, opts = {}) {
|
|
222
|
+
for (const [fieldName, field] of Object.entries(fields)) {
|
|
223
|
+
if (fieldName === "id") continue;
|
|
224
|
+
if (!field || field.default === void 0) continue;
|
|
225
|
+
if (field.default === UNKNOWN_FUNCTION_DEFAULT) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (Object.prototype.hasOwnProperty.call(data, fieldName) && data[fieldName] !== void 0) {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
data[fieldName] = resolveDefaultValue(field.default, {
|
|
232
|
+
fieldName,
|
|
233
|
+
modelName: opts.modelName,
|
|
234
|
+
decode: opts.decodeFunctionDefault
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
return data;
|
|
238
|
+
}
|
|
239
|
+
function applyAutoStampsFromSchema(fields, data, opts) {
|
|
240
|
+
const { isNew, now } = opts;
|
|
241
|
+
for (const [fieldName, field] of Object.entries(fields)) {
|
|
242
|
+
const stamp = field?.autoStamp;
|
|
243
|
+
if (!stamp) continue;
|
|
244
|
+
const explicit = Object.prototype.hasOwnProperty.call(data, fieldName) && data[fieldName] !== null && data[fieldName] !== void 0;
|
|
245
|
+
if (explicit) continue;
|
|
246
|
+
if (stamp === "create" && !isNew) continue;
|
|
247
|
+
data[fieldName] = now;
|
|
248
|
+
}
|
|
249
|
+
return data;
|
|
250
|
+
}
|
|
251
|
+
var KNOWN_FIELD_TYPE_MAP, KNOWN_FIELD_TYPES, FUNCTION_DEFAULT_GENERATORS, UNKNOWN_FUNCTION_DEFAULT;
|
|
252
|
+
var init_writeLifecycle = __esm({
|
|
253
|
+
"src/models/writeLifecycle.ts"() {
|
|
254
|
+
"use strict";
|
|
255
|
+
KNOWN_FIELD_TYPE_MAP = {
|
|
256
|
+
string: true,
|
|
257
|
+
number: true,
|
|
258
|
+
boolean: true,
|
|
259
|
+
date: true,
|
|
260
|
+
id: true,
|
|
261
|
+
stringset: true
|
|
262
|
+
};
|
|
263
|
+
KNOWN_FIELD_TYPES = new Set(Object.keys(KNOWN_FIELD_TYPE_MAP));
|
|
264
|
+
FUNCTION_DEFAULT_GENERATORS = /* @__PURE__ */ new Map();
|
|
265
|
+
registerFunctionDefaultGenerator("generate_ulid", () => ulid());
|
|
266
|
+
UNKNOWN_FUNCTION_DEFAULT = "$unknown_function";
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// src/models/metaSync.ts
|
|
271
|
+
import * as Y3 from "yjs";
|
|
77
272
|
function inferFieldType(value) {
|
|
78
273
|
if (isStringSetYMap(value)) return "stringset";
|
|
79
274
|
switch (typeof value) {
|
|
@@ -94,7 +289,10 @@ function encodeDefault(value) {
|
|
|
94
289
|
if (value === void 0 || value === null) return void 0;
|
|
95
290
|
if (typeof value === "function") {
|
|
96
291
|
const name = KNOWN_FUNCTION_DEFAULTS.get(value);
|
|
97
|
-
return name ? `$${name}` :
|
|
292
|
+
return name ? `$${name}` : UNKNOWN_FUNCTION_DEFAULT;
|
|
293
|
+
}
|
|
294
|
+
if (typeof value === "string" && value.startsWith("$")) {
|
|
295
|
+
return `$${value}`;
|
|
98
296
|
}
|
|
99
297
|
return value;
|
|
100
298
|
}
|
|
@@ -120,7 +318,7 @@ function syncModelMeta(yDoc, modelName, schema) {
|
|
|
120
318
|
if (compoundConstraints.length > 0) {
|
|
121
319
|
let constraints = meta.get("_constraints");
|
|
122
320
|
if (!constraints) {
|
|
123
|
-
constraints = new
|
|
321
|
+
constraints = new Y3.Map();
|
|
124
322
|
meta.set("_constraints", constraints);
|
|
125
323
|
}
|
|
126
324
|
for (const constraint of compoundConstraints) {
|
|
@@ -131,7 +329,7 @@ function syncModelMeta(yDoc, modelName, schema) {
|
|
|
131
329
|
if (relationships && Object.keys(relationships).length > 0) {
|
|
132
330
|
let rels = meta.get("_relationships");
|
|
133
331
|
if (!rels) {
|
|
134
|
-
rels = new
|
|
332
|
+
rels = new Y3.Map();
|
|
135
333
|
meta.set("_relationships", rels);
|
|
136
334
|
}
|
|
137
335
|
for (const [relName, relConfig] of Object.entries(relationships)) {
|
|
@@ -143,7 +341,7 @@ function syncModelMeta(yDoc, modelName, schema) {
|
|
|
143
341
|
function syncFieldMeta(metaMap, fieldName, fieldOpts) {
|
|
144
342
|
let fieldMeta = metaMap.get(fieldName);
|
|
145
343
|
if (!fieldMeta) {
|
|
146
|
-
fieldMeta = new
|
|
344
|
+
fieldMeta = new Y3.Map();
|
|
147
345
|
metaMap.set(fieldName, fieldMeta);
|
|
148
346
|
}
|
|
149
347
|
setIfChanged(fieldMeta, "type", fieldOpts.type);
|
|
@@ -160,7 +358,7 @@ function syncFieldMeta(metaMap, fieldName, fieldOpts) {
|
|
|
160
358
|
function syncConstraintMeta(constraintsMap, constraint) {
|
|
161
359
|
let cMeta = constraintsMap.get(constraint.name);
|
|
162
360
|
if (!cMeta) {
|
|
163
|
-
cMeta = new
|
|
361
|
+
cMeta = new Y3.Map();
|
|
164
362
|
constraintsMap.set(constraint.name, cMeta);
|
|
165
363
|
}
|
|
166
364
|
setIfChanged(cMeta, "type", "unique");
|
|
@@ -170,7 +368,7 @@ function syncConstraintMeta(constraintsMap, constraint) {
|
|
|
170
368
|
function syncRelationshipMeta(relsMap, relName, relConfig) {
|
|
171
369
|
let relMeta = relsMap.get(relName);
|
|
172
370
|
if (!relMeta) {
|
|
173
|
-
relMeta = new
|
|
371
|
+
relMeta = new Y3.Map();
|
|
174
372
|
relsMap.set(relName, relMeta);
|
|
175
373
|
}
|
|
176
374
|
for (const [key, value] of Object.entries(relConfig)) {
|
|
@@ -185,7 +383,7 @@ function syncInferredMeta(yDoc, modelName, recordData) {
|
|
|
185
383
|
if (fieldName.startsWith("_")) continue;
|
|
186
384
|
let fieldMeta = meta.get(fieldName);
|
|
187
385
|
if (!fieldMeta) {
|
|
188
|
-
fieldMeta = new
|
|
386
|
+
fieldMeta = new Y3.Map();
|
|
189
387
|
meta.set(fieldName, fieldMeta);
|
|
190
388
|
}
|
|
191
389
|
if (!fieldMeta.has("type")) {
|
|
@@ -206,16 +404,42 @@ var init_metaSync = __esm({
|
|
|
206
404
|
"src/models/metaSync.ts"() {
|
|
207
405
|
"use strict";
|
|
208
406
|
init_yjsValues();
|
|
407
|
+
init_writeLifecycle();
|
|
209
408
|
KNOWN_FUNCTION_DEFAULTS = /* @__PURE__ */ new WeakMap();
|
|
210
409
|
_syncedCache = /* @__PURE__ */ new WeakMap();
|
|
211
410
|
}
|
|
212
411
|
});
|
|
213
412
|
|
|
413
|
+
// src/utils/uniqueIndex.ts
|
|
414
|
+
import * as Y4 from "yjs";
|
|
415
|
+
function buildUniqueKey(recordData, fields) {
|
|
416
|
+
const keyParts = [];
|
|
417
|
+
for (const field of fields) {
|
|
418
|
+
const value = recordData instanceof Y4.Map ? recordData.get(field) : recordData[field];
|
|
419
|
+
if (value === null || value === void 0) {
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
keyParts.push(String(value));
|
|
423
|
+
}
|
|
424
|
+
return keyParts.join("|");
|
|
425
|
+
}
|
|
426
|
+
function uniqueIndexMapName(modelName, constraintName) {
|
|
427
|
+
return `_uniqueIdx_${modelName}_${constraintName}`;
|
|
428
|
+
}
|
|
429
|
+
function fieldUniqueConstraintName(modelName, fieldName) {
|
|
430
|
+
return `${modelName}_${fieldName}_unique`;
|
|
431
|
+
}
|
|
432
|
+
var init_uniqueIndex = __esm({
|
|
433
|
+
"src/utils/uniqueIndex.ts"() {
|
|
434
|
+
"use strict";
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
|
|
214
438
|
// src/models/BaseModel.ts
|
|
215
|
-
import * as
|
|
216
|
-
import { ulid } from "ulid";
|
|
439
|
+
import * as Y5 from "yjs";
|
|
440
|
+
import { ulid as ulid2 } from "ulid";
|
|
217
441
|
function generateULID() {
|
|
218
|
-
return
|
|
442
|
+
return ulid2();
|
|
219
443
|
}
|
|
220
444
|
var Logger;
|
|
221
445
|
var init_BaseModel = __esm({
|
|
@@ -227,7 +451,9 @@ var init_BaseModel = __esm({
|
|
|
227
451
|
init_CursorManager();
|
|
228
452
|
init_sql();
|
|
229
453
|
init_metaSync();
|
|
454
|
+
init_writeLifecycle();
|
|
230
455
|
init_yjsValues();
|
|
456
|
+
init_uniqueIndex();
|
|
231
457
|
Logger = class {
|
|
232
458
|
static _logLevel = 1 /* ERROR */;
|
|
233
459
|
static _logCallback = null;
|
|
@@ -1195,7 +1421,7 @@ function connectDoDb(options) {
|
|
|
1195
1421
|
|
|
1196
1422
|
// src/utils/yDocSchema.ts
|
|
1197
1423
|
init_yjsValues();
|
|
1198
|
-
import * as
|
|
1424
|
+
import * as Y6 from "yjs";
|
|
1199
1425
|
function discoverSchema(yDoc) {
|
|
1200
1426
|
const models = {};
|
|
1201
1427
|
const metaNames = /* @__PURE__ */ new Set();
|
|
@@ -1229,7 +1455,7 @@ function discoverModelNames(yDoc) {
|
|
|
1229
1455
|
function materializeMap(yDoc, key) {
|
|
1230
1456
|
try {
|
|
1231
1457
|
const map = yDoc.getMap(key);
|
|
1232
|
-
return map instanceof
|
|
1458
|
+
return map instanceof Y6.Map ? map : null;
|
|
1233
1459
|
} catch {
|
|
1234
1460
|
return null;
|
|
1235
1461
|
}
|
|
@@ -1239,11 +1465,11 @@ function readModelMeta(metaMap) {
|
|
|
1239
1465
|
let constraints;
|
|
1240
1466
|
let relationships;
|
|
1241
1467
|
for (const [key, value] of metaMap.entries()) {
|
|
1242
|
-
if (key === "_constraints" && value instanceof
|
|
1468
|
+
if (key === "_constraints" && value instanceof Y6.Map) {
|
|
1243
1469
|
constraints = readConstraints(value);
|
|
1244
|
-
} else if (key === "_relationships" && value instanceof
|
|
1470
|
+
} else if (key === "_relationships" && value instanceof Y6.Map) {
|
|
1245
1471
|
relationships = readRelationships(value);
|
|
1246
|
-
} else if (value instanceof
|
|
1472
|
+
} else if (value instanceof Y6.Map) {
|
|
1247
1473
|
fields[key] = readFieldMeta(value);
|
|
1248
1474
|
}
|
|
1249
1475
|
}
|
|
@@ -1278,7 +1504,7 @@ function inferModelFromData(dataMap) {
|
|
|
1278
1504
|
const fields = {};
|
|
1279
1505
|
let sampled = 0;
|
|
1280
1506
|
for (const [_recordId, recordValue] of dataMap.entries()) {
|
|
1281
|
-
if (!(recordValue instanceof
|
|
1507
|
+
if (!(recordValue instanceof Y6.Map)) continue;
|
|
1282
1508
|
if (++sampled > 5) break;
|
|
1283
1509
|
for (const [fieldName, value] of recordValue.entries()) {
|
|
1284
1510
|
if (fieldName.startsWith("_")) continue;
|
|
@@ -1306,7 +1532,7 @@ function inferTypeFromValue(value) {
|
|
|
1306
1532
|
function readConstraints(constraintsMap) {
|
|
1307
1533
|
const out = {};
|
|
1308
1534
|
for (const [name, value] of constraintsMap.entries()) {
|
|
1309
|
-
if (!(value instanceof
|
|
1535
|
+
if (!(value instanceof Y6.Map)) continue;
|
|
1310
1536
|
let fields = [];
|
|
1311
1537
|
const rawFields = value.get("fields");
|
|
1312
1538
|
if (typeof rawFields === "string") {
|
|
@@ -1325,7 +1551,7 @@ function readConstraints(constraintsMap) {
|
|
|
1325
1551
|
function readRelationships(relsMap) {
|
|
1326
1552
|
const out = {};
|
|
1327
1553
|
for (const [name, value] of relsMap.entries()) {
|
|
1328
|
-
if (!(value instanceof
|
|
1554
|
+
if (!(value instanceof Y6.Map)) continue;
|
|
1329
1555
|
const rel = {};
|
|
1330
1556
|
for (const [k, v] of value.entries()) {
|
|
1331
1557
|
rel[k] = v;
|
|
@@ -1404,6 +1630,7 @@ import { parse as parseToml } from "smol-toml";
|
|
|
1404
1630
|
// src/models/schema.ts
|
|
1405
1631
|
init_BaseModel();
|
|
1406
1632
|
init_ModelRegistry();
|
|
1633
|
+
init_uniqueIndex();
|
|
1407
1634
|
function defineModelSchema(input) {
|
|
1408
1635
|
const { name, fields } = input;
|
|
1409
1636
|
const options = {
|
|
@@ -1446,7 +1673,7 @@ function resolveUniqueConstraints(modelName, fields, customConstraints) {
|
|
|
1446
1673
|
for (const [fieldName, options] of fields.entries()) {
|
|
1447
1674
|
if (options.unique) {
|
|
1448
1675
|
resolved.push({
|
|
1449
|
-
name:
|
|
1676
|
+
name: fieldUniqueConstraintName(modelName, fieldName),
|
|
1450
1677
|
fields: [fieldName]
|
|
1451
1678
|
});
|
|
1452
1679
|
}
|
|
@@ -1692,20 +1919,39 @@ function loadSchemaFromTomlString(tomlString, options = {}) {
|
|
|
1692
1919
|
}
|
|
1693
1920
|
|
|
1694
1921
|
// src/cloudflare.ts
|
|
1922
|
+
init_uniqueIndex();
|
|
1695
1923
|
init_metaSync();
|
|
1924
|
+
init_writeLifecycle();
|
|
1696
1925
|
export {
|
|
1697
1926
|
DOClientEngine,
|
|
1927
|
+
applyAutoStampsFromSchema,
|
|
1928
|
+
applyDefaultsFromSchema,
|
|
1929
|
+
applyStringSetChange,
|
|
1930
|
+
applyStringSetDelta,
|
|
1931
|
+
assertNever,
|
|
1932
|
+
buildUniqueKey,
|
|
1698
1933
|
clearMetaSyncCache,
|
|
1699
1934
|
connectDoDb,
|
|
1935
|
+
decodeFunctionDefault,
|
|
1700
1936
|
discoverModelNames,
|
|
1701
1937
|
discoverSchema,
|
|
1938
|
+
ensureStringSetYMap,
|
|
1939
|
+
fieldUniqueConstraintName,
|
|
1940
|
+
fieldWriteKind,
|
|
1702
1941
|
getActiveDOEngine,
|
|
1703
1942
|
inferFieldType,
|
|
1704
1943
|
initJsBaoDO,
|
|
1944
|
+
isKnownFieldType,
|
|
1705
1945
|
loadSchemaFromTomlString,
|
|
1946
|
+
parseStringSetOp,
|
|
1706
1947
|
registerFunctionDefault,
|
|
1948
|
+
registerFunctionDefaultGenerator,
|
|
1949
|
+
replaceStringSet,
|
|
1707
1950
|
resetJsBaoDO,
|
|
1951
|
+
resolveDefaultValue,
|
|
1708
1952
|
schemaToToml,
|
|
1709
1953
|
syncInferredMeta,
|
|
1710
|
-
syncModelMeta
|
|
1954
|
+
syncModelMeta,
|
|
1955
|
+
uniqueIndexMapName,
|
|
1956
|
+
writeField
|
|
1711
1957
|
};
|
package/dist/codegen-v2.cjs
CHANGED
|
@@ -89,37 +89,76 @@ 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
|
+
|
|
106
143
|
// src/models/BaseModel.ts
|
|
107
144
|
function generateULID() {
|
|
108
|
-
return (0,
|
|
145
|
+
return (0, import_ulid2.ulid)();
|
|
109
146
|
}
|
|
110
|
-
var
|
|
147
|
+
var Y5, import_ulid2;
|
|
111
148
|
var init_BaseModel = __esm({
|
|
112
149
|
"src/models/BaseModel.ts"() {
|
|
113
150
|
"use strict";
|
|
114
|
-
|
|
115
|
-
|
|
151
|
+
Y5 = __toESM(require("yjs"), 1);
|
|
152
|
+
import_ulid2 = require("ulid");
|
|
116
153
|
init_StringSet();
|
|
117
154
|
init_documentTypes();
|
|
118
155
|
init_DocumentQueryTranslator();
|
|
119
156
|
init_CursorManager();
|
|
120
157
|
init_sql();
|
|
121
158
|
init_metaSync();
|
|
159
|
+
init_writeLifecycle();
|
|
122
160
|
init_yjsValues();
|
|
161
|
+
init_uniqueIndex();
|
|
123
162
|
registerFunctionDefault(generateULID, "generate_ulid");
|
|
124
163
|
}
|
|
125
164
|
});
|
|
@@ -155,6 +194,7 @@ var import_smol_toml = require("smol-toml");
|
|
|
155
194
|
// src/models/schema.ts
|
|
156
195
|
init_BaseModel();
|
|
157
196
|
init_ModelRegistry();
|
|
197
|
+
init_uniqueIndex();
|
|
158
198
|
function defineModelSchema(input) {
|
|
159
199
|
const { name, fields } = input;
|
|
160
200
|
const options = {
|
|
@@ -197,7 +237,7 @@ function resolveUniqueConstraints(modelName, fields, customConstraints) {
|
|
|
197
237
|
for (const [fieldName, options] of fields.entries()) {
|
|
198
238
|
if (options.unique) {
|
|
199
239
|
resolved.push({
|
|
200
|
-
name:
|
|
240
|
+
name: fieldUniqueConstraintName(modelName, fieldName),
|
|
201
241
|
fields: [fieldName]
|
|
202
242
|
});
|
|
203
243
|
}
|
|
@@ -616,14 +656,12 @@ function renderModelFile(input) {
|
|
|
616
656
|
lines.push("");
|
|
617
657
|
lines.push(`export class ${className} extends BaseModelImpl {}`);
|
|
618
658
|
lines.push("");
|
|
619
|
-
lines.push(
|
|
620
|
-
`export const ${className}_modelName: "${escapeStringLiteral(modelName)}" = ${JSON.stringify(modelName)};`
|
|
621
|
-
);
|
|
659
|
+
lines.push(`export const ${className}_modelName = ${JSON.stringify(modelName)} as const;`);
|
|
622
660
|
lines.push("");
|
|
623
661
|
return lines.join("\n");
|
|
624
662
|
}
|
|
625
663
|
function renderBarrel(input) {
|
|
626
|
-
const { fingerprint,
|
|
664
|
+
const { fingerprint, tomlImportPath, entries } = input;
|
|
627
665
|
const lines = [];
|
|
628
666
|
lines.push(HEADER_BANNER);
|
|
629
667
|
lines.push(REGEN_INSTRUCTION);
|
|
@@ -644,7 +682,7 @@ function renderBarrel(input) {
|
|
|
644
682
|
lines.push(
|
|
645
683
|
`import { attachAndRegisterModel, loadSchemaFromTomlString } from "js-bao";`
|
|
646
684
|
);
|
|
647
|
-
lines.push(`import modelsToml from
|
|
685
|
+
lines.push(`import modelsToml from ${JSON.stringify(`${tomlImportPath}?raw`)};`);
|
|
648
686
|
for (const { className } of entries) {
|
|
649
687
|
lines.push(`import { ${className} } from "./${className}.generated";`);
|
|
650
688
|
}
|
|
@@ -697,11 +735,18 @@ function renderBarrel(input) {
|
|
|
697
735
|
lines.push("");
|
|
698
736
|
return lines.join("\n");
|
|
699
737
|
}
|
|
700
|
-
function escapeStringLiteral(s) {
|
|
701
|
-
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
702
|
-
}
|
|
703
738
|
|
|
704
739
|
// src/cli/v2/generator.ts
|
|
740
|
+
function computeSchemaImportSpecifier(outputDirAbs, inputTomlAbs, pathImpl = path) {
|
|
741
|
+
const relative2 = pathImpl.relative(outputDirAbs, inputTomlAbs);
|
|
742
|
+
if (pathImpl.isAbsolute(relative2)) {
|
|
743
|
+
throw new Error(
|
|
744
|
+
`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.`
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
const posix = relative2.split(pathImpl.sep).join("/");
|
|
748
|
+
return posix.startsWith("./") || posix.startsWith("../") ? posix : `./${posix}`;
|
|
749
|
+
}
|
|
705
750
|
var GENERATED_FILE_SUFFIX = ".generated.ts";
|
|
706
751
|
var BARREL_FILENAME = "index.ts";
|
|
707
752
|
async function generate(options) {
|
|
@@ -733,7 +778,7 @@ async function generate(options) {
|
|
|
733
778
|
modelName: s.name,
|
|
734
779
|
className: classNamesByModelName[s.name]
|
|
735
780
|
})).sort((a, b) => a.className.localeCompare(b.className));
|
|
736
|
-
const
|
|
781
|
+
const tomlImportPath = options.schemaImportPath !== void 0 && options.schemaImportPath.trim() !== "" ? options.schemaImportPath : computeSchemaImportSpecifier(outAbs, inputAbs);
|
|
737
782
|
const filesToWrite = /* @__PURE__ */ new Map();
|
|
738
783
|
for (const schema of schemas) {
|
|
739
784
|
const className = classNamesByModelName[schema.name];
|
|
@@ -755,7 +800,7 @@ async function generate(options) {
|
|
|
755
800
|
barrelPath,
|
|
756
801
|
renderBarrel({
|
|
757
802
|
fingerprint,
|
|
758
|
-
|
|
803
|
+
tomlImportPath,
|
|
759
804
|
entries
|
|
760
805
|
})
|
|
761
806
|
);
|
|
@@ -1548,7 +1593,7 @@ var Logger2 = class _Logger {
|
|
|
1548
1593
|
// package.json
|
|
1549
1594
|
var package_default = {
|
|
1550
1595
|
name: "js-bao",
|
|
1551
|
-
version: "0.5.
|
|
1596
|
+
version: "0.5.2",
|
|
1552
1597
|
description: "A library providing data modeling capabilities which support live updates and queries.",
|
|
1553
1598
|
types: "dist/index.d.ts",
|
|
1554
1599
|
type: "module",
|
|
@@ -1604,6 +1649,7 @@ var package_default = {
|
|
|
1604
1649
|
"jsbao-codegen-v2": "./dist/codegen-v2.cjs"
|
|
1605
1650
|
},
|
|
1606
1651
|
scripts: {
|
|
1652
|
+
typecheck: "tsc --noEmit -p tsconfig.json",
|
|
1607
1653
|
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
1654
|
"build:main": "pnpm build:browser && pnpm build:node && pnpm build:universal && pnpm build:cloudflare && pnpm build:cloudflare-do && pnpm build:client",
|
|
1609
1655
|
"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 +1732,9 @@ var CodegenV2CLI = class {
|
|
|
1686
1732
|
).requiredOption("-i, --input <file>", "Path to models.toml").requiredOption(
|
|
1687
1733
|
"-o, --output <dir>",
|
|
1688
1734
|
"Output directory for *.generated.ts and index.ts"
|
|
1735
|
+
).option(
|
|
1736
|
+
"--schema-import <specifier>",
|
|
1737
|
+
"Import specifier for the schema in the generated barrel (default: path from --output to --input, e.g. ./models.toml)"
|
|
1689
1738
|
).option(
|
|
1690
1739
|
"--check",
|
|
1691
1740
|
"Exit non-zero if generated output would change (CI-friendly)",
|
|
@@ -1726,6 +1775,14 @@ var CodegenV2CLI = class {
|
|
|
1726
1775
|
const outputAbs = path3.resolve(options.output);
|
|
1727
1776
|
Logger2.verbose(`Input: ${inputAbs}`, "js-bao-codegen-v2");
|
|
1728
1777
|
Logger2.verbose(`Output: ${outputAbs}`, "js-bao-codegen-v2");
|
|
1778
|
+
if (options.schemaImport !== void 0 && options.schemaImport.trim() === "") {
|
|
1779
|
+
Logger2.error(
|
|
1780
|
+
"--schema-import was empty. Pass a module specifier (e.g. @shared/models.toml), or omit the flag to import the schema relative to --output.",
|
|
1781
|
+
"js-bao-codegen-v2"
|
|
1782
|
+
);
|
|
1783
|
+
process.exit(1);
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1729
1786
|
let result;
|
|
1730
1787
|
try {
|
|
1731
1788
|
result = await generate({
|
|
@@ -1735,7 +1792,8 @@ var CodegenV2CLI = class {
|
|
|
1735
1792
|
// commander turns `--no-strict` into `strict: false`; otherwise
|
|
1736
1793
|
// `options.strict` is `true` by default (its negation-flag
|
|
1737
1794
|
// behavior — see the option declaration above).
|
|
1738
|
-
strict: options.strict !== false
|
|
1795
|
+
strict: options.strict !== false,
|
|
1796
|
+
schemaImportPath: options.schemaImport
|
|
1739
1797
|
});
|
|
1740
1798
|
} catch (err) {
|
|
1741
1799
|
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.5.
|
|
1189
|
+
version: "0.5.2",
|
|
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",
|