@fabrika/app 0.8.1 → 0.9.0-dev.2

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 (135) hide show
  1. package/package.json +35 -24
  2. package/skill/SKILL.md +1 -1
  3. package/skill/references/app-setup.md +8 -8
  4. package/src/dev/changes.ts +35 -0
  5. package/src/dev/contract-digest.ts +17 -0
  6. package/src/dev/index.ts +11 -0
  7. package/src/dev/launcher.ts +604 -0
  8. package/src/dev/output.ts +62 -0
  9. package/src/dev/wire.ts +127 -0
  10. package/types/src/agent-skill.d.ts +29 -0
  11. package/types/src/build.d.ts +11 -0
  12. package/types/src/bun.d.ts +66 -0
  13. package/types/src/client/caller.d.ts +19 -0
  14. package/types/src/client/contract.d.ts +131 -0
  15. package/types/src/client/error-reporting.d.ts +66 -0
  16. package/types/src/client/index.d.ts +4 -0
  17. package/types/src/client/rpc.d.ts +14 -0
  18. package/types/src/client/share.d.ts +2 -0
  19. package/types/src/client/transport.d.ts +42 -0
  20. package/types/src/cloudflare.d.ts +49 -0
  21. package/types/src/contract/artifact-schema.d.ts +8 -0
  22. package/types/src/contract/attachment.d.ts +41 -0
  23. package/types/src/contract/build.d.ts +12 -0
  24. package/types/src/contract/compile.d.ts +11 -0
  25. package/types/src/contract/connect.d.ts +51 -0
  26. package/types/src/contract/context.d.ts +501 -0
  27. package/types/src/contract/declaration.d.ts +303 -0
  28. package/types/src/contract/defaults.d.ts +208 -0
  29. package/types/src/contract/define.d.ts +359 -0
  30. package/types/src/contract/file.d.ts +44 -0
  31. package/types/src/contract/group.d.ts +274 -0
  32. package/types/src/contract/handled.d.ts +18 -0
  33. package/types/src/contract/index.d.ts +19 -0
  34. package/types/src/contract/kit.d.ts +210 -0
  35. package/types/src/contract/platform.d.ts +9 -0
  36. package/types/src/contract/problems.d.ts +14 -0
  37. package/types/src/contract/redirect.d.ts +25 -0
  38. package/types/src/contract/schema-from-shape.d.ts +10 -0
  39. package/types/src/contract/schema-shape.d.ts +5 -0
  40. package/types/src/contract/snapshot-source.d.ts +15 -0
  41. package/types/src/contract/token.d.ts +58 -0
  42. package/types/src/contract/vocabulary.d.ts +30 -0
  43. package/types/src/contract/webhook-binding.d.ts +24 -0
  44. package/types/src/contract/webhook-scheme.d.ts +23 -0
  45. package/types/src/dev/changes.d.ts +7 -0
  46. package/types/src/dev/contract-digest.d.ts +1 -0
  47. package/types/src/dev/index.d.ts +2 -0
  48. package/types/src/dev/launcher.d.ts +32 -0
  49. package/types/src/dev/output.d.ts +22 -0
  50. package/types/src/dev/wire.d.ts +122 -0
  51. package/types/src/disk-assets.d.ts +3 -0
  52. package/types/src/errors.d.ts +46 -0
  53. package/types/src/fetch.d.ts +7 -0
  54. package/types/src/files/archive.d.ts +26 -0
  55. package/types/src/files/clamscan.d.ts +32 -0
  56. package/types/src/files/handle.d.ts +106 -0
  57. package/types/src/files/kinds.d.ts +105 -0
  58. package/types/src/files/scan.d.ts +80 -0
  59. package/types/src/files/sniff.d.ts +7 -0
  60. package/types/src/files/streams.d.ts +17 -0
  61. package/types/src/files/treatment.d.ts +18 -0
  62. package/types/src/from-row.d.ts +20 -0
  63. package/types/src/honeypot.d.ts +2 -0
  64. package/types/src/implement/anonymous.d.ts +26 -0
  65. package/types/src/implement/attachment.d.ts +14 -0
  66. package/types/src/implement/boot.d.ts +109 -0
  67. package/types/src/implement/bounded.d.ts +22 -0
  68. package/types/src/implement/browser-config.d.ts +19 -0
  69. package/types/src/implement/capability.d.ts +140 -0
  70. package/types/src/implement/challenge.d.ts +75 -0
  71. package/types/src/implement/client-address.d.ts +11 -0
  72. package/types/src/implement/connect.d.ts +67 -0
  73. package/types/src/implement/crashes.d.ts +31 -0
  74. package/types/src/implement/dispatch.d.ts +218 -0
  75. package/types/src/implement/egress.d.ts +14 -0
  76. package/types/src/implement/environment.d.ts +14 -0
  77. package/types/src/implement/failures.d.ts +34 -0
  78. package/types/src/implement/faults.d.ts +44 -0
  79. package/types/src/implement/headers.d.ts +7 -0
  80. package/types/src/implement/implement.d.ts +58 -0
  81. package/types/src/implement/index.d.ts +24 -0
  82. package/types/src/implement/invocation.d.ts +120 -0
  83. package/types/src/implement/membership.d.ts +201 -0
  84. package/types/src/implement/multipart.d.ts +36 -0
  85. package/types/src/implement/params.d.ts +7 -0
  86. package/types/src/implement/principal.d.ts +52 -0
  87. package/types/src/implement/project.d.ts +11 -0
  88. package/types/src/implement/public.d.ts +61 -0
  89. package/types/src/implement/serve.d.ts +25 -0
  90. package/types/src/implement/tokens.d.ts +49 -0
  91. package/types/src/implement/types.d.ts +243 -0
  92. package/types/src/implement/urls.d.ts +15 -0
  93. package/types/src/implement/verifiers.d.ts +19 -0
  94. package/types/src/implement/webhook.d.ts +55 -0
  95. package/types/src/implement/workload.d.ts +56 -0
  96. package/types/src/implement/xlsx.d.ts +6 -0
  97. package/types/src/index.d.ts +12 -0
  98. package/types/src/jobs/exception.d.ts +40 -0
  99. package/types/src/jobs/mail.d.ts +67 -0
  100. package/types/src/jobs/report.d.ts +56 -0
  101. package/types/src/jobs/runner.d.ts +145 -0
  102. package/types/src/jobs/schedule.d.ts +15 -0
  103. package/types/src/jobs/scrub.d.ts +12 -0
  104. package/types/src/jobs/types.d.ts +92 -0
  105. package/types/src/react/caller.d.ts +30 -0
  106. package/types/src/react/errors.d.ts +40 -0
  107. package/types/src/react/hooks.d.ts +110 -0
  108. package/types/src/react/index.d.ts +5 -0
  109. package/types/src/react/provider.d.ts +58 -0
  110. package/types/src/react/store.d.ts +68 -0
  111. package/types/src/react/testing.d.ts +28 -0
  112. package/types/src/react/types.d.ts +33 -0
  113. package/types/src/rpc/builder.d.ts +52 -0
  114. package/types/src/rpc/contract.d.ts +23 -0
  115. package/types/src/rpc/dispatcher.d.ts +11 -0
  116. package/types/src/rpc/types.d.ts +62 -0
  117. package/types/src/service/define.d.ts +42 -0
  118. package/types/src/service/index.d.ts +3 -0
  119. package/types/src/service/serve.d.ts +28 -0
  120. package/types/src/standard-schema.d.ts +55 -0
  121. package/types/src/testing/caller.d.ts +95 -0
  122. package/types/src/testing/challenge.d.ts +11 -0
  123. package/types/src/testing/dev.d.ts +97 -0
  124. package/types/src/testing/endpoint-access.d.ts +99 -0
  125. package/types/src/testing/index.d.ts +12 -0
  126. package/types/src/testing/isolation.d.ts +3 -0
  127. package/types/src/testing/kit.d.ts +182 -0
  128. package/types/src/testing/membership.d.ts +132 -0
  129. package/types/src/testing/policy-isolation.d.ts +113 -0
  130. package/types/src/testing/preload.d.ts +1 -0
  131. package/types/src/testing/proxy.d.ts +40 -0
  132. package/types/src/testing/runner.d.ts +8 -0
  133. package/types/src/testing/sample-file.d.ts +5 -0
  134. package/types/src/testing/status.d.ts +4 -0
  135. package/types/src/undumpable.d.ts +5 -0
@@ -0,0 +1,274 @@
1
+ import type { EndpointCache, RpcCaller } from '@fabrika/auth-core';
2
+ import type { AnyDbIndex, ReadOnlyUnscoped, Unavailable, UnscopedDeclaration, UnscopedMode } from '@fabrika/db/tables';
3
+ import type { z } from 'zod/v4';
4
+ import type { Snake } from '../from-row';
5
+ import type { ExtraKeys, HandlerInput, IsAny } from '../implement/types';
6
+ import type { AttachmentBrand } from './attachment';
7
+ import type { CheckedAccess, Declared, EndpointContext, ExportContext, ImportOf, KickContext, KitTypes, LinkContext, PublicContext, SqlMode, TokensContext, WebhooksContext } from './context';
8
+ import type { ProcedureType } from './declaration';
9
+ import type { AppAccess, CapabilitiesAccess, CapabilityAccess, ChallengeOption, InputOf, InputSchema, LinkAccess, MemberAccess, MutationAccess, NotLoose, Procedure, PublicAccess, QueryAccess, Schema } from './define';
10
+ import type { WithClaims } from './token';
11
+ /** Fields a builder sets itself: a definition that carries one does not type-check. */
12
+ type Owned<K extends string> = {
13
+ readonly [P in K]?: never;
14
+ };
15
+ /** Unknown keys of an `unscoped` declaration, each refused at its own line. */
16
+ type ExactTables<U, Tables extends string> = [Exclude<keyof U, Tables>] extends [never] ? unknown : {
17
+ readonly [P in Exclude<keyof U, Tables>]: Unavailable<`${P & string} is not a table of src/db/tables.ts`>;
18
+ };
19
+ /**
20
+ * The off-road fields a site declares. Each is inferred from its optional field and then required: a handle exists
21
+ * only for a declaration the object really carries, never for one an annotation merely allows.
22
+ */
23
+ export type DeclaredFields<S, U, Cn, Is, Ix extends AnyDbIndex> = {
24
+ /** `ctx.sql`, in this mode; a query declares only `'read'`. */
25
+ readonly sql?: S;
26
+ /** `ctx.db.unscoped.<table>`, each in its mode, scope predicate `true`; a query declares only `'read'`. */
27
+ readonly unscoped?: U;
28
+ /** `ctx.connect.<connector>`, for the connectors the kit imports. */
29
+ readonly connect?: Cn;
30
+ /** `ctx.links.issue` for this link mount, on an endpoint whose action is the mount's `issuedBy`. */
31
+ readonly issues?: Is;
32
+ } & ([S] extends [never] ? unknown : {
33
+ readonly sql: S & NoInfer<SqlReach<keyof Ix['tables'] & string>>;
34
+ }) & ([U] extends [never] ? unknown : {
35
+ readonly unscoped: U & NoInfer<ExactTables<U, keyof Ix['tables'] & string> & ReadOnlyUnscoped<Ix, U>>;
36
+ }) & ([Cn] extends [never] ? unknown : {
37
+ readonly connect: Cn & NoInfer<LiteralList<Cn>>;
38
+ }) & ([Is] extends [never] ? unknown : {
39
+ readonly issues: Is & NoInfer<OneLiteral<Is>>;
40
+ });
41
+ /** `ctx.sql` runs on `@fabrika/db`, so a kit without tables declares no `sql`. */
42
+ type SqlReach<Tables extends string> = [Tables] extends [never] ? Unavailable<'ctx.sql runs on @fabrika/db: a kit without tables (defineApp(vocabulary)) declares no sql'> : unknown;
43
+ /** A list typed only by its element (`readonly 'catalog'[]`) may hold none of them; the declaration is a literal tuple. */
44
+ type LiteralList<Cn> = Cn extends readonly unknown[] ? number extends Cn['length'] ? "connect names its connectors as a literal list: connect: ['catalog']" : unknown : unknown;
45
+ /** `issues` names one link mount, as a literal. */
46
+ type OneLiteral<Is> = string extends Is ? Unavailable<"issues names one link mount, as a literal: issues: 'shared'"> : true extends IsUnion<Is> ? Unavailable<"issues names one link mount, as a literal: issues: 'shared'"> : unknown;
47
+ /** A query writes nothing, so it has nothing to kick a job for and no binding to write. */
48
+ type NoKick = {
49
+ readonly kicks?: Unavailable<'a query kicks no job: declare kicks on a mutation'>;
50
+ readonly binds?: Unavailable<'a query binds no webhook: declare binds on a mutation'>;
51
+ };
52
+ /** `binds` names one webhook, as a literal. */
53
+ type OneWebhook<Bs> = string extends Bs ? Unavailable<"binds names one webhook, as a literal: binds: 'stripe'"> : true extends IsUnion<Bs> ? Unavailable<"binds names one webhook, as a literal: binds: 'stripe'"> : unknown;
54
+ /** The webhook whose bindings a mutation writes (`ctx.webhooks`), inferred from its optional field and then required. */
55
+ type BindsField<Bs> = {
56
+ readonly binds?: Bs;
57
+ } & ([Bs] extends [never] ? unknown : {
58
+ readonly binds: Bs & NoInfer<OneWebhook<Bs>>;
59
+ });
60
+ /** The jobs a mutation may kick (`ctx.kick`), inferred from its optional field and then required, as a literal list. */
61
+ export type KicksField<Ks> = {
62
+ readonly kicks?: Ks;
63
+ } & ([Ks] extends [never] ? unknown : {
64
+ readonly kicks: Ks & NoInfer<LiteralList<Ks>>;
65
+ });
66
+ /** The token purposes a site signs (`ctx.tokens.sign`), inferred from its optional field and then required, as a literal list. */
67
+ export type SignsField<Sg, Purposes extends string> = {
68
+ readonly signs?: Sg;
69
+ } & ([Sg] extends [never] ? unknown : {
70
+ readonly signs: Sg & NoInfer<KnownPurposes<Sg, Purposes>>;
71
+ });
72
+ /**
73
+ * The HTTPS origins a site's code calls (`fetch`): each an exact origin, no path or wildcard. A guard on the global
74
+ * `fetch` refuses any other while the site runs; a public procedure declares none.
75
+ */
76
+ export interface EgressField {
77
+ readonly egress?: readonly `https://${string}`[];
78
+ }
79
+ /** Each purpose `signs` names is one of `defineApp`'s `tokens`. */
80
+ type KnownPurposes<Sg, Purposes extends string> = Sg extends readonly (infer P extends string)[] ? [Exclude<P, Purposes>] extends [never] ? LiteralList<Sg> : Unavailable<`signs names ${ListOf<Exclude<P, Purposes>>}, which defineApp's tokens do not declare`> : unknown;
81
+ type IsUnion<T, All = T> = T extends unknown ? ([All] extends [T] ? false : true) : never;
82
+ /** A bucket's calls per minute, or `null` to turn a default bucket off. */
83
+ type Bucket = number | null;
84
+ /**
85
+ * How a procedure is admitted (`admission`), merged into its kind's default: a public mutation counts 10 calls per
86
+ * minute per client and 100 for the endpoint; every other procedure counts none unless it declares a bucket.
87
+ */
88
+ export type AdmissionOption<Acc> = [Acc] extends [PublicAccess] ? {
89
+ /** `'same-origin'` by default; `'listed'` the environment's listed origins; `'any'` every origin. */
90
+ readonly origins?: 'same-origin' | 'listed' | 'any';
91
+ readonly rate?: {
92
+ readonly perClient?: Bucket;
93
+ readonly perEndpoint?: Bucket;
94
+ readonly bytesPerHour?: Bucket;
95
+ };
96
+ /** Verified on the server before the handler; the input carries the widget's token in `challengeToken`. */
97
+ readonly challenge?: ChallengeOption;
98
+ } : {
99
+ /** `'same-origin'` by default; `'listed'` the environment's listed origins, with a key only (ADR-0022). */
100
+ readonly origins?: 'same-origin' | 'listed';
101
+ readonly rate?: {
102
+ readonly perCaller?: Bucket;
103
+ readonly perEndpoint?: Bucket;
104
+ };
105
+ };
106
+ /** A procedure's bounds: its body in bytes (64 KiB by default, at most 1 MiB) and its handler's time (10 s, at most 60 s). */
107
+ export interface LimitsOption {
108
+ readonly maxBytes?: number;
109
+ readonly timeoutMs?: number;
110
+ }
111
+ /**
112
+ * A public procedure's workload actions, which its handler holds and nothing else; no other procedure declares them.
113
+ * Inferred from the optional field and then required, like a declared field.
114
+ */
115
+ export type PublicFields<Acc, Acts> = [Acc] extends [PublicAccess] ? {
116
+ readonly actions: Acts & NoInfer<Acts extends readonly [] ? Unavailable<"a public procedure names what its handler holds: actions: ['<action>']"> : unknown>;
117
+ } : {
118
+ readonly actions?: Unavailable<'only a public procedure declares actions: its handler runs as its own workload'>;
119
+ };
120
+ /** The handler context of a group's procedure: a public one runs as its own workload, every other as its caller. */
121
+ export type ProcedureContext<K extends KitTypes, Caller extends RpcCaller, Kind extends 'query' | 'mutation', Acc, Acts extends readonly string[], D extends Declared<SqlMode, unknown, readonly string[], string>, Ks = never, Bs = never, Sg = never> = ([Acc] extends [PublicAccess] ? PublicContext<K, Kind, Acts[number]> : EndpointContext<K, Caller, Kind, CheckedAccess<Acc>, D> & WebhooksContext<Bs>) & KickContext<Ks> & TokensContext<K, Sg>;
122
+ /** A group without callers holds public procedures only; any other group may hold both. */
123
+ export type GroupAccess<Caller extends RpcCaller, Acc> = [Caller] extends [never] ? PublicAccess : Acc | PublicAccess;
124
+ /** An endpoint's declaration: its schemas, its access form and the reach it declares. */
125
+ export type EndpointDef<I, O, Acc, S, U, Cn, Is, Ix extends AnyDbIndex> = Owned<'~kind' | 'type'> & {
126
+ readonly input?: I & NotLoose<I>;
127
+ readonly output: O & NotLoose<O>;
128
+ readonly access: Acc;
129
+ readonly admission?: AdmissionOption<Acc>;
130
+ readonly limits?: LimitsOption;
131
+ } & DeclaredFields<S, U, Cn, Is, Ix>;
132
+ /**
133
+ * A group procedure's HTTP shape, its `query` schema inferred: what its handler then reads as `query`. Only a public
134
+ * procedure has a path of its own.
135
+ */
136
+ type HttpField<Q, Acc> = {
137
+ readonly http?: HttpOption<Q & NoInfer<NotLoose<Q>>> & OwnPathOption<Acc>;
138
+ };
139
+ /**
140
+ * `http.path`: a public procedure served at a literal path of its own instead of `<prefix>/<name>`, so a caller outside
141
+ * the application keeps its URL. It lies outside every mount's prefix and under no `/__fabrika`.
142
+ */
143
+ export type OwnPathOption<Acc> = [Acc] extends [PublicAccess] ? {
144
+ readonly path?: `/${string}`;
145
+ } : unknown;
146
+ type Returned<F> = F extends (args: never) => infer R ? Awaited<R> : never;
147
+ /** The last member of a union, in the order the compiler holds it. */
148
+ type LastOf<U> = (U extends unknown ? (member: () => U) => void : never) extends (member: infer I) => void ? I extends () => infer L ? L : never : never;
149
+ /** `'a' | 'b'` → `'a, b'`, for a message. */
150
+ export type ListOf<U extends string, Listed extends string = ''> = [U] extends [never] ? Listed : ListOf<Exclude<U, LastOf<U>>, Listed extends '' ? LastOf<U> & string : `${LastOf<U> & string}, ${Listed}`>;
151
+ /** The fields, at any depth, that a handler `F` returns and the output `O` does not declare. */
152
+ export type UndeclaredFields<F, O extends Schema> = ExtraKeys<Returned<F>, z.input<O>>;
153
+ /** An object with a camelCase field, which a database row names in snake_case. */
154
+ type HasCamel<V> = {
155
+ [K in keyof V]: K extends string ? (Snake<K> extends K ? never : K) : never;
156
+ }[keyof V];
157
+ /**
158
+ * A database row returned where the output declares camelCase fields: its snake_case columns, of any value, at the
159
+ * depth the output has them. `.handle` admits it so that `ExactReturn` can name `fromRow` in one line.
160
+ */
161
+ type RowShaped<V> = V extends readonly (infer Item)[] ? readonly RowShaped<Item>[] : V extends object ? [HasCamel<V>] extends [never] ? {
162
+ readonly [K in keyof V]: RowShaped<V[K]>;
163
+ } : {
164
+ readonly [K in keyof V as Snake<K & string>]: unknown;
165
+ } : V;
166
+ /**
167
+ * What a kit handler `F` may return: the output, or — only when `F` returns one — a database row of it, which
168
+ * `ExactReturn` refuses with the fix, as it refuses anything but rows from an attachment's handler. Any other mistake
169
+ * keeps the compiler's own message about the output.
170
+ */
171
+ export type HandlerReturn<F, O extends Schema> = [Returned<F>] extends [z.input<O>] ? z.input<O> : [O] extends [AttachmentBrand] ? unknown : [Returned<F>] extends [RowShaped<z.input<O>>] ? RowShaped<z.input<O>> : z.input<O>;
172
+ /** A kit endpoint's handler, returning `R`; `X` adds what its HTTP shape reads beside the input (`query`). */
173
+ export type KitHandler<In, Ctx, R, X = unknown> = (args: {
174
+ readonly input: In;
175
+ readonly ctx: Ctx;
176
+ } & X) => R | Promise<R>;
177
+ /**
178
+ * What a handler reads beside its input: the URL's `query` of a POST that declares `http.query`, each signed token in it
179
+ * as the claims of its purpose.
180
+ */
181
+ export type QueryArgs<Q, T = Record<never, never>> = [Q] extends [never] ? unknown : Q extends InputSchema ? {
182
+ readonly query: WithClaims<z.output<Q>, T>;
183
+ } : unknown;
184
+ /**
185
+ * The wire of a procedure: `POST` with a JSON body by default; a query may be `GET`, its input then flat scalar URL
186
+ * parameters; a POST may read a flat `query` from the URL and take a native form's `urlencoded` body.
187
+ */
188
+ export interface HttpOption<Q> {
189
+ readonly method?: 'GET' | 'POST';
190
+ readonly query?: Q;
191
+ readonly body?: 'json' | 'urlencoded';
192
+ /**
193
+ * A public GET query's successful answers may be reused: `{ maxAgeSeconds }`, or `'immutable'` (a year) when its
194
+ * input names an immutable value. Every other answer is `no-store`.
195
+ */
196
+ readonly cache?: EndpointCache;
197
+ }
198
+ /**
199
+ * What `.handle` answers: the endpoint, or a message the group refuses at the endpoint's line — when the handler
200
+ * returns a database row where the output is camelCase, anything but rows for an attachment, or, at any depth, a
201
+ * field the output does not declare. A field whose type is an error elsewhere in the handler is not reported again here.
202
+ */
203
+ export type ExactReturn<F, O extends Schema, E> = [Returned<F>] extends [z.input<O>] ? [UndeclaredFields<F, O>] extends [never] ? E : IsAny<UndeclaredFields<F, O>> extends true ? E : Unavailable<`the handler returns ${ListOf<UndeclaredFields<F, O> & string>}, which the output does not declare: return only declared fields`> : [O] extends [AttachmentBrand] ? Unavailable<'an attachment handler returns its rows: an array of its row schema, with nothing around it'> : Unavailable<`the handler returns a database row (${ListOf<UndeclaredFields<F, O> & string>}) where the output is camelCase: map it with fromRow(Schema, row) from @fabrika/app`>;
204
+ /** A declared, handled endpoint: what a group holds. Its type keeps the declaration and drops the handler's. */
205
+ export interface Endpoint<T extends ProcedureType, I extends InputSchema | null, O extends Schema, Acc, D> extends Procedure<T, I, O, Acc> {
206
+ readonly declared: D;
207
+ }
208
+ /**
209
+ * An endpoint before `.handle`: a group refuses it. `Tk` are the kit's token purposes: a signed token field of the input
210
+ * reaches the handler as the claims of its purpose.
211
+ */
212
+ export interface EndpointBuilder<T extends ProcedureType, I extends InputSchema | null, O extends Schema, Acc, D, Ctx, X = unknown, Tk = Record<never, never>> extends PendingEndpoint {
213
+ /** The endpoint's handler, typed by its access form and declaration; it may return only the output's fields. */
214
+ handle<const F extends KitHandler<WithClaims<HandlerInput<I, Acc>, Tk>, Ctx, HandlerReturn<F, O>, X>>(handler: F): ExactReturn<F, O, Endpoint<T, I, O, Acc, D>>;
215
+ }
216
+ /** What every endpoint builder has and no handled endpoint has. */
217
+ export interface PendingEndpoint {
218
+ handle(handler: never): unknown;
219
+ }
220
+ /**
221
+ * The builders of a group's callback: they know the group's callers, so a handler knows its principal. A group without
222
+ * callers (`Caller` is `never`) declares public procedures only.
223
+ */
224
+ export interface GroupKit<K extends KitTypes, Caller extends RpcCaller> {
225
+ query<const Acc extends GroupAccess<Caller, QueryAccess<K['action'], K['dimension'], InputOf<I>>>, O extends Schema, I extends InputSchema | null = null, const S extends 'read' = never, const U extends UnscopedDeclaration<K['tables'], 'read'> = never, const Cn extends readonly ImportOf<K>[] = never, const Is extends string = never, const Acts extends readonly K['action'][] = never, Q extends InputSchema = never, const Sg extends readonly string[] = never>(def: EndpointDef<I, O, Acc, S, U, Cn, Is, K['index']> & PublicFields<Acc, Acts> & HttpField<Q, Acc> & NoKick & SignsField<Sg, keyof K['tokens'] & string> & EgressField): EndpointBuilder<'query', I, O, Acc, Declared<S, U, Cn, Is>, ProcedureContext<K, Caller, 'query', Acc, Acts, Declared<S, U, Cn, Is>, never, never, Sg>, QueryArgs<Q, K['tokens']>, K['tokens']>;
226
+ mutation<const Acc extends GroupAccess<Caller, MutationAccess<K['action'], K['dimension'], K['creatable'], InputOf<I>>>, O extends Schema, I extends InputSchema | null = null, const S extends SqlMode = never, const U extends UnscopedDeclaration<K['tables'], UnscopedMode> = never, const Cn extends readonly ImportOf<K>[] = never, const Is extends string = never, const Acts extends readonly K['action'][] = never, Q extends InputSchema = never, const Ks extends readonly string[] = never, const Bs extends string = never, const Sg extends readonly string[] = never>(def: EndpointDef<I, O, Acc, S, U, Cn, Is, K['index']> & PublicFields<Acc, Acts> & HttpField<Q, Acc> & KicksField<Ks> & BindsField<Bs> & SignsField<Sg, keyof K['tokens'] & string> & EgressField): EndpointBuilder<'mutation', I, O, Acc, Declared<S, U, Cn, Is>, ProcedureContext<K, Caller, 'mutation', Acc, Acts, Declared<S, U, Cn, Is>, Ks, Bs, Sg>, QueryArgs<Q, K['tokens']>, K['tokens']>;
227
+ }
228
+ /** Any handled endpoint. */
229
+ export type AnyEndpoint = Endpoint<ProcedureType, InputSchema | null, Schema, unknown, unknown>;
230
+ /** What a group's callback returns: its endpoints by name. A mount nests groups; a group does not nest. */
231
+ export interface GroupTree {
232
+ readonly [name: string]: AnyEndpoint;
233
+ }
234
+ /** What a group's callback may return before the group checks that every endpoint took its handler. */
235
+ export interface GroupInput {
236
+ readonly [name: string]: AnyEndpoint | PendingEndpoint;
237
+ }
238
+ declare const failedBuild: unique symbol;
239
+ /**
240
+ * The constraint `app.group` infers against. A refused callback falls back to it, and its private symbol keeps the
241
+ * mount from repeating that error. It is not an annotation: a group typed with it mounts unchecked.
242
+ */
243
+ export interface GroupBuild extends GroupInput {
244
+ readonly [failedBuild]?: true;
245
+ }
246
+ /**
247
+ * A builder without `.handle(…)`. An endpoint typed by the compiler's error type is the consequence of a type error
248
+ * inside its handler, reported there; every check is wrapped in a tuple, since an unwrapped one answers the error type.
249
+ */
250
+ type IsPending<E> = [0] extends [1 & E] ? false : [Extract<E, PendingEndpoint>] extends [never] ? false : true;
251
+ /** The endpoints of a group, prefixed by `Path`, that have no `.handle(…)`. */
252
+ export type PendingIn<T, Path extends string> = typeof failedBuild extends keyof T ? never : string extends keyof T ? [IsPending<T[string & keyof T]>] extends [true] ? `${Path}* (its type admits an endpoint without a handler)` : never : {
253
+ [K in keyof T]: [IsPending<T[K]>] extends [true] ? `${Path}${K & string}` : never;
254
+ }[keyof T];
255
+ /** `app.group(…)`: endpoints for one set of callers (none for a group of public procedures), mounted by the contract. */
256
+ export interface Group<C extends readonly RpcCaller[], T extends GroupInput> {
257
+ readonly '~kind': 'group';
258
+ readonly callers: C;
259
+ readonly endpoints: T;
260
+ }
261
+ /** The builders of a link mount's callback: each procedure acts on the object its key is bound to. */
262
+ export interface LinkGroupKit<K extends KitTypes, LD extends string, G extends string> {
263
+ query<const Acc extends LinkAccess<G>, O extends Schema, I extends InputSchema | null = null, const S extends 'read' = never, const U extends UnscopedDeclaration<K['tables'], 'read'> = never>(def: EndpointDef<I, O, Acc, S, U, never, never, K['index']> & NoKick): EndpointBuilder<'query', I, O, Acc, Declared<S, U, never, never>, LinkContext<K, 'query', LD, Acc['action'], Declared<S, U, never, never>>, unknown, K['tokens']>;
264
+ mutation<const Acc extends LinkAccess<G>, O extends Schema, I extends InputSchema | null = null, const S extends SqlMode = never, const U extends UnscopedDeclaration<K['tables'], UnscopedMode> = never, const Ks extends readonly string[] = never>(def: EndpointDef<I, O, Acc, S, U, never, never, K['index']> & KicksField<Ks>): EndpointBuilder<'mutation', I, O, Acc, Declared<S, U, never, never>, LinkContext<K, 'mutation', LD, Acc['action'], Declared<S, U, never, never>> & KickContext<Ks>, unknown, K['tokens']>;
265
+ }
266
+ /** An export procedure names its action and its scope; `{ member: true }` would give the consumer's key nothing to hold. */
267
+ export type ExportAccess<A extends string, D extends string, In> = Exclude<QueryAccess<A, D, In>, MemberAccess | AppAccess<A> | CapabilitiesAccess<{
268
+ readonly [name: string]: CapabilityAccess<A, D, In>;
269
+ }>>;
270
+ /** The builder of an export's callback: queries only, run read-only. */
271
+ export interface ExportKit<K extends KitTypes> {
272
+ query<const Acc extends ExportAccess<K['action'], K['dimension'], InputOf<I>>, O extends Schema, I extends InputSchema | null = null, const S extends 'read' = never, const U extends UnscopedDeclaration<K['tables'], 'read'> = never>(def: EndpointDef<I, O, Acc, S, U, never, never, K['index']>): EndpointBuilder<'query', I, O, Acc, Declared<S, U, never, never>, ExportContext<K, CheckedAccess<Acc>, Declared<S, U, never, never>>>;
273
+ }
274
+ export {};
@@ -0,0 +1,18 @@
1
+ import type { ConnectSnapshot } from './connect';
2
+ /** `site` with its handler, which only `handlerOf` reads. */
3
+ export declare function withHandler<T extends object>(site: T, handler: unknown): T;
4
+ /** The handler `.handle` attached to a site of the kit, or `undefined` for a site that took none. */
5
+ export declare function handlerOf(site: object): unknown;
6
+ /** `contract` with the snapshots of the kit's imports, by the import's name. */
7
+ export declare function withSnapshots<T extends object>(contract: T, imported: Readonly<Record<string, ConnectSnapshot>>): T;
8
+ /** The snapshots `app.contract` recorded for `contract`; none for a contract the kit did not build. */
9
+ export declare function snapshotsOf(contract: object): Readonly<Record<string, ConnectSnapshot>>;
10
+ /** Which kit built a contract: one with tables, `defineApp(vocabulary, tables)`, or one without, `defineApp(vocabulary)`. */
11
+ export type KitOrigin = 'tables' | 'tableless';
12
+ /** `contract` as `app.contract` built it, with the kind of kit that built it. */
13
+ export declare function withKitOrigin<T extends object>(contract: T, origin: KitOrigin): T;
14
+ /**
15
+ * The kind of kit that built `contract`, or `undefined` for any other object, a copy of a kit's contract included: a
16
+ * copy loses what is kept beside the original, so `serve` refuses it.
17
+ */
18
+ export declare function kitOriginOf(contract: object): KitOrigin | undefined;
@@ -0,0 +1,19 @@
1
+ export { contractArtifactSchema, parseContractArtifact, schemaShapeSchema } from './artifact-schema';
2
+ export { type Attachment, attachment, type AttachmentBrand, type AttachmentMark, attachmentOf, type AttachmentOptions, attachmentOutput, } from './attachment';
3
+ export { buildArtifact } from './build';
4
+ export { compileContract, describeContract } from './compile';
5
+ export { type ConnectSnapshot, describeSnapshot, exportDescription, exportDescriptionSchema, incompatibleChanges, incompatibleMountChanges, parseExportDescription, type SnapshotProcedure, } from './connect';
6
+ export type * from './context';
7
+ export * from './declaration';
8
+ export * from './defaults';
9
+ export * from './define';
10
+ export { type ClientInput, file, type FileBrand, type FileMark, fileOf, type FileRef, type FileSchema, type FileStatus } from './file';
11
+ export type * from './group';
12
+ export * from './kit';
13
+ export { schemaFromContract } from './platform';
14
+ export { ContractError } from './problems';
15
+ export { type Redirect, redirect, type RedirectBrand, type RedirectMark, redirectOf, type RedirectOptions } from './redirect';
16
+ export { SNAPSHOT_DIRECTORY, type SnapshotNames, snapshotNames, snapshotSource } from './snapshot-source';
17
+ export { SIGNED_TOKEN_MAX_LENGTH, signedToken, type SignedTokenMark, signedTokenOf, type SignedTokenSchema, token, TOKEN_MAX_DAYS, type TokenOptions, type TokenPurpose, type TokenPurposes, type TokenSigning, type WithClaims, } from './token';
18
+ export * from './vocabulary';
19
+ export { type WebhookBindings, WebhookSecret } from './webhook-binding';
@@ -0,0 +1,210 @@
1
+ import type { JobMailer, RpcCaller, WebhookScheme } from '@fabrika/auth-core';
2
+ import type { AnyDbIndex, DbIndex, Tables, Unavailable, UnscopedDeclaration, UnscopedMode } from '@fabrika/db/tables';
3
+ import type { z } from 'zod/v4';
4
+ import type { Declared, JobKitContext, KickContext, KitImports, KitTypes, NoTablesIndex, SqlMode, TokensContext, WebhookKitContext } from './context';
5
+ import { type ExportAccessDeclaration, type ImportDeclaration, type LinkAccessDeclaration, type ProcedureType } from './declaration';
6
+ import { type Contract, type CreatableDimension, type CronJob, type Export, type InputSchema, type JobLimitsOption, type Kit, type LinkMount, type NotLoose, type Path, type ProcedureTree, type RpcMount, type Schema, type Surface, type WebhookMount } from './define';
7
+ import type { DeclaredFields, EgressField, Endpoint, ExportKit, Group, GroupBuild, GroupInput, GroupKit, KicksField, LimitsOption, LinkGroupKit, ListOf, PendingIn, SignsField } from './group';
8
+ import type { TokenPurposes } from './token';
9
+ import type { AnyAppVocabulary, AppVocabulary } from './vocabulary';
10
+ /** Fields a builder sets itself: an options object that carries one does not type-check. */
11
+ type Owned<K extends string> = {
12
+ readonly [P in K]?: never;
13
+ };
14
+ /** The kit's types, computed once from the vocabulary, the tables' index, the imports and the token purposes. */
15
+ export type KitOf<V, Ix, Imp extends KitImports, Tk extends TokenPurposes = Record<never, never>> = V extends AppVocabulary<infer A, infer D, infer R, infer Dims, infer M> ? {
16
+ readonly action: A;
17
+ readonly dimension: D;
18
+ readonly creatable: CreatableDimension<Dims>;
19
+ readonly role: R;
20
+ readonly dimensions: Dims;
21
+ readonly members: M;
22
+ readonly index: Ix;
23
+ readonly tables: Ix extends {
24
+ readonly tables: infer T;
25
+ } ? keyof T & string : never;
26
+ readonly imports: Imp;
27
+ readonly tokens: Tk;
28
+ } : never;
29
+ export type CronOptions<Acts, S, U, Is, Ix extends AnyDbIndex, M = never, Ks = never, Sg = never, Purposes extends string = never> = Owned<'kind' | 'schedule'> & {
30
+ readonly actions: Acts;
31
+ readonly limits?: JobLimitsOption;
32
+ readonly retries?: number;
33
+ } & DeclaredFields<S, U, never, Is, Ix> & MailerField<M> & KicksField<Ks> & SignsField<Sg, Purposes> & EgressField;
34
+ /** The mail transport a job reaches, inferred from its optional field and then required, like a declared field. */
35
+ type MailerField<M> = {
36
+ /** `'installation'`: the installation's mail transport; `'own'`: the application's own. */
37
+ readonly mailer?: M;
38
+ } & ([M] extends [never] ? unknown : {
39
+ readonly mailer: M;
40
+ });
41
+ /** A cron job of the kit, handled. */
42
+ export interface KitCronJob<Acts extends string, D> extends CronJob<Acts> {
43
+ readonly declared: D;
44
+ }
45
+ /** A cron job before `.handle`: the contract's `jobs` refuses it. */
46
+ export interface CronBuilder<K extends KitTypes, Acts extends string, D extends Declared<SqlMode, unknown, never, string, JobMailer>, Ks = never, Sg = never> {
47
+ handle(handler: (args: {
48
+ readonly ctx: JobKitContext<K, Acts, D> & KickContext<Ks> & TokensContext<K, Sg>;
49
+ }) => void | Promise<void>): KitCronJob<Acts, D>;
50
+ }
51
+ export type WebhookOptions<B, Acts, I, S, U, Ix extends AnyDbIndex, Ks = never, Sg = never, Purposes extends string = never> = Owned<'kind' | 'path'> & {
52
+ readonly scheme: WebhookScheme;
53
+ readonly boundTo: B;
54
+ readonly actions: Acts;
55
+ readonly input: I & NotLoose<I>;
56
+ /** A delivery's body (1 MiB by default and at most) and its handler's time (10 s by default, at most 60 s). */
57
+ readonly limits?: LimitsOption;
58
+ } & DeclaredFields<S, U, never, never, Ix> & KicksField<Ks> & SignsField<Sg, Purposes> & EgressField;
59
+ /** A webhook of the kit, handled. */
60
+ export interface KitWebhook<B extends string, Acts extends string, I extends Schema, D> extends WebhookMount<B, Acts, I> {
61
+ readonly declared: D;
62
+ }
63
+ /** A webhook before `.handle`: the contract refuses it as a mount. */
64
+ export interface WebhookBuilder<K extends KitTypes, B extends string, Acts extends string, I extends InputSchema, D extends Declared<SqlMode, unknown, never, never>, Ks = never, Sg = never> {
65
+ handle(handler: (args: {
66
+ readonly input: z.output<I>;
67
+ readonly ctx: WebhookKitContext<K, B, Acts, D> & KickContext<Ks> & TokensContext<K, Sg>;
68
+ }) => void | Promise<void>): KitWebhook<B, Acts, I, D>;
69
+ }
70
+ /** A link mount's procedures: handled endpoints whose access names one of the mount's granted actions. */
71
+ export interface LinkTree {
72
+ readonly [name: string]: Endpoint<ProcedureType, InputSchema | null, Schema, LinkAccessDeclaration, unknown>;
73
+ }
74
+ /** An export's procedures: handled queries. */
75
+ export interface ExportTree {
76
+ readonly [name: string]: Endpoint<'query', InputSchema | null, Schema, ExportAccessDeclaration, unknown>;
77
+ }
78
+ /** What `c.rpc` mounts: one group, or groups by name, nested. */
79
+ export type MountedGroups = Group<readonly RpcCaller[], GroupInput> | {
80
+ readonly [name: string]: MountedGroups;
81
+ };
82
+ /** The callers each group names; a group of public procedures names none and is left out. */
83
+ type CallersOf<G> = G extends Group<infer C, GroupInput> ? (C extends readonly [] ? never : C) : {
84
+ [K in keyof G]: CallersOf<G[K]>;
85
+ }[keyof G];
86
+ type EndpointsOf<G> = G extends Group<readonly RpcCaller[], infer T> ? T : {
87
+ readonly [K in keyof G]: EndpointsOf<G[K]>;
88
+ };
89
+ /** A group that names callers names at least one; a group of public procedures leaves `callers` out. */
90
+ type SomeCallers<C> = C extends readonly [] ? Unavailable<"callers names at least one caller: callers: ['human']; a group of public procedures names none"> : unknown;
91
+ /** The callers of the mount's credentialed procedures, `readonly []` when every group is public. */
92
+ type Callers<G> = [CallersOf<G>] extends [never] ? readonly [] : CallersOf<G> extends infer C extends readonly RpcCaller[] ? C : never;
93
+ type Endpoints<G> = EndpointsOf<G> extends infer T extends ProcedureTree ? T : never;
94
+ type IsUnion<T, All = T> = T extends unknown ? ([All] extends [T] ? false : true) : never;
95
+ type PendingOf<G, Path extends string = ''> = G extends Group<readonly RpcCaller[], infer T> ? PendingIn<T, Path> : {
96
+ [K in keyof G & string]: PendingOf<G[K], `${Path}${K}.`>;
97
+ }[keyof G & string];
98
+ /**
99
+ * A mount takes its prefix only when it can serve every group: each endpoint took its `.handle(…)` (a group accepts
100
+ * one without, because its own callback cannot be checked before it is typed), and every group names the same callers.
101
+ */
102
+ type MountPrefix<G> = [PendingOf<G>] extends [never] ? true extends IsUnion<CallersOf<G>> ? Unavailable<'every group of one RPC mount that names callers names the same ones, in the same order'> : Path : Unavailable<`add .handle(…) to ${ListOf<PendingOf<G>>}: every endpoint takes its handler beside it`>;
103
+ /** The builders of the contract's callback: the mounts that take no handler, and `rpc`, which mounts groups. */
104
+ export interface ContractKit<K extends KitTypes> extends Pick<Kit<K['action'], K['dimension'], K['creatable']>, 'spa' | 'health' | 'files'> {
105
+ /**
106
+ * The groups' endpoints at `POST <prefix>/<group>.<endpoint>`, to the callers the groups name. `compatibility:
107
+ * 'backward'` promises their callers that a later deploy breaks none of them; Control refuses one that does.
108
+ */
109
+ rpc<const G extends MountedGroups>(prefix: MountPrefix<G>, groups: G, options?: RpcMountOptions): RpcMount<Callers<G>, Endpoints<G>>;
110
+ }
111
+ /** The options of `c.rpc`: the promise the mount makes its callers, `'unchecked'` by default. */
112
+ export interface RpcMountOptions {
113
+ readonly compatibility?: 'backward' | 'unchecked';
114
+ }
115
+ /** The `imports` section the contract carries: the kit's imports, with `usedBy` from the endpoints' `connect`. */
116
+ type ImportsSection<K extends KitTypes> = [keyof K['imports']] extends [never] ? unknown : {
117
+ readonly imports: {
118
+ readonly [N in keyof K['imports']]: ImportDeclaration;
119
+ };
120
+ };
121
+ /** The `tokens` section the contract carries: the kit's token purposes, as `defineApp`'s options declare them. */
122
+ type TokensSection<K extends KitTypes> = [keyof K['tokens']] extends [never] ? unknown : {
123
+ readonly tokens: K['tokens'];
124
+ };
125
+ /** The contract `app.contract` returns: the same `Contract` the client, the compiler and the test kit read. */
126
+ export type KitContract<K extends KitTypes, S extends Surface> = Contract<K['action'], K['dimension'], K['role'], K['dimensions'], S & ImportsSection<K> & TokensSection<K>>;
127
+ /** The kit of one application: every builder is typed by its vocabulary, its tables and its imports. */
128
+ export interface App<K extends KitTypes> {
129
+ /**
130
+ * Endpoints for `callers`, declared and handled together; `fabrika.contract.ts` mounts the group with `c.rpc`. A group
131
+ * of public procedures only (`access: { public: true }`), which anyone calls, names no callers: `app.group({}, …)`.
132
+ */
133
+ group<const C extends readonly RpcCaller[] = readonly [], const T extends GroupBuild = GroupBuild>(options: {
134
+ readonly callers?: C & NoInfer<SomeCallers<C>>;
135
+ } & Owned<'kind' | 'endpoints'>, build: (r: GroupKit<K, C[number]>) => T): Group<C, T>;
136
+ /** A job of the whole application (UTC, five fields) holding `actions`; the contract mounts it under `jobs`. */
137
+ cron<const Acts extends readonly [K['action'], ...K['action'][]], const S extends SqlMode = never, const U extends UnscopedDeclaration<K['tables'], UnscopedMode> = never, const Is extends string = never, const M extends JobMailer = never, const Ks extends readonly string[] = never, const Sg extends readonly string[] = never>(schedule: string, options: CronOptions<Acts, S, U, Is, K['index'], M, Ks, Sg, keyof K['tokens'] & string>): CronBuilder<K, Acts[number], Declared<S, U, never, Is, M>, Ks, Sg>;
138
+ /**
139
+ * A webhook whose deliveries `scheme` verifies, bound per value of `boundTo` or once for the application (`'app'`);
140
+ * the contract mounts it by name.
141
+ */
142
+ webhook<const B extends K['dimension'] | 'app', const Acts extends readonly [K['action'], ...K['action'][]], I extends InputSchema, const S extends SqlMode = never, const U extends UnscopedDeclaration<K['tables'], UnscopedMode> = never, const Ks extends readonly string[] = never, const Sg extends readonly string[] = never>(path: Path, options: WebhookOptions<B, Acts, I, S, U, K['index'], Ks, Sg, keyof K['tokens'] & string>): WebhookBuilder<K, B, Acts[number], I, Declared<S, U, never, never>, Ks, Sg>;
143
+ /** A share SPA under `prefix` and its procedures under `<prefix>/api`, for an anonymous key bound to one object. */
144
+ link<const LD extends K['dimension'], const G extends readonly [K['action'], ...K['action'][]], const IB extends K['action'], const T extends LinkTree>(prefix: Path, options: {
145
+ readonly spa: string;
146
+ readonly dimension: LD;
147
+ readonly grants: G;
148
+ readonly issuedBy: IB;
149
+ readonly maxDays: number;
150
+ readonly procedures: (l: LinkGroupKit<K, LD, G[number]>) => T;
151
+ } & Owned<'kind' | 'prefix'>): LinkMount<LD, G[number], IB, T>;
152
+ /** Read-only queries another application's connector calls; the contract mounts it under `exports`. */
153
+ export<const T extends ExportTree>(definition: {
154
+ readonly version: number;
155
+ readonly consumers: readonly [string, ...string[]];
156
+ readonly audience: 'any consumer user';
157
+ readonly procedures: (e: ExportKit<K>) => T;
158
+ } & Owned<'kind'>): Export<T>;
159
+ /**
160
+ * The contract: mounts by name and the `files`, `jobs`, `exports` and `csp` sections; `imports` and `tokens` come from
161
+ * the kit.
162
+ */
163
+ contract<const S extends Surface & Owned<'imports' | 'tokens'>>(build: (c: ContractKit<K>) => S): KitContract<K, S>;
164
+ }
165
+ /**
166
+ * The application's kit, built once in `src/app-kit.ts`: `defineApp(vocabulary, tables)`, plus the connectors it
167
+ * imports (`{ imports: { <name>: { snapshot, procedures, timeoutMs? } } }`). The tables' `DbIndex` is computed here,
168
+ * once, so each endpoint's `ctx.db` is a lookup.
169
+ *
170
+ * This signature is the kit's typed face over `RuntimeApp`, which builds plain declarations. The face answers types
171
+ * no implementation can return (`.handle`'s `ExactReturn`, `contract`'s `imports` section by the kit's imports), so
172
+ * the compiler relates the two nowhere else; `kit-runtime.test.ts` holds that each builder returns what its type says.
173
+ */
174
+ export declare function defineApp<V extends AnyAppVocabulary>(vocabulary: V): App<KitOf<V, NoTablesIndex, Record<never, never>>>;
175
+ export declare function defineApp<V extends AnyAppVocabulary, DB, P>(vocabulary: V, tables: Tables<DB, P>): App<KitOf<V, DbIndex<DB, P, V>, Record<never, never>>>;
176
+ /**
177
+ * Options that may be absent are no overload, and neither is an option field that may be absent: the contract's type
178
+ * would promise an imports section, or token purposes, it may not have. Each overload requires the fields it infers.
179
+ */
180
+ export declare function defineApp<V extends AnyAppVocabulary, DB, P, const Imp extends KitImports, const Tk extends TokenPurposes>(vocabulary: V, tables: Tables<DB, P>, options: {
181
+ readonly imports: Imp;
182
+ readonly tokens: Tk;
183
+ }): App<KitOf<V, DbIndex<DB, P, V>, Imp, Tk>>;
184
+ export declare function defineApp<V extends AnyAppVocabulary, DB, P, const Tk extends TokenPurposes>(vocabulary: V, tables: Tables<DB, P>, options: {
185
+ readonly tokens: Tk;
186
+ }): App<KitOf<V, DbIndex<DB, P, V>, Record<never, never>, Tk>>;
187
+ export declare function defineApp<V extends AnyAppVocabulary, DB, P, const Imp extends KitImports>(vocabulary: V, tables: Tables<DB, P>, options: {
188
+ readonly imports: Imp;
189
+ }): App<KitOf<V, DbIndex<DB, P, V>, Imp>>;
190
+ /** What `defineApp`'s options carry: the connectors the kit imports, and the purposes of the tokens it signs. */
191
+ export interface KitOptions {
192
+ readonly imports?: KitImports;
193
+ /** `{ <purpose>: token(Claims, { maxDays }) }`: each kind of signed token, declared once. */
194
+ readonly tokens?: TokenPurposes;
195
+ }
196
+ /** One import of the kit as the contract records it: the snapshot's identity, the procedures called, the deadline. */
197
+ export interface KitImportDeclaration {
198
+ readonly app: string;
199
+ readonly export: string;
200
+ readonly version: number;
201
+ readonly digest: string;
202
+ readonly procedures: readonly string[];
203
+ readonly timeoutMs?: number;
204
+ }
205
+ /**
206
+ * The contract's `imports` section: each import of the kit, used by the RPC endpoints that declare `connect` of it,
207
+ * in id order. The static reader builds it with this same function, so both read one `usedBy`.
208
+ */
209
+ export declare function kitImportsSection(imports: Readonly<Record<string, KitImportDeclaration>>, surface: Surface): Record<string, ImportDeclaration>;
210
+ export {};
@@ -0,0 +1,9 @@
1
+ import { type AppSchema, type ContractArtifact } from '@fabrika/auth-core';
2
+ /**
3
+ * The IAM vocabulary of a contract application, marked `contract` so IAM refuses every wildcard written for it: the
4
+ * dimensions as scopes with their container, creator role and members actions; the actions; the roles, a membership
5
+ * role with its scope and the roles that may assign it; the link mounts; the delegations; the workloads; and the locale,
6
+ * display name and e-mail wording IAM names the application with. Every artifact
7
+ * dimension is a scope, a file collection's `file:<name>` included, because access to a file is checked there.
8
+ */
9
+ export declare function schemaFromContract(artifact: ContractArtifact): AppSchema;
@@ -0,0 +1,14 @@
1
+ /** Every reason a contract does not compile, each with where it is and the allowed form. */
2
+ export declare class ContractError extends Error {
3
+ readonly name = "ContractError";
4
+ readonly problems: readonly string[];
5
+ constructor(problems: readonly string[]);
6
+ }
7
+ /** Collects problems so that one compile reports all of them, not the first. */
8
+ export declare class Problems {
9
+ #private;
10
+ add(where: string, problem: string): void;
11
+ throwIfAny(): void;
12
+ }
13
+ /** A builder of the staged kit whose signature is fixed and whose runtime a later work unit of the sprint adds. */
14
+ export declare function notImplemented(what: string, unit: string): never;
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod/v4';
2
+ import type { Schema } from './define';
3
+ declare const REDIRECT: unique symbol;
4
+ /** What `redirect()` adds to the `{ to }` schema: the origins a target may name besides the application's own. */
5
+ export interface RedirectMark {
6
+ readonly origins: readonly string[];
7
+ }
8
+ declare const Target: z.ZodObject<{
9
+ to: z.ZodString;
10
+ }, z.core.$strict>;
11
+ /** A redirect output: the handler returns `{ to }`, and the caller receives a 303 or a 302 there. */
12
+ export type Redirect = typeof Target & RedirectBrand;
13
+ /** What tells a redirect output from a JSON one in the types. */
14
+ export interface RedirectBrand {
15
+ readonly [REDIRECT]: RedirectMark;
16
+ }
17
+ export interface RedirectOptions {
18
+ /** Exact `https://` origins a target may name, besides the application's own: `['https://shop.example']`. */
19
+ readonly origins?: readonly string[];
20
+ }
21
+ /** The output of a procedure that answers a redirect. `compileContract` and the checker refuse an origin it may not list. */
22
+ export declare function redirect(options?: RedirectOptions): Redirect;
23
+ /** The mark of a `redirect()` output, or `null` for any other schema. */
24
+ export declare function redirectOf(schema: Schema): RedirectMark | null;
25
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { SchemaShape } from '@fabrika/auth-core';
2
+ import { z } from 'zod/v4';
3
+ /** The zod schema that admits what `shape` describes; `describeSchema` reads it back into the same shape. */
4
+ export declare function schemaFromShape(shape: SchemaShape): z.ZodType;
5
+ /**
6
+ * The path of a validation issue as far as `shape` declares it: field names the schema names, `[]` for an array item,
7
+ * a tuple position, `{}` for a record value. Record keys and array indexes come from the value, which another
8
+ * application wrote, so they never reach a message or a log.
9
+ */
10
+ export declare function declaredPath(shape: SchemaShape, path: readonly PropertyKey[]): string;
@@ -0,0 +1,5 @@
1
+ import type { SchemaShape } from '@fabrika/auth-core';
2
+ import { z } from 'zod/v4';
3
+ import type { Problems } from './problems';
4
+ /** A schema's shape, or `null` after recording why it has none. */
5
+ export declare function describeSchema(schema: z.core.$ZodType, where: string, problems: Problems): SchemaShape | null;
@@ -0,0 +1,15 @@
1
+ import type { ExportDescription } from '@fabrika/auth-core';
2
+ /** The directory, relative to the application root, that holds the vendored snapshots. */
3
+ export declare const SNAPSHOT_DIRECTORY = "fabrika/connect";
4
+ export interface SnapshotNames {
5
+ /** Relative to the application root: `fabrika/connect/catalog.products.v1.ts`. */
6
+ readonly file: string;
7
+ /** The snapshot const: `catalogProductsV1`. */
8
+ readonly snapshot: string;
9
+ /** The digest const the contract's import names: `catalogProductsV1Digest`. */
10
+ readonly digest: string;
11
+ }
12
+ /** The file and the identifiers of the snapshot of `app`'s export `name` at `version`. */
13
+ export declare function snapshotNames(app: string, name: string, version: number): SnapshotNames;
14
+ /** The snapshot module of `description`. Throws `ContractError` for a shape no zod source in the subset writes. */
15
+ export declare function snapshotSource(description: ExportDescription): string;