@gaganref/confect-test 10.3.1-fork.91 → 10.3.1-fork.93

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.
Files changed (51) hide show
  1. package/dist/TestConfect.d.ts +26 -0
  2. package/dist/TestConfect.d.ts.map +1 -1
  3. package/dist/TestConfect.js +9 -1
  4. package/dist/TestConfect.js.map +1 -1
  5. package/dist/internal/Attempt.d.ts +14 -1
  6. package/dist/internal/Attempt.d.ts.map +1 -1
  7. package/dist/internal/Attempt.js +18 -1
  8. package/dist/internal/Attempt.js.map +1 -1
  9. package/dist/internal/ConvexTest.d.ts +26 -1
  10. package/dist/internal/ConvexTest.d.ts.map +1 -1
  11. package/dist/internal/ConvexTest.js +55 -27
  12. package/dist/internal/ConvexTest.js.map +1 -1
  13. package/dist/internal/Execution.d.ts +151 -1
  14. package/dist/internal/Execution.d.ts.map +1 -1
  15. package/dist/internal/Execution.js +731 -214
  16. package/dist/internal/Execution.js.map +1 -1
  17. package/dist/internal/KernelQuery.d.ts +8 -3
  18. package/dist/internal/KernelQuery.d.ts.map +1 -1
  19. package/dist/internal/KernelQuery.js +10 -3
  20. package/dist/internal/KernelQuery.js.map +1 -1
  21. package/dist/internal/KernelRefusal.d.ts +134 -0
  22. package/dist/internal/KernelRefusal.d.ts.map +1 -1
  23. package/dist/internal/KernelRefusal.js +134 -1
  24. package/dist/internal/KernelRefusal.js.map +1 -1
  25. package/dist/internal/Metering.d.ts +186 -0
  26. package/dist/internal/Metering.d.ts.map +1 -0
  27. package/dist/internal/Metering.js +401 -0
  28. package/dist/internal/Metering.js.map +1 -0
  29. package/dist/internal/Redaction.d.ts +142 -0
  30. package/dist/internal/Redaction.d.ts.map +1 -0
  31. package/dist/internal/Redaction.js +448 -0
  32. package/dist/internal/Redaction.js.map +1 -0
  33. package/dist/internal/Snapshot.d.ts +298 -0
  34. package/dist/internal/Snapshot.d.ts.map +1 -0
  35. package/dist/internal/Snapshot.js +532 -0
  36. package/dist/internal/Snapshot.js.map +1 -0
  37. package/dist/internal/Subscriptions.d.ts +13 -0
  38. package/dist/internal/Subscriptions.d.ts.map +1 -1
  39. package/dist/internal/Subscriptions.js +27 -3
  40. package/dist/internal/Subscriptions.js.map +1 -1
  41. package/package.json +3 -3
  42. package/src/TestConfect.ts +63 -4
  43. package/src/internal/Attempt.ts +24 -0
  44. package/src/internal/ConvexTest.ts +135 -38
  45. package/src/internal/Execution.ts +1141 -324
  46. package/src/internal/KernelQuery.ts +17 -6
  47. package/src/internal/KernelRefusal.ts +160 -0
  48. package/src/internal/Metering.ts +520 -0
  49. package/src/internal/Redaction.ts +730 -0
  50. package/src/internal/Snapshot.ts +945 -0
  51. package/src/internal/Subscriptions.ts +34 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Redaction.js","names":["KernelRefusal.SnapshotSecretMissing"],"sources":["../../src/internal/Redaction.ts"],"sourcesContent":["import * as DatabaseSchema from \"@confect/server/DatabaseSchema\";\nimport {\n convexToJson,\n jsonToConvex,\n type JSONValue,\n type Value,\n} from \"convex/values\";\nimport * as Result from \"effect/Result\";\nimport type * as Schema from \"effect/Schema\";\nimport * as SchemaAST from \"effect/SchemaAST\";\nimport * as KernelRefusal from \"./KernelRefusal.js\";\nimport type { FunctionPath } from \"./KernelValues.js\";\n\n/**\n * What a marker writes in place of a secret in text and in values: a failure\n * report, a diff, a read record.\n */\nexport const marker = \"[redacted]\";\n\n/**\n * The key of a snapshot's marker object, `{ \"$redacted\": <ref> }`. Convex's\n * encoded JSON allows no object key that starts with `$`, so no stored value\n * reads as a marker.\n */\nexport const markerKey = \"$redacted\";\n\n/**\n * Free text has no schema, so a failure report's message and stack are searched\n * for every kept secret string. A string shorter than this is not searched for,\n * or text that merely shares a few letters would be marked. Values are marked\n * by their schema at any length.\n */\nconst searchableLength = 4;\n\n/**\n * Where a value may hold secrets: the type side of a schema's AST. A walk\n * follows it through the encoded value, so the value bounds the walk.\n */\nexport type Shape = SchemaAST.AST;\n\n/**\n * A shape placed at a path inside a value: a table's schema at a document's\n * root, a job's target arguments at its row's `args.0`.\n */\nexport interface Placement {\n readonly at: ReadonlyArray<string>;\n readonly shape: Shape;\n}\n\nconst isSecretNode = (ast: SchemaAST.AST): boolean =>\n ast._tag === \"Declaration\" &&\n (SchemaAST.resolve(ast)?.[\"representation\"] as { id?: unknown } | undefined)\n ?.id === \"effect/schema/Redacted\";\n\n/**\n * Whether a secret node is reachable from `ast`. A suspension is followed once\n * per ancestry, so a recursive schema ends, and a suspension reused at another\n * path is followed again there.\n */\nconst reachesSecret = (\n ast: SchemaAST.AST,\n ancestry: Set<SchemaAST.AST>,\n): boolean => {\n if (isSecretNode(ast)) return true;\n switch (ast._tag) {\n case \"Objects\":\n return (\n ast.propertySignatures.some((p) => reachesSecret(p.type, ancestry)) ||\n ast.indexSignatures.some((i) => reachesSecret(i.type, ancestry))\n );\n case \"Arrays\":\n return [...ast.elements, ...ast.rest].some((e) =>\n reachesSecret(e, ancestry),\n );\n case \"Union\":\n return ast.types.some((t) => reachesSecret(t, ancestry));\n case \"Declaration\":\n return ast.typeParameters.some((t) => reachesSecret(t, ancestry));\n case \"Suspend\": {\n if (ancestry.has(ast)) return false;\n ancestry.add(ast);\n const found = reachesSecret(ast.thunk(), ancestry);\n ancestry.delete(ast);\n return found;\n }\n default:\n return false;\n }\n};\n\nconst reaches = new WeakMap<SchemaAST.AST, boolean>();\n\n/**\n * Whether `shape` holds a secret anywhere beneath it.\n */\nexport const hasSecret = (shape: Shape): boolean => {\n let found = reaches.get(shape);\n if (found === undefined) {\n found = reachesSecret(shape, new Set());\n reaches.set(shape, found);\n }\n return found;\n};\n\nconst isObject = (json: JSONValue): json is { [key: string]: JSONValue } =>\n typeof json === \"object\" && json !== null && !Array.isArray(json);\n\n/**\n * A Convex encoded leaf, such as `{\"$integer\": …}` or `{\"$bytes\": …}`, or a\n * marker: one key that starts with `$`.\n */\nconst isWrapped = (json: JSONValue): boolean => {\n if (!isObject(json)) return false;\n const keys = Object.keys(json);\n return keys.length === 1 && keys[0]!.startsWith(\"$\");\n};\n\nconst isMarker = (json: JSONValue): boolean =>\n isObject(json) && Object.keys(json).length === 1 && markerKey in json;\n\nconst isRecord = (json: JSONValue): json is { [key: string]: JSONValue } =>\n isObject(json) && !isWrapped(json);\n\n/**\n * Whether `json` can be a value of `ast`, for choosing a union's members. Nodes\n * the walk does not look into fit anything.\n */\nconst fits = (\n ast: SchemaAST.AST,\n json: JSONValue,\n ancestry: Set<SchemaAST.AST> = new Set(),\n): boolean => {\n switch (ast._tag) {\n case \"Objects\":\n return isRecord(json);\n case \"Arrays\":\n return Array.isArray(json);\n case \"String\":\n case \"TemplateLiteral\":\n return typeof json === \"string\";\n case \"Number\":\n return typeof json === \"number\" || (isObject(json) && \"$float\" in json);\n case \"BigInt\":\n return isObject(json) && \"$integer\" in json;\n case \"Boolean\":\n return typeof json === \"boolean\";\n case \"Null\":\n return json === null;\n case \"Literal\":\n return typeof ast.literal === \"bigint\"\n ? isObject(json) && \"$integer\" in json\n : json === ast.literal;\n case \"Union\":\n return ast.types.some((t) => fits(t, json, ancestry));\n case \"Suspend\": {\n if (ancestry.has(ast)) return true;\n ancestry.add(ast);\n const fit = fits(ast.thunk(), json, ancestry);\n ancestry.delete(ast);\n return fit;\n }\n case \"Declaration\":\n // A secret is stored as what its inner type encodes to, so a union\n // member that is a secret fits only those values.\n return (\n !isSecretNode(ast) ||\n ast.typeParameters.some((t) => fits(t, json, ancestry))\n );\n default:\n return true;\n }\n};\n\n/**\n * `json` with `onSecret` applied at every position where `shape` puts a secret.\n * A value whose structure the shape cannot follow, beneath a node that holds a\n * secret, is treated as secret whole: the walk fails closed. A marker is never\n * walked again, so marking is idempotent and overlapping members of a union\n * mark a shared field once.\n */\nconst walk = (\n shape: SchemaAST.AST,\n json: JSONValue,\n onSecret: (value: JSONValue) => JSONValue,\n unconsumed: Set<SchemaAST.AST> = new Set(),\n): JSONValue => {\n if (isMarker(json)) return json;\n if (isSecretNode(shape)) return onSecret(json);\n if (!hasSecret(shape)) return json;\n switch (shape._tag) {\n case \"Objects\": {\n if (!isRecord(json)) return onSecret(json);\n const named = new Map(\n shape.propertySignatures.map((p) => [String(p.name), p.type]),\n );\n return Object.fromEntries(\n Object.entries(json).map(([key, item]) => {\n const type = named.get(key);\n return [\n key,\n type !== undefined\n ? walk(type, item, onSecret)\n : shape.indexSignatures.reduce(\n (value, index) => walk(index.type, value, onSecret),\n item,\n ),\n ];\n }),\n );\n }\n case \"Arrays\": {\n if (!Array.isArray(json)) return onSecret(json);\n const [rest, ...post] = shape.rest;\n return json.map((item, i) => {\n if (i < shape.elements.length)\n return walk(shape.elements[i]!, item, onSecret);\n const fromEnd = json.length - i;\n if (fromEnd <= post.length)\n return walk(post[post.length - fromEnd]!, item, onSecret);\n return rest === undefined ? item : walk(rest, item, onSecret);\n });\n }\n case \"Union\": {\n const members = shape.types.filter((t) => fits(t, json));\n if (members.length === 0) return onSecret(json);\n return members.reduce(\n (value, member) => walk(member, value, onSecret, unconsumed),\n json,\n );\n }\n case \"Suspend\": {\n if (unconsumed.has(shape)) return json;\n unconsumed.add(shape);\n const walked = walk(shape.thunk(), json, onSecret, unconsumed);\n unconsumed.delete(shape);\n return walked;\n }\n case \"Declaration\":\n return shape.typeParameters.reduce(\n (value, parameter) => walk(parameter, value, onSecret, unconsumed),\n json,\n );\n default:\n return onSecret(json);\n }\n};\n\nconst replaceAt = (\n json: JSONValue,\n path: ReadonlyArray<string>,\n replace: (value: JSONValue) => JSONValue,\n): JSONValue => {\n if (path.length === 0) return replace(json);\n const [head, ...rest] = path as [string, ...Array<string>];\n if (Array.isArray(json)) {\n return json.map((item, i) =>\n `${i}` === head ? replaceAt(item, rest, replace) : item,\n );\n }\n if (isRecord(json)) {\n return Object.fromEntries(\n Object.entries(json).map(([key, item]) => [\n key,\n key === head ? replaceAt(item, rest, replace) : item,\n ]),\n );\n }\n return json;\n};\n\nconst walkPlaced = (\n json: JSONValue,\n placements: ReadonlyArray<Placement>,\n onSecret: (value: JSONValue) => JSONValue,\n): JSONValue =>\n placements.reduce(\n (value, { at, shape }) =>\n replaceAt(value, at, (inner) => walk(shape, inner, onSecret)),\n json,\n );\n\n/**\n * Whether the field at `fieldPath` of a document of `shape` holds a secret, or\n * sits under one.\n */\nexport const sensitiveAt = (\n shape: Shape,\n fieldPath: ReadonlyArray<string>,\n): boolean => {\n const at = (\n ast: SchemaAST.AST,\n path: ReadonlyArray<string>,\n ancestry: Set<SchemaAST.AST>,\n ): boolean => {\n if (isSecretNode(ast)) return true;\n if (path.length === 0) return hasSecret(ast);\n const [head, ...rest] = path as [string, ...Array<string>];\n switch (ast._tag) {\n case \"Objects\": {\n const property = ast.propertySignatures.find(\n (p) => String(p.name) === head,\n );\n // A segment is consumed here, so a suspension met again further down\n // the path is a new descent, not a cycle.\n return property !== undefined\n ? at(property.type, rest, new Set())\n : ast.indexSignatures.some((i) => at(i.type, rest, new Set()));\n }\n case \"Union\":\n return ast.types.some((t) => at(t, path, ancestry));\n case \"Declaration\":\n return ast.typeParameters.some((t) => at(t, path, ancestry));\n case \"Suspend\": {\n if (ancestry.has(ast)) return false;\n ancestry.add(ast);\n const found = at(ast.thunk(), path, ancestry);\n ancestry.delete(ast);\n return found;\n }\n default:\n return hasSecret(ast);\n }\n };\n return at(shape, fieldPath, new Set());\n};\n\n/**\n * Which values the kernel treats as secret: the shapes of a table's documents,\n * of a function's arguments and of its return value.\n */\nexport interface Policy {\n readonly table: (componentPath: string, table: string) => Shape | undefined;\n readonly args: (functionPath: FunctionPath) => Shape | undefined;\n readonly returns: (functionPath: FunctionPath) => Shape | undefined;\n}\n\n/**\n * A schema the policy builds the first time it needs it, as Confect's specs and\n * tables keep theirs.\n */\nexport type Lazy = () => Schema.Top;\n\n/**\n * The schemas a policy reads its secret nodes from, by component path, then\n * table name or `module:export`. Row 8's codegen fills this from the Confect\n * specs. A test that declares it by hand writes the same record.\n */\nexport interface Declared {\n readonly tables?: Readonly<Record<string, Readonly<Record<string, Lazy>>>>;\n readonly functions?: Readonly<\n Record<\n string,\n Readonly<\n Record<string, { readonly args?: Lazy; readonly returns?: Lazy }>\n >\n >\n >;\n}\n\nconst memo = <A>(compute: (key: string) => A) => {\n const cache = new Map<string, A>();\n return (key: string): A => {\n if (!cache.has(key)) cache.set(key, compute(key));\n return cache.get(key)!;\n };\n};\n\n/**\n * A policy from `declared`'s schemas. Each schema is built the first time its\n * shape is asked for.\n */\nexport const policy = (declared: Declared): Policy => {\n const split = (key: string) => key.split(\"\\u0000\") as [string, string];\n const table = memo((key) => {\n const [componentPath, name] = split(key);\n return declared.tables?.[componentPath]?.[name]?.().ast;\n });\n const fn = (part: \"args\" | \"returns\") =>\n memo((key) => {\n const [componentPath, udfPath] = split(key);\n return declared.functions?.[componentPath]?.[udfPath]?.[part]?.().ast;\n });\n const args = fn(\"args\");\n const returns = fn(\"returns\");\n return {\n table: (componentPath, name) => table(`${componentPath}\\u0000${name}`),\n args: ({ componentPath, udfPath }) =>\n args(`${componentPath}\\u0000${udfPath}`),\n returns: ({ componentPath, udfPath }) =>\n returns(`${componentPath}\\u0000${udfPath}`),\n };\n};\n\nexport const none: Policy = policy({});\n\n/**\n * Two declarations as one: `second`'s entries win where both name a table or\n * function.\n */\nexport const merge = (first: Declared, second: Declared): Declared => {\n const each = <A>(\n a: Readonly<Record<string, Readonly<Record<string, A>>>> | undefined,\n b: Readonly<Record<string, Readonly<Record<string, A>>>> | undefined,\n ) =>\n Object.fromEntries(\n [...new Set([...Object.keys(a ?? {}), ...Object.keys(b ?? {})])].map(\n (componentPath) => [\n componentPath,\n { ...a?.[componentPath], ...b?.[componentPath] },\n ],\n ),\n );\n return {\n tables: each(first.tables, second.tables),\n functions: each(first.functions, second.functions),\n };\n};\n\n/**\n * A Confect database schema's tables, as a policy's `tables` entry for one\n * component. No table's schema is built until the kernel asks for its shape.\n */\nexport const tablesOf = (\n databaseSchema: DatabaseSchema.AnyWithProps,\n): Readonly<Record<string, Lazy>> =>\n Object.fromEntries(\n Object.values(DatabaseSchema.tables(databaseSchema)).map(\n (table: { readonly tableName: string; readonly Fields: Schema.Top }) => [\n table.tableName,\n () => table.Fields,\n ],\n ),\n );\n\n/**\n * The text a secret leaf can show in free text: a string itself, an int64 as\n * its decimal digits.\n */\nconst leafTexts = (json: JSONValue): Array<string> => {\n if (typeof json === \"string\") return [json];\n if (Array.isArray(json)) return json.flatMap(leafTexts);\n if (isObject(json)) {\n if (\"$integer\" in json) {\n try {\n const integer = jsonToConvex(json);\n return typeof integer === \"bigint\" ? [integer.toString()] : [];\n } catch {\n return [];\n }\n }\n if (isWrapped(json)) return [];\n return Object.values(json).flatMap(leafTexts);\n }\n return [];\n};\n\n/**\n * The raw secrets the kernel has seen under a secret node, in the order it\n * first saw each, with every string a compound secret holds beneath it. This\n * store is replay state: it lives in memory beside the world and is never\n * written to an artifact. A snapshot's markers name entries here by position.\n */\nexport class Secrets {\n private readonly values: Array<JSONValue> = [];\n private readonly refs = new Map<string, number>();\n private readonly texts = new Set<string>();\n\n /**\n * Keep `value` and answer its position. A value kept before answers its first\n * position.\n */\n keep(value: JSONValue): number {\n const key = JSON.stringify(value);\n const known = this.refs.get(key);\n if (known !== undefined) return known;\n this.values.push(value);\n this.refs.set(key, this.values.length - 1);\n for (const text of leafTexts(value)) this.texts.add(text);\n return this.values.length - 1;\n }\n\n raw(ref: number): JSONValue | undefined {\n return this.values[ref];\n }\n\n /**\n * Every kept secret's text long enough to search free text for, longest\n * first, so a secret inside another is never marked half.\n */\n searchable(): ReadonlyArray<string> {\n return [...this.texts]\n .filter((text) => text.length >= searchableLength)\n .sort((a, b) => b.length - a.length);\n }\n\n copy(): Secrets {\n const copy = new Secrets();\n for (const value of this.values) copy.keep(value);\n return copy;\n }\n}\n\n/**\n * Keep every secret of `value` that `placements` put there, before it is\n * validated, so a validation error can already mark it.\n */\nexport const keep = (\n value: unknown,\n placements: ReadonlyArray<Placement>,\n secrets: Secrets,\n): void => {\n if (placements.length === 0) return;\n let json: JSONValue;\n try {\n json = convexToJson(value as Value);\n } catch {\n // A value Convex cannot encode is never stored or passed, so it reaches no\n // artifact as a value.\n return;\n }\n walkPlaced(json, placements, (secret) => {\n secrets.keep(secret);\n return secret;\n });\n};\n\nconst containsSecret = (text: string, searchable: ReadonlyArray<string>) =>\n searchable.some((secret) => text.includes(secret));\n\n/**\n * The backstop beneath every schema walk: each string, outside a marker, that\n * holds a kept secret, replaced by `replace`.\n */\nconst backstop = (\n json: JSONValue,\n searchable: ReadonlyArray<string>,\n replace: (value: JSONValue) => JSONValue,\n): JSONValue => {\n if (searchable.length === 0) return json;\n const go = (value: JSONValue): JSONValue => {\n if (typeof value === \"string\")\n return containsSecret(value, searchable) ? replace(value) : value;\n if (Array.isArray(value)) return value.map(go);\n if (isObject(value)) {\n if (isWrapped(value)) return value;\n // A document's ID and creation time are its identity, never a secret\n // value, even when a secret field holds the same ID. Convex reserves\n // these names for system fields, so no user value is skipped.\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [\n key,\n systemFields.has(key) ? item : go(item),\n ]),\n );\n }\n return value;\n };\n return go(json);\n};\n\nconst systemFields = new Set([\"_id\", \"_creationTime\"]);\n\n/**\n * `json`, a document bound for a snapshot, with every secret its placements put\n * there, and every string holding a kept secret, replaced by a marker that\n * names the raw value's position in `secrets`. The walk never enters a marker,\n * so marking a marked value changes nothing.\n */\nexport const mark = (\n json: JSONValue,\n placements: ReadonlyArray<Placement>,\n secrets: Secrets,\n): JSONValue => {\n const toMarker = (value: JSONValue): JSONValue => ({\n [markerKey]: secrets.keep(value),\n });\n return backstop(\n walkPlaced(json, placements, toMarker),\n secrets.searchable(),\n toMarker,\n );\n};\n\n/**\n * `value` as an artifact other than a snapshot writes it: every secret its\n * placements put there, and every string holding a kept secret, replaced by the\n * marker text.\n */\nexport const markValue = (\n value: Value,\n placements: ReadonlyArray<Placement>,\n secrets: Secrets,\n): Value => {\n let json: JSONValue;\n try {\n json = convexToJson(value);\n } catch {\n return value;\n }\n const marked = backstop(\n walkPlaced(json, placements, () => marker),\n secrets.searchable(),\n () => marker,\n );\n return marked === json ? value : jsonToConvex(marked);\n};\n\n/**\n * `json` with each marker replaced by the raw value it names in `secrets`, or\n * `SnapshotSecretMissing` for the first marker the store cannot answer.\n */\nexport const unmark = (\n json: JSONValue,\n secrets: Secrets,\n): Result.Result<JSONValue, KernelRefusal.SnapshotSecretMissing> => {\n let missing: unknown = undefined;\n const go = (value: JSONValue): JSONValue => {\n if (Array.isArray(value)) return value.map(go);\n if (!isObject(value)) return value;\n if (isMarker(value)) {\n const ref = value[markerKey];\n const raw = typeof ref === \"number\" ? secrets.raw(ref) : undefined;\n if (raw === undefined) missing ??= ref;\n return raw ?? null;\n }\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [key, go(item)]),\n );\n };\n const unmarked = go(json);\n return missing === undefined\n ? Result.succeed(unmarked)\n : Result.fail(\n new KernelRefusal.SnapshotSecretMissing({\n ref: JSON.stringify(missing),\n message: `The snapshot marks a secret at ${JSON.stringify(missing)}, which the secrets passed to restore do not hold. Restore with the secrets of the backend that exported it.`,\n }),\n );\n};\n\n/**\n * `text` with every kept secret, raw or as it appears inside a JSON string,\n * replaced by the marker.\n */\nexport const scrubText = (text: string, secrets: Secrets): string =>\n secrets.searchable().reduce((scrubbed, secret) => {\n const escaped = JSON.stringify(secret).slice(1, -1);\n return scrubbed.split(secret).join(marker).split(escaped).join(marker);\n }, text);\n\nconst isPlainObject = (value: object): boolean =>\n Object.getPrototypeOf(value) === Object.prototype ||\n Object.getPrototypeOf(value) === null;\n\n/**\n * A failure report for `thrown`, whatever was thrown: every kept secret in its\n * text, its data and its causes marked. When nothing needs marking it is\n * `thrown` itself. Otherwise it is a copy with the same prototype and fields,\n * so its class and tag still read the same. `thrown` is never changed, so a\n * subscription that keeps the raw error compares it as it was.\n */\nexport const failure = (thrown: unknown, secrets: Secrets): unknown => {\n if (secrets.searchable().length === 0) return thrown;\n const copyable = (value: object) =>\n Array.isArray(value) || value instanceof Error || isPlainObject(value);\n const field = (value: object, key: string | symbol) => {\n const descriptor = Object.getOwnPropertyDescriptor(value, key)!;\n return {\n raw: \"value\" in descriptor ? descriptor.value : Reflect.get(value, key),\n enumerable: descriptor.enumerable ?? false,\n };\n };\n // First find whether anything reachable holds a kept secret. Every object is\n // visited once, so a cycle ends.\n const visited = new Set<object>();\n const holdsSecret = (value: unknown): boolean => {\n if (typeof value === \"string\") return scrubText(value, secrets) !== value;\n if (typeof value !== \"object\" || value === null) return false;\n if (visited.has(value) || !copyable(value)) return false;\n visited.add(value);\n return Reflect.ownKeys(value).some((key) =>\n holdsSecret(field(value, key).raw),\n );\n };\n if (!holdsSecret(thrown)) return thrown;\n // Then copy every reachable error, array and plain object. Each copy is\n // registered before its fields are walked, so a cycle that leads back to it\n // reaches the copy, never the raw value.\n const copies = new Map<object, unknown>();\n const copy = (value: unknown): unknown => {\n if (typeof value === \"string\") return scrubText(value, secrets);\n if (typeof value !== \"object\" || value === null) return value;\n if (copies.has(value)) return copies.get(value);\n if (!copyable(value)) return value;\n if (Array.isArray(value)) {\n // The copy is registered first, so a cycle through it reaches the copy.\n // Its entries and its own other properties, such as a `code`, are copied.\n const items: Array<unknown> = [];\n copies.set(value, items);\n for (const key of Reflect.ownKeys(value)) {\n if (key === \"length\") continue;\n const { raw, enumerable } = field(value, key);\n if (typeof key === \"string\" && /^(0|[1-9][0-9]*)$/.test(key))\n items[Number(key)] = copy(raw);\n else\n Object.defineProperty(items, key, {\n value: copy(raw),\n writable: true,\n enumerable,\n configurable: true,\n });\n }\n items.length = value.length;\n return items;\n }\n const target: object = Object.create(Object.getPrototypeOf(value));\n copies.set(value, target);\n for (const key of Reflect.ownKeys(value)) {\n const { raw, enumerable } = field(value, key);\n Object.defineProperty(target, key, {\n value: copy(raw),\n writable: true,\n enumerable,\n configurable: true,\n });\n }\n return target;\n };\n return copy(thrown);\n};\n"],"mappings":"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"}
@@ -0,0 +1,298 @@
1
+ import { type JSONValue } from "convex/values";
2
+ import * as Result from "effect/Result";
3
+ import * as Schema from "effect/Schema";
4
+ import type * as Kernel from "./Kernel.js";
5
+ import * as KernelRefusal from "./KernelRefusal.js";
6
+ import { type DocumentId, type FunctionPath } from "./KernelValues.js";
7
+ /**
8
+ * The counters the kernel allocates identities from: the next document ID, the
9
+ * latest creation time handed out, the next held attempt's ID, and the identity
10
+ * epoch, which every subscriber's `authenticate` advances. A restored world
11
+ * continues each where its source stopped, so the same calls mint the same
12
+ * identities and the same identity versions.
13
+ */
14
+ export interface Identity {
15
+ readonly nextDocumentId: number;
16
+ readonly lastCreationTime: number;
17
+ readonly nextAttemptId: number;
18
+ readonly identityEpoch: number;
19
+ }
20
+ /**
21
+ * What the kernel keeps beside a job's row, with the job's test world named
22
+ * rather than held. `null` is a job scheduled with no invocation bound.
23
+ */
24
+ export interface JobTarget {
25
+ readonly functionPath: FunctionPath;
26
+ readonly standing: boolean;
27
+ readonly world: string | null;
28
+ }
29
+ /**
30
+ * The kernel state a snapshot carries: committed rows of every component with
31
+ * the version that wrote each, the write log, the latest commit timestamp,
32
+ * every job's target, the clock's floor and the identity counters.
33
+ */
34
+ export interface Image {
35
+ readonly components: ReadonlyArray<string>;
36
+ readonly state: Kernel.State;
37
+ /**
38
+ * The latest deadline the clock was advanced to. `-Infinity` before any.
39
+ */
40
+ readonly floor: number;
41
+ readonly identity: Identity;
42
+ /**
43
+ * The target of every job whose row is committed, by job ID.
44
+ */
45
+ readonly jobs: ReadonlyMap<DocumentId, JobTarget>;
46
+ }
47
+ /**
48
+ * Whether a piece of kernel state is in a snapshot. `exported` names the
49
+ * snapshot field that carries it. `excluded` says why a restore starts without
50
+ * it.
51
+ */
52
+ export type Participation = {
53
+ readonly exported: string;
54
+ } | {
55
+ readonly excluded: string;
56
+ };
57
+ /**
58
+ * The snapshot's contract with the kernel's state. Every field of the committed
59
+ * state, of a job's target and of a `World` is listed here as exported or
60
+ * excluded with its reason. The first two are checked by type: a field added to
61
+ * `Kernel.State` or `Scheduling.Target` without an entry fails to compile. A
62
+ * `World`'s fields are private, which no type can enumerate, so
63
+ * `Snapshot.test.ts` compares a fresh world's own fields with `world` below,
64
+ * and a field added without an entry fails that test.
65
+ *
66
+ * That test sees only the own fields a fresh world has. It cannot see state
67
+ * created lazily after construction, held under a symbol or a `#private` name,
68
+ * or kept in a closure or another object, as subscribers are. So every live
69
+ * registry, state that exists only while something runs or a client is
70
+ * attached, is also listed in `live`. `World.liveCounts` reports each one,
71
+ * typed against `live`, and a restore refuses while any of them is non-empty,
72
+ * so a piece of live state the snapshot does not carry fails loudly rather than
73
+ * surviving a restore silently. A new live registry adds itself there.
74
+ *
75
+ * Owed by later rows, which add their state here when they land on `main`: cron
76
+ * state (#133), stored file bytes, storage ID mappings, `nextFile` and
77
+ * upload-token counters (#138), and component init markers. A restore never
78
+ * redeclares a cron and never draws a fresh random value: it installs the
79
+ * declared state as the snapshot holds it, so a row whose state comes from a
80
+ * declaration or a random draw exports what was declared or drawn.
81
+ */
82
+ export declare const contract: {
83
+ readonly state: {
84
+ tables: {
85
+ exported: string;
86
+ };
87
+ version: {
88
+ exported: string;
89
+ };
90
+ commitTs: {
91
+ exported: string;
92
+ };
93
+ log: {
94
+ exported: string;
95
+ };
96
+ };
97
+ readonly target: {
98
+ functionPath: {
99
+ exported: string;
100
+ };
101
+ standing: {
102
+ exported: string;
103
+ };
104
+ world: {
105
+ exported: string;
106
+ };
107
+ };
108
+ readonly world: {
109
+ components: {
110
+ excluded: string;
111
+ };
112
+ state: {
113
+ exported: string;
114
+ };
115
+ opened: {
116
+ excluded: string;
117
+ };
118
+ nextDocId: {
119
+ exported: string;
120
+ };
121
+ lastCreationTime: {
122
+ exported: string;
123
+ };
124
+ nextQueryId: {
125
+ excluded: string;
126
+ };
127
+ queries: {
128
+ excluded: string;
129
+ };
130
+ holding: {
131
+ excluded: string;
132
+ };
133
+ nextAttemptId: {
134
+ exported: string;
135
+ };
136
+ floor: {
137
+ exported: string;
138
+ };
139
+ targets: {
140
+ exported: string;
141
+ };
142
+ live: {
143
+ excluded: string;
144
+ };
145
+ identityEpoch: {
146
+ exported: string;
147
+ };
148
+ runtime: {
149
+ excluded: string;
150
+ };
151
+ redaction: {
152
+ excluded: string;
153
+ };
154
+ secrets: {
155
+ excluded: string;
156
+ };
157
+ };
158
+ /**
159
+ * Live registries: what blocks a snapshot while it is non-empty, and why.
160
+ */
161
+ readonly live: {
162
+ running: {
163
+ blocks: "export and restore";
164
+ reason: string;
165
+ };
166
+ walks: {
167
+ blocks: "export and restore";
168
+ reason: string;
169
+ };
170
+ functions: {
171
+ blocks: "export and restore";
172
+ reason: string;
173
+ };
174
+ held: {
175
+ blocks: "export and restore";
176
+ reason: string;
177
+ };
178
+ subscribers: {
179
+ blocks: "restore";
180
+ reason: string;
181
+ };
182
+ };
183
+ /**
184
+ * State outside the kernel's world, live per client or per process.
185
+ */
186
+ readonly outside: {
187
+ subscriptions: {
188
+ excluded: string;
189
+ };
190
+ requestIds: {
191
+ excluded: string;
192
+ };
193
+ };
194
+ };
195
+ declare const Body: Schema.Struct<{
196
+ readonly components: Schema.$Array<Schema.String>;
197
+ readonly version: Schema.Int;
198
+ readonly commitTs: Schema.String;
199
+ readonly floor: Schema.NullOr<Schema.Finite>;
200
+ readonly identity: Schema.Struct<{
201
+ readonly nextDocumentId: Schema.Int;
202
+ readonly lastCreationTime: Schema.Finite;
203
+ readonly nextAttemptId: Schema.Int;
204
+ readonly identityEpoch: Schema.Int;
205
+ }>;
206
+ readonly tables: Schema.$Array<Schema.Struct<{
207
+ readonly componentPath: Schema.String;
208
+ readonly table: Schema.String;
209
+ readonly rows: Schema.$Array<Schema.Struct<{
210
+ readonly version: Schema.Int;
211
+ readonly doc: Schema.Unknown;
212
+ }>>;
213
+ }>>;
214
+ readonly jobs: Schema.$Array<Schema.Struct<{
215
+ readonly id: Schema.String;
216
+ readonly target: Schema.Struct<{
217
+ readonly componentPath: Schema.String;
218
+ readonly udfPath: Schema.String;
219
+ }>;
220
+ readonly standing: Schema.Boolean;
221
+ readonly world: Schema.NullOr<Schema.String>;
222
+ }>>;
223
+ readonly log: Schema.$Array<Schema.Struct<{
224
+ readonly version: Schema.Int;
225
+ readonly commitTs: Schema.String;
226
+ readonly changes: Schema.$Array<Schema.Struct<{
227
+ readonly componentPath: Schema.String;
228
+ readonly id: Schema.String;
229
+ readonly before: Schema.Unknown;
230
+ readonly after: Schema.Unknown;
231
+ }>>;
232
+ }>>;
233
+ }>;
234
+ type Body = typeof Body.Type;
235
+ /**
236
+ * What an export writes for one document, before it reaches the bytes: the
237
+ * kernel marks secrets here. `table` is the document's table.
238
+ */
239
+ export type Redact = (componentPath: string, table: string, json: JSONValue) => JSONValue;
240
+ /**
241
+ * What a restore reads back for one document before decoding it: the kernel
242
+ * puts marked secrets back here.
243
+ */
244
+ export type Unredact = (json: JSONValue) => Result.Result<JSONValue, KernelRefusal.SnapshotSecretMissing>;
245
+ /**
246
+ * Encode `image` as snapshot bytes: a header line naming the format and the
247
+ * SHA-256 digest of the body, then the body as JSON. Components, tables, rows
248
+ * and jobs are sorted, and every document keeps its own field order, so the
249
+ * same state always encodes to the same bytes.
250
+ */
251
+ export declare const encode: (image: Image, redact?: Redact) => Uint8Array;
252
+ /**
253
+ * Check the decoded body before any map is built from it, so its order cannot
254
+ * change the result: components, tables, rows and jobs each appear once, and
255
+ * every document carries the system fields the kernel writes.
256
+ */
257
+ export declare const checkBody: (body: Body) => Result.Result<void, KernelRefusal.SnapshotMalformed | KernelRefusal.SnapshotRowInconsistent | KernelRefusal.SnapshotJobInconsistent>;
258
+ /**
259
+ * Why a decoded snapshot is not state the kernel could have reached.
260
+ */
261
+ export type Inconsistency = KernelRefusal.SnapshotAllocatorBehind | KernelRefusal.SnapshotRowInconsistent | KernelRefusal.SnapshotTimestampInconsistent | KernelRefusal.SnapshotJobInconsistent;
262
+ /**
263
+ * Rows match the write log: replaying every commit from the empty world, each
264
+ * change replacing the value the log last published, gives exactly the
265
+ * snapshot's rows, each at the version that last wrote it, in a registered
266
+ * component and under its ID's table.
267
+ */
268
+ export declare const checkRows: (image: Image) => Result.Result<void, KernelRefusal.SnapshotRowInconsistent>;
269
+ /**
270
+ * Identity counters run ahead of every identity the state holds: the next
271
+ * document ID past every ID's counter, the latest creation time at or past
272
+ * every document's, a positive next attempt ID and a non-negative epoch.
273
+ */
274
+ export declare const checkAllocators: (image: Image) => Result.Result<void, KernelRefusal.SnapshotAllocatorBehind>;
275
+ /**
276
+ * Commit timestamps strictly increase through the write log, and the latest
277
+ * commit timestamp is the log's last, or zero before any commit.
278
+ */
279
+ export declare const checkTimestamps: (image: Image) => Result.Result<void, KernelRefusal.SnapshotTimestampInconsistent>;
280
+ /**
281
+ * Every job names a committed job row and a registered component, every job row
282
+ * has its job, and no job is left running: a snapshot is never taken while a
283
+ * job runs.
284
+ */
285
+ export declare const checkJobs: (image: Image, table: string) => Result.Result<void, KernelRefusal.SnapshotJobInconsistent>;
286
+ /**
287
+ * Check a decoded image against every rule the kernel's own exports keep,
288
+ * before any of it is installed.
289
+ */
290
+ export declare const check: (image: Image, jobTable: string) => Result.Result<void, Inconsistency>;
291
+ /**
292
+ * Read snapshot bytes back into the state they encode. Bytes whose body no
293
+ * longer hashes to their header's digest refuse with `SnapshotDigestMismatch`
294
+ * before any of the body is read.
295
+ */
296
+ export declare const decode: (bytes: Uint8Array, unredact?: Unredact) => Result.Result<Image, KernelRefusal.SnapshotMalformed | KernelRefusal.SnapshotDigestMismatch | KernelRefusal.SnapshotSecretMissing | KernelRefusal.SnapshotRowInconsistent | KernelRefusal.SnapshotJobInconsistent>;
297
+ export {};
298
+ //# sourceMappingURL=Snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Snapshot.d.ts","sourceRoot":"","sources":["../../src/internal/Snapshot.ts"],"names":[],"mappings":"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"}