From 8114d4a68f2a4a0f425549e0f05286a90d2237d9 Mon Sep 17 00:00:00 2001 From: gimenes Date: Sat, 3 Oct 2026 18:54:58 -0300 Subject: [PATCH 1/3] feat(build): publish per-file tsc output (TypeScript 7), no bundler The 8 packages published raw .ts, which plain Node (scripts, Playwright, Node servers, Next without transpilePackages) can't import from node_modules. Each package now compiles file-for-file with the TypeScript 7 native compiler: every src/**/*.ts(x) becomes one dist/**/*.js plus .d.ts and maps, imports left as imports, so module identity and singletons are exactly the source's (no bundle, no inlined second copy). - tsconfig.build.json per package (rootDir src, outDir dist, NodeNext, rewriteRelativeImportExtensions, declaration + maps, tests excluded); relative imports in emitted files now carry .ts extensions. - exports: { types, source, default } per subpath (node/default order kept for /protocol/storage/fs); files ship dist + src; main/types point at dist. - deco bin runs dist/v8/cli/main.js; tsx is no longer a runtime dependency. typescript stays the 5.x peer that `deco schema` loads (TS 7 has no JS API); builds use the `typescript7` alias through scripts/tsc.mjs. - `deco schema` names a compiled .d.ts after its source (declaration map), so schema definition ids are the same from dist or source. - Workspace: root prepare builds on install; type-checks and vitest resolve @decocms/* through the "source" condition; tests/globalSetup.ts rebuilds blocks' dist for the CLI tests that spawn the bin. - Release prepareCmd builds after the version sync; each package's prepack rebuilds. New CI workflow: typecheck, build, plain-Node import of every built export. - nextjs-smoke drops transpilePackages. CLAUDE.md documents the build rule. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig --- .../scripts/steps.test.ts | 2 +- .github/workflows/ci.yml | 52 +++++++++++ .releaserc.json | 2 +- CLAUDE.md | 27 ++++-- bun.lock | 89 +++++++++++-------- examples/nextjs-smoke/next.config.ts | 5 +- .../nextjs-smoke/scripts/build-installed.sh | 4 +- knip.json | 3 + package.json | 9 +- packages/apps-algolia/package.json | 18 ++-- packages/apps-algolia/tsconfig.build.json | 16 ++++ packages/apps-algolia/tsconfig.json | 3 - packages/apps-magento/package.json | 18 ++-- packages/apps-magento/src/index.ts | 2 +- packages/apps-magento/tsconfig.build.json | 16 ++++ packages/apps-magento/tsconfig.json | 3 - packages/apps-resend/package.json | 18 ++-- packages/apps-resend/src/emails.ts | 2 +- packages/apps-resend/src/index.ts | 4 +- packages/apps-resend/tsconfig.build.json | 16 ++++ packages/apps-resend/tsconfig.json | 3 - .../apps-sfmc-personalization/package.json | 18 ++-- .../apps-sfmc-personalization/src/index.ts | 4 +- .../tsconfig.build.json | 16 ++++ .../apps-sfmc-personalization/tsconfig.json | 3 - packages/apps-shopify/package.json | 18 ++-- packages/apps-shopify/src/client.ts | 2 +- packages/apps-shopify/src/index.ts | 2 +- packages/apps-shopify/tsconfig.build.json | 16 ++++ packages/apps-shopify/tsconfig.json | 3 - packages/apps-vtex/package.json | 18 ++-- packages/apps-vtex/src/index.ts | 2 +- packages/apps-vtex/src/vtexClient.ts | 8 +- packages/apps-vtex/tsconfig.build.json | 16 ++++ packages/apps-vtex/tsconfig.json | 3 - packages/apps-wake/package.json | 30 +++++-- packages/apps-wake/src/index.ts | 4 +- packages/apps-wake/src/storefront.ts | 2 +- packages/apps-wake/src/storefrontTypes.ts | 2 +- .../apps-wake/src/utils/graphql/queries.ts | 2 +- packages/apps-wake/src/wakeClient.ts | 6 +- packages/apps-wake/tsconfig.build.json | 16 ++++ packages/apps-wake/tsconfig.json | 3 - packages/blocks/bin/deco.js | 17 ++-- packages/blocks/package.json | 79 ++++++++++++---- packages/blocks/src/index.ts | 2 +- packages/blocks/src/protocol/canonical.ts | 2 +- packages/blocks/src/protocol/ciphertext.ts | 2 +- packages/blocks/src/protocol/client.ts | 4 +- .../src/protocol/conformance/cases/assets.ts | 6 +- .../src/protocol/conformance/cases/guards.ts | 8 +- .../src/protocol/conformance/cases/reads.ts | 8 +- .../src/protocol/conformance/cases/types.ts | 2 +- .../src/protocol/conformance/cases/wire.ts | 8 +- .../src/protocol/conformance/cases/writes.ts | 8 +- .../src/protocol/conformance/context.ts | 8 +- .../blocks/src/protocol/conformance/index.ts | 20 ++--- packages/blocks/src/protocol/index.ts | 12 +-- packages/blocks/src/protocol/params.ts | 4 +- packages/blocks/src/protocol/secrets.ts | 6 +- packages/blocks/src/protocol/server/assets.ts | 12 +-- packages/blocks/src/protocol/server/auth.ts | 2 +- .../blocks/src/protocol/server/content.ts | 10 +-- packages/blocks/src/protocol/server/core.ts | 18 ++-- .../blocks/src/protocol/server/handler.ts | 12 +-- packages/blocks/src/protocol/server/http.ts | 2 +- packages/blocks/src/protocol/server/index.ts | 6 +- .../src/protocol/server/methods/apply.ts | 18 ++-- .../src/protocol/server/methods/read.ts | 10 +-- packages/blocks/src/protocol/server/rpc.ts | 12 +-- packages/blocks/src/protocol/storage.ts | 2 +- .../blocks/src/protocol/storage/fs/index.ts | 14 +-- .../blocks/src/protocol/storage/fs/lock.ts | 2 +- .../src/protocol/storage/fs/unsupported.ts | 4 +- .../blocks/src/protocol/storage/memory.ts | 8 +- .../blocks/src/v8/__conformance__/cli.test.ts | 18 ++-- .../src/v8/__conformance__/delivery.test.ts | 2 +- .../blocks/src/v8/__conformance__/sdk.test.ts | 12 ++- packages/blocks/src/v8/analytics.ts | 4 +- packages/blocks/src/v8/builtins/data.ts | 2 +- packages/blocks/src/v8/builtins/index.ts | 12 +-- packages/blocks/src/v8/builtins/lazy.ts | 2 +- packages/blocks/src/v8/builtins/legacy.ts | 2 +- .../blocks/src/v8/builtins/multivariate.ts | 2 +- packages/blocks/src/v8/builtins/secret.ts | 4 +- packages/blocks/src/v8/cli/builtins.ts | 4 +- packages/blocks/src/v8/cli/check/index.ts | 22 ++--- packages/blocks/src/v8/cli/content.ts | 12 +-- packages/blocks/src/v8/cli/index.ts | 14 +-- packages/blocks/src/v8/cli/main.ts | 2 +- packages/blocks/src/v8/cli/run.test.ts | 10 ++- packages/blocks/src/v8/cli/run.ts | 14 +-- .../src/v8/cli/schema/builtinSchemas.ts | 2 +- packages/blocks/src/v8/cli/schema/generate.ts | 12 +-- packages/blocks/src/v8/cli/schema/index.ts | 8 +- .../blocks/src/v8/cli/schema/schema.test.ts | 30 ++++++- .../blocks/src/v8/cli/schema/tsProgram.ts | 2 +- .../blocks/src/v8/cli/schema/typeToSchema.ts | 26 +++++- packages/blocks/src/v8/cli/serve/server.ts | 18 ++-- packages/blocks/src/v8/client.ts | 10 +-- packages/blocks/src/v8/cms.ts | 18 ++-- packages/blocks/src/v8/content.ts | 8 +- packages/blocks/src/v8/draft.ts | 2 +- packages/blocks/src/v8/errors.ts | 2 +- packages/blocks/src/v8/fetch.ts | 2 +- packages/blocks/src/v8/identity.ts | 2 +- packages/blocks/src/v8/index.ts | 10 +-- packages/blocks/src/v8/matchRoute.ts | 2 +- packages/blocks/src/v8/remoteLoader.ts | 12 +-- packages/blocks/src/v8/resolver.ts | 12 +-- packages/blocks/src/v8/secrets.ts | 2 +- packages/blocks/src/v8/telemetry.ts | 10 +-- packages/blocks/tsconfig.build.json | 16 ++++ packages/blocks/tsconfig.json | 5 +- scripts/tsc.mjs | 28 ++++++ tests/globalSetup.ts | 18 ++++ tsconfig.base.json | 10 ++- tsconfig.build.base.json | 13 +++ vitest.config.ts | 10 +++ 119 files changed, 836 insertions(+), 426 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 packages/apps-algolia/tsconfig.build.json create mode 100644 packages/apps-magento/tsconfig.build.json create mode 100644 packages/apps-resend/tsconfig.build.json create mode 100644 packages/apps-sfmc-personalization/tsconfig.build.json create mode 100644 packages/apps-shopify/tsconfig.build.json create mode 100644 packages/apps-vtex/tsconfig.build.json create mode 100644 packages/apps-wake/tsconfig.build.json create mode 100644 packages/blocks/tsconfig.build.json create mode 100644 scripts/tsc.mjs create mode 100644 tests/globalSetup.ts create mode 100644 tsconfig.build.base.json diff --git a/.agents/skills/deco-v7-to-v8-migration/scripts/steps.test.ts b/.agents/skills/deco-v7-to-v8-migration/scripts/steps.test.ts index 2bf0eebb..88c541a4 100644 --- a/.agents/skills/deco-v7-to-v8-migration/scripts/steps.test.ts +++ b/.agents/skills/deco-v7-to-v8-migration/scripts/steps.test.ts @@ -256,7 +256,7 @@ describe("the codemod's list of the root's next-major exports", () => { path.resolve(__dirname, "../../../../packages/blocks/src/index.ts"), "utf8", ); - const block = /export \{([^}]*)\} from "\.\/v8\/index";/.exec(index)?.[1] ?? ""; + const block = /export \{([^}]*)\} from "\.\/v8\/index\.ts";/.exec(index)?.[1] ?? ""; const names = block .split(",") .map((n) => n.trim().replace(/^type\s+/, "")) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..4ffd7352 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +name: CI + +# Type-checks and builds the 8 publishable packages on every PR. The build is +# what npm publishes: `tsc` emits one .js (+ .d.ts and maps) per source file +# into each package's dist/, with no bundler, so the module graph — and every +# module-level singleton — is the same as the source's. The last step imports +# each built entry point with plain Node, which can't load .ts from +# node_modules: if a relative import lost its extension, it fails here. + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 24 + + - uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.5 + + # The root `prepare` script builds the workspace on install. + - run: bun install --frozen-lockfile + + - run: bun run typecheck + + - run: bun run build + + - name: Plain Node imports every built export + run: | + for dir in packages/*; do + (cd "$dir" && node --input-type=module -e ' + import fs from "node:fs"; + const pkg = JSON.parse(fs.readFileSync("package.json", "utf8")); + const leaves = (v) => typeof v === "string" ? [] : "default" in v && typeof v.default === "string" ? [v.default] : Object.values(v).flatMap(leaves); + for (const target of Object.values(pkg.exports).flatMap(leaves)) { + await import(new URL(target, `file://${process.cwd()}/`).href); + console.log(`${pkg.name}: ${target}`); + } + ') + done + node packages/blocks/bin/deco.js --help > /dev/null diff --git a/.releaserc.json b/.releaserc.json index 3db1f963..84cb173a 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -60,7 +60,7 @@ [ "@semantic-release/exec", { - "prepareCmd": "VERSION=${nextRelease.version} node scripts/sync-versions.mjs", + "prepareCmd": "VERSION=${nextRelease.version} node scripts/sync-versions.mjs && bun run build", "publishCmd": "PACKAGES=\"blocks apps-algolia apps-magento apps-resend apps-sfmc-personalization apps-shopify apps-vtex apps-wake\"; if [ \"$DRY_RUN\" = \"true\" ]; then echo \"[dry-run] would publish version ${nextRelease.version} for: $PACKAGES\"; else failed=0; for name in $PACKAGES; do (cd \"packages/$name\" && npm publish --access public --tag ${nextRelease.channel ? nextRelease.channel : 'latest'}) || { echo \"::error::npm publish failed for packages/$name\"; failed=1; }; done; exit \"$failed\"; fi" } ], diff --git a/CLAUDE.md b/CLAUDE.md index 7d8f6994..3bcf046c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,7 +8,7 @@ This is **blocks** (repo `decocms/blocks`): a Bun workspace monorepo for the fra **v7 lives on the `7.x` branch.** `@decocms/tanstack`, `@decocms/nextjs`, `@decocms/blocks-admin`, `@decocms/blocks-cli`, `@decocms/apps-commerce`, `@decocms/apps-blog`, `@decocms/apps-website` and v7's `@decocms/blocks` modules (`/cms`, `/sdk/*`, `/hooks`, `/setup`, …) are maintained and released there, not here. Don't reintroduce them on this line. -History worth knowing: the framework used to be a single tsup-bundled package, `@decocms/start`, reverted at v5.2.2 because bundling created two module instances of what must be one singleton (the CMS registry). Packages here import each other's plain `.ts` source; no bundler is in the loop. +History worth knowing: the framework used to be a single tsup-bundled package, `@decocms/start`, reverted at v5.2.2 because bundling created two module instances of what must be one singleton (the CMS registry). Here no bundler is in the loop: each package is compiled file-for-file by `tsc` (see "How packages build" below), so module boundaries, and the singletons that live in them, are exactly the source's. ## Tech Stack @@ -20,10 +20,11 @@ History worth knowing: the framework used to be a single tsup-bundled package, ` ## Common Commands ```bash -bun install +bun install # also builds every package's dist/ (root `prepare` script) +bun run build # tsc (TypeScript 7) -> dist/, per package, blocks first bun run test # vitest, whole repo: packages, tests/, the migration skill's scripts bun run typecheck # tsc --noEmit per package, plus the skill scripts and tests/ -bun run examples # build the three examples, then typecheck them +bun run examples # build the packages and the three examples, then typecheck them bun run check # typecheck + lint + lint:unused ``` @@ -55,24 +56,36 @@ v7-only design docs, plans and Cursor skills live on the `7.x` branch. The docs Nothing else is published from this line: the release allowlist in `.releaserc.json` is `blocks` plus the seven `apps-*`. +### How packages build (per-file `tsc`, no bundler) + +Every package publishes compiled JavaScript so plain Node (scripts, Playwright, Node servers, Next without `transpilePackages`) can import it; npm never ships only `.ts`. The build is `tsc -p tsconfig.build.json` (via `scripts/tsc.mjs`, which runs the TypeScript 7 native compiler from the root `typescript7` alias): `rootDir: src`, `outDir: dist`, `module`/`moduleResolution: NodeNext`, `declaration` + declaration and source maps, tests and fixtures excluded. Each `src/**/*.ts(x)` becomes exactly one `dist/**/*.js` (+ `.d.ts`), with its imports left as imports. + +- **Why no bundler**: a bundle inlines modules, so a package that bundles another (or a bundle loaded next to the unbundled copy) carries a second instance of module state — the `@decocms/start` registry bug. With per-file output there is one `dist/x.js` per `src/x.ts` and every importer gets that one module, as with the source; cross-package imports stay package imports (`@decocms/blocks`), never inlined. Don't add tsup/esbuild/rollup to a package build. +- **Relative imports carry the `.ts` extension** (`from "./run.ts"`, `from "./server/index.ts"`, never extensionless or a bare directory) and `rewriteRelativeImportExtensions` turns them into `.js` in the output; the build's `NodeNext` resolution rejects a specifier Node couldn't resolve. Test files may stay extensionless (they're never emitted). +- **Exports maps**: every subpath is `{ "types": "./dist/….d.ts", "source": "./src/….ts", "default": "./dist/….js" }`; conditional subpaths nest that object under each branch (`/protocol/storage/fs`: `node` before `default`). `files` ships `dist` and `src` (minus tests) so the `source` condition and the declaration maps resolve. Add a subpath to both `src` and the map in that shape (`sdk.test.ts`/`run.test.ts` check it). +- **The `source` condition** lets in-repo tools use `.ts` without a build: `tsconfig.base.json` (`customConditions`) for type-checks and `vitest.config.ts` (`resolve.conditions`) for tests, so a test importing a file by path and one importing `@decocms/blocks` share one module. A consumer that opts into `source` must do so for every environment it builds; mixing `source` and dist in one process loads both copies. +- **The bin runs dist**: `bin/deco.js` imports `dist/v8/cli/main.js` (no tsx). `tests/globalSetup.ts` rebuilds blocks' dist before the suite because the CLI conformance tests spawn the bin. +- **Two TypeScripts**: builds and type-checks use TypeScript 7 (`typescript7`, npm alias of `typescript@7`); the plain `typescript` name stays on 5.x because TypeScript 7 has no JavaScript compiler API, and `deco schema` loads the app's `typescript` peer through that API (as do Next's type-check and a few conformance tests). +- **Release**: `.releaserc.json`'s `prepareCmd` runs `bun run build` after the version sync, and each package's `prepack` rebuilds, so `npm publish` never ships a stale or missing dist. CI (`.github/workflows/ci.yml`) type-checks, builds and imports every built export with plain Node. + ### `@decocms/blocks` exports -Every export maps to a source file; there is no dist indirection. +Each export is built from the source file below (`dist/.js`, see above). | Import path | File | |---|---| -| `@decocms/blocks` | `src/index.ts` — the v8 runtime API only (`createCMS`, `matchRoute`, `remoteLoader`, `draftPointer`, `Blocks`, `Lazy`, …), re-exported from `src/v8/index.ts` as one explicit `export { … } from "./v8/index"` block (a conformance test parses that form) | +| `@decocms/blocks` | `src/index.ts` — the v8 runtime API only (`createCMS`, `matchRoute`, `remoteLoader`, `draftPointer`, `Blocks`, `Lazy`, …), re-exported from `src/v8/index.ts` as one explicit `export { … } from "./v8/index.ts"` block (a conformance test parses that form) | | `@decocms/blocks/analytics` | `src/v8/analytics.ts` — `AnalyticsScript`, `track` | | `@decocms/blocks/fetch` | `src/v8/fetch.ts` — `createInstrumentedFetch` | | `@decocms/blocks/secrets` | `src/v8/secrets.ts` | -| `@decocms/blocks/cli` | `src/v8/cli/index.ts` — the `deco` CLI (`schema`, `content`, `check`, `serve`), also the bin (`bin/deco.js`, which loads the TS sources via tsx under Node, directly under Bun). CLI-only: the runtime never imports it (`run.test.ts`), so it and the TypeScript compiler never reach an app bundle | +| `@decocms/blocks/cli` | `src/v8/cli/index.ts` — the `deco` CLI (`schema`, `content`, `check`, `serve`), also the bin (`bin/deco.js`, which runs the compiled `dist/v8/cli/main.js` under Node or Bun). CLI-only: the runtime never imports it (`run.test.ts`), so it and the TypeScript compiler never reach an app bundle | | `@decocms/blocks/protocol` (+ `/keys`, `/server`, `/storage/fs`, `/conformance`) | `src/protocol/**` — the content protocol the site editor uses; browser-safe except `storage/fs` (conditional export: `node` → real, `default` → a stub that throws) | ### Key boundaries - **The runtime never imports the protocol or the CLI.** `src/v8` modules import only each other (no Node built-ins, no React at runtime except `/analytics`); `src/v8/browserBundle.test.ts` proves it with a real esbuild bundle. The CLI may import the protocol. - **Clients depend only on `@decocms/blocks`**, with no peers and no framework binding. A client takes settings as arguments (no env reads), never caches, has no hooks, converters or `"use client"` code: those belong in the site's platform template (`tests/upstream-clients.conformance.test.ts`). -- **Cross-package imports resolve to `.ts` source** (`moduleResolution: bundler`). No `tsconfig.json` `references` anywhere: adding them back reintroduces a TS6305 build-ordering bug. +- **Cross-package imports are package imports**: type-checks resolve them to `.ts` source through the `source` condition; the build resolves them to the dependency's built `dist/*.d.ts`, which is why `bun run build` builds blocks before the clients. No `tsconfig.json` `references` anywhere: adding them back reintroduces a TS6305 build-ordering bug. - **No compat layers.** If a site needs something a package should export, add the export; don't let sites (or this repo) re-create v7 APIs as shims. ## v8 core — `packages/blocks/src/v8/` diff --git a/bun.lock b/bun.lock index 85c251e3..399907ba 100644 --- a/bun.lock +++ b/bun.lock @@ -7,10 +7,14 @@ "devDependencies": { "@biomejs/biome": "^2.5.3", "@semantic-release/exec": "^7.1.0", + "@types/node": "^22.0.0", "jsdom": "^29.1.1", "knip": "^5.86.0", "semantic-release": "^25.0.5", + "tsx": "^4.22.5", "typescript": "^5.9.3", + "typescript7": "npm:typescript@7.0.2", + "vite": "^8.0.1", "vitest": "^4.1.10", }, }, @@ -78,9 +82,6 @@ "dependencies": { "@decocms/blocks": "workspace:*", }, - "devDependencies": { - "typescript": "^5.9.0", - }, }, "packages/apps-magento": { "name": "@decocms/apps-magento", @@ -88,9 +89,6 @@ "dependencies": { "@decocms/blocks": "workspace:*", }, - "devDependencies": { - "typescript": "^5.9.0", - }, }, "packages/apps-resend": { "name": "@decocms/apps-resend", @@ -98,9 +96,6 @@ "dependencies": { "@decocms/blocks": "workspace:*", }, - "devDependencies": { - "typescript": "^5.9.0", - }, }, "packages/apps-sfmc-personalization": { "name": "@decocms/apps-sfmc-personalization", @@ -108,9 +103,6 @@ "dependencies": { "@decocms/blocks": "workspace:*", }, - "devDependencies": { - "typescript": "^5.9.0", - }, }, "packages/apps-shopify": { "name": "@decocms/apps-shopify", @@ -118,9 +110,6 @@ "dependencies": { "@decocms/blocks": "workspace:*", }, - "devDependencies": { - "typescript": "^5.9.0", - }, }, "packages/apps-vtex": { "name": "@decocms/apps-vtex", @@ -128,9 +117,6 @@ "dependencies": { "@decocms/blocks": "workspace:*", }, - "devDependencies": { - "typescript": "^5.9.0", - }, }, "packages/apps-wake": { "name": "@decocms/apps-wake", @@ -138,9 +124,6 @@ "dependencies": { "@decocms/blocks": "workspace:*", }, - "devDependencies": { - "typescript": "^5.9.0", - }, }, "packages/blocks": { "name": "@decocms/blocks", @@ -150,7 +133,6 @@ }, "dependencies": { "ajv": "^8.20.0", - "tsx": "^4.22.5", "zod": "^4.4.3", }, "devDependencies": { @@ -158,7 +140,6 @@ "@types/react-dom": "^19.0.0", "esbuild": "^0.27.3", "react-dom": "^19.0.0", - "typescript": "^5.9.0", }, "peerDependencies": { "react": "^19.0.0", @@ -403,7 +384,7 @@ "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, ""], - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.6", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg=="], @@ -625,6 +606,46 @@ "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], + "@typescript/typescript-aix-ppc64": ["@typescript/typescript-aix-ppc64@7.0.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ=="], + + "@typescript/typescript-darwin-arm64": ["@typescript/typescript-darwin-arm64@7.0.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA=="], + + "@typescript/typescript-darwin-x64": ["@typescript/typescript-darwin-x64@7.0.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA=="], + + "@typescript/typescript-freebsd-arm64": ["@typescript/typescript-freebsd-arm64@7.0.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ=="], + + "@typescript/typescript-freebsd-x64": ["@typescript/typescript-freebsd-x64@7.0.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw=="], + + "@typescript/typescript-linux-arm": ["@typescript/typescript-linux-arm@7.0.2", "", { "os": "linux", "cpu": "arm" }, "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ=="], + + "@typescript/typescript-linux-arm64": ["@typescript/typescript-linux-arm64@7.0.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ=="], + + "@typescript/typescript-linux-loong64": ["@typescript/typescript-linux-loong64@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ=="], + + "@typescript/typescript-linux-mips64el": ["@typescript/typescript-linux-mips64el@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA=="], + + "@typescript/typescript-linux-ppc64": ["@typescript/typescript-linux-ppc64@7.0.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA=="], + + "@typescript/typescript-linux-riscv64": ["@typescript/typescript-linux-riscv64@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ=="], + + "@typescript/typescript-linux-s390x": ["@typescript/typescript-linux-s390x@7.0.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw=="], + + "@typescript/typescript-linux-x64": ["@typescript/typescript-linux-x64@7.0.2", "", { "os": "linux", "cpu": "x64" }, "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A=="], + + "@typescript/typescript-netbsd-arm64": ["@typescript/typescript-netbsd-arm64@7.0.2", "", { "os": "none", "cpu": "arm64" }, "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA=="], + + "@typescript/typescript-netbsd-x64": ["@typescript/typescript-netbsd-x64@7.0.2", "", { "os": "none", "cpu": "x64" }, "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA=="], + + "@typescript/typescript-openbsd-arm64": ["@typescript/typescript-openbsd-arm64@7.0.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ=="], + + "@typescript/typescript-openbsd-x64": ["@typescript/typescript-openbsd-x64@7.0.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg=="], + + "@typescript/typescript-sunos-x64": ["@typescript/typescript-sunos-x64@7.0.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g=="], + + "@typescript/typescript-win32-arm64": ["@typescript/typescript-win32-arm64@7.0.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ=="], + + "@typescript/typescript-win32-x64": ["@typescript/typescript-win32-x64@7.0.2", "", { "os": "win32", "cpu": "x64" }, "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g=="], + "@vitejs/plugin-react": ["@vitejs/plugin-react@6.1.1", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.1" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "oxc-transform-react": "^0.145.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler", "oxc-transform-react"] }, "sha512-yxLaQV9gkhS8ezJqCM6+ndU7mDY6gqAg75NQ+0IjwEI8IYOmQCgkRwHKVSfWXW076DsqMo0Dk+0FK1U+M5RgFw=="], "@vitejs/plugin-rsc": ["@vitejs/plugin-rsc@0.5.30", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.1", "es-module-lexer": "^2.3.1", "estree-walker": "^3.0.3", "magic-string": "^0.30.21", "srvx": "^0.11.22", "strip-literal": "^3.1.0", "turbo-stream": "^3.2.0", "vitefu": "^1.1.3" }, "peerDependencies": { "react": "*", "react-dom": "*", "react-server-dom-webpack": "*", "vite": "*" }, "optionalPeers": ["react-server-dom-webpack"] }, "sha512-q4fje/9heG/Mx3m5hEC9fpP1bUcpVtpq1sSZ7pWcVrYVxkMNBEEfcILwmUIo2EtMwbBp0/aPzVBsXcA8mG777A=="], @@ -1139,7 +1160,7 @@ "pkg-conf": ["pkg-conf@2.1.0", "", { "dependencies": { "find-up": "^2.0.0", "load-json-file": "^4.0.0" } }, "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g=="], - "postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], + "postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, ""], "prettier": ["prettier@3.9.9", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg=="], @@ -1327,6 +1348,8 @@ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, ""], + "typescript7": ["typescript@7.0.2", "", { "optionalDependencies": { "@typescript/typescript-aix-ppc64": "7.0.2", "@typescript/typescript-darwin-arm64": "7.0.2", "@typescript/typescript-darwin-x64": "7.0.2", "@typescript/typescript-freebsd-arm64": "7.0.2", "@typescript/typescript-freebsd-x64": "7.0.2", "@typescript/typescript-linux-arm": "7.0.2", "@typescript/typescript-linux-arm64": "7.0.2", "@typescript/typescript-linux-loong64": "7.0.2", "@typescript/typescript-linux-mips64el": "7.0.2", "@typescript/typescript-linux-ppc64": "7.0.2", "@typescript/typescript-linux-riscv64": "7.0.2", "@typescript/typescript-linux-s390x": "7.0.2", "@typescript/typescript-linux-x64": "7.0.2", "@typescript/typescript-netbsd-arm64": "7.0.2", "@typescript/typescript-netbsd-x64": "7.0.2", "@typescript/typescript-openbsd-arm64": "7.0.2", "@typescript/typescript-openbsd-x64": "7.0.2", "@typescript/typescript-sunos-x64": "7.0.2", "@typescript/typescript-win32-arm64": "7.0.2", "@typescript/typescript-win32-x64": "7.0.2" }, "bin": { "tsc": "bin/tsc" } }, "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA=="], + "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="], "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], @@ -1439,8 +1462,6 @@ "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], @@ -1459,11 +1480,7 @@ "@babel/traverse/@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], - "@jridgewell/gen-mapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - - "@jridgewell/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - - "@jridgewell/source-map/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], "@pnpm/network.ca-file/graceful-fs": ["graceful-fs@4.2.10", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="], @@ -1527,7 +1544,7 @@ "micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], - "minimizer-webpack-plugin/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], "npm/@gar/promise-retry": ["@gar/promise-retry@1.0.3", "", {}, "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA=="], @@ -1843,8 +1860,6 @@ "unplugin/picomatch": ["picomatch@4.0.5", "", {}, "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A=="], - "vite/postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, ""], - "vitest/picomatch": ["picomatch@4.0.5", "", {}, "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A=="], "webpack/es-module-lexer": ["es-module-lexer@2.3.2", "", {}, "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw=="], @@ -1853,10 +1868,6 @@ "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - "@babel/core/@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - - "@babel/traverse/@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@rolldown/binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], "@rolldown/binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], diff --git a/examples/nextjs-smoke/next.config.ts b/examples/nextjs-smoke/next.config.ts index 56b721b6..56f6ed22 100644 --- a/examples/nextjs-smoke/next.config.ts +++ b/examples/nextjs-smoke/next.config.ts @@ -1,6 +1,7 @@ import type { NextConfig } from "next"; -// @decocms/blocks ships plain .ts source; Next compiles it only when told to. -const nextConfig: NextConfig = { transpilePackages: ["@decocms/blocks"] }; +// No transpilePackages: @decocms/blocks ships compiled JavaScript (dist/, one +// .js per source file), which Next loads from node_modules like any package. +const nextConfig: NextConfig = {}; export default nextConfig; diff --git a/examples/nextjs-smoke/scripts/build-installed.sh b/examples/nextjs-smoke/scripts/build-installed.sh index 6a5a6497..962a9bcf 100755 --- a/examples/nextjs-smoke/scripts/build-installed.sh +++ b/examples/nextjs-smoke/scripts/build-installed.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Builds this example the way npm installs it: @decocms/blocks as a real folder in node_modules, -# not the workspace symlink (Next only compiles .ts outside node_modules unless transpilePackages says so). -# Needs .deco/blocks.gen.ts (run `deco content` first). +# not the workspace symlink, so the build loads the package's compiled dist/ from node_modules. +# Needs .deco/blocks.gen.ts (run `deco content` first) and packages/blocks/dist (run `bun run build`). set -euo pipefail here="$(cd "$(dirname "$0")/.." && pwd)" root="$(cd "$here/../.." && pwd)" diff --git a/knip.json b/knip.json index 7bef957a..70b17f22 100644 --- a/knip.json +++ b/knip.json @@ -36,6 +36,9 @@ ], "ignoreDependencies": [ "esbuild" + ], + "entry": [ + "src/v8/cli/main.ts" ] } }, diff --git a/package.json b/package.json index f84b7f53..cb171eaa 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,11 @@ ], "packageManager": "bun@1.3.5", "scripts": { + "prepare": "bun run build", "build": "bun run --filter='./packages/*' build", "test": "vitest run", - "typecheck": "bun run --filter='./packages/*' typecheck && tsc -p .agents/skills/deco-v7-to-v8-migration/scripts && tsc -p tests", - "examples": "bun run --filter='./examples/*' build && bun run --filter='./examples/*' typecheck", + "typecheck": "bun run --filter='./packages/*' typecheck && node scripts/tsc.mjs -p .agents/skills/deco-v7-to-v8-migration/scripts && node scripts/tsc.mjs -p tests", + "examples": "bun run build && bun run --filter='./examples/*' build && bun run --filter='./examples/*' typecheck", "lint": "biome check packages/*/src tests .agents/skills/deco-v7-to-v8-migration/scripts", "lint:fix": "biome check --write packages/*/src tests .agents/skills/deco-v7-to-v8-migration/scripts", "lint:unused": "knip", @@ -23,10 +24,14 @@ "devDependencies": { "@biomejs/biome": "^2.5.3", "@semantic-release/exec": "^7.1.0", + "@types/node": "^22.0.0", "jsdom": "^29.1.1", "knip": "^5.86.0", "semantic-release": "^25.0.5", + "tsx": "^4.22.5", "typescript": "^5.9.3", + "typescript7": "npm:typescript@7.0.2", + "vite": "^8.0.1", "vitest": "^4.1.10" } } diff --git a/packages/apps-algolia/package.json b/packages/apps-algolia/package.json index 29ff5f93..6ebab912 100644 --- a/packages/apps-algolia/package.json +++ b/packages/apps-algolia/package.json @@ -9,25 +9,29 @@ "directory": "packages/apps-algolia" }, "files": [ + "dist", "src", "!src/**/*.test.ts", "!src/**/__tests__" ], - "main": "./src/index.ts", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { - ".": "./src/index.ts" + ".": { + "types": "./dist/index.d.ts", + "source": "./src/index.ts", + "default": "./dist/index.js" + } }, "scripts": { - "build": "tsc", + "build": "node ../../scripts/tsc.mjs --clean dist -p tsconfig.build.json", + "prepack": "npm run build", "test": "vitest run --root ../.. packages/apps-algolia/", - "typecheck": "tsc --noEmit" + "typecheck": "node ../../scripts/tsc.mjs -p tsconfig.json" }, "dependencies": { "@decocms/blocks": "workspace:*" }, - "devDependencies": { - "typescript": "^5.9.0" - }, "publishConfig": { "registry": "https://registry.npmjs.org", "access": "public" diff --git a/packages/apps-algolia/tsconfig.build.json b/packages/apps-algolia/tsconfig.build.json new file mode 100644 index 00000000..7dd791e6 --- /dev/null +++ b/packages/apps-algolia/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.build.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src/**/*"], + "exclude": [ + "src/**/*.test.ts", + "src/**/*.test.tsx", + "src/**/__tests__/**", + "src/**/__fixtures__/**", + "src/**/__conformance__/**", + "src/v8/testFixtures.ts" + ] +} diff --git a/packages/apps-algolia/tsconfig.json b/packages/apps-algolia/tsconfig.json index 42386d32..bf5a36dd 100644 --- a/packages/apps-algolia/tsconfig.json +++ b/packages/apps-algolia/tsconfig.json @@ -1,7 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "dist" - }, "include": ["src/**/*"] } diff --git a/packages/apps-magento/package.json b/packages/apps-magento/package.json index d74ee888..e6b26bd8 100644 --- a/packages/apps-magento/package.json +++ b/packages/apps-magento/package.json @@ -9,25 +9,29 @@ "directory": "packages/apps-magento" }, "files": [ + "dist", "src", "!src/**/*.test.ts", "!src/**/__tests__" ], - "main": "./src/index.ts", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { - ".": "./src/index.ts" + ".": { + "types": "./dist/index.d.ts", + "source": "./src/index.ts", + "default": "./dist/index.js" + } }, "scripts": { - "build": "tsc", + "build": "node ../../scripts/tsc.mjs --clean dist -p tsconfig.build.json", + "prepack": "npm run build", "test": "vitest run --root ../.. packages/apps-magento/", - "typecheck": "tsc --noEmit" + "typecheck": "node ../../scripts/tsc.mjs -p tsconfig.json" }, "dependencies": { "@decocms/blocks": "workspace:*" }, - "devDependencies": { - "typescript": "^5.9.0" - }, "publishConfig": { "registry": "https://registry.npmjs.org", "access": "public" diff --git a/packages/apps-magento/src/index.ts b/packages/apps-magento/src/index.ts index 4943328a..ec62a25f 100644 --- a/packages/apps-magento/src/index.ts +++ b/packages/apps-magento/src/index.ts @@ -6,4 +6,4 @@ export { type MagentoClientOptions, MagentoError, type MagentoRequestInit, -} from "./magentoClient"; +} from "./magentoClient.ts"; diff --git a/packages/apps-magento/tsconfig.build.json b/packages/apps-magento/tsconfig.build.json new file mode 100644 index 00000000..7dd791e6 --- /dev/null +++ b/packages/apps-magento/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.build.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src/**/*"], + "exclude": [ + "src/**/*.test.ts", + "src/**/*.test.tsx", + "src/**/__tests__/**", + "src/**/__fixtures__/**", + "src/**/__conformance__/**", + "src/v8/testFixtures.ts" + ] +} diff --git a/packages/apps-magento/tsconfig.json b/packages/apps-magento/tsconfig.json index 42386d32..bf5a36dd 100644 --- a/packages/apps-magento/tsconfig.json +++ b/packages/apps-magento/tsconfig.json @@ -1,7 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "dist" - }, "include": ["src/**/*"] } diff --git a/packages/apps-resend/package.json b/packages/apps-resend/package.json index d4539a58..7b640214 100644 --- a/packages/apps-resend/package.json +++ b/packages/apps-resend/package.json @@ -9,25 +9,29 @@ "directory": "packages/apps-resend" }, "files": [ + "dist", "src", "!src/**/*.test.ts", "!src/**/__tests__" ], - "main": "./src/index.ts", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { - ".": "./src/index.ts" + ".": { + "types": "./dist/index.d.ts", + "source": "./src/index.ts", + "default": "./dist/index.js" + } }, "scripts": { - "build": "tsc", + "build": "node ../../scripts/tsc.mjs --clean dist -p tsconfig.build.json", + "prepack": "npm run build", "test": "vitest run --root ../.. packages/apps-resend/", - "typecheck": "tsc --noEmit" + "typecheck": "node ../../scripts/tsc.mjs -p tsconfig.json" }, "dependencies": { "@decocms/blocks": "workspace:*" }, - "devDependencies": { - "typescript": "^5.9.0" - }, "publishConfig": { "registry": "https://registry.npmjs.org", "access": "public" diff --git a/packages/apps-resend/src/emails.ts b/packages/apps-resend/src/emails.ts index 8f7244ec..53480bab 100644 --- a/packages/apps-resend/src/emails.ts +++ b/packages/apps-resend/src/emails.ts @@ -7,7 +7,7 @@ * Default senders, recipients and subjects belong to the site. */ import { createInstrumentedFetch } from "@decocms/blocks/fetch"; -import type { CreateEmailOptions, CreateEmailResponseSuccess } from "./types"; +import type { CreateEmailOptions, CreateEmailResponseSuccess } from "./types.ts"; export interface ResendClientConfig { apiKey: string; diff --git a/packages/apps-resend/src/index.ts b/packages/apps-resend/src/index.ts index a6ab011d..8cca9000 100644 --- a/packages/apps-resend/src/index.ts +++ b/packages/apps-resend/src/index.ts @@ -8,5 +8,5 @@ export { type ResendClientConfig, ResendError, type SendEmailOptions, -} from "./emails"; -export type { CreateEmailOptions, CreateEmailResponseSuccess } from "./types"; +} from "./emails.ts"; +export type { CreateEmailOptions, CreateEmailResponseSuccess } from "./types.ts"; diff --git a/packages/apps-resend/tsconfig.build.json b/packages/apps-resend/tsconfig.build.json new file mode 100644 index 00000000..7dd791e6 --- /dev/null +++ b/packages/apps-resend/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.build.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src/**/*"], + "exclude": [ + "src/**/*.test.ts", + "src/**/*.test.tsx", + "src/**/__tests__/**", + "src/**/__fixtures__/**", + "src/**/__conformance__/**", + "src/v8/testFixtures.ts" + ] +} diff --git a/packages/apps-resend/tsconfig.json b/packages/apps-resend/tsconfig.json index 42386d32..bf5a36dd 100644 --- a/packages/apps-resend/tsconfig.json +++ b/packages/apps-resend/tsconfig.json @@ -1,7 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "dist" - }, "include": ["src/**/*"] } diff --git a/packages/apps-sfmc-personalization/package.json b/packages/apps-sfmc-personalization/package.json index ac3d294f..4912b61a 100644 --- a/packages/apps-sfmc-personalization/package.json +++ b/packages/apps-sfmc-personalization/package.json @@ -9,25 +9,29 @@ "directory": "packages/apps-sfmc-personalization" }, "files": [ + "dist", "src", "!src/**/*.test.ts", "!src/**/__tests__" ], - "main": "./src/index.ts", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { - ".": "./src/index.ts" + ".": { + "types": "./dist/index.d.ts", + "source": "./src/index.ts", + "default": "./dist/index.js" + } }, "scripts": { - "build": "tsc", + "build": "node ../../scripts/tsc.mjs --clean dist -p tsconfig.build.json", + "prepack": "npm run build", "test": "vitest run --root ../.. packages/apps-sfmc-personalization/", - "typecheck": "tsc --noEmit" + "typecheck": "node ../../scripts/tsc.mjs -p tsconfig.json" }, "dependencies": { "@decocms/blocks": "workspace:*" }, - "devDependencies": { - "typescript": "^5.9.0" - }, "publishConfig": { "registry": "https://registry.npmjs.org", "access": "public" diff --git a/packages/apps-sfmc-personalization/src/index.ts b/packages/apps-sfmc-personalization/src/index.ts index ae725af7..fc1a6b92 100644 --- a/packages/apps-sfmc-personalization/src/index.ts +++ b/packages/apps-sfmc-personalization/src/index.ts @@ -8,7 +8,7 @@ * to the site (platform templates and site code). */ import { createInstrumentedFetch } from "@decocms/blocks/fetch"; -import type { PersonalizationEvent, PersonalizationResponse } from "./types"; +import type { PersonalizationEvent, PersonalizationResponse } from "./types.ts"; export type { CampaignResponse, @@ -16,7 +16,7 @@ export type { PersonalizationLineItem, PersonalizationProduct, PersonalizationResponse, -} from "./types"; +} from "./types.ts"; export interface SfmcPersonalizationConfig { /** The account's API origin, e.g. `https://..evergage.com`. */ diff --git a/packages/apps-sfmc-personalization/tsconfig.build.json b/packages/apps-sfmc-personalization/tsconfig.build.json new file mode 100644 index 00000000..7dd791e6 --- /dev/null +++ b/packages/apps-sfmc-personalization/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.build.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src/**/*"], + "exclude": [ + "src/**/*.test.ts", + "src/**/*.test.tsx", + "src/**/__tests__/**", + "src/**/__fixtures__/**", + "src/**/__conformance__/**", + "src/v8/testFixtures.ts" + ] +} diff --git a/packages/apps-sfmc-personalization/tsconfig.json b/packages/apps-sfmc-personalization/tsconfig.json index 42386d32..bf5a36dd 100644 --- a/packages/apps-sfmc-personalization/tsconfig.json +++ b/packages/apps-sfmc-personalization/tsconfig.json @@ -1,7 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "dist" - }, "include": ["src/**/*"] } diff --git a/packages/apps-shopify/package.json b/packages/apps-shopify/package.json index 4164e296..1db1598b 100644 --- a/packages/apps-shopify/package.json +++ b/packages/apps-shopify/package.json @@ -9,25 +9,29 @@ "directory": "packages/apps-shopify" }, "files": [ + "dist", "src", "!src/**/*.test.ts", "!src/**/__tests__" ], - "main": "./src/index.ts", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { - ".": "./src/index.ts" + ".": { + "types": "./dist/index.d.ts", + "source": "./src/index.ts", + "default": "./dist/index.js" + } }, "scripts": { - "build": "tsc", + "build": "node ../../scripts/tsc.mjs --clean dist -p tsconfig.build.json", + "prepack": "npm run build", "test": "vitest run --root ../.. packages/apps-shopify/", - "typecheck": "tsc --noEmit" + "typecheck": "node ../../scripts/tsc.mjs -p tsconfig.json" }, "dependencies": { "@decocms/blocks": "workspace:*" }, - "devDependencies": { - "typescript": "^5.9.0" - }, "publishConfig": { "registry": "https://registry.npmjs.org", "access": "public" diff --git a/packages/apps-shopify/src/client.ts b/packages/apps-shopify/src/client.ts index 05280daf..8d9b38fd 100644 --- a/packages/apps-shopify/src/client.ts +++ b/packages/apps-shopify/src/client.ts @@ -11,7 +11,7 @@ * is the site's job. */ import { createInstrumentedFetch } from "@decocms/blocks/fetch"; -import { extractGraphqlOperationName } from "./graphqlOperationName"; +import { extractGraphqlOperationName } from "./graphqlOperationName.ts"; export interface ShopifyClientConfig { /** The store's subdomain: "acme" for acme.myshopify.com. */ diff --git a/packages/apps-shopify/src/index.ts b/packages/apps-shopify/src/index.ts index 2412b6eb..b2fce843 100644 --- a/packages/apps-shopify/src/index.ts +++ b/packages/apps-shopify/src/index.ts @@ -7,4 +7,4 @@ export { type ShopifyClient, type ShopifyClientConfig, ShopifyError, -} from "./client"; +} from "./client.ts"; diff --git a/packages/apps-shopify/tsconfig.build.json b/packages/apps-shopify/tsconfig.build.json new file mode 100644 index 00000000..7dd791e6 --- /dev/null +++ b/packages/apps-shopify/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.build.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src/**/*"], + "exclude": [ + "src/**/*.test.ts", + "src/**/*.test.tsx", + "src/**/__tests__/**", + "src/**/__fixtures__/**", + "src/**/__conformance__/**", + "src/v8/testFixtures.ts" + ] +} diff --git a/packages/apps-shopify/tsconfig.json b/packages/apps-shopify/tsconfig.json index 42386d32..bf5a36dd 100644 --- a/packages/apps-shopify/tsconfig.json +++ b/packages/apps-shopify/tsconfig.json @@ -1,7 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "dist" - }, "include": ["src/**/*"] } diff --git a/packages/apps-vtex/package.json b/packages/apps-vtex/package.json index 06c7d4f9..d7a89f86 100644 --- a/packages/apps-vtex/package.json +++ b/packages/apps-vtex/package.json @@ -9,25 +9,29 @@ "directory": "packages/apps-vtex" }, "files": [ + "dist", "src", "!src/**/*.test.ts", "!src/**/__tests__" ], - "main": "./src/index.ts", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { - ".": "./src/index.ts" + ".": { + "types": "./dist/index.d.ts", + "source": "./src/index.ts", + "default": "./dist/index.js" + } }, "scripts": { - "build": "tsc", + "build": "node ../../scripts/tsc.mjs --clean dist -p tsconfig.build.json", + "prepack": "npm run build", "test": "vitest run --root ../.. packages/apps-vtex/", - "typecheck": "tsc --noEmit" + "typecheck": "node ../../scripts/tsc.mjs -p tsconfig.json" }, "dependencies": { "@decocms/blocks": "workspace:*" }, - "devDependencies": { - "typescript": "^5.9.0" - }, "publishConfig": { "registry": "https://registry.npmjs.org", "access": "public" diff --git a/packages/apps-vtex/src/index.ts b/packages/apps-vtex/src/index.ts index e793ae8c..0d48d42b 100644 --- a/packages/apps-vtex/src/index.ts +++ b/packages/apps-vtex/src/index.ts @@ -11,4 +11,4 @@ export { type VtexRequestOptions, type VtexResponse, type VtexSearchArgs, -} from "./vtexClient"; +} from "./vtexClient.ts"; diff --git a/packages/apps-vtex/src/vtexClient.ts b/packages/apps-vtex/src/vtexClient.ts index 49193707..5daa7b84 100644 --- a/packages/apps-vtex/src/vtexClient.ts +++ b/packages/apps-vtex/src/vtexClient.ts @@ -26,9 +26,9 @@ * never repeated. Pass `retry: false` / `circuitBreaker: false` to turn them off. */ import { createInstrumentedFetch } from "@decocms/blocks/fetch"; -import { DEFAULT_RESILIENCE_CONFIG } from "./utils/constants"; -import { sanitizeOutboundCookieHeader } from "./utils/cookieSanitizer"; -import { vtexOperationRouter } from "./utils/operationRouter"; +import { DEFAULT_RESILIENCE_CONFIG } from "./utils/constants.ts"; +import { sanitizeOutboundCookieHeader } from "./utils/cookieSanitizer.ts"; +import { vtexOperationRouter } from "./utils/operationRouter.ts"; import type { Category, CrossSellingType, @@ -46,7 +46,7 @@ import type { SimulationOrderForm, Sort, Suggestion, -} from "./utils/types"; +} from "./utils/types.ts"; export interface VtexClientConfig { /** The VTEX account name, e.g. `mystore`. */ diff --git a/packages/apps-vtex/tsconfig.build.json b/packages/apps-vtex/tsconfig.build.json new file mode 100644 index 00000000..7dd791e6 --- /dev/null +++ b/packages/apps-vtex/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.build.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src/**/*"], + "exclude": [ + "src/**/*.test.ts", + "src/**/*.test.tsx", + "src/**/__tests__/**", + "src/**/__fixtures__/**", + "src/**/__conformance__/**", + "src/v8/testFixtures.ts" + ] +} diff --git a/packages/apps-vtex/tsconfig.json b/packages/apps-vtex/tsconfig.json index 42386d32..bf5a36dd 100644 --- a/packages/apps-vtex/tsconfig.json +++ b/packages/apps-vtex/tsconfig.json @@ -1,7 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "dist" - }, "include": ["src/**/*"] } diff --git a/packages/apps-wake/package.json b/packages/apps-wake/package.json index 0e7e9844..740d5797 100644 --- a/packages/apps-wake/package.json +++ b/packages/apps-wake/package.json @@ -9,27 +9,39 @@ "directory": "packages/apps-wake" }, "files": [ + "dist", "src", "!src/**/*.test.ts", "!src/**/__tests__" ], - "main": "./src/index.ts", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { - ".": "./src/index.ts", - "./storefront": "./src/storefront.ts", - "./storefront/types": "./src/storefrontTypes.ts" + ".": { + "types": "./dist/index.d.ts", + "source": "./src/index.ts", + "default": "./dist/index.js" + }, + "./storefront": { + "types": "./dist/storefront.d.ts", + "source": "./src/storefront.ts", + "default": "./dist/storefront.js" + }, + "./storefront/types": { + "types": "./dist/storefrontTypes.d.ts", + "source": "./src/storefrontTypes.ts", + "default": "./dist/storefrontTypes.js" + } }, "scripts": { - "build": "tsc", + "build": "node ../../scripts/tsc.mjs --clean dist -p tsconfig.build.json", + "prepack": "npm run build", "test": "vitest run --root ../.. packages/apps-wake/", - "typecheck": "tsc --noEmit" + "typecheck": "node ../../scripts/tsc.mjs -p tsconfig.json" }, "dependencies": { "@decocms/blocks": "workspace:*" }, - "devDependencies": { - "typescript": "^5.9.0" - }, "publishConfig": { "registry": "https://registry.npmjs.org", "access": "public" diff --git a/packages/apps-wake/src/index.ts b/packages/apps-wake/src/index.ts index 44cde26c..3c5b4c39 100644 --- a/packages/apps-wake/src/index.ts +++ b/packages/apps-wake/src/index.ts @@ -1,11 +1,11 @@ // The thin Wake client (see /next/upstream-clients). Operations are in // `@decocms/apps-wake/storefront`, their types in `.../storefront/types`. -export type { UserAuthenticate } from "./utils/client"; +export type { UserAuthenticate } from "./utils/client.ts"; export { createWakeClient, type WakeClient, type WakeClientConfig, type WakeClientOptions, WakeError, -} from "./wakeClient"; +} from "./wakeClient.ts"; diff --git a/packages/apps-wake/src/storefront.ts b/packages/apps-wake/src/storefront.ts index 59c34694..d66c05b1 100644 --- a/packages/apps-wake/src/storefront.ts +++ b/packages/apps-wake/src/storefront.ts @@ -10,4 +10,4 @@ * const data = await wake.graphql(GetProduct, { productId: 1 }); * ``` */ -export * from "./utils/graphql/queries"; +export * from "./utils/graphql/queries.ts"; diff --git a/packages/apps-wake/src/storefrontTypes.ts b/packages/apps-wake/src/storefrontTypes.ts index 7386af6b..f5a9ae2c 100644 --- a/packages/apps-wake/src/storefrontTypes.ts +++ b/packages/apps-wake/src/storefrontTypes.ts @@ -3,4 +3,4 @@ * Storefront GraphQL schema, one `Query`/`Mutation` and * `...Variables` pair per operation in `@decocms/apps-wake/storefront`. */ -export type * from "./utils/graphql/storefront.graphql.gen"; +export type * from "./utils/graphql/storefront.graphql.gen.ts"; diff --git a/packages/apps-wake/src/utils/graphql/queries.ts b/packages/apps-wake/src/utils/graphql/queries.ts index e9375040..df8f0d57 100644 --- a/packages/apps-wake/src/utils/graphql/queries.ts +++ b/packages/apps-wake/src/utils/graphql/queries.ts @@ -1,4 +1,4 @@ -import { gql } from "../gql"; +import { gql } from "../gql.ts"; const Checkout = gql` fragment Checkout on Checkout { diff --git a/packages/apps-wake/src/wakeClient.ts b/packages/apps-wake/src/wakeClient.ts index 7ea62cf3..5323743e 100644 --- a/packages/apps-wake/src/wakeClient.ts +++ b/packages/apps-wake/src/wakeClient.ts @@ -8,9 +8,9 @@ * proxying belong to the site (platform templates), not here. */ import { createInstrumentedFetch } from "@decocms/blocks/fetch"; -import type { UserAuthenticate } from "./utils/client"; -import { buildQuery, type QueryDefinition } from "./utils/gql"; -import { extractGraphqlOperationName } from "./utils/graphqlOperationName"; +import type { UserAuthenticate } from "./utils/client.ts"; +import { buildQuery, type QueryDefinition } from "./utils/gql.ts"; +import { extractGraphqlOperationName } from "./utils/graphqlOperationName.ts"; const WAKE_STOREFRONT_ENDPOINT = "https://storefront-api.fbits.net/graphql"; diff --git a/packages/apps-wake/tsconfig.build.json b/packages/apps-wake/tsconfig.build.json new file mode 100644 index 00000000..7dd791e6 --- /dev/null +++ b/packages/apps-wake/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.build.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src/**/*"], + "exclude": [ + "src/**/*.test.ts", + "src/**/*.test.tsx", + "src/**/__tests__/**", + "src/**/__fixtures__/**", + "src/**/__conformance__/**", + "src/v8/testFixtures.ts" + ] +} diff --git a/packages/apps-wake/tsconfig.json b/packages/apps-wake/tsconfig.json index 42386d32..bf5a36dd 100644 --- a/packages/apps-wake/tsconfig.json +++ b/packages/apps-wake/tsconfig.json @@ -1,7 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "dist" - }, "include": ["src/**/*"] } diff --git a/packages/blocks/bin/deco.js b/packages/blocks/bin/deco.js index 4b7faa54..53da1791 100755 --- a/packages/blocks/bin/deco.js +++ b/packages/blocks/bin/deco.js @@ -1,13 +1,6 @@ #!/usr/bin/env node -// The `deco` command (spec: internals › How the CLI ships). A small JavaScript -// file that loads the CLI's TypeScript sources: Bun runs them as they are; -// under Node, tsx's loader is registered first. -const entry = new URL("../src/v8/cli/main.ts", import.meta.url); - -if (typeof globalThis.Bun !== "undefined") { - await import(entry.href); -} else { - const { register } = await import("tsx/esm/api"); - register(); - await import(entry.href); -} +// The `deco` command (spec: internals › How the CLI ships). It runs the CLI's +// compiled JavaScript in dist/ (one .js per source file, emitted by `tsc`), so +// plain Node, Bun and npx all run it with no TypeScript loader. In a checkout, +// `bun run build` (or `bun install`, which builds the workspace) writes dist/. +await import(new URL("../dist/v8/cli/main.js", import.meta.url).href); diff --git a/packages/blocks/package.json b/packages/blocks/package.json index cc40ea9e..3d35b2c2 100644 --- a/packages/blocks/package.json +++ b/packages/blocks/package.json @@ -11,9 +11,11 @@ "url": "https://github.com/decocms/blocks.git", "directory": "packages/blocks" }, - "main": "./src/index.ts", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "files": [ "bin", + "dist", "src", "!src/**/*.test.ts", "!src/**/*.test.tsx", @@ -26,28 +28,72 @@ "deco": "./bin/deco.js" }, "exports": { - ".": "./src/index.ts", - "./analytics": "./src/v8/analytics.ts", - "./cli": "./src/v8/cli/index.ts", - "./fetch": "./src/v8/fetch.ts", - "./secrets": "./src/v8/secrets.ts", - "./protocol": "./src/protocol/index.ts", - "./protocol/keys": "./src/protocol/keys.ts", - "./protocol/server": "./src/protocol/server/index.ts", + ".": { + "types": "./dist/index.d.ts", + "source": "./src/index.ts", + "default": "./dist/index.js" + }, + "./analytics": { + "types": "./dist/v8/analytics.d.ts", + "source": "./src/v8/analytics.ts", + "default": "./dist/v8/analytics.js" + }, + "./cli": { + "types": "./dist/v8/cli/index.d.ts", + "source": "./src/v8/cli/index.ts", + "default": "./dist/v8/cli/index.js" + }, + "./fetch": { + "types": "./dist/v8/fetch.d.ts", + "source": "./src/v8/fetch.ts", + "default": "./dist/v8/fetch.js" + }, + "./secrets": { + "types": "./dist/v8/secrets.d.ts", + "source": "./src/v8/secrets.ts", + "default": "./dist/v8/secrets.js" + }, + "./protocol": { + "types": "./dist/protocol/index.d.ts", + "source": "./src/protocol/index.ts", + "default": "./dist/protocol/index.js" + }, + "./protocol/keys": { + "types": "./dist/protocol/keys.d.ts", + "source": "./src/protocol/keys.ts", + "default": "./dist/protocol/keys.js" + }, + "./protocol/server": { + "types": "./dist/protocol/server/index.d.ts", + "source": "./src/protocol/server/index.ts", + "default": "./dist/protocol/server/index.js" + }, "./protocol/storage/fs": { - "node": "./src/protocol/storage/fs/index.ts", - "default": "./src/protocol/storage/fs/unsupported.ts" + "node": { + "types": "./dist/protocol/storage/fs/index.d.ts", + "source": "./src/protocol/storage/fs/index.ts", + "default": "./dist/protocol/storage/fs/index.js" + }, + "default": { + "types": "./dist/protocol/storage/fs/unsupported.d.ts", + "source": "./src/protocol/storage/fs/unsupported.ts", + "default": "./dist/protocol/storage/fs/unsupported.js" + } }, - "./protocol/conformance": "./src/protocol/conformance/index.ts" + "./protocol/conformance": { + "types": "./dist/protocol/conformance/index.d.ts", + "source": "./src/protocol/conformance/index.ts", + "default": "./dist/protocol/conformance/index.js" + } }, "scripts": { - "build": "tsc", + "build": "node ../../scripts/tsc.mjs --clean dist -p tsconfig.build.json", + "prepack": "npm run build", "test": "vitest run --root ../.. packages/blocks/", - "typecheck": "tsc --noEmit" + "typecheck": "node ../../scripts/tsc.mjs -p tsconfig.json" }, "dependencies": { "ajv": "^8.20.0", - "tsx": "^4.22.5", "zod": "^4.4.3" }, "peerDependencies": { @@ -58,8 +104,7 @@ "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "esbuild": "^0.27.3", - "react-dom": "^19.0.0", - "typescript": "^5.9.0" + "react-dom": "^19.0.0" }, "publishConfig": { "registry": "https://registry.npmjs.org", diff --git a/packages/blocks/src/index.ts b/packages/blocks/src/index.ts index 43614f38..eba90a74 100644 --- a/packages/blocks/src/index.ts +++ b/packages/blocks/src/index.ts @@ -32,4 +32,4 @@ export { type Telemetry, type TelemetryConfig, type Variant, -} from "./v8/index"; +} from "./v8/index.ts"; diff --git a/packages/blocks/src/protocol/canonical.ts b/packages/blocks/src/protocol/canonical.ts index f850c84d..18727742 100644 --- a/packages/blocks/src/protocol/canonical.ts +++ b/packages/blocks/src/protocol/canonical.ts @@ -4,4 +4,4 @@ * content revisions too; the protocol re-exports it so the CLI, the server * and the site editor share one definition. */ -export * from "../v8/canonical"; +export * from "../v8/canonical.ts"; diff --git a/packages/blocks/src/protocol/ciphertext.ts b/packages/blocks/src/protocol/ciphertext.ts index fef7b9d7..8e3aa9f2 100644 --- a/packages/blocks/src/protocol/ciphertext.ts +++ b/packages/blocks/src/protocol/ciphertext.ts @@ -3,4 +3,4 @@ * module of the SDK (`src/v8/ciphertext.ts`), where the `secret` built-in * decrypts it; the protocol re-exports it for its secret guard. */ -export * from "../v8/ciphertext"; +export * from "../v8/ciphertext.ts"; diff --git a/packages/blocks/src/protocol/client.ts b/packages/blocks/src/protocol/client.ts index b1463d67..a910dfe5 100644 --- a/packages/blocks/src/protocol/client.ts +++ b/packages/blocks/src/protocol/client.ts @@ -2,7 +2,7 @@ * A small content-protocol client: one method per protocol method, plus * batches. Uses `fetch`, so it runs in browsers, on Workers and on Node. */ -import { ContentProtocolError, ErrorCode, type RpcErrorObject } from "./errors"; +import { ContentProtocolError, ErrorCode, type RpcErrorObject } from "./errors.ts"; import { type DescribeResult, type MethodName, @@ -10,7 +10,7 @@ import { PROTOCOL_NAME, PROTOCOL_VERSION, type RpcId, -} from "./types"; +} from "./types.ts"; export interface ContentClientOptions { /** The endpoint URL, such as `http://127.0.0.1:4545/rpc`. */ diff --git a/packages/blocks/src/protocol/conformance/cases/assets.ts b/packages/blocks/src/protocol/conformance/cases/assets.ts index 4822f817..65753d72 100644 --- a/packages/blocks/src/protocol/conformance/cases/assets.ts +++ b/packages/blocks/src/protocol/conformance/cases/assets.ts @@ -2,9 +2,9 @@ * Uploads beside the protocol: `PUT /assets/`. These cases run only * when the harness passes `assetsEndpoint`. */ -import { ErrorCode } from "../../errors"; -import { assert, assertEqual, type ConformanceContext, rawErrorCode } from "../context"; -import type { ConformanceCase } from "./types"; +import { ErrorCode } from "../../errors.ts"; +import { assert, assertEqual, type ConformanceContext, rawErrorCode } from "../context.ts"; +import type { ConformanceCase } from "./types.ts"; /** The smallest PNG header: enough bytes for an upload, never executed. */ const PNG = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); diff --git a/packages/blocks/src/protocol/conformance/cases/guards.ts b/packages/blocks/src/protocol/conformance/cases/guards.ts index 819fc712..6cd50a59 100644 --- a/packages/blocks/src/protocol/conformance/cases/guards.ts +++ b/packages/blocks/src/protocol/conformance/cases/guards.ts @@ -1,16 +1,16 @@ /** * Limits, the secret guard and request-key idempotency. */ -import { encryptToCiphertext, publicKeyPemFromDer } from "../../ciphertext"; -import { ErrorCode, type InvalidBlockData } from "../../errors"; +import { encryptToCiphertext, publicKeyPemFromDer } from "../../ciphertext.ts"; +import { ErrorCode, type InvalidBlockData } from "../../errors.ts"; import { assert, assertEqual, type ConformanceContext, expectError, rawErrorCode, -} from "../context"; -import type { ConformanceCase } from "./types"; +} from "../context.ts"; +import type { ConformanceCase } from "./types.ts"; async function writable(ctx: ConformanceContext) { const d = await ctx.describe(); diff --git a/packages/blocks/src/protocol/conformance/cases/reads.ts b/packages/blocks/src/protocol/conformance/cases/reads.ts index c4e0c2ca..e5039147 100644 --- a/packages/blocks/src/protocol/conformance/cases/reads.ts +++ b/packages/blocks/src/protocol/conformance/cases/reads.ts @@ -1,10 +1,10 @@ /** * `describe`, `schema.get` and `blocks.list`, including conditional reads. */ -import { ErrorCode } from "../../errors"; -import { PROTOCOL_NAME, SCHEMA_FORMAT } from "../../types"; -import { assert, assertEqual, expectError } from "../context"; -import type { ConformanceCase } from "./types"; +import { ErrorCode } from "../../errors.ts"; +import { PROTOCOL_NAME, SCHEMA_FORMAT } from "../../types.ts"; +import { assert, assertEqual, expectError } from "../context.ts"; +import type { ConformanceCase } from "./types.ts"; const LIMIT_KEYS = [ "maxOpsPerApply", diff --git a/packages/blocks/src/protocol/conformance/cases/types.ts b/packages/blocks/src/protocol/conformance/cases/types.ts index d85083b9..66e36e85 100644 --- a/packages/blocks/src/protocol/conformance/cases/types.ts +++ b/packages/blocks/src/protocol/conformance/cases/types.ts @@ -1,4 +1,4 @@ -import type { ConformanceContext } from "../context"; +import type { ConformanceContext } from "../context.ts"; /** One black-box check of a content-protocol endpoint. */ export interface ConformanceCase { diff --git a/packages/blocks/src/protocol/conformance/cases/wire.ts b/packages/blocks/src/protocol/conformance/cases/wire.ts index 5e903770..c898125c 100644 --- a/packages/blocks/src/protocol/conformance/cases/wire.ts +++ b/packages/blocks/src/protocol/conformance/cases/wire.ts @@ -1,10 +1,10 @@ /** * The wire format: JSON-RPC 2.0 envelopes, batches, HTTP status codes, gzip. */ -import { ErrorCode } from "../../errors"; -import { MAX_BATCH_CALLS } from "../../types"; -import { assert, assertEqual, rawErrorCode } from "../context"; -import type { ConformanceCase } from "./types"; +import { ErrorCode } from "../../errors.ts"; +import { MAX_BATCH_CALLS } from "../../types.ts"; +import { assert, assertEqual, rawErrorCode } from "../context.ts"; +import type { ConformanceCase } from "./types.ts"; const req = (id: unknown, method: string, params?: unknown) => params === undefined ? { jsonrpc: "2.0", id, method } : { jsonrpc: "2.0", id, method, params }; diff --git a/packages/blocks/src/protocol/conformance/cases/writes.ts b/packages/blocks/src/protocol/conformance/cases/writes.ts index 0c3528e3..a9e55476 100644 --- a/packages/blocks/src/protocol/conformance/cases/writes.ts +++ b/packages/blocks/src/protocol/conformance/cases/writes.ts @@ -2,10 +2,10 @@ * `blocks.apply`: atomic set and delete, set precedence, validation, the * file-name rule and preconditions. */ -import { ErrorCode, type InvalidBlockData } from "../../errors"; -import type { BlocksListResult } from "../../types"; -import { assert, assertEqual, type ConformanceContext, expectError } from "../context"; -import type { ConformanceCase } from "./types"; +import { ErrorCode, type InvalidBlockData } from "../../errors.ts"; +import type { BlocksListResult } from "../../types.ts"; +import { assert, assertEqual, type ConformanceContext, expectError } from "../context.ts"; +import type { ConformanceCase } from "./types.ts"; type FullList = Extract; diff --git a/packages/blocks/src/protocol/conformance/context.ts b/packages/blocks/src/protocol/conformance/context.ts index acceaf3f..27c7968d 100644 --- a/packages/blocks/src/protocol/conformance/context.ts +++ b/packages/blocks/src/protocol/conformance/context.ts @@ -2,10 +2,10 @@ * What every conformance case gets: a client, raw HTTP access, the endpoint's * `describe`, unique names and assertion helpers. */ -import { canonicalJson } from "../canonical"; -import { type ContentClient, createContentClient, readResponseJson } from "../client"; -import { ContentProtocolError } from "../errors"; -import type { DescribeResult } from "../types"; +import { canonicalJson } from "../canonical.ts"; +import { type ContentClient, createContentClient, readResponseJson } from "../client.ts"; +import { ContentProtocolError } from "../errors.ts"; +import type { DescribeResult } from "../types.ts"; export interface ConformanceOptions { /** The endpoint URL, such as `http://127.0.0.1:4545/rpc`. */ diff --git a/packages/blocks/src/protocol/conformance/index.ts b/packages/blocks/src/protocol/conformance/index.ts index aab67675..a412dcca 100644 --- a/packages/blocks/src/protocol/conformance/index.ts +++ b/packages/blocks/src/protocol/conformance/index.ts @@ -19,17 +19,17 @@ * don't apply to an endpoint (a read-only one, one without request keys) * skip themselves. Browser-safe: it only needs `fetch`. */ -import { assetCases } from "./cases/assets"; -import { guardCases } from "./cases/guards"; -import { readCases } from "./cases/reads"; -import type { ConformanceCase } from "./cases/types"; -import { wireCases } from "./cases/wire"; -import { writeCases } from "./cases/writes"; -import { ConformanceContext, type ConformanceOptions, SkipCase } from "./context"; +import { assetCases } from "./cases/assets.ts"; +import { guardCases } from "./cases/guards.ts"; +import { readCases } from "./cases/reads.ts"; +import type { ConformanceCase } from "./cases/types.ts"; +import { wireCases } from "./cases/wire.ts"; +import { writeCases } from "./cases/writes.ts"; +import { ConformanceContext, type ConformanceOptions, SkipCase } from "./context.ts"; -export type { ConformanceCase } from "./cases/types"; -export { type ContentHashFixture, contentHashFixtures } from "./contentHashFixtures"; -export type { ConformanceOptions } from "./context"; +export type { ConformanceCase } from "./cases/types.ts"; +export { type ContentHashFixture, contentHashFixtures } from "./contentHashFixtures.ts"; +export type { ConformanceOptions } from "./context.ts"; /** Every conformance case, in the order they run. */ export const conformanceCases: readonly ConformanceCase[] = [ diff --git a/packages/blocks/src/protocol/index.ts b/packages/blocks/src/protocol/index.ts index 92517d98..41c755f0 100644 --- a/packages/blocks/src/protocol/index.ts +++ b/packages/blocks/src/protocol/index.ts @@ -24,7 +24,7 @@ export { canonicalJson, computeContentRevision, sha256Hex, -} from "./canonical"; +} from "./canonical.ts"; export { assertSupportedEndpoint, type BatchCall, @@ -32,8 +32,8 @@ export { type ContentClient, type ContentClientOptions, createContentClient, -} from "./client"; -export * from "./errors"; -export * from "./keys"; -export * from "./storage"; -export * from "./types"; +} from "./client.ts"; +export * from "./errors.ts"; +export * from "./keys.ts"; +export * from "./storage.ts"; +export * from "./types.ts"; diff --git a/packages/blocks/src/protocol/params.ts b/packages/blocks/src/protocol/params.ts index c0c693cf..69a64960 100644 --- a/packages/blocks/src/protocol/params.ts +++ b/packages/blocks/src/protocol/params.ts @@ -7,8 +7,8 @@ * parsed copy of a record would turn an own `__proto__` key into a prototype. */ import { z } from "zod"; -import { invalidParams } from "./errors"; -import type { BlocksApplyParams, MethodName, ReadParams } from "./types"; +import { invalidParams } from "./errors.ts"; +import type { BlocksApplyParams, MethodName, ReadParams } from "./types.ts"; const opaque = z.string().min(1).max(1024); diff --git a/packages/blocks/src/protocol/secrets.ts b/packages/blocks/src/protocol/secrets.ts index 8ff5cc50..a6f4a671 100644 --- a/packages/blocks/src/protocol/secrets.ts +++ b/packages/blocks/src/protocol/secrets.ts @@ -11,9 +11,9 @@ * The schema marks a `Secret` field with `"format": "secret"` — the contract * `deco schema` emits for the `Secret` type. Browser-safe. */ -import { parseCiphertext } from "./ciphertext"; -import type { BlockViolation } from "./errors"; -import type { DecoMeta } from "./types"; +import { parseCiphertext } from "./ciphertext.ts"; +import type { BlockViolation } from "./errors.ts"; +import type { DecoMeta } from "./types.ts"; /** The built-in block type that holds an encrypted value. */ export const SECRET_BLOCK_TYPE = "secret"; diff --git a/packages/blocks/src/protocol/server/assets.ts b/packages/blocks/src/protocol/server/assets.ts index 651c8505..494688a4 100644 --- a/packages/blocks/src/protocol/server/assets.ts +++ b/packages/blocks/src/protocol/server/assets.ts @@ -17,7 +17,7 @@ import { assetNameForType, isAcceptedAssetType, sanitizeAssetName, -} from "../assets"; +} from "../assets.ts"; import { type ContentProtocolError, ErrorCode, @@ -27,11 +27,11 @@ import { readOnly, unauthorized, unsupported, -} from "../errors"; -import type { ContentStorage } from "../storage"; -import { ASSETS_URL_PREFIX } from "../types"; -import { type AuthOptions, assertAuthOptions, authenticate } from "./auth"; -import { BodyEncodingError, BodyTooLargeError, jsonResponse, readBody } from "./http"; +} from "../errors.ts"; +import type { ContentStorage } from "../storage.ts"; +import { ASSETS_URL_PREFIX } from "../types.ts"; +import { type AuthOptions, assertAuthOptions, authenticate } from "./auth.ts"; +import { BodyEncodingError, BodyTooLargeError, jsonResponse, readBody } from "./http.ts"; const STATUS: Record = { [ErrorCode.Unauthorized]: 401, diff --git a/packages/blocks/src/protocol/server/auth.ts b/packages/blocks/src/protocol/server/auth.ts index 6a5242b5..94f6e870 100644 --- a/packages/blocks/src/protocol/server/auth.ts +++ b/packages/blocks/src/protocol/server/auth.ts @@ -1,7 +1,7 @@ /** * Request authorization shared by the content handler and the asset handler. */ -import { bearerToken, timingSafeEqualStrings } from "./http"; +import { bearerToken, timingSafeEqualStrings } from "./http.ts"; /** * What an `authorize` hook decides: diff --git a/packages/blocks/src/protocol/server/content.ts b/packages/blocks/src/protocol/server/content.ts index 4721f915..3bed20fe 100644 --- a/packages/blocks/src/protocol/server/content.ts +++ b/packages/blocks/src/protocol/server/content.ts @@ -4,11 +4,11 @@ * Shared by `blocks.list` (which needs every body) and `blocks.apply` (which * needs bodies only to break ties between spellings). */ -import { limitExceeded, unavailable } from "../errors"; -import { entryHasPath, fullyDecodeFileName, isBlockFileName, resolveSpellings } from "../keys"; -import type { ContentStorage, StorageFile, StorageSnapshot } from "../storage"; -import type { Diagnostic, Limits } from "../types"; -import { type BodyCache, type ParsedBody, parseBody } from "./bodyCache"; +import { limitExceeded, unavailable } from "../errors.ts"; +import { entryHasPath, fullyDecodeFileName, isBlockFileName, resolveSpellings } from "../keys.ts"; +import type { ContentStorage, StorageFile, StorageSnapshot } from "../storage.ts"; +import type { Diagnostic, Limits } from "../types.ts"; +import { type BodyCache, type ParsedBody, parseBody } from "./bodyCache.ts"; export interface LoadedEntry { file: string; diff --git a/packages/blocks/src/protocol/server/core.ts b/packages/blocks/src/protocol/server/core.ts index 8924897c..0d63e8a0 100644 --- a/packages/blocks/src/protocol/server/core.ts +++ b/packages/blocks/src/protocol/server/core.ts @@ -1,18 +1,24 @@ /** * The shared state of one content handler: its storage, options and caches. */ -import { ContentProtocolError, invalidBlock, notFound, unavailable, unsupported } from "../errors"; -import { blockNameFromFile } from "../keys"; +import { + ContentProtocolError, + invalidBlock, + notFound, + unavailable, + unsupported, +} from "../errors.ts"; +import { blockNameFromFile } from "../keys.ts"; import { type ContentStorage, type StorageDescription, StorageInvalidFileError, StorageNotFoundError, StorageUnavailableError, -} from "../storage"; -import { DEFAULT_LIMITS, type DecoMeta, type Limits } from "../types"; -import type { AuthOptions } from "./auth"; -import { BodyCache } from "./bodyCache"; +} from "../storage.ts"; +import { DEFAULT_LIMITS, type DecoMeta, type Limits } from "../types.ts"; +import type { AuthOptions } from "./auth.ts"; +import { BodyCache } from "./bodyCache.ts"; export interface ContentHandlerOptions extends AuthOptions { /** Reported by `describe`, such as `{ name: "deco-cli", version: "8.0.0" }`. */ diff --git a/packages/blocks/src/protocol/server/handler.ts b/packages/blocks/src/protocol/server/handler.ts index 861ec542..dabec8eb 100644 --- a/packages/blocks/src/protocol/server/handler.ts +++ b/packages/blocks/src/protocol/server/handler.ts @@ -23,18 +23,18 @@ import { limitExceeded, parseError, unauthorized, -} from "../errors"; -import type { ContentStorage } from "../storage"; -import { assertAuthOptions, authenticate } from "./auth"; -import { type ContentHandlerOptions, Core } from "./core"; +} from "../errors.ts"; +import type { ContentStorage } from "../storage.ts"; +import { assertAuthOptions, authenticate } from "./auth.ts"; +import { type ContentHandlerOptions, Core } from "./core.ts"; import { BodyEncodingError, BodyTooLargeError, isJsonContentType, jsonResponse, readBody, -} from "./http"; -import { dispatch } from "./rpc"; +} from "./http.ts"; +import { dispatch } from "./rpc.ts"; export type ContentHandler = (request: Request) => Promise; diff --git a/packages/blocks/src/protocol/server/http.ts b/packages/blocks/src/protocol/server/http.ts index c59c5e9d..972f62ef 100644 --- a/packages/blocks/src/protocol/server/http.ts +++ b/packages/blocks/src/protocol/server/http.ts @@ -4,7 +4,7 @@ * only (Request, Response, CompressionStream), so it runs on Node, Bun, * Workers and Deno. */ -import { sha256Hex } from "../canonical"; +import { sha256Hex } from "../canonical.ts"; /** The body was larger than allowed (after decompression). */ export class BodyTooLargeError extends Error { diff --git a/packages/blocks/src/protocol/server/index.ts b/packages/blocks/src/protocol/server/index.ts index ad0cf3af..79604616 100644 --- a/packages/blocks/src/protocol/server/index.ts +++ b/packages/blocks/src/protocol/server/index.ts @@ -6,6 +6,6 @@ * and Deno. (`deco serve`'s asset uploads use `./assets`, which isn't public.) */ -export type { AuthOptions, AuthorizeResult } from "./auth"; -export type { ContentHandlerOptions } from "./core"; -export { type ContentHandler, createContentHandler } from "./handler"; +export type { AuthOptions, AuthorizeResult } from "./auth.ts"; +export type { ContentHandlerOptions } from "./core.ts"; +export { type ContentHandler, createContentHandler } from "./handler.ts"; diff --git a/packages/blocks/src/protocol/server/methods/apply.ts b/packages/blocks/src/protocol/server/methods/apply.ts index 49768c7d..90265d08 100644 --- a/packages/blocks/src/protocol/server/methods/apply.ts +++ b/packages/blocks/src/protocol/server/methods/apply.ts @@ -18,7 +18,7 @@ * key reserved meanwhile) is retried against a new snapshot after a jittered * backoff, rechecking every guard, up to `maxCommitAttempts` times. */ -import { applyRequestDigest, canonicalJson } from "../../canonical"; +import { applyRequestDigest, canonicalJson } from "../../canonical.ts"; import { type BlockViolation, conflict, @@ -29,7 +29,7 @@ import { unavailable, unsupported, type VersionMismatch, -} from "../../errors"; +} from "../../errors.ts"; import { blockFileName, blockNameFromFile, @@ -39,13 +39,13 @@ import { isBlockFileName, serializeBlock, spellingKey, -} from "../../keys"; -import { checkSecrets } from "../../secrets"; -import type { StorageDescription, StoredReceipt } from "../../storage"; -import type { BlocksApplyParams, BlocksApplyResult, DecoMeta, Limits } from "../../types"; -import { type LoadedContent, type LoadedEntry, loadCurrentContent } from "../content"; -import type { Core } from "../core"; -import { parseSchema, readSchema } from "./read"; +} from "../../keys.ts"; +import { checkSecrets } from "../../secrets.ts"; +import type { StorageDescription, StoredReceipt } from "../../storage.ts"; +import type { BlocksApplyParams, BlocksApplyResult, DecoMeta, Limits } from "../../types.ts"; +import { type LoadedContent, type LoadedEntry, loadCurrentContent } from "../content.ts"; +import type { Core } from "../core.ts"; +import { parseSchema, readSchema } from "./read.ts"; const utf8 = new TextEncoder(); diff --git a/packages/blocks/src/protocol/server/methods/read.ts b/packages/blocks/src/protocol/server/methods/read.ts index d512d1b6..578990e5 100644 --- a/packages/blocks/src/protocol/server/methods/read.ts +++ b/packages/blocks/src/protocol/server/methods/read.ts @@ -1,8 +1,8 @@ /** * The three read methods: `describe`, `schema.get` and `blocks.list`. */ -import { publicKeyDerFromPem } from "../../ciphertext"; -import { limitExceeded, notFound, unavailable } from "../../errors"; +import { publicKeyDerFromPem } from "../../ciphertext.ts"; +import { limitExceeded, notFound, unavailable } from "../../errors.ts"; import { ASSETS_URL_PREFIX, type BlocksListResult, @@ -13,9 +13,9 @@ import { type ReadParams, SCHEMA_FORMAT, type SchemaGetResult, -} from "../../types"; -import { loadCurrentContent } from "../content"; -import type { Core } from "../core"; +} from "../../types.ts"; +import { loadCurrentContent } from "../content.ts"; +import type { Core } from "../core.ts"; const DEFAULT_SERVER = { name: "deco-blocks", version: "unknown" }; diff --git a/packages/blocks/src/protocol/server/rpc.ts b/packages/blocks/src/protocol/server/rpc.ts index 57b5ad80..e99feaf3 100644 --- a/packages/blocks/src/protocol/server/rpc.ts +++ b/packages/blocks/src/protocol/server/rpc.ts @@ -15,12 +15,12 @@ import { invalidRequest, limitExceeded, methodNotFound, -} from "../errors"; -import { validateParams } from "../params"; -import { MAX_BATCH_CALLS, METHOD_NAMES, type MethodName, type RpcId } from "../types"; -import { type Core, toProtocolError } from "./core"; -import { blocksApply } from "./methods/apply"; -import { blocksList, describe, schemaGet } from "./methods/read"; +} from "../errors.ts"; +import { validateParams } from "../params.ts"; +import { MAX_BATCH_CALLS, METHOD_NAMES, type MethodName, type RpcId } from "../types.ts"; +import { type Core, toProtocolError } from "./core.ts"; +import { blocksApply } from "./methods/apply.ts"; +import { blocksList, describe, schemaGet } from "./methods/read.ts"; const utf8 = new TextEncoder(); diff --git a/packages/blocks/src/protocol/storage.ts b/packages/blocks/src/protocol/storage.ts index 571a0ca1..ce89c4de 100644 --- a/packages/blocks/src/protocol/storage.ts +++ b/packages/blocks/src/protocol/storage.ts @@ -10,7 +10,7 @@ * * Browser-safe: types and small error classes only. */ -import type { Limits, StorageKind } from "./types"; +import type { Limits, StorageKind } from "./types.ts"; /** What a storage tells `describe`. */ export interface StorageDescription { diff --git a/packages/blocks/src/protocol/storage/fs/index.ts b/packages/blocks/src/protocol/storage/fs/index.ts index 14cf6c4e..56264fc8 100644 --- a/packages/blocks/src/protocol/storage/fs/index.ts +++ b/packages/blocks/src/protocol/storage/fs/index.ts @@ -21,8 +21,8 @@ */ import { lstat, mkdir, open, readdir, readFile, stat } from "node:fs/promises"; import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path"; -import { suffixedAssetName } from "../../assets"; -import { isBlockFileName } from "../../keys"; +import { suffixedAssetName } from "../../assets.ts"; +import { isBlockFileName } from "../../keys.ts"; import { type CommitResult, type ContentStorage, @@ -34,11 +34,11 @@ import { StorageUnavailableError, type StoredFileBody, type StoredSchema, -} from "../../storage"; -import type { Limits } from "../../types"; -import { gitBlobHash, revisionOf } from "./hash"; -import { withCommitLock } from "./lock"; -import { applyFileChange, sweepStaleTransactions } from "./transaction"; +} from "../../storage.ts"; +import type { Limits } from "../../types.ts"; +import { gitBlobHash, revisionOf } from "./hash.ts"; +import { withCommitLock } from "./lock.ts"; +import { applyFileChange, sweepStaleTransactions } from "./transaction.ts"; export interface FsStorageOptions { /** The app root: the folder that contains `.deco/`. */ diff --git a/packages/blocks/src/protocol/storage/fs/lock.ts b/packages/blocks/src/protocol/storage/fs/lock.ts index 616cd1a1..21db002f 100644 --- a/packages/blocks/src/protocol/storage/fs/lock.ts +++ b/packages/blocks/src/protocol/storage/fs/lock.ts @@ -5,7 +5,7 @@ */ import { open, rm, stat } from "node:fs/promises"; import { join } from "node:path"; -import { StorageUnavailableError } from "../../storage"; +import { StorageUnavailableError } from "../../storage.ts"; const LOCK_FILE = ".blocks.lock"; const queues = new Map>(); diff --git a/packages/blocks/src/protocol/storage/fs/unsupported.ts b/packages/blocks/src/protocol/storage/fs/unsupported.ts index dc03acb4..95ae1593 100644 --- a/packages/blocks/src/protocol/storage/fs/unsupported.ts +++ b/packages/blocks/src/protocol/storage/fs/unsupported.ts @@ -4,9 +4,9 @@ * filesystem storage needs `node:fs`; on Workers or in a browser, implement * `ContentStorage` over the storage you have instead. */ -import type { createFsStorage as nodeCreateFsStorage } from "./index"; +import type { createFsStorage as nodeCreateFsStorage } from "./index.ts"; -export type { FsStorage, FsStorageOptions } from "./index"; +export type { FsStorage, FsStorageOptions } from "./index.ts"; export const createFsStorage: typeof nodeCreateFsStorage = () => { throw new Error( diff --git a/packages/blocks/src/protocol/storage/memory.ts b/packages/blocks/src/protocol/storage/memory.ts index 9403192b..609eac8b 100644 --- a/packages/blocks/src/protocol/storage/memory.ts +++ b/packages/blocks/src/protocol/storage/memory.ts @@ -6,9 +6,9 @@ * for tests: its state can be dumped and restored to simulate a restart, and * hooks let a test change files between a snapshot and a commit. Browser-safe. */ -import { suffixedAssetName } from "../assets"; -import { sha256Hex } from "../canonical"; -import { isBlockFileName } from "../keys"; +import { suffixedAssetName } from "../assets.ts"; +import { sha256Hex } from "../canonical.ts"; +import { isBlockFileName } from "../keys.ts"; import { type CommitAttempt, type CommitResult, @@ -20,7 +20,7 @@ import { type StoredFileBody, type StoredReceipt, type StoredSchema, -} from "../storage"; +} from "../storage.ts"; const DAY_MS = 24 * 60 * 60 * 1000; diff --git a/packages/blocks/src/v8/__conformance__/cli.test.ts b/packages/blocks/src/v8/__conformance__/cli.test.ts index e0909903..f05bd4b7 100644 --- a/packages/blocks/src/v8/__conformance__/cli.test.ts +++ b/packages/blocks/src/v8/__conformance__/cli.test.ts @@ -372,7 +372,11 @@ describe("cli.mdx", () => { it("cli-02: the CLI is importable from @decocms/blocks/cli", async () => { const pkg = JSON.parse(fs.readFileSync(path.join(PKG, "package.json"), "utf8")); - expect(pkg.exports["./cli"]).toBe("./src/v8/cli/index.ts"); + expect(pkg.exports["./cli"]).toEqual({ + types: "./dist/v8/cli/index.d.ts", + source: "./src/v8/cli/index.ts", + default: "./dist/v8/cli/index.js", + }); const cli = await import("@decocms/blocks/cli"); const f = fixture({ ".deco/blocks/A.json": { __resolveType: "hero", title: "x" } }); const code = await cli.runCli(["content"], { cwd: f.root, reporter: cli.silentReporter }); @@ -1830,9 +1834,9 @@ describe("content-protocol.mdx", () => { it("cp-40: deco content, deco serve and the fs storage import the protocol's keys", () => { const read = (p: string) => fs.readFileSync(path.join(PKG, "src", p), "utf8"); - expect(read("v8/cli/content.ts")).toMatch(/from "\.\.\/\.\.\/protocol\/keys"/); - expect(read("v8/cli/serve/server.ts")).toMatch(/protocol\/keys"/); - expect(read("protocol/storage/fs/index.ts")).toMatch(/from "\.\.\/\.\.\/keys"/); + expect(read("v8/cli/content.ts")).toMatch(/from "\.\.\/\.\.\/protocol\/keys\.ts"/); + expect(read("v8/cli/serve/server.ts")).toMatch(/protocol\/keys\.ts"/); + expect(read("protocol/storage/fs/index.ts")).toMatch(/from "\.\.\/\.\.\/keys\.ts"/); }); it("cp-43: Host must be the server's own loopback address", async () => { @@ -1897,7 +1901,9 @@ describe("content-protocol.mdx", () => { for (const m of src.matchAll(/(?:^|[\s}])from\s+"([^"]+)"|import\(\s*"([^"]+)"/gm)) { const spec = m[1] ?? m[2]; if (spec.startsWith(".")) { - const target = path.resolve(path.dirname(path.join(PKG, "src/protocol", f)), spec); + const target = path + .resolve(path.dirname(path.join(PKG, "src/protocol", f)), spec) + .replace(/\.tsx?$/, ""); // The canonical hash and the ciphertext format are the SDK's own // dependency-free leaf modules (no imports at all); the protocol // re-exports them rather than keep a second copy. @@ -2235,7 +2241,7 @@ describe("studio-implementation.mdx", () => { expect(await computeContentRevision(fx.blocks)).toBe(fx.revision ?? fx.hash); } const content = fs.readFileSync(path.join(PKG, "src/v8/cli/content.ts"), "utf8"); - expect(content).toMatch(/protocol\/canonical"/); + expect(content).toMatch(/protocol\/canonical\.ts"/); }); it("si-07: the local poll interval is 2 seconds", async () => { diff --git a/packages/blocks/src/v8/__conformance__/delivery.test.ts b/packages/blocks/src/v8/__conformance__/delivery.test.ts index b862a9a0..0f0f7066 100644 --- a/packages/blocks/src/v8/__conformance__/delivery.test.ts +++ b/packages/blocks/src/v8/__conformance__/delivery.test.ts @@ -182,7 +182,7 @@ describe("content-delivery", () => { const sdk = fs.readFileSync(path.join(HERE, "../remoteLoader.ts"), "utf8"); const shared = // remoteLoader imports the SDK's leaf module; the CLI may go through the protocol's re-export. - /import \{[^}]*\bcomputeContentRevision\b[^}]*\} from "[./]+(protocol\/)?canonical"/; + /import \{[^}]*\bcomputeContentRevision\b[^}]*\} from "[./]+(protocol\/)?canonical\.ts"/; expect(cli).toMatch(shared); expect(sdk).toMatch(shared); }); diff --git a/packages/blocks/src/v8/__conformance__/sdk.test.ts b/packages/blocks/src/v8/__conformance__/sdk.test.ts index f85bf0c0..8e844b47 100644 --- a/packages/blocks/src/v8/__conformance__/sdk.test.ts +++ b/packages/blocks/src/v8/__conformance__/sdk.test.ts @@ -151,7 +151,7 @@ describe("AR-01 the root exports exactly the documented v8 surface", () => { }); it("the root's v8 block re-exports only documented names (no extra types)", () => { - const names = exportedNames(readSource("src/index.ts"), "./v8/index"); + const names = exportedNames(readSource("src/index.ts"), "./v8/index.ts"); expect(names).toEqual([...DOCUMENTED_ROOT_VALUES, ...DOCUMENTED_ROOT_TYPES].sort()); }); }); @@ -159,9 +159,13 @@ describe("AR-01 the root exports exactly the documented v8 surface", () => { describe("AR-02 fetch, analytics and secrets live on their own subpaths", () => { it("package.json maps the subpaths to the v8 modules", () => { const pkg = JSON.parse(readSource("package.json")); - expect(pkg.exports["./fetch"]).toBe("./src/v8/fetch.ts"); - expect(pkg.exports["./analytics"]).toBe("./src/v8/analytics.ts"); - expect(pkg.exports["./secrets"]).toBe("./src/v8/secrets.ts"); + for (const name of ["fetch", "analytics", "secrets"]) { + expect(pkg.exports[`./${name}`]).toEqual({ + types: `./dist/v8/${name}.d.ts`, + source: `./src/v8/${name}.ts`, + default: `./dist/v8/${name}.js`, + }); + } }); it("each subpath exports exactly the documented runtime names", () => { diff --git a/packages/blocks/src/v8/analytics.ts b/packages/blocks/src/v8/analytics.ts index 7df679ff..dbca4a07 100644 --- a/packages/blocks/src/v8/analytics.ts +++ b/packages/blocks/src/v8/analytics.ts @@ -17,8 +17,8 @@ * `navigator.sendBeacon` or a `POST`. */ import { createElement, type ReactNode } from "react"; -import { HOSTED_ANALYTICS_COLLECTOR } from "./builtins/data"; -import type { Analytics } from "./types"; +import { HOSTED_ANALYTICS_COLLECTOR } from "./builtins/data.ts"; +import type { Analytics } from "./types.ts"; const GLOBAL = "__decoAnalytics"; diff --git a/packages/blocks/src/v8/builtins/data.ts b/packages/blocks/src/v8/builtins/data.ts index 15d24426..3082f4f5 100644 --- a/packages/blocks/src/v8/builtins/data.ts +++ b/packages/blocks/src/v8/builtins/data.ts @@ -1,4 +1,4 @@ -import type { Analytics, Redirect, Telemetry } from "../types"; +import type { Analytics, Redirect, Telemetry } from "../types.ts"; /** The hosted Deco CMS collector: where page views go when `collector` is left out. */ export const HOSTED_ANALYTICS_COLLECTOR = "https://d.lilstts.com/events"; diff --git a/packages/blocks/src/v8/builtins/index.ts b/packages/blocks/src/v8/builtins/index.ts index 686fe98e..4841945c 100644 --- a/packages/blocks/src/v8/builtins/index.ts +++ b/packages/blocks/src/v8/builtins/index.ts @@ -1,9 +1,9 @@ -import type { BlockFunction } from "../types"; -import { analytics, page, redirect, telemetry } from "./data"; -import { lazy } from "./lazy"; -import { always, date, never } from "./matchers"; -import { multivariate } from "./multivariate"; -import { secretBlock } from "./secret"; +import type { BlockFunction } from "../types.ts"; +import { analytics, page, redirect, telemetry } from "./data.ts"; +import { lazy } from "./lazy.ts"; +import { always, date, never } from "./matchers.ts"; +import { multivariate } from "./multivariate.ts"; +import { secretBlock } from "./secret.ts"; /** * The built-in blocks every block map gets. `secret` here has no key, so it diff --git a/packages/blocks/src/v8/builtins/lazy.ts b/packages/blocks/src/v8/builtins/lazy.ts index 7ae40762..f00406eb 100644 --- a/packages/blocks/src/v8/builtins/lazy.ts +++ b/packages/blocks/src/v8/builtins/lazy.ts @@ -1,4 +1,4 @@ -import type { Lazy } from "../types"; +import type { Lazy } from "../types.ts"; /** Marks the built-in `lazy` function, the resolver's one special case. */ const LAZY_BLOCK: unique symbol = Symbol.for("decocms.blocks.v8.lazy"); diff --git a/packages/blocks/src/v8/builtins/legacy.ts b/packages/blocks/src/v8/builtins/legacy.ts index 8cb470d0..1595549b 100644 --- a/packages/blocks/src/v8/builtins/legacy.ts +++ b/packages/blocks/src/v8/builtins/legacy.ts @@ -16,7 +16,7 @@ * - Legacy variants are saved as plain values; on the way to `multivariate` * each one is wrapped in a `lazy` block, so only the chosen one runs. */ -import { isPlainObject, type JsonObject } from "../json"; +import { isPlainObject, type JsonObject } from "../json.ts"; /** * Legacy type name → built-in. The one table: the runtime falls back to it, diff --git a/packages/blocks/src/v8/builtins/multivariate.ts b/packages/blocks/src/v8/builtins/multivariate.ts index 9dae249d..e7fb6ee9 100644 --- a/packages/blocks/src/v8/builtins/multivariate.ts +++ b/packages/blocks/src/v8/builtins/multivariate.ts @@ -1,4 +1,4 @@ -import type { Variant } from "../types"; +import type { Variant } from "../types.ts"; interface MultivariateProps { variants?: Variant[]; diff --git a/packages/blocks/src/v8/builtins/secret.ts b/packages/blocks/src/v8/builtins/secret.ts index b42c067d..adb26c06 100644 --- a/packages/blocks/src/v8/builtins/secret.ts +++ b/packages/blocks/src/v8/builtins/secret.ts @@ -17,8 +17,8 @@ * telemetry). A decrypted value stays on the server because it's resolved * there; tainting it (React's taint API) is up to the site's own code. */ -import { parseCiphertext } from "../ciphertext"; -import type { BlockFunction } from "../types"; +import { parseCiphertext } from "../ciphertext.ts"; +import type { BlockFunction } from "../types.ts"; /** True in a browser, where a secret must never be decrypted. */ function inBrowser(): boolean { diff --git a/packages/blocks/src/v8/cli/builtins.ts b/packages/blocks/src/v8/cli/builtins.ts index c6dbb194..bd22f17a 100644 --- a/packages/blocks/src/v8/cli/builtins.ts +++ b/packages/blocks/src/v8/cli/builtins.ts @@ -2,7 +2,7 @@ * Names the CLI knows without reading any code: the built-in blocks (the * core's reserved names) and the legacy alias table. */ -import { RESERVED_NAMES } from "../builtins"; +import { RESERVED_NAMES } from "../builtins/index.ts"; /** Spec: built-in-blocks. Every block map gets these, in this order. */ export const BUILT_IN_BLOCKS: readonly string[] = [...RESERVED_NAMES]; @@ -17,4 +17,4 @@ export function isBuiltIn(name: string): boolean { * editor's special screens still look types up by these names (spec: * studio-compatibility › Well-known types and the alias table). */ -export { LEGACY_ALIASES, storesPlainVariants } from "../builtins/legacy"; +export { LEGACY_ALIASES, storesPlainVariants } from "../builtins/legacy.ts"; diff --git a/packages/blocks/src/v8/cli/check/index.ts b/packages/blocks/src/v8/cli/check/index.ts index f2d52396..69cbc80a 100644 --- a/packages/blocks/src/v8/cli/check/index.ts +++ b/packages/blocks/src/v8/cli/check/index.ts @@ -18,17 +18,17 @@ */ import fs from "node:fs"; -import Ajv, { type ValidateFunction } from "ajv"; -import { isWellFormedCiphertext } from "../../../protocol/secrets"; -import { isBlock, own } from "../../json"; -import { findRouteConflicts } from "../../matchRoute"; -import { isBuiltIn, storesPlainVariants } from "../builtins"; -import { readSavedBlocks, type SavedBlocks } from "../content"; -import { consoleReporter, type Reporter } from "../log"; -import { CliError, decoPaths, findDecoRoot } from "../root"; -import type { DecoMeta } from "../schema/generate"; -import { SECTION_REF_KEY, toBase64 } from "../schema/typeToSchema"; -import { BLOCK_DEF, joinPath, rewriteErrors } from "./messages"; +import { Ajv, type ValidateFunction } from "ajv"; +import { isWellFormedCiphertext } from "../../../protocol/secrets.ts"; +import { isBlock, own } from "../../json.ts"; +import { findRouteConflicts } from "../../matchRoute.ts"; +import { isBuiltIn, storesPlainVariants } from "../builtins.ts"; +import { readSavedBlocks, type SavedBlocks } from "../content.ts"; +import { consoleReporter, type Reporter } from "../log.ts"; +import { CliError, decoPaths, findDecoRoot } from "../root.ts"; +import type { DecoMeta } from "../schema/generate.ts"; +import { SECTION_REF_KEY, toBase64 } from "../schema/typeToSchema.ts"; +import { BLOCK_DEF, joinPath, rewriteErrors } from "./messages.ts"; export interface Problem { /** The saved block's file, relative to the root: `.deco/blocks/HomePage.json`. */ diff --git a/packages/blocks/src/v8/cli/content.ts b/packages/blocks/src/v8/cli/content.ts index b992752a..f5b875ef 100644 --- a/packages/blocks/src/v8/cli/content.ts +++ b/packages/blocks/src/v8/cli/content.ts @@ -5,7 +5,7 @@ */ import fs from "node:fs"; import path from "node:path"; -import { computeContentRevision } from "../../protocol/canonical"; +import { computeContentRevision } from "../../protocol/canonical.ts"; import { blockNameFromFile, checkBlockName, @@ -13,11 +13,11 @@ import { isBlockFileName, resolveSpellings, type SpellingCandidate, -} from "../../protocol/keys"; -import { isPlainObject } from "../json"; -import { LEGACY_ALIASES } from "./builtins"; -import { consoleReporter, type Reporter } from "./log"; -import { CliError, type DecoPaths, decoPaths, findDecoRoot } from "./root"; +} from "../../protocol/keys.ts"; +import { isPlainObject } from "../json.ts"; +import { LEGACY_ALIASES } from "./builtins.ts"; +import { consoleReporter, type Reporter } from "./log.ts"; +import { CliError, type DecoPaths, decoPaths, findDecoRoot } from "./root.ts"; export interface ContentDiagnostic { /** The file name inside `.deco/blocks`. */ diff --git a/packages/blocks/src/v8/cli/index.ts b/packages/blocks/src/v8/cli/index.ts index c2c3db36..3d8116d1 100644 --- a/packages/blocks/src/v8/cli/index.ts +++ b/packages/blocks/src/v8/cli/index.ts @@ -8,10 +8,10 @@ * (the `deco-v7-to-v8-migration` skill) reads: the built-in block names, the alias * table and the saved-blocks reader. */ -export { BUILT_IN_BLOCKS, LEGACY_ALIASES } from "./builtins"; -export { type CheckOptions, check } from "./check/index"; -export { type ContentOptions, content, readSavedBlocks, type SavedBlocks } from "./content"; -export { type Reporter, silentReporter } from "./log"; -export { runCli } from "./run"; -export { type SchemaOptions, schema } from "./schema/index"; -export { type ServeOptions, serve } from "./serve/server"; +export { BUILT_IN_BLOCKS, LEGACY_ALIASES } from "./builtins.ts"; +export { type CheckOptions, check } from "./check/index.ts"; +export { type ContentOptions, content, readSavedBlocks, type SavedBlocks } from "./content.ts"; +export { type Reporter, silentReporter } from "./log.ts"; +export { runCli } from "./run.ts"; +export { type SchemaOptions, schema } from "./schema/index.ts"; +export { type ServeOptions, serve } from "./serve/server.ts"; diff --git a/packages/blocks/src/v8/cli/main.ts b/packages/blocks/src/v8/cli/main.ts index bab0c1e8..bab5e2e3 100644 --- a/packages/blocks/src/v8/cli/main.ts +++ b/packages/blocks/src/v8/cli/main.ts @@ -1,5 +1,5 @@ /** The `deco` bin's entry: run the command line, then exit with its code. */ -import { runCli } from "./run"; +import { runCli } from "./run.ts"; runCli(process.argv.slice(2)).then( (code) => { diff --git a/packages/blocks/src/v8/cli/run.test.ts b/packages/blocks/src/v8/cli/run.test.ts index 26e8b6e0..42b80ec7 100644 --- a/packages/blocks/src/v8/cli/run.test.ts +++ b/packages/blocks/src/v8/cli/run.test.ts @@ -179,7 +179,7 @@ describe("runCli", () => { }); describe("the bin", () => { - it("runs under plain Node, through tsx", () => { + it("runs under plain Node, from the compiled dist/", () => { fixture = createFixture(); fixture.write(".deco/blocks/A.json", hero); const result = spawnSync(process.execPath, [path.join(packageRoot, "bin/deco.js"), "content"], { @@ -204,13 +204,17 @@ describe("the bin", () => { it("is the package's single bin, and the commands are the ./cli subpath", () => { const pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf8")); expect(pkg.bin).toEqual({ deco: "./bin/deco.js" }); - expect(pkg.exports["./cli"]).toBe("./src/v8/cli/index.ts"); + expect(pkg.exports["./cli"]).toEqual({ + types: "./dist/v8/cli/index.d.ts", + source: "./src/v8/cli/index.ts", + default: "./dist/v8/cli/index.js", + }); expect(pkg.peerDependencies.typescript).toBeDefined(); // The compiler is the app's peer, not one bundled into a dependency. expect(pkg.dependencies["ts-morph"]).toBeUndefined(); // Tests and their fixtures stay out of the published package. expect(pkg.files).toEqual( - expect.arrayContaining(["bin", "src", "!src/**/*.test.ts", "!src/**/__tests__"]), + expect.arrayContaining(["bin", "dist", "src", "!src/**/*.test.ts", "!src/**/__tests__"]), ); }); diff --git a/packages/blocks/src/v8/cli/run.ts b/packages/blocks/src/v8/cli/run.ts index 4f0d17d3..18ff61c9 100644 --- a/packages/blocks/src/v8/cli/run.ts +++ b/packages/blocks/src/v8/cli/run.ts @@ -2,13 +2,13 @@ * The `deco` command line: `deco [flags]` * (spec: cli). Parses flags, runs one command and returns its exit code. */ -import { check } from "./check/index"; -import { content, writeContent } from "./content"; -import { consoleReporter, type Reporter } from "./log"; -import { CliError, decoPaths, findDecoRoot } from "./root"; -import { reportSchema, schema, writeSchema } from "./schema/index"; -import { serve, startServer } from "./serve/server"; -import { watchFiles, watchTree } from "./watch"; +import { check } from "./check/index.ts"; +import { content, writeContent } from "./content.ts"; +import { consoleReporter, type Reporter } from "./log.ts"; +import { CliError, decoPaths, findDecoRoot } from "./root.ts"; +import { reportSchema, schema, writeSchema } from "./schema/index.ts"; +import { serve, startServer } from "./serve/server.ts"; +import { watchFiles, watchTree } from "./watch.ts"; type FlagKind = "string" | "boolean" | "list"; diff --git a/packages/blocks/src/v8/cli/schema/builtinSchemas.ts b/packages/blocks/src/v8/cli/schema/builtinSchemas.ts index 98c500bf..2274cd08 100644 --- a/packages/blocks/src/v8/cli/schema/builtinSchemas.ts +++ b/packages/blocks/src/v8/cli/schema/builtinSchemas.ts @@ -3,7 +3,7 @@ * in api-reference › Types). They're always in the schema, unless the block * map declares the same key, which replaces the built-in. */ -import { lazySchema, resolvableRef, sectionRef } from "./typeToSchema"; +import { lazySchema, resolvableRef, sectionRef } from "./typeToSchema.ts"; export type ManifestGroup = "sections" | "matchers" | "loaders" | "pages" | "redirects" | "content"; diff --git a/packages/blocks/src/v8/cli/schema/generate.ts b/packages/blocks/src/v8/cli/schema/generate.ts index 6803628d..895a85e6 100644 --- a/packages/blocks/src/v8/cli/schema/generate.ts +++ b/packages/blocks/src/v8/cli/schema/generate.ts @@ -12,17 +12,17 @@ */ import fs from "node:fs"; import path from "node:path"; -import { SCHEMA_FORMAT } from "../../../protocol/types"; -import { BUILT_IN_BLOCKS, LEGACY_ALIASES } from "../builtins"; -import { CliError, type DecoPaths, packageVersion } from "../root"; +import { SCHEMA_FORMAT } from "../../../protocol/types.ts"; +import { BUILT_IN_BLOCKS, LEGACY_ALIASES } from "../builtins.ts"; +import { CliError, type DecoPaths, packageVersion } from "../root.ts"; import { BUILT_IN_GROUPS, builtInDefinition, flatDefinition, legacyMultivariateValue, type ManifestGroup, -} from "./builtinSchemas"; -import { createTsProject, type TsNode as Node, type TsType as Type } from "./tsProgram"; +} from "./builtinSchemas.ts"; +import { createTsProject, type TsNode as Node, type TsType as Type } from "./tsProgram.ts"; import { awaitedOf, getJsDocTags, @@ -35,7 +35,7 @@ import { stableFileId, toBase64, typeToJsonSchema, -} from "./typeToSchema"; +} from "./typeToSchema.ts"; const MANIFEST_GROUPS: ManifestGroup[] = [ "sections", diff --git a/packages/blocks/src/v8/cli/schema/index.ts b/packages/blocks/src/v8/cli/schema/index.ts index 74740e18..a57cd93e 100644 --- a/packages/blocks/src/v8/cli/schema/index.ts +++ b/packages/blocks/src/v8/cli/schema/index.ts @@ -1,8 +1,8 @@ import path from "node:path"; -import { writeIfChanged } from "../content"; -import { consoleReporter, type Reporter } from "../log"; -import { CliError, type DecoPaths, decoPaths, findDecoRoot } from "../root"; -import { generateSchema, type SchemaResult } from "./generate"; +import { writeIfChanged } from "../content.ts"; +import { consoleReporter, type Reporter } from "../log.ts"; +import { CliError, type DecoPaths, decoPaths, findDecoRoot } from "../root.ts"; +import { generateSchema, type SchemaResult } from "./generate.ts"; export interface SchemaOptions { root?: string; diff --git a/packages/blocks/src/v8/cli/schema/schema.test.ts b/packages/blocks/src/v8/cli/schema/schema.test.ts index 83342ced..04210ee1 100644 --- a/packages/blocks/src/v8/cli/schema/schema.test.ts +++ b/packages/blocks/src/v8/cli/schema/schema.test.ts @@ -6,7 +6,7 @@ import { LEGACY_ALIASES } from "../builtins"; import { CliError, decoPaths } from "../root"; import { type DecoMeta, generateSchema, type SchemaDiagnostic } from "./generate"; import { schema, writeSchema } from "./index"; -import { toBase64 } from "./typeToSchema"; +import { stableFileId, toBase64 } from "./typeToSchema"; const b64 = toBase64; const ref = (key: string) => ({ $ref: `#/definitions/${b64(key)}` }); @@ -480,3 +480,31 @@ describe("errors and warnings", () => { expect(out.text()).toMatch(/schema\.gen\.json from index\.ts \(\d+ sections/); }, 30_000); }); + +describe("stableFileId", () => { + it("names a package's compiled .d.ts after its source, so dist and the source condition agree", () => { + const f = createFixture(); + try { + const pkg = "node_modules/@acme/kit"; + f.write(`${pkg}/package.json`, { name: "@acme/kit" }); + f.write(`${pkg}/dist/v8/types.d.ts`, "export interface Seo { title: string }\n"); + f.write( + `${pkg}/dist/v8/types.d.ts.map`, + JSON.stringify({ version: 3, file: "types.d.ts", sources: ["../../src/v8/types.ts"] }), + ); + f.write(`${pkg}/dist/v8/plain.d.ts`, "export {};\n"); + expect(stableFileId(`${f.root}/${pkg}/dist/v8/types.d.ts`, f.root)).toBe( + "@acme/kit/src/v8/types.ts", + ); + expect(stableFileId(`${f.root}/${pkg}/src/v8/types.ts`, f.root)).toBe( + "@acme/kit/src/v8/types.ts", + ); + // No declaration map: the file keeps its own name. + expect(stableFileId(`${f.root}/${pkg}/dist/v8/plain.d.ts`, f.root)).toBe( + "@acme/kit/dist/v8/plain.d.ts", + ); + } finally { + f.remove(); + } + }); +}); diff --git a/packages/blocks/src/v8/cli/schema/tsProgram.ts b/packages/blocks/src/v8/cli/schema/tsProgram.ts index b29ef4f8..511582ad 100644 --- a/packages/blocks/src/v8/cli/schema/tsProgram.ts +++ b/packages/blocks/src/v8/cli/schema/tsProgram.ts @@ -17,7 +17,7 @@ import fs from "node:fs"; import path from "node:path"; import type * as TS from "typescript"; -import { CliError } from "../root"; +import { CliError } from "../root.ts"; type TypeScript = typeof TS; diff --git a/packages/blocks/src/v8/cli/schema/typeToSchema.ts b/packages/blocks/src/v8/cli/schema/typeToSchema.ts index 39829a7e..812ab57d 100644 --- a/packages/blocks/src/v8/cli/schema/typeToSchema.ts +++ b/packages/blocks/src/v8/cli/schema/typeToSchema.ts @@ -23,7 +23,7 @@ import fs from "node:fs"; import path from "node:path"; -import type { TsSymbol as MorphSymbol, TsType as Type } from "./tsProgram"; +import type { TsSymbol as MorphSymbol, TsType as Type } from "./tsProgram.ts"; export const RESOLVABLE_KEY = "Resolvable"; export const SECTION_REF_KEY = "__SECTION_REF__"; @@ -662,9 +662,14 @@ export function typeToJsonSchema( * A machine-independent id for a source file: relative to the app root, or * `/` for a file in a dependency (including a * workspace package the checker reached through a symlink). + * + * A declaration file with a declaration map (`x.d.ts` + `x.d.ts.map`, as + * `tsc` emits into a package's dist/) is named after the source it was + * compiled from, so a type keeps one id whether the checker read the + * package's compiled `.d.ts` or its `.ts` source (the "source" condition). */ export function stableFileId(filePath: string, root: string): string { - const file = filePath.replace(/^file:\/+/, "/"); + const file = sourceOfDeclaration(filePath.replace(/^file:\/+/, "/")); const nm = file.lastIndexOf("/node_modules/"); if (nm >= 0) return file.slice(nm + "/node_modules/".length); const rel = path.relative(root, file).split(path.sep).join("/"); @@ -687,3 +692,20 @@ export function stableFileId(filePath: string, root: string): string { dir = parent; } } + +/** The `.ts` file a `.d.ts` was emitted from, per its declaration map; else the file itself. */ +function sourceOfDeclaration(file: string): string { + if (!/\.d\.[cm]?ts$/.test(file)) return file; + try { + const map = JSON.parse(fs.readFileSync(`${file}.map`, "utf8")) as { + sources?: unknown; + sourceRoot?: unknown; + }; + const source = Array.isArray(map.sources) ? map.sources[0] : undefined; + if (typeof source !== "string") return file; + const sourceRoot = typeof map.sourceRoot === "string" ? map.sourceRoot : ""; + return path.resolve(path.dirname(file), sourceRoot, source); + } catch { + return file; + } +} diff --git a/packages/blocks/src/v8/cli/serve/server.ts b/packages/blocks/src/v8/cli/serve/server.ts index 48da854f..04848c22 100644 --- a/packages/blocks/src/v8/cli/serve/server.ts +++ b/packages/blocks/src/v8/cli/serve/server.ts @@ -20,15 +20,15 @@ import http from "node:http"; import type { AddressInfo } from "node:net"; import path from "node:path"; import { Readable } from "node:stream"; -import { ErrorCode } from "../../../protocol/errors"; -import { blockNameFromFile } from "../../../protocol/keys"; -import { createContentHandler } from "../../../protocol/server"; -import { createAssetHandler } from "../../../protocol/server/assets"; -import type { ContentStorage } from "../../../protocol/storage"; -import { createFsStorage } from "../../../protocol/storage/fs"; -import { readSavedBlocks, writeContent } from "../content"; -import { consoleReporter, type Reporter } from "../log"; -import { CliError, decoPaths, findDecoRoot, packageVersion } from "../root"; +import { ErrorCode } from "../../../protocol/errors.ts"; +import { blockNameFromFile } from "../../../protocol/keys.ts"; +import { createAssetHandler } from "../../../protocol/server/assets.ts"; +import { createContentHandler } from "../../../protocol/server/index.ts"; +import { createFsStorage } from "../../../protocol/storage/fs/index.ts"; +import type { ContentStorage } from "../../../protocol/storage.ts"; +import { readSavedBlocks, writeContent } from "../content.ts"; +import { consoleReporter, type Reporter } from "../log.ts"; +import { CliError, decoPaths, findDecoRoot, packageVersion } from "../root.ts"; /** The site editor's origins: the browser origins allowed by default. */ const STUDIO_ORIGINS = [ diff --git a/packages/blocks/src/v8/client.ts b/packages/blocks/src/v8/client.ts index 45189591..170f55f6 100644 --- a/packages/blocks/src/v8/client.ts +++ b/packages/blocks/src/v8/client.ts @@ -2,10 +2,10 @@ * A client: one revision, loaded on first use and read for the rest of its * life, plus a memo of block results. Create one per request. */ -import { errors, isResolutionError, ResolutionError } from "./errors"; -import { isBlock } from "./json"; -import { Resolver } from "./resolver"; -import type { ClientTelemetry } from "./telemetry"; +import { errors, isResolutionError, ResolutionError } from "./errors.ts"; +import { isBlock } from "./json.ts"; +import { Resolver } from "./resolver.ts"; +import type { ClientTelemetry } from "./telemetry.ts"; import type { Block, Blocks, @@ -15,7 +15,7 @@ import type { ResolveOptions, Result, Snapshot, -} from "./types"; +} from "./types.ts"; interface ClientOptions { /** Loads this client's snapshot; called at most once. */ diff --git a/packages/blocks/src/v8/cms.ts b/packages/blocks/src/v8/cms.ts index 2c3f835a..ffc35cdc 100644 --- a/packages/blocks/src/v8/cms.ts +++ b/packages/blocks/src/v8/cms.ts @@ -6,15 +6,15 @@ * a package loaded twice (two bundles, a dev reload) still shares one content * cache. See /next/api-reference#one-instance-per-process. */ -import { runInBackground } from "./background"; -import { builtIns } from "./builtins/index"; -import { secretBlock } from "./builtins/secret"; -import { CMSClient } from "./client"; -import { ContentStore, isLoader, isSnapshot } from "./content"; -import { clearGlobals, contentIdentity, fnv1a, readEnv } from "./identity"; -import { remoteLoader, resetRemoteLoaders } from "./remoteLoader"; -import { resolveDestination, setCurrentTelemetry, TelemetryPipeline } from "./telemetry"; -import type { Blocks, Client, CMS, CMSConfig, Loader, Snapshot } from "./types"; +import { runInBackground } from "./background.ts"; +import { builtIns } from "./builtins/index.ts"; +import { secretBlock } from "./builtins/secret.ts"; +import { CMSClient } from "./client.ts"; +import { ContentStore, isLoader, isSnapshot } from "./content.ts"; +import { clearGlobals, contentIdentity, fnv1a, readEnv } from "./identity.ts"; +import { remoteLoader, resetRemoteLoaders } from "./remoteLoader.ts"; +import { resolveDestination, setCurrentTelemetry, TelemetryPipeline } from "./telemetry.ts"; +import type { Blocks, Client, CMS, CMSConfig, Loader, Snapshot } from "./types.ts"; const INSTANCE_PREFIX = "decocms.blocks.cms:"; const MIN_INTERVAL = 60_000; diff --git a/packages/blocks/src/v8/content.ts b/packages/blocks/src/v8/content.ts index 81d031c5..c2acd301 100644 --- a/packages/blocks/src/v8/content.ts +++ b/packages/blocks/src/v8/content.ts @@ -7,10 +7,10 @@ * revision string a client may hand back, so it must only ever reach published * content, never a draft someone loaded with a pointer. */ -import { formatDraftPointer, parseDraftPointer } from "./draft"; -import { errors, isResolutionError } from "./errors"; -import { isPlainObject } from "./json"; -import type { Loader, Snapshot } from "./types"; +import { formatDraftPointer, parseDraftPointer } from "./draft.ts"; +import { errors, isResolutionError } from "./errors.ts"; +import { isPlainObject } from "./json.ts"; +import type { Loader, Snapshot } from "./types.ts"; const SERVED_REVISIONS = 16; const CACHED_DRAFTS = 32; diff --git a/packages/blocks/src/v8/draft.ts b/packages/blocks/src/v8/draft.ts index 0bf521c8..12d0a4d4 100644 --- a/packages/blocks/src/v8/draft.ts +++ b/packages/blocks/src/v8/draft.ts @@ -3,7 +3,7 @@ * `@` that names a draft, and the two * helpers that carry one from a `?__draft=` link into a cookie. */ -import type { DraftPointer } from "./types"; +import type { DraftPointer } from "./types.ts"; /** The draft cookie's name, for frameworks whose cookie API has no Request (Next.js `cookies()`). */ export const DRAFT_COOKIE = "deco-draft"; diff --git a/packages/blocks/src/v8/errors.ts b/packages/blocks/src/v8/errors.ts index 7cb182b3..dab2e593 100644 --- a/packages/blocks/src/v8/errors.ts +++ b/packages/blocks/src/v8/errors.ts @@ -1,4 +1,4 @@ -import type { CMSError, CMSErrorCode } from "./types"; +import type { CMSError, CMSErrorCode } from "./types.ts"; /** * The concrete {@link CMSError}. It extends `Error` so a lazy block can reject diff --git a/packages/blocks/src/v8/fetch.ts b/packages/blocks/src/v8/fetch.ts index 5ca149ed..2b32c1ad 100644 --- a/packages/blocks/src/v8/fetch.ts +++ b/packages/blocks/src/v8/fetch.ts @@ -9,7 +9,7 @@ * has no telemetry destination. Nothing about a request's body, headers or * query string is recorded. */ -import { currentTelemetry, describe, newTraceId } from "./telemetry"; +import { currentTelemetry, describe, newTraceId } from "./telemetry.ts"; interface InstrumentedFetchOptions { /** The provider label, e.g. "vtex", "acme-search". */ diff --git a/packages/blocks/src/v8/identity.ts b/packages/blocks/src/v8/identity.ts index ca1e77d0..5d0c4580 100644 --- a/packages/blocks/src/v8/identity.ts +++ b/packages/blocks/src/v8/identity.ts @@ -3,7 +3,7 @@ * keys go into the global symbol registry, so they're derived from the * configuration and never carry a secret. */ -import type { Loader, Snapshot } from "./types"; +import type { Loader, Snapshot } from "./types.ts"; const OBJECT_IDS = Symbol.for("decocms.blocks.cms-loader-ids"); diff --git a/packages/blocks/src/v8/index.ts b/packages/blocks/src/v8/index.ts index 77297c37..75a4da09 100644 --- a/packages/blocks/src/v8/index.ts +++ b/packages/blocks/src/v8/index.ts @@ -3,16 +3,16 @@ * `matchRoute` and the draft helpers. Re-exported from the package root, where * these names are the documented ones; see /next/api-reference. */ -export { createCMS, resetForTests } from "./cms"; +export { createCMS, resetForTests } from "./cms.ts"; export { DRAFT_COOKIE, draftCookie, draftPointer, formatDraftPointer, parseDraftPointer, -} from "./draft"; -export { matchRoute } from "./matchRoute"; -export { remoteLoader } from "./remoteLoader"; +} from "./draft.ts"; +export { matchRoute } from "./matchRoute.ts"; +export { remoteLoader } from "./remoteLoader.ts"; export type { Analytics, Block, @@ -36,4 +36,4 @@ export type { Telemetry, TelemetryConfig, Variant, -} from "./types"; +} from "./types.ts"; diff --git a/packages/blocks/src/v8/matchRoute.ts b/packages/blocks/src/v8/matchRoute.ts index f23b5215..e0bc3360 100644 --- a/packages/blocks/src/v8/matchRoute.ts +++ b/packages/blocks/src/v8/matchRoute.ts @@ -11,7 +11,7 @@ * reach the same leaf are a conflict `deco check` reports; here the earlier * one keeps it, so a lookup never throws. No regex, no sorting. */ -import type { LegacyRedirect, Match, Redirect, RedirectStatus, Route } from "./types"; +import type { LegacyRedirect, Match, Redirect, RedirectStatus, Route } from "./types.ts"; /** A leaf holds the entry and its parameter names, in path order; `splat` is a trailing `*`'s leaf. */ type Leaf = { value: T; names: string[] }; diff --git a/packages/blocks/src/v8/remoteLoader.ts b/packages/blocks/src/v8/remoteLoader.ts index 0df6c039..d9d8a65b 100644 --- a/packages/blocks/src/v8/remoteLoader.ts +++ b/packages/blocks/src/v8/remoteLoader.ts @@ -22,12 +22,12 @@ * * Instances are process-wide singletons, like `createCMS`'s. */ -import { computeContentRevision } from "./canonical"; -import { isSnapshot } from "./content"; -import { parseDraftPointer } from "./draft"; -import { clearGlobals, contentIdentity, fnv1a } from "./identity"; -import { isPlainObject } from "./json"; -import type { Loader, Snapshot } from "./types"; +import { computeContentRevision } from "./canonical.ts"; +import { isSnapshot } from "./content.ts"; +import { parseDraftPointer } from "./draft.ts"; +import { clearGlobals, contentIdentity, fnv1a } from "./identity.ts"; +import { isPlainObject } from "./json.ts"; +import type { Loader, Snapshot } from "./types.ts"; /** The hosted delivery origin: channel manifests, release assets and drafts. */ const HOSTED_DELIVERY_ORIGIN = "https://delivery.decocms.com"; diff --git a/packages/blocks/src/v8/resolver.ts b/packages/blocks/src/v8/resolver.ts index d18663e5..2e53ffbf 100644 --- a/packages/blocks/src/v8/resolver.ts +++ b/packages/blocks/src/v8/resolver.ts @@ -16,12 +16,12 @@ * are read-only (see `Client` in ./types): mutating one in place would change * the others, the class of bug behind the v7 layout-cache race. */ -import { RESERVED_NAMES } from "./builtins/index"; -import { isLazyBuiltin } from "./builtins/lazy"; -import { LEGACY_ALIASES, wrapLegacyVariants } from "./builtins/legacy"; -import { errors, isResolutionError } from "./errors"; -import { canonicalKey, isPlainObject, type JsonObject, own } from "./json"; -import type { BlockFunction, Blocks, Lazy, Snapshot } from "./types"; +import { RESERVED_NAMES } from "./builtins/index.ts"; +import { isLazyBuiltin } from "./builtins/lazy.ts"; +import { LEGACY_ALIASES, wrapLegacyVariants } from "./builtins/legacy.ts"; +import { errors, isResolutionError } from "./errors.ts"; +import { canonicalKey, isPlainObject, type JsonObject, own } from "./json.ts"; +import type { BlockFunction, Blocks, Lazy, Snapshot } from "./types.ts"; type Path = (string | number)[]; diff --git a/packages/blocks/src/v8/secrets.ts b/packages/blocks/src/v8/secrets.ts index 187d0122..b41b8f9a 100644 --- a/packages/blocks/src/v8/secrets.ts +++ b/packages/blocks/src/v8/secrets.ts @@ -3,7 +3,7 @@ * script or an AI agent that writes content (see /next/api-reference#secrets). * Web Crypto only, so it runs in browsers, on Workers and on Node. */ -import { encryptToCiphertext } from "./ciphertext"; +import { encryptToCiphertext } from "./ciphertext.ts"; /** * Encrypts `value` with your public key (the contents of `.deco/secrets.pub`) diff --git a/packages/blocks/src/v8/telemetry.ts b/packages/blocks/src/v8/telemetry.ts index af448732..a4e7fe0a 100644 --- a/packages/blocks/src/v8/telemetry.ts +++ b/packages/blocks/src/v8/telemetry.ts @@ -14,11 +14,11 @@ * - Everything is scrubbed before encoding: no query strings, tokens, * cookies or authorization values, and no value a secret block decrypted. */ -import { hasBackgroundHook, later, runInBackground } from "./background"; -import { isResolutionError } from "./errors"; -import { readEnv } from "./identity"; -import { isPlainObject } from "./json"; -import type { CMSError, Snapshot, TelemetryConfig } from "./types"; +import { hasBackgroundHook, later, runInBackground } from "./background.ts"; +import { isResolutionError } from "./errors.ts"; +import { readEnv } from "./identity.ts"; +import { isPlainObject } from "./json.ts"; +import type { CMSError, Snapshot, TelemetryConfig } from "./types.ts"; /** The hosted Deco CMS collector, for `telemetry: { site, token }`. */ const HOSTED_TELEMETRY_ENDPOINT = "https://otel.decocms.com"; diff --git a/packages/blocks/tsconfig.build.json b/packages/blocks/tsconfig.build.json new file mode 100644 index 00000000..7dd791e6 --- /dev/null +++ b/packages/blocks/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.build.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src/**/*"], + "exclude": [ + "src/**/*.test.ts", + "src/**/*.test.tsx", + "src/**/__tests__/**", + "src/**/__fixtures__/**", + "src/**/__conformance__/**", + "src/v8/testFixtures.ts" + ] +} diff --git a/packages/blocks/tsconfig.json b/packages/blocks/tsconfig.json index 7e8bd25e..bf5a36dd 100644 --- a/packages/blocks/tsconfig.json +++ b/packages/blocks/tsconfig.json @@ -1,7 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "dist" - }, - "include": ["src/**/*", "package.json"] + "include": ["src/**/*"] } diff --git a/scripts/tsc.mjs b/scripts/tsc.mjs new file mode 100644 index 00000000..22a7f522 --- /dev/null +++ b/scripts/tsc.mjs @@ -0,0 +1,28 @@ +#!/usr/bin/env node +// Runs the TypeScript 7 native compiler (`typescript7`, an npm alias of +// typescript@7 in the root devDependencies) with the given arguments. +// +// The alias exists because the plain `typescript` name has to stay on 5.x in +// this workspace: TypeScript 7 ships no JavaScript compiler API, and +// `deco schema` (plus Next's type-check and a few conformance tests) load the +// app's `typescript` through that API. Builds and type-checks run on 7; +// whatever imports "typescript" keeps getting 5.x. +// +// `--clean ` removes first, so a build never ships output for a +// source file that was deleted or renamed. +import { spawnSync } from "node:child_process"; +import { rmSync } from "node:fs"; +import { createRequire } from "node:module"; +import { dirname, join } from "node:path"; + +const args = process.argv.slice(2); +const clean = args.indexOf("--clean"); +if (clean !== -1) { + rmSync(args[clean + 1], { recursive: true, force: true }); + args.splice(clean, 2); +} + +const require = createRequire(import.meta.url); +const tsc = join(dirname(require.resolve("typescript7/package.json")), "bin/tsc"); +const result = spawnSync(process.execPath, [tsc, ...args], { stdio: "inherit" }); +process.exit(result.status ?? 1); diff --git a/tests/globalSetup.ts b/tests/globalSetup.ts new file mode 100644 index 00000000..91329f7f --- /dev/null +++ b/tests/globalSetup.ts @@ -0,0 +1,18 @@ +/** + * Builds @decocms/blocks's dist/ once before the suite. The `deco` bin runs + * dist/ (bin/deco.js), and the CLI conformance tests spawn it and run temp + * apps that import the package the way an installed app does, so they must see + * the current sources compiled, not a dist/ left over from an earlier build. + */ +import { execFileSync } from "node:child_process"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +export default function setup(): void { + const repo = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); + execFileSync( + process.execPath, + [path.join(repo, "scripts/tsc.mjs"), "--clean", "dist", "-p", "tsconfig.build.json"], + { cwd: path.join(repo, "packages/blocks"), stdio: "inherit" }, + ); +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 53fd9534..df97ee79 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -8,6 +8,14 @@ "strictNullChecks": true, "declaration": true, "resolveJsonModule": true, - "composite": true + "allowImportingTsExtensions": true, + "customConditions": [ + "source" + ], + "noEmit": true, + "types": [ + "node" + ], + "strict": false } } diff --git a/tsconfig.build.base.json b/tsconfig.build.base.json new file mode 100644 index 00000000..70dc1bf1 --- /dev/null +++ b/tsconfig.build.base.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "customConditions": [], + "rewriteRelativeImportExtensions": true, + "noEmit": false, + "declaration": true, + "declarationMap": true, + "sourceMap": true + } +} diff --git a/vitest.config.ts b/vitest.config.ts index 62addf10..da69cc90 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,9 +1,18 @@ +import { defaultClientConditions, defaultServerConditions } from "vite"; import { defineConfig } from "vitest/config"; // One config for the whole repo: `bun run test` at the root runs every // package, the cross-package tests in tests/ and the migration skill's // scripts. Files that need Node APIs say so with `// @vitest-environment node`. +// +// Imports of `@decocms/*` resolve through the packages' "source" export +// condition, so a test that imports a file by relative path and one that +// imports the package name load the same module (one instance, as in an app) +// and no test needs a build. Only the spawned `deco` bin and the temp apps the +// CLI conformance tests create run dist/, which tests/globalSetup.ts builds. export default defineConfig({ + resolve: { conditions: ["source", ...defaultClientConditions] }, + ssr: { resolve: { conditions: ["source", ...defaultServerConditions] } }, test: { environment: "jsdom", include: [ @@ -12,5 +21,6 @@ export default defineConfig({ ".agents/skills/*/scripts/**/*.test.ts", ], globals: true, + globalSetup: ["tests/globalSetup.ts"], }, }); From 57bed93aee2f878689e240383b5372d659a1d6ad Mon Sep 17 00:00:00 2001 From: gimenes Date: Sat, 3 Oct 2026 19:04:27 -0300 Subject: [PATCH 2/3] fix(blocks): declare @opentelemetry/api as a devDependency for the observability conformance fixture The v7 removal dropped it from dependencies, but the telemetry docs' snippet fixture still imports it for typechecking, so a fresh install failed observability.test.ts. Dev-only; knip ignores it since only the fixture uses it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig --- bun.lock | 3 +++ knip.json | 3 ++- packages/blocks/package.json | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bun.lock b/bun.lock index 399907ba..3d6f853a 100644 --- a/bun.lock +++ b/bun.lock @@ -136,6 +136,7 @@ "zod": "^4.4.3", }, "devDependencies": { + "@opentelemetry/api": "^1.9.1", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "esbuild": "^0.27.3", @@ -442,6 +443,8 @@ "@oozcitak/util": ["@oozcitak/util@10.0.0", "", {}, "sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA=="], + "@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="], + "@oxc-project/types": ["@oxc-project/types@0.120.0", "", {}, "sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg=="], "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.23.0", "", { "os": "android", "cpu": "arm" }, "sha512-8IJyWRLVAyhTfe9/TIEbQqSQnl5rUqYJrUOS6Dkr+Mq9FGHMxDGeiEmwkBqCvDP5KckpPh/GYSgbag66O6JsCw=="], diff --git a/knip.json b/knip.json index 70b17f22..8e1d943f 100644 --- a/knip.json +++ b/knip.json @@ -35,7 +35,8 @@ "bin/*.js" ], "ignoreDependencies": [ - "esbuild" + "esbuild", + "@opentelemetry/api" ], "entry": [ "src/v8/cli/main.ts" diff --git a/packages/blocks/package.json b/packages/blocks/package.json index 3d35b2c2..25b3e1ec 100644 --- a/packages/blocks/package.json +++ b/packages/blocks/package.json @@ -101,6 +101,7 @@ "typescript": "^5.0.0" }, "devDependencies": { + "@opentelemetry/api": "^1.9.1", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "esbuild": "^0.27.3", From 013607c2fe7781458e22e65333883f23ce735ed6 Mon Sep 17 00:00:00 2001 From: gimenes Date: Wed, 7 Oct 2026 13:02:09 -0300 Subject: [PATCH 3/3] fix(build): build @decocms/blocks before the apps; rename lockfile root to decocms-blocks The apps resolve @decocms/blocks/* through its dist types, so a parallel --filter build raced blocks' tsc and failed with TS2307 in prepare. Co-Authored-By: Claude Opus 5.5 --- bun.lock | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bun.lock b/bun.lock index 3d6f853a..6e36e54e 100644 --- a/bun.lock +++ b/bun.lock @@ -3,7 +3,7 @@ "configVersion": 0, "workspaces": { "": { - "name": "@decocms/start", + "name": "decocms-blocks", "devDependencies": { "@biomejs/biome": "^2.5.3", "@semantic-release/exec": "^7.1.0", diff --git a/package.json b/package.json index cb171eaa..057c02c9 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "packageManager": "bun@1.3.5", "scripts": { "prepare": "bun run build", - "build": "bun run --filter='./packages/*' build", + "build": "bun run --filter=@decocms/blocks build && bun run --filter='./packages/apps-*' build", "test": "vitest run", "typecheck": "bun run --filter='./packages/*' typecheck && node scripts/tsc.mjs -p .agents/skills/deco-v7-to-v8-migration/scripts && node scripts/tsc.mjs -p tests", "examples": "bun run build && bun run --filter='./examples/*' build && bun run --filter='./examples/*' typecheck",