@pikku/core 0.12.106 → 0.12.111
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 +358 -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/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/rpc/rpc-runner.js +3 -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/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 -566
- 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,1013 +0,0 @@
|
|
|
1
|
-
import { runPikkuFunc } from '../../function/function-runner.js'
|
|
2
|
-
import {
|
|
3
|
-
getSingletonServices,
|
|
4
|
-
getCreateWireServices,
|
|
5
|
-
pikkuState,
|
|
6
|
-
} from '../../pikku-state.js'
|
|
7
|
-
import { getDurationInMilliseconds } from '../../time-utils.js'
|
|
8
|
-
import { closeWireServices } from '../../utils.js'
|
|
9
|
-
import { PikkuError, addError } from '../../errors/error-handler.js'
|
|
10
|
-
import { InMemoryWorkflowService } from '../../services/in-memory-workflow-service.js'
|
|
11
|
-
import { runScheduledTask } from '../scheduler/scheduler-runner.js'
|
|
12
|
-
import { WorkflowStepNameNotString } from './workflow-errors.js'
|
|
13
|
-
import type {
|
|
14
|
-
RunLifecycleContext,
|
|
15
|
-
WorkflowRunEngine,
|
|
16
|
-
WorkflowRunExtension,
|
|
17
|
-
} from './workflow-run-engine.types.js'
|
|
18
|
-
import type { PikkuRawWire } from '../../types/core.types.js'
|
|
19
|
-
import type { ScenarioPersonas } from '../../services/personas-service.js'
|
|
20
|
-
import type { CorePikkuFunctionConfig } from '../../function/functions.types.js'
|
|
21
|
-
import type {
|
|
22
|
-
ScenarioBrowserProvider,
|
|
23
|
-
ScenarioEnvironment,
|
|
24
|
-
ScenarioStepOptions,
|
|
25
|
-
ScenarioStepPhase,
|
|
26
|
-
ScenarioSurface,
|
|
27
|
-
} from './scenario-step.types.js'
|
|
28
|
-
import { resolveScenarioSurfaces, witnessesAgree } from './scenario-surface.js'
|
|
29
|
-
import type {
|
|
30
|
-
PikkuWorkflowWire,
|
|
31
|
-
WorkflowQueueOptions,
|
|
32
|
-
} from './workflow.types.js'
|
|
33
|
-
import type { PikkuScenarioWire } from './scenario.types.js'
|
|
34
|
-
import type {
|
|
35
|
-
WorkflowExpectEventuallyOptions,
|
|
36
|
-
WorkflowExpectErrorOptions,
|
|
37
|
-
WorkflowExpectScoreOptions,
|
|
38
|
-
WorkflowExpectServiceOptions,
|
|
39
|
-
WorkflowStepOptions,
|
|
40
|
-
} from './dsl/workflow-dsl.types.js'
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* The retry default for the `expect*` family: none, the same as `given`,
|
|
44
|
-
* `when` and `then` take, and for the same reason — a failed assertion is a
|
|
45
|
-
* result, not a transient fault.
|
|
46
|
-
*
|
|
47
|
-
* Left to the workflow-wide `DEFAULT_STEP_RETRIES` they get six attempts each,
|
|
48
|
-
* which re-runs the RPC behind a failing `expectError`, restarts a whole
|
|
49
|
-
* `expectEventually` poll after it has already spent its own deadline, and
|
|
50
|
-
* lets a live judge re-roll a grade until one lands inside the band. The last
|
|
51
|
-
* of those is how it was found: a judge scored a deliberately useless answer
|
|
52
|
-
* 1, and the scenario went green anyway on the next attempt.
|
|
53
|
-
*
|
|
54
|
-
* A caller that genuinely wants attempts still asks for them.
|
|
55
|
-
*/
|
|
56
|
-
const assertionStep = <T extends WorkflowStepOptions>(
|
|
57
|
-
options?: T
|
|
58
|
-
): T & { retries: number } =>
|
|
59
|
-
({ ...options, retries: options?.retries ?? 0 }) as T & { retries: number }
|
|
60
|
-
|
|
61
|
-
export { addFeature, resolveFeatureScenarios } from './feature.js'
|
|
62
|
-
export type {
|
|
63
|
-
CoreFeature,
|
|
64
|
-
CoreFeatureScenario,
|
|
65
|
-
FeatureMeta,
|
|
66
|
-
FeaturesMeta,
|
|
67
|
-
PikkuBrowserWire,
|
|
68
|
-
PikkuScenarioWire,
|
|
69
|
-
ScenarioBrowserFailure,
|
|
70
|
-
ScenarioBrowserProvider,
|
|
71
|
-
ScenarioEnvironment,
|
|
72
|
-
ScenarioStepKind,
|
|
73
|
-
ScenarioStepMeta,
|
|
74
|
-
ScenarioStepOptions,
|
|
75
|
-
ScenarioStepPhase,
|
|
76
|
-
ScenarioSurface,
|
|
77
|
-
TestIdSelector,
|
|
78
|
-
} from './scenario.types.js'
|
|
79
|
-
export type {
|
|
80
|
-
ScenarioArtifact,
|
|
81
|
-
ScenarioFailureDetail,
|
|
82
|
-
ScenarioResult,
|
|
83
|
-
ScenarioRunRecord,
|
|
84
|
-
ScenarioRunReport,
|
|
85
|
-
ScenarioRunStatus,
|
|
86
|
-
ScenarioRunStore,
|
|
87
|
-
ScenarioRunSummary,
|
|
88
|
-
ScenarioStepRow,
|
|
89
|
-
} from './scenario-run.types.js'
|
|
90
|
-
export { SCENARIO_SURFACES } from './scenario-step.types.js'
|
|
91
|
-
|
|
92
|
-
// Which of a step's bindings run: one for an action, every witness for a `then`
|
|
93
|
-
export { resolveScenarioSurfaces } from './scenario-surface.js'
|
|
94
|
-
|
|
95
|
-
export { pollUntil, type PollOptions } from './scenario-poll.js'
|
|
96
|
-
export { createCookieJar } from './scenario-cookie-jar.js'
|
|
97
|
-
export type { ScenarioCookieJar } from './scenario-cookie-jar.js'
|
|
98
|
-
export { composeStepProse, renderStepTemplate } from './scenario-prose.js'
|
|
99
|
-
|
|
100
|
-
export { requireScenarioEnv } from './scenario-step-guards.js'
|
|
101
|
-
|
|
102
|
-
export type {
|
|
103
|
-
ScenarioHttpResponse,
|
|
104
|
-
ScenarioJsonRequest,
|
|
105
|
-
} from '../../services/personas-service.js'
|
|
106
|
-
// The readers themselves live on `@pikku/core/persona`
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* A workflow service with the scenario capability attached — the two lines
|
|
110
|
-
* `pikku scenario run` needs, in one call so no caller has to remember that the
|
|
111
|
-
* capability is installed rather than inherited.
|
|
112
|
-
*
|
|
113
|
-
* The in-memory service is the right engine because a scenario run is a single
|
|
114
|
-
* external process driving a deployed app over its real transport: there is
|
|
115
|
-
* nothing to persist and no second worker to resume it.
|
|
116
|
-
*/
|
|
117
|
-
export const createScenarioRunner = (
|
|
118
|
-
options: WorkflowQueueOptions = {}
|
|
119
|
-
): {
|
|
120
|
-
workflowService: InMemoryWorkflowService
|
|
121
|
-
scenarioService: PikkuScenarioService
|
|
122
|
-
} => {
|
|
123
|
-
const workflowService = new InMemoryWorkflowService(options)
|
|
124
|
-
const scenarioService = workflowService.setRunExtension(
|
|
125
|
-
(engine) => new PikkuScenarioService(engine)
|
|
126
|
-
)
|
|
127
|
-
return { workflowService, scenarioService }
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* A scenario lifecycle callback, erased to its runtime shape. The typed form a
|
|
132
|
-
* project writes against lives on the generated `pikkuScenario` config; by the
|
|
133
|
-
* time the service reaches it, it is just a function taking the same three
|
|
134
|
-
* arguments the scenario body takes.
|
|
135
|
-
*/
|
|
136
|
-
type ScenarioHook = (
|
|
137
|
-
services: any,
|
|
138
|
-
data: any,
|
|
139
|
-
wire: PikkuRawWire
|
|
140
|
-
) => Promise<void> | void
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Everything a scenario step needs from the wire that created it. Passed as a
|
|
144
|
-
* bundle so `given`/`when`/`then` stay one-liners.
|
|
145
|
-
*/
|
|
146
|
-
interface ScenarioStepContext {
|
|
147
|
-
runId: string
|
|
148
|
-
workflowName: string
|
|
149
|
-
addonNamespace?: string | null
|
|
150
|
-
workflowWire: PikkuScenarioWire
|
|
151
|
-
rpcService: any
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* A scenario's `before` or `after` hook threw. The original error is kept as
|
|
156
|
-
* the `cause` so the failure that actually happened is never lost behind the
|
|
157
|
-
* label saying which phase it happened in.
|
|
158
|
-
*/
|
|
159
|
-
export class ScenarioHookError extends PikkuError {
|
|
160
|
-
constructor(
|
|
161
|
-
public readonly scenarioName: string,
|
|
162
|
-
public readonly phase: 'before' | 'after',
|
|
163
|
-
cause: unknown
|
|
164
|
-
) {
|
|
165
|
-
super(
|
|
166
|
-
`Scenario '${scenarioName}' ${phase} hook failed: ${
|
|
167
|
-
cause instanceof Error ? cause.message : String(cause)
|
|
168
|
-
}`
|
|
169
|
-
)
|
|
170
|
-
this.cause = cause
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
addError(ScenarioHookError, {
|
|
174
|
-
status: 500,
|
|
175
|
-
message: 'A scenario lifecycle hook failed.',
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Two witnesses of the same `then` disagreed.
|
|
180
|
-
*
|
|
181
|
-
* This is the failure the whole additive-witness design exists to produce: the
|
|
182
|
-
* system of record is right and the surface the actor was looking at is not, or
|
|
183
|
-
* the other way round. Both observations go in the message, because either one
|
|
184
|
-
* alone reads as a passing assertion.
|
|
185
|
-
*/
|
|
186
|
-
export class ScenarioWitnessDisagreement extends PikkuError {
|
|
187
|
-
constructor(
|
|
188
|
-
public readonly stepFunc: string,
|
|
189
|
-
public readonly expected: { surface: ScenarioSurface; observed: unknown },
|
|
190
|
-
public readonly actual: { surface: ScenarioSurface; observed: unknown }
|
|
191
|
-
) {
|
|
192
|
-
super(
|
|
193
|
-
`Scenario step '${stepFunc}' observed different things on different surfaces — ` +
|
|
194
|
-
`${expected.surface}: ${JSON.stringify(expected.observed)}, ` +
|
|
195
|
-
`${actual.surface}: ${JSON.stringify(actual.observed)}.`
|
|
196
|
-
)
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
addError(ScenarioWitnessDisagreement, {
|
|
200
|
-
status: 500,
|
|
201
|
-
message: 'Two surfaces disagreed about what happened.',
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* A step resolved to its browser binding but nothing can provide a browser.
|
|
206
|
-
*/
|
|
207
|
-
export class ScenarioBrowserUnavailable extends PikkuError {
|
|
208
|
-
constructor(public readonly stepFunc: string) {
|
|
209
|
-
super(
|
|
210
|
-
`[scenario] step '${stepFunc}' resolved to its browser binding but no browser provider is registered. ` +
|
|
211
|
-
`Install @pikku/playwright and register its provider, or run with --run default to take the server-side path.`
|
|
212
|
-
)
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
addError(ScenarioBrowserUnavailable, {
|
|
216
|
-
status: 500,
|
|
217
|
-
message: 'No browser provider is registered.',
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* A step that is driven by a persona was dispatched without one.
|
|
222
|
-
*
|
|
223
|
-
* Raised before the body runs rather than partway through it: the step declared
|
|
224
|
-
* that it needs an actor — by having a `browser` binding, which cannot be
|
|
225
|
-
* provisioned without a window to open, or by `actor: true` — so a call site
|
|
226
|
-
* that omits one is a mistake at the call site.
|
|
227
|
-
*/
|
|
228
|
-
export class ScenarioActorRequired extends PikkuError {
|
|
229
|
-
constructor(public readonly stepFunc: string) {
|
|
230
|
-
super(
|
|
231
|
-
`[scenario] step '${stepFunc}' is driven by a persona but was called without an actor. ` +
|
|
232
|
-
`Pass { actor: actors.<name> } so it runs as that persona.`
|
|
233
|
-
)
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
addError(ScenarioActorRequired, {
|
|
237
|
-
status: 500,
|
|
238
|
-
message: 'This step needs an actor.',
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* A step declares no binding the run can execute.
|
|
243
|
-
*
|
|
244
|
-
* Reached when a step has no `default` and the run targets a surface it does not
|
|
245
|
-
* implement — an action step with nothing to run is a broken ladder, not a
|
|
246
|
-
* coverage gap. (A `then` that ran somewhere, just not on the run surface, is
|
|
247
|
-
* the coverage gap; it is reported rather than thrown. See
|
|
248
|
-
* {@link ScenarioNoWitness} for one that ran nowhere.)
|
|
249
|
-
*/
|
|
250
|
-
export class ScenarioNoSurfaceBinding extends PikkuError {
|
|
251
|
-
constructor(
|
|
252
|
-
public readonly stepFunc: string,
|
|
253
|
-
public readonly declared: ScenarioSurface[],
|
|
254
|
-
public readonly runSurface: ScenarioSurface
|
|
255
|
-
) {
|
|
256
|
-
super(
|
|
257
|
-
`[scenario] step '${stepFunc}' declares no binding for '${runSurface}' and no 'default' to fall back to ` +
|
|
258
|
-
`(declares: ${declared.join(', ') || 'nothing'}).`
|
|
259
|
-
)
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
addError(ScenarioNoSurfaceBinding, {
|
|
263
|
-
status: 500,
|
|
264
|
-
message: 'Step has no runnable binding for this surface.',
|
|
265
|
-
})
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* An assertion had no witness this run could execute.
|
|
269
|
-
*
|
|
270
|
-
* Distinct from an unwitnessed `then`, which ran server-side and merely did not
|
|
271
|
-
* look at the surface its prose claims. This one ran nowhere: without the throw
|
|
272
|
-
* the step returns `undefined` and renders as a tick, reporting a pass for
|
|
273
|
-
* something nobody checked. That is the exact failure the phase exists to
|
|
274
|
-
* prevent, so it is fatal regardless of `--strict`.
|
|
275
|
-
*/
|
|
276
|
-
export class ScenarioNoWitness extends PikkuError {
|
|
277
|
-
constructor(
|
|
278
|
-
public readonly stepFunc: string,
|
|
279
|
-
public readonly declared: ScenarioSurface[],
|
|
280
|
-
public readonly runSurface: ScenarioSurface
|
|
281
|
-
) {
|
|
282
|
-
super(
|
|
283
|
-
`[scenario] assertion '${stepFunc}' has no witness to run on '${runSurface}' ` +
|
|
284
|
-
`(declares: ${declared.join(', ') || 'nothing'}). Add a 'default' witness so the ` +
|
|
285
|
-
`assertion is checked server-side even when the surface cannot check it.`
|
|
286
|
-
)
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
addError(ScenarioNoWitness, {
|
|
290
|
-
status: 500,
|
|
291
|
-
message: 'Assertion has no witness for this surface.',
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* The scenario capability, layered onto a workflow service rather than being
|
|
296
|
-
* one.
|
|
297
|
-
*
|
|
298
|
-
* Every scenario affordance — steps, actors, lifecycle hooks, the browser
|
|
299
|
-
* provider, the assertion wire members — lives here rather than on
|
|
300
|
-
* `PikkuWorkflowService`, because a bundler drops an unused *module* but never
|
|
301
|
-
* an unused class member: anything declared on the workflow service ships in
|
|
302
|
-
* every server built on Pikku, along with everything it imports. Scenarios only
|
|
303
|
-
* ever run from `pikku scenario run`, so the whole surface stays behind an
|
|
304
|
-
* import only that runner makes.
|
|
305
|
-
*
|
|
306
|
-
* It is not a workflow service because a scenario is not a different kind of
|
|
307
|
-
* run — it is the same durable run with a step vocabulary on top. What it
|
|
308
|
-
* needs from the engine it gets through the narrow `WorkflowRunEngine` handle,
|
|
309
|
-
* which is why recording a step never became public API.
|
|
310
|
-
*
|
|
311
|
-
* ```ts
|
|
312
|
-
* const workflowService = new InMemoryWorkflowService()
|
|
313
|
-
* const scenarioService = workflowService.setRunExtension(
|
|
314
|
-
* (engine) => new PikkuScenarioService(engine)
|
|
315
|
-
* )
|
|
316
|
-
* ```
|
|
317
|
-
*/
|
|
318
|
-
export class PikkuScenarioService implements WorkflowRunExtension {
|
|
319
|
-
// Scenario actors per run: live authenticated clients (cookie jars) are
|
|
320
|
-
// process-local by nature, so they ride this map, never the persisted wire.
|
|
321
|
-
private runActors = new Map<string, ScenarioPersonas>()
|
|
322
|
-
// What each run has accumulated so far — process-local like the actors above,
|
|
323
|
-
// so the body and its hooks share one object rather than reading it back off
|
|
324
|
-
// the persisted wire.
|
|
325
|
-
private runContexts = new Map<string, Record<string, unknown>>()
|
|
326
|
-
private scenarioBrowserProvider?: ScenarioBrowserProvider
|
|
327
|
-
private scenarioEnvironment?: ScenarioEnvironment
|
|
328
|
-
private runSurface: ScenarioSurface = 'default'
|
|
329
|
-
|
|
330
|
-
constructor(private readonly engine: WorkflowRunEngine) {}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* The surface every actor drives the system through for this run, set once by
|
|
334
|
-
* the runner from `--run`. `default` is the server-side path — the fast suite.
|
|
335
|
-
*/
|
|
336
|
-
public setRunSurface(surface: ScenarioSurface) {
|
|
337
|
-
this.runSurface = surface
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
public getRunSurface(): ScenarioSurface {
|
|
341
|
-
return this.runSurface
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Registered by `@pikku/playwright` (or any other driver) before a scenario
|
|
346
|
-
* runs. Absent means browser steps cannot run, which the CLI checks up front
|
|
347
|
-
* so a run fails fast rather than mid-flow.
|
|
348
|
-
*/
|
|
349
|
-
public setScenarioBrowserProvider(
|
|
350
|
-
provider: ScenarioBrowserProvider | undefined
|
|
351
|
-
) {
|
|
352
|
-
this.scenarioBrowserProvider = provider
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
public getScenarioBrowserProvider(): ScenarioBrowserProvider | undefined {
|
|
356
|
-
return this.scenarioBrowserProvider
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* The environment scenario steps run against, set once by the runner. It is
|
|
361
|
-
* per-service rather than per-run because a runner process targets exactly
|
|
362
|
-
* one environment for every scenario it executes.
|
|
363
|
-
*/
|
|
364
|
-
public setScenarioEnvironment(env: ScenarioEnvironment | undefined) {
|
|
365
|
-
this.scenarioEnvironment = env
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
public getScenarioEnvironment(): ScenarioEnvironment | undefined {
|
|
369
|
-
return this.scenarioEnvironment
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
public async attachRunContext(
|
|
373
|
-
runId: string,
|
|
374
|
-
workflowMeta: any,
|
|
375
|
-
options?: { actors?: ScenarioPersonas }
|
|
376
|
-
): Promise<void> {
|
|
377
|
-
const actors =
|
|
378
|
-
options?.actors ??
|
|
379
|
-
(workflowMeta.source === 'scenario'
|
|
380
|
-
? await this.resolvePersonas()
|
|
381
|
-
: undefined)
|
|
382
|
-
if (actors) {
|
|
383
|
-
this.runActors.set(runId, actors)
|
|
384
|
-
}
|
|
385
|
-
if (workflowMeta.source === 'scenario') {
|
|
386
|
-
this.runContexts.set(runId, {})
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
public detachRunContext(runId: string): void {
|
|
391
|
-
this.runActors.delete(runId)
|
|
392
|
-
this.runContexts.delete(runId)
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
/**
|
|
396
|
-
* What the run has accumulated.
|
|
397
|
-
*
|
|
398
|
-
* Undefined only for a run whose wire was never decorated — decoration calls
|
|
399
|
-
* `contextForRun` unconditionally, so a plain workflow that has reached a
|
|
400
|
-
* step holds an empty context rather than none.
|
|
401
|
-
*/
|
|
402
|
-
public getRunContext(runId: string): Record<string, unknown> | undefined {
|
|
403
|
-
return this.runContexts.get(runId)
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* The run's context, created on demand because the wire is also built on
|
|
408
|
-
* paths that skip `attachRunContext`.
|
|
409
|
-
*/
|
|
410
|
-
private contextForRun(runId: string): Record<string, unknown> {
|
|
411
|
-
let runContext = this.runContexts.get(runId)
|
|
412
|
-
if (!runContext) {
|
|
413
|
-
runContext = {}
|
|
414
|
-
this.runContexts.set(runId, runContext)
|
|
415
|
-
}
|
|
416
|
-
return runContext
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
public decorateRunWire(
|
|
420
|
-
wire: PikkuRawWire,
|
|
421
|
-
context: {
|
|
422
|
-
runId: string
|
|
423
|
-
workflowMeta: any
|
|
424
|
-
workflowWire: PikkuWorkflowWire
|
|
425
|
-
}
|
|
426
|
-
): void {
|
|
427
|
-
wire.scenario =
|
|
428
|
-
context.workflowMeta?.source === 'scenario'
|
|
429
|
-
? (context.workflowWire as PikkuScenarioWire)
|
|
430
|
-
: undefined
|
|
431
|
-
wire.actors = this.runActors.get(context.runId)
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
public async onBeforeRunFunc(context: RunLifecycleContext): Promise<void> {
|
|
435
|
-
const hooks = this.scenarioHooks(context)
|
|
436
|
-
if (!hooks?.before) return
|
|
437
|
-
await this.runScenarioHook(
|
|
438
|
-
'before',
|
|
439
|
-
context.workflowMeta.name,
|
|
440
|
-
hooks.before,
|
|
441
|
-
context.wire,
|
|
442
|
-
context.run.input,
|
|
443
|
-
context.packageName
|
|
444
|
-
)
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
public async onAfterRunFunc(
|
|
448
|
-
context: RunLifecycleContext,
|
|
449
|
-
outcome: 'completed' | 'failed' | 'interrupted',
|
|
450
|
-
failure: unknown
|
|
451
|
-
): Promise<void> {
|
|
452
|
-
if (outcome === 'interrupted') return
|
|
453
|
-
const hooks = this.scenarioHooks(context)
|
|
454
|
-
if (!hooks?.after) return
|
|
455
|
-
|
|
456
|
-
const { runId, run, workflowMeta } = context
|
|
457
|
-
try {
|
|
458
|
-
await this.runScenarioHook(
|
|
459
|
-
'after',
|
|
460
|
-
workflowMeta.name,
|
|
461
|
-
hooks.after,
|
|
462
|
-
context.wire,
|
|
463
|
-
run.input,
|
|
464
|
-
context.packageName
|
|
465
|
-
)
|
|
466
|
-
} catch (hookError: any) {
|
|
467
|
-
if (outcome === 'failed') {
|
|
468
|
-
// The scenario already failed for its own reason; a teardown failure is
|
|
469
|
-
// diagnostic context, never the headline.
|
|
470
|
-
if (failure instanceof Error && failure.cause === undefined) {
|
|
471
|
-
failure.cause = hookError
|
|
472
|
-
}
|
|
473
|
-
getSingletonServices()?.logger.error(
|
|
474
|
-
`Scenario ${workflowMeta.name} (run ${runId}) failed, and its after hook also failed:`,
|
|
475
|
-
hookError
|
|
476
|
-
)
|
|
477
|
-
} else {
|
|
478
|
-
await this.engine.updateRunStatus(runId, 'failed', undefined, {
|
|
479
|
-
message: hookError.message,
|
|
480
|
-
stack: hookError.stack,
|
|
481
|
-
code: hookError.code,
|
|
482
|
-
})
|
|
483
|
-
await this.engine.onChildWorkflowFailed(run, hookError)
|
|
484
|
-
throw hookError
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
/**
|
|
490
|
-
* Hooks are a scenario affordance only: a plain workflow is durable and
|
|
491
|
-
* resumable, so a callback that reruns on every replay has no honest meaning
|
|
492
|
-
* there.
|
|
493
|
-
*/
|
|
494
|
-
private scenarioHooks(
|
|
495
|
-
context: RunLifecycleContext
|
|
496
|
-
): { before?: ScenarioHook; after?: ScenarioHook } | undefined {
|
|
497
|
-
return context.workflowMeta.source === 'scenario'
|
|
498
|
-
? (context.workflow.func as {
|
|
499
|
-
before?: ScenarioHook
|
|
500
|
-
after?: ScenarioHook
|
|
501
|
-
})
|
|
502
|
-
: undefined
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
/**
|
|
506
|
-
* Run a scenario `before`/`after` hook.
|
|
507
|
-
*
|
|
508
|
-
* A hook is not a pikku function: it has no id, no meta and no schema, so it
|
|
509
|
-
* cannot go through `runPikkuFunc` and the runner records nothing for it. It
|
|
510
|
-
* gets exactly what the scenario body gets — the same wire (so `actors` is
|
|
511
|
-
* how it reaches the app), and singleton services composed with this
|
|
512
|
-
* invocation's wire services — and nothing else.
|
|
513
|
-
*/
|
|
514
|
-
private async runScenarioHook(
|
|
515
|
-
phase: 'before' | 'after',
|
|
516
|
-
scenarioName: string,
|
|
517
|
-
hook: ScenarioHook,
|
|
518
|
-
wire: PikkuRawWire,
|
|
519
|
-
data: unknown,
|
|
520
|
-
packageName: string | null
|
|
521
|
-
): Promise<void> {
|
|
522
|
-
const singletonServices = getSingletonServices()!
|
|
523
|
-
let createWireServices = getCreateWireServices()
|
|
524
|
-
if (packageName) {
|
|
525
|
-
const factories = pikkuState(packageName, 'package', 'factories')
|
|
526
|
-
if (factories?.createWireServices) {
|
|
527
|
-
createWireServices = factories.createWireServices
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
let wireServices: Record<string, unknown> | undefined
|
|
532
|
-
try {
|
|
533
|
-
wireServices = (await createWireServices?.(singletonServices, wire)) as
|
|
534
|
-
Record<string, unknown> | undefined
|
|
535
|
-
const services =
|
|
536
|
-
wireServices && Object.keys(wireServices).length > 0
|
|
537
|
-
? { ...singletonServices, ...wireServices }
|
|
538
|
-
: singletonServices
|
|
539
|
-
await hook(services, data, wire)
|
|
540
|
-
} catch (error) {
|
|
541
|
-
throw new ScenarioHookError(scenarioName, phase, error)
|
|
542
|
-
} finally {
|
|
543
|
-
if (wireServices && Object.keys(wireServices).length > 0) {
|
|
544
|
-
await closeWireServices(singletonServices.logger, wireServices)
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
/**
|
|
550
|
-
* Build HTTP scenario actors for a run started without them; undefined when
|
|
551
|
-
* SCENARIO_ACTOR_SECRET or the API URL is missing.
|
|
552
|
-
*
|
|
553
|
-
* The actor client is imported lazily so that even a runner bundle only pays
|
|
554
|
-
* for the AI persona conversation loop it pulls in when a scenario actually
|
|
555
|
-
* signs an actor in.
|
|
556
|
-
*/
|
|
557
|
-
public async resolvePersonas(): Promise<ScenarioPersonas | undefined> {
|
|
558
|
-
const services = getSingletonServices()
|
|
559
|
-
const variables = services?.variables
|
|
560
|
-
const metaService = services?.metaService
|
|
561
|
-
if (!variables || !metaService) {
|
|
562
|
-
return undefined
|
|
563
|
-
}
|
|
564
|
-
const secret = await variables.get('SCENARIO_ACTOR_SECRET')
|
|
565
|
-
const apiUrl = await variables.get('API_URL')
|
|
566
|
-
if (!secret || !apiUrl) {
|
|
567
|
-
services?.logger?.warn(
|
|
568
|
-
'A scenario was started without personas but SCENARIO_ACTOR_SECRET / API_URL is not configured — running without them.'
|
|
569
|
-
)
|
|
570
|
-
return undefined
|
|
571
|
-
}
|
|
572
|
-
const personas = await metaService.getPersonasMeta()
|
|
573
|
-
if (!personas || Object.keys(personas).length === 0) {
|
|
574
|
-
return undefined
|
|
575
|
-
}
|
|
576
|
-
const signInPath =
|
|
577
|
-
(await variables.get('SCENARIO_SIGN_IN_PATH')) ??
|
|
578
|
-
'/api/auth/sign-in/actor'
|
|
579
|
-
const rpcPath = (await variables.get('SCENARIO_RPC_PATH')) ?? '/rpc'
|
|
580
|
-
// A run started outside the CLI still targets an environment — its own.
|
|
581
|
-
this.scenarioEnvironment ??= {
|
|
582
|
-
apiUrl,
|
|
583
|
-
appUrl: (await variables.get('APP_URL')) ?? undefined,
|
|
584
|
-
}
|
|
585
|
-
const { createHttpPersonas } =
|
|
586
|
-
await import('../../services/http-personas.js')
|
|
587
|
-
return createHttpPersonas({
|
|
588
|
-
apiUrl,
|
|
589
|
-
secret,
|
|
590
|
-
personas,
|
|
591
|
-
signInPath,
|
|
592
|
-
rpcPath,
|
|
593
|
-
})
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
public decorateWorkflowWire(
|
|
597
|
-
wire: PikkuWorkflowWire,
|
|
598
|
-
context: {
|
|
599
|
-
name: string
|
|
600
|
-
runId: string
|
|
601
|
-
rpcService: any
|
|
602
|
-
addonNamespace?: string | null
|
|
603
|
-
}
|
|
604
|
-
): void {
|
|
605
|
-
const { name, runId, rpcService, addonNamespace } = context
|
|
606
|
-
const workflowWire = wire as PikkuScenarioWire
|
|
607
|
-
const scenarioStepContext = (): ScenarioStepContext => ({
|
|
608
|
-
runId,
|
|
609
|
-
workflowName: name,
|
|
610
|
-
addonNamespace,
|
|
611
|
-
workflowWire,
|
|
612
|
-
rpcService,
|
|
613
|
-
})
|
|
614
|
-
Object.assign(workflowWire, {
|
|
615
|
-
context: this.contextForRun(runId),
|
|
616
|
-
|
|
617
|
-
// Durable polling step: invoke an RPC (as an actor when options.as is
|
|
618
|
-
// set) until the predicate passes or `within` elapses. The whole poll is
|
|
619
|
-
// ONE recorded step, so replay returns the cached outcome.
|
|
620
|
-
expectEventually: async (
|
|
621
|
-
stepName: string,
|
|
622
|
-
rpcName: string,
|
|
623
|
-
data: any,
|
|
624
|
-
predicate: (output: any) => boolean,
|
|
625
|
-
options?: WorkflowExpectEventuallyOptions
|
|
626
|
-
) => {
|
|
627
|
-
this.engine.verifyStepName(stepName)
|
|
628
|
-
const resolvedRpcName =
|
|
629
|
-
addonNamespace && !rpcName.includes(':')
|
|
630
|
-
? `${addonNamespace}:${rpcName}`
|
|
631
|
-
: rpcName
|
|
632
|
-
const within = getDurationInMilliseconds(options?.within ?? '30s')
|
|
633
|
-
const interval = getDurationInMilliseconds(options?.interval ?? '1s')
|
|
634
|
-
return await this.engine.inlineStep(
|
|
635
|
-
runId,
|
|
636
|
-
stepName,
|
|
637
|
-
async () => {
|
|
638
|
-
const deadline = Date.now() + within
|
|
639
|
-
let last: any
|
|
640
|
-
while (true) {
|
|
641
|
-
last = options?.actor
|
|
642
|
-
? await options.actor.invoke(resolvedRpcName, data)
|
|
643
|
-
: await rpcService.rpcWithWire(resolvedRpcName, data, {})
|
|
644
|
-
if (predicate(last)) return last
|
|
645
|
-
if (Date.now() + interval > deadline) {
|
|
646
|
-
throw new Error(
|
|
647
|
-
`[workflow] expectEventually '${stepName}' ('${resolvedRpcName}'` +
|
|
648
|
-
`${options?.actor ? ` as '${options.actor.name}'` : ''}) did not pass within ${within}ms; ` +
|
|
649
|
-
`last result: ${JSON.stringify(last)?.slice(0, 300)}`
|
|
650
|
-
)
|
|
651
|
-
}
|
|
652
|
-
await new Promise((resolve) => setTimeout(resolve, interval))
|
|
653
|
-
}
|
|
654
|
-
},
|
|
655
|
-
assertionStep(options)
|
|
656
|
-
)
|
|
657
|
-
},
|
|
658
|
-
|
|
659
|
-
expectError: async (
|
|
660
|
-
stepName: string,
|
|
661
|
-
rpcName: string,
|
|
662
|
-
data: any,
|
|
663
|
-
options?: WorkflowExpectErrorOptions
|
|
664
|
-
) => {
|
|
665
|
-
this.engine.verifyStepName(stepName)
|
|
666
|
-
const resolvedRpcName =
|
|
667
|
-
addonNamespace && !rpcName.includes(':')
|
|
668
|
-
? `${addonNamespace}:${rpcName}`
|
|
669
|
-
: rpcName
|
|
670
|
-
return await this.engine.inlineStep(
|
|
671
|
-
runId,
|
|
672
|
-
stepName,
|
|
673
|
-
async () => {
|
|
674
|
-
let result: any
|
|
675
|
-
try {
|
|
676
|
-
result = options?.actor
|
|
677
|
-
? await options.actor.invoke(resolvedRpcName, data)
|
|
678
|
-
: await rpcService.rpcWithWire(resolvedRpcName, data, {})
|
|
679
|
-
} catch (e: any) {
|
|
680
|
-
const message = e?.message ?? String(e)
|
|
681
|
-
if (options?.matches) {
|
|
682
|
-
const matched =
|
|
683
|
-
typeof options.matches === 'string'
|
|
684
|
-
? message.includes(options.matches)
|
|
685
|
-
: options.matches.test(message)
|
|
686
|
-
if (!matched) {
|
|
687
|
-
throw new Error(
|
|
688
|
-
`[workflow] expectError '${stepName}' ('${resolvedRpcName}') threw, but the message did not match ${options.matches}: ${message}`
|
|
689
|
-
)
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
return message
|
|
693
|
-
}
|
|
694
|
-
throw new Error(
|
|
695
|
-
`[workflow] expectError '${stepName}' ('${resolvedRpcName}') expected an error but the call succeeded: ${JSON.stringify(result)?.slice(0, 300)}`
|
|
696
|
-
)
|
|
697
|
-
},
|
|
698
|
-
assertionStep(options)
|
|
699
|
-
)
|
|
700
|
-
},
|
|
701
|
-
|
|
702
|
-
expectService: async (
|
|
703
|
-
stepName: string,
|
|
704
|
-
serviceMethod: string,
|
|
705
|
-
options?: WorkflowExpectServiceOptions
|
|
706
|
-
) => {
|
|
707
|
-
this.engine.verifyStepName(stepName)
|
|
708
|
-
const [service, method] = serviceMethod.split('.')
|
|
709
|
-
if (!service || !method) {
|
|
710
|
-
throw new Error(
|
|
711
|
-
`[workflow] expectService '${stepName}' needs 'service.method', got '${serviceMethod}'`
|
|
712
|
-
)
|
|
713
|
-
}
|
|
714
|
-
await this.engine.inlineStep(
|
|
715
|
-
runId,
|
|
716
|
-
stepName,
|
|
717
|
-
async () => {
|
|
718
|
-
const rpcName = 'pikkuScenarioGetStubCalls'
|
|
719
|
-
const calls: Array<{
|
|
720
|
-
service: string
|
|
721
|
-
method: string
|
|
722
|
-
args: unknown[]
|
|
723
|
-
}> = options?.actor
|
|
724
|
-
? await options.actor.invoke(rpcName, { service })
|
|
725
|
-
: await rpcService.rpcWithWire(rpcName, { service }, {})
|
|
726
|
-
const matching = (calls ?? []).filter(
|
|
727
|
-
(c) =>
|
|
728
|
-
c.service === service &&
|
|
729
|
-
c.method === method &&
|
|
730
|
-
(options?.calledWith === undefined ||
|
|
731
|
-
JSON.stringify(c.args?.[0]) ===
|
|
732
|
-
JSON.stringify(options.calledWith))
|
|
733
|
-
)
|
|
734
|
-
const expected = options?.times
|
|
735
|
-
const ok =
|
|
736
|
-
expected === undefined
|
|
737
|
-
? matching.length > 0
|
|
738
|
-
: matching.length === expected
|
|
739
|
-
if (!ok) {
|
|
740
|
-
const seen =
|
|
741
|
-
(calls ?? [])
|
|
742
|
-
.map(
|
|
743
|
-
(c) =>
|
|
744
|
-
`${c.service}.${c.method}(${JSON.stringify(c.args?.[0])?.slice(0, 120) ?? ''})`
|
|
745
|
-
)
|
|
746
|
-
.join('\n ') || '(none)'
|
|
747
|
-
throw new Error(
|
|
748
|
-
`[workflow] expectService '${stepName}' expected ${expected ?? 'at least one'} call(s) to '${serviceMethod}'` +
|
|
749
|
-
`${options?.calledWith !== undefined ? ` with ${JSON.stringify(options.calledWith)}` : ''}, found ${matching.length}. Recorded:\n ${seen}`
|
|
750
|
-
)
|
|
751
|
-
}
|
|
752
|
-
},
|
|
753
|
-
assertionStep(options)
|
|
754
|
-
)
|
|
755
|
-
},
|
|
756
|
-
|
|
757
|
-
expectScore: async (
|
|
758
|
-
stepName: string,
|
|
759
|
-
agentRunId: string,
|
|
760
|
-
scorerName: string,
|
|
761
|
-
options?: WorkflowExpectScoreOptions
|
|
762
|
-
) => {
|
|
763
|
-
this.engine.verifyStepName(stepName)
|
|
764
|
-
return await this.engine.inlineStep(
|
|
765
|
-
runId,
|
|
766
|
-
stepName,
|
|
767
|
-
async () => {
|
|
768
|
-
const rpcName = 'pikkuScenarioGradeRun'
|
|
769
|
-
const data = {
|
|
770
|
-
runId: agentRunId,
|
|
771
|
-
scorer: scorerName,
|
|
772
|
-
...(options?.reference !== undefined
|
|
773
|
-
? { reference: options.reference }
|
|
774
|
-
: {}),
|
|
775
|
-
}
|
|
776
|
-
const grade: { score: number; reason?: string } = options?.actor
|
|
777
|
-
? await options.actor.invoke(rpcName, data)
|
|
778
|
-
: await rpcService.rpcWithWire(rpcName, data, {})
|
|
779
|
-
|
|
780
|
-
// A scorer that graded is a scorer that answered, so an unstated
|
|
781
|
-
// bound still fails a zero rather than passing anything at all.
|
|
782
|
-
const atLeast = options?.atLeast ?? 0.5
|
|
783
|
-
const failed =
|
|
784
|
-
grade.score < atLeast ||
|
|
785
|
-
(options?.atMost !== undefined && grade.score > options.atMost)
|
|
786
|
-
if (failed) {
|
|
787
|
-
const bound =
|
|
788
|
-
options?.atMost !== undefined
|
|
789
|
-
? `between ${atLeast} and ${options.atMost}`
|
|
790
|
-
: `at least ${atLeast}`
|
|
791
|
-
throw new Error(
|
|
792
|
-
`[workflow] expectScore '${stepName}' expected '${scorerName}' to grade run ${agentRunId} ${bound}, got ${grade.score}` +
|
|
793
|
-
`${grade.reason ? `: ${grade.reason}` : ''}`
|
|
794
|
-
)
|
|
795
|
-
}
|
|
796
|
-
return grade
|
|
797
|
-
},
|
|
798
|
-
assertionStep(options)
|
|
799
|
-
)
|
|
800
|
-
},
|
|
801
|
-
|
|
802
|
-
// knowledge: decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md
|
|
803
|
-
given: (stepName, stepFunc, data, options) =>
|
|
804
|
-
this.scenarioStep(
|
|
805
|
-
'given',
|
|
806
|
-
scenarioStepContext(),
|
|
807
|
-
stepName,
|
|
808
|
-
stepFunc,
|
|
809
|
-
data,
|
|
810
|
-
options
|
|
811
|
-
),
|
|
812
|
-
when: (stepName, stepFunc, data, options) =>
|
|
813
|
-
this.scenarioStep(
|
|
814
|
-
'when',
|
|
815
|
-
scenarioStepContext(),
|
|
816
|
-
stepName,
|
|
817
|
-
stepFunc,
|
|
818
|
-
data,
|
|
819
|
-
options
|
|
820
|
-
),
|
|
821
|
-
then: (stepName, stepFunc, data, options) =>
|
|
822
|
-
this.scenarioStep(
|
|
823
|
-
'then',
|
|
824
|
-
scenarioStepContext(),
|
|
825
|
-
stepName,
|
|
826
|
-
stepFunc,
|
|
827
|
-
data,
|
|
828
|
-
options
|
|
829
|
-
),
|
|
830
|
-
|
|
831
|
-
runScheduledTask: async (taskName: string) => {
|
|
832
|
-
await runScheduledTask({ name: taskName })
|
|
833
|
-
},
|
|
834
|
-
} satisfies Omit<PikkuScenarioWire, keyof PikkuWorkflowWire>)
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
private async scenarioStep(
|
|
838
|
-
phase: ScenarioStepPhase,
|
|
839
|
-
context: ScenarioStepContext,
|
|
840
|
-
stepName: string,
|
|
841
|
-
stepFunc: string,
|
|
842
|
-
data?: any,
|
|
843
|
-
options?: ScenarioStepOptions
|
|
844
|
-
): Promise<any> {
|
|
845
|
-
const { runId, workflowName, addonNamespace, workflowWire } = context
|
|
846
|
-
// Also the guard for `then` being a wire member: an accidental
|
|
847
|
-
// `await scenario` calls it with a resolve function, which lands here as a
|
|
848
|
-
// loud, named error instead of a silent hang.
|
|
849
|
-
this.engine.verifyStepName(stepName)
|
|
850
|
-
if (typeof stepFunc !== 'string') {
|
|
851
|
-
throw new WorkflowStepNameNotString(stepFunc)
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
const packageName =
|
|
855
|
-
addonNamespace && !stepFunc.includes(':') ? addonNamespace : null
|
|
856
|
-
const resolvedStepFunc =
|
|
857
|
-
addonNamespace && !stepFunc.includes(':')
|
|
858
|
-
? `${addonNamespace}:${stepFunc}`
|
|
859
|
-
: stepFunc
|
|
860
|
-
|
|
861
|
-
const actor = options?.actor as ScenarioPersonas[string] | undefined
|
|
862
|
-
const description =
|
|
863
|
-
options?.description ??
|
|
864
|
-
this.scenarioStepDescription(packageName, resolvedStepFunc) ??
|
|
865
|
-
stepName
|
|
866
|
-
|
|
867
|
-
if (!actor && this.requiresActor(packageName, resolvedStepFunc)) {
|
|
868
|
-
throw new ScenarioActorRequired(resolvedStepFunc)
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
const declared = this.declaredSurfaces(packageName, resolvedStepFunc)
|
|
872
|
-
const resolution = resolveScenarioSurfaces(phase, declared, this.runSurface)
|
|
873
|
-
|
|
874
|
-
return await this.engine.inlineStep(
|
|
875
|
-
runId,
|
|
876
|
-
stepName,
|
|
877
|
-
async () => {
|
|
878
|
-
const runOnSurface = async (surface: ScenarioSurface) => {
|
|
879
|
-
// No `rpc` yet — runPikkuFunc attaches it lazily for the invocation.
|
|
880
|
-
const wire: PikkuRawWire = {
|
|
881
|
-
workflow: workflowWire,
|
|
882
|
-
scenario: workflowWire,
|
|
883
|
-
pikkuUserId: workflowWire.pikkuUserId,
|
|
884
|
-
actors: this.runActors.get(runId),
|
|
885
|
-
...(actor ? { actor } : {}),
|
|
886
|
-
scenarioStep: {
|
|
887
|
-
name: resolvedStepFunc,
|
|
888
|
-
stepName,
|
|
889
|
-
runId,
|
|
890
|
-
phase,
|
|
891
|
-
surface,
|
|
892
|
-
env: this.scenarioEnvironment,
|
|
893
|
-
},
|
|
894
|
-
}
|
|
895
|
-
if (surface === 'browser') {
|
|
896
|
-
if (!this.scenarioBrowserProvider) {
|
|
897
|
-
throw new ScenarioBrowserUnavailable(resolvedStepFunc)
|
|
898
|
-
}
|
|
899
|
-
// The dispatch guard above already refused an actor-less call, and a
|
|
900
|
-
// browser binding always requires one.
|
|
901
|
-
wire.browser = await this.scenarioBrowserProvider.sessionFor(
|
|
902
|
-
actor!.name
|
|
903
|
-
)
|
|
904
|
-
}
|
|
905
|
-
return await runPikkuFunc(
|
|
906
|
-
'workflow',
|
|
907
|
-
workflowName,
|
|
908
|
-
resolvedStepFunc,
|
|
909
|
-
{
|
|
910
|
-
singletonServices: getSingletonServices()!,
|
|
911
|
-
createWireServices: getCreateWireServices(),
|
|
912
|
-
data: () => data,
|
|
913
|
-
wire,
|
|
914
|
-
packageName: packageName ?? undefined,
|
|
915
|
-
}
|
|
916
|
-
)
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
if (resolution.kind === 'action') {
|
|
920
|
-
if (resolution.fellBack && !declared.includes('default')) {
|
|
921
|
-
throw new ScenarioNoSurfaceBinding(
|
|
922
|
-
resolvedStepFunc,
|
|
923
|
-
declared,
|
|
924
|
-
this.runSurface
|
|
925
|
-
)
|
|
926
|
-
}
|
|
927
|
-
return await runOnSurface(resolution.surface)
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
if (resolution.surfaces.length === 0) {
|
|
931
|
-
throw new ScenarioNoWitness(
|
|
932
|
-
resolvedStepFunc,
|
|
933
|
-
declared,
|
|
934
|
-
this.runSurface
|
|
935
|
-
)
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
// A `then` runs every witness it has and they must agree. The surface
|
|
939
|
-
// witness runs first so that when the page is the thing that is wrong,
|
|
940
|
-
// it is the failure that surfaces.
|
|
941
|
-
let first: { surface: ScenarioSurface; observed: unknown } | undefined
|
|
942
|
-
for (const surface of resolution.surfaces) {
|
|
943
|
-
const observed = await runOnSurface(surface)
|
|
944
|
-
if (!first) {
|
|
945
|
-
first = { surface, observed }
|
|
946
|
-
continue
|
|
947
|
-
}
|
|
948
|
-
if (!witnessesAgree(first.observed, observed)) {
|
|
949
|
-
throw new ScenarioWitnessDisagreement(resolvedStepFunc, first, {
|
|
950
|
-
surface,
|
|
951
|
-
observed,
|
|
952
|
-
})
|
|
953
|
-
}
|
|
954
|
-
// Keep whichever witness actually reported a value, so a step pairing
|
|
955
|
-
// a returning witness with a throwing one still records an output.
|
|
956
|
-
if (first.observed === undefined) {
|
|
957
|
-
first = { surface, observed }
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
return first?.observed
|
|
961
|
-
},
|
|
962
|
-
{
|
|
963
|
-
description,
|
|
964
|
-
// Retrying a failed assertion is the wrong behaviour for a test
|
|
965
|
-
// primitive, so steps opt out of the workflow-wide retry default.
|
|
966
|
-
retries: options?.retries ?? 0,
|
|
967
|
-
retryDelay: options?.retryDelay,
|
|
968
|
-
},
|
|
969
|
-
data,
|
|
970
|
-
resolvedStepFunc
|
|
971
|
-
)
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
private scenarioStepConfig(
|
|
975
|
-
packageName: string | null,
|
|
976
|
-
stepFunc: string
|
|
977
|
-
): CorePikkuFunctionConfig<any, any> | undefined {
|
|
978
|
-
const localName =
|
|
979
|
-
packageName && stepFunc.startsWith(`${packageName}:`)
|
|
980
|
-
? stepFunc.slice(packageName.length + 1)
|
|
981
|
-
: stepFunc
|
|
982
|
-
return pikkuState(packageName, 'function', 'functions').get(localName)
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
private scenarioStepDescription(
|
|
986
|
-
packageName: string | null,
|
|
987
|
-
stepFunc: string
|
|
988
|
-
): string | undefined {
|
|
989
|
-
return this.scenarioStepConfig(packageName, stepFunc)?.description
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
/**
|
|
993
|
-
* Which surfaces a step declares a binding for. A step that declares none is
|
|
994
|
-
* treated as server-side only, which is what an ordinary function is.
|
|
995
|
-
*/
|
|
996
|
-
private declaredSurfaces(
|
|
997
|
-
packageName: string | null,
|
|
998
|
-
stepFunc: string
|
|
999
|
-
): ScenarioSurface[] {
|
|
1000
|
-
const surfaces = this.scenarioStepConfig(packageName, stepFunc)?.surfaces
|
|
1001
|
-
return surfaces?.length ? surfaces : ['default']
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
/**
|
|
1005
|
-
* Whether a step is driven by a persona, and so must be given one. Stamped by
|
|
1006
|
-
* the definer from a `browser` binding or an explicit `actor: true`.
|
|
1007
|
-
*/
|
|
1008
|
-
private requiresActor(packageName: string | null, stepFunc: string): boolean {
|
|
1009
|
-
return (
|
|
1010
|
-
this.scenarioStepConfig(packageName, stepFunc)?.requiresActor === true
|
|
1011
|
-
)
|
|
1012
|
-
}
|
|
1013
|
-
}
|