spine-framework 0.4.4 → 0.5.0-rc.4

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 (283) hide show
  1. package/.env.example +13 -3
  2. package/.framework/cli/commands/bootstrap.ts +392 -0
  3. package/.framework/cli/commands/dev.ts +91 -218
  4. package/.framework/cli/commands/doctor.ts +132 -26
  5. package/.framework/cli/commands/generate.ts +38 -298
  6. package/.framework/cli/commands/init.ts +20 -1
  7. package/.framework/cli/commands/migrate.ts +36 -30
  8. package/.framework/cli/commands/migrations.ts +16 -56
  9. package/.framework/cli/commands/upgrade.ts +35 -0
  10. package/.framework/cli/commands/validate-schema.ts +147 -0
  11. package/.framework/cli/context.ts +223 -110
  12. package/.framework/cli/index.ts +6 -0
  13. package/.framework/cli/lib/project-files.ts +241 -1
  14. package/.framework/functions/_shared/hash-api-key.ts +183 -79
  15. package/.framework/functions/_shared/logging.ts +562 -224
  16. package/.framework/functions/_shared/middleware.ts +47 -44
  17. package/.framework/functions/admin-data.ts +39 -28
  18. package/.framework/functions/ai-agents.ts +10 -6
  19. package/.framework/functions/api-keys.ts +301 -122
  20. package/.framework/functions/apps.ts +43 -26
  21. package/.framework/functions/cil-ingest.ts +48 -15
  22. package/.framework/functions/debug-auth.ts +14 -8
  23. package/.framework/functions/deliveries.ts +39 -12
  24. package/.framework/functions/embeddings.ts +145 -76
  25. package/.framework/functions/integration-outbound.ts +67 -27
  26. package/.framework/functions/integrations.ts +254 -127
  27. package/.framework/functions/logs.ts +273 -133
  28. package/.framework/functions/observability.ts +277 -147
  29. package/.framework/functions/pipeline-executions.ts +1 -1
  30. package/.framework/functions/pipelines.ts +14 -9
  31. package/.framework/functions/prompt-configs.ts +7 -4
  32. package/.framework/functions/roles.ts +8 -5
  33. package/.framework/functions/security.ts +30 -17
  34. package/.framework/functions/system-cron.ts +240 -127
  35. package/.framework/functions/tests.ts +7 -6
  36. package/.framework/functions/timers.ts +310 -107
  37. package/.framework/functions/triggers.ts +28 -13
  38. package/.framework/functions/types.ts +13 -10
  39. package/.framework/migrations/069_log_stats_window.sql +54 -0
  40. package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
  41. package/.framework/migrations/071_timer_interval_keys.sql +96 -0
  42. package/.framework/migrations/072_slug_autofill.sql +77 -0
  43. package/.framework/migrations/073_seed_member_roles.sql +26 -0
  44. package/.framework/src/apps/admin/index.tsx +1141 -775
  45. package/.framework/src/components/ErrorBoundary.tsx +136 -0
  46. package/.framework/src/components/admin/AdminListPage.tsx +81 -73
  47. package/.framework/src/components/admin/AdminSidebar.tsx +88 -79
  48. package/.framework/src/components/admin/EntitySelect.tsx +181 -0
  49. package/.framework/src/components/admin/PageInstructions.tsx +86 -127
  50. package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
  51. package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
  52. package/.framework/src/components/layout/Sidebar.tsx +300 -177
  53. package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
  54. package/.framework/src/components/runtime/DataHeader.tsx +96 -48
  55. package/.framework/src/components/runtime/DataListPage.tsx +3 -26
  56. package/.framework/src/components/runtime/DataStats.tsx +10 -10
  57. package/.framework/src/components/runtime/DataTable.tsx +12 -10
  58. package/.framework/src/components/ui/sheet.tsx +24 -26
  59. package/.framework/src/components/ui/textarea.tsx +74 -48
  60. package/.framework/src/hooks/useEntityList.ts +12 -9
  61. package/.framework/src/hooks/useListSchema.ts +108 -58
  62. package/.framework/src/instructions/README.md +57 -0
  63. package/.framework/src/instructions/ai-agents.md +69 -0
  64. package/.framework/src/instructions/alerts.md +80 -0
  65. package/.framework/src/instructions/api-keys.md +87 -0
  66. package/.framework/src/instructions/apps.md +77 -0
  67. package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
  68. package/.framework/src/instructions/concepts/apps-and-renderers.md +162 -0
  69. package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
  70. package/.framework/src/instructions/concepts/automation.md +186 -0
  71. package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
  72. package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
  73. package/.framework/src/instructions/concepts/design-schema.md +152 -0
  74. package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
  75. package/.framework/src/instructions/concepts/observability.md +116 -0
  76. package/.framework/src/instructions/concepts/permissions.md +150 -0
  77. package/.framework/src/instructions/concepts/runtime-records.md +111 -0
  78. package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
  79. package/.framework/src/instructions/concepts/spine-way.md +172 -0
  80. package/.framework/src/instructions/deliveries.md +59 -0
  81. package/.framework/src/instructions/guide/00-orientation.md +106 -0
  82. package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
  83. package/.framework/src/instructions/guide/02-project-map.md +147 -0
  84. package/.framework/src/instructions/guide/03-domain-model.md +223 -0
  85. package/.framework/src/instructions/guide/04-first-app.md +227 -0
  86. package/.framework/src/instructions/guide/05-glossary.md +183 -0
  87. package/.framework/src/instructions/integrations.md +96 -0
  88. package/.framework/src/instructions/internal/cil-markers.md +83 -0
  89. package/.framework/src/instructions/invites.md +60 -0
  90. package/.framework/src/instructions/kb.md +80 -0
  91. package/.framework/src/instructions/logs.md +77 -0
  92. package/.framework/src/instructions/observability.md +61 -0
  93. package/.framework/src/instructions/operations/deployment.md +115 -0
  94. package/.framework/src/instructions/operations/migrations.md +125 -0
  95. package/.framework/src/instructions/operations/security-checklist.md +148 -0
  96. package/.framework/src/instructions/operations/troubleshooting.md +170 -0
  97. package/.framework/src/instructions/operations/upgrade.md +116 -0
  98. package/.framework/src/instructions/pipeline-executions.md +62 -0
  99. package/.framework/src/instructions/pipelines.md +78 -0
  100. package/.framework/src/instructions/prompts.md +95 -0
  101. package/.framework/src/instructions/reference/api/admin-data.md +162 -0
  102. package/.framework/src/instructions/reference/api/auth.md +113 -0
  103. package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
  104. package/.framework/src/instructions/reference/app-manifest.md +150 -0
  105. package/.framework/src/instructions/reference/cli.md +124 -0
  106. package/.framework/src/instructions/reference/database.md +132 -0
  107. package/.framework/src/instructions/reference/design-schema.md +280 -0
  108. package/.framework/src/instructions/reference/env-vars.md +133 -0
  109. package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
  110. package/.framework/src/instructions/reference/functions/admin-data.md +195 -0
  111. package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
  112. package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
  113. package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
  114. package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
  115. package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
  116. package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
  117. package/.framework/src/instructions/reference/functions/apps.md +140 -0
  118. package/.framework/src/instructions/reference/functions/auth.md +99 -0
  119. package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
  120. package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
  121. package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
  122. package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
  123. package/.framework/src/instructions/reference/functions/index.md +103 -0
  124. package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
  125. package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
  126. package/.framework/src/instructions/reference/functions/integrations.md +130 -0
  127. package/.framework/src/instructions/reference/functions/invites.md +182 -0
  128. package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
  129. package/.framework/src/instructions/reference/functions/kb.md +166 -0
  130. package/.framework/src/instructions/reference/functions/logs.md +141 -0
  131. package/.framework/src/instructions/reference/functions/observability.md +105 -0
  132. package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
  133. package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
  134. package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
  135. package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
  136. package/.framework/src/instructions/reference/functions/roles.md +121 -0
  137. package/.framework/src/instructions/reference/functions/security.md +140 -0
  138. package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
  139. package/.framework/src/instructions/reference/functions/system.md +106 -0
  140. package/.framework/src/instructions/reference/functions/tests.md +97 -0
  141. package/.framework/src/instructions/reference/functions/timers.md +117 -0
  142. package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
  143. package/.framework/src/instructions/reference/functions/triggers.md +140 -0
  144. package/.framework/src/instructions/reference/functions/types.md +146 -0
  145. package/.framework/src/instructions/reference/seeds.md +126 -0
  146. package/.framework/src/instructions/reference/shared-modules.md +127 -0
  147. package/.framework/src/instructions/reference/spine-config.md +114 -0
  148. package/.framework/src/instructions/roles.md +80 -0
  149. package/.framework/src/instructions/runtime-detail.md +70 -0
  150. package/.framework/src/instructions/runtime-list.md +77 -0
  151. package/.framework/src/instructions/security.md +67 -0
  152. package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
  153. package/.framework/src/instructions/tasks/add-a-role.md +96 -0
  154. package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
  155. package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
  156. package/.framework/src/instructions/tasks/add-a-type.md +151 -0
  157. package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
  158. package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
  159. package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
  160. package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
  161. package/.framework/src/instructions/tasks/package-and-install-an-app.md +127 -0
  162. package/.framework/src/instructions/tasks/test-your-code.md +108 -0
  163. package/.framework/src/instructions/tasks/write-a-function.md +132 -0
  164. package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
  165. package/.framework/src/instructions/testing.md +59 -0
  166. package/.framework/src/instructions/timers.md +82 -0
  167. package/.framework/src/instructions/triggers.md +69 -0
  168. package/.framework/src/instructions/types.md +93 -0
  169. package/.framework/src/pages/NotFoundPage.tsx +62 -31
  170. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
  171. package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
  172. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
  173. package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
  174. package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
  175. package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
  176. package/.framework/src/pages/admin/AppsPage.tsx +104 -66
  177. package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
  178. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
  179. package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
  180. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
  181. package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
  182. package/.framework/src/pages/admin/LogsPage.tsx +144 -76
  183. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
  184. package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
  185. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
  186. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
  187. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
  188. package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
  189. package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
  190. package/.framework/src/pages/admin/RolesPage.tsx +86 -43
  191. package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
  192. package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
  193. package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
  194. package/.framework/src/pages/admin/TimersPage.tsx +90 -62
  195. package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
  196. package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
  197. package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
  198. package/.framework/src/pages/admin/TypesPage.tsx +90 -48
  199. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
  200. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
  201. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
  202. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
  203. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
  204. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
  205. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
  206. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
  207. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
  208. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
  209. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
  210. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
  211. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
  212. package/.framework/templates/agent/AGENTS.md +150 -0
  213. package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
  214. package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
  215. package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
  216. package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
  217. package/.framework/templates/agent/skills/spine-install-app/SKILL.md +72 -0
  218. package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
  219. package/.framework/templates/agent/skills/spine-new-app/SKILL.md +67 -0
  220. package/.framework/templates/agent/skills/spine-new-function/SKILL.md +65 -0
  221. package/.framework/templates/agent/skills/spine-new-type/SKILL.md +65 -0
  222. package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
  223. package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
  224. package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
  225. package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
  226. package/.framework/templates/project.json +4 -1
  227. package/.framework/tests/unit/account-scoping-gates.test.ts +392 -0
  228. package/.framework/tests/unit/agent-files.test.ts +355 -0
  229. package/.framework/tests/unit/agent-runner.test.ts +479 -44
  230. package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
  231. package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
  232. package/.framework/tests/unit/bootstrap.test.ts +242 -0
  233. package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
  234. package/.framework/tests/unit/debug-auth.test.ts +38 -0
  235. package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
  236. package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
  237. package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
  238. package/.framework/tests/unit/logging-app-id.test.ts +75 -0
  239. package/.framework/tests/unit/system-context-denial.test.ts +145 -0
  240. package/.framework/tests/unit/system-cron.test.ts +240 -0
  241. package/.framework/tests/unit/timers.test.ts +159 -0
  242. package/README.md +125 -166
  243. package/config/tsconfig.cli.json +2 -2
  244. package/package.json +15 -4
  245. package/templates/project/package-lock.json +2 -2
  246. package/.framework/docs/admin-routes.md +0 -76
  247. package/.framework/docs/api-docs-progress.md +0 -38
  248. package/.framework/docs/api-governance.md +0 -146
  249. package/.framework/docs/api-testing-results.md +0 -212
  250. package/.framework/docs/assembly-launch-guide.md +0 -138
  251. package/.framework/docs/audit-results.md +0 -590
  252. package/.framework/docs/db-api-inventory.md +0 -95
  253. package/.framework/docs/gap-remediation-backlog.md +0 -103
  254. package/.framework/docs/ui-adoption-verification.md +0 -111
  255. package/.framework/docs/ui-api-coverage.md +0 -84
  256. package/.framework/docs/v2-compatibility-audit.md +0 -228
  257. package/.framework/mcp/index.ts +0 -133
  258. package/.framework/mcp/load-env.ts +0 -60
  259. package/.framework/mcp/shared/app-manifest.ts +0 -275
  260. package/.framework/mcp/shared/db.ts +0 -477
  261. package/.framework/mcp/shared/kb.ts +0 -118
  262. package/.framework/mcp/tools/architect.ts +0 -431
  263. package/.framework/mcp/tools/cil/context.ts +0 -345
  264. package/.framework/mcp/tools/cil/graph.ts +0 -242
  265. package/.framework/mcp/tools/cil/ingest.ts +0 -1217
  266. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
  267. package/.framework/mcp/tools/cil/pipeline.ts +0 -767
  268. package/.framework/mcp/tools/cil/project.ts +0 -791
  269. package/.framework/mcp/tools/cil/retrieval.ts +0 -336
  270. package/.framework/mcp/tools/cil/search-core.ts +0 -454
  271. package/.framework/mcp/tools/cil/search.ts +0 -97
  272. package/.framework/mcp/tools/cil/suggest.ts +0 -186
  273. package/.framework/mcp/tools/cil/validate.ts +0 -1369
  274. package/.framework/mcp/tools/kb/delete.ts +0 -139
  275. package/.framework/mcp/tools/kb/index.ts +0 -52
  276. package/.framework/mcp/tools/kb/ingest.ts +0 -84
  277. package/.framework/mcp/tools/kb/list-types.ts +0 -102
  278. package/.framework/mcp/tools/kb/publish.ts +0 -100
  279. package/.framework/mcp/tools/kb/reindex.ts +0 -86
  280. package/.framework/mcp/tools/kb/revoke.ts +0 -85
  281. package/.framework/mcp/tools/kb/search.ts +0 -101
  282. package/.framework/mcp/tools/kb/upsert.ts +0 -125
  283. package/.framework/mcp/tools/observability.ts +0 -510
@@ -1,4 +1,20 @@
1
1
  // CIL[BEGIN stable_id="~/.framework/functions/api-keys.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/functions/api-keys.ts"]
2
+ /**
3
+ * @module api-keys
4
+ * @audience both
5
+ * @layer shared-core
6
+ * @stability stable
7
+ *
8
+ * This module manages API key operations, including creation and validation, as part of the system's security framework. It serves as a middleware handler that interacts with the database and performs necessary logging and permission checks. INVARIANT: All API key operations require system admin privileges. Route patterns include /api/keys for key management operations.
9
+ *
10
+ * @seeAlso middleware.ts (provides request handling functionality).
11
+ * @seeAlso db.ts (interacts with the database for key storage).
12
+ * @seeAlso audit.ts (handles logging of operations).
13
+ * @seeAlso permissions.ts (ensures proper access control).
14
+ *
15
+ * @cil-generated
16
+ */
17
+
2
18
 
3
19
 
4
20
 
@@ -29,39 +45,65 @@
29
45
 
30
46
 
31
47
 
32
- // CIL[DOC-AUDIENCE audience="function-developers,system-integrators"]
33
- // CIL[DOC-MACRO purpose="Netlify function module for API key lifecycle management"]
34
- // CIL[DOC-RESPONSIBILITY responsibility="Import shared middleware, DB, audit, principal, permissions and hash helpers"]
35
- // CIL[DOC-CONTEXT module="api-keys" layer="netlify-functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/hash-api-key.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts"]
36
- // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
37
- // CIL[DOC-MICRO logic_summary="Sets up imports used by list/get/create/validate/revoke/usage-logs handlers" notable_decisions="Uses shared middleware and principal checks"]
38
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
39
- // CIL[DOC-STABILITY stable]
48
+
49
+
50
+
51
+
52
+
53
+
54
+
55
+
40
56
  import { createHandler } from './_shared/middleware'
41
57
  import { adminDb } from './_shared/db'
42
58
  import { emitLog } from './_shared/audit'
43
59
  import { isSystemAdmin } from './_shared/principal'
44
60
  import { sanitizeRecordData } from './_shared/permissions'
45
- import { hashApiKey } from './_shared/hash-api-key'
46
- // CIL[DOC-VECTOR type="context" content="purpose='Netlify function module for API key lifecycle management'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
47
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
48
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
49
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
50
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
51
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
61
+ import { hashApiKey, omitSecretFields } from './_shared/hash-api-key'
62
+ import { resolveAppUuid } from './_shared/logging'
52
63
  // CIL[END stable_id="~/.framework/functions/api-keys.ts:module_header:module_header"]
64
+
65
+
66
+ // True only for platform-level principals: a system_admin role or an
67
+ // internal machine principal with no account binding (SYSTEM_PRINCIPAL,
68
+ // produced only by the INTERNAL_INVOKE_SECRET path). Machine principals
69
+ // resolve to the service-role adminDb via getPrincipalDb, so account-bound
70
+ // API keys must be scoped to their own account below.
71
+ // CIL[BEGIN stable_id="~/.framework/functions/api-keys.ts:isSystemPrincipal:function" type="function" identity="isSystemPrincipal" parent="~/.framework/functions/api-keys.ts"]
72
+ function isSystemPrincipal(ctx: any): boolean {
73
+ return isSystemAdmin(ctx.principal) || (ctx.principal?.isInternal === true && !ctx.accountId)
74
+ }
75
+ // CIL[END stable_id="~/.framework/functions/api-keys.ts:isSystemPrincipal:function"]
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+
53
91
  // CIL[BEGIN stable_id="~/.framework/functions/api-keys.ts:list:constant" type="constant" identity="list" parent="~/.framework/functions/api-keys.ts"]
54
- // CIL[DOC-MACRO purpose="List API keys for an account with optional filters"]
55
- // CIL[DOC-RESPONSIBILITY responsibility="Query api_keys table, apply filters, sanitize results, and return paginated list"]
56
- // CIL[DOC-CONTEXT module="api-keys" layer="netlify-functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/hash-api-key.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/api-keys.ts"]
57
- // CIL[DOC-CONTRACT inputs="integration_id,key_type,is_active,expires_before,expires_after,limit,offset via ctx.query" outputs="Array of sanitized api_key records" errors="Account context required; DB query errors" side_effects="none"]
58
- // CIL[DOC-MICRO logic_summary="Builds a Supabase query with filters and range, then sanitizes each record" notable_decisions="Uses isSystemAdmin to choose adminDb vs ctx.db"]
59
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
60
- // CIL[DOC-STABILITY stable]
92
+ /**
93
+ * This function retrieves a list of API keys based on various query parameters and returns sanitized records. It ensures that only authorized users can access the data and applies filters based on the provided criteria.
94
+ *
95
+ * @throws Error — Account context required.
96
+ * @sideEffects none
97
+ * @stability internal
98
+ * @calls adminDb.from('api_keys'), ctx.db.from('api_keys'), sanitizeRecordData
99
+ * @cil-generated
100
+ */
61
101
  export const list = createHandler(async (ctx, _body) => {
62
102
  const { integration_id, key_type, is_active, expires_before, expires_after, limit = 100, offset = 0 } = ctx.query || {}
63
103
 
64
- if (!ctx.accountId) {
104
+ const isSystem = isSystemPrincipal(ctx)
105
+
106
+ if (!isSystem && !ctx.accountId) {
65
107
  throw new Error('Account context required')
66
108
  }
67
109
 
@@ -72,6 +114,12 @@ export const list = createHandler(async (ctx, _body) => {
72
114
  .select('*')
73
115
  .order('created_at', { ascending: false })
74
116
 
117
+ // Machine principals run on the service-role client — pin them to their
118
+ // own account so they cannot enumerate other tenants' keys.
119
+ if (!isSystem) {
120
+ query = query.eq('account_id', ctx.accountId)
121
+ }
122
+
75
123
  if (integration_id) {
76
124
  query = query.eq('integration_id', integration_id)
77
125
  }
@@ -97,26 +145,37 @@ export const list = createHandler(async (ctx, _body) => {
97
145
 
98
146
  const sanitized = []
99
147
  for (const key of data || []) {
100
- sanitized.push(await sanitizeRecordData(ctx, key, 'api_key'))
148
+ sanitized.push(omitSecretFields(await sanitizeRecordData(ctx, key, 'api_key')))
101
149
  }
102
150
 
103
151
  return sanitized
104
152
  })
105
- // CIL[DOC-VECTOR type="context" content="purpose='List API keys for an account with optional filters'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
106
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
107
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
108
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
109
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
110
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
111
153
  // CIL[END stable_id="~/.framework/functions/api-keys.ts:list:constant"]
154
+
155
+
156
+
157
+
158
+
159
+
160
+
161
+
162
+
163
+
164
+
165
+
166
+
167
+
168
+
112
169
  // CIL[BEGIN stable_id="~/.framework/functions/api-keys.ts:get:constant" type="constant" identity="get" parent="~/.framework/functions/api-keys.ts"]
113
- // CIL[DOC-MACRO purpose="Fetch a single API key by ID"]
114
- // CIL[DOC-RESPONSIBILITY responsibility="Retrieve one api_keys row by id and sanitize it"]
115
- // CIL[DOC-CONTEXT module="api-keys" layer="netlify-functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/hash-api-key.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/api-keys.ts"]
116
- // CIL[DOC-CONTRACT inputs="id via ctx.query" outputs="Sanitized api_key record" errors="API key ID is required; DB errors" side_effects="none"]
117
- // CIL[DOC-MICRO logic_summary="Queries by id with .single(), then sanitizes" notable_decisions="Reuses principal/adminDb selection"]
118
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
119
- // CIL[DOC-STABILITY stable]
170
+ /**
171
+ * Retrieves an API key from the database based on the provided ID in the query parameters. It ensures that the caller has the necessary permissions and sanitizes the returned data before sending it back.
172
+ *
173
+ * @throws Error — API key ID is required, Error — if there is an error fetching the API key.
174
+ * @sideEffects none
175
+ * @stability internal
176
+ * @calls adminDb.from('api_keys'), ctx.db.from('api_keys'), sanitizeRecordData
177
+ * @cil-generated
178
+ */
120
179
  export const get = createHandler(async (ctx, _body) => {
121
180
  const { id } = ctx.query || {}
122
181
 
@@ -126,31 +185,50 @@ export const get = createHandler(async (ctx, _body) => {
126
185
 
127
186
  const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
128
187
 
129
- const { data, error: err } = await db
188
+ let query = db
130
189
  .from('api_keys')
131
190
  .select('*')
132
191
  .eq('id', id)
133
- .single()
192
+
193
+ if (!isSystemPrincipal(ctx)) {
194
+ if (!ctx.accountId) {
195
+ throw new Error('Account context required')
196
+ }
197
+ query = query.eq('account_id', ctx.accountId)
198
+ }
199
+
200
+ const { data, error: err } = await query.single()
134
201
 
135
202
  if (err) throw err
136
203
 
137
- return await sanitizeRecordData(ctx, data, 'api_key')
204
+ return omitSecretFields(await sanitizeRecordData(ctx, data, 'api_key'))
138
205
  })
139
- // CIL[DOC-VECTOR type="context" content="purpose='Fetch a single API key by ID'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
140
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
141
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
142
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
143
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
144
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
145
206
  // CIL[END stable_id="~/.framework/functions/api-keys.ts:get:constant"]
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+
218
+
219
+
220
+
221
+
146
222
  // CIL[BEGIN stable_id="~/.framework/functions/api-keys.ts:create:constant" type="constant" identity="create" parent="~/.framework/functions/api-keys.ts"]
147
- // CIL[DOC-MACRO purpose="Create a new API key"]
148
- // CIL[DOC-RESPONSIBILITY responsibility="Validate input, generate key hash, insert record, emit audit log, and return the raw key once"]
149
- // CIL[DOC-CONTEXT module="api-keys" layer="netlify-functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/hash-api-key.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/api-keys.ts"]
150
- // CIL[DOC-CONTRACT inputs="integration_id,app_id,name,key_type,permissions,scopes,rate_limit,expires_at,metadata,machine_type,is_internal via body" outputs="Created api_key record plus raw_key and warning" errors="name is required; Account context required; DB insert errors" side_effects="Inserts into api_keys; emits api_key.created audit log"]
151
- // CIL[DOC-MICRO logic_summary="Generates slug and raw key, hashes it, inserts data, logs, and returns a one-time raw key" notable_decisions="Hashes the raw key before storage; returns raw key only on creation"]
152
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
153
- // CIL[DOC-STABILITY stable]
223
+ /**
224
+ * Creates a new API key for a specified integration and application, ensuring required fields are validated and generating a unique key. This function is essential for managing access to the API securely.
225
+ *
226
+ * @throws Error — name is required, Error — Account context required, Error — database error
227
+ * @sideEffects Writes a new record to the 'api_keys' table in the database and emits a log event.
228
+ * @stability internal
229
+ * @calls ctx.db.from('api_keys'), emitLog, resolveAppUuid
230
+ * @cil-generated
231
+ */
154
232
  export const create = createHandler(async (ctx, body) => {
155
233
  const {
156
234
  integration_id,
@@ -174,6 +252,35 @@ export const create = createHandler(async (ctx, body) => {
174
252
  throw new Error('Account context required')
175
253
  }
176
254
 
255
+ // S-011: scopes and is_internal are privilege-bearing fields. A machine
256
+ // caller runs on the service-role client, so accepting them verbatim let
257
+ // any scoped key mint a *:* or is_internal key and escalate itself past
258
+ // the isInternal gates elsewhere. Only system principals may request a
259
+ // wildcard scope or an internal key — for everyone else those are hard
260
+ // denials, other requested scopes are clipped to the scopes the caller
261
+ // itself holds, and an omitted scopes list inherits the caller's own.
262
+ const isSystem = isSystemPrincipal(ctx)
263
+ let effectiveScopes: string[] = scopes || []
264
+ let effectiveIsInternal = is_internal || false
265
+
266
+ if (!isSystem) {
267
+ if (is_internal) {
268
+ const e: any = new Error('Insufficient permissions to create an internal API key')
269
+ e.statusCode = 403
270
+ throw e
271
+ }
272
+ if (Array.isArray(scopes) && scopes.includes('*:*')) {
273
+ const e: any = new Error('Insufficient permissions to create a wildcard-scoped API key')
274
+ e.statusCode = 403
275
+ throw e
276
+ }
277
+ const callerScopes = Array.isArray(ctx.principal?.scopes) ? ctx.principal.scopes : []
278
+ effectiveScopes = Array.isArray(scopes)
279
+ ? scopes.filter((s: string) => callerScopes.includes(s))
280
+ : callerScopes
281
+ effectiveIsInternal = false
282
+ }
283
+
177
284
  const slug = body.slug || name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '')
178
285
 
179
286
  const rawKey = `sk_${crypto.randomUUID().replace(/-/g, '')}`
@@ -181,7 +288,7 @@ export const create = createHandler(async (ctx, body) => {
181
288
 
182
289
  const insertData = {
183
290
  integration_id: integration_id || null,
184
- app_id: app_id || ctx.appId || null,
291
+ app_id: (await resolveAppUuid(app_id || ctx.appId)) || null,
185
292
  account_id: ctx.accountId,
186
293
  slug,
187
294
  name,
@@ -189,14 +296,14 @@ export const create = createHandler(async (ctx, body) => {
189
296
  key_hash,
190
297
  key_type: key_type || 'inbound',
191
298
  permissions: permissions || [],
192
- scopes: scopes || [],
299
+ scopes: effectiveScopes,
193
300
  rate_limit: rate_limit || 100,
194
301
  expires_at: expires_at || null,
195
302
  metadata: metadata || {},
196
303
  machine_type: machine_type || 'integration',
197
- is_internal: is_internal || false,
304
+ is_internal: effectiveIsInternal,
198
305
  is_active: true,
199
- created_by: ctx.principal?.id || null
306
+ created_by: ctx.principal?.type === 'human' ? ctx.principal.id : null
200
307
  }
201
308
 
202
309
  const { data, error: err } = await ctx.db
@@ -218,21 +325,32 @@ export const create = createHandler(async (ctx, body) => {
218
325
  warning: 'Store this key now. It will not be shown again.'
219
326
  }
220
327
  })
221
- // CIL[DOC-VECTOR type="context" content="purpose='Create a new API key'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
222
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
223
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
224
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
225
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
226
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
227
328
  // CIL[END stable_id="~/.framework/functions/api-keys.ts:create:constant"]
329
+
330
+
331
+
332
+
333
+
334
+
335
+
336
+
337
+
338
+
339
+
340
+
341
+
342
+
343
+
228
344
  // CIL[BEGIN stable_id="~/.framework/functions/api-keys.ts:validate:constant" type="constant" identity="validate" parent="~/.framework/functions/api-keys.ts"]
229
- // CIL[DOC-MACRO purpose="Validate an API key value and optional permissions"]
230
- // CIL[DOC-RESPONSIBILITY responsibility="Look up active keys by prefix, verify hash, check permissions, and return validity and identity"]
231
- // CIL[DOC-CONTEXT module="api-keys" layer="netlify-functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/hash-api-key.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/api-keys.ts"]
232
- // CIL[DOC-CONTRACT inputs="key_value,required_permissions via body" outputs="{ is_valid, api_key_id, integration_id, app_id, account_id, scopes, permissions } or { is_valid, error }" errors="key_value is required; DB errors" side_effects="none"]
233
- // CIL[DOC-MICRO logic_summary="Searches active or unexpired keys matching prefix, verifies hash against key_hash, and checks required permissions" notable_decisions="Dynamically imports verifyApiKey; returns first matched key"]
234
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
235
- // CIL[DOC-STABILITY stable]
345
+ /**
346
+ * Validates an API key by checking its existence and permissions in the database. This function ensures that only active keys with the required permissions can be used.
347
+ *
348
+ * @throws Error — key_value is required, Error — database error
349
+ * @sideEffects Database read operations.
350
+ * @stability internal
351
+ * @calls ctx.db.from('api_keys'), import('./_shared/hash-api-key')
352
+ * @cil-generated
353
+ */
236
354
  export const validate = createHandler(async (ctx, body) => {
237
355
  const { key_value, required_permissions } = body
238
356
 
@@ -240,15 +358,29 @@ export const validate = createHandler(async (ctx, body) => {
240
358
  throw new Error('key_value is required')
241
359
  }
242
360
 
361
+ const isSystem = isSystemPrincipal(ctx)
362
+ if (!isSystem && !ctx.accountId) {
363
+ throw new Error('Account context required')
364
+ }
365
+
243
366
  const keyPrefix = key_value.slice(0, 8)
244
367
 
245
- const { data: rows, error: err } = await ctx.db
368
+ let query = ctx.db
246
369
  .from('api_keys')
247
370
  .select('*')
248
371
  .eq('key_prefix', keyPrefix)
249
372
  .eq('is_active', true)
250
373
  .or('expires_at.is.null,expires_at.gte.now()')
251
374
 
375
+ // Scoped callers may only validate keys belonging to their own account —
376
+ // ctx.db is service-role for machine principals, so without this filter a
377
+ // caller could probe another account's key material.
378
+ if (!isSystem) {
379
+ query = query.eq('account_id', ctx.accountId)
380
+ }
381
+
382
+ const { data: rows, error: err } = await query
383
+
252
384
  if (err) throw err
253
385
  if (!rows || rows.length === 0) {
254
386
  return { is_valid: false, error: 'Invalid or inactive API key' }
@@ -283,21 +415,32 @@ export const validate = createHandler(async (ctx, body) => {
283
415
 
284
416
  return { is_valid: false, error: 'Invalid or inactive API key' }
285
417
  })
286
- // CIL[DOC-VECTOR type="context" content="purpose='Validate an API key value and optional permissions'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
287
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
288
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
289
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
290
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
291
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
292
418
  // CIL[END stable_id="~/.framework/functions/api-keys.ts:validate:constant"]
419
+
420
+
421
+
422
+
423
+
424
+
425
+
426
+
427
+
428
+
429
+
430
+
431
+
432
+
433
+
293
434
  // CIL[BEGIN stable_id="~/.framework/functions/api-keys.ts:revoke:constant" type="constant" identity="revoke" parent="~/.framework/functions/api-keys.ts"]
294
- // CIL[DOC-MACRO purpose="Deactivate an API key by ID"]
295
- // CIL[DOC-RESPONSIBILITY responsibility="Update is_active to false and emit an audit log"]
296
- // CIL[DOC-CONTEXT module="api-keys" layer="netlify-functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/hash-api-key.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/api-keys.ts"]
297
- // CIL[DOC-CONTRACT inputs="id via body" outputs="Updated api_key record" errors="API key ID is required; DB update errors" side_effects="Sets is_active=false on api_keys row; emits api_key.revoked audit log"]
298
- // CIL[DOC-MICRO logic_summary="Updates the row with is_active false and current timestamp, then logs" notable_decisions="Performs soft revocation via is_active flag"]
299
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
300
- // CIL[DOC-STABILITY stable]
435
+ /**
436
+ * The 'revoke' constant defines a handler for deactivating an API key by its ID. It ensures that the API key ID is provided and logs the revocation action.
437
+ *
438
+ * @throws Error — if the API key ID is missing or if a database error occurs.
439
+ * @sideEffects Updates the 'api_keys' table in the database and emits a log event.
440
+ * @stability internal
441
+ * @calls ctx.db.from('api_keys'), emitLog
442
+ * @cil-generated
443
+ */
301
444
  export const revoke = createHandler(async (ctx, body) => {
302
445
  const { id } = body
303
446
 
@@ -305,12 +448,19 @@ export const revoke = createHandler(async (ctx, body) => {
305
448
  throw new Error('API key ID is required')
306
449
  }
307
450
 
308
- const { data, error: err } = await ctx.db
451
+ let query = ctx.db
309
452
  .from('api_keys')
310
453
  .update({ is_active: false, updated_at: new Date().toISOString() })
311
454
  .eq('id', id)
312
- .select()
313
- .single()
455
+
456
+ if (!isSystemPrincipal(ctx)) {
457
+ if (!ctx.accountId) {
458
+ throw new Error('Account context required')
459
+ }
460
+ query = query.eq('account_id', ctx.accountId)
461
+ }
462
+
463
+ const { data, error: err } = await query.select().single()
314
464
 
315
465
  if (err) throw err
316
466
 
@@ -319,27 +469,41 @@ export const revoke = createHandler(async (ctx, body) => {
319
469
  { after: { revoked_by: ctx.principal?.id } }
320
470
  )
321
471
 
322
- return data
472
+ return omitSecretFields(data)
323
473
  })
324
- // CIL[DOC-VECTOR type="context" content="purpose='Deactivate an API key by ID'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
325
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
326
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
327
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
328
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
329
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
330
474
  // CIL[END stable_id="~/.framework/functions/api-keys.ts:revoke:constant"]
475
+
476
+
477
+
478
+
479
+
480
+
481
+
482
+
483
+
484
+
485
+
486
+
487
+
488
+
489
+
331
490
  // CIL[BEGIN stable_id="~/.framework/functions/api-keys.ts:listUsageLogs:constant" type="constant" identity="listUsageLogs" parent="~/.framework/functions/api-keys.ts"]
332
- // CIL[DOC-MACRO purpose="List API key usage logs with filters"]
333
- // CIL[DOC-RESPONSIBILITY responsibility="Query api_key_usage_logs, join api_keys, apply filters, and return paginated results"]
334
- // CIL[DOC-CONTEXT module="api-keys" layer="netlify-functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/hash-api-key.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/api-keys.ts"]
335
- // CIL[DOC-CONTRACT inputs="api_key_id,response_status,success,date_from,date_to,limit,offset via ctx.query" outputs="Array of usage log records with api_key details" errors="Account context required; DB query errors" side_effects="none"]
336
- // CIL[DOC-MICRO logic_summary="Builds a Supabase query with filters and range over usage logs" notable_decisions="Joins api_keys in select; normalizes success to boolean"]
337
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
338
- // CIL[DOC-STABILITY stable]
491
+ /**
492
+ * The listUsageLogs constant defines an asynchronous handler for retrieving API key usage logs based on various query parameters. It ensures that the account context is valid and constructs a query to fetch logs from the database.
493
+ *
494
+ * @throws Error — Account context required.
495
+ * @sideEffects none
496
+ * @stability internal
497
+ * @calls ctx.db.from('api_key_usage_logs'), ctx.db.select, ctx.db.eq, ctx.db.gte, ctx.db.lte, ctx.db.range
498
+ * @errorHandling none
499
+ * @cil-generated
500
+ */
339
501
  export const listUsageLogs = createHandler(async (ctx, _body) => {
340
502
  const { api_key_id, response_status, success, date_from, date_to, limit = 100, offset = 0 } = ctx.query || {}
341
503
 
342
- if (!ctx.accountId) {
504
+ const isSystem = isSystemPrincipal(ctx)
505
+
506
+ if (!isSystem && !ctx.accountId) {
343
507
  throw new Error('Account context required')
344
508
  }
345
509
 
@@ -351,6 +515,10 @@ export const listUsageLogs = createHandler(async (ctx, _body) => {
351
515
  `)
352
516
  .order('created_at', { ascending: false })
353
517
 
518
+ if (!isSystem) {
519
+ query = query.eq('account_id', ctx.accountId)
520
+ }
521
+
354
522
  if (api_key_id) {
355
523
  query = query.eq('api_key_id', api_key_id)
356
524
  }
@@ -376,21 +544,32 @@ export const listUsageLogs = createHandler(async (ctx, _body) => {
376
544
 
377
545
  return data
378
546
  })
379
- // CIL[DOC-VECTOR type="context" content="purpose='List API key usage logs with filters'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
380
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
381
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
382
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
383
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
384
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
385
547
  // CIL[END stable_id="~/.framework/functions/api-keys.ts:listUsageLogs:constant"]
548
+
549
+
550
+
551
+
552
+
553
+
554
+
555
+
556
+
557
+
558
+
559
+
560
+
561
+
562
+
386
563
  // CIL[BEGIN stable_id="~/.framework/functions/api-keys.ts:handler:constant" type="constant" identity="handler" parent="~/.framework/functions/api-keys.ts"]
387
- // CIL[DOC-MACRO purpose="Route incoming Netlify function requests to the appropriate action"]
388
- // CIL[DOC-RESPONSIBILITY responsibility="Dispatch GET/POST actions to list, get, create, validate, revoke, or listUsageLogs"]
389
- // CIL[DOC-CONTEXT module="api-keys" layer="netlify-functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/hash-api-key.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/api-keys.ts"]
390
- // CIL[DOC-CONTRACT inputs="action,method,id via ctx.query; body" outputs="Result from delegated handler or error" errors="Invalid action or method" side_effects="Calls delegated handlers"]
391
- // CIL[DOC-MICRO logic_summary="Switch on action and HTTP method to call the correct sub-handler" notable_decisions="Default GET lists or gets; POST creates; validate/revoke/usage-logs are explicit"]
392
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
393
- // CIL[DOC-STABILITY stable]
564
+ /**
565
+ * The handler processes API requests based on the action and method specified in the query parameters. It routes the request to the appropriate function for validation, revocation, usage logs, or general data handling.
566
+ *
567
+ * @throws Error — Invalid action or method
568
+ * @sideEffects none
569
+ * @stability internal
570
+ * @calls validate, revoke, listUsageLogs, get, list, create
571
+ * @cil-generated
572
+ */
394
573
  export const handler = createHandler(async (ctx, body) => {
395
574
  const { action } = ctx.query || {}
396
575
  const method = ctx.query?.method || 'GET'
@@ -425,10 +604,10 @@ export const handler = createHandler(async (ctx, body) => {
425
604
 
426
605
  throw new Error('Invalid action or method')
427
606
  })
428
- // CIL[DOC-VECTOR type="context" content="purpose='Route incoming Netlify function requests to the appropriate action'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
429
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
430
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
431
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
432
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
433
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
434
- // CIL[END stable_id="~/.framework/functions/api-keys.ts:handler:constant"]
607
+ // CIL[END stable_id="~/.framework/functions/api-keys.ts:handler:constant"]
608
+
609
+
610
+
611
+
612
+
613
+