@segmentstream/ontology 0.0.0-stage → 0.92.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/NOTICE +2 -0
- package/README.md +1655 -2
- package/dist/action.d.ts +193 -0
- package/dist/action.js +41 -0
- package/dist/agent-chat.d.ts +44 -0
- package/dist/agent-chat.js +91 -0
- package/dist/agent-task-contract.d.ts +64 -0
- package/dist/agent-task-contract.js +15 -0
- package/dist/agent-task.d.ts +39 -0
- package/dist/agent-task.js +112 -0
- package/dist/analyze.d.ts +215 -0
- package/dist/analyze.js +2438 -0
- package/dist/app-feedback.d.ts +167 -0
- package/dist/app-feedback.js +176 -0
- package/dist/authoring-input.d.ts +3 -0
- package/dist/authoring-input.js +107 -0
- package/dist/authoring-names.d.ts +4 -0
- package/dist/authoring-names.js +13 -0
- package/dist/authoring-records.d.ts +35 -0
- package/dist/authoring-records.js +264 -0
- package/dist/authoring.d.ts +15 -0
- package/dist/authoring.js +331 -0
- package/dist/bin/check.d.ts +30 -0
- package/dist/bin/check.js +99 -0
- package/dist/bin/load.d.ts +48 -0
- package/dist/bin/load.js +139 -0
- package/dist/bin/main.d.ts +31 -0
- package/dist/bin/main.js +121 -0
- package/dist/bin/migrate.d.ts +57 -0
- package/dist/bin/migrate.js +170 -0
- package/dist/bin/output.d.ts +31 -0
- package/dist/bin/output.js +84 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +31 -0
- package/dist/blob.d.ts +52 -0
- package/dist/blob.js +87 -0
- package/dist/channel-session.d.ts +16 -0
- package/dist/channel-session.js +16 -0
- package/dist/chat.d.ts +43 -0
- package/dist/chat.js +34 -0
- package/dist/confirmation.d.ts +46 -0
- package/dist/confirmation.js +41 -0
- package/dist/connection.d.ts +213 -0
- package/dist/connection.js +289 -0
- package/dist/deployment.d.ts +35 -0
- package/dist/deployment.js +76 -0
- package/dist/diagnostics.d.ts +27 -0
- package/dist/diagnostics.js +106 -0
- package/dist/emails.d.ts +70 -0
- package/dist/emails.js +221 -0
- package/dist/entity.d.ts +331 -0
- package/dist/entity.js +153 -0
- package/dist/errors.d.ts +154 -0
- package/dist/errors.js +109 -0
- package/dist/feedback-config.d.ts +24 -0
- package/dist/feedback-config.js +126 -0
- package/dist/files.d.ts +39 -0
- package/dist/files.js +4 -0
- package/dist/groups.d.ts +95 -0
- package/dist/groups.js +280 -0
- package/dist/index.d.ts +109 -0
- package/dist/index.js +70 -0
- package/dist/internal/diagnostics.js +594 -0
- package/dist/legacy.d.ts +160 -0
- package/dist/legacy.js +270 -0
- package/dist/manifest-compatibility.d.ts +8 -0
- package/dist/manifest-compatibility.js +87 -0
- package/dist/manifest.d.ts +3329 -0
- package/dist/manifest.js +757 -0
- package/dist/me.d.ts +46 -0
- package/dist/me.js +109 -0
- package/dist/metric-filters.d.ts +48 -0
- package/dist/metric-filters.js +252 -0
- package/dist/metric-routes.d.ts +132 -0
- package/dist/metric-routes.js +498 -0
- package/dist/metric.d.ts +172 -0
- package/dist/metric.js +132 -0
- package/dist/migrate/apply.d.ts +94 -0
- package/dist/migrate/apply.js +526 -0
- package/dist/migrate/errors.d.ts +46 -0
- package/dist/migrate/errors.js +38 -0
- package/dist/migrate/index.d.ts +10 -0
- package/dist/migrate/index.js +7 -0
- package/dist/migrate/model.d.ts +2311 -0
- package/dist/migrate/model.js +148 -0
- package/dist/migrate/plan.d.ts +51 -0
- package/dist/migrate/plan.js +1856 -0
- package/dist/migrate/preview.d.ts +13 -0
- package/dist/migrate/preview.js +65 -0
- package/dist/migrate/storage.d.ts +226 -0
- package/dist/migrate/storage.js +774 -0
- package/dist/model-metrics.d.ts +22 -0
- package/dist/model-metrics.js +545 -0
- package/dist/names.d.ts +49 -0
- package/dist/names.js +110 -0
- package/dist/navigation-artifact.d.ts +13 -0
- package/dist/navigation-artifact.js +11 -0
- package/dist/navigation-catalog.d.ts +55 -0
- package/dist/navigation-catalog.js +297 -0
- package/dist/nitro-navigation.d.ts +3 -0
- package/dist/nitro-navigation.js +64 -0
- package/dist/nitro-workflows.d.ts +108 -0
- package/dist/nitro-workflows.js +286 -0
- package/dist/nitro.d.ts +40 -0
- package/dist/nitro.js +50 -0
- package/dist/ontology.d.ts +41 -0
- package/dist/ontology.js +46 -0
- package/dist/permissions.d.ts +198 -0
- package/dist/permissions.js +272 -0
- package/dist/property.d.ts +188 -0
- package/dist/property.js +301 -0
- package/dist/query.d.ts +245 -0
- package/dist/query.js +615 -0
- package/dist/relationship.d.ts +99 -0
- package/dist/relationship.js +33 -0
- package/dist/render.d.ts +81 -0
- package/dist/render.js +512 -0
- package/dist/replication/baseline.d.ts +51 -0
- package/dist/replication/baseline.js +215 -0
- package/dist/replication/bigquery.d.ts +37 -0
- package/dist/replication/bigquery.js +211 -0
- package/dist/replication/coverage.d.ts +14 -0
- package/dist/replication/coverage.js +53 -0
- package/dist/replication/evolution.d.ts +25 -0
- package/dist/replication/evolution.js +184 -0
- package/dist/replication/identities.d.ts +6 -0
- package/dist/replication/identities.js +47 -0
- package/dist/replication/legacy-baseline.d.ts +27 -0
- package/dist/replication/legacy-baseline.js +109 -0
- package/dist/replication/legacy-store.d.ts +19 -0
- package/dist/replication/legacy-store.js +63 -0
- package/dist/replication/lineage.d.ts +36 -0
- package/dist/replication/lineage.js +72 -0
- package/dist/replication/migrate.d.ts +21 -0
- package/dist/replication/migrate.js +84 -0
- package/dist/replication/model.d.ts +52 -0
- package/dist/replication/model.js +99 -0
- package/dist/replication/scans.d.ts +34 -0
- package/dist/replication/scans.js +158 -0
- package/dist/replication/schema.d.ts +11 -0
- package/dist/replication/schema.js +226 -0
- package/dist/replication/shadow-schema.d.ts +4 -0
- package/dist/replication/shadow-schema.js +61 -0
- package/dist/replication/shadow.d.ts +127 -0
- package/dist/replication/shadow.js +614 -0
- package/dist/replication/source-replacement.d.ts +33 -0
- package/dist/replication/source-replacement.js +76 -0
- package/dist/replication/store.d.ts +36 -0
- package/dist/replication/store.js +382 -0
- package/dist/replication/transaction.d.ts +23 -0
- package/dist/replication/transaction.js +88 -0
- package/dist/role.d.ts +61 -0
- package/dist/role.js +76 -0
- package/dist/runtime/action-deadlocks.d.ts +21 -0
- package/dist/runtime/action-deadlocks.js +130 -0
- package/dist/runtime/action-transactions.d.ts +35 -0
- package/dist/runtime/action-transactions.js +54 -0
- package/dist/runtime/agent-counters.d.ts +26 -0
- package/dist/runtime/agent-counters.js +98 -0
- package/dist/runtime/agent-tasks.d.ts +63 -0
- package/dist/runtime/agent-tasks.js +120 -0
- package/dist/runtime/agents.d.ts +15 -0
- package/dist/runtime/agents.js +457 -0
- package/dist/runtime/batch-diagnostics.d.ts +22 -0
- package/dist/runtime/batch-diagnostics.js +89 -0
- package/dist/runtime/batch.d.ts +52 -0
- package/dist/runtime/batch.js +534 -0
- package/dist/runtime/channel-session-revocation.d.ts +3 -0
- package/dist/runtime/channel-session-revocation.js +5 -0
- package/dist/runtime/channel-sessions.d.ts +4 -0
- package/dist/runtime/channel-sessions.js +61 -0
- package/dist/runtime/confirmations.d.ts +29 -0
- package/dist/runtime/confirmations.js +57 -0
- package/dist/runtime/cursor.d.ts +23 -0
- package/dist/runtime/cursor.js +100 -0
- package/dist/runtime/deployment.d.ts +7 -0
- package/dist/runtime/deployment.js +4 -0
- package/dist/runtime/errors.d.ts +118 -0
- package/dist/runtime/errors.js +109 -0
- package/dist/runtime/federation-tables.d.ts +2 -0
- package/dist/runtime/federation-tables.js +20 -0
- package/dist/runtime/federation.d.ts +42 -0
- package/dist/runtime/federation.js +222 -0
- package/dist/runtime/files.d.ts +39 -0
- package/dist/runtime/files.js +44 -0
- package/dist/runtime/generated-actions.d.ts +37 -0
- package/dist/runtime/generated-actions.js +307 -0
- package/dist/runtime/history.d.ts +91 -0
- package/dist/runtime/history.js +77 -0
- package/dist/runtime/ids.d.ts +6 -0
- package/dist/runtime/ids.js +39 -0
- package/dist/runtime/member-tables.d.ts +8 -0
- package/dist/runtime/member-tables.js +33 -0
- package/dist/runtime/member-writes.d.ts +78 -0
- package/dist/runtime/member-writes.js +202 -0
- package/dist/runtime/metric-query.d.ts +19 -0
- package/dist/runtime/metric-query.js +411 -0
- package/dist/runtime/model.d.ts +67 -0
- package/dist/runtime/model.js +150 -0
- package/dist/runtime/new-user-hook.d.ts +6 -0
- package/dist/runtime/new-user-hook.js +37 -0
- package/dist/runtime/oauth.d.ts +9 -0
- package/dist/runtime/oauth.js +299 -0
- package/dist/runtime/pipeline.d.ts +155 -0
- package/dist/runtime/pipeline.js +597 -0
- package/dist/runtime/postgres-tls.d.ts +10 -0
- package/dist/runtime/postgres-tls.js +14 -0
- package/dist/runtime/principals.d.ts +302 -0
- package/dist/runtime/principals.js +1307 -0
- package/dist/runtime/reads.d.ts +55 -0
- package/dist/runtime/reads.js +313 -0
- package/dist/runtime/records.d.ts +42 -0
- package/dist/runtime/records.js +245 -0
- package/dist/runtime/resolve-agent-identity.d.ts +6 -0
- package/dist/runtime/resolve-agent-identity.js +181 -0
- package/dist/runtime/service-binding.d.ts +18 -0
- package/dist/runtime/service-binding.js +266 -0
- package/dist/runtime/sign-in-links.d.ts +68 -0
- package/dist/runtime/sign-in-links.js +147 -0
- package/dist/runtime/sql-runtime.d.ts +131 -0
- package/dist/runtime/sql-runtime.js +362 -0
- package/dist/runtime/statement.d.ts +18 -0
- package/dist/runtime/statement.js +31 -0
- package/dist/runtime/user-identities.d.ts +66 -0
- package/dist/runtime/user-identities.js +106 -0
- package/dist/runtime/user-identity-sql.d.ts +86 -0
- package/dist/runtime/user-identity-sql.js +297 -0
- package/dist/runtime/user-roles.d.ts +16 -0
- package/dist/runtime/user-roles.js +32 -0
- package/dist/runtime/validation.d.ts +16 -0
- package/dist/runtime/validation.js +26 -0
- package/dist/runtime/where.d.ts +57 -0
- package/dist/runtime/where.js +404 -0
- package/dist/runtime/workflow-admission.d.ts +49 -0
- package/dist/runtime/workflow-admission.js +92 -0
- package/dist/runtime/workflow-argument-codec.d.ts +10 -0
- package/dist/runtime/workflow-argument-codec.js +120 -0
- package/dist/runtime/workflow-arguments.d.ts +17 -0
- package/dist/runtime/workflow-arguments.js +99 -0
- package/dist/runtime/workflow-starts.d.ts +203 -0
- package/dist/runtime/workflow-starts.js +493 -0
- package/dist/runtime/workflow-users.d.ts +9 -0
- package/dist/runtime/workflow-users.js +17 -0
- package/dist/runtime/workload.d.ts +25 -0
- package/dist/runtime/workload.js +24 -0
- package/dist/runtime/writes.d.ts +108 -0
- package/dist/runtime/writes.js +491 -0
- package/dist/runtime-source.d.ts +22 -0
- package/dist/runtime-source.js +28 -0
- package/dist/runtime.d.ts +310 -0
- package/dist/runtime.js +31 -0
- package/dist/server.d.ts +23 -0
- package/dist/server.js +107 -0
- package/dist/service/agent/attachments.d.ts +33 -0
- package/dist/service/agent/attachments.js +228 -0
- package/dist/service/agent/authentication.d.ts +22 -0
- package/dist/service/agent/authentication.js +58 -0
- package/dist/service/agent/confirmations.d.ts +5 -0
- package/dist/service/agent/confirmations.js +73 -0
- package/dist/service/agent/conversation-routes.d.ts +14 -0
- package/dist/service/agent/conversation-routes.js +45 -0
- package/dist/service/agent/conversations.d.ts +40 -0
- package/dist/service/agent/conversations.js +69 -0
- package/dist/service/agent/files.d.ts +12 -0
- package/dist/service/agent/files.js +69 -0
- package/dist/service/agent/protocol.d.ts +90 -0
- package/dist/service/agent/protocol.js +114 -0
- package/dist/service/agent/server.d.ts +28 -0
- package/dist/service/agent/server.js +374 -0
- package/dist/service/agent/task-caller.d.ts +21 -0
- package/dist/service/agent/task-caller.js +35 -0
- package/dist/service/agent/task-start.d.ts +53 -0
- package/dist/service/agent/task-start.js +161 -0
- package/dist/service/agent/tasks.d.ts +40 -0
- package/dist/service/agent/tasks.js +155 -0
- package/dist/service/api.d.ts +50 -0
- package/dist/service/api.js +288 -0
- package/dist/service/authentication.d.ts +227 -0
- package/dist/service/authentication.js +767 -0
- package/dist/service/caller-context.d.ts +24 -0
- package/dist/service/caller-context.js +6 -0
- package/dist/service/catalog.d.ts +42 -0
- package/dist/service/catalog.js +66 -0
- package/dist/service/channel/provider.d.ts +10 -0
- package/dist/service/channel/provider.js +1 -0
- package/dist/service/channel/providers/telegram.d.ts +18 -0
- package/dist/service/channel/providers/telegram.js +108 -0
- package/dist/service/channel/sessions.d.ts +5 -0
- package/dist/service/channel/sessions.js +53 -0
- package/dist/service/channel/sign-in.d.ts +7 -0
- package/dist/service/channel/sign-in.js +78 -0
- package/dist/service/chat/archive.d.ts +64 -0
- package/dist/service/chat/archive.js +62 -0
- package/dist/service/chat/attribution.d.ts +26 -0
- package/dist/service/chat/attribution.js +28 -0
- package/dist/service/chat/delivery.d.ts +18 -0
- package/dist/service/chat/delivery.js +251 -0
- package/dist/service/chat/diagnostics.d.ts +2 -0
- package/dist/service/chat/diagnostics.js +35 -0
- package/dist/service/chat/envelope.d.ts +96 -0
- package/dist/service/chat/envelope.js +39 -0
- package/dist/service/chat/idempotency.d.ts +19 -0
- package/dist/service/chat/idempotency.js +37 -0
- package/dist/service/chat/providers/telegram.d.ts +36 -0
- package/dist/service/chat/providers/telegram.js +133 -0
- package/dist/service/chat/reads.d.ts +25 -0
- package/dist/service/chat/reads.js +75 -0
- package/dist/service/chat/resolve.d.ts +34 -0
- package/dist/service/chat/resolve.js +150 -0
- package/dist/service/chat/routes.d.ts +23 -0
- package/dist/service/chat/routes.js +75 -0
- package/dist/service/chat/schemas.d.ts +43 -0
- package/dist/service/chat/schemas.js +31 -0
- package/dist/service/config.d.ts +218 -0
- package/dist/service/config.js +265 -0
- package/dist/service/connection-stream.d.ts +10 -0
- package/dist/service/connection-stream.js +191 -0
- package/dist/service/connections.d.ts +60 -0
- package/dist/service/connections.js +271 -0
- package/dist/service/decisions.d.ts +35 -0
- package/dist/service/decisions.js +63 -0
- package/dist/service/descriptions.d.ts +8 -0
- package/dist/service/descriptions.js +20 -0
- package/dist/service/discovery-schemas.d.ts +92 -0
- package/dist/service/discovery-schemas.js +59 -0
- package/dist/service/discovery-search.d.ts +30 -0
- package/dist/service/discovery-search.js +95 -0
- package/dist/service/discovery.d.ts +37 -0
- package/dist/service/discovery.js +436 -0
- package/dist/service/docs.d.ts +9 -0
- package/dist/service/docs.js +197 -0
- package/dist/service/errors.d.ts +145 -0
- package/dist/service/errors.js +704 -0
- package/dist/service/federation-provider.d.ts +36 -0
- package/dist/service/federation-provider.js +110 -0
- package/dist/service/federation-server.d.ts +20 -0
- package/dist/service/federation-server.js +249 -0
- package/dist/service/federation-status.d.ts +40 -0
- package/dist/service/federation-status.js +151 -0
- package/dist/service/handlers.d.ts +18 -0
- package/dist/service/handlers.js +287 -0
- package/dist/service/mcp/confirmation.d.ts +68 -0
- package/dist/service/mcp/confirmation.js +178 -0
- package/dist/service/mcp/find-input.d.ts +12 -0
- package/dist/service/mcp/find-input.js +122 -0
- package/dist/service/mcp/input-schema.d.ts +6 -0
- package/dist/service/mcp/input-schema.js +126 -0
- package/dist/service/mcp/listing.d.ts +26 -0
- package/dist/service/mcp/listing.js +92 -0
- package/dist/service/mcp/metric-tools.d.ts +85 -0
- package/dist/service/mcp/metric-tools.js +258 -0
- package/dist/service/mcp/request-log.d.ts +5 -0
- package/dist/service/mcp/request-log.js +53 -0
- package/dist/service/mcp/runtime-policy.d.ts +27 -0
- package/dist/service/mcp/runtime-policy.js +62 -0
- package/dist/service/mcp/server.d.ts +52 -0
- package/dist/service/mcp/server.js +861 -0
- package/dist/service/mcp/tools.d.ts +99 -0
- package/dist/service/mcp/tools.js +938 -0
- package/dist/service/member-file-routes.d.ts +22 -0
- package/dist/service/member-file-routes.js +52 -0
- package/dist/service/member-files.d.ts +245 -0
- package/dist/service/member-files.js +258 -0
- package/dist/service/metric-query-platform.d.ts +77 -0
- package/dist/service/metric-query-platform.js +198 -0
- package/dist/service/metric-query-scopes.d.ts +43 -0
- package/dist/service/metric-query-scopes.js +147 -0
- package/dist/service/metric-query.d.ts +48 -0
- package/dist/service/metric-query.js +200 -0
- package/dist/service/name-suggestions.d.ts +3 -0
- package/dist/service/name-suggestions.js +38 -0
- package/dist/service/navigation-schemas.d.ts +80 -0
- package/dist/service/navigation-schemas.js +49 -0
- package/dist/service/navigation.d.ts +20 -0
- package/dist/service/navigation.js +165 -0
- package/dist/service/oauth/protocol.d.ts +70 -0
- package/dist/service/oauth/protocol.js +157 -0
- package/dist/service/oauth/refresh-replay.d.ts +2 -0
- package/dist/service/oauth/refresh-replay.js +20 -0
- package/dist/service/oauth/server.d.ts +28 -0
- package/dist/service/oauth/server.js +769 -0
- package/dist/service/operations.d.ts +170 -0
- package/dist/service/operations.js +392 -0
- package/dist/service/plan.d.ts +57 -0
- package/dist/service/plan.js +96 -0
- package/dist/service/rate-limit.d.ts +22 -0
- package/dist/service/rate-limit.js +52 -0
- package/dist/service/record-reads.d.ts +21 -0
- package/dist/service/record-reads.js +155 -0
- package/dist/service/replication.d.ts +5 -0
- package/dist/service/replication.js +39 -0
- package/dist/service/runtime-contract.d.ts +508 -0
- package/dist/service/runtime-contract.js +18 -0
- package/dist/service/runtime-identity.d.ts +71 -0
- package/dist/service/runtime-identity.js +122 -0
- package/dist/service/schemas.d.ts +961 -0
- package/dist/service/schemas.js +639 -0
- package/dist/service/service.d.ts +21 -0
- package/dist/service/service.js +526 -0
- package/dist/service/warehouse-platform.d.ts +17 -0
- package/dist/service/warehouse-platform.js +122 -0
- package/dist/service/warehouse-query.d.ts +24 -0
- package/dist/service/warehouse-query.js +280 -0
- package/dist/service/webhooks.d.ts +106 -0
- package/dist/service/webhooks.js +233 -0
- package/dist/service/workflow-admission-provider.d.ts +31 -0
- package/dist/service/workflow-admission-provider.js +205 -0
- package/dist/service/workflow-argument-serialization.d.ts +2 -0
- package/dist/service/workflow-argument-serialization.js +14 -0
- package/dist/service/workflow-callback.d.ts +22 -0
- package/dist/service/workflow-callback.js +75 -0
- package/dist/service/workflow-deployment.d.ts +8 -0
- package/dist/service/workflow-deployment.js +131 -0
- package/dist/service/workflow-diagnostics.d.ts +23 -0
- package/dist/service/workflow-diagnostics.js +263 -0
- package/dist/service/workflow-errors.d.ts +26 -0
- package/dist/service/workflow-errors.js +181 -0
- package/dist/service/workflow-logging.d.ts +2 -0
- package/dist/service/workflow-logging.js +50 -0
- package/dist/service/workflow-queue-fence.d.ts +6 -0
- package/dist/service/workflow-queue-fence.js +66 -0
- package/dist/service/workflows.d.ts +200 -0
- package/dist/service/workflows.js +1549 -0
- package/dist/sign-in.d.ts +58 -0
- package/dist/sign-in.js +57 -0
- package/dist/source.d.ts +30 -0
- package/dist/source.js +107 -0
- package/dist/start-recovery-contract.d.ts +49 -0
- package/dist/start-recovery-contract.js +26 -0
- package/dist/start-recovery.d.ts +27 -0
- package/dist/start-recovery.js +81 -0
- package/dist/storage/api.d.ts +4 -0
- package/dist/storage/api.js +40 -0
- package/dist/storage/attachments.d.ts +146 -0
- package/dist/storage/attachments.js +733 -0
- package/dist/storage/authorization.d.ts +38 -0
- package/dist/storage/authorization.js +83 -0
- package/dist/storage/file-access.d.ts +17 -0
- package/dist/storage/file-access.js +8 -0
- package/dist/storage/limits.d.ts +12 -0
- package/dist/storage/limits.js +17 -0
- package/dist/storage/maintenance-auth.d.ts +20 -0
- package/dist/storage/maintenance-auth.js +24 -0
- package/dist/storage/maintenance.d.ts +11 -0
- package/dist/storage/maintenance.js +67 -0
- package/dist/storage/neon.d.ts +4 -0
- package/dist/storage/neon.js +318 -0
- package/dist/storage/operator.d.ts +11 -0
- package/dist/storage/operator.js +30 -0
- package/dist/storage/provider.d.ts +93 -0
- package/dist/storage/provider.js +36 -0
- package/dist/storage/sessions.d.ts +184 -0
- package/dist/storage/sessions.js +688 -0
- package/dist/storage/tables.d.ts +54 -0
- package/dist/storage/tables.js +205 -0
- package/dist/storage/transfers.d.ts +16 -0
- package/dist/storage/transfers.js +153 -0
- package/dist/storage/writes.d.ts +7 -0
- package/dist/storage/writes.js +88 -0
- package/dist/telegram.d.ts +35 -0
- package/dist/telegram.js +173 -0
- package/dist/user-identity.d.ts +28 -0
- package/dist/user-identity.js +106 -0
- package/dist/user.d.ts +75 -0
- package/dist/user.js +111 -0
- package/dist/warehouse-backed.d.ts +6 -0
- package/dist/warehouse-backed.js +495 -0
- package/dist/webhook-token.d.ts +11 -0
- package/dist/webhook-token.js +18 -0
- package/dist/webhooks.d.ts +40 -0
- package/dist/webhooks.js +55 -0
- package/dist/wire.d.ts +10 -0
- package/dist/wire.js +35 -0
- package/dist/workflow-runtime.d.ts +116 -0
- package/dist/workflow-runtime.js +109 -0
- package/dist/workflow-topics.d.ts +28 -0
- package/dist/workflow-topics.js +28 -0
- package/dist/workflow.d.ts +284 -0
- package/dist/workflow.js +259 -0
- package/dist/workflows.d.ts +24 -0
- package/dist/workflows.js +18 -0
- package/package.json +127 -4
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import type { Principal } from "../../runtime.js";
|
|
3
|
+
import type { AgentIdentity } from "../runtime-contract.js";
|
|
4
|
+
/** How long a member has to open the connect link, sign in and approve the pairing. */
|
|
5
|
+
export declare const PAIRING_TTL_MS: number;
|
|
6
|
+
/**
|
|
7
|
+
* The letters and digits a pairing code uses: no 0/O, 1/I/L, so that a code read aloud or typed from
|
|
8
|
+
* a phone comes out right. 31 symbols, 8 of them: about 40 bits, against ten minutes of guessing by
|
|
9
|
+
* signed-in members only.
|
|
10
|
+
*/
|
|
11
|
+
export declare const PAIRING_CODE_ALPHABET = "ABCDEFGHJKMNPQRSTUVWXYZ23456789";
|
|
12
|
+
export declare const PAIRING_CODE_LENGTH = 8;
|
|
13
|
+
/** A new pairing code, from the operating system's random source without modulo bias. */
|
|
14
|
+
export declare function newPairingCode(): string;
|
|
15
|
+
/**
|
|
16
|
+
* A code as the member's browser sends it, in the canonical form it was hashed in: upper case,
|
|
17
|
+
* without the spaces or dashes someone may type between groups. `undefined` when it cannot be one.
|
|
18
|
+
*/
|
|
19
|
+
export declare function canonicalPairingCode(value: string): string | undefined;
|
|
20
|
+
/** A channel's name: `telegram`, `slack`. It is part of a URL path and of every identity. */
|
|
21
|
+
export declare const Provider: Schema.String;
|
|
22
|
+
/** `POST /api/ontology/agent/pairings`: the account an unknown sender writes from. */
|
|
23
|
+
export declare const PairingRequest: Schema.Struct<{
|
|
24
|
+
readonly provider: Schema.String;
|
|
25
|
+
readonly external_id: Schema.String;
|
|
26
|
+
readonly display: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
27
|
+
}>;
|
|
28
|
+
export declare const ResolveIdentityRequest: Schema.Struct<{
|
|
29
|
+
readonly chat: Schema.Literals<readonly ["private", "group"]>;
|
|
30
|
+
readonly turn: Schema.Boolean;
|
|
31
|
+
readonly username: Schema.optionalKey<Schema.String>;
|
|
32
|
+
readonly notice_version: Schema.optionalKey<Schema.String>;
|
|
33
|
+
readonly notice_sha256: Schema.optionalKey<Schema.String>;
|
|
34
|
+
readonly limits: Schema.optionalKey<Schema.Struct<{
|
|
35
|
+
readonly perSender: Schema.optionalKey<Schema.Struct<{
|
|
36
|
+
readonly turnsPerMinute: Schema.optionalKey<Schema.Int>;
|
|
37
|
+
readonly turnsPerDay: Schema.optionalKey<Schema.Int>;
|
|
38
|
+
}>>;
|
|
39
|
+
readonly newUsersPerHour: Schema.optionalKey<Schema.Int>;
|
|
40
|
+
readonly workspaceTurnsPerDay: Schema.optionalKey<Schema.Int>;
|
|
41
|
+
}>>;
|
|
42
|
+
readonly provider: Schema.String;
|
|
43
|
+
readonly external_id: Schema.String;
|
|
44
|
+
readonly display: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
45
|
+
}>;
|
|
46
|
+
export declare const IdentityNoticeRequest: Schema.Struct<{
|
|
47
|
+
readonly provider: Schema.String;
|
|
48
|
+
readonly external_id: Schema.String;
|
|
49
|
+
readonly sha256: Schema.String;
|
|
50
|
+
readonly version: Schema.optionalKey<Schema.String>;
|
|
51
|
+
}>;
|
|
52
|
+
export declare const LimitNoticeRequest: Schema.Struct<{
|
|
53
|
+
readonly notification_id: Schema.String;
|
|
54
|
+
readonly delivered: Schema.Boolean;
|
|
55
|
+
}>;
|
|
56
|
+
export type PairingRequest = typeof PairingRequest.Type;
|
|
57
|
+
/**
|
|
58
|
+
* `POST /api/ontology/agent/chats/seen`: a group chat the agent saw a message in, and who wrote, or
|
|
59
|
+
* the paired member who left it, or the agent itself leaving it, or the group it was before it
|
|
60
|
+
* became a supergroup.
|
|
61
|
+
*/
|
|
62
|
+
export declare const ChatSeenRequest: Schema.Struct<{
|
|
63
|
+
readonly provider: Schema.String;
|
|
64
|
+
readonly externalId: Schema.String;
|
|
65
|
+
readonly title: Schema.String;
|
|
66
|
+
readonly memberId: Schema.optionalKey<Schema.String>;
|
|
67
|
+
readonly leftMemberId: Schema.optionalKey<Schema.String>;
|
|
68
|
+
readonly agentLeft: Schema.optionalKey<Schema.Literal<true>>;
|
|
69
|
+
readonly migratedFrom: Schema.optionalKey<Schema.String>;
|
|
70
|
+
}>;
|
|
71
|
+
/** An identity on the wire, as the member's connect page and settings show it. */
|
|
72
|
+
export declare function identityForWire(identity: AgentIdentity): {
|
|
73
|
+
created_at: string;
|
|
74
|
+
username?: string | undefined;
|
|
75
|
+
id: string;
|
|
76
|
+
provider: string;
|
|
77
|
+
external_id: string;
|
|
78
|
+
display: string | null;
|
|
79
|
+
};
|
|
80
|
+
/** The member the agent acts for, as `GET …/identities/{provider}/{external_id}` answers. */
|
|
81
|
+
export declare function memberForWire(input: {
|
|
82
|
+
readonly name: string;
|
|
83
|
+
readonly principal: Principal;
|
|
84
|
+
}): {
|
|
85
|
+
user: {
|
|
86
|
+
id: string;
|
|
87
|
+
name: string;
|
|
88
|
+
};
|
|
89
|
+
roles: readonly string[];
|
|
90
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { randomInt } from "node:crypto";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
/** How long a member has to open the connect link, sign in and approve the pairing. */
|
|
4
|
+
export const PAIRING_TTL_MS = 10 * 60 * 1000;
|
|
5
|
+
/**
|
|
6
|
+
* The letters and digits a pairing code uses: no 0/O, 1/I/L, so that a code read aloud or typed from
|
|
7
|
+
* a phone comes out right. 31 symbols, 8 of them: about 40 bits, against ten minutes of guessing by
|
|
8
|
+
* signed-in members only.
|
|
9
|
+
*/
|
|
10
|
+
export const PAIRING_CODE_ALPHABET = "ABCDEFGHJKMNPQRSTUVWXYZ23456789";
|
|
11
|
+
export const PAIRING_CODE_LENGTH = 8;
|
|
12
|
+
const PAIRING_CODE = new RegExp(`^[${PAIRING_CODE_ALPHABET}]{${PAIRING_CODE_LENGTH}}$`);
|
|
13
|
+
/** A new pairing code, from the operating system's random source without modulo bias. */
|
|
14
|
+
export function newPairingCode() {
|
|
15
|
+
let code = "";
|
|
16
|
+
for (let index = 0; index < PAIRING_CODE_LENGTH; index++) {
|
|
17
|
+
code += PAIRING_CODE_ALPHABET[randomInt(PAIRING_CODE_ALPHABET.length)];
|
|
18
|
+
}
|
|
19
|
+
return code;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A code as the member's browser sends it, in the canonical form it was hashed in: upper case,
|
|
23
|
+
* without the spaces or dashes someone may type between groups. `undefined` when it cannot be one.
|
|
24
|
+
*/
|
|
25
|
+
export function canonicalPairingCode(value) {
|
|
26
|
+
const code = value.replace(/[\s-]/g, "").toUpperCase();
|
|
27
|
+
return PAIRING_CODE.test(code) ? code : undefined;
|
|
28
|
+
}
|
|
29
|
+
const MAX_EXTERNAL_ID_LENGTH = 256;
|
|
30
|
+
const MAX_DISPLAY_LENGTH = 200;
|
|
31
|
+
/** A channel's name: `telegram`, `slack`. It is part of a URL path and of every identity. */
|
|
32
|
+
export const Provider = Schema.String.check(Schema.isPattern(/^[a-z][a-z0-9_-]{0,31}$/)).annotate({
|
|
33
|
+
description: "The channel, such as telegram: lower case letters, digits, - and _.",
|
|
34
|
+
});
|
|
35
|
+
/** `POST /api/ontology/agent/pairings`: the account an unknown sender writes from. */
|
|
36
|
+
export const PairingRequest = Schema.Struct({
|
|
37
|
+
provider: Provider,
|
|
38
|
+
external_id: Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(MAX_EXTERNAL_ID_LENGTH)).annotate({ description: "The account's id on the channel." }),
|
|
39
|
+
display: Schema.optionalKey(Schema.NullOr(Schema.String.check(Schema.isMaxLength(MAX_DISPLAY_LENGTH))).annotate({
|
|
40
|
+
description: "How the channel names the account, shown to the member who approves.",
|
|
41
|
+
})),
|
|
42
|
+
});
|
|
43
|
+
/** Trusted runtime resolution: channel admission and limits run before expensive processing. */
|
|
44
|
+
const PositiveLimit = Schema.Int.check(Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(1_000_000_000));
|
|
45
|
+
export const ResolveIdentityRequest = Schema.Struct({
|
|
46
|
+
...PairingRequest.fields,
|
|
47
|
+
chat: Schema.Literals(["private", "group"]),
|
|
48
|
+
turn: Schema.Boolean,
|
|
49
|
+
username: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(MAX_DISPLAY_LENGTH))),
|
|
50
|
+
notice_version: Schema.optionalKey(Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(200))),
|
|
51
|
+
notice_sha256: Schema.optionalKey(Schema.String.check(Schema.isPattern(/^[a-f0-9]{64}$/))),
|
|
52
|
+
limits: Schema.optionalKey(Schema.Struct({
|
|
53
|
+
perSender: Schema.optionalKey(Schema.Struct({
|
|
54
|
+
turnsPerMinute: Schema.optionalKey(PositiveLimit),
|
|
55
|
+
turnsPerDay: Schema.optionalKey(PositiveLimit),
|
|
56
|
+
})),
|
|
57
|
+
newUsersPerHour: Schema.optionalKey(PositiveLimit),
|
|
58
|
+
workspaceTurnsPerDay: Schema.optionalKey(PositiveLimit),
|
|
59
|
+
})),
|
|
60
|
+
});
|
|
61
|
+
export const IdentityNoticeRequest = Schema.Struct({
|
|
62
|
+
provider: Provider,
|
|
63
|
+
external_id: PairingRequest.fields.external_id,
|
|
64
|
+
sha256: Schema.String.check(Schema.isPattern(/^[a-f0-9]{64}$/)),
|
|
65
|
+
version: Schema.optionalKey(Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(200))),
|
|
66
|
+
});
|
|
67
|
+
export const LimitNoticeRequest = Schema.Struct({
|
|
68
|
+
notification_id: Schema.String.check(Schema.isUUID()),
|
|
69
|
+
delivered: Schema.Boolean,
|
|
70
|
+
});
|
|
71
|
+
/** A chat's id on the channel. */
|
|
72
|
+
const ChatId = Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(MAX_EXTERNAL_ID_LENGTH));
|
|
73
|
+
/**
|
|
74
|
+
* `POST /api/ontology/agent/chats/seen`: a group chat the agent saw a message in, and who wrote, or
|
|
75
|
+
* the paired member who left it, or the agent itself leaving it, or the group it was before it
|
|
76
|
+
* became a supergroup.
|
|
77
|
+
*/
|
|
78
|
+
export const ChatSeenRequest = Schema.Struct({
|
|
79
|
+
provider: Provider,
|
|
80
|
+
externalId: ChatId.annotate({ description: "The chat's id on the channel." }),
|
|
81
|
+
title: Schema.String.check(Schema.isMaxLength(MAX_DISPLAY_LENGTH)).annotate({
|
|
82
|
+
description: "The chat's name on the channel.",
|
|
83
|
+
}),
|
|
84
|
+
memberId: Schema.optionalKey(Schema.String.annotate({
|
|
85
|
+
description: "The user id of the member who wrote, when the sender is paired.",
|
|
86
|
+
})),
|
|
87
|
+
leftMemberId: Schema.optionalKey(Schema.String.annotate({
|
|
88
|
+
description: "The user id of a paired member who left the chat, to unlink from its members.",
|
|
89
|
+
})),
|
|
90
|
+
agentLeft: Schema.optionalKey(Schema.Literal(true).annotate({
|
|
91
|
+
description: "The agent itself left the chat or was removed: every member is unlinked.",
|
|
92
|
+
})),
|
|
93
|
+
migratedFrom: Schema.optionalKey(ChatId.annotate({
|
|
94
|
+
description: "The chat's id before it became a supergroup: its record moves to externalId.",
|
|
95
|
+
})),
|
|
96
|
+
});
|
|
97
|
+
/** An identity on the wire, as the member's connect page and settings show it. */
|
|
98
|
+
export function identityForWire(identity) {
|
|
99
|
+
return {
|
|
100
|
+
id: identity.id,
|
|
101
|
+
provider: identity.provider,
|
|
102
|
+
external_id: identity.externalId,
|
|
103
|
+
display: identity.display,
|
|
104
|
+
...(identity.username === undefined ? {} : { username: identity.username }),
|
|
105
|
+
created_at: identity.createdAt.toISOString(),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/** The member the agent acts for, as `GET …/identities/{provider}/{external_id}` answers. */
|
|
109
|
+
export function memberForWire(input) {
|
|
110
|
+
return {
|
|
111
|
+
user: { id: input.principal.id, name: input.name },
|
|
112
|
+
roles: input.principal.roles,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
import { HttpRouter } from "effect/unstable/http";
|
|
3
|
+
import { type SessionExchange, type TokenVerifier } from "../authentication.js";
|
|
4
|
+
import { RequestId } from "../errors.js";
|
|
5
|
+
import { type RateLimit } from "../rate-limit.js";
|
|
6
|
+
import { OntologyBackend } from "../runtime-contract.js";
|
|
7
|
+
import { type RuntimeTokenVerifier } from "../runtime-identity.js";
|
|
8
|
+
/** The agent's endpoints, under the ontology service's path. */
|
|
9
|
+
export declare const AGENT_PATH = "/api/ontology/agent";
|
|
10
|
+
/**
|
|
11
|
+
* Pairings one client address may start per minute; each one is a row in the database. The agent's
|
|
12
|
+
* functions share a few egress addresses, so the limit leaves room for a busy channel.
|
|
13
|
+
*/
|
|
14
|
+
export declare const PAIRING_LIMIT: RateLimit;
|
|
15
|
+
export interface AgentServerOptions {
|
|
16
|
+
readonly verifyToken: TokenVerifier;
|
|
17
|
+
/** The deployment's runtime tokens; `undefined` while runtime authentication is disabled. */
|
|
18
|
+
readonly verifyRuntime: RuntimeTokenVerifier | undefined;
|
|
19
|
+
readonly exchangeSession: SessionExchange | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The routes that pair channel accounts with members for the app's own agent, and record the group
|
|
23
|
+
* chats it sees. Runtime routes take
|
|
24
|
+
* only the deployment's runtime token. Member routes take a member's Neon Auth session or token, and
|
|
25
|
+
* refuse API keys and the runtime, even acting as a member: only the member pairs or unpairs.
|
|
26
|
+
* Without the agent tables, it serves nothing.
|
|
27
|
+
*/
|
|
28
|
+
export declare function agentLayer(options: AgentServerOptions): Layer.Layer<never, never, OntologyBackend | HttpRouter.HttpRouter | HttpRouter.Request<"Requires", RequestId>>;
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { confirmationCommand } from "./confirmations.js";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { Effect, Layer, Redacted, Result, Schema } from "effect";
|
|
4
|
+
import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
5
|
+
import { HttpApiBuilder, HttpApiSecurity } from "effect/unstable/httpapi";
|
|
6
|
+
import { schemaIssues } from "../../runtime/validation.js";
|
|
7
|
+
import { BASE_PATH } from "../api.js";
|
|
8
|
+
import { CurrentPrincipal, withPrincipal, } from "../authentication.js";
|
|
9
|
+
import { RequestId, errorBodyForWire, forbidden, notFound, rateLimited, toServerResponse, unauthorized, unavailable, } from "../errors.js";
|
|
10
|
+
import { secretHash } from "../oauth/protocol.js";
|
|
11
|
+
import { clientAddress, fixedWindowLimiter, } from "../rate-limit.js";
|
|
12
|
+
import { OntologyBackend } from "../runtime-contract.js";
|
|
13
|
+
import { AGENT_TASK_HEADER, agentTaskSecret, logRuntimeRejection, } from "../runtime-identity.js";
|
|
14
|
+
import { ChatSeenRequest, ResolveIdentityRequest, IdentityNoticeRequest, LimitNoticeRequest, PAIRING_TTL_MS, PairingRequest, canonicalPairingCode, identityForWire, memberForWire, newPairingCode, } from "./protocol.js";
|
|
15
|
+
/** The agent's endpoints, under the ontology service's path. */
|
|
16
|
+
export const AGENT_PATH = `${BASE_PATH}/agent`;
|
|
17
|
+
const PAIRINGS_PATH = `${AGENT_PATH}/pairings`;
|
|
18
|
+
const IDENTITIES_PATH = `${AGENT_PATH}/identities`;
|
|
19
|
+
const CHATS_SEEN_PATH = `${AGENT_PATH}/chats/seen`;
|
|
20
|
+
/**
|
|
21
|
+
* Pairings one client address may start per minute; each one is a row in the database. The agent's
|
|
22
|
+
* functions share a few egress addresses, so the limit leaves room for a busy channel.
|
|
23
|
+
*/
|
|
24
|
+
export const PAIRING_LIMIT = { limit: 60, windowMs: 60_000, maxKeys: 10_000 };
|
|
25
|
+
/** A fresh code collides with a live one about never; a few attempts make it never in practice. */
|
|
26
|
+
const CODE_ATTEMPTS = 3;
|
|
27
|
+
const NO_STORE = { "cache-control": "no-store" };
|
|
28
|
+
function json(body, status = 200) {
|
|
29
|
+
return HttpServerResponse.jsonUnsafe(body, { status, headers: NO_STORE });
|
|
30
|
+
}
|
|
31
|
+
function jsonBody(request) {
|
|
32
|
+
return Effect.map(Effect.orDie(request.text), (text) => {
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(text);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function invalidBody(requestId, issues) {
|
|
42
|
+
return HttpServerResponse.jsonUnsafe(errorBodyForWire({
|
|
43
|
+
error: "invalid_request",
|
|
44
|
+
detail: "The request body is invalid.",
|
|
45
|
+
requestId,
|
|
46
|
+
issues,
|
|
47
|
+
}), { status: 400 });
|
|
48
|
+
}
|
|
49
|
+
function pairingNotFound(requestId) {
|
|
50
|
+
return toServerResponse(notFound(requestId, "The pairing code expired or was already used. Send the agent a message for a new link."));
|
|
51
|
+
}
|
|
52
|
+
function routeParam(name) {
|
|
53
|
+
return Effect.map(HttpRouter.params, (params) => params[name] ?? "");
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* `POST /api/ontology/agent/pairings` (runtime): a sender the agent does not know gets a short code
|
|
57
|
+
* that a signed-in member approves on the app's connect page. Only the code's hash is stored.
|
|
58
|
+
*/
|
|
59
|
+
function createPairing(store, limiter) {
|
|
60
|
+
return (request) => Effect.gen(function* () {
|
|
61
|
+
const requestId = yield* RequestId;
|
|
62
|
+
const retryAfter = limiter.take(clientAddress(request));
|
|
63
|
+
if (retryAfter !== undefined) {
|
|
64
|
+
return toServerResponse(rateLimited(requestId, "Too many pairings; try again in a minute.", retryAfter));
|
|
65
|
+
}
|
|
66
|
+
const body = yield* jsonBody(request);
|
|
67
|
+
const decoded = Schema.decodeUnknownResult(PairingRequest)(body, {
|
|
68
|
+
errors: "all",
|
|
69
|
+
onExcessProperty: "error",
|
|
70
|
+
});
|
|
71
|
+
if (Result.isFailure(decoded)) {
|
|
72
|
+
return invalidBody(requestId, schemaIssues(decoded.failure));
|
|
73
|
+
}
|
|
74
|
+
const { provider, external_id: externalId, display } = decoded.success;
|
|
75
|
+
const trimmedDisplay = display?.trim() || null;
|
|
76
|
+
for (let attempt = 0; attempt < CODE_ATTEMPTS; attempt++) {
|
|
77
|
+
const code = newPairingCode();
|
|
78
|
+
const expiresAt = new Date(Date.now() + PAIRING_TTL_MS);
|
|
79
|
+
const saved = yield* store.savePairing({
|
|
80
|
+
id: randomUUID(),
|
|
81
|
+
codeHash: secretHash(code),
|
|
82
|
+
provider,
|
|
83
|
+
externalId,
|
|
84
|
+
display: trimmedDisplay,
|
|
85
|
+
expiresAt,
|
|
86
|
+
});
|
|
87
|
+
if (saved) {
|
|
88
|
+
return json({ code, expires_at: expiresAt.toISOString() }, 201);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return yield* Effect.die(new Error("No free pairing code after several attempts."));
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/** `GET /api/ontology/agent/pairings/:code` (member): what the connect page shows. */
|
|
95
|
+
function describePairing(store) {
|
|
96
|
+
return Effect.gen(function* () {
|
|
97
|
+
const requestId = yield* RequestId;
|
|
98
|
+
const code = canonicalPairingCode(yield* routeParam("code"));
|
|
99
|
+
const pairing = code === undefined ? undefined : yield* store.findPairing(secretHash(code));
|
|
100
|
+
if (pairing === undefined) {
|
|
101
|
+
return pairingNotFound(requestId);
|
|
102
|
+
}
|
|
103
|
+
return json({
|
|
104
|
+
provider: pairing.provider,
|
|
105
|
+
display: pairing.display,
|
|
106
|
+
expires_at: pairing.expiresAt.toISOString(),
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* `POST /api/ontology/agent/pairings/:code/approve` (member): pairs the account with the signed-in
|
|
112
|
+
* member, once. Another member's live account cannot be claimed. A member may replace their own
|
|
113
|
+
* previous account on the same provider.
|
|
114
|
+
*/
|
|
115
|
+
function approvePairing(store, member) {
|
|
116
|
+
return Effect.gen(function* () {
|
|
117
|
+
const requestId = yield* RequestId;
|
|
118
|
+
const code = canonicalPairingCode(yield* routeParam("code"));
|
|
119
|
+
const identity = code === undefined
|
|
120
|
+
? undefined
|
|
121
|
+
: yield* store
|
|
122
|
+
.approvePairing({
|
|
123
|
+
codeHash: secretHash(code),
|
|
124
|
+
userId: member.id,
|
|
125
|
+
identityId: randomUUID(),
|
|
126
|
+
})
|
|
127
|
+
.pipe(Effect.catchTag("IdentityInUse", () => Effect.succeed("identity_in_use")));
|
|
128
|
+
if (identity === "identity_in_use") {
|
|
129
|
+
return HttpServerResponse.jsonUnsafe(errorBodyForWire({
|
|
130
|
+
error: "identity_in_use",
|
|
131
|
+
detail: "identity_in_use",
|
|
132
|
+
requestId,
|
|
133
|
+
}), { status: 409, headers: NO_STORE });
|
|
134
|
+
}
|
|
135
|
+
if (identity === undefined) {
|
|
136
|
+
return pairingNotFound(requestId);
|
|
137
|
+
}
|
|
138
|
+
yield* Effect.logInfo("ontology.agent.paired").pipe(Effect.annotateLogs({ identityId: identity.id, provider: identity.provider, requestId }));
|
|
139
|
+
return json({ identity: identityForWire(identity) });
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* `GET /api/ontology/agent/identities/:provider/:external_id` (runtime): the member an account acts
|
|
144
|
+
* as, with the roles they hold now. 404 for an account nobody paired; 403 once its identity was
|
|
145
|
+
* revoked or its member deactivated.
|
|
146
|
+
*/
|
|
147
|
+
function resolveIdentity(store) {
|
|
148
|
+
return Effect.gen(function* () {
|
|
149
|
+
const requestId = yield* RequestId;
|
|
150
|
+
const provider = yield* routeParam("provider");
|
|
151
|
+
const externalId = yield* routeParam("external_id");
|
|
152
|
+
const identity = yield* store.findIdentity({ provider, externalId });
|
|
153
|
+
if (identity === undefined) {
|
|
154
|
+
return toServerResponse(notFound(requestId, "No member paired this account."));
|
|
155
|
+
}
|
|
156
|
+
if (identity.revokedAt !== null) {
|
|
157
|
+
return toServerResponse(forbidden(requestId, "The account's pairing was revoked."));
|
|
158
|
+
}
|
|
159
|
+
const member = yield* store.member(identity.userId);
|
|
160
|
+
if (member === undefined) {
|
|
161
|
+
return toServerResponse(forbidden(requestId, "The member is inactive."));
|
|
162
|
+
}
|
|
163
|
+
return json(memberForWire(member));
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
/** Runtime-only admission; expected refusals and limits are 200 discriminated results. */
|
|
167
|
+
function resolveChannelIdentity(store) {
|
|
168
|
+
return (request) => Effect.gen(function* () {
|
|
169
|
+
const requestId = yield* RequestId;
|
|
170
|
+
const decoded = Schema.decodeUnknownResult(ResolveIdentityRequest)(yield* jsonBody(request), {
|
|
171
|
+
errors: "all",
|
|
172
|
+
onExcessProperty: "error",
|
|
173
|
+
});
|
|
174
|
+
if (Result.isFailure(decoded)) {
|
|
175
|
+
return invalidBody(requestId, schemaIssues(decoded.failure));
|
|
176
|
+
}
|
|
177
|
+
const { external_id: externalId, notice_version, notice_sha256, ...input } = decoded.success;
|
|
178
|
+
const resolution = yield* store.resolveIdentity({
|
|
179
|
+
...input,
|
|
180
|
+
externalId,
|
|
181
|
+
...(notice_version === undefined ? {} : { noticeVersion: notice_version }),
|
|
182
|
+
...(notice_sha256 === undefined ? {} : { noticeSha256: notice_sha256 }),
|
|
183
|
+
});
|
|
184
|
+
switch (resolution.status) {
|
|
185
|
+
case "existing":
|
|
186
|
+
case "created":
|
|
187
|
+
return json({
|
|
188
|
+
status: resolution.status,
|
|
189
|
+
...memberForWire(resolution.member),
|
|
190
|
+
provisioned: resolution.provisioned,
|
|
191
|
+
notice_due: resolution.noticeDue,
|
|
192
|
+
on_new_user_pending: resolution.onNewUserPending,
|
|
193
|
+
});
|
|
194
|
+
case "limited":
|
|
195
|
+
return json({
|
|
196
|
+
status: resolution.status,
|
|
197
|
+
scope: resolution.scope,
|
|
198
|
+
retry_after_seconds: resolution.retryAfterSeconds,
|
|
199
|
+
notify: resolution.notify,
|
|
200
|
+
...(resolution.notificationId === undefined
|
|
201
|
+
? {}
|
|
202
|
+
: { notification_id: resolution.notificationId }),
|
|
203
|
+
});
|
|
204
|
+
default:
|
|
205
|
+
return json(resolution);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/** Notice delivery is acknowledged only after the channel has accepted the fixed message. */
|
|
210
|
+
function recordNotice(store) {
|
|
211
|
+
return (request) => Effect.gen(function* () {
|
|
212
|
+
const requestId = yield* RequestId;
|
|
213
|
+
const decoded = Schema.decodeUnknownResult(IdentityNoticeRequest)(yield* jsonBody(request), {
|
|
214
|
+
errors: "all",
|
|
215
|
+
onExcessProperty: "error",
|
|
216
|
+
});
|
|
217
|
+
if (Result.isFailure(decoded)) {
|
|
218
|
+
return invalidBody(requestId, schemaIssues(decoded.failure));
|
|
219
|
+
}
|
|
220
|
+
const { provider, external_id: externalId, sha256, version } = decoded.success;
|
|
221
|
+
yield* store.recordNotice({
|
|
222
|
+
provider,
|
|
223
|
+
externalId,
|
|
224
|
+
sha256,
|
|
225
|
+
...(version === undefined ? {} : { version }),
|
|
226
|
+
});
|
|
227
|
+
return HttpServerResponse.empty({ status: 204, headers: NO_STORE });
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
function completeLimitNotice(store) {
|
|
231
|
+
return (request) => Effect.gen(function* () {
|
|
232
|
+
const requestId = yield* RequestId;
|
|
233
|
+
const decoded = Schema.decodeUnknownResult(LimitNoticeRequest)(yield* jsonBody(request), {
|
|
234
|
+
errors: "all",
|
|
235
|
+
onExcessProperty: "error",
|
|
236
|
+
});
|
|
237
|
+
if (Result.isFailure(decoded)) {
|
|
238
|
+
return invalidBody(requestId, schemaIssues(decoded.failure));
|
|
239
|
+
}
|
|
240
|
+
yield* store.completeLimitNotice({
|
|
241
|
+
notificationId: decoded.success.notification_id,
|
|
242
|
+
delivered: decoded.success.delivered,
|
|
243
|
+
});
|
|
244
|
+
return HttpServerResponse.empty({ status: 204, headers: NO_STORE });
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* `POST /api/ontology/agent/chats/seen` (runtime): the agent saw a message in a group chat. The chat
|
|
249
|
+
* is recorded, or its title kept current, a paired writer joins its members and a paired member who
|
|
250
|
+
* left is unlinked from them, or all of them when the agent itself left; the answer says what the
|
|
251
|
+
* chat is for, so that the agent knows it.
|
|
252
|
+
*/
|
|
253
|
+
function seeChat(store) {
|
|
254
|
+
return (request) => Effect.gen(function* () {
|
|
255
|
+
const requestId = yield* RequestId;
|
|
256
|
+
const decoded = Schema.decodeUnknownResult(ChatSeenRequest)(yield* jsonBody(request), {
|
|
257
|
+
errors: "all",
|
|
258
|
+
onExcessProperty: "error",
|
|
259
|
+
});
|
|
260
|
+
if (Result.isFailure(decoded)) {
|
|
261
|
+
return invalidBody(requestId, schemaIssues(decoded.failure));
|
|
262
|
+
}
|
|
263
|
+
const chat = yield* store.seeChat(decoded.success);
|
|
264
|
+
yield* Effect.logInfo("ontology.agent.chat_reported").pipe(Effect.annotateLogs({
|
|
265
|
+
requestId,
|
|
266
|
+
provider: decoded.success.provider,
|
|
267
|
+
chatId: decoded.success.externalId,
|
|
268
|
+
}));
|
|
269
|
+
return json(chat);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/** `GET /api/ontology/agent/identities` (member): the member's own live identities. */
|
|
273
|
+
function listIdentities(store, member) {
|
|
274
|
+
return Effect.gen(function* () {
|
|
275
|
+
const identities = yield* store.listIdentities(member.id);
|
|
276
|
+
return json({ identities: identities.map(identityForWire) });
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
/** `DELETE /api/ontology/agent/identities/:id` (member): revokes one of the member's identities. */
|
|
280
|
+
function revokeIdentity(store, member) {
|
|
281
|
+
return Effect.gen(function* () {
|
|
282
|
+
const requestId = yield* RequestId;
|
|
283
|
+
const id = yield* routeParam("id");
|
|
284
|
+
const revoked = yield* store.revokeIdentity({ id, userId: member.id });
|
|
285
|
+
if (!revoked) {
|
|
286
|
+
return toServerResponse(notFound(requestId, "You have no such identity."));
|
|
287
|
+
}
|
|
288
|
+
yield* Effect.logInfo("ontology.agent.unpaired").pipe(Effect.annotateLogs({ identityId: id, requestId }));
|
|
289
|
+
return HttpServerResponse.empty({ status: 204, headers: NO_STORE });
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* The routes that pair channel accounts with members for the app's own agent, and record the group
|
|
294
|
+
* chats it sees. Runtime routes take
|
|
295
|
+
* only the deployment's runtime token. Member routes take a member's Neon Auth session or token, and
|
|
296
|
+
* refuse API keys and the runtime, even acting as a member: only the member pairs or unpairs.
|
|
297
|
+
* Without the agent tables, it serves nothing.
|
|
298
|
+
*/
|
|
299
|
+
export function agentLayer(options) {
|
|
300
|
+
return Layer.effectDiscard(Effect.gen(function* () {
|
|
301
|
+
const router = yield* HttpRouter.HttpRouter;
|
|
302
|
+
const backend = yield* OntologyBackend;
|
|
303
|
+
const store = backend.agents;
|
|
304
|
+
if (store === undefined) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const limiter = fixedWindowLimiter(PAIRING_LIMIT);
|
|
308
|
+
const credential = HttpApiBuilder.securityDecode(HttpApiSecurity.bearer);
|
|
309
|
+
const bearerOf = (request) => Effect.provideService(credential, HttpServerRequest.HttpServerRequest, request);
|
|
310
|
+
const asRuntime = (answer) => (request) => Effect.gen(function* () {
|
|
311
|
+
const requestId = yield* RequestId;
|
|
312
|
+
const bearer = yield* bearerOf(request);
|
|
313
|
+
const token = Redacted.value(bearer);
|
|
314
|
+
const verified = options.verifyRuntime === undefined || token === ""
|
|
315
|
+
? undefined
|
|
316
|
+
: yield* Effect.promise(() => options.verifyRuntime(token));
|
|
317
|
+
switch (verified?.status) {
|
|
318
|
+
case "valid":
|
|
319
|
+
// A task acts as its workflow's user, which pairs, resolves and records nothing here.
|
|
320
|
+
return agentTaskSecret(request) === undefined
|
|
321
|
+
? yield* answer(request)
|
|
322
|
+
: toServerResponse(forbidden(requestId, `This route does not accept ${AGENT_TASK_HEADER}.`));
|
|
323
|
+
case "invalid":
|
|
324
|
+
yield* logRuntimeRejection(verified.reason);
|
|
325
|
+
return toServerResponse(unauthorized(requestId, "The bearer token is invalid, expired or revoked."));
|
|
326
|
+
case "unavailable":
|
|
327
|
+
return toServerResponse(unavailable(requestId));
|
|
328
|
+
default:
|
|
329
|
+
// Any other credential is authenticated as usual, so that it gets the usual 401, and
|
|
330
|
+
// then refused: these routes are the agent's.
|
|
331
|
+
return yield* withPrincipal(bearer, options.verifyToken, backend, Effect.succeed(toServerResponse(forbidden(requestId, "Only the app's agent calls this route."))));
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
const asMember = (answer) => (request) => Effect.gen(function* () {
|
|
335
|
+
const bearer = yield* bearerOf(request);
|
|
336
|
+
const decided = Effect.gen(function* () {
|
|
337
|
+
const requestId = yield* RequestId;
|
|
338
|
+
const principal = yield* CurrentPrincipal;
|
|
339
|
+
if (principal.kind !== "member") {
|
|
340
|
+
return toServerResponse(forbidden(requestId, "Only a signed-in member can pair the app's agent."));
|
|
341
|
+
}
|
|
342
|
+
return yield* answer(request, principal);
|
|
343
|
+
});
|
|
344
|
+
return yield* withPrincipal(bearer, options.verifyToken, backend, decided, {
|
|
345
|
+
session: { request, exchange: options.exchangeSession },
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
if (store.confirmations !== undefined) {
|
|
349
|
+
// @legacy agent.retired-confirmation-ledger
|
|
350
|
+
yield* router.add("POST", `${AGENT_PATH}/confirmations`, asRuntime(confirmationCommand(store.confirmations)));
|
|
351
|
+
}
|
|
352
|
+
yield* router.add("POST", PAIRINGS_PATH, asRuntime(createPairing(store, limiter)));
|
|
353
|
+
yield* router.add("GET", `${PAIRINGS_PATH}/:code`, asMember(() => describePairing(store)));
|
|
354
|
+
yield* router.add("POST", `${PAIRINGS_PATH}/:code/approve`, asMember((_, member) => approvePairing(store, member)));
|
|
355
|
+
yield* router.add("GET", IDENTITIES_PATH, asMember((_, member) => listIdentities(store, member)));
|
|
356
|
+
yield* router.add("GET", `${IDENTITIES_PATH}/:provider/:external_id`, asRuntime(() => resolveIdentity(store)));
|
|
357
|
+
yield* router.add("POST", `${IDENTITIES_PATH}/resolve`, asRuntime(resolveChannelIdentity(store)));
|
|
358
|
+
yield* router.add("POST", `${IDENTITIES_PATH}/notice`, asRuntime(recordNotice(store)));
|
|
359
|
+
yield* router.add("POST", `${IDENTITIES_PATH}/limit-notice`, asRuntime(completeLimitNotice(store)));
|
|
360
|
+
for (const blocked of [true, false]) {
|
|
361
|
+
const operation = blocked ? "block" : "unblock";
|
|
362
|
+
yield* router.add("POST", `${AGENT_PATH}/members/:id/${operation}`, asRuntime(() => Effect.gen(function* () {
|
|
363
|
+
const requestId = yield* RequestId;
|
|
364
|
+
const id = yield* routeParam("id");
|
|
365
|
+
const updated = yield* store.setMemberBlocked({ id, blocked });
|
|
366
|
+
return updated
|
|
367
|
+
? HttpServerResponse.empty({ status: 204, headers: NO_STORE })
|
|
368
|
+
: toServerResponse(notFound(requestId, "not_found"));
|
|
369
|
+
})));
|
|
370
|
+
}
|
|
371
|
+
yield* router.add("POST", CHATS_SEEN_PATH, asRuntime(seeChat(store)));
|
|
372
|
+
yield* router.add("DELETE", `${IDENTITIES_PATH}/:id`, asMember((_, member) => revokeIdentity(store, member)));
|
|
373
|
+
}));
|
|
374
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Effect, Redacted } from "effect";
|
|
2
|
+
import type { AgentTaskRecord } from "../../runtime/agent-tasks.js";
|
|
3
|
+
import type { Principal } from "../../runtime.js";
|
|
4
|
+
import { OntologyBackend } from "../runtime-contract.js";
|
|
5
|
+
/** How a principal that a task's secret authenticated says it authenticated. */
|
|
6
|
+
export declare const AGENT_TASK_AUTHENTICATION = "agent_task";
|
|
7
|
+
export type AgentTaskCaller = {
|
|
8
|
+
readonly status: "live";
|
|
9
|
+
readonly task: AgentTaskRecord;
|
|
10
|
+
readonly principal: Principal;
|
|
11
|
+
} | {
|
|
12
|
+
readonly status: "refused";
|
|
13
|
+
readonly detail: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The live task a secret names and the user it acts as: its workflow's user, resolved as the
|
|
17
|
+
* workflow's steps resolve it, with the roles it holds now. Refused when the secret matches no live
|
|
18
|
+
* task (an unknown secret, a terminal task or one past its deadline) or the workflow user is
|
|
19
|
+
* missing or inactive. The ontology resolves the identity from the task; the caller never names it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function agentTaskCaller(secret: Redacted.Redacted<string>, workspaceId: string): Effect.Effect<AgentTaskCaller, never, OntologyBackend>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Effect, Redacted } from "effect";
|
|
2
|
+
import { OntologyBackend } from "../runtime-contract.js";
|
|
3
|
+
import { taskSecretSha256 } from "./task-start.js";
|
|
4
|
+
/** How a principal that a task's secret authenticated says it authenticated. */
|
|
5
|
+
export const AGENT_TASK_AUTHENTICATION = "agent_task";
|
|
6
|
+
/**
|
|
7
|
+
* The live task a secret names and the user it acts as: its workflow's user, resolved as the
|
|
8
|
+
* workflow's steps resolve it, with the roles it holds now. Refused when the secret matches no live
|
|
9
|
+
* task (an unknown secret, a terminal task or one past its deadline) or the workflow user is
|
|
10
|
+
* missing or inactive. The ontology resolves the identity from the task; the caller never names it.
|
|
11
|
+
*/
|
|
12
|
+
export function agentTaskCaller(secret, workspaceId) {
|
|
13
|
+
return Effect.gen(function* () {
|
|
14
|
+
const backend = yield* OntologyBackend;
|
|
15
|
+
const task = backend.agentTasks === undefined
|
|
16
|
+
? undefined
|
|
17
|
+
: yield* backend.agentTasks.live(taskSecretSha256(Redacted.value(secret)));
|
|
18
|
+
if (task === undefined) {
|
|
19
|
+
return { status: "refused", detail: "The task secret matches no live task." };
|
|
20
|
+
}
|
|
21
|
+
const principal = backend.resolveWorkflowUser === undefined
|
|
22
|
+
? undefined
|
|
23
|
+
: yield* backend.resolveWorkflowUser({ workspaceId, workflow: task.workflow });
|
|
24
|
+
return principal === undefined
|
|
25
|
+
? {
|
|
26
|
+
status: "refused",
|
|
27
|
+
detail: `The workflow user of ${task.workflow} is missing or inactive.`,
|
|
28
|
+
}
|
|
29
|
+
: {
|
|
30
|
+
status: "live",
|
|
31
|
+
task,
|
|
32
|
+
principal: { ...principal, authenticatedVia: AGENT_TASK_AUTHENTICATION },
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|