@opensaas/stack-cli 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +76 -0
  2. package/dist/commands/migrate.d.ts.map +1 -1
  3. package/dist/commands/migrate.js +91 -265
  4. package/dist/commands/migrate.js.map +1 -1
  5. package/package.json +7 -2
  6. package/plugin/.claude-plugin/plugin.json +15 -0
  7. package/plugin/README.md +112 -0
  8. package/plugin/agents/migration-assistant.md +150 -0
  9. package/plugin/commands/analyze-schema.md +34 -0
  10. package/plugin/commands/generate-config.md +33 -0
  11. package/plugin/commands/validate-migration.md +34 -0
  12. package/plugin/skills/opensaas-migration/SKILL.md +192 -0
  13. package/.turbo/turbo-build.log +0 -4
  14. package/CHANGELOG.md +0 -462
  15. package/CLAUDE.md +0 -298
  16. package/src/commands/__snapshots__/generate.test.ts.snap +0 -413
  17. package/src/commands/dev.test.ts +0 -215
  18. package/src/commands/dev.ts +0 -48
  19. package/src/commands/generate.test.ts +0 -282
  20. package/src/commands/generate.ts +0 -182
  21. package/src/commands/init.ts +0 -34
  22. package/src/commands/mcp.ts +0 -135
  23. package/src/commands/migrate.ts +0 -534
  24. package/src/generator/__snapshots__/context.test.ts.snap +0 -361
  25. package/src/generator/__snapshots__/prisma.test.ts.snap +0 -174
  26. package/src/generator/__snapshots__/types.test.ts.snap +0 -1702
  27. package/src/generator/context.test.ts +0 -139
  28. package/src/generator/context.ts +0 -227
  29. package/src/generator/index.ts +0 -7
  30. package/src/generator/lists.test.ts +0 -335
  31. package/src/generator/lists.ts +0 -140
  32. package/src/generator/plugin-types.ts +0 -147
  33. package/src/generator/prisma-config.ts +0 -46
  34. package/src/generator/prisma-extensions.ts +0 -159
  35. package/src/generator/prisma.test.ts +0 -211
  36. package/src/generator/prisma.ts +0 -161
  37. package/src/generator/types.test.ts +0 -268
  38. package/src/generator/types.ts +0 -537
  39. package/src/index.ts +0 -46
  40. package/src/mcp/lib/documentation-provider.ts +0 -710
  41. package/src/mcp/lib/features/catalog.ts +0 -301
  42. package/src/mcp/lib/generators/feature-generator.ts +0 -598
  43. package/src/mcp/lib/types.ts +0 -89
  44. package/src/mcp/lib/wizards/migration-wizard.ts +0 -584
  45. package/src/mcp/lib/wizards/wizard-engine.ts +0 -427
  46. package/src/mcp/server/index.ts +0 -361
  47. package/src/mcp/server/stack-mcp-server.ts +0 -544
  48. package/src/migration/generators/migration-generator.ts +0 -675
  49. package/src/migration/introspectors/index.ts +0 -12
  50. package/src/migration/introspectors/keystone-introspector.ts +0 -296
  51. package/src/migration/introspectors/nextjs-introspector.ts +0 -209
  52. package/src/migration/introspectors/prisma-introspector.ts +0 -233
  53. package/src/migration/types.ts +0 -92
  54. package/tests/introspectors/keystone-introspector.test.ts +0 -255
  55. package/tests/introspectors/nextjs-introspector.test.ts +0 -302
  56. package/tests/introspectors/prisma-introspector.test.ts +0 -268
  57. package/tests/migration-generator.test.ts +0 -592
  58. package/tests/migration-wizard.test.ts +0 -442
  59. package/tsconfig.json +0 -13
  60. package/tsconfig.tsbuildinfo +0 -1
  61. package/vitest.config.ts +0 -26
@@ -1,361 +0,0 @@
1
- // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
-
3
- exports[`Context Generator > generateContext > should export rawOpensaasContext 1`] = `
4
- "/**
5
- * Auto-generated context factory
6
- *
7
- * This module provides a simple API for creating OpenSaas contexts.
8
- * It abstracts away Prisma client management and configuration.
9
- *
10
- * DO NOT EDIT - This file is automatically generated by 'pnpm generate'
11
- */
12
-
13
- import { getContext as getOpensaasContext } from '@opensaas/stack-core'
14
- import type { Session as OpensaasSession, OpenSaasConfig } from '@opensaas/stack-core'
15
- import { PrismaClient } from './prisma-client/client'
16
- import type { Context } from './types'
17
- import { prismaExtensions } from './prisma-extensions'
18
- import configOrPromise from '../opensaas.config'
19
-
20
- // Resolve config if it's a Promise (when plugins are present)
21
- const configPromise = Promise.resolve(configOrPromise)
22
- let resolvedConfig: OpenSaasConfig | null = null
23
-
24
- // Internal Prisma singleton - managed automatically
25
- const globalForPrisma = globalThis as unknown as { prisma: ReturnType<typeof createExtendedPrisma> | null }
26
- let prisma: ReturnType<typeof createExtendedPrisma> | null = null
27
-
28
- /**
29
- * Create Prisma client with result extensions
30
- */
31
- function createExtendedPrisma(basePrisma: PrismaClient) {
32
- // Check if there are any extensions to apply
33
- if (Object.keys(prismaExtensions).length === 0) {
34
- return basePrisma
35
- }
36
- // Apply result extensions
37
- return basePrisma.$extends(prismaExtensions)
38
- }
39
-
40
- async function getPrisma() {
41
- if (!prisma) {
42
- if (!resolvedConfig) {
43
- resolvedConfig = await configPromise
44
- }
45
- const basePrisma = resolvedConfig.db.prismaClientConstructor!(PrismaClient)
46
- const extendedPrisma = createExtendedPrisma(basePrisma)
47
- prisma = globalForPrisma.prisma ?? extendedPrisma
48
- if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
49
- }
50
- return prisma
51
- }
52
-
53
- async function getConfig() {
54
- if (!resolvedConfig) {
55
- resolvedConfig = await configPromise
56
- }
57
- return resolvedConfig
58
- }
59
-
60
- /**
61
- * Storage utilities (not configured)
62
- */
63
- const storage = {
64
- uploadFile: async () => {
65
- throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
66
- },
67
- uploadImage: async () => {
68
- throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
69
- },
70
- deleteFile: async () => {
71
- throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
72
- },
73
- deleteImage: async () => {
74
- throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
75
- },
76
- }
77
-
78
- /**
79
- * Get OpenSaas context with optional session
80
- *
81
- * @param session - Optional session object (structure defined by your application)
82
- *
83
- * @example
84
- * \`\`\`typescript
85
- * // Anonymous access
86
- * const context = await getContext()
87
- * const posts = await context.db.post.findMany()
88
- *
89
- * // Authenticated access
90
- * const context = await getContext({ userId: 'user-123' })
91
- * const myPosts = await context.db.post.findMany()
92
- *
93
- * // With custom session type
94
- * type CustomSession = { userId: string; email: string; role: string } | null
95
- * const context = await getContext<CustomSession>({ userId: '123', email: 'user@example.com', role: 'admin' })
96
- * // context.session is now typed as CustomSession
97
- * \`\`\`
98
- */
99
- export async function getContext<TSession extends OpensaasSession = OpensaasSession>(session?: TSession): Promise<Context<TSession>> {
100
- const config = await getConfig()
101
- const prismaClient = await getPrisma()
102
- return getOpensaasContext(config, prismaClient, session ?? null, storage) as unknown as Context<TSession>
103
- }
104
-
105
- /**
106
- * Raw context for synchronous initialization (e.g., Better-auth setup)
107
- * This is only available after config is resolved, use with caution
108
- */
109
- export const rawOpensaasContext = (async () => {
110
- const config = await getConfig()
111
- const prismaClient = await getPrisma()
112
- return getOpensaasContext(config, prismaClient, null, storage) as unknown as Context
113
- })()
114
-
115
- /**
116
- * Re-export resolved config for use in admin pages and server actions
117
- * This is a promise that resolves to the config
118
- */
119
- export const config = getConfig()
120
- "
121
- `;
122
-
123
- exports[`Context Generator > generateContext > should generate context factory with custom Prisma client constructor 1`] = `
124
- "/**
125
- * Auto-generated context factory
126
- *
127
- * This module provides a simple API for creating OpenSaas contexts.
128
- * It abstracts away Prisma client management and configuration.
129
- *
130
- * DO NOT EDIT - This file is automatically generated by 'pnpm generate'
131
- */
132
-
133
- import { getContext as getOpensaasContext } from '@opensaas/stack-core'
134
- import type { Session as OpensaasSession, OpenSaasConfig } from '@opensaas/stack-core'
135
- import { PrismaClient } from './prisma-client/client'
136
- import type { Context } from './types'
137
- import { prismaExtensions } from './prisma-extensions'
138
- import configOrPromise from '../opensaas.config'
139
-
140
- // Resolve config if it's a Promise (when plugins are present)
141
- const configPromise = Promise.resolve(configOrPromise)
142
- let resolvedConfig: OpenSaasConfig | null = null
143
-
144
- // Internal Prisma singleton - managed automatically
145
- const globalForPrisma = globalThis as unknown as { prisma: ReturnType<typeof createExtendedPrisma> | null }
146
- let prisma: ReturnType<typeof createExtendedPrisma> | null = null
147
-
148
- /**
149
- * Create Prisma client with result extensions
150
- */
151
- function createExtendedPrisma(basePrisma: PrismaClient) {
152
- // Check if there are any extensions to apply
153
- if (Object.keys(prismaExtensions).length === 0) {
154
- return basePrisma
155
- }
156
- // Apply result extensions
157
- return basePrisma.$extends(prismaExtensions)
158
- }
159
-
160
- async function getPrisma() {
161
- if (!prisma) {
162
- if (!resolvedConfig) {
163
- resolvedConfig = await configPromise
164
- }
165
- const basePrisma = resolvedConfig.db.prismaClientConstructor!(PrismaClient)
166
- const extendedPrisma = createExtendedPrisma(basePrisma)
167
- prisma = globalForPrisma.prisma ?? extendedPrisma
168
- if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
169
- }
170
- return prisma
171
- }
172
-
173
- async function getConfig() {
174
- if (!resolvedConfig) {
175
- resolvedConfig = await configPromise
176
- }
177
- return resolvedConfig
178
- }
179
-
180
- /**
181
- * Storage utilities (not configured)
182
- */
183
- const storage = {
184
- uploadFile: async () => {
185
- throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
186
- },
187
- uploadImage: async () => {
188
- throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
189
- },
190
- deleteFile: async () => {
191
- throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
192
- },
193
- deleteImage: async () => {
194
- throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
195
- },
196
- }
197
-
198
- /**
199
- * Get OpenSaas context with optional session
200
- *
201
- * @param session - Optional session object (structure defined by your application)
202
- *
203
- * @example
204
- * \`\`\`typescript
205
- * // Anonymous access
206
- * const context = await getContext()
207
- * const posts = await context.db.post.findMany()
208
- *
209
- * // Authenticated access
210
- * const context = await getContext({ userId: 'user-123' })
211
- * const myPosts = await context.db.post.findMany()
212
- *
213
- * // With custom session type
214
- * type CustomSession = { userId: string; email: string; role: string } | null
215
- * const context = await getContext<CustomSession>({ userId: '123', email: 'user@example.com', role: 'admin' })
216
- * // context.session is now typed as CustomSession
217
- * \`\`\`
218
- */
219
- export async function getContext<TSession extends OpensaasSession = OpensaasSession>(session?: TSession): Promise<Context<TSession>> {
220
- const config = await getConfig()
221
- const prismaClient = await getPrisma()
222
- return getOpensaasContext(config, prismaClient, session ?? null, storage) as unknown as Context<TSession>
223
- }
224
-
225
- /**
226
- * Raw context for synchronous initialization (e.g., Better-auth setup)
227
- * This is only available after config is resolved, use with caution
228
- */
229
- export const rawOpensaasContext = (async () => {
230
- const config = await getConfig()
231
- const prismaClient = await getPrisma()
232
- return getOpensaasContext(config, prismaClient, null, storage) as unknown as Context
233
- })()
234
-
235
- /**
236
- * Re-export resolved config for use in admin pages and server actions
237
- * This is a promise that resolves to the config
238
- */
239
- export const config = getConfig()
240
- "
241
- `;
242
-
243
- exports[`Context Generator > generateContext > should generate context factory with default Prisma client 1`] = `
244
- "/**
245
- * Auto-generated context factory
246
- *
247
- * This module provides a simple API for creating OpenSaas contexts.
248
- * It abstracts away Prisma client management and configuration.
249
- *
250
- * DO NOT EDIT - This file is automatically generated by 'pnpm generate'
251
- */
252
-
253
- import { getContext as getOpensaasContext } from '@opensaas/stack-core'
254
- import type { Session as OpensaasSession, OpenSaasConfig } from '@opensaas/stack-core'
255
- import { PrismaClient } from './prisma-client/client'
256
- import type { Context } from './types'
257
- import { prismaExtensions } from './prisma-extensions'
258
- import configOrPromise from '../opensaas.config'
259
-
260
- // Resolve config if it's a Promise (when plugins are present)
261
- const configPromise = Promise.resolve(configOrPromise)
262
- let resolvedConfig: OpenSaasConfig | null = null
263
-
264
- // Internal Prisma singleton - managed automatically
265
- const globalForPrisma = globalThis as unknown as { prisma: ReturnType<typeof createExtendedPrisma> | null }
266
- let prisma: ReturnType<typeof createExtendedPrisma> | null = null
267
-
268
- /**
269
- * Create Prisma client with result extensions
270
- */
271
- function createExtendedPrisma(basePrisma: PrismaClient) {
272
- // Check if there are any extensions to apply
273
- if (Object.keys(prismaExtensions).length === 0) {
274
- return basePrisma
275
- }
276
- // Apply result extensions
277
- return basePrisma.$extends(prismaExtensions)
278
- }
279
-
280
- async function getPrisma() {
281
- if (!prisma) {
282
- if (!resolvedConfig) {
283
- resolvedConfig = await configPromise
284
- }
285
- const basePrisma = resolvedConfig.db.prismaClientConstructor!(PrismaClient)
286
- const extendedPrisma = createExtendedPrisma(basePrisma)
287
- prisma = globalForPrisma.prisma ?? extendedPrisma
288
- if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
289
- }
290
- return prisma
291
- }
292
-
293
- async function getConfig() {
294
- if (!resolvedConfig) {
295
- resolvedConfig = await configPromise
296
- }
297
- return resolvedConfig
298
- }
299
-
300
- /**
301
- * Storage utilities (not configured)
302
- */
303
- const storage = {
304
- uploadFile: async () => {
305
- throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
306
- },
307
- uploadImage: async () => {
308
- throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
309
- },
310
- deleteFile: async () => {
311
- throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
312
- },
313
- deleteImage: async () => {
314
- throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
315
- },
316
- }
317
-
318
- /**
319
- * Get OpenSaas context with optional session
320
- *
321
- * @param session - Optional session object (structure defined by your application)
322
- *
323
- * @example
324
- * \`\`\`typescript
325
- * // Anonymous access
326
- * const context = await getContext()
327
- * const posts = await context.db.post.findMany()
328
- *
329
- * // Authenticated access
330
- * const context = await getContext({ userId: 'user-123' })
331
- * const myPosts = await context.db.post.findMany()
332
- *
333
- * // With custom session type
334
- * type CustomSession = { userId: string; email: string; role: string } | null
335
- * const context = await getContext<CustomSession>({ userId: '123', email: 'user@example.com', role: 'admin' })
336
- * // context.session is now typed as CustomSession
337
- * \`\`\`
338
- */
339
- export async function getContext<TSession extends OpensaasSession = OpensaasSession>(session?: TSession): Promise<Context<TSession>> {
340
- const config = await getConfig()
341
- const prismaClient = await getPrisma()
342
- return getOpensaasContext(config, prismaClient, session ?? null, storage) as unknown as Context<TSession>
343
- }
344
-
345
- /**
346
- * Raw context for synchronous initialization (e.g., Better-auth setup)
347
- * This is only available after config is resolved, use with caution
348
- */
349
- export const rawOpensaasContext = (async () => {
350
- const config = await getConfig()
351
- const prismaClient = await getPrisma()
352
- return getOpensaasContext(config, prismaClient, null, storage) as unknown as Context
353
- })()
354
-
355
- /**
356
- * Re-export resolved config for use in admin pages and server actions
357
- * This is a promise that resolves to the config
358
- */
359
- export const config = getConfig()
360
- "
361
- `;
@@ -1,174 +0,0 @@
1
- // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
-
3
- exports[`Prisma Schema Generator > generatePrismaSchema > should generate basic schema with datasource and generator 1`] = `
4
- "generator client {
5
- provider = "prisma-client"
6
- output = "../.opensaas/prisma-client"
7
- }
8
-
9
- datasource db {
10
- provider = "sqlite"
11
- }
12
- "
13
- `;
14
-
15
- exports[`Prisma Schema Generator > generatePrismaSchema > should generate many-to-one relationship 1`] = `
16
- "generator client {
17
- provider = "prisma-client"
18
- output = "../.opensaas/prisma-client"
19
- }
20
-
21
- datasource db {
22
- provider = "sqlite"
23
- }
24
-
25
- model User {
26
- id String @id @default(cuid())
27
- name String?
28
- createdAt DateTime @default(now())
29
- updatedAt DateTime @updatedAt
30
- }
31
-
32
- model Post {
33
- id String @id @default(cuid())
34
- title String?
35
- authorId String?
36
- author User? @relation(fields: [authorId], references: [id])
37
- createdAt DateTime @default(now())
38
- updatedAt DateTime @updatedAt
39
- }
40
- "
41
- `;
42
-
43
- exports[`Prisma Schema Generator > generatePrismaSchema > should generate model with basic fields 1`] = `
44
- "generator client {
45
- provider = "prisma-client"
46
- output = "../.opensaas/prisma-client"
47
- }
48
-
49
- datasource db {
50
- provider = "sqlite"
51
- }
52
-
53
- model User {
54
- id String @id @default(cuid())
55
- name String
56
- email String
57
- age Int?
58
- createdAt DateTime @default(now())
59
- updatedAt DateTime @updatedAt
60
- }
61
- "
62
- `;
63
-
64
- exports[`Prisma Schema Generator > generatePrismaSchema > should generate model with checkbox field 1`] = `
65
- "generator client {
66
- provider = "prisma-client"
67
- output = "../.opensaas/prisma-client"
68
- }
69
-
70
- datasource db {
71
- provider = "sqlite"
72
- }
73
-
74
- model Post {
75
- id String @id @default(cuid())
76
- title String?
77
- isPublished Boolean @default(false)
78
- createdAt DateTime @default(now())
79
- updatedAt DateTime @updatedAt
80
- }
81
- "
82
- `;
83
-
84
- exports[`Prisma Schema Generator > generatePrismaSchema > should generate model with timestamp field 1`] = `
85
- "generator client {
86
- provider = "prisma-client"
87
- output = "../.opensaas/prisma-client"
88
- }
89
-
90
- datasource db {
91
- provider = "sqlite"
92
- }
93
-
94
- model Post {
95
- id String @id @default(cuid())
96
- title String?
97
- publishedAt DateTime?
98
- createdAt DateTime @default(now())
99
- updatedAt DateTime @updatedAt
100
- }
101
- "
102
- `;
103
-
104
- exports[`Prisma Schema Generator > generatePrismaSchema > should generate multiple models 1`] = `
105
- "generator client {
106
- provider = "prisma-client"
107
- output = "../.opensaas/prisma-client"
108
- }
109
-
110
- datasource db {
111
- provider = "postgresql"
112
- }
113
-
114
- model User {
115
- id String @id @default(cuid())
116
- name String?
117
- createdAt DateTime @default(now())
118
- updatedAt DateTime @updatedAt
119
- }
120
-
121
- model Post {
122
- id String @id @default(cuid())
123
- title String?
124
- createdAt DateTime @default(now())
125
- updatedAt DateTime @updatedAt
126
- }
127
-
128
- model Comment {
129
- id String @id @default(cuid())
130
- content String?
131
- createdAt DateTime @default(now())
132
- updatedAt DateTime @updatedAt
133
- }
134
- "
135
- `;
136
-
137
- exports[`Prisma Schema Generator > generatePrismaSchema > should generate one-to-many relationship 1`] = `
138
- "generator client {
139
- provider = "prisma-client"
140
- output = "../.opensaas/prisma-client"
141
- }
142
-
143
- datasource db {
144
- provider = "sqlite"
145
- }
146
-
147
- model User {
148
- id String @id @default(cuid())
149
- name String?
150
- posts Post[]
151
- createdAt DateTime @default(now())
152
- updatedAt DateTime @updatedAt
153
- }
154
-
155
- model Post {
156
- id String @id @default(cuid())
157
- title String?
158
- createdAt DateTime @default(now())
159
- updatedAt DateTime @updatedAt
160
- }
161
- "
162
- `;
163
-
164
- exports[`Prisma Schema Generator > generatePrismaSchema > should use custom opensaasPath for generator output 1`] = `
165
- "generator client {
166
- provider = "prisma-client"
167
- output = "../.custom-path/prisma-client"
168
- }
169
-
170
- datasource db {
171
- provider = "sqlite"
172
- }
173
- "
174
- `;