@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
package/dist/role.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type ScopedPermission } from "./permissions.js";
|
|
2
|
+
export declare const RoleTypeId: unique symbol;
|
|
3
|
+
/**
|
|
4
|
+
* A business role: a named set of permissions. Members are given roles from the CLI or the app; an
|
|
5
|
+
* API key holds exactly the roles it was created with.
|
|
6
|
+
*/
|
|
7
|
+
export interface Role<Name extends string = string> {
|
|
8
|
+
readonly [RoleTypeId]: typeof RoleTypeId;
|
|
9
|
+
readonly name: Name;
|
|
10
|
+
readonly description: string;
|
|
11
|
+
/**
|
|
12
|
+
* What the role may do, as `<entity>:<verb>` permissions: `lead:read`, `lead:changeStatus`. `*`
|
|
13
|
+
* stands for any entity or any verb: `lead:*`, `*:read`, `*:*`. Scoped permissions are listed
|
|
14
|
+
* too, once each, so that whatever reads permissions sees every one the role holds.
|
|
15
|
+
*/
|
|
16
|
+
readonly permissions: ReadonlyArray<string>;
|
|
17
|
+
/**
|
|
18
|
+
* The scoped permissions, with their `where`, in declaration order. A permission the role also
|
|
19
|
+
* grants unscoped is not scoped: the unscoped grant covers every record.
|
|
20
|
+
*/
|
|
21
|
+
readonly scopes: ReadonlyArray<ScopedPermission>;
|
|
22
|
+
/**
|
|
23
|
+
* Scoped entries the role also grants unscoped by the same permission, dropped from `scopes`;
|
|
24
|
+
* kept only for `check` to report. Never in the manifest.
|
|
25
|
+
*/
|
|
26
|
+
readonly unusedScopes?: ReadonlyArray<ScopedPermission>;
|
|
27
|
+
}
|
|
28
|
+
/** A role permission: `<entity>:<verb>`, or a scoped one, `{ permission, where }`. */
|
|
29
|
+
export type RolePermission = string | ScopedPermission;
|
|
30
|
+
export interface RoleOptions {
|
|
31
|
+
readonly description: string;
|
|
32
|
+
/**
|
|
33
|
+
* At least one permission; `check` refuses a role without any. A string grants every record; a
|
|
34
|
+
* {@link ScopedPermission} only those its `where` matches.
|
|
35
|
+
*/
|
|
36
|
+
readonly permissions: ReadonlyArray<RolePermission>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The permissions and scopes of a role's entries. A string is kept as written, even twice, so that
|
|
40
|
+
* an ontology without scoped permissions lists exactly what it declares; a scoped entry adds its
|
|
41
|
+
* permission once, and is dropped into `unusedScopes` when the role grants the same permission
|
|
42
|
+
* unscoped, in any case. Anything else is kept for `check` to report.
|
|
43
|
+
*/
|
|
44
|
+
export declare function rolePermissions(entries: ReadonlyArray<RolePermission>): {
|
|
45
|
+
readonly permissions: ReadonlyArray<string>;
|
|
46
|
+
readonly scopes: ReadonlyArray<ScopedPermission>;
|
|
47
|
+
readonly unusedScopes?: ReadonlyArray<ScopedPermission>;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* A role's entries rebuilt from its permissions and scopes, as a manifest lists them: each scoped
|
|
51
|
+
* permission at its place, once per scope. A scope whose permission the list lacks comes last.
|
|
52
|
+
*/
|
|
53
|
+
export declare function roleEntries(permissions: ReadonlyArray<string>, scopes: ReadonlyArray<ScopedPermission>): ReadonlyArray<RolePermission>;
|
|
54
|
+
export declare function role<const Name extends string>(name: Name, options: RoleOptions): Role<Name>;
|
|
55
|
+
export declare function isRole(value: unknown): value is Role;
|
|
56
|
+
/**
|
|
57
|
+
* The built-in role every active app user holds, with its default permissions. An ontology sets
|
|
58
|
+
* what members may do with `defineOntology({ member: { permissions } })`. Service principals hold
|
|
59
|
+
* only the roles they were given.
|
|
60
|
+
*/
|
|
61
|
+
export declare const member: Role<"member">;
|
package/dist/role.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { MEMBER_ROLE } from "./names.js";
|
|
2
|
+
import { DEFAULT_MEMBER_PERMISSIONS, normalizePermission, } from "./permissions.js";
|
|
3
|
+
export const RoleTypeId = Symbol.for("@segmentstream/ontology/Role");
|
|
4
|
+
function isScoped(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The permissions and scopes of a role's entries. A string is kept as written, even twice, so that
|
|
9
|
+
* an ontology without scoped permissions lists exactly what it declares; a scoped entry adds its
|
|
10
|
+
* permission once, and is dropped into `unusedScopes` when the role grants the same permission
|
|
11
|
+
* unscoped, in any case. Anything else is kept for `check` to report.
|
|
12
|
+
*/
|
|
13
|
+
export function rolePermissions(entries) {
|
|
14
|
+
if (!Array.isArray(entries)) {
|
|
15
|
+
return { permissions: entries, scopes: [] };
|
|
16
|
+
}
|
|
17
|
+
const normalized = (value) => typeof value === "string" ? normalizePermission(value) : value;
|
|
18
|
+
const unscoped = new Set(entries.filter((entry) => !isScoped(entry)).map(normalized));
|
|
19
|
+
const permissions = [];
|
|
20
|
+
const scopes = [];
|
|
21
|
+
const unusedScopes = [];
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
if (!isScoped(entry)) {
|
|
24
|
+
permissions.push(entry);
|
|
25
|
+
}
|
|
26
|
+
else if (unscoped.has(normalized(entry.permission))) {
|
|
27
|
+
unusedScopes.push(entry);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
if (!permissions.includes(entry.permission)) {
|
|
31
|
+
permissions.push(entry.permission);
|
|
32
|
+
}
|
|
33
|
+
scopes.push(entry);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { permissions, scopes, ...(unusedScopes.length === 0 ? {} : { unusedScopes }) };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A role's entries rebuilt from its permissions and scopes, as a manifest lists them: each scoped
|
|
40
|
+
* permission at its place, once per scope. A scope whose permission the list lacks comes last.
|
|
41
|
+
*/
|
|
42
|
+
export function roleEntries(permissions, scopes) {
|
|
43
|
+
return [
|
|
44
|
+
...permissions.flatMap((permission) => {
|
|
45
|
+
const own = scopes.filter((scope) => scope.permission === permission);
|
|
46
|
+
return own.length === 0 ? [permission] : own;
|
|
47
|
+
}),
|
|
48
|
+
...scopes.filter((scope) => !permissions.includes(scope.permission)),
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
// @legacy ontology.removed-allow-option
|
|
52
|
+
/** Options removed from earlier releases, kept on the role so that `check` can explain them. */
|
|
53
|
+
function removedOptions(options) {
|
|
54
|
+
return "allow" in options ? { allow: options.allow } : {};
|
|
55
|
+
}
|
|
56
|
+
export function role(name, options) {
|
|
57
|
+
return {
|
|
58
|
+
...removedOptions(options),
|
|
59
|
+
[RoleTypeId]: RoleTypeId,
|
|
60
|
+
name,
|
|
61
|
+
description: options.description,
|
|
62
|
+
...rolePermissions(options.permissions),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function isRole(value) {
|
|
66
|
+
return typeof value === "object" && value !== null && RoleTypeId in value;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The built-in role every active app user holds, with its default permissions. An ontology sets
|
|
70
|
+
* what members may do with `defineOntology({ member: { permissions } })`. Service principals hold
|
|
71
|
+
* only the roles they were given.
|
|
72
|
+
*/
|
|
73
|
+
export const member = role(MEMBER_ROLE, {
|
|
74
|
+
description: "Every active app user.",
|
|
75
|
+
permissions: DEFAULT_MEMBER_PERMISSIONS,
|
|
76
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { SqlClient } from "effect/unstable/sql";
|
|
3
|
+
import { type SqlError } from "effect/unstable/sql/SqlError";
|
|
4
|
+
import { Conflict } from "../errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* Owns complete SQL transactions, never an aborted transaction's statements. The caller admits
|
|
7
|
+
* this entire effect once. Each body is built anew; only its successful attempt's state escapes.
|
|
8
|
+
*/
|
|
9
|
+
export declare function actionTransaction<A, E, R>(sql: Pick<SqlClient.SqlClient, "withTransaction">, body: () => Effect.Effect<A, E, R>, options: {
|
|
10
|
+
readonly qualified: string;
|
|
11
|
+
readonly actionId?: string;
|
|
12
|
+
readonly requestId?: string;
|
|
13
|
+
readonly retryOnDeadlock: boolean;
|
|
14
|
+
readonly handlerTimeoutMs: number;
|
|
15
|
+
/**
|
|
16
|
+
* Whether a cleanly rolled-back conflict may be answered as a retryable Conflict: true unless
|
|
17
|
+
* sending the request again would repeat an effect outside the transaction, such as a
|
|
18
|
+
* connection call in `prepare`. Absent means true.
|
|
19
|
+
*/
|
|
20
|
+
readonly conflictRetryable?: boolean;
|
|
21
|
+
}): Effect.Effect<A, E | SqlError | Conflict, R>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { randomInt } from "node:crypto";
|
|
2
|
+
import { Cause, Clock, Duration, Effect, Exit } from "effect";
|
|
3
|
+
import { isSqlError } from "effect/unstable/sql/SqlError";
|
|
4
|
+
import { Conflict } from "../errors.js";
|
|
5
|
+
import { captureRuntimeFailure } from "../internal/diagnostics.js";
|
|
6
|
+
import { ActionTransactionDeadline } from "./action-transactions.js";
|
|
7
|
+
const MAX_DEADLOCK_RETRIES = 2;
|
|
8
|
+
const monotonicMillis = Clock.monotonicTimeNanos.pipe(Effect.map((nanos) => Number(nanos) / 1_000_000));
|
|
9
|
+
/** A distinct failure prevents Effect from deduplicating equal body and cleanup SQL errors. */
|
|
10
|
+
class AttemptFailure {
|
|
11
|
+
cause;
|
|
12
|
+
constructor(cause) {
|
|
13
|
+
this.cause = cause;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The SQLSTATE of the one original PostgreSQL failure, when it is a deadlock (`40P01`) or a
|
|
18
|
+
* serialization failure (`40001`) with no interruption or cleanup failure alongside it. Both mean
|
|
19
|
+
* PostgreSQL chose this transaction to roll back because of a concurrent one.
|
|
20
|
+
*/
|
|
21
|
+
function rolledBackConflictOf(cause) {
|
|
22
|
+
if (cause?.reasons.length !== 1) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
const reason = cause.reasons[0];
|
|
26
|
+
const error = reason._tag === "Fail" ? reason.error : reason._tag === "Die" ? reason.defect : undefined;
|
|
27
|
+
if (!isSqlError(error)) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const driver = error.reason.cause;
|
|
31
|
+
const code = typeof driver === "object" && driver !== null && "code" in driver ? driver.code : undefined;
|
|
32
|
+
if (error.reason._tag === "DeadlockError" && code === "40P01") {
|
|
33
|
+
return "40P01";
|
|
34
|
+
}
|
|
35
|
+
return error.reason._tag === "SerializationError" && code === "40001" ? "40001" : undefined;
|
|
36
|
+
}
|
|
37
|
+
/** Only one original PostgreSQL deadlock, with no interruption or cleanup failure alongside it. */
|
|
38
|
+
function deadlockOf(cause) {
|
|
39
|
+
return rolledBackConflictOf(cause) === "40P01";
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Owns complete SQL transactions, never an aborted transaction's statements. The caller admits
|
|
43
|
+
* this entire effect once. Each body is built anew; only its successful attempt's state escapes.
|
|
44
|
+
*/
|
|
45
|
+
export function actionTransaction(sql, body, options) {
|
|
46
|
+
return Effect.gen(function* () {
|
|
47
|
+
let deadlineAt;
|
|
48
|
+
for (let retries = 0;; retries += 1) {
|
|
49
|
+
let failedBody;
|
|
50
|
+
const transaction = sql.withTransaction(Effect.gen(function* () {
|
|
51
|
+
const now = yield* monotonicMillis;
|
|
52
|
+
deadlineAt ??= now + options.handlerTimeoutMs;
|
|
53
|
+
const expired = Effect.logWarning("ontology.action.transaction_deadline").pipe(Effect.annotateLogs({ deadlineMs: options.handlerTimeoutMs }), Effect.andThen(Effect.die(new ActionTransactionDeadline(`${options.qualified} exceeded its transaction deadline.`))));
|
|
54
|
+
if (deadlineAt <= now) {
|
|
55
|
+
return yield* expired;
|
|
56
|
+
}
|
|
57
|
+
return yield* Effect.suspend(body).pipe(Effect.timeoutOrElse({
|
|
58
|
+
duration: Duration.millis(deadlineAt - now),
|
|
59
|
+
orElse: () => expired,
|
|
60
|
+
}), Effect.catchCause((cause) => {
|
|
61
|
+
failedBody = new AttemptFailure(cause);
|
|
62
|
+
return Effect.fail(failedBody);
|
|
63
|
+
}));
|
|
64
|
+
}));
|
|
65
|
+
// Effect SQL finalizes uninterruptibly, including rollback and connection release. Only a
|
|
66
|
+
// body failure that survives finalization unchanged proves a completed, clean rollback.
|
|
67
|
+
// Acquisition, BEGIN, COMMIT and cleanup failures can never satisfy both checks.
|
|
68
|
+
const settled = yield* Effect.exit(transaction);
|
|
69
|
+
if (Exit.isSuccess(settled)) {
|
|
70
|
+
return settled.value;
|
|
71
|
+
}
|
|
72
|
+
const reasons = settled.cause.reasons;
|
|
73
|
+
const cleanRollback = reasons.length === 1 && reasons[0]._tag === "Fail" && reasons[0].error === failedBody;
|
|
74
|
+
const deadlock = deadlockOf(failedBody?.cause);
|
|
75
|
+
const conflict = cleanRollback && options.conflictRetryable !== false
|
|
76
|
+
? rolledBackConflictOf(failedBody?.cause)
|
|
77
|
+
: undefined;
|
|
78
|
+
// Restore the exact original reasons, including defects/interruptions, alongside any
|
|
79
|
+
// transaction finalization failures. The private marker never reaches public diagnostics.
|
|
80
|
+
const cause = Cause.fromReasons(reasons.flatMap((reason) => reason._tag === "Fail" && reason.error instanceof AttemptFailure
|
|
81
|
+
? reason.error.cause.reasons
|
|
82
|
+
: [reason]));
|
|
83
|
+
// A conflict PostgreSQL rolled back cleanly wrote nothing, so the caller may send the same
|
|
84
|
+
// request again: answer it as a retryable Conflict, and keep the original cause for operators.
|
|
85
|
+
// An action whose prepare called a connection is not: a resend would call it again.
|
|
86
|
+
const settle = () => conflict === undefined
|
|
87
|
+
? Effect.failCause(cause)
|
|
88
|
+
: Effect.sync(() => captureRuntimeFailure(cause, {
|
|
89
|
+
service: "ontology",
|
|
90
|
+
boundary: "ontology.action.transaction_conflict",
|
|
91
|
+
severity: "warning",
|
|
92
|
+
action: options.qualified,
|
|
93
|
+
actionId: options.actionId,
|
|
94
|
+
requestId: options.requestId,
|
|
95
|
+
retries,
|
|
96
|
+
sqlState: conflict,
|
|
97
|
+
})).pipe(Effect.andThen(Effect.fail(new Conflict({
|
|
98
|
+
entity: options.qualified.split(".")[0] ?? options.qualified,
|
|
99
|
+
message: `${options.qualified} conflicted with a concurrent change and was rolled ` +
|
|
100
|
+
"back; nothing was written. Send the same request again.",
|
|
101
|
+
retryAfter: 1,
|
|
102
|
+
}))));
|
|
103
|
+
if (!options.retryOnDeadlock ||
|
|
104
|
+
retries >= MAX_DEADLOCK_RETRIES ||
|
|
105
|
+
!deadlock ||
|
|
106
|
+
!cleanRollback) {
|
|
107
|
+
return yield* settle();
|
|
108
|
+
}
|
|
109
|
+
const delayMs = randomInt(10, 51) * 2 ** retries;
|
|
110
|
+
const now = yield* monotonicMillis;
|
|
111
|
+
// Retry backoff and finalization consume the same budget as the first body. Do not replace
|
|
112
|
+
// the original deadlock when there is insufficient time for another attempt.
|
|
113
|
+
if (deadlineAt === undefined || deadlineAt - now <= delayMs) {
|
|
114
|
+
return yield* settle();
|
|
115
|
+
}
|
|
116
|
+
yield* Effect.sync(() => captureRuntimeFailure(cause, {
|
|
117
|
+
service: "ontology",
|
|
118
|
+
boundary: "ontology.action.deadlock_retry",
|
|
119
|
+
severity: "warning",
|
|
120
|
+
action: options.qualified,
|
|
121
|
+
actionId: options.actionId,
|
|
122
|
+
requestId: options.requestId,
|
|
123
|
+
retry: retries + 1,
|
|
124
|
+
delayMs,
|
|
125
|
+
sqlState: "40P01",
|
|
126
|
+
}));
|
|
127
|
+
yield* Effect.sleep(Duration.millis(delayMs));
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Context, Effect } from "effect";
|
|
2
|
+
/** Admission happens before reserving SQL connections; two pool slots remain for other work. */
|
|
3
|
+
export declare const ACTION_TRANSACTION_LIMITS: {
|
|
4
|
+
readonly concurrency: 3;
|
|
5
|
+
readonly maxWaiting: 32;
|
|
6
|
+
readonly queueTimeoutMs: 5000;
|
|
7
|
+
readonly handlerTimeoutMs: 60000;
|
|
8
|
+
readonly statementTimeoutMs: 30000;
|
|
9
|
+
readonly lockTimeoutMs: 5000;
|
|
10
|
+
};
|
|
11
|
+
export interface ActionTransactionLimits {
|
|
12
|
+
readonly handlerTimeoutMs: number;
|
|
13
|
+
readonly statementTimeoutMs: number;
|
|
14
|
+
readonly lockTimeoutMs: number;
|
|
15
|
+
}
|
|
16
|
+
export declare class ActionTransactionDeadline extends Error {
|
|
17
|
+
readonly name = "ActionTransactionDeadline";
|
|
18
|
+
}
|
|
19
|
+
export declare class ActionAdmissionRejected extends Error {
|
|
20
|
+
readonly name = "ActionAdmissionRejected";
|
|
21
|
+
}
|
|
22
|
+
export interface ActionTransactionsService {
|
|
23
|
+
readonly limits: ActionTransactionLimits;
|
|
24
|
+
readonly admit: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
|
|
25
|
+
}
|
|
26
|
+
declare const ActionTransactions_base: Context.ServiceClass<ActionTransactions, "segmentstream/ontology/ActionTransactions", ActionTransactionsService>;
|
|
27
|
+
/** Internal configuration and one admission gate per service instance, never per request. */
|
|
28
|
+
export declare class ActionTransactions extends ActionTransactions_base {
|
|
29
|
+
}
|
|
30
|
+
export declare function makeActionTransactions(options?: ActionTransactionLimits & {
|
|
31
|
+
readonly concurrency: number;
|
|
32
|
+
readonly maxWaiting: number;
|
|
33
|
+
readonly queueTimeoutMs: number;
|
|
34
|
+
}): ActionTransactionsService;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Context, Duration, Effect, Exit, Semaphore } from "effect";
|
|
2
|
+
/** Admission happens before reserving SQL connections; two pool slots remain for other work. */
|
|
3
|
+
export const ACTION_TRANSACTION_LIMITS = {
|
|
4
|
+
concurrency: 3,
|
|
5
|
+
maxWaiting: 32,
|
|
6
|
+
queueTimeoutMs: 5_000,
|
|
7
|
+
handlerTimeoutMs: 60_000,
|
|
8
|
+
statementTimeoutMs: 30_000,
|
|
9
|
+
lockTimeoutMs: 5_000,
|
|
10
|
+
};
|
|
11
|
+
export class ActionTransactionDeadline extends Error {
|
|
12
|
+
name = "ActionTransactionDeadline";
|
|
13
|
+
}
|
|
14
|
+
export class ActionAdmissionRejected extends Error {
|
|
15
|
+
name = "ActionAdmissionRejected";
|
|
16
|
+
}
|
|
17
|
+
/** Internal configuration and one admission gate per service instance, never per request. */
|
|
18
|
+
export class ActionTransactions extends Context.Service()("segmentstream/ontology/ActionTransactions") {
|
|
19
|
+
}
|
|
20
|
+
export function makeActionTransactions(options = ACTION_TRANSACTION_LIMITS) {
|
|
21
|
+
const permits = Semaphore.makeUnsafe(options.concurrency);
|
|
22
|
+
let waiting = 0;
|
|
23
|
+
let active = 0;
|
|
24
|
+
return {
|
|
25
|
+
limits: options,
|
|
26
|
+
admit: (effect) => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
|
|
27
|
+
const queuedAt = Date.now();
|
|
28
|
+
if (!(yield* permits.takeIfAvailable(1))) {
|
|
29
|
+
if (waiting >= options.maxWaiting) {
|
|
30
|
+
yield* Effect.logWarning("ontology.action.admission_rejected").pipe(Effect.annotateLogs({ active, waiting, reason: "queue_full" }));
|
|
31
|
+
return yield* Effect.die(new ActionAdmissionRejected("Action write queue is full."));
|
|
32
|
+
}
|
|
33
|
+
waiting += 1;
|
|
34
|
+
yield* restore(permits.take(1).pipe(Effect.timeoutOrElse({
|
|
35
|
+
duration: Duration.millis(options.queueTimeoutMs),
|
|
36
|
+
orElse: () => Effect.logWarning("ontology.action.admission_rejected").pipe(Effect.annotateLogs({ active, waiting, reason: "queue_timeout" }), Effect.andThen(Effect.die(new ActionAdmissionRejected("Action write admission timed out.")))),
|
|
37
|
+
}))).pipe(Effect.ensuring(Effect.sync(() => {
|
|
38
|
+
waiting -= 1;
|
|
39
|
+
})));
|
|
40
|
+
}
|
|
41
|
+
active += 1;
|
|
42
|
+
const startedAt = Date.now();
|
|
43
|
+
return yield* restore(effect).pipe(Effect.onExit((exit) => Effect.logDebug("ontology.action.transaction_completed").pipe(Effect.annotateLogs({
|
|
44
|
+
active,
|
|
45
|
+
waiting,
|
|
46
|
+
queueMs: startedAt - queuedAt,
|
|
47
|
+
transactionMs: Date.now() - startedAt,
|
|
48
|
+
outcome: Exit.isSuccess(exit) ? "success" : "failure",
|
|
49
|
+
}))), Effect.ensuring(Effect.sync(() => {
|
|
50
|
+
active -= 1;
|
|
51
|
+
}).pipe(Effect.andThen(permits.release(1)))));
|
|
52
|
+
})),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { SqlClient } from "effect/unstable/sql";
|
|
3
|
+
import type { AgentLimits, AgentLimitScope, AgentResolution, ResolveIdentityInput } from "../service/runtime-contract.js";
|
|
4
|
+
/** Defaults shared by bot resolution and other trusted channel admission boundaries. */
|
|
5
|
+
export declare const DEFAULT_AGENT_LIMITS: AgentLimits;
|
|
6
|
+
/** Platform ceilings. Workspace policy can only lower these values. */
|
|
7
|
+
export declare const PLATFORM_CHANNEL_LIMITS: AgentLimits;
|
|
8
|
+
export declare function clampChannelLimits(input: ResolveIdentityInput["limits"]): AgentLimits;
|
|
9
|
+
/** Only trusted runtimes submit limits; channel-app callers omit them and reuse the latest policy. */
|
|
10
|
+
export declare function effectiveChannelLimits(sql: SqlClient.SqlClient, input?: ResolveIdentityInput["limits"]): Effect.Effect<AgentLimits, never, never>;
|
|
11
|
+
type Limited = Extract<AgentResolution, {
|
|
12
|
+
status: "limited";
|
|
13
|
+
}>;
|
|
14
|
+
/** A failed send releases its claim; a lost process can be retried after a 30-second lease. */
|
|
15
|
+
export declare function completeAgentLimitNotice(sql: SqlClient.SqlClient, input: {
|
|
16
|
+
readonly notificationId: string;
|
|
17
|
+
readonly delivered: boolean;
|
|
18
|
+
}): Effect.Effect<boolean, never, never>;
|
|
19
|
+
/** Count attempts durably; notify once per effective threshold within each fixed window. */
|
|
20
|
+
export declare function countAgentAttempt(sql: SqlClient.SqlClient, input: {
|
|
21
|
+
readonly scope: AgentLimitScope;
|
|
22
|
+
readonly subject: string;
|
|
23
|
+
readonly window: "minute" | "hour" | "day";
|
|
24
|
+
readonly limit: number;
|
|
25
|
+
}): Effect.Effect<Limited | undefined>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { Effect, Schema } from "effect";
|
|
3
|
+
import { AGENT_COUNTERS_TABLE, CHANNEL_LIMITS_TABLE } from "../migrate/storage.js";
|
|
4
|
+
/** Defaults shared by bot resolution and other trusted channel admission boundaries. */
|
|
5
|
+
export const DEFAULT_AGENT_LIMITS = Object.freeze({
|
|
6
|
+
perSender: Object.freeze({ turnsPerMinute: 6, turnsPerDay: 80 }),
|
|
7
|
+
newUsersPerHour: 30,
|
|
8
|
+
workspaceTurnsPerDay: 3000,
|
|
9
|
+
});
|
|
10
|
+
/** Platform ceilings. Workspace policy can only lower these values. */
|
|
11
|
+
export const PLATFORM_CHANNEL_LIMITS = DEFAULT_AGENT_LIMITS;
|
|
12
|
+
const Limits = Schema.Struct({
|
|
13
|
+
perSender: Schema.Struct({ turnsPerMinute: Schema.Int, turnsPerDay: Schema.Int }),
|
|
14
|
+
newUsersPerHour: Schema.Int,
|
|
15
|
+
workspaceTurnsPerDay: Schema.Int,
|
|
16
|
+
});
|
|
17
|
+
export function clampChannelLimits(input) {
|
|
18
|
+
const clamp = (value, ceiling) => Number.isSafeInteger(value) && value > 0 ? Math.min(value, ceiling) : ceiling;
|
|
19
|
+
return {
|
|
20
|
+
perSender: {
|
|
21
|
+
turnsPerMinute: clamp(input?.perSender?.turnsPerMinute, PLATFORM_CHANNEL_LIMITS.perSender.turnsPerMinute),
|
|
22
|
+
turnsPerDay: clamp(input?.perSender?.turnsPerDay, PLATFORM_CHANNEL_LIMITS.perSender.turnsPerDay),
|
|
23
|
+
},
|
|
24
|
+
newUsersPerHour: clamp(input?.newUsersPerHour, PLATFORM_CHANNEL_LIMITS.newUsersPerHour),
|
|
25
|
+
workspaceTurnsPerDay: clamp(input?.workspaceTurnsPerDay, PLATFORM_CHANNEL_LIMITS.workspaceTurnsPerDay),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Only trusted runtimes submit limits; channel-app callers omit them and reuse the latest policy. */
|
|
29
|
+
export function effectiveChannelLimits(sql, input) {
|
|
30
|
+
return Effect.gen(function* () {
|
|
31
|
+
if (input !== undefined) {
|
|
32
|
+
const limits = clampChannelLimits(input);
|
|
33
|
+
yield* sql.unsafe(`INSERT INTO "${CHANNEL_LIMITS_TABLE}" ("id", "limits") VALUES (true, $1::jsonb)
|
|
34
|
+
ON CONFLICT ("id") DO UPDATE SET "limits" = EXCLUDED."limits"`, [JSON.stringify(limits)]);
|
|
35
|
+
return limits;
|
|
36
|
+
}
|
|
37
|
+
const [stored] = yield* sql.unsafe(`SELECT "limits" FROM "${CHANNEL_LIMITS_TABLE}" WHERE "id"`);
|
|
38
|
+
return stored === undefined
|
|
39
|
+
? DEFAULT_AGENT_LIMITS
|
|
40
|
+
: clampChannelLimits(Schema.decodeUnknownSync(Limits)(stored.limits));
|
|
41
|
+
}).pipe(Effect.orDie);
|
|
42
|
+
}
|
|
43
|
+
const Counter = Schema.Struct({ count: Schema.Int, retry_after: Schema.Int });
|
|
44
|
+
const decodeCounter = Schema.decodeUnknownSync(Counter);
|
|
45
|
+
/** A failed send releases its claim; a lost process can be retried after a 30-second lease. */
|
|
46
|
+
export function completeAgentLimitNotice(sql, input) {
|
|
47
|
+
const statement = input.delivered
|
|
48
|
+
? `UPDATE "${AGENT_COUNTERS_TABLE}" SET "count" = 1, "notification_claimed_until" = NULL`
|
|
49
|
+
: `DELETE FROM "${AGENT_COUNTERS_TABLE}"`;
|
|
50
|
+
return sql
|
|
51
|
+
.unsafe(`${statement}
|
|
52
|
+
WHERE "notification_claim" = $1::uuid AND "count" = 0 RETURNING "key"`, [input.notificationId])
|
|
53
|
+
.pipe(Effect.map((updated) => updated.length > 0), Effect.orDie);
|
|
54
|
+
}
|
|
55
|
+
/** Count attempts durably; notify once per effective threshold within each fixed window. */
|
|
56
|
+
export function countAgentAttempt(sql, input) {
|
|
57
|
+
return Effect.gen(function* () {
|
|
58
|
+
const [stored] = yield* sql.unsafe(`INSERT INTO "${AGENT_COUNTERS_TABLE}" ("key", "window_start", "count")
|
|
59
|
+
VALUES ($1, date_trunc($2, now()), 1)
|
|
60
|
+
ON CONFLICT ("key", "window_start") DO UPDATE
|
|
61
|
+
SET "count" = "${AGENT_COUNTERS_TABLE}"."count" + 1
|
|
62
|
+
RETURNING "count", ceil(extract(epoch FROM
|
|
63
|
+
"window_start" + ('1 ' || $2)::interval - now()))::int AS "retry_after"`, [`${input.scope}:${input.subject}`, input.window]);
|
|
64
|
+
if (stored === undefined) {
|
|
65
|
+
return yield* Effect.die(new Error("Agent counter did not return its count."));
|
|
66
|
+
}
|
|
67
|
+
const counter = decodeCounter(stored);
|
|
68
|
+
if (counter.count === 1) {
|
|
69
|
+
// Bound maintenance work under admission locks and leave busy windows to another request.
|
|
70
|
+
yield* sql.unsafe(`DELETE FROM "${AGENT_COUNTERS_TABLE}"
|
|
71
|
+
WHERE ctid IN (
|
|
72
|
+
SELECT ctid FROM "${AGENT_COUNTERS_TABLE}"
|
|
73
|
+
WHERE "window_start" < date_trunc('day', now()) - interval '1 day'
|
|
74
|
+
LIMIT 100
|
|
75
|
+
FOR UPDATE SKIP LOCKED
|
|
76
|
+
)`);
|
|
77
|
+
}
|
|
78
|
+
if (counter.count <= input.limit) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
const [claimed] = yield* sql.unsafe(`INSERT INTO "${AGENT_COUNTERS_TABLE}"
|
|
82
|
+
("key", "window_start", "count", "notification_claim", "notification_claimed_until")
|
|
83
|
+
VALUES ($1, date_trunc($2, now()), 0, $3::uuid, now() + interval '30 seconds')
|
|
84
|
+
ON CONFLICT ("key", "window_start") DO UPDATE
|
|
85
|
+
SET "notification_claim" = EXCLUDED."notification_claim",
|
|
86
|
+
"notification_claimed_until" = EXCLUDED."notification_claimed_until"
|
|
87
|
+
WHERE "${AGENT_COUNTERS_TABLE}"."count" = 0
|
|
88
|
+
AND "${AGENT_COUNTERS_TABLE}"."notification_claimed_until" <= now()
|
|
89
|
+
RETURNING "notification_claim"`, [`notify:${input.scope}:${input.subject}:${input.limit}`, input.window, randomUUID()]);
|
|
90
|
+
return {
|
|
91
|
+
status: "limited",
|
|
92
|
+
scope: input.scope,
|
|
93
|
+
retryAfterSeconds: Math.max(1, counter.retry_after),
|
|
94
|
+
notify: claimed !== undefined,
|
|
95
|
+
...(claimed === undefined ? {} : { notificationId: claimed.notification_claim }),
|
|
96
|
+
};
|
|
97
|
+
}).pipe(Effect.orDie);
|
|
98
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { SqlClient } from "effect/unstable/sql";
|
|
3
|
+
import type { AgentTaskResult } from "../agent-task-contract.js";
|
|
4
|
+
/** A task's status: `pending` and `started` are live until the deadline; the others are terminal. */
|
|
5
|
+
export type AgentTaskStatus = "pending" | "started" | AgentTaskResult["status"];
|
|
6
|
+
/** One row of `_agent_tasks`, as the service reads it. Its secret's hash is never read back. */
|
|
7
|
+
export interface AgentTaskRecord {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
/** The workflow's wire name, whose user the task acts as. */
|
|
10
|
+
readonly workflow: string;
|
|
11
|
+
readonly runId: string;
|
|
12
|
+
readonly hookToken: string;
|
|
13
|
+
readonly prompt: string;
|
|
14
|
+
readonly status: AgentTaskStatus;
|
|
15
|
+
/** The terminal outcome; `undefined` while the task is live. */
|
|
16
|
+
readonly result: AgentTaskResult | undefined;
|
|
17
|
+
readonly deadlineAt: Date;
|
|
18
|
+
}
|
|
19
|
+
/** How long tasks are kept after their deadline, for diagnosis, before the next start deletes them. */
|
|
20
|
+
export declare const AGENT_TASK_RETENTION_DAYS = 30;
|
|
21
|
+
/** The task store: the ontology database's `_agent_tasks`, which the service reads and changes. */
|
|
22
|
+
export interface AgentTaskStore {
|
|
23
|
+
/** The task an `agentTask` call recorded under its hook token. */
|
|
24
|
+
readonly byHook: (hookToken: string) => Effect.Effect<AgentTaskRecord | undefined>;
|
|
25
|
+
/** The live task whose secret has this SHA-256: not terminal, and its deadline not passed. */
|
|
26
|
+
readonly live: (secretSha256: string) => Effect.Effect<AgentTaskRecord | undefined>;
|
|
27
|
+
/**
|
|
28
|
+
* Records a pending task, due `timeoutMs` from now on the database's clock, unless `limit` tasks
|
|
29
|
+
* are live: then `busy`, and nothing is written. A task the hook token already names is returned
|
|
30
|
+
* as it is. Tasks whose deadline passed {@link AGENT_TASK_RETENTION_DAYS} days ago are deleted.
|
|
31
|
+
*/
|
|
32
|
+
readonly create: (input: {
|
|
33
|
+
readonly hookToken: string;
|
|
34
|
+
readonly workflow: string;
|
|
35
|
+
readonly runId: string;
|
|
36
|
+
readonly prompt: string;
|
|
37
|
+
readonly timeoutMs: number;
|
|
38
|
+
readonly secretSha256: string;
|
|
39
|
+
readonly limit: number;
|
|
40
|
+
}) => Effect.Effect<{
|
|
41
|
+
readonly status: "created";
|
|
42
|
+
readonly task: AgentTaskRecord;
|
|
43
|
+
} | {
|
|
44
|
+
readonly status: "existing";
|
|
45
|
+
readonly task: AgentTaskRecord;
|
|
46
|
+
} | {
|
|
47
|
+
readonly status: "busy";
|
|
48
|
+
}>;
|
|
49
|
+
/** Replaces the secret of a pending task; `false` when it is no longer pending. */
|
|
50
|
+
readonly rekey: (id: string, secretSha256: string) => Effect.Effect<boolean>;
|
|
51
|
+
/** Marks a pending task started; `false` when it is no longer pending. */
|
|
52
|
+
readonly markStarted: (id: string) => Effect.Effect<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Makes a task that is not terminal end with `result`. The first outcome wins: `finished` is
|
|
55
|
+
* `false` when the task was already terminal, and `task` is the row after the attempt.
|
|
56
|
+
*/
|
|
57
|
+
readonly finish: (id: string, result: AgentTaskResult) => Effect.Effect<{
|
|
58
|
+
readonly finished: boolean;
|
|
59
|
+
readonly task: AgentTaskRecord | undefined;
|
|
60
|
+
}>;
|
|
61
|
+
}
|
|
62
|
+
/** The task store over `_agent_tasks`. Database failures are defects. */
|
|
63
|
+
export declare function sqlAgentTaskStore(sql: SqlClient.SqlClient): AgentTaskStore;
|