@zapier/kitcore 0.16.0 → 0.17.1

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,138 @@
1
1
  # @zapier/kitcore
2
2
 
3
+ ## 0.17.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 52b672a: Added a `browser` field that maps `node:async_hooks` to `false`, so bundling `@zapier/kitcore` for the browser no longer fails on that Node-only import. Its `AsyncLocalStorage`-backed contexts already fall back to inert when the module is unavailable, so Node behavior is unchanged.
8
+
9
+ `openEnum`'s return type is now written out rather than inferred. The generated declaration expanded it into a form TypeScript rejected (`TS2536`), which surfaced as an error in `dist/index.d.mts` for anyone typechecking with `skipLibCheck: false`.
10
+
11
+ ## 0.17.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 9cde1f6: **`getRegistry(sdk)` reads an SDK's registry without the SDK surfacing
16
+ anything**, and `createController` accepts any built SDK, so introspection costs
17
+ no `getRegistryPlugin` re-export. Re-export it anyway if you want
18
+ `sdk.getRegistry()` for your own callers; both return the same result.
19
+
20
+ Every accessor reads one registry: the free `getRegistry(sdk)`, a re-exported
21
+ `getRegistry()`, and the one a legacy-bridged SDK surfaces all return the same
22
+ memoized object. It is memoized per SDK and per package filter, and every reader
23
+ shares it, so `functions`, `categories`, and each category's own `functions` are
24
+ frozen. Copy before sorting or splicing. The memo lives on the SDK's context, so a process holding two
25
+ copies of kitcore, one bundled into a head and one loaded directly, shares it
26
+ and invalidates it once. A `createPluginStack()` build has no kitcore context and so no
27
+ memo: there the call forwards to the SDK's own `getRegistry()` and hands back a
28
+ fresh, mutable result each time.
29
+
30
+ **A property that declares `dynamicMembers` must have an object value when the
31
+ SDK is built.** `createSdk` throws otherwise, naming the property. The registry
32
+ reports a member like `apps.{appKey}` only while its root is a live object, and
33
+ that answer is memoized, so a root arriving later would leave the registry
34
+ reporting whatever was true when something first read it. Build the root in
35
+ `setup` and return it from `get`.
36
+
37
+ **`defineOverride(method, { ... })` patches how a surface presents a method.**
38
+ Pass the method itself, or a `declareMethod` stand-in when you want to patch one
39
+ without importing it, so no id is respelled and a rename cannot leave a silent
40
+ no-op behind. `namespace` names the override rather than the target, so two
41
+ surfaces can patch the same method in one graph. `defineMethodOverride({ target })`
42
+ still works and warns.
43
+
44
+ **An override patches presentation only.** Its config takes
45
+ `OverridableMetaFields`: `description`, `categories`, `itemType`, `returnType`,
46
+ `packages`, `experimental`, `deprecation`, and `supportsJsonOutput`. Anything
47
+ else throws, including for JavaScript callers the type does not reach. An
48
+ override changes how a surface describes a method, never what it does. A
49
+ method's declared type is fixed at `defineMethod` and nothing re-checks it
50
+ afterwards, so patching output validation, a host's confirmation prompt, or
51
+ which input a caller can pass would let a call fail against a contract its own
52
+ return type says it satisfies. That rules out `outputSchema`, `confirm`, and
53
+ `aliases`, and `type` too, because the registry derives `confirm` from it.
54
+
55
+ **Provide a declared method or property by reference.**
56
+ `defineProperty(ref, { value })` and `defineMethod(ref, { run })` take a
57
+ `declareProperty` / `declareMethod` stand-in instead of a config that respells
58
+ its `name` and `namespace`, so no id string is repeated and `value` and `run`
59
+ are typed against the declaration. It is also how a graph supplies framework
60
+ options as ordinary properties rather than through `createSdk`'s `configuration`
61
+ channel. The method form covers raw output only.
62
+
63
+ **`requireParameters` accepts an absolute path**, which says exactly which value
64
+ a resolver means. A bare name is convenient and can go wrong: it resolves in the
65
+ resolver's own container first, then the root, so when both hold the name the
66
+ container wins and there is no way to say otherwise. An array
67
+ (`[["nested", "owner"]]`) is a path from the root, so it names one place. It also
68
+ reaches a field inside another parameter, which no bare name can address. A
69
+ dotted string is one key, not a path.
70
+
71
+ **A raw method's `outputSchema` is enforced.** Raw has no envelope, so the schema
72
+ is matched against the whole return, and a method that meant to be
73
+ `output: "item"` and returns `{ data }` fails with an error saying so. It
74
+ validates without reshaping: the caller gets the original object back, extras and
75
+ all. **A raw method carrying a schema for projection only needs
76
+ `skipOutputValidation: true`.**
77
+
78
+ **A caller can skip output validation for one call** by passing
79
+ `skipOutputDataValidation: true` alongside an item or list method's input. An
80
+ author's `skipOutputValidation` wins, so a caller can only ever subtract. Raw
81
+ methods do not take it: their call object is entirely the author's, so the key
82
+ there is ordinary input.
83
+
84
+ **A call runs through BOTH schemas.** The framework's own parameters (`cursor`,
85
+ `pageSize`, `maxItems`, `skipOutputDataValidation`) are held to a minimal floor,
86
+ whatever a method declares and even when it declares no `inputSchema` at all.
87
+ The floor rejects only what the machinery cannot act on: `pageSize` at least 1,
88
+ because a page loop asking for zero items does not terminate, `maxItems` at
89
+ least 0, and `cursor` any string.
90
+
91
+ The method's own `inputSchema` then sees the whole call, so a constraint it
92
+ declares on one of those parameters still applies. Write
93
+ `pageSize: z.number().max(100)` and callers get your cap on top of the floor.
94
+ Nothing reads your schema's shape to work this out, so a `.transform()` or
95
+ `.refine()` wrapper cannot hide a declaration.
96
+
97
+ A `strict()` schema is the exception, since it cannot ignore a key it never
98
+ declared. When it rejects a framework parameter by name, that parameter is
99
+ removed and the parse runs again, so the method sees exactly the input it
100
+ described and the error names only the caller's own mistakes.
101
+
102
+ On the way to `run`, the framework's validated value wins for the parameters it
103
+ owns, so a caller asking for `pageSize: 5` gets 5. A list `run` receives the
104
+ `cursor` and `pageSize` of the page it must fetch. `maxItems` and the output
105
+ skip stop at the framework, which is the only thing that can act on them. The
106
+ types say the same: `Parameters<typeof method.run>[0]["input"]` carries the page
107
+ controls and nothing else.
108
+
109
+ **`meta.outputDataValidation` reports what the framework did**, typed
110
+ `OutputDataValidationReport`:
111
+
112
+ ```ts
113
+ | { skipped: true }
114
+ | { skipped: false; droppedPaths: null }
115
+ | { skipped: false; droppedPaths: string[]; instruction: string }
116
+ ```
117
+
118
+ `skipped` says whether the framework parsed, never that the data is unchecked.
119
+ `droppedPaths: null` means nothing was dropped, and `instruction` rides only the
120
+ arm where it is actionable. Reading `droppedPaths` requires narrowing on
121
+ `skipped` first. A report appears only when there is something to say: a caller's
122
+ skip that changed something, or paths dropped with the
123
+ `includeOutputValidationDroppedPaths` core option on.
124
+
125
+ The shape and the instruction wording match the connectors SDK, so a consumer
126
+ moving between them reads one report.
127
+
128
+ `meta.outputValidation` is deprecated in favour of it. It is still written, with
129
+ the same `{ droppedPaths }` shape and the same emission rule, and it will be
130
+ removed in a later release.
131
+
132
+ `StandInId` and `SdkContextCarrier` are exported so a package building on
133
+ kitcore can emit declarations that name them. Nothing asks you to write either
134
+ one yourself.
135
+
3
136
  ## 0.16.0
4
137
 
5
138
  ### Minor Changes
package/README.md CHANGED
@@ -350,21 +350,23 @@ await disposeSdk(sdk, { exitCode: 0 });
350
350
 
351
351
  ## Introspection
352
352
 
353
- Re-export the built-in `getRegistryPlugin` to put a `getRegistry()` method on the SDK. It reports the live surface as plain data (one entry per binding, with the leaf's metadata), which is what drives generated docs, CLI commands, and MCP tools.
353
+ `getRegistry(sdk)` reports the live surface as plain data (one entry per binding, with the leaf's metadata), which is what drives generated docs, CLI commands, and MCP tools. It needs nothing on the SDK itself.
354
354
 
355
355
  ```ts
356
- import { getRegistryPlugin } from "@zapier/kitcore";
356
+ import { getRegistry } from "@zapier/kitcore";
357
357
 
358
- const sdk = createSdk(
359
- definePlugin({ name: "api", exports: [greet, getRegistryPlugin] }),
360
- );
358
+ const sdk = createSdk(definePlugin({ name: "api", exports: [greet] }));
361
359
 
362
- const registry = sdk.getRegistry();
360
+ const registry = getRegistry(sdk);
363
361
  registry.functions; // [{ name, description, inputSchema, ... }]
364
362
  registry.categories; // grouped for menus / docs
365
363
  ```
366
364
 
367
- Because the registry reads the surface at call time, it also reflects anything added later with `addPlugin`.
365
+ Re-export the built-in `getRegistryPlugin` if you also want a `getRegistry()` method on the SDK surface for your own callers. It is a thin shim over the same result, so the two agree. Ids are scoped to a graph, so separate SDKs in one process can each register it; what cannot work is one graph pulling in two copies of kitcore, whose built-ins would then collide on the shared `kitcore/getRegistry` id. Introspection does not depend on the re-export either way.
366
+
367
+ The result is memoized per SDK and per package filter, and `addPlugin` drops it, so a registry read still reflects anything added after the build. Because every reader shares that one object, its `functions` and `categories` arrays are frozen: copy before sorting or filtering in place.
368
+
369
+ That holds for an SDK with a kitcore context, which is anything `createSdk` built. An SDK without one, meaning a `createPluginStack()` build, has no memo to share: `getRegistry(sdk)` forwards to the SDK's own `getRegistry()` and hands back whatever it builds, fresh and mutable on every call.
368
370
 
369
371
  ## Resolving inputs: controllers
370
372