@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.
Files changed (254) hide show
  1. package/CONTRIBUTING.md +80 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +20 -0
  4. package/README.md +342 -0
  5. package/ROADMAP.md +248 -0
  6. package/SECURITY.md +40 -0
  7. package/data/agents/LICENSES/ai-robots-txt.txt +24 -0
  8. package/data/agents/LICENSES/crawler-user-agents.txt +23 -0
  9. package/data/agents/ai-crawlers.json +1240 -0
  10. package/data/agents/crawlers.json +10515 -0
  11. package/data/agents/index.d.ts +3 -0
  12. package/data/agents/index.js +2453 -0
  13. package/data/agents/monitoring.json +1520 -0
  14. package/data/agents/seo.json +3865 -0
  15. package/dist/BUILD-MANIFEST.json +60 -0
  16. package/dist/adapters.js +59 -0
  17. package/dist/agent-lists.js +59 -0
  18. package/dist/assets.js +129 -0
  19. package/dist/authoring.js +68 -0
  20. package/dist/aws.js +110 -0
  21. package/dist/build-cloudflare.js +164 -0
  22. package/dist/cli.js +185 -0
  23. package/dist/client-address.js +85 -0
  24. package/dist/cloudflare.js +165 -0
  25. package/dist/compliance-rules/baseline.js +98 -0
  26. package/dist/compliance-rules/privacy.js +38 -0
  27. package/dist/compliance-rules/shared.js +62 -0
  28. package/dist/compliance-rules/strict.js +61 -0
  29. package/dist/compliance.js +219 -0
  30. package/dist/config-worker.js +9 -0
  31. package/dist/config.js +172 -0
  32. package/dist/errors.js +8 -0
  33. package/dist/function-sources.js +54 -0
  34. package/dist/function-worker.js +105 -0
  35. package/dist/functions.js +174 -0
  36. package/dist/guest-api.js +114 -0
  37. package/dist/header-validation.js +18 -0
  38. package/dist/http-policy.js +74 -0
  39. package/dist/http-response.js +84 -0
  40. package/dist/index.js +11 -0
  41. package/dist/link-api.js +136 -0
  42. package/dist/link-cli.js +141 -0
  43. package/dist/link-events.js +76 -0
  44. package/dist/link-records.js +31 -0
  45. package/dist/link-store-worker.js +150 -0
  46. package/dist/link-store.js +250 -0
  47. package/dist/logging.js +22 -0
  48. package/dist/management-policy.js +41 -0
  49. package/dist/match.js +124 -0
  50. package/dist/observability.js +242 -0
  51. package/dist/plugins.js +74 -0
  52. package/dist/policies/agents.js +248 -0
  53. package/dist/policies/cache.js +297 -0
  54. package/dist/policies/compression.js +187 -0
  55. package/dist/policies/security.js +0 -0
  56. package/dist/policies/throttle.js +131 -0
  57. package/dist/policies.js +142 -0
  58. package/dist/policy.js +55 -0
  59. package/dist/prerender.js +165 -0
  60. package/dist/project-tests.js +23 -0
  61. package/dist/readiness.js +216 -0
  62. package/dist/router.js +166 -0
  63. package/dist/runtime.js +244 -0
  64. package/dist/scaffold.js +0 -0
  65. package/dist/scripts/operational-drills.js +75 -0
  66. package/dist/server.js +270 -0
  67. package/dist/site.js +0 -0
  68. package/dist/sqlite-version.js +6 -0
  69. package/dist/types/adapters.d.ts +12 -0
  70. package/dist/types/agent-lists.d.ts +5 -0
  71. package/dist/types/assets.d.ts +13 -0
  72. package/dist/types/authoring.d.ts +2 -0
  73. package/dist/types/aws.d.ts +35 -0
  74. package/dist/types/build-cloudflare.d.ts +14 -0
  75. package/dist/types/cli.d.ts +2 -0
  76. package/dist/types/client-address.d.ts +9 -0
  77. package/dist/types/cloudflare.d.ts +75 -0
  78. package/dist/types/compliance-rules/baseline.d.ts +12 -0
  79. package/dist/types/compliance-rules/privacy.d.ts +6 -0
  80. package/dist/types/compliance-rules/shared.d.ts +24 -0
  81. package/dist/types/compliance-rules/strict.d.ts +9 -0
  82. package/dist/types/compliance.d.ts +119 -0
  83. package/dist/types/config-worker.d.ts +1 -0
  84. package/dist/types/config.d.ts +21 -0
  85. package/dist/types/errors.d.ts +7 -0
  86. package/dist/types/function-sources.d.ts +21 -0
  87. package/dist/types/function-worker.d.ts +1 -0
  88. package/dist/types/functions.d.ts +92 -0
  89. package/dist/types/guest-api.d.ts +16 -0
  90. package/dist/types/header-validation.d.ts +2 -0
  91. package/dist/types/http-policy.d.ts +39 -0
  92. package/dist/types/http-response.d.ts +43 -0
  93. package/dist/types/index.d.ts +11 -0
  94. package/dist/types/link-api.d.ts +30 -0
  95. package/dist/types/link-cli.d.ts +36 -0
  96. package/dist/types/link-events.d.ts +27 -0
  97. package/dist/types/link-records.d.ts +11 -0
  98. package/dist/types/link-store-worker.d.ts +1 -0
  99. package/dist/types/link-store.d.ts +130 -0
  100. package/dist/types/logging.d.ts +9 -0
  101. package/dist/types/management-policy.d.ts +9 -0
  102. package/dist/types/match.d.ts +81 -0
  103. package/dist/types/observability.d.ts +104 -0
  104. package/dist/types/plugins.d.ts +27 -0
  105. package/dist/types/policies/agents.d.ts +86 -0
  106. package/dist/types/policies/cache.d.ts +82 -0
  107. package/dist/types/policies/compression.d.ts +41 -0
  108. package/dist/types/policies/security.d.ts +37 -0
  109. package/dist/types/policies/throttle.d.ts +55 -0
  110. package/dist/types/policies.d.ts +36 -0
  111. package/dist/types/policy.d.ts +21 -0
  112. package/dist/types/prerender.d.ts +31 -0
  113. package/dist/types/project-tests.d.ts +13 -0
  114. package/dist/types/readiness.d.ts +121 -0
  115. package/dist/types/router.d.ts +11 -0
  116. package/dist/types/runtime.d.ts +91 -0
  117. package/dist/types/scaffold.d.ts +17 -0
  118. package/dist/types/server.d.ts +37 -0
  119. package/dist/types/site.d.ts +12 -0
  120. package/dist/types/sqlite-version.d.ts +1 -0
  121. package/dist/types/types.d.ts +332 -0
  122. package/dist/types/vercel.d.ts +12 -0
  123. package/dist/types.js +177 -0
  124. package/dist/vercel.js +65 -0
  125. package/docs/AI-AUTHORING.md +113 -0
  126. package/docs/ASSETS.md +106 -0
  127. package/docs/AWS.md +77 -0
  128. package/docs/BEST-PRACTICES.md +267 -0
  129. package/docs/CAPACITY.md +208 -0
  130. package/docs/CLOUDFLARE.md +110 -0
  131. package/docs/COMPLIANCE.md +242 -0
  132. package/docs/DYNAMIC-LINKS.md +561 -0
  133. package/docs/FUNCTION-SECURITY.md +113 -0
  134. package/docs/HTTP.md +129 -0
  135. package/docs/INSTALL.md +90 -0
  136. package/docs/LOAD-TESTING.md +91 -0
  137. package/docs/LOCAL-DEVELOPMENT.md +99 -0
  138. package/docs/MANAGEMENT-SECURITY.md +82 -0
  139. package/docs/MIDDLEWARE.md +83 -0
  140. package/docs/MONITORING.md +132 -0
  141. package/docs/OBSERVABILITY.md +229 -0
  142. package/docs/OPERATIONAL-PROOF.md +42 -0
  143. package/docs/OPERATIONS.md +207 -0
  144. package/docs/ORGANIZATION.md +135 -0
  145. package/docs/PERFORMANCE.md +72 -0
  146. package/docs/PLUGINS.md +234 -0
  147. package/docs/POLICIES.md +489 -0
  148. package/docs/PRERENDER.md +193 -0
  149. package/docs/PROJECT-DIRECTION.md +51 -0
  150. package/docs/READINESS.md +125 -0
  151. package/docs/README.md +58 -0
  152. package/docs/RELEASE-READINESS.md +95 -0
  153. package/docs/RELEASE-SECURITY.md +72 -0
  154. package/docs/RESILIENCE.md +160 -0
  155. package/docs/ROUTING.md +95 -0
  156. package/docs/SANDBOX-REVIEW.md +59 -0
  157. package/docs/SCAFFOLDING.md +72 -0
  158. package/docs/SECURITY-AUDIT.md +124 -0
  159. package/docs/SITE.md +150 -0
  160. package/docs/SPECIFICATION.md +232 -0
  161. package/docs/SPIKE-EXTENSIONS.md +475 -0
  162. package/docs/STANDARDS.md +303 -0
  163. package/docs/STARTERS.md +51 -0
  164. package/docs/TUNNELS.md +75 -0
  165. package/docs/TYPESCRIPT.md +102 -0
  166. package/docs/VERCEL.md +107 -0
  167. package/docs/YAML-GUIDE.md +521 -0
  168. package/docs/YAML-REFERENCE.md +328 -0
  169. package/docs/policies/agents.md +182 -0
  170. package/docs/policies/cache.md +139 -0
  171. package/docs/policies/compression.md +168 -0
  172. package/docs/policies/security.md +160 -0
  173. package/docs/policies/throttle.md +103 -0
  174. package/examples/assets/.env.example +1 -0
  175. package/examples/assets/.gitattributes +2 -0
  176. package/examples/assets/Makefile +30 -0
  177. package/examples/assets/README.md +18 -0
  178. package/examples/assets/functions/hello.mjs +3 -0
  179. package/examples/assets/gitignore.template +7 -0
  180. package/examples/assets/public/about.html +2 -0
  181. package/examples/assets/public/assets/example.txt +1 -0
  182. package/examples/assets/public/guide.txt +1 -0
  183. package/examples/assets/tests/requests.json +44 -0
  184. package/examples/assets/urlcode.yaml +27 -0
  185. package/examples/aws/README.md +13 -0
  186. package/examples/aws/handler.mjs +5 -0
  187. package/examples/aws/public/index.html +3 -0
  188. package/examples/aws/public/notes.txt +1 -0
  189. package/examples/aws/template.yaml +33 -0
  190. package/examples/aws/tests/requests.json +9 -0
  191. package/examples/aws/urlcode.yaml +19 -0
  192. package/examples/cloudflare/README.md +18 -0
  193. package/examples/cloudflare/package.json +14 -0
  194. package/examples/cloudflare/tests/requests.json +9 -0
  195. package/examples/cloudflare/urlcode.yaml +24 -0
  196. package/examples/cloudflare/wrangler.toml +5 -0
  197. package/examples/compliance/README.md +20 -0
  198. package/examples/compliance/rules.mjs +65 -0
  199. package/examples/cookbook/README.md +21 -0
  200. package/examples/cookbook/functions/choice.mjs +4 -0
  201. package/examples/cookbook/functions/echo.mjs +3 -0
  202. package/examples/cookbook/functions/hello.mjs +3 -0
  203. package/examples/cookbook/functions/text.mjs +3 -0
  204. package/examples/cookbook/middleware/headers.mjs +6 -0
  205. package/examples/cookbook/public/about.html +1 -0
  206. package/examples/cookbook/public/assets/index.html +1 -0
  207. package/examples/cookbook/public/assets/site.css +1 -0
  208. package/examples/cookbook/public/favicon.svg +1 -0
  209. package/examples/cookbook/public/guide.txt +1 -0
  210. package/examples/cookbook/public/llms.txt +6 -0
  211. package/examples/cookbook/routes/code.yaml +55 -0
  212. package/examples/cookbook/routes/files.yaml +17 -0
  213. package/examples/cookbook/routes/policies.yaml +28 -0
  214. package/examples/cookbook/routes/redirects.yaml +38 -0
  215. package/examples/cookbook/routes/responses.yaml +26 -0
  216. package/examples/cookbook/tests/requests.json +254 -0
  217. package/examples/cookbook/urlcode.yaml +22 -0
  218. package/examples/live-links/README.md +11 -0
  219. package/examples/live-links/tests/requests.json +6 -0
  220. package/examples/live-links/urlcode.yaml +16 -0
  221. package/examples/monitoring/blackbox-jobs.yaml +37 -0
  222. package/examples/monitoring/prometheus-rules.yaml +88 -0
  223. package/examples/monitoring/prometheus-scrape.yaml +20 -0
  224. package/examples/monitoring/vector.toml +65 -0
  225. package/examples/prerender/README.md +48 -0
  226. package/examples/prerender/functions/page.mjs +6 -0
  227. package/examples/prerender/middleware/template.mjs +29 -0
  228. package/examples/prerender/prerender.d.mts +4 -0
  229. package/examples/prerender/prerender.mjs +63 -0
  230. package/examples/prerender/tests/requests.json +39 -0
  231. package/examples/prerender/urlcode.yaml +50 -0
  232. package/examples/tunnel/dev-with-ngrok.sh +61 -0
  233. package/examples/vercel/README.md +13 -0
  234. package/examples/vercel/api/index.js +5 -0
  235. package/examples/vercel/package.json +8 -0
  236. package/examples/vercel/public/index.html +3 -0
  237. package/examples/vercel/public/notes.txt +1 -0
  238. package/examples/vercel/tests/requests.json +48 -0
  239. package/examples/vercel/urlcode.yaml +19 -0
  240. package/examples/vercel/vercel.json +10 -0
  241. package/llms.txt +46 -0
  242. package/package.json +123 -0
  243. package/schemas/urlcode.schema.json +1230 -0
  244. package/starters/default/.gitattributes +1 -0
  245. package/starters/default/Makefile +30 -0
  246. package/starters/default/README.md +34 -0
  247. package/starters/default/functions/hello.mjs +3 -0
  248. package/starters/default/gitignore.template +8 -0
  249. package/starters/default/middleware/headers.mjs +6 -0
  250. package/starters/default/routes/functions.yaml +20 -0
  251. package/starters/default/routes/marketing/links.yaml +7 -0
  252. package/starters/default/starter.json +5 -0
  253. package/starters/default/tests/requests.json +56 -0
  254. package/starters/default/urlcode.yaml +8 -0
@@ -0,0 +1,104 @@
1
+ export declare const events: Readonly<{
2
+ request: readonly string[];
3
+ reload: readonly string[];
4
+ watch: readonly string[];
5
+ function_worker: readonly string[];
6
+ link_store_worker: readonly string[];
7
+ link_request: readonly string[];
8
+ link_observer: readonly string[];
9
+ logs_dropped: readonly string[];
10
+ observer: readonly string[];
11
+ management_request: readonly string[];
12
+ throttle: readonly string[];
13
+ agents: readonly string[];
14
+ cache: readonly string[];
15
+ listening: readonly string[];
16
+ }>;
17
+ /** One log record: a flat object whose `event` key names the kind (see `events`). */
18
+ export type ObserverEvent = Record<string, unknown>;
19
+ export interface Observer {
20
+ name: string;
21
+ version: string;
22
+ onEvent?(event: ObserverEvent): unknown;
23
+ onMetrics?(snapshot: MetricsSnapshot): unknown;
24
+ onClose?(): unknown;
25
+ }
26
+ /** What the event does not say: the route when the request log is minimal, and whether this was a probe. */
27
+ export interface RecordContext {
28
+ probe?: boolean;
29
+ route?: string;
30
+ }
31
+ type Counters = Record<string, number>;
32
+ export interface MetricsSnapshot {
33
+ version: number;
34
+ uptimeSeconds: number;
35
+ rssBytes: number;
36
+ requests: {
37
+ total: number;
38
+ byStatusClass: Counters;
39
+ inFlight: number;
40
+ byRoute: Counters;
41
+ };
42
+ health: {
43
+ total: number;
44
+ byStatusClass: Counters;
45
+ inFlight: number;
46
+ };
47
+ shed: {
48
+ requests: number;
49
+ health: number;
50
+ };
51
+ reloads: {
52
+ ok: number;
53
+ rejected: number;
54
+ };
55
+ watch: {
56
+ failed: number;
57
+ };
58
+ functionWorkers: {
59
+ started: number;
60
+ restarts: number;
61
+ healthySlots: number;
62
+ slots: number;
63
+ };
64
+ linkStoreWorkers: {
65
+ started: number;
66
+ restarts: number;
67
+ };
68
+ policies: {
69
+ throttle: Counters;
70
+ agents: Counters;
71
+ cache: Counters;
72
+ };
73
+ linkRequests: Counters;
74
+ linkObserver: {
75
+ failed: number;
76
+ dropped: number;
77
+ };
78
+ logsDropped: number;
79
+ observers: {
80
+ errors: number;
81
+ };
82
+ [extra: string]: unknown;
83
+ }
84
+ export interface Metrics {
85
+ record(event: unknown, context?: RecordContext): void;
86
+ inFlight(kind: string, delta: number): void;
87
+ shed(kind: string): void;
88
+ observerError(): void;
89
+ snapshot(extra?: Record<string, unknown>): MetricsSnapshot;
90
+ }
91
+ /** The log sink the runtime writes to: callable like a logger, with the counters and observers hanging off it. */
92
+ export type ObserverSink = ((event: ObserverEvent, context?: RecordContext) => void) & {
93
+ fail(observer: Observer): void;
94
+ metrics: Metrics;
95
+ observers: Observer[];
96
+ publish(snapshot: MetricsSnapshot): void;
97
+ close(): Promise<void>;
98
+ };
99
+ export declare function validateObservers(observers?: unknown): Observer[];
100
+ export declare const SNAPSHOT_VERSION = 1;
101
+ export declare function createMetrics(): Metrics;
102
+ export declare function createObserverSink(observers?: unknown, fallbackLog?: (event: ObserverEvent) => void, metrics?: Metrics): ObserverSink;
103
+ export declare function renderPrometheus(snapshot: Partial<MetricsSnapshot>): string;
104
+ export {};
@@ -0,0 +1,27 @@
1
+ import type { HandlerResult } from './http-response.ts';
2
+ import type { PolicyRequest, TargetName, TestPlan } from './types.ts';
3
+ export type { PolicyRequest, TargetName, TestPlan } from './types.ts';
4
+ export type { HandlerResult, HeaderPair } from './http-response.ts';
5
+ /** What onActivate receives: the started runtime's public facts, never its handlers. */
6
+ export interface PluginRuntime {
7
+ testPlan(): TestPlan;
8
+ version: string;
9
+ root: string;
10
+ target: string;
11
+ }
12
+ export interface Plugin {
13
+ name: string;
14
+ version: string;
15
+ targets: TargetName[];
16
+ onActivate?(runtime: PluginRuntime): void | Promise<void>;
17
+ onRequest?(request: PolicyRequest): HandlerResult | undefined | void | Promise<HandlerResult | undefined | void>;
18
+ onResponse?(request: PolicyRequest, result: HandlerResult): HandlerResult | undefined | void | Promise<HandlerResult | undefined | void>;
19
+ onError?(request: PolicyRequest, error: unknown): void | Promise<void>;
20
+ onClose?(): void | Promise<void>;
21
+ }
22
+ export declare function validatePlugins(plugins?: unknown, target?: string): Plugin[];
23
+ export declare function activatePlugins(plugins: Plugin[], runtime: PluginRuntime): Promise<void>;
24
+ export declare function pluginsRequest(plugins: Plugin[], request: PolicyRequest): Promise<HandlerResult | undefined>;
25
+ export declare function pluginsResponse(plugins: Plugin[], request: PolicyRequest, result: HandlerResult): Promise<HandlerResult>;
26
+ export declare function pluginsError(plugins: Plugin[], request: PolicyRequest, error: unknown): Promise<void>;
27
+ export declare function closePlugins(plugins: Plugin[]): Promise<void>;
@@ -0,0 +1,86 @@
1
+ import type { HandlerResult } from '../http-response.ts';
2
+ export declare const name = "agents";
3
+ export declare const phases: readonly string[];
4
+ export declare function targets(): Record<string, 'native' | 'compiled'>;
5
+ export interface AgentEntry {
6
+ name?: string;
7
+ pattern: string;
8
+ }
9
+ export interface AgentsConfig {
10
+ mode?: 'enforce' | 'report';
11
+ status?: number;
12
+ denyEmpty?: boolean;
13
+ deny?: string[];
14
+ allow?: string[];
15
+ denyPatterns?: string[];
16
+ allowPatterns?: string[];
17
+ /** Project list files attached by the Cloudflare build, keyed by reference. */
18
+ resolved?: Record<string, AgentEntry[]>;
19
+ }
20
+ type Log = (event: Record<string, unknown>) => void;
21
+ export interface PolicyContext {
22
+ route: {
23
+ pattern: string;
24
+ };
25
+ shared?: {
26
+ log?: Log;
27
+ };
28
+ target?: string;
29
+ root?: string;
30
+ }
31
+ interface CompiledList {
32
+ label: string;
33
+ count: number;
34
+ regexp: RegExp;
35
+ }
36
+ interface ListUse {
37
+ name: string;
38
+ patterns: number;
39
+ source: string;
40
+ revision: string;
41
+ }
42
+ export interface AgentsState {
43
+ route: string;
44
+ mode: 'enforce' | 'report';
45
+ status: number;
46
+ denyEmpty: boolean;
47
+ deny: CompiledList[];
48
+ allow: CompiledList[];
49
+ used: {
50
+ deny: ListUse[];
51
+ allow: ListUse[];
52
+ };
53
+ patternCounts: {
54
+ deny: number;
55
+ allow: number;
56
+ };
57
+ log: Log | undefined;
58
+ }
59
+ export interface AgentsDescription {
60
+ mode: 'enforce' | 'report';
61
+ status: number;
62
+ denyEmpty: boolean;
63
+ deny: ListUse[];
64
+ allow: ListUse[];
65
+ denyPatterns: number;
66
+ allowPatterns: number;
67
+ patterns: {
68
+ deny: number;
69
+ allow: number;
70
+ };
71
+ }
72
+ export declare const bundledLists: readonly string[];
73
+ export declare const MAX_PATTERN_BYTES = 256;
74
+ export declare const MAX_REPEAT = 64;
75
+ export declare function validatePattern(pattern: unknown): string | undefined;
76
+ export declare function isBundled(reference: string): boolean;
77
+ export declare function isListFile(reference: unknown): reference is string;
78
+ export declare function compile(config: AgentsConfig | undefined, context: PolicyContext): AgentsState | Promise<AgentsState>;
79
+ export declare function onRequest(state: AgentsState, request: {
80
+ headers: {
81
+ get(name: string): string | null;
82
+ };
83
+ }): HandlerResult | undefined;
84
+ export declare function describe(state: AgentsState): AgentsDescription;
85
+ export declare function close(): Promise<void>;
86
+ export {};
@@ -0,0 +1,82 @@
1
+ import type { HandlerResult, HeaderPair } from '../http-response.ts';
2
+ import type { LogFn, PolicyContext, PolicyRequest, PolicyShared, PolicySupport, TargetName } from '../types.ts';
3
+ export declare const name = "cache";
4
+ export declare const phases: readonly string[];
5
+ export type Strategy = 'no-store' | 'revalidate' | 'public' | 'immutable' | 'swr' | 'sie' | 'micro' | 'cdn-only' | 'private';
6
+ export interface CacheConfig {
7
+ strategy: Strategy;
8
+ maxAge?: number;
9
+ staleWhileRevalidate?: number;
10
+ staleIfError?: number;
11
+ cdnMaxAge?: number;
12
+ originTtl?: number;
13
+ vary?: string[];
14
+ statuses?: number[];
15
+ maxBytes?: number;
16
+ maxEntries?: number;
17
+ force?: boolean;
18
+ }
19
+ /** A stored 200 representation: the result minus its body and headers, which are kept separately. */
20
+ export interface CacheEntry {
21
+ result: Omit<HandlerResult, 'body' | 'headers'>;
22
+ headers: HeaderPair[];
23
+ body: Buffer;
24
+ storedAt: number;
25
+ revalidating: boolean;
26
+ }
27
+ /** The in-flight fill for one key; waiters share its promise up to MAX_WAITERS. */
28
+ export interface Flight {
29
+ waiters: number;
30
+ promise: Promise<CacheEntry | null>;
31
+ resolve: (entry: CacheEntry | null) => void;
32
+ reject: (error: Error) => void;
33
+ }
34
+ /** The one origin cache per runtime, shared by every route with an origin-caching strategy. */
35
+ export interface CacheStore {
36
+ entries: Map<string, CacheEntry>;
37
+ pending: Map<string, Flight>;
38
+ bytes: number;
39
+ maxBytes: number;
40
+ now: () => number;
41
+ }
42
+ export interface CacheState {
43
+ strategy: Strategy;
44
+ cacheControl: string;
45
+ cdnCacheControl: string | undefined;
46
+ vary: string[];
47
+ statuses: Set<number>;
48
+ maxBytes: number;
49
+ maxEntries: number;
50
+ origin: boolean;
51
+ freshMs: number;
52
+ staleMs: number;
53
+ originTtl: number | null;
54
+ staleIfError: number | null;
55
+ route: string;
56
+ secrets: boolean;
57
+ log: LogFn | undefined;
58
+ store: CacheStore;
59
+ yamlCacheControl: boolean;
60
+ inheritedAsset: boolean;
61
+ inflight: WeakMap<object, {
62
+ key: string;
63
+ flight: Flight;
64
+ }>;
65
+ }
66
+ export interface CacheDescription {
67
+ strategy: Strategy;
68
+ cacheControl: string;
69
+ origin: boolean;
70
+ originTtl: number | null;
71
+ vary: string[];
72
+ cdnCacheControl?: string;
73
+ staleWhileRevalidate?: number;
74
+ staleIfError?: number;
75
+ }
76
+ export declare function targets(): Record<TargetName, PolicySupport>;
77
+ export declare function compile(config: CacheConfig, { route, shared }: PolicyContext): Promise<CacheState>;
78
+ export declare function onRequest(state: CacheState, req: PolicyRequest): Promise<HandlerResult | undefined>;
79
+ export declare function onResponse(state: CacheState, req: PolicyRequest, result: HandlerResult): HandlerResult;
80
+ export declare function onError(state: CacheState, req: PolicyRequest, _error?: unknown): void;
81
+ export declare function describe(state: CacheState): CacheDescription;
82
+ export declare function close(shared: PolicyShared | undefined): Promise<void>;
@@ -0,0 +1,41 @@
1
+ import type { HandlerResult } from '../http-response.ts';
2
+ import type { AssetResult, PolicyContext, PolicyRequest, PolicyShared, PolicySupport, TargetName } from '../types.ts';
3
+ export declare const name = "compression";
4
+ export declare const phases: readonly string[];
5
+ export type Coding = 'br' | 'gzip' | 'deflate' | 'zstd';
6
+ export interface CompressionConfig {
7
+ encodings?: Coding[];
8
+ minBytes?: number;
9
+ types?: string[];
10
+ level?: number;
11
+ allowWithSecrets?: boolean;
12
+ }
13
+ interface Levels {
14
+ dynamic: number;
15
+ stored: number;
16
+ }
17
+ export interface CompressionState {
18
+ encodings: Coding[];
19
+ minBytes: number;
20
+ types: string[];
21
+ matches: (header: string | undefined) => boolean;
22
+ level: number | null;
23
+ levels: Partial<Record<Coding, Levels>>;
24
+ allowWithSecrets: boolean;
25
+ precompressed: number;
26
+ }
27
+ export interface CompressionDescription {
28
+ encodings: Coding[];
29
+ minBytes: number;
30
+ types: number;
31
+ level: number | null;
32
+ precompressed: number;
33
+ }
34
+ export declare const zstdAvailable: boolean;
35
+ export declare function targets(): Record<TargetName, PolicySupport>;
36
+ export declare function compile(config: CompressionConfig, { route, shared }: PolicyContext): Promise<CompressionState>;
37
+ export declare function negotiate<C extends string>(acceptEncoding: string | null | undefined, encodings: readonly C[]): C | null;
38
+ export declare function onResponse(state: CompressionState, request: PolicyRequest, result: AssetResult): HandlerResult;
39
+ export declare function describe(state: CompressionState): CompressionDescription;
40
+ export declare function close(shared: PolicyShared | undefined): Promise<void>;
41
+ export {};
@@ -0,0 +1,37 @@
1
+ import type { HandlerResult, HeaderPair } from '../http-response.ts';
2
+ export interface SecurityConfig {
3
+ headers?: string;
4
+ unset?: string[];
5
+ set?: Record<string, string>;
6
+ }
7
+ export interface SecurityState {
8
+ profileName: string;
9
+ profile: readonly HeaderPair[];
10
+ overrides: readonly HeaderPair[];
11
+ size: number;
12
+ unset: readonly string[];
13
+ overrideKeys: Set<string>;
14
+ }
15
+ export interface SecurityDescription {
16
+ headers: string;
17
+ emits: string[];
18
+ set: string[];
19
+ unset: string[];
20
+ bytes: number;
21
+ }
22
+ export declare const name = "security";
23
+ export declare const phases: readonly string[];
24
+ export declare const oshpRevision = "OSHP 2024 best practices";
25
+ export declare const profiles: Readonly<Record<string, readonly (readonly [string, string])[]>>;
26
+ export declare const reservedHeaders: Readonly<Set<string>>;
27
+ export declare function targets(): Record<string, 'native' | 'compiled'>;
28
+ export declare function compile(config: unknown, { route }: {
29
+ route: {
30
+ pattern: string;
31
+ };
32
+ }): SecurityState;
33
+ export declare function onResponse(state: SecurityState, request: {
34
+ origin?: unknown;
35
+ } | null | undefined, result: HandlerResult): HandlerResult;
36
+ export declare function describe(state: SecurityState): SecurityDescription;
37
+ export declare function close(): void;
@@ -0,0 +1,55 @@
1
+ import type { HandlerResult } from '../http-response.ts';
2
+ import type { LogFn, PolicyContext, PolicyRequest, PolicyShared, PolicySupport, TargetName } from '../types.ts';
3
+ export declare const name = "throttle";
4
+ export declare const phases: readonly string[];
5
+ export type Partition = 'client' | 'route' | 'client-route';
6
+ export interface ThrottleConfig {
7
+ quota: number;
8
+ window: number;
9
+ partition?: Partition;
10
+ status?: number;
11
+ mode?: 'enforce' | 'report';
12
+ maxKeys?: number;
13
+ }
14
+ interface Entry {
15
+ start: number;
16
+ current: number;
17
+ previous: number;
18
+ }
19
+ /** The one counter table per runtime, shared by every route that declares a throttle. */
20
+ export interface ThrottleTable {
21
+ keys: Map<string, Entry>;
22
+ maxKeys: number;
23
+ now: () => number;
24
+ }
25
+ interface Budget {
26
+ remaining: number;
27
+ reset: number;
28
+ }
29
+ export interface ThrottleState {
30
+ quota: number;
31
+ window: number;
32
+ windowMs: number;
33
+ partition: Partition;
34
+ status: number;
35
+ mode: 'enforce' | 'report';
36
+ route: string;
37
+ table: ThrottleTable;
38
+ log: LogFn | undefined;
39
+ pending: WeakMap<object, Budget>;
40
+ }
41
+ export interface ThrottleDescription {
42
+ quota: number;
43
+ window: number;
44
+ partition: Partition;
45
+ mode: 'enforce' | 'report';
46
+ status: number;
47
+ unresolvedClient?: string;
48
+ }
49
+ export declare function targets(config?: Partial<ThrottleConfig>): Record<TargetName, PolicySupport>;
50
+ export declare function compile(config: ThrottleConfig, { route, shared }: PolicyContext): Promise<ThrottleState>;
51
+ export declare function onRequest(state: ThrottleState, req: PolicyRequest): Promise<HandlerResult | undefined>;
52
+ export declare function onResponse(state: ThrottleState, req: PolicyRequest, result: HandlerResult): HandlerResult;
53
+ export declare function describe(state: ThrottleState): ThrottleDescription;
54
+ export declare function close(shared: PolicyShared): Promise<void>;
55
+ export {};
@@ -0,0 +1,36 @@
1
+ import type { HeaderPair } from './http-response.ts';
2
+ import type { SecurityState } from './policies/security.ts';
3
+ import type { EffectivePolicies, PolicyChain, PolicyConfigs, PolicyContext, PolicyDescriptions, PolicyLayer, PolicyModule, PolicyName, PolicyRequest, PolicyShared, PolicyStates, ProjectDocument, RouteConfig, TargetName } from './types.ts';
4
+ export type { PolicyChain, PolicyContext, PolicyModule, PolicyRequest, PolicyShared } from './types.ts';
5
+ /** The registry, typed per policy so `registry.cache.compile` returns a CacheState; erased to PolicyModule where iterated. */
6
+ export type PolicyRegistry = {
7
+ [K in PolicyName]: PolicyModule<PolicyConfigs[K], PolicyStates[K], PolicyDescriptions[K]>;
8
+ };
9
+ export declare const registry: PolicyRegistry;
10
+ export declare const requestOrder: readonly PolicyName[];
11
+ export declare const responseOrder: readonly PolicyName[];
12
+ export declare const targets: readonly TargetName[];
13
+ export declare const builtinProfiles: Readonly<Record<string, PolicyLayer>>;
14
+ export declare function effectivePolicies(document: ProjectDocument, routeConfig: Pick<RouteConfig, 'policies'> | undefined): EffectivePolicies;
15
+ export declare function compilePolicies(document: ProjectDocument, routeConfig: Pick<RouteConfig, 'policies'> | undefined, { route, shared, target, root }: PolicyContext): Promise<PolicyChain>;
16
+ export declare function compileErrorPolicy(document: ProjectDocument, { target }?: {
17
+ target?: TargetName;
18
+ }): SecurityState | null;
19
+ export declare function errorHeaders(state: SecurityState | null | undefined, origin: string | undefined): HeaderPair[];
20
+ export declare function closePolicies(shared: PolicyShared): Promise<void>;
21
+ export interface PolicyRequestInput {
22
+ method: string;
23
+ target: string;
24
+ path: string;
25
+ params?: Record<string, string>;
26
+ query: URLSearchParams;
27
+ headers: PolicyRequest['headers'];
28
+ headerCounts?: Record<string, number> | undefined;
29
+ client?: string | null | undefined;
30
+ origin?: string | undefined;
31
+ route: {
32
+ pattern: string;
33
+ secrets?: Record<string, string>;
34
+ };
35
+ }
36
+ export declare function policyRequest({ method, target, path, params, query, headers, headerCounts, client, origin, route }: PolicyRequestInput): PolicyRequest;
@@ -0,0 +1,21 @@
1
+ import type { FunctionSources } from './function-sources.ts';
2
+ import type { LoadedDocument } from './types.ts';
3
+ /** The operator's binding grants: which env and secret names each route may read, pinned to a project hash. */
4
+ export interface OperatorPolicy {
5
+ version: 1;
6
+ projectSha256: string;
7
+ routes: Record<string, {
8
+ env?: string[];
9
+ secrets?: string[];
10
+ }>;
11
+ }
12
+ /** The function snapshot plus the hash operator grants are pinned to. */
13
+ export interface FunctionSnapshot extends FunctionSources {
14
+ projectSha256: string;
15
+ }
16
+ export declare function prepareFunctionSnapshot(loaded: LoadedDocument): Promise<FunctionSnapshot>;
17
+ export declare function validatePolicy(value: unknown): OperatorPolicy;
18
+ export declare function loadOperatorPolicy(file: string | undefined, project: string): Promise<OperatorPolicy | undefined>;
19
+ export declare function requestedPermissions(loaded: LoadedDocument, snapshot: {
20
+ projectSha256: string;
21
+ }): OperatorPolicy;
@@ -0,0 +1,31 @@
1
+ import type { RouteInventory, RequestCase } from './readiness.ts';
2
+ import type { LogFn } from './types.ts';
3
+ export interface NativeProjectOptions {
4
+ allow?: string[] | undefined;
5
+ log?: LogFn | undefined;
6
+ }
7
+ export interface PrerenderOptions {
8
+ origin?: string | undefined;
9
+ fileName?: ((path: string) => string) | undefined;
10
+ ignoreUnrenderable?: boolean | undefined;
11
+ maxPages?: number | undefined;
12
+ maxPageBytes?: number | undefined;
13
+ maxTotalBytes?: number | undefined;
14
+ log?: LogFn | undefined;
15
+ }
16
+ export interface PrerenderedPage {
17
+ path: string;
18
+ file: string;
19
+ bytes: number;
20
+ }
21
+ export interface PrerenderReport {
22
+ count: number;
23
+ bytes: number;
24
+ directory: string;
25
+ pages: PrerenderedPage[];
26
+ fixtures: RequestCase[];
27
+ }
28
+ export declare function assertLiteralRoutePath(path: string): string[];
29
+ export declare function pageFileName(path: string): string;
30
+ export declare function assertNativeProject(project: string, { allow, log }?: NativeProjectOptions): Promise<RouteInventory[]>;
31
+ export declare function prerenderPages(project: string, output: string, { origin, fileName, ignoreUnrenderable, maxPages, maxPageBytes, maxTotalBytes, log, }?: PrerenderOptions): Promise<PrerenderReport>;
@@ -0,0 +1,13 @@
1
+ import type { ServerOptions } from './server.ts';
2
+ import type { LogFn } from './types.ts';
3
+ export interface ProjectTestOptions {
4
+ log?: LogFn | undefined;
5
+ permissions?: ServerOptions['permissions'];
6
+ linkStore?: ServerOptions['linkStore'];
7
+ origin?: string | undefined;
8
+ }
9
+ export interface ProjectTestResult {
10
+ total: number;
11
+ failed: number;
12
+ }
13
+ export declare function runProjectTests(project: string, { log, permissions, linkStore, origin }?: ProjectTestOptions): Promise<ProjectTestResult>;
@@ -0,0 +1,121 @@
1
+ import { Agent } from 'node:http';
2
+ import type { AddressInfo } from 'node:net';
3
+ import type { CompiledRedirect, CompiledRoute, LogFn, PlanInventoryEntry, PolicyInventory } from './types.ts';
4
+ import type { ComplianceOptions, ComplianceReport } from './compliance.ts';
5
+ import type { CompiledRoutes } from './match.ts';
6
+ export type { RouteState } from './types.ts';
7
+ export type HandlerName = 'redirect' | 'function' | 'page' | 'static' | 'download' | 'respond' | 'link';
8
+ /** One configured route as the inventory reports it: a PlanInventoryEntry with the handler kind named. */
9
+ export interface RouteInventory extends PlanInventoryEntry {
10
+ handler: HandlerName | undefined;
11
+ }
12
+ /** One request case: a generated probe or a `tests/requests.json` fixture. */
13
+ export interface RequestCase {
14
+ path: string;
15
+ method?: string | undefined;
16
+ status: number;
17
+ headers?: Record<string, string> | undefined;
18
+ body?: string | undefined;
19
+ expectHeaders?: Record<string, string> | undefined;
20
+ expectBody?: string | undefined;
21
+ }
22
+ export interface ProjectPlan {
23
+ inventory: RouteInventory[];
24
+ cases: RequestCase[];
25
+ resolve: (path: string) => string | undefined;
26
+ }
27
+ export interface HitResult {
28
+ pass: boolean;
29
+ status: number;
30
+ durationMs: number;
31
+ error?: string;
32
+ }
33
+ export interface BenchmarkTarget {
34
+ protocol: string;
35
+ hostname: string;
36
+ port: number | string;
37
+ }
38
+ /** A started server as the audit and benchmark see it. structural: the real type is startServer's result in src/server.ts. */
39
+ export interface AuditableApp {
40
+ address: AddressInfo;
41
+ root: string;
42
+ testPlan(): ProjectPlan & {
43
+ dynamicLinks?: boolean;
44
+ policies?: Record<string, PolicyInventory>;
45
+ };
46
+ }
47
+ export type { ComplianceOptions, ComplianceReport } from './compliance.ts';
48
+ export interface AuditOptions {
49
+ expectRoutes?: number | undefined;
50
+ log?: LogFn | undefined;
51
+ compliance?: ComplianceOptions | undefined;
52
+ }
53
+ export interface AuditReport {
54
+ dynamicLinks: boolean | undefined;
55
+ elapsedMs: number;
56
+ ready: boolean;
57
+ counts: {
58
+ configured: number;
59
+ active: number;
60
+ disabled: number;
61
+ expired: number;
62
+ byHandler: Record<string, number>;
63
+ };
64
+ expectedRoutes: number | null;
65
+ countMatches: boolean;
66
+ checks: number;
67
+ passed: number;
68
+ failed: number;
69
+ coveredRouteMethods: number;
70
+ unassertedCases: number[];
71
+ uncovered: {
72
+ route: string;
73
+ method: string;
74
+ }[];
75
+ policies: Record<string, PolicyInventory>;
76
+ compliance: ComplianceReport | null;
77
+ }
78
+ export interface BenchmarkOptions {
79
+ requests?: number | undefined;
80
+ concurrency?: number | undefined;
81
+ maxP95Ms?: number | undefined;
82
+ seconds?: number | undefined;
83
+ warmup?: number | undefined;
84
+ target?: string | undefined;
85
+ }
86
+ export interface BenchmarkReport {
87
+ pass: boolean;
88
+ requested: number;
89
+ completed: number;
90
+ complete: boolean;
91
+ failed: number;
92
+ transportErrors: number;
93
+ shedResponses: number;
94
+ concurrency: number;
95
+ workloadCases: number;
96
+ exercisedWorkloadCases: number;
97
+ workload: string;
98
+ target: string | null;
99
+ warmupRequests: number;
100
+ elapsedMs: number;
101
+ requestsPerSecond: number;
102
+ p50Ms: number | null;
103
+ p95Ms: number | null;
104
+ p99Ms: number | null;
105
+ maxP95Ms: number | null;
106
+ statuses: Record<string, number>;
107
+ rssMiB: number | null;
108
+ node: string;
109
+ platform: string;
110
+ }
111
+ /** Narrows a compiled route to one that redirects, so redirectLocation can read its spec. */
112
+ export declare const hasRedirect: (route: CompiledRoute) => route is CompiledRoute & {
113
+ redirect: CompiledRedirect;
114
+ };
115
+ export declare const probeAgent = "Mozilla/5.0 (compatible; RouteProbe/0.1)";
116
+ export declare function projectPlan(compiled: CompiledRoutes<CompiledRoute>): ProjectPlan;
117
+ export declare function readCases(root: string, optional?: boolean): Promise<RequestCase[]>;
118
+ export declare function benchmarkTarget(value: string): BenchmarkTarget;
119
+ export declare function hit(app: AuditableApp, test: RequestCase, agent: Agent, target?: BenchmarkTarget): Promise<HitResult>;
120
+ export declare function auditProject(app: AuditableApp, { expectRoutes, log, compliance }?: AuditOptions): Promise<AuditReport>;
121
+ export declare function benchmarkProject(app: AuditableApp, { requests, concurrency, maxP95Ms, seconds, warmup, target }?: BenchmarkOptions): Promise<BenchmarkReport>;
@@ -0,0 +1,11 @@
1
+ import type { CompiledRouteTable, LoadedDocument } from './types.ts';
2
+ export { parseTarget, matchRoute, contextFor, resolveValue, redirectLocation } from './match.ts';
3
+ /** The grants compileRoutes consults: a validated OperatorPolicy (policy.ts) or nothing, which denies every binding. */
4
+ export interface BindingPermissions {
5
+ projectSha256?: string;
6
+ routes?: Record<string, {
7
+ env?: string[];
8
+ secrets?: string[];
9
+ }>;
10
+ }
11
+ export declare function compileRoutes(loaded: LoadedDocument, bindings: Record<string, string | undefined>, permissions?: BindingPermissions, projectSha256?: string): Promise<CompiledRouteTable>;