@ekanos/cli 0.2.0 → 0.2.2
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/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ekanos/cli",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"private": false,
|
|
3
|
+
"version": "0.2.2",
|
|
5
4
|
"type": "module",
|
|
6
5
|
"description": "The Ekanos partner toolchain CLI: scaffold, validate, and test a Fusion integration against the published @ekanos packages. Agent-native — every verb speaks JSON with a stable exit-code taxonomy.",
|
|
7
6
|
"license": "MIT",
|
|
@@ -34,7 +33,7 @@
|
|
|
34
33
|
},
|
|
35
34
|
"dependencies": {
|
|
36
35
|
"@clack/prompts": "1.7.0",
|
|
37
|
-
"@ekanos/integration-schema": "0.
|
|
36
|
+
"@ekanos/integration-schema": "0.2.0",
|
|
38
37
|
"esbuild": "0.28.1",
|
|
39
38
|
"picocolors": "1.1.1"
|
|
40
39
|
},
|
package/templates/AGENTS.md.tmpl
CHANGED
|
@@ -212,9 +212,15 @@ your slug (`__SLUG__-<name>`). `widgetState` (usually `'active'`), plus
|
|
|
212
212
|
|
|
213
213
|
Render through the `Widget.*` compound API and `WidgetContext` from
|
|
214
214
|
`@ekanos/sdk/components`; wrap in `WidgetPreviewProvider` to render outside
|
|
215
|
-
the host.
|
|
216
|
-
`
|
|
217
|
-
|
|
215
|
+
the host. Widgets talk to a vendor with `useIntegrationFetch()` from
|
|
216
|
+
`@ekanos/sdk/hooks` — never global `fetch` — and reach for `useActivationData()`
|
|
217
|
+
(same module) when a widget needs a client-visible credential or activation
|
|
218
|
+
field. Both have a safe default when nothing has mounted a provider (a plain
|
|
219
|
+
fetch wrapper, and `null`, respectively), so calling them never crashes; see
|
|
220
|
+
"Network model" below for what that fetch is actually gated by, in the
|
|
221
|
+
harness and in production. A widget reads declared `clientReadable`
|
|
222
|
+
account-scope storage back with `fetchIntegrationStorage()` from
|
|
223
|
+
`@ekanos/sdk/hooks`.
|
|
218
224
|
|
|
219
225
|
Build widget UI from `@ekanos/ui` — the published slice of the host design
|
|
220
226
|
system. Available modules (import individually, e.g. `@ekanos/ui/button`):
|
|
@@ -240,11 +246,13 @@ it looking like anything in particular.
|
|
|
240
246
|
The harness (`npx ekanos dev`) mocks FUSION, not your vendor. **You do not
|
|
241
247
|
need mock data to develop against the real API**, and never claim otherwise:
|
|
242
248
|
the dev toolbar has a fixtures ⇄ live switch per integration, and in live
|
|
243
|
-
mode your widgets' real query functions
|
|
244
|
-
real vendor API. The
|
|
245
|
-
`defineIntegration()
|
|
246
|
-
uses, so an origin you forgot to declare fails on
|
|
247
|
-
`EgressDeniedError` instead of in review
|
|
249
|
+
mode your widgets' real query functions — calling `useIntegrationFetch()` —
|
|
250
|
+
run and their requests reach the real vendor API. The gate is the `egress`
|
|
251
|
+
allowlist from `defineIntegration()`, checked with the same matcher
|
|
252
|
+
production's `ctx.fetch` uses, so an origin you forgot to declare fails on
|
|
253
|
+
this machine with `EgressDeniedError` instead of in review — see "Network
|
|
254
|
+
model" below for what that check does and does not mean once you're not in
|
|
255
|
+
the harness anymore.
|
|
248
256
|
|
|
249
257
|
Live mode is opt-in per integration. Add a `live` block to the entry in
|
|
250
258
|
`harness.config.ts`:
|
|
@@ -269,6 +277,30 @@ webhook/schedule/onActivate handlers against the mock context (its
|
|
|
269
277
|
`ctx.fetch` never touches the network) — cover handler network behavior
|
|
270
278
|
with fixtures in tests, then for real on the dev host after publishing.
|
|
271
279
|
|
|
280
|
+
### Network model
|
|
281
|
+
|
|
282
|
+
Two different fetches, two different guarantees:
|
|
283
|
+
|
|
284
|
+
- **`ctx.fetch` (handlers — `onActivate`/webhooks/schedules/tools).** Real
|
|
285
|
+
enforcement, in the harness AND in production: your `egress` allowlist,
|
|
286
|
+
redirect re-vetting, IP pinning. Locally, handlers only ever run on
|
|
287
|
+
Triggers/Activate against the mock context, so their `ctx.fetch` never
|
|
288
|
+
leaves your machine regardless of the toolbar — real network only after
|
|
289
|
+
you publish to a dev host.
|
|
290
|
+
- **`useIntegrationFetch()` (widgets, browser-side).** In the harness, live
|
|
291
|
+
mode routes it through the same egress check as a convenience, enforced
|
|
292
|
+
centrally rather than something you configure per widget. **That check
|
|
293
|
+
does not exist in production** — a browser can't pin an address or
|
|
294
|
+
re-vet a redirect the way `ctx.fetch` does, and today's host mounts no
|
|
295
|
+
egress check on the client path at any layer. Do not read
|
|
296
|
+
`useIntegrationFetch()`'s live-mode behavior as "the same protection as
|
|
297
|
+
`ctx.fetch`, just in the browser" — that is the one thing this section
|
|
298
|
+
means to rule out.
|
|
299
|
+
|
|
300
|
+
In short: widgets get real network in Live API mode, gated by convenience in
|
|
301
|
+
the harness and by nothing in production; handlers get fixtures locally and
|
|
302
|
+
the real, enforced thing only after publish.
|
|
303
|
+
|
|
272
304
|
## Testing
|
|
273
305
|
|
|
274
306
|
`@ekanos/sdk/testing` builds the same context production uses, in memory —
|
|
@@ -71,8 +71,11 @@ hierarchy, and no amount of padding will save it.
|
|
|
71
71
|
|
|
72
72
|
Every widget: `'use client'`, `Widget.DataState` wrapping `Widget.Card` →
|
|
73
73
|
`Widget.Header` + `Widget.Loading` + `Widget.Error` + `Widget.Active`. Gate
|
|
74
|
-
fetching on `ctx?.state.state === 'active'` from `WidgetContext
|
|
75
|
-
|
|
74
|
+
fetching on `ctx?.state.state === 'active'` from `WidgetContext`, and fetch
|
|
75
|
+
with `useIntegrationFetch()` from `@ekanos/sdk/hooks` — never global
|
|
76
|
+
`fetch` — reaching for `useActivationData()` (same module) if the widget
|
|
77
|
+
needs a client-visible credential. Copy the canonical example from the SDK
|
|
78
|
+
README rather than improvising the tree.
|
|
76
79
|
|
|
77
80
|
`Widget.Active` itself renders flush (no padding) so full-bleed charts and
|
|
78
81
|
tables can run edge-to-edge. For ordinary content — text, rows, a KPI
|