@cossistant/core 0.0.7

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.
Files changed (76) hide show
  1. package/dist/_virtual/rolldown_runtime.js +33 -0
  2. package/dist/client.d.ts +82 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +275 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/contact.d.ts +28 -0
  7. package/dist/contact.d.ts.map +1 -0
  8. package/dist/conversation.d.ts +85 -0
  9. package/dist/conversation.d.ts.map +1 -0
  10. package/dist/index.d.ts +15 -0
  11. package/dist/index.js +16 -0
  12. package/dist/locale-utils.d.ts +17 -0
  13. package/dist/locale-utils.d.ts.map +1 -0
  14. package/dist/locale-utils.js +22 -0
  15. package/dist/locale-utils.js.map +1 -0
  16. package/dist/logger.d.ts +11 -0
  17. package/dist/logger.d.ts.map +1 -0
  18. package/dist/logger.js +22 -0
  19. package/dist/logger.js.map +1 -0
  20. package/dist/realtime-events.d.ts +120 -0
  21. package/dist/realtime-events.d.ts.map +1 -0
  22. package/dist/rest-client.d.ts +65 -0
  23. package/dist/rest-client.d.ts.map +1 -0
  24. package/dist/rest-client.js +367 -0
  25. package/dist/rest-client.js.map +1 -0
  26. package/dist/schemas.d.ts +33 -0
  27. package/dist/schemas.d.ts.map +1 -0
  28. package/dist/store/conversations-store.d.ts +22 -0
  29. package/dist/store/conversations-store.d.ts.map +1 -0
  30. package/dist/store/conversations-store.js +108 -0
  31. package/dist/store/conversations-store.js.map +1 -0
  32. package/dist/store/create-store.d.ts +14 -0
  33. package/dist/store/create-store.d.ts.map +1 -0
  34. package/dist/store/create-store.js +47 -0
  35. package/dist/store/create-store.js.map +1 -0
  36. package/dist/store/seen-store.d.ts +37 -0
  37. package/dist/store/seen-store.d.ts.map +1 -0
  38. package/dist/store/seen-store.js +131 -0
  39. package/dist/store/seen-store.js.map +1 -0
  40. package/dist/store/support-store.d.ts +63 -0
  41. package/dist/store/support-store.d.ts.map +1 -0
  42. package/dist/store/support-store.js +170 -0
  43. package/dist/store/support-store.js.map +1 -0
  44. package/dist/store/timeline-items-store.d.ts +27 -0
  45. package/dist/store/timeline-items-store.d.ts.map +1 -0
  46. package/dist/store/timeline-items-store.js +142 -0
  47. package/dist/store/timeline-items-store.js.map +1 -0
  48. package/dist/store/typing-store.d.ts +50 -0
  49. package/dist/store/typing-store.d.ts.map +1 -0
  50. package/dist/store/typing-store.js +149 -0
  51. package/dist/store/typing-store.js.map +1 -0
  52. package/dist/store/website-store.d.ts +24 -0
  53. package/dist/store/website-store.d.ts.map +1 -0
  54. package/dist/store/website-store.js +60 -0
  55. package/dist/store/website-store.js.map +1 -0
  56. package/dist/timeline-item.d.ts +207 -0
  57. package/dist/timeline-item.d.ts.map +1 -0
  58. package/dist/types/src/enums.js +24 -0
  59. package/dist/types/src/enums.js.map +1 -0
  60. package/dist/types.d.ts +17 -0
  61. package/dist/types.d.ts.map +1 -0
  62. package/dist/types.js +17 -0
  63. package/dist/types.js.map +1 -0
  64. package/dist/utils.d.ts +8 -0
  65. package/dist/utils.d.ts.map +1 -0
  66. package/dist/utils.js +20 -0
  67. package/dist/utils.js.map +1 -0
  68. package/dist/visitor-data.d.ts +33 -0
  69. package/dist/visitor-data.d.ts.map +1 -0
  70. package/dist/visitor-data.js +212 -0
  71. package/dist/visitor-data.js.map +1 -0
  72. package/dist/visitor-tracker.d.ts +31 -0
  73. package/dist/visitor-tracker.d.ts.map +1 -0
  74. package/dist/visitor-tracker.js +109 -0
  75. package/dist/visitor-tracker.js.map +1 -0
  76. package/package.json +48 -0
@@ -0,0 +1,11 @@
1
+ //#region src/logger.d.ts
2
+ type LogMethod = (message: string, ...details: unknown[]) => void;
3
+ declare const logger: {
4
+ debug: LogMethod;
5
+ info: LogMethod;
6
+ warn: LogMethod;
7
+ error: LogMethod;
8
+ };
9
+ //#endregion
10
+ export { logger };
11
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","names":[],"sources":["../src/logger.ts"],"sourcesContent":[],"mappings":";KAIK,SAAA;AAAA,cAsBQ,MAtBC,EAAA;EAsBD,KAAA,WAKZ"}
package/dist/logger.js ADDED
@@ -0,0 +1,22 @@
1
+ //#region src/logger.ts
2
+ const LOG_PREFIX = "[cossistant]";
3
+ const resolveConsole = () => {
4
+ if (typeof globalThis === "undefined") return null;
5
+ return globalThis.console ?? null;
6
+ };
7
+ const createLoggerMethod = (level) => (message, ...details) => {
8
+ const target = resolveConsole();
9
+ if (!target) return;
10
+ const consoleMethod = (target[level] ?? target.log)?.bind(target);
11
+ consoleMethod?.(LOG_PREFIX, message, ...details);
12
+ };
13
+ const logger = {
14
+ debug: createLoggerMethod("debug"),
15
+ info: createLoggerMethod("info"),
16
+ warn: createLoggerMethod("warn"),
17
+ error: createLoggerMethod("error")
18
+ };
19
+
20
+ //#endregion
21
+ export { logger };
22
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","names":[],"sources":["../src/logger.ts"],"sourcesContent":["const LOG_PREFIX = \"[cossistant]\";\n\ntype LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\ntype LogMethod = (message: string, ...details: unknown[]) => void;\n\nconst resolveConsole = (): Console | null => {\n\tif (typeof globalThis === \"undefined\") {\n\t\treturn null;\n\t}\n\n\treturn globalThis.console ?? null;\n};\n\nconst createLoggerMethod =\n\t(level: LogLevel): LogMethod =>\n\t(message, ...details) => {\n\t\tconst target = resolveConsole();\n\t\tif (!target) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst consoleMethod = (target[level] ?? target.log)?.bind(target);\n\t\tconsoleMethod?.(LOG_PREFIX, message, ...details);\n\t};\n\nexport const logger = {\n\tdebug: createLoggerMethod(\"debug\"),\n\tinfo: createLoggerMethod(\"info\"),\n\twarn: createLoggerMethod(\"warn\"),\n\terror: createLoggerMethod(\"error\"),\n};\n"],"mappings":";AAAA,MAAM,aAAa;AAMnB,MAAM,uBAAuC;AAC5C,KAAI,OAAO,eAAe,YACzB,QAAO;AAGR,QAAO,WAAW,WAAW;;AAG9B,MAAM,sBACJ,WACA,SAAS,GAAG,YAAY;CACxB,MAAM,SAAS,gBAAgB;AAC/B,KAAI,CAAC,OACJ;CAGD,MAAM,iBAAiB,OAAO,UAAU,OAAO,MAAM,KAAK,OAAO;AACjE,iBAAgB,YAAY,SAAS,GAAG,QAAQ;;AAGlD,MAAa,SAAS;CACrB,OAAO,mBAAmB,QAAQ;CAClC,MAAM,mBAAmB,OAAO;CAChC,MAAM,mBAAmB,OAAO;CAChC,OAAO,mBAAmB,QAAQ;CAClC"}
@@ -0,0 +1,120 @@
1
+ import { z } from "zod";
2
+
3
+ //#region ../types/src/realtime-events.d.ts
4
+
5
+ /**
6
+ * Central event system for real-time communication
7
+ * All WebSocket and Redis Pub/Sub events are defined here
8
+ */
9
+ declare const realtimeSchema: {
10
+ readonly userConnected: z.ZodObject<{
11
+ websiteId: z.ZodString;
12
+ organizationId: z.ZodString;
13
+ visitorId: z.ZodNullable<z.ZodString>;
14
+ userId: z.ZodNullable<z.ZodString>;
15
+ connectionId: z.ZodString;
16
+ }, z.core.$strip>;
17
+ readonly userDisconnected: z.ZodObject<{
18
+ websiteId: z.ZodString;
19
+ organizationId: z.ZodString;
20
+ visitorId: z.ZodNullable<z.ZodString>;
21
+ userId: z.ZodNullable<z.ZodString>;
22
+ connectionId: z.ZodString;
23
+ }, z.core.$strip>;
24
+ readonly visitorConnected: z.ZodObject<{
25
+ websiteId: z.ZodString;
26
+ organizationId: z.ZodString;
27
+ userId: z.ZodNullable<z.ZodString>;
28
+ visitorId: z.ZodString;
29
+ connectionId: z.ZodString;
30
+ }, z.core.$strip>;
31
+ readonly visitorDisconnected: z.ZodObject<{
32
+ websiteId: z.ZodString;
33
+ organizationId: z.ZodString;
34
+ userId: z.ZodNullable<z.ZodString>;
35
+ visitorId: z.ZodString;
36
+ connectionId: z.ZodString;
37
+ }, z.core.$strip>;
38
+ readonly userPresenceUpdate: z.ZodObject<{
39
+ websiteId: z.ZodString;
40
+ organizationId: z.ZodString;
41
+ visitorId: z.ZodNullable<z.ZodString>;
42
+ userId: z.ZodString;
43
+ status: z.ZodEnum<{
44
+ online: "online";
45
+ away: "away";
46
+ offline: "offline";
47
+ }>;
48
+ lastSeen: z.ZodString;
49
+ }, z.core.$strip>;
50
+ readonly conversationSeen: z.ZodObject<{
51
+ websiteId: z.ZodString;
52
+ organizationId: z.ZodString;
53
+ visitorId: z.ZodNullable<z.ZodString>;
54
+ userId: z.ZodNullable<z.ZodString>;
55
+ conversationId: z.ZodString;
56
+ aiAgentId: z.ZodNullable<z.ZodString>;
57
+ lastSeenAt: z.ZodString;
58
+ }, z.core.$strip>;
59
+ readonly conversationTyping: z.ZodObject<{
60
+ websiteId: z.ZodString;
61
+ organizationId: z.ZodString;
62
+ visitorId: z.ZodNullable<z.ZodString>;
63
+ userId: z.ZodNullable<z.ZodString>;
64
+ conversationId: z.ZodString;
65
+ aiAgentId: z.ZodNullable<z.ZodString>;
66
+ isTyping: z.ZodBoolean;
67
+ visitorPreview: z.ZodOptional<z.ZodNullable<z.ZodString>>;
68
+ }, z.core.$strip>;
69
+ readonly timelineItemCreated: z.ZodObject<{
70
+ websiteId: z.ZodString;
71
+ organizationId: z.ZodString;
72
+ visitorId: z.ZodNullable<z.ZodString>;
73
+ userId: z.ZodNullable<z.ZodString>;
74
+ conversationId: z.ZodString;
75
+ item: z.ZodObject<{
76
+ id: z.ZodString;
77
+ conversationId: z.ZodString;
78
+ organizationId: z.ZodString;
79
+ visibility: z.ZodEnum<{
80
+ [x: string]: any;
81
+ }>;
82
+ type: z.ZodEnum<{
83
+ [x: string]: any;
84
+ }>;
85
+ text: z.ZodNullable<z.ZodString>;
86
+ parts: z.ZodArray<z.ZodUnknown>;
87
+ userId: z.ZodNullable<z.ZodString>;
88
+ visitorId: z.ZodNullable<z.ZodString>;
89
+ aiAgentId: z.ZodNullable<z.ZodString>;
90
+ createdAt: z.ZodString;
91
+ deletedAt: z.ZodNullable<z.ZodString>;
92
+ tool: z.ZodOptional<z.ZodNullable<z.ZodString>>;
93
+ }, z.core.$strip>;
94
+ }, z.core.$strip>;
95
+ readonly conversationCreated: z.ZodObject<{
96
+ websiteId: z.ZodString;
97
+ organizationId: z.ZodString;
98
+ visitorId: z.ZodNullable<z.ZodString>;
99
+ userId: z.ZodNullable<z.ZodString>;
100
+ conversationId: z.ZodString;
101
+ conversation: any;
102
+ header: any;
103
+ }, z.core.$strip>;
104
+ readonly visitorIdentified: z.ZodObject<{
105
+ websiteId: z.ZodString;
106
+ organizationId: z.ZodString;
107
+ userId: z.ZodNullable<z.ZodString>;
108
+ visitorId: z.ZodString;
109
+ visitor: any;
110
+ }, z.core.$strip>;
111
+ };
112
+ type RealtimeEventType = keyof typeof realtimeSchema;
113
+ type RealtimeEventPayload<T extends RealtimeEventType> = z.infer<(typeof realtimeSchema)[T]>;
114
+ type RealtimeEvent<T extends RealtimeEventType> = {
115
+ type: T;
116
+ payload: RealtimeEventPayload<T>;
117
+ };
118
+ //#endregion
119
+ export { RealtimeEvent };
120
+ //# sourceMappingURL=realtime-events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-events.d.ts","names":[],"sources":["../../types/src/realtime-events.ts"],"sourcesContent":[],"mappings":";;;;;;;;cAiBa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmED,iBAAA,gBAAiC;KAEjC,+BAA+B,qBAAqB,CAAA,CAAE,cACzD,gBAAgB;KAGb,wBAAwB;QAC7B;WACG,qBAAqB"}
@@ -0,0 +1,65 @@
1
+ import { CreateConversationRequestBody, CreateConversationResponseBody, GetConversationRequest, GetConversationResponse, GetConversationSeenDataResponse, ListConversationsRequest, ListConversationsResponse, MarkConversationSeenRequestBody, MarkConversationSeenResponseBody, SetConversationTypingResponseBody } from "./conversation.js";
2
+ import { GetConversationTimelineItemsRequest, GetConversationTimelineItemsResponse, SendTimelineItemRequest, SendTimelineItemResponse } from "./timeline-item.js";
3
+ import { types_d_exports } from "./types.js";
4
+ import { IdentifyContactResponse } from "./contact.js";
5
+
6
+ //#region src/rest-client.d.ts
7
+ declare class CossistantRestClient {
8
+ private config;
9
+ private baseHeaders;
10
+ private publicKey;
11
+ private websiteId;
12
+ private visitorId;
13
+ private visitorBlocked;
14
+ constructor(config: types_d_exports.CossistantConfig);
15
+ private normalizeVisitorResponse;
16
+ private resolveVisitorId;
17
+ private syncVisitorSnapshot;
18
+ private request;
19
+ getWebsite(): Promise<types_d_exports.PublicWebsiteResponse>;
20
+ setWebsiteContext(websiteId: string, visitorId?: string): void;
21
+ setVisitorBlocked(isBlocked: boolean): void;
22
+ getCurrentWebsiteId(): string | null;
23
+ getCurrentVisitorId(): string | null;
24
+ updateVisitorMetadata(metadata: types_d_exports.VisitorMetadata): Promise<types_d_exports.VisitorResponse>;
25
+ /**
26
+ * Identify a visitor by creating or updating their contact information
27
+ * This will link the visitor to a contact record that can be tracked across devices
28
+ */
29
+ identify(params: {
30
+ externalId?: string;
31
+ email?: string;
32
+ name?: string;
33
+ image?: string;
34
+ metadata?: Record<string, unknown>;
35
+ contactOrganizationId?: string;
36
+ }): Promise<IdentifyContactResponse>;
37
+ /**
38
+ * Update metadata for the contact associated with the current visitor
39
+ * Note: The visitor must be identified first via the identify() method
40
+ */
41
+ updateContactMetadata(metadata: Record<string, unknown>): Promise<types_d_exports.VisitorResponse>;
42
+ createConversation(params?: Partial<CreateConversationRequestBody>): Promise<CreateConversationResponseBody>;
43
+ updateConfiguration(config: Partial<types_d_exports.CossistantConfig>): Promise<void>;
44
+ listConversations(params?: Partial<ListConversationsRequest>): Promise<ListConversationsResponse>;
45
+ getConversation(params: GetConversationRequest): Promise<GetConversationResponse>;
46
+ markConversationSeen(params: {
47
+ conversationId: string;
48
+ } & Partial<MarkConversationSeenRequestBody>): Promise<MarkConversationSeenResponseBody>;
49
+ getConversationSeenData(params: {
50
+ conversationId: string;
51
+ }): Promise<GetConversationSeenDataResponse>;
52
+ setConversationTyping(params: {
53
+ conversationId: string;
54
+ isTyping: boolean;
55
+ visitorPreview?: string | null;
56
+ visitorId?: string;
57
+ }): Promise<SetConversationTypingResponseBody>;
58
+ sendMessage(params: SendTimelineItemRequest): Promise<SendTimelineItemResponse>;
59
+ getConversationTimelineItems(params: GetConversationTimelineItemsRequest & {
60
+ conversationId: string;
61
+ }): Promise<GetConversationTimelineItemsResponse>;
62
+ }
63
+ //#endregion
64
+ export { CossistantRestClient };
65
+ //# sourceMappingURL=rest-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest-client.d.ts","names":[],"sources":["../src/rest-client.ts"],"sourcesContent":[],"mappings":";;;;;;cAqCa,oBAAA;;EAAA,QAAA,WAAA;EAQQ,QAAA,SAAA;EA2LQ,QAAA,SAAA;EAAR,QAAA,SAAA;EA6ET,QAAA,cAAA;EACA,WAAA,CAAA,MAAA,EAzQS,eAAA,CAAA,gBAyQT;EAAR,QAAA,wBAAA;EAyBS,QAAA,gBAAA;EAEA,QAAA,mBAAA;EAAR,QAAA,OAAA;EAqCO,UAAA,CAAA,CAAA,EA9IS,OA8IT,CA9IiB,eAAA,CAAA,qBA8IjB,CAAA;EACA,iBAAA,CAAA,SAAA,EAAA,MAAA,EAAA,SAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAAR,iBAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,IAAA;EAOc,mBAAA,CAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAAR,mBAAA,CAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EACE,qBAAA,CAAA,QAAA,EA1EA,eAAA,CAAA,eA0EA,CAAA,EAzER,OAyEQ,CAzEA,eAAA,CAAA,eAyEA,CAAA;EAAR;;;;EAwEc,QAAA,CAAA,MAAA,EAAA;IAAR,UAAA,CAAA,EAAA,MAAA;IACE,KAAA,CAAA,EAAA,MAAA;IAAR,IAAA,CAAA,EAAA,MAAA;IAiEM,KAAA,CAAA,EAAA,MAAA;IACE,QAAA,CAAA,EA3LC,MA2LD,CAAA,MAAA,EAAA,OAAA,CAAA;IAAR,qBAAA,CAAA,EAAA,MAAA;EAgCU,CAAA,CAAA,EAzNT,OAyNS,CAzND,uBAyNC,CAAA;EAAR;;;;EAsCD,qBAAA,CAAA,QAAA,EA1NO,MA0NP,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,EAzND,OAyNC,CAzNO,eAAA,CAAA,eAyNP,CAAA;EAwBQ,kBAAA,CAAA,MAAA,CAAA,EA1OH,OA0OG,CA1OK,6BA0OL,CAAA,CAAA,EAzOT,OAyOS,CAzOD,8BAyOC,CAAA;EAAR,mBAAA,CAAA,MAAA,EAzL8B,OAyL9B,CAzLsC,eAAA,CAAA,gBAyLtC,CAAA,CAAA,EAzL0D,OAyL1D,CAAA,IAAA,CAAA;EA6CK,iBAAA,CAAA,MAAA,CAAA,EA9MA,OA8MA,CA9MQ,wBA8MR,CAAA,CAAA,EA7MN,OA6MM,CA7ME,yBA6MF,CAAA;EACE,eAAA,CAAA,MAAA,EA7IF,sBA6IE,CAAA,EA5IR,OA4IQ,CA5IA,uBA4IA,CAAA;EAAR,oBAAA,CAAA,MAAA,EAAA;IAsBM,cAAA,EAAA,MAAA;EACE,CAAA,GAnIN,OAmIM,CAnIE,+BAmIF,CAAA,CAAA,EAlIR,OAkIQ,CAlIA,gCAkIA,CAAA;EAAR,uBAAA,CAAA,MAAA,EAAA;IAAO,cAAA,EAAA,MAAA;MA7FN,QAAQ;;;;;;MAwBR,QAAQ;sBA6CH,0BACN,QAAQ;uCAsBF;;MACN,QAAQ"}
@@ -0,0 +1,367 @@
1
+ import { logger } from "./logger.js";
2
+ import { CossistantAPIError } from "./types.js";
3
+ import { generateConversationId } from "./utils.js";
4
+ import { collectVisitorData } from "./visitor-data.js";
5
+ import { getExistingVisitorId, getVisitorId, setVisitorId } from "./visitor-tracker.js";
6
+
7
+ //#region src/rest-client.ts
8
+ var CossistantRestClient = class {
9
+ config;
10
+ baseHeaders;
11
+ publicKey;
12
+ websiteId = null;
13
+ visitorId = null;
14
+ visitorBlocked = false;
15
+ constructor(config) {
16
+ this.config = config;
17
+ this.publicKey = config.publicKey || (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_COSSISTANT_KEY : void 0) || (typeof process !== "undefined" ? process.env.COSSISTANT_PUBLIC_KEY : void 0) || "";
18
+ if (!this.publicKey) throw new Error("Public key is required. Please provide it in the config or set NEXT_PUBLIC_COSSISTANT_KEY or COSSISTANT_PUBLIC_KEY environment variable.");
19
+ this.baseHeaders = {
20
+ "Content-Type": "application/json",
21
+ "X-Public-Key": this.publicKey
22
+ };
23
+ if (config.userId) this.baseHeaders["X-User-ID"] = config.userId;
24
+ if (config.organizationId) this.baseHeaders["X-Organization-ID"] = config.organizationId;
25
+ }
26
+ normalizeVisitorResponse(payload) {
27
+ payload.contact && payload.contact;
28
+ return {
29
+ ...payload,
30
+ latitude: typeof payload.latitude === "string" ? Number.parseFloat(payload.latitude) : payload.latitude,
31
+ longitude: typeof payload.longitude === "string" ? Number.parseFloat(payload.longitude) : payload.longitude,
32
+ createdAt: payload.createdAt,
33
+ updatedAt: payload.updatedAt,
34
+ lastSeenAt: payload.lastSeenAt ? payload.lastSeenAt : null,
35
+ blockedAt: payload.blockedAt ? payload.blockedAt : null,
36
+ contact: payload.contact ? payload.contact : null
37
+ };
38
+ }
39
+ resolveVisitorId() {
40
+ if (this.visitorId) return this.visitorId;
41
+ if (this.websiteId) {
42
+ const storedVisitorId = getVisitorId(this.websiteId);
43
+ if (storedVisitorId) {
44
+ this.visitorId = storedVisitorId;
45
+ return storedVisitorId;
46
+ }
47
+ }
48
+ throw new Error("Visitor ID is required");
49
+ }
50
+ async syncVisitorSnapshot(visitorId) {
51
+ try {
52
+ const visitorData = await collectVisitorData();
53
+ if (!visitorData) return;
54
+ const payload = Object.entries(visitorData).reduce((acc, [key, value]) => {
55
+ if (value === null || value === void 0) return acc;
56
+ acc[key] = value;
57
+ return acc;
58
+ }, {});
59
+ if (Object.keys(payload).length === 0) return;
60
+ await this.request(`/visitors/${visitorId}`, {
61
+ method: "PATCH",
62
+ body: JSON.stringify(payload),
63
+ headers: { "X-Visitor-Id": visitorId }
64
+ });
65
+ } catch (error) {
66
+ logger.warn("Failed to sync visitor data", error);
67
+ }
68
+ }
69
+ async request(path, options = {}) {
70
+ if (this.visitorBlocked) {
71
+ const method = (options.method ?? "GET").toUpperCase();
72
+ const [rawPath] = path.split("?");
73
+ if (!((rawPath.endsWith("/") ? rawPath.slice(0, -1) : rawPath) === "/websites" && (method === "GET" || method === "HEAD"))) throw new CossistantAPIError({
74
+ code: "VISITOR_BLOCKED",
75
+ message: "Visitor is blocked and cannot perform this action.",
76
+ details: {
77
+ path,
78
+ method
79
+ }
80
+ });
81
+ }
82
+ const url = `${this.config.apiUrl}${path}`;
83
+ const response = await fetch(url, {
84
+ ...options,
85
+ headers: {
86
+ ...this.baseHeaders,
87
+ ...options.headers
88
+ }
89
+ });
90
+ if (!response.ok) {
91
+ const errorData = await response.json().catch(() => ({}));
92
+ const statusCode = response.status;
93
+ const errorCode = errorData.code || `HTTP_${statusCode}`;
94
+ const serverMessage = errorData.message;
95
+ const isAuthError = statusCode === 401 || statusCode === 403 || errorCode === "UNAUTHORIZED" || errorCode === "FORBIDDEN" || errorCode === "INVALID_API_KEY" || errorCode === "API_KEY_EXPIRED" || errorCode === "API_KEY_MISSING" || errorCode?.toUpperCase().includes("AUTH") || errorCode?.toUpperCase().includes("API_KEY");
96
+ const errorMessage = isAuthError ? "Your Cossistant public API key is invalid, expired, missing or not authorized to access this resource." : serverMessage || `Request failed with status ${statusCode}`;
97
+ if (isAuthError) logger.error(errorMessage, {
98
+ details: errorData.details,
99
+ path,
100
+ status: statusCode,
101
+ code: errorCode
102
+ });
103
+ else logger.error("API request failed", {
104
+ message: errorMessage,
105
+ details: errorData.details,
106
+ path,
107
+ status: statusCode,
108
+ code: errorCode
109
+ });
110
+ throw new CossistantAPIError({
111
+ code: errorCode,
112
+ message: errorMessage,
113
+ details: errorData.details
114
+ });
115
+ }
116
+ return response.json();
117
+ }
118
+ async getWebsite() {
119
+ const headers = {};
120
+ if (this.websiteId) {
121
+ const storedVisitorId = getVisitorId(this.websiteId);
122
+ if (storedVisitorId) headers["X-Visitor-Id"] = storedVisitorId;
123
+ } else {
124
+ const existingVisitor = getExistingVisitorId(this.publicKey);
125
+ if (existingVisitor) {
126
+ headers["X-Visitor-Id"] = existingVisitor.visitorId;
127
+ this.websiteId = existingVisitor.websiteId;
128
+ this.visitorId = existingVisitor.visitorId;
129
+ }
130
+ }
131
+ const response = await this.request("/websites", { headers });
132
+ this.websiteId = response.id;
133
+ this.visitorBlocked = response.visitor?.isBlocked ?? false;
134
+ if (response.visitor?.id) {
135
+ if (this.visitorBlocked) {
136
+ this.visitorId = response.visitor.id;
137
+ setVisitorId(response.id, response.visitor.id);
138
+ return response;
139
+ }
140
+ this.visitorId = response.visitor.id;
141
+ setVisitorId(response.id, response.visitor.id);
142
+ this.syncVisitorSnapshot(response.visitor.id);
143
+ }
144
+ return response;
145
+ }
146
+ setWebsiteContext(websiteId, visitorId) {
147
+ this.websiteId = websiteId;
148
+ if (visitorId) {
149
+ this.visitorId = visitorId;
150
+ setVisitorId(websiteId, visitorId);
151
+ }
152
+ }
153
+ setVisitorBlocked(isBlocked) {
154
+ this.visitorBlocked = isBlocked;
155
+ }
156
+ getCurrentWebsiteId() {
157
+ return this.websiteId;
158
+ }
159
+ getCurrentVisitorId() {
160
+ if (this.visitorId) return this.visitorId;
161
+ if (!this.websiteId) return null;
162
+ return getVisitorId(this.websiteId) ?? null;
163
+ }
164
+ async updateVisitorMetadata(metadata) {
165
+ const visitorId = this.resolveVisitorId();
166
+ const response = await this.request(`/visitors/${visitorId}/metadata`, {
167
+ method: "PATCH",
168
+ body: JSON.stringify({ metadata }),
169
+ headers: { "X-Visitor-Id": visitorId }
170
+ });
171
+ return this.normalizeVisitorResponse(response);
172
+ }
173
+ /**
174
+ * Identify a visitor by creating or updating their contact information
175
+ * This will link the visitor to a contact record that can be tracked across devices
176
+ */
177
+ async identify(params) {
178
+ const visitorId = this.resolveVisitorId();
179
+ const response = await this.request("/contacts/identify", {
180
+ method: "POST",
181
+ body: JSON.stringify({
182
+ visitorId,
183
+ ...params
184
+ }),
185
+ headers: { "X-Visitor-Id": visitorId }
186
+ });
187
+ return {
188
+ contact: {
189
+ ...response.contact,
190
+ metadata: typeof response.contact.metadata === "string" ? JSON.parse(response.contact.metadata) : response.contact.metadata,
191
+ createdAt: response.contact.createdAt,
192
+ updatedAt: response.contact.updatedAt
193
+ },
194
+ visitorId: response.visitorId
195
+ };
196
+ }
197
+ /**
198
+ * Update metadata for the contact associated with the current visitor
199
+ * Note: The visitor must be identified first via the identify() method
200
+ */
201
+ async updateContactMetadata(metadata) {
202
+ return this.updateVisitorMetadata(metadata);
203
+ }
204
+ async createConversation(params = {}) {
205
+ const conversationId = params.conversationId || generateConversationId();
206
+ const storedVisitorId = this.websiteId ? getVisitorId(this.websiteId) : void 0;
207
+ const visitorId = params.visitorId || storedVisitorId;
208
+ if (!visitorId) throw new Error("Visitor ID is required");
209
+ const body = {
210
+ conversationId,
211
+ visitorId,
212
+ defaultTimelineItems: params.defaultTimelineItems || [],
213
+ channel: params.channel || "widget"
214
+ };
215
+ const headers = {};
216
+ if (visitorId) headers["X-Visitor-Id"] = visitorId;
217
+ const response = await this.request("/conversations", {
218
+ method: "POST",
219
+ body: JSON.stringify(body),
220
+ headers
221
+ });
222
+ return {
223
+ conversation: {
224
+ ...response.conversation,
225
+ createdAt: response.conversation.createdAt,
226
+ updatedAt: response.conversation.updatedAt,
227
+ deletedAt: response.conversation.deletedAt ?? null,
228
+ lastTimelineItem: response.conversation.lastTimelineItem
229
+ },
230
+ initialTimelineItems: response.initialTimelineItems
231
+ };
232
+ }
233
+ async updateConfiguration(config) {
234
+ if (config.publicKey) {
235
+ this.publicKey = config.publicKey;
236
+ this.baseHeaders["X-Public-Key"] = config.publicKey;
237
+ }
238
+ if (config.userId) this.baseHeaders["X-User-ID"] = config.userId;
239
+ else if (config.userId === null) {
240
+ const { "X-User-ID": _,...rest } = this.baseHeaders;
241
+ this.baseHeaders = rest;
242
+ }
243
+ if (config.organizationId) this.baseHeaders["X-Organization-ID"] = config.organizationId;
244
+ else if (config.organizationId === null) {
245
+ const { "X-Organization-ID": _,...rest } = this.baseHeaders;
246
+ this.baseHeaders = rest;
247
+ }
248
+ this.config = {
249
+ ...this.config,
250
+ ...config
251
+ };
252
+ }
253
+ async listConversations(params = {}) {
254
+ const storedVisitorId = this.websiteId ? getVisitorId(this.websiteId) : void 0;
255
+ const visitorId = params.visitorId || storedVisitorId;
256
+ if (!visitorId) throw new Error("Visitor ID is required");
257
+ const queryParams = new URLSearchParams();
258
+ if (visitorId) queryParams.set("visitorId", visitorId);
259
+ if (params.page) queryParams.set("page", params.page.toString());
260
+ if (params.limit) queryParams.set("limit", params.limit.toString());
261
+ if (params.status) queryParams.set("status", params.status);
262
+ if (params.orderBy) queryParams.set("orderBy", params.orderBy);
263
+ if (params.order) queryParams.set("order", params.order);
264
+ const headers = {};
265
+ if (visitorId) headers["X-Visitor-Id"] = visitorId;
266
+ const response = await this.request(`/conversations?${queryParams.toString()}`, { headers });
267
+ return {
268
+ conversations: response.conversations.map((conv) => ({
269
+ ...conv,
270
+ createdAt: conv.createdAt,
271
+ updatedAt: conv.updatedAt,
272
+ deletedAt: conv.deletedAt ?? null,
273
+ lastTimelineItem: conv.lastTimelineItem
274
+ })),
275
+ pagination: response.pagination
276
+ };
277
+ }
278
+ async getConversation(params) {
279
+ const visitorId = this.websiteId ? getVisitorId(this.websiteId) : void 0;
280
+ const headers = {};
281
+ if (visitorId) headers["X-Visitor-Id"] = visitorId;
282
+ const response = await this.request(`/conversations/${params.conversationId}`, { headers });
283
+ return { conversation: {
284
+ ...response.conversation,
285
+ createdAt: response.conversation.createdAt,
286
+ updatedAt: response.conversation.updatedAt,
287
+ deletedAt: response.conversation.deletedAt ?? null,
288
+ lastTimelineItem: response.conversation.lastTimelineItem
289
+ } };
290
+ }
291
+ async markConversationSeen(params) {
292
+ const storedVisitorId = this.websiteId ? getVisitorId(this.websiteId) : void 0;
293
+ const visitorId = params.visitorId || storedVisitorId;
294
+ if (!visitorId) throw new Error("Visitor ID is required to mark a conversation as seen");
295
+ const headers = {};
296
+ if (visitorId) headers["X-Visitor-Id"] = visitorId;
297
+ const body = {};
298
+ if (params.visitorId) body.visitorId = params.visitorId;
299
+ const response = await this.request(`/conversations/${params.conversationId}/seen`, {
300
+ method: "POST",
301
+ body: JSON.stringify(body),
302
+ headers
303
+ });
304
+ return {
305
+ conversationId: response.conversationId,
306
+ lastSeenAt: response.lastSeenAt
307
+ };
308
+ }
309
+ async getConversationSeenData(params) {
310
+ return { seenData: (await this.request(`/conversations/${params.conversationId}/seen`, { method: "GET" })).seenData.map((item) => ({
311
+ ...item,
312
+ lastSeenAt: item.lastSeenAt,
313
+ createdAt: item.createdAt,
314
+ updatedAt: item.updatedAt,
315
+ deletedAt: item.deletedAt ? item.deletedAt : null
316
+ })) };
317
+ }
318
+ async setConversationTyping(params) {
319
+ const storedVisitorId = this.websiteId ? getVisitorId(this.websiteId) : void 0;
320
+ const visitorId = params.visitorId || storedVisitorId;
321
+ if (!visitorId) throw new Error("Visitor ID is required to report typing state");
322
+ const headers = {};
323
+ if (visitorId) headers["X-Visitor-Id"] = visitorId;
324
+ const body = { isTyping: params.isTyping };
325
+ if (params.visitorId) body.visitorId = params.visitorId;
326
+ if (params.visitorPreview && params.isTyping) body.visitorPreview = params.visitorPreview.slice(0, 2e3);
327
+ const response = await this.request(`/conversations/${params.conversationId}/typing`, {
328
+ method: "POST",
329
+ body: JSON.stringify(body),
330
+ headers
331
+ });
332
+ return {
333
+ conversationId: response.conversationId,
334
+ isTyping: response.isTyping,
335
+ visitorPreview: response.visitorPreview,
336
+ sentAt: response.sentAt
337
+ };
338
+ }
339
+ async sendMessage(params) {
340
+ const visitorId = this.websiteId ? getVisitorId(this.websiteId) : void 0;
341
+ const headers = {};
342
+ if (visitorId) headers["X-Visitor-Id"] = visitorId;
343
+ return { item: (await this.request("/messages", {
344
+ method: "POST",
345
+ body: JSON.stringify(params),
346
+ headers
347
+ })).item };
348
+ }
349
+ async getConversationTimelineItems(params) {
350
+ const visitorId = this.websiteId ? getVisitorId(this.websiteId) : void 0;
351
+ const queryParams = new URLSearchParams();
352
+ if (params.limit) queryParams.set("limit", params.limit.toString());
353
+ if (params.cursor) queryParams.set("cursor", params.cursor);
354
+ const headers = {};
355
+ if (visitorId) headers["X-Visitor-Id"] = visitorId;
356
+ const response = await this.request(`/conversations/${params.conversationId}/timeline?${queryParams.toString()}`, { headers });
357
+ return {
358
+ items: response.items,
359
+ nextCursor: response.nextCursor,
360
+ hasNextPage: response.hasNextPage
361
+ };
362
+ }
363
+ };
364
+
365
+ //#endregion
366
+ export { CossistantRestClient };
367
+ //# sourceMappingURL=rest-client.js.map