@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,495 @@
|
|
|
1
|
+
import { dimensionTypeOf, filterTypeIssue, filterValuesIssue, METRIC_CONDITION_OPERATORS, } from "./metric-filters.js";
|
|
2
|
+
import { metricsManifest } from "./manifest.js";
|
|
3
|
+
import { balanceOf, conditionProperty, conditionsOf, METRIC_AGGREGATES, } from "./metric.js";
|
|
4
|
+
import { humanize, isSystemProperty, SNAKE_CASE_NAME } from "./names.js";
|
|
5
|
+
const columnName = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
6
|
+
const types = new Set(["text", "integer", "number", "boolean", "date", "timestamp", "select"]);
|
|
7
|
+
/**
|
|
8
|
+
* Types a join key may have. Joins deduplicate their target with `PARTITION BY` the key, which
|
|
9
|
+
* BigQuery refuses for FLOAT64; booleans, JSON and files identify nothing.
|
|
10
|
+
*/
|
|
11
|
+
const joinTypes = new Set(["text", "email", "url", "select", "integer", "date", "timestamp"]);
|
|
12
|
+
/** Types `m.countDistinct` counts: the join key types, whose values compare exactly. */
|
|
13
|
+
const distinctTypes = joinTypes;
|
|
14
|
+
/** Cross-field validation runs after relationships have resolved their target entities. */
|
|
15
|
+
export function checkWarehouseSource(entities, report) {
|
|
16
|
+
for (const entity of entities) {
|
|
17
|
+
const { source, metrics = {} } = entity.entity.definition;
|
|
18
|
+
const path = entity.name;
|
|
19
|
+
if (source === undefined) {
|
|
20
|
+
if (entity.builtIn && Object.keys(metrics).length) {
|
|
21
|
+
report("invalid-metric", path, "User cannot declare metrics.");
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
checkMetrics({
|
|
25
|
+
entity,
|
|
26
|
+
metrics,
|
|
27
|
+
properties: new Map(entity.properties.map((property) => [property.name, property.definition])),
|
|
28
|
+
hasCurrency: false,
|
|
29
|
+
report,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
if (entity.properties.some(({ definition }) => definition.column !== undefined || definition.scope !== undefined)) {
|
|
33
|
+
report("invalid-column", path, "Column mappings and scopes belong to warehouse-backed entities.");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
if (entity.builtIn ||
|
|
38
|
+
!source ||
|
|
39
|
+
!/^[A-Za-z_][A-Za-z0-9_]*\/[A-Za-z_][A-Za-z0-9_]*$/.test(source.asset) ||
|
|
40
|
+
!Array.isArray(source.key) ||
|
|
41
|
+
!source.key.length ||
|
|
42
|
+
source.key.some((key) => !columnName.test(key)) ||
|
|
43
|
+
new Set(source.key).size !== source.key.length) {
|
|
44
|
+
report("invalid-source", path, "Use a warehouse asset and nonempty, unique key columns; User cannot have a warehouse source.");
|
|
45
|
+
}
|
|
46
|
+
if (entity.actions.length || "actions" in entity.entity.definition) {
|
|
47
|
+
report("source-with-actions", path, "Warehouse-backed entities cannot have actions.");
|
|
48
|
+
}
|
|
49
|
+
if (entity.entity.definition.indexes !== undefined) {
|
|
50
|
+
report("source-with-index", path, "Warehouse-backed entities cannot have indexes.");
|
|
51
|
+
}
|
|
52
|
+
const properties = new Map(entity.properties.map((property) => [property.name, property.definition]));
|
|
53
|
+
for (const [name, property] of properties) {
|
|
54
|
+
const field = `${path}.properties.${name}`;
|
|
55
|
+
if (!property.column) {
|
|
56
|
+
report("missing-column", field, "Warehouse-backed properties require a column.");
|
|
57
|
+
}
|
|
58
|
+
else if (!columnName.test(property.column)) {
|
|
59
|
+
report("invalid-column", field, "Invalid warehouse column.");
|
|
60
|
+
}
|
|
61
|
+
// `unique` is allowed: an unenforced assertion that makes the property a join target.
|
|
62
|
+
if (!types.has(property.type) || property.managed || "default" in property) {
|
|
63
|
+
report("invalid-property", field, "Warehouse-backed properties must use a supported scalar type without managed or default.");
|
|
64
|
+
}
|
|
65
|
+
let remainingScopes = 10_000;
|
|
66
|
+
const visit = (key, ancestors) => {
|
|
67
|
+
const definition = properties.get(key);
|
|
68
|
+
if (--remainingScopes < 0 ||
|
|
69
|
+
!definition ||
|
|
70
|
+
ancestors.includes(key) ||
|
|
71
|
+
ancestors.length > 20) {
|
|
72
|
+
report("invalid-scope", field, "Scopes must reference properties without cycles.");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (definition.scope !== undefined &&
|
|
76
|
+
(!Array.isArray(definition.scope) ||
|
|
77
|
+
new Set(definition.scope).size !== definition.scope.length)) {
|
|
78
|
+
report("invalid-scope", field, "Scopes must be a list of unique properties.");
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
for (const parent of definition.scope ?? []) {
|
|
82
|
+
visit(parent, [...ancestors, key]);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
visit(name, []);
|
|
86
|
+
}
|
|
87
|
+
const hasCurrency = source?.currency !== undefined && properties.get(source.currency)?.type === "text";
|
|
88
|
+
if (source?.currency !== undefined && !hasCurrency) {
|
|
89
|
+
report("invalid-source", path, "Currency must name a text property.");
|
|
90
|
+
}
|
|
91
|
+
checkMetrics({ entity, metrics, properties, hasCurrency, report });
|
|
92
|
+
}
|
|
93
|
+
for (const resolved of entity.relationships) {
|
|
94
|
+
checkRelationship({ entity, resolved, entities, report });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The aggregates of one property, which take one argument. `countDistinct` counts what compares
|
|
100
|
+
* exactly; `sum`, `avg`, `min` and `max` take numbers.
|
|
101
|
+
*/
|
|
102
|
+
const AGGREGATES = new Set(["sum", "countDistinct", "avg", "min", "max"]);
|
|
103
|
+
const OPERATORS = new Set([...AGGREGATES, "add", "subtract", "multiply", "divide"]);
|
|
104
|
+
/** The most conditions one aggregate takes. */
|
|
105
|
+
const MAXIMUM_CONDITIONS = 10;
|
|
106
|
+
const CONDITION_OPERATORS = new Set(METRIC_CONDITION_OPERATORS);
|
|
107
|
+
const CONDITION_PROPERTIES = "Metric conditions name properties of the entity.";
|
|
108
|
+
/**
|
|
109
|
+
* The most dimensions and metrics the platform accepts in one entity's model. It also refuses a
|
|
110
|
+
* model definition over {@link MAXIMUM_MODEL_BYTES}.
|
|
111
|
+
*/
|
|
112
|
+
const MAXIMUM_MODEL_MEMBERS = 100;
|
|
113
|
+
/** Stored property types that are not dimensions: their values cannot be grouped by. */
|
|
114
|
+
const UNGROUPABLE_TYPES = new Set(["json", "blob"]);
|
|
115
|
+
/** The most JSON the platform reads as one entity's model: its dimensions and metrics. */
|
|
116
|
+
const MAXIMUM_MODEL_BYTES = 60 * 1024;
|
|
117
|
+
/**
|
|
118
|
+
* An entity's model as the platform decodes it (`warehouse-backed-entities.ts`): a warehouse-backed
|
|
119
|
+
* entity's properties as dimensions, or a stored entity's id and groupable properties over its
|
|
120
|
+
* replication view, and its metrics as the manifest writes them.
|
|
121
|
+
*/
|
|
122
|
+
function modelDefinition(entity) {
|
|
123
|
+
const { definition } = entity.entity;
|
|
124
|
+
const { source } = definition;
|
|
125
|
+
const label = (name, property) => property.label ?? humanize(name);
|
|
126
|
+
const identity = {
|
|
127
|
+
name: entity.name,
|
|
128
|
+
label: definition.label,
|
|
129
|
+
description: definition.description,
|
|
130
|
+
};
|
|
131
|
+
const metrics = metricsManifest(entity);
|
|
132
|
+
if (source === undefined) {
|
|
133
|
+
const entityLabel = typeof definition.label === "string" ? definition.label.toLowerCase() : "";
|
|
134
|
+
const id = {
|
|
135
|
+
name: "id",
|
|
136
|
+
column: "id",
|
|
137
|
+
type: "string",
|
|
138
|
+
label: "ID",
|
|
139
|
+
description: `The ${entityLabel}'s id.`,
|
|
140
|
+
scope: [],
|
|
141
|
+
};
|
|
142
|
+
return {
|
|
143
|
+
...identity,
|
|
144
|
+
source: `ontology/${entity.name}`,
|
|
145
|
+
dimensions: [
|
|
146
|
+
id,
|
|
147
|
+
...entity.properties.flatMap(({ name, definition: property }) => {
|
|
148
|
+
const type = dimensionTypeOf(property.type);
|
|
149
|
+
return type === undefined
|
|
150
|
+
? []
|
|
151
|
+
: [
|
|
152
|
+
{
|
|
153
|
+
name,
|
|
154
|
+
column: name,
|
|
155
|
+
type,
|
|
156
|
+
label: label(name, property),
|
|
157
|
+
description: property.description ?? "",
|
|
158
|
+
scope: [],
|
|
159
|
+
},
|
|
160
|
+
];
|
|
161
|
+
}),
|
|
162
|
+
],
|
|
163
|
+
metrics,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
...identity,
|
|
168
|
+
source: source.asset,
|
|
169
|
+
...(source.currency ? { currencyDimension: source.currency } : {}),
|
|
170
|
+
dimensions: entity.properties.map(({ name, definition: property }) => ({
|
|
171
|
+
name,
|
|
172
|
+
label: label(name, property),
|
|
173
|
+
description: property.description ?? "",
|
|
174
|
+
type: dimensionTypeOf(property.type),
|
|
175
|
+
column: property.column,
|
|
176
|
+
scope: property.scope ?? [],
|
|
177
|
+
})),
|
|
178
|
+
metrics,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function isRecord(value) {
|
|
182
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
183
|
+
}
|
|
184
|
+
/** Whether an expression is an aggregate: `count`, or an aggregate of one property. */
|
|
185
|
+
function isAggregate(expression) {
|
|
186
|
+
return METRIC_AGGREGATES.includes(expression.op);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Why a metric condition is refused, or `undefined`. It names a property of the entity, never a
|
|
190
|
+
* path, with an operator and values a request filter on that property would take, and never a
|
|
191
|
+
* period relative to today.
|
|
192
|
+
*/
|
|
193
|
+
function conditionIssue(condition, properties) {
|
|
194
|
+
if (!isRecord(condition)) {
|
|
195
|
+
return CONDITION_PROPERTIES;
|
|
196
|
+
}
|
|
197
|
+
const property = conditionProperty(condition);
|
|
198
|
+
const definition = typeof property === "string" ? properties.get(property) : undefined;
|
|
199
|
+
const type = definition === undefined ? undefined : dimensionTypeOf(definition.type);
|
|
200
|
+
const { operator, value, values } = condition;
|
|
201
|
+
if (type === undefined) {
|
|
202
|
+
return CONDITION_PROPERTIES;
|
|
203
|
+
}
|
|
204
|
+
if (operator === "inPeriod") {
|
|
205
|
+
return "Metric conditions cannot be relative to today.";
|
|
206
|
+
}
|
|
207
|
+
if (typeof operator !== "string" || !CONDITION_OPERATORS.has(operator)) {
|
|
208
|
+
return `Metric conditions use ${METRIC_CONDITION_OPERATORS.join(", ")}.`;
|
|
209
|
+
}
|
|
210
|
+
// Values that are not a list are as wrong as an empty list, which no operator takes.
|
|
211
|
+
const listed = values === undefined || Array.isArray(values) ? values : [];
|
|
212
|
+
const filter = { operator, value, values: listed };
|
|
213
|
+
return filterValuesIssue(filter) ?? filterTypeIssue(filter, type);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* The metrics of a warehouse-backed or stored entity. A metric's columns name properties of the
|
|
217
|
+
* entity. `hasCurrency` says whether the entity maps a text `source.currency`, which stored entities
|
|
218
|
+
* never do, so their metrics cannot be currency amounts.
|
|
219
|
+
*/
|
|
220
|
+
function checkMetrics(input) {
|
|
221
|
+
const { entity, metrics, properties, hasCurrency } = input;
|
|
222
|
+
let refusals = 0;
|
|
223
|
+
const report = (code, path, message) => {
|
|
224
|
+
refusals++;
|
|
225
|
+
input.report(code, path, message);
|
|
226
|
+
};
|
|
227
|
+
// A stored entity's rows carry its system fields, whose names a metric cannot take.
|
|
228
|
+
const stored = entity.entity.definition.source === undefined;
|
|
229
|
+
const metricCount = Object.keys(metrics).length;
|
|
230
|
+
// A stored entity's dimensions are its id and its groupable properties.
|
|
231
|
+
const dimensionCount = stored
|
|
232
|
+
? 1 + [...properties.values()].filter(({ type }) => !UNGROUPABLE_TYPES.has(type)).length
|
|
233
|
+
: properties.size;
|
|
234
|
+
if (metricCount > 0 && dimensionCount + metricCount > MAXIMUM_MODEL_MEMBERS) {
|
|
235
|
+
report("invalid-metric", `${entity.name}.metrics`, `${entity.name} has ${dimensionCount + metricCount} dimensions and metrics; an entity with ` +
|
|
236
|
+
`metrics may have at most ${MAXIMUM_MODEL_MEMBERS}${stored ? ", counting its id" : ""}, ` +
|
|
237
|
+
"and its definition at most 60 KiB.");
|
|
238
|
+
}
|
|
239
|
+
for (const [name, metric] of Object.entries(metrics)) {
|
|
240
|
+
const field = `${entity.name}.metrics.${name}`;
|
|
241
|
+
if (!SNAKE_CASE_NAME.test(name) ||
|
|
242
|
+
properties.has(name) ||
|
|
243
|
+
(stored && isSystemProperty(name)) ||
|
|
244
|
+
entity.relationships.some((r) => r.name === name) ||
|
|
245
|
+
!metric.description?.trim()) {
|
|
246
|
+
report("invalid-metric", field, "Metrics require unique snake_case names and a description.");
|
|
247
|
+
}
|
|
248
|
+
if (metric.unit !== undefined &&
|
|
249
|
+
!["number", "currency", "ratio", "percent"].includes(metric.unit)) {
|
|
250
|
+
report("invalid-metric", field, "Invalid metric unit.");
|
|
251
|
+
}
|
|
252
|
+
if (metric.format !== undefined &&
|
|
253
|
+
!["decimal", "currency", "percent"].includes(metric.format)) {
|
|
254
|
+
report("invalid-metric", field, "Invalid metric format.");
|
|
255
|
+
}
|
|
256
|
+
if (metric.align !== undefined) {
|
|
257
|
+
report("invalid-metric", field, "Entity metrics take no align; a metric that aligns the properties of several " +
|
|
258
|
+
"entities belongs in defineOntology({ metrics }).");
|
|
259
|
+
}
|
|
260
|
+
let remaining = 10_000;
|
|
261
|
+
/** The balance properties of the metric's aggregates and of the metrics it references. */
|
|
262
|
+
const balances = new Set();
|
|
263
|
+
/** An aggregate's balance property, which must be a date or timestamp property. */
|
|
264
|
+
const checkBalance = (balance) => {
|
|
265
|
+
const type = typeof balance === "string" ? properties.get(balance)?.type : undefined;
|
|
266
|
+
if (type !== "date" && type !== "timestamp") {
|
|
267
|
+
report("invalid-metric", field, "balanceOver names a date or timestamp property.");
|
|
268
|
+
}
|
|
269
|
+
if (typeof balance === "string") {
|
|
270
|
+
balances.add(balance);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
/** An aggregate's conditions, from its `where` option or the `filtered` expression around it. */
|
|
274
|
+
const checkConditions = (where) => {
|
|
275
|
+
if (!Array.isArray(where) || where.length === 0) {
|
|
276
|
+
report("invalid-metric", field, "Metric conditions take at least one entry.");
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (where.length > MAXIMUM_CONDITIONS) {
|
|
280
|
+
report("invalid-metric", field, "Metric conditions take at most 10 entries.");
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
for (const condition of where) {
|
|
284
|
+
const issue = conditionIssue(condition, properties);
|
|
285
|
+
if (issue !== undefined) {
|
|
286
|
+
report("invalid-metric", field, issue);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
/** `aggregate` is the aggregate the expression is an argument of, if any. */
|
|
291
|
+
const visit = (expression, references, depth, aggregate) => {
|
|
292
|
+
if (--remaining < 0 ||
|
|
293
|
+
depth > 30 ||
|
|
294
|
+
references.length > 20 ||
|
|
295
|
+
!expression ||
|
|
296
|
+
typeof expression !== "object") {
|
|
297
|
+
report("invalid-metric", field, "Invalid or overly complex expression.");
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
const conditions = conditionsOf(expression);
|
|
301
|
+
const balance = balanceOf(expression);
|
|
302
|
+
if (conditions !== undefined && expression.op !== "filtered") {
|
|
303
|
+
if (isAggregate(expression)) {
|
|
304
|
+
checkConditions(conditions);
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
report("invalid-metric", field, "Only count, sum, countDistinct, avg, min and max take where.");
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
if (balance !== undefined) {
|
|
311
|
+
if (isAggregate(expression)) {
|
|
312
|
+
checkBalance(balance);
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
report("invalid-metric", field, "Only count, sum, countDistinct, avg, min and max take balanceOver.");
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
switch (expression.op) {
|
|
319
|
+
case "count":
|
|
320
|
+
if (aggregate !== undefined) {
|
|
321
|
+
report("invalid-metric", field, "Nested aggregates are unsupported.");
|
|
322
|
+
}
|
|
323
|
+
return true;
|
|
324
|
+
case "literal":
|
|
325
|
+
if (typeof expression.value !== "string" ||
|
|
326
|
+
expression.value.length >= 100 ||
|
|
327
|
+
!/^[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?$/.test(expression.value) ||
|
|
328
|
+
!Number.isFinite(Number(expression.value))) {
|
|
329
|
+
report("invalid-metric", field, "Literals must be finite numbers.");
|
|
330
|
+
}
|
|
331
|
+
return false;
|
|
332
|
+
case "column": {
|
|
333
|
+
const type = properties.get(expression.name)?.type ?? "";
|
|
334
|
+
if (aggregate === "countDistinct") {
|
|
335
|
+
if (!distinctTypes.has(type)) {
|
|
336
|
+
report("invalid-metric", field, "Distinct counts require a text, email, url, select, integer, date or timestamp " +
|
|
337
|
+
"property.");
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
else if (aggregate === undefined) {
|
|
341
|
+
report("invalid-metric", field, "Sums require a numeric property.");
|
|
342
|
+
}
|
|
343
|
+
else if (!["integer", "number"].includes(type)) {
|
|
344
|
+
report("invalid-metric", field, "avg, min, max and sum require a numeric property.");
|
|
345
|
+
}
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
case "metric": {
|
|
349
|
+
const target = metrics[expression.name];
|
|
350
|
+
if (!target) {
|
|
351
|
+
report("unknown-metric", field, "Unknown metric reference.");
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
if (references.includes(expression.name)) {
|
|
355
|
+
report("circular-metric", field, "Circular metric reference.");
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
if (aggregate !== undefined) {
|
|
359
|
+
report("invalid-metric", field, "Metric references cannot be aggregated again.");
|
|
360
|
+
}
|
|
361
|
+
if (target.unit === "currency" && !hasCurrency) {
|
|
362
|
+
report("invalid-metric", field, "Currency metrics require source.currency.");
|
|
363
|
+
}
|
|
364
|
+
return visit(target, [...references, expression.name], depth + 1);
|
|
365
|
+
}
|
|
366
|
+
case "filtered": {
|
|
367
|
+
// The wrapper counts as the aggregate it wraps, which must not declare conditions too.
|
|
368
|
+
const args = Array.isArray(expression.args)
|
|
369
|
+
? expression.args
|
|
370
|
+
: [];
|
|
371
|
+
const [inner] = args;
|
|
372
|
+
if (args.length !== 1 ||
|
|
373
|
+
!isRecord(inner) ||
|
|
374
|
+
!isAggregate(inner) ||
|
|
375
|
+
conditionsOf(inner) !== undefined) {
|
|
376
|
+
report("invalid-metric", field, "Invalid expression operator or arity.");
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
checkConditions(expression.where);
|
|
380
|
+
return visit(inner, references, depth + 1, aggregate);
|
|
381
|
+
}
|
|
382
|
+
default: {
|
|
383
|
+
const aggregates = AGGREGATES.has(expression.op);
|
|
384
|
+
if (!OPERATORS.has(expression.op) ||
|
|
385
|
+
!Array.isArray(expression.args) ||
|
|
386
|
+
expression.args.length !== (aggregates ? 1 : 2)) {
|
|
387
|
+
report("invalid-metric", field, "Invalid expression operator or arity.");
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
if (aggregates && aggregate !== undefined) {
|
|
391
|
+
report("invalid-metric", field, "Nested aggregates are unsupported.");
|
|
392
|
+
}
|
|
393
|
+
if (expression.op === "countDistinct" && expression.args[0]?.op !== "column") {
|
|
394
|
+
report("invalid-metric", field, "Distinct counts take one property.");
|
|
395
|
+
}
|
|
396
|
+
const aggregated = expression.args
|
|
397
|
+
.map((arg) => visit(arg, references, depth + 1, aggregates ? expression.op : aggregate))
|
|
398
|
+
.some(Boolean);
|
|
399
|
+
return aggregates || aggregated;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
if (!visit(metric, [name], 0)) {
|
|
404
|
+
report("invalid-metric", field, "A metric must contain an aggregate.");
|
|
405
|
+
}
|
|
406
|
+
if (metric.unit === "currency" && !hasCurrency) {
|
|
407
|
+
report("invalid-metric", field, "Currency metrics require source.currency.");
|
|
408
|
+
}
|
|
409
|
+
if (balances.size > 1) {
|
|
410
|
+
report("invalid-metric", field, "A metric reads balances over two properties.");
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
// The platform builds a model of every warehouse-backed entity, and of each stored entity with
|
|
414
|
+
// metrics. Its size is checked only once the metrics are valid, which writing them requires.
|
|
415
|
+
if (refusals === 0 && (!stored || metricCount > 0)) {
|
|
416
|
+
const bytes = new TextEncoder().encode(JSON.stringify(modelDefinition(entity))).byteLength;
|
|
417
|
+
if (bytes > MAXIMUM_MODEL_BYTES) {
|
|
418
|
+
input.report("invalid-metric", entity.name, `${entity.name}'s model, its dimensions and metrics as SegmentStream reads them, takes ` +
|
|
419
|
+
`${(bytes / 1024).toFixed(1)} KiB; the limit is ${MAXIMUM_MODEL_BYTES / 1024} KiB.`);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* One case per pairing. Stored → stored relationships never declare `on`. A relationship with a
|
|
425
|
+
* warehouse-backed end is value-matched: a `rel.one` with one `on` pair and no delete rule or
|
|
426
|
+
* optionality, because no key column or foreign key backs it.
|
|
427
|
+
*/
|
|
428
|
+
function checkRelationship(input) {
|
|
429
|
+
const { entity, resolved, entities, report } = input;
|
|
430
|
+
const { name, relationship, target } = resolved;
|
|
431
|
+
const landing = entities.find((candidate) => candidate.name === target);
|
|
432
|
+
const field = `${entity.name}.relationships.${name}`;
|
|
433
|
+
const storedOwner = entity.entity.definition.source === undefined;
|
|
434
|
+
const targetSource = landing?.entity.definition.source;
|
|
435
|
+
if (storedOwner && targetSource === undefined) {
|
|
436
|
+
if (relationship.cardinality === "one" && relationship.on !== undefined) {
|
|
437
|
+
report("invalid-join", field, "Stored relationships cannot declare on.");
|
|
438
|
+
}
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
if (relationship.cardinality !== "one") {
|
|
442
|
+
const message = storedOwner
|
|
443
|
+
? "Relationships to warehouse-backed entities support rel.one only."
|
|
444
|
+
: "Warehouse-backed entities support rel.one only.";
|
|
445
|
+
report("invalid-join", field, message);
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const pairs = Object.entries(relationship.on ?? {});
|
|
449
|
+
const [own, other] = pairs.length === 1 ? pairs[0] : [undefined, undefined];
|
|
450
|
+
if (relationship.onDelete !== undefined || relationship.optional) {
|
|
451
|
+
const message = storedOwner
|
|
452
|
+
? "A relationship to a warehouse-backed entity has no delete rule; its optionality follows " +
|
|
453
|
+
`${own ?? "the property named in on"}.`
|
|
454
|
+
: "Relationships of warehouse-backed entities have no delete rule or optionality: their " +
|
|
455
|
+
"joins never drop a row.";
|
|
456
|
+
report("invalid-join", field, message);
|
|
457
|
+
}
|
|
458
|
+
if (own === undefined || other === undefined) {
|
|
459
|
+
report(pairs.length ? "invalid-join" : "missing-join", field, "Declare one property pair in on.");
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const ownProperty = entity.properties.find((property) => property.name === own)?.definition;
|
|
463
|
+
if (storedOwner && ownProperty === undefined) {
|
|
464
|
+
report("invalid-join", field, `The own side of on must be a declared property of ${entity.name}: it holds the reference.`);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
const targetProperty = landing?.properties.find((property) => property.name === other);
|
|
468
|
+
const text = (type) => ["email", "url", "select"].includes(type ?? "") ? "text" : type;
|
|
469
|
+
let targetType;
|
|
470
|
+
let keyed;
|
|
471
|
+
if (targetSource === undefined) {
|
|
472
|
+
targetType = other === "id" ? "text" : targetProperty?.definition.type;
|
|
473
|
+
keyed = other === "id" || targetProperty?.definition.unique === true;
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
const { key } = targetSource;
|
|
477
|
+
const singleKey = Array.isArray(key) && key.length === 1 ? key[0] : undefined;
|
|
478
|
+
targetType = targetProperty?.definition.type;
|
|
479
|
+
keyed =
|
|
480
|
+
targetProperty !== undefined &&
|
|
481
|
+
(targetProperty.definition.unique === true ||
|
|
482
|
+
(singleKey !== undefined && targetProperty.definition.column === singleKey));
|
|
483
|
+
}
|
|
484
|
+
if ((ownProperty !== undefined && !joinTypes.has(ownProperty.type)) ||
|
|
485
|
+
(targetType !== undefined && !joinTypes.has(targetType))) {
|
|
486
|
+
report("invalid-join", field, "Join properties must be text, integer, date or timestamp.");
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
if (!ownProperty || !targetType || text(ownProperty.type) !== text(targetType) || !keyed) {
|
|
490
|
+
const accepted = targetSource === undefined
|
|
491
|
+
? "id or a unique property"
|
|
492
|
+
: "the property that maps its single source key column, or a unique property";
|
|
493
|
+
report("invalid-join", field, `Join properties must have compatible types and target ${accepted}.`);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** What a token signs before the webhook's name, so the key derives nothing else. */
|
|
2
|
+
export declare const WEBHOOK_TOKEN_CONTEXT = "segmentstream.webhook.v1:";
|
|
3
|
+
/**
|
|
4
|
+
* The token of an unsigned webhook: `base64url(HMAC-SHA256(secret, context + name))` without
|
|
5
|
+
* padding, 43 characters. `secret` is the workspace's webhook secret as the platform stores it and
|
|
6
|
+
* `name` the webhook's wire name. The ontology service and backend-next derive the same value, so
|
|
7
|
+
* no token is ever stored (`tests/fixtures/ontology-webhook-token.json`).
|
|
8
|
+
*/
|
|
9
|
+
export declare function webhookToken(secret: string, name: string): string;
|
|
10
|
+
/** Whether a received token is the webhook's, compared in constant time. */
|
|
11
|
+
export declare function webhookTokenMatches(secret: string, name: string, received: string): boolean;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
/** What a token signs before the webhook's name, so the key derives nothing else. */
|
|
3
|
+
export const WEBHOOK_TOKEN_CONTEXT = "segmentstream.webhook.v1:";
|
|
4
|
+
/**
|
|
5
|
+
* The token of an unsigned webhook: `base64url(HMAC-SHA256(secret, context + name))` without
|
|
6
|
+
* padding, 43 characters. `secret` is the workspace's webhook secret as the platform stores it and
|
|
7
|
+
* `name` the webhook's wire name. The ontology service and backend-next derive the same value, so
|
|
8
|
+
* no token is ever stored (`tests/fixtures/ontology-webhook-token.json`).
|
|
9
|
+
*/
|
|
10
|
+
export function webhookToken(secret, name) {
|
|
11
|
+
return createHmac("sha256", secret).update(`${WEBHOOK_TOKEN_CONTEXT}${name}`).digest("base64url");
|
|
12
|
+
}
|
|
13
|
+
/** Whether a received token is the webhook's, compared in constant time. */
|
|
14
|
+
export function webhookTokenMatches(secret, name, received) {
|
|
15
|
+
const expected = Buffer.from(webhookToken(secret, name));
|
|
16
|
+
const actual = Buffer.from(received);
|
|
17
|
+
return actual.length === expected.length && timingSafeEqual(actual, expected);
|
|
18
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
/**
|
|
3
|
+
* Webhook triggers: what a declaration may say and what a delivery carries. This module imports no
|
|
4
|
+
* Node built-in, so the workflows entry may re-export it; the token derivation, which needs
|
|
5
|
+
* `node:crypto`, is `webhook-token.ts`.
|
|
6
|
+
*/
|
|
7
|
+
/** The signature formats a webhook trigger can check, each a provider's published format. */
|
|
8
|
+
export declare const WEBHOOK_SIGNATURE_SCHEMES: readonly ["stripe", "meta"];
|
|
9
|
+
export type WebhookSignatureScheme = (typeof WEBHOOK_SIGNATURE_SCHEMES)[number];
|
|
10
|
+
/** The most webhook triggers one ontology may declare across its workflows. */
|
|
11
|
+
export declare const MAX_WEBHOOKS = 20;
|
|
12
|
+
/** The most request headers one webhook trigger may pass to its workflow. */
|
|
13
|
+
export declare const MAX_WEBHOOK_HEADERS = 10;
|
|
14
|
+
/** The default delivery body limit, in bytes. Meta's opt-in scheme has its own limit below. */
|
|
15
|
+
export declare const MAX_WEBHOOK_BODY_BYTES = 1048576;
|
|
16
|
+
/** Meta batches messages and statuses into deliveries up to 3 MiB. Other schemes keep 1 MiB. */
|
|
17
|
+
export declare const MAX_META_WEBHOOK_BODY_BYTES: number;
|
|
18
|
+
/** Bounds registration query values before they are sent to the backend or echoed. */
|
|
19
|
+
export declare const MAX_WEBHOOK_VERIFICATION_CHARS = 4096;
|
|
20
|
+
/** Where deliveries arrive: `/api/webhooks/<wire name>`, followed by the token when unsigned. */
|
|
21
|
+
export declare const WEBHOOK_BASE_PATH = "/api/webhooks";
|
|
22
|
+
/** The path of a webhook, without its token: `/api/webhooks/stripe_eu`. */
|
|
23
|
+
export declare function webhookPath(name: string): string;
|
|
24
|
+
/** A workspace secret's name, as the secrets API accepts it: `stripe-webhook-signing-secret`. */
|
|
25
|
+
export declare const WORKSPACE_SECRET_NAME: RegExp;
|
|
26
|
+
/** Why a header may not be passed to a workflow, or `undefined` when it may. */
|
|
27
|
+
export declare function webhookHeaderProblem(name: unknown): string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* The input of a workflow that a webhook starts: one delivery exactly as it arrived. The workflow
|
|
30
|
+
* parses the body; header names are data and keep their lowercase spelling on the wire.
|
|
31
|
+
*/
|
|
32
|
+
export declare const webhookDelivery: Schema.Struct<{
|
|
33
|
+
readonly body: import("./property.js").Property<string, false, false>;
|
|
34
|
+
readonly contentType: import("./property.js").Property<string, false, false>;
|
|
35
|
+
readonly query: import("./property.js").Property<string, false, false>;
|
|
36
|
+
readonly headers: Schema.$Record<Schema.String, Schema.String>;
|
|
37
|
+
readonly receivedAt: import("./property.js").Property<string, false, false>;
|
|
38
|
+
}>;
|
|
39
|
+
/** One webhook delivery, as the workflow's run function receives it. */
|
|
40
|
+
export type WebhookDelivery = typeof webhookDelivery.Type;
|
package/dist/webhooks.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { p } from "./property.js";
|
|
3
|
+
/**
|
|
4
|
+
* Webhook triggers: what a declaration may say and what a delivery carries. This module imports no
|
|
5
|
+
* Node built-in, so the workflows entry may re-export it; the token derivation, which needs
|
|
6
|
+
* `node:crypto`, is `webhook-token.ts`.
|
|
7
|
+
*/
|
|
8
|
+
/** The signature formats a webhook trigger can check, each a provider's published format. */
|
|
9
|
+
export const WEBHOOK_SIGNATURE_SCHEMES = ["stripe", "meta"];
|
|
10
|
+
/** The most webhook triggers one ontology may declare across its workflows. */
|
|
11
|
+
export const MAX_WEBHOOKS = 20;
|
|
12
|
+
/** The most request headers one webhook trigger may pass to its workflow. */
|
|
13
|
+
export const MAX_WEBHOOK_HEADERS = 10;
|
|
14
|
+
/** The default delivery body limit, in bytes. Meta's opt-in scheme has its own limit below. */
|
|
15
|
+
export const MAX_WEBHOOK_BODY_BYTES = 1_048_576;
|
|
16
|
+
/** Meta batches messages and statuses into deliveries up to 3 MiB. Other schemes keep 1 MiB. */
|
|
17
|
+
export const MAX_META_WEBHOOK_BODY_BYTES = 3 * 1_048_576;
|
|
18
|
+
/** Bounds registration query values before they are sent to the backend or echoed. */
|
|
19
|
+
export const MAX_WEBHOOK_VERIFICATION_CHARS = 4_096;
|
|
20
|
+
/** Where deliveries arrive: `/api/webhooks/<wire name>`, followed by the token when unsigned. */
|
|
21
|
+
export const WEBHOOK_BASE_PATH = "/api/webhooks";
|
|
22
|
+
/** The path of a webhook, without its token: `/api/webhooks/stripe_eu`. */
|
|
23
|
+
export function webhookPath(name) {
|
|
24
|
+
return `${WEBHOOK_BASE_PATH}/${name}`;
|
|
25
|
+
}
|
|
26
|
+
/** A workspace secret's name, as the secrets API accepts it: `stripe-webhook-signing-secret`. */
|
|
27
|
+
export const WORKSPACE_SECRET_NAME = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
28
|
+
const HEADER_NAME = /^[a-z0-9!#$%&'*+.^_`|~-]{1,64}$/;
|
|
29
|
+
/** Headers that carry credentials or the platform's own context and never reach a workflow. */
|
|
30
|
+
const REFUSED_HEADERS = new Set(["authorization", "proxy-authorization", "cookie"]);
|
|
31
|
+
const REFUSED_HEADER_PREFIXES = ["x-vercel-", "x-segmentstream-"];
|
|
32
|
+
/** Why a header may not be passed to a workflow, or `undefined` when it may. */
|
|
33
|
+
export function webhookHeaderProblem(name) {
|
|
34
|
+
if (typeof name !== "string" || !HEADER_NAME.test(name)) {
|
|
35
|
+
return `${JSON.stringify(name) ?? "undefined"} is not a lowercase header name.`;
|
|
36
|
+
}
|
|
37
|
+
if (REFUSED_HEADERS.has(name) ||
|
|
38
|
+
REFUSED_HEADER_PREFIXES.some((prefix) => name.startsWith(prefix))) {
|
|
39
|
+
return `${name} carries credentials or platform context and is never passed to a workflow.`;
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The input of a workflow that a webhook starts: one delivery exactly as it arrived. The workflow
|
|
45
|
+
* parses the body; header names are data and keep their lowercase spelling on the wire.
|
|
46
|
+
*/
|
|
47
|
+
export const webhookDelivery = Schema.Struct({
|
|
48
|
+
body: p.text({ description: "The request body as UTF-8 text, exactly as received." }),
|
|
49
|
+
contentType: p.text({ description: "The Content-Type header, or empty when it was absent." }),
|
|
50
|
+
query: p.text({ description: "The raw query string without ?, or empty." }),
|
|
51
|
+
headers: Schema.Record(Schema.String, Schema.String).annotate({
|
|
52
|
+
description: "The headers the trigger lists that were present, lowercase names to values.",
|
|
53
|
+
}),
|
|
54
|
+
receivedAt: p.timestamp({ description: "When the service received the request, in UTC." }),
|
|
55
|
+
});
|
package/dist/wire.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
/**
|
|
3
|
+
* `Unknown operator. Expected one of: eq, ne, in`: what a closed struct reports for a key it does
|
|
4
|
+
* not declare, so that a caller can correct the key without guessing. Long lists are cut short.
|
|
5
|
+
*/
|
|
6
|
+
export declare function expectedOneOf(problem: string, accepted: ReadonlyArray<string>): string;
|
|
7
|
+
/** A closed wire object with explicit key mappings and an unchanged decoded TypeScript shape. */
|
|
8
|
+
export declare function wireStruct<const F extends Schema.Struct.Fields, const M extends {
|
|
9
|
+
readonly [K in keyof F]?: string;
|
|
10
|
+
}>(fields: F, mapping: M, unknownKey?: string): Schema.encodeKeys<Schema.Struct<F>, M>;
|