@fabrika/app 0.8.2 → 0.9.0-cloudflare.1
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 +40 -24
- package/skill/SKILL.md +27 -3
- package/skill/references/app-setup.md +8 -8
- package/skill/references/dev.md +2 -1
- package/skill/references/endpoint.md +7 -3
- package/skill/references/errors.md +39 -35
- package/skill/references/files.md +4 -2
- package/skill/references/table-and-migration.md +19 -2
- package/skill/references/tests.md +11 -0
- package/skill/references/webhooks-links-connectors.md +1 -1
- package/src/build-recipe.ts +198 -0
- package/src/build.ts +55 -4
- package/src/bun.ts +23 -8
- package/src/cloudflare/application.ts +352 -0
- package/src/cloudflare/bindings.ts +138 -0
- package/src/cloudflare/names.ts +10 -0
- package/src/cloudflare/ops.ts +246 -0
- package/src/cloudflare/r2-files.ts +172 -0
- package/src/cloudflare.ts +99 -146
- package/src/contract/app-id.ts +5 -0
- package/src/contract/artifact-schema.ts +2 -0
- package/src/contract/build.ts +35 -1
- package/src/contract/compile.ts +1 -0
- package/src/contract/context.ts +9 -0
- package/src/contract/declaration.ts +2 -0
- package/src/contract/define.ts +28 -2
- package/src/contract/kit.ts +4 -1
- package/src/contract/platform.ts +3 -2
- package/src/contract/vocabulary.ts +26 -8
- package/src/dev/changes.ts +35 -0
- package/src/dev/contract-digest.ts +17 -0
- package/src/dev/index.ts +11 -0
- package/src/dev/launcher.ts +713 -0
- package/src/dev/output.ts +72 -0
- package/src/dev/wire.ts +136 -0
- package/src/files/archive.ts +2 -2
- package/src/files/job-names.ts +12 -0
- package/src/files/kinds.ts +19 -7
- package/src/files/scan.ts +3 -4
- package/src/files/streams.ts +3 -1
- package/src/implement/anonymous.ts +11 -1
- package/src/implement/boot.ts +61 -4
- package/src/implement/bounded.ts +21 -2
- package/src/implement/capability.ts +15 -3
- package/src/implement/dispatch.ts +249 -145
- package/src/implement/failures.ts +17 -1
- package/src/implement/faults.ts +1 -0
- package/src/implement/index.ts +1 -0
- package/src/implement/invocation.ts +8 -0
- package/src/implement/principal.ts +25 -2
- package/src/implement/terminals.ts +93 -0
- package/src/implement/workload.ts +24 -13
- package/src/jobs/report.ts +5 -1
- package/src/jobs/runner.ts +33 -17
- package/src/jobs/schedule.ts +7 -1
- package/src/jobs/scrub.ts +14 -1
- package/src/testing/endpoint-access.ts +180 -137
- package/src/testing/kit.ts +20 -2
- package/src/testing/proxy.ts +5 -5
- package/types/src/agent-skill.d.ts +29 -0
- package/types/src/build-recipe.d.ts +70 -0
- package/types/src/build.d.ts +29 -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/application.d.ts +42 -0
- package/types/src/cloudflare/bindings.d.ts +27 -0
- package/types/src/cloudflare/names.d.ts +6 -0
- package/types/src/cloudflare/ops.d.ts +46 -0
- package/types/src/cloudflare/r2-files.d.ts +9 -0
- package/types/src/cloudflare.d.ts +42 -0
- package/types/src/contract/app-id.d.ts +2 -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 +510 -0
- package/types/src/contract/declaration.d.ts +307 -0
- package/types/src/contract/defaults.d.ts +208 -0
- package/types/src/contract/define.d.ts +376 -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 +211 -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 +32 -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 +28 -0
- package/types/src/dev/wire.d.ts +126 -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/job-names.d.ts +9 -0
- package/types/src/files/kinds.d.ts +101 -0
- package/types/src/files/scan.d.ts +78 -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 +28 -0
- package/types/src/implement/attachment.d.ts +14 -0
- package/types/src/implement/boot.d.ts +114 -0
- package/types/src/implement/bounded.d.ts +32 -0
- package/types/src/implement/browser-config.d.ts +19 -0
- package/types/src/implement/capability.d.ts +142 -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 +220 -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 +39 -0
- package/types/src/implement/faults.d.ts +45 -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 +25 -0
- package/types/src/implement/invocation.d.ts +125 -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 +57 -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/terminals.d.ts +33 -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 +151 -0
- package/types/src/jobs/schedule.d.ts +17 -0
- package/types/src/jobs/scrub.d.ts +12 -0
- package/types/src/jobs/types.d.ts +98 -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 +107 -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 +187 -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,66 @@
|
|
|
1
|
+
import type { FileObjectStore } from '@fabrika/platform';
|
|
2
|
+
import type { FetchService, RequestExecutionContext } from './fetch.js';
|
|
3
|
+
import { type IamKeySource } from './implement/boot.js';
|
|
4
|
+
import { type CrashEvents } from './implement/crashes.js';
|
|
5
|
+
import { type ContractImplementation } from './implement/implement.js';
|
|
6
|
+
import { type JobRunOptions, type JobRunResult } from './jobs/runner.js';
|
|
7
|
+
export { diskAssets } from './disk-assets.js';
|
|
8
|
+
export { clamscanArguments, type ClamscanOptions, clamscanScanner } from './files/clamscan.js';
|
|
9
|
+
export { markProductionProcess } from '@fabrika/db/production';
|
|
10
|
+
export interface ManagedBunHandlerOptions {
|
|
11
|
+
/** Required sink for rejected background tasks. Do not log raw errors or secret-bearing values. */
|
|
12
|
+
onBackgroundError(error: unknown): void;
|
|
13
|
+
executionContext?: never;
|
|
14
|
+
}
|
|
15
|
+
export interface ExternalBunHandlerOptions {
|
|
16
|
+
/** Existing supervised process context. Its owner remains responsible for draining it. */
|
|
17
|
+
executionContext: RequestExecutionContext;
|
|
18
|
+
onBackgroundError?: never;
|
|
19
|
+
}
|
|
20
|
+
export type BunHandlerOptions = ManagedBunHandlerOptions | ExternalBunHandlerOptions;
|
|
21
|
+
export interface BunHandler {
|
|
22
|
+
fetch(request: Request): Promise<Response>;
|
|
23
|
+
/** Wait until every task registered through `waitUntil()` has settled. */
|
|
24
|
+
drain(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export declare function createBunHandler<Env>(app: FetchService<Env>, env: Env, options: BunHandlerOptions): BunHandler;
|
|
27
|
+
/** IAM's public key set at the issuer's `/.well-known/jwks.json`, for a process with no IAM binding. */
|
|
28
|
+
export declare function issuerJwks(issuer: unknown): IamKeySource;
|
|
29
|
+
export interface ContractServer {
|
|
30
|
+
/** The port the server listens on; `PORT=0` picks a free one. */
|
|
31
|
+
readonly port: number;
|
|
32
|
+
/** Stops accepting requests and waits for the ones in flight. */
|
|
33
|
+
stop(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The stored files' object storage (Zerops object storage, path-style), when the platform wrote its variables;
|
|
37
|
+
* a partial set stops the boot. The credentials are never quoted in a message.
|
|
38
|
+
*/
|
|
39
|
+
export declare function openFileStorage(framework: Readonly<Record<string, string>>): FileObjectStore | undefined;
|
|
40
|
+
/** The application module, imported only after the environment was captured: the generated entrypoint's `import()`. */
|
|
41
|
+
export type ImplementationLoader = () => Promise<{
|
|
42
|
+
readonly default: ContractImplementation;
|
|
43
|
+
}>;
|
|
44
|
+
export interface ContractServerOptions {
|
|
45
|
+
/** Where the process hears of an uncaught exception or an unhandled rejection; `process` by default. */
|
|
46
|
+
readonly crashes?: CrashEvents;
|
|
47
|
+
/** What posts a report to Operations' ingest; `fetch` by default. */
|
|
48
|
+
readonly operationsFetch?: (request: Request) => Promise<Response>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Captures the framework's variables and scrubs them from the process, then imports the application, boots it and
|
|
52
|
+
* serves it on `PORT` (default 3000), on every interface: the project's private network is how the proxy reaches
|
|
53
|
+
* it. Called only by the generated entrypoint, with `process.env`. SIGTERM drains. Given the provisioning credential,
|
|
54
|
+
* it is the launcher instead: it never loads the application and re-runs the entrypoint as the runtime role.
|
|
55
|
+
* With an Operations DSN, a startup that throws is reported before it is rethrown, and so is a crash once it serves.
|
|
56
|
+
*/
|
|
57
|
+
export declare function serveContract(load: ImplementationLoader, env: Readonly<Record<string, string | undefined>>, options?: ContractServerOptions): Promise<ContractServer>;
|
|
58
|
+
/** The application module at `path`, imported when the loader runs; its default export must be what `serve` returned. */
|
|
59
|
+
export declare function implementationAt(path: string): ImplementationLoader;
|
|
60
|
+
/**
|
|
61
|
+
* One run of the job `name` (`fabrika job run <name>`, the crontab's command): the framework's variables are captured
|
|
62
|
+
* and scrubbed before the application loads, exactly as `serveContract` does, then `boot` binds the job and the run
|
|
63
|
+
* takes its lease. The connection closes when the run ends. Given the provisioning credential, it re-runs the command
|
|
64
|
+
* as the runtime role, as `serveContract` does.
|
|
65
|
+
*/
|
|
66
|
+
export declare function runContractJob(load: ImplementationLoader, env: Readonly<Record<string, string | undefined>>, name: string, options?: JobRunOptions): Promise<JobRunResult>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
declare const PageCallerSchema: z.ZodObject<{
|
|
3
|
+
label: z.ZodString;
|
|
4
|
+
email: z.ZodString;
|
|
5
|
+
actions: z.ZodObject<{
|
|
6
|
+
/** The actions held as a global grant, so in every value. */
|
|
7
|
+
app: z.ZodArray<z.ZodString>;
|
|
8
|
+
/** Each scope value the person holds something in, with those actions; sorted by dimension, then value. */
|
|
9
|
+
scopes: z.ZodArray<z.ZodObject<{
|
|
10
|
+
type: z.ZodString;
|
|
11
|
+
value: z.ZodString;
|
|
12
|
+
actions: z.ZodArray<z.ZodString>;
|
|
13
|
+
}, z.core.$strict>>;
|
|
14
|
+
}, z.core.$strict>;
|
|
15
|
+
}, z.core.$strict>;
|
|
16
|
+
export type PageCaller = z.infer<typeof PageCallerSchema>;
|
|
17
|
+
/** The caller document as the framework answers it; throws on any other value. */
|
|
18
|
+
export declare function parsePageCaller(value: unknown): PageCaller;
|
|
19
|
+
export {};
|
|
@@ -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,42 @@
|
|
|
1
|
+
import { type SqliteStorage } from '@fabrika/db/sqlite';
|
|
2
|
+
import { type CrashEvents } from '../implement/crashes.js';
|
|
3
|
+
import type { ContractImplementation } from '../implement/implement.js';
|
|
4
|
+
import { type OpsStorage } from './ops.js';
|
|
5
|
+
/** The application module, imported only after the environment was captured: the generated entrypoint's `import()`. */
|
|
6
|
+
export type ImplementationLoader = () => Promise<{
|
|
7
|
+
readonly default: ContractImplementation;
|
|
8
|
+
}>;
|
|
9
|
+
/** One of the application's SQLite migrations, as `fabrika app build` bundles them from `db/migrations`. */
|
|
10
|
+
export interface ApplicationMigration {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly sql: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ContractWorkerOptions {
|
|
15
|
+
/** The application's own SQLite migrations, applied as the bundle `app` after the framework's `fabrika`. */
|
|
16
|
+
readonly migrations?: readonly ApplicationMigration[];
|
|
17
|
+
/** Where the isolate hears of an unhandled rejection; the global `unhandledrejection` event by default. */
|
|
18
|
+
readonly rejections?: CrashEvents;
|
|
19
|
+
/** What posts a report to Operations' ingest; `fetch` by default. */
|
|
20
|
+
readonly operationsFetch?: (request: Request) => Promise<Response>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Marks the Worker's minute tick, with its `scheduledTime`. The Worker's `fetch` removes it from every request it
|
|
24
|
+
* forwards, so only its own `scheduled` handler reaches the tick.
|
|
25
|
+
*/
|
|
26
|
+
export declare const TICK_HEADER = "X-Fabrika-Tick";
|
|
27
|
+
/** What the object needs of its `ctx.storage`; a Durable Object's `DurableObjectStorage` fits it. */
|
|
28
|
+
export type ApplicationStorage = SqliteStorage & OpsStorage;
|
|
29
|
+
/** What the object needs of its `DurableObjectState`. */
|
|
30
|
+
export interface ApplicationState {
|
|
31
|
+
readonly storage: ApplicationStorage;
|
|
32
|
+
blockConcurrencyWhile<T>(callback: () => Promise<T>): Promise<T>;
|
|
33
|
+
waitUntil(promise: Promise<unknown>): void;
|
|
34
|
+
}
|
|
35
|
+
/** What the object classes of this isolate boot: the generated entrypoint's `createContractWorker` registers it. */
|
|
36
|
+
export declare function registerApplication(load: ImplementationLoader, options: ContractWorkerOptions): void;
|
|
37
|
+
/** The application environment's one object. The Worker's generated entrypoint exports it as `FabrikaApplication`. */
|
|
38
|
+
export declare class FabrikaApplication {
|
|
39
|
+
#private;
|
|
40
|
+
constructor(state: ApplicationState, env: Readonly<Record<string, unknown>>);
|
|
41
|
+
fetch(request: Request): Promise<Response>;
|
|
42
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { IamMembershipRpc, IamTerminalRpc } from '@fabrika/auth-core';
|
|
2
|
+
import type { IamKeySource } from '../implement/boot.js';
|
|
3
|
+
import { type ConnectFetch } from '../implement/connect.js';
|
|
4
|
+
import type { SpaAssets } from '../implement/dispatch.js';
|
|
5
|
+
import type { WorkloadTokenSource } from '../implement/workload.js';
|
|
6
|
+
/** The method `name` of a binding, bound to it, or `null` when it has none. */
|
|
7
|
+
export declare function method(target: unknown, name: string): ((...args: unknown[]) => unknown) | null;
|
|
8
|
+
export declare function bindingKeySource(binding: unknown): IamKeySource;
|
|
9
|
+
/**
|
|
10
|
+
* IAM's membership operations on the `IAM` binding (`PropustkaApplication`), every answer decoded like the HTTP
|
|
11
|
+
* transport's. A binding without them is no membership transport, and `boot` refuses a contract that needs one.
|
|
12
|
+
*/
|
|
13
|
+
export declare function bindingMembership(binding: unknown): IamMembershipRpc | undefined;
|
|
14
|
+
/** The identifications at a terminal over the IAM binding, when its entrypoint serves them (ADR-0067). */
|
|
15
|
+
export declare function bindingTerminals(binding: unknown): IamTerminalRpc | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* IAM's token exchange on the `IAM` binding (`mintFromKey`), for the keys of the jobs, webhooks and public procedures.
|
|
18
|
+
* An answer that is not IAM's decided outcome throws: "IAM could not be asked".
|
|
19
|
+
*/
|
|
20
|
+
export declare function bindingWorkloadTokens(binding: unknown): WorkloadTokenSource | undefined;
|
|
21
|
+
export declare function bindingAssets(binding: unknown): SpaAssets | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* The service bindings to owners' proxy Workers (`FABRIKA_CONNECT_<IMPORT>`), which `captureEnvironment` keeps from
|
|
24
|
+
* the application because no `FABRIKA_*` value reaches it. A binding routes by itself: the URL it is called with
|
|
25
|
+
* carries the owner's host, which the proxy Worker selects the application by.
|
|
26
|
+
*/
|
|
27
|
+
export declare function connectBindings(env: Readonly<Record<string, unknown>>): Record<string, ConnectFetch>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** The Durable Object class the Cloudflare entry exports: one object per application environment runs it (ADR-0065). */
|
|
2
|
+
export declare const CLOUDFLARE_APPLICATION_CLASS = "FabrikaApplication";
|
|
3
|
+
/** The binding through which the application's Worker reaches its object. */
|
|
4
|
+
export declare const CLOUDFLARE_APPLICATION_BINDING = "FABRIKA_APPLICATION";
|
|
5
|
+
/** The R2 bucket binding of the environment's stored files. */
|
|
6
|
+
export declare const CLOUDFLARE_FILES_BINDING = "FABRIKA_FILES";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type ApplicationObjects, type OpsBootFailureContent, type OpsOperation } from '@fabrika/auth-core';
|
|
2
|
+
import type { SqliteCursor, SqliteValue } from '@fabrika/db/sqlite';
|
|
3
|
+
/** What the view reads of the object's storage; workerd's `DurableObjectStorage` has both optional members. */
|
|
4
|
+
export interface OpsStorage {
|
|
5
|
+
readonly sql: {
|
|
6
|
+
exec(query: string, ...bindings: SqliteValue[]): SqliteCursor;
|
|
7
|
+
/** The bun:sqlite test double has no size. */
|
|
8
|
+
readonly databaseSize?: number;
|
|
9
|
+
};
|
|
10
|
+
/** The bun:sqlite test double has no alarm. */
|
|
11
|
+
getAlarm?(): Promise<number | null>;
|
|
12
|
+
}
|
|
13
|
+
/** `X-Fabrika-Endpoint` of the composed ops row, the only value an ops request may carry (ADR-0022 rule 3). */
|
|
14
|
+
export declare const OPS_ENDPOINT: string;
|
|
15
|
+
/** What the platform wrote for the ops channel: the key digests and the objects a request may name. */
|
|
16
|
+
export interface OpsAccess {
|
|
17
|
+
readonly digests: readonly Uint8Array[];
|
|
18
|
+
readonly objects: ApplicationObjects;
|
|
19
|
+
}
|
|
20
|
+
/** The environment's ops access, or `null` (an older deploy, or a malformed value), which refuses every ops request. */
|
|
21
|
+
export declare function opsAccess(env: Readonly<Record<string, unknown>>): OpsAccess | null;
|
|
22
|
+
/** What an ops request reads of the object it reached. */
|
|
23
|
+
export interface OpsTarget {
|
|
24
|
+
readonly storage: OpsStorage;
|
|
25
|
+
/**
|
|
26
|
+
* The instance's last failed boot, the application's error text included. Asked only after authentication: it
|
|
27
|
+
* waits for a boot under way and never starts one.
|
|
28
|
+
*/
|
|
29
|
+
bootFailure(): Promise<OpsBootFailureContent | null>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Answers an ops request the Worker forwarded with the proxy secret, which the object checked before. Authentication
|
|
33
|
+
* runs first; an unknown operation, a malformed body and an object name the list lacks are refused after it.
|
|
34
|
+
*/
|
|
35
|
+
export declare function serveOps(request: Request, access: OpsAccess | null, target: OpsTarget): Promise<Response>;
|
|
36
|
+
/** The object an ops request names, read with its operation's strict parser; `null` for a body that does not parse. */
|
|
37
|
+
export declare function objectNamed(operation: OpsOperation, body: unknown): string | null;
|
|
38
|
+
/** The request's body as JSON, or `undefined` when it is none: every parser refuses `undefined`. */
|
|
39
|
+
export declare function jsonBody(request: {
|
|
40
|
+
text(): Promise<string>;
|
|
41
|
+
}): Promise<unknown>;
|
|
42
|
+
/**
|
|
43
|
+
* Control's credentials on an ops request: the row's method, its endpoint header, and a key whose digest is one the
|
|
44
|
+
* platform wrote, compared in constant time. The Worker and the object both run it; it reads nothing the body names.
|
|
45
|
+
*/
|
|
46
|
+
export declare function opsAuthenticated(request: Request, access: OpsAccess): boolean;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type FileObjectStore } from '@fabrika/platform';
|
|
2
|
+
/**
|
|
3
|
+
* R2 stores a stream only when its length is known up front, which an upload's is not. A body up to this size is
|
|
4
|
+
* buffered and written in one conditional put; a longer one goes up in parts of this size, so an object holds at most
|
|
5
|
+
* one part in memory. R2 takes parts of at least 5 MiB, all but the last of one size.
|
|
6
|
+
*/
|
|
7
|
+
export declare const R2_PART_BYTES: number;
|
|
8
|
+
/** `bucket` (an R2 binding) as the files' object store, or `undefined` when the environment binds none. */
|
|
9
|
+
export declare function r2FileObjectStore(bucket: unknown): FileObjectStore | undefined;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ContractWorkerOptions, type ImplementationLoader } from './cloudflare/application.js';
|
|
2
|
+
import type { FetchService, RequestExecutionContext } from './fetch.js';
|
|
3
|
+
export { markProductionProcess } from '@fabrika/db/production';
|
|
4
|
+
export { type ApplicationMigration, type ApplicationState, type ApplicationStorage, type ContractWorkerOptions, FabrikaApplication, type ImplementationLoader, } from './cloudflare/application.js';
|
|
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
|
+
export interface ContractWorker {
|
|
32
|
+
fetch(request: Request, env: Readonly<Record<string, unknown>>, exec: CloudflareExecutionContext): Promise<Response>;
|
|
33
|
+
scheduled(controller: CloudflareScheduledController, env: Readonly<Record<string, unknown>>, exec: CloudflareExecutionContext): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The Worker module of a contract application, called only by the generated entrypoint, which also exports
|
|
37
|
+
* `FabrikaApplication`. The application runs in the environment's Durable Object (ADR-0065): `fetch` forwards every
|
|
38
|
+
* request to it with the proxy secret, the proxy's own headers unchanged, and `scheduled` forwards the minute tick.
|
|
39
|
+
* An ops request goes to the object its body names instead (ADR-0069). The object captures the environment, imports
|
|
40
|
+
* the application and boots it.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createContractWorker(load: ImplementationLoader, options?: ContractWorkerOptions): ContractWorker;
|
|
@@ -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>;
|