@getuserfeedback/protocol 3.1.3 → 3.1.5

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.
@@ -14,6 +14,8 @@ export declare const coreCommandKindSchema: z.ZodMiniEnum<{
14
14
  init: "init";
15
15
  close: "close";
16
16
  reset: "reset";
17
+ "instanceFeedback.capture": "instanceFeedback.capture";
18
+ "instanceFeedback.listMine": "instanceFeedback.listMine";
17
19
  }>;
18
20
  export declare const publicCommandKindSchema: z.ZodMiniEnum<{
19
21
  open: "open";
@@ -45,6 +47,8 @@ export declare const allCommandKindSchema: z.ZodMiniEnum<{
45
47
  init: "init";
46
48
  close: "close";
47
49
  reset: "reset";
50
+ "instanceFeedback.capture": "instanceFeedback.capture";
51
+ "instanceFeedback.listMine": "instanceFeedback.listMine";
48
52
  updateHostContext: "updateHostContext";
49
53
  emitHostSignal: "emitHostSignal";
50
54
  setContainer: "setContainer";
@@ -1 +1 @@
1
- {"version":3,"file":"command-kinds.d.ts","sourceRoot":"","sources":["../src/command-kinds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAmC9B,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;EAA2B,CAAC;AAC9D,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;EAA6B,CAAC;AAKlE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;EAA0B,CAAC"}
1
+ {"version":3,"file":"command-kinds.d.ts","sourceRoot":"","sources":["../src/command-kinds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAqC9B,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;EAA2B,CAAC;AAC9D,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;EAA6B,CAAC;AAKlE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;EAA0B,CAAC"}
@@ -13,6 +13,8 @@ const coreCommandKinds = [
13
13
  "init",
14
14
  "close",
15
15
  "reset",
16
+ "instanceFeedback.capture",
17
+ "instanceFeedback.listMine",
16
18
  "error",
17
19
  ];
18
20
  const publicCommandKinds = [
@@ -329,6 +329,35 @@ export declare const coreCommandEnvelopeSchema: z.ZodMiniObject<{
329
329
  }>>;
330
330
  }, z.core.$strip>, z.ZodMiniObject<{
331
331
  kind: z.ZodMiniLiteral<"reset">;
332
+ }, z.core.$strip>, z.ZodMiniObject<{
333
+ kind: z.ZodMiniLiteral<"instanceFeedback.capture">;
334
+ payload: z.ZodMiniObject<{
335
+ targetBindingToken: z.ZodMiniString<string>;
336
+ capturedAt: z.ZodMiniString<string>;
337
+ comment: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniString<string>>>;
338
+ dataType: z.ZodMiniEnum<{
339
+ boolean: "boolean";
340
+ categorical: "categorical";
341
+ numeric: "numeric";
342
+ }>;
343
+ label: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniString<string>>>;
344
+ name: z.ZodMiniOptional<z.ZodMiniString<string>>;
345
+ reasonCategories: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
346
+ scoreValue: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniNumber<number>>>;
347
+ valence: z.ZodMiniEnum<{
348
+ positive: "positive";
349
+ negative: "negative";
350
+ neutral: "neutral";
351
+ }>;
352
+ }, z.core.$strip>;
353
+ }, z.core.$strip>, z.ZodMiniObject<{
354
+ kind: z.ZodMiniLiteral<"instanceFeedback.listMine">;
355
+ payload: z.ZodMiniObject<{
356
+ targets: z.ZodMiniArray<z.ZodMiniObject<{
357
+ name: z.ZodMiniOptional<z.ZodMiniString<string>>;
358
+ targetBindingToken: z.ZodMiniString<string>;
359
+ }, z.core.$strip>>;
360
+ }, z.core.$strip>;
332
361
  }, z.core.$strip>, z.ZodMiniObject<{
333
362
  kind: z.ZodMiniLiteral<"error">;
334
363
  event: z.ZodMiniObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"core-command-envelope.d.ts","sourceRoot":"","sources":["../src/core-command-envelope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,kBAAkB,CAAC;AAOrE,sEAAsE;AACtE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAOpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE7E,wEAAwE;AACxE,MAAM,MAAM,cAAc,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,UAAU,CAAC;CACxB,CAAC"}
1
+ {"version":3,"file":"core-command-envelope.d.ts","sourceRoot":"","sources":["../src/core-command-envelope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,kBAAkB,CAAC;AAOrE,sEAAsE;AACtE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAOpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE7E,wEAAwE;AACxE,MAAM,MAAM,cAAc,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,UAAU,CAAC;CACxB,CAAC"}
@@ -286,6 +286,35 @@ export declare const coreCommandPayloadSchema: z.ZodMiniUnion<readonly [z.ZodMin
286
286
  }>>;
287
287
  }, z.core.$strip>, z.ZodMiniObject<{
288
288
  kind: z.ZodMiniLiteral<"reset">;
289
+ }, z.core.$strip>, z.ZodMiniObject<{
290
+ kind: z.ZodMiniLiteral<"instanceFeedback.capture">;
291
+ payload: z.ZodMiniObject<{
292
+ targetBindingToken: z.ZodMiniString<string>;
293
+ capturedAt: z.ZodMiniString<string>;
294
+ comment: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniString<string>>>;
295
+ dataType: z.ZodMiniEnum<{
296
+ boolean: "boolean";
297
+ categorical: "categorical";
298
+ numeric: "numeric";
299
+ }>;
300
+ label: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniString<string>>>;
301
+ name: z.ZodMiniOptional<z.ZodMiniString<string>>;
302
+ reasonCategories: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
303
+ scoreValue: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniNumber<number>>>;
304
+ valence: z.ZodMiniEnum<{
305
+ positive: "positive";
306
+ negative: "negative";
307
+ neutral: "neutral";
308
+ }>;
309
+ }, z.core.$strip>;
310
+ }, z.core.$strip>, z.ZodMiniObject<{
311
+ kind: z.ZodMiniLiteral<"instanceFeedback.listMine">;
312
+ payload: z.ZodMiniObject<{
313
+ targets: z.ZodMiniArray<z.ZodMiniObject<{
314
+ name: z.ZodMiniOptional<z.ZodMiniString<string>>;
315
+ targetBindingToken: z.ZodMiniString<string>;
316
+ }, z.core.$strip>>;
317
+ }, z.core.$strip>;
289
318
  }, z.core.$strip>, z.ZodMiniObject<{
290
319
  kind: z.ZodMiniLiteral<"error">;
291
320
  event: z.ZodMiniObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"core-commands.d.ts","sourceRoot":"","sources":["../src/core-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AA8M9B,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAInC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
1
+ {"version":3,"file":"core-commands.d.ts","sourceRoot":"","sources":["../src/core-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AA8N9B,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAInC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import * as z from "zod/mini";
2
2
  import { appEventCustomerTrackSchema, appEventExternalIdSchema, appEventSystemTrackSchema, } from "./app-event.js";
3
3
  import { ErrorEventSchema } from "./errors.js";
4
+ import { captureInstanceFeedbackRequestSchema, listInstanceFeedbackMineRequestSchema, } from "./instance-feedback.js";
4
5
  import { responseMetadataInputSchema } from "./response-metadata.js";
5
6
  import { configureOptionsSchema, initOptionsSchema } from "./widget-config.js";
6
7
  const flowHandleIdSchema = z.string().check(z.trim(), z.minLength(1));
@@ -145,6 +146,14 @@ const initCorePayloadSchema = z.strictObject({
145
146
  const resetPayloadSchema = z.object({
146
147
  kind: z.literal("reset"),
147
148
  });
149
+ const instanceFeedbackCapturePayloadSchema = z.object({
150
+ kind: z.literal("instanceFeedback.capture"),
151
+ payload: captureInstanceFeedbackRequestSchema,
152
+ });
153
+ const instanceFeedbackListMinePayloadSchema = z.object({
154
+ kind: z.literal("instanceFeedback.listMine"),
155
+ payload: listInstanceFeedbackMineRequestSchema,
156
+ });
148
157
  const coreCommandPayloadWithoutIdentifySchema = z.union([
149
158
  z.union([openPersistedCorePayloadSchema, openInlineCorePayloadSchema]),
150
159
  z.union([prefetchPayloadSchema, prefetchInlinePayloadSchema]),
@@ -160,6 +169,8 @@ const coreCommandPayloadWithoutIdentifySchema = z.union([
160
169
  initCorePayloadSchema,
161
170
  closeCorePayloadSchema,
162
171
  resetPayloadSchema,
172
+ instanceFeedbackCapturePayloadSchema,
173
+ instanceFeedbackListMinePayloadSchema,
163
174
  errorPayloadSchema,
164
175
  ]);
165
176
  export const coreCommandPayloadSchema = z.union([
@@ -0,0 +1,16 @@
1
+ export type FlowCommandHandleController<THandleId extends string, TSettlement> = {
2
+ runCommand<TPayload>(buildPayload: (handleId: THandleId | undefined) => TPayload, dispatchAndWait: (payload: TPayload) => Promise<TSettlement>): Promise<TSettlement>;
3
+ getHandleId(): THandleId | undefined;
4
+ hasHandleId(handleId: string): boolean;
5
+ hasPendingCommands(): boolean;
6
+ subscribeHandle(subscriber: (handleId: THandleId) => void): () => void;
7
+ clearResolvedHandle(): THandleId | undefined;
8
+ reset(): void;
9
+ };
10
+ export type CreateFlowCommandHandleControllerOptions<THandleId extends string, TSettlement> = {
11
+ getHandleIdFromSettlement: (settlement: TSettlement) => THandleId | undefined;
12
+ isStaleHandleError: (error: unknown) => boolean;
13
+ onClearResolvedHandle?: (handleId: THandleId) => void;
14
+ };
15
+ export declare function createFlowCommandHandleController<THandleId extends string, TSettlement>({ getHandleIdFromSettlement, isStaleHandleError, onClearResolvedHandle, }: CreateFlowCommandHandleControllerOptions<THandleId, TSettlement>): FlowCommandHandleController<THandleId, TSettlement>;
16
+ //# sourceMappingURL=flow-command-handle-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-command-handle-controller.d.ts","sourceRoot":"","sources":["../../src/host/flow-command-handle-controller.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,2BAA2B,CACtC,SAAS,SAAS,MAAM,EACxB,WAAW,IACR;IACH,UAAU,CAAC,QAAQ,EAClB,YAAY,EAAE,CAAC,QAAQ,EAAE,SAAS,GAAG,SAAS,KAAK,QAAQ,EAC3D,eAAe,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,WAAW,CAAC,GAC1D,OAAO,CAAC,WAAW,CAAC,CAAC;IACxB,WAAW,IAAI,SAAS,GAAG,SAAS,CAAC;IACrC,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACvC,kBAAkB,IAAI,OAAO,CAAC;IAC9B,eAAe,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACvE,mBAAmB,IAAI,SAAS,GAAG,SAAS,CAAC;IAC7C,KAAK,IAAI,IAAI,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,wCAAwC,CACnD,SAAS,SAAS,MAAM,EACxB,WAAW,IACR;IACH,yBAAyB,EAAE,CAAC,UAAU,EAAE,WAAW,KAAK,SAAS,GAAG,SAAS,CAAC;IAC9E,kBAAkB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAChD,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,KAAK,IAAI,CAAC;CACtD,CAAC;AAEF,wBAAgB,iCAAiC,CAChD,SAAS,SAAS,MAAM,EACxB,WAAW,EACV,EACD,yBAAyB,EACzB,kBAAkB,EAClB,qBAAqB,GACrB,EAAE,wCAAwC,CAC1C,SAAS,EACT,WAAW,CACX,GAAG,2BAA2B,CAAC,SAAS,EAAE,WAAW,CAAC,CA6CtD"}
@@ -0,0 +1,39 @@
1
+ import { createLazyHandleClient, } from "./lazy-handle-client.js";
2
+ export function createFlowCommandHandleController({ getHandleIdFromSettlement, isStaleHandleError, onClearResolvedHandle, }) {
3
+ const handleClient = createLazyHandleClient({
4
+ getHandleIdFromSettlement,
5
+ });
6
+ const clearResolvedHandle = () => {
7
+ const previousHandleId = handleClient.getHandleId();
8
+ if (!previousHandleId) {
9
+ return undefined;
10
+ }
11
+ handleClient.reset();
12
+ onClearResolvedHandle?.(previousHandleId);
13
+ return previousHandleId;
14
+ };
15
+ const reset = () => {
16
+ const previousHandleId = handleClient.getHandleId();
17
+ handleClient.reset();
18
+ if (previousHandleId) {
19
+ onClearResolvedHandle?.(previousHandleId);
20
+ }
21
+ };
22
+ const runCommand = async (buildPayload, dispatchAndWait) => {
23
+ return handleClient.runCommandWithRetry(buildPayload, dispatchAndWait, {
24
+ shouldRetry: isStaleHandleError,
25
+ onBeforeRetry: () => {
26
+ clearResolvedHandle();
27
+ },
28
+ });
29
+ };
30
+ return {
31
+ runCommand,
32
+ getHandleId: () => handleClient.getHandleId(),
33
+ hasHandleId: (handleId) => handleClient.getHandleId() === handleId,
34
+ hasPendingCommands: () => handleClient.hasPendingCommands(),
35
+ subscribeHandle: (subscriber) => handleClient.subscribeHandle(subscriber),
36
+ clearResolvedHandle,
37
+ reset,
38
+ };
39
+ }
@@ -32,6 +32,8 @@ export declare const commandSettledDetailSchema: z.ZodMiniDiscriminatedUnion<[z.
32
32
  init: "init";
33
33
  close: "close";
34
34
  reset: "reset";
35
+ "instanceFeedback.capture": "instanceFeedback.capture";
36
+ "instanceFeedback.listMine": "instanceFeedback.listMine";
35
37
  updateHostContext: "updateHostContext";
36
38
  emitHostSignal: "emitHostSignal";
37
39
  setContainer: "setContainer";
@@ -60,6 +62,8 @@ export declare const commandSettledDetailSchema: z.ZodMiniDiscriminatedUnion<[z.
60
62
  init: "init";
61
63
  close: "close";
62
64
  reset: "reset";
65
+ "instanceFeedback.capture": "instanceFeedback.capture";
66
+ "instanceFeedback.listMine": "instanceFeedback.listMine";
63
67
  updateHostContext: "updateHostContext";
64
68
  emitHostSignal: "emitHostSignal";
65
69
  setContainer: "setContainer";
@@ -1 +1 @@
1
- {"version":3,"file":"host-event-schemas.d.ts","sourceRoot":"","sources":["../../src/host/host-event-schemas.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAoB9B;;;GAGG;AACH,eAAO,MAAM,gCAAgC;;;kBAG3C,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAChD,OAAO,gCAAgC,CACvC,CAAC;AAcF,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAGrC,CAAC;AAEH,YAAY,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAUrE,eAAO,MAAM,4BAA4B;;;;;;;kBAGvC,CAAC;AAEH,YAAY,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAEvE,eAAO,MAAM,oCAAoC;;;;;;;kBAG/C,CAAC;AAEH,YAAY,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAC;AAE/E,eAAO,MAAM,yBAAyB;;;;;;;;;kBAMpC,CAAC;AAEH,YAAY,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;kBASxC,CAAC;AAEH,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAExE;;GAEG;AACH,wBAAgB,+BAA+B,CAC9C,MAAM,EAAE,OAAO,GACb,0BAA0B,GAAG,IAAI,CAGnC;AAED;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE;IACzD,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,0BAA0B,GAAG,IAAI,CAUpC;AAED,YAAY,EAAE,kCAAkC,EAAE,MAAM,0BAA0B,CAAC;AACnF,OAAO,EAAE,qCAAqC,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"host-event-schemas.d.ts","sourceRoot":"","sources":["../../src/host/host-event-schemas.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAoB9B;;;GAGG;AACH,eAAO,MAAM,gCAAgC;;;kBAG3C,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAChD,OAAO,gCAAgC,CACvC,CAAC;AAcF,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAGrC,CAAC;AAEH,YAAY,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAUrE,eAAO,MAAM,4BAA4B;;;;;;;kBAGvC,CAAC;AAEH,YAAY,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAEvE,eAAO,MAAM,oCAAoC;;;;;;;kBAG/C,CAAC;AAEH,YAAY,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAC;AAE/E,eAAO,MAAM,yBAAyB;;;;;;;;;kBAMpC,CAAC;AAEH,YAAY,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;kBASxC,CAAC;AAEH,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAExE;;GAEG;AACH,wBAAgB,+BAA+B,CAC9C,MAAM,EAAE,OAAO,GACb,0BAA0B,GAAG,IAAI,CAGnC;AAED;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE;IACzD,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,0BAA0B,GAAG,IAAI,CAUpC;AAED,YAAY,EAAE,kCAAkC,EAAE,MAAM,0BAA0B,CAAC;AACnF,OAAO,EAAE,qCAAqC,EAAE,MAAM,0BAA0B,CAAC"}
@@ -6,6 +6,7 @@ export * from "./command-envelope.js";
6
6
  export * from "./command-settlement.js";
7
7
  export * from "./constants.js";
8
8
  export * from "./external-id-argument-guards.js";
9
+ export * from "./flow-command-handle-controller.js";
9
10
  export * from "./host-event-contract.js";
10
11
  export * from "./lazy-handle-client.js";
11
12
  export { createCommandRequestId } from "./request-id.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/host/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kCAAkC,CAAC;AACjD,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oCAAoC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/host/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kCAAkC,CAAC;AACjD,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oCAAoC,CAAC"}
@@ -6,6 +6,7 @@ export * from "./command-envelope.js";
6
6
  export * from "./command-settlement.js";
7
7
  export * from "./constants.js";
8
8
  export * from "./external-id-argument-guards.js";
9
+ export * from "./flow-command-handle-controller.js";
9
10
  export * from "./host-event-contract.js";
10
11
  export * from "./lazy-handle-client.js";
11
12
  export { createCommandRequestId } from "./request-id.js";
@@ -8,7 +8,12 @@ type StageMap<TStage extends string> = {
8
8
  };
9
9
  export type LazyHandleClient<THandleId extends string, TSettlement, TStage extends string = LifecycleStage> = {
10
10
  runCommand<TPayload>(buildPayload: (handleId: THandleId | undefined) => TPayload, dispatchAndWait: (payload: TPayload) => Promise<TSettlement>): Promise<TSettlement>;
11
+ runCommandWithRetry<TPayload>(buildPayload: (handleId: THandleId | undefined) => TPayload, dispatchAndWait: (payload: TPayload) => Promise<TSettlement>, options: {
12
+ shouldRetry: (error: unknown) => boolean;
13
+ onBeforeRetry?: (error: unknown) => void;
14
+ }): Promise<TSettlement>;
11
15
  getHandleId(): THandleId | undefined;
16
+ hasPendingCommands(): boolean;
12
17
  subscribeHandle(subscriber: Subscriber<THandleId>): () => void;
13
18
  getStage(): TStage;
14
19
  setStage(stage: TStage): void;
@@ -1 +1 @@
1
- {"version":3,"file":"lazy-handle-client.d.ts","sourceRoot":"","sources":["../../src/host/lazy-handle-client.ts"],"names":[],"mappings":"AAAA,KAAK,UAAU,CAAC,SAAS,SAAS,MAAM,IAAI,CAAC,QAAQ,EAAE,SAAS,KAAK,IAAI,CAAC;AAC1E,KAAK,eAAe,CAAC,MAAM,SAAS,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;AAEtE,KAAK,cAAc,GAAG,eAAe,GAAG,OAAO,GAAG,aAAa,CAAC;AAChE,KAAK,QAAQ,CAAC,MAAM,SAAS,MAAM,IAAI;IACtC,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACpB,CAAC;AAQF,MAAM,MAAM,gBAAgB,CAC3B,SAAS,SAAS,MAAM,EACxB,WAAW,EACX,MAAM,SAAS,MAAM,GAAG,cAAc,IACnC;IACH,UAAU,CAAC,QAAQ,EAClB,YAAY,EAAE,CAAC,QAAQ,EAAE,SAAS,GAAG,SAAS,KAAK,QAAQ,EAC3D,eAAe,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,WAAW,CAAC,GAC1D,OAAO,CAAC,WAAW,CAAC,CAAC;IACxB,WAAW,IAAI,SAAS,GAAG,SAAS,CAAC;IACrC,eAAe,CAAC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,MAAM,IAAI,CAAC;IAC/D,QAAQ,IAAI,MAAM,CAAC;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,CAAC,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC;IAChE,KAAK,IAAI,IAAI,CAAC;IACd,UAAU,IAAI,IAAI,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,6BAA6B,CACxC,SAAS,SAAS,MAAM,EACxB,WAAW,EACX,MAAM,SAAS,MAAM,GAAG,cAAc,IACnC;IACH,yBAAyB,EAAE,CAAC,UAAU,EAAE,WAAW,KAAK,SAAS,GAAG,SAAS,CAAC;IAC9E,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,KAAK,oCAAoC,CACxC,SAAS,SAAS,MAAM,EACxB,WAAW,IACR;IACH,yBAAyB,EAAE,CAAC,UAAU,EAAE,WAAW,KAAK,SAAS,GAAG,SAAS,CAAC;IAC9E,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B,MAAM,CAAC,EAAE,SAAS,CAAC;CACnB,CAAC;AAEF,KAAK,mCAAmC,CACvC,SAAS,SAAS,MAAM,EACxB,WAAW,EACX,MAAM,SAAS,MAAM,IAClB;IACH,yBAAyB,EAAE,CAAC,UAAU,EAAE,WAAW,KAAK,SAAS,GAAG,SAAS,CAAC;IAC9E,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAuHF,wBAAgB,sBAAsB,CAAC,SAAS,SAAS,MAAM,EAAE,WAAW,EAC3E,OAAO,EAAE,oCAAoC,CAAC,SAAS,EAAE,WAAW,CAAC,GACnE,gBAAgB,CAAC,SAAS,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;AAC5D,wBAAgB,sBAAsB,CACrC,SAAS,SAAS,MAAM,EACxB,WAAW,EACX,MAAM,SAAS,MAAM,EAErB,OAAO,EAAE,mCAAmC,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,CAAC,GAC1E,gBAAgB,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC"}
1
+ {"version":3,"file":"lazy-handle-client.d.ts","sourceRoot":"","sources":["../../src/host/lazy-handle-client.ts"],"names":[],"mappings":"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"}
@@ -62,9 +62,49 @@ const createLazyHandleClientWithStages = (input) => {
62
62
  });
63
63
  return run;
64
64
  };
65
+ const runCommandWithRetry = (buildPayload, dispatchAndWait, options) => {
66
+ const execute = async () => {
67
+ let didRetry = false;
68
+ for (;;) {
69
+ if (stage === stages.invalidated) {
70
+ throw new Error("Handle client is invalidated");
71
+ }
72
+ const commandEpoch = epoch;
73
+ const payload = buildPayload(handleId);
74
+ try {
75
+ const settlement = await dispatchAndWait(payload);
76
+ const settledHandleId = input.getHandleIdFromSettlement(settlement);
77
+ if (settledHandleId && commandEpoch === epoch) {
78
+ publishHandle(settledHandleId);
79
+ }
80
+ return settlement;
81
+ }
82
+ catch (error) {
83
+ if (commandEpoch === epoch &&
84
+ !didRetry &&
85
+ options.shouldRetry(error)) {
86
+ didRetry = true;
87
+ options.onBeforeRetry?.(error);
88
+ continue;
89
+ }
90
+ throw error;
91
+ }
92
+ }
93
+ };
94
+ const run = queuedCommandCount === 0 ? execute() : tail.then(execute, execute);
95
+ queuedCommandCount += 1;
96
+ tail = run.then(() => {
97
+ queuedCommandCount -= 1;
98
+ }, () => {
99
+ queuedCommandCount -= 1;
100
+ });
101
+ return run;
102
+ };
65
103
  return {
66
104
  runCommand,
105
+ runCommandWithRetry,
67
106
  getHandleId: () => handleId,
107
+ hasPendingCommands: () => queuedCommandCount > 0,
68
108
  subscribeHandle: (subscriber) => {
69
109
  subscribers.add(subscriber);
70
110
  if (handleId) {
@@ -4,6 +4,8 @@
4
4
  */
5
5
  export { createCommandDispatch } from "./command-dispatch.js";
6
6
  export { COMMAND_SETTLEMENT_TIMEOUT_CODE, CommandSettlementError, CommandSettlementTimeoutError, toCommandSettlementError, waitForCommandSettlement, } from "./command-settlement.js";
7
+ export type { FlowCommandHandleController } from "./flow-command-handle-controller.js";
8
+ export { createFlowCommandHandleController } from "./flow-command-handle-controller.js";
7
9
  export type { FlowHandleFromSettlement, FlowState, } from "./host-event-contract.js";
8
10
  export { getFlowHandleFromSettlementDetail, isFlowStateChangedDetail, isHandleInvalidatedDetail, isInstanceFlowStateChangedDetail, } from "./host-event-contract.js";
9
11
  export type { AppEventCapability, AppEventFlag, AppEventFlagProvider, AppEventFlagValue, AppEventPayload, CapabilitiesInput, ClientMeta, ClientOptions, Command, CommandEnvelope, ConfigureOptions, ContainerPolicy, FlagsInput, InitOptions, PublicCommandPayload, ResponseMetadataInput, TelemetryEvent, } from "./sdk-types.js";
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/host/sdk.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EACN,+BAA+B,EAC/B,sBAAsB,EACtB,6BAA6B,EAC7B,wBAAwB,EACxB,wBAAwB,GACxB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACX,wBAAwB,EACxB,SAAS,GACT,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACN,iCAAiC,EACjC,wBAAwB,EACxB,yBAAyB,EACzB,gCAAgC,GAChC,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACX,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,OAAO,EACP,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,WAAW,EACX,oBAAoB,EACpB,qBAAqB,EAErB,cAAc,GACd,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/host/sdk.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EACN,+BAA+B,EAC/B,sBAAsB,EACtB,6BAA6B,EAC7B,wBAAwB,EACxB,wBAAwB,GACxB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AACvF,OAAO,EAAE,iCAAiC,EAAE,MAAM,qCAAqC,CAAC;AACxF,YAAY,EACX,wBAAwB,EACxB,SAAS,GACT,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACN,iCAAiC,EACjC,wBAAwB,EACxB,yBAAyB,EACzB,gCAAgC,GAChC,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACX,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,OAAO,EACP,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,WAAW,EACX,oBAAoB,EACpB,qBAAqB,EAErB,cAAc,GACd,MAAM,gBAAgB,CAAC"}
package/dist/host/sdk.js CHANGED
@@ -4,4 +4,5 @@
4
4
  */
5
5
  export { createCommandDispatch } from "./command-dispatch.js";
6
6
  export { COMMAND_SETTLEMENT_TIMEOUT_CODE, CommandSettlementError, CommandSettlementTimeoutError, toCommandSettlementError, waitForCommandSettlement, } from "./command-settlement.js";
7
+ export { createFlowCommandHandleController } from "./flow-command-handle-controller.js";
7
8
  export { getFlowHandleFromSettlementDetail, isFlowStateChangedDetail, isHandleInvalidatedDetail, isInstanceFlowStateChangedDetail, } from "./host-event-contract.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/protocol",
3
- "version": "3.1.3",
3
+ "version": "3.1.5",
4
4
  "description": "getuserfeedback widget protocol — host surface and (later) wire protocol",
5
5
  "keywords": [
6
6
  "getuserfeedback",
@@ -14,6 +14,8 @@ const coreCommandKinds = [
14
14
  "init",
15
15
  "close",
16
16
  "reset",
17
+ "instanceFeedback.capture",
18
+ "instanceFeedback.listMine",
17
19
  "error",
18
20
  ] as const;
19
21
 
@@ -5,6 +5,10 @@ import {
5
5
  appEventSystemTrackSchema,
6
6
  } from "./app-event.js";
7
7
  import { ErrorEventSchema } from "./errors.js";
8
+ import {
9
+ captureInstanceFeedbackRequestSchema,
10
+ listInstanceFeedbackMineRequestSchema,
11
+ } from "./instance-feedback.js";
8
12
  import { responseMetadataInputSchema } from "./response-metadata.js";
9
13
  import { configureOptionsSchema, initOptionsSchema } from "./widget-config.js";
10
14
 
@@ -186,6 +190,16 @@ const resetPayloadSchema = z.object({
186
190
  kind: z.literal("reset"),
187
191
  });
188
192
 
193
+ const instanceFeedbackCapturePayloadSchema = z.object({
194
+ kind: z.literal("instanceFeedback.capture"),
195
+ payload: captureInstanceFeedbackRequestSchema,
196
+ });
197
+
198
+ const instanceFeedbackListMinePayloadSchema = z.object({
199
+ kind: z.literal("instanceFeedback.listMine"),
200
+ payload: listInstanceFeedbackMineRequestSchema,
201
+ });
202
+
189
203
  const coreCommandPayloadWithoutIdentifySchema = z.union([
190
204
  z.union([openPersistedCorePayloadSchema, openInlineCorePayloadSchema]),
191
205
  z.union([prefetchPayloadSchema, prefetchInlinePayloadSchema]),
@@ -201,6 +215,8 @@ const coreCommandPayloadWithoutIdentifySchema = z.union([
201
215
  initCorePayloadSchema,
202
216
  closeCorePayloadSchema,
203
217
  resetPayloadSchema,
218
+ instanceFeedbackCapturePayloadSchema,
219
+ instanceFeedbackListMinePayloadSchema,
204
220
  errorPayloadSchema,
205
221
  ]);
206
222
 
@@ -0,0 +1,239 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { createFlowCommandHandleController } from "./flow-command-handle-controller";
3
+
4
+ describe("flow command handle controller", () => {
5
+ it("serializes commands and publishes settled handles to later payloads", async () => {
6
+ const dispatched: Array<{ flowHandleId?: string; kind: string }> = [];
7
+ const controller = createFlowCommandHandleController<
8
+ string,
9
+ { result?: { flowHandleId?: string } }
10
+ >({
11
+ getHandleIdFromSettlement: (settlement) =>
12
+ settlement.result?.flowHandleId,
13
+ isStaleHandleError: () => false,
14
+ });
15
+
16
+ await controller.runCommand(
17
+ (flowHandleId) => ({ kind: "prefetch", flowHandleId }),
18
+ async (payload) => {
19
+ dispatched.push(payload);
20
+ return { result: { flowHandleId: "handle_123" } };
21
+ },
22
+ );
23
+ await controller.runCommand(
24
+ (flowHandleId) => ({ kind: "open", flowHandleId }),
25
+ async (payload) => {
26
+ dispatched.push(payload);
27
+ return { result: { flowHandleId: "handle_123" } };
28
+ },
29
+ );
30
+
31
+ expect(dispatched).toEqual([
32
+ { kind: "prefetch", flowHandleId: undefined },
33
+ { kind: "open", flowHandleId: "handle_123" },
34
+ ]);
35
+ expect(controller.getHandleId()).toBe("handle_123");
36
+ expect(controller.hasHandleId("handle_123")).toBe(true);
37
+ });
38
+
39
+ it("clears stale handles and retries once without the handle", async () => {
40
+ const dispatched: Array<{ flowHandleId?: string; kind: string }> = [];
41
+ const clearedHandles: string[] = [];
42
+ const controller = createFlowCommandHandleController<
43
+ string,
44
+ { result?: { flowHandleId?: string } }
45
+ >({
46
+ getHandleIdFromSettlement: (settlement) =>
47
+ settlement.result?.flowHandleId,
48
+ isStaleHandleError: (error) =>
49
+ error instanceof Error && error.message === "stale",
50
+ onClearResolvedHandle: (flowHandleId) => {
51
+ clearedHandles.push(flowHandleId);
52
+ },
53
+ });
54
+
55
+ await controller.runCommand(
56
+ (flowHandleId) => ({ kind: "prefetch", flowHandleId }),
57
+ async (payload) => {
58
+ dispatched.push(payload);
59
+ return { result: { flowHandleId: "handle_stale" } };
60
+ },
61
+ );
62
+ let didFailOnce = false;
63
+ await controller.runCommand(
64
+ (flowHandleId) => ({ kind: "open", flowHandleId }),
65
+ async (payload) => {
66
+ dispatched.push(payload);
67
+ if (!didFailOnce) {
68
+ didFailOnce = true;
69
+ throw new Error("stale");
70
+ }
71
+ return { result: { flowHandleId: "handle_recovered" } };
72
+ },
73
+ );
74
+
75
+ expect(dispatched).toEqual([
76
+ { kind: "prefetch", flowHandleId: undefined },
77
+ { kind: "open", flowHandleId: "handle_stale" },
78
+ { kind: "open", flowHandleId: undefined },
79
+ ]);
80
+ expect(clearedHandles).toEqual(["handle_stale"]);
81
+ expect(controller.getHandleId()).toBe("handle_recovered");
82
+ });
83
+
84
+ it("keeps stale-handle retry in the same serialized command slot", async () => {
85
+ const dispatched: Array<{ flowHandleId?: string; kind: string }> = [];
86
+ const controller = createFlowCommandHandleController<
87
+ string,
88
+ { result?: { flowHandleId?: string } }
89
+ >({
90
+ getHandleIdFromSettlement: (settlement) =>
91
+ settlement.result?.flowHandleId,
92
+ isStaleHandleError: (error) =>
93
+ error instanceof Error && error.message === "stale",
94
+ });
95
+
96
+ await controller.runCommand(
97
+ (flowHandleId) => ({ kind: "prefetch", flowHandleId }),
98
+ async (payload) => {
99
+ dispatched.push(payload);
100
+ return { result: { flowHandleId: "handle_stale" } };
101
+ },
102
+ );
103
+ let didFailOnce = false;
104
+ const staleOpen = controller.runCommand(
105
+ (flowHandleId) => ({ kind: "open", flowHandleId }),
106
+ async (payload) => {
107
+ dispatched.push(payload);
108
+ if (!didFailOnce) {
109
+ didFailOnce = true;
110
+ throw new Error("stale");
111
+ }
112
+ return { result: { flowHandleId: "handle_recovered" } };
113
+ },
114
+ );
115
+ const queuedPrerender = controller.runCommand(
116
+ (flowHandleId) => ({ kind: "prerender", flowHandleId }),
117
+ async (payload) => {
118
+ dispatched.push(payload);
119
+ return { result: { flowHandleId: "handle_second" } };
120
+ },
121
+ );
122
+
123
+ await staleOpen;
124
+ await queuedPrerender;
125
+
126
+ expect(dispatched).toEqual([
127
+ { kind: "prefetch", flowHandleId: undefined },
128
+ { kind: "open", flowHandleId: "handle_stale" },
129
+ { kind: "open", flowHandleId: undefined },
130
+ { kind: "prerender", flowHandleId: "handle_recovered" },
131
+ ]);
132
+ expect(controller.getHandleId()).toBe("handle_second");
133
+ });
134
+
135
+ it("does not retry non-stale failures", async () => {
136
+ const dispatched: Array<{ flowHandleId?: string; kind: string }> = [];
137
+ const controller = createFlowCommandHandleController<
138
+ string,
139
+ { result?: { flowHandleId?: string } }
140
+ >({
141
+ getHandleIdFromSettlement: (settlement) =>
142
+ settlement.result?.flowHandleId,
143
+ isStaleHandleError: () => false,
144
+ });
145
+
146
+ await expect(
147
+ controller.runCommand(
148
+ (flowHandleId) => ({ kind: "open", flowHandleId }),
149
+ async (payload) => {
150
+ dispatched.push(payload);
151
+ throw new Error("boom");
152
+ },
153
+ ),
154
+ ).rejects.toThrow("boom");
155
+
156
+ expect(dispatched).toEqual([{ kind: "open", flowHandleId: undefined }]);
157
+ });
158
+
159
+ it("ignores handles from commands that settle after reset", async () => {
160
+ const dispatched: Array<{ flowHandleId?: string; kind: string }> = [];
161
+ let resolveSettlement:
162
+ | ((settlement: { result?: { flowHandleId?: string } }) => void)
163
+ | undefined;
164
+ const controller = createFlowCommandHandleController<
165
+ string,
166
+ { result?: { flowHandleId?: string } }
167
+ >({
168
+ getHandleIdFromSettlement: (settlement) =>
169
+ settlement.result?.flowHandleId,
170
+ isStaleHandleError: () => false,
171
+ });
172
+
173
+ const pendingCommand = controller.runCommand(
174
+ (flowHandleId) => ({ kind: "prefetch", flowHandleId }),
175
+ (payload) => {
176
+ dispatched.push(payload);
177
+ return new Promise((resolve) => {
178
+ resolveSettlement = resolve;
179
+ });
180
+ },
181
+ );
182
+ controller.reset();
183
+ resolveSettlement?.({ result: { flowHandleId: "handle_from_old_epoch" } });
184
+ await pendingCommand;
185
+ await controller.runCommand(
186
+ (flowHandleId) => ({ kind: "open", flowHandleId }),
187
+ async (payload) => {
188
+ dispatched.push(payload);
189
+ return { result: { flowHandleId: "handle_current" } };
190
+ },
191
+ );
192
+
193
+ expect(dispatched).toEqual([
194
+ { kind: "prefetch", flowHandleId: undefined },
195
+ { kind: "open", flowHandleId: undefined },
196
+ ]);
197
+ expect(controller.getHandleId()).toBe("handle_current");
198
+ });
199
+
200
+ it("does not retry stale failures from commands that fail after reset", async () => {
201
+ const dispatched: Array<{ flowHandleId?: string; kind: string }> = [];
202
+ let rejectSettlement: ((error: Error) => void) | undefined;
203
+ const controller = createFlowCommandHandleController<
204
+ string,
205
+ { result?: { flowHandleId?: string } }
206
+ >({
207
+ getHandleIdFromSettlement: (settlement) =>
208
+ settlement.result?.flowHandleId,
209
+ isStaleHandleError: (error) =>
210
+ error instanceof Error && error.message === "stale",
211
+ });
212
+
213
+ await controller.runCommand(
214
+ (flowHandleId) => ({ kind: "prefetch", flowHandleId }),
215
+ async (payload) => {
216
+ dispatched.push(payload);
217
+ return { result: { flowHandleId: "handle_before_reset" } };
218
+ },
219
+ );
220
+ const pendingCommand = controller.runCommand(
221
+ (flowHandleId) => ({ kind: "open", flowHandleId }),
222
+ (payload) => {
223
+ dispatched.push(payload);
224
+ return new Promise((_resolve, reject) => {
225
+ rejectSettlement = reject;
226
+ });
227
+ },
228
+ );
229
+ controller.reset();
230
+ rejectSettlement?.(new Error("stale"));
231
+
232
+ await expect(pendingCommand).rejects.toThrow("stale");
233
+ expect(dispatched).toEqual([
234
+ { kind: "prefetch", flowHandleId: undefined },
235
+ { kind: "open", flowHandleId: "handle_before_reset" },
236
+ ]);
237
+ expect(controller.getHandleId()).toBeUndefined();
238
+ });
239
+ });
@@ -0,0 +1,86 @@
1
+ import {
2
+ createLazyHandleClient,
3
+ type LazyHandleClient,
4
+ } from "./lazy-handle-client.js";
5
+
6
+ export type FlowCommandHandleController<
7
+ THandleId extends string,
8
+ TSettlement,
9
+ > = {
10
+ runCommand<TPayload>(
11
+ buildPayload: (handleId: THandleId | undefined) => TPayload,
12
+ dispatchAndWait: (payload: TPayload) => Promise<TSettlement>,
13
+ ): Promise<TSettlement>;
14
+ getHandleId(): THandleId | undefined;
15
+ hasHandleId(handleId: string): boolean;
16
+ hasPendingCommands(): boolean;
17
+ subscribeHandle(subscriber: (handleId: THandleId) => void): () => void;
18
+ clearResolvedHandle(): THandleId | undefined;
19
+ reset(): void;
20
+ };
21
+
22
+ export type CreateFlowCommandHandleControllerOptions<
23
+ THandleId extends string,
24
+ TSettlement,
25
+ > = {
26
+ getHandleIdFromSettlement: (settlement: TSettlement) => THandleId | undefined;
27
+ isStaleHandleError: (error: unknown) => boolean;
28
+ onClearResolvedHandle?: (handleId: THandleId) => void;
29
+ };
30
+
31
+ export function createFlowCommandHandleController<
32
+ THandleId extends string,
33
+ TSettlement,
34
+ >({
35
+ getHandleIdFromSettlement,
36
+ isStaleHandleError,
37
+ onClearResolvedHandle,
38
+ }: CreateFlowCommandHandleControllerOptions<
39
+ THandleId,
40
+ TSettlement
41
+ >): FlowCommandHandleController<THandleId, TSettlement> {
42
+ const handleClient: LazyHandleClient<THandleId, TSettlement> =
43
+ createLazyHandleClient<THandleId, TSettlement>({
44
+ getHandleIdFromSettlement,
45
+ });
46
+
47
+ const clearResolvedHandle = (): THandleId | undefined => {
48
+ const previousHandleId = handleClient.getHandleId();
49
+ if (!previousHandleId) {
50
+ return undefined;
51
+ }
52
+ handleClient.reset();
53
+ onClearResolvedHandle?.(previousHandleId);
54
+ return previousHandleId;
55
+ };
56
+
57
+ const reset = (): void => {
58
+ const previousHandleId = handleClient.getHandleId();
59
+ handleClient.reset();
60
+ if (previousHandleId) {
61
+ onClearResolvedHandle?.(previousHandleId);
62
+ }
63
+ };
64
+
65
+ const runCommand: FlowCommandHandleController<
66
+ THandleId,
67
+ TSettlement
68
+ >["runCommand"] = async (buildPayload, dispatchAndWait) => {
69
+ return handleClient.runCommandWithRetry(buildPayload, dispatchAndWait, {
70
+ shouldRetry: isStaleHandleError,
71
+ onBeforeRetry: () => {
72
+ clearResolvedHandle();
73
+ },
74
+ });
75
+ };
76
+
77
+ return {
78
+ runCommand,
79
+ getHandleId: () => handleClient.getHandleId(),
80
+ hasHandleId: (handleId) => handleClient.getHandleId() === handleId,
81
+ hasPendingCommands: () => handleClient.hasPendingCommands(),
82
+ subscribeHandle: (subscriber) => handleClient.subscribeHandle(subscriber),
83
+ clearResolvedHandle,
84
+ reset,
85
+ };
86
+ }
@@ -0,0 +1,30 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { commandSettledDetailSchema } from "./host-event-schemas";
3
+
4
+ describe("commandSettledDetailSchema", () => {
5
+ it("accepts instance feedback command settlements", () => {
6
+ for (const kind of [
7
+ "instanceFeedback.capture",
8
+ "instanceFeedback.listMine",
9
+ ] as const) {
10
+ expect(
11
+ commandSettledDetailSchema.safeParse({
12
+ instanceId: "instance_123",
13
+ kind,
14
+ ok: true,
15
+ requestId: "req_123",
16
+ result: { status: "accepted" },
17
+ }).success,
18
+ ).toBe(true);
19
+ expect(
20
+ commandSettledDetailSchema.safeParse({
21
+ error: { code: "INSTANCE_FEEDBACK_FAILED", message: "failed" },
22
+ instanceId: "instance_123",
23
+ kind,
24
+ ok: false,
25
+ requestId: "req_123",
26
+ }).success,
27
+ ).toBe(true);
28
+ }
29
+ });
30
+ });
package/src/host/index.ts CHANGED
@@ -7,6 +7,7 @@ export * from "./command-envelope.js";
7
7
  export * from "./command-settlement.js";
8
8
  export * from "./constants.js";
9
9
  export * from "./external-id-argument-guards.js";
10
+ export * from "./flow-command-handle-controller.js";
10
11
  export * from "./host-event-contract.js";
11
12
  export * from "./lazy-handle-client.js";
12
13
  export { createCommandRequestId } from "./request-id.js";
@@ -23,7 +23,16 @@ export type LazyHandleClient<
23
23
  buildPayload: (handleId: THandleId | undefined) => TPayload,
24
24
  dispatchAndWait: (payload: TPayload) => Promise<TSettlement>,
25
25
  ): Promise<TSettlement>;
26
+ runCommandWithRetry<TPayload>(
27
+ buildPayload: (handleId: THandleId | undefined) => TPayload,
28
+ dispatchAndWait: (payload: TPayload) => Promise<TSettlement>,
29
+ options: {
30
+ shouldRetry: (error: unknown) => boolean;
31
+ onBeforeRetry?: (error: unknown) => void;
32
+ },
33
+ ): Promise<TSettlement>;
26
34
  getHandleId(): THandleId | undefined;
35
+ hasPendingCommands(): boolean;
27
36
  subscribeHandle(subscriber: Subscriber<THandleId>): () => void;
28
37
  getStage(): TStage;
29
38
  setStage(stage: TStage): void;
@@ -141,9 +150,60 @@ const createLazyHandleClientWithStages = <
141
150
  return run;
142
151
  };
143
152
 
153
+ const runCommandWithRetry: LazyHandleClient<
154
+ THandleId,
155
+ TSettlement,
156
+ TStage
157
+ >["runCommandWithRetry"] = (buildPayload, dispatchAndWait, options) => {
158
+ const execute = async (): Promise<TSettlement> => {
159
+ let didRetry = false;
160
+ for (;;) {
161
+ if (stage === stages.invalidated) {
162
+ throw new Error("Handle client is invalidated");
163
+ }
164
+ const commandEpoch = epoch;
165
+ const payload = buildPayload(handleId);
166
+ try {
167
+ const settlement = await dispatchAndWait(payload);
168
+ const settledHandleId = input.getHandleIdFromSettlement(settlement);
169
+ if (settledHandleId && commandEpoch === epoch) {
170
+ publishHandle(settledHandleId);
171
+ }
172
+ return settlement;
173
+ } catch (error) {
174
+ if (
175
+ commandEpoch === epoch &&
176
+ !didRetry &&
177
+ options.shouldRetry(error)
178
+ ) {
179
+ didRetry = true;
180
+ options.onBeforeRetry?.(error);
181
+ continue;
182
+ }
183
+ throw error;
184
+ }
185
+ }
186
+ };
187
+
188
+ const run =
189
+ queuedCommandCount === 0 ? execute() : tail.then(execute, execute);
190
+ queuedCommandCount += 1;
191
+ tail = run.then(
192
+ () => {
193
+ queuedCommandCount -= 1;
194
+ },
195
+ () => {
196
+ queuedCommandCount -= 1;
197
+ },
198
+ );
199
+ return run;
200
+ };
201
+
144
202
  return {
145
203
  runCommand,
204
+ runCommandWithRetry,
146
205
  getHandleId: () => handleId,
206
+ hasPendingCommands: () => queuedCommandCount > 0,
147
207
  subscribeHandle: (subscriber) => {
148
208
  subscribers.add(subscriber);
149
209
  if (handleId) {
package/src/host/sdk.ts CHANGED
@@ -11,6 +11,8 @@ export {
11
11
  toCommandSettlementError,
12
12
  waitForCommandSettlement,
13
13
  } from "./command-settlement.js";
14
+ export type { FlowCommandHandleController } from "./flow-command-handle-controller.js";
15
+ export { createFlowCommandHandleController } from "./flow-command-handle-controller.js";
14
16
  export type {
15
17
  FlowHandleFromSettlement,
16
18
  FlowState,