@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":"schema.js","names":[],"sources":["../../../src/web/database/schema.ts"],"sourcesContent":["/**\n * Drizzle schema for sandbox runtime database tables.\n *\n * This schema defines all tables used by the template examples:\n * - Todos (tasks, categories)\n * - Messaging (conversations, participants, messages)\n * - Recipes (categories, recipes, ingredients, instructions)\n * - CRM (pipelines, stages, deals, companies, contacts)\n * - SaaS (projects, subscriptions, usage)\n * - Agent Console (tools, definitions, runs, steps, logs)\n * - Workflow System (definitions, steps, instances, approvals)\n * - Marketplace (stores, products, orders, items, payouts, reviews)\n * - Integration Hub (integrations, connections, syncs, mappings)\n * - Analytics (dashboards, widgets, queries)\n * - Policy-Safe Knowledge Assistant (contexts, rules, versions, snapshots, candidates, tasks)\n */\nimport { integer, pgTable, real, text, timestamp } from 'drizzle-orm/pg-core';\n\n// ============ Todos Template ============\n\nexport const templateTaskCategory = pgTable('template_task_category', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n name: text('name').notNull(),\n color: text('color'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const templateTask = pgTable('template_task', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n categoryId: text('categoryId'),\n title: text('title').notNull(),\n description: text('description'),\n completed: integer('completed').default(0),\n priority: text('priority').default('MEDIUM'),\n dueDate: text('dueDate'),\n tags: text('tags'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\n// ============ Messaging Template ============\n\nexport const templateConversation = pgTable('template_conversation', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n name: text('name'),\n isGroup: integer('isGroup').default(0),\n avatarUrl: text('avatarUrl'),\n lastMessageId: text('lastMessageId'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const templateConversationParticipant = pgTable(\n 'template_conversation_participant',\n {\n id: text('id').primaryKey(),\n conversationId: text('conversationId').notNull(),\n projectId: text('projectId').notNull(),\n userId: text('userId').notNull(),\n displayName: text('displayName'),\n role: text('role'),\n joinedAt: timestamp('joinedAt').defaultNow(),\n lastReadAt: text('lastReadAt'),\n }\n);\n\nexport const templateMessage = pgTable('template_message', {\n id: text('id').primaryKey(),\n conversationId: text('conversationId').notNull(),\n projectId: text('projectId').notNull(),\n senderId: text('senderId').notNull(),\n senderName: text('senderName'),\n content: text('content').notNull(),\n attachments: text('attachments'),\n status: text('status').default('SENT'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\n// ============ Recipes Template ============\n\nexport const templateRecipeCategory = pgTable('template_recipe_category', {\n id: text('id').primaryKey(),\n nameEn: text('nameEn').notNull(),\n nameFr: text('nameFr').notNull(),\n icon: text('icon'),\n});\n\nexport const templateRecipe = pgTable('template_recipe', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n categoryId: text('categoryId'),\n slugEn: text('slugEn').notNull(),\n slugFr: text('slugFr').notNull(),\n nameEn: text('nameEn').notNull(),\n nameFr: text('nameFr').notNull(),\n descriptionEn: text('descriptionEn'),\n descriptionFr: text('descriptionFr'),\n heroImageUrl: text('heroImageUrl'),\n prepTimeMinutes: integer('prepTimeMinutes'),\n cookTimeMinutes: integer('cookTimeMinutes'),\n servings: integer('servings'),\n isFavorite: integer('isFavorite').default(0),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const templateRecipeIngredient = pgTable('template_recipe_ingredient', {\n id: text('id').primaryKey(),\n recipeId: text('recipeId').notNull(),\n nameEn: text('nameEn').notNull(),\n nameFr: text('nameFr').notNull(),\n quantity: text('quantity').notNull(),\n ordering: integer('ordering').default(0),\n});\n\nexport const templateRecipeInstruction = pgTable(\n 'template_recipe_instruction',\n {\n id: text('id').primaryKey(),\n recipeId: text('recipeId').notNull(),\n contentEn: text('contentEn').notNull(),\n contentFr: text('contentFr').notNull(),\n ordering: integer('ordering').default(0),\n }\n);\n\n// ============ CRM Template ============\n\nexport const crmPipeline = pgTable('crm_pipeline', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n name: text('name').notNull(),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const crmStage = pgTable('crm_stage', {\n id: text('id').primaryKey(),\n pipelineId: text('pipelineId').notNull(),\n name: text('name').notNull(),\n position: integer('position').notNull(),\n createdAt: timestamp('createdAt').defaultNow(),\n});\n\nexport const crmDeal = pgTable('crm_deal', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n pipelineId: text('pipelineId').notNull(),\n stageId: text('stageId').notNull(),\n name: text('name').notNull(),\n value: real('value').notNull().default(0),\n currency: text('currency').default('USD'),\n status: text('status').default('OPEN'),\n contactId: text('contactId'),\n companyId: text('companyId'),\n ownerId: text('ownerId').notNull(),\n expectedCloseDate: text('expectedCloseDate'),\n wonSource: text('wonSource'),\n lostReason: text('lostReason'),\n notes: text('notes'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const crmCompany = pgTable('crm_company', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n name: text('name').notNull(),\n domain: text('domain'),\n industry: text('industry'),\n size: text('size'),\n website: text('website'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const crmContact = pgTable('crm_contact', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n companyId: text('companyId'),\n firstName: text('firstName').notNull(),\n lastName: text('lastName'),\n email: text('email'),\n phone: text('phone'),\n title: text('title'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\n// ============ SaaS Template ============\n\nexport const saasProject = pgTable('saas_project', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n organizationId: text('organizationId').notNull(),\n name: text('name').notNull(),\n description: text('description'),\n status: text('status').default('DRAFT'),\n tier: text('tier').default('FREE'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const saasSubscription = pgTable('saas_subscription', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n organizationId: text('organizationId').notNull(),\n plan: text('plan').notNull().default('FREE'),\n status: text('status').default('ACTIVE'),\n billingCycle: text('billingCycle').default('MONTHLY'),\n currentPeriodStart: text('currentPeriodStart'),\n currentPeriodEnd: text('currentPeriodEnd'),\n cancelAtPeriodEnd: integer('cancelAtPeriodEnd').default(0),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const saasUsage = pgTable('saas_usage', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n organizationId: text('organizationId').notNull(),\n metricName: text('metricName').notNull(),\n value: real('value').notNull().default(0),\n periodStart: text('periodStart').notNull(),\n periodEnd: text('periodEnd').notNull(),\n createdAt: timestamp('createdAt').defaultNow(),\n});\n\n// ============ Agent Console Template ============\n\nexport const agentTool = pgTable('agent_tool', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n organizationId: text('organizationId').notNull(),\n name: text('name').notNull(),\n description: text('description'),\n version: text('version').default('1.0.0'),\n category: text('category').default('UTILITY'),\n status: text('status').default('ACTIVE'),\n inputSchema: text('inputSchema'),\n outputSchema: text('outputSchema'),\n endpoint: text('endpoint'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const agentDefinition = pgTable('agent_definition', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n organizationId: text('organizationId').notNull(),\n name: text('name').notNull(),\n description: text('description'),\n modelProvider: text('modelProvider').default('openai'),\n modelName: text('modelName').default('gpt-4'),\n systemPrompt: text('systemPrompt'),\n temperature: real('temperature').default(0.7),\n maxTokens: integer('maxTokens').default(4096),\n status: text('status').default('DRAFT'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const agentToolAssignment = pgTable('agent_tool_assignment', {\n id: text('id').primaryKey(),\n agentId: text('agentId').notNull(),\n toolId: text('toolId').notNull(),\n assignedAt: timestamp('assignedAt').defaultNow(),\n});\n\nexport const agentRun = pgTable('agent_run', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n agentId: text('agentId').notNull(),\n status: text('status').default('QUEUED'),\n input: text('input'),\n output: text('output'),\n totalTokens: integer('totalTokens').default(0),\n promptTokens: integer('promptTokens').default(0),\n completionTokens: integer('completionTokens').default(0),\n estimatedCostUsd: real('estimatedCostUsd').default(0),\n durationMs: integer('durationMs'),\n errorMessage: text('errorMessage'),\n queuedAt: timestamp('queuedAt').defaultNow(),\n startedAt: text('startedAt'),\n completedAt: text('completedAt'),\n});\n\nexport const agentRunStep = pgTable('agent_run_step', {\n id: text('id').primaryKey(),\n runId: text('runId').notNull(),\n stepNumber: integer('stepNumber').notNull(),\n type: text('type').notNull(),\n toolId: text('toolId'),\n toolInput: text('toolInput'),\n toolOutput: text('toolOutput'),\n reasoning: text('reasoning'),\n tokensUsed: integer('tokensUsed').default(0),\n durationMs: integer('durationMs'),\n status: text('status').default('PENDING'),\n createdAt: timestamp('createdAt').defaultNow(),\n});\n\nexport const agentRunLog = pgTable('agent_run_log', {\n id: text('id').primaryKey(),\n runId: text('runId').notNull(),\n level: text('level').default('INFO'),\n message: text('message').notNull(),\n metadata: text('metadata'),\n timestamp: timestamp('timestamp').defaultNow(),\n});\n\n// ============ Workflow Template ============\n\nexport const workflowDefinition = pgTable('workflow_definition', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n organizationId: text('organizationId').notNull(),\n name: text('name').notNull(),\n description: text('description'),\n type: text('type').default('APPROVAL'),\n status: text('status').default('DRAFT'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const workflowStep = pgTable('workflow_step', {\n id: text('id').primaryKey(),\n definitionId: text('definitionId').notNull(),\n name: text('name').notNull(),\n description: text('description'),\n stepOrder: integer('stepOrder').notNull(),\n type: text('type').default('APPROVAL'),\n requiredRoles: text('requiredRoles'),\n autoApproveCondition: text('autoApproveCondition'),\n timeoutHours: integer('timeoutHours'),\n createdAt: timestamp('createdAt').defaultNow(),\n});\n\nexport const workflowInstance = pgTable('workflow_instance', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n definitionId: text('definitionId').notNull(),\n status: text('status').default('PENDING'),\n currentStepId: text('currentStepId'),\n data: text('data'),\n requestedBy: text('requestedBy').notNull(),\n startedAt: timestamp('startedAt').defaultNow(),\n completedAt: text('completedAt'),\n});\n\nexport const workflowApproval = pgTable('workflow_approval', {\n id: text('id').primaryKey(),\n instanceId: text('instanceId').notNull(),\n stepId: text('stepId').notNull(),\n status: text('status').default('PENDING'),\n actorId: text('actorId'),\n comment: text('comment'),\n decidedAt: text('decidedAt'),\n createdAt: timestamp('createdAt').defaultNow(),\n});\n\n// ============ Marketplace Template ============\n\nexport const marketplaceStore = pgTable('marketplace_store', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n organizationId: text('organizationId').notNull(),\n name: text('name').notNull(),\n description: text('description'),\n status: text('status').default('PENDING'),\n rating: real('rating').default(0),\n reviewCount: integer('reviewCount').default(0),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const marketplaceProduct = pgTable('marketplace_product', {\n id: text('id').primaryKey(),\n storeId: text('storeId').notNull(),\n name: text('name').notNull(),\n description: text('description'),\n price: real('price').notNull().default(0),\n currency: text('currency').default('USD'),\n status: text('status').default('DRAFT'),\n stock: integer('stock').default(0),\n category: text('category'),\n imageUrl: text('imageUrl'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const marketplaceOrder = pgTable('marketplace_order', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n storeId: text('storeId').notNull(),\n customerId: text('customerId').notNull(),\n status: text('status').default('PENDING'),\n total: real('total').notNull().default(0),\n currency: text('currency').default('USD'),\n shippingAddress: text('shippingAddress'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const marketplaceOrderItem = pgTable('marketplace_order_item', {\n id: text('id').primaryKey(),\n orderId: text('orderId').notNull(),\n productId: text('productId').notNull(),\n quantity: integer('quantity').notNull().default(1),\n price: real('price').notNull().default(0),\n createdAt: timestamp('createdAt').defaultNow(),\n});\n\nexport const marketplacePayout = pgTable('marketplace_payout', {\n id: text('id').primaryKey(),\n storeId: text('storeId').notNull(),\n amount: real('amount').notNull().default(0),\n currency: text('currency').default('USD'),\n status: text('status').default('PENDING'),\n processedAt: text('processedAt'),\n createdAt: timestamp('createdAt').defaultNow(),\n});\n\nexport const marketplaceReview = pgTable('marketplace_review', {\n id: text('id').primaryKey(),\n productId: text('productId').notNull(),\n customerId: text('customerId').notNull(),\n orderId: text('orderId'),\n rating: integer('rating').notNull(),\n comment: text('comment'),\n createdAt: timestamp('createdAt').defaultNow(),\n});\n\n// ============ Integration Hub Template ============\n\nexport const integration = pgTable('integration', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n organizationId: text('organizationId').notNull(),\n name: text('name').notNull(),\n description: text('description'),\n type: text('type').notNull(),\n status: text('status').default('INACTIVE'),\n iconUrl: text('iconUrl'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const integrationConnection = pgTable('integration_connection', {\n id: text('id').primaryKey(),\n integrationId: text('integrationId').notNull(),\n name: text('name').notNull(),\n status: text('status').default('DISCONNECTED'),\n credentials: text('credentials'),\n config: text('config'),\n lastSyncAt: text('lastSyncAt'),\n errorMessage: text('errorMessage'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const integrationSyncConfig = pgTable('integration_sync_config', {\n id: text('id').primaryKey(),\n connectionId: text('connectionId').notNull(),\n name: text('name').notNull(),\n sourceEntity: text('sourceEntity').notNull(),\n targetEntity: text('targetEntity').notNull(),\n frequency: text('frequency').default('DAILY'),\n status: text('status').default('ACTIVE'),\n lastRunAt: text('lastRunAt'),\n lastRunStatus: text('lastRunStatus'),\n recordsSynced: integer('recordsSynced').default(0),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const integrationFieldMapping = pgTable('integration_field_mapping', {\n id: text('id').primaryKey(),\n syncConfigId: text('syncConfigId').notNull(),\n sourceField: text('sourceField').notNull(),\n targetField: text('targetField').notNull(),\n transformType: text('transformType'),\n transformConfig: text('transformConfig'),\n createdAt: timestamp('createdAt').defaultNow(),\n});\n\n// ============ Analytics Dashboard Template ============\n\nexport const analyticsDashboard = pgTable('analytics_dashboard', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n organizationId: text('organizationId').notNull(),\n name: text('name').notNull(),\n slug: text('slug').notNull(),\n description: text('description'),\n status: text('status').default('DRAFT'),\n refreshInterval: text('refreshInterval').default('NONE'),\n isPublic: integer('isPublic').default(0),\n shareToken: text('shareToken'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const analyticsWidget = pgTable('analytics_widget', {\n id: text('id').primaryKey(),\n dashboardId: text('dashboardId').notNull(),\n name: text('name').notNull(),\n type: text('type').notNull(),\n gridX: integer('gridX').default(0),\n gridY: integer('gridY').default(0),\n gridWidth: integer('gridWidth').default(6),\n gridHeight: integer('gridHeight').default(4),\n queryId: text('queryId'),\n config: text('config'),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\nexport const analyticsQuery = pgTable('analytics_query', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n organizationId: text('organizationId').notNull(),\n name: text('name').notNull(),\n description: text('description'),\n type: text('type').notNull(),\n definition: text('definition').notNull(),\n sql: text('sql'),\n cacheTtlSeconds: integer('cacheTtlSeconds').default(300),\n isShared: integer('isShared').default(0),\n createdAt: timestamp('createdAt').defaultNow(),\n updatedAt: timestamp('updatedAt').defaultNow(),\n});\n\n// ============ Policy-Safe Knowledge Assistant Template ============\n\nexport const psaUserContext = pgTable('psa_user_context', {\n projectId: text('projectId').primaryKey(),\n locale: text('locale').notNull(),\n jurisdiction: text('jurisdiction').notNull(),\n allowedScope: text('allowedScope').notNull(),\n kbSnapshotId: text('kbSnapshotId'),\n});\n\nexport const psaRule = pgTable('psa_rule', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n jurisdiction: text('jurisdiction').notNull(),\n topicKey: text('topicKey').notNull(),\n});\n\nexport const psaRuleVersion = pgTable('psa_rule_version', {\n id: text('id').primaryKey(),\n ruleId: text('ruleId').notNull(),\n jurisdiction: text('jurisdiction').notNull(),\n topicKey: text('topicKey').notNull(),\n version: integer('version').notNull(),\n content: text('content').notNull(),\n status: text('status').notNull(),\n sourceRefsJson: text('sourceRefsJson').notNull(),\n approvedBy: text('approvedBy'),\n approvedAt: text('approvedAt'),\n createdAt: timestamp('createdAt').defaultNow(),\n});\n\nexport const psaSnapshot = pgTable('psa_snapshot', {\n id: text('id').primaryKey(),\n jurisdiction: text('jurisdiction').notNull(),\n asOfDate: text('asOfDate').notNull(),\n includedRuleVersionIdsJson: text('includedRuleVersionIdsJson').notNull(),\n publishedAt: text('publishedAt').notNull(),\n});\n\nexport const psaChangeCandidate = pgTable('psa_change_candidate', {\n id: text('id').primaryKey(),\n projectId: text('projectId').notNull(),\n jurisdiction: text('jurisdiction').notNull(),\n detectedAt: text('detectedAt').notNull(),\n diffSummary: text('diffSummary').notNull(),\n riskLevel: text('riskLevel').notNull(),\n proposedRuleVersionIdsJson: text('proposedRuleVersionIdsJson').notNull(),\n});\n\nexport const psaReviewTask = pgTable('psa_review_task', {\n id: text('id').primaryKey(),\n changeCandidateId: text('changeCandidateId').notNull(),\n status: text('status').notNull(),\n assignedRole: text('assignedRole').notNull(),\n decision: text('decision'),\n decidedAt: text('decidedAt'),\n decidedBy: text('decidedBy'),\n});\n"],"mappings":"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"}
@@ -1,24 +0,0 @@
1
- //#region src/web/events/local-pubsub.ts
2
- var LocalEventBus = class {
3
- listeners = /* @__PURE__ */ new Map();
4
- emit(event, payload) {
5
- const listeners = this.listeners.get(event);
6
- if (!listeners) return;
7
- for (const listener of listeners) listener(payload);
8
- }
9
- subscribe(event, listener) {
10
- let listeners = this.listeners.get(event);
11
- if (!listeners) {
12
- listeners = /* @__PURE__ */ new Set();
13
- this.listeners.set(event, listeners);
14
- }
15
- listeners.add(listener);
16
- return () => {
17
- listeners.delete(listener);
18
- };
19
- }
20
- };
21
-
22
- //#endregion
23
- export { LocalEventBus };
24
- //# sourceMappingURL=local-pubsub.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"local-pubsub.js","names":[],"sources":["../../../src/web/events/local-pubsub.ts"],"sourcesContent":["type Listener<TPayload> = (payload: TPayload) => void;\n\nexport class LocalEventBus {\n private listeners = new Map<string, Set<Listener<unknown>>>();\n\n emit<TPayload = unknown>(event: string, payload: TPayload): void {\n const listeners = this.listeners.get(event);\n if (!listeners) return;\n for (const listener of listeners) {\n listener(payload);\n }\n }\n\n subscribe<TPayload = unknown>(\n event: string,\n listener: Listener<TPayload>\n ): () => void {\n let listeners = this.listeners.get(event);\n if (!listeners) {\n listeners = new Set();\n this.listeners.set(event, listeners);\n }\n listeners.add(listener as Listener<unknown>);\n return () => {\n listeners.delete(listener as Listener<unknown>);\n };\n }\n}\n"],"mappings":";AAEA,IAAa,gBAAb,MAA2B;CACzB,AAAQ,4BAAY,IAAI,KAAqC;CAE7D,KAAyB,OAAe,SAAyB;EAC/D,MAAM,YAAY,KAAK,UAAU,IAAI,MAAM;AAC3C,MAAI,CAAC,UAAW;AAChB,OAAK,MAAM,YAAY,UACrB,UAAS,QAAQ;;CAIrB,UACE,OACA,UACY;EACZ,IAAI,YAAY,KAAK,UAAU,IAAI,MAAM;AACzC,MAAI,CAAC,WAAW;AACd,+BAAY,IAAI,KAAK;AACrB,QAAK,UAAU,IAAI,OAAO,UAAU;;AAEtC,YAAU,IAAI,SAA8B;AAC5C,eAAa;AACX,aAAU,OAAO,SAA8B"}
@@ -1,536 +0,0 @@
1
- import { generateId } from "../utils/id.js";
2
- import { LocalEventBus } from "../events/local-pubsub.js";
3
- import { ApolloClient, InMemoryCache } from "@apollo/client";
4
- import { SchemaLink } from "@apollo/client/link/schema";
5
- import { makeExecutableSchema } from "@graphql-tools/schema";
6
- import { GraphQLScalarType, Kind } from "graphql";
7
-
8
- //#region src/web/graphql/local-client.ts
9
- const typeDefs = `
10
- scalar DateTime
11
-
12
- enum TaskPriority {
13
- LOW
14
- MEDIUM
15
- HIGH
16
- URGENT
17
- }
18
-
19
- enum MessageStatus {
20
- SENT
21
- DELIVERED
22
- READ
23
- }
24
-
25
- enum RecipeLocale {
26
- EN
27
- FR
28
- }
29
-
30
- type TaskCategory {
31
- id: ID!
32
- projectId: ID!
33
- name: String!
34
- color: String
35
- createdAt: DateTime!
36
- updatedAt: DateTime!
37
- }
38
-
39
- type Task {
40
- id: ID!
41
- projectId: ID!
42
- categoryId: ID
43
- title: String!
44
- description: String
45
- completed: Boolean!
46
- priority: TaskPriority!
47
- dueDate: DateTime
48
- tags: [String!]!
49
- createdAt: DateTime!
50
- updatedAt: DateTime!
51
- category: TaskCategory
52
- }
53
-
54
- input CreateTaskInput {
55
- projectId: ID!
56
- categoryId: ID
57
- title: String!
58
- description: String
59
- priority: TaskPriority = MEDIUM
60
- dueDate: DateTime
61
- tags: [String!]
62
- }
63
-
64
- input UpdateTaskInput {
65
- categoryId: ID
66
- title: String
67
- description: String
68
- priority: TaskPriority
69
- dueDate: DateTime
70
- tags: [String!]
71
- }
72
-
73
- type ConversationParticipant {
74
- id: ID!
75
- conversationId: ID!
76
- projectId: ID!
77
- userId: String!
78
- displayName: String
79
- role: String
80
- joinedAt: DateTime!
81
- lastReadAt: DateTime
82
- }
83
-
84
- input ConversationParticipantInput {
85
- userId: String!
86
- displayName: String
87
- role: String
88
- }
89
-
90
- type Message {
91
- id: ID!
92
- conversationId: ID!
93
- projectId: ID!
94
- senderId: String!
95
- senderName: String
96
- content: String!
97
- attachments: [String!]!
98
- status: MessageStatus!
99
- createdAt: DateTime!
100
- updatedAt: DateTime!
101
- }
102
-
103
- input SendMessageInput {
104
- conversationId: ID!
105
- projectId: ID!
106
- senderId: String!
107
- senderName: String
108
- content: String!
109
- }
110
-
111
- input CreateConversationInput {
112
- projectId: ID!
113
- name: String
114
- isGroup: Boolean = false
115
- avatarUrl: String
116
- participants: [ConversationParticipantInput!]!
117
- }
118
-
119
- type Conversation {
120
- id: ID!
121
- projectId: ID!
122
- name: String
123
- isGroup: Boolean!
124
- avatarUrl: String
125
- lastMessageId: ID
126
- updatedAt: DateTime!
127
- participants: [ConversationParticipant!]!
128
- messages(limit: Int = 50): [Message!]!
129
- }
130
-
131
- type RecipeCategory {
132
- id: ID!
133
- nameEn: String!
134
- nameFr: String!
135
- icon: String
136
- }
137
-
138
- type RecipeIngredient {
139
- id: ID!
140
- name: String!
141
- quantity: String!
142
- ordering: Int!
143
- }
144
-
145
- type RecipeInstruction {
146
- id: ID!
147
- content: String!
148
- ordering: Int!
149
- }
150
-
151
- type Recipe {
152
- id: ID!
153
- projectId: ID!
154
- slugEn: String!
155
- slugFr: String!
156
- name: String!
157
- description: String
158
- heroImageUrl: String
159
- prepTimeMinutes: Int
160
- cookTimeMinutes: Int
161
- servings: Int
162
- isFavorite: Boolean!
163
- locale: RecipeLocale!
164
- category: RecipeCategory
165
- ingredients: [RecipeIngredient!]!
166
- instructions: [RecipeInstruction!]!
167
- }
168
-
169
- type Query {
170
- taskCategories(projectId: ID!): [TaskCategory!]!
171
- tasks(projectId: ID!): [Task!]!
172
- conversations(projectId: ID!): [Conversation!]!
173
- messages(conversationId: ID!, limit: Int = 50): [Message!]!
174
- recipes(projectId: ID!, locale: RecipeLocale = EN): [Recipe!]!
175
- recipe(id: ID!, locale: RecipeLocale = EN): Recipe
176
- }
177
-
178
- type Mutation {
179
- createTask(input: CreateTaskInput!): Task!
180
- updateTask(id: ID!, input: UpdateTaskInput!): Task!
181
- toggleTask(id: ID!, completed: Boolean!): Task!
182
- deleteTask(id: ID!): Boolean!
183
- createConversation(input: CreateConversationInput!): Conversation!
184
- sendMessage(input: SendMessageInput!): Message!
185
- setMessagesRead(conversationId: ID!, userId: String!): Boolean!
186
- favoriteRecipe(id: ID!, isFavorite: Boolean!): Recipe!
187
- }
188
- `;
189
- const DateTimeScalar = new GraphQLScalarType({
190
- name: "DateTime",
191
- parseValue(value) {
192
- return value ? new Date(value).toISOString() : null;
193
- },
194
- serialize(value) {
195
- if (!value) return null;
196
- if (typeof value === "string") return value;
197
- return new Date(value).toISOString();
198
- },
199
- parseLiteral(ast) {
200
- if (ast.kind === Kind.STRING) return new Date(ast.value).toISOString();
201
- return null;
202
- }
203
- });
204
- var LocalGraphQLClient = class {
205
- apollo;
206
- constructor(options) {
207
- this.options = options;
208
- const schema = makeExecutableSchema({
209
- typeDefs,
210
- resolvers: this.createResolvers()
211
- });
212
- this.apollo = new ApolloClient({
213
- cache: new InMemoryCache(),
214
- link: new SchemaLink({
215
- schema,
216
- context: () => ({
217
- db: this.options.db,
218
- storage: this.options.storage,
219
- pubsub: this.options.pubsub ?? new LocalEventBus()
220
- })
221
- }),
222
- devtools: { enabled: typeof window !== "undefined" }
223
- });
224
- }
225
- createResolvers() {
226
- return {
227
- DateTime: DateTimeScalar,
228
- Query: {
229
- taskCategories: async (_, args, ctx) => {
230
- return (await ctx.db.query(`SELECT * FROM template_task_category WHERE "projectId" = $1 ORDER BY name ASC`, [args.projectId])).rows.map(mapTaskCategory);
231
- },
232
- tasks: async (_, args, ctx) => {
233
- return (await ctx.db.query(`SELECT * FROM template_task WHERE "projectId" = $1 ORDER BY "createdAt" DESC`, [args.projectId])).rows.map(mapTask);
234
- },
235
- conversations: async (_, args, ctx) => {
236
- return (await ctx.db.query(`SELECT * FROM template_conversation WHERE "projectId" = $1 ORDER BY "updatedAt" DESC`, [args.projectId])).rows.map(mapConversation);
237
- },
238
- messages: async (_, args, ctx) => {
239
- return (await ctx.db.query(`SELECT * FROM template_message WHERE "conversationId" = $1 ORDER BY "createdAt" DESC LIMIT $2`, [args.conversationId, args.limit])).rows.map(mapMessage);
240
- },
241
- recipes: async (_, args, ctx) => {
242
- return (await ctx.db.query(`SELECT * FROM template_recipe WHERE "projectId" = $1 ORDER BY "nameEn" ASC`, [args.projectId])).rows.map((row) => mapRecipe(row, args.locale));
243
- },
244
- recipe: async (_, args, ctx) => {
245
- const result = await ctx.db.query(`SELECT * FROM template_recipe WHERE id = $1 LIMIT 1`, [args.id]);
246
- if (!result.rows.length || !result.rows[0]) return null;
247
- return mapRecipe(result.rows[0], args.locale);
248
- }
249
- },
250
- Mutation: {
251
- createTask: async (_, args, ctx) => {
252
- const id = generateId("task");
253
- const now = (/* @__PURE__ */ new Date()).toISOString();
254
- const tags = JSON.stringify(args.input.tags ?? []);
255
- await ctx.db.execute(`INSERT INTO template_task (id, "projectId", "categoryId", title, description, completed, priority, "dueDate", tags, "createdAt", "updatedAt")
256
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`, [
257
- id,
258
- args.input.projectId,
259
- args.input.categoryId ?? null,
260
- args.input.title,
261
- args.input.description ?? null,
262
- 0,
263
- args.input.priority ?? "MEDIUM",
264
- args.input.dueDate ?? null,
265
- tags,
266
- now,
267
- now
268
- ]);
269
- const result = await ctx.db.query(`SELECT * FROM template_task WHERE id = $1 LIMIT 1`, [id]);
270
- if (!result.rows.length || !result.rows[0]) throw new Error("Failed to create task");
271
- return mapTask(result.rows[0]);
272
- },
273
- updateTask: async (_, args, ctx) => {
274
- const now = (/* @__PURE__ */ new Date()).toISOString();
275
- await ctx.db.execute(`UPDATE template_task
276
- SET "categoryId" = COALESCE($1, "categoryId"),
277
- title = COALESCE($2, title),
278
- description = COALESCE($3, description),
279
- priority = COALESCE($4, priority),
280
- "dueDate" = COALESCE($5, "dueDate"),
281
- tags = COALESCE($6, tags),
282
- "updatedAt" = $7
283
- WHERE id = $8`, [
284
- args.input.categoryId ?? null,
285
- args.input.title ?? null,
286
- args.input.description ?? null,
287
- args.input.priority ?? null,
288
- args.input.dueDate ?? null,
289
- args.input.tags ? JSON.stringify(args.input.tags) : null,
290
- now,
291
- args.id
292
- ]);
293
- const result = await ctx.db.query(`SELECT * FROM template_task WHERE id = $1 LIMIT 1`, [args.id]);
294
- if (!result.rows.length || !result.rows[0]) throw new Error("Task not found");
295
- return mapTask(result.rows[0]);
296
- },
297
- toggleTask: async (_, args, ctx) => {
298
- const now = (/* @__PURE__ */ new Date()).toISOString();
299
- await ctx.db.execute(`UPDATE template_task SET completed = $1, "updatedAt" = $2 WHERE id = $3`, [
300
- args.completed ? 1 : 0,
301
- now,
302
- args.id
303
- ]);
304
- const result = await ctx.db.query(`SELECT * FROM template_task WHERE id = $1 LIMIT 1`, [args.id]);
305
- if (!result.rows.length || !result.rows[0]) throw new Error("Task not found");
306
- return mapTask(result.rows[0]);
307
- },
308
- deleteTask: async (_, args, ctx) => {
309
- await ctx.db.execute(`DELETE FROM template_task WHERE id = $1`, [args.id]);
310
- return true;
311
- },
312
- createConversation: async (_, args, ctx) => {
313
- const id = generateId("conversation");
314
- const now = (/* @__PURE__ */ new Date()).toISOString();
315
- await ctx.db.execute(`INSERT INTO template_conversation (id, "projectId", name, "isGroup", "avatarUrl", "updatedAt")
316
- VALUES ($1, $2, $3, $4, $5, $6)`, [
317
- id,
318
- args.input.projectId,
319
- args.input.name ?? null,
320
- args.input.isGroup ? 1 : 0,
321
- args.input.avatarUrl ?? null,
322
- now
323
- ]);
324
- const participants = args.input.participants ?? [];
325
- for (const participant of participants) await ctx.db.execute(`INSERT INTO template_conversation_participant (id, "conversationId", "projectId", "userId", "displayName", role, "joinedAt")
326
- VALUES ($1, $2, $3, $4, $5, $6, $7)`, [
327
- generateId("participant"),
328
- id,
329
- args.input.projectId,
330
- participant.userId,
331
- participant.displayName ?? null,
332
- participant.role ?? null,
333
- now
334
- ]);
335
- const result = await ctx.db.query(`SELECT * FROM template_conversation WHERE id = $1 LIMIT 1`, [id]);
336
- if (!result.rows.length || !result.rows[0]) throw new Error("Failed to create conversation");
337
- return mapConversation(result.rows[0]);
338
- },
339
- sendMessage: async (_, args, ctx) => {
340
- const id = generateId("message");
341
- const now = (/* @__PURE__ */ new Date()).toISOString();
342
- await ctx.db.execute(`INSERT INTO template_message (id, "conversationId", "projectId", "senderId", "senderName", content, attachments, status, "createdAt", "updatedAt")
343
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, [
344
- id,
345
- args.input.conversationId,
346
- args.input.projectId,
347
- args.input.senderId,
348
- args.input.senderName ?? null,
349
- args.input.content,
350
- JSON.stringify([]),
351
- "SENT",
352
- now,
353
- now
354
- ]);
355
- await ctx.db.execute(`UPDATE template_conversation SET "lastMessageId" = $1, "updatedAt" = $2 WHERE id = $3`, [
356
- id,
357
- now,
358
- args.input.conversationId
359
- ]);
360
- const result = await ctx.db.query(`SELECT * FROM template_message WHERE id = $1`, [id]);
361
- if (!result.rows.length || !result.rows[0]) throw new Error("Failed to send message");
362
- const message = mapMessage(result.rows[0]);
363
- ctx.pubsub.emit("message:new", message);
364
- return message;
365
- },
366
- setMessagesRead: async (_, args, ctx) => {
367
- const now = (/* @__PURE__ */ new Date()).toISOString();
368
- await ctx.db.execute(`UPDATE template_conversation_participant
369
- SET "lastReadAt" = $1
370
- WHERE "conversationId" = $2 AND "userId" = $3`, [
371
- now,
372
- args.conversationId,
373
- args.userId
374
- ]);
375
- return true;
376
- },
377
- favoriteRecipe: async (_, args, ctx) => {
378
- const now = (/* @__PURE__ */ new Date()).toISOString();
379
- await ctx.db.execute(`UPDATE template_recipe SET "isFavorite" = $1, "updatedAt" = $2 WHERE id = $3`, [
380
- args.isFavorite ? 1 : 0,
381
- now,
382
- args.id
383
- ]);
384
- const result = await ctx.db.query(`SELECT * FROM template_recipe WHERE id = $1 LIMIT 1`, [args.id]);
385
- if (!result.rows.length || !result.rows[0]) throw new Error("Recipe not found");
386
- return mapRecipe(result.rows[0], "EN");
387
- }
388
- },
389
- Task: { category: async (parent, _, ctx) => {
390
- if (!parent.categoryId) return null;
391
- const result = await ctx.db.query(`SELECT * FROM template_task_category WHERE id = $1 LIMIT 1`, [parent.categoryId]);
392
- if (!result.rows.length || !result.rows[0]) return null;
393
- return mapTaskCategory(result.rows[0]);
394
- } },
395
- Conversation: {
396
- participants: async (parent, _, ctx) => {
397
- return (await ctx.db.query(`SELECT * FROM template_conversation_participant WHERE "conversationId" = $1 ORDER BY "joinedAt" ASC`, [parent.id])).rows.map(mapParticipant);
398
- },
399
- messages: async (parent, args, ctx) => {
400
- return (await ctx.db.query(`SELECT * FROM template_message WHERE "conversationId" = $1 ORDER BY "createdAt" DESC LIMIT $2`, [parent.id, args.limit])).rows.map(mapMessage);
401
- }
402
- },
403
- Recipe: {
404
- category: async (parent, _, ctx) => {
405
- if (!parent.categoryId) return null;
406
- const result = await ctx.db.query(`SELECT * FROM template_recipe_category WHERE id = $1 LIMIT 1`, [parent.categoryId]);
407
- if (!result.rows.length || !result.rows[0]) return null;
408
- return mapRecipeCategory(result.rows[0]);
409
- },
410
- ingredients: async (parent, _, ctx) => {
411
- return (await ctx.db.query(`SELECT * FROM template_recipe_ingredient WHERE "recipeId" = $1 ORDER BY ordering ASC`, [parent.id])).rows.map((row) => mapRecipeIngredient(row, parent.locale));
412
- },
413
- instructions: async (parent, _, ctx) => {
414
- return (await ctx.db.query(`SELECT * FROM template_recipe_instruction WHERE "recipeId" = $1 ORDER BY ordering ASC`, [parent.id])).rows.map((row) => mapRecipeInstruction(row, parent.locale));
415
- }
416
- }
417
- };
418
- }
419
- };
420
- function mapTaskCategory(row) {
421
- return {
422
- id: row.id,
423
- projectId: row.projectId,
424
- name: row.name,
425
- color: row.color,
426
- createdAt: row.createdAt,
427
- updatedAt: row.updatedAt
428
- };
429
- }
430
- function mapTask(row) {
431
- return {
432
- id: row.id,
433
- projectId: row.projectId,
434
- categoryId: row.categoryId,
435
- title: row.title,
436
- description: row.description,
437
- completed: Boolean(row.completed),
438
- priority: row.priority ?? "MEDIUM",
439
- dueDate: row.dueDate,
440
- tags: parseTags(row.tags),
441
- createdAt: row.createdAt,
442
- updatedAt: row.updatedAt
443
- };
444
- }
445
- function parseTags(value) {
446
- if (typeof value !== "string") return [];
447
- try {
448
- const parsed = JSON.parse(value);
449
- return Array.isArray(parsed) ? parsed : [];
450
- } catch {
451
- return [];
452
- }
453
- }
454
- function mapConversation(row) {
455
- return {
456
- id: row.id,
457
- projectId: row.projectId,
458
- name: row.name,
459
- isGroup: Boolean(row.isGroup),
460
- avatarUrl: row.avatarUrl,
461
- lastMessageId: row.lastMessageId,
462
- updatedAt: row.updatedAt
463
- };
464
- }
465
- function mapParticipant(row) {
466
- return {
467
- id: row.id,
468
- conversationId: row.conversationId,
469
- projectId: row.projectId,
470
- userId: row.userId,
471
- displayName: row.displayName,
472
- role: row.role,
473
- joinedAt: row.joinedAt,
474
- lastReadAt: row.lastReadAt
475
- };
476
- }
477
- function mapMessage(row) {
478
- return {
479
- id: row.id,
480
- conversationId: row.conversationId,
481
- projectId: row.projectId,
482
- senderId: row.senderId,
483
- senderName: row.senderName,
484
- content: row.content,
485
- attachments: [],
486
- status: row.status ?? "SENT",
487
- createdAt: row.createdAt,
488
- updatedAt: row.updatedAt
489
- };
490
- }
491
- function mapRecipe(row, locale) {
492
- return {
493
- id: row.id,
494
- projectId: row.projectId,
495
- slugEn: row.slugEn,
496
- slugFr: row.slugFr,
497
- name: locale === "FR" ? row.nameFr : row.nameEn,
498
- description: locale === "FR" ? row.descriptionFr : row.descriptionEn,
499
- heroImageUrl: row.heroImageUrl,
500
- prepTimeMinutes: row.prepTimeMinutes ?? null,
501
- cookTimeMinutes: row.cookTimeMinutes ?? null,
502
- servings: row.servings ?? null,
503
- isFavorite: Boolean(row.isFavorite),
504
- locale,
505
- categoryId: row.categoryId,
506
- createdAt: row.createdAt,
507
- updatedAt: row.updatedAt
508
- };
509
- }
510
- function mapRecipeCategory(row) {
511
- return {
512
- id: row.id,
513
- nameEn: row.nameEn,
514
- nameFr: row.nameFr,
515
- icon: row.icon
516
- };
517
- }
518
- function mapRecipeIngredient(row, locale) {
519
- return {
520
- id: row.id,
521
- name: locale === "FR" ? row.nameFr : row.nameEn,
522
- quantity: row.quantity,
523
- ordering: row.ordering ?? 0
524
- };
525
- }
526
- function mapRecipeInstruction(row, locale) {
527
- return {
528
- id: row.id,
529
- content: locale === "FR" ? row.contentFr : row.contentEn,
530
- ordering: row.ordering ?? 0
531
- };
532
- }
533
-
534
- //#endregion
535
- export { LocalGraphQLClient };
536
- //# sourceMappingURL=local-client.js.map