@pikku/inspector 0.12.42 → 0.12.44
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 +266 -0
- package/dist/add/add-addon-bans.js +1 -0
- package/dist/add/add-ai-agent.d.ts +3 -1
- package/dist/add/add-ai-agent.js +82 -0
- package/dist/add/add-credential.js +5 -1
- package/dist/add/add-functions.js +10 -9
- package/dist/add/add-gateway.js +3 -0
- package/dist/add/add-http-route.js +2 -2
- package/dist/add/add-keyed-wiring.js +2 -0
- package/dist/add/add-mcp-prompt.js +0 -1
- package/dist/add/add-mcp-resource.js +0 -1
- package/dist/add/add-permission.d.ts +1 -1
- package/dist/add/add-permission.js +3 -177
- package/dist/add/add-queue-worker.js +3 -0
- package/dist/add/add-schedule.js +3 -0
- package/dist/add/add-scope.d.ts +2 -0
- package/dist/add/add-scope.js +146 -0
- package/dist/add/add-trigger.js +3 -0
- package/dist/add/add-wire-remote-addon.d.ts +10 -0
- package/dist/add/add-wire-remote-addon.js +66 -0
- package/dist/add/add-workflow-graph.js +32 -3
- package/dist/add/add-workflow.js +9 -4
- package/dist/error-codes.d.ts +3 -0
- package/dist/error-codes.js +4 -0
- package/dist/inspector.js +11 -5
- package/dist/types.d.ts +19 -13
- package/dist/utils/custom-types-generator.js +2 -1
- package/dist/utils/ensure-function-metadata.d.ts +15 -0
- package/dist/utils/ensure-function-metadata.js +24 -0
- package/dist/utils/filter-inspector-state.js +9 -0
- package/dist/utils/get-property-value.d.ts +7 -2
- package/dist/utils/get-property-value.js +48 -1
- package/dist/utils/load-addon-functions-meta.js +81 -6
- package/dist/utils/permissions.d.ts +1 -21
- package/dist/utils/permissions.js +17 -108
- package/dist/utils/post-process.d.ts +30 -1
- package/dist/utils/post-process.js +150 -72
- package/dist/utils/schema-generator.js +19 -4
- package/dist/utils/serialize-inspector-state.d.ts +13 -8
- package/dist/utils/serialize-inspector-state.js +12 -6
- package/dist/utils/serialize-permissions-groups-meta.d.ts +0 -2
- package/dist/utils/serialize-permissions-groups-meta.js +0 -26
- package/dist/utils/workflow/derive-workflow-plan.js +9 -3
- package/dist/utils/workflow/dsl/deserialize-dsl-workflow.js +373 -91
- package/dist/utils/workflow/dsl/extract-dsl-workflow.js +274 -100
- package/dist/utils/workflow/dsl/patterns.d.ts +4 -0
- package/dist/utils/workflow/dsl/patterns.js +11 -0
- package/dist/utils/workflow/graph/convert-dsl-to-graph.js +76 -5
- package/dist/utils/workflow/graph/finalize-workflows.d.ts +7 -0
- package/dist/utils/workflow/graph/finalize-workflows.js +11 -2
- package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +2 -0
- package/dist/utils/workflow/graph/serialize-workflow-graph.js +4 -0
- package/dist/utils/workflow/graph/workflow-graph.types.d.ts +8 -4
- package/dist/visit.js +4 -0
- package/package.json +3 -3
- package/run-tests.sh +1 -1
- package/src/add/add-addon-bans.ts +1 -0
- package/src/add/add-ai-agent.test.ts +87 -0
- package/src/add/add-ai-agent.ts +122 -0
- package/src/add/add-credential.ts +8 -0
- package/src/add/add-functions.ts +10 -12
- package/src/add/add-gateway.ts +11 -0
- package/src/add/add-http-route.ts +2 -8
- package/src/add/add-keyed-wiring.ts +2 -0
- package/src/add/add-mcp-prompt.ts +0 -1
- package/src/add/add-mcp-resource.ts +0 -1
- package/src/add/add-permission.ts +4 -242
- package/src/add/add-queue-worker.ts +11 -0
- package/src/add/add-schedule.ts +11 -0
- package/src/add/add-scope.test.ts +346 -0
- package/src/add/add-scope.ts +225 -0
- package/src/add/add-trigger.ts +11 -0
- package/src/add/add-wire-remote-addon.ts +77 -0
- package/src/add/add-workflow-edge-cases.test.ts +201 -0
- package/src/add/add-workflow-fanout.test.ts +60 -0
- package/src/add/add-workflow-graph-input.test.ts +94 -0
- package/src/add/add-workflow-graph-notes.test.ts +74 -0
- package/src/add/add-workflow-graph.ts +35 -3
- package/src/add/add-workflow-on-error.test.ts +118 -0
- package/src/add/add-workflow-return-switch.test.ts +121 -0
- package/src/add/add-workflow-silent-drops.test.ts +163 -0
- package/src/add/add-workflow-sleep-expression.test.ts +97 -0
- package/src/add/add-workflow.ts +9 -4
- package/src/add/config-value-metadata.test.ts +169 -0
- package/src/add/inline-wiring-function.test.ts +104 -0
- package/src/add/validate-workflow-graph-addons.test.ts +102 -0
- package/src/error-codes.ts +5 -0
- package/src/inspector.ts +14 -4
- package/src/types.ts +16 -17
- package/src/utils/custom-types-generator.test.ts +26 -1
- package/src/utils/custom-types-generator.ts +2 -1
- package/src/utils/ensure-function-metadata.ts +42 -0
- package/src/utils/filter-inspector-state.test.ts +0 -2
- package/src/utils/filter-inspector-state.ts +9 -0
- package/src/utils/get-property-value.test.ts +141 -0
- package/src/utils/get-property-value.ts +62 -1
- package/src/utils/load-addon-functions-meta.test.ts +157 -0
- package/src/utils/load-addon-functions-meta.ts +94 -6
- package/src/utils/load-addon-scopes.test.ts +138 -0
- package/src/utils/permissions.test.ts +7 -232
- package/src/utils/permissions.ts +20 -160
- package/src/utils/post-process.test.ts +269 -4
- package/src/utils/post-process.ts +216 -95
- package/src/utils/schema-generator.test.ts +164 -0
- package/src/utils/schema-generator.ts +26 -3
- package/src/utils/serialize-inspector-state.ts +22 -25
- package/src/utils/serialize-permissions-groups-meta.ts +0 -28
- package/src/utils/workflow/derive-workflow-plan.test.ts +41 -3
- package/src/utils/workflow/derive-workflow-plan.ts +11 -4
- package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +480 -119
- package/src/utils/workflow/dsl/deserialize-fanout-body.test.ts +71 -0
- package/src/utils/workflow/dsl/deserialize-fanout-fidelity.test.ts +99 -0
- package/src/utils/workflow/dsl/deserialize-graph-next.test.ts +161 -0
- package/src/utils/workflow/dsl/deserialize-roundtrip-bindings.test.ts +121 -0
- package/src/utils/workflow/dsl/deserialize-roundtrip-values.test.ts +116 -0
- package/src/utils/workflow/dsl/deserialize-roundtrip.test.ts +145 -0
- package/src/utils/workflow/dsl/extract-dsl-workflow.ts +311 -105
- package/src/utils/workflow/dsl/patterns.ts +18 -0
- package/src/utils/workflow/graph/convert-dsl-to-graph.ts +82 -10
- package/src/utils/workflow/graph/fanout-node-identity.test.ts +105 -0
- package/src/utils/workflow/graph/finalize-workflows.test.ts +50 -0
- package/src/utils/workflow/graph/finalize-workflows.ts +13 -2
- package/src/utils/workflow/graph/serialize-workflow-graph.ts +6 -0
- package/src/utils/workflow/graph/workflow-graph.types.ts +11 -2
- package/src/visit.ts +4 -0
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,269 @@
|
|
|
1
|
+
## 0.12.44
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- 1a86d3f: Stop silently dropping DSL workflow constructs during extraction.
|
|
6
|
+
|
|
7
|
+
Four constructs produced a wrong workflow graph with no diagnostic:
|
|
8
|
+
- A property access on the fanout item (`users.map((u) => workflow.do(..., { userId: u.id }))`)
|
|
9
|
+
was dropped from the step's inputs — `extractInputSource` resolved property
|
|
10
|
+
access against the input param and output variables but not loop variables.
|
|
11
|
+
- `const [org, user] = await Promise.all([...])` dropped **both** steps, because
|
|
12
|
+
extraction bailed on any non-identifier binding name before reaching the
|
|
13
|
+
`Promise.all` branch. Array destructuring now binds each name to its matching
|
|
14
|
+
child step's output.
|
|
15
|
+
- A brace-less `for (const x of xs) await workflow.do(...)` dropped the entire
|
|
16
|
+
loop, since only block bodies were walked.
|
|
17
|
+
- Object destructuring of a step result and multi-declarator statements now
|
|
18
|
+
report a diagnostic instead of vanishing.
|
|
19
|
+
|
|
20
|
+
- 1a86d3f: Fix a fanout collapsing into a single step, and preserve graph node config.
|
|
21
|
+
- A fanout took its `stepName` from the first step of its body. Node ids _are_
|
|
22
|
+
step names, so the loop and that step got the same id and the step overwrote
|
|
23
|
+
the loop: `await Promise.all(users.map(...))` rendered as one plain call, and
|
|
24
|
+
everything after the loop became unreachable. A fanout is not itself a cached
|
|
25
|
+
step, so it no longer borrows a name.
|
|
26
|
+
- A `workflow.sleep` or `workflow.suspend` inside a fanout body was dropped at
|
|
27
|
+
extraction — `FanoutStepMeta.body` was typed RPC-only. It now admits sleep and
|
|
28
|
+
suspend, and the regenerated body emits them.
|
|
29
|
+
- Regenerating a `pikkuWorkflowGraph` dropped `onError`, `retries` and
|
|
30
|
+
`retryDelay` from every node, and graph-level `notes`. All four are honoured
|
|
31
|
+
at runtime, so the round trip silently changed behaviour.
|
|
32
|
+
|
|
33
|
+
- 1a86d3f: Support multi-step fanout bodies in DSL workflows.
|
|
34
|
+
|
|
35
|
+
A `Promise.all(array.map(...))` (or `for...of`) body containing more than one
|
|
36
|
+
`workflow.do` call previously extracted only a single step: `const`-captured
|
|
37
|
+
steps were skipped entirely by the parallel extractor, so a body like
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
await Promise.all(
|
|
41
|
+
users.map(async (u) => {
|
|
42
|
+
const digestData = await workflow.do('Get pipeline', 'getDigestData', {
|
|
43
|
+
userId: u.id,
|
|
44
|
+
})
|
|
45
|
+
await workflow.do('Send digest', 'sendDigestEmail', { ...digestData })
|
|
46
|
+
})
|
|
47
|
+
)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
produced a graph with `getDigestData` missing and `sendDigestEmail` referencing
|
|
51
|
+
an unregistered variable. `FanoutStepMeta.child` is replaced by
|
|
52
|
+
`FanoutStepMeta.body: RpcStepMeta[]`, holding the per-iteration steps inline in
|
|
53
|
+
the same workflow — no sub-workflow boundary. Per-iteration `const` bindings are
|
|
54
|
+
now registered so later steps in the same iteration can reference them, and the
|
|
55
|
+
sequential path no longer hard-errors on bodies with more than one step.
|
|
56
|
+
|
|
57
|
+
- 1a86d3f: Add `onError` compensation to DSL workflows.
|
|
58
|
+
|
|
59
|
+
A DSL workflow had no way to express error handling at all — `try/catch` is not
|
|
60
|
+
an allowed statement, and step options carried only `retries`/`retryDelay`. A
|
|
61
|
+
step can now name a compensation RPC:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
await workflow.do(
|
|
65
|
+
'Charge',
|
|
66
|
+
'chargeCard',
|
|
67
|
+
{ id },
|
|
68
|
+
{
|
|
69
|
+
retries: 3,
|
|
70
|
+
onError: 'refundOrder',
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Semantics mirror a graph node's `onError` exactly: once the step's retries are
|
|
76
|
+
exhausted the handler is invoked with `{ error: { message } }` and the original
|
|
77
|
+
error is still thrown. This is compensation, not recovery — the workflow fails
|
|
78
|
+
either way. The handler runs as its own durable step, so a replay cannot
|
|
79
|
+
compensate twice, and it does not inherit `onError` itself.
|
|
80
|
+
|
|
81
|
+
The handler is materialised as a real graph node, so it is wired like any other
|
|
82
|
+
RPC and the console draws a dashed red "on error" edge to it rather than the
|
|
83
|
+
route being invisible.
|
|
84
|
+
|
|
85
|
+
- 1a86d3f: Keep a numeric `retryDelay` numeric through the graph round-trip. The serialized
|
|
86
|
+
graph typed it as `string` and the DSL→graph conversion called `.toString()`, so
|
|
87
|
+
`retryDelay: 500` regenerated as `retryDelay: '500'` — a different value to the
|
|
88
|
+
runtime, which parses strings as durations.
|
|
89
|
+
- 1a86d3f: Stop silently dropping switch cases and spread returns from workflow graphs.
|
|
90
|
+
- A fall-through case (`case 'a': case 'b': ...`) recorded only the last value.
|
|
91
|
+
A run entering on `'a'` therefore appeared to match no case at all. Empty
|
|
92
|
+
clauses now carry through to the entry they fall into — the next non-empty
|
|
93
|
+
case, otherwise `default`, otherwise the switch exit.
|
|
94
|
+
- `return { ...r, extra: 1 }` produced a return node listing only `extra`, so
|
|
95
|
+
the graph claimed an output shape the workflow does not have, with no
|
|
96
|
+
diagnostic. `return r` produced no return node at all. `ReturnStepMeta` now
|
|
97
|
+
records a `spread` list, and the regenerated code emits it.
|
|
98
|
+
|
|
99
|
+
- 1a86d3f: Stop deleting code when regenerating a DSL workflow from its graph.
|
|
100
|
+
|
|
101
|
+
Regenerating a workflow (as the console's graph editor does) silently dropped
|
|
102
|
+
steps:
|
|
103
|
+
- Only the **first** step of an `if` arm survived. The walk stopped via a
|
|
104
|
+
heuristic that tested whether the next node id contained `_then_`/`_else_`,
|
|
105
|
+
but node ids are step names, so it never matched. Branch and switch bodies now
|
|
106
|
+
walk the `next` chain up to an explicit exit boundary — the enclosing flow
|
|
107
|
+
node's own `next`.
|
|
108
|
+
- Switch cases emitted only their entry node, never walking `next` at all.
|
|
109
|
+
- Every step was renamed to `Call <rpcName>`, because the graph conversion never
|
|
110
|
+
wrote `stepName` onto the node. Step names are the durable replay cache key,
|
|
111
|
+
so a round-trip silently invalidated in-flight runs.
|
|
112
|
+
- `workflow.suspend()` had no graph node, yet the preceding step's `next` still
|
|
113
|
+
pointed at its id — traversal dead-ended there and every following step was
|
|
114
|
+
deleted. `suspend` is now a real flow node, and both `suspend` and `approval`
|
|
115
|
+
have deserializer cases.
|
|
116
|
+
- Numeric and boolean `switch` case values were emitted quoted (`case '1':`),
|
|
117
|
+
so the case could never match. Step names and reasons containing a quote are
|
|
118
|
+
now escaped.
|
|
119
|
+
|
|
120
|
+
Also fixed in the same pass:
|
|
121
|
+
- `const [org, user] = await Promise.all([...])` regenerated as a bare
|
|
122
|
+
`await Promise.all([...])`, leaving both names unbound.
|
|
123
|
+
- A step result assigned inside a branch was re-declared with `const` inside
|
|
124
|
+
that branch, so any later reference was out of scope. Hoisting analysis was
|
|
125
|
+
keyed off the same dead node-id heuristic and never fired.
|
|
126
|
+
- A top-level step whose _name_ contained `_case`, `_item_`, `_then_`,
|
|
127
|
+
`_else_`, `_child_` or `_default_` was silently deleted, because node ids are
|
|
128
|
+
step names and were matched against those structural substrings. Ownership is
|
|
129
|
+
now read from the parent constructs themselves.
|
|
130
|
+
|
|
131
|
+
- 1a86d3f: Stop corrupting values when regenerating a workflow from its graph.
|
|
132
|
+
- A numeric `workflow.sleep('Wait', 5000)` came back as `'5000'`, and a numeric
|
|
133
|
+
`retryDelay` likewise. Durations are `string | number`; only strings are
|
|
134
|
+
quoted now.
|
|
135
|
+
- An assignment to a context variable was stored as an opaque `value`, so
|
|
136
|
+
`count = count + 1` regenerated as `count = 'count + 1'` — an expression
|
|
137
|
+
turned into a string literal. `SetStepMeta` now carries a separate
|
|
138
|
+
`expression` field (mirroring `SwitchCaseMeta`), so a string literal and a
|
|
139
|
+
code expression are no longer indistinguishable in the meta.
|
|
140
|
+
- A `next` that was not a single node id was coerced with a string cast: an
|
|
141
|
+
array became the bogus id `'a,b'` and a branch-key record became
|
|
142
|
+
`'[object Object]'`, severing every downstream node. Arrays, key-based
|
|
143
|
+
routing tables and condition lists now each render in their own shape.
|
|
144
|
+
- A `filter`/`some`/`every` node with no `outputVar` emitted
|
|
145
|
+
`const undefined = ...`, which does not parse.
|
|
146
|
+
|
|
147
|
+
- 1a86d3f: Keep a `workflow.sleep` whose duration is only known at runtime (a loop
|
|
148
|
+
variable, a field off the input). The closure evaluates it, so it is legal DSL;
|
|
149
|
+
its source text is recorded as an `expression` and emitted raw when regenerating
|
|
150
|
+
code, as a set step already does.
|
|
151
|
+
- 314ace3: Cut the schema generator's ts.Program cost — the dominant contributor to `pikku all` memory and time.
|
|
152
|
+
|
|
153
|
+
Two independent fixes: the program is now scoped to the virtual file's import
|
|
154
|
+
closure (870 source files instead of the whole tsconfig's 2572), and it is
|
|
155
|
+
released once schemas are generated instead of being pinned at module scope for
|
|
156
|
+
the life of the process. On a 279-function tree this cuts cold codegen ~20% and
|
|
157
|
+
in-pass live heap ~21%, with byte-identical schema output.
|
|
158
|
+
|
|
159
|
+
- 3d76f51: Add an optional `docsUrl` to `wireSecret`, `wireVariable`, and `wireCredential`, so a console or deploy UI reporting a missing value can link the user to where they obtain it instead of showing a bare identifier.
|
|
160
|
+
- Updated dependencies [1a86d3f]
|
|
161
|
+
- Updated dependencies [1a86d3f]
|
|
162
|
+
- Updated dependencies [1a86d3f]
|
|
163
|
+
- Updated dependencies [1a86d3f]
|
|
164
|
+
- Updated dependencies [1a86d3f]
|
|
165
|
+
- Updated dependencies [1a86d3f]
|
|
166
|
+
- Updated dependencies [3d76f51]
|
|
167
|
+
- @pikku/core@0.12.65
|
|
168
|
+
|
|
169
|
+
## 0.12.43
|
|
170
|
+
|
|
171
|
+
### Patch Changes
|
|
172
|
+
|
|
173
|
+
- c478794: Simplify authorization to be session + function based (#972). Permissions are now function-scoped only: global permissions AND together, a function's own permissions OR together, and the two are independent gates that both must pass — a broad global can no longer satisfy an admin-only function. Removed wire-, tag-, and HTTP-route-level permissions (`addTagPermission`, `addHTTPPermission`, wire-level `permissions` on HTTP/channel/MCP wirings). Tags are now organizational only. `auth` (session presence) and tag/HTTP middleware are unchanged.
|
|
174
|
+
- b714fd4: Merge an addon's credential meta into the consuming app during inspection, the
|
|
175
|
+
same way addon secrets and variables are already merged. Without this, a
|
|
176
|
+
credential declared by an addon (e.g. an OAuth2 integration) never reached the
|
|
177
|
+
app's `CREDENTIAL_OAUTH2_CONFIGS`, so the `credential-oauth` provider and the
|
|
178
|
+
credential service could not resolve it — the addon's Connect flow and status
|
|
179
|
+
silently no-op'd. Addon credentials are added as fallbacks: an app-declared
|
|
180
|
+
credential of the same name still wins.
|
|
181
|
+
- cb079cc: `pikkuAIAgent` gains a `workflows: []` capability: a referenced workflow is exposed to the LLM as a tool that runs inline and returns its output.
|
|
182
|
+
- 13474a6: Generate a `ScopeId` union from `wireScope` declarations.
|
|
183
|
+
|
|
184
|
+
`pikku all` now emits `.pikku/scopes/pikku-scopes.gen.ts` with a `ScopeId` union
|
|
185
|
+
of every declared scope, plus a wildcard form for each node that has
|
|
186
|
+
descendants. A project's generated `pikkuFunc` narrows `scopes` to that union,
|
|
187
|
+
so an undeclared scope is a compile error with editor autocomplete:
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
wireScope({ admin: { scopes: { invoices: { scopes: { create: {} } } } } })
|
|
191
|
+
|
|
192
|
+
pikkuFunc({
|
|
193
|
+
scopes: ['admin:invoices:create'], // ✓ autocompleted
|
|
194
|
+
func: ...,
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
pikkuFunc({
|
|
198
|
+
scopes: ['admin:invoice:create'], // ✗ compile error (typo)
|
|
199
|
+
func: ...,
|
|
200
|
+
})
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The inspector independently rejects undeclared scopes, so a cast that defeats
|
|
204
|
+
the compiler is still caught at build time.
|
|
205
|
+
|
|
206
|
+
Also fixes `getArrayPropertyValue` dropping any array behind a cast — idiomatic
|
|
207
|
+
`tags: ['a'] as const` was previously invisible to the inspector and silently
|
|
208
|
+
omitted from meta.
|
|
209
|
+
|
|
210
|
+
- ca0d14f: Apply `credentialOverrides` when merging an addon's credentials into the consuming app, mirroring the existing `secretOverrides`/`variableOverrides` handling. Previously the credentials merge ignored overrides and always registered the addon's logical credential name, so a second instance of the same package (`wireAddon` with a `credentialOverrides` map) failed `validateCredentialOverrides` and both instances shared one OAuth provider. Now each override's resolved name is provisioned as its own credential — and since the credential name doubles as the better-auth providerId, two instances surface two distinct providers instead of a shared account pool.
|
|
211
|
+
- 13474a6: feat: propagate an addon's declared scopes to the host
|
|
212
|
+
|
|
213
|
+
An addon can now declare scopes with `wireScope`, and a host that wires it picks
|
|
214
|
+
them up: they merge into the host's `ScopeId` union and its declared set, so a
|
|
215
|
+
host function can require an addon scope and the `pikku_scopes` foreign key
|
|
216
|
+
accepts granting one. This mirrors how addon secrets and variables are loaded.
|
|
217
|
+
|
|
218
|
+
The generated `pikku-scopes.gen.ts` now imports its metadata sidecar and derives
|
|
219
|
+
`SCOPES` from it, rather than inlining the list. TypeScript only emits a `.json`
|
|
220
|
+
into the build output when something imports it, and an addon publishes only
|
|
221
|
+
that output — without the import, an addon's scopes never reached a host.
|
|
222
|
+
|
|
223
|
+
- cb079cc: `pikkuWorkflowGraph` nodes accept an optional `notes?: string` and the graph an optional `notes?: string[]`; notes are documentation only and excluded from `graphHash`.
|
|
224
|
+
- cb079cc: Fix two corpus type-check failures: n8n `graph:sort`/`graph:summarize` enum rows now emit `as const`, and the inspector's `sanitizeTypeName` prefixes an underscore when a name starts with a digit.
|
|
225
|
+
- 8601505: Make `wireCredential` the single source of truth for an addon's OAuth2 config: `pikku-credentials.gen.ts` exports `CREDENTIAL_OAUTH2_CONFIGS`, generated services import from it, the OpenAPI importer emits a `wireCredential`, and the inspector now extracts `oauth2.additionalParams`.
|
|
226
|
+
- 70fa400: Add outgoing webhooks — `webhookService.send()` enqueues signed deliveries onto a retrying queue, `@pikku/kysely`'s `KyselyWebhookService` persists per-attempt delivery history, and `@pikku/console` gains a read-only `/webhooks` page; also caches resolved secrets in `TypedSecretService` and registers inline-`func` metadata for queue/scheduler/trigger/gateway wirings.
|
|
227
|
+
- 3c75366: Key `secretOverrides`/`variableOverrides` on the secretId/variableId (the string the addon actually reads by — its typed map is keyed by id, e.g. `getSecret('MAILGUN_CREDENTIALS')`), not the logical meta name. The runtime aliaser already keys on the id, but the inspector merge + validation keyed on the logical name, so a correctly-keyed override failed validation and never provisioned its target whenever an addon's logical name differed from its id (the common case — `mailgun`/`MAILGUN_CREDENTIALS`). The existing test masked it by using a secret whose name equalled its id. The merge now resolves and provisions by id (with a name-fallback for older meta), validation checks ids, and the console install codegen generates overrides keyed by id.
|
|
228
|
+
- 7b2ea23: `wireAddon` can install one addon package as multiple named instances, each with its own per-instance singleton services and `secretOverrides`/`variableOverrides`/`credentialOverrides` that alias logical names to real project secrets/variables/credentials.
|
|
229
|
+
- 13474a6: Extract `wireScope` declarations and validate scope references.
|
|
230
|
+
|
|
231
|
+
Functions referencing a scope that no `wireScope` declares now fail the build
|
|
232
|
+
with an `INVALID_VALUE` critical listing the available scopes, so a typo like
|
|
233
|
+
`admin:invoice:create` is caught at codegen rather than at runtime.
|
|
234
|
+
|
|
235
|
+
`wireScope` declarations wrapped in a cast (`as const`, `as any`) are unwrapped
|
|
236
|
+
before extraction rather than being silently skipped.
|
|
237
|
+
|
|
238
|
+
- d2a6eea: Add `wireRemoteAddon` — consume a hosted addon's `remote: true` RPCs transparently over HTTP, with the addon installed as a devDependency (types only). `rpc('ns:fn', input)` dispatches to the host's `/remote/rpc/:rpcName`, authenticating as a client with a token bound from a local source (`{ credentialId }` per-user, `{ secretId }` platform, or a custom `resolve()`), or omitted for a public surface. This is any-machine → hosted-library client auth, distinct from the trusted mesh (`PIKKU_REMOTE_SECRET`). A new `.remote.gen.d.ts` RPC map exposes only the `remote: true` surface to consumers. `pikku` verify errors if a `wireRemoteAddon` package is a production dependency (or missing) instead of a devDependency, and if a bound `credentialId`/`secretId` isn't wired.
|
|
239
|
+
- 30e62ee: Add `workflow.approval(reason, { schema, expiry })` — a return-valued, expiring human-in-the-loop gate that stays closed until a decision is recorded (via `workflowService.approveStep` or `POST /workflow/:workflowName/approve/:runId`), unlike the one-shot `workflow.suspend()`.
|
|
240
|
+
- Updated dependencies [7ab5287]
|
|
241
|
+
- Updated dependencies [e86bc17]
|
|
242
|
+
- Updated dependencies [a9b96a0]
|
|
243
|
+
- Updated dependencies [3f7fc54]
|
|
244
|
+
- Updated dependencies [c478794]
|
|
245
|
+
- Updated dependencies [3f04ae4]
|
|
246
|
+
- Updated dependencies [90d9f04]
|
|
247
|
+
- Updated dependencies [cb079cc]
|
|
248
|
+
- Updated dependencies [cb079cc]
|
|
249
|
+
- Updated dependencies [0a7db82]
|
|
250
|
+
- Updated dependencies [981c4db]
|
|
251
|
+
- Updated dependencies [13474a6]
|
|
252
|
+
- Updated dependencies [5a2b0d5]
|
|
253
|
+
- Updated dependencies [13474a6]
|
|
254
|
+
- Updated dependencies [ee040dc]
|
|
255
|
+
- Updated dependencies [cb079cc]
|
|
256
|
+
- Updated dependencies [13474a6]
|
|
257
|
+
- Updated dependencies [9f0d0eb]
|
|
258
|
+
- Updated dependencies [13474a6]
|
|
259
|
+
- Updated dependencies [70fa400]
|
|
260
|
+
- Updated dependencies [7b2ea23]
|
|
261
|
+
- Updated dependencies [1dc77d5]
|
|
262
|
+
- Updated dependencies [416606c]
|
|
263
|
+
- Updated dependencies [d2a6eea]
|
|
264
|
+
- Updated dependencies [30e62ee]
|
|
265
|
+
- @pikku/core@0.12.64
|
|
266
|
+
|
|
1
267
|
## 0.12.42
|
|
2
268
|
|
|
3
269
|
### Patch Changes
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import type { AddWiring, InspectorLogger } from '../types.js';
|
|
3
|
+
export declare function resolveWorkflowReferences(obj: ts.ObjectLiteralExpression, checker: ts.TypeChecker, agentName: string, logger: InspectorLogger): string[] | null;
|
|
2
4
|
export declare const addAIAgent: AddWiring;
|
package/dist/add/add-ai-agent.js
CHANGED
|
@@ -83,6 +83,81 @@ function resolveAgentReferences(obj, checker, agentName, logger) {
|
|
|
83
83
|
}
|
|
84
84
|
return resolved.length > 0 ? resolved : null;
|
|
85
85
|
}
|
|
86
|
+
export function resolveWorkflowReferences(obj, checker, agentName, logger) {
|
|
87
|
+
const property = obj.properties.find((p) => ts.isPropertyAssignment(p) &&
|
|
88
|
+
ts.isIdentifier(p.name) &&
|
|
89
|
+
p.name.text === 'workflows');
|
|
90
|
+
if (!property || !ts.isPropertyAssignment(property)) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const initializer = property.initializer;
|
|
94
|
+
if (!ts.isArrayLiteralExpression(initializer)) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const resolved = [];
|
|
98
|
+
for (const element of initializer.elements) {
|
|
99
|
+
if (ts.isStringLiteral(element)) {
|
|
100
|
+
logger.critical(ErrorCode.INVALID_VALUE, `AI agent '${agentName}' workflows array contains a string literal '${element.text}'. ` +
|
|
101
|
+
`Use a workflow reference instead (e.g., ref('<workflowName>') or import the pikkuWorkflowGraph variable).`);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (ts.isCallExpression(element) && ts.isIdentifier(element.expression)) {
|
|
105
|
+
const calleeName = element.expression.text;
|
|
106
|
+
if (calleeName === 'ref' || calleeName === 'workflow') {
|
|
107
|
+
const [firstArg] = element.arguments;
|
|
108
|
+
if (firstArg && ts.isStringLiteral(firstArg)) {
|
|
109
|
+
resolved.push(firstArg.text);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (ts.isIdentifier(element)) {
|
|
115
|
+
const name = resolveIdentifierToWorkflowName(element, checker);
|
|
116
|
+
if (name) {
|
|
117
|
+
resolved.push(name);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
logger.critical(ErrorCode.INVALID_VALUE, `AI agent '${agentName}' workflows array contains identifier '${element.text}' ` +
|
|
121
|
+
`that could not be resolved to a pikkuWorkflowGraph.`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return resolved.length > 0 ? resolved : null;
|
|
125
|
+
}
|
|
126
|
+
function resolveIdentifierToWorkflowName(identifier, checker) {
|
|
127
|
+
const symbol = checker.getSymbolAtLocation(identifier);
|
|
128
|
+
if (!symbol)
|
|
129
|
+
return null;
|
|
130
|
+
let resolved = symbol;
|
|
131
|
+
if (resolved.flags & ts.SymbolFlags.Alias) {
|
|
132
|
+
resolved = checker.getAliasedSymbol(resolved) ?? resolved;
|
|
133
|
+
}
|
|
134
|
+
const decl = resolved.valueDeclaration ?? resolved.declarations?.[0];
|
|
135
|
+
if (!decl)
|
|
136
|
+
return null;
|
|
137
|
+
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
138
|
+
if (ts.isCallExpression(decl.initializer) &&
|
|
139
|
+
ts.isIdentifier(decl.initializer.expression) &&
|
|
140
|
+
(decl.initializer.expression.text === 'pikkuWorkflowGraph' ||
|
|
141
|
+
decl.initializer.expression.text === 'pikkuWorkflow' ||
|
|
142
|
+
decl.initializer.expression.text === 'pikkuWorkflowComplex')) {
|
|
143
|
+
const firstArg = decl.initializer.arguments[0];
|
|
144
|
+
if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
|
|
145
|
+
for (const prop of firstArg.properties) {
|
|
146
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
147
|
+
ts.isIdentifier(prop.name) &&
|
|
148
|
+
prop.name.text === 'name' &&
|
|
149
|
+
ts.isStringLiteral(prop.initializer)) {
|
|
150
|
+
return prop.initializer.text;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (ts.isIdentifier(decl.name)) {
|
|
155
|
+
return decl.name.text;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
86
161
|
function resolveIdentifierToRpcName(identifier, checker) {
|
|
87
162
|
const symbol = checker.getSymbolAtLocation(identifier);
|
|
88
163
|
if (!symbol)
|
|
@@ -181,6 +256,12 @@ export const addAIAgent = (logger, node, checker, state, options) => {
|
|
|
181
256
|
}
|
|
182
257
|
}
|
|
183
258
|
const agentsValue = resolveAgentReferences(obj, checker, nameValue || '', logger);
|
|
259
|
+
const workflowsValue = resolveWorkflowReferences(obj, checker, nameValue || '', logger);
|
|
260
|
+
if (workflowsValue) {
|
|
261
|
+
for (const workflowName of workflowsValue) {
|
|
262
|
+
state.workflows.invokedWorkflows.add(workflowName);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
184
265
|
if (!nameValue) {
|
|
185
266
|
logger.critical(ErrorCode.MISSING_NAME, "AI agent is missing the required 'name' property.");
|
|
186
267
|
return;
|
|
@@ -307,6 +388,7 @@ export const addAIAgent = (logger, node, checker, state, options) => {
|
|
|
307
388
|
}),
|
|
308
389
|
...(toolsValue !== null && { tools: toolsValue }),
|
|
309
390
|
...(agentsValue !== null && { agents: agentsValue }),
|
|
391
|
+
...(workflowsValue !== null && { workflows: workflowsValue }),
|
|
310
392
|
tags,
|
|
311
393
|
inputSchema,
|
|
312
394
|
outputSchema,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue, getArrayPropertyValue, assertStringLiteralProperty, } from '../utils/get-property-value.js';
|
|
2
|
+
import { getPropertyValue, getArrayPropertyValue, getRecordPropertyValue, assertStringLiteralProperty, } from '../utils/get-property-value.js';
|
|
3
3
|
import { ErrorCode } from '../error-codes.js';
|
|
4
4
|
import { detectSchemaVendorOrError } from '../utils/detect-schema-vendor.js';
|
|
5
5
|
export const addCredential = (logger, node, checker, state, _options) => {
|
|
@@ -22,6 +22,7 @@ export const addCredential = (logger, node, checker, state, _options) => {
|
|
|
22
22
|
const displayNameValue = getPropertyValue(obj, 'displayName');
|
|
23
23
|
const descriptionValue = getPropertyValue(obj, 'description');
|
|
24
24
|
const typeValue = getPropertyValue(obj, 'type');
|
|
25
|
+
const docsUrlValue = getPropertyValue(obj, 'docsUrl');
|
|
25
26
|
if (!nameValue) {
|
|
26
27
|
logger.critical(ErrorCode.MISSING_NAME, "Credential is missing the required 'name' property.");
|
|
27
28
|
return;
|
|
@@ -81,6 +82,7 @@ export const addCredential = (logger, node, checker, state, _options) => {
|
|
|
81
82
|
const tokenUrl = getPropertyValue(oauth2Obj, 'tokenUrl');
|
|
82
83
|
const scopes = getArrayPropertyValue(oauth2Obj, 'scopes');
|
|
83
84
|
const pkce = getPropertyValue(oauth2Obj, 'pkce');
|
|
85
|
+
const additionalParams = getRecordPropertyValue(oauth2Obj, 'additionalParams');
|
|
84
86
|
if (appCredentialSecretId && authorizationUrl && tokenUrl && scopes) {
|
|
85
87
|
oauth2 = {
|
|
86
88
|
appCredentialSecretId,
|
|
@@ -89,6 +91,7 @@ export const addCredential = (logger, node, checker, state, _options) => {
|
|
|
89
91
|
tokenUrl,
|
|
90
92
|
scopes,
|
|
91
93
|
pkce: pkce || undefined,
|
|
94
|
+
additionalParams: additionalParams || undefined,
|
|
92
95
|
};
|
|
93
96
|
}
|
|
94
97
|
}
|
|
@@ -111,6 +114,7 @@ export const addCredential = (logger, node, checker, state, _options) => {
|
|
|
111
114
|
displayName: displayNameValue,
|
|
112
115
|
description: descriptionValue || undefined,
|
|
113
116
|
type: typeValue,
|
|
117
|
+
docsUrl: docsUrlValue || undefined,
|
|
114
118
|
schema: schemaLookupName,
|
|
115
119
|
oauth2,
|
|
116
120
|
sourceFile,
|
|
@@ -4,7 +4,7 @@ import { extractFunctionName, funcIdToTypeName, } from '../utils/extract-functio
|
|
|
4
4
|
import { extractFunctionNode } from '../utils/extract-function-node.js';
|
|
5
5
|
import { extractUsedWires } from '../utils/extract-services.js';
|
|
6
6
|
import { formatVersionedId, parseVersionedId } from '@pikku/core';
|
|
7
|
-
import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
|
|
7
|
+
import { getPropertyValue, getArrayPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
|
|
8
8
|
import { canonicalJSON, hashString } from '../utils/hash.js';
|
|
9
9
|
import { resolveMiddleware } from '../utils/middleware.js';
|
|
10
10
|
import { resolvePermissions } from '../utils/permissions.js';
|
|
@@ -304,6 +304,7 @@ export const addFunctions = (logger, node, checker, state, options) => {
|
|
|
304
304
|
let workflowQueued;
|
|
305
305
|
let workflowRetries;
|
|
306
306
|
let workflowTimeout;
|
|
307
|
+
let scopes;
|
|
307
308
|
let version;
|
|
308
309
|
let objectNode;
|
|
309
310
|
let nodeDisplayName = null;
|
|
@@ -374,6 +375,7 @@ export const addFunctions = (logger, node, checker, state, options) => {
|
|
|
374
375
|
workflowQueued = getPropertyValue(firstArg, 'workflowQueued');
|
|
375
376
|
workflowRetries = getPropertyValue(firstArg, 'workflowRetries');
|
|
376
377
|
workflowTimeout = getPropertyValue(firstArg, 'workflowTimeout');
|
|
378
|
+
scopes = getArrayPropertyValue(firstArg, 'scopes') ?? undefined;
|
|
377
379
|
// Extract approvalDescription identifier reference
|
|
378
380
|
for (const prop of firstArg.properties) {
|
|
379
381
|
if (ts.isPropertyAssignment(prop) &&
|
|
@@ -735,13 +737,6 @@ export const addFunctions = (logger, node, checker, state, options) => {
|
|
|
735
737
|
if (newMiddleware.length > 0) {
|
|
736
738
|
middleware = [...(middleware || []), ...newMiddleware];
|
|
737
739
|
}
|
|
738
|
-
const existingPermissionTags = new Set((permissions || [])
|
|
739
|
-
.filter((p) => p.type === 'tag')
|
|
740
|
-
.map((p) => p.tag));
|
|
741
|
-
const newPermissions = tagEntries.filter((e) => !existingPermissionTags.has(e.tag));
|
|
742
|
-
if (newPermissions.length > 0) {
|
|
743
|
-
permissions = [...(permissions || []), ...newPermissions];
|
|
744
|
-
}
|
|
745
740
|
}
|
|
746
741
|
const implementationHash = computeImplementationHash({
|
|
747
742
|
wrapper: expression.text,
|
|
@@ -786,6 +781,7 @@ export const addFunctions = (logger, node, checker, state, options) => {
|
|
|
786
781
|
workflowQueued: workflowQueued === true ? true : undefined,
|
|
787
782
|
workflowRetries: workflowRetries ?? undefined,
|
|
788
783
|
workflowTimeout: workflowTimeout ?? undefined,
|
|
784
|
+
scopes: scopes ?? undefined,
|
|
789
785
|
implementationHash,
|
|
790
786
|
version,
|
|
791
787
|
title,
|
|
@@ -836,7 +832,6 @@ export const addFunctions = (logger, node, checker, state, options) => {
|
|
|
836
832
|
inputSchema: inputNames[0] ?? null,
|
|
837
833
|
outputSchema: outputNames[0] ?? null,
|
|
838
834
|
middleware,
|
|
839
|
-
permissions,
|
|
840
835
|
};
|
|
841
836
|
state.serviceAggregation.usedFunctions.add(pikkuFuncId);
|
|
842
837
|
extractWireNames(middleware).forEach((n) => state.serviceAggregation.usedMiddleware.add(n));
|
|
@@ -870,6 +865,12 @@ export const addFunctions = (logger, node, checker, state, options) => {
|
|
|
870
865
|
}
|
|
871
866
|
if (remote) {
|
|
872
867
|
state.rpc.invokedFunctions.add(pikkuFuncId);
|
|
868
|
+
// The consumer-facing surface a wireRemoteAddon imports (mirrors exposedMeta)
|
|
869
|
+
state.rpc.remoteMeta[name] = pikkuFuncId;
|
|
870
|
+
state.rpc.remoteFiles.set(name, {
|
|
871
|
+
path: node.getSourceFile().fileName,
|
|
872
|
+
exportedName,
|
|
873
|
+
});
|
|
873
874
|
}
|
|
874
875
|
if (expose) {
|
|
875
876
|
state.rpc.exposedMeta[name] = pikkuFuncId;
|
package/dist/add/add-gateway.js
CHANGED
|
@@ -2,6 +2,7 @@ import * as ts from 'typescript';
|
|
|
2
2
|
import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
|
|
3
3
|
import { extractFunctionName, makeContextBasedId, } from '../utils/extract-function-name.js';
|
|
4
4
|
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
5
|
+
import { ensureInlineWiringFunction } from '../utils/ensure-function-metadata.js';
|
|
5
6
|
import { resolveMiddleware } from '../utils/middleware.js';
|
|
6
7
|
import { extractWireNames } from '../utils/post-process.js';
|
|
7
8
|
import { resolveAddonName } from '../utils/resolve-addon-package.js';
|
|
@@ -44,6 +45,8 @@ export const addGateway = (logger, node, checker, state, _options) => {
|
|
|
44
45
|
if (!nameValue || !typeValue) {
|
|
45
46
|
return;
|
|
46
47
|
}
|
|
48
|
+
// Register metadata for a func inlined into the wiring (see helper).
|
|
49
|
+
ensureInlineWiringFunction(state, pikkuFuncId, nameValue, funcInitializer, checker, extracted.isHelper);
|
|
47
50
|
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
48
51
|
state.serviceAggregation.usedFunctions.add(pikkuFuncId);
|
|
49
52
|
extractWireNames(middleware).forEach((name) => state.serviceAggregation.usedMiddleware.add(name));
|
|
@@ -4,7 +4,7 @@ import { pathToRegexp } from 'path-to-regexp';
|
|
|
4
4
|
import { extractFunctionName, makeContextBasedId, } from '../utils/extract-function-name.js';
|
|
5
5
|
import { getPropertyAssignmentInitializer, extractTypeKeys, } from '../utils/type-utils.js';
|
|
6
6
|
import { resolveHTTPMiddlewareFromObject } from '../utils/middleware.js';
|
|
7
|
-
import {
|
|
7
|
+
import { resolvePermissions } from '../utils/permissions.js';
|
|
8
8
|
import { extractWireNames } from '../utils/post-process.js';
|
|
9
9
|
import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js';
|
|
10
10
|
import { resolveFunctionMeta } from '../utils/resolve-function-meta.js';
|
|
@@ -219,7 +219,7 @@ export function registerHTTPRoute({ obj, state, checker, logger, sourceFile, bas
|
|
|
219
219
|
// Resolve middleware
|
|
220
220
|
const middleware = resolveHTTPMiddlewareFromObject(state, fullRoute, obj, tags, checker);
|
|
221
221
|
// Resolve permissions
|
|
222
|
-
const permissions =
|
|
222
|
+
const permissions = resolvePermissions(state, obj, tags, checker);
|
|
223
223
|
state.serviceAggregation.usedFunctions.add(funcName);
|
|
224
224
|
if (refAddonTarget) {
|
|
225
225
|
state.serviceAggregation.usedFunctions.add(refAddonTarget);
|
|
@@ -26,6 +26,7 @@ export const createAddKeyedWiring = (config) => {
|
|
|
26
26
|
const displayNameValue = getPropertyValue(obj, 'displayName');
|
|
27
27
|
const descriptionValue = getPropertyValue(obj, 'description');
|
|
28
28
|
const rotationPeriodValue = getPropertyValue(obj, 'rotationPeriod');
|
|
29
|
+
const docsUrlValue = getPropertyValue(obj, 'docsUrl');
|
|
29
30
|
const idValue = getPropertyValue(obj, config.idField);
|
|
30
31
|
let schemaVariableName = null;
|
|
31
32
|
let schemaSourceFile = null;
|
|
@@ -102,6 +103,7 @@ export const createAddKeyedWiring = (config) => {
|
|
|
102
103
|
displayName: displayNameValue,
|
|
103
104
|
description: descriptionValue || undefined,
|
|
104
105
|
rotationPeriod: rotationPeriodValue || undefined,
|
|
106
|
+
docsUrl: docsUrlValue || undefined,
|
|
105
107
|
[config.idField]: idValue,
|
|
106
108
|
schema: schemaLookupName,
|
|
107
109
|
sourceFile,
|