@w6w/react 0.5.0 → 0.9.9
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/README.md +183 -44
- package/dist/mod.d.ts +3 -3
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +4 -3
- package/dist/mod.js.map +1 -1
- package/dist/src/W6WProvider.d.ts +89 -39
- package/dist/src/W6WProvider.d.ts.map +1 -1
- package/dist/src/W6WProvider.js +104 -57
- package/dist/src/W6WProvider.js.map +1 -1
- package/dist/src/adapter.d.ts +157 -2
- package/dist/src/adapter.d.ts.map +1 -1
- package/dist/src/adapter.js +116 -1
- package/dist/src/adapter.js.map +1 -1
- package/dist/src/hooks.d.ts +90 -11
- package/dist/src/hooks.d.ts.map +1 -1
- package/dist/src/hooks.js +181 -42
- package/dist/src/hooks.js.map +1 -1
- package/dist/src/single-flight.d.ts +33 -0
- package/dist/src/single-flight.d.ts.map +1 -0
- package/dist/src/single-flight.js +71 -0
- package/dist/src/single-flight.js.map +1 -0
- package/dist/src/version.js +1 -1
- package/package.json +13 -4
package/README.md
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
React bindings for [`@w6w/sdk`](../node) — a `<W6WProvider>` that holds one memoized
|
|
4
4
|
`W6WClient` with per-request token freshness, a small hook set over the SDK's public
|
|
5
|
-
surface (`me`, `documents`, `vars`, `connections`, `workflows`, `run`), and
|
|
5
|
+
surface (`me`, `documents`, `vars`, `connections`, `workflows`, `functions`, `run`), and
|
|
6
6
|
`createW6WUiAdapter`, a structural bridge from a `W6WClient` to
|
|
7
7
|
[`@w6w/ui`](https://github.com/w6w-io/w6w-ui)'s `W6WApi` contract.
|
|
8
8
|
|
|
9
|
-
License: MIT · Version: 0.
|
|
9
|
+
License: MIT · Version: 0.9.8 · Guides: [docs.w6w.io/clients/react](https://docs.w6w.io/clients/react/)
|
|
10
|
+
(with a [hooks reference](https://docs.w6w.io/clients/react/hooks/) and a
|
|
11
|
+
[Next.js walkthrough](https://docs.w6w.io/clients/react/nextjs/))
|
|
10
12
|
|
|
11
13
|
This lane implements no endpoint — it composes `@w6w/sdk`, which is already
|
|
12
14
|
conformant against [`endpoints.json`](../endpoints.json). There is nothing here to
|
|
@@ -18,6 +20,10 @@ re-verify against the wire contract; verify `@w6w/sdk` instead.
|
|
|
18
20
|
npm install @w6w/react react
|
|
19
21
|
```
|
|
20
22
|
|
|
23
|
+
`@w6w/sdk` comes in as a dependency. Add it to your own `package.json` too
|
|
24
|
+
(`npm install @w6w/sdk`) if you import from it directly — `ApiError` for an
|
|
25
|
+
`instanceof` check, or `exchangeToken` from `@w6w/sdk/server` on your backend.
|
|
26
|
+
|
|
21
27
|
`react-dom` is not a dependency of this package — `<W6WProvider>`'s only JSX is a
|
|
22
28
|
context wrapper (`<Ctx.Provider>`), never a DOM element of its own. Your app already
|
|
23
29
|
depends on `react-dom` to mount itself; nothing extra is needed here.
|
|
@@ -38,11 +44,16 @@ function App() {
|
|
|
38
44
|
}
|
|
39
45
|
```
|
|
40
46
|
|
|
41
|
-
`token` accepts a literal string, or a supplier
|
|
42
|
-
request
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
`token` accepts a literal string, or a supplier — sync or **async** — called per
|
|
48
|
+
request (requests in flight at the same time share ONE supplier call; nothing is cached once
|
|
49
|
+
it settles, so memoize an expensive supplier yourself): `() => getCurrentJwt()` or `async () => await getCurrentJwt()` both
|
|
50
|
+
work, and either is awaited before the bearer is attached. Pass a supplier when your
|
|
51
|
+
token rotates (e.g. a short-lived JWT read from an auth SDK, or minted on demand by
|
|
52
|
+
your own backend) and the client picks up the new value on the very next call, with no
|
|
53
|
+
teardown/rebuild of the underlying `W6WClient`. A nullish or blank result (from either
|
|
54
|
+
form) never reaches the wire: every read hook below reports `loading: true` instead of
|
|
55
|
+
sending a request with no credential. See `src/W6WProvider.tsx`'s module header for the
|
|
56
|
+
exact mechanism.
|
|
46
57
|
|
|
47
58
|
Then, anywhere under the provider:
|
|
48
59
|
|
|
@@ -61,6 +72,70 @@ function DocList() {
|
|
|
61
72
|
}
|
|
62
73
|
```
|
|
63
74
|
|
|
75
|
+
## Embedding for enterprise tenants
|
|
76
|
+
|
|
77
|
+
A host juggling more than one signed-in identity — or one that does not have a
|
|
78
|
+
token/identity yet at mount time — needs more than the Quick start's one-shot
|
|
79
|
+
`token` prop. `<W6WProvider>` takes five more props for exactly this:
|
|
80
|
+
|
|
81
|
+
- **`ready`** (default `true`) — set it `false` until you actually have a
|
|
82
|
+
token/identity to embed with. While `false`, every read hook reports
|
|
83
|
+
`loading: true` and none of them calls the SDK at all; flipping it back to
|
|
84
|
+
`true` fetches.
|
|
85
|
+
- **`identityKey`** — a string identifying WHICH signed-in identity this
|
|
86
|
+
client speaks for, e.g. `` `${subject}:${account}` ``. Changing it rebuilds
|
|
87
|
+
the underlying `W6WClient` and resets every read hook's state — the
|
|
88
|
+
supported way to switch accounts without a stale read from the previous
|
|
89
|
+
identity ever rendering under the new one.
|
|
90
|
+
- **`refreshOnUnauthorized`** + **`onUnauthorized`** — opt in to a single,
|
|
91
|
+
one-shot recovery when a request 401s with `{code: "unauthorized"}`: your
|
|
92
|
+
`token` supplier is called once more with `{forceRefresh: true}`, and a
|
|
93
|
+
usable result retries the same request once. `onUnauthorized` receives the
|
|
94
|
+
terminal error — after a failed retry, or immediately when recovery is off
|
|
95
|
+
or not possible — at most once per call.
|
|
96
|
+
- **`headers`** — default headers sent with every request. This is how a
|
|
97
|
+
tenant on the custom-authorizer integration path (no OIDC on your side)
|
|
98
|
+
attaches the tenant header your w6w account's authorizer webhook expects
|
|
99
|
+
(e.g. `headers={{ "X-W6W-Tenant": tenantId }}`) alongside the bearer token.
|
|
100
|
+
Compared by content, not identity — a new-but-equal object on every render
|
|
101
|
+
never rebuilds the client.
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
"use client";
|
|
105
|
+
|
|
106
|
+
import { W6WProvider } from "@w6w/react";
|
|
107
|
+
|
|
108
|
+
export default function W6WLayout({ children }: { children: React.ReactNode }) {
|
|
109
|
+
return (
|
|
110
|
+
<W6WProvider
|
|
111
|
+
baseUrl="https://api.example.com"
|
|
112
|
+
ready={true}
|
|
113
|
+
identityKey={`${session.subject}:${session.account}`}
|
|
114
|
+
headers={{ "X-W6W-Tenant": session.tenantId }}
|
|
115
|
+
refreshOnUnauthorized
|
|
116
|
+
onUnauthorized={() => redirectToLogin()}
|
|
117
|
+
token={async () => {
|
|
118
|
+
// Your own backend route, not w6w's — it holds whatever credential
|
|
119
|
+
// mints a w6w token for this signed-in user (a tenant exchange, a
|
|
120
|
+
// cached short-lived token, …). This is a Next.js App Router layout,
|
|
121
|
+
// so it is a Client Component ("use client" above) even though the
|
|
122
|
+
// token-minting route itself runs on your server.
|
|
123
|
+
const res = await fetch("/api/w6w-token");
|
|
124
|
+
if (!res.ok) return null;
|
|
125
|
+
const { token } = await res.json();
|
|
126
|
+
return token;
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
{children}
|
|
130
|
+
</W6WProvider>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The [Next.js walkthrough](https://docs.w6w.io/clients/react/nextjs/) builds the
|
|
136
|
+
`/api/w6w-token` route this example fetches from, with `exchangeToken` and a
|
|
137
|
+
cached, refreshable token supplier.
|
|
138
|
+
|
|
64
139
|
## Using this package with `@w6w/ui`
|
|
65
140
|
|
|
66
141
|
`@w6w/ui`'s components (e.g. `AppPicker`, `ActionTestForm`, the flow editor) take a
|
|
@@ -68,6 +143,7 @@ function DocList() {
|
|
|
68
143
|
`@w6w/react` client with `createW6WUiAdapter`:
|
|
69
144
|
|
|
70
145
|
```tsx
|
|
146
|
+
import { useMemo } from "react";
|
|
71
147
|
import { createW6WUiAdapter, useW6WClient, W6WProvider } from "@w6w/react";
|
|
72
148
|
import { W6WUIProvider, AppPicker } from "@w6w/ui";
|
|
73
149
|
|
|
@@ -88,23 +164,55 @@ function App() {
|
|
|
88
164
|
}
|
|
89
165
|
```
|
|
90
166
|
|
|
91
|
-
**`@w6w/ui` is not on npm today
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
`
|
|
99
|
-
|
|
100
|
-
`
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
**`client.console.*` is documented
|
|
104
|
-
excluded from `endpoints.json`'s
|
|
105
|
-
That means a `console.*`
|
|
106
|
-
|
|
107
|
-
`@w6w/
|
|
167
|
+
**`@w6w/ui` is not on npm today** (`npm view @w6w/ui` → 404, checked 2026-10-06);
|
|
168
|
+
the source is a public GitHub repository (`w6w-io/w6w-ui`). `createW6WUiAdapter`'s
|
|
169
|
+
`W6WApi` return type targets that contract *structurally* — this package needs no
|
|
170
|
+
change whenever `@w6w/ui` becomes reachable another way (a `git+https://`
|
|
171
|
+
dependency on the public repo, or a private registry). `npm i @w6w/ui` does not
|
|
172
|
+
resolve yet.
|
|
173
|
+
|
|
174
|
+
`createW6WUiAdapter` is built on `@w6w/sdk/console` for most members — the SAME
|
|
175
|
+
namespace `packages/studio`'s own facade uses for these routes
|
|
176
|
+
(`packages/ui/src/createW6WApi.ts` is the *other* hand-rolled client for them; this
|
|
177
|
+
package is not a third one) — and on the BASE `client.functions.*`/
|
|
178
|
+
`client.workflows.*` surface for `listFunctions`/`getFunction`/`invokeFunction`/
|
|
179
|
+
`listWorkflows`/`getWorkflow`/`runWorkflow`. **`client.console.*` is documented
|
|
180
|
+
"Studio-internal… unstable" and is deliberately excluded from `endpoints.json`'s
|
|
181
|
+
conformance runner** (`node/src/client.ts:114-116`). That means a `console.*`
|
|
182
|
+
signature change ships with no lockstep protection for this bridge beyond
|
|
183
|
+
`@w6w/sdk`'s own version — pin your `@w6w/sdk` version alongside `@w6w/react`'s, and
|
|
184
|
+
re-test the bridge on an upgrade rather than assuming it.
|
|
185
|
+
|
|
186
|
+
### Keeping `createW6WUiAdapter` in sync with the real `@w6w/ui`
|
|
187
|
+
|
|
188
|
+
`package.json`'s `devDependencies` carries a **dev-only, type-only** edge onto
|
|
189
|
+
`@w6w/ui` — `"@w6w/ui": "github:w6w-io/w6w-ui#<sha>"` — that this package never
|
|
190
|
+
ships: `files: ["dist"]` means `dist/` is the only thing npm packs and publishes, so
|
|
191
|
+
no installer of `@w6w/react` ever resolves or needs `@w6w/ui` at all. Its one job is
|
|
192
|
+
`src/__tests__/ui-conformance.test.ts`, which runs at **dev/CI time only** (`npm
|
|
193
|
+
test`, never part of `dist/`): it compiles `src/__tests__/ui-conformance.check.ts`
|
|
194
|
+
against `@w6w/ui`'s real `provider.tsx` and fails, naming the member, the moment
|
|
195
|
+
`createW6WUiAdapter`'s return type stops being assignable to the real `W6WApi` —
|
|
196
|
+
closing the gap a hand-duplicated interface alone cannot (nothing previously caught
|
|
197
|
+
this package's `W6WApi` drifting from `@w6w/ui`'s own).
|
|
198
|
+
|
|
199
|
+
**Why a `github:<owner>/<repo>#<sha>` pin, and not a `link:`/workspace reference to
|
|
200
|
+
a sibling checkout:** `release.yml`'s `react` step checks out **this one repo**
|
|
201
|
+
(`w6w-wrappers`) with no sibling checkout and no submodules — a relative `link:` to `../../ui` resolves only in the
|
|
202
|
+
local devcontainer's incidental directory layout and fails `ENOENT` on every CI run
|
|
203
|
+
and on a fresh clone of `w6w-wrappers` alone. A `github:` spec needs nothing but a
|
|
204
|
+
network fetch of the one pinned commit, which is why it is the only install story
|
|
205
|
+
that survives both environments unchanged. The pin targets `provider.tsx` by
|
|
206
|
+
RELATIVE PATH, not the `@w6w/ui` package barrel — the barrel's own import chain
|
|
207
|
+
reaches `@w6w/expr` (`packages/core`) via a `github:…#path:` subpath npm does not
|
|
208
|
+
honor on a `github:` dependency, which `TS2307`s the moment anything resolves it;
|
|
209
|
+
`provider.tsx`'s own closure (`theme.ts` → `types.ts` → `react`) has no such edge.
|
|
210
|
+
|
|
211
|
+
**Moving the pin:** update the `#<sha>` in `package.json`'s `@w6w/ui` entry to a
|
|
212
|
+
commit on `w6w-io/w6w-ui`'s `main` (`git ls-remote https://github.com/w6w-io/w6w-ui
|
|
213
|
+
main`) and run `npm install` again to refresh `package-lock.json`'s resolved
|
|
214
|
+
entry — no code change is required unless `@w6w/ui`'s `W6WApi` itself changed
|
|
215
|
+
shape, in which case `ui-conformance.test.ts` will say so.
|
|
108
216
|
|
|
109
217
|
## Hooks catalog
|
|
110
218
|
|
|
@@ -112,6 +220,11 @@ Every read hook returns `{data, error, loading, refetch}`; every mutation hook
|
|
|
112
220
|
returns `{call, data, error, loading}`. None depends on react-query or any other
|
|
113
221
|
data-fetching library.
|
|
114
222
|
|
|
223
|
+
Read hooks asking for the same thing (same hook, same arguments, same provider) while a
|
|
224
|
+
request is in flight share ONE request — two consumers, or React StrictMode's
|
|
225
|
+
mount/unmount/mount, send a single fetch. Nothing is kept once it settles: a hook mounting
|
|
226
|
+
later sends a new request, and `refetch()` starts a fresh one.
|
|
227
|
+
|
|
115
228
|
| Hook | Wraps |
|
|
116
229
|
|---|---|
|
|
117
230
|
| `useMe()` | `client.me()` |
|
|
@@ -128,15 +241,52 @@ data-fetching library.
|
|
|
128
241
|
| `useDeleteVar()` | `client.vars.delete()` |
|
|
129
242
|
| `useConnections()` | `client.connections.list()` |
|
|
130
243
|
| `useWorkflows(options?)` | `client.workflows.list()` |
|
|
244
|
+
| `useWorkflow(id)` | `client.workflows.get()` |
|
|
245
|
+
| `useCreateWorkflow()` | `client.workflows.create()` |
|
|
246
|
+
| `useUpdateWorkflow()` | `client.workflows.update()` |
|
|
247
|
+
| `useArchiveWorkflow()` | `client.workflows.archive()` |
|
|
248
|
+
| `useDeleteWorkflow()` | `client.workflows.delete()` |
|
|
131
249
|
| `useRunWorkflow()` | `client.workflows.run()`, defaults `wait: true` |
|
|
250
|
+
| `useFunctions()` | `client.functions.list()` |
|
|
251
|
+
| `useFunction(id)` | `client.functions.get()` |
|
|
252
|
+
| `useCreateFunction()` | `client.functions.create()` |
|
|
253
|
+
| `useUpdateFunction()` | `client.functions.update()` |
|
|
254
|
+
| `useDeleteFunction()` | `client.functions.delete()` |
|
|
132
255
|
| `useRun()` | `client.run()` (the generic URN dispatch) |
|
|
133
256
|
|
|
257
|
+
Three things the definition hooks inherit from the SDK rather than invent:
|
|
258
|
+
|
|
259
|
+
- **`create` mints the id.** The server requires one in the body and never
|
|
260
|
+
generates it, so `useCreateWorkflow().call({name, steps})` works and the
|
|
261
|
+
`wf_…` / `fn_…` id comes back in the result.
|
|
262
|
+
- **`update` is a full replacement, not a patch.** This is the one place they
|
|
263
|
+
differ from `useUpdateDocument`/`useUpdateVar`, whose second argument is a
|
|
264
|
+
patch of just the fields to change. Read with `useWorkflow`/`useFunction`,
|
|
265
|
+
spread, change, send the whole thing back — passing only the changed fields
|
|
266
|
+
deletes the rest. `useUpdateWorkflow()`'s third argument carries
|
|
267
|
+
`ifUnmodifiedSince`: hand it the `updatedAt` from `useWorkflow` and a save
|
|
268
|
+
that would clobber someone else's edit is refused with `409 workflow_stale`
|
|
269
|
+
rather than winning silently.
|
|
270
|
+
- **Deleting a workflow is two calls**, `useArchiveWorkflow` then
|
|
271
|
+
`useDeleteWorkflow`. Nothing chains them for you: the archive step is the one
|
|
272
|
+
a user can still change their mind after.
|
|
273
|
+
|
|
274
|
+
No mutation hook refetches a list on success — this package carries no cache to
|
|
275
|
+
invalidate, so pair one with the matching read hook's own `refetch`.
|
|
276
|
+
|
|
277
|
+
`client.functions.run()` has **no** hook, and neither does `endpoints.run()` —
|
|
278
|
+
that predates the definition hooks and is unchanged by them. `useRun()` reaches
|
|
279
|
+
a Function by its `fn_…` id today (the server dispatches it through the same
|
|
280
|
+
service the dedicated invoke route uses); calling one by the `key` a user gave
|
|
281
|
+
it still means `useW6WClient().functions.run("send-email", …)`.
|
|
282
|
+
|
|
134
283
|
`useRunWorkflow()`'s `call` defaults `wait: true` when the caller's options omit
|
|
135
284
|
`wait`: `workflows.run` without `wait` (`node/src/workflows.ts`) leaves the caller
|
|
136
285
|
with only a `runId` and no public polling operation to follow it with —
|
|
137
286
|
`console.workflows.getRun` exists, but it is the same studio-internal, unstable
|
|
138
287
|
surface described above, so this hook does not reach for it. Pass `wait: false`
|
|
139
|
-
explicitly if you
|
|
288
|
+
explicitly if you want the queued-and-walk-away behaviour, and follow the run
|
|
289
|
+
with `` useW6WClient().request({ method: "GET", path: path`/runs/${runId}` }) ``.
|
|
140
290
|
|
|
141
291
|
`useW6WClient()` returns the underlying `W6WClient` for anything not covered by a
|
|
142
292
|
hook (e.g. `client.console.*` directly, at your own risk per the caveat above).
|
|
@@ -151,22 +301,11 @@ hook (e.g. `client.console.*` directly, at your own risk per the caveat above).
|
|
|
151
301
|
fine — every extra field is optional — and there is no runtime data loss (the JSON
|
|
152
302
|
payload is unfiltered); a caller typing a variable through this adapter's declared
|
|
153
303
|
return type just gets no autocomplete for those extra fields.
|
|
154
|
-
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
showing the outbound calls the action made — even though this adapter's thrown
|
|
163
|
-
error genuinely carries that data on `.body`/`.raw`. This adapter still aliases
|
|
164
|
-
`@w6w/sdk`'s `ApiError.raw` onto `.body` (`err.body === err.raw`) and sets
|
|
165
|
-
`err.name = "ApiError"`, so it is already correct for any DUCK-TYPING consumer, and
|
|
166
|
-
needs no further change the moment `@w6w/ui` switches its own check to one. The fix
|
|
167
|
-
belongs to `@w6w/ui`, not this package, and is filed there:
|
|
168
|
-
`.ai/projects/backlog/26-08-13-01-ui-error-nominal-check.md`.
|
|
169
|
-
- **No `AbortSignal`/cancellation support in the hook set.** `@w6w/sdk`'s transport
|
|
170
|
-
(`node/src/http.ts`) has nothing to hook an abort into. A read hook only IGNORES a
|
|
171
|
-
result that resolves after its component unmounts (a mounted-ref guard); it cannot
|
|
172
|
-
cancel the in-flight request itself.
|
|
304
|
+
- **Cancellation is per-hook, not exposed to the caller.** Every read hook aborts its
|
|
305
|
+
own superseded or unmounted calls internally (a superseded call, an `identityKey`
|
|
306
|
+
switch, or an unmount all abort the in-flight `AbortSignal` — but a shared request
|
|
307
|
+
aborts only when its LAST subscriber detaches, so StrictMode's remount or a second
|
|
308
|
+
consumer re-attaches instead of aborting it — see `src/hooks.ts`'s
|
|
309
|
+
module header) — but there is no option to pass your OWN `AbortSignal` into a hook
|
|
310
|
+
from outside it. `useW6WClient()` plus the underlying SDK method (which does take a
|
|
311
|
+
`signal`) is the escape hatch if you need that.
|
package/dist/mod.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@w6w/react` — the package barrel.
|
|
3
3
|
*
|
|
4
|
-
* A thin React binding over `@w6w/sdk`: `<W6WProvider>` (
|
|
5
|
-
*
|
|
4
|
+
* A thin React binding over `@w6w/sdk`: `<W6WProvider>` (with its native token
|
|
5
|
+
* supplier), a small hook set, and `createW6WUiAdapter` (the
|
|
6
6
|
* `@w6w/ui` `W6WApi` structural bridge, C-1/C-2). See `README.md` for the
|
|
7
7
|
* install + wrap-your-root example, the hooks catalog, and this lane's
|
|
8
8
|
* documented limitations.
|
|
@@ -14,6 +14,6 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export { VERSION } from "./src/version.ts";
|
|
16
16
|
export { type TokenSource, useW6WClient, W6WProvider, type W6WProviderProps, } from "./src/W6WProvider.tsx";
|
|
17
|
-
export { type MutationResult, type ReadResult, useConnections, useCreateDocument, useCreateVar, useDeleteDocument, useDeleteVar, useDocument, useDocumentByKey, useDocuments, useMe, useRun, useRunWorkflow, useUpdateDocument, useUpdateVar, useVar, useVars, useWorkflows, } from "./src/hooks.ts";
|
|
17
|
+
export { type MutationResult, type ReadResult, useArchiveWorkflow, useConnections, useCreateDocument, useCreateFunction, useCreateVar, useCreateWorkflow, useDeleteDocument, useDeleteFunction, useDeleteVar, useDeleteWorkflow, useDocument, useDocumentByKey, useDocuments, useFunction, useFunctions, useMe, useRun, useRunWorkflow, useUpdateDocument, useUpdateFunction, useUpdateVar, useUpdateWorkflow, useVar, useVars, useWorkflow, useWorkflows, } from "./src/hooks.ts";
|
|
18
18
|
export { createW6WUiAdapter, type W6WApi } from "./src/adapter.ts";
|
|
19
19
|
//# sourceMappingURL=mod.d.ts.map
|
package/dist/mod.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../mod.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../mod.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,OAAO,EACL,KAAK,WAAW,EAChB,YAAY,EACZ,WAAW,EACX,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,KAAK,EACL,MAAM,EACN,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,MAAM,EACN,OAAO,EACP,WAAW,EACX,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAE,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/mod.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
/**
|
|
2
3
|
* `@w6w/react` — the package barrel.
|
|
3
4
|
*
|
|
4
|
-
* A thin React binding over `@w6w/sdk`: `<W6WProvider>` (
|
|
5
|
-
*
|
|
5
|
+
* A thin React binding over `@w6w/sdk`: `<W6WProvider>` (with its native token
|
|
6
|
+
* supplier), a small hook set, and `createW6WUiAdapter` (the
|
|
6
7
|
* `@w6w/ui` `W6WApi` structural bridge, C-1/C-2). See `README.md` for the
|
|
7
8
|
* install + wrap-your-root example, the hooks catalog, and this lane's
|
|
8
9
|
* documented limitations.
|
|
@@ -14,6 +15,6 @@
|
|
|
14
15
|
*/
|
|
15
16
|
export { VERSION } from "./src/version.js";
|
|
16
17
|
export { useW6WClient, W6WProvider, } from "./src/W6WProvider.js";
|
|
17
|
-
export { useConnections, useCreateDocument, useCreateVar, useDeleteDocument, useDeleteVar, useDocument, useDocumentByKey, useDocuments, useMe, useRun, useRunWorkflow, useUpdateDocument, useUpdateVar, useVar, useVars, useWorkflows, } from "./src/hooks.js";
|
|
18
|
+
export { useArchiveWorkflow, useConnections, useCreateDocument, useCreateFunction, useCreateVar, useCreateWorkflow, useDeleteDocument, useDeleteFunction, useDeleteVar, useDeleteWorkflow, useDocument, useDocumentByKey, useDocuments, useFunction, useFunctions, useMe, useRun, useRunWorkflow, useUpdateDocument, useUpdateFunction, useUpdateVar, useUpdateWorkflow, useVar, useVars, useWorkflow, useWorkflows, } from "./src/hooks.js";
|
|
18
19
|
export { createW6WUiAdapter } from "./src/adapter.js";
|
|
19
20
|
//# sourceMappingURL=mod.js.map
|
package/dist/mod.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,OAAO,EAEL,YAAY,EACZ,WAAW,GAEZ,MAAM,sBAAuB,CAAC;AAE/B,OAAO,EAGL,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,KAAK,EACL,MAAM,EACN,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,MAAM,EACN,OAAO,EACP,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAe,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../mod.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,OAAO,EAEL,YAAY,EACZ,WAAW,GAEZ,MAAM,sBAAuB,CAAC;AAE/B,OAAO,EAGL,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,KAAK,EACL,MAAM,EACN,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,MAAM,EACN,OAAO,EACP,WAAW,EACX,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAe,MAAM,kBAAkB,CAAC"}
|
|
@@ -1,62 +1,104 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `<W6WProvider>` — one `W6WClient` per `baseUrl
|
|
3
|
-
*
|
|
2
|
+
* `<W6WProvider>` — one `W6WClient` per `{baseUrl, project, identityKey,
|
|
3
|
+
* refreshOnUnauthorized, headers}` combination, with the token resolved per
|
|
4
|
+
* request (concurrent requests share one supplier call).
|
|
4
5
|
*
|
|
5
|
-
* `@w6w/sdk`'s `W6WClientOptions.token` (`node/src/config.ts:41-63`)
|
|
6
|
-
*
|
|
7
|
-
* (
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* `@w6w/sdk`'s `W6WClientOptions.token` (`node/src/config.ts:41-63`) accepts
|
|
7
|
+
* either a plain string or a {@linkcode TokenProvider} function — the
|
|
8
|
+
* function form is called (and its result awaited) per request — requests in
|
|
9
|
+
* flight at the same time share ONE call, nothing is cached once it settles,
|
|
10
|
+
* and it is never resolved once at construction. This provider hands the
|
|
11
|
+
* SDK a single STABLE function that reads the CURRENT `token` prop through a
|
|
12
|
+
* ref: a string prop is returned as-is, a function prop is called with
|
|
13
|
+
* whatever `ctx` the SDK forwards (including `{forceRefresh: true}` on its
|
|
14
|
+
* own one-shot 401 recovery retry, `node/src/http.ts`). `fetch` and
|
|
15
|
+
* `onUnauthorized` are the same shape — stable wrappers over "latest" refs —
|
|
16
|
+
* so neither a token rotation, a new `fetch` identity, nor a new
|
|
17
|
+
* `onUnauthorized` closure identity ever rebuilds the client. A nullish or
|
|
18
|
+
* blank token (sync or async) never reaches the wire: the SDK's own
|
|
19
|
+
* `requireToken` raises a local {@linkcode ConfigError} before any `fetch`
|
|
20
|
+
* call, which is the floor `hooks.ts`'s `useAsync` reports as `loading`, not
|
|
21
|
+
* `error`.
|
|
10
22
|
*
|
|
11
|
-
*
|
|
12
|
-
* `
|
|
13
|
-
*
|
|
14
|
-
* the
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* always overwrites it first) and an injected `fetch` that resolves the
|
|
22
|
-
* current `token` prop (calling it, if it is a supplier) on every call.
|
|
23
|
+
* **What DOES rebuild the client** (the `useMemo` below): `baseUrl`,
|
|
24
|
+
* `project`, `identityKey`, `refreshOnUnauthorized`, and a canonical STRING of
|
|
25
|
+
* `headers`' sorted entries — never the `headers` object's own identity (an
|
|
26
|
+
* inline literal would rebuild the client on every render) and never
|
|
27
|
+
* `token`. `identityKey` (e.g. `${subject}:${account}`) is the one supported
|
|
28
|
+
* way to force a rebuild on purpose, for a host juggling more than one
|
|
29
|
+
* signed-in identity: every hook built on `useAsync` (`hooks.ts`) resets its
|
|
30
|
+
* state to `{data: undefined, error: undefined, loading: true}` when the
|
|
31
|
+
* client it reads through changes, aborting whatever it had in flight first —
|
|
32
|
+
* a stale account's data is never shown under a new one.
|
|
23
33
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* function has a stable identity across renders, so keying on the supplier
|
|
28
|
-
* would never rebuild AND never read a fresh value, while keying on the
|
|
29
|
-
* token's resolved value would tear the client down and rebuild it on every
|
|
30
|
-
* rotation — exactly what C-4 says not to do ("without tearing down"). The
|
|
31
|
-
* memo below depends on `[baseUrl, project]` only; `token` and `fetch` are
|
|
32
|
-
* read through "latest" refs, updated every render but never a dependency, so
|
|
33
|
-
* a rotating token is read fresh per request without ever rebuilding the
|
|
34
|
-
* client.
|
|
34
|
+
* `ready` (default `true`) gates every READ hook, never a mutation: while
|
|
35
|
+
* `false`, a read hook reports `loading: true` and never calls the SDK at
|
|
36
|
+
* all. Flipping it to `true` (or changing `identityKey`) fetches.
|
|
35
37
|
*
|
|
36
38
|
* @module
|
|
37
39
|
*/
|
|
38
|
-
import { type FetchLike, W6WClient } from "@w6w/sdk";
|
|
40
|
+
import { type ApiError, type FetchLike, type TokenProvider, W6WClient } from "@w6w/sdk";
|
|
39
41
|
import { type ReactNode } from "react";
|
|
40
|
-
/** A static bearer token, or a supplier
|
|
41
|
-
export type TokenSource = string |
|
|
42
|
+
/** A static bearer token, or a supplier called per request (concurrent requests share one call). */
|
|
43
|
+
export type TokenSource = string | TokenProvider;
|
|
42
44
|
export interface W6WProviderProps {
|
|
43
45
|
/** The w6w server's origin, e.g. `"https://api.example.com"`. */
|
|
44
46
|
baseUrl: string;
|
|
45
|
-
/** A literal bearer token, or a supplier called
|
|
47
|
+
/** A literal bearer token, or a supplier called per request (concurrent requests share one call). */
|
|
46
48
|
token: TokenSource;
|
|
47
49
|
/**
|
|
48
|
-
* The real transport this provider's
|
|
49
|
-
*
|
|
50
|
-
*
|
|
50
|
+
* The real transport this provider's stable `fetch` wrapper delegates to.
|
|
51
|
+
* Defaults to `globalThis.fetch`. Mainly for tests — a caller wanting to
|
|
52
|
+
* record or stub outbound requests.
|
|
51
53
|
*/
|
|
52
54
|
fetch?: FetchLike;
|
|
53
55
|
/** Default project id for the project-scoped operations (`documents.*`, `workflows.list`). */
|
|
54
56
|
project?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Default headers sent with every request — e.g. `{"X-W6W-Tenant": "t1"}`
|
|
59
|
+
* for a Path 3 tenant binding. Compared by CONTENT (sorted entries), not by
|
|
60
|
+
* object identity: a new-but-equal `headers` object on every render never
|
|
61
|
+
* rebuilds the client.
|
|
62
|
+
*/
|
|
63
|
+
headers?: Record<string, string>;
|
|
64
|
+
/**
|
|
65
|
+
* Gates every read hook. `false` (default `true`) means "I don't have a
|
|
66
|
+
* token/identity yet": no read hook calls the SDK, and every one reports
|
|
67
|
+
* `loading: true` until this flips — or forever, if it never does.
|
|
68
|
+
*/
|
|
69
|
+
ready?: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Identifies WHICH signed-in identity this client speaks for. Changing it
|
|
72
|
+
* (e.g. `${subject}:${account}`) rebuilds the `W6WClient` and resets every
|
|
73
|
+
* read hook's state — the one supported way to switch accounts without a
|
|
74
|
+
* stale read from the previous identity ever rendering under the new one.
|
|
75
|
+
*/
|
|
76
|
+
identityKey?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Opt in to a single, one-shot recovery when a request 401s with
|
|
79
|
+
* `{code: "unauthorized"}`: the `token` supplier is called once more with
|
|
80
|
+
* `{forceRefresh: true}`, and a usable result retries the same request
|
|
81
|
+
* once. See `@w6w/sdk`'s `W6WClientOptions.refreshOnUnauthorized`.
|
|
82
|
+
*/
|
|
83
|
+
refreshOnUnauthorized?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Called with the terminal `401`/`unauthorized` error — after a failed
|
|
86
|
+
* recovery retry, or immediately when recovery is off or not possible — at
|
|
87
|
+
* most once per call. Always the LATEST `onUnauthorized` prop, read through
|
|
88
|
+
* a ref like `token`/`fetch`.
|
|
89
|
+
*/
|
|
90
|
+
onUnauthorized?: (error: ApiError) => void;
|
|
55
91
|
children: ReactNode;
|
|
56
92
|
}
|
|
93
|
+
interface W6WContextValue {
|
|
94
|
+
client: W6WClient;
|
|
95
|
+
/** Mirrors the `ready` prop. Read by `hooks.ts`'s `useAsync`, never by `useW6WClient`. */
|
|
96
|
+
ready: boolean;
|
|
97
|
+
}
|
|
57
98
|
/**
|
|
58
|
-
* Provides one memoized `W6WClient` to every component under
|
|
59
|
-
* module's header for the
|
|
99
|
+
* Provides one memoized `W6WClient` (plus `ready`) to every component under
|
|
100
|
+
* it. See this module's header for the token-freshness mechanism and the
|
|
101
|
+
* memoization policy.
|
|
60
102
|
*/
|
|
61
103
|
export declare function W6WProvider(props: W6WProviderProps): ReactNode;
|
|
62
104
|
/**
|
|
@@ -65,4 +107,12 @@ export declare function W6WProvider(props: W6WProviderProps): ReactNode;
|
|
|
65
107
|
* `useW6WApi` shape — read-only reference, transcribed here, never imported).
|
|
66
108
|
*/
|
|
67
109
|
export declare function useW6WClient(): W6WClient;
|
|
110
|
+
/**
|
|
111
|
+
* Internal: the context value including `ready`, consumed only by the read
|
|
112
|
+
* hooks in `hooks.ts` (via a relative import — never re-exported from
|
|
113
|
+
* `mod.ts`). `useW6WClient`'s `W6WClient` return type is the public surface;
|
|
114
|
+
* this is the one extra bit every read hook needs to gate on.
|
|
115
|
+
*/
|
|
116
|
+
export declare function useW6WProviderContext(): W6WContextValue;
|
|
117
|
+
export {};
|
|
68
118
|
//# sourceMappingURL=W6WProvider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"W6WProvider.d.ts","sourceRoot":"","sources":["../../src/W6WProvider.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"W6WProvider.d.ts","sourceRoot":"","sources":["../../src/W6WProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACxF,OAAO,EAAE,KAAK,SAAS,EAA8C,MAAM,OAAO,CAAC;AAEnF,oGAAoG;AACpG,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,aAAa,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,qGAAqG;IACrG,KAAK,EAAE,WAAW,CAAC;IACnB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,8FAA8F;IAC9F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;IAC3C,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,UAAU,eAAe;IACvB,MAAM,EAAE,SAAS,CAAC;IAClB,0FAA0F;IAC1F,KAAK,EAAE,OAAO,CAAC;CAChB;AAeD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,SAAS,CAqE9D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,SAAS,CASxC;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CASvD"}
|