@segmentstream/ontology 0.0.0-stage → 0.92.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/NOTICE +2 -0
- package/README.md +1655 -2
- package/dist/action.d.ts +193 -0
- package/dist/action.js +41 -0
- package/dist/agent-chat.d.ts +44 -0
- package/dist/agent-chat.js +91 -0
- package/dist/agent-task-contract.d.ts +64 -0
- package/dist/agent-task-contract.js +15 -0
- package/dist/agent-task.d.ts +39 -0
- package/dist/agent-task.js +112 -0
- package/dist/analyze.d.ts +215 -0
- package/dist/analyze.js +2438 -0
- package/dist/app-feedback.d.ts +167 -0
- package/dist/app-feedback.js +176 -0
- package/dist/authoring-input.d.ts +3 -0
- package/dist/authoring-input.js +107 -0
- package/dist/authoring-names.d.ts +4 -0
- package/dist/authoring-names.js +13 -0
- package/dist/authoring-records.d.ts +35 -0
- package/dist/authoring-records.js +264 -0
- package/dist/authoring.d.ts +15 -0
- package/dist/authoring.js +331 -0
- package/dist/bin/check.d.ts +30 -0
- package/dist/bin/check.js +99 -0
- package/dist/bin/load.d.ts +48 -0
- package/dist/bin/load.js +139 -0
- package/dist/bin/main.d.ts +31 -0
- package/dist/bin/main.js +121 -0
- package/dist/bin/migrate.d.ts +57 -0
- package/dist/bin/migrate.js +170 -0
- package/dist/bin/output.d.ts +31 -0
- package/dist/bin/output.js +84 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +31 -0
- package/dist/blob.d.ts +52 -0
- package/dist/blob.js +87 -0
- package/dist/channel-session.d.ts +16 -0
- package/dist/channel-session.js +16 -0
- package/dist/chat.d.ts +43 -0
- package/dist/chat.js +34 -0
- package/dist/confirmation.d.ts +46 -0
- package/dist/confirmation.js +41 -0
- package/dist/connection.d.ts +213 -0
- package/dist/connection.js +289 -0
- package/dist/deployment.d.ts +35 -0
- package/dist/deployment.js +76 -0
- package/dist/diagnostics.d.ts +27 -0
- package/dist/diagnostics.js +106 -0
- package/dist/emails.d.ts +70 -0
- package/dist/emails.js +221 -0
- package/dist/entity.d.ts +331 -0
- package/dist/entity.js +153 -0
- package/dist/errors.d.ts +154 -0
- package/dist/errors.js +109 -0
- package/dist/feedback-config.d.ts +24 -0
- package/dist/feedback-config.js +126 -0
- package/dist/files.d.ts +39 -0
- package/dist/files.js +4 -0
- package/dist/groups.d.ts +95 -0
- package/dist/groups.js +280 -0
- package/dist/index.d.ts +109 -0
- package/dist/index.js +70 -0
- package/dist/internal/diagnostics.js +594 -0
- package/dist/legacy.d.ts +160 -0
- package/dist/legacy.js +270 -0
- package/dist/manifest-compatibility.d.ts +8 -0
- package/dist/manifest-compatibility.js +87 -0
- package/dist/manifest.d.ts +3329 -0
- package/dist/manifest.js +757 -0
- package/dist/me.d.ts +46 -0
- package/dist/me.js +109 -0
- package/dist/metric-filters.d.ts +48 -0
- package/dist/metric-filters.js +252 -0
- package/dist/metric-routes.d.ts +132 -0
- package/dist/metric-routes.js +498 -0
- package/dist/metric.d.ts +172 -0
- package/dist/metric.js +132 -0
- package/dist/migrate/apply.d.ts +94 -0
- package/dist/migrate/apply.js +526 -0
- package/dist/migrate/errors.d.ts +46 -0
- package/dist/migrate/errors.js +38 -0
- package/dist/migrate/index.d.ts +10 -0
- package/dist/migrate/index.js +7 -0
- package/dist/migrate/model.d.ts +2311 -0
- package/dist/migrate/model.js +148 -0
- package/dist/migrate/plan.d.ts +51 -0
- package/dist/migrate/plan.js +1856 -0
- package/dist/migrate/preview.d.ts +13 -0
- package/dist/migrate/preview.js +65 -0
- package/dist/migrate/storage.d.ts +226 -0
- package/dist/migrate/storage.js +774 -0
- package/dist/model-metrics.d.ts +22 -0
- package/dist/model-metrics.js +545 -0
- package/dist/names.d.ts +49 -0
- package/dist/names.js +110 -0
- package/dist/navigation-artifact.d.ts +13 -0
- package/dist/navigation-artifact.js +11 -0
- package/dist/navigation-catalog.d.ts +55 -0
- package/dist/navigation-catalog.js +297 -0
- package/dist/nitro-navigation.d.ts +3 -0
- package/dist/nitro-navigation.js +64 -0
- package/dist/nitro-workflows.d.ts +108 -0
- package/dist/nitro-workflows.js +286 -0
- package/dist/nitro.d.ts +40 -0
- package/dist/nitro.js +50 -0
- package/dist/ontology.d.ts +41 -0
- package/dist/ontology.js +46 -0
- package/dist/permissions.d.ts +198 -0
- package/dist/permissions.js +272 -0
- package/dist/property.d.ts +188 -0
- package/dist/property.js +301 -0
- package/dist/query.d.ts +245 -0
- package/dist/query.js +615 -0
- package/dist/relationship.d.ts +99 -0
- package/dist/relationship.js +33 -0
- package/dist/render.d.ts +81 -0
- package/dist/render.js +512 -0
- package/dist/replication/baseline.d.ts +51 -0
- package/dist/replication/baseline.js +215 -0
- package/dist/replication/bigquery.d.ts +37 -0
- package/dist/replication/bigquery.js +211 -0
- package/dist/replication/coverage.d.ts +14 -0
- package/dist/replication/coverage.js +53 -0
- package/dist/replication/evolution.d.ts +25 -0
- package/dist/replication/evolution.js +184 -0
- package/dist/replication/identities.d.ts +6 -0
- package/dist/replication/identities.js +47 -0
- package/dist/replication/legacy-baseline.d.ts +27 -0
- package/dist/replication/legacy-baseline.js +109 -0
- package/dist/replication/legacy-store.d.ts +19 -0
- package/dist/replication/legacy-store.js +63 -0
- package/dist/replication/lineage.d.ts +36 -0
- package/dist/replication/lineage.js +72 -0
- package/dist/replication/migrate.d.ts +21 -0
- package/dist/replication/migrate.js +84 -0
- package/dist/replication/model.d.ts +52 -0
- package/dist/replication/model.js +99 -0
- package/dist/replication/scans.d.ts +34 -0
- package/dist/replication/scans.js +158 -0
- package/dist/replication/schema.d.ts +11 -0
- package/dist/replication/schema.js +226 -0
- package/dist/replication/shadow-schema.d.ts +4 -0
- package/dist/replication/shadow-schema.js +61 -0
- package/dist/replication/shadow.d.ts +127 -0
- package/dist/replication/shadow.js +614 -0
- package/dist/replication/source-replacement.d.ts +33 -0
- package/dist/replication/source-replacement.js +76 -0
- package/dist/replication/store.d.ts +36 -0
- package/dist/replication/store.js +382 -0
- package/dist/replication/transaction.d.ts +23 -0
- package/dist/replication/transaction.js +88 -0
- package/dist/role.d.ts +61 -0
- package/dist/role.js +76 -0
- package/dist/runtime/action-deadlocks.d.ts +21 -0
- package/dist/runtime/action-deadlocks.js +130 -0
- package/dist/runtime/action-transactions.d.ts +35 -0
- package/dist/runtime/action-transactions.js +54 -0
- package/dist/runtime/agent-counters.d.ts +26 -0
- package/dist/runtime/agent-counters.js +98 -0
- package/dist/runtime/agent-tasks.d.ts +63 -0
- package/dist/runtime/agent-tasks.js +120 -0
- package/dist/runtime/agents.d.ts +15 -0
- package/dist/runtime/agents.js +457 -0
- package/dist/runtime/batch-diagnostics.d.ts +22 -0
- package/dist/runtime/batch-diagnostics.js +89 -0
- package/dist/runtime/batch.d.ts +52 -0
- package/dist/runtime/batch.js +534 -0
- package/dist/runtime/channel-session-revocation.d.ts +3 -0
- package/dist/runtime/channel-session-revocation.js +5 -0
- package/dist/runtime/channel-sessions.d.ts +4 -0
- package/dist/runtime/channel-sessions.js +61 -0
- package/dist/runtime/confirmations.d.ts +29 -0
- package/dist/runtime/confirmations.js +57 -0
- package/dist/runtime/cursor.d.ts +23 -0
- package/dist/runtime/cursor.js +100 -0
- package/dist/runtime/deployment.d.ts +7 -0
- package/dist/runtime/deployment.js +4 -0
- package/dist/runtime/errors.d.ts +118 -0
- package/dist/runtime/errors.js +109 -0
- package/dist/runtime/federation-tables.d.ts +2 -0
- package/dist/runtime/federation-tables.js +20 -0
- package/dist/runtime/federation.d.ts +42 -0
- package/dist/runtime/federation.js +222 -0
- package/dist/runtime/files.d.ts +39 -0
- package/dist/runtime/files.js +44 -0
- package/dist/runtime/generated-actions.d.ts +37 -0
- package/dist/runtime/generated-actions.js +307 -0
- package/dist/runtime/history.d.ts +91 -0
- package/dist/runtime/history.js +77 -0
- package/dist/runtime/ids.d.ts +6 -0
- package/dist/runtime/ids.js +39 -0
- package/dist/runtime/member-tables.d.ts +8 -0
- package/dist/runtime/member-tables.js +33 -0
- package/dist/runtime/member-writes.d.ts +78 -0
- package/dist/runtime/member-writes.js +202 -0
- package/dist/runtime/metric-query.d.ts +19 -0
- package/dist/runtime/metric-query.js +411 -0
- package/dist/runtime/model.d.ts +67 -0
- package/dist/runtime/model.js +150 -0
- package/dist/runtime/new-user-hook.d.ts +6 -0
- package/dist/runtime/new-user-hook.js +37 -0
- package/dist/runtime/oauth.d.ts +9 -0
- package/dist/runtime/oauth.js +299 -0
- package/dist/runtime/pipeline.d.ts +155 -0
- package/dist/runtime/pipeline.js +597 -0
- package/dist/runtime/postgres-tls.d.ts +10 -0
- package/dist/runtime/postgres-tls.js +14 -0
- package/dist/runtime/principals.d.ts +302 -0
- package/dist/runtime/principals.js +1307 -0
- package/dist/runtime/reads.d.ts +55 -0
- package/dist/runtime/reads.js +313 -0
- package/dist/runtime/records.d.ts +42 -0
- package/dist/runtime/records.js +245 -0
- package/dist/runtime/resolve-agent-identity.d.ts +6 -0
- package/dist/runtime/resolve-agent-identity.js +181 -0
- package/dist/runtime/service-binding.d.ts +18 -0
- package/dist/runtime/service-binding.js +266 -0
- package/dist/runtime/sign-in-links.d.ts +68 -0
- package/dist/runtime/sign-in-links.js +147 -0
- package/dist/runtime/sql-runtime.d.ts +131 -0
- package/dist/runtime/sql-runtime.js +362 -0
- package/dist/runtime/statement.d.ts +18 -0
- package/dist/runtime/statement.js +31 -0
- package/dist/runtime/user-identities.d.ts +66 -0
- package/dist/runtime/user-identities.js +106 -0
- package/dist/runtime/user-identity-sql.d.ts +86 -0
- package/dist/runtime/user-identity-sql.js +297 -0
- package/dist/runtime/user-roles.d.ts +16 -0
- package/dist/runtime/user-roles.js +32 -0
- package/dist/runtime/validation.d.ts +16 -0
- package/dist/runtime/validation.js +26 -0
- package/dist/runtime/where.d.ts +57 -0
- package/dist/runtime/where.js +404 -0
- package/dist/runtime/workflow-admission.d.ts +49 -0
- package/dist/runtime/workflow-admission.js +92 -0
- package/dist/runtime/workflow-argument-codec.d.ts +10 -0
- package/dist/runtime/workflow-argument-codec.js +120 -0
- package/dist/runtime/workflow-arguments.d.ts +17 -0
- package/dist/runtime/workflow-arguments.js +99 -0
- package/dist/runtime/workflow-starts.d.ts +203 -0
- package/dist/runtime/workflow-starts.js +493 -0
- package/dist/runtime/workflow-users.d.ts +9 -0
- package/dist/runtime/workflow-users.js +17 -0
- package/dist/runtime/workload.d.ts +25 -0
- package/dist/runtime/workload.js +24 -0
- package/dist/runtime/writes.d.ts +108 -0
- package/dist/runtime/writes.js +491 -0
- package/dist/runtime-source.d.ts +22 -0
- package/dist/runtime-source.js +28 -0
- package/dist/runtime.d.ts +310 -0
- package/dist/runtime.js +31 -0
- package/dist/server.d.ts +23 -0
- package/dist/server.js +107 -0
- package/dist/service/agent/attachments.d.ts +33 -0
- package/dist/service/agent/attachments.js +228 -0
- package/dist/service/agent/authentication.d.ts +22 -0
- package/dist/service/agent/authentication.js +58 -0
- package/dist/service/agent/confirmations.d.ts +5 -0
- package/dist/service/agent/confirmations.js +73 -0
- package/dist/service/agent/conversation-routes.d.ts +14 -0
- package/dist/service/agent/conversation-routes.js +45 -0
- package/dist/service/agent/conversations.d.ts +40 -0
- package/dist/service/agent/conversations.js +69 -0
- package/dist/service/agent/files.d.ts +12 -0
- package/dist/service/agent/files.js +69 -0
- package/dist/service/agent/protocol.d.ts +90 -0
- package/dist/service/agent/protocol.js +114 -0
- package/dist/service/agent/server.d.ts +28 -0
- package/dist/service/agent/server.js +374 -0
- package/dist/service/agent/task-caller.d.ts +21 -0
- package/dist/service/agent/task-caller.js +35 -0
- package/dist/service/agent/task-start.d.ts +53 -0
- package/dist/service/agent/task-start.js +161 -0
- package/dist/service/agent/tasks.d.ts +40 -0
- package/dist/service/agent/tasks.js +155 -0
- package/dist/service/api.d.ts +50 -0
- package/dist/service/api.js +288 -0
- package/dist/service/authentication.d.ts +227 -0
- package/dist/service/authentication.js +767 -0
- package/dist/service/caller-context.d.ts +24 -0
- package/dist/service/caller-context.js +6 -0
- package/dist/service/catalog.d.ts +42 -0
- package/dist/service/catalog.js +66 -0
- package/dist/service/channel/provider.d.ts +10 -0
- package/dist/service/channel/provider.js +1 -0
- package/dist/service/channel/providers/telegram.d.ts +18 -0
- package/dist/service/channel/providers/telegram.js +108 -0
- package/dist/service/channel/sessions.d.ts +5 -0
- package/dist/service/channel/sessions.js +53 -0
- package/dist/service/channel/sign-in.d.ts +7 -0
- package/dist/service/channel/sign-in.js +78 -0
- package/dist/service/chat/archive.d.ts +64 -0
- package/dist/service/chat/archive.js +62 -0
- package/dist/service/chat/attribution.d.ts +26 -0
- package/dist/service/chat/attribution.js +28 -0
- package/dist/service/chat/delivery.d.ts +18 -0
- package/dist/service/chat/delivery.js +251 -0
- package/dist/service/chat/diagnostics.d.ts +2 -0
- package/dist/service/chat/diagnostics.js +35 -0
- package/dist/service/chat/envelope.d.ts +96 -0
- package/dist/service/chat/envelope.js +39 -0
- package/dist/service/chat/idempotency.d.ts +19 -0
- package/dist/service/chat/idempotency.js +37 -0
- package/dist/service/chat/providers/telegram.d.ts +36 -0
- package/dist/service/chat/providers/telegram.js +133 -0
- package/dist/service/chat/reads.d.ts +25 -0
- package/dist/service/chat/reads.js +75 -0
- package/dist/service/chat/resolve.d.ts +34 -0
- package/dist/service/chat/resolve.js +150 -0
- package/dist/service/chat/routes.d.ts +23 -0
- package/dist/service/chat/routes.js +75 -0
- package/dist/service/chat/schemas.d.ts +43 -0
- package/dist/service/chat/schemas.js +31 -0
- package/dist/service/config.d.ts +218 -0
- package/dist/service/config.js +265 -0
- package/dist/service/connection-stream.d.ts +10 -0
- package/dist/service/connection-stream.js +191 -0
- package/dist/service/connections.d.ts +60 -0
- package/dist/service/connections.js +271 -0
- package/dist/service/decisions.d.ts +35 -0
- package/dist/service/decisions.js +63 -0
- package/dist/service/descriptions.d.ts +8 -0
- package/dist/service/descriptions.js +20 -0
- package/dist/service/discovery-schemas.d.ts +92 -0
- package/dist/service/discovery-schemas.js +59 -0
- package/dist/service/discovery-search.d.ts +30 -0
- package/dist/service/discovery-search.js +95 -0
- package/dist/service/discovery.d.ts +37 -0
- package/dist/service/discovery.js +436 -0
- package/dist/service/docs.d.ts +9 -0
- package/dist/service/docs.js +197 -0
- package/dist/service/errors.d.ts +145 -0
- package/dist/service/errors.js +704 -0
- package/dist/service/federation-provider.d.ts +36 -0
- package/dist/service/federation-provider.js +110 -0
- package/dist/service/federation-server.d.ts +20 -0
- package/dist/service/federation-server.js +249 -0
- package/dist/service/federation-status.d.ts +40 -0
- package/dist/service/federation-status.js +151 -0
- package/dist/service/handlers.d.ts +18 -0
- package/dist/service/handlers.js +287 -0
- package/dist/service/mcp/confirmation.d.ts +68 -0
- package/dist/service/mcp/confirmation.js +178 -0
- package/dist/service/mcp/find-input.d.ts +12 -0
- package/dist/service/mcp/find-input.js +122 -0
- package/dist/service/mcp/input-schema.d.ts +6 -0
- package/dist/service/mcp/input-schema.js +126 -0
- package/dist/service/mcp/listing.d.ts +26 -0
- package/dist/service/mcp/listing.js +92 -0
- package/dist/service/mcp/metric-tools.d.ts +85 -0
- package/dist/service/mcp/metric-tools.js +258 -0
- package/dist/service/mcp/request-log.d.ts +5 -0
- package/dist/service/mcp/request-log.js +53 -0
- package/dist/service/mcp/runtime-policy.d.ts +27 -0
- package/dist/service/mcp/runtime-policy.js +62 -0
- package/dist/service/mcp/server.d.ts +52 -0
- package/dist/service/mcp/server.js +861 -0
- package/dist/service/mcp/tools.d.ts +99 -0
- package/dist/service/mcp/tools.js +938 -0
- package/dist/service/member-file-routes.d.ts +22 -0
- package/dist/service/member-file-routes.js +52 -0
- package/dist/service/member-files.d.ts +245 -0
- package/dist/service/member-files.js +258 -0
- package/dist/service/metric-query-platform.d.ts +77 -0
- package/dist/service/metric-query-platform.js +198 -0
- package/dist/service/metric-query-scopes.d.ts +43 -0
- package/dist/service/metric-query-scopes.js +147 -0
- package/dist/service/metric-query.d.ts +48 -0
- package/dist/service/metric-query.js +200 -0
- package/dist/service/name-suggestions.d.ts +3 -0
- package/dist/service/name-suggestions.js +38 -0
- package/dist/service/navigation-schemas.d.ts +80 -0
- package/dist/service/navigation-schemas.js +49 -0
- package/dist/service/navigation.d.ts +20 -0
- package/dist/service/navigation.js +165 -0
- package/dist/service/oauth/protocol.d.ts +70 -0
- package/dist/service/oauth/protocol.js +157 -0
- package/dist/service/oauth/refresh-replay.d.ts +2 -0
- package/dist/service/oauth/refresh-replay.js +20 -0
- package/dist/service/oauth/server.d.ts +28 -0
- package/dist/service/oauth/server.js +769 -0
- package/dist/service/operations.d.ts +170 -0
- package/dist/service/operations.js +392 -0
- package/dist/service/plan.d.ts +57 -0
- package/dist/service/plan.js +96 -0
- package/dist/service/rate-limit.d.ts +22 -0
- package/dist/service/rate-limit.js +52 -0
- package/dist/service/record-reads.d.ts +21 -0
- package/dist/service/record-reads.js +155 -0
- package/dist/service/replication.d.ts +5 -0
- package/dist/service/replication.js +39 -0
- package/dist/service/runtime-contract.d.ts +508 -0
- package/dist/service/runtime-contract.js +18 -0
- package/dist/service/runtime-identity.d.ts +71 -0
- package/dist/service/runtime-identity.js +122 -0
- package/dist/service/schemas.d.ts +961 -0
- package/dist/service/schemas.js +639 -0
- package/dist/service/service.d.ts +21 -0
- package/dist/service/service.js +526 -0
- package/dist/service/warehouse-platform.d.ts +17 -0
- package/dist/service/warehouse-platform.js +122 -0
- package/dist/service/warehouse-query.d.ts +24 -0
- package/dist/service/warehouse-query.js +280 -0
- package/dist/service/webhooks.d.ts +106 -0
- package/dist/service/webhooks.js +233 -0
- package/dist/service/workflow-admission-provider.d.ts +31 -0
- package/dist/service/workflow-admission-provider.js +205 -0
- package/dist/service/workflow-argument-serialization.d.ts +2 -0
- package/dist/service/workflow-argument-serialization.js +14 -0
- package/dist/service/workflow-callback.d.ts +22 -0
- package/dist/service/workflow-callback.js +75 -0
- package/dist/service/workflow-deployment.d.ts +8 -0
- package/dist/service/workflow-deployment.js +131 -0
- package/dist/service/workflow-diagnostics.d.ts +23 -0
- package/dist/service/workflow-diagnostics.js +263 -0
- package/dist/service/workflow-errors.d.ts +26 -0
- package/dist/service/workflow-errors.js +181 -0
- package/dist/service/workflow-logging.d.ts +2 -0
- package/dist/service/workflow-logging.js +50 -0
- package/dist/service/workflow-queue-fence.d.ts +6 -0
- package/dist/service/workflow-queue-fence.js +66 -0
- package/dist/service/workflows.d.ts +200 -0
- package/dist/service/workflows.js +1549 -0
- package/dist/sign-in.d.ts +58 -0
- package/dist/sign-in.js +57 -0
- package/dist/source.d.ts +30 -0
- package/dist/source.js +107 -0
- package/dist/start-recovery-contract.d.ts +49 -0
- package/dist/start-recovery-contract.js +26 -0
- package/dist/start-recovery.d.ts +27 -0
- package/dist/start-recovery.js +81 -0
- package/dist/storage/api.d.ts +4 -0
- package/dist/storage/api.js +40 -0
- package/dist/storage/attachments.d.ts +146 -0
- package/dist/storage/attachments.js +733 -0
- package/dist/storage/authorization.d.ts +38 -0
- package/dist/storage/authorization.js +83 -0
- package/dist/storage/file-access.d.ts +17 -0
- package/dist/storage/file-access.js +8 -0
- package/dist/storage/limits.d.ts +12 -0
- package/dist/storage/limits.js +17 -0
- package/dist/storage/maintenance-auth.d.ts +20 -0
- package/dist/storage/maintenance-auth.js +24 -0
- package/dist/storage/maintenance.d.ts +11 -0
- package/dist/storage/maintenance.js +67 -0
- package/dist/storage/neon.d.ts +4 -0
- package/dist/storage/neon.js +318 -0
- package/dist/storage/operator.d.ts +11 -0
- package/dist/storage/operator.js +30 -0
- package/dist/storage/provider.d.ts +93 -0
- package/dist/storage/provider.js +36 -0
- package/dist/storage/sessions.d.ts +184 -0
- package/dist/storage/sessions.js +688 -0
- package/dist/storage/tables.d.ts +54 -0
- package/dist/storage/tables.js +205 -0
- package/dist/storage/transfers.d.ts +16 -0
- package/dist/storage/transfers.js +153 -0
- package/dist/storage/writes.d.ts +7 -0
- package/dist/storage/writes.js +88 -0
- package/dist/telegram.d.ts +35 -0
- package/dist/telegram.js +173 -0
- package/dist/user-identity.d.ts +28 -0
- package/dist/user-identity.js +106 -0
- package/dist/user.d.ts +75 -0
- package/dist/user.js +111 -0
- package/dist/warehouse-backed.d.ts +6 -0
- package/dist/warehouse-backed.js +495 -0
- package/dist/webhook-token.d.ts +11 -0
- package/dist/webhook-token.js +18 -0
- package/dist/webhooks.d.ts +40 -0
- package/dist/webhooks.js +55 -0
- package/dist/wire.d.ts +10 -0
- package/dist/wire.js +35 -0
- package/dist/workflow-runtime.d.ts +116 -0
- package/dist/workflow-runtime.js +109 -0
- package/dist/workflow-topics.d.ts +28 -0
- package/dist/workflow-topics.js +28 -0
- package/dist/workflow.d.ts +284 -0
- package/dist/workflow.js +259 -0
- package/dist/workflows.d.ts +24 -0
- package/dist/workflows.js +18 -0
- package/package.json +127 -4
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { WorkloadExecution } from "./workload.js";
|
|
3
|
+
import type { StoredRecord } from "../runtime.js";
|
|
4
|
+
import type { EntityModel } from "./model.js";
|
|
5
|
+
import type { Params } from "./statement.js";
|
|
6
|
+
export declare const EditKind: Schema.Literals<readonly ["create", "update", "delete", "link", "unlink"]>;
|
|
7
|
+
export type EditKind = typeof EditKind.Type;
|
|
8
|
+
/** One property's change. A relationship's change carries record ids. */
|
|
9
|
+
export declare const Change: Schema.Struct<{
|
|
10
|
+
readonly before: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
11
|
+
readonly after: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
12
|
+
}>;
|
|
13
|
+
export type Change = typeof Change.Type;
|
|
14
|
+
export declare const Changes: Schema.$Record<Schema.String, Schema.Struct<{
|
|
15
|
+
readonly before: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
16
|
+
readonly after: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
17
|
+
}>>;
|
|
18
|
+
export type Changes = typeof Changes.Type;
|
|
19
|
+
/**
|
|
20
|
+
* A change an action made to one record, as the action response lists it. A link between two
|
|
21
|
+
* records is an edit of each, keyed by the relationship's name on that side.
|
|
22
|
+
*/
|
|
23
|
+
export declare const Edit: Schema.Struct<{
|
|
24
|
+
readonly entity: Schema.String;
|
|
25
|
+
readonly id: Schema.String;
|
|
26
|
+
readonly kind: Schema.Literals<readonly ["create", "update", "delete", "link", "unlink"]>;
|
|
27
|
+
readonly changes: Schema.$Record<Schema.String, Schema.Struct<{
|
|
28
|
+
readonly before: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
29
|
+
readonly after: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
30
|
+
}>>;
|
|
31
|
+
}>;
|
|
32
|
+
export type Edit = typeof Edit.Type;
|
|
33
|
+
/** A row of `<entity>_history`. */
|
|
34
|
+
export declare const HistoryEntry: Schema.Struct<{
|
|
35
|
+
readonly execution: Schema.optionalKey<Schema.Struct<{
|
|
36
|
+
readonly issuer: Schema.String;
|
|
37
|
+
readonly audience: Schema.String;
|
|
38
|
+
readonly organizationId: Schema.String;
|
|
39
|
+
readonly workspaceId: Schema.String;
|
|
40
|
+
readonly subject: Schema.String;
|
|
41
|
+
readonly deploymentId: Schema.String;
|
|
42
|
+
readonly ontologyDeploymentId: Schema.String;
|
|
43
|
+
readonly servingOntologyDeploymentId: Schema.String;
|
|
44
|
+
readonly ontologyOrigin: Schema.String;
|
|
45
|
+
readonly environment: Schema.Literals<readonly ["production", "preview"]>;
|
|
46
|
+
readonly jobName: Schema.NullOr<Schema.String>;
|
|
47
|
+
readonly runId: Schema.String;
|
|
48
|
+
readonly executionId: Schema.NullOr<Schema.String>;
|
|
49
|
+
readonly attemptId: Schema.String;
|
|
50
|
+
readonly generation: Schema.Number;
|
|
51
|
+
readonly tokenId: Schema.String;
|
|
52
|
+
readonly issuedAt: Schema.Number;
|
|
53
|
+
readonly expiresAt: Schema.Number;
|
|
54
|
+
}>>;
|
|
55
|
+
readonly id: Schema.String;
|
|
56
|
+
readonly recordId: Schema.String;
|
|
57
|
+
/** The qualified action, for example `lead.changeStatus`. */
|
|
58
|
+
readonly action: Schema.String;
|
|
59
|
+
/** Shared by every row one run of an action wrote. */
|
|
60
|
+
readonly actionId: Schema.String;
|
|
61
|
+
readonly kind: Schema.Literals<readonly ["create", "update", "delete", "link", "unlink"]>;
|
|
62
|
+
/** The user who ran the action; `null` when the platform wrote. */
|
|
63
|
+
readonly principalId: Schema.NullOr<Schema.String>;
|
|
64
|
+
readonly at: Schema.String;
|
|
65
|
+
readonly changes: Schema.$Record<Schema.String, Schema.Struct<{
|
|
66
|
+
readonly before: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
67
|
+
readonly after: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
68
|
+
}>>;
|
|
69
|
+
}>;
|
|
70
|
+
export type HistoryEntry = typeof HistoryEntry.Type;
|
|
71
|
+
/** The fields whose values differ. A created record diffs from nothing, a deleted one to nothing. */
|
|
72
|
+
export declare function diffRecords(entity: EntityModel, before: StoredRecord | undefined, after: StoredRecord | undefined): Changes;
|
|
73
|
+
export interface HistoryWrite {
|
|
74
|
+
readonly entity: EntityModel;
|
|
75
|
+
readonly edit: Edit;
|
|
76
|
+
}
|
|
77
|
+
export interface HistoryScope {
|
|
78
|
+
readonly execution?: WorkloadExecution;
|
|
79
|
+
readonly workflow?: {
|
|
80
|
+
readonly name: string;
|
|
81
|
+
readonly subject: string;
|
|
82
|
+
};
|
|
83
|
+
readonly action: string;
|
|
84
|
+
readonly actionId: string;
|
|
85
|
+
readonly principalId: string | null;
|
|
86
|
+
readonly branchId?: string;
|
|
87
|
+
readonly blobActionKey?: string;
|
|
88
|
+
readonly createIntent?: string;
|
|
89
|
+
}
|
|
90
|
+
/** `INSERT` of one history row; `at` is the transaction's time, shared by the whole action. */
|
|
91
|
+
export declare function insertHistory(scope: HistoryScope, write: HistoryWrite, params: Params): string;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { canonicalJson } from "../manifest.js";
|
|
3
|
+
import { WorkloadExecution } from "./workload.js";
|
|
4
|
+
import { quoteIdentifier } from "../migrate/storage.js";
|
|
5
|
+
import { uuidv7 } from "./ids.js";
|
|
6
|
+
export const EditKind = Schema.Literals(["create", "update", "delete", "link", "unlink"]);
|
|
7
|
+
/** One property's change. A relationship's change carries record ids. */
|
|
8
|
+
export const Change = Schema.Struct({
|
|
9
|
+
before: Schema.Json,
|
|
10
|
+
after: Schema.Json,
|
|
11
|
+
});
|
|
12
|
+
export const Changes = Schema.Record(Schema.String, Change);
|
|
13
|
+
/**
|
|
14
|
+
* A change an action made to one record, as the action response lists it. A link between two
|
|
15
|
+
* records is an edit of each, keyed by the relationship's name on that side.
|
|
16
|
+
*/
|
|
17
|
+
export const Edit = Schema.Struct({
|
|
18
|
+
entity: Schema.String,
|
|
19
|
+
id: Schema.String,
|
|
20
|
+
kind: EditKind,
|
|
21
|
+
changes: Changes,
|
|
22
|
+
});
|
|
23
|
+
/** A row of `<entity>_history`. */
|
|
24
|
+
export const HistoryEntry = Schema.Struct({
|
|
25
|
+
execution: Schema.optionalKey(WorkloadExecution),
|
|
26
|
+
id: Schema.String,
|
|
27
|
+
recordId: Schema.String,
|
|
28
|
+
/** The qualified action, for example `lead.changeStatus`. */
|
|
29
|
+
action: Schema.String,
|
|
30
|
+
/** Shared by every row one run of an action wrote. */
|
|
31
|
+
actionId: Schema.String,
|
|
32
|
+
kind: EditKind,
|
|
33
|
+
/** The user who ran the action; `null` when the platform wrote. */
|
|
34
|
+
principalId: Schema.NullOr(Schema.String),
|
|
35
|
+
at: Schema.String,
|
|
36
|
+
changes: Changes,
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* The fields a write's history diffs: declared properties and `<relationship>_id` keys. A projection
|
|
40
|
+
* such as the user's `roles` changes through no column write; the writes that change it record
|
|
41
|
+
* their own rows.
|
|
42
|
+
*/
|
|
43
|
+
function changedFields(entity) {
|
|
44
|
+
return entity.fields.filter((field) => field.source !== "system" && field.source !== "projection");
|
|
45
|
+
}
|
|
46
|
+
function same(left, right) {
|
|
47
|
+
return canonicalJson(left ?? null) === canonicalJson(right ?? null);
|
|
48
|
+
}
|
|
49
|
+
/** The fields whose values differ. A created record diffs from nothing, a deleted one to nothing. */
|
|
50
|
+
export function diffRecords(entity, before, after) {
|
|
51
|
+
const changes = {};
|
|
52
|
+
for (const field of changedFields(entity)) {
|
|
53
|
+
const previous = (before?.[field.name] ?? null);
|
|
54
|
+
const next = (after?.[field.name] ?? null);
|
|
55
|
+
if (!same(previous, next)) {
|
|
56
|
+
changes[field.name] = { before: previous, after: next };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return changes;
|
|
60
|
+
}
|
|
61
|
+
/** `INSERT` of one history row; `at` is the transaction's time, shared by the whole action. */
|
|
62
|
+
export function insertHistory(scope, write, params) {
|
|
63
|
+
const table = quoteIdentifier(write.entity.historyTable);
|
|
64
|
+
const values = [
|
|
65
|
+
params.add(uuidv7(), "uuid"),
|
|
66
|
+
params.add(write.edit.id, "uuid"),
|
|
67
|
+
params.add(scope.action, "text"),
|
|
68
|
+
params.add(scope.actionId, "uuid"),
|
|
69
|
+
params.add(write.edit.kind, "text"),
|
|
70
|
+
params.add(scope.principalId, "uuid"),
|
|
71
|
+
"now()",
|
|
72
|
+
params.add(JSON.stringify(write.edit.changes), "jsonb"),
|
|
73
|
+
];
|
|
74
|
+
return (`INSERT INTO ${table} ` +
|
|
75
|
+
'("id", "record_id", "action", "action_id", "kind", "principal_id", "at", "changes") ' +
|
|
76
|
+
`VALUES (${values.join(", ")})`);
|
|
77
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A UUIDv7 (RFC 9562): a millisecond timestamp, a 12-bit sequence and random bits. Ids from one
|
|
3
|
+
* process sort in the order they were made, also within a millisecond, so record ids keep index
|
|
4
|
+
* locality and the history rows of one action, which share their `at`, read back in order.
|
|
5
|
+
*/
|
|
6
|
+
export declare function uuidv7(): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
let lastMillis = 0;
|
|
3
|
+
let sequence = 0;
|
|
4
|
+
/**
|
|
5
|
+
* A UUIDv7 (RFC 9562): a millisecond timestamp, a 12-bit sequence and random bits. Ids from one
|
|
6
|
+
* process sort in the order they were made, also within a millisecond, so record ids keep index
|
|
7
|
+
* locality and the history rows of one action, which share their `at`, read back in order.
|
|
8
|
+
*/
|
|
9
|
+
export function uuidv7() {
|
|
10
|
+
const now = Date.now();
|
|
11
|
+
if (now > lastMillis) {
|
|
12
|
+
lastMillis = now;
|
|
13
|
+
sequence = 0;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
sequence += 1;
|
|
17
|
+
if (sequence > 0xfff) {
|
|
18
|
+
lastMillis += 1;
|
|
19
|
+
sequence = 0;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const bytes = randomBytes(16);
|
|
23
|
+
let millis = lastMillis;
|
|
24
|
+
for (let index = 5; index >= 0; index -= 1) {
|
|
25
|
+
bytes[index] = millis % 256;
|
|
26
|
+
millis = Math.floor(millis / 256);
|
|
27
|
+
}
|
|
28
|
+
bytes[6] = 0x70 | (sequence >> 8);
|
|
29
|
+
bytes[7] = sequence & 0xff;
|
|
30
|
+
bytes[8] = 0x80 | (bytes[8] & 0x3f);
|
|
31
|
+
const hex = bytes.toString("hex");
|
|
32
|
+
return [
|
|
33
|
+
hex.slice(0, 8),
|
|
34
|
+
hex.slice(8, 12),
|
|
35
|
+
hex.slice(12, 16),
|
|
36
|
+
hex.slice(16, 20),
|
|
37
|
+
hex.slice(20, 32),
|
|
38
|
+
].join("-");
|
|
39
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { SqlClient } from "effect/unstable/sql";
|
|
3
|
+
/** Legacy workspace databases remain readable before their next additive migration. */
|
|
4
|
+
export declare function channelUsersAvailable(sql: SqlClient.SqlClient): Effect.Effect<boolean, import("effect/unstable/sql/SqlError").SqlError, never>;
|
|
5
|
+
/** Records how a user came to be: `invite`, `email` or a channel's sign-up. The first record stays. */
|
|
6
|
+
export declare function recordUserCreation(sql: SqlClient.SqlClient, userId: string, via: string): Effect.Effect<void, import("effect/unstable/sql/SqlError").SqlError, never>;
|
|
7
|
+
/** Session revocation integration point for every channel-app issuer (including Mini Apps). */
|
|
8
|
+
export declare function revokeMemberSessions(sql: SqlClient.SqlClient, userId: string): Effect.Effect<void, import("effect/unstable/sql/SqlError").SqlError, never>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { CHANNEL_USERS_TABLE } from "../migrate/storage.js";
|
|
3
|
+
// @legacy ontology.pre-upgrade-database-tolerance
|
|
4
|
+
/** Legacy workspace databases remain readable before their next additive migration. */
|
|
5
|
+
export function channelUsersAvailable(sql) {
|
|
6
|
+
return sql
|
|
7
|
+
.unsafe(`SELECT to_regclass($1) IS NOT NULL AS "present"`, [
|
|
8
|
+
CHANNEL_USERS_TABLE,
|
|
9
|
+
])
|
|
10
|
+
.pipe(Effect.map(([table]) => table?.present === true));
|
|
11
|
+
}
|
|
12
|
+
/** Records how a user came to be: `invite`, `email` or a channel's sign-up. The first record stays. */
|
|
13
|
+
export function recordUserCreation(sql, userId, via) {
|
|
14
|
+
return Effect.gen(function* () {
|
|
15
|
+
if (yield* channelUsersAvailable(sql)) {
|
|
16
|
+
yield* sql.unsafe(`INSERT INTO "${CHANNEL_USERS_TABLE}" ("user_id", "created_via") VALUES ($1::uuid, $2)
|
|
17
|
+
ON CONFLICT ("user_id") DO NOTHING`, [userId, via]);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/** Session revocation integration point for every channel-app issuer (including Mini Apps). */
|
|
22
|
+
export function revokeMemberSessions(sql, userId) {
|
|
23
|
+
return Effect.gen(function* () {
|
|
24
|
+
const [tables] = yield* sql.unsafe(`SELECT to_regclass('_oauth_grants') IS NOT NULL AS "oauth",
|
|
25
|
+
to_regclass('_federation_sessions') IS NOT NULL AS "federation"`);
|
|
26
|
+
if (tables?.oauth) {
|
|
27
|
+
yield* sql.unsafe(`UPDATE "_oauth_grants" SET "revoked_at" = now() WHERE "user_id" = $1::uuid AND "revoked_at" IS NULL`, [userId]);
|
|
28
|
+
}
|
|
29
|
+
if (tables?.federation) {
|
|
30
|
+
yield* sql.unsafe(`DELETE FROM "_federation_sessions" WHERE "user_id" = $1::uuid`, [userId]);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { SqlClient } from "effect/unstable/sql";
|
|
3
|
+
import type { SqlError } from "effect/unstable/sql/SqlError";
|
|
4
|
+
import { ActionRejected, type Conflict, type NotFound } from "../errors.js";
|
|
5
|
+
import type { EmailTemplateManifest } from "../manifest.js";
|
|
6
|
+
import type { StoredRecord } from "../runtime.js";
|
|
7
|
+
import { UnknownRole } from "./errors.js";
|
|
8
|
+
import type { EntityModel } from "./model.js";
|
|
9
|
+
import { type WriteContext } from "./writes.js";
|
|
10
|
+
/**
|
|
11
|
+
* Member management: inviting a member, granting and revoking roles, and deactivating and
|
|
12
|
+
* reactivating a member. The generated `user` actions, the `User` handle's writes in a handler and
|
|
13
|
+
* the console's and CLI's principal functions all run these, under the scope of the write: history
|
|
14
|
+
* names its action and principal. Only members are managed here; a service's roles come with its
|
|
15
|
+
* API key.
|
|
16
|
+
*/
|
|
17
|
+
export interface MemberWriteContext extends WriteContext {
|
|
18
|
+
/** The client whose transaction the write runs on, for the tables beside the user. */
|
|
19
|
+
readonly sql: SqlClient.SqlClient;
|
|
20
|
+
/** The roles the ontology declares, `member` included. */
|
|
21
|
+
readonly roles: ReadonlyArray<string>;
|
|
22
|
+
}
|
|
23
|
+
/** Implicit human roles cannot be assigned or revoked; their authority comes from resolution. */
|
|
24
|
+
export declare function refuseMember(roles: ReadonlyArray<string>): Effect.Effect<void, UnknownRole>;
|
|
25
|
+
/** Only declared business roles may be granted; implicit built-in roles are never assignable. */
|
|
26
|
+
export declare function requireGrantable(declared: ReadonlyArray<string>, roles: ReadonlyArray<string>): Effect.Effect<void, UnknownRole>;
|
|
27
|
+
/** Grants declared roles to a member. A role the member holds changes nothing. */
|
|
28
|
+
export declare function grantMemberRoles(context: MemberWriteContext, entity: EntityModel, input: {
|
|
29
|
+
readonly id: string;
|
|
30
|
+
readonly roles: ReadonlyArray<string>;
|
|
31
|
+
}): Effect.Effect<StoredRecord, UnknownRole | NotFound | SqlError>;
|
|
32
|
+
/**
|
|
33
|
+
* Revokes roles from a member, or every role. A role the member does not hold, or one the ontology
|
|
34
|
+
* no longer declares, is removed without error.
|
|
35
|
+
*/
|
|
36
|
+
export declare function revokeMemberRoles(context: MemberWriteContext, entity: EntityModel, input: {
|
|
37
|
+
readonly id: string;
|
|
38
|
+
readonly roles: ReadonlyArray<string> | "all";
|
|
39
|
+
}): Effect.Effect<StoredRecord, UnknownRole | NotFound | SqlError>;
|
|
40
|
+
/**
|
|
41
|
+
* Creates a member for an email no user has, with declared roles: a `create` row, and an `update`
|
|
42
|
+
* row for the roles. The member is linked to their identity by email at their first sign-in. An
|
|
43
|
+
* email a user has fails with Conflict, through the unique index, so concurrent invitations of one
|
|
44
|
+
* email fail too. The name defaults to the email.
|
|
45
|
+
*/
|
|
46
|
+
export declare function inviteMember(context: MemberWriteContext, entity: EntityModel, input: {
|
|
47
|
+
readonly email: string;
|
|
48
|
+
readonly name?: string | undefined;
|
|
49
|
+
readonly roles?: ReadonlyArray<string> | undefined;
|
|
50
|
+
}): Effect.Effect<StoredRecord, UnknownRole | Conflict | SqlError>;
|
|
51
|
+
/**
|
|
52
|
+
* Deactivates or reactivates a member. An inactive member keeps their roles and history, and the
|
|
53
|
+
* service rejects their requests. Deactivation also ends their sessions, even when they were
|
|
54
|
+
* inactive already. A change that leaves `active` as it was writes no history.
|
|
55
|
+
*/
|
|
56
|
+
export declare function setMemberActive(context: MemberWriteContext, entity: EntityModel, input: {
|
|
57
|
+
readonly id: string;
|
|
58
|
+
readonly active: boolean;
|
|
59
|
+
}): Effect.Effect<StoredRecord, NotFound | SqlError>;
|
|
60
|
+
/** A sign-in email an action queued: the row, the address and the path its link opens. */
|
|
61
|
+
export interface QueuedSignInEmail {
|
|
62
|
+
readonly id: string;
|
|
63
|
+
readonly email: string;
|
|
64
|
+
readonly returnTo: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Queues an email with a sign-in link for an active member, in the action's transaction: a row of
|
|
68
|
+
* {@link SIGN_IN_EMAILS_TABLE}, sent once the action commits. `template` is the wire name of one of
|
|
69
|
+
* the ontology's `emails`, or none for the platform's own email; `returnTo` is the path of the app
|
|
70
|
+
* the link opens, `/` by default. What the caller can fix is ActionRejected; a service or an
|
|
71
|
+
* unknown id is NotFound.
|
|
72
|
+
*/
|
|
73
|
+
export declare function queueSignInEmail(context: MemberWriteContext, entity: EntityModel, emails: Readonly<Record<string, EmailTemplateManifest>>, input: {
|
|
74
|
+
readonly id: string;
|
|
75
|
+
readonly template?: string | undefined;
|
|
76
|
+
readonly returnTo?: string | undefined;
|
|
77
|
+
readonly values?: Readonly<Record<string, string>> | undefined;
|
|
78
|
+
}): Effect.Effect<QueuedSignInEmail, ActionRejected | NotFound | SqlError>;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { appReturnPath, emailValueNames, MAX_EMAIL_TEXT, MAX_EMAIL_VALUES } from "../emails.js";
|
|
3
|
+
import { ActionRejected } from "../errors.js";
|
|
4
|
+
import { MEMBER_ROLE, FEEDBACK_REPORTER_ROLE, toCamelCase, toSnakeCase } from "../names.js";
|
|
5
|
+
import { SIGN_IN_EMAILS_TABLE } from "../storage/tables.js";
|
|
6
|
+
import { UnknownRole } from "./errors.js";
|
|
7
|
+
import { uuidv7 } from "./ids.js";
|
|
8
|
+
import { recordUserCreation, revokeMemberSessions } from "./member-tables.js";
|
|
9
|
+
import { loadRecord, notFound } from "./reads.js";
|
|
10
|
+
import { changeUserRoles, createRecord, updateRecord } from "./writes.js";
|
|
11
|
+
/** Implicit human roles cannot be assigned or revoked; their authority comes from resolution. */
|
|
12
|
+
export function refuseMember(roles) {
|
|
13
|
+
const reporter = roles.find((name) => toSnakeCase(name) === FEEDBACK_REPORTER_ROLE);
|
|
14
|
+
if (reporter !== undefined) {
|
|
15
|
+
return Effect.fail(new UnknownRole({
|
|
16
|
+
role: reporter,
|
|
17
|
+
message: "feedback_reporter is implicit human authority; it cannot be granted or revoked.",
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
if (!roles.includes(MEMBER_ROLE)) {
|
|
21
|
+
return Effect.void;
|
|
22
|
+
}
|
|
23
|
+
return Effect.fail(new UnknownRole({
|
|
24
|
+
role: MEMBER_ROLE,
|
|
25
|
+
message: `${MEMBER_ROLE} is held by every active member; it cannot be granted or revoked.`,
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
/** Only declared business roles may be granted; implicit built-in roles are never assignable. */
|
|
29
|
+
export function requireGrantable(declared, roles) {
|
|
30
|
+
return Effect.gen(function* () {
|
|
31
|
+
yield* refuseMember(roles);
|
|
32
|
+
const unknown = roles.find((candidate) => !declared.includes(candidate));
|
|
33
|
+
if (unknown !== undefined) {
|
|
34
|
+
return yield* new UnknownRole({
|
|
35
|
+
role: unknown,
|
|
36
|
+
message: `${unknown} is not a role of this ontology.`,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/** The member with this id, locked until the transaction ends. A service is not found. */
|
|
42
|
+
function lockMember(context, entity, id) {
|
|
43
|
+
return Effect.gen(function* () {
|
|
44
|
+
const user = yield* loadRecord(context, entity, id, "update");
|
|
45
|
+
if (user === undefined || user.kind !== "member") {
|
|
46
|
+
return yield* notFound(entity, id);
|
|
47
|
+
}
|
|
48
|
+
return user;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** Grants declared roles to a member. A role the member holds changes nothing. */
|
|
52
|
+
export function grantMemberRoles(context, entity, input) {
|
|
53
|
+
return Effect.gen(function* () {
|
|
54
|
+
yield* requireGrantable(context.roles, input.roles);
|
|
55
|
+
yield* lockMember(context, entity, input.id);
|
|
56
|
+
return yield* changeUserRoles(context, entity, input.id, { grant: input.roles });
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Revokes roles from a member, or every role. A role the member does not hold, or one the ontology
|
|
61
|
+
* no longer declares, is removed without error.
|
|
62
|
+
*/
|
|
63
|
+
export function revokeMemberRoles(context, entity, input) {
|
|
64
|
+
return Effect.gen(function* () {
|
|
65
|
+
yield* refuseMember(input.roles === "all" ? [] : input.roles);
|
|
66
|
+
yield* lockMember(context, entity, input.id);
|
|
67
|
+
return yield* changeUserRoles(context, entity, input.id, { revoke: input.roles });
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Creates a member for an email no user has, with declared roles: a `create` row, and an `update`
|
|
72
|
+
* row for the roles. The member is linked to their identity by email at their first sign-in. An
|
|
73
|
+
* email a user has fails with Conflict, through the unique index, so concurrent invitations of one
|
|
74
|
+
* email fail too. The name defaults to the email.
|
|
75
|
+
*/
|
|
76
|
+
export function inviteMember(context, entity, input) {
|
|
77
|
+
return Effect.gen(function* () {
|
|
78
|
+
const roles = input.roles ?? [];
|
|
79
|
+
yield* requireGrantable(context.roles, roles);
|
|
80
|
+
// Emails are stored lowercased, as sign-in links them.
|
|
81
|
+
const email = input.email.trim().toLowerCase();
|
|
82
|
+
const user = yield* createRecord(context, entity, {
|
|
83
|
+
name: input.name?.trim() || email,
|
|
84
|
+
email,
|
|
85
|
+
kind: "member",
|
|
86
|
+
// An unguarded write: no scope applies, so ScopeViolated cannot occur.
|
|
87
|
+
}).pipe(Effect.catchTag(["NotFound", "ScopeViolated"], (error) => Effect.die(error)));
|
|
88
|
+
const id = user.id;
|
|
89
|
+
yield* recordUserCreation(context.sql, id, "invite");
|
|
90
|
+
return roles.length === 0
|
|
91
|
+
? user
|
|
92
|
+
: yield* changeUserRoles(context, entity, id, { grant: roles }).pipe(Effect.catchTag("NotFound", (error) => Effect.die(error)));
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Deactivates or reactivates a member. An inactive member keeps their roles and history, and the
|
|
97
|
+
* service rejects their requests. Deactivation also ends their sessions, even when they were
|
|
98
|
+
* inactive already. A change that leaves `active` as it was writes no history.
|
|
99
|
+
*/
|
|
100
|
+
export function setMemberActive(context, entity, input) {
|
|
101
|
+
return Effect.gen(function* () {
|
|
102
|
+
const user = yield* lockMember(context, entity, input.id);
|
|
103
|
+
const id = user.id;
|
|
104
|
+
const after = user.active === input.active
|
|
105
|
+
? user
|
|
106
|
+
: yield* updateRecord(context, entity, id, { active: input.active }).pipe(Effect.catchTag(["Conflict", "ScopeViolated"], (error) => Effect.die(error)));
|
|
107
|
+
if (!input.active) {
|
|
108
|
+
yield* revokeMemberSessions(context.sql, id);
|
|
109
|
+
}
|
|
110
|
+
return after;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The values a sign-in email is sent with, checked against its template: every value the template
|
|
115
|
+
* uses, and no other, each a text of at most {@link MAX_EMAIL_TEXT} characters. Without a template
|
|
116
|
+
* the platform's own email takes none.
|
|
117
|
+
*/
|
|
118
|
+
function signInEmailValues(name, template, values) {
|
|
119
|
+
const reject = (message) => Effect.fail(new ActionRejected({ message }));
|
|
120
|
+
if (values === undefined) {
|
|
121
|
+
values = {};
|
|
122
|
+
}
|
|
123
|
+
if (typeof values !== "object" || values === null || Array.isArray(values)) {
|
|
124
|
+
return reject("values maps each value the email uses to its text.");
|
|
125
|
+
}
|
|
126
|
+
const entries = Object.entries(values);
|
|
127
|
+
if (entries.length > MAX_EMAIL_VALUES) {
|
|
128
|
+
return reject(`An email takes at most ${MAX_EMAIL_VALUES} values.`);
|
|
129
|
+
}
|
|
130
|
+
for (const [key, value] of entries) {
|
|
131
|
+
if (typeof value !== "string") {
|
|
132
|
+
return reject(`The value ${key} is a text.`);
|
|
133
|
+
}
|
|
134
|
+
if (value.length > MAX_EMAIL_TEXT) {
|
|
135
|
+
return reject(`The value ${key} has at most ${MAX_EMAIL_TEXT} characters.`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (template === undefined) {
|
|
139
|
+
return entries.length === 0
|
|
140
|
+
? Effect.succeed({})
|
|
141
|
+
: reject("values fill one of the ontology's emails; name it with template.");
|
|
142
|
+
}
|
|
143
|
+
const used = emailValueNames(template);
|
|
144
|
+
const missing = used.filter((key) => !Object.hasOwn(values, key));
|
|
145
|
+
const unknown = entries.map(([key]) => key).filter((key) => !used.includes(key));
|
|
146
|
+
if (missing.length > 0) {
|
|
147
|
+
return reject(`The email ${name} needs the values ${missing.join(", ")}.`);
|
|
148
|
+
}
|
|
149
|
+
if (unknown.length > 0) {
|
|
150
|
+
return reject(`The email ${name} does not use the values ${unknown.join(", ")}.`);
|
|
151
|
+
}
|
|
152
|
+
return Effect.succeed(Object.fromEntries(entries));
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Queues an email with a sign-in link for an active member, in the action's transaction: a row of
|
|
156
|
+
* {@link SIGN_IN_EMAILS_TABLE}, sent once the action commits. `template` is the wire name of one of
|
|
157
|
+
* the ontology's `emails`, or none for the platform's own email; `returnTo` is the path of the app
|
|
158
|
+
* the link opens, `/` by default. What the caller can fix is ActionRejected; a service or an
|
|
159
|
+
* unknown id is NotFound.
|
|
160
|
+
*/
|
|
161
|
+
export function queueSignInEmail(context, entity, emails, input) {
|
|
162
|
+
return Effect.gen(function* () {
|
|
163
|
+
const user = yield* lockMember(context, entity, input.id);
|
|
164
|
+
const email = typeof user.email === "string" ? user.email.trim().toLowerCase() : "";
|
|
165
|
+
if (user.active === false) {
|
|
166
|
+
return yield* new ActionRejected({
|
|
167
|
+
message: "The member is inactive; reactivate them before sending a sign-in link.",
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
if (email === "") {
|
|
171
|
+
return yield* new ActionRejected({ message: "The member has no email address." });
|
|
172
|
+
}
|
|
173
|
+
const template = input.template === undefined ? undefined : emails[input.template];
|
|
174
|
+
if (input.template !== undefined && template === undefined) {
|
|
175
|
+
return yield* new ActionRejected({
|
|
176
|
+
message: `${toCamelCase(input.template)} is not one of the ontology's emails.`,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
const name = input.template === undefined ? undefined : toCamelCase(input.template);
|
|
180
|
+
const values = yield* signInEmailValues(name, template, input.values);
|
|
181
|
+
const returnTo = appReturnPath(input.returnTo ?? "/");
|
|
182
|
+
if (returnTo === undefined) {
|
|
183
|
+
return yield* new ActionRejected({
|
|
184
|
+
message: "returnTo is a path of the app, such as /shared/123.",
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
const id = uuidv7();
|
|
188
|
+
yield* context.sql.unsafe(`INSERT INTO "${SIGN_IN_EMAILS_TABLE}"
|
|
189
|
+
("id", "user_id", "email", "template", "values", "return_to", "action_id", "sender_id", "status")
|
|
190
|
+
VALUES ($1::uuid, $2::uuid, $3, $4, $5::jsonb, $6, $7::uuid, $8::uuid, 'pending')`, [
|
|
191
|
+
id,
|
|
192
|
+
user.id,
|
|
193
|
+
email,
|
|
194
|
+
input.template ?? null,
|
|
195
|
+
JSON.stringify(values),
|
|
196
|
+
returnTo,
|
|
197
|
+
context.scope.actionId,
|
|
198
|
+
context.scope.principalId,
|
|
199
|
+
]);
|
|
200
|
+
return { id, email, returnTo };
|
|
201
|
+
});
|
|
202
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { SqlError } from "effect/unstable/sql/SqlError";
|
|
3
|
+
import { type Where } from "../query.js";
|
|
4
|
+
import type { StoredRecord } from "../runtime.js";
|
|
5
|
+
import { InvalidQuery } from "./errors.js";
|
|
6
|
+
import type { EntityModel } from "./model.js";
|
|
7
|
+
import { type SqlContext } from "./reads.js";
|
|
8
|
+
export declare function indexedFieldsOf(entity: EntityModel): ReadonlySet<string>;
|
|
9
|
+
/**
|
|
10
|
+
* Whether a validated `where` confines the records to an index lookup: a condition of its own, or
|
|
11
|
+
* of an `and` entry, that looks up an indexed field, or an `or` every branch of which does. `not`
|
|
12
|
+
* never confines.
|
|
13
|
+
*/
|
|
14
|
+
export declare function anchored(entity: EntityModel, where: Where | undefined): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Computes the metrics over the records the `where` matches, grouped by the fields of `groupBy`:
|
|
17
|
+
* one row per group, ordered by the groups, or one row without them. One statement.
|
|
18
|
+
*/
|
|
19
|
+
export declare function runMetricQuery(context: SqlContext, entity: EntityModel, options: unknown): Effect.Effect<ReadonlyArray<StoredRecord>, InvalidQuery | SqlError>;
|