@fabrika/app 0.3.2 → 0.4.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.
- package/README.md +78 -90
- package/package.json +68 -6
- package/skill/SKILL.md +319 -0
- package/skill/references/app-setup.md +364 -0
- package/skill/references/dev.md +67 -0
- package/skill/references/endpoint.md +627 -0
- package/skill/references/errors.md +108 -0
- package/skill/references/files.md +335 -0
- package/skill/references/jobs.md +169 -0
- package/skill/references/public-intake.md +1495 -0
- package/skill/references/spa.md +741 -0
- package/skill/references/start.md +179 -0
- package/skill/references/table-and-migration.md +264 -0
- package/skill/references/tests.md +305 -0
- package/skill/references/webhooks-links-connectors.md +190 -0
- package/src/agent-skill.ts +77 -0
- package/src/build.ts +53 -0
- package/src/bun.ts +302 -3
- package/src/client/caller.ts +24 -0
- package/src/client/contract.ts +309 -0
- package/src/client/files.ts +135 -0
- package/src/client/index.ts +19 -0
- package/src/client/rpc.ts +47 -0
- package/src/client/share.ts +14 -0
- package/src/{client.ts → client/transport.ts} +58 -61
- package/src/cloudflare.ts +139 -3
- package/src/contract/artifact-schema.ts +317 -0
- package/src/contract/attachment.ts +74 -0
- package/src/contract/build.ts +1936 -0
- package/src/contract/compile.ts +143 -0
- package/src/contract/connect.ts +170 -0
- package/src/contract/context.ts +437 -0
- package/src/contract/declaration.ts +310 -0
- package/src/contract/defaults.ts +156 -0
- package/src/contract/define.ts +567 -0
- package/src/contract/file-schemas.ts +25 -0
- package/src/contract/group.ts +263 -0
- package/src/contract/handled.ts +50 -0
- package/src/contract/index.ts +34 -0
- package/src/contract/kit.ts +607 -0
- package/src/contract/platform.ts +113 -0
- package/src/contract/problems.ts +30 -0
- package/src/contract/schema-from-shape.ts +152 -0
- package/src/contract/schema-shape.ts +407 -0
- package/src/contract/snapshot-source.ts +168 -0
- package/src/contract/vocabulary.ts +50 -0
- package/src/disk-assets.ts +25 -0
- package/src/fetch.ts +10 -0
- package/src/files/archive.ts +292 -0
- package/src/files/clamscan.ts +253 -0
- package/src/files/collections.ts +669 -0
- package/src/files/handle.ts +77 -0
- package/src/files/scan.ts +308 -0
- package/src/files/sniff.ts +70 -0
- package/src/files/treatment.ts +48 -0
- package/src/from-row.ts +53 -0
- package/src/implement/anonymous.ts +102 -0
- package/src/implement/attachment.ts +143 -0
- package/src/implement/boot.ts +808 -0
- package/src/implement/bounded.ts +72 -0
- package/src/implement/browser-config.ts +54 -0
- package/src/implement/capability.ts +439 -0
- package/src/implement/challenge.ts +115 -0
- package/src/implement/connect.ts +386 -0
- package/src/implement/dispatch.ts +1085 -0
- package/src/implement/environment.ts +47 -0
- package/src/implement/failures.ts +116 -0
- package/src/implement/faults.ts +46 -0
- package/src/implement/form-admission.ts +120 -0
- package/src/implement/headers.ts +17 -0
- package/src/implement/implement.ts +81 -0
- package/src/implement/index.ts +60 -0
- package/src/implement/invocation.ts +346 -0
- package/src/implement/membership.ts +485 -0
- package/src/implement/principal.ts +99 -0
- package/src/implement/project.ts +76 -0
- package/src/implement/serve.ts +142 -0
- package/src/implement/types.ts +215 -0
- package/src/implement/webhook.ts +108 -0
- package/src/implement/workload.ts +160 -0
- package/src/implement/xlsx.ts +275 -0
- package/src/index.ts +12 -13
- package/src/jobs/report.ts +134 -0
- package/src/jobs/runner.ts +749 -0
- package/src/jobs/schedule.ts +129 -0
- package/src/jobs/types.ts +44 -0
- package/src/react/caller.tsx +60 -0
- package/src/react/errors.ts +82 -0
- package/src/react/hooks.ts +239 -0
- package/src/react/index.ts +31 -0
- package/src/react/provider.tsx +165 -0
- package/src/react/store.ts +215 -0
- package/src/react/types.ts +40 -0
- package/src/rpc/dispatcher.ts +4 -19
- package/src/service/define.ts +121 -0
- package/src/service/index.ts +21 -0
- package/src/service/serve.ts +99 -0
- package/src/testing/caller.ts +123 -0
- package/src/testing/dev.ts +73 -0
- package/src/testing/endpoint-access.ts +806 -0
- package/src/testing/index.ts +23 -0
- package/src/testing/isolation.ts +25 -0
- package/src/testing/kit.ts +552 -0
- package/src/testing/membership.ts +747 -0
- package/src/testing/policy-isolation.ts +827 -0
- package/src/testing/preload.ts +6 -0
- package/src/testing/proxy.ts +87 -0
- package/src/testing/runner.ts +61 -0
- package/src/testing/status.ts +19 -0
- package/src/undumpable.ts +42 -0
- package/src/app.ts +0 -76
- package/src/middleware.ts +0 -38
- package/src/router.ts +0 -149
- package/src/testing.ts +0 -119
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
// The builders a group, a link mount and an export hand their callback: each declares one endpoint and takes its
|
|
2
|
+
// handler with `.handle(fn)` beside it. `.handle` returns the declaration without the handler's type, so a contract
|
|
3
|
+
// of many endpoints stays cheap to type-check, and an endpoint without `.handle` is not a group member.
|
|
4
|
+
|
|
5
|
+
import type { RpcCaller } from '@fabrika/auth-core'
|
|
6
|
+
import type { AnyDbIndex, ReadOnlyUnscoped, Unavailable, UnscopedDeclaration, UnscopedMode } from '@fabrika/db/tables'
|
|
7
|
+
import type { z } from 'zod/v4'
|
|
8
|
+
import type { Snake } from '../from-row'
|
|
9
|
+
import type { ExtraKeys, HandlerInput, IsAny } from '../implement/types'
|
|
10
|
+
import type { AttachmentBrand } from './attachment'
|
|
11
|
+
import type { CheckedAccess, Declared, EndpointContext, ExportContext, ImportOf, KitTypes, LinkContext, SqlMode } from './context'
|
|
12
|
+
import type { ProcedureType } from './declaration'
|
|
13
|
+
import type { AppAccess, InputOf, InputSchema, LinkAccess, MemberAccess, MutationAccess, NotLoose, Procedure, QueryAccess, Schema } from './define'
|
|
14
|
+
|
|
15
|
+
/** Fields a builder sets itself: a definition that carries one does not type-check. */
|
|
16
|
+
type Owned<K extends string> = { readonly [P in K]?: never }
|
|
17
|
+
|
|
18
|
+
/** Unknown keys of an `unscoped` declaration, each refused at its own line. */
|
|
19
|
+
type ExactTables<U, Tables extends string> = [Exclude<keyof U, Tables>] extends [never] ? unknown
|
|
20
|
+
: { readonly [P in Exclude<keyof U, Tables>]: Unavailable<`${P & string} is not a table of src/db/tables.ts`> }
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The off-road fields a site declares. Each is inferred from its optional field and then required: a handle exists
|
|
24
|
+
* only for a declaration the object really carries, never for one an annotation merely allows.
|
|
25
|
+
*/
|
|
26
|
+
export type DeclaredFields<S, U, Cn, Is, Ix extends AnyDbIndex> =
|
|
27
|
+
& {
|
|
28
|
+
/** `ctx.sql`, in this mode; a query declares only `'read'`. */
|
|
29
|
+
readonly sql?: S
|
|
30
|
+
/** `ctx.db.unscoped.<table>`, each in its mode, scope predicate `true`; a query declares only `'read'`. */
|
|
31
|
+
readonly unscoped?: U
|
|
32
|
+
/** `ctx.connect.<connector>`, for the connectors the kit imports. */
|
|
33
|
+
readonly connect?: Cn
|
|
34
|
+
/** `ctx.links.issue` for this link mount, on an endpoint whose action is the mount's `issuedBy`. */
|
|
35
|
+
readonly issues?: Is
|
|
36
|
+
}
|
|
37
|
+
& ([S] extends [never] ? unknown : { readonly sql: S & NoInfer<SqlReach<keyof Ix['tables'] & string>> })
|
|
38
|
+
& ([U] extends [never] ? unknown : { readonly unscoped: U & NoInfer<ExactTables<U, keyof Ix['tables'] & string> & ReadOnlyUnscoped<Ix, U>> })
|
|
39
|
+
& ([Cn] extends [never] ? unknown : { readonly connect: Cn & NoInfer<LiteralList<Cn>> })
|
|
40
|
+
& ([Is] extends [never] ? unknown : { readonly issues: Is & NoInfer<OneLiteral<Is>> })
|
|
41
|
+
|
|
42
|
+
/** `ctx.sql` runs on `@fabrika/db`, so a kit without tables declares no `sql`. */
|
|
43
|
+
type SqlReach<Tables extends string> = [Tables] extends [never]
|
|
44
|
+
? Unavailable<'ctx.sql runs on @fabrika/db: a kit without tables (defineApp(vocabulary)) declares no sql'>
|
|
45
|
+
: unknown
|
|
46
|
+
|
|
47
|
+
/** A list typed only by its element (`readonly 'catalog'[]`) may hold none of them; the declaration is a literal tuple. */
|
|
48
|
+
type LiteralList<Cn> = Cn extends readonly unknown[]
|
|
49
|
+
? number extends Cn['length'] ? "connect names its connectors as a literal list: connect: ['catalog']"
|
|
50
|
+
: unknown
|
|
51
|
+
: unknown
|
|
52
|
+
|
|
53
|
+
/** `issues` names one link mount, as a literal. */
|
|
54
|
+
type OneLiteral<Is> = string extends Is ? Unavailable<"issues names one link mount, as a literal: issues: 'shared'">
|
|
55
|
+
: true extends IsUnion<Is> ? Unavailable<"issues names one link mount, as a literal: issues: 'shared'">
|
|
56
|
+
: unknown
|
|
57
|
+
|
|
58
|
+
type IsUnion<T, All = T> = T extends unknown ? ([All] extends [T] ? false : true) : never
|
|
59
|
+
|
|
60
|
+
/** An endpoint's declaration: its schemas, its access form and the reach it declares. */
|
|
61
|
+
export type EndpointDef<I, O, Acc, S, U, Cn, Is, Ix extends AnyDbIndex> =
|
|
62
|
+
& Owned<'~kind' | 'type'>
|
|
63
|
+
& {
|
|
64
|
+
readonly input?: I & NotLoose<I>
|
|
65
|
+
readonly output: O & NotLoose<O>
|
|
66
|
+
readonly access: Acc
|
|
67
|
+
}
|
|
68
|
+
& DeclaredFields<S, U, Cn, Is, Ix>
|
|
69
|
+
|
|
70
|
+
type Returned<F> = F extends (args: never) => infer R ? Awaited<R> : never
|
|
71
|
+
|
|
72
|
+
/** The last member of a union, in the order the compiler holds it. */
|
|
73
|
+
type LastOf<U> = (U extends unknown ? (member: () => U) => void : never) extends (member: infer I) => void ? I extends () => infer L ? L : never
|
|
74
|
+
: never
|
|
75
|
+
|
|
76
|
+
/** `'a' | 'b'` → `'a, b'`, for a message. */
|
|
77
|
+
export type ListOf<U extends string, Listed extends string = ''> = [U] extends [never] ? Listed
|
|
78
|
+
: ListOf<Exclude<U, LastOf<U>>, Listed extends '' ? LastOf<U> & string : `${LastOf<U> & string}, ${Listed}`>
|
|
79
|
+
|
|
80
|
+
/** The fields, at any depth, that a handler `F` returns and the output `O` does not declare. */
|
|
81
|
+
export type UndeclaredFields<F, O extends Schema> = ExtraKeys<Returned<F>, z.input<O>>
|
|
82
|
+
|
|
83
|
+
/** An object with a camelCase field, which a database row names in snake_case. */
|
|
84
|
+
type HasCamel<V> = { [K in keyof V]: K extends string ? (Snake<K> extends K ? never : K) : never }[keyof V]
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* A database row returned where the output declares camelCase fields: its snake_case columns, of any value, at the
|
|
88
|
+
* depth the output has them. `.handle` admits it so that `ExactReturn` can name `fromRow` in one line.
|
|
89
|
+
*/
|
|
90
|
+
type RowShaped<V> = V extends readonly (infer Item)[] ? readonly RowShaped<Item>[]
|
|
91
|
+
: V extends object
|
|
92
|
+
? [HasCamel<V>] extends [never] ? { readonly [K in keyof V]: RowShaped<V[K]> } : { readonly [K in keyof V as Snake<K & string>]: unknown }
|
|
93
|
+
: V
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* What a kit handler `F` may return: the output, or — only when `F` returns one — a database row of it, which
|
|
97
|
+
* `ExactReturn` refuses with the fix, as it refuses anything but rows from an attachment's handler. Any other mistake
|
|
98
|
+
* keeps the compiler's own message about the output.
|
|
99
|
+
*/
|
|
100
|
+
export type HandlerReturn<F, O extends Schema> = [Returned<F>] extends [z.input<O>] ? z.input<O>
|
|
101
|
+
: [O] extends [AttachmentBrand] ? unknown
|
|
102
|
+
: [Returned<F>] extends [RowShaped<z.input<O>>] ? RowShaped<z.input<O>>
|
|
103
|
+
: z.input<O>
|
|
104
|
+
|
|
105
|
+
/** A kit endpoint's handler, returning `R`. */
|
|
106
|
+
export type KitHandler<In, Ctx, R> = (args: { readonly input: In; readonly ctx: Ctx }) => R | Promise<R>
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* What `.handle` answers: the endpoint, or a message the group refuses at the endpoint's line — when the handler
|
|
110
|
+
* returns a database row where the output is camelCase, anything but rows for an attachment, or, at any depth, a
|
|
111
|
+
* field the output does not declare. A field whose type is an error elsewhere in the handler is not reported again here.
|
|
112
|
+
*/
|
|
113
|
+
export type ExactReturn<F, O extends Schema, E> = [Returned<F>] extends [z.input<O>] ? [UndeclaredFields<F, O>] extends [never] ? E
|
|
114
|
+
: IsAny<UndeclaredFields<F, O>> extends true ? E
|
|
115
|
+
: Unavailable<`the handler returns ${ListOf<UndeclaredFields<F, O> & string>}, which the output does not declare: return only declared fields`>
|
|
116
|
+
: [O] extends [AttachmentBrand] ? Unavailable<'an attachment handler returns its rows: an array of its row schema, with nothing around it'>
|
|
117
|
+
: Unavailable<
|
|
118
|
+
`the handler returns a database row (${ListOf<
|
|
119
|
+
UndeclaredFields<F, O> & string
|
|
120
|
+
>}) where the output is camelCase: map it with fromRow(Schema, row) from @fabrika/app`
|
|
121
|
+
>
|
|
122
|
+
|
|
123
|
+
/** A declared, handled endpoint: what a group holds. Its type keeps the declaration and drops the handler's. */
|
|
124
|
+
export interface Endpoint<T extends ProcedureType, I extends InputSchema | null, O extends Schema, Acc, D> extends Procedure<T, I, O, Acc> {
|
|
125
|
+
readonly declared: D
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** An endpoint before `.handle`: a group refuses it. */
|
|
129
|
+
export interface EndpointBuilder<T extends ProcedureType, I extends InputSchema | null, O extends Schema, Acc, D, Ctx> extends PendingEndpoint {
|
|
130
|
+
/** The endpoint's handler, typed by its access form and declaration; it may return only the output's fields. */
|
|
131
|
+
handle<const F extends KitHandler<HandlerInput<I, Acc>, Ctx, HandlerReturn<F, O>>>(handler: F): ExactReturn<F, O, Endpoint<T, I, O, Acc, D>>
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** What every endpoint builder has and no handled endpoint has. */
|
|
135
|
+
export interface PendingEndpoint {
|
|
136
|
+
handle(handler: never): unknown
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** The builders of a group's callback: they know the group's callers, so a handler knows its principal. */
|
|
140
|
+
export interface GroupKit<K extends KitTypes, Caller extends RpcCaller> {
|
|
141
|
+
query<
|
|
142
|
+
const Acc extends QueryAccess<K['action'], K['dimension'], InputOf<I>>,
|
|
143
|
+
O extends Schema,
|
|
144
|
+
I extends InputSchema | null = null,
|
|
145
|
+
const S extends 'read' = never,
|
|
146
|
+
const U extends UnscopedDeclaration<K['tables'], 'read'> = never,
|
|
147
|
+
const Cn extends readonly ImportOf<K>[] = never,
|
|
148
|
+
const Is extends string = never,
|
|
149
|
+
>(
|
|
150
|
+
def: EndpointDef<I, O, Acc, S, U, Cn, Is, K['index']>,
|
|
151
|
+
): EndpointBuilder<
|
|
152
|
+
'query',
|
|
153
|
+
I,
|
|
154
|
+
O,
|
|
155
|
+
Acc,
|
|
156
|
+
Declared<S, U, Cn, Is>,
|
|
157
|
+
EndpointContext<K, Caller, 'query', CheckedAccess<Acc>, Declared<S, U, Cn, Is>>
|
|
158
|
+
>
|
|
159
|
+
mutation<
|
|
160
|
+
const Acc extends MutationAccess<K['action'], K['dimension'], K['creatable'], InputOf<I>>,
|
|
161
|
+
O extends Schema,
|
|
162
|
+
I extends InputSchema | null = null,
|
|
163
|
+
const S extends SqlMode = never,
|
|
164
|
+
const U extends UnscopedDeclaration<K['tables'], UnscopedMode> = never,
|
|
165
|
+
const Cn extends readonly ImportOf<K>[] = never,
|
|
166
|
+
const Is extends string = never,
|
|
167
|
+
>(
|
|
168
|
+
def: EndpointDef<I, O, Acc, S, U, Cn, Is, K['index']>,
|
|
169
|
+
): EndpointBuilder<
|
|
170
|
+
'mutation',
|
|
171
|
+
I,
|
|
172
|
+
O,
|
|
173
|
+
Acc,
|
|
174
|
+
Declared<S, U, Cn, Is>,
|
|
175
|
+
EndpointContext<K, Caller, 'mutation', CheckedAccess<Acc>, Declared<S, U, Cn, Is>>
|
|
176
|
+
>
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Any handled endpoint. */
|
|
180
|
+
export type AnyEndpoint = Endpoint<ProcedureType, InputSchema | null, Schema, unknown, unknown>
|
|
181
|
+
|
|
182
|
+
/** What a group's callback returns: its endpoints by name. A mount nests groups; a group does not nest. */
|
|
183
|
+
export interface GroupTree {
|
|
184
|
+
readonly [name: string]: AnyEndpoint
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** What a group's callback may return before the group checks that every endpoint took its handler. */
|
|
188
|
+
export interface GroupInput {
|
|
189
|
+
readonly [name: string]: AnyEndpoint | PendingEndpoint
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
declare const failedBuild: unique symbol
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* The constraint `app.group` infers against. A refused callback falls back to it, and its private symbol keeps the
|
|
196
|
+
* mount from repeating that error. It is not an annotation: a group typed with it mounts unchecked.
|
|
197
|
+
*/
|
|
198
|
+
export interface GroupBuild extends GroupInput {
|
|
199
|
+
readonly [failedBuild]?: true
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* A builder without `.handle(…)`. An endpoint typed by the compiler's error type is the consequence of a type error
|
|
204
|
+
* inside its handler, reported there; every check is wrapped in a tuple, since an unwrapped one answers the error type.
|
|
205
|
+
*/
|
|
206
|
+
type IsPending<E> = [0] extends [1 & E] ? false : [Extract<E, PendingEndpoint>] extends [never] ? false : true
|
|
207
|
+
|
|
208
|
+
/** The endpoints of a group, prefixed by `Path`, that have no `.handle(…)`. */
|
|
209
|
+
export type PendingIn<T, Path extends string> = typeof failedBuild extends keyof T ? never
|
|
210
|
+
: string extends keyof T ? [IsPending<T[string & keyof T]>] extends [true] ? `${Path}* (its type admits an endpoint without a handler)` : never
|
|
211
|
+
: { [K in keyof T]: [IsPending<T[K]>] extends [true] ? `${Path}${K & string}` : never }[keyof T]
|
|
212
|
+
|
|
213
|
+
/** `app.group(…)`: endpoints for one set of callers, declared in any module and mounted by the contract. */
|
|
214
|
+
export interface Group<C extends readonly [RpcCaller, ...RpcCaller[]], T extends GroupInput> {
|
|
215
|
+
readonly '~kind': 'group'
|
|
216
|
+
readonly callers: C
|
|
217
|
+
readonly endpoints: T
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** The builders of a link mount's callback: each procedure acts on the object its key is bound to. */
|
|
221
|
+
export interface LinkGroupKit<K extends KitTypes, LD extends string, G extends string> {
|
|
222
|
+
query<
|
|
223
|
+
const Acc extends LinkAccess<G>,
|
|
224
|
+
O extends Schema,
|
|
225
|
+
I extends InputSchema | null = null,
|
|
226
|
+
const S extends 'read' = never,
|
|
227
|
+
const U extends UnscopedDeclaration<K['tables'], 'read'> = never,
|
|
228
|
+
>(
|
|
229
|
+
def: EndpointDef<I, O, Acc, S, U, never, never, K['index']>,
|
|
230
|
+
): EndpointBuilder<'query', I, O, Acc, Declared<S, U, never, never>, LinkContext<K, 'query', LD, Acc['action'], Declared<S, U, never, never>>>
|
|
231
|
+
mutation<
|
|
232
|
+
const Acc extends LinkAccess<G>,
|
|
233
|
+
O extends Schema,
|
|
234
|
+
I extends InputSchema | null = null,
|
|
235
|
+
const S extends SqlMode = never,
|
|
236
|
+
const U extends UnscopedDeclaration<K['tables'], UnscopedMode> = never,
|
|
237
|
+
>(
|
|
238
|
+
def: EndpointDef<I, O, Acc, S, U, never, never, K['index']>,
|
|
239
|
+
): EndpointBuilder<'mutation', I, O, Acc, Declared<S, U, never, never>, LinkContext<K, 'mutation', LD, Acc['action'], Declared<S, U, never, never>>>
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** An export procedure names its action and its scope; `{ member: true }` would give the consumer's key nothing to hold. */
|
|
243
|
+
export type ExportAccess<A extends string, D extends string, In> = Exclude<QueryAccess<A, D, In>, MemberAccess | AppAccess<A>>
|
|
244
|
+
|
|
245
|
+
/** The builder of an export's callback: queries only, run read-only. */
|
|
246
|
+
export interface ExportKit<K extends KitTypes> {
|
|
247
|
+
query<
|
|
248
|
+
const Acc extends ExportAccess<K['action'], K['dimension'], InputOf<I>>,
|
|
249
|
+
O extends Schema,
|
|
250
|
+
I extends InputSchema | null = null,
|
|
251
|
+
const S extends 'read' = never,
|
|
252
|
+
const U extends UnscopedDeclaration<K['tables'], 'read'> = never,
|
|
253
|
+
>(
|
|
254
|
+
def: EndpointDef<I, O, Acc, S, U, never, never, K['index']>,
|
|
255
|
+
): EndpointBuilder<
|
|
256
|
+
'query',
|
|
257
|
+
I,
|
|
258
|
+
O,
|
|
259
|
+
Acc,
|
|
260
|
+
Declared<S, U, never, never>,
|
|
261
|
+
ExportContext<K, CheckedAccess<Acc>, Declared<S, U, never, never>>
|
|
262
|
+
>
|
|
263
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// What the staged kit keeps beside a declaration, out of the declaration itself: a site's handler and a contract's
|
|
2
|
+
// vendored snapshots and whether its kit had tables. `compileContract` and the static reader see only the declaration; `serve` reads these.
|
|
3
|
+
// Browser-safe: a handler is held here, never called.
|
|
4
|
+
|
|
5
|
+
import type { ConnectSnapshot } from './connect'
|
|
6
|
+
|
|
7
|
+
const handlers = new WeakMap<object, unknown>()
|
|
8
|
+
|
|
9
|
+
/** `site` with its handler, which only `handlerOf` reads. */
|
|
10
|
+
export function withHandler<T extends object>(site: T, handler: unknown): T {
|
|
11
|
+
handlers.set(site, handler)
|
|
12
|
+
return site
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** The handler `.handle` attached to a site of the kit, or `undefined` for a site that took none. */
|
|
16
|
+
export function handlerOf(site: object): unknown {
|
|
17
|
+
return handlers.get(site)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const snapshots = new WeakMap<object, Readonly<Record<string, ConnectSnapshot>>>()
|
|
21
|
+
|
|
22
|
+
/** `contract` with the snapshots of the kit's imports, by the import's name. */
|
|
23
|
+
export function withSnapshots<T extends object>(contract: T, imported: Readonly<Record<string, ConnectSnapshot>>): T {
|
|
24
|
+
snapshots.set(contract, imported)
|
|
25
|
+
return contract
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The snapshots `app.contract` recorded for `contract`; none for a contract the kit did not build. */
|
|
29
|
+
export function snapshotsOf(contract: object): Readonly<Record<string, ConnectSnapshot>> {
|
|
30
|
+
return snapshots.get(contract) ?? {}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Which kit built a contract: one with tables, `defineApp(vocabulary, tables)`, or one without, `defineApp(vocabulary)`. */
|
|
34
|
+
export type KitOrigin = 'tables' | 'tableless'
|
|
35
|
+
|
|
36
|
+
const origins = new WeakMap<object, KitOrigin>()
|
|
37
|
+
|
|
38
|
+
/** `contract` as `app.contract` built it, with the kind of kit that built it. */
|
|
39
|
+
export function withKitOrigin<T extends object>(contract: T, origin: KitOrigin): T {
|
|
40
|
+
origins.set(contract, origin)
|
|
41
|
+
return contract
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The kind of kit that built `contract`, or `undefined` for any other object, a copy of a kit's contract included: a
|
|
46
|
+
* copy loses what is kept beside the original, so `serve` refuses it.
|
|
47
|
+
*/
|
|
48
|
+
export function kitOriginOf(contract: object): KitOrigin | undefined {
|
|
49
|
+
return origins.get(contract)
|
|
50
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// @fabrika/app/contract — the contract of an application: the staged kit (`defineVocabulary`, `defineApp`, its
|
|
2
|
+
// groups), `defineContract`, `compileContract`, the artifact parser, and the IAM schema it compiles to. Browser-safe:
|
|
3
|
+
// no server runtime, no Node or Bun API.
|
|
4
|
+
export { contractArtifactSchema, parseContractArtifact, schemaShapeSchema } from './artifact-schema'
|
|
5
|
+
export {
|
|
6
|
+
type Attachment,
|
|
7
|
+
attachment,
|
|
8
|
+
type AttachmentBrand,
|
|
9
|
+
type AttachmentMark,
|
|
10
|
+
attachmentOf,
|
|
11
|
+
type AttachmentOptions,
|
|
12
|
+
attachmentOutput,
|
|
13
|
+
} from './attachment'
|
|
14
|
+
export { buildArtifact } from './build'
|
|
15
|
+
export { compileContract, describeContract } from './compile'
|
|
16
|
+
export {
|
|
17
|
+
type ConnectSnapshot,
|
|
18
|
+
describeSnapshot,
|
|
19
|
+
exportDescription,
|
|
20
|
+
exportDescriptionSchema,
|
|
21
|
+
incompatibleChanges,
|
|
22
|
+
parseExportDescription,
|
|
23
|
+
type SnapshotProcedure,
|
|
24
|
+
} from './connect'
|
|
25
|
+
export type * from './context'
|
|
26
|
+
export * from './declaration'
|
|
27
|
+
export * from './defaults'
|
|
28
|
+
export * from './define'
|
|
29
|
+
export type * from './group'
|
|
30
|
+
export * from './kit'
|
|
31
|
+
export { schemaFromContract } from './platform'
|
|
32
|
+
export { ContractError } from './problems'
|
|
33
|
+
export { SNAPSHOT_DIRECTORY, type SnapshotNames, snapshotNames, snapshotSource } from './snapshot-source'
|
|
34
|
+
export * from './vocabulary'
|