@getuserfeedback/protocol 1.5.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import { describe, expect, it } from "bun:test";
2
2
  import type { FlowDismissedPayload, FlowViewedPayload } from "./host";
3
3
  import { createCommandEnvelope } from "./host";
4
+ import { commandEnvelopeWithInstanceIdSchema } from "./host/command-envelope-schema.js";
4
5
  import type { WebViewTransportWebMessage } from "./index";
5
6
  import {
6
7
  appEventCapabilitySchema,
@@ -225,6 +226,30 @@ describe("@getuserfeedback/protocol root contract", () => {
225
226
  );
226
227
  });
227
228
 
229
+ it("parses public open commands with response metadata from the root contract", () => {
230
+ const result = parsePublicCommand({
231
+ kind: "open",
232
+ flowId: "sur_123",
233
+ metadata: {
234
+ tags: {
235
+ campaign: "spring-sale",
236
+ segments: ["beta", "enterprise"],
237
+ },
238
+ },
239
+ });
240
+
241
+ expect(result).toEqual({
242
+ kind: "open",
243
+ flowId: "sur_123",
244
+ metadata: {
245
+ tags: {
246
+ campaign: "spring-sale",
247
+ segments: ["beta", "enterprise"],
248
+ },
249
+ },
250
+ });
251
+ });
252
+
228
253
  it("strips legacy open.containerRequirement for enum values any and hostOnly", () => {
229
254
  for (const containerRequirement of ["any", "hostOnly"] as const) {
230
255
  const result = parsePublicCommand({
@@ -338,6 +363,44 @@ describe("@getuserfeedback/protocol root contract", () => {
338
363
  expect("instanceId" in envelope).toBe(false);
339
364
  });
340
365
 
366
+ it("parses public command envelopes with required instance ids", () => {
367
+ const result = commandEnvelopeWithInstanceIdSchema.safeParse({
368
+ version: "1",
369
+ instanceId: "instance_123",
370
+ requestId: "request_123",
371
+ idempotencyKey: "request_123",
372
+ command: {
373
+ kind: "init",
374
+ opts: {
375
+ apiKey: "key_test",
376
+ runtimeEndpoints: {
377
+ coreUrl: "https://cdn.example.com/core.html",
378
+ apiUrl: "https://api.example.com/v1",
379
+ },
380
+ },
381
+ },
382
+ });
383
+
384
+ expect(result.success).toBe(true);
385
+ if (result.success) {
386
+ expect(result.data.instanceId).toBe("instance_123");
387
+ expect(result.data.command.kind).toBe("init");
388
+ }
389
+ });
390
+
391
+ it("rejects public command envelopes without instance ids", () => {
392
+ const result = commandEnvelopeWithInstanceIdSchema.safeParse({
393
+ version: "1",
394
+ requestId: "request_123",
395
+ idempotencyKey: "request_123",
396
+ command: {
397
+ kind: "reset",
398
+ },
399
+ });
400
+
401
+ expect(result.success).toBe(false);
402
+ });
403
+
341
404
  it("rejects internal navigation context commands from the public contract", () => {
342
405
  expect(() =>
343
406
  parsePublicCommand({
@@ -0,0 +1,10 @@
1
+ import * as z from "zod/mini";
2
+
3
+ const responseMetadataTagValueSchema = z.union([
4
+ z.string(),
5
+ z.array(z.string()),
6
+ ]);
7
+
8
+ export const responseMetadataInputSchema = z.strictObject({
9
+ tags: z.optional(z.record(z.string(), responseMetadataTagValueSchema)),
10
+ });
@@ -3,6 +3,7 @@ import {
3
3
  appEventCustomerTrackSchema,
4
4
  appEventExternalIdSchema,
5
5
  } from "./app-event.js";
6
+ import { responseMetadataInputSchema } from "./response-metadata.js";
6
7
  import {
7
8
  type ConfigureOptions,
8
9
  configureOptionsSchema,
@@ -108,6 +109,7 @@ const openPublicPayloadSchema = z.pipe(
108
109
  flowId: flowIdSchema,
109
110
  flowHandleId: z.optional(flowHandleIdSchema),
110
111
  container: z.optional(htmlElementOrNullSchema),
112
+ metadata: z.optional(responseMetadataInputSchema),
111
113
  /** Accepted for legacy browser SDK payloads; stripped before dispatch. */
112
114
  containerRequirement: z.optional(legacyOpenContainerRequirementSchema),
113
115
  hideCloseButton: z.optional(z.boolean()),