@daloyjs/core 1.0.0-rc.1 → 1.0.0-rc.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 CHANGED
@@ -211,7 +211,7 @@ That single command runs the two scripts:
211
211
  ```jsonc
212
212
  // package.json
213
213
  "scripts": {
214
- "gen:openapi": "node --import tsx scripts/dump-openapi.ts",
214
+ "gen:openapi": "node scripts/dump-openapi.ts",
215
215
  "gen:client": "openapi-ts",
216
216
  "gen": "pnpm gen:openapi && pnpm gen:client"
217
217
  }
@@ -339,11 +339,11 @@ const app = createApp({ docs: true });
339
339
 
340
340
  | Runtime | Spawned command |
341
341
  | ------- | --------------------------------------------------------------- |
342
- | Node | `node --import tsx --watch <entry>` |
342
+ | Node | `node --watch <entry>` |
343
343
  | Bun | `bun --hot <entry>` |
344
344
  | Deno | `deno run --watch --allow-net --allow-env --allow-read <entry>` |
345
345
 
346
- Entry defaults to `src/index.ts`, `src/main.ts`, `src/server.ts`, or `src/app.ts`. Install `tsx` as a dev dependency on Node for TypeScript entries.
346
+ Entry defaults to `src/index.ts`, `src/main.ts`, `src/server.ts`, or `src/app.ts`. Node.js (>= 22.18) runs TypeScript entries natively via built-in type stripping — no loader needed. Projects that rely on non-erasable syntax (enums, runtime namespaces, parameter properties) or extensionless relative imports can keep using a loader directly, e.g. `node --import tsx --watch <entry>` (and `daloy inspect` falls back to `tsx` automatically when the native load fails and `tsx` is installed).
347
347
 
348
348
  Pass `--runtime <node|bun|deno>` to override runtime detection. This is required when running `daloy dev` from a `package.json` script on Bun or Deno, because the CLI binary's `#!/usr/bin/env node` shebang otherwise forces Node detection. The `bun-basic` template ships `"dev": "daloy dev --runtime bun"` for this reason.
349
349
 
@@ -509,7 +509,7 @@ The core only ever sees `Request → Response`. Adapters live at the edge.
509
509
 
510
510
  ## Status
511
511
 
512
- DaloyJS is at **`1.0.0-rc.1`**, a security-hardening release candidate. Because the framework has no external users yet, this RC ships a few intentional breaking changes (see the [CHANGELOG](CHANGELOG.md)) to get the secure-by-default posture right before GA rather than deferring them; the generated OpenAPI contract is unchanged. From `1.0.0` GA onward, breaking changes follow SemVer with deprecations getting at least one minor cycle. The framework is already in use for production trials.
512
+ DaloyJS is at **`1.0.0-rc.2`**, a security-hardening release candidate. Because the framework has no external users yet, this RC ships a few intentional breaking changes (see the [CHANGELOG](CHANGELOG.md)) to get the secure-by-default posture right before GA rather than deferring them; the generated OpenAPI contract is unchanged. From `1.0.0` GA onward, breaking changes follow SemVer with deprecations getting at least one minor cycle. The framework is already in use for production trials.
513
513
 
514
514
  **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.
515
515
 
@@ -527,7 +527,7 @@ DaloyJS is at **`1.0.0-rc.1`**, a security-hardening release candidate. Because
527
527
  ### Runtimes and deployment
528
528
 
529
529
  - 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.
530
- - `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.
530
+ - `daloy dev` watch loop delegates to the host runtime's native watcher (`node --watch`, `bun --hot`, or `deno run --watch`) with a `--runtime` override for cross-runtime `package.json` scripts.
531
531
  - `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.
532
532
  - Container-first templates: `HEALTHCHECK` to `/readyz`, `STOPSIGNAL SIGTERM`, non-root user, `tini` as PID 1.
533
533
  - 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.
package/bin/daloy.mjs CHANGED
@@ -2,9 +2,11 @@
2
2
  /**
3
3
  * `daloy` CLI shim. Real logic lives in `dist/cli.js` (`src/cli.ts`).
4
4
  *
5
- * For TypeScript entry files we try to register `tsx` if it's installed
6
- * in the consumer project; otherwise we surface a friendly error pointing
7
- * users at `node --import tsx`.
5
+ * TypeScript entry files are imported directly Node.js >= 22.18 strips
6
+ * erasable TypeScript syntax natively. If the native load fails (older
7
+ * Node, non-erasable syntax such as enums, or extensionless relative
8
+ * imports) we fall back to registering `tsx` when the consumer project has
9
+ * it installed; otherwise we surface a friendly error.
8
10
  */
9
11
 
10
12
  import { pathToFileURL, fileURLToPath } from "node:url";
@@ -20,17 +22,33 @@ const PKG = JSON.parse(
20
22
 
21
23
  const TS_EXT = /\.(ts|tsx|mts|cts)$/i;
22
24
 
25
+ /**
26
+ * Error codes that mean the host Node.js could not load a TypeScript file
27
+ * natively — the cases where falling back to a transpiling loader (tsx)
28
+ * can still succeed.
29
+ */
30
+ const NATIVE_TS_ERROR_CODES = new Set([
31
+ // Type stripping disabled (--no-strip-types) or Node too old.
32
+ "ERR_UNKNOWN_FILE_EXTENSION",
33
+ // Non-erasable syntax: enums, runtime namespaces, parameter properties.
34
+ "ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX",
35
+ // Extensionless relative imports that native stripping refuses to resolve.
36
+ "ERR_MODULE_NOT_FOUND",
37
+ ]);
38
+
23
39
  let tsxRegistered = false;
24
- async function ensureTsxIfNeeded(specifier) {
25
- if (!TS_EXT.test(specifier) || tsxRegistered) return;
40
+ async function registerTsxFallback(specifier, cause) {
26
41
  try {
27
42
  const api = await import("tsx/esm/api");
28
43
  api.register();
29
44
  tsxRegistered = true;
30
45
  } catch {
31
46
  throw new Error(
32
- `Loading TypeScript entry "${specifier}" requires tsx. Install it ` +
33
- `(\`pnpm add -D tsx\`) or run: node --import tsx ./node_modules/.bin/daloy inspect ${specifier}`
47
+ `Loading TypeScript entry "${specifier}" failed: ${cause?.message ?? cause}\n` +
48
+ "Node.js runs erasable-only TypeScript natively (>= 22.18). If the entry uses " +
49
+ "non-erasable syntax (enums, runtime namespaces, parameter properties) or " +
50
+ "extensionless relative imports, install tsx (`pnpm add -D tsx`) and re-run.",
51
+ { cause }
34
52
  );
35
53
  }
36
54
  }
@@ -40,8 +58,18 @@ async function importEntry(specifier) {
40
58
  if (!existsSync(abs)) {
41
59
  throw new Error(`Entry file not found: ${abs}`);
42
60
  }
43
- await ensureTsxIfNeeded(abs);
44
- return import(pathToFileURL(abs).href);
61
+ const href = pathToFileURL(abs).href;
62
+ if (!TS_EXT.test(abs) || tsxRegistered) return import(href);
63
+ try {
64
+ return await import(href);
65
+ } catch (err) {
66
+ if (!NATIVE_TS_ERROR_CODES.has(err?.code)) throw err;
67
+ await registerTsxFallback(abs, err);
68
+ // Cache-bust so the retried load resolves through tsx's hooks instead of
69
+ // the failed native module job. The first attempt failed before
70
+ // evaluation, so no side effects ran twice.
71
+ return import(`${href}?daloy-tsx-fallback=1`);
72
+ }
45
73
  }
46
74
 
47
75
  function spawnDev(command, args) {
@@ -62,7 +90,7 @@ function spawnDev(command, args) {
62
90
  new Error(
63
91
  `\`${command}\` was not found on PATH. ` +
64
92
  (command === "node"
65
- ? "Install `tsx` as a dev dependency (`pnpm add -D tsx`) and ensure Node.js is on PATH."
93
+ ? "Ensure Node.js is on PATH."
66
94
  : `Install ${command} or run daloy dev from the runtime that hosts it.`)
67
95
  )
68
96
  );
package/dist/cli.d.ts CHANGED
@@ -130,8 +130,11 @@ export declare function normalizeEntryArg(entry: string): string;
130
130
  * runtime and entry file. Pure function so tests can assert exact argv
131
131
  * without spawning a child process.
132
132
  *
133
- * - Node: `node --import tsx --watch <entry>` (tsx must be installed as a
134
- * dev dependency for TS files; .js entries also work).
133
+ * - Node: `node --watch <entry>` (Node >= 22.18 strips TypeScript types
134
+ * natively, so `.ts` entries with erasable-only syntax run without a
135
+ * loader; `.js` entries also work. Projects that need non-erasable
136
+ * syntax — enums, runtime namespaces, parameter properties — should
137
+ * transpile or add a loader such as tsx themselves).
135
138
  * - Bun: `bun --hot <entry>` (Bun ships with TS support).
136
139
  * - Deno: `deno run --watch --allow-net --allow-env --allow-read <entry>`
137
140
  * (the three permissions cover serving HTTP, reading env vars, and
package/dist/cli.js CHANGED
@@ -22,8 +22,9 @@ Usage:
22
22
  Commands:
23
23
  inspect [entry] Load an App and print its routes (default command).
24
24
  dev [entry] Start the entry file with the host runtime's
25
- native watch mode (tsx --watch on Node, --hot on
26
- Bun, --watch on Deno).
25
+ native watch mode (node --watch on Node, --hot on
26
+ Bun, --watch on Deno). Node runs TypeScript
27
+ entries via its built-in type stripping.
27
28
  doctor [entry] Audit a loaded App's secure-by-default posture.
28
29
  Exits non-zero on any violation so the
29
30
  command can guard container HEALTHCHECK and CI
@@ -186,8 +187,11 @@ export function normalizeEntryArg(entry) {
186
187
  * runtime and entry file. Pure function so tests can assert exact argv
187
188
  * without spawning a child process.
188
189
  *
189
- * - Node: `node --import tsx --watch <entry>` (tsx must be installed as a
190
- * dev dependency for TS files; .js entries also work).
190
+ * - Node: `node --watch <entry>` (Node >= 22.18 strips TypeScript types
191
+ * natively, so `.ts` entries with erasable-only syntax run without a
192
+ * loader; `.js` entries also work. Projects that need non-erasable
193
+ * syntax — enums, runtime namespaces, parameter properties — should
194
+ * transpile or add a loader such as tsx themselves).
191
195
  * - Bun: `bun --hot <entry>` (Bun ships with TS support).
192
196
  * - Deno: `deno run --watch --allow-net --allow-env --allow-read <entry>`
193
197
  * (the three permissions cover serving HTTP, reading env vars, and
@@ -219,7 +223,7 @@ export function buildDevCommand(runtime, entry) {
219
223
  };
220
224
  case "node":
221
225
  default:
222
- return { command: "node", args: ["--import", "tsx", "--watch", safe] };
226
+ return { command: "node", args: ["--watch", safe] };
223
227
  }
224
228
  }
225
229
  /**
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "bomFormat": "CycloneDX",
3
3
  "specVersion": "1.5",
4
- "serialNumber": "urn:uuid:63bae5ad-16c4-5db2-9929-3188903cb4f9",
4
+ "serialNumber": "urn:uuid:8448de36-3a72-553d-882f-b5b36bbd1426",
5
5
  "version": 1,
6
6
  "metadata": {
7
- "timestamp": "2026-07-04T14:31:15.314Z",
7
+ "timestamp": "2026-07-07T09:24:36.816Z",
8
8
  "tools": [
9
9
  {
10
10
  "vendor": "DaloyJS",
11
11
  "name": "daloy-generate-sbom",
12
- "version": "1.0.0-rc.1"
12
+ "version": "1.0.0-rc.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-rc.1",
22
+ "bom-ref": "pkg:npm/@daloyjs/core@1.0.0-rc.2",
23
23
  "name": "@daloyjs/core",
24
- "version": "1.0.0-rc.1",
24
+ "version": "1.0.0-rc.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-rc.1",
26
+ "purl": "pkg:npm/@daloyjs/core@1.0.0-rc.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-rc.1",
49
+ "tagId": "swidtag--daloyjs-core-1.0.0-rc.2",
50
50
  "name": "@daloyjs/core",
51
- "version": "1.0.0-rc.1",
51
+ "version": "1.0.0-rc.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-rc.1",
60
+ "ref": "pkg:npm/@daloyjs/core@1.0.0-rc.2",
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-1.0.0-rc.1",
6
- "documentNamespace": "https://github.com/daloyjs/daloy/sbom/@daloyjs/core-1.0.0-rc.1-63bae5ad-16c4-5db2-9929-3188903cb4f9",
5
+ "name": "@daloyjs/core-1.0.0-rc.2",
6
+ "documentNamespace": "https://github.com/daloyjs/daloy/sbom/@daloyjs/core-1.0.0-rc.2-8448de36-3a72-553d-882f-b5b36bbd1426",
7
7
  "creationInfo": {
8
- "created": "2026-07-04T14:31:15.314Z",
8
+ "created": "2026-07-07T09:24:36.816Z",
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-rc.1",
19
+ "versionInfo": "1.0.0-rc.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-rc.1"
30
+ "referenceLocator": "pkg:npm/@daloyjs/core@1.0.0-rc.2"
31
31
  }
32
32
  ]
33
33
  }
package/dist/types.d.ts CHANGED
@@ -199,7 +199,10 @@ export interface AuthSpec {
199
199
  *
200
200
  * @example
201
201
  * ```ts
202
- * // src/types.d.ts
202
+ * // Put this in a regular module the compiler always checks (e.g. the
203
+ * // plugin file that calls `app.decorate(...)`). Avoid a separate .d.ts:
204
+ * // `skipLibCheck` skips declaration files, so a broken import there
205
+ * // silently types the state value as `any`.
203
206
  * declare module "@daloyjs/core" {
204
207
  * interface AppState {
205
208
  * user: { id: string; roles: string[] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daloyjs/core",
3
- "version": "1.0.0-rc.1",
3
+ "version": "1.0.0-rc.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": {