@client-compose/client 0.6.0 → 0.8.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.
@@ -1 +1 @@
1
- {"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@client-compose/client",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Framework-agnostic Client Compose client: island registry, screen requests and render planning.",
5
5
  "keywords": [
6
6
  "client-compose",
@@ -44,10 +44,10 @@
44
44
  "LICENSE"
45
45
  ],
46
46
  "dependencies": {
47
- "@client-compose/protocol": "0.3.0"
47
+ "@client-compose/protocol": "0.5.0"
48
48
  },
49
49
  "devDependencies": {
50
- "@client-compose/conformance": "0.6.0"
50
+ "@client-compose/conformance": "0.8.0"
51
51
  },
52
52
  "publishConfig": {
53
53
  "access": "public"
package/src/index.ts CHANGED
@@ -10,7 +10,10 @@ import {
10
10
  type DeclaredError,
11
11
  type IslandDescriptor,
12
12
  type IslandEntry,
13
+ type IslandRequest,
14
+ type IslandResponse,
13
15
  PROTOCOL_VERSION,
16
+ type ScreenHead,
14
17
  type ScreenRequest,
15
18
  type ScreenResponse,
16
19
  } from "@client-compose/protocol";
@@ -20,8 +23,26 @@ type ErrorEntry = IslandEntry & { status: "error" };
20
23
 
21
24
  export type IslandRenderer<R, P = unknown> = (props: P, entry: OkEntry<P>) => R;
22
25
 
26
+ /** What a client shows for an island still pending in a stream's head (spec §4.6). */
27
+ export type IslandPlaceholder<R> = () => R;
28
+
23
29
  export class IslandRegistry<R> {
24
30
  private renderers = new Map<string, Map<number, IslandRenderer<R>>>();
31
+ private placeholders = new Map<string, IslandPlaceholder<R>>();
32
+
33
+ /**
34
+ * Register a placeholder for an island version, shown while it's pending in a stream's head
35
+ * (spec §4.6). Each app draws its own: the protocol says nothing about how one looks.
36
+ */
37
+ registerPlaceholder(island: IslandDescriptor<unknown>, placeholder: IslandPlaceholder<R>): this {
38
+ this.placeholders.set(`${island.type}@${island.version}`, placeholder);
39
+ return this;
40
+ }
41
+
42
+ /** The placeholder for an island version, if one was registered. */
43
+ placeholder(type: string, version: number): IslandPlaceholder<R> | undefined {
44
+ return this.placeholders.get(`${type}@${version}`);
45
+ }
25
46
 
26
47
  /** Register a renderer for a generated island descriptor: `register(ProfileHeaderV2, (props) => …)`. */
27
48
  register<P>(island: IslandDescriptor<P>, render: IslandRenderer<R, P>): this;
@@ -31,13 +52,25 @@ export class IslandRegistry<R> {
31
52
  versionOrRender: number | IslandRenderer<R, P>,
32
53
  maybeRender?: IslandRenderer<R, P>,
33
54
  ): this {
34
- const [type, version, render] =
35
- typeof islandOrType === "string"
36
- ? [islandOrType, versionOrRender as number, maybeRender!]
37
- : [islandOrType.type, islandOrType.version, versionOrRender as IslandRenderer<R, P>];
38
- if (!this.renderers.has(type)) this.renderers.set(type, new Map());
39
- // The registry hands each renderer the props of its own island type and version.
40
- this.renderers.get(type)!.set(version, render as IslandRenderer<R>);
55
+ if (typeof islandOrType !== "string") {
56
+ if (typeof versionOrRender === "number") {
57
+ throw new Error("register(descriptor, render): pass the renderer, not a version");
58
+ }
59
+ return this.add(islandOrType.type, islandOrType.version, versionOrRender);
60
+ }
61
+ if (typeof versionOrRender !== "number" || !maybeRender) {
62
+ throw new Error("register(type, version, render): pass a version and a renderer");
63
+ }
64
+ return this.add(islandOrType, versionOrRender, maybeRender);
65
+ }
66
+
67
+ private add<P>(type: string, version: number, render: IslandRenderer<R, P>): this {
68
+ const versions = this.renderers.get(type) ?? new Map<number, IslandRenderer<R>>();
69
+ // The registry hands each renderer the props of its own island type and version, so the
70
+ // renderer's props type holds. TypeScript can't see that through one map of every island.
71
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
72
+ versions.set(version, render as IslandRenderer<R>);
73
+ this.renderers.set(type, versions);
41
74
  return this;
42
75
  }
43
76
 
@@ -61,12 +94,20 @@ export function buildRequest(
61
94
  client: ClientContext,
62
95
  params?: Record<string, string>,
63
96
  ): ScreenRequest {
64
- return { protocol: PROTOCOL_VERSION, screen, params, client, islands: registry.capabilities() };
97
+ return {
98
+ protocol: PROTOCOL_VERSION,
99
+ screen,
100
+ params,
101
+ client,
102
+ islands: registry.capabilities(),
103
+ };
65
104
  }
66
105
 
67
106
  export interface PlannedIsland<R> {
68
107
  key: string;
69
108
  render: () => R;
109
+ /** It's a placeholder, for an island still pending in a stream's head (spec §4.6). */
110
+ pending?: boolean;
70
111
  }
71
112
 
72
113
  export type SkipReason = "unknown_island" | "unknown_status";
@@ -78,17 +119,35 @@ export interface PlanOptions<R> {
78
119
  onSkipped?: (entry: IslandEntry, reason: SkipReason) => void;
79
120
  }
80
121
 
81
- /** Turn a response into an ordered list of renderable islands. */
122
+ /**
123
+ * Turn a screen, or a stream's head (spec §4.6), into an ordered list of renderable islands. An
124
+ * island still pending is its registered placeholder, or left out until it arrives.
125
+ */
82
126
  export function plan<R>(
83
127
  registry: IslandRegistry<R>,
84
- response: ScreenResponse,
128
+ response: ScreenResponse | ScreenHead,
85
129
  options: PlanOptions<R> = {},
86
130
  ): PlannedIsland<R>[] {
87
131
  const out: PlannedIsland<R>[] = [];
88
132
  for (const entry of response.islands) {
133
+ if (entry.status === "pending") {
134
+ const placeholder = registry.get(entry.type, entry.version)
135
+ ? registry.placeholder(entry.type, entry.version)
136
+ : undefined;
137
+ if (placeholder) {
138
+ out.push({
139
+ key: entry.key,
140
+ render: placeholder,
141
+ pending: true,
142
+ });
143
+ }
144
+ continue;
145
+ }
89
146
  if (entry.status === "error") {
90
147
  const fallback = options.onError?.(entry);
91
- if (fallback !== undefined) out.push({ key: entry.key, render: () => fallback });
148
+ if (fallback !== undefined) {
149
+ out.push({ key: entry.key, render: () => fallback });
150
+ }
92
151
  continue;
93
152
  }
94
153
  if (entry.status !== "ok") {
@@ -105,6 +164,34 @@ export function plan<R>(
105
164
  return out;
106
165
  }
107
166
 
167
+ // ---- Reading what the composer answered ----
168
+
169
+ function isRecord(value: unknown): value is Record<string, unknown> {
170
+ return typeof value === "object" && value !== null && !Array.isArray(value);
171
+ }
172
+
173
+ /** The body as JSON, or undefined if it isn't JSON. */
174
+ function parseJson(text: string): unknown {
175
+ try {
176
+ return JSON.parse(text);
177
+ } catch {
178
+ return undefined;
179
+ }
180
+ }
181
+
182
+ function isIslandEntry(value: unknown): value is IslandEntry {
183
+ if (!isRecord(value)) {
184
+ return false;
185
+ }
186
+ const named = typeof value.key === "string" && typeof value.type === "string";
187
+ return named && typeof value.version === "number" && typeof value.status === "string";
188
+ }
189
+
190
+ /** An action's outcome: what a client needs of one is its status (the client fixtures, spec §8.2). */
191
+ function isActionResponse(value: unknown): value is ActionResponse {
192
+ return isRecord(value) && (value.status === "ok" || value.status === "error");
193
+ }
194
+
108
195
  export class ScreenFetchError extends Error {
109
196
  readonly status: number;
110
197
  readonly body: string;
@@ -121,27 +208,265 @@ export class ScreenFetchError extends Error {
121
208
 
122
209
  function errorCode(body: string): string | undefined {
123
210
  try {
124
- const code = (JSON.parse(body) as { error?: { code?: unknown } }).error?.code;
211
+ const parsed: unknown = JSON.parse(body);
212
+ const error = isRecord(parsed) ? parsed.error : undefined;
213
+ const code = isRecord(error) ? error.code : undefined;
125
214
  return typeof code === "string" ? code : undefined;
126
215
  } catch {
127
216
  return undefined;
128
217
  }
129
218
  }
130
219
 
220
+ /**
221
+ * The caller's headers, given any way fetch takes them, sent as JSON unless they say otherwise.
222
+ * (Spreading a `Headers` object would drop them all.)
223
+ */
224
+ function jsonHeaders(init: HeadersInit | undefined): Headers {
225
+ const headers = new Headers(init);
226
+ if (!headers.has("content-type")) {
227
+ headers.set("content-type", "application/json");
228
+ }
229
+ return headers;
230
+ }
231
+
232
+ /**
233
+ * Fetch a screen, all of it: its stream (spec §4.6) read to the end. Throws ScreenFetchError for a
234
+ * non-2xx response (e.g. `not_found`) or one that isn't a screen. To show its islands as they
235
+ * arrive, use openScreen.
236
+ */
131
237
  export async function fetchScreen(
132
238
  baseUrl: string,
133
239
  request: ScreenRequest,
134
240
  init: RequestInit = {},
135
241
  fetchImpl: typeof fetch = fetch,
136
242
  ): Promise<ScreenResponse> {
243
+ return collectScreen(await openScreen(baseUrl, request, init, fetchImpl));
244
+ }
245
+
246
+ // ---- Streams (spec §4.6) ----
247
+
248
+ /** A screen as it arrives: its head, then each pending island as the composer resolves it. */
249
+ export interface ScreenStream {
250
+ /** The screen, its islands resolved or pending. */
251
+ head: ScreenHead;
252
+ /**
253
+ * Each pending island's entry, as it arrives. If the stream ends early, those that never came
254
+ * arrive as errors: `incomplete`, retryable.
255
+ */
256
+ islands: AsyncIterable<IslandEntry>;
257
+ }
258
+
259
+ /**
260
+ * Request a screen, and resolve once its head has arrived. Throws ScreenFetchError for a non-2xx
261
+ * response (e.g. `not_found`) or one that isn't a screen's stream.
262
+ */
263
+ export async function openScreen(
264
+ baseUrl: string,
265
+ request: ScreenRequest,
266
+ init: RequestInit = {},
267
+ fetchImpl: typeof fetch = fetch,
268
+ ): Promise<ScreenStream> {
137
269
  const res = await fetchImpl(`${baseUrl}/screens/${encodeURIComponent(request.screen)}`, {
138
270
  ...init,
139
271
  method: "POST",
140
- headers: { "content-type": "application/json", ...init.headers },
272
+ headers: jsonHeaders(init.headers),
273
+ body: JSON.stringify(request),
274
+ });
275
+ if (!res.ok) {
276
+ throw new ScreenFetchError(res.status, await res.text());
277
+ }
278
+ const lines = linesOf(res)[Symbol.asyncIterator]();
279
+ const first = await lines.next();
280
+ const head = first.done ? undefined : parseJson(first.value);
281
+ if (!isRecord(head) || head.kind !== "head" || !isScreenHead(head)) {
282
+ await lines.return?.();
283
+ throw new ScreenFetchError(res.status, first.done ? "" : first.value);
284
+ }
285
+ const { kind: _kind, ...screen } = head;
286
+ return { head: screen, islands: pendingIslands(screen, lines) };
287
+ }
288
+
289
+ /** Reads the rest of a stream, and returns the screen with every island in place. */
290
+ export async function collectScreen(stream: ScreenStream): Promise<ScreenResponse> {
291
+ let head = stream.head;
292
+ for await (const entry of stream.islands) {
293
+ head = withIsland(head, entry);
294
+ }
295
+ return {
296
+ ...head,
297
+ islands: head.islands.filter((e): e is IslandEntry => e.status !== "pending"),
298
+ };
299
+ }
300
+
301
+ /** The head with a pending island's entry in its place; unchanged if the key isn't pending. */
302
+ export function withIsland(head: ScreenHead, entry: IslandEntry): ScreenHead {
303
+ return {
304
+ ...head,
305
+ islands: head.islands.map((e) => (e.key === entry.key && e.status === "pending" ? entry : e)),
306
+ };
307
+ }
308
+
309
+ /** A screen's head and end as a stream, for a screen that's already complete (spec §4.6). */
310
+ export function screenLines(screen: ScreenResponse): string {
311
+ return `${JSON.stringify({ kind: "head", ...screen })}\n${JSON.stringify({ kind: "end" })}\n`;
312
+ }
313
+
314
+ function isScreenHead(
315
+ value: Record<string, unknown>,
316
+ ): value is Record<string, unknown> & ScreenHead {
317
+ return (
318
+ typeof value.screen === "string" &&
319
+ Array.isArray(value.islands) &&
320
+ value.islands.every(isIslandEntry)
321
+ );
322
+ }
323
+
324
+ /** The islands pending in `head`, as `lines` bring them, until the end line. */
325
+ async function* pendingIslands(
326
+ head: ScreenHead,
327
+ lines: AsyncIterator<string>,
328
+ ): AsyncIterable<IslandEntry> {
329
+ const waiting = new Map(
330
+ head.islands.filter((e) => e.status === "pending").map((e) => [e.key, e]),
331
+ );
332
+ try {
333
+ while (waiting.size > 0) {
334
+ const next = await lines.next();
335
+ if (next.done) {
336
+ break;
337
+ }
338
+ const line = parseJson(next.value);
339
+ if (!isRecord(line) || line.kind === "end") {
340
+ break;
341
+ }
342
+ // Lines of a kind it doesn't know, or for an island that isn't pending, are skipped (spec §4.6).
343
+ const entry = line.kind === "island" && isRecord(line.island) ? line.island : undefined;
344
+ if (entry?.status !== "pending" && isIslandEntry(entry) && waiting.delete(entry.key)) {
345
+ yield entry;
346
+ }
347
+ }
348
+ } finally {
349
+ await lines.return?.();
350
+ }
351
+ for (const e of waiting.values()) {
352
+ yield {
353
+ key: e.key,
354
+ type: e.type,
355
+ version: e.version,
356
+ status: "error",
357
+ error: { code: "incomplete", retryable: true },
358
+ };
359
+ }
360
+ }
361
+
362
+ /** A body's lines, as they arrive if the body can be read as a stream, or all at once. */
363
+ async function* linesOf(res: Response): AsyncIterable<string> {
364
+ if (!res.body) {
365
+ yield* (await res.text()).split("\n").filter((line) => line !== "");
366
+ return;
367
+ }
368
+ const reader = res.body.getReader();
369
+ const decoder = new TextDecoder();
370
+ let buffered = "";
371
+ try {
372
+ for (;;) {
373
+ const { done, value } = await reader.read();
374
+ if (done) {
375
+ break;
376
+ }
377
+ buffered += decoder.decode(value, { stream: true });
378
+ const lines = buffered.split("\n");
379
+ buffered = lines.pop() ?? "";
380
+ yield* lines.filter((line) => line !== "");
381
+ }
382
+ buffered += decoder.decode();
383
+ if (buffered.trim() !== "") {
384
+ yield buffered;
385
+ }
386
+ } finally {
387
+ await reader.cancel().catch(() => undefined);
388
+ }
389
+ }
390
+
391
+ // ---- Island requests (spec §4.5) ----
392
+
393
+ /**
394
+ * A request for one island of a screen: the page `cursor` asks for (an entry's `next`), or the
395
+ * island from its first page without one. `params` are the screen's own.
396
+ */
397
+ export function buildIslandRequest(
398
+ screen: string,
399
+ params: Record<string, string> | undefined,
400
+ entry: { key: string; version: number },
401
+ client: ClientContext,
402
+ cursor?: string,
403
+ ): IslandRequest {
404
+ return {
405
+ protocol: PROTOCOL_VERSION,
406
+ screen,
407
+ key: entry.key,
408
+ version: entry.version,
409
+ params,
410
+ client,
411
+ ...(cursor !== undefined && { cursor }),
412
+ };
413
+ }
414
+
415
+ /**
416
+ * POST an island request. Resolves with the island's entry: its props (and `next`, if it has more
417
+ * pages) or the error it failed with. Throws IslandFetchError for a non-2xx response (e.g.
418
+ * `invalid_cursor`, `unknown_island`, `unauthenticated`), or an answer that isn't this island.
419
+ */
420
+ export async function fetchIsland(
421
+ baseUrl: string,
422
+ request: IslandRequest,
423
+ init: RequestInit = {},
424
+ fetchImpl: typeof fetch = fetch,
425
+ ): Promise<IslandEntry> {
426
+ const path = `${encodeURIComponent(request.screen)}/islands/${encodeURIComponent(request.key)}`;
427
+ const res = await fetchImpl(`${baseUrl}/screens/${path}`, {
428
+ ...init,
429
+ method: "POST",
430
+ headers: jsonHeaders(init.headers),
141
431
  body: JSON.stringify(request),
142
432
  });
143
- if (!res.ok) throw new ScreenFetchError(res.status, await res.text());
144
- return (await res.json()) as ScreenResponse;
433
+ const text = await res.text();
434
+ if (!res.ok) {
435
+ throw new IslandFetchError(res.status, text);
436
+ }
437
+ const response = parseJson(text);
438
+ if (!isIslandResponse(response) || !isIslandAsked(response.island, request)) {
439
+ throw new IslandFetchError(res.status, text);
440
+ }
441
+ return response.island;
442
+ }
443
+
444
+ /**
445
+ * An island request failed: a non-2xx response such as `invalid_cursor`, `unknown_island` or
446
+ * `unauthenticated`, or an answer that isn't the island asked for. An island that failed on the
447
+ * composer isn't thrown: it's an entry with `status: "error"`.
448
+ */
449
+ export class IslandFetchError extends Error {
450
+ readonly status: number;
451
+ readonly body: string;
452
+ /** The protocol error code from the response body (e.g. "invalid_cursor"), if there was one. */
453
+ readonly code: string | undefined;
454
+
455
+ constructor(status: number, body: string) {
456
+ super(`Island request failed with status ${status}`);
457
+ this.status = status;
458
+ this.body = body;
459
+ this.code = errorCode(body);
460
+ }
461
+ }
462
+
463
+ function isIslandResponse(value: unknown): value is IslandResponse {
464
+ return isRecord(value) && typeof value.screen === "string" && isIslandEntry(value.island);
465
+ }
466
+
467
+ /** Whether the answer is the island the request asked for, at the version it asked for. */
468
+ function isIslandAsked(island: IslandEntry, request: IslandRequest): boolean {
469
+ return island.key === request.key && island.version === request.version;
145
470
  }
146
471
 
147
472
  // ---- Actions (spec §5) ----
@@ -166,8 +491,11 @@ export class ActionFetchError extends Error {
166
491
 
167
492
  /** A fresh idempotency key: one per user intent, reused when retrying it (spec §5.2). */
168
493
  export function newIdempotencyKey(): string {
169
- const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;
170
- if (c?.randomUUID) return c.randomUUID();
494
+ // React Native's Hermes may have no crypto, or crypto without randomUUID.
495
+ const c: Partial<Pick<Crypto, "randomUUID">> | undefined = globalThis.crypto;
496
+ if (c?.randomUUID) {
497
+ return c.randomUUID();
498
+ }
171
499
  // React Native's Hermes has no crypto.randomUUID. Uniqueness, not secrecy, is what matters here.
172
500
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (ch) => {
173
501
  const r = (Math.random() * 16) | 0;
@@ -205,16 +533,18 @@ export async function fetchAction(
205
533
  const res = await fetchImpl(`${baseUrl}/actions/${encodeURIComponent(request.action)}`, {
206
534
  ...init,
207
535
  method: "POST",
208
- headers: { "content-type": "application/json", ...init.headers },
536
+ headers: jsonHeaders(init.headers),
209
537
  body: JSON.stringify(request),
210
538
  });
211
539
  const text = await res.text();
212
- if (!res.ok) throw new ActionFetchError(res.status, text);
213
- try {
214
- return JSON.parse(text) as ActionResponse;
215
- } catch {
540
+ if (!res.ok) {
541
+ throw new ActionFetchError(res.status, text);
542
+ }
543
+ const response = parseJson(text);
544
+ if (!isActionResponse(response)) {
216
545
  throw new ActionFetchError(res.status, text);
217
546
  }
547
+ return response;
218
548
  }
219
549
 
220
550
  /**
@@ -226,12 +556,16 @@ export function checkActionResponse<I, R, E extends DeclaredError>(
226
556
  action: ActionDescriptor<I, R, E>,
227
557
  response: unknown,
228
558
  ): ActionResponse<R, E> {
229
- const r = response as { status?: unknown; error?: { code?: unknown } } | null;
230
- const declared =
231
- r?.status === "error" &&
232
- typeof r.error?.code === "string" &&
233
- action.errors.includes(r.error.code);
234
- if (r?.status === "ok" || declared) return response as ActionResponse<R, E>;
559
+ const error = isRecord(response) ? response.error : undefined;
560
+ const code = isRecord(error) ? error.code : undefined;
561
+ const status = isRecord(response) ? response.status : undefined;
562
+ const declared = status === "error" && typeof code === "string" && action.errors.includes(code);
563
+ if (isActionResponse(response) && (status === "ok" || declared)) {
564
+ // The result's and error's types are the action's: generated from its manifest, which the
565
+ // composer checks its outcomes against. They exist only at the type level.
566
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
567
+ return response as ActionResponse<R, E>;
568
+ }
235
569
  throw new ActionFetchError(200, JSON.stringify(response));
236
570
  }
237
571