primitive-admin 1.2.0-alpha.1 → 1.2.0-alpha.10
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/README.md +105 -134
- package/assets/skill/skills/primitive-platform/SKILL.md +37 -4
- package/dist/bin/primitive.js +30 -35
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/agent-sessions.d.ts +133 -0
- package/dist/src/commands/agent-sessions.js +792 -0
- package/dist/src/commands/agent-sessions.js.map +1 -0
- package/dist/src/commands/analytics.js +0 -148
- package/dist/src/commands/analytics.js.map +1 -1
- package/dist/src/commands/apps-children.d.ts +54 -0
- package/dist/src/commands/apps-children.js +631 -0
- package/dist/src/commands/apps-children.js.map +1 -0
- package/dist/src/commands/apps.d.ts +6 -0
- package/dist/src/commands/apps.js +131 -9
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/auth-sessions.d.ts +3 -3
- package/dist/src/commands/auth-sessions.js +117 -23
- package/dist/src/commands/auth-sessions.js.map +1 -1
- package/dist/src/commands/auth.js +460 -36
- package/dist/src/commands/auth.js.map +1 -1
- package/dist/src/commands/collections.js +316 -256
- package/dist/src/commands/collections.js.map +1 -1
- package/dist/src/commands/config.d.ts +1 -1
- package/dist/src/commands/config.js +60 -28
- package/dist/src/commands/config.js.map +1 -1
- package/dist/src/commands/connections.js +11 -12
- package/dist/src/commands/connections.js.map +1 -1
- package/dist/src/commands/database-type-configs.js +2 -76
- package/dist/src/commands/database-type-configs.js.map +1 -1
- package/dist/src/commands/databases.d.ts +9 -0
- package/dist/src/commands/databases.js +221 -457
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/db3-types.d.ts +15 -0
- package/dist/src/commands/db3-types.js +157 -0
- package/dist/src/commands/db3-types.js.map +1 -0
- package/dist/src/commands/db3.d.ts +12 -0
- package/dist/src/commands/db3.js +1052 -0
- package/dist/src/commands/db3.js.map +1 -0
- package/dist/src/commands/documents.d.ts +121 -2
- package/dist/src/commands/documents.js +1601 -1251
- package/dist/src/commands/documents.js.map +1 -1
- package/dist/src/commands/env.d.ts +9 -1
- package/dist/src/commands/env.js +164 -49
- package/dist/src/commands/env.js.map +1 -1
- package/dist/src/commands/function-trigger-commands.d.ts +28 -0
- package/dist/src/commands/function-trigger-commands.js +341 -0
- package/dist/src/commands/function-trigger-commands.js.map +1 -0
- package/dist/src/commands/functions.js +297 -24
- package/dist/src/commands/functions.js.map +1 -1
- package/dist/src/commands/groups.js +150 -49
- package/dist/src/commands/groups.js.map +1 -1
- package/dist/src/commands/guides.js +5 -5
- package/dist/src/commands/init.d.ts +7 -0
- package/dist/src/commands/init.js +23 -5
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/integrations.js +14 -8
- package/dist/src/commands/integrations.js.map +1 -1
- package/dist/src/commands/metadata-category-configs.d.ts +2 -2
- package/dist/src/commands/metadata-category-configs.js +2 -2
- package/dist/src/commands/prompts.d.ts +7 -0
- package/dist/src/commands/prompts.js +48 -5
- package/dist/src/commands/prompts.js.map +1 -1
- package/dist/src/commands/scripts.d.ts +9 -17
- package/dist/src/commands/scripts.js +24 -479
- package/dist/src/commands/scripts.js.map +1 -1
- package/dist/src/commands/sync-app-settings.d.ts +36 -8
- package/dist/src/commands/sync-app-settings.js +109 -23
- package/dist/src/commands/sync-app-settings.js.map +1 -1
- package/dist/src/commands/sync.d.ts +360 -610
- package/dist/src/commands/sync.js +3151 -6697
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/tokens.js +3 -3
- package/dist/src/commands/tokens.js.map +1 -1
- package/dist/src/commands/users.js +77 -2
- package/dist/src/commands/users.js.map +1 -1
- package/dist/src/commands/workflows.d.ts +5 -83
- package/dist/src/commands/workflows.js +57 -2282
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/aggregate-output.d.ts +25 -0
- package/dist/src/lib/aggregate-output.js +53 -0
- package/dist/src/lib/aggregate-output.js.map +1 -0
- package/dist/src/lib/api-client.d.ts +681 -551
- package/dist/src/lib/api-client.js +880 -814
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/app-settings-descriptor.d.ts +47 -1
- package/dist/src/lib/app-settings-descriptor.js +114 -10
- package/dist/src/lib/app-settings-descriptor.js.map +1 -1
- package/dist/src/lib/auth-fixtures.d.ts +44 -0
- package/dist/src/lib/auth-fixtures.js +61 -0
- package/dist/src/lib/auth-fixtures.js.map +1 -0
- package/dist/src/lib/auth-flow.d.ts +41 -1
- package/dist/src/lib/auth-flow.js +70 -16
- package/dist/src/lib/auth-flow.js.map +1 -1
- package/dist/src/lib/block-layout.d.ts +12 -23
- package/dist/src/lib/block-layout.js +26 -92
- package/dist/src/lib/block-layout.js.map +1 -1
- package/dist/src/lib/block-selector.d.ts +2 -2
- package/dist/src/lib/block-selector.js +2 -2
- package/dist/src/lib/child-apps-local.d.ts +164 -0
- package/dist/src/lib/child-apps-local.js +258 -0
- package/dist/src/lib/child-apps-local.js.map +1 -0
- package/dist/src/lib/ci-session-request.d.ts +22 -0
- package/dist/src/lib/ci-session-request.js +51 -0
- package/dist/src/lib/ci-session-request.js.map +1 -0
- package/dist/src/lib/codegen-shared/generatedFiles.d.ts +10 -8
- package/dist/src/lib/codegen-shared/generatedFiles.js +21 -15
- package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -1
- package/dist/src/lib/codegen-shared/prettierStable.d.ts +1 -1
- package/dist/src/lib/codegen-shared/prettierStable.js +1 -1
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +2 -2
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +2 -2
- package/dist/src/lib/collection-export.d.ts +76 -15
- package/dist/src/lib/collection-export.js +116 -23
- package/dist/src/lib/collection-export.js.map +1 -1
- package/dist/src/lib/collection-principal.d.ts +22 -0
- package/dist/src/lib/collection-principal.js +35 -0
- package/dist/src/lib/collection-principal.js.map +1 -0
- package/dist/src/lib/config-object-descriptor.d.ts +3 -22
- package/dist/src/lib/config-object-descriptor.js +56 -290
- package/dist/src/lib/config-object-descriptor.js.map +1 -1
- package/dist/src/lib/config-payload.js +2 -3
- package/dist/src/lib/config-payload.js.map +1 -1
- package/dist/src/lib/config-surface.d.ts +5 -7
- package/dist/src/lib/config-surface.js +18 -40
- package/dist/src/lib/config-surface.js.map +1 -1
- package/dist/src/lib/connections-list.d.ts +10 -0
- package/dist/src/lib/connections-list.js +18 -0
- package/dist/src/lib/connections-list.js.map +1 -0
- package/dist/src/lib/credentials-home.d.ts +58 -0
- package/dist/src/lib/credentials-home.js +204 -0
- package/dist/src/lib/credentials-home.js.map +1 -0
- package/dist/src/lib/credentials-lock.d.ts +88 -0
- package/dist/src/lib/credentials-lock.js +302 -0
- package/dist/src/lib/credentials-lock.js.map +1 -0
- package/dist/src/lib/credentials-store.d.ts +179 -24
- package/dist/src/lib/credentials-store.js +712 -77
- package/dist/src/lib/credentials-store.js.map +1 -1
- package/dist/src/lib/csv.d.ts +8 -9
- package/dist/src/lib/csv.js +3 -4
- package/dist/src/lib/csv.js.map +1 -1
- package/dist/src/lib/custodian.d.ts +8 -0
- package/dist/src/lib/custodian.js +18 -0
- package/dist/src/lib/custodian.js.map +1 -0
- package/dist/src/lib/db-codegen/dbGenerator.js +5 -16
- package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -1
- package/dist/src/lib/db-codegen/dbNaming.d.ts +5 -13
- package/dist/src/lib/db-codegen/dbNaming.js +5 -17
- package/dist/src/lib/db-codegen/dbNaming.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTemplates.d.ts +7 -56
- package/dist/src/lib/db-codegen/dbTemplates.js +25 -125
- package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTsTypes.d.ts +2 -2
- package/dist/src/lib/db-codegen/dbTsTypes.js +2 -2
- package/dist/src/lib/db-codegen/dbTypeIR.d.ts +67 -2
- package/dist/src/lib/db-codegen/dbTypeIR.js +13 -2
- package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -1
- package/dist/src/lib/db3-export.d.ts +231 -0
- package/dist/src/lib/db3-export.js +510 -0
- package/dist/src/lib/db3-export.js.map +1 -0
- package/dist/src/lib/db3-index-output.d.ts +27 -0
- package/dist/src/lib/db3-index-output.js +49 -0
- package/dist/src/lib/db3-index-output.js.map +1 -0
- package/dist/src/lib/document-export-lookups.d.ts +31 -0
- package/dist/src/lib/document-export-lookups.js +53 -0
- package/dist/src/lib/document-export-lookups.js.map +1 -0
- package/dist/src/lib/document-export-permissions.d.ts +7 -5
- package/dist/src/lib/document-export-permissions.js +7 -5
- package/dist/src/lib/document-export-permissions.js.map +1 -1
- package/dist/src/lib/document-export-record-log.d.ts +57 -0
- package/dist/src/lib/document-export-record-log.js +215 -0
- package/dist/src/lib/document-export-record-log.js.map +1 -0
- package/dist/src/lib/document-ingest-artifact.d.ts +26 -2
- package/dist/src/lib/document-ingest-artifact.js +42 -8
- package/dist/src/lib/document-ingest-artifact.js.map +1 -1
- package/dist/src/lib/document-ingest-format2.d.ts +36 -0
- package/dist/src/lib/document-ingest-format2.js +78 -0
- package/dist/src/lib/document-ingest-format2.js.map +1 -0
- package/dist/src/lib/document-ingest-input.d.ts +9 -0
- package/dist/src/lib/document-ingest-input.js +28 -1
- package/dist/src/lib/document-ingest-input.js.map +1 -1
- package/dist/src/lib/document-ingest-rows.d.ts +16 -0
- package/dist/src/lib/document-ingest-rows.js +17 -0
- package/dist/src/lib/document-ingest-rows.js.map +1 -1
- package/dist/src/lib/document-ingest.d.ts +33 -1
- package/dist/src/lib/document-ingest.js +49 -0
- package/dist/src/lib/document-ingest.js.map +1 -1
- package/dist/src/lib/document-schema-rows.d.ts +42 -0
- package/dist/src/lib/document-schema-rows.js +53 -0
- package/dist/src/lib/document-schema-rows.js.map +1 -0
- package/dist/src/lib/env-resolver-core.d.ts +70 -2
- package/dist/src/lib/env-resolver-core.js +137 -20
- package/dist/src/lib/env-resolver-core.js.map +1 -1
- package/dist/src/lib/env-resolver.d.ts +14 -2
- package/dist/src/lib/env-resolver.js +32 -10
- package/dist/src/lib/env-resolver.js.map +1 -1
- package/dist/src/lib/function-authorize-check.d.ts +142 -0
- package/dist/src/lib/function-authorize-check.js +310 -0
- package/dist/src/lib/function-authorize-check.js.map +1 -0
- package/dist/src/lib/function-authorize-view.d.ts +15 -0
- package/dist/src/lib/function-authorize-view.js +50 -0
- package/dist/src/lib/function-authorize-view.js.map +1 -0
- package/dist/src/lib/function-bundle.d.ts +38 -18
- package/dist/src/lib/function-bundle.js +96 -35
- package/dist/src/lib/function-bundle.js.map +1 -1
- package/dist/src/lib/function-collect.d.ts +75 -12
- package/dist/src/lib/function-collect.js +427 -12
- package/dist/src/lib/function-collect.js.map +1 -1
- package/dist/src/lib/function-db-types.d.ts +29 -0
- package/dist/src/lib/function-db-types.js +117 -7
- package/dist/src/lib/function-db-types.js.map +1 -1
- package/dist/src/lib/function-document-types.d.ts +5 -3
- package/dist/src/lib/function-document-types.js +10 -14
- package/dist/src/lib/function-document-types.js.map +1 -1
- package/dist/src/lib/function-lint.d.ts +34 -0
- package/dist/src/lib/function-lint.js +112 -0
- package/dist/src/lib/function-lint.js.map +1 -0
- package/dist/src/lib/function-log-row.js +21 -2
- package/dist/src/lib/function-log-row.js.map +1 -1
- package/dist/src/lib/function-run.d.ts +16 -21
- package/dist/src/lib/function-run.js +37 -30
- package/dist/src/lib/function-run.js.map +1 -1
- package/dist/src/lib/function-schema-codegen.d.ts +1 -1
- package/dist/src/lib/function-schema-codegen.js +5 -5
- package/dist/src/lib/function-schema-codegen.js.map +1 -1
- package/dist/src/lib/function-source-roots.d.ts +67 -0
- package/dist/src/lib/function-source-roots.js +148 -0
- package/dist/src/lib/function-source-roots.js.map +1 -0
- package/dist/src/lib/function-sync.d.ts +108 -22
- package/dist/src/lib/function-sync.js +127 -39
- package/dist/src/lib/function-sync.js.map +1 -1
- package/dist/src/lib/function-trigger-listing.d.ts +11 -6
- package/dist/src/lib/function-trigger-listing.js +32 -11
- package/dist/src/lib/function-trigger-listing.js.map +1 -1
- package/dist/src/lib/function-typecheck.d.ts +37 -2
- package/dist/src/lib/function-typecheck.js +210 -28
- package/dist/src/lib/function-typecheck.js.map +1 -1
- package/dist/src/lib/function-versions.d.ts +2 -0
- package/dist/src/lib/function-versions.js +1 -0
- package/dist/src/lib/function-versions.js.map +1 -1
- package/dist/src/lib/generated-allowlist.js +0 -20
- package/dist/src/lib/generated-allowlist.js.map +1 -1
- package/dist/src/lib/generated-config-surfaces.d.ts +703 -203
- package/dist/src/lib/generated-config-surfaces.js +2270 -2014
- package/dist/src/lib/generated-config-surfaces.js.map +1 -1
- package/dist/src/lib/generated-sdk-types.d.ts +1 -1
- package/dist/src/lib/generated-sdk-types.js +1 -1
- package/dist/src/lib/generated-sdk-types.js.map +1 -1
- package/dist/src/lib/init-adopt.js +12 -3
- package/dist/src/lib/init-adopt.js.map +1 -1
- package/dist/src/lib/init-login-note.d.ts +13 -0
- package/dist/src/lib/init-login-note.js +22 -0
- package/dist/src/lib/init-login-note.js.map +1 -0
- package/dist/src/lib/json-value.d.ts +6 -0
- package/dist/src/lib/json-value.js +13 -0
- package/dist/src/lib/json-value.js.map +1 -0
- package/dist/src/lib/load-routes.d.ts +33 -0
- package/dist/src/lib/load-routes.js +35 -0
- package/dist/src/lib/load-routes.js.map +1 -0
- package/dist/src/lib/local-state.d.ts +38 -7
- package/dist/src/lib/local-state.js +172 -49
- package/dist/src/lib/local-state.js.map +1 -1
- package/dist/src/lib/local-test-cases.d.ts +5 -2
- package/dist/src/lib/local-test-cases.js +7 -4
- package/dist/src/lib/local-test-cases.js.map +1 -1
- package/dist/src/lib/log-inspection.d.ts +42 -4
- package/dist/src/lib/log-inspection.js +37 -5
- package/dist/src/lib/log-inspection.js.map +1 -1
- package/dist/src/lib/login-exchange-check.d.ts +18 -0
- package/dist/src/lib/login-exchange-check.js +27 -0
- package/dist/src/lib/login-exchange-check.js.map +1 -0
- package/dist/src/lib/login-scope-lines.d.ts +25 -0
- package/dist/src/lib/login-scope-lines.js +45 -0
- package/dist/src/lib/login-scope-lines.js.map +1 -0
- package/dist/src/lib/logout-admin-session.d.ts +2 -1
- package/dist/src/lib/logout-admin-session.js +7 -1
- package/dist/src/lib/logout-admin-session.js.map +1 -1
- package/dist/src/lib/object-status-filter.d.ts +9 -1
- package/dist/src/lib/object-status-filter.js +9 -1
- package/dist/src/lib/object-status-filter.js.map +1 -1
- package/dist/src/lib/output.js +2 -0
- package/dist/src/lib/output.js.map +1 -1
- package/dist/src/lib/paginate.d.ts +0 -5
- package/dist/src/lib/paginate.js +0 -5
- package/dist/src/lib/paginate.js.map +1 -1
- package/dist/src/lib/pin-refusal-hint.d.ts +12 -0
- package/dist/src/lib/pin-refusal-hint.js +35 -0
- package/dist/src/lib/pin-refusal-hint.js.map +1 -0
- package/dist/src/lib/primitive-env-plugin.d.ts +99 -0
- package/dist/src/lib/primitive-env-plugin.js +408 -0
- package/dist/src/lib/primitive-env-plugin.js.map +1 -0
- package/dist/src/lib/project-config.d.ts +7 -0
- package/dist/src/lib/project-config.js +22 -1
- package/dist/src/lib/project-config.js.map +1 -1
- package/dist/src/lib/project-login-apps.d.ts +8 -0
- package/dist/src/lib/project-login-apps.js +27 -0
- package/dist/src/lib/project-login-apps.js.map +1 -0
- package/dist/src/lib/prompt-schema-codegen.d.ts +10 -3
- package/dist/src/lib/prompt-schema-codegen.js +52 -11
- package/dist/src/lib/prompt-schema-codegen.js.map +1 -1
- package/dist/src/lib/pull-write.d.ts +31 -0
- package/dist/src/lib/pull-write.js +49 -0
- package/dist/src/lib/pull-write.js.map +1 -0
- package/dist/src/lib/push-failure-report.d.ts +45 -0
- package/dist/src/lib/push-failure-report.js +57 -0
- package/dist/src/lib/push-failure-report.js.map +1 -0
- package/dist/src/lib/records-verbs.d.ts +69 -0
- package/dist/src/lib/records-verbs.js +40 -0
- package/dist/src/lib/records-verbs.js.map +1 -0
- package/dist/src/lib/refresh-admin-credentials.d.ts +7 -0
- package/dist/src/lib/refresh-admin-credentials.js +16 -4
- package/dist/src/lib/refresh-admin-credentials.js.map +1 -1
- package/dist/src/lib/root-import-decision.d.ts +65 -0
- package/dist/src/lib/root-import-decision.js +109 -0
- package/dist/src/lib/root-import-decision.js.map +1 -0
- package/dist/src/lib/run-status.d.ts +1 -1
- package/dist/src/lib/run-status.generated.d.ts +2 -2
- package/dist/src/lib/run-status.generated.js +3 -1
- package/dist/src/lib/run-status.generated.js.map +1 -1
- package/dist/src/lib/run-status.js +1 -1
- package/dist/src/lib/schema-codegen/generated-schema-descriptor.d.ts +129 -0
- package/dist/src/lib/schema-codegen/generated-schema-descriptor.js +269 -0
- package/dist/src/lib/schema-codegen/generated-schema-descriptor.js.map +1 -0
- package/dist/src/lib/schema-codegen/naming.d.ts +35 -0
- package/dist/src/lib/schema-codegen/naming.js +83 -0
- package/dist/src/lib/schema-codegen/naming.js.map +1 -0
- package/dist/src/lib/schema-codegen/schemaToTs.d.ts +82 -0
- package/dist/src/lib/schema-codegen/schemaToTs.js +305 -0
- package/dist/src/lib/schema-codegen/schemaToTs.js.map +1 -0
- package/dist/src/lib/scope-request.d.ts +84 -0
- package/dist/src/lib/scope-request.js +235 -0
- package/dist/src/lib/scope-request.js.map +1 -0
- package/dist/src/lib/session-id.d.ts +9 -0
- package/dist/src/lib/session-id.js +28 -0
- package/dist/src/lib/session-id.js.map +1 -0
- package/dist/src/lib/snapshot-build-rows.d.ts +21 -0
- package/dist/src/lib/snapshot-build-rows.js +22 -0
- package/dist/src/lib/snapshot-build-rows.js.map +1 -1
- package/dist/src/lib/snapshot-build.js +8 -3
- package/dist/src/lib/snapshot-build.js.map +1 -1
- package/dist/src/lib/snapshots.d.ts +17 -1
- package/dist/src/lib/snapshots.js +50 -2
- package/dist/src/lib/snapshots.js.map +1 -1
- package/dist/src/lib/swift-codegen/agentGenerator.d.ts +6 -2
- package/dist/src/lib/swift-codegen/agentGenerator.js +57 -5
- package/dist/src/lib/swift-codegen/agentGenerator.js.map +1 -1
- package/dist/src/lib/swift-codegen/banners.d.ts +34 -7
- package/dist/src/lib/swift-codegen/banners.js +37 -7
- package/dist/src/lib/swift-codegen/banners.js.map +1 -1
- package/dist/src/lib/swift-codegen/dbGenerator.d.ts +4 -3
- package/dist/src/lib/swift-codegen/dbGenerator.js +14 -117
- package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -1
- package/dist/src/lib/swift-codegen/functionGenerator.d.ts +3 -3
- package/dist/src/lib/swift-codegen/functionGenerator.js +23 -18
- package/dist/src/lib/swift-codegen/functionGenerator.js.map +1 -1
- package/dist/src/lib/swift-codegen/generator.d.ts +5 -5
- package/dist/src/lib/swift-codegen/generator.js +35 -40
- package/dist/src/lib/swift-codegen/generator.js.map +1 -1
- package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +3 -3
- package/dist/src/lib/swift-codegen/schemaToSwift.js +4 -4
- package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -1
- package/dist/src/lib/swift-codegen/swiftKeys.d.ts +19 -0
- package/dist/src/lib/swift-codegen/swiftKeys.js +31 -0
- package/dist/src/lib/swift-codegen/swiftKeys.js.map +1 -0
- package/dist/src/lib/sync-paths.d.ts +35 -0
- package/dist/src/lib/sync-paths.js +57 -5
- package/dist/src/lib/sync-paths.js.map +1 -1
- package/dist/src/lib/sync-resource-types.d.ts +26 -26
- package/dist/src/lib/sync-resource-types.js +61 -189
- package/dist/src/lib/sync-resource-types.js.map +1 -1
- package/dist/src/lib/sync-selectors.d.ts +5 -1
- package/dist/src/lib/sync-selectors.js +23 -13
- package/dist/src/lib/sync-selectors.js.map +1 -1
- package/dist/src/lib/test-case-file-names.d.ts +3 -5
- package/dist/src/lib/test-case-file-names.js +3 -5
- package/dist/src/lib/test-case-file-names.js.map +1 -1
- package/dist/src/lib/toml-database-config.d.ts +15 -75
- package/dist/src/lib/toml-database-config.js +17 -306
- package/dist/src/lib/toml-database-config.js.map +1 -1
- package/dist/src/lib/transient-retry.d.ts +43 -0
- package/dist/src/lib/transient-retry.js +94 -0
- package/dist/src/lib/transient-retry.js.map +1 -0
- package/dist/src/lib/vars-override.d.ts +105 -0
- package/dist/src/lib/vars-override.js +143 -0
- package/dist/src/lib/vars-override.js.map +1 -0
- package/dist/src/lib/webhook-capture.d.ts +43 -0
- package/dist/src/lib/webhook-capture.js +91 -0
- package/dist/src/lib/webhook-capture.js.map +1 -0
- package/dist/src/lib/webhook-deliver.d.ts +18 -20
- package/dist/src/lib/webhook-deliver.js +34 -89
- package/dist/src/lib/webhook-deliver.js.map +1 -1
- package/dist/src/lib/webhook-test-run.d.ts +32 -0
- package/dist/src/lib/webhook-test-run.js +108 -0
- package/dist/src/lib/webhook-test-run.js.map +1 -0
- package/dist/src/lib/workflow-codegen/generator.d.ts +7 -7
- package/dist/src/lib/workflow-codegen/generator.js +16 -23
- package/dist/src/lib/workflow-codegen/generator.js.map +1 -1
- package/dist/src/lib/workflow-codegen/invokerIR.d.ts +6 -12
- package/dist/src/lib/workflow-codegen/invokerIR.js +4 -5
- package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -1
- package/dist/src/lib/workflow-toml-validator.d.ts +2 -0
- package/dist/src/lib/workflow-toml-validator.js +28 -1
- package/dist/src/lib/workflow-toml-validator.js.map +1 -1
- package/dist/src/types/index.d.ts +30 -37
- package/dist/src/validators.d.ts +7 -55
- package/dist/src/validators.js +7 -53
- package/dist/src/validators.js.map +1 -1
- package/dist/src/vite.d.ts +17 -0
- package/dist/src/vite.js +18 -0
- package/dist/src/vite.js.map +1 -0
- package/package.json +20 -12
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The side reads `primitive documents export` makes for each document (#4149):
|
|
3
|
+
* its permissions, its pending invitations, its aliases and its blob list.
|
|
4
|
+
*
|
|
5
|
+
* Each one used to sit in a bare `catch {}`, so a 403, a 429 or a 5xx wrote an
|
|
6
|
+
* empty list and the export reported success. Aliases and blobs are what an
|
|
7
|
+
* import restores, so the loss carried straight into the migrated app. Only a
|
|
8
|
+
* documented "none" answer reads as empty here — a 404, or whatever extra
|
|
9
|
+
* statuses the caller names — exactly as the import's own existence check
|
|
10
|
+
* reads only a 404 as absence. A transient failure is retried through the
|
|
11
|
+
* CLI's shared retry; anything else fails the document.
|
|
12
|
+
*/
|
|
13
|
+
/** Options for {@link readExportLookup}. */
|
|
14
|
+
export interface ExportLookupOptions {
|
|
15
|
+
/** Statuses that mean "the document has none". Defaults to `[404]`. */
|
|
16
|
+
absentStatuses?: readonly number[];
|
|
17
|
+
/** The wait between tries; injectable so a test need not spend it. */
|
|
18
|
+
sleep?: (ms: number) => Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Read one of a document's export lookups, or `null` when it has none.
|
|
22
|
+
*
|
|
23
|
+
* Throws when the read fails with anything other than an absent status, after
|
|
24
|
+
* retrying a transient failure. The error names the document and the lookup,
|
|
25
|
+
* so a caller exporting many documents can report which one is incomplete.
|
|
26
|
+
*
|
|
27
|
+
* @param documentId - The document being exported, named in a failure.
|
|
28
|
+
* @param lookup - What is being read, as an operator reads it ("aliases").
|
|
29
|
+
* @param read - The read itself.
|
|
30
|
+
*/
|
|
31
|
+
export declare function readExportLookup<T>(documentId: string, lookup: string, read: () => Promise<T>, options?: ExportLookupOptions): Promise<T | null>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The side reads `primitive documents export` makes for each document (#4149):
|
|
3
|
+
* its permissions, its pending invitations, its aliases and its blob list.
|
|
4
|
+
*
|
|
5
|
+
* Each one used to sit in a bare `catch {}`, so a 403, a 429 or a 5xx wrote an
|
|
6
|
+
* empty list and the export reported success. Aliases and blobs are what an
|
|
7
|
+
* import restores, so the loss carried straight into the migrated app. Only a
|
|
8
|
+
* documented "none" answer reads as empty here — a 404, or whatever extra
|
|
9
|
+
* statuses the caller names — exactly as the import's own existence check
|
|
10
|
+
* reads only a 404 as absence. A transient failure is retried through the
|
|
11
|
+
* CLI's shared retry; anything else fails the document.
|
|
12
|
+
*/
|
|
13
|
+
import { failureStatus, withTransientRetry } from "./transient-retry.js";
|
|
14
|
+
/** An absent status, carried out of the retry so it is not retried. */
|
|
15
|
+
const ABSENT = Symbol("absent");
|
|
16
|
+
/**
|
|
17
|
+
* Read one of a document's export lookups, or `null` when it has none.
|
|
18
|
+
*
|
|
19
|
+
* Throws when the read fails with anything other than an absent status, after
|
|
20
|
+
* retrying a transient failure. The error names the document and the lookup,
|
|
21
|
+
* so a caller exporting many documents can report which one is incomplete.
|
|
22
|
+
*
|
|
23
|
+
* @param documentId - The document being exported, named in a failure.
|
|
24
|
+
* @param lookup - What is being read, as an operator reads it ("aliases").
|
|
25
|
+
* @param read - The read itself.
|
|
26
|
+
*/
|
|
27
|
+
export async function readExportLookup(documentId, lookup, read, options = {}) {
|
|
28
|
+
const absent = options.absentStatuses ?? [404];
|
|
29
|
+
let attempts = 0;
|
|
30
|
+
try {
|
|
31
|
+
const result = await withTransientRetry(async () => {
|
|
32
|
+
attempts++;
|
|
33
|
+
try {
|
|
34
|
+
return await read();
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
const status = failureStatus(error);
|
|
38
|
+
if (status !== undefined && absent.includes(status))
|
|
39
|
+
return ABSENT;
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}, undefined, undefined, options.sleep);
|
|
43
|
+
return result === ABSENT ? null : result;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
const status = failureStatus(error);
|
|
47
|
+
const reason = `${error?.message || "no reason given"}${status !== undefined ? ` (${status})` : ""}`;
|
|
48
|
+
const tries = attempts > 1 ? ` after ${attempts} attempts` : "";
|
|
49
|
+
throw new Error(`Document ${documentId}: reading its ${lookup} failed${tries} — ` +
|
|
50
|
+
`${reason}. Its export would be incomplete, so it was not exported.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=document-export-lookups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-export-lookups.js","sourceRoot":"","sources":["../../../src/lib/document-export-lookups.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAUzE,uEAAuE;AACvE,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEhC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,UAAkB,EAClB,MAAc,EACd,IAAsB,EACtB,UAA+B,EAAE;IAEjC,MAAM,MAAM,GAAG,OAAO,CAAC,cAAc,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC,KAAK,IAAI,EAAE;YACT,QAAQ,EAAE,CAAC;YACX,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,EAAE,CAAC;YACtB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;gBACpC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAAE,OAAO,MAAM,CAAC;gBACnE,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC,EACD,SAAS,EACT,SAAS,EACT,OAAO,CAAC,KAAK,CACd,CAAC;QACF,OAAO,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,GAAG,KAAK,EAAE,OAAO,IAAI,iBAAiB,GACnD,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,EAC1C,EAAE,CAAC;QACH,MAAM,KAAK,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,QAAQ,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CACb,YAAY,UAAU,iBAAiB,MAAM,UAAU,KAAK,KAAK;YAC/D,GAAG,MAAM,2DAA2D,CACvE,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
* which returns a `{ items }` envelope of deferred grants the server has
|
|
10
10
|
* already filtered down to unresolved, unexpired, still-invited ones.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* An older server answers the pending read with 403 or 404; the caller reads
|
|
13
|
+
* either as "no pending invitations" and passes `null`, and the export still
|
|
14
|
+
* writes the permission rows. Any other failure fails the export (#4149).
|
|
15
15
|
*/
|
|
16
|
+
/** The pending-invitations statuses that mean "none": an older server's 403 or 404. */
|
|
17
|
+
export declare const PENDING_INVITATIONS_ABSENT_STATUSES: readonly number[];
|
|
16
18
|
export interface ExportedPermissionRow {
|
|
17
19
|
email: string;
|
|
18
20
|
permission: string;
|
|
@@ -24,7 +26,7 @@ export interface ExportedPermissionRow {
|
|
|
24
26
|
* Merge a document's permission rows and its pending deferred grants into the
|
|
25
27
|
* single email-keyed list `permissions.json` carries.
|
|
26
28
|
*
|
|
27
|
-
* @param permissionsResponse - `GET /documents/:id/permissions`, or `null` when the
|
|
28
|
-
* @param pendingResponse - `GET /documents/:id/pending-invitations`, or `null` when the
|
|
29
|
+
* @param permissionsResponse - `GET /documents/:id/permissions`, or `null` when the document has none.
|
|
30
|
+
* @param pendingResponse - `GET /documents/:id/pending-invitations`, or `null` when the server has none to report.
|
|
29
31
|
*/
|
|
30
32
|
export declare function buildPermissionsExport(permissionsResponse: unknown, pendingResponse: unknown): ExportedPermissionRow[];
|
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
* which returns a `{ items }` envelope of deferred grants the server has
|
|
10
10
|
* already filtered down to unresolved, unexpired, still-invited ones.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* An older server answers the pending read with 403 or 404; the caller reads
|
|
13
|
+
* either as "no pending invitations" and passes `null`, and the export still
|
|
14
|
+
* writes the permission rows. Any other failure fails the export (#4149).
|
|
15
15
|
*/
|
|
16
|
+
/** The pending-invitations statuses that mean "none": an older server's 403 or 404. */
|
|
17
|
+
export const PENDING_INVITATIONS_ABSENT_STATUSES = [403, 404];
|
|
16
18
|
/** Unwrap a list that may arrive bare, or under `items`, or under a named key. */
|
|
17
19
|
function rows(value, key) {
|
|
18
20
|
if (Array.isArray(value))
|
|
@@ -30,8 +32,8 @@ function rows(value, key) {
|
|
|
30
32
|
* Merge a document's permission rows and its pending deferred grants into the
|
|
31
33
|
* single email-keyed list `permissions.json` carries.
|
|
32
34
|
*
|
|
33
|
-
* @param permissionsResponse - `GET /documents/:id/permissions`, or `null` when the
|
|
34
|
-
* @param pendingResponse - `GET /documents/:id/pending-invitations`, or `null` when the
|
|
35
|
+
* @param permissionsResponse - `GET /documents/:id/permissions`, or `null` when the document has none.
|
|
36
|
+
* @param pendingResponse - `GET /documents/:id/pending-invitations`, or `null` when the server has none to report.
|
|
35
37
|
*/
|
|
36
38
|
export function buildPermissionsExport(permissionsResponse, pendingResponse) {
|
|
37
39
|
const granted = rows(permissionsResponse, "permissions")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-export-permissions.js","sourceRoot":"","sources":["../../../src/lib/document-export-permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"document-export-permissions.js","sourceRoot":"","sources":["../../../src/lib/document-export-permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,uFAAuF;AACvF,MAAM,CAAC,MAAM,mCAAmC,GAAsB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAUjF,kFAAkF;AAClF,SAAS,IAAI,CAAC,KAAc,EAAE,GAAW;IACvC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,KAAgC,CAAC;QAClD,KAAK,MAAM,SAAS,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC;YACvC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;gBAAE,OAAO,QAAQ,CAAC,SAAS,CAAU,CAAC;QAC9E,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CACpC,mBAA4B,EAC5B,eAAwB;IAExB,MAAM,OAAO,GAAG,IAAI,CAAC,mBAAmB,EAAE,aAAa,CAAC;SACrD,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC;SAC5B,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC;QAChB,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,SAAS,EAAE,CAAC,CAAC,SAAS;KACvB,CAAC,CAAC,CAAC;IAEN,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC;SACjD,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC;SAC5B,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC;QAChB,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,MAAM,EAAE,YAAqB;QAC7B,MAAM,EAAE,SAAkB;KAC3B,CAAC,CAAC,CAAC;IAEN,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `documents export` of a record-log (format 3) document (#4310, behavior 24).
|
|
3
|
+
*
|
|
4
|
+
* The document's base is a segment: its row chunks were written across
|
|
5
|
+
* alarms while writes continued, so they are no image of the document at any
|
|
6
|
+
* one log number; its corrections chunk holds every row and tombstone written
|
|
7
|
+
* between the export's start `B` and the read `C`. This module requests a
|
|
8
|
+
* segment, waits for it, downloads the chunks and the corrections through the
|
|
9
|
+
* chain export's grant, verifies each, merges the corrections into the rows
|
|
10
|
+
* (a changed row replaces its line, a tombstone removes it, a new row joins
|
|
11
|
+
* in id order) and re-cuts the merged rows into snapshot-layout chunks — so
|
|
12
|
+
* the directory is the document at `C`, which `documents ingest` loads into
|
|
13
|
+
* another format-3 document.
|
|
14
|
+
*
|
|
15
|
+
* Nothing is written under `snapshot/` until every download has verified.
|
|
16
|
+
*/
|
|
17
|
+
/** The calls an export makes; `ApiClient` supplies them in the verb. */
|
|
18
|
+
export interface RecordLogExportClient {
|
|
19
|
+
requestSegment(): Promise<any>;
|
|
20
|
+
getSegment(segmentId: string): Promise<any>;
|
|
21
|
+
listSegments(): Promise<any>;
|
|
22
|
+
exportChain(): Promise<any>;
|
|
23
|
+
/** Read one object through a `/doc-artifact/…` path. */
|
|
24
|
+
download(artifactPath: string): Promise<Buffer>;
|
|
25
|
+
}
|
|
26
|
+
/** What the export wrote. */
|
|
27
|
+
export interface RecordLogExportResult {
|
|
28
|
+
/** Bytes of the segment's chunks and corrections, as downloaded. */
|
|
29
|
+
bytes: number;
|
|
30
|
+
/** `C`: the log number the directory is an image of. */
|
|
31
|
+
lsn: number;
|
|
32
|
+
segment: {
|
|
33
|
+
segmentId: string;
|
|
34
|
+
lsn: number;
|
|
35
|
+
completedLsn: number;
|
|
36
|
+
rows: number;
|
|
37
|
+
chunks: number;
|
|
38
|
+
corrections: number;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Rows per re-cut chunk. */
|
|
42
|
+
export declare const RECORD_LOG_EXPORT_CHUNK_ROWS = 10000;
|
|
43
|
+
/**
|
|
44
|
+
* Export a format-3 document into `docDir`: `snapshot/manifest.json`, its
|
|
45
|
+
* re-cut chunks `snapshot/{model}/{n}.ndjson.gz`, and `chain.json`
|
|
46
|
+
* (`{version: 3, documentFormat: 3, documentId, lsn: C, segment}`, with no
|
|
47
|
+
* grant in it). The caller writes `permissions.json`, `metadata.json` and the
|
|
48
|
+
* blobs, as for every format.
|
|
49
|
+
*/
|
|
50
|
+
export declare function exportRecordLogDocument(options: {
|
|
51
|
+
client: RecordLogExportClient;
|
|
52
|
+
documentId: string;
|
|
53
|
+
docDir: string;
|
|
54
|
+
chunkRows?: number;
|
|
55
|
+
sleep?: (ms: number) => Promise<void>;
|
|
56
|
+
onProgress?: (line: string) => void;
|
|
57
|
+
}): Promise<RecordLogExportResult>;
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `documents export` of a record-log (format 3) document (#4310, behavior 24).
|
|
3
|
+
*
|
|
4
|
+
* The document's base is a segment: its row chunks were written across
|
|
5
|
+
* alarms while writes continued, so they are no image of the document at any
|
|
6
|
+
* one log number; its corrections chunk holds every row and tombstone written
|
|
7
|
+
* between the export's start `B` and the read `C`. This module requests a
|
|
8
|
+
* segment, waits for it, downloads the chunks and the corrections through the
|
|
9
|
+
* chain export's grant, verifies each, merges the corrections into the rows
|
|
10
|
+
* (a changed row replaces its line, a tombstone removes it, a new row joins
|
|
11
|
+
* in id order) and re-cuts the merged rows into snapshot-layout chunks — so
|
|
12
|
+
* the directory is the document at `C`, which `documents ingest` loads into
|
|
13
|
+
* another format-3 document.
|
|
14
|
+
*
|
|
15
|
+
* Nothing is written under `snapshot/` until every download has verified.
|
|
16
|
+
*/
|
|
17
|
+
import fs from "fs";
|
|
18
|
+
import path from "path";
|
|
19
|
+
import zlib from "zlib";
|
|
20
|
+
import { createHash } from "crypto";
|
|
21
|
+
import { compareRecordIds, readSnapshotChunk } from "js-bao";
|
|
22
|
+
/** Rows per re-cut chunk. */
|
|
23
|
+
export const RECORD_LOG_EXPORT_CHUNK_ROWS = 10_000;
|
|
24
|
+
const POLL_MS = 500;
|
|
25
|
+
/**
|
|
26
|
+
* Request a segment and wait for it: one already exporting is waited for
|
|
27
|
+
* rather than refused. Answers the complete segment's view; a failed one
|
|
28
|
+
* throws with its reason.
|
|
29
|
+
*/
|
|
30
|
+
async function awaitSegment(client, options) {
|
|
31
|
+
let segmentId;
|
|
32
|
+
try {
|
|
33
|
+
segmentId = (await client.requestSegment()).segmentId;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (error?.code !== "SEGMENT_EXPORT_ACTIVE")
|
|
37
|
+
throw error;
|
|
38
|
+
const listed = await client.listSegments();
|
|
39
|
+
const active = (listed?.items ?? []).find((s) => s.state === "exporting");
|
|
40
|
+
if (!active)
|
|
41
|
+
throw error;
|
|
42
|
+
segmentId = active.segmentId;
|
|
43
|
+
}
|
|
44
|
+
options.onProgress?.(`Exporting segment ${segmentId}...`);
|
|
45
|
+
for (;;) {
|
|
46
|
+
const view = await client.getSegment(segmentId);
|
|
47
|
+
if (view.state === "complete")
|
|
48
|
+
return view;
|
|
49
|
+
if (view.state === "failed" || view.state === "superseded") {
|
|
50
|
+
const failure = view.failure ? `${view.failure.code}: ${view.failure.reason}` : view.state;
|
|
51
|
+
throw new Error(`The segment export ${segmentId} failed (${failure}); nothing was written.`);
|
|
52
|
+
}
|
|
53
|
+
await options.sleep(POLL_MS);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** The lines of a downloaded corrections chunk, verified against the manifest's entry. */
|
|
57
|
+
function readCorrections(body, entry) {
|
|
58
|
+
if (!entry || body.byteLength !== entry.bytes || createHash("sha256").update(body).digest("hex") !== entry.sha256) {
|
|
59
|
+
throw new Error(`The segment's corrections chunk does not match its manifest (expected ${entry?.bytes} bytes and sha256 ${entry?.sha256}); nothing was written.`);
|
|
60
|
+
}
|
|
61
|
+
const text = zlib.gunzipSync(body).toString("utf8");
|
|
62
|
+
const out = [];
|
|
63
|
+
for (const raw of text.split("\n")) {
|
|
64
|
+
if (!raw)
|
|
65
|
+
continue;
|
|
66
|
+
const tab = raw.indexOf("\t");
|
|
67
|
+
if (tab < 0)
|
|
68
|
+
throw new Error("The segment's corrections chunk holds a line with no id; nothing was written.");
|
|
69
|
+
const line = JSON.parse(raw.slice(tab + 1));
|
|
70
|
+
if (!line || typeof line !== "object" || Array.isArray(line)) {
|
|
71
|
+
throw new Error("The segment's corrections chunk holds a line that is not an object; nothing was written.");
|
|
72
|
+
}
|
|
73
|
+
out.push({ id: raw.slice(0, tab), line });
|
|
74
|
+
}
|
|
75
|
+
if (out.length !== entry.rows) {
|
|
76
|
+
throw new Error(`The segment's corrections chunk holds ${out.length} lines, not ${entry.rows}; nothing was written.`);
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Whether a corrections line is a tombstone: exactly `{_type, _deleted: true}`,
|
|
82
|
+
* as the room writes one. A live row's line carries its fields beside `_type`,
|
|
83
|
+
* so a field of the record named `_deleted` does not remove it.
|
|
84
|
+
*/
|
|
85
|
+
function isTombstoneLine(line) {
|
|
86
|
+
const keys = Object.keys(line);
|
|
87
|
+
return line._deleted === true && keys.length === 2 && keys.includes("_type");
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Refuse a model whose directory would not be a plain child of `snapshotDir`:
|
|
91
|
+
* an empty name, `.` or `..`, a path separator, or a NUL. Model names are any
|
|
92
|
+
* string a writer sent, so they are checked before they become paths.
|
|
93
|
+
*/
|
|
94
|
+
function assertModelDirectory(snapshotDir, model) {
|
|
95
|
+
const plain = model !== "" && model !== "." && model !== ".." && !/[\\/\0]/.test(model);
|
|
96
|
+
const resolved = path.resolve(snapshotDir, model);
|
|
97
|
+
if (!plain || path.dirname(resolved) !== path.resolve(snapshotDir)) {
|
|
98
|
+
throw new Error(`The document holds a model named ${JSON.stringify(model)}, which cannot be written as a directory of the export; nothing was written.`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/** Gzip one chunk's rows in the snapshot layout, `⟨id⟩\t⟨data⟩` per line, and describe it. */
|
|
102
|
+
function encodeChunk(model, index, rows) {
|
|
103
|
+
const raw = Buffer.from(rows.map(([id, data]) => `${id}\t${data}\n`).join(""), "utf8");
|
|
104
|
+
const body = zlib.gzipSync(raw, { level: 9 });
|
|
105
|
+
return {
|
|
106
|
+
body,
|
|
107
|
+
entry: {
|
|
108
|
+
key: `snapshot/${model}/${index}.ndjson.gz`,
|
|
109
|
+
path: `${model}/${index}`,
|
|
110
|
+
model,
|
|
111
|
+
bytes: body.byteLength,
|
|
112
|
+
rawBytes: raw.byteLength,
|
|
113
|
+
rows: rows.length,
|
|
114
|
+
firstId: rows[0][0],
|
|
115
|
+
lastId: rows[rows.length - 1][0],
|
|
116
|
+
sha256: createHash("sha256").update(body).digest("hex"),
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Export a format-3 document into `docDir`: `snapshot/manifest.json`, its
|
|
122
|
+
* re-cut chunks `snapshot/{model}/{n}.ndjson.gz`, and `chain.json`
|
|
123
|
+
* (`{version: 3, documentFormat: 3, documentId, lsn: C, segment}`, with no
|
|
124
|
+
* grant in it). The caller writes `permissions.json`, `metadata.json` and the
|
|
125
|
+
* blobs, as for every format.
|
|
126
|
+
*/
|
|
127
|
+
export async function exportRecordLogDocument(options) {
|
|
128
|
+
const { client, documentId, docDir } = options;
|
|
129
|
+
const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
130
|
+
await awaitSegment(client, { sleep, onProgress: options.onProgress });
|
|
131
|
+
const chain = await client.exportChain();
|
|
132
|
+
const grant = chain.segment.download.path;
|
|
133
|
+
const manifest = JSON.parse((await client.download(grant)).toString("utf8"));
|
|
134
|
+
let bytes = 0;
|
|
135
|
+
// Every row of every chunk, verified, by model and id.
|
|
136
|
+
const tables = new Map();
|
|
137
|
+
const table = (model) => {
|
|
138
|
+
let rows = tables.get(model);
|
|
139
|
+
if (!rows)
|
|
140
|
+
tables.set(model, (rows = new Map()));
|
|
141
|
+
return rows;
|
|
142
|
+
};
|
|
143
|
+
for (const entry of manifest.chunks ?? []) {
|
|
144
|
+
const body = await client.download(`${grant}/${entry.path}`);
|
|
145
|
+
bytes += body.byteLength;
|
|
146
|
+
let rows;
|
|
147
|
+
try {
|
|
148
|
+
rows = await readSnapshotChunk(new Uint8Array(body), { ...entry, key: entry.path });
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
throw new Error(`The segment's chunk ${entry.path} failed verification (${error?.message ?? error}); nothing was written.`);
|
|
152
|
+
}
|
|
153
|
+
for (const row of rows)
|
|
154
|
+
table(row._type).set(row._id, row._data);
|
|
155
|
+
}
|
|
156
|
+
const correctionsBody = await client.download(`${grant}/${manifest.corrections?.path ?? "corrections"}`);
|
|
157
|
+
bytes += correctionsBody.byteLength;
|
|
158
|
+
for (const { id, line } of readCorrections(correctionsBody, manifest.corrections)) {
|
|
159
|
+
const { _type, ...fields } = line;
|
|
160
|
+
if (typeof _type !== "string") {
|
|
161
|
+
throw new Error(`The segment's corrections chunk holds a line for ${id} with no model; nothing was written.`);
|
|
162
|
+
}
|
|
163
|
+
if (isTombstoneLine(line))
|
|
164
|
+
table(_type).delete(id);
|
|
165
|
+
else
|
|
166
|
+
table(_type).set(id, JSON.stringify(fields));
|
|
167
|
+
}
|
|
168
|
+
// Re-cut, model by model in id order. A model is a directory of the export,
|
|
169
|
+
// so one that is not a plain name refuses the export before anything is written.
|
|
170
|
+
const chunkRows = options.chunkRows ?? RECORD_LOG_EXPORT_CHUNK_ROWS;
|
|
171
|
+
const snapshotDir = path.join(docDir, "snapshot");
|
|
172
|
+
for (const model of tables.keys())
|
|
173
|
+
assertModelDirectory(snapshotDir, model);
|
|
174
|
+
fs.rmSync(snapshotDir, { recursive: true, force: true });
|
|
175
|
+
const entries = [];
|
|
176
|
+
let rows = 0;
|
|
177
|
+
let written = 0;
|
|
178
|
+
for (const model of [...tables.keys()].sort(compareRecordIds)) {
|
|
179
|
+
const sorted = [...tables.get(model)].sort(([a], [b]) => compareRecordIds(a, b));
|
|
180
|
+
for (let at = 0, index = 0; at < sorted.length; at += chunkRows, index++) {
|
|
181
|
+
const { body, entry } = encodeChunk(model, index, sorted.slice(at, at + chunkRows));
|
|
182
|
+
const file = path.join(snapshotDir, model, `${index}.ndjson.gz`);
|
|
183
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
184
|
+
fs.writeFileSync(file, body);
|
|
185
|
+
entries.push({ ...entry, ordinal: entries.length });
|
|
186
|
+
rows += entry.rows;
|
|
187
|
+
written += entry.bytes;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const completedLsn = Number(chain.completedLsn);
|
|
191
|
+
fs.mkdirSync(snapshotDir, { recursive: true });
|
|
192
|
+
fs.writeFileSync(path.join(snapshotDir, "manifest.json"), JSON.stringify({
|
|
193
|
+
kind: "segment-export",
|
|
194
|
+
version: 1,
|
|
195
|
+
documentFormat: 3,
|
|
196
|
+
documentId,
|
|
197
|
+
lsn: completedLsn,
|
|
198
|
+
schema: manifest.schema ?? {},
|
|
199
|
+
chunks: entries,
|
|
200
|
+
totals: { rows, chunks: entries.length, bytes: written },
|
|
201
|
+
}, null, 2));
|
|
202
|
+
const segment = {
|
|
203
|
+
segmentId: String(chain.segment.segmentId),
|
|
204
|
+
lsn: Number(chain.lsn),
|
|
205
|
+
completedLsn,
|
|
206
|
+
rows: Number(chain.segment.rows),
|
|
207
|
+
chunks: Number(chain.segment.chunks),
|
|
208
|
+
corrections: Number(chain.segment.corrections),
|
|
209
|
+
};
|
|
210
|
+
// Last, and without the grant: a signature is this run's read of the
|
|
211
|
+
// document, and an artifact that outlives it must not carry one.
|
|
212
|
+
fs.writeFileSync(path.join(docDir, "chain.json"), JSON.stringify({ version: 3, documentFormat: 3, documentId, lsn: completedLsn, segment }, null, 2));
|
|
213
|
+
return { bytes, lsn: completedLsn, segment };
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=document-export-record-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-export-record-log.js","sourceRoot":"","sources":["../../../src/lib/document-export-record-log.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* falls back to a bounded external sort.
|
|
15
15
|
*
|
|
16
16
|
* The local check is the server's, said on this side: the rules it mirrors are
|
|
17
|
-
* `planLine`'s in `src/
|
|
18
|
-
*
|
|
17
|
+
* `planLine`'s in `src/rooms/record-room/load.ts`, and the artifact's own
|
|
18
|
+
* rules are in `docs/large-document-ingest.md`.
|
|
19
19
|
*/
|
|
20
20
|
import type { DiscoveredIngestInput } from "./document-ingest-input.js";
|
|
21
21
|
/** A line, a file or a plan this document's schema does not accept. */
|
|
@@ -26,6 +26,12 @@ export declare class IngestArtifactError extends Error {
|
|
|
26
26
|
export interface IngestModelSchema {
|
|
27
27
|
fields: Set<string>;
|
|
28
28
|
stringSets: Set<string>;
|
|
29
|
+
/**
|
|
30
|
+
* A record-log (format 3) document takes fields and models it does not
|
|
31
|
+
* declare, as its writes do; the room refuses a row that breaks a declared
|
|
32
|
+
* type, row by row.
|
|
33
|
+
*/
|
|
34
|
+
open?: boolean;
|
|
29
35
|
}
|
|
30
36
|
/** Every model the document has a declaration for. */
|
|
31
37
|
export interface IngestSchema {
|
|
@@ -62,10 +68,23 @@ export interface IngestModelSummary {
|
|
|
62
68
|
rawBytes: number;
|
|
63
69
|
deletes: number;
|
|
64
70
|
}
|
|
71
|
+
/** A row of a format-2 export left out of the artifact, and why. */
|
|
72
|
+
export interface IngestRefusedRow {
|
|
73
|
+
model: string;
|
|
74
|
+
id: string;
|
|
75
|
+
/** `file:line`. */
|
|
76
|
+
where: string;
|
|
77
|
+
reason: string;
|
|
78
|
+
}
|
|
65
79
|
/** The artifact, ready to upload. */
|
|
66
80
|
export interface IngestArtifactPlan {
|
|
67
81
|
models: IngestModelSummary[];
|
|
68
82
|
chunks: IngestChunkDescriptor[];
|
|
83
|
+
/**
|
|
84
|
+
* Rows of a format-2 export that cannot be sent as one record, left out
|
|
85
|
+
* before upload. Every other input either builds whole or is refused.
|
|
86
|
+
*/
|
|
87
|
+
refused: IngestRefusedRow[];
|
|
69
88
|
rows: number;
|
|
70
89
|
bytes: number;
|
|
71
90
|
rawBytes: number;
|
|
@@ -79,6 +98,11 @@ export interface IngestArtifactPlan {
|
|
|
79
98
|
export interface BuildIngestArtifactOptions {
|
|
80
99
|
input: DiscoveredIngestInput;
|
|
81
100
|
schema: IngestSchema;
|
|
101
|
+
/**
|
|
102
|
+
* The document is a record-log (format 3) document: a model or a field it
|
|
103
|
+
* does not declare is taken as it is, as its writes take them.
|
|
104
|
+
*/
|
|
105
|
+
open?: boolean;
|
|
82
106
|
/** Where chunk bodies and sort runs are written. */
|
|
83
107
|
tmpDir?: string;
|
|
84
108
|
/** Cut a chunk at this many decompressed bytes. */
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* falls back to a bounded external sort.
|
|
15
15
|
*
|
|
16
16
|
* The local check is the server's, said on this side: the rules it mirrors are
|
|
17
|
-
* `planLine`'s in `src/
|
|
18
|
-
*
|
|
17
|
+
* `planLine`'s in `src/rooms/record-room/load.ts`, and the artifact's own
|
|
18
|
+
* rules are in `docs/large-document-ingest.md`.
|
|
19
19
|
*/
|
|
20
20
|
import fs from "fs";
|
|
21
21
|
import path from "path";
|
|
@@ -25,6 +25,7 @@ import zlib from "zlib";
|
|
|
25
25
|
import { createHash } from "crypto";
|
|
26
26
|
import { StringDecoder } from "string_decoder";
|
|
27
27
|
import { compareRecordIds, INGEST_CHUNK_LIMITS } from "js-bao";
|
|
28
|
+
import { flattenFormat2Row } from "./document-ingest-format2.js";
|
|
28
29
|
/** A line, a file or a plan this document's schema does not accept. */
|
|
29
30
|
export class IngestArtifactError extends Error {
|
|
30
31
|
constructor(message) {
|
|
@@ -64,6 +65,8 @@ export async function buildIngestArtifact(options) {
|
|
|
64
65
|
const { input, schema, cutRawBytes = INGEST_CUT_RAW_BYTES, cutRows = INGEST_CUT_ROWS, runBytes = INGEST_SORT_RUN_BYTES, maxChunkBytes = INGEST_CHUNK_LIMITS.maxChunkBytes, maxChunkRawBytes = INGEST_CHUNK_LIMITS.maxChunkRawBytes, maxChunkRows = INGEST_CHUNK_LIMITS.maxChunkRows, maxChunks = INGEST_CHUNK_LIMITS.maxChunks, maxTotalBytes = INGEST_CHUNK_LIMITS.maxTotalBytes, } = options;
|
|
65
66
|
const scratch = fs.mkdtempSync(path.join(options.tmpDir ?? os.tmpdir(), "primitive-ingest-"));
|
|
66
67
|
const written = [];
|
|
68
|
+
const refused = [];
|
|
69
|
+
const read = (source, onRefused) => readRows(source, Boolean(input.format2), onRefused);
|
|
67
70
|
const cleanup = async () => {
|
|
68
71
|
fs.rmSync(scratch, { recursive: true, force: true });
|
|
69
72
|
};
|
|
@@ -79,7 +82,15 @@ export async function buildIngestArtifact(options) {
|
|
|
79
82
|
entry.sources.push(source);
|
|
80
83
|
}
|
|
81
84
|
for (const [model, entry] of models) {
|
|
82
|
-
|
|
85
|
+
// A format-2 export's converted row into a record-log document is held
|
|
86
|
+
// to the line's structure only: a value its declaration refuses (an
|
|
87
|
+
// array that is not all strings) is the room's to refuse, row by row
|
|
88
|
+
// and naming the field, not a reason to stop the whole load.
|
|
89
|
+
const declared = options.open
|
|
90
|
+
? input.format2
|
|
91
|
+
? { fields: new Set(), stringSets: new Set(), open: true }
|
|
92
|
+
: { ...(schema.models.get(model) ?? { fields: new Set(), stringSets: new Set() }), open: true }
|
|
93
|
+
: schema.models.get(model);
|
|
83
94
|
if (!declared) {
|
|
84
95
|
throw new IngestArtifactError(`This document declares no model ${model}. An ingest applies the ` +
|
|
85
96
|
"document's existing schema; declare the model through your app's " +
|
|
@@ -87,7 +98,7 @@ export async function buildIngestArtifact(options) {
|
|
|
87
98
|
}
|
|
88
99
|
let previous = null;
|
|
89
100
|
for (const source of entry.sources) {
|
|
90
|
-
for await (const line of
|
|
101
|
+
for await (const line of read(source, (row) => refused.push(row))) {
|
|
91
102
|
const parsed = checkIngestLine(line.where, model, line.text, declared);
|
|
92
103
|
entry.rows += 1;
|
|
93
104
|
if (parsed.deleted)
|
|
@@ -124,7 +135,7 @@ export async function buildIngestArtifact(options) {
|
|
|
124
135
|
if (entry.sorted) {
|
|
125
136
|
let previousId = null;
|
|
126
137
|
for (const source of entry.sources) {
|
|
127
|
-
for await (const line of
|
|
138
|
+
for await (const line of read(source)) {
|
|
128
139
|
const parsed = parseIngestLine(line.where, line.text);
|
|
129
140
|
assertNoDuplicate(previousId, parsed, line.where);
|
|
130
141
|
previousId = parsed.id;
|
|
@@ -133,7 +144,7 @@ export async function buildIngestArtifact(options) {
|
|
|
133
144
|
}
|
|
134
145
|
}
|
|
135
146
|
else {
|
|
136
|
-
const sorted = await externalSort(entry.sources, scratch, runBytes);
|
|
147
|
+
const sorted = await externalSort(entry.sources, read, scratch, runBytes);
|
|
137
148
|
sortRuns += sorted.runs;
|
|
138
149
|
let previous = null;
|
|
139
150
|
for (const line of sorted.lines()) {
|
|
@@ -172,6 +183,7 @@ export async function buildIngestArtifact(options) {
|
|
|
172
183
|
return {
|
|
173
184
|
models: summaries,
|
|
174
185
|
chunks,
|
|
186
|
+
refused,
|
|
175
187
|
rows: summaries.reduce((sum, model) => sum + model.rows, 0),
|
|
176
188
|
bytes: totalBytes,
|
|
177
189
|
rawBytes: summaries.reduce((sum, model) => sum + model.rawBytes, 0),
|
|
@@ -211,6 +223,26 @@ async function* readSource(source) {
|
|
|
211
223
|
stream.destroy?.();
|
|
212
224
|
}
|
|
213
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Every row of one source, as {@link readSource} reads it, or as a record-log
|
|
228
|
+
* row when the source is a format-2 export's. A row that cannot be converted
|
|
229
|
+
* is left out and handed to `onRefused`.
|
|
230
|
+
*/
|
|
231
|
+
async function* readRows(source, format2, onRefused) {
|
|
232
|
+
for await (const line of readSource(source)) {
|
|
233
|
+
if (!format2) {
|
|
234
|
+
yield line;
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const parsed = parseIngestLine(line.where, line.text);
|
|
238
|
+
const converted = flattenFormat2Row(source.model, parsed.id, JSON.parse(parsed.patch));
|
|
239
|
+
if ("refused" in converted) {
|
|
240
|
+
onRefused?.({ model: source.model, id: parsed.id, where: line.where, reason: converted.refused });
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
yield { where: line.where, text: `${parsed.id}\t${JSON.stringify(converted.fields)}` };
|
|
244
|
+
}
|
|
245
|
+
}
|
|
214
246
|
/** One line's id and patch, whichever of the two forms it is written in. */
|
|
215
247
|
export function parseIngestLine(where, text) {
|
|
216
248
|
let id;
|
|
@@ -299,6 +331,8 @@ export function checkIngestLine(where, model, text, declared) {
|
|
|
299
331
|
continue;
|
|
300
332
|
}
|
|
301
333
|
if (!declared.fields.has(key)) {
|
|
334
|
+
if (declared.open)
|
|
335
|
+
continue;
|
|
302
336
|
throw new IngestArtifactError(`${where}: the model ${model} does not declare the field ${key}`);
|
|
303
337
|
}
|
|
304
338
|
if (Array.isArray(value)) {
|
|
@@ -314,7 +348,7 @@ export function checkIngestLine(where, model, text, declared) {
|
|
|
314
348
|
* writes each sorted run out and merges them back k-way, so the peak cost is
|
|
315
349
|
* the run size plus one line per run whatever the input's size.
|
|
316
350
|
*/
|
|
317
|
-
async function externalSort(sources, scratch, runBytes) {
|
|
351
|
+
async function externalSort(sources, read, scratch, runBytes) {
|
|
318
352
|
const runFiles = [];
|
|
319
353
|
let buffer = [];
|
|
320
354
|
let buffered = 0;
|
|
@@ -327,7 +361,7 @@ async function externalSort(sources, scratch, runBytes) {
|
|
|
327
361
|
buffered = 0;
|
|
328
362
|
};
|
|
329
363
|
for (const source of sources) {
|
|
330
|
-
for await (const raw of
|
|
364
|
+
for await (const raw of read(source)) {
|
|
331
365
|
const parsed = parseIngestLine(raw.where, raw.text);
|
|
332
366
|
buffer.push({ ...parsed, where: raw.where });
|
|
333
367
|
buffered += parsed.id.length + parsed.patch.length + raw.where.length + 2;
|