Repository navigation
feat(core,devtools): compose core extension Prisma models and migrations at build - #707
seanspeaks wants to merge 3 commits into
Conversation
…ons at build
A core extension could declare a Prisma schema (coreExtensions[].schema),
but nothing put its models into the generated client or created its
tables: getExtensionSchemaPaths and composeSchemas were never called. So
every prisma.<model> an extension used was undefined at runtime (the
db-credentials extension's /admin/oauth-credentials answered 500) and
its encrypted fields were registered for a model the client did not have.
core/extensions/prisma-composer.js, for each database the app uses:
- keeps the pristine core schema as schema.base.prisma and writes
base + the extensions' models to prisma-<db>/schema.prisma, so a second
run appends nothing and removing an extension restores the base;
- refuses an extension model that redeclares a core model or another
extension's;
- PostgreSQL: copies coreExtensions[].migrations (new, a directory of
<timestamp>_<name>/migration.sql) beside core's migrations, refusing a
same-named migration with different SQL;
- runs prisma generate when the schema changed or the client is stale.
coreExtensions[].schema may now be { postgresql, mongodb } paths, since a
model written for one database does not compile for the other.
devtools runs it on the backend's installed core in the Netlify build
(provider-build.js), the AWS build (infrastructure-composer.js, which
also invalidates a Prisma layer built from the old client) and
`frigg db:setup`. With no extension declaring a schema it is a no-op.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HyrF4oqcTdK2AtvcrocxE6
There was a problem hiding this comment.
If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.
Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 2702ff3. Configure here.
…hema The composer skipped a database with no extension schema before copying migrations, so an extension that ships only SQL (Bugbot on #707) never had its migration folders put beside core's and its tables were never created. Migrations are now copied first; the schema and client are still left as shipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HyrF4oqcTdK2AtvcrocxE6
|
The 5 extra passing tests are this PR's new Generated by Claude Code |
The bootstrap only patched modules reached through integrations[].Definition.modules, so a module declared only in appDefinition.entities (e.g. google) never read its DB credentials. It also used a record with isActive: false. Collect definitions from both places (each wrapped once) and fall back to the static env for an inactive record. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HyrF4oqcTdK2AtvcrocxE6
|




Stacked on #690.
Problem
A core extension can declare a Prisma schema (
coreExtensions[].schema), but nothing ever put its models into the generated client or created its tables.getExtensionSchemaPathsandcomposeSchemasexisted and were never called. So:prisma.<model>an extension uses isundefinedat runtime;For example, the db-credentials extension's
/admin/oauth-credentialsanswers 500 on every request.Change
core/extensions/prisma-composer.jshandles each database the app uses:schema.base.prisma. It then writes base + the extensions' models toprisma-<db>/schema.prisma.coreExtensions[].migrations, takes a directory of<timestamp>_<name>/migration.sql. The composer copies them beside core's migrations, soprisma migrate deployapplies them in order with core's. It refuses a same-named migration with different SQL. Copied migrations are never removed, because an applied one must stay in the history.prisma generatewhen the schema changed or the generated client is stale.coreExtensions[].schemamay now be{ postgresql, mongodb }paths, because a model written for one database does not compile for the other.devtools runs the composer on the backend's installed core in three places:
provider-build.js);infrastructure-composer.js), which also invalidates a Prisma layer built from the old client;frigg db:setup.It is a no-op when no extension declares a schema.
The extension's encrypted fields need nothing new.
loadExtensionEncryptionSchemasalready registered them; with the model now in the client, they go through the same Prisma encryption extension asCredential.Tests
core/extensions/__tests__/prisma-composer.test.jscovers:prisma generateand asserts the client exposes the extension model.extension-loader.test.jsadds validation of the newschemaandmigrationsforms.devtools/infrastructure/__tests__/compose-extension-prisma.test.jschecks that composition runs on the backend's core, not devtools' copy, and thatbuildWithProvidercomposes before writing files and not after a failed validation.buildWithProvidercall fails 1.oAuthAppCredentialand the rhel engine.The pre-existing failures in
infrastructure-composer.test.jsare unchanged: 44 failing on the base, 44 with this change.Generated by Claude Code
Note
Medium Risk
Changes how Prisma schemas and migrations are assembled at build/deploy time; mistakes could break client generation or migration ordering, though guards exist for duplicate models and conflicting migration SQL.
Overview
Adds build-time Prisma composition so core extensions that declare
coreExtensions[].schemaandcoreExtensions[].migrationsactually land in the generated client and PostgreSQL migration history. NewcomposeExtensionPrismakeeps a pristineschema.base.prisma, merges extension models (with clash checks), copies extension migration folders on PostgreSQL, and runsprisma generatewhen the schema or client is stale.Extension config now accepts per-database schema paths (
{ postgresql, mongodb }) and amigrationsdirectory string, with validation inextension-loader. Devtools runs composition against the backend’s installed@friggframework/coreduring Netlifyprovider-build, AWSinfrastructure-composer(invalidating a stale Prisma Lambda layer when the client changes), andfrigg db:setup.The db-credentials bootstrap now wraps OAuth
envloaders for modules fromappDefinition.entitiesas well as integrations, ignores inactive DB credentials (isActive === false), and still dedupes shared definitions.Reviewed by Cursor Bugbot for commit df52379. Bugbot is set up for automated code reviews on this repo. Configure here.
📦 Published PR as canary version:
2.0.0--canary.707.df52379.0✨ Test out this PR locally via:
npm install @friggframework/admin-scripts@2.0.0--canary.707.df52379.0 npm install @friggframework/core@2.0.0--canary.707.df52379.0 npm install @friggframework/devtools@2.0.0--canary.707.df52379.0 npm install @friggframework/eslint-config@2.0.0--canary.707.df52379.0 npm install @friggframework/extension-db-credentials@2.0.0--canary.707.df52379.0 npm install @friggframework/prettier-config@2.0.0--canary.707.df52379.0 npm install @friggframework/provider-aws@2.0.0--canary.707.df52379.0 npm install @friggframework/provider-netlify@2.0.0--canary.707.df52379.0 npm install @friggframework/schemas@2.0.0--canary.707.df52379.0 npm install @friggframework/serverless-plugin@2.0.0--canary.707.df52379.0 npm install @friggframework/test@2.0.0--canary.707.df52379.0 npm install @friggframework/ui@2.0.0--canary.707.df52379.0 # or yarn add @friggframework/admin-scripts@2.0.0--canary.707.df52379.0 yarn add @friggframework/core@2.0.0--canary.707.df52379.0 yarn add @friggframework/devtools@2.0.0--canary.707.df52379.0 yarn add @friggframework/eslint-config@2.0.0--canary.707.df52379.0 yarn add @friggframework/extension-db-credentials@2.0.0--canary.707.df52379.0 yarn add @friggframework/prettier-config@2.0.0--canary.707.df52379.0 yarn add @friggframework/provider-aws@2.0.0--canary.707.df52379.0 yarn add @friggframework/provider-netlify@2.0.0--canary.707.df52379.0 yarn add @friggframework/schemas@2.0.0--canary.707.df52379.0 yarn add @friggframework/serverless-plugin@2.0.0--canary.707.df52379.0 yarn add @friggframework/test@2.0.0--canary.707.df52379.0 yarn add @friggframework/ui@2.0.0--canary.707.df52379.0