@pikku/core 0.12.67 → 0.12.70
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 +397 -0
- package/README.md +34 -2
- package/dist/function/functions.types.d.ts +27 -0
- package/dist/index.d.ts +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.js +1 -1
- package/dist/pikku-state.js +1 -0
- package/dist/services/http-scenario-actors.d.ts +12 -4
- package/dist/services/http-scenario-actors.js +47 -45
- package/dist/services/in-memory-workflow-service.d.ts +2 -2
- package/dist/services/in-memory-workflow-service.js +2 -2
- package/dist/services/index.d.ts +2 -1
- package/dist/services/index.js +1 -0
- package/dist/services/meta-service.d.ts +5 -1
- package/dist/services/meta-service.js +44 -18
- package/dist/services/scenario-actors-service.d.ts +108 -2
- package/dist/services/scenario-actors-service.js +40 -1
- package/dist/types/core.types.d.ts +21 -3
- package/dist/types/state.types.d.ts +3 -1
- package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -1
- package/dist/wirings/actor-flow/index.d.ts +1 -1
- package/dist/wirings/actor-flow/run-conversation.d.ts +10 -10
- package/dist/wirings/actor-flow/run-conversation.js +27 -27
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +18 -1
- package/dist/wirings/ai-agent/ai-agent-prepare.js +26 -4
- package/dist/wirings/cli/command-parser.js +11 -1
- package/dist/wirings/queue/index.d.ts +1 -1
- package/dist/wirings/queue/queue.types.d.ts +30 -0
- package/dist/wirings/rpc/rpc-runner.js +1 -1
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +52 -3
- package/dist/wirings/workflow/feature.d.ts +28 -0
- package/dist/wirings/workflow/feature.js +57 -0
- package/dist/wirings/workflow/index.d.ts +13 -2
- package/dist/wirings/workflow/index.js +15 -0
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +121 -0
- package/dist/wirings/workflow/pikku-scenario-service.js +419 -0
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +118 -12
- package/dist/wirings/workflow/pikku-workflow-service.js +166 -153
- package/dist/wirings/workflow/scenario-cookie-jar.d.ts +29 -0
- package/dist/wirings/workflow/scenario-cookie-jar.js +51 -0
- package/dist/wirings/workflow/scenario-poll.d.ts +20 -0
- package/dist/wirings/workflow/scenario-poll.js +25 -0
- package/dist/wirings/workflow/scenario-prose.d.ts +38 -0
- package/dist/wirings/workflow/scenario-prose.js +45 -0
- package/dist/wirings/workflow/scenario-step-guards.d.ts +16 -0
- package/dist/wirings/workflow/scenario-step-guards.js +29 -0
- package/dist/wirings/workflow/scenario-step.types.d.ts +148 -0
- package/dist/wirings/workflow/scenario-step.types.js +1 -0
- package/dist/wirings/workflow/workflow.types.d.ts +119 -2
- package/package.json +3 -1
- package/src/function/functions.types.ts +32 -0
- package/src/index.ts +1 -0
- package/src/internal.ts +5 -1
- package/src/pikku-state.ts +1 -0
- package/src/services/http-scenario-actors.test.ts +85 -1
- package/src/services/http-scenario-actors.ts +65 -51
- package/src/services/in-memory-workflow-service.test.ts +50 -1
- package/src/services/in-memory-workflow-service.ts +3 -2
- package/src/services/index.ts +5 -0
- package/src/services/meta-service.test.ts +79 -0
- package/src/services/meta-service.ts +61 -26
- package/src/services/scenario-actors-service.ts +157 -2
- package/src/types/core.types.ts +27 -2
- package/src/types/state.types.ts +3 -0
- package/src/wirings/actor-flow/actor-flow.types.ts +1 -1
- package/src/wirings/actor-flow/index.ts +1 -1
- package/src/wirings/actor-flow/run-conversation.test.ts +12 -6
- package/src/wirings/actor-flow/run-conversation.ts +36 -41
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +29 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +38 -4
- package/src/wirings/cli/command-parser.test.ts +60 -0
- package/src/wirings/cli/command-parser.ts +12 -1
- package/src/wirings/queue/index.ts +2 -0
- package/src/wirings/queue/queue.types.ts +32 -0
- package/src/wirings/rpc/rpc-runner.test.ts +28 -5
- package/src/wirings/rpc/rpc-runner.ts +1 -1
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +86 -2
- package/src/wirings/workflow/feature.test.ts +131 -0
- package/src/wirings/workflow/feature.ts +78 -0
- package/src/wirings/workflow/index.ts +74 -0
- package/src/wirings/workflow/pikku-scenario-service.ts +682 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +126 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +306 -228
- package/src/wirings/workflow/scenario-cookie-jar.test.ts +108 -0
- package/src/wirings/workflow/scenario-cookie-jar.ts +65 -0
- package/src/wirings/workflow/scenario-hooks.test.ts +212 -0
- package/src/wirings/workflow/scenario-poll.test.ts +66 -0
- package/src/wirings/workflow/scenario-poll.ts +36 -0
- package/src/wirings/workflow/scenario-prose.test.ts +152 -0
- package/src/wirings/workflow/scenario-prose.ts +79 -0
- package/src/wirings/workflow/scenario-service.test.ts +155 -0
- package/src/wirings/workflow/scenario-step-guards.ts +43 -0
- package/src/wirings/workflow/scenario-step.test.ts +441 -8
- package/src/wirings/workflow/scenario-step.types.ts +157 -0
- package/src/wirings/workflow/workflow.types.ts +137 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,400 @@
|
|
|
1
|
+
## 0.12.70
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- 539ee0b: Give browser scenario steps a shared way to name an element: `browser.locate(selector)`. `TestIdSelector` (test id, `prefix`, `where` data attributes, `containing` text, `within` scope) is declared in core so a step's input stays structural, and `@pikku/playwright` resolves it against the page — applying `:visible` by default, since Mantine layouts routinely mount a hidden copy of a control.
|
|
6
|
+
- a1a6816: Let a scenario actor declare the scopes and roles it holds
|
|
7
|
+
|
|
8
|
+
`scenarios.actors.<name>` in `pikku.config.json` now takes optional `scopes` and
|
|
9
|
+
`roles`, carried through to `scenarioActorConfigs`. Pikku never applies them —
|
|
10
|
+
which scope store exists and which roles have been created is the app's own — so
|
|
11
|
+
the generated actors file also exports `scenarioActorList`, the registry widened
|
|
12
|
+
to `ScenarioActorConfig`, which is what a seed needs to read an optional field
|
|
13
|
+
off every actor.
|
|
14
|
+
|
|
15
|
+
- dc3e11e: Generate scenarios, features and scenario steps into `.pikku/scenarios/` with their own bootstrap, so a deployed server never imports a step body.
|
|
16
|
+
|
|
17
|
+
A `pikkuScenarioStep` body is an ordinary pikku function and a `pikkuScenario` is an ordinary workflow, so codegen wired both into `pikku-functions.gen.ts` and `pikku-workflow-wirings.gen.ts` — the files every server's bootstrap imports. A project's steps, and whatever a step imports (Playwright, fixtures, assertion helpers), therefore shipped in production. The e2e project's app bootstrap pulled in 20 step modules and 7 scenarios this way.
|
|
18
|
+
|
|
19
|
+
Codegen now partitions on the flags that already existed — `scenarioStep: true` in function meta and `source: 'scenario'` in workflow meta — and emits:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
.pikku/scenarios/pikku-scenario-functions.gen.ts addFunction for every step
|
|
23
|
+
.pikku/scenarios/pikku-scenario-functions-meta.gen.ts step meta, merged onto the app's
|
|
24
|
+
.pikku/scenarios/pikku-scenario-wirings.gen.ts addWorkflow + addFeature
|
|
25
|
+
.pikku/scenarios/pikku-scenario-wirings-meta.gen.ts scenario meta, merged onto the app's
|
|
26
|
+
.pikku/scenarios/meta/*.gen.json per-scenario graph meta
|
|
27
|
+
.pikku/pikku-bootstrap-scenarios.gen.ts imports the app bootstrap, then the above
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`pikku scenario run` is the only thing that loads `pikku-bootstrap-scenarios.gen.ts`; `pikku dev` and `pikku serve` keep loading `pikku-bootstrap.gen.ts`. Bundling the e2e app bootstrap now resolves **zero** scenario or step modules.
|
|
31
|
+
|
|
32
|
+
Both meta files _merge_ rather than replace — `pikkuState(…, 'meta', value)` is a wholesale setter — and each imports the app meta file it merges onto, so the ordering holds regardless of entry point. Features move wholesale to the scenario side: `serializeWorkflowRegistration` no longer emits `addFeature` at all.
|
|
33
|
+
|
|
34
|
+
`LocalMetaService` reads the new locations alongside the old ones (`scenarios/meta` in `getWorkflowMeta()`, `pikku-scenario-functions-meta.gen.json` in `getFunctionsMeta()`), so the console's scenario list and function meta are unchanged — those read from disk, not from the bundle. Scenario meta left behind in `workflow/meta` by an earlier CLI is removed on the next codegen, so it cannot be served as a stale duplicate.
|
|
35
|
+
|
|
36
|
+
**Not included:** a scenario step's input/output JSON schemas still register in the app's `schemas/register.gen.ts`. They are inert data rather than a module edge, and splitting them safely means deriving "required only by a step" across every other schema consumer — a wrong answer there unregisters a schema the server validates against.
|
|
37
|
+
|
|
38
|
+
- 24da616: `createCookieJar` is now the one place a scenario keeps a session. `HttpScenarioActor` is built on it rather than tracking a single cookie string of its own, which means it follows a cookie the target rotates on any response — previously only the sign-in response was read, so a rotated session cookie was dropped and the only recovery was the 401 re-login.
|
|
39
|
+
|
|
40
|
+
It is exported from `@pikku/core/workflow` because a step driving a real auth client SDK needs the same thing an actor does.
|
|
41
|
+
|
|
42
|
+
Two fixes to what the jar holds. A `Set-Cookie` with an empty value is how a target **deletes** a cookie, so the name is now dropped rather than held with a value that says it is gone; and a `cookie` header the caller already set is merged with the jar's rather than silently replaced, which matters when the jar is handed to an SDK as its `customFetchImpl`.
|
|
43
|
+
|
|
44
|
+
`HttpScenarioActor` no longer reads `jar.empty` to decide whether it is signed in — it tracks the sign-in. `empty` is a fact about the jar, not about the session: a target that sets a CSRF or locale cookie before anyone signs in filled it, which made the actor skip its first `login()` and send that call unauthenticated, and made the "sign-in returned no session cookie" guard pass without a session ever being established. That guard now checks the sign-in response's own `Set-Cookie`.
|
|
45
|
+
|
|
46
|
+
- 04bfe3f: Scenarios get a fresh browser each time, a failure report worth reading, and a formatter that owns the output.
|
|
47
|
+
|
|
48
|
+
Three changes that only make sense together.
|
|
49
|
+
|
|
50
|
+
**A scenario no longer inherits the last one's browser.** `ScenarioBrowserProvider` gains an optional `reset()`, called between scenarios: every actor's context — cookies, storage, open pages, in-page listeners — is discarded, while the browser itself stays up. Before this, one browser context per actor lived for the whole run, so scenario 2 started signed in as whoever scenario 1 left behind. The boundary is the context rather than the browser because that is where the isolation actually lives, and re-opening one costs milliseconds instead of a relaunch. `reset()` runs _before_ each scenario, so the last one's window is still there to look at when a headed run stops.
|
|
51
|
+
|
|
52
|
+
**A failure says what happened.** The runner reported `run.error.message` and nothing else — which for a browser step is "Timed out waiting for selector" with every useful detail removed. `ScenarioBrowserProvider` gains an optional `captureFailure(label)`, and the driver's page diagnostics (console errors, uncaught exceptions, failed requests, 4xx/5xx API responses) — collected all along and until now thrown away — are reported under the failing step, with a screenshot written to `<outDir>/scenario-failures`:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
✗ failed at: Then the admin sees the edit button
|
|
56
|
+
Timed out waiting for selector button[title="Edit function"]
|
|
57
|
+
browser (admin): http://localhost:4077/console/functions
|
|
58
|
+
console: TypeError: x is not a function
|
|
59
|
+
api: 500 /api/rpc/console:readFunctionSource
|
|
60
|
+
screenshot: .pikku/scenario-failures/code-editor-admin.png
|
|
61
|
+
at readsFunctionSource (…/code-editor.steps.ts:71:5)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Stacks are trimmed to the project's own frames, because the framework's are never the bug; `--trace` keeps all of them. An expected failure (a `PikkuError`) prints its message alone — a stack adds nothing to a deliberate one.
|
|
65
|
+
|
|
66
|
+
**A failed scenario now shows its ladder at all.** It did not before, for a reason that took a live run to find: an inline run that fails throws out of `startWorkflow` instead of returning `{ runId }`, so the runner never learned the id of the one run whose steps were worth reading — and fell back to the run error alone. `startWorkflow` gains an `onRunCreated` option, called the moment the run exists, which is the only point guaranteed to happen whether the run goes on to pass, fail or suspend. A failure now prints every step that ran, marks the one that didn't, and names it in `✗ failed at:`.
|
|
67
|
+
|
|
68
|
+
A browser timeout's `message` carries its entire call log, so the summary line and the ladder row take its first line only — the block underneath still prints all of it. Three copies of the same paragraph, one of them wrapping mid-table, is not a report.
|
|
69
|
+
|
|
70
|
+
**All of that output now goes through one formatter.** `formatScenarioReport(report)` takes a plain serialisable report — no Maps, no meta handles — and returns the lines to print, the way `deploy plan` already works. Joining a run to the prose that declared it stays in `scenario-ladder.ts`, where the inspector state is; laying it out is the formatter's job. A second reporter (JSON, JUnit) is now a function rather than an excavation.
|
|
71
|
+
|
|
72
|
+
**Browser drivers are pluggable.** `scenarios.browserDriver` in `pikku.config.json` names the package that drives `browser: true` steps; it defaults to `@pikku/playwright` but nothing requires it. A driver is any package exporting `createScenarioBrowserProvider(options)` — or a provider class — returning an object with `sessionFor()` and `close()`. `reset()` and `captureFailure()` are optional, so a driver written against the earlier interface keeps working: it simply offers no isolation and no diagnostics. A package that is neither says so, instead of failing later in a way nobody can read.
|
|
73
|
+
|
|
74
|
+
- 5962e51: Add `pikkuFeature`, a grouping primitive for scenarios.
|
|
75
|
+
|
|
76
|
+
A feature groups scenarios the way gherkin's `Feature:` groups `Scenario:`, and gets `Examples:` for free as an ordinary loop:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
export const credentialFeature = pikkuFeature({
|
|
80
|
+
name: 'Credential API',
|
|
81
|
+
tags: ['credential'],
|
|
82
|
+
before: startsMockOAuthServer,
|
|
83
|
+
after: stopsMockOAuthServer,
|
|
84
|
+
scenarios: [
|
|
85
|
+
credentialLazyLoadScenario,
|
|
86
|
+
...['stripe', 'google', 'hmac-key'].map((name) => ({
|
|
87
|
+
scenario: credentialRoundTripScenario,
|
|
88
|
+
data: { name },
|
|
89
|
+
})),
|
|
90
|
+
],
|
|
91
|
+
})
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- Scenarios are referenced by **imported identifier**, not by string name, so a renamed or deleted scenario is a compile error rather than a silent skip. A `{ scenario, data }` entry's `data` is typed against that scenario's own input.
|
|
95
|
+
- Feature hooks run **once around the whole group** (`before → a → b → c → after`), not per scenario, and `after` runs in a `finally`. Per-scenario setup stays the scenario's own `before`; gherkin's `Background:` is deliberately not expressible.
|
|
96
|
+
- A scenario's effective tags are its own plus its feature's, so `--tags credential` selects through the feature.
|
|
97
|
+
- New `--features` selector on `pikku scenario run`, and `pikku scenario list` now prints features with their scenarios indented. Every filter narrows the same plan, so narrowing a feature to two of its five scenarios still runs its hooks exactly once around those two.
|
|
98
|
+
- The **feature is the run unit**: `--flows` on a scenario whose every feature entry carries `data` errors and names the features containing it, because the feature is what supplies that data. A scenario referenced bare anywhere, or in no feature at all, still runs standalone.
|
|
99
|
+
|
|
100
|
+
`pikkuFeature` infers its scenario list with a `const` generic, so `CoreFeature['scenarios']` is `readonly` — otherwise the emitted `addFeature(id, feature)` call does not typecheck.
|
|
101
|
+
|
|
102
|
+
Membership is resolved at runtime by object identity — `pikkuScenario` returns its config verbatim, so a feature holds the very object that was registered. That is what lets the scenario list be built by a loop, which no static analysis could enumerate. It also means a scenario constructed inline inside a feature is never registered, and is reported as unresolved rather than silently running as something else.
|
|
103
|
+
|
|
104
|
+
- 5962e51: Add `before` / `after` hooks to `pikkuScenario`, and make an unextractable scenario a hard error.
|
|
105
|
+
|
|
106
|
+
A scenario config now takes `before` and `after`. Both have the same signature as `func` — `(services, data, wire)` — with the return value discarded, so there is no new type to learn and a hook reaches the app the same way the body does, through `wire.actors`:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
export const credentialScenario = pikkuScenario({
|
|
110
|
+
title: 'A credential is loaded on first use',
|
|
111
|
+
tags: ['scenario', 'credential'],
|
|
112
|
+
before: resetsCredentials,
|
|
113
|
+
after: removesInstalledAddon,
|
|
114
|
+
func: async (services, data, { scenario, actors }) => { ... },
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- `before` throwing skips the body and fails the run, but `after` still runs.
|
|
119
|
+
- `after` always runs, in a `finally`. Throwing fails a run that would otherwise have passed; on an already-failed run it attaches as the `cause` and never replaces the original error.
|
|
120
|
+
- Neither runs when the run is suspended or waiting — teardown only fires at a terminal outcome.
|
|
121
|
+
- Hooks are not ladder rows: the runner records nothing for them, and a failure is labelled by phase via the new `ScenarioHookError`.
|
|
122
|
+
- Hooks are scenario-only. A `before`/`after` on a `pikkuWorkflowFunc` never runs — a workflow is durable and resumable, so a callback that reran on every replay would have no honest meaning.
|
|
123
|
+
|
|
124
|
+
Two fixes that scenarios needed to be safe to write:
|
|
125
|
+
- A closure in a complex-workflow or scenario body is no longer held to the DSL statement whitelist. A single `try`/`catch` inside any callback previously failed extraction, and the fallback path understands `do`/`sleep` but not `step`/`given`/`when`/`then` — so the scenario registered with **zero steps** and passed vacuously, with no diagnostic. Plain DSL workflows still descend into callbacks, which is what validates fanout bodies.
|
|
126
|
+
- New `PKU679`: a scenario that fails DSL extraction is now a critical error and refuses to register, instead of silently registering empty. A scenario that declares no input parameter at all is legitimate and still extracts.
|
|
127
|
+
|
|
128
|
+
- cd6453c: `ScenarioHttpResponse` is what an actor's transport answers with.
|
|
129
|
+
|
|
130
|
+
Nothing about the shape (status, ok, body) is RPC-specific — it is an HTTP response with its body already drained — so it is not named for RPC, and it carries `serialized`, the body as text. `readScenarioHttpResponse(res)` is exported so a step that has to reach past `invokeRaw` for a non-RPC route drains the response the same way instead of inventing its own record, and `invoke`'s refusal error quotes the raw text, so an HTML or plain-text error body says what went wrong instead of `"undefined"`.
|
|
131
|
+
|
|
132
|
+
Both are generic in the body — `readScenarioHttpResponse<{ runId?: string }>(res)` — defaulting to `unknown`. A body that will not parse as JSON is carried as its raw text rather than dropped.
|
|
133
|
+
|
|
134
|
+
The whole scenario-actor surface is new and unreleased, so there is nothing here to migrate from.
|
|
135
|
+
|
|
136
|
+
- a436645: Redesign the console's scenarios screen as living documentation of a project's BDD features.
|
|
137
|
+
|
|
138
|
+
The inspector now statically extracts `pikkuFeature` declarations — name, description, tags, the scenarios each one groups (including `{ scenario, data }` examples), and whether it declares `before`/`after` — and the CLI writes them to `<outDir>/scenarios/features.gen.json`, which `MetaService.getFeaturesMeta()` reads and the console addon returns from `getAllMeta`.
|
|
139
|
+
|
|
140
|
+
The scenarios page reads that back as a document: features on the left, and on the right the selected feature's scenarios, each rendered as the given/when/then ladder of prose its author actually wrote, with repeats shown as `for each x in xs`, `Examples:` tables for parameterised entries, skip reasons stated rather than hidden, and each scenario's cast of personas inline. The Flows/Personas segmented control is gone; tags filter the document the same way `pikku scenario run --tags` filters a run.
|
|
141
|
+
|
|
142
|
+
- 46cf63e: Scenario personas — the KIND of person, separate from the body that signs in
|
|
143
|
+
|
|
144
|
+
`scenarios.actors` conflated two things: who a kind of person is, and which
|
|
145
|
+
synthetic user a step runs as. That works until a scenario needs two of the same
|
|
146
|
+
kind — tenant isolation, peer sharing, a member hitting another member's row —
|
|
147
|
+
at which point the registry grows two near-identical entries and neither says
|
|
148
|
+
they are the same kind of person.
|
|
149
|
+
|
|
150
|
+
`scenarios.personas` now declares the kinds:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
"scenarios": {
|
|
154
|
+
"personas": {
|
|
155
|
+
"owner": { "description": "Owns their own entries", "primary": true },
|
|
156
|
+
"viewer": { "description": "Someone the owner shares with", "proficiency": "casual" },
|
|
157
|
+
"reminders": { "description": "The app sending reminders", "kind": "system" }
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
A persona carries only what is true of that kind of person for the app's whole
|
|
163
|
+
lifetime — `description`, `primary` (whose experience the product is), `kind`
|
|
164
|
+
(`person` or `system`), `proficiency` (`casual` or `power`). What someone is
|
|
165
|
+
trying to get done, and the circumstances they are doing it in, belong to the
|
|
166
|
+
scenario, not to them.
|
|
167
|
+
|
|
168
|
+
Actors are materialised from personas, so the common case — one body per kind —
|
|
169
|
+
needs no `actors` block at all. Declare an actor by hand only for a second body
|
|
170
|
+
of one persona:
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
"actors": { "ownerB": { "persona": "owner", "email": "owner-b@actors.local" } }
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
A `system` persona mints no actor: there is nobody to sign in.
|
|
177
|
+
|
|
178
|
+
Resolution is shared by codegen and `pikku scenario run` (previously three
|
|
179
|
+
independent reads of `config.scenarios.actors`), so the generated
|
|
180
|
+
`scenarioActorConfigs` — and therefore the `ScenarioActorName` union that types
|
|
181
|
+
`wire.scenarioStep.actor` — always matches the registry a run builds. Two actors
|
|
182
|
+
sharing an email is now an error rather than a silently-shared user row, which
|
|
183
|
+
is exactly the bug a second body exists to catch.
|
|
184
|
+
|
|
185
|
+
Fully backwards compatible: an actor with no `persona` resolves as its own
|
|
186
|
+
implicit persona, and a project with no `personas` block is untouched.
|
|
187
|
+
|
|
188
|
+
Because "persona" now names a config entity, actor-flow no longer uses it for
|
|
189
|
+
"the actor config the LLM plays": `RunConversationParams.persona`/`personaName`
|
|
190
|
+
are now `actor`/`actorName`, and the exported `PersonaLLM` type is `ActorLLM`.
|
|
191
|
+
The `'in-persona'` approval policy value is unchanged — it is the English idiom
|
|
192
|
+
("stay in character"), not a reference to a declared persona.
|
|
193
|
+
|
|
194
|
+
- 9e666bc: `postScenarioJson(url, { body, headers })` — one way for a scenario step to POST JSON at a route and keep what came back.
|
|
195
|
+
|
|
196
|
+
Every step that reaches past an actor was writing this by hand, and the copies had drifted. Two of them answered `response.json()`, which discards the status and **throws outright** when the target answers an empty body or an HTML error page — so a refusal, which is the expected outcome of a permissions scenario, surfaced as a parse error instead of as data. It returns a `ScenarioHttpResponse`, never throws on a non-2xx, and takes an optional `fetch` so a call that has to keep a session can be sent through a `ScenarioCookieJar`.
|
|
197
|
+
|
|
198
|
+
`ScenarioHttpResponse` and `readScenarioHttpResponse` are now generic in the body: `postScenarioJson<{ runId?: string }>(…)` types `body` at the call site instead of casting at every use. The default is still `unknown`, so nothing that omits the parameter changes.
|
|
199
|
+
|
|
200
|
+
`body`'s doc now says what it always did: a body that will not parse as JSON is carried as its raw text, not dropped.
|
|
201
|
+
|
|
202
|
+
- 1c841d8: Move the scenario engine off `PikkuWorkflowService` onto a `PikkuScenarioService` the runner constructs, so no production bundle carries it.
|
|
203
|
+
|
|
204
|
+
Scenario support was built as members of `PikkuWorkflowService` — the class every Pikku server instantiates. A bundler drops an unused _module_, never an unused class _member_, so every deployed app was shipping the step runner, the lifecycle-hook runner, the actor registry, the browser-provider hooks and the `expectEventually`/`expectError`/`expectService` assertion wire, whether or not it had a single scenario. `resolveScenarioActors` pulled the HTTP actor client — and the AI persona conversation loop behind it — in with them.
|
|
205
|
+
|
|
206
|
+
All of it now lives in `PikkuScenarioService`, exported from a new `@pikku/core/scenario` entry point and reached only by `pikku scenario run`:
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
import { createScenarioRunner } from '@pikku/core/scenario'
|
|
210
|
+
|
|
211
|
+
const { workflowService, scenarioService } = createScenarioRunner()
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Measured with esbuild against `InMemoryWorkflowService`: the production bundle drops 35 KB and every `sign-in/actor`, `runConversation`, `expectEventually` and `ScenarioHookError` occurrence, along with the scheduler runner that `wire.runScheduledTask` pulled in. The one remaining `scenarioStep` reference in a production bundle is the RPC guard that refuses to expose a step over `/rpc` — a security check, not scenario machinery.
|
|
215
|
+
|
|
216
|
+
`PikkuScenarioService` is **not** a workflow service. A scenario is not a different kind of run — it is the same durable run with a step vocabulary on top — so it is installed onto one rather than subclassing it. `PikkuWorkflowService` gains a single `setRunExtension(create)` slot, and calls the installed `WorkflowRunExtension` at six points: `attachRunContext`, `detachRunContext`, `decorateRunWire`, `decorateWorkflowWire`, `onBeforeRunFunc`, `onAfterRunFunc`. Nothing on that interface names scenarios.
|
|
217
|
+
|
|
218
|
+
The extension is built from a `WorkflowRunEngine` handle the service hands it — `inlineStep`, `updateRunStatus`, `onChildWorkflowFailed`, `verifyStepName` — which is what lets a scenario record a durable step without any of those becoming public API on the service every production app instantiates.
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
const workflowService = new InMemoryWorkflowService()
|
|
222
|
+
const scenarioService = workflowService.setRunExtension(
|
|
223
|
+
(engine) => new PikkuScenarioService(engine)
|
|
224
|
+
)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
`{ actor }` on a workflow step is deliberately **not** part of the move: `scenario.do(name, rpc, data, { actor })` dispatches through the base wire's `do`, so the actor branch stays in `rpcStep`.
|
|
228
|
+
|
|
229
|
+
**Behaviour change:** a scenario started on a _server_ rather than through the runner (the console can start any registered workflow by name) no longer resolves actors or runs `before`/`after` hooks — a server's workflow service is not a scenario service. Run scenarios with `pikku scenario run`.
|
|
230
|
+
|
|
231
|
+
- 47478a4: Let a scenario declare why it is held out of a default run.
|
|
232
|
+
|
|
233
|
+
`pikkuScenario({ skip: 'why' })` keeps the scenario in the plan and reports it as `SKIP <name> (<reason>)` on the ladder, instead of the alternatives available until now: deleting it, commenting it out, or leaving it red. Naming it directly with `--flows` clears the quarantine and runs it; selecting the feature it belongs to does not, because a feature is a group and running the group should not silently drag a quarantined member in.
|
|
234
|
+
|
|
235
|
+
The run report's `skipped` list now carries a reason per scenario rather than assuming `--no-browser`, so a browser scenario held back on a machine with no browser reads differently from one the project quarantined itself.
|
|
236
|
+
|
|
237
|
+
`@pikku/console` gains a test id on the addon detail page's Setup tab, which was previously only reachable through its translated label.
|
|
238
|
+
|
|
239
|
+
- 9e666bc: Settle what a scenario step imports from `@pikku/core/workflow`.
|
|
240
|
+
|
|
241
|
+
Core carries what the scenario runtime contract needs — the step wire, the browser-driver interface, the transport's response shape — and what core itself implements. Two helpers that had been promoted alongside them are neither, and are not exported: `describeValue`, a one-line formatter for an assertion message, and `readScenarioSseEvents`, a general SSE reader with a scenario-flavoured name. Both are a test suite's own vocabulary, with no consumer inside the framework; a project that wants them owns them, at three and twenty lines. Neither shipped, so nothing to migrate.
|
|
242
|
+
|
|
243
|
+
What stays, and why:
|
|
244
|
+
- `requireActor(scenarioStep)` / `requireScenarioEnv(scenarioStep)` — narrow the optional halves of the step wire, naming the step and what to pass.
|
|
245
|
+
- `pollUntil(attempt, { timeoutMs, intervalMs })` — retries until `attempt` answers anything but `undefined`, then answers with it. Reaching the deadline answers `undefined` rather than throwing, because only the caller knows what was being waited for and can say so. `@pikku/playwright` waits on it too.
|
|
246
|
+
- `createCookieJar` and `readScenarioHttpResponse` / `postScenarioJson` — `HttpScenarioActor` is built on all three, so a step producing the same record reaches the same function.
|
|
247
|
+
- The browser-driver interface, and the reporter's `composeStepProse` / `renderStepTemplate`.
|
|
248
|
+
|
|
249
|
+
The export list is now grouped by who imports it — writing a step, driving a browser, reporting a run — rather than by the order the exports were added.
|
|
250
|
+
|
|
251
|
+
- 5962e51: Add `template` to `pikkuScenarioStep`, so a step's reported prose names the values it was called with.
|
|
252
|
+
|
|
253
|
+
`description` documents what a step does, for the console and for whoever reads the source. `template` is what a reader of the report sees, with `{placeholders}` filled from the input the step was actually called with:
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
export const seesAddonCard = pikkuScenarioStep<
|
|
257
|
+
{ packageName: string; state?: 'installed' | 'available' },
|
|
258
|
+
{ visible: true },
|
|
259
|
+
true
|
|
260
|
+
>({
|
|
261
|
+
name: 'seesAddonCard',
|
|
262
|
+
description: 'sees an addon in the gallery',
|
|
263
|
+
template: 'sees {state} addon {packageName}',
|
|
264
|
+
browser: true,
|
|
265
|
+
func: async (_services, { packageName, state }, { browser }) => { … },
|
|
266
|
+
})
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
Then the admin sees at least 10 addons on offer ✓ 3ms
|
|
271
|
+
When the admin searches for stripe ✓ 10ms
|
|
272
|
+
Then the admin sees available addon @pikku/addon-stripe ✓ 77ms
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Previously the only way to get that was a `description` at every call site, which meant writing the sentence once per call rather than once per step — and a call site that forgot it reported the same sentence three times in a row.
|
|
276
|
+
- A placeholder with no recorded value renders as nothing and the surrounding whitespace collapses, so an omitted optional input reads as a shorter sentence rather than leaking a literal `{state}` into the report. Type placeholder values so they read as words (`state?: 'installed' | 'available'`, not `installed?: boolean`).
|
|
277
|
+
- A call-site `description` still wins, the same way it already won over the step's `description`.
|
|
278
|
+
- `renderStepTemplate` is exported from `@pikku/core/workflow` alongside `composeStepProse`, so the CLI reporter and the console render identically.
|
|
279
|
+
|
|
280
|
+
Scenario steps now record their input on the run (`inlineStep` persisted `null` for every inline step, so there was nothing for a reporter to interpolate). This is what `getRunSteps` already exposes as `data` for RPC steps.
|
|
281
|
+
|
|
282
|
+
A step called from a loop gets its template too. Its durable name is built at runtime (`sees @pikku/addon-todos`) from a declaration the static meta records verbatim (`sees ${packageName}`), so the two can never match by name — it used to fall back to the bare name, with no keyword, actor or template:
|
|
283
|
+
|
|
284
|
+
```
|
|
285
|
+
sees @pikku/addon-console ✓ 85ms
|
|
286
|
+
Then the admin sees installed addon @pikku/addon-console ✓ 92ms
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
The join is by **step function**. A scenario step is dispatched by name exactly as an RPC is, so it now records that name in the run's existing `rpcName` slot — no new field, no schema change in any workflow store. Nothing dispatches off that value anywhere; step identity always comes from the code being replayed.
|
|
290
|
+
|
|
291
|
+
To keep the slot honest, a scenario step is now its own **kind of RPC**, alongside public / private / remote: `FunctionMeta.scenarioStep` marks it, and `rpcExposed` refuses it even if something marks it `expose: true`. Steps were already left out of the RPC registry; this makes "never network-callable" a property the runtime enforces rather than one the registration path happens to produce.
|
|
292
|
+
|
|
293
|
+
`collectScenarioStepProse` now returns `{ byStepName, byStepFunc }` rather than a bare `Map`, and `buildStepLadder` takes that. The step name still wins; the function index only decides steps recorded under a name no declaration carries, and a function called from several sites that disagree on their prose is left out rather than guessed at.
|
|
294
|
+
|
|
295
|
+
- 5962e51: Add `pikkuScenarioStep` — named, typed scenario steps whose body is an ordinary pikku function.
|
|
296
|
+
|
|
297
|
+
A scenario step is referenced by typed string name, the same way `workflow.do` references an RPC, and is checked against a generated `FlattenedScenarioStepMap`:
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
export const buysAnApple = pikkuScenarioStep({
|
|
301
|
+
name: 'buysAnApple',
|
|
302
|
+
description: 'buys an apple',
|
|
303
|
+
func: async (services, data: { qty: number }) => { ... },
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
await scenario.given('buys an apple', 'buysAnApple', { qty: 1 }, { actor: actors.shopper })
|
|
307
|
+
// renders: Given the shopper buys an apple
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
- `given`/`when`/`then` are sugar over `step`, setting only the prose prefix. The runner renders a step ladder from the recorded run.
|
|
311
|
+
- Steps default to `retries: 0` — a failed assertion is not retried.
|
|
312
|
+
- Steps are deliberately **not** registered as RPCs, so a browser-driving step is never network-callable.
|
|
313
|
+
- `browser: true` steps receive a browser handle on the wire. `@pikku/playwright` is a new package providing the Playwright-backed provider, signing each actor's browser context in through the same actor path the HTTP actors use. Without a provider, `pikku scenario run --no-browser` **skips** browser scenarios instead of failing them.
|
|
314
|
+
- New diagnostics: PKU677 (a `browser: true` step called without an actor) and PKU678 (a step target that is not a static string literal).
|
|
315
|
+
- Fixes `--no-<flag>` boolean negation in the CLI command parser, which previously parsed as an unknown option.
|
|
316
|
+
- Fixes PKU673 (a scenario func destructuring services), which never fired because it ran before function meta existed; it now runs in post-processing.
|
|
317
|
+
- Fixes scenario/workflow steps nested in `for...of` and `Promise.all` being dropped from workflow meta.
|
|
318
|
+
|
|
319
|
+
- 61b9bf8: Type a scenario actor's `invoke` over the project's exposed RPC map, and give a step the environment it targets.
|
|
320
|
+
|
|
321
|
+
`ScenarioActor` is now generic in the RPC surface it can reach, and the generated `pikku-scenario-actors.gen.ts` binds it to `FlattenedRPCMap` — exactly the `/rpc/:name` surface an HTTP actor can reach. An unknown RPC name or a payload of the wrong shape is a compile error rather than a 400 mid-run, and the result is narrowed instead of `unknown`:
|
|
322
|
+
|
|
323
|
+
```ts
|
|
324
|
+
const listed = await actor.invoke('todos:listTodos', { limit: 5 })
|
|
325
|
+
const todos: string[] = listed.todos
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
`wire.scenarioStep.actor` stops being `any`: `PikkuWire` takes the project's actor registry as a type argument, threaded through the generated function types. The actors file is now written even for an empty registry, so `TypedScenarioActors` is always a resolvable import.
|
|
329
|
+
|
|
330
|
+
Alongside it:
|
|
331
|
+
- **`invokeRaw(rpcName, data, { headers })`** on `ScenarioActor`, reporting `{ status, ok, body }` rather than throwing. A refusal is the expected outcome of a permissions or scopes scenario, and `invoke`'s error truncates the body naming which scope was missing. `invoke` is now `invokeRaw` plus a throw on `!ok`. The `headers` option is how a step expresses an identity the actor registry cannot.
|
|
332
|
+
- **`scenarioStep.env`** — `{ apiUrl, appUrl? }`, from `scenarios.environments[<environment>]`. Steps run in the CLI process, where there is no `variables` service, so without this every raw-HTTP step would reach for `process.env`. A run started on a server falls back to its own `API_URL`/`APP_URL`.
|
|
333
|
+
- **`requireActor(scenarioStep)` and `requireScenarioEnv(scenarioStep)`** exported from `@pikku/core/workflow`, replacing the hand-rolled `actorOf(...)` guard each step file was writing. Both name the step and say what to pass.
|
|
334
|
+
|
|
335
|
+
## 0.12.69
|
|
336
|
+
|
|
337
|
+
### Patch Changes
|
|
338
|
+
|
|
339
|
+
- 24252b8: Emit queue meta for workflow-only projects, so per-workflow orchestrator queues actually work.
|
|
340
|
+
|
|
341
|
+
Workflows synthesise their own `wf-orchestrator-*` / `wf-step-*` queue meta during
|
|
342
|
+
post-processing, and those entries have no declaring source file. The queue codegen
|
|
343
|
+
bailed early on `queueWorkers.files.size === 0`, so a project that uses workflows but
|
|
344
|
+
hand-declares no `wireQueueWorker` wrote no queue meta at all — and the generated
|
|
345
|
+
bootstrap therefore never imported it.
|
|
346
|
+
|
|
347
|
+
With `queue.meta` empty at runtime, `getOrchestratorQueueName()` never found a
|
|
348
|
+
per-workflow queue and every workflow silently fell back to the single shared
|
|
349
|
+
`pikku-workflow-orchestrator` queue. Nothing failed, but the isolation was gone: one
|
|
350
|
+
long-running workflow step head-of-line-blocked every other workflow queued behind it.
|
|
351
|
+
|
|
352
|
+
The codegen now gates on the meta alone. `@pikku/core` additionally warns at wiring
|
|
353
|
+
time when workflows are registered but no per-workflow orchestrator queue is present,
|
|
354
|
+
so this degradation can't recur silently.
|
|
355
|
+
|
|
356
|
+
- e3d4454: Add job groups, so one shared queue can stay fair without splitting into one
|
|
357
|
+
queue per producer.
|
|
358
|
+
|
|
359
|
+
A job may now carry `group: { id, tier }`, and a worker may cap how many jobs
|
|
360
|
+
of any one group run at once via `groupConcurrency`. On pg-boss this maps to
|
|
361
|
+
`localGroupConcurrency`, which excludes at-capacity groups from the fetch query
|
|
362
|
+
itself, so a capped group costs nothing rather than being fetched and restored.
|
|
363
|
+
BullMQ declares it unsupported (groups are a BullMQ Pro feature) — being
|
|
364
|
+
push-based, it can simply use a queue per group at no polling cost.
|
|
365
|
+
|
|
366
|
+
Workflow services accept a `queueStrategy`. The default `'per-workflow'` is
|
|
367
|
+
unchanged: every workflow gets its own `wf-orchestrator-*` / `wf-step-*` queue,
|
|
368
|
+
which is also what lets serverless providers deploy one unit per workflow. The
|
|
369
|
+
new `'shared-groups'` routes every workflow through the shared
|
|
370
|
+
orchestrator/step-worker queues and isolates them by group instead, so a
|
|
371
|
+
monolith runs one set of pollers rather than one per workflow — on a
|
|
372
|
+
pull-based backend with dozens of workflows that is the difference between
|
|
373
|
+
hundreds of poll loops and twenty. It is for single-process runtimes only; a
|
|
374
|
+
per-unit serverless deploy still needs the per-workflow queues to route to its
|
|
375
|
+
units.
|
|
376
|
+
|
|
377
|
+
## 0.12.68
|
|
378
|
+
|
|
379
|
+
### Patch Changes
|
|
380
|
+
|
|
381
|
+
- f11675f: Forward the parent run's `context` into delegated sub-agent invocations.
|
|
382
|
+
|
|
383
|
+
A supervisor agent's injected `context` (the "Current context" block holding the
|
|
384
|
+
authoritative identifiers — organizationId, project/stage ids) was appended only
|
|
385
|
+
to the supervisor's own instructions. When it delegated, the sub-agent tool's
|
|
386
|
+
input schema carries just `{ message, session }`, and `buildToolDefs` invoked the
|
|
387
|
+
sub-agent with `{ message, threadId, resourceId }` — dropping the context. The
|
|
388
|
+
sub-agent therefore never saw the real ids and depended on the model re-typing
|
|
389
|
+
them into the free-text `message`, which weaker models routinely botch, producing
|
|
390
|
+
schema-validation and permission rejections that the agent then retries — burning
|
|
391
|
+
steps and ballooning the transcript.
|
|
392
|
+
|
|
393
|
+
`buildToolDefs` now takes the parent `context` and forwards it (via the new
|
|
394
|
+
`buildSubAgentRunInput` helper) into both the streaming and non-streaming
|
|
395
|
+
sub-agent invocations, so a specialist inherits the same identifier block in its
|
|
396
|
+
instructions.
|
|
397
|
+
|
|
1
398
|
## 0.12.67
|
|
2
399
|
|
|
3
400
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @pikku/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The Pikku runtime. Defines functions, wirings, services, middleware and the
|
|
4
|
+
types every other Pikku package builds on.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
You rarely install this alone — a runtime package (`@pikku/express`,
|
|
7
|
+
`@pikku/lambda`, …) takes it as a peer dependency.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @pikku/core
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Write functions against the types the CLI generates for your project:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { pikkuFunc } from '../.pikku/pikku-types.gen.js'
|
|
21
|
+
|
|
22
|
+
export const getTodo = pikkuFunc({
|
|
23
|
+
input: GetTodoInput,
|
|
24
|
+
output: TodoOutput,
|
|
25
|
+
func: async (services, data) => services.db.getTodo(data.id),
|
|
26
|
+
})
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Wire them to HTTP, queues, cron, channels or MCP, then run `npx pikku` to
|
|
30
|
+
regenerate the bootstrap files and typed clients.
|
|
31
|
+
|
|
32
|
+
Subpath exports cover the individual wiring types — `@pikku/core/http`,
|
|
33
|
+
`@pikku/core/workflow`, `@pikku/core/channel`, `@pikku/core/ai-agent` and more.
|
|
34
|
+
|
|
35
|
+
## Docs
|
|
36
|
+
|
|
37
|
+
https://pikku.dev/docs
|
|
@@ -135,6 +135,12 @@ export type CorePikkuAuthConfig<Services extends CoreSingletonServices = CoreSer
|
|
|
135
135
|
};
|
|
136
136
|
export declare const pikkuAuth: <Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession>(auth: CorePikkuAuth<Services, Session> | CorePikkuAuthConfig<Services, Session>) => CorePikkuPermission<any, Services, any>;
|
|
137
137
|
export type CorePermissionGroup<PikkuPermission = CorePikkuPermission<any>> = Record<string, PikkuPermission | PikkuPermission[]> | undefined;
|
|
138
|
+
/**
|
|
139
|
+
* A lifecycle hook: the same call signature as the function it hangs off, but
|
|
140
|
+
* its return value is discarded. A hook is setup/teardown, not a step — it has
|
|
141
|
+
* no id, no meta and no schema, so it is never recorded and never replayed.
|
|
142
|
+
*/
|
|
143
|
+
export type CorePikkuFunctionHook<Services = any, Data = any, Wire = any> = (services: Services, data: Data, wire: Wire) => Promise<void> | void;
|
|
138
144
|
export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any, any, any, any, any> | CorePikkuFunctionSessionless<any, any, any, any, any>, PikkuPermission extends CorePikkuPermission<any, any, any> = CorePikkuPermission<any>, PikkuMiddleware extends CorePikkuMiddleware<any, any> = CorePikkuMiddleware<any, any>, InputSchema extends StandardSchemaV1 | undefined = undefined, OutputSchema extends StandardSchemaV1 | undefined = undefined, Scope extends string = string> = {
|
|
139
145
|
/** Short human-readable name (e.g. "Create Todo") */
|
|
140
146
|
title?: string;
|
|
@@ -156,11 +162,32 @@ export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any,
|
|
|
156
162
|
workflowRetries?: number;
|
|
157
163
|
/** Timeout for this function when used as a workflow step (e.g. '30s', '5m'). */
|
|
158
164
|
workflowTimeout?: string;
|
|
165
|
+
/** Scenario steps only: this step drives a browser, so the runner must provision one before calling it. */
|
|
166
|
+
browser?: boolean;
|
|
159
167
|
audit?: boolean | {
|
|
160
168
|
durability?: 'best-effort' | 'transactional';
|
|
161
169
|
};
|
|
162
170
|
approvalDescription?: any;
|
|
163
171
|
func: PikkuFunction;
|
|
172
|
+
/**
|
|
173
|
+
* Scenarios only: runs before the scenario body, with the scenario's own
|
|
174
|
+
* signature. Throwing skips the body and fails the run, but `after` still
|
|
175
|
+
* runs.
|
|
176
|
+
*/
|
|
177
|
+
before?: CorePikkuFunctionHook;
|
|
178
|
+
/**
|
|
179
|
+
* Scenarios only: always runs after the scenario body, in a `finally`.
|
|
180
|
+
* Throwing fails a run that would otherwise have passed; on an
|
|
181
|
+
* already-failed run it attaches as the `cause` and never replaces the
|
|
182
|
+
* original error.
|
|
183
|
+
*/
|
|
184
|
+
after?: CorePikkuFunctionHook;
|
|
185
|
+
/**
|
|
186
|
+
* Scenarios only: why this scenario is held out of a default run. It is
|
|
187
|
+
* reported as skipped rather than quietly omitted, and naming it directly
|
|
188
|
+
* with `--flows` runs it anyway.
|
|
189
|
+
*/
|
|
190
|
+
skip?: string;
|
|
164
191
|
auth?: boolean;
|
|
165
192
|
/**
|
|
166
193
|
* Scopes the session must hold to run this function. All of them are
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export type { AuthInstance, CommonWireMeta, CoreConfig, CorePikkuMiddleware, CorePikkuMiddlewareConfig, CorePikkuMiddlewareFactory, CorePikkuMiddlewareGroup, CoreServices, CoreSingletonServices, CoreUserSession, CreateConfig, ServerLifecycle, FunctionMeta, FunctionRuntimeMeta, FunctionServicesMeta, FunctionWiresMeta, FunctionsMeta, FunctionsRuntimeMeta, JSONPrimitive, JSONValue, MakeRequired, MiddlewareMetadata, MiddlewarePriority, PermissionMetadata, PickOptional, PickRequired, PikkuAIMiddlewareHooks, PikkuWire, PikkuRawWire, PikkuWiringTypes, PostgresConfig, RequireAtLeastOne, SecurityAuditIssue, SecurityAuditReport, SecurityAuditSummary, SecurityAuditUpdate, SecuritySeverity, SecurityUpdateLevel, SerializedError, WireServices, } from './types/core.types.js';
|
|
5
5
|
export { pikkuAIMiddleware, pikkuChannelMiddleware, pikkuChannelMiddlewareFactory, pikkuMiddleware, pikkuMiddlewareFactory, } from './types/core.types.js';
|
|
6
|
-
export type { CorePikkuAuth, CorePikkuAuthConfig, CorePikkuFunction, CorePikkuFunctionConfig, CorePikkuPermission, CorePikkuPermissionConfig, CorePikkuPermissionFactory, CorePikkuApprovalDescription, CorePermissionGroup, ZodLike, } from './function/functions.types.js';
|
|
6
|
+
export type { CorePikkuAuth, CorePikkuAuthConfig, CorePikkuFunction, CorePikkuFunctionConfig, CorePikkuFunctionHook, CorePikkuPermission, CorePikkuPermissionConfig, CorePikkuPermissionFactory, CorePikkuApprovalDescription, CorePermissionGroup, ZodLike, } from './function/functions.types.js';
|
|
7
7
|
export { pikkuAuth, pikkuPermission, pikkuPermissionFactory, pikkuApprovalDescription, } from './function/functions.types.js';
|
|
8
8
|
export { addFunction, getAllFunctionNames } from './function/index.js';
|
|
9
9
|
export type { ListInput, ListOutput, Filter, LeafFilter, LeafValue, } from './function/list.types.js';
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { pikkuState, resetPikkuState } from './pikku-state.js';
|
|
1
|
+
export { pikkuState, resetPikkuState, getAllPackageStates, } from './pikku-state.js';
|
|
2
2
|
export { httpRouter } from './wirings/http/routers/http-router.js';
|
|
3
3
|
export type { CreateSingletonServices, CreateWireServices, } from './types/core.types.js';
|
package/dist/internal.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { pikkuState, resetPikkuState } from './pikku-state.js';
|
|
1
|
+
export { pikkuState, resetPikkuState, getAllPackageStates, } from './pikku-state.js';
|
|
2
2
|
export { httpRouter } from './wirings/http/routers/http-router.js';
|
package/dist/pikku-state.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ScenarioActor, ScenarioActorConfig, ScenarioActors } from './scenario-actors-service.js';
|
|
1
|
+
import type { ScenarioActor, ScenarioActorConfig, ScenarioActors, ScenarioInvokeOptions, ScenarioHttpResponse } from './scenario-actors-service.js';
|
|
2
2
|
import type { ConverseOptions, ActorFlowVerdict } from '../wirings/actor-flow/actor-flow.types.js';
|
|
3
3
|
export interface HttpScenarioActorsConfig {
|
|
4
4
|
/**
|
|
@@ -38,11 +38,18 @@ export declare class HttpScenarioActor implements ScenarioActor {
|
|
|
38
38
|
readonly name: string;
|
|
39
39
|
private actorConfig;
|
|
40
40
|
private config;
|
|
41
|
-
private
|
|
42
|
-
|
|
41
|
+
private jar;
|
|
42
|
+
/**
|
|
43
|
+
* Whether `login()` has succeeded since the last time the session was
|
|
44
|
+
* dropped. The jar cannot answer this — a target may set a cookie before
|
|
45
|
+
* anyone signs in, and it would then look like a session that was never
|
|
46
|
+
* established.
|
|
47
|
+
*/
|
|
48
|
+
private signedIn;
|
|
43
49
|
constructor(name: string, actorConfig: ScenarioActorConfig, config: HttpScenarioActorsConfig);
|
|
44
50
|
get email(): string;
|
|
45
51
|
invoke(rpcName: string, data: unknown): Promise<unknown>;
|
|
52
|
+
invokeRaw(rpcName: string, data: unknown, options?: ScenarioInvokeOptions): Promise<ScenarioHttpResponse>;
|
|
46
53
|
converse(options: ConverseOptions): Promise<ActorFlowVerdict>;
|
|
47
54
|
/** Start/continue the target agent's run over HTTP as this actor. */
|
|
48
55
|
private agentRun;
|
|
@@ -57,7 +64,8 @@ export declare class HttpScenarioActor implements ScenarioActor {
|
|
|
57
64
|
*/
|
|
58
65
|
private postAgent;
|
|
59
66
|
private postRpc;
|
|
60
|
-
|
|
67
|
+
/** Drop the session, so the next call signs in again before it goes out. */
|
|
68
|
+
private signOut;
|
|
61
69
|
private login;
|
|
62
70
|
}
|
|
63
71
|
/**
|