@daloyjs/core 1.0.0-beta.2 → 1.0.0-beta.4
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 +2 -2
- package/dist/adapters/node.js +18 -1
- package/dist/app.js +68 -1
- package/dist/docs.js +1 -0
- package/dist/pagination.d.ts +10 -9
- package/dist/pagination.js +8 -7
- package/dist/safe-redirect.d.ts +5 -2
- package/dist/safe-redirect.js +30 -2
- package/dist/sbom.cdx.json +9 -9
- package/dist/sbom.spdx.json +5 -5
- package/dist/streaming.d.ts +8 -2
- package/dist/types.d.ts +28 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,7 +55,7 @@ DaloyJS exists to be the framework you'd build if you took the best ideas from e
|
|
|
55
55
|
| **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. |
|
|
56
56
|
| 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. |
|
|
57
57
|
| 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. |
|
|
58
|
-
| **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. |
|
|
58
|
+
| **Services + real-time** API framework | [FeathersJS](https://feathersjs.com/) | First-party `app.ws()` with CSWSH refuse-to-boot guards, plus SSE / NDJSON streaming and raw `Response` passthrough (return a Vercel AI SDK stream straight from a handler) over explicit OpenAPI routes. |
|
|
59
59
|
| Battle-tested **Node middleware compatibility** | [Express v5](https://expressjs.com/en/blog/2024-10-15-v5-release) | Regex-free trie router, schema-validated routes, RFC 9457 problem+json, and refuse-to-boot guards on every runtime. |
|
|
60
60
|
| **Portable supply-chain hardening** for the apps you build | [pnpm](https://pnpm.io/motivation) defaults + a zero-runtime-dep core | Hardened `.npmrc`, source-verified lockfiles, zero runtime deps, CycloneDX + SPDX SBOM, and npm provenance attestations. |
|
|
61
61
|
|
|
@@ -507,7 +507,7 @@ The core only ever sees `Request → Response`. Adapters live at the edge.
|
|
|
507
507
|
|
|
508
508
|
## Status
|
|
509
509
|
|
|
510
|
-
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.4`). 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.
|
|
511
511
|
|
|
512
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.
|
|
513
513
|
|
package/dist/adapters/node.js
CHANGED
|
@@ -296,7 +296,7 @@ function toWebRequest(req, trustProxy, bufferedBody) {
|
|
|
296
296
|
: undefined;
|
|
297
297
|
const proto = forwardedProto ??
|
|
298
298
|
(req.socket.encrypted ? "https" : "http");
|
|
299
|
-
const url = `${proto}://${host}${req.url
|
|
299
|
+
const url = `${proto}://${host}${normalizeRequestTarget(req.url)}`;
|
|
300
300
|
// Build headers from `rawHeaders` (a flat [k0,v0,k1,v1,...] array) instead
|
|
301
301
|
// of the parsed `req.headers` object. This matches @hono/node-server's
|
|
302
302
|
// `newHeadersFromIncoming`: one `new Headers([[k,v],...])` constructor
|
|
@@ -348,6 +348,23 @@ function firstHeader(v) {
|
|
|
348
348
|
const comma = raw.indexOf(",");
|
|
349
349
|
return (comma === -1 ? raw : raw.slice(0, comma)).trim() || undefined;
|
|
350
350
|
}
|
|
351
|
+
function normalizeRequestTarget(target) {
|
|
352
|
+
const raw = target && target.length > 0 ? target : "/";
|
|
353
|
+
if (raw.charCodeAt(0) === 47 /* / */)
|
|
354
|
+
return raw;
|
|
355
|
+
if (raw.startsWith("http://") || raw.startsWith("https://")) {
|
|
356
|
+
try {
|
|
357
|
+
const url = new URL(raw);
|
|
358
|
+
return `${url.pathname}${url.search}`;
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
return "/";
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (raw.charCodeAt(0) === 63 /* ? */)
|
|
365
|
+
return `/${raw}`;
|
|
366
|
+
return `/${raw}`;
|
|
367
|
+
}
|
|
351
368
|
function sendWebResponse(res, out) {
|
|
352
369
|
out.statusCode = res.status;
|
|
353
370
|
res.headers.forEach((v, k) => out.setHeader(k, v));
|
package/dist/app.js
CHANGED
|
@@ -623,6 +623,42 @@ export class App {
|
|
|
623
623
|
* a misconfigured surface.
|
|
624
624
|
*/
|
|
625
625
|
assertSecureHookConfig(hooks) {
|
|
626
|
+
// Always-on correctness guard (independent of secureDefaults / environment).
|
|
627
|
+
// A hook bundle must be a single Hooks object. Passing an ARRAY — or any
|
|
628
|
+
// object carrying none of the recognized hook keys — is a silent no-op: the
|
|
629
|
+
// framework reads `.beforeHandle` / `.onSend` / ... off it, finds
|
|
630
|
+
// `undefined`, and applies NOTHING. A route that looks guarded
|
|
631
|
+
// (`hooks: [ipRestriction(...), bearerAuth(...)]`) would then ship wide open.
|
|
632
|
+
// TypeScript already rejects an array literal here; this catches JS callers,
|
|
633
|
+
// spreads, and `as`-casts, where the silent runtime skip is the dangerous part.
|
|
634
|
+
if (hooks !== null && typeof hooks === "object") {
|
|
635
|
+
const HOOK_KEYS = [
|
|
636
|
+
"onRequest",
|
|
637
|
+
"beforeHandle",
|
|
638
|
+
"afterHandle",
|
|
639
|
+
"onError",
|
|
640
|
+
"onSend",
|
|
641
|
+
"onResponse",
|
|
642
|
+
];
|
|
643
|
+
const carriesAHook = HOOK_KEYS.some((k) => typeof hooks[k] === "function");
|
|
644
|
+
if (!carriesAHook) {
|
|
645
|
+
if (Array.isArray(hooks)) {
|
|
646
|
+
throw new Error("Hooks must be a single Hooks object, not an array. To run multiple " +
|
|
647
|
+
"hook bundles (e.g. ipRestriction + bearerAuth) on one route, compose " +
|
|
648
|
+
"them with every(...) (all must pass) or some(...) (any may pass) from " +
|
|
649
|
+
"@daloyjs/core. Passing an array silently applies NO hooks, leaving the " +
|
|
650
|
+
"route unguarded.");
|
|
651
|
+
}
|
|
652
|
+
if (Object.keys(hooks).length > 0) {
|
|
653
|
+
throw new Error("Hooks object carries none of the recognized hook keys (onRequest, " +
|
|
654
|
+
"beforeHandle, afterHandle, onError, onSend, onResponse), so it would " +
|
|
655
|
+
"silently apply no hooks. To compose multiple hook bundles use " +
|
|
656
|
+
"every(...) / some(...) from @daloyjs/core.");
|
|
657
|
+
}
|
|
658
|
+
// An empty object `{}` carries no hook and makes no false promise of one;
|
|
659
|
+
// it is an explicit no-op, equivalent to omitting `hooks`, and is allowed.
|
|
660
|
+
}
|
|
661
|
+
}
|
|
626
662
|
if (this.options.secureDefaults === false)
|
|
627
663
|
return;
|
|
628
664
|
const record = hooks;
|
|
@@ -2260,6 +2296,37 @@ export class App {
|
|
|
2260
2296
|
if (afterReturn !== undefined)
|
|
2261
2297
|
result = afterReturn;
|
|
2262
2298
|
}
|
|
2299
|
+
// Escape hatch: a handler (or an `afterHandle` transform) may return a
|
|
2300
|
+
// raw web-standard `Response` — an AI SDK stream, a forwarded upstream
|
|
2301
|
+
// response, or any pre-built body that no response schema can describe.
|
|
2302
|
+
// It bypasses response-schema validation by design, but is finalized
|
|
2303
|
+
// through the exact same path as every other response (and as the
|
|
2304
|
+
// `beforeHandle` `Response` passthrough above), so no security control
|
|
2305
|
+
// is skipped: `ctx.set` headers (secureHeaders / CORS) are copied on, the
|
|
2306
|
+
// request id is added when absent, `onSend` / `onResponse` hooks run,
|
|
2307
|
+
// fingerprint headers are stripped, and `HEAD` yields an empty body.
|
|
2308
|
+
if (result instanceof Response) {
|
|
2309
|
+
copyContextHeaders(ctx, result);
|
|
2310
|
+
if (!result.headers.has("x-request-id")) {
|
|
2311
|
+
result.headers.set("x-request-id", requestId);
|
|
2312
|
+
}
|
|
2313
|
+
let finalizedRaw;
|
|
2314
|
+
if (hasFinalizeHook) {
|
|
2315
|
+
const fin = finalizeResponse(result, ctx, allHooks, stripFingerprint);
|
|
2316
|
+
finalizedRaw = isPromiseLike(fin) ? await fin : fin;
|
|
2317
|
+
}
|
|
2318
|
+
else {
|
|
2319
|
+
finalizedRaw = finalizeFast(result, stripFingerprint);
|
|
2320
|
+
}
|
|
2321
|
+
if (method === "HEAD") {
|
|
2322
|
+
return new Response(null, {
|
|
2323
|
+
status: finalizedRaw.status,
|
|
2324
|
+
statusText: finalizedRaw.statusText,
|
|
2325
|
+
headers: finalizedRaw.headers,
|
|
2326
|
+
});
|
|
2327
|
+
}
|
|
2328
|
+
return finalizedRaw;
|
|
2329
|
+
}
|
|
2263
2330
|
const serializeResultRes = serializeResult(result, def, this.options.validateResponses ?? true);
|
|
2264
2331
|
let response = isPromiseLike(serializeResultRes) ? await serializeResultRes : serializeResultRes;
|
|
2265
2332
|
copyContextHeaders(ctx, response);
|
|
@@ -3265,7 +3332,7 @@ function serializeResult(result, def, validateResponses) {
|
|
|
3265
3332
|
const treatAsJson = !explicitCt || explicitCt.includes("application/json");
|
|
3266
3333
|
if (!explicitCt)
|
|
3267
3334
|
headers.set("content-type", "application/json");
|
|
3268
|
-
//
|
|
3335
|
+
// Deprecation lifecycle headers. A route with an explicit RFC 8594
|
|
3269
3336
|
// `sunset` date is implicitly deprecated. Never overwrite a value the
|
|
3270
3337
|
// handler set deliberately.
|
|
3271
3338
|
if (def.deprecated === true || def.sunset !== undefined) {
|
package/dist/docs.js
CHANGED
|
@@ -218,6 +218,7 @@ export function htmlResponse(html, opts = {}) {
|
|
|
218
218
|
connectOrigins: opts.connectOrigins,
|
|
219
219
|
scriptNonce: opts.scriptNonce,
|
|
220
220
|
allowInlineStyles: opts.allowInlineStyles,
|
|
221
|
+
allowBlobWorkers: opts.allowBlobWorkers,
|
|
221
222
|
}),
|
|
222
223
|
"x-content-type-options": "nosniff",
|
|
223
224
|
"referrer-policy": "no-referrer",
|
package/dist/pagination.d.ts
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* - {@link buildLinkHeader} / {@link buildPageLinks} — assemble a Web-standard
|
|
16
16
|
* `Link` header, with CRLF / angle-bracket header-injection guards baked in.
|
|
17
17
|
* - {@link paginationQuery} — a Standard Schema validator for the `cursor` +
|
|
18
|
-
* `limit` query parameters that both validates
|
|
19
|
-
*
|
|
18
|
+
* `limit` query parameters that both validates runtime page-size bounds
|
|
19
|
+
* **and** advertises itself to the OpenAPI generator via a
|
|
20
20
|
* `toJSONSchema()` method, so `request: { query: paginationQuery() }` wires
|
|
21
21
|
* the parameters into the contract with no extra code.
|
|
22
22
|
*
|
|
@@ -157,12 +157,12 @@ export interface PaginationQueryOptions {
|
|
|
157
157
|
defaultLimit?: number;
|
|
158
158
|
/** Minimum accepted page size. Default: `1`. */
|
|
159
159
|
minLimit?: number;
|
|
160
|
-
/** Maximum accepted page size
|
|
160
|
+
/** Maximum accepted page size. Over-large requests are rejected. Default: `100`. */
|
|
161
161
|
maxLimit?: number;
|
|
162
162
|
}
|
|
163
163
|
/** Validated output of {@link paginationQuery}. */
|
|
164
164
|
export interface PaginationParams {
|
|
165
|
-
/** The resolved page size
|
|
165
|
+
/** The resolved page size after validation against `[minLimit, maxLimit]`. */
|
|
166
166
|
limit: number;
|
|
167
167
|
/** The opaque cursor, if the client supplied one. */
|
|
168
168
|
cursor?: string;
|
|
@@ -180,11 +180,12 @@ export interface PaginationQuerySchema extends StandardSchemaV1<Record<string, u
|
|
|
180
180
|
* Build a Standard Schema validator for cursor-pagination query parameters.
|
|
181
181
|
*
|
|
182
182
|
* Use it as a route's `request.query`. At runtime it parses and validates
|
|
183
|
-
* `limit` (coerced from its string query value to an integer
|
|
184
|
-
* `[minLimit, maxLimit]`, defaulting to `defaultLimit` when absent)
|
|
185
|
-
* `cursor` through as an optional opaque string. Because it also
|
|
186
|
-
* `toJSONSchema()`, the same call wires both parameters into the
|
|
187
|
-
* OpenAPI document and typed client — no duplicate parameter
|
|
183
|
+
* `limit` (coerced from its string query value to an integer, rejected when
|
|
184
|
+
* outside `[minLimit, maxLimit]`, and defaulting to `defaultLimit` when absent)
|
|
185
|
+
* and passes `cursor` through as an optional opaque string. Because it also
|
|
186
|
+
* exposes `toJSONSchema()`, the same call wires both parameters into the
|
|
187
|
+
* generated OpenAPI document and typed client — no duplicate parameter
|
|
188
|
+
* declarations.
|
|
188
189
|
*
|
|
189
190
|
* @example
|
|
190
191
|
* ```ts
|
package/dist/pagination.js
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* - {@link buildLinkHeader} / {@link buildPageLinks} — assemble a Web-standard
|
|
16
16
|
* `Link` header, with CRLF / angle-bracket header-injection guards baked in.
|
|
17
17
|
* - {@link paginationQuery} — a Standard Schema validator for the `cursor` +
|
|
18
|
-
* `limit` query parameters that both validates
|
|
19
|
-
*
|
|
18
|
+
* `limit` query parameters that both validates runtime page-size bounds
|
|
19
|
+
* **and** advertises itself to the OpenAPI generator via a
|
|
20
20
|
* `toJSONSchema()` method, so `request: { query: paginationQuery() }` wires
|
|
21
21
|
* the parameters into the contract with no extra code.
|
|
22
22
|
*
|
|
@@ -190,11 +190,12 @@ export function buildPageLinks(opts) {
|
|
|
190
190
|
* Build a Standard Schema validator for cursor-pagination query parameters.
|
|
191
191
|
*
|
|
192
192
|
* Use it as a route's `request.query`. At runtime it parses and validates
|
|
193
|
-
* `limit` (coerced from its string query value to an integer
|
|
194
|
-
* `[minLimit, maxLimit]`, defaulting to `defaultLimit` when absent)
|
|
195
|
-
* `cursor` through as an optional opaque string. Because it also
|
|
196
|
-
* `toJSONSchema()`, the same call wires both parameters into the
|
|
197
|
-
* OpenAPI document and typed client — no duplicate parameter
|
|
193
|
+
* `limit` (coerced from its string query value to an integer, rejected when
|
|
194
|
+
* outside `[minLimit, maxLimit]`, and defaulting to `defaultLimit` when absent)
|
|
195
|
+
* and passes `cursor` through as an optional opaque string. Because it also
|
|
196
|
+
* exposes `toJSONSchema()`, the same call wires both parameters into the
|
|
197
|
+
* generated OpenAPI document and typed client — no duplicate parameter
|
|
198
|
+
* declarations.
|
|
198
199
|
*
|
|
199
200
|
* @example
|
|
200
201
|
* ```ts
|
package/dist/safe-redirect.d.ts
CHANGED
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
* - Same-origin paths must start with `/` and must not start with `//`
|
|
15
15
|
* or `/\` (which browsers interpret as protocol-relative URLs that
|
|
16
16
|
* escape your origin).
|
|
17
|
-
* - Backslashes, control characters, and `CR`/`LF`
|
|
18
|
-
* stop response-splitting and homograph tricks.
|
|
17
|
+
* - Backslashes, encoded backslashes, control characters, and `CR`/`LF`
|
|
18
|
+
* are rejected to stop response-splitting and homograph tricks.
|
|
19
|
+
* Percent-encoded protocol-relative path prefixes such as `/%2f%2f`
|
|
20
|
+
* are also refused so downstream decoders cannot turn a same-origin
|
|
21
|
+
* `Location` into an origin-escaping redirect.
|
|
19
22
|
* - Absolute URLs are only allowed when their `origin` exactly matches
|
|
20
23
|
* one of the entries in `allowedOrigins`.
|
|
21
24
|
* - `javascript:`, `data:`, `vbscript:`, and `file:` schemes are always
|
package/dist/safe-redirect.js
CHANGED
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
* - Same-origin paths must start with `/` and must not start with `//`
|
|
15
15
|
* or `/\` (which browsers interpret as protocol-relative URLs that
|
|
16
16
|
* escape your origin).
|
|
17
|
-
* - Backslashes, control characters, and `CR`/`LF`
|
|
18
|
-
* stop response-splitting and homograph tricks.
|
|
17
|
+
* - Backslashes, encoded backslashes, control characters, and `CR`/`LF`
|
|
18
|
+
* are rejected to stop response-splitting and homograph tricks.
|
|
19
|
+
* Percent-encoded protocol-relative path prefixes such as `/%2f%2f`
|
|
20
|
+
* are also refused so downstream decoders cannot turn a same-origin
|
|
21
|
+
* `Location` into an origin-escaping redirect.
|
|
19
22
|
* - Absolute URLs are only allowed when their `origin` exactly matches
|
|
20
23
|
* one of the entries in `allowedOrigins`.
|
|
21
24
|
* - `javascript:`, `data:`, `vbscript:`, and `file:` schemes are always
|
|
@@ -79,6 +82,11 @@ function classify(target, allowedPaths, allowedOrigins) {
|
|
|
79
82
|
// `/\evil.com` is interpreted by some browsers as protocol-relative too.
|
|
80
83
|
if (target.startsWith("/\\"))
|
|
81
84
|
return { ok: false, reason: "backslash-path" };
|
|
85
|
+
if (hasEncodedBackslash(target))
|
|
86
|
+
return { ok: false, reason: "backslash-path" };
|
|
87
|
+
if (hasEncodedProtocolRelativePrefix(target)) {
|
|
88
|
+
return { ok: false, reason: "protocol-relative" };
|
|
89
|
+
}
|
|
82
90
|
if (target.startsWith("/")) {
|
|
83
91
|
// Same-origin path. Backslashes anywhere in the path can confuse
|
|
84
92
|
// user agents and proxies — refuse them outright.
|
|
@@ -113,6 +121,26 @@ function classify(target, allowedPaths, allowedOrigins) {
|
|
|
113
121
|
}
|
|
114
122
|
return { ok: true, location: parsed.toString() };
|
|
115
123
|
}
|
|
124
|
+
function hasEncodedBackslash(value) {
|
|
125
|
+
return /%5c/i.test(value);
|
|
126
|
+
}
|
|
127
|
+
function hasEncodedProtocolRelativePrefix(value) {
|
|
128
|
+
let raw = value;
|
|
129
|
+
for (let i = 0; i < 3; i++) {
|
|
130
|
+
if (/^\/%2f/i.test(raw))
|
|
131
|
+
return true;
|
|
132
|
+
try {
|
|
133
|
+
const decoded = decodeURIComponent(raw);
|
|
134
|
+
if (decoded === raw)
|
|
135
|
+
return false;
|
|
136
|
+
raw = decoded;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return raw.startsWith("//");
|
|
143
|
+
}
|
|
116
144
|
/**
|
|
117
145
|
* Build a redirect `Response` after validating the target against an
|
|
118
146
|
* explicit allowlist. Throws {@link OpenRedirectBlockedError} when the
|
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:609085f8-6098-51c0-9dce-7717eb9fb590",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
|
-
"timestamp": "2026-06-
|
|
7
|
+
"timestamp": "2026-06-26T13:41:51.513Z",
|
|
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.4"
|
|
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.4",
|
|
23
23
|
"name": "@daloyjs/core",
|
|
24
|
-
"version": "1.0.0-beta.
|
|
24
|
+
"version": "1.0.0-beta.4",
|
|
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.4",
|
|
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.4",
|
|
50
50
|
"name": "@daloyjs/core",
|
|
51
|
-
"version": "1.0.0-beta.
|
|
51
|
+
"version": "1.0.0-beta.4",
|
|
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.4",
|
|
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.4",
|
|
6
|
+
"documentNamespace": "https://github.com/daloyjs/daloy/sbom/@daloyjs/core-1.0.0-beta.4-609085f8-6098-51c0-9dce-7717eb9fb590",
|
|
7
7
|
"creationInfo": {
|
|
8
|
-
"created": "2026-06-
|
|
8
|
+
"created": "2026-06-26T13:41:51.513Z",
|
|
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.4",
|
|
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.4"
|
|
31
31
|
}
|
|
32
32
|
]
|
|
33
33
|
}
|
package/dist/streaming.d.ts
CHANGED
|
@@ -28,9 +28,15 @@
|
|
|
28
28
|
*
|
|
29
29
|
* For NDJSON, each yielded value is JSON-encoded and terminated with `\n`.
|
|
30
30
|
*/
|
|
31
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* A single SSE event or control frame.
|
|
33
|
+
*
|
|
34
|
+
* `data` may be a string or any JSON-serializable value. It is optional so
|
|
35
|
+
* callers can emit valid comment-only or retry-only SSE frames for keep-alive
|
|
36
|
+
* and reconnection control without sending an event payload.
|
|
37
|
+
*/
|
|
32
38
|
export interface SSEMessage {
|
|
33
|
-
data
|
|
39
|
+
data?: unknown;
|
|
34
40
|
event?: string;
|
|
35
41
|
id?: string;
|
|
36
42
|
/** Reconnection delay in milliseconds. */
|
package/dist/types.d.ts
CHANGED
|
@@ -327,8 +327,8 @@ export interface RouteDefinition<P extends PathString = PathString, M extends Ht
|
|
|
327
327
|
*
|
|
328
328
|
* - implicitly treats the route as {@link RouteDefinition.deprecated}
|
|
329
329
|
* (the OpenAPI operation is emitted with `deprecated: true`);
|
|
330
|
-
* - emits a `Deprecation: true` response header
|
|
331
|
-
*
|
|
330
|
+
* - emits a `Deprecation: true` response header on every response from the
|
|
331
|
+
* route; and
|
|
332
332
|
* - emits a `Sunset: <IMF-fixdate>` response header normalized to an HTTP
|
|
333
333
|
* date so clients and gateways can schedule migration.
|
|
334
334
|
*
|
|
@@ -422,7 +422,32 @@ export interface RouteDefinition<P extends PathString = PathString, M extends Ht
|
|
|
422
422
|
*/
|
|
423
423
|
meta?: RouteMeta;
|
|
424
424
|
hooks?: Hooks;
|
|
425
|
-
|
|
425
|
+
/**
|
|
426
|
+
* The route handler. Receives the typed, validated {@link BaseContext} and
|
|
427
|
+
* returns either:
|
|
428
|
+
*
|
|
429
|
+
* - a structured result `{ status, body, headers? }` whose `body` is
|
|
430
|
+
* validated against the route's response schema and typed end-to-end into
|
|
431
|
+
* the OpenAPI document and generated client (the common case), or
|
|
432
|
+
* - a raw web-standard {@link Response} as an escape hatch for streaming,
|
|
433
|
+
* proxying, or pre-built bodies (for example an AI SDK
|
|
434
|
+
* `result.toUIMessageStreamResponse()`, or an upstream `fetch()` response
|
|
435
|
+
* forwarded verbatim).
|
|
436
|
+
*
|
|
437
|
+
* A returned `Response` **bypasses response-schema validation and the
|
|
438
|
+
* typed-client body type by design** — there is no schema that can describe
|
|
439
|
+
* an opaque stream. It is still finalized exactly like every other response,
|
|
440
|
+
* so no security control is skipped: headers set via `ctx.set` (including
|
|
441
|
+
* `secureHeaders()` and CORS) are copied onto it, `x-request-id` is added
|
|
442
|
+
* when absent, any `onSend` / `onResponse` hooks run, server-fingerprint
|
|
443
|
+
* headers (`server`, `x-powered-by`) are stripped, and a `HEAD` request still
|
|
444
|
+
* yields an empty body. This mirrors the existing `beforeHandle` `Response`
|
|
445
|
+
* passthrough. Prefer the structured result whenever a schema can describe
|
|
446
|
+
* the payload; reach for `Response` only when it genuinely cannot.
|
|
447
|
+
*
|
|
448
|
+
* @since 0.1.0
|
|
449
|
+
*/
|
|
450
|
+
handler: (ctx: BaseContext<P, Req>) => HandlerReturn<Res> | Response | Promise<HandlerReturn<Res> | Response>;
|
|
426
451
|
}
|
|
427
452
|
/**
|
|
428
453
|
* One operation inside an OpenAPI Callback Object. Mirrors a route minus
|
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.4",
|
|
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": {
|