@daloyjs/core 0.38.0 → 0.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,6 +15,7 @@
15
15
  [![Publish](https://github.com/daloyjs/daloy/actions/workflows/release.yml/badge.svg)](https://github.com/daloyjs/daloy/actions/workflows/release.yml)
16
16
  [![Zizmor](https://github.com/daloyjs/daloy/actions/workflows/zizmor.yml/badge.svg?branch=main)](https://github.com/daloyjs/daloy/actions/workflows/zizmor.yml)
17
17
  [![GitHub last commit](https://img.shields.io/github/last-commit/daloyjs/daloy)](https://github.com/daloyjs/daloy/commits/main)
18
+ [![npm version](https://img.shields.io/npm/v/@daloyjs/core)](https://www.npmjs.com/package/@daloyjs/core)
18
19
  [![JSR](https://jsr.io/badges/@daloyjs/daloy)](https://jsr.io/@daloyjs/daloy)
19
20
  [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/13058/badge)](https://www.bestpractices.dev/projects/13058)
20
21
  [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/daloyjs/daloy/badge)](https://securityscorecards.dev/viewer/?uri=github.com/daloyjs/daloy)
@@ -38,6 +39,7 @@ DaloyJS exists to be the framework you'd build if you took the best ideas from e
38
39
  | Mature **Swagger / docs / ops** in Node | [Fastify](https://fastify.dev/docs/latest/Reference/) | Encapsulated plugins, structured logger, graceful shutdown, request ids, and lifecycle hooks — all first-party. |
39
40
  | Modern **TS-first DX**, Bun acceptable | [Elysia](https://elysiajs.com/at-glance.html) | End-to-end typed handlers, typed context, and a typed in-process client — no codegen step required. |
40
41
  | Best-in-class **typed client codegen** for any consumer | [Hey API](https://heyapi.dev/openapi-ts/get-started) | One `pnpm gen` command emits a fully-typed fetch SDK from your live OpenAPI spec. |
42
+ | **Contract-first typed client, no codegen** | [ts-rest](https://ts-rest.com/) | Your route definition *is* the contract: an in-process typed client with zero codegen, plus OpenAPI 3.1 + a Hey API SDK for consumers that can't import your types. |
41
43
  | Opinionated **DI / module architecture** for large teams | [NestJS](https://docs.nestjs.com/) | Plugin encapsulation, `register()` prefixes, and `defineDependency()` typed-DI with per-request dedup — no decorators. |
42
44
  | Minimalist **async middleware cascade** | [Koa](https://koajs.com/) | Koa-style `Context` on a web-standard core, with validation, OpenAPI, errors, and security headers in-box. |
43
45
  | **Services + real-time** API framework | [FeathersJS](https://feathersjs.com/) | First-party `app.ws()` with CSWSH refuse-to-boot guards, plus SSE / NDJSON streaming over explicit OpenAPI routes. |
@@ -61,6 +63,7 @@ Each existing stack is excellent at one thing and forces tradeoffs everywhere el
61
63
  - Fastify has the best Node ops story but is Node-only and validation/types/docs are not unified.
62
64
  - FastAPI has the best docs ergonomics — but it's Python.
63
65
  - Hey API gives you the best typed client — but you still need a server that produces a clean spec.
66
+ - ts-rest gives lovely end-to-end types from a shared contract — but it rides on top of another server (Express/Fastify/Nest/Next), its safety is TypeScript-only, and OpenAPI and security are bring-your-own.
64
67
  - npm leaves supply-chain protection up to you.
65
68
 
66
69
  DaloyJS combines the wins:
@@ -339,6 +342,33 @@ deployment.
339
342
 
340
343
  ---
341
344
 
345
+ ## Authentication, OAuth2 & OpenID Connect
346
+
347
+ DaloyJS is a **resource server** (and a toolkit for building a relying party),
348
+ **not** an identity provider. Like Hono, Express, Fastify, or ASP.NET Core, it
349
+ *verifies* and *enforces* tokens on each request — it does **not** ship a login
350
+ UI, a user database, or an OAuth2 authorization server. It is **not** an
351
+ "IdentityServer": it cannot, on its own, do what Duende IdentityServer,
352
+ Keycloak, or Auth0 do (run login pages, manage clients/consent, mint tokens).
353
+
354
+ To add login you bring an **OpenID Connect provider**. It does not have to be
355
+ Auth0/Okta/Clerk specifically — any standards-compliant IdP works, including
356
+ managed (Auth0, Okta, Clerk, Microsoft Entra ID, AWS Cognito) and **self-hosted
357
+ open source** (Keycloak, Zitadel, Ory, Authentik, Logto, SuperTokens, Dex).
358
+ Don't build your own authorization server — verify tokens from a vetted one.
359
+
360
+ - **API as a resource server (default):** verify JWTs with `jwk()` against the
361
+ provider's JWKS (asymmetric-only algorithm allowlist, `issuer`/`audience`
362
+ enforced), then authorize per route with `requireScopes()`.
363
+ - **Browser app:** use the back-end-for-frontend (BFF) pattern — run the
364
+ authorization-code + PKCE flow server-side, keep tokens in a `session()`
365
+ cookie (never in JavaScript), and protect mutations with `csrf()`.
366
+
367
+ Read [Auth architecture: where DaloyJS fits in OAuth2 & OpenID Connect](https://daloyjs.dev/docs/auth/architecture)
368
+ for the full picture, plus the per-provider guides under [`/docs/auth`](https://daloyjs.dev/docs/auth).
369
+
370
+ ---
371
+
342
372
  ## Performance
343
373
 
344
374
  ```text
@@ -429,6 +459,7 @@ The core only ever sees `Request → Response`. Adapters live at the edge.
429
459
  - Hono — portable web-standard router: <https://hono.dev/docs/>
430
460
  - Elysia — TS-first DX & typed context: <https://elysiajs.com/at-glance.html>
431
461
  - Fastify — production Node web framework: <https://fastify.dev/docs/latest/Reference/>
462
+ - ts-rest — contract-first, RPC-like client/server over REST: <https://ts-rest.com/>
432
463
  - pnpm — strict, secure, content-addressable package manager: <https://pnpm.io/motivation>
433
464
  - Standard Schema — universal validator interface: <https://github.com/standard-schema/standard-schema>
434
465
  - RFC 9457 — Problem Details for HTTP APIs: <https://www.rfc-editor.org/rfc/rfc9457>
package/dist/app.js CHANGED
@@ -351,7 +351,8 @@ export class App {
351
351
  "If you really need this in production, also pass " +
352
352
  "acknowledgeInsecureDefaults: true to confirm. Prefer per-feature opt-outs " +
353
353
  "(secureHeaders: false, corsCrossOriginGuard: false, crashOnUnhandledRejection: false, " +
354
- "trustProxy: false, csrf: \"off\") instead.");
354
+ "trustProxy: false, csrf: \"off\") instead. " +
355
+ "See https://daloyjs.dev/docs/security/secure-defaults-enforcement.");
355
356
  }
356
357
  if (!insecureDefaultsLoggedThisProcess) {
357
358
  insecureDefaultsLoggedThisProcess = true;
@@ -666,8 +667,11 @@ export class App {
666
667
  return;
667
668
  const err = new Error(`session() is registered in the hook chain for a state-changing route ` +
668
669
  `(${stateChanging.method} ${stateChanging.path}) but no csrf() hook is installed. ` +
670
+ `Without CSRF protection a browser can be tricked into making authenticated ` +
671
+ `state-changing requests cross-site. ` +
669
672
  `Register csrf() via app.use(csrf({ strategy: "fetch-metadata", allowedOrigins: [...] })), ` +
670
- `or pass app({ csrf: "off" }) to acknowledge that this app is not browser-facing.`);
673
+ `or pass app({ csrf: "off" }) to acknowledge that this app is not browser-facing. ` +
674
+ `See https://daloyjs.dev/docs/security/boot-guards.`);
671
675
  this.bootGuard.error = err;
672
676
  throw err;
673
677
  }
@@ -717,9 +721,12 @@ export class App {
717
721
  this.log.warn({ event: "trust-proxy.unconfigured", header: found }, `Request carried ${found} but app({ trustProxy }) is unset; refusing to honour spoofable proxy headers.`);
718
722
  }
719
723
  throw new InternalError(`Refusing to dispatch request: ${found} header is present but app({ trustProxy }) is unconfigured. ` +
724
+ `Honouring a spoofable forwarded header would let a client forge its source IP for the rate ` +
725
+ `limiter, audit log, and request-id propagation. ` +
720
726
  `Pass app({ trustProxy: true }) when running behind a trusted reverse proxy, ` +
721
727
  `or app({ trustProxy: false }) to ignore forwarded headers, ` +
722
- `or app({ secureDefaults: false }) to disable this guard.`);
728
+ `or app({ secureDefaults: false }) to disable this guard. ` +
729
+ `See https://daloyjs.dev/docs/security/boot-guards.`);
723
730
  }
724
731
  /**
725
732
  * Resolve the {@link AppOptions.docs} option and, when enabled, register
package/dist/jwt.js CHANGED
@@ -236,7 +236,10 @@ export function createJwtSigner(opts) {
236
236
  }
237
237
  const { alg } = opts;
238
238
  if (alg === "none") {
239
- throw new JwtError("alg_none_refused", 'jwt(): alg "none" is refused.');
239
+ throw new JwtError("alg_none_refused", 'jwt(): alg "none" is refused — it disables signature verification, so anyone could forge a ' +
240
+ 'token by setting the header alg to "none" (the classic JWT signature-stripping / algorithm-' +
241
+ "confusion attack). Choose a real signing algorithm such as HS256 (shared secret) or " +
242
+ "RS256 / ES256 (key pair). See https://daloyjs.dev/docs/security/secure-defaults-enforcement.");
240
243
  }
241
244
  if (!ALL_ALGS.has(alg)) {
242
245
  throw new JwtError("invalid_alg", `jwt(): unknown algorithm "${String(alg)}". Allowed: ${[...ALL_ALGS].sort().join(", ")}.`);
@@ -335,7 +338,10 @@ export function createJwtVerifier(opts) {
335
338
  const allow = new Set();
336
339
  for (const alg of opts.algorithms) {
337
340
  if (alg === "none") {
338
- throw new JwtError("alg_none_refused", 'jwt(): alg "none" cannot appear in the allowlist.');
341
+ throw new JwtError("alg_none_refused", 'jwt(): alg "none" cannot appear in the algorithms allowlist — it disables signature ' +
342
+ "verification and would let any caller forge a token. Remove it and list only real " +
343
+ "algorithms such as HS256, RS256, or ES256. " +
344
+ "See https://daloyjs.dev/docs/security/secure-defaults-enforcement.");
339
345
  }
340
346
  if (!ALL_ALGS.has(alg)) {
341
347
  throw new JwtError("invalid_alg", `jwt(): unknown algorithm "${String(alg)}" in allowlist.`);
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "bomFormat": "CycloneDX",
3
3
  "specVersion": "1.5",
4
- "serialNumber": "urn:uuid:c230d67e-08ae-5162-959c-66cbbb24366a",
4
+ "serialNumber": "urn:uuid:51e4c48d-6a2e-5180-8452-1c9b9a5987d9",
5
5
  "version": 1,
6
6
  "metadata": {
7
- "timestamp": "2026-06-10T11:58:42.238Z",
7
+ "timestamp": "2026-06-11T09:54:26.041Z",
8
8
  "tools": [
9
9
  {
10
10
  "vendor": "DaloyJS",
11
11
  "name": "daloy-generate-sbom",
12
- "version": "0.38.0"
12
+ "version": "0.38.1"
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@0.38.0",
22
+ "bom-ref": "pkg:npm/@daloyjs/core@0.38.1",
23
23
  "name": "@daloyjs/core",
24
- "version": "0.38.0",
24
+ "version": "0.38.1",
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@0.38.0",
26
+ "purl": "pkg:npm/@daloyjs/core@0.38.1",
27
27
  "licenses": [
28
28
  {
29
29
  "license": {
@@ -46,9 +46,9 @@
46
46
  }
47
47
  ],
48
48
  "swid": {
49
- "tagId": "swidtag--daloyjs-core-0.38.0",
49
+ "tagId": "swidtag--daloyjs-core-0.38.1",
50
50
  "name": "@daloyjs/core",
51
- "version": "0.38.0",
51
+ "version": "0.38.1",
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@0.38.0",
60
+ "ref": "pkg:npm/@daloyjs/core@0.38.1",
61
61
  "dependsOn": []
62
62
  }
63
63
  ]
@@ -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-0.38.0",
6
- "documentNamespace": "https://github.com/daloyjs/daloy/sbom/@daloyjs/core-0.38.0-c230d67e-08ae-5162-959c-66cbbb24366a",
5
+ "name": "@daloyjs/core-0.38.1",
6
+ "documentNamespace": "https://github.com/daloyjs/daloy/sbom/@daloyjs/core-0.38.1-51e4c48d-6a2e-5180-8452-1c9b9a5987d9",
7
7
  "creationInfo": {
8
- "created": "2026-06-10T11:58:42.238Z",
8
+ "created": "2026-06-11T09:54:26.041Z",
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": "0.38.0",
19
+ "versionInfo": "0.38.1",
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@0.38.0"
30
+ "referenceLocator": "pkg:npm/@daloyjs/core@0.38.1"
31
31
  }
32
32
  ]
33
33
  }
package/dist/session.js CHANGED
@@ -57,7 +57,10 @@ function bytesToBase64Url(bytes) {
57
57
  }
58
58
  function makeSigner(secret) {
59
59
  if (typeof secret !== "string" || secret.length < 16) {
60
- throw new Error("session(): each secret must be a string of at least 16 characters.");
60
+ throw new Error("session(): each secret must be a string of at least 16 characters — it is the HMAC key " +
61
+ "that signs every session cookie, so a short or guessable value lets an attacker forge sessions. " +
62
+ "Generate one with `openssl rand -base64 32` and load it from an env var or secret manager " +
63
+ "(never hard-code or commit it). See https://daloyjs.dev/docs/security/session.");
61
64
  }
62
65
  let keyPromise = null;
63
66
  const getKey = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daloyjs/core",
3
- "version": "0.38.0",
3
+ "version": "0.38.1",
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": {