@contractspec/lib.runtime-sandbox 0.12.0 → 0.14.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 (59) hide show
  1. package/dist/adapters/pglite/adapter.d.ts +27 -0
  2. package/dist/adapters/pglite/adapter.d.ts.map +1 -0
  3. package/dist/adapters/pglite/index.d.ts +2 -0
  4. package/dist/adapters/pglite/index.d.ts.map +1 -0
  5. package/dist/browser/index.js +2443 -0
  6. package/dist/index.d.ts +10 -8
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +2436 -22
  9. package/dist/node/index.js +2438 -0
  10. package/dist/ports/database.port.d.ts +49 -53
  11. package/dist/ports/database.port.d.ts.map +1 -1
  12. package/dist/ports/index.d.ts +2 -0
  13. package/dist/ports/index.d.ts.map +1 -0
  14. package/dist/types/database.types.d.ts +21 -24
  15. package/dist/types/database.types.d.ts.map +1 -1
  16. package/dist/types/index.d.ts +2 -0
  17. package/dist/types/index.d.ts.map +1 -0
  18. package/dist/web/database/migrations.d.ts +8 -6
  19. package/dist/web/database/migrations.d.ts.map +1 -1
  20. package/dist/web/database/schema.d.ts +7297 -7302
  21. package/dist/web/database/schema.d.ts.map +1 -1
  22. package/dist/web/events/local-pubsub.d.ts +5 -7
  23. package/dist/web/events/local-pubsub.d.ts.map +1 -1
  24. package/dist/web/graphql/local-client.d.ts +13 -17
  25. package/dist/web/graphql/local-client.d.ts.map +1 -1
  26. package/dist/web/index.d.ts +7 -14
  27. package/dist/web/index.d.ts.map +1 -1
  28. package/dist/web/runtime/seeders/index.d.ts +19 -0
  29. package/dist/web/runtime/seeders/index.d.ts.map +1 -0
  30. package/dist/web/runtime/services.d.ts +51 -50
  31. package/dist/web/runtime/services.d.ts.map +1 -1
  32. package/dist/web/storage/indexeddb.d.ts +16 -19
  33. package/dist/web/storage/indexeddb.d.ts.map +1 -1
  34. package/dist/web/utils/id.d.ts +1 -4
  35. package/dist/web/utils/id.d.ts.map +1 -1
  36. package/package.json +18 -16
  37. package/dist/_virtual/_rolldown/runtime.js +0 -18
  38. package/dist/adapters/pglite/adapter.js +0 -97
  39. package/dist/adapters/pglite/adapter.js.map +0 -1
  40. package/dist/adapters/pglite/index.js +0 -3
  41. package/dist/index.js.map +0 -1
  42. package/dist/web/database/migrations.js +0 -746
  43. package/dist/web/database/migrations.js.map +0 -1
  44. package/dist/web/database/schema.js +0 -528
  45. package/dist/web/database/schema.js.map +0 -1
  46. package/dist/web/events/local-pubsub.js +0 -24
  47. package/dist/web/events/local-pubsub.js.map +0 -1
  48. package/dist/web/graphql/local-client.js +0 -536
  49. package/dist/web/graphql/local-client.js.map +0 -1
  50. package/dist/web/index.js +0 -68
  51. package/dist/web/index.js.map +0 -1
  52. package/dist/web/runtime/seeders/index.js +0 -358
  53. package/dist/web/runtime/seeders/index.js.map +0 -1
  54. package/dist/web/runtime/services.js +0 -80
  55. package/dist/web/runtime/services.js.map +0 -1
  56. package/dist/web/storage/indexeddb.js +0 -85
  57. package/dist/web/storage/indexeddb.js.map +0 -1
  58. package/dist/web/utils/id.js +0 -9
  59. package/dist/web/utils/id.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"local-client.js","names":[],"sources":["../../../src/web/graphql/local-client.ts"],"sourcesContent":["import { ApolloClient, InMemoryCache } from '@apollo/client';\nimport { SchemaLink } from '@apollo/client/link/schema';\nimport { makeExecutableSchema } from '@graphql-tools/schema';\nimport { GraphQLScalarType, Kind } from 'graphql';\n\nimport type { DatabasePort, DbRow } from '@contractspec/lib.runtime-sandbox';\nimport { LocalEventBus } from '../events/local-pubsub';\nimport { LocalStorageService } from '../storage/indexeddb';\nimport { generateId } from '../utils/id';\n\nconst typeDefs = /* GraphQL */ `\n scalar DateTime\n\n enum TaskPriority {\n LOW\n MEDIUM\n HIGH\n URGENT\n }\n\n enum MessageStatus {\n SENT\n DELIVERED\n READ\n }\n\n enum RecipeLocale {\n EN\n FR\n }\n\n type TaskCategory {\n id: ID!\n projectId: ID!\n name: String!\n color: String\n createdAt: DateTime!\n updatedAt: DateTime!\n }\n\n type Task {\n id: ID!\n projectId: ID!\n categoryId: ID\n title: String!\n description: String\n completed: Boolean!\n priority: TaskPriority!\n dueDate: DateTime\n tags: [String!]!\n createdAt: DateTime!\n updatedAt: DateTime!\n category: TaskCategory\n }\n\n input CreateTaskInput {\n projectId: ID!\n categoryId: ID\n title: String!\n description: String\n priority: TaskPriority = MEDIUM\n dueDate: DateTime\n tags: [String!]\n }\n\n input UpdateTaskInput {\n categoryId: ID\n title: String\n description: String\n priority: TaskPriority\n dueDate: DateTime\n tags: [String!]\n }\n\n type ConversationParticipant {\n id: ID!\n conversationId: ID!\n projectId: ID!\n userId: String!\n displayName: String\n role: String\n joinedAt: DateTime!\n lastReadAt: DateTime\n }\n\n input ConversationParticipantInput {\n userId: String!\n displayName: String\n role: String\n }\n\n type Message {\n id: ID!\n conversationId: ID!\n projectId: ID!\n senderId: String!\n senderName: String\n content: String!\n attachments: [String!]!\n status: MessageStatus!\n createdAt: DateTime!\n updatedAt: DateTime!\n }\n\n input SendMessageInput {\n conversationId: ID!\n projectId: ID!\n senderId: String!\n senderName: String\n content: String!\n }\n\n input CreateConversationInput {\n projectId: ID!\n name: String\n isGroup: Boolean = false\n avatarUrl: String\n participants: [ConversationParticipantInput!]!\n }\n\n type Conversation {\n id: ID!\n projectId: ID!\n name: String\n isGroup: Boolean!\n avatarUrl: String\n lastMessageId: ID\n updatedAt: DateTime!\n participants: [ConversationParticipant!]!\n messages(limit: Int = 50): [Message!]!\n }\n\n type RecipeCategory {\n id: ID!\n nameEn: String!\n nameFr: String!\n icon: String\n }\n\n type RecipeIngredient {\n id: ID!\n name: String!\n quantity: String!\n ordering: Int!\n }\n\n type RecipeInstruction {\n id: ID!\n content: String!\n ordering: Int!\n }\n\n type Recipe {\n id: ID!\n projectId: ID!\n slugEn: String!\n slugFr: String!\n name: String!\n description: String\n heroImageUrl: String\n prepTimeMinutes: Int\n cookTimeMinutes: Int\n servings: Int\n isFavorite: Boolean!\n locale: RecipeLocale!\n category: RecipeCategory\n ingredients: [RecipeIngredient!]!\n instructions: [RecipeInstruction!]!\n }\n\n type Query {\n taskCategories(projectId: ID!): [TaskCategory!]!\n tasks(projectId: ID!): [Task!]!\n conversations(projectId: ID!): [Conversation!]!\n messages(conversationId: ID!, limit: Int = 50): [Message!]!\n recipes(projectId: ID!, locale: RecipeLocale = EN): [Recipe!]!\n recipe(id: ID!, locale: RecipeLocale = EN): Recipe\n }\n\n type Mutation {\n createTask(input: CreateTaskInput!): Task!\n updateTask(id: ID!, input: UpdateTaskInput!): Task!\n toggleTask(id: ID!, completed: Boolean!): Task!\n deleteTask(id: ID!): Boolean!\n createConversation(input: CreateConversationInput!): Conversation!\n sendMessage(input: SendMessageInput!): Message!\n setMessagesRead(conversationId: ID!, userId: String!): Boolean!\n favoriteRecipe(id: ID!, isFavorite: Boolean!): Recipe!\n }\n`;\n\ninterface ResolverContext {\n db: DatabasePort;\n storage: LocalStorageService;\n pubsub: LocalEventBus;\n}\n\ntype ResolverParent = Record<string, unknown>;\n\n/**\n * Local row type for query results\n */\ntype LocalRow = DbRow;\n\nconst DateTimeScalar = new GraphQLScalarType({\n name: 'DateTime',\n parseValue(value: unknown) {\n return value ? new Date(value as string).toISOString() : null;\n },\n serialize(value: unknown) {\n if (!value) return null;\n if (typeof value === 'string') return value;\n return new Date(value as string).toISOString();\n },\n parseLiteral(ast) {\n if (ast.kind === Kind.STRING) {\n return new Date(ast.value).toISOString();\n }\n return null;\n },\n});\n\nexport interface LocalGraphQLClientOptions {\n db: DatabasePort;\n storage: LocalStorageService;\n pubsub?: LocalEventBus;\n}\n\nexport class LocalGraphQLClient {\n readonly apollo: InstanceType<typeof ApolloClient>;\n\n constructor(private readonly options: LocalGraphQLClientOptions) {\n const schema = makeExecutableSchema({\n typeDefs,\n resolvers: this.createResolvers(),\n });\n\n this.apollo = new ApolloClient({\n cache: new InMemoryCache(),\n link: new SchemaLink({\n schema,\n context: () => ({\n db: this.options.db,\n storage: this.options.storage,\n pubsub: this.options.pubsub ?? new LocalEventBus(),\n }),\n }),\n devtools: {\n enabled: typeof window !== 'undefined',\n },\n });\n }\n\n private createResolvers() {\n return {\n DateTime: DateTimeScalar,\n Query: {\n taskCategories: async (\n _: ResolverParent,\n args: { projectId: string },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_task_category WHERE \"projectId\" = $1 ORDER BY name ASC`,\n [args.projectId]\n );\n return result.rows.map(mapTaskCategory);\n },\n tasks: async (\n _: ResolverParent,\n args: { projectId: string },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_task WHERE \"projectId\" = $1 ORDER BY \"createdAt\" DESC`,\n [args.projectId]\n );\n return result.rows.map(mapTask);\n },\n conversations: async (\n _: ResolverParent,\n args: { projectId: string },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_conversation WHERE \"projectId\" = $1 ORDER BY \"updatedAt\" DESC`,\n [args.projectId]\n );\n return result.rows.map(mapConversation);\n },\n messages: async (\n _: ResolverParent,\n args: { conversationId: string; limit: number },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_message WHERE \"conversationId\" = $1 ORDER BY \"createdAt\" DESC LIMIT $2`,\n [args.conversationId, args.limit]\n );\n return result.rows.map(mapMessage);\n },\n recipes: async (\n _: ResolverParent,\n args: { projectId: string; locale: 'EN' | 'FR' },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_recipe WHERE \"projectId\" = $1 ORDER BY \"nameEn\" ASC`,\n [args.projectId]\n );\n return result.rows.map((row: LocalRow) =>\n mapRecipe(row, args.locale)\n );\n },\n recipe: async (\n _: ResolverParent,\n args: { id: string; locale: 'EN' | 'FR' },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_recipe WHERE id = $1 LIMIT 1`,\n [args.id]\n );\n if (!result.rows.length || !result.rows[0]) return null;\n return mapRecipe(result.rows[0], args.locale);\n },\n },\n Mutation: {\n createTask: async (\n _: ResolverParent,\n args: { input: Record<string, unknown> },\n ctx: ResolverContext\n ) => {\n const id = generateId('task');\n const now = new Date().toISOString();\n const tags = JSON.stringify(args.input.tags ?? []);\n await ctx.db.execute(\n `INSERT INTO template_task (id, \"projectId\", \"categoryId\", title, description, completed, priority, \"dueDate\", tags, \"createdAt\", \"updatedAt\")\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,\n [\n id,\n args.input.projectId as string,\n (args.input.categoryId as string | undefined) ?? null,\n args.input.title as string,\n (args.input.description as string | undefined) ?? null,\n 0,\n (args.input.priority as string | undefined) ?? 'MEDIUM',\n (args.input.dueDate as string | undefined) ?? null,\n tags,\n now,\n now,\n ]\n );\n const result = await ctx.db.query(\n `SELECT * FROM template_task WHERE id = $1 LIMIT 1`,\n [id]\n );\n if (!result.rows.length || !result.rows[0])\n throw new Error('Failed to create task');\n return mapTask(result.rows[0]);\n },\n updateTask: async (\n _: ResolverParent,\n args: { id: string; input: Record<string, unknown> },\n ctx: ResolverContext\n ) => {\n const now = new Date().toISOString();\n await ctx.db.execute(\n `UPDATE template_task\n SET \"categoryId\" = COALESCE($1, \"categoryId\"),\n title = COALESCE($2, title),\n description = COALESCE($3, description),\n priority = COALESCE($4, priority),\n \"dueDate\" = COALESCE($5, \"dueDate\"),\n tags = COALESCE($6, tags),\n \"updatedAt\" = $7\n WHERE id = $8`,\n [\n (args.input.categoryId as string | undefined) ?? null,\n (args.input.title as string | undefined) ?? null,\n (args.input.description as string | undefined) ?? null,\n (args.input.priority as string | undefined) ?? null,\n (args.input.dueDate as string | undefined) ?? null,\n args.input.tags ? JSON.stringify(args.input.tags) : null,\n now,\n args.id,\n ]\n );\n const result = await ctx.db.query(\n `SELECT * FROM template_task WHERE id = $1 LIMIT 1`,\n [args.id]\n );\n if (!result.rows.length || !result.rows[0])\n throw new Error('Task not found');\n return mapTask(result.rows[0]);\n },\n toggleTask: async (\n _: ResolverParent,\n args: { id: string; completed: boolean },\n ctx: ResolverContext\n ) => {\n const now = new Date().toISOString();\n await ctx.db.execute(\n `UPDATE template_task SET completed = $1, \"updatedAt\" = $2 WHERE id = $3`,\n [args.completed ? 1 : 0, now, args.id]\n );\n const result = await ctx.db.query(\n `SELECT * FROM template_task WHERE id = $1 LIMIT 1`,\n [args.id]\n );\n if (!result.rows.length || !result.rows[0])\n throw new Error('Task not found');\n return mapTask(result.rows[0]);\n },\n deleteTask: async (\n _: ResolverParent,\n args: { id: string },\n ctx: ResolverContext\n ) => {\n await ctx.db.execute(`DELETE FROM template_task WHERE id = $1`, [\n args.id,\n ]);\n return true;\n },\n createConversation: async (\n _: ResolverParent,\n args: { input: Record<string, unknown> },\n ctx: ResolverContext\n ) => {\n const id = generateId('conversation');\n const now = new Date().toISOString();\n await ctx.db.execute(\n `INSERT INTO template_conversation (id, \"projectId\", name, \"isGroup\", \"avatarUrl\", \"updatedAt\")\n VALUES ($1, $2, $3, $4, $5, $6)`,\n [\n id,\n args.input.projectId as string,\n (args.input.name as string | undefined) ?? null,\n (args.input.isGroup as boolean | undefined) ? 1 : 0,\n (args.input.avatarUrl as string | undefined) ?? null,\n now,\n ]\n );\n\n const participants =\n (args.input.participants as Record<string, string>[]) ?? [];\n for (const participant of participants) {\n await ctx.db.execute(\n `INSERT INTO template_conversation_participant (id, \"conversationId\", \"projectId\", \"userId\", \"displayName\", role, \"joinedAt\")\n VALUES ($1, $2, $3, $4, $5, $6, $7)`,\n [\n generateId('participant'),\n id,\n args.input.projectId as string,\n participant.userId,\n participant.displayName ?? null,\n participant.role ?? null,\n now,\n ]\n );\n }\n\n const result = await ctx.db.query(\n `SELECT * FROM template_conversation WHERE id = $1 LIMIT 1`,\n [id]\n );\n if (!result.rows.length || !result.rows[0])\n throw new Error('Failed to create conversation');\n return mapConversation(result.rows[0]);\n },\n sendMessage: async (\n _: ResolverParent,\n args: { input: Record<string, unknown> },\n ctx: ResolverContext\n ) => {\n const id = generateId('message');\n const now = new Date().toISOString();\n await ctx.db.execute(\n `INSERT INTO template_message (id, \"conversationId\", \"projectId\", \"senderId\", \"senderName\", content, attachments, status, \"createdAt\", \"updatedAt\")\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,\n [\n id,\n args.input.conversationId as string,\n args.input.projectId as string,\n args.input.senderId as string,\n (args.input.senderName as string | undefined) ?? null,\n args.input.content as string,\n JSON.stringify([]),\n 'SENT',\n now,\n now,\n ]\n );\n await ctx.db.execute(\n `UPDATE template_conversation SET \"lastMessageId\" = $1, \"updatedAt\" = $2 WHERE id = $3`,\n [id, now, args.input.conversationId as string]\n );\n const result = await ctx.db.query(\n `SELECT * FROM template_message WHERE id = $1`,\n [id]\n );\n if (!result.rows.length || !result.rows[0])\n throw new Error('Failed to send message');\n const message = mapMessage(result.rows[0]);\n ctx.pubsub.emit('message:new', message);\n return message;\n },\n setMessagesRead: async (\n _: ResolverParent,\n args: { conversationId: string; userId: string },\n ctx: ResolverContext\n ) => {\n const now = new Date().toISOString();\n await ctx.db.execute(\n `UPDATE template_conversation_participant\n SET \"lastReadAt\" = $1\n WHERE \"conversationId\" = $2 AND \"userId\" = $3`,\n [now, args.conversationId, args.userId]\n );\n return true;\n },\n favoriteRecipe: async (\n _: ResolverParent,\n args: { id: string; isFavorite: boolean },\n ctx: ResolverContext\n ) => {\n const now = new Date().toISOString();\n await ctx.db.execute(\n `UPDATE template_recipe SET \"isFavorite\" = $1, \"updatedAt\" = $2 WHERE id = $3`,\n [args.isFavorite ? 1 : 0, now, args.id]\n );\n const result = await ctx.db.query(\n `SELECT * FROM template_recipe WHERE id = $1 LIMIT 1`,\n [args.id]\n );\n if (!result.rows.length || !result.rows[0])\n throw new Error('Recipe not found');\n const locale: 'EN' | 'FR' = 'EN';\n return mapRecipe(result.rows[0], locale);\n },\n },\n Task: {\n category: async (\n parent: LocalRow,\n _: unknown,\n ctx: ResolverContext\n ) => {\n if (!parent.categoryId) return null;\n const result = await ctx.db.query(\n `SELECT * FROM template_task_category WHERE id = $1 LIMIT 1`,\n [parent.categoryId]\n );\n if (!result.rows.length || !result.rows[0]) return null;\n return mapTaskCategory(result.rows[0]);\n },\n },\n Conversation: {\n participants: async (\n parent: LocalRow,\n _: unknown,\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_conversation_participant WHERE \"conversationId\" = $1 ORDER BY \"joinedAt\" ASC`,\n [parent.id]\n );\n return result.rows.map(mapParticipant);\n },\n messages: async (\n parent: LocalRow,\n args: { limit: number },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_message WHERE \"conversationId\" = $1 ORDER BY \"createdAt\" DESC LIMIT $2`,\n [parent.id, args.limit]\n );\n return result.rows.map(mapMessage);\n },\n },\n Recipe: {\n category: async (\n parent: LocalRow & { categoryId?: string | null },\n _: unknown,\n ctx: ResolverContext\n ) => {\n if (!parent.categoryId) return null;\n const result = await ctx.db.query(\n `SELECT * FROM template_recipe_category WHERE id = $1 LIMIT 1`,\n [parent.categoryId]\n );\n if (!result.rows.length || !result.rows[0]) return null;\n return mapRecipeCategory(result.rows[0]);\n },\n ingredients: async (\n parent: LocalRow & { locale: 'EN' | 'FR' },\n _: unknown,\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_recipe_ingredient WHERE \"recipeId\" = $1 ORDER BY ordering ASC`,\n [parent.id]\n );\n return result.rows.map((row: LocalRow) =>\n mapRecipeIngredient(row, parent.locale)\n );\n },\n instructions: async (\n parent: LocalRow & { locale: 'EN' | 'FR' },\n _: unknown,\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_recipe_instruction WHERE \"recipeId\" = $1 ORDER BY ordering ASC`,\n [parent.id]\n );\n return result.rows.map((row: LocalRow) =>\n mapRecipeInstruction(row, parent.locale)\n );\n },\n },\n };\n }\n}\n\nfunction mapTaskCategory(row: LocalRow) {\n return {\n id: row.id,\n projectId: row.projectId,\n name: row.name,\n color: row.color,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapTask(row: LocalRow) {\n return {\n id: row.id,\n projectId: row.projectId,\n categoryId: row.categoryId,\n title: row.title,\n description: row.description,\n completed: Boolean(row.completed),\n priority: row.priority ?? 'MEDIUM',\n dueDate: row.dueDate,\n tags: parseTags(row.tags),\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction parseTags(value: LocalRow['tags']): string[] {\n if (typeof value !== 'string') return [];\n try {\n const parsed = JSON.parse(value);\n return Array.isArray(parsed) ? (parsed as string[]) : [];\n } catch {\n return [];\n }\n}\n\nfunction mapConversation(row: LocalRow) {\n return {\n id: row.id,\n projectId: row.projectId,\n name: row.name,\n isGroup: Boolean(row.isGroup),\n avatarUrl: row.avatarUrl,\n lastMessageId: row.lastMessageId,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapParticipant(row: LocalRow) {\n return {\n id: row.id,\n conversationId: row.conversationId,\n projectId: row.projectId,\n userId: row.userId,\n displayName: row.displayName,\n role: row.role,\n joinedAt: row.joinedAt,\n lastReadAt: row.lastReadAt,\n };\n}\n\nfunction mapMessage(row: LocalRow) {\n return {\n id: row.id,\n conversationId: row.conversationId,\n projectId: row.projectId,\n senderId: row.senderId,\n senderName: row.senderName,\n content: row.content,\n attachments: [],\n status: row.status ?? 'SENT',\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapRecipe(row: LocalRow, locale: 'EN' | 'FR') {\n return {\n id: row.id,\n projectId: row.projectId,\n slugEn: row.slugEn,\n slugFr: row.slugFr,\n name: locale === 'FR' ? row.nameFr : row.nameEn,\n description: locale === 'FR' ? row.descriptionFr : row.descriptionEn,\n heroImageUrl: row.heroImageUrl,\n prepTimeMinutes: row.prepTimeMinutes ?? null,\n cookTimeMinutes: row.cookTimeMinutes ?? null,\n servings: row.servings ?? null,\n isFavorite: Boolean(row.isFavorite),\n locale,\n categoryId: row.categoryId,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapRecipeCategory(row: LocalRow) {\n return {\n id: row.id,\n nameEn: row.nameEn,\n nameFr: row.nameFr,\n icon: row.icon,\n };\n}\n\nfunction mapRecipeIngredient(row: LocalRow, locale: 'EN' | 'FR') {\n return {\n id: row.id,\n name: locale === 'FR' ? row.nameFr : row.nameEn,\n quantity: row.quantity,\n ordering: row.ordering ?? 0,\n };\n}\n\nfunction mapRecipeInstruction(row: LocalRow, locale: 'EN' | 'FR') {\n return {\n id: row.id,\n content: locale === 'FR' ? row.contentFr : row.contentEn,\n ordering: row.ordering ?? 0,\n };\n}\n"],"mappings":";;;;;;;;AAUA,MAAM,WAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkM/B,MAAM,iBAAiB,IAAI,kBAAkB;CAC3C,MAAM;CACN,WAAW,OAAgB;AACzB,SAAO,QAAQ,IAAI,KAAK,MAAgB,CAAC,aAAa,GAAG;;CAE3D,UAAU,OAAgB;AACxB,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,SAAO,IAAI,KAAK,MAAgB,CAAC,aAAa;;CAEhD,aAAa,KAAK;AAChB,MAAI,IAAI,SAAS,KAAK,OACpB,QAAO,IAAI,KAAK,IAAI,MAAM,CAAC,aAAa;AAE1C,SAAO;;CAEV,CAAC;AAQF,IAAa,qBAAb,MAAgC;CAC9B,AAAS;CAET,YAAY,AAAiB,SAAoC;EAApC;EAC3B,MAAM,SAAS,qBAAqB;GAClC;GACA,WAAW,KAAK,iBAAiB;GAClC,CAAC;AAEF,OAAK,SAAS,IAAI,aAAa;GAC7B,OAAO,IAAI,eAAe;GAC1B,MAAM,IAAI,WAAW;IACnB;IACA,gBAAgB;KACd,IAAI,KAAK,QAAQ;KACjB,SAAS,KAAK,QAAQ;KACtB,QAAQ,KAAK,QAAQ,UAAU,IAAI,eAAe;KACnD;IACF,CAAC;GACF,UAAU,EACR,SAAS,OAAO,WAAW,aAC5B;GACF,CAAC;;CAGJ,AAAQ,kBAAkB;AACxB,SAAO;GACL,UAAU;GACV,OAAO;IACL,gBAAgB,OACd,GACA,MACA,QACG;AAKH,aAJe,MAAM,IAAI,GAAG,MAC1B,iFACA,CAAC,KAAK,UAAU,CACjB,EACa,KAAK,IAAI,gBAAgB;;IAEzC,OAAO,OACL,GACA,MACA,QACG;AAKH,aAJe,MAAM,IAAI,GAAG,MAC1B,gFACA,CAAC,KAAK,UAAU,CACjB,EACa,KAAK,IAAI,QAAQ;;IAEjC,eAAe,OACb,GACA,MACA,QACG;AAKH,aAJe,MAAM,IAAI,GAAG,MAC1B,wFACA,CAAC,KAAK,UAAU,CACjB,EACa,KAAK,IAAI,gBAAgB;;IAEzC,UAAU,OACR,GACA,MACA,QACG;AAKH,aAJe,MAAM,IAAI,GAAG,MAC1B,iGACA,CAAC,KAAK,gBAAgB,KAAK,MAAM,CAClC,EACa,KAAK,IAAI,WAAW;;IAEpC,SAAS,OACP,GACA,MACA,QACG;AAKH,aAJe,MAAM,IAAI,GAAG,MAC1B,8EACA,CAAC,KAAK,UAAU,CACjB,EACa,KAAK,KAAK,QACtB,UAAU,KAAK,KAAK,OAAO,CAC5B;;IAEH,QAAQ,OACN,GACA,MACA,QACG;KACH,MAAM,SAAS,MAAM,IAAI,GAAG,MAC1B,uDACA,CAAC,KAAK,GAAG,CACV;AACD,SAAI,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,KAAK,GAAI,QAAO;AACnD,YAAO,UAAU,OAAO,KAAK,IAAI,KAAK,OAAO;;IAEhD;GACD,UAAU;IACR,YAAY,OACV,GACA,MACA,QACG;KACH,MAAM,KAAK,WAAW,OAAO;KAC7B,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;KACpC,MAAM,OAAO,KAAK,UAAU,KAAK,MAAM,QAAQ,EAAE,CAAC;AAClD,WAAM,IAAI,GAAG,QACX;qEAEA;MACE;MACA,KAAK,MAAM;MACV,KAAK,MAAM,cAAqC;MACjD,KAAK,MAAM;MACV,KAAK,MAAM,eAAsC;MAClD;MACC,KAAK,MAAM,YAAmC;MAC9C,KAAK,MAAM,WAAkC;MAC9C;MACA;MACA;MACD,CACF;KACD,MAAM,SAAS,MAAM,IAAI,GAAG,MAC1B,qDACA,CAAC,GAAG,CACL;AACD,SAAI,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,KAAK,GACtC,OAAM,IAAI,MAAM,wBAAwB;AAC1C,YAAO,QAAQ,OAAO,KAAK,GAAG;;IAEhC,YAAY,OACV,GACA,MACA,QACG;KACH,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AACpC,WAAM,IAAI,GAAG,QACX;;;;;;;;6BASA;MACG,KAAK,MAAM,cAAqC;MAChD,KAAK,MAAM,SAAgC;MAC3C,KAAK,MAAM,eAAsC;MACjD,KAAK,MAAM,YAAmC;MAC9C,KAAK,MAAM,WAAkC;MAC9C,KAAK,MAAM,OAAO,KAAK,UAAU,KAAK,MAAM,KAAK,GAAG;MACpD;MACA,KAAK;MACN,CACF;KACD,MAAM,SAAS,MAAM,IAAI,GAAG,MAC1B,qDACA,CAAC,KAAK,GAAG,CACV;AACD,SAAI,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,KAAK,GACtC,OAAM,IAAI,MAAM,iBAAiB;AACnC,YAAO,QAAQ,OAAO,KAAK,GAAG;;IAEhC,YAAY,OACV,GACA,MACA,QACG;KACH,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AACpC,WAAM,IAAI,GAAG,QACX,2EACA;MAAC,KAAK,YAAY,IAAI;MAAG;MAAK,KAAK;MAAG,CACvC;KACD,MAAM,SAAS,MAAM,IAAI,GAAG,MAC1B,qDACA,CAAC,KAAK,GAAG,CACV;AACD,SAAI,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,KAAK,GACtC,OAAM,IAAI,MAAM,iBAAiB;AACnC,YAAO,QAAQ,OAAO,KAAK,GAAG;;IAEhC,YAAY,OACV,GACA,MACA,QACG;AACH,WAAM,IAAI,GAAG,QAAQ,2CAA2C,CAC9D,KAAK,GACN,CAAC;AACF,YAAO;;IAET,oBAAoB,OAClB,GACA,MACA,QACG;KACH,MAAM,KAAK,WAAW,eAAe;KACrC,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AACpC,WAAM,IAAI,GAAG,QACX;+CAEA;MACE;MACA,KAAK,MAAM;MACV,KAAK,MAAM,QAA+B;MAC1C,KAAK,MAAM,UAAkC,IAAI;MACjD,KAAK,MAAM,aAAoC;MAChD;MACD,CACF;KAED,MAAM,eACH,KAAK,MAAM,gBAA6C,EAAE;AAC7D,UAAK,MAAM,eAAe,aACxB,OAAM,IAAI,GAAG,QACX;qDAEA;MACE,WAAW,cAAc;MACzB;MACA,KAAK,MAAM;MACX,YAAY;MACZ,YAAY,eAAe;MAC3B,YAAY,QAAQ;MACpB;MACD,CACF;KAGH,MAAM,SAAS,MAAM,IAAI,GAAG,MAC1B,6DACA,CAAC,GAAG,CACL;AACD,SAAI,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,KAAK,GACtC,OAAM,IAAI,MAAM,gCAAgC;AAClD,YAAO,gBAAgB,OAAO,KAAK,GAAG;;IAExC,aAAa,OACX,GACA,MACA,QACG;KACH,MAAM,KAAK,WAAW,UAAU;KAChC,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AACpC,WAAM,IAAI,GAAG,QACX;gEAEA;MACE;MACA,KAAK,MAAM;MACX,KAAK,MAAM;MACX,KAAK,MAAM;MACV,KAAK,MAAM,cAAqC;MACjD,KAAK,MAAM;MACX,KAAK,UAAU,EAAE,CAAC;MAClB;MACA;MACA;MACD,CACF;AACD,WAAM,IAAI,GAAG,QACX,yFACA;MAAC;MAAI;MAAK,KAAK,MAAM;MAAyB,CAC/C;KACD,MAAM,SAAS,MAAM,IAAI,GAAG,MAC1B,gDACA,CAAC,GAAG,CACL;AACD,SAAI,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,KAAK,GACtC,OAAM,IAAI,MAAM,yBAAyB;KAC3C,MAAM,UAAU,WAAW,OAAO,KAAK,GAAG;AAC1C,SAAI,OAAO,KAAK,eAAe,QAAQ;AACvC,YAAO;;IAET,iBAAiB,OACf,GACA,MACA,QACG;KACH,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AACpC,WAAM,IAAI,GAAG,QACX;;6DAGA;MAAC;MAAK,KAAK;MAAgB,KAAK;MAAO,CACxC;AACD,YAAO;;IAET,gBAAgB,OACd,GACA,MACA,QACG;KACH,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AACpC,WAAM,IAAI,GAAG,QACX,gFACA;MAAC,KAAK,aAAa,IAAI;MAAG;MAAK,KAAK;MAAG,CACxC;KACD,MAAM,SAAS,MAAM,IAAI,GAAG,MAC1B,uDACA,CAAC,KAAK,GAAG,CACV;AACD,SAAI,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,KAAK,GACtC,OAAM,IAAI,MAAM,mBAAmB;AAErC,YAAO,UAAU,OAAO,KAAK,IADD,KACY;;IAE3C;GACD,MAAM,EACJ,UAAU,OACR,QACA,GACA,QACG;AACH,QAAI,CAAC,OAAO,WAAY,QAAO;IAC/B,MAAM,SAAS,MAAM,IAAI,GAAG,MAC1B,8DACA,CAAC,OAAO,WAAW,CACpB;AACD,QAAI,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,KAAK,GAAI,QAAO;AACnD,WAAO,gBAAgB,OAAO,KAAK,GAAG;MAEzC;GACD,cAAc;IACZ,cAAc,OACZ,QACA,GACA,QACG;AAKH,aAJe,MAAM,IAAI,GAAG,MAC1B,uGACA,CAAC,OAAO,GAAG,CACZ,EACa,KAAK,IAAI,eAAe;;IAExC,UAAU,OACR,QACA,MACA,QACG;AAKH,aAJe,MAAM,IAAI,GAAG,MAC1B,iGACA,CAAC,OAAO,IAAI,KAAK,MAAM,CACxB,EACa,KAAK,IAAI,WAAW;;IAErC;GACD,QAAQ;IACN,UAAU,OACR,QACA,GACA,QACG;AACH,SAAI,CAAC,OAAO,WAAY,QAAO;KAC/B,MAAM,SAAS,MAAM,IAAI,GAAG,MAC1B,gEACA,CAAC,OAAO,WAAW,CACpB;AACD,SAAI,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,KAAK,GAAI,QAAO;AACnD,YAAO,kBAAkB,OAAO,KAAK,GAAG;;IAE1C,aAAa,OACX,QACA,GACA,QACG;AAKH,aAJe,MAAM,IAAI,GAAG,MAC1B,wFACA,CAAC,OAAO,GAAG,CACZ,EACa,KAAK,KAAK,QACtB,oBAAoB,KAAK,OAAO,OAAO,CACxC;;IAEH,cAAc,OACZ,QACA,GACA,QACG;AAKH,aAJe,MAAM,IAAI,GAAG,MAC1B,yFACA,CAAC,OAAO,GAAG,CACZ,EACa,KAAK,KAAK,QACtB,qBAAqB,KAAK,OAAO,OAAO,CACzC;;IAEJ;GACF;;;AAIL,SAAS,gBAAgB,KAAe;AACtC,QAAO;EACL,IAAI,IAAI;EACR,WAAW,IAAI;EACf,MAAM,IAAI;EACV,OAAO,IAAI;EACX,WAAW,IAAI;EACf,WAAW,IAAI;EAChB;;AAGH,SAAS,QAAQ,KAAe;AAC9B,QAAO;EACL,IAAI,IAAI;EACR,WAAW,IAAI;EACf,YAAY,IAAI;EAChB,OAAO,IAAI;EACX,aAAa,IAAI;EACjB,WAAW,QAAQ,IAAI,UAAU;EACjC,UAAU,IAAI,YAAY;EAC1B,SAAS,IAAI;EACb,MAAM,UAAU,IAAI,KAAK;EACzB,WAAW,IAAI;EACf,WAAW,IAAI;EAChB;;AAGH,SAAS,UAAU,OAAmC;AACpD,KAAI,OAAO,UAAU,SAAU,QAAO,EAAE;AACxC,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,MAAM;AAChC,SAAO,MAAM,QAAQ,OAAO,GAAI,SAAsB,EAAE;SAClD;AACN,SAAO,EAAE;;;AAIb,SAAS,gBAAgB,KAAe;AACtC,QAAO;EACL,IAAI,IAAI;EACR,WAAW,IAAI;EACf,MAAM,IAAI;EACV,SAAS,QAAQ,IAAI,QAAQ;EAC7B,WAAW,IAAI;EACf,eAAe,IAAI;EACnB,WAAW,IAAI;EAChB;;AAGH,SAAS,eAAe,KAAe;AACrC,QAAO;EACL,IAAI,IAAI;EACR,gBAAgB,IAAI;EACpB,WAAW,IAAI;EACf,QAAQ,IAAI;EACZ,aAAa,IAAI;EACjB,MAAM,IAAI;EACV,UAAU,IAAI;EACd,YAAY,IAAI;EACjB;;AAGH,SAAS,WAAW,KAAe;AACjC,QAAO;EACL,IAAI,IAAI;EACR,gBAAgB,IAAI;EACpB,WAAW,IAAI;EACf,UAAU,IAAI;EACd,YAAY,IAAI;EAChB,SAAS,IAAI;EACb,aAAa,EAAE;EACf,QAAQ,IAAI,UAAU;EACtB,WAAW,IAAI;EACf,WAAW,IAAI;EAChB;;AAGH,SAAS,UAAU,KAAe,QAAqB;AACrD,QAAO;EACL,IAAI,IAAI;EACR,WAAW,IAAI;EACf,QAAQ,IAAI;EACZ,QAAQ,IAAI;EACZ,MAAM,WAAW,OAAO,IAAI,SAAS,IAAI;EACzC,aAAa,WAAW,OAAO,IAAI,gBAAgB,IAAI;EACvD,cAAc,IAAI;EAClB,iBAAiB,IAAI,mBAAmB;EACxC,iBAAiB,IAAI,mBAAmB;EACxC,UAAU,IAAI,YAAY;EAC1B,YAAY,QAAQ,IAAI,WAAW;EACnC;EACA,YAAY,IAAI;EAChB,WAAW,IAAI;EACf,WAAW,IAAI;EAChB;;AAGH,SAAS,kBAAkB,KAAe;AACxC,QAAO;EACL,IAAI,IAAI;EACR,QAAQ,IAAI;EACZ,QAAQ,IAAI;EACZ,MAAM,IAAI;EACX;;AAGH,SAAS,oBAAoB,KAAe,QAAqB;AAC/D,QAAO;EACL,IAAI,IAAI;EACR,MAAM,WAAW,OAAO,IAAI,SAAS,IAAI;EACzC,UAAU,IAAI;EACd,UAAU,IAAI,YAAY;EAC3B;;AAGH,SAAS,qBAAqB,KAAe,QAAqB;AAChE,QAAO;EACL,IAAI,IAAI;EACR,SAAS,WAAW,OAAO,IAAI,YAAY,IAAI;EAC/C,UAAU,IAAI,YAAY;EAC3B"}
package/dist/web/index.js DELETED
@@ -1,68 +0,0 @@
1
- import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
- import { SANDBOX_MIGRATIONS } from "./database/migrations.js";
3
- import { agentDefinition, agentRun, agentRunLog, agentRunStep, agentTool, agentToolAssignment, analyticsDashboard, analyticsQuery, analyticsWidget, crmCompany, crmContact, crmDeal, crmPipeline, crmStage, integration, integrationConnection, integrationFieldMapping, integrationSyncConfig, marketplaceOrder, marketplaceOrderItem, marketplacePayout, marketplaceProduct, marketplaceReview, marketplaceStore, psaChangeCandidate, psaReviewTask, psaRule, psaRuleVersion, psaSnapshot, psaUserContext, saasProject, saasSubscription, saasUsage, templateConversation, templateConversationParticipant, templateMessage, templateRecipe, templateRecipeCategory, templateRecipeIngredient, templateRecipeInstruction, templateTask, templateTaskCategory, workflowApproval, workflowDefinition, workflowInstance, workflowStep } from "./database/schema.js";
4
- import { LocalStorageService } from "./storage/indexeddb.js";
5
- import { generateId } from "./utils/id.js";
6
- import { LocalEventBus } from "./events/local-pubsub.js";
7
- import { LocalGraphQLClient } from "./graphql/local-client.js";
8
- import { LocalRuntimeServices } from "./runtime/services.js";
9
-
10
- //#region src/web/index.ts
11
- var web_exports = /* @__PURE__ */ __exportAll({
12
- LocalEventBus: () => LocalEventBus,
13
- LocalGraphQLClient: () => LocalGraphQLClient,
14
- LocalRuntimeServices: () => LocalRuntimeServices,
15
- LocalStorageService: () => LocalStorageService,
16
- SANDBOX_MIGRATIONS: () => SANDBOX_MIGRATIONS,
17
- agentDefinition: () => agentDefinition,
18
- agentRun: () => agentRun,
19
- agentRunLog: () => agentRunLog,
20
- agentRunStep: () => agentRunStep,
21
- agentTool: () => agentTool,
22
- agentToolAssignment: () => agentToolAssignment,
23
- analyticsDashboard: () => analyticsDashboard,
24
- analyticsQuery: () => analyticsQuery,
25
- analyticsWidget: () => analyticsWidget,
26
- crmCompany: () => crmCompany,
27
- crmContact: () => crmContact,
28
- crmDeal: () => crmDeal,
29
- crmPipeline: () => crmPipeline,
30
- crmStage: () => crmStage,
31
- generateId: () => generateId,
32
- integration: () => integration,
33
- integrationConnection: () => integrationConnection,
34
- integrationFieldMapping: () => integrationFieldMapping,
35
- integrationSyncConfig: () => integrationSyncConfig,
36
- marketplaceOrder: () => marketplaceOrder,
37
- marketplaceOrderItem: () => marketplaceOrderItem,
38
- marketplacePayout: () => marketplacePayout,
39
- marketplaceProduct: () => marketplaceProduct,
40
- marketplaceReview: () => marketplaceReview,
41
- marketplaceStore: () => marketplaceStore,
42
- psaChangeCandidate: () => psaChangeCandidate,
43
- psaReviewTask: () => psaReviewTask,
44
- psaRule: () => psaRule,
45
- psaRuleVersion: () => psaRuleVersion,
46
- psaSnapshot: () => psaSnapshot,
47
- psaUserContext: () => psaUserContext,
48
- saasProject: () => saasProject,
49
- saasSubscription: () => saasSubscription,
50
- saasUsage: () => saasUsage,
51
- templateConversation: () => templateConversation,
52
- templateConversationParticipant: () => templateConversationParticipant,
53
- templateMessage: () => templateMessage,
54
- templateRecipe: () => templateRecipe,
55
- templateRecipeCategory: () => templateRecipeCategory,
56
- templateRecipeIngredient: () => templateRecipeIngredient,
57
- templateRecipeInstruction: () => templateRecipeInstruction,
58
- templateTask: () => templateTask,
59
- templateTaskCategory: () => templateTaskCategory,
60
- workflowApproval: () => workflowApproval,
61
- workflowDefinition: () => workflowDefinition,
62
- workflowInstance: () => workflowInstance,
63
- workflowStep: () => workflowStep
64
- });
65
-
66
- //#endregion
67
- export { web_exports };
68
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/web/index.ts"],"sourcesContent":["// Re-export database schema and types\nexport * from './database/migrations';\nexport * from './database/schema';\n\n// Storage\nexport * from './storage/indexeddb';\n\n// Utils\nexport * from './utils/id';\n\n// GraphQL client\nexport * from './graphql/local-client';\n\n// Event bus\nexport * from './events/local-pubsub';\n\n// Runtime services\nexport * from './runtime/services';\n\n// Handlers (Deprecated/Removed)\n// export * from './handlers';\n"],"mappings":""}
@@ -1,358 +0,0 @@
1
- //#region src/web/runtime/seeders/index.ts
2
- /**
3
- * Seed the database with template-specific data.
4
- *
5
- * Unknown templates are a no-op (safe default).
6
- */
7
- async function seedTemplate(params) {
8
- const { templateId, projectId, db } = params;
9
- switch (templateId) {
10
- case "todos-app": return seedTodos({
11
- projectId,
12
- db
13
- });
14
- case "messaging-app": return seedMessaging({
15
- projectId,
16
- db
17
- });
18
- case "recipe-app-i18n": return seedRecipes({
19
- projectId,
20
- db
21
- });
22
- case "crm-pipeline": return seedCrmPipeline({
23
- projectId,
24
- db
25
- });
26
- case "saas-boilerplate": return seedSaasBoilerplate({
27
- projectId,
28
- db
29
- });
30
- case "agent-console": return seedAgentConsole({
31
- projectId,
32
- db
33
- });
34
- case "workflow-system": return seedWorkflowSystem({
35
- projectId,
36
- db
37
- });
38
- case "marketplace": return seedMarketplace({
39
- projectId,
40
- db
41
- });
42
- case "integration-hub": return seedIntegrationHub({
43
- projectId,
44
- db
45
- });
46
- case "analytics-dashboard": return seedAnalyticsDashboard({
47
- projectId,
48
- db
49
- });
50
- case "policy-safe-knowledge-assistant": return seedPolicyKnowledgeAssistant({
51
- projectId,
52
- db
53
- });
54
- default: return;
55
- }
56
- }
57
- async function seedTodos(params) {
58
- const { projectId, db } = params;
59
- if ((await db.query(`SELECT COUNT(*) as count FROM template_task WHERE "projectId" = $1`, [projectId])).rows[0]?.count > 0) return;
60
- const workCategoryId = "todo_category_ops";
61
- const homeCategoryId = "todo_category_home";
62
- await db.execute(`INSERT INTO template_task_category (id, "projectId", name, color) VALUES ($1, $2, $3, $4)`, [
63
- workCategoryId,
64
- projectId,
65
- "Operations",
66
- "#8b5cf6"
67
- ]);
68
- await db.execute(`INSERT INTO template_task_category (id, "projectId", name, color) VALUES ($1, $2, $3, $4)`, [
69
- homeCategoryId,
70
- projectId,
71
- "Home",
72
- "#f472b6"
73
- ]);
74
- const tasks = [
75
- {
76
- id: "todo_task_1",
77
- title: "Review intent signals",
78
- description: "Scan yesterday's signals and flag the ones to promote.",
79
- categoryId: workCategoryId,
80
- priority: "HIGH"
81
- },
82
- {
83
- id: "todo_task_2",
84
- title: "Schedule studio walkthrough",
85
- description: "Prep the sandbox before tomorrow's ceremony.",
86
- categoryId: workCategoryId,
87
- priority: "MEDIUM"
88
- },
89
- {
90
- id: "todo_task_3",
91
- title: "Collect testimonials",
92
- description: "Ask last week's pilot crew for quotes.",
93
- categoryId: homeCategoryId,
94
- priority: "LOW"
95
- }
96
- ];
97
- for (const task of tasks) await db.execute(`INSERT INTO template_task (id, "projectId", "categoryId", title, description, completed, priority, tags)
98
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, [
99
- task.id,
100
- projectId,
101
- task.categoryId,
102
- task.title,
103
- task.description,
104
- 0,
105
- task.priority,
106
- JSON.stringify(["demo"])
107
- ]);
108
- }
109
- async function seedMessaging(params) {
110
- const { projectId, db } = params;
111
- if ((await db.query(`SELECT COUNT(*) as count FROM template_conversation WHERE "projectId" = $1`, [projectId])).rows[0]?.count > 0) return;
112
- const conversationId = "conv_demo_1";
113
- const now = (/* @__PURE__ */ new Date()).toISOString();
114
- await db.execute(`INSERT INTO template_conversation (id, "projectId", name, "isGroup", "avatarUrl", "updatedAt")
115
- VALUES ($1, $2, $3, $4, $5, $6)`, [
116
- conversationId,
117
- projectId,
118
- "Team Chat",
119
- 1,
120
- null,
121
- now
122
- ]);
123
- await db.execute(`INSERT INTO template_conversation_participant (id, "conversationId", "projectId", "userId", "displayName", role, "joinedAt")
124
- VALUES ($1, $2, $3, $4, $5, $6, $7)`, [
125
- "part_1",
126
- conversationId,
127
- projectId,
128
- "user_alice",
129
- "Alice",
130
- "member",
131
- now
132
- ]);
133
- await db.execute(`INSERT INTO template_conversation_participant (id, "conversationId", "projectId", "userId", "displayName", role, "joinedAt")
134
- VALUES ($1, $2, $3, $4, $5, $6, $7)`, [
135
- "part_2",
136
- conversationId,
137
- projectId,
138
- "user_bob",
139
- "Bob",
140
- "member",
141
- now
142
- ]);
143
- await db.execute(`INSERT INTO template_message (id, "conversationId", "projectId", "senderId", "senderName", content, attachments, status, "createdAt", "updatedAt")
144
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, [
145
- "msg_1",
146
- conversationId,
147
- projectId,
148
- "user_alice",
149
- "Alice",
150
- "Hey team! Ready for the demo?",
151
- JSON.stringify([]),
152
- "DELIVERED",
153
- now,
154
- now
155
- ]);
156
- }
157
- async function seedRecipes(params) {
158
- const { projectId, db } = params;
159
- if ((await db.query(`SELECT COUNT(*) as count FROM template_recipe WHERE "projectId" = $1`, [projectId])).rows[0]?.count > 0) return;
160
- await db.execute(`INSERT INTO template_recipe_category (id, "nameEn", "nameFr", icon) VALUES ($1, $2, $3, $4)`, [
161
- "cat_main",
162
- "Main Courses",
163
- "Plats Principaux",
164
- "🍽️"
165
- ]);
166
- const recipeId = "recipe_1";
167
- await db.execute(`INSERT INTO template_recipe (id, "projectId", "categoryId", "slugEn", "slugFr", "nameEn", "nameFr", "descriptionEn", "descriptionFr", "prepTimeMinutes", "cookTimeMinutes", servings, "isFavorite")
168
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`, [
169
- recipeId,
170
- projectId,
171
- "cat_main",
172
- "grilled-salmon",
173
- "saumon-grille",
174
- "Grilled Salmon",
175
- "Saumon Grillé",
176
- "Delicious grilled salmon with lemon",
177
- "Délicieux saumon grillé au citron",
178
- 10,
179
- 15,
180
- 4,
181
- 0
182
- ]);
183
- await db.execute(`INSERT INTO template_recipe_ingredient (id, "recipeId", "nameEn", "nameFr", quantity, ordering)
184
- VALUES ($1, $2, $3, $4, $5, $6)`, [
185
- "ing_1",
186
- recipeId,
187
- "Salmon fillet",
188
- "Filet de saumon",
189
- "4 pieces",
190
- 1
191
- ]);
192
- await db.execute(`INSERT INTO template_recipe_ingredient (id, "recipeId", "nameEn", "nameFr", quantity, ordering)
193
- VALUES ($1, $2, $3, $4, $5, $6)`, [
194
- "ing_2",
195
- recipeId,
196
- "Lemon",
197
- "Citron",
198
- "1 whole",
199
- 2
200
- ]);
201
- await db.execute(`INSERT INTO template_recipe_instruction (id, "recipeId", "contentEn", "contentFr", ordering)
202
- VALUES ($1, $2, $3, $4, $5)`, [
203
- "inst_1",
204
- recipeId,
205
- "Preheat grill to medium-high heat.",
206
- "Préchauffer le grill à feu moyen-vif.",
207
- 1
208
- ]);
209
- await db.execute(`INSERT INTO template_recipe_instruction (id, "recipeId", "contentEn", "contentFr", ordering)
210
- VALUES ($1, $2, $3, $4, $5)`, [
211
- "inst_2",
212
- recipeId,
213
- "Season salmon and grill for 4-5 minutes per side.",
214
- "Assaisonner le saumon et griller 4-5 minutes de chaque côté.",
215
- 2
216
- ]);
217
- }
218
- async function seedCrmPipeline(params) {
219
- const { projectId, db } = params;
220
- if ((await db.query(`SELECT COUNT(*) as count FROM crm_pipeline WHERE "projectId" = $1`, [projectId])).rows[0]?.count > 0) return;
221
- const pipelineId = "pipeline_sales";
222
- await db.execute(`INSERT INTO crm_pipeline (id, "projectId", name) VALUES ($1, $2, $3)`, [
223
- pipelineId,
224
- projectId,
225
- "Sales Pipeline"
226
- ]);
227
- for (const stage of [
228
- {
229
- id: "stage_lead",
230
- name: "Lead",
231
- position: 1
232
- },
233
- {
234
- id: "stage_contact",
235
- name: "Contact Made",
236
- position: 2
237
- },
238
- {
239
- id: "stage_proposal",
240
- name: "Proposal",
241
- position: 3
242
- },
243
- {
244
- id: "stage_negotiation",
245
- name: "Negotiation",
246
- position: 4
247
- },
248
- {
249
- id: "stage_closed",
250
- name: "Closed",
251
- position: 5
252
- }
253
- ]) await db.execute(`INSERT INTO crm_stage (id, "pipelineId", name, position) VALUES ($1, $2, $3, $4)`, [
254
- stage.id,
255
- pipelineId,
256
- stage.name,
257
- stage.position
258
- ]);
259
- }
260
- async function seedSaasBoilerplate(params) {
261
- const { projectId, db } = params;
262
- if ((await db.query(`SELECT COUNT(*) as count FROM saas_project WHERE "projectId" = $1`, [projectId])).rows[0]?.count > 0) return;
263
- await db.execute(`INSERT INTO saas_project (id, "projectId", "organizationId", name, description, status, tier)
264
- VALUES ($1, $2, $3, $4, $5, $6, $7)`, [
265
- "saas_proj_1",
266
- projectId,
267
- "org_demo",
268
- "Demo Project",
269
- "A demo SaaS project",
270
- "ACTIVE",
271
- "PRO"
272
- ]);
273
- }
274
- async function seedAgentConsole(params) {
275
- const { projectId, db } = params;
276
- if ((await db.query(`SELECT COUNT(*) as count FROM agent_definition WHERE "projectId" = $1`, [projectId])).rows[0]?.count > 0) return;
277
- await db.execute(`INSERT INTO agent_definition (id, "projectId", "organizationId", name, description, "modelProvider", "modelName", status)
278
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, [
279
- "agent_1",
280
- projectId,
281
- "org_demo",
282
- "Demo Agent",
283
- "A demo AI agent",
284
- "openai",
285
- "gpt-4",
286
- "ACTIVE"
287
- ]);
288
- }
289
- async function seedWorkflowSystem(params) {
290
- const { projectId, db } = params;
291
- if ((await db.query(`SELECT COUNT(*) as count FROM workflow_definition WHERE "projectId" = $1`, [projectId])).rows[0]?.count > 0) return;
292
- await db.execute(`INSERT INTO workflow_definition (id, "projectId", "organizationId", name, description, type, status)
293
- VALUES ($1, $2, $3, $4, $5, $6, $7)`, [
294
- "wf_1",
295
- projectId,
296
- "org_demo",
297
- "Approval Workflow",
298
- "Demo approval workflow",
299
- "APPROVAL",
300
- "ACTIVE"
301
- ]);
302
- }
303
- async function seedMarketplace(params) {
304
- const { projectId, db } = params;
305
- if ((await db.query(`SELECT COUNT(*) as count FROM marketplace_store WHERE "projectId" = $1`, [projectId])).rows[0]?.count > 0) return;
306
- await db.execute(`INSERT INTO marketplace_store (id, "projectId", "organizationId", name, description, status)
307
- VALUES ($1, $2, $3, $4, $5, $6)`, [
308
- "store_1",
309
- projectId,
310
- "org_demo",
311
- "Demo Store",
312
- "A demo store",
313
- "ACTIVE"
314
- ]);
315
- }
316
- async function seedIntegrationHub(params) {
317
- const { projectId, db } = params;
318
- if ((await db.query(`SELECT COUNT(*) as count FROM integration WHERE "projectId" = $1`, [projectId])).rows[0]?.count > 0) return;
319
- await db.execute(`INSERT INTO integration (id, "projectId", "organizationId", name, description, type, status)
320
- VALUES ($1, $2, $3, $4, $5, $6, $7)`, [
321
- "int_1",
322
- projectId,
323
- "org_demo",
324
- "Salesforce",
325
- "Salesforce CRM integration",
326
- "CRM",
327
- "ACTIVE"
328
- ]);
329
- }
330
- async function seedAnalyticsDashboard(params) {
331
- const { projectId, db } = params;
332
- if ((await db.query(`SELECT COUNT(*) as count FROM analytics_dashboard WHERE "projectId" = $1`, [projectId])).rows[0]?.count > 0) return;
333
- await db.execute(`INSERT INTO analytics_dashboard (id, "projectId", "organizationId", name, slug, description, status)
334
- VALUES ($1, $2, $3, $4, $5, $6, $7)`, [
335
- "dash_1",
336
- projectId,
337
- "org_demo",
338
- "Sales Overview",
339
- "sales-overview",
340
- "Sales performance dashboard",
341
- "PUBLISHED"
342
- ]);
343
- }
344
- async function seedPolicyKnowledgeAssistant(params) {
345
- const { projectId, db } = params;
346
- if ((await db.query(`SELECT COUNT(*) as count FROM psa_user_context WHERE "projectId" = $1`, [projectId])).rows[0]?.count > 0) return;
347
- await db.execute(`INSERT INTO psa_user_context ("projectId", locale, jurisdiction, "allowedScope")
348
- VALUES ($1, $2, $3, $4)`, [
349
- projectId,
350
- "en-GB",
351
- "EU",
352
- "education_only"
353
- ]);
354
- }
355
-
356
- //#endregion
357
- export { seedTemplate };
358
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/web/runtime/seeders/index.ts"],"sourcesContent":["/**\n * Seed template data into the sandbox database.\n *\n * Lazy-loads individual seeders to avoid bundle bloat.\n */\nimport type { DatabasePort } from '@contractspec/lib.runtime-sandbox';\nimport type { TemplateId } from '../services';\n\nexport interface SeedTemplateParams {\n templateId: TemplateId;\n projectId: string;\n db: DatabasePort;\n}\n\n/**\n * Seed the database with template-specific data.\n *\n * Unknown templates are a no-op (safe default).\n */\nexport async function seedTemplate(params: SeedTemplateParams): Promise<void> {\n const { templateId, projectId, db } = params;\n\n switch (templateId) {\n case 'todos-app':\n return seedTodos({ projectId, db });\n case 'messaging-app':\n return seedMessaging({ projectId, db });\n case 'recipe-app-i18n':\n return seedRecipes({ projectId, db });\n case 'crm-pipeline':\n return seedCrmPipeline({ projectId, db });\n case 'saas-boilerplate':\n return seedSaasBoilerplate({ projectId, db });\n case 'agent-console':\n return seedAgentConsole({ projectId, db });\n case 'workflow-system':\n return seedWorkflowSystem({ projectId, db });\n case 'marketplace':\n return seedMarketplace({ projectId, db });\n case 'integration-hub':\n return seedIntegrationHub({ projectId, db });\n case 'analytics-dashboard':\n return seedAnalyticsDashboard({ projectId, db });\n case 'policy-safe-knowledge-assistant':\n return seedPolicyKnowledgeAssistant({ projectId, db });\n default:\n // Unknown template - no-op\n return;\n }\n}\n\n// --------------------------------------------------------------------------\n// Individual seeder functions with PostgreSQL syntax\n// --------------------------------------------------------------------------\n\nasync function seedTodos(params: { projectId: string; db: DatabasePort }) {\n const { projectId, db } = params;\n\n // Check if already seeded\n const existing = await db.query(\n `SELECT COUNT(*) as count FROM template_task WHERE \"projectId\" = $1`,\n [projectId]\n );\n if ((existing.rows[0]?.count as number) > 0) return;\n\n const workCategoryId = 'todo_category_ops';\n const homeCategoryId = 'todo_category_home';\n\n await db.execute(\n `INSERT INTO template_task_category (id, \"projectId\", name, color) VALUES ($1, $2, $3, $4)`,\n [workCategoryId, projectId, 'Operations', '#8b5cf6']\n );\n await db.execute(\n `INSERT INTO template_task_category (id, \"projectId\", name, color) VALUES ($1, $2, $3, $4)`,\n [homeCategoryId, projectId, 'Home', '#f472b6']\n );\n\n const tasks = [\n {\n id: 'todo_task_1',\n title: 'Review intent signals',\n description: \"Scan yesterday's signals and flag the ones to promote.\",\n categoryId: workCategoryId,\n priority: 'HIGH',\n },\n {\n id: 'todo_task_2',\n title: 'Schedule studio walkthrough',\n description: \"Prep the sandbox before tomorrow's ceremony.\",\n categoryId: workCategoryId,\n priority: 'MEDIUM',\n },\n {\n id: 'todo_task_3',\n title: 'Collect testimonials',\n description: \"Ask last week's pilot crew for quotes.\",\n categoryId: homeCategoryId,\n priority: 'LOW',\n },\n ];\n\n for (const task of tasks) {\n await db.execute(\n `INSERT INTO template_task (id, \"projectId\", \"categoryId\", title, description, completed, priority, tags)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,\n [\n task.id,\n projectId,\n task.categoryId,\n task.title,\n task.description,\n 0,\n task.priority,\n JSON.stringify(['demo']),\n ]\n );\n }\n}\n\nasync function seedMessaging(params: { projectId: string; db: DatabasePort }) {\n const { projectId, db } = params;\n\n const existing = await db.query(\n `SELECT COUNT(*) as count FROM template_conversation WHERE \"projectId\" = $1`,\n [projectId]\n );\n if ((existing.rows[0]?.count as number) > 0) return;\n\n const conversationId = 'conv_demo_1';\n const now = new Date().toISOString();\n\n await db.execute(\n `INSERT INTO template_conversation (id, \"projectId\", name, \"isGroup\", \"avatarUrl\", \"updatedAt\")\n VALUES ($1, $2, $3, $4, $5, $6)`,\n [conversationId, projectId, 'Team Chat', 1, null, now]\n );\n\n // Add participants\n await db.execute(\n `INSERT INTO template_conversation_participant (id, \"conversationId\", \"projectId\", \"userId\", \"displayName\", role, \"joinedAt\")\n VALUES ($1, $2, $3, $4, $5, $6, $7)`,\n ['part_1', conversationId, projectId, 'user_alice', 'Alice', 'member', now]\n );\n await db.execute(\n `INSERT INTO template_conversation_participant (id, \"conversationId\", \"projectId\", \"userId\", \"displayName\", role, \"joinedAt\")\n VALUES ($1, $2, $3, $4, $5, $6, $7)`,\n ['part_2', conversationId, projectId, 'user_bob', 'Bob', 'member', now]\n );\n\n // Add messages\n await db.execute(\n `INSERT INTO template_message (id, \"conversationId\", \"projectId\", \"senderId\", \"senderName\", content, attachments, status, \"createdAt\", \"updatedAt\")\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,\n [\n 'msg_1',\n conversationId,\n projectId,\n 'user_alice',\n 'Alice',\n 'Hey team! Ready for the demo?',\n JSON.stringify([]),\n 'DELIVERED',\n now,\n now,\n ]\n );\n}\n\nasync function seedRecipes(params: { projectId: string; db: DatabasePort }) {\n const { projectId, db } = params;\n\n const existing = await db.query(\n `SELECT COUNT(*) as count FROM template_recipe WHERE \"projectId\" = $1`,\n [projectId]\n );\n if ((existing.rows[0]?.count as number) > 0) return;\n\n // Add category\n await db.execute(\n `INSERT INTO template_recipe_category (id, \"nameEn\", \"nameFr\", icon) VALUES ($1, $2, $3, $4)`,\n ['cat_main', 'Main Courses', 'Plats Principaux', '🍽️']\n );\n\n // Add recipe\n const recipeId = 'recipe_1';\n await db.execute(\n `INSERT INTO template_recipe (id, \"projectId\", \"categoryId\", \"slugEn\", \"slugFr\", \"nameEn\", \"nameFr\", \"descriptionEn\", \"descriptionFr\", \"prepTimeMinutes\", \"cookTimeMinutes\", servings, \"isFavorite\")\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`,\n [\n recipeId,\n projectId,\n 'cat_main',\n 'grilled-salmon',\n 'saumon-grille',\n 'Grilled Salmon',\n 'Saumon Grillé',\n 'Delicious grilled salmon with lemon',\n 'Délicieux saumon grillé au citron',\n 10,\n 15,\n 4,\n 0,\n ]\n );\n\n // Add ingredients\n await db.execute(\n `INSERT INTO template_recipe_ingredient (id, \"recipeId\", \"nameEn\", \"nameFr\", quantity, ordering)\n VALUES ($1, $2, $3, $4, $5, $6)`,\n ['ing_1', recipeId, 'Salmon fillet', 'Filet de saumon', '4 pieces', 1]\n );\n await db.execute(\n `INSERT INTO template_recipe_ingredient (id, \"recipeId\", \"nameEn\", \"nameFr\", quantity, ordering)\n VALUES ($1, $2, $3, $4, $5, $6)`,\n ['ing_2', recipeId, 'Lemon', 'Citron', '1 whole', 2]\n );\n\n // Add instructions\n await db.execute(\n `INSERT INTO template_recipe_instruction (id, \"recipeId\", \"contentEn\", \"contentFr\", ordering)\n VALUES ($1, $2, $3, $4, $5)`,\n [\n 'inst_1',\n recipeId,\n 'Preheat grill to medium-high heat.',\n 'Préchauffer le grill à feu moyen-vif.',\n 1,\n ]\n );\n await db.execute(\n `INSERT INTO template_recipe_instruction (id, \"recipeId\", \"contentEn\", \"contentFr\", ordering)\n VALUES ($1, $2, $3, $4, $5)`,\n [\n 'inst_2',\n recipeId,\n 'Season salmon and grill for 4-5 minutes per side.',\n 'Assaisonner le saumon et griller 4-5 minutes de chaque côté.',\n 2,\n ]\n );\n}\n\nasync function seedCrmPipeline(params: {\n projectId: string;\n db: DatabasePort;\n}) {\n const { projectId, db } = params;\n\n const existing = await db.query(\n `SELECT COUNT(*) as count FROM crm_pipeline WHERE \"projectId\" = $1`,\n [projectId]\n );\n if ((existing.rows[0]?.count as number) > 0) return;\n\n const pipelineId = 'pipeline_sales';\n await db.execute(\n `INSERT INTO crm_pipeline (id, \"projectId\", name) VALUES ($1, $2, $3)`,\n [pipelineId, projectId, 'Sales Pipeline']\n );\n\n const stages = [\n { id: 'stage_lead', name: 'Lead', position: 1 },\n { id: 'stage_contact', name: 'Contact Made', position: 2 },\n { id: 'stage_proposal', name: 'Proposal', position: 3 },\n { id: 'stage_negotiation', name: 'Negotiation', position: 4 },\n { id: 'stage_closed', name: 'Closed', position: 5 },\n ];\n\n for (const stage of stages) {\n await db.execute(\n `INSERT INTO crm_stage (id, \"pipelineId\", name, position) VALUES ($1, $2, $3, $4)`,\n [stage.id, pipelineId, stage.name, stage.position]\n );\n }\n}\n\nasync function seedSaasBoilerplate(params: {\n projectId: string;\n db: DatabasePort;\n}) {\n const { projectId, db } = params;\n\n const existing = await db.query(\n `SELECT COUNT(*) as count FROM saas_project WHERE \"projectId\" = $1`,\n [projectId]\n );\n if ((existing.rows[0]?.count as number) > 0) return;\n\n await db.execute(\n `INSERT INTO saas_project (id, \"projectId\", \"organizationId\", name, description, status, tier)\n VALUES ($1, $2, $3, $4, $5, $6, $7)`,\n [\n 'saas_proj_1',\n projectId,\n 'org_demo',\n 'Demo Project',\n 'A demo SaaS project',\n 'ACTIVE',\n 'PRO',\n ]\n );\n}\n\nasync function seedAgentConsole(params: {\n projectId: string;\n db: DatabasePort;\n}) {\n const { projectId, db } = params;\n\n const existing = await db.query(\n `SELECT COUNT(*) as count FROM agent_definition WHERE \"projectId\" = $1`,\n [projectId]\n );\n if ((existing.rows[0]?.count as number) > 0) return;\n\n await db.execute(\n `INSERT INTO agent_definition (id, \"projectId\", \"organizationId\", name, description, \"modelProvider\", \"modelName\", status)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,\n [\n 'agent_1',\n projectId,\n 'org_demo',\n 'Demo Agent',\n 'A demo AI agent',\n 'openai',\n 'gpt-4',\n 'ACTIVE',\n ]\n );\n}\n\nasync function seedWorkflowSystem(params: {\n projectId: string;\n db: DatabasePort;\n}) {\n const { projectId, db } = params;\n\n const existing = await db.query(\n `SELECT COUNT(*) as count FROM workflow_definition WHERE \"projectId\" = $1`,\n [projectId]\n );\n if ((existing.rows[0]?.count as number) > 0) return;\n\n await db.execute(\n `INSERT INTO workflow_definition (id, \"projectId\", \"organizationId\", name, description, type, status)\n VALUES ($1, $2, $3, $4, $5, $6, $7)`,\n [\n 'wf_1',\n projectId,\n 'org_demo',\n 'Approval Workflow',\n 'Demo approval workflow',\n 'APPROVAL',\n 'ACTIVE',\n ]\n );\n}\n\nasync function seedMarketplace(params: {\n projectId: string;\n db: DatabasePort;\n}) {\n const { projectId, db } = params;\n\n const existing = await db.query(\n `SELECT COUNT(*) as count FROM marketplace_store WHERE \"projectId\" = $1`,\n [projectId]\n );\n if ((existing.rows[0]?.count as number) > 0) return;\n\n await db.execute(\n `INSERT INTO marketplace_store (id, \"projectId\", \"organizationId\", name, description, status)\n VALUES ($1, $2, $3, $4, $5, $6)`,\n ['store_1', projectId, 'org_demo', 'Demo Store', 'A demo store', 'ACTIVE']\n );\n}\n\nasync function seedIntegrationHub(params: {\n projectId: string;\n db: DatabasePort;\n}) {\n const { projectId, db } = params;\n\n const existing = await db.query(\n `SELECT COUNT(*) as count FROM integration WHERE \"projectId\" = $1`,\n [projectId]\n );\n if ((existing.rows[0]?.count as number) > 0) return;\n\n await db.execute(\n `INSERT INTO integration (id, \"projectId\", \"organizationId\", name, description, type, status)\n VALUES ($1, $2, $3, $4, $5, $6, $7)`,\n [\n 'int_1',\n projectId,\n 'org_demo',\n 'Salesforce',\n 'Salesforce CRM integration',\n 'CRM',\n 'ACTIVE',\n ]\n );\n}\n\nasync function seedAnalyticsDashboard(params: {\n projectId: string;\n db: DatabasePort;\n}) {\n const { projectId, db } = params;\n\n const existing = await db.query(\n `SELECT COUNT(*) as count FROM analytics_dashboard WHERE \"projectId\" = $1`,\n [projectId]\n );\n if ((existing.rows[0]?.count as number) > 0) return;\n\n await db.execute(\n `INSERT INTO analytics_dashboard (id, \"projectId\", \"organizationId\", name, slug, description, status)\n VALUES ($1, $2, $3, $4, $5, $6, $7)`,\n [\n 'dash_1',\n projectId,\n 'org_demo',\n 'Sales Overview',\n 'sales-overview',\n 'Sales performance dashboard',\n 'PUBLISHED',\n ]\n );\n}\n\nasync function seedPolicyKnowledgeAssistant(params: {\n projectId: string;\n db: DatabasePort;\n}) {\n const { projectId, db } = params;\n\n const existing = await db.query(\n `SELECT COUNT(*) as count FROM psa_user_context WHERE \"projectId\" = $1`,\n [projectId]\n );\n if ((existing.rows[0]?.count as number) > 0) return;\n\n await db.execute(\n `INSERT INTO psa_user_context (\"projectId\", locale, jurisdiction, \"allowedScope\")\n VALUES ($1, $2, $3, $4)`,\n [projectId, 'en-GB', 'EU', 'education_only']\n );\n}\n"],"mappings":"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"}
@@ -1,80 +0,0 @@
1
- import { SANDBOX_MIGRATIONS } from "../database/migrations.js";
2
- import { LocalStorageService } from "../storage/indexeddb.js";
3
- import { LocalEventBus } from "../events/local-pubsub.js";
4
- import { LocalGraphQLClient } from "../graphql/local-client.js";
5
-
6
- //#region src/web/runtime/services.ts
7
- const DEFAULT_PROJECT_ID = "local-project";
8
- /**
9
- * Local runtime services for sandbox environment.
10
- *
11
- * Provides lazy-loaded database access via DatabasePort interface.
12
- */
13
- var LocalRuntimeServices = class {
14
- storage = new LocalStorageService();
15
- pubsub = new LocalEventBus();
16
- #initialized = false;
17
- _db;
18
- /**
19
- * Get the database port (must be initialized first).
20
- */
21
- get db() {
22
- if (!this._db) throw new Error("LocalRuntimeServices not initialized. Call init() first.");
23
- return this._db;
24
- }
25
- _graphql;
26
- /**
27
- * Get the GraphQL client (must be initialized first).
28
- */
29
- get graphql() {
30
- if (!this._graphql) throw new Error("LocalRuntimeServices not initialized. Call init() first.");
31
- return this._graphql;
32
- }
33
- /**
34
- * Initialize the runtime services.
35
- *
36
- * Lazy-loads PGLite adapter to avoid bundle bloat.
37
- */
38
- async init(options = {}) {
39
- if (this.#initialized) return;
40
- const { createPGLiteAdapter } = await import("@contractspec/lib.runtime-sandbox");
41
- this._db = await createPGLiteAdapter();
42
- await this._db.init({ dataDir: options.dataDir });
43
- await this._db.migrate(SANDBOX_MIGRATIONS);
44
- await this.storage.init();
45
- this._graphql = new LocalGraphQLClient({
46
- db: this._db,
47
- storage: this.storage,
48
- pubsub: this.pubsub
49
- });
50
- this.#initialized = true;
51
- }
52
- /**
53
- * Check if runtime is initialized.
54
- */
55
- isInitialized() {
56
- return this.#initialized;
57
- }
58
- /**
59
- * Seed the database with deterministic defaults for a template.
60
- *
61
- * - No randomness
62
- * - No wall-clock timestamps
63
- * - Unknown templates are a no-op (safe default)
64
- */
65
- async seedTemplate(options) {
66
- if (!this.#initialized) throw new Error("Call init() before seeding templates.");
67
- const projectId = options.projectId ?? DEFAULT_PROJECT_ID;
68
- if (!this._db) throw new Error("Database not initialized");
69
- const { seedTemplate } = await import("./seeders/index.js");
70
- await seedTemplate({
71
- templateId: options.templateId,
72
- projectId,
73
- db: this._db
74
- });
75
- }
76
- };
77
-
78
- //#endregion
79
- export { LocalRuntimeServices };
80
- //# sourceMappingURL=services.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"services.js","names":["#initialized"],"sources":["../../../src/web/runtime/services.ts"],"sourcesContent":["/**\n * Runtime services for local (browser) sandbox environment.\n *\n * Uses lazy-loading for PGLite to avoid bundle bloat.\n */\nimport type { DatabasePort } from '@contractspec/lib.runtime-sandbox';\n\nimport { LocalEventBus } from '../events/local-pubsub';\nimport { LocalGraphQLClient } from '../graphql/local-client';\nimport { LocalStorageService } from '../storage/indexeddb';\n\nimport { SANDBOX_MIGRATIONS } from '../database/migrations';\n\nexport type TemplateId = string;\n\nexport interface LocalRuntimeInitOptions {\n /**\n * Data directory for IndexedDB persistence (optional).\n * If omitted, uses in-memory database.\n */\n dataDir?: string;\n}\n\nexport interface TemplateSeedOptions {\n templateId: TemplateId;\n projectId?: string;\n}\n\nconst DEFAULT_PROJECT_ID = 'local-project' as const;\n\n/**\n * Local runtime services for sandbox environment.\n *\n * Provides lazy-loaded database access via DatabasePort interface.\n */\nexport class LocalRuntimeServices {\n readonly storage = new LocalStorageService();\n readonly pubsub = new LocalEventBus();\n #initialized = false;\n\n private _db?: DatabasePort;\n\n /**\n * Get the database port (must be initialized first).\n */\n get db(): DatabasePort {\n if (!this._db) {\n throw new Error(\n 'LocalRuntimeServices not initialized. Call init() first.'\n );\n }\n return this._db;\n }\n\n private _graphql?: LocalGraphQLClient;\n\n /**\n * Get the GraphQL client (must be initialized first).\n */\n get graphql(): LocalGraphQLClient {\n if (!this._graphql) {\n throw new Error(\n 'LocalRuntimeServices not initialized. Call init() first.'\n );\n }\n return this._graphql;\n }\n\n /**\n * Initialize the runtime services.\n *\n * Lazy-loads PGLite adapter to avoid bundle bloat.\n */\n async init(options: LocalRuntimeInitOptions = {}): Promise<void> {\n if (this.#initialized) return;\n\n // Lazy-load PGLite adapter\n const { createPGLiteAdapter } =\n await import('@contractspec/lib.runtime-sandbox');\n this._db = await createPGLiteAdapter();\n await this._db.init({ dataDir: options.dataDir });\n\n // Run migrations\n await this._db.migrate(SANDBOX_MIGRATIONS);\n\n // Initialize storage\n await this.storage.init();\n\n // Initialize GraphQL client with the new database port\n this._graphql = new LocalGraphQLClient({\n db: this._db,\n storage: this.storage,\n pubsub: this.pubsub,\n });\n\n this.#initialized = true;\n }\n\n /**\n * Check if runtime is initialized.\n */\n isInitialized(): boolean {\n return this.#initialized;\n }\n\n /**\n * Seed the database with deterministic defaults for a template.\n *\n * - No randomness\n * - No wall-clock timestamps\n * - Unknown templates are a no-op (safe default)\n */\n async seedTemplate(options: TemplateSeedOptions): Promise<void> {\n if (!this.#initialized) {\n throw new Error('Call init() before seeding templates.');\n }\n\n const projectId = options.projectId ?? DEFAULT_PROJECT_ID;\n\n if (!this._db) {\n throw new Error('Database not initialized');\n }\n\n // Lazy-load seeders to avoid bundle bloat\n const { seedTemplate } = await import('./seeders');\n await seedTemplate({\n templateId: options.templateId,\n projectId,\n db: this._db,\n });\n }\n}\n"],"mappings":";;;;;;AA4BA,MAAM,qBAAqB;;;;;;AAO3B,IAAa,uBAAb,MAAkC;CAChC,AAAS,UAAU,IAAI,qBAAqB;CAC5C,AAAS,SAAS,IAAI,eAAe;CACrC,eAAe;CAEf,AAAQ;;;;CAKR,IAAI,KAAmB;AACrB,MAAI,CAAC,KAAK,IACR,OAAM,IAAI,MACR,2DACD;AAEH,SAAO,KAAK;;CAGd,AAAQ;;;;CAKR,IAAI,UAA8B;AAChC,MAAI,CAAC,KAAK,SACR,OAAM,IAAI,MACR,2DACD;AAEH,SAAO,KAAK;;;;;;;CAQd,MAAM,KAAK,UAAmC,EAAE,EAAiB;AAC/D,MAAI,MAAKA,YAAc;EAGvB,MAAM,EAAE,wBACN,MAAM,OAAO;AACf,OAAK,MAAM,MAAM,qBAAqB;AACtC,QAAM,KAAK,IAAI,KAAK,EAAE,SAAS,QAAQ,SAAS,CAAC;AAGjD,QAAM,KAAK,IAAI,QAAQ,mBAAmB;AAG1C,QAAM,KAAK,QAAQ,MAAM;AAGzB,OAAK,WAAW,IAAI,mBAAmB;GACrC,IAAI,KAAK;GACT,SAAS,KAAK;GACd,QAAQ,KAAK;GACd,CAAC;AAEF,QAAKA,cAAe;;;;;CAMtB,gBAAyB;AACvB,SAAO,MAAKA;;;;;;;;;CAUd,MAAM,aAAa,SAA6C;AAC9D,MAAI,CAAC,MAAKA,YACR,OAAM,IAAI,MAAM,wCAAwC;EAG1D,MAAM,YAAY,QAAQ,aAAa;AAEvC,MAAI,CAAC,KAAK,IACR,OAAM,IAAI,MAAM,2BAA2B;EAI7C,MAAM,EAAE,iBAAiB,MAAM,OAAO;AACtC,QAAM,aAAa;GACjB,YAAY,QAAQ;GACpB;GACA,IAAI,KAAK;GACV,CAAC"}