js-bao 0.4.0 → 0.4.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/dist/browser.cjs +179 -48
- package/dist/browser.d.cts +45 -1
- package/dist/browser.d.ts +45 -1
- package/dist/browser.js +179 -48
- package/dist/client.d.cts +32 -0
- package/dist/client.d.ts +32 -0
- package/dist/cloudflare-do.cjs +70 -5
- package/dist/cloudflare-do.d.cts +47 -3
- package/dist/cloudflare-do.d.ts +47 -3
- package/dist/cloudflare-do.js +70 -5
- package/dist/cloudflare.cjs +70 -5
- package/dist/cloudflare.d.cts +45 -1
- package/dist/cloudflare.d.ts +45 -1
- package/dist/cloudflare.js +70 -5
- package/dist/codegen-v2.cjs +1766 -0
- package/dist/codegen-v2.d.cts +1 -0
- package/dist/codegen.cjs +7 -10
- package/dist/index.cjs +181 -50
- package/dist/index.d.cts +46 -2
- package/dist/index.d.ts +46 -2
- package/dist/index.js +181 -50
- package/dist/node.cjs +181 -50
- package/dist/node.d.cts +46 -2
- package/dist/node.d.ts +46 -2
- package/dist/node.js +181 -50
- package/package.json +7 -10
package/dist/cloudflare-do.d.cts
CHANGED
|
@@ -40,6 +40,13 @@ interface UniqueConstraintConfig {
|
|
|
40
40
|
}
|
|
41
41
|
interface ModelOptions {
|
|
42
42
|
name: string;
|
|
43
|
+
/**
|
|
44
|
+
* Optional PascalCase class name. Used by the v2 codegen to drive
|
|
45
|
+
* generated TypeScript class names (and relationship method names that
|
|
46
|
+
* derive from a target's class name). When absent, the v2 codegen
|
|
47
|
+
* falls back to suffix-based singularization of `name`.
|
|
48
|
+
*/
|
|
49
|
+
className?: string;
|
|
43
50
|
uniqueConstraints?: UniqueConstraintConfig[];
|
|
44
51
|
relationships?: Record<string, RelationshipConfig>;
|
|
45
52
|
}
|
|
@@ -1221,8 +1228,8 @@ declare function createDatabaseDO(config?: DatabaseDOConfig): {
|
|
|
1221
1228
|
_initialized: boolean;
|
|
1222
1229
|
/** @internal — cache for $contains misuse check: "model:field" keys known to be in data_json */
|
|
1223
1230
|
_containsMisuseCache: Set<string>;
|
|
1224
|
-
|
|
1225
|
-
|
|
1231
|
+
readonly state: DurableObjectState;
|
|
1232
|
+
readonly engine: DurableObjectEngine;
|
|
1226
1233
|
/** @internal */
|
|
1227
1234
|
_ensureInitialized(): Promise<void>;
|
|
1228
1235
|
fetch(request: Request): Promise<Response>;
|
|
@@ -1628,6 +1635,7 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
1628
1635
|
permissionHint: DocumentPermissionHint;
|
|
1629
1636
|
}>;
|
|
1630
1637
|
protected static documentYMaps: Map<string, Y.Map<any>>;
|
|
1638
|
+
private static _observedStringSetMaps;
|
|
1631
1639
|
private _localChanges;
|
|
1632
1640
|
private _isDirty;
|
|
1633
1641
|
private _isLoadingFromYjs;
|
|
@@ -1702,7 +1710,17 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
1702
1710
|
added: Record<string, any>;
|
|
1703
1711
|
modified: Record<string, any>;
|
|
1704
1712
|
removed: string[];
|
|
1713
|
+
stringSetChanges: Record<string, {
|
|
1714
|
+
additions: Set<string>;
|
|
1715
|
+
removals: Set<string>;
|
|
1716
|
+
}>;
|
|
1705
1717
|
};
|
|
1718
|
+
/**
|
|
1719
|
+
* Apply a stringset change set to the parent record's Y.Map by mutating a
|
|
1720
|
+
* nested Y.Map keyed by member. Migrates from a legacy plain-object value
|
|
1721
|
+
* if the field hasn't been touched since the wire-format change in #561.
|
|
1722
|
+
*/
|
|
1723
|
+
private applyStringSetChangeToYMap;
|
|
1706
1724
|
/**
|
|
1707
1725
|
* Deep equality check for comparing field values
|
|
1708
1726
|
*/
|
|
@@ -1804,6 +1822,20 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
1804
1822
|
* Execute a callback with automatic transaction handling for all modified models
|
|
1805
1823
|
*/
|
|
1806
1824
|
static withTransaction<T>(callback: () => Promise<T> | T): Promise<T>;
|
|
1825
|
+
/**
|
|
1826
|
+
* Attach a one-shot observer to a nested-Y.Map stringset field. Calls
|
|
1827
|
+
* notifyListeners() when the nested map's keys change (i.e. when a remote
|
|
1828
|
+
* member arrives via Y.applyUpdate, or a local per-member set/delete).
|
|
1829
|
+
* Idempotent — re-calling on the same Y.Map is a no-op.
|
|
1830
|
+
*/
|
|
1831
|
+
protected static observeStringSetMapOnce(nestedMap: Y.Map<any>): void;
|
|
1832
|
+
/**
|
|
1833
|
+
* Walk the schema's stringset fields on `recordYMap` and observe any nested
|
|
1834
|
+
* Y.Map values. Called from observer setup and from the parent observer body
|
|
1835
|
+
* so newly-arrived stringset Y.Maps (local migration or remote create) get
|
|
1836
|
+
* an observer too.
|
|
1837
|
+
*/
|
|
1838
|
+
protected static attachStringSetObserversToRecord(recordYMap: Y.Map<any>, schema: any): void;
|
|
1807
1839
|
/**
|
|
1808
1840
|
* Sets up deep observation on a nested YMap to sync field-level changes to the database
|
|
1809
1841
|
*/
|
|
@@ -1845,10 +1877,22 @@ interface DefinedModelSchema<TFields extends Record<string, FieldOptions> = Reco
|
|
|
1845
1877
|
* - Compound unique constraints are [[models.*.unique_constraints]]
|
|
1846
1878
|
*/
|
|
1847
1879
|
|
|
1880
|
+
interface LoadSchemaOptions {
|
|
1881
|
+
/**
|
|
1882
|
+
* When true (default), throw on unknown keys at the model, field,
|
|
1883
|
+
* relationship, and unique-constraint level. When false, unknown
|
|
1884
|
+
* keys are silently ignored (legacy behavior).
|
|
1885
|
+
*/
|
|
1886
|
+
strict?: boolean;
|
|
1887
|
+
}
|
|
1848
1888
|
/**
|
|
1849
1889
|
* Parse a TOML string and return an array of DefinedModelSchema objects.
|
|
1890
|
+
*
|
|
1891
|
+
* By default operates in strict mode: unknown keys at the model, field,
|
|
1892
|
+
* relationship, or unique-constraint level cause an error. Pass
|
|
1893
|
+
* `{ strict: false }` to silently ignore unknown keys (legacy behavior).
|
|
1850
1894
|
*/
|
|
1851
|
-
declare function loadSchemaFromTomlString(tomlString: string): DefinedModelSchema[];
|
|
1895
|
+
declare function loadSchemaFromTomlString(tomlString: string, options?: LoadSchemaOptions): DefinedModelSchema[];
|
|
1852
1896
|
|
|
1853
1897
|
/**
|
|
1854
1898
|
* Meta Sync — writes _meta_* YMaps into a YDoc.
|
package/dist/cloudflare-do.d.ts
CHANGED
|
@@ -40,6 +40,13 @@ interface UniqueConstraintConfig {
|
|
|
40
40
|
}
|
|
41
41
|
interface ModelOptions {
|
|
42
42
|
name: string;
|
|
43
|
+
/**
|
|
44
|
+
* Optional PascalCase class name. Used by the v2 codegen to drive
|
|
45
|
+
* generated TypeScript class names (and relationship method names that
|
|
46
|
+
* derive from a target's class name). When absent, the v2 codegen
|
|
47
|
+
* falls back to suffix-based singularization of `name`.
|
|
48
|
+
*/
|
|
49
|
+
className?: string;
|
|
43
50
|
uniqueConstraints?: UniqueConstraintConfig[];
|
|
44
51
|
relationships?: Record<string, RelationshipConfig>;
|
|
45
52
|
}
|
|
@@ -1221,8 +1228,8 @@ declare function createDatabaseDO(config?: DatabaseDOConfig): {
|
|
|
1221
1228
|
_initialized: boolean;
|
|
1222
1229
|
/** @internal — cache for $contains misuse check: "model:field" keys known to be in data_json */
|
|
1223
1230
|
_containsMisuseCache: Set<string>;
|
|
1224
|
-
|
|
1225
|
-
|
|
1231
|
+
readonly state: DurableObjectState;
|
|
1232
|
+
readonly engine: DurableObjectEngine;
|
|
1226
1233
|
/** @internal */
|
|
1227
1234
|
_ensureInitialized(): Promise<void>;
|
|
1228
1235
|
fetch(request: Request): Promise<Response>;
|
|
@@ -1628,6 +1635,7 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
1628
1635
|
permissionHint: DocumentPermissionHint;
|
|
1629
1636
|
}>;
|
|
1630
1637
|
protected static documentYMaps: Map<string, Y.Map<any>>;
|
|
1638
|
+
private static _observedStringSetMaps;
|
|
1631
1639
|
private _localChanges;
|
|
1632
1640
|
private _isDirty;
|
|
1633
1641
|
private _isLoadingFromYjs;
|
|
@@ -1702,7 +1710,17 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
1702
1710
|
added: Record<string, any>;
|
|
1703
1711
|
modified: Record<string, any>;
|
|
1704
1712
|
removed: string[];
|
|
1713
|
+
stringSetChanges: Record<string, {
|
|
1714
|
+
additions: Set<string>;
|
|
1715
|
+
removals: Set<string>;
|
|
1716
|
+
}>;
|
|
1705
1717
|
};
|
|
1718
|
+
/**
|
|
1719
|
+
* Apply a stringset change set to the parent record's Y.Map by mutating a
|
|
1720
|
+
* nested Y.Map keyed by member. Migrates from a legacy plain-object value
|
|
1721
|
+
* if the field hasn't been touched since the wire-format change in #561.
|
|
1722
|
+
*/
|
|
1723
|
+
private applyStringSetChangeToYMap;
|
|
1706
1724
|
/**
|
|
1707
1725
|
* Deep equality check for comparing field values
|
|
1708
1726
|
*/
|
|
@@ -1804,6 +1822,20 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
1804
1822
|
* Execute a callback with automatic transaction handling for all modified models
|
|
1805
1823
|
*/
|
|
1806
1824
|
static withTransaction<T>(callback: () => Promise<T> | T): Promise<T>;
|
|
1825
|
+
/**
|
|
1826
|
+
* Attach a one-shot observer to a nested-Y.Map stringset field. Calls
|
|
1827
|
+
* notifyListeners() when the nested map's keys change (i.e. when a remote
|
|
1828
|
+
* member arrives via Y.applyUpdate, or a local per-member set/delete).
|
|
1829
|
+
* Idempotent — re-calling on the same Y.Map is a no-op.
|
|
1830
|
+
*/
|
|
1831
|
+
protected static observeStringSetMapOnce(nestedMap: Y.Map<any>): void;
|
|
1832
|
+
/**
|
|
1833
|
+
* Walk the schema's stringset fields on `recordYMap` and observe any nested
|
|
1834
|
+
* Y.Map values. Called from observer setup and from the parent observer body
|
|
1835
|
+
* so newly-arrived stringset Y.Maps (local migration or remote create) get
|
|
1836
|
+
* an observer too.
|
|
1837
|
+
*/
|
|
1838
|
+
protected static attachStringSetObserversToRecord(recordYMap: Y.Map<any>, schema: any): void;
|
|
1807
1839
|
/**
|
|
1808
1840
|
* Sets up deep observation on a nested YMap to sync field-level changes to the database
|
|
1809
1841
|
*/
|
|
@@ -1845,10 +1877,22 @@ interface DefinedModelSchema<TFields extends Record<string, FieldOptions> = Reco
|
|
|
1845
1877
|
* - Compound unique constraints are [[models.*.unique_constraints]]
|
|
1846
1878
|
*/
|
|
1847
1879
|
|
|
1880
|
+
interface LoadSchemaOptions {
|
|
1881
|
+
/**
|
|
1882
|
+
* When true (default), throw on unknown keys at the model, field,
|
|
1883
|
+
* relationship, and unique-constraint level. When false, unknown
|
|
1884
|
+
* keys are silently ignored (legacy behavior).
|
|
1885
|
+
*/
|
|
1886
|
+
strict?: boolean;
|
|
1887
|
+
}
|
|
1848
1888
|
/**
|
|
1849
1889
|
* Parse a TOML string and return an array of DefinedModelSchema objects.
|
|
1890
|
+
*
|
|
1891
|
+
* By default operates in strict mode: unknown keys at the model, field,
|
|
1892
|
+
* relationship, or unique-constraint level cause an error. Pass
|
|
1893
|
+
* `{ strict: false }` to silently ignore unknown keys (legacy behavior).
|
|
1850
1894
|
*/
|
|
1851
|
-
declare function loadSchemaFromTomlString(tomlString: string): DefinedModelSchema[];
|
|
1895
|
+
declare function loadSchemaFromTomlString(tomlString: string, options?: LoadSchemaOptions): DefinedModelSchema[];
|
|
1852
1896
|
|
|
1853
1897
|
/**
|
|
1854
1898
|
* Meta Sync — writes _meta_* YMaps into a YDoc.
|
package/dist/cloudflare-do.js
CHANGED
|
@@ -4217,6 +4217,7 @@ function defineModelSchema(input) {
|
|
|
4217
4217
|
const { name, fields } = input;
|
|
4218
4218
|
const options = {
|
|
4219
4219
|
name,
|
|
4220
|
+
className: input.options?.className,
|
|
4220
4221
|
uniqueConstraints: input.options?.uniqueConstraints ? [...input.options.uniqueConstraints] : void 0,
|
|
4221
4222
|
relationships: input.options?.relationships
|
|
4222
4223
|
};
|
|
@@ -4293,12 +4294,52 @@ var VALID_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
|
4293
4294
|
"id",
|
|
4294
4295
|
"stringset"
|
|
4295
4296
|
]);
|
|
4296
|
-
|
|
4297
|
+
var KNOWN_FIELD_KEYS = /* @__PURE__ */ new Set([
|
|
4298
|
+
"type",
|
|
4299
|
+
"indexed",
|
|
4300
|
+
"unique",
|
|
4301
|
+
"required",
|
|
4302
|
+
"auto_assign",
|
|
4303
|
+
"max_length",
|
|
4304
|
+
"max_count",
|
|
4305
|
+
"default"
|
|
4306
|
+
]);
|
|
4307
|
+
var KNOWN_MODEL_KEYS = /* @__PURE__ */ new Set([
|
|
4308
|
+
"fields",
|
|
4309
|
+
"relationships",
|
|
4310
|
+
"unique_constraints",
|
|
4311
|
+
"class_name"
|
|
4312
|
+
]);
|
|
4313
|
+
var KNOWN_RELATIONSHIP_KEYS = /* @__PURE__ */ new Set([
|
|
4314
|
+
"type",
|
|
4315
|
+
"model",
|
|
4316
|
+
"related_id_field",
|
|
4317
|
+
"join_model",
|
|
4318
|
+
"join_model_local_field",
|
|
4319
|
+
"join_model_related_field",
|
|
4320
|
+
"order_by_field",
|
|
4321
|
+
"order_direction",
|
|
4322
|
+
"join_model_order_by_field",
|
|
4323
|
+
"join_model_order_direction"
|
|
4324
|
+
]);
|
|
4325
|
+
var KNOWN_UNIQUE_CONSTRAINT_KEYS = /* @__PURE__ */ new Set(["name", "fields"]);
|
|
4326
|
+
function checkUnknownKeys(raw, known, context, strict) {
|
|
4327
|
+
if (!strict) return;
|
|
4328
|
+
for (const key of Object.keys(raw)) {
|
|
4329
|
+
if (!known.has(key)) {
|
|
4330
|
+
throw new Error(
|
|
4331
|
+
`${context}: unknown key "${key}". Allowed: ${[...known].join(", ")}`
|
|
4332
|
+
);
|
|
4333
|
+
}
|
|
4334
|
+
}
|
|
4335
|
+
}
|
|
4336
|
+
function parseFieldOptions(raw, context, strict) {
|
|
4297
4337
|
if (!raw.type || !VALID_FIELD_TYPES.has(raw.type)) {
|
|
4298
4338
|
throw new Error(
|
|
4299
4339
|
`Invalid field type "${raw.type}". Must be one of: ${[...VALID_FIELD_TYPES].join(", ")}`
|
|
4300
4340
|
);
|
|
4301
4341
|
}
|
|
4342
|
+
checkUnknownKeys(raw, KNOWN_FIELD_KEYS, context, strict);
|
|
4302
4343
|
const opts = { type: raw.type };
|
|
4303
4344
|
if (raw.indexed === true) opts.indexed = true;
|
|
4304
4345
|
if (raw.unique === true) opts.unique = true;
|
|
@@ -4314,8 +4355,9 @@ function requireField(raw, field, context) {
|
|
|
4314
4355
|
throw new Error(`Relationship ${context}: missing required field "${field}"`);
|
|
4315
4356
|
}
|
|
4316
4357
|
}
|
|
4317
|
-
function parseRelationship(raw) {
|
|
4358
|
+
function parseRelationship(raw, context, strict) {
|
|
4318
4359
|
const type = raw.type;
|
|
4360
|
+
checkUnknownKeys(raw, KNOWN_RELATIONSHIP_KEYS, context, strict);
|
|
4319
4361
|
if (type === "refersTo") {
|
|
4320
4362
|
requireField(raw, "model", "refersTo");
|
|
4321
4363
|
requireField(raw, "related_id_field", "refersTo");
|
|
@@ -4357,7 +4399,8 @@ function parseRelationship(raw) {
|
|
|
4357
4399
|
}
|
|
4358
4400
|
throw new Error(`Unknown relationship type: ${type}`);
|
|
4359
4401
|
}
|
|
4360
|
-
function loadSchemaFromTomlString(tomlString) {
|
|
4402
|
+
function loadSchemaFromTomlString(tomlString, options = {}) {
|
|
4403
|
+
const strict = options.strict !== false;
|
|
4361
4404
|
const parsed = parseToml(tomlString);
|
|
4362
4405
|
const models = parsed.models;
|
|
4363
4406
|
if (!models || typeof models !== "object") {
|
|
@@ -4365,10 +4408,20 @@ function loadSchemaFromTomlString(tomlString) {
|
|
|
4365
4408
|
}
|
|
4366
4409
|
const schemas = [];
|
|
4367
4410
|
for (const [modelName, modelDef] of Object.entries(models)) {
|
|
4411
|
+
checkUnknownKeys(
|
|
4412
|
+
modelDef,
|
|
4413
|
+
KNOWN_MODEL_KEYS,
|
|
4414
|
+
`[models.${modelName}]`,
|
|
4415
|
+
strict
|
|
4416
|
+
);
|
|
4368
4417
|
const fields = {};
|
|
4369
4418
|
if (modelDef.fields) {
|
|
4370
4419
|
for (const [fieldName, fieldDef] of Object.entries(modelDef.fields)) {
|
|
4371
|
-
fields[fieldName] = parseFieldOptions(
|
|
4420
|
+
fields[fieldName] = parseFieldOptions(
|
|
4421
|
+
fieldDef,
|
|
4422
|
+
`[models.${modelName}.fields.${fieldName}]`,
|
|
4423
|
+
strict
|
|
4424
|
+
);
|
|
4372
4425
|
}
|
|
4373
4426
|
}
|
|
4374
4427
|
let relationships;
|
|
@@ -4377,24 +4430,36 @@ function loadSchemaFromTomlString(tomlString) {
|
|
|
4377
4430
|
for (const [relName, relDef] of Object.entries(
|
|
4378
4431
|
modelDef.relationships
|
|
4379
4432
|
)) {
|
|
4380
|
-
relationships[relName] = parseRelationship(
|
|
4433
|
+
relationships[relName] = parseRelationship(
|
|
4434
|
+
relDef,
|
|
4435
|
+
`[models.${modelName}.relationships.${relName}]`,
|
|
4436
|
+
strict
|
|
4437
|
+
);
|
|
4381
4438
|
}
|
|
4382
4439
|
}
|
|
4383
4440
|
let uniqueConstraints;
|
|
4384
4441
|
if (modelDef.unique_constraints) {
|
|
4385
4442
|
uniqueConstraints = [];
|
|
4386
4443
|
for (const raw of modelDef.unique_constraints) {
|
|
4444
|
+
checkUnknownKeys(
|
|
4445
|
+
raw,
|
|
4446
|
+
KNOWN_UNIQUE_CONSTRAINT_KEYS,
|
|
4447
|
+
`[[models.${modelName}.unique_constraints]]`,
|
|
4448
|
+
strict
|
|
4449
|
+
);
|
|
4387
4450
|
uniqueConstraints.push({
|
|
4388
4451
|
name: raw.name,
|
|
4389
4452
|
fields: [...raw.fields]
|
|
4390
4453
|
});
|
|
4391
4454
|
}
|
|
4392
4455
|
}
|
|
4456
|
+
const className = typeof modelDef.class_name === "string" ? modelDef.class_name : void 0;
|
|
4393
4457
|
schemas.push(
|
|
4394
4458
|
defineModelSchema({
|
|
4395
4459
|
name: modelName,
|
|
4396
4460
|
fields,
|
|
4397
4461
|
options: {
|
|
4462
|
+
className,
|
|
4398
4463
|
uniqueConstraints,
|
|
4399
4464
|
relationships
|
|
4400
4465
|
}
|
package/dist/cloudflare.cjs
CHANGED
|
@@ -1430,6 +1430,7 @@ function defineModelSchema(input) {
|
|
|
1430
1430
|
const { name, fields } = input;
|
|
1431
1431
|
const options = {
|
|
1432
1432
|
name,
|
|
1433
|
+
className: input.options?.className,
|
|
1433
1434
|
uniqueConstraints: input.options?.uniqueConstraints ? [...input.options.uniqueConstraints] : void 0,
|
|
1434
1435
|
relationships: input.options?.relationships
|
|
1435
1436
|
};
|
|
@@ -1506,12 +1507,52 @@ var VALID_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
|
1506
1507
|
"id",
|
|
1507
1508
|
"stringset"
|
|
1508
1509
|
]);
|
|
1509
|
-
|
|
1510
|
+
var KNOWN_FIELD_KEYS = /* @__PURE__ */ new Set([
|
|
1511
|
+
"type",
|
|
1512
|
+
"indexed",
|
|
1513
|
+
"unique",
|
|
1514
|
+
"required",
|
|
1515
|
+
"auto_assign",
|
|
1516
|
+
"max_length",
|
|
1517
|
+
"max_count",
|
|
1518
|
+
"default"
|
|
1519
|
+
]);
|
|
1520
|
+
var KNOWN_MODEL_KEYS = /* @__PURE__ */ new Set([
|
|
1521
|
+
"fields",
|
|
1522
|
+
"relationships",
|
|
1523
|
+
"unique_constraints",
|
|
1524
|
+
"class_name"
|
|
1525
|
+
]);
|
|
1526
|
+
var KNOWN_RELATIONSHIP_KEYS = /* @__PURE__ */ new Set([
|
|
1527
|
+
"type",
|
|
1528
|
+
"model",
|
|
1529
|
+
"related_id_field",
|
|
1530
|
+
"join_model",
|
|
1531
|
+
"join_model_local_field",
|
|
1532
|
+
"join_model_related_field",
|
|
1533
|
+
"order_by_field",
|
|
1534
|
+
"order_direction",
|
|
1535
|
+
"join_model_order_by_field",
|
|
1536
|
+
"join_model_order_direction"
|
|
1537
|
+
]);
|
|
1538
|
+
var KNOWN_UNIQUE_CONSTRAINT_KEYS = /* @__PURE__ */ new Set(["name", "fields"]);
|
|
1539
|
+
function checkUnknownKeys(raw, known, context, strict) {
|
|
1540
|
+
if (!strict) return;
|
|
1541
|
+
for (const key of Object.keys(raw)) {
|
|
1542
|
+
if (!known.has(key)) {
|
|
1543
|
+
throw new Error(
|
|
1544
|
+
`${context}: unknown key "${key}". Allowed: ${[...known].join(", ")}`
|
|
1545
|
+
);
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
function parseFieldOptions(raw, context, strict) {
|
|
1510
1550
|
if (!raw.type || !VALID_FIELD_TYPES.has(raw.type)) {
|
|
1511
1551
|
throw new Error(
|
|
1512
1552
|
`Invalid field type "${raw.type}". Must be one of: ${[...VALID_FIELD_TYPES].join(", ")}`
|
|
1513
1553
|
);
|
|
1514
1554
|
}
|
|
1555
|
+
checkUnknownKeys(raw, KNOWN_FIELD_KEYS, context, strict);
|
|
1515
1556
|
const opts = { type: raw.type };
|
|
1516
1557
|
if (raw.indexed === true) opts.indexed = true;
|
|
1517
1558
|
if (raw.unique === true) opts.unique = true;
|
|
@@ -1527,8 +1568,9 @@ function requireField(raw, field, context) {
|
|
|
1527
1568
|
throw new Error(`Relationship ${context}: missing required field "${field}"`);
|
|
1528
1569
|
}
|
|
1529
1570
|
}
|
|
1530
|
-
function parseRelationship(raw) {
|
|
1571
|
+
function parseRelationship(raw, context, strict) {
|
|
1531
1572
|
const type = raw.type;
|
|
1573
|
+
checkUnknownKeys(raw, KNOWN_RELATIONSHIP_KEYS, context, strict);
|
|
1532
1574
|
if (type === "refersTo") {
|
|
1533
1575
|
requireField(raw, "model", "refersTo");
|
|
1534
1576
|
requireField(raw, "related_id_field", "refersTo");
|
|
@@ -1570,7 +1612,8 @@ function parseRelationship(raw) {
|
|
|
1570
1612
|
}
|
|
1571
1613
|
throw new Error(`Unknown relationship type: ${type}`);
|
|
1572
1614
|
}
|
|
1573
|
-
function loadSchemaFromTomlString(tomlString) {
|
|
1615
|
+
function loadSchemaFromTomlString(tomlString, options = {}) {
|
|
1616
|
+
const strict = options.strict !== false;
|
|
1574
1617
|
const parsed = (0, import_smol_toml.parse)(tomlString);
|
|
1575
1618
|
const models = parsed.models;
|
|
1576
1619
|
if (!models || typeof models !== "object") {
|
|
@@ -1578,10 +1621,20 @@ function loadSchemaFromTomlString(tomlString) {
|
|
|
1578
1621
|
}
|
|
1579
1622
|
const schemas = [];
|
|
1580
1623
|
for (const [modelName, modelDef] of Object.entries(models)) {
|
|
1624
|
+
checkUnknownKeys(
|
|
1625
|
+
modelDef,
|
|
1626
|
+
KNOWN_MODEL_KEYS,
|
|
1627
|
+
`[models.${modelName}]`,
|
|
1628
|
+
strict
|
|
1629
|
+
);
|
|
1581
1630
|
const fields = {};
|
|
1582
1631
|
if (modelDef.fields) {
|
|
1583
1632
|
for (const [fieldName, fieldDef] of Object.entries(modelDef.fields)) {
|
|
1584
|
-
fields[fieldName] = parseFieldOptions(
|
|
1633
|
+
fields[fieldName] = parseFieldOptions(
|
|
1634
|
+
fieldDef,
|
|
1635
|
+
`[models.${modelName}.fields.${fieldName}]`,
|
|
1636
|
+
strict
|
|
1637
|
+
);
|
|
1585
1638
|
}
|
|
1586
1639
|
}
|
|
1587
1640
|
let relationships;
|
|
@@ -1590,24 +1643,36 @@ function loadSchemaFromTomlString(tomlString) {
|
|
|
1590
1643
|
for (const [relName, relDef] of Object.entries(
|
|
1591
1644
|
modelDef.relationships
|
|
1592
1645
|
)) {
|
|
1593
|
-
relationships[relName] = parseRelationship(
|
|
1646
|
+
relationships[relName] = parseRelationship(
|
|
1647
|
+
relDef,
|
|
1648
|
+
`[models.${modelName}.relationships.${relName}]`,
|
|
1649
|
+
strict
|
|
1650
|
+
);
|
|
1594
1651
|
}
|
|
1595
1652
|
}
|
|
1596
1653
|
let uniqueConstraints;
|
|
1597
1654
|
if (modelDef.unique_constraints) {
|
|
1598
1655
|
uniqueConstraints = [];
|
|
1599
1656
|
for (const raw of modelDef.unique_constraints) {
|
|
1657
|
+
checkUnknownKeys(
|
|
1658
|
+
raw,
|
|
1659
|
+
KNOWN_UNIQUE_CONSTRAINT_KEYS,
|
|
1660
|
+
`[[models.${modelName}.unique_constraints]]`,
|
|
1661
|
+
strict
|
|
1662
|
+
);
|
|
1600
1663
|
uniqueConstraints.push({
|
|
1601
1664
|
name: raw.name,
|
|
1602
1665
|
fields: [...raw.fields]
|
|
1603
1666
|
});
|
|
1604
1667
|
}
|
|
1605
1668
|
}
|
|
1669
|
+
const className = typeof modelDef.class_name === "string" ? modelDef.class_name : void 0;
|
|
1606
1670
|
schemas.push(
|
|
1607
1671
|
defineModelSchema({
|
|
1608
1672
|
name: modelName,
|
|
1609
1673
|
fields,
|
|
1610
1674
|
options: {
|
|
1675
|
+
className,
|
|
1611
1676
|
uniqueConstraints,
|
|
1612
1677
|
relationships
|
|
1613
1678
|
}
|
package/dist/cloudflare.d.cts
CHANGED
|
@@ -40,6 +40,13 @@ interface UniqueConstraintConfig {
|
|
|
40
40
|
}
|
|
41
41
|
interface ModelOptions {
|
|
42
42
|
name: string;
|
|
43
|
+
/**
|
|
44
|
+
* Optional PascalCase class name. Used by the v2 codegen to drive
|
|
45
|
+
* generated TypeScript class names (and relationship method names that
|
|
46
|
+
* derive from a target's class name). When absent, the v2 codegen
|
|
47
|
+
* falls back to suffix-based singularization of `name`.
|
|
48
|
+
*/
|
|
49
|
+
className?: string;
|
|
43
50
|
uniqueConstraints?: UniqueConstraintConfig[];
|
|
44
51
|
relationships?: Record<string, RelationshipConfig>;
|
|
45
52
|
}
|
|
@@ -346,6 +353,7 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
346
353
|
permissionHint: DocumentPermissionHint;
|
|
347
354
|
}>;
|
|
348
355
|
protected static documentYMaps: Map<string, Y.Map<any>>;
|
|
356
|
+
private static _observedStringSetMaps;
|
|
349
357
|
private _localChanges;
|
|
350
358
|
private _isDirty;
|
|
351
359
|
private _isLoadingFromYjs;
|
|
@@ -420,7 +428,17 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
420
428
|
added: Record<string, any>;
|
|
421
429
|
modified: Record<string, any>;
|
|
422
430
|
removed: string[];
|
|
431
|
+
stringSetChanges: Record<string, {
|
|
432
|
+
additions: Set<string>;
|
|
433
|
+
removals: Set<string>;
|
|
434
|
+
}>;
|
|
423
435
|
};
|
|
436
|
+
/**
|
|
437
|
+
* Apply a stringset change set to the parent record's Y.Map by mutating a
|
|
438
|
+
* nested Y.Map keyed by member. Migrates from a legacy plain-object value
|
|
439
|
+
* if the field hasn't been touched since the wire-format change in #561.
|
|
440
|
+
*/
|
|
441
|
+
private applyStringSetChangeToYMap;
|
|
424
442
|
/**
|
|
425
443
|
* Deep equality check for comparing field values
|
|
426
444
|
*/
|
|
@@ -522,6 +540,20 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
522
540
|
* Execute a callback with automatic transaction handling for all modified models
|
|
523
541
|
*/
|
|
524
542
|
static withTransaction<T>(callback: () => Promise<T> | T): Promise<T>;
|
|
543
|
+
/**
|
|
544
|
+
* Attach a one-shot observer to a nested-Y.Map stringset field. Calls
|
|
545
|
+
* notifyListeners() when the nested map's keys change (i.e. when a remote
|
|
546
|
+
* member arrives via Y.applyUpdate, or a local per-member set/delete).
|
|
547
|
+
* Idempotent — re-calling on the same Y.Map is a no-op.
|
|
548
|
+
*/
|
|
549
|
+
protected static observeStringSetMapOnce(nestedMap: Y.Map<any>): void;
|
|
550
|
+
/**
|
|
551
|
+
* Walk the schema's stringset fields on `recordYMap` and observe any nested
|
|
552
|
+
* Y.Map values. Called from observer setup and from the parent observer body
|
|
553
|
+
* so newly-arrived stringset Y.Maps (local migration or remote create) get
|
|
554
|
+
* an observer too.
|
|
555
|
+
*/
|
|
556
|
+
protected static attachStringSetObserversToRecord(recordYMap: Y.Map<any>, schema: any): void;
|
|
525
557
|
/**
|
|
526
558
|
* Sets up deep observation on a nested YMap to sync field-level changes to the database
|
|
527
559
|
*/
|
|
@@ -1476,10 +1508,22 @@ interface DefinedModelSchema<TFields extends Record<string, FieldOptions> = Reco
|
|
|
1476
1508
|
* - Compound unique constraints are [[models.*.unique_constraints]]
|
|
1477
1509
|
*/
|
|
1478
1510
|
|
|
1511
|
+
interface LoadSchemaOptions {
|
|
1512
|
+
/**
|
|
1513
|
+
* When true (default), throw on unknown keys at the model, field,
|
|
1514
|
+
* relationship, and unique-constraint level. When false, unknown
|
|
1515
|
+
* keys are silently ignored (legacy behavior).
|
|
1516
|
+
*/
|
|
1517
|
+
strict?: boolean;
|
|
1518
|
+
}
|
|
1479
1519
|
/**
|
|
1480
1520
|
* Parse a TOML string and return an array of DefinedModelSchema objects.
|
|
1521
|
+
*
|
|
1522
|
+
* By default operates in strict mode: unknown keys at the model, field,
|
|
1523
|
+
* relationship, or unique-constraint level cause an error. Pass
|
|
1524
|
+
* `{ strict: false }` to silently ignore unknown keys (legacy behavior).
|
|
1481
1525
|
*/
|
|
1482
|
-
declare function loadSchemaFromTomlString(tomlString: string): DefinedModelSchema[];
|
|
1526
|
+
declare function loadSchemaFromTomlString(tomlString: string, options?: LoadSchemaOptions): DefinedModelSchema[];
|
|
1483
1527
|
|
|
1484
1528
|
/**
|
|
1485
1529
|
* Meta Sync — writes _meta_* YMaps into a YDoc.
|
package/dist/cloudflare.d.ts
CHANGED
|
@@ -40,6 +40,13 @@ interface UniqueConstraintConfig {
|
|
|
40
40
|
}
|
|
41
41
|
interface ModelOptions {
|
|
42
42
|
name: string;
|
|
43
|
+
/**
|
|
44
|
+
* Optional PascalCase class name. Used by the v2 codegen to drive
|
|
45
|
+
* generated TypeScript class names (and relationship method names that
|
|
46
|
+
* derive from a target's class name). When absent, the v2 codegen
|
|
47
|
+
* falls back to suffix-based singularization of `name`.
|
|
48
|
+
*/
|
|
49
|
+
className?: string;
|
|
43
50
|
uniqueConstraints?: UniqueConstraintConfig[];
|
|
44
51
|
relationships?: Record<string, RelationshipConfig>;
|
|
45
52
|
}
|
|
@@ -346,6 +353,7 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
346
353
|
permissionHint: DocumentPermissionHint;
|
|
347
354
|
}>;
|
|
348
355
|
protected static documentYMaps: Map<string, Y.Map<any>>;
|
|
356
|
+
private static _observedStringSetMaps;
|
|
349
357
|
private _localChanges;
|
|
350
358
|
private _isDirty;
|
|
351
359
|
private _isLoadingFromYjs;
|
|
@@ -420,7 +428,17 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
420
428
|
added: Record<string, any>;
|
|
421
429
|
modified: Record<string, any>;
|
|
422
430
|
removed: string[];
|
|
431
|
+
stringSetChanges: Record<string, {
|
|
432
|
+
additions: Set<string>;
|
|
433
|
+
removals: Set<string>;
|
|
434
|
+
}>;
|
|
423
435
|
};
|
|
436
|
+
/**
|
|
437
|
+
* Apply a stringset change set to the parent record's Y.Map by mutating a
|
|
438
|
+
* nested Y.Map keyed by member. Migrates from a legacy plain-object value
|
|
439
|
+
* if the field hasn't been touched since the wire-format change in #561.
|
|
440
|
+
*/
|
|
441
|
+
private applyStringSetChangeToYMap;
|
|
424
442
|
/**
|
|
425
443
|
* Deep equality check for comparing field values
|
|
426
444
|
*/
|
|
@@ -522,6 +540,20 @@ declare class BaseModel implements StringSetChangeTracker {
|
|
|
522
540
|
* Execute a callback with automatic transaction handling for all modified models
|
|
523
541
|
*/
|
|
524
542
|
static withTransaction<T>(callback: () => Promise<T> | T): Promise<T>;
|
|
543
|
+
/**
|
|
544
|
+
* Attach a one-shot observer to a nested-Y.Map stringset field. Calls
|
|
545
|
+
* notifyListeners() when the nested map's keys change (i.e. when a remote
|
|
546
|
+
* member arrives via Y.applyUpdate, or a local per-member set/delete).
|
|
547
|
+
* Idempotent — re-calling on the same Y.Map is a no-op.
|
|
548
|
+
*/
|
|
549
|
+
protected static observeStringSetMapOnce(nestedMap: Y.Map<any>): void;
|
|
550
|
+
/**
|
|
551
|
+
* Walk the schema's stringset fields on `recordYMap` and observe any nested
|
|
552
|
+
* Y.Map values. Called from observer setup and from the parent observer body
|
|
553
|
+
* so newly-arrived stringset Y.Maps (local migration or remote create) get
|
|
554
|
+
* an observer too.
|
|
555
|
+
*/
|
|
556
|
+
protected static attachStringSetObserversToRecord(recordYMap: Y.Map<any>, schema: any): void;
|
|
525
557
|
/**
|
|
526
558
|
* Sets up deep observation on a nested YMap to sync field-level changes to the database
|
|
527
559
|
*/
|
|
@@ -1476,10 +1508,22 @@ interface DefinedModelSchema<TFields extends Record<string, FieldOptions> = Reco
|
|
|
1476
1508
|
* - Compound unique constraints are [[models.*.unique_constraints]]
|
|
1477
1509
|
*/
|
|
1478
1510
|
|
|
1511
|
+
interface LoadSchemaOptions {
|
|
1512
|
+
/**
|
|
1513
|
+
* When true (default), throw on unknown keys at the model, field,
|
|
1514
|
+
* relationship, and unique-constraint level. When false, unknown
|
|
1515
|
+
* keys are silently ignored (legacy behavior).
|
|
1516
|
+
*/
|
|
1517
|
+
strict?: boolean;
|
|
1518
|
+
}
|
|
1479
1519
|
/**
|
|
1480
1520
|
* Parse a TOML string and return an array of DefinedModelSchema objects.
|
|
1521
|
+
*
|
|
1522
|
+
* By default operates in strict mode: unknown keys at the model, field,
|
|
1523
|
+
* relationship, or unique-constraint level cause an error. Pass
|
|
1524
|
+
* `{ strict: false }` to silently ignore unknown keys (legacy behavior).
|
|
1481
1525
|
*/
|
|
1482
|
-
declare function loadSchemaFromTomlString(tomlString: string): DefinedModelSchema[];
|
|
1526
|
+
declare function loadSchemaFromTomlString(tomlString: string, options?: LoadSchemaOptions): DefinedModelSchema[];
|
|
1483
1527
|
|
|
1484
1528
|
/**
|
|
1485
1529
|
* Meta Sync — writes _meta_* YMaps into a YDoc.
|