@fabrika/app 0.9.0-dev.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.
- package/package.json +27 -26
- package/skill/SKILL.md +1 -1
- package/skill/references/app-setup.md +8 -8
- package/src/dev/changes.ts +5 -43
- package/src/dev/contract-digest.ts +17 -0
- package/src/dev/index.ts +1 -1
- package/src/dev/launcher.ts +69 -22
- package/src/dev/wire.ts +2 -1
- package/types/src/agent-skill.d.ts +29 -0
- package/types/src/build.d.ts +11 -0
- package/types/src/bun.d.ts +66 -0
- package/types/src/client/caller.d.ts +19 -0
- package/types/src/client/contract.d.ts +131 -0
- package/types/src/client/error-reporting.d.ts +66 -0
- package/types/src/client/index.d.ts +4 -0
- package/types/src/client/rpc.d.ts +14 -0
- package/types/src/client/share.d.ts +2 -0
- package/types/src/client/transport.d.ts +42 -0
- package/types/src/cloudflare.d.ts +49 -0
- package/types/src/contract/artifact-schema.d.ts +8 -0
- package/types/src/contract/attachment.d.ts +41 -0
- package/types/src/contract/build.d.ts +12 -0
- package/types/src/contract/compile.d.ts +11 -0
- package/types/src/contract/connect.d.ts +51 -0
- package/types/src/contract/context.d.ts +501 -0
- package/types/src/contract/declaration.d.ts +303 -0
- package/types/src/contract/defaults.d.ts +208 -0
- package/types/src/contract/define.d.ts +359 -0
- package/types/src/contract/file.d.ts +44 -0
- package/types/src/contract/group.d.ts +274 -0
- package/types/src/contract/handled.d.ts +18 -0
- package/types/src/contract/index.d.ts +19 -0
- package/types/src/contract/kit.d.ts +210 -0
- package/types/src/contract/platform.d.ts +9 -0
- package/types/src/contract/problems.d.ts +14 -0
- package/types/src/contract/redirect.d.ts +25 -0
- package/types/src/contract/schema-from-shape.d.ts +10 -0
- package/types/src/contract/schema-shape.d.ts +5 -0
- package/types/src/contract/snapshot-source.d.ts +15 -0
- package/types/src/contract/token.d.ts +58 -0
- package/types/src/contract/vocabulary.d.ts +30 -0
- package/types/src/contract/webhook-binding.d.ts +24 -0
- package/types/src/contract/webhook-scheme.d.ts +23 -0
- package/types/src/dev/changes.d.ts +7 -0
- package/types/src/dev/contract-digest.d.ts +1 -0
- package/types/src/dev/index.d.ts +2 -0
- package/types/src/dev/launcher.d.ts +32 -0
- package/types/src/dev/output.d.ts +22 -0
- package/types/src/dev/wire.d.ts +122 -0
- package/types/src/disk-assets.d.ts +3 -0
- package/types/src/errors.d.ts +46 -0
- package/types/src/fetch.d.ts +7 -0
- package/types/src/files/archive.d.ts +26 -0
- package/types/src/files/clamscan.d.ts +32 -0
- package/types/src/files/handle.d.ts +106 -0
- package/types/src/files/kinds.d.ts +105 -0
- package/types/src/files/scan.d.ts +80 -0
- package/types/src/files/sniff.d.ts +7 -0
- package/types/src/files/streams.d.ts +17 -0
- package/types/src/files/treatment.d.ts +18 -0
- package/types/src/from-row.d.ts +20 -0
- package/types/src/honeypot.d.ts +2 -0
- package/types/src/implement/anonymous.d.ts +26 -0
- package/types/src/implement/attachment.d.ts +14 -0
- package/types/src/implement/boot.d.ts +109 -0
- package/types/src/implement/bounded.d.ts +22 -0
- package/types/src/implement/browser-config.d.ts +19 -0
- package/types/src/implement/capability.d.ts +140 -0
- package/types/src/implement/challenge.d.ts +75 -0
- package/types/src/implement/client-address.d.ts +11 -0
- package/types/src/implement/connect.d.ts +67 -0
- package/types/src/implement/crashes.d.ts +31 -0
- package/types/src/implement/dispatch.d.ts +218 -0
- package/types/src/implement/egress.d.ts +14 -0
- package/types/src/implement/environment.d.ts +14 -0
- package/types/src/implement/failures.d.ts +34 -0
- package/types/src/implement/faults.d.ts +44 -0
- package/types/src/implement/headers.d.ts +7 -0
- package/types/src/implement/implement.d.ts +58 -0
- package/types/src/implement/index.d.ts +24 -0
- package/types/src/implement/invocation.d.ts +120 -0
- package/types/src/implement/membership.d.ts +201 -0
- package/types/src/implement/multipart.d.ts +36 -0
- package/types/src/implement/params.d.ts +7 -0
- package/types/src/implement/principal.d.ts +52 -0
- package/types/src/implement/project.d.ts +11 -0
- package/types/src/implement/public.d.ts +61 -0
- package/types/src/implement/serve.d.ts +25 -0
- package/types/src/implement/tokens.d.ts +49 -0
- package/types/src/implement/types.d.ts +243 -0
- package/types/src/implement/urls.d.ts +15 -0
- package/types/src/implement/verifiers.d.ts +19 -0
- package/types/src/implement/webhook.d.ts +55 -0
- package/types/src/implement/workload.d.ts +56 -0
- package/types/src/implement/xlsx.d.ts +6 -0
- package/types/src/index.d.ts +12 -0
- package/types/src/jobs/exception.d.ts +40 -0
- package/types/src/jobs/mail.d.ts +67 -0
- package/types/src/jobs/report.d.ts +56 -0
- package/types/src/jobs/runner.d.ts +145 -0
- package/types/src/jobs/schedule.d.ts +15 -0
- package/types/src/jobs/scrub.d.ts +12 -0
- package/types/src/jobs/types.d.ts +92 -0
- package/types/src/react/caller.d.ts +30 -0
- package/types/src/react/errors.d.ts +40 -0
- package/types/src/react/hooks.d.ts +110 -0
- package/types/src/react/index.d.ts +5 -0
- package/types/src/react/provider.d.ts +58 -0
- package/types/src/react/store.d.ts +68 -0
- package/types/src/react/testing.d.ts +28 -0
- package/types/src/react/types.d.ts +33 -0
- package/types/src/rpc/builder.d.ts +52 -0
- package/types/src/rpc/contract.d.ts +23 -0
- package/types/src/rpc/dispatcher.d.ts +11 -0
- package/types/src/rpc/types.d.ts +62 -0
- package/types/src/service/define.d.ts +42 -0
- package/types/src/service/index.d.ts +3 -0
- package/types/src/service/serve.d.ts +28 -0
- package/types/src/standard-schema.d.ts +55 -0
- package/types/src/testing/caller.d.ts +95 -0
- package/types/src/testing/challenge.d.ts +11 -0
- package/types/src/testing/dev.d.ts +97 -0
- package/types/src/testing/endpoint-access.d.ts +99 -0
- package/types/src/testing/index.d.ts +12 -0
- package/types/src/testing/isolation.d.ts +3 -0
- package/types/src/testing/kit.d.ts +182 -0
- package/types/src/testing/membership.d.ts +132 -0
- package/types/src/testing/policy-isolation.d.ts +113 -0
- package/types/src/testing/preload.d.ts +1 -0
- package/types/src/testing/proxy.d.ts +40 -0
- package/types/src/testing/runner.d.ts +8 -0
- package/types/src/testing/sample-file.d.ts +5 -0
- package/types/src/testing/status.d.ts +4 -0
- package/types/src/undumpable.d.ts +5 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
import { type AttachmentBrand } from '../contract/attachment';
|
|
3
|
+
import { type ProcedureType } from '../contract/declaration';
|
|
4
|
+
import type { AnyContract, InputSchema, Procedure, Schema } from '../contract/define';
|
|
5
|
+
import { type ClientInput, type FileBrand } from '../contract/file';
|
|
6
|
+
import { type BounceOption, type RpcFetch } from './transport';
|
|
7
|
+
type SurfaceOf<C> = C extends {
|
|
8
|
+
readonly surface: infer S;
|
|
9
|
+
} ? S : never;
|
|
10
|
+
/** The mounts a client calls: RPC mounts and link mounts. */
|
|
11
|
+
export type ClientMount<C> = {
|
|
12
|
+
[M in keyof SurfaceOf<C>]: SurfaceOf<C>[M] extends {
|
|
13
|
+
readonly kind: 'rpc' | 'link';
|
|
14
|
+
} ? M : never;
|
|
15
|
+
}[keyof SurfaceOf<C>] & string;
|
|
16
|
+
/**
|
|
17
|
+
* One procedure: its input as the caller writes it (defaults optional), its output as parsed, and the output schema
|
|
18
|
+
* it parses with (`@fabrika/app/react` reads a cached answer back through it).
|
|
19
|
+
*/
|
|
20
|
+
export type ProcedureCall<I, O extends Schema> = ([I] extends [InputSchema] ? (input: ClientInput<z.input<I>>) => Promise<z.output<O>> : (input?: Record<never, never>) => Promise<z.output<O>>) & {
|
|
21
|
+
readonly output: O;
|
|
22
|
+
};
|
|
23
|
+
export type ClientTree<T> = {
|
|
24
|
+
readonly [K in keyof T]: T[K] extends Procedure<'query' | 'mutation', infer I, infer O, unknown> ? O extends AttachmentBrand ? AttachmentProcedure<I> : O extends FileBrand<string> ? FileProcedure<I> : ProcedureCall<I, O> : ClientTree<T[K]>;
|
|
25
|
+
};
|
|
26
|
+
type MountOf<C, M> = SurfaceOf<C>[M & keyof SurfaceOf<C>];
|
|
27
|
+
/** One function per procedure, and an `AttachmentProcedure` or `FileProcedure` per procedure that answers a file. */
|
|
28
|
+
export type ContractClient<C, M> = MountOf<C, M> extends {
|
|
29
|
+
readonly procedures: infer T;
|
|
30
|
+
} ? ClientTree<T> : never;
|
|
31
|
+
/** The answer of a client procedure: `ResultOf<typeof api.tasks.get>`; a procedure that answers a file, a `DownloadedFile`. */
|
|
32
|
+
export type ResultOf<F> = F extends (...args: never[]) => Promise<infer R> ? R : F extends AttachmentProcedure<unknown> | FileProcedure<unknown> ? DownloadedFile : never;
|
|
33
|
+
/** The input of a client procedure as the caller writes it: `InputOf<typeof api.tasks.create>`. */
|
|
34
|
+
export type InputOf<F> = F extends (...args: infer A) => Promise<unknown> ? A[0] : F extends AttachmentProcedure<infer I> | FileProcedure<infer I> ? DownloadInput<I>[0] : never;
|
|
35
|
+
export interface ClientOptions {
|
|
36
|
+
/** The application's origin; procedure paths are joined to it. Defaults to the page's own origin. */
|
|
37
|
+
readonly baseUrl?: string;
|
|
38
|
+
/** Override `fetch` (tests, a script). Defaults to the global `fetch`. */
|
|
39
|
+
readonly fetch?: RpcFetch;
|
|
40
|
+
/**
|
|
41
|
+
* A `px_` key, sent as `Authorization: Bearer`. A request with a key carries no cookie. In a browser the key goes
|
|
42
|
+
* only to the page's own origin.
|
|
43
|
+
*/
|
|
44
|
+
readonly key?: string;
|
|
45
|
+
/** On a 401 that carries a login URL, send the browser to sign in instead of throwing. */
|
|
46
|
+
readonly bounceOnAuth?: BounceOption;
|
|
47
|
+
}
|
|
48
|
+
/** A link mount's caller is the holder of its share key, which every request presents. */
|
|
49
|
+
export interface LinkClientOptions extends ClientOptions {
|
|
50
|
+
readonly key: string;
|
|
51
|
+
}
|
|
52
|
+
type OptionsFor<C, M> = SurfaceOf<C>[M & keyof SurfaceOf<C>] extends {
|
|
53
|
+
readonly kind: 'link';
|
|
54
|
+
} ? [options: LinkClientOptions] : [options?: ClientOptions];
|
|
55
|
+
/**
|
|
56
|
+
* What a value of a client tree is, kept beside it so the value stays a plain function or record: a procedure's
|
|
57
|
+
* `<mount>.<path>`, its type and input schema, or a group's prefix. `@fabrika/app/react` keys its cache by it.
|
|
58
|
+
*/
|
|
59
|
+
export interface ClientNode {
|
|
60
|
+
readonly mount: string;
|
|
61
|
+
/** The dotted path below the mount; `''` for the client itself. */
|
|
62
|
+
readonly path: string;
|
|
63
|
+
readonly procedure: {
|
|
64
|
+
readonly type: ProcedureType;
|
|
65
|
+
readonly input: Schema | null;
|
|
66
|
+
} | null;
|
|
67
|
+
}
|
|
68
|
+
/** The node a value of a client tree is, or `null` for any other value. */
|
|
69
|
+
export declare function clientNodeOf(value: unknown): ClientNode | null;
|
|
70
|
+
/**
|
|
71
|
+
* The URL a page's ALTCHA widget fetches the challenge of `procedure` from (`GET /__fabrika/challenge/<action>`), on the
|
|
72
|
+
* client's `baseUrl`. Throws for a procedure whose `admission.challenge` is not `provider: 'altcha'`.
|
|
73
|
+
*/
|
|
74
|
+
export declare function challengeUrl(procedure: object): string;
|
|
75
|
+
declare const attachmentInput: unique symbol;
|
|
76
|
+
/**
|
|
77
|
+
* An attachment procedure of a client: not a function, because its answer is a file. `download(api.<procedure>,
|
|
78
|
+
* input)` fetches and saves it.
|
|
79
|
+
*/
|
|
80
|
+
export interface AttachmentProcedure<I> {
|
|
81
|
+
/** `<mount>.<path>` */
|
|
82
|
+
readonly id: string;
|
|
83
|
+
/** The file name the contract declares. */
|
|
84
|
+
readonly filename: string;
|
|
85
|
+
/** Carries the input schema for `download`; never present at runtime. */
|
|
86
|
+
readonly [attachmentInput]?: I;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* A procedure whose output is a file (`file('<kind>')`): not a function, because its answer is a file.
|
|
90
|
+
* `download(api.<procedure>, input)` fetches it with the caller's credential, and a GET one's `url(input)` is where a
|
|
91
|
+
* same-origin page links to it (`<img src>`, `<a download>`).
|
|
92
|
+
*/
|
|
93
|
+
export interface FileProcedure<I> {
|
|
94
|
+
/** `<mount>.<path>` */
|
|
95
|
+
readonly id: string;
|
|
96
|
+
/**
|
|
97
|
+
* The URL of the file a GET procedure answers, for a page signed in on the same origin. A client with a key has none:
|
|
98
|
+
* a key never goes into a URL, so it downloads instead.
|
|
99
|
+
*/
|
|
100
|
+
url(...input: DownloadInput<I>): string;
|
|
101
|
+
/** Carries the input schema for `download`; never present at runtime. */
|
|
102
|
+
readonly [attachmentInput]?: I;
|
|
103
|
+
}
|
|
104
|
+
/** A downloaded file: a `File`, and the page's offer to save it. */
|
|
105
|
+
export declare class DownloadedFile extends File {
|
|
106
|
+
/** The file as a `Blob`. */
|
|
107
|
+
blob(): Blob;
|
|
108
|
+
/** Offers the file as a download under its name; nothing where there is no page. */
|
|
109
|
+
save(): void;
|
|
110
|
+
}
|
|
111
|
+
/** The mount and path of an attachment procedure of a client, or `null` for any other value. */
|
|
112
|
+
export declare function attachmentAt(value: unknown): {
|
|
113
|
+
readonly mount: string;
|
|
114
|
+
readonly path: string;
|
|
115
|
+
} | null;
|
|
116
|
+
/** The input `download` takes: the procedure's, or none. */
|
|
117
|
+
export type DownloadInput<I> = [I] extends [InputSchema] ? [input: z.input<I>] : [input?: Record<never, never>];
|
|
118
|
+
/**
|
|
119
|
+
* Calls a procedure that answers a file (an attachment, or a `file('<kind>')` output) with the caller's credential, and
|
|
120
|
+
* answers the file: `blob()`, `stream()`, `save()`. An attachment is also offered as a download in a browser, under the
|
|
121
|
+
* declared name. A refusal is an `RpcError`.
|
|
122
|
+
*/
|
|
123
|
+
export declare function download<I>(procedure: AttachmentProcedure<I> | FileProcedure<I>, ...input: DownloadInput<I>): Promise<DownloadedFile>;
|
|
124
|
+
/** `download` of any file procedure of a client, its input unchecked: the provider's `useDownload` runs it. */
|
|
125
|
+
export declare function downloadFile(procedure: object, input: unknown): Promise<DownloadedFile>;
|
|
126
|
+
/**
|
|
127
|
+
* The client of mount `mount` of `contract`: one function per declared procedure. A link mount's client sends its
|
|
128
|
+
* share key as a bearer, so `options.key` is required there.
|
|
129
|
+
*/
|
|
130
|
+
export declare function createClient<const C extends AnyContract, const M extends ClientMount<C>>(contract: C, mount: M, ...rest: OptionsFor<C, M>): ContractClient<C, M>;
|
|
131
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { RpcFetch } from './transport';
|
|
2
|
+
/** One stack frame in Sentry's shape, the file a script URL. */
|
|
3
|
+
export interface BrowserFrame {
|
|
4
|
+
readonly filename: string;
|
|
5
|
+
readonly function?: string;
|
|
6
|
+
readonly lineno: number;
|
|
7
|
+
readonly colno: number;
|
|
8
|
+
/** A frame of a script of the page's own origin. */
|
|
9
|
+
readonly in_app: boolean;
|
|
10
|
+
}
|
|
11
|
+
/** Where the page reports, read from its browser config. */
|
|
12
|
+
export interface ReportingTarget {
|
|
13
|
+
/** The ingest's envelope endpoint, authenticated by the DSN's public key in its query, as the Sentry SDK sends it. */
|
|
14
|
+
readonly envelopeUrl: string;
|
|
15
|
+
readonly release: string | null;
|
|
16
|
+
readonly environment: string | null;
|
|
17
|
+
}
|
|
18
|
+
/** What the reporter listens on and reads the page's address from: `window` in a page. */
|
|
19
|
+
export interface ReportingPage {
|
|
20
|
+
addEventListener(type: 'error' | 'unhandledrejection', listener: (event: Event) => void): void;
|
|
21
|
+
removeEventListener(type: 'error' | 'unhandledrejection', listener: (event: Event) => void): void;
|
|
22
|
+
readonly location: {
|
|
23
|
+
readonly origin: string;
|
|
24
|
+
readonly pathname: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** A page that keeps failing stops reporting here; Operations rate-limits the whole source, not one page. */
|
|
28
|
+
export declare const MAX_REPORTS_PER_PAGE = 20;
|
|
29
|
+
/**
|
|
30
|
+
* The envelope endpoint of an ingest DSN `https://<key>@<host>/<project>`, or `null` for any other value. The server's
|
|
31
|
+
* reporter parses the same DSN (`jobs/report.ts`); it is server code, so a page does not import it.
|
|
32
|
+
*/
|
|
33
|
+
export declare function envelopeUrlOf(dsn: string): string | null;
|
|
34
|
+
/** The reporting target the browser config names, or `null` when it names no usable DSN. */
|
|
35
|
+
export declare function reportingTargetOf(config: unknown): ReportingTarget | null;
|
|
36
|
+
/**
|
|
37
|
+
* The frames of a V8, SpiderMonkey or JavaScriptCore `stack`, oldest call first as Sentry orders them, the
|
|
38
|
+
* `MAX_FRAMES` nearest the throw kept. A frame whose file is no URL (an `eval`, a native function) is left out.
|
|
39
|
+
*/
|
|
40
|
+
export declare function parseBrowserStack(stack: string, origin: string): BrowserFrame[];
|
|
41
|
+
type Mechanism = 'onerror' | 'onunhandledrejection';
|
|
42
|
+
interface ReportedException {
|
|
43
|
+
readonly type: string;
|
|
44
|
+
readonly value: string;
|
|
45
|
+
readonly mechanism: {
|
|
46
|
+
readonly type: Mechanism;
|
|
47
|
+
readonly handled: false;
|
|
48
|
+
};
|
|
49
|
+
readonly stacktrace?: {
|
|
50
|
+
readonly frames: readonly BrowserFrame[];
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/** The envelope of one error event. The page's address goes without its query and fragment, which may carry a key. */
|
|
54
|
+
export declare function browserEnvelope(exception: ReportedException, target: ReportingTarget, page: ReportingPage['location'], now: Date): string;
|
|
55
|
+
/**
|
|
56
|
+
* Listen for the page's uncaught errors and unhandled rejections and send each to `target`; answers the uninstall.
|
|
57
|
+
* An error equal to the one just sent is not sent again, and the page sends at most `MAX_REPORTS_PER_PAGE`. A failed
|
|
58
|
+
* delivery is dropped: reporting never throws into the page.
|
|
59
|
+
*/
|
|
60
|
+
export declare function installErrorReporting(page: ReportingPage, target: ReportingTarget, send: RpcFetch): () => void;
|
|
61
|
+
/**
|
|
62
|
+
* Read the browser config at `configUrl` and install reporting when it names a DSN; answers the uninstall, or `null`
|
|
63
|
+
* when nothing was installed. A missing, refused or unreadable config (local development, a test) installs nothing.
|
|
64
|
+
*/
|
|
65
|
+
export declare function startErrorReporting(configUrl: string, fetch: RpcFetch, page: ReportingPage): Promise<(() => void) | null>;
|
|
66
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { type PageCaller, parsePageCaller } from './caller';
|
|
2
|
+
export { type AttachmentProcedure, challengeUrl, type ClientMount, type ClientOptions, type ClientTree, type ContractClient, createClient, download, DownloadedFile, type DownloadInput, type FileProcedure, type InputOf, type LinkClientOptions, type ProcedureCall, type ResultOf, } from './contract';
|
|
3
|
+
export { shareKey } from './share';
|
|
4
|
+
export { type BounceOption, RpcError, type RpcFetch } from './transport';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { InferRpcClient } from '../rpc/contract.js';
|
|
2
|
+
import { type BounceOption, type RpcFetch } from './transport.js';
|
|
3
|
+
export interface RpcClientOptions {
|
|
4
|
+
/** Endpoint the RPC proxy POSTs to (e.g. `/rpc`). */
|
|
5
|
+
readonly baseUrl: string;
|
|
6
|
+
/**
|
|
7
|
+
* Auto-redirect to SSO on a sign-in 401 (`type: 'auth'` + `loginUrl`) instead of throwing.
|
|
8
|
+
* `true` uses sane defaults; pass `{ sessionKey, windowMs }` to tune the re-entry guard.
|
|
9
|
+
*/
|
|
10
|
+
readonly bounceOnAuth?: BounceOption;
|
|
11
|
+
/** Override `fetch` (tests / non-browser). Defaults to the global `fetch`. */
|
|
12
|
+
readonly fetch?: RpcFetch;
|
|
13
|
+
}
|
|
14
|
+
export declare function createRpcClient<TApi>(opts: RpcClientOptions): InferRpcClient<TApi>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export declare class RpcError extends Error {
|
|
2
|
+
readonly type: string;
|
|
3
|
+
readonly issues?: unknown;
|
|
4
|
+
readonly loginUrl?: string;
|
|
5
|
+
readonly httpStatus?: number;
|
|
6
|
+
constructor(payload: {
|
|
7
|
+
type: string;
|
|
8
|
+
message: string;
|
|
9
|
+
issues?: unknown;
|
|
10
|
+
loginUrl?: string;
|
|
11
|
+
httpStatus?: number;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
/** Minimal Fetch API surface required by the RPC client. */
|
|
15
|
+
export type RpcFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
16
|
+
/**
|
|
17
|
+
* Auto-redirect to SSO on a sign-in 401 (`type: 'auth'` + `loginUrl`) instead of throwing.
|
|
18
|
+
* `true` uses sane defaults; pass `{ sessionKey, windowMs }` to tune the re-entry guard.
|
|
19
|
+
*/
|
|
20
|
+
export type BounceOption = boolean | {
|
|
21
|
+
sessionKey?: string;
|
|
22
|
+
windowMs?: number;
|
|
23
|
+
};
|
|
24
|
+
export interface BounceConfig {
|
|
25
|
+
readonly sessionKey: string;
|
|
26
|
+
readonly windowMs: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function resolveBounce(scope: string, opt: BounceOption | undefined): BounceConfig | null;
|
|
29
|
+
/**
|
|
30
|
+
* Sends one request and answers the envelope's `result`; every failure is an `RpcError`, and so is every answer that is
|
|
31
|
+
* not 2xx, whatever its body holds. `init` builds the request inside the guard, so an input that does not serialize
|
|
32
|
+
* rejects like a failed request instead of throwing.
|
|
33
|
+
*/
|
|
34
|
+
export declare function exchange(doFetch: RpcFetch, url: string, init: () => RequestInit, bounce: BounceConfig | null): Promise<unknown>;
|
|
35
|
+
/**
|
|
36
|
+
* Sends one request whose success is a file and answers its bytes and its `Content-Disposition`; a failure is read from
|
|
37
|
+
* its `{ error }` envelope.
|
|
38
|
+
*/
|
|
39
|
+
export declare function exchangeFile(doFetch: RpcFetch, url: string, init: () => RequestInit, bounce: BounceConfig | null): Promise<{
|
|
40
|
+
readonly body: Blob;
|
|
41
|
+
readonly disposition: string | null;
|
|
42
|
+
}>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { FetchService, RequestExecutionContext } from './fetch.js';
|
|
2
|
+
import { type CrashEvents } from './implement/crashes.js';
|
|
3
|
+
import type { ContractImplementation } from './implement/implement.js';
|
|
4
|
+
export { markProductionProcess } from '@fabrika/db/production';
|
|
5
|
+
/** Minimal structural view of a Workers `ExecutionContext`. */
|
|
6
|
+
export interface CloudflareExecutionContext extends RequestExecutionContext {
|
|
7
|
+
passThroughOnException(): void;
|
|
8
|
+
}
|
|
9
|
+
/** Minimal structural view of a Workers cron `ScheduledController`. */
|
|
10
|
+
export interface CloudflareScheduledController {
|
|
11
|
+
readonly scheduledTime: number;
|
|
12
|
+
readonly cron: string;
|
|
13
|
+
noRetry(): void;
|
|
14
|
+
}
|
|
15
|
+
/** Minimal structural view of a Workers queue `MessageBatch`. */
|
|
16
|
+
export interface CloudflareMessageBatch {
|
|
17
|
+
readonly queue: string;
|
|
18
|
+
readonly messages: ReadonlyArray<unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface CloudflareWorkerOptions<Env> {
|
|
21
|
+
scheduled?: (controller: CloudflareScheduledController, env: Env, exec: CloudflareExecutionContext) => Promise<void>;
|
|
22
|
+
queue?: (batch: CloudflareMessageBatch, env: Env, exec: CloudflareExecutionContext) => Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export interface CloudflareWorker<Env> {
|
|
25
|
+
fetch(request: Request, env: Env, exec: CloudflareExecutionContext): Promise<Response>;
|
|
26
|
+
scheduled?(controller: CloudflareScheduledController, env: Env, exec: CloudflareExecutionContext): Promise<void>;
|
|
27
|
+
queue?(batch: CloudflareMessageBatch, env: Env, exec: CloudflareExecutionContext): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
/** Adapt a runtime-neutral `{ fetch }` service to a Workers module export. */
|
|
30
|
+
export declare function createCloudflareWorker<Env>(app: FetchService<Env>, options?: CloudflareWorkerOptions<Env>): CloudflareWorker<Env>;
|
|
31
|
+
/** The application module, imported only after the environment was captured: the generated entrypoint's `import()`. */
|
|
32
|
+
export type ImplementationLoader = () => Promise<{
|
|
33
|
+
readonly default: ContractImplementation;
|
|
34
|
+
}>;
|
|
35
|
+
export interface ContractWorkerOptions {
|
|
36
|
+
/** Where the isolate hears of an unhandled rejection; the global `unhandledrejection` event by default. */
|
|
37
|
+
readonly rejections?: CrashEvents;
|
|
38
|
+
/** What posts a report to Operations' ingest; `fetch` by default. */
|
|
39
|
+
readonly operationsFetch?: (request: Request) => Promise<Response>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A Worker module for a contract application, called only by the generated entrypoint. A Worker receives its
|
|
43
|
+
* environment with the first request, so the framework captures it, scrubs the process environment and only then
|
|
44
|
+
* imports the application and boots it, once per environment object. With an Operations DSN, the first failed boot
|
|
45
|
+
* of an isolate is reported, and once one booted, every unhandled rejection of the isolate is, within a budget.
|
|
46
|
+
*/
|
|
47
|
+
export declare function createContractWorker(load: ImplementationLoader, options?: ContractWorkerOptions): {
|
|
48
|
+
fetch(request: Request, env: Readonly<Record<string, unknown>>, exec: CloudflareExecutionContext): Promise<Response>;
|
|
49
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ContractArtifact, type OutputShape, type SchemaShape } from '@fabrika/auth-core';
|
|
2
|
+
import { z } from 'zod/v4';
|
|
3
|
+
/** A `SchemaShape` read back as JSON. */
|
|
4
|
+
export declare const schemaShapeSchema: z.ZodType<SchemaShape>;
|
|
5
|
+
export declare const outputShapeSchema: z.ZodType<OutputShape>;
|
|
6
|
+
export declare const contractArtifactSchema: z.ZodType<ContractArtifact>;
|
|
7
|
+
/** Parses JSON that should be a contract artifact; throws a `ZodError` naming every mismatch. */
|
|
8
|
+
export declare function parseContractArtifact(value: unknown): ContractArtifact;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
import { type AttachmentDeclaration } from './declaration';
|
|
3
|
+
import type { InputSchema, NotLoose, Schema } from './define';
|
|
4
|
+
declare const ATTACHMENT: unique symbol;
|
|
5
|
+
/** What `attachment()` adds to the rows' array schema: its declaration and its row schema. */
|
|
6
|
+
export interface AttachmentMark {
|
|
7
|
+
readonly declaration: AttachmentDeclaration;
|
|
8
|
+
readonly row: InputSchema;
|
|
9
|
+
}
|
|
10
|
+
/** An attachment output of rows `R`: the handler returns `z.input<R>[]`, and the caller receives a file. */
|
|
11
|
+
export type Attachment<R extends InputSchema> = z.ZodArray<R> & AttachmentBrand;
|
|
12
|
+
/** What tells an attachment output from a JSON one in the types. */
|
|
13
|
+
export interface AttachmentBrand {
|
|
14
|
+
readonly [ATTACHMENT]: AttachmentMark;
|
|
15
|
+
}
|
|
16
|
+
export interface AttachmentOptions<R> {
|
|
17
|
+
/**
|
|
18
|
+
* `'csv'`: RFC 4180, UTF-8 with a byte order mark, a header line of the row's field names. `'xlsx'`: one sheet, the
|
|
19
|
+
* header row of the field names, then a number, boolean or text cell per value, and a date cell for a string whose
|
|
20
|
+
* schema is `z.iso.date()` or `z.iso.datetime()`.
|
|
21
|
+
*/
|
|
22
|
+
readonly format: 'csv' | 'xlsx';
|
|
23
|
+
/** The file name the browser saves: `[A-Za-z0-9._-]`, ending in `.csv` or `.xlsx`, as the format. */
|
|
24
|
+
readonly filename: string;
|
|
25
|
+
/** The row schema: a strict object of scalar fields, in the file's column order. */
|
|
26
|
+
readonly row: R;
|
|
27
|
+
/** The encoded file's limit; an encoding over it fails the invocation and sends no body. */
|
|
28
|
+
readonly maxBytes: number;
|
|
29
|
+
/** At most this many rows; 10 000 when left out. */
|
|
30
|
+
readonly maxRows?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The output of a procedure that answers a file of `row`s. Like every builder it validates nothing: `compileContract`
|
|
34
|
+
* and the checker refuse a format, a name, a limit or a column outside what an attachment may be.
|
|
35
|
+
*/
|
|
36
|
+
export declare function attachment<R extends InputSchema>(options: AttachmentOptions<R & NotLoose<R>>): Attachment<R>;
|
|
37
|
+
/** The rows' array schema marked with `declaration`; the static reader builds the evaluated value with it. */
|
|
38
|
+
export declare function attachmentOutput<R extends InputSchema>(row: R, declaration: AttachmentDeclaration): Attachment<R>;
|
|
39
|
+
/** The mark of an `attachment()` output, or `null` for any other schema. */
|
|
40
|
+
export declare function attachmentOf(schema: Schema): AttachmentMark | null;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ContractArtifact, type FileShape, type SchemaShape, type TablePolicyArtifact } from '@fabrika/auth-core';
|
|
2
|
+
import { type ContractDeclaration } from './declaration';
|
|
3
|
+
/** Turnstile's `action`: the procedure's endpoint id, which the verification expects back. */
|
|
4
|
+
/** Validates a described contract against its table policies and normalizes it; throws `ContractError` with every problem. */
|
|
5
|
+
export declare function buildArtifact(contract: ContractDeclaration<SchemaShape>, tables: Readonly<Record<string, TablePolicyArtifact>>): ContractArtifact;
|
|
6
|
+
/** Whether a schema holds a file anywhere. */
|
|
7
|
+
export declare function containsFile(shape: SchemaShape): boolean;
|
|
8
|
+
/** The file fields of an input, by name: the parts a multipart body carries beside its JSON. */
|
|
9
|
+
export declare function fileFieldsOf(input: SchemaShape | null): ReadonlyMap<string, FileShape & {
|
|
10
|
+
readonly many: boolean;
|
|
11
|
+
readonly max: number;
|
|
12
|
+
}>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ContractArtifact, SchemaShape, TablePolicyArtifact } from '@fabrika/auth-core';
|
|
2
|
+
import { type Tables } from '@fabrika/db/tables';
|
|
3
|
+
import { type ContractDeclaration } from './declaration';
|
|
4
|
+
import type { AnyContract } from './define';
|
|
5
|
+
/**
|
|
6
|
+
* The normalized artifact of a contract and its table policies: what `defineTables` returned (`src/db/tables.ts`),
|
|
7
|
+
* or the artifact form of each policy.
|
|
8
|
+
*/
|
|
9
|
+
export declare function compileContract<DB, P>(contract: AnyContract, tables: Tables<DB, P> | Readonly<Record<string, TablePolicyArtifact>>): ContractArtifact;
|
|
10
|
+
/** The contract with its schemas read as shapes; throws `ContractError` for a schema outside the subset. */
|
|
11
|
+
export declare function describeContract(contract: AnyContract): ContractDeclaration<SchemaShape>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type ContractArtifact, type ExportDescription } from '@fabrika/auth-core';
|
|
2
|
+
import { z } from 'zod/v4';
|
|
3
|
+
import type { InputSchema, Schema } from './define';
|
|
4
|
+
/** One vendored procedure: the zod schemas `fabrika connect add` generated from the owner's description. */
|
|
5
|
+
export interface SnapshotProcedure {
|
|
6
|
+
readonly input: InputSchema | null;
|
|
7
|
+
readonly output: Schema;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The vendored description of another application's export, as `fabrika connect add` writes it to
|
|
11
|
+
* `fabrika/connect/<app>.<export>.v<version>.ts`. The consumer passes it to `implement({ connect })` and imports its
|
|
12
|
+
* digest into the contract.
|
|
13
|
+
*/
|
|
14
|
+
export interface ConnectSnapshot {
|
|
15
|
+
readonly app: string;
|
|
16
|
+
readonly export: string;
|
|
17
|
+
readonly version: number;
|
|
18
|
+
readonly audience: string;
|
|
19
|
+
readonly digest: string;
|
|
20
|
+
/** By the procedure's dotted path in the export. */
|
|
21
|
+
readonly procedures: {
|
|
22
|
+
readonly [path: string]: SnapshotProcedure;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** The description the owner serves for `name`, or `null` when the artifact declares no such export. */
|
|
26
|
+
export declare function exportDescription(artifact: ContractArtifact, name: string): ExportDescription | null;
|
|
27
|
+
/**
|
|
28
|
+
* The description a snapshot's schemas describe now, with the digest of that. A snapshot whose recomputed digest is
|
|
29
|
+
* not its own `digest` was edited after `fabrika connect add` wrote it. Throws `ContractError` for a schema outside
|
|
30
|
+
* the contract subset.
|
|
31
|
+
*/
|
|
32
|
+
export declare function describeSnapshot(snapshot: ConnectSnapshot): ExportDescription;
|
|
33
|
+
/** The parser of a description another application served; the digest is checked by `parseExportDescription`. */
|
|
34
|
+
export declare const exportDescriptionSchema: z.ZodType<ExportDescription>;
|
|
35
|
+
/** A served description, parsed, whose digest is the digest of what it describes; throws `ContractError` otherwise. */
|
|
36
|
+
export declare function parseExportDescription(value: unknown): ExportDescription;
|
|
37
|
+
/**
|
|
38
|
+
* What an owner's change of one export version breaks for a consumer that imports `procedures` of it: a removed
|
|
39
|
+
* procedure, an input that accepts less, a changed output, or a changed audience. An output may not even gain a field,
|
|
40
|
+
* because the consumer parses every answer against its vendored schema, whose objects are strict; an input object may
|
|
41
|
+
* gain optional fields. Every other change is a new version. Empty when the change is compatible.
|
|
42
|
+
*/
|
|
43
|
+
export declare function incompatibleChanges(before: ExportDescription, after: ExportDescription, procedures: readonly string[]): string[];
|
|
44
|
+
/**
|
|
45
|
+
* What `after` breaks for the callers of each mount `before` promises `compatibility: 'backward'`: a procedure it
|
|
46
|
+
* removes (including its generated challenge endpoint), an input or a query that accepts less, another output, another
|
|
47
|
+
* HTTP shape (method, path, body codec), file answer or access (its kind, callers, requirement and cross-origin form), or a
|
|
48
|
+
* mount moved. The promise binds the
|
|
49
|
+
* publication that drops it too, so a breaking change is a new mount beside the old one. Empty when compatible.
|
|
50
|
+
*/
|
|
51
|
+
export declare function incompatibleMountChanges(before: ContractArtifact, after: ContractArtifact): string[];
|