refactor: consolidate and reorganize packages per ADR-0026/0027/0028#60
Merged
Conversation
…sma-cloud Boundary at the user's one real choice (where does it run): core absorbs CLI, assemble, and the target-agnostic authoring surfaces (/rpc /node /nextjs as subpaths); compose-prisma-cloud carries the target plus first-party modules as entrypoints (/cron) — module is a role, not an artifact, per the ADR-0025 register model, and cron's scheduler is a Prisma Cloud compute service anyway. No unscoped bin wrapper. Naming conventions: compose-* in-scope, prisma-compose-* outside, targets carry their full name (the compose-prisma-cloud stutter is deliberate). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Private workspace packages are unconstrained — internal seams are free; names users install are not. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…rced Adopt Prisma Next's Domains/Layers/Planes organization with a 9-public twist: 0-framework (imports nothing), 1-prisma-cloud (imports framework), 9-public (the only publishable packages, a sink; examples import only these). The numbering is the ruleset. Planes adopted now as entrypoint-mapped globs — they name ADR-0017's existing control/ execution split, not a directory axis. Internals are @internal/* (unscoped internal/x verified fatal at Node ESM runtime). Public packages bundle internal deps at build. Enforced by dependency-cruiser from architecture.config.json via pnpm lint:deps. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…R-0027/0028)
packages/ is reorganized into numbered domains and layers:
0-framework/{0-foundation,1-core,2-authoring,3-tooling}
1-prisma-cloud/{0-lowering,1-extensions,2-modules}
9-public/{compose,compose-prisma-cloud}
Every internal package is @internal/<name> with "private": true (foundation,
tsdown-config, core, rpc, node, nextjs, assemble, cli, lowering, prisma-cloud,
cron). casts/assertions split out of core into @internal/foundation; cron split
out of the cloud extensions into @internal/cron; the unscoped prisma-compose
wrapper package is deleted (ADR-0027: no unscoped wrapper — npx @prisma/compose
runs the bin).
Exactly two publishable packages, both in 9-public:
- @prisma/compose — the prisma-compose bin, core at the root, and subpaths
./config ./deploy ./testing ./casts ./assertions ./rpc ./node(/control)
./nextjs(/control). Bundles its @internal deps at build time (tsdown
noExternal on the @internal scope); the tarball is self-contained.
- @prisma/compose-prisma-cloud — the target at the root (+ ./control,
./prisma-next, ./testing) and ./cron(/scheduler-entrypoint). Cloud-domain
internals are inlined; framework imports are rewritten to @prisma/compose
subpaths and left external (a resolve hook + a post-build dts rewrite), so
one framework copy exists at runtime and type identity holds (the node brand
is a unique symbol — two bundled declaration copies would not unify).
Examples and the integration test import only the two public packages (+ their
subpaths); the extension routing ids follow the public identities
(@prisma/compose/node, @prisma/compose/nextjs, @prisma/compose-prisma-cloud).
Versions restart at 0.1.0 lockstep — the old names were unpublished 2026-07-12
and the new names have never been published. bun.lock regenerated (bun does not
resolve the nested workspace globs; it tracks the root only and no CI uses it).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…er (ADR-0028)
architecture.config.json maps directory globs to {domain, layer, plane};
dependency-cruiser.config.mjs derives the forbidden rules from it — copied
from Prisma Next's implementation (Package-Layering + ADR 140) with two
additions: 9-public is a sink (no internal package imports it), and examples
plus the integration tests may import only the 9-public packages.
Rules: lower numbers importable by higher, never the reverse (domains and
layers); lateral same-layer imports allowed; control and execution planes
never import each other, both may import shared (ADR-0017), mapped
per-entrypoint. One declared cross-domain exception: the CLI's pre-stack
container-ensure step imports @internal/lowering — known, documented debt.
Package specifiers alias to workspace sources via tsconfig.depcruise.json
paths (exports maps point at dist, which is excluded from the cruise). Wired
as pnpm lint:deps, in CI after the Biome check, and in lint-staged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The retired @prisma/compose-* per-capability names become their ADR-0027
homes across README, docs/design, skills, SECURITY, and the integration-test
README: compose-cloud → @prisma/compose-prisma-cloud; compose-{node,nextjs,
rpc} → @prisma/compose subpaths; compose-{assemble,cli,alchemy,tsdown} →
their @internal/* names. versioning.md now records the two-package publish
surface. ADR-0026/0027 keep the old names as the rename record; ADR-0027/0028
cross-links retargeted to ADR-0014-one-authoring-primitive.md. .drive process
history untouched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The generic .config. exclude was silently skipping the examples' prisma-compose.config.ts files — exactly the user-facing imports that pull /control extensions into a deploy (ADR-0017) — and the /testing/fake and example-test excludes skipped more user-visible import surface. Build-tool configs are now excluded by name (tsdown/vitest/next), package-internal tests stay excluded (they legitimately cross plane boundaries), and everything under examples/ and test/ is cruised. 180→191 modules, 308→346 edges, still zero violations; a planted @internal import in an example config fails the examples-import-public-only rule. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
commit: |
wmadden
approved these changes
Jul 12, 2026
- packages/1-prisma-cloud/1-extensions/prisma-cloud → …/1-extensions/target — the leaf said the domain name twice; the package IS the Prisma Cloud target extension. Package name stays @internal/prisma-cloud. - packages/1-prisma-cloud/2-modules → 2-shared-modules — "modules" alone was underqualified for the layer holding first-party modules realized on this target; ADR-0028 tree sketch updated to match. - scripts/lint-publishable-location.mjs: every workspace package outside packages/9-public/ must be "private": true, and everything inside 9-public must be publishable — ADR-0027 made mechanical. Wired into pnpm lint:deps (so also lint-staged and CI). Verified both directions: flipping @internal/cron non-private fails the gate; 20 manifests checked clean. - Internal repository.directory fields updated to the real paths (were stale from the manifest restore). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the package rename, consolidation, and reorganization designed in ADR-0026, ADR-0027, and ADR-0028. Carries #59's ADR-0027/0028 docs (cherry-picked; this PR subsumes #59).
The workspace shape (ADR-0028)
All internals are
@internal/*+"private": true. Exactly two publishable packages, verified by the publish gate (check:publish-depsfinds exactly 2) andnpm pack --dry-runon each (no@internal/*in any published dependency field or dist import).Public surface (ADR-0027)
@prisma/compose:prisma-composebin, core at root, subpaths./config./deploy./testing./casts./assertions./rpc./node(/control)./nextjs(/control). Internals inlined at build (tsdownnoExternalon the@internalscope).@prisma/compose-prisma-cloud: target at root +./control./prisma-next./testing./cron(/scheduler-entrypoint). Cloud internals inlined; framework imports rewritten to@prisma/composesubpaths and left external (resolve hook + post-build dts rewrite) so one framework copy exists at runtime and type identity holds — core's node brand is aunique symbol; two bundled declaration copies would not unify (found empirically: the storefront example failed to typecheck against a bundled-framework cloud package).packages/prisma-composedeleted.@prisma/compose/node,@prisma/compose/nextjs,@prisma/compose-prisma-cloud.Enforcement (ADR-0028)
architecture.config.json(globs →{domain, layer, plane}) +dependency-cruiser.config.mjscopied from prisma-next's shape. Downward-only across domains and layers; lateral allowed; 9-public is a sink; examples + integration tests import only 9-public; control/execution planes never import each other (ADR-0017), mapped per-entrypoint. Wired aspnpm lint:deps, in CI, and in lint-staged. Currently:✔ no dependency violations (180 modules, 308 dependencies).Judgment calls
0-framework/3-toolingwith one declared cross-domain exception (cli →@internal/lowering): the pre-stack container-ensure step (Project/Branch resolution) is Prisma Cloud-specific today. Known debt, documented in the config's exception entry, rather than moving the CLI into the cloud domain (ADR-0027 puts the bin in@prisma/compose).serializer.tsclassified shared, not control — the cruiser corrected the initial guess: the authoring surface (index/compute/testing) imports it..d.mts. Building publics straight from cross-package TS sources broke rolldown-plugin-dts three different ways (anonymous default re-exports, Effect-heavy files failing isolated-declaration emit,eagersegfaulting).@prisma/composepublic exports keep./config./deploy./testing./casts./assertionsbeyond ADR-0027's enumerated./rpc./node./nextjs— examples and user configs (prisma-compose.config.tsimportsdefineConfigfrom@prisma/compose/config) need them.@internal/foundation); cloud's updated for cron's move.grep "Prisma App Framework"→ zero.bun.lockregenerated — bun doesn't resolve the nested workspace globs, so it now tracks the root only; nothing in CI uses it.Acceptance
pnpm build(17) /typecheck(36) /test(29) /test:types(20) /lint/lint:deps— all green.@prisma/compose/@prisma/compose-prisma-cloud(+ subpaths) — enforced by the cruiser from now on.🤖 Generated with Claude Code