@getuserfeedback/protocol 0.8.0 → 0.9.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.
- package/dist/host/external-id-argument-guards.d.ts +13 -2
- package/dist/host/external-id-argument-guards.d.ts.map +1 -1
- package/dist/host/external-id-argument-guards.js +24 -9
- package/dist/host/sdk-types.d.ts +25 -2
- package/dist/host/sdk-types.d.ts.map +1 -1
- package/dist/version-resolution.d.ts +1 -0
- package/dist/version-resolution.d.ts.map +1 -1
- package/dist/version-resolution.js +1 -0
- package/package.json +1 -1
- package/src/host/external-id-argument-guards.test.ts +57 -0
- package/src/host/external-id-argument-guards.ts +49 -10
- package/src/host/sdk-types.ts +25 -2
- package/src/protocol-root.test.ts +12 -0
- package/src/version-resolution.ts +1 -0
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
type ExternalIdArgumentCommandName = "identify" | "track";
|
|
2
2
|
type ExternalIdArgumentValueName = "traits" | "properties";
|
|
3
|
-
|
|
3
|
+
type ExternalIdsCallShape = "identify(userId, traits, { externalIds })" | "identify(traits, { externalIds })" | "track(eventName, properties, { externalIds })";
|
|
4
|
+
export declare const assertNoSegmentExternalIdsInValueArgument: ({ argument, commandName, valueArgumentName, callShape, }: {
|
|
4
5
|
argument: unknown;
|
|
5
|
-
options: unknown;
|
|
6
6
|
commandName: ExternalIdArgumentCommandName;
|
|
7
7
|
valueArgumentName: ExternalIdArgumentValueName;
|
|
8
|
+
callShape: ExternalIdsCallShape;
|
|
9
|
+
}) => void;
|
|
10
|
+
/**
|
|
11
|
+
* @deprecated Use `assertNoSegmentExternalIdsInValueArgument`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const assertNoAmbiguousExternalIdsArgument: ({ argument, options, commandName, valueArgumentName, callShape, }: {
|
|
14
|
+
argument: unknown;
|
|
15
|
+
options?: unknown;
|
|
16
|
+
commandName: ExternalIdArgumentCommandName;
|
|
17
|
+
valueArgumentName: ExternalIdArgumentValueName;
|
|
18
|
+
callShape?: ExternalIdsCallShape;
|
|
8
19
|
}) => void;
|
|
9
20
|
export {};
|
|
10
21
|
//# sourceMappingURL=external-id-argument-guards.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-id-argument-guards.d.ts","sourceRoot":"","sources":["../../src/host/external-id-argument-guards.ts"],"names":[],"mappings":"AAAA,KAAK,6BAA6B,GAAG,UAAU,GAAG,OAAO,CAAC;AAC1D,KAAK,2BAA2B,GAAG,QAAQ,GAAG,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"external-id-argument-guards.d.ts","sourceRoot":"","sources":["../../src/host/external-id-argument-guards.ts"],"names":[],"mappings":"AAAA,KAAK,6BAA6B,GAAG,UAAU,GAAG,OAAO,CAAC;AAC1D,KAAK,2BAA2B,GAAG,QAAQ,GAAG,YAAY,CAAC;AAC3D,KAAK,oBAAoB,GACtB,2CAA2C,GAC3C,mCAAmC,GACnC,+CAA+C,CAAC;AA4CnD,eAAO,MAAM,yCAAyC,GAAI,0DAKvD;IACF,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,6BAA6B,CAAC;IAC3C,iBAAiB,EAAE,2BAA2B,CAAC;IAC/C,SAAS,EAAE,oBAAoB,CAAC;CAChC,KAAG,IAQH,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oCAAoC,GAAI,mEAMlD;IACF,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,6BAA6B,CAAC;IAC3C,iBAAiB,EAAE,2BAA2B,CAAC;IAC/C,SAAS,CAAC,EAAE,oBAAoB,CAAC;CACjC,KAAG,IAWH,CAAC"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
const
|
|
1
|
+
const defaultCallShapeByCommand = {
|
|
2
|
+
identify: "identify(userId, traits, { externalIds })",
|
|
3
|
+
track: "track(eventName, properties, { externalIds })",
|
|
4
|
+
};
|
|
5
|
+
const hasSegmentExternalIdsProperty = (value) => {
|
|
2
6
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
3
7
|
return false;
|
|
4
8
|
}
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
return (entries.length === 1 &&
|
|
8
|
-
entries[0]?.[0] === "externalIds" &&
|
|
9
|
-
Array.isArray(externalIds) &&
|
|
9
|
+
const externalIds = Object.entries(value).find(([key]) => key === "externalIds")?.[1];
|
|
10
|
+
return (Array.isArray(externalIds) &&
|
|
10
11
|
externalIds.length > 0 &&
|
|
11
12
|
externalIds.every(isSegmentExternalIdLike));
|
|
12
13
|
};
|
|
@@ -19,9 +20,23 @@ const isSegmentExternalIdLike = (value) => {
|
|
|
19
20
|
Reflect.get(value, "collection") === "users" &&
|
|
20
21
|
Reflect.get(value, "encoding") === "none");
|
|
21
22
|
};
|
|
22
|
-
export const
|
|
23
|
-
if (
|
|
23
|
+
export const assertNoSegmentExternalIdsInValueArgument = ({ argument, commandName, valueArgumentName, callShape, }) => {
|
|
24
|
+
if (!hasSegmentExternalIdsProperty(argument)) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
throw new Error(`${commandName} received externalIds in the ${valueArgumentName} argument. Use ${callShape} instead.`);
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* @deprecated Use `assertNoSegmentExternalIdsInValueArgument`.
|
|
31
|
+
*/
|
|
32
|
+
export const assertNoAmbiguousExternalIdsArgument = ({ argument, options, commandName, valueArgumentName, callShape, }) => {
|
|
33
|
+
if (options !== undefined) {
|
|
24
34
|
return;
|
|
25
35
|
}
|
|
26
|
-
|
|
36
|
+
assertNoSegmentExternalIdsInValueArgument({
|
|
37
|
+
argument,
|
|
38
|
+
commandName,
|
|
39
|
+
valueArgumentName,
|
|
40
|
+
callShape: callShape ?? defaultCallShapeByCommand[commandName],
|
|
41
|
+
});
|
|
27
42
|
};
|
package/dist/host/sdk-types.d.ts
CHANGED
|
@@ -22,6 +22,9 @@ export type AppEventIdentity = {
|
|
|
22
22
|
* Segment-compatible external identifier.
|
|
23
23
|
*
|
|
24
24
|
* Only `collection: "users"` participates in person identity resolution today.
|
|
25
|
+
* External IDs help match profiles, but they are not traits by themselves.
|
|
26
|
+
*
|
|
27
|
+
* @see https://getuserfeedback.com/docs/guides/identity-resolution
|
|
25
28
|
*/
|
|
26
29
|
export type AppEventExternalId = {
|
|
27
30
|
id: string;
|
|
@@ -299,13 +302,13 @@ export type PrerenderCommandPayload = {
|
|
|
299
302
|
*/
|
|
300
303
|
hideCloseButton?: boolean | undefined;
|
|
301
304
|
};
|
|
302
|
-
/** Identify with traits only (`client.identify(traits)`). */
|
|
305
|
+
/** Identify with traits only (`client.identify(traits)` or `client.identify(traits, options)`). */
|
|
303
306
|
export type IdentifyTraitsOnlyCommandPayload = {
|
|
304
307
|
kind: "identify";
|
|
305
308
|
traits: Record<string, unknown>;
|
|
306
309
|
options?: IdentifyOptions | undefined;
|
|
307
310
|
};
|
|
308
|
-
/** Identify with userId and optional
|
|
311
|
+
/** Identify with userId, optional traits, and optional external IDs (`client.identify(userId, traits?, options?)`). */
|
|
309
312
|
export type IdentifyUserCommandPayload = {
|
|
310
313
|
kind: "identify";
|
|
311
314
|
userId: string;
|
|
@@ -314,9 +317,29 @@ export type IdentifyUserCommandPayload = {
|
|
|
314
317
|
};
|
|
315
318
|
/** Identify command payload: either traits-only or userId+traits shape. */
|
|
316
319
|
export type IdentifyCommandPayload = IdentifyTraitsOnlyCommandPayload | IdentifyUserCommandPayload;
|
|
320
|
+
/**
|
|
321
|
+
* Optional identity context accepted by `client.identify()`.
|
|
322
|
+
*
|
|
323
|
+
* Use `externalIds` for Segment-compatible identifiers from another system,
|
|
324
|
+
* such as Shopify customer IDs or Salesforce contact IDs. Without a user ID,
|
|
325
|
+
* pass options as `client.identify(traits, options)`, or use
|
|
326
|
+
* `client.identify(traits, undefined, options)` when your call site needs the
|
|
327
|
+
* explicit three-argument form. Do not put Segment-shaped `externalIds` in
|
|
328
|
+
* traits.
|
|
329
|
+
*
|
|
330
|
+
* @see https://getuserfeedback.com/docs/guides/identity-resolution
|
|
331
|
+
*/
|
|
317
332
|
export type IdentifyOptions = {
|
|
318
333
|
externalIds?: AppEventExternalId[] | undefined;
|
|
319
334
|
};
|
|
335
|
+
/**
|
|
336
|
+
* Optional context accepted by `client.track()`.
|
|
337
|
+
*
|
|
338
|
+
* Use `externalIds` when the event carries a Segment-compatible identifier
|
|
339
|
+
* from another system. Do not put Segment-shaped `externalIds` in properties.
|
|
340
|
+
*
|
|
341
|
+
* @see https://getuserfeedback.com/docs/reference/events
|
|
342
|
+
*/
|
|
320
343
|
export type TrackOptions = {
|
|
321
344
|
externalIds?: AppEventExternalId[] | undefined;
|
|
322
345
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk-types.d.ts","sourceRoot":"","sources":["../../src/host/sdk-types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAI1C;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAC7B,aAAa,GACb,QAAQ,GACR,cAAc,GACd,cAAc,GACd,mBAAmB,GACnB,8BAA8B,GAC9B,sBAAsB,CAAC;AAE1B,0FAA0F;AAC1F,MAAM,MAAM,gBAAgB,GAAG;IAC9B,IAAI,EAAE,oBAAoB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;CACd,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"sdk-types.d.ts","sourceRoot":"","sources":["../../src/host/sdk-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ export declare const flowVersionResolutionSchema: z.ZodMiniObject<{
|
|
|
3
3
|
flowVersionId: z.ZodMiniString<string>;
|
|
4
4
|
}, z.core.$strip>;
|
|
5
5
|
export declare const themeVersionResolutionSchema: z.ZodMiniObject<{
|
|
6
|
+
themeRuntimeArtifactId: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
6
7
|
themeVersionId: z.ZodMiniString<string>;
|
|
7
8
|
}, z.core.$strip>;
|
|
8
9
|
export type FlowVersionResolution = z.output<typeof flowVersionResolutionSchema>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-resolution.d.ts","sourceRoot":"","sources":["../src/version-resolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAI9B,eAAO,MAAM,2BAA2B;;iBAEtC,CAAC;AAEH,eAAO,MAAM,4BAA4B
|
|
1
|
+
{"version":3,"file":"version-resolution.d.ts","sourceRoot":"","sources":["../src/version-resolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAI9B,eAAO,MAAM,2BAA2B;;iBAEtC,CAAC;AAEH,eAAO,MAAM,4BAA4B;;;iBAGvC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAC3C,OAAO,2BAA2B,CAClC,CAAC;AACF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAC5C,OAAO,4BAA4B,CACnC,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
assertNoAmbiguousExternalIdsArgument,
|
|
5
|
+
assertNoSegmentExternalIdsInValueArgument,
|
|
6
|
+
} from "./external-id-argument-guards";
|
|
7
|
+
|
|
8
|
+
const segmentExternalIds = [
|
|
9
|
+
{
|
|
10
|
+
id: "gid://shopify/Customer/123",
|
|
11
|
+
type: "shopify_customer_id",
|
|
12
|
+
collection: "users" as const,
|
|
13
|
+
encoding: "none" as const,
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
describe("external ID argument guards", () => {
|
|
18
|
+
it("rejects own Segment-shaped externalIds in value arguments", () => {
|
|
19
|
+
expect(() =>
|
|
20
|
+
assertNoSegmentExternalIdsInValueArgument({
|
|
21
|
+
argument: { plan: "pro", externalIds: segmentExternalIds },
|
|
22
|
+
commandName: "identify",
|
|
23
|
+
valueArgumentName: "traits",
|
|
24
|
+
callShape: "identify(userId, traits, { externalIds })",
|
|
25
|
+
}),
|
|
26
|
+
).toThrow(
|
|
27
|
+
"identify received externalIds in the traits argument. Use identify(userId, traits, { externalIds }) instead.",
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("ignores inherited Segment-shaped externalIds", () => {
|
|
32
|
+
const argument = Object.create({
|
|
33
|
+
externalIds: segmentExternalIds,
|
|
34
|
+
}) as Record<string, unknown>;
|
|
35
|
+
argument.plan = "pro";
|
|
36
|
+
|
|
37
|
+
expect(() =>
|
|
38
|
+
assertNoSegmentExternalIdsInValueArgument({
|
|
39
|
+
argument,
|
|
40
|
+
commandName: "identify",
|
|
41
|
+
valueArgumentName: "traits",
|
|
42
|
+
callShape: "identify(userId, traits, { externalIds })",
|
|
43
|
+
}),
|
|
44
|
+
).not.toThrow();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("preserves deprecated ambiguous guard behavior when options are present", () => {
|
|
48
|
+
expect(() =>
|
|
49
|
+
assertNoAmbiguousExternalIdsArgument({
|
|
50
|
+
argument: { externalIds: segmentExternalIds },
|
|
51
|
+
options: {},
|
|
52
|
+
commandName: "identify",
|
|
53
|
+
valueArgumentName: "traits",
|
|
54
|
+
}),
|
|
55
|
+
).not.toThrow();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
type ExternalIdArgumentCommandName = "identify" | "track";
|
|
2
2
|
type ExternalIdArgumentValueName = "traits" | "properties";
|
|
3
|
+
type ExternalIdsCallShape =
|
|
4
|
+
| "identify(userId, traits, { externalIds })"
|
|
5
|
+
| "identify(traits, { externalIds })"
|
|
6
|
+
| "track(eventName, properties, { externalIds })";
|
|
3
7
|
|
|
4
|
-
const
|
|
8
|
+
const defaultCallShapeByCommand: Record<
|
|
9
|
+
ExternalIdArgumentCommandName,
|
|
10
|
+
ExternalIdsCallShape
|
|
11
|
+
> = {
|
|
12
|
+
identify: "identify(userId, traits, { externalIds })",
|
|
13
|
+
track: "track(eventName, properties, { externalIds })",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const hasSegmentExternalIdsProperty = (value: unknown): boolean => {
|
|
5
17
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
6
18
|
return false;
|
|
7
19
|
}
|
|
8
20
|
|
|
9
|
-
const
|
|
10
|
-
|
|
21
|
+
const externalIds = Object.entries(value).find(
|
|
22
|
+
([key]) => key === "externalIds",
|
|
23
|
+
)?.[1];
|
|
11
24
|
return (
|
|
12
|
-
entries.length === 1 &&
|
|
13
|
-
entries[0]?.[0] === "externalIds" &&
|
|
14
25
|
Array.isArray(externalIds) &&
|
|
15
26
|
externalIds.length > 0 &&
|
|
16
27
|
externalIds.every(isSegmentExternalIdLike)
|
|
@@ -36,22 +47,50 @@ const isSegmentExternalIdLike = (
|
|
|
36
47
|
);
|
|
37
48
|
};
|
|
38
49
|
|
|
39
|
-
export const
|
|
50
|
+
export const assertNoSegmentExternalIdsInValueArgument = ({
|
|
40
51
|
argument,
|
|
41
|
-
options,
|
|
42
52
|
commandName,
|
|
43
53
|
valueArgumentName,
|
|
54
|
+
callShape,
|
|
44
55
|
}: {
|
|
45
56
|
argument: unknown;
|
|
46
|
-
options: unknown;
|
|
47
57
|
commandName: ExternalIdArgumentCommandName;
|
|
48
58
|
valueArgumentName: ExternalIdArgumentValueName;
|
|
59
|
+
callShape: ExternalIdsCallShape;
|
|
49
60
|
}): void => {
|
|
50
|
-
if (
|
|
61
|
+
if (!hasSegmentExternalIdsProperty(argument)) {
|
|
51
62
|
return;
|
|
52
63
|
}
|
|
53
64
|
|
|
54
65
|
throw new Error(
|
|
55
|
-
`${commandName} received externalIds in the ${valueArgumentName} argument.
|
|
66
|
+
`${commandName} received externalIds in the ${valueArgumentName} argument. Use ${callShape} instead.`,
|
|
56
67
|
);
|
|
57
68
|
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @deprecated Use `assertNoSegmentExternalIdsInValueArgument`.
|
|
72
|
+
*/
|
|
73
|
+
export const assertNoAmbiguousExternalIdsArgument = ({
|
|
74
|
+
argument,
|
|
75
|
+
options,
|
|
76
|
+
commandName,
|
|
77
|
+
valueArgumentName,
|
|
78
|
+
callShape,
|
|
79
|
+
}: {
|
|
80
|
+
argument: unknown;
|
|
81
|
+
options?: unknown;
|
|
82
|
+
commandName: ExternalIdArgumentCommandName;
|
|
83
|
+
valueArgumentName: ExternalIdArgumentValueName;
|
|
84
|
+
callShape?: ExternalIdsCallShape;
|
|
85
|
+
}): void => {
|
|
86
|
+
if (options !== undefined) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
assertNoSegmentExternalIdsInValueArgument({
|
|
91
|
+
argument,
|
|
92
|
+
commandName,
|
|
93
|
+
valueArgumentName,
|
|
94
|
+
callShape: callShape ?? defaultCallShapeByCommand[commandName],
|
|
95
|
+
});
|
|
96
|
+
};
|
package/src/host/sdk-types.ts
CHANGED
|
@@ -35,6 +35,9 @@ export type AppEventIdentity = {
|
|
|
35
35
|
* Segment-compatible external identifier.
|
|
36
36
|
*
|
|
37
37
|
* Only `collection: "users"` participates in person identity resolution today.
|
|
38
|
+
* External IDs help match profiles, but they are not traits by themselves.
|
|
39
|
+
*
|
|
40
|
+
* @see https://getuserfeedback.com/docs/guides/identity-resolution
|
|
38
41
|
*/
|
|
39
42
|
export type AppEventExternalId = {
|
|
40
43
|
id: string;
|
|
@@ -379,14 +382,14 @@ export type PrerenderCommandPayload = {
|
|
|
379
382
|
hideCloseButton?: boolean | undefined;
|
|
380
383
|
};
|
|
381
384
|
|
|
382
|
-
/** Identify with traits only (`client.identify(traits)`). */
|
|
385
|
+
/** Identify with traits only (`client.identify(traits)` or `client.identify(traits, options)`). */
|
|
383
386
|
export type IdentifyTraitsOnlyCommandPayload = {
|
|
384
387
|
kind: "identify";
|
|
385
388
|
traits: Record<string, unknown>;
|
|
386
389
|
options?: IdentifyOptions | undefined;
|
|
387
390
|
};
|
|
388
391
|
|
|
389
|
-
/** Identify with userId and optional
|
|
392
|
+
/** Identify with userId, optional traits, and optional external IDs (`client.identify(userId, traits?, options?)`). */
|
|
390
393
|
export type IdentifyUserCommandPayload = {
|
|
391
394
|
kind: "identify";
|
|
392
395
|
userId: string;
|
|
@@ -399,10 +402,30 @@ export type IdentifyCommandPayload =
|
|
|
399
402
|
| IdentifyTraitsOnlyCommandPayload
|
|
400
403
|
| IdentifyUserCommandPayload;
|
|
401
404
|
|
|
405
|
+
/**
|
|
406
|
+
* Optional identity context accepted by `client.identify()`.
|
|
407
|
+
*
|
|
408
|
+
* Use `externalIds` for Segment-compatible identifiers from another system,
|
|
409
|
+
* such as Shopify customer IDs or Salesforce contact IDs. Without a user ID,
|
|
410
|
+
* pass options as `client.identify(traits, options)`, or use
|
|
411
|
+
* `client.identify(traits, undefined, options)` when your call site needs the
|
|
412
|
+
* explicit three-argument form. Do not put Segment-shaped `externalIds` in
|
|
413
|
+
* traits.
|
|
414
|
+
*
|
|
415
|
+
* @see https://getuserfeedback.com/docs/guides/identity-resolution
|
|
416
|
+
*/
|
|
402
417
|
export type IdentifyOptions = {
|
|
403
418
|
externalIds?: AppEventExternalId[] | undefined;
|
|
404
419
|
};
|
|
405
420
|
|
|
421
|
+
/**
|
|
422
|
+
* Optional context accepted by `client.track()`.
|
|
423
|
+
*
|
|
424
|
+
* Use `externalIds` when the event carries a Segment-compatible identifier
|
|
425
|
+
* from another system. Do not put Segment-shaped `externalIds` in properties.
|
|
426
|
+
*
|
|
427
|
+
* @see https://getuserfeedback.com/docs/reference/events
|
|
428
|
+
*/
|
|
406
429
|
export type TrackOptions = {
|
|
407
430
|
externalIds?: AppEventExternalId[] | undefined;
|
|
408
431
|
};
|
|
@@ -161,6 +161,18 @@ describe("@getuserfeedback/protocol root contract", () => {
|
|
|
161
161
|
});
|
|
162
162
|
});
|
|
163
163
|
|
|
164
|
+
it("parses theme resolution payloads with optional runtime artifacts", () => {
|
|
165
|
+
expect(
|
|
166
|
+
themeVersionResolutionSchema.parse({
|
|
167
|
+
themeRuntimeArtifactId: "thra_xyz",
|
|
168
|
+
themeVersionId: "tv_xyz",
|
|
169
|
+
}),
|
|
170
|
+
).toEqual({
|
|
171
|
+
themeRuntimeArtifactId: "thra_xyz",
|
|
172
|
+
themeVersionId: "tv_xyz",
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
164
176
|
it("exposes public widget command kind validation aligned with public payloads", () => {
|
|
165
177
|
expect(publicWidgetCommandKindSchema.safeParse("open").success).toBe(true);
|
|
166
178
|
expect(publicWidgetCommandKindSchema.safeParse("telemetry").success).toBe(
|