imessage-sdk 0.1.0-beta.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/index.js ADDED
@@ -0,0 +1,438 @@
1
+ // src/core/conversation-id.ts
2
+ var FALLBACK_CONVERSATION_ID_PREFIX = "imsg-sdk-v1-";
3
+ function createFallbackConversationId(message, timestamp) {
4
+ if (message.length === 0) {
5
+ throw new TypeError("Fallback conversation message must not be empty.");
6
+ }
7
+ if (Number.isNaN(timestamp.getTime())) {
8
+ throw new TypeError("Fallback conversation timestamp must be valid.");
9
+ }
10
+ const payload = {
11
+ message,
12
+ timestamp: timestamp.toISOString()
13
+ };
14
+ const encoded = Buffer.from(JSON.stringify(payload), "utf8").toString(
15
+ "base64url"
16
+ );
17
+ return `${FALLBACK_CONVERSATION_ID_PREFIX}${encoded}`;
18
+ }
19
+ function isFallbackConversationId(value) {
20
+ return value.startsWith(FALLBACK_CONVERSATION_ID_PREFIX);
21
+ }
22
+
23
+ // src/core/errors.ts
24
+ var IMessageSDKError = class extends Error {
25
+ provider;
26
+ connectionId;
27
+ code;
28
+ statusCode;
29
+ retryable;
30
+ retryAfter;
31
+ traceId;
32
+ raw;
33
+ constructor(message, options = {}) {
34
+ super(message);
35
+ this.name = new.target.name;
36
+ this.provider = options.provider;
37
+ this.connectionId = options.connectionId;
38
+ this.code = options.code;
39
+ this.statusCode = options.statusCode;
40
+ this.retryable = options.retryable ?? false;
41
+ this.retryAfter = options.retryAfter;
42
+ this.traceId = options.traceId;
43
+ this.raw = options.raw;
44
+ }
45
+ };
46
+ var ValidationError = class extends IMessageSDKError {
47
+ };
48
+ var AuthenticationError = class extends IMessageSDKError {
49
+ };
50
+ var NotFoundError = class extends IMessageSDKError {
51
+ };
52
+ var ConflictError = class extends IMessageSDKError {
53
+ };
54
+ var RateLimitError = class extends IMessageSDKError {
55
+ };
56
+ var ProviderUnavailableError = class extends IMessageSDKError {
57
+ };
58
+ var AmbiguousDeliveryError = class extends IMessageSDKError {
59
+ };
60
+ var UnsupportedCapabilityError = class extends IMessageSDKError {
61
+ capability;
62
+ constructor(capability, options = {}) {
63
+ super(`The selected provider does not support ${capability}.`, {
64
+ ...options,
65
+ code: "unsupported_capability"
66
+ });
67
+ this.capability = capability;
68
+ }
69
+ };
70
+ var WebhookVerificationError = class extends IMessageSDKError {
71
+ constructor(options = {}) {
72
+ super("Webhook signature verification failed.", {
73
+ ...options,
74
+ code: "webhook_verification_failed"
75
+ });
76
+ }
77
+ };
78
+ var ClientClosedError = class extends IMessageSDKError {
79
+ constructor(options = {}) {
80
+ super("This iMessage client has already been closed.", {
81
+ ...options,
82
+ code: "client_closed"
83
+ });
84
+ }
85
+ };
86
+
87
+ // src/core/client.ts
88
+ var DEFAULT_CONNECTION_ID = "default";
89
+ function validateProvider(provider) {
90
+ const capabilities = provider.capabilities;
91
+ const requirements = [
92
+ [capabilities.messages.get, provider.messages.get, "messages.get"],
93
+ [capabilities.messages.edit, provider.messages.edit, "messages.edit"],
94
+ [capabilities.messages.delete, provider.messages.delete, "messages.delete"],
95
+ [
96
+ capabilities.conversations.get,
97
+ provider.conversations.get,
98
+ "conversations.get"
99
+ ],
100
+ [
101
+ capabilities.conversations.markRead,
102
+ provider.conversations.markRead,
103
+ "conversations.markRead"
104
+ ],
105
+ [capabilities.interactions.reactions, provider.reactions, "reactions"],
106
+ [capabilities.interactions.typingStart, provider.typing, "typing.start"],
107
+ [
108
+ capabilities.interactions.typingStop,
109
+ provider.typing?.stop,
110
+ "typing.stop"
111
+ ],
112
+ [capabilities.events.webhooks, provider.webhooks, "webhooks"],
113
+ [capabilities.events.stream, provider.events, "events.subscribe"]
114
+ ];
115
+ for (const [enabled, implementation, capability] of requirements) {
116
+ if (enabled && implementation === void 0) {
117
+ throw new ValidationError(
118
+ `Provider ${provider.name} declares ${capability} but does not implement it.`,
119
+ { provider: provider.name, code: "invalid_provider_contract" }
120
+ );
121
+ }
122
+ }
123
+ }
124
+ function decorateMessage(message, provider, connectionId) {
125
+ return {
126
+ ...message,
127
+ id: message.providerMessageId,
128
+ conversationId: message.conversationId ?? createFallbackConversationId(
129
+ message.providerMessageId,
130
+ message.createdAt
131
+ ),
132
+ provider,
133
+ connectionId
134
+ };
135
+ }
136
+ function decorateConversation(conversation, provider, connectionId) {
137
+ return {
138
+ ...conversation,
139
+ id: conversation.providerConversationId,
140
+ provider,
141
+ connectionId
142
+ };
143
+ }
144
+ function decorateEvent(event, provider, connectionId) {
145
+ switch (event.type) {
146
+ case "message.received":
147
+ case "message.sent":
148
+ case "message.delivered":
149
+ case "message.read":
150
+ case "message.failed":
151
+ case "message.edited":
152
+ return {
153
+ ...event,
154
+ provider,
155
+ connectionId,
156
+ message: decorateMessage(event.message, provider, connectionId)
157
+ };
158
+ case "message.deleted":
159
+ case "reaction.added":
160
+ case "reaction.removed":
161
+ case "typing.started":
162
+ case "typing.stopped":
163
+ return { ...event, provider, connectionId };
164
+ }
165
+ }
166
+ function mapEvents(events, provider, connectionId) {
167
+ return {
168
+ async *[Symbol.asyncIterator]() {
169
+ for await (const event of events) {
170
+ yield decorateEvent(event, provider, connectionId);
171
+ }
172
+ }
173
+ };
174
+ }
175
+ function createIMessageClient(options) {
176
+ const { provider } = options;
177
+ const connectionId = options.connectionId ?? DEFAULT_CONNECTION_ID;
178
+ if (connectionId.trim().length === 0) {
179
+ throw new ValidationError("connectionId must not be empty.", {
180
+ provider: provider.name,
181
+ code: "invalid_connection_id"
182
+ });
183
+ }
184
+ validateProvider(provider);
185
+ let closed = false;
186
+ let closePromise;
187
+ const errorContext = {
188
+ provider: provider.name,
189
+ connectionId
190
+ };
191
+ const assertOpen = () => {
192
+ if (closed) {
193
+ throw new ClientClosedError(errorContext);
194
+ }
195
+ };
196
+ const unsupported = (capability) => {
197
+ throw new UnsupportedCapabilityError(capability, errorContext);
198
+ };
199
+ const assertRoutableConversationId = (conversationId) => {
200
+ if (isFallbackConversationId(conversationId)) {
201
+ throw new ValidationError(
202
+ "SDK fallback conversation IDs are diagnostic and cannot be used for provider operations.",
203
+ { ...errorContext, code: "non_routable_conversation_id" }
204
+ );
205
+ }
206
+ };
207
+ const requireImplementation = (implementation, capability) => {
208
+ if (implementation === void 0) {
209
+ throw new UnsupportedCapabilityError(capability, errorContext);
210
+ }
211
+ return implementation;
212
+ };
213
+ const providers = Object.freeze({
214
+ [provider.name]: provider
215
+ });
216
+ return {
217
+ provider: provider.name,
218
+ connectionId,
219
+ capabilities: provider.capabilities,
220
+ providers,
221
+ messages: {
222
+ async send(input) {
223
+ assertOpen();
224
+ if (input.conversationId !== void 0) {
225
+ assertRoutableConversationId(input.conversationId);
226
+ }
227
+ if (input.text !== void 0 && !provider.capabilities.messages.text) {
228
+ unsupported("messages.text");
229
+ }
230
+ if (input.attachments !== void 0 && input.attachments.length > 0 && !provider.capabilities.messages.attachments) {
231
+ unsupported("messages.attachments");
232
+ }
233
+ if (input.replyTo !== void 0 && !provider.capabilities.messages.replies) {
234
+ unsupported("messages.replies");
235
+ }
236
+ if (input.to !== void 0) {
237
+ const recipients = Array.isArray(input.to) ? input.to : [input.to];
238
+ const isGroup = recipients.length > 1;
239
+ if (isGroup && !provider.capabilities.conversations.groups) {
240
+ unsupported("conversations.groups");
241
+ }
242
+ if (!isGroup && !provider.capabilities.conversations.direct) {
243
+ unsupported("conversations.direct");
244
+ }
245
+ }
246
+ const message = await provider.messages.send(input);
247
+ return decorateMessage(message, provider.name, connectionId);
248
+ },
249
+ async get(message) {
250
+ assertOpen();
251
+ assertRoutableConversationId(message.conversationId);
252
+ if (!provider.capabilities.messages.get) {
253
+ unsupported("messages.get");
254
+ }
255
+ const get = requireImplementation(
256
+ provider.messages.get,
257
+ "messages.get"
258
+ );
259
+ const result = await get.call(provider.messages, message);
260
+ return result === null ? null : decorateMessage(result, provider.name, connectionId);
261
+ },
262
+ async edit(message, input) {
263
+ assertOpen();
264
+ assertRoutableConversationId(message.conversationId);
265
+ if (!provider.capabilities.messages.edit) {
266
+ unsupported("messages.edit");
267
+ }
268
+ const edit = requireImplementation(
269
+ provider.messages.edit,
270
+ "messages.edit"
271
+ );
272
+ const result = await edit.call(provider.messages, message, input);
273
+ return decorateMessage(result, provider.name, connectionId);
274
+ },
275
+ async delete(message) {
276
+ assertOpen();
277
+ assertRoutableConversationId(message.conversationId);
278
+ if (!provider.capabilities.messages.delete) {
279
+ unsupported("messages.delete");
280
+ }
281
+ const deleteMessage = requireImplementation(
282
+ provider.messages.delete,
283
+ "messages.delete"
284
+ );
285
+ await deleteMessage.call(provider.messages, message);
286
+ }
287
+ },
288
+ conversations: {
289
+ async open(input) {
290
+ assertOpen();
291
+ const isGroup = input.participants.length > 1;
292
+ if (isGroup && !provider.capabilities.conversations.groups) {
293
+ unsupported("conversations.groups");
294
+ }
295
+ if (!isGroup && !provider.capabilities.conversations.direct) {
296
+ unsupported("conversations.direct");
297
+ }
298
+ const conversation = await provider.conversations.open(input);
299
+ return decorateConversation(
300
+ conversation,
301
+ provider.name,
302
+ connectionId
303
+ );
304
+ },
305
+ async get(conversationId) {
306
+ assertOpen();
307
+ assertRoutableConversationId(conversationId);
308
+ if (!provider.capabilities.conversations.get) {
309
+ unsupported("conversations.get");
310
+ }
311
+ const get = requireImplementation(
312
+ provider.conversations.get,
313
+ "conversations.get"
314
+ );
315
+ const conversation = await get.call(
316
+ provider.conversations,
317
+ conversationId
318
+ );
319
+ return conversation === null ? null : decorateConversation(conversation, provider.name, connectionId);
320
+ },
321
+ async markRead(conversationId) {
322
+ assertOpen();
323
+ assertRoutableConversationId(conversationId);
324
+ if (!provider.capabilities.conversations.markRead) {
325
+ unsupported("conversations.markRead");
326
+ }
327
+ const markRead = requireImplementation(
328
+ provider.conversations.markRead,
329
+ "conversations.markRead"
330
+ );
331
+ await markRead.call(provider.conversations, conversationId);
332
+ }
333
+ },
334
+ reactions: {
335
+ async add(input) {
336
+ assertOpen();
337
+ assertRoutableConversationId(input.conversationId);
338
+ if (!provider.capabilities.interactions.reactions) {
339
+ unsupported("reactions.add");
340
+ }
341
+ const reactions = requireImplementation(
342
+ provider.reactions,
343
+ "reactions.add"
344
+ );
345
+ await reactions.add(input);
346
+ },
347
+ async remove(input) {
348
+ assertOpen();
349
+ assertRoutableConversationId(input.conversationId);
350
+ if (!provider.capabilities.interactions.reactions) {
351
+ unsupported("reactions.remove");
352
+ }
353
+ const reactions = requireImplementation(
354
+ provider.reactions,
355
+ "reactions.remove"
356
+ );
357
+ await reactions.remove(input);
358
+ }
359
+ },
360
+ typing: {
361
+ async start(conversationId) {
362
+ assertOpen();
363
+ assertRoutableConversationId(conversationId);
364
+ if (!provider.capabilities.interactions.typingStart) {
365
+ unsupported("typing.start");
366
+ }
367
+ const typing = requireImplementation(provider.typing, "typing.start");
368
+ await typing.start(conversationId);
369
+ },
370
+ async stop(conversationId) {
371
+ assertOpen();
372
+ assertRoutableConversationId(conversationId);
373
+ if (!provider.capabilities.interactions.typingStop) {
374
+ unsupported("typing.stop");
375
+ }
376
+ const typing = requireImplementation(provider.typing, "typing.stop");
377
+ const stop = requireImplementation(typing.stop, "typing.stop");
378
+ await stop.call(typing, conversationId);
379
+ }
380
+ },
381
+ webhooks: {
382
+ async handle(request) {
383
+ assertOpen();
384
+ if (!provider.capabilities.events.webhooks) {
385
+ unsupported("webhooks.handle");
386
+ }
387
+ const webhooks = requireImplementation(
388
+ provider.webhooks,
389
+ "webhooks.handle"
390
+ );
391
+ const verified = await webhooks.verify(request.clone());
392
+ if (!verified) {
393
+ throw new WebhookVerificationError(errorContext);
394
+ }
395
+ const events = await webhooks.parse(request);
396
+ return events.map(
397
+ (event) => decorateEvent(event, provider.name, connectionId)
398
+ );
399
+ }
400
+ },
401
+ events: {
402
+ subscribe(options2) {
403
+ assertOpen();
404
+ if (!provider.capabilities.events.stream) {
405
+ unsupported("events.subscribe");
406
+ }
407
+ const events = requireImplementation(
408
+ provider.events,
409
+ "events.subscribe"
410
+ );
411
+ return mapEvents(
412
+ events.subscribe(options2),
413
+ provider.name,
414
+ connectionId
415
+ );
416
+ }
417
+ },
418
+ close() {
419
+ if (closePromise !== void 0) {
420
+ return closePromise;
421
+ }
422
+ closed = true;
423
+ closePromise = Promise.resolve().then(
424
+ async () => await provider.close?.()
425
+ );
426
+ return closePromise;
427
+ }
428
+ };
429
+ }
430
+
431
+ // src/core/provider.ts
432
+ function defineProvider(provider) {
433
+ return provider;
434
+ }
435
+
436
+ export { AmbiguousDeliveryError, AuthenticationError, ClientClosedError, ConflictError, DEFAULT_CONNECTION_ID, IMessageSDKError, NotFoundError, ProviderUnavailableError, RateLimitError, UnsupportedCapabilityError, ValidationError, WebhookVerificationError, createFallbackConversationId, createIMessageClient, defineProvider, isFallbackConversationId };
437
+ //# sourceMappingURL=index.js.map
438
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/conversation-id.ts","../src/core/errors.ts","../src/core/client.ts","../src/core/provider.ts"],"names":["options"],"mappings":"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","file":"index.js","sourcesContent":["const FALLBACK_CONVERSATION_ID_PREFIX = \"imsg-sdk-v1-\";\n\ninterface FallbackConversationIdPayload {\n readonly message: string;\n readonly timestamp: string;\n}\n\n/**\n * Creates a diagnostic fallback when a provider message omits its native\n * conversation ID. Fallback IDs are stable for the same message and timestamp,\n * but are not provider-routable conversation handles.\n */\nexport function createFallbackConversationId(\n message: string,\n timestamp: Date,\n): string {\n if (message.length === 0) {\n throw new TypeError(\"Fallback conversation message must not be empty.\");\n }\n if (Number.isNaN(timestamp.getTime())) {\n throw new TypeError(\"Fallback conversation timestamp must be valid.\");\n }\n\n const payload: FallbackConversationIdPayload = {\n message,\n timestamp: timestamp.toISOString(),\n };\n const encoded = Buffer.from(JSON.stringify(payload), \"utf8\").toString(\n \"base64url\",\n );\n return `${FALLBACK_CONVERSATION_ID_PREFIX}${encoded}`;\n}\n\nexport function isFallbackConversationId(value: string): boolean {\n return value.startsWith(FALLBACK_CONVERSATION_ID_PREFIX);\n}\n","export interface IMessageSDKErrorOptions {\n readonly provider?: string;\n readonly connectionId?: string;\n readonly code?: string;\n readonly statusCode?: number;\n readonly retryable?: boolean;\n readonly retryAfter?: number;\n readonly traceId?: string;\n readonly raw?: unknown;\n}\n\nexport class IMessageSDKError extends Error {\n readonly provider: string | undefined;\n readonly connectionId: string | undefined;\n readonly code: string | undefined;\n readonly statusCode: number | undefined;\n readonly retryable: boolean;\n readonly retryAfter: number | undefined;\n readonly traceId: string | undefined;\n readonly raw: unknown;\n\n constructor(message: string, options: IMessageSDKErrorOptions = {}) {\n super(message);\n this.name = new.target.name;\n this.provider = options.provider;\n this.connectionId = options.connectionId;\n this.code = options.code;\n this.statusCode = options.statusCode;\n this.retryable = options.retryable ?? false;\n this.retryAfter = options.retryAfter;\n this.traceId = options.traceId;\n this.raw = options.raw;\n }\n}\n\nexport class ValidationError extends IMessageSDKError {}\n\nexport class AuthenticationError extends IMessageSDKError {}\n\nexport class NotFoundError extends IMessageSDKError {}\n\nexport class ConflictError extends IMessageSDKError {}\n\nexport class RateLimitError extends IMessageSDKError {}\n\nexport class ProviderUnavailableError extends IMessageSDKError {}\n\n/** A send may have reached the provider, so blindly retrying could duplicate it. */\nexport class AmbiguousDeliveryError extends IMessageSDKError {}\n\nexport class UnsupportedCapabilityError extends IMessageSDKError {\n readonly capability: string;\n\n constructor(\n capability: string,\n options: Pick<IMessageSDKErrorOptions, \"provider\" | \"connectionId\"> = {},\n ) {\n super(`The selected provider does not support ${capability}.`, {\n ...options,\n code: \"unsupported_capability\",\n });\n this.capability = capability;\n }\n}\n\nexport class WebhookVerificationError extends IMessageSDKError {\n constructor(\n options: Pick<IMessageSDKErrorOptions, \"provider\" | \"connectionId\"> = {},\n ) {\n super(\"Webhook signature verification failed.\", {\n ...options,\n code: \"webhook_verification_failed\",\n });\n }\n}\n\nexport class ClientClosedError extends IMessageSDKError {\n constructor(\n options: Pick<IMessageSDKErrorOptions, \"provider\" | \"connectionId\"> = {},\n ) {\n super(\"This iMessage client has already been closed.\", {\n ...options,\n code: \"client_closed\",\n });\n }\n}\n","import {\n ClientClosedError,\n UnsupportedCapabilityError,\n ValidationError,\n WebhookVerificationError,\n} from \"./errors.js\";\nimport {\n createFallbackConversationId,\n isFallbackConversationId,\n} from \"./conversation-id.js\";\nimport type { IMessageEvent, ProviderEvent } from \"./events.js\";\nimport type { AnyIMessageProvider } from \"./provider.js\";\nimport type {\n AddReactionInput,\n Conversation,\n EditMessageInput,\n IMessageProviderName,\n Message,\n MessageLocator,\n OpenConversationInput,\n ProviderConversation,\n ProviderMessage,\n RemoveReactionInput,\n SendMessageInput,\n SentMessage,\n SubscribeOptions,\n} from \"./types.js\";\n\ntype ProviderNameOf<TProvider extends AnyIMessageProvider> = TProvider[\"name\"];\n\nexport const DEFAULT_CONNECTION_ID = \"default\" as const;\n\nexport type ClientProvider<TProvider extends AnyIMessageProvider> = TProvider;\n\nexport type ClientProviders<TProvider extends AnyIMessageProvider> = {\n readonly [TName in TProvider[\"name\"]]: ClientProvider<\n Extract<TProvider, { readonly name: TName }>\n >;\n};\n\nexport interface IMessageClient<\n TProvider extends AnyIMessageProvider = AnyIMessageProvider,\n TConnectionId extends string = string,\n> {\n readonly provider: ProviderNameOf<TProvider>;\n readonly connectionId: TConnectionId;\n readonly capabilities: TProvider[\"capabilities\"];\n readonly providers: ClientProviders<TProvider>;\n\n readonly messages: {\n send(\n input: SendMessageInput,\n ): Promise<SentMessage<ProviderNameOf<TProvider>, TConnectionId>>;\n get(message: MessageLocator): Promise<\n Message<ProviderNameOf<TProvider>, TConnectionId> | null\n >;\n edit(\n message: MessageLocator,\n input: EditMessageInput,\n ): Promise<Message<ProviderNameOf<TProvider>, TConnectionId>>;\n delete(message: MessageLocator): Promise<void>;\n };\n\n readonly conversations: {\n open(\n input: OpenConversationInput,\n ): Promise<Conversation<ProviderNameOf<TProvider>, TConnectionId>>;\n get(\n conversationId: string,\n ): Promise<Conversation<ProviderNameOf<TProvider>, TConnectionId> | null>;\n markRead(conversationId: string): Promise<void>;\n };\n\n readonly reactions: {\n add(input: AddReactionInput): Promise<void>;\n remove(input: RemoveReactionInput): Promise<void>;\n };\n\n readonly typing: {\n start(conversationId: string): Promise<void>;\n stop(conversationId: string): Promise<void>;\n };\n\n readonly webhooks: {\n handle(\n request: Request,\n ): Promise<\n readonly IMessageEvent<ProviderNameOf<TProvider>, TConnectionId>[]\n >;\n };\n\n readonly events: {\n subscribe(\n options?: SubscribeOptions,\n ): AsyncIterable<IMessageEvent<ProviderNameOf<TProvider>, TConnectionId>>;\n };\n\n close(): Promise<void>;\n}\n\nexport interface CreateIMessageClientOptions<\n TProvider extends AnyIMessageProvider,\n TConnectionId extends string = typeof DEFAULT_CONNECTION_ID,\n> {\n readonly connectionId?: TConnectionId;\n readonly provider: TProvider;\n}\n\nfunction validateProvider(provider: AnyIMessageProvider): void {\n const capabilities = provider.capabilities;\n\n const requirements: readonly [boolean, unknown, string][] = [\n [capabilities.messages.get, provider.messages.get, \"messages.get\"],\n [capabilities.messages.edit, provider.messages.edit, \"messages.edit\"],\n [capabilities.messages.delete, provider.messages.delete, \"messages.delete\"],\n [\n capabilities.conversations.get,\n provider.conversations.get,\n \"conversations.get\",\n ],\n [\n capabilities.conversations.markRead,\n provider.conversations.markRead,\n \"conversations.markRead\",\n ],\n [capabilities.interactions.reactions, provider.reactions, \"reactions\"],\n [capabilities.interactions.typingStart, provider.typing, \"typing.start\"],\n [\n capabilities.interactions.typingStop,\n provider.typing?.stop,\n \"typing.stop\",\n ],\n [capabilities.events.webhooks, provider.webhooks, \"webhooks\"],\n [capabilities.events.stream, provider.events, \"events.subscribe\"],\n ];\n\n for (const [enabled, implementation, capability] of requirements) {\n if (enabled && implementation === undefined) {\n throw new ValidationError(\n `Provider ${provider.name} declares ${capability} but does not implement it.`,\n { provider: provider.name, code: \"invalid_provider_contract\" },\n );\n }\n }\n}\n\nfunction decorateMessage<\n TProvider extends IMessageProviderName,\n TConnectionId extends string,\n>(\n message: ProviderMessage,\n provider: TProvider,\n connectionId: TConnectionId,\n): Message<TProvider, TConnectionId> {\n return {\n ...message,\n id: message.providerMessageId,\n conversationId:\n message.conversationId ??\n createFallbackConversationId(\n message.providerMessageId,\n message.createdAt,\n ),\n provider,\n connectionId,\n };\n}\n\nfunction decorateConversation<\n TProvider extends IMessageProviderName,\n TConnectionId extends string,\n>(\n conversation: ProviderConversation,\n provider: TProvider,\n connectionId: TConnectionId,\n): Conversation<TProvider, TConnectionId> {\n return {\n ...conversation,\n id: conversation.providerConversationId,\n provider,\n connectionId,\n };\n}\n\nfunction decorateEvent<\n TProvider extends IMessageProviderName,\n TConnectionId extends string,\n>(\n event: ProviderEvent,\n provider: TProvider,\n connectionId: TConnectionId,\n): IMessageEvent<TProvider, TConnectionId> {\n switch (event.type) {\n case \"message.received\":\n case \"message.sent\":\n case \"message.delivered\":\n case \"message.read\":\n case \"message.failed\":\n case \"message.edited\":\n return {\n ...event,\n provider,\n connectionId,\n message: decorateMessage(event.message, provider, connectionId),\n };\n case \"message.deleted\":\n case \"reaction.added\":\n case \"reaction.removed\":\n case \"typing.started\":\n case \"typing.stopped\":\n return { ...event, provider, connectionId };\n }\n}\n\nfunction mapEvents<\n TProvider extends IMessageProviderName,\n TConnectionId extends string,\n>(\n events: AsyncIterable<ProviderEvent>,\n provider: TProvider,\n connectionId: TConnectionId,\n): AsyncIterable<IMessageEvent<TProvider, TConnectionId>> {\n return {\n async *[Symbol.asyncIterator]() {\n for await (const event of events) {\n yield decorateEvent(event, provider, connectionId);\n }\n },\n };\n}\n\nexport function createIMessageClient<\n const TProvider extends AnyIMessageProvider,\n const TConnectionId extends string = typeof DEFAULT_CONNECTION_ID,\n>(\n options: CreateIMessageClientOptions<TProvider, TConnectionId>,\n): IMessageClient<TProvider, TConnectionId> {\n const { provider } = options;\n const connectionId = (options.connectionId ??\n DEFAULT_CONNECTION_ID) as TConnectionId;\n\n if (connectionId.trim().length === 0) {\n throw new ValidationError(\"connectionId must not be empty.\", {\n provider: provider.name,\n code: \"invalid_connection_id\",\n });\n }\n\n validateProvider(provider);\n\n let closed = false;\n let closePromise: Promise<void> | undefined;\n\n const errorContext = {\n provider: provider.name,\n connectionId,\n } as const;\n\n const assertOpen = (): void => {\n if (closed) {\n throw new ClientClosedError(errorContext);\n }\n };\n\n const unsupported = (capability: string): never => {\n throw new UnsupportedCapabilityError(capability, errorContext);\n };\n\n const assertRoutableConversationId = (conversationId: string): void => {\n if (isFallbackConversationId(conversationId)) {\n throw new ValidationError(\n \"SDK fallback conversation IDs are diagnostic and cannot be used for provider operations.\",\n { ...errorContext, code: \"non_routable_conversation_id\" },\n );\n }\n };\n\n const requireImplementation = <T>(\n implementation: T | undefined,\n capability: string,\n ): T => {\n if (implementation === undefined) {\n throw new UnsupportedCapabilityError(capability, errorContext);\n }\n\n return implementation;\n };\n\n const providers = Object.freeze({\n [provider.name]: provider,\n }) as ClientProviders<TProvider>;\n\n return {\n provider: provider.name,\n connectionId,\n capabilities: provider.capabilities,\n providers,\n messages: {\n async send(input) {\n assertOpen();\n\n if (input.conversationId !== undefined) {\n assertRoutableConversationId(input.conversationId);\n }\n\n if (input.text !== undefined && !provider.capabilities.messages.text) {\n unsupported(\"messages.text\");\n }\n\n if (\n input.attachments !== undefined &&\n input.attachments.length > 0 &&\n !provider.capabilities.messages.attachments\n ) {\n unsupported(\"messages.attachments\");\n }\n\n if (\n input.replyTo !== undefined &&\n !provider.capabilities.messages.replies\n ) {\n unsupported(\"messages.replies\");\n }\n\n if (input.to !== undefined) {\n const recipients = Array.isArray(input.to) ? input.to : [input.to];\n const isGroup = recipients.length > 1;\n\n if (isGroup && !provider.capabilities.conversations.groups) {\n unsupported(\"conversations.groups\");\n }\n\n if (!isGroup && !provider.capabilities.conversations.direct) {\n unsupported(\"conversations.direct\");\n }\n }\n\n const message = await provider.messages.send(input);\n return decorateMessage(message, provider.name, connectionId) as SentMessage<\n ProviderNameOf<TProvider>,\n TConnectionId\n >;\n },\n async get(message) {\n assertOpen();\n assertRoutableConversationId(message.conversationId);\n\n if (!provider.capabilities.messages.get) {\n unsupported(\"messages.get\");\n }\n\n const get = requireImplementation(\n provider.messages.get,\n \"messages.get\",\n );\n\n const result = await get.call(provider.messages, message);\n return result === null\n ? null\n : decorateMessage(result, provider.name, connectionId);\n },\n async edit(message, input) {\n assertOpen();\n assertRoutableConversationId(message.conversationId);\n\n if (!provider.capabilities.messages.edit) {\n unsupported(\"messages.edit\");\n }\n\n const edit = requireImplementation(\n provider.messages.edit,\n \"messages.edit\",\n );\n\n const result = await edit.call(provider.messages, message, input);\n return decorateMessage(result, provider.name, connectionId);\n },\n async delete(message) {\n assertOpen();\n assertRoutableConversationId(message.conversationId);\n\n if (!provider.capabilities.messages.delete) {\n unsupported(\"messages.delete\");\n }\n\n const deleteMessage = requireImplementation(\n provider.messages.delete,\n \"messages.delete\",\n );\n\n await deleteMessage.call(provider.messages, message);\n },\n },\n conversations: {\n async open(input) {\n assertOpen();\n const isGroup = input.participants.length > 1;\n\n if (isGroup && !provider.capabilities.conversations.groups) {\n unsupported(\"conversations.groups\");\n }\n\n if (!isGroup && !provider.capabilities.conversations.direct) {\n unsupported(\"conversations.direct\");\n }\n\n const conversation = await provider.conversations.open(input);\n return decorateConversation(\n conversation,\n provider.name,\n connectionId,\n );\n },\n async get(conversationId) {\n assertOpen();\n assertRoutableConversationId(conversationId);\n\n if (!provider.capabilities.conversations.get) {\n unsupported(\"conversations.get\");\n }\n\n const get = requireImplementation(\n provider.conversations.get,\n \"conversations.get\",\n );\n\n const conversation = await get.call(\n provider.conversations,\n conversationId,\n );\n return conversation === null\n ? null\n : decorateConversation(conversation, provider.name, connectionId);\n },\n async markRead(conversationId) {\n assertOpen();\n assertRoutableConversationId(conversationId);\n\n if (!provider.capabilities.conversations.markRead) {\n unsupported(\"conversations.markRead\");\n }\n\n const markRead = requireImplementation(\n provider.conversations.markRead,\n \"conversations.markRead\",\n );\n await markRead.call(provider.conversations, conversationId);\n },\n },\n reactions: {\n async add(input) {\n assertOpen();\n assertRoutableConversationId(input.conversationId);\n\n if (!provider.capabilities.interactions.reactions) {\n unsupported(\"reactions.add\");\n }\n\n const reactions = requireImplementation(\n provider.reactions,\n \"reactions.add\",\n );\n\n await reactions.add(input);\n },\n async remove(input) {\n assertOpen();\n assertRoutableConversationId(input.conversationId);\n\n if (!provider.capabilities.interactions.reactions) {\n unsupported(\"reactions.remove\");\n }\n\n const reactions = requireImplementation(\n provider.reactions,\n \"reactions.remove\",\n );\n\n await reactions.remove(input);\n },\n },\n typing: {\n async start(conversationId) {\n assertOpen();\n assertRoutableConversationId(conversationId);\n\n if (!provider.capabilities.interactions.typingStart) {\n unsupported(\"typing.start\");\n }\n\n const typing = requireImplementation(provider.typing, \"typing.start\");\n\n await typing.start(conversationId);\n },\n async stop(conversationId) {\n assertOpen();\n assertRoutableConversationId(conversationId);\n\n if (!provider.capabilities.interactions.typingStop) {\n unsupported(\"typing.stop\");\n }\n\n const typing = requireImplementation(provider.typing, \"typing.stop\");\n const stop = requireImplementation(typing.stop, \"typing.stop\");\n\n await stop.call(typing, conversationId);\n },\n },\n webhooks: {\n async handle(request) {\n assertOpen();\n\n if (!provider.capabilities.events.webhooks) {\n unsupported(\"webhooks.handle\");\n }\n\n const webhooks = requireImplementation(\n provider.webhooks,\n \"webhooks.handle\",\n );\n\n const verified = await webhooks.verify(request.clone());\n if (!verified) {\n throw new WebhookVerificationError(errorContext);\n }\n\n const events = await webhooks.parse(request);\n return events.map((event) =>\n decorateEvent(event, provider.name, connectionId),\n );\n },\n },\n events: {\n subscribe(options) {\n assertOpen();\n\n if (!provider.capabilities.events.stream) {\n unsupported(\"events.subscribe\");\n }\n\n const events = requireImplementation(\n provider.events,\n \"events.subscribe\",\n );\n\n return mapEvents(\n events.subscribe(options),\n provider.name,\n connectionId,\n );\n },\n },\n close() {\n if (closePromise !== undefined) {\n return closePromise;\n }\n\n closed = true;\n closePromise = Promise.resolve().then(\n async () => await provider.close?.(),\n );\n return closePromise;\n },\n };\n}\n","import type { IMessageCapabilities } from \"./capabilities.js\";\nimport type { ProviderEvent } from \"./events.js\";\nimport type {\n AddReactionInput,\n EditMessageInput,\n IMessageProviderName,\n MessageLocator,\n OpenConversationInput,\n ProviderConversation,\n ProviderMessage,\n ProviderSentMessage,\n RemoveReactionInput,\n SendMessageInput,\n SubscribeOptions,\n} from \"./types.js\";\n\nexport interface ProviderMessages {\n send(input: SendMessageInput): Promise<ProviderSentMessage>;\n get?(message: MessageLocator): Promise<ProviderMessage | null>;\n edit?(\n message: MessageLocator,\n input: EditMessageInput,\n ): Promise<ProviderMessage>;\n delete?(message: MessageLocator): Promise<void>;\n}\n\nexport interface ProviderConversations {\n open(input: OpenConversationInput): Promise<ProviderConversation>;\n get?(conversationId: string): Promise<ProviderConversation | null>;\n markRead?(conversationId: string): Promise<void>;\n}\n\nexport interface ProviderReactions {\n add(input: AddReactionInput): Promise<void>;\n remove(input: RemoveReactionInput): Promise<void>;\n}\n\nexport interface ProviderTyping {\n start(conversationId: string): Promise<void>;\n stop?(conversationId: string): Promise<void>;\n}\n\nexport interface ProviderWebhooks {\n verify(request: Request): Promise<boolean>;\n parse(request: Request): Promise<readonly ProviderEvent[]>;\n}\n\nexport interface ProviderEvents {\n subscribe(options?: SubscribeOptions): AsyncIterable<ProviderEvent>;\n}\n\n/**\n * Contract implemented by a provider adapter.\n *\n * The complete adapter is exposed at `client.providers.<name>`, so\n * provider-specific APIs should be defined directly on the concrete provider.\n */\nexport interface IMessageProvider<\n TName extends IMessageProviderName = IMessageProviderName,\n TCapabilities extends IMessageCapabilities = IMessageCapabilities,\n> {\n readonly name: TName;\n readonly capabilities: TCapabilities;\n readonly messages: ProviderMessages;\n readonly conversations: ProviderConversations;\n readonly reactions?: ProviderReactions;\n readonly typing?: ProviderTyping;\n readonly webhooks?: ProviderWebhooks;\n readonly events?: ProviderEvents;\n close?(): Promise<void>;\n}\n\nexport type AnyIMessageProvider = IMessageProvider<\n IMessageProviderName,\n IMessageCapabilities\n>;\n\n/** Preserves the concrete name, capabilities, and methods of an adapter. */\nexport function defineProvider<const TProvider extends AnyIMessageProvider>(\n provider: TProvider,\n): TProvider {\n return provider;\n}\n"]}