@getuserfeedback/protocol 3.0.2 → 3.0.4

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.
@@ -12,19 +12,19 @@ export declare const telemetryConfigInputSchema: z.ZodMiniObject<{
12
12
  }, z.core.$strip>;
13
13
  export type TelemetryConfigInput = z.output<typeof telemetryConfigInputSchema>;
14
14
  export declare const consentConfigInputSchema: z.ZodMiniUnion<readonly [z.ZodMiniEnum<{
15
- pending: "pending";
16
15
  granted: "granted";
17
16
  denied: "denied";
17
+ pending: "pending";
18
18
  revoked: "revoked";
19
19
  }>, z.ZodMiniArray<z.ZodMiniEnum<{
20
+ "functionality.storage": "functionality.storage";
21
+ "security.storage": "security.storage";
20
22
  "analytics.storage": "analytics.storage";
21
23
  "analytics.measurement": "analytics.measurement";
22
24
  "personalization.storage": "personalization.storage";
23
25
  "ads.storage": "ads.storage";
24
26
  "ads.user_data": "ads.user_data";
25
27
  "ads.personalization": "ads.personalization";
26
- "functionality.storage": "functionality.storage";
27
- "security.storage": "security.storage";
28
28
  }>>]>;
29
29
  export type ConsentConfigInput = z.output<typeof consentConfigInputSchema>;
30
30
  export declare const debugInputSchema: z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>;
@@ -149,19 +149,19 @@ export declare const configureOptionsSchema: z.ZodMiniObject<{
149
149
  dark: "dark";
150
150
  }>]>>;
151
151
  consent: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniEnum<{
152
- pending: "pending";
153
152
  granted: "granted";
154
153
  denied: "denied";
154
+ pending: "pending";
155
155
  revoked: "revoked";
156
156
  }>, z.ZodMiniArray<z.ZodMiniEnum<{
157
+ "functionality.storage": "functionality.storage";
158
+ "security.storage": "security.storage";
157
159
  "analytics.storage": "analytics.storage";
158
160
  "analytics.measurement": "analytics.measurement";
159
161
  "personalization.storage": "personalization.storage";
160
162
  "ads.storage": "ads.storage";
161
163
  "ads.user_data": "ads.user_data";
162
164
  "ads.personalization": "ads.personalization";
163
- "functionality.storage": "functionality.storage";
164
- "security.storage": "security.storage";
165
165
  }>>]>>;
166
166
  auth: z.ZodMiniOptional<z.ZodMiniObject<{
167
167
  jwt: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniObject<{
@@ -191,19 +191,19 @@ export declare const initOptionsSchema: z.ZodMiniObject<{
191
191
  disableTelemetry: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
192
192
  enableDebug: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
193
193
  defaultConsent: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniEnum<{
194
- pending: "pending";
195
194
  granted: "granted";
196
195
  denied: "denied";
196
+ pending: "pending";
197
197
  revoked: "revoked";
198
198
  }>, z.ZodMiniArray<z.ZodMiniEnum<{
199
+ "functionality.storage": "functionality.storage";
200
+ "security.storage": "security.storage";
199
201
  "analytics.storage": "analytics.storage";
200
202
  "analytics.measurement": "analytics.measurement";
201
203
  "personalization.storage": "personalization.storage";
202
204
  "ads.storage": "ads.storage";
203
205
  "ads.user_data": "ads.user_data";
204
206
  "ads.personalization": "ads.personalization";
205
- "functionality.storage": "functionality.storage";
206
- "security.storage": "security.storage";
207
207
  }>>]>>;
208
208
  clientMeta: z.ZodMiniOptional<z.ZodMiniObject<{
209
209
  loader: z.ZodMiniEnum<{
@@ -341,19 +341,19 @@ export declare const instanceUpdateableConfigSchema: z.ZodMiniObject<{
341
341
  dark: "dark";
342
342
  }>]>>;
343
343
  consent: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniEnum<{
344
- pending: "pending";
345
344
  granted: "granted";
346
345
  denied: "denied";
346
+ pending: "pending";
347
347
  revoked: "revoked";
348
348
  }>, z.ZodMiniArray<z.ZodMiniEnum<{
349
+ "functionality.storage": "functionality.storage";
350
+ "security.storage": "security.storage";
349
351
  "analytics.storage": "analytics.storage";
350
352
  "analytics.measurement": "analytics.measurement";
351
353
  "personalization.storage": "personalization.storage";
352
354
  "ads.storage": "ads.storage";
353
355
  "ads.user_data": "ads.user_data";
354
356
  "ads.personalization": "ads.personalization";
355
- "functionality.storage": "functionality.storage";
356
- "security.storage": "security.storage";
357
357
  }>>]>>;
358
358
  auth: z.ZodMiniOptional<z.ZodMiniObject<{
359
359
  jwt: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniObject<{
@@ -402,19 +402,19 @@ export declare const coreInstanceConfigSchema: z.ZodMiniObject<{
402
402
  disableTelemetry: z.ZodMiniDefault<z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>>;
403
403
  enableDebug: z.ZodMiniDefault<z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>>;
404
404
  consent: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniEnum<{
405
- pending: "pending";
406
405
  granted: "granted";
407
406
  denied: "denied";
407
+ pending: "pending";
408
408
  revoked: "revoked";
409
409
  }>, z.ZodMiniArray<z.ZodMiniEnum<{
410
+ "functionality.storage": "functionality.storage";
411
+ "security.storage": "security.storage";
410
412
  "analytics.storage": "analytics.storage";
411
413
  "analytics.measurement": "analytics.measurement";
412
414
  "personalization.storage": "personalization.storage";
413
415
  "ads.storage": "ads.storage";
414
416
  "ads.user_data": "ads.user_data";
415
417
  "ads.personalization": "ads.personalization";
416
- "functionality.storage": "functionality.storage";
417
- "security.storage": "security.storage";
418
418
  }>>]>>;
419
419
  auth: z.ZodMiniOptional<z.ZodMiniObject<{
420
420
  jwt: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniObject<{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/protocol",
3
- "version": "3.0.2",
3
+ "version": "3.0.4",
4
4
  "description": "getuserfeedback widget protocol — host surface and (later) wire protocol",
5
5
  "keywords": [
6
6
  "getuserfeedback",
@@ -0,0 +1,27 @@
1
+ import * as z from "zod/mini";
2
+ import { type ClientMeta, clientMetaSchema } from "./client-meta.js";
3
+ import { coreCommandPayloadSchema } from "./core-commands.js";
4
+
5
+ const requestIdSchema = z.string().check(z.trim(), z.minLength(1));
6
+ const idempotencyKeySchema = z.string().check(z.trim(), z.minLength(1));
7
+ const versionSchema = z.literal("1");
8
+
9
+ /** Loader -> core iframe command envelope (MessagePort transport). */
10
+ export const coreCommandEnvelopeSchema = z.object({
11
+ version: versionSchema,
12
+ instanceId: z.string().check(z.trim(), z.minLength(1)),
13
+ requestId: requestIdSchema,
14
+ idempotencyKey: idempotencyKeySchema,
15
+ clientMeta: z.optional(clientMetaSchema),
16
+ command: coreCommandPayloadSchema,
17
+ });
18
+
19
+ export type CoreCommandEnvelope = z.output<typeof coreCommandEnvelopeSchema>;
20
+
21
+ /** Context passed to core plugin handlers after envelope validation. */
22
+ export type CommandContext = {
23
+ instanceId: string;
24
+ requestId: string;
25
+ idempotencyKey: string;
26
+ clientMeta?: ClientMeta;
27
+ };
@@ -0,0 +1,164 @@
1
+ import * as z from "zod/mini";
2
+ import {
3
+ appEventCustomerTrackSchema,
4
+ appEventExternalIdSchema,
5
+ appEventSystemTrackSchema,
6
+ } from "./app-event.js";
7
+ import { ErrorEventSchema } from "./errors.js";
8
+ import { responseMetadataInputSchema } from "./response-metadata.js";
9
+ import { configureOptionsSchema, initOptionsSchema } from "./widget-config.js";
10
+
11
+ const flowHandleIdSchema = z.string().check(z.trim(), z.minLength(1));
12
+ const flowIdSchema = z.string().check(z.trim(), z.minLength(1));
13
+
14
+ const identifyTraitsSchema = z.record(z.string(), z.unknown());
15
+ const identifyOptionsSchema = z.strictObject({
16
+ externalIds: z.optional(
17
+ z.array(appEventExternalIdSchema).check(z.maxLength(20)),
18
+ ),
19
+ });
20
+
21
+ const identifyPayloadSchema = z.union([
22
+ z.strictObject({
23
+ kind: z.literal("identify"),
24
+ traits: identifyTraitsSchema,
25
+ options: z.optional(identifyOptionsSchema),
26
+ }),
27
+ z.strictObject({
28
+ kind: z.literal("identify"),
29
+ userId: z.string().check(z.trim(), z.minLength(1)),
30
+ traits: z.optional(identifyTraitsSchema),
31
+ options: z.optional(identifyOptionsSchema),
32
+ }),
33
+ ]);
34
+
35
+ const legacySystemTrackPayloadSchema = z.pipe(
36
+ z.extend(appEventSystemTrackSchema, {
37
+ kind: z.literal("track"),
38
+ origin: z.optional(z.literal("system")),
39
+ }),
40
+ z.transform(({ origin: _origin, ...rest }) => ({
41
+ ...rest,
42
+ origin: "system" as const,
43
+ })),
44
+ );
45
+
46
+ const customerTrackPayloadSchema = z.extend(appEventCustomerTrackSchema, {
47
+ kind: z.literal("track"),
48
+ });
49
+
50
+ const trackPayloadSchema = z.union([
51
+ legacySystemTrackPayloadSchema,
52
+ customerTrackPayloadSchema,
53
+ ]);
54
+
55
+ const prefetchPayloadSchema = z.strictObject({
56
+ kind: z.literal("prefetch"),
57
+ flowId: flowIdSchema,
58
+ flowHandleId: z.optional(flowHandleIdSchema),
59
+ });
60
+
61
+ const openCorePayloadSchema = z.strictObject({
62
+ kind: z.literal("open"),
63
+ flowId: flowIdSchema,
64
+ flowHandleId: z.optional(flowHandleIdSchema),
65
+ metadata: z.optional(responseMetadataInputSchema),
66
+ hideCloseButton: z.optional(z.boolean()),
67
+ });
68
+
69
+ const prerenderCorePayloadSchema = z.strictObject({
70
+ kind: z.literal("prerender"),
71
+ flowId: flowIdSchema,
72
+ flowHandleId: z.optional(flowHandleIdSchema),
73
+ hideCloseButton: z.optional(z.boolean()),
74
+ });
75
+
76
+ const closeCorePayloadSchema = z.object({
77
+ kind: z.literal("close"),
78
+ flowHandleId: z.optional(flowHandleIdSchema),
79
+ reasonCode: z.optional(z.enum(["CLOSED", "RESET"])),
80
+ });
81
+
82
+ const hostContextUpdatedPayloadSchema = z.object({
83
+ kind: z.literal("hostContextUpdated"),
84
+ context: z.object({
85
+ url: z.string().check(z.url()),
86
+ env: z.optional(z.record(z.string(), z.string())),
87
+ storage: z.optional(z.record(z.string(), z.string())),
88
+ page: z.optional(
89
+ z.object({
90
+ path: z.optional(z.string()),
91
+ referrer: z.optional(z.string()),
92
+ search: z.optional(z.string()),
93
+ }),
94
+ ),
95
+ }),
96
+ });
97
+
98
+ const hostSignalPayloadSchema = z.object({
99
+ kind: z.literal("hostSignal"),
100
+ name: z.string(),
101
+ data: z.optional(z.unknown()),
102
+ });
103
+
104
+ const setTargetingPlanPayloadSchema = z.object({
105
+ kind: z.literal("setTargetingPlan"),
106
+ plan: z.object({
107
+ strategy: z.optional(z.enum(["firstMatch"])),
108
+ candidates: z.array(
109
+ z.object({
110
+ action: z.enum(["open", "prefetch"]),
111
+ flowId: flowIdSchema,
112
+ rules: z.array(z.unknown()),
113
+ }),
114
+ ),
115
+ }),
116
+ });
117
+
118
+ const telemetryPayloadSchema = z.object({
119
+ kind: z.literal("telemetry"),
120
+ name: z.string(),
121
+ props: z.optional(z.record(z.string(), z.unknown())),
122
+ });
123
+
124
+ const errorPayloadSchema = z.object({
125
+ kind: z.literal("error"),
126
+ event: ErrorEventSchema,
127
+ });
128
+
129
+ const configureCorePayloadSchema = z.object({
130
+ kind: z.literal("configure"),
131
+ opts: configureOptionsSchema,
132
+ });
133
+
134
+ const initCorePayloadSchema = z.strictObject({
135
+ kind: z.literal("init"),
136
+ opts: initOptionsSchema,
137
+ });
138
+
139
+ const resetPayloadSchema = z.object({
140
+ kind: z.literal("reset"),
141
+ });
142
+
143
+ const coreCommandPayloadWithoutIdentifySchema = z.discriminatedUnion("kind", [
144
+ openCorePayloadSchema,
145
+ prefetchPayloadSchema,
146
+ prerenderCorePayloadSchema,
147
+ hostContextUpdatedPayloadSchema,
148
+ hostSignalPayloadSchema,
149
+ setTargetingPlanPayloadSchema,
150
+ telemetryPayloadSchema,
151
+ configureCorePayloadSchema,
152
+ initCorePayloadSchema,
153
+ closeCorePayloadSchema,
154
+ resetPayloadSchema,
155
+ errorPayloadSchema,
156
+ ]);
157
+
158
+ export const coreCommandPayloadSchema = z.union([
159
+ coreCommandPayloadWithoutIdentifySchema,
160
+ identifyPayloadSchema,
161
+ trackPayloadSchema,
162
+ ]);
163
+
164
+ export type CoreCommandPayload = z.output<typeof coreCommandPayloadSchema>;
@@ -103,6 +103,82 @@ describe("flow display sync contracts", () => {
103
103
  });
104
104
  });
105
105
 
106
+ it("accepts runtime broadcast attention policy metadata", () => {
107
+ const result = flowDisplaySyncResponseSchema.parse({
108
+ fetchedAt: "2026-06-18T00:00:00.000Z",
109
+ assignments: {
110
+ claimed: [],
111
+ },
112
+ broadcasts: {
113
+ version: "broadcasts_1",
114
+ opportunities: [
115
+ {
116
+ opportunityId: "rtb_daver_1",
117
+ flowId: "sur_1",
118
+ flowVersionId: "flv_1",
119
+ source: {
120
+ kind: "runtime_broadcast",
121
+ },
122
+ runtimeEligibility: {
123
+ requiredCapabilities: [],
124
+ },
125
+ attentionPolicy: {
126
+ priority: "high",
127
+ attentionMode: "concurrent",
128
+ cooldown: {
129
+ key: "automation:dauto_1",
130
+ afterDisplayMs: 60_000,
131
+ },
132
+ },
133
+ },
134
+ ],
135
+ },
136
+ });
137
+
138
+ expect(result.broadcasts.opportunities[0]?.attentionPolicy).toEqual({
139
+ priority: "high",
140
+ attentionMode: "concurrent",
141
+ cooldown: {
142
+ key: "automation:dauto_1",
143
+ afterDisplayMs: 60_000,
144
+ },
145
+ });
146
+ });
147
+
148
+ it("rejects invalid runtime broadcast attention policy metadata", () => {
149
+ expect(() =>
150
+ flowDisplaySyncResponseSchema.parse({
151
+ fetchedAt: "2026-06-18T00:00:00.000Z",
152
+ assignments: {
153
+ claimed: [],
154
+ },
155
+ broadcasts: {
156
+ version: "broadcasts_1",
157
+ opportunities: [
158
+ {
159
+ opportunityId: "rtb_daver_1",
160
+ flowId: "sur_1",
161
+ flowVersionId: "flv_1",
162
+ source: {
163
+ kind: "runtime_broadcast",
164
+ },
165
+ runtimeEligibility: {
166
+ requiredCapabilities: [],
167
+ },
168
+ attentionPolicy: {
169
+ priority: "urgent",
170
+ cooldown: {
171
+ key: "automation:dauto_1",
172
+ afterDisplayMs: -1,
173
+ },
174
+ },
175
+ },
176
+ ],
177
+ },
178
+ }),
179
+ ).toThrow();
180
+ });
181
+
106
182
  it("defaults legacy runtime broadcast opportunities to an immediate runtime trigger", () => {
107
183
  const result = flowDisplaySyncResponseSchema.parse({
108
184
  fetchedAt: "2026-06-18T00:00:00.000Z",
@@ -33,6 +33,20 @@ const immediateRuntimeDisplayTrigger: z.output<
33
33
  kind: "immediate",
34
34
  };
35
35
 
36
+ export const runtimeDisplayAttentionPolicySchema = z.object({
37
+ priority: z.optional(z.enum(["critical", "high", "normal", "low"])),
38
+ attentionMode: z.optional(z.enum(["exclusive", "concurrent"])),
39
+ cooldown: z.optional(
40
+ z.union([
41
+ z.object({
42
+ key: z.string().check(z.trim(), z.minLength(1)),
43
+ afterDisplayMs: z.number().check(z.positive()),
44
+ }),
45
+ z.null(),
46
+ ]),
47
+ ),
48
+ });
49
+
36
50
  export const runtimeDisplayBroadcastOpportunitySchema = z.object({
37
51
  opportunityId: z.string().check(z.trim(), z.minLength(1)),
38
52
  flowId: z.string().check(z.trim(), z.minLength(1)),
@@ -47,6 +61,7 @@ export const runtimeDisplayBroadcastOpportunitySchema = z.object({
47
61
  runtimeDisplayTriggerSchema,
48
62
  immediateRuntimeDisplayTrigger,
49
63
  ),
64
+ attentionPolicy: z.optional(runtimeDisplayAttentionPolicySchema),
50
65
  });
51
66
 
52
67
  export const runtimeDisplayBroadcastsSchema = z.object({
@@ -79,6 +94,9 @@ export type RuntimeDisplayBroadcasts = z.output<
79
94
  export type RuntimeDisplayBroadcastOpportunity = z.output<
80
95
  typeof runtimeDisplayBroadcastOpportunitySchema
81
96
  >;
97
+ export type RuntimeDisplayAttentionPolicy = z.output<
98
+ typeof runtimeDisplayAttentionPolicySchema
99
+ >;
82
100
  export type RuntimeDisplayEligibility = z.output<
83
101
  typeof runtimeDisplayEligibilitySchema
84
102
  >;
package/src/index.ts CHANGED
@@ -26,6 +26,15 @@ export {
26
26
  type ClientMeta,
27
27
  clientMetaSchema,
28
28
  } from "./client-meta.js";
29
+ export {
30
+ type CommandContext,
31
+ type CoreCommandEnvelope,
32
+ coreCommandEnvelopeSchema,
33
+ } from "./core-command-envelope.js";
34
+ export {
35
+ type CoreCommandPayload,
36
+ coreCommandPayloadSchema,
37
+ } from "./core-commands.js";
29
38
  export { DEFAULT_AUTO_DETECT_COLOR_SCHEME_ATTRS } from "./defaults.js";
30
39
  export type { ErrorEvent, ProtocolErrorCode } from "./errors.js";
31
40
  export {
@@ -66,10 +75,12 @@ export {
66
75
  type FlowDisplaySyncResponse,
67
76
  flowDisplaySyncRequestSchema,
68
77
  flowDisplaySyncResponseSchema,
78
+ type RuntimeDisplayAttentionPolicy,
69
79
  type RuntimeDisplayBroadcastOpportunity,
70
80
  type RuntimeDisplayBroadcasts,
71
81
  type RuntimeDisplayEligibility,
72
82
  type RuntimeDisplayTrigger,
83
+ runtimeDisplayAttentionPolicySchema,
73
84
  runtimeDisplayBroadcastOpportunitySchema,
74
85
  runtimeDisplayBroadcastsSchema,
75
86
  runtimeDisplayEligibilitySchema,