@mcp-b/do-runtime 0.3.5 → 0.4.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/dist/gate.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"gate.js","names":[],"sources":["../src/gate.ts"],"sourcesContent":["/* @do-runtime-gated */\n\nimport {\n tryCurrentContinuation,\n tryCurrentIoContext,\n type IoContext,\n} from \"./io/io-context\";\n\ntype Publication = {\n readonly publish: () => Promise<void>;\n readonly reject: (exception: unknown) => void;\n};\n\ntype Outcome<T> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly exception: unknown };\n\nconst TRANSFORMED_AWAIT = Symbol(\"@mcp-b/do-runtime/transformed-await\");\nconst warnedUngatedAwaits = new Set<string>();\n\ntype TransformedAwait<T> = {\n readonly [TRANSFORMED_AWAIT]: true;\n readonly context: IoContext;\n readonly outcome: Outcome<T>;\n};\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n (typeof value === \"object\" && value !== null) ||\n typeof value === \"function\"\n ) && typeof Reflect.get(value, \"then\") === \"function\";\n}\n\n/** Re-enter the actor that owns this transformed await; fail open outside actors. */\nexport function __gate<T>(value: T): T | Promise<Awaited<T>> {\n const context = tryCurrentIoContext();\n if (!isThenable(value) && context === undefined) return value;\n if (context === undefined) return value;\n return resumeWithContext(context, Promise.resolve(value));\n}\n\n/** Capture an actor await without publishing its context before the continuation runs. */\nexport function __gateAwait<T>(\n value: T,\n developmentSource?: string,\n): T | Promise<TransformedAwait<Awaited<T>>> {\n const context = tryCurrentIoContext();\n if (context === undefined) {\n if (developmentSource !== undefined && !warnedUngatedAwaits.has(developmentSource)) {\n warnedUngatedAwaits.add(developmentSource);\n console.warn(\n `do-runtime: transformed await in ${developmentSource} ran without an actor input lock; ` +\n \"an earlier await or entry path is not gated\",\n );\n }\n return value;\n }\n return resumeAwaitWithContext(context, Promise.resolve(value));\n}\n\n/** Restore the captured actor at the first instruction after a transformed await. */\nexport function __resumeAwait<T>(value: T | TransformedAwait<T>): T {\n if (!isTransformedAwait(value)) return value as T;\n\n value.context.restoreContinuation();\n if (value.outcome.ok) return value.outcome.value;\n throw value.outcome.exception;\n}\n\nfunction isTransformedAwait<T>(value: T | TransformedAwait<T>): value is TransformedAwait<T> {\n return Reflect.get(Object(value), TRANSFORMED_AWAIT) === true;\n}\n\nfunction publishOutcome<T, Result>(\n context: IoContext,\n promise: Promise<T>,\n finish: (outcome: Outcome<T>) => Result,\n): Promise<Result> {\n return new Promise<Result>((resolve, reject) => {\n const publish = context.makeTransformReentryCallback((outcome: Outcome<T>) => {\n if (tryCurrentContinuation() !== undefined) {\n schedulePublication({ publish: () => publish(outcome), reject });\n return;\n }\n resolve(finish(outcome));\n });\n void promise.then(\n (value) => {\n schedulePublication({ publish: () => publish({ ok: true, value }), reject });\n },\n (exception: unknown) => {\n schedulePublication({ publish: () => publish({ ok: false, exception }), reject });\n },\n );\n });\n}\n\nfunction resumeAwaitWithContext<T>(\n context: IoContext,\n promise: Promise<T>,\n): Promise<TransformedAwait<T>> {\n return publishOutcome(context, promise, (outcome) => ({\n [TRANSFORMED_AWAIT]: true,\n context,\n outcome,\n }));\n}\n\nfunction resumeWithContext<T>(context: IoContext, promise: Promise<T>): Promise<T> {\n return publishOutcome(context, promise, (outcome) => {\n context.restoreContinuation();\n if (outcome.ok) return outcome.value;\n throw outcome.exception;\n });\n}\n\n/**\n * Resolve one transformed await per task, inside a fresh actor slice. Admission\n * attempts are independent so a blocked actor cannot stall the actor that will\n * unblock it. The task boundary keeps each continuation ambient isolated.\n */\nfunction schedulePublication(publication: Publication): void {\n const channel = new MessageChannel();\n channel.port1.onmessage = () => {\n channel.port1.close();\n channel.port2.close();\n\n void publication.publish().catch((exception: unknown) => {\n publication.reject(exception);\n });\n };\n channel.port2.postMessage(undefined);\n}\n\nfunction iteratorFor<T>(iterable: AsyncIterable<T> | Iterable<T>): AsyncIterator<T> | Iterator<T> {\n const subject = Object(iterable);\n const asyncIterator: unknown = Reflect.get(subject, Symbol.asyncIterator);\n if (typeof asyncIterator === \"function\") return Reflect.apply(asyncIterator, iterable, []);\n const iterator: unknown = Reflect.get(subject, Symbol.iterator);\n if (typeof iterator === \"function\") return Reflect.apply(iterator, iterable, []);\n throw new TypeError(\"value is not async iterable or iterable\");\n}\n\nfunction gatedIterator<T>(iterable: AsyncIterable<T> | Iterable<T>): AsyncIterator<T> {\n const iterator = iteratorFor(iterable);\n\n function invoke(methodName: \"next\" | \"return\" | \"throw\", args: unknown[]): Promise<IteratorResult<T>> {\n const method: unknown = Reflect.get(iterator, methodName);\n if (typeof method === \"function\") {\n return Promise.resolve(__gate(Reflect.apply(method, iterator, args)));\n }\n if (methodName === \"throw\") return Promise.reject(args[0]);\n return Promise.resolve({ done: true, value: args[0] });\n }\n\n return {\n next: (...args: [] | [unknown]) => invoke(\"next\", args),\n return: (value?: unknown) => invoke(\"return\", [value]),\n throw: (exception?: unknown) => invoke(\"throw\", [exception]),\n };\n}\n\n/** Gate every operation used by `for await`, including early return and throw. */\nexport function __gateAsyncIterable<T, IterableType extends AsyncIterable<T> | Iterable<T>>(\n iterable: IterableType,\n): IterableType;\nexport function __gateAsyncIterable<T>(\n iterable: AsyncIterable<T> | Iterable<T>,\n): AsyncIterable<T> | Iterable<T> {\n const wrapper: AsyncIterable<T> = {\n [Symbol.asyncIterator]: () => gatedIterator(iterable),\n };\n if ((typeof iterable !== \"object\" || iterable === null) && typeof iterable !== \"function\") {\n return wrapper;\n }\n return new Proxy(iterable, {\n get(target, property, receiver): unknown {\n if (property === Symbol.asyncIterator) return wrapper[Symbol.asyncIterator];\n return Reflect.get(target, property, receiver);\n },\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"gate.js","names":[],"sources":["../src/gate.ts"],"sourcesContent":["/* @do-runtime-gated */\n\nimport {\n atCheckpointEnd,\n tryCurrentContinuation,\n tryCurrentIoContext,\n type IoContext,\n} from \"./io/io-context\";\n\ntype Publication = {\n readonly publish: () => Promise<void>;\n readonly reject: (exception: unknown) => void;\n};\n\ntype Outcome<T> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly exception: unknown };\n\nconst TRANSFORMED_AWAIT = Symbol(\"@mcp-b/do-runtime/transformed-await\");\n/**\n * Own the gap between publishing an await result and its `__resumeAwait` call.\n * This is deliberately separate from the current-continuation ambient: a\n * reservation serializes publishers but must never make its actor look current.\n * See §2.3 and decision 8.\n */\nconst CURRENT_PUBLICATION = Symbol.for(\"@mcp-b/do-runtime/current-await-publication\");\nconst warnedUngatedAwaits = new Set<string>();\n\ntype PublicationReservation = {\n readonly context: IoContext;\n};\n\ntype TransformedAwait<T> = {\n readonly [TRANSFORMED_AWAIT]: true;\n readonly context: IoContext;\n readonly outcome: Outcome<T>;\n readonly reservation: PublicationReservation;\n};\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n (typeof value === \"object\" && value !== null) ||\n typeof value === \"function\"\n ) && typeof Reflect.get(value, \"then\") === \"function\";\n}\n\n/** Re-enter the actor that owns this transformed await; fail open outside actors. */\nexport function __gate<T>(value: T): T | Promise<Awaited<T>> {\n const context = tryCurrentIoContext();\n if (!isThenable(value) && context === undefined) return value;\n if (context === undefined) return value;\n return resumeWithContext(context, Promise.resolve(value));\n}\n\n/** Capture an actor await without publishing its context before the continuation runs. */\nexport function __gateAwait<T>(\n value: T,\n developmentSource?: string,\n): T | Promise<TransformedAwait<Awaited<T>>> {\n const context = tryCurrentIoContext();\n if (context === undefined) {\n if (developmentSource !== undefined && !warnedUngatedAwaits.has(developmentSource)) {\n warnedUngatedAwaits.add(developmentSource);\n console.warn(\n `do-runtime: transformed await in ${developmentSource} ran without an actor input lock; ` +\n \"an earlier await or entry path is not gated\",\n );\n }\n return value;\n }\n return resumeAwaitWithContext(context, Promise.resolve(value));\n}\n\n/** Restore the captured actor at the first instruction after a transformed await. */\nexport function __resumeAwait<T>(value: T | TransformedAwait<T>): T {\n if (!isTransformedAwait(value)) return value as T;\n\n clearPublication(value.reservation);\n value.context.restoreContinuation();\n if (value.outcome.ok) return value.outcome.value;\n throw value.outcome.exception;\n}\n\nfunction isTransformedAwait<T>(value: T | TransformedAwait<T>): value is TransformedAwait<T> {\n return Reflect.get(Object(value), TRANSFORMED_AWAIT) === true;\n}\n\nfunction currentPublication(): PublicationReservation | undefined {\n return Reflect.get(globalThis, CURRENT_PUBLICATION) as PublicationReservation | undefined;\n}\n\nfunction reservePublication(context: IoContext): PublicationReservation | undefined {\n if (tryCurrentContinuation() !== undefined || currentPublication() !== undefined) return undefined;\n const reservation = { context };\n Reflect.set(globalThis, CURRENT_PUBLICATION, reservation);\n atCheckpointEnd(() => clearPublication(reservation));\n return reservation;\n}\n\nfunction clearPublication(reservation: PublicationReservation): void {\n if (currentPublication() === reservation) {\n Reflect.deleteProperty(globalThis, CURRENT_PUBLICATION);\n }\n}\n\nfunction publishOutcome<T, Result>(\n context: IoContext,\n promise: Promise<T>,\n finish: (outcome: Outcome<T>, reservation: PublicationReservation) => Result,\n): Promise<Result> {\n return new Promise<Result>((resolve, reject) => {\n const publish = context.makeTransformReentryCallback((outcome: Outcome<T>) => {\n const reservation = reservePublication(context);\n if (reservation === undefined) {\n schedulePublication({ publish: () => publish(outcome), reject });\n return;\n }\n resolve(finish(outcome, reservation));\n });\n void promise.then(\n (value) => {\n schedulePublication({ publish: () => publish({ ok: true, value }), reject });\n },\n (exception: unknown) => {\n schedulePublication({ publish: () => publish({ ok: false, exception }), reject });\n },\n );\n });\n}\n\nfunction resumeAwaitWithContext<T>(\n context: IoContext,\n promise: Promise<T>,\n): Promise<TransformedAwait<T>> {\n return publishOutcome(context, promise, (outcome, reservation) => ({\n [TRANSFORMED_AWAIT]: true,\n context,\n outcome,\n reservation,\n }));\n}\n\nfunction resumeWithContext<T>(context: IoContext, promise: Promise<T>): Promise<T> {\n return publishOutcome(context, promise, (outcome, reservation) => {\n clearPublication(reservation);\n context.restoreContinuation();\n if (outcome.ok) return outcome.value;\n throw outcome.exception;\n });\n}\n\n/**\n * Resolve one transformed await per task, inside a fresh actor slice. Admission\n * attempts are independent so a blocked actor cannot stall the actor that will\n * unblock it. The task boundary keeps each continuation ambient isolated.\n */\nfunction schedulePublication(publication: Publication): void {\n const channel = new MessageChannel();\n channel.port1.onmessage = () => {\n channel.port1.close();\n channel.port2.close();\n\n void publication.publish().catch((exception: unknown) => {\n publication.reject(exception);\n });\n };\n channel.port2.postMessage(undefined);\n}\n\nfunction iteratorFor<T>(iterable: AsyncIterable<T> | Iterable<T>): AsyncIterator<T> | Iterator<T> {\n const subject = Object(iterable);\n const asyncIterator: unknown = Reflect.get(subject, Symbol.asyncIterator);\n if (typeof asyncIterator === \"function\") return Reflect.apply(asyncIterator, iterable, []);\n const iterator: unknown = Reflect.get(subject, Symbol.iterator);\n if (typeof iterator === \"function\") return Reflect.apply(iterator, iterable, []);\n throw new TypeError(\"value is not async iterable or iterable\");\n}\n\nfunction gatedIterator<T>(iterable: AsyncIterable<T> | Iterable<T>): AsyncIterator<T> {\n const iterator = iteratorFor(iterable);\n\n function invoke(methodName: \"next\" | \"return\" | \"throw\", args: unknown[]): Promise<IteratorResult<T>> {\n const method: unknown = Reflect.get(iterator, methodName);\n if (typeof method === \"function\") {\n return Promise.resolve(__gate(Reflect.apply(method, iterator, args)));\n }\n if (methodName === \"throw\") return Promise.reject(args[0]);\n return Promise.resolve({ done: true, value: args[0] });\n }\n\n return {\n next: (...args: [] | [unknown]) => invoke(\"next\", args),\n return: (value?: unknown) => invoke(\"return\", [value]),\n throw: (exception?: unknown) => invoke(\"throw\", [exception]),\n };\n}\n\n/** Gate every operation used by `for await`, including early return and throw. */\nexport function __gateAsyncIterable<T, IterableType extends AsyncIterable<T> | Iterable<T>>(\n iterable: IterableType,\n): IterableType;\nexport function __gateAsyncIterable<T>(\n iterable: AsyncIterable<T> | Iterable<T>,\n): AsyncIterable<T> | Iterable<T> {\n const wrapper: AsyncIterable<T> = {\n [Symbol.asyncIterator]: () => gatedIterator(iterable),\n };\n if ((typeof iterable !== \"object\" || iterable === null) && typeof iterable !== \"function\") {\n return wrapper;\n }\n return new Proxy(iterable, {\n get(target, property, receiver): unknown {\n if (property === Symbol.asyncIterator) return wrapper[Symbol.asyncIterator];\n return Reflect.get(target, property, receiver);\n },\n });\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { a as hasUserErrorDetail, c as setUserErrorDetail, d as tryCurrentSlice, f as CanceledError, i as captureGateStack, m as OutputGate, n as IoContext, o as isExceptionFromInputGateBroken, p as InputGate, r as atCheckpointEnd, s as requireInputLock, t as BrokenActorError, u as tryCurrentIoContext } from "./chunks/io-context-RmmjNtwm.js";
2
2
  import { RpcTarget as RpcTarget$1 } from "./cloudflare-workers.js";
3
- import { a as getInt64, c as isNull, i as getBlob, o as getText, r as SqliteDatabase, s as hasCurrentSqliteTable } from "./chunks/sqlite-DFg92Tgt.js";
3
+ import { a as SqliteDatabase, c as getText, l as hasCurrentSqliteTable, o as getBlob, s as getInt64, t as ensureRuntimeStorageVersion, u as isNull } from "./chunks/sqlite-migrations-DsWmLP_B.js";
4
4
  import { ALARM_RETRY_MAX_TRIES, ALARM_RETRY_START_SECONDS, AlarmScheduler, RETRY_BACKOFF_MAX, RETRY_JITTER_FACTOR, alarmRetryDelayMs } from "./server/alarm-scheduler.js";
5
5
  import { deserialize, serialize } from "@ungap/structured-clone";
6
6
  import { RpcTarget, newMessagePortRpcSession } from "capnweb";
@@ -1119,6 +1119,247 @@ function refuseTransactionControl(statement) {
1119
1119
  if (TRANSACTION_CONTROL.test(code)) SqlStorageRegulator.allowTransactions();
1120
1120
  }
1121
1121
  /**
1122
+ * ← the message a `SQLITE_DENY` from the authorizer surfaces to JavaScript,
1123
+ * byte-identical so a caller matching on it ports unchanged.
1124
+ */
1125
+ var SQL_NOT_AUTHORIZED_MESSAGE = "not authorized: SQLITE_AUTH";
1126
+ /** Comments are never code. String literals STAY: pragma arguments may be quoted. */
1127
+ var NOT_COMMENT = /--[^\n]*|\/\*[\s\S]*?\*\//g;
1128
+ /** Cheap pre-test; `PRAGMA` and the `pragma_` functions both contain it. */
1129
+ var PRAGMA_HINT = /pragma/i;
1130
+ /** `PRAGMA [schema.]name`, then `= value`, `(argument)`, or nothing. */
1131
+ var PRAGMA_STATEMENT = /^\s*PRAGMA\s+(?:[A-Za-z_][A-Za-z0-9_$]*\s*\.\s*)?([A-Za-z_][A-Za-z0-9_$]*)(?:\s*=\s*([\s\S]+?)|\s*\(\s*([\s\S]*?)\s*\))?\s*;?\s*$/i;
1132
+ /**
1133
+ * ← `ALLOWED_PRAGMAS` and `PragmaSignature` (`util/sqlite.c++:525-563`),
1134
+ * verbatim. `table_list`, `table_info`, and `table_xinfo` are special-cased
1135
+ * ahead of the table in the authorizer, exactly as upstream's `SQLITE_PRAGMA`
1136
+ * case does (`util/sqlite.c++:1194-1273`).
1137
+ */
1138
+ var ALLOWED_PRAGMAS = /* @__PURE__ */ new Map([
1139
+ ["data_version", "NO_ARG"],
1140
+ ["case_sensitive_like", "BOOLEAN"],
1141
+ ["foreign_keys", "BOOLEAN"],
1142
+ ["defer_foreign_keys", "BOOLEAN"],
1143
+ ["ignore_check_constraints", "BOOLEAN"],
1144
+ ["legacy_alter_table", "BOOLEAN"],
1145
+ ["recursive_triggers", "BOOLEAN"],
1146
+ ["reverse_unordered_selects", "BOOLEAN"],
1147
+ ["foreign_key_check", "OPTIONAL_OBJECT_NAME"],
1148
+ ["foreign_key_list", "OBJECT_NAME"],
1149
+ ["index_info", "OBJECT_NAME"],
1150
+ ["index_list", "OBJECT_NAME"],
1151
+ ["index_xinfo", "OBJECT_NAME"],
1152
+ ["quick_check", "NULL_NUMBER_OR_OBJECT_NAME"],
1153
+ ["optimize", "NULL_OR_NUMBER"]
1154
+ ]);
1155
+ /** Upstream compares the eight literal forms as PREFIXES, case-insensitively. */
1156
+ var BOOLEAN_PRAGMA_VALUE = /^(?:true|false|yes|no|on|off|1|0)/i;
1157
+ /**
1158
+ * The pragmas SQLite ships (https://www.sqlite.org/pragma.html), so a
1159
+ * `pragma_X` identifier can be told apart: `X` here means the table-valued
1160
+ * pragma function and follows the allowlist; any other `pragma_`-prefixed
1161
+ * identifier is an ordinary application name, which upstream's authorizer
1162
+ * distinguishes by resolution and the conformance suite pins.
1163
+ */
1164
+ var SQLITE_PRAGMA_NAMES = /* @__PURE__ */ new Set([
1165
+ "analysis_limit",
1166
+ "application_id",
1167
+ "auto_vacuum",
1168
+ "automatic_index",
1169
+ "busy_timeout",
1170
+ "cache_size",
1171
+ "cache_spill",
1172
+ "case_sensitive_like",
1173
+ "cell_size_check",
1174
+ "checkpoint_fullfsync",
1175
+ "collation_list",
1176
+ "compile_options",
1177
+ "data_version",
1178
+ "database_list",
1179
+ "defer_foreign_keys",
1180
+ "encoding",
1181
+ "foreign_key_check",
1182
+ "foreign_key_list",
1183
+ "foreign_keys",
1184
+ "freelist_count",
1185
+ "full_column_names",
1186
+ "fullfsync",
1187
+ "function_list",
1188
+ "hard_heap_limit",
1189
+ "ignore_check_constraints",
1190
+ "incremental_vacuum",
1191
+ "index_info",
1192
+ "index_list",
1193
+ "index_xinfo",
1194
+ "integrity_check",
1195
+ "journal_mode",
1196
+ "journal_size_limit",
1197
+ "legacy_alter_table",
1198
+ "legacy_file_format",
1199
+ "locking_mode",
1200
+ "max_page_count",
1201
+ "mmap_size",
1202
+ "module_list",
1203
+ "optimize",
1204
+ "page_count",
1205
+ "page_size",
1206
+ "pragma_list",
1207
+ "query_only",
1208
+ "quick_check",
1209
+ "read_uncommitted",
1210
+ "recursive_triggers",
1211
+ "reverse_unordered_selects",
1212
+ "schema_version",
1213
+ "secure_delete",
1214
+ "short_column_names",
1215
+ "shrink_memory",
1216
+ "soft_heap_limit",
1217
+ "synchronous",
1218
+ "table_info",
1219
+ "table_list",
1220
+ "table_xinfo",
1221
+ "temp_store",
1222
+ "threads",
1223
+ "trusted_schema",
1224
+ "user_version",
1225
+ "wal_autocheckpoint",
1226
+ "wal_checkpoint",
1227
+ "writable_schema"
1228
+ ]);
1229
+ /** kj's `tryParseAs` is decimal; keep the same acceptance. */
1230
+ var DECIMAL = /^[+-]?\d+$/;
1231
+ /** One layer of SQL quoting off a pragma argument, any of the four forms. */
1232
+ function unquoted(argument) {
1233
+ const first = argument[0];
1234
+ const last = argument[argument.length - 1];
1235
+ if (argument.length >= 2) {
1236
+ if ((first === "'" || first === "\"" || first === "`") && last === first) return argument.slice(1, -1);
1237
+ if (first === "[" && last === "]") return argument.slice(1, -1);
1238
+ }
1239
+ return argument;
1240
+ }
1241
+ /** ← the `SQLITE_PRAGMA` authorizer case (`util/sqlite.c++:1194-1273`), whole. */
1242
+ function isAllowedPragma(name, argument) {
1243
+ const pragma = name.toLowerCase();
1244
+ if (pragma === "table_list") return true;
1245
+ if (pragma === "table_info" || pragma === "table_xinfo") {
1246
+ if (argument === void 0) return false;
1247
+ return SqlStorageRegulator.isAllowedName(unquoted(argument));
1248
+ }
1249
+ const signature = ALLOWED_PRAGMAS.get(pragma);
1250
+ if (signature === void 0) return false;
1251
+ switch (signature) {
1252
+ case "NO_ARG": return argument === void 0;
1253
+ case "BOOLEAN": return argument === void 0 || BOOLEAN_PRAGMA_VALUE.test(unquoted(argument));
1254
+ case "OBJECT_NAME": return argument !== void 0 && SqlStorageRegulator.isAllowedName(unquoted(argument));
1255
+ case "OPTIONAL_OBJECT_NAME": return argument === void 0 || SqlStorageRegulator.isAllowedName(unquoted(argument));
1256
+ case "NULL_OR_NUMBER": return argument === void 0 || DECIMAL.test(argument);
1257
+ case "NULL_NUMBER_OR_OBJECT_NAME": return argument === void 0 || DECIMAL.test(argument) || SqlStorageRegulator.isAllowedName(unquoted(argument));
1258
+ }
1259
+ }
1260
+ /**
1261
+ * The text-level stand-in for the authorizer's `SQLITE_PRAGMA` case, against
1262
+ * one SQLite-decided statement boundary. Load-bearing beyond fidelity:
1263
+ * `user_version` is where runtime storage versioning keeps its per-file stamp
1264
+ * (`util/sqlite-migrations.ts`), and `writable_schema` would let application
1265
+ * SQL rewrite `sqlite_master` out from under the `_cf_` reservation.
1266
+ *
1267
+ * The `pragma_` table-valued functions reach the same authorizer path
1268
+ * upstream, so they follow the same allowlist here — by pragma NAME only. An
1269
+ * argument the text cannot see (a string literal or a binding) goes unchecked
1270
+ * where upstream's authorizer sees the resolved value; a `_cf_` name smuggled
1271
+ * that way reads schema whose shape is public source anyway, while identifier
1272
+ * arguments stay covered by `requireAllowedNames`. The README divergence row
1273
+ * records this.
1274
+ */
1275
+ function requireAllowedPragmas(statement) {
1276
+ if (!PRAGMA_HINT.test(statement)) return;
1277
+ const code = statement.replace(NOT_COMMENT, " ");
1278
+ const direct = code.match(PRAGMA_STATEMENT);
1279
+ if (direct !== null) {
1280
+ const [, name = "", assigned, called] = direct;
1281
+ const argument = (assigned ?? called)?.trim();
1282
+ if (!isAllowedPragma(name, argument === "" ? void 0 : argument)) throw new Error(SQL_NOT_AUTHORIZED_MESSAGE);
1283
+ return;
1284
+ }
1285
+ if (/^\s*PRAGMA\b/i.test(code)) throw new Error(SQL_NOT_AUTHORIZED_MESSAGE);
1286
+ const literalFree = code.replace(NOT_CODE, " ");
1287
+ for (const [token] of literalFree.matchAll(IDENTIFIER)) {
1288
+ if (token.length <= 7 || token.slice(0, 7).toLowerCase() !== "pragma_") continue;
1289
+ const name = token.slice(7).toLowerCase();
1290
+ if (!SQLITE_PRAGMA_NAMES.has(name)) continue;
1291
+ if (name !== "table_list" && name !== "table_info" && name !== "table_xinfo" && !ALLOWED_PRAGMAS.has(name)) throw new Error(SQL_NOT_AUTHORIZED_MESSAGE);
1292
+ }
1293
+ }
1294
+ /** Everything the untrusted path refuses at one statement boundary. */
1295
+ function regulateUntrustedStatement(statement) {
1296
+ refuseTransactionControl(statement);
1297
+ requireAllowedPragmas(statement);
1298
+ }
1299
+ /** ← `JSG_INHERIT_INTRINSIC(v8::kIteratorPrototype)` (`jsg/iterator.h:1044`). */
1300
+ var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
1301
+ /**
1302
+ * ← the `JSG_ITERATOR` types (`jsg/iterator.h:1036-1050`): `next` and
1303
+ * self-iterability on `%IteratorPrototype%` — which is what carries the ES
1304
+ * iterator helpers; `raw().toArray()` is what Drizzle's durable-sqlite driver
1305
+ * calls — and NOTHING else. No `return`, no `throw` (only the async variant
1306
+ * registers `return_`, `:1069-1085`), so `IteratorClose` after a `break`, a
1307
+ * partial destructuring, or a `take()` is a no-op and a retained iterator
1308
+ * resumes. Results are `JSG_STRUCT(done, value)` in that key order
1309
+ * (`jsg/iterator.h:706-710`).
1310
+ */
1311
+ var RawIterator = class {
1312
+ #pull;
1313
+ constructor(pull) {
1314
+ this.#pull = pull;
1315
+ }
1316
+ next() {
1317
+ const raw = this.#pull();
1318
+ if (raw === void 0) return {
1319
+ done: true,
1320
+ value: void 0
1321
+ };
1322
+ return {
1323
+ done: false,
1324
+ value: asRawRow([...raw])
1325
+ };
1326
+ }
1327
+ [Symbol.iterator]() {
1328
+ return this;
1329
+ }
1330
+ };
1331
+ Object.setPrototypeOf(RawIterator.prototype, IteratorPrototype);
1332
+ Object.defineProperty(RawIterator.prototype, Symbol.toStringTag, {
1333
+ value: "RawIterator",
1334
+ configurable: true
1335
+ });
1336
+ /** ← `RowIterator`, shaped exactly as `RawIterator` above. */
1337
+ var RowIterator = class {
1338
+ #pull;
1339
+ constructor(pull) {
1340
+ this.#pull = pull;
1341
+ }
1342
+ next() {
1343
+ const row = this.#pull();
1344
+ if (row === void 0) return {
1345
+ done: true,
1346
+ value: void 0
1347
+ };
1348
+ return {
1349
+ done: false,
1350
+ value: row
1351
+ };
1352
+ }
1353
+ [Symbol.iterator]() {
1354
+ return this;
1355
+ }
1356
+ };
1357
+ Object.setPrototypeOf(RowIterator.prototype, IteratorPrototype);
1358
+ Object.defineProperty(RowIterator.prototype, Symbol.toStringTag, {
1359
+ value: "RowIterator",
1360
+ configurable: true
1361
+ });
1362
+ /**
1122
1363
  * ← `SqlStorage::Cursor`.
1123
1364
  *
1124
1365
  * `rowsRead` is the one counter that is not upstream's. Upstream reads
@@ -1130,20 +1371,30 @@ function refuseTransactionControl(statement) {
1130
1371
  * undercounts any query that scans more rows than it returns.
1131
1372
  */
1132
1373
  var Cursor = class {
1133
- columnNames;
1374
+ #columnNames;
1134
1375
  #rawRows;
1135
1376
  #rowsWritten;
1136
1377
  #position = 0;
1137
1378
  constructor(state) {
1138
1379
  if (state === void 0) throw new Error(CURSOR_NOT_CONSTRUCTIBLE_MESSAGE);
1139
- this.columnNames = state.columnNames;
1380
+ this.#columnNames = state.columnNames;
1140
1381
  this.#rawRows = state.rawRows;
1141
1382
  this.#rowsWritten = state.rowsWritten;
1142
1383
  }
1384
+ /**
1385
+ * ← `JSG_READONLY_PROTOTYPE_PROPERTY(columnNames)` (`sql.h:210`): a
1386
+ * prototype accessor, not an own field, so a cursor JSON-stringifies to `{}`.
1387
+ */
1388
+ get columnNames() {
1389
+ return this.#columnNames;
1390
+ }
1143
1391
  /** ← `Cursor::next`, whose `RowIterator::Next` is this exact shape. */
1144
1392
  next() {
1145
1393
  const row = this.#nextRow();
1146
- if (row === void 0) return { done: true };
1394
+ if (row === void 0) return {
1395
+ done: true,
1396
+ value: void 0
1397
+ };
1147
1398
  return {
1148
1399
  done: false,
1149
1400
  value: row
@@ -1168,45 +1419,16 @@ var Cursor = class {
1168
1419
  }
1169
1420
  return row;
1170
1421
  }
1171
- /** ← `Cursor::raw`, which shares this cursor's position rather than restarting. */
1422
+ /**
1423
+ * ← `Cursor::raw`, which shares this cursor's position rather than
1424
+ * restarting. The iterator's shape is `RawIterator`'s whole doc comment.
1425
+ */
1172
1426
  raw() {
1173
- const iterator = {
1174
- [Symbol.iterator]() {
1175
- return iterator;
1176
- },
1177
- next: () => {
1178
- const raw = this.#nextRaw();
1179
- if (raw === void 0) return {
1180
- done: true,
1181
- value: void 0
1182
- };
1183
- return {
1184
- done: false,
1185
- value: asRawRow([...raw])
1186
- };
1187
- }
1188
- };
1189
- return iterator;
1427
+ return new RawIterator(() => this.#nextRaw());
1190
1428
  }
1191
- /** ← `JSG_ITERABLE(rows)`. */
1429
+ /** ← `JSG_ITERABLE(rows)`, yielding through the same shared position. */
1192
1430
  [Symbol.iterator]() {
1193
- const iterator = {
1194
- [Symbol.iterator]() {
1195
- return iterator;
1196
- },
1197
- next: () => {
1198
- const row = this.#nextRow();
1199
- if (row === void 0) return {
1200
- done: true,
1201
- value: void 0
1202
- };
1203
- return {
1204
- done: false,
1205
- value: row
1206
- };
1207
- }
1208
- };
1209
- return iterator;
1431
+ return new RowIterator(() => this.#nextRow());
1210
1432
  }
1211
1433
  get rowsRead() {
1212
1434
  return this.#position;
@@ -1226,12 +1448,17 @@ var Cursor = class {
1226
1448
  const raw = this.#nextRaw();
1227
1449
  if (raw === void 0) return void 0;
1228
1450
  const row = {};
1229
- this.columnNames.forEach((name, index) => {
1451
+ this.#columnNames.forEach((name, index) => {
1230
1452
  row[name] = raw[index] ?? null;
1231
1453
  });
1232
1454
  return asRow(row);
1233
1455
  }
1234
1456
  };
1457
+ /** ← the jsg resource-type tag every workerd API object carries (`resource.h`). */
1458
+ Object.defineProperty(Cursor.prototype, Symbol.toStringTag, {
1459
+ value: "Cursor",
1460
+ configurable: true
1461
+ });
1235
1462
  /**
1236
1463
  * ← `SqlStorage::Statement`, which upstream describes as "supported only for
1237
1464
  * backwards compatibility ... it is actually just a wrapper around `exec()`".
@@ -1261,7 +1488,7 @@ var SqlStorage = class {
1261
1488
  const db = this.#owner.getSqliteDb();
1262
1489
  const sqlBindings = bindings.map(toSqlBindingValue);
1263
1490
  requireAllowedNames(query);
1264
- const result = db.run({ regulate: refuseTransactionControl }, query, ...sqlBindings);
1491
+ const result = db.run({ regulate: regulateUntrustedStatement }, query, ...sqlBindings);
1265
1492
  return new Cursor({
1266
1493
  columnNames: [...result.columnNames],
1267
1494
  rawRows: result.rawRows.map((row) => row.map(toSqlStorageValue)),
@@ -1294,7 +1521,7 @@ var SqlStorage = class {
1294
1521
  ingest(query) {
1295
1522
  requireInputLock(this.#ctx, "sql.ingest()");
1296
1523
  requireAllowedNames(query);
1297
- return this.#owner.getSqliteDb().ingest(query, refuseTransactionControl);
1524
+ return this.#owner.getSqliteDb().ingest(query, regulateUntrustedStatement);
1298
1525
  }
1299
1526
  /** ← `SqlStorage::setMaxPageCountForTest`, which is what its name says. */
1300
1527
  setMaxPageCountForTest(count) {
@@ -5827,9 +6054,13 @@ var ActorContainerImpl = class {
5827
6054
  * `state`.
5828
6055
  */
5829
6056
  async function createActorContainer(options) {
5830
- const db = new SqliteDatabase(await options.ports.sql.open(ACTOR_DATABASE_NAME));
6057
+ const actorDb = await options.ports.sql.open(ACTOR_DATABASE_NAME);
6058
+ ensureRuntimeStorageVersion(actorDb, ACTOR_DATABASE_NAME);
6059
+ const db = new SqliteDatabase(actorDb);
5831
6060
  if (options.facet !== void 0) return new ActorContainerImpl(options, db, void 0, options.facet.tree);
5832
- const tree = new ActorTree(await options.ports.sql.open(FACET_DATABASE_NAME), options.ports.facets);
6061
+ const facetDb = await options.ports.sql.open(FACET_DATABASE_NAME);
6062
+ ensureRuntimeStorageVersion(facetDb, FACET_DATABASE_NAME);
6063
+ const tree = new ActorTree(facetDb, options.ports.facets);
5833
6064
  return new ActorContainerImpl(options, db, tree, tree);
5834
6065
  }
5835
6066
  //#endregion