@contractspec/example.analytics-dashboard 1.57.0 β†’ 1.59.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 (173) hide show
  1. package/dist/browser/dashboard/dashboard.enum.js +34 -0
  2. package/dist/browser/dashboard/dashboard.operation.js +289 -0
  3. package/dist/browser/dashboard/dashboard.presentation.js +197 -0
  4. package/dist/browser/dashboard/dashboard.schema.js +126 -0
  5. package/dist/browser/dashboard/dashboard.test-spec.js +213 -0
  6. package/dist/browser/dashboard/index.js +299 -0
  7. package/dist/browser/dashboard.feature.js +84 -0
  8. package/dist/browser/datasource/posthog-datasource.js +289 -0
  9. package/dist/browser/docs/analytics-dashboard.docblock.js +103 -0
  10. package/dist/browser/docs/index.js +103 -0
  11. package/dist/browser/events.js +81 -0
  12. package/dist/browser/example.js +42 -0
  13. package/dist/browser/handlers/analytics.handlers.js +278 -0
  14. package/dist/browser/handlers/index.js +571 -0
  15. package/dist/browser/handlers/query.handlers.js +294 -0
  16. package/dist/browser/index.js +1677 -0
  17. package/dist/browser/query/index.js +159 -0
  18. package/dist/browser/query/query.enum.js +11 -0
  19. package/dist/browser/query/query.operation.js +154 -0
  20. package/dist/browser/query/query.presentation.js +119 -0
  21. package/dist/browser/query/query.schema.js +70 -0
  22. package/dist/browser/query/query.test-spec.js +113 -0
  23. package/dist/browser/query-engine/index.js +491 -0
  24. package/dist/browser/seeders/index.js +20 -0
  25. package/dist/browser/ui/AnalyticsDashboard.js +394 -0
  26. package/dist/browser/ui/hooks/index.js +69 -0
  27. package/dist/browser/ui/hooks/useAnalyticsData.js +66 -0
  28. package/dist/browser/ui/index.js +671 -0
  29. package/dist/browser/ui/renderers/analytics.markdown.js +275 -0
  30. package/dist/browser/ui/renderers/index.js +275 -0
  31. package/dist/dashboard/dashboard.enum.d.ts +3 -8
  32. package/dist/dashboard/dashboard.enum.d.ts.map +1 -1
  33. package/dist/dashboard/dashboard.enum.js +31 -39
  34. package/dist/dashboard/dashboard.operation.d.ts +444 -450
  35. package/dist/dashboard/dashboard.operation.d.ts.map +1 -1
  36. package/dist/dashboard/dashboard.operation.js +284 -207
  37. package/dist/dashboard/dashboard.presentation.d.ts +3 -8
  38. package/dist/dashboard/dashboard.presentation.d.ts.map +1 -1
  39. package/dist/dashboard/dashboard.presentation.js +193 -85
  40. package/dist/dashboard/dashboard.schema.d.ts +289 -294
  41. package/dist/dashboard/dashboard.schema.d.ts.map +1 -1
  42. package/dist/dashboard/dashboard.schema.js +119 -228
  43. package/dist/dashboard/dashboard.test-spec.d.ts +4 -9
  44. package/dist/dashboard/dashboard.test-spec.d.ts.map +1 -1
  45. package/dist/dashboard/dashboard.test-spec.js +209 -228
  46. package/dist/dashboard/index.d.ts +7 -4
  47. package/dist/dashboard/index.d.ts.map +1 -0
  48. package/dist/dashboard/index.js +299 -4
  49. package/dist/dashboard.feature.d.ts +1 -6
  50. package/dist/dashboard.feature.d.ts.map +1 -1
  51. package/dist/dashboard.feature.js +83 -175
  52. package/dist/datasource/posthog-datasource.d.ts +15 -19
  53. package/dist/datasource/posthog-datasource.d.ts.map +1 -1
  54. package/dist/datasource/posthog-datasource.js +274 -238
  55. package/dist/docs/analytics-dashboard.docblock.d.ts +2 -1
  56. package/dist/docs/analytics-dashboard.docblock.d.ts.map +1 -0
  57. package/dist/docs/analytics-dashboard.docblock.js +45 -56
  58. package/dist/docs/index.d.ts +2 -1
  59. package/dist/docs/index.d.ts.map +1 -0
  60. package/dist/docs/index.js +104 -1
  61. package/dist/events.d.ts +109 -115
  62. package/dist/events.d.ts.map +1 -1
  63. package/dist/events.js +74 -120
  64. package/dist/example.d.ts +2 -6
  65. package/dist/example.d.ts.map +1 -1
  66. package/dist/example.js +41 -55
  67. package/dist/handlers/analytics.handlers.d.ts +110 -109
  68. package/dist/handlers/analytics.handlers.d.ts.map +1 -1
  69. package/dist/handlers/analytics.handlers.js +267 -298
  70. package/dist/handlers/index.d.ts +3 -3
  71. package/dist/handlers/index.d.ts.map +1 -0
  72. package/dist/handlers/index.js +571 -3
  73. package/dist/handlers/query.handlers.d.ts +7 -11
  74. package/dist/handlers/query.handlers.d.ts.map +1 -1
  75. package/dist/handlers/query.handlers.js +292 -7
  76. package/dist/index.d.ts +12 -13
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +1678 -14
  79. package/dist/node/dashboard/dashboard.enum.js +34 -0
  80. package/dist/node/dashboard/dashboard.operation.js +289 -0
  81. package/dist/node/dashboard/dashboard.presentation.js +197 -0
  82. package/dist/node/dashboard/dashboard.schema.js +126 -0
  83. package/dist/node/dashboard/dashboard.test-spec.js +213 -0
  84. package/dist/node/dashboard/index.js +299 -0
  85. package/dist/node/dashboard.feature.js +84 -0
  86. package/dist/node/datasource/posthog-datasource.js +289 -0
  87. package/dist/node/docs/analytics-dashboard.docblock.js +103 -0
  88. package/dist/node/docs/index.js +103 -0
  89. package/dist/node/events.js +81 -0
  90. package/dist/node/example.js +42 -0
  91. package/dist/node/handlers/analytics.handlers.js +278 -0
  92. package/dist/node/handlers/index.js +571 -0
  93. package/dist/node/handlers/query.handlers.js +294 -0
  94. package/dist/node/index.js +1677 -0
  95. package/dist/node/query/index.js +159 -0
  96. package/dist/node/query/query.enum.js +11 -0
  97. package/dist/node/query/query.operation.js +154 -0
  98. package/dist/node/query/query.presentation.js +119 -0
  99. package/dist/node/query/query.schema.js +70 -0
  100. package/dist/node/query/query.test-spec.js +113 -0
  101. package/dist/node/query-engine/index.js +491 -0
  102. package/dist/node/seeders/index.js +20 -0
  103. package/dist/node/ui/AnalyticsDashboard.js +394 -0
  104. package/dist/node/ui/hooks/index.js +69 -0
  105. package/dist/node/ui/hooks/useAnalyticsData.js +66 -0
  106. package/dist/node/ui/index.js +671 -0
  107. package/dist/node/ui/renderers/analytics.markdown.js +275 -0
  108. package/dist/node/ui/renderers/index.js +275 -0
  109. package/dist/query/index.d.ts +7 -4
  110. package/dist/query/index.d.ts.map +1 -0
  111. package/dist/query/index.js +159 -4
  112. package/dist/query/query.enum.d.ts +1 -6
  113. package/dist/query/query.enum.d.ts.map +1 -1
  114. package/dist/query/query.enum.js +10 -14
  115. package/dist/query/query.operation.d.ts +148 -154
  116. package/dist/query/query.operation.d.ts.map +1 -1
  117. package/dist/query/query.operation.js +151 -109
  118. package/dist/query/query.presentation.d.ts +2 -7
  119. package/dist/query/query.presentation.d.ts.map +1 -1
  120. package/dist/query/query.presentation.js +116 -56
  121. package/dist/query/query.schema.d.ts +121 -126
  122. package/dist/query/query.schema.d.ts.map +1 -1
  123. package/dist/query/query.schema.js +66 -152
  124. package/dist/query/query.test-spec.d.ts +2 -7
  125. package/dist/query/query.test-spec.d.ts.map +1 -1
  126. package/dist/query/query.test-spec.js +111 -121
  127. package/dist/query-engine/index.d.ts +84 -88
  128. package/dist/query-engine/index.d.ts.map +1 -1
  129. package/dist/query-engine/index.js +489 -188
  130. package/dist/seeders/index.d.ts +4 -8
  131. package/dist/seeders/index.d.ts.map +1 -1
  132. package/dist/seeders/index.js +18 -16
  133. package/dist/ui/AnalyticsDashboard.d.ts +1 -6
  134. package/dist/ui/AnalyticsDashboard.d.ts.map +1 -1
  135. package/dist/ui/AnalyticsDashboard.js +389 -259
  136. package/dist/ui/hooks/index.d.ts +2 -2
  137. package/dist/ui/hooks/index.d.ts.map +1 -0
  138. package/dist/ui/hooks/index.js +69 -4
  139. package/dist/ui/hooks/useAnalyticsData.d.ts +16 -20
  140. package/dist/ui/hooks/useAnalyticsData.d.ts.map +1 -1
  141. package/dist/ui/hooks/useAnalyticsData.js +63 -69
  142. package/dist/ui/index.d.ts +7 -6
  143. package/dist/ui/index.d.ts.map +1 -0
  144. package/dist/ui/index.js +671 -5
  145. package/dist/ui/renderers/analytics.markdown.d.ts +13 -14
  146. package/dist/ui/renderers/analytics.markdown.d.ts.map +1 -1
  147. package/dist/ui/renderers/analytics.markdown.js +266 -254
  148. package/dist/ui/renderers/index.d.ts +2 -2
  149. package/dist/ui/renderers/index.d.ts.map +1 -0
  150. package/dist/ui/renderers/index.js +275 -2
  151. package/package.json +328 -67
  152. package/dist/dashboard/dashboard.enum.js.map +0 -1
  153. package/dist/dashboard/dashboard.operation.js.map +0 -1
  154. package/dist/dashboard/dashboard.presentation.js.map +0 -1
  155. package/dist/dashboard/dashboard.schema.js.map +0 -1
  156. package/dist/dashboard/dashboard.test-spec.js.map +0 -1
  157. package/dist/dashboard.feature.js.map +0 -1
  158. package/dist/datasource/posthog-datasource.js.map +0 -1
  159. package/dist/docs/analytics-dashboard.docblock.js.map +0 -1
  160. package/dist/events.js.map +0 -1
  161. package/dist/example.js.map +0 -1
  162. package/dist/handlers/analytics.handlers.js.map +0 -1
  163. package/dist/handlers/query.handlers.js.map +0 -1
  164. package/dist/query/query.enum.js.map +0 -1
  165. package/dist/query/query.operation.js.map +0 -1
  166. package/dist/query/query.presentation.js.map +0 -1
  167. package/dist/query/query.schema.js.map +0 -1
  168. package/dist/query/query.test-spec.js.map +0 -1
  169. package/dist/query-engine/index.js.map +0 -1
  170. package/dist/seeders/index.js.map +0 -1
  171. package/dist/ui/AnalyticsDashboard.js.map +0 -1
  172. package/dist/ui/hooks/useAnalyticsData.js.map +0 -1
  173. package/dist/ui/renderers/analytics.markdown.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"example.js","names":[],"sources":["../src/example.ts"],"sourcesContent":["import { defineExample } from '@contractspec/lib.contracts';\n\nconst example = defineExample({\n meta: {\n key: 'analytics-dashboard',\n version: '1.0.0',\n title: 'Analytics Dashboard',\n description:\n 'Tenant-scoped dashboards, widgets, query builder, and scheduled reports (spec-first widgets/queries).',\n kind: 'template',\n visibility: 'public',\n stability: 'experimental',\n owners: ['@platform.core'],\n tags: ['analytics', 'dashboards', 'bi', 'queries'],\n },\n docs: {\n rootDocId: 'docs.examples.analytics-dashboard',\n goalDocId: 'docs.examples.analytics-dashboard.goal',\n usageDocId: 'docs.examples.analytics-dashboard.usage',\n constraintsDocId: 'docs.examples.analytics-dashboard.constraints',\n },\n entrypoints: {\n packageName: '@contractspec/example.analytics-dashboard',\n feature: './feature',\n contracts: './contracts',\n presentations: './presentations',\n handlers: './handlers',\n docs: './docs',\n },\n surfaces: {\n templates: true,\n sandbox: {\n enabled: true,\n modes: ['playground', 'specs', 'builder', 'markdown', 'evolution'],\n },\n studio: { enabled: true, installable: true },\n mcp: { enabled: true },\n },\n});\n\nexport default example;\n"],"mappings":";;;AAEA,MAAM,UAAU,cAAc;CAC5B,MAAM;EACJ,KAAK;EACL,SAAS;EACT,OAAO;EACP,aACE;EACF,MAAM;EACN,YAAY;EACZ,WAAW;EACX,QAAQ,CAAC,iBAAiB;EAC1B,MAAM;GAAC;GAAa;GAAc;GAAM;GAAU;EACnD;CACD,MAAM;EACJ,WAAW;EACX,WAAW;EACX,YAAY;EACZ,kBAAkB;EACnB;CACD,aAAa;EACX,aAAa;EACb,SAAS;EACT,WAAW;EACX,eAAe;EACf,UAAU;EACV,MAAM;EACP;CACD,UAAU;EACR,WAAW;EACX,SAAS;GACP,SAAS;GACT,OAAO;IAAC;IAAc;IAAS;IAAW;IAAY;IAAY;GACnE;EACD,QAAQ;GAAE,SAAS;GAAM,aAAa;GAAM;EAC5C,KAAK,EAAE,SAAS,MAAM;EACvB;CACF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"analytics.handlers.js","names":[],"sources":["../../src/handlers/analytics.handlers.ts"],"sourcesContent":["/**\n * Runtime-local Analytics Dashboard handlers\n *\n * Database-backed handlers for the analytics-dashboard template.\n */\nimport type { DatabasePort, DbRow } from '@contractspec/lib.runtime-sandbox';\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport { web } from '@contractspec/lib.runtime-sandbox';\nconst { generateId } = web;\n\n// ============ Types ============\n\nexport interface Dashboard {\n id: string;\n projectId: string;\n organizationId: string;\n name: string;\n slug: string;\n description?: string;\n status: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';\n refreshInterval:\n | 'NONE'\n | 'MINUTE'\n | 'FIVE_MINUTES'\n | 'FIFTEEN_MINUTES'\n | 'HOUR'\n | 'DAY';\n isPublic: boolean;\n shareToken?: string;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface Widget {\n id: string;\n dashboardId: string;\n name: string;\n type:\n | 'LINE_CHART'\n | 'BAR_CHART'\n | 'PIE_CHART'\n | 'AREA_CHART'\n | 'SCATTER_PLOT'\n | 'METRIC'\n | 'TABLE'\n | 'HEATMAP'\n | 'FUNNEL'\n | 'MAP'\n | 'TEXT'\n | 'EMBED';\n gridX: number;\n gridY: number;\n gridWidth: number;\n gridHeight: number;\n queryId?: string;\n config?: Record<string, unknown>;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface Query {\n id: string;\n projectId: string;\n organizationId: string;\n name: string;\n description?: string;\n type: 'SQL' | 'METRIC' | 'AGGREGATION' | 'CUSTOM';\n definition: Record<string, unknown>;\n sql?: string;\n cacheTtlSeconds: number;\n isShared: boolean;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateDashboardInput {\n name: string;\n slug: string;\n description?: string;\n refreshInterval?: Dashboard['refreshInterval'];\n}\n\nexport interface AddWidgetInput {\n dashboardId: string;\n name: string;\n type: Widget['type'];\n gridX?: number;\n gridY?: number;\n gridWidth?: number;\n gridHeight?: number;\n queryId?: string;\n config?: Record<string, unknown>;\n}\n\nexport interface CreateQueryInput {\n name: string;\n description?: string;\n type: Query['type'];\n definition: Record<string, unknown>;\n sql?: string;\n cacheTtlSeconds?: number;\n isShared?: boolean;\n}\n\nexport interface ListDashboardsInput {\n projectId: string;\n status?: Dashboard['status'] | 'all';\n search?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface ListDashboardsOutput {\n dashboards: Dashboard[];\n total: number;\n}\n\nexport interface ListQueriesInput {\n projectId: string;\n type?: Query['type'] | 'all';\n isShared?: boolean;\n search?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface ListQueriesOutput {\n queries: Query[];\n total: number;\n}\n\n// ============ Row Types ============\n\ninterface DashboardRow {\n id: string;\n projectId: string;\n organizationId: string;\n name: string;\n slug: string;\n description: string | null;\n status: string;\n refreshInterval: string;\n isPublic: number;\n shareToken: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface WidgetRow {\n id: string;\n dashboardId: string;\n name: string;\n type: string;\n gridX: number;\n gridY: number;\n gridWidth: number;\n gridHeight: number;\n queryId: string | null;\n config: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface QueryRow {\n id: string;\n projectId: string;\n organizationId: string;\n name: string;\n description: string | null;\n type: string;\n definition: string;\n sql: string | null;\n cacheTtlSeconds: number;\n isShared: number;\n createdAt: string;\n updatedAt: string;\n}\n\nfunction rowToDashboard(row: DashboardRow): Dashboard {\n return {\n id: row.id,\n projectId: row.projectId,\n organizationId: row.organizationId,\n name: row.name,\n slug: row.slug,\n description: row.description ?? undefined,\n status: row.status as Dashboard['status'],\n refreshInterval: row.refreshInterval as Dashboard['refreshInterval'],\n isPublic: row.isPublic === 1,\n shareToken: row.shareToken ?? undefined,\n createdAt: new Date(row.createdAt),\n updatedAt: new Date(row.updatedAt),\n };\n}\n\nfunction rowToWidget(row: WidgetRow): Widget {\n return {\n id: row.id,\n dashboardId: row.dashboardId,\n name: row.name,\n type: row.type as Widget['type'],\n gridX: row.gridX,\n gridY: row.gridY,\n gridWidth: row.gridWidth,\n gridHeight: row.gridHeight,\n queryId: row.queryId ?? undefined,\n config: row.config ? JSON.parse(row.config) : undefined,\n createdAt: new Date(row.createdAt),\n updatedAt: new Date(row.updatedAt),\n };\n}\n\nfunction rowToQuery(row: QueryRow): Query {\n return {\n id: row.id,\n projectId: row.projectId,\n organizationId: row.organizationId,\n name: row.name,\n description: row.description ?? undefined,\n type: row.type as Query['type'],\n definition: JSON.parse(row.definition),\n sql: row.sql ?? undefined,\n cacheTtlSeconds: row.cacheTtlSeconds,\n isShared: row.isShared === 1,\n createdAt: new Date(row.createdAt),\n updatedAt: new Date(row.updatedAt),\n };\n}\n\n// ============ Handler Factory ============\n\nexport function createAnalyticsHandlers(db: DatabasePort) {\n /**\n * List dashboards\n */\n async function listDashboards(\n input: ListDashboardsInput\n ): Promise<ListDashboardsOutput> {\n const { projectId, status, search, limit = 20, offset = 0 } = input;\n\n let whereClause = 'WHERE projectId = ?';\n const params: (string | number)[] = [projectId];\n\n if (status && status !== 'all') {\n whereClause += ' AND status = ?';\n params.push(status);\n }\n\n if (search) {\n whereClause += ' AND (name LIKE ? OR description LIKE ?)';\n params.push(`%${search}%`, `%${search}%`);\n }\n\n const countResult = (\n await db.query(\n `SELECT COUNT(*) as count FROM analytics_dashboard ${whereClause}`,\n params\n )\n ).rows as DbRow[];\n const total = (countResult[0]?.count as number) ?? 0;\n\n const rows = (\n await db.query(\n `SELECT * FROM analytics_dashboard ${whereClause} ORDER BY updatedAt DESC LIMIT ? OFFSET ?`,\n [...params, limit, offset]\n )\n ).rows as unknown as DashboardRow[];\n\n return {\n dashboards: rows.map(rowToDashboard),\n total,\n };\n }\n\n /**\n * Create a dashboard\n */\n async function createDashboard(\n input: CreateDashboardInput,\n context: { projectId: string; organizationId: string }\n ): Promise<Dashboard> {\n const id = generateId('dash');\n const now = new Date().toISOString();\n\n await db.execute(\n `INSERT INTO analytics_dashboard (id, projectId, organizationId, name, slug, description, status, refreshInterval, isPublic, createdAt, updatedAt)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n context.projectId,\n context.organizationId,\n input.name,\n input.slug,\n input.description ?? null,\n 'DRAFT',\n input.refreshInterval ?? 'NONE',\n 0,\n now,\n now,\n ]\n );\n\n const rows = (\n await db.query(`SELECT * FROM analytics_dashboard WHERE id = ?`, [id])\n ).rows as unknown as DashboardRow[];\n\n return rowToDashboard(rows[0]!);\n }\n\n /**\n * Get a dashboard by ID or slug\n */\n async function getDashboard(input: {\n dashboardId?: string;\n slug?: string;\n shareToken?: string;\n }): Promise<Dashboard | null> {\n let whereClause = '';\n const params: string[] = [];\n\n if (input.dashboardId) {\n whereClause = 'WHERE id = ?';\n params.push(input.dashboardId);\n } else if (input.slug) {\n whereClause = 'WHERE slug = ?';\n params.push(input.slug);\n } else if (input.shareToken) {\n whereClause = 'WHERE shareToken = ?';\n params.push(input.shareToken);\n } else {\n return null;\n }\n\n const rows = (\n await db.query(`SELECT * FROM analytics_dashboard ${whereClause}`, params)\n ).rows as unknown as DashboardRow[];\n\n return rows[0] ? rowToDashboard(rows[0]) : null;\n }\n\n /**\n * Update dashboard\n */\n async function updateDashboard(\n dashboardId: string,\n updates: Partial<\n Pick<\n Dashboard,\n 'name' | 'description' | 'status' | 'refreshInterval' | 'isPublic'\n >\n >\n ): Promise<Dashboard> {\n const now = new Date().toISOString();\n const setClauses: string[] = ['updatedAt = ?'];\n const params: (string | number)[] = [now];\n\n if (updates.name !== undefined) {\n setClauses.push('name = ?');\n params.push(updates.name);\n }\n if (updates.description !== undefined) {\n setClauses.push('description = ?');\n params.push(updates.description);\n }\n if (updates.status !== undefined) {\n setClauses.push('status = ?');\n params.push(updates.status);\n }\n if (updates.refreshInterval !== undefined) {\n setClauses.push('refreshInterval = ?');\n params.push(updates.refreshInterval);\n }\n if (updates.isPublic !== undefined) {\n setClauses.push('isPublic = ?');\n params.push(updates.isPublic ? 1 : 0);\n\n // Generate share token if making public\n if (updates.isPublic) {\n setClauses.push('shareToken = ?');\n params.push(generateId('share'));\n } else {\n setClauses.push('shareToken = NULL');\n }\n }\n\n params.push(dashboardId);\n\n await db.execute(\n `UPDATE analytics_dashboard SET ${setClauses.join(', ')} WHERE id = ?`,\n params\n );\n\n const rows = (\n await db.query(`SELECT * FROM analytics_dashboard WHERE id = ?`, [\n dashboardId,\n ])\n ).rows as unknown as DashboardRow[];\n\n return rowToDashboard(rows[0]!);\n }\n\n /**\n * Get widgets for a dashboard\n */\n async function getWidgets(dashboardId: string): Promise<Widget[]> {\n const rows = (\n await db.query(\n `SELECT * FROM analytics_widget WHERE dashboardId = ? ORDER BY gridY, gridX`,\n [dashboardId]\n )\n ).rows as unknown as WidgetRow[];\n\n return rows.map(rowToWidget);\n }\n\n /**\n * Add a widget to a dashboard\n */\n async function addWidget(input: AddWidgetInput): Promise<Widget> {\n const id = generateId('widget');\n const now = new Date().toISOString();\n\n await db.execute(\n `INSERT INTO analytics_widget (id, dashboardId, name, type, gridX, gridY, gridWidth, gridHeight, queryId, config, createdAt, updatedAt)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n input.dashboardId,\n input.name,\n input.type,\n input.gridX ?? 0,\n input.gridY ?? 0,\n input.gridWidth ?? 6,\n input.gridHeight ?? 4,\n input.queryId ?? null,\n input.config ? JSON.stringify(input.config) : null,\n now,\n now,\n ]\n );\n\n const rows = (\n await db.query(`SELECT * FROM analytics_widget WHERE id = ?`, [id])\n ).rows as unknown as WidgetRow[];\n\n return rowToWidget(rows[0]!);\n }\n\n /**\n * Update a widget\n */\n async function updateWidget(\n widgetId: string,\n updates: Partial<\n Pick<\n Widget,\n | 'name'\n | 'gridX'\n | 'gridY'\n | 'gridWidth'\n | 'gridHeight'\n | 'queryId'\n | 'config'\n >\n >\n ): Promise<Widget> {\n const now = new Date().toISOString();\n const setClauses: string[] = ['updatedAt = ?'];\n const params: (string | number | null)[] = [now];\n\n if (updates.name !== undefined) {\n setClauses.push('name = ?');\n params.push(updates.name);\n }\n if (updates.gridX !== undefined) {\n setClauses.push('gridX = ?');\n params.push(updates.gridX);\n }\n if (updates.gridY !== undefined) {\n setClauses.push('gridY = ?');\n params.push(updates.gridY);\n }\n if (updates.gridWidth !== undefined) {\n setClauses.push('gridWidth = ?');\n params.push(updates.gridWidth);\n }\n if (updates.gridHeight !== undefined) {\n setClauses.push('gridHeight = ?');\n params.push(updates.gridHeight);\n }\n if (updates.queryId !== undefined) {\n setClauses.push('queryId = ?');\n params.push(updates.queryId ?? null);\n }\n if (updates.config !== undefined) {\n setClauses.push('config = ?');\n params.push(updates.config ? JSON.stringify(updates.config) : null);\n }\n\n params.push(widgetId);\n\n await db.execute(\n `UPDATE analytics_widget SET ${setClauses.join(', ')} WHERE id = ?`,\n params\n );\n\n const rows = (\n await db.query(`SELECT * FROM analytics_widget WHERE id = ?`, [widgetId])\n ).rows as unknown as WidgetRow[];\n\n return rowToWidget(rows[0]!);\n }\n\n /**\n * Delete a widget\n */\n async function deleteWidget(widgetId: string): Promise<void> {\n await db.execute(`DELETE FROM analytics_widget WHERE id = ?`, [widgetId]);\n }\n\n /**\n * List queries\n */\n async function listQueries(\n input: ListQueriesInput\n ): Promise<ListQueriesOutput> {\n const { projectId, type, isShared, search, limit = 20, offset = 0 } = input;\n\n let whereClause = 'WHERE projectId = ?';\n const params: (string | number)[] = [projectId];\n\n if (type && type !== 'all') {\n whereClause += ' AND type = ?';\n params.push(type);\n }\n\n if (isShared !== undefined) {\n whereClause += ' AND isShared = ?';\n params.push(isShared ? 1 : 0);\n }\n\n if (search) {\n whereClause += ' AND (name LIKE ? OR description LIKE ?)';\n params.push(`%${search}%`, `%${search}%`);\n }\n\n const countResult = (\n await db.query(\n `SELECT COUNT(*) as count FROM analytics_query ${whereClause}`,\n params\n )\n ).rows as DbRow[];\n const total = (countResult[0]?.count as number) ?? 0;\n\n const rows = (\n await db.query(\n `SELECT * FROM analytics_query ${whereClause} ORDER BY updatedAt DESC LIMIT ? OFFSET ?`,\n [...params, limit, offset]\n )\n ).rows as unknown as QueryRow[];\n\n return {\n queries: rows.map(rowToQuery),\n total,\n };\n }\n\n /**\n * Create a query\n */\n async function createQuery(\n input: CreateQueryInput,\n context: { projectId: string; organizationId: string }\n ): Promise<Query> {\n const id = generateId('query');\n const now = new Date().toISOString();\n\n await db.execute(\n `INSERT INTO analytics_query (id, projectId, organizationId, name, description, type, definition, sql, cacheTtlSeconds, isShared, createdAt, updatedAt)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n context.projectId,\n context.organizationId,\n input.name,\n input.description ?? null,\n input.type,\n JSON.stringify(input.definition),\n input.sql ?? null,\n input.cacheTtlSeconds ?? 300,\n input.isShared ? 1 : 0,\n now,\n now,\n ]\n );\n\n const rows = (\n await db.query(`SELECT * FROM analytics_query WHERE id = ?`, [id])\n ).rows as unknown as QueryRow[];\n\n return rowToQuery(rows[0]!);\n }\n\n /**\n * Get a query by ID\n */\n async function getQuery(queryId: string): Promise<Query | null> {\n const rows = (\n await db.query(`SELECT * FROM analytics_query WHERE id = ?`, [queryId])\n ).rows as unknown as QueryRow[];\n\n return rows[0] ? rowToQuery(rows[0]) : null;\n }\n\n return {\n listDashboards,\n createDashboard,\n getDashboard,\n updateDashboard,\n getWidgets,\n addWidget,\n updateWidget,\n deleteWidget,\n listQueries,\n createQuery,\n getQuery,\n };\n}\n\nexport type AnalyticsHandlers = ReturnType<typeof createAnalyticsHandlers>;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"query.handlers.js","names":[],"sources":["../../src/handlers/query.handlers.ts"],"sourcesContent":["import type { AnalyticsReader } from '@contractspec/lib.contracts/integrations/providers/analytics';\nimport type {\n QueryDefinition,\n QueryParameters,\n QueryResult,\n} from '../query-engine';\nimport { createPosthogQueryEngine } from '../datasource/posthog-datasource';\n\nexport interface ExecutePosthogQueryInput {\n definition: QueryDefinition;\n params: QueryParameters;\n reader: AnalyticsReader;\n}\n\nexport async function executePosthogQuery(\n input: ExecutePosthogQueryInput\n): Promise<QueryResult> {\n const engine = createPosthogQueryEngine(input.reader);\n return engine.execute(input.definition, input.params);\n}\n"],"mappings":";;;AAcA,eAAsB,oBACpB,OACsB;AAEtB,QADe,yBAAyB,MAAM,OAAO,CACvC,QAAQ,MAAM,YAAY,MAAM,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"query.enum.js","names":[],"sources":["../../src/query/query.enum.ts"],"sourcesContent":["import { defineEnum } from '@contractspec/lib.schema';\n\n/**\n * Query type enum.\n */\nexport const QueryTypeEnum = defineEnum('QueryType', [\n 'SQL',\n 'METRIC',\n 'AGGREGATION',\n 'CUSTOM',\n]);\n"],"mappings":";;;;;;AAKA,MAAa,gBAAgB,WAAW,aAAa;CACnD;CACA;CACA;CACA;CACD,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"query.operation.js","names":[],"sources":["../../src/query/query.operation.ts"],"sourcesContent":["import {\n defineCommand,\n defineQuery,\n} from '@contractspec/lib.contracts/operations';\nimport {\n QueryModel,\n QueryResultModel,\n CreateQueryInputModel,\n ExecuteQueryInputModel,\n} from './query.schema';\n\nconst OWNERS = ['@example.analytics-dashboard'] as const;\n\n/**\n * Create a data query.\n */\nexport const CreateQueryContract = defineCommand({\n meta: {\n key: 'analytics.query.create',\n version: '1.0.0',\n stability: 'stable',\n owners: [...OWNERS],\n tags: ['analytics', 'query', 'create'],\n description: 'Create a data query.',\n goal: 'Define reusable data queries.',\n context: 'Query builder.',\n },\n io: { input: CreateQueryInputModel, output: QueryModel },\n policy: { auth: 'user' },\n sideEffects: {\n emits: [\n {\n key: 'analytics.query.created',\n version: '1.0.0',\n stability: 'stable',\n owners: [...OWNERS],\n tags: ['analytics', 'query', 'created'],\n when: 'Query created',\n payload: QueryModel,\n },\n ],\n audit: ['analytics.query.created'],\n },\n acceptance: {\n scenarios: [\n {\n key: 'create-query-happy-path',\n given: ['User is authenticated'],\n when: ['User submits valid query definition'],\n then: ['Query is created', 'QueryCreated event is emitted'],\n },\n ],\n examples: [\n {\n key: 'create-sql-query',\n input: {\n name: 'Monthly Revenue',\n sql: 'SELECT SUM(amount) FROM orders WHERE date >= :startDate',\n },\n output: { id: 'query-123', name: 'Monthly Revenue', type: 'sql' },\n },\n ],\n },\n});\n\n/**\n * Execute a data query.\n */\nexport const ExecuteQueryContract = defineQuery({\n meta: {\n key: 'analytics.query.execute',\n version: '1.0.0',\n stability: 'stable',\n owners: [...OWNERS],\n tags: ['analytics', 'query', 'execute'],\n description: 'Execute a data query.',\n goal: 'Fetch data for visualizations.',\n context: 'Dashboard rendering.',\n },\n io: { input: ExecuteQueryInputModel, output: QueryResultModel },\n policy: { auth: 'user' },\n acceptance: {\n scenarios: [\n {\n key: 'execute-query-happy-path',\n given: ['Query exists'],\n when: ['User executes query with parameters'],\n then: ['Query results are returned'],\n },\n ],\n examples: [\n {\n key: 'execute-with-params',\n input: { queryId: 'query-123', params: { startDate: '2025-01-01' } },\n output: { columns: ['total'], rows: [{ total: 50000 }], rowCount: 1 },\n },\n ],\n },\n});\n"],"mappings":";;;;AAWA,MAAM,SAAS,CAAC,+BAA+B;;;;AAK/C,MAAa,sBAAsB,cAAc;CAC/C,MAAM;EACJ,KAAK;EACL,SAAS;EACT,WAAW;EACX,QAAQ,CAAC,GAAG,OAAO;EACnB,MAAM;GAAC;GAAa;GAAS;GAAS;EACtC,aAAa;EACb,MAAM;EACN,SAAS;EACV;CACD,IAAI;EAAE,OAAO;EAAuB,QAAQ;EAAY;CACxD,QAAQ,EAAE,MAAM,QAAQ;CACxB,aAAa;EACX,OAAO,CACL;GACE,KAAK;GACL,SAAS;GACT,WAAW;GACX,QAAQ,CAAC,GAAG,OAAO;GACnB,MAAM;IAAC;IAAa;IAAS;IAAU;GACvC,MAAM;GACN,SAAS;GACV,CACF;EACD,OAAO,CAAC,0BAA0B;EACnC;CACD,YAAY;EACV,WAAW,CACT;GACE,KAAK;GACL,OAAO,CAAC,wBAAwB;GAChC,MAAM,CAAC,sCAAsC;GAC7C,MAAM,CAAC,oBAAoB,gCAAgC;GAC5D,CACF;EACD,UAAU,CACR;GACE,KAAK;GACL,OAAO;IACL,MAAM;IACN,KAAK;IACN;GACD,QAAQ;IAAE,IAAI;IAAa,MAAM;IAAmB,MAAM;IAAO;GAClE,CACF;EACF;CACF,CAAC;;;;AAKF,MAAa,uBAAuB,YAAY;CAC9C,MAAM;EACJ,KAAK;EACL,SAAS;EACT,WAAW;EACX,QAAQ,CAAC,GAAG,OAAO;EACnB,MAAM;GAAC;GAAa;GAAS;GAAU;EACvC,aAAa;EACb,MAAM;EACN,SAAS;EACV;CACD,IAAI;EAAE,OAAO;EAAwB,QAAQ;EAAkB;CAC/D,QAAQ,EAAE,MAAM,QAAQ;CACxB,YAAY;EACV,WAAW,CACT;GACE,KAAK;GACL,OAAO,CAAC,eAAe;GACvB,MAAM,CAAC,sCAAsC;GAC7C,MAAM,CAAC,6BAA6B;GACrC,CACF;EACD,UAAU,CACR;GACE,KAAK;GACL,OAAO;IAAE,SAAS;IAAa,QAAQ,EAAE,WAAW,cAAc;IAAE;GACpE,QAAQ;IAAE,SAAS,CAAC,QAAQ;IAAE,MAAM,CAAC,EAAE,OAAO,KAAO,CAAC;IAAE,UAAU;IAAG;GACtE,CACF;EACF;CACF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"query.presentation.js","names":[],"sources":["../../src/query/query.presentation.ts"],"sourcesContent":["import { definePresentation, StabilityEnum } from '@contractspec/lib.contracts';\nimport { QueryModel } from './query.schema';\n\nexport const QueriesListPresentation = definePresentation({\n meta: {\n key: 'analytics.query.list',\n version: '1.0.0',\n title: 'Queries List',\n description: 'List of saved queries',\n domain: 'analytics',\n owners: ['@analytics-dashboard'],\n tags: ['analytics', 'queries', 'list'],\n stability: StabilityEnum.Experimental,\n goal: 'Browse and manage saved data queries.',\n context: 'The library of reusable data definitions.',\n },\n source: {\n type: 'component',\n framework: 'react',\n componentKey: 'QueriesList',\n props: QueryModel,\n },\n targets: ['react', 'markdown'],\n policy: {\n flags: ['analytics.queries.enabled'],\n },\n});\n\nexport const QueryBuilderPresentation = definePresentation({\n meta: {\n key: 'analytics.query.builder',\n version: '1.0.0',\n title: 'Query Builder',\n description: 'Visual query builder interface',\n domain: 'analytics',\n owners: ['@analytics-dashboard'],\n tags: ['analytics', 'query', 'builder'],\n stability: StabilityEnum.Experimental,\n goal: 'Visually construct data queries and transformations.',\n context: 'Developer tool for data analysis.',\n },\n source: {\n type: 'component',\n framework: 'react',\n componentKey: 'QueryBuilder',\n props: QueryModel,\n },\n targets: ['react'],\n policy: {\n flags: ['analytics.queries.enabled'],\n },\n});\n"],"mappings":";;;;AAGA,MAAa,0BAA0B,mBAAmB;CACxD,MAAM;EACJ,KAAK;EACL,SAAS;EACT,OAAO;EACP,aAAa;EACb,QAAQ;EACR,QAAQ,CAAC,uBAAuB;EAChC,MAAM;GAAC;GAAa;GAAW;GAAO;EACtC,WAAW,cAAc;EACzB,MAAM;EACN,SAAS;EACV;CACD,QAAQ;EACN,MAAM;EACN,WAAW;EACX,cAAc;EACd,OAAO;EACR;CACD,SAAS,CAAC,SAAS,WAAW;CAC9B,QAAQ,EACN,OAAO,CAAC,4BAA4B,EACrC;CACF,CAAC;AAEF,MAAa,2BAA2B,mBAAmB;CACzD,MAAM;EACJ,KAAK;EACL,SAAS;EACT,OAAO;EACP,aAAa;EACb,QAAQ;EACR,QAAQ,CAAC,uBAAuB;EAChC,MAAM;GAAC;GAAa;GAAS;GAAU;EACvC,WAAW,cAAc;EACzB,MAAM;EACN,SAAS;EACV;CACD,QAAQ;EACN,MAAM;EACN,WAAW;EACX,cAAc;EACd,OAAO;EACR;CACD,SAAS,CAAC,QAAQ;CAClB,QAAQ,EACN,OAAO,CAAC,4BAA4B,EACrC;CACF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"query.schema.js","names":[],"sources":["../../src/query/query.schema.ts"],"sourcesContent":["import { defineSchemaModel, ScalarTypeEnum } from '@contractspec/lib.schema';\nimport { QueryTypeEnum } from './query.enum';\n\n/**\n * A data query.\n */\nexport const QueryModel = defineSchemaModel({\n name: 'QueryModel',\n fields: {\n id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },\n type: { type: QueryTypeEnum, isOptional: false },\n definition: { type: ScalarTypeEnum.JSON(), isOptional: false },\n sql: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },\n cacheTtlSeconds: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },\n isShared: { type: ScalarTypeEnum.Boolean(), isOptional: false },\n createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },\n },\n});\n\n/**\n * Query execution result.\n */\nexport const QueryResultModel = defineSchemaModel({\n name: 'QueryResultModel',\n fields: {\n queryId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n data: { type: ScalarTypeEnum.JSON(), isOptional: false },\n columns: { type: ScalarTypeEnum.JSON(), isOptional: false },\n rowCount: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },\n executionTimeMs: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },\n cachedAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },\n error: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },\n },\n});\n\n/**\n * Input for creating a query.\n */\nexport const CreateQueryInputModel = defineSchemaModel({\n name: 'CreateQueryInput',\n fields: {\n name: { type: ScalarTypeEnum.NonEmptyString(), isOptional: false },\n description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },\n type: { type: QueryTypeEnum, isOptional: false },\n definition: { type: ScalarTypeEnum.JSON(), isOptional: false },\n sql: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },\n metricIds: {\n type: ScalarTypeEnum.String_unsecure(),\n isArray: true,\n isOptional: true,\n },\n cacheTtlSeconds: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },\n isShared: { type: ScalarTypeEnum.Boolean(), isOptional: true },\n },\n});\n\n/**\n * Input for executing a query.\n */\nexport const ExecuteQueryInputModel = defineSchemaModel({\n name: 'ExecuteQueryInput',\n fields: {\n queryId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n parameters: { type: ScalarTypeEnum.JSON(), isOptional: true },\n dateRange: { type: ScalarTypeEnum.JSON(), isOptional: true },\n filters: { type: ScalarTypeEnum.JSON(), isOptional: true },\n forceRefresh: { type: ScalarTypeEnum.Boolean(), isOptional: true },\n },\n});\n"],"mappings":";;;;;;;AAMA,MAAa,aAAa,kBAAkB;CAC1C,MAAM;CACN,QAAQ;EACN,IAAI;GAAE,MAAM,eAAe,iBAAiB;GAAE,YAAY;GAAO;EACjE,MAAM;GAAE,MAAM,eAAe,iBAAiB;GAAE,YAAY;GAAO;EACnE,aAAa;GAAE,MAAM,eAAe,iBAAiB;GAAE,YAAY;GAAM;EACzE,MAAM;GAAE,MAAM;GAAe,YAAY;GAAO;EAChD,YAAY;GAAE,MAAM,eAAe,MAAM;GAAE,YAAY;GAAO;EAC9D,KAAK;GAAE,MAAM,eAAe,iBAAiB;GAAE,YAAY;GAAM;EACjE,iBAAiB;GAAE,MAAM,eAAe,cAAc;GAAE,YAAY;GAAO;EAC3E,UAAU;GAAE,MAAM,eAAe,SAAS;GAAE,YAAY;GAAO;EAC/D,WAAW;GAAE,MAAM,eAAe,UAAU;GAAE,YAAY;GAAO;EAClE;CACF,CAAC;;;;AAKF,MAAa,mBAAmB,kBAAkB;CAChD,MAAM;CACN,QAAQ;EACN,SAAS;GAAE,MAAM,eAAe,iBAAiB;GAAE,YAAY;GAAO;EACtE,MAAM;GAAE,MAAM,eAAe,MAAM;GAAE,YAAY;GAAO;EACxD,SAAS;GAAE,MAAM,eAAe,MAAM;GAAE,YAAY;GAAO;EAC3D,UAAU;GAAE,MAAM,eAAe,cAAc;GAAE,YAAY;GAAO;EACpE,iBAAiB;GAAE,MAAM,eAAe,cAAc;GAAE,YAAY;GAAO;EAC3E,UAAU;GAAE,MAAM,eAAe,UAAU;GAAE,YAAY;GAAM;EAC/D,OAAO;GAAE,MAAM,eAAe,iBAAiB;GAAE,YAAY;GAAM;EACpE;CACF,CAAC;;;;AAKF,MAAa,wBAAwB,kBAAkB;CACrD,MAAM;CACN,QAAQ;EACN,MAAM;GAAE,MAAM,eAAe,gBAAgB;GAAE,YAAY;GAAO;EAClE,aAAa;GAAE,MAAM,eAAe,iBAAiB;GAAE,YAAY;GAAM;EACzE,MAAM;GAAE,MAAM;GAAe,YAAY;GAAO;EAChD,YAAY;GAAE,MAAM,eAAe,MAAM;GAAE,YAAY;GAAO;EAC9D,KAAK;GAAE,MAAM,eAAe,iBAAiB;GAAE,YAAY;GAAM;EACjE,WAAW;GACT,MAAM,eAAe,iBAAiB;GACtC,SAAS;GACT,YAAY;GACb;EACD,iBAAiB;GAAE,MAAM,eAAe,cAAc;GAAE,YAAY;GAAM;EAC1E,UAAU;GAAE,MAAM,eAAe,SAAS;GAAE,YAAY;GAAM;EAC/D;CACF,CAAC;;;;AAKF,MAAa,yBAAyB,kBAAkB;CACtD,MAAM;CACN,QAAQ;EACN,SAAS;GAAE,MAAM,eAAe,iBAAiB;GAAE,YAAY;GAAO;EACtE,YAAY;GAAE,MAAM,eAAe,MAAM;GAAE,YAAY;GAAM;EAC7D,WAAW;GAAE,MAAM,eAAe,MAAM;GAAE,YAAY;GAAM;EAC5D,SAAS;GAAE,MAAM,eAAe,MAAM;GAAE,YAAY;GAAM;EAC1D,cAAc;GAAE,MAAM,eAAe,SAAS;GAAE,YAAY;GAAM;EACnE;CACF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"query.test-spec.js","names":[],"sources":["../../src/query/query.test-spec.ts"],"sourcesContent":["import { defineTestSpec } from '@contractspec/lib.contracts';\n\nexport const CreateQueryTest = defineTestSpec({\n meta: {\n key: 'analytics.query.create.test',\n version: '1.0.0',\n title: 'Create Query Test',\n description: 'Verifies query creation flow',\n owners: ['@example.analytics-dashboard'],\n tags: ['analytics', 'query', 'test'],\n stability: 'stable',\n },\n target: {\n type: 'operation',\n operation: { key: 'analytics.query.create', version: '1.0.0' },\n },\n scenarios: [\n {\n key: 'success',\n description: 'Successfully create a query',\n when: {\n operation: { key: 'analytics.query.create', version: '1.0.0' },\n input: {\n name: 'Revenue Query',\n sql: 'SELECT * FROM revenue',\n },\n },\n then: [\n {\n type: 'expectOutput',\n match: {\n name: 'Revenue Query',\n type: 'sql',\n },\n },\n ],\n },\n {\n key: 'error-invalid-sql',\n description: 'Fail with invalid SQL',\n when: {\n operation: { key: 'analytics.query.create', version: '1.0.0' },\n input: {\n name: 'Bad Query',\n sql: '',\n },\n },\n then: [\n {\n type: 'expectError',\n messageIncludes: 'VALIDATION_ERROR',\n },\n ],\n },\n ],\n});\n\nexport const ExecuteQueryTest = defineTestSpec({\n meta: {\n key: 'analytics.query.execute.test',\n version: '1.0.0',\n title: 'Execute Query Test',\n description: 'Verifies query execution',\n owners: ['@example.analytics-dashboard'],\n tags: ['analytics', 'query', 'test'],\n stability: 'stable',\n },\n target: {\n type: 'operation',\n operation: { key: 'analytics.query.execute', version: '1.0.0' },\n },\n scenarios: [\n {\n key: 'success',\n description: 'Successfully execute query',\n when: {\n operation: { key: 'analytics.query.execute', version: '1.0.0' },\n input: {\n queryId: 'q-123',\n params: { limit: 10 },\n },\n },\n then: [\n {\n type: 'expectOutput',\n match: {\n rowCount: 1,\n },\n },\n ],\n },\n {\n key: 'error-query-not-found',\n description: 'Fail when query not found',\n when: {\n operation: { key: 'analytics.query.execute', version: '1.0.0' },\n input: {\n queryId: 'q-999',\n params: {},\n },\n },\n then: [\n {\n type: 'expectError',\n messageIncludes: 'NOT_FOUND',\n },\n ],\n },\n ],\n});\n"],"mappings":";;;AAEA,MAAa,kBAAkB,eAAe;CAC5C,MAAM;EACJ,KAAK;EACL,SAAS;EACT,OAAO;EACP,aAAa;EACb,QAAQ,CAAC,+BAA+B;EACxC,MAAM;GAAC;GAAa;GAAS;GAAO;EACpC,WAAW;EACZ;CACD,QAAQ;EACN,MAAM;EACN,WAAW;GAAE,KAAK;GAA0B,SAAS;GAAS;EAC/D;CACD,WAAW,CACT;EACE,KAAK;EACL,aAAa;EACb,MAAM;GACJ,WAAW;IAAE,KAAK;IAA0B,SAAS;IAAS;GAC9D,OAAO;IACL,MAAM;IACN,KAAK;IACN;GACF;EACD,MAAM,CACJ;GACE,MAAM;GACN,OAAO;IACL,MAAM;IACN,MAAM;IACP;GACF,CACF;EACF,EACD;EACE,KAAK;EACL,aAAa;EACb,MAAM;GACJ,WAAW;IAAE,KAAK;IAA0B,SAAS;IAAS;GAC9D,OAAO;IACL,MAAM;IACN,KAAK;IACN;GACF;EACD,MAAM,CACJ;GACE,MAAM;GACN,iBAAiB;GAClB,CACF;EACF,CACF;CACF,CAAC;AAEF,MAAa,mBAAmB,eAAe;CAC7C,MAAM;EACJ,KAAK;EACL,SAAS;EACT,OAAO;EACP,aAAa;EACb,QAAQ,CAAC,+BAA+B;EACxC,MAAM;GAAC;GAAa;GAAS;GAAO;EACpC,WAAW;EACZ;CACD,QAAQ;EACN,MAAM;EACN,WAAW;GAAE,KAAK;GAA2B,SAAS;GAAS;EAChE;CACD,WAAW,CACT;EACE,KAAK;EACL,aAAa;EACb,MAAM;GACJ,WAAW;IAAE,KAAK;IAA2B,SAAS;IAAS;GAC/D,OAAO;IACL,SAAS;IACT,QAAQ,EAAE,OAAO,IAAI;IACtB;GACF;EACD,MAAM,CACJ;GACE,MAAM;GACN,OAAO,EACL,UAAU,GACX;GACF,CACF;EACF,EACD;EACE,KAAK;EACL,aAAa;EACb,MAAM;GACJ,WAAW;IAAE,KAAK;IAA2B,SAAS;IAAS;GAC/D,OAAO;IACL,SAAS;IACT,QAAQ,EAAE;IACX;GACF;EACD,MAAM,CACJ;GACE,MAAM;GACN,iBAAiB;GAClB,CACF;EACF,CACF;CACF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/query-engine/index.ts"],"sourcesContent":["/**\n * Analytics Query Engine\n *\n * Provides query execution and caching for analytics dashboards.\n */\n\n// ============ Types ============\n\nexport interface QueryDefinition {\n type: 'SQL' | 'METRIC' | 'AGGREGATION' | 'CUSTOM';\n sql?: string;\n metricIds?: string[];\n aggregation?: AggregationDefinition;\n custom?: CustomQueryDefinition;\n}\n\nexport interface AggregationDefinition {\n source: string;\n measures: MeasureDefinition[];\n dimensions: DimensionDefinition[];\n filters?: FilterDefinition[];\n orderBy?: OrderByDefinition[];\n limit?: number;\n}\n\nexport interface MeasureDefinition {\n name: string;\n field: string;\n aggregation: 'COUNT' | 'SUM' | 'AVG' | 'MIN' | 'MAX' | 'COUNT_DISTINCT';\n format?: string;\n}\n\nexport interface DimensionDefinition {\n name: string;\n field: string;\n type?: 'TIME' | 'STRING' | 'NUMBER';\n granularity?: 'HOUR' | 'DAY' | 'WEEK' | 'MONTH' | 'YEAR';\n}\n\nexport interface FilterDefinition {\n field: string;\n operator:\n | 'eq'\n | 'neq'\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'in'\n | 'nin'\n | 'contains'\n | 'between';\n value: unknown;\n}\n\nexport interface OrderByDefinition {\n field: string;\n direction: 'ASC' | 'DESC';\n}\n\nexport interface CustomQueryDefinition {\n handler: string;\n parameters: Record<string, unknown>;\n}\n\nexport interface QueryParameters {\n dateRange?: {\n start: Date;\n end: Date;\n granularity?: string;\n };\n filters?: FilterDefinition[];\n parameters?: Record<string, unknown>;\n}\n\nexport interface QueryResult {\n data: Record<string, unknown>[];\n columns: ColumnDefinition[];\n rowCount: number;\n executionTimeMs: number;\n cached: boolean;\n cachedAt?: Date;\n error?: string;\n}\n\nexport interface ColumnDefinition {\n name: string;\n type: 'STRING' | 'NUMBER' | 'DATE' | 'BOOLEAN';\n label?: string;\n format?: string;\n}\n\n// ============ Query Engine Interface ============\n\nexport interface IQueryEngine {\n execute(\n definition: QueryDefinition,\n params: QueryParameters\n ): Promise<QueryResult>;\n validateQuery(definition: QueryDefinition): {\n valid: boolean;\n errors: string[];\n };\n}\n\n// ============ Query Cache ============\n\nexport interface IQueryCache {\n get(key: string): Promise<QueryResult | null>;\n set(key: string, result: QueryResult, ttlSeconds: number): Promise<void>;\n invalidate(pattern: string): Promise<void>;\n}\n\nexport class InMemoryQueryCache implements IQueryCache {\n private cache = new Map<string, { result: QueryResult; expiresAt: Date }>();\n\n async get(key: string): Promise<QueryResult | null> {\n const entry = this.cache.get(key);\n if (!entry) return null;\n if (entry.expiresAt < new Date()) {\n this.cache.delete(key);\n return null;\n }\n return { ...entry.result, cached: true, cachedAt: entry.expiresAt };\n }\n\n async set(\n key: string,\n result: QueryResult,\n ttlSeconds: number\n ): Promise<void> {\n const expiresAt = new Date(Date.now() + ttlSeconds * 1000);\n this.cache.set(key, { result, expiresAt });\n }\n\n async invalidate(pattern: string): Promise<void> {\n const regex = new RegExp(pattern);\n for (const key of this.cache.keys()) {\n if (regex.test(key)) {\n this.cache.delete(key);\n }\n }\n }\n}\n\n// ============ Basic Query Engine ============\n\nexport class BasicQueryEngine implements IQueryEngine {\n private cache: IQueryCache;\n\n constructor(cache?: IQueryCache) {\n this.cache = cache ?? new InMemoryQueryCache();\n }\n\n async execute(\n definition: QueryDefinition,\n params: QueryParameters\n ): Promise<QueryResult> {\n const startTime = Date.now();\n\n // Validate query\n const validation = this.validateQuery(definition);\n if (!validation.valid) {\n return {\n data: [],\n columns: [],\n rowCount: 0,\n executionTimeMs: Date.now() - startTime,\n cached: false,\n error: validation.errors.join(', '),\n };\n }\n\n // Check cache\n const cacheKey = this.buildCacheKey(definition, params);\n const cachedResult = await this.cache.get(cacheKey);\n if (cachedResult) {\n return cachedResult;\n }\n\n // Execute query based on type\n let result: QueryResult;\n switch (definition.type) {\n case 'AGGREGATION':\n if (!definition.aggregation) {\n throw new Error('Aggregation definition is missing');\n }\n result = await this.executeAggregation(definition.aggregation, params);\n break;\n case 'METRIC':\n if (!definition.metricIds) {\n throw new Error('Metric IDs are missing');\n }\n result = await this.executeMetric(definition.metricIds, params);\n break;\n case 'SQL':\n if (!definition.sql) {\n throw new Error('SQL query is missing');\n }\n result = await this.executeSql(definition.sql, params);\n break;\n default:\n result = {\n data: [],\n columns: [],\n rowCount: 0,\n executionTimeMs: Date.now() - startTime,\n cached: false,\n error: `Unknown query type: ${definition.type}`,\n };\n }\n\n result.executionTimeMs = Date.now() - startTime;\n result.cached = false;\n\n // Cache result\n await this.cache.set(cacheKey, result, 300);\n\n return result;\n }\n\n validateQuery(definition: QueryDefinition): {\n valid: boolean;\n errors: string[];\n } {\n const errors: string[] = [];\n\n if (!definition.type) {\n errors.push('Query type is required');\n }\n\n switch (definition.type) {\n case 'SQL':\n if (!definition.sql) {\n errors.push('SQL query is required for SQL type');\n }\n break;\n case 'METRIC':\n if (!definition.metricIds || definition.metricIds.length === 0) {\n errors.push('Metric IDs are required for METRIC type');\n }\n break;\n case 'AGGREGATION':\n if (!definition.aggregation) {\n errors.push(\n 'Aggregation definition is required for AGGREGATION type'\n );\n } else {\n if (!definition.aggregation.source) {\n errors.push('Aggregation source is required');\n }\n if (\n !definition.aggregation.measures ||\n definition.aggregation.measures.length === 0\n ) {\n errors.push('At least one measure is required');\n }\n }\n break;\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n private buildCacheKey(\n definition: QueryDefinition,\n params: QueryParameters\n ): string {\n return JSON.stringify({ definition, params });\n }\n\n private async executeAggregation(\n aggregation: AggregationDefinition,\n params: QueryParameters\n ): Promise<QueryResult> {\n // In production, this would execute against a data warehouse\n // For demo, return mock data\n const columns: ColumnDefinition[] = [\n ...aggregation.dimensions.map((d) => ({\n name: d.name,\n type: (d.type === 'NUMBER'\n ? 'NUMBER'\n : d.type === 'TIME'\n ? 'DATE'\n : 'STRING') as ColumnDefinition['type'],\n label: d.name,\n })),\n ...aggregation.measures.map((m) => ({\n name: m.name,\n type: 'NUMBER' as const,\n label: m.name,\n format: m.format,\n })),\n ];\n\n // Mock data generation\n const data = this.generateMockData(aggregation, params);\n\n return {\n data,\n columns,\n rowCount: data.length,\n executionTimeMs: 0,\n cached: false,\n };\n }\n\n private async executeMetric(\n metricIds: string[],\n _params: QueryParameters\n ): Promise<QueryResult> {\n // In production, this would fetch from metering service\n const data = metricIds.map((id) => ({\n metricId: id,\n value: Math.random() * 1000,\n change: (Math.random() - 0.5) * 20,\n }));\n\n return {\n data,\n columns: [\n { name: 'metricId', type: 'STRING' },\n { name: 'value', type: 'NUMBER' },\n { name: 'change', type: 'NUMBER' },\n ],\n rowCount: data.length,\n executionTimeMs: 0,\n cached: false,\n };\n }\n\n private async executeSql(\n _sql: string,\n _params: QueryParameters\n ): Promise<QueryResult> {\n // In production, this would execute SQL against a database\n return {\n data: [],\n columns: [],\n rowCount: 0,\n executionTimeMs: 0,\n cached: false,\n error: 'SQL execution not implemented in demo',\n };\n }\n\n private generateMockData(\n aggregation: AggregationDefinition,\n params: QueryParameters\n ): Record<string, unknown>[] {\n const data: Record<string, unknown>[] = [];\n const rowCount = 10;\n\n // Generate time series data if there's a time dimension\n const timeDimension = aggregation.dimensions.find((d) => d.type === 'TIME');\n\n for (let i = 0; i < rowCount; i++) {\n const row: Record<string, unknown> = {};\n\n for (const dim of aggregation.dimensions) {\n if (dim.type === 'TIME') {\n const date = new Date(params.dateRange?.start ?? new Date());\n date.setDate(date.getDate() + i);\n row[dim.name] = date.toISOString().split('T')[0];\n } else {\n row[dim.name] = `${dim.name}_${i % 5}`;\n }\n }\n\n for (const measure of aggregation.measures) {\n const baseValue = timeDimension ? 100 + i * 10 : Math.random() * 1000;\n const noise = (Math.random() - 0.5) * 20;\n row[measure.name] = Math.round((baseValue + noise) * 100) / 100;\n }\n\n data.push(row);\n }\n\n return data;\n }\n}\n\n// ============ Factory ============\n\nexport function createQueryEngine(cache?: IQueryCache): IQueryEngine {\n return new BasicQueryEngine(cache);\n}\n\nexport {\n PosthogQueryEngine,\n createPosthogQueryEngine,\n} from '../datasource/posthog-datasource';\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/seeders/index.ts"],"sourcesContent":["import type { DatabasePort } from '@contractspec/lib.runtime-sandbox';\n\nexport async 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"],"mappings":";AAEA,eAAsB,uBAAuB,QAG1C;CACD,MAAM,EAAE,WAAW,OAAO;AAM1B,MAJiB,MAAM,GAAG,MACxB,4EACA,CAAC,UAAU,CACZ,EACa,KAAK,IAAI,QAAmB,EAAG;AAE7C,OAAM,GAAG,QACP;2CAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"AnalyticsDashboard.js","names":[],"sources":["../../src/ui/AnalyticsDashboard.tsx"],"sourcesContent":["'use client';\n\n/**\n * Analytics Dashboard\n *\n * Interactive dashboard for the analytics-dashboard template.\n * Displays dashboards, widgets, and queries.\n */\nimport { useState } from 'react';\nimport {\n Button,\n ErrorState,\n LoaderBlock,\n StatCard,\n StatCardGroup,\n} from '@contractspec/lib.design-system';\nimport { useAnalyticsData } from './hooks/useAnalyticsData';\n\ntype Tab = 'dashboards' | 'queries';\n\nconst STATUS_COLORS: Record<string, string> = {\n PUBLISHED:\n 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400',\n DRAFT: 'bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400',\n ARCHIVED:\n 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400',\n};\n\nconst WIDGET_ICONS: Record<string, string> = {\n LINE_CHART: 'πŸ“ˆ',\n BAR_CHART: 'πŸ“Š',\n PIE_CHART: 'πŸ₯§',\n AREA_CHART: 'πŸ“‰',\n SCATTER_PLOT: '⚬',\n METRIC: 'πŸ”’',\n TABLE: 'πŸ“‹',\n HEATMAP: 'πŸ—ΊοΈ',\n FUNNEL: '⏬',\n MAP: '🌍',\n TEXT: 'πŸ“',\n EMBED: 'πŸ”—',\n};\n\nconst QUERY_TYPE_COLORS: Record<string, string> = {\n SQL: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400',\n METRIC:\n 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400',\n AGGREGATION:\n 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-400',\n CUSTOM: 'bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400',\n};\n\nexport function AnalyticsDashboard() {\n const [activeTab, setActiveTab] = useState<Tab>('dashboards');\n const {\n dashboards,\n queries,\n selectedDashboard,\n widgets,\n loading,\n error,\n stats,\n refetch,\n selectDashboard,\n } = useAnalyticsData();\n\n const tabs: { id: Tab; label: string; icon: string }[] = [\n { id: 'dashboards', label: 'Dashboards', icon: 'πŸ“Š' },\n { id: 'queries', label: 'Queries', icon: 'πŸ”' },\n ];\n\n if (loading) {\n return <LoaderBlock label=\"Loading Analytics...\" />;\n }\n\n if (error) {\n return (\n <ErrorState\n title=\"Failed to load Analytics\"\n description={error.message}\n onRetry={refetch}\n retryLabel=\"Retry\"\n />\n );\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-2xl font-bold\">Analytics Dashboard</h2>\n <Button onClick={() => alert('Create dashboard modal')}>\n <span className=\"mr-2\">+</span> New Dashboard\n </Button>\n </div>\n\n {/* Stats Row */}\n <StatCardGroup>\n <StatCard\n label=\"Dashboards\"\n value={stats.totalDashboards}\n hint={`${stats.publishedDashboards} published`}\n />\n <StatCard\n label=\"Queries\"\n value={stats.totalQueries}\n hint={`${stats.sharedQueries} shared`}\n />\n <StatCard\n label=\"Widgets\"\n value={widgets.length}\n hint=\"on current dashboard\"\n />\n </StatCardGroup>\n\n {/* Navigation Tabs */}\n <nav className=\"bg-muted flex gap-1 rounded-lg p-1\" role=\"tablist\">\n {tabs.map((tab) => (\n <Button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={activeTab === tab.id}\n onClick={() => setActiveTab(tab.id)}\n className={`flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors ${\n activeTab === tab.id\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n <span>{tab.icon}</span>\n {tab.label}\n </Button>\n ))}\n </nav>\n\n {/* Tab Content */}\n <div className=\"min-h-[400px]\" role=\"tabpanel\">\n {activeTab === 'dashboards' && (\n <div className=\"space-y-6\">\n {/* Dashboard List */}\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {dashboards.map((dashboard) => (\n <div\n key={dashboard.id}\n onClick={() => selectDashboard(dashboard)}\n className={`border-border bg-card cursor-pointer rounded-lg border p-4 transition-all ${\n selectedDashboard?.id === dashboard.id\n ? 'ring-primary ring-2'\n : 'hover:bg-muted/50'\n }`}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ')\n selectDashboard(dashboard);\n }}\n >\n <div className=\"mb-2 flex items-center justify-between\">\n <h3 className=\"font-medium\">{dashboard.name}</h3>\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[dashboard.status] ?? ''}`}\n >\n {dashboard.status}\n </span>\n </div>\n <p className=\"text-muted-foreground mb-3 text-sm\">\n {dashboard.description}\n </p>\n <div className=\"text-muted-foreground flex items-center justify-between text-xs\">\n <span>/{dashboard.slug}</span>\n {dashboard.isPublic && (\n <span className=\"text-green-600 dark:text-green-400\">\n 🌐 Public\n </span>\n )}\n </div>\n </div>\n ))}\n {dashboards.length === 0 && (\n <div className=\"text-muted-foreground col-span-full flex h-64 items-center justify-center\">\n No dashboards created yet\n </div>\n )}\n </div>\n\n {/* Widget Grid for Selected Dashboard */}\n {selectedDashboard && widgets.length > 0 && (\n <div>\n <h3 className=\"mb-4 text-lg font-semibold\">\n Widgets in \"{selectedDashboard.name}\"\n </h3>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {widgets.map((widget) => (\n <div\n key={widget.id}\n className=\"border-border bg-card rounded-lg border p-4\"\n >\n <div className=\"mb-2 flex items-center gap-2\">\n <span className=\"text-xl\">\n {WIDGET_ICONS[widget.type] ?? 'πŸ“Š'}\n </span>\n <span className=\"font-medium\">{widget.name}</span>\n </div>\n <div className=\"text-muted-foreground text-sm\">\n {widget.type.replace(/_/g, ' ')}\n </div>\n <div className=\"text-muted-foreground mt-2 text-xs\">\n Position: ({widget.gridX}, {widget.gridY}) β€’{' '}\n {widget.gridWidth}x{widget.gridHeight}\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n\n {activeTab === 'queries' && (\n <div className=\"border-border rounded-lg border\">\n <table className=\"w-full\">\n <thead className=\"border-border bg-muted/30 border-b\">\n <tr>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Query\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Type\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Cache TTL\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Shared\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-border divide-y\">\n {queries.map((query) => (\n <tr key={query.id} className=\"hover:bg-muted/50\">\n <td className=\"px-4 py-3\">\n <div className=\"font-medium\">{query.name}</div>\n <div className=\"text-muted-foreground text-sm\">\n {query.description}\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${QUERY_TYPE_COLORS[query.type] ?? ''}`}\n >\n {query.type}\n </span>\n </td>\n <td className=\"text-muted-foreground px-4 py-3 text-sm\">\n {query.cacheTtlSeconds}s\n </td>\n <td className=\"px-4 py-3\">\n {query.isShared ? (\n <span className=\"text-green-600 dark:text-green-400\">\n βœ“\n </span>\n ) : (\n <span className=\"text-muted-foreground\">β€”</span>\n )}\n </td>\n </tr>\n ))}\n {queries.length === 0 && (\n <tr>\n <td\n colSpan={4}\n className=\"text-muted-foreground px-4 py-8 text-center\"\n >\n No queries saved\n </td>\n </tr>\n )}\n </tbody>\n </table>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"useAnalyticsData.js","names":[],"sources":["../../../src/ui/hooks/useAnalyticsData.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\nimport type {\n AnalyticsHandlers,\n Dashboard,\n Query,\n Widget,\n} from '../../handlers/analytics.handlers';\nimport { useTemplateRuntime } from '@contractspec/lib.example-shared-ui';\n\nexport interface AnalyticsStats {\n totalDashboards: number;\n publishedDashboards: number;\n totalQueries: number;\n sharedQueries: number;\n}\n\nexport function useAnalyticsData(projectId = 'local-project') {\n const { handlers } = useTemplateRuntime<{ analytics: AnalyticsHandlers }>();\n const analytics = handlers.analytics;\n const [dashboards, setDashboards] = useState<Dashboard[]>([]);\n const [queries, setQueries] = useState<Query[]>([]);\n const [selectedDashboard, setSelectedDashboard] = useState<Dashboard | null>(\n null\n );\n const [widgets, setWidgets] = useState<Widget[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n try {\n setLoading(true);\n setError(null);\n\n const [dashResult, queryResult] = await Promise.all([\n analytics.listDashboards({ projectId, limit: 100 }),\n analytics.listQueries({ projectId, limit: 100 }),\n ]);\n\n setDashboards(dashResult.dashboards);\n setQueries(queryResult.queries);\n\n // Select first dashboard if available\n if (dashResult.dashboards.length > 0 && !selectedDashboard) {\n const first = dashResult.dashboards[0];\n if (first) {\n setSelectedDashboard(first);\n const dashboardWidgets = await analytics.getWidgets(first.id);\n setWidgets(dashboardWidgets);\n }\n }\n } catch (err) {\n setError(\n err instanceof Error ? err : new Error('Failed to load analytics')\n );\n } finally {\n setLoading(false);\n }\n }, [analytics, projectId, selectedDashboard]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n const selectDashboard = useCallback(\n async (dashboard: Dashboard) => {\n setSelectedDashboard(dashboard);\n const dashboardWidgets = await analytics.getWidgets(dashboard.id);\n setWidgets(dashboardWidgets);\n },\n [analytics]\n );\n\n const stats: AnalyticsStats = {\n totalDashboards: dashboards.length,\n publishedDashboards: dashboards.filter((d) => d.status === 'PUBLISHED')\n .length,\n totalQueries: queries.length,\n sharedQueries: queries.filter((q) => q.isShared).length,\n };\n\n return {\n dashboards,\n queries,\n selectedDashboard,\n widgets,\n loading,\n error,\n stats,\n refetch: fetchData,\n selectDashboard,\n };\n}\n"],"mappings":";;;;;;AAkBA,SAAgB,iBAAiB,YAAY,iBAAiB;CAC5D,MAAM,EAAE,aAAa,oBAAsD;CAC3E,MAAM,YAAY,SAAS;CAC3B,MAAM,CAAC,YAAY,iBAAiB,SAAsB,EAAE,CAAC;CAC7D,MAAM,CAAC,SAAS,cAAc,SAAkB,EAAE,CAAC;CACnD,MAAM,CAAC,mBAAmB,wBAAwB,SAChD,KACD;CACD,MAAM,CAAC,SAAS,cAAc,SAAmB,EAAE,CAAC;CACpD,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,OAAO,YAAY,SAAuB,KAAK;CAEtD,MAAM,YAAY,YAAY,YAAY;AACxC,MAAI;AACF,cAAW,KAAK;AAChB,YAAS,KAAK;GAEd,MAAM,CAAC,YAAY,eAAe,MAAM,QAAQ,IAAI,CAClD,UAAU,eAAe;IAAE;IAAW,OAAO;IAAK,CAAC,EACnD,UAAU,YAAY;IAAE;IAAW,OAAO;IAAK,CAAC,CACjD,CAAC;AAEF,iBAAc,WAAW,WAAW;AACpC,cAAW,YAAY,QAAQ;AAG/B,OAAI,WAAW,WAAW,SAAS,KAAK,CAAC,mBAAmB;IAC1D,MAAM,QAAQ,WAAW,WAAW;AACpC,QAAI,OAAO;AACT,0BAAqB,MAAM;AAE3B,gBADyB,MAAM,UAAU,WAAW,MAAM,GAAG,CACjC;;;WAGzB,KAAK;AACZ,YACE,eAAe,QAAQ,sBAAM,IAAI,MAAM,2BAA2B,CACnE;YACO;AACR,cAAW,MAAM;;IAElB;EAAC;EAAW;EAAW;EAAkB,CAAC;AAE7C,iBAAgB;AACd,aAAW;IACV,CAAC,UAAU,CAAC;CAEf,MAAM,kBAAkB,YACtB,OAAO,cAAyB;AAC9B,uBAAqB,UAAU;AAE/B,aADyB,MAAM,UAAU,WAAW,UAAU,GAAG,CACrC;IAE9B,CAAC,UAAU,CACZ;AAUD,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA,OAf4B;GAC5B,iBAAiB,WAAW;GAC5B,qBAAqB,WAAW,QAAQ,MAAM,EAAE,WAAW,YAAY,CACpE;GACH,cAAc,QAAQ;GACtB,eAAe,QAAQ,QAAQ,MAAM,EAAE,SAAS,CAAC;GAClD;EAUC,SAAS;EACT;EACD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"analytics.markdown.js","names":[],"sources":["../../../src/ui/renderers/analytics.markdown.ts"],"sourcesContent":["/**\n * Markdown renderers for Analytics Dashboard presentations\n */\nimport type { PresentationRenderer } from '@contractspec/lib.contracts';\n\n// Mock data for analytics rendering\nconst mockDashboards = [\n {\n id: 'dash-1',\n name: 'Sales Overview',\n slug: 'sales-overview',\n status: 'PUBLISHED',\n widgetCount: 8,\n viewCount: 1250,\n lastViewedAt: '2024-01-16T12:00:00Z',\n },\n {\n id: 'dash-2',\n name: 'User Engagement',\n slug: 'user-engagement',\n status: 'PUBLISHED',\n widgetCount: 6,\n viewCount: 890,\n lastViewedAt: '2024-01-16T10:00:00Z',\n },\n {\n id: 'dash-3',\n name: 'Product Analytics',\n slug: 'product-analytics',\n status: 'PUBLISHED',\n widgetCount: 10,\n viewCount: 560,\n lastViewedAt: '2024-01-15T14:00:00Z',\n },\n {\n id: 'dash-4',\n name: 'Finance Report',\n slug: 'finance-report',\n status: 'DRAFT',\n widgetCount: 4,\n viewCount: 0,\n lastViewedAt: null,\n },\n];\n\nconst mockWidgets = [\n {\n id: 'w-1',\n dashboardId: 'dash-1',\n name: 'Total Revenue',\n type: 'METRIC',\n value: 125000,\n change: 12.5,\n },\n {\n id: 'w-2',\n dashboardId: 'dash-1',\n name: 'Active Users',\n type: 'METRIC',\n value: 4500,\n change: 8.2,\n },\n {\n id: 'w-3',\n dashboardId: 'dash-1',\n name: 'Revenue Trend',\n type: 'LINE_CHART',\n dataPoints: 30,\n },\n {\n id: 'w-4',\n dashboardId: 'dash-1',\n name: 'Top Products',\n type: 'BAR_CHART',\n dataPoints: 10,\n },\n {\n id: 'w-5',\n dashboardId: 'dash-2',\n name: 'Daily Active Users',\n type: 'LINE_CHART',\n dataPoints: 30,\n },\n {\n id: 'w-6',\n dashboardId: 'dash-2',\n name: 'Session Duration',\n type: 'METRIC',\n value: 245,\n change: -3.1,\n },\n];\n\nconst mockQueries = [\n {\n id: 'q-1',\n name: 'Monthly Revenue',\n type: 'AGGREGATION',\n isShared: true,\n executionCount: 1500,\n },\n {\n id: 'q-2',\n name: 'User Growth',\n type: 'METRIC',\n isShared: true,\n executionCount: 890,\n },\n {\n id: 'q-3',\n name: 'Product Sales',\n type: 'SQL',\n isShared: false,\n executionCount: 340,\n },\n {\n id: 'q-4',\n name: 'Conversion Funnel',\n type: 'AGGREGATION',\n isShared: true,\n executionCount: 450,\n },\n];\n\nfunction formatNumber(value: number): string {\n if (value >= 1000000) {\n return `${(value / 1000000).toFixed(1)}M`;\n }\n if (value >= 1000) {\n return `${(value / 1000).toFixed(1)}K`;\n }\n return value.toString();\n}\n\nfunction formatChange(change: number): string {\n const icon = change >= 0 ? 'πŸ“ˆ' : 'πŸ“‰';\n const sign = change >= 0 ? '+' : '';\n return `${icon} ${sign}${change.toFixed(1)}%`;\n}\n\n/**\n * Markdown renderer for Analytics Dashboard Overview\n */\nexport const analyticsDashboardMarkdownRenderer: PresentationRenderer<{\n mimeType: string;\n body: string;\n}> = {\n target: 'markdown',\n render: async (desc) => {\n if (\n desc.source.type !== 'component' ||\n desc.source.componentKey !== 'AnalyticsDashboard'\n ) {\n throw new Error(\n 'analyticsDashboardMarkdownRenderer: not AnalyticsDashboard'\n );\n }\n\n const dashboards = mockDashboards;\n const widgets = mockWidgets;\n const queries = mockQueries;\n\n // Get the first dashboard for detailed view\n const dashboard = dashboards[0];\n if (!dashboard) {\n return {\n mimeType: 'text/markdown',\n body: '# No Dashboards\\n\\nNo dashboards available.',\n };\n }\n const dashboardWidgets = widgets.filter(\n (w) => w.dashboardId === dashboard.id\n );\n\n // Calculate stats\n const publishedDashboards = dashboards.filter(\n (d) => d.status === 'PUBLISHED'\n );\n const totalViews = dashboards.reduce((sum, d) => sum + d.viewCount, 0);\n const sharedQueries = queries.filter((q) => q.isShared);\n\n const lines: string[] = [\n `# ${dashboard.name}`,\n '',\n '> Analytics dashboard overview',\n '',\n '## Key Metrics',\n '',\n ];\n\n // Show metric widgets\n const metricWidgets = dashboardWidgets.filter((w) => w.type === 'METRIC');\n for (const widget of metricWidgets) {\n const w = widget as { name: string; value: number; change: number };\n lines.push(`### ${w.name}`);\n lines.push(`**${formatNumber(w.value)}** ${formatChange(w.change)}`);\n lines.push('');\n }\n\n lines.push('## Visualizations');\n lines.push('');\n\n // List chart widgets\n const chartWidgets = dashboardWidgets.filter((w) => w.type !== 'METRIC');\n for (const widget of chartWidgets) {\n const w = widget as { name: string; type: string; dataPoints: number };\n lines.push(\n `- **${w.name}** (${w.type.replace('_', ' ')}) - ${w.dataPoints} data points`\n );\n }\n\n lines.push('');\n lines.push('## Dashboard Stats');\n lines.push('');\n lines.push('| Metric | Value |');\n lines.push('|--------|-------|');\n lines.push(`| Total Dashboards | ${dashboards.length} |`);\n lines.push(`| Published | ${publishedDashboards.length} |`);\n lines.push(`| Total Views | ${totalViews.toLocaleString()} |`);\n lines.push(`| Shared Queries | ${sharedQueries.length} |`);\n\n return {\n mimeType: 'text/markdown',\n body: lines.join('\\n'),\n };\n },\n};\n\n/**\n * Markdown renderer for Dashboard List\n */\nexport const dashboardListMarkdownRenderer: PresentationRenderer<{\n mimeType: string;\n body: string;\n}> = {\n target: 'markdown',\n render: async (desc) => {\n if (\n desc.source.type !== 'component' ||\n desc.source.componentKey !== 'DashboardList'\n ) {\n throw new Error('dashboardListMarkdownRenderer: not DashboardList');\n }\n\n const dashboards = mockDashboards;\n\n const lines: string[] = [\n '# Dashboards',\n '',\n '> Browse and manage analytics dashboards',\n '',\n '| Dashboard | Widgets | Views | Status | Last Viewed |',\n '|-----------|---------|-------|--------|-------------|',\n ];\n\n for (const dashboard of dashboards) {\n const lastViewed = dashboard.lastViewedAt\n ? new Date(dashboard.lastViewedAt).toLocaleDateString()\n : 'Never';\n const statusIcon = dashboard.status === 'PUBLISHED' ? '🟒' : '⚫';\n lines.push(\n `| [${dashboard.name}](/dashboards/${dashboard.slug}) | ${dashboard.widgetCount} | ${dashboard.viewCount.toLocaleString()} | ${statusIcon} ${dashboard.status} | ${lastViewed} |`\n );\n }\n\n lines.push('');\n lines.push('## Quick Actions');\n lines.push('');\n lines.push('- **Create Dashboard** - Start with a blank canvas');\n lines.push('- **Import Template** - Use a pre-built template');\n lines.push('- **Clone Dashboard** - Duplicate an existing dashboard');\n\n return {\n mimeType: 'text/markdown',\n body: lines.join('\\n'),\n };\n },\n};\n\n/**\n * Markdown renderer for Query Builder\n */\nexport const queryBuilderMarkdownRenderer: PresentationRenderer<{\n mimeType: string;\n body: string;\n}> = {\n target: 'markdown',\n render: async (desc) => {\n if (\n desc.source.type !== 'component' ||\n desc.source.componentKey !== 'QueryBuilder'\n ) {\n throw new Error('queryBuilderMarkdownRenderer: not QueryBuilder');\n }\n\n const queries = mockQueries;\n\n const lines: string[] = [\n '# Query Builder',\n '',\n '> Create and manage data queries',\n '',\n '## Saved Queries',\n '',\n '| Query | Type | Shared | Executions |',\n '|-------|------|--------|------------|',\n ];\n\n for (const query of queries) {\n const sharedIcon = query.isShared ? '🌐' : 'πŸ”’';\n lines.push(\n `| ${query.name} | ${query.type} | ${sharedIcon} | ${query.executionCount.toLocaleString()} |`\n );\n }\n\n lines.push('');\n lines.push('## Query Types');\n lines.push('');\n lines.push('### METRIC');\n lines.push('Query usage metrics from the metering system.');\n lines.push('');\n lines.push('### AGGREGATION');\n lines.push(\n 'Build aggregations with measures and dimensions without writing SQL.'\n );\n lines.push('');\n lines.push('### SQL');\n lines.push('Write custom SQL queries for advanced analysis.');\n lines.push('');\n lines.push('## Features');\n lines.push('');\n lines.push('- Visual query builder');\n lines.push('- Auto-complete for fields and functions');\n lines.push('- Query validation and optimization');\n lines.push('- Result caching');\n lines.push('- Query sharing and collaboration');\n\n return {\n mimeType: 'text/markdown',\n body: lines.join('\\n'),\n };\n },\n};\n"],"mappings":"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"}