@daloyjs/core 0.7.4 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -63
- package/dist/adapters/bun.d.ts +26 -4
- package/dist/adapters/bun.d.ts.map +1 -1
- package/dist/adapters/bun.js +16 -4
- package/dist/adapters/bun.js.map +1 -1
- package/dist/adapters/cloudflare.d.ts +21 -4
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/deno.d.ts +25 -2
- package/dist/adapters/deno.d.ts.map +1 -1
- package/dist/adapters/deno.js +39 -7
- package/dist/adapters/deno.js.map +1 -1
- package/dist/adapters/fastly.d.ts +23 -0
- package/dist/adapters/fastly.d.ts.map +1 -0
- package/dist/adapters/fastly.js +11 -0
- package/dist/adapters/fastly.js.map +1 -0
- package/dist/adapters/lambda.d.ts +67 -0
- package/dist/adapters/lambda.d.ts.map +1 -0
- package/dist/adapters/lambda.js +117 -0
- package/dist/adapters/lambda.js.map +1 -0
- package/dist/adapters/node.d.ts +7 -0
- package/dist/adapters/node.d.ts.map +1 -1
- package/dist/adapters/node.js +17 -4
- package/dist/adapters/node.js.map +1 -1
- package/dist/adapters/vercel.d.ts +35 -7
- package/dist/adapters/vercel.d.ts.map +1 -1
- package/dist/adapters/vercel.js +22 -1
- package/dist/adapters/vercel.js.map +1 -1
- package/dist/app.d.ts +235 -8
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +222 -8
- package/dist/app.js.map +1 -1
- package/dist/client.d.ts +27 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +27 -0
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +169 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +143 -0
- package/dist/errors.js.map +1 -1
- package/dist/logger.d.ts +26 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +26 -0
- package/dist/logger.js.map +1 -1
- package/dist/middleware.d.ts +143 -0
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +147 -4
- package/dist/middleware.js.map +1 -1
- package/dist/openapi.d.ts +32 -0
- package/dist/openapi.d.ts.map +1 -1
- package/dist/openapi.js +33 -2
- package/dist/openapi.js.map +1 -1
- package/dist/schema.d.ts +33 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +33 -2
- package/dist/schema.js.map +1 -1
- package/dist/security-schemes.d.ts +75 -5
- package/dist/security-schemes.d.ts.map +1 -1
- package/dist/security-schemes.js +75 -5
- package/dist/security-schemes.js.map +1 -1
- package/dist/security.d.ts +73 -4
- package/dist/security.d.ts.map +1 -1
- package/dist/security.js +73 -4
- package/dist/security.js.map +1 -1
- package/dist/types.d.ts +195 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ DaloyJS exists to be the framework you'd build if you took the best ideas from e
|
|
|
24
24
|
| **Supply-chain-hardened installs and publishing** | [pnpm](https://pnpm.io/motivation) + hardened CI/CD | `ignore-scripts`, release-age cooldown, explicit build allowlist, SHA-pinned actions, isolated OIDC publish with provenance. |
|
|
25
25
|
|
|
26
26
|
```
|
|
27
|
-
|
|
27
|
+
framework test suite passing · 100% line + function coverage · clean strict TypeScript 6
|
|
28
28
|
runs on Node, Bun, Deno, Cloudflare, Vercel
|
|
29
29
|
~12.3M static-route ops/sec · ~1.5M dynamic-route ops/sec on M-class CPU
|
|
30
30
|
```
|
|
@@ -61,9 +61,12 @@ For a new DaloyJS project, the recommended path is the official scaffolder:
|
|
|
61
61
|
pnpm create daloy@latest my-api
|
|
62
62
|
# or
|
|
63
63
|
npm create daloy@latest my-api
|
|
64
|
+
|
|
65
|
+
# add GitHub Actions + governance files for a company repo
|
|
66
|
+
pnpm create daloy@latest my-api --with-ci --code-owner @acme/security
|
|
64
67
|
```
|
|
65
68
|
|
|
66
|
-
`create-daloy` gives you a working project structure, runtime template selection, docs routes, OpenAPI wiring,
|
|
69
|
+
`create-daloy` gives you a working project structure, runtime template selection, docs routes, OpenAPI wiring, production-oriented defaults, and an optional hardened GitHub security bundle without copying code out of the README.
|
|
67
70
|
|
|
68
71
|
See [Scaffold a project](https://daloyjs.dev/docs/scaffolder) for templates and flags.
|
|
69
72
|
|
|
@@ -178,7 +181,7 @@ import { swaggerUiHtml, htmlResponse } from "@daloyjs/core/docs";
|
|
|
178
181
|
```
|
|
179
182
|
|
|
180
183
|
Mount at `/docs` and the UI is always contract-accurate — never stale.
|
|
181
|
-
`create-daloy@0.
|
|
184
|
+
`create-daloy@0.2.0` mounts Swagger UI at `/docs` and the live spec at `/openapi.json` by default.
|
|
182
185
|
|
|
183
186
|
---
|
|
184
187
|
|
|
@@ -262,11 +265,17 @@ await app.ready();
|
|
|
262
265
|
## Multi-runtime
|
|
263
266
|
|
|
264
267
|
```ts
|
|
265
|
-
import { serve } from "@daloyjs/core/node";
|
|
266
|
-
import { serve } from "@daloyjs/core/bun";
|
|
267
|
-
import { serve } from "@daloyjs/core/deno";
|
|
268
|
+
import { serve } from "@daloyjs/core/node"; // Node (Heroku, Railway, Render, Fly.io, any PaaS)
|
|
269
|
+
import { serve } from "@daloyjs/core/bun"; // Bun
|
|
270
|
+
import { serve } from "@daloyjs/core/deno"; // Deno
|
|
268
271
|
import { toFetchHandler } from "@daloyjs/core/cloudflare"; // Cloudflare Workers
|
|
269
|
-
import {
|
|
272
|
+
import {
|
|
273
|
+
toFetchHandler as toVercelFetchHandler,
|
|
274
|
+
toRouteHandlers,
|
|
275
|
+
toWebHandler,
|
|
276
|
+
} from "@daloyjs/core/vercel"; // Vercel Node / Edge / Next.js / Netlify Edge
|
|
277
|
+
import { installFastlyListener } from "@daloyjs/core/fastly"; // Fastly Compute
|
|
278
|
+
import { toLambdaHandler } from "@daloyjs/core/lambda"; // AWS Lambda / Netlify Functions / Lambda Function URLs
|
|
270
279
|
```
|
|
271
280
|
|
|
272
281
|
The core only ever sees `Request → Response`. Adapters live at the edge.
|
|
@@ -285,62 +294,23 @@ The core only ever sees `Request → Response`. Adapters live at the edge.
|
|
|
285
294
|
|
|
286
295
|
---
|
|
287
296
|
|
|
288
|
-
## Status
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
-
|
|
295
|
-
-
|
|
296
|
-
-
|
|
297
|
-
-
|
|
298
|
-
-
|
|
299
|
-
-
|
|
300
|
-
-
|
|
301
|
-
-
|
|
302
|
-
-
|
|
303
|
-
|
|
304
|
-
-
|
|
305
|
-
- [x] Graceful shutdown
|
|
306
|
-
- [x] `app.onClose()` lifecycle hook + augmentable `AppState` for plugin-typed context
|
|
307
|
-
- [x] Mock mode
|
|
308
|
-
- [x] Scalar + Swagger UI handlers
|
|
309
|
-
- [x] **pnpm-first distribution with hardened `.npmrc`**
|
|
310
|
-
- [x] **Lockfile source verification for git/non-registry tarball dependencies**
|
|
311
|
-
- [x] **100% line + function coverage** enforced by `pnpm coverage`
|
|
312
|
-
|
|
313
|
-
**Current (`0.2.x` follow-up — see [ROADMAP.md](./ROADMAP.md) for the full plan):**
|
|
314
|
-
|
|
315
|
-
- [x] `onSend` hook for response transformation
|
|
316
|
-
- [x] GitHub Actions CI for install, typecheck, tests, coverage, build, and audit
|
|
317
|
-
- [x] `SECURITY.md` and vulnerability disclosure process
|
|
318
|
-
- [x] `pnpm create daloy` project scaffolder (Node + Vercel Edge + Cloudflare templates)
|
|
319
|
-
- [x] Docs site discoverability pass: page metadata, sitemap, robots, OpenGraph image, ORM guides
|
|
320
|
-
- [x] Streaming response helpers: SSE + NDJSON with backpressure-safe writers (`sseStream` / `sseResponse` / `ndjsonStream` / `ndjsonResponse`)
|
|
321
|
-
- [x] OpenAPI extras: `securitySchemes` builders (`httpBearerScheme` / `httpBasicScheme` / `apiKeyScheme` / `oauth2Scheme` / `openIdConnectScheme`), top-level `webhooks`, per-operation `callbacks`, and `discriminator` / `discriminatedUnion` helpers
|
|
322
|
-
- [x] OpenTelemetry-compatible tracing hook (`otelTracing`) with HTTP semantic-convention attributes and per-request `SERVER` spans
|
|
323
|
-
- [x] CSRF helper (`csrf`) with double-submit-cookie pattern, timing-safe verification, and `__Host-` cookie defaults
|
|
324
|
-
- [x] Multipart/form-data ergonomics: `fileField` + `multipartObject` (per-file size and MIME caps, OpenAPI-aware emission) and `AppOptions.multipart` defense-in-depth caps
|
|
325
|
-
- [ ] Branch coverage push to `>= 98%`
|
|
326
|
-
- [ ] Release checklist and publishing docs cleanup
|
|
327
|
-
|
|
328
|
-
**On deck (`0.3.x` and beyond):**
|
|
329
|
-
WebSockets and HTTP/2 + HTTP/3 adapters.
|
|
330
|
-
|
|
331
|
-
**Shipped from the `0.x` extensibility track so far:**
|
|
332
|
-
|
|
333
|
-
- [x] Plugin lifecycle events: `app.onPluginInstalled((info) => ...)` fires once per `register()` (sync or async), and `app.onShutdown(({ reason, timeoutMs }) => ...)` fires at the start of `app.shutdown()` before in-flight requests drain. `onClose()` still runs after drain for resource cleanup.
|
|
334
|
-
- [x] Edge-friendly session middleware: `session({ secret, store })` exposes `ctx.state.session` (`get` / `set` / `delete` / `regenerate` / `destroy`) backed by a signed `__Host-` cookie (HMAC-SHA256, key rotation) and a pluggable `SessionStore` (`MemorySessionStore` ships in-process; KV/Redis stores plug in directly). Standalone `signValue` / `verifySignedValue` helpers are exported for ad-hoc cookie/token signing.
|
|
335
|
-
|
|
336
|
-
**Shipped from `0.5.x` ("project ops") so far:**
|
|
337
|
-
|
|
338
|
-
- [x] Bun and Deno scaffolder templates (`bun-basic`, `deno-basic`)
|
|
339
|
-
- [x] `--minimal` flag that strips the bookstore demo and `/docs` + `/openapi.json` routes from any template
|
|
340
|
-
- [x] `daloy inspect` CLI: route table, schema summary, contract-test gate, OpenAPI dump, tag/method filters
|
|
341
|
-
- [x] Redis-backed `RateLimitStore` at `@daloyjs/core/rate-limit-redis` with `ioredisAdapter` / `nodeRedisAdapter` and a fail-open default for shared counters across replicas
|
|
342
|
-
- [x] AI-agent helper files (`AGENTS.md` + `SKILL.md`) shipped in every `create-daloy` template so Copilot/Claude/Cursor/Codex have project context out of the box
|
|
343
|
-
- [x] Polished `create-daloy` terminal UX: DaloyJS welcome banner, arrow-key pickers, install spinner, and boxed next steps while preserving zero runtime dependencies
|
|
297
|
+
## Status
|
|
298
|
+
|
|
299
|
+
DaloyJS is in **public preview** (`0.x`). The public API may still change between minor versions; deprecations will get at least one minor cycle once `1.0.0` ships. The framework is already in use for production trials — every release ships with **100% line + function test coverage**, strict TypeScript, OpenSSF Scorecard, CodeQL, zizmor workflow linting, and npm provenance.
|
|
300
|
+
|
|
301
|
+
What works today, at a glance:
|
|
302
|
+
|
|
303
|
+
- Contract-first routing, Standard Schema validation (Zod 4 / Valibot / ArkType / TypeBox), and OpenAPI 3.1 from a single source of truth.
|
|
304
|
+
- Adapters for Node (Heroku/Railway/Render/Fly.io), Bun, Deno, Cloudflare Workers, Vercel Node / Edge / Next.js / Netlify Edge, Fastly Compute, and AWS Lambda / Netlify Functions / Lambda Function URLs.
|
|
305
|
+
- Built-in security primitives (body limits, prototype-pollution-safe JSON, path-traversal guard, request timeouts, header injection guards) plus first-party middleware (`secureHeaders`, `cors`, `rateLimit`, `requestId`, `bearerAuth`, `csrf`, `session`, `timing` / `timingSafeEqual`).
|
|
306
|
+
- Streaming helpers (SSE + NDJSON), multipart ergonomics, OpenTelemetry-compatible tracing, signed-cookie sessions with pluggable stores, and a Redis-backed rate-limit store at `@daloyjs/core/rate-limit-redis`.
|
|
307
|
+
- In-process test client (`app.request()`), contract-test runner, in-process typed client, and Hey API codegen via `pnpm gen`.
|
|
308
|
+
- `pnpm create daloy` scaffolder with Node, Bun, Deno, Cloudflare Worker, and Vercel Edge templates, plus optional `--with-ci` GitHub Actions / Dependabot / CODEOWNERS / SECURITY.md hardening.
|
|
309
|
+
- Plugin encapsulation, decorators, structured logging, request-id propagation, lifecycle events (`onPluginInstalled`, `onShutdown`, `onClose`), and graceful shutdown.
|
|
310
|
+
- Integration guides for transactional email providers — AWS SES, SendGrid, Resend, Postmark, Mailgun, and Mailtrap — with a common `EmailSender` plugin pattern and runtime-compatibility matrix.
|
|
311
|
+
- Authentication & authorization guides for AWS Cognito, Microsoft Entra ID (MSAL), Auth0, Okta, and Clerk — with a common bearer-auth plugin, scope/role enforcement, and runtime-compatibility matrix.
|
|
312
|
+
|
|
313
|
+
Roadmap, version-by-version plan, and shipped/in-progress checklists live in [ROADMAP.md](./ROADMAP.md).
|
|
344
314
|
|
|
345
315
|
## License
|
|
346
316
|
|
package/dist/adapters/bun.d.ts
CHANGED
|
@@ -1,16 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Bun adapter — `Bun.serve` already speaks web-standard fetch,
|
|
3
|
-
* so this is the smallest possible wrapper.
|
|
3
|
+
* so this is the smallest possible wrapper. The adapter passes through the
|
|
4
|
+
* commonly-needed modern `Bun.serve` options (`idleTimeout`, `tls`,
|
|
5
|
+
* `development`, `unix`) and exposes the server's `url` for ergonomic logging.
|
|
4
6
|
*/
|
|
5
7
|
import type { App } from "../app.js";
|
|
8
|
+
export interface BunTLSOptions {
|
|
9
|
+
/** PEM certificate. */
|
|
10
|
+
cert: string;
|
|
11
|
+
/** PEM private key. */
|
|
12
|
+
key: string;
|
|
13
|
+
/** Optional passphrase for the key. */
|
|
14
|
+
passphrase?: string;
|
|
15
|
+
/** Optional CA bundle. */
|
|
16
|
+
ca?: string;
|
|
17
|
+
}
|
|
6
18
|
export interface BunServeOptions {
|
|
7
19
|
port?: number;
|
|
8
20
|
hostname?: string;
|
|
9
21
|
/** Maximum request body bytes (Bun-level cap). Default: 16 MiB. */
|
|
10
22
|
maxRequestBodySize?: number;
|
|
23
|
+
/** Seconds before an idle connection is closed. Default: Bun default (10). */
|
|
24
|
+
idleTimeout?: number;
|
|
25
|
+
/** When true, Bun enables development-mode error pages and verbose output. */
|
|
26
|
+
development?: boolean;
|
|
27
|
+
/** Optional unix socket path; when set, TCP `port`/`hostname` are not passed to Bun. */
|
|
28
|
+
unix?: string;
|
|
29
|
+
/** When supplied, Bun.serve listens on HTTPS. */
|
|
30
|
+
tls?: BunTLSOptions;
|
|
11
31
|
}
|
|
12
|
-
export
|
|
13
|
-
stop: () => Promise<void>;
|
|
32
|
+
export interface BunServerHandle {
|
|
14
33
|
port: number;
|
|
15
|
-
|
|
34
|
+
url: URL | undefined;
|
|
35
|
+
stop: () => Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export declare function serve(app: App, opts?: BunServeOptions): BunServerHandle;
|
|
16
38
|
//# sourceMappingURL=bun.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/adapters/bun.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/adapters/bun.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAErC,MAAM,WAAW,aAAa;IAC5B,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,wFAAwF;IACxF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,GAAG,CAAC,EAAE,aAAa,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,GAAG,GAAG,SAAS,CAAC;IACrB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,wBAAgB,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,GAAE,eAAoB,GAAG,eAAe,CAoC3E"}
|
package/dist/adapters/bun.js
CHANGED
|
@@ -2,9 +2,7 @@ export function serve(app, opts = {}) {
|
|
|
2
2
|
const Bun = globalThis.Bun;
|
|
3
3
|
if (!Bun?.serve)
|
|
4
4
|
throw new Error("Bun runtime not detected");
|
|
5
|
-
const
|
|
6
|
-
port: opts.port ?? 3000,
|
|
7
|
-
hostname: opts.hostname ?? "0.0.0.0",
|
|
5
|
+
const cfg = {
|
|
8
6
|
maxRequestBodySize: opts.maxRequestBodySize ?? 16 * 1024 * 1024,
|
|
9
7
|
fetch: (req) => app.fetch(req),
|
|
10
8
|
error: (err) => new Response(JSON.stringify({
|
|
@@ -13,9 +11,23 @@ export function serve(app, opts = {}) {
|
|
|
13
11
|
status: 500,
|
|
14
12
|
detail: err.message,
|
|
15
13
|
}), { status: 500, headers: { "content-type": "application/problem+json" } }),
|
|
16
|
-
}
|
|
14
|
+
};
|
|
15
|
+
if (opts.unix === undefined) {
|
|
16
|
+
cfg.port = opts.port ?? 3000;
|
|
17
|
+
cfg.hostname = opts.hostname ?? "0.0.0.0";
|
|
18
|
+
}
|
|
19
|
+
if (opts.idleTimeout !== undefined)
|
|
20
|
+
cfg.idleTimeout = opts.idleTimeout;
|
|
21
|
+
if (opts.development !== undefined)
|
|
22
|
+
cfg.development = opts.development;
|
|
23
|
+
if (opts.unix !== undefined)
|
|
24
|
+
cfg.unix = opts.unix;
|
|
25
|
+
if (opts.tls)
|
|
26
|
+
cfg.tls = opts.tls;
|
|
27
|
+
const server = Bun.serve(cfg);
|
|
17
28
|
return {
|
|
18
29
|
port: server.port,
|
|
30
|
+
url: server.url,
|
|
19
31
|
stop: async () => {
|
|
20
32
|
await app.shutdown();
|
|
21
33
|
server.stop(true);
|
package/dist/adapters/bun.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun.js","sourceRoot":"","sources":["../../src/adapters/bun.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bun.js","sourceRoot":"","sources":["../../src/adapters/bun.ts"],"names":[],"mappings":"AAwCA,MAAM,UAAU,KAAK,CAAC,GAAQ,EAAE,OAAwB,EAAE;IACxD,MAAM,GAAG,GAAI,UAAmI,CAAC,GAAG,CAAC;IACrJ,IAAI,CAAC,GAAG,EAAE,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAE7D,MAAM,GAAG,GAA4B;QACnC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI;QAC/D,KAAK,EAAE,CAAC,GAAY,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;QACvC,KAAK,EAAE,CAAC,GAAU,EAAE,EAAE,CACpB,IAAI,QAAQ,CACV,IAAI,CAAC,SAAS,CAAC;YACb,IAAI,EAAE,qCAAqC;YAC3C,KAAK,EAAE,uBAAuB;YAC9B,MAAM,EAAE,GAAG;YACX,MAAM,EAAE,GAAG,CAAC,OAAO;SACpB,CAAC,EACF,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,EAAE,CACzE;KACJ,CAAC;IACF,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;QAC7B,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC;IAC5C,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS;QAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACvE,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS;QAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACvE,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;QAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IAClD,IAAI,IAAI,CAAC,GAAG;QAAE,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;IAEjC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,IAAI,EAAE,KAAK,IAAI,EAAE;YACf,MAAM,GAAG,CAAC,QAAQ,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cloudflare Workers / generic fetch handler adapter.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Cloudflare Workers expect the module's default export to expose a `fetch`
|
|
5
|
+
* property whose value is the `(request, env, ctx) => Response` function.
|
|
6
|
+
* `toFetchHandler` returns that exact shape, so the recommended usage is:
|
|
7
|
+
*
|
|
8
|
+
* import { toFetchHandler } from "@daloyjs/core/cloudflare";
|
|
9
|
+
* import { app } from "./server.js";
|
|
5
10
|
* export default toFetchHandler(app);
|
|
11
|
+
*
|
|
12
|
+
* Do NOT wrap the result again (e.g. `export default { fetch: toFetchHandler(app) }`),
|
|
13
|
+
* that nests the object and breaks the Workers runtime.
|
|
14
|
+
*
|
|
15
|
+
* The generic accepts the Worker's `Env` type when you want stronger typing
|
|
16
|
+
* against bindings, e.g. `toFetchHandler<MyEnv>(app)`.
|
|
6
17
|
*/
|
|
7
18
|
import type { App } from "../app.js";
|
|
8
|
-
export
|
|
9
|
-
fetch: (
|
|
10
|
-
}
|
|
19
|
+
export interface ExportedFetchHandler<Env = unknown> {
|
|
20
|
+
fetch: (request: Request, env?: Env, ctx?: ExecutionContextLike) => Promise<Response>;
|
|
21
|
+
}
|
|
22
|
+
interface ExecutionContextLike {
|
|
23
|
+
waitUntil?: (promise: Promise<unknown>) => void;
|
|
24
|
+
passThroughOnException?: () => void;
|
|
25
|
+
}
|
|
26
|
+
export declare function toFetchHandler<Env = unknown>(app: App): ExportedFetchHandler<Env>;
|
|
27
|
+
export {};
|
|
11
28
|
//# sourceMappingURL=cloudflare.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../src/adapters/cloudflare.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../src/adapters/cloudflare.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAErC,MAAM,WAAW,oBAAoB,CAAC,GAAG,GAAG,OAAO;IACjD,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACvF;AAED,UAAU,oBAAoB;IAC5B,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IAChD,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,wBAAgB,cAAc,CAAC,GAAG,GAAG,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAIjF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare.js","sourceRoot":"","sources":["../../src/adapters/cloudflare.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cloudflare.js","sourceRoot":"","sources":["../../src/adapters/cloudflare.ts"],"names":[],"mappings":"AA4BA,MAAM,UAAU,cAAc,CAAgB,GAAQ;IACpD,OAAO;QACL,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;KAC/B,CAAC;AACJ,CAAC"}
|
package/dist/adapters/deno.d.ts
CHANGED
|
@@ -1,12 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Deno adapter — `Deno.serve` is web-standard fetch.
|
|
3
|
+
*
|
|
4
|
+
* Supports the modern `Deno.serve(options, handler)` signature: HTTPS via
|
|
5
|
+
* `cert`/`key`, an `onListen` callback, an `onError` hook, and signal-based
|
|
6
|
+
* graceful shutdown (also wired to SIGTERM/SIGINT when `handleSignals` is
|
|
7
|
+
* left at the default).
|
|
3
8
|
*/
|
|
4
9
|
import type { App } from "../app.js";
|
|
5
10
|
export interface DenoServeOptions {
|
|
6
11
|
port?: number;
|
|
7
12
|
hostname?: string;
|
|
13
|
+
/** Optional external signal that triggers graceful shutdown. */
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
/** Optional TLS certificate (PEM). When supplied together with `key`, serves HTTPS. */
|
|
16
|
+
cert?: string;
|
|
17
|
+
/** Optional TLS private key (PEM). Pairs with `cert`. */
|
|
18
|
+
key?: string;
|
|
19
|
+
/** Invoked once the server is listening. */
|
|
20
|
+
onListen?: (info: {
|
|
21
|
+
hostname: string;
|
|
22
|
+
port: number;
|
|
23
|
+
}) => void;
|
|
24
|
+
/** Invoked when the fetch handler itself throws. Must return a fallback Response. */
|
|
25
|
+
onError?: (err: unknown) => Response | Promise<Response>;
|
|
26
|
+
/** Listen for SIGTERM/SIGINT and shut down. Default: true. */
|
|
27
|
+
handleSignals?: boolean;
|
|
28
|
+
/** Drain timeout for graceful shutdown. Default: 10000. */
|
|
29
|
+
shutdownTimeoutMs?: number;
|
|
8
30
|
}
|
|
9
|
-
export
|
|
31
|
+
export interface DenoServerHandle {
|
|
10
32
|
shutdown: () => Promise<void>;
|
|
11
|
-
}
|
|
33
|
+
}
|
|
34
|
+
export declare function serve(app: App, opts?: DenoServeOptions): DenoServerHandle;
|
|
12
35
|
//# sourceMappingURL=deno.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deno.d.ts","sourceRoot":"","sources":["../../src/adapters/deno.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"deno.d.ts","sourceRoot":"","sources":["../../src/adapters/deno.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAErC,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC9D,qFAAqF;IACrF,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzD,8DAA8D;IAC9D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAED,wBAAgB,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,GAAE,gBAAqB,GAAG,gBAAgB,CAoD7E"}
|
package/dist/adapters/deno.js
CHANGED
|
@@ -1,13 +1,45 @@
|
|
|
1
1
|
export function serve(app, opts = {}) {
|
|
2
2
|
const D = globalThis.Deno;
|
|
3
|
-
|
|
3
|
+
const denoServe = D?.serve;
|
|
4
|
+
if (!denoServe)
|
|
4
5
|
throw new Error("Deno runtime not detected");
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
},
|
|
6
|
+
const controller = new AbortController();
|
|
7
|
+
const init = {
|
|
8
|
+
port: opts.port ?? 3000,
|
|
9
|
+
hostname: opts.hostname ?? "0.0.0.0",
|
|
10
|
+
signal: controller.signal,
|
|
11
11
|
};
|
|
12
|
+
if (opts.cert && opts.key) {
|
|
13
|
+
init.cert = opts.cert;
|
|
14
|
+
init.key = opts.key;
|
|
15
|
+
}
|
|
16
|
+
if (opts.onListen)
|
|
17
|
+
init.onListen = opts.onListen;
|
|
18
|
+
if (opts.onError)
|
|
19
|
+
init.onError = opts.onError;
|
|
20
|
+
const server = denoServe(init, (req) => app.fetch(req));
|
|
21
|
+
const onSignal = () => {
|
|
22
|
+
void shutdown();
|
|
23
|
+
};
|
|
24
|
+
if (opts.handleSignals !== false && typeof D?.addSignalListener === "function") {
|
|
25
|
+
D.addSignalListener("SIGTERM", onSignal);
|
|
26
|
+
D.addSignalListener("SIGINT", onSignal);
|
|
27
|
+
}
|
|
28
|
+
opts.signal?.addEventListener("abort", onSignal, { once: true });
|
|
29
|
+
let stopped = false;
|
|
30
|
+
const shutdown = async () => {
|
|
31
|
+
if (stopped)
|
|
32
|
+
return;
|
|
33
|
+
stopped = true;
|
|
34
|
+
controller.abort();
|
|
35
|
+
opts.signal?.removeEventListener("abort", onSignal);
|
|
36
|
+
if (opts.handleSignals !== false && typeof D?.removeSignalListener === "function") {
|
|
37
|
+
D.removeSignalListener("SIGTERM", onSignal);
|
|
38
|
+
D.removeSignalListener("SIGINT", onSignal);
|
|
39
|
+
}
|
|
40
|
+
await app.shutdown(opts.shutdownTimeoutMs ?? 10_000);
|
|
41
|
+
await server.shutdown?.();
|
|
42
|
+
};
|
|
43
|
+
return { shutdown };
|
|
12
44
|
}
|
|
13
45
|
//# sourceMappingURL=deno.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deno.js","sourceRoot":"","sources":["../../src/adapters/deno.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deno.js","sourceRoot":"","sources":["../../src/adapters/deno.ts"],"names":[],"mappings":"AAiCA,MAAM,UAAU,KAAK,CAAC,GAAQ,EAAE,OAAyB,EAAE;IACzD,MAAM,CAAC,GAAI,UAMT,CAAC,IAAI,CAAC;IACR,MAAM,SAAS,GAAG,CAAC,EAAE,KAER,CAAC;IACd,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAE7D,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,IAAI,GAA4B;QACpC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI;QACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,SAAS;QACpC,MAAM,EAAE,UAAU,CAAC,MAAM;KAC1B,CAAC;IACF,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;IACtB,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ;QAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IACjD,IAAI,IAAI,CAAC,OAAO;QAAE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAE9C,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAExD,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,KAAK,QAAQ,EAAE,CAAC;IAClB,CAAC,CAAC;IACF,IAAI,IAAI,CAAC,aAAa,KAAK,KAAK,IAAI,OAAO,CAAC,EAAE,iBAAiB,KAAK,UAAU,EAAE,CAAC;QAC/E,CAAC,CAAC,iBAAiB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACzC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAEjE,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,IAAI,OAAO;YAAE,OAAO;QACpB,OAAO,GAAG,IAAI,CAAC;QACf,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACpD,IAAI,IAAI,CAAC,aAAa,KAAK,KAAK,IAAI,OAAO,CAAC,EAAE,oBAAoB,KAAK,UAAU,EAAE,CAAC;YAClF,CAAC,CAAC,oBAAoB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YAC5C,CAAC,CAAC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,IAAI,MAAM,CAAC,CAAC;QACrD,MAAM,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;IAC5B,CAAC,CAAC;IAEF,OAAO,EAAE,QAAQ,EAAE,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastly Compute adapter.
|
|
3
|
+
*
|
|
4
|
+
* Fastly Compute uses the standard `fetch` event model, so the adapter is a
|
|
5
|
+
* one-liner wrapper around {@link App.fetch}. Two usage styles are supported:
|
|
6
|
+
*
|
|
7
|
+
* // 1. Event listener style (Fastly Compute @ Edge JS default):
|
|
8
|
+
* import { installFastlyListener } from "@daloyjs/core/fastly";
|
|
9
|
+
* installFastlyListener(app);
|
|
10
|
+
*
|
|
11
|
+
* // 2. Plain function style (composable with other handlers):
|
|
12
|
+
* import { toFastlyHandler } from "@daloyjs/core/fastly";
|
|
13
|
+
* const handler = toFastlyHandler(app);
|
|
14
|
+
* addEventListener("fetch", (event) => event.respondWith(handler(event.request)));
|
|
15
|
+
*
|
|
16
|
+
* Caveats: Fastly Compute does not expose `node:*` modules or full WHATWG
|
|
17
|
+
* streams; avoid Node-only middleware (Node session store, Redis client,
|
|
18
|
+
* multipart helpers that rely on `node:stream`).
|
|
19
|
+
*/
|
|
20
|
+
import type { App } from "../app.js";
|
|
21
|
+
export declare function toFastlyHandler(app: App): (req: Request) => Promise<Response>;
|
|
22
|
+
export declare function installFastlyListener(app: App): void;
|
|
23
|
+
//# sourceMappingURL=fastly.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastly.d.ts","sourceRoot":"","sources":["../../src/adapters/fastly.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAErC,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAE7E;AAOD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAMpD"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function toFastlyHandler(app) {
|
|
2
|
+
return (req) => app.fetch(req);
|
|
3
|
+
}
|
|
4
|
+
export function installFastlyListener(app) {
|
|
5
|
+
const g = globalThis;
|
|
6
|
+
if (typeof g.addEventListener !== "function") {
|
|
7
|
+
throw new Error("Fastly Compute runtime not detected: globalThis.addEventListener is missing");
|
|
8
|
+
}
|
|
9
|
+
g.addEventListener("fetch", (event) => event.respondWith(app.fetch(event.request)));
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=fastly.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastly.js","sourceRoot":"","sources":["../../src/adapters/fastly.ts"],"names":[],"mappings":"AAqBA,MAAM,UAAU,eAAe,CAAC,GAAQ;IACtC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACjC,CAAC;AAOD,MAAM,UAAU,qBAAqB,CAAC,GAAQ;IAC5C,MAAM,CAAC,GAAG,UAAwG,CAAC;IACnH,IAAI,OAAO,CAAC,CAAC,gBAAgB,KAAK,UAAU,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;IACjG,CAAC;IACD,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACtF,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { App } from "../app.js";
|
|
2
|
+
/**
|
|
3
|
+
* AWS Lambda / Netlify Functions adapter.
|
|
4
|
+
*
|
|
5
|
+
* Supports API Gateway HTTP API (payload format v2.0), Lambda Function URLs,
|
|
6
|
+
* API Gateway REST API (payload format v1.0), and Netlify Functions.
|
|
7
|
+
*
|
|
8
|
+
* // handler.ts (Netlify Functions / Lambda @ Function URL)
|
|
9
|
+
* import { toLambdaHandler } from "@daloyjs/core/lambda";
|
|
10
|
+
* import { app } from "./server.js";
|
|
11
|
+
* export const handler = toLambdaHandler(app);
|
|
12
|
+
*
|
|
13
|
+
* The adapter performs no Node-only I/O, so it is safe in any runtime that
|
|
14
|
+
* provides the standard `Request`/`Response`/`atob`/`btoa` globals.
|
|
15
|
+
*/
|
|
16
|
+
export interface LambdaEventV1 {
|
|
17
|
+
version?: "1.0" | string;
|
|
18
|
+
path?: string;
|
|
19
|
+
httpMethod?: string;
|
|
20
|
+
headers?: Record<string, string | undefined>;
|
|
21
|
+
multiValueHeaders?: Record<string, string[] | undefined>;
|
|
22
|
+
queryStringParameters?: Record<string, string | undefined> | null;
|
|
23
|
+
multiValueQueryStringParameters?: Record<string, string[] | undefined> | null;
|
|
24
|
+
requestContext?: {
|
|
25
|
+
domainName?: string;
|
|
26
|
+
path?: string;
|
|
27
|
+
};
|
|
28
|
+
body?: string;
|
|
29
|
+
isBase64Encoded?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface LambdaEventV2 {
|
|
32
|
+
version?: string;
|
|
33
|
+
rawPath?: string;
|
|
34
|
+
rawQueryString?: string;
|
|
35
|
+
headers?: Record<string, string | undefined>;
|
|
36
|
+
cookies?: string[];
|
|
37
|
+
requestContext?: {
|
|
38
|
+
http?: {
|
|
39
|
+
method?: string;
|
|
40
|
+
path?: string;
|
|
41
|
+
};
|
|
42
|
+
domainName?: string;
|
|
43
|
+
};
|
|
44
|
+
body?: string;
|
|
45
|
+
isBase64Encoded?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export type LambdaEvent = LambdaEventV1 | LambdaEventV2;
|
|
48
|
+
export interface LambdaResponseV1 {
|
|
49
|
+
statusCode: number;
|
|
50
|
+
headers: Record<string, string>;
|
|
51
|
+
multiValueHeaders?: Record<string, string[]>;
|
|
52
|
+
cookies?: never;
|
|
53
|
+
body: string;
|
|
54
|
+
isBase64Encoded: boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface LambdaResponseV2 {
|
|
57
|
+
statusCode: number;
|
|
58
|
+
headers: Record<string, string>;
|
|
59
|
+
cookies?: string[];
|
|
60
|
+
multiValueHeaders?: never;
|
|
61
|
+
body: string;
|
|
62
|
+
isBase64Encoded: boolean;
|
|
63
|
+
}
|
|
64
|
+
export type LambdaResponse = LambdaResponseV1 | LambdaResponseV2;
|
|
65
|
+
export type LambdaHandler = (event: LambdaEvent) => Promise<LambdaResponse>;
|
|
66
|
+
export declare function toLambdaHandler(app: App): LambdaHandler;
|
|
67
|
+
//# sourceMappingURL=lambda.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lambda.d.ts","sourceRoot":"","sources":["../../src/adapters/lambda.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAErC;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACzD,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC;IAClE,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC;IAC9E,cAAc,CAAC,EAAE;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,cAAc,CAAC,EAAE;QACf,IAAI,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,iBAAiB,CAAC,EAAE,KAAK,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;AACjE,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAI5E,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,aAAa,CAMvD"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const TEXT_TYPE_RE = /^(text\/|application\/(json|xml|javascript|x-www-form-urlencoded|.*\+json|.*\+xml))/i;
|
|
2
|
+
export function toLambdaHandler(app) {
|
|
3
|
+
return async (event) => {
|
|
4
|
+
const request = eventToRequest(event);
|
|
5
|
+
const response = await app.fetch(request);
|
|
6
|
+
return responseToLambda(response, isV2Event(event));
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function eventToRequest(event) {
|
|
10
|
+
const headers = new Headers();
|
|
11
|
+
for (const [k, v] of Object.entries(event.headers ?? {})) {
|
|
12
|
+
if (v === undefined)
|
|
13
|
+
continue;
|
|
14
|
+
headers.set(k, v);
|
|
15
|
+
}
|
|
16
|
+
if ("multiValueHeaders" in event) {
|
|
17
|
+
for (const [k, values] of Object.entries(event.multiValueHeaders ?? {})) {
|
|
18
|
+
if (!values?.length)
|
|
19
|
+
continue;
|
|
20
|
+
headers.set(k, k.toLowerCase() === "cookie" ? values.join("; ") : values.join(", "));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if ("cookies" in event && event.cookies?.length)
|
|
24
|
+
headers.set("cookie", event.cookies.join("; "));
|
|
25
|
+
const method = isV2Event(event) ? event.requestContext?.http?.method ?? "GET" : event.httpMethod ?? "GET";
|
|
26
|
+
const rawPath = isV2Event(event)
|
|
27
|
+
? event.rawPath ?? event.requestContext?.http?.path ?? "/"
|
|
28
|
+
: event.path ?? event.requestContext?.path ?? "/";
|
|
29
|
+
const host = headers.get("host") ?? event.requestContext?.domainName ?? "localhost";
|
|
30
|
+
const proto = headers.get("x-forwarded-proto") ?? "https";
|
|
31
|
+
const rawQueryString = isV2Event(event) ? event.rawQueryString ?? "" : queryStringForV1(event);
|
|
32
|
+
const qs = rawQueryString ? `?${rawQueryString}` : "";
|
|
33
|
+
const path = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
|
|
34
|
+
const url = `${proto}://${host}${path}${qs}`;
|
|
35
|
+
const init = { method, headers };
|
|
36
|
+
if (method !== "GET" && method !== "HEAD" && event.body != null) {
|
|
37
|
+
init.body = event.isBase64Encoded
|
|
38
|
+
? base64ToBytes(event.body)
|
|
39
|
+
: event.body;
|
|
40
|
+
}
|
|
41
|
+
return new Request(url, init);
|
|
42
|
+
}
|
|
43
|
+
async function responseToLambda(res, useV2Response) {
|
|
44
|
+
const headers = {};
|
|
45
|
+
const getSetCookie = res.headers.getSetCookie;
|
|
46
|
+
const cookies = typeof getSetCookie === "function"
|
|
47
|
+
? getSetCookie.call(res.headers)
|
|
48
|
+
: cookieFallback(res.headers);
|
|
49
|
+
res.headers.forEach((value, key) => {
|
|
50
|
+
if (key.toLowerCase() === "set-cookie")
|
|
51
|
+
return;
|
|
52
|
+
headers[key] = value;
|
|
53
|
+
});
|
|
54
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
55
|
+
const isText = TEXT_TYPE_RE.test(contentType);
|
|
56
|
+
let body = "";
|
|
57
|
+
let isBase64Encoded = false;
|
|
58
|
+
if (res.body) {
|
|
59
|
+
const buf = new Uint8Array(await res.arrayBuffer());
|
|
60
|
+
if (buf.length > 0) {
|
|
61
|
+
if (isText) {
|
|
62
|
+
body = new TextDecoder().decode(buf);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
body = bytesToBase64(buf);
|
|
66
|
+
isBase64Encoded = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const out = {
|
|
71
|
+
statusCode: res.status,
|
|
72
|
+
headers,
|
|
73
|
+
body,
|
|
74
|
+
isBase64Encoded,
|
|
75
|
+
};
|
|
76
|
+
if (!cookies.length)
|
|
77
|
+
return out;
|
|
78
|
+
if (useV2Response)
|
|
79
|
+
return { ...out, cookies };
|
|
80
|
+
return { ...out, multiValueHeaders: { "set-cookie": cookies } };
|
|
81
|
+
}
|
|
82
|
+
function isV2Event(event) {
|
|
83
|
+
const requestContext = event.requestContext;
|
|
84
|
+
return event.version === "2.0" || "rawPath" in event || "rawQueryString" in event || !!requestContext?.http;
|
|
85
|
+
}
|
|
86
|
+
function queryStringForV1(event) {
|
|
87
|
+
const values = new URLSearchParams();
|
|
88
|
+
for (const [key, list] of Object.entries(event.multiValueQueryStringParameters ?? {})) {
|
|
89
|
+
for (const value of list ?? [])
|
|
90
|
+
values.append(key, value);
|
|
91
|
+
}
|
|
92
|
+
if (values.size > 0)
|
|
93
|
+
return values.toString();
|
|
94
|
+
for (const [key, value] of Object.entries(event.queryStringParameters ?? {})) {
|
|
95
|
+
if (value !== undefined)
|
|
96
|
+
values.append(key, value);
|
|
97
|
+
}
|
|
98
|
+
return values.toString();
|
|
99
|
+
}
|
|
100
|
+
function cookieFallback(headers) {
|
|
101
|
+
const cookie = headers.get("set-cookie");
|
|
102
|
+
return cookie ? [cookie] : [];
|
|
103
|
+
}
|
|
104
|
+
function base64ToBytes(b64) {
|
|
105
|
+
const binary = atob(b64);
|
|
106
|
+
const bytes = new Uint8Array(binary.length);
|
|
107
|
+
for (let i = 0; i < binary.length; i++)
|
|
108
|
+
bytes[i] = binary.charCodeAt(i);
|
|
109
|
+
return bytes;
|
|
110
|
+
}
|
|
111
|
+
function bytesToBase64(bytes) {
|
|
112
|
+
let binary = "";
|
|
113
|
+
for (let i = 0; i < bytes.length; i++)
|
|
114
|
+
binary += String.fromCharCode(bytes[i]);
|
|
115
|
+
return btoa(binary);
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=lambda.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lambda.js","sourceRoot":"","sources":["../../src/adapters/lambda.ts"],"names":[],"mappings":"AAsEA,MAAM,YAAY,GAAG,sFAAsF,CAAC;AAE5G,MAAM,UAAU,eAAe,CAAC,GAAQ;IACtC,OAAO,KAAK,EAAE,KAAK,EAAE,EAAE;QACrB,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1C,OAAO,gBAAgB,CAAC,QAAQ,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,KAAkB;IACxC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;QACzD,IAAI,CAAC,KAAK,SAAS;YAAE,SAAS;QAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,mBAAmB,IAAI,KAAK,EAAE,CAAC;QACjC,KAAK,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,EAAE,CAAC;YACxE,IAAI,CAAC,MAAM,EAAE,MAAM;gBAAE,SAAS;YAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IACD,IAAI,SAAS,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,MAAM;QAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAEjG,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC;IAC1G,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC;QAC9B,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,IAAI,GAAG;QAC1D,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,cAAc,EAAE,IAAI,IAAI,GAAG,CAAC;IACpD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,cAAc,EAAE,UAAU,IAAI,WAAW,CAAC;IACpF,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,OAAO,CAAC;IAC1D,MAAM,cAAc,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC/F,MAAM,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;IAC/D,MAAM,GAAG,GAAG,GAAG,KAAK,MAAM,IAAI,GAAG,IAAI,GAAG,EAAE,EAAE,CAAC;IAE7C,MAAM,IAAI,GAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAC9C,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;QAChE,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,eAAe;YAC/B,CAAC,CAAE,aAAa,CAAC,KAAK,CAAC,IAAI,CAAc;YACzC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IACjB,CAAC;IACD,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,GAAa,EAAE,aAAsB;IACnE,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,MAAM,YAAY,GAAI,GAAG,CAAC,OAAuD,CAAC,YAAY,CAAC;IAC/F,MAAM,OAAO,GAAa,OAAO,YAAY,KAAK,UAAU;QAC1D,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QAChC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAChC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACjC,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK,YAAY;YAAE,OAAO;QAC/C,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IAC1D,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAE9C,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QACpD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnB,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;gBAC1B,eAAe,GAAG,IAAI,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,GAAG,GAAG;QACV,UAAU,EAAE,GAAG,CAAC,MAAM;QACtB,OAAO;QACP,IAAI;QACJ,eAAe;KAChB,CAAC;IACF,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,GAAG,CAAC;IAChC,IAAI,aAAa;QAAE,OAAO,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,CAAC;IAC9C,OAAO,EAAE,GAAG,GAAG,EAAE,iBAAiB,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,CAAC;AAClE,CAAC;AAED,SAAS,SAAS,CAAC,KAAkB;IACnC,MAAM,cAAc,GAAG,KAAK,CAAC,cAAgD,CAAC;IAC9E,OAAO,KAAK,CAAC,OAAO,KAAK,KAAK,IAAI,SAAS,IAAI,KAAK,IAAI,gBAAgB,IAAI,KAAK,IAAI,CAAC,CAAC,cAAc,EAAE,IAAI,CAAC;AAC9G,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAoB;IAC5C,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,+BAA+B,IAAI,EAAE,CAAC,EAAE,CAAC;QACtF,KAAK,MAAM,KAAK,IAAI,IAAI,IAAI,EAAE;YAAE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;IAC9C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,qBAAqB,IAAI,EAAE,CAAC,EAAE,CAAC;QAC7E,IAAI,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,cAAc,CAAC,OAAgB;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IAChC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACxE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAC,KAAiB;IACtC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;IAChF,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC"}
|