diff --git a/.changeset/fix-cli-bundle-workspace-deps.md b/.changeset/fix-cli-bundle-workspace-deps.md new file mode 100644 index 00000000..d961e68c --- /dev/null +++ b/.changeset/fix-cli-bundle-workspace-deps.md @@ -0,0 +1,5 @@ +--- +"@stackwright/cli": patch +--- + +Bundle internal `@stackwright/*` workspace dependencies into the CLI binary via tsup `noExternal`. This fixes `ERR_PNPM_WORKSPACE_PKG_NOT_FOUND` when installing `@stackwright/cli` via `pnpm dlx` outside a monorepo. Also adds a `prepublishOnly` guard to catch any future `workspace:*` leakage before publish. diff --git a/.changeset/fix-core-dts-zod-compat.md b/.changeset/fix-core-dts-zod-compat.md new file mode 100644 index 00000000..e7d775dd --- /dev/null +++ b/.changeset/fix-core-dts-zod-compat.md @@ -0,0 +1,31 @@ +--- +"@stackwright/core": patch +--- + +fix(core): remove zod internals from published .d.ts + +The generated `dist/index.d.ts` previously embedded zod-version-specific +internal types (`z.ZodTypeAny`, `z.core.$strip`, `z.ZodObject` generics) +directly into the exported API surface. This caused TypeScript errors in +consumer projects whose installed zod version differed from the one used +at build time — particularly the zod@3 → zod@4 upgrade — forcing them to +maintain `stackwright-core.d.ts` module-override stubs as workarounds. + +Two root causes fixed: + +1. `ContentTypeEntry.schema` and the `registerContentType` / `getContentTypeSchema` + signatures now use a local `ZodSchema` structural interface instead of + `z.ZodTypeAny`. Any real Zod schema satisfies `ZodSchema` via duck-typing, + so existing call-sites are unaffected. + +2. `siteDefaults.ts` was importing `SiteConfig` via a relative path to the + `@stackwright/types` source file, causing tsup to inline the entire + `siteConfigSchema: z.ZodObject<{..., z.core.$strip}>` declaration into the + bundled d.ts. Changed to `import type { SiteConfig } from '@stackwright/types'` + so tsup treats it as an external package reference. + +Additionally, `@stackwright/types`, `@stackwright/themes`, and +`@stackwright/collections` are now listed in tsup's `external` array as a +defensive measure against future inlining regressions. + +Consumer projects can now delete any `stackwright-core.d.ts` stub override files. diff --git a/.changeset/fix-scaffold-template-versions.md b/.changeset/fix-scaffold-template-versions.md new file mode 100644 index 00000000..b91bff12 --- /dev/null +++ b/.changeset/fix-scaffold-template-versions.md @@ -0,0 +1,26 @@ +--- +"@stackwright/cli": patch +--- + +fix(cli): update stale scaffold template package versions + +`buildPackageJson()` in `template-processor.ts` was pinning scaffolded +projects to package versions that were 4+ releases behind: + +- `@stackwright/core`: `^0.7.0` → `^0.8.0` +- `@stackwright/nextjs`: `^0.3.1` → `^0.5.0` +- `@stackwright/icons`: `^0.3.0` → `^0.5.0` +- `@stackwright/build-scripts`: `^0.4.0` → `^0.7.0` ← **critical** +- `@stackwright/ui-shadcn`: `^0.1.0` → `^0.1.2` +- `@stackwright/otters`: `^0.2.0-alpha.0` → `^0.2.0` + +The `build-scripts` version was the critical failure: the plugin API +(`PrebuildPlugin`, `beforeBuild`, `contentItemSchemas`) was introduced in +0.5.0, but scaffolded projects installed 0.4.0 — a version that has no +plugin system at all. This caused Pro plugin hooks to silently fail or +crash in freshly scaffolded projects. + +Also adds `scripts/sync-versions.mjs` — a Node ESM utility that reads +workspace `package.json` versions and rewrites the VERSIONS constant +automatically. Run `node scripts/sync-versions.mjs` before cutting releases +to prevent version drift. diff --git a/.changeset/fix-types-prebuild-plugin-zod-compat.md b/.changeset/fix-types-prebuild-plugin-zod-compat.md new file mode 100644 index 00000000..e4cbdb8b --- /dev/null +++ b/.changeset/fix-types-prebuild-plugin-zod-compat.md @@ -0,0 +1,19 @@ +--- +"@stackwright/types": patch +--- + +fix(types): remove zod internals from PrebuildPlugin public interface + +`PrebuildPlugin.configSchema` was typed as `z.ZodSchema` and +`contentItemSchemas` as `z.ZodTypeAny[]`. These zod-version-specific +types bled into the published `.d.ts`, causing TypeScript errors in Pro +packages that implemented `PrebuildPlugin` when their installed zod version +differed from what `@stackwright/types` was built with. + +Both fields now use a local structural `ZodLike` interface +(`{ safeParse(data: unknown): { success: boolean; error?: unknown } }`) +which any real Zod schema satisfies via duck-typing. Existing plugin +implementations are unaffected. + +This is the same fix applied to `@stackwright/core`'s `ContentTypeEntry` +in the companion changeset. diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 00000000..a11e3c81 --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,31 @@ +{ + "mode": "pre", + "tag": "alpha", + "initialVersions": { + "stackwright-docs": "0.1.3", + "@stackwright/build-scripts": "0.6.0", + "@stackwright/cli": "0.8.2", + "@stackwright/collections": "0.1.0", + "@stackwright/core": "0.8.1", + "@stackwright/e2e": "0.3.0", + "@stackwright/hooks-registry": "0.1.0", + "@stackwright/icons": "0.5.1", + "launch-stackwright": "0.2.2", + "@stackwright/maplibre": "2.0.1", + "@stackwright/mcp": "0.4.2", + "@stackwright/nextjs": "0.5.0", + "@stackwright/otters": "0.2.0", + "@stackwright/sbom-generator": "0.2.0", + "@stackwright/scaffold-core": "0.3.0", + "@stackwright/themes": "0.5.2", + "@stackwright/types": "1.3.0", + "@stackwright/ui-shadcn": "0.1.2" + }, + "changesets": [ + "fix-cli-bundle-workspace-deps", + "fix-core-dts-zod-compat", + "fix-scaffold-template-versions", + "fix-types-prebuild-plugin-zod-compat", + "zodlike-export-path-fix" + ] +} diff --git a/.changeset/zodlike-export-path-fix.md b/.changeset/zodlike-export-path-fix.md new file mode 100644 index 00000000..10484cd5 --- /dev/null +++ b/.changeset/zodlike-export-path-fix.md @@ -0,0 +1,5 @@ +--- +"@stackwright/types": patch +--- + +Export `ZodLike` from `@stackwright/types` so plugin authors can reference it by name without index-access workarounds. Also widens `ZodLike.issues[].path` from `(string | number)[]` to `PropertyKey[]` to match Zod v4's actual `$ZodIssue.path` type, fixing a nominal TypeScript incompatibility where real Zod schemas did not satisfy `ZodLike` at the type level. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b74ec1f7..799c16d6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -126,14 +126,22 @@ jobs: - name: Back-merge into dev if: steps.check.outputs.skip != 'true' run: | + git fetch origin dev git checkout dev git pull origin dev - # -X theirs: main's graduated versions win over dev's stale alphas - git merge main -X theirs --no-edit -m "chore: back-merge main after release [skip ci]" - # Re-enter prerelease mode so the next dev push produces alphas + # Rebase dev's unique commits onto main for clean, linear history. + # Using rebase (instead of merge) prevents phantom commits from + # accumulating in dev's ancestry — which previously caused dev→main + # PRs to show dozens of already-released commits. + # + # -X ours: when conflicts arise (e.g. version numbers in package.json), + # prefer main's graduated stable versions over dev's stale alpha versions. + git rebase origin/main -X ours + # Re-enter prerelease mode so the next dev push produces alphas. if [ ! -f ".changeset/pre.json" ]; then pnpm changeset pre enter alpha git add .changeset/pre.json git commit -m "chore: re-enter prerelease mode after back-merge [skip ci]" fi - git push origin dev + # Force push is required after a rebase to rewrite dev's remote history. + git push origin dev --force-with-lease diff --git a/examples/stackwright-docs/CHANGELOG.md b/examples/stackwright-docs/CHANGELOG.md index 468ec792..367a2437 100644 --- a/examples/stackwright-docs/CHANGELOG.md +++ b/examples/stackwright-docs/CHANGELOG.md @@ -1,5 +1,20 @@ # stackwright-docs +## 0.1.5-alpha.1 + +### Patch Changes + +- @stackwright/core@0.8.3-alpha.1 +- @stackwright/nextjs@0.5.2-alpha.1 + +## 0.1.5-alpha.0 + +### Patch Changes + +- Updated dependencies [5cfa88e] + - @stackwright/core@0.8.3-alpha.0 + - @stackwright/nextjs@0.5.2-alpha.0 + ## 0.1.4 ### Patch Changes diff --git a/examples/stackwright-docs/package.json b/examples/stackwright-docs/package.json index ae1fb543..e8ab8cdc 100644 --- a/examples/stackwright-docs/package.json +++ b/examples/stackwright-docs/package.json @@ -1,6 +1,6 @@ { "name": "stackwright-docs", - "version": "0.1.4", + "version": "0.1.5-alpha.1", "private": true, "scripts": { "prebuild": "stackwright-prebuild", diff --git a/package.json b/package.json index bbe31490..38ca4043 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "next": ">=16.1.7", "hono": ">=4.12.14", "@hono/node-server": ">=1.19.10", - "basic-ftp": ">=5.3.0", + "basic-ftp": ">=5.3.1", "express-rate-limit": ">=8.2.2", "uuid": ">=14.0.0" }, diff --git a/packages/build-scripts/CHANGELOG.md b/packages/build-scripts/CHANGELOG.md index e0ac1332..0d27c9df 100644 --- a/packages/build-scripts/CHANGELOG.md +++ b/packages/build-scripts/CHANGELOG.md @@ -1,5 +1,19 @@ # @stackwright/build-scripts +## 0.7.1-alpha.1 + +### Patch Changes + +- Updated dependencies [21ed937] + - @stackwright/types@1.4.1-alpha.1 + +## 0.7.1-alpha.0 + +### Patch Changes + +- Updated dependencies [5cfa88e] + - @stackwright/types@1.4.1-alpha.0 + ## 0.7.0 ### Minor Changes diff --git a/packages/build-scripts/package.json b/packages/build-scripts/package.json index a4c4e640..10c9ee99 100644 --- a/packages/build-scripts/package.json +++ b/packages/build-scripts/package.json @@ -1,6 +1,6 @@ { "name": "@stackwright/build-scripts", - "version": "0.7.0", + "version": "0.7.1-alpha.1", "description": "Build-time scripts for Stackwright projects (prebuild image processing, YAML compilation)", "license": "MIT", "repository": { @@ -31,7 +31,8 @@ "dependencies": { "@stackwright/sbom-generator": "workspace:*", "@stackwright/types": "workspace:*", - "js-yaml": "^4.1.0" + "js-yaml": "^4.1.0", + "zod": "^4.3.6" }, "devDependencies": { "@types/js-yaml": "^4.0", diff --git a/packages/build-scripts/src/prebuild.ts b/packages/build-scripts/src/prebuild.ts index d8435b58..702df7ae 100644 --- a/packages/build-scripts/src/prebuild.ts +++ b/packages/build-scripts/src/prebuild.ts @@ -23,6 +23,7 @@ import fs from 'fs'; import path from 'path'; import yaml from 'js-yaml'; +import { z } from 'zod'; import { siteConfigSchema, validatePageContent, @@ -1019,7 +1020,9 @@ export async function runPrebuild(options?: string | PrebuildOptions): Promise p.contentItemSchemas ?? []); + // Cast from ZodLike[] to ZodTypeAny[] — plugins always supply real Zod schemas; + // ZodLike is used only in the public API surface to avoid d.ts version coupling. + const extraContentSchemas = plugins.flatMap((p) => p.contentItemSchemas ?? []) as z.ZodTypeAny[]; const pluginKnownTypes = plugins.flatMap((p) => p.knownContentTypeKeys ?? []); const pagesDir = path.join(projectRoot, 'pages'); diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index bf4cba80..9f7671e1 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,32 @@ # @stackwright/cli +## 0.8.4-alpha.0 + +### Patch Changes + +- f756476: Bundle internal `@stackwright/*` workspace dependencies into the CLI binary via tsup `noExternal`. This fixes `ERR_PNPM_WORKSPACE_PKG_NOT_FOUND` when installing `@stackwright/cli` via `pnpm dlx` outside a monorepo. Also adds a `prepublishOnly` guard to catch any future `workspace:*` leakage before publish. +- 5cfa88e: fix(cli): update stale scaffold template package versions + + `buildPackageJson()` in `template-processor.ts` was pinning scaffolded + projects to package versions that were 4+ releases behind: + - `@stackwright/core`: `^0.7.0` → `^0.8.0` + - `@stackwright/nextjs`: `^0.3.1` → `^0.5.0` + - `@stackwright/icons`: `^0.3.0` → `^0.5.0` + - `@stackwright/build-scripts`: `^0.4.0` → `^0.7.0` ← **critical** + - `@stackwright/ui-shadcn`: `^0.1.0` → `^0.1.2` + - `@stackwright/otters`: `^0.2.0-alpha.0` → `^0.2.0` + + The `build-scripts` version was the critical failure: the plugin API + (`PrebuildPlugin`, `beforeBuild`, `contentItemSchemas`) was introduced in + 0.5.0, but scaffolded projects installed 0.4.0 — a version that has no + plugin system at all. This caused Pro plugin hooks to silently fail or + crash in freshly scaffolded projects. + + Also adds `scripts/sync-versions.mjs` — a Node ESM utility that reads + workspace `package.json` versions and rewrites the VERSIONS constant + automatically. Run `node scripts/sync-versions.mjs` before cutting releases + to prevent version drift. + ## 0.8.3 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index a5836b95..9fbcc3f2 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@stackwright/cli", - "version": "0.8.3", + "version": "0.8.4-alpha.0", "description": "CLI for Stackwright framework", "license": "MIT", "repository": { @@ -28,15 +28,11 @@ "build": "tsup", "dev": "tsup --watch", "test": "vitest run", - "test:coverage": "vitest run --coverage" + "test:coverage": "vitest run --coverage", + "prepublishOnly": "node -e \"const p=require('./package.json');const fields=[...Object.values(p.dependencies||{}),...Object.values(p.peerDependencies||{})];const bad=fields.filter(v=>String(v).includes('workspace:'));if(bad.length){console.error('ERR: workspace: specifiers found in publishable dep fields:',bad);process.exit(1)}\"" }, "dependencies": { "@inquirer/prompts": "^8.3.0", - "@stackwright/build-scripts": "workspace:*", - "@stackwright/sbom-generator": "workspace:*", - "@stackwright/scaffold-core": "workspace:*", - "@stackwright/themes": "workspace:*", - "@stackwright/types": "workspace:*", "chalk": "^5.6.2", "commander": "^14.0.3", "fs-extra": "^11.3", @@ -52,6 +48,11 @@ } }, "devDependencies": { + "@stackwright/build-scripts": "workspace:*", + "@stackwright/sbom-generator": "workspace:*", + "@stackwright/scaffold-core": "workspace:*", + "@stackwright/themes": "workspace:*", + "@stackwright/types": "workspace:*", "@types/fs-extra": "^11.0", "@types/js-yaml": "^4.0", "@types/node": "^25.4", diff --git a/packages/cli/src/commands/prebuild.ts b/packages/cli/src/commands/prebuild.ts index 702f7935..7db438c3 100644 --- a/packages/cli/src/commands/prebuild.ts +++ b/packages/cli/src/commands/prebuild.ts @@ -1,4 +1,5 @@ import { Command } from 'commander'; +import { runPrebuild } from '@stackwright/build-scripts'; import { outputResult, outputError } from '../utils/json-output'; // --------------------------------------------------------------------------- @@ -14,12 +15,6 @@ export interface PrebuildResult { } export function runPrebuildCommand(projectRoot = process.cwd()): PrebuildResult { - // Import here to avoid triggering the auto-invoke guard at module load time. - // The guard `if (require.main === module)` in prebuild.ts prevents auto-run, - // but we keep the import lazy for clarity. - const { runPrebuild } = require('@stackwright/build-scripts') as { - runPrebuild: (root?: string) => void; - }; runPrebuild(projectRoot); return { success: true, processed: -1, images: -1 }; } diff --git a/packages/cli/src/commands/sbom.ts b/packages/cli/src/commands/sbom.ts index 82834b8f..f21f1b7a 100644 --- a/packages/cli/src/commands/sbom.ts +++ b/packages/cli/src/commands/sbom.ts @@ -1,6 +1,12 @@ import { Command } from 'commander'; import path from 'path'; import fs from 'fs'; +import { + createSBOM, + validateSPDX, + validateCycloneDX, + validateBuildManifest, +} from '@stackwright/sbom-generator'; import { outputResult, outputError } from '../utils/json-output'; /** @@ -33,8 +39,6 @@ export interface SBOMGenerateResult { async function generateSBOM(options: SBOMGenerateOptions = {}): Promise { const projectRoot = options.projectRoot ?? process.cwd(); - const { createSBOM } = await import('@stackwright/sbom-generator'); - const formats = (options.formats as ('spdx' | 'cyclonedx' | 'build-manifest')[]) ?? [ 'spdx', 'cyclonedx', @@ -78,9 +82,6 @@ export interface SBOMValidateResult { } async function validateSBOM(options: SBOMValidateOptions): Promise { - const { validateSPDX, validateCycloneDX, validateBuildManifest } = - await import('@stackwright/sbom-generator'); - const inputPath = path.resolve(options.inputFile); if (!fs.existsSync(inputPath)) { @@ -139,9 +140,7 @@ export interface SBOMDiffResult { changed: string[]; } -async function diffSBOM(_options: SBOMDiffOptions): Promise { - void (await import('@stackwright/sbom-generator')); - +async function diffSBOM(options: SBOMDiffOptions): Promise { const oldPath = path.resolve(options.oldFile); const newPath = path.resolve(options.newFile); diff --git a/packages/cli/src/utils/template-processor.ts b/packages/cli/src/utils/template-processor.ts index 08091a41..45495aff 100644 --- a/packages/cli/src/utils/template-processor.ts +++ b/packages/cli/src/utils/template-processor.ts @@ -223,13 +223,13 @@ async function collectFiles(dir: string, base: string = ''): Promise { export function buildPackageJson(projectName: string, useWorkspaceDeps: boolean = false): object { const VERSIONS = { tailwindcss: '^4.1.11', - // Stackwright packages — pinned to current stable for reproducibility - swCore: '^0.7.0', - swNextjs: '^0.3.1', - swIcons: '^0.3.0', - swBuildScripts: '^0.4.0', + // Stackwright packages — keep in sync with workspace via scripts/sync-versions.mjs + swCore: '^0.8.0', + swNextjs: '^0.5.0', + swIcons: '^0.5.0', + swBuildScripts: '^0.7.0', swUiShadcn: '^0.1.0', - swOtters: '^0.2.0-alpha.0', + swOtters: '^0.2.0', // Third-party jsYaml: '^4.1.1', next: '^16.1.6', diff --git a/packages/cli/test/commands/scaffold.test.ts b/packages/cli/test/commands/scaffold.test.ts index 60cbafc0..1ce78751 100644 --- a/packages/cli/test/commands/scaffold.test.ts +++ b/packages/cli/test/commands/scaffold.test.ts @@ -207,7 +207,7 @@ describe('scaffold — dependency mode', () => { const pkg = readJson(path.join(targetDir, 'package.json')); const deps = pkg.dependencies as Record; expect(deps['@stackwright/core']).not.toBe('workspace:*'); - expect(deps['@stackwright/core']).toBe('^0.7.0'); + expect(deps['@stackwright/core']).toBe('^0.8.0'); }); }); diff --git a/packages/cli/tsup.config.ts b/packages/cli/tsup.config.ts index 6890e118..b07d767c 100644 --- a/packages/cli/tsup.config.ts +++ b/packages/cli/tsup.config.ts @@ -10,6 +10,16 @@ export default defineConfig({ format: ['cjs', 'esm'], dts: true, splitting: false, + noExternal: [/^@stackwright\//], + // CLI is Node.js-only. Force the `require` condition so CJS-only workspace + // packages (e.g. @stackwright/build-scripts, which has no `import` export) + // resolve correctly during the ESM format pass as well as the CJS pass. + esbuildOptions(options) { + if (!options.conditions) options.conditions = []; + if (!options.conditions.includes('require')) { + options.conditions.unshift('require'); + } + }, sourcemap: false, clean: true, outExtension({ format }) { diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 010c36e1..87c71f01 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,45 @@ # @stackwright/core +## 0.8.3-alpha.1 + +### Patch Changes + +- Updated dependencies [21ed937] + - @stackwright/types@1.4.1-alpha.1 + +## 0.8.3-alpha.0 + +### Patch Changes + +- 5cfa88e: fix(core): remove zod internals from published .d.ts + + The generated `dist/index.d.ts` previously embedded zod-version-specific + internal types (`z.ZodTypeAny`, `z.core.$strip`, `z.ZodObject` generics) + directly into the exported API surface. This caused TypeScript errors in + consumer projects whose installed zod version differed from the one used + at build time — particularly the zod@3 → zod@4 upgrade — forcing them to + maintain `stackwright-core.d.ts` module-override stubs as workarounds. + + Two root causes fixed: + 1. `ContentTypeEntry.schema` and the `registerContentType` / `getContentTypeSchema` + signatures now use a local `ZodSchema` structural interface instead of + `z.ZodTypeAny`. Any real Zod schema satisfies `ZodSchema` via duck-typing, + so existing call-sites are unaffected. + 2. `siteDefaults.ts` was importing `SiteConfig` via a relative path to the + `@stackwright/types` source file, causing tsup to inline the entire + `siteConfigSchema: z.ZodObject<{..., z.core.$strip}>` declaration into the + bundled d.ts. Changed to `import type { SiteConfig } from '@stackwright/types'` + so tsup treats it as an external package reference. + + Additionally, `@stackwright/types`, `@stackwright/themes`, and + `@stackwright/collections` are now listed in tsup's `external` array as a + defensive measure against future inlining regressions. + + Consumer projects can now delete any `stackwright-core.d.ts` stub override files. + +- Updated dependencies [5cfa88e] + - @stackwright/types@1.4.1-alpha.0 + ## 0.8.2 ### Patch Changes diff --git a/packages/core/package.json b/packages/core/package.json index dbcd0361..c891ccd8 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@stackwright/core", - "version": "0.8.2", + "version": "0.8.3-alpha.1", "description": "Core framework for building applications from YAML configuration", "license": "MIT", "repository": { diff --git a/packages/core/src/config/siteDefaults.ts b/packages/core/src/config/siteDefaults.ts index c0dd6f09..4b842239 100644 --- a/packages/core/src/config/siteDefaults.ts +++ b/packages/core/src/config/siteDefaults.ts @@ -1,4 +1,4 @@ -import { SiteConfig } from '../../../types/src/types/siteConfig'; +import type { SiteConfig } from '@stackwright/types'; /** * Default site configuration used across Stackwright diff --git a/packages/core/src/utils/contentTypeRegistry.ts b/packages/core/src/utils/contentTypeRegistry.ts index a71bcb71..c3d535c3 100644 --- a/packages/core/src/utils/contentTypeRegistry.ts +++ b/packages/core/src/utils/contentTypeRegistry.ts @@ -1,10 +1,10 @@ import { ComponentType } from 'react'; -import { z } from 'zod'; +import type { ZodSchema } from './zod-compat'; import { registerComponent, deregisterComponent } from './componentRegistry'; export interface ContentTypeEntry { key: string; - schema: z.ZodTypeAny; + schema: ZodSchema; component: ComponentType; } @@ -30,7 +30,7 @@ const customContentTypes = new Map(); */ export function registerContentType( key: string, - schema: z.ZodTypeAny, + schema: ZodSchema, component: ComponentType ): void { customContentTypes.set(key, { key, schema, component }); @@ -50,7 +50,7 @@ export function getRegisteredContentTypes(): ContentTypeEntry[] { * Return the Zod schema for a specific custom content type key, or undefined * if the key is not a registered custom type. */ -export function getContentTypeSchema(key: string): z.ZodTypeAny | undefined { +export function getContentTypeSchema(key: string): ZodSchema | undefined { return customContentTypes.get(key)?.schema; } diff --git a/packages/core/src/utils/zod-compat.ts b/packages/core/src/utils/zod-compat.ts new file mode 100644 index 00000000..f5ea60fa --- /dev/null +++ b/packages/core/src/utils/zod-compat.ts @@ -0,0 +1,16 @@ +/** + * Minimal structural interface that replaces z.ZodTypeAny in @stackwright/core's + * public API surface. + * + * Using this instead of z.ZodTypeAny prevents zod's internal type machinery + * (e.g. z.core.$strip, z.ZodObject generic parameters) from bleeding into the + * published .d.ts file. Any real Zod schema satisfies this interface via + * structural typing, so existing call-sites are unaffected. + * + * @see https://github.com/Per-Aspera-LLC/stackwright/issues — "fix core d.ts against zod@4" + */ +export interface ZodSchema { + safeParse(data: unknown): + | { success: true } + | { success: false; error: { issues: unknown[] } }; +} diff --git a/packages/core/tsup.config.ts b/packages/core/tsup.config.ts index bd1e06bb..f895b29c 100644 --- a/packages/core/tsup.config.ts +++ b/packages/core/tsup.config.ts @@ -8,7 +8,7 @@ export default defineConfig({ splitting: false, sourcemap: true, clean: true, - external: ['react', 'react-dom'], + external: ['react', 'react-dom', '@stackwright/types', '@stackwright/themes', '@stackwright/collections'], noExternal: ['prismjs'], outExtension({ format }) { return { diff --git a/packages/launch-stackwright/CHANGELOG.md b/packages/launch-stackwright/CHANGELOG.md index ab009552..1c099e50 100644 --- a/packages/launch-stackwright/CHANGELOG.md +++ b/packages/launch-stackwright/CHANGELOG.md @@ -1,5 +1,13 @@ # launch-stackwright +## 0.2.4-alpha.0 + +### Patch Changes + +- Updated dependencies [f756476] +- Updated dependencies [5cfa88e] + - @stackwright/cli@0.8.4-alpha.0 + ## 0.2.3 ### Patch Changes diff --git a/packages/launch-stackwright/package.json b/packages/launch-stackwright/package.json index 622ace5b..74c46f34 100644 --- a/packages/launch-stackwright/package.json +++ b/packages/launch-stackwright/package.json @@ -1,6 +1,6 @@ { "name": "launch-stackwright", - "version": "0.2.3", + "version": "0.2.4-alpha.0", "description": "Launch a new Stackwright project with the otter raft ready to build", "license": "MIT", "repository": { diff --git a/packages/maplibre/CHANGELOG.md b/packages/maplibre/CHANGELOG.md index 2a4a7742..d54ddf66 100644 --- a/packages/maplibre/CHANGELOG.md +++ b/packages/maplibre/CHANGELOG.md @@ -1,5 +1,18 @@ # @stackwright/maplibre +## 2.0.3-alpha.1 + +### Patch Changes + +- @stackwright/core@0.8.3-alpha.1 + +## 2.0.3-alpha.0 + +### Patch Changes + +- Updated dependencies [5cfa88e] + - @stackwright/core@0.8.3-alpha.0 + ## 2.0.2 ### Patch Changes diff --git a/packages/maplibre/package.json b/packages/maplibre/package.json index d836055c..b875f90e 100644 --- a/packages/maplibre/package.json +++ b/packages/maplibre/package.json @@ -1,6 +1,6 @@ { "name": "@stackwright/maplibre", - "version": "2.0.2", + "version": "2.0.3-alpha.1", "description": "MapLibre GL adapter for Stackwright maps (free tier, no API keys required)", "license": "MIT", "repository": { diff --git a/packages/mcp/CHANGELOG.md b/packages/mcp/CHANGELOG.md index 7b02720f..80bb20ef 100644 --- a/packages/mcp/CHANGELOG.md +++ b/packages/mcp/CHANGELOG.md @@ -1,5 +1,23 @@ # @stackwright/mcp +## 0.4.4-alpha.1 + +### Patch Changes + +- Updated dependencies [21ed937] + - @stackwright/types@1.4.1-alpha.1 + - @stackwright/cli@0.8.4-alpha.0 + +## 0.4.4-alpha.0 + +### Patch Changes + +- Updated dependencies [f756476] +- Updated dependencies [5cfa88e] +- Updated dependencies [5cfa88e] + - @stackwright/cli@0.8.4-alpha.0 + - @stackwright/types@1.4.1-alpha.0 + ## 0.4.3 ### Patch Changes diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 87bfb46b..7cad0381 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -1,6 +1,6 @@ { "name": "@stackwright/mcp", - "version": "0.4.3", + "version": "0.4.4-alpha.1", "description": "MCP server for Stackwright — exposes content types, page management, and validation as agent tools", "license": "MIT", "repository": { diff --git a/packages/nextjs/CHANGELOG.md b/packages/nextjs/CHANGELOG.md index 303846c6..c3a2ad1b 100644 --- a/packages/nextjs/CHANGELOG.md +++ b/packages/nextjs/CHANGELOG.md @@ -1,5 +1,22 @@ # @stackwright/nextjs +## 0.5.2-alpha.1 + +### Patch Changes + +- Updated dependencies [21ed937] + - @stackwright/types@1.4.1-alpha.1 + - @stackwright/core@0.8.3-alpha.1 + +## 0.5.2-alpha.0 + +### Patch Changes + +- Updated dependencies [5cfa88e] +- Updated dependencies [5cfa88e] + - @stackwright/core@0.8.3-alpha.0 + - @stackwright/types@1.4.1-alpha.0 + ## 0.5.1 ### Patch Changes diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 64a0d410..e1bf1a2a 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@stackwright/nextjs", - "version": "0.5.1", + "version": "0.5.2-alpha.1", "description": "Next.js implementations for Stackwright components", "license": "MIT", "repository": { diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 4da6c809..12aeb312 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,5 +1,31 @@ # @stackwright/types +## 1.4.1-alpha.1 + +### Patch Changes + +- 21ed937: Export `ZodLike` from `@stackwright/types` so plugin authors can reference it by name without index-access workarounds. Also widens `ZodLike.issues[].path` from `(string | number)[]` to `PropertyKey[]` to match Zod v4's actual `$ZodIssue.path` type, fixing a nominal TypeScript incompatibility where real Zod schemas did not satisfy `ZodLike` at the type level. + +## 1.4.1-alpha.0 + +### Patch Changes + +- 5cfa88e: fix(types): remove zod internals from PrebuildPlugin public interface + + `PrebuildPlugin.configSchema` was typed as `z.ZodSchema` and + `contentItemSchemas` as `z.ZodTypeAny[]`. These zod-version-specific + types bled into the published `.d.ts`, causing TypeScript errors in Pro + packages that implemented `PrebuildPlugin` when their installed zod version + differed from what `@stackwright/types` was built with. + + Both fields now use a local structural `ZodLike` interface + (`{ safeParse(data: unknown): { success: boolean; error?: unknown } }`) + which any real Zod schema satisfies via duck-typing. Existing plugin + implementations are unaffected. + + This is the same fix applied to `@stackwright/core`'s `ContentTypeEntry` + in the companion changeset. + ## 1.4.0 ### Minor Changes diff --git a/packages/types/package.json b/packages/types/package.json index 9f3a6d08..629a86a9 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@stackwright/types", - "version": "1.4.0", + "version": "1.4.1-alpha.1", "description": "TypeScript types and JSON schemas for Stackwright", "license": "MIT", "repository": { diff --git a/packages/types/src/types/plugin.ts b/packages/types/src/types/plugin.ts index a9ad9328..4479c3e8 100644 --- a/packages/types/src/types/plugin.ts +++ b/packages/types/src/types/plugin.ts @@ -8,7 +8,24 @@ * TypeScript types from OpenAPI specs during prebuild. */ -import { z } from 'zod'; +/** + * Minimal structural interface used in place of z.ZodTypeAny / z.ZodSchema + * in the PrebuildPlugin public API. + * + * Using a structural interface prevents zod-version-specific internal types + * from bleeding into the published .d.ts. Any real Zod schema satisfies this + * via duck-typing, so existing implementations are unaffected. + */ +export interface ZodLike { + safeParse(data: unknown): + | { success: true } + | { + success: false; + error: { + issues: Array<{ path: PropertyKey[]; message: string }>; + }; + }; +} /** * Plugin context provided to plugin hooks @@ -59,7 +76,7 @@ export interface PrebuildPlugin { * }; * ``` */ - configSchema?: z.ZodSchema; + configSchema?: ZodLike; /** * Additional Zod schemas for content items provided by this plugin. @@ -80,7 +97,7 @@ export interface PrebuildPlugin { * }; * ``` */ - contentItemSchemas?: z.ZodTypeAny[]; + contentItemSchemas?: ZodLike[]; /** * Additional content type key strings recognized by this plugin. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8047d9e4..81928a40 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,7 +29,7 @@ overrides: next: '>=16.1.7' hono: '>=4.12.14' '@hono/node-server': '>=1.19.10' - basic-ftp: '>=5.3.0' + basic-ftp: '>=5.3.1' express-rate-limit: '>=8.2.2' uuid: '>=14.0.0' @@ -176,6 +176,9 @@ importers: js-yaml: specifier: ^4.1.0 version: 4.1.1 + zod: + specifier: ^4.3.6 + version: 4.3.6 devDependencies: '@types/js-yaml': specifier: ^4.0 @@ -198,21 +201,6 @@ importers: '@inquirer/prompts': specifier: ^8.3.0 version: 8.4.1(@types/node@24.12.2) - '@stackwright/build-scripts': - specifier: workspace:* - version: link:../build-scripts - '@stackwright/sbom-generator': - specifier: workspace:* - version: link:../sbom-generator - '@stackwright/scaffold-core': - specifier: workspace:* - version: link:../scaffold-core - '@stackwright/themes': - specifier: workspace:* - version: link:../themes - '@stackwright/types': - specifier: workspace:* - version: link:../types chalk: specifier: ^5.6.2 version: 5.6.2 @@ -232,6 +220,21 @@ importers: specifier: ^4.3.6 version: 4.3.6 devDependencies: + '@stackwright/build-scripts': + specifier: workspace:* + version: link:../build-scripts + '@stackwright/sbom-generator': + specifier: workspace:* + version: link:../sbom-generator + '@stackwright/scaffold-core': + specifier: workspace:* + version: link:../scaffold-core + '@stackwright/themes': + specifier: workspace:* + version: link:../themes + '@stackwright/types': + specifier: workspace:* + version: link:../types '@types/fs-extra': specifier: ^11.0 version: 11.0.4 @@ -3286,8 +3289,8 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - basic-ftp@5.3.0: - resolution: {integrity: sha512-5K9eNNn7ywHPsYnFwjKgYH8Hf8B5emh7JKcPaVjjrMJFQQwGpwowEnZNEtHs7DfR7hCZsmaK3VA4HUK0YarT+w==} + basic-ftp@6.0.1: + resolution: {integrity: sha512-3ilxa3n4276wGQp/ImRAuz4ALdsj/2Wd3FqoZBZlajDYnByCZ0JMb4+26Rde0wGXIbM0G2HWSfr/Fi8b21KX8g==} engines: {node: '>=10.0.0'} better-path-resolve@1.0.0: @@ -8504,7 +8507,7 @@ snapshots: baseline-browser-mapping@2.10.18: {} - basic-ftp@5.3.0: {} + basic-ftp@6.0.1: {} better-path-resolve@1.0.0: dependencies: @@ -9489,7 +9492,7 @@ snapshots: get-uri@6.0.5: dependencies: - basic-ftp: 5.3.0 + basic-ftp: 6.0.1 data-uri-to-buffer: 6.0.2 debug: 4.4.3 transitivePeerDependencies: diff --git a/scripts/sync-versions.mjs b/scripts/sync-versions.mjs new file mode 100644 index 00000000..9e38e9c5 --- /dev/null +++ b/scripts/sync-versions.mjs @@ -0,0 +1,82 @@ +#!/usr/bin/env node +/** + * sync-versions.mjs + * + * Keeps the VERSIONS constant in packages/cli/src/utils/template-processor.ts + * in sync with the actual package versions in the workspace. + * + * Run before cutting a release: + * node scripts/sync-versions.mjs + * + * Or add to the release workflow so stale scaffold templates are caught automatically. + */ + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const root = path.resolve(__dirname, '..'); + +/** Read a package.json and return its version string. */ +function readVersion(packageDir) { + const pkgPath = path.join(root, 'packages', packageDir, 'package.json'); + if (!fs.existsSync(pkgPath)) return null; + const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + return pkg.version ?? null; +} + +/** Convert a semver like "0.8.2" to a conservative range "^0.8.0". */ +function toRange(version) { + const [major, minor] = version.split('.'); + return `^${major}.${minor}.0`; +} + +// Map from VERSIONS key → workspace package directory name +const PACKAGE_MAP = { + swCore: 'core', + swNextjs: 'nextjs', + swIcons: 'icons', + swBuildScripts: 'build-scripts', + swUiShadcn: 'ui-shadcn', + swOtters: 'otters', +}; + +// Resolve current versions +const updates = {}; +for (const [key, dir] of Object.entries(PACKAGE_MAP)) { + const version = readVersion(dir); + if (!version) { + console.warn(` ⚠️ Could not read version for ${dir} — skipping`); + continue; + } + updates[key] = { version, range: toRange(version) }; +} + +// Read template-processor.ts +const TARGET = path.join(root, 'packages', 'cli', 'src', 'utils', 'template-processor.ts'); +let src = fs.readFileSync(TARGET, 'utf8'); + +// Apply each update with a targeted regex per key +let changed = false; +for (const [key, { range, version }] of Object.entries(updates)) { + // Matches: swCore: '^0.7.0', or swCore: "^0.7.0", + const pattern = new RegExp(`(${key}:\\s*)['"]([^'"]+)['"]`); + const newSrc = src.replace(pattern, `$1'${range}'`); + if (newSrc !== src) { + const oldMatch = src.match(pattern); + const oldRange = oldMatch ? oldMatch[2] : '(unknown)'; + console.log(` ${key}: '${oldRange}' → '${range}' (from ${version})`); + src = newSrc; + changed = true; + } else { + console.log(` ${key}: already '${range}' ✓`); + } +} + +if (changed) { + fs.writeFileSync(TARGET, src, 'utf8'); + console.log('\n✅ template-processor.ts updated.'); +} else { + console.log('\n✅ All versions already in sync — no changes needed.'); +}