@canonmsg/backend-contracts 0.2.4 → 1.1.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.
- package/dist/cjs/contactRequest.js +16 -5
- package/dist/cjs/message.js +24 -19
- package/dist/cjs/turnProtocol.js +5 -6
- package/dist/contactRequest.d.ts +2 -2
- package/dist/contactRequest.js +16 -5
- package/dist/message.d.ts +2 -2
- package/dist/message.js +25 -20
- package/dist/turnProtocol.d.ts +0 -4
- package/dist/turnProtocol.js +5 -6
- package/package.json +1 -1
|
@@ -33,6 +33,19 @@ function serializeContactRequest(requestId, data) {
|
|
|
33
33
|
if (typeof data.targetId !== 'string' || data.targetId.length === 0) {
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
|
+
if (typeof data.targetName !== 'string' || data.targetName.trim().length === 0) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
if (data.targetAvatarUrl !== null && data.targetAvatarUrl !== undefined && typeof data.targetAvatarUrl !== 'string') {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (data.targetUserType !== 'human' && data.targetUserType !== 'ai_agent') {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
if (data.targetUserType === 'ai_agent'
|
|
46
|
+
&& (typeof data.targetOwnerId !== 'string' || data.targetOwnerId.length === 0)) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
36
49
|
const kindValue = typeof data.kind === 'string' ? data.kind : null;
|
|
37
50
|
if (kindValue !== 'dm' && kindValue !== 'group_invite') {
|
|
38
51
|
return null;
|
|
@@ -57,11 +70,9 @@ function serializeContactRequest(requestId, data) {
|
|
|
57
70
|
requesterName: typeof data.requesterName === 'string' ? data.requesterName : 'Unknown',
|
|
58
71
|
requesterAvatarUrl: typeof data.requesterAvatarUrl === 'string' ? data.requesterAvatarUrl : null,
|
|
59
72
|
targetId: data.targetId,
|
|
60
|
-
targetName:
|
|
73
|
+
targetName: data.targetName.trim(),
|
|
61
74
|
targetAvatarUrl: typeof data.targetAvatarUrl === 'string' ? data.targetAvatarUrl : null,
|
|
62
|
-
targetUserType: data.targetUserType
|
|
63
|
-
? data.targetUserType
|
|
64
|
-
: null,
|
|
75
|
+
targetUserType: data.targetUserType,
|
|
65
76
|
approverId: data.approverId,
|
|
66
77
|
message: typeof data.message === 'string' ? data.message : null,
|
|
67
78
|
status: normalizeStatus(data.status),
|
|
@@ -73,7 +84,7 @@ function serializeContactRequest(requestId, data) {
|
|
|
73
84
|
if (groupContext) {
|
|
74
85
|
payload.groupContext = groupContext;
|
|
75
86
|
}
|
|
76
|
-
if (
|
|
87
|
+
if (data.targetUserType === 'ai_agent') {
|
|
77
88
|
payload.targetOwnerId = data.targetOwnerId;
|
|
78
89
|
}
|
|
79
90
|
return payload;
|
package/dist/cjs/message.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.serializeStoredMessage = serializeStoredMessage;
|
|
4
4
|
const media_js_1 = require("./media.js");
|
|
5
|
-
const MISSING_CREATED_AT_ISO = new Date(0).toISOString();
|
|
6
5
|
function isRecord(value) {
|
|
7
6
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
8
7
|
}
|
|
@@ -21,14 +20,17 @@ function normalizeTimestamp(value) {
|
|
|
21
20
|
}
|
|
22
21
|
return null;
|
|
23
22
|
}
|
|
24
|
-
function
|
|
25
|
-
const timestamp = normalizeTimestamp(value)
|
|
26
|
-
|
|
23
|
+
function requireCreatedAt(value) {
|
|
24
|
+
const timestamp = normalizeTimestamp(value);
|
|
25
|
+
if (!timestamp) {
|
|
26
|
+
throw new Error('Message is missing canonical createdAt');
|
|
27
|
+
}
|
|
28
|
+
return timestamp.toISOString();
|
|
27
29
|
}
|
|
28
|
-
function
|
|
29
|
-
if (value === '
|
|
30
|
-
return
|
|
31
|
-
|
|
30
|
+
function requireSenderType(value) {
|
|
31
|
+
if (value === 'human' || value === 'ai_agent')
|
|
32
|
+
return value;
|
|
33
|
+
throw new Error('Message is missing canonical senderType');
|
|
32
34
|
}
|
|
33
35
|
function normalizeAgentClientType(value) {
|
|
34
36
|
if (value === 'claude-code'
|
|
@@ -40,7 +42,7 @@ function normalizeAgentClientType(value) {
|
|
|
40
42
|
}
|
|
41
43
|
return undefined;
|
|
42
44
|
}
|
|
43
|
-
function normalizeContentType(value
|
|
45
|
+
function normalizeContentType(value) {
|
|
44
46
|
if (value === 'text'
|
|
45
47
|
|| value === 'image'
|
|
46
48
|
|| value === 'audio'
|
|
@@ -48,10 +50,7 @@ function normalizeContentType(value, attachments) {
|
|
|
48
50
|
|| value === 'contact_card') {
|
|
49
51
|
return value;
|
|
50
52
|
}
|
|
51
|
-
|
|
52
|
-
if (primary === 'image' || primary === 'audio' || primary === 'file')
|
|
53
|
-
return primary;
|
|
54
|
-
return 'text';
|
|
53
|
+
throw new Error('Message is missing canonical contentType');
|
|
55
54
|
}
|
|
56
55
|
function normalizeForwardedFrom(value) {
|
|
57
56
|
if (!isRecord(value))
|
|
@@ -96,22 +95,25 @@ function normalizeContactCard(value) {
|
|
|
96
95
|
}
|
|
97
96
|
function serializeStoredMessage(input) {
|
|
98
97
|
const { data } = input;
|
|
99
|
-
const attachments =
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
const attachments = data.attachments === undefined
|
|
99
|
+
? []
|
|
100
|
+
: (0, media_js_1.normalizeStoredAttachments)(data.attachments);
|
|
101
|
+
if (!attachments) {
|
|
102
|
+
throw new Error('Message has malformed attachments');
|
|
103
|
+
}
|
|
102
104
|
const result = {
|
|
103
105
|
id: input.id,
|
|
104
106
|
senderId: typeof data.senderId === 'string' ? data.senderId : '',
|
|
105
|
-
senderType:
|
|
107
|
+
senderType: requireSenderType(data.senderType),
|
|
106
108
|
isOwner: input.isOwner,
|
|
107
|
-
contentType: normalizeContentType(data.contentType
|
|
109
|
+
contentType: normalizeContentType(data.contentType),
|
|
108
110
|
text: typeof data.text === 'string' ? data.text : null,
|
|
109
111
|
attachments,
|
|
110
112
|
mentions: normalizeStringArray(data.mentions),
|
|
111
113
|
replyTo: typeof data.replyTo === 'string' ? data.replyTo : null,
|
|
112
114
|
replyToPosition: typeof data.replyToPosition === 'number' ? data.replyToPosition : null,
|
|
113
115
|
status: data.status === 'read' ? 'read' : 'sent',
|
|
114
|
-
createdAt:
|
|
116
|
+
createdAt: requireCreatedAt(data.createdAt),
|
|
115
117
|
};
|
|
116
118
|
const forwardedFrom = normalizeForwardedFrom(data.forwardedFrom);
|
|
117
119
|
if (data.forwarded === true || forwardedFrom) {
|
|
@@ -130,5 +132,8 @@ function serializeStoredMessage(input) {
|
|
|
130
132
|
if (contactCard) {
|
|
131
133
|
result.contactCard = contactCard;
|
|
132
134
|
}
|
|
135
|
+
if (isRecord(data.runtimeCard)) {
|
|
136
|
+
result.runtimeCard = data.runtimeCard;
|
|
137
|
+
}
|
|
133
138
|
return result;
|
|
134
139
|
}
|
package/dist/cjs/turnProtocol.js
CHANGED
|
@@ -22,7 +22,9 @@ function isHiddenRuntimeCardMetadata(metadata) {
|
|
|
22
22
|
|| metadata.type === 'question_reply'
|
|
23
23
|
|| metadata.type === 'plan_approval_reply'
|
|
24
24
|
|| metadata.type === 'runtime_input_reply'
|
|
25
|
-
|| metadata.type === 'runtime_input_outcome'
|
|
25
|
+
|| metadata.type === 'runtime_input_outcome'
|
|
26
|
+
|| metadata.type === 'runtime_card_reply'
|
|
27
|
+
|| metadata.type === 'runtime_card_outcome';
|
|
26
28
|
}
|
|
27
29
|
function normalizeTurnMetadata(metadata) {
|
|
28
30
|
if (!isRecord(metadata))
|
|
@@ -36,12 +38,11 @@ function normalizeTurnMetadata(metadata) {
|
|
|
36
38
|
|| metadata.replyBehavior === 'suppress_auto_reply'
|
|
37
39
|
? metadata.replyBehavior
|
|
38
40
|
: undefined;
|
|
39
|
-
if (!turnSemantics &&
|
|
41
|
+
if (!turnSemantics && !replyBehavior) {
|
|
40
42
|
return null;
|
|
41
43
|
}
|
|
42
44
|
return {
|
|
43
45
|
...(turnSemantics ? { turnSemantics } : {}),
|
|
44
|
-
...(typeof metadata.turnComplete === 'boolean' ? { turnComplete: metadata.turnComplete } : {}),
|
|
45
46
|
...(replyBehavior ? { replyBehavior } : {}),
|
|
46
47
|
};
|
|
47
48
|
}
|
|
@@ -80,11 +81,9 @@ function resolveTurnMessageSemantics(input) {
|
|
|
80
81
|
const turnMetadata = normalizeTurnMetadata(input.metadata);
|
|
81
82
|
if (turnMetadata?.turnSemantics)
|
|
82
83
|
return turnMetadata.turnSemantics;
|
|
83
|
-
if (turnMetadata?.turnComplete === true)
|
|
84
|
-
return 'turn_complete';
|
|
85
84
|
if (input.senderType === 'human')
|
|
86
85
|
return 'turn_complete';
|
|
87
|
-
return
|
|
86
|
+
return 'progress';
|
|
88
87
|
}
|
|
89
88
|
function shouldPromoteConversationMessage(input) {
|
|
90
89
|
if (isHiddenRuntimeCardMetadata(input.metadata)) {
|
package/dist/contactRequest.d.ts
CHANGED
|
@@ -5,9 +5,9 @@ export interface SerializedContactRequest {
|
|
|
5
5
|
requesterName: string;
|
|
6
6
|
requesterAvatarUrl: string | null;
|
|
7
7
|
targetId: string;
|
|
8
|
-
targetName: string
|
|
8
|
+
targetName: string;
|
|
9
9
|
targetAvatarUrl: string | null;
|
|
10
|
-
targetUserType: 'human' | 'ai_agent'
|
|
10
|
+
targetUserType: 'human' | 'ai_agent';
|
|
11
11
|
targetOwnerId?: string | null;
|
|
12
12
|
approverId: string;
|
|
13
13
|
message: string | null;
|
package/dist/contactRequest.js
CHANGED
|
@@ -30,6 +30,19 @@ export function serializeContactRequest(requestId, data) {
|
|
|
30
30
|
if (typeof data.targetId !== 'string' || data.targetId.length === 0) {
|
|
31
31
|
return null;
|
|
32
32
|
}
|
|
33
|
+
if (typeof data.targetName !== 'string' || data.targetName.trim().length === 0) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
if (data.targetAvatarUrl !== null && data.targetAvatarUrl !== undefined && typeof data.targetAvatarUrl !== 'string') {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
if (data.targetUserType !== 'human' && data.targetUserType !== 'ai_agent') {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (data.targetUserType === 'ai_agent'
|
|
43
|
+
&& (typeof data.targetOwnerId !== 'string' || data.targetOwnerId.length === 0)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
33
46
|
const kindValue = typeof data.kind === 'string' ? data.kind : null;
|
|
34
47
|
if (kindValue !== 'dm' && kindValue !== 'group_invite') {
|
|
35
48
|
return null;
|
|
@@ -54,11 +67,9 @@ export function serializeContactRequest(requestId, data) {
|
|
|
54
67
|
requesterName: typeof data.requesterName === 'string' ? data.requesterName : 'Unknown',
|
|
55
68
|
requesterAvatarUrl: typeof data.requesterAvatarUrl === 'string' ? data.requesterAvatarUrl : null,
|
|
56
69
|
targetId: data.targetId,
|
|
57
|
-
targetName:
|
|
70
|
+
targetName: data.targetName.trim(),
|
|
58
71
|
targetAvatarUrl: typeof data.targetAvatarUrl === 'string' ? data.targetAvatarUrl : null,
|
|
59
|
-
targetUserType: data.targetUserType
|
|
60
|
-
? data.targetUserType
|
|
61
|
-
: null,
|
|
72
|
+
targetUserType: data.targetUserType,
|
|
62
73
|
approverId: data.approverId,
|
|
63
74
|
message: typeof data.message === 'string' ? data.message : null,
|
|
64
75
|
status: normalizeStatus(data.status),
|
|
@@ -70,7 +81,7 @@ export function serializeContactRequest(requestId, data) {
|
|
|
70
81
|
if (groupContext) {
|
|
71
82
|
payload.groupContext = groupContext;
|
|
72
83
|
}
|
|
73
|
-
if (
|
|
84
|
+
if (data.targetUserType === 'ai_agent') {
|
|
74
85
|
payload.targetOwnerId = data.targetOwnerId;
|
|
75
86
|
}
|
|
76
87
|
return payload;
|
package/dist/message.d.ts
CHANGED
|
@@ -36,12 +36,12 @@ export interface SerializedMessage {
|
|
|
36
36
|
createdAt: string;
|
|
37
37
|
metadata?: Record<string, unknown>;
|
|
38
38
|
contactCard?: SerializedContactCard;
|
|
39
|
+
/** Durable canon.card.v1 runtime card content, passed through opaquely. */
|
|
40
|
+
runtimeCard?: Record<string, unknown>;
|
|
39
41
|
}
|
|
40
42
|
export interface SerializeMessageInput {
|
|
41
43
|
id: string;
|
|
42
44
|
data: Record<string, unknown>;
|
|
43
|
-
createdAtFallback?: unknown;
|
|
44
|
-
senderTypeFallback?: unknown;
|
|
45
45
|
senderName?: string;
|
|
46
46
|
isOwner: boolean;
|
|
47
47
|
}
|
package/dist/message.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const MISSING_CREATED_AT_ISO = new Date(0).toISOString();
|
|
1
|
+
import { normalizeStoredAttachments } from './media.js';
|
|
3
2
|
function isRecord(value) {
|
|
4
3
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
5
4
|
}
|
|
@@ -18,14 +17,17 @@ function normalizeTimestamp(value) {
|
|
|
18
17
|
}
|
|
19
18
|
return null;
|
|
20
19
|
}
|
|
21
|
-
function
|
|
22
|
-
const timestamp = normalizeTimestamp(value)
|
|
23
|
-
|
|
20
|
+
function requireCreatedAt(value) {
|
|
21
|
+
const timestamp = normalizeTimestamp(value);
|
|
22
|
+
if (!timestamp) {
|
|
23
|
+
throw new Error('Message is missing canonical createdAt');
|
|
24
|
+
}
|
|
25
|
+
return timestamp.toISOString();
|
|
24
26
|
}
|
|
25
|
-
function
|
|
26
|
-
if (value === '
|
|
27
|
-
return
|
|
28
|
-
|
|
27
|
+
function requireSenderType(value) {
|
|
28
|
+
if (value === 'human' || value === 'ai_agent')
|
|
29
|
+
return value;
|
|
30
|
+
throw new Error('Message is missing canonical senderType');
|
|
29
31
|
}
|
|
30
32
|
function normalizeAgentClientType(value) {
|
|
31
33
|
if (value === 'claude-code'
|
|
@@ -37,7 +39,7 @@ function normalizeAgentClientType(value) {
|
|
|
37
39
|
}
|
|
38
40
|
return undefined;
|
|
39
41
|
}
|
|
40
|
-
function normalizeContentType(value
|
|
42
|
+
function normalizeContentType(value) {
|
|
41
43
|
if (value === 'text'
|
|
42
44
|
|| value === 'image'
|
|
43
45
|
|| value === 'audio'
|
|
@@ -45,10 +47,7 @@ function normalizeContentType(value, attachments) {
|
|
|
45
47
|
|| value === 'contact_card') {
|
|
46
48
|
return value;
|
|
47
49
|
}
|
|
48
|
-
|
|
49
|
-
if (primary === 'image' || primary === 'audio' || primary === 'file')
|
|
50
|
-
return primary;
|
|
51
|
-
return 'text';
|
|
50
|
+
throw new Error('Message is missing canonical contentType');
|
|
52
51
|
}
|
|
53
52
|
function normalizeForwardedFrom(value) {
|
|
54
53
|
if (!isRecord(value))
|
|
@@ -93,22 +92,25 @@ function normalizeContactCard(value) {
|
|
|
93
92
|
}
|
|
94
93
|
export function serializeStoredMessage(input) {
|
|
95
94
|
const { data } = input;
|
|
96
|
-
const attachments =
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
const attachments = data.attachments === undefined
|
|
96
|
+
? []
|
|
97
|
+
: normalizeStoredAttachments(data.attachments);
|
|
98
|
+
if (!attachments) {
|
|
99
|
+
throw new Error('Message has malformed attachments');
|
|
100
|
+
}
|
|
99
101
|
const result = {
|
|
100
102
|
id: input.id,
|
|
101
103
|
senderId: typeof data.senderId === 'string' ? data.senderId : '',
|
|
102
|
-
senderType:
|
|
104
|
+
senderType: requireSenderType(data.senderType),
|
|
103
105
|
isOwner: input.isOwner,
|
|
104
|
-
contentType: normalizeContentType(data.contentType
|
|
106
|
+
contentType: normalizeContentType(data.contentType),
|
|
105
107
|
text: typeof data.text === 'string' ? data.text : null,
|
|
106
108
|
attachments,
|
|
107
109
|
mentions: normalizeStringArray(data.mentions),
|
|
108
110
|
replyTo: typeof data.replyTo === 'string' ? data.replyTo : null,
|
|
109
111
|
replyToPosition: typeof data.replyToPosition === 'number' ? data.replyToPosition : null,
|
|
110
112
|
status: data.status === 'read' ? 'read' : 'sent',
|
|
111
|
-
createdAt:
|
|
113
|
+
createdAt: requireCreatedAt(data.createdAt),
|
|
112
114
|
};
|
|
113
115
|
const forwardedFrom = normalizeForwardedFrom(data.forwardedFrom);
|
|
114
116
|
if (data.forwarded === true || forwardedFrom) {
|
|
@@ -127,5 +129,8 @@ export function serializeStoredMessage(input) {
|
|
|
127
129
|
if (contactCard) {
|
|
128
130
|
result.contactCard = contactCard;
|
|
129
131
|
}
|
|
132
|
+
if (isRecord(data.runtimeCard)) {
|
|
133
|
+
result.runtimeCard = data.runtimeCard;
|
|
134
|
+
}
|
|
130
135
|
return result;
|
|
131
136
|
}
|
package/dist/turnProtocol.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ export type TurnLifecycleState = 'idle' | 'thinking' | 'streaming' | 'tool' | 'w
|
|
|
3
3
|
export type TurnMessageSemantics = 'progress' | 'turn_complete' | 'control';
|
|
4
4
|
export interface TurnMetadata {
|
|
5
5
|
turnSemantics?: TurnMessageSemantics;
|
|
6
|
-
turnComplete?: boolean;
|
|
7
6
|
replyBehavior?: 'allow_auto_reply' | 'suppress_auto_reply';
|
|
8
7
|
}
|
|
9
8
|
export interface TurnStateLike {
|
|
@@ -21,17 +20,14 @@ export declare function isTurnStateStale(turnState: TurnStateLike | null | undef
|
|
|
21
20
|
export declare function resolveTurnMessageSemantics(input: {
|
|
22
21
|
senderType: SenderType;
|
|
23
22
|
metadata?: unknown;
|
|
24
|
-
senderTurnState?: TurnStateLike | null;
|
|
25
23
|
}): TurnMessageSemantics;
|
|
26
24
|
export declare function shouldPromoteConversationMessage(input: {
|
|
27
25
|
senderType: SenderType;
|
|
28
26
|
metadata?: unknown;
|
|
29
|
-
senderTurnState?: TurnStateLike | null;
|
|
30
27
|
}): boolean;
|
|
31
28
|
export declare function shouldTriggerAgentTurn(input: {
|
|
32
29
|
senderType: SenderType;
|
|
33
30
|
metadata?: unknown;
|
|
34
|
-
senderTurnState?: TurnStateLike | null;
|
|
35
31
|
}): {
|
|
36
32
|
allow: boolean;
|
|
37
33
|
semantics: TurnMessageSemantics;
|
package/dist/turnProtocol.js
CHANGED
|
@@ -11,7 +11,9 @@ function isHiddenRuntimeCardMetadata(metadata) {
|
|
|
11
11
|
|| metadata.type === 'question_reply'
|
|
12
12
|
|| metadata.type === 'plan_approval_reply'
|
|
13
13
|
|| metadata.type === 'runtime_input_reply'
|
|
14
|
-
|| metadata.type === 'runtime_input_outcome'
|
|
14
|
+
|| metadata.type === 'runtime_input_outcome'
|
|
15
|
+
|| metadata.type === 'runtime_card_reply'
|
|
16
|
+
|| metadata.type === 'runtime_card_outcome';
|
|
15
17
|
}
|
|
16
18
|
export function normalizeTurnMetadata(metadata) {
|
|
17
19
|
if (!isRecord(metadata))
|
|
@@ -25,12 +27,11 @@ export function normalizeTurnMetadata(metadata) {
|
|
|
25
27
|
|| metadata.replyBehavior === 'suppress_auto_reply'
|
|
26
28
|
? metadata.replyBehavior
|
|
27
29
|
: undefined;
|
|
28
|
-
if (!turnSemantics &&
|
|
30
|
+
if (!turnSemantics && !replyBehavior) {
|
|
29
31
|
return null;
|
|
30
32
|
}
|
|
31
33
|
return {
|
|
32
34
|
...(turnSemantics ? { turnSemantics } : {}),
|
|
33
|
-
...(typeof metadata.turnComplete === 'boolean' ? { turnComplete: metadata.turnComplete } : {}),
|
|
34
35
|
...(replyBehavior ? { replyBehavior } : {}),
|
|
35
36
|
};
|
|
36
37
|
}
|
|
@@ -69,11 +70,9 @@ export function resolveTurnMessageSemantics(input) {
|
|
|
69
70
|
const turnMetadata = normalizeTurnMetadata(input.metadata);
|
|
70
71
|
if (turnMetadata?.turnSemantics)
|
|
71
72
|
return turnMetadata.turnSemantics;
|
|
72
|
-
if (turnMetadata?.turnComplete === true)
|
|
73
|
-
return 'turn_complete';
|
|
74
73
|
if (input.senderType === 'human')
|
|
75
74
|
return 'turn_complete';
|
|
76
|
-
return
|
|
75
|
+
return 'progress';
|
|
77
76
|
}
|
|
78
77
|
export function shouldPromoteConversationMessage(input) {
|
|
79
78
|
if (isHiddenRuntimeCardMetadata(input.metadata)) {
|