@tangle-network/agent-integrations 0.54.0 → 0.54.2
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/conversation-events/index.d.ts +4 -2
- package/dist/conversation-events/index.js +23 -14
- package/dist/conversation-events/index.js.map +1 -1
- package/dist/managed-messaging/index.d.ts +2 -0
- package/dist/managed-messaging/index.js +38 -25
- package/dist/managed-messaging/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -38,13 +38,15 @@ interface ConversationChannel {
|
|
|
38
38
|
declare function listConversationChannels(): ConversationChannel[];
|
|
39
39
|
interface ConversationEndpointOption {
|
|
40
40
|
id: string;
|
|
41
|
+
/** Provider display address. Use id, not a reformatted address, to select a resource. */
|
|
41
42
|
address: string;
|
|
42
43
|
providerId: string;
|
|
43
|
-
channel: 'imessage';
|
|
44
|
+
channel: 'imessage' | 'whatsapp';
|
|
44
45
|
health: 'healthy' | 'at-risk' | 'critical' | 'unknown';
|
|
45
46
|
}
|
|
46
47
|
/** Project an authenticated provider-owned inventory response, not user input.
|
|
47
|
-
* Protocol
|
|
48
|
+
* Protocol shapes stay with the adapters. Unknown provider health remains unknown;
|
|
49
|
+
* configuration, customer eligibility and delivery readiness are separate facts. */
|
|
48
50
|
declare function conversationEndpointOptions(providerId: string, result: unknown): ConversationEndpointOption[];
|
|
49
51
|
|
|
50
52
|
/** Additive provider vocabulary. Neither sender identity nor group membership is authority. */
|
|
@@ -695,29 +695,38 @@ var channels = [
|
|
|
695
695
|
{ providerId: "linq", eventType: "linq.message.received", label: "iMessage / SMS", transport: "imessage", sourceKind: "connection", replies: true, inventoryAction: "linq.numbers.list", replyAction: "linq.messages.reply", numberProvisioning: "provider-assigned" },
|
|
696
696
|
{ providerId: "contiguity", eventType: "contiguity.imessage.incoming", label: "iMessage", transport: "imessage", sourceKind: "connection", replies: true },
|
|
697
697
|
{ providerId: "contiguity", eventType: "contiguity.text.incoming.sms", label: "SMS", transport: "sms", sourceKind: "connection", replies: true },
|
|
698
|
-
{ providerId: "linq-whatsapp", eventType: "linq-whatsapp.message.received", label: "WhatsApp", transport: "whatsapp", sourceKind: "connection", replies: true }
|
|
698
|
+
{ providerId: "linq-whatsapp", eventType: "linq-whatsapp.message.received", label: "WhatsApp", transport: "whatsapp", sourceKind: "connection", replies: true, inventoryAction: "linq-whatsapp.numbers.list", replyAction: "linq-whatsapp.messages.reply" }
|
|
699
699
|
];
|
|
700
700
|
function listConversationChannels() {
|
|
701
701
|
return channels.map((channel) => ({ ...channel }));
|
|
702
702
|
}
|
|
703
|
+
function record2(value) {
|
|
704
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
705
|
+
}
|
|
706
|
+
function bounded(value, max) {
|
|
707
|
+
return typeof value === "string" && value.trim().length > 0 && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
|
|
708
|
+
}
|
|
703
709
|
function conversationEndpointOptions(providerId, result) {
|
|
704
|
-
if (providerId !== "linq") throw new Error("Owned endpoint enumeration is not available for this provider");
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
const values = result.phone_numbers;
|
|
710
|
+
if (providerId !== "linq" && providerId !== "linq-whatsapp") throw new Error("Owned endpoint enumeration is not available for this provider");
|
|
711
|
+
const whatsapp = providerId === "linq-whatsapp";
|
|
712
|
+
const values = record2(result) ? result[whatsapp ? "data" : "phone_numbers"] : null;
|
|
713
|
+
if (!Array.isArray(values)) throw new Error("Provider did not return its owned phone-number inventory");
|
|
709
714
|
if (values.length > 1e3) throw new Error("Phone inventory exceeds the supported response limit");
|
|
710
|
-
const
|
|
715
|
+
const ids = /* @__PURE__ */ new Set(), addresses = /* @__PURE__ */ new Set();
|
|
711
716
|
return values.map((value) => {
|
|
712
|
-
if (!value
|
|
713
|
-
const
|
|
714
|
-
if (
|
|
717
|
+
if (!record2(value)) throw new Error("Invalid phone inventory row");
|
|
718
|
+
const { id: id2, phone_number: address } = value;
|
|
719
|
+
if (!bounded(id2, 256) || !bounded(address, 320) || ids.has(id2) || addresses.has(address)) {
|
|
720
|
+
throw new Error("Invalid or ambiguous owned phone-number identity");
|
|
721
|
+
}
|
|
722
|
+
if (!whatsapp && (!/^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$/i.test(id2) || !/^\+[1-9]\d{6,14}$/.test(address))) {
|
|
715
723
|
throw new Error("Invalid or ambiguous owned phone-number identity");
|
|
716
724
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
const
|
|
720
|
-
|
|
725
|
+
ids.add(id2);
|
|
726
|
+
addresses.add(address);
|
|
727
|
+
const status = whatsapp ? value.quality_band : record2(value.reputation) ? value.reputation.status : void 0;
|
|
728
|
+
const health = status === (whatsapp ? "green" : "HEALTHY") ? "healthy" : status === (whatsapp ? "yellow" : "AT_RISK") ? "at-risk" : status === (whatsapp ? "red" : "CRITICAL") ? "critical" : "unknown";
|
|
729
|
+
return { id: id2, address, providerId, channel: whatsapp ? "whatsapp" : "imessage", health };
|
|
721
730
|
});
|
|
722
731
|
}
|
|
723
732
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/conversation-events/core.ts","../../src/conversation-events/linq-whatsapp.ts","../../src/conversation-events/mobile.ts","../../src/conversation-events/reply.ts","../../src/conversation-events/channels.ts","../../src/conversation-events/index.ts"],"sourcesContent":["import type { TriggerEventCatalog } from '../webhooks/router.js'\n\nexport const MICROSOFT_TEAMS_PROVIDER_ID = 'microsoft-teams' as const\nexport const MICROSOFT_TEAMS_MESSAGE_EVENT = 'teams.message' as const\n\nexport const MICROSOFT_TEAMS_TRIGGER_EVENT_CATALOG = {\n namespace: 'teams.',\n closed: true,\n events: [{ id: MICROSOFT_TEAMS_MESSAGE_EVENT }],\n} as const satisfies TriggerEventCatalog\n\nexport interface InboundEmailAttachment {\n filename?: string\n contentType?: string\n contentBase64?: string\n url?: string\n size?: number\n}\n\n/** Payload emitted by Tangle's verified inbound-email receiver. */\nexport interface InboundEmailPayload {\n messageId?: string\n from: string\n to: string\n subject?: string\n text?: string\n html?: string\n headers?: Record<string, string>\n attachments?: InboundEmailAttachment[]\n receivedAt?: number\n}\n\nexport interface ProviderConversationEvent {\n provider: string\n type: string\n deliveryId?: string\n payload: unknown\n}\n\nexport interface ConversationParticipant {\n id: string | null\n address: string | null\n displayName: string | null\n}\n\nexport interface ConversationDestination {\n kind: 'mailbox' | 'channel' | 'chat' | 'user'\n id: string | null\n address: string | null\n displayName: string | null\n}\n\nexport interface ConversationAttachment {\n id: string | null\n name: string | null\n contentType: string | null\n size: number | null\n contentBase64: string | null\n url: string | null\n}\n\n/**\n * Provider-neutral message data for product ingestion.\n *\n * The signed Hub delivery remains the audit record. This projection contains\n * only the stable fields products need for threading, prompts, and files.\n */\nexport interface ConversationEvent {\n version: 1\n provider: 'email' | 'slack' | 'teams'\n eventType: string\n operation: 'created' | 'updated' | 'deleted'\n eventId: string | null\n conversationId: string | null\n parentEventIds: string[]\n sender: ConversationParticipant\n destinations: ConversationDestination[]\n subject: string | null\n text: string | null\n html: string | null\n attachments: ConversationAttachment[]\n occurredAt: number | null\n}\n\nexport type ConversationEventNormalizationErrorCode =\n | 'unsupported_provider'\n | 'unsupported_event'\n | 'invalid_payload'\n\nexport type ConversationEventNormalizationResult =\n | { ok: true; event: ConversationEvent }\n | {\n ok: false\n code: ConversationEventNormalizationErrorCode\n message: string\n }\n\nconst MAX_BODY_LENGTH = 1_000_000\nconst MAX_ATTACHMENTS = 50\nconst MAX_INLINE_ATTACHMENT_LENGTH = 1_100_000\nconst MAX_ATTACHMENT_SIZE = 20 * 1024 * 1024\nconst MAX_HEADERS = 200\n\nexport function normalizeConversationEvent(\n value: unknown,\n): ConversationEventNormalizationResult {\n if (\n !isRecord(value) ||\n typeof value.provider !== 'string' ||\n typeof value.type !== 'string' ||\n (value.deliveryId !== undefined &&\n typeof value.deliveryId !== 'string') ||\n !Object.prototype.hasOwnProperty.call(value, 'payload')\n ) {\n return invalidPayload(\n 'Provider conversation event requires provider, type, and payload',\n )\n }\n const input: ProviderConversationEvent = {\n provider: value.provider,\n type: value.type,\n ...(typeof value.deliveryId === 'string'\n ? { deliveryId: value.deliveryId }\n : {}),\n payload: value.payload,\n }\n if (input.provider === 'email') {\n if (input.type !== 'email.received') {\n return unsupportedEvent(input.provider, input.type)\n }\n return normalizeEmail(input)\n }\n if (input.provider === 'slack') {\n if (input.type !== 'slack.message' && input.type !== 'slack.app_mention') {\n return unsupportedEvent(input.provider, input.type)\n }\n return normalizeSlack(input)\n }\n if (input.provider === MICROSOFT_TEAMS_PROVIDER_ID) {\n if (input.type !== MICROSOFT_TEAMS_MESSAGE_EVENT) {\n return unsupportedEvent(input.provider, input.type)\n }\n return normalizeMicrosoftTeams(input)\n }\n return {\n ok: false,\n code: 'unsupported_provider',\n message: `Conversation events do not support provider ${input.provider}`,\n }\n}\n\nfunction normalizeMicrosoftTeams(\n input: ProviderConversationEvent,\n): ConversationEventNormalizationResult {\n const activity = input.payload\n if (!isRecord(activity) || activity.type !== 'message') {\n return invalidPayload('Teams payload requires a message activity')\n }\n if (\n activity.channelId !== undefined &&\n activity.channelId !== 'msteams'\n ) {\n return invalidPayload('Teams activity came from an unsupported channel')\n }\n const text = optionalString(activity.text, MAX_BODY_LENGTH)\n if (text === undefined) {\n return invalidPayload('Teams message text is invalid')\n }\n const conversation = isRecord(activity.conversation)\n ? activity.conversation\n : null\n const conversationId = normalizeNullableString(conversation?.id, 2_000)\n if (!conversationId) {\n return invalidPayload('Teams message requires a conversation id')\n }\n const channelData = isRecord(activity.channelData)\n ? activity.channelData\n : null\n const tenant = resolveMicrosoftTeamsTenantId(activity)\n if (!tenant.ok) return invalidPayload(tenant.message)\n const tenantId = tenant.tenantId\n const from = isRecord(activity.from) ? activity.from : null\n const channel = isRecord(channelData?.channel)\n ? channelData.channel\n : null\n const team = isRecord(channelData?.team) ? channelData.team : null\n const channelId = normalizeNullableString(channel?.id, 2_000)\n const channelName = normalizeNullableString(channel?.name, 300)\n const teamId = normalizeNullableString(team?.id, 2_000)\n const replyToId = normalizeNullableString(activity.replyToId, 2_000)\n const eventId =\n normalizeNullableString(activity.id, 2_000) ??\n normalizeNullableString(input.deliveryId, 2_000)\n const attachments = normalizeTeamsAttachments(activity.attachments)\n if (!attachments.ok) return attachments\n const timestamp = normalizeTeamsTimestamp(\n activity.timestamp ?? activity.localTimestamp,\n )\n if (timestamp === undefined) {\n return invalidPayload('Teams message timestamp is invalid')\n }\n\n return {\n ok: true,\n event: {\n version: 1,\n provider: 'teams',\n eventType: input.type,\n operation: 'created',\n eventId,\n conversationId: `${tenantId}:${conversationId}`,\n parentEventIds: replyToId ? [replyToId] : [],\n sender: {\n id:\n normalizeNullableString(from?.aadObjectId, 300) ??\n normalizeNullableString(from?.id, 2_000),\n address: null,\n displayName: normalizeNullableString(from?.name, 300),\n },\n destinations: [\n {\n kind: channelId ? 'channel' : 'chat',\n id: channelId ?? conversationId,\n address: null,\n displayName: channelName,\n },\n ...(teamId\n ? [\n {\n kind: 'channel' as const,\n id: teamId,\n address: null,\n displayName: normalizeNullableString(team?.name, 300),\n },\n ]\n : []),\n ],\n subject: null,\n text: text ?? null,\n html: null,\n attachments: attachments.value,\n occurredAt: timestamp ?? null,\n },\n }\n}\n\nexport type MicrosoftTeamsTenantResolution =\n | { ok: true; tenantId: string }\n | { ok: false; message: string }\n\n/**\n * Resolve the authenticated Teams tenant identity shared by the platform\n * receiver and product normalizer. Teams may repeat it in both\n * `channelData.tenant.id` and `conversation.tenantId`; disagreement is\n * rejected so an event can never be attributed to a guessed tenant.\n */\nexport function resolveMicrosoftTeamsTenantId(\n payload: unknown,\n): MicrosoftTeamsTenantResolution {\n if (!isRecord(payload)) {\n return { ok: false, message: 'Teams payload requires an activity object' }\n }\n const conversation = isRecord(payload.conversation)\n ? payload.conversation\n : null\n const channelData = isRecord(payload.channelData)\n ? payload.channelData\n : null\n const channelDataTenant = isRecord(channelData?.tenant)\n ? normalizeNullableString(channelData.tenant.id, 300)\n : null\n const conversationTenant = normalizeNullableString(\n conversation?.tenantId,\n 300,\n )\n if (\n channelDataTenant &&\n conversationTenant &&\n channelDataTenant !== conversationTenant\n ) {\n return {\n ok: false,\n message: 'Teams activity contains conflicting tenant ids',\n }\n }\n const tenantId = channelDataTenant ?? conversationTenant\n return tenantId\n ? { ok: true, tenantId }\n : { ok: false, message: 'Teams message requires a tenant id' }\n}\n\nfunction normalizeEmail(\n input: ProviderConversationEvent,\n): ConversationEventNormalizationResult {\n const payload = input.payload\n if (!isRecord(payload)) return invalidPayload('Email payload must be an object')\n const from = optionalString(payload.from, 320)\n const to = optionalString(payload.to, 320)\n if (\n from === undefined ||\n from === null ||\n to === undefined ||\n to === null ||\n !from.trim() ||\n !to.trim()\n ) {\n return invalidPayload('Email payload requires non-empty string from and to')\n }\n const messageId = optionalString(payload.messageId, 1_000)\n const subject = optionalString(payload.subject, 2_000)\n const text = optionalString(payload.text, MAX_BODY_LENGTH)\n const html = optionalString(payload.html, MAX_BODY_LENGTH)\n if (\n messageId === undefined ||\n subject === undefined ||\n text === undefined ||\n html === undefined\n ) {\n return invalidPayload('Email payload contains an invalid string field')\n }\n const receivedAt = optionalFiniteNumber(payload.receivedAt, 0)\n if (receivedAt === undefined) {\n return invalidPayload('Email receivedAt must be a non-negative number')\n }\n const headers = normalizeHeaders(payload.headers)\n if (!headers.ok) return headers\n const attachments = normalizeEmailAttachments(payload.attachments)\n if (!attachments.ok) return attachments\n\n return {\n ok: true,\n event: {\n version: 1,\n provider: 'email',\n eventType: input.type,\n operation: 'created',\n eventId:\n normalizeMessageId(messageId) ??\n normalizeNullableString(input.deliveryId, 1_000),\n conversationId: null,\n parentEventIds: referencedMessageIds(headers.value),\n sender: {\n id: null,\n address: normalizeNullableString(from, 320),\n displayName: null,\n },\n destinations: [\n {\n kind: 'mailbox',\n id: null,\n address: normalizeMailbox(to),\n displayName: null,\n },\n ],\n subject: normalizeNullableString(subject, 2_000),\n text: text ?? null,\n html: html ?? null,\n attachments: attachments.value,\n occurredAt: receivedAt ?? null,\n },\n }\n}\n\nfunction normalizeSlack(\n input: ProviderConversationEvent,\n): ConversationEventNormalizationResult {\n const wrapper = input.payload\n if (!isRecord(wrapper) || !isRecord(wrapper.event)) {\n return invalidPayload('Slack payload requires an Events API event object')\n }\n const outerEvent = wrapper.event\n const changedMessage =\n outerEvent.subtype === 'message_changed' && isRecord(outerEvent.message)\n ? outerEvent.message\n : null\n const deletedMessage =\n outerEvent.subtype === 'message_deleted' &&\n isRecord(outerEvent.previous_message)\n ? outerEvent.previous_message\n : null\n const message = changedMessage ?? deletedMessage ?? outerEvent\n if (\n message.type !== 'message' &&\n input.type !== 'slack.app_mention'\n ) {\n return invalidPayload('Slack event does not contain a message')\n }\n const text = optionalString(message.text, MAX_BODY_LENGTH)\n if (text === undefined) {\n return invalidPayload('Slack message text is invalid')\n }\n const channel =\n normalizeNullableString(outerEvent.channel, 300) ??\n normalizeNullableString(message.channel, 300)\n if (!channel) return invalidPayload('Slack message requires a channel')\n const timestamp =\n normalizeNullableString(message.ts, 100) ??\n normalizeNullableString(outerEvent.event_ts, 100)\n const threadTimestamp = normalizeNullableString(message.thread_ts, 100)\n const team =\n normalizeNullableString(wrapper.team_id, 300) ??\n normalizeNullableString(wrapper.context_team_id, 300)\n const rootTimestamp = threadTimestamp ?? timestamp\n const files = normalizeSlackFiles(message.files)\n if (!files.ok) return files\n const subtype = normalizeNullableString(outerEvent.subtype, 100)\n\n return {\n ok: true,\n event: {\n version: 1,\n provider: 'slack',\n eventType: input.type,\n operation:\n subtype === 'message_deleted'\n ? 'deleted'\n : subtype === 'message_changed'\n ? 'updated'\n : 'created',\n eventId:\n normalizeNullableString(wrapper.event_id, 300) ??\n normalizeNullableString(message.client_msg_id, 300) ??\n normalizeNullableString(input.deliveryId, 300) ??\n timestamp,\n conversationId: rootTimestamp\n ? [team, channel, rootTimestamp].filter(Boolean).join(':')\n : null,\n parentEventIds:\n threadTimestamp && timestamp && threadTimestamp !== timestamp\n ? [threadTimestamp]\n : [],\n sender: {\n id:\n normalizeNullableString(message.user, 300) ??\n normalizeNullableString(message.bot_id, 300),\n address: null,\n displayName:\n normalizeNullableString(message.username, 300) ??\n (isRecord(message.user_profile)\n ? normalizeNullableString(\n message.user_profile.display_name,\n 300,\n )\n : null),\n },\n destinations: [\n {\n kind: 'channel',\n id: channel,\n address: null,\n displayName: null,\n },\n ],\n subject: null,\n text: text ?? null,\n html: null,\n attachments: files.value,\n occurredAt:\n slackTimestampMs(timestamp) ??\n epochSecondsMs(wrapper.event_time) ??\n null,\n },\n }\n}\n\nfunction normalizeHeaders(\n value: unknown,\n):\n | { ok: true; value: Record<string, string> }\n | {\n ok: false\n code: 'invalid_payload'\n message: string\n } {\n if (value === undefined) return { ok: true, value: {} }\n if (!isRecord(value) || Object.keys(value).length > MAX_HEADERS) {\n return invalidPayload('Email headers must be a bounded string record')\n }\n const headers: Record<string, string> = {}\n for (const [key, entry] of Object.entries(value)) {\n if (\n key.length === 0 ||\n key.length > 200 ||\n typeof entry !== 'string' ||\n entry.length > 4_000\n ) {\n return invalidPayload('Email headers must be a bounded string record')\n }\n headers[key.toLowerCase()] = entry\n }\n return { ok: true, value: headers }\n}\n\nfunction normalizeEmailAttachments(\n value: unknown,\n):\n | { ok: true; value: ConversationAttachment[] }\n | {\n ok: false\n code: 'invalid_payload'\n message: string\n } {\n if (value === undefined) return { ok: true, value: [] }\n if (!Array.isArray(value) || value.length > MAX_ATTACHMENTS) {\n return invalidPayload('Email attachments exceed the supported limit')\n }\n const attachments: ConversationAttachment[] = []\n for (const entry of value) {\n if (!isRecord(entry)) {\n return invalidPayload('Email attachment must be an object')\n }\n const name = optionalString(entry.filename, 240)\n const contentType = optionalString(entry.contentType, 200)\n const contentBase64 = optionalString(\n entry.contentBase64,\n MAX_INLINE_ATTACHMENT_LENGTH,\n )\n const url = optionalString(entry.url, 2_048)\n const size = optionalFiniteNumber(entry.size, 0, MAX_ATTACHMENT_SIZE, true)\n if (\n name === undefined ||\n contentType === undefined ||\n contentBase64 === undefined ||\n url === undefined ||\n size === undefined\n ) {\n return invalidPayload('Email attachment contains an invalid field')\n }\n attachments.push({\n id: null,\n name: name ?? null,\n contentType: contentType ?? null,\n size: size ?? null,\n contentBase64: contentBase64 ?? null,\n url: url ?? null,\n })\n }\n return { ok: true, value: attachments }\n}\n\nfunction normalizeSlackFiles(\n value: unknown,\n):\n | { ok: true; value: ConversationAttachment[] }\n | {\n ok: false\n code: 'invalid_payload'\n message: string\n } {\n if (value === undefined) return { ok: true, value: [] }\n if (!Array.isArray(value) || value.length > MAX_ATTACHMENTS) {\n return invalidPayload('Slack files exceed the supported limit')\n }\n const files: ConversationAttachment[] = []\n for (const entry of value) {\n if (!isRecord(entry)) return invalidPayload('Slack file must be an object')\n const size = optionalFiniteNumber(entry.size, 0, MAX_ATTACHMENT_SIZE, true)\n if (size === undefined) return invalidPayload('Slack file size is invalid')\n files.push({\n id: normalizeNullableString(entry.id, 300),\n name:\n normalizeNullableString(entry.name, 240) ??\n normalizeNullableString(entry.title, 240),\n contentType: normalizeNullableString(entry.mimetype, 200),\n size: size ?? null,\n contentBase64: null,\n // Slack file URLs require the workspace bot token. Products use the\n // `slack.download_file` Hub action with this file id; exposing a private\n // URL here would make downstream runtimes attempt an unauthenticated fetch.\n url: null,\n })\n }\n return { ok: true, value: files }\n}\n\nfunction normalizeTeamsAttachments(\n value: unknown,\n):\n | { ok: true; value: ConversationAttachment[] }\n | {\n ok: false\n code: 'invalid_payload'\n message: string\n } {\n if (value === undefined) return { ok: true, value: [] }\n if (!Array.isArray(value) || value.length > MAX_ATTACHMENTS) {\n return invalidPayload('Teams attachments exceed the supported limit')\n }\n const attachments: ConversationAttachment[] = []\n for (const entry of value) {\n if (!isRecord(entry)) {\n return invalidPayload('Teams attachment must be an object')\n }\n const id = optionalString(entry.id, 300)\n const name = optionalString(entry.name, 240)\n const contentType = optionalString(entry.contentType, 200)\n if (\n id === undefined ||\n name === undefined ||\n contentType === undefined\n ) {\n return invalidPayload('Teams attachment contains an invalid field')\n }\n attachments.push({\n id: normalizeNullableString(id, 300),\n name: normalizeNullableString(name, 240),\n contentType: normalizeNullableString(contentType, 200),\n size: null,\n contentBase64: null,\n // Bot attachment URLs require Microsoft authorization. The receiver\n // keeps that credential inside Hub; products only receive stable metadata.\n url: null,\n })\n }\n return { ok: true, value: attachments }\n}\n\nfunction normalizeTeamsTimestamp(value: unknown): number | null | undefined {\n if (value === undefined || value === null) return null\n if (typeof value !== 'string' || value.length > 100) return undefined\n const timestamp = Date.parse(value)\n return Number.isFinite(timestamp) && timestamp >= 0\n ? timestamp\n : undefined\n}\n\nfunction referencedMessageIds(headers: Record<string, string>): string[] {\n const values = [headers['in-reply-to'], headers.references].filter(\n (value): value is string => Boolean(value?.trim()),\n )\n const ids: string[] = []\n for (const value of values) {\n const bracketed = value.match(/<[^<>]{1,1000}>/g)\n const candidates = bracketed ?? value.split(/\\s+/)\n for (const candidate of candidates) {\n const normalized = normalizeMessageId(candidate)\n if (normalized && !ids.includes(normalized)) ids.push(normalized)\n }\n }\n return ids.slice(0, 50)\n}\n\nfunction normalizeMessageId(value: string | null | undefined): string | null {\n if (!value) return null\n const trimmed = value.trim()\n if (!trimmed) return null\n return trimmed.startsWith('<') && trimmed.endsWith('>')\n ? trimmed.slice(1, -1).trim() || null\n : trimmed\n}\n\nfunction normalizeMailbox(value: string): string {\n return value.trim().toLowerCase()\n}\n\nfunction normalizeNullableString(\n value: unknown,\n maxLength: number,\n): string | null {\n return typeof value === 'string' && value.length <= maxLength\n ? value.trim() || null\n : null\n}\n\n/**\n * Undefined means invalid; null means the optional field was absent.\n */\nfunction optionalString(\n value: unknown,\n maxLength: number,\n): string | null | undefined {\n if (value === undefined) return null\n return typeof value === 'string' && value.length <= maxLength\n ? value\n : undefined\n}\n\n/**\n * Undefined means invalid; null means the optional field was absent.\n */\nfunction optionalFiniteNumber(\n value: unknown,\n minimum: number,\n maximum = Number.MAX_SAFE_INTEGER,\n integer = false,\n): number | null | undefined {\n if (value === undefined) return null\n if (\n typeof value !== 'number' ||\n !Number.isFinite(value) ||\n value < minimum ||\n value > maximum ||\n (integer && !Number.isInteger(value))\n ) {\n return undefined\n }\n return value\n}\n\nfunction slackTimestampMs(value: string | null): number | null {\n if (!value || !/^\\d{1,12}(?:\\.\\d{1,9})?$/.test(value)) return null\n const seconds = Number(value)\n return Number.isFinite(seconds) ? Math.round(seconds * 1_000) : null\n}\n\nfunction epochSecondsMs(value: unknown): number | null {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0\n ? Math.round(value * 1_000)\n : null\n}\n\nfunction unsupportedEvent(\n provider: string,\n type: string,\n): ConversationEventNormalizationResult {\n return {\n ok: false,\n code: 'unsupported_event',\n message: `Conversation events do not support ${provider} event ${type}`,\n }\n}\n\nfunction invalidPayload(\n message: string,\n): {\n ok: false\n code: 'invalid_payload'\n message: string\n} {\n return { ok: false, code: 'invalid_payload', message }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","import type { ConversationEventNormalizationResult, ProviderConversationEvent } from './index.js'\n\nfunction object(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\nfunction id(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0 && value.length <= 256 && !/[\\u0000-\\u001f\\u007f]/.test(value)\n}\nconst invalid = (message: string): ConversationEventNormalizationResult => ({ ok: false, code: 'invalid_payload', message })\n\n/** Fresh webhook snapshots only. Historical range notifications need journal hydration.\n * A chat represents one customer, but the message does not contain their address.\n * Keep that customer opaque; never mislabel message.from (our number) as the sender. */\nexport function normalizeLinqWhatsappConversation(input: ProviderConversationEvent): ConversationEventNormalizationResult {\n const value = input.payload\n if (!object(value) || input.type !== `linq-whatsapp.${value.type}`) return invalid('Event type does not match the provider envelope')\n if (value.type !== 'message.received') return { ok: false, code: 'unsupported_event', message: 'Not an incoming message' }\n if (!object(value.data) || !object(value.data.message)) return invalid('Read the chat journal to hydrate this historical event')\n const message = value.data.message\n if (!id(value.id) || !id(message.id) || !id(message.chat_id) || !id(message.from) || message.direction !== 'inbound') {\n return invalid('Incoming message requires a stable identity, conversation and owned destination')\n }\n if (value.data.chat_id !== undefined && value.data.chat_id !== message.chat_id) return invalid('Chat identity mismatch')\n if (!Array.isArray(message.parts) || !message.parts.length || message.parts.length > 50) return invalid('Invalid message parts')\n const text: string[] = []\n for (const part of message.parts) {\n if (!object(part) || part.type !== 'text' || typeof part.body !== 'string' || part.body.length > 4096) {\n return { ok: false, code: 'unsupported_event', message: 'This message requires non-text handling' }\n }\n text.push(part.body)\n }\n const occurredAt = typeof message.created_at === 'string' ? Date.parse(message.created_at) : NaN\n if (!Number.isSafeInteger(occurredAt) || occurredAt < 0) return invalid('Invalid message timestamp')\n return { ok: true, event: {\n version: 1, provider: 'linq-whatsapp', eventType: input.type, operation: 'created', eventId: message.id,\n conversationId: message.chat_id, parentEventIds: [],\n sender: { id: `customer:${message.chat_id}`, address: null, displayName: null },\n destinations: [{ kind: 'chat', id: message.from, address: message.from, displayName: null }],\n subject: null, text: text.join('\\n'), html: null, attachments: [], occurredAt, isGroup: false,\n } }\n}\n","import type { ConversationAttachment, ConversationEvent, ConversationEventNormalizationResult, ProviderConversationEvent } from './index.js'\n\ntype RecordValue = Record<string, unknown>\nfunction record(value: unknown): value is RecordValue { return value !== null && typeof value === 'object' && !Array.isArray(value) }\nfunction string(value: unknown, max = 2000): string | null {\n return typeof value === 'string' && value.length > 0 && value.length <= max && !/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]/.test(value) ? value : null\n}\nfunction timestamp(value: unknown): number | null {\n const n = typeof value === 'number' ? value * 1000 : typeof value === 'string' ? Date.parse(value) : NaN\n return Number.isSafeInteger(n) && n >= 0 ? n : null\n}\nconst invalid = (message: string): ConversationEventNormalizationResult => ({ ok: false, code: 'invalid_payload', message })\nconst unsupported = (): ConversationEventNormalizationResult => ({ ok: false, code: 'unsupported_event', message: 'Not a supported incoming conversation message' })\n\nfunction attachment(value: unknown): ConversationAttachment | null {\n if (!record(value)) return null\n const url = string(value.url ?? value.value, 8192)\n if (!url) return null\n try { const u = new URL(url); if (u.protocol !== 'https:' || u.username || u.password) return null } catch { return null }\n return { id: string(value.id), name: string(value.filename ?? value.name, 255),\n contentType: string(value.mime_type ?? value.mime ?? value.content_type, 200), size: null, contentBase64: null, url }\n}\n\nfunction finish(input: ProviderConversationEvent, data: {\n id: unknown; conversation: unknown; sender: unknown; destination: unknown;\n destinationAddress?: unknown; text: unknown; time: unknown; media?: unknown; parent?: unknown;\n subject?: unknown; destinationKind?: 'chat' | 'mailbox'; isGroup?: boolean; historyOnly?: boolean;\n}): ConversationEventNormalizationResult {\n const id = string(data.id), conversation = string(data.conversation), sender = string(data.sender), destination = string(data.destination)\n if (!id || !conversation || !sender || !destination) return invalid('Message identity, conversation, sender and destination are required')\n if (data.text !== null && data.text !== undefined && (typeof data.text !== 'string' || data.text.length > 1_000_000)) return invalid('Invalid message text')\n if (data.media !== undefined && data.media !== null && (!Array.isArray(data.media) || data.media.length > 50)) return invalid('Invalid attachment list')\n const media = (data.media ?? []) as unknown[]\n const attachments = media.map(attachment)\n if (attachments.some((a) => !a)) return invalid('Attachments require HTTPS references; bytes must be resolved through the authorized file boundary')\n const time = timestamp(data.time)\n if (time === null) return invalid('A valid provider timestamp is required')\n const provider = input.provider as 'inkbox' | 'linq' | 'contiguity'\n const event: ConversationEvent = {\n version: 1, provider, eventType: input.type, operation: 'created', eventId: id,\n conversationId: conversation, parentEventIds: string(data.parent) ? [String(data.parent)] : [],\n sender: { id: sender, address: sender, displayName: null },\n destinations: [{ kind: data.destinationKind ?? 'chat', id: destination, address: string(data.destinationAddress), displayName: null }],\n subject: string(data.subject, 998), text: (data.text as string | null | undefined) ?? null, html: null,\n attachments: attachments as ConversationAttachment[], occurredAt: time,\n isGroup: data.isGroup === true, historyOnly: data.historyOnly === true,\n }\n return { ok: true, event }\n}\n\n/** Called after the host verifies signatures and resolves the owning connection. */\nexport function normalizeMobileConversation(input: ProviderConversationEvent): ConversationEventNormalizationResult {\n const p = input.payload\n if (!record(p) || !record(p.data)) return invalid('Provider payload requires a data object')\n const data = p.data\n if (input.provider === 'inkbox') {\n if (input.type !== `inkbox.${p.event_type}`) return invalid('Event type does not match the provider envelope')\n if (p.event_type === 'imessage.received') {\n const m = data.message\n if (!record(m) || m.direction !== 'inbound') return invalid('Expected an inbound iMessage')\n return finish(input, { id: m.id, conversation: m.conversation_id, sender: m.sender_number ?? m.remote_number,\n destination: m.conversation_id, text: m.content, time: m.created_at ?? p.timestamp, media: m.media, isGroup: m.is_group === true })\n }\n if (p.event_type === 'text.received') {\n const m = data.text_message\n if (!record(m) || m.direction !== 'inbound') return invalid('Expected an inbound phone text')\n return finish(input, { id: m.id, conversation: m.conversation_id, sender: m.sender_phone_number ?? m.remote_phone_number,\n destination: m.local_phone_number, destinationAddress: m.local_phone_number, text: m.text, time: m.created_at ?? p.timestamp,\n media: m.media, isGroup: m.is_group === true })\n }\n if (p.event_type === 'message.received') {\n const m = data.message\n if (!record(m) || m.direction !== 'inbound') return invalid('Expected inbound mail')\n return finish(input, { id: m.id, conversation: m.thread_id ?? m.id, sender: m.from_address,\n destination: m.email_address, destinationAddress: m.email_address, destinationKind: 'mailbox', text: m.body,\n time: m.created_at ?? p.timestamp, subject: m.subject,\n historyOnly: m.body_state !== 'complete' || m.body_truncated === true })\n }\n return unsupported()\n }\n if (input.provider === 'linq') {\n if (input.type !== `linq.${p.event_type}`) return invalid('Event type does not match the provider envelope')\n if (p.event_type !== 'message.received') return unsupported()\n if (p.webhook_version !== '2026-02-03' || data.direction !== 'inbound' || !record(data.chat)\n || !record(data.sender_handle) || !record(data.chat.owner_handle) || data.chat.owner_handle.is_me !== true || data.sender_handle.is_me === true) {\n return invalid('Linq requires v2026-02-03 incoming payloads with explicit sender and owner handles')\n }\n if (!Array.isArray(data.parts) || data.parts.length > 50) return invalid('Invalid Linq parts')\n const texts: string[] = [], media: RecordValue[] = []\n for (const part of data.parts) {\n if (!record(part)) return invalid('Invalid Linq part')\n if (part.type === 'text' || part.type === 'link') {\n if (typeof part.value !== 'string') return invalid('Invalid Linq text')\n texts.push(part.value)\n } else if (part.type === 'media') media.push(part)\n else return unsupported()\n }\n return finish(input, { id: data.id, conversation: data.chat.id, sender: data.sender_handle.handle,\n destination: data.chat.id, destinationAddress: data.chat.owner_handle.handle,\n text: texts.join('\\n'), time: data.sent_at ?? p.created_at, media,\n parent: record(data.reply_to) ? data.reply_to.message_id : undefined,\n isGroup: data.chat.is_group === true, historyOnly: data.reconciled_at != null || data.zero_retention === true })\n }\n if (input.provider === 'contiguity') {\n if (input.type !== `contiguity.${p.type}`) return invalid('Event type does not match the provider envelope')\n if (!['imessage.incoming', 'text.incoming.sms', 'text.incoming.mms'].includes(String(p.type))) return unsupported()\n if (!string(data.to, 320) || !string(data.from, 320)) return invalid('Missing Contiguity phone routing')\n // No native chat id in v2: use a collision-free tuple, not a bare sender across channels.\n return finish(input, { id: p.id, conversation: JSON.stringify([p.type === 'imessage.incoming' ? 'imessage' : 'text', data.to, data.from]),\n sender: data.from, destination: data.to, destinationAddress: data.to, text: data.body,\n time: data.timestamp ?? p.timestamp, media: data.attachments })\n }\n return { ok: false, code: 'unsupported_provider', message: 'Unsupported mobile provider' }\n}\n","import { normalizeConversationEvent, type ConversationEventNormalizationResult, type ProviderConversationEvent } from './index.js'\n\nexport interface ConversationReply {\n /** Qualified existing Hub action. The host supplies the bound connection. */\n action: string\n input: Record<string, unknown>\n /** Pass as the invocation's idempotency key, unchanged on every retry of this reply. */\n idempotencyKey: string\n}\n\ntype Failure = Exclude<ConversationEventNormalizationResult, { ok: true }>\nfunction object(value: unknown): Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {}\n}\nconst fail = (message: string): Failure => ({ ok: false, code: 'invalid_payload', message })\n\n/**\n * Derive a plain-text reply from a previously authenticated, stored event.\n * No model-selected recipient, sender, fallback channel or credential.\n * This is routing, not permission: recheck the bound connection and current\n * grant, persist the outbox key/body, then invoke through the existing Hub SDK.\n */\nexport function buildMessagingReply(\n input: ProviderConversationEvent,\n text: string,\n operationId: string,\n): { ok: true; reply: ConversationReply } | Failure {\n const normalized = normalizeConversationEvent(input)\n if (!normalized.ok) return normalized\n const event = normalized.event\n if (typeof text !== 'string' || !text.trim() || text.length > 10000 || text.includes('\\0')) return fail('Reply text is empty or exceeds its limit')\n if (typeof operationId !== 'string' || !operationId || operationId.length > 256 || /[\\u0000-\\u001f]/.test(operationId)) return fail('A stable operation id is required')\n if (event.historyOnly || event.isGroup) return fail('This event requires review or complete input before a reply')\n const data = object(object(input.payload).data)\n if (event.provider === 'inkbox') {\n if (event.eventType === 'inkbox.imessage.received') {\n return { ok: true, reply: { idempotencyKey: operationId, action: 'inkbox.imessage.reply', input: { conversation_id: event.conversationId, text } } }\n }\n if (event.eventType === 'inkbox.text.received') {\n const message = object(data.text_message)\n if (typeof message.phone_number_id !== 'string' || !message.phone_number_id || text.length > 1600) return fail('SMS requires its owned phone id and at most 1600 characters')\n return { ok: true, reply: { idempotencyKey: operationId, action: 'inkbox.sms.reply', input: { phone_number_id: message.phone_number_id, conversation_id: event.conversationId, text } } }\n }\n if (event.eventType === 'inkbox.message.received') {\n const message = object(data.message)\n if (!event.sender.address || typeof message.email_address !== 'string') return fail('Mail reply requires an explicit sender and mailbox')\n const subject = event.subject ?? ''\n return { ok: true, reply: { idempotencyKey: operationId, action: 'inkbox.email.send', input: {\n email_address: message.email_address, to: [event.sender.address],\n subject: /^re:/i.test(subject) ? subject : `Re: ${subject}`.slice(0, 998), text,\n in_reply_to_message_id: event.eventId,\n } } }\n }\n }\n if (event.provider === 'linq-whatsapp') {\n if (text.length > 4096) return fail('WhatsApp text is limited to 4096 characters')\n return { ok: true, reply: { idempotencyKey: operationId, action: 'linq-whatsapp.messages.reply', input: { chat_id: event.conversationId, text } } }\n }\n if (event.provider === 'linq') {\n return { ok: true, reply: { idempotencyKey: operationId, action: 'linq.messages.reply', input: { chat_id: event.conversationId, text, message_key: operationId } } }\n }\n if (event.provider === 'contiguity') {\n return { ok: true, reply: { idempotencyKey: operationId, action: event.eventType === 'contiguity.imessage.incoming' ? 'contiguity.messages.send_imessage' : 'contiguity.sms.send',\n input: { to: event.sender.address, from: event.destinations[0]?.address, message: text } } }\n }\n return { ok: false, code: 'unsupported_provider', message: 'Use the existing channel-specific reply tool for this provider' }\n}\n","/** Protocol metadata, not a claim that a deployment or account is configured. */\nexport interface ConversationChannel {\n providerId: string\n eventType: string\n label: string\n transport: 'email' | 'imessage' | 'sms' | 'whatsapp'\n sourceKind: 'channel' | 'connection'\n replies: boolean\n inventoryAction?: string\n replyAction?: string\n numberProvisioning?: 'provider-assigned'\n}\n\nconst channels: readonly ConversationChannel[] = [\n { providerId: 'email', eventType: 'email.received', label: 'Tangle email', transport: 'email', sourceKind: 'channel', replies: false },\n { providerId: 'inkbox', eventType: 'inkbox.imessage.received', label: 'iMessage', transport: 'imessage', sourceKind: 'connection', replies: true },\n { providerId: 'inkbox', eventType: 'inkbox.text.received', label: 'SMS', transport: 'sms', sourceKind: 'connection', replies: true },\n { providerId: 'inkbox', eventType: 'inkbox.message.received', label: 'Email', transport: 'email', sourceKind: 'connection', replies: true },\n { providerId: 'linq', eventType: 'linq.message.received', label: 'iMessage / SMS', transport: 'imessage', sourceKind: 'connection', replies: true, inventoryAction: 'linq.numbers.list', replyAction: 'linq.messages.reply', numberProvisioning: 'provider-assigned' },\n { providerId: 'contiguity', eventType: 'contiguity.imessage.incoming', label: 'iMessage', transport: 'imessage', sourceKind: 'connection', replies: true },\n { providerId: 'contiguity', eventType: 'contiguity.text.incoming.sms', label: 'SMS', transport: 'sms', sourceKind: 'connection', replies: true },\n { providerId: 'linq-whatsapp', eventType: 'linq-whatsapp.message.received', label: 'WhatsApp', transport: 'whatsapp', sourceKind: 'connection', replies: true },\n]\n\n/** Fresh copies let applications filter by their live Hub catalog without mutating ours. */\nexport function listConversationChannels(): ConversationChannel[] {\n return channels.map(channel => ({ ...channel }))\n}\n\n\nexport interface ConversationEndpointOption {\n id: string; address: string; providerId: string; channel: 'imessage'\n health: 'healthy' | 'at-risk' | 'critical' | 'unknown'\n}\n/** Project an authenticated provider-owned inventory response, not user input.\n * Protocol shape stays here with the adapter; applications never guess addresses. */\nexport function conversationEndpointOptions(providerId: string, result: unknown): ConversationEndpointOption[] {\n if (providerId !== 'linq') throw new Error('Owned endpoint enumeration is not available for this provider')\n if (!result || typeof result !== 'object' || !Array.isArray((result as { phone_numbers?: unknown }).phone_numbers)) {\n throw new Error('Linq did not return its owned phone-number inventory')\n }\n const values = (result as { phone_numbers: unknown[] }).phone_numbers\n if (values.length > 1000) throw new Error('Phone inventory exceeds the supported response limit')\n const seen = new Set<string>()\n return values.map(value => {\n if (!value || typeof value !== 'object') throw new Error('Invalid phone inventory row')\n const r = value as { id?: unknown; phone_number?: unknown; reputation?: { status?: unknown } }\n if (typeof r.id !== 'string' || !/^[a-f0-9-]{36}$/i.test(r.id) || typeof r.phone_number !== 'string' ||\n !/^\\+[1-9]\\d{6,14}$/.test(r.phone_number) || seen.has(r.id) || seen.has(r.phone_number)) {\n throw new Error('Invalid or ambiguous owned phone-number identity')\n }\n seen.add(r.id); seen.add(r.phone_number)\n const health: ConversationEndpointOption['health'] = r.reputation?.status === 'HEALTHY' ? 'healthy' :\n r.reputation?.status === 'AT_RISK' ? 'at-risk' : r.reputation?.status === 'CRITICAL' ? 'critical' : 'unknown'\n return { id: r.id, address: r.phone_number, providerId, channel: 'imessage', health }\n })\n}\n","import {\n normalizeConversationEvent as normalizeExistingConversationEvent,\n type ConversationEvent as ExistingConversationEvent,\n type ConversationEventNormalizationResult as ExistingNormalizationResult,\n} from './core.js'\nimport { normalizeLinqWhatsappConversation } from './linq-whatsapp.js'\nimport { normalizeMobileConversation } from './mobile.js'\n\nexport * from './core.js'\nexport { buildMessagingReply, type ConversationReply } from './reply.js'\nexport { listConversationChannels, conversationEndpointOptions, type ConversationChannel, type ConversationEndpointOption } from './channels.js'\n\n/** Additive provider vocabulary. Neither sender identity nor group membership is authority. */\nexport interface ConversationEvent extends Omit<ExistingConversationEvent, 'provider'> {\n provider: ExistingConversationEvent['provider'] | 'inkbox' | 'linq' | 'contiguity' | 'linq-whatsapp'\n isGroup?: boolean\n /** Historical or incomplete input is not a new automatic command. */\n historyOnly?: boolean\n}\nexport type ConversationEventNormalizationResult =\n | { ok: true; event: ConversationEvent }\n | Exclude<ExistingNormalizationResult, { ok: true }>\n\nexport function normalizeConversationEvent(value: unknown): ConversationEventNormalizationResult {\n if (value && typeof value === 'object' && 'provider' in value\n && ['inkbox', 'linq', 'contiguity', 'linq-whatsapp'].includes(String(value.provider))) {\n if (!('type' in value) || typeof value.type !== 'string' || !('payload' in value)) {\n return { ok: false, code: 'invalid_payload', message: 'Provider event requires type and payload' }\n }\n if (value.provider === 'linq-whatsapp') return normalizeLinqWhatsappConversation({ provider: value.provider, type: value.type, payload: value.payload })\n return normalizeMobileConversation({ provider: String(value.provider), type: value.type, payload: value.payload })\n }\n return normalizeExistingConversationEvent(value)\n}\n"],"mappings":"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","names":["timestamp","id","invalid","id","object","normalizeConversationEvent","normalizeConversationEvent"]}
|
|
1
|
+
{"version":3,"sources":["../../src/conversation-events/core.ts","../../src/conversation-events/linq-whatsapp.ts","../../src/conversation-events/mobile.ts","../../src/conversation-events/reply.ts","../../src/conversation-events/channels.ts","../../src/conversation-events/index.ts"],"sourcesContent":["import type { TriggerEventCatalog } from '../webhooks/router.js'\n\nexport const MICROSOFT_TEAMS_PROVIDER_ID = 'microsoft-teams' as const\nexport const MICROSOFT_TEAMS_MESSAGE_EVENT = 'teams.message' as const\n\nexport const MICROSOFT_TEAMS_TRIGGER_EVENT_CATALOG = {\n namespace: 'teams.',\n closed: true,\n events: [{ id: MICROSOFT_TEAMS_MESSAGE_EVENT }],\n} as const satisfies TriggerEventCatalog\n\nexport interface InboundEmailAttachment {\n filename?: string\n contentType?: string\n contentBase64?: string\n url?: string\n size?: number\n}\n\n/** Payload emitted by Tangle's verified inbound-email receiver. */\nexport interface InboundEmailPayload {\n messageId?: string\n from: string\n to: string\n subject?: string\n text?: string\n html?: string\n headers?: Record<string, string>\n attachments?: InboundEmailAttachment[]\n receivedAt?: number\n}\n\nexport interface ProviderConversationEvent {\n provider: string\n type: string\n deliveryId?: string\n payload: unknown\n}\n\nexport interface ConversationParticipant {\n id: string | null\n address: string | null\n displayName: string | null\n}\n\nexport interface ConversationDestination {\n kind: 'mailbox' | 'channel' | 'chat' | 'user'\n id: string | null\n address: string | null\n displayName: string | null\n}\n\nexport interface ConversationAttachment {\n id: string | null\n name: string | null\n contentType: string | null\n size: number | null\n contentBase64: string | null\n url: string | null\n}\n\n/**\n * Provider-neutral message data for product ingestion.\n *\n * The signed Hub delivery remains the audit record. This projection contains\n * only the stable fields products need for threading, prompts, and files.\n */\nexport interface ConversationEvent {\n version: 1\n provider: 'email' | 'slack' | 'teams'\n eventType: string\n operation: 'created' | 'updated' | 'deleted'\n eventId: string | null\n conversationId: string | null\n parentEventIds: string[]\n sender: ConversationParticipant\n destinations: ConversationDestination[]\n subject: string | null\n text: string | null\n html: string | null\n attachments: ConversationAttachment[]\n occurredAt: number | null\n}\n\nexport type ConversationEventNormalizationErrorCode =\n | 'unsupported_provider'\n | 'unsupported_event'\n | 'invalid_payload'\n\nexport type ConversationEventNormalizationResult =\n | { ok: true; event: ConversationEvent }\n | {\n ok: false\n code: ConversationEventNormalizationErrorCode\n message: string\n }\n\nconst MAX_BODY_LENGTH = 1_000_000\nconst MAX_ATTACHMENTS = 50\nconst MAX_INLINE_ATTACHMENT_LENGTH = 1_100_000\nconst MAX_ATTACHMENT_SIZE = 20 * 1024 * 1024\nconst MAX_HEADERS = 200\n\nexport function normalizeConversationEvent(\n value: unknown,\n): ConversationEventNormalizationResult {\n if (\n !isRecord(value) ||\n typeof value.provider !== 'string' ||\n typeof value.type !== 'string' ||\n (value.deliveryId !== undefined &&\n typeof value.deliveryId !== 'string') ||\n !Object.prototype.hasOwnProperty.call(value, 'payload')\n ) {\n return invalidPayload(\n 'Provider conversation event requires provider, type, and payload',\n )\n }\n const input: ProviderConversationEvent = {\n provider: value.provider,\n type: value.type,\n ...(typeof value.deliveryId === 'string'\n ? { deliveryId: value.deliveryId }\n : {}),\n payload: value.payload,\n }\n if (input.provider === 'email') {\n if (input.type !== 'email.received') {\n return unsupportedEvent(input.provider, input.type)\n }\n return normalizeEmail(input)\n }\n if (input.provider === 'slack') {\n if (input.type !== 'slack.message' && input.type !== 'slack.app_mention') {\n return unsupportedEvent(input.provider, input.type)\n }\n return normalizeSlack(input)\n }\n if (input.provider === MICROSOFT_TEAMS_PROVIDER_ID) {\n if (input.type !== MICROSOFT_TEAMS_MESSAGE_EVENT) {\n return unsupportedEvent(input.provider, input.type)\n }\n return normalizeMicrosoftTeams(input)\n }\n return {\n ok: false,\n code: 'unsupported_provider',\n message: `Conversation events do not support provider ${input.provider}`,\n }\n}\n\nfunction normalizeMicrosoftTeams(\n input: ProviderConversationEvent,\n): ConversationEventNormalizationResult {\n const activity = input.payload\n if (!isRecord(activity) || activity.type !== 'message') {\n return invalidPayload('Teams payload requires a message activity')\n }\n if (\n activity.channelId !== undefined &&\n activity.channelId !== 'msteams'\n ) {\n return invalidPayload('Teams activity came from an unsupported channel')\n }\n const text = optionalString(activity.text, MAX_BODY_LENGTH)\n if (text === undefined) {\n return invalidPayload('Teams message text is invalid')\n }\n const conversation = isRecord(activity.conversation)\n ? activity.conversation\n : null\n const conversationId = normalizeNullableString(conversation?.id, 2_000)\n if (!conversationId) {\n return invalidPayload('Teams message requires a conversation id')\n }\n const channelData = isRecord(activity.channelData)\n ? activity.channelData\n : null\n const tenant = resolveMicrosoftTeamsTenantId(activity)\n if (!tenant.ok) return invalidPayload(tenant.message)\n const tenantId = tenant.tenantId\n const from = isRecord(activity.from) ? activity.from : null\n const channel = isRecord(channelData?.channel)\n ? channelData.channel\n : null\n const team = isRecord(channelData?.team) ? channelData.team : null\n const channelId = normalizeNullableString(channel?.id, 2_000)\n const channelName = normalizeNullableString(channel?.name, 300)\n const teamId = normalizeNullableString(team?.id, 2_000)\n const replyToId = normalizeNullableString(activity.replyToId, 2_000)\n const eventId =\n normalizeNullableString(activity.id, 2_000) ??\n normalizeNullableString(input.deliveryId, 2_000)\n const attachments = normalizeTeamsAttachments(activity.attachments)\n if (!attachments.ok) return attachments\n const timestamp = normalizeTeamsTimestamp(\n activity.timestamp ?? activity.localTimestamp,\n )\n if (timestamp === undefined) {\n return invalidPayload('Teams message timestamp is invalid')\n }\n\n return {\n ok: true,\n event: {\n version: 1,\n provider: 'teams',\n eventType: input.type,\n operation: 'created',\n eventId,\n conversationId: `${tenantId}:${conversationId}`,\n parentEventIds: replyToId ? [replyToId] : [],\n sender: {\n id:\n normalizeNullableString(from?.aadObjectId, 300) ??\n normalizeNullableString(from?.id, 2_000),\n address: null,\n displayName: normalizeNullableString(from?.name, 300),\n },\n destinations: [\n {\n kind: channelId ? 'channel' : 'chat',\n id: channelId ?? conversationId,\n address: null,\n displayName: channelName,\n },\n ...(teamId\n ? [\n {\n kind: 'channel' as const,\n id: teamId,\n address: null,\n displayName: normalizeNullableString(team?.name, 300),\n },\n ]\n : []),\n ],\n subject: null,\n text: text ?? null,\n html: null,\n attachments: attachments.value,\n occurredAt: timestamp ?? null,\n },\n }\n}\n\nexport type MicrosoftTeamsTenantResolution =\n | { ok: true; tenantId: string }\n | { ok: false; message: string }\n\n/**\n * Resolve the authenticated Teams tenant identity shared by the platform\n * receiver and product normalizer. Teams may repeat it in both\n * `channelData.tenant.id` and `conversation.tenantId`; disagreement is\n * rejected so an event can never be attributed to a guessed tenant.\n */\nexport function resolveMicrosoftTeamsTenantId(\n payload: unknown,\n): MicrosoftTeamsTenantResolution {\n if (!isRecord(payload)) {\n return { ok: false, message: 'Teams payload requires an activity object' }\n }\n const conversation = isRecord(payload.conversation)\n ? payload.conversation\n : null\n const channelData = isRecord(payload.channelData)\n ? payload.channelData\n : null\n const channelDataTenant = isRecord(channelData?.tenant)\n ? normalizeNullableString(channelData.tenant.id, 300)\n : null\n const conversationTenant = normalizeNullableString(\n conversation?.tenantId,\n 300,\n )\n if (\n channelDataTenant &&\n conversationTenant &&\n channelDataTenant !== conversationTenant\n ) {\n return {\n ok: false,\n message: 'Teams activity contains conflicting tenant ids',\n }\n }\n const tenantId = channelDataTenant ?? conversationTenant\n return tenantId\n ? { ok: true, tenantId }\n : { ok: false, message: 'Teams message requires a tenant id' }\n}\n\nfunction normalizeEmail(\n input: ProviderConversationEvent,\n): ConversationEventNormalizationResult {\n const payload = input.payload\n if (!isRecord(payload)) return invalidPayload('Email payload must be an object')\n const from = optionalString(payload.from, 320)\n const to = optionalString(payload.to, 320)\n if (\n from === undefined ||\n from === null ||\n to === undefined ||\n to === null ||\n !from.trim() ||\n !to.trim()\n ) {\n return invalidPayload('Email payload requires non-empty string from and to')\n }\n const messageId = optionalString(payload.messageId, 1_000)\n const subject = optionalString(payload.subject, 2_000)\n const text = optionalString(payload.text, MAX_BODY_LENGTH)\n const html = optionalString(payload.html, MAX_BODY_LENGTH)\n if (\n messageId === undefined ||\n subject === undefined ||\n text === undefined ||\n html === undefined\n ) {\n return invalidPayload('Email payload contains an invalid string field')\n }\n const receivedAt = optionalFiniteNumber(payload.receivedAt, 0)\n if (receivedAt === undefined) {\n return invalidPayload('Email receivedAt must be a non-negative number')\n }\n const headers = normalizeHeaders(payload.headers)\n if (!headers.ok) return headers\n const attachments = normalizeEmailAttachments(payload.attachments)\n if (!attachments.ok) return attachments\n\n return {\n ok: true,\n event: {\n version: 1,\n provider: 'email',\n eventType: input.type,\n operation: 'created',\n eventId:\n normalizeMessageId(messageId) ??\n normalizeNullableString(input.deliveryId, 1_000),\n conversationId: null,\n parentEventIds: referencedMessageIds(headers.value),\n sender: {\n id: null,\n address: normalizeNullableString(from, 320),\n displayName: null,\n },\n destinations: [\n {\n kind: 'mailbox',\n id: null,\n address: normalizeMailbox(to),\n displayName: null,\n },\n ],\n subject: normalizeNullableString(subject, 2_000),\n text: text ?? null,\n html: html ?? null,\n attachments: attachments.value,\n occurredAt: receivedAt ?? null,\n },\n }\n}\n\nfunction normalizeSlack(\n input: ProviderConversationEvent,\n): ConversationEventNormalizationResult {\n const wrapper = input.payload\n if (!isRecord(wrapper) || !isRecord(wrapper.event)) {\n return invalidPayload('Slack payload requires an Events API event object')\n }\n const outerEvent = wrapper.event\n const changedMessage =\n outerEvent.subtype === 'message_changed' && isRecord(outerEvent.message)\n ? outerEvent.message\n : null\n const deletedMessage =\n outerEvent.subtype === 'message_deleted' &&\n isRecord(outerEvent.previous_message)\n ? outerEvent.previous_message\n : null\n const message = changedMessage ?? deletedMessage ?? outerEvent\n if (\n message.type !== 'message' &&\n input.type !== 'slack.app_mention'\n ) {\n return invalidPayload('Slack event does not contain a message')\n }\n const text = optionalString(message.text, MAX_BODY_LENGTH)\n if (text === undefined) {\n return invalidPayload('Slack message text is invalid')\n }\n const channel =\n normalizeNullableString(outerEvent.channel, 300) ??\n normalizeNullableString(message.channel, 300)\n if (!channel) return invalidPayload('Slack message requires a channel')\n const timestamp =\n normalizeNullableString(message.ts, 100) ??\n normalizeNullableString(outerEvent.event_ts, 100)\n const threadTimestamp = normalizeNullableString(message.thread_ts, 100)\n const team =\n normalizeNullableString(wrapper.team_id, 300) ??\n normalizeNullableString(wrapper.context_team_id, 300)\n const rootTimestamp = threadTimestamp ?? timestamp\n const files = normalizeSlackFiles(message.files)\n if (!files.ok) return files\n const subtype = normalizeNullableString(outerEvent.subtype, 100)\n\n return {\n ok: true,\n event: {\n version: 1,\n provider: 'slack',\n eventType: input.type,\n operation:\n subtype === 'message_deleted'\n ? 'deleted'\n : subtype === 'message_changed'\n ? 'updated'\n : 'created',\n eventId:\n normalizeNullableString(wrapper.event_id, 300) ??\n normalizeNullableString(message.client_msg_id, 300) ??\n normalizeNullableString(input.deliveryId, 300) ??\n timestamp,\n conversationId: rootTimestamp\n ? [team, channel, rootTimestamp].filter(Boolean).join(':')\n : null,\n parentEventIds:\n threadTimestamp && timestamp && threadTimestamp !== timestamp\n ? [threadTimestamp]\n : [],\n sender: {\n id:\n normalizeNullableString(message.user, 300) ??\n normalizeNullableString(message.bot_id, 300),\n address: null,\n displayName:\n normalizeNullableString(message.username, 300) ??\n (isRecord(message.user_profile)\n ? normalizeNullableString(\n message.user_profile.display_name,\n 300,\n )\n : null),\n },\n destinations: [\n {\n kind: 'channel',\n id: channel,\n address: null,\n displayName: null,\n },\n ],\n subject: null,\n text: text ?? null,\n html: null,\n attachments: files.value,\n occurredAt:\n slackTimestampMs(timestamp) ??\n epochSecondsMs(wrapper.event_time) ??\n null,\n },\n }\n}\n\nfunction normalizeHeaders(\n value: unknown,\n):\n | { ok: true; value: Record<string, string> }\n | {\n ok: false\n code: 'invalid_payload'\n message: string\n } {\n if (value === undefined) return { ok: true, value: {} }\n if (!isRecord(value) || Object.keys(value).length > MAX_HEADERS) {\n return invalidPayload('Email headers must be a bounded string record')\n }\n const headers: Record<string, string> = {}\n for (const [key, entry] of Object.entries(value)) {\n if (\n key.length === 0 ||\n key.length > 200 ||\n typeof entry !== 'string' ||\n entry.length > 4_000\n ) {\n return invalidPayload('Email headers must be a bounded string record')\n }\n headers[key.toLowerCase()] = entry\n }\n return { ok: true, value: headers }\n}\n\nfunction normalizeEmailAttachments(\n value: unknown,\n):\n | { ok: true; value: ConversationAttachment[] }\n | {\n ok: false\n code: 'invalid_payload'\n message: string\n } {\n if (value === undefined) return { ok: true, value: [] }\n if (!Array.isArray(value) || value.length > MAX_ATTACHMENTS) {\n return invalidPayload('Email attachments exceed the supported limit')\n }\n const attachments: ConversationAttachment[] = []\n for (const entry of value) {\n if (!isRecord(entry)) {\n return invalidPayload('Email attachment must be an object')\n }\n const name = optionalString(entry.filename, 240)\n const contentType = optionalString(entry.contentType, 200)\n const contentBase64 = optionalString(\n entry.contentBase64,\n MAX_INLINE_ATTACHMENT_LENGTH,\n )\n const url = optionalString(entry.url, 2_048)\n const size = optionalFiniteNumber(entry.size, 0, MAX_ATTACHMENT_SIZE, true)\n if (\n name === undefined ||\n contentType === undefined ||\n contentBase64 === undefined ||\n url === undefined ||\n size === undefined\n ) {\n return invalidPayload('Email attachment contains an invalid field')\n }\n attachments.push({\n id: null,\n name: name ?? null,\n contentType: contentType ?? null,\n size: size ?? null,\n contentBase64: contentBase64 ?? null,\n url: url ?? null,\n })\n }\n return { ok: true, value: attachments }\n}\n\nfunction normalizeSlackFiles(\n value: unknown,\n):\n | { ok: true; value: ConversationAttachment[] }\n | {\n ok: false\n code: 'invalid_payload'\n message: string\n } {\n if (value === undefined) return { ok: true, value: [] }\n if (!Array.isArray(value) || value.length > MAX_ATTACHMENTS) {\n return invalidPayload('Slack files exceed the supported limit')\n }\n const files: ConversationAttachment[] = []\n for (const entry of value) {\n if (!isRecord(entry)) return invalidPayload('Slack file must be an object')\n const size = optionalFiniteNumber(entry.size, 0, MAX_ATTACHMENT_SIZE, true)\n if (size === undefined) return invalidPayload('Slack file size is invalid')\n files.push({\n id: normalizeNullableString(entry.id, 300),\n name:\n normalizeNullableString(entry.name, 240) ??\n normalizeNullableString(entry.title, 240),\n contentType: normalizeNullableString(entry.mimetype, 200),\n size: size ?? null,\n contentBase64: null,\n // Slack file URLs require the workspace bot token. Products use the\n // `slack.download_file` Hub action with this file id; exposing a private\n // URL here would make downstream runtimes attempt an unauthenticated fetch.\n url: null,\n })\n }\n return { ok: true, value: files }\n}\n\nfunction normalizeTeamsAttachments(\n value: unknown,\n):\n | { ok: true; value: ConversationAttachment[] }\n | {\n ok: false\n code: 'invalid_payload'\n message: string\n } {\n if (value === undefined) return { ok: true, value: [] }\n if (!Array.isArray(value) || value.length > MAX_ATTACHMENTS) {\n return invalidPayload('Teams attachments exceed the supported limit')\n }\n const attachments: ConversationAttachment[] = []\n for (const entry of value) {\n if (!isRecord(entry)) {\n return invalidPayload('Teams attachment must be an object')\n }\n const id = optionalString(entry.id, 300)\n const name = optionalString(entry.name, 240)\n const contentType = optionalString(entry.contentType, 200)\n if (\n id === undefined ||\n name === undefined ||\n contentType === undefined\n ) {\n return invalidPayload('Teams attachment contains an invalid field')\n }\n attachments.push({\n id: normalizeNullableString(id, 300),\n name: normalizeNullableString(name, 240),\n contentType: normalizeNullableString(contentType, 200),\n size: null,\n contentBase64: null,\n // Bot attachment URLs require Microsoft authorization. The receiver\n // keeps that credential inside Hub; products only receive stable metadata.\n url: null,\n })\n }\n return { ok: true, value: attachments }\n}\n\nfunction normalizeTeamsTimestamp(value: unknown): number | null | undefined {\n if (value === undefined || value === null) return null\n if (typeof value !== 'string' || value.length > 100) return undefined\n const timestamp = Date.parse(value)\n return Number.isFinite(timestamp) && timestamp >= 0\n ? timestamp\n : undefined\n}\n\nfunction referencedMessageIds(headers: Record<string, string>): string[] {\n const values = [headers['in-reply-to'], headers.references].filter(\n (value): value is string => Boolean(value?.trim()),\n )\n const ids: string[] = []\n for (const value of values) {\n const bracketed = value.match(/<[^<>]{1,1000}>/g)\n const candidates = bracketed ?? value.split(/\\s+/)\n for (const candidate of candidates) {\n const normalized = normalizeMessageId(candidate)\n if (normalized && !ids.includes(normalized)) ids.push(normalized)\n }\n }\n return ids.slice(0, 50)\n}\n\nfunction normalizeMessageId(value: string | null | undefined): string | null {\n if (!value) return null\n const trimmed = value.trim()\n if (!trimmed) return null\n return trimmed.startsWith('<') && trimmed.endsWith('>')\n ? trimmed.slice(1, -1).trim() || null\n : trimmed\n}\n\nfunction normalizeMailbox(value: string): string {\n return value.trim().toLowerCase()\n}\n\nfunction normalizeNullableString(\n value: unknown,\n maxLength: number,\n): string | null {\n return typeof value === 'string' && value.length <= maxLength\n ? value.trim() || null\n : null\n}\n\n/**\n * Undefined means invalid; null means the optional field was absent.\n */\nfunction optionalString(\n value: unknown,\n maxLength: number,\n): string | null | undefined {\n if (value === undefined) return null\n return typeof value === 'string' && value.length <= maxLength\n ? value\n : undefined\n}\n\n/**\n * Undefined means invalid; null means the optional field was absent.\n */\nfunction optionalFiniteNumber(\n value: unknown,\n minimum: number,\n maximum = Number.MAX_SAFE_INTEGER,\n integer = false,\n): number | null | undefined {\n if (value === undefined) return null\n if (\n typeof value !== 'number' ||\n !Number.isFinite(value) ||\n value < minimum ||\n value > maximum ||\n (integer && !Number.isInteger(value))\n ) {\n return undefined\n }\n return value\n}\n\nfunction slackTimestampMs(value: string | null): number | null {\n if (!value || !/^\\d{1,12}(?:\\.\\d{1,9})?$/.test(value)) return null\n const seconds = Number(value)\n return Number.isFinite(seconds) ? Math.round(seconds * 1_000) : null\n}\n\nfunction epochSecondsMs(value: unknown): number | null {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0\n ? Math.round(value * 1_000)\n : null\n}\n\nfunction unsupportedEvent(\n provider: string,\n type: string,\n): ConversationEventNormalizationResult {\n return {\n ok: false,\n code: 'unsupported_event',\n message: `Conversation events do not support ${provider} event ${type}`,\n }\n}\n\nfunction invalidPayload(\n message: string,\n): {\n ok: false\n code: 'invalid_payload'\n message: string\n} {\n return { ok: false, code: 'invalid_payload', message }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","import type { ConversationEventNormalizationResult, ProviderConversationEvent } from './index.js'\n\nfunction object(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\nfunction id(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0 && value.length <= 256 && !/[\\u0000-\\u001f\\u007f]/.test(value)\n}\nconst invalid = (message: string): ConversationEventNormalizationResult => ({ ok: false, code: 'invalid_payload', message })\n\n/** Fresh webhook snapshots only. Historical range notifications need journal hydration.\n * A chat represents one customer, but the message does not contain their address.\n * Keep that customer opaque; never mislabel message.from (our number) as the sender. */\nexport function normalizeLinqWhatsappConversation(input: ProviderConversationEvent): ConversationEventNormalizationResult {\n const value = input.payload\n if (!object(value) || input.type !== `linq-whatsapp.${value.type}`) return invalid('Event type does not match the provider envelope')\n if (value.type !== 'message.received') return { ok: false, code: 'unsupported_event', message: 'Not an incoming message' }\n if (!object(value.data) || !object(value.data.message)) return invalid('Read the chat journal to hydrate this historical event')\n const message = value.data.message\n if (!id(value.id) || !id(message.id) || !id(message.chat_id) || !id(message.from) || message.direction !== 'inbound') {\n return invalid('Incoming message requires a stable identity, conversation and owned destination')\n }\n if (value.data.chat_id !== undefined && value.data.chat_id !== message.chat_id) return invalid('Chat identity mismatch')\n if (!Array.isArray(message.parts) || !message.parts.length || message.parts.length > 50) return invalid('Invalid message parts')\n const text: string[] = []\n for (const part of message.parts) {\n if (!object(part) || part.type !== 'text' || typeof part.body !== 'string' || part.body.length > 4096) {\n return { ok: false, code: 'unsupported_event', message: 'This message requires non-text handling' }\n }\n text.push(part.body)\n }\n const occurredAt = typeof message.created_at === 'string' ? Date.parse(message.created_at) : NaN\n if (!Number.isSafeInteger(occurredAt) || occurredAt < 0) return invalid('Invalid message timestamp')\n return { ok: true, event: {\n version: 1, provider: 'linq-whatsapp', eventType: input.type, operation: 'created', eventId: message.id,\n conversationId: message.chat_id, parentEventIds: [],\n sender: { id: `customer:${message.chat_id}`, address: null, displayName: null },\n destinations: [{ kind: 'chat', id: message.from, address: message.from, displayName: null }],\n subject: null, text: text.join('\\n'), html: null, attachments: [], occurredAt, isGroup: false,\n } }\n}\n","import type { ConversationAttachment, ConversationEvent, ConversationEventNormalizationResult, ProviderConversationEvent } from './index.js'\n\ntype RecordValue = Record<string, unknown>\nfunction record(value: unknown): value is RecordValue { return value !== null && typeof value === 'object' && !Array.isArray(value) }\nfunction string(value: unknown, max = 2000): string | null {\n return typeof value === 'string' && value.length > 0 && value.length <= max && !/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]/.test(value) ? value : null\n}\nfunction timestamp(value: unknown): number | null {\n const n = typeof value === 'number' ? value * 1000 : typeof value === 'string' ? Date.parse(value) : NaN\n return Number.isSafeInteger(n) && n >= 0 ? n : null\n}\nconst invalid = (message: string): ConversationEventNormalizationResult => ({ ok: false, code: 'invalid_payload', message })\nconst unsupported = (): ConversationEventNormalizationResult => ({ ok: false, code: 'unsupported_event', message: 'Not a supported incoming conversation message' })\n\nfunction attachment(value: unknown): ConversationAttachment | null {\n if (!record(value)) return null\n const url = string(value.url ?? value.value, 8192)\n if (!url) return null\n try { const u = new URL(url); if (u.protocol !== 'https:' || u.username || u.password) return null } catch { return null }\n return { id: string(value.id), name: string(value.filename ?? value.name, 255),\n contentType: string(value.mime_type ?? value.mime ?? value.content_type, 200), size: null, contentBase64: null, url }\n}\n\nfunction finish(input: ProviderConversationEvent, data: {\n id: unknown; conversation: unknown; sender: unknown; destination: unknown;\n destinationAddress?: unknown; text: unknown; time: unknown; media?: unknown; parent?: unknown;\n subject?: unknown; destinationKind?: 'chat' | 'mailbox'; isGroup?: boolean; historyOnly?: boolean;\n}): ConversationEventNormalizationResult {\n const id = string(data.id), conversation = string(data.conversation), sender = string(data.sender), destination = string(data.destination)\n if (!id || !conversation || !sender || !destination) return invalid('Message identity, conversation, sender and destination are required')\n if (data.text !== null && data.text !== undefined && (typeof data.text !== 'string' || data.text.length > 1_000_000)) return invalid('Invalid message text')\n if (data.media !== undefined && data.media !== null && (!Array.isArray(data.media) || data.media.length > 50)) return invalid('Invalid attachment list')\n const media = (data.media ?? []) as unknown[]\n const attachments = media.map(attachment)\n if (attachments.some((a) => !a)) return invalid('Attachments require HTTPS references; bytes must be resolved through the authorized file boundary')\n const time = timestamp(data.time)\n if (time === null) return invalid('A valid provider timestamp is required')\n const provider = input.provider as 'inkbox' | 'linq' | 'contiguity'\n const event: ConversationEvent = {\n version: 1, provider, eventType: input.type, operation: 'created', eventId: id,\n conversationId: conversation, parentEventIds: string(data.parent) ? [String(data.parent)] : [],\n sender: { id: sender, address: sender, displayName: null },\n destinations: [{ kind: data.destinationKind ?? 'chat', id: destination, address: string(data.destinationAddress), displayName: null }],\n subject: string(data.subject, 998), text: (data.text as string | null | undefined) ?? null, html: null,\n attachments: attachments as ConversationAttachment[], occurredAt: time,\n isGroup: data.isGroup === true, historyOnly: data.historyOnly === true,\n }\n return { ok: true, event }\n}\n\n/** Called after the host verifies signatures and resolves the owning connection. */\nexport function normalizeMobileConversation(input: ProviderConversationEvent): ConversationEventNormalizationResult {\n const p = input.payload\n if (!record(p) || !record(p.data)) return invalid('Provider payload requires a data object')\n const data = p.data\n if (input.provider === 'inkbox') {\n if (input.type !== `inkbox.${p.event_type}`) return invalid('Event type does not match the provider envelope')\n if (p.event_type === 'imessage.received') {\n const m = data.message\n if (!record(m) || m.direction !== 'inbound') return invalid('Expected an inbound iMessage')\n return finish(input, { id: m.id, conversation: m.conversation_id, sender: m.sender_number ?? m.remote_number,\n destination: m.conversation_id, text: m.content, time: m.created_at ?? p.timestamp, media: m.media, isGroup: m.is_group === true })\n }\n if (p.event_type === 'text.received') {\n const m = data.text_message\n if (!record(m) || m.direction !== 'inbound') return invalid('Expected an inbound phone text')\n return finish(input, { id: m.id, conversation: m.conversation_id, sender: m.sender_phone_number ?? m.remote_phone_number,\n destination: m.local_phone_number, destinationAddress: m.local_phone_number, text: m.text, time: m.created_at ?? p.timestamp,\n media: m.media, isGroup: m.is_group === true })\n }\n if (p.event_type === 'message.received') {\n const m = data.message\n if (!record(m) || m.direction !== 'inbound') return invalid('Expected inbound mail')\n return finish(input, { id: m.id, conversation: m.thread_id ?? m.id, sender: m.from_address,\n destination: m.email_address, destinationAddress: m.email_address, destinationKind: 'mailbox', text: m.body,\n time: m.created_at ?? p.timestamp, subject: m.subject,\n historyOnly: m.body_state !== 'complete' || m.body_truncated === true })\n }\n return unsupported()\n }\n if (input.provider === 'linq') {\n if (input.type !== `linq.${p.event_type}`) return invalid('Event type does not match the provider envelope')\n if (p.event_type !== 'message.received') return unsupported()\n if (p.webhook_version !== '2026-02-03' || data.direction !== 'inbound' || !record(data.chat)\n || !record(data.sender_handle) || !record(data.chat.owner_handle) || data.chat.owner_handle.is_me !== true || data.sender_handle.is_me === true) {\n return invalid('Linq requires v2026-02-03 incoming payloads with explicit sender and owner handles')\n }\n if (!Array.isArray(data.parts) || data.parts.length > 50) return invalid('Invalid Linq parts')\n const texts: string[] = [], media: RecordValue[] = []\n for (const part of data.parts) {\n if (!record(part)) return invalid('Invalid Linq part')\n if (part.type === 'text' || part.type === 'link') {\n if (typeof part.value !== 'string') return invalid('Invalid Linq text')\n texts.push(part.value)\n } else if (part.type === 'media') media.push(part)\n else return unsupported()\n }\n return finish(input, { id: data.id, conversation: data.chat.id, sender: data.sender_handle.handle,\n destination: data.chat.id, destinationAddress: data.chat.owner_handle.handle,\n text: texts.join('\\n'), time: data.sent_at ?? p.created_at, media,\n parent: record(data.reply_to) ? data.reply_to.message_id : undefined,\n isGroup: data.chat.is_group === true, historyOnly: data.reconciled_at != null || data.zero_retention === true })\n }\n if (input.provider === 'contiguity') {\n if (input.type !== `contiguity.${p.type}`) return invalid('Event type does not match the provider envelope')\n if (!['imessage.incoming', 'text.incoming.sms', 'text.incoming.mms'].includes(String(p.type))) return unsupported()\n if (!string(data.to, 320) || !string(data.from, 320)) return invalid('Missing Contiguity phone routing')\n // No native chat id in v2: use a collision-free tuple, not a bare sender across channels.\n return finish(input, { id: p.id, conversation: JSON.stringify([p.type === 'imessage.incoming' ? 'imessage' : 'text', data.to, data.from]),\n sender: data.from, destination: data.to, destinationAddress: data.to, text: data.body,\n time: data.timestamp ?? p.timestamp, media: data.attachments })\n }\n return { ok: false, code: 'unsupported_provider', message: 'Unsupported mobile provider' }\n}\n","import { normalizeConversationEvent, type ConversationEventNormalizationResult, type ProviderConversationEvent } from './index.js'\n\nexport interface ConversationReply {\n /** Qualified existing Hub action. The host supplies the bound connection. */\n action: string\n input: Record<string, unknown>\n /** Pass as the invocation's idempotency key, unchanged on every retry of this reply. */\n idempotencyKey: string\n}\n\ntype Failure = Exclude<ConversationEventNormalizationResult, { ok: true }>\nfunction object(value: unknown): Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {}\n}\nconst fail = (message: string): Failure => ({ ok: false, code: 'invalid_payload', message })\n\n/**\n * Derive a plain-text reply from a previously authenticated, stored event.\n * No model-selected recipient, sender, fallback channel or credential.\n * This is routing, not permission: recheck the bound connection and current\n * grant, persist the outbox key/body, then invoke through the existing Hub SDK.\n */\nexport function buildMessagingReply(\n input: ProviderConversationEvent,\n text: string,\n operationId: string,\n): { ok: true; reply: ConversationReply } | Failure {\n const normalized = normalizeConversationEvent(input)\n if (!normalized.ok) return normalized\n const event = normalized.event\n if (typeof text !== 'string' || !text.trim() || text.length > 10000 || text.includes('\\0')) return fail('Reply text is empty or exceeds its limit')\n if (typeof operationId !== 'string' || !operationId || operationId.length > 256 || /[\\u0000-\\u001f]/.test(operationId)) return fail('A stable operation id is required')\n if (event.historyOnly || event.isGroup) return fail('This event requires review or complete input before a reply')\n const data = object(object(input.payload).data)\n if (event.provider === 'inkbox') {\n if (event.eventType === 'inkbox.imessage.received') {\n return { ok: true, reply: { idempotencyKey: operationId, action: 'inkbox.imessage.reply', input: { conversation_id: event.conversationId, text } } }\n }\n if (event.eventType === 'inkbox.text.received') {\n const message = object(data.text_message)\n if (typeof message.phone_number_id !== 'string' || !message.phone_number_id || text.length > 1600) return fail('SMS requires its owned phone id and at most 1600 characters')\n return { ok: true, reply: { idempotencyKey: operationId, action: 'inkbox.sms.reply', input: { phone_number_id: message.phone_number_id, conversation_id: event.conversationId, text } } }\n }\n if (event.eventType === 'inkbox.message.received') {\n const message = object(data.message)\n if (!event.sender.address || typeof message.email_address !== 'string') return fail('Mail reply requires an explicit sender and mailbox')\n const subject = event.subject ?? ''\n return { ok: true, reply: { idempotencyKey: operationId, action: 'inkbox.email.send', input: {\n email_address: message.email_address, to: [event.sender.address],\n subject: /^re:/i.test(subject) ? subject : `Re: ${subject}`.slice(0, 998), text,\n in_reply_to_message_id: event.eventId,\n } } }\n }\n }\n if (event.provider === 'linq-whatsapp') {\n if (text.length > 4096) return fail('WhatsApp text is limited to 4096 characters')\n return { ok: true, reply: { idempotencyKey: operationId, action: 'linq-whatsapp.messages.reply', input: { chat_id: event.conversationId, text } } }\n }\n if (event.provider === 'linq') {\n return { ok: true, reply: { idempotencyKey: operationId, action: 'linq.messages.reply', input: { chat_id: event.conversationId, text, message_key: operationId } } }\n }\n if (event.provider === 'contiguity') {\n return { ok: true, reply: { idempotencyKey: operationId, action: event.eventType === 'contiguity.imessage.incoming' ? 'contiguity.messages.send_imessage' : 'contiguity.sms.send',\n input: { to: event.sender.address, from: event.destinations[0]?.address, message: text } } }\n }\n return { ok: false, code: 'unsupported_provider', message: 'Use the existing channel-specific reply tool for this provider' }\n}\n","/** Protocol metadata, not a claim that a deployment or account is configured. */\nexport interface ConversationChannel {\n providerId: string\n eventType: string\n label: string\n transport: 'email' | 'imessage' | 'sms' | 'whatsapp'\n sourceKind: 'channel' | 'connection'\n replies: boolean\n inventoryAction?: string\n replyAction?: string\n numberProvisioning?: 'provider-assigned'\n}\n\nconst channels: readonly ConversationChannel[] = [\n { providerId: 'email', eventType: 'email.received', label: 'Tangle email', transport: 'email', sourceKind: 'channel', replies: false },\n { providerId: 'inkbox', eventType: 'inkbox.imessage.received', label: 'iMessage', transport: 'imessage', sourceKind: 'connection', replies: true },\n { providerId: 'inkbox', eventType: 'inkbox.text.received', label: 'SMS', transport: 'sms', sourceKind: 'connection', replies: true },\n { providerId: 'inkbox', eventType: 'inkbox.message.received', label: 'Email', transport: 'email', sourceKind: 'connection', replies: true },\n { providerId: 'linq', eventType: 'linq.message.received', label: 'iMessage / SMS', transport: 'imessage', sourceKind: 'connection', replies: true, inventoryAction: 'linq.numbers.list', replyAction: 'linq.messages.reply', numberProvisioning: 'provider-assigned' },\n { providerId: 'contiguity', eventType: 'contiguity.imessage.incoming', label: 'iMessage', transport: 'imessage', sourceKind: 'connection', replies: true },\n { providerId: 'contiguity', eventType: 'contiguity.text.incoming.sms', label: 'SMS', transport: 'sms', sourceKind: 'connection', replies: true },\n { providerId: 'linq-whatsapp', eventType: 'linq-whatsapp.message.received', label: 'WhatsApp', transport: 'whatsapp', sourceKind: 'connection', replies: true, inventoryAction: 'linq-whatsapp.numbers.list', replyAction: 'linq-whatsapp.messages.reply' },\n]\n\n/** Fresh copies let applications filter by their live Hub catalog without mutating ours. */\nexport function listConversationChannels(): ConversationChannel[] {\n return channels.map(channel => ({ ...channel }))\n}\n\nexport interface ConversationEndpointOption {\n id: string\n /** Provider display address. Use id, not a reformatted address, to select a resource. */\n address: string\n providerId: string\n channel: 'imessage' | 'whatsapp'\n health: 'healthy' | 'at-risk' | 'critical' | 'unknown'\n}\nfunction record(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\nfunction bounded(value: unknown, max: number): value is string {\n return typeof value === 'string' && value.trim().length > 0 && value.length <= max && !/[\\u0000-\\u001f\\u007f]/.test(value)\n}\n/** Project an authenticated provider-owned inventory response, not user input.\n * Protocol shapes stay with the adapters. Unknown provider health remains unknown;\n * configuration, customer eligibility and delivery readiness are separate facts. */\nexport function conversationEndpointOptions(providerId: string, result: unknown): ConversationEndpointOption[] {\n if (providerId !== 'linq' && providerId !== 'linq-whatsapp') throw new Error('Owned endpoint enumeration is not available for this provider')\n const whatsapp = providerId === 'linq-whatsapp'\n const values = record(result) ? result[whatsapp ? 'data' : 'phone_numbers'] : null\n if (!Array.isArray(values)) throw new Error('Provider did not return its owned phone-number inventory')\n if (values.length > 1000) throw new Error('Phone inventory exceeds the supported response limit')\n const ids = new Set<string>(), addresses = new Set<string>()\n return values.map(value => {\n if (!record(value)) throw new Error('Invalid phone inventory row')\n const { id, phone_number: address } = value\n if (!bounded(id, 256) || !bounded(address, 320) || ids.has(id) || addresses.has(address)) {\n throw new Error('Invalid or ambiguous owned phone-number identity')\n }\n if (!whatsapp && (!/^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$/i.test(id) || !/^\\+[1-9]\\d{6,14}$/.test(address))) {\n throw new Error('Invalid or ambiguous owned phone-number identity')\n }\n ids.add(id); addresses.add(address)\n const status = whatsapp ? value.quality_band : record(value.reputation) ? value.reputation.status : undefined\n // WhatsApp raw quality values evolve. Only its documented quality_band is classified.\n const health: ConversationEndpointOption['health'] = status === (whatsapp ? 'green' : 'HEALTHY') ? 'healthy'\n : status === (whatsapp ? 'yellow' : 'AT_RISK') ? 'at-risk'\n : status === (whatsapp ? 'red' : 'CRITICAL') ? 'critical' : 'unknown'\n return { id, address, providerId, channel: whatsapp ? 'whatsapp' as const : 'imessage' as const, health }\n })\n}\n","import {\n normalizeConversationEvent as normalizeExistingConversationEvent,\n type ConversationEvent as ExistingConversationEvent,\n type ConversationEventNormalizationResult as ExistingNormalizationResult,\n} from './core.js'\nimport { normalizeLinqWhatsappConversation } from './linq-whatsapp.js'\nimport { normalizeMobileConversation } from './mobile.js'\n\nexport * from './core.js'\nexport { buildMessagingReply, type ConversationReply } from './reply.js'\nexport { listConversationChannels, conversationEndpointOptions, type ConversationChannel, type ConversationEndpointOption } from './channels.js'\n\n/** Additive provider vocabulary. Neither sender identity nor group membership is authority. */\nexport interface ConversationEvent extends Omit<ExistingConversationEvent, 'provider'> {\n provider: ExistingConversationEvent['provider'] | 'inkbox' | 'linq' | 'contiguity' | 'linq-whatsapp'\n isGroup?: boolean\n /** Historical or incomplete input is not a new automatic command. */\n historyOnly?: boolean\n}\nexport type ConversationEventNormalizationResult =\n | { ok: true; event: ConversationEvent }\n | Exclude<ExistingNormalizationResult, { ok: true }>\n\nexport function normalizeConversationEvent(value: unknown): ConversationEventNormalizationResult {\n if (value && typeof value === 'object' && 'provider' in value\n && ['inkbox', 'linq', 'contiguity', 'linq-whatsapp'].includes(String(value.provider))) {\n if (!('type' in value) || typeof value.type !== 'string' || !('payload' in value)) {\n return { ok: false, code: 'invalid_payload', message: 'Provider event requires type and payload' }\n }\n if (value.provider === 'linq-whatsapp') return normalizeLinqWhatsappConversation({ provider: value.provider, type: value.type, payload: value.payload })\n return normalizeMobileConversation({ provider: String(value.provider), type: value.type, payload: value.payload })\n }\n return normalizeExistingConversationEvent(value)\n}\n"],"mappings":"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","names":["timestamp","id","invalid","id","object","normalizeConversationEvent","record","id","normalizeConversationEvent"]}
|
|
@@ -71,6 +71,8 @@ interface ManagedNumberOrder {
|
|
|
71
71
|
connectionId?: string;
|
|
72
72
|
status: 'pending' | 'provider_pending' | 'needs_review' | 'ready_for_setup' | 'cancelled';
|
|
73
73
|
errorCode?: string;
|
|
74
|
+
/** HTTP status behind `errorCode`, when the provider gave one. 402, 401 and 422 need different operator work. */
|
|
75
|
+
errorStatus?: number;
|
|
74
76
|
nextAttemptAt?: number;
|
|
75
77
|
}
|
|
76
78
|
interface ManagedNumberOrderStore {
|
|
@@ -189,18 +189,22 @@ function selectedNumber(order, identity) {
|
|
|
189
189
|
return order.transport === "sms" ? identity.sms : identity.imessageEnabled ? identity.imessage : null;
|
|
190
190
|
}
|
|
191
191
|
var IN_FLIGHT_MS = 5 * 6e4;
|
|
192
|
+
var REVIEW_BACKOFF_MS = 6 * 60 * 6e4;
|
|
192
193
|
async function advanceManagedNumber(orderId, ports) {
|
|
193
194
|
let order = await ports.orders.get(orderId);
|
|
194
195
|
if (!order) throw new Error("Managed number order not found");
|
|
195
|
-
if (!order.id || order.id.length > 128 || !/^[a-zA-Z0-9:._-]+$/.test(order.id) || order.id !== orderId || !order.ownerId || !order.organizationId || !order.fundingAuthorizationId || !["sms", "imessage"].includes(order.transport) || !["identity", "number", "credential", "connection", "complete"].includes(order.phase) ||
|
|
196
|
+
if (!order.id || order.id.length > 128 || !/^[a-zA-Z0-9:._-]+$/.test(order.id) || order.id !== orderId || !order.ownerId || !order.organizationId || !order.fundingAuthorizationId || !["sms", "imessage"].includes(order.transport) || !["identity", "number", "credential", "connection", "complete"].includes(order.phase) || // The provider refuses a malformed state; reject it here so it can never reach a purchase.
|
|
197
|
+
order.state !== void 0 && !/^[A-Z]{2}$/.test(order.state) || !Number.isSafeInteger(order.version) || order.version < 0) throw new MessagingProvisionError("invalid_input");
|
|
196
198
|
let mutationRefused = false;
|
|
199
|
+
let mutationUnsent = false;
|
|
197
200
|
let mutationSettled = false;
|
|
198
201
|
if (order.phase === "complete" || order.status === "cancelled") return order;
|
|
199
|
-
const
|
|
202
|
+
const clock = ports.now ?? Date.now;
|
|
203
|
+
const now = clock();
|
|
200
204
|
if (order.nextAttemptAt && order.nextAttemptAt > now) return order;
|
|
201
205
|
async function save(patch) {
|
|
202
206
|
const before = order;
|
|
203
|
-
const next = { ...before, ...patch, version: before.version + 1 };
|
|
207
|
+
const next = { ...before, ..."errorCode" in patch && !("errorStatus" in patch) ? { errorStatus: void 0 } : {}, ...patch, version: before.version + 1 };
|
|
204
208
|
if (await ports.orders.saveIfVersion(next, before.version)) {
|
|
205
209
|
order = next;
|
|
206
210
|
return next;
|
|
@@ -231,7 +235,10 @@ async function advanceManagedNumber(orderId, ports) {
|
|
|
231
235
|
try {
|
|
232
236
|
return await call();
|
|
233
237
|
} catch (error) {
|
|
234
|
-
if (error instanceof MessagingProvisionError
|
|
238
|
+
if (error instanceof MessagingProvisionError) {
|
|
239
|
+
if (error.code === "invalid_input") mutationUnsent = true;
|
|
240
|
+
if (error.code === "provider_rejected" || error.code === "invalid_input") mutationRefused = true;
|
|
241
|
+
}
|
|
235
242
|
throw error;
|
|
236
243
|
} finally {
|
|
237
244
|
mutationSettled = true;
|
|
@@ -239,7 +246,7 @@ async function advanceManagedNumber(orderId, ports) {
|
|
|
239
246
|
}
|
|
240
247
|
async function claim() {
|
|
241
248
|
const before = order;
|
|
242
|
-
const claimed = await save({ attempted: true, attemptedAt:
|
|
249
|
+
const claimed = await save({ attempted: true, attemptedAt: clock(), status: "pending", errorCode: void 0, nextAttemptAt: void 0 });
|
|
243
250
|
if (claimed.version !== before.version + 1 || order !== claimed) return false;
|
|
244
251
|
let authorized = false;
|
|
245
252
|
try {
|
|
@@ -263,45 +270,49 @@ async function advanceManagedNumber(orderId, ports) {
|
|
|
263
270
|
const current = await ports.orders.get(orderId);
|
|
264
271
|
if (!current || current.version !== order.version || current.status === "cancelled") return false;
|
|
265
272
|
if (!await ports.canProvision(current)) {
|
|
266
|
-
await save({ status: "provider_pending", errorCode: "activation_not_configured", nextAttemptAt:
|
|
273
|
+
await save({ status: "provider_pending", errorCode: "activation_not_configured", nextAttemptAt: clock() + 6e4 });
|
|
267
274
|
return false;
|
|
268
275
|
}
|
|
269
276
|
if (!await ports.authorizeFunding(current)) {
|
|
270
|
-
await save({ status: "provider_pending", errorCode: "funding_required", nextAttemptAt:
|
|
277
|
+
await save({ status: "provider_pending", errorCode: "funding_required", nextAttemptAt: clock() + 6e4 });
|
|
271
278
|
return false;
|
|
272
279
|
}
|
|
273
280
|
const rechecked = await ports.orders.get(orderId);
|
|
274
281
|
return rechecked?.version === order.version && rechecked.status !== "cancelled";
|
|
275
282
|
}
|
|
283
|
+
async function leaseAttempt(burnedCode) {
|
|
284
|
+
if (inFlight(order)) return order;
|
|
285
|
+
if (order.attempted) return save({ status: "needs_review", errorCode: burnedCode, nextAttemptAt: clock() + REVIEW_BACKOFF_MS });
|
|
286
|
+
if (!await claim()) return await ports.orders.get(orderId);
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
276
289
|
try {
|
|
277
290
|
if (order.phase === "identity") {
|
|
278
291
|
let identity2 = await ports.provider.getIdentity(order.handle);
|
|
279
292
|
if (!identity2) {
|
|
280
|
-
|
|
281
|
-
if (
|
|
282
|
-
if (!await claim()) return await ports.orders.get(orderId);
|
|
293
|
+
const lease = await leaseAttempt("identity_outcome_unknown");
|
|
294
|
+
if (lease) return lease;
|
|
283
295
|
const handle = order.handle;
|
|
284
296
|
identity2 = await mutate(() => ports.provider.createIdentity(handle));
|
|
285
297
|
} else if (!order.attempted && !order.identityId) {
|
|
286
|
-
return save({ status: "needs_review", errorCode: "identity_already_exists" });
|
|
298
|
+
return save({ status: "needs_review", errorCode: "identity_already_exists", nextAttemptAt: clock() + REVIEW_BACKOFF_MS });
|
|
287
299
|
}
|
|
288
300
|
identityMatches(order, identity2);
|
|
289
301
|
return save({ identityId: identity2.id, phase: "number", attempted: false, status: "pending", errorCode: void 0 });
|
|
290
302
|
}
|
|
291
303
|
if (!order.identityId) throw new MessagingProvisionError("invalid_receipt");
|
|
292
304
|
const identity = await ports.provider.getIdentity(order.handle);
|
|
293
|
-
if (!identity) return save({ status: "needs_review", errorCode: "identity_missing" });
|
|
305
|
+
if (!identity) return save({ status: "needs_review", errorCode: "identity_missing", nextAttemptAt: clock() + REVIEW_BACKOFF_MS });
|
|
294
306
|
identityMatches(order, identity);
|
|
295
307
|
if (order.phase === "number") {
|
|
296
308
|
let number2 = selectedNumber(order, identity);
|
|
297
|
-
if (!number2 && order.number) return save({ status: "needs_review", errorCode: "number_missing" });
|
|
309
|
+
if (!number2 && order.number) return save({ status: "needs_review", errorCode: "number_missing", nextAttemptAt: clock() + REVIEW_BACKOFF_MS });
|
|
298
310
|
if (!number2) {
|
|
299
311
|
if (order.attempted && order.transport === "imessage" && identity.imessageEnabled) {
|
|
300
|
-
return save({ status: "provider_pending", errorCode: "number_pending", nextAttemptAt:
|
|
312
|
+
return save({ status: "provider_pending", errorCode: "number_pending", nextAttemptAt: clock() + 3e4 });
|
|
301
313
|
}
|
|
302
|
-
|
|
303
|
-
if (
|
|
304
|
-
if (!await claim()) return await ports.orders.get(orderId);
|
|
314
|
+
const lease = await leaseAttempt("number_outcome_unknown");
|
|
315
|
+
if (lease) return lease;
|
|
305
316
|
const { handle, state, id } = order;
|
|
306
317
|
if (order.transport === "sms") {
|
|
307
318
|
const purchased = await mutate(() => ports.provider.provisionSms(handle, `${id}:sms`, state));
|
|
@@ -318,10 +329,10 @@ async function advanceManagedNumber(orderId, ports) {
|
|
|
318
329
|
number2 = selectedNumber(order, receipt);
|
|
319
330
|
}
|
|
320
331
|
}
|
|
321
|
-
if (!number2) return save({ status: "provider_pending", errorCode: "number_pending", nextAttemptAt:
|
|
332
|
+
if (!number2) return save({ status: "provider_pending", errorCode: "number_pending", nextAttemptAt: clock() + 3e4 });
|
|
322
333
|
if (order.number && (order.number.id !== number2.id || order.number.number !== number2.number)) throw new MessagingProvisionError("invalid_receipt");
|
|
323
334
|
if (order.transport === "sms" && (number2.smsStatus !== "ready" || number2.status !== "active")) {
|
|
324
|
-
return save({ number: number2, attempted: false, status: "provider_pending", nextAttemptAt:
|
|
335
|
+
return save({ number: number2, attempted: false, status: "provider_pending", nextAttemptAt: clock() + 3e4, errorCode: "sms_not_ready" });
|
|
325
336
|
}
|
|
326
337
|
return save({ number: number2, phase: "credential", attempted: false, status: "pending", errorCode: void 0, nextAttemptAt: void 0 });
|
|
327
338
|
}
|
|
@@ -330,9 +341,8 @@ async function advanceManagedNumber(orderId, ports) {
|
|
|
330
341
|
if (order.phase === "credential") {
|
|
331
342
|
let credential2 = await ports.vault.read(order.id);
|
|
332
343
|
if (!credential2) {
|
|
333
|
-
|
|
334
|
-
if (
|
|
335
|
-
if (!await claim()) return await ports.orders.get(orderId);
|
|
344
|
+
const lease = await leaseAttempt("credential_receipt_lost");
|
|
345
|
+
if (lease) return lease;
|
|
336
346
|
const { identityId, id } = order;
|
|
337
347
|
const minted = await mutate(() => ports.provider.mintIdentityKey(identityId, `Tangle number ${id}`));
|
|
338
348
|
credential2 = { ...minted, identityId: order.identityId };
|
|
@@ -351,13 +361,16 @@ async function advanceManagedNumber(orderId, ports) {
|
|
|
351
361
|
} catch (error) {
|
|
352
362
|
const code = error instanceof MessagingProvisionError ? error.code : "outcome_unknown";
|
|
353
363
|
const retryAfter = error instanceof MessagingProvisionError ? error.retryAfterSeconds : void 0;
|
|
354
|
-
const refused = mutationRefused && order.phase !== "credential";
|
|
364
|
+
const refused = mutationRefused && (order.phase !== "credential" || mutationUnsent);
|
|
365
|
+
const review = code === "invalid_receipt";
|
|
366
|
+
const failedAt = clock();
|
|
355
367
|
return save({
|
|
356
|
-
status:
|
|
368
|
+
status: review ? "needs_review" : "provider_pending",
|
|
357
369
|
errorCode: code,
|
|
370
|
+
errorStatus: error instanceof MessagingProvisionError ? error.status : void 0,
|
|
358
371
|
...refused ? { attempted: false } : {},
|
|
359
372
|
...mutationSettled ? { attemptedAt: void 0 } : {},
|
|
360
|
-
nextAttemptAt:
|
|
373
|
+
nextAttemptAt: failedAt + (review ? REVIEW_BACKOFF_MS : Math.max(30, Math.min(retryAfter ?? 30, 86400)) * 1e3)
|
|
361
374
|
});
|
|
362
375
|
}
|
|
363
376
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/managed-messaging/inkbox.ts","../../src/managed-messaging/provision.ts"],"sourcesContent":["export type ManagedMessageTransport = 'sms' | 'imessage'\nexport interface InkboxNumber { id: string; number: string; smsStatus: string | null; status: string | null }\nexport interface InkboxIdentity {\n id: string\n handle: string\n organizationId: string\n status: string\n imessageEnabled: boolean\n sms: InkboxNumber | null\n imessage: InkboxNumber | null\n}\nexport class MessagingProvisionError extends Error {\n constructor(\n readonly code: 'invalid_input' | 'unavailable' | 'provider_rejected' | 'outcome_unknown' | 'invalid_receipt',\n readonly status?: number,\n readonly retryAfterSeconds?: number,\n ) {\n super(`Messaging provisioning: ${code}${status ? ` (HTTP ${status})` : ''}`)\n this.name = 'MessagingProvisionError'\n }\n}\nconst BASE = 'https://inkbox.ai/api/v1'\nconst UUID = /^[a-f\\d]{8}(?:-[a-f\\d]{4}){3}-[a-f\\d]{12}$/i\nconst PHONE = /^\\+[1-9]\\d{6,14}$/\nconst HANDLE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/\nfunction record(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) throw new MessagingProvisionError('invalid_receipt')\n return value as Record<string, unknown>\n}\nfunction readNumber(value: unknown): InkboxNumber | null {\n if (value == null) return null\n const row = record(value)\n if (typeof row.id !== 'string' || !UUID.test(row.id) || typeof row.number !== 'string' || !PHONE.test(row.number)) throw new MessagingProvisionError('invalid_receipt')\n return { id: row.id, number: row.number, smsStatus: typeof row.sms_status === 'string' ? row.sms_status : null, status: typeof row.status === 'string' ? row.status : null }\n}\n/** Project only channel identity. Mailbox, tunnel, credentials and contacts never leave this boundary. */\nexport function parseInkboxIdentity(value: unknown): InkboxIdentity {\n const row = record(value)\n if (typeof row.id !== 'string' || !UUID.test(row.id) || typeof row.agent_handle !== 'string' ||\n row.agent_handle.length < 3 || row.agent_handle.length > 63 || !HANDLE.test(row.agent_handle) ||\n typeof row.organization_id !== 'string' || !row.organization_id || row.organization_id.length > 256 ||\n typeof row.status !== 'string' || !row.status || typeof row.imessage_enabled !== 'boolean') throw new MessagingProvisionError('invalid_receipt')\n return { id: row.id, handle: row.agent_handle, organizationId: row.organization_id, status: row.status,\n imessageEnabled: row.imessage_enabled, sms: readNumber(row.phone_number), imessage: readNumber(row.imessage_number) }\n}\nfunction assertHandle(value: string): void {\n if (value.length < 3 || value.length > 63 || !HANDLE.test(value)) throw new MessagingProvisionError('invalid_input')\n}\nfunction assertOperation(value: string): void {\n if (!value || value.length > 200 || !/^[a-zA-Z0-9:._-]+$/.test(value)) throw new MessagingProvisionError('invalid_input')\n}\nasync function readJson(response: Response): Promise<unknown> {\n if (!response.body) throw new MessagingProvisionError('invalid_receipt')\n const reader = response.body.getReader()\n const chunks: Uint8Array[] = []; let size = 0\n try {\n while (true) {\n const chunk = await reader.read()\n if (chunk.done) break\n size += chunk.value.byteLength\n if (size > 1_048_576) { await reader.cancel(); throw new MessagingProvisionError('invalid_receipt') }\n chunks.push(chunk.value)\n }\n const bytes = new Uint8Array(size); let offset = 0\n for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.length }\n return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes)) as unknown\n } catch { throw new MessagingProvisionError('invalid_receipt') }\n finally { reader.releaseLock() }\n}\n\n/**\n * A read that fails transiently is `unavailable`: it says nothing about a\n * mutation that already succeeded. Only a mutation's own definitive 4xx is\n * `provider_rejected`, which is what permits another purchase attempt.\n */\nfunction failureCode(method: string, status: number): MessagingProvisionError['code'] {\n const transient = status >= 500 || status === 408\n if (method === 'GET') return transient || status === 429 ? 'unavailable' : 'provider_rejected'\n return transient ? 'outcome_unknown' : 'provider_rejected'\n}\n\n/** Host-only administrative client; NOT a ConnectorAdapter and never an agent tool. */\nexport class InkboxProvisioner {\n private readonly fetchImpl: typeof fetch\n private readonly timeoutMs: number\n readonly #adminKey: string\n constructor(options: { adminKey: string; fetchImpl?: typeof fetch; timeoutMs?: number }) {\n if (!options.adminKey || options.adminKey.length > 4096 || /[^\\x21-\\x7e]/.test(options.adminKey)) throw new MessagingProvisionError('unavailable')\n this.#adminKey = options.adminKey\n this.fetchImpl = options.fetchImpl ?? fetch.bind(globalThis)\n this.timeoutMs = options.timeoutMs ?? 15_000\n if (!Number.isSafeInteger(this.timeoutMs) || this.timeoutMs < 1 || this.timeoutMs > 120_000) throw new MessagingProvisionError('invalid_input')\n }\n private async request(method: 'GET' | 'POST' | 'PATCH' | 'DELETE', path: string, body?: unknown, operationId?: string, key = this.#adminKey): Promise<unknown> {\n let response: Response\n try {\n response = await this.fetchImpl(`${BASE}${path}`, { method, redirect: 'error', signal: AbortSignal.timeout(this.timeoutMs),\n headers: { 'X-API-Key': key, ...(body === undefined ? {} : { 'Content-Type': 'application/json' }), ...(operationId ? { 'Idempotency-Key': operationId } : {}) },\n ...(body === undefined ? {} : { body: JSON.stringify(body) }) })\n } catch { throw new MessagingProvisionError(method === 'GET' ? 'unavailable' : 'outcome_unknown') }\n if ((method === 'GET' || method === 'DELETE') && response.status === 404) return null\n if (!response.ok) {\n const retry = response.headers.get('retry-after')\n const seconds = retry && /^\\d+$/.test(retry) && Number.isSafeInteger(Number(retry)) ? Number(retry) : undefined\n throw new MessagingProvisionError(failureCode(method, response.status), response.status, seconds)\n }\n if (method === 'DELETE' && response.status === 204) return null\n return readJson(response)\n }\n async verifyAdminKey(): Promise<void> {\n const self = record(await this.request('GET', '/api-keys/self'))\n if (self.scoped_identity_id !== null || self.status !== 'active') throw new MessagingProvisionError('invalid_receipt')\n }\n async getIdentity(agentHandle: string): Promise<InkboxIdentity | null> {\n assertHandle(agentHandle)\n const value = await this.request('GET', `/identities/${encodeURIComponent(agentHandle)}`)\n if (value === null) return null\n return this.identityReceipt(value, agentHandle)\n }\n async createIdentity(agentHandle: string): Promise<InkboxIdentity> {\n assertHandle(agentHandle)\n return this.identityReceipt(await this.request('POST', '/identities', {\n agent_handle: agentHandle, imessage_enabled: false, contact_sharing_enabled: false,\n mailbox: { sending_domain: null },\n }), agentHandle)\n }\n async claimIMessage(agentHandle: string, operationId: string): Promise<InkboxIdentity> {\n assertHandle(agentHandle); assertOperation(operationId)\n return this.identityReceipt(await this.request('PATCH', `/identities/${encodeURIComponent(agentHandle)}`,\n { imessage_enabled: true, claim_imessage_number: true }, operationId), agentHandle)\n }\n async provisionSms(agentHandle: string, operationId: string, state?: string): Promise<InkboxNumber> {\n assertHandle(agentHandle); assertOperation(operationId)\n if (state !== undefined && !/^[A-Z]{2}$/.test(state)) throw new MessagingProvisionError('invalid_input')\n const result = readNumber(await this.request('POST', '/phone/numbers', {\n agent_handle: agentHandle, type: 'local', incoming_call_action: 'auto_reject', ...(state ? { state } : {}),\n }, operationId))\n if (!result) throw new MessagingProvisionError('invalid_receipt')\n return result\n }\n /** Encrypt before any other work. A lost response cannot be repaired by blindly minting another key. */\n async mintIdentityKey(identityId: string, label: string): Promise<{ key: string; keyId: string }> {\n if (!UUID.test(identityId) || !label.trim() || label.length > 255) throw new MessagingProvisionError('invalid_input')\n const result = record(await this.request('POST', '/api-keys', { label, scoped_identity_id: identityId }))\n const meta = record(result.record)\n if (meta.scoped_identity_id !== identityId || typeof result.api_key !== 'string' || !result.api_key || result.api_key.length > 4096 ||\n /[^\\x21-\\x7e]/.test(result.api_key) || typeof meta.id !== 'string' || !meta.id) throw new MessagingProvisionError('invalid_receipt')\n // Only a successful receipt is returned. The host journals this call before sending it.\n return { key: result.api_key, keyId: meta.id }\n }\n /** Safe read after the once-shown key is durable in the host vault. */\n async verifyIdentityKey(key: string, identityId: string, keyId: string): Promise<void> {\n if (!UUID.test(identityId) || !key || /[^\\x21-\\x7e]/.test(key) || key.length > 4096 || !keyId) throw new MessagingProvisionError('invalid_input')\n const self = record(await this.request('GET', '/api-keys/self', undefined, undefined, key))\n if (self.scoped_identity_id !== identityId || self.id !== keyId || self.status !== 'active') throw new MessagingProvisionError('invalid_receipt')\n }\n /** The host must authorize the recorded handle. Dedicated iMessage line release is not attested by this response. */\n async deleteIdentity(agentHandle: string): Promise<void> {\n assertHandle(agentHandle)\n await this.request('DELETE', `/identities/${encodeURIComponent(agentHandle)}`)\n }\n private identityReceipt(value: unknown, expectedHandle: string): InkboxIdentity {\n const identity = parseInkboxIdentity(value)\n if (identity.handle !== expectedHandle) throw new MessagingProvisionError('invalid_receipt')\n return identity\n }\n}\n","import { type InkboxIdentity, type InkboxNumber, InkboxProvisioner, MessagingProvisionError, type ManagedMessageTransport } from './inkbox.js'\n\nexport type NumberPhase = 'identity' | 'number' | 'credential' | 'connection' | 'complete'\nexport interface ManagedNumberOrder {\n id: string\n ownerId: string\n /** Unique to this order. After an attempt, an existing identity with this handle is adopted as the receipt. */\n handle: string\n organizationId: string\n transport: ManagedMessageTransport\n state?: string\n /** Immutable, server-created ledger authorization; never accept a browser-supplied paid flag. */\n fundingAuthorizationId: string\n version: number\n phase: NumberPhase\n attempted: boolean\n /** When the attempt journal was written. Within the in-flight window another worker may still be mid-call. */\n attemptedAt?: number\n identityId?: string\n number?: InkboxNumber\n connectionId?: string\n status: 'pending' | 'provider_pending' | 'needs_review' | 'ready_for_setup' | 'cancelled'\n errorCode?: string\n nextAttemptAt?: number\n}\nexport interface ManagedNumberOrderStore {\n get(id: string): Promise<ManagedNumberOrder | null>\n /** One atomic version check; preserve all rows across host/worker restarts. */\n saveIfVersion(order: ManagedNumberOrder, expectedVersion: number): Promise<boolean>\n}\nexport interface ManagedNumberPorts {\n orders: ManagedNumberOrderStore\n provider: Pick<InkboxProvisioner, 'getIdentity' | 'createIdentity' | 'claimIMessage' | 'provisionSms' | 'mintIdentityKey' | 'verifyIdentityKey'>\n /** Validate/capture through the platform ledger with this order's stable reference. Must be idempotent. */\n authorizeFunding(order: Readonly<ManagedNumberOrder>): Promise<boolean>\n /** Re-read configuration and commercial permission before every mutation, including resumed work. */\n canProvision(order: Readonly<ManagedNumberOrder>): Promise<boolean>\n vault: {\n read(orderId: string): Promise<{ key: string; keyId: string; identityId: string } | null>\n /** Encrypt once under the order and identity; reject an existing, different credential. */\n putIfAbsent(orderId: string, value: { key: string; keyId: string; identityId: string }): Promise<void>\n }\n /** Create/recover exactly this order's owner-scoped Hub connection using the vault reference. Never return its key. */\n bindConnection(order: Readonly<ManagedNumberOrder>): Promise<string>\n now?: () => number\n}\n\nfunction identityMatches(order: ManagedNumberOrder, identity: InkboxIdentity): void {\n if (identity.handle !== order.handle || identity.organizationId !== order.organizationId || identity.status !== 'active' ||\n (order.identityId && identity.id !== order.identityId)) throw new MessagingProvisionError('invalid_receipt')\n}\nfunction selectedNumber(order: ManagedNumberOrder, identity: InkboxIdentity): InkboxNumber | null {\n return order.transport === 'sms' ? identity.sms : identity.imessageEnabled ? identity.imessage : null\n}\n\n/** Longer than one provider mutation plus its ownership read at the maximum client timeout. */\nconst IN_FLIGHT_MS = 5 * 60_000\n\n/** One recoverable provisioning step, called by the host's EXISTING queue.\n * No agent loop, background worker, payment ledger or credential store lives here.\n * A journaled non-idempotent call is reconciled by reading provider state, never blindly repeated. */\nexport async function advanceManagedNumber(orderId: string, ports: ManagedNumberPorts): Promise<ManagedNumberOrder> {\n let order = await ports.orders.get(orderId)\n if (!order) throw new Error('Managed number order not found')\n if (!order.id || order.id.length > 128 || !/^[a-zA-Z0-9:._-]+$/.test(order.id) || order.id !== orderId ||\n !order.ownerId || !order.organizationId || !order.fundingAuthorizationId ||\n !['sms', 'imessage'].includes(order.transport) || !['identity', 'number', 'credential', 'connection', 'complete'].includes(order.phase) ||\n !Number.isSafeInteger(order.version) || order.version < 0) throw new MessagingProvisionError('invalid_input')\n // Set only when a provider mutation itself is definitively refused. A read\n // failing after a successful mutation must never re-open the purchase.\n let mutationRefused = false\n // Set once this tick's provider mutation has returned or thrown: it is no longer in flight.\n let mutationSettled = false\n if (order.phase === 'complete' || order.status === 'cancelled') return order\n const now = (ports.now ?? Date.now)()\n if (order.nextAttemptAt && order.nextAttemptAt > now) return order\n async function save(patch: Partial<ManagedNumberOrder>): Promise<ManagedNumberOrder> {\n const before = order!\n const next = { ...before, ...patch, version: before.version + 1 }\n if (await ports.orders.saveIfVersion(next, before.version)) { order = next; return next }\n return recordReceipt(patch)\n }\n /**\n * The order changed underneath this tick, usually a cancellation racing a\n * provider call. Drop the patch, but keep any provider receipt it carried:\n * a purchased number no order records cannot be released by cleanup.\n */\n async function recordReceipt(patch: Partial<ManagedNumberOrder>): Promise<ManagedNumberOrder> {\n const receipt: Partial<ManagedNumberOrder> = {\n ...(patch.identityId ? { identityId: patch.identityId } : {}),\n ...(patch.number ? { number: patch.number } : {}),\n }\n for (let attempt = 0; attempt < 3; attempt++) {\n const current = await ports.orders.get(orderId)\n if (!current) throw new Error('Managed number order disappeared')\n const missing = (receipt.identityId && !current.identityId) || (receipt.number && !current.number)\n if (!missing) return current\n const merged = {\n ...current,\n ...(current.identityId ? {} : { identityId: receipt.identityId }),\n ...(current.number ? {} : { number: receipt.number }),\n version: current.version + 1,\n }\n if (await ports.orders.saveIfVersion(merged, current.version)) return merged\n }\n throw new MessagingProvisionError('outcome_unknown')\n }\n async function mutate<T>(call: () => Promise<T>): Promise<T> {\n try { return await call() }\n catch (error) {\n if (error instanceof MessagingProvisionError && error.code === 'provider_rejected') mutationRefused = true\n throw error\n }\n finally { mutationSettled = true }\n }\n /** Journal the attempt, then recheck authority. Release the journal if no provider call follows. */\n async function claim(): Promise<boolean> {\n const before = order!\n const claimed = await save({ attempted: true, attemptedAt: now, status: 'pending', errorCode: undefined, nextAttemptAt: undefined })\n if (claimed.version !== before.version + 1 || order !== claimed) return false\n let authorized = false\n try { authorized = await authorize() }\n finally {\n if (!authorized) await releaseClaim()\n }\n return authorized\n }\n async function releaseClaim(): Promise<void> {\n const current = await ports.orders.get(orderId)\n if (!current || !current.attempted || current.status === 'cancelled') return\n if (await ports.orders.saveIfVersion({ ...current, attempted: false, version: current.version + 1 }, current.version)) {\n order = { ...current, attempted: false, version: current.version + 1 }\n }\n }\n /** A concurrent tick (a user's progress check during a sweep) must not judge another worker's live call. */\n function inFlight(current: ManagedNumberOrder): boolean {\n return current.attempted && current.attemptedAt !== undefined && now - current.attemptedAt < IN_FLIGHT_MS\n }\n async function authorize(): Promise<boolean> {\n const current = await ports.orders.get(orderId)\n if (!current || current.version !== order!.version || current.status === 'cancelled') return false\n // Back off: an order that cannot be funded or activated must not stay due\n // and crowd other orders out of the host's bounded reconcile sweep.\n if (!await ports.canProvision(current)) { await save({ status: 'provider_pending', errorCode: 'activation_not_configured', nextAttemptAt: now + 60_000 }); return false }\n if (!await ports.authorizeFunding(current)) { await save({ status: 'provider_pending', errorCode: 'funding_required', nextAttemptAt: now + 60_000 }); return false }\n // The checks above may wait on remote services. Do not act on a stale cancellation snapshot.\n const rechecked = await ports.orders.get(orderId)\n return rechecked?.version === order!.version && rechecked.status !== 'cancelled'\n }\n try {\n // Reads need no funding or activation permission; every provider mutation\n // authorizes through claim(). Reconciling a completed purchase therefore\n // still works after its funding hold expired.\n if (order.phase === 'identity') {\n let identity = await ports.provider.getIdentity(order.handle)\n if (!identity) {\n if (inFlight(order)) return order\n if (order.attempted) return save({ status: 'needs_review', errorCode: 'identity_outcome_unknown' })\n if (!await claim()) return (await ports.orders.get(orderId))!\n const handle = order.handle\n identity = await mutate(() => ports.provider.createIdentity(handle))\n } else if (!order.attempted && !order.identityId) {\n // A pre-existing handle is not evidence this order created the identity.\n return save({ status: 'needs_review', errorCode: 'identity_already_exists' })\n }\n identityMatches(order, identity)\n return save({ identityId: identity.id, phase: 'number', attempted: false, status: 'pending', errorCode: undefined })\n }\n if (!order.identityId) throw new MessagingProvisionError('invalid_receipt')\n const identity = await ports.provider.getIdentity(order.handle)\n if (!identity) return save({ status: 'needs_review', errorCode: 'identity_missing' })\n identityMatches(order, identity)\n if (order.phase === 'number') {\n let number = selectedNumber(order, identity)\n // A recorded number is an ownership receipt. Its absence now is a provider\n // change to review, never a reason to buy another line.\n if (!number && order.number) return save({ status: 'needs_review', errorCode: 'number_missing' })\n if (!number) {\n // An accepted iMessage claim enables the identity before the provider attaches a line.\n if (order.attempted && order.transport === 'imessage' && identity.imessageEnabled) {\n return save({ status: 'provider_pending', errorCode: 'number_pending', nextAttemptAt: now + 30_000 })\n }\n if (inFlight(order)) return order\n if (order.attempted) return save({ status: 'needs_review', errorCode: 'number_outcome_unknown' })\n if (!await claim()) return (await ports.orders.get(orderId))!\n const { handle, state, id } = order\n if (order.transport === 'sms') {\n const purchased = await mutate(() => ports.provider.provisionSms(handle, `${id}:sms`, state))\n // A purchase response alone is not an ownership receipt. Read the\n // exact identity before the host can treat this number as billable.\n const receipt = await ports.provider.getIdentity(order.handle)\n if (!receipt) throw new MessagingProvisionError('invalid_receipt')\n identityMatches(order, receipt)\n number = selectedNumber(order, receipt)\n if (!number || purchased.id !== number.id || purchased.number !== number.number) {\n throw new MessagingProvisionError('invalid_receipt')\n }\n }\n else {\n const receipt = await mutate(() => ports.provider.claimIMessage(handle, `${id}:imessage`))\n identityMatches(order, receipt); number = selectedNumber(order, receipt)\n }\n }\n if (!number) return save({ status: 'provider_pending', errorCode: 'number_pending', nextAttemptAt: now + 30_000 })\n if (order.number && (order.number.id !== number.id || order.number.number !== number.number)) throw new MessagingProvisionError('invalid_receipt')\n if (order.transport === 'sms' && (number.smsStatus !== 'ready' || number.status !== 'active')) {\n // The purchase has completed with an ownership receipt; nothing is in flight while SMS readiness settles.\n return save({ number, attempted: false, status: 'provider_pending', nextAttemptAt: now + 30_000, errorCode: 'sms_not_ready' })\n }\n return save({ number, phase: 'credential', attempted: false, status: 'pending', errorCode: undefined, nextAttemptAt: undefined })\n }\n const number = selectedNumber(order, identity)\n if (!number || number.id !== order.number?.id || number.number !== order.number.number ||\n (order.transport === 'sms' && (number.smsStatus !== 'ready' || number.status !== 'active'))) throw new MessagingProvisionError('invalid_receipt')\n if (order.phase === 'credential') {\n let credential = await ports.vault.read(order.id)\n if (!credential) {\n if (inFlight(order)) return order\n if (order.attempted) return save({ status: 'needs_review', errorCode: 'credential_receipt_lost' })\n if (!await claim()) return (await ports.orders.get(orderId))!\n const { identityId, id } = order\n const minted = await mutate(() => ports.provider.mintIdentityKey(identityId!, `Tangle number ${id}`))\n credential = { ...minted, identityId: order.identityId }\n // No fallible provider read between receiving the secret and durable encryption.\n await ports.vault.putIfAbsent(order.id, credential)\n }\n if (credential.identityId !== order.identityId) throw new MessagingProvisionError('invalid_receipt')\n await ports.provider.verifyIdentityKey(credential.key, order.identityId, credential.keyId)\n return save({ phase: 'connection', attempted: false, status: 'pending', errorCode: undefined })\n }\n const credential = await ports.vault.read(order.id)\n if (!credential || credential.identityId !== order.identityId) throw new MessagingProvisionError('invalid_receipt')\n if (!await authorize()) return (await ports.orders.get(orderId))!\n const connectionId = await ports.bindConnection(order)\n if (!connectionId || connectionId.length > 256) throw new MessagingProvisionError('invalid_receipt')\n return save({ connectionId, phase: 'complete', status: 'ready_for_setup', attempted: false, errorCode: undefined })\n } catch (error) {\n const code = error instanceof MessagingProvisionError ? error.code : 'outcome_unknown'\n const retryAfter = error instanceof MessagingProvisionError ? error.retryAfterSeconds : undefined\n // A definitive 4xx refusal permits another attempt after account setup. An unknown outcome does not.\n const refused = mutationRefused && order.phase !== 'credential'\n return save({ status: code === 'invalid_receipt' ? 'needs_review' : 'provider_pending', errorCode: code,\n ...(refused ? { attempted: false } : {}),\n ...(mutationSettled ? { attemptedAt: undefined } : {}),\n nextAttemptAt: now + Math.max(30, Math.min(retryAfter ?? 30, 86_400)) * 1000 })\n }\n}\n"],"mappings":"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","names":["identity","number","credential"]}
|
|
1
|
+
{"version":3,"sources":["../../src/managed-messaging/inkbox.ts","../../src/managed-messaging/provision.ts"],"sourcesContent":["export type ManagedMessageTransport = 'sms' | 'imessage'\nexport interface InkboxNumber { id: string; number: string; smsStatus: string | null; status: string | null }\nexport interface InkboxIdentity {\n id: string\n handle: string\n organizationId: string\n status: string\n imessageEnabled: boolean\n sms: InkboxNumber | null\n imessage: InkboxNumber | null\n}\nexport class MessagingProvisionError extends Error {\n constructor(\n readonly code: 'invalid_input' | 'unavailable' | 'provider_rejected' | 'outcome_unknown' | 'invalid_receipt',\n readonly status?: number,\n readonly retryAfterSeconds?: number,\n ) {\n super(`Messaging provisioning: ${code}${status ? ` (HTTP ${status})` : ''}`)\n this.name = 'MessagingProvisionError'\n }\n}\nconst BASE = 'https://inkbox.ai/api/v1'\nconst UUID = /^[a-f\\d]{8}(?:-[a-f\\d]{4}){3}-[a-f\\d]{12}$/i\nconst PHONE = /^\\+[1-9]\\d{6,14}$/\nconst HANDLE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/\nfunction record(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) throw new MessagingProvisionError('invalid_receipt')\n return value as Record<string, unknown>\n}\nfunction readNumber(value: unknown): InkboxNumber | null {\n if (value == null) return null\n const row = record(value)\n if (typeof row.id !== 'string' || !UUID.test(row.id) || typeof row.number !== 'string' || !PHONE.test(row.number)) throw new MessagingProvisionError('invalid_receipt')\n return { id: row.id, number: row.number, smsStatus: typeof row.sms_status === 'string' ? row.sms_status : null, status: typeof row.status === 'string' ? row.status : null }\n}\n/** Project only channel identity. Mailbox, tunnel, credentials and contacts never leave this boundary. */\nexport function parseInkboxIdentity(value: unknown): InkboxIdentity {\n const row = record(value)\n if (typeof row.id !== 'string' || !UUID.test(row.id) || typeof row.agent_handle !== 'string' ||\n row.agent_handle.length < 3 || row.agent_handle.length > 63 || !HANDLE.test(row.agent_handle) ||\n typeof row.organization_id !== 'string' || !row.organization_id || row.organization_id.length > 256 ||\n typeof row.status !== 'string' || !row.status || typeof row.imessage_enabled !== 'boolean') throw new MessagingProvisionError('invalid_receipt')\n return { id: row.id, handle: row.agent_handle, organizationId: row.organization_id, status: row.status,\n imessageEnabled: row.imessage_enabled, sms: readNumber(row.phone_number), imessage: readNumber(row.imessage_number) }\n}\nfunction assertHandle(value: string): void {\n if (value.length < 3 || value.length > 63 || !HANDLE.test(value)) throw new MessagingProvisionError('invalid_input')\n}\nfunction assertOperation(value: string): void {\n if (!value || value.length > 200 || !/^[a-zA-Z0-9:._-]+$/.test(value)) throw new MessagingProvisionError('invalid_input')\n}\nasync function readJson(response: Response): Promise<unknown> {\n if (!response.body) throw new MessagingProvisionError('invalid_receipt')\n const reader = response.body.getReader()\n const chunks: Uint8Array[] = []; let size = 0\n try {\n while (true) {\n const chunk = await reader.read()\n if (chunk.done) break\n size += chunk.value.byteLength\n if (size > 1_048_576) { await reader.cancel(); throw new MessagingProvisionError('invalid_receipt') }\n chunks.push(chunk.value)\n }\n const bytes = new Uint8Array(size); let offset = 0\n for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.length }\n return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes)) as unknown\n } catch { throw new MessagingProvisionError('invalid_receipt') }\n finally { reader.releaseLock() }\n}\n\n/**\n * A read that fails transiently is `unavailable`: it says nothing about a\n * mutation that already succeeded. Only a mutation's own definitive 4xx is\n * `provider_rejected`, which is what permits another purchase attempt.\n */\nfunction failureCode(method: string, status: number): MessagingProvisionError['code'] {\n const transient = status >= 500 || status === 408\n if (method === 'GET') return transient || status === 429 ? 'unavailable' : 'provider_rejected'\n return transient ? 'outcome_unknown' : 'provider_rejected'\n}\n\n/** Host-only administrative client; NOT a ConnectorAdapter and never an agent tool. */\nexport class InkboxProvisioner {\n private readonly fetchImpl: typeof fetch\n private readonly timeoutMs: number\n readonly #adminKey: string\n constructor(options: { adminKey: string; fetchImpl?: typeof fetch; timeoutMs?: number }) {\n if (!options.adminKey || options.adminKey.length > 4096 || /[^\\x21-\\x7e]/.test(options.adminKey)) throw new MessagingProvisionError('unavailable')\n this.#adminKey = options.adminKey\n this.fetchImpl = options.fetchImpl ?? fetch.bind(globalThis)\n this.timeoutMs = options.timeoutMs ?? 15_000\n if (!Number.isSafeInteger(this.timeoutMs) || this.timeoutMs < 1 || this.timeoutMs > 120_000) throw new MessagingProvisionError('invalid_input')\n }\n private async request(method: 'GET' | 'POST' | 'PATCH' | 'DELETE', path: string, body?: unknown, operationId?: string, key = this.#adminKey): Promise<unknown> {\n let response: Response\n try {\n response = await this.fetchImpl(`${BASE}${path}`, { method, redirect: 'error', signal: AbortSignal.timeout(this.timeoutMs),\n headers: { 'X-API-Key': key, ...(body === undefined ? {} : { 'Content-Type': 'application/json' }), ...(operationId ? { 'Idempotency-Key': operationId } : {}) },\n ...(body === undefined ? {} : { body: JSON.stringify(body) }) })\n } catch { throw new MessagingProvisionError(method === 'GET' ? 'unavailable' : 'outcome_unknown') }\n if ((method === 'GET' || method === 'DELETE') && response.status === 404) return null\n if (!response.ok) {\n const retry = response.headers.get('retry-after')\n const seconds = retry && /^\\d+$/.test(retry) && Number.isSafeInteger(Number(retry)) ? Number(retry) : undefined\n throw new MessagingProvisionError(failureCode(method, response.status), response.status, seconds)\n }\n if (method === 'DELETE' && response.status === 204) return null\n return readJson(response)\n }\n async verifyAdminKey(): Promise<void> {\n const self = record(await this.request('GET', '/api-keys/self'))\n if (self.scoped_identity_id !== null || self.status !== 'active') throw new MessagingProvisionError('invalid_receipt')\n }\n async getIdentity(agentHandle: string): Promise<InkboxIdentity | null> {\n assertHandle(agentHandle)\n const value = await this.request('GET', `/identities/${encodeURIComponent(agentHandle)}`)\n if (value === null) return null\n return this.identityReceipt(value, agentHandle)\n }\n async createIdentity(agentHandle: string): Promise<InkboxIdentity> {\n assertHandle(agentHandle)\n return this.identityReceipt(await this.request('POST', '/identities', {\n agent_handle: agentHandle, imessage_enabled: false, contact_sharing_enabled: false,\n mailbox: { sending_domain: null },\n }), agentHandle)\n }\n async claimIMessage(agentHandle: string, operationId: string): Promise<InkboxIdentity> {\n assertHandle(agentHandle); assertOperation(operationId)\n return this.identityReceipt(await this.request('PATCH', `/identities/${encodeURIComponent(agentHandle)}`,\n { imessage_enabled: true, claim_imessage_number: true }, operationId), agentHandle)\n }\n async provisionSms(agentHandle: string, operationId: string, state?: string): Promise<InkboxNumber> {\n assertHandle(agentHandle); assertOperation(operationId)\n if (state !== undefined && !/^[A-Z]{2}$/.test(state)) throw new MessagingProvisionError('invalid_input')\n const result = readNumber(await this.request('POST', '/phone/numbers', {\n agent_handle: agentHandle, type: 'local', incoming_call_action: 'auto_reject', ...(state ? { state } : {}),\n }, operationId))\n if (!result) throw new MessagingProvisionError('invalid_receipt')\n return result\n }\n /** Encrypt before any other work. A lost response cannot be repaired by blindly minting another key. */\n async mintIdentityKey(identityId: string, label: string): Promise<{ key: string; keyId: string }> {\n if (!UUID.test(identityId) || !label.trim() || label.length > 255) throw new MessagingProvisionError('invalid_input')\n const result = record(await this.request('POST', '/api-keys', { label, scoped_identity_id: identityId }))\n const meta = record(result.record)\n if (meta.scoped_identity_id !== identityId || typeof result.api_key !== 'string' || !result.api_key || result.api_key.length > 4096 ||\n /[^\\x21-\\x7e]/.test(result.api_key) || typeof meta.id !== 'string' || !meta.id) throw new MessagingProvisionError('invalid_receipt')\n // Only a successful receipt is returned. The host journals this call before sending it.\n return { key: result.api_key, keyId: meta.id }\n }\n /** Safe read after the once-shown key is durable in the host vault. */\n async verifyIdentityKey(key: string, identityId: string, keyId: string): Promise<void> {\n if (!UUID.test(identityId) || !key || /[^\\x21-\\x7e]/.test(key) || key.length > 4096 || !keyId) throw new MessagingProvisionError('invalid_input')\n const self = record(await this.request('GET', '/api-keys/self', undefined, undefined, key))\n if (self.scoped_identity_id !== identityId || self.id !== keyId || self.status !== 'active') throw new MessagingProvisionError('invalid_receipt')\n }\n /** The host must authorize the recorded handle. Dedicated iMessage line release is not attested by this response. */\n async deleteIdentity(agentHandle: string): Promise<void> {\n assertHandle(agentHandle)\n await this.request('DELETE', `/identities/${encodeURIComponent(agentHandle)}`)\n }\n private identityReceipt(value: unknown, expectedHandle: string): InkboxIdentity {\n const identity = parseInkboxIdentity(value)\n if (identity.handle !== expectedHandle) throw new MessagingProvisionError('invalid_receipt')\n return identity\n }\n}\n","import { type InkboxIdentity, type InkboxNumber, InkboxProvisioner, MessagingProvisionError, type ManagedMessageTransport } from './inkbox.js'\n\nexport type NumberPhase = 'identity' | 'number' | 'credential' | 'connection' | 'complete'\nexport interface ManagedNumberOrder {\n id: string\n ownerId: string\n /** Unique to this order. After an attempt, an existing identity with this handle is adopted as the receipt. */\n handle: string\n organizationId: string\n transport: ManagedMessageTransport\n state?: string\n /** Immutable, server-created ledger authorization; never accept a browser-supplied paid flag. */\n fundingAuthorizationId: string\n version: number\n phase: NumberPhase\n attempted: boolean\n /** When the attempt journal was written. Within the in-flight window another worker may still be mid-call. */\n attemptedAt?: number\n identityId?: string\n number?: InkboxNumber\n connectionId?: string\n status: 'pending' | 'provider_pending' | 'needs_review' | 'ready_for_setup' | 'cancelled'\n errorCode?: string\n /** HTTP status behind `errorCode`, when the provider gave one. 402, 401 and 422 need different operator work. */\n errorStatus?: number\n nextAttemptAt?: number\n}\nexport interface ManagedNumberOrderStore {\n get(id: string): Promise<ManagedNumberOrder | null>\n /** One atomic version check; preserve all rows across host/worker restarts. */\n saveIfVersion(order: ManagedNumberOrder, expectedVersion: number): Promise<boolean>\n}\nexport interface ManagedNumberPorts {\n orders: ManagedNumberOrderStore\n provider: Pick<InkboxProvisioner, 'getIdentity' | 'createIdentity' | 'claimIMessage' | 'provisionSms' | 'mintIdentityKey' | 'verifyIdentityKey'>\n /** Validate/capture through the platform ledger with this order's stable reference. Must be idempotent. */\n authorizeFunding(order: Readonly<ManagedNumberOrder>): Promise<boolean>\n /** Re-read configuration and commercial permission before every mutation, including resumed work. */\n canProvision(order: Readonly<ManagedNumberOrder>): Promise<boolean>\n vault: {\n read(orderId: string): Promise<{ key: string; keyId: string; identityId: string } | null>\n /** Encrypt once under the order and identity; reject an existing, different credential. */\n putIfAbsent(orderId: string, value: { key: string; keyId: string; identityId: string }): Promise<void>\n }\n /** Create/recover exactly this order's owner-scoped Hub connection using the vault reference. Never return its key. */\n bindConnection(order: Readonly<ManagedNumberOrder>): Promise<string>\n now?: () => number\n}\n\nfunction identityMatches(order: ManagedNumberOrder, identity: InkboxIdentity): void {\n if (identity.handle !== order.handle || identity.organizationId !== order.organizationId || identity.status !== 'active' ||\n (order.identityId && identity.id !== order.identityId)) throw new MessagingProvisionError('invalid_receipt')\n}\nfunction selectedNumber(order: ManagedNumberOrder, identity: InkboxIdentity): InkboxNumber | null {\n return order.transport === 'sms' ? identity.sms : identity.imessageEnabled ? identity.imessage : null\n}\n\n/** Longer than one provider mutation plus its ownership read at the maximum client timeout. */\nconst IN_FLIGHT_MS = 5 * 60_000\n/** An order under review waits for an operator, not for the queue. A self-healing provider\n * state still recovers on its own, but a reviewed row must not hold a slot in the host's\n * bounded sweep, which would starve orders that can still make progress. */\nconst REVIEW_BACKOFF_MS = 6 * 60 * 60_000\n\n/** One recoverable provisioning step, called by the host's EXISTING queue.\n * No agent loop, background worker, payment ledger or credential store lives here.\n * A journaled non-idempotent call is reconciled by reading provider state, never blindly repeated. */\nexport async function advanceManagedNumber(orderId: string, ports: ManagedNumberPorts): Promise<ManagedNumberOrder> {\n let order = await ports.orders.get(orderId)\n if (!order) throw new Error('Managed number order not found')\n if (!order.id || order.id.length > 128 || !/^[a-zA-Z0-9:._-]+$/.test(order.id) || order.id !== orderId ||\n !order.ownerId || !order.organizationId || !order.fundingAuthorizationId ||\n !['sms', 'imessage'].includes(order.transport) || !['identity', 'number', 'credential', 'connection', 'complete'].includes(order.phase) ||\n // The provider refuses a malformed state; reject it here so it can never reach a purchase.\n (order.state !== undefined && !/^[A-Z]{2}$/.test(order.state)) ||\n !Number.isSafeInteger(order.version) || order.version < 0) throw new MessagingProvisionError('invalid_input')\n // Set only when a provider mutation itself is definitively refused. A read\n // failing after a successful mutation must never re-open the purchase.\n let mutationRefused = false\n // Narrower than `mutationRefused`: the client refused the arguments before any HTTP request\n // left it, so the provider never saw the call and cannot have issued a once-shown credential.\n let mutationUnsent = false\n // Set once this tick's provider mutation has returned or thrown: it is no longer in flight.\n let mutationSettled = false\n if (order.phase === 'complete' || order.status === 'cancelled') return order\n // A tick can spend minutes inside two or three provider calls, so `now` dates only\n // this tick's due check and its in-flight judgement, where a clock that has since\n // advanced could only declare another worker's live call dead too early. Every lease\n // and every backoff reads the clock where it is written.\n const clock = ports.now ?? Date.now\n const now = clock()\n if (order.nextAttemptAt && order.nextAttemptAt > now) return order\n async function save(patch: Partial<ManagedNumberOrder>): Promise<ManagedNumberOrder> {\n const before = order!\n // `errorStatus` only ever qualifies `errorCode`: a new code never inherits the old code's status.\n const next = { ...before, ...('errorCode' in patch && !('errorStatus' in patch) ? { errorStatus: undefined } : {}), ...patch, version: before.version + 1 }\n if (await ports.orders.saveIfVersion(next, before.version)) { order = next; return next }\n return recordReceipt(patch)\n }\n /**\n * The order changed underneath this tick, usually a cancellation racing a\n * provider call. Drop the patch, but keep any provider receipt it carried:\n * a purchased number no order records cannot be released by cleanup.\n */\n async function recordReceipt(patch: Partial<ManagedNumberOrder>): Promise<ManagedNumberOrder> {\n const receipt: Partial<ManagedNumberOrder> = {\n ...(patch.identityId ? { identityId: patch.identityId } : {}),\n ...(patch.number ? { number: patch.number } : {}),\n }\n for (let attempt = 0; attempt < 3; attempt++) {\n const current = await ports.orders.get(orderId)\n if (!current) throw new Error('Managed number order disappeared')\n const missing = (receipt.identityId && !current.identityId) || (receipt.number && !current.number)\n if (!missing) return current\n const merged = {\n ...current,\n ...(current.identityId ? {} : { identityId: receipt.identityId }),\n ...(current.number ? {} : { number: receipt.number }),\n version: current.version + 1,\n }\n if (await ports.orders.saveIfVersion(merged, current.version)) return merged\n }\n throw new MessagingProvisionError('outcome_unknown')\n }\n async function mutate<T>(call: () => Promise<T>): Promise<T> {\n try { return await call() }\n catch (error) {\n // `invalid_input` is raised by argument validation before any HTTP leaves the client:\n // like a definitive refusal, it proves no purchase exists to reconcile.\n if (error instanceof MessagingProvisionError) {\n if (error.code === 'invalid_input') mutationUnsent = true\n if (error.code === 'provider_rejected' || error.code === 'invalid_input') mutationRefused = true\n }\n throw error\n }\n finally { mutationSettled = true }\n }\n /** Journal the attempt, then recheck authority. Release the journal if no provider call follows. */\n async function claim(): Promise<boolean> {\n const before = order!\n // The lease starts here, not at the tick's start: reads already made in this tick\n // would otherwise hand a concurrent tick a lease that is spent before the call returns.\n const claimed = await save({ attempted: true, attemptedAt: clock(), status: 'pending', errorCode: undefined, nextAttemptAt: undefined })\n if (claimed.version !== before.version + 1 || order !== claimed) return false\n let authorized = false\n try { authorized = await authorize() }\n finally {\n if (!authorized) await releaseClaim()\n }\n return authorized\n }\n async function releaseClaim(): Promise<void> {\n const current = await ports.orders.get(orderId)\n if (!current || !current.attempted || current.status === 'cancelled') return\n if (await ports.orders.saveIfVersion({ ...current, attempted: false, version: current.version + 1 }, current.version)) {\n order = { ...current, attempted: false, version: current.version + 1 }\n }\n }\n /** A concurrent tick (a user's progress check during a sweep) must not judge another worker's live call. */\n function inFlight(current: ManagedNumberOrder): boolean {\n return current.attempted && current.attemptedAt !== undefined && now - current.attemptedAt < IN_FLIGHT_MS\n }\n async function authorize(): Promise<boolean> {\n const current = await ports.orders.get(orderId)\n if (!current || current.version !== order!.version || current.status === 'cancelled') return false\n // Back off: an order that cannot be funded or activated must not stay due\n // and crowd other orders out of the host's bounded reconcile sweep.\n if (!await ports.canProvision(current)) { await save({ status: 'provider_pending', errorCode: 'activation_not_configured', nextAttemptAt: clock() + 60_000 }); return false }\n if (!await ports.authorizeFunding(current)) { await save({ status: 'provider_pending', errorCode: 'funding_required', nextAttemptAt: clock() + 60_000 }); return false }\n // The checks above may wait on remote services. Do not act on a stale cancellation snapshot.\n const rechecked = await ports.orders.get(orderId)\n return rechecked?.version === order!.version && rechecked.status !== 'cancelled'\n }\n /**\n * The money gate every non-idempotent provider call passes through, once per phase.\n * Three questions in one fixed order: is another worker's call still in flight, has this\n * order already burned its attempt with no receipt to show for it, and can this tick claim\n * the journal and re-authorize the spend. `burnedCode` is the review code for the second.\n * Returns null when the call is granted, otherwise the order the caller must return.\n */\n async function leaseAttempt(burnedCode: string): Promise<ManagedNumberOrder | null> {\n if (inFlight(order!)) return order!\n if (order!.attempted) return save({ status: 'needs_review', errorCode: burnedCode, nextAttemptAt: clock() + REVIEW_BACKOFF_MS })\n if (!await claim()) return (await ports.orders.get(orderId))!\n return null\n }\n try {\n // Reads need no funding or activation permission; every provider mutation\n // authorizes through claim(). Reconciling a completed purchase therefore\n // still works after its funding hold expired.\n if (order.phase === 'identity') {\n let identity = await ports.provider.getIdentity(order.handle)\n if (!identity) {\n const lease = await leaseAttempt('identity_outcome_unknown')\n if (lease) return lease\n const handle = order.handle\n identity = await mutate(() => ports.provider.createIdentity(handle))\n } else if (!order.attempted && !order.identityId) {\n // A pre-existing handle is not evidence this order created the identity.\n return save({ status: 'needs_review', errorCode: 'identity_already_exists', nextAttemptAt: clock() + REVIEW_BACKOFF_MS })\n }\n identityMatches(order, identity)\n return save({ identityId: identity.id, phase: 'number', attempted: false, status: 'pending', errorCode: undefined })\n }\n if (!order.identityId) throw new MessagingProvisionError('invalid_receipt')\n const identity = await ports.provider.getIdentity(order.handle)\n if (!identity) return save({ status: 'needs_review', errorCode: 'identity_missing', nextAttemptAt: clock() + REVIEW_BACKOFF_MS })\n identityMatches(order, identity)\n if (order.phase === 'number') {\n let number = selectedNumber(order, identity)\n // A recorded number is an ownership receipt. Its absence now is a provider\n // change to review, never a reason to buy another line.\n if (!number && order.number) return save({ status: 'needs_review', errorCode: 'number_missing', nextAttemptAt: clock() + REVIEW_BACKOFF_MS })\n if (!number) {\n // An accepted iMessage claim enables the identity before the provider attaches a line.\n if (order.attempted && order.transport === 'imessage' && identity.imessageEnabled) {\n return save({ status: 'provider_pending', errorCode: 'number_pending', nextAttemptAt: clock() + 30_000 })\n }\n const lease = await leaseAttempt('number_outcome_unknown')\n if (lease) return lease\n const { handle, state, id } = order\n if (order.transport === 'sms') {\n const purchased = await mutate(() => ports.provider.provisionSms(handle, `${id}:sms`, state))\n // A purchase response alone is not an ownership receipt. Read the\n // exact identity before the host can treat this number as billable.\n const receipt = await ports.provider.getIdentity(order.handle)\n if (!receipt) throw new MessagingProvisionError('invalid_receipt')\n identityMatches(order, receipt)\n number = selectedNumber(order, receipt)\n if (!number || purchased.id !== number.id || purchased.number !== number.number) {\n throw new MessagingProvisionError('invalid_receipt')\n }\n }\n else {\n const receipt = await mutate(() => ports.provider.claimIMessage(handle, `${id}:imessage`))\n identityMatches(order, receipt); number = selectedNumber(order, receipt)\n }\n }\n if (!number) return save({ status: 'provider_pending', errorCode: 'number_pending', nextAttemptAt: clock() + 30_000 })\n if (order.number && (order.number.id !== number.id || order.number.number !== number.number)) throw new MessagingProvisionError('invalid_receipt')\n if (order.transport === 'sms' && (number.smsStatus !== 'ready' || number.status !== 'active')) {\n // The purchase has completed with an ownership receipt; nothing is in flight while SMS readiness settles.\n return save({ number, attempted: false, status: 'provider_pending', nextAttemptAt: clock() + 30_000, errorCode: 'sms_not_ready' })\n }\n return save({ number, phase: 'credential', attempted: false, status: 'pending', errorCode: undefined, nextAttemptAt: undefined })\n }\n const number = selectedNumber(order, identity)\n if (!number || number.id !== order.number?.id || number.number !== order.number.number ||\n (order.transport === 'sms' && (number.smsStatus !== 'ready' || number.status !== 'active'))) throw new MessagingProvisionError('invalid_receipt')\n if (order.phase === 'credential') {\n let credential = await ports.vault.read(order.id)\n if (!credential) {\n const lease = await leaseAttempt('credential_receipt_lost')\n if (lease) return lease\n const { identityId, id } = order\n const minted = await mutate(() => ports.provider.mintIdentityKey(identityId!, `Tangle number ${id}`))\n credential = { ...minted, identityId: order.identityId }\n // No fallible provider read between receiving the secret and durable encryption.\n await ports.vault.putIfAbsent(order.id, credential)\n }\n if (credential.identityId !== order.identityId) throw new MessagingProvisionError('invalid_receipt')\n await ports.provider.verifyIdentityKey(credential.key, order.identityId, credential.keyId)\n return save({ phase: 'connection', attempted: false, status: 'pending', errorCode: undefined })\n }\n const credential = await ports.vault.read(order.id)\n if (!credential || credential.identityId !== order.identityId) throw new MessagingProvisionError('invalid_receipt')\n if (!await authorize()) return (await ports.orders.get(orderId))!\n const connectionId = await ports.bindConnection(order)\n if (!connectionId || connectionId.length > 256) throw new MessagingProvisionError('invalid_receipt')\n return save({ connectionId, phase: 'complete', status: 'ready_for_setup', attempted: false, errorCode: undefined })\n } catch (error) {\n const code = error instanceof MessagingProvisionError ? error.code : 'outcome_unknown'\n const retryAfter = error instanceof MessagingProvisionError ? error.retryAfterSeconds : undefined\n // A definitive 4xx refusal permits another attempt after account setup. An unknown outcome does not.\n // The credential phase asks for more: a mint request that reached the provider may have issued a\n // once-shown key whatever it answered, so only a call the client never sent releases the journal there.\n const refused = mutationRefused && (order.phase !== 'credential' || mutationUnsent)\n const review = code === 'invalid_receipt'\n // The failing call spent its own clock, up to the client timeout. A backoff measured\n // from the tick's start clock can land in the past, leaving the order due immediately.\n const failedAt = clock()\n return save({ status: review ? 'needs_review' : 'provider_pending', errorCode: code,\n errorStatus: error instanceof MessagingProvisionError ? error.status : undefined,\n ...(refused ? { attempted: false } : {}),\n ...(mutationSettled ? { attemptedAt: undefined } : {}),\n nextAttemptAt: failedAt + (review ? REVIEW_BACKOFF_MS : Math.max(30, Math.min(retryAfter ?? 30, 86_400)) * 1000) })\n }\n}\n"],"mappings":"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","names":["identity","number","credential"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-integrations",
|
|
3
|
-
"version": "0.54.
|
|
3
|
+
"version": "0.54.2",
|
|
4
4
|
"description": "Vendor-neutral integration contracts and runtime helpers for sandbox and agent apps.",
|
|
5
5
|
"homepage": "https://github.com/tangle-network/agent-integrations#readme",
|
|
6
6
|
"repository": {
|