@segmentstream/ontology 0.0.0-stage → 0.92.1
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,24 @@
|
|
|
1
|
+
import type { EntityManifest, OntologyManifest } from "../manifest.js";
|
|
2
|
+
import { type Query } from "../query.js";
|
|
3
|
+
import type { StoredRecord } from "../runtime.js";
|
|
4
|
+
export interface WarehouseParameter {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly type: "STRING" | "INT64" | "FLOAT64" | "BOOL" | "DATE" | "TIMESTAMP";
|
|
7
|
+
readonly value?: string;
|
|
8
|
+
readonly values?: ReadonlyArray<string>;
|
|
9
|
+
}
|
|
10
|
+
export interface WarehouseStatement {
|
|
11
|
+
readonly sql: string;
|
|
12
|
+
readonly parameters: ReadonlyArray<WarehouseParameter>;
|
|
13
|
+
readonly maxRows: number;
|
|
14
|
+
}
|
|
15
|
+
/** Source keys are opaque record identities, including composite and non-UUID keys. */
|
|
16
|
+
export declare function isWarehouseRecordId(value: string): boolean;
|
|
17
|
+
/** A checked entity query compiled only from declared identifiers and bound values. */
|
|
18
|
+
export declare function compileWarehouseQuery(manifest: OntologyManifest, entity: EntityManifest, query: Query): WarehouseStatement & {
|
|
19
|
+
readonly decode: (rows: ReadonlyArray<StoredRecord>) => {
|
|
20
|
+
readonly items: ReadonlyArray<StoredRecord>;
|
|
21
|
+
readonly nextCursor: string | null;
|
|
22
|
+
readonly projected?: true;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { queryFields, } from "../query.js";
|
|
3
|
+
import { InvalidQuery } from "../runtime/errors.js";
|
|
4
|
+
const PREFIX = "wr1_";
|
|
5
|
+
const ID = /^wr1_[A-Za-z0-9_-]{1,12000}$/;
|
|
6
|
+
const COLUMN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
7
|
+
function invalid(entity, message) {
|
|
8
|
+
throw new InvalidQuery({ entity, message, issues: [{ path: [], message }] });
|
|
9
|
+
}
|
|
10
|
+
/** Source keys are opaque record identities, including composite and non-UUID keys. */
|
|
11
|
+
export function isWarehouseRecordId(value) {
|
|
12
|
+
if (!ID.test(value)) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const key = JSON.parse(Buffer.from(value.slice(PREFIX.length), "base64url").toString());
|
|
17
|
+
return Array.isArray(key) && key.length > 0 && key.every((part) => typeof part === "string");
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function identifier(value) {
|
|
24
|
+
if (!COLUMN.test(value)) {
|
|
25
|
+
throw new Error("A checked warehouse column was expected.");
|
|
26
|
+
}
|
|
27
|
+
return `\`${value}\``;
|
|
28
|
+
}
|
|
29
|
+
function canonical(value) {
|
|
30
|
+
if (Array.isArray(value)) {
|
|
31
|
+
return value.map(canonical);
|
|
32
|
+
}
|
|
33
|
+
if (value !== null && typeof value === "object") {
|
|
34
|
+
return Object.fromEntries(Object.entries(value)
|
|
35
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
36
|
+
.map(([key, item]) => [key, canonical(item)]));
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
function parameterType(field) {
|
|
41
|
+
switch (field.storage) {
|
|
42
|
+
case "integer":
|
|
43
|
+
return "INT64";
|
|
44
|
+
case "number":
|
|
45
|
+
return "FLOAT64";
|
|
46
|
+
case "boolean":
|
|
47
|
+
return "BOOL";
|
|
48
|
+
case "date":
|
|
49
|
+
return "DATE";
|
|
50
|
+
case "timestamp":
|
|
51
|
+
return "TIMESTAMP";
|
|
52
|
+
default:
|
|
53
|
+
return "STRING";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function scalar(field, value) {
|
|
57
|
+
if (value === null) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
if (field.storage === "integer" || field.storage === "number") {
|
|
61
|
+
const number = typeof value === "number" ? value : Number(value);
|
|
62
|
+
if (!Number.isFinite(number) ||
|
|
63
|
+
(field.storage === "integer" && !Number.isSafeInteger(number))) {
|
|
64
|
+
throw new Error("The warehouse returned a number outside the record's supported range.");
|
|
65
|
+
}
|
|
66
|
+
return number;
|
|
67
|
+
}
|
|
68
|
+
if (field.storage === "boolean") {
|
|
69
|
+
if (value === true || value === "true") {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
if (value === false || value === "false") {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
throw new Error("The warehouse returned an invalid boolean.");
|
|
76
|
+
}
|
|
77
|
+
if (typeof value !== "string") {
|
|
78
|
+
throw new Error("The warehouse returned an invalid scalar record field.");
|
|
79
|
+
}
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
82
|
+
/** A checked entity query compiled only from declared identifiers and bound values. */
|
|
83
|
+
export function compileWarehouseQuery(manifest, entity, query) {
|
|
84
|
+
const source = entity.source;
|
|
85
|
+
if (source === undefined) {
|
|
86
|
+
throw new Error("A warehouse source was expected.");
|
|
87
|
+
}
|
|
88
|
+
const asset = source.asset.split("/").map(identifier).join(".");
|
|
89
|
+
const fields = queryFields(entity);
|
|
90
|
+
const byName = new Map(fields.map((field) => [field.name, field]));
|
|
91
|
+
const mapped = new Map(entity.properties.map((property) => [property.name, property.column]));
|
|
92
|
+
const key = `TO_JSON_STRING([${source.key.map((column) => `CAST(r.${identifier(column)} AS STRING)`).join(", ")}])`;
|
|
93
|
+
const id = `CONCAT('${PREFIX}', RTRIM(REPLACE(REPLACE(TO_BASE64(CAST(${key} AS BYTES)), '+', '-'), '/', '_'), '='))`;
|
|
94
|
+
const column = (name) => name === "id" ? id : `r.${identifier(mapped.get(name))}`;
|
|
95
|
+
const parameters = [];
|
|
96
|
+
const bind = (field, value, array = false) => {
|
|
97
|
+
const name = `p${parameters.length}`;
|
|
98
|
+
parameters.push({
|
|
99
|
+
name,
|
|
100
|
+
type: parameterType(field),
|
|
101
|
+
...(array
|
|
102
|
+
? { values: value.map(String) }
|
|
103
|
+
: { value: String(value) }),
|
|
104
|
+
});
|
|
105
|
+
return `@${name}`;
|
|
106
|
+
};
|
|
107
|
+
const compileField = (field, condition) => {
|
|
108
|
+
const expression = column(field.name);
|
|
109
|
+
const filter = condition === null
|
|
110
|
+
? { isNull: true }
|
|
111
|
+
: typeof condition === "object" && !Array.isArray(condition)
|
|
112
|
+
? condition
|
|
113
|
+
: { eq: condition };
|
|
114
|
+
return (Object.entries(filter)
|
|
115
|
+
.map(([operator, value]) => {
|
|
116
|
+
if (operator === "isNull") {
|
|
117
|
+
return `${expression} IS ${value ? "" : "NOT "}NULL`;
|
|
118
|
+
}
|
|
119
|
+
if (operator === "in") {
|
|
120
|
+
return value.length === 0
|
|
121
|
+
? "FALSE"
|
|
122
|
+
: `${expression} IN UNNEST(${bind(field, value, true)})`;
|
|
123
|
+
}
|
|
124
|
+
if (operator === "between") {
|
|
125
|
+
const pair = value;
|
|
126
|
+
return `${expression} BETWEEN ${bind(field, pair[0])} AND ${bind(field, pair[1])}`;
|
|
127
|
+
}
|
|
128
|
+
const parameter = bind(field, value);
|
|
129
|
+
switch (operator) {
|
|
130
|
+
case "eq":
|
|
131
|
+
return `${expression} = ${parameter}`;
|
|
132
|
+
case "ne":
|
|
133
|
+
return `(${expression} != ${parameter} OR ${expression} IS NULL)`;
|
|
134
|
+
case "gt":
|
|
135
|
+
return `${expression} > ${parameter}`;
|
|
136
|
+
case "gte":
|
|
137
|
+
return `${expression} >= ${parameter}`;
|
|
138
|
+
case "lt":
|
|
139
|
+
return `${expression} < ${parameter}`;
|
|
140
|
+
case "lte":
|
|
141
|
+
return `${expression} <= ${parameter}`;
|
|
142
|
+
case "contains":
|
|
143
|
+
return `STRPOS(LOWER(${expression}), LOWER(${parameter})) > 0`;
|
|
144
|
+
case "startsWith":
|
|
145
|
+
return `STARTS_WITH(LOWER(${expression}), LOWER(${parameter}))`;
|
|
146
|
+
default:
|
|
147
|
+
return invalid(entity.name, `Unsupported warehouse field operator ${operator}.`);
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
.map((part) => `(${part})`)
|
|
151
|
+
.join(" AND ") || "TRUE");
|
|
152
|
+
};
|
|
153
|
+
const where = (condition) => Object.entries(condition)
|
|
154
|
+
.map(([name, value]) => {
|
|
155
|
+
if (name === "and" || name === "or") {
|
|
156
|
+
const parts = value.map((part) => `(${where(part)})`);
|
|
157
|
+
return (parts.join(name === "and" ? " AND " : " OR ") || (name === "and" ? "TRUE" : "FALSE"));
|
|
158
|
+
}
|
|
159
|
+
if (name === "not") {
|
|
160
|
+
return `NOT (${where(value)})`;
|
|
161
|
+
}
|
|
162
|
+
const field = byName.get(name);
|
|
163
|
+
if (field === undefined) {
|
|
164
|
+
return invalid(entity.name, "Warehouse filters name mapped fields.");
|
|
165
|
+
}
|
|
166
|
+
return compileField(field, value);
|
|
167
|
+
})
|
|
168
|
+
.map((part) => `(${part})`)
|
|
169
|
+
.join(" AND ") || "TRUE";
|
|
170
|
+
const orders = [];
|
|
171
|
+
for (const entry of [...(query.orderBy ?? []), { field: "id", direction: "asc" }]) {
|
|
172
|
+
if (!orders.some((order) => order.field.name === entry.field)) {
|
|
173
|
+
const field = byName.get(entry.field);
|
|
174
|
+
if (field === undefined) {
|
|
175
|
+
invalid(entity.name, "Unknown warehouse sort field.");
|
|
176
|
+
}
|
|
177
|
+
orders.push({ field, direction: entry.direction ?? "asc" });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const fingerprint = createHash("sha256")
|
|
181
|
+
.update(JSON.stringify(canonical([
|
|
182
|
+
manifest.hash,
|
|
183
|
+
entity.name,
|
|
184
|
+
query.where ?? {},
|
|
185
|
+
orders.map((order) => [order.field.name, order.direction]),
|
|
186
|
+
])))
|
|
187
|
+
.digest("hex");
|
|
188
|
+
const predicates = [where(query.where ?? {})];
|
|
189
|
+
if (query.after !== undefined) {
|
|
190
|
+
let values;
|
|
191
|
+
try {
|
|
192
|
+
if (query.after.length > 32000) {
|
|
193
|
+
throw new Error("oversized");
|
|
194
|
+
}
|
|
195
|
+
const cursor = JSON.parse(Buffer.from(query.after, "base64url").toString());
|
|
196
|
+
if (cursor.v !== 1 ||
|
|
197
|
+
cursor.fingerprint !== fingerprint ||
|
|
198
|
+
!Array.isArray(cursor.values) ||
|
|
199
|
+
cursor.values.length !== orders.length) {
|
|
200
|
+
throw new Error("mismatch");
|
|
201
|
+
}
|
|
202
|
+
values = cursor.values;
|
|
203
|
+
orders.forEach((order, index) => {
|
|
204
|
+
const value = values[index];
|
|
205
|
+
if (value !== null) {
|
|
206
|
+
scalar(order.field, value);
|
|
207
|
+
}
|
|
208
|
+
if (order.field.name === "id" &&
|
|
209
|
+
(typeof value !== "string" || !isWarehouseRecordId(value))) {
|
|
210
|
+
throw new Error("invalid key");
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
invalid(entity.name, "This cursor does not belong to the current warehouse query.");
|
|
216
|
+
}
|
|
217
|
+
const ties = [];
|
|
218
|
+
const after = [];
|
|
219
|
+
orders.forEach((order, index) => {
|
|
220
|
+
const expression = column(order.field.name);
|
|
221
|
+
const value = values[index];
|
|
222
|
+
if (value === null) {
|
|
223
|
+
ties.push(`${expression} IS NULL`);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
const parameter = bind(order.field, value);
|
|
227
|
+
const past = `(${expression} ${order.direction === "asc" ? ">" : "<"} ${parameter} OR ${expression} IS NULL)`;
|
|
228
|
+
after.push([...ties, past].join(" AND "));
|
|
229
|
+
ties.push(`${expression} = ${parameter}`);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
predicates.push(after.length === 0 ? "FALSE" : after.map((part) => `(${part})`).join(" OR "));
|
|
233
|
+
}
|
|
234
|
+
const selected = [...new Set(["id", ...(query.select ?? fields.map((field) => field.name))])];
|
|
235
|
+
const limit = query.limit ?? 50;
|
|
236
|
+
const projection = [
|
|
237
|
+
...selected.map((name) => `${column(name)} AS ${identifier(name)}`),
|
|
238
|
+
...orders.map((order, index) => `${column(order.field.name)} AS ${identifier(`__order_${index}`)}`),
|
|
239
|
+
];
|
|
240
|
+
const ordering = orders.map((order) => `${column(order.field.name)} ${order.direction.toUpperCase()} NULLS LAST`);
|
|
241
|
+
const sql = [
|
|
242
|
+
`SELECT ${projection.join(", ")}`,
|
|
243
|
+
`FROM ${asset} AS r`,
|
|
244
|
+
`WHERE ${predicates.map((part) => `(${part})`).join(" AND ")}`,
|
|
245
|
+
`ORDER BY ${ordering.join(", ")}`,
|
|
246
|
+
`LIMIT ${bind({ name: "limit", storage: "integer", nullable: false }, limit + 1)}`,
|
|
247
|
+
].join("\n");
|
|
248
|
+
if (parameters.length > 100) {
|
|
249
|
+
invalid(entity.name, "A warehouse record query accepts at most 100 bound parameters.");
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
sql,
|
|
253
|
+
parameters,
|
|
254
|
+
maxRows: limit + 1,
|
|
255
|
+
decode: (rows) => {
|
|
256
|
+
const seen = new Set();
|
|
257
|
+
for (const row of rows) {
|
|
258
|
+
if (typeof row.id !== "string" || !isWarehouseRecordId(row.id) || seen.has(row.id)) {
|
|
259
|
+
invalid(entity.name, "Warehouse source keys must be non-null and unique.");
|
|
260
|
+
}
|
|
261
|
+
seen.add(row.id);
|
|
262
|
+
}
|
|
263
|
+
const page = rows.slice(0, limit);
|
|
264
|
+
const items = page.map((row) => Object.fromEntries(selected.map((name) => [name, scalar(byName.get(name), row[name])])));
|
|
265
|
+
const last = page.at(-1);
|
|
266
|
+
const nextCursor = rows.length > limit && last !== undefined
|
|
267
|
+
? Buffer.from(JSON.stringify({
|
|
268
|
+
v: 1,
|
|
269
|
+
fingerprint,
|
|
270
|
+
values: orders.map((order, index) => scalar(order.field, last[`__order_${index}`])),
|
|
271
|
+
})).toString("base64url")
|
|
272
|
+
: null;
|
|
273
|
+
return {
|
|
274
|
+
items,
|
|
275
|
+
nextCursor,
|
|
276
|
+
...(query.select === undefined ? {} : { projected: true }),
|
|
277
|
+
};
|
|
278
|
+
},
|
|
279
|
+
};
|
|
280
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Effect, Redacted } from "effect";
|
|
2
|
+
import type { HttpServerRequest } from "effect/unstable/http";
|
|
3
|
+
import type { WebhookSignatureScheme } from "../webhooks.js";
|
|
4
|
+
/**
|
|
5
|
+
* The pieces of the webhook route that do not need the router: reading the body, the signature
|
|
6
|
+
* schemes, the backend's verification and the throttle on refused signatures.
|
|
7
|
+
*/
|
|
8
|
+
/** What SegmentStream's backend answered about a delivery's signature. */
|
|
9
|
+
export type WebhookVerification = {
|
|
10
|
+
readonly outcome: "valid";
|
|
11
|
+
} | {
|
|
12
|
+
readonly outcome: "invalid";
|
|
13
|
+
}
|
|
14
|
+
/** The workspace secret the webhook names does not exist. */
|
|
15
|
+
| {
|
|
16
|
+
readonly outcome: "secret_missing";
|
|
17
|
+
}
|
|
18
|
+
/** The backend could not answer; the provider retries. `cause` is for operator logs only. */
|
|
19
|
+
| {
|
|
20
|
+
readonly outcome: "unavailable";
|
|
21
|
+
readonly status?: number;
|
|
22
|
+
readonly cause?: unknown;
|
|
23
|
+
};
|
|
24
|
+
/** A signature check the ontology service asks the backend for: the secret never leaves it. */
|
|
25
|
+
export interface WebhookVerifyRequest {
|
|
26
|
+
/** The workspace secret's name. */
|
|
27
|
+
readonly secret: string;
|
|
28
|
+
readonly algorithm: "sha256";
|
|
29
|
+
readonly encoding: "hex";
|
|
30
|
+
/** The bytes the provider signed. */
|
|
31
|
+
readonly message: Uint8Array;
|
|
32
|
+
/** The signatures the delivery carried; any that matches is enough. */
|
|
33
|
+
readonly signatures: ReadonlyArray<string>;
|
|
34
|
+
/** The deployment's Vercel OIDC token, which proves the workspace application. */
|
|
35
|
+
readonly identityToken: string | undefined;
|
|
36
|
+
readonly requestId: string;
|
|
37
|
+
}
|
|
38
|
+
/** Checks webhook signatures. The service calls SegmentStream's backend by default. */
|
|
39
|
+
export type WebhookVerifier = (request: WebhookVerifyRequest) => Promise<WebhookVerification>;
|
|
40
|
+
/** Registration checks return only a match; the stored verify token never leaves the backend. */
|
|
41
|
+
export type WebhookTokenVerifyRequest = Omit<WebhookVerifyRequest, "algorithm" | "encoding" | "message" | "signatures"> & {
|
|
42
|
+
readonly token: string;
|
|
43
|
+
};
|
|
44
|
+
export type WebhookTokenVerifier = (request: WebhookTokenVerifyRequest) => Promise<WebhookVerification>;
|
|
45
|
+
/** How long the service waits for the backend's answer before answering 503. */
|
|
46
|
+
export declare const WEBHOOK_VERIFY_TIMEOUT_MS = 3000;
|
|
47
|
+
/**
|
|
48
|
+
* The verifier of a deployed ontology service: `POST
|
|
49
|
+
* /api/internal/v1/workspaces/{id}/secrets/{name}/verify-hmac` on SegmentStream with the request's
|
|
50
|
+
* Vercel OIDC token, admitted only for the secrets the deployed ontology's webhooks name.
|
|
51
|
+
*/
|
|
52
|
+
export declare function deployedWebhookVerifier(environment: {
|
|
53
|
+
readonly segmentstreamUrl: string;
|
|
54
|
+
readonly workspaceId: string;
|
|
55
|
+
readonly organizationId: string;
|
|
56
|
+
readonly deploymentId?: string | undefined;
|
|
57
|
+
readonly previewCredential?: Redacted.Redacted<string> | undefined;
|
|
58
|
+
}, fetchImpl?: typeof fetch): WebhookVerifier;
|
|
59
|
+
/** Meta registration token comparison, authenticated by the deployment identity like HMAC checks. */
|
|
60
|
+
export declare function deployedWebhookTokenVerifier(environment: {
|
|
61
|
+
readonly segmentstreamUrl: string;
|
|
62
|
+
readonly workspaceId: string;
|
|
63
|
+
readonly organizationId: string;
|
|
64
|
+
readonly deploymentId?: string | undefined;
|
|
65
|
+
readonly previewCredential?: Redacted.Redacted<string> | undefined;
|
|
66
|
+
}, fetchImpl?: typeof fetch): WebhookTokenVerifier;
|
|
67
|
+
/** The bytes a scheme's signatures cover and the signatures to compare, or why it refused. */
|
|
68
|
+
export type SignedContent = {
|
|
69
|
+
readonly ok: true;
|
|
70
|
+
readonly message: Uint8Array;
|
|
71
|
+
readonly signatures: ReadonlyArray<string>;
|
|
72
|
+
} | {
|
|
73
|
+
readonly ok: false;
|
|
74
|
+
readonly reason: "signature_missing" | "signature_malformed" | "signature_stale";
|
|
75
|
+
};
|
|
76
|
+
/** A scheme: what was signed and with which signatures, read from the request alone. */
|
|
77
|
+
export type SignatureScheme = (headers: Readonly<Record<string, string | undefined>>, body: Uint8Array, receivedAt: Date) => SignedContent;
|
|
78
|
+
/** How far Stripe's `t` may be from the time the delivery arrived, in seconds. */
|
|
79
|
+
export declare const STRIPE_TOLERANCE_SECONDS = 300;
|
|
80
|
+
/**
|
|
81
|
+
* Stripe's `Stripe-Signature`: `t=<unix seconds>` and one or more `v1=<hex>`. The signed bytes are
|
|
82
|
+
* `<t>.` followed by the raw body; the HMAC is SHA-256 keyed with the whole `whsec_…` string.
|
|
83
|
+
*/
|
|
84
|
+
export declare const stripeSignature: SignatureScheme;
|
|
85
|
+
/** Meta signs exactly the raw body; its app secret stays in the backend. */
|
|
86
|
+
export declare const metaSignature: SignatureScheme;
|
|
87
|
+
/** Every scheme the SDK checks, by the name a declaration uses. */
|
|
88
|
+
export declare const SIGNATURE_SCHEMES: Readonly<Record<WebhookSignatureScheme, SignatureScheme>>;
|
|
89
|
+
/**
|
|
90
|
+
* The request's body, read up to `limit` bytes: `too_large` without reading further, or
|
|
91
|
+
* `unreadable` when the client went away.
|
|
92
|
+
*/
|
|
93
|
+
export declare function readWebhookBody(request: HttpServerRequest.HttpServerRequest, limit: number): Effect.Effect<Uint8Array | "too_large" | "unreadable">;
|
|
94
|
+
/** The body as UTF-8 text, or `undefined` when it is not valid UTF-8. */
|
|
95
|
+
export declare function utf8Text(body: Uint8Array): string | undefined;
|
|
96
|
+
/** Refused signatures one client address may send a webhook per minute before it is throttled. */
|
|
97
|
+
export declare const MAX_REFUSED_SIGNATURES_PER_MINUTE = 20;
|
|
98
|
+
/**
|
|
99
|
+
* Counts refused signatures per client address and webhook in this instance's memory. Once a
|
|
100
|
+
* client is over the limit it is answered 429 until its window ends, without a backend call.
|
|
101
|
+
*/
|
|
102
|
+
export declare function signatureRefusals(now?: () => number): {
|
|
103
|
+
/** Seconds the client must wait, or `undefined` when it may be checked. */
|
|
104
|
+
blocked(key: string): number | undefined;
|
|
105
|
+
refused(key: string): void;
|
|
106
|
+
};
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { Effect, Redacted } from "effect";
|
|
2
|
+
import { fixedWindowLimiter } from "./rate-limit.js";
|
|
3
|
+
/** How long the service waits for the backend's answer before answering 503. */
|
|
4
|
+
export const WEBHOOK_VERIFY_TIMEOUT_MS = 3_000;
|
|
5
|
+
/**
|
|
6
|
+
* The verifier of a deployed ontology service: `POST
|
|
7
|
+
* /api/internal/v1/workspaces/{id}/secrets/{name}/verify-hmac` on SegmentStream with the request's
|
|
8
|
+
* Vercel OIDC token, admitted only for the secrets the deployed ontology's webhooks name.
|
|
9
|
+
*/
|
|
10
|
+
export function deployedWebhookVerifier(environment, fetchImpl = fetch) {
|
|
11
|
+
const verify = deployedSecretVerifier(environment, "verify-hmac", fetchImpl);
|
|
12
|
+
return (request) => verify(request, {
|
|
13
|
+
algorithm: request.algorithm,
|
|
14
|
+
encoding: request.encoding,
|
|
15
|
+
message: Buffer.from(request.message).toString("base64"),
|
|
16
|
+
signatures: request.signatures,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/** Meta registration token comparison, authenticated by the deployment identity like HMAC checks. */
|
|
20
|
+
export function deployedWebhookTokenVerifier(environment, fetchImpl = fetch) {
|
|
21
|
+
const verify = deployedSecretVerifier(environment, "verify-token", fetchImpl);
|
|
22
|
+
return (request) => verify(request, { token: request.token });
|
|
23
|
+
}
|
|
24
|
+
function deployedSecretVerifier(environment, operation, fetchImpl) {
|
|
25
|
+
const base = `${environment.segmentstreamUrl}/api/internal/v1/workspaces/` +
|
|
26
|
+
`${encodeURIComponent(environment.workspaceId)}/secrets/`;
|
|
27
|
+
return async (request, payload) => {
|
|
28
|
+
if (request.identityToken === undefined || request.identityToken === "") {
|
|
29
|
+
return {
|
|
30
|
+
outcome: "unavailable",
|
|
31
|
+
cause: new Error("The request carries no Vercel OIDC token for webhook verification."),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const response = await fetchImpl(`${base}${encodeURIComponent(request.secret)}/${operation}`, {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: {
|
|
38
|
+
"content-type": "application/json",
|
|
39
|
+
"x-segmentstream-runtime-identity": request.identityToken,
|
|
40
|
+
"x-segmentstream-organization-id": environment.organizationId,
|
|
41
|
+
"x-segmentstream-request-id": request.requestId,
|
|
42
|
+
...(environment.deploymentId
|
|
43
|
+
? { "x-segmentstream-ontology-deployment-id": environment.deploymentId }
|
|
44
|
+
: {}),
|
|
45
|
+
...(environment.previewCredential
|
|
46
|
+
? {
|
|
47
|
+
"x-segmentstream-preview-credential": Redacted.value(environment.previewCredential),
|
|
48
|
+
}
|
|
49
|
+
: {}),
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify(payload),
|
|
52
|
+
signal: AbortSignal.timeout(WEBHOOK_VERIFY_TIMEOUT_MS),
|
|
53
|
+
});
|
|
54
|
+
const text = await response.text();
|
|
55
|
+
let body;
|
|
56
|
+
try {
|
|
57
|
+
body = JSON.parse(text);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
body = undefined;
|
|
61
|
+
}
|
|
62
|
+
const answer = typeof body === "object" && body !== null ? body : {};
|
|
63
|
+
if (response.status === 404 && answer.error === "secret_not_found") {
|
|
64
|
+
return { outcome: "secret_missing" };
|
|
65
|
+
}
|
|
66
|
+
if (response.ok && typeof answer.valid === "boolean") {
|
|
67
|
+
return { outcome: answer.valid ? "valid" : "invalid" };
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
outcome: "unavailable",
|
|
71
|
+
status: response.status,
|
|
72
|
+
cause: new Error(`SegmentStream answered ${response.status} to the signature check: ${text.slice(0, 500)}`),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
catch (cause) {
|
|
76
|
+
return { outcome: "unavailable", cause };
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/** How far Stripe's `t` may be from the time the delivery arrived, in seconds. */
|
|
81
|
+
export const STRIPE_TOLERANCE_SECONDS = 300;
|
|
82
|
+
/** The most signatures of one delivery that are sent to the backend. */
|
|
83
|
+
const MAX_SIGNATURES = 5;
|
|
84
|
+
/**
|
|
85
|
+
* Stripe's `Stripe-Signature`: `t=<unix seconds>` and one or more `v1=<hex>`. The signed bytes are
|
|
86
|
+
* `<t>.` followed by the raw body; the HMAC is SHA-256 keyed with the whole `whsec_…` string.
|
|
87
|
+
*/
|
|
88
|
+
export const stripeSignature = (headers, body, receivedAt) => {
|
|
89
|
+
const header = headers["stripe-signature"];
|
|
90
|
+
if (header === undefined || header.trim() === "") {
|
|
91
|
+
return { ok: false, reason: "signature_missing" };
|
|
92
|
+
}
|
|
93
|
+
let timestamp;
|
|
94
|
+
const signatures = [];
|
|
95
|
+
for (const part of header.split(",")) {
|
|
96
|
+
const separator = part.indexOf("=");
|
|
97
|
+
if (separator <= 0) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const key = part.slice(0, separator).trim();
|
|
101
|
+
const value = part.slice(separator + 1).trim();
|
|
102
|
+
if (key === "t") {
|
|
103
|
+
timestamp = value;
|
|
104
|
+
}
|
|
105
|
+
else if (key === "v1" &&
|
|
106
|
+
/^[0-9a-f]{64}$/i.test(value) &&
|
|
107
|
+
signatures.length < MAX_SIGNATURES) {
|
|
108
|
+
signatures.push(value.toLowerCase());
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (timestamp === undefined || !/^\d{1,12}$/.test(timestamp) || signatures.length === 0) {
|
|
112
|
+
return { ok: false, reason: "signature_malformed" };
|
|
113
|
+
}
|
|
114
|
+
if (Math.abs(receivedAt.getTime() / 1000 - Number(timestamp)) > STRIPE_TOLERANCE_SECONDS) {
|
|
115
|
+
return { ok: false, reason: "signature_stale" };
|
|
116
|
+
}
|
|
117
|
+
const prefix = new TextEncoder().encode(`${timestamp}.`);
|
|
118
|
+
const message = new Uint8Array(prefix.length + body.length);
|
|
119
|
+
message.set(prefix);
|
|
120
|
+
message.set(body, prefix.length);
|
|
121
|
+
return { ok: true, message, signatures };
|
|
122
|
+
};
|
|
123
|
+
/** Meta signs exactly the raw body; its app secret stays in the backend. */
|
|
124
|
+
export const metaSignature = (headers, body) => {
|
|
125
|
+
const header = headers["x-hub-signature-256"];
|
|
126
|
+
if (header === undefined || header === "") {
|
|
127
|
+
return { ok: false, reason: "signature_missing" };
|
|
128
|
+
}
|
|
129
|
+
if (!/^sha256=[0-9a-f]{64}$/i.test(header)) {
|
|
130
|
+
return { ok: false, reason: "signature_malformed" };
|
|
131
|
+
}
|
|
132
|
+
return { ok: true, message: body, signatures: [header.slice(7).toLowerCase()] };
|
|
133
|
+
};
|
|
134
|
+
/** Every scheme the SDK checks, by the name a declaration uses. */
|
|
135
|
+
export const SIGNATURE_SCHEMES = {
|
|
136
|
+
stripe: stripeSignature,
|
|
137
|
+
meta: metaSignature,
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* The request's body, read up to `limit` bytes: `too_large` without reading further, or
|
|
141
|
+
* `unreadable` when the client went away.
|
|
142
|
+
*/
|
|
143
|
+
export function readWebhookBody(request, limit) {
|
|
144
|
+
const declared = Number(request.headers["content-length"]);
|
|
145
|
+
if (Number.isFinite(declared) && declared > limit) {
|
|
146
|
+
return Effect.succeed("too_large");
|
|
147
|
+
}
|
|
148
|
+
const source = request.source;
|
|
149
|
+
if (source instanceof Request) {
|
|
150
|
+
return Effect.promise(() => readCapped(source, limit));
|
|
151
|
+
}
|
|
152
|
+
return request.arrayBuffer.pipe(Effect.map((buffer) => buffer.byteLength > limit ? "too_large" : new Uint8Array(buffer)), Effect.orElseSucceed(() => "unreadable"));
|
|
153
|
+
}
|
|
154
|
+
async function readCapped(request, limit) {
|
|
155
|
+
if (request.body === null) {
|
|
156
|
+
return new Uint8Array();
|
|
157
|
+
}
|
|
158
|
+
const reader = request.body.getReader();
|
|
159
|
+
const chunks = [];
|
|
160
|
+
let size = 0;
|
|
161
|
+
try {
|
|
162
|
+
for (;;) {
|
|
163
|
+
const { done, value } = await reader.read();
|
|
164
|
+
if (done) {
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
size += value.byteLength;
|
|
168
|
+
if (size > limit) {
|
|
169
|
+
await reader.cancel().catch(() => undefined);
|
|
170
|
+
return "too_large";
|
|
171
|
+
}
|
|
172
|
+
chunks.push(value);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return "unreadable";
|
|
177
|
+
}
|
|
178
|
+
const body = new Uint8Array(size);
|
|
179
|
+
let offset = 0;
|
|
180
|
+
for (const chunk of chunks) {
|
|
181
|
+
body.set(chunk, offset);
|
|
182
|
+
offset += chunk.byteLength;
|
|
183
|
+
}
|
|
184
|
+
return body;
|
|
185
|
+
}
|
|
186
|
+
/** The body as UTF-8 text, or `undefined` when it is not valid UTF-8. */
|
|
187
|
+
export function utf8Text(body) {
|
|
188
|
+
try {
|
|
189
|
+
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(body);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/** Refused signatures one client address may send a webhook per minute before it is throttled. */
|
|
196
|
+
export const MAX_REFUSED_SIGNATURES_PER_MINUTE = 20;
|
|
197
|
+
/**
|
|
198
|
+
* Counts refused signatures per client address and webhook in this instance's memory. Once a
|
|
199
|
+
* client is over the limit it is answered 429 until its window ends, without a backend call.
|
|
200
|
+
*/
|
|
201
|
+
export function signatureRefusals(now = Date.now) {
|
|
202
|
+
const limiter = fixedWindowLimiter({
|
|
203
|
+
limit: MAX_REFUSED_SIGNATURES_PER_MINUTE,
|
|
204
|
+
windowMs: 60_000,
|
|
205
|
+
maxKeys: 10_000,
|
|
206
|
+
});
|
|
207
|
+
const blockedUntil = new Map();
|
|
208
|
+
return {
|
|
209
|
+
/** Seconds the client must wait, or `undefined` when it may be checked. */
|
|
210
|
+
blocked(key) {
|
|
211
|
+
const until = blockedUntil.get(key);
|
|
212
|
+
const current = now();
|
|
213
|
+
if (until === undefined) {
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
if (until <= current) {
|
|
217
|
+
blockedUntil.delete(key);
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
return Math.max(1, Math.ceil((until - current) / 1000));
|
|
221
|
+
},
|
|
222
|
+
refused(key) {
|
|
223
|
+
const current = now();
|
|
224
|
+
const wait = limiter.take(key, current);
|
|
225
|
+
if (wait !== undefined) {
|
|
226
|
+
if (blockedUntil.size >= 10_000) {
|
|
227
|
+
blockedUntil.clear();
|
|
228
|
+
}
|
|
229
|
+
blockedUntil.set(key, current + wait * 1000);
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type World } from "@workflow/world";
|
|
2
|
+
export interface WorkflowProviderReservation {
|
|
3
|
+
readonly runId: string;
|
|
4
|
+
readonly deploymentId: string;
|
|
5
|
+
readonly namespace: string;
|
|
6
|
+
readonly region?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface WorkflowProviderAdmission {
|
|
9
|
+
readonly reservation: WorkflowProviderReservation;
|
|
10
|
+
/** Random, immutable identity of the database reservation, allocated under its lock. */
|
|
11
|
+
readonly admissionId: string;
|
|
12
|
+
readonly attributes?: Readonly<Record<string, string>>;
|
|
13
|
+
}
|
|
14
|
+
export declare class WorkflowAdmissionBindingError extends Error {
|
|
15
|
+
readonly runId: string;
|
|
16
|
+
readonly reason: string;
|
|
17
|
+
readonly name = "WorkflowAdmissionBindingError";
|
|
18
|
+
constructor(runId: string, reason: string);
|
|
19
|
+
}
|
|
20
|
+
/** Allocate once, then persist the entire result before any call to startReservedWorkflowRun. */
|
|
21
|
+
export declare function allocateWorkflowRun(world: World, options: Omit<WorkflowProviderReservation, "runId">): Promise<WorkflowProviderReservation>;
|
|
22
|
+
/**
|
|
23
|
+
* Dispatch the database's immutable reservation through the public World override.
|
|
24
|
+
* A failed acknowledgement is uncertain: callers must retry this same reservation.
|
|
25
|
+
* This helper supplies neither a reservation store nor permission to cross a cutover fence.
|
|
26
|
+
*/
|
|
27
|
+
export declare function startReservedWorkflowRun(world: World, workflow: {
|
|
28
|
+
readonly workflowId: string;
|
|
29
|
+
}, args: ReadonlyArray<unknown>, options: WorkflowProviderAdmission): Promise<{
|
|
30
|
+
readonly runId: string;
|
|
31
|
+
}>;
|