@pikku/core 0.12.107 → 0.12.112
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/CHANGELOG.md +357 -0
- package/dist/analytics/analytics.d.ts +6 -0
- package/dist/analytics/analytics.js +58 -0
- package/dist/analytics/analytics.types.d.ts +156 -0
- package/dist/analytics/analytics.types.js +1 -0
- package/dist/analytics/anonymous-analytics-identity.d.ts +23 -0
- package/dist/analytics/anonymous-analytics-identity.js +27 -0
- package/dist/analytics/compose-analytics-identity.d.ts +14 -0
- package/dist/analytics/compose-analytics-identity.js +33 -0
- package/dist/analytics/cookie-analytics-identity.d.ts +24 -0
- package/dist/analytics/cookie-analytics-identity.js +37 -0
- package/dist/analytics/define-analytics-events.d.ts +22 -0
- package/dist/analytics/define-analytics-events.js +9 -0
- package/dist/analytics/fan-out-analytics.d.ts +15 -0
- package/dist/analytics/fan-out-analytics.js +36 -0
- package/dist/analytics/index.d.ts +13 -0
- package/dist/analytics/index.js +8 -0
- package/dist/analytics/logger-analytics-service.d.ts +14 -0
- package/dist/analytics/logger-analytics-service.js +23 -0
- package/dist/analytics/mint-cookie.d.ts +44 -0
- package/dist/analytics/mint-cookie.js +55 -0
- package/dist/dev/hot-reload.d.ts +0 -1
- package/dist/dev/hot-reload.js +4 -25
- package/dist/dev/module-runner.js +104 -25
- package/dist/errors/errors.d.ts +7 -0
- package/dist/errors/errors.js +17 -0
- package/dist/function/function-meta.types.d.ts +2 -0
- package/dist/function/function-runner.js +29 -0
- package/dist/function/functions.types.d.ts +22 -3
- package/dist/middleware/auth-apikey.d.ts +1 -1
- package/dist/pikku-state.d.ts +1 -1
- package/dist/scopes.d.ts +11 -0
- package/dist/scopes.js +17 -0
- package/dist/services/credential-wire-service.d.ts +1 -1
- package/dist/services/feature-flag-service.d.ts +100 -0
- package/dist/services/feature-flag-service.js +1 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/meta-service.d.ts +16 -0
- package/dist/services/meta-service.js +19 -0
- package/dist/services/webhook-service.d.ts +7 -2
- package/dist/services/webhook-service.js +11 -6
- package/dist/testing/service-tests/agent-run-service-tests.d.ts +2 -2
- package/dist/testing/service-tests/agent-storage-service-tests.d.ts +1 -1
- package/dist/testing/service-tests/channel-store-tests.d.ts +1 -1
- package/dist/testing/service-tests/credential-service-tests.d.ts +1 -1
- package/dist/testing/service-tests/deployment-service-tests.d.ts +1 -1
- package/dist/testing/service-tests/event-hub-store-tests.d.ts +1 -1
- package/dist/testing/service-tests/secret-service-tests.d.ts +1 -1
- package/dist/testing/service-tests/session-store-tests.d.ts +1 -1
- package/dist/testing/service-tests/workflow-run-service-tests.d.ts +1 -1
- package/dist/testing/service-tests/workflow-service-tests.d.ts +1 -1
- package/dist/types/core.types.d.ts +23 -0
- package/dist/wirings/agent/agent-rpc.d.ts +1 -1
- package/dist/wirings/agent/agent-turn.d.ts +1 -1
- package/dist/wirings/agent-scorer/agent-scorer-live.d.ts +1 -1
- package/dist/wirings/channel/channel-common.d.ts +1 -1
- package/dist/wirings/channel/channel-rpc-validators.d.ts +2 -2
- package/dist/wirings/channel/channel-runner.d.ts +1 -1
- package/dist/wirings/channel/local/local-channel-runner.d.ts +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +1 -1
- package/dist/wirings/cli/channel/cli-approval.d.ts +2 -2
- package/dist/wirings/flag/assert-feature-available.d.ts +15 -0
- package/dist/wirings/flag/assert-feature-available.js +23 -0
- package/dist/wirings/flag/cached-flag-source.d.ts +73 -0
- package/dist/wirings/flag/cached-flag-source.js +96 -0
- package/dist/wirings/flag/define-feature-flags.d.ts +33 -0
- package/dist/wirings/flag/define-feature-flags.js +32 -0
- package/dist/wirings/flag/flag.types.d.ts +97 -0
- package/dist/wirings/flag/flag.types.js +1 -0
- package/dist/wirings/flag/index.d.ts +7 -0
- package/dist/wirings/flag/index.js +5 -0
- package/dist/wirings/flag/resolve-flag.d.ts +52 -0
- package/dist/wirings/flag/resolve-flag.js +90 -0
- package/dist/wirings/flag/validate-flag-definitions.d.ts +26 -0
- package/dist/wirings/flag/validate-flag-definitions.js +103 -0
- package/dist/wirings/virtual-user/virtual-user-scaffold.d.ts +8 -8
- package/dist/wirings/virtual-user/virtual-user-schedule.d.ts +1 -1
- package/dist/wirings/workflow/workflow-queue-routing.d.ts +1 -1
- package/knowledge/decisions/internals/a-reset-suite-makes-the-dev-seed-the-fixture.md +50 -0
- package/knowledge/decisions/internals/hot-reload-reads-the-changed-source-never-a-compiled-copy.md +38 -0
- package/knowledge/decisions/internals/index.md +2 -0
- package/package.json +11 -5
- package/run-tests.sh +17 -9
- package/src/public-surface.json +26 -0
- package/src/agent-naming.test.ts +0 -68
- package/src/api-report.test.ts +0 -138
- package/src/app-alias-surface.test.ts +0 -179
- package/src/app-leaf-surface.test.ts +0 -222
- package/src/bootstrap-compat/root.ts +0 -20
- package/src/classification/column-form.test.ts +0 -97
- package/src/classification/column-form.ts +0 -55
- package/src/classification/data-classification.ts +0 -73
- package/src/classification/index.ts +0 -40
- package/src/classification/key-ids.ts +0 -2
- package/src/classification/secret-value.test.ts +0 -204
- package/src/classification/secret-value.ts +0 -106
- package/src/crypto-utils.test.ts +0 -668
- package/src/crypto-utils.ts +0 -460
- package/src/dev/hot-reload.test.ts +0 -587
- package/src/dev/hot-reload.ts +0 -225
- package/src/dev/module-runner.test.ts +0 -235
- package/src/dev/module-runner.ts +0 -138
- package/src/dev/reload-meta.test.ts +0 -183
- package/src/dev/reload-meta.ts +0 -144
- package/src/ecosystem-tier-removed.test.ts +0 -72
- package/src/env.ts +0 -1
- package/src/errors/error-handler.ts +0 -77
- package/src/errors/error.test.ts +0 -229
- package/src/errors/errors.ts +0 -393
- package/src/errors/index.ts +0 -11
- package/src/errors/serialized-error.ts +0 -12
- package/src/factory-functions.test.ts +0 -111
- package/src/function/abort-scope.test.ts +0 -97
- package/src/function/abort-scope.ts +0 -80
- package/src/function/function-meta.types.ts +0 -151
- package/src/function/function-runner.test.ts +0 -1619
- package/src/function/function-runner.ts +0 -499
- package/src/function/functions.types.ts +0 -319
- package/src/function/index.ts +0 -40
- package/src/function/list.types.test.ts +0 -100
- package/src/function/list.types.ts +0 -69
- package/src/function/pikku-request.test.ts +0 -35
- package/src/function/pikku-request.ts +0 -17
- package/src/gopass-secrets-removed.test.ts +0 -51
- package/src/handle-error.test.ts +0 -532
- package/src/handle-error.ts +0 -64
- package/src/middleware/auth-apikey.test.ts +0 -362
- package/src/middleware/auth-apikey.ts +0 -39
- package/src/middleware/auth-bearer.test.ts +0 -566
- package/src/middleware/auth-bearer.ts +0 -83
- package/src/middleware/auth-cookie.test.ts +0 -572
- package/src/middleware/auth-cookie.ts +0 -107
- package/src/middleware/cors.test.ts +0 -579
- package/src/middleware/cors.ts +0 -103
- package/src/middleware/index.ts +0 -30
- package/src/middleware/middleware-factories.ts +0 -76
- package/src/middleware/middleware.types.ts +0 -61
- package/src/middleware/remote-auth.test.ts +0 -547
- package/src/middleware/remote-auth.ts +0 -95
- package/src/middleware/remote-jobs-secret.ts +0 -35
- package/src/middleware/require-origin.test.ts +0 -115
- package/src/middleware/require-origin.ts +0 -79
- package/src/middleware/telemetry.ts +0 -83
- package/src/middleware-runner.test.ts +0 -578
- package/src/middleware-runner.ts +0 -232
- package/src/no-any-casts.test.ts +0 -57
- package/src/no-root-barrel.test.ts +0 -122
- package/src/permissions.test.ts +0 -256
- package/src/permissions.ts +0 -217
- package/src/pikku-state.test.ts +0 -198
- package/src/pikku-state.ts +0 -206
- package/src/production-barrels-stay-lean.test.ts +0 -110
- package/src/public-surface.test.ts +0 -133
- package/src/remote.test.ts +0 -173
- package/src/remote.ts +0 -56
- package/src/removed-legacy-exports.test.ts +0 -66
- package/src/run-tests-script.test.ts +0 -67
- package/src/schema.test.ts +0 -430
- package/src/schema.ts +0 -204
- package/src/scopes.test.ts +0 -203
- package/src/scopes.ts +0 -67
- package/src/services/agent-run-state-service.ts +0 -37
- package/src/services/agent-runner-service.ts +0 -238
- package/src/services/agent-storage-service.ts +0 -39
- package/src/services/ai-embedding-service.ts +0 -9
- package/src/services/audit-service.test.ts +0 -44
- package/src/services/audit-service.ts +0 -280
- package/src/services/content-service.ts +0 -65
- package/src/services/credential-service.ts +0 -20
- package/src/services/credential-wire-service.test.ts +0 -235
- package/src/services/credential-wire-service.ts +0 -120
- package/src/services/deployment-service.ts +0 -32
- package/src/services/email-service.test.ts +0 -100
- package/src/services/email-service.ts +0 -60
- package/src/services/email-template.test.ts +0 -311
- package/src/services/email-template.ts +0 -254
- package/src/services/file-scenario-run-store.test.ts +0 -349
- package/src/services/file-scenario-run-store.ts +0 -282
- package/src/services/gateway-service.ts +0 -5
- package/src/services/http-personas-converse.test.ts +0 -274
- package/src/services/http-personas.test.ts +0 -379
- package/src/services/http-personas.ts +0 -508
- package/src/services/in-memory-agent-run-state-service.ts +0 -87
- package/src/services/in-memory-queue-service.test.ts +0 -162
- package/src/services/in-memory-queue-service.ts +0 -78
- package/src/services/in-memory-session-store.test.ts +0 -58
- package/src/services/in-memory-session-store.ts +0 -20
- package/src/services/in-memory-trigger-service.ts +0 -47
- package/src/services/in-memory-workflow-service.test.ts +0 -430
- package/src/services/in-memory-workflow-service.ts +0 -595
- package/src/services/index.ts +0 -192
- package/src/services/istanbul-coverage-service.test.ts +0 -66
- package/src/services/istanbul-coverage-service.ts +0 -59
- package/src/services/jwt-service.ts +0 -15
- package/src/services/local-content-request-handler.test.ts +0 -240
- package/src/services/local-content-request-handler.ts +0 -295
- package/src/services/local-content.test.ts +0 -186
- package/src/services/local-content.ts +0 -242
- package/src/services/local-credential-service.ts +0 -63
- package/src/services/local-email-service.test.ts +0 -182
- package/src/services/local-email-service.ts +0 -43
- package/src/services/local-gateway-service.ts +0 -51
- package/src/services/local-secrets.test.ts +0 -95
- package/src/services/local-secrets.ts +0 -71
- package/src/services/local-variables.test.ts +0 -61
- package/src/services/local-variables.ts +0 -45
- package/src/services/logger-console.test.ts +0 -117
- package/src/services/logger-console.ts +0 -174
- package/src/services/logger.ts +0 -48
- package/src/services/meta-service.test.ts +0 -75
- package/src/services/meta-service.ts +0 -767
- package/src/services/persona-actor-secret.test.ts +0 -68
- package/src/services/persona-actor-secret.ts +0 -70
- package/src/services/persona-sign-in.test.ts +0 -219
- package/src/services/persona-sign-in.ts +0 -238
- package/src/services/personas-service.ts +0 -191
- package/src/services/pikku-user-id.test.ts +0 -62
- package/src/services/pikku-user-id.ts +0 -13
- package/src/services/queue-webhook-service.test.ts +0 -409
- package/src/services/queue-webhook-service.ts +0 -150
- package/src/services/remote-jobs.test.ts +0 -106
- package/src/services/remote-jobs.ts +0 -92
- package/src/services/scheduler-service.ts +0 -37
- package/src/services/schema-service.ts +0 -10
- package/src/services/scope-service.ts +0 -91
- package/src/services/scoped-credential-service.test.ts +0 -86
- package/src/services/scoped-credential-service.ts +0 -63
- package/src/services/scoped-secret-service.test.ts +0 -93
- package/src/services/scoped-secret-service.ts +0 -40
- package/src/services/secret-host-binding.test.ts +0 -138
- package/src/services/secret-host-binding.ts +0 -51
- package/src/services/secret-service.ts +0 -25
- package/src/services/secretless.test.ts +0 -54
- package/src/services/secretless.ts +0 -29
- package/src/services/session-store.ts +0 -9
- package/src/services/stub-tracker.test.ts +0 -104
- package/src/services/stub-tracker.ts +0 -175
- package/src/services/system-role-guard.test.ts +0 -96
- package/src/services/system-role-guard.ts +0 -71
- package/src/services/temporary-file-service.ts +0 -76
- package/src/services/trigger-service.ts +0 -5
- package/src/services/typed-credential-service.ts +0 -83
- package/src/services/typed-secret-service.test.ts +0 -204
- package/src/services/typed-secret-service.ts +0 -132
- package/src/services/typed-variables-service.test.ts +0 -166
- package/src/services/typed-variables-service.ts +0 -166
- package/src/services/user-session-service.test.ts +0 -147
- package/src/services/user-session-service.ts +0 -85
- package/src/services/v8-coverage-service.test.ts +0 -69
- package/src/services/v8-coverage-service.ts +0 -163
- package/src/services/variables-service.ts +0 -13
- package/src/services/webhook-service.ts +0 -147
- package/src/services/workflow-service.ts +0 -120
- package/src/side-effects-are-declared.test.ts +0 -84
- package/src/source-files-stay-composable.test.ts +0 -41
- package/src/template-alias-surface.test.ts +0 -240
- package/src/test-utils.ts +0 -38
- package/src/testing/index.ts +0 -3
- package/src/testing/service-tests/agent-run-service-tests.ts +0 -98
- package/src/testing/service-tests/agent-storage-service-tests.ts +0 -379
- package/src/testing/service-tests/channel-store-tests.ts +0 -98
- package/src/testing/service-tests/credential-service-tests.ts +0 -143
- package/src/testing/service-tests/deployment-service-tests.ts +0 -33
- package/src/testing/service-tests/event-hub-store-tests.ts +0 -48
- package/src/testing/service-tests/secret-service-tests.ts +0 -105
- package/src/testing/service-tests/session-store-tests.ts +0 -62
- package/src/testing/service-tests/workflow-run-service-tests.ts +0 -59
- package/src/testing/service-tests/workflow-service-tests.ts +0 -308
- package/src/testing/service-tests.ts +0 -95
- package/src/time-utils.test.ts +0 -56
- package/src/time-utils.ts +0 -89
- package/src/types/core.types.ts +0 -446
- package/src/types/index.ts +0 -25
- package/src/types/state.types.ts +0 -226
- package/src/types/typed-credentials.test.ts +0 -72
- package/src/utils/hash.test.ts +0 -68
- package/src/utils/hash.ts +0 -26
- package/src/utils/hmac.ts +0 -21
- package/src/utils/node-host-resolver.ts +0 -20
- package/src/utils/safe-fetch.test.ts +0 -515
- package/src/utils/safe-fetch.ts +0 -347
- package/src/utils.test.ts +0 -359
- package/src/utils.ts +0 -165
- package/src/version.test.ts +0 -80
- package/src/version.ts +0 -25
- package/src/wirings/actor-flow/actor-flow.types.ts +0 -40
- package/src/wirings/actor-flow/index.ts +0 -10
- package/src/wirings/actor-flow/run-conversation.test.ts +0 -187
- package/src/wirings/actor-flow/run-conversation.ts +0 -280
- package/src/wirings/addon/addon-auth-tags.test.ts +0 -219
- package/src/wirings/addon/addon-runner.ts +0 -236
- package/src/wirings/addon/addon-scopes.test.ts +0 -225
- package/src/wirings/addon/addon-secrets.test.ts +0 -391
- package/src/wirings/addon/index.ts +0 -12
- package/src/wirings/addon/remote-addon-auth.ts +0 -65
- package/src/wirings/addon/wire-addon.test.ts +0 -102
- package/src/wirings/addon/wire-addon.ts +0 -202
- package/src/wirings/addon/wire-remote-addon.ts +0 -41
- package/src/wirings/agent/agent-agui.test.ts +0 -1213
- package/src/wirings/agent/agent-agui.ts +0 -405
- package/src/wirings/agent/agent-authorization.test.ts +0 -208
- package/src/wirings/agent/agent-finalize.test.ts +0 -187
- package/src/wirings/agent/agent-finalize.ts +0 -197
- package/src/wirings/agent/agent-helpers.test.ts +0 -215
- package/src/wirings/agent/agent-helpers.ts +0 -96
- package/src/wirings/agent/agent-interrupt.test.ts +0 -833
- package/src/wirings/agent/agent-interrupt.ts +0 -400
- package/src/wirings/agent/agent-memory.test.ts +0 -397
- package/src/wirings/agent/agent-memory.ts +0 -496
- package/src/wirings/agent/agent-middleware.types.test.ts +0 -41
- package/src/wirings/agent/agent-model-config.test.ts +0 -103
- package/src/wirings/agent/agent-model-config.ts +0 -59
- package/src/wirings/agent/agent-prepare.test.ts +0 -977
- package/src/wirings/agent/agent-prepare.ts +0 -1083
- package/src/wirings/agent/agent-registry.test.ts +0 -455
- package/src/wirings/agent/agent-registry.ts +0 -99
- package/src/wirings/agent/agent-resume-authorization.test.ts +0 -206
- package/src/wirings/agent/agent-rpc.ts +0 -116
- package/src/wirings/agent/agent-runner.test.ts +0 -1229
- package/src/wirings/agent/agent-runner.ts +0 -858
- package/src/wirings/agent/agent-stream-delegate.test.ts +0 -381
- package/src/wirings/agent/agent-stream-output-hooks.test.ts +0 -353
- package/src/wirings/agent/agent-stream.test.ts +0 -1800
- package/src/wirings/agent/agent-stream.ts +0 -1639
- package/src/wirings/agent/agent-thread-ownership.test.ts +0 -297
- package/src/wirings/agent/agent-turn.test.ts +0 -65
- package/src/wirings/agent/agent-turn.ts +0 -122
- package/src/wirings/agent/agent-utils.ts +0 -20
- package/src/wirings/agent/agent.types.ts +0 -676
- package/src/wirings/agent/index.ts +0 -58
- package/src/wirings/agent/voice-input.test.ts +0 -220
- package/src/wirings/agent/voice-input.ts +0 -180
- package/src/wirings/agent/voice-output.test.ts +0 -510
- package/src/wirings/agent/voice-output.ts +0 -311
- package/src/wirings/agent-scorer/agent-scorer-grade.test.ts +0 -106
- package/src/wirings/agent-scorer/agent-scorer-grade.ts +0 -55
- package/src/wirings/agent-scorer/agent-scorer-judge.test.ts +0 -285
- package/src/wirings/agent-scorer/agent-scorer-judge.ts +0 -180
- package/src/wirings/agent-scorer/agent-scorer-live.test.ts +0 -174
- package/src/wirings/agent-scorer/agent-scorer-live.ts +0 -56
- package/src/wirings/agent-scorer/agent-scorer-registry.ts +0 -66
- package/src/wirings/agent-scorer/agent-scorer-sampling.test.ts +0 -34
- package/src/wirings/agent-scorer/agent-scorer-sampling.ts +0 -36
- package/src/wirings/agent-scorer/agent-scorer-snapshots.test.ts +0 -49
- package/src/wirings/agent-scorer/agent-scorer-snapshots.ts +0 -46
- package/src/wirings/agent-scorer/agent-scorer-worker.test.ts +0 -122
- package/src/wirings/agent-scorer/agent-scorer-worker.ts +0 -71
- package/src/wirings/agent-scorer/agent-scorer.ts +0 -102
- package/src/wirings/agent-scorer/agent-scorer.types.ts +0 -128
- package/src/wirings/agent-scorer/index.ts +0 -23
- package/src/wirings/channel/channel-common.ts +0 -102
- package/src/wirings/channel/channel-handler-shapes.test.ts +0 -72
- package/src/wirings/channel/channel-handler.test.ts +0 -322
- package/src/wirings/channel/channel-handler.ts +0 -259
- package/src/wirings/channel/channel-host-rpc.test.ts +0 -150
- package/src/wirings/channel/channel-host-rpc.ts +0 -69
- package/src/wirings/channel/channel-middleware-runner.test.ts +0 -188
- package/src/wirings/channel/channel-middleware-runner.ts +0 -126
- package/src/wirings/channel/channel-rpc-registry.ts +0 -116
- package/src/wirings/channel/channel-rpc-responder.ts +0 -117
- package/src/wirings/channel/channel-rpc-service.ts +0 -132
- package/src/wirings/channel/channel-rpc-validators.ts +0 -65
- package/src/wirings/channel/channel-rpc.test.ts +0 -841
- package/src/wirings/channel/channel-rpc.ts +0 -5
- package/src/wirings/channel/channel-rpc.types.ts +0 -160
- package/src/wirings/channel/channel-runner.ts +0 -164
- package/src/wirings/channel/channel-store.ts +0 -35
- package/src/wirings/channel/channel.types.ts +0 -193
- package/src/wirings/channel/define-channel-routes.ts +0 -5
- package/src/wirings/channel/eventhub-service.ts +0 -16
- package/src/wirings/channel/eventhub-store.ts +0 -13
- package/src/wirings/channel/index.ts +0 -40
- package/src/wirings/channel/local/index.ts +0 -3
- package/src/wirings/channel/local/local-channel-handler.ts +0 -98
- package/src/wirings/channel/local/local-channel-runner.test.ts +0 -339
- package/src/wirings/channel/local/local-channel-runner.ts +0 -271
- package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -77
- package/src/wirings/channel/local/local-eventhub-service.ts +0 -69
- package/src/wirings/channel/log-channels.ts +0 -16
- package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +0 -135
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +0 -60
- package/src/wirings/channel/serverless/index.ts +0 -6
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +0 -328
- package/src/wirings/cli/channel/cli-approval.test.ts +0 -177
- package/src/wirings/cli/channel/cli-approval.ts +0 -135
- package/src/wirings/cli/channel/cli-channel-runner.ts +0 -118
- package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +0 -192
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +0 -148
- package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +0 -480
- package/src/wirings/cli/channel/cli-raw-client-runner.ts +0 -188
- package/src/wirings/cli/channel/index.ts +0 -6
- package/src/wirings/cli/cli-runner.test.ts +0 -969
- package/src/wirings/cli/cli-runner.ts +0 -538
- package/src/wirings/cli/cli.types.ts +0 -388
- package/src/wirings/cli/command-parser.test.ts +0 -1120
- package/src/wirings/cli/command-parser.ts +0 -713
- package/src/wirings/cli/define-cli-commands.ts +0 -13
- package/src/wirings/cli/format-cli-error.test.ts +0 -91
- package/src/wirings/cli/format-cli-error.ts +0 -96
- package/src/wirings/cli/index.ts +0 -19
- package/src/wirings/credential/credential.types.ts +0 -37
- package/src/wirings/credential/define-credential.ts +0 -49
- package/src/wirings/credential/index.ts +0 -7
- package/src/wirings/credential/validate-credential-definitions.ts +0 -63
- package/src/wirings/gateway/gateway-authorization.test.ts +0 -575
- package/src/wirings/gateway/gateway-channel-meta.test.ts +0 -44
- package/src/wirings/gateway/gateway-runner.test.ts +0 -581
- package/src/wirings/gateway/gateway-runner.ts +0 -411
- package/src/wirings/gateway/gateway.types.ts +0 -137
- package/src/wirings/gateway/index.ts +0 -15
- package/src/wirings/http/http-routes.test.ts +0 -318
- package/src/wirings/http/http-routes.ts +0 -111
- package/src/wirings/http/http-runner-addon-ref.test.ts +0 -238
- package/src/wirings/http/http-runner.test.ts +0 -503
- package/src/wirings/http/http-runner.ts +0 -462
- package/src/wirings/http/http.types.ts +0 -307
- package/src/wirings/http/index.ts +0 -27
- package/src/wirings/http/log-http-routes.ts +0 -18
- package/src/wirings/http/pikku-fetch-http-request.test.ts +0 -318
- package/src/wirings/http/pikku-fetch-http-request.ts +0 -260
- package/src/wirings/http/pikku-fetch-http-response.test.ts +0 -123
- package/src/wirings/http/pikku-fetch-http-response.ts +0 -149
- package/src/wirings/http/routers/http-router.ts +0 -13
- package/src/wirings/http/routers/path-to-regex.test.ts +0 -306
- package/src/wirings/http/routers/path-to-regex.ts +0 -115
- package/src/wirings/http/web-request.test.ts +0 -382
- package/src/wirings/http/web-request.ts +0 -162
- package/src/wirings/mcp/index.ts +0 -26
- package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -388
- package/src/wirings/mcp/mcp-endpoint-registry.ts +0 -159
- package/src/wirings/mcp/mcp-runner.test.ts +0 -588
- package/src/wirings/mcp/mcp-runner.ts +0 -330
- package/src/wirings/mcp/mcp.types.ts +0 -199
- package/src/wirings/node/index.ts +0 -2
- package/src/wirings/node/node.types.ts +0 -23
- package/src/wirings/oauth2/index.ts +0 -1
- package/src/wirings/oauth2/oauth2.types.ts +0 -12
- package/src/wirings/persona/define-personas.ts +0 -33
- package/src/wirings/persona/index.ts +0 -75
- package/src/wirings/persona/persona-app-scopes.test.ts +0 -47
- package/src/wirings/persona/persona-app-scopes.ts +0 -74
- package/src/wirings/persona/persona-email.ts +0 -87
- package/src/wirings/persona/persona-environments.test.ts +0 -194
- package/src/wirings/persona/persona-environments.ts +0 -138
- package/src/wirings/persona/persona-mailbox.ts +0 -156
- package/src/wirings/persona/persona.test.ts +0 -230
- package/src/wirings/persona/persona.types.ts +0 -156
- package/src/wirings/persona/validate-personas.ts +0 -137
- package/src/wirings/queue/index.ts +0 -29
- package/src/wirings/queue/queue-identity.test.ts +0 -454
- package/src/wirings/queue/queue-identity.ts +0 -176
- package/src/wirings/queue/queue-runner.test.ts +0 -705
- package/src/wirings/queue/queue-runner.ts +0 -181
- package/src/wirings/queue/queue.types.ts +0 -161
- package/src/wirings/queue/register-queue-helper.ts +0 -46
- package/src/wirings/queue/signed-queue-service.ts +0 -60
- package/src/wirings/queue/validate-worker-config.test.ts +0 -108
- package/src/wirings/queue/validate-worker-config.ts +0 -90
- package/src/wirings/role/define-system-role.ts +0 -33
- package/src/wirings/role/index.ts +0 -13
- package/src/wirings/role/role.test.ts +0 -104
- package/src/wirings/role/role.types.ts +0 -47
- package/src/wirings/role/validate-role-definitions.ts +0 -93
- package/src/wirings/rpc/index.ts +0 -8
- package/src/wirings/rpc/rpc-runner.test.ts +0 -1130
- package/src/wirings/rpc/rpc-runner.ts +0 -569
- package/src/wirings/rpc/rpc-types.ts +0 -87
- package/src/wirings/scheduler/index.ts +0 -11
- package/src/wirings/scheduler/log-schedulers.ts +0 -16
- package/src/wirings/scheduler/scheduler-runner.test.ts +0 -835
- package/src/wirings/scheduler/scheduler-runner.ts +0 -138
- package/src/wirings/scheduler/scheduler.types.ts +0 -42
- package/src/wirings/scope/define-scope.ts +0 -33
- package/src/wirings/scope/index.ts +0 -15
- package/src/wirings/scope/scope.test.ts +0 -159
- package/src/wirings/scope/scope.types.ts +0 -42
- package/src/wirings/scope/validate-scope-definitions.ts +0 -107
- package/src/wirings/secret/index.ts +0 -9
- package/src/wirings/secret/secret.types.ts +0 -70
- package/src/wirings/secret/validate-secret-definitions.test.ts +0 -232
- package/src/wirings/secret/validate-secret-definitions.ts +0 -88
- package/src/wirings/trigger/index.ts +0 -9
- package/src/wirings/trigger/pikku-trigger-service.ts +0 -107
- package/src/wirings/trigger/trigger-runner.test.ts +0 -78
- package/src/wirings/trigger/trigger-runner.ts +0 -113
- package/src/wirings/trigger/trigger.types.ts +0 -100
- package/src/wirings/variable/index.ts +0 -8
- package/src/wirings/variable/validate-variable-definitions.test.ts +0 -115
- package/src/wirings/variable/validate-variable-definitions.ts +0 -71
- package/src/wirings/variable/variable.types.ts +0 -40
- package/src/wirings/virtual-user/index.ts +0 -107
- package/src/wirings/virtual-user/prepare-virtual-user-run.test.ts +0 -115
- package/src/wirings/virtual-user/prepare-virtual-user-run.ts +0 -95
- package/src/wirings/virtual-user/run-virtual-user.test.ts +0 -774
- package/src/wirings/virtual-user/run-virtual-user.ts +0 -684
- package/src/wirings/virtual-user/virtual-user-agents.test.ts +0 -72
- package/src/wirings/virtual-user/virtual-user-agents.ts +0 -62
- package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +0 -215
- package/src/wirings/virtual-user/virtual-user-catalogue.ts +0 -184
- package/src/wirings/virtual-user/virtual-user-derive.test.ts +0 -426
- package/src/wirings/virtual-user/virtual-user-derive.ts +0 -161
- package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +0 -68
- package/src/wirings/virtual-user/virtual-user-dispositions.ts +0 -210
- package/src/wirings/virtual-user/virtual-user-intents.test.ts +0 -218
- package/src/wirings/virtual-user/virtual-user-intents.ts +0 -185
- package/src/wirings/virtual-user/virtual-user-rng.test.ts +0 -72
- package/src/wirings/virtual-user/virtual-user-rng.ts +0 -50
- package/src/wirings/virtual-user/virtual-user-run-store.ts +0 -131
- package/src/wirings/virtual-user/virtual-user-scaffold.test.ts +0 -854
- package/src/wirings/virtual-user/virtual-user-scaffold.ts +0 -664
- package/src/wirings/virtual-user/virtual-user-schedule-store.ts +0 -93
- package/src/wirings/virtual-user/virtual-user-schedule.test.ts +0 -280
- package/src/wirings/virtual-user/virtual-user-schedule.ts +0 -156
- package/src/wirings/virtual-user/virtual-user-target.ts +0 -47
- package/src/wirings/virtual-user/virtual-user.types.ts +0 -215
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +0 -709
- package/src/wirings/workflow/dsl/workflow-runner.ts +0 -25
- package/src/wirings/workflow/feature.test.ts +0 -131
- package/src/wirings/workflow/feature.ts +0 -59
- package/src/wirings/workflow/graph/graph-foreach-queued.test.ts +0 -569
- package/src/wirings/workflow/graph/graph-foreach.test.ts +0 -626
- package/src/wirings/workflow/graph/graph-node.ts +0 -115
- package/src/wirings/workflow/graph/graph-runner.test.ts +0 -1049
- package/src/wirings/workflow/graph/graph-runner.ts +0 -1376
- package/src/wirings/workflow/graph/graph-validation.test.ts +0 -27
- package/src/wirings/workflow/graph/graph-validation.ts +0 -41
- package/src/wirings/workflow/graph/template.test.ts +0 -49
- package/src/wirings/workflow/graph/template.ts +0 -42
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -39
- package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -75
- package/src/wirings/workflow/index.ts +0 -107
- package/src/wirings/workflow/pikku-scenario-service.ts +0 -1013
- package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -963
- package/src/wirings/workflow/pikku-workflow-service.ts +0 -1993
- package/src/wirings/workflow/run-timeline.test.ts +0 -199
- package/src/wirings/workflow/run-timeline.ts +0 -185
- package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -107
- package/src/wirings/workflow/scenario-cookie-jar.ts +0 -57
- package/src/wirings/workflow/scenario-expectations.test.ts +0 -238
- package/src/wirings/workflow/scenario-hooks.test.ts +0 -259
- package/src/wirings/workflow/scenario-poll.test.ts +0 -64
- package/src/wirings/workflow/scenario-poll.ts +0 -27
- package/src/wirings/workflow/scenario-prose.test.ts +0 -275
- package/src/wirings/workflow/scenario-prose.ts +0 -86
- package/src/wirings/workflow/scenario-run.types.ts +0 -193
- package/src/wirings/workflow/scenario-service.test.ts +0 -147
- package/src/wirings/workflow/scenario-step-guards.ts +0 -23
- package/src/wirings/workflow/scenario-step.test.ts +0 -800
- package/src/wirings/workflow/scenario-step.types.ts +0 -262
- package/src/wirings/workflow/scenario-surface.test.ts +0 -146
- package/src/wirings/workflow/scenario-surface.ts +0 -71
- package/src/wirings/workflow/scenario.types.ts +0 -63
- package/src/wirings/workflow/workflow-approval-audit.ts +0 -47
- package/src/wirings/workflow/workflow-approval-policy.test.ts +0 -594
- package/src/wirings/workflow/workflow-approval-policy.ts +0 -68
- package/src/wirings/workflow/workflow-approval.ts +0 -290
- package/src/wirings/workflow/workflow-child-run-session.test.ts +0 -168
- package/src/wirings/workflow/workflow-constants.ts +0 -66
- package/src/wirings/workflow/workflow-dispatch-durability.test.ts +0 -116
- package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -55
- package/src/wirings/workflow/workflow-dispatch-relay.test.ts +0 -128
- package/src/wirings/workflow/workflow-errors.ts +0 -132
- package/src/wirings/workflow/workflow-inline-authority.test.ts +0 -175
- package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -51
- package/src/wirings/workflow/workflow-invocation-id.ts +0 -28
- package/src/wirings/workflow/workflow-meta-resolver.ts +0 -45
- package/src/wirings/workflow/workflow-mirror.test.ts +0 -171
- package/src/wirings/workflow/workflow-missing-meta.test.ts +0 -92
- package/src/wirings/workflow/workflow-on-error.test.ts +0 -145
- package/src/wirings/workflow/workflow-queue-routing.ts +0 -129
- package/src/wirings/workflow/workflow-queue-wiring.ts +0 -149
- package/src/wirings/workflow/workflow-queue-workers.test.ts +0 -131
- package/src/wirings/workflow/workflow-queue-workers.ts +0 -66
- package/src/wirings/workflow/workflow-recovery.ts +0 -192
- package/src/wirings/workflow/workflow-replay-snapshot.test.ts +0 -140
- package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -113
- package/src/wirings/workflow/workflow-run-authority.test.ts +0 -212
- package/src/wirings/workflow/workflow-run-context.test.ts +0 -172
- package/src/wirings/workflow/workflow-run-engine.types.ts +0 -92
- package/src/wirings/workflow/workflow-run-ownership.ts +0 -37
- package/src/wirings/workflow/workflow-run-polling.test.ts +0 -127
- package/src/wirings/workflow/workflow-stalled-recovery.test.ts +0 -152
- package/src/wirings/workflow/workflow-status-stream.test.ts +0 -354
- package/src/wirings/workflow/workflow-status-stream.ts +0 -144
- package/src/wirings/workflow/workflow-step-claim.ts +0 -46
- package/src/wirings/workflow/workflow-step-ordinal.test.ts +0 -94
- package/src/wirings/workflow/workflow-step-session.test.ts +0 -87
- package/src/wirings/workflow/workflow-suspend.ts +0 -61
- package/src/wirings/workflow/workflow-terminal-run-guard.test.ts +0 -105
- package/src/wirings/workflow/workflow.types.ts +0 -268
- package/src/wirings-stay-decoupled.test.ts +0 -130
- package/tsconfig.json +0 -14
- package/tsconfig.tsbuildinfo +0 -1
- package/tsconfig.type-tests.json +0 -15
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import { describe, test } from 'node:test'
|
|
2
|
-
import assert from 'node:assert'
|
|
3
|
-
import { TypedSecretService } from './typed-secret-service.js'
|
|
4
|
-
|
|
5
|
-
const createMockSecrets = (store: Map<string, string> = new Map()) => ({
|
|
6
|
-
getSecret: async <T = string>(key: string): Promise<T> => {
|
|
7
|
-
const val = store.get(key)
|
|
8
|
-
if (!val) throw new Error(`Not found: ${key}`)
|
|
9
|
-
try {
|
|
10
|
-
return JSON.parse(val) as T
|
|
11
|
-
} catch {
|
|
12
|
-
return val as unknown as T
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
hasSecret: async (key: string) => store.has(key),
|
|
16
|
-
setSecret: async (key: string, value: unknown) => {
|
|
17
|
-
store.set(key, JSON.stringify(value))
|
|
18
|
-
},
|
|
19
|
-
deleteSecret: async (key: string) => {
|
|
20
|
-
store.delete(key)
|
|
21
|
-
},
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
describe('TypedSecretService', () => {
|
|
25
|
-
test('should delegate getSecret to underlying service', async () => {
|
|
26
|
-
const store = new Map([['API_KEY', '"sk-123"']])
|
|
27
|
-
const service = new TypedSecretService(createMockSecrets(store), {})
|
|
28
|
-
const result = await service.getSecret('API_KEY')
|
|
29
|
-
assert.strictEqual(result, 'sk-123')
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
test('should delegate getSecret with type to underlying service', async () => {
|
|
33
|
-
const store = new Map([['CONFIG', '{"port":3000}']])
|
|
34
|
-
const service = new TypedSecretService(createMockSecrets(store), {})
|
|
35
|
-
const result = await service.getSecret<{ port: number }>('CONFIG')
|
|
36
|
-
assert.deepStrictEqual(result, { port: 3000 })
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
test('should delegate hasSecret to underlying service', async () => {
|
|
40
|
-
const store = new Map([['EXISTS', '"val"']])
|
|
41
|
-
const service = new TypedSecretService(createMockSecrets(store), {})
|
|
42
|
-
assert.strictEqual(await service.hasSecret('EXISTS'), true)
|
|
43
|
-
assert.strictEqual(await service.hasSecret('MISSING'), false)
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
test('should delegate setSecret to underlying service', async () => {
|
|
47
|
-
const store = new Map<string, string>()
|
|
48
|
-
const service = new TypedSecretService(createMockSecrets(store), {})
|
|
49
|
-
await service.setSecret('NEW_KEY', { data: 'val' })
|
|
50
|
-
assert.strictEqual(store.get('NEW_KEY'), '{"data":"val"}')
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
test('should delegate deleteSecret to underlying service', async () => {
|
|
54
|
-
const store = new Map([['KEY', '"val"']])
|
|
55
|
-
const service = new TypedSecretService(createMockSecrets(store), {})
|
|
56
|
-
await service.deleteSecret('KEY')
|
|
57
|
-
assert.strictEqual(store.has('KEY'), false)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
test('should get all status for credentials', async () => {
|
|
61
|
-
const store = new Map([['STRIPE_KEY', '"sk-123"']])
|
|
62
|
-
const meta = {
|
|
63
|
-
STRIPE_KEY: { name: 'stripe', displayName: 'Stripe' },
|
|
64
|
-
GITHUB_TOKEN: {
|
|
65
|
-
name: 'github',
|
|
66
|
-
displayName: 'GitHub',
|
|
67
|
-
oauth2: { tokenSecretId: 'GH_TOKEN' },
|
|
68
|
-
},
|
|
69
|
-
}
|
|
70
|
-
const service = new TypedSecretService(createMockSecrets(store), meta)
|
|
71
|
-
const status = await service.getAllStatus()
|
|
72
|
-
assert.strictEqual(status.length, 2)
|
|
73
|
-
const stripeStatus = status.find((s) => s.secretId === 'STRIPE_KEY')!
|
|
74
|
-
assert.strictEqual(stripeStatus.isConfigured, true)
|
|
75
|
-
assert.strictEqual(stripeStatus.displayName, 'Stripe')
|
|
76
|
-
const ghStatus = status.find((s) => s.secretId === 'GITHUB_TOKEN')!
|
|
77
|
-
assert.strictEqual(ghStatus.isConfigured, false)
|
|
78
|
-
assert.deepStrictEqual(ghStatus.oauth2, { tokenSecretId: 'GH_TOKEN' })
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
test('should cache getSecret and not re-hit the underlying service', async () => {
|
|
82
|
-
let calls = 0
|
|
83
|
-
const inner = {
|
|
84
|
-
getSecret: async <T = string>(key: string): Promise<T> => {
|
|
85
|
-
calls++
|
|
86
|
-
return `v-${key}` as unknown as T
|
|
87
|
-
},
|
|
88
|
-
hasSecret: async () => true,
|
|
89
|
-
setSecret: async () => {},
|
|
90
|
-
deleteSecret: async () => {},
|
|
91
|
-
}
|
|
92
|
-
const service = new TypedSecretService(inner, {})
|
|
93
|
-
assert.strictEqual(await service.getSecret('K'), 'v-K')
|
|
94
|
-
assert.strictEqual(await service.getSecret('K'), 'v-K')
|
|
95
|
-
assert.strictEqual(calls, 1)
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
test('should invalidate the cache on setSecret and deleteSecret', async () => {
|
|
99
|
-
const store = new Map([['K', '"a"']])
|
|
100
|
-
const service = new TypedSecretService(createMockSecrets(store), {})
|
|
101
|
-
assert.strictEqual(await service.getSecret('K'), 'a')
|
|
102
|
-
await service.setSecret('K', 'b')
|
|
103
|
-
assert.strictEqual(await service.getSecret('K'), 'b')
|
|
104
|
-
await service.deleteSecret('K')
|
|
105
|
-
await assert.rejects(() => service.getSecret('K'))
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
test('should not cache a getSecret miss', async () => {
|
|
109
|
-
const store = new Map<string, string>()
|
|
110
|
-
const service = new TypedSecretService(createMockSecrets(store), {})
|
|
111
|
-
await assert.rejects(() => service.getSecret('K'))
|
|
112
|
-
store.set('K', '"now-here"')
|
|
113
|
-
assert.strictEqual(await service.getSecret('K'), 'now-here')
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
test('should get missing credentials', async () => {
|
|
117
|
-
const store = new Map([['STRIPE_KEY', '"sk-123"']])
|
|
118
|
-
const meta = {
|
|
119
|
-
STRIPE_KEY: { name: 'stripe', displayName: 'Stripe' },
|
|
120
|
-
GITHUB_TOKEN: { name: 'github', displayName: 'GitHub' },
|
|
121
|
-
}
|
|
122
|
-
const service = new TypedSecretService(createMockSecrets(store), meta)
|
|
123
|
-
const missing = await service.getMissing()
|
|
124
|
-
assert.strictEqual(missing.length, 1)
|
|
125
|
-
assert.strictEqual(missing[0].secretId, 'GITHUB_TOKEN')
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
test('an optional secret that is missing resolves undefined instead of throwing', async () => {
|
|
129
|
-
// getSecret throws for a missing secret, which is right for a required one:
|
|
130
|
-
// the app cannot run without it. An optional secret's absence is a supported
|
|
131
|
-
// state, so throwing forces every caller into a `.catch(() => null)` that
|
|
132
|
-
// also swallows a real vault failure.
|
|
133
|
-
const service = new TypedSecretService(createMockSecrets(), {
|
|
134
|
-
SCENARIO_ACTOR_SECRET: {
|
|
135
|
-
name: 'scenarioActor',
|
|
136
|
-
displayName: 'Scenario Actor Secret',
|
|
137
|
-
optional: true,
|
|
138
|
-
},
|
|
139
|
-
})
|
|
140
|
-
assert.strictEqual(
|
|
141
|
-
await service.getSecret('SCENARIO_ACTOR_SECRET'),
|
|
142
|
-
undefined
|
|
143
|
-
)
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
test('an optional secret that IS set resolves its value', async () => {
|
|
147
|
-
const store = new Map([['SCENARIO_ACTOR_SECRET', '"shh"']])
|
|
148
|
-
const service = new TypedSecretService(createMockSecrets(store), {
|
|
149
|
-
SCENARIO_ACTOR_SECRET: {
|
|
150
|
-
name: 'scenarioActor',
|
|
151
|
-
displayName: 'Scenario Actor Secret',
|
|
152
|
-
optional: true,
|
|
153
|
-
},
|
|
154
|
-
})
|
|
155
|
-
assert.strictEqual(await service.getSecret('SCENARIO_ACTOR_SECRET'), 'shh')
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
test('a missing secret still throws unless it declared itself optional', async () => {
|
|
159
|
-
const service = new TypedSecretService(createMockSecrets(), {
|
|
160
|
-
STRIPE_KEY: { name: 'stripe', displayName: 'Stripe' },
|
|
161
|
-
})
|
|
162
|
-
await assert.rejects(() => service.getSecret('STRIPE_KEY'))
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
test('a resolved-absent optional secret still reports hasSecret false', async () => {
|
|
166
|
-
// The cache stores `undefined` to remember the absence, so a `has(key)`
|
|
167
|
-
// test on it answers "we have looked", not "there is a value". Reading an
|
|
168
|
-
// optional secret must not turn its own absence into a claim it is set.
|
|
169
|
-
const service = new TypedSecretService(createMockSecrets(), {
|
|
170
|
-
OPTIONAL: { name: 'opt', displayName: 'Optional', optional: true },
|
|
171
|
-
})
|
|
172
|
-
assert.strictEqual(await service.getSecret('OPTIONAL'), undefined)
|
|
173
|
-
assert.strictEqual(await service.hasSecret('OPTIONAL'), false)
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
test('an optional secret set after an absent read is picked up', async () => {
|
|
177
|
-
const store = new Map<string, string>()
|
|
178
|
-
const service = new TypedSecretService(createMockSecrets(store), {
|
|
179
|
-
OPTIONAL: { name: 'opt', displayName: 'Optional', optional: true },
|
|
180
|
-
})
|
|
181
|
-
assert.strictEqual(await service.getSecret('OPTIONAL'), undefined)
|
|
182
|
-
await service.setSecret('OPTIONAL', 'later')
|
|
183
|
-
assert.strictEqual(await service.hasSecret('OPTIONAL'), true)
|
|
184
|
-
assert.strictEqual(await service.getSecret('OPTIONAL'), 'later')
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
test('an optional secret does not re-hit the store once resolved', async () => {
|
|
188
|
-
let reads = 0
|
|
189
|
-
const base = createMockSecrets()
|
|
190
|
-
const service = new TypedSecretService(
|
|
191
|
-
{
|
|
192
|
-
...base,
|
|
193
|
-
hasSecret: async (key: string) => {
|
|
194
|
-
reads++
|
|
195
|
-
return base.hasSecret(key)
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
{ OPTIONAL: { name: 'opt', displayName: 'Optional', optional: true } }
|
|
199
|
-
)
|
|
200
|
-
await service.getSecret('OPTIONAL')
|
|
201
|
-
await service.getSecret('OPTIONAL')
|
|
202
|
-
assert.strictEqual(reads, 1)
|
|
203
|
-
})
|
|
204
|
-
})
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import type { SecretValue } from '../classification/secret-value.js'
|
|
2
|
-
import type { SecretService, SecretValues } from './secret-service.js'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* The wrapper, or `undefined` when the generated map declares the key as an
|
|
6
|
-
* optional property. The `undefined` has to be lifted OUT of `SecretValue` —
|
|
7
|
-
* a missing optional secret resolves to `undefined` itself, not to a wrapper
|
|
8
|
-
* around it, so `SecretValue<T | undefined>` would type a value that never
|
|
9
|
-
* exists and hide the `undefined` behind a `.reveal()` the caller never reaches.
|
|
10
|
-
*/
|
|
11
|
-
export type SecretResult<T> = undefined extends T
|
|
12
|
-
? SecretValue<Exclude<T, undefined>> | undefined
|
|
13
|
-
: SecretValue<T>
|
|
14
|
-
|
|
15
|
-
export interface CredentialStatus {
|
|
16
|
-
secretId: string
|
|
17
|
-
name: string
|
|
18
|
-
displayName: string
|
|
19
|
-
isConfigured: boolean
|
|
20
|
-
oauth2?: { tokenSecretId: string }
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export type CredentialMeta = {
|
|
24
|
-
name: string
|
|
25
|
-
displayName: string
|
|
26
|
-
/**
|
|
27
|
-
* Declared `optional: true`, so absence is a supported state rather than a
|
|
28
|
-
* misconfiguration. The generated map types the key as an optional property,
|
|
29
|
-
* which is what puts `undefined` in `getSecret`'s return type.
|
|
30
|
-
*/
|
|
31
|
-
optional?: boolean
|
|
32
|
-
oauth2?: { tokenSecretId: string }
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export class TypedSecretService<
|
|
36
|
-
TMap = Record<string, unknown>,
|
|
37
|
-
> implements SecretService {
|
|
38
|
-
// knowledge: decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md
|
|
39
|
-
private cache = new Map<string, unknown>()
|
|
40
|
-
|
|
41
|
-
constructor(
|
|
42
|
-
private secrets: SecretService,
|
|
43
|
-
private credentialsMeta: Record<string, CredentialMeta>
|
|
44
|
-
) {}
|
|
45
|
-
|
|
46
|
-
async getSecret<K extends keyof TMap & string>(
|
|
47
|
-
key: K
|
|
48
|
-
): Promise<SecretResult<TMap[K]>>
|
|
49
|
-
async getSecret<T = string>(key: string): Promise<SecretValue<T>>
|
|
50
|
-
async getSecret(key: string): Promise<unknown> {
|
|
51
|
-
if (this.cache.has(key)) {
|
|
52
|
-
return this.cache.get(key)
|
|
53
|
-
}
|
|
54
|
-
if (
|
|
55
|
-
this.credentialsMeta[key]?.optional &&
|
|
56
|
-
!(await this.secrets.hasSecret(key))
|
|
57
|
-
) {
|
|
58
|
-
this.cache.set(key, undefined)
|
|
59
|
-
return undefined
|
|
60
|
-
}
|
|
61
|
-
const value = await this.secrets.getSecret(key)
|
|
62
|
-
this.cache.set(key, value)
|
|
63
|
-
return value
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async hasSecret(key: string): Promise<boolean> {
|
|
67
|
-
// `undefined` is cached for an optional secret that resolved absent, so a
|
|
68
|
-
// cache hit means "already looked", not "there is a value". Reporting true
|
|
69
|
-
// for it would let a read of an optional secret assert its own presence.
|
|
70
|
-
if (this.cache.has(key)) {
|
|
71
|
-
return this.cache.get(key) !== undefined
|
|
72
|
-
}
|
|
73
|
-
return this.secrets.hasSecret(key)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async setSecret<K extends string>(
|
|
77
|
-
key: K,
|
|
78
|
-
value: K extends keyof TMap ? TMap[K] : unknown
|
|
79
|
-
): Promise<void> {
|
|
80
|
-
await this.secrets.setSecret(key, value)
|
|
81
|
-
this.cache.delete(key)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async deleteSecret(key: string): Promise<void> {
|
|
85
|
-
await this.secrets.deleteSecret(key)
|
|
86
|
-
this.cache.delete(key)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async getSecrets<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
90
|
-
keys: (keyof T & string)[]
|
|
91
|
-
): Promise<Partial<SecretValues<T>>> {
|
|
92
|
-
const result: Partial<SecretValues<T>> = {}
|
|
93
|
-
const missing: (keyof T & string)[] = []
|
|
94
|
-
for (const key of keys) {
|
|
95
|
-
if (this.cache.has(key)) {
|
|
96
|
-
result[key] = this.cache.get(key) as SecretValues<T>[keyof T & string]
|
|
97
|
-
} else {
|
|
98
|
-
missing.push(key)
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (missing.length > 0) {
|
|
102
|
-
const fetched = await this.secrets.getSecrets<T>(missing)
|
|
103
|
-
for (const [key, value] of Object.entries(fetched)) {
|
|
104
|
-
this.cache.set(key, value)
|
|
105
|
-
result[key as keyof T & string] = value as SecretValues<T>[keyof T &
|
|
106
|
-
string]
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return result
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async getAllStatus(): Promise<CredentialStatus[]> {
|
|
113
|
-
const results: CredentialStatus[] = []
|
|
114
|
-
|
|
115
|
-
for (const [secretId, meta] of Object.entries(this.credentialsMeta)) {
|
|
116
|
-
results.push({
|
|
117
|
-
secretId,
|
|
118
|
-
name: meta.name,
|
|
119
|
-
displayName: meta.displayName,
|
|
120
|
-
isConfigured: await this.secrets.hasSecret(secretId),
|
|
121
|
-
oauth2: meta.oauth2,
|
|
122
|
-
})
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return results
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async getMissing(): Promise<CredentialStatus[]> {
|
|
129
|
-
const all = await this.getAllStatus()
|
|
130
|
-
return all.filter((c) => !c.isConfigured)
|
|
131
|
-
}
|
|
132
|
-
}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { describe, test } from 'node:test'
|
|
2
|
-
import assert from 'node:assert'
|
|
3
|
-
import { TypedVariablesService } from './typed-variables-service.js'
|
|
4
|
-
import { LocalVariablesService } from './local-variables.js'
|
|
5
|
-
import type { StandardSchemaV1 } from '@standard-schema/spec'
|
|
6
|
-
|
|
7
|
-
describe('TypedVariablesService', () => {
|
|
8
|
-
const createService = (vars: Record<string, string | undefined> = {}) => {
|
|
9
|
-
const underlying = new LocalVariablesService(vars)
|
|
10
|
-
const meta = {
|
|
11
|
-
DB_URL: { name: 'DB_URL', displayName: 'Database URL' },
|
|
12
|
-
API_KEY: { name: 'API_KEY', displayName: 'API Key' },
|
|
13
|
-
}
|
|
14
|
-
return new TypedVariablesService(underlying, meta)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
test('should delegate get to underlying service', () => {
|
|
18
|
-
const service = createService({ DB_URL: 'postgres://...' })
|
|
19
|
-
assert.strictEqual(service.get('DB_URL'), 'postgres://...')
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
test('should delegate set to underlying service', () => {
|
|
23
|
-
const service = createService()
|
|
24
|
-
service.set('DB_URL', 'new-value')
|
|
25
|
-
assert.strictEqual(service.get('DB_URL'), 'new-value')
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test('should delegate has to underlying service', () => {
|
|
29
|
-
const service = createService({ DB_URL: 'val' })
|
|
30
|
-
assert.strictEqual(service.has('DB_URL'), true)
|
|
31
|
-
assert.strictEqual(service.has('MISSING'), false)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
test('should delegate delete to underlying service', () => {
|
|
35
|
-
const service = createService({ DB_URL: 'val' })
|
|
36
|
-
service.delete('DB_URL')
|
|
37
|
-
assert.strictEqual(service.has('DB_URL'), false)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
test('should delegate get to underlying service', () => {
|
|
41
|
-
const service = createService({ DATA: '{"key":"val"}' })
|
|
42
|
-
assert.deepStrictEqual(service.get('DATA'), { key: 'val' })
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
test('should delegate set to underlying service', () => {
|
|
46
|
-
const service = createService()
|
|
47
|
-
service.set('DATA', { key: 'val' })
|
|
48
|
-
assert.deepStrictEqual(service.get('DATA'), { key: 'val' })
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
test('should get all status for configured variables', async () => {
|
|
52
|
-
const service = createService({ DB_URL: 'postgres://...' })
|
|
53
|
-
const status = await service.getAllStatus()
|
|
54
|
-
assert.strictEqual(status.length, 2)
|
|
55
|
-
const dbStatus = status.find((s) => s.variableId === 'DB_URL')!
|
|
56
|
-
assert.strictEqual(dbStatus.isConfigured, true)
|
|
57
|
-
assert.strictEqual(dbStatus.displayName, 'Database URL')
|
|
58
|
-
const apiStatus = status.find((s) => s.variableId === 'API_KEY')!
|
|
59
|
-
assert.strictEqual(apiStatus.isConfigured, false)
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
test('should get missing variables', async () => {
|
|
63
|
-
const service = createService({ DB_URL: 'val' })
|
|
64
|
-
const missing = await service.getMissing()
|
|
65
|
-
assert.strictEqual(missing.length, 1)
|
|
66
|
-
assert.strictEqual(missing[0].variableId, 'API_KEY')
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
test('should return empty missing when all configured', async () => {
|
|
70
|
-
const service = createService({ DB_URL: 'val', API_KEY: 'key' })
|
|
71
|
-
const missing = await service.getMissing()
|
|
72
|
-
assert.strictEqual(missing.length, 0)
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Stands in for `z.enum([...]).default(...)`: a schema that answers `undefined`
|
|
78
|
-
* with a value rather than an issue. Core declares no schema library of its
|
|
79
|
-
* own, so the contract under test is Standard Schema's, not Zod's.
|
|
80
|
-
*/
|
|
81
|
-
const withDefault = <T>(value: T): StandardSchemaV1<unknown, T> => ({
|
|
82
|
-
'~standard': {
|
|
83
|
-
version: 1,
|
|
84
|
-
vendor: 'test',
|
|
85
|
-
validate: (input: unknown) =>
|
|
86
|
-
input === undefined ? { value } : { value: input as T },
|
|
87
|
-
},
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
const noDefault: StandardSchemaV1<unknown, string> = {
|
|
91
|
-
'~standard': {
|
|
92
|
-
version: 1,
|
|
93
|
-
vendor: 'test',
|
|
94
|
-
validate: (input: unknown) =>
|
|
95
|
-
typeof input === 'string'
|
|
96
|
-
? { value: input }
|
|
97
|
-
: { issues: [{ message: 'expected a string' }] },
|
|
98
|
-
},
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
describe('TypedVariablesService schema defaults', () => {
|
|
102
|
-
const createService = (vars: Record<string, string | undefined> = {}) =>
|
|
103
|
-
new TypedVariablesService(new LocalVariablesService(vars), {
|
|
104
|
-
GITHUB_BASE_URL: {
|
|
105
|
-
name: 'GITHUB_BASE_URL',
|
|
106
|
-
displayName: 'GitHub Base URL',
|
|
107
|
-
schema: withDefault('https://api.github.com'),
|
|
108
|
-
},
|
|
109
|
-
API_KEY: {
|
|
110
|
-
name: 'API_KEY',
|
|
111
|
-
displayName: 'API Key',
|
|
112
|
-
schema: noDefault,
|
|
113
|
-
},
|
|
114
|
-
// The form code generation emits, deferred past the import cycle.
|
|
115
|
-
REGION: {
|
|
116
|
-
name: 'REGION',
|
|
117
|
-
displayName: 'Region',
|
|
118
|
-
schema: () => withDefault('eu-west-1'),
|
|
119
|
-
},
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
test('resolves a declared default when the host sets nothing', async () => {
|
|
123
|
-
const service = createService()
|
|
124
|
-
assert.strictEqual(
|
|
125
|
-
await service.get('GITHUB_BASE_URL'),
|
|
126
|
-
'https://api.github.com'
|
|
127
|
-
)
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
test('prefers the host value over the default', async () => {
|
|
131
|
-
const service = createService({ GITHUB_BASE_URL: 'https://ghe.internal' })
|
|
132
|
-
assert.strictEqual(
|
|
133
|
-
await service.get('GITHUB_BASE_URL'),
|
|
134
|
-
'https://ghe.internal'
|
|
135
|
-
)
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
test('stays undefined when the schema carries no default', async () => {
|
|
139
|
-
const service = createService()
|
|
140
|
-
assert.strictEqual(await service.get('API_KEY'), undefined)
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
test('resolves a default behind a thunk', async () => {
|
|
144
|
-
const service = createService()
|
|
145
|
-
assert.strictEqual(await service.get('REGION'), 'eu-west-1')
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
test('a defaulted variable is not missing', async () => {
|
|
149
|
-
const service = createService()
|
|
150
|
-
const missing = await service.getMissing()
|
|
151
|
-
assert.deepStrictEqual(
|
|
152
|
-
missing.map((v) => v.variableId),
|
|
153
|
-
['API_KEY']
|
|
154
|
-
)
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
test('status separates having a default from being configured', async () => {
|
|
158
|
-
const service = createService()
|
|
159
|
-
const status = await service.getAllStatus()
|
|
160
|
-
const github = status.find((s) => s.variableId === 'GITHUB_BASE_URL')!
|
|
161
|
-
assert.strictEqual(github.isConfigured, false)
|
|
162
|
-
assert.strictEqual(github.hasDefault, true)
|
|
163
|
-
const apiKey = status.find((s) => s.variableId === 'API_KEY')!
|
|
164
|
-
assert.strictEqual(apiKey.hasDefault, false)
|
|
165
|
-
})
|
|
166
|
-
})
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import type { StandardSchemaV1 } from '@standard-schema/spec'
|
|
2
|
-
import type { VariablesService } from './variables-service.js'
|
|
3
|
-
|
|
4
|
-
export interface VariableStatus {
|
|
5
|
-
variableId: string
|
|
6
|
-
name: string
|
|
7
|
-
displayName: string
|
|
8
|
-
isConfigured: boolean
|
|
9
|
-
/** Whether the declaration answers for itself when the host sets nothing. */
|
|
10
|
-
hasDefault: boolean
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export type VariableMeta = {
|
|
14
|
-
name: string
|
|
15
|
-
displayName: string
|
|
16
|
-
/**
|
|
17
|
-
* The shape the variable was declared with. It is the schema itself rather
|
|
18
|
-
* than a description of it, because a default is only knowable by running it:
|
|
19
|
-
* `undefined` goes in and, if the declaration carries one, the default comes
|
|
20
|
-
* back out.
|
|
21
|
-
*
|
|
22
|
-
* A thunk is accepted, and is what code generation emits. The generated file
|
|
23
|
-
* and the file declaring the schema import each other, so reading the schema
|
|
24
|
-
* while the modules are still initializing throws — deferring the read until
|
|
25
|
-
* a variable is actually asked for is what keeps the cycle harmless.
|
|
26
|
-
*/
|
|
27
|
-
schema?: StandardSchemaV1 | (() => StandardSchemaV1)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const isPromise = (value: unknown): value is Promise<unknown> =>
|
|
31
|
-
typeof (value as Promise<unknown> | undefined)?.then === 'function'
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* A declared default is the answer to a variable nobody set, so it is resolved
|
|
35
|
-
* here rather than in `VariablesService`: the store knows what a host has put
|
|
36
|
-
* in it, and only this layer knows what was declared.
|
|
37
|
-
*/
|
|
38
|
-
export class TypedVariablesService<
|
|
39
|
-
TMap = Record<string, unknown>,
|
|
40
|
-
> implements VariablesService {
|
|
41
|
-
constructor(
|
|
42
|
-
private variables: VariablesService,
|
|
43
|
-
private variablesMeta: Record<string, VariableMeta>
|
|
44
|
-
) {}
|
|
45
|
-
|
|
46
|
-
get<K extends keyof TMap & string>(
|
|
47
|
-
name: K
|
|
48
|
-
): Promise<TMap[K] | undefined> | TMap[K] | undefined
|
|
49
|
-
get<T = string>(name: string): Promise<T | undefined> | T | undefined
|
|
50
|
-
get(name: string): Promise<unknown> | unknown {
|
|
51
|
-
const stored = this.variables.get(name)
|
|
52
|
-
if (isPromise(stored)) {
|
|
53
|
-
return stored.then((value) =>
|
|
54
|
-
value === undefined ? this.resolveDefault(name) : value
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
return stored === undefined ? this.resolveDefault(name) : stored
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
getVariables<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
61
|
-
names: (keyof T & string)[]
|
|
62
|
-
): Promise<Partial<T>> | Partial<T> {
|
|
63
|
-
const stored = this.variables.getVariables<T>(names)
|
|
64
|
-
if (isPromise(stored)) {
|
|
65
|
-
return stored.then((values) => this.withDefaults(names, values))
|
|
66
|
-
}
|
|
67
|
-
return this.withDefaults(names, stored)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
getAll():
|
|
71
|
-
| Promise<Record<string, string | undefined>>
|
|
72
|
-
| Record<string, string | undefined> {
|
|
73
|
-
return this.variables.getAll()
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
set(name: string, value: unknown): Promise<void> | void {
|
|
77
|
-
return this.variables.set(name, value)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
has(name: string): Promise<boolean> | boolean {
|
|
81
|
-
return this.variables.has(name)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
delete(name: string): Promise<void> | void {
|
|
85
|
-
return this.variables.delete(name)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async getAllStatus(): Promise<VariableStatus[]> {
|
|
89
|
-
const results: VariableStatus[] = []
|
|
90
|
-
const all = await this.variables.getAll()
|
|
91
|
-
|
|
92
|
-
for (const [variableId, meta] of Object.entries(this.variablesMeta)) {
|
|
93
|
-
results.push({
|
|
94
|
-
variableId,
|
|
95
|
-
name: meta.name,
|
|
96
|
-
displayName: meta.displayName,
|
|
97
|
-
isConfigured: all[variableId] !== undefined,
|
|
98
|
-
hasDefault: (await this.resolveDefault(variableId)) !== undefined,
|
|
99
|
-
})
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return results
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* What a deployment still has to be told. A variable that defaults is not on
|
|
107
|
-
* this list — it has a value, just not one anybody has to supply.
|
|
108
|
-
*/
|
|
109
|
-
async getMissing(): Promise<VariableStatus[]> {
|
|
110
|
-
const all = await this.getAllStatus()
|
|
111
|
-
return all.filter((v) => !v.isConfigured && !v.hasDefault)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* The value the declaration answers with when the host set nothing, or
|
|
116
|
-
* `undefined` when it does not answer for itself.
|
|
117
|
-
*/
|
|
118
|
-
private resolveDefault(name: string): Promise<unknown> | unknown {
|
|
119
|
-
const declared = this.variablesMeta[name]?.schema
|
|
120
|
-
if (!declared) {
|
|
121
|
-
return undefined
|
|
122
|
-
}
|
|
123
|
-
const schema = typeof declared === 'function' ? declared() : declared
|
|
124
|
-
const result = schema['~standard'].validate(undefined)
|
|
125
|
-
if (isPromise(result)) {
|
|
126
|
-
return result.then(unwrapDefault)
|
|
127
|
-
}
|
|
128
|
-
return unwrapDefault(result)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Kept synchronous when the defaults resolve synchronously, so a caller that
|
|
133
|
-
* did not await `getVariables` before does not have to start.
|
|
134
|
-
*/
|
|
135
|
-
private withDefaults<T extends Record<string, unknown>>(
|
|
136
|
-
names: (keyof T & string)[],
|
|
137
|
-
values: Partial<T>
|
|
138
|
-
): Promise<Partial<T>> | Partial<T> {
|
|
139
|
-
const out: Record<string, unknown> = { ...values }
|
|
140
|
-
const pending: Promise<void>[] = []
|
|
141
|
-
for (const name of names) {
|
|
142
|
-
if (out[name] !== undefined) continue
|
|
143
|
-
const fallback = this.resolveDefault(name)
|
|
144
|
-
if (isPromise(fallback)) {
|
|
145
|
-
pending.push(
|
|
146
|
-
fallback.then((value) => {
|
|
147
|
-
if (value !== undefined) out[name] = value
|
|
148
|
-
})
|
|
149
|
-
)
|
|
150
|
-
} else if (fallback !== undefined) {
|
|
151
|
-
out[name] = fallback
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (pending.length > 0) {
|
|
155
|
-
return Promise.all(pending).then(() => out as Partial<T>)
|
|
156
|
-
}
|
|
157
|
-
return out as Partial<T>
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* A schema with no default rejects `undefined`, which is not a failure here —
|
|
163
|
-
* it is the answer that there is nothing to fall back to.
|
|
164
|
-
*/
|
|
165
|
-
const unwrapDefault = (result: StandardSchemaV1.Result<unknown>) =>
|
|
166
|
-
result.issues ? undefined : result.value
|