@fabrika/app 0.9.0-dev.1 → 0.9.0-dev.3

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 (134) hide show
  1. package/package.json +27 -26
  2. package/skill/SKILL.md +1 -1
  3. package/skill/references/app-setup.md +8 -8
  4. package/src/dev/changes.ts +5 -43
  5. package/src/dev/contract-digest.ts +17 -0
  6. package/src/dev/index.ts +1 -1
  7. package/src/dev/launcher.ts +116 -31
  8. package/src/dev/wire.ts +11 -1
  9. package/types/src/agent-skill.d.ts +29 -0
  10. package/types/src/build.d.ts +11 -0
  11. package/types/src/bun.d.ts +66 -0
  12. package/types/src/client/caller.d.ts +19 -0
  13. package/types/src/client/contract.d.ts +131 -0
  14. package/types/src/client/error-reporting.d.ts +66 -0
  15. package/types/src/client/index.d.ts +4 -0
  16. package/types/src/client/rpc.d.ts +14 -0
  17. package/types/src/client/share.d.ts +2 -0
  18. package/types/src/client/transport.d.ts +42 -0
  19. package/types/src/cloudflare.d.ts +49 -0
  20. package/types/src/contract/artifact-schema.d.ts +8 -0
  21. package/types/src/contract/attachment.d.ts +41 -0
  22. package/types/src/contract/build.d.ts +12 -0
  23. package/types/src/contract/compile.d.ts +11 -0
  24. package/types/src/contract/connect.d.ts +51 -0
  25. package/types/src/contract/context.d.ts +501 -0
  26. package/types/src/contract/declaration.d.ts +303 -0
  27. package/types/src/contract/defaults.d.ts +208 -0
  28. package/types/src/contract/define.d.ts +359 -0
  29. package/types/src/contract/file.d.ts +44 -0
  30. package/types/src/contract/group.d.ts +274 -0
  31. package/types/src/contract/handled.d.ts +18 -0
  32. package/types/src/contract/index.d.ts +19 -0
  33. package/types/src/contract/kit.d.ts +210 -0
  34. package/types/src/contract/platform.d.ts +9 -0
  35. package/types/src/contract/problems.d.ts +14 -0
  36. package/types/src/contract/redirect.d.ts +25 -0
  37. package/types/src/contract/schema-from-shape.d.ts +10 -0
  38. package/types/src/contract/schema-shape.d.ts +5 -0
  39. package/types/src/contract/snapshot-source.d.ts +15 -0
  40. package/types/src/contract/token.d.ts +58 -0
  41. package/types/src/contract/vocabulary.d.ts +30 -0
  42. package/types/src/contract/webhook-binding.d.ts +24 -0
  43. package/types/src/contract/webhook-scheme.d.ts +23 -0
  44. package/types/src/dev/changes.d.ts +7 -0
  45. package/types/src/dev/contract-digest.d.ts +1 -0
  46. package/types/src/dev/index.d.ts +2 -0
  47. package/types/src/dev/launcher.d.ts +32 -0
  48. package/types/src/dev/output.d.ts +22 -0
  49. package/types/src/dev/wire.d.ts +126 -0
  50. package/types/src/disk-assets.d.ts +3 -0
  51. package/types/src/errors.d.ts +46 -0
  52. package/types/src/fetch.d.ts +7 -0
  53. package/types/src/files/archive.d.ts +26 -0
  54. package/types/src/files/clamscan.d.ts +32 -0
  55. package/types/src/files/handle.d.ts +106 -0
  56. package/types/src/files/kinds.d.ts +105 -0
  57. package/types/src/files/scan.d.ts +80 -0
  58. package/types/src/files/sniff.d.ts +7 -0
  59. package/types/src/files/streams.d.ts +17 -0
  60. package/types/src/files/treatment.d.ts +18 -0
  61. package/types/src/from-row.d.ts +20 -0
  62. package/types/src/honeypot.d.ts +2 -0
  63. package/types/src/implement/anonymous.d.ts +26 -0
  64. package/types/src/implement/attachment.d.ts +14 -0
  65. package/types/src/implement/boot.d.ts +109 -0
  66. package/types/src/implement/bounded.d.ts +22 -0
  67. package/types/src/implement/browser-config.d.ts +19 -0
  68. package/types/src/implement/capability.d.ts +140 -0
  69. package/types/src/implement/challenge.d.ts +75 -0
  70. package/types/src/implement/client-address.d.ts +11 -0
  71. package/types/src/implement/connect.d.ts +67 -0
  72. package/types/src/implement/crashes.d.ts +31 -0
  73. package/types/src/implement/dispatch.d.ts +218 -0
  74. package/types/src/implement/egress.d.ts +14 -0
  75. package/types/src/implement/environment.d.ts +14 -0
  76. package/types/src/implement/failures.d.ts +34 -0
  77. package/types/src/implement/faults.d.ts +44 -0
  78. package/types/src/implement/headers.d.ts +7 -0
  79. package/types/src/implement/implement.d.ts +58 -0
  80. package/types/src/implement/index.d.ts +24 -0
  81. package/types/src/implement/invocation.d.ts +120 -0
  82. package/types/src/implement/membership.d.ts +201 -0
  83. package/types/src/implement/multipart.d.ts +36 -0
  84. package/types/src/implement/params.d.ts +7 -0
  85. package/types/src/implement/principal.d.ts +52 -0
  86. package/types/src/implement/project.d.ts +11 -0
  87. package/types/src/implement/public.d.ts +61 -0
  88. package/types/src/implement/serve.d.ts +25 -0
  89. package/types/src/implement/tokens.d.ts +49 -0
  90. package/types/src/implement/types.d.ts +243 -0
  91. package/types/src/implement/urls.d.ts +15 -0
  92. package/types/src/implement/verifiers.d.ts +19 -0
  93. package/types/src/implement/webhook.d.ts +55 -0
  94. package/types/src/implement/workload.d.ts +56 -0
  95. package/types/src/implement/xlsx.d.ts +6 -0
  96. package/types/src/index.d.ts +12 -0
  97. package/types/src/jobs/exception.d.ts +40 -0
  98. package/types/src/jobs/mail.d.ts +67 -0
  99. package/types/src/jobs/report.d.ts +56 -0
  100. package/types/src/jobs/runner.d.ts +145 -0
  101. package/types/src/jobs/schedule.d.ts +15 -0
  102. package/types/src/jobs/scrub.d.ts +12 -0
  103. package/types/src/jobs/types.d.ts +92 -0
  104. package/types/src/react/caller.d.ts +30 -0
  105. package/types/src/react/errors.d.ts +40 -0
  106. package/types/src/react/hooks.d.ts +110 -0
  107. package/types/src/react/index.d.ts +5 -0
  108. package/types/src/react/provider.d.ts +58 -0
  109. package/types/src/react/store.d.ts +68 -0
  110. package/types/src/react/testing.d.ts +28 -0
  111. package/types/src/react/types.d.ts +33 -0
  112. package/types/src/rpc/builder.d.ts +52 -0
  113. package/types/src/rpc/contract.d.ts +23 -0
  114. package/types/src/rpc/dispatcher.d.ts +11 -0
  115. package/types/src/rpc/types.d.ts +62 -0
  116. package/types/src/service/define.d.ts +42 -0
  117. package/types/src/service/index.d.ts +3 -0
  118. package/types/src/service/serve.d.ts +28 -0
  119. package/types/src/standard-schema.d.ts +55 -0
  120. package/types/src/testing/caller.d.ts +95 -0
  121. package/types/src/testing/challenge.d.ts +11 -0
  122. package/types/src/testing/dev.d.ts +97 -0
  123. package/types/src/testing/endpoint-access.d.ts +99 -0
  124. package/types/src/testing/index.d.ts +12 -0
  125. package/types/src/testing/isolation.d.ts +3 -0
  126. package/types/src/testing/kit.d.ts +182 -0
  127. package/types/src/testing/membership.d.ts +132 -0
  128. package/types/src/testing/policy-isolation.d.ts +113 -0
  129. package/types/src/testing/preload.d.ts +1 -0
  130. package/types/src/testing/proxy.d.ts +40 -0
  131. package/types/src/testing/runner.d.ts +8 -0
  132. package/types/src/testing/sample-file.d.ts +5 -0
  133. package/types/src/testing/status.d.ts +4 -0
  134. package/types/src/undumpable.d.ts +5 -0
@@ -0,0 +1,359 @@
1
+ import type { BuiltinRoleKey, ChallengeProvider, Locale, MailTemplates, RpcCaller, WebhookScheme } from '@fabrika/auth-core';
2
+ import type { z } from 'zod/v4';
3
+ import { type CronDeclaration, type CspDeclaration, type ExportAccessDeclaration, type ExportDeclaration, type FileKindDeclaration, type HealthMountDeclaration, type ImportDeclaration, type LinkAccessDeclaration, type LinkMountDeclaration, type ProcedureDeclaration, type ProcedureTreeDeclaration, type ProcedureType, type RpcMountDeclaration, type SpaAccessDeclaration, type SpaMountDeclaration, type WebhookMountDeclaration } from './declaration';
4
+ import type { TokenPurposes } from './token';
5
+ export type Path = `/${string}`;
6
+ /** A job attempt's time limit: 15 minutes by default, at most a day. A job reads no body, so it has no `maxBytes`. */
7
+ export interface JobLimitsOption {
8
+ readonly timeoutMs?: number;
9
+ }
10
+ /** Any zod 4 schema. `compileContract` refuses every form outside the contract subset. */
11
+ export type Schema = z.core.$ZodType;
12
+ /**
13
+ * An input object. zod 4's types do not tell `z.object` from `z.strictObject`, so the type refuses only loose
14
+ * objects; `compileContract` and `@fabrika/check` refuse `z.object` too.
15
+ */
16
+ export type InputSchema = z.ZodObject<z.core.$ZodShape, z.core.$ZodObjectConfig>;
17
+ type LooseMessage = 'a loose object admits undeclared keys: declare it with z.strictObject({ … })';
18
+ /** `S`, unless it is an object that admits undeclared keys (`.loose()`, `.passthrough()`, `.catchall()`). */
19
+ export type NotLoose<S> = S extends z.ZodObject<z.core.$ZodShape, infer Config extends z.core.$ZodObjectConfig> ? string extends keyof Config['out'] ? LooseMessage : S : S;
20
+ /** Fields a builder sets itself: an options object that carries one does not type-check. */
21
+ type Owned<K extends string> = {
22
+ readonly [P in K]?: never;
23
+ };
24
+ export type WildcardMessage = 'an action is exact: a role grants listed actions, and * is not an action';
25
+ /** What a vocabulary's role of a reserved name must be instead: the refusal, at the role's own line. */
26
+ export type ReservedRoleMessage = `${BuiltinRoleKey} is a role IAM defines itself for every application (reserved: ${BuiltinRoleKey}): choose another name`;
27
+ /** A vocabulary's roles: each a `RoleDef`, and none of a name IAM reserves. */
28
+ export type RoleDefs<A extends string, D extends string, R extends string> = {
29
+ readonly [K in R]: RoleDef<A, D, NoInfer<R>>;
30
+ } & (string extends R ? unknown : {
31
+ readonly [K in NoInfer<R> & BuiltinRoleKey]: ReservedRoleMessage;
32
+ });
33
+ export interface DimensionDef<A extends string, D extends string, R extends string> {
34
+ /** Containment: every value of this dimension lies in exactly one value of `in`. */
35
+ readonly in?: D;
36
+ /** `creates: <dimension>` mints a value and grants the caller this role in it. */
37
+ readonly creator?: R;
38
+ /** The action that manages the dimension's members, and the one that lists them. */
39
+ readonly members?: {
40
+ readonly manage: A;
41
+ readonly list: A;
42
+ };
43
+ /**
44
+ * `'labels'`: `ctx.members.list()` of a `members.list` endpoint also answers each member's label, for a people
45
+ * picker. A user's label spells its address, so this widens what members see of each other: a reviewed declaration.
46
+ */
47
+ readonly directory?: 'labels';
48
+ }
49
+ export interface RoleDef<A extends string, D extends string, R extends string> {
50
+ /** Exact actions only: `'*'` and `'notes.*'` are not actions of this contract. */
51
+ readonly grants: readonly A[];
52
+ /**
53
+ * A membership role, granted in one value of `scope`. `assignableBy` names who may assign it there: a holder of one
54
+ * of its membership roles of `scope` in that value, or of an application-wide role (one with no `member`) globally.
55
+ */
56
+ readonly member?: {
57
+ readonly scope: D;
58
+ readonly assignableBy: readonly R[];
59
+ };
60
+ /**
61
+ * An external principal, a person from outside the organization, may hold this membership role (ADR-0051). Absent,
62
+ * only internal people hold it. Only a role with `member` may declare it; an internal person may hold it too.
63
+ */
64
+ readonly external?: true;
65
+ }
66
+ export interface Vocabulary<A extends string, D extends string, R extends string> extends Presentation, AppPeople<A> {
67
+ readonly app: string;
68
+ readonly dimensions: {
69
+ readonly [K in D]: DimensionDef<A, D, R>;
70
+ };
71
+ readonly actions: {
72
+ readonly [K in A]: string;
73
+ };
74
+ readonly roles: {
75
+ readonly [K in R]: RoleDef<A, D, R>;
76
+ };
77
+ }
78
+ /** The actions that manage and list the application's own people. */
79
+ export interface AppMembers<A extends string> {
80
+ readonly manage: A;
81
+ readonly list: A;
82
+ }
83
+ /**
84
+ * The application's own people: every holder of one of its roles, globally or in a value. A holder of `members.manage`,
85
+ * globally, grants and revokes the application's global roles in IAM's console within its own actions; an `app: true`
86
+ * endpoint whose action is `members.list` reads them (`ctx.members.list()`).
87
+ */
88
+ export interface AppPeople<A extends string> {
89
+ readonly members?: AppMembers<A>;
90
+ /** `'labels'`: the directory also answers each person's label to a `members.list` holder. A reviewed declaration. */
91
+ readonly directory?: 'labels';
92
+ }
93
+ /** A vocabulary's people fields, copied one by one: each exists only when declared. */
94
+ export declare function peopleOf<A extends string>(vocabulary: AppPeople<A>): AppPeople<A>;
95
+ /** How IAM names the application to a person: on its sign-in, password and invitation pages, and in its e-mails. */
96
+ export interface Presentation {
97
+ /** The language of those pages and e-mails; absent, the installation's default. */
98
+ readonly locale?: Locale;
99
+ /** The application's name there, plain text of one short line; absent, a wording without a name. */
100
+ readonly displayName?: string;
101
+ /** The application's subject and text of IAM's e-mails, by message and language; absent, IAM's own wording. */
102
+ readonly mail?: MailTemplates;
103
+ }
104
+ /** A vocabulary's presentation fields, copied one by one: each exists only when declared. */
105
+ export declare function presentationOf(vocabulary: Presentation): Presentation;
106
+ /**
107
+ * Top-level dimensions that declare a `creator` role; only they can be the target of `creates`. IAM creates a value
108
+ * with no container (`createScope`); a contained value is a row its container's members insert.
109
+ */
110
+ export type CreatableDimension<Dims> = {
111
+ [K in keyof Dims]: Dims[K] extends {
112
+ readonly creator: string;
113
+ } ? Dims[K] extends {
114
+ readonly in: string;
115
+ } ? never : K : never;
116
+ }[keyof Dims] & string;
117
+ export interface MemberAccess {
118
+ readonly member: true;
119
+ }
120
+ export interface OverAccess<A extends string, D extends string> {
121
+ readonly action: A;
122
+ readonly over: D;
123
+ }
124
+ export interface InAccess<A extends string, D extends string, F extends string> {
125
+ readonly action: A;
126
+ readonly in: D;
127
+ readonly from: F;
128
+ }
129
+ export interface OnAccess<A extends string, D extends string, F extends string> {
130
+ readonly action: A;
131
+ readonly on: D;
132
+ readonly from: F;
133
+ }
134
+ export interface CreatesAccess<A extends string, D extends string> {
135
+ readonly action: A;
136
+ readonly creates: D;
137
+ }
138
+ /** The action held as a global grant: data of the whole application (`ctx.db.app`). */
139
+ export interface AppAccess<A extends string> {
140
+ readonly action: A;
141
+ readonly app: true;
142
+ }
143
+ export interface LinkAccess<A extends string> {
144
+ readonly action: A;
145
+ }
146
+ /**
147
+ * Anyone opens it, with no session: an SPA whose page reaches only the anonymous endpoints, or a procedure whose
148
+ * handler runs as its own workload, holding the `actions` declared beside it.
149
+ */
150
+ export interface PublicAccess {
151
+ readonly public: true;
152
+ }
153
+ /** Without an `input`, TS infers `I` as its whole constraint, not the `null` default; both mean "no input". */
154
+ export type InputOf<I> = [I] extends [InputSchema] ? z.output<I> : Record<never, never>;
155
+ /** Input fields of string type: the only fields a scope value can be read from. */
156
+ export type StringField<In> = {
157
+ [K in keyof In]-?: In[K] extends string ? K : never;
158
+ }[keyof In] & string;
159
+ /** One of several capabilities: an action listed over a dimension, or held on or in the value an input field names. */
160
+ export type CapabilityAccess<A extends string, D extends string, In> = OverAccess<A, D> | InAccess<A, D, StringField<In>> | OnAccess<A, D, StringField<In>>;
161
+ /**
162
+ * Several capabilities, by the name the handler reads each under (`ctx.capabilities.<name>`): an operation that reads
163
+ * one dimension and writes another holds both, each checked and minted as its own access form would be.
164
+ */
165
+ export interface CapabilitiesAccess<C> {
166
+ readonly capabilities: C;
167
+ }
168
+ export type QueryAccess<A extends string, D extends string, In> = MemberAccess | OverAccess<A, D> | InAccess<A, D, StringField<In>> | OnAccess<A, D, StringField<In>> | AppAccess<A> | CapabilitiesAccess<{
169
+ readonly [name: string]: CapabilityAccess<A, D, In>;
170
+ }>;
171
+ export type MutationAccess<A extends string, D extends string, CD extends string, In> = QueryAccess<A, D, In> | CreatesAccess<A, CD>;
172
+ export interface Procedure<T extends ProcedureType, I extends InputSchema | null, O extends Schema, Acc> extends ProcedureDeclaration<Schema, Acc> {
173
+ readonly type: T;
174
+ readonly input: I | null;
175
+ readonly output: O;
176
+ }
177
+ export type ProcedureTree = ProcedureTreeDeclaration<Schema>;
178
+ export type LinkProcedureTree = ProcedureTreeDeclaration<Schema, LinkAccessDeclaration>;
179
+ /** Exports serve queries only: a read-only context, so retrying one is safe. */
180
+ export interface QueryTree {
181
+ readonly [name: string]: (ProcedureDeclaration<Schema, ExportAccessDeclaration> & {
182
+ readonly type: 'query';
183
+ }) | QueryTree;
184
+ }
185
+ export interface ProcedureDef<I, O, Acc> extends Owned<'~kind' | 'type'> {
186
+ readonly input?: I & NotLoose<I>;
187
+ readonly output: O & NotLoose<O>;
188
+ readonly access: Acc;
189
+ }
190
+ /** `C` names the callers of its credentialed procedures; `readonly []` when every procedure is public. */
191
+ export interface RpcMount<C extends readonly RpcCaller[], T extends ProcedureTree> extends RpcMountDeclaration<Schema> {
192
+ readonly callers: C;
193
+ readonly procedures: T;
194
+ }
195
+ export interface LinkMount<D extends string, G extends string, IB extends string, T extends LinkProcedureTree> extends LinkMountDeclaration<Schema> {
196
+ readonly dimension: D;
197
+ readonly grants: readonly G[];
198
+ readonly issuedBy: IB;
199
+ readonly procedures: T;
200
+ }
201
+ export interface SpaMount<Acc extends SpaAccessDeclaration> extends SpaMountDeclaration {
202
+ readonly access: Acc;
203
+ }
204
+ export type HealthMount = HealthMountDeclaration;
205
+ export interface WebhookMount<B extends string, Acts extends string, I extends Schema> extends WebhookMountDeclaration<Schema> {
206
+ readonly boundTo: B;
207
+ readonly actions: readonly Acts[];
208
+ readonly input: I;
209
+ }
210
+ /** A file kind `c.files({ types, maxBytes, scan? })` declares: what a file column of that kind holds. */
211
+ export interface FileKind extends FileKindDeclaration {
212
+ }
213
+ export interface CronJob<Acts extends string> extends CronDeclaration {
214
+ readonly actions: readonly Acts[];
215
+ }
216
+ export interface Export<T extends QueryTree> extends ExportDeclaration<Schema> {
217
+ readonly procedures: T;
218
+ }
219
+ export type AnyMount = RpcMount<readonly RpcCaller[], ProcedureTree> | LinkMount<string, string, string, LinkProcedureTree> | SpaMount<SpaAccessDeclaration> | HealthMount | WebhookMount<string, string, Schema>;
220
+ /** What the callback of `defineContract` returns: mounts by name, and the sections `SURFACE_SECTIONS` names. */
221
+ export interface SurfaceSections {
222
+ readonly files?: {
223
+ readonly [name: string]: FileKind;
224
+ };
225
+ readonly jobs?: {
226
+ readonly [name: string]: CronJob<string>;
227
+ };
228
+ readonly exports?: {
229
+ readonly [name: string]: Export<QueryTree>;
230
+ };
231
+ readonly imports?: {
232
+ readonly [name: string]: ImportDeclaration;
233
+ };
234
+ readonly csp?: CspDeclaration;
235
+ /** The token purposes; a kit contract takes them from `defineApp`'s options. */
236
+ readonly tokens?: TokenPurposes;
237
+ }
238
+ export interface Surface extends SurfaceSections {
239
+ readonly [name: string]: AnyMount | SurfaceSections[keyof SurfaceSections];
240
+ }
241
+ /** A public procedure's challenge, by provider: Turnstile, verified at Cloudflare, or ALTCHA, which the application issues and verifies. */
242
+ export type ChallengeOption = TurnstileChallengeOption | AltchaChallengeOption;
243
+ interface ChallengeOptionBase {
244
+ readonly provider: ChallengeProvider;
245
+ /** The application variable that holds the provider's secret (Turnstile's) or the HMAC key (ALTCHA's): a name, never the value. */
246
+ readonly secret: string;
247
+ /**
248
+ * The widget's `action`, which the verification expects back: at most 32 letters, digits, `_` and `-`. The endpoint id
249
+ * with `_` for `.` by default (`api_visitors_register`).
250
+ */
251
+ readonly action?: string;
252
+ }
253
+ export interface TurnstileChallengeOption extends ChallengeOptionBase {
254
+ readonly provider: 'turnstile';
255
+ /** Served by every SPA mount at `<prefix>/__fabrika-config.json`, so the page renders the widget with it. */
256
+ readonly siteKey?: string;
257
+ }
258
+ /** The page fetches its challenge from `GET /__fabrika/challenge/<action>` (`challengeUrl` of `@fabrika/app/client`). */
259
+ export interface AltchaChallengeOption extends ChallengeOptionBase {
260
+ readonly provider: 'altcha';
261
+ /**
262
+ * The PBKDF2 iterations of one attempt, 1000 to 18000; 5000 by default. A browser makes up to 10000 attempts, about
263
+ * 5000 on average, and the build refuses a cost a slow phone would not solve within 90 s or half of `maxAgeMs`.
264
+ */
265
+ readonly cost?: number;
266
+ /** How long a challenge may be solved and submitted, in ms, 60 s to an hour; ten minutes by default. */
267
+ readonly maxAgeMs?: number;
268
+ }
269
+ export interface LinkKit<A extends string> {
270
+ query<const Acc extends LinkAccess<A>, O extends Schema, I extends InputSchema | null = null>(def: ProcedureDef<I, O, Acc>): Procedure<'query', I, O, Acc>;
271
+ mutation<const Acc extends LinkAccess<A>, O extends Schema, I extends InputSchema | null = null>(def: ProcedureDef<I, O, Acc>): Procedure<'mutation', I, O, Acc>;
272
+ }
273
+ export interface Kit<A extends string, D extends string, CD extends string> {
274
+ query<const Acc extends QueryAccess<A, D, InputOf<I>>, O extends Schema, I extends InputSchema | null = null>(def: ProcedureDef<I, O, Acc>): Procedure<'query', I, O, Acc>;
275
+ mutation<const Acc extends MutationAccess<A, D, CD, InputOf<I>>, O extends Schema, I extends InputSchema | null = null>(def: ProcedureDef<I, O, Acc>): Procedure<'mutation', I, O, Acc>;
276
+ /** Procedures served at `POST <prefix>/<name>`, to the callers named once here. There is no public caller. */
277
+ rpc<const C extends readonly [RpcCaller, ...RpcCaller[]], const T extends ProcedureTree>(prefix: Path, options: {
278
+ readonly callers: C;
279
+ } & Owned<'kind' | 'prefix' | 'procedures'>, procedures: T): RpcMount<C, T>;
280
+ /** A share SPA under `prefix` and its procedures under `<prefix>/api`, for an anonymous key bound to one object. */
281
+ link<const LD extends D, const G extends readonly [A, ...A[]], const IB extends A, const T extends LinkProcedureTree>(prefix: Path, options: {
282
+ readonly spa: string;
283
+ readonly dimension: LD;
284
+ readonly grants: G;
285
+ readonly issuedBy: IB;
286
+ readonly maxDays: number;
287
+ readonly procedures: (l: LinkKit<G[number]>) => T;
288
+ } & Owned<'kind' | 'prefix'>): LinkMount<LD, G[number], IB, T>;
289
+ /** The SPA under `prefix`: for signed-in people, or for anyone with `access: { public: true }`. */
290
+ spa<const Acc extends MemberAccess | OverAccess<A, D> | AppAccess<A> | PublicAccess>(prefix: Path, options: {
291
+ readonly dir: string;
292
+ readonly access: Acc;
293
+ /** Application variables whose values the pages read from `<prefix>/__fabrika-config.json`: public values only. */
294
+ readonly browserConfig?: readonly [string, ...string[]];
295
+ } & Owned<'kind' | 'prefix'>): SpaMount<Acc>;
296
+ health(path: Path): HealthMount;
297
+ webhook<const B extends D | 'app', const Acts extends readonly [A, ...A[]], I extends InputSchema>(path: Path, options: {
298
+ readonly scheme: WebhookScheme;
299
+ readonly boundTo: B;
300
+ readonly actions: Acts;
301
+ readonly input: I & NotLoose<I>;
302
+ /** A delivery's body (1 MiB by default and at most) and its handler's time (10 s by default, at most 60 s). */
303
+ readonly limits?: {
304
+ readonly maxBytes?: number;
305
+ readonly timeoutMs?: number;
306
+ };
307
+ } & Owned<'kind' | 'path'>): WebhookMount<B, Acts[number], I>;
308
+ /**
309
+ * A file kind: the media types its files may be, the largest one, and whether each waits for a clean scan. A table's
310
+ * file column holds files of it (`files: { <column>: '<kind>' }`), and the table's actions are their authority.
311
+ */
312
+ files(kind: {
313
+ readonly types: readonly [string, ...string[]];
314
+ readonly maxBytes: number;
315
+ /** Each file is scanned for malware and served only after a clean verdict; until then it answers 409. */
316
+ readonly scan?: boolean;
317
+ } & Owned<'kind'>): FileKind;
318
+ /** A job of the whole application, holding `actions`; it runs on its schedule (UTC, five fields) and when kicked. */
319
+ cron<const Acts extends readonly [A, ...A[]]>(schedule: string, options: {
320
+ readonly actions: Acts;
321
+ readonly limits?: JobLimitsOption;
322
+ readonly retries?: number;
323
+ } & Owned<'kind' | 'schedule'>): CronJob<Acts[number]>;
324
+ export<const T extends QueryTree>(definition: {
325
+ readonly version: number;
326
+ readonly consumers: readonly [string, ...string[]];
327
+ readonly audience: 'any consumer user';
328
+ readonly procedures: T;
329
+ } & Owned<'kind'>): Export<T>;
330
+ }
331
+ export interface Contract<A extends string, D extends string, R extends string, Dims, S extends Surface> {
332
+ readonly vocabulary: Vocabulary<A, D, R>;
333
+ /** The dimension definitions as written, with their literal actions and roles, for the types only. */
334
+ readonly dimensions: Dims;
335
+ readonly surface: S;
336
+ }
337
+ export type AnyContract = Contract<string, string, string, unknown, Surface>;
338
+ export type ActionOf<C> = C extends Contract<infer A, string, string, unknown, Surface> ? A : never;
339
+ export type DimensionOf<C> = C extends Contract<string, infer D, string, unknown, Surface> ? D : never;
340
+ export type RoleOf<C> = C extends Contract<string, string, infer R, unknown, Surface> ? R : never;
341
+ /** The builders `defineContract` hands its callback; the staged kit's contract reuses its mounts that take no handler. */
342
+ export declare function surfaceKit<A extends string, D extends string, CD extends string>(): Kit<A, D, CD>;
343
+ /**
344
+ * Declares the contract: the authorization vocabulary, then the surface built from `c` — mounts by name, and the
345
+ * `files`, `jobs`, `exports`, `imports` and `csp` sections. The contract is a literal (`@fabrika/check`).
346
+ */
347
+ export declare function defineContract<const A extends string, const D extends string, const R extends string, const Dims extends {
348
+ readonly [K in D]: DimensionDef<NoInfer<A>, NoInfer<D>, NoInfer<R>>;
349
+ }, const S extends Surface>(vocabulary: Presentation & AppPeople<NoInfer<A>> & {
350
+ readonly app: string;
351
+ readonly dimensions: Dims & {
352
+ readonly [K in D]: DimensionDef<NoInfer<A>, NoInfer<D>, NoInfer<R>>;
353
+ };
354
+ readonly actions: {
355
+ readonly [K in A]: K extends `${string}*${string}` ? WildcardMessage : string;
356
+ };
357
+ readonly roles: RoleDefs<NoInfer<A>, NoInfer<D>, R>;
358
+ }, surface: (c: Kit<A, D, CreatableDimension<Dims>>) => S): Contract<A, D, R, Dims, S>;
359
+ export {};
@@ -0,0 +1,44 @@
1
+ import { z } from 'zod/v4';
2
+ import type { Schema } from './define';
3
+ declare const FILE: unique symbol;
4
+ /** A stored file's states: written, waiting for a scan, served, or refused by the scan. */
5
+ export type FileStatus = 'pending' | 'quarantined' | 'live' | 'rejected';
6
+ /**
7
+ * What a handler holds of a stored file: its metadata, never its bytes. A file column read through `ctx.db`, an input
8
+ * file and `ctx.files.put` answer one; only one this request holds is written into a column, served or opened.
9
+ */
10
+ export interface FileRef {
11
+ readonly id: string;
12
+ readonly name: string | null;
13
+ readonly type: string;
14
+ readonly size: number;
15
+ readonly status: FileStatus;
16
+ }
17
+ /** What `file()` adds to its schema: the kind of file it holds. */
18
+ export interface FileMark {
19
+ readonly kind: string;
20
+ }
21
+ /** A file field or output of kind `K`. */
22
+ export type FileSchema<K extends string = string> = z.ZodType<FileRef, FileRef> & FileBrand<K>;
23
+ /** What tells a file schema from a JSON one in the types. */
24
+ export interface FileBrand<K extends string> {
25
+ readonly [FILE]: FileMark & {
26
+ readonly '~kind'?: K;
27
+ };
28
+ }
29
+ /**
30
+ * A file of kind `kind` (`c.files({ … })` of the contract): an input field (top level, `z.optional`, or `z.array(…).max(n)`)
31
+ * or a procedure's output. `compileContract` and the checker refuse it anywhere else.
32
+ */
33
+ export declare function file<const K extends string>(kind: K): FileSchema<K>;
34
+ /** The mark of a `file()` schema, or `null` for any other schema. */
35
+ export declare function fileOf(schema: Schema | z.core.$ZodType): FileMark | null;
36
+ type ClientValue<V> = V extends FileRef ? Blob : V extends readonly FileRef[] ? readonly Blob[] : V;
37
+ /**
38
+ * An input as a client sends it: each file field takes the `Blob` (or `File`) the page holds, which the client sends as
39
+ * a part of its own. An input without a file field is the input itself.
40
+ */
41
+ export type ClientInput<T> = [Extract<T[keyof T], FileRef | readonly FileRef[]>] extends [never] ? T : {
42
+ [K in keyof T]: ClientValue<T[K]>;
43
+ };
44
+ export {};