@daloyjs/core 1.0.0-beta.1 → 1.0.0-beta.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 +16 -7
- package/dist/adapters/vercel.d.ts +1 -1
- package/dist/app.d.ts +18 -5
- package/dist/app.js +57 -8
- package/dist/compression.d.ts +5 -5
- package/dist/compression.js +1 -1
- package/dist/docs.d.ts +61 -2
- package/dist/docs.js +14 -3
- package/dist/idempotency.d.ts +1 -1
- package/dist/idempotency.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/metrics.d.ts +1 -1
- package/dist/metrics.js +2 -5
- package/dist/middleware.d.ts +6 -6
- package/dist/middleware.js +7 -16
- package/dist/pagination.d.ts +1 -1
- package/dist/pagination.js +1 -1
- package/dist/request-decompression.d.ts +1 -1
- package/dist/request-decompression.js +1 -1
- package/dist/response-cache.d.ts +1 -1
- package/dist/response-cache.js +2 -4
- package/dist/sbom.cdx.json +9 -9
- package/dist/sbom.spdx.json +5 -5
- package/dist/scheduler.d.ts +1 -1
- package/dist/scheduler.js +40 -7
- package/dist/session.d.ts +1 -1
- package/dist/session.js +4 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -278,13 +278,21 @@ new App({
|
|
|
278
278
|
customCss: ":root { --scalar-color-accent: #2563eb; }",
|
|
279
279
|
hideTestRequestButton: true,
|
|
280
280
|
},
|
|
281
|
+
swagger: {
|
|
282
|
+
docExpansion: "none",
|
|
283
|
+
displayRequestDuration: true,
|
|
284
|
+
},
|
|
281
285
|
tags: ["Docs"],
|
|
282
286
|
},
|
|
283
287
|
});
|
|
284
288
|
```
|
|
285
289
|
|
|
286
|
-
Switch UIs with one word.
|
|
287
|
-
|
|
290
|
+
Switch UIs with one word. Scalar and Swagger UI include developer request
|
|
291
|
+
consoles for authenticated endpoints: Scalar selects the first configured
|
|
292
|
+
OpenAPI security scheme by default, and Swagger UI keeps values from the
|
|
293
|
+
Authorize dialog across reloads. `ui: "redoc"` renders Redoc instead, and its
|
|
294
|
+
options are forwarded to `Redoc.init` via `docs.redoc`; Redoc displays security
|
|
295
|
+
requirements but is a read-only reference UI, not a Try It console:
|
|
288
296
|
|
|
289
297
|
```ts
|
|
290
298
|
new App({
|
|
@@ -299,7 +307,8 @@ new App({
|
|
|
299
307
|
The `scalar` option is forwarded to Scalar's HTML API as JSON configuration,
|
|
300
308
|
with Daloy keeping the live `openapiPath` as the source. Use it for themes,
|
|
301
309
|
custom CSS, layout, auth defaults, and client visibility without copying the
|
|
302
|
-
HTML helper.
|
|
310
|
+
HTML helper. The `swagger` option is forwarded to `SwaggerUIBundle` with Daloy
|
|
311
|
+
owning `url` / `dom_id`. Redoc spins up a `blob:` Web Worker for search, so the
|
|
303
312
|
auto-mounted `/docs` page widens its CSP with `worker-src 'self' blob:` for
|
|
304
313
|
`ui: "redoc"` only — Scalar and Swagger UI keep the tighter default.
|
|
305
314
|
|
|
@@ -413,7 +422,7 @@ miss 4,763,878 ops/sec
|
|
|
413
422
|
|
|
414
423
|
### Cold-start tip (serverless / edge)
|
|
415
424
|
|
|
416
|
-
For deployments where every millisecond of startup matters (Lambda, Vercel
|
|
425
|
+
For deployments where every millisecond of startup matters (Lambda, Vercel, Cloudflare Workers, Fastly Compute), import `App` from the deep entry point instead of the barrel:
|
|
417
426
|
|
|
418
427
|
```ts
|
|
419
428
|
import { App } from "@daloyjs/core/app"; // ~13 ms faster cold start than "@daloyjs/core"
|
|
@@ -498,14 +507,14 @@ The core only ever sees `Request → Response`. Adapters live at the edge.
|
|
|
498
507
|
|
|
499
508
|
## Status
|
|
500
509
|
|
|
501
|
-
DaloyJS is now in the **`1.0.0` beta** (`1.0.0-beta.
|
|
510
|
+
DaloyJS is now in the **`1.0.0` beta** (`1.0.0-beta.2`). The public API is feature-complete and stable for the 1.0 line; from `1.0.0` onward, breaking changes follow SemVer and deprecations get at least one minor cycle. Small adjustments are still possible before the `1.0.0` GA if beta feedback surfaces something. The framework is already in use for production trials.
|
|
502
511
|
|
|
503
512
|
**Release quality bar.** Every release ships with **≥90% line + function coverage and ≥90% branch coverage**, strict TypeScript, OpenSSF Scorecard, CodeQL + Opengrep dual SAST, zizmor workflow linting, and npm provenance. Coverage was relaxed from a former 100% gate so complex security work isn't blocked chasing throwaway tests for unreachable defensive branches or tsx source-map phantoms; see [AGENTS.md](AGENTS.md) for the policy.
|
|
504
513
|
|
|
505
514
|
### Routing, validation, and docs
|
|
506
515
|
|
|
507
516
|
- Contract-first routing with Standard Schema validation (Zod 4, Valibot, ArkType, TypeBox) and OpenAPI 3.1 generated from a single source of truth.
|
|
508
|
-
- Live OpenAPI 3.1 spec served as both JSON (`GET /openapi.json`) and YAML (`GET /openapi.yaml`) when `docs: true`, with a choice of Scalar (default), Swagger UI, or Redoc via `docs.ui`, plus Scalar theming/custom CSS via `docs.scalar` and Redoc options via `docs.redoc`.
|
|
517
|
+
- Live OpenAPI 3.1 spec served as both JSON (`GET /openapi.json`) and YAML (`GET /openapi.yaml`) when `docs: true`, with a choice of Scalar (default), Swagger UI, or Redoc via `docs.ui`, plus Scalar theming/custom CSS/auth defaults via `docs.scalar`, Swagger UI options via `docs.swagger` (including persisted Authorize credentials), and Redoc options via `docs.redoc`.
|
|
509
518
|
- Zero-config OpenAPI `info` autofill from `package.json` (Node / Bun) or `deno.json` / `deno.jsonc` (Deno); explicit `openapi.info` values always win.
|
|
510
519
|
- RFC 7231 + RFC 5789 HTTP-method allowlist enforced inside `app.route()` (WebDAV, `TRACE`, `CONNECT` rejected at the framework boundary).
|
|
511
520
|
- AI-friendly route metadata via optional `meta: { examples, extensions, summary, description, tags }`; examples are validated against your schemas at build time, surfaced as OpenAPI `examples` + `x-daloy-*` extensions, and dumped as `routes.json` / `routes.yaml` via `daloy inspect --ai`.
|
|
@@ -516,7 +525,7 @@ DaloyJS is now in the **`1.0.0` beta** (`1.0.0-beta.1`). The public API is featu
|
|
|
516
525
|
|
|
517
526
|
- 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.
|
|
518
527
|
- `daloy dev` watch loop delegates to the host runtime's native watcher (`node --import tsx --watch`, `bun --hot`, or `deno run --watch`) with a `--runtime` override for cross-runtime `package.json` scripts.
|
|
519
|
-
- `pnpm create daloy` scaffolder with Node, Bun, Deno, Cloudflare Worker, and Vercel
|
|
528
|
+
- `pnpm create daloy` scaffolder with Node, Bun, Deno, Cloudflare Worker, and Vercel templates, plus optional `--with-ci` GitHub Actions / Dependabot / CODEOWNERS / SECURITY.md hardening. The completion summary surfaces official install links (nodejs.org, pnpm.io, bun.sh) for any runtime or package manager your selections need but that is missing from `PATH`, and skips a doomed dependency install when the chosen package manager is absent.
|
|
520
529
|
- Container-first templates: `HEALTHCHECK` to `/readyz`, `STOPSIGNAL SIGTERM`, non-root user, `tini` as PID 1.
|
|
521
530
|
- Generated `deploy.yml` for container templates signs every pushed GHCR image with **Sigstore Cosign** (keyless OIDC) and attaches an **SPDX SBOM attestation** so consumers can `cosign verify` and `cosign verify-attestation --type spdxjson` instead of trusting the registry alone.
|
|
522
531
|
- Pretty `printStartupBanner()` / `formatStartupBanner()` helpers at `@daloyjs/core/banner`, used by every starter template (TTY + `NO_COLOR` / `FORCE_COLOR` aware, ASCII fallback for dumb terminals).
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* `toEdgeHandler` is kept as a backward-compatible alias of `toWebHandler`.
|
|
20
20
|
*/
|
|
21
21
|
import type { App } from "../app.js";
|
|
22
|
-
/** Web-standard handler shape used by Vercel
|
|
22
|
+
/** Web-standard handler shape used by Vercel Functions, Next.js route handlers, and middleware. */
|
|
23
23
|
export type WebHandler = (req: Request) => Promise<Response>;
|
|
24
24
|
/** Default export shape for Vercel's web-standard `{ fetch }` runtime. */
|
|
25
25
|
export interface FetchHandler {
|
package/dist/app.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { WebSocketRegistry, type WebSocketHandler } from "./websocket.js";
|
|
|
2
2
|
import { type Logger } from "./logger.js";
|
|
3
3
|
import type { HttpMethod, Hooks, PathString, RequestSchemas, ResponsesMap, RouteDefinition } from "./types.js";
|
|
4
4
|
import { type OpenAPIInfo, type OpenAPIOptions } from "./openapi.js";
|
|
5
|
-
import { type DocsAssetOptions, type DocsContentSecurityPolicyOptions, type RedocConfiguration, type ScalarJsonValue, type ScalarReferenceConfiguration } from "./docs.js";
|
|
5
|
+
import { type DocsAssetOptions, type DocsContentSecurityPolicyOptions, type RedocConfiguration, type ScalarJsonValue, type ScalarReferenceConfiguration, type SwaggerUiConfiguration } from "./docs.js";
|
|
6
6
|
import { type AsyncAPIServer } from "./asyncapi.js";
|
|
7
7
|
import { type SecureHeadersOptions } from "./middleware.js";
|
|
8
8
|
import { type LoadSheddingOptions } from "./load-shedding.js";
|
|
@@ -246,7 +246,7 @@ export interface AppOptions {
|
|
|
246
246
|
* {@link AppOptions.secureDefaults} is not `false`. Pass `false` to opt
|
|
247
247
|
* out (long-running CLI processes / test harnesses that intentionally
|
|
248
248
|
* swallow rejections may want this). No-op on runtimes without
|
|
249
|
-
* `process.on` (Cloudflare Workers / Vercel
|
|
249
|
+
* `process.on` (Cloudflare Workers / Vercel / Fastly).
|
|
250
250
|
*
|
|
251
251
|
* @since 0.18.0
|
|
252
252
|
*/
|
|
@@ -380,8 +380,21 @@ export interface DocsRouteOptions {
|
|
|
380
380
|
* renders Redoc.
|
|
381
381
|
*/
|
|
382
382
|
ui?: "scalar" | "swagger" | "redoc";
|
|
383
|
-
/**
|
|
383
|
+
/**
|
|
384
|
+
* Scalar API reference UI configuration. Ignored unless `ui` is `"scalar"`.
|
|
385
|
+
* When OpenAPI security schemes are configured and this object does not set
|
|
386
|
+
* `authentication.preferredSecurityScheme`, DaloyJS selects the first scheme
|
|
387
|
+
* so Scalar's developer console opens with an auth type ready to fill.
|
|
388
|
+
*/
|
|
384
389
|
scalar?: ScalarReferenceConfiguration;
|
|
390
|
+
/**
|
|
391
|
+
* Swagger UI configuration, forwarded to `SwaggerUIBundle`. Ignored unless
|
|
392
|
+
* `ui: "swagger"`. DaloyJS owns `url` and `dom_id`; credentials entered in
|
|
393
|
+
* the Authorize dialog persist across reloads by default.
|
|
394
|
+
*
|
|
395
|
+
* @since 0.42.0
|
|
396
|
+
*/
|
|
397
|
+
swagger?: SwaggerUiConfiguration;
|
|
385
398
|
/**
|
|
386
399
|
* Redoc UI configuration, forwarded to `Redoc.init`. Ignored unless
|
|
387
400
|
* `ui: "redoc"`.
|
|
@@ -730,7 +743,7 @@ export declare const DALOY_RAW_STREAM: unique symbol;
|
|
|
730
743
|
* - graceful shutdown and lifecycle observability
|
|
731
744
|
*
|
|
732
745
|
* `App` is **runtime-agnostic**: the same instance runs on Node, Bun, Deno,
|
|
733
|
-
* Cloudflare Workers, Vercel
|
|
746
|
+
* Cloudflare Workers, Vercel, AWS Lambda, and Fastly Compute via the
|
|
734
747
|
* dedicated adapters.
|
|
735
748
|
*
|
|
736
749
|
* @example
|
|
@@ -998,7 +1011,7 @@ export declare class App<Routes extends readonly RouteDefinition<any, any, any,
|
|
|
998
1011
|
* Whether the resolved runtime environment is indeterminate: no explicit
|
|
999
1012
|
* {@link AppOptions.env} / {@link AppOptions.production} was provided AND
|
|
1000
1013
|
* `process.env.NODE_ENV` is unset or empty. This is the common default on
|
|
1001
|
-
* edge runtimes (Cloudflare Workers, Deno Deploy
|
|
1014
|
+
* edge runtimes (Cloudflare Workers, Deno Deploy), which have no
|
|
1002
1015
|
* `NODE_ENV`. Deliberately does not sniff the runtime — it only reports
|
|
1003
1016
|
* whether the environment signal is absent — so it stays runtime-portable.
|
|
1004
1017
|
*
|
package/dist/app.js
CHANGED
|
@@ -630,7 +630,7 @@ export class App {
|
|
|
630
630
|
// The refusals below are production-only. When the environment is
|
|
631
631
|
// *indeterminate* (no explicit `env` / `production` option and no
|
|
632
632
|
// `NODE_ENV` — the common default on edge runtimes such as Workers /
|
|
633
|
-
// Deno Deploy / Vercel
|
|
633
|
+
// Deno Deploy / Vercel), those refusals never fire, so a risky
|
|
634
634
|
// config could ship unguarded. Surface that once as a warning when such
|
|
635
635
|
// a config is actually present. Enforcement is unchanged — this only
|
|
636
636
|
// makes the silent skip observable. The runtime itself is deliberately
|
|
@@ -659,7 +659,7 @@ export class App {
|
|
|
659
659
|
* Whether the resolved runtime environment is indeterminate: no explicit
|
|
660
660
|
* {@link AppOptions.env} / {@link AppOptions.production} was provided AND
|
|
661
661
|
* `process.env.NODE_ENV` is unset or empty. This is the common default on
|
|
662
|
-
* edge runtimes (Cloudflare Workers, Deno Deploy
|
|
662
|
+
* edge runtimes (Cloudflare Workers, Deno Deploy), which have no
|
|
663
663
|
* `NODE_ENV`. Deliberately does not sniff the runtime — it only reports
|
|
664
664
|
* whether the environment signal is absent — so it stays runtime-portable.
|
|
665
665
|
*
|
|
@@ -934,9 +934,16 @@ export class App {
|
|
|
934
934
|
// (unless the caller explicitly overrode it). Scalar / Swagger UI keep the
|
|
935
935
|
// tighter default. The policy is deterministic from `ui` + `opts.csp`, so
|
|
936
936
|
// compute it once at mount time instead of per request.
|
|
937
|
-
const
|
|
938
|
-
|
|
939
|
-
|
|
937
|
+
const docsConnectOrigins = [
|
|
938
|
+
...(opts.csp?.connectOrigins ?? []),
|
|
939
|
+
...serverConnectOrigins(this.options.openapi?.servers),
|
|
940
|
+
];
|
|
941
|
+
const docsCsp = docsContentSecurityPolicy({
|
|
942
|
+
...(ui === "redoc"
|
|
943
|
+
? { ...opts.csp, allowBlobWorkers: opts.csp?.allowBlobWorkers ?? true }
|
|
944
|
+
: opts.csp),
|
|
945
|
+
...(docsConnectOrigins.length ? { connectOrigins: docsConnectOrigins } : {}),
|
|
946
|
+
});
|
|
940
947
|
this.route({
|
|
941
948
|
method: "GET",
|
|
942
949
|
path: docsPath,
|
|
@@ -952,6 +959,7 @@ export class App {
|
|
|
952
959
|
? swaggerUiHtml({
|
|
953
960
|
specUrl: openapiPath,
|
|
954
961
|
title,
|
|
962
|
+
configuration: opts.swagger,
|
|
955
963
|
assets: opts.assets,
|
|
956
964
|
})
|
|
957
965
|
: ui === "redoc"
|
|
@@ -964,7 +972,7 @@ export class App {
|
|
|
964
972
|
: scalarHtml({
|
|
965
973
|
specUrl: openapiPath,
|
|
966
974
|
title,
|
|
967
|
-
configuration: opts.scalar,
|
|
975
|
+
configuration: scalarConfigurationWithPreferredAuth(opts.scalar, this.options.openapi?.securitySchemes),
|
|
968
976
|
assets: opts.assets,
|
|
969
977
|
});
|
|
970
978
|
return {
|
|
@@ -2773,6 +2781,47 @@ function responsePipeline(fns) {
|
|
|
2773
2781
|
return current;
|
|
2774
2782
|
};
|
|
2775
2783
|
}
|
|
2784
|
+
function serverConnectOrigins(servers) {
|
|
2785
|
+
if (!servers)
|
|
2786
|
+
return [];
|
|
2787
|
+
const origins = [];
|
|
2788
|
+
for (const server of servers) {
|
|
2789
|
+
try {
|
|
2790
|
+
const url = new URL(server.url);
|
|
2791
|
+
if ((url.protocol === "http:" || url.protocol === "https:") &&
|
|
2792
|
+
!origins.includes(url.origin)) {
|
|
2793
|
+
origins.push(url.origin);
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
catch {
|
|
2797
|
+
// Relative server URLs are already covered by connect-src 'self'.
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
return origins;
|
|
2801
|
+
}
|
|
2802
|
+
function scalarConfigurationWithPreferredAuth(configuration, schemes) {
|
|
2803
|
+
const preferredSecurityScheme = schemes ? Object.keys(schemes)[0] : undefined;
|
|
2804
|
+
if (!preferredSecurityScheme)
|
|
2805
|
+
return configuration;
|
|
2806
|
+
const authentication = configuration?.authentication;
|
|
2807
|
+
if (authentication &&
|
|
2808
|
+
typeof authentication === "object" &&
|
|
2809
|
+
!Array.isArray(authentication) &&
|
|
2810
|
+
"preferredSecurityScheme" in authentication) {
|
|
2811
|
+
return configuration;
|
|
2812
|
+
}
|
|
2813
|
+
return {
|
|
2814
|
+
...(configuration ?? {}),
|
|
2815
|
+
authentication: {
|
|
2816
|
+
...(authentication &&
|
|
2817
|
+
typeof authentication === "object" &&
|
|
2818
|
+
!Array.isArray(authentication)
|
|
2819
|
+
? authentication
|
|
2820
|
+
: {}),
|
|
2821
|
+
preferredSecurityScheme,
|
|
2822
|
+
},
|
|
2823
|
+
};
|
|
2824
|
+
}
|
|
2776
2825
|
function finalizeResponse(res, ctx, hooks, stripFingerprint = true) {
|
|
2777
2826
|
let final = res;
|
|
2778
2827
|
const finish = (f) => {
|
|
@@ -3133,7 +3182,7 @@ async function readBody(req, ct, limit, multipart) {
|
|
|
3133
3182
|
// chunked upload sends none, and a lying small value slips past the check —
|
|
3134
3183
|
// in both cases the platform parser would otherwise buffer the whole body
|
|
3135
3184
|
// in memory on runtimes whose adapter does not cap at the socket layer
|
|
3136
|
-
// (Workers / Deno / Vercel
|
|
3185
|
+
// (Workers / Deno / Vercel). `readBodyLimited` streams the body and
|
|
3137
3186
|
// throws `PayloadTooLargeError` the instant it exceeds `limit`; we then
|
|
3138
3187
|
// re-parse the bounded bytes with the standard `formData()` parser,
|
|
3139
3188
|
// preserving the multipart boundary via the original Content-Type. This is
|
|
@@ -3360,7 +3409,7 @@ const PACKAGE_JSON_CACHE = {};
|
|
|
3360
3409
|
* none is found while walking up from `process.cwd()`, falls back to
|
|
3361
3410
|
* `deno.json` / `deno.jsonc` so Deno projects get the same DX without a
|
|
3362
3411
|
* `package.json`. Returns an empty object on edge runtimes (Cloudflare
|
|
3363
|
-
* Workers
|
|
3412
|
+
* Workers) where `node:fs` is absent, on any I/O or parse
|
|
3364
3413
|
* error, and when nothing is found.
|
|
3365
3414
|
*
|
|
3366
3415
|
* The result is memoized at module scope: manifests do not change
|
package/dist/compression.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* BREACH-aware safe defaults.
|
|
4
4
|
*
|
|
5
5
|
* Built on the web-standard `CompressionStream` API so the same line works
|
|
6
|
-
* on Node, Bun, Deno, Cloudflare Workers, Vercel
|
|
6
|
+
* on Node, Bun, Deno, Cloudflare Workers, Vercel, and Fastly Compute.
|
|
7
7
|
* The middleware deliberately refuses to expose a configurable compression
|
|
8
8
|
* level — `CompressionStream` uses the runtime's documented default (gzip
|
|
9
9
|
* level 6 on Node / V8); a `level: 9` opt-in is rejected at construction
|
|
@@ -68,10 +68,10 @@ export interface CompressionOptions {
|
|
|
68
68
|
*/
|
|
69
69
|
authCookieNames?: readonly string[];
|
|
70
70
|
/**
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
* Deliberately unsupported. Provided as a `never`-typed trap so the type
|
|
72
|
+
* system flags accidental opt-in. The actual `CompressionStream` never
|
|
73
|
+
* exposes a level knob — passing any value triggers a construction-time
|
|
74
|
+
* refusal.
|
|
75
75
|
*
|
|
76
76
|
* @internal
|
|
77
77
|
*/
|
package/dist/compression.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* BREACH-aware safe defaults.
|
|
4
4
|
*
|
|
5
5
|
* Built on the web-standard `CompressionStream` API so the same line works
|
|
6
|
-
* on Node, Bun, Deno, Cloudflare Workers, Vercel
|
|
6
|
+
* on Node, Bun, Deno, Cloudflare Workers, Vercel, and Fastly Compute.
|
|
7
7
|
* The middleware deliberately refuses to expose a configurable compression
|
|
8
8
|
* level — `CompressionStream` uses the runtime's documented default (gzip
|
|
9
9
|
* level 6 on Node / V8); a `level: 9` opt-in is rejected at construction
|
package/dist/docs.d.ts
CHANGED
|
@@ -254,7 +254,7 @@ export interface DocsAssetOptions {
|
|
|
254
254
|
*/
|
|
255
255
|
crossOrigin?: "anonymous" | "use-credentials";
|
|
256
256
|
}
|
|
257
|
-
/** Shared options for {@link scalarHtml} and {@link
|
|
257
|
+
/** Shared options for {@link scalarHtml}, {@link swaggerUiHtml}, and {@link redocHtml}. */
|
|
258
258
|
export interface DocsOptions {
|
|
259
259
|
/** Absolute or relative URL of the OpenAPI document to render. */
|
|
260
260
|
specUrl: string;
|
|
@@ -273,6 +273,53 @@ export interface ScalarHtmlOptions extends DocsOptions {
|
|
|
273
273
|
/** Forwarded to the Scalar `<script id="api-reference">` tag. */
|
|
274
274
|
configuration?: ScalarReferenceConfiguration;
|
|
275
275
|
}
|
|
276
|
+
/** JSON-only subset of Swagger UI's `SwaggerUIBundle(...)` configuration. */
|
|
277
|
+
export interface SwaggerUiConfiguration {
|
|
278
|
+
[key: string]: ScalarJsonValue | undefined;
|
|
279
|
+
/**
|
|
280
|
+
* Preserve developer-entered API credentials across reloads. Defaults to
|
|
281
|
+
* `true` in {@link swaggerUiHtml} so the built-in docs behave like a local
|
|
282
|
+
* developer console instead of forgetting the bearer token on every refresh.
|
|
283
|
+
*/
|
|
284
|
+
persistAuthorization?: boolean;
|
|
285
|
+
/** Expand operations by default: `"list"`, `"full"`, or `"none"`. */
|
|
286
|
+
docExpansion?: "list" | "full" | "none";
|
|
287
|
+
/** Enable filtering operations by tag/path text. */
|
|
288
|
+
filter?: boolean | string;
|
|
289
|
+
/** Show operation extension fields such as `x-*`. */
|
|
290
|
+
showExtensions?: boolean;
|
|
291
|
+
/** Show common extension fields. */
|
|
292
|
+
showCommonExtensions?: boolean;
|
|
293
|
+
/** Render request duration after "Try it out" calls. */
|
|
294
|
+
displayRequestDuration?: boolean;
|
|
295
|
+
/** Sort operations by HTTP method, alphabetically, or with no sorter. */
|
|
296
|
+
operationsSorter?: "alpha" | "method";
|
|
297
|
+
/** Sort tags alphabetically or with no sorter. */
|
|
298
|
+
tagsSorter?: "alpha";
|
|
299
|
+
/**
|
|
300
|
+
* Internal URL wiring owned by DaloyJS. Use {@link DocsOptions.specUrl}
|
|
301
|
+
* instead of passing Swagger UI's `url` directly.
|
|
302
|
+
*/
|
|
303
|
+
url?: never;
|
|
304
|
+
/**
|
|
305
|
+
* Internal DOM mount point owned by DaloyJS. The generated HTML always mounts
|
|
306
|
+
* Swagger UI into `#swagger`.
|
|
307
|
+
*/
|
|
308
|
+
dom_id?: never;
|
|
309
|
+
/** Function-valued Swagger UI plugins cannot cross the server-to-HTML boundary. */
|
|
310
|
+
plugins?: never;
|
|
311
|
+
/** Function-valued presets cannot cross the server-to-HTML boundary. */
|
|
312
|
+
presets?: never;
|
|
313
|
+
/** Function-valued request interceptors cannot cross the server-to-HTML boundary. */
|
|
314
|
+
requestInterceptor?: never;
|
|
315
|
+
/** Function-valued response interceptors cannot cross the server-to-HTML boundary. */
|
|
316
|
+
responseInterceptor?: never;
|
|
317
|
+
}
|
|
318
|
+
/** Options for {@link swaggerUiHtml}; adds Swagger UI-specific configuration. */
|
|
319
|
+
export interface SwaggerUiHtmlOptions extends DocsOptions {
|
|
320
|
+
/** Forwarded into `SwaggerUIBundle(...)` after `url` and `dom_id`. */
|
|
321
|
+
configuration?: SwaggerUiConfiguration;
|
|
322
|
+
}
|
|
276
323
|
/**
|
|
277
324
|
* Options for {@link redocHtml}; adds Redoc-specific UI configuration.
|
|
278
325
|
*
|
|
@@ -300,6 +347,14 @@ export interface AsyncApiHtmlOptions extends DocsOptions {
|
|
|
300
347
|
export interface DocsContentSecurityPolicyOptions {
|
|
301
348
|
/** Extra origins to allow for `script-src` / `style-src` (defaults to jsDelivr). */
|
|
302
349
|
assetOrigins?: string[];
|
|
350
|
+
/**
|
|
351
|
+
* Extra origins to allow for `connect-src`. Add API origins here when the
|
|
352
|
+
* docs UI should send "Try it" requests somewhere other than the same origin
|
|
353
|
+
* serving the docs page.
|
|
354
|
+
*
|
|
355
|
+
* @since 0.42.0
|
|
356
|
+
*/
|
|
357
|
+
connectOrigins?: string[];
|
|
303
358
|
/** When set, allows nonce-protected inline scripts instead of `'unsafe-inline'`. */
|
|
304
359
|
scriptNonce?: string;
|
|
305
360
|
/** When `false`, omits `'unsafe-inline'` from `style-src`. Defaults to `true`. */
|
|
@@ -331,8 +386,12 @@ export declare function scalarHtml(opts: ScalarHtmlOptions): string;
|
|
|
331
386
|
/**
|
|
332
387
|
* Render a Swagger UI HTML page that loads `opts.specUrl`. Same usage as
|
|
333
388
|
* {@link scalarHtml} but emits the classic Swagger UI bundle.
|
|
389
|
+
*
|
|
390
|
+
* Developer-entered credentials are persisted by default
|
|
391
|
+
* (`persistAuthorization: true`) so routes with OpenAPI security requirements
|
|
392
|
+
* can be exercised after using Swagger UI's Authorize dialog.
|
|
334
393
|
*/
|
|
335
|
-
export declare function swaggerUiHtml(opts:
|
|
394
|
+
export declare function swaggerUiHtml(opts: SwaggerUiHtmlOptions): string;
|
|
336
395
|
/**
|
|
337
396
|
* Render a Redoc HTML page that loads `opts.specUrl`. Same usage as
|
|
338
397
|
* {@link scalarHtml} / {@link swaggerUiHtml} but emits the Redoc standalone
|
package/dist/docs.js
CHANGED
|
@@ -67,10 +67,13 @@ export function scalarHtml(opts) {
|
|
|
67
67
|
/**
|
|
68
68
|
* Render a Swagger UI HTML page that loads `opts.specUrl`. Same usage as
|
|
69
69
|
* {@link scalarHtml} but emits the classic Swagger UI bundle.
|
|
70
|
+
*
|
|
71
|
+
* Developer-entered credentials are persisted by default
|
|
72
|
+
* (`persistAuthorization: true`) so routes with OpenAPI security requirements
|
|
73
|
+
* can be exercised after using Swagger UI's Authorize dialog.
|
|
70
74
|
*/
|
|
71
75
|
export function swaggerUiHtml(opts) {
|
|
72
76
|
const title = escapeHtml(opts.title ?? "API Docs");
|
|
73
|
-
const url = escapeHtml(opts.specUrl);
|
|
74
77
|
const cssUrl = escapeHtml(opts.assets?.swaggerUiCssUrl ??
|
|
75
78
|
`${JSDELIVR_ORIGIN}/npm/swagger-ui-dist/swagger-ui.css`);
|
|
76
79
|
const bundleUrl = escapeHtml(opts.assets?.swaggerUiBundleUrl ??
|
|
@@ -78,6 +81,12 @@ export function swaggerUiHtml(opts) {
|
|
|
78
81
|
const cssSri = integrityAttr(opts.assets?.swaggerUiCssIntegrity, opts.assets?.crossOrigin);
|
|
79
82
|
const bundleSri = integrityAttr(opts.assets?.swaggerUiBundleIntegrity, opts.assets?.crossOrigin);
|
|
80
83
|
const nonce = nonceAttr(opts.scriptNonce);
|
|
84
|
+
const configuration = jsonForScript({
|
|
85
|
+
persistAuthorization: true,
|
|
86
|
+
...(opts.configuration ?? {}),
|
|
87
|
+
url: opts.specUrl,
|
|
88
|
+
dom_id: "#swagger",
|
|
89
|
+
});
|
|
81
90
|
return `<!doctype html>
|
|
82
91
|
<html><head>
|
|
83
92
|
<meta charset="utf-8" />
|
|
@@ -87,7 +96,7 @@ export function swaggerUiHtml(opts) {
|
|
|
87
96
|
</head><body>
|
|
88
97
|
<div id="swagger"></div>
|
|
89
98
|
<script src="${bundleUrl}"${bundleSri}${nonce}></script>
|
|
90
|
-
<script${nonce}>window.onload=()=>SwaggerUIBundle(
|
|
99
|
+
<script${nonce}>window.onload=()=>SwaggerUIBundle(${configuration});</script>
|
|
91
100
|
</body></html>`;
|
|
92
101
|
}
|
|
93
102
|
/**
|
|
@@ -179,12 +188,13 @@ export function docsContentSecurityPolicy(opts = {}) {
|
|
|
179
188
|
const styleSrc = ["'self'", ...assetOrigins];
|
|
180
189
|
if (opts.allowInlineStyles !== false)
|
|
181
190
|
styleSrc.push("'unsafe-inline'");
|
|
191
|
+
const connectSrc = ["'self'", ...(opts.connectOrigins ?? [])];
|
|
182
192
|
const directives = [
|
|
183
193
|
"default-src 'self'",
|
|
184
194
|
`script-src ${scriptSrc.join(" ")}`,
|
|
185
195
|
`style-src ${styleSrc.join(" ")}`,
|
|
186
196
|
"img-src 'self' data: https:",
|
|
187
|
-
|
|
197
|
+
`connect-src ${connectSrc.join(" ")}`,
|
|
188
198
|
];
|
|
189
199
|
// Redoc spawns a Web Worker from a `blob:` URL; without an explicit
|
|
190
200
|
// worker-src the browser falls back to script-src, which forbids `blob:`
|
|
@@ -205,6 +215,7 @@ export function htmlResponse(html, opts = {}) {
|
|
|
205
215
|
"content-security-policy": opts.contentSecurityPolicy ??
|
|
206
216
|
docsContentSecurityPolicy({
|
|
207
217
|
assetOrigins: opts.assetOrigins,
|
|
218
|
+
connectOrigins: opts.connectOrigins,
|
|
208
219
|
scriptNonce: opts.scriptNonce,
|
|
209
220
|
allowInlineStyles: opts.allowInlineStyles,
|
|
210
221
|
}),
|
package/dist/idempotency.d.ts
CHANGED
package/dist/idempotency.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -74,7 +74,7 @@ export type { RequestIdOptions, SecureHeadersOptions, CspDirectivesOptions, Cors
|
|
|
74
74
|
export type { BearerAuthOptions, BearerAuthVerifyHook } from "./middleware.js";
|
|
75
75
|
export { createLogger, noopLogger, DEFAULT_REDACT_KEYS } from "./logger.js";
|
|
76
76
|
export type { Logger, LogLevel, ConsoleLoggerOptions, LoggerRedactionOptions, } from "./logger.js";
|
|
77
|
-
export type { ScalarJsonPrimitive, ScalarJsonValue, ScalarReferenceConfiguration, ScalarTheme, RedocConfiguration, RedocHtmlOptions, AsyncApiHtmlOptions, DocsAssetOptions, } from "./docs.js";
|
|
77
|
+
export type { ScalarJsonPrimitive, ScalarJsonValue, ScalarReferenceConfiguration, ScalarTheme, RedocConfiguration, RedocHtmlOptions, SwaggerUiConfiguration, SwaggerUiHtmlOptions, AsyncApiHtmlOptions, DocsAssetOptions, } from "./docs.js";
|
|
78
78
|
export { formatStartupBanner, printStartupBanner } from "./banner.js";
|
|
79
79
|
export type { StartupBannerLink, StartupBannerOptions } from "./banner.js";
|
|
80
80
|
export { sseStream, sseResponse, ndjsonStream, ndjsonResponse, } from "./streaming.js";
|
package/dist/metrics.d.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*
|
|
19
19
|
* Everything is built on Web-standard primitives (plus optional `process.*`
|
|
20
20
|
* gauges guarded for non-Node runtimes), so it runs unchanged on Node, Bun,
|
|
21
|
-
* Deno, Cloudflare Workers, and Vercel
|
|
21
|
+
* Deno, Cloudflare Workers, and Vercel.
|
|
22
22
|
*
|
|
23
23
|
* @module
|
|
24
24
|
* @since 0.37.0
|
package/dist/metrics.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*
|
|
19
19
|
* Everything is built on Web-standard primitives (plus optional `process.*`
|
|
20
20
|
* gauges guarded for non-Node runtimes), so it runs unchanged on Node, Bun,
|
|
21
|
-
* Deno, Cloudflare Workers, and Vercel
|
|
21
|
+
* Deno, Cloudflare Workers, and Vercel.
|
|
22
22
|
*
|
|
23
23
|
* @module
|
|
24
24
|
* @since 0.37.0
|
|
@@ -231,10 +231,7 @@ export class Histogram extends Metric {
|
|
|
231
231
|
}
|
|
232
232
|
/** @internal */
|
|
233
233
|
render() {
|
|
234
|
-
const lines = [
|
|
235
|
-
`# HELP ${this.name} ${escapeHelp(this.help)}`,
|
|
236
|
-
`# TYPE ${this.name} histogram`,
|
|
237
|
-
];
|
|
234
|
+
const lines = [`# HELP ${this.name} ${escapeHelp(this.help)}`, `# TYPE ${this.name} histogram`];
|
|
238
235
|
for (const s of this.series.values()) {
|
|
239
236
|
for (let i = 0; i < this.bounds.length; i++) {
|
|
240
237
|
lines.push(`${this.name}_bucket${renderLabelBlock(s.labels, ["le", String(this.bounds[i])])} ${s.counts[i]}`);
|
package/dist/middleware.d.ts
CHANGED
|
@@ -72,7 +72,7 @@ export interface CspDirectivesOptions {
|
|
|
72
72
|
* Pair with {@link SecureHeadersOptions.reportingEndpoints} (or
|
|
73
73
|
* {@link App.cspReportRoute}) to register the receiver.
|
|
74
74
|
*
|
|
75
|
-
|
|
75
|
+
* @since 0.20.0
|
|
76
76
|
*/
|
|
77
77
|
reportTo?: string;
|
|
78
78
|
}
|
|
@@ -112,7 +112,7 @@ export interface SecureHeadersOptions {
|
|
|
112
112
|
* `reportTo: "csp-endpoint"` here as a shortcut) to direct CSP
|
|
113
113
|
* violation reports there.
|
|
114
114
|
*
|
|
115
|
-
|
|
115
|
+
* @since 0.20.0
|
|
116
116
|
*/
|
|
117
117
|
reportingEndpoints?: Record<string, string>;
|
|
118
118
|
/**
|
|
@@ -121,7 +121,7 @@ export interface SecureHeadersOptions {
|
|
|
121
121
|
* header so violation reports land at the matching
|
|
122
122
|
* `reportingEndpoints` URL.
|
|
123
123
|
*
|
|
124
|
-
|
|
124
|
+
* @since 0.20.0
|
|
125
125
|
*/
|
|
126
126
|
reportTo?: string;
|
|
127
127
|
}
|
|
@@ -500,9 +500,9 @@ export interface BearerAuthOptions {
|
|
|
500
500
|
realm?: string;
|
|
501
501
|
/**
|
|
502
502
|
* Optional per-request revalidation hook. Called after `validate`
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
503
|
+
* accepts the token. Returning `false` rejects the request with `403`;
|
|
504
|
+
* returning `true` or `undefined` accepts. Use for revocation lists,
|
|
505
|
+
* token-version counters, etc.
|
|
506
506
|
*
|
|
507
507
|
* @since 0.22.0
|
|
508
508
|
*/
|
package/dist/middleware.js
CHANGED
|
@@ -44,7 +44,7 @@ function generateCspNonce() {
|
|
|
44
44
|
const cryptoApi = globalThis.crypto;
|
|
45
45
|
if (!cryptoApi?.getRandomValues) {
|
|
46
46
|
throw new Error("secureHeaders(): WebCrypto is required to generate a CSP nonce. " +
|
|
47
|
-
"Run on Node 20+, Bun, Deno, Cloudflare Workers, or Vercel
|
|
47
|
+
"Run on Node 20+, Bun, Deno, Cloudflare Workers, or Vercel.");
|
|
48
48
|
}
|
|
49
49
|
const nonceBytes = new Uint8Array(16);
|
|
50
50
|
cryptoApi.getRandomValues(nonceBytes);
|
|
@@ -193,10 +193,7 @@ export function secureHeaders(opts = {}) {
|
|
|
193
193
|
}
|
|
194
194
|
cspOpt = { directives, reportTo: opts.reportTo };
|
|
195
195
|
}
|
|
196
|
-
else if (opts.reportTo &&
|
|
197
|
-
cspOpt !== false &&
|
|
198
|
-
typeof cspOpt === "object" &&
|
|
199
|
-
!cspOpt.reportTo) {
|
|
196
|
+
else if (opts.reportTo && cspOpt !== false && typeof cspOpt === "object" && !cspOpt.reportTo) {
|
|
200
197
|
cspOpt = { ...cspOpt, reportTo: opts.reportTo };
|
|
201
198
|
}
|
|
202
199
|
const cspIsDynamic = cspOpt !== false && typeof cspOpt === "object";
|
|
@@ -479,10 +476,9 @@ export function cors(opts) {
|
|
|
479
476
|
// produces broken-but-not-obviously-broken behavior in production. Fail
|
|
480
477
|
// closed at construction time instead.
|
|
481
478
|
if (opts.credentials) {
|
|
482
|
-
const includesWildcard = opts.origin === "*" ||
|
|
483
|
-
(Array.isArray(opts.origin) && opts.origin.includes("*"));
|
|
479
|
+
const includesWildcard = opts.origin === "*" || (Array.isArray(opts.origin) && opts.origin.includes("*"));
|
|
484
480
|
if (includesWildcard) {
|
|
485
|
-
throw new Error(
|
|
481
|
+
throw new Error('cors(): origin: "*" cannot be combined with credentials: true. ' +
|
|
486
482
|
"Pass an explicit origin string, an array of allowed origins, or a predicate function instead.");
|
|
487
483
|
}
|
|
488
484
|
}
|
|
@@ -558,8 +554,7 @@ export function cors(opts) {
|
|
|
558
554
|
};
|
|
559
555
|
hooks[CORS_HOOK_MARKER] = true;
|
|
560
556
|
hooks[CORS_ORIGIN_ALLOW_MARKER] = (origin) => allow(origin) !== null;
|
|
561
|
-
const hasWildcard = opts.origin === "*" ||
|
|
562
|
-
(Array.isArray(opts.origin) && opts.origin.includes("*"));
|
|
557
|
+
const hasWildcard = opts.origin === "*" || (Array.isArray(opts.origin) && opts.origin.includes("*"));
|
|
563
558
|
if (hasWildcard) {
|
|
564
559
|
hooks[CORS_WILDCARD_ORIGIN_MARKER] = true;
|
|
565
560
|
}
|
|
@@ -732,9 +727,7 @@ export function loginThrottle(opts = {}) {
|
|
|
732
727
|
groupId,
|
|
733
728
|
keyGenerator,
|
|
734
729
|
...(opts.store ? { store: opts.store } : {}),
|
|
735
|
-
...(opts.trustProxyHeaders !== undefined
|
|
736
|
-
? { trustProxyHeaders: opts.trustProxyHeaders }
|
|
737
|
-
: {}),
|
|
730
|
+
...(opts.trustProxyHeaders !== undefined ? { trustProxyHeaders: opts.trustProxyHeaders } : {}),
|
|
738
731
|
...(opts.retryAfter !== undefined ? { retryAfter: opts.retryAfter } : {}),
|
|
739
732
|
});
|
|
740
733
|
let slowdownBuckets = SHARED_LOGIN_THROTTLE_BUCKETS.get(groupId);
|
|
@@ -1229,9 +1222,7 @@ export function requireScopes(scopes) {
|
|
|
1229
1222
|
});
|
|
1230
1223
|
}
|
|
1231
1224
|
const owned = readUserScopes(user);
|
|
1232
|
-
const missing = owned === null
|
|
1233
|
-
? aggregate.slice()
|
|
1234
|
-
: aggregate.filter((s) => !owned.has(s));
|
|
1225
|
+
const missing = owned === null ? aggregate.slice() : aggregate.filter((s) => !owned.has(s));
|
|
1235
1226
|
if (missing.length > 0) {
|
|
1236
1227
|
throw new ForbiddenError(`Missing required scope(s): ${missing.join(", ")}.`);
|
|
1237
1228
|
}
|
package/dist/pagination.d.ts
CHANGED
package/dist/pagination.js
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
*
|
|
25
25
|
* The compressed input itself is bounded by `maxCompressedBytes` before a single
|
|
26
26
|
* byte is inflated. Built on the web-standard `DecompressionStream`, so the same
|
|
27
|
-
* line works on Node, Bun, Deno, Cloudflare Workers, and Vercel
|
|
27
|
+
* line works on Node, Bun, Deno, Cloudflare Workers, and Vercel. Zero
|
|
28
28
|
* runtime dependencies.
|
|
29
29
|
*
|
|
30
30
|
* The middleware runs in the {@link "./types.js".Hooks.onRequest} phase — before
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
*
|
|
25
25
|
* The compressed input itself is bounded by `maxCompressedBytes` before a single
|
|
26
26
|
* byte is inflated. Built on the web-standard `DecompressionStream`, so the same
|
|
27
|
-
* line works on Node, Bun, Deno, Cloudflare Workers, and Vercel
|
|
27
|
+
* line works on Node, Bun, Deno, Cloudflare Workers, and Vercel. Zero
|
|
28
28
|
* runtime dependencies.
|
|
29
29
|
*
|
|
30
30
|
* The middleware runs in the {@link "./types.js".Hooks.onRequest} phase — before
|
package/dist/response-cache.d.ts
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
*
|
|
35
35
|
* This module is dependency-free and uses only Web Standard
|
|
36
36
|
* `Request`/`Response` + `Headers`, so it runs unchanged on Node, Bun, Deno,
|
|
37
|
-
* Cloudflare Workers, and Vercel
|
|
37
|
+
* Cloudflare Workers, and Vercel.
|
|
38
38
|
*
|
|
39
39
|
* @module
|
|
40
40
|
* @since 0.37.0
|
package/dist/response-cache.js
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
*
|
|
35
35
|
* This module is dependency-free and uses only Web Standard
|
|
36
36
|
* `Request`/`Response` + `Headers`, so it runs unchanged on Node, Bun, Deno,
|
|
37
|
-
* Cloudflare Workers, and Vercel
|
|
37
|
+
* Cloudflare Workers, and Vercel.
|
|
38
38
|
*
|
|
39
39
|
* @module
|
|
40
40
|
* @since 0.37.0
|
|
@@ -304,9 +304,7 @@ export function responseCache(opts = {}) {
|
|
|
304
304
|
const reqCc = parseCacheControl(ctx.request.headers.get("cache-control"));
|
|
305
305
|
if (reqCc.has("no-store"))
|
|
306
306
|
return undefined;
|
|
307
|
-
const rawKey = opts.keyGenerator
|
|
308
|
-
? opts.keyGenerator(ctx)
|
|
309
|
-
: defaultKey(ctx, varyHeaders);
|
|
307
|
+
const rawKey = opts.keyGenerator ? opts.keyGenerator(ctx) : defaultKey(ctx, varyHeaders);
|
|
310
308
|
if (rawKey === null)
|
|
311
309
|
return undefined;
|
|
312
310
|
const key = `${keyPrefix}${rawKey}`;
|
package/dist/sbom.cdx.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bomFormat": "CycloneDX",
|
|
3
3
|
"specVersion": "1.5",
|
|
4
|
-
"serialNumber": "urn:uuid:
|
|
4
|
+
"serialNumber": "urn:uuid:086b2383-b351-57fb-bd98-0fbf04f2342b",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
|
-
"timestamp": "2026-06-
|
|
7
|
+
"timestamp": "2026-06-22T21:07:28.471Z",
|
|
8
8
|
"tools": [
|
|
9
9
|
{
|
|
10
10
|
"vendor": "DaloyJS",
|
|
11
11
|
"name": "daloy-generate-sbom",
|
|
12
|
-
"version": "1.0.0-beta.
|
|
12
|
+
"version": "1.0.0-beta.2"
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
15
|
"authors": [
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
],
|
|
20
20
|
"component": {
|
|
21
21
|
"type": "library",
|
|
22
|
-
"bom-ref": "pkg:npm/@daloyjs/core@1.0.0-beta.
|
|
22
|
+
"bom-ref": "pkg:npm/@daloyjs/core@1.0.0-beta.2",
|
|
23
23
|
"name": "@daloyjs/core",
|
|
24
|
-
"version": "1.0.0-beta.
|
|
24
|
+
"version": "1.0.0-beta.2",
|
|
25
25
|
"description": "DaloyJS is a runtime-portable, contract-first TypeScript web framework with built-in OpenAPI (Hey API), typed client generation, large-scale maintainability, and security-first defaults. Hono-grade portability, Elysia-grade DX, FastAPI-grade docs, Fastify-grade ops — distributed via pnpm.",
|
|
26
|
-
"purl": "pkg:npm/@daloyjs/core@1.0.0-beta.
|
|
26
|
+
"purl": "pkg:npm/@daloyjs/core@1.0.0-beta.2",
|
|
27
27
|
"licenses": [
|
|
28
28
|
{
|
|
29
29
|
"license": {
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
}
|
|
47
47
|
],
|
|
48
48
|
"swid": {
|
|
49
|
-
"tagId": "swidtag--daloyjs-core-1.0.0-beta.
|
|
49
|
+
"tagId": "swidtag--daloyjs-core-1.0.0-beta.2",
|
|
50
50
|
"name": "@daloyjs/core",
|
|
51
|
-
"version": "1.0.0-beta.
|
|
51
|
+
"version": "1.0.0-beta.2",
|
|
52
52
|
"tagVersion": 0,
|
|
53
53
|
"patch": false
|
|
54
54
|
}
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"components": [],
|
|
58
58
|
"dependencies": [
|
|
59
59
|
{
|
|
60
|
-
"ref": "pkg:npm/@daloyjs/core@1.0.0-beta.
|
|
60
|
+
"ref": "pkg:npm/@daloyjs/core@1.0.0-beta.2",
|
|
61
61
|
"dependsOn": []
|
|
62
62
|
}
|
|
63
63
|
]
|
package/dist/sbom.spdx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"spdxVersion": "SPDX-2.3",
|
|
3
3
|
"dataLicense": "CC0-1.0",
|
|
4
4
|
"SPDXID": "SPDXRef-DOCUMENT",
|
|
5
|
-
"name": "@daloyjs/core-1.0.0-beta.
|
|
6
|
-
"documentNamespace": "https://github.com/daloyjs/daloy/sbom/@daloyjs/core-1.0.0-beta.
|
|
5
|
+
"name": "@daloyjs/core-1.0.0-beta.2",
|
|
6
|
+
"documentNamespace": "https://github.com/daloyjs/daloy/sbom/@daloyjs/core-1.0.0-beta.2-086b2383-b351-57fb-bd98-0fbf04f2342b",
|
|
7
7
|
"creationInfo": {
|
|
8
|
-
"created": "2026-06-
|
|
8
|
+
"created": "2026-06-22T21:07:28.471Z",
|
|
9
9
|
"creators": [
|
|
10
10
|
"Tool: daloy-generate-sbom",
|
|
11
11
|
"Organization: DaloyJS"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
{
|
|
17
17
|
"SPDXID": "SPDXRef-Package--daloyjs-core",
|
|
18
18
|
"name": "@daloyjs/core",
|
|
19
|
-
"versionInfo": "1.0.0-beta.
|
|
19
|
+
"versionInfo": "1.0.0-beta.2",
|
|
20
20
|
"downloadLocation": "https://github.com/daloyjs/daloy",
|
|
21
21
|
"filesAnalyzed": false,
|
|
22
22
|
"licenseConcluded": "MIT",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
{
|
|
28
28
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
29
29
|
"referenceType": "purl",
|
|
30
|
-
"referenceLocator": "pkg:npm/@daloyjs/core@1.0.0-beta.
|
|
30
|
+
"referenceLocator": "pkg:npm/@daloyjs/core@1.0.0-beta.2"
|
|
31
31
|
}
|
|
32
32
|
]
|
|
33
33
|
}
|
package/dist/scheduler.d.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*
|
|
23
23
|
* Everything is built on Web-standard primitives (`AbortController`,
|
|
24
24
|
* `Intl.DateTimeFormat` for timezone wall-clock math, `setTimeout`), so it
|
|
25
|
-
* runs unchanged on Node, Bun, Deno, Cloudflare Workers, and Vercel
|
|
25
|
+
* runs unchanged on Node, Bun, Deno, Cloudflare Workers, and Vercel, with
|
|
26
26
|
* zero runtime dependencies. Pair it with {@link App.cron} for an app-managed
|
|
27
27
|
* scheduler whose lifecycle is tied to graceful shutdown, or drive a
|
|
28
28
|
* {@link Scheduler} directly.
|
package/dist/scheduler.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*
|
|
23
23
|
* Everything is built on Web-standard primitives (`AbortController`,
|
|
24
24
|
* `Intl.DateTimeFormat` for timezone wall-clock math, `setTimeout`), so it
|
|
25
|
-
* runs unchanged on Node, Bun, Deno, Cloudflare Workers, and Vercel
|
|
25
|
+
* runs unchanged on Node, Bun, Deno, Cloudflare Workers, and Vercel, with
|
|
26
26
|
* zero runtime dependencies. Pair it with {@link App.cron} for an app-managed
|
|
27
27
|
* scheduler whose lifecycle is tied to graceful shutdown, or drive a
|
|
28
28
|
* {@link Scheduler} directly.
|
|
@@ -63,11 +63,27 @@ const CRON_ALIASES = {
|
|
|
63
63
|
"@hourly": "0 * * * *",
|
|
64
64
|
};
|
|
65
65
|
const MONTH_NAMES = {
|
|
66
|
-
jan: 1,
|
|
67
|
-
|
|
66
|
+
jan: 1,
|
|
67
|
+
feb: 2,
|
|
68
|
+
mar: 3,
|
|
69
|
+
apr: 4,
|
|
70
|
+
may: 5,
|
|
71
|
+
jun: 6,
|
|
72
|
+
jul: 7,
|
|
73
|
+
aug: 8,
|
|
74
|
+
sep: 9,
|
|
75
|
+
oct: 10,
|
|
76
|
+
nov: 11,
|
|
77
|
+
dec: 12,
|
|
68
78
|
};
|
|
69
79
|
const DAY_NAMES = {
|
|
70
|
-
sun: 0,
|
|
80
|
+
sun: 0,
|
|
81
|
+
mon: 1,
|
|
82
|
+
tue: 2,
|
|
83
|
+
wed: 3,
|
|
84
|
+
thu: 4,
|
|
85
|
+
fri: 5,
|
|
86
|
+
sat: 6,
|
|
71
87
|
};
|
|
72
88
|
function resolveNamed(token, names) {
|
|
73
89
|
const lower = token.toLowerCase();
|
|
@@ -163,7 +179,13 @@ export function parseCron(expression) {
|
|
|
163
179
|
};
|
|
164
180
|
}
|
|
165
181
|
const WEEKDAY_INDEX = {
|
|
166
|
-
Sun: 0,
|
|
182
|
+
Sun: 0,
|
|
183
|
+
Mon: 1,
|
|
184
|
+
Tue: 2,
|
|
185
|
+
Wed: 3,
|
|
186
|
+
Thu: 4,
|
|
187
|
+
Fri: 5,
|
|
188
|
+
Sat: 6,
|
|
167
189
|
};
|
|
168
190
|
function wallClockOf(date, timeZone) {
|
|
169
191
|
if (timeZone === undefined || timeZone === "UTC") {
|
|
@@ -323,7 +345,12 @@ export class Scheduler {
|
|
|
323
345
|
skipped: 0,
|
|
324
346
|
};
|
|
325
347
|
this.#tasks.set(def.name, task);
|
|
326
|
-
this.#logger?.debug({
|
|
348
|
+
this.#logger?.debug({
|
|
349
|
+
event: "scheduler.task.defined",
|
|
350
|
+
task: def.name,
|
|
351
|
+
cron: def.cron,
|
|
352
|
+
intervalMs: def.intervalMs,
|
|
353
|
+
}, `Scheduled task "${def.name}" defined`);
|
|
327
354
|
if (this.#started && !this.#stopped)
|
|
328
355
|
this.#arm(task, def.runOnStart === true);
|
|
329
356
|
return this;
|
|
@@ -518,7 +545,13 @@ export class Scheduler {
|
|
|
518
545
|
catch (error) {
|
|
519
546
|
task.failures++;
|
|
520
547
|
task.lastError = error;
|
|
521
|
-
this.#logger?.error({
|
|
548
|
+
this.#logger?.error({
|
|
549
|
+
event: "scheduler.task.failed",
|
|
550
|
+
task: task.def.name,
|
|
551
|
+
runCount,
|
|
552
|
+
timedOut,
|
|
553
|
+
err: serializeError(error),
|
|
554
|
+
}, `Scheduled task "${task.def.name}" failed`);
|
|
522
555
|
try {
|
|
523
556
|
task.def.onError?.(error, { name: task.def.name, runCount, timedOut });
|
|
524
557
|
}
|
package/dist/session.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* backed by Redis, Cloudflare KV, Vercel KV, or any other shared store.
|
|
14
14
|
*
|
|
15
15
|
* The module is dependency-free and uses Web Crypto (`crypto.subtle`), so it
|
|
16
|
-
* works on Node, Bun, Deno, Cloudflare Workers, and Vercel
|
|
16
|
+
* works on Node, Bun, Deno, Cloudflare Workers, and Vercel.
|
|
17
17
|
*/
|
|
18
18
|
import type { BaseContext, Hooks } from "./types.js";
|
|
19
19
|
/**
|
package/dist/session.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* backed by Redis, Cloudflare KV, Vercel KV, or any other shared store.
|
|
14
14
|
*
|
|
15
15
|
* The module is dependency-free and uses Web Crypto (`crypto.subtle`), so it
|
|
16
|
-
* works on Node, Bun, Deno, Cloudflare Workers, and Vercel
|
|
16
|
+
* works on Node, Bun, Deno, Cloudflare Workers, and Vercel.
|
|
17
17
|
*/
|
|
18
18
|
import { assertCookieAttributes, readRequestCookie, serializeClearCookie, serializeCookie, } from "./cookie.js";
|
|
19
19
|
import { timingSafeEqual } from "./security.js";
|
|
@@ -385,7 +385,9 @@ const DEFAULT_ROTATE_SESSION_KEYS = [
|
|
|
385
385
|
];
|
|
386
386
|
function sessionFromContext(ctx) {
|
|
387
387
|
const value = ctx.state[STATE_KEY];
|
|
388
|
-
if (!value ||
|
|
388
|
+
if (!value ||
|
|
389
|
+
typeof value !== "object" ||
|
|
390
|
+
typeof value.regenerate !== "function") {
|
|
389
391
|
throw new Error("rotateSession(): session() must run before rotateSession().");
|
|
390
392
|
}
|
|
391
393
|
return value;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@daloyjs/core",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
4
4
|
"description": "DaloyJS is a runtime-portable, contract-first TypeScript web framework with built-in OpenAPI (Hey API), typed client generation, large-scale maintainability, and security-first defaults. Hono-grade portability, Elysia-grade DX, FastAPI-grade docs, Fastify-grade ops — distributed via pnpm.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|