Skip to content

Version Packages#343

Merged
borisno2 merged 1 commit intomainfrom
changeset-release/main
Mar 3, 2026
Merged

Version Packages#343
borisno2 merged 1 commit intomainfrom
changeset-release/main

Conversation

@github-actions
Copy link
Contributor

@github-actions github-actions bot commented Feb 22, 2026

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

@opensaas/stack-cli@0.19.0

Minor Changes

  • #346 aa5edec Thanks @borisno2! - Improve KeystoneJS migration guidance for virtual fields and context.graphql patterns

    The Keystone migration guide now covers two areas that require changes beyond a simple import swap:

    Virtual fields — detected automatically; the generated guide shows how to replace graphql.field({ resolve }) with hooks: { resolveOutput } and a type declaration:

    - fullName: virtual({
    -   field: graphql.field({
    -     type: graphql.String,
    -     resolve: (item) => `${item.firstName} ${item.lastName}`,
    -   }),
    - })
    + fullName: virtual({
    +   type: 'string',
    +   hooks: {
    +     resolveOutput: ({ item }) => `${item.firstName} ${item.lastName}`,
    +   },
    + })

    context.graphql calls — the guide now includes a step showing how to replace context.graphql.run() and context.query.* with context.db.{listName}.{method}():

    - const { posts } = await context.graphql.run({
    -   query: `query { posts(where: { status: { equals: published } }) { id title } }`,
    - })
    + const posts = await context.db.post.findMany({
    +   where: { status: { equals: 'published' } },
    + })

    The introspector warning for virtual fields is also updated to give clearer guidance.

  • #348 5410cb6 Thanks @borisno2! - Add db.type: 'enum' support to the select field for native database enum storage

    The select field now supports db.type: 'enum' to store values as a native Prisma enum type rather than a plain string. This generates an enum block in the Prisma schema and uses the enum type in the model, matching Keystone 6's enum select behaviour.

    import { select } from '@opensaas/stack-core/fields'
    
    lists: {
      Post: list({
        fields: {
          status: select({
            options: [
              { label: 'Draft', value: 'draft' },
              { label: 'Published', value: 'published' },
              { label: 'Archived', value: 'archived' },
            ],
            db: { type: 'enum' },   // generates a Prisma enum
            defaultValue: 'draft',
          }),
        },
      }),
    }

    This generates the following Prisma schema:

    enum PostStatus {
      draft
      published
      archived
    }
    
    model Post {
      id        String     @id @default(cuid())
      status    PostStatus @default(draft)
      createdAt DateTime   @default(now())
      updatedAt DateTime   @default(now()) @updatedAt
    }

    Notes:

    • The enum name is derived from <ListName><FieldName> in PascalCase (e.g. PostStatus, UserRole)
    • Default values use unquoted Prisma enum syntax (@default(draft) not @default("draft"))
    • Enum option values must be valid Prisma identifiers: start with a letter, contain only letters, digits, and underscores (e.g. in_progress is valid, in-progress is not)
    • The TypeScript union type ('draft' | 'published') is generated identically to a string select field
    • Omitting db.type or setting db.type: 'string' (the default) preserves the existing String column behaviour
  • #342 94b0df6 Thanks @borisno2! - Improve KeystoneJS migration agent with side-by-side examples and targeted update guidance

    The Keystone migration wizard and agent now produce a targeted migration guide instead of
    regenerating the entire config. Since Keystone and OpenSaaS Stack share the same
    list()/field/hook/access API, only imports, the database adapter config, and auth setup
    need to change.

    Key improvements:

    • The migration agent prompt now includes side-by-side Keystone vs OpenSaaS examples for
      config structure, imports, access control, hooks, auth, and many-to-many join tables
    • The wizard uses a minimal fast-path for Keystone projects (just 3 questions: db provider,
      auth, auth methods) instead of the full question flow
    • The generator produces a diff-style migration guide for Keystone showing exactly what to
      change, rather than regenerating list definitions the user already has
    • Many-to-many join table naming is now surfaced automatically when M2M relations are
      detected, with joinTableNaming: 'keystone' guidance to preserve existing data

Patch Changes

  • #345 c815d2f Thanks @borisno2! - Fix migrate --with-ai generating path instead of repo in Claude marketplace settings

  • #345 c815d2f Thanks @borisno2! - Fix broken migration guide URL in migrate console output (missing /docs prefix)

  • #352 bd41b1e Thanks @borisno2! - Fix singleton lists to use Int @id @default(1) matching Keystone 6 behaviour

    Singleton lists now generate Int @id @default(1) in the Prisma schema instead of
    String @id @default(cuid()). This matches Keystone 6's behaviour where singleton
    records always use integer primary key 1, making migration from Keystone 6 straightforward
    without data loss.

    Migration guide for existing singleton lists:

    If you have an existing database with singleton models that use String @id, you will need
    to run an SQL migration to convert the id column from text to integer:

    -- Example for PostgreSQL (adjust table name as needed)
    ALTER TABLE "EmailSettings" ALTER COLUMN id TYPE INTEGER USING id::integer;
    UPDATE "EmailSettings" SET id = 1;

    For SQLite (which does not support ALTER COLUMN):

    -- Recreate the table with Int id
    CREATE TABLE "EmailSettings_new" (id INTEGER PRIMARY KEY DEFAULT 1, ...);
    INSERT INTO "EmailSettings_new" SELECT 1, ... FROM "EmailSettings";
    DROP TABLE "EmailSettings";
    ALTER TABLE "EmailSettings_new" RENAME TO "EmailSettings";

    New projects and fresh databases will work automatically without any migration steps.
    Fixes Breaking migration: isSingleton models change primary key from Int (1) to String (cuid) #350.

  • #344 c259030 Thanks @borisno2! - Fix updatedAt field to include @default(now()) in generated Prisma schema to prevent migration failures on databases with existing data

  • Updated dependencies [bd41b1e, 28f2834, 5410cb6]:

    • @opensaas/stack-core@0.19.0

@opensaas/stack-core@0.19.0

Minor Changes

  • #353 28f2834 Thanks @borisno2! - Add db.isNullable and db.nativeType support to all field types

    All field types now support two new db configuration options that were previously only available in Keystone 6:

    db.isNullable

    Controls DB-level nullability independently of validation.isRequired. This allows you to:

    • Make a field non-nullable at the DB level without making it API-required
    • Explicitly mark a field as nullable regardless of other settings
    fields: {
      // DB non-nullable, but API optional (relies on a default value or hook)
      phoneNumber: text({
        db: { isNullable: false }
        // Generates: phoneNumber String (non-nullable)
      }),
    
      // DB nullable, explicitly set
      lastMessagePreview: text({
        db: { isNullable: true }
        // Generates: lastMessagePreview String? (nullable)
      }),
    
      // DB non-nullable without API validation (field must always be set via hooks or defaults)
      internalCode: integer({
        db: { isNullable: false }
        // Generates: internalCode Int (non-nullable)
      })
    }

    db.nativeType

    Overrides the native database column type. Generates a @db.<nativeType> attribute in the Prisma schema. Available types depend on your database provider.

    fields: {
      // PostgreSQL: use TEXT instead of VARCHAR for long content
      medical: text({
        db: { isNullable: true, nativeType: 'Text' }
        // Generates: medical String? @db.Text
      }),
    
      // PostgreSQL: use SMALLINT for small numbers
      score: integer({
        db: { nativeType: 'SmallInt' }
        // Generates: score Int? @db.SmallInt
      }),
    
      // PostgreSQL: use TIMESTAMPTZ for timezone-aware timestamps
      scheduledAt: timestamp({
        db: { nativeType: 'Timestamptz' }
        // Generates: scheduledAt DateTime? @db.Timestamptz
      })
    }

    Both options are supported on text, integer, password, json, timestamp, checkbox (isNullable only), decimal, and calendarDay fields.

  • #348 5410cb6 Thanks @borisno2! - Add db.type: 'enum' support to the select field for native database enum storage

    The select field now supports db.type: 'enum' to store values as a native Prisma enum type rather than a plain string. This generates an enum block in the Prisma schema and uses the enum type in the model, matching Keystone 6's enum select behaviour.

    import { select } from '@opensaas/stack-core/fields'
    
    lists: {
      Post: list({
        fields: {
          status: select({
            options: [
              { label: 'Draft', value: 'draft' },
              { label: 'Published', value: 'published' },
              { label: 'Archived', value: 'archived' },
            ],
            db: { type: 'enum' },   // generates a Prisma enum
            defaultValue: 'draft',
          }),
        },
      }),
    }

    This generates the following Prisma schema:

    enum PostStatus {
      draft
      published
      archived
    }
    
    model Post {
      id        String     @id @default(cuid())
      status    PostStatus @default(draft)
      createdAt DateTime   @default(now())
      updatedAt DateTime   @default(now()) @updatedAt
    }

    Notes:

    • The enum name is derived from <ListName><FieldName> in PascalCase (e.g. PostStatus, UserRole)
    • Default values use unquoted Prisma enum syntax (@default(draft) not @default("draft"))
    • Enum option values must be valid Prisma identifiers: start with a letter, contain only letters, digits, and underscores (e.g. in_progress is valid, in-progress is not)
    • The TypeScript union type ('draft' | 'published') is generated identically to a string select field
    • Omitting db.type or setting db.type: 'string' (the default) preserves the existing String column behaviour

Patch Changes

  • #352 bd41b1e Thanks @borisno2! - Fix singleton lists to use Int @id @default(1) matching Keystone 6 behaviour

    Singleton lists now generate Int @id @default(1) in the Prisma schema instead of
    String @id @default(cuid()). This matches Keystone 6's behaviour where singleton
    records always use integer primary key 1, making migration from Keystone 6 straightforward
    without data loss.

    Migration guide for existing singleton lists:

    If you have an existing database with singleton models that use String @id, you will need
    to run an SQL migration to convert the id column from text to integer:

    -- Example for PostgreSQL (adjust table name as needed)
    ALTER TABLE "EmailSettings" ALTER COLUMN id TYPE INTEGER USING id::integer;
    UPDATE "EmailSettings" SET id = 1;

    For SQLite (which does not support ALTER COLUMN):

    -- Recreate the table with Int id
    CREATE TABLE "EmailSettings_new" (id INTEGER PRIMARY KEY DEFAULT 1, ...);
    INSERT INTO "EmailSettings_new" SELECT 1, ... FROM "EmailSettings";
    DROP TABLE "EmailSettings";
    ALTER TABLE "EmailSettings_new" RENAME TO "EmailSettings";

    New projects and fresh databases will work automatically without any migration steps.
    Fixes Breaking migration: isSingleton models change primary key from Int (1) to String (cuid) #350.

@opensaas/stack-auth@0.19.0

@opensaas/stack-rag@0.19.0

@opensaas/stack-storage@0.19.0

@opensaas/stack-storage-s3@0.19.0

@opensaas/stack-storage-vercel@0.19.0

@opensaas/stack-tiptap@0.19.0

@opensaas/stack-ui@0.19.0

@vercel
Copy link

vercel bot commented Feb 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stack-docs Ready Ready Preview, Comment Mar 3, 2026 10:09am

@github-actions github-actions bot force-pushed the changeset-release/main branch from 80466e4 to 7e792c7 Compare March 3, 2026 10:08
@borisno2 borisno2 merged commit 9fb71bc into main Mar 3, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Breaking migration: isSingleton models change primary key from Int (1) to String (cuid)

1 participant