@flowdular/sdk 0.2.4 → 0.3.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/.ai/agents/sandbox/business-manager.md +5 -1
- package/.ai/blueprints/author-spec/README.md +1 -1
- package/.ai/blueprints/author-spec/spec-requirements.yaml +44 -0
- package/.ai/blueprints/author-spec/steps.yaml +5 -5
- package/.ai/blueprints/author-spec/templates/module.yaml +99 -3
- package/.ai/blueprints/edit-module/gates.yaml +4 -0
- package/.ai/blueprints/edit-module/required-files.yaml +9 -0
- package/.ai/blueprints/new-module/gates.yaml +4 -0
- package/.ai/blueprints/new-module/spec-requirements.yaml +2 -2
- package/.ai/blueprints/release/gates.yaml +4 -0
- package/.ai/platform-capabilities.md +128 -0
- package/.ai/policies/capabilities.yaml +130 -3
- package/.ai/policies/path-ownership.yaml +5 -2
- package/.ai/policies/task-budgets.yaml +5 -3
- package/.ai/references/catalog/module.json +4 -4
- package/.ai/references/catalog/package.json +2 -2
- package/.ai/references/catalog/spec/module.yaml +5 -3
- package/.ai/references/catalog/src/platform.ts +2 -0
- package/.ai/references/catalog/src/services/catalog-service.ts +89 -1
- package/.ai/references/catalog/src/services/data-classes.ts +47 -0
- package/.ai/references/catalog/src/services/database-repository.ts +98 -1
- package/.ai/references/catalog/src/services/repository.ts +22 -1
- package/.ai/references/catalog/tests/data-classes.test.ts +157 -0
- package/.ai/references/catalog.provenance.json +12 -10
- package/.ai/skills/README.md +10 -0
- package/.ai/skills/agent-tool-design/SKILL.md +1 -2
- package/.ai/skills/auth-security-review/SKILL.md +1 -1
- package/.ai/skills/business-agent-design/SKILL.md +0 -1
- package/.ai/skills/cli-extension/SKILL.md +1 -1
- package/.ai/skills/deploy-operate/SKILL.md +119 -0
- package/.ai/skills/module-new/SKILL.md +29 -3
- package/.ai/skills/module-update/SKILL.md +9 -3
- package/.ai/skills/perf-audit/SKILL.md +0 -1
- package/.ai/skills/release-eject-pr/SKILL.md +0 -1
- package/.ai/skills/spec-interview/SKILL.md +120 -0
- package/.ai/skills/test-hardening/SKILL.md +1 -0
- package/.ai/skills/ux-design/SKILL.md +34 -3
- package/.ai/skills/variables/SKILL.md +0 -2
- package/.ai/skills/workflow-development/SKILL.md +0 -1
- package/AGENTS.md +4 -0
- package/docs/agent-contract.md +2 -2
- package/docs/design-system.md +185 -31
- package/modules/access/migrations/0001_access_core.down.sql +1 -0
- package/modules/access/migrations/0001_access_core.up.sql +28 -0
- package/modules/access/migrations/README.md +3 -0
- package/modules/access/module.json +33 -0
- package/modules/access/package.json +43 -0
- package/modules/access/spec/module.yaml +225 -0
- package/modules/access/src/acl/permissions.ts +6 -0
- package/modules/access/src/api/endpoints.ts +244 -0
- package/modules/access/src/client/ActivityView.tsrx +245 -0
- package/modules/access/src/client/AttestationsView.tsrx +176 -0
- package/modules/access/src/client/ReviewView.tsrx +586 -0
- package/modules/access/src/client/api.ts +132 -0
- package/modules/access/src/client/contribution.tsrx +41 -0
- package/modules/access/src/client/index.ts +41 -0
- package/modules/access/src/client/navigation.ts +57 -0
- package/modules/access/src/client/presentation.ts +69 -0
- package/modules/access/src/client/state.ts +72 -0
- package/modules/access/src/domain/types.ts +189 -0
- package/modules/access/src/index.ts +38 -0
- package/modules/access/src/platform.ts +60 -0
- package/modules/access/src/server/index.ts +42 -0
- package/modules/access/src/server/runtime.ts +105 -0
- package/modules/access/src/services/access-service.ts +298 -0
- package/modules/access/src/services/audit-window.ts +78 -0
- package/modules/access/src/services/auth-directory.ts +72 -0
- package/modules/access/src/services/changes.ts +91 -0
- package/modules/access/src/services/data-classes.ts +28 -0
- package/modules/access/src/services/database-repository.ts +185 -0
- package/modules/access/src/services/directory.ts +102 -0
- package/modules/access/src/services/index.ts +33 -0
- package/modules/access/src/services/list-exports.ts +150 -0
- package/modules/access/src/services/migration.ts +54 -0
- package/modules/access/src/services/repository.ts +30 -0
- package/modules/access/src/services/review.ts +178 -0
- package/modules/access/translations/en.json +155 -0
- package/modules/access/translations/pl.json +155 -0
- package/modules/agents/migrations/0022_credential_rotation_inventory.down.sql +2 -0
- package/modules/agents/migrations/0022_credential_rotation_inventory.up.sql +7 -0
- package/modules/agents/migrations/0023_agents_retention_indexes.down.sql +2 -0
- package/modules/agents/migrations/0023_agents_retention_indexes.up.sql +9 -0
- package/modules/agents/migrations/0024_agent_meter_refusals.down.sql +3 -0
- package/modules/agents/migrations/0024_agent_meter_refusals.up.sql +22 -0
- package/modules/agents/migrations/0025_agent_list_indexes.down.sql +3 -0
- package/modules/agents/migrations/0025_agent_list_indexes.up.sql +11 -0
- package/modules/agents/module.json +30 -4
- package/modules/agents/package.json +2 -1
- package/modules/agents/spec/module.yaml +63 -5
- package/modules/agents/src/api/endpoints.ts +291 -33
- package/modules/agents/src/cli/commands.json +11 -0
- package/modules/agents/src/cli/index.ts +45 -0
- package/modules/agents/src/client/AgentDashboardWidget.tsrx +19 -11
- package/modules/agents/src/client/AgentDefinitionList.tsrx +53 -10
- package/modules/agents/src/client/AgentPlaygroundView.tsrx +4 -4
- package/modules/agents/src/client/AgentProceduresView.tsrx +2 -2
- package/modules/agents/src/client/AgentRunsView.tsrx +143 -40
- package/modules/agents/src/client/AgentsView.tsrx +109 -33
- package/modules/agents/src/client/api.ts +99 -21
- package/modules/agents/src/client/state.ts +97 -0
- package/modules/agents/src/domain/types.ts +44 -4
- package/modules/agents/src/platform.ts +42 -0
- package/modules/agents/src/server/action-execution.ts +201 -106
- package/modules/agents/src/server/runtime.ts +32 -0
- package/modules/agents/src/services/agent-service.ts +158 -30
- package/modules/agents/src/services/credential-rotation.ts +185 -0
- package/modules/agents/src/services/credential-vault.ts +71 -46
- package/modules/agents/src/services/data-classes.ts +176 -0
- package/modules/agents/src/services/database-repository.ts +393 -101
- package/modules/agents/src/services/metering.ts +111 -0
- package/modules/agents/src/services/migration.ts +109 -0
- package/modules/agents/src/services/module-agent-preflight.ts +17 -9
- package/modules/agents/src/services/notifications.ts +98 -0
- package/modules/agents/src/services/provider-repository.ts +9 -18
- package/modules/agents/src/services/provider-service.ts +1 -9
- package/modules/agents/src/services/reports.ts +107 -0
- package/modules/agents/src/services/repository.ts +86 -6
- package/modules/agents/src/services/usage-service.ts +2 -0
- package/modules/agents/src/services/worker.ts +114 -4
- package/modules/agents/src/settings.ts +14 -3
- package/modules/agents/translations/en.json +14 -4
- package/modules/agents/translations/pl.json +14 -4
- package/modules/approvals/migrations/0001_approvals_core.down.sql +3 -0
- package/modules/approvals/migrations/0001_approvals_core.up.sql +78 -0
- package/modules/approvals/migrations/0002_approvals_expiry_routing_role.down.sql +2 -0
- package/modules/approvals/migrations/0002_approvals_expiry_routing_role.up.sql +19 -0
- package/modules/approvals/migrations/0003_approvals_retention_indexes.down.sql +6 -0
- package/modules/approvals/migrations/0003_approvals_retention_indexes.up.sql +14 -0
- package/modules/approvals/migrations/0004_approvals_inbox_keyset_indexes.down.sql +5 -0
- package/modules/approvals/migrations/0004_approvals_inbox_keyset_indexes.up.sql +12 -0
- package/modules/approvals/migrations/0005_approvals_grant_audit.down.sql +4 -0
- package/modules/approvals/migrations/0005_approvals_grant_audit.up.sql +20 -0
- package/modules/approvals/migrations/README.md +3 -0
- package/modules/approvals/module.json +34 -0
- package/modules/approvals/package.json +43 -0
- package/modules/approvals/spec/module.yaml +327 -0
- package/modules/approvals/src/acl/permissions.ts +7 -0
- package/modules/approvals/src/api/endpoints.ts +457 -0
- package/modules/approvals/src/client/ApprovalRequestDrawer.tsrx +138 -0
- package/modules/approvals/src/client/ApprovalsView.tsrx +562 -0
- package/modules/approvals/src/client/PendingCountWidget.tsrx +52 -0
- package/modules/approvals/src/client/api.ts +203 -0
- package/modules/approvals/src/client/approvals.css +51 -0
- package/modules/approvals/src/client/contribution.tsrx +44 -0
- package/modules/approvals/src/client/index.ts +26 -0
- package/modules/approvals/src/client/navigation.ts +39 -0
- package/modules/approvals/src/client/pending-count.ts +26 -0
- package/modules/approvals/src/client/presentation.ts +52 -0
- package/modules/approvals/src/client/state.ts +141 -0
- package/modules/approvals/src/domain/capability.ts +107 -0
- package/modules/approvals/src/domain/grant.ts +69 -0
- package/modules/approvals/src/domain/types.ts +168 -0
- package/modules/approvals/src/index.ts +61 -0
- package/modules/approvals/src/platform.ts +136 -0
- package/modules/approvals/src/server/index.ts +42 -0
- package/modules/approvals/src/server/runtime.ts +185 -0
- package/modules/approvals/src/services/approvals-service.ts +637 -0
- package/modules/approvals/src/services/callbacks.ts +75 -0
- package/modules/approvals/src/services/data-classes.ts +167 -0
- package/modules/approvals/src/services/database-repository.ts +783 -0
- package/modules/approvals/src/services/eligibility.ts +121 -0
- package/modules/approvals/src/services/expiry-runner.ts +81 -0
- package/modules/approvals/src/services/index.ts +31 -0
- package/modules/approvals/src/services/migration.ts +256 -0
- package/modules/approvals/src/services/notifications.ts +95 -0
- package/modules/approvals/src/services/repository.ts +169 -0
- package/modules/approvals/src/services/service-error.ts +70 -0
- package/modules/approvals/src/settings.ts +102 -0
- package/modules/approvals/translations/en.json +104 -0
- package/modules/approvals/translations/pl.json +104 -0
- package/modules/audit/migrations/0001_audit_core.down.sql +8 -0
- package/modules/audit/migrations/0001_audit_core.up.sql +107 -0
- package/modules/audit/migrations/0002_audit_sweep_routing_role.down.sql +2 -0
- package/modules/audit/migrations/0002_audit_sweep_routing_role.up.sql +21 -0
- package/modules/audit/migrations/0003_audit_export_request.down.sql +12 -0
- package/modules/audit/migrations/0003_audit_export_request.up.sql +40 -0
- package/modules/audit/migrations/0004_audit_hold_seal_erasure.down.sql +17 -0
- package/modules/audit/migrations/0004_audit_hold_seal_erasure.up.sql +192 -0
- package/modules/audit/migrations/0005_audit_event_format.down.sql +17 -0
- package/modules/audit/migrations/0005_audit_event_format.up.sql +60 -0
- package/modules/audit/migrations/0006_audit_own_class_walks.down.sql +3 -0
- package/modules/audit/migrations/0006_audit_own_class_walks.up.sql +14 -0
- package/modules/audit/migrations/README.md +3 -0
- package/modules/audit/module.json +32 -0
- package/modules/audit/package.json +49 -0
- package/modules/audit/spec/module.yaml +809 -0
- package/modules/audit/src/acl/permissions.ts +7 -0
- package/modules/audit/src/api/endpoints.ts +315 -0
- package/modules/audit/src/cli/commands.json +95 -0
- package/modules/audit/src/cli/index.ts +658 -0
- package/modules/audit/src/client/DataClassesView.tsrx +420 -0
- package/modules/audit/src/client/ExportsView.tsrx +256 -0
- package/modules/audit/src/client/HoldsView.tsrx +604 -0
- package/modules/audit/src/client/SweepsView.tsrx +251 -0
- package/modules/audit/src/client/api.ts +185 -0
- package/modules/audit/src/client/contribution.tsrx +52 -0
- package/modules/audit/src/client/index.ts +23 -0
- package/modules/audit/src/client/navigation.ts +74 -0
- package/modules/audit/src/client/presentation.ts +105 -0
- package/modules/audit/src/client/state.ts +86 -0
- package/modules/audit/src/domain/data-classes.ts +16 -0
- package/modules/audit/src/domain/types.ts +339 -0
- package/modules/audit/src/index.ts +76 -0
- package/modules/audit/src/platform.ts +44 -0
- package/modules/audit/src/server/index.ts +177 -0
- package/modules/audit/src/server/runtime.ts +303 -0
- package/modules/audit/src/services/anchor-key.ts +143 -0
- package/modules/audit/src/services/anchor-rotation.ts +147 -0
- package/modules/audit/src/services/audit-runners.ts +278 -0
- package/modules/audit/src/services/backup-guard.ts +95 -0
- package/modules/audit/src/services/database-repository.ts +1946 -0
- package/modules/audit/src/services/declared-classes.ts +64 -0
- package/modules/audit/src/services/erasure-port.ts +126 -0
- package/modules/audit/src/services/erasure-service.ts +770 -0
- package/modules/audit/src/services/export-directory.ts +106 -0
- package/modules/audit/src/services/export-service.ts +714 -0
- package/modules/audit/src/services/hold-service.ts +295 -0
- package/modules/audit/src/services/index.ts +17 -0
- package/modules/audit/src/services/migration.ts +658 -0
- package/modules/audit/src/services/own-classes.ts +318 -0
- package/modules/audit/src/services/platform-version.ts +23 -0
- package/modules/audit/src/services/repository.ts +495 -0
- package/modules/audit/src/services/retention-service.ts +191 -0
- package/modules/audit/src/services/seal-service.ts +769 -0
- package/modules/audit/src/services/service-error.ts +61 -0
- package/modules/audit/src/services/subject-keys.ts +90 -0
- package/modules/audit/src/services/sweep-service.ts +298 -0
- package/modules/audit/src/services/zip.ts +217 -0
- package/modules/audit/src/settings.ts +69 -0
- package/modules/audit/translations/en.json +210 -0
- package/modules/audit/translations/pl.json +210 -0
- package/modules/auth/README.md +77 -29
- package/modules/auth/migrations/0016_external_identities.up.sql +16 -0
- package/modules/auth/migrations/0017_mfa_key_id.up.sql +8 -0
- package/modules/auth/migrations/0018_retire_bundled_module_scopes.up.sql +29 -0
- package/modules/auth/migrations/0019_notifications_member_scopes.up.sql +44 -0
- package/modules/auth/migrations/0020_identity_providers.up.sql +61 -0
- package/modules/auth/migrations/0021_membership_status.up.sql +19 -0
- package/modules/auth/migrations/0022_auth_provider_scopes.up.sql +45 -0
- package/modules/auth/migrations/0023_enterprise_module_scopes.down.sql +19 -0
- package/modules/auth/migrations/0023_enterprise_module_scopes.up.sql +71 -0
- package/modules/auth/migrations/0024_approvals_member_scopes.down.sql +22 -0
- package/modules/auth/migrations/0024_approvals_member_scopes.up.sql +48 -0
- package/modules/auth/migrations/0025_audit_holds_owner_scope.down.sql +21 -0
- package/modules/auth/migrations/0025_audit_holds_owner_scope.up.sql +47 -0
- package/modules/auth/migrations/0026_auth_export_keyset_indexes.down.sql +6 -0
- package/modules/auth/migrations/0026_auth_export_keyset_indexes.up.sql +15 -0
- package/modules/auth/migrations/0027_workflow_automation_profile_scopes.down.sql +34 -0
- package/modules/auth/migrations/0027_workflow_automation_profile_scopes.up.sql +72 -0
- package/modules/auth/migrations/0028_auth_member_search_prefix_indexes.down.sql +6 -0
- package/modules/auth/migrations/0028_auth_member_search_prefix_indexes.up.sql +21 -0
- package/modules/auth/migrations/0029_reports_exports_access_scopes.down.sql +22 -0
- package/modules/auth/migrations/0029_reports_exports_access_scopes.up.sql +56 -0
- package/modules/auth/migrations/0030_auth_membership_keyset_index.down.sql +4 -0
- package/modules/auth/migrations/0030_auth_membership_keyset_index.up.sql +10 -0
- package/modules/auth/migrations/0031_membership_scope_backfills_under_rls.down.sql +4 -0
- package/modules/auth/migrations/0031_membership_scope_backfills_under_rls.up.sql +31 -0
- package/modules/auth/migrations/0032_audit_actor_service.down.sql +9 -0
- package/modules/auth/migrations/0032_audit_actor_service.up.sql +10 -0
- package/modules/auth/migrations/0033_auth_account_keyset_indexes.down.sql +5 -0
- package/modules/auth/migrations/0033_auth_account_keyset_indexes.up.sql +23 -0
- package/modules/auth/module.json +3 -3
- package/modules/auth/package.json +2 -1
- package/modules/auth/spec/module.yaml +372 -3
- package/modules/auth/src/acl/scopes.ts +50 -6
- package/modules/auth/src/cli/commands.json +11 -0
- package/modules/auth/src/cli/greenfield.ts +2 -2
- package/modules/auth/src/cli/index.ts +14 -0
- package/modules/auth/src/cli/secrets.ts +114 -0
- package/modules/auth/src/client/AuthenticationCore.tsrx +61 -8
- package/modules/auth/src/client/api.ts +72 -6
- package/modules/auth/src/client/contribution.tsrx +23 -0
- package/modules/auth/src/client/index.ts +6 -0
- package/modules/auth/src/client/providers/IdentityProviderForm.tsrx +191 -0
- package/modules/auth/src/client/providers/IdentityProvidersView.tsrx +358 -0
- package/modules/auth/src/client/providers/api.ts +128 -0
- package/modules/auth/src/client/providers/provider-columns.tsrx +60 -0
- package/modules/auth/src/client/providers/state.ts +35 -0
- package/modules/auth/src/client/security/SecurityView.tsrx +9 -1
- package/modules/auth/src/client/state.ts +15 -1
- package/modules/auth/src/domain/types.ts +55 -0
- package/modules/auth/src/index.ts +11 -1
- package/modules/auth/src/middleware/authentication.ts +4 -0
- package/modules/auth/src/server/endpoints.ts +467 -171
- package/modules/auth/src/server/http.ts +3 -2
- package/modules/auth/src/server/index.ts +22 -1
- package/modules/auth/src/server/membership-endpoints.ts +62 -0
- package/modules/auth/src/server/mfa-enforcement.ts +156 -0
- package/modules/auth/src/server/oidc.ts +389 -0
- package/modules/auth/src/server/provider-endpoints.ts +246 -0
- package/modules/auth/src/server/provider-host.ts +77 -0
- package/modules/auth/src/server/runtime.ts +231 -55
- package/modules/auth/src/services/auth-service-error.ts +7 -2
- package/modules/auth/src/services/auth-service.ts +948 -51
- package/modules/auth/src/services/data-classes.ts +236 -0
- package/modules/auth/src/services/database-repository.ts +853 -71
- package/modules/auth/src/services/identity-provider-service.ts +571 -0
- package/modules/auth/src/services/mail-delivery.ts +16 -16
- package/modules/auth/src/services/mail-message.ts +54 -0
- package/modules/auth/src/services/mail-port.ts +24 -0
- package/modules/auth/src/services/mail-smtp.ts +85 -0
- package/modules/auth/src/services/mfa-rotation.ts +144 -0
- package/modules/auth/src/services/migration.ts +810 -0
- package/modules/auth/src/services/password.ts +14 -0
- package/modules/auth/src/services/provider-secret-rotation.ts +169 -0
- package/modules/auth/src/services/provider-secrets.ts +136 -0
- package/modules/auth/src/services/repository.ts +321 -5
- package/modules/auth/src/services/session-sweep-runner.ts +73 -0
- package/modules/auth/src/services/settings-store.ts +10 -83
- package/modules/auth/src/services/totp.ts +88 -62
- package/modules/auth/src/services/validation.ts +194 -7
- package/modules/auth/src/settings.ts +18 -0
- package/modules/auth/translations/en.json +84 -1
- package/modules/auth/translations/pl.json +84 -1
- package/modules/automations/migrations/0005_secret_rotation_inventory.down.sql +1 -0
- package/modules/automations/migrations/0005_secret_rotation_inventory.up.sql +6 -0
- package/modules/automations/migrations/0006_automations_list_sort_indexes.down.sql +4 -0
- package/modules/automations/migrations/0006_automations_list_sort_indexes.up.sql +11 -0
- package/modules/automations/module.json +24 -6
- package/modules/automations/package.json +4 -1
- package/modules/automations/spec/module.yaml +81 -7
- package/modules/automations/src/api/endpoints.ts +202 -28
- package/modules/automations/src/cli/commands.json +17 -0
- package/modules/automations/src/cli/index.ts +114 -0
- package/modules/automations/src/client/AutomationScheduleForm.tsrx +77 -19
- package/modules/automations/src/client/AutomationSchedulesView.tsrx +144 -40
- package/modules/automations/src/client/AutomationTriggersView.tsrx +131 -32
- package/modules/automations/src/client/api.ts +62 -19
- package/modules/automations/src/client/presentation.ts +20 -2
- package/modules/automations/src/client/state.ts +84 -0
- package/modules/automations/src/domain/cadence.ts +99 -3
- package/modules/automations/src/domain/cron.ts +366 -0
- package/modules/automations/src/domain/time-zone.ts +61 -0
- package/modules/automations/src/platform.ts +38 -4
- package/modules/automations/src/server/index.ts +11 -0
- package/modules/automations/src/server/runtime.ts +46 -22
- package/modules/{automations-workflows-integration/src/server/adapter.ts → automations/src/server/workflow-target.ts} +13 -14
- package/modules/{automations-workflows-integration/src/server/tools.ts → automations/src/server/workflow-tools.ts} +0 -0
- package/modules/automations/src/services/data-classes.ts +62 -0
- package/modules/automations/src/services/database-repository.ts +152 -38
- package/modules/automations/src/services/migration.ts +119 -9
- package/modules/automations/src/services/repository.ts +52 -1
- package/modules/automations/src/services/schedule-runner.ts +84 -0
- package/modules/automations/src/services/schedule-service.ts +152 -26
- package/modules/automations/src/services/secret-rotation.ts +176 -0
- package/modules/automations/src/services/secret-vault.ts +68 -41
- package/modules/automations/src/services/trigger-service.ts +13 -10
- package/modules/automations/translations/en.json +15 -2
- package/modules/automations/translations/pl.json +15 -2
- package/modules/connectors/migrations/0001_connectors_core.down.sql +3 -0
- package/modules/connectors/migrations/0001_connectors_core.up.sql +72 -0
- package/modules/connectors/migrations/0002_connectors_call_keys.down.sql +3 -0
- package/modules/connectors/migrations/0002_connectors_call_keys.up.sql +18 -0
- package/modules/connectors/migrations/0003_connectors_rotation_inventory.down.sql +2 -0
- package/modules/connectors/migrations/0003_connectors_rotation_inventory.up.sql +19 -0
- package/modules/connectors/migrations/README.md +3 -0
- package/modules/connectors/module.json +32 -0
- package/modules/{automations-workflows-integration → connectors}/package.json +28 -26
- package/modules/connectors/spec/module.yaml +448 -0
- package/modules/connectors/src/acl/permissions.ts +6 -0
- package/modules/connectors/src/agent/tools.ts +180 -0
- package/modules/connectors/src/api/endpoints.ts +572 -0
- package/modules/connectors/src/cli/commands.json +17 -0
- package/modules/connectors/src/cli/index.ts +126 -0
- package/modules/connectors/src/client/ConnectorCallsView.tsrx +358 -0
- package/modules/connectors/src/client/ConnectorForm.tsrx +424 -0
- package/modules/connectors/src/client/ConnectorsView.tsrx +711 -0
- package/modules/connectors/src/client/api.ts +281 -0
- package/modules/connectors/src/client/consent.ts +48 -0
- package/modules/connectors/src/client/contribution.tsrx +37 -0
- package/modules/connectors/src/client/index.ts +22 -0
- package/modules/connectors/src/client/navigation.ts +42 -0
- package/modules/connectors/src/client/presentation.ts +38 -0
- package/modules/connectors/src/client/state.ts +175 -0
- package/modules/connectors/src/domain/calls.ts +70 -0
- package/modules/connectors/src/domain/definitions.ts +190 -0
- package/modules/connectors/src/domain/http-json.ts +68 -0
- package/modules/connectors/src/domain/types.ts +185 -0
- package/modules/connectors/src/index.ts +64 -0
- package/modules/connectors/src/platform.ts +56 -0
- package/modules/connectors/src/server/index.ts +66 -0
- package/modules/connectors/src/server/runtime.ts +163 -0
- package/modules/connectors/src/services/call-service.ts +903 -0
- package/modules/connectors/src/services/connectors-service.ts +653 -0
- package/modules/connectors/src/services/credential-rotation.ts +221 -0
- package/modules/connectors/src/services/credential-vault.ts +194 -0
- package/modules/connectors/src/services/data-classes.ts +158 -0
- package/modules/connectors/src/services/database-repository.ts +897 -0
- package/modules/connectors/src/services/egress.ts +261 -0
- package/modules/connectors/src/services/index.ts +19 -0
- package/modules/connectors/src/services/migration.ts +202 -0
- package/modules/connectors/src/services/repository.ts +175 -0
- package/modules/connectors/src/services/service-error.ts +46 -0
- package/modules/connectors/src/settings.ts +69 -0
- package/modules/connectors/translations/en.json +191 -0
- package/modules/connectors/translations/pl.json +191 -0
- package/modules/directory/migrations/0001_directory_core.down.sql +5 -0
- package/modules/directory/migrations/0001_directory_core.up.sql +111 -0
- package/modules/directory/migrations/README.md +3 -0
- package/modules/directory/module.json +27 -0
- package/modules/directory/package.json +46 -0
- package/modules/directory/spec/module.yaml +351 -0
- package/modules/directory/src/acl/permissions.ts +7 -0
- package/modules/directory/src/api/endpoints.ts +478 -0
- package/modules/directory/src/api/scim-endpoints.ts +516 -0
- package/modules/directory/src/client/GroupMappingsView.tsrx +430 -0
- package/modules/directory/src/client/ProvisioningLogView.tsrx +248 -0
- package/modules/directory/src/client/ScimTokensView.tsrx +587 -0
- package/modules/directory/src/client/api.ts +222 -0
- package/modules/directory/src/client/contribution.tsrx +46 -0
- package/modules/directory/src/client/index.ts +22 -0
- package/modules/directory/src/client/navigation.ts +57 -0
- package/modules/directory/src/client/presentation.ts +143 -0
- package/modules/directory/src/client/state.ts +173 -0
- package/modules/directory/src/domain/scim.ts +346 -0
- package/modules/directory/src/domain/types.ts +166 -0
- package/modules/directory/src/index.ts +44 -0
- package/modules/directory/src/platform.ts +43 -0
- package/modules/directory/src/server/index.ts +17 -0
- package/modules/directory/src/server/runtime.ts +124 -0
- package/modules/directory/src/services/auth-port.ts +127 -0
- package/modules/directory/src/services/data-classes.ts +41 -0
- package/modules/directory/src/services/database-repository.ts +1067 -0
- package/modules/directory/src/services/directory-service.ts +311 -0
- package/modules/directory/src/services/index.ts +43 -0
- package/modules/directory/src/services/migration.ts +146 -0
- package/modules/directory/src/services/provisioning-service.ts +1420 -0
- package/modules/directory/src/services/rate-limiter.ts +103 -0
- package/modules/directory/src/services/repository.ts +208 -0
- package/modules/directory/src/services/service-error.ts +42 -0
- package/modules/directory/src/services/token-service.ts +215 -0
- package/modules/directory/src/settings.ts +86 -0
- package/modules/directory/translations/en.json +185 -0
- package/modules/directory/translations/pl.json +185 -0
- package/modules/documents/migrations/0001_documents_core.down.sql +1 -0
- package/modules/documents/migrations/0001_documents_core.up.sql +35 -0
- package/modules/documents/migrations/0002_documents_files_page.down.sql +1 -0
- package/modules/documents/migrations/0002_documents_files_page.up.sql +6 -0
- package/modules/documents/migrations/0003_documents_rotation_inventory.down.sql +2 -0
- package/modules/documents/migrations/0003_documents_rotation_inventory.up.sql +18 -0
- package/modules/documents/migrations/README.md +3 -0
- package/modules/documents/module.json +32 -0
- package/modules/documents/package.json +50 -0
- package/modules/documents/spec/module.yaml +248 -0
- package/modules/documents/src/acl/permissions.ts +6 -0
- package/modules/documents/src/api/endpoints.ts +401 -0
- package/modules/documents/src/cli/commands.json +17 -0
- package/modules/documents/src/cli/index.ts +145 -0
- package/modules/documents/src/client/DocumentUploader.tsrx +148 -0
- package/modules/documents/src/client/DocumentsView.tsrx +540 -0
- package/modules/documents/src/client/api.ts +209 -0
- package/modules/documents/src/client/contribution.tsrx +29 -0
- package/modules/documents/src/client/download.ts +70 -0
- package/modules/documents/src/client/index.ts +22 -0
- package/modules/documents/src/client/navigation.ts +25 -0
- package/modules/documents/src/client/presentation.ts +110 -0
- package/modules/documents/src/client/state.ts +117 -0
- package/modules/documents/src/domain/attachments.ts +84 -0
- package/modules/documents/src/domain/types.ts +80 -0
- package/modules/documents/src/index.ts +46 -0
- package/modules/documents/src/platform.ts +61 -0
- package/modules/documents/src/server/index.ts +30 -0
- package/modules/documents/src/server/runtime.ts +107 -0
- package/modules/documents/src/services/attachments.ts +39 -0
- package/modules/documents/src/services/data-classes.ts +25 -0
- package/modules/documents/src/services/database-repository.ts +270 -0
- package/modules/documents/src/services/documents-service.ts +590 -0
- package/modules/documents/src/services/index.ts +18 -0
- package/modules/documents/src/services/migration.ts +117 -0
- package/modules/documents/src/services/repository.ts +58 -0
- package/modules/documents/src/services/storage-rotation.ts +157 -0
- package/modules/documents/src/settings.ts +107 -0
- package/modules/documents/translations/en.json +111 -0
- package/modules/documents/translations/pl.json +111 -0
- package/modules/exports/migrations/0001_exports_core.down.sql +2 -0
- package/modules/exports/migrations/0001_exports_core.up.sql +28 -0
- package/modules/exports/migrations/0002_exports_job_routing_role.down.sql +4 -0
- package/modules/exports/migrations/0002_exports_job_routing_role.up.sql +21 -0
- package/modules/exports/migrations/0003_exports_rotation_inventory.down.sql +1 -0
- package/modules/exports/migrations/0003_exports_rotation_inventory.up.sql +9 -0
- package/modules/exports/migrations/README.md +3 -0
- package/modules/exports/module.json +32 -0
- package/modules/exports/package.json +45 -0
- package/modules/exports/spec/module.yaml +230 -0
- package/modules/exports/src/acl/permissions.ts +6 -0
- package/modules/exports/src/api/endpoints.ts +211 -0
- package/modules/exports/src/cli/commands.json +17 -0
- package/modules/exports/src/cli/index.ts +145 -0
- package/modules/exports/src/client/ExportsView.tsrx +327 -0
- package/modules/exports/src/client/api.ts +133 -0
- package/modules/exports/src/client/contribution.tsrx +31 -0
- package/modules/exports/src/client/index.ts +20 -0
- package/modules/exports/src/client/navigation.ts +25 -0
- package/modules/exports/src/client/presentation.ts +53 -0
- package/modules/exports/src/client/state.ts +56 -0
- package/modules/exports/src/domain/lists.ts +29 -0
- package/modules/exports/src/domain/types.ts +120 -0
- package/modules/exports/src/index.ts +41 -0
- package/modules/exports/src/platform.ts +80 -0
- package/modules/exports/src/server/index.ts +50 -0
- package/modules/exports/src/server/runtime.ts +160 -0
- package/modules/exports/src/services/data-classes.ts +59 -0
- package/modules/exports/src/services/database-repository.ts +403 -0
- package/modules/exports/src/services/export-runner.ts +123 -0
- package/modules/exports/src/services/export-service.ts +356 -0
- package/modules/exports/src/services/index.ts +6 -0
- package/modules/exports/src/services/list-registry.ts +105 -0
- package/modules/exports/src/services/migration.ts +116 -0
- package/modules/exports/src/services/repository.ts +96 -0
- package/modules/exports/src/services/storage-rotation.ts +138 -0
- package/modules/exports/src/settings.ts +70 -0
- package/modules/exports/translations/en.json +69 -0
- package/modules/exports/translations/pl.json +69 -0
- package/modules/import/migrations/0001_import_core.down.sql +6 -0
- package/modules/import/migrations/0001_import_core.up.sql +61 -0
- package/modules/import/migrations/0002_import_job_routing_role.down.sql +4 -0
- package/modules/import/migrations/0002_import_job_routing_role.up.sql +20 -0
- package/modules/import/migrations/0003_import_jobs_export_index.down.sql +1 -0
- package/modules/import/migrations/0003_import_jobs_export_index.up.sql +7 -0
- package/modules/import/migrations/0004_import_jobs_traceparent.down.sql +1 -0
- package/modules/import/migrations/0004_import_jobs_traceparent.up.sql +7 -0
- package/modules/import/migrations/README.md +3 -0
- package/modules/import/module.json +37 -0
- package/modules/import/package.json +50 -0
- package/modules/import/spec/module.yaml +335 -0
- package/modules/import/src/acl/permissions.ts +6 -0
- package/modules/import/src/api/endpoints.ts +400 -0
- package/modules/import/src/client/ImportJobDrawer.tsrx +229 -0
- package/modules/import/src/client/ImportsView.tsrx +455 -0
- package/modules/import/src/client/NewImportForm.tsrx +274 -0
- package/modules/import/src/client/api.ts +243 -0
- package/modules/import/src/client/contribution.tsrx +29 -0
- package/modules/import/src/client/index.ts +23 -0
- package/modules/import/src/client/navigation.ts +25 -0
- package/modules/import/src/client/presentation.ts +59 -0
- package/modules/import/src/client/state.ts +43 -0
- package/modules/import/src/domain/csv.ts +258 -0
- package/modules/import/src/domain/ports.ts +157 -0
- package/modules/import/src/domain/types.ts +179 -0
- package/modules/import/src/index.ts +58 -0
- package/modules/import/src/platform.ts +60 -0
- package/modules/import/src/server/index.ts +49 -0
- package/modules/import/src/server/runtime.ts +158 -0
- package/modules/import/src/services/csv-source.ts +121 -0
- package/modules/import/src/services/data-classes.ts +63 -0
- package/modules/import/src/services/database-repository.ts +780 -0
- package/modules/import/src/services/import-runner.ts +127 -0
- package/modules/import/src/services/import-service.ts +872 -0
- package/modules/import/src/services/index.ts +6 -0
- package/modules/import/src/services/migration.ts +156 -0
- package/modules/import/src/services/port-registry.ts +158 -0
- package/modules/import/src/services/repository.ts +147 -0
- package/modules/import/src/settings.ts +70 -0
- package/modules/import/translations/en.json +175 -0
- package/modules/import/translations/pl.json +175 -0
- package/modules/metering/migrations/0001_metering_core.down.sql +6 -0
- package/modules/metering/migrations/0001_metering_core.up.sql +119 -0
- package/modules/metering/migrations/0002_metering_bucket_export.down.sql +3 -0
- package/modules/metering/migrations/0002_metering_bucket_export.up.sql +5 -0
- package/modules/metering/migrations/README.md +3 -0
- package/modules/metering/module.json +46 -0
- package/modules/metering/package.json +50 -0
- package/modules/metering/spec/module.yaml +269 -0
- package/modules/metering/src/acl/permissions.ts +5 -0
- package/modules/metering/src/api/endpoints.ts +104 -0
- package/modules/metering/src/cli/commands.json +28 -0
- package/modules/metering/src/cli/index.ts +246 -0
- package/modules/metering/src/client/LimitsView.tsrx +170 -0
- package/modules/metering/src/client/UsageSummaryWidget.tsrx +63 -0
- package/modules/metering/src/client/UsageView.tsrx +205 -0
- package/modules/metering/src/client/api.ts +91 -0
- package/modules/metering/src/client/contribution.tsrx +42 -0
- package/modules/metering/src/client/index.ts +26 -0
- package/modules/metering/src/client/navigation.ts +54 -0
- package/modules/metering/src/client/presentation.ts +63 -0
- package/modules/metering/src/client/state.ts +31 -0
- package/modules/metering/src/domain/meters.ts +100 -0
- package/modules/metering/src/domain/types.ts +71 -0
- package/modules/metering/src/index.ts +51 -0
- package/modules/metering/src/platform.ts +84 -0
- package/modules/metering/src/server/index.ts +40 -0
- package/modules/metering/src/server/runtime.ts +165 -0
- package/modules/metering/src/services/data-classes.ts +34 -0
- package/modules/metering/src/services/database-repository.ts +574 -0
- package/modules/metering/src/services/index.ts +9 -0
- package/modules/metering/src/services/meter-registry.ts +145 -0
- package/modules/metering/src/services/metering-service.ts +441 -0
- package/modules/metering/src/services/migration.ts +183 -0
- package/modules/metering/src/services/notifications.ts +75 -0
- package/modules/metering/src/services/reports.ts +105 -0
- package/modules/metering/src/services/repository.ts +132 -0
- package/modules/metering/src/services/service-error.ts +46 -0
- package/modules/metering/src/settings.ts +47 -0
- package/modules/metering/translations/en.json +68 -0
- package/modules/metering/translations/pl.json +68 -0
- package/modules/notifications/migrations/0001_notifications_core.down.sql +1 -0
- package/modules/notifications/migrations/0001_notifications_core.up.sql +26 -0
- package/modules/notifications/migrations/0002_notifications_preferences.down.sql +1 -0
- package/modules/notifications/migrations/0002_notifications_preferences.up.sql +17 -0
- package/modules/notifications/migrations/0003_notifications_webhook_subscriptions.down.sql +1 -0
- package/modules/notifications/migrations/0003_notifications_webhook_subscriptions.up.sql +30 -0
- package/modules/notifications/migrations/0004_notifications_deliveries.down.sql +1 -0
- package/modules/notifications/migrations/0004_notifications_deliveries.up.sql +35 -0
- package/modules/notifications/migrations/0005_notifications_delivery_routing_role.down.sql +2 -0
- package/modules/notifications/migrations/0005_notifications_delivery_routing_role.up.sql +17 -0
- package/modules/notifications/migrations/0006_notifications_delivery_title.down.sql +1 -0
- package/modules/notifications/migrations/0006_notifications_delivery_title.up.sql +11 -0
- package/modules/notifications/migrations/0007_notifications_secret_rotation_inventory.down.sql +2 -0
- package/modules/notifications/migrations/0007_notifications_secret_rotation_inventory.up.sql +19 -0
- package/modules/notifications/migrations/0008_notifications_delivery_claim.down.sql +8 -0
- package/modules/notifications/migrations/0008_notifications_delivery_claim.up.sql +19 -0
- package/modules/notifications/migrations/0009_notifications_kind_approvals.down.sql +16 -0
- package/modules/notifications/migrations/0009_notifications_kind_approvals.up.sql +18 -0
- package/modules/notifications/migrations/0010_notifications_kind_meter_threshold.down.sql +16 -0
- package/modules/notifications/migrations/0010_notifications_kind_meter_threshold.up.sql +18 -0
- package/modules/notifications/migrations/0011_notifications_retention_keyset.down.sql +5 -0
- package/modules/notifications/migrations/0011_notifications_retention_keyset.up.sql +15 -0
- package/modules/notifications/migrations/0012_notifications_email_channel.down.sql +12 -0
- package/modules/notifications/migrations/0012_notifications_email_channel.up.sql +38 -0
- package/modules/notifications/migrations/0013_notifications_list_pages.down.sql +5 -0
- package/modules/notifications/migrations/0013_notifications_list_pages.up.sql +13 -0
- package/modules/notifications/migrations/README.md +3 -0
- package/modules/notifications/module.json +32 -0
- package/modules/notifications/package.json +49 -0
- package/modules/notifications/spec/module.yaml +718 -0
- package/modules/notifications/src/acl/permissions.ts +11 -0
- package/modules/notifications/src/api/endpoints.ts +814 -0
- package/modules/notifications/src/cli/commands.json +17 -0
- package/modules/notifications/src/cli/index.ts +126 -0
- package/modules/notifications/src/client/DeliveriesView.tsrx +483 -0
- package/modules/notifications/src/client/FactList.tsrx +24 -0
- package/modules/notifications/src/client/NotificationPreferencesView.tsrx +240 -0
- package/modules/notifications/src/client/NotificationsInboxView.tsrx +592 -0
- package/modules/notifications/src/client/UnreadCountWidget.tsrx +62 -0
- package/modules/notifications/src/client/WebhookForm.tsrx +297 -0
- package/modules/notifications/src/client/WebhooksView.tsrx +637 -0
- package/modules/notifications/src/client/api.ts +382 -0
- package/modules/notifications/src/client/contribution.tsrx +83 -0
- package/modules/notifications/src/client/inbox.ts +41 -0
- package/modules/notifications/src/client/index.ts +29 -0
- package/modules/notifications/src/client/navigation.ts +92 -0
- package/modules/notifications/src/client/notifications.css +70 -0
- package/modules/notifications/src/client/presentation.ts +81 -0
- package/modules/notifications/src/client/state.ts +246 -0
- package/modules/notifications/src/client/unread-count.ts +26 -0
- package/modules/notifications/src/domain/locale.ts +47 -0
- package/modules/notifications/src/domain/publish.ts +46 -0
- package/modules/notifications/src/domain/types.ts +186 -0
- package/modules/notifications/src/index.ts +62 -0
- package/modules/notifications/src/platform.ts +85 -0
- package/modules/notifications/src/server/index.ts +82 -0
- package/modules/notifications/src/server/runtime.ts +251 -0
- package/modules/notifications/src/services/data-classes.ts +139 -0
- package/modules/notifications/src/services/database-repository.ts +1334 -0
- package/modules/notifications/src/services/delivery-payload.ts +93 -0
- package/modules/notifications/src/services/delivery-runner.ts +170 -0
- package/modules/notifications/src/services/delivery-service.ts +811 -0
- package/modules/notifications/src/services/egress.ts +239 -0
- package/modules/notifications/src/services/email-channel.ts +93 -0
- package/modules/notifications/src/services/index.ts +23 -0
- package/modules/notifications/src/services/migration.ts +572 -0
- package/modules/notifications/src/services/notifications-service.ts +297 -0
- package/modules/notifications/src/services/paging.ts +60 -0
- package/modules/notifications/src/services/publish-service.ts +133 -0
- package/modules/notifications/src/services/repository.ts +342 -0
- package/modules/notifications/src/services/secret-rotation.ts +177 -0
- package/modules/notifications/src/services/secret-vault.ts +168 -0
- package/modules/notifications/src/services/service-error.ts +67 -0
- package/modules/notifications/src/services/signature.ts +81 -0
- package/modules/notifications/src/services/webhook-service.ts +307 -0
- package/modules/notifications/src/settings.ts +130 -0
- package/modules/notifications/translations/en.json +255 -0
- package/modules/notifications/translations/pl.json +255 -0
- package/modules/profile/module.json +3 -3
- package/modules/profile/package.json +1 -1
- package/modules/profile/spec/module.yaml +3 -3
- package/modules/profile/src/services/database-repository.ts +3 -13
- package/modules/reports/module.json +28 -0
- package/modules/reports/package.json +42 -0
- package/modules/reports/spec/module.yaml +231 -0
- package/modules/reports/src/acl/permissions.ts +5 -0
- package/modules/reports/src/api/endpoints.ts +72 -0
- package/modules/reports/src/client/ReportsSummaryWidget.tsrx +52 -0
- package/modules/reports/src/client/ReportsView.tsrx +246 -0
- package/modules/reports/src/client/api.ts +65 -0
- package/modules/reports/src/client/contribution.tsrx +36 -0
- package/modules/reports/src/client/index.ts +18 -0
- package/modules/reports/src/client/navigation.ts +39 -0
- package/modules/reports/src/client/presentation.ts +123 -0
- package/modules/reports/src/client/state.ts +28 -0
- package/modules/reports/src/domain/providers.ts +115 -0
- package/modules/reports/src/domain/types.ts +44 -0
- package/modules/reports/src/index.ts +47 -0
- package/modules/reports/src/platform.ts +37 -0
- package/modules/reports/src/server/index.ts +21 -0
- package/modules/reports/src/server/runtime.ts +40 -0
- package/modules/reports/src/services/index.ts +17 -0
- package/modules/reports/src/services/provider-registry.ts +144 -0
- package/modules/reports/src/services/range.ts +65 -0
- package/modules/reports/src/services/reports-service.ts +316 -0
- package/modules/reports/src/services/service-error.ts +26 -0
- package/modules/reports/src/settings.ts +49 -0
- package/modules/reports/translations/en.json +35 -0
- package/modules/reports/translations/pl.json +35 -0
- package/modules/sandbox/module.json +4 -4
- package/modules/sandbox/package.json +1 -1
- package/modules/sandbox/spec/module.yaml +3 -3
- package/modules/sandbox/src/services/database-repository.ts +14 -23
- package/modules/sandbox/src/services/directory.ts +16 -0
- package/modules/sandbox/src/services/sandbox-service.ts +13 -11
- package/modules/search/migrations/0001_search_core.down.sql +1 -0
- package/modules/search/migrations/0001_search_core.up.sql +22 -0
- package/modules/search/migrations/0002_search_recent_export.down.sql +3 -0
- package/modules/search/migrations/0002_search_recent_export.up.sql +5 -0
- package/modules/search/migrations/README.md +3 -0
- package/modules/search/module.json +28 -0
- package/modules/search/package.json +43 -0
- package/modules/search/spec/module.yaml +177 -0
- package/modules/search/src/acl/permissions.ts +5 -0
- package/modules/search/src/api/endpoints.ts +221 -0
- package/modules/search/src/client/SearchView.tsrx +346 -0
- package/modules/search/src/client/api.ts +157 -0
- package/modules/search/src/client/contribution.tsrx +31 -0
- package/modules/search/src/client/index.ts +17 -0
- package/modules/search/src/client/navigation.ts +97 -0
- package/modules/search/src/client/search.css +56 -0
- package/modules/search/src/client/state.ts +113 -0
- package/modules/search/src/domain/data-classes.ts +73 -0
- package/modules/search/src/domain/providers.ts +88 -0
- package/modules/search/src/domain/types.ts +56 -0
- package/modules/search/src/index.ts +46 -0
- package/modules/search/src/platform.ts +42 -0
- package/modules/search/src/server/index.ts +25 -0
- package/modules/search/src/server/runtime.ts +123 -0
- package/modules/search/src/services/database-repository.ts +163 -0
- package/modules/search/src/services/index.ts +21 -0
- package/modules/search/src/services/migration.ts +65 -0
- package/modules/search/src/services/provider-registry.ts +137 -0
- package/modules/search/src/services/repository.ts +43 -0
- package/modules/search/src/services/search-service.ts +442 -0
- package/modules/search/src/services/service-error.ts +35 -0
- package/modules/search/src/settings.ts +68 -0
- package/modules/search/translations/en.json +45 -0
- package/modules/search/translations/pl.json +45 -0
- package/modules/system/module.json +2 -2
- package/modules/system/package.json +1 -1
- package/modules/system/spec/module.yaml +30 -3
- package/modules/system/src/client/FlagsPanel.tsrx +127 -0
- package/modules/system/src/client/ModuleSettingRow.tsrx +17 -7
- package/modules/system/src/client/ModuleSettingsSection.tsrx +10 -71
- package/modules/system/src/client/ModulesView.tsrx +91 -65
- package/modules/system/src/client/flags.ts +35 -0
- package/modules/system/src/client/index.ts +8 -0
- package/modules/system/src/client/navigation.ts +8 -0
- package/modules/system/src/client/settings-state.ts +159 -0
- package/modules/system/src/client/state.ts +2 -0
- package/modules/system/src/domain/time-zone.ts +105 -0
- package/modules/system/src/index.ts +12 -0
- package/modules/system/src/platform.ts +5 -1
- package/modules/system/src/server/endpoints.ts +72 -21
- package/modules/system/src/settings.ts +28 -0
- package/modules/system/translations/en.json +17 -0
- package/modules/system/translations/pl.json +17 -0
- package/modules/users/module.json +30 -4
- package/modules/users/package.json +4 -1
- package/modules/users/spec/module.yaml +290 -7
- package/modules/users/src/api/endpoints.ts +228 -15
- package/modules/users/src/client/InviteMemberForm.tsrx +2 -2
- package/modules/users/src/client/MemberDrawer.tsrx +142 -26
- package/modules/users/src/client/UserAccountForm.tsrx +2 -2
- package/modules/users/src/client/UsersView.tsrx +432 -71
- package/modules/users/src/client/api.ts +106 -12
- package/modules/users/src/client/contribution.tsrx +5 -0
- package/modules/users/src/client/member-columns.tsrx +22 -9
- package/modules/users/src/client/state.ts +172 -7
- package/modules/users/src/domain/lists.ts +9 -0
- package/modules/users/src/index.ts +11 -0
- package/modules/users/src/platform.ts +50 -1
- package/modules/users/src/services/member-export.ts +51 -0
- package/modules/users/src/services/member-import.ts +249 -0
- package/modules/users/src/services/member-search.ts +145 -0
- package/modules/users/src/services/users-service.ts +117 -4
- package/modules/users/translations/en.json +57 -8
- package/modules/users/translations/pl.json +57 -8
- package/modules/workflows/migrations/0004_payload_rotation_inventory.up.sql +17 -0
- package/modules/workflows/migrations/0005_workflows_human_approval.up.sql +28 -0
- package/modules/workflows/migrations/0006_workflows_retention_indexes.up.sql +11 -0
- package/modules/workflows/migrations/0007_workflows_erasure_subject_indexes.up.sql +17 -0
- package/modules/workflows/migrations/0008_workflows_subject_account.up.sql +24 -0
- package/modules/workflows/migrations/0009_workflows_definition_list_indexes.up.sql +9 -0
- package/modules/workflows/module.json +34 -6
- package/modules/workflows/package.json +2 -1
- package/modules/workflows/spec/module.yaml +26 -9
- package/modules/workflows/src/api/endpoints.ts +131 -25
- package/modules/workflows/src/cli/commands.json +17 -0
- package/modules/workflows/src/cli/index.ts +114 -0
- package/modules/workflows/src/client/WorkflowExecutionHistory.tsrx +36 -27
- package/modules/workflows/src/client/WorkflowInspector.tsrx +116 -0
- package/modules/workflows/src/client/WorkflowNodePalette.tsrx +1 -0
- package/modules/workflows/src/client/WorkflowsView.tsrx +236 -99
- package/modules/workflows/src/client/api.ts +54 -34
- package/modules/workflows/src/client/canvas-model.ts +12 -0
- package/modules/workflows/src/client/state.ts +95 -0
- package/modules/workflows/src/domain/events.ts +25 -11
- package/modules/workflows/src/domain/graph.ts +135 -1
- package/modules/workflows/src/domain/types.ts +91 -4
- package/modules/workflows/src/platform.ts +12 -0
- package/modules/workflows/src/server/runtime.ts +78 -5
- package/modules/workflows/src/services/approvals.ts +62 -0
- package/modules/workflows/src/services/cursors.ts +37 -0
- package/modules/workflows/src/services/data-classes.ts +232 -0
- package/modules/workflows/src/services/database-repository.ts +660 -171
- package/modules/workflows/src/services/migration.ts +240 -0
- package/modules/workflows/src/services/notifications.ts +98 -0
- package/modules/workflows/src/services/payload-codec.ts +51 -28
- package/modules/workflows/src/services/payload-rotation.ts +171 -0
- package/modules/workflows/src/services/repository.ts +123 -8
- package/modules/workflows/src/services/simulation.ts +7 -0
- package/modules/workflows/src/services/worker.ts +446 -25
- package/modules/workflows/src/services/workflows-service.ts +264 -103
- package/modules/workflows/translations/en.json +12 -4
- package/modules/workflows/translations/pl.json +12 -4
- package/modules.json +48 -4
- package/package.json +64 -6
- package/packages/client/package.json +1 -0
- package/packages/client/src/ApplicationShell.tsrx +43 -0
- package/packages/client/src/contributions.ts +55 -0
- package/packages/client/src/i18n/locales/en.json +5 -0
- package/packages/client/src/i18n/locales/pl.json +5 -0
- package/packages/client/src/index.ts +13 -1
- package/packages/client/src/routing.ts +22 -0
- package/packages/client/src/shell/CommandPalette.tsrx +223 -11
- package/packages/client/src/shell/command-search.ts +126 -0
- package/packages/client/src/shell/command.ts +30 -0
- package/packages/client/src/shell/navigation.ts +12 -0
- package/packages/client/src/shell/palette-keys.ts +27 -0
- package/packages/client/src/shell/shell.css +7 -0
- package/packages/contracts/schemas/module-spec.schema.json +287 -1
- package/packages/contracts/schemas/module.schema.json +25 -0
- package/packages/contracts/src/index.ts +144 -1
- package/packages/database/src/backup.ts +180 -0
- package/packages/database/src/decoders.ts +25 -0
- package/packages/database/src/index.ts +17 -0
- package/packages/database/src/migrations.ts +7 -0
- package/packages/database/src/record-history.ts +5 -14
- package/packages/harness/src/index.ts +2 -0
- package/packages/harness/src/runtime.ts +378 -2
- package/packages/harness/src/tool-adapters.ts +20 -9
- package/packages/kernel/src/acl.ts +179 -0
- package/packages/kernel/src/approval-grant.ts +310 -0
- package/packages/kernel/src/capability-registry.ts +69 -2
- package/packages/kernel/src/data-class-registry.ts +354 -0
- package/packages/kernel/src/index.ts +85 -4
- package/packages/kernel/src/keyring.ts +208 -0
- package/packages/kernel/src/module-compatibility.ts +35 -4
- package/packages/kernel/src/module-registry.ts +49 -2
- package/packages/kernel/src/module-settings.ts +189 -27
- package/packages/server/package.json +2 -1
- package/packages/server/src/composition.ts +38 -0
- package/packages/server/src/endpoint.ts +104 -47
- package/packages/server/src/export/csv.ts +34 -0
- package/packages/server/src/export/definition.ts +346 -0
- package/packages/server/src/export/index.ts +61 -0
- package/packages/server/src/export/run.ts +116 -0
- package/packages/server/src/index.ts +155 -0
- package/packages/server/src/jobs/index.ts +93 -0
- package/packages/server/src/jobs/runner.ts +486 -0
- package/packages/server/src/log.ts +291 -0
- package/packages/server/src/mail/config.ts +184 -0
- package/packages/server/src/mail/contracts.ts +251 -0
- package/packages/server/src/mail/index.ts +31 -0
- package/packages/server/src/mail/port.ts +101 -0
- package/packages/server/src/mail/smtp.ts +191 -0
- package/packages/server/src/mail/template.ts +105 -0
- package/packages/server/src/metrics.ts +447 -0
- package/packages/server/src/pagination.ts +246 -0
- package/packages/server/src/trace/context.ts +103 -0
- package/packages/server/src/trace/egress.ts +66 -0
- package/packages/server/src/trace/error-sink.ts +296 -0
- package/packages/server/src/trace/exporter.ts +295 -0
- package/packages/server/src/trace/index.ts +60 -0
- package/packages/server/src/trace/job-sink.ts +172 -0
- package/packages/server/src/trace/tracer.ts +338 -0
- package/packages/server/src/web.ts +5 -1
- package/packages/storage/package.json +40 -0
- package/packages/storage/src/config.ts +189 -0
- package/packages/storage/src/content-type.ts +124 -0
- package/packages/storage/src/contracts.ts +112 -0
- package/packages/storage/src/envelope.ts +238 -0
- package/packages/storage/src/index.ts +49 -0
- package/packages/storage/src/local.ts +75 -0
- package/packages/storage/src/port.ts +262 -0
- package/packages/storage/src/read-token.ts +130 -0
- package/packages/storage/src/reseal.ts +128 -0
- package/packages/storage/src/s3.ts +144 -0
- package/packages/storage/src/scanner.ts +22 -0
- package/packages/storage/src/sigv4.ts +104 -0
- package/packages/storage/src/store.ts +13 -0
- package/packages/ui/package.json +1 -0
- package/packages/ui/src/components/Button.tsrx +3 -0
- package/packages/ui/src/components/ConfirmDialog.tsrx +13 -2
- package/packages/ui/src/components/DateField.tsrx +92 -0
- package/packages/ui/src/components/DatePicker.tsrx +525 -0
- package/packages/ui/src/components/DateRangeField.tsrx +93 -0
- package/packages/ui/src/components/Drawer.tsrx +10 -1
- package/packages/ui/src/components/FileUpload.tsrx +158 -0
- package/packages/ui/src/components/Pagination.tsrx +130 -0
- package/packages/ui/src/components/Select.tsrx +78 -0
- package/packages/ui/src/components/Table.tsrx +498 -81
- package/packages/ui/src/components/Tabs.tsrx +53 -0
- package/packages/ui/src/components/ToastHost.tsrx +48 -0
- package/packages/ui/src/components/calendar.ts +243 -0
- package/packages/ui/src/components/date-field.ts +62 -0
- package/packages/ui/src/components/file-upload.ts +49 -0
- package/packages/ui/src/components/focus-trap.ts +62 -0
- package/packages/ui/src/components/pagination.ts +68 -0
- package/packages/ui/src/components/table-sorting.ts +49 -0
- package/packages/ui/src/components/tabs.ts +61 -0
- package/packages/ui/src/components/toast-store.ts +116 -0
- package/packages/ui/src/icons/Icon.tsrx +5 -0
- package/packages/ui/src/index.ts +45 -0
- package/packages/ui/src/styles/components.css +598 -0
- package/modules/automations-workflows-integration/module.json +0 -27
- package/modules/automations-workflows-integration/spec/module.yaml +0 -93
- package/modules/automations-workflows-integration/src/index.ts +0 -14
- package/modules/automations-workflows-integration/src/platform.ts +0 -24
- package/modules/automations-workflows-integration/src/server/index.ts +0 -11
- package/modules/automations-workflows-integration/translations/en.json +0 -21
- package/modules/automations-workflows-integration/translations/pl.json +0 -21
- package/modules/workflows/src/services/cursor-codec.ts +0 -62
|
@@ -0,0 +1,769 @@
|
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { mkdir, open, readdir, rm, stat } from 'node:fs/promises';
|
|
4
|
+
import { resolve } from 'node:path';
|
|
5
|
+
import { createInterface } from 'node:readline';
|
|
6
|
+
import { AUDIT_EVENT_ACTIONS, type AuditChainAnchor } from '../domain/types.ts';
|
|
7
|
+
import type { AnchorSigner } from './anchor-key.ts';
|
|
8
|
+
import { storedAuditEventHash } from './database-repository.ts';
|
|
9
|
+
import { exportOutputDirectory } from './export-directory.ts';
|
|
10
|
+
import type { AuditRepository, StoredAuditEvent } from './repository.ts';
|
|
11
|
+
import { AuditServiceError } from './service-error.ts';
|
|
12
|
+
|
|
13
|
+
export const SEGMENT_FORMAT_VERSION = 'audit-segment/1';
|
|
14
|
+
|
|
15
|
+
/** Bounds. A segment is a file an operator has to be able to hold and read. */
|
|
16
|
+
export const SEAL_LIMITS = {
|
|
17
|
+
/** Events one page of the walk carries. */
|
|
18
|
+
page: 500,
|
|
19
|
+
/** Events one segment may close; more are sealed by the next run. */
|
|
20
|
+
rowsPerSegment: 200_000,
|
|
21
|
+
/**
|
|
22
|
+
* Files one verification pass reads from a directory, and anchors it reads
|
|
23
|
+
* from the workspace. Both windows take the newest end of their order, so a
|
|
24
|
+
* directory holding more than this is checked against the anchors of the
|
|
25
|
+
* same end of the chain rather than against the other one.
|
|
26
|
+
*/
|
|
27
|
+
filesPerVerify: 4_096,
|
|
28
|
+
/** Bytes one segment file may hold before verification refuses to read it. */
|
|
29
|
+
fileBytes: 256 * 1_024 * 1_024,
|
|
30
|
+
} as const;
|
|
31
|
+
|
|
32
|
+
/** One link of the segment chain, so neither walk ever holds a hash list. */
|
|
33
|
+
function chainStep(accumulator: string, eventHash: string): string {
|
|
34
|
+
return createHash('sha256')
|
|
35
|
+
.update(JSON.stringify([accumulator, eventHash]))
|
|
36
|
+
.digest('hex');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The first line of a segment file; every line after it is an event. */
|
|
40
|
+
export interface SegmentAnchorLine {
|
|
41
|
+
readonly kind: 'anchor';
|
|
42
|
+
readonly formatVersion: string;
|
|
43
|
+
readonly tenantId: string;
|
|
44
|
+
readonly anchorSequence: number;
|
|
45
|
+
readonly fromSequence: number;
|
|
46
|
+
readonly toSequence: number;
|
|
47
|
+
readonly rowCount: number;
|
|
48
|
+
readonly firstOccurredAt: number;
|
|
49
|
+
readonly lastOccurredAt: number;
|
|
50
|
+
readonly segmentHash: string;
|
|
51
|
+
readonly previousAnchorHash: string | null;
|
|
52
|
+
readonly anchorHash: string;
|
|
53
|
+
readonly signature: string;
|
|
54
|
+
readonly keyId: string;
|
|
55
|
+
readonly sealedBy: string;
|
|
56
|
+
readonly sealedAt: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface SegmentEventLine extends StoredAuditEvent {
|
|
60
|
+
readonly kind: 'event';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface SealPlan {
|
|
64
|
+
readonly fromSequence: number;
|
|
65
|
+
readonly toSequence: number;
|
|
66
|
+
readonly rowCount: number;
|
|
67
|
+
readonly firstOccurredAt: number | null;
|
|
68
|
+
readonly lastOccurredAt: number | null;
|
|
69
|
+
readonly previousAnchor: AuditChainAnchor | null;
|
|
70
|
+
/** True when more events remain than one segment may close. */
|
|
71
|
+
readonly truncated: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface SealResult {
|
|
75
|
+
readonly applied: boolean;
|
|
76
|
+
readonly plan: SealPlan;
|
|
77
|
+
readonly segmentFile: string | null;
|
|
78
|
+
readonly segmentPath: string | null;
|
|
79
|
+
readonly anchor: AuditChainAnchor | null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface SegmentVerification {
|
|
83
|
+
readonly file: string;
|
|
84
|
+
readonly ok: boolean;
|
|
85
|
+
readonly anchorSequence: number | null;
|
|
86
|
+
readonly fromSequence: number | null;
|
|
87
|
+
readonly toSequence: number | null;
|
|
88
|
+
readonly events: number;
|
|
89
|
+
/**
|
|
90
|
+
* Events written before audit.core recorded an event format, so nothing says
|
|
91
|
+
* whether the actor and the subject of one naming a person are in the clear.
|
|
92
|
+
* An event about nobody is not one of them.
|
|
93
|
+
*/
|
|
94
|
+
readonly plaintextEvents: number;
|
|
95
|
+
readonly signatureKeyId: string | null;
|
|
96
|
+
readonly failures: readonly string[];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface VerifyReport {
|
|
100
|
+
readonly ok: boolean;
|
|
101
|
+
readonly directory: string;
|
|
102
|
+
readonly segments: readonly SegmentVerification[];
|
|
103
|
+
readonly chain: {
|
|
104
|
+
readonly ok: boolean;
|
|
105
|
+
readonly anchors: number;
|
|
106
|
+
readonly failures: readonly string[];
|
|
107
|
+
};
|
|
108
|
+
readonly totals: {
|
|
109
|
+
readonly events: number;
|
|
110
|
+
readonly plaintextEvents: number;
|
|
111
|
+
};
|
|
112
|
+
/** What this pass was able to look at, so a report is read for its bound. */
|
|
113
|
+
readonly window: {
|
|
114
|
+
readonly limit: number;
|
|
115
|
+
readonly files: number;
|
|
116
|
+
readonly anchors: number;
|
|
117
|
+
/**
|
|
118
|
+
* True when the directory or the chain may hold more than one pass reads,
|
|
119
|
+
* so the verification covers the newest `limit` of each and says nothing
|
|
120
|
+
* about what lies before them. A chain of exactly `limit` anchors reports
|
|
121
|
+
* it too: the read cannot tell a full window from a truncated one.
|
|
122
|
+
*/
|
|
123
|
+
readonly truncated: boolean;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface SealRequest {
|
|
128
|
+
readonly tenantId: string;
|
|
129
|
+
readonly outputDirectory: string;
|
|
130
|
+
readonly sealedBy: string;
|
|
131
|
+
readonly apply: boolean;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface SealServiceOptions {
|
|
135
|
+
readonly repository: AuditRepository;
|
|
136
|
+
readonly signer: AnchorSigner;
|
|
137
|
+
readonly environment: NodeJS.ProcessEnv;
|
|
138
|
+
readonly workspaceRoot: string;
|
|
139
|
+
readonly now?: () => number;
|
|
140
|
+
/** Test seam; the shipped window is SEAL_LIMITS.filesPerVerify. */
|
|
141
|
+
readonly verifyWindow?: number;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* One chained hash over a segment. It starts at the anchor before it, so a
|
|
146
|
+
* segment can only be checked in the place the chain actually put it: moving a
|
|
147
|
+
* file between directories or reordering two segments breaks the link.
|
|
148
|
+
*/
|
|
149
|
+
export function segmentChain(
|
|
150
|
+
previousAnchorHash: string | null,
|
|
151
|
+
eventHashes: Iterable<string>,
|
|
152
|
+
): string {
|
|
153
|
+
let accumulator = previousAnchorHash ?? '';
|
|
154
|
+
for (const hash of eventHashes) accumulator = chainStep(accumulator, hash);
|
|
155
|
+
return accumulator;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function anchorHashOf(input: {
|
|
159
|
+
readonly tenantId: string;
|
|
160
|
+
readonly anchorSequence: number;
|
|
161
|
+
readonly fromSequence: number;
|
|
162
|
+
readonly toSequence: number;
|
|
163
|
+
readonly rowCount: number;
|
|
164
|
+
readonly firstOccurredAt: number;
|
|
165
|
+
readonly lastOccurredAt: number;
|
|
166
|
+
readonly segmentHash: string;
|
|
167
|
+
readonly previousAnchorHash: string | null;
|
|
168
|
+
}): string {
|
|
169
|
+
return createHash('sha256')
|
|
170
|
+
.update(
|
|
171
|
+
JSON.stringify([
|
|
172
|
+
input.tenantId,
|
|
173
|
+
input.anchorSequence,
|
|
174
|
+
input.fromSequence,
|
|
175
|
+
input.toSequence,
|
|
176
|
+
input.rowCount,
|
|
177
|
+
input.firstOccurredAt,
|
|
178
|
+
input.lastOccurredAt,
|
|
179
|
+
input.segmentHash,
|
|
180
|
+
input.previousAnchorHash,
|
|
181
|
+
]),
|
|
182
|
+
)
|
|
183
|
+
.digest('hex');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Sealing and verification of the per-workspace audit chain.
|
|
188
|
+
*
|
|
189
|
+
* A seal is two walks over the same closed range: the first computes the chain
|
|
190
|
+
* and the bounds, the second writes the file. The range is closed before the
|
|
191
|
+
* second walk starts and events only ever append, so both walks read exactly
|
|
192
|
+
* the same rows and neither holds more than one page in memory.
|
|
193
|
+
*/
|
|
194
|
+
export class AuditSealService {
|
|
195
|
+
readonly #repository: AuditRepository;
|
|
196
|
+
readonly #signer: AnchorSigner;
|
|
197
|
+
readonly #environment: NodeJS.ProcessEnv;
|
|
198
|
+
readonly #workspaceRoot: string;
|
|
199
|
+
readonly #now: () => number;
|
|
200
|
+
readonly #verifyWindow: number;
|
|
201
|
+
|
|
202
|
+
constructor(options: SealServiceOptions) {
|
|
203
|
+
this.#repository = options.repository;
|
|
204
|
+
this.#signer = options.signer;
|
|
205
|
+
this.#environment = options.environment;
|
|
206
|
+
this.#workspaceRoot = options.workspaceRoot;
|
|
207
|
+
this.#now = options.now ?? Date.now;
|
|
208
|
+
this.#verifyWindow = Math.max(
|
|
209
|
+
1,
|
|
210
|
+
Math.trunc(options.verifyWindow ?? SEAL_LIMITS.filesPerVerify),
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async plan(tenantId: string): Promise<SealPlan> {
|
|
215
|
+
const previousAnchor = await this.#repository.latestAnchor(tenantId);
|
|
216
|
+
const after = previousAnchor?.toSequence ?? 0;
|
|
217
|
+
let rowCount = 0;
|
|
218
|
+
let fromSequence = 0;
|
|
219
|
+
let toSequence = after;
|
|
220
|
+
let firstOccurredAt: number | null = null;
|
|
221
|
+
let lastOccurredAt: number | null = null;
|
|
222
|
+
const complete = await this.#walk(tenantId, after, (event) => {
|
|
223
|
+
if (rowCount === 0) {
|
|
224
|
+
fromSequence = event.sequence;
|
|
225
|
+
firstOccurredAt = event.occurredAt;
|
|
226
|
+
}
|
|
227
|
+
toSequence = event.sequence;
|
|
228
|
+
lastOccurredAt = event.occurredAt;
|
|
229
|
+
rowCount += 1;
|
|
230
|
+
return rowCount < SEAL_LIMITS.rowsPerSegment;
|
|
231
|
+
});
|
|
232
|
+
const truncated = !complete;
|
|
233
|
+
return {
|
|
234
|
+
fromSequence: rowCount === 0 ? after + 1 : fromSequence,
|
|
235
|
+
toSequence,
|
|
236
|
+
rowCount,
|
|
237
|
+
firstOccurredAt,
|
|
238
|
+
lastOccurredAt,
|
|
239
|
+
previousAnchor,
|
|
240
|
+
truncated,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async seal(request: SealRequest): Promise<SealResult> {
|
|
245
|
+
const plan = await this.plan(request.tenantId);
|
|
246
|
+
if (plan.rowCount === 0) {
|
|
247
|
+
throw new AuditServiceError(
|
|
248
|
+
'NOTHING_TO_SEAL',
|
|
249
|
+
'Every audit event of this workspace is already in a segment file.',
|
|
250
|
+
409,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
/* Resolved for the plan too, so an operator learns that the directory is
|
|
254
|
+
refused before being told how much would be written. */
|
|
255
|
+
const directory = this.#directory(request.outputDirectory);
|
|
256
|
+
const segmentFile = segmentName(
|
|
257
|
+
request.tenantId,
|
|
258
|
+
plan.fromSequence,
|
|
259
|
+
plan.toSequence,
|
|
260
|
+
);
|
|
261
|
+
if (!request.apply) {
|
|
262
|
+
return {
|
|
263
|
+
applied: false,
|
|
264
|
+
plan,
|
|
265
|
+
segmentFile,
|
|
266
|
+
segmentPath: resolve(directory, segmentFile),
|
|
267
|
+
anchor: null,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
let accumulator = plan.previousAnchor?.anchorHash ?? '';
|
|
271
|
+
await this.#walk(
|
|
272
|
+
request.tenantId,
|
|
273
|
+
plan.previousAnchor?.toSequence ?? 0,
|
|
274
|
+
(event) => {
|
|
275
|
+
if (event.sequence > plan.toSequence) return false;
|
|
276
|
+
accumulator = chainStep(accumulator, event.eventHash);
|
|
277
|
+
return true;
|
|
278
|
+
},
|
|
279
|
+
);
|
|
280
|
+
const segmentHash = accumulator;
|
|
281
|
+
const anchorSequence = (plan.previousAnchor?.anchorSequence ?? 0) + 1;
|
|
282
|
+
const anchorHash = anchorHashOf({
|
|
283
|
+
tenantId: request.tenantId,
|
|
284
|
+
anchorSequence,
|
|
285
|
+
fromSequence: plan.fromSequence,
|
|
286
|
+
toSequence: plan.toSequence,
|
|
287
|
+
rowCount: plan.rowCount,
|
|
288
|
+
firstOccurredAt: plan.firstOccurredAt!,
|
|
289
|
+
lastOccurredAt: plan.lastOccurredAt!,
|
|
290
|
+
segmentHash,
|
|
291
|
+
previousAnchorHash: plan.previousAnchor?.anchorHash ?? null,
|
|
292
|
+
});
|
|
293
|
+
const sealedAt = this.#now();
|
|
294
|
+
const anchorLine: SegmentAnchorLine = {
|
|
295
|
+
kind: 'anchor',
|
|
296
|
+
formatVersion: SEGMENT_FORMAT_VERSION,
|
|
297
|
+
tenantId: request.tenantId,
|
|
298
|
+
anchorSequence,
|
|
299
|
+
fromSequence: plan.fromSequence,
|
|
300
|
+
toSequence: plan.toSequence,
|
|
301
|
+
rowCount: plan.rowCount,
|
|
302
|
+
firstOccurredAt: plan.firstOccurredAt!,
|
|
303
|
+
lastOccurredAt: plan.lastOccurredAt!,
|
|
304
|
+
segmentHash,
|
|
305
|
+
previousAnchorHash: plan.previousAnchor?.anchorHash ?? null,
|
|
306
|
+
anchorHash,
|
|
307
|
+
signature: this.#signer.sign(anchorHash),
|
|
308
|
+
keyId: this.#signer.keyId,
|
|
309
|
+
sealedBy: request.sealedBy,
|
|
310
|
+
sealedAt,
|
|
311
|
+
};
|
|
312
|
+
const segmentPath = await this.#write(
|
|
313
|
+
directory,
|
|
314
|
+
segmentFile,
|
|
315
|
+
request.tenantId,
|
|
316
|
+
plan,
|
|
317
|
+
anchorLine,
|
|
318
|
+
);
|
|
319
|
+
/* The file exists before the anchor is recorded: an anchor without its
|
|
320
|
+
segment would let retention remove links nothing holds, while a file
|
|
321
|
+
without an anchor is only a file the next seal rewrites. */
|
|
322
|
+
const anchor = await this.#repository.insertAnchor({
|
|
323
|
+
tenantId: request.tenantId,
|
|
324
|
+
anchorSequence,
|
|
325
|
+
fromSequence: plan.fromSequence,
|
|
326
|
+
toSequence: plan.toSequence,
|
|
327
|
+
rowCount: plan.rowCount,
|
|
328
|
+
firstOccurredAt: plan.firstOccurredAt!,
|
|
329
|
+
lastOccurredAt: plan.lastOccurredAt!,
|
|
330
|
+
segmentHash,
|
|
331
|
+
previousAnchorHash: plan.previousAnchor?.anchorHash ?? null,
|
|
332
|
+
anchorHash,
|
|
333
|
+
signature: anchorLine.signature,
|
|
334
|
+
keyId: anchorLine.keyId,
|
|
335
|
+
segmentFile,
|
|
336
|
+
sealedBy: request.sealedBy,
|
|
337
|
+
sealedAt,
|
|
338
|
+
});
|
|
339
|
+
await this.#repository.appendAuditEvent({
|
|
340
|
+
tenantId: request.tenantId,
|
|
341
|
+
actorId: request.sealedBy,
|
|
342
|
+
action: AUDIT_EVENT_ACTIONS.chainSealed,
|
|
343
|
+
subjectType: 'chain-anchor',
|
|
344
|
+
subjectId: anchor.id,
|
|
345
|
+
metadata: {
|
|
346
|
+
anchorSequence,
|
|
347
|
+
fromSequence: plan.fromSequence,
|
|
348
|
+
toSequence: plan.toSequence,
|
|
349
|
+
rowCount: plan.rowCount,
|
|
350
|
+
segmentFile,
|
|
351
|
+
keyId: anchorLine.keyId,
|
|
352
|
+
},
|
|
353
|
+
occurredAt: this.#now(),
|
|
354
|
+
});
|
|
355
|
+
return { applied: true, plan, segmentFile, segmentPath, anchor };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Verifies the segment files of a directory against the anchors the
|
|
360
|
+
* workspace recorded. It reads and never writes, so it is the same run with
|
|
361
|
+
* and without --apply.
|
|
362
|
+
*
|
|
363
|
+
* One pass reads the newest `filesPerVerify` files and the newest
|
|
364
|
+
* `filesPerVerify` anchors, and the report states that bound: a deployment
|
|
365
|
+
* that has sealed more than one window holds evidence this pass did not
|
|
366
|
+
* look at.
|
|
367
|
+
*/
|
|
368
|
+
async verify(request: {
|
|
369
|
+
readonly tenantId: string;
|
|
370
|
+
readonly inputDirectory: string;
|
|
371
|
+
}): Promise<VerifyReport> {
|
|
372
|
+
const directory = this.#directory(request.inputDirectory);
|
|
373
|
+
/* One directory holds the segments of every workspace a deployment
|
|
374
|
+
sealed, so the name prefix is what selects this workspace's. A file of
|
|
375
|
+
another one is not this verification's to accept or reject. */
|
|
376
|
+
const prefix = segmentNamePrefix(request.tenantId);
|
|
377
|
+
const matching = (await readdir(directory))
|
|
378
|
+
.filter((name) => name.startsWith(prefix) && name.endsWith('.jsonl'))
|
|
379
|
+
.sort();
|
|
380
|
+
/* The name carries the zero-padded sequence range, so the sort is chain
|
|
381
|
+
order and the newest files are the last of it. The anchors are read
|
|
382
|
+
newest first, so taking the oldest files here would compare one end of
|
|
383
|
+
the directory against the other end of the chain. */
|
|
384
|
+
const names = matching.slice(
|
|
385
|
+
Math.max(0, matching.length - this.#verifyWindow),
|
|
386
|
+
);
|
|
387
|
+
const anchors = await this.#repository.listAnchors(
|
|
388
|
+
request.tenantId,
|
|
389
|
+
this.#verifyWindow,
|
|
390
|
+
);
|
|
391
|
+
const recorded = new Map(
|
|
392
|
+
anchors.map((anchor) => [anchor.anchorSequence, anchor]),
|
|
393
|
+
);
|
|
394
|
+
const segments: SegmentVerification[] = [];
|
|
395
|
+
const seen = new Map<number, SegmentAnchorLine>();
|
|
396
|
+
for (const name of names) {
|
|
397
|
+
segments.push(
|
|
398
|
+
await this.#verifySegment(
|
|
399
|
+
directory,
|
|
400
|
+
name,
|
|
401
|
+
request.tenantId,
|
|
402
|
+
recorded,
|
|
403
|
+
seen,
|
|
404
|
+
),
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
const chainFailures = chainFailuresOf(seen, recorded);
|
|
408
|
+
const totals = segments.reduce(
|
|
409
|
+
(sum, entry) => ({
|
|
410
|
+
events: sum.events + entry.events,
|
|
411
|
+
plaintextEvents: sum.plaintextEvents + entry.plaintextEvents,
|
|
412
|
+
}),
|
|
413
|
+
{ events: 0, plaintextEvents: 0 },
|
|
414
|
+
);
|
|
415
|
+
return {
|
|
416
|
+
ok: segments.every((entry) => entry.ok) && chainFailures.length === 0,
|
|
417
|
+
directory,
|
|
418
|
+
segments,
|
|
419
|
+
chain: {
|
|
420
|
+
ok: chainFailures.length === 0,
|
|
421
|
+
anchors: seen.size,
|
|
422
|
+
failures: chainFailures,
|
|
423
|
+
},
|
|
424
|
+
totals,
|
|
425
|
+
window: {
|
|
426
|
+
limit: this.#verifyWindow,
|
|
427
|
+
files: names.length,
|
|
428
|
+
anchors: anchors.length,
|
|
429
|
+
truncated:
|
|
430
|
+
matching.length > names.length ||
|
|
431
|
+
anchors.length >= this.#verifyWindow,
|
|
432
|
+
},
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/** One file of this workspace's own name prefix, read once, start to end. */
|
|
437
|
+
async #verifySegment(
|
|
438
|
+
directory: string,
|
|
439
|
+
name: string,
|
|
440
|
+
tenantId: string,
|
|
441
|
+
recorded: ReadonlyMap<number, AuditChainAnchor>,
|
|
442
|
+
seen: Map<number, SegmentAnchorLine>,
|
|
443
|
+
): Promise<SegmentVerification> {
|
|
444
|
+
const failures: string[] = [];
|
|
445
|
+
const path = resolve(directory, name);
|
|
446
|
+
const stats = await stat(path);
|
|
447
|
+
if (stats.size > SEAL_LIMITS.fileBytes) {
|
|
448
|
+
return {
|
|
449
|
+
file: name,
|
|
450
|
+
ok: false,
|
|
451
|
+
anchorSequence: null,
|
|
452
|
+
fromSequence: null,
|
|
453
|
+
toSequence: null,
|
|
454
|
+
events: 0,
|
|
455
|
+
plaintextEvents: 0,
|
|
456
|
+
signatureKeyId: null,
|
|
457
|
+
failures: [
|
|
458
|
+
`${name} is larger than ${SEAL_LIMITS.fileBytes} bytes and was not read.`,
|
|
459
|
+
],
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
/* Read a line at a time: a segment may hold every event of a year and
|
|
463
|
+
verification has to stay a constant amount of memory. */
|
|
464
|
+
let anchor: SegmentAnchorLine | null = null;
|
|
465
|
+
let events = 0;
|
|
466
|
+
let plaintextEvents = 0;
|
|
467
|
+
let accumulator = '';
|
|
468
|
+
let previousHash: string | null | undefined;
|
|
469
|
+
let lineNumber = 0;
|
|
470
|
+
const reader = createInterface({
|
|
471
|
+
input: createReadStream(path, { encoding: 'utf8' }),
|
|
472
|
+
crlfDelay: Number.POSITIVE_INFINITY,
|
|
473
|
+
});
|
|
474
|
+
try {
|
|
475
|
+
for await (const raw of reader) {
|
|
476
|
+
lineNumber += 1;
|
|
477
|
+
if (raw.trim() === '') continue;
|
|
478
|
+
if (lineNumber === 1) {
|
|
479
|
+
anchor = parseAnchorLine(raw);
|
|
480
|
+
if (!anchor) break;
|
|
481
|
+
accumulator = anchor.previousAnchorHash ?? '';
|
|
482
|
+
previousHash = anchor.fromSequence > 1 ? undefined : null;
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
if (failures.length > 0) break;
|
|
486
|
+
const event = parseEventLine(raw);
|
|
487
|
+
if (!event) {
|
|
488
|
+
failures.push(`Line ${lineNumber} of ${name} is not an audit event.`);
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
if (storedAuditEventHash(event) !== event.eventHash) {
|
|
492
|
+
failures.push(
|
|
493
|
+
`Line ${lineNumber} of ${name} (sequence ${event.sequence}) does not match its own hash.`,
|
|
494
|
+
);
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
if (previousHash !== undefined && event.previousHash !== previousHash) {
|
|
498
|
+
failures.push(
|
|
499
|
+
`Line ${lineNumber} of ${name} (sequence ${event.sequence}) does not link to the event before it.`,
|
|
500
|
+
);
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
previousHash = event.eventHash;
|
|
504
|
+
/* A row that names its format was written by a build that seals a
|
|
505
|
+
person's fields, so one without a sealed payload is an event
|
|
506
|
+
about nobody. Only a row from before the marker existed can be a
|
|
507
|
+
person left in the clear. */
|
|
508
|
+
if (event.sealedPayload === null && !event.sealFormat) {
|
|
509
|
+
plaintextEvents += 1;
|
|
510
|
+
}
|
|
511
|
+
accumulator = chainStep(accumulator, event.eventHash);
|
|
512
|
+
events += 1;
|
|
513
|
+
}
|
|
514
|
+
} finally {
|
|
515
|
+
reader.close();
|
|
516
|
+
}
|
|
517
|
+
if (!anchor) {
|
|
518
|
+
return {
|
|
519
|
+
file: name,
|
|
520
|
+
ok: false,
|
|
521
|
+
anchorSequence: null,
|
|
522
|
+
fromSequence: null,
|
|
523
|
+
toSequence: null,
|
|
524
|
+
events: 0,
|
|
525
|
+
plaintextEvents: 0,
|
|
526
|
+
signatureKeyId: null,
|
|
527
|
+
failures: [`${name} does not start with a segment anchor.`],
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
/* Read after the whole file, because the anchor line is what names the
|
|
531
|
+
workspace. Another workspace's segments carry another name prefix and
|
|
532
|
+
were never opened here, so a file this pass did read and that names
|
|
533
|
+
somebody else is a rewritten anchor, not a foreign file. The anchor it
|
|
534
|
+
claims is also reported missing from the directory, which is what it
|
|
535
|
+
now is. */
|
|
536
|
+
if (anchor.tenantId !== tenantId) {
|
|
537
|
+
return {
|
|
538
|
+
file: name,
|
|
539
|
+
ok: false,
|
|
540
|
+
anchorSequence: anchor.anchorSequence,
|
|
541
|
+
fromSequence: anchor.fromSequence,
|
|
542
|
+
toSequence: anchor.toSequence,
|
|
543
|
+
events,
|
|
544
|
+
plaintextEvents,
|
|
545
|
+
signatureKeyId: anchor.keyId,
|
|
546
|
+
failures: [
|
|
547
|
+
...failures,
|
|
548
|
+
`${name} is named after this workspace and its anchor names ${anchor.tenantId}.`,
|
|
549
|
+
],
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
if (failures.length === 0 && events !== anchor.rowCount) {
|
|
553
|
+
failures.push(
|
|
554
|
+
`${name} holds ${events} events and its anchor claims ${anchor.rowCount}.`,
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
if (failures.length === 0 && accumulator !== anchor.segmentHash) {
|
|
558
|
+
failures.push(`The segment hash of ${name} does not match its anchor.`);
|
|
559
|
+
}
|
|
560
|
+
const expectedAnchorHash = anchorHashOf(anchor);
|
|
561
|
+
if (expectedAnchorHash !== anchor.anchorHash) {
|
|
562
|
+
failures.push(`The anchor of ${name} does not match its own hash.`);
|
|
563
|
+
}
|
|
564
|
+
if (
|
|
565
|
+
!this.#signer.verify(anchor.anchorHash, anchor.signature, anchor.keyId)
|
|
566
|
+
) {
|
|
567
|
+
failures.push(
|
|
568
|
+
`The anchor signature of ${name} does not verify under key ${anchor.keyId}.`,
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
const stored = recorded.get(anchor.anchorSequence);
|
|
572
|
+
if (!stored) {
|
|
573
|
+
failures.push(
|
|
574
|
+
`The workspace records no anchor ${anchor.anchorSequence} for ${name}.`,
|
|
575
|
+
);
|
|
576
|
+
} else if (stored.anchorHash !== anchor.anchorHash) {
|
|
577
|
+
failures.push(
|
|
578
|
+
`The anchor of ${name} differs from the one the workspace recorded.`,
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
if (seen.has(anchor.anchorSequence)) {
|
|
582
|
+
failures.push(`Two segment files claim anchor ${anchor.anchorSequence}.`);
|
|
583
|
+
} else {
|
|
584
|
+
seen.set(anchor.anchorSequence, anchor);
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
file: name,
|
|
588
|
+
ok: failures.length === 0,
|
|
589
|
+
anchorSequence: anchor.anchorSequence,
|
|
590
|
+
fromSequence: anchor.fromSequence,
|
|
591
|
+
toSequence: anchor.toSequence,
|
|
592
|
+
events,
|
|
593
|
+
plaintextEvents,
|
|
594
|
+
signatureKeyId: anchor.keyId,
|
|
595
|
+
failures,
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
async #write(
|
|
600
|
+
directory: string,
|
|
601
|
+
segmentFile: string,
|
|
602
|
+
tenantId: string,
|
|
603
|
+
plan: SealPlan,
|
|
604
|
+
anchorLine: SegmentAnchorLine,
|
|
605
|
+
): Promise<string> {
|
|
606
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
607
|
+
const path = resolve(directory, segmentFile);
|
|
608
|
+
/* A previous run that died left a partial file at this name; it belonged
|
|
609
|
+
to no anchor, so it is this run's to replace. */
|
|
610
|
+
await rm(path, { force: true });
|
|
611
|
+
const handle = await open(path, 'wx', 0o600);
|
|
612
|
+
try {
|
|
613
|
+
await handle.write(`${JSON.stringify(anchorLine)}\n`);
|
|
614
|
+
await this.#walk(
|
|
615
|
+
tenantId,
|
|
616
|
+
plan.previousAnchor?.toSequence ?? 0,
|
|
617
|
+
async (event) => {
|
|
618
|
+
if (event.sequence > plan.toSequence) return false;
|
|
619
|
+
await handle.write(
|
|
620
|
+
`${JSON.stringify({ kind: 'event', ...event })}\n`,
|
|
621
|
+
);
|
|
622
|
+
return true;
|
|
623
|
+
},
|
|
624
|
+
);
|
|
625
|
+
await handle.close();
|
|
626
|
+
return path;
|
|
627
|
+
} catch (error) {
|
|
628
|
+
/* A segment is complete or it does not exist: a half-written file
|
|
629
|
+
would be read as the workspace's evidence. */
|
|
630
|
+
await handle.close().catch(() => undefined);
|
|
631
|
+
await rm(path, { force: true });
|
|
632
|
+
throw error;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/** Answers false when `visit` stopped the walk before the last event. */
|
|
637
|
+
async #walk(
|
|
638
|
+
tenantId: string,
|
|
639
|
+
afterSequence: number,
|
|
640
|
+
visit: (event: StoredAuditEvent) => boolean | Promise<boolean>,
|
|
641
|
+
): Promise<boolean> {
|
|
642
|
+
let cursor = afterSequence;
|
|
643
|
+
for (;;) {
|
|
644
|
+
const page = await this.#repository.sealAuditEventsPage(
|
|
645
|
+
tenantId,
|
|
646
|
+
cursor,
|
|
647
|
+
SEAL_LIMITS.page,
|
|
648
|
+
);
|
|
649
|
+
for (const event of page) {
|
|
650
|
+
cursor = event.sequence;
|
|
651
|
+
if (!(await visit(event))) return false;
|
|
652
|
+
}
|
|
653
|
+
if (page.length < SEAL_LIMITS.page) return true;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
#directory(requested: string): string {
|
|
658
|
+
return exportOutputDirectory({
|
|
659
|
+
environment: this.#environment,
|
|
660
|
+
workspaceRoot: this.#workspaceRoot,
|
|
661
|
+
requested,
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function chainFailuresOf(
|
|
667
|
+
seen: ReadonlyMap<number, SegmentAnchorLine>,
|
|
668
|
+
recorded: ReadonlyMap<number, AuditChainAnchor>,
|
|
669
|
+
): readonly string[] {
|
|
670
|
+
const failures: string[] = [];
|
|
671
|
+
const ordered = [...seen.keys()].sort((left, right) => left - right);
|
|
672
|
+
let previous: SegmentAnchorLine | null = null;
|
|
673
|
+
for (const sequence of ordered) {
|
|
674
|
+
const anchor = seen.get(sequence)!;
|
|
675
|
+
const expected = previous?.anchorHash ?? null;
|
|
676
|
+
/* The first anchor a directory holds need not be anchor one: an operator
|
|
677
|
+
may verify a directory that carries only the newest segments, and the
|
|
678
|
+
recorded anchors are what prove the anchors before it existed. */
|
|
679
|
+
if (previous && anchor.previousAnchorHash !== expected) {
|
|
680
|
+
failures.push(
|
|
681
|
+
`Anchor ${sequence} does not link to anchor ${previous.anchorSequence}.`,
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
if (previous && anchor.anchorSequence !== previous.anchorSequence + 1) {
|
|
685
|
+
failures.push(
|
|
686
|
+
`Anchor ${sequence} follows anchor ${previous.anchorSequence}, so a segment is missing from this directory.`,
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
if (previous && anchor.fromSequence !== previous.toSequence + 1) {
|
|
690
|
+
failures.push(
|
|
691
|
+
`Anchor ${sequence} starts at sequence ${anchor.fromSequence} and anchor ${previous.anchorSequence} ended at ${previous.toSequence}.`,
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
previous = anchor;
|
|
695
|
+
}
|
|
696
|
+
if (ordered.length === 0) {
|
|
697
|
+
if (recorded.size > 0) {
|
|
698
|
+
failures.push(
|
|
699
|
+
`This workspace records ${recorded.size} anchors and the directory holds no segment for any of them.`,
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
return failures;
|
|
703
|
+
}
|
|
704
|
+
/* A directory may begin above anchor one, because an operator may verify one
|
|
705
|
+
holding only the newest segments. It may not end below the newest recorded
|
|
706
|
+
anchor and it may not skip one inside the range it does hold: either is a
|
|
707
|
+
segment file that is gone, which the links between the files it still
|
|
708
|
+
holds cannot show. */
|
|
709
|
+
const lowest = ordered[0]!;
|
|
710
|
+
for (const sequence of [...recorded.keys()].sort(
|
|
711
|
+
(left, right) => left - right,
|
|
712
|
+
)) {
|
|
713
|
+
if (sequence < lowest || seen.has(sequence)) continue;
|
|
714
|
+
failures.push(
|
|
715
|
+
`This workspace records anchor ${sequence} and the directory holds no segment for it.`,
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
return failures;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
function parseAnchorLine(line: string): SegmentAnchorLine | null {
|
|
722
|
+
try {
|
|
723
|
+
const parsed = JSON.parse(line) as SegmentAnchorLine;
|
|
724
|
+
return parsed?.kind === 'anchor' &&
|
|
725
|
+
parsed.formatVersion === SEGMENT_FORMAT_VERSION &&
|
|
726
|
+
typeof parsed.anchorHash === 'string' &&
|
|
727
|
+
typeof parsed.segmentHash === 'string' &&
|
|
728
|
+
typeof parsed.signature === 'string' &&
|
|
729
|
+
typeof parsed.keyId === 'string' &&
|
|
730
|
+
Number.isSafeInteger(parsed.anchorSequence) &&
|
|
731
|
+
Number.isSafeInteger(parsed.fromSequence) &&
|
|
732
|
+
Number.isSafeInteger(parsed.toSequence) &&
|
|
733
|
+
Number.isSafeInteger(parsed.rowCount)
|
|
734
|
+
? parsed
|
|
735
|
+
: null;
|
|
736
|
+
} catch {
|
|
737
|
+
return null;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
function parseEventLine(line: string): StoredAuditEvent | null {
|
|
742
|
+
try {
|
|
743
|
+
const parsed = JSON.parse(line) as SegmentEventLine;
|
|
744
|
+
return parsed?.kind === 'event' &&
|
|
745
|
+
typeof parsed.id === 'string' &&
|
|
746
|
+
typeof parsed.eventHash === 'string' &&
|
|
747
|
+
Number.isSafeInteger(parsed.sequence)
|
|
748
|
+
? parsed
|
|
749
|
+
: null;
|
|
750
|
+
} catch {
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* What every segment file of one workspace is named after. The trailing
|
|
757
|
+
* separator is load bearing: without it the prefix of one workspace would also
|
|
758
|
+
* select the files of another whose id starts with the same characters.
|
|
759
|
+
*/
|
|
760
|
+
export function segmentNamePrefix(tenantId: string): string {
|
|
761
|
+
return `audit-segment-${tenantId.replaceAll(/[^A-Za-z0-9_-]/g, '-').slice(0, 64)}-`;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
/* The sequence range is part of the name, so a directory listing reads as the
|
|
765
|
+
chain it holds and two segments can never collide. */
|
|
766
|
+
function segmentName(tenantId: string, from: number, to: number): string {
|
|
767
|
+
const pad = (value: number) => String(value).padStart(12, '0');
|
|
768
|
+
return `${segmentNamePrefix(tenantId)}${pad(from)}-${pad(to)}.jsonl`;
|
|
769
|
+
}
|