stitchkit 0.49.2 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/cli.js +3 -3
  2. package/dist/contract/errors-factory.d.ts +27 -6
  3. package/dist/contract/errors-factory.d.ts.map +1 -1
  4. package/dist/contract/factory.d.ts +15 -2
  5. package/dist/contract/factory.d.ts.map +1 -1
  6. package/dist/contract/index.d.ts +1 -1
  7. package/dist/contract/index.d.ts.map +1 -1
  8. package/dist/contract/index.js +1 -1
  9. package/dist/{index-z992nfbx.js → index-8mt47qk7.js} +127 -123
  10. package/dist/{index-jewp9r0a.js → index-8qghvg18.js} +1 -1
  11. package/dist/{index-h05ygjqx.js → index-bmnhqtya.js} +4 -1
  12. package/dist/{index-p9d4cxt5.js → index-gff2mxzk.js} +1 -1
  13. package/dist/{index-0hj37z43.js → index-h55e1wyq.js} +2 -2
  14. package/dist/{index-v58mwa19.js → index-psrxjvbw.js} +2 -2
  15. package/dist/{index-45dz4m51.js → index-trz4ate5.js} +6 -2
  16. package/dist/{index-03j2t778.js → index-tw7mhqgy.js} +15 -4
  17. package/dist/index-ynts85ew.js +246 -0
  18. package/dist/index.js +1 -1
  19. package/dist/node.d.ts +3 -2
  20. package/dist/node.d.ts.map +1 -1
  21. package/dist/node.js +15 -6
  22. package/dist/observability/index.js +3 -3
  23. package/dist/server/implement.d.ts +101 -8
  24. package/dist/server/implement.d.ts.map +1 -1
  25. package/dist/server/index.d.ts +4 -3
  26. package/dist/server/index.d.ts.map +1 -1
  27. package/dist/server/index.js +19 -11
  28. package/dist/server/middleware/auth.d.ts +63 -3
  29. package/dist/server/middleware/auth.d.ts.map +1 -1
  30. package/dist/server/process-signals.d.ts +117 -0
  31. package/dist/server/process-signals.d.ts.map +1 -0
  32. package/dist/server/types.d.ts +38 -0
  33. package/dist/server/types.d.ts.map +1 -1
  34. package/dist/testing.js +2 -2
  35. package/dist/tools/list-names.d.ts +13 -1
  36. package/dist/tools/list-names.d.ts.map +1 -1
  37. package/dist/tools.d.ts +1 -1
  38. package/dist/tools.d.ts.map +1 -1
  39. package/dist/tools.js +13 -8
  40. package/llms-full.txt +404 -39
  41. package/package.json +1 -1
  42. package/dist/index-r1qp4rve.js +0 -57
package/dist/cli.js CHANGED
@@ -4,10 +4,10 @@ import {
4
4
  emitResult,
5
5
  parseCliArgs,
6
6
  pollUntilDone
7
- } from "./index-0hj37z43.js";
7
+ } from "./index-h55e1wyq.js";
8
8
  import"./index-yxpe3phd.js";
9
- import"./index-jewp9r0a.js";
10
- import"./index-h05ygjqx.js";
9
+ import"./index-8qghvg18.js";
10
+ import"./index-bmnhqtya.js";
11
11
  export {
12
12
  pollUntilDone,
13
13
  parseCliArgs,
@@ -1,18 +1,20 @@
1
1
  /**
2
2
  * Declare an application's domain errors once. Each definition owns its HTTP
3
- * status and optional Zod schema for structured details; generated factories
4
- * construct (but do not throw) branded `AppError` instances.
3
+ * status, its default message and an optional Zod schema for structured
4
+ * details; generated factories construct (but do not throw) branded `AppError`
5
+ * instances.
5
6
  *
6
7
  * ```ts
7
8
  * export const appErrors = defineErrors({
8
- * SESSION_NOT_FOUND: { status: 404 },
9
+ * SESSION_NOT_FOUND: { status: 404, message: 'No such session' },
9
10
  * QUOTA_EXCEEDED: {
10
11
  * status: 429,
12
+ * message: 'Monthly quota exhausted',
11
13
  * details: z.object({ retryAfterSeconds: z.number().int().positive() }),
12
14
  * },
13
15
  * })
14
16
  *
15
- * throw appErrors.errors.SESSION_NOT_FOUND({ message: 'No such session' })
17
+ * throw appErrors.errors.SESSION_NOT_FOUND()
16
18
  * throw appErrors.errors.QUOTA_EXCEEDED({
17
19
  * details: { retryAfterSeconds: 30 },
18
20
  * hint: 'Wait for the current window to expire',
@@ -23,12 +25,20 @@ import { z } from 'zod';
23
25
  import { AppError } from './errors';
24
26
  /** Supported structured-details schemas: a required or optional Zod object. */
25
27
  export type ErrorDetailsSchema = z.ZodObject | z.ZodOptional<z.ZodObject>;
26
- /** One domain error definition. Omitting `details` forbids structured details. */
28
+ /**
29
+ * One domain error definition. Omitting `details` forbids structured details.
30
+ *
31
+ * `message` is the code's default human-readable text: without it `AppError`
32
+ * falls back to the code itself, and every `throw` site has to repeat the
33
+ * sentence. A per-call `message` still wins.
34
+ */
27
35
  export type ErrorDefinition = {
28
36
  readonly status: number;
37
+ readonly message?: string;
29
38
  readonly details?: never;
30
39
  } | {
31
40
  readonly status: number;
41
+ readonly message?: string;
32
42
  readonly details: ErrorDetailsSchema;
33
43
  };
34
44
  export type ErrorDefinitions = Record<string, ErrorDefinition>;
@@ -70,8 +80,19 @@ export type ErrorFactory<TCode extends string, TDefinition extends ErrorDefiniti
70
80
  export type ErrorFactories<TDefinitions extends ErrorDefinitions> = {
71
81
  readonly [TCode in keyof TDefinitions]: ErrorFactory<TCode & string, TDefinitions[TCode]>;
72
82
  };
83
+ /**
84
+ * `const` inference keeps only the keys a definition actually wrote, so a
85
+ * registry that mixes codes with and without `message` has no common `message`
86
+ * key — and `definitions[code].message`, the whole point of declaring it, would
87
+ * not type-check. Normalising the optional key restores that lookup.
88
+ *
89
+ * A declared literal stays literal (`'gone' & string` is `'gone'`); this only
90
+ * adds the key where a definition omitted it.
91
+ */
73
92
  export type FrozenErrorDefinitions<TDefinitions extends ErrorDefinitions> = {
74
- readonly [TCode in keyof TDefinitions]: Readonly<TDefinitions[TCode]>;
93
+ readonly [TCode in keyof TDefinitions]: Readonly<TDefinitions[TCode]> & {
94
+ readonly message?: string;
95
+ };
75
96
  };
76
97
  /** The immutable handle returned by `defineErrors`. */
77
98
  export interface DefinedErrors<TDefinitions extends ErrorDefinitions> {
@@ -1 +1 @@
1
- {"version":3,"file":"errors-factory.d.ts","sourceRoot":"","sources":["../../src/contract/errors-factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAE1E,kFAAkF;AAClF,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAEtE,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAE/D,6DAA6D;AAC7D,MAAM,MAAM,kBAAkB,CAAC,WAAW,SAAS,eAAe,IAAI,WAAW,SAAS;IACxF,OAAO,EAAE,MAAM,OAAO,SAAS,kBAAkB,CAAC;CACnD,GACG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,GAC/D,SAAS,CAAC;AAEd,mFAAmF;AACnF,MAAM,MAAM,eAAe,CACzB,KAAK,SAAS,MAAM,EACpB,WAAW,SAAS,eAAe,IACjC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC,WAAW,CAAC,CAAC,GAClD,CAAC,WAAW,SAAS;IAAE,OAAO,EAAE,MAAM,OAAO,SAAS,kBAAkB,CAAA;CAAE,GACtE,SAAS,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GACjC,MAAM,GACN;IAAE,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,WAAW,CAAC,CAAA;CAAE,GACvD,MAAM,CAAC,CAAC;AAEd;;;GAGG;AACH,MAAM,MAAM,qBAAqB,CAAC,WAAW,SAAS,eAAe,IAAI,WAAW,SAAS;IAC3F,OAAO,EAAE,MAAM,OAAO,SAAS,kBAAkB,CAAC;CACnD,GACG,SAAS,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAChC;IACE,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC;QAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;CACF,GACD;IACE,OAAO,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;CACF,GACH,CAAC,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAErE,4DAA4D;AAC5D,MAAM,MAAM,YAAY,CAAC,KAAK,SAAS,MAAM,EAAE,WAAW,SAAS,eAAe,IAAI,CACpF,GAAG,IAAI,EAAE,qBAAqB,CAAC,WAAW,CAAC,KACxC,eAAe,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;AAEzC,MAAM,MAAM,cAAc,CAAC,YAAY,SAAS,gBAAgB,IAAI;IAClE,QAAQ,EAAE,KAAK,IAAI,MAAM,YAAY,GAAG,YAAY,CAAC,KAAK,GAAG,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;CAC1F,CAAC;AAEF,MAAM,MAAM,sBAAsB,CAAC,YAAY,SAAS,gBAAgB,IAAI;IAC1E,QAAQ,EAAE,KAAK,IAAI,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;CACtE,CAAC;AAEF,uDAAuD;AACvD,MAAM,WAAW,aAAa,CAAC,YAAY,SAAS,gBAAgB;IAClE,mFAAmF;IACnF,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;IAC9C,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,KAAK,IAAI,MAAM,YAAY,GAAG,KAAK,GAAG,MAAM;KAAE,CAAC;IAC3E,oFAAoF;IACpF,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC,YAAY,CAAC,CAAC;IAC3D,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,YAAY,EAAE,MAAM,CAAC,CAAC;CAChF;AAgCD,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,KAAK,CAAC,YAAY,SAAS,gBAAgB,EACtE,MAAM,EAAE,YAAY,GACnB,aAAa,CAAC,YAAY,CAAC,CA0C7B"}
1
+ {"version":3,"file":"errors-factory.d.ts","sourceRoot":"","sources":["../../src/contract/errors-factory.ts"],"names":[],"mappings":"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"}
@@ -39,14 +39,27 @@ export interface ScopedContractDef<T extends Record<string, EndpointDef> = Recor
39
39
  scope: TScope;
40
40
  };
41
41
  }
42
+ /**
43
+ * An endpoint authored through the factory: the per-endpoint `scope` override is
44
+ * held to the same union as the contract's.
45
+ *
46
+ * Constraining the type parameter (rather than intersecting the argument) keeps
47
+ * `T` itself unchanged, so `ExplicitToolExposureEndpoints<T>` and the boundary
48
+ * mapping below still see the endpoints the caller wrote. The check is
49
+ * structural, so it also covers `HeadEndpointDef`, which declares its own
50
+ * `scope` outside `EndpointDefBase`.
51
+ */
52
+ export type FactoryScopedEndpoint<TScope extends string> = EndpointDef & {
53
+ scope?: TScope;
54
+ };
42
55
  /** A `defineContract` whose `scope` is required and typed to `TScope`. */
43
- export type ScopedDefineContract<TScope extends string> = <const TContractScope extends TScope, const T extends Record<string, EndpointDef>>(meta: {
56
+ export type ScopedDefineContract<TScope extends string> = <const TContractScope extends TScope, const T extends Record<string, FactoryScopedEndpoint<TScope>>>(meta: {
44
57
  prefix: string;
45
58
  scope: TContractScope;
46
59
  meta?: Record<string, unknown>;
47
60
  }, endpoints: T) => ScopedContractDef<T, TContractScope>;
48
61
  /** Scoped contract authoring where every omitted exposure becomes HTTP-only. */
49
- export type ExplicitScopedDefineContract<TScope extends string> = <const TContractScope extends TScope, const T extends Record<string, EndpointDef>>(meta: {
62
+ export type ExplicitScopedDefineContract<TScope extends string> = <const TContractScope extends TScope, const T extends Record<string, FactoryScopedEndpoint<TScope>>>(meta: {
50
63
  prefix: string;
51
64
  scope: TContractScope;
52
65
  meta?: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/contract/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGlF,MAAM,MAAM,2BAA2B,GAAG,UAAU,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,YAAY,EAAE,2BAA2B,CAAC;CAC3C;AAED,MAAM,MAAM,6BAA6B,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI;KAChF,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,MAAM,EAAE,SAAS,SAAS,EAAE,CAAA;KAAE,GACzD,CAAC,CAAC,CAAC,CAAC,GACJ,CAAC,CAAC,CAAC,CAAC,GAAG;QAAE,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;KAAE;CACzC,CAAC;AAEF,oFAAoF;AACpF,MAAM,WAAW,iBAAiB,CAChC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACnE,MAAM,SAAS,MAAM,GAAG,MAAM,CAC9B,SAAQ,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD;AAED,0EAA0E;AAC1E,MAAM,MAAM,oBAAoB,CAAC,MAAM,SAAS,MAAM,IAAI,CACxD,KAAK,CAAC,cAAc,SAAS,MAAM,EACnC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAE3C,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAC/E,SAAS,EAAE,CAAC,KACT,iBAAiB,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;AAE1C,gFAAgF;AAChF,MAAM,MAAM,4BAA4B,CAAC,MAAM,SAAS,MAAM,IAAI,CAChE,KAAK,CAAC,cAAc,SAAS,MAAM,EACnC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAE3C,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAC/E,SAAS,EAAE,CAAC,KACT,iBAAiB,CAAC,6BAA6B,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,MAAM,KAAK;IAC9D,cAAc,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;CAC9C,CAAC;AACF,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,MAAM,EACzD,MAAM,EAAE,qBAAqB,GAC5B;IACD,cAAc,EAAE,4BAA4B,CAAC,MAAM,CAAC,CAAC;CACtD,CAAC"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/contract/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGlF,MAAM,MAAM,2BAA2B,GAAG,UAAU,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,YAAY,EAAE,2BAA2B,CAAC;CAC3C;AAED,MAAM,MAAM,6BAA6B,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI;KAChF,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,MAAM,EAAE,SAAS,SAAS,EAAE,CAAA;KAAE,GACzD,CAAC,CAAC,CAAC,CAAC,GACJ,CAAC,CAAC,CAAC,CAAC,GAAG;QAAE,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;KAAE;CACzC,CAAC;AAEF,oFAAoF;AACpF,MAAM,WAAW,iBAAiB,CAChC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACnE,MAAM,SAAS,MAAM,GAAG,MAAM,CAC9B,SAAQ,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,qBAAqB,CAAC,MAAM,SAAS,MAAM,IAAI,WAAW,GAAG;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,0EAA0E;AAC1E,MAAM,MAAM,oBAAoB,CAAC,MAAM,SAAS,MAAM,IAAI,CACxD,KAAK,CAAC,cAAc,SAAS,MAAM,EACnC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,MAAM,CAAC,CAAC,EAE7D,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAC/E,SAAS,EAAE,CAAC,KACT,iBAAiB,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;AAE1C,gFAAgF;AAChF,MAAM,MAAM,4BAA4B,CAAC,MAAM,SAAS,MAAM,IAAI,CAChE,KAAK,CAAC,cAAc,SAAS,MAAM,EACnC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,MAAM,CAAC,CAAC,EAE7D,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAC/E,SAAS,EAAE,CAAC,KACT,iBAAiB,CAAC,6BAA6B,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,MAAM,KAAK;IAC9D,cAAc,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;CAC9C,CAAC;AACF,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,MAAM,EACzD,MAAM,EAAE,qBAAqB,GAC5B;IACD,cAAc,EAAE,4BAA4B,CAAC,MAAM,CAAC,CAAC;CACtD,CAAC"}
@@ -1,6 +1,6 @@
1
1
  export { ALL_TRANSPORTS, type BodyHttpSuccessStatus, type ClientRequestOptions, type ContractDef, type ContractMeta, defineContract, type EndpointDef, type EndpointFn, type EndpointMcpInputRequired, type EndpointMcpPolicy, type EndpointResponseMeta, type EndpointToolAnnotations, type EndpointUiMeta, type FileDescriptor, type HandlerContext, type HeadEndpointDef, type HttpMethod, type HttpSuccessStatus, type MultipartBufferedFiles, type MultipartDescriptor, type MultipartFile, type MultipartFilePolicy, type ResponseMetadata, type RuntimeContext, type ScopedEndpointFn, type ScopedHttpClient, type ScopedUrlBuilder, type ScopedUrlFn, type Transport, type TransportSource, type TypedClient, type TypedHttpClient, type TypedUrlBuilder, } from './define';
2
2
  export { AppError, appError, badRequest, conflict, type ErrorEnvelope, forbidden, isStitchErrorCode, notFound, rateLimited, STITCH_ERROR_STATUS, type StitchErrorCode, unauthorized, } from './errors';
3
3
  export { type DefinedAppError, type DefinedErrors, defineErrors, type ErrorDefinition, type ErrorDefinitions, type ErrorDetailsOutput, type ErrorDetailsSchema, type ErrorFactories, type ErrorFactory, type ErrorFactoryArguments, type FrozenErrorDefinitions, } from './errors-factory';
4
- export { type ContractFactoryConfig, type ContractFactoryToolExposure, createContractFactory, type ExplicitScopedDefineContract, type ExplicitToolExposureEndpoints, type ScopedContractDef, type ScopedDefineContract, } from './factory';
4
+ export { type ContractFactoryConfig, type ContractFactoryToolExposure, createContractFactory, type ExplicitScopedDefineContract, type ExplicitToolExposureEndpoints, type FactoryScopedEndpoint, type ScopedContractDef, type ScopedDefineContract, } from './factory';
5
5
  export { decodeCursor, encodeCursor, type Paginated, paginatedSchema, } from './pagination';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contract/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,KAAK,aAAa,EAClB,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,KAAK,eAAe,EACpB,YAAY,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,YAAY,EACZ,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,KAAK,6BAA6B,EAClC,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,GAC1B,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,KAAK,SAAS,EACd,eAAe,GAChB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contract/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,KAAK,aAAa,EAClB,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,KAAK,eAAe,EACpB,YAAY,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,YAAY,EACZ,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,KAAK,6BAA6B,EAClC,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,GAC1B,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,KAAK,SAAS,EACd,eAAe,GAChB,MAAM,cAAc,CAAC"}
@@ -16,7 +16,7 @@ import {
16
16
  paginatedSchema,
17
17
  rateLimited,
18
18
  unauthorized
19
- } from "../index-45dz4m51.js";
19
+ } from "../index-trz4ate5.js";
20
20
  import"../index-tss6bk5c.js";
21
21
  export {
22
22
  unauthorized,
@@ -2,7 +2,7 @@ import {
2
2
  assertCorsConfig,
3
3
  corsHeaders,
4
4
  corsPreflightResponse
5
- } from "./index-r1qp4rve.js";
5
+ } from "./index-ynts85ew.js";
6
6
  import {
7
7
  AppError,
8
8
  badRequest,
@@ -11,7 +11,6 @@ import {
11
11
  getClientInfo,
12
12
  getRequestContext,
13
13
  isUnsafeKey,
14
- mergeMeta,
15
14
  normalizeError,
16
15
  parseQueryParams,
17
16
  recordedErrorMessage,
@@ -23,15 +22,13 @@ import {
23
22
  setRequestError,
24
23
  validateDeclaredOutput,
25
24
  zodIssues
26
- } from "./index-jewp9r0a.js";
25
+ } from "./index-8qghvg18.js";
27
26
  import {
28
27
  __require,
29
- callRuntimeHandler,
30
28
  isRecord,
31
29
  parseTrailingWildcard,
32
- resolveTraceContext,
33
- typedEntries
34
- } from "./index-h05ygjqx.js";
30
+ resolveTraceContext
31
+ } from "./index-bmnhqtya.js";
35
32
 
36
33
  // src/server/multipart.ts
37
34
  var DEFAULT_MAX_REQUEST_BYTES = 25 * 1024 * 1024;
@@ -1607,131 +1604,138 @@ function createServerLifecycle(getAdapter) {
1607
1604
  };
1608
1605
  }
1609
1606
 
1610
- // src/server/implement.ts
1611
- function isStreamingImplementation(value) {
1612
- return typeof value === "object" && value !== null && "kind" in value && value.kind === "stitchkit.multipart.stream";
1613
- }
1614
- function defineMultipartStream(endpoint, config) {
1615
- const receivers = {};
1616
- for (const [key, receiver] of typedEntries(config.files)) {
1617
- receivers[String(key)] = receiver;
1618
- }
1619
- const declared = Object.keys(endpoint.multipart.files);
1620
- const configured = Object.keys(receivers);
1621
- if (declared.length !== configured.length || declared.some((field) => !Object.hasOwn(receivers, field))) {
1622
- throw new Error("Streaming multipart receivers must exactly match declared file fields");
1607
+ // src/server/process-signals.ts
1608
+ var DEFAULT_SIGNALS = ["SIGINT", "SIGTERM"];
1609
+ var defaultSignalSource = {
1610
+ on: (signal, handler) => {
1611
+ process.on(signal, handler);
1612
+ },
1613
+ off: (signal, handler) => {
1614
+ process.off(signal, handler);
1615
+ },
1616
+ raiseDefault: (signal) => {
1617
+ if (process.listenerCount(signal) > 0)
1618
+ return false;
1619
+ process.kill(process.pid, signal);
1620
+ return true;
1623
1621
  }
1624
- return {
1625
- kind: "stitchkit.multipart.stream",
1626
- receivers,
1627
- execute(ctx, files) {
1628
- return callRuntimeHandler(config.handler, { ...ctx, files });
1629
- }
1630
- };
1622
+ };
1623
+ var bound = new WeakSet;
1624
+ function reportError(phase, error, onError) {
1625
+ try {
1626
+ onError?.(phase, error);
1627
+ } catch {}
1631
1628
  }
1632
- var HTTP_ONLY = Object.freeze(["HTTP"]);
1633
- function bindContract(contract, handlers) {
1634
- const methods = {};
1635
- const groupScope = contract.meta.scope ?? "public";
1636
- for (const [key, endpoint] of typedEntries(contract.endpoints)) {
1637
- const typedHandler = handlers[String(key)];
1638
- const isStreaming = endpoint.multipart?.delivery === "stream";
1639
- if (!isStreaming && typeof typedHandler !== "function") {
1640
- throw new Error(`[stitchkit] implement: missing handler for "${contract.meta.prefix}.${String(key)}"`);
1629
+ function guard(run, phase, onError) {
1630
+ try {
1631
+ run();
1632
+ } catch (error) {
1633
+ reportError(phase, error, onError);
1634
+ }
1635
+ }
1636
+ function bindProcessSignals(handle, options = {}) {
1637
+ if (bound.has(handle)) {
1638
+ throw new Error("[stitchkit] bindProcessSignals: this server is already bound; close the first binding before creating another");
1639
+ }
1640
+ bound.add(handle);
1641
+ const signals = [...new Set(options.signals ?? DEFAULT_SIGNALS)];
1642
+ const source = options.signalSource ?? defaultSignalSource;
1643
+ const budgets = ShutdownOptionsSchema.omit({ signal: true }).parse(options.shutdown ?? {});
1644
+ const controller = new AbortController;
1645
+ const handlers = [];
1646
+ let started = false;
1647
+ let sameTurnAsStart = false;
1648
+ let settled = false;
1649
+ let closed = false;
1650
+ let resolveChain = () => {
1651
+ return;
1652
+ };
1653
+ let rejectChain = () => {
1654
+ return;
1655
+ };
1656
+ const promise = new Promise((resolve, reject) => {
1657
+ resolveChain = resolve;
1658
+ rejectChain = reject;
1659
+ });
1660
+ promise.catch(() => {
1661
+ return;
1662
+ });
1663
+ const removeListeners = () => {
1664
+ if (closed)
1665
+ return;
1666
+ closed = true;
1667
+ for (const [signal, handler] of handlers)
1668
+ source.off(signal, handler);
1669
+ if (!started)
1670
+ bound.delete(handle);
1671
+ };
1672
+ const close = () => {
1673
+ const hadStarted = started;
1674
+ removeListeners();
1675
+ if (!hadStarted)
1676
+ resolveChain(undefined);
1677
+ };
1678
+ const run = async (signal) => {
1679
+ try {
1680
+ await options.onShutdown?.(signal);
1681
+ } catch (error) {
1682
+ reportError("prepare", error, options.onError);
1641
1683
  }
1642
- if (isStreaming && !isStreamingImplementation(typedHandler)) {
1643
- throw new Error(`[stitchkit] implement: streaming multipart endpoint "${contract.meta.prefix}.${String(key)}" must use defineMultipartStream()`);
1684
+ let result;
1685
+ try {
1686
+ result = await handle.shutdown({ ...budgets, signal: controller.signal });
1687
+ } catch (error) {
1688
+ settled = true;
1689
+ rejectChain(error);
1690
+ reportError("shutdown", error, options.onError);
1691
+ removeListeners();
1692
+ return;
1693
+ }
1694
+ settled = true;
1695
+ resolveChain(result);
1696
+ try {
1697
+ await options.onComplete?.(result);
1698
+ } catch (error) {
1699
+ reportError("complete", error, options.onError);
1700
+ } finally {
1701
+ removeListeners();
1644
1702
  }
1645
- const streamingHandler = isStreamingImplementation(typedHandler) ? typedHandler : undefined;
1646
- const regularHandler = typeof typedHandler === "function" ? typedHandler : undefined;
1647
- methods[String(key)] = {
1648
- method: endpoint.method,
1649
- path: endpoint.path,
1650
- desc: endpoint.desc,
1651
- serviceName: contract.meta.prefix,
1652
- key: String(key),
1653
- toolName: "toolName" in endpoint ? endpoint.toolName : undefined,
1654
- expose: endpoint.rawResponse || endpoint.rawBody || endpoint.responseMeta ? HTTP_ONLY : endpoint.expose,
1655
- scope: endpoint.scope ?? groupScope,
1656
- paramsSchema: endpoint.params,
1657
- inputSchema: endpoint.input,
1658
- outputSchema: endpoint.output,
1659
- multipart: endpoint.multipart,
1660
- multipartReceivers: streamingHandler?.receivers,
1661
- maxJsonBodyBytes: endpoint.maxJsonBodyBytes,
1662
- idempotent: endpoint.idempotent,
1663
- ui: "ui" in endpoint ? endpoint.ui : undefined,
1664
- annotations: "annotations" in endpoint ? endpoint.annotations : undefined,
1665
- mcp: "mcp" in endpoint ? endpoint.mcp : undefined,
1666
- meta: mergeMeta(contract.meta.meta, endpoint.meta),
1667
- rawResponse: endpoint.rawResponse,
1668
- rawBody: endpoint.rawBody,
1669
- responseMeta: endpoint.responseMeta,
1670
- contentType: "contentType" in endpoint ? endpoint.contentType : undefined,
1671
- handler: streamingHandler ? (ctx) => streamingHandler.execute(ctx, ctx.files ?? {}) : (ctx) => {
1672
- if (!regularHandler) {
1673
- throw new Error(`[stitchkit] implement: missing handler for "${contract.meta.prefix}.${String(key)}"`);
1674
- }
1675
- return callRuntimeHandler(regularHandler, ctx);
1676
- }
1677
- };
1678
- }
1679
- return {
1680
- name: contract.meta.prefix,
1681
- prefix: contract.meta.prefix,
1682
- scope: groupScope,
1683
- methods
1684
1703
  };
1685
- }
1686
- function implement(contract, handlers) {
1687
- return bindContract(contract, handlers);
1688
- }
1689
- function createImplement() {
1690
- return (contract, handlers) => implement(contract, handlers);
1691
- }
1692
- function isImplementationContract(value) {
1693
- return isRecord(value) && isRecord(value.meta) && typeof value.meta.prefix === "string" && isRecord(value.endpoints);
1694
- }
1695
- function bindRegistry(contracts, handlers) {
1696
- const contractKeys = Object.keys(contracts);
1697
- const handlerKeys = Object.keys(handlers);
1698
- const missing = contractKeys.filter((key) => !Object.hasOwn(handlers, key));
1699
- const extra = handlerKeys.filter((key) => !Object.hasOwn(contracts, key));
1700
- if (missing.length > 0 || extra.length > 0) {
1701
- throw new Error(`[stitchkit] implementRegistry: registry mismatch (missing: ${missing.join(", ") || "none"}; extra: ${extra.join(", ") || "none"})`);
1702
- }
1703
- const prefixes = new Map;
1704
- const services = [];
1705
- for (const [key, candidate] of Object.entries(contracts)) {
1706
- if (!isImplementationContract(candidate)) {
1707
- throw new TypeError(`[stitchkit] implementRegistry: registry entry "${key}" must be one contract; composed arrays and namespaces are not supported`);
1704
+ const onSignal = (signal) => {
1705
+ if (!started) {
1706
+ started = true;
1707
+ sameTurnAsStart = true;
1708
+ queueMicrotask(() => {
1709
+ sameTurnAsStart = false;
1710
+ });
1711
+ run(signal).catch((error) => reportError("shutdown", error, options.onError));
1712
+ return;
1708
1713
  }
1709
- const contract = candidate;
1710
- const previousKey = prefixes.get(contract.meta.prefix);
1711
- if (previousKey !== undefined) {
1712
- throw new Error(`[stitchkit] implementRegistry: duplicate contract prefix "${contract.meta.prefix}" at "${previousKey}" and "${key}"`);
1714
+ if (sameTurnAsStart)
1715
+ return;
1716
+ if (!settled && !controller.signal.aborted) {
1717
+ controller.abort();
1718
+ guard(() => options.onRepeatedSignal?.(signal, "force"), "shutdown", options.onError);
1719
+ return;
1713
1720
  }
1714
- prefixes.set(contract.meta.prefix, key);
1715
- const entryHandlers = handlers[key];
1716
- if (!isRecord(entryHandlers)) {
1717
- throw new TypeError(`[stitchkit] implementRegistry: handlers for "${key}" must be an object`);
1721
+ removeListeners();
1722
+ guard(() => options.onRepeatedSignal?.(signal, "escalate"), "shutdown", options.onError);
1723
+ let restored = false;
1724
+ try {
1725
+ restored = source.raiseDefault(signal);
1726
+ } catch (error) {
1727
+ reportError("shutdown", error, options.onError);
1718
1728
  }
1719
- const endpointKeys = Object.keys(contract.endpoints);
1720
- const handlerEntryKeys = Object.keys(entryHandlers);
1721
- const missingEndpoints = endpointKeys.filter((endpointKey) => !Object.hasOwn(entryHandlers, endpointKey));
1722
- const extraEndpoints = handlerEntryKeys.filter((endpointKey) => !Object.hasOwn(contract.endpoints, endpointKey));
1723
- if (missingEndpoints.length > 0 || extraEndpoints.length > 0) {
1724
- throw new Error(`[stitchkit] implementRegistry: handlers for "${key}" mismatch (missing: ${missingEndpoints.join(", ") || "none"}; extra: ${extraEndpoints.join(", ") || "none"})`);
1729
+ if (!restored) {
1730
+ guard(() => options.onEscalationBlocked?.(signal), "shutdown", options.onError);
1725
1731
  }
1726
- services.push(bindContract(contract, entryHandlers));
1732
+ };
1733
+ for (const signal of signals) {
1734
+ const handler = () => onSignal(signal);
1735
+ handlers.push([signal, handler]);
1736
+ source.on(signal, handler);
1727
1737
  }
1728
- return services;
1729
- }
1730
- function implementRegistry(contracts, handlers) {
1731
- return bindRegistry(contracts, handlers);
1732
- }
1733
- function createImplementRegistry() {
1734
- return (contracts, handlers) => bindRegistry(contracts, handlers);
1738
+ return { promise, close };
1735
1739
  }
1736
1740
 
1737
1741
  // src/realtime/rejection.ts
@@ -2148,4 +2152,4 @@ function socketIoLane(websocket) {
2148
2152
  });
2149
2153
  }
2150
2154
 
2151
- export { parseMultipart, createHandler, ShutdownStateSchema, ShutdownOptionsSchema, ShutdownStatusSchema, ShutdownResultSchema, createServerLifecycle, defineMultipartStream, implement, createImplement, implementRegistry, createImplementRegistry, bindRealtimeServer, webSocketLane, composeWebSocketHandlers, createSocketIOServer, socketIoLane };
2155
+ export { parseMultipart, createHandler, ShutdownStateSchema, ShutdownOptionsSchema, ShutdownStatusSchema, ShutdownResultSchema, createServerLifecycle, bindProcessSignals, bindRealtimeServer, webSocketLane, composeWebSocketHandlers, createSocketIOServer, socketIoLane };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  isRecord,
3
3
  resolveTraceContext
4
- } from "./index-h05ygjqx.js";
4
+ } from "./index-bmnhqtya.js";
5
5
 
6
6
  // src/contract/errors.ts
7
7
  var APP_ERROR_BRAND = Symbol.for("stitchkit.AppError");
@@ -136,6 +136,9 @@ function callRuntimeHandler(handler, context) {
136
136
  }
137
137
  return Reflect.apply(handler, undefined, [context]);
138
138
  }
139
+ function transportResult(value) {
140
+ return value;
141
+ }
139
142
  function mapObject(source, mapper) {
140
143
  const result = {};
141
144
  for (const [key, value] of typedEntries(source)) {
@@ -146,4 +149,4 @@ function mapObject(source, mapper) {
146
149
  return result;
147
150
  }
148
151
 
149
- export { __require, parseTrailingWildcard, typedEntries, isRecord, callRuntimeHandler, mapObject, createTraceContext, parseTraceparent, formatTraceparent, resolveTraceContext, childSpan, resolvePropagationContext };
152
+ export { __require, parseTrailingWildcard, typedEntries, isRecord, callRuntimeHandler, transportResult, mapObject, createTraceContext, parseTraceparent, formatTraceparent, resolveTraceContext, childSpan, resolvePropagationContext };
@@ -6,7 +6,7 @@ import {
6
6
  mapObject,
7
7
  parseTrailingWildcard,
8
8
  typedEntries
9
- } from "./index-h05ygjqx.js";
9
+ } from "./index-bmnhqtya.js";
10
10
 
11
11
  // src/browser/cancellation.ts
12
12
  class RequestCancellationError extends Error {
@@ -14,10 +14,10 @@ import {
14
14
  runWithRequestContext,
15
15
  safeJsonParse,
16
16
  validateDeclaredOutput
17
- } from "./index-jewp9r0a.js";
17
+ } from "./index-8qghvg18.js";
18
18
  import {
19
19
  isRecord
20
- } from "./index-h05ygjqx.js";
20
+ } from "./index-bmnhqtya.js";
21
21
 
22
22
  // src/tools/coerce.ts
23
23
  import { z } from "zod";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  isUnsafeKey
3
- } from "./index-jewp9r0a.js";
3
+ } from "./index-8qghvg18.js";
4
4
  import {
5
5
  isRecord
6
- } from "./index-h05ygjqx.js";
6
+ } from "./index-bmnhqtya.js";
7
7
 
8
8
  // src/observability/sanitize.ts
9
9
  var SENSITIVE_WORDS = new Set([
@@ -295,6 +295,9 @@ function validateDefinition(code, definition) {
295
295
  if (definition.details !== undefined && !isErrorDetailsSchema(definition.details)) {
296
296
  throw new Error(`[stitchkit] Error "${code}" details must be a Zod object or optional Zod object`);
297
297
  }
298
+ if (definition.message !== undefined && (typeof definition.message !== "string" || definition.message.trim() === "")) {
299
+ throw new Error(`[stitchkit] Error "${code}" message must be a non-empty string`);
300
+ }
298
301
  }
299
302
  function defineErrors(source) {
300
303
  const definitions = mapObjectTypeBoundary(source, (code, definition) => {
@@ -306,14 +309,15 @@ function defineErrors(source) {
306
309
  const errors = mapObjectTypeBoundary(definitions, (code, definition) => {
307
310
  const name = String(code);
308
311
  return (options = {}) => {
312
+ const message = options.message ?? definition.message;
309
313
  if (definition.details === undefined) {
310
314
  if ("details" in options) {
311
315
  throw new Error(`[stitchkit] Error "${name}" does not declare details`);
312
316
  }
313
- return new AppError(name, options.message, definition.status, undefined, options.hint);
317
+ return new AppError(name, message, definition.status, undefined, options.hint);
314
318
  }
315
319
  const details = definition.details.parse(options.details);
316
- return new AppError(name, options.message, definition.status, details, options.hint);
320
+ return new AppError(name, message, definition.status, details, options.hint);
317
321
  };
318
322
  });
319
323
  Object.freeze(errors);
@@ -5,10 +5,10 @@ import {
5
5
  isUnsafeKey,
6
6
  safeJsonParse,
7
7
  unauthorized
8
- } from "./index-jewp9r0a.js";
8
+ } from "./index-8qghvg18.js";
9
9
  import {
10
10
  isRecord
11
- } from "./index-h05ygjqx.js";
11
+ } from "./index-bmnhqtya.js";
12
12
 
13
13
  // src/server/middleware/cookies.ts
14
14
  function parseCookies(header) {
@@ -150,6 +150,9 @@ function extractToken(req, cookieName) {
150
150
  }
151
151
  return null;
152
152
  }
153
+ function isThenable(value) {
154
+ return "then" in value && typeof value.then === "function";
155
+ }
153
156
  function createAuthHook(config) {
154
157
  const onAnonymous = config.onAnonymous ?? (() => unauthorized());
155
158
  const onForbidden = config.onForbidden ?? (() => forbidden());
@@ -159,10 +162,18 @@ function createAuthHook(config) {
159
162
  const scope = endpoint.scope ?? config.defaultScope;
160
163
  if (!scope)
161
164
  return;
162
- const rule = Object.hasOwn(config.rules, scope) ? config.rules[scope] : undefined;
163
- if (!rule) {
165
+ const entry = Object.hasOwn(config.rules, scope) ? config.rules[scope] : undefined;
166
+ if (!entry) {
164
167
  throw new Error(`[stitchkit] auth: no rule for scope "${scope}"`);
165
168
  }
169
+ const rule = typeof entry === "object" ? entry.rule : entry;
170
+ if (typeof entry === "object" && entry.inject && identity !== null) {
171
+ const fields = entry.inject(identity, ctx);
172
+ if (isThenable(fields)) {
173
+ throw new Error(`[stitchkit] auth: the inject of scope "${scope}" must be synchronous — an async inject merges a Promise, not fields`);
174
+ }
175
+ Object.assign(ctx, fields);
176
+ }
166
177
  if (rule === "public")
167
178
  return;
168
179
  if (!identity) {