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
package/dist/var.d.cts ADDED
@@ -0,0 +1,46 @@
1
+ import { LiteralString, Prettify } from "./types.cjs";
2
+ import { AttrBag, DefineOutput, InferArgs, InferInput, TypeDefination, vTypes } from "./schema.cjs";
3
+ import { Fn } from "./fn.cjs";
4
+ //#region src/var.d.ts
5
+ interface VarDefination<N extends LiteralString, T, Schema = unknown, Source extends string = never> {
6
+ $var: true;
7
+ name: N;
8
+ default?: T;
9
+ /** Kept in the type so the var can also be used as an input field. */
10
+ schema?: Schema;
11
+ type?: T;
12
+ /** Phantom: the var this one derives from - `requires` on the source
13
+ * makes this one non-null too. */
14
+ $source?: Source;
15
+ /** Whole-var plugin attributes (field attrs live on the schema). */
16
+ $attrs?: AttrBag;
17
+ /**
18
+ * Object contributions from `use` modules merge instead of replacing:
19
+ * same-name var defaults and same-export-key namespaces shallow-merge
20
+ * onto this value (storage default + helpers). Writes accumulate too.
21
+ * `v.var(..., { merge: true })` brands this as `true` so context types
22
+ * fold same-key helpers onto the value.
23
+ */
24
+ $merge?: true | boolean;
25
+ customize: <S>(options: {
26
+ schema: (v: VarCustomizer<T>) => S;
27
+ }) => VarDefination<N, InferInput<S>, S>;
28
+ }
29
+ type ValueOfVar<SV> = SV extends VarDefination<any, infer T, any, any> ? T : never;
30
+ type NameOfVar<SV> = SV extends VarDefination<infer N, any, any, any> ? N : never;
31
+ /**
32
+ * The toolkit a `customize` callback receives. It is a SUPERSET of `v`'s
33
+ * type constructors on purpose - the callback parameter shadows `v`, so
34
+ * `(v) => v.add({ role: v.string() })` has to keep working.
35
+ */
36
+ type VarCustomizer<T> = typeof vTypes & {
37
+ /** Declare a fn-typed field: bare `fn` is "any function",
38
+ * `fn({ input, output })` a specific signature. */
39
+ fn: Fn;
40
+ add: <S>(shape: S) => TypeDefination<InferArgs<S>, Prettify<NonNullable<T> & DefineOutput<S>>>;
41
+ replace: <S>(schema: S) => S;
42
+ };
43
+ type VarMap = Record<string, VarDefination<any, any, any, any>>;
44
+ //#endregion
45
+ export { NameOfVar, ValueOfVar, VarCustomizer, VarDefination, VarMap };
46
+ //# sourceMappingURL=var.d.cts.map
package/dist/var.d.mts ADDED
@@ -0,0 +1,46 @@
1
+ import { LiteralString, Prettify } from "./types.mjs";
2
+ import { AttrBag, DefineOutput, InferArgs, InferInput, TypeDefination, vTypes } from "./schema.mjs";
3
+ import { Fn } from "./fn.mjs";
4
+ //#region src/var.d.ts
5
+ interface VarDefination<N extends LiteralString, T, Schema = unknown, Source extends string = never> {
6
+ $var: true;
7
+ name: N;
8
+ default?: T;
9
+ /** Kept in the type so the var can also be used as an input field. */
10
+ schema?: Schema;
11
+ type?: T;
12
+ /** Phantom: the var this one derives from - `requires` on the source
13
+ * makes this one non-null too. */
14
+ $source?: Source;
15
+ /** Whole-var plugin attributes (field attrs live on the schema). */
16
+ $attrs?: AttrBag;
17
+ /**
18
+ * Object contributions from `use` modules merge instead of replacing:
19
+ * same-name var defaults and same-export-key namespaces shallow-merge
20
+ * onto this value (storage default + helpers). Writes accumulate too.
21
+ * `v.var(..., { merge: true })` brands this as `true` so context types
22
+ * fold same-key helpers onto the value.
23
+ */
24
+ $merge?: true | boolean;
25
+ customize: <S>(options: {
26
+ schema: (v: VarCustomizer<T>) => S;
27
+ }) => VarDefination<N, InferInput<S>, S>;
28
+ }
29
+ type ValueOfVar<SV> = SV extends VarDefination<any, infer T, any, any> ? T : never;
30
+ type NameOfVar<SV> = SV extends VarDefination<infer N, any, any, any> ? N : never;
31
+ /**
32
+ * The toolkit a `customize` callback receives. It is a SUPERSET of `v`'s
33
+ * type constructors on purpose - the callback parameter shadows `v`, so
34
+ * `(v) => v.add({ role: v.string() })` has to keep working.
35
+ */
36
+ type VarCustomizer<T> = typeof vTypes & {
37
+ /** Declare a fn-typed field: bare `fn` is "any function",
38
+ * `fn({ input, output })` a specific signature. */
39
+ fn: Fn;
40
+ add: <S>(shape: S) => TypeDefination<InferArgs<S>, Prettify<NonNullable<T> & DefineOutput<S>>>;
41
+ replace: <S>(schema: S) => S;
42
+ };
43
+ type VarMap = Record<string, VarDefination<any, any, any, any>>;
44
+ //#endregion
45
+ export { NameOfVar, ValueOfVar, VarCustomizer, VarDefination, VarMap };
46
+ //# sourceMappingURL=var.d.mts.map
package/dist/var.mjs ADDED
@@ -0,0 +1,177 @@
1
+ import { ValidationError } from "./error.mjs";
2
+ import { asType, vTypes } from "./schema.mjs";
3
+ import { matchesTarget } from "./module.mjs";
4
+ import { fnImpl } from "./fn.mjs";
5
+ //#region src/var.ts
6
+ const varRegistry = /* @__PURE__ */ new Map();
7
+ const makeVar = (name, options = {}) => {
8
+ const schema = options.schema === void 0 ? void 0 : asType(options.schema);
9
+ const def = {
10
+ $var: true,
11
+ name,
12
+ default: options.default,
13
+ schema,
14
+ ...options.attrs !== void 0 ? { $attrs: options.attrs } : {},
15
+ $accessor: options.accessor === true,
16
+ $merge: options.merge === true,
17
+ $derive: options.derive,
18
+ customize: (opts) => makeVar(name, {
19
+ ...options,
20
+ default: def.default,
21
+ ...def.$attrs !== void 0 ? { attrs: def.$attrs } : {},
22
+ schema: opts.schema({
23
+ ...vTypes,
24
+ fn: fnImpl,
25
+ add: (shape) => ({
26
+ name: "object",
27
+ shape: {
28
+ ...def.schema?.shape ?? {},
29
+ ...shape
30
+ }
31
+ }),
32
+ replace: (schema) => schema
33
+ })
34
+ })
35
+ };
36
+ varRegistry.set(name, def);
37
+ return def;
38
+ };
39
+ /**
40
+ * Derive a var from another: computed lazily off the source on every read,
41
+ * so setting the source "sets" every var derived from it. Writing a
42
+ * derived var directly shadows the computation for that scope.
43
+ */
44
+ const deriveVar = (name, source, get) => makeVar(name, { derive: {
45
+ source: source.name,
46
+ get
47
+ } });
48
+ /** Cells materialize lazily from the registry on first touch. */
49
+ const getCell = (cells, name) => {
50
+ const existing = cells[name];
51
+ if (existing) return existing;
52
+ const def = varRegistry.get(name);
53
+ const cell = {
54
+ value: def?.$derive ? void 0 : def?.$accessor ? {} : def?.default,
55
+ derive: def?.$derive,
56
+ shadowed: false,
57
+ accumulate: def?.$accessor === true || def?.$merge === true
58
+ };
59
+ cells[name] = cell;
60
+ return cell;
61
+ };
62
+ /** The current value, deriveds computed off their source. A name never
63
+ * declared and never written reads `undefined` WITHOUT materializing a
64
+ * cell - property probes on the context must not pollute the scope. */
65
+ const readVar = (cells, name) => {
66
+ if (!cells[name] && !varRegistry.has(name)) return void 0;
67
+ const cell = getCell(cells, name);
68
+ if (cell.derive && !cell.shadowed) {
69
+ const src = readVar(cells, cell.derive.source);
70
+ return src == null ? null : cell.derive.get(src);
71
+ }
72
+ return cell.value;
73
+ };
74
+ /**
75
+ * A handler's `c`: its own fields (`name`, `value`, `fn`) in front, every
76
+ * other property a RAW read of the scope's vars - so a handler reading
77
+ * `c.<var>` cannot recurse into its own get hook.
78
+ */
79
+ const handlerContext = (cells, base) => new Proxy(base, {
80
+ get: (t, prop) => prop in t ? t[prop] : typeof prop === "string" ? readVar(cells, prop) : void 0,
81
+ has: (t, prop) => prop in t || typeof prop === "string" && prop in cells
82
+ });
83
+ const isThenable = (value) => typeof value?.then === "function";
84
+ /**
85
+ * Every write funnels here: the readonly lock beats everything, then the
86
+ * matching `var.set.<name>` entries run SYNCHRONOUSLY around the actual
87
+ * write - call `next()` to land it, skip to cancel, throw to abort. The
88
+ * bare "*" target means "every fn", never "every var write".
89
+ */
90
+ const writeVar = (frame, name, value) => {
91
+ if (frame.lockedBy) throw new ValidationError(`${frame.key}.readonly`, `"${frame.lockedBy}" is readonly: attempted to write var "${name}"`);
92
+ const cell = getCell(frame.cells, name);
93
+ const merged = () => {
94
+ const current = cell.derive && !cell.shadowed ? readVar(frame.cells, name) : cell.value;
95
+ return {
96
+ ...typeof current === "object" && current !== null ? current : {},
97
+ ...value
98
+ };
99
+ };
100
+ const next = cell.accumulate ? merged() : value;
101
+ const apply = () => {
102
+ cell.value = next;
103
+ if (cell.derive) cell.shadowed = true;
104
+ };
105
+ const hooks = frame.entries.filter((e) => e.target !== "*" && matchesTarget(e.target, `var.set.${name}`));
106
+ if (hooks.length === 0) return apply();
107
+ hooks.reduceRight((proceed, entry) => () => {
108
+ const result = entry.handler(handlerContext(frame.cells, {
109
+ name,
110
+ value: next,
111
+ fn: frame.key
112
+ }), proceed);
113
+ if (isThenable(result)) throw new ValidationError(`${frame.key}.set`, `var-set handlers must be synchronous - "${String(entry.target)}" returned a promise`);
114
+ }, apply)();
115
+ };
116
+ /**
117
+ * Context reads funnel here: matching `var.get.<name>` entries run
118
+ * SYNCHRONOUSLY around the raw read - `next()` yields the stored value and
119
+ * whatever the handler returns becomes the read result. Internal reads
120
+ * stay raw: derive sources, handler contexts (so a handler reading a var
121
+ * off `c` cannot recurse into itself) and contract checks all see the
122
+ * cell as-is.
123
+ */
124
+ const readVarThrough = (frame, name) => {
125
+ const hooks = frame.entries.filter((e) => e.target !== "*" && matchesTarget(e.target, `var.get.${name}`));
126
+ if (hooks.length === 0) return readVar(frame.cells, name);
127
+ return hooks.reduceRight((proceed, entry) => () => {
128
+ const result = entry.handler(handlerContext(frame.cells, {
129
+ name,
130
+ fn: frame.key
131
+ }), proceed);
132
+ if (isThenable(result)) throw new ValidationError(`${frame.key}.get`, `var-get handlers must be synchronous - "${String(entry.target)}" returned a promise`);
133
+ return result;
134
+ }, () => readVar(frame.cells, name))();
135
+ };
136
+ /**
137
+ * Merge-var reads expose a shallow view that binds any `$fn` member into
138
+ * this context - helpers contributed via `use` call like usable fns.
139
+ */
140
+ const viewMergeVar = (name, value, ctx) => {
141
+ if (!varRegistry.get(name)?.$merge || value == null || typeof value !== "object") return value;
142
+ return new Proxy(value, { get: (t, prop, receiver) => {
143
+ const member = Reflect.get(t, prop, receiver);
144
+ if (typeof member !== "function" || member.$fn !== true) return member;
145
+ const usedArity = member.$arity;
146
+ return usedArity === void 0 ? (i) => member(i, ctx) : (...args) => {
147
+ const padded = args.slice(0, usedArity);
148
+ while (padded.length < usedArity) padded.push(void 0);
149
+ return member(...padded, ctx);
150
+ };
151
+ } });
152
+ };
153
+ /**
154
+ * The fn context for one frame: `base` carries the fixed surface (input,
155
+ * error, fn, types, the bound `use` fns, internal symbols) and EVERY
156
+ * other property is a var - read it directly (`c.session.userId`) and
157
+ * write it by plain assignment (`c.session = {...}`). Reads route through
158
+ * the `var.get` entries, writes through `writeVar` (readonly lock,
159
+ * `var.set` entries), and both are always synchronous. Base keys shadow
160
+ * vars of the same name, both ways.
161
+ */
162
+ const contextScope = (frame, base) => new Proxy(base, {
163
+ get: (t, prop, receiver) => {
164
+ if (prop in t) return Reflect.get(t, prop, receiver);
165
+ if (typeof prop === "string") return viewMergeVar(prop, readVarThrough(frame, prop), receiver);
166
+ },
167
+ set: (t, prop, value, receiver) => {
168
+ if (typeof prop !== "string" || prop in t) return Reflect.set(t, prop, value, receiver);
169
+ writeVar(frame, prop, value);
170
+ return true;
171
+ },
172
+ has: (t, prop) => prop in t || typeof prop === "string"
173
+ });
174
+ //#endregion
175
+ export { contextScope, deriveVar, getCell, handlerContext, makeVar, readVar, readVarThrough, varRegistry, viewMergeVar, writeVar };
176
+
177
+ //# sourceMappingURL=var.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"var.mjs","names":[],"sources":["../src/var.ts"],"sourcesContent":["import { ValidationError } from \"./error\";\n// Cycle with fn.ts (it imports our cells): fine, `fnImpl` is only touched\n// inside the lazy `customize` closure, never during module evaluation.\nimport { type Fn, fnImpl } from \"./fn\";\nimport { matchesTarget, type OnEntry } from \"./module\";\nimport {\n\ttype AttrBag,\n\tasType,\n\ttype DefineOutput,\n\ttype InferArgs,\n\ttype InferInput,\n\ttype TypeDefination,\n\tvTypes,\n} from \"./schema\";\nimport type { LiteralString, Prettify } from \"./types\";\n\nexport interface VarDefination<\n\tN extends LiteralString,\n\tT,\n\tSchema = unknown,\n\tSource extends string = never,\n> {\n\t$var: true;\n\tname: N;\n\tdefault?: T;\n\t/** Kept in the type so the var can also be used as an input field. */\n\tschema?: Schema;\n\ttype?: T;\n\t/** Phantom: the var this one derives from - `requires` on the source\n\t * makes this one non-null too. */\n\t$source?: Source;\n\t/** Whole-var plugin attributes (field attrs live on the schema). */\n\t$attrs?: AttrBag;\n\t/**\n\t * Object contributions from `use` modules merge instead of replacing:\n\t * same-name var defaults and same-export-key namespaces shallow-merge\n\t * onto this value (storage default + helpers). Writes accumulate too.\n\t * `v.var(..., { merge: true })` brands this as `true` so context types\n\t * fold same-key helpers onto the value.\n\t */\n\t$merge?: true | boolean;\n\tcustomize: <S>(options: {\n\t\tschema: (v: VarCustomizer<T>) => S;\n\t}) => VarDefination<N, InferInput<S>, S>;\n}\n\nexport type ValueOfVar<SV> =\n\tSV extends VarDefination<any, infer T, any, any> ? T : never;\n\nexport type NameOfVar<SV> =\n\tSV extends VarDefination<infer N, any, any, any> ? N : never;\n\n/**\n * The toolkit a `customize` callback receives. It is a SUPERSET of `v`'s\n * type constructors on purpose - the callback parameter shadows `v`, so\n * `(v) => v.add({ role: v.string() })` has to keep working.\n */\nexport type VarCustomizer<T> = typeof vTypes & {\n\t/** Declare a fn-typed field: bare `fn` is \"any function\",\n\t * `fn({ input, output })` a specific signature. */\n\tfn: Fn;\n\t// The args side goes through InferArgs, not a plain key-for-key map, so\n\t// an `optional`/defaulted added field is optional to SEND as well - the\n\t// same rule `v.object` applies to its shape.\n\tadd: <S>(\n\t\tshape: S,\n\t) => TypeDefination<InferArgs<S>, Prettify<NonNullable<T> & DefineOutput<S>>>;\n\treplace: <S>(schema: S) => S;\n};\n\nexport type VarMap = Record<string, VarDefination<any, any, any, any>>;\n\nexport const varRegistry = new Map<string, any>();\n\nexport const makeVar = (name: string, options: any = {}): any => {\n\tconst schema =\n\t\toptions.schema === undefined ? undefined : asType(options.schema);\n\tconst def: any = {\n\t\t$var: true,\n\t\tname,\n\t\tdefault: options.default,\n\t\tschema,\n\t\t...(options.attrs !== undefined ? { $attrs: options.attrs } : {}),\n\t\t$accessor: options.accessor === true,\n\t\t$merge: options.merge === true,\n\t\t$derive: options.derive,\n\t\tcustomize: (opts: any) =>\n\t\t\tmakeVar(name, {\n\t\t\t\t...options,\n\t\t\t\tdefault: def.default,\n\t\t\t\t// Carry whole-var attrs through customize (including any\n\t\t\t\t// attached after mint via withAttrs-rebinding, which goes\n\t\t\t\t// through its own path; this covers options.attrs).\n\t\t\t\t...(def.$attrs !== undefined ? { attrs: def.$attrs } : {}),\n\t\t\t\tschema: opts.schema({\n\t\t\t\t\t...vTypes,\n\t\t\t\t\tfn: fnImpl,\n\t\t\t\t\tadd: (shape: any) => ({\n\t\t\t\t\t\tname: \"object\",\n\t\t\t\t\t\tshape: { ...((def.schema?.shape as any) ?? {}), ...shape },\n\t\t\t\t\t}),\n\t\t\t\t\treplace: (schema: any) => schema,\n\t\t\t\t}),\n\t\t\t}),\n\t};\n\tvarRegistry.set(name, def);\n\treturn def;\n};\n\n/**\n * Derive a var from another: computed lazily off the source on every read,\n * so setting the source \"sets\" every var derived from it. Writing a\n * derived var directly shadows the computation for that scope.\n */\nexport const deriveVar = (name: string, source: any, get: any): any =>\n\tmakeVar(name, { derive: { source: source.name, get } });\n\n/* ---------------------------------- cells ---------------------------------- */\n\n/**\n * One var's state within a scope: the current value, plus how reads and\n * writes behave for it (derived computation, record accumulation).\n */\nexport type Cell = {\n\tvalue: unknown;\n\tderive?: { source: string; get: (value: any) => any };\n\t/** A direct write to a derived var shadows its computation. */\n\tshadowed: boolean;\n\t/** Record / merge var: `set()` merges instead of replacing. */\n\taccumulate: boolean;\n};\n\nexport type Cells = Record<string, Cell>;\n\n/** Cells materialize lazily from the registry on first touch. */\nexport const getCell = (cells: Cells, name: string): Cell => {\n\tconst existing = cells[name];\n\tif (existing) return existing;\n\tconst def = varRegistry.get(name);\n\tconst cell: Cell = {\n\t\tvalue: def?.$derive ? undefined : def?.$accessor ? {} : def?.default,\n\t\tderive: def?.$derive,\n\t\tshadowed: false,\n\t\taccumulate: def?.$accessor === true || def?.$merge === true,\n\t};\n\tcells[name] = cell;\n\treturn cell;\n};\n\n/** The current value, deriveds computed off their source. A name never\n * declared and never written reads `undefined` WITHOUT materializing a\n * cell - property probes on the context must not pollute the scope. */\nexport const readVar = (cells: Cells, name: string): unknown => {\n\tif (!cells[name] && !varRegistry.has(name)) return undefined;\n\tconst cell = getCell(cells, name);\n\tif (cell.derive && !cell.shadowed) {\n\t\tconst src = readVar(cells, cell.derive.source);\n\t\treturn src == null ? null : cell.derive.get(src);\n\t}\n\treturn cell.value;\n};\n\n/**\n * A handler's `c`: its own fields (`name`, `value`, `fn`) in front, every\n * other property a RAW read of the scope's vars - so a handler reading\n * `c.<var>` cannot recurse into its own get hook.\n */\nexport const handlerContext = (\n\tcells: Cells,\n\tbase: Record<string, unknown>,\n): Record<string, unknown> =>\n\tnew Proxy(base, {\n\t\tget: (t, prop) =>\n\t\t\tprop in t\n\t\t\t\t? (t as any)[prop]\n\t\t\t\t: typeof prop === \"string\"\n\t\t\t\t\t? readVar(cells, prop)\n\t\t\t\t\t: undefined,\n\t\thas: (t, prop) => prop in t || (typeof prop === \"string\" && prop in cells),\n\t});\n\n/* ---------------------------------- frame ---------------------------------- */\n\n/**\n * What a handle needs to know about the fn frame it was created in: the\n * scope's cells, plus everything write behavior depends on there.\n */\nexport type Frame = {\n\tcells: Cells;\n\tkey: string;\n\tlockedBy: string | undefined;\n\tentries: readonly OnEntry<string>[];\n};\n\nconst isThenable = (value: any): value is Promise<unknown> =>\n\ttypeof value?.then === \"function\";\n\n/**\n * Every write funnels here: the readonly lock beats everything, then the\n * matching `var.set.<name>` entries run SYNCHRONOUSLY around the actual\n * write - call `next()` to land it, skip to cancel, throw to abort. The\n * bare \"*\" target means \"every fn\", never \"every var write\".\n */\nexport const writeVar = (frame: Frame, name: string, value: unknown) => {\n\tif (frame.lockedBy) {\n\t\tthrow new ValidationError(\n\t\t\t`${frame.key}.readonly`,\n\t\t\t`\"${frame.lockedBy}\" is readonly: attempted to write var \"${name}\"`,\n\t\t);\n\t}\n\tconst cell = getCell(frame.cells, name);\n\tconst merged = () => {\n\t\tconst current =\n\t\t\tcell.derive && !cell.shadowed ? readVar(frame.cells, name) : cell.value;\n\t\tconst base = typeof current === \"object\" && current !== null ? current : {};\n\t\treturn { ...base, ...(value as Record<string, unknown>) };\n\t};\n\tconst next = cell.accumulate ? merged() : value;\n\tconst apply = () => {\n\t\tcell.value = next;\n\t\tif (cell.derive) cell.shadowed = true;\n\t};\n\tconst hooks = frame.entries.filter(\n\t\t(e) => e.target !== \"*\" && matchesTarget(e.target, `var.set.${name}`),\n\t);\n\tif (hooks.length === 0) return apply();\n\tconst chain = hooks.reduceRight<() => void>(\n\t\t(proceed, entry) => () => {\n\t\t\tconst result = entry.handler(\n\t\t\t\thandlerContext(frame.cells, {\n\t\t\t\t\tname,\n\t\t\t\t\tvalue: next,\n\t\t\t\t\tfn: frame.key,\n\t\t\t\t}) as any,\n\t\t\t\tproceed as any,\n\t\t\t);\n\t\t\tif (isThenable(result)) {\n\t\t\t\tthrow new ValidationError(\n\t\t\t\t\t`${frame.key}.set`,\n\t\t\t\t\t`var-set handlers must be synchronous - \"${String(entry.target)}\" returned a promise`,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t\tapply,\n\t);\n\tchain();\n};\n\n/**\n * Context reads funnel here: matching `var.get.<name>` entries run\n * SYNCHRONOUSLY around the raw read - `next()` yields the stored value and\n * whatever the handler returns becomes the read result. Internal reads\n * stay raw: derive sources, handler contexts (so a handler reading a var\n * off `c` cannot recurse into itself) and contract checks all see the\n * cell as-is.\n */\nexport const readVarThrough = (frame: Frame, name: string): unknown => {\n\tconst hooks = frame.entries.filter(\n\t\t(e) => e.target !== \"*\" && matchesTarget(e.target, `var.get.${name}`),\n\t);\n\tif (hooks.length === 0) return readVar(frame.cells, name);\n\tconst chain = hooks.reduceRight<() => unknown>(\n\t\t(proceed, entry) => () => {\n\t\t\tconst result = entry.handler(\n\t\t\t\thandlerContext(frame.cells, {\n\t\t\t\t\tname,\n\t\t\t\t\tfn: frame.key,\n\t\t\t\t}) as any,\n\t\t\t\tproceed as any,\n\t\t\t);\n\t\t\tif (isThenable(result)) {\n\t\t\t\tthrow new ValidationError(\n\t\t\t\t\t`${frame.key}.get`,\n\t\t\t\t\t`var-get handlers must be synchronous - \"${String(entry.target)}\" returned a promise`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn result;\n\t\t},\n\t\t() => readVar(frame.cells, name),\n\t);\n\treturn chain();\n};\n\n/* ---------------------------------- scope ---------------------------------- */\n\n/**\n * Merge-var reads expose a shallow view that binds any `$fn` member into\n * this context - helpers contributed via `use` call like usable fns.\n */\nexport const viewMergeVar = (\n\tname: string,\n\tvalue: unknown,\n\tctx: unknown,\n): unknown => {\n\tconst def = varRegistry.get(name);\n\tif (!def?.$merge || value == null || typeof value !== \"object\") return value;\n\treturn new Proxy(value as object, {\n\t\tget: (t, prop, receiver) => {\n\t\t\tconst member = Reflect.get(t, prop, receiver);\n\t\t\tif (\n\t\t\t\ttypeof member !== \"function\" ||\n\t\t\t\t(member as { $fn?: boolean }).$fn !== true\n\t\t\t) {\n\t\t\t\treturn member;\n\t\t\t}\n\t\t\tconst usedArity = (member as { $arity?: number }).$arity;\n\t\t\treturn usedArity === undefined\n\t\t\t\t? (i?: unknown) => (member as any)(i, ctx)\n\t\t\t\t: (...args: unknown[]) => {\n\t\t\t\t\t\tconst padded = args.slice(0, usedArity);\n\t\t\t\t\t\twhile (padded.length < usedArity) padded.push(undefined);\n\t\t\t\t\t\treturn (member as any)(...padded, ctx);\n\t\t\t\t\t};\n\t\t},\n\t});\n};\n\n/**\n * The fn context for one frame: `base` carries the fixed surface (input,\n * error, fn, types, the bound `use` fns, internal symbols) and EVERY\n * other property is a var - read it directly (`c.session.userId`) and\n * write it by plain assignment (`c.session = {...}`). Reads route through\n * the `var.get` entries, writes through `writeVar` (readonly lock,\n * `var.set` entries), and both are always synchronous. Base keys shadow\n * vars of the same name, both ways.\n */\nexport const contextScope = (frame: Frame, base: object): any =>\n\tnew Proxy(base, {\n\t\tget: (t, prop, receiver) => {\n\t\t\tif (prop in t) return Reflect.get(t, prop, receiver);\n\t\t\tif (typeof prop === \"string\") {\n\t\t\t\treturn viewMergeVar(prop, readVarThrough(frame, prop), receiver);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t\tset: (t, prop, value, receiver) => {\n\t\t\tif (typeof prop !== \"string\" || prop in t) {\n\t\t\t\treturn Reflect.set(t, prop, value, receiver);\n\t\t\t}\n\t\t\twriteVar(frame, prop, value);\n\t\t\treturn true;\n\t\t},\n\t\thas: (t, prop) => prop in t || typeof prop === \"string\",\n\t});\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,114 @@
1
+ {
2
+ "name": "better-call",
3
+ "version": "0.0.0-experimental.01ff4b77",
4
+ "type": "module",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/better-auth/better-call.git",
8
+ "directory": "packages/experimental"
9
+ },
10
+ "copyright": "Copyright (C) 2025 Bereket Engida",
11
+ "license": "MIT",
12
+ "main": "./dist/index.mjs",
13
+ "module": "./dist/index.mjs",
14
+ "types": "./dist/index.d.mts",
15
+ "peerDependencies": {
16
+ "zod": "^4.0.0"
17
+ },
18
+ "peerDependenciesMeta": {
19
+ "zod": {
20
+ "optional": true
21
+ }
22
+ },
23
+ "exports": {
24
+ ".": {
25
+ "dev-source": "./src/index.ts",
26
+ "import": {
27
+ "types": "./dist/index.d.mts",
28
+ "default": "./dist/index.mjs"
29
+ },
30
+ "require": {
31
+ "types": "./dist/index.d.cts",
32
+ "default": "./dist/index.cjs"
33
+ }
34
+ },
35
+ "./error": {
36
+ "dev-source": "./src/error.ts",
37
+ "import": {
38
+ "types": "./dist/error.d.mts",
39
+ "default": "./dist/error.mjs"
40
+ },
41
+ "require": {
42
+ "types": "./dist/error.d.cts",
43
+ "default": "./dist/error.cjs"
44
+ }
45
+ },
46
+ "./schema": {
47
+ "dev-source": "./src/schema.ts",
48
+ "import": {
49
+ "types": "./dist/schema.d.mts",
50
+ "default": "./dist/schema.mjs"
51
+ },
52
+ "require": {
53
+ "types": "./dist/schema.d.cts",
54
+ "default": "./dist/schema.cjs"
55
+ }
56
+ },
57
+ "./plugins/http": {
58
+ "dev-source": "./src/plugins/http/index.ts",
59
+ "import": {
60
+ "types": "./dist/plugins/http.d.mts",
61
+ "default": "./dist/plugins/http.mjs"
62
+ },
63
+ "require": {
64
+ "types": "./dist/plugins/http.d.cts",
65
+ "default": "./dist/plugins/http.cjs"
66
+ }
67
+ },
68
+ "./plugins/read-only": {
69
+ "dev-source": "./src/plugins/read-only.ts",
70
+ "import": {
71
+ "types": "./dist/plugins/read-only.d.mts",
72
+ "default": "./dist/plugins/read-only.mjs"
73
+ },
74
+ "require": {
75
+ "types": "./dist/plugins/read-only.d.cts",
76
+ "default": "./dist/plugins/read-only.cjs"
77
+ }
78
+ },
79
+ "./plugins/db": {
80
+ "dev-source": "./src/plugins/db.ts",
81
+ "import": {
82
+ "types": "./dist/plugins/db.d.mts",
83
+ "default": "./dist/plugins/db.mjs"
84
+ },
85
+ "require": {
86
+ "types": "./dist/plugins/db.d.cts",
87
+ "default": "./dist/plugins/db.cjs"
88
+ }
89
+ },
90
+ "./capability": {
91
+ "dev-source": "./src/capability.ts",
92
+ "import": {
93
+ "types": "./dist/capability.d.mts",
94
+ "default": "./dist/capability.mjs"
95
+ },
96
+ "require": {
97
+ "types": "./dist/capability.d.cts",
98
+ "default": "./dist/capability.cjs"
99
+ }
100
+ }
101
+ },
102
+ "files": [
103
+ "dist"
104
+ ],
105
+ "scripts": {
106
+ "lint:package": "publint --strict .",
107
+ "lint:type": "attw --profile node16 --pack .",
108
+ "test": "vitest",
109
+ "coverage": "vitest run --coverage",
110
+ "coverage:open": "open coverage/index.html",
111
+ "build": "tsdown",
112
+ "dev": "tsdown --watch"
113
+ }
114
+ }