@zapier/kitcore 0.10.1 → 0.11.0

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @zapier/kitcore
2
2
 
3
+ ## 0.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 60892be: Added an explicit per-call annotation channel for attaching and reading per-invocation metadata:
8
+ - A method's `run` bag now includes the live `callContext` plus an `annotate(metadata)` function for recording per-invocation metadata onto the call's annotation bag.
9
+ - The `onMethodStart` / `onMethodEnd` hook context now carries `callId`, the call's `annotations`, and a `callOrigin` field (`"surface"` | `"internal"`), so observers can read a call's correlation id, annotations, and origin directly.
10
+ - `CallContext` gains a `callOrigin` field (`"surface"` | `"internal"`) that marks framework-internal calls, letting observers distinguish user calls from framework machinery (e.g. to keep framework calls out of telemetry). It is inherited by child calls, so a delegated subtree shares its root's origin.
11
+ - `defineHook` gains an optional `annotator` for deriving annotations from a call's input before `onMethodStart`. Multiple plugins' annotators compose (merged right-additively into the call's annotation bag), so annotation is contributed through the plugin graph rather than a single handler.
12
+ - `defineMethod` gains an optional pre-run `annotator` whose result merges into the call's annotations before `run`.
13
+ - Exported the `CallContext`, `Annotations`, and `CallOrigin` types, plus the `MethodAnnotator`, `HookAnnotator`, and `ComposedAnnotator` annotator function types.
14
+
3
15
  ## 0.10.1
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -44,7 +44,7 @@ There are four kinds of plugin, and an SDK is just a materialized plugin:
44
44
 
45
45
  - **Method** (`defineMethod`) — a leaf that _is_ a function.
46
46
  - **Property** (`defineProperty`) — a leaf that _is_ a value.
47
- - **Hook** (`defineHook`) — a leaf contributing cross-cutting behavior (see [Hooks](#hooks-wrap-and-observe)).
47
+ - **Hook** (`defineHook`) — a leaf contributing cross-cutting behavior (see [Hooks](#hooks-wrap-observe-and-annotate)).
48
48
  - **Aggregate** (`definePlugin`) — re-exports other plugins under binding names.
49
49
 
50
50
  A plugin declares `imports` (an array of the plugins it depends on) and receives them as a flat `imports` bag, with each import bound under its own name. The two ends share the word the way ES modules do: `import { x } from "y"` is the declaration, `x` is the binding.
@@ -120,6 +120,26 @@ sdk.next(); // 2
120
120
 
121
121
  `setup` can read `imports`, so state can be built from dependencies. Because state lives behind `setup`, several small "state plugins" can each own a slice instead of one monolith.
122
122
 
123
+ ## Per-call context and annotations
124
+
125
+ Every method `run` bag includes a live `callContext` with the invocation's `callId`, `depth`, `callOrigin`, and `annotations`. Each method invocation gets its own annotation bag; a delegated child shares its root's call ID and origin but starts with empty annotations.
126
+
127
+ Use the run bag's `annotate(fields)` helper for metadata learned during execution. For metadata available from raw input, a method can declare a synchronous `annotator`; it runs before validation, `onMethodStart`, and `run`, so its `input` is `unknown` and must be narrowed before fields are read.
128
+
129
+ ```ts
130
+ const runJob = defineMethod({
131
+ name: "runJob",
132
+ annotator: () => ({ operationType: "write" }),
133
+ run: async ({ input, callContext, annotate }) => {
134
+ const worker = await selectWorker(input);
135
+ annotate({ worker });
136
+ return executeJob(input, callContext.annotations);
137
+ },
138
+ });
139
+ ```
140
+
141
+ Both forms merge into the same bag. `annotator` supplies fields before the method starts; `annotate` adds fields as the method runs.
142
+
123
143
  ## Properties
124
144
 
125
145
  A property is a value rather than a function. It can be a static `value`, or a **live** `get` re-derived on every read, with an optional `setup` building the state `get` returns. So `setup` + `get` mirrors a method's `setup` + `run`.
@@ -217,9 +237,9 @@ const fetchMethod = defineMethod({
217
237
  sdk.fetch("https://example.com", { method: "GET" });
218
238
  ```
219
239
 
220
- ## Hooks: wrap and observe
240
+ ## Hooks: wrap, observe, and annotate
221
241
 
222
- Cross-cutting behavior lives in a **hook** (`defineHook`), a fourth kind of leaf with two faces.
242
+ Cross-cutting behavior lives in a **hook** (`defineHook`), a fourth kind of leaf with three faces.
223
243
 
224
244
  `wrap` is targeted middleware. An entry is keyed by the import binding it wraps and receives `{ imports, next, input }`. It must preserve the target's contract (enforced by the types), so it cannot change the public signature.
225
245
 
@@ -260,6 +280,17 @@ const telemetry = defineHook({
260
280
  });
261
281
  ```
262
282
 
283
+ `annotator` adds cross-cutting annotations before `onMethodStart`. It is a synchronous mapper over `{ methodName, input, state }`; like method annotators, it receives raw pre-validation input. Multiple hook annotators compose in graph order, later fields win on collision, and the method's own annotator runs last. Each contributor is best-effort, so a thrown annotation error never breaks the method or suppresses other contributors.
284
+
285
+ ```ts
286
+ const classifyOperations = defineHook({
287
+ name: "classifyOperations",
288
+ annotator: ({ methodName }) => ({ methodCategory: classify(methodName) }),
289
+ });
290
+ ```
291
+
292
+ Hook annotators run only for outermost surface-origin calls. They are suppressed for nested and internal-origin calls, and for methods called from an observer or another hook annotator. A method's own annotator still runs for every invocation, including those suppressed cases, so method behavior does not depend on how the method was reached.
293
+
263
294
  A hook joins the graph like any other plugin: import or export it from an aggregate.
264
295
 
265
296
  ## Dependency injection