@typicalday/firegraph 0.11.1 → 0.12.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 +40 -15
- package/dist/backend-BsR0lnFL.d.ts +200 -0
- package/dist/backend-Ct-fLlkG.d.cts +200 -0
- package/dist/backend.cjs +143 -2
- package/dist/backend.cjs.map +1 -1
- package/dist/backend.d.cts +3 -3
- package/dist/backend.d.ts +3 -3
- package/dist/backend.js +13 -4
- package/dist/backend.js.map +1 -1
- package/dist/chunk-AWW4MUJ5.js +245 -0
- package/dist/chunk-AWW4MUJ5.js.map +1 -0
- package/dist/{chunk-5753Y42M.js → chunk-C2QMD7RY.js} +6 -10
- package/dist/chunk-C2QMD7RY.js.map +1 -0
- package/dist/chunk-EQJUUVFG.js +14 -0
- package/dist/chunk-EQJUUVFG.js.map +1 -0
- package/dist/{chunk-6SB34IPQ.js → chunk-HONQY4HF.js} +100 -28
- package/dist/chunk-HONQY4HF.js.map +1 -0
- package/dist/cloudflare/index.cjs +509 -102
- package/dist/cloudflare/index.cjs.map +1 -1
- package/dist/cloudflare/index.d.cts +45 -17
- package/dist/cloudflare/index.d.ts +45 -17
- package/dist/cloudflare/index.js +265 -74
- package/dist/cloudflare/index.js.map +1 -1
- package/dist/codegen/index.d.cts +1 -1
- package/dist/codegen/index.d.ts +1 -1
- package/dist/index.cjs +291 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +59 -77
- package/dist/index.d.ts +59 -77
- package/dist/index.js +58 -28
- package/dist/index.js.map +1 -1
- package/dist/registry-B1qsVL0E.d.cts +64 -0
- package/dist/registry-Fi074zVa.d.ts +64 -0
- package/dist/{serialization-ZZ7RSDRX.js → serialization-OE2PFZMY.js} +6 -4
- package/dist/{types-BGWxcpI_.d.cts → types-DxYLy8Ol.d.cts} +36 -2
- package/dist/{types-BGWxcpI_.d.ts → types-DxYLy8Ol.d.ts} +36 -2
- package/package.json +8 -3
- package/dist/backend-U-MLShlg.d.ts +0 -97
- package/dist/backend-np4gEVhB.d.cts +0 -97
- package/dist/chunk-5753Y42M.js.map +0 -1
- package/dist/chunk-6SB34IPQ.js.map +0 -1
- package/dist/chunk-R7CRGYY4.js +0 -94
- package/dist/chunk-R7CRGYY4.js.map +0 -1
- /package/dist/{serialization-ZZ7RSDRX.js.map → serialization-OE2PFZMY.js.map} +0 -0
package/dist/cloudflare/index.js
CHANGED
|
@@ -1,14 +1,173 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_CORE_INDEXES,
|
|
3
|
+
META_EDGE_TYPE,
|
|
4
|
+
META_NODE_TYPE,
|
|
3
5
|
NODE_RELATION,
|
|
4
6
|
buildEdgeQueryPlan,
|
|
5
7
|
computeEdgeDocId,
|
|
6
8
|
computeNodeDocId,
|
|
7
|
-
createGraphClientFromBackend
|
|
8
|
-
|
|
9
|
+
createGraphClientFromBackend,
|
|
10
|
+
createMergedRegistry,
|
|
11
|
+
createRegistry,
|
|
12
|
+
generateId
|
|
13
|
+
} from "../chunk-HONQY4HF.js";
|
|
9
14
|
import {
|
|
10
|
-
FiregraphError
|
|
11
|
-
|
|
15
|
+
FiregraphError,
|
|
16
|
+
assertUpdatePayloadExclusive,
|
|
17
|
+
deleteField,
|
|
18
|
+
flattenPatch,
|
|
19
|
+
isDeleteSentinel
|
|
20
|
+
} from "../chunk-AWW4MUJ5.js";
|
|
21
|
+
import {
|
|
22
|
+
SERIALIZATION_TAG
|
|
23
|
+
} from "../chunk-EQJUUVFG.js";
|
|
24
|
+
|
|
25
|
+
// src/internal/sqlite-data-ops.ts
|
|
26
|
+
var FIRESTORE_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
27
|
+
"Timestamp",
|
|
28
|
+
"GeoPoint",
|
|
29
|
+
"VectorValue",
|
|
30
|
+
"DocumentReference",
|
|
31
|
+
"FieldValue"
|
|
32
|
+
]);
|
|
33
|
+
function isFirestoreSpecialType(value) {
|
|
34
|
+
const ctorName = value.constructor?.name;
|
|
35
|
+
if (ctorName && FIRESTORE_TYPE_NAMES.has(ctorName)) return ctorName;
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
var JSON_PATH_KEY_RE = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
39
|
+
function validateJsonPathKey(key, backendLabel) {
|
|
40
|
+
if (key.length === 0) {
|
|
41
|
+
throw new FiregraphError(
|
|
42
|
+
`${backendLabel}: empty JSON path component is not allowed`,
|
|
43
|
+
"INVALID_QUERY"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
if (!JSON_PATH_KEY_RE.test(key)) {
|
|
47
|
+
throw new FiregraphError(
|
|
48
|
+
`${backendLabel}: data field path component "${key}" is not a safe JSON-path identifier. Allowed pattern: /^[A-Za-z_][A-Za-z0-9_-]*$/. Use replaceNode/replaceEdge (full-data overwrite) for keys with reserved characters (whitespace, dots, brackets, quotes, etc.).`,
|
|
49
|
+
"INVALID_QUERY"
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function jsonBind(value, backendLabel) {
|
|
54
|
+
if (value === void 0) return "null";
|
|
55
|
+
if (value !== null && typeof value === "object") {
|
|
56
|
+
const firestoreType = isFirestoreSpecialType(value);
|
|
57
|
+
if (firestoreType) {
|
|
58
|
+
throw new FiregraphError(
|
|
59
|
+
`${backendLabel} cannot persist a Firestore ${firestoreType} value. Convert to a primitive before writing (e.g. \`ts.toMillis()\` for Timestamp).`,
|
|
60
|
+
"INVALID_ARGUMENT"
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return JSON.stringify(value);
|
|
65
|
+
}
|
|
66
|
+
function compileDataOpsExpr(ops, base, params, backendLabel) {
|
|
67
|
+
if (ops.length === 0) return null;
|
|
68
|
+
const deletes = [];
|
|
69
|
+
const sets = [];
|
|
70
|
+
for (const op of ops) (op.delete ? deletes : sets).push(op);
|
|
71
|
+
let expr = base;
|
|
72
|
+
if (deletes.length > 0) {
|
|
73
|
+
const placeholders = deletes.map(() => "?").join(", ");
|
|
74
|
+
expr = `json_remove(${expr}, ${placeholders})`;
|
|
75
|
+
for (const op of deletes) {
|
|
76
|
+
for (const seg of op.path) validateJsonPathKey(seg, backendLabel);
|
|
77
|
+
params.push(`$.${op.path.join(".")}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (sets.length > 0) {
|
|
81
|
+
const pieces = sets.map(() => "?, json(?)").join(", ");
|
|
82
|
+
expr = `json_set(${expr}, ${pieces})`;
|
|
83
|
+
for (const op of sets) {
|
|
84
|
+
for (const seg of op.path) validateJsonPathKey(seg, backendLabel);
|
|
85
|
+
params.push(`$.${op.path.join(".")}`);
|
|
86
|
+
params.push(jsonBind(op.value, backendLabel));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return expr;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/internal/sqlite-payload-guard.ts
|
|
93
|
+
var FIRESTORE_TYPE_NAMES2 = /* @__PURE__ */ new Set([
|
|
94
|
+
"Timestamp",
|
|
95
|
+
"GeoPoint",
|
|
96
|
+
"VectorValue",
|
|
97
|
+
"DocumentReference",
|
|
98
|
+
"FieldValue"
|
|
99
|
+
]);
|
|
100
|
+
function assertJsonSafePayload(data, label) {
|
|
101
|
+
walk(data, [], label);
|
|
102
|
+
}
|
|
103
|
+
function walk(node, path, label) {
|
|
104
|
+
if (node === null || node === void 0) return;
|
|
105
|
+
if (isDeleteSentinel(node)) {
|
|
106
|
+
throw new FiregraphError(
|
|
107
|
+
`${label} backend cannot persist a deleteField() sentinel inside a full-data payload (replaceNode/replaceEdge or first-insert). The sentinel is only valid inside an updateNode/updateEdge dataOps patch. Path: ${formatPath(path)}.`,
|
|
108
|
+
"INVALID_ARGUMENT"
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
const t = typeof node;
|
|
112
|
+
if (t === "symbol" || t === "function") {
|
|
113
|
+
throw new FiregraphError(
|
|
114
|
+
`${label} backend cannot persist a value of type ${t}. JSON.stringify drops it silently. Path: ${formatPath(path)}.`,
|
|
115
|
+
"INVALID_ARGUMENT"
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
if (t === "bigint") {
|
|
119
|
+
throw new FiregraphError(
|
|
120
|
+
`${label} backend cannot persist a value of type bigint. JSON.stringify cannot serialize this type (throws TypeError). Path: ${formatPath(path)}.`,
|
|
121
|
+
"INVALID_ARGUMENT"
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
if (t !== "object") return;
|
|
125
|
+
if (Array.isArray(node)) {
|
|
126
|
+
for (let i = 0; i < node.length; i++) {
|
|
127
|
+
walk(node[i], [...path, String(i)], label);
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const obj = node;
|
|
132
|
+
if (Object.prototype.hasOwnProperty.call(obj, SERIALIZATION_TAG)) {
|
|
133
|
+
const tagValue = obj[SERIALIZATION_TAG];
|
|
134
|
+
throw new FiregraphError(
|
|
135
|
+
`${label} backend cannot persist an object with a \`${SERIALIZATION_TAG}\` key (value: ${formatTagValue(tagValue)}). Recognised tags are valid only on the Firestore backend (migration-sandbox output); a literal \`${SERIALIZATION_TAG}\` field in user data is reserved and not allowed. Path: ${formatPath(path)}.`,
|
|
136
|
+
"INVALID_ARGUMENT"
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
const proto = Object.getPrototypeOf(node);
|
|
140
|
+
if (proto !== null && proto !== Object.prototype) {
|
|
141
|
+
const ctor = node.constructor;
|
|
142
|
+
const ctorName = ctor && typeof ctor.name === "string" ? ctor.name : "<anonymous>";
|
|
143
|
+
if (FIRESTORE_TYPE_NAMES2.has(ctorName)) {
|
|
144
|
+
throw new FiregraphError(
|
|
145
|
+
`${label} backend cannot persist a Firestore ${ctorName} value. Convert to a primitive before writing (e.g. \`ts.toMillis()\` for Timestamp, \`{lat,lng}\` for GeoPoint). Path: ${formatPath(path)}.`,
|
|
146
|
+
"INVALID_ARGUMENT"
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
if (node instanceof Date) return;
|
|
150
|
+
throw new FiregraphError(
|
|
151
|
+
`${label} backend cannot persist a class instance of type ${ctorName}. Only plain objects, arrays, and primitives round-trip safely through JSON storage. Path: ${formatPath(path)}.`,
|
|
152
|
+
"INVALID_ARGUMENT"
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
for (const key of Object.keys(obj)) {
|
|
156
|
+
walk(obj[key], [...path, key], label);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function formatPath(path) {
|
|
160
|
+
return path.length === 0 ? "<root>" : path.map((p) => JSON.stringify(p)).join(" > ");
|
|
161
|
+
}
|
|
162
|
+
function formatTagValue(value) {
|
|
163
|
+
if (value === null) return "null";
|
|
164
|
+
if (value === void 0) return "undefined";
|
|
165
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
166
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
167
|
+
return String(value);
|
|
168
|
+
}
|
|
169
|
+
return typeof value;
|
|
170
|
+
}
|
|
12
171
|
|
|
13
172
|
// src/timestamp.ts
|
|
14
173
|
var GraphTimestampImpl = class _GraphTimestampImpl {
|
|
@@ -37,7 +196,7 @@ var GraphTimestampImpl = class _GraphTimestampImpl {
|
|
|
37
196
|
|
|
38
197
|
// src/internal/sqlite-index-ddl.ts
|
|
39
198
|
var IDENT_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
40
|
-
var
|
|
199
|
+
var JSON_PATH_KEY_RE2 = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
41
200
|
function quoteIdent(name) {
|
|
42
201
|
if (!IDENT_RE.test(name)) {
|
|
43
202
|
throw new FiregraphError(
|
|
@@ -85,7 +244,7 @@ function compileFieldExpr(path, fieldToColumn) {
|
|
|
85
244
|
const suffix = path.slice(5);
|
|
86
245
|
const parts = suffix.split(".");
|
|
87
246
|
for (const part of parts) {
|
|
88
|
-
if (!
|
|
247
|
+
if (!JSON_PATH_KEY_RE2.test(part)) {
|
|
89
248
|
throw new FiregraphError(
|
|
90
249
|
`IndexSpec data path "${path}" has invalid component "${part}". Each component must match /^[A-Za-z_][A-Za-z0-9_-]*$/.`,
|
|
91
250
|
"INVALID_INDEX"
|
|
@@ -180,6 +339,8 @@ function buildDOSchemaStatements(table, options = {}) {
|
|
|
180
339
|
}
|
|
181
340
|
|
|
182
341
|
// src/cloudflare/sql.ts
|
|
342
|
+
var DO_BACKEND_LABEL = "DO SQLite";
|
|
343
|
+
var DO_BACKEND_ERR_LABEL = "DO SQLite backend";
|
|
183
344
|
function compileFieldRef(field) {
|
|
184
345
|
const column = DO_FIELD_TO_COLUMN[field];
|
|
185
346
|
if (column) {
|
|
@@ -188,7 +349,7 @@ function compileFieldRef(field) {
|
|
|
188
349
|
if (field.startsWith("data.")) {
|
|
189
350
|
const suffix = field.slice(5);
|
|
190
351
|
for (const part of suffix.split(".")) {
|
|
191
|
-
validateJsonPathKey(part);
|
|
352
|
+
validateJsonPathKey(part, DO_BACKEND_ERR_LABEL);
|
|
192
353
|
}
|
|
193
354
|
return { expr: `json_extract("data", '$.${suffix}')` };
|
|
194
355
|
}
|
|
@@ -200,18 +361,6 @@ function compileFieldRef(field) {
|
|
|
200
361
|
"INVALID_QUERY"
|
|
201
362
|
);
|
|
202
363
|
}
|
|
203
|
-
var FIRESTORE_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
204
|
-
"Timestamp",
|
|
205
|
-
"GeoPoint",
|
|
206
|
-
"VectorValue",
|
|
207
|
-
"DocumentReference",
|
|
208
|
-
"FieldValue"
|
|
209
|
-
]);
|
|
210
|
-
function isFirestoreSpecialType(value) {
|
|
211
|
-
const ctorName = value.constructor?.name;
|
|
212
|
-
if (ctorName && FIRESTORE_TYPE_NAMES.has(ctorName)) return ctorName;
|
|
213
|
-
return null;
|
|
214
|
-
}
|
|
215
364
|
function bindValue(value) {
|
|
216
365
|
if (value === null || value === void 0) return null;
|
|
217
366
|
if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
|
|
@@ -230,21 +379,6 @@ function bindValue(value) {
|
|
|
230
379
|
}
|
|
231
380
|
return String(value);
|
|
232
381
|
}
|
|
233
|
-
var JSON_PATH_KEY_RE2 = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
234
|
-
function validateJsonPathKey(key) {
|
|
235
|
-
if (key.length === 0) {
|
|
236
|
-
throw new FiregraphError(
|
|
237
|
-
"DO SQLite backend: empty JSON path component is not allowed",
|
|
238
|
-
"INVALID_QUERY"
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
if (!JSON_PATH_KEY_RE2.test(key)) {
|
|
242
|
-
throw new FiregraphError(
|
|
243
|
-
`DO SQLite backend: data field path component "${key}" is not a safe JSON-path identifier. Allowed pattern: /^[A-Za-z_][A-Za-z0-9_-]*$/. Use replaceData (full-data overwrite) for keys with reserved characters (whitespace, dots, brackets, quotes, etc.).`,
|
|
244
|
-
"INVALID_QUERY"
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
382
|
function compileFilter(filter, params) {
|
|
249
383
|
const { expr } = compileFieldRef(filter.field);
|
|
250
384
|
switch (filter.op) {
|
|
@@ -331,11 +465,27 @@ function compileDOSelectByDocId(table, docId) {
|
|
|
331
465
|
params: [docId]
|
|
332
466
|
};
|
|
333
467
|
}
|
|
334
|
-
function compileDOSet(table, docId, record, nowMillis) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
468
|
+
function compileDOSet(table, docId, record, nowMillis, mode) {
|
|
469
|
+
assertJsonSafePayload(record.data, DO_BACKEND_LABEL);
|
|
470
|
+
if (mode === "replace") {
|
|
471
|
+
const sql2 = `INSERT OR REPLACE INTO ${quoteDOIdent(table)} (
|
|
472
|
+
doc_id, a_type, a_uid, axb_type, b_type, b_uid, data, v, created_at, updated_at
|
|
473
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
474
|
+
const params = [
|
|
475
|
+
docId,
|
|
476
|
+
record.aType,
|
|
477
|
+
record.aUid,
|
|
478
|
+
record.axbType,
|
|
479
|
+
record.bType,
|
|
480
|
+
record.bUid,
|
|
481
|
+
JSON.stringify(record.data ?? {}),
|
|
482
|
+
record.v ?? null,
|
|
483
|
+
nowMillis,
|
|
484
|
+
nowMillis
|
|
485
|
+
];
|
|
486
|
+
return { sql: sql2, params };
|
|
487
|
+
}
|
|
488
|
+
const insertParams = [
|
|
339
489
|
docId,
|
|
340
490
|
record.aType,
|
|
341
491
|
record.aUid,
|
|
@@ -347,22 +497,44 @@ function compileDOSet(table, docId, record, nowMillis) {
|
|
|
347
497
|
nowMillis,
|
|
348
498
|
nowMillis
|
|
349
499
|
];
|
|
350
|
-
|
|
500
|
+
const ops = flattenPatch(record.data ?? {});
|
|
501
|
+
const updateParams = [];
|
|
502
|
+
const dataExpr = compileDataOpsExpr(ops, `COALESCE("data", '{}')`, updateParams, DO_BACKEND_ERR_LABEL) ?? `COALESCE("data", '{}')`;
|
|
503
|
+
const sql = `INSERT INTO ${quoteDOIdent(table)} (
|
|
504
|
+
doc_id, a_type, a_uid, axb_type, b_type, b_uid, data, v, created_at, updated_at
|
|
505
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
506
|
+
ON CONFLICT(doc_id) DO UPDATE SET
|
|
507
|
+
"a_type" = excluded."a_type",
|
|
508
|
+
"a_uid" = excluded."a_uid",
|
|
509
|
+
"axb_type" = excluded."axb_type",
|
|
510
|
+
"b_type" = excluded."b_type",
|
|
511
|
+
"b_uid" = excluded."b_uid",
|
|
512
|
+
"data" = ${dataExpr},
|
|
513
|
+
"v" = COALESCE(excluded."v", "v"),
|
|
514
|
+
"created_at" = excluded."created_at",
|
|
515
|
+
"updated_at" = excluded."updated_at"`;
|
|
516
|
+
return { sql, params: [...insertParams, ...updateParams] };
|
|
351
517
|
}
|
|
352
518
|
function compileDOUpdate(table, docId, update, nowMillis) {
|
|
519
|
+
assertUpdatePayloadExclusive(update);
|
|
353
520
|
const setClauses = [];
|
|
354
521
|
const params = [];
|
|
355
522
|
if (update.replaceData) {
|
|
523
|
+
assertJsonSafePayload(update.replaceData, DO_BACKEND_LABEL);
|
|
356
524
|
setClauses.push(`"data" = ?`);
|
|
357
525
|
params.push(JSON.stringify(update.replaceData));
|
|
358
|
-
} else if (update.
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
params
|
|
526
|
+
} else if (update.dataOps && update.dataOps.length > 0) {
|
|
527
|
+
for (const op of update.dataOps) {
|
|
528
|
+
if (!op.delete) assertJsonSafePayload(op.value, DO_BACKEND_LABEL);
|
|
529
|
+
}
|
|
530
|
+
const expr = compileDataOpsExpr(
|
|
531
|
+
update.dataOps,
|
|
532
|
+
`COALESCE("data", '{}')`,
|
|
533
|
+
params,
|
|
534
|
+
DO_BACKEND_ERR_LABEL
|
|
535
|
+
);
|
|
536
|
+
if (expr !== null) {
|
|
537
|
+
setClauses.push(`"data" = ${expr}`);
|
|
366
538
|
}
|
|
367
539
|
}
|
|
368
540
|
if (update.v !== void 0) {
|
|
@@ -458,8 +630,8 @@ var DORPCBatchBackend = class {
|
|
|
458
630
|
this.getStub = getStub;
|
|
459
631
|
}
|
|
460
632
|
ops = [];
|
|
461
|
-
setDoc(docId, record) {
|
|
462
|
-
this.ops.push({ kind: "set", docId, record });
|
|
633
|
+
setDoc(docId, record, mode) {
|
|
634
|
+
this.ops.push({ kind: "set", docId, record, mode });
|
|
463
635
|
}
|
|
464
636
|
updateDoc(docId, update) {
|
|
465
637
|
this.ops.push({ kind: "update", docId, update });
|
|
@@ -509,8 +681,8 @@ var DORPCBackend = class _DORPCBackend {
|
|
|
509
681
|
return wires.map(hydrateDORecord);
|
|
510
682
|
}
|
|
511
683
|
// --- Writes ---
|
|
512
|
-
async setDoc(docId, record) {
|
|
513
|
-
return this.stub._fgSetDoc(docId, record);
|
|
684
|
+
async setDoc(docId, record, mode) {
|
|
685
|
+
return this.stub._fgSetDoc(docId, record, mode);
|
|
514
686
|
}
|
|
515
687
|
async updateDoc(docId, update) {
|
|
516
688
|
return this.stub._fgUpdateDoc(docId, update);
|
|
@@ -697,15 +869,28 @@ function createSiblingClient(client, siblingRootKey) {
|
|
|
697
869
|
}
|
|
698
870
|
|
|
699
871
|
// src/cloudflare/do.ts
|
|
872
|
+
import { DurableObject } from "cloudflare:workers";
|
|
700
873
|
var DEFAULT_OPTIONS = {
|
|
701
874
|
table: "firegraph",
|
|
702
875
|
autoMigrate: true
|
|
703
876
|
};
|
|
704
|
-
var FiregraphDO = class {
|
|
705
|
-
/**
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
877
|
+
var FiregraphDO = class extends DurableObject {
|
|
878
|
+
/**
|
|
879
|
+
* @internal — locally-narrowed alias for `this.ctx`, used only by
|
|
880
|
+
* FiregraphDO's own SQL helpers. Same runtime object as the inherited
|
|
881
|
+
* `this.ctx`, but typed as `DurableObjectStateLike` (just `storage.sql`
|
|
882
|
+
* / `transactionSync` / `blockConcurrencyWhile`) so internal calls
|
|
883
|
+
* don't trip over workers-types' stricter
|
|
884
|
+
* `SqlStorage.exec<T extends Record<string, SqlStorageValue>>`
|
|
885
|
+
* constraint vs the `Record<string, unknown>` rows firegraph passes.
|
|
886
|
+
*
|
|
887
|
+
* **Subclasses should use `this.ctx`, not `this.state`.** `this.state`
|
|
888
|
+
* deliberately exposes only the slice FiregraphDO needs internally;
|
|
889
|
+
* subclasses that want `id`, `acceptWebSocket`, `setAlarm`, `getAlarm`,
|
|
890
|
+
* `waitUntil`, `props`, etc. must reach for the inherited `this.ctx`
|
|
891
|
+
* (the full workers-types `DurableObjectState`).
|
|
892
|
+
*/
|
|
893
|
+
state;
|
|
709
894
|
/** @internal — table name used by every compiled statement. */
|
|
710
895
|
table;
|
|
711
896
|
/** @internal — registry consulted by `runSchema` for per-entry indexes. */
|
|
@@ -713,8 +898,8 @@ var FiregraphDO = class {
|
|
|
713
898
|
/** @internal — overrides `DEFAULT_CORE_INDEXES` when set. */
|
|
714
899
|
coreIndexes;
|
|
715
900
|
constructor(ctx, env, options = {}) {
|
|
716
|
-
|
|
717
|
-
this.
|
|
901
|
+
super(ctx, env);
|
|
902
|
+
this.state = ctx;
|
|
718
903
|
const table = options.table ?? DEFAULT_OPTIONS.table;
|
|
719
904
|
validateDOTableName(table);
|
|
720
905
|
this.table = table;
|
|
@@ -722,7 +907,7 @@ var FiregraphDO = class {
|
|
|
722
907
|
this.coreIndexes = options.coreIndexes;
|
|
723
908
|
const autoMigrate = options.autoMigrate ?? DEFAULT_OPTIONS.autoMigrate;
|
|
724
909
|
if (autoMigrate) {
|
|
725
|
-
void this.
|
|
910
|
+
void this.state.blockConcurrencyWhile(async () => {
|
|
726
911
|
this.runSchema();
|
|
727
912
|
});
|
|
728
913
|
}
|
|
@@ -747,14 +932,14 @@ var FiregraphDO = class {
|
|
|
747
932
|
// ---------------------------------------------------------------------------
|
|
748
933
|
// RPC: writes
|
|
749
934
|
// ---------------------------------------------------------------------------
|
|
750
|
-
async _fgSetDoc(docId, record) {
|
|
751
|
-
const stmt = compileDOSet(this.table, docId, record, Date.now());
|
|
935
|
+
async _fgSetDoc(docId, record, mode) {
|
|
936
|
+
const stmt = compileDOSet(this.table, docId, record, Date.now(), mode);
|
|
752
937
|
this.execRun(stmt);
|
|
753
938
|
}
|
|
754
939
|
async _fgUpdateDoc(docId, update) {
|
|
755
940
|
const stmt = compileDOUpdate(this.table, docId, update, Date.now());
|
|
756
941
|
const sqlWithReturning = `${stmt.sql} RETURNING "doc_id"`;
|
|
757
|
-
const rows = this.
|
|
942
|
+
const rows = this.state.storage.sql.exec(sqlWithReturning, ...stmt.params).toArray();
|
|
758
943
|
if (rows.length === 0) {
|
|
759
944
|
throw new FiregraphError(`updateDoc: no document found for doc_id=${docId}`, "NOT_FOUND");
|
|
760
945
|
}
|
|
@@ -778,16 +963,16 @@ var FiregraphDO = class {
|
|
|
778
963
|
const statements = ops.map((op) => {
|
|
779
964
|
switch (op.kind) {
|
|
780
965
|
case "set":
|
|
781
|
-
return compileDOSet(this.table, op.docId, op.record, now);
|
|
966
|
+
return compileDOSet(this.table, op.docId, op.record, now, op.mode);
|
|
782
967
|
case "update":
|
|
783
968
|
return compileDOUpdate(this.table, op.docId, op.update, now);
|
|
784
969
|
case "delete":
|
|
785
970
|
return compileDODelete(this.table, op.docId);
|
|
786
971
|
}
|
|
787
972
|
});
|
|
788
|
-
this.
|
|
973
|
+
this.state.storage.transactionSync(() => {
|
|
789
974
|
for (const stmt of statements) {
|
|
790
|
-
this.
|
|
975
|
+
this.state.storage.sql.exec(stmt.sql, ...stmt.params).toArray();
|
|
791
976
|
}
|
|
792
977
|
});
|
|
793
978
|
}
|
|
@@ -836,9 +1021,9 @@ var FiregraphDO = class {
|
|
|
836
1021
|
};
|
|
837
1022
|
}
|
|
838
1023
|
try {
|
|
839
|
-
this.
|
|
1024
|
+
this.state.storage.transactionSync(() => {
|
|
840
1025
|
for (const stmt of statements) {
|
|
841
|
-
this.
|
|
1026
|
+
this.state.storage.sql.exec(stmt.sql, ...stmt.params).toArray();
|
|
842
1027
|
}
|
|
843
1028
|
});
|
|
844
1029
|
return {
|
|
@@ -878,9 +1063,9 @@ var FiregraphDO = class {
|
|
|
878
1063
|
}
|
|
879
1064
|
const deleteStmts = docIds.map((id) => compileDODelete(this.table, id));
|
|
880
1065
|
try {
|
|
881
|
-
this.
|
|
1066
|
+
this.state.storage.transactionSync(() => {
|
|
882
1067
|
for (const stmt of deleteStmts) {
|
|
883
|
-
this.
|
|
1068
|
+
this.state.storage.sql.exec(stmt.sql, ...stmt.params).toArray();
|
|
884
1069
|
}
|
|
885
1070
|
});
|
|
886
1071
|
return { deleted: deleteStmts.length, batches: 1, errors: [] };
|
|
@@ -914,21 +1099,27 @@ var FiregraphDO = class {
|
|
|
914
1099
|
registry: this.registry
|
|
915
1100
|
});
|
|
916
1101
|
for (const sql of statements) {
|
|
917
|
-
this.
|
|
1102
|
+
this.state.storage.sql.exec(sql).toArray();
|
|
918
1103
|
}
|
|
919
1104
|
}
|
|
920
1105
|
execAll(stmt) {
|
|
921
|
-
return this.
|
|
1106
|
+
return this.state.storage.sql.exec(stmt.sql, ...stmt.params).toArray();
|
|
922
1107
|
}
|
|
923
1108
|
execRun(stmt) {
|
|
924
|
-
this.
|
|
1109
|
+
this.state.storage.sql.exec(stmt.sql, ...stmt.params).toArray();
|
|
925
1110
|
}
|
|
926
1111
|
};
|
|
927
1112
|
export {
|
|
928
1113
|
DORPCBackend,
|
|
929
1114
|
FiregraphDO,
|
|
1115
|
+
META_EDGE_TYPE,
|
|
1116
|
+
META_NODE_TYPE,
|
|
930
1117
|
buildDOSchemaStatements,
|
|
931
1118
|
createDOClient,
|
|
932
|
-
|
|
1119
|
+
createMergedRegistry,
|
|
1120
|
+
createRegistry,
|
|
1121
|
+
createSiblingClient,
|
|
1122
|
+
deleteField,
|
|
1123
|
+
generateId
|
|
933
1124
|
};
|
|
934
1125
|
//# sourceMappingURL=index.js.map
|