@tangle-network/agent-integrations 0.54.0 → 0.54.1

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.
@@ -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,21 @@ 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) || !Number.isSafeInteger(order.version) || order.version < 0) throw new MessagingProvisionError("invalid_input");
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;
197
199
  let mutationSettled = false;
198
200
  if (order.phase === "complete" || order.status === "cancelled") return order;
199
- const now = (ports.now ?? Date.now)();
201
+ const clock = ports.now ?? Date.now;
202
+ const now = clock();
200
203
  if (order.nextAttemptAt && order.nextAttemptAt > now) return order;
201
204
  async function save(patch) {
202
205
  const before = order;
203
- const next = { ...before, ...patch, version: before.version + 1 };
206
+ const next = { ...before, ..."errorCode" in patch && !("errorStatus" in patch) ? { errorStatus: void 0 } : {}, ...patch, version: before.version + 1 };
204
207
  if (await ports.orders.saveIfVersion(next, before.version)) {
205
208
  order = next;
206
209
  return next;
@@ -231,7 +234,7 @@ async function advanceManagedNumber(orderId, ports) {
231
234
  try {
232
235
  return await call();
233
236
  } catch (error) {
234
- if (error instanceof MessagingProvisionError && error.code === "provider_rejected") mutationRefused = true;
237
+ if (error instanceof MessagingProvisionError && (error.code === "provider_rejected" || error.code === "invalid_input")) mutationRefused = true;
235
238
  throw error;
236
239
  } finally {
237
240
  mutationSettled = true;
@@ -239,7 +242,7 @@ async function advanceManagedNumber(orderId, ports) {
239
242
  }
240
243
  async function claim() {
241
244
  const before = order;
242
- const claimed = await save({ attempted: true, attemptedAt: now, status: "pending", errorCode: void 0, nextAttemptAt: void 0 });
245
+ const claimed = await save({ attempted: true, attemptedAt: clock(), status: "pending", errorCode: void 0, nextAttemptAt: void 0 });
243
246
  if (claimed.version !== before.version + 1 || order !== claimed) return false;
244
247
  let authorized = false;
245
248
  try {
@@ -263,11 +266,11 @@ async function advanceManagedNumber(orderId, ports) {
263
266
  const current = await ports.orders.get(orderId);
264
267
  if (!current || current.version !== order.version || current.status === "cancelled") return false;
265
268
  if (!await ports.canProvision(current)) {
266
- await save({ status: "provider_pending", errorCode: "activation_not_configured", nextAttemptAt: now + 6e4 });
269
+ await save({ status: "provider_pending", errorCode: "activation_not_configured", nextAttemptAt: clock() + 6e4 });
267
270
  return false;
268
271
  }
269
272
  if (!await ports.authorizeFunding(current)) {
270
- await save({ status: "provider_pending", errorCode: "funding_required", nextAttemptAt: now + 6e4 });
273
+ await save({ status: "provider_pending", errorCode: "funding_required", nextAttemptAt: clock() + 6e4 });
271
274
  return false;
272
275
  }
273
276
  const rechecked = await ports.orders.get(orderId);
@@ -278,29 +281,29 @@ async function advanceManagedNumber(orderId, ports) {
278
281
  let identity2 = await ports.provider.getIdentity(order.handle);
279
282
  if (!identity2) {
280
283
  if (inFlight(order)) return order;
281
- if (order.attempted) return save({ status: "needs_review", errorCode: "identity_outcome_unknown" });
284
+ if (order.attempted) return save({ status: "needs_review", errorCode: "identity_outcome_unknown", nextAttemptAt: clock() + REVIEW_BACKOFF_MS });
282
285
  if (!await claim()) return await ports.orders.get(orderId);
283
286
  const handle = order.handle;
284
287
  identity2 = await mutate(() => ports.provider.createIdentity(handle));
285
288
  } else if (!order.attempted && !order.identityId) {
286
- return save({ status: "needs_review", errorCode: "identity_already_exists" });
289
+ return save({ status: "needs_review", errorCode: "identity_already_exists", nextAttemptAt: clock() + REVIEW_BACKOFF_MS });
287
290
  }
288
291
  identityMatches(order, identity2);
289
292
  return save({ identityId: identity2.id, phase: "number", attempted: false, status: "pending", errorCode: void 0 });
290
293
  }
291
294
  if (!order.identityId) throw new MessagingProvisionError("invalid_receipt");
292
295
  const identity = await ports.provider.getIdentity(order.handle);
293
- if (!identity) return save({ status: "needs_review", errorCode: "identity_missing" });
296
+ if (!identity) return save({ status: "needs_review", errorCode: "identity_missing", nextAttemptAt: clock() + REVIEW_BACKOFF_MS });
294
297
  identityMatches(order, identity);
295
298
  if (order.phase === "number") {
296
299
  let number2 = selectedNumber(order, identity);
297
- if (!number2 && order.number) return save({ status: "needs_review", errorCode: "number_missing" });
300
+ if (!number2 && order.number) return save({ status: "needs_review", errorCode: "number_missing", nextAttemptAt: clock() + REVIEW_BACKOFF_MS });
298
301
  if (!number2) {
299
302
  if (order.attempted && order.transport === "imessage" && identity.imessageEnabled) {
300
- return save({ status: "provider_pending", errorCode: "number_pending", nextAttemptAt: now + 3e4 });
303
+ return save({ status: "provider_pending", errorCode: "number_pending", nextAttemptAt: clock() + 3e4 });
301
304
  }
302
305
  if (inFlight(order)) return order;
303
- if (order.attempted) return save({ status: "needs_review", errorCode: "number_outcome_unknown" });
306
+ if (order.attempted) return save({ status: "needs_review", errorCode: "number_outcome_unknown", nextAttemptAt: clock() + REVIEW_BACKOFF_MS });
304
307
  if (!await claim()) return await ports.orders.get(orderId);
305
308
  const { handle, state, id } = order;
306
309
  if (order.transport === "sms") {
@@ -318,10 +321,10 @@ async function advanceManagedNumber(orderId, ports) {
318
321
  number2 = selectedNumber(order, receipt);
319
322
  }
320
323
  }
321
- if (!number2) return save({ status: "provider_pending", errorCode: "number_pending", nextAttemptAt: now + 3e4 });
324
+ if (!number2) return save({ status: "provider_pending", errorCode: "number_pending", nextAttemptAt: clock() + 3e4 });
322
325
  if (order.number && (order.number.id !== number2.id || order.number.number !== number2.number)) throw new MessagingProvisionError("invalid_receipt");
323
326
  if (order.transport === "sms" && (number2.smsStatus !== "ready" || number2.status !== "active")) {
324
- return save({ number: number2, attempted: false, status: "provider_pending", nextAttemptAt: now + 3e4, errorCode: "sms_not_ready" });
327
+ return save({ number: number2, attempted: false, status: "provider_pending", nextAttemptAt: clock() + 3e4, errorCode: "sms_not_ready" });
325
328
  }
326
329
  return save({ number: number2, phase: "credential", attempted: false, status: "pending", errorCode: void 0, nextAttemptAt: void 0 });
327
330
  }
@@ -331,7 +334,7 @@ async function advanceManagedNumber(orderId, ports) {
331
334
  let credential2 = await ports.vault.read(order.id);
332
335
  if (!credential2) {
333
336
  if (inFlight(order)) return order;
334
- if (order.attempted) return save({ status: "needs_review", errorCode: "credential_receipt_lost" });
337
+ if (order.attempted) return save({ status: "needs_review", errorCode: "credential_receipt_lost", nextAttemptAt: clock() + REVIEW_BACKOFF_MS });
335
338
  if (!await claim()) return await ports.orders.get(orderId);
336
339
  const { identityId, id } = order;
337
340
  const minted = await mutate(() => ports.provider.mintIdentityKey(identityId, `Tangle number ${id}`));
@@ -352,12 +355,15 @@ async function advanceManagedNumber(orderId, ports) {
352
355
  const code = error instanceof MessagingProvisionError ? error.code : "outcome_unknown";
353
356
  const retryAfter = error instanceof MessagingProvisionError ? error.retryAfterSeconds : void 0;
354
357
  const refused = mutationRefused && order.phase !== "credential";
358
+ const review = code === "invalid_receipt";
359
+ const failedAt = clock();
355
360
  return save({
356
- status: code === "invalid_receipt" ? "needs_review" : "provider_pending",
361
+ status: review ? "needs_review" : "provider_pending",
357
362
  errorCode: code,
363
+ errorStatus: error instanceof MessagingProvisionError ? error.status : void 0,
358
364
  ...refused ? { attempted: false } : {},
359
365
  ...mutationSettled ? { attemptedAt: void 0 } : {},
360
- nextAttemptAt: now + Math.max(30, Math.min(retryAfter ?? 30, 86400)) * 1e3
366
+ nextAttemptAt: failedAt + (review ? REVIEW_BACKOFF_MS : Math.max(30, Math.min(retryAfter ?? 30, 86400)) * 1e3)
361
367
  });
362
368
  }
363
369
  }
@@ -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 // 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 && (error.code === 'provider_rejected' || error.code === 'invalid_input')) 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 // 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 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', nextAttemptAt: clock() + REVIEW_BACKOFF_MS })\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', 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 if (inFlight(order)) return order\n if (order.attempted) return save({ status: 'needs_review', errorCode: 'number_outcome_unknown', nextAttemptAt: clock() + REVIEW_BACKOFF_MS })\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: 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 if (inFlight(order)) return order\n if (order.attempted) return save({ status: 'needs_review', errorCode: 'credential_receipt_lost', nextAttemptAt: clock() + REVIEW_BACKOFF_MS })\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 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.0",
3
+ "version": "0.54.1",
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": {