js-bao 0.4.2 → 0.5.1

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.
@@ -57,10 +57,25 @@ var init_DocumentQueryTranslator = __esm({
57
57
  }
58
58
  });
59
59
 
60
- // src/models/metaSync.ts
60
+ // src/utils/yjsValues.ts
61
61
  import * as Y from "yjs";
62
+ function isStringSetYMap(value) {
63
+ if (!(value instanceof Y.Map)) return false;
64
+ for (const v of value.values()) {
65
+ if (v !== true) return false;
66
+ }
67
+ return true;
68
+ }
69
+ var init_yjsValues = __esm({
70
+ "src/utils/yjsValues.ts"() {
71
+ "use strict";
72
+ }
73
+ });
74
+
75
+ // src/models/metaSync.ts
76
+ import * as Y2 from "yjs";
62
77
  function inferFieldType(value) {
63
- if (value instanceof Y.Map) return "stringset";
78
+ if (isStringSetYMap(value)) return "stringset";
64
79
  switch (typeof value) {
65
80
  case "string":
66
81
  return "string";
@@ -105,7 +120,7 @@ function syncModelMeta(yDoc, modelName, schema) {
105
120
  if (compoundConstraints.length > 0) {
106
121
  let constraints = meta.get("_constraints");
107
122
  if (!constraints) {
108
- constraints = new Y.Map();
123
+ constraints = new Y2.Map();
109
124
  meta.set("_constraints", constraints);
110
125
  }
111
126
  for (const constraint of compoundConstraints) {
@@ -116,7 +131,7 @@ function syncModelMeta(yDoc, modelName, schema) {
116
131
  if (relationships && Object.keys(relationships).length > 0) {
117
132
  let rels = meta.get("_relationships");
118
133
  if (!rels) {
119
- rels = new Y.Map();
134
+ rels = new Y2.Map();
120
135
  meta.set("_relationships", rels);
121
136
  }
122
137
  for (const [relName, relConfig] of Object.entries(relationships)) {
@@ -128,7 +143,7 @@ function syncModelMeta(yDoc, modelName, schema) {
128
143
  function syncFieldMeta(metaMap, fieldName, fieldOpts) {
129
144
  let fieldMeta = metaMap.get(fieldName);
130
145
  if (!fieldMeta) {
131
- fieldMeta = new Y.Map();
146
+ fieldMeta = new Y2.Map();
132
147
  metaMap.set(fieldName, fieldMeta);
133
148
  }
134
149
  setIfChanged(fieldMeta, "type", fieldOpts.type);
@@ -136,6 +151,7 @@ function syncFieldMeta(metaMap, fieldName, fieldOpts) {
136
151
  if (fieldOpts.unique) setIfChanged(fieldMeta, "unique", true);
137
152
  if (fieldOpts.required) setIfChanged(fieldMeta, "required", true);
138
153
  if (fieldOpts.autoAssign) setIfChanged(fieldMeta, "autoAssign", true);
154
+ if (fieldOpts.autoStamp) setIfChanged(fieldMeta, "autoStamp", fieldOpts.autoStamp);
139
155
  if (fieldOpts.maxLength !== void 0) setIfChanged(fieldMeta, "maxLength", fieldOpts.maxLength);
140
156
  if (fieldOpts.maxCount !== void 0) setIfChanged(fieldMeta, "maxCount", fieldOpts.maxCount);
141
157
  const encoded = encodeDefault(fieldOpts.default);
@@ -144,7 +160,7 @@ function syncFieldMeta(metaMap, fieldName, fieldOpts) {
144
160
  function syncConstraintMeta(constraintsMap, constraint) {
145
161
  let cMeta = constraintsMap.get(constraint.name);
146
162
  if (!cMeta) {
147
- cMeta = new Y.Map();
163
+ cMeta = new Y2.Map();
148
164
  constraintsMap.set(constraint.name, cMeta);
149
165
  }
150
166
  setIfChanged(cMeta, "type", "unique");
@@ -154,7 +170,7 @@ function syncConstraintMeta(constraintsMap, constraint) {
154
170
  function syncRelationshipMeta(relsMap, relName, relConfig) {
155
171
  let relMeta = relsMap.get(relName);
156
172
  if (!relMeta) {
157
- relMeta = new Y.Map();
173
+ relMeta = new Y2.Map();
158
174
  relsMap.set(relName, relMeta);
159
175
  }
160
176
  for (const [key, value] of Object.entries(relConfig)) {
@@ -169,7 +185,7 @@ function syncInferredMeta(yDoc, modelName, recordData) {
169
185
  if (fieldName.startsWith("_")) continue;
170
186
  let fieldMeta = meta.get(fieldName);
171
187
  if (!fieldMeta) {
172
- fieldMeta = new Y.Map();
188
+ fieldMeta = new Y2.Map();
173
189
  meta.set(fieldName, fieldMeta);
174
190
  }
175
191
  if (!fieldMeta.has("type")) {
@@ -189,13 +205,14 @@ var KNOWN_FUNCTION_DEFAULTS, _syncedCache;
189
205
  var init_metaSync = __esm({
190
206
  "src/models/metaSync.ts"() {
191
207
  "use strict";
208
+ init_yjsValues();
192
209
  KNOWN_FUNCTION_DEFAULTS = /* @__PURE__ */ new WeakMap();
193
210
  _syncedCache = /* @__PURE__ */ new WeakMap();
194
211
  }
195
212
  });
196
213
 
197
214
  // src/models/BaseModel.ts
198
- import * as Y2 from "yjs";
215
+ import * as Y3 from "yjs";
199
216
  import { ulid } from "ulid";
200
217
  function generateULID() {
201
218
  return ulid();
@@ -210,6 +227,7 @@ var init_BaseModel = __esm({
210
227
  init_CursorManager();
211
228
  init_sql();
212
229
  init_metaSync();
230
+ init_yjsValues();
213
231
  Logger = class {
214
232
  static _logLevel = 1 /* ERROR */;
215
233
  static _logCallback = null;
@@ -1176,7 +1194,8 @@ function connectDoDb(options) {
1176
1194
  }
1177
1195
 
1178
1196
  // src/utils/yDocSchema.ts
1179
- import * as Y3 from "yjs";
1197
+ init_yjsValues();
1198
+ import * as Y4 from "yjs";
1180
1199
  function discoverSchema(yDoc) {
1181
1200
  const models = {};
1182
1201
  const metaNames = /* @__PURE__ */ new Set();
@@ -1210,7 +1229,7 @@ function discoverModelNames(yDoc) {
1210
1229
  function materializeMap(yDoc, key) {
1211
1230
  try {
1212
1231
  const map = yDoc.getMap(key);
1213
- return map instanceof Y3.Map ? map : null;
1232
+ return map instanceof Y4.Map ? map : null;
1214
1233
  } catch {
1215
1234
  return null;
1216
1235
  }
@@ -1220,11 +1239,11 @@ function readModelMeta(metaMap) {
1220
1239
  let constraints;
1221
1240
  let relationships;
1222
1241
  for (const [key, value] of metaMap.entries()) {
1223
- if (key === "_constraints" && value instanceof Y3.Map) {
1242
+ if (key === "_constraints" && value instanceof Y4.Map) {
1224
1243
  constraints = readConstraints(value);
1225
- } else if (key === "_relationships" && value instanceof Y3.Map) {
1244
+ } else if (key === "_relationships" && value instanceof Y4.Map) {
1226
1245
  relationships = readRelationships(value);
1227
- } else if (value instanceof Y3.Map) {
1246
+ } else if (value instanceof Y4.Map) {
1228
1247
  fields[key] = readFieldMeta(value);
1229
1248
  }
1230
1249
  }
@@ -1243,6 +1262,10 @@ function readFieldMeta(fieldMap) {
1243
1262
  if (fieldMap.get("unique") === true) field.unique = true;
1244
1263
  if (fieldMap.get("required") === true) field.required = true;
1245
1264
  if (fieldMap.get("autoAssign") === true) field.autoAssign = true;
1265
+ const autoStamp = fieldMap.get("autoStamp");
1266
+ if (typeof autoStamp === "string" && (autoStamp === "create" || autoStamp === "update" || autoStamp === "both")) {
1267
+ field.autoStamp = autoStamp;
1268
+ }
1246
1269
  const def = fieldMap.get("default");
1247
1270
  if (def !== void 0) field.default = def;
1248
1271
  const maxLength = fieldMap.get("maxLength");
@@ -1255,7 +1278,7 @@ function inferModelFromData(dataMap) {
1255
1278
  const fields = {};
1256
1279
  let sampled = 0;
1257
1280
  for (const [_recordId, recordValue] of dataMap.entries()) {
1258
- if (!(recordValue instanceof Y3.Map)) continue;
1281
+ if (!(recordValue instanceof Y4.Map)) continue;
1259
1282
  if (++sampled > 5) break;
1260
1283
  for (const [fieldName, value] of recordValue.entries()) {
1261
1284
  if (fieldName.startsWith("_")) continue;
@@ -1268,7 +1291,7 @@ function inferModelFromData(dataMap) {
1268
1291
  return { fields };
1269
1292
  }
1270
1293
  function inferTypeFromValue(value) {
1271
- if (value instanceof Y3.Map) return "stringset";
1294
+ if (isStringSetYMap(value)) return "stringset";
1272
1295
  switch (typeof value) {
1273
1296
  case "string":
1274
1297
  return "string";
@@ -1283,7 +1306,7 @@ function inferTypeFromValue(value) {
1283
1306
  function readConstraints(constraintsMap) {
1284
1307
  const out = {};
1285
1308
  for (const [name, value] of constraintsMap.entries()) {
1286
- if (!(value instanceof Y3.Map)) continue;
1309
+ if (!(value instanceof Y4.Map)) continue;
1287
1310
  let fields = [];
1288
1311
  const rawFields = value.get("fields");
1289
1312
  if (typeof rawFields === "string") {
@@ -1302,7 +1325,7 @@ function readConstraints(constraintsMap) {
1302
1325
  function readRelationships(relsMap) {
1303
1326
  const out = {};
1304
1327
  for (const [name, value] of relsMap.entries()) {
1305
- if (!(value instanceof Y3.Map)) continue;
1328
+ if (!(value instanceof Y4.Map)) continue;
1306
1329
  const rel = {};
1307
1330
  for (const [k, v] of value.entries()) {
1308
1331
  rel[k] = v;
@@ -1313,6 +1336,7 @@ function readRelationships(relsMap) {
1313
1336
  }
1314
1337
  var CAMEL_TO_SNAKE = {
1315
1338
  autoAssign: "auto_assign",
1339
+ autoStamp: "auto_stamp",
1316
1340
  maxLength: "max_length",
1317
1341
  maxCount: "max_count",
1318
1342
  relatedIdField: "related_id_field",
@@ -1343,6 +1367,7 @@ function schemaToToml(schema) {
1343
1367
  lines.push(`[models.${modelName}.fields.${fieldName}]`);
1344
1368
  lines.push(`type = ${tomlValue(field.type)}`);
1345
1369
  if (field.autoAssign) lines.push("auto_assign = true");
1370
+ if (field.autoStamp) lines.push(`auto_stamp = ${tomlValue(field.autoStamp)}`);
1346
1371
  if (field.indexed) lines.push("indexed = true");
1347
1372
  if (field.unique) lines.push("unique = true");
1348
1373
  if (field.required) lines.push("required = true");
@@ -1466,10 +1491,13 @@ var KNOWN_FIELD_KEYS = /* @__PURE__ */ new Set([
1466
1491
  "unique",
1467
1492
  "required",
1468
1493
  "auto_assign",
1494
+ "auto_stamp",
1469
1495
  "max_length",
1470
1496
  "max_count",
1471
- "default"
1497
+ "default",
1498
+ "enum"
1472
1499
  ]);
1500
+ var VALID_AUTO_STAMP_VALUES = /* @__PURE__ */ new Set(["create", "update", "both"]);
1473
1501
  var KNOWN_MODEL_KEYS = /* @__PURE__ */ new Set([
1474
1502
  "fields",
1475
1503
  "relationships",
@@ -1511,9 +1539,37 @@ function parseFieldOptions(raw, context, strict) {
1511
1539
  if (raw.unique === true) opts.unique = true;
1512
1540
  if (raw.required === true) opts.required = true;
1513
1541
  if (raw.auto_assign === true) opts.autoAssign = true;
1542
+ if (raw.auto_stamp !== void 0) {
1543
+ if (typeof raw.auto_stamp !== "string" || !VALID_AUTO_STAMP_VALUES.has(raw.auto_stamp)) {
1544
+ throw new Error(
1545
+ `${context}: invalid auto_stamp value "${raw.auto_stamp}". Must be one of: ${[
1546
+ ...VALID_AUTO_STAMP_VALUES
1547
+ ].join(", ")}`
1548
+ );
1549
+ }
1550
+ opts.autoStamp = raw.auto_stamp;
1551
+ }
1514
1552
  if (raw.max_length !== void 0) opts.maxLength = raw.max_length;
1515
1553
  if (raw.max_count !== void 0) opts.maxCount = raw.max_count;
1516
1554
  if (raw.default !== void 0) opts.default = raw.default;
1555
+ if (raw.enum !== void 0) {
1556
+ if (raw.type !== "string") {
1557
+ throw new Error(
1558
+ `${context}: \`enum\` is only valid on a "string" field, not "${raw.type}".`
1559
+ );
1560
+ }
1561
+ if (!Array.isArray(raw.enum) || raw.enum.length === 0) {
1562
+ throw new Error(
1563
+ `${context}: \`enum\` must be a non-empty array of strings.`
1564
+ );
1565
+ }
1566
+ if (!raw.enum.every((v) => typeof v === "string")) {
1567
+ throw new Error(
1568
+ `${context}: \`enum\` values must all be strings.`
1569
+ );
1570
+ }
1571
+ opts.enum = [...raw.enum];
1572
+ }
1517
1573
  return opts;
1518
1574
  }
1519
1575
  function requireField(raw, field, context) {
@@ -80,15 +80,25 @@ var init_DocumentQueryTranslator = __esm({
80
80
  }
81
81
  });
82
82
 
83
+ // src/utils/yjsValues.ts
84
+ var Y;
85
+ var init_yjsValues = __esm({
86
+ "src/utils/yjsValues.ts"() {
87
+ "use strict";
88
+ Y = __toESM(require("yjs"), 1);
89
+ }
90
+ });
91
+
83
92
  // src/models/metaSync.ts
84
93
  function registerFunctionDefault(fn, name) {
85
94
  KNOWN_FUNCTION_DEFAULTS.set(fn, name);
86
95
  }
87
- var Y, KNOWN_FUNCTION_DEFAULTS;
96
+ var Y2, KNOWN_FUNCTION_DEFAULTS;
88
97
  var init_metaSync = __esm({
89
98
  "src/models/metaSync.ts"() {
90
99
  "use strict";
91
- Y = __toESM(require("yjs"), 1);
100
+ Y2 = __toESM(require("yjs"), 1);
101
+ init_yjsValues();
92
102
  KNOWN_FUNCTION_DEFAULTS = /* @__PURE__ */ new WeakMap();
93
103
  }
94
104
  });
@@ -97,11 +107,11 @@ var init_metaSync = __esm({
97
107
  function generateULID() {
98
108
  return (0, import_ulid.ulid)();
99
109
  }
100
- var Y2, import_ulid;
110
+ var Y3, import_ulid;
101
111
  var init_BaseModel = __esm({
102
112
  "src/models/BaseModel.ts"() {
103
113
  "use strict";
104
- Y2 = __toESM(require("yjs"), 1);
114
+ Y3 = __toESM(require("yjs"), 1);
105
115
  import_ulid = require("ulid");
106
116
  init_StringSet();
107
117
  init_documentTypes();
@@ -109,6 +119,7 @@ var init_BaseModel = __esm({
109
119
  init_CursorManager();
110
120
  init_sql();
111
121
  init_metaSync();
122
+ init_yjsValues();
112
123
  registerFunctionDefault(generateULID, "generate_ulid");
113
124
  }
114
125
  });
@@ -231,10 +242,13 @@ var KNOWN_FIELD_KEYS = /* @__PURE__ */ new Set([
231
242
  "unique",
232
243
  "required",
233
244
  "auto_assign",
245
+ "auto_stamp",
234
246
  "max_length",
235
247
  "max_count",
236
- "default"
248
+ "default",
249
+ "enum"
237
250
  ]);
251
+ var VALID_AUTO_STAMP_VALUES = /* @__PURE__ */ new Set(["create", "update", "both"]);
238
252
  var KNOWN_MODEL_KEYS = /* @__PURE__ */ new Set([
239
253
  "fields",
240
254
  "relationships",
@@ -276,9 +290,37 @@ function parseFieldOptions(raw, context, strict) {
276
290
  if (raw.unique === true) opts.unique = true;
277
291
  if (raw.required === true) opts.required = true;
278
292
  if (raw.auto_assign === true) opts.autoAssign = true;
293
+ if (raw.auto_stamp !== void 0) {
294
+ if (typeof raw.auto_stamp !== "string" || !VALID_AUTO_STAMP_VALUES.has(raw.auto_stamp)) {
295
+ throw new Error(
296
+ `${context}: invalid auto_stamp value "${raw.auto_stamp}". Must be one of: ${[
297
+ ...VALID_AUTO_STAMP_VALUES
298
+ ].join(", ")}`
299
+ );
300
+ }
301
+ opts.autoStamp = raw.auto_stamp;
302
+ }
279
303
  if (raw.max_length !== void 0) opts.maxLength = raw.max_length;
280
304
  if (raw.max_count !== void 0) opts.maxCount = raw.max_count;
281
305
  if (raw.default !== void 0) opts.default = raw.default;
306
+ if (raw.enum !== void 0) {
307
+ if (raw.type !== "string") {
308
+ throw new Error(
309
+ `${context}: \`enum\` is only valid on a "string" field, not "${raw.type}".`
310
+ );
311
+ }
312
+ if (!Array.isArray(raw.enum) || raw.enum.length === 0) {
313
+ throw new Error(
314
+ `${context}: \`enum\` must be a non-empty array of strings.`
315
+ );
316
+ }
317
+ if (!raw.enum.every((v) => typeof v === "string")) {
318
+ throw new Error(
319
+ `${context}: \`enum\` values must all be strings.`
320
+ );
321
+ }
322
+ opts.enum = [...raw.enum];
323
+ }
282
324
  return opts;
283
325
  }
284
326
  function requireField(raw, field, context) {
@@ -479,6 +521,12 @@ function tsTypeForFieldType(fieldType) {
479
521
  }
480
522
  }
481
523
  }
524
+ function tsTypeForFieldOptions(opts) {
525
+ if (opts.type === "string" && Array.isArray(opts.enum) && opts.enum.length > 0) {
526
+ return opts.enum.map((v) => JSON.stringify(v)).join(" | ");
527
+ }
528
+ return tsTypeForFieldType(opts.type);
529
+ }
482
530
 
483
531
  // src/cli/v2/templates.ts
484
532
  var HEADER_BANNER = "// AUTO-GENERATED FROM models.toml \u2014 DO NOT EDIT.";
@@ -532,8 +580,9 @@ function renderModelFile(input) {
532
580
  lines.push("");
533
581
  lines.push(`export interface ${className}Attrs {`);
534
582
  for (const [fieldName, opts] of Object.entries(fields)) {
535
- const tsType = tsTypeForFieldType(opts.type);
536
- const optional = opts.required === true ? "" : "?";
583
+ const tsType = tsTypeForFieldOptions(opts);
584
+ const isRequired = opts.required === true || opts.autoAssign === true && fieldName === "id";
585
+ const optional = isRequired ? "" : "?";
537
586
  lines.push(` ${fieldName}${optional}: ${tsType};`);
538
587
  }
539
588
  lines.push(`}`);
@@ -642,7 +691,9 @@ function renderBarrel(input) {
642
691
  lines.push(` }`);
643
692
  lines.push(`}`);
644
693
  lines.push("");
645
- lines.push(`export const allModels: unknown[] = _modelPairs.map((m) => m.class);`);
694
+ lines.push(
695
+ `export const allModels: Array<typeof BaseModel> = _modelPairs.map((m) => m.class);`
696
+ );
646
697
  lines.push("");
647
698
  return lines.join("\n");
648
699
  }
@@ -801,6 +852,7 @@ var ts = __toESM(require("typescript"), 1);
801
852
  // src/cli/v2/toml-writer.ts
802
853
  var CAMEL_TO_SNAKE = {
803
854
  autoAssign: "auto_assign",
855
+ autoStamp: "auto_stamp",
804
856
  maxLength: "max_length",
805
857
  maxCount: "max_count",
806
858
  relatedIdField: "related_id_field",
@@ -841,11 +893,17 @@ function renderModelsToml(models) {
841
893
  lines.push(`[models.${model.name}.fields.${fieldName}]`);
842
894
  lines.push(`type = ${tomlValue(opts.type)}`);
843
895
  if (opts.autoAssign === true) lines.push("auto_assign = true");
896
+ if (opts.autoStamp !== void 0) {
897
+ lines.push(`auto_stamp = ${tomlValue(opts.autoStamp)}`);
898
+ }
844
899
  if (opts.indexed === true) lines.push("indexed = true");
845
900
  if (opts.unique === true) lines.push("unique = true");
846
901
  if (opts.required === true) lines.push("required = true");
847
902
  if (opts.maxLength !== void 0) lines.push(`max_length = ${opts.maxLength}`);
848
903
  if (opts.maxCount !== void 0) lines.push(`max_count = ${opts.maxCount}`);
904
+ if (opts.enum !== void 0) {
905
+ lines.push(`enum = [${opts.enum.map((v) => tomlValue(v)).join(", ")}]`);
906
+ }
849
907
  if (opts.default !== void 0) {
850
908
  lines.push(`default = ${tomlValue(opts.default)}`);
851
909
  }
@@ -1062,10 +1120,18 @@ function parseDefineModelSchemaArg(obj, sf) {
1062
1120
  if (opts && opts.type === "id") {
1063
1121
  fd.severity = "info";
1064
1122
  opts.autoAssign = true;
1123
+ if (fd.field === "id") {
1124
+ opts.required = true;
1125
+ }
1065
1126
  } else {
1066
1127
  fd.severity = "warn";
1067
1128
  }
1068
1129
  }
1130
+ for (const [fieldName, opts] of Object.entries(fields)) {
1131
+ if (fieldName === "id" && opts.autoAssign === true && opts.required !== false) {
1132
+ opts.required = true;
1133
+ }
1134
+ }
1069
1135
  return { modelName, fields, relationships, uniqueConstraints, functionDefaults };
1070
1136
  }
1071
1137
  function parseFields(obj, sf) {
@@ -1097,6 +1163,11 @@ function parseFields(obj, sf) {
1097
1163
  case "autoAssign":
1098
1164
  if (typeof value === "boolean") opts.autoAssign = value;
1099
1165
  break;
1166
+ case "autoStamp":
1167
+ if (value === "create" || value === "update" || value === "both") {
1168
+ opts.autoStamp = value;
1169
+ }
1170
+ break;
1100
1171
  case "maxLength":
1101
1172
  if (typeof value === "number") opts.maxLength = value;
1102
1173
  break;
@@ -1477,7 +1548,7 @@ var Logger2 = class _Logger {
1477
1548
  // package.json
1478
1549
  var package_default = {
1479
1550
  name: "js-bao",
1480
- version: "0.4.2",
1551
+ version: "0.5.1",
1481
1552
  description: "A library providing data modeling capabilities which support live updates and queries.",
1482
1553
  types: "dist/index.d.ts",
1483
1554
  type: "module",
package/dist/codegen.cjs CHANGED
@@ -1136,6 +1136,11 @@ var SchemaExtractor = class {
1136
1136
  fieldDef.autoAssign = value;
1137
1137
  }
1138
1138
  break;
1139
+ case "autoStamp":
1140
+ if (value === "create" || value === "update" || value === "both") {
1141
+ fieldDef.autoStamp = value;
1142
+ }
1143
+ break;
1139
1144
  case "primaryKey":
1140
1145
  if (typeof value === "boolean") {
1141
1146
  fieldDef.primaryKey = value;
@@ -1181,7 +1186,7 @@ var SchemaExtractor = class {
1181
1186
  // package.json
1182
1187
  var package_default = {
1183
1188
  name: "js-bao",
1184
- version: "0.4.2",
1189
+ version: "0.5.1",
1185
1190
  description: "A library providing data modeling capabilities which support live updates and queries.",
1186
1191
  types: "dist/index.d.ts",
1187
1192
  type: "module",