|
1 | 1 | # @opensaas/stack-cli |
2 | 2 |
|
| 3 | +## 0.19.0 |
| 4 | + |
| 5 | +### Minor Changes |
| 6 | + |
| 7 | +- [#346](https://github.com/OpenSaasAU/stack/pull/346) [`aa5edec`](https://github.com/OpenSaasAU/stack/commit/aa5edecfbd2fc2dcab67479088d4c6ff2dd24600) Thanks [@borisno2](https://github.com/borisno2)! - Improve KeystoneJS migration guidance for virtual fields and context.graphql patterns |
| 8 | + |
| 9 | + The Keystone migration guide now covers two areas that require changes beyond a simple import swap: |
| 10 | + |
| 11 | + **Virtual fields** — detected automatically; the generated guide shows how to replace `graphql.field({ resolve })` with `hooks: { resolveOutput }` and a `type` declaration: |
| 12 | + |
| 13 | + ```diff |
| 14 | + - fullName: virtual({ |
| 15 | + - field: graphql.field({ |
| 16 | + - type: graphql.String, |
| 17 | + - resolve: (item) => `${item.firstName} ${item.lastName}`, |
| 18 | + - }), |
| 19 | + - }) |
| 20 | + + fullName: virtual({ |
| 21 | + + type: 'string', |
| 22 | + + hooks: { |
| 23 | + + resolveOutput: ({ item }) => `${item.firstName} ${item.lastName}`, |
| 24 | + + }, |
| 25 | + + }) |
| 26 | + ``` |
| 27 | + |
| 28 | + **context.graphql calls** — the guide now includes a step showing how to replace `context.graphql.run()` and `context.query.*` with `context.db.{listName}.{method}()`: |
| 29 | + |
| 30 | + ```diff |
| 31 | + - const { posts } = await context.graphql.run({ |
| 32 | + - query: `query { posts(where: { status: { equals: published } }) { id title } }`, |
| 33 | + - }) |
| 34 | + + const posts = await context.db.post.findMany({ |
| 35 | + + where: { status: { equals: 'published' } }, |
| 36 | + + }) |
| 37 | + ``` |
| 38 | + |
| 39 | + The introspector warning for virtual fields is also updated to give clearer guidance. |
| 40 | + |
| 41 | +- [#348](https://github.com/OpenSaasAU/stack/pull/348) [`5410cb6`](https://github.com/OpenSaasAU/stack/commit/5410cb604198e087762e39c8aec87fe3736d8c01) Thanks [@borisno2](https://github.com/borisno2)! - Add `db.type: 'enum'` support to the `select` field for native database enum storage |
| 42 | + |
| 43 | + 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. |
| 44 | + |
| 45 | + ```typescript |
| 46 | + import { select } from '@opensaas/stack-core/fields' |
| 47 | + |
| 48 | + lists: { |
| 49 | + Post: list({ |
| 50 | + fields: { |
| 51 | + status: select({ |
| 52 | + options: [ |
| 53 | + { label: 'Draft', value: 'draft' }, |
| 54 | + { label: 'Published', value: 'published' }, |
| 55 | + { label: 'Archived', value: 'archived' }, |
| 56 | + ], |
| 57 | + db: { type: 'enum' }, // generates a Prisma enum |
| 58 | + defaultValue: 'draft', |
| 59 | + }), |
| 60 | + }, |
| 61 | + }), |
| 62 | + } |
| 63 | + ``` |
| 64 | + |
| 65 | + This generates the following Prisma schema: |
| 66 | + |
| 67 | + ```prisma |
| 68 | + enum PostStatus { |
| 69 | + draft |
| 70 | + published |
| 71 | + archived |
| 72 | + } |
| 73 | +
|
| 74 | + model Post { |
| 75 | + id String @id @default(cuid()) |
| 76 | + status PostStatus @default(draft) |
| 77 | + createdAt DateTime @default(now()) |
| 78 | + updatedAt DateTime @default(now()) @updatedAt |
| 79 | + } |
| 80 | + ``` |
| 81 | + |
| 82 | + **Notes:** |
| 83 | + - The enum name is derived from `<ListName><FieldName>` in PascalCase (e.g. `PostStatus`, `UserRole`) |
| 84 | + - Default values use unquoted Prisma enum syntax (`@default(draft)` not `@default("draft")`) |
| 85 | + - 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) |
| 86 | + - The TypeScript union type (`'draft' | 'published'`) is generated identically to a string select field |
| 87 | + - Omitting `db.type` or setting `db.type: 'string'` (the default) preserves the existing `String` column behaviour |
| 88 | + |
| 89 | +- [#342](https://github.com/OpenSaasAU/stack/pull/342) [`94b0df6`](https://github.com/OpenSaasAU/stack/commit/94b0df65c860348441200d914dbf37bda3bd25cf) Thanks [@borisno2](https://github.com/borisno2)! - Improve KeystoneJS migration agent with side-by-side examples and targeted update guidance |
| 90 | + |
| 91 | + The Keystone migration wizard and agent now produce a targeted migration guide instead of |
| 92 | + regenerating the entire config. Since Keystone and OpenSaaS Stack share the same |
| 93 | + `list()`/field/hook/access API, only imports, the database adapter config, and auth setup |
| 94 | + need to change. |
| 95 | + |
| 96 | + Key improvements: |
| 97 | + - The migration agent prompt now includes side-by-side Keystone vs OpenSaaS examples for |
| 98 | + config structure, imports, access control, hooks, auth, and many-to-many join tables |
| 99 | + - The wizard uses a minimal fast-path for Keystone projects (just 3 questions: db provider, |
| 100 | + auth, auth methods) instead of the full question flow |
| 101 | + - The generator produces a diff-style migration guide for Keystone showing exactly what to |
| 102 | + change, rather than regenerating list definitions the user already has |
| 103 | + - Many-to-many join table naming is now surfaced automatically when M2M relations are |
| 104 | + detected, with `joinTableNaming: 'keystone'` guidance to preserve existing data |
| 105 | + |
| 106 | +### Patch Changes |
| 107 | + |
| 108 | +- [#345](https://github.com/OpenSaasAU/stack/pull/345) [`c815d2f`](https://github.com/OpenSaasAU/stack/commit/c815d2f02a81b16189e8eea0e635ea1aa0a1d6ec) Thanks [@borisno2](https://github.com/borisno2)! - Fix `migrate --with-ai` generating `path` instead of `repo` in Claude marketplace settings |
| 109 | + |
| 110 | +- [#345](https://github.com/OpenSaasAU/stack/pull/345) [`c815d2f`](https://github.com/OpenSaasAU/stack/commit/c815d2f02a81b16189e8eea0e635ea1aa0a1d6ec) Thanks [@borisno2](https://github.com/borisno2)! - Fix broken migration guide URL in `migrate` console output (missing `/docs` prefix) |
| 111 | + |
| 112 | +- [#352](https://github.com/OpenSaasAU/stack/pull/352) [`bd41b1e`](https://github.com/OpenSaasAU/stack/commit/bd41b1e75b78c2e9748422352e6a500ed26df4e9) Thanks [@borisno2](https://github.com/borisno2)! - Fix singleton lists to use `Int @id @default(1)` matching Keystone 6 behaviour |
| 113 | + |
| 114 | + Singleton lists now generate `Int @id @default(1)` in the Prisma schema instead of |
| 115 | + `String @id @default(cuid())`. This matches Keystone 6's behaviour where singleton |
| 116 | + records always use integer primary key `1`, making migration from Keystone 6 straightforward |
| 117 | + without data loss. |
| 118 | + |
| 119 | + **Migration guide for existing singleton lists:** |
| 120 | + |
| 121 | + If you have an existing database with singleton models that use `String @id`, you will need |
| 122 | + to run an SQL migration to convert the id column from text to integer: |
| 123 | + |
| 124 | + ```sql |
| 125 | + -- Example for PostgreSQL (adjust table name as needed) |
| 126 | + ALTER TABLE "EmailSettings" ALTER COLUMN id TYPE INTEGER USING id::integer; |
| 127 | + UPDATE "EmailSettings" SET id = 1; |
| 128 | + ``` |
| 129 | + |
| 130 | + For SQLite (which does not support ALTER COLUMN): |
| 131 | + |
| 132 | + ```sql |
| 133 | + -- Recreate the table with Int id |
| 134 | + CREATE TABLE "EmailSettings_new" (id INTEGER PRIMARY KEY DEFAULT 1, ...); |
| 135 | + INSERT INTO "EmailSettings_new" SELECT 1, ... FROM "EmailSettings"; |
| 136 | + DROP TABLE "EmailSettings"; |
| 137 | + ALTER TABLE "EmailSettings_new" RENAME TO "EmailSettings"; |
| 138 | + ``` |
| 139 | + |
| 140 | + New projects and fresh databases will work automatically without any migration steps. |
| 141 | + Fixes #350. |
| 142 | + |
| 143 | +- [#344](https://github.com/OpenSaasAU/stack/pull/344) [`c259030`](https://github.com/OpenSaasAU/stack/commit/c259030dab3cdc641a9f40dd21746a1bd46fb76d) Thanks [@borisno2](https://github.com/borisno2)! - Fix updatedAt field to include @default(now()) in generated Prisma schema to prevent migration failures on databases with existing data |
| 144 | + |
| 145 | +- Updated dependencies [[`bd41b1e`](https://github.com/OpenSaasAU/stack/commit/bd41b1e75b78c2e9748422352e6a500ed26df4e9), [`5410cb6`](https://github.com/OpenSaasAU/stack/commit/5410cb604198e087762e39c8aec87fe3736d8c01)]: |
| 146 | + - @opensaas/stack-core@0.19.0 |
| 147 | + |
3 | 148 | ## 0.18.2 |
4 | 149 |
|
5 | 150 | ### Patch Changes |
|
0 commit comments