@jimhoyd/urlcode 0.3.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/CONTRIBUTING.md +80 -0
- package/LICENSE +202 -0
- package/NOTICE +20 -0
- package/README.md +342 -0
- package/ROADMAP.md +248 -0
- package/SECURITY.md +40 -0
- package/data/agents/LICENSES/ai-robots-txt.txt +24 -0
- package/data/agents/LICENSES/crawler-user-agents.txt +23 -0
- package/data/agents/ai-crawlers.json +1240 -0
- package/data/agents/crawlers.json +10515 -0
- package/data/agents/index.d.ts +3 -0
- package/data/agents/index.js +2453 -0
- package/data/agents/monitoring.json +1520 -0
- package/data/agents/seo.json +3865 -0
- package/dist/BUILD-MANIFEST.json +60 -0
- package/dist/adapters.js +59 -0
- package/dist/agent-lists.js +59 -0
- package/dist/assets.js +129 -0
- package/dist/authoring.js +68 -0
- package/dist/aws.js +110 -0
- package/dist/build-cloudflare.js +164 -0
- package/dist/cli.js +185 -0
- package/dist/client-address.js +85 -0
- package/dist/cloudflare.js +165 -0
- package/dist/compliance-rules/baseline.js +98 -0
- package/dist/compliance-rules/privacy.js +38 -0
- package/dist/compliance-rules/shared.js +62 -0
- package/dist/compliance-rules/strict.js +61 -0
- package/dist/compliance.js +219 -0
- package/dist/config-worker.js +9 -0
- package/dist/config.js +172 -0
- package/dist/errors.js +8 -0
- package/dist/function-sources.js +54 -0
- package/dist/function-worker.js +105 -0
- package/dist/functions.js +174 -0
- package/dist/guest-api.js +114 -0
- package/dist/header-validation.js +18 -0
- package/dist/http-policy.js +74 -0
- package/dist/http-response.js +84 -0
- package/dist/index.js +11 -0
- package/dist/link-api.js +136 -0
- package/dist/link-cli.js +141 -0
- package/dist/link-events.js +76 -0
- package/dist/link-records.js +31 -0
- package/dist/link-store-worker.js +150 -0
- package/dist/link-store.js +250 -0
- package/dist/logging.js +22 -0
- package/dist/management-policy.js +41 -0
- package/dist/match.js +124 -0
- package/dist/observability.js +242 -0
- package/dist/plugins.js +74 -0
- package/dist/policies/agents.js +248 -0
- package/dist/policies/cache.js +297 -0
- package/dist/policies/compression.js +187 -0
- package/dist/policies/security.js +0 -0
- package/dist/policies/throttle.js +131 -0
- package/dist/policies.js +142 -0
- package/dist/policy.js +55 -0
- package/dist/prerender.js +165 -0
- package/dist/project-tests.js +23 -0
- package/dist/readiness.js +216 -0
- package/dist/router.js +166 -0
- package/dist/runtime.js +244 -0
- package/dist/scaffold.js +0 -0
- package/dist/scripts/operational-drills.js +75 -0
- package/dist/server.js +270 -0
- package/dist/site.js +0 -0
- package/dist/sqlite-version.js +6 -0
- package/dist/types/adapters.d.ts +12 -0
- package/dist/types/agent-lists.d.ts +5 -0
- package/dist/types/assets.d.ts +13 -0
- package/dist/types/authoring.d.ts +2 -0
- package/dist/types/aws.d.ts +35 -0
- package/dist/types/build-cloudflare.d.ts +14 -0
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/client-address.d.ts +9 -0
- package/dist/types/cloudflare.d.ts +75 -0
- package/dist/types/compliance-rules/baseline.d.ts +12 -0
- package/dist/types/compliance-rules/privacy.d.ts +6 -0
- package/dist/types/compliance-rules/shared.d.ts +24 -0
- package/dist/types/compliance-rules/strict.d.ts +9 -0
- package/dist/types/compliance.d.ts +119 -0
- package/dist/types/config-worker.d.ts +1 -0
- package/dist/types/config.d.ts +21 -0
- package/dist/types/errors.d.ts +7 -0
- package/dist/types/function-sources.d.ts +21 -0
- package/dist/types/function-worker.d.ts +1 -0
- package/dist/types/functions.d.ts +92 -0
- package/dist/types/guest-api.d.ts +16 -0
- package/dist/types/header-validation.d.ts +2 -0
- package/dist/types/http-policy.d.ts +39 -0
- package/dist/types/http-response.d.ts +43 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/link-api.d.ts +30 -0
- package/dist/types/link-cli.d.ts +36 -0
- package/dist/types/link-events.d.ts +27 -0
- package/dist/types/link-records.d.ts +11 -0
- package/dist/types/link-store-worker.d.ts +1 -0
- package/dist/types/link-store.d.ts +130 -0
- package/dist/types/logging.d.ts +9 -0
- package/dist/types/management-policy.d.ts +9 -0
- package/dist/types/match.d.ts +81 -0
- package/dist/types/observability.d.ts +104 -0
- package/dist/types/plugins.d.ts +27 -0
- package/dist/types/policies/agents.d.ts +86 -0
- package/dist/types/policies/cache.d.ts +82 -0
- package/dist/types/policies/compression.d.ts +41 -0
- package/dist/types/policies/security.d.ts +37 -0
- package/dist/types/policies/throttle.d.ts +55 -0
- package/dist/types/policies.d.ts +36 -0
- package/dist/types/policy.d.ts +21 -0
- package/dist/types/prerender.d.ts +31 -0
- package/dist/types/project-tests.d.ts +13 -0
- package/dist/types/readiness.d.ts +121 -0
- package/dist/types/router.d.ts +11 -0
- package/dist/types/runtime.d.ts +91 -0
- package/dist/types/scaffold.d.ts +17 -0
- package/dist/types/server.d.ts +37 -0
- package/dist/types/site.d.ts +12 -0
- package/dist/types/sqlite-version.d.ts +1 -0
- package/dist/types/types.d.ts +332 -0
- package/dist/types/vercel.d.ts +12 -0
- package/dist/types.js +177 -0
- package/dist/vercel.js +65 -0
- package/docs/AI-AUTHORING.md +113 -0
- package/docs/ASSETS.md +106 -0
- package/docs/AWS.md +77 -0
- package/docs/BEST-PRACTICES.md +267 -0
- package/docs/CAPACITY.md +208 -0
- package/docs/CLOUDFLARE.md +110 -0
- package/docs/COMPLIANCE.md +242 -0
- package/docs/DYNAMIC-LINKS.md +561 -0
- package/docs/FUNCTION-SECURITY.md +113 -0
- package/docs/HTTP.md +129 -0
- package/docs/INSTALL.md +90 -0
- package/docs/LOAD-TESTING.md +91 -0
- package/docs/LOCAL-DEVELOPMENT.md +99 -0
- package/docs/MANAGEMENT-SECURITY.md +82 -0
- package/docs/MIDDLEWARE.md +83 -0
- package/docs/MONITORING.md +132 -0
- package/docs/OBSERVABILITY.md +229 -0
- package/docs/OPERATIONAL-PROOF.md +42 -0
- package/docs/OPERATIONS.md +207 -0
- package/docs/ORGANIZATION.md +135 -0
- package/docs/PERFORMANCE.md +72 -0
- package/docs/PLUGINS.md +234 -0
- package/docs/POLICIES.md +489 -0
- package/docs/PRERENDER.md +193 -0
- package/docs/PROJECT-DIRECTION.md +51 -0
- package/docs/READINESS.md +125 -0
- package/docs/README.md +58 -0
- package/docs/RELEASE-READINESS.md +95 -0
- package/docs/RELEASE-SECURITY.md +72 -0
- package/docs/RESILIENCE.md +160 -0
- package/docs/ROUTING.md +95 -0
- package/docs/SANDBOX-REVIEW.md +59 -0
- package/docs/SCAFFOLDING.md +72 -0
- package/docs/SECURITY-AUDIT.md +124 -0
- package/docs/SITE.md +150 -0
- package/docs/SPECIFICATION.md +232 -0
- package/docs/SPIKE-EXTENSIONS.md +475 -0
- package/docs/STANDARDS.md +303 -0
- package/docs/STARTERS.md +51 -0
- package/docs/TUNNELS.md +75 -0
- package/docs/TYPESCRIPT.md +102 -0
- package/docs/VERCEL.md +107 -0
- package/docs/YAML-GUIDE.md +521 -0
- package/docs/YAML-REFERENCE.md +328 -0
- package/docs/policies/agents.md +182 -0
- package/docs/policies/cache.md +139 -0
- package/docs/policies/compression.md +168 -0
- package/docs/policies/security.md +160 -0
- package/docs/policies/throttle.md +103 -0
- package/examples/assets/.env.example +1 -0
- package/examples/assets/.gitattributes +2 -0
- package/examples/assets/Makefile +30 -0
- package/examples/assets/README.md +18 -0
- package/examples/assets/functions/hello.mjs +3 -0
- package/examples/assets/gitignore.template +7 -0
- package/examples/assets/public/about.html +2 -0
- package/examples/assets/public/assets/example.txt +1 -0
- package/examples/assets/public/guide.txt +1 -0
- package/examples/assets/tests/requests.json +44 -0
- package/examples/assets/urlcode.yaml +27 -0
- package/examples/aws/README.md +13 -0
- package/examples/aws/handler.mjs +5 -0
- package/examples/aws/public/index.html +3 -0
- package/examples/aws/public/notes.txt +1 -0
- package/examples/aws/template.yaml +33 -0
- package/examples/aws/tests/requests.json +9 -0
- package/examples/aws/urlcode.yaml +19 -0
- package/examples/cloudflare/README.md +18 -0
- package/examples/cloudflare/package.json +14 -0
- package/examples/cloudflare/tests/requests.json +9 -0
- package/examples/cloudflare/urlcode.yaml +24 -0
- package/examples/cloudflare/wrangler.toml +5 -0
- package/examples/compliance/README.md +20 -0
- package/examples/compliance/rules.mjs +65 -0
- package/examples/cookbook/README.md +21 -0
- package/examples/cookbook/functions/choice.mjs +4 -0
- package/examples/cookbook/functions/echo.mjs +3 -0
- package/examples/cookbook/functions/hello.mjs +3 -0
- package/examples/cookbook/functions/text.mjs +3 -0
- package/examples/cookbook/middleware/headers.mjs +6 -0
- package/examples/cookbook/public/about.html +1 -0
- package/examples/cookbook/public/assets/index.html +1 -0
- package/examples/cookbook/public/assets/site.css +1 -0
- package/examples/cookbook/public/favicon.svg +1 -0
- package/examples/cookbook/public/guide.txt +1 -0
- package/examples/cookbook/public/llms.txt +6 -0
- package/examples/cookbook/routes/code.yaml +55 -0
- package/examples/cookbook/routes/files.yaml +17 -0
- package/examples/cookbook/routes/policies.yaml +28 -0
- package/examples/cookbook/routes/redirects.yaml +38 -0
- package/examples/cookbook/routes/responses.yaml +26 -0
- package/examples/cookbook/tests/requests.json +254 -0
- package/examples/cookbook/urlcode.yaml +22 -0
- package/examples/live-links/README.md +11 -0
- package/examples/live-links/tests/requests.json +6 -0
- package/examples/live-links/urlcode.yaml +16 -0
- package/examples/monitoring/blackbox-jobs.yaml +37 -0
- package/examples/monitoring/prometheus-rules.yaml +88 -0
- package/examples/monitoring/prometheus-scrape.yaml +20 -0
- package/examples/monitoring/vector.toml +65 -0
- package/examples/prerender/README.md +48 -0
- package/examples/prerender/functions/page.mjs +6 -0
- package/examples/prerender/middleware/template.mjs +29 -0
- package/examples/prerender/prerender.d.mts +4 -0
- package/examples/prerender/prerender.mjs +63 -0
- package/examples/prerender/tests/requests.json +39 -0
- package/examples/prerender/urlcode.yaml +50 -0
- package/examples/tunnel/dev-with-ngrok.sh +61 -0
- package/examples/vercel/README.md +13 -0
- package/examples/vercel/api/index.js +5 -0
- package/examples/vercel/package.json +8 -0
- package/examples/vercel/public/index.html +3 -0
- package/examples/vercel/public/notes.txt +1 -0
- package/examples/vercel/tests/requests.json +48 -0
- package/examples/vercel/urlcode.yaml +19 -0
- package/examples/vercel/vercel.json +10 -0
- package/llms.txt +46 -0
- package/package.json +123 -0
- package/schemas/urlcode.schema.json +1230 -0
- package/starters/default/.gitattributes +1 -0
- package/starters/default/Makefile +30 -0
- package/starters/default/README.md +34 -0
- package/starters/default/functions/hello.mjs +3 -0
- package/starters/default/gitignore.template +8 -0
- package/starters/default/middleware/headers.mjs +6 -0
- package/starters/default/routes/functions.yaml +20 -0
- package/starters/default/routes/marketing/links.yaml +7 -0
- package/starters/default/starter.json +5 -0
- package/starters/default/tests/requests.json +56 -0
- package/starters/default/urlcode.yaml +8 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { LoadedDocument, ProjectDocument } from './types.ts';
|
|
2
|
+
/** What config-worker.ts posts back: the loaded document, or the ConfigError message. */
|
|
3
|
+
export type ConfigWorkerResult = {
|
|
4
|
+
value: LoadedDocument;
|
|
5
|
+
} | {
|
|
6
|
+
error: string;
|
|
7
|
+
};
|
|
8
|
+
export interface ConfigWorkerData {
|
|
9
|
+
project: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const MAX_CONFIG_BYTES: number;
|
|
12
|
+
export declare function parseYaml(text: string): unknown;
|
|
13
|
+
export declare function validateDocument(data: unknown): ProjectDocument;
|
|
14
|
+
export declare function safeFile(root: string, file: unknown): Promise<string>;
|
|
15
|
+
export declare const MAX_PROJECT_CONFIG_BYTES: number;
|
|
16
|
+
export declare function loadDocument(project: string, { timeoutMs }?: {
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
}): Promise<LoadedDocument>;
|
|
19
|
+
export declare function loadDocumentInWorker(project: string): Promise<LoadedDocument>;
|
|
20
|
+
export declare function loadBindings(root: string, local?: boolean, environment?: Record<string, string | undefined>): Promise<Record<string, string | undefined>>;
|
|
21
|
+
export declare function functionFile(root: string, file: string): Promise<string>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare class ConfigError extends Error {
|
|
2
|
+
}
|
|
3
|
+
export declare class HttpError extends Error {
|
|
4
|
+
readonly status: number;
|
|
5
|
+
constructor(status: number, message: string);
|
|
6
|
+
}
|
|
7
|
+
export declare function assert(condition: unknown, message: string): asserts condition;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** A function or middleware reference with its export named: what the sandbox loads. */
|
|
2
|
+
export interface FunctionDefinition {
|
|
3
|
+
source: string;
|
|
4
|
+
export: string;
|
|
5
|
+
}
|
|
6
|
+
/** Any route-like object carrying function definitions (a YAML route, whose `export` may be absent, or a compiled one). */
|
|
7
|
+
export interface FunctionRoute<D = FunctionDefinition> {
|
|
8
|
+
middleware?: D[] | undefined;
|
|
9
|
+
function?: D | undefined;
|
|
10
|
+
}
|
|
11
|
+
export interface FunctionSources {
|
|
12
|
+
/** Module source text keyed by project-relative name (`/lib/a.mjs`). */
|
|
13
|
+
sources: Record<string, string>;
|
|
14
|
+
dependencies: Record<string, string[]>;
|
|
15
|
+
/** Distinct [module, export] entry points. */
|
|
16
|
+
entries: [string, string][];
|
|
17
|
+
/** Absolute source path to module name. */
|
|
18
|
+
names: Map<string, string>;
|
|
19
|
+
}
|
|
20
|
+
export declare function routeFunctions<D>(route: FunctionRoute<D>): D[];
|
|
21
|
+
export declare function collectFunctionSources(routes: FunctionRoute[], root: string): Promise<FunctionSources>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Worker } from 'node:worker_threads';
|
|
2
|
+
import type { FunctionRoute, FunctionSources } from './function-sources.ts';
|
|
3
|
+
import type { HandlerResult, HeaderPair } from './http-response.ts';
|
|
4
|
+
import type { ParameterValue, RequestContext } from './match.ts';
|
|
5
|
+
import type { LogFn } from './types.ts';
|
|
6
|
+
import type { GuestRequestPayload } from './guest-api.ts';
|
|
7
|
+
export type { FunctionDefinition, FunctionRoute } from './function-sources.ts';
|
|
8
|
+
export type { GuestRequestPayload, GuestResponsePayload } from './guest-api.ts';
|
|
9
|
+
export interface FunctionPoolOptions {
|
|
10
|
+
root?: string | undefined;
|
|
11
|
+
snapshot?: FunctionSources | undefined;
|
|
12
|
+
workers?: number | undefined;
|
|
13
|
+
timeoutMs?: number | undefined;
|
|
14
|
+
maxBytes?: number | undefined;
|
|
15
|
+
log?: LogFn | undefined;
|
|
16
|
+
}
|
|
17
|
+
export interface FunctionWorkerData {
|
|
18
|
+
sources: Record<string, string>;
|
|
19
|
+
dependencies: Record<string, string[]>;
|
|
20
|
+
entries: [string, string][];
|
|
21
|
+
}
|
|
22
|
+
export type FunctionContext = RequestContext & {
|
|
23
|
+
args?: Record<string, ParameterValue>;
|
|
24
|
+
};
|
|
25
|
+
export interface FunctionWorkerRequest {
|
|
26
|
+
id: string;
|
|
27
|
+
source: string | undefined;
|
|
28
|
+
name: string | undefined;
|
|
29
|
+
chain: {
|
|
30
|
+
source: string | undefined;
|
|
31
|
+
name: string;
|
|
32
|
+
}[];
|
|
33
|
+
native: {
|
|
34
|
+
status: number;
|
|
35
|
+
headers: HeaderPair[];
|
|
36
|
+
} | undefined;
|
|
37
|
+
request: GuestRequestPayload;
|
|
38
|
+
context: FunctionContext;
|
|
39
|
+
maxBytes: number;
|
|
40
|
+
timeoutMs: number;
|
|
41
|
+
}
|
|
42
|
+
export interface FunctionResult extends HandlerResult {
|
|
43
|
+
nativeBody?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export type FunctionWorkerMessage = {
|
|
46
|
+
ready: true;
|
|
47
|
+
} | {
|
|
48
|
+
startupError: true;
|
|
49
|
+
} | {
|
|
50
|
+
id: string;
|
|
51
|
+
status: number;
|
|
52
|
+
headers: HeaderPair[];
|
|
53
|
+
body: Uint8Array;
|
|
54
|
+
nativeBody: boolean;
|
|
55
|
+
} | {
|
|
56
|
+
id: string;
|
|
57
|
+
error: true;
|
|
58
|
+
};
|
|
59
|
+
interface Pending {
|
|
60
|
+
id: string;
|
|
61
|
+
timer: NodeJS.Timeout;
|
|
62
|
+
resolve: (message: FunctionResult) => void;
|
|
63
|
+
reject: (error: Error) => void;
|
|
64
|
+
}
|
|
65
|
+
interface Slot {
|
|
66
|
+
worker: Worker;
|
|
67
|
+
ready: boolean;
|
|
68
|
+
pending: Pending | null;
|
|
69
|
+
}
|
|
70
|
+
export declare class FunctionPool {
|
|
71
|
+
root: string | undefined;
|
|
72
|
+
routes: FunctionRoute[];
|
|
73
|
+
preparedSnapshot: FunctionSources | undefined;
|
|
74
|
+
snapshot: FunctionSources | undefined;
|
|
75
|
+
restarts: Map<number, number>;
|
|
76
|
+
restartTimers: Set<NodeJS.Timeout>;
|
|
77
|
+
log: LogFn;
|
|
78
|
+
timeoutMs: number;
|
|
79
|
+
maxBytes: number;
|
|
80
|
+
modules: [string, string[]][];
|
|
81
|
+
size: number;
|
|
82
|
+
slots: (Slot | undefined)[];
|
|
83
|
+
closed: boolean;
|
|
84
|
+
constructor(routes: FunctionRoute[], { root, snapshot, workers, timeoutMs, maxBytes, log }?: FunctionPoolOptions);
|
|
85
|
+
start(): Promise<this>;
|
|
86
|
+
spawn(index: number): Promise<void>;
|
|
87
|
+
report(status: string, index: number, extra?: object): void;
|
|
88
|
+
scheduleRespawn(index: number): void;
|
|
89
|
+
get healthy(): boolean;
|
|
90
|
+
execute(route: FunctionRoute, request: GuestRequestPayload, context: FunctionContext, native: HandlerResult | undefined): Promise<FunctionResult>;
|
|
91
|
+
close(): Promise<void>;
|
|
92
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HeaderPair } from './http-response.ts';
|
|
2
|
+
/** The request the guest receives (stringified as JSON in the worker). */
|
|
3
|
+
export interface GuestRequestPayload {
|
|
4
|
+
url: string;
|
|
5
|
+
method: string;
|
|
6
|
+
headers: HeaderPair[];
|
|
7
|
+
body?: Uint8Array | undefined;
|
|
8
|
+
}
|
|
9
|
+
/** What the guest returns as JSON text; the worker enforces this shape before trusting it. */
|
|
10
|
+
export interface GuestResponsePayload {
|
|
11
|
+
status: number;
|
|
12
|
+
headers: HeaderPair[];
|
|
13
|
+
body: string;
|
|
14
|
+
nativeBody?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare const guestBootstrap: string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { HandlerResult, HeaderPair } from './http-response.ts';
|
|
2
|
+
import type { HeadersLike } from './match.ts';
|
|
3
|
+
export interface RespondSpec {
|
|
4
|
+
status?: number;
|
|
5
|
+
json?: unknown;
|
|
6
|
+
text?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface RequestBodyPolicy {
|
|
9
|
+
maxBytes?: number;
|
|
10
|
+
required?: boolean;
|
|
11
|
+
contentTypes?: string[];
|
|
12
|
+
format?: 'json' | 'text';
|
|
13
|
+
}
|
|
14
|
+
/** A static reply compiled from `respond`; the body is bytes so every host, including the Worker, shares the type. */
|
|
15
|
+
export interface Reply {
|
|
16
|
+
status: number;
|
|
17
|
+
headers: HeaderPair[];
|
|
18
|
+
body: Uint8Array;
|
|
19
|
+
}
|
|
20
|
+
/** The declared HTTP surface of a route: response headers, request body policy and a static reply. */
|
|
21
|
+
export interface HttpRoute {
|
|
22
|
+
response?: {
|
|
23
|
+
headers?: Record<string, string | string[]>;
|
|
24
|
+
};
|
|
25
|
+
request?: {
|
|
26
|
+
body?: RequestBodyPolicy;
|
|
27
|
+
};
|
|
28
|
+
respond?: RespondSpec;
|
|
29
|
+
page?: unknown;
|
|
30
|
+
static?: unknown;
|
|
31
|
+
download?: unknown;
|
|
32
|
+
responseHeaders?: HeaderPair[];
|
|
33
|
+
reply?: Reply | undefined;
|
|
34
|
+
}
|
|
35
|
+
export declare function compileHttp(route: HttpRoute): void;
|
|
36
|
+
export declare function checkRequest(route: HttpRoute, body: Uint8Array, headers: HeadersLike, counts?: Record<string, number>): void;
|
|
37
|
+
export declare function decorateResponse(route: HttpRoute & {
|
|
38
|
+
responseHeaders: HeaderPair[];
|
|
39
|
+
}, result: HandlerResult): HandlerResult;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type HeaderPair = [string, string];
|
|
2
|
+
export type ResponseBody = string | Uint8Array | null | undefined;
|
|
3
|
+
/** What a handler, policy or asset produced; every host turns it into a wire response here. */
|
|
4
|
+
export interface HandlerResult {
|
|
5
|
+
status: number;
|
|
6
|
+
headers: HeaderPair[];
|
|
7
|
+
body?: ResponseBody;
|
|
8
|
+
contentLength?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface PreparedResponse {
|
|
11
|
+
status: number;
|
|
12
|
+
headers: HeaderPair[];
|
|
13
|
+
cookies: string[];
|
|
14
|
+
body: ResponseBody;
|
|
15
|
+
}
|
|
16
|
+
export interface ErrorAnswer {
|
|
17
|
+
status: number;
|
|
18
|
+
headers: HeaderPair[];
|
|
19
|
+
body: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
export interface ResponseOptions {
|
|
22
|
+
requestId: string;
|
|
23
|
+
method: string;
|
|
24
|
+
}
|
|
25
|
+
/** The node:http ServerResponse surface this module writes to, kept structural so the module stays Node-free. */
|
|
26
|
+
export interface ResponseWriter {
|
|
27
|
+
statusCode: number;
|
|
28
|
+
headersSent: boolean;
|
|
29
|
+
setHeader(name: string, value: string | string[]): unknown;
|
|
30
|
+
getHeaderNames(): string[];
|
|
31
|
+
removeHeader(name: string): void;
|
|
32
|
+
end(body?: ResponseBody): unknown;
|
|
33
|
+
destroy(): unknown;
|
|
34
|
+
}
|
|
35
|
+
export declare const forbiddenHeaders: Set<string>;
|
|
36
|
+
export declare function prepareResponse(result: HandlerResult, { requestId, method }: ResponseOptions): PreparedResponse;
|
|
37
|
+
export declare function writeResponse(res: ResponseWriter, result: HandlerResult, options: ResponseOptions): number;
|
|
38
|
+
export declare function errorResponse(error: unknown, { requestId, method, headers }: ResponseOptions & {
|
|
39
|
+
headers?: HeaderPair[];
|
|
40
|
+
}): ErrorAnswer;
|
|
41
|
+
export declare function writeError(res: ResponseWriter, error: unknown, options: ResponseOptions & {
|
|
42
|
+
headers?: HeaderPair[];
|
|
43
|
+
}): number;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { createRuntime } from './runtime.ts';
|
|
2
|
+
export type { Runtime, RuntimeOptions, RuntimeRequest, RequestTrace, LinkReader, LinkStoreBinding, HostPlugin, Observer, TestPlan } from './runtime.ts';
|
|
3
|
+
export { startServer } from './server.ts';
|
|
4
|
+
export type { Server, ServerOptions } from './server.ts';
|
|
5
|
+
export { loadDocument, validateDocument, parseYaml } from './config.ts';
|
|
6
|
+
export { openLinkStore } from './link-store.ts';
|
|
7
|
+
export type { LinkStore, LinkRow, LinkStoreOptions } from './link-store.ts';
|
|
8
|
+
export { startLinkApi } from './link-api.ts';
|
|
9
|
+
export type { LinkApi, LinkApiOptions } from './link-api.ts';
|
|
10
|
+
export type { LinkEvent, LinkObserverOptions, LinkObserverStats } from './link-events.ts';
|
|
11
|
+
export { events as observabilityEvents, validateObservers, createObserverSink, createMetrics, renderPrometheus } from './observability.ts';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AddressInfo } from 'node:net';
|
|
2
|
+
import type { AuditIdentity, LinkRow, ListOptions } from './link-store.ts';
|
|
3
|
+
import type { ManagementAuthorizer } from './management-policy.ts';
|
|
4
|
+
import type { LogFn } from './types.ts';
|
|
5
|
+
/** The store surface management needs: the pooled link store, or anything with the same contract. */
|
|
6
|
+
export interface ManagementStore {
|
|
7
|
+
readonly atomicAudit?: boolean;
|
|
8
|
+
get(collection: string, code: string): Promise<LinkRow | null>;
|
|
9
|
+
list(collection: string, options?: ListOptions): Promise<LinkRow[]>;
|
|
10
|
+
create(collection: string, data: unknown, code?: unknown, audit?: AuditIdentity | undefined): Promise<LinkRow>;
|
|
11
|
+
update(collection: string, code: string, data: unknown, expectedVersion: unknown, audit?: AuditIdentity | undefined): Promise<LinkRow>;
|
|
12
|
+
delete(collection: string, code: string, expectedVersion: unknown, audit?: AuditIdentity | undefined): Promise<boolean>;
|
|
13
|
+
}
|
|
14
|
+
export interface LinkApiOptions {
|
|
15
|
+
store: ManagementStore;
|
|
16
|
+
collection: string;
|
|
17
|
+
token?: string | undefined;
|
|
18
|
+
authorize?: ManagementAuthorizer | undefined;
|
|
19
|
+
host?: string | undefined;
|
|
20
|
+
port?: number | undefined;
|
|
21
|
+
maxInFlightRequests?: number | undefined;
|
|
22
|
+
socketTimeoutMs?: number | undefined;
|
|
23
|
+
log?: LogFn | undefined;
|
|
24
|
+
}
|
|
25
|
+
export interface LinkApi {
|
|
26
|
+
address: AddressInfo;
|
|
27
|
+
close(): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
export declare function loadLinkToken(file: unknown, project: string): Promise<string>;
|
|
30
|
+
export declare function startLinkApi({ store, collection, token, authorize, host, port, maxInFlightRequests, socketTimeoutMs, log }: LinkApiOptions): Promise<LinkApi>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** The parsed command-line values the links commands read; every flag is a string or absent. */
|
|
2
|
+
export interface LinkCommandValues {
|
|
3
|
+
project?: string | undefined;
|
|
4
|
+
store?: string | undefined;
|
|
5
|
+
collection?: string | undefined;
|
|
6
|
+
code?: string | undefined;
|
|
7
|
+
destination?: string | undefined;
|
|
8
|
+
status?: string | undefined;
|
|
9
|
+
enabled?: string | undefined;
|
|
10
|
+
expires?: string | undefined;
|
|
11
|
+
'if-version'?: string | undefined;
|
|
12
|
+
limit?: string | undefined;
|
|
13
|
+
after?: string | undefined;
|
|
14
|
+
input?: string | undefined;
|
|
15
|
+
'page-size'?: string | undefined;
|
|
16
|
+
'auth-file'?: string | undefined;
|
|
17
|
+
'token-file'?: string | undefined;
|
|
18
|
+
port?: string | undefined;
|
|
19
|
+
host?: string | undefined;
|
|
20
|
+
'link-readers'?: string | undefined;
|
|
21
|
+
'link-read-limit'?: string | undefined;
|
|
22
|
+
'link-write-limit'?: string | undefined;
|
|
23
|
+
}
|
|
24
|
+
export type Print = (value: unknown) => unknown;
|
|
25
|
+
export interface LinkPoolOptions {
|
|
26
|
+
readers?: number;
|
|
27
|
+
maxReads?: number;
|
|
28
|
+
maxWrites?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface LinkBinding extends LinkPoolOptions {
|
|
31
|
+
collection: string;
|
|
32
|
+
file: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function linkPoolOptions(values: LinkCommandValues): LinkPoolOptions;
|
|
35
|
+
export declare function parseLinkBinding(value: string | undefined, options?: LinkPoolOptions): LinkBinding | undefined;
|
|
36
|
+
export declare function runLinkCommand(action: string | undefined, values: LinkCommandValues, print: Print): Promise<void>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface LinkEvent {
|
|
2
|
+
outcome: string;
|
|
3
|
+
code?: string | null;
|
|
4
|
+
[field: string]: unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface LinkObserverOptions {
|
|
7
|
+
observe: (event: LinkEvent) => unknown;
|
|
8
|
+
includeCode?: boolean;
|
|
9
|
+
maxQueue?: number;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface LinkObserverStats {
|
|
13
|
+
queued: number;
|
|
14
|
+
delivered: number;
|
|
15
|
+
dropped: number;
|
|
16
|
+
failed: number;
|
|
17
|
+
timedOut: number;
|
|
18
|
+
closed: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface LinkObserver {
|
|
21
|
+
emit(event: LinkEvent): void;
|
|
22
|
+
stats(): LinkObserverStats;
|
|
23
|
+
close(): Promise<LinkObserverStats>;
|
|
24
|
+
}
|
|
25
|
+
type Log = (event: Record<string, unknown>) => void;
|
|
26
|
+
export declare function createLinkObserver(options: unknown, log?: Log): LinkObserver | undefined;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface LinkRecord {
|
|
2
|
+
url: string;
|
|
3
|
+
status: number;
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
expires: string | null;
|
|
6
|
+
}
|
|
7
|
+
export declare function linkCollection(value: unknown): string;
|
|
8
|
+
export declare function linkCode(value: unknown): string;
|
|
9
|
+
export declare function linkVersion(value: unknown): number;
|
|
10
|
+
export declare function linkData(value: unknown): LinkRecord;
|
|
11
|
+
export declare const randomLinkCode: () => string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { LinkRecord } from './link-records.ts';
|
|
2
|
+
import type { LogFn } from './types.ts';
|
|
3
|
+
/** A stored link as the worker returns it. */
|
|
4
|
+
export interface LinkRow extends LinkRecord {
|
|
5
|
+
collection: string;
|
|
6
|
+
code: string;
|
|
7
|
+
version: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ListOptions {
|
|
10
|
+
limit?: number | undefined;
|
|
11
|
+
after?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
export interface AuditIdentity {
|
|
14
|
+
actor?: string | undefined;
|
|
15
|
+
requestId?: string | undefined;
|
|
16
|
+
}
|
|
17
|
+
export interface ExportHeader {
|
|
18
|
+
format: string;
|
|
19
|
+
schemaVersion: number;
|
|
20
|
+
applicationId: number;
|
|
21
|
+
collection: string | null;
|
|
22
|
+
revision: number;
|
|
23
|
+
records: number;
|
|
24
|
+
generatedAt: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ExportPageOptions {
|
|
27
|
+
afterCollection?: string | undefined;
|
|
28
|
+
afterCode?: string | undefined;
|
|
29
|
+
limit?: number | undefined;
|
|
30
|
+
}
|
|
31
|
+
export interface ExportOptions {
|
|
32
|
+
collection?: string | undefined;
|
|
33
|
+
pageSize?: number | undefined;
|
|
34
|
+
deadlineMs?: number | undefined;
|
|
35
|
+
}
|
|
36
|
+
export interface ExportHandlers {
|
|
37
|
+
onHeader?: ((header: ExportHeader) => unknown) | undefined;
|
|
38
|
+
onRecords?: ((records: LinkRow[]) => unknown) | undefined;
|
|
39
|
+
}
|
|
40
|
+
export interface ExportSummary extends ExportHeader {
|
|
41
|
+
exported: number;
|
|
42
|
+
}
|
|
43
|
+
export interface PoolStats {
|
|
44
|
+
connections: number;
|
|
45
|
+
healthyConnections: number;
|
|
46
|
+
limit: number;
|
|
47
|
+
inFlight: number;
|
|
48
|
+
completed: number;
|
|
49
|
+
failed: number;
|
|
50
|
+
rejected: number;
|
|
51
|
+
durationMs: number;
|
|
52
|
+
}
|
|
53
|
+
export interface LinkStoreStats {
|
|
54
|
+
closed: boolean;
|
|
55
|
+
exporting: boolean;
|
|
56
|
+
read: PoolStats;
|
|
57
|
+
write: PoolStats;
|
|
58
|
+
}
|
|
59
|
+
export interface LinkStoreWorkerData {
|
|
60
|
+
file: string;
|
|
61
|
+
readOnly: boolean;
|
|
62
|
+
}
|
|
63
|
+
export type LinkStoreOperation = 'get' | 'list' | 'create' | 'update' | 'delete' | 'exportBegin' | 'exportPage' | 'exportEnd' | 'close';
|
|
64
|
+
export interface LinkStoreArgs extends ListOptions, ExportPageOptions {
|
|
65
|
+
collection?: string | undefined;
|
|
66
|
+
code?: unknown;
|
|
67
|
+
data?: unknown;
|
|
68
|
+
expectedVersion?: unknown;
|
|
69
|
+
audit?: AuditIdentity | undefined;
|
|
70
|
+
}
|
|
71
|
+
export interface LinkStoreCommand {
|
|
72
|
+
id: number;
|
|
73
|
+
operation: LinkStoreOperation;
|
|
74
|
+
args: LinkStoreArgs;
|
|
75
|
+
}
|
|
76
|
+
export type LinkStoreReply = {
|
|
77
|
+
ready: true;
|
|
78
|
+
} | {
|
|
79
|
+
failed: true;
|
|
80
|
+
} | {
|
|
81
|
+
id: number;
|
|
82
|
+
value: unknown;
|
|
83
|
+
} | {
|
|
84
|
+
id: number;
|
|
85
|
+
error: {
|
|
86
|
+
status: number;
|
|
87
|
+
message: string;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
/** One worker-backed SQLite connection. */
|
|
91
|
+
export interface LinkConnection {
|
|
92
|
+
readonly healthy: boolean;
|
|
93
|
+
get(collection: string, code: string): Promise<LinkRow | null>;
|
|
94
|
+
list(collection: string, options?: ListOptions): Promise<LinkRow[]>;
|
|
95
|
+
exportBegin(options?: {
|
|
96
|
+
collection?: string | undefined;
|
|
97
|
+
}): Promise<ExportHeader>;
|
|
98
|
+
exportPage(options?: ExportPageOptions): Promise<LinkRow[]>;
|
|
99
|
+
exportEnd(): Promise<boolean>;
|
|
100
|
+
create(collection: string, data: unknown, code?: unknown, audit?: AuditIdentity | undefined): Promise<LinkRow>;
|
|
101
|
+
update(collection: string, code: string, data: unknown, expectedVersion: unknown, audit?: AuditIdentity | undefined): Promise<LinkRow>;
|
|
102
|
+
delete(collection: string, code: string, expectedVersion: unknown, audit?: AuditIdentity | undefined): Promise<boolean>;
|
|
103
|
+
close(): Promise<void>;
|
|
104
|
+
}
|
|
105
|
+
/** The pooled store openLinkStore returns. */
|
|
106
|
+
export interface LinkStore {
|
|
107
|
+
readonly readHealthy: boolean;
|
|
108
|
+
readonly writeHealthy: boolean;
|
|
109
|
+
readonly healthy: boolean;
|
|
110
|
+
readonly atomicAudit: true;
|
|
111
|
+
stats(): LinkStoreStats;
|
|
112
|
+
exportSnapshot(options?: ExportOptions, handlers?: ExportHandlers): Promise<ExportSummary>;
|
|
113
|
+
get(collection: string, code: string): Promise<LinkRow | null>;
|
|
114
|
+
list(collection: string, options?: ListOptions): Promise<LinkRow[]>;
|
|
115
|
+
create(collection: string, data: unknown, code?: unknown, audit?: AuditIdentity | undefined): Promise<LinkRow>;
|
|
116
|
+
update(collection: string, code: string, data: unknown, expectedVersion: unknown, audit?: AuditIdentity | undefined): Promise<LinkRow>;
|
|
117
|
+
delete(collection: string, code: string, expectedVersion: unknown, audit?: AuditIdentity | undefined): Promise<boolean>;
|
|
118
|
+
close(): Promise<void>;
|
|
119
|
+
}
|
|
120
|
+
export interface LinkStoreOptions {
|
|
121
|
+
file?: string | undefined;
|
|
122
|
+
project?: string | undefined;
|
|
123
|
+
readOnly?: boolean | undefined;
|
|
124
|
+
readers?: number | undefined;
|
|
125
|
+
maxReads?: number | undefined;
|
|
126
|
+
maxWrites?: number | undefined;
|
|
127
|
+
log?: LogFn | undefined;
|
|
128
|
+
}
|
|
129
|
+
export declare function outsideProject(file: unknown, project: string): Promise<string>;
|
|
130
|
+
export declare function openLinkStore({ file, project, readOnly, readers, maxReads, maxWrites, log }?: LinkStoreOptions): Promise<LinkStore>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type JsonLogger = (event: object) => void;
|
|
2
|
+
/** What the logger needs from its sink: the members of a Writable it touches. process.stdout satisfies it. */
|
|
3
|
+
export interface LogSink {
|
|
4
|
+
write(chunk: string): unknown;
|
|
5
|
+
writableLength: number;
|
|
6
|
+
destroyed?: boolean;
|
|
7
|
+
on?(event: 'error', listener: () => void): unknown;
|
|
8
|
+
}
|
|
9
|
+
export declare function createJsonLogger(stream?: LogSink, maxBufferBytes?: number): JsonLogger;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ManagementAction = 'get' | 'list' | 'create' | 'update' | 'delete';
|
|
2
|
+
/** A credential from the operator's management policy file, once it authenticated a request. */
|
|
3
|
+
export interface ManagementPrincipal {
|
|
4
|
+
id: string;
|
|
5
|
+
collections: string[];
|
|
6
|
+
actions: string[];
|
|
7
|
+
}
|
|
8
|
+
export type ManagementAuthorizer = (token: string) => Promise<ManagementPrincipal | undefined>;
|
|
9
|
+
export declare function managementPolicy(file: unknown, project: string): Promise<ManagementAuthorizer>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export type ParameterLocation = 'path' | 'query' | 'header';
|
|
2
|
+
export type ScalarType = 'string' | 'integer' | 'number' | 'boolean';
|
|
3
|
+
export type Scalar = string | number | boolean;
|
|
4
|
+
/** A parsed scalar, a parsed array, or a schema default (which the schema may shape freely). */
|
|
5
|
+
export type ParameterValue = Scalar | Scalar[] | unknown;
|
|
6
|
+
export interface ParameterSchema {
|
|
7
|
+
type: ScalarType | 'array';
|
|
8
|
+
items?: {
|
|
9
|
+
type: ScalarType;
|
|
10
|
+
};
|
|
11
|
+
default?: unknown;
|
|
12
|
+
[keyword: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
export interface CompiledParameter {
|
|
15
|
+
name: string;
|
|
16
|
+
in: ParameterLocation;
|
|
17
|
+
required: boolean;
|
|
18
|
+
schema: ParameterSchema;
|
|
19
|
+
validate: (value: unknown) => boolean;
|
|
20
|
+
}
|
|
21
|
+
/** A value taken from a request input or a binding when a redirect is assembled. */
|
|
22
|
+
export interface ValueRef {
|
|
23
|
+
from?: ParameterLocation;
|
|
24
|
+
name?: string;
|
|
25
|
+
env?: string;
|
|
26
|
+
secret?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface RedirectSpec {
|
|
29
|
+
url: string;
|
|
30
|
+
query?: {
|
|
31
|
+
map?: Record<string, ValueRef | Scalar>;
|
|
32
|
+
pass?: string[];
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** The part of a compiled route that request-time matching reads. router.ts widens it. */
|
|
36
|
+
export interface MatchableRoute {
|
|
37
|
+
pattern: string;
|
|
38
|
+
parts: string[];
|
|
39
|
+
prefix?: string;
|
|
40
|
+
parameters: CompiledParameter[];
|
|
41
|
+
env: Record<string, string>;
|
|
42
|
+
secrets: Record<string, string>;
|
|
43
|
+
redirect?: RedirectSpec;
|
|
44
|
+
}
|
|
45
|
+
export interface CompiledRoutes<R extends MatchableRoute = MatchableRoute> {
|
|
46
|
+
exact: Map<string, R>;
|
|
47
|
+
byLength: Map<number, R[]>;
|
|
48
|
+
mounts: R[];
|
|
49
|
+
}
|
|
50
|
+
export interface Target {
|
|
51
|
+
path: string;
|
|
52
|
+
parts: string[];
|
|
53
|
+
query: URLSearchParams;
|
|
54
|
+
}
|
|
55
|
+
export interface Match<R extends MatchableRoute = MatchableRoute> {
|
|
56
|
+
route: R;
|
|
57
|
+
path: Record<string, string>;
|
|
58
|
+
}
|
|
59
|
+
export interface Inputs {
|
|
60
|
+
path: Record<string, string>;
|
|
61
|
+
query: Record<string, ParameterValue>;
|
|
62
|
+
header: Record<string, ParameterValue>;
|
|
63
|
+
}
|
|
64
|
+
export interface RequestContext {
|
|
65
|
+
inputs: Inputs;
|
|
66
|
+
env: Record<string, string>;
|
|
67
|
+
secrets: Record<string, string>;
|
|
68
|
+
}
|
|
69
|
+
/** The subset of Headers both a node:http-derived map and the Fetch Headers class provide. */
|
|
70
|
+
export interface HeadersLike {
|
|
71
|
+
has(name: string): boolean;
|
|
72
|
+
get(name: string): string | null | undefined;
|
|
73
|
+
}
|
|
74
|
+
export declare function parameterName(segment: string): string | null;
|
|
75
|
+
export declare function resolveValue(ref: ValueRef | Scalar | null | undefined, context: RequestContext): ParameterValue;
|
|
76
|
+
export declare function parseTarget(target: string): Target;
|
|
77
|
+
export declare function matchRoute<R extends MatchableRoute>(compiled: CompiledRoutes<R>, target: Target): Match<R> | null;
|
|
78
|
+
export declare function contextFor(route: MatchableRoute, path: Record<string, string>, query: URLSearchParams, headers: HeadersLike, headerCounts?: Record<string, number>): RequestContext;
|
|
79
|
+
export declare function redirectLocation(route: MatchableRoute & {
|
|
80
|
+
redirect: RedirectSpec;
|
|
81
|
+
}, context: RequestContext, query: URLSearchParams): string;
|