@canonmsg/backend-contracts 0.2.3 → 1.0.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.
@@ -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: typeof data.targetName === 'string' ? data.targetName : null,
73
+ targetName: data.targetName.trim(),
61
74
  targetAvatarUrl: typeof data.targetAvatarUrl === 'string' ? data.targetAvatarUrl : null,
62
- targetUserType: data.targetUserType === 'human' || data.targetUserType === 'ai_agent'
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 (typeof data.targetOwnerId === 'string' && data.targetOwnerId.length > 0) {
87
+ if (data.targetUserType === 'ai_agent') {
77
88
  payload.targetOwnerId = data.targetOwnerId;
78
89
  }
79
90
  return payload;
@@ -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 normalizeCreatedAt(value, fallback) {
25
- const timestamp = normalizeTimestamp(value) ?? normalizeTimestamp(fallback);
26
- return timestamp ? timestamp.toISOString() : MISSING_CREATED_AT_ISO;
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 normalizeSenderType(value, fallback) {
29
- if (value === 'ai_agent' || fallback === 'ai_agent')
30
- return 'ai_agent';
31
- return 'human';
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, attachments) {
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
- const primary = attachments[0]?.kind;
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 = (0, media_js_1.getMessageAttachments)({
100
- attachments: data.attachments,
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: normalizeSenderType(data.senderType, input.senderTypeFallback),
107
+ senderType: requireSenderType(data.senderType),
106
108
  isOwner: input.isOwner,
107
- contentType: normalizeContentType(data.contentType, attachments),
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: normalizeCreatedAt(data.createdAt, input.createdAtFallback),
116
+ createdAt: requireCreatedAt(data.createdAt),
115
117
  };
116
118
  const forwardedFrom = normalizeForwardedFrom(data.forwardedFrom);
117
119
  if (data.forwarded === true || forwardedFrom) {
@@ -1,11 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WAITING_INPUT_STALE_THRESHOLD_MS = exports.ACTIVE_TURN_STALE_THRESHOLD_MS = void 0;
3
4
  exports.normalizeTurnMetadata = normalizeTurnMetadata;
4
5
  exports.isTurnOpen = isTurnOpen;
6
+ exports.getTurnStateStaleThresholdMs = getTurnStateStaleThresholdMs;
7
+ exports.isTurnStateStale = isTurnStateStale;
5
8
  exports.resolveTurnMessageSemantics = resolveTurnMessageSemantics;
6
9
  exports.shouldPromoteConversationMessage = shouldPromoteConversationMessage;
7
10
  exports.shouldTriggerAgentTurn = shouldTriggerAgentTurn;
8
11
  exports.normalizeRuntimeTurnState = normalizeRuntimeTurnState;
12
+ exports.ACTIVE_TURN_STALE_THRESHOLD_MS = 30 * 60 * 1000;
13
+ exports.WAITING_INPUT_STALE_THRESHOLD_MS = 12 * 60 * 60 * 1000;
9
14
  function isRecord(value) {
10
15
  return typeof value === 'object' && value !== null && !Array.isArray(value);
11
16
  }
@@ -31,31 +36,52 @@ function normalizeTurnMetadata(metadata) {
31
36
  || metadata.replyBehavior === 'suppress_auto_reply'
32
37
  ? metadata.replyBehavior
33
38
  : undefined;
34
- if (!turnSemantics && typeof metadata.turnComplete !== 'boolean' && !replyBehavior) {
39
+ if (!turnSemantics && !replyBehavior) {
35
40
  return null;
36
41
  }
37
42
  return {
38
43
  ...(turnSemantics ? { turnSemantics } : {}),
39
- ...(typeof metadata.turnComplete === 'boolean' ? { turnComplete: metadata.turnComplete } : {}),
40
44
  ...(replyBehavior ? { replyBehavior } : {}),
41
45
  };
42
46
  }
43
47
  function isTurnOpen(turnState) {
44
48
  if (!turnState)
45
49
  return false;
46
- return turnState.state !== 'idle'
50
+ const open = turnState.state !== 'idle'
47
51
  && turnState.state !== 'completed'
48
52
  && turnState.state !== 'interrupted';
53
+ if (!open)
54
+ return false;
55
+ return !isTurnStateStale(turnState);
56
+ }
57
+ function getTurnStateStaleThresholdMs(state) {
58
+ return state === 'waiting_input'
59
+ ? exports.WAITING_INPUT_STALE_THRESHOLD_MS
60
+ : exports.ACTIVE_TURN_STALE_THRESHOLD_MS;
61
+ }
62
+ function isTurnStateStale(turnState) {
63
+ if (!turnState)
64
+ return false;
65
+ if (turnState.state !== 'thinking'
66
+ && turnState.state !== 'streaming'
67
+ && turnState.state !== 'tool'
68
+ && turnState.state !== 'waiting_input') {
69
+ return false;
70
+ }
71
+ const updatedAt = turnState.turnUpdatedAt
72
+ ?? turnState.updatedAt
73
+ ?? turnState.openedAt;
74
+ if (updatedAt == null)
75
+ return false;
76
+ return Date.now() - updatedAt >= getTurnStateStaleThresholdMs(turnState.state);
49
77
  }
50
78
  function resolveTurnMessageSemantics(input) {
51
79
  const turnMetadata = normalizeTurnMetadata(input.metadata);
52
80
  if (turnMetadata?.turnSemantics)
53
81
  return turnMetadata.turnSemantics;
54
- if (turnMetadata?.turnComplete === true)
55
- return 'turn_complete';
56
82
  if (input.senderType === 'human')
57
83
  return 'turn_complete';
58
- return isTurnOpen(input.senderTurnState) ? 'progress' : 'turn_complete';
84
+ return 'progress';
59
85
  }
60
86
  function shouldPromoteConversationMessage(input) {
61
87
  if (isHiddenRuntimeCardMetadata(input.metadata)) {
@@ -84,7 +110,12 @@ function normalizeRuntimeTurnState(value) {
84
110
  || value.state === 'waiting_input'
85
111
  || value.state === 'completed'
86
112
  || value.state === 'interrupted') {
87
- return { state: value.state };
113
+ return {
114
+ state: value.state,
115
+ ...(typeof value.openedAt === 'number' ? { openedAt: value.openedAt } : {}),
116
+ ...(typeof value.updatedAt === 'number' ? { updatedAt: value.updatedAt } : {}),
117
+ ...(typeof value.turnUpdatedAt === 'number' ? { turnUpdatedAt: value.turnUpdatedAt } : {}),
118
+ };
88
119
  }
89
120
  return null;
90
121
  }
@@ -5,9 +5,9 @@ export interface SerializedContactRequest {
5
5
  requesterName: string;
6
6
  requesterAvatarUrl: string | null;
7
7
  targetId: string;
8
- targetName: string | null;
8
+ targetName: string;
9
9
  targetAvatarUrl: string | null;
10
- targetUserType: 'human' | 'ai_agent' | null;
10
+ targetUserType: 'human' | 'ai_agent';
11
11
  targetOwnerId?: string | null;
12
12
  approverId: string;
13
13
  message: string | null;
@@ -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: typeof data.targetName === 'string' ? data.targetName : null,
70
+ targetName: data.targetName.trim(),
58
71
  targetAvatarUrl: typeof data.targetAvatarUrl === 'string' ? data.targetAvatarUrl : null,
59
- targetUserType: data.targetUserType === 'human' || data.targetUserType === 'ai_agent'
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 (typeof data.targetOwnerId === 'string' && data.targetOwnerId.length > 0) {
84
+ if (data.targetUserType === 'ai_agent') {
74
85
  payload.targetOwnerId = data.targetOwnerId;
75
86
  }
76
87
  return payload;
package/dist/message.d.ts CHANGED
@@ -40,8 +40,6 @@ export interface SerializedMessage {
40
40
  export interface SerializeMessageInput {
41
41
  id: string;
42
42
  data: Record<string, unknown>;
43
- createdAtFallback?: unknown;
44
- senderTypeFallback?: unknown;
45
43
  senderName?: string;
46
44
  isOwner: boolean;
47
45
  }
package/dist/message.js CHANGED
@@ -1,5 +1,4 @@
1
- import { getMessageAttachments } from './media.js';
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 normalizeCreatedAt(value, fallback) {
22
- const timestamp = normalizeTimestamp(value) ?? normalizeTimestamp(fallback);
23
- return timestamp ? timestamp.toISOString() : MISSING_CREATED_AT_ISO;
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 normalizeSenderType(value, fallback) {
26
- if (value === 'ai_agent' || fallback === 'ai_agent')
27
- return 'ai_agent';
28
- return 'human';
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, attachments) {
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
- const primary = attachments[0]?.kind;
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 = getMessageAttachments({
97
- attachments: data.attachments,
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: normalizeSenderType(data.senderType, input.senderTypeFallback),
104
+ senderType: requireSenderType(data.senderType),
103
105
  isOwner: input.isOwner,
104
- contentType: normalizeContentType(data.contentType, attachments),
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: normalizeCreatedAt(data.createdAt, input.createdAtFallback),
113
+ createdAt: requireCreatedAt(data.createdAt),
112
114
  };
113
115
  const forwardedFrom = normalizeForwardedFrom(data.forwardedFrom);
114
116
  if (data.forwarded === true || forwardedFrom) {
@@ -3,28 +3,31 @@ 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 {
10
9
  state: TurnLifecycleState;
10
+ openedAt?: number;
11
+ updatedAt?: number;
12
+ turnUpdatedAt?: number | null;
11
13
  }
14
+ export declare const ACTIVE_TURN_STALE_THRESHOLD_MS: number;
15
+ export declare const WAITING_INPUT_STALE_THRESHOLD_MS: number;
12
16
  export declare function normalizeTurnMetadata(metadata: unknown): TurnMetadata | null;
13
17
  export declare function isTurnOpen(turnState: TurnStateLike | null | undefined): boolean;
18
+ export declare function getTurnStateStaleThresholdMs(state: TurnLifecycleState): number;
19
+ export declare function isTurnStateStale(turnState: TurnStateLike | null | undefined): boolean;
14
20
  export declare function resolveTurnMessageSemantics(input: {
15
21
  senderType: SenderType;
16
22
  metadata?: unknown;
17
- senderTurnState?: TurnStateLike | null;
18
23
  }): TurnMessageSemantics;
19
24
  export declare function shouldPromoteConversationMessage(input: {
20
25
  senderType: SenderType;
21
26
  metadata?: unknown;
22
- senderTurnState?: TurnStateLike | null;
23
27
  }): boolean;
24
28
  export declare function shouldTriggerAgentTurn(input: {
25
29
  senderType: SenderType;
26
30
  metadata?: unknown;
27
- senderTurnState?: TurnStateLike | null;
28
31
  }): {
29
32
  allow: boolean;
30
33
  semantics: TurnMessageSemantics;
@@ -1,3 +1,5 @@
1
+ export const ACTIVE_TURN_STALE_THRESHOLD_MS = 30 * 60 * 1000;
2
+ export const WAITING_INPUT_STALE_THRESHOLD_MS = 12 * 60 * 60 * 1000;
1
3
  function isRecord(value) {
2
4
  return typeof value === 'object' && value !== null && !Array.isArray(value);
3
5
  }
@@ -23,31 +25,52 @@ export function normalizeTurnMetadata(metadata) {
23
25
  || metadata.replyBehavior === 'suppress_auto_reply'
24
26
  ? metadata.replyBehavior
25
27
  : undefined;
26
- if (!turnSemantics && typeof metadata.turnComplete !== 'boolean' && !replyBehavior) {
28
+ if (!turnSemantics && !replyBehavior) {
27
29
  return null;
28
30
  }
29
31
  return {
30
32
  ...(turnSemantics ? { turnSemantics } : {}),
31
- ...(typeof metadata.turnComplete === 'boolean' ? { turnComplete: metadata.turnComplete } : {}),
32
33
  ...(replyBehavior ? { replyBehavior } : {}),
33
34
  };
34
35
  }
35
36
  export function isTurnOpen(turnState) {
36
37
  if (!turnState)
37
38
  return false;
38
- return turnState.state !== 'idle'
39
+ const open = turnState.state !== 'idle'
39
40
  && turnState.state !== 'completed'
40
41
  && turnState.state !== 'interrupted';
42
+ if (!open)
43
+ return false;
44
+ return !isTurnStateStale(turnState);
45
+ }
46
+ export function getTurnStateStaleThresholdMs(state) {
47
+ return state === 'waiting_input'
48
+ ? WAITING_INPUT_STALE_THRESHOLD_MS
49
+ : ACTIVE_TURN_STALE_THRESHOLD_MS;
50
+ }
51
+ export function isTurnStateStale(turnState) {
52
+ if (!turnState)
53
+ return false;
54
+ if (turnState.state !== 'thinking'
55
+ && turnState.state !== 'streaming'
56
+ && turnState.state !== 'tool'
57
+ && turnState.state !== 'waiting_input') {
58
+ return false;
59
+ }
60
+ const updatedAt = turnState.turnUpdatedAt
61
+ ?? turnState.updatedAt
62
+ ?? turnState.openedAt;
63
+ if (updatedAt == null)
64
+ return false;
65
+ return Date.now() - updatedAt >= getTurnStateStaleThresholdMs(turnState.state);
41
66
  }
42
67
  export function resolveTurnMessageSemantics(input) {
43
68
  const turnMetadata = normalizeTurnMetadata(input.metadata);
44
69
  if (turnMetadata?.turnSemantics)
45
70
  return turnMetadata.turnSemantics;
46
- if (turnMetadata?.turnComplete === true)
47
- return 'turn_complete';
48
71
  if (input.senderType === 'human')
49
72
  return 'turn_complete';
50
- return isTurnOpen(input.senderTurnState) ? 'progress' : 'turn_complete';
73
+ return 'progress';
51
74
  }
52
75
  export function shouldPromoteConversationMessage(input) {
53
76
  if (isHiddenRuntimeCardMetadata(input.metadata)) {
@@ -76,7 +99,12 @@ export function normalizeRuntimeTurnState(value) {
76
99
  || value.state === 'waiting_input'
77
100
  || value.state === 'completed'
78
101
  || value.state === 'interrupted') {
79
- return { state: value.state };
102
+ return {
103
+ state: value.state,
104
+ ...(typeof value.openedAt === 'number' ? { openedAt: value.openedAt } : {}),
105
+ ...(typeof value.updatedAt === 'number' ? { updatedAt: value.updatedAt } : {}),
106
+ ...(typeof value.turnUpdatedAt === 'number' ? { turnUpdatedAt: value.turnUpdatedAt } : {}),
107
+ };
80
108
  }
81
109
  return null;
82
110
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/backend-contracts",
3
- "version": "0.2.3",
3
+ "version": "1.0.0",
4
4
  "description": "Canon backend contract helpers shared by Functions and stream-service",
5
5
  "type": "module",
6
6
  "main": "dist/cjs/index.js",