better-call 0.0.0-experimental.01ff4b77

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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +265 -0
  3. package/dist/capability.cjs +417 -0
  4. package/dist/capability.cjs.map +1 -0
  5. package/dist/capability.d.cts +189 -0
  6. package/dist/capability.d.mts +189 -0
  7. package/dist/capability.mjs +401 -0
  8. package/dist/capability.mjs.map +1 -0
  9. package/dist/error.cjs +76 -0
  10. package/dist/error.cjs.map +1 -0
  11. package/dist/error.d.cts +51 -0
  12. package/dist/error.d.mts +51 -0
  13. package/dist/error.mjs +72 -0
  14. package/dist/error.mjs.map +1 -0
  15. package/dist/fn.cjs +350 -0
  16. package/dist/fn.cjs.map +1 -0
  17. package/dist/fn.d.cts +378 -0
  18. package/dist/fn.d.mts +378 -0
  19. package/dist/fn.mjs +350 -0
  20. package/dist/fn.mjs.map +1 -0
  21. package/dist/index.cjs +43 -0
  22. package/dist/index.cjs.map +1 -0
  23. package/dist/index.d.cts +50 -0
  24. package/dist/index.d.mts +50 -0
  25. package/dist/index.mjs +24 -0
  26. package/dist/index.mjs.map +1 -0
  27. package/dist/module.cjs +176 -0
  28. package/dist/module.cjs.map +1 -0
  29. package/dist/module.d.cts +283 -0
  30. package/dist/module.d.mts +283 -0
  31. package/dist/module.mjs +166 -0
  32. package/dist/module.mjs.map +1 -0
  33. package/dist/plugins/db.cjs +24 -0
  34. package/dist/plugins/db.cjs.map +1 -0
  35. package/dist/plugins/db.d.cts +18 -0
  36. package/dist/plugins/db.d.mts +18 -0
  37. package/dist/plugins/db.mjs +19 -0
  38. package/dist/plugins/db.mjs.map +1 -0
  39. package/dist/plugins/http/attrs.cjs +91 -0
  40. package/dist/plugins/http/attrs.cjs.map +1 -0
  41. package/dist/plugins/http/attrs.d.cts +26 -0
  42. package/dist/plugins/http/attrs.d.mts +26 -0
  43. package/dist/plugins/http/attrs.mjs +87 -0
  44. package/dist/plugins/http/attrs.mjs.map +1 -0
  45. package/dist/plugins/http/cookie.cjs +117 -0
  46. package/dist/plugins/http/cookie.cjs.map +1 -0
  47. package/dist/plugins/http/cookie.d.cts +637 -0
  48. package/dist/plugins/http/cookie.d.mts +637 -0
  49. package/dist/plugins/http/cookie.mjs +113 -0
  50. package/dist/plugins/http/cookie.mjs.map +1 -0
  51. package/dist/plugins/http/error.cjs +39 -0
  52. package/dist/plugins/http/error.cjs.map +1 -0
  53. package/dist/plugins/http/error.d.cts +38 -0
  54. package/dist/plugins/http/error.d.mts +38 -0
  55. package/dist/plugins/http/error.mjs +35 -0
  56. package/dist/plugins/http/error.mjs.map +1 -0
  57. package/dist/plugins/http/handle.cjs +73 -0
  58. package/dist/plugins/http/handle.cjs.map +1 -0
  59. package/dist/plugins/http/handle.d.cts +955 -0
  60. package/dist/plugins/http/handle.d.mts +955 -0
  61. package/dist/plugins/http/handle.mjs +72 -0
  62. package/dist/plugins/http/handle.mjs.map +1 -0
  63. package/dist/plugins/http/redirect.cjs +82 -0
  64. package/dist/plugins/http/redirect.cjs.map +1 -0
  65. package/dist/plugins/http/redirect.d.cts +67 -0
  66. package/dist/plugins/http/redirect.d.mts +67 -0
  67. package/dist/plugins/http/redirect.mjs +79 -0
  68. package/dist/plugins/http/redirect.mjs.map +1 -0
  69. package/dist/plugins/http/request.cjs +63 -0
  70. package/dist/plugins/http/request.cjs.map +1 -0
  71. package/dist/plugins/http/request.d.cts +142 -0
  72. package/dist/plugins/http/request.d.mts +142 -0
  73. package/dist/plugins/http/request.mjs +61 -0
  74. package/dist/plugins/http/request.mjs.map +1 -0
  75. package/dist/plugins/http/response.cjs +13 -0
  76. package/dist/plugins/http/response.cjs.map +1 -0
  77. package/dist/plugins/http/response.d.cts +18 -0
  78. package/dist/plugins/http/response.d.mts +18 -0
  79. package/dist/plugins/http/response.mjs +13 -0
  80. package/dist/plugins/http/response.mjs.map +1 -0
  81. package/dist/plugins/http.cjs +64 -0
  82. package/dist/plugins/http.cjs.map +1 -0
  83. package/dist/plugins/http.d.cts +945 -0
  84. package/dist/plugins/http.d.mts +945 -0
  85. package/dist/plugins/http.mjs +37 -0
  86. package/dist/plugins/http.mjs.map +1 -0
  87. package/dist/plugins/read-only.cjs +19 -0
  88. package/dist/plugins/read-only.cjs.map +1 -0
  89. package/dist/plugins/read-only.d.cts +17 -0
  90. package/dist/plugins/read-only.d.mts +17 -0
  91. package/dist/plugins/read-only.mjs +19 -0
  92. package/dist/plugins/read-only.mjs.map +1 -0
  93. package/dist/schema.cjs +245 -0
  94. package/dist/schema.cjs.map +1 -0
  95. package/dist/schema.d.cts +411 -0
  96. package/dist/schema.d.mts +411 -0
  97. package/dist/schema.mjs +235 -0
  98. package/dist/schema.mjs.map +1 -0
  99. package/dist/scope.d.cts +31 -0
  100. package/dist/scope.d.mts +31 -0
  101. package/dist/storage.cjs +308 -0
  102. package/dist/storage.cjs.map +1 -0
  103. package/dist/storage.d.cts +220 -0
  104. package/dist/storage.d.mts +220 -0
  105. package/dist/storage.mjs +302 -0
  106. package/dist/storage.mjs.map +1 -0
  107. package/dist/types.d.cts +8 -0
  108. package/dist/types.d.mts +8 -0
  109. package/dist/var.cjs +186 -0
  110. package/dist/var.cjs.map +1 -0
  111. package/dist/var.d.cts +46 -0
  112. package/dist/var.d.mts +46 -0
  113. package/dist/var.mjs +177 -0
  114. package/dist/var.mjs.map +1 -0
  115. package/package.json +114 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.mjs","names":[],"sources":["../src/schema.ts"],"sourcesContent":["import { type Issue, ValidationError } from \"./error\";\nimport type { LiteralString, Prettify } from \"./types\";\n\nexport type Rules = {\n\t/** Strings: length. Numbers: value. */\n\tmin?: number;\n\t/** Strings: length. Numbers: value. */\n\tmax?: number;\n\t/** Strings only: exact length. */\n\tlength?: number;\n\tregex?: RegExp;\n\t/** Strings only. Trims and lowercases before the format check. */\n\temail?: boolean;\n\turl?: boolean;\n\tstartsWith?: string;\n\tendsWith?: string;\n\t/** Numbers only. */\n\tint?: boolean;\n\t/** Allowed values. */\n\tenum?: readonly unknown[];\n\t/** Escape hatch - return true, or a message to fail with. */\n\tcheck?: (value: any) => boolean | string;\n};\n\n/** Plugin-owned field metadata. Outer key is the plugin namespace\n * (`\"http\"`, `\"db\"`, …); core never interprets the contents. */\nexport type AttrBag = Record<string, Record<string, unknown>>;\n\nexport interface TypeDefination<T, O, D = never> extends Rules {\n\tname: LiteralString;\n\ttype?: T;\n\toutput?: O;\n\tshape?: unknown;\n\t/** `function` types only: the declared input of the expected fn -\n\t * plain closures get it validated at their door on every call. */\n\tfnInput?: unknown;\n\t/** Used when the incoming value is `undefined`. A zero-arg function\n\t * is called (fresh value per validate) except on `function` schemas,\n\t * where the default IS the fn. */\n\tdefault?: D | (() => D);\n\t/** When true, `undefined` and `null` pass straight through unvalidated. */\n\toptional?: boolean;\n\ttransform?: (value: any) => O;\n\t/** Opaque plugin attributes - ignored by validate / Infer*. */\n\t$attrs?: AttrBag;\n}\n\nexport type TypeOptions<T, O> = {\n\ttransform?: (value: T) => O;\n\t/** Accepted on every helper; overloads refine the output when `true`. */\n\toptional?: boolean;\n};\n\n/**\n * `optional` widens the output with `| undefined | null`; `default` keeps\n * it narrow because a value is always produced. Declaring both means\n * optional to send, never absent.\n *\n * Helpers select among these via option-shape overloads rather than `Opt` /\n * `D` type parameters: providing a partial type argument (e.g.\n * `v.string<\"a\" | \"b\">`) would lock remaining params to their defaults, so\n * `{ optional: true }` would fail to type-check.\n */\ntype OutOf<O, D, Opt> = [Opt] extends [true]\n\t? [D] extends [never]\n\t\t? O | undefined | null\n\t\t: O\n\t: O;\n\n/**\n * Recover a type's output `O`. Plain `infer O` from\n * `TypeDefination<any, infer O, …>` drops `| undefined` because `output?`\n * is optional and TypeScript attributes the undefined to the property.\n * When the third type arg is `undefined` (optional, no default), put\n * `| undefined | null` back so handlers see the same absence validate\n * produces at runtime.\n */\ntype OutputOf<F> =\n\tF extends TypeDefination<any, infer O, infer D>\n\t\t? [D] extends [never]\n\t\t\t? O\n\t\t\t: undefined extends D\n\t\t\t\t? O | undefined | null\n\t\t\t\t: O\n\t\t: never;\n\ntype StringOptions<E extends string, O> = TypeOptions<E, O> &\n\tPick<\n\t\tRules,\n\t\t| \"min\"\n\t\t| \"max\"\n\t\t| \"length\"\n\t\t| \"regex\"\n\t\t| \"email\"\n\t\t| \"url\"\n\t\t| \"startsWith\"\n\t\t| \"endsWith\"\n\t\t| \"check\"\n\t> & { enum?: readonly E[] };\n\ntype ArrayOptions<E, O> = TypeOptions<FieldOut<E>[], O> &\n\tPick<Rules, \"min\" | \"max\" | \"length\" | \"check\">;\n\ntype UnionOptions<T extends readonly unknown[], O> = TypeOptions<\n\tFieldOut<T[number]>,\n\tO\n> &\n\tPick<Rules, \"check\">;\n\ntype NumberOptions<O> = TypeOptions<number, O> &\n\tPick<Rules, \"min\" | \"max\" | \"int\" | \"check\"> & {\n\t\tenum?: readonly number[];\n\t};\n\nexport type InferType<T> =\n\tT extends TypeDefination<infer T2, any, any> ? T2 : never;\n\nexport type InferOutput<T> =\n\tT extends TypeDefination<any, any, any> ? OutputOf<T> : never;\n\nexport type DefineInput<I> = Prettify<{\n\t[K in keyof I]: FieldIn<I[K]>;\n}>;\n\n/** Keys whose field is OPTIONAL with no default: absent from the output\n * too, so they mark `?`. A defaulted field always produces a value and\n * stays required. */\ntype OutOptional<O> = {\n\t[K in keyof O]: [DefaultOf<O[K]>] extends [never]\n\t\t? never\n\t\t: [DefaultOf<O[K]>] extends [undefined]\n\t\t\t? K\n\t\t\t: never;\n}[keyof O];\n\nexport type DefineOutput<O> = Prettify<\n\t{ [K in keyof O as K extends OutOptional<O> ? never : K]: FieldOut<O[K]> } & {\n\t\t[K in keyof O as K extends OutOptional<O> ? K : never]?: FieldOut<O[K]>;\n\t}\n>;\n\n/**\n * A handler-less `v.fn({ input, output })` used as a schema describes\n * \"a fn from `input` to `output`\" - the VALUE is the fn itself. Two\n * views of the same signature:\n *\n * `SchemaFnIn` is the PROVIDER's side - what a caller must hand over.\n * Like any handler, their fn receives the PARSED input (validation runs\n * at its door) and returns the declared output, sync or async.\n *\n * `SchemaFnOut` is the CONSUMER's side (`c.input.x`) - the handler calls\n * it with RAW args, exactly like calling the fn it stands in for.\n *\n * No declared input means the signature is UNSPECIFIED, not zero-arg -\n * any fn fits (`create: v.fn`), so the args stay open.\n */\ntype SchemaFnIn<FI, FO> = (\n\t...args: unknown extends FI ? any[] : [input: InferInput<FI>]\n) => unknown extends FO\n\t? any\n\t: InferInput<OutputSchemaOf<FO>> | Promise<InferInput<OutputSchemaOf<FO>>>;\n\ntype SchemaFnOut<FI, FO> = (\n\t...args: unknown extends FI ? any[] : [input: InferArgs<FI>]\n) => unknown extends FO\n\t? any\n\t: InferInput<OutputSchemaOf<FO>> | Promise<InferInput<OutputSchemaOf<FO>>>;\n\n/**\n * A fn schema whose input IS a var carries that var's name as an optional\n * phantom (`$fnVar`, tuple-wrapped so a plain fn can never false-match).\n * Scope resolution reads it to WIDEN the fn's args with everything the\n * scope mounts on that var - see `WidenSchemaFns`. Optional, so any plain\n * closure still satisfies the type.\n */\nexport type FnVarBrand<FI> = FI extends {\n\t$var: true;\n\tname: infer N extends string;\n}\n\t? { readonly $fnVar?: [N] }\n\t: unknown;\n\n/**\n * A declared `output` comes in two forms: a bare schema (the signature\n * AND the exit check), or the wrapper `{ def?, validation? }` splitting\n * what the fn PROMISES from what gets CHECKED - `{ def }` documents\n * without paying runtime validation, `{ def, validation }` checks with a\n * different (usually looser) schema than it documents. The wrapper is\n * recognized by its keys, so an output that IS an object with only\n * `def`/`validation` fields must be written `v.object({...})`.\n *\n * `OutputSchemaOf` is the type-level unwrap - the schema the fn's return\n * type (and its rendered signature) comes from.\n */\nexport type OutputSchemaOf<O> =\n\tExclude<keyof O, \"def\" | \"validation\"> extends never\n\t\t? O extends { def: infer D }\n\t\t\t? D\n\t\t\t: O extends { validation: infer Vl }\n\t\t\t\t? Vl\n\t\t\t\t: O\n\t\t: O;\n\n/** The runtime unwrap: `def` is the documented schema (falls back to\n * `validation`), `validation` is what the exit check runs - undefined\n * means no check. A bare schema is both. */\nexport const outputContract = (\n\toutput: unknown,\n): { def?: unknown; validation?: unknown } => {\n\tif (output === undefined) return {};\n\tif (\n\t\toutput !== null &&\n\t\ttypeof output === \"object\" &&\n\t\t!Array.isArray(output) &&\n\t\t!isType(output) &&\n\t\t!isVar(output) &&\n\t\t!isFnSchema(output)\n\t) {\n\t\tconst keys = Object.keys(output);\n\t\tif (\n\t\t\tkeys.length > 0 &&\n\t\t\tkeys.every((k) => k === \"def\" || k === \"validation\")\n\t\t) {\n\t\t\tconst { def, validation } = output as {\n\t\t\t\tdef?: unknown;\n\t\t\t\tvalidation?: unknown;\n\t\t\t};\n\t\t\treturn { def: def ?? validation, validation };\n\t\t}\n\t}\n\treturn { def: output, validation: output };\n};\n\n/**\n * One input field, in five flavours:\n * - a `v.var()`, whose shape comes from the var's own `schema`\n * - a handler-less `v.fn(...)` builder, which types the field as a FN\n * - a type from `v.string()` / `v.object()` / ...\n * - a bare nested record, which recurses\n * - anything else (e.g. `null`, `\"lit\"`) kept as itself - so\n * `v.union([user, null])` infers `User | null`, not just `User`\n *\n * The record case has to come after TypeDefination: a TypeDefination is\n * itself a record, and so is a builder.\n */\ntype FieldOut<F> = F extends { $var: true; schema?: infer S }\n\t? InferInput<NonNullable<S>>\n\t: F extends { $fnSchema: { input?: infer FI; output?: infer FO } }\n\t\t? FnSchemaOut<F, SchemaFnOut<FI, FO> & FnVarBrand<FI>>\n\t\t: F extends TypeDefination<any, any, any>\n\t\t\t? OutputOf<F>\n\t\t\t: F extends Record<string, unknown>\n\t\t\t\t? Prettify<{ [K in keyof F]: FieldOut<F[K]> }>\n\t\t\t\t: F;\n\ntype FieldIn<F> = F extends { $var: true; schema?: infer S }\n\t? InferArgs<NonNullable<S>>\n\t: F extends { $fnSchema: { input?: infer FI; output?: infer FO } }\n\t\t? SchemaFnIn<FI, FO> & FnVarBrand<FI>\n\t\t: F extends TypeDefination<infer T, any, infer D>\n\t\t\t? undefined extends D\n\t\t\t\t? T | null\n\t\t\t\t: T\n\t\t\t: F extends Record<string, unknown>\n\t\t\t\t? ArgsShape<F>\n\t\t\t\t: F;\n\n/**\n * `optional: true` on `v.fn.type` widens the same way a type's `optional`\n * does: absent without a default means the value may be `undefined` or\n * `null`.\n */\ntype FnSchemaOut<F, Fn> = F extends { optional: true }\n\t? F extends { default: infer _D }\n\t\t? Fn\n\t\t: Fn | undefined | null\n\t: Fn;\n\n/**\n * A field's declared default, looked through a var to its schema. Only a\n * TYPE's default counts - a var's own default is its initial value, not a\n * licence to omit the input. The `$fnSchema` guard mirrors `asType`'s\n * ordering: a bare `v.fn` is CALLABLE, and any callable duck-matches\n * TypeDefination (`.name` comes with every function), which would read a\n * phantom default off it and wrongly mark the field optional. `v.fn.type`\n * may still declare `optional` / `default` on the carrier itself.\n */\ntype DefaultOf<F> = F extends { $var: true; schema?: infer S }\n\t? NonNullable<S> extends TypeDefination<any, any, infer D>\n\t\t? D\n\t\t: never\n\t: F extends { $fnSchema: unknown }\n\t\t? F extends { optional: true }\n\t\t\t? F extends { default: infer D }\n\t\t\t\t? D\n\t\t\t\t: undefined\n\t\t\t: F extends { default: infer D }\n\t\t\t\t? D\n\t\t\t\t: never\n\t\t: F extends TypeDefination<any, any, infer D>\n\t\t\t? D\n\t\t\t: never;\n\ntype Defaulted<I> = {\n\t[K in keyof I]: [DefaultOf<I[K]>] extends [never] ? never : K;\n}[keyof I];\n\n/** Defaulted keys are optional to send, but always present in the handler. */\ntype ArgsShape<I> = Prettify<\n\t{ [K in keyof I as K extends Defaulted<I> ? never : K]: FieldIn<I[K]> } & {\n\t\t[K in keyof I as K extends Defaulted<I> ? K : never]?: FieldIn<I[K]>;\n\t}\n>;\n\n/**\n * Post-transform shape - what a handler sees. The `$var` branch must come\n * first: a var's `name` property duck-matches TypeDefination, and falling\n * into that branch reads the var's VALUE type instead of its schema. A\n * TUPLE input maps position by position - the fn takes that many args.\n */\nexport type InferInput<I> = I extends { $var: true; schema?: infer S }\n\t? InferInput<NonNullable<S>>\n\t: I extends { $fnSchema: { input?: infer FI; output?: infer FO } }\n\t\t? SchemaFnOut<FI, FO> & FnVarBrand<FI>\n\t\t: I extends readonly unknown[]\n\t\t\t? { -readonly [K in keyof I]: InferInput<I[K]> }\n\t\t\t: I extends TypeDefination<any, any, any>\n\t\t\t\t? OutputOf<I>\n\t\t\t\t: Prettify<{ [K in keyof I]: FieldOut<I[K]> }>;\n\n/** Pre-transform shape - what a caller sends. Same branch order. */\nexport type InferArgs<I> = I extends { $var: true; schema?: infer S }\n\t? InferArgs<NonNullable<S>>\n\t: I extends { $fnSchema: { input?: infer FI; output?: infer FO } }\n\t\t? SchemaFnIn<FI, FO> & FnVarBrand<FI>\n\t\t: I extends readonly unknown[]\n\t\t\t? { -readonly [K in keyof I]: InferArgs<I[K]> }\n\t\t\t: I extends TypeDefination<infer T, any, infer D>\n\t\t\t\t? undefined extends D\n\t\t\t\t\t? T | null\n\t\t\t\t\t: T\n\t\t\t\t: ArgsShape<I>;\n\nexport const isType = (value: any): value is TypeDefination<any, any> =>\n\ttypeof value?.name === \"string\";\n\n/** A handler-less `v.fn(...)` builder doubles as a schema: the value it\n * describes is a FN with the declared signature. The builder FN itself is\n * branded too, so bare `v.fn` reads as \"any function\". */\nexport const isFnSchema = (\n\tvalue: any,\n): value is {\n\t$fnSchema: { input?: unknown; output?: unknown };\n\toptional?: boolean;\n\tdefault?: unknown;\n} => typeof value?.$fnSchema === \"object\" && value.$fnSchema !== null;\n\nexport const asType = (value: any): TypeDefination<any, any> =>\n\t// A var's own `name` (\"user\") would duck-match isType, so unwrap first -\n\t// and a builder is a record, so it must be caught before the fallback.\n\tisVar(value)\n\t\t? asType(value.schema ?? {})\n\t\t: isFnSchema(value)\n\t\t\t? ({\n\t\t\t\t\tname: \"function\",\n\t\t\t\t\tfnInput: value.$fnSchema.input,\n\t\t\t\t\t...(value.optional ? { optional: true } : {}),\n\t\t\t\t\t...(value.default !== undefined ? { default: value.default } : {}),\n\t\t\t\t} as TypeDefination<any, any>)\n\t\t\t: isType(value)\n\t\t\t\t? value\n\t\t\t\t: // Bare literals in `v.union([schema, null])` / `[\"a\", \"b\"]`:\n\t\t\t\t\t// map to a type whose `name` matches `typeOf`, with `enum`\n\t\t\t\t\t// pinning the exact value for string/number/boolean.\n\t\t\t\t\tvalue === null\n\t\t\t\t\t? ({ name: \"null\" } as TypeDefination<null, null>)\n\t\t\t\t\t: value === undefined\n\t\t\t\t\t\t? ({ name: \"undefined\" } as TypeDefination<undefined, undefined>)\n\t\t\t\t\t\t: typeof value === \"string\" ||\n\t\t\t\t\t\t\t\ttypeof value === \"number\" ||\n\t\t\t\t\t\t\t\ttypeof value === \"boolean\"\n\t\t\t\t\t\t\t? ({\n\t\t\t\t\t\t\t\t\tname: typeof value,\n\t\t\t\t\t\t\t\t\tenum: [value],\n\t\t\t\t\t\t\t\t} as TypeDefination<any, any>)\n\t\t\t\t\t\t\t: { name: \"object\", shape: value };\n\n/**\n * Replace the whole `$attrs` bag. On a var, rebinds `customize` so a later\n * customize keeps these attrs (the original closure closes over pre-attr\n * options and would otherwise drop them).\n */\nconst withAttrBag = <S>(schema: S, bag: AttrBag): S => {\n\tif (isVar(schema)) {\n\t\tconst v = schema as {\n\t\t\t$attrs?: AttrBag;\n\t\t\tcustomize: (opts: any) => unknown;\n\t\t\t[key: string]: unknown;\n\t\t};\n\t\treturn {\n\t\t\t...v,\n\t\t\t$attrs: bag,\n\t\t\tcustomize: (opts: any) => withAttrBag(v.customize(opts) as S, bag),\n\t\t} as S;\n\t}\n\treturn { ...asType(schema), $attrs: bag } as S;\n};\n\n/**\n * Attach plugin attributes under `namespace`, deep-merging with any\n * already on the schema. Returns a new type def (or var) with the same\n * value type. Core never reads these - only plugin edges do.\n *\n * Passed a var, attributes land on the var itself (`$attrs`) and the\n * `$var` / `name` / `schema` identity is preserved; `customize` is rebound\n * so attrs survive further customization.\n */\nexport const withAttrs = <S>(\n\tschema: S,\n\tnamespace: string,\n\tattrs: Record<string, unknown>,\n): S => {\n\tconst prev = (attrsOf(schema) ?? {}) as AttrBag;\n\treturn withAttrBag(schema, {\n\t\t...prev,\n\t\t[namespace]: { ...(prev[namespace] ?? {}), ...attrs },\n\t});\n};\n\n/** Read the whole attr bag, or one plugin namespace. */\nexport function attrsOf(schema: unknown): AttrBag | undefined;\nexport function attrsOf(\n\tschema: unknown,\n\tnamespace: string,\n): Record<string, unknown> | undefined;\nexport function attrsOf(\n\tschema: unknown,\n\tnamespace?: string,\n): AttrBag | Record<string, unknown> | undefined {\n\tif (schema === null || schema === undefined) return undefined;\n\t// Vars carry whole-var attrs on themselves; field attrs live on the\n\t// schema type def. Do not unwrap through asType or var identity is\n\t// lost and whole-var attrs become invisible.\n\tconst bag = isVar(schema)\n\t\t? (schema as { $attrs?: AttrBag }).$attrs\n\t\t: asType(schema).$attrs;\n\tif (!bag) return undefined;\n\treturn namespace === undefined ? bag : bag[namespace];\n}\n\nexport const typeOf = (value: unknown) =>\n\tvalue === null\n\t\t? \"null\"\n\t\t: Array.isArray(value)\n\t\t\t? \"array\"\n\t\t\t: Number.isNaN(value)\n\t\t\t\t? \"NaN\"\n\t\t\t\t: typeof value;\n\nexport const isVar = (value: any): boolean => value?.$var === true;\n\n// Zod's email regex\n// The author has written about this explicitly: trying to accept every technically valid email address leads to overly complex,\n// hard-to-maintain, and sometimes ReDoS-vulnerable regexes that still reject real-world addresses people actually use.\n// Zod prioritizes a practical filter that works well for the vast majority of real user-entered emails.\nconst EMAIL =\n\t/^(?!\\.)(?!.*\\.\\.)([a-z0-9_'+\\-.]*)[a-z0-9_+-]@([a-z0-9][a-z0-9-]*\\.)+[a-z]{2,}$/;\n\nconst fail = (path: string, message: string): never => {\n\tthrow new ValidationError(path, message);\n};\n\n/** Constraint checks, run after the value's type is known to be right. */\nconst applyRules = (def: Rules, value: any, path: string) => {\n\tif (def.enum && !def.enum.includes(value)) {\n\t\tfail(path, `expected one of ${def.enum.join(\", \")}, received ${value}`);\n\t}\n\tif (typeof value === \"string\") {\n\t\tif (def.length !== undefined && value.length !== def.length) {\n\t\t\tfail(path, `expected length ${def.length}, received ${value.length}`);\n\t\t}\n\t\tif (def.min !== undefined && value.length < def.min) {\n\t\t\tfail(\n\t\t\t\tpath,\n\t\t\t\t`expected at least ${def.min} characters, received ${value.length}`,\n\t\t\t);\n\t\t}\n\t\tif (def.max !== undefined && value.length > def.max) {\n\t\t\tfail(\n\t\t\t\tpath,\n\t\t\t\t`expected at most ${def.max} characters, received ${value.length}`,\n\t\t\t);\n\t\t}\n\t\tif (def.regex && !def.regex.test(value)) {\n\t\t\tfail(path, `does not match ${def.regex}`);\n\t\t}\n\t\tif (def.email && !EMAIL.test(value))\n\t\t\tfail(path, \"expected an email address\");\n\t\tif (def.url) {\n\t\t\ttry {\n\t\t\t\tnew URL(value);\n\t\t\t} catch {\n\t\t\t\tfail(path, \"expected a URL\");\n\t\t\t}\n\t\t}\n\t\tif (def.startsWith !== undefined && !value.startsWith(def.startsWith)) {\n\t\t\tfail(path, `expected to start with \"${def.startsWith}\"`);\n\t\t}\n\t\tif (def.endsWith !== undefined && !value.endsWith(def.endsWith)) {\n\t\t\tfail(path, `expected to end with \"${def.endsWith}\"`);\n\t\t}\n\t}\n\tif (Array.isArray(value)) {\n\t\tif (def.length !== undefined && value.length !== def.length) {\n\t\t\tfail(path, `expected length ${def.length}, received ${value.length}`);\n\t\t}\n\t\tif (def.min !== undefined && value.length < def.min) {\n\t\t\tfail(\n\t\t\t\tpath,\n\t\t\t\t`expected at least ${def.min} items, received ${value.length}`,\n\t\t\t);\n\t\t}\n\t\tif (def.max !== undefined && value.length > def.max) {\n\t\t\tfail(path, `expected at most ${def.max} items, received ${value.length}`);\n\t\t}\n\t}\n\tif (typeof value === \"number\") {\n\t\tif (def.int && !Number.isInteger(value)) {\n\t\t\tfail(path, `expected an integer, received ${value}`);\n\t\t}\n\t\tif (def.min !== undefined && value < def.min) {\n\t\t\tfail(path, `expected >= ${def.min}, received ${value}`);\n\t\t}\n\t\tif (def.max !== undefined && value > def.max) {\n\t\t\tfail(path, `expected <= ${def.max}, received ${value}`);\n\t\t}\n\t}\n\tif (def.check) {\n\t\tconst result = def.check(value);\n\t\tif (result !== true) {\n\t\t\tfail(path, typeof result === \"string\" ? result : \"failed check\");\n\t\t}\n\t}\n};\n\nexport const validate = (\n\tdef: TypeDefination<any, any, any>,\n\tvalue: unknown,\n\tpath: string,\n): any => {\n\t// `undefined` / (when optional) `null` fall back to the declared\n\t// default before anything else, then to `optional`, which passes the\n\t// absence through untouched. A shaped object with no default treats\n\t// omit as `{}` so all-optional fields can be left off the call without\n\t// a dummy payload. Non-optional `null` falls through to the type check.\n\tif (value === undefined || (value === null && def.optional)) {\n\t\tif (def.default !== undefined) {\n\t\t\t// Factories produce a fresh value each time - needed for Date /\n\t\t\t// object / array defaults. Skip on `function` schemas: there the\n\t\t\t// default IS the fn.\n\t\t\tvalue =\n\t\t\t\ttypeof def.default === \"function\" && def.name !== \"function\"\n\t\t\t\t\t? (def.default as () => unknown)()\n\t\t\t\t\t: def.default;\n\t\t} else if (def.optional) return value;\n\t\telse if (def.name === \"object\" && def.shape !== undefined) value = {};\n\t}\n\t// A var used as an input field validates against its own schema. An\n\t// absent value is left alone so the var keeps its default.\n\tif (isVar(def)) {\n\t\tif (value === undefined) return undefined;\n\t\tconst schema = (def as any).schema;\n\t\treturn schema === undefined ? value : validate(schema, value, path);\n\t}\n\tif (def.name === \"any\") {\n\t\treturn def.transform ? def.transform(value) : value;\n\t}\n\tif (def.name === \"date\") {\n\t\tif (!(value instanceof Date)) {\n\t\t\tthrow new ValidationError(\n\t\t\t\tpath,\n\t\t\t\t`expected date, received ${typeOf(value)}`,\n\t\t\t);\n\t\t}\n\t\treturn def.transform ? def.transform(value) : value;\n\t}\n\tif (def.name === \"function\") {\n\t\tif (typeof value !== \"function\") {\n\t\t\tthrow new ValidationError(\n\t\t\t\tpath,\n\t\t\t\t`expected function, received ${typeOf(value)}`,\n\t\t\t);\n\t\t}\n\t\t// A branded fn (`$fn`) validates its own declared input at its own\n\t\t// door; a plain closure gets THIS schema's input validated for it.\n\t\tconst inner = def.fnInput;\n\t\tif (inner === undefined || (value as { $fn?: boolean }).$fn === true) {\n\t\t\treturn value;\n\t\t}\n\t\tconst innerType = asType(inner);\n\t\treturn (input?: unknown, parent?: unknown) =>\n\t\t\t(value as (i: unknown, p: unknown) => unknown)(\n\t\t\t\tvalidate(innerType, input, `${path}()`),\n\t\t\t\tparent,\n\t\t\t);\n\t}\n\tif (def.name === \"array\") {\n\t\tif (!Array.isArray(value)) {\n\t\t\tthrow new ValidationError(\n\t\t\t\tpath,\n\t\t\t\t`expected array, received ${typeOf(value)}`,\n\t\t\t);\n\t\t}\n\t\tapplyRules(def, value, path);\n\t\t// No declared element (`v.array()`): ANY array - passed through\n\t\t// as-is, elements untouched.\n\t\tif (def.shape === undefined) {\n\t\t\treturn def.transform ? def.transform(value) : value;\n\t\t}\n\t\t// Every element validates - ALL failures report together, not\n\t\t// just the first, mirroring object fields.\n\t\tconst elementType = asType(def.shape);\n\t\tconst items: unknown[] = [];\n\t\tconst problems: Issue[] = [];\n\t\tfor (let index = 0; index < value.length; index++) {\n\t\t\ttry {\n\t\t\t\titems.push(validate(elementType, value[index], `${path}[${index}]`));\n\t\t\t} catch (thrown) {\n\t\t\t\tif (!(thrown instanceof ValidationError)) throw thrown;\n\t\t\t\tproblems.push(...thrown.issues);\n\t\t\t}\n\t\t}\n\t\tconst firstProblem = problems[0];\n\t\tif (firstProblem) {\n\t\t\tthrow new ValidationError(\n\t\t\t\tfirstProblem.path,\n\t\t\t\tfirstProblem.message,\n\t\t\t\tproblems,\n\t\t\t);\n\t\t}\n\t\treturn def.transform ? def.transform(items) : items;\n\t}\n\tif (def.name === \"object\") {\n\t\tif (typeOf(value) !== \"object\") {\n\t\t\tthrow new ValidationError(\n\t\t\t\tpath,\n\t\t\t\t`expected object, received ${typeOf(value)}`,\n\t\t\t);\n\t\t}\n\t\t// No declared shape (`v.object()`): ANY object - passed through\n\t\t// as-is, nothing stripped.\n\t\tif (def.shape === undefined) {\n\t\t\treturn def.transform ? def.transform(value) : value;\n\t\t}\n\t\t// Every field validates - ALL failures report together, not just\n\t\t// the first. Three bad fields is one error with three issues.\n\t\tconst parsed: Record<string, unknown> = {};\n\t\tconst issues: Issue[] = [];\n\t\tfor (const [field, child] of Object.entries(\n\t\t\tdef.shape as Record<string, unknown>,\n\t\t)) {\n\t\t\ttry {\n\t\t\t\tconst parsedField = validate(\n\t\t\t\t\tasType(child),\n\t\t\t\t\t(value as Record<string, unknown>)[field],\n\t\t\t\t\t`${path}.${field}`,\n\t\t\t\t);\n\t\t\t\t// An absent optional field stays ABSENT - materializing the key\n\t\t\t\t// as `undefined` would clobber values it gets spread over.\n\t\t\t\tif (parsedField !== undefined) parsed[field] = parsedField;\n\t\t\t} catch (thrown) {\n\t\t\t\tif (!(thrown instanceof ValidationError)) throw thrown;\n\t\t\t\tissues.push(...thrown.issues);\n\t\t\t}\n\t\t}\n\t\tconst firstIssue = issues[0];\n\t\tif (firstIssue) {\n\t\t\tthrow new ValidationError(firstIssue.path, firstIssue.message, issues);\n\t\t}\n\t\treturn def.transform ? def.transform(parsed) : parsed;\n\t}\n\tif (def.name === \"union\") {\n\t\t// Try each option in order - first success wins. All failures\n\t\t// report together so callers see every branch's issues.\n\t\tconst options = def.shape;\n\t\tif (!Array.isArray(options) || options.length === 0) {\n\t\t\tthrow new ValidationError(path, \"expected a non-empty union\");\n\t\t}\n\t\tconst issues: Issue[] = [];\n\t\tlet parsed: unknown;\n\t\tlet matched = false;\n\t\tfor (const member of options) {\n\t\t\ttry {\n\t\t\t\tparsed = validate(asType(member), value, path);\n\t\t\t\tmatched = true;\n\t\t\t\tbreak;\n\t\t\t} catch (thrown) {\n\t\t\t\tif (!(thrown instanceof ValidationError)) throw thrown;\n\t\t\t\tissues.push(...thrown.issues);\n\t\t\t}\n\t\t}\n\t\tif (!matched) {\n\t\t\tconst firstIssue = issues[0];\n\t\t\tif (firstIssue) {\n\t\t\t\tthrow new ValidationError(firstIssue.path, firstIssue.message, issues);\n\t\t\t}\n\t\t\tthrow new ValidationError(\n\t\t\t\tpath,\n\t\t\t\t`expected union, received ${typeOf(value)}`,\n\t\t\t);\n\t\t}\n\t\tapplyRules(def, parsed, path);\n\t\treturn def.transform ? def.transform(parsed) : parsed;\n\t}\n\tif (typeOf(value) !== def.name) {\n\t\tthrow new ValidationError(\n\t\t\tpath,\n\t\t\t`expected ${def.name}, received ${typeOf(value)}`,\n\t\t);\n\t}\n\t// Canonicalize before rules so padded / mixed-case addresses pass the\n\t// email regex and handlers always see the normalized form.\n\tif (def.email && typeof value === \"string\") {\n\t\tvalue = value.trim().toLowerCase();\n\t}\n\tapplyRules(def, value, path);\n\treturn def.transform ? def.transform(value) : value;\n};\n\n/** Builds the runtime object; the declared return type is the contract. */\nconst build = (name: string, options: any, extra?: any): any => ({\n\tname,\n\t...extra,\n\t...options,\n});\n\n/** A default may be the value itself or a factory that mints it fresh on\n * each validate - `() => new Date()`, `() => []`, …. */\ntype DefaultInput<T> = T | (() => T);\n\n/**\n * Call signatures for the type helpers. Option-shape overloads replace\n * `Opt` / `D` type parameters so a partial type argument (literal narrowing)\n * does not lock `optional` / `default` to their defaults.\n */\ntype StringFn = {\n\t<const E extends string, O = E>(\n\t\toptions: StringOptions<E, O> & {\n\t\t\toptional: true;\n\t\t\tdefault: DefaultInput<string>;\n\t\t},\n\t): TypeDefination<E, O, string>;\n\t<const E extends string, O = E>(\n\t\toptions: StringOptions<E, O> & { optional: true },\n\t): TypeDefination<E, OutOf<O, never, true>, undefined>;\n\t<const E extends string, O = E>(\n\t\toptions: StringOptions<E, O> & { default: DefaultInput<string> },\n\t): TypeDefination<E, O, string>;\n\t<const E extends string, O = E>(\n\t\toptions?: StringOptions<E, O>,\n\t): TypeDefination<E, O, never>;\n};\n\ntype NumberFn = {\n\t<O = number>(\n\t\toptions: NumberOptions<O> & {\n\t\t\toptional: true;\n\t\t\tdefault: DefaultInput<number>;\n\t\t},\n\t): TypeDefination<number, O, number>;\n\t<O = number>(\n\t\toptions: NumberOptions<O> & { optional: true },\n\t): TypeDefination<number, OutOf<O, never, true>, undefined>;\n\t<O = number>(\n\t\toptions: NumberOptions<O> & { default: DefaultInput<number> },\n\t): TypeDefination<number, O, number>;\n\t<O = number>(options?: NumberOptions<O>): TypeDefination<number, O, never>;\n};\n\ntype BooleanFn = {\n\t<O = boolean>(\n\t\toptions: TypeOptions<boolean, O> & {\n\t\t\toptional: true;\n\t\t\tdefault: DefaultInput<boolean>;\n\t\t},\n\t): TypeDefination<boolean, O, boolean>;\n\t<O = boolean>(\n\t\toptions: TypeOptions<boolean, O> & { optional: true },\n\t): TypeDefination<boolean, OutOf<O, never, true>, undefined>;\n\t<O = boolean>(\n\t\toptions: TypeOptions<boolean, O> & { default: DefaultInput<boolean> },\n\t): TypeDefination<boolean, O, boolean>;\n\t<O = boolean>(\n\t\toptions?: TypeOptions<boolean, O>,\n\t): TypeDefination<boolean, O, never>;\n};\n\ntype DateFn = {\n\t<O = Date>(\n\t\toptions: TypeOptions<Date, O> & {\n\t\t\toptional: true;\n\t\t\tdefault: DefaultInput<Date>;\n\t\t},\n\t): TypeDefination<Date, O, Date>;\n\t<O = Date>(\n\t\toptions: TypeOptions<Date, O> & { optional: true },\n\t): TypeDefination<Date, OutOf<O, never, true>, undefined>;\n\t<O = Date>(\n\t\toptions: TypeOptions<Date, O> & { default: DefaultInput<Date> },\n\t): TypeDefination<Date, O, Date>;\n\t<O = Date>(options?: TypeOptions<Date, O>): TypeDefination<Date, O, never>;\n};\n\ntype AnyFn = {\n\t<T = unknown>(\n\t\toptions: TypeOptions<T, T> & { optional: true; default: DefaultInput<T> },\n\t): TypeDefination<T, T, T>;\n\t<T = unknown>(\n\t\toptions: TypeOptions<T, T> & { optional: true },\n\t): TypeDefination<T, OutOf<T, never, true>, undefined>;\n\t<T = unknown>(\n\t\toptions: TypeOptions<T, T> & { default: DefaultInput<T> },\n\t): TypeDefination<T, T, T>;\n\t<T = unknown>(options?: TypeOptions<T, T>): TypeDefination<T, T, never>;\n};\n\n/**\n * Object defaults may be partial: nested fields still run through\n * validate (so their own defaults apply). An empty `{}` is always\n * fine at the type level - parent `optional` / `default` must not\n * demand that every required child be listed in the default.\n */\ntype ObjectDefault<S> = DefaultInput<Partial<ArgsShape<S>>>;\n\ntype ObjectFn = {\n\t<S, O = DefineOutput<S>>(\n\t\tshape: S,\n\t\toptions: TypeOptions<DefineOutput<S>, O> & {\n\t\t\toptional: true;\n\t\t\tdefault: ObjectDefault<S>;\n\t\t},\n\t): TypeDefination<ArgsShape<S>, O, ArgsShape<S>>;\n\t<S, O = DefineOutput<S>>(\n\t\tshape: S,\n\t\toptions: TypeOptions<DefineOutput<S>, O> & { optional: true },\n\t): TypeDefination<ArgsShape<S>, OutOf<O, never, true>, undefined>;\n\t<S, O = DefineOutput<S>>(\n\t\tshape: S,\n\t\toptions: TypeOptions<DefineOutput<S>, O> & {\n\t\t\tdefault: ObjectDefault<S>;\n\t\t},\n\t): TypeDefination<ArgsShape<S>, O, ArgsShape<S>>;\n\t<S, O = DefineOutput<S>>(\n\t\tshape: S,\n\t\toptions?: TypeOptions<DefineOutput<S>, O>,\n\t): TypeDefination<ArgsShape<S>, O, never>;\n\t(): TypeDefination<Record<string, any>, Record<string, any>>;\n};\n\ntype ArrayFn = {\n\t<E, O = FieldOut<E>[]>(\n\t\telement: E,\n\t\toptions: ArrayOptions<E, O> & {\n\t\t\toptional: true;\n\t\t\t// Defaults are validated as inputs, so they use FieldIn.\n\t\t\tdefault: DefaultInput<FieldIn<E>[]>;\n\t\t},\n\t): TypeDefination<FieldIn<E>[], O, FieldIn<E>[]>;\n\t<E, O = FieldOut<E>[]>(\n\t\telement: E,\n\t\toptions: ArrayOptions<E, O> & { optional: true },\n\t): TypeDefination<FieldIn<E>[], OutOf<O, never, true>, undefined>;\n\t<E, O = FieldOut<E>[]>(\n\t\telement: E,\n\t\toptions: ArrayOptions<E, O> & { default: DefaultInput<FieldIn<E>[]> },\n\t): TypeDefination<FieldIn<E>[], O, FieldIn<E>[]>;\n\t<E, O = FieldOut<E>[]>(\n\t\telement: E,\n\t\toptions?: ArrayOptions<E, O>,\n\t): TypeDefination<FieldIn<E>[], O, never>;\n\t(\n\t\telement?: undefined,\n\t\toptions?: ArrayOptions<undefined, any[]> & {\n\t\t\toptional: true;\n\t\t\tdefault: DefaultInput<any[]>;\n\t\t},\n\t): TypeDefination<any[], any[], any[]>;\n\t(\n\t\telement?: undefined,\n\t\toptions?: ArrayOptions<undefined, any[]> & { optional: true },\n\t): TypeDefination<any[], any[] | undefined | null, undefined>;\n\t(\n\t\telement?: undefined,\n\t\toptions?: ArrayOptions<undefined, any[]> & {\n\t\t\tdefault: DefaultInput<any[]>;\n\t\t},\n\t): TypeDefination<any[], any[], any[]>;\n\t(\n\t\telement?: undefined,\n\t\toptions?: ArrayOptions<undefined, any[]>,\n\t): TypeDefination<any[], any[], never>;\n};\n\ntype UnionFn = {\n\t<const T extends readonly [unknown, ...unknown[]], O = FieldOut<T[number]>>(\n\t\tmembers: T,\n\t\toptions: UnionOptions<T, O> & {\n\t\t\toptional: true;\n\t\t\tdefault: DefaultInput<FieldIn<T[number]>>;\n\t\t},\n\t): TypeDefination<FieldIn<T[number]>, O, FieldIn<T[number]>>;\n\t<const T extends readonly [unknown, ...unknown[]], O = FieldOut<T[number]>>(\n\t\tmembers: T,\n\t\toptions: UnionOptions<T, O> & { optional: true },\n\t): TypeDefination<FieldIn<T[number]>, OutOf<O, never, true>, undefined>;\n\t<const T extends readonly [unknown, ...unknown[]], O = FieldOut<T[number]>>(\n\t\tmembers: T,\n\t\toptions: UnionOptions<T, O> & {\n\t\t\tdefault: DefaultInput<FieldIn<T[number]>>;\n\t\t},\n\t): TypeDefination<FieldIn<T[number]>, O, FieldIn<T[number]>>;\n\t<const T extends readonly [unknown, ...unknown[]], O = FieldOut<T[number]>>(\n\t\tmembers: T,\n\t\toptions?: UnionOptions<T, O>,\n\t): TypeDefination<FieldIn<T[number]>, O, never>;\n};\n\nexport const vTypes = {\n\t/** An `enum` narrows both sides to the literal union: `v.string({\n\t * enum: [\"a\", \"b\"] })` types as `\"a\" | \"b\"`, not `string`. */\n\tstring: ((options?: any) => build(\"string\", options)) as StringFn,\n\tnumber: ((options?: any) => build(\"number\", options)) as NumberFn,\n\tboolean: ((options?: any) => build(\"boolean\", options)) as BooleanFn,\n\t/** A Date INSTANCE - checked with `instanceof`, never parsed. */\n\tdate: ((options?: any) => build(\"date\", options)) as DateFn,\n\t/** Passthrough - validated as-is, never coerced or stripped. */\n\tany: ((options?: any) => build(\"any\", options)) as AnyFn,\n\t/** With a SHAPE every field validates; with NO shape (`v.object()`)\n\t * any object passes, as-is. */\n\tobject: ((shape?: any, options?: any) =>\n\t\tbuild(\"object\", options, shape === undefined ? {} : { shape })) as ObjectFn,\n\t/** With an ELEMENT every item validates - all failures report\n\t * together, like object fields; with NO element (`v.array()`) any\n\t * array passes, as-is. `min`/`max`/`length` count items. */\n\tarray: ((element?: any, options?: any) =>\n\t\tbuild(\n\t\t\t\"array\",\n\t\t\toptions,\n\t\t\telement === undefined ? {} : { shape: element },\n\t\t)) as ArrayFn,\n\t/** Try each option in order - first successful parse wins. All\n\t * failing branches report together when none match. */\n\tunion: ((members: any, options?: any) =>\n\t\tbuild(\"union\", options, { shape: members })) as UnionFn,\n};\n"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { Prettify } from "./types.cjs";
2
+ import { Collection } from "./storage.cjs";
3
+ import { ModuleVars, VarArgsInScope, VarExtensionsFor } from "./module.cjs";
4
+ //#region src/scope.d.ts
5
+ type MergeExtension<T, E> = T extends object ? Prettify<T & E> : T;
6
+ type Merged<PL, Base> = ModuleVars<PL> & Base;
7
+ type ResolvedVars<PL> = { [K in keyof ModuleVars<PL>]: MergeExtension<ModuleVars<PL>[K], VarExtensionsFor<PL, K & string>>; };
8
+ /**
9
+ * Row shape a collection uses inside scope `PL`: the model var as the
10
+ * scope sees it (extensions + same-name customize), falling back to the
11
+ * declared row plus any mounted `v.extend` fields.
12
+ */
13
+ type RowInScope<R, PL, N extends string> = N extends keyof ResolvedVars<PL> ? NonNullable<ResolvedVars<PL>[N]> : unknown extends VarExtensionsFor<PL, N> ? R : Prettify<R & VarExtensionsFor<PL, N>>;
14
+ type WidenSchemaFn<T, PL> = T extends {
15
+ $fnVar?: [infer N extends string];
16
+ } ? T extends ((input: infer A) => infer R) ? unknown extends VarArgsInScope<PL, N> ? T : ((input: Prettify<A & VarArgsInScope<PL, N>>) => R) & {
17
+ readonly $fnVar?: [N];
18
+ } : T : T;
19
+ /**
20
+ * Rewrite a `$modelVar`-branded collection so `Where` / returns use the
21
+ * composed model shape - same PL math as {@link WidenSchemaFn} / {@link
22
+ * ResolvedVars}.
23
+ */
24
+ type WidenCollection<T, PL> = T extends Collection<infer R, infer N> ? [R] extends [RowInScope<R, PL, N & string>] ? T : Collection<RowInScope<R, PL, N & string>, N & string> : T;
25
+ type WidenSchemaFns<T, PL> = T extends Collection<any, string> ? WidenCollection<T, PL> : T extends ((...args: any[]) => any) ? WidenSchemaFn<T, PL> : T extends readonly unknown[] ? { [K in keyof T]: WidenSchemaFns<T[K], PL>; } : T extends Date | RegExp | Promise<unknown> | Map<any, any> | Set<any> ? T : T extends object ? { [K in keyof T]: WidenSchemaFns<T[K], PL>; } : T;
26
+ type ScopeOf<PL, Base = unknown, ExtPL = PL> = { [K in keyof Merged<PL, Base>]: WidenSchemaFns<MergeExtension<Merged<PL, Base>[K], VarExtensionsFor<ExtPL, K & string>>, ExtPL>; };
27
+ type VarScope<RV, Required, RO extends boolean = false> = RO extends true ? { readonly [K in keyof RV]: K extends Required ? NonNullable<RV[K]> : RV[K]; } : Prettify<{ [K in keyof RV]: K extends Required ? NonNullable<RV[K]> : RV[K]; }>;
28
+ type VarName<RV> = keyof RV & string;
29
+ //#endregion
30
+ export { ResolvedVars, RowInScope, ScopeOf, VarName, VarScope, WidenSchemaFns };
31
+ //# sourceMappingURL=scope.d.cts.map
@@ -0,0 +1,31 @@
1
+ import { Prettify } from "./types.mjs";
2
+ import { Collection } from "./storage.mjs";
3
+ import { ModuleVars, VarArgsInScope, VarExtensionsFor } from "./module.mjs";
4
+ //#region src/scope.d.ts
5
+ type MergeExtension<T, E> = T extends object ? Prettify<T & E> : T;
6
+ type Merged<PL, Base> = ModuleVars<PL> & Base;
7
+ type ResolvedVars<PL> = { [K in keyof ModuleVars<PL>]: MergeExtension<ModuleVars<PL>[K], VarExtensionsFor<PL, K & string>>; };
8
+ /**
9
+ * Row shape a collection uses inside scope `PL`: the model var as the
10
+ * scope sees it (extensions + same-name customize), falling back to the
11
+ * declared row plus any mounted `v.extend` fields.
12
+ */
13
+ type RowInScope<R, PL, N extends string> = N extends keyof ResolvedVars<PL> ? NonNullable<ResolvedVars<PL>[N]> : unknown extends VarExtensionsFor<PL, N> ? R : Prettify<R & VarExtensionsFor<PL, N>>;
14
+ type WidenSchemaFn<T, PL> = T extends {
15
+ $fnVar?: [infer N extends string];
16
+ } ? T extends ((input: infer A) => infer R) ? unknown extends VarArgsInScope<PL, N> ? T : ((input: Prettify<A & VarArgsInScope<PL, N>>) => R) & {
17
+ readonly $fnVar?: [N];
18
+ } : T : T;
19
+ /**
20
+ * Rewrite a `$modelVar`-branded collection so `Where` / returns use the
21
+ * composed model shape - same PL math as {@link WidenSchemaFn} / {@link
22
+ * ResolvedVars}.
23
+ */
24
+ type WidenCollection<T, PL> = T extends Collection<infer R, infer N> ? [R] extends [RowInScope<R, PL, N & string>] ? T : Collection<RowInScope<R, PL, N & string>, N & string> : T;
25
+ type WidenSchemaFns<T, PL> = T extends Collection<any, string> ? WidenCollection<T, PL> : T extends ((...args: any[]) => any) ? WidenSchemaFn<T, PL> : T extends readonly unknown[] ? { [K in keyof T]: WidenSchemaFns<T[K], PL>; } : T extends Date | RegExp | Promise<unknown> | Map<any, any> | Set<any> ? T : T extends object ? { [K in keyof T]: WidenSchemaFns<T[K], PL>; } : T;
26
+ type ScopeOf<PL, Base = unknown, ExtPL = PL> = { [K in keyof Merged<PL, Base>]: WidenSchemaFns<MergeExtension<Merged<PL, Base>[K], VarExtensionsFor<ExtPL, K & string>>, ExtPL>; };
27
+ type VarScope<RV, Required, RO extends boolean = false> = RO extends true ? { readonly [K in keyof RV]: K extends Required ? NonNullable<RV[K]> : RV[K]; } : Prettify<{ [K in keyof RV]: K extends Required ? NonNullable<RV[K]> : RV[K]; }>;
28
+ type VarName<RV> = keyof RV & string;
29
+ //#endregion
30
+ export { ResolvedVars, RowInScope, ScopeOf, VarName, VarScope, WidenSchemaFns };
31
+ //# sourceMappingURL=scope.d.mts.map
@@ -0,0 +1,308 @@
1
+ const require_schema = require("./schema.cjs");
2
+ const require_module = require("./module.cjs");
3
+ //#region src/storage.ts
4
+ const WHERE_OPS = {
5
+ eq: true,
6
+ ne: true,
7
+ lt: true,
8
+ lte: true,
9
+ gt: true,
10
+ gte: true,
11
+ in: true,
12
+ notIn: true,
13
+ contains: true,
14
+ startsWith: true,
15
+ endsWith: true
16
+ };
17
+ /** An operator object is a plain record whose keys are ALL operator names.
18
+ * Anything else - a Date, an array, an empty object - is a value. */
19
+ const isOps = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date) && Object.keys(value).length > 0 && Object.keys(value).every((key) => key in WHERE_OPS);
20
+ /** Flatten a where to normalized conditions - the adapter author's
21
+ * translation seam: map each condition onto your query language, AND them. */
22
+ const conditionsOf = (where = {}) => Object.entries(where).flatMap(([field, spec]) => isOps(spec) ? Object.entries(spec).map(([op, value]) => ({
23
+ field,
24
+ op,
25
+ value
26
+ })) : [{
27
+ field,
28
+ op: "eq",
29
+ value: spec
30
+ }]);
31
+ /** Dates equate and order by their instant. */
32
+ const rawValue = (value) => value instanceof Date ? value.getTime() : value;
33
+ const equals = (a, b) => rawValue(a) === rawValue(b);
34
+ const compare = (a, b) => {
35
+ const left = rawValue(a);
36
+ const right = rawValue(b);
37
+ return left < right ? -1 : left > right ? 1 : 0;
38
+ };
39
+ const holds = (row, { field, op, value }) => {
40
+ const current = row[field];
41
+ switch (op) {
42
+ case "eq": return equals(current, value);
43
+ case "ne": return !equals(current, value);
44
+ case "lt":
45
+ case "lte":
46
+ case "gt":
47
+ case "gte": {
48
+ if (current == null || value == null) return false;
49
+ const order = compare(current, value);
50
+ if (op === "lt") return order < 0;
51
+ if (op === "lte") return order <= 0;
52
+ if (op === "gt") return order > 0;
53
+ return order >= 0;
54
+ }
55
+ case "in": return value.some((member) => equals(current, member));
56
+ case "notIn": return !value.some((member) => equals(current, member));
57
+ case "contains": return typeof current === "string" && current.includes(value);
58
+ case "startsWith": return typeof current === "string" && current.startsWith(value);
59
+ case "endsWith": return typeof current === "string" && current.endsWith(value);
60
+ }
61
+ };
62
+ /** Does a row satisfy a where? The in-memory evaluator - the dummy adapter
63
+ * runs on it, and any adapter over an unqueryable backend can too. */
64
+ const matchesWhere = (row, where = {}) => conditionsOf(where).every((condition) => holds(row, condition));
65
+ /** The DUMMY adapter: rows in arrays, one per model. Implements the whole
66
+ * surface - the optional verbs by mutation (single-threaded, so "atomic"),
67
+ * transactions by snapshot-and-restore. */
68
+ const memoryAdapter = () => {
69
+ let tables = /* @__PURE__ */ new Map();
70
+ const rows = (model) => {
71
+ let list = tables.get(model);
72
+ if (!list) {
73
+ list = [];
74
+ tables.set(model, list);
75
+ }
76
+ return list;
77
+ };
78
+ const self = {
79
+ create: (model, data) => {
80
+ const row = { ...data };
81
+ rows(model).push(row);
82
+ return row;
83
+ },
84
+ findOne: (model, where) => rows(model).find((row) => matchesWhere(row, where)) ?? null,
85
+ findMany: (model, where, options) => {
86
+ let list = rows(model).filter((row) => matchesWhere(row, where));
87
+ const sort = options?.sortBy;
88
+ if (sort) {
89
+ const direction = sort.direction === "desc" ? -1 : 1;
90
+ list = [...list].sort((a, b) => direction * compare(a[sort.field], b[sort.field]));
91
+ }
92
+ const start = options?.offset ?? 0;
93
+ const end = options?.limit === void 0 ? void 0 : start + options.limit;
94
+ return start === 0 && end === void 0 ? list : list.slice(start, end);
95
+ },
96
+ update: (model, where, patch) => {
97
+ const row = rows(model).find((r) => matchesWhere(r, where));
98
+ return row ? Object.assign(row, patch) : null;
99
+ },
100
+ delete: (model, where) => {
101
+ const list = rows(model);
102
+ const keep = list.filter((row) => !matchesWhere(row, where));
103
+ tables.set(model, keep);
104
+ return list.length - keep.length;
105
+ },
106
+ count: (model, where) => rows(model).filter((row) => matchesWhere(row, where)).length,
107
+ consumeOne: (model, where) => {
108
+ const list = rows(model);
109
+ const index = list.findIndex((row) => matchesWhere(row, where));
110
+ return index === -1 ? null : list.splice(index, 1)[0];
111
+ },
112
+ incrementOne: (model, where, increments) => {
113
+ const row = rows(model).find((r) => matchesWhere(r, where));
114
+ if (!row) return null;
115
+ for (const [field, by] of Object.entries(increments)) row[field] = (row[field] ?? 0) + by;
116
+ return row;
117
+ },
118
+ transaction: async (run) => {
119
+ const snapshot = new Map([...tables].map(([model, list]) => [model, list.map((row) => ({ ...row }))]));
120
+ try {
121
+ return await run(self);
122
+ } catch (thrown) {
123
+ tables = snapshot;
124
+ throw thrown;
125
+ }
126
+ }
127
+ };
128
+ return self;
129
+ };
130
+ /** Read `$attrs.db` off each field of a var's object schema. */
131
+ const fieldsFromSchema = (sv) => {
132
+ const schema = require_schema.asType(sv.schema ?? {});
133
+ if (schema.name !== "object" || schema.shape === void 0) return {};
134
+ const fields = {};
135
+ for (const [key, child] of Object.entries(schema.shape)) {
136
+ const meta = require_schema.attrsOf(child, "db");
137
+ if (meta && Object.keys(meta).length > 0) fields[key] = { ...meta };
138
+ }
139
+ return fields;
140
+ };
141
+ /**
142
+ * Schema attrs first; `ModelConfig.fields[k]` replaces that key entirely
143
+ * when present (compat override).
144
+ */
145
+ const resolveModelFields = (input) => {
146
+ if (require_schema.isVar(input)) {
147
+ const fromSchema = fieldsFromSchema(input);
148
+ return Object.keys(fromSchema).length > 0 ? fromSchema : void 0;
149
+ }
150
+ const config = input;
151
+ const fromSchema = fieldsFromSchema(config.schema);
152
+ const override = config.fields ?? {};
153
+ const merged = { ...fromSchema };
154
+ for (const [key, meta] of Object.entries(override)) if (meta !== void 0) merged[key] = meta;
155
+ return Object.keys(merged).length > 0 ? merged : void 0;
156
+ };
157
+ /** Normalize `$models` entries so adapters always see merged `fields`.
158
+ * Bare vars stay bare vars (identity preserved); use
159
+ * {@link resolveModelFields} to read schema attrs off them. ModelConfig
160
+ * entries get `fields` filled from schema attrs + overrides. */
161
+ const resolveModels = (models) => {
162
+ const out = {};
163
+ for (const [key, input] of Object.entries(models)) {
164
+ if (require_schema.isVar(input)) {
165
+ out[key] = input;
166
+ continue;
167
+ }
168
+ const config = input;
169
+ const fields = resolveModelFields(config);
170
+ out[key] = fields === void 0 ? { ...config } : {
171
+ ...config,
172
+ fields
173
+ };
174
+ }
175
+ return out;
176
+ };
177
+ /** Duck-type a storage instance - `$models` plus the `$adapter` method. */
178
+ const isStorage = (value) => typeof value === "object" && value !== null && "$models" in value && typeof value.$adapter === "function";
179
+ const OPS = [
180
+ "create",
181
+ "findOne",
182
+ "findMany",
183
+ "update",
184
+ "delete",
185
+ "count",
186
+ "consumeOne",
187
+ "incrementOne"
188
+ ];
189
+ /** The op against the backend, optional verbs falling back to the required
190
+ * six: find-then-write - correct alone, racy under contention. The comment
191
+ * every fallback deserves lives on `StorageAdapter`. */
192
+ const rawOp = (adapter, name, op, args) => {
193
+ if (op === "consumeOne" && !adapter.consumeOne) return (async () => {
194
+ const where = args[0];
195
+ const row = await adapter.findOne(name, where);
196
+ if (!row) return null;
197
+ await adapter.delete(name, row);
198
+ return row;
199
+ })();
200
+ if (op === "incrementOne" && !adapter.incrementOne) return (async () => {
201
+ const [where, increments] = args;
202
+ const row = await adapter.findOne(name, where);
203
+ if (!row) return null;
204
+ const patch = Object.fromEntries(Object.entries(increments).map(([field, by]) => [field, (row[field] ?? 0) + by]));
205
+ return adapter.update(name, where, patch);
206
+ })();
207
+ return adapter[op](name, ...args);
208
+ };
209
+ const buildStorage = (state, models) => {
210
+ const run = (key, name, op, args) => {
211
+ const base = () => Promise.resolve(rawOp(state.adapter, name, op, args));
212
+ return state.hooks.filter((entry) => require_module.matchesTarget(entry.target, `${key}.${op}`)).reduceRight((next, entry) => () => Promise.resolve(entry.hook({
213
+ model: key,
214
+ op,
215
+ args
216
+ }, next)), base)();
217
+ };
218
+ const storage = {};
219
+ for (const [key, input] of Object.entries(models)) {
220
+ const name = (require_schema.isVar(input) ? input : input.schema).name;
221
+ const collection = {
222
+ create: (data) => run(key, name, "create", [data]),
223
+ findOne: (where) => run(key, name, "findOne", [where]),
224
+ findMany: (where, options) => run(key, name, "findMany", [where, options]),
225
+ update: (where, patch) => run(key, name, "update", [where, patch]),
226
+ delete: (where) => run(key, name, "delete", [where]),
227
+ count: (where) => run(key, name, "count", [where]),
228
+ consumeOne: (where) => run(key, name, "consumeOne", [where]),
229
+ incrementOne: (where, increments) => run(key, name, "incrementOne", [where, increments])
230
+ };
231
+ storage[key] = collection;
232
+ if (require_schema.isVar(input)) continue;
233
+ for (const op of OPS) {
234
+ const declared = input[op];
235
+ if (!declared) continue;
236
+ const cacheKey = `${key}.${op}`;
237
+ let entries = state.subscriptions.get(cacheKey);
238
+ if (!entries) {
239
+ const produced = typeof declared === "function" ? declared(collection[op]) : declared;
240
+ entries = Array.isArray(produced) ? produced : [produced];
241
+ state.subscriptions.set(cacheKey, entries);
242
+ }
243
+ entries.forEach((entry, index) => {
244
+ storage[`${key}$${op}${index === 0 ? "" : index}`] = entry;
245
+ });
246
+ }
247
+ }
248
+ const self = Object.assign(storage, {
249
+ $adapter: (adapter) => {
250
+ state.adapter = adapter;
251
+ return self;
252
+ },
253
+ $on: (target, hook) => {
254
+ state.hooks.push({
255
+ target,
256
+ hook
257
+ });
258
+ return self;
259
+ },
260
+ $omit: (...keys) => buildStorage(state, Object.fromEntries(Object.entries(models).filter(([key]) => !keys.includes(key)))),
261
+ $pick: (...keys) => buildStorage(state, Object.fromEntries(keys.map((key) => [key, models[key]]))),
262
+ $extend: (more) => buildStorage(state, {
263
+ ...models,
264
+ ...more
265
+ }),
266
+ $transaction: (fn) => {
267
+ const inside = (adapter) => Promise.resolve(fn(buildStorage({
268
+ ...state,
269
+ adapter
270
+ }, models)));
271
+ return state.adapter.transaction ? state.adapter.transaction((tx) => inside(tx)) : inside(state.adapter);
272
+ },
273
+ $models: resolveModels(models)
274
+ });
275
+ return self;
276
+ };
277
+ /**
278
+ * MANY instances of a var: each model is a collection of rows shaped like
279
+ * the var's VALUE, addressed by the var's NAME - the var stays what it
280
+ * always was (the scope's one current instance), the storage holds every
281
+ * other one, and the query API is how rows move between the two.
282
+ *
283
+ * The returned storage is CUSTOMIZABLE through its `$` surface: `$adapter`
284
+ * swaps the backend in place, `$on` mounts hooks around ops,
285
+ * `$omit`/`$pick`/`$extend` derive model views over the same state, and
286
+ * `$transaction` scopes ops to one adapter transaction.
287
+ *
288
+ * A model can also DECLARE its persistence: pass `{ schema, create: ... }`
289
+ * instead of the bare var, and the op subscriptions ride on the storage as
290
+ * mountable `v.on` entries - `use: [db]` wires them into the app. The same
291
+ * config carries `fields` metadata (unique, index, references) for schema
292
+ * generators to consume.
293
+ */
294
+ const makeStorage = (adapter, models) => buildStorage({
295
+ adapter,
296
+ hooks: [],
297
+ subscriptions: /* @__PURE__ */ new Map()
298
+ }, models);
299
+ //#endregion
300
+ exports.conditionsOf = conditionsOf;
301
+ exports.fieldsFromSchema = fieldsFromSchema;
302
+ exports.isStorage = isStorage;
303
+ exports.makeStorage = makeStorage;
304
+ exports.matchesWhere = matchesWhere;
305
+ exports.memoryAdapter = memoryAdapter;
306
+ exports.resolveModelFields = resolveModelFields;
307
+
308
+ //# sourceMappingURL=storage.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.cjs","names":["asType","attrsOf","isVar","matchesTarget"],"sources":["../src/storage.ts"],"sourcesContent":["import { matchesTarget, type OnEntry } from \"./module\";\nimport { asType, attrsOf, isVar } from \"./schema\";\nimport type { NameOfVar, ValueOfVar, VarDefination } from \"./var\";\n\n/* ---------------------------------- where ---------------------------------- */\n\n/** Per-field operators, for everything equality can't say: expiry sweeps\n * (`lt`), revocation lists (`in`), guarded counters (`lt` as the guard).\n * A bare value stays plain equality - the common case reads like data. */\nexport type WhereOps<V> = {\n\teq?: V;\n\tne?: V;\n\tlt?: V;\n\tlte?: V;\n\tgt?: V;\n\tgte?: V;\n\tin?: readonly V[];\n\tnotIn?: readonly V[];\n\tcontains?: string;\n\tstartsWith?: string;\n\tendsWith?: string;\n};\n\nexport type WhereOp = keyof WhereOps<unknown>;\n\n/** AND across fields; each field a bare value (equality) or operators. */\nexport type Where<R> = { [K in keyof R]?: R[K] | WhereOps<R[K]> };\n\n/** One normalized clause: `{ tag: \"a\" }` -> `{ field: \"tag\", op: \"eq\" }`. */\nexport type Condition = { field: string; op: WhereOp; value: unknown };\n\nconst WHERE_OPS: Record<WhereOp, true> = {\n\teq: true,\n\tne: true,\n\tlt: true,\n\tlte: true,\n\tgt: true,\n\tgte: true,\n\tin: true,\n\tnotIn: true,\n\tcontains: true,\n\tstartsWith: true,\n\tendsWith: true,\n};\n\n/** An operator object is a plain record whose keys are ALL operator names.\n * Anything else - a Date, an array, an empty object - is a value. */\nconst isOps = (value: unknown): value is WhereOps<unknown> =>\n\ttypeof value === \"object\" &&\n\tvalue !== null &&\n\t!Array.isArray(value) &&\n\t!(value instanceof Date) &&\n\tObject.keys(value).length > 0 &&\n\tObject.keys(value).every((key) => key in WHERE_OPS);\n\n/** Flatten a where to normalized conditions - the adapter author's\n * translation seam: map each condition onto your query language, AND them. */\nexport const conditionsOf = (\n\twhere: Record<string, unknown> = {},\n): Condition[] =>\n\tObject.entries(where).flatMap(([field, spec]) =>\n\t\tisOps(spec)\n\t\t\t? Object.entries(spec).map(([op, value]) => ({\n\t\t\t\t\tfield,\n\t\t\t\t\top: op as WhereOp,\n\t\t\t\t\tvalue,\n\t\t\t\t}))\n\t\t\t: [{ field, op: \"eq\" as const, value: spec }],\n\t);\n\n/** Dates equate and order by their instant. */\nconst rawValue = (value: unknown) =>\n\tvalue instanceof Date ? value.getTime() : value;\n\nconst equals = (a: unknown, b: unknown) => rawValue(a) === rawValue(b);\n\nconst compare = (a: unknown, b: unknown): number => {\n\tconst left = rawValue(a) as number;\n\tconst right = rawValue(b) as number;\n\treturn left < right ? -1 : left > right ? 1 : 0;\n};\n\nconst holds = (\n\trow: Record<string, unknown>,\n\t{ field, op, value }: Condition,\n): boolean => {\n\tconst current = row[field];\n\tswitch (op) {\n\t\tcase \"eq\":\n\t\t\treturn equals(current, value);\n\t\tcase \"ne\":\n\t\t\treturn !equals(current, value);\n\t\tcase \"lt\":\n\t\tcase \"lte\":\n\t\tcase \"gt\":\n\t\tcase \"gte\": {\n\t\t\tif (current == null || value == null) return false;\n\t\t\tconst order = compare(current, value);\n\t\t\tif (op === \"lt\") return order < 0;\n\t\t\tif (op === \"lte\") return order <= 0;\n\t\t\tif (op === \"gt\") return order > 0;\n\t\t\treturn order >= 0;\n\t\t}\n\t\tcase \"in\":\n\t\t\treturn (value as readonly unknown[]).some((member) =>\n\t\t\t\tequals(current, member),\n\t\t\t);\n\t\tcase \"notIn\":\n\t\t\treturn !(value as readonly unknown[]).some((member) =>\n\t\t\t\tequals(current, member),\n\t\t\t);\n\t\tcase \"contains\":\n\t\t\treturn typeof current === \"string\" && current.includes(value as string);\n\t\tcase \"startsWith\":\n\t\t\treturn typeof current === \"string\" && current.startsWith(value as string);\n\t\tcase \"endsWith\":\n\t\t\treturn typeof current === \"string\" && current.endsWith(value as string);\n\t}\n};\n\n/** Does a row satisfy a where? The in-memory evaluator - the dummy adapter\n * runs on it, and any adapter over an unqueryable backend can too. */\nexport const matchesWhere = (\n\trow: Record<string, unknown>,\n\twhere: Record<string, unknown> = {},\n): boolean => conditionsOf(where).every((condition) => holds(row, condition));\n\n/* ----------------------------------- ops ----------------------------------- */\n\n/** Shaping for `findMany`: sort, then window. */\nexport type FindManyOptions<R> = {\n\tlimit?: number;\n\toffset?: number;\n\tsortBy?: { field: keyof R & string; direction?: \"asc\" | \"desc\" };\n};\n\n/** One model's CRUD surface. `create` is generic so a row EXTENDED by a\n * mounted module (an account with a password field) keeps its extra\n * fields through the round-trip outside a widened scope. Inside a scope\n * that mounts `v.extend` / same-name customize on the model var, {@link\n * WidenSchemaFns} rewrites `R` (see `$modelVar`) the same way it widens\n * `v.fn.type({ input: user })`. */\nexport type Collection<R, N extends string = string> = {\n\tcreate: <T extends R>(data: T) => Promise<T>;\n\tfindOne: (where: Where<R>) => Promise<R | null>;\n\tfindMany: (where?: Where<R>, options?: FindManyOptions<R>) => Promise<R[]>;\n\t/** Merge `patch` into the FIRST match - null when nothing matched. */\n\tupdate: (where: Where<R>, patch: Partial<R>) => Promise<R | null>;\n\t/** Remove every match; how many is the answer. */\n\tdelete: (where: Where<R>) => Promise<number>;\n\tcount: (where?: Where<R>) => Promise<number>;\n\t/** Claim the FIRST match: the row comes back and is GONE, atomically -\n\t * two racing consumers never both get it. Single-use credentials\n\t * (verification tokens, one-time codes) hang off this. */\n\tconsumeOne: (where: Where<R>) => Promise<R | null>;\n\t/** Add to numeric fields of the FIRST match, atomically; the where is\n\t * also the GUARD (`count: { lt: max }`), so check-and-bump is one op -\n\t * null means no row passed it. Rate limiting hangs off this. */\n\tincrementOne: (\n\t\twhere: Where<R>,\n\t\tincrements: Partial<Record<keyof R & string, number>>,\n\t) => Promise<R | null>;\n\t/**\n\t * Phantom: the model var's name. Scope resolution reads it to WIDEN\n\t * `R` with everything the scope mounts on that var - same role as\n\t * `$fnVar` on fn schemas. Optional, so plain collection objects still\n\t * satisfy the type.\n\t */\n\treadonly $modelVar?: [N];\n};\n\n/**\n * What a real database implements: six required verbs, models addressed by\n * NAME, `where` as bare-equality fields and/or operator objects\n * (`conditionsOf` normalizes either form). The storage API above never\n * changes - adapters translate it, sync or async.\n *\n * The optional verbs are ATOMICITY upgrades: without `consumeOne` /\n * `incrementOne` the storage falls back to find-then-write - correct alone,\n * racy under contention - and without `transaction` a `$transaction` block\n * runs plainly. Implement them where the backend has the primitive.\n */\nexport type StorageAdapter = {\n\tcreate: (model: string, data: Record<string, unknown>) => unknown;\n\tfindOne: (model: string, where: Record<string, unknown>) => unknown;\n\tfindMany: (\n\t\tmodel: string,\n\t\twhere?: Record<string, unknown>,\n\t\toptions?: FindManyOptions<Record<string, unknown>>,\n\t) => unknown;\n\tupdate: (\n\t\tmodel: string,\n\t\twhere: Record<string, unknown>,\n\t\tpatch: Record<string, unknown>,\n\t) => unknown;\n\tdelete: (model: string, where: Record<string, unknown>) => unknown;\n\tcount: (model: string, where?: Record<string, unknown>) => unknown;\n\t/** Atomic find-and-delete of the first match. */\n\tconsumeOne?: (model: string, where: Record<string, unknown>) => unknown;\n\t/** Atomic guarded add to numeric fields of the first match. */\n\tincrementOne?: (\n\t\tmodel: string,\n\t\twhere: Record<string, unknown>,\n\t\tincrements: Record<string, number>,\n\t) => unknown;\n\t/** Run `run` against a transaction-bound view of this adapter:\n\t * committed when it resolves, rolled back when it throws. */\n\ttransaction?: <T>(run: (tx: StorageAdapter) => Promise<T>) => Promise<T>;\n};\n\n/** The DUMMY adapter: rows in arrays, one per model. Implements the whole\n * surface - the optional verbs by mutation (single-threaded, so \"atomic\"),\n * transactions by snapshot-and-restore. */\nexport const memoryAdapter = (): StorageAdapter => {\n\tlet tables = new Map<string, Record<string, unknown>[]>();\n\tconst rows = (model: string) => {\n\t\tlet list = tables.get(model);\n\t\tif (!list) {\n\t\t\tlist = [];\n\t\t\ttables.set(model, list);\n\t\t}\n\t\treturn list;\n\t};\n\tconst self: StorageAdapter = {\n\t\tcreate: (model, data) => {\n\t\t\tconst row = { ...data };\n\t\t\trows(model).push(row);\n\t\t\treturn row;\n\t\t},\n\t\tfindOne: (model, where) =>\n\t\t\trows(model).find((row) => matchesWhere(row, where)) ?? null,\n\t\tfindMany: (model, where, options) => {\n\t\t\tlet list = rows(model).filter((row) => matchesWhere(row, where));\n\t\t\tconst sort = options?.sortBy;\n\t\t\tif (sort) {\n\t\t\t\tconst direction = sort.direction === \"desc\" ? -1 : 1;\n\t\t\t\tlist = [...list].sort(\n\t\t\t\t\t(a, b) => direction * compare(a[sort.field], b[sort.field]),\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst start = options?.offset ?? 0;\n\t\t\tconst end =\n\t\t\t\toptions?.limit === undefined ? undefined : start + options.limit;\n\t\t\treturn start === 0 && end === undefined ? list : list.slice(start, end);\n\t\t},\n\t\tupdate: (model, where, patch) => {\n\t\t\tconst row = rows(model).find((r) => matchesWhere(r, where));\n\t\t\treturn row ? Object.assign(row, patch) : null;\n\t\t},\n\t\tdelete: (model, where) => {\n\t\t\tconst list = rows(model);\n\t\t\tconst keep = list.filter((row) => !matchesWhere(row, where));\n\t\t\ttables.set(model, keep);\n\t\t\treturn list.length - keep.length;\n\t\t},\n\t\tcount: (model, where) =>\n\t\t\trows(model).filter((row) => matchesWhere(row, where)).length,\n\t\tconsumeOne: (model, where) => {\n\t\t\tconst list = rows(model);\n\t\t\tconst index = list.findIndex((row) => matchesWhere(row, where));\n\t\t\treturn index === -1 ? null : list.splice(index, 1)[0];\n\t\t},\n\t\tincrementOne: (model, where, increments) => {\n\t\t\tconst row = rows(model).find((r) => matchesWhere(r, where));\n\t\t\tif (!row) return null;\n\t\t\tfor (const [field, by] of Object.entries(increments)) {\n\t\t\t\trow[field] = ((row[field] as number) ?? 0) + by;\n\t\t\t}\n\t\t\treturn row;\n\t\t},\n\t\ttransaction: async (run) => {\n\t\t\tconst snapshot = new Map(\n\t\t\t\t[...tables].map(([model, list]) => [\n\t\t\t\t\tmodel,\n\t\t\t\t\tlist.map((row) => ({ ...row })),\n\t\t\t\t]),\n\t\t\t);\n\t\t\ttry {\n\t\t\t\treturn await run(self);\n\t\t\t} catch (thrown) {\n\t\t\t\ttables = snapshot;\n\t\t\t\tthrow thrown;\n\t\t\t}\n\t\t},\n\t};\n\treturn self;\n};\n\n/* ---------------------------------- models ---------------------------------- */\n\ntype AnyVar = VarDefination<any, any, any, any>;\n\n/** Persistence facts about one field the ROW SHAPE can't say - consumed by\n * schema generators and adapters, never acted on by the runtime. (Read\n * shaping like redaction is a `$on` hook, not metadata.) Prefer declaring\n * these via `db.unique` / `db.indexed` / `db.references` / `db.id` on the\n * field schema; `ModelConfig.fields` remains an override. */\nexport type FieldMeta = {\n\t/** Primary key for this model. */\n\tid?: boolean;\n\t/** No two rows share a value. */\n\tunique?: boolean;\n\t/** Worth an index. */\n\tindex?: boolean;\n\t/** Foreign key: this field holds `model.field` values. */\n\treferences?: {\n\t\tmodel: string;\n\t\tfield: string;\n\t\tonDelete?: \"cascade\" | \"set null\" | \"restrict\";\n\t};\n};\n\n/** Read `$attrs.db` off each field of a var's object schema. */\nexport const fieldsFromSchema = (sv: AnyVar): Record<string, FieldMeta> => {\n\tconst schema = asType((sv as { schema?: unknown }).schema ?? {});\n\tif (schema.name !== \"object\" || schema.shape === undefined) return {};\n\tconst fields: Record<string, FieldMeta> = {};\n\tfor (const [key, child] of Object.entries(\n\t\tschema.shape as Record<string, unknown>,\n\t)) {\n\t\tconst meta = attrsOf(child, \"db\") as FieldMeta | undefined;\n\t\tif (meta && Object.keys(meta).length > 0) fields[key] = { ...meta };\n\t}\n\treturn fields;\n};\n\n/**\n * Schema attrs first; `ModelConfig.fields[k]` replaces that key entirely\n * when present (compat override).\n */\nexport const resolveModelFields = (\n\tinput: ModelInput,\n): Record<string, FieldMeta> | undefined => {\n\tif (isVar(input)) {\n\t\tconst fromSchema = fieldsFromSchema(input as AnyVar);\n\t\treturn Object.keys(fromSchema).length > 0 ? fromSchema : undefined;\n\t}\n\tconst config = input as ModelConfig;\n\tconst fromSchema = fieldsFromSchema(config.schema);\n\tconst override = config.fields ?? {};\n\tconst merged: Record<string, FieldMeta> = { ...fromSchema };\n\tfor (const [key, meta] of Object.entries(override)) {\n\t\tif (meta !== undefined) merged[key] = meta;\n\t}\n\treturn Object.keys(merged).length > 0 ? merged : undefined;\n};\n\n/** Normalize `$models` entries so adapters always see merged `fields`.\n * Bare vars stay bare vars (identity preserved); use\n * {@link resolveModelFields} to read schema attrs off them. ModelConfig\n * entries get `fields` filled from schema attrs + overrides. */\nconst resolveModels = <M extends StorageModels>(models: M): M => {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [key, input] of Object.entries(models)) {\n\t\tif (isVar(input)) {\n\t\t\tout[key] = input;\n\t\t\tcontinue;\n\t\t}\n\t\tconst config = input as ModelConfig;\n\t\tconst fields = resolveModelFields(config);\n\t\tout[key] = fields === undefined ? { ...config } : { ...config, fields };\n\t}\n\treturn out as M;\n};\n\n/** What an op subscription hands back: `v.on` entries to mount. */\ntype SubscriptionEntries = OnEntry<string> | readonly OnEntry<string>[];\n\n/**\n * A model declared WITH its persistence: `schema` is the var (the shape),\n * `fields` carries per-field storage metadata, and each op key SUBSCRIBES\n * that op to app events - handed the bound collection op, it returns `v.on`\n * entries that mount wherever the storage does (`use: [db]`). An\n * already-built entry works in place of the fn.\n */\nexport type ModelConfig<SV extends AnyVar = AnyVar> = {\n\tschema: SV;\n\tfields?: {\n\t\t[F in keyof NonNullable<ValueOfVar<SV>>]?: FieldMeta;\n\t};\n} & {\n\t[Op in StorageOp]?:\n\t\t| ((\n\t\t\t\taction: Collection<NonNullable<ValueOfVar<SV>>>[Op],\n\t\t ) => SubscriptionEntries)\n\t\t| SubscriptionEntries;\n};\n\n/** A model is a bare var, or a config carrying the var as `schema`. */\ntype ModelInput = AnyVar | ModelConfig;\n\n/** The var behind a model input. Checked through `$var`, never `schema` -\n * a bare var also HAS a `schema` property (its type shape). */\ntype SchemaOf<T> = T extends { $var: true }\n\t? T\n\t: T extends { schema: infer SV }\n\t\t? SV\n\t\t: never;\n\ntype RowOf<T> = NonNullable<ValueOfVar<SchemaOf<T>>>;\n\n/** Declared name of the var behind a model input - brands the collection. */\ntype ModelVarName<T> = NameOfVar<SchemaOf<T>> & string;\n\nexport type StorageModels = Record<string, ModelInput>;\n\nexport type StorageOp =\n\t| \"create\"\n\t| \"findOne\"\n\t| \"findMany\"\n\t| \"update\"\n\t| \"delete\"\n\t| \"count\"\n\t| \"consumeOne\"\n\t| \"incrementOne\";\n\n/** What a storage hook sees: which model and op, with the op's arguments\n * positionally (`create` -> [data], `update` -> [where, patch], `findMany`\n * -> [where, options], `incrementOne` -> [where, increments], ...). */\nexport type StorageHookContext = {\n\t/** The model KEY being addressed (the storage's property name). */\n\tmodel: string;\n\top: StorageOp;\n\targs: readonly unknown[];\n};\n\n/** `next()` runs the op (hooks below it included) and resolves its result;\n * the hook's own return value IS the op's result - wrap, veto, transform. */\nexport type StorageHook = (\n\tc: StorageHookContext,\n\tnext: () => Promise<unknown>,\n) => unknown;\n\n/** Every target a storage hook can name - a flat union, so editors offer\n * the whole surface: exact (\"user.create\"), per-model (\"user.*\"), per-op\n * (\"*.create\"), everything (\"*\"). */\nexport type StorageTarget<M> =\n\t| \"*\"\n\t| `${keyof M & string}.${StorageOp | \"*\"}`\n\t| `*.${StorageOp}`;\n\nexport type Storage<M extends StorageModels> = {\n\t[K in keyof M]: Collection<RowOf<M[K]>, ModelVarName<M[K]>>;\n} & StorageApi<M>;\n\n/** Duck-type a storage instance - `$models` plus the `$adapter` method. */\nexport const isStorage = (value: unknown): value is Storage<StorageModels> =>\n\ttypeof value === \"object\" &&\n\tvalue !== null &&\n\t\"$models\" in value &&\n\ttypeof (value as { $adapter?: unknown }).$adapter === \"function\";\n\n/** The customization surface, `$`-prefixed so model keys never collide. */\nexport type StorageApi<M extends StorageModels> = {\n\t/** Swap the backend IN PLACE: every view of this storage - and every\n\t * module that captured it - starts hitting the new adapter. */\n\t$adapter: (adapter: StorageAdapter) => Storage<M>;\n\t/** Intercept ops: hooks stack in mount order and apply to every view\n\t * sharing this storage's state. */\n\t$on: (target: StorageTarget<M>, hook: StorageHook) => Storage<M>;\n\t/** A view WITHOUT these models - same adapter, same hooks. */\n\t$omit: <K extends keyof M & string>(...keys: K[]) => Storage<Omit<M, K>>;\n\t/** A view of ONLY these models - same adapter, same hooks. */\n\t$pick: <K extends keyof M & string>(...keys: K[]) => Storage<Pick<M, K>>;\n\t/** A view with MORE models - same adapter, same hooks. */\n\t$extend: <M2 extends StorageModels>(models: M2) => Storage<M & M2>;\n\t/** Run `fn` against a view whose ops share ONE adapter transaction -\n\t * committed when it resolves, rolled back when it throws. Same models,\n\t * same hooks (they run inside). An adapter without `transaction` runs\n\t * `fn` plainly - no atomicity, same answer. */\n\t$transaction: <T>(fn: (tx: Storage<M>) => Promise<T> | T) => Promise<T>;\n\t/** The model definitions this view exposes. */\n\t$models: M;\n};\n\n/** Adapter, hooks and produced subscription entries live HERE, shared by\n * every view of one storage - a `$pick`ed slice still writes through the\n * same backend and hook stack, and a subscription materializes ONCE (same\n * entry object across views, so double-mounting dedups by identity). */\ntype StorageState = {\n\tadapter: StorageAdapter;\n\thooks: { target: string; hook: StorageHook }[];\n\tsubscriptions: Map<string, readonly OnEntry<string>[]>;\n};\n\nconst OPS: readonly StorageOp[] = [\n\t\"create\",\n\t\"findOne\",\n\t\"findMany\",\n\t\"update\",\n\t\"delete\",\n\t\"count\",\n\t\"consumeOne\",\n\t\"incrementOne\",\n];\n\n/** The op against the backend, optional verbs falling back to the required\n * six: find-then-write - correct alone, racy under contention. The comment\n * every fallback deserves lives on `StorageAdapter`. */\nconst rawOp = (\n\tadapter: StorageAdapter,\n\tname: string,\n\top: StorageOp,\n\targs: unknown[],\n) => {\n\tif (op === \"consumeOne\" && !adapter.consumeOne) {\n\t\treturn (async () => {\n\t\t\tconst where = args[0] as Record<string, unknown>;\n\t\t\tconst row = (await adapter.findOne(name, where)) as Record<\n\t\t\t\tstring,\n\t\t\t\tunknown\n\t\t\t> | null;\n\t\t\tif (!row) return null;\n\t\t\t// Delete THE row by its own fields, not the where - an operator\n\t\t\t// where (`expiresAt: { lt }`) must not sweep other matches.\n\t\t\tawait adapter.delete(name, row);\n\t\t\treturn row;\n\t\t})();\n\t}\n\tif (op === \"incrementOne\" && !adapter.incrementOne) {\n\t\treturn (async () => {\n\t\t\tconst [where, increments] = args as [\n\t\t\t\tRecord<string, unknown>,\n\t\t\t\tRecord<string, number>,\n\t\t\t];\n\t\t\tconst row = (await adapter.findOne(name, where)) as Record<\n\t\t\t\tstring,\n\t\t\t\tunknown\n\t\t\t> | null;\n\t\t\tif (!row) return null;\n\t\t\tconst patch = Object.fromEntries(\n\t\t\t\tObject.entries(increments).map(([field, by]) => [\n\t\t\t\t\tfield,\n\t\t\t\t\t((row[field] as number) ?? 0) + by,\n\t\t\t\t]),\n\t\t\t);\n\t\t\treturn adapter.update(name, where, patch);\n\t\t})();\n\t}\n\treturn (adapter[op] as (...a: unknown[]) => unknown)(name, ...args);\n};\n\nconst buildStorage = <M extends StorageModels>(\n\tstate: StorageState,\n\tmodels: M,\n): Storage<M> => {\n\t// Every op funnels here: matching hooks compose around the adapter\n\t// call, first mounted outermost - the `v.on` rules, one layer down.\n\tconst run = (key: string, name: string, op: StorageOp, args: unknown[]) => {\n\t\tconst base = () => Promise.resolve(rawOp(state.adapter, name, op, args));\n\t\treturn state.hooks\n\t\t\t.filter((entry) => matchesTarget(entry.target, `${key}.${op}`))\n\t\t\t.reduceRight<() => Promise<unknown>>(\n\t\t\t\t(next, entry) => () =>\n\t\t\t\t\tPromise.resolve(entry.hook({ model: key, op, args }, next)),\n\t\t\t\tbase,\n\t\t\t)();\n\t};\n\n\tconst storage: Record<string, unknown> = {};\n\tfor (const [key, input] of Object.entries(models)) {\n\t\tconst def = isVar(input) ? input : (input as ModelConfig).schema;\n\t\tconst name = (def as { name: string }).name;\n\t\tconst collection = {\n\t\t\tcreate: (data: unknown) => run(key, name, \"create\", [data]),\n\t\t\tfindOne: (where: unknown) => run(key, name, \"findOne\", [where]),\n\t\t\tfindMany: (where?: unknown, options?: unknown) =>\n\t\t\t\trun(key, name, \"findMany\", [where, options]),\n\t\t\tupdate: (where: unknown, patch: unknown) =>\n\t\t\t\trun(key, name, \"update\", [where, patch]),\n\t\t\tdelete: (where: unknown) => run(key, name, \"delete\", [where]),\n\t\t\tcount: (where?: unknown) => run(key, name, \"count\", [where]),\n\t\t\tconsumeOne: (where: unknown) => run(key, name, \"consumeOne\", [where]),\n\t\t\tincrementOne: (where: unknown, increments: unknown) =>\n\t\t\t\trun(key, name, \"incrementOne\", [where, increments]),\n\t\t} satisfies Record<StorageOp, unknown>;\n\t\tstorage[key] = collection;\n\n\t\t// Op subscriptions become PROPERTIES of the storage, so mounting it\n\t\t// as a module (`use: [db]`) mounts the persistence it declared.\n\t\t// Materialized once per state - views share entry identity.\n\t\tif (isVar(input)) continue;\n\t\tfor (const op of OPS) {\n\t\t\tconst declared = (input as Record<string, unknown>)[op];\n\t\t\tif (!declared) continue;\n\t\t\tconst cacheKey = `${key}.${op}`;\n\t\t\tlet entries = state.subscriptions.get(cacheKey);\n\t\t\tif (!entries) {\n\t\t\t\tconst produced =\n\t\t\t\t\ttypeof declared === \"function\"\n\t\t\t\t\t\t? declared(collection[op])\n\t\t\t\t\t\t: (declared as SubscriptionEntries);\n\t\t\t\tentries = Array.isArray(produced) ? produced : [produced];\n\t\t\t\tstate.subscriptions.set(cacheKey, entries as OnEntry<string>[]);\n\t\t\t}\n\t\t\tentries.forEach((entry, index) => {\n\t\t\t\tstorage[`${key}$${op}${index === 0 ? \"\" : index}`] = entry;\n\t\t\t});\n\t\t}\n\t}\n\n\tconst self: Storage<M> = Object.assign(storage, {\n\t\t$adapter: (adapter: StorageAdapter) => {\n\t\t\tstate.adapter = adapter;\n\t\t\treturn self;\n\t\t},\n\t\t$on: (target: StorageTarget<M>, hook: StorageHook) => {\n\t\t\tstate.hooks.push({ target, hook });\n\t\t\treturn self;\n\t\t},\n\t\t$omit: (...keys: string[]) =>\n\t\t\tbuildStorage(\n\t\t\t\tstate,\n\t\t\t\tObject.fromEntries(\n\t\t\t\t\tObject.entries(models).filter(([key]) => !keys.includes(key)),\n\t\t\t\t) as StorageModels,\n\t\t\t),\n\t\t$pick: (...keys: string[]) =>\n\t\t\tbuildStorage(\n\t\t\t\tstate,\n\t\t\t\tObject.fromEntries(\n\t\t\t\t\tkeys.map((key) => [key, models[key]]),\n\t\t\t\t) as StorageModels,\n\t\t\t),\n\t\t$extend: (more: StorageModels) =>\n\t\t\tbuildStorage(state, { ...models, ...more }),\n\t\t$transaction: <T>(fn: (tx: Storage<M>) => Promise<T> | T) => {\n\t\t\t// The tx view is this storage with only the adapter swapped:\n\t\t\t// hooks and subscriptions stay the SHARED arrays, so they apply\n\t\t\t// (and mount) inside exactly as outside.\n\t\t\tconst inside = (adapter: StorageAdapter) =>\n\t\t\t\tPromise.resolve(fn(buildStorage({ ...state, adapter }, models)));\n\t\t\treturn state.adapter.transaction\n\t\t\t\t? state.adapter.transaction((tx) => inside(tx))\n\t\t\t\t: inside(state.adapter);\n\t\t},\n\t\t$models: resolveModels(models),\n\t} as StorageApi<M>) as Storage<M>;\n\treturn self;\n};\n\n/**\n * MANY instances of a var: each model is a collection of rows shaped like\n * the var's VALUE, addressed by the var's NAME - the var stays what it\n * always was (the scope's one current instance), the storage holds every\n * other one, and the query API is how rows move between the two.\n *\n * The returned storage is CUSTOMIZABLE through its `$` surface: `$adapter`\n * swaps the backend in place, `$on` mounts hooks around ops,\n * `$omit`/`$pick`/`$extend` derive model views over the same state, and\n * `$transaction` scopes ops to one adapter transaction.\n *\n * A model can also DECLARE its persistence: pass `{ schema, create: ... }`\n * instead of the bare var, and the op subscriptions ride on the storage as\n * mountable `v.on` entries - `use: [db]` wires them into the app. The same\n * config carries `fields` metadata (unique, index, references) for schema\n * generators to consume.\n */\nexport const makeStorage = <const M extends StorageModels>(\n\tadapter: StorageAdapter,\n\tmodels: M,\n): Storage<M> =>\n\tbuildStorage({ adapter, hooks: [], subscriptions: new Map() }, models);\n"],"mappings":"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"}