spine-framework 0.3.124 → 0.3.126
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.
- package/.framework/cli/commands/agents.ts +35 -37
- package/.framework/cli/commands/auth.ts +35 -34
- package/.framework/cli/commands/create-app.ts +104 -40
- package/.framework/cli/commands/dev.ts +104 -69
- package/.framework/cli/commands/doctor.ts +179 -69
- package/.framework/cli/commands/generate.ts +83 -143
- package/.framework/cli/commands/init.ts +72 -34
- package/.framework/cli/commands/install-app.ts +260 -125
- package/.framework/cli/commands/items.ts +33 -44
- package/.framework/cli/commands/migrate.ts +122 -40
- package/.framework/cli/commands/migrations.ts +33 -40
- package/.framework/cli/commands/pipelines.ts +31 -39
- package/.framework/cli/commands/status.ts +47 -23
- package/.framework/cli/commands/system.ts +47 -37
- package/.framework/cli/commands/test.ts +112 -68
- package/.framework/cli/commands/validate-app.ts +215 -121
- package/.framework/cli/context.ts +112 -130
- package/.framework/cli/env-loader.ts +47 -18
- package/.framework/cli/index.ts +81 -42
- package/.framework/docs/runtime-types.md +1024 -0
- package/.framework/functions/_shared/agent-runner.ts +1296 -961
- package/.framework/functions/_shared/app-manifest.ts +82 -68
- package/.framework/functions/_shared/audit.ts +135 -83
- package/.framework/functions/_shared/{cil-state.ts → cil.ts} +158 -56
- package/.framework/functions/_shared/db.ts +80 -126
- package/.framework/functions/_shared/hash-api-key.ts +63 -0
- package/.framework/functions/_shared/index.ts +224 -335
- package/.framework/functions/_shared/kb.ts +319 -0
- package/.framework/functions/_shared/llm.ts +92 -0
- package/.framework/functions/_shared/logging.ts +288 -0
- package/.framework/functions/_shared/middleware.ts +329 -365
- package/.framework/functions/_shared/outcomes.ts +36 -0
- package/.framework/functions/_shared/permissions.ts +359 -643
- package/.framework/functions/_shared/pipeline-runner.ts +243 -316
- package/.framework/functions/_shared/principal.ts +376 -468
- package/.framework/functions/_shared/resolve-credentials.ts +102 -0
- package/.framework/functions/_shared/resolve-ids.ts +188 -16
- package/.framework/functions/_shared/retry-deliveries.ts +104 -0
- package/.framework/functions/_shared/schema-utils.ts +611 -373
- package/.framework/functions/_shared/testing.ts +207 -137
- package/.framework/functions/_shared/tracing.ts +276 -0
- package/.framework/functions/_shared/trigger-engine.ts +159 -211
- package/.framework/functions/_shared/webhook-registration.ts +95 -81
- package/.framework/functions/_shared/webhook-registry.ts +153 -75
- package/.framework/functions/account-nodes.ts +31 -53
- package/.framework/functions/adapters/generic-webhook-inbound.ts +56 -0
- package/.framework/functions/adapters/generic-webhook-outbound.ts +43 -0
- package/.framework/functions/adapters/openai-outbound.ts +40 -0
- package/.framework/functions/admin-data.ts +685 -537
- package/.framework/functions/admin-funnel.ts +31 -20
- package/.framework/functions/admin-install-funnel.ts +47 -28
- package/.framework/functions/admin-signals.ts +47 -29
- package/.framework/functions/ai-agents.ts +122 -147
- package/.framework/functions/ai-interactions.ts +180 -90
- package/.framework/functions/api-keys.ts +250 -192
- package/.framework/functions/apps.ts +203 -197
- package/.framework/functions/auth.ts +98 -91
- package/.framework/functions/cil-agent-ingest.ts +773 -0
- package/.framework/functions/cil-agent.ts +592 -0
- package/.framework/functions/cil-callmap.ts +1227 -0
- package/.framework/functions/cil-config.ts +583 -0
- package/.framework/functions/cil-context.ts +445 -0
- package/.framework/functions/cil-doc.ts +1752 -0
- package/.framework/functions/cil-embeddings.ts +1202 -0
- package/.framework/functions/cil-graph.ts +585 -0
- package/.framework/functions/cil-ingest.ts +2416 -0
- package/.framework/functions/cil-pipeline.ts +318 -0
- package/.framework/functions/cil-project.ts +499 -0
- package/.framework/functions/cil-validate.ts +469 -0
- package/.framework/functions/debug-auth.ts +73 -53
- package/.framework/functions/deliveries.ts +117 -0
- package/.framework/functions/embeddings.ts +528 -516
- package/.framework/functions/eval-harness.ts +158 -106
- package/.framework/functions/integration-outbound.ts +311 -0
- package/.framework/functions/integration-routes.ts +240 -466
- package/.framework/functions/integrations.ts +132 -140
- package/.framework/functions/invites.ts +401 -201
- package/.framework/functions/item-progress.ts +113 -53
- package/.framework/functions/kb.ts +28 -0
- package/.framework/functions/logs.ts +239 -222
- package/.framework/functions/observability.ts +308 -259
- package/.framework/functions/pipeline-executions.ts +179 -235
- package/.framework/functions/pipelines.ts +163 -205
- package/.framework/functions/prompt-configs.ts +109 -156
- package/.framework/functions/roles.ts +97 -147
- package/.framework/functions/system-cron.ts +132 -218
- package/.framework/functions/system.ts +112 -52
- package/.framework/functions/tests.ts +32 -28
- package/.framework/functions/timers.ts +162 -210
- package/.framework/functions/triggers.ts +282 -346
- package/.framework/functions/types.ts +283 -400
- package/.framework/migrations/001_core_schema.sql +630 -0
- package/.framework/migrations/002_core_rls_and_functions.sql +532 -0
- package/.framework/migrations/{003_system_data.sql → 003_core_system_data.sql} +26 -153
- package/.framework/migrations/004_core_rpc_and_broker.sql +421 -0
- package/.framework/migrations/005_core_observability.sql +598 -0
- package/.framework/migrations/006_security_hardening_rls.sql +97 -0
- package/.framework/migrations/007_kb_article_list.sql +237 -0
- package/.framework/migrations/008_items_target.sql +8 -0
- package/.framework/migrations/009_roles_slug_unique.sql +11 -0
- package/.framework/public/spine.config.json +91 -0
- package/.framework/scripts/app-install-cli.ts +112 -98
- package/.framework/src/App.tsx +67 -20
- package/.framework/src/apps/admin/index.tsx +97 -27
- package/.framework/src/components/AppWrapper.tsx +50 -11
- package/.framework/src/components/CustomAppLoader.tsx +131 -22
- package/.framework/src/components/admin/AdminListPage.tsx +75 -8
- package/.framework/src/components/admin/AdminSidebar.tsx +148 -36
- package/.framework/src/components/admin/AdminStatsCard.tsx +48 -29
- package/.framework/src/components/admin/PageInstructions.tsx +49 -0
- package/.framework/src/components/admin/SortableTableHeader.tsx +49 -2
- package/.framework/src/components/app-shell/GenericAppShell.tsx +69 -11
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +55 -10
- package/.framework/src/components/app-shell/GenericListPage.tsx +76 -9
- package/.framework/src/components/app-sidebar.tsx +50 -3
- package/.framework/src/components/auth/ProtectedRoute.tsx +53 -45
- package/.framework/src/components/kb/KBArticleEditor.tsx +409 -0
- package/.framework/src/components/kb/KBArticleList.tsx +557 -0
- package/.framework/src/components/layout/AppShell.tsx +54 -16
- package/.framework/src/components/layout/Header.tsx +50 -38
- package/.framework/src/components/layout/Layout.tsx +48 -32
- package/.framework/src/components/layout/Sidebar.tsx +167 -16
- package/.framework/src/components/runtime/DataDetailHeader.tsx +33 -1
- package/.framework/src/components/runtime/DataDetailPage.tsx +289 -4
- package/.framework/src/components/runtime/DataFilters.tsx +78 -1
- package/.framework/src/components/runtime/DataHeader.tsx +32 -29
- package/.framework/src/components/runtime/DataListPage.tsx +161 -2
- package/.framework/src/components/runtime/DataStats.tsx +48 -1
- package/.framework/src/components/runtime/DataTable.tsx +153 -1
- package/.framework/src/components/runtime/SchemaDetailForm.tsx +77 -46
- package/.framework/src/components/runtime/index.ts +16 -9
- package/.framework/src/components/search-form.tsx +33 -1
- package/.framework/src/components/shared/AgentView.tsx +48 -51
- package/.framework/src/components/shared/FieldRenderer.tsx +84 -67
- package/.framework/src/components/shared/InviteManager.tsx +113 -52
- package/.framework/src/components/shared/MemberList.tsx +182 -0
- package/.framework/src/components/shared/SchemaFields.tsx +96 -78
- package/.framework/src/components/ui/DataTable.tsx +86 -56
- package/.framework/src/components/ui/Form.tsx +188 -109
- package/.framework/src/components/ui/ItemCard.tsx +86 -58
- package/.framework/src/components/ui/ItemListView.tsx +88 -61
- package/.framework/src/components/ui/LoadingSpinner.tsx +52 -27
- package/.framework/src/components/ui/Modal.tsx +81 -4
- package/.framework/src/components/ui/RichTextEditor.tsx +101 -9
- package/.framework/src/components/ui/accordion.tsx +97 -5
- package/.framework/src/components/ui/alert-dialog.tsx +225 -13
- package/.framework/src/components/ui/alert.tsx +113 -6
- package/.framework/src/components/ui/aspect-ratio.tsx +49 -2
- package/.framework/src/components/ui/avatar.tsx +129 -7
- package/.framework/src/components/ui/badge.tsx +65 -3
- package/.framework/src/components/ui/breadcrumb.tsx +145 -8
- package/.framework/src/components/ui/button-group.tsx +81 -4
- package/.framework/src/components/ui/button.tsx +49 -2
- package/.framework/src/components/ui/calendar.tsx +65 -3
- package/.framework/src/components/ui/card.tsx +145 -8
- package/.framework/src/components/ui/carousel.tsx +129 -7
- package/.framework/src/components/ui/chart.tsx +161 -10
- package/.framework/src/components/ui/checkbox.tsx +49 -2
- package/.framework/src/components/ui/collapsible.tsx +81 -5
- package/.framework/src/components/ui/combobox.tsx +305 -20
- package/.framework/src/components/ui/command.tsx +177 -11
- package/.framework/src/components/ui/context-menu.tsx +273 -17
- package/.framework/src/components/ui/dialog.tsx +209 -27
- package/.framework/src/components/ui/direction.tsx +64 -4
- package/.framework/src/components/ui/drawer.tsx +193 -12
- package/.framework/src/components/ui/dropdown-menu.tsx +273 -18
- package/.framework/src/components/ui/empty.tsx +145 -9
- package/.framework/src/components/ui/field.tsx +209 -14
- package/.framework/src/components/ui/hover-card.tsx +81 -4
- package/.framework/src/components/ui/input-group.tsx +162 -10
- package/.framework/src/components/ui/input-otp.tsx +98 -5
- package/.framework/src/components/ui/input.tsx +49 -2
- package/.framework/src/components/ui/item.tsx +225 -13
- package/.framework/src/components/ui/kbd.tsx +65 -3
- package/.framework/src/components/ui/label.tsx +49 -2
- package/.framework/src/components/ui/menubar.tsx +289 -17
- package/.framework/src/components/ui/native-select.tsx +97 -5
- package/.framework/src/components/ui/navigation-menu.tsx +177 -10
- package/.framework/src/components/ui/pagination.tsx +161 -9
- package/.framework/src/components/ui/popover.tsx +145 -8
- package/.framework/src/components/ui/progress.tsx +49 -2
- package/.framework/src/components/ui/radio-group.tsx +65 -3
- package/.framework/src/components/ui/resizable.tsx +82 -4
- package/.framework/src/components/ui/scroll-area.tsx +65 -3
- package/.framework/src/components/ui/select.tsx +193 -11
- package/.framework/src/components/ui/separator.tsx +49 -2
- package/.framework/src/components/ui/sheet.tsx +193 -11
- package/.framework/src/components/ui/sidebar.tsx +481 -38
- package/.framework/src/components/ui/skeleton.tsx +49 -2
- package/.framework/src/components/ui/slider.tsx +49 -2
- package/.framework/src/components/ui/sonner.tsx +49 -2
- package/.framework/src/components/ui/spinner.tsx +49 -2
- package/.framework/src/components/ui/switch.tsx +49 -2
- package/.framework/src/components/ui/table-primitives.tsx +160 -33
- package/.framework/src/components/ui/table.tsx +161 -9
- package/.framework/src/components/ui/tabs.tsx +113 -6
- package/.framework/src/components/ui/textarea.tsx +49 -2
- package/.framework/src/components/ui/toggle-group.tsx +81 -4
- package/.framework/src/components/ui/toggle.tsx +65 -3
- package/.framework/src/components/ui/tooltip.tsx +97 -5
- package/.framework/src/contexts/AppContext.tsx +129 -45
- package/.framework/src/contexts/AuthContext.tsx +187 -144
- package/.framework/src/hooks/use-mobile.ts +48 -2
- package/.framework/src/hooks/useApi.ts +208 -159
- package/.framework/src/hooks/useAppPath.ts +32 -23
- package/.framework/src/hooks/useApps.ts +51 -20
- package/.framework/src/hooks/useEntityList.ts +32 -78
- package/.framework/src/hooks/useEntityRecord.ts +35 -96
- package/.framework/src/hooks/useForm.ts +32 -92
- package/.framework/src/hooks/useListSchema.ts +49 -78
- package/.framework/src/hooks/useSchemaRecord.ts +114 -105
- package/.framework/src/lib/api.ts +195 -116
- package/.framework/src/lib/supabase.ts +98 -64
- package/.framework/src/lib/utils.ts +287 -151
- package/.framework/src/main.tsx +49 -3
- package/.framework/src/pages/DashboardPage.tsx +52 -29
- package/.framework/src/pages/NotFoundPage.tsx +32 -10
- package/.framework/src/pages/SetupPage.tsx +32 -12
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +119 -10
- package/.framework/src/pages/admin/AIAgentsPage.tsx +48 -19
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +187 -17
- package/.framework/src/pages/admin/APIKeysPage.tsx +98 -22
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +113 -26
- package/.framework/src/pages/admin/AppDetailPage.tsx +125 -8
- package/.framework/src/pages/admin/AppsPage.tsx +49 -2
- package/.framework/src/pages/admin/DeliveriesPage.tsx +196 -0
- package/.framework/src/pages/admin/DesignedPage.tsx +32 -18
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +215 -484
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +116 -319
- package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -16
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +183 -26
- package/.framework/src/pages/admin/IntegrationsPage.tsx +48 -19
- package/.framework/src/pages/admin/InvitesPage.tsx +48 -14
- package/.framework/src/pages/admin/LogsPage.tsx +422 -75
- package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +113 -24
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +206 -34
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +50 -17
- package/.framework/src/pages/admin/PipelinesPage.tsx +160 -21
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +378 -88
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +125 -16
- package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +49 -10
- package/.framework/src/pages/admin/RoleDetailPage.tsx +130 -10
- package/.framework/src/pages/admin/RolesPage.tsx +171 -18
- package/.framework/src/pages/admin/SelectTestPage.tsx +34 -9
- package/.framework/src/pages/admin/ShadcnTestPage.tsx +49 -11
- package/.framework/src/pages/admin/SimpleDashboard.tsx +49 -10
- package/.framework/src/pages/admin/TestRunDetailPage.tsx +49 -4
- package/.framework/src/pages/admin/TestingDashboard.tsx +98 -28
- package/.framework/src/pages/admin/TimerDetailPage.tsx +143 -33
- package/.framework/src/pages/admin/TimersPage.tsx +48 -20
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +118 -30
- package/.framework/src/pages/admin/TriggersPage.tsx +64 -19
- package/.framework/src/pages/admin/TypeDetailPage.tsx +138 -15
- package/.framework/src/pages/admin/TypesPage.tsx +48 -20
- package/.framework/src/pages/admin/cil/CILAgentPage.tsx +465 -0
- package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +787 -0
- package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +699 -0
- package/.framework/src/pages/admin/cil/CILFileListPage.tsx +647 -0
- package/.framework/src/pages/admin/cil/CILGraphPage.tsx +616 -0
- package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +1402 -0
- package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +614 -0
- package/.framework/src/pages/admin/cil/CILSearchPage.tsx +571 -0
- package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +731 -0
- package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
- package/.framework/src/pages/auth/AuthConfirmPage.tsx +52 -51
- package/.framework/src/pages/auth/ForgotPasswordPage.tsx +31 -22
- package/.framework/src/pages/auth/LoginPage.tsx +50 -23
- package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -15
- package/.framework/src/pages/auth/RegisterPage.tsx +281 -317
- package/.framework/src/pages/spine-framework/APIPage.tsx +33 -0
- package/.framework/src/pages/spine-framework/CLIPage.tsx +33 -0
- package/.framework/src/types/auth.ts +128 -71
- package/.framework/src/types/types.ts +373 -157
- package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +39 -0
- package/custom/.devin/skills/spine-workbench-idea/SKILL.md +36 -0
- package/custom/.devin/skills/spine-workbench-implement/SKILL.md +46 -0
- package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +28 -0
- package/custom/.devin/skills/spine-workbench-plan/SKILL.md +38 -0
- package/docs/README.md +9 -130
- package/netlify.toml +5 -2
- package/package.json +13 -25
- package/scripts/kb-ingest-docs.ts +203 -0
- package/spine.config.json +65 -4
- package/.framework/migrations/001_schema.sql +0 -425
- package/.framework/migrations/002_rls_and_functions.sql +0 -763
- package/.framework/migrations/004_enhancements.sql +0 -43
- package/.framework/migrations/005_auth_user_trigger.sql +0 -105
- package/.framework/migrations/006_fix_current_actor_id.sql +0 -21
- package/.framework/migrations/016_invites.sql +0 -27
- package/.framework/migrations/017_fix_get_account_apps.sql +0 -78
- package/.framework/migrations/018_apps_required_roles.sql +0 -17
- package/.framework/migrations/019_triggers_unique_constraint.sql +0 -13
- package/.framework/migrations/020_get_account_apps_role_filter.sql +0 -117
- package/.framework/migrations/021_app_domains.sql +0 -112
- package/.framework/migrations/022_route_prefix_domain_unique.sql +0 -21
- package/.framework/migrations/023_match_embeddings_rpc.sql +0 -78
- package/.framework/migrations/024_messages_account_id.sql +0 -9
- package/.framework/migrations/025_retype_threads_messages.sql +0 -240
- package/.framework/migrations/026_fix_rls_policies.sql +0 -47
- package/.framework/migrations/027_embedding_lifecycle.sql +0 -176
- package/.framework/migrations/028_fix_message_data_permissions.sql +0 -49
- package/.framework/migrations/029_tighten_support_triage_prompt.sql +0 -41
- package/.framework/migrations/030_messages_updated_by.sql +0 -6
- package/.framework/migrations/031_seed_upsert_constraints.sql +0 -35
- package/docs/APPS.md +0 -232
- package/docs/ARCHITECTURE.md +0 -246
- package/docs/INSTALL.md +0 -155
- package/docs/design-schema-spec.md +0 -1837
- package/docs/dev-guides/01-create-an-app.md +0 -183
- package/docs/dev-guides/02-create-a-function.md +0 -178
- package/docs/dev-guides/03-create-a-component.md +0 -178
- package/docs/dev-guides/04-webhook-handlers.md +0 -129
- package/docs/dev-guides/05-testing.md +0 -168
- package/docs/dev-guides/README.md +0 -40
- package/docs/npm-packages-plan.md +0 -288
- package/docs/spine-core--api-reference.md +0 -822
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module src/pages/admin/AIAgentsPage
|
|
3
|
-
* @audience installer
|
|
4
|
-
* @layer frontend-page
|
|
5
|
-
* @stability stable
|
|
6
|
-
*
|
|
7
|
-
* Admin list page for AI agents. Fetches all agents via
|
|
8
|
-
* `/api/ai-agents?action=list`, applies client-side search, agent-type
|
|
9
|
-
* filter (`chat` | `analysis` | `automation` | `custom`), and sort.
|
|
10
|
-
* Renders inside `AdminListPage` with stat cards and a sortable table.
|
|
11
|
-
* Row clicks navigate to `/spine-framework/admin/configs/ai-agents/:id`.
|
|
12
|
-
*
|
|
13
|
-
* @seeAlso src/pages/admin/AIAgentDetailPage.tsx
|
|
14
|
-
*/
|
|
15
1
|
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
// CIL[BEGIN chunk_id="aiagentspage_module_header_1783668265" type="module_header" identity="module_header" parent="none"]
|
|
5
|
+
// CIL[DOC-MACRO purpose="Import dependencies for AIAgentsPage component"]
|
|
6
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Import React hooks, UI components, and utilities"]
|
|
7
|
+
// CIL[DOC-CONTEXT module="AIAgentsPage" layer="presentation" related_files="[\".framework/src/components/layout/Sidebar.tsx\",\".framework/src/components/ui/dialog.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"\\\"]"]
|
|
8
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Imported modules" errors="none" side_effects="none"]
|
|
9
|
+
// CIL[DOC-MICRO logic_summary="Imports React state management, routing, API hooks, UI components" notable_decisions="[]"]
|
|
10
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
11
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
12
|
+
// CIL[DOC-AUDIENCE audience="developer"]
|
|
13
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/src/components/layout/Sidebar.tsx, .framework/src/components/ui/dialog.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, \."]
|
|
14
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
15
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
16
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
17
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
18
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
16
19
|
import { useState } from 'react'
|
|
17
20
|
import { useNavigate } from 'react-router-dom'
|
|
18
21
|
import { Cpu, CheckCircle, Clock } from 'lucide-react';
|
|
@@ -22,7 +25,21 @@ import { apiFetch } from '../../lib/api'
|
|
|
22
25
|
import { AdminListPage } from '../../components/admin/AdminListPage'
|
|
23
26
|
import { SortableTableHeader } from '../../components/admin/SortableTableHeader'
|
|
24
27
|
import { Badge } from '../../components/ui/badge'
|
|
25
|
-
|
|
28
|
+
// CIL[END chunk_id="aiagentspage_module_header_1783668265"]
|
|
29
|
+
// CIL[BEGIN chunk_id="aiagentspage_interface_aiagent_1783668265" type="interface" identity="AIAgent" parent="none"]
|
|
30
|
+
// CIL[DOC-MACRO purpose="Define AIAgent data structure"]
|
|
31
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Type definition for AI agent objects"]
|
|
32
|
+
// CIL[DOC-CONTEXT module="AIAgentsPage" layer="types" related_files="[\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\".framework/functions/_shared/principal.ts\",\".framework/src/components/layout/Sidebar.tsx\",\"\\\"]"]
|
|
33
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="AIAgent interface type" errors="none" side_effects="none"]
|
|
34
|
+
// CIL[DOC-MICRO logic_summary="Defines complete AI agent structure with model config and metadata" notable_decisions="[]"]
|
|
35
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
36
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
37
|
+
// CIL[DOC-VECTOR type="context" content="Layer: types. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/schema-utils.ts, .framework/functions/_shared/principal.ts, .framework/src/components/layout/Sidebar.tsx, \."]
|
|
38
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
39
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
40
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
41
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
42
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
26
43
|
interface AIAgent {
|
|
27
44
|
id: string
|
|
28
45
|
name: string
|
|
@@ -45,7 +62,21 @@ interface AIAgent {
|
|
|
45
62
|
app_id?: string
|
|
46
63
|
metadata?: Record<string, any>
|
|
47
64
|
}
|
|
48
|
-
|
|
65
|
+
// CIL[END chunk_id="aiagentspage_interface_aiagent_1783668265"]
|
|
66
|
+
// CIL[BEGIN chunk_id="aiagentspage_function_aiagentspage_1783668265" type="function" identity="AIAgentsPage" parent="none"]
|
|
67
|
+
// CIL[DOC-MACRO purpose="Main AIAgentsPage component implementation"]
|
|
68
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Render AI agent management interface with filtering, sorting, and stats"]
|
|
69
|
+
// CIL[DOC-CONTEXT module="AIAgentsPage" layer="presentation" related_files="[\".framework/src/components/ui/dialog.tsx\",\".framework/src/components/layout/Sidebar.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
|
|
70
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="React component" errors="API failures" side_effects="Navigation, API calls"]
|
|
71
|
+
// CIL[DOC-MICRO logic_summary="Manages state, fetches AI agents, handles filtering/sorting, renders table" notable_decisions="[]"]
|
|
72
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
73
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
74
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/src/components/ui/dialog.tsx, .framework/src/components/layout/Sidebar.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/RolesPage.tsx, \."]
|
|
75
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
76
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
77
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
78
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
79
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
49
80
|
export function AIAgentsPage() {
|
|
50
81
|
const navigate = useNavigate()
|
|
51
82
|
|
|
@@ -56,7 +87,6 @@ export function AIAgentsPage() {
|
|
|
56
87
|
const [sortKey, setSortKey] = useState('name')
|
|
57
88
|
const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc')
|
|
58
89
|
|
|
59
|
-
// Fetch AI agents from API
|
|
60
90
|
const { data: agents, loading } = useApi<AIAgent[]>(
|
|
61
91
|
async (params) => {
|
|
62
92
|
const response = await apiFetch('/api/ai-agents?action=list', { signal: params?.signal })
|
|
@@ -103,7 +133,6 @@ export function AIAgentsPage() {
|
|
|
103
133
|
console.log('AIAgentsPage - agents:', agents)
|
|
104
134
|
console.log('AIAgentsPage - filteredAgents:', filteredAgents)
|
|
105
135
|
|
|
106
|
-
// Helper functions
|
|
107
136
|
const getAgentBadgeColor = (agentType: string) => {
|
|
108
137
|
switch (agentType) {
|
|
109
138
|
case 'chat':
|
|
@@ -136,7 +165,6 @@ export function AIAgentsPage() {
|
|
|
136
165
|
navigate(`/spine-framework/admin/configs/ai-agents/${agent.id}`)
|
|
137
166
|
}
|
|
138
167
|
|
|
139
|
-
// Sort agents
|
|
140
168
|
const sortedAgents = [...(filteredAgents || [])].sort((a, b) => {
|
|
141
169
|
let aValue: any = a[sortKey as keyof AIAgent]
|
|
142
170
|
let bValue: any = b[sortKey as keyof AIAgent]
|
|
@@ -316,3 +344,4 @@ export function AIAgentsPage() {
|
|
|
316
344
|
</AdminListPage>
|
|
317
345
|
)
|
|
318
346
|
}
|
|
347
|
+
// CIL[END chunk_id="aiagentspage_function_aiagentspage_1783668265"]
|
|
@@ -1,6 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
// CIL[BEGIN chunk_id="apikeydetailpage_module_header_1783668265" type="module_header" identity="module_header" parent="none"]
|
|
6
|
+
// CIL[DOC-MACRO purpose="Import dependencies for APIKeyDetailPage component"]
|
|
7
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Import React hooks, routing, and UI components"]
|
|
8
|
+
// CIL[DOC-CONTEXT module="APIKeyDetailPage" layer="presentation" related_files="[\".framework/src/components/ui/dialog.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
|
|
9
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Imported modules" errors="none" side_effects="none"]
|
|
10
|
+
// CIL[DOC-MICRO logic_summary="Imports React state management, routing, UI components, and utilities" notable_decisions="[]"]
|
|
11
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
12
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
13
|
+
// CIL[DOC-AUDIENCE audience="developer"]
|
|
14
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/src/components/ui/dialog.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/RolesPage.tsx, \."]
|
|
15
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
16
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
17
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
18
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
19
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
4
20
|
import { useState, useEffect } from 'react'
|
|
5
21
|
import { useParams, useNavigate } from 'react-router-dom'
|
|
6
22
|
import { Button } from '../../components/ui/button'
|
|
@@ -16,31 +32,80 @@ import { ArrowLeft, Key, RefreshCw, Trash2, AlertCircle, Copy, Check } from 'luc
|
|
|
16
32
|
import { useApi } from '../../hooks/useApi'
|
|
17
33
|
import { apiFetch } from '../../lib/api'
|
|
18
34
|
import { formatDateTime } from '../../lib/utils'
|
|
19
|
-
|
|
35
|
+
import { PageInstructions } from '../../components/admin/PageInstructions'
|
|
36
|
+
// CIL[END chunk_id="apikeydetailpage_module_header_1783668265"]
|
|
37
|
+
// CIL[BEGIN chunk_id="apikeydetailpage_interface_apikey_1783668265" type="interface" identity="APIKey" parent="none"]
|
|
38
|
+
// CIL[DOC-MACRO purpose="Define APIKey data structure"]
|
|
39
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Type definition for API key objects"]
|
|
40
|
+
// CIL[DOC-CONTEXT module="APIKeyDetailPage" layer="types" related_files="[\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"\\\"]"]
|
|
41
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="APIKey interface type" errors="none" side_effects="none"]
|
|
42
|
+
// CIL[DOC-MICRO logic_summary="Defines complete API key structure with permissions and metadata" notable_decisions="[]"]
|
|
43
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
44
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
45
|
+
// CIL[DOC-VECTOR type="context" content="Layer: types. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/schema-utils.ts, .framework/functions/_shared/principal.ts, custom/apps/cortex/functions/custom_cil-embeddings.ts, \."]
|
|
46
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
47
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
48
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
49
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
50
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
20
51
|
interface APIKey {
|
|
21
52
|
id: string
|
|
22
53
|
name: string
|
|
23
|
-
|
|
54
|
+
integration_id?: string
|
|
55
|
+
app_id?: string
|
|
56
|
+
key_type: 'inbound' | 'outbound' | 'internal' | 'cli'
|
|
24
57
|
key_value?: string
|
|
25
58
|
key_prefix: string
|
|
26
59
|
is_active: boolean
|
|
27
60
|
permissions?: Record<string, any>
|
|
61
|
+
scopes?: string[]
|
|
28
62
|
rate_limit: number
|
|
29
63
|
expires_at?: string
|
|
30
64
|
last_used_at?: string
|
|
31
65
|
usage_count: number
|
|
32
|
-
|
|
66
|
+
machine_type?: string
|
|
67
|
+
is_internal?: boolean
|
|
33
68
|
metadata?: Record<string, any>
|
|
34
69
|
created_by_person?: { id: string; full_name: string; email: string }
|
|
35
70
|
created_at: string
|
|
36
71
|
updated_at: string
|
|
37
72
|
}
|
|
38
|
-
|
|
73
|
+
// CIL[END chunk_id="apikeydetailpage_interface_apikey_1783668265"]
|
|
74
|
+
// CIL[BEGIN chunk_id="apikeydetailpage_constant_key_type_options_1783668265" type="constant" identity="KEY_TYPE_OPTIONS" parent="none"]
|
|
75
|
+
// CIL[DOC-MACRO purpose="Define API key type options"]
|
|
76
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Configure available key type choices"]
|
|
77
|
+
// CIL[DOC-CONTEXT module="APIKeyDetailPage" layer="constants" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/migrations/025_retype_threads_messages.sql\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\".framework/functions/_shared/principal.ts\",\"\\\"]"]
|
|
78
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Key type options" errors="none" side_effects="none"]
|
|
79
|
+
// CIL[DOC-MICRO logic_summary="Defines private and public key type options with descriptions" notable_decisions="[]"]
|
|
80
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
81
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
82
|
+
// CIL[DOC-VECTOR type="context" content="Layer: constants. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, .framework/migrations/025_retype_threads_messages.sql, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/schema-utils.ts, .framework/functions/_shared/principal.ts, \."]
|
|
83
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
84
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
85
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
86
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
87
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
39
88
|
const KEY_TYPE_OPTIONS = [
|
|
40
|
-
{ value: '
|
|
41
|
-
{ value: '
|
|
89
|
+
{ value: 'inbound', label: 'Inbound (External callers to Spine)' },
|
|
90
|
+
{ value: 'outbound', label: 'Outbound (Spine to external services)' },
|
|
91
|
+
{ value: 'internal', label: 'Internal (Spine-to-Spine)' },
|
|
92
|
+
{ value: 'cli', label: 'CLI / Script' }
|
|
42
93
|
]
|
|
43
|
-
|
|
94
|
+
// CIL[END chunk_id="apikeydetailpage_constant_key_type_options_1783668265"]
|
|
95
|
+
// CIL[BEGIN chunk_id="apikeydetailpage_function_apikeydetailpage_1783668265" type="function" identity="APIKeyDetailPage" parent="none"]
|
|
96
|
+
// CIL[DOC-MACRO purpose="Main APIKeyDetailPage component implementation"]
|
|
97
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Render API key detail view with create/edit functionality"]
|
|
98
|
+
// CIL[DOC-CONTEXT module="APIKeyDetailPage" layer="presentation" related_files="[\".framework/src/components/ui/dialog.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
|
|
99
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="React component" errors="API failures" side_effects="Navigation, API calls"]
|
|
100
|
+
// CIL[DOC-MICRO logic_summary="Manages CRUD operations for API keys with form validation and key generation" notable_decisions="[]"]
|
|
101
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
102
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
103
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/src/components/ui/dialog.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/RolesPage.tsx, \."]
|
|
104
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
105
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
106
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
107
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
108
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
44
109
|
export function APIKeyDetailPage() {
|
|
45
110
|
const { id } = useParams<{ id: string }>()
|
|
46
111
|
const navigate = useNavigate()
|
|
@@ -48,13 +113,17 @@ export function APIKeyDetailPage() {
|
|
|
48
113
|
|
|
49
114
|
const [formData, setFormData] = useState({
|
|
50
115
|
name: '',
|
|
51
|
-
|
|
116
|
+
integration_id: '',
|
|
117
|
+
app_id: '',
|
|
118
|
+
key_type: 'inbound' as 'inbound' | 'outbound' | 'internal' | 'cli',
|
|
52
119
|
key_prefix: 'sk_',
|
|
53
120
|
rate_limit: 1000,
|
|
54
121
|
expires_at: '',
|
|
55
|
-
integration_id: '',
|
|
56
122
|
permissions: {},
|
|
123
|
+
scopes: '[]',
|
|
57
124
|
metadata: {},
|
|
125
|
+
machine_type: 'integration',
|
|
126
|
+
is_internal: false,
|
|
58
127
|
is_active: true
|
|
59
128
|
})
|
|
60
129
|
const [permissionsJson, setPermissionsJson] = useState('{}')
|
|
@@ -79,13 +148,17 @@ export function APIKeyDetailPage() {
|
|
|
79
148
|
if (apiKey) {
|
|
80
149
|
setFormData({
|
|
81
150
|
name: apiKey.name || '',
|
|
82
|
-
|
|
151
|
+
integration_id: apiKey.integration_id || '',
|
|
152
|
+
app_id: apiKey.app_id || '',
|
|
153
|
+
key_type: apiKey.key_type || 'inbound',
|
|
83
154
|
key_prefix: apiKey.key_prefix || 'sk_',
|
|
84
155
|
rate_limit: apiKey.rate_limit || 1000,
|
|
85
156
|
expires_at: apiKey.expires_at ? apiKey.expires_at.split('T')[0] : '',
|
|
86
|
-
integration_id: apiKey.integration_id || '',
|
|
87
157
|
permissions: apiKey.permissions || {},
|
|
158
|
+
scopes: JSON.stringify(apiKey.scopes || [], null, 2),
|
|
88
159
|
metadata: apiKey.metadata || {},
|
|
160
|
+
machine_type: apiKey.machine_type || 'integration',
|
|
161
|
+
is_internal: apiKey.is_internal || false,
|
|
89
162
|
is_active: apiKey.is_active
|
|
90
163
|
})
|
|
91
164
|
setPermissionsJson(JSON.stringify(apiKey.permissions || {}, null, 2))
|
|
@@ -99,9 +172,12 @@ export function APIKeyDetailPage() {
|
|
|
99
172
|
try {
|
|
100
173
|
let permissions = {}
|
|
101
174
|
let metadata = {}
|
|
175
|
+
let scopes: string[] = []
|
|
102
176
|
try { permissions = JSON.parse(permissionsJson) } catch {}
|
|
103
177
|
try { metadata = JSON.parse(metadataJson) } catch {}
|
|
104
|
-
|
|
178
|
+
try { scopes = JSON.parse(formData.scopes) } catch {}
|
|
179
|
+
const { key_prefix: _kp, ...rest } = formData
|
|
180
|
+
const body = { ...rest, permissions, scopes, metadata }
|
|
105
181
|
const response = await apiFetch('/api/api-keys', {
|
|
106
182
|
method: 'POST',
|
|
107
183
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -144,6 +220,49 @@ export function APIKeyDetailPage() {
|
|
|
144
220
|
<Button variant="ghost" onClick={() => navigate(-1)}><ArrowLeft className="h-5 w-5" /></Button>
|
|
145
221
|
<h1 className="text-2xl font-bold">{apiKey.name}</h1>
|
|
146
222
|
</div>
|
|
223
|
+
<PageInstructions
|
|
224
|
+
description="Create an API key and set its permissions, rate limits, and expiration."
|
|
225
|
+
sections={[
|
|
226
|
+
{ title: 'What this API key controls', content: 'API keys authenticate callers to Spine. A key controls which callers are accepted, how fast they can call, and which permissions they carry.' },
|
|
227
|
+
{ title: 'Fields explained', content: <ul className="list-disc pl-4 space-y-1">
|
|
228
|
+
<li><strong>Name</strong> — string, required. A human-readable label. Missing name blocks creation.</li>
|
|
229
|
+
<li><strong>Integration ID</strong> — string. Optional UUID of the integration this key is for.</li>
|
|
230
|
+
<li><strong>App ID</strong> — string. Optional UUID of the owning app.</li>
|
|
231
|
+
<li><strong>Key Type</strong> — select. inbound, outbound, internal, or cli. Determines which direction the key is used and how it is validated.</li>
|
|
232
|
+
<li><strong>Prefix</strong> — string. The public prefix that appears before the generated secret. Default is "sk_". The create API may override this with the generated prefix.</li>
|
|
233
|
+
<li><strong>Rate Limit (requests/min)</strong> — number 1-10000. Enforces a cap on calls per minute. Missing or 0 may prevent usage.</li>
|
|
234
|
+
<li><strong>Expires At</strong> — date. Optional expiration. After this date the key is rejected.</li>
|
|
235
|
+
<li><strong>Machine Type</strong> — string. The machine principal type, e.g. integration.</li>
|
|
236
|
+
<li><strong>Internal</strong> — checkbox. Marks a key for internal service-to-service use.</li>
|
|
237
|
+
<li><strong>Active</strong> — checkbox. Inactive keys are rejected.</li>
|
|
238
|
+
<li><strong>Permissions (JSON)</strong> — JSON object. Defines allowed actions/resources. Invalid JSON fails creation.</li>
|
|
239
|
+
<li><strong>Scopes (JSON)</strong> — JSON array of scope strings. Invalid JSON fails creation.</li>
|
|
240
|
+
<li><strong>Metadata (JSON)</strong> — JSON object. Optional notes such as environment. Invalid JSON fails creation.</li>
|
|
241
|
+
</ul> },
|
|
242
|
+
{ title: 'Options and values', content: <ul className="list-disc pl-4 space-y-1">
|
|
243
|
+
<li><strong>inbound</strong>: External callers into Spine APIs.</li>
|
|
244
|
+
<li><strong>outbound</strong>: Spine calling external services.</li>
|
|
245
|
+
<li><strong>internal</strong>: Service-to-service calls within Spine.</li>
|
|
246
|
+
<li><strong>cli</strong>: Scripts or command-line tooling.</li>
|
|
247
|
+
</ul> },
|
|
248
|
+
{ title: 'Downstream impact', content: <ul className="list-disc pl-4 space-y-1">
|
|
249
|
+
<li>API gateway validates the key on every call. An inactive, expired, or missing key is rejected.</li>
|
|
250
|
+
<li>Rate limits are enforced at the edge; a misconfigured limit may throttle or deny callers.</li>
|
|
251
|
+
<li>Permission JSON is parsed and used for authorization checks. Badly shaped permissions may grant too much or too little access.</li>
|
|
252
|
+
</ul> },
|
|
253
|
+
{ title: 'How to create, save, and validate', content: <ol className="list-decimal pl-4 space-y-1">
|
|
254
|
+
<li>Only create mode is available; existing keys are shown read-only with the value masked.</li>
|
|
255
|
+
<li>Fill Name, Key Type, and Rate Limit. Provide valid JSON for Permissions and Metadata.</li>
|
|
256
|
+
<li>Submit the form. A one-time key is generated and shown; copy it immediately because it cannot be retrieved again.</li>
|
|
257
|
+
<li>Validation checks required fields, rate limit range, and valid JSON.</li>
|
|
258
|
+
</ol> },
|
|
259
|
+
{ title: 'Common mistakes', content: <ul className="list-disc pl-4 space-y-1">
|
|
260
|
+
<li>Forgetting to copy the generated key before leaving the page.</li>
|
|
261
|
+
<li>Entering Permissions as a comma-separated list instead of JSON.</li>
|
|
262
|
+
<li>Setting Rate Limit to 0, which blocks all requests.</li>
|
|
263
|
+
</ul> },
|
|
264
|
+
]}
|
|
265
|
+
/>
|
|
147
266
|
<Card><CardContent className="p-6">
|
|
148
267
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
149
268
|
<div className="flex justify-between"><span className="text-muted-foreground">Key Type</span><span>{apiKey.key_type}</span></div>
|
|
@@ -178,18 +297,68 @@ export function APIKeyDetailPage() {
|
|
|
178
297
|
<Button variant="ghost" onClick={() => navigate(-1)}><ArrowLeft className="h-5 w-5" /></Button>
|
|
179
298
|
<h1 className="text-2xl font-bold">Create API Key</h1>
|
|
180
299
|
</div>
|
|
300
|
+
<PageInstructions
|
|
301
|
+
description="Create an API key and set its permissions, rate limits, and expiration."
|
|
302
|
+
sections={[
|
|
303
|
+
{ title: 'What this API key controls', content: 'API keys authenticate callers to Spine. A key controls which callers are accepted, how fast they can call, and which permissions they carry.' },
|
|
304
|
+
{ title: 'Fields explained', content: <ul className="list-disc pl-4 space-y-1">
|
|
305
|
+
<li><strong>Name</strong> — string, required. A human-readable label. Missing name blocks creation.</li>
|
|
306
|
+
<li><strong>Integration ID</strong> — string. Optional UUID of the integration this key is for.</li>
|
|
307
|
+
<li><strong>App ID</strong> — string. Optional UUID of the owning app.</li>
|
|
308
|
+
<li><strong>Key Type</strong> — select. inbound, outbound, internal, or cli. Determines which direction the key is used and how it is validated.</li>
|
|
309
|
+
<li><strong>Prefix</strong> — string. The public prefix that appears before the generated secret. Default is "sk_". The create API may override this with the generated prefix.</li>
|
|
310
|
+
<li><strong>Rate Limit (requests/min)</strong> — number 1-10000. Enforces a cap on calls per minute. Missing or 0 may prevent usage.</li>
|
|
311
|
+
<li><strong>Expires At</strong> — date. Optional expiration. After this date the key is rejected.</li>
|
|
312
|
+
<li><strong>Machine Type</strong> — string. The machine principal type, e.g. integration.</li>
|
|
313
|
+
<li><strong>Internal</strong> — checkbox. Marks a key for internal service-to-service use.</li>
|
|
314
|
+
<li><strong>Active</strong> — checkbox. Inactive keys are rejected.</li>
|
|
315
|
+
<li><strong>Permissions (JSON)</strong> — JSON object. Defines allowed actions/resources. Invalid JSON fails creation.</li>
|
|
316
|
+
<li><strong>Scopes (JSON)</strong> — JSON array of scope strings. Invalid JSON fails creation.</li>
|
|
317
|
+
<li><strong>Metadata (JSON)</strong> — JSON object. Optional notes such as environment. Invalid JSON fails creation.</li>
|
|
318
|
+
</ul> },
|
|
319
|
+
{ title: 'Options and values', content: <ul className="list-disc pl-4 space-y-1">
|
|
320
|
+
<li><strong>inbound</strong>: External callers into Spine APIs.</li>
|
|
321
|
+
<li><strong>outbound</strong>: Spine calling external services.</li>
|
|
322
|
+
<li><strong>internal</strong>: Service-to-service calls within Spine.</li>
|
|
323
|
+
<li><strong>cli</strong>: Scripts or command-line tooling.</li>
|
|
324
|
+
</ul> },
|
|
325
|
+
{ title: 'Downstream impact', content: <ul className="list-disc pl-4 space-y-1">
|
|
326
|
+
<li>API gateway validates the key on every call. An inactive, expired, or missing key is rejected.</li>
|
|
327
|
+
<li>Rate limits are enforced at the edge; a misconfigured limit may throttle or deny callers.</li>
|
|
328
|
+
<li>Permission JSON is parsed and used for authorization checks. Badly shaped permissions may grant too much or too little access.</li>
|
|
329
|
+
</ul> },
|
|
330
|
+
{ title: 'How to create, save, and validate', content: <ol className="list-decimal pl-4 space-y-1">
|
|
331
|
+
<li>Only create mode is available; existing keys are shown read-only with the value masked.</li>
|
|
332
|
+
<li>Fill Name, Key Type, and Rate Limit. Provide valid JSON for Permissions and Metadata.</li>
|
|
333
|
+
<li>Submit the form. A one-time key is generated and shown; copy it immediately because it cannot be retrieved again.</li>
|
|
334
|
+
<li>Validation checks required fields, rate limit range, and valid JSON.</li>
|
|
335
|
+
</ol> },
|
|
336
|
+
{ title: 'Common mistakes', content: <ul className="list-disc pl-4 space-y-1">
|
|
337
|
+
<li>Forgetting to copy the generated key before leaving the page.</li>
|
|
338
|
+
<li>Entering Permissions as a comma-separated list instead of JSON.</li>
|
|
339
|
+
<li>Setting Rate Limit to 0, which blocks all requests.</li>
|
|
340
|
+
</ul> },
|
|
341
|
+
]}
|
|
342
|
+
/>
|
|
181
343
|
{error && <Alert variant="destructive"><AlertCircle className="h-4 w-4" /><AlertTitle>Error</AlertTitle><AlertDescription>{error}</AlertDescription></Alert>}
|
|
182
344
|
<form onSubmit={handleSubmit} className="space-y-6">
|
|
183
345
|
<Card><CardContent className="p-6 space-y-4">
|
|
184
346
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
185
347
|
<div className="space-y-2"><Label>Name *</Label><Input value={formData.name} onChange={e => setFormData({...formData, name: e.target.value})} required placeholder="e.g., Production API Key" /></div>
|
|
186
|
-
<div className="space-y-2"><Label>Key Type</Label><Select value={formData.key_type} onValueChange={v => setFormData({...formData, key_type: v as '
|
|
348
|
+
<div className="space-y-2"><Label>Key Type</Label><Select value={formData.key_type} onValueChange={v => setFormData({...formData, key_type: v as 'inbound' | 'outbound' | 'internal' | 'cli'})}><SelectTrigger><SelectValue /></SelectTrigger><SelectContent>{KEY_TYPE_OPTIONS.map(opt => <SelectItem key={opt.value} value={opt.value}>{opt.label}</SelectItem>)}</SelectContent></Select></div>
|
|
349
|
+
<div className="space-y-2"><Label>Integration ID</Label><Input value={formData.integration_id} onChange={e => setFormData({...formData, integration_id: e.target.value})} placeholder="Optional integration UUID" /></div>
|
|
350
|
+
<div className="space-y-2"><Label>App ID</Label><Input value={formData.app_id} onChange={e => setFormData({...formData, app_id: e.target.value})} placeholder="Optional app UUID" /></div>
|
|
187
351
|
<div className="space-y-2"><Label>Prefix</Label><Input value={formData.key_prefix} onChange={e => setFormData({...formData, key_prefix: e.target.value})} placeholder="e.g., sk_" /></div>
|
|
188
352
|
<div className="space-y-2"><Label>Rate Limit (requests/min)</Label><Input type="number" value={formData.rate_limit} onChange={e => setFormData({...formData, rate_limit: parseInt(e.target.value)})} min={1} max={10000} /></div>
|
|
189
353
|
<div className="space-y-2"><Label>Expires At</Label><Input type="date" value={formData.expires_at} onChange={e => setFormData({...formData, expires_at: e.target.value})} /></div>
|
|
354
|
+
<div className="space-y-2"><Label>Machine Type</Label><Input value={formData.machine_type} onChange={e => setFormData({...formData, machine_type: e.target.value})} placeholder="e.g., integration" /></div>
|
|
355
|
+
</div>
|
|
356
|
+
<div className="flex flex-wrap items-center gap-6">
|
|
357
|
+
<div className="flex items-center gap-2"><Checkbox id="active" checked={formData.is_active} onCheckedChange={c => setFormData({...formData, is_active: c === true})} /><Label htmlFor="active">Active</Label></div>
|
|
358
|
+
<div className="flex items-center gap-2"><Checkbox id="is_internal" checked={formData.is_internal} onCheckedChange={c => setFormData({...formData, is_internal: c === true})} /><Label htmlFor="is_internal">Internal</Label></div>
|
|
190
359
|
</div>
|
|
191
|
-
<div className="flex items-center gap-2"><Checkbox id="active" checked={formData.is_active} onCheckedChange={c => setFormData({...formData, is_active: c === true})} /><Label htmlFor="active">Active</Label></div>
|
|
192
360
|
<div className="space-y-2"><Label>Permissions (JSON)</Label><Textarea value={permissionsJson} onChange={e => setPermissionsJson(e.target.value)} rows={4} className="font-mono text-sm" placeholder='{"resources": ["read", "write"]}' /></div>
|
|
361
|
+
<div className="space-y-2"><Label>Scopes (JSON array)</Label><Textarea value={formData.scopes} onChange={e => setFormData({...formData, scopes: e.target.value})} rows={3} className="font-mono text-sm" placeholder='["read:items"]' /></div>
|
|
193
362
|
<div className="space-y-2"><Label>Metadata (JSON)</Label><Textarea value={metadataJson} onChange={e => setMetadataJson(e.target.value)} rows={3} className="font-mono text-sm" placeholder='{"env": "production"}' /></div>
|
|
194
363
|
</CardContent></Card>
|
|
195
364
|
<div className="flex justify-end gap-3"><Button type="button" variant="outline" onClick={() => navigate(-1)}>Cancel</Button><Button type="submit" disabled={isSubmitting}>{isSubmitting ? 'Creating...' : 'Create API Key'}</Button></div>
|
|
@@ -197,3 +366,4 @@ export function APIKeyDetailPage() {
|
|
|
197
366
|
</div>
|
|
198
367
|
)
|
|
199
368
|
}
|
|
369
|
+
// CIL[END chunk_id="apikeydetailpage_function_apikeydetailpage_1783668265"]
|
|
@@ -1,32 +1,51 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module src/pages/admin/APIKeysPage
|
|
3
|
-
* @audience installer
|
|
4
|
-
* @layer frontend-page
|
|
5
|
-
* @stability stable
|
|
6
|
-
*
|
|
7
|
-
* Admin list page for API keys. Fetches all keys via
|
|
8
|
-
* `/api/api-keys?action=list`, applies client-side search, type filter
|
|
9
|
-
* (`public` | `private`), and sort. Key values are never shown in the
|
|
10
|
-
* list — only the prefix. Renders inside `AdminListPage`. Row clicks
|
|
11
|
-
* navigate to `/spine-framework/admin/configs/api-keys/:id`.
|
|
12
|
-
*
|
|
13
|
-
* @seeAlso src/pages/admin/APIKeyDetailPage.tsx
|
|
14
|
-
*/
|
|
15
1
|
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
// CIL[BEGIN chunk_id="apikeyspage_module_header_1783668265" type="module_header" identity="module_header" parent="none"]
|
|
5
|
+
// CIL[DOC-MACRO purpose="Import dependencies for APIKeysPage component"]
|
|
6
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Import React hooks, UI components, and utilities"]
|
|
7
|
+
// CIL[DOC-CONTEXT module="APIKeysPage" layer="presentation" related_files="[\".framework/src/components/layout/Sidebar.tsx\",\".framework/src/components/ui/dialog.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"\\\"]"]
|
|
8
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Imported modules" errors="none" side_effects="none"]
|
|
9
|
+
// CIL[DOC-MICRO logic_summary="Imports React state management, UI components, API hooks" notable_decisions="[]"]
|
|
10
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
11
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
12
|
+
// CIL[DOC-AUDIENCE audience="developer"]
|
|
13
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/src/components/layout/Sidebar.tsx, .framework/src/components/ui/dialog.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, \."]
|
|
14
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
15
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
16
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
17
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
18
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
16
19
|
import React, { useState } from 'react'
|
|
17
20
|
import { Plus, Key, CheckCircle, Clock, ShieldCheck, RefreshCw } from 'lucide-react';
|
|
18
21
|
import { LoadingSpinner } from '../../components/ui/LoadingSpinner'
|
|
19
22
|
import { Button } from '../../components/ui/button'
|
|
20
23
|
import { AdminListPage } from '../../components/admin/AdminListPage'
|
|
21
24
|
import { SortableTableHeader } from '../../components/admin/SortableTableHeader'
|
|
25
|
+
|
|
26
|
+
import { PageInstructions } from '../../components/admin/PageInstructions'
|
|
22
27
|
import { formatDateTime } from '../../lib/utils'
|
|
23
28
|
import { useApi } from '../../hooks/useApi'
|
|
24
29
|
import { apiFetch } from '../../lib/api'
|
|
25
|
-
|
|
30
|
+
// CIL[END chunk_id="apikeyspage_module_header_1783668265"]
|
|
31
|
+
// CIL[BEGIN chunk_id="apikeyspage_interface_apikey_1783668265" type="interface" identity="APIKey" parent="none"]
|
|
32
|
+
// CIL[DOC-MACRO purpose="Define APIKey data structure"]
|
|
33
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Type definition for API key objects"]
|
|
34
|
+
// CIL[DOC-CONTEXT module="APIKeysPage" layer="types" related_files="[\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\".framework/functions/_shared/principal.ts\",\".framework/src/components/layout/Sidebar.tsx\",\"\\\"]"]
|
|
35
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="APIKey interface type" errors="none" side_effects="none"]
|
|
36
|
+
// CIL[DOC-MICRO logic_summary="Defines complete API key structure with metadata and usage" notable_decisions="[]"]
|
|
37
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
38
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
39
|
+
// CIL[DOC-VECTOR type="context" content="Layer: types. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/schema-utils.ts, .framework/functions/_shared/principal.ts, .framework/src/components/layout/Sidebar.tsx, \."]
|
|
40
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
41
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
42
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
43
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
44
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
26
45
|
interface APIKey {
|
|
27
46
|
id: string
|
|
28
47
|
name: string
|
|
29
|
-
key_type: '
|
|
48
|
+
key_type: 'inbound' | 'outbound'
|
|
30
49
|
is_active: boolean
|
|
31
50
|
last_used_at?: string
|
|
32
51
|
expires_at?: string
|
|
@@ -44,7 +63,21 @@ interface APIKey {
|
|
|
44
63
|
}
|
|
45
64
|
created_at: string
|
|
46
65
|
}
|
|
47
|
-
|
|
66
|
+
// CIL[END chunk_id="apikeyspage_interface_apikey_1783668265"]
|
|
67
|
+
// CIL[BEGIN chunk_id="apikeyspage_function_apikeyspage_1783668265" type="function" identity="APIKeysPage" parent="none"]
|
|
68
|
+
// CIL[DOC-MACRO purpose="Main APIKeysPage component implementation"]
|
|
69
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Render API key management interface with filtering, sorting, and stats"]
|
|
70
|
+
// CIL[DOC-CONTEXT module="APIKeysPage" layer="presentation" related_files="[\".framework/src/components/ui/dialog.tsx\",\".framework/src/components/layout/Sidebar.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
|
|
71
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="React component" errors="API failures" side_effects="Navigation, API calls"]
|
|
72
|
+
// CIL[DOC-MICRO logic_summary="Manages state, fetches API keys, handles filtering/sorting, renders table" notable_decisions="[]"]
|
|
73
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
74
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
75
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/src/components/ui/dialog.tsx, .framework/src/components/layout/Sidebar.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/RolesPage.tsx, \."]
|
|
76
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
77
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
78
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
79
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
80
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
48
81
|
export function APIKeysPage() {
|
|
49
82
|
const [searchTerm, setSearchTerm] = useState('')
|
|
50
83
|
const [selectedStatus, setSelectedStatus] = useState('all')
|
|
@@ -121,8 +154,8 @@ export function APIKeysPage() {
|
|
|
121
154
|
iconColor: 'text-green-500'
|
|
122
155
|
},
|
|
123
156
|
{
|
|
124
|
-
title: '
|
|
125
|
-
value: (apiKeys || []).filter(k => k.key_type === '
|
|
157
|
+
title: 'Inbound Keys',
|
|
158
|
+
value: (apiKeys || []).filter(k => k.key_type === 'inbound').length,
|
|
126
159
|
icon: ShieldCheck,
|
|
127
160
|
iconColor: 'text-purple-500'
|
|
128
161
|
},
|
|
@@ -146,8 +179,8 @@ export function APIKeysPage() {
|
|
|
146
179
|
|
|
147
180
|
const typeOptions = [
|
|
148
181
|
{ value: 'all', label: 'All Types' },
|
|
149
|
-
{ value: '
|
|
150
|
-
{ value: '
|
|
182
|
+
{ value: 'inbound', label: 'Inbound' },
|
|
183
|
+
{ value: 'outbound', label: 'Outbound' }
|
|
151
184
|
]
|
|
152
185
|
|
|
153
186
|
const filters = [
|
|
@@ -169,6 +202,7 @@ export function APIKeysPage() {
|
|
|
169
202
|
<AdminListPage
|
|
170
203
|
title="API Keys"
|
|
171
204
|
description="Manage API keys and access tokens"
|
|
205
|
+
noPageInstructions
|
|
172
206
|
newButtonText="Generate API Key"
|
|
173
207
|
newButtonHref="/spine-framework/admin/configs/api-keys/new"
|
|
174
208
|
statsCards={statsCards}
|
|
@@ -181,6 +215,47 @@ export function APIKeysPage() {
|
|
|
181
215
|
emptyMessage="No API keys found"
|
|
182
216
|
emptyIcon={Key}
|
|
183
217
|
>
|
|
218
|
+
<PageInstructions
|
|
219
|
+
title="API key usage instructions"
|
|
220
|
+
description="API keys are generated tokens that authenticate external callers or service-to-service calls. The full key is shown once after creation. Copy it immediately and store it securely."
|
|
221
|
+
sections={[
|
|
222
|
+
{ title: '1. Inbound webhooks (authenticate callers to Spine)', content: (
|
|
223
|
+
<div className="space-y-2">
|
|
224
|
+
<p className="text-sm text-slate-600">
|
|
225
|
+
Create an <code className="text-xs bg-muted px-1 rounded">inbound</code> key, optionally bound to an Integration. Send the key in the request header to <code className="text-xs bg-muted px-1 rounded">/api/integration-routes</code>:
|
|
226
|
+
</p>
|
|
227
|
+
<pre className="text-xs bg-muted p-2 rounded overflow-auto font-mono">{`X-Api-Key: sk_...`}</pre>
|
|
228
|
+
<p className="text-sm text-slate-600">
|
|
229
|
+
The Integration Broker will validate the key and route the event to the adapter defined by the integration.
|
|
230
|
+
</p>
|
|
231
|
+
</div>
|
|
232
|
+
)},
|
|
233
|
+
{ title: '2. Outbound / service calls (use a key instead of an env var)', content: (
|
|
234
|
+
<div className="space-y-2">
|
|
235
|
+
<p className="text-sm text-slate-600">
|
|
236
|
+
You can use a literal key value in an integration's <code className="text-xs bg-muted px-1 rounded">credentials</code> instead of <code className="text-xs bg-muted px-1 rounded">env_var</code>. Create a key, copy the value, and paste it into the integration's credentials JSON with <code className="text-xs bg-muted px-1 rounded">source: "value"</code>:
|
|
237
|
+
</p>
|
|
238
|
+
<pre className="text-xs bg-muted p-2 rounded overflow-auto font-mono">{JSON.stringify({ api_token: { source: 'value', value: 'sk_...' } }, null, 2)}</pre>
|
|
239
|
+
</div>
|
|
240
|
+
)},
|
|
241
|
+
{ title: '3. Key types', content: (
|
|
242
|
+
<div className="space-y-2">
|
|
243
|
+
<ul className="text-sm text-slate-600 list-disc list-inside space-y-1">
|
|
244
|
+
<li><strong>inbound</strong> — external services calling Spine (webhooks, API clients).</li>
|
|
245
|
+
<li><strong>outbound</strong> — Spine services calling another system, often linked to an integration.</li>
|
|
246
|
+
<li><strong>internal</strong> — internal Spine function-to-function calls.</li>
|
|
247
|
+
<li><strong>cli</strong> — command-line scripts and tooling.</li>
|
|
248
|
+
</ul>
|
|
249
|
+
</div>
|
|
250
|
+
)},
|
|
251
|
+
{ title: '4. Rate limits, scopes, and expiration', content: (
|
|
252
|
+
<p className="text-sm text-slate-600">
|
|
253
|
+
Use <code className="text-xs bg-muted px-1 rounded">rate_limit</code> to throttle usage, set <code className="text-xs bg-muted px-1 rounded">expires_at</code> for short-lived keys, and define <code className="text-xs bg-muted px-1 rounded">permissions</code> / <code className="text-xs bg-muted px-1 rounded">scopes</code> as JSON arrays to restrict what the key can do.
|
|
254
|
+
</p>
|
|
255
|
+
)},
|
|
256
|
+
]}
|
|
257
|
+
/>
|
|
258
|
+
|
|
184
259
|
{sortedKeys.length === 0 ? (
|
|
185
260
|
<div className="p-8 text-center">
|
|
186
261
|
<Key className="mx-auto h-12 w-12 text-slate-400" />
|
|
@@ -259,7 +334,7 @@ export function APIKeysPage() {
|
|
|
259
334
|
</td>
|
|
260
335
|
<td className="px-6 py-4 whitespace-nowrap">
|
|
261
336
|
<span className={`inline-flex px-2 py-0.5 text-xs font-medium rounded-md ${
|
|
262
|
-
key.key_type === '
|
|
337
|
+
key.key_type === 'inbound'
|
|
263
338
|
? 'bg-purple-100 text-purple-700'
|
|
264
339
|
: 'bg-blue-100 text-blue-700'
|
|
265
340
|
}`}>
|
|
@@ -301,3 +376,4 @@ export function APIKeysPage() {
|
|
|
301
376
|
</AdminListPage>
|
|
302
377
|
)
|
|
303
378
|
}
|
|
379
|
+
// CIL[END chunk_id="apikeyspage_function_apikeyspage_1783668265"]
|