@pikku/cli 0.12.90 → 0.12.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +106 -0
- package/README.md +25 -2
- package/console-app/assets/{index-CSzCJzBb.css → index-D0HG8q0B.css} +1 -1
- package/console-app/assets/{index-C5Bd44e4.js → index-DDpIMCpy.js} +149 -149
- package/console-app/index.html +2 -2
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.js +6 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.json +15 -0
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +43 -0
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +4 -4
- package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +39 -44
- package/dist/.pikku/function/pikku-functions.gen.js +1 -3
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +9 -0
- package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +9 -0
- package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
- package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
- package/dist/.pikku/pikku-meta-service.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.d.ts +1 -0
- package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +10 -0
- package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.json +1 -0
- package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +4 -0
- package/dist/.pikku/scenarios/pikku-scenario-functions.gen.js +1 -0
- package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.d.ts +1 -0
- package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +10 -0
- package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +4 -0
- package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.js +1 -0
- package/dist/.pikku/scenarios/schemas/register.gen.d.ts +4 -0
- package/dist/.pikku/scenarios/schemas/register.gen.js +4 -0
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +5 -3
- package/dist/.pikku/schemas/schemas/FabricSecretsListOutput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/FabricSecretsRotateInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/FabricSecretsRotateOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/FabricSecretsSetOutput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/ScenarioRunInput.schema.json +1 -1
- package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
- package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
- package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
- package/dist/.pikku/workflow/meta/allWorkflow.gen.json +2 -8
- package/dist/.pikku/workflow/pikku-scenario-actors.gen.d.ts +19 -0
- package/dist/.pikku/workflow/pikku-scenario-actors.gen.js +17 -0
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +152 -3
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +39 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/bin/pikku-bin.mjs +2 -2
- package/dist/src/cli.wiring.js +28 -0
- package/dist/src/deploy/analyzer/analyzer.js +22 -5
- package/dist/src/deploy/build-pipeline.js +5 -1
- package/dist/src/fabric/fabric-commands.d.ts +37 -9
- package/dist/src/fabric/fabric-commands.js +12 -0
- package/dist/src/fabric/functions/domains-add.function.d.ts +4 -4
- package/dist/src/fabric/functions/secrets-list.function.d.ts +16 -4
- package/dist/src/fabric/functions/secrets-list.function.js +12 -10
- package/dist/src/fabric/functions/secrets-rotate.function.d.ts +24 -0
- package/dist/src/fabric/functions/secrets-rotate.function.js +36 -0
- package/dist/src/fabric/functions/secrets-set.function.d.ts +8 -4
- package/dist/src/fabric/functions/secrets-set.function.js +18 -7
- package/dist/src/fabric/lib/http.d.ts +7 -1
- package/dist/src/fabric/lib/sealed-box.d.ts +16 -0
- package/dist/src/fabric/lib/sealed-box.js +72 -0
- package/dist/src/functions/commands/dev.js +11 -0
- package/dist/src/functions/commands/load-user-project.d.ts +7 -0
- package/dist/src/functions/commands/load-user-project.js +21 -0
- package/dist/src/functions/commands/pikku-command-bootstrap.js +13 -0
- package/dist/src/functions/commands/scenario-browser.d.ts +84 -0
- package/dist/src/functions/commands/scenario-browser.js +68 -0
- package/dist/src/functions/commands/scenario-environment.d.ts +32 -0
- package/dist/src/functions/commands/scenario-environment.js +61 -0
- package/dist/src/functions/commands/scenario-formatter.d.ts +81 -0
- package/dist/src/functions/commands/scenario-formatter.js +120 -0
- package/dist/src/functions/commands/scenario-ladder.d.ts +66 -0
- package/dist/src/functions/commands/scenario-ladder.js +132 -0
- package/dist/src/functions/commands/scenario-plan.d.ts +61 -0
- package/dist/src/functions/commands/scenario-plan.js +106 -0
- package/dist/src/functions/commands/scenario.d.ts +24 -0
- package/dist/src/functions/commands/scenario.js +322 -50
- package/dist/src/functions/commands/serve.js +2 -0
- package/dist/src/functions/commands/skills.js +27 -61
- package/dist/src/functions/db/db-codegen.d.ts +6 -0
- package/dist/src/functions/db/db-codegen.js +9 -0
- package/dist/src/functions/db/db-migrator.js +14 -0
- package/dist/src/functions/db/local-db.d.ts +8 -0
- package/dist/src/functions/db/local-db.js +24 -2
- package/dist/src/functions/db/migration-identifiers.d.ts +58 -0
- package/dist/src/functions/db/migration-identifiers.js +262 -0
- package/dist/src/functions/db/migration-provenance.d.ts +35 -0
- package/dist/src/functions/db/migration-provenance.js +80 -0
- package/dist/src/functions/db/schema-sql.d.ts +43 -0
- package/dist/src/functions/db/schema-sql.js +135 -0
- package/dist/src/functions/db/sqlite/sqlite-kysely.js +22 -2
- package/dist/src/functions/wirings/functions/pikku-command-functions.js +26 -8
- package/dist/src/functions/wirings/functions/schemas.js +13 -1
- package/dist/src/functions/wirings/functions/serialize-function-types.js +3 -3
- package/dist/src/functions/wirings/rpc/pikku-command-rpc.js +6 -1
- package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.d.ts +10 -0
- package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.js +102 -0
- package/dist/src/functions/wirings/scenarios/scenario-partition.d.ts +42 -0
- package/dist/src/functions/wirings/scenarios/scenario-partition.js +71 -0
- package/dist/src/functions/wirings/scenarios/scenario-schema-partition.d.ts +33 -0
- package/dist/src/functions/wirings/scenarios/scenario-schema-partition.js +49 -0
- package/dist/src/functions/wirings/scenarios/serialize-feature-meta.d.ts +14 -0
- package/dist/src/functions/wirings/scenarios/serialize-feature-meta.js +29 -0
- package/dist/src/functions/wirings/scenarios/serialize-scenario-meta.d.ts +12 -0
- package/dist/src/functions/wirings/scenarios/serialize-scenario-meta.js +56 -0
- package/dist/src/functions/wirings/scenarios/serialize-scenario-registration.d.ts +7 -0
- package/dist/src/functions/wirings/scenarios/serialize-scenario-registration.js +40 -0
- package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +43 -8
- package/dist/src/functions/wirings/workflow/serialize-scenario-actors.d.ts +1 -1
- package/dist/src/functions/wirings/workflow/serialize-scenario-actors.js +13 -2
- package/dist/src/functions/wirings/workflow/serialize-scenario-step-map.d.ts +4 -0
- package/dist/src/functions/wirings/workflow/serialize-scenario-step-map.js +62 -0
- package/dist/src/functions/wirings/workflow/serialize-workflow-bootstrap-map.js +10 -3
- package/dist/src/functions/wirings/workflow/serialize-workflow-map.js +10 -3
- package/dist/src/functions/wirings/workflow/serialize-workflow-meta.js +4 -4
- package/dist/src/functions/wirings/workflow/serialize-workflow-types.d.ts +1 -1
- package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +232 -3
- package/dist/src/functions/workflows/all.workflow.js +2 -7
- package/dist/src/server/server-ready.d.ts +12 -0
- package/dist/src/server/server-ready.js +12 -0
- package/dist/src/server/spawn-dev-server.d.ts +50 -0
- package/dist/src/server/spawn-dev-server.js +112 -0
- package/dist/src/services.js +12 -1
- package/dist/src/utils/file-writer.js +14 -2
- package/dist/src/utils/meta-diff.js +5 -2
- package/dist/src/utils/pikku-cli-config.d.ts +14 -0
- package/dist/src/utils/pikku-cli-config.js +60 -0
- package/dist/src/utils/remove-legacy-scaffold-file.d.ts +14 -0
- package/dist/src/utils/remove-legacy-scaffold-file.js +23 -0
- package/dist/src/utils/resolve-scenario-actors.d.ts +23 -0
- package/dist/src/utils/resolve-scenario-actors.js +74 -0
- package/dist/src/utils/serialize-schemas.d.ts +3 -1
- package/dist/src/utils/serialize-schemas.js +39 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +18 -8
- package/dist/.pikku/schemas/schemas/PikkuScenarioFunctionsOutput.schema.json +0 -1
- package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.d.ts +0 -1
- package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.js +0 -31
- package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.d.ts +0 -10
- package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.js +0 -104
- package/skills/pikku-addon/SKILL.md +0 -243
- package/skills/pikku-addon/references/addon-package-manifest.md +0 -63
- package/skills/pikku-ai-agent/SKILL.md +0 -231
- package/skills/pikku-ai-vercel/SKILL.md +0 -82
- package/skills/pikku-ai-voice/SKILL.md +0 -88
- package/skills/pikku-audit/SKILL.md +0 -175
- package/skills/pikku-aws/SKILL.md +0 -111
- package/skills/pikku-backblaze/SKILL.md +0 -71
- package/skills/pikku-better-auth/SKILL.md +0 -298
- package/skills/pikku-cli/SKILL.md +0 -198
- package/skills/pikku-cli/references/complete-example.md +0 -82
- package/skills/pikku-concepts/SKILL.md +0 -250
- package/skills/pikku-concepts/references/concept-mapping.md +0 -556
- package/skills/pikku-concepts/references/packages.md +0 -29
- package/skills/pikku-config/SKILL.md +0 -212
- package/skills/pikku-cron/SKILL.md +0 -214
- package/skills/pikku-deploy-azure/SKILL.md +0 -71
- package/skills/pikku-deploy-cloudflare/SKILL.md +0 -82
- package/skills/pikku-deploy-express/SKILL.md +0 -86
- package/skills/pikku-deploy-fastify/SKILL.md +0 -73
- package/skills/pikku-deploy-lambda/SKILL.md +0 -110
- package/skills/pikku-deploy-nextjs/SKILL.md +0 -78
- package/skills/pikku-deploy-uws/SKILL.md +0 -88
- package/skills/pikku-deps/SKILL.md +0 -98
- package/skills/pikku-emails/SKILL.md +0 -163
- package/skills/pikku-fabric/SKILL.md +0 -318
- package/skills/pikku-fabric-debug/SKILL.md +0 -112
- package/skills/pikku-feature/SKILL.md +0 -258
- package/skills/pikku-gateway-slack/SKILL.md +0 -115
- package/skills/pikku-http/SKILL.md +0 -220
- package/skills/pikku-http/references/http-options.md +0 -55
- package/skills/pikku-i18n/SKILL.md +0 -137
- package/skills/pikku-info/SKILL.md +0 -100
- package/skills/pikku-jose/SKILL.md +0 -105
- package/skills/pikku-kysely/SKILL.md +0 -219
- package/skills/pikku-machine-auth/SKILL.md +0 -183
- package/skills/pikku-mcp/SKILL.md +0 -241
- package/skills/pikku-middleware/SKILL.md +0 -231
- package/skills/pikku-middleware/references/middleware-patterns.md +0 -61
- package/skills/pikku-mongodb/SKILL.md +0 -105
- package/skills/pikku-n8n-import/SKILL.md +0 -109
- package/skills/pikku-n8n-import/SPEC.md +0 -84
- package/skills/pikku-n8n-import/references/addon-mapping.md +0 -121
- package/skills/pikku-n8n-import/references/code-translation.md +0 -121
- package/skills/pikku-n8n-import/references/loops-and-control.md +0 -87
- package/skills/pikku-paraglide/SKILL.md +0 -117
- package/skills/pikku-permissions/SKILL.md +0 -192
- package/skills/pikku-pino/SKILL.md +0 -79
- package/skills/pikku-product-second-opinion/README.md +0 -43
- package/skills/pikku-product-second-opinion/SKILL.md +0 -158
- package/skills/pikku-product-second-opinion/example/sample-report.md +0 -90
- package/skills/pikku-product-second-opinion/references/report-template.md +0 -73
- package/skills/pikku-queue/SKILL.md +0 -240
- package/skills/pikku-react/SKILL.md +0 -212
- package/skills/pikku-react-query/SKILL.md +0 -242
- package/skills/pikku-realtime/SKILL.md +0 -236
- package/skills/pikku-realtime/references/other-routes.md +0 -23
- package/skills/pikku-redis/SKILL.md +0 -90
- package/skills/pikku-rpc/SKILL.md +0 -171
- package/skills/pikku-rtl/SKILL.md +0 -219
- package/skills/pikku-scenario/SKILL.md +0 -215
- package/skills/pikku-schedule/SKILL.md +0 -57
- package/skills/pikku-schema-ajv/SKILL.md +0 -62
- package/skills/pikku-schema-cfworker/SKILL.md +0 -63
- package/skills/pikku-security/SKILL.md +0 -108
- package/skills/pikku-services/SKILL.md +0 -248
- package/skills/pikku-services/references/audit-wire-service.md +0 -34
- package/skills/pikku-software-archaeology/README.md +0 -70
- package/skills/pikku-software-archaeology/SKILL.md +0 -186
- package/skills/pikku-software-archaeology/references/blueprint.schema.json +0 -625
- package/skills/pikku-software-archaeology/references/pikku-mapping.md +0 -49
- package/skills/pikku-software-archaeology/scripts/validate.mjs +0 -173
- package/skills/pikku-tag-middleware/SKILL.md +0 -13
- package/skills/pikku-template-clone/SKILL.md +0 -40
- package/skills/pikku-trigger/SKILL.md +0 -181
- package/skills/pikku-versioning/SKILL.md +0 -173
- package/skills/pikku-websocket/SKILL.md +0 -243
- package/skills/pikku-workflow/SKILL.md +0 -172
- package/skills/pikku-workflow/references/workflow-reference.md +0 -63
- package/skills/pikku-workflows-client/SKILL.md +0 -150
- package/skills/pikku-ws/SKILL.md +0 -47
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const serializeWorkflowTypes = (functionTypesImportPath, rpcMapImportPath, workflowMapImportPath, agentMapImportPath, scopesImportPath) => {
|
|
1
|
+
export const serializeWorkflowTypes = (functionTypesImportPath, rpcMapImportPath, workflowMapImportPath, agentMapImportPath, scopesImportPath, scenarioStepMapImportPath = './pikku-scenario-step-map.gen.js', scenarioActorsImportPath = './pikku-scenario-actors.gen.js') => {
|
|
2
2
|
return `import { WorkflowCancelledException } from '@pikku/core/workflow'
|
|
3
3
|
import { template } from '@pikku/core/workflow'
|
|
4
4
|
import {
|
|
@@ -6,13 +6,17 @@ import {
|
|
|
6
6
|
type PikkuWorkflowGraphConfig,
|
|
7
7
|
type PikkuWorkflowGraphResult,
|
|
8
8
|
} from '@pikku/core/workflow'
|
|
9
|
-
import type { PikkuWorkflowWire, PikkuScenarioWire, WorkflowStepOptions } from '@pikku/core/workflow'
|
|
9
|
+
import type { PikkuWorkflowWire, PikkuScenarioWire, WorkflowStepOptions, ScenarioStepOptions } from '@pikku/core/workflow'
|
|
10
10
|
|
|
11
11
|
export { WorkflowCancelledException }
|
|
12
12
|
import type { PikkuFunctionSessionless, PikkuFunctionConfig } from '${functionTypesImportPath}'
|
|
13
13
|
import type { FlattenedRPCMap } from '${rpcMapImportPath}'
|
|
14
14
|
import type { FlattenedWorkflowMap } from '${workflowMapImportPath}'
|
|
15
15
|
import type { AgentMap as FlattenedAgentMap } from '${agentMapImportPath}'
|
|
16
|
+
import type { FlattenedScenarioStepMap } from '${scenarioStepMapImportPath}'
|
|
17
|
+
import type { TypedScenarioActors } from '${scenarioActorsImportPath}'
|
|
18
|
+
|
|
19
|
+
export type { TypedScenarioActors }
|
|
16
20
|
|
|
17
21
|
export { template }
|
|
18
22
|
|
|
@@ -38,7 +42,44 @@ export interface TypedWorkflow extends PikkuWorkflowWire {
|
|
|
38
42
|
): Promise<T>
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
|
|
45
|
+
/**
|
|
46
|
+
* The typed half of a scenario wire: \`step\` and its \`given\`/\`when\`/\`then\`
|
|
47
|
+
* sugar, narrowed to the names declared by \`pikkuScenarioStep\` in this project.
|
|
48
|
+
* The phase only changes the prose the reporter renders.
|
|
49
|
+
*/
|
|
50
|
+
export interface TypedScenarioSteps {
|
|
51
|
+
step<K extends keyof FlattenedScenarioStepMap>(
|
|
52
|
+
stepName: string,
|
|
53
|
+
stepFunc: K,
|
|
54
|
+
data?: FlattenedScenarioStepMap[K]['input'],
|
|
55
|
+
options?: ScenarioStepOptions
|
|
56
|
+
): Promise<FlattenedScenarioStepMap[K]['output']>
|
|
57
|
+
|
|
58
|
+
given<K extends keyof FlattenedScenarioStepMap>(
|
|
59
|
+
stepName: string,
|
|
60
|
+
stepFunc: K,
|
|
61
|
+
data?: FlattenedScenarioStepMap[K]['input'],
|
|
62
|
+
options?: ScenarioStepOptions
|
|
63
|
+
): Promise<FlattenedScenarioStepMap[K]['output']>
|
|
64
|
+
|
|
65
|
+
when<K extends keyof FlattenedScenarioStepMap>(
|
|
66
|
+
stepName: string,
|
|
67
|
+
stepFunc: K,
|
|
68
|
+
data?: FlattenedScenarioStepMap[K]['input'],
|
|
69
|
+
options?: ScenarioStepOptions
|
|
70
|
+
): Promise<FlattenedScenarioStepMap[K]['output']>
|
|
71
|
+
|
|
72
|
+
then<K extends keyof FlattenedScenarioStepMap>(
|
|
73
|
+
stepName: string,
|
|
74
|
+
stepFunc: K,
|
|
75
|
+
data?: FlattenedScenarioStepMap[K]['input'],
|
|
76
|
+
options?: ScenarioStepOptions
|
|
77
|
+
): Promise<FlattenedScenarioStepMap[K]['output']>
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type TypedScenario = TypedWorkflow &
|
|
81
|
+
Omit<PikkuScenarioWire, keyof PikkuWorkflowWire | keyof TypedScenarioSteps> &
|
|
82
|
+
TypedScenarioSteps
|
|
42
83
|
|
|
43
84
|
import type { StandardSchemaV1 } from '@standard-schema/spec'
|
|
44
85
|
import type { InferSchemaOutput, PikkuPermission, PikkuMiddleware, NodeConfig, PikkuApprovalDescription } from '${functionTypesImportPath}'
|
|
@@ -129,6 +170,49 @@ export type PikkuScenarioConfigWithSchema<
|
|
|
129
170
|
InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown,
|
|
130
171
|
OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown
|
|
131
172
|
>
|
|
173
|
+
/**
|
|
174
|
+
* Runs before the scenario body. Same signature as \`func\`, but its return
|
|
175
|
+
* value is discarded — a hook is setup, not a step, so it is never recorded
|
|
176
|
+
* on the ladder. Throwing skips the body and fails the run; \`after\` still
|
|
177
|
+
* runs.
|
|
178
|
+
*/
|
|
179
|
+
before?: PikkuScenarioHook<InputSchema>
|
|
180
|
+
/**
|
|
181
|
+
* Always runs after the scenario body, in a \`finally\`, whether it passed or
|
|
182
|
+
* failed. Throwing fails a run that would otherwise have passed; on an
|
|
183
|
+
* already-failed run it attaches as the \`cause\` and never replaces the
|
|
184
|
+
* original error.
|
|
185
|
+
*/
|
|
186
|
+
after?: PikkuScenarioHook<InputSchema>
|
|
187
|
+
/**
|
|
188
|
+
* Why this scenario is held out of a default run, stated where the scenario
|
|
189
|
+
* is. The scenario still appears in the plan and is reported as skipped
|
|
190
|
+
* rather than quietly omitted; naming it directly with \`--flows\` runs it
|
|
191
|
+
* anyway.
|
|
192
|
+
*/
|
|
193
|
+
skip?: string
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* A scenario lifecycle hook: the scenario's own \`(services, data, wire)\`
|
|
198
|
+
* signature with its result discarded.
|
|
199
|
+
*/
|
|
200
|
+
export type PikkuScenarioHook<
|
|
201
|
+
InputSchema extends StandardSchemaV1 | undefined = undefined
|
|
202
|
+
> = PikkuFunctionScenario<
|
|
203
|
+
InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown,
|
|
204
|
+
void
|
|
205
|
+
>
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Declares a scenario hook. Returns the function verbatim — a hook is never
|
|
209
|
+
* registered, so this exists purely to give an inline hook a call site to be
|
|
210
|
+
* contextually typed from, the way every other pikku primitive is.
|
|
211
|
+
*/
|
|
212
|
+
export function pikkuScenarioHook<In = unknown>(
|
|
213
|
+
hook: PikkuFunctionScenario<In, void>
|
|
214
|
+
): PikkuFunctionScenario<In, void> {
|
|
215
|
+
return hook
|
|
132
216
|
}
|
|
133
217
|
|
|
134
218
|
/**
|
|
@@ -152,6 +236,151 @@ export function pikkuScenario(func: any) {
|
|
|
152
236
|
return typeof func === 'function' ? { func } : func
|
|
153
237
|
}
|
|
154
238
|
|
|
239
|
+
/**
|
|
240
|
+
* A scenario as a feature references it. Any \`pikkuScenario\` export is
|
|
241
|
+
* assignable; \`In\` is recovered from it so the paired form's \`data\` is
|
|
242
|
+
* checked against that scenario's own input.
|
|
243
|
+
*/
|
|
244
|
+
export type PikkuScenarioRef<In = any, Out = any> = PikkuFunctionConfig<
|
|
245
|
+
In,
|
|
246
|
+
Out,
|
|
247
|
+
'scenario' | 'actors',
|
|
248
|
+
PikkuFunctionScenario<In, Out>,
|
|
249
|
+
any,
|
|
250
|
+
any
|
|
251
|
+
>
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* One entry in a feature's \`scenarios\` list, validated against itself: a bare
|
|
255
|
+
* scenario, or a scenario paired with the input to run it with. The paired form
|
|
256
|
+
* is gherkin's \`Examples:\` written as an ordinary loop.
|
|
257
|
+
*/
|
|
258
|
+
export type PikkuFeatureEntry<Entry> = Entry extends {
|
|
259
|
+
scenario: PikkuScenarioRef<infer In>
|
|
260
|
+
}
|
|
261
|
+
? { scenario: PikkuScenarioRef<In>; data: In }
|
|
262
|
+
: Entry extends PikkuScenarioRef
|
|
263
|
+
? Entry
|
|
264
|
+
: never
|
|
265
|
+
|
|
266
|
+
export type PikkuFeatureConfig<Scenarios extends readonly unknown[]> = {
|
|
267
|
+
/** Human-readable name. The export identifier is the id. */
|
|
268
|
+
name: string
|
|
269
|
+
description?: string
|
|
270
|
+
tags?: string[]
|
|
271
|
+
scenarios: { [K in keyof Scenarios]: PikkuFeatureEntry<Scenarios[K]> }
|
|
272
|
+
/**
|
|
273
|
+
* Runs ONCE before the whole group — not before each scenario. Per-scenario
|
|
274
|
+
* setup is the scenario's own \`before\`; gherkin's \`Background:\` is
|
|
275
|
+
* deliberately not expressible here.
|
|
276
|
+
*/
|
|
277
|
+
before?: PikkuScenarioHook
|
|
278
|
+
after?: PikkuScenarioHook
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* A feature: an ordered group of scenarios, mirroring gherkin's Feature ↔
|
|
283
|
+
* Scenario structure. Scenarios are referenced by imported identifier, so a
|
|
284
|
+
* renamed or deleted scenario is a compile error rather than a silent skip.
|
|
285
|
+
*
|
|
286
|
+
* A scenario does not have to belong to a feature — a void-input scenario
|
|
287
|
+
* still runs standalone.
|
|
288
|
+
*
|
|
289
|
+
* \`\`\`ts
|
|
290
|
+
* export const credentialFeature = pikkuFeature({
|
|
291
|
+
* name: 'Credential API',
|
|
292
|
+
* tags: ['credential'],
|
|
293
|
+
* before: startsMockOAuthServer,
|
|
294
|
+
* after: stopsMockOAuthServer,
|
|
295
|
+
* scenarios: [
|
|
296
|
+
* credentialLazyLoadScenario,
|
|
297
|
+
* ...['stripe', 'google'].map((name) => ({
|
|
298
|
+
* scenario: credentialRoundTripScenario,
|
|
299
|
+
* data: { name },
|
|
300
|
+
* })),
|
|
301
|
+
* ],
|
|
302
|
+
* })
|
|
303
|
+
* \`\`\`
|
|
304
|
+
*/
|
|
305
|
+
export function pikkuFeature<const Scenarios extends readonly unknown[]>(
|
|
306
|
+
config: PikkuFeatureConfig<Scenarios>
|
|
307
|
+
): PikkuFeatureConfig<Scenarios> {
|
|
308
|
+
return config
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export type PikkuFunctionScenarioStep<
|
|
312
|
+
In = unknown,
|
|
313
|
+
Out = never,
|
|
314
|
+
B extends boolean = false
|
|
315
|
+
> = PikkuFunctionSessionless<In, Out, B extends true ? 'scenarioStep' | 'browser' : 'scenarioStep'>
|
|
316
|
+
|
|
317
|
+
export type PikkuScenarioStepConfigWithSchema<
|
|
318
|
+
InputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
319
|
+
OutputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
320
|
+
B extends boolean = false
|
|
321
|
+
> = {
|
|
322
|
+
/** Registered name — this is the string \`scenario.step()\` references. */
|
|
323
|
+
name: string
|
|
324
|
+
/**
|
|
325
|
+
* What this step does, for the console and for whoever reads the source. It
|
|
326
|
+
* is also the fallback prose when no \`template\` is declared, in which case a
|
|
327
|
+
* reporter renders "Given the shopper buys an apple". Defaults to the call
|
|
328
|
+
* site's step name.
|
|
329
|
+
*/
|
|
330
|
+
description?: string
|
|
331
|
+
/**
|
|
332
|
+
* The prose a reporter renders for this step, with \`{placeholders}\` filled
|
|
333
|
+
* from the input the step was called with — \`'sees {packageName}'\` reports as
|
|
334
|
+
* "Then the admin sees @pikku/addon-todos". Every input field should appear,
|
|
335
|
+
* so the report names the values under test rather than repeating one
|
|
336
|
+
* sentence per call site.
|
|
337
|
+
*/
|
|
338
|
+
template?: string
|
|
339
|
+
/**
|
|
340
|
+
* This step drives a browser. The runner provisions one for the step's actor
|
|
341
|
+
* before calling it — which also makes an actor mandatory — and \`wire.browser\`
|
|
342
|
+
* is non-optional inside \`func\`.
|
|
343
|
+
*/
|
|
344
|
+
browser?: B
|
|
345
|
+
title?: string
|
|
346
|
+
tags?: string[]
|
|
347
|
+
input?: InputSchema
|
|
348
|
+
output?: OutputSchema
|
|
349
|
+
errors?: Array<typeof PikkuError>
|
|
350
|
+
func: PikkuFunctionScenarioStep<
|
|
351
|
+
InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown,
|
|
352
|
+
OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown,
|
|
353
|
+
B
|
|
354
|
+
>
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export type PikkuScenarioStepConfig<In, Out, B extends boolean = false> =
|
|
358
|
+
Omit<PikkuScenarioStepConfigWithSchema<undefined, undefined, B>, 'func' | 'input' | 'output'> & {
|
|
359
|
+
func: PikkuFunctionScenarioStep<In, Out, B>
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* A named, reusable scenario step. Unlike \`scenario.do\`, which can only name an
|
|
364
|
+
* RPC, a step's body is an ordinary pikku function — so it may drive a browser,
|
|
365
|
+
* invoke RPCs as its actor, or run a workflow.
|
|
366
|
+
*
|
|
367
|
+
* Steps are deliberately NOT registered as RPCs: a browser-driving step must
|
|
368
|
+
* never be network-callable.
|
|
369
|
+
*/
|
|
370
|
+
export function pikkuScenarioStep<
|
|
371
|
+
InputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
372
|
+
OutputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
373
|
+
B extends boolean = false
|
|
374
|
+
>(
|
|
375
|
+
config: PikkuScenarioStepConfigWithSchema<InputSchema, OutputSchema, B>
|
|
376
|
+
): PikkuFunctionConfig<InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown, OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown, B extends true ? 'scenarioStep' | 'browser' : 'scenarioStep', PikkuFunctionScenarioStep<InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown, OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown, B>, InputSchema, OutputSchema>
|
|
377
|
+
export function pikkuScenarioStep<In, Out = unknown, B extends boolean = false>(
|
|
378
|
+
config: PikkuScenarioStepConfig<In, Out, B>
|
|
379
|
+
): PikkuFunctionConfig<In, Out, B extends true ? 'scenarioStep' | 'browser' : 'scenarioStep'>
|
|
380
|
+
export function pikkuScenarioStep(config: any) {
|
|
381
|
+
return config
|
|
382
|
+
}
|
|
383
|
+
|
|
155
384
|
type TypedRef<T> = { $ref: string; path?: string } & { __phantomType?: T }
|
|
156
385
|
|
|
157
386
|
type TemplateString = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'fs';
|
|
2
2
|
import { pikkuWorkflowComplexFunc } from '#pikku/workflow/pikku-workflow-types.gen.js';
|
|
3
3
|
import { assertSingleCoreVersion } from '../../utils/assert-single-core-version.js';
|
|
4
|
-
import { pruneLegacyScaffoldFiles } from '../../utils/remove-legacy-scaffold-file.js';
|
|
4
|
+
import { pruneLegacyScaffoldFiles, removeRetiredScaffoldFiles, } from '../../utils/remove-legacy-scaffold-file.js';
|
|
5
5
|
import { PikkuTypecheckFailedError, renderTscFull, renderTscSummary, runProjectTypecheck, } from '../../utils/tsc-check.js';
|
|
6
6
|
const scaffoldFiles = (config) => {
|
|
7
7
|
const files = [];
|
|
@@ -17,11 +17,6 @@ const scaffoldFiles = (config) => {
|
|
|
17
17
|
file: config.consoleFunctionsFile,
|
|
18
18
|
generator: 'pikkuConsoleFunctions',
|
|
19
19
|
});
|
|
20
|
-
if (config.scaffold?.scenarios && config.scenariosFunctionsFile)
|
|
21
|
-
files.push({
|
|
22
|
-
file: config.scenariosFunctionsFile,
|
|
23
|
-
generator: 'pikkuScenarioFunctions',
|
|
24
|
-
});
|
|
25
20
|
if (config.scaffold?.userAdmin && config.userAdminFunctionsFile)
|
|
26
21
|
files.push({
|
|
27
22
|
file: config.userAdminFunctionsFile,
|
|
@@ -46,6 +41,7 @@ export const allWorkflow = pikkuWorkflowComplexFunc({
|
|
|
46
41
|
// (workflows/RPCs "disappear"), so refuse to codegen against it.
|
|
47
42
|
await assertSingleCoreVersion(config.rootDir, logger);
|
|
48
43
|
await pruneLegacyScaffoldFiles(config);
|
|
44
|
+
await removeRetiredScaffoldFiles(config);
|
|
49
45
|
const allImports = [];
|
|
50
46
|
let typesDeclarationFileExists = true;
|
|
51
47
|
if (!existsSync(config.outDir)) {
|
|
@@ -150,7 +146,6 @@ export const allWorkflow = pikkuWorkflowComplexFunc({
|
|
|
150
146
|
workflow.do('Graph wirings', 'pikkuGraphWirings', null),
|
|
151
147
|
workflow.do('Public RPC', 'pikkuPublicRPC', null),
|
|
152
148
|
workflow.do('Console functions', 'pikkuConsoleFunctions', null),
|
|
153
|
-
workflow.do('Scenario functions', 'pikkuScenarioFunctions', null),
|
|
154
149
|
workflow.do('User admin functions', 'pikkuUserAdminFunctions', null),
|
|
155
150
|
workflow.do('Events scaffold', 'pikkuEventsScaffold', null),
|
|
156
151
|
workflow.do('Emails', 'pikkuEmails', null),
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Printed once the server is listening AND the project's `afterStart`
|
|
3
|
+
* lifecycle has resolved.
|
|
4
|
+
*
|
|
5
|
+
* The runtime's own `listening on …` line is emitted inside `server.start()`,
|
|
6
|
+
* which runs *before* `afterStart` — so anything a project seeds there (users,
|
|
7
|
+
* scopes, fixtures) is still pending when it appears, and a parent process
|
|
8
|
+
* that treats it as readiness races the seed. This marker is the point at
|
|
9
|
+
* which the server is actually usable, and it is what `--spawn` waits for.
|
|
10
|
+
*/
|
|
11
|
+
export declare const SERVER_READY_MARKER = "pikku: ready";
|
|
12
|
+
export declare const serverReadyLine: (hostname: string, port: number) => string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Printed once the server is listening AND the project's `afterStart`
|
|
3
|
+
* lifecycle has resolved.
|
|
4
|
+
*
|
|
5
|
+
* The runtime's own `listening on …` line is emitted inside `server.start()`,
|
|
6
|
+
* which runs *before* `afterStart` — so anything a project seeds there (users,
|
|
7
|
+
* scopes, fixtures) is still pending when it appears, and a parent process
|
|
8
|
+
* that treats it as readiness races the seed. This marker is the point at
|
|
9
|
+
* which the server is actually usable, and it is what `--spawn` waits for.
|
|
10
|
+
*/
|
|
11
|
+
export const SERVER_READY_MARKER = 'pikku: ready';
|
|
12
|
+
export const serverReadyLine = (hostname, port) => `${SERVER_READY_MARKER} on http://${hostname}:${port}`;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rejects if anything is already listening on `port`.
|
|
3
|
+
*
|
|
4
|
+
* A readiness check cannot tell "my server" from "someone else's": both answer
|
|
5
|
+
* on the same address once spawned, so a stale server left on the target port
|
|
6
|
+
* silently absorbs a whole run and reports failures that belong to code nobody
|
|
7
|
+
* is looking at. A TCP-level check before spawning is the only point at which
|
|
8
|
+
* the two are distinguishable.
|
|
9
|
+
*/
|
|
10
|
+
export declare const assertPortFree: (port: number, host?: string, timeoutMs?: number) => Promise<void>;
|
|
11
|
+
export interface ReadyBarrier {
|
|
12
|
+
/** Feed a chunk of the child's output. */
|
|
13
|
+
observe: (text: string) => void;
|
|
14
|
+
/** Record that the child exited, so the wait fails fast instead of timing out. */
|
|
15
|
+
markExited: (code: number | null) => void;
|
|
16
|
+
wait: (options?: {
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
pollMs?: number;
|
|
19
|
+
}) => Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Watches a spawned server's output for the ready marker. Separated from the
|
|
23
|
+
* spawn so the three outcomes that matter — ready, the child died, nothing
|
|
24
|
+
* happened for long enough — are testable without a real process.
|
|
25
|
+
*/
|
|
26
|
+
export declare const createReadyBarrier: (label: string) => ReadyBarrier;
|
|
27
|
+
export interface SpawnedServer {
|
|
28
|
+
/** Kills the whole process group, so the server's own children go with it. */
|
|
29
|
+
stop: () => void;
|
|
30
|
+
/** Resolves on the ready marker; rejects if the server dies or never reports. */
|
|
31
|
+
waitUntilReady: (options?: {
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
}) => Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
export interface SpawnDevServerOptions {
|
|
36
|
+
cwd: string;
|
|
37
|
+
port: number;
|
|
38
|
+
hostname?: string;
|
|
39
|
+
coverage?: boolean;
|
|
40
|
+
/** Passed through as `--test`, which sets PIKKU_TEST_RUN for isTestRun(). */
|
|
41
|
+
test?: boolean;
|
|
42
|
+
env?: NodeJS.ProcessEnv;
|
|
43
|
+
/** Where the server's own output goes. Defaults to this process's streams. */
|
|
44
|
+
onOutput?: (text: string) => void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Start `pikku dev` as its own process group and stream its output under a
|
|
48
|
+
* `[server]` prefix. Does not wait — call `waitUntilReady`.
|
|
49
|
+
*/
|
|
50
|
+
export declare const spawnDevServer: (options: SpawnDevServerOptions) => Promise<SpawnedServer>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { connect } from 'node:net';
|
|
3
|
+
import { SERVER_READY_MARKER } from './server-ready.js';
|
|
4
|
+
/**
|
|
5
|
+
* Rejects if anything is already listening on `port`.
|
|
6
|
+
*
|
|
7
|
+
* A readiness check cannot tell "my server" from "someone else's": both answer
|
|
8
|
+
* on the same address once spawned, so a stale server left on the target port
|
|
9
|
+
* silently absorbs a whole run and reports failures that belong to code nobody
|
|
10
|
+
* is looking at. A TCP-level check before spawning is the only point at which
|
|
11
|
+
* the two are distinguishable.
|
|
12
|
+
*/
|
|
13
|
+
export const assertPortFree = (port, host = '127.0.0.1', timeoutMs = 1000) => new Promise((resolve, reject) => {
|
|
14
|
+
const socket = connect({ port, host });
|
|
15
|
+
const settle = (error) => {
|
|
16
|
+
socket.removeAllListeners();
|
|
17
|
+
socket.destroy();
|
|
18
|
+
error ? reject(error) : resolve();
|
|
19
|
+
};
|
|
20
|
+
socket.setTimeout(timeoutMs);
|
|
21
|
+
socket.on('connect', () => settle(new Error(`Port ${port} is already in use — something is already listening on ${host}:${port}. ` +
|
|
22
|
+
`Stop it, or point this environment's apiUrl at a free port.`)));
|
|
23
|
+
// Nothing listening, or unreachable: either way this process is free to bind.
|
|
24
|
+
socket.on('error', () => settle());
|
|
25
|
+
socket.on('timeout', () => settle());
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Watches a spawned server's output for the ready marker. Separated from the
|
|
29
|
+
* spawn so the three outcomes that matter — ready, the child died, nothing
|
|
30
|
+
* happened for long enough — are testable without a real process.
|
|
31
|
+
*/
|
|
32
|
+
export const createReadyBarrier = (label) => {
|
|
33
|
+
let ready = false;
|
|
34
|
+
let exit;
|
|
35
|
+
// Stdout arrives in arbitrary chunks, so the marker can straddle two of them.
|
|
36
|
+
// Keep just enough of the tail to rejoin a split marker.
|
|
37
|
+
let tail = '';
|
|
38
|
+
return {
|
|
39
|
+
observe: (text) => {
|
|
40
|
+
if (ready)
|
|
41
|
+
return;
|
|
42
|
+
const window = tail + text;
|
|
43
|
+
if (window.includes(SERVER_READY_MARKER)) {
|
|
44
|
+
ready = true;
|
|
45
|
+
tail = '';
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
tail = window.slice(-SERVER_READY_MARKER.length);
|
|
49
|
+
},
|
|
50
|
+
markExited: (code) => {
|
|
51
|
+
exit = { code };
|
|
52
|
+
},
|
|
53
|
+
wait: async ({ timeoutMs = 120_000, pollMs = 100 } = {}) => {
|
|
54
|
+
const deadline = Date.now() + timeoutMs;
|
|
55
|
+
while (Date.now() < deadline) {
|
|
56
|
+
if (ready)
|
|
57
|
+
return;
|
|
58
|
+
if (exit) {
|
|
59
|
+
throw new Error(`${label} exited with code ${exit.code} before it was ready`);
|
|
60
|
+
}
|
|
61
|
+
await new Promise((r) => setTimeout(r, pollMs));
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`${label} did not report ready within ${timeoutMs / 1000} seconds`);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Start `pikku dev` as its own process group and stream its output under a
|
|
69
|
+
* `[server]` prefix. Does not wait — call `waitUntilReady`.
|
|
70
|
+
*/
|
|
71
|
+
export const spawnDevServer = async (options) => {
|
|
72
|
+
const { cwd, port, hostname = '127.0.0.1', coverage, test = true, env, onOutput = (text) => process.stdout.write(text), } = options;
|
|
73
|
+
await assertPortFree(port, hostname);
|
|
74
|
+
const args = ['pikku', 'dev', '--port', String(port)];
|
|
75
|
+
if (coverage)
|
|
76
|
+
args.push('--coverage');
|
|
77
|
+
if (test)
|
|
78
|
+
args.push('--test');
|
|
79
|
+
const child = spawn('npx', args, {
|
|
80
|
+
cwd,
|
|
81
|
+
env: { ...process.env, ...env },
|
|
82
|
+
stdio: 'pipe',
|
|
83
|
+
detached: true,
|
|
84
|
+
});
|
|
85
|
+
const barrier = createReadyBarrier('Server');
|
|
86
|
+
const forward = (chunk) => {
|
|
87
|
+
const text = chunk.toString();
|
|
88
|
+
barrier.observe(text);
|
|
89
|
+
onOutput(text
|
|
90
|
+
.split('\n')
|
|
91
|
+
.map((line) => (line ? `[server] ${line}` : line))
|
|
92
|
+
.join('\n'));
|
|
93
|
+
};
|
|
94
|
+
child.stdout?.on('data', forward);
|
|
95
|
+
child.stderr?.on('data', forward);
|
|
96
|
+
child.on('exit', (code) => barrier.markExited(code));
|
|
97
|
+
return {
|
|
98
|
+
waitUntilReady: barrier.wait,
|
|
99
|
+
stop: () => {
|
|
100
|
+
child.stdout?.destroy();
|
|
101
|
+
child.stderr?.destroy();
|
|
102
|
+
if (child.pid) {
|
|
103
|
+
try {
|
|
104
|
+
process.kill(-child.pid, 'SIGTERM');
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Process group may already be gone
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
};
|
package/dist/src/services.js
CHANGED
|
@@ -149,7 +149,14 @@ export const createSingletonServices = async (config) => {
|
|
|
149
149
|
let unfilteredStateIsSetupOnly = false;
|
|
150
150
|
let inspectedTsGeneration;
|
|
151
151
|
let inspectorInvalidated = false;
|
|
152
|
-
|
|
152
|
+
/**
|
|
153
|
+
* `unfiltered` is for commands that RUN the project rather than generate from
|
|
154
|
+
* it. The CLI filters narrow what gets written out, which is meaningless to a
|
|
155
|
+
* runner and actively wrong for one: `--tags` on `pikku scenario run` selects
|
|
156
|
+
* which scenarios to run, and if it also narrowed the state the runner would
|
|
157
|
+
* lose the very step functions it is about to call.
|
|
158
|
+
*/
|
|
159
|
+
const getInspectorState = async (refresh = false, setupOnly = false, bootstrapMode = false, unfiltered = false) => {
|
|
153
160
|
// In bootstrap mode, return a minimal "zero state" with core types
|
|
154
161
|
// This allows bootstrap to run immediately without inspecting the codebase
|
|
155
162
|
if (bootstrapMode) {
|
|
@@ -240,6 +247,7 @@ export const createSingletonServices = async (config) => {
|
|
|
240
247
|
rootDir,
|
|
241
248
|
isAddon: !!config.addon,
|
|
242
249
|
oldProgram,
|
|
250
|
+
tsconfig: config.tsconfig,
|
|
243
251
|
types: {
|
|
244
252
|
configFileType: config.configFile,
|
|
245
253
|
userSessionType: config.userSessionType,
|
|
@@ -287,6 +295,9 @@ export const createSingletonServices = async (config) => {
|
|
|
287
295
|
}
|
|
288
296
|
}
|
|
289
297
|
}
|
|
298
|
+
if (unfiltered) {
|
|
299
|
+
return unfilteredState;
|
|
300
|
+
}
|
|
290
301
|
// Apply filters as a post-processing step
|
|
291
302
|
const filteredState = filterInspectorState(unfilteredState, filters, logger);
|
|
292
303
|
return filteredState;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { dirname, join } from 'path';
|
|
2
|
-
import { mkdir, readFile, writeFile, rm } from 'fs/promises';
|
|
2
|
+
import { mkdir, readFile, rename, writeFile, rm } from 'fs/promises';
|
|
3
3
|
import { existsSync } from 'fs';
|
|
4
4
|
import { getCLIVersion } from './get-cli-version.js';
|
|
5
5
|
export const DO_NOT_MODIFY_COMMENT = `/**
|
|
@@ -36,7 +36,19 @@ export const writeFileInDir = async (logger, path, content, { ignoreModifyCommen
|
|
|
36
36
|
// Only write if content has changed or file doesn't exist
|
|
37
37
|
if (existingContent !== content) {
|
|
38
38
|
await mkdir(dirname(path), { recursive: true });
|
|
39
|
-
|
|
39
|
+
// Atomically, because generated files are read while they are generated:
|
|
40
|
+
// `pikku scenario run --spawn` bundles the registers while the dev server it
|
|
41
|
+
// spawned is regenerating them, and `writeFile` truncates before it writes —
|
|
42
|
+
// a reader that lands in that window gets an empty file, not an old one.
|
|
43
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
44
|
+
try {
|
|
45
|
+
await writeFile(tmp, content, 'utf-8');
|
|
46
|
+
await rename(tmp, path);
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
await rm(tmp, { force: true }).catch(() => { });
|
|
50
|
+
throw e;
|
|
51
|
+
}
|
|
40
52
|
if (TS_FILE_REGEX.test(path)) {
|
|
41
53
|
tsWriteGeneration++;
|
|
42
54
|
}
|
|
@@ -19,7 +19,7 @@ const UNWRAP = {
|
|
|
19
19
|
email: 'templates',
|
|
20
20
|
agent: 'agentsMeta',
|
|
21
21
|
};
|
|
22
|
-
// Workflows (incl.
|
|
22
|
+
// Workflows (incl. scenarios) are written one file per workflow under
|
|
23
23
|
// this dir; the file basename (sans `.gen.json`) is the id, `-verbose` excluded.
|
|
24
24
|
const WORKFLOW_META_DIR = 'workflow/meta';
|
|
25
25
|
function readJson(path) {
|
|
@@ -40,7 +40,10 @@ function readSingle(outDir, category, relPath) {
|
|
|
40
40
|
const unwrapKey = UNWRAP[category];
|
|
41
41
|
if (unwrapKey) {
|
|
42
42
|
const inner = raw[unwrapKey];
|
|
43
|
-
raw =
|
|
43
|
+
raw =
|
|
44
|
+
inner && typeof inner === 'object' && !Array.isArray(inner)
|
|
45
|
+
? inner
|
|
46
|
+
: {};
|
|
44
47
|
}
|
|
45
48
|
if (category !== 'http')
|
|
46
49
|
return raw;
|
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import type { PikkuCLIConfig } from '../../types/config.js';
|
|
2
2
|
import type { CLILogger } from '../services/cli-logger.service.js';
|
|
3
3
|
export declare const getPikkuCLIConfig: (logger: CLILogger, configFile: string | undefined, requiredFields: Array<keyof PikkuCLIConfig>, exitProcess?: boolean, outDirOverride?: string) => Promise<PikkuCLIConfig>;
|
|
4
|
+
/** A config that was found and parsed, but says something impossible. */
|
|
5
|
+
export declare class PikkuCLIConfigError extends Error {
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The two schema registers must be two directories.
|
|
9
|
+
*
|
|
10
|
+
* `saveSchemas` owns whatever directory it is given: it writes `register.gen.ts`
|
|
11
|
+
* and prunes every schema file that its own required-set does not name. Point the
|
|
12
|
+
* scenario write at `schemaDirectory` and the second call overwrites the app's
|
|
13
|
+
* register with the scenario-only one and deletes the app's schema files — the
|
|
14
|
+
* exact leak the split exists to prevent, silently, and only in a deployed
|
|
15
|
+
* bundle. Nothing downstream can detect it, so it is rejected here.
|
|
16
|
+
*/
|
|
17
|
+
export declare const assertSchemaDirectoriesAreDistinct: (config: Pick<PikkuCLIConfig, "schemaDirectory" | "scenarioSchemaDirectory">) => void;
|
|
4
18
|
export declare const validateCLIConfig: (cliConfig: PikkuCLIConfig, required: Array<keyof PikkuCLIConfig>) => void;
|