@tangle-network/agent-app 0.50.2 → 0.50.4

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.
@@ -69,6 +69,7 @@ function createApplicationLineHandler(options) {
69
69
  if (observed.state === "missing") {
70
70
  if (immutable.acceptedExecutionId !== void 0)
71
71
  return failure(503, "accepted_execution_unavailable");
72
+ await options.authorize(target, immutable);
72
73
  await options.admit(target, immutable);
73
74
  observed = await options.read(target, immutable);
74
75
  if (observed.state === "missing") observed = { state: "pending", admitted: false };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hosted-agent/application.ts","../../src/hosted-agent/workspace-line.ts"],"sourcesContent":["import { parseJsonObjectBody } from '../web/core'\nimport {\n LINE_APPLICATION_REQUEST_MAX_BYTES,\n parseLineApplicationRequest,\n parseLineApplicationResult,\n type LineApplicationRequest,\n type LineApplicationResult,\n type LineApplicationState,\n} from '@tangle-network/sandbox/core'\n\nexport { attachWorkspaceLine } from './workspace-line'\n\n/** Missing is an affirmative storage observation, never an error fallback. */\nexport type ApplicationLineObservation = LineApplicationState | { state: 'missing' }\n\nexport interface ApplicationLineOptions<T> {\n /** Authenticate before consuming the body. It must not trust model-supplied identity. */\n authenticate(request: Request): Promise<{ binding: string; target: T }>\n /** Recheck live binding, membership, owner authority and exact retained message. */\n authorize(target: T, input: Readonly<LineApplicationRequest>): Promise<void>\n /** Observe the application's existing durable turn, transcript and outputs. */\n read(target: T, input: Readonly<LineApplicationRequest>): Promise<ApplicationLineObservation>\n /**\n * Enter the normal persisted chat route using input.messageId as its stable\n * client turn identity. That route owns admission, locks and completion.\n * This callback MUST deduplicate that identity across concurrent requests.\n */\n admit(target: T, input: Readonly<LineApplicationRequest>): Promise<void>\n}\n\n/** One bounded pass from the native Lines worker into the application's existing execution path. */\nexport function createApplicationLineHandler<T>(options: ApplicationLineOptions<T>) {\n return async (request: Request): Promise<Response> => {\n if (request.method !== 'POST') return failure(405, 'method_not_allowed')\n let authenticated: { binding: string; target: T }\n try {\n authenticated = await options.authenticate(request)\n } catch (error) {\n return error instanceof Response ? error : failure(503, 'line_authentication_unavailable')\n }\n let input: LineApplicationRequest\n try {\n if (request.headers.get('content-type')?.split(';')[0]?.trim().toLowerCase() !== 'application/json')\n return failure(415, 'json_required')\n const [body, error] = await parseJsonObjectBody(request, { maxBytes: LINE_APPLICATION_REQUEST_MAX_BYTES })\n if (error) return error\n input = parseLineApplicationRequest(body)\n if (input.binding !== authenticated.binding) return failure(403, 'line_binding_mismatch')\n if (request.headers.get('idempotency-key') !== `line-application:${input.messageId}`)\n return failure(400, 'idempotency_key_mismatch')\n } catch {\n return failure(400, 'line_request_invalid')\n }\n // A viewer's AbortSignal must not cancel the accepted application task.\n const immutable = Object.freeze({ ...input, sender: Object.freeze({ ...input.sender }) })\n try {\n const { target } = authenticated\n await options.authorize(target, immutable)\n let observed = await options.read(target, immutable)\n if (observed.state === 'missing') {\n if (immutable.acceptedExecutionId !== undefined)\n return failure(503, 'accepted_execution_unavailable')\n await options.admit(target, immutable)\n observed = await options.read(target, immutable)\n if (observed.state === 'missing') observed = { state: 'pending', admitted: false }\n }\n // Reading or admitting work may yield to a disconnect or member revocation.\n await options.authorize(target, immutable)\n const result: LineApplicationResult = parseLineApplicationResult({\n ...observed, version: 1, binding: input.binding,\n messageId: input.messageId, attachmentId: input.attachmentId,\n }, input)\n return Response.json(result, { headers: { 'cache-control': 'no-store' } })\n } catch (error) {\n // Unavailable authoritative state is not permission to start a new task.\n return error instanceof Response ? error : failure(503, 'line_application_unavailable')\n }\n }\n}\n\nfunction failure(status: number, code: string): Response {\n return Response.json({ error: { code } }, { status, headers: { 'cache-control': 'no-store' } })\n}\n","import type { LineApplication, LineAttachment, SandboxInstance } from '@tangle-network/sandbox/core'\n\n/** A line delegates its nominated owner to the application's normal chat path. */\nexport async function attachWorkspaceLine(input: {\n box: Pick<SandboxInstance, 'lines'>\n lineId: string\n ownerAddress: string\n application: LineApplication\n turnsPerDay?: number\n}): Promise<LineAttachment> {\n const address = input.ownerAddress.trim()\n const turnsPerDay = input.turnsPerDay ?? 20\n if (!/^\\+[1-9]\\d{6,14}$/.test(address) && !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(address)) {\n throw new TypeError('The delegated sender must be an E.164 number or email/Apple ID')\n }\n if (!Number.isSafeInteger(turnsPerDay) || turnsPerDay < 1 || turnsPerDay > 10_000) {\n throw new TypeError('A daily turn limit between 1 and 10000 is required')\n }\n const url = new URL(input.application.url)\n if (url.protocol !== 'https:' || url.username || url.password || url.hash) {\n throw new TypeError('The application callback must use HTTPS without URL credentials or a fragment')\n }\n if (!/^[\\x21-\\x7e]{1,1024}$/.test(input.application.binding)\n || !/^[\\x21-\\x7e]{16,512}$/.test(input.application.secret)) {\n throw new TypeError('A binding and a header-safe callback credential are required')\n }\n return input.box.lines.attach({\n number: input.lineId,\n mode: 'personal',\n members: [{ address: address.includes('@') ? address.toLowerCase() : address, role: 'owner' }],\n unknownSenders: 'reject',\n roles: { owner: { context: 'own', tools: 'act' } },\n respond: { kind: 'agent', application: { ...input.application } },\n limits: { turnsPerMemberPerDay: turnsPerDay },\n })\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/hosted-agent/application.ts","../../src/hosted-agent/workspace-line.ts"],"sourcesContent":["import { parseJsonObjectBody } from '../web/core'\nimport {\n LINE_APPLICATION_REQUEST_MAX_BYTES,\n parseLineApplicationRequest,\n parseLineApplicationResult,\n type LineApplicationRequest,\n type LineApplicationResult,\n type LineApplicationState,\n} from '@tangle-network/sandbox/core'\n\nexport { attachWorkspaceLine } from './workspace-line'\n\n/** Missing is an affirmative storage observation, never an error fallback. */\nexport type ApplicationLineObservation = LineApplicationState | { state: 'missing' }\n\nexport interface ApplicationLineOptions<T> {\n /** Authenticate before consuming the body. It must not trust model-supplied identity. */\n authenticate(request: Request): Promise<{ binding: string; target: T }>\n /** Recheck live binding, membership, owner authority and exact retained message. */\n authorize(target: T, input: Readonly<LineApplicationRequest>): Promise<void>\n /** Observe the application's existing durable turn, transcript and outputs. */\n read(target: T, input: Readonly<LineApplicationRequest>): Promise<ApplicationLineObservation>\n /**\n * Enter the normal persisted chat route using input.messageId as its stable\n * client turn identity. That route owns admission, locks and completion.\n * This callback MUST deduplicate that identity across concurrent requests.\n */\n admit(target: T, input: Readonly<LineApplicationRequest>): Promise<void>\n}\n\n/** One bounded pass from the native Lines worker into the application's existing execution path. */\nexport function createApplicationLineHandler<T>(options: ApplicationLineOptions<T>) {\n return async (request: Request): Promise<Response> => {\n if (request.method !== 'POST') return failure(405, 'method_not_allowed')\n let authenticated: { binding: string; target: T }\n try {\n authenticated = await options.authenticate(request)\n } catch (error) {\n return error instanceof Response ? error : failure(503, 'line_authentication_unavailable')\n }\n let input: LineApplicationRequest\n try {\n if (request.headers.get('content-type')?.split(';')[0]?.trim().toLowerCase() !== 'application/json')\n return failure(415, 'json_required')\n const [body, error] = await parseJsonObjectBody(request, { maxBytes: LINE_APPLICATION_REQUEST_MAX_BYTES })\n if (error) return error\n input = parseLineApplicationRequest(body)\n if (input.binding !== authenticated.binding) return failure(403, 'line_binding_mismatch')\n if (request.headers.get('idempotency-key') !== `line-application:${input.messageId}`)\n return failure(400, 'idempotency_key_mismatch')\n } catch {\n return failure(400, 'line_request_invalid')\n }\n // A viewer's AbortSignal must not cancel the accepted application task.\n const immutable = Object.freeze({ ...input, sender: Object.freeze({ ...input.sender }) })\n try {\n const { target } = authenticated\n await options.authorize(target, immutable)\n let observed = await options.read(target, immutable)\n if (observed.state === 'missing') {\n if (immutable.acceptedExecutionId !== undefined)\n return failure(503, 'accepted_execution_unavailable')\n // The read may yield to revocation; check again before admitting work.\n await options.authorize(target, immutable)\n await options.admit(target, immutable)\n observed = await options.read(target, immutable)\n if (observed.state === 'missing') observed = { state: 'pending', admitted: false }\n }\n // Reading or admitting work may yield to a disconnect or member revocation.\n await options.authorize(target, immutable)\n const result: LineApplicationResult = parseLineApplicationResult({\n ...observed, version: 1, binding: input.binding,\n messageId: input.messageId, attachmentId: input.attachmentId,\n }, input)\n return Response.json(result, { headers: { 'cache-control': 'no-store' } })\n } catch (error) {\n // Unavailable authoritative state is not permission to start a new task.\n return error instanceof Response ? error : failure(503, 'line_application_unavailable')\n }\n }\n}\n\nfunction failure(status: number, code: string): Response {\n return Response.json({ error: { code } }, { status, headers: { 'cache-control': 'no-store' } })\n}\n","import type { LineApplication, LineAttachment, SandboxInstance } from '@tangle-network/sandbox/core'\n\n/** A line delegates its nominated owner to the application's normal chat path. */\nexport async function attachWorkspaceLine(input: {\n box: Pick<SandboxInstance, 'lines'>\n lineId: string\n ownerAddress: string\n application: LineApplication\n turnsPerDay?: number\n}): Promise<LineAttachment> {\n const address = input.ownerAddress.trim()\n const turnsPerDay = input.turnsPerDay ?? 20\n if (!/^\\+[1-9]\\d{6,14}$/.test(address) && !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(address)) {\n throw new TypeError('The delegated sender must be an E.164 number or email/Apple ID')\n }\n if (!Number.isSafeInteger(turnsPerDay) || turnsPerDay < 1 || turnsPerDay > 10_000) {\n throw new TypeError('A daily turn limit between 1 and 10000 is required')\n }\n const url = new URL(input.application.url)\n if (url.protocol !== 'https:' || url.username || url.password || url.hash) {\n throw new TypeError('The application callback must use HTTPS without URL credentials or a fragment')\n }\n if (!/^[\\x21-\\x7e]{1,1024}$/.test(input.application.binding)\n || !/^[\\x21-\\x7e]{16,512}$/.test(input.application.secret)) {\n throw new TypeError('A binding and a header-safe callback credential are required')\n }\n return input.box.lines.attach({\n number: input.lineId,\n mode: 'personal',\n members: [{ address: address.includes('@') ? address.toLowerCase() : address, role: 'owner' }],\n unknownSenders: 'reject',\n roles: { owner: { context: 'own', tools: 'act' } },\n respond: { kind: 'agent', application: { ...input.application } },\n limits: { turnsPerMemberPerDay: turnsPerDay },\n })\n}\n"],"mappings":"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","names":[]}
@@ -63,7 +63,8 @@ function LineSetup({ client, scopeKey, initialTargetId, targetLabel, canManage,
63
63
  const [targetId, setTargetId] = useState(initialTargetId ?? "");
64
64
  const [boxMode, setBoxMode] = useState("per-member");
65
65
  const [phoneNumberId, setPhoneNumberId] = useState("");
66
- const [confirmLineId, setConfirmLineId] = useState(null);
66
+ const [confirmation, setConfirmation] = useState(null);
67
+ const confirmLineId = confirmation?.lineId ?? null;
67
68
  function stillCurrent(requestIncarnation) {
68
69
  return requestIncarnation === incarnation.current;
69
70
  }
@@ -93,7 +94,7 @@ function LineSetup({ client, scopeKey, initialTargetId, targetLabel, canManage,
93
94
  }
94
95
  function closeConfirmation(lineId) {
95
96
  restoreFocusTo.current = lineId;
96
- setConfirmLineId(null);
97
+ setConfirmation(null);
97
98
  }
98
99
  useEffect(() => {
99
100
  setLoading(true);
@@ -106,7 +107,7 @@ function LineSetup({ client, scopeKey, initialTargetId, targetLabel, canManage,
106
107
  setTargetId(initialTargetId ?? "");
107
108
  setBoxMode("per-member");
108
109
  setPhoneNumberId("");
109
- setConfirmLineId(null);
110
+ setConfirmation(null);
110
111
  restoreFocusTo.current = null;
111
112
  void reload(incarnation.current);
112
113
  return () => {
@@ -175,13 +176,13 @@ function LineSetup({ client, scopeKey, initialTargetId, targetLabel, canManage,
175
176
  if (stillCurrent(requestIncarnation)) setBusy(false);
176
177
  }
177
178
  }
178
- async function disconnect(lineId) {
179
- if (busy || loading || refreshFailed) return;
179
+ async function disconnect() {
180
+ if (!confirmation || busy || loading || refreshFailed) return;
181
+ const { lineId, attachmentId: expectedAttachmentId } = confirmation;
180
182
  const requestIncarnation = incarnation.current;
181
183
  setBusy(true);
182
184
  setError(null);
183
185
  try {
184
- const expectedAttachmentId = snapshot?.lines.find((line) => line.id === lineId)?.attachmentId ?? void 0;
185
186
  await clientRef.current.disconnect(lineId, expectedAttachmentId);
186
187
  if (!stillCurrent(requestIncarnation)) return;
187
188
  const updated = await reload(requestIncarnation);
@@ -250,12 +251,12 @@ function LineSetup({ client, scopeKey, initialTargetId, targetLabel, canManage,
250
251
  ] }),
251
252
  canManage && line.canDisconnect && line.targetId !== null && line.status === "active" && /* @__PURE__ */ jsx("div", { className: "tangle-lines__row-actions", children: confirmLineId === line.id ? /* @__PURE__ */ jsxs("div", { className: "tangle-lines__confirm", role: "group", "aria-label": `Disconnect ${line.address}?`, children: [
252
253
  /* @__PURE__ */ jsx("span", { children: "Disconnect this line?" }),
253
- /* @__PURE__ */ jsx("button", { ref: confirmButton, type: "button", className: "tangle-lines__danger", disabled: busy || loading || refreshFailed, onClick: () => void disconnect(line.id), children: "Disconnect" }),
254
+ /* @__PURE__ */ jsx("button", { ref: confirmButton, type: "button", className: "tangle-lines__danger", disabled: busy || loading || refreshFailed, onClick: () => void disconnect(), children: "Disconnect" }),
254
255
  /* @__PURE__ */ jsx("button", { type: "button", disabled: busy, onClick: () => closeConfirmation(line.id), children: "Keep line" })
255
256
  ] }) : /* @__PURE__ */ jsx("button", { ref: (node) => {
256
257
  if (node) disconnectTriggers.current.set(line.id, node);
257
258
  else disconnectTriggers.current.delete(line.id);
258
- }, type: "button", className: "tangle-lines__quiet", disabled: busy || loading || refreshFailed, onClick: () => setConfirmLineId(line.id), children: "Disconnect line" }) })
259
+ }, type: "button", className: "tangle-lines__quiet", disabled: busy || loading || refreshFailed, onClick: () => setConfirmation({ lineId: line.id, attachmentId: line.attachmentId ?? void 0 }), children: "Disconnect line" }) })
259
260
  ] }, line.id))
260
261
  ] }),
261
262
  canManage && showConnectionSetup && (snapshot.connections === null || choices.length > 0 || allChoices.length === 0) && /* @__PURE__ */ jsxs("div", { className: "tangle-lines__setup", children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hosted-agent/react/LineSetup.tsx","../../../src/hosted-agent/react/LineMembers.tsx","../../../src/hosted-agent/react/LineBilling.tsx","../../../src/hosted-agent/react/ApplicationLineSetup.tsx"],"sourcesContent":["import { useEffect, useLayoutEffect, useRef, useState } from 'react'\nimport type { Line } from '@tangle-network/sandbox'\nimport type {\n LineBoxMode, LineConnectionOption, LineIdentityKind, LineIdentityOption,\n LineSetupLine, LineSetupProps, LineSetupSnapshot,\n} from './contracts'\n\nconst useBrowserLayoutEffect = typeof document !== 'undefined' ? useLayoutEffect : useEffect\n\nconst TRANSPORT: Record<Line['transport'], string> = {\n imessage: 'iMessage', sms: 'SMS', whatsapp: 'WhatsApp', email: 'Email',\n}\nconst IDENTITY: Record<LineIdentityKind, string> = {\n handle: 'Inkbox handle', number: 'Dedicated number', email: 'Email line',\n}\n\ntype Choice = { key: string; connection: LineConnectionOption; identity: LineIdentityOption }\n\nfunction message(error: unknown): string {\n return error instanceof Error ? error.message : 'The line request failed. Try again.'\n}\n\nfunction dateTime(value: string): string {\n const date = new Date(value)\n return Number.isNaN(date.getTime()) ? value : date.toLocaleString()\n}\n\nfunction choicesFor(snapshot: LineSetupSnapshot): Choice[] {\n return (snapshot.connections ?? []).flatMap(connection => connection.identities.map((identity, index) => ({\n key: `${connection.id}:${index}`,\n connection,\n identity,\n })))\n}\n\nfunction canOfferReconnect(line: LineSetupLine, choice: Choice): boolean {\n if (line.connectionId !== choice.connection.id || line.transport !== choice.identity.transport || line.targetId !== null) return false\n if (line.providerNumberId === null) return line.transport !== 'whatsapp' && !choice.identity.phoneNumberId && !choice.identity.requiresPhoneNumberId\n return choice.identity.phoneNumberId === line.providerNumberId ||\n (!choice.identity.phoneNumberId && choice.identity.requiresPhoneNumberId === true)\n}\n\nfunction matchesLineIdentity(line: LineSetupLine, identity: LineIdentityOption, numberId: string): boolean {\n if (line.transport !== identity.transport) return false\n if (line.providerNumberId === null) return line.transport !== 'whatsapp' && !identity.phoneNumberId && !identity.requiresPhoneNumberId\n return numberId === line.providerNumberId\n}\n\n/** Set up an owned identity through a host route backed by sandbox.lines and Hub. */\nexport function LineSetup({ client, scopeKey, initialTargetId, targetLabel, canManage, canConnect = canManage, showConnectionSetup = true, onNotice }: LineSetupProps) {\n const clientRef = useRef(client)\n clientRef.current = client\n const sequence = useRef(0)\n const incarnation = useRef(0)\n const confirmButton = useRef<HTMLButtonElement>(null)\n const heading = useRef<HTMLHeadingElement>(null)\n const disconnectTriggers = useRef(new Map<string, HTMLButtonElement>())\n const restoreFocusTo = useRef<string | null>(null)\n useBrowserLayoutEffect(() => {\n incarnation.current++\n return () => { incarnation.current++ }\n }, [scopeKey, initialTargetId])\n const [loadedSnapshot, setLoadedSnapshot] = useState<{ scopeKey: string; initialTargetId: string | undefined; value: LineSetupSnapshot } | null>(null)\n const snapshot = loadedSnapshot?.scopeKey === scopeKey && loadedSnapshot.initialTargetId === initialTargetId ? loadedSnapshot.value : null\n const [loading, setLoading] = useState(true)\n const [refreshFailed, setRefreshFailed] = useState(false)\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [kind, setKind] = useState<LineIdentityKind>('handle')\n const [choiceKey, setChoiceKey] = useState('')\n const [targetId, setTargetId] = useState(initialTargetId ?? '')\n const [boxMode, setBoxMode] = useState<LineBoxMode>('per-member')\n const [phoneNumberId, setPhoneNumberId] = useState('')\n const [confirmLineId, setConfirmLineId] = useState<string | null>(null)\n\n function stillCurrent(requestIncarnation: number): boolean {\n return requestIncarnation === incarnation.current\n }\n\n async function reload(requestIncarnation: number): Promise<LineSetupSnapshot | null> {\n const request = ++sequence.current\n try {\n const next = await clientRef.current.load()\n if (request !== sequence.current || !stillCurrent(requestIncarnation)) return null\n setLoadedSnapshot({ scopeKey, initialTargetId, value: next })\n setError(null)\n setRefreshFailed(false)\n setTargetId(current => next.targets.some(target => target.id === current)\n ? current : next.targets.find(target => target.id === initialTargetId)?.id ?? next.targets[0]?.id ?? '')\n setLoading(false)\n return next\n } catch (cause) {\n if (request !== sequence.current || !stillCurrent(requestIncarnation)) return null\n setError(message(cause))\n setRefreshFailed(true)\n setLoading(false)\n return null\n }\n }\n\n function retry() {\n if (loading) return\n setLoading(true)\n void reload(incarnation.current)\n }\n\n function closeConfirmation(lineId: string) {\n restoreFocusTo.current = lineId\n setConfirmLineId(null)\n }\n\n useEffect(() => {\n setLoading(true)\n setLoadedSnapshot(null)\n setError(null)\n setRefreshFailed(false)\n setBusy(false)\n setKind('handle')\n setChoiceKey('')\n setTargetId(initialTargetId ?? '')\n setBoxMode('per-member')\n setPhoneNumberId('')\n setConfirmLineId(null)\n restoreFocusTo.current = null\n void reload(incarnation.current)\n return () => { sequence.current++ }\n }, [scopeKey, initialTargetId])\n\n useEffect(() => {\n if (confirmLineId) confirmButton.current?.focus()\n }, [confirmLineId])\n\n useEffect(() => {\n const lineId = restoreFocusTo.current\n if (confirmLineId !== null || lineId === null) return\n restoreFocusTo.current = null\n const trigger = disconnectTriggers.current.get(lineId)\n if (trigger && !trigger.disabled) trigger.focus()\n else heading.current?.focus()\n }, [confirmLineId, snapshot, refreshFailed])\n\n const allChoices = snapshot ? choicesFor(snapshot) : []\n const choices = snapshot ? allChoices.filter(choice => {\n const occupied = snapshot.lines.filter(line => line.status !== 'released' && line.transport === choice.identity.transport)\n const [line] = occupied\n return occupied.length === 0 || (occupied.length === 1 && line !== undefined && canOfferReconnect(line, choice))\n }) : []\n const availableKinds = (['handle', 'number', 'email'] as const).filter(value => choices.some(choice => choice.identity.kind === value))\n const selectedKind = availableKinds.includes(kind) ? kind : availableKinds[0]\n const kindChoices = choices.filter(choice => choice.identity.kind === selectedKind)\n const selected = kindChoices.find(choice => choice.key === choiceKey) ?? kindChoices[0]\n const selectedTarget = snapshot?.targets.find(target => target.id === targetId)\n const selectedMode = selectedTarget?.modes.includes(boxMode) ? boxMode : selectedTarget?.modes[0]\n const enteredNumber = selected?.identity.phoneNumberId ?? phoneNumberId.trim()\n const needsNumber = selected?.identity.transport === 'whatsapp' || selected?.identity.requiresPhoneNumberId\n const occupied = selected && snapshot?.lines.filter(line => line.status !== 'released' && line.transport === selected.identity.transport)\n const [occupiedLine] = occupied || []\n const reconnectChoice = Boolean(selected && occupied?.length === 1 && occupiedLine && canOfferReconnect(occupiedLine, selected))\n const reconnecting = Boolean(reconnectChoice && selected && occupiedLine &&\n matchesLineIdentity(occupiedLine, selected.identity, enteredNumber))\n const blockedByExistingLine = Boolean(occupied?.length && !reconnecting)\n const answeringCount = snapshot?.lines.filter(line => line.answering).length ?? 0\n\n async function connect() {\n if (!canManage || !canConnect || !selected || !selectedTarget || !selectedMode || (needsNumber && !enteredNumber) || blockedByExistingLine || busy || loading || refreshFailed) return\n const requestIncarnation = incarnation.current\n setBusy(true)\n setError(null)\n try {\n await clientRef.current.connect({\n connectionId: selected.connection.id,\n transport: selected.identity.transport,\n ...(enteredNumber ? { phoneNumberId: enteredNumber } : {}),\n targetId: selectedTarget.id,\n boxMode: selectedMode,\n })\n if (!stillCurrent(requestIncarnation)) return\n const updated = await reload(requestIncarnation)\n if (!stillCurrent(requestIncarnation)) return\n if (!updated) {\n onNotice?.({ kind: 'error', message: 'Line connected, but its current status could not be loaded.' })\n return\n }\n const line = updated.lines.find(item => item.status !== 'released' && item.connectionId === selected.connection.id &&\n item.transport === selected.identity.transport && item.providerNumberId === (enteredNumber || null))\n onNotice?.({ kind: 'success', message: line?.answering ? 'The line is answering.' : 'Line connected. Add a member to start answers.' })\n } catch (cause) {\n if (!stillCurrent(requestIncarnation)) return\n const detail = message(cause)\n setError(detail)\n onNotice?.({ kind: 'error', message: detail })\n } finally {\n if (stillCurrent(requestIncarnation)) setBusy(false)\n }\n }\n\n async function disconnect(lineId: string) {\n if (busy || loading || refreshFailed) return\n const requestIncarnation = incarnation.current\n setBusy(true)\n setError(null)\n try {\n const expectedAttachmentId = snapshot?.lines.find(line => line.id === lineId)?.attachmentId ?? undefined\n await clientRef.current.disconnect(lineId, expectedAttachmentId)\n if (!stillCurrent(requestIncarnation)) return\n const updated = await reload(requestIncarnation)\n if (!stillCurrent(requestIncarnation)) return\n closeConfirmation(lineId)\n onNotice?.(updated\n ? { kind: 'success', message: 'The line stopped answering.' }\n : { kind: 'error', message: 'Line disconnected, but its current status could not be loaded.' })\n } catch (cause) {\n if (!stillCurrent(requestIncarnation)) return\n const detail = message(cause)\n setError(detail)\n onNotice?.({ kind: 'error', message: detail })\n } finally {\n if (stillCurrent(requestIncarnation)) setBusy(false)\n }\n }\n\n return <section className=\"tangle-lines\" aria-label=\"Agent lines\">\n <header className=\"tangle-lines__heading\">\n <div>\n <h2 ref={heading} tabIndex={-1}>Lines</h2>\n {snapshot && <p>{snapshot.workspaceName} can use one line per transport.</p>}\n </div>\n {answeringCount > 1 && <span className=\"tangle-lines__count\">{answeringCount} answering</span>}\n </header>\n\n {error && <div className=\"tangle-lines__error\" role=\"alert\">\n <div><strong>{refreshFailed ? 'Lines are unavailable' : 'Line action failed'}</strong><p>{error}</p></div>\n {(!snapshot || refreshFailed) && <button type=\"button\" disabled={loading} onClick={retry}>Retry</button>}\n </div>}\n {loading && <p className=\"tangle-lines__muted\" role=\"status\">Loading lines…</p>}\n\n {snapshot && <>\n <div className=\"tangle-lines__list\">\n {snapshot.lines.filter(line => line.status !== 'released').length === 0 &&\n <div className=\"tangle-lines__empty\"><strong>No lines connected</strong><p>{canManage && showConnectionSetup\n ? 'Connect an owned identity below to let this workspace answer messages.'\n : 'There are no connected lines in this workspace.'}</p></div>}\n {snapshot.lines.filter(line => line.status !== 'released').map(line =>\n <div className=\"tangle-lines__row\" key={line.id}>\n <div className=\"tangle-lines__row-main\">\n <div className=\"tangle-lines__row-heading\"><span className=\"tangle-lines__transport\">{TRANSPORT[line.transport]}</span><span className={`tangle-lines__status${line.answering ? ' tangle-lines__status--answering' : ''}`}>{line.answering ? 'Answering' : line.targetId === null ? 'Disconnected' : line.status === 'active' ? 'Awaiting member' : line.status}</span></div>\n <strong>{line.routerAddress ?? line.address}</strong>\n {line.connect && line.targetId !== null && <p>To reach this agent, text <code>{line.connect}</code>.</p>}\n <p>{line.targetLabel ?? 'No agent or box assigned'}{line.boxMode && ` · ${line.boxMode === 'per-member' ? 'one box per member' : 'shared box'}`}</p>\n {line.lastTurn.kind === 'latest' ? <p>Last turn: {line.lastTurn.status} · {dateTime(line.lastTurn.at)}</p>\n : <p>{line.lastTurn.kind === 'none' ? 'No turns yet.' : 'Turn history unavailable.'}</p>}\n </div>\n {canManage && line.canDisconnect && line.targetId !== null && line.status === 'active' && <div className=\"tangle-lines__row-actions\">\n {confirmLineId === line.id ? <div className=\"tangle-lines__confirm\" role=\"group\" aria-label={`Disconnect ${line.address}?`}>\n <span>Disconnect this line?</span>\n <button ref={confirmButton} type=\"button\" className=\"tangle-lines__danger\" disabled={busy || loading || refreshFailed} onClick={() => void disconnect(line.id)}>Disconnect</button>\n <button type=\"button\" disabled={busy} onClick={() => closeConfirmation(line.id)}>Keep line</button>\n </div> : <button ref={node => { if (node) disconnectTriggers.current.set(line.id, node); else disconnectTriggers.current.delete(line.id) }} type=\"button\" className=\"tangle-lines__quiet\" disabled={busy || loading || refreshFailed} onClick={() => setConfirmLineId(line.id)}>Disconnect line</button>}\n </div>}\n </div>)}\n </div>\n\n {canManage && showConnectionSetup && (snapshot.connections === null || choices.length > 0 || allChoices.length === 0) && <div className=\"tangle-lines__setup\">\n <span className=\"tangle-lines__overline\">New line</span>\n <h3>Connect an identity you own</h3>\n <p>Choose an identity already connected in Hub. Billing details appear below.</p>\n {snapshot.connections === null ? <div className=\"tangle-lines__error\" role=\"status\">\n <span>Hub connections could not be read. Check Hub access and try again.</span>\n <button type=\"button\" disabled={loading} onClick={retry}>Retry</button>\n </div>\n : availableKinds.length === 0 ? <p className=\"tangle-lines__empty\">\n Connect an owned handle, number, or mailbox in Hub, then <button type=\"button\" disabled={loading} onClick={retry}>reload</button>.\n </p>\n : <>\n <div className=\"tangle-lines__kinds\" role=\"group\" aria-label=\"Identity type\">\n {availableKinds.map(value => <button key={value} type=\"button\" aria-pressed={selectedKind === value} onClick={() => { setKind(value); setChoiceKey(''); setPhoneNumberId('') }}>{IDENTITY[value]}</button>)}\n </div>\n <div className=\"tangle-lines__fields\">\n <label>Owned connection\n <select value={selected?.key ?? ''} onChange={event => { setChoiceKey(event.target.value); setPhoneNumberId('') }}>\n {kindChoices.map(choice => <option key={choice.key} value={choice.key}>{choice.connection.label} · {choice.identity.label}</option>)}\n </select>\n </label>\n <label>{targetLabel ?? 'Agent or box'}\n <select value={selectedTarget?.id ?? ''} onChange={event => setTargetId(event.target.value)}>\n {snapshot.targets.map(target => <option key={target.id} value={target.id}>{target.label}{targetLabel ? '' : ` · ${target.kind}`}</option>)}\n </select>\n </label>\n {selectedTarget && selectedTarget.modes.length > 1 && <fieldset>\n <legend>Conversation space</legend>\n <label><input type=\"radio\" name={`line-box-mode-${scopeKey}`} value=\"per-member\" checked={selectedMode === 'per-member'} disabled={!selectedTarget?.modes.includes('per-member')} onChange={() => setBoxMode('per-member')} /> One box per member</label>\n <label><input type=\"radio\" name={`line-box-mode-${scopeKey}`} value=\"shared\" checked={selectedMode === 'shared'} disabled={!selectedTarget?.modes.includes('shared')} onChange={() => setBoxMode('shared')} /> Shared box for a team</label>\n </fieldset>}\n {needsNumber && !selected?.identity.phoneNumberId && <label>Existing provider number ID\n <input value={phoneNumberId} onChange={event => setPhoneNumberId(event.target.value)} autoComplete=\"off\" placeholder=\"Number ID from Hub\" />\n </label>}\n </div>\n {reconnectChoice && blockedByExistingLine && <p className=\"tangle-lines__warning\">Enter this line's current provider number ID to reconnect.</p>}\n <button className=\"tangle-lines__primary\" type=\"button\" disabled={!canConnect || busy || loading || refreshFailed || !selected || !selectedTarget || !selectedMode || (needsNumber && !enteredNumber) || blockedByExistingLine} onClick={() => void connect()}>\n {busy ? (reconnectChoice ? 'Reconnecting…' : 'Connecting…') : `${reconnectChoice ? 'Reconnect' : 'Connect'} ${selected ? TRANSPORT[selected.identity.transport] : 'line'}`}\n </button>\n </>}\n </div>}\n </>}\n </section>\n}\n","import { useEffect, useLayoutEffect, useRef, useState } from 'react'\nimport type { LineMember } from '@tangle-network/sandbox'\nimport type { LineMembersProps } from './contracts'\n\nconst useBrowserLayoutEffect = typeof document !== 'undefined' ? useLayoutEffect : useEffect\n\nconst STATUS: Record<LineMember['status'], { label: string; detail: string }> = {\n invited: { label: 'Awaiting consent', detail: 'The first message from this address confirms consent.' },\n active: { label: 'Consented', detail: 'This member has sent a message to the line.' },\n stopped: { label: 'Stopped', detail: 'The member texted STOP. Only a message from them with START resumes replies.' },\n removed: { label: 'Removed', detail: 'This address no longer has access to the line.' },\n}\n\nfunction errorMessage(cause: unknown): string {\n return cause instanceof Error ? cause.message : 'The member request failed. Try again.'\n}\n\n/** Manage Hub line members while keeping consent and STOP authority with the sender. */\nexport function LineMembers({ lineId, scopeKey, client, roles, canManage, canAdd = true, maxMembers, allowRoleChange = true, allowRemoveLastOwner = false, onNotice }: LineMembersProps) {\n const clientRef = useRef(client)\n clientRef.current = client\n const sequence = useRef(0)\n const incarnation = useRef(0)\n const confirmButton = useRef<HTMLButtonElement>(null)\n const heading = useRef<HTMLHeadingElement>(null)\n const removeTriggers = useRef(new Map<string, HTMLButtonElement>())\n const restoreFocusTo = useRef<string | null>(null)\n useBrowserLayoutEffect(() => {\n incarnation.current++\n return () => { incarnation.current++ }\n }, [lineId, scopeKey])\n const [memberSnapshot, setMemberSnapshot] = useState<{ lineId: string; scopeKey: string; members: LineMember[] } | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [refreshFailed, setRefreshFailed] = useState(false)\n const [address, setAddress] = useState('')\n const [label, setLabel] = useState('')\n const [role, setRole] = useState('member')\n const [busy, setBusy] = useState<string | null>(null)\n const [confirmId, setConfirmId] = useState<string | null>(null)\n const members = memberSnapshot?.lineId === lineId && memberSnapshot.scopeKey === scopeKey ? memberSnapshot.members : null\n\n function stillCurrent(requestIncarnation: number): boolean {\n return requestIncarnation === incarnation.current\n }\n\n async function reload(requestIncarnation: number): Promise<boolean> {\n const request = ++sequence.current\n try {\n const next = await clientRef.current.list(lineId)\n if (request !== sequence.current || !stillCurrent(requestIncarnation)) return false\n setMemberSnapshot({ lineId, scopeKey, members: next })\n setError(null)\n setRefreshFailed(false)\n return true\n } catch (cause) {\n if (request !== sequence.current || !stillCurrent(requestIncarnation)) return false\n setError(errorMessage(cause))\n setRefreshFailed(true)\n return false\n }\n }\n\n async function retry() {\n if (busy) return\n const requestIncarnation = incarnation.current\n setBusy('refresh')\n try { await reload(requestIncarnation) }\n finally { if (stillCurrent(requestIncarnation)) setBusy(null) }\n }\n\n function closeConfirmation(memberId: string) {\n restoreFocusTo.current = memberId\n setConfirmId(null)\n }\n\n useEffect(() => {\n setMemberSnapshot(null)\n setError(null)\n setRefreshFailed(false)\n setAddress('')\n setLabel('')\n setRole('member')\n setConfirmId(null)\n restoreFocusTo.current = null\n setBusy(null)\n void reload(incarnation.current)\n return () => { sequence.current++ }\n }, [lineId, scopeKey])\n\n useEffect(() => {\n if (confirmId) confirmButton.current?.focus()\n }, [confirmId])\n\n useEffect(() => {\n const memberId = restoreFocusTo.current\n if (confirmId !== null || memberId === null) return\n restoreFocusTo.current = null\n const trigger = removeTriggers.current.get(memberId)\n if (trigger && !trigger.disabled) trigger.focus()\n else heading.current?.focus()\n }, [confirmId, members, refreshFailed])\n\n const selectedRole = roles.some(item => item.value === role) ? role : roles.find(item => item.value === 'member')?.value ?? roles[0]?.value ?? ''\n const activeMembers = members?.filter(member => member.status !== 'removed').length ?? 0\n const activeOwners = members?.filter(member => member.role === 'owner' && member.status !== 'removed').length ?? 0\n\n async function mutate(key: string, action: () => Promise<void>, success: string, onSuccess?: () => void) {\n if (busy || refreshFailed) return\n const requestIncarnation = incarnation.current\n setBusy(key)\n setError(null)\n try {\n await action()\n if (!stillCurrent(requestIncarnation)) return\n const refreshed = await reload(requestIncarnation)\n if (!stillCurrent(requestIncarnation)) return\n onSuccess?.()\n onNotice?.(refreshed\n ? { kind: 'success', message: success }\n : { kind: 'error', message: 'Member updated, but the current member list could not be loaded.' })\n } catch (cause) {\n if (!stillCurrent(requestIncarnation)) return\n const detail = errorMessage(cause)\n setError(detail)\n onNotice?.({ kind: 'error', message: detail })\n } finally {\n if (stillCurrent(requestIncarnation)) setBusy(null)\n }\n }\n\n function add() {\n const trimmed = address.trim()\n if (!trimmed || !selectedRole || members === null || (maxMembers !== undefined && activeMembers >= maxMembers)) return\n void mutate('add', () => clientRef.current.add(lineId, { address: trimmed, role: selectedRole, ...(label.trim() ? { label: label.trim() } : {}) }), 'Member invited. Their first message confirms consent.', () => {\n setAddress('')\n setLabel('')\n })\n }\n\n return <section className=\"tangle-lines\" aria-label=\"Line members\">\n <header className=\"tangle-lines__heading\">\n <div><h2 ref={heading} tabIndex={-1}>Members</h2><p>Each address controls its own consent and STOP state.</p></div>\n {members && <span className=\"tangle-lines__count\">{activeMembers} {activeMembers === 1 ? 'member' : 'members'}</span>}\n </header>\n {error && <div className=\"tangle-lines__error\" role=\"alert\">\n <span>{error}</span>\n {(members === null || refreshFailed) && <button type=\"button\" disabled={busy !== null} onClick={() => void retry()}>Retry</button>}\n </div>}\n {members === null ? !error && <p className=\"tangle-lines__muted\" role=\"status\">Loading members…</p> : <div className=\"tangle-lines__list\">\n {members.length === 0 && <p className=\"tangle-lines__empty\">{canAdd ? 'No members yet. Invite an address that you own or have permission to add.' : 'No members yet.'}</p>}\n {members.map(member => {\n const lastOwner = member.role === 'owner' && activeOwners <= 1\n const editable = canManage && member.status !== 'removed' && (!lastOwner || allowRemoveLastOwner)\n return <div className=\"tangle-lines__row\" key={member.id}>\n <div className=\"tangle-lines__row-main\">\n <span className={`tangle-lines__state tangle-lines__state--${member.status}`}>{STATUS[member.status].label}</span>\n <strong>{member.label || member.address}</strong>\n {member.label && <p>{member.address}</p>}\n <p>{STATUS[member.status].detail}</p>\n </div>\n <div className=\"tangle-lines__row-actions\">\n {editable ? <>\n {allowRoleChange && !lastOwner ? <label className=\"tangle-lines__compact-label\">Role\n <select value={member.role} disabled={busy !== null || refreshFailed} onChange={event => void mutate(member.id, () => clientRef.current.update(lineId, member.id, { role: event.target.value }), 'Role updated.')}>\n {!roles.some(item => item.value === member.role) && <option value={member.role}>{member.role}</option>}\n {roles.map(item => <option key={item.value} value={item.value}>{item.label}{item.tools === 'chat' ? ' · chat only' : ''}</option>)}\n </select>\n </label> : <span className=\"tangle-lines__role\">{roles.find(item => item.value === member.role)?.label ?? member.role}</span>}\n {confirmId === member.id ? <div className=\"tangle-lines__confirm\" role=\"group\" aria-label={`Remove ${member.label || member.address}?`}>\n <span>Remove {member.label || member.address}?</span>\n <button ref={confirmButton} type=\"button\" className=\"tangle-lines__danger\" disabled={busy !== null || refreshFailed} onClick={() => void mutate(member.id, () => clientRef.current.remove(lineId, member.id), 'Member removed.', () => closeConfirmation(member.id))}>Remove</button>\n <button type=\"button\" disabled={busy !== null} onClick={() => closeConfirmation(member.id)}>Keep</button>\n </div> : <button ref={node => { if (node) removeTriggers.current.set(member.id, node); else removeTriggers.current.delete(member.id) }} type=\"button\" className=\"tangle-lines__quiet\" disabled={busy !== null || refreshFailed} onClick={() => setConfirmId(member.id)}>Remove</button>}\n </> : <span className=\"tangle-lines__role\">{roles.find(item => item.value === member.role)?.label ?? member.role}</span>}\n </div>\n </div>\n })}\n </div>}\n\n {canManage && canAdd && members !== null && (maxMembers === undefined || activeMembers < maxMembers) && <div className=\"tangle-lines__setup\">\n <h3>Invite a member</h3>\n <p>Hub marks the address as invited. The member confirms by messaging the line.</p>\n <div className=\"tangle-lines__fields\">\n <label>Phone number or email\n <input value={address} onChange={event => setAddress(event.target.value)} autoComplete=\"off\" placeholder=\"+15551234567 or name@example.com\" />\n </label>\n <label>Name (optional)\n <input value={label} onChange={event => setLabel(event.target.value)} placeholder=\"Member name\" />\n </label>\n <label>Role\n <select value={selectedRole} disabled={roles.length === 0} onChange={event => setRole(event.target.value)}>\n {roles.map(item => <option key={item.value} value={item.value}>{item.label}{item.tools === 'chat' ? ' · chat only' : ''}</option>)}\n </select>\n </label>\n </div>\n <button type=\"button\" className=\"tangle-lines__primary\" disabled={busy !== null || refreshFailed || !address.trim() || !selectedRole} onClick={add}>\n {busy === 'add' ? 'Inviting…' : 'Invite member'}\n </button>\n </div>}\n </section>\n}\n","import type { LineBillingProps } from './contracts'\n\nfunction resetTime(value: string): string {\n const date = new Date(value)\n return Number.isNaN(date.getTime()) ? value : date.toLocaleString()\n}\n\n/** Read-only billing facts from the line attachment and Hub allowance status. */\nexport function LineBilling({ view }: LineBillingProps) {\n return <section className=\"tangle-lines\" aria-label=\"Line billing\">\n <header className=\"tangle-lines__heading\">\n <div><h2>Billing</h2><p>{view.lineAddress}</p></div>\n </header>\n <dl className=\"tangle-lines__billing\">\n <div>\n <dt>Line</dt>\n <dd>{view.linePayer.kind === 'workspace' ? view.linePayer.label : 'Payer not verified'}</dd>\n {view.linePayer.kind === 'workspace' && <dd className=\"tangle-lines__billing-detail\">Charged to {view.workspaceName}.</dd>}\n </div>\n <div>\n <dt>Agent turns</dt>\n <dd>{view.turnPayer.kind === 'unverified' ? 'Payer not verified' : view.turnPayer.label}</dd>\n {view.turnPayer.kind === 'member' && <dd className=\"tangle-lines__billing-detail\">Each member pays for their own admitted turns.</dd>}\n </div>\n <div>\n <dt>Allowance</dt>\n {view.allowance ? <>\n <dd>{view.allowance.turnsPerMemberPerDay} turns per member each day</dd>\n {view.allowance.used !== undefined && view.allowance.limit !== undefined &&\n <dd className=\"tangle-lines__billing-detail\">{view.allowance.used} of {view.allowance.limit} turns used{view.allowance.resetsAt ? ` · resets ${resetTime(view.allowance.resetsAt)}` : ''}</dd>}\n </> : <dd>No allowance reported</dd>}\n </div>\n </dl>\n </section>\n}\n","import { useMemo, useState } from 'react'\nimport { LineSetup } from './LineSetup'\nimport type { LineConnectInput, LineSetupClient, LineSetupProps } from './contracts'\n\nexport interface ApplicationLineConnectInput extends LineConnectInput {\n operatorAddress: string\n turnsPerDay: number\n}\nexport interface ApplicationLineSetupClient extends Omit<LineSetupClient, 'connect'> {\n connect(input: ApplicationLineConnectInput): Promise<void>\n}\nexport interface ApplicationLineSetupProps extends Omit<LineSetupProps, 'client' | 'canConnect'> {\n client: ApplicationLineSetupClient\n /** Disable new grants without preventing disconnection of an existing line. */\n enabled: boolean\n}\n\n/** Nominate a sender explicitly, then use the existing connection and disconnect UI. */\nexport function ApplicationLineSetup(props: ApplicationLineSetupProps) {\n return <ApplicationLineSetupScope key={props.scopeKey} {...props} />\n}\n\nfunction ApplicationLineSetupScope({ client, enabled, ...props }: ApplicationLineSetupProps) {\n const [operatorAddress, setAddress] = useState('')\n const [limit, setLimit] = useState('20')\n const [approved, setApproved] = useState<string | null>(null)\n const address = operatorAddress.trim()\n const turnsPerDay = Number(limit)\n const nomination = JSON.stringify({ address, turnsPerDay })\n const valid = address.length <= 320 && (/^\\+[1-9]\\d{6,14}$/.test(address) || /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(address))\n && Number.isSafeInteger(turnsPerDay) && turnsPerDay >= 1 && turnsPerDay <= 10_000\n const canConnect = props.canManage && enabled && valid && approved === nomination\n const lineClient = useMemo<LineSetupClient>(() => ({\n load: () => client.load(),\n disconnect: (id, expectedAttachmentId) => client.disconnect(id, expectedAttachmentId),\n connect: input => {\n if (!canConnect) throw new Error('Confirm the sender and daily limit before connecting')\n return client.connect({ ...input, operatorAddress: address, turnsPerDay })\n },\n }), [client, canConnect, address, turnsPerDay])\n return <>\n {props.canManage && <section className=\"tangle-lines tangle-lines--application\" aria-label=\"Application access\">\n <header className=\"tangle-lines__application-heading\">\n <h2>Text your workspace</h2>\n <p>Continue a conversation from a number or mailbox you own. The agent keeps the same context and saved work.</p>\n </header>\n {!enabled ? <div className=\"tangle-lines__notice\" role=\"status\">\n <strong>New connections are disabled</strong>\n <p>You can still review and disconnect an existing line below.</p>\n </div> : <div className=\"tangle-lines__authorization\">\n <div className=\"tangle-lines__authorization-heading\">\n <h3>Authorize a sender</h3>\n <p>Only this sender can issue commands through the line you connect.</p>\n </div>\n <div className=\"tangle-lines__fields\">\n <label>Authorized sender\n <input value={operatorAddress} onChange={e => { setAddress(e.target.value); setApproved(null) }}\n autoComplete=\"off\" placeholder=\"+15550100001 or your Apple ID / email\" />\n </label>\n <label>Maximum messages per day\n <input type=\"number\" min={1} max={10_000} step={1} value={limit}\n onChange={e => { setLimit(e.target.value); setApproved(null) }} />\n </label>\n </div>\n <label className=\"tangle-lines__delegation\">\n <input type=\"checkbox\" checked={approved === nomination} disabled={!valid}\n onChange={e => setApproved(e.target.checked ? nomination : null)} />\n I authorize this sender to work in the conversation I select below using my application access and compute budget.\n </label>\n <p className=\"tangle-lines__fine-print\">The daily message limit is not a dollar cap. The first inbound message establishes messaging consent.\n STOP stops replies, not an already accepted task; cancel that task in the application.</p>\n </div>}\n </section>}\n <LineSetup {...props} targetLabel={props.targetLabel ?? 'Conversation'} client={lineClient} canConnect={canConnect} showConnectionSetup={enabled} />\n </>\n}\n"],"mappings":"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","names":["occupied","line","useEffect","useLayoutEffect","useRef","useState","Fragment","jsx","jsxs","useBrowserLayoutEffect","Fragment","jsx","jsxs","useState","Fragment","jsx","jsxs","useState"]}
1
+ {"version":3,"sources":["../../../src/hosted-agent/react/LineSetup.tsx","../../../src/hosted-agent/react/LineMembers.tsx","../../../src/hosted-agent/react/LineBilling.tsx","../../../src/hosted-agent/react/ApplicationLineSetup.tsx"],"sourcesContent":["import { useEffect, useLayoutEffect, useRef, useState } from 'react'\nimport type { Line } from '@tangle-network/sandbox'\nimport type {\n LineBoxMode, LineConnectionOption, LineIdentityKind, LineIdentityOption,\n LineSetupLine, LineSetupProps, LineSetupSnapshot,\n} from './contracts'\n\nconst useBrowserLayoutEffect = typeof document !== 'undefined' ? useLayoutEffect : useEffect\n\nconst TRANSPORT: Record<Line['transport'], string> = {\n imessage: 'iMessage', sms: 'SMS', whatsapp: 'WhatsApp', email: 'Email',\n}\nconst IDENTITY: Record<LineIdentityKind, string> = {\n handle: 'Inkbox handle', number: 'Dedicated number', email: 'Email line',\n}\n\ntype Choice = { key: string; connection: LineConnectionOption; identity: LineIdentityOption }\n\nfunction message(error: unknown): string {\n return error instanceof Error ? error.message : 'The line request failed. Try again.'\n}\n\nfunction dateTime(value: string): string {\n const date = new Date(value)\n return Number.isNaN(date.getTime()) ? value : date.toLocaleString()\n}\n\nfunction choicesFor(snapshot: LineSetupSnapshot): Choice[] {\n return (snapshot.connections ?? []).flatMap(connection => connection.identities.map((identity, index) => ({\n key: `${connection.id}:${index}`,\n connection,\n identity,\n })))\n}\n\nfunction canOfferReconnect(line: LineSetupLine, choice: Choice): boolean {\n if (line.connectionId !== choice.connection.id || line.transport !== choice.identity.transport || line.targetId !== null) return false\n if (line.providerNumberId === null) return line.transport !== 'whatsapp' && !choice.identity.phoneNumberId && !choice.identity.requiresPhoneNumberId\n return choice.identity.phoneNumberId === line.providerNumberId ||\n (!choice.identity.phoneNumberId && choice.identity.requiresPhoneNumberId === true)\n}\n\nfunction matchesLineIdentity(line: LineSetupLine, identity: LineIdentityOption, numberId: string): boolean {\n if (line.transport !== identity.transport) return false\n if (line.providerNumberId === null) return line.transport !== 'whatsapp' && !identity.phoneNumberId && !identity.requiresPhoneNumberId\n return numberId === line.providerNumberId\n}\n\n/** Set up an owned identity through a host route backed by sandbox.lines and Hub. */\nexport function LineSetup({ client, scopeKey, initialTargetId, targetLabel, canManage, canConnect = canManage, showConnectionSetup = true, onNotice }: LineSetupProps) {\n const clientRef = useRef(client)\n clientRef.current = client\n const sequence = useRef(0)\n const incarnation = useRef(0)\n const confirmButton = useRef<HTMLButtonElement>(null)\n const heading = useRef<HTMLHeadingElement>(null)\n const disconnectTriggers = useRef(new Map<string, HTMLButtonElement>())\n const restoreFocusTo = useRef<string | null>(null)\n useBrowserLayoutEffect(() => {\n incarnation.current++\n return () => { incarnation.current++ }\n }, [scopeKey, initialTargetId])\n const [loadedSnapshot, setLoadedSnapshot] = useState<{ scopeKey: string; initialTargetId: string | undefined; value: LineSetupSnapshot } | null>(null)\n const snapshot = loadedSnapshot?.scopeKey === scopeKey && loadedSnapshot.initialTargetId === initialTargetId ? loadedSnapshot.value : null\n const [loading, setLoading] = useState(true)\n const [refreshFailed, setRefreshFailed] = useState(false)\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [kind, setKind] = useState<LineIdentityKind>('handle')\n const [choiceKey, setChoiceKey] = useState('')\n const [targetId, setTargetId] = useState(initialTargetId ?? '')\n const [boxMode, setBoxMode] = useState<LineBoxMode>('per-member')\n const [phoneNumberId, setPhoneNumberId] = useState('')\n const [confirmation, setConfirmation] = useState<{ lineId: string; attachmentId: string | undefined } | null>(null)\n const confirmLineId = confirmation?.lineId ?? null\n\n function stillCurrent(requestIncarnation: number): boolean {\n return requestIncarnation === incarnation.current\n }\n\n async function reload(requestIncarnation: number): Promise<LineSetupSnapshot | null> {\n const request = ++sequence.current\n try {\n const next = await clientRef.current.load()\n if (request !== sequence.current || !stillCurrent(requestIncarnation)) return null\n setLoadedSnapshot({ scopeKey, initialTargetId, value: next })\n setError(null)\n setRefreshFailed(false)\n setTargetId(current => next.targets.some(target => target.id === current)\n ? current : next.targets.find(target => target.id === initialTargetId)?.id ?? next.targets[0]?.id ?? '')\n setLoading(false)\n return next\n } catch (cause) {\n if (request !== sequence.current || !stillCurrent(requestIncarnation)) return null\n setError(message(cause))\n setRefreshFailed(true)\n setLoading(false)\n return null\n }\n }\n\n function retry() {\n if (loading) return\n setLoading(true)\n void reload(incarnation.current)\n }\n\n function closeConfirmation(lineId: string) {\n restoreFocusTo.current = lineId\n setConfirmation(null)\n }\n\n useEffect(() => {\n setLoading(true)\n setLoadedSnapshot(null)\n setError(null)\n setRefreshFailed(false)\n setBusy(false)\n setKind('handle')\n setChoiceKey('')\n setTargetId(initialTargetId ?? '')\n setBoxMode('per-member')\n setPhoneNumberId('')\n setConfirmation(null)\n restoreFocusTo.current = null\n void reload(incarnation.current)\n return () => { sequence.current++ }\n }, [scopeKey, initialTargetId])\n\n useEffect(() => {\n if (confirmLineId) confirmButton.current?.focus()\n }, [confirmLineId])\n\n useEffect(() => {\n const lineId = restoreFocusTo.current\n if (confirmLineId !== null || lineId === null) return\n restoreFocusTo.current = null\n const trigger = disconnectTriggers.current.get(lineId)\n if (trigger && !trigger.disabled) trigger.focus()\n else heading.current?.focus()\n }, [confirmLineId, snapshot, refreshFailed])\n\n const allChoices = snapshot ? choicesFor(snapshot) : []\n const choices = snapshot ? allChoices.filter(choice => {\n const occupied = snapshot.lines.filter(line => line.status !== 'released' && line.transport === choice.identity.transport)\n const [line] = occupied\n return occupied.length === 0 || (occupied.length === 1 && line !== undefined && canOfferReconnect(line, choice))\n }) : []\n const availableKinds = (['handle', 'number', 'email'] as const).filter(value => choices.some(choice => choice.identity.kind === value))\n const selectedKind = availableKinds.includes(kind) ? kind : availableKinds[0]\n const kindChoices = choices.filter(choice => choice.identity.kind === selectedKind)\n const selected = kindChoices.find(choice => choice.key === choiceKey) ?? kindChoices[0]\n const selectedTarget = snapshot?.targets.find(target => target.id === targetId)\n const selectedMode = selectedTarget?.modes.includes(boxMode) ? boxMode : selectedTarget?.modes[0]\n const enteredNumber = selected?.identity.phoneNumberId ?? phoneNumberId.trim()\n const needsNumber = selected?.identity.transport === 'whatsapp' || selected?.identity.requiresPhoneNumberId\n const occupied = selected && snapshot?.lines.filter(line => line.status !== 'released' && line.transport === selected.identity.transport)\n const [occupiedLine] = occupied || []\n const reconnectChoice = Boolean(selected && occupied?.length === 1 && occupiedLine && canOfferReconnect(occupiedLine, selected))\n const reconnecting = Boolean(reconnectChoice && selected && occupiedLine &&\n matchesLineIdentity(occupiedLine, selected.identity, enteredNumber))\n const blockedByExistingLine = Boolean(occupied?.length && !reconnecting)\n const answeringCount = snapshot?.lines.filter(line => line.answering).length ?? 0\n\n async function connect() {\n if (!canManage || !canConnect || !selected || !selectedTarget || !selectedMode || (needsNumber && !enteredNumber) || blockedByExistingLine || busy || loading || refreshFailed) return\n const requestIncarnation = incarnation.current\n setBusy(true)\n setError(null)\n try {\n await clientRef.current.connect({\n connectionId: selected.connection.id,\n transport: selected.identity.transport,\n ...(enteredNumber ? { phoneNumberId: enteredNumber } : {}),\n targetId: selectedTarget.id,\n boxMode: selectedMode,\n })\n if (!stillCurrent(requestIncarnation)) return\n const updated = await reload(requestIncarnation)\n if (!stillCurrent(requestIncarnation)) return\n if (!updated) {\n onNotice?.({ kind: 'error', message: 'Line connected, but its current status could not be loaded.' })\n return\n }\n const line = updated.lines.find(item => item.status !== 'released' && item.connectionId === selected.connection.id &&\n item.transport === selected.identity.transport && item.providerNumberId === (enteredNumber || null))\n onNotice?.({ kind: 'success', message: line?.answering ? 'The line is answering.' : 'Line connected. Add a member to start answers.' })\n } catch (cause) {\n if (!stillCurrent(requestIncarnation)) return\n const detail = message(cause)\n setError(detail)\n onNotice?.({ kind: 'error', message: detail })\n } finally {\n if (stillCurrent(requestIncarnation)) setBusy(false)\n }\n }\n\n async function disconnect() {\n if (!confirmation || busy || loading || refreshFailed) return\n const { lineId, attachmentId: expectedAttachmentId } = confirmation\n const requestIncarnation = incarnation.current\n setBusy(true)\n setError(null)\n try {\n await clientRef.current.disconnect(lineId, expectedAttachmentId)\n if (!stillCurrent(requestIncarnation)) return\n const updated = await reload(requestIncarnation)\n if (!stillCurrent(requestIncarnation)) return\n closeConfirmation(lineId)\n onNotice?.(updated\n ? { kind: 'success', message: 'The line stopped answering.' }\n : { kind: 'error', message: 'Line disconnected, but its current status could not be loaded.' })\n } catch (cause) {\n if (!stillCurrent(requestIncarnation)) return\n const detail = message(cause)\n setError(detail)\n onNotice?.({ kind: 'error', message: detail })\n } finally {\n if (stillCurrent(requestIncarnation)) setBusy(false)\n }\n }\n\n return <section className=\"tangle-lines\" aria-label=\"Agent lines\">\n <header className=\"tangle-lines__heading\">\n <div>\n <h2 ref={heading} tabIndex={-1}>Lines</h2>\n {snapshot && <p>{snapshot.workspaceName} can use one line per transport.</p>}\n </div>\n {answeringCount > 1 && <span className=\"tangle-lines__count\">{answeringCount} answering</span>}\n </header>\n\n {error && <div className=\"tangle-lines__error\" role=\"alert\">\n <div><strong>{refreshFailed ? 'Lines are unavailable' : 'Line action failed'}</strong><p>{error}</p></div>\n {(!snapshot || refreshFailed) && <button type=\"button\" disabled={loading} onClick={retry}>Retry</button>}\n </div>}\n {loading && <p className=\"tangle-lines__muted\" role=\"status\">Loading lines…</p>}\n\n {snapshot && <>\n <div className=\"tangle-lines__list\">\n {snapshot.lines.filter(line => line.status !== 'released').length === 0 &&\n <div className=\"tangle-lines__empty\"><strong>No lines connected</strong><p>{canManage && showConnectionSetup\n ? 'Connect an owned identity below to let this workspace answer messages.'\n : 'There are no connected lines in this workspace.'}</p></div>}\n {snapshot.lines.filter(line => line.status !== 'released').map(line =>\n <div className=\"tangle-lines__row\" key={line.id}>\n <div className=\"tangle-lines__row-main\">\n <div className=\"tangle-lines__row-heading\"><span className=\"tangle-lines__transport\">{TRANSPORT[line.transport]}</span><span className={`tangle-lines__status${line.answering ? ' tangle-lines__status--answering' : ''}`}>{line.answering ? 'Answering' : line.targetId === null ? 'Disconnected' : line.status === 'active' ? 'Awaiting member' : line.status}</span></div>\n <strong>{line.routerAddress ?? line.address}</strong>\n {line.connect && line.targetId !== null && <p>To reach this agent, text <code>{line.connect}</code>.</p>}\n <p>{line.targetLabel ?? 'No agent or box assigned'}{line.boxMode && ` · ${line.boxMode === 'per-member' ? 'one box per member' : 'shared box'}`}</p>\n {line.lastTurn.kind === 'latest' ? <p>Last turn: {line.lastTurn.status} · {dateTime(line.lastTurn.at)}</p>\n : <p>{line.lastTurn.kind === 'none' ? 'No turns yet.' : 'Turn history unavailable.'}</p>}\n </div>\n {canManage && line.canDisconnect && line.targetId !== null && line.status === 'active' && <div className=\"tangle-lines__row-actions\">\n {confirmLineId === line.id ? <div className=\"tangle-lines__confirm\" role=\"group\" aria-label={`Disconnect ${line.address}?`}>\n <span>Disconnect this line?</span>\n <button ref={confirmButton} type=\"button\" className=\"tangle-lines__danger\" disabled={busy || loading || refreshFailed} onClick={() => void disconnect()}>Disconnect</button>\n <button type=\"button\" disabled={busy} onClick={() => closeConfirmation(line.id)}>Keep line</button>\n </div> : <button ref={node => { if (node) disconnectTriggers.current.set(line.id, node); else disconnectTriggers.current.delete(line.id) }} type=\"button\" className=\"tangle-lines__quiet\" disabled={busy || loading || refreshFailed} onClick={() => setConfirmation({ lineId: line.id, attachmentId: line.attachmentId ?? undefined })}>Disconnect line</button>}\n </div>}\n </div>)}\n </div>\n\n {canManage && showConnectionSetup && (snapshot.connections === null || choices.length > 0 || allChoices.length === 0) && <div className=\"tangle-lines__setup\">\n <span className=\"tangle-lines__overline\">New line</span>\n <h3>Connect an identity you own</h3>\n <p>Choose an identity already connected in Hub. Billing details appear below.</p>\n {snapshot.connections === null ? <div className=\"tangle-lines__error\" role=\"status\">\n <span>Hub connections could not be read. Check Hub access and try again.</span>\n <button type=\"button\" disabled={loading} onClick={retry}>Retry</button>\n </div>\n : availableKinds.length === 0 ? <p className=\"tangle-lines__empty\">\n Connect an owned handle, number, or mailbox in Hub, then <button type=\"button\" disabled={loading} onClick={retry}>reload</button>.\n </p>\n : <>\n <div className=\"tangle-lines__kinds\" role=\"group\" aria-label=\"Identity type\">\n {availableKinds.map(value => <button key={value} type=\"button\" aria-pressed={selectedKind === value} onClick={() => { setKind(value); setChoiceKey(''); setPhoneNumberId('') }}>{IDENTITY[value]}</button>)}\n </div>\n <div className=\"tangle-lines__fields\">\n <label>Owned connection\n <select value={selected?.key ?? ''} onChange={event => { setChoiceKey(event.target.value); setPhoneNumberId('') }}>\n {kindChoices.map(choice => <option key={choice.key} value={choice.key}>{choice.connection.label} · {choice.identity.label}</option>)}\n </select>\n </label>\n <label>{targetLabel ?? 'Agent or box'}\n <select value={selectedTarget?.id ?? ''} onChange={event => setTargetId(event.target.value)}>\n {snapshot.targets.map(target => <option key={target.id} value={target.id}>{target.label}{targetLabel ? '' : ` · ${target.kind}`}</option>)}\n </select>\n </label>\n {selectedTarget && selectedTarget.modes.length > 1 && <fieldset>\n <legend>Conversation space</legend>\n <label><input type=\"radio\" name={`line-box-mode-${scopeKey}`} value=\"per-member\" checked={selectedMode === 'per-member'} disabled={!selectedTarget?.modes.includes('per-member')} onChange={() => setBoxMode('per-member')} /> One box per member</label>\n <label><input type=\"radio\" name={`line-box-mode-${scopeKey}`} value=\"shared\" checked={selectedMode === 'shared'} disabled={!selectedTarget?.modes.includes('shared')} onChange={() => setBoxMode('shared')} /> Shared box for a team</label>\n </fieldset>}\n {needsNumber && !selected?.identity.phoneNumberId && <label>Existing provider number ID\n <input value={phoneNumberId} onChange={event => setPhoneNumberId(event.target.value)} autoComplete=\"off\" placeholder=\"Number ID from Hub\" />\n </label>}\n </div>\n {reconnectChoice && blockedByExistingLine && <p className=\"tangle-lines__warning\">Enter this line's current provider number ID to reconnect.</p>}\n <button className=\"tangle-lines__primary\" type=\"button\" disabled={!canConnect || busy || loading || refreshFailed || !selected || !selectedTarget || !selectedMode || (needsNumber && !enteredNumber) || blockedByExistingLine} onClick={() => void connect()}>\n {busy ? (reconnectChoice ? 'Reconnecting…' : 'Connecting…') : `${reconnectChoice ? 'Reconnect' : 'Connect'} ${selected ? TRANSPORT[selected.identity.transport] : 'line'}`}\n </button>\n </>}\n </div>}\n </>}\n </section>\n}\n","import { useEffect, useLayoutEffect, useRef, useState } from 'react'\nimport type { LineMember } from '@tangle-network/sandbox'\nimport type { LineMembersProps } from './contracts'\n\nconst useBrowserLayoutEffect = typeof document !== 'undefined' ? useLayoutEffect : useEffect\n\nconst STATUS: Record<LineMember['status'], { label: string; detail: string }> = {\n invited: { label: 'Awaiting consent', detail: 'The first message from this address confirms consent.' },\n active: { label: 'Consented', detail: 'This member has sent a message to the line.' },\n stopped: { label: 'Stopped', detail: 'The member texted STOP. Only a message from them with START resumes replies.' },\n removed: { label: 'Removed', detail: 'This address no longer has access to the line.' },\n}\n\nfunction errorMessage(cause: unknown): string {\n return cause instanceof Error ? cause.message : 'The member request failed. Try again.'\n}\n\n/** Manage Hub line members while keeping consent and STOP authority with the sender. */\nexport function LineMembers({ lineId, scopeKey, client, roles, canManage, canAdd = true, maxMembers, allowRoleChange = true, allowRemoveLastOwner = false, onNotice }: LineMembersProps) {\n const clientRef = useRef(client)\n clientRef.current = client\n const sequence = useRef(0)\n const incarnation = useRef(0)\n const confirmButton = useRef<HTMLButtonElement>(null)\n const heading = useRef<HTMLHeadingElement>(null)\n const removeTriggers = useRef(new Map<string, HTMLButtonElement>())\n const restoreFocusTo = useRef<string | null>(null)\n useBrowserLayoutEffect(() => {\n incarnation.current++\n return () => { incarnation.current++ }\n }, [lineId, scopeKey])\n const [memberSnapshot, setMemberSnapshot] = useState<{ lineId: string; scopeKey: string; members: LineMember[] } | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [refreshFailed, setRefreshFailed] = useState(false)\n const [address, setAddress] = useState('')\n const [label, setLabel] = useState('')\n const [role, setRole] = useState('member')\n const [busy, setBusy] = useState<string | null>(null)\n const [confirmId, setConfirmId] = useState<string | null>(null)\n const members = memberSnapshot?.lineId === lineId && memberSnapshot.scopeKey === scopeKey ? memberSnapshot.members : null\n\n function stillCurrent(requestIncarnation: number): boolean {\n return requestIncarnation === incarnation.current\n }\n\n async function reload(requestIncarnation: number): Promise<boolean> {\n const request = ++sequence.current\n try {\n const next = await clientRef.current.list(lineId)\n if (request !== sequence.current || !stillCurrent(requestIncarnation)) return false\n setMemberSnapshot({ lineId, scopeKey, members: next })\n setError(null)\n setRefreshFailed(false)\n return true\n } catch (cause) {\n if (request !== sequence.current || !stillCurrent(requestIncarnation)) return false\n setError(errorMessage(cause))\n setRefreshFailed(true)\n return false\n }\n }\n\n async function retry() {\n if (busy) return\n const requestIncarnation = incarnation.current\n setBusy('refresh')\n try { await reload(requestIncarnation) }\n finally { if (stillCurrent(requestIncarnation)) setBusy(null) }\n }\n\n function closeConfirmation(memberId: string) {\n restoreFocusTo.current = memberId\n setConfirmId(null)\n }\n\n useEffect(() => {\n setMemberSnapshot(null)\n setError(null)\n setRefreshFailed(false)\n setAddress('')\n setLabel('')\n setRole('member')\n setConfirmId(null)\n restoreFocusTo.current = null\n setBusy(null)\n void reload(incarnation.current)\n return () => { sequence.current++ }\n }, [lineId, scopeKey])\n\n useEffect(() => {\n if (confirmId) confirmButton.current?.focus()\n }, [confirmId])\n\n useEffect(() => {\n const memberId = restoreFocusTo.current\n if (confirmId !== null || memberId === null) return\n restoreFocusTo.current = null\n const trigger = removeTriggers.current.get(memberId)\n if (trigger && !trigger.disabled) trigger.focus()\n else heading.current?.focus()\n }, [confirmId, members, refreshFailed])\n\n const selectedRole = roles.some(item => item.value === role) ? role : roles.find(item => item.value === 'member')?.value ?? roles[0]?.value ?? ''\n const activeMembers = members?.filter(member => member.status !== 'removed').length ?? 0\n const activeOwners = members?.filter(member => member.role === 'owner' && member.status !== 'removed').length ?? 0\n\n async function mutate(key: string, action: () => Promise<void>, success: string, onSuccess?: () => void) {\n if (busy || refreshFailed) return\n const requestIncarnation = incarnation.current\n setBusy(key)\n setError(null)\n try {\n await action()\n if (!stillCurrent(requestIncarnation)) return\n const refreshed = await reload(requestIncarnation)\n if (!stillCurrent(requestIncarnation)) return\n onSuccess?.()\n onNotice?.(refreshed\n ? { kind: 'success', message: success }\n : { kind: 'error', message: 'Member updated, but the current member list could not be loaded.' })\n } catch (cause) {\n if (!stillCurrent(requestIncarnation)) return\n const detail = errorMessage(cause)\n setError(detail)\n onNotice?.({ kind: 'error', message: detail })\n } finally {\n if (stillCurrent(requestIncarnation)) setBusy(null)\n }\n }\n\n function add() {\n const trimmed = address.trim()\n if (!trimmed || !selectedRole || members === null || (maxMembers !== undefined && activeMembers >= maxMembers)) return\n void mutate('add', () => clientRef.current.add(lineId, { address: trimmed, role: selectedRole, ...(label.trim() ? { label: label.trim() } : {}) }), 'Member invited. Their first message confirms consent.', () => {\n setAddress('')\n setLabel('')\n })\n }\n\n return <section className=\"tangle-lines\" aria-label=\"Line members\">\n <header className=\"tangle-lines__heading\">\n <div><h2 ref={heading} tabIndex={-1}>Members</h2><p>Each address controls its own consent and STOP state.</p></div>\n {members && <span className=\"tangle-lines__count\">{activeMembers} {activeMembers === 1 ? 'member' : 'members'}</span>}\n </header>\n {error && <div className=\"tangle-lines__error\" role=\"alert\">\n <span>{error}</span>\n {(members === null || refreshFailed) && <button type=\"button\" disabled={busy !== null} onClick={() => void retry()}>Retry</button>}\n </div>}\n {members === null ? !error && <p className=\"tangle-lines__muted\" role=\"status\">Loading members…</p> : <div className=\"tangle-lines__list\">\n {members.length === 0 && <p className=\"tangle-lines__empty\">{canAdd ? 'No members yet. Invite an address that you own or have permission to add.' : 'No members yet.'}</p>}\n {members.map(member => {\n const lastOwner = member.role === 'owner' && activeOwners <= 1\n const editable = canManage && member.status !== 'removed' && (!lastOwner || allowRemoveLastOwner)\n return <div className=\"tangle-lines__row\" key={member.id}>\n <div className=\"tangle-lines__row-main\">\n <span className={`tangle-lines__state tangle-lines__state--${member.status}`}>{STATUS[member.status].label}</span>\n <strong>{member.label || member.address}</strong>\n {member.label && <p>{member.address}</p>}\n <p>{STATUS[member.status].detail}</p>\n </div>\n <div className=\"tangle-lines__row-actions\">\n {editable ? <>\n {allowRoleChange && !lastOwner ? <label className=\"tangle-lines__compact-label\">Role\n <select value={member.role} disabled={busy !== null || refreshFailed} onChange={event => void mutate(member.id, () => clientRef.current.update(lineId, member.id, { role: event.target.value }), 'Role updated.')}>\n {!roles.some(item => item.value === member.role) && <option value={member.role}>{member.role}</option>}\n {roles.map(item => <option key={item.value} value={item.value}>{item.label}{item.tools === 'chat' ? ' · chat only' : ''}</option>)}\n </select>\n </label> : <span className=\"tangle-lines__role\">{roles.find(item => item.value === member.role)?.label ?? member.role}</span>}\n {confirmId === member.id ? <div className=\"tangle-lines__confirm\" role=\"group\" aria-label={`Remove ${member.label || member.address}?`}>\n <span>Remove {member.label || member.address}?</span>\n <button ref={confirmButton} type=\"button\" className=\"tangle-lines__danger\" disabled={busy !== null || refreshFailed} onClick={() => void mutate(member.id, () => clientRef.current.remove(lineId, member.id), 'Member removed.', () => closeConfirmation(member.id))}>Remove</button>\n <button type=\"button\" disabled={busy !== null} onClick={() => closeConfirmation(member.id)}>Keep</button>\n </div> : <button ref={node => { if (node) removeTriggers.current.set(member.id, node); else removeTriggers.current.delete(member.id) }} type=\"button\" className=\"tangle-lines__quiet\" disabled={busy !== null || refreshFailed} onClick={() => setConfirmId(member.id)}>Remove</button>}\n </> : <span className=\"tangle-lines__role\">{roles.find(item => item.value === member.role)?.label ?? member.role}</span>}\n </div>\n </div>\n })}\n </div>}\n\n {canManage && canAdd && members !== null && (maxMembers === undefined || activeMembers < maxMembers) && <div className=\"tangle-lines__setup\">\n <h3>Invite a member</h3>\n <p>Hub marks the address as invited. The member confirms by messaging the line.</p>\n <div className=\"tangle-lines__fields\">\n <label>Phone number or email\n <input value={address} onChange={event => setAddress(event.target.value)} autoComplete=\"off\" placeholder=\"+15551234567 or name@example.com\" />\n </label>\n <label>Name (optional)\n <input value={label} onChange={event => setLabel(event.target.value)} placeholder=\"Member name\" />\n </label>\n <label>Role\n <select value={selectedRole} disabled={roles.length === 0} onChange={event => setRole(event.target.value)}>\n {roles.map(item => <option key={item.value} value={item.value}>{item.label}{item.tools === 'chat' ? ' · chat only' : ''}</option>)}\n </select>\n </label>\n </div>\n <button type=\"button\" className=\"tangle-lines__primary\" disabled={busy !== null || refreshFailed || !address.trim() || !selectedRole} onClick={add}>\n {busy === 'add' ? 'Inviting…' : 'Invite member'}\n </button>\n </div>}\n </section>\n}\n","import type { LineBillingProps } from './contracts'\n\nfunction resetTime(value: string): string {\n const date = new Date(value)\n return Number.isNaN(date.getTime()) ? value : date.toLocaleString()\n}\n\n/** Read-only billing facts from the line attachment and Hub allowance status. */\nexport function LineBilling({ view }: LineBillingProps) {\n return <section className=\"tangle-lines\" aria-label=\"Line billing\">\n <header className=\"tangle-lines__heading\">\n <div><h2>Billing</h2><p>{view.lineAddress}</p></div>\n </header>\n <dl className=\"tangle-lines__billing\">\n <div>\n <dt>Line</dt>\n <dd>{view.linePayer.kind === 'workspace' ? view.linePayer.label : 'Payer not verified'}</dd>\n {view.linePayer.kind === 'workspace' && <dd className=\"tangle-lines__billing-detail\">Charged to {view.workspaceName}.</dd>}\n </div>\n <div>\n <dt>Agent turns</dt>\n <dd>{view.turnPayer.kind === 'unverified' ? 'Payer not verified' : view.turnPayer.label}</dd>\n {view.turnPayer.kind === 'member' && <dd className=\"tangle-lines__billing-detail\">Each member pays for their own admitted turns.</dd>}\n </div>\n <div>\n <dt>Allowance</dt>\n {view.allowance ? <>\n <dd>{view.allowance.turnsPerMemberPerDay} turns per member each day</dd>\n {view.allowance.used !== undefined && view.allowance.limit !== undefined &&\n <dd className=\"tangle-lines__billing-detail\">{view.allowance.used} of {view.allowance.limit} turns used{view.allowance.resetsAt ? ` · resets ${resetTime(view.allowance.resetsAt)}` : ''}</dd>}\n </> : <dd>No allowance reported</dd>}\n </div>\n </dl>\n </section>\n}\n","import { useMemo, useState } from 'react'\nimport { LineSetup } from './LineSetup'\nimport type { LineConnectInput, LineSetupClient, LineSetupProps } from './contracts'\n\nexport interface ApplicationLineConnectInput extends LineConnectInput {\n operatorAddress: string\n turnsPerDay: number\n}\nexport interface ApplicationLineSetupClient extends Omit<LineSetupClient, 'connect'> {\n connect(input: ApplicationLineConnectInput): Promise<void>\n}\nexport interface ApplicationLineSetupProps extends Omit<LineSetupProps, 'client' | 'canConnect'> {\n client: ApplicationLineSetupClient\n /** Disable new grants without preventing disconnection of an existing line. */\n enabled: boolean\n}\n\n/** Nominate a sender explicitly, then use the existing connection and disconnect UI. */\nexport function ApplicationLineSetup(props: ApplicationLineSetupProps) {\n return <ApplicationLineSetupScope key={props.scopeKey} {...props} />\n}\n\nfunction ApplicationLineSetupScope({ client, enabled, ...props }: ApplicationLineSetupProps) {\n const [operatorAddress, setAddress] = useState('')\n const [limit, setLimit] = useState('20')\n const [approved, setApproved] = useState<string | null>(null)\n const address = operatorAddress.trim()\n const turnsPerDay = Number(limit)\n const nomination = JSON.stringify({ address, turnsPerDay })\n const valid = address.length <= 320 && (/^\\+[1-9]\\d{6,14}$/.test(address) || /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(address))\n && Number.isSafeInteger(turnsPerDay) && turnsPerDay >= 1 && turnsPerDay <= 10_000\n const canConnect = props.canManage && enabled && valid && approved === nomination\n const lineClient = useMemo<LineSetupClient>(() => ({\n load: () => client.load(),\n disconnect: (id, expectedAttachmentId) => client.disconnect(id, expectedAttachmentId),\n connect: input => {\n if (!canConnect) throw new Error('Confirm the sender and daily limit before connecting')\n return client.connect({ ...input, operatorAddress: address, turnsPerDay })\n },\n }), [client, canConnect, address, turnsPerDay])\n return <>\n {props.canManage && <section className=\"tangle-lines tangle-lines--application\" aria-label=\"Application access\">\n <header className=\"tangle-lines__application-heading\">\n <h2>Text your workspace</h2>\n <p>Continue a conversation from a number or mailbox you own. The agent keeps the same context and saved work.</p>\n </header>\n {!enabled ? <div className=\"tangle-lines__notice\" role=\"status\">\n <strong>New connections are disabled</strong>\n <p>You can still review and disconnect an existing line below.</p>\n </div> : <div className=\"tangle-lines__authorization\">\n <div className=\"tangle-lines__authorization-heading\">\n <h3>Authorize a sender</h3>\n <p>Only this sender can issue commands through the line you connect.</p>\n </div>\n <div className=\"tangle-lines__fields\">\n <label>Authorized sender\n <input value={operatorAddress} onChange={e => { setAddress(e.target.value); setApproved(null) }}\n autoComplete=\"off\" placeholder=\"+15550100001 or your Apple ID / email\" />\n </label>\n <label>Maximum messages per day\n <input type=\"number\" min={1} max={10_000} step={1} value={limit}\n onChange={e => { setLimit(e.target.value); setApproved(null) }} />\n </label>\n </div>\n <label className=\"tangle-lines__delegation\">\n <input type=\"checkbox\" checked={approved === nomination} disabled={!valid}\n onChange={e => setApproved(e.target.checked ? nomination : null)} />\n I authorize this sender to work in the conversation I select below using my application access and compute budget.\n </label>\n <p className=\"tangle-lines__fine-print\">The daily message limit is not a dollar cap. The first inbound message establishes messaging consent.\n STOP stops replies, not an already accepted task; cancel that task in the application.</p>\n </div>}\n </section>}\n <LineSetup {...props} targetLabel={props.targetLabel ?? 'Conversation'} client={lineClient} canConnect={canConnect} showConnectionSetup={enabled} />\n </>\n}\n"],"mappings":"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","names":["occupied","line","useEffect","useLayoutEffect","useRef","useState","Fragment","jsx","jsxs","useBrowserLayoutEffect","Fragment","jsx","jsxs","useState","Fragment","jsx","jsxs","useState"]}
@@ -99,7 +99,7 @@ import {
99
99
  workspaceSandboxRecoveryMessage,
100
100
  workspaceSandboxRecoveryRecommendedActions,
101
101
  writeProfileFilesToBox
102
- } from "../chunk-GEHULTVU.js";
102
+ } from "../chunk-TFW7OB4L.js";
103
103
  import "../chunk-MCYJON3F.js";
104
104
  import "../chunk-LWSJK546.js";
105
105
  import "../chunk-FZOGDD2E.js";
@@ -73,9 +73,11 @@ export type WorkspaceSandboxRecoveryCode = keyof typeof CODES;
73
73
  declare const ACTIONS: {
74
74
  readonly confirmation_required: {
75
75
  readonly replacementChosen: false;
76
+ readonly canDecide: true;
76
77
  };
77
78
  readonly deletion_declined: {
78
79
  readonly replacementChosen: false;
80
+ readonly canDecide: true;
79
81
  };
80
82
  readonly replacement_authorized: {
81
83
  readonly replacementChosen: false;
@@ -85,27 +87,32 @@ declare const ACTIONS: {
85
87
  };
86
88
  readonly replacement_started: {
87
89
  readonly replacementChosen: true;
90
+ readonly completedAs: 'replacement_completed';
88
91
  };
89
92
  readonly replacement_completed: {
90
93
  readonly replacementChosen: true;
91
94
  };
92
95
  readonly snapshot_replacement_started: {
93
96
  readonly replacementChosen: true;
97
+ readonly completedAs: 'snapshot_replacement_completed';
94
98
  };
95
99
  readonly snapshot_restore_failed: {
96
100
  readonly replacementChosen: true;
101
+ readonly completedAs: 'snapshot_replacement_completed';
97
102
  };
98
103
  readonly snapshot_replacement_completed: {
99
104
  readonly replacementChosen: true;
100
105
  };
101
106
  readonly missing_replacement_started: {
102
107
  readonly replacementChosen: true;
108
+ readonly completedAs: 'missing_replacement_completed';
103
109
  };
104
110
  readonly missing_replacement_completed: {
105
111
  readonly replacementChosen: true;
106
112
  };
107
113
  readonly unrecoverable_replacement_started: {
108
114
  readonly replacementChosen: true;
115
+ readonly completedAs: 'unrecoverable_replacement_completed';
109
116
  };
110
117
  readonly unrecoverable_replacement_completed: {
111
118
  readonly replacementChosen: true;
@@ -120,16 +127,16 @@ export interface WorkspaceSandboxSnapshot {
120
127
  createdAt: string;
121
128
  [key: string]: unknown;
122
129
  }
123
- export interface WorkspaceSandboxSnapshotAssessment {
130
+ export interface WorkspaceSandboxSnapshotAssessment<Snapshot extends WorkspaceSandboxSnapshot = WorkspaceSandboxSnapshot> {
124
131
  availability: WorkspaceSandboxSnapshotAvailability;
125
132
  freshness: WorkspaceSandboxSnapshotFreshness;
126
- snapshot?: WorkspaceSandboxSnapshot;
133
+ snapshot?: Snapshot;
127
134
  }
128
- export interface WorkspaceSandboxRecoveryState {
135
+ export interface WorkspaceSandboxRecoveryState<Snapshot extends WorkspaceSandboxSnapshot = WorkspaceSandboxSnapshot> {
129
136
  code: WorkspaceSandboxRecoveryCode;
130
137
  sandboxId: string;
131
138
  detectedAt: string;
132
- snapshot: WorkspaceSandboxSnapshotAssessment;
139
+ snapshot: WorkspaceSandboxSnapshotAssessment<Snapshot>;
133
140
  action: WorkspaceSandboxRecoveryAction;
134
141
  replacementBoxKey?: string;
135
142
  replacementSandboxId?: string;
@@ -153,7 +160,7 @@ export declare function isWorkspaceSandboxSnapshotRestoreError(error: unknown):
153
160
  * the age bound — a snapshot from a different box restores someone else's
154
161
  * filesystem, which is worse than starting empty.
155
162
  */
156
- export declare function assessWorkspaceSandboxSnapshot(snapshot: WorkspaceSandboxSnapshot | undefined, sandboxId: string, now?: number): WorkspaceSandboxSnapshotAssessment;
163
+ export declare function assessWorkspaceSandboxSnapshot<Snapshot extends WorkspaceSandboxSnapshot>(snapshot: Snapshot | undefined, sandboxId: string, now?: number): WorkspaceSandboxSnapshotAssessment<Snapshot>;
157
164
  export declare function isWorkspaceSandboxRecoveryAction(value: unknown): value is WorkspaceSandboxRecoveryAction;
158
165
  export declare function isWorkspaceSandboxRecoveryCode(value: unknown): value is WorkspaceSandboxRecoveryCode;
159
166
  export declare function isWorkspaceSandboxRecoveryState(value: unknown): value is WorkspaceSandboxRecoveryState;
@@ -175,40 +182,33 @@ export declare function workspaceSandboxRecoveryDiagnostic(recovery: WorkspaceSa
175
182
  export declare function preferredWorkspaceSandboxRecoveryBoxKey(recovery: WorkspaceSandboxRecoveryState | undefined): string | undefined;
176
183
  /** Whether the replacement should be restored from the old box's snapshot. */
177
184
  export declare function shouldRestoreWorkspaceSandboxRecovery(recovery: WorkspaceSandboxRecoveryState | undefined): boolean;
178
- /**
179
- * Where an app keeps recovery state. One row per workspace, last write wins —
180
- * a recovery is a current situation, not a history.
181
- */
182
- export interface WorkspaceSandboxRecoveryStore {
183
- read: (workspaceId: string) => Promise<WorkspaceSandboxRecoveryState | undefined>;
184
- write: (workspaceId: string, recovery: WorkspaceSandboxRecoveryState) => Promise<void>;
185
+ /** One current recovery per workspace, stored by the application.
186
+ * Concurrent writers should supply compareAndSet. Legacy write-only stores
187
+ * remain supported but must serialize decisions and completion themselves. */
188
+ export interface WorkspaceSandboxRecoveryStore<Snapshot extends WorkspaceSandboxSnapshot = WorkspaceSandboxSnapshot> {
189
+ read: (workspaceId: string) => Promise<WorkspaceSandboxRecoveryState<Snapshot> | undefined>;
190
+ write: (workspaceId: string, recovery: WorkspaceSandboxRecoveryState<Snapshot>) => Promise<void>;
191
+ /** Commit a transition only while the exact recovery read above remains current. */
192
+ compareAndSet?: (workspaceId: string, expected: WorkspaceSandboxRecoveryState<Snapshot>, recovery: WorkspaceSandboxRecoveryState<Snapshot>) => Promise<boolean>;
185
193
  }
186
- export interface WorkspaceSandboxRecoveryManager {
187
- read: (workspaceId: string) => Promise<WorkspaceSandboxRecoveryState | undefined>;
188
- record: (workspaceId: string, recovery: WorkspaceSandboxRecoveryState) => Promise<void>;
189
- /** Record an owner's decision. Returns undefined when the stored recovery does
190
- * not name this sandbox — a decision about a box that has already been
191
- * replaced must not resurrect it. */
194
+ export interface WorkspaceSandboxRecoveryManager<Snapshot extends WorkspaceSandboxSnapshot = WorkspaceSandboxSnapshot> {
195
+ read: WorkspaceSandboxRecoveryStore<Snapshot>['read'];
196
+ record: WorkspaceSandboxRecoveryStore<Snapshot>['write'];
197
+ /** Only a pending/declined recovery for this sandbox accepts a new decision. */
192
198
  decide: (args: {
193
199
  workspaceId: string;
194
200
  sandboxId: string;
195
201
  decision: WorkspaceSandboxRecoveryDecision;
196
202
  replacementBoxKey?: string;
197
- }) => Promise<WorkspaceSandboxRecoveryState | undefined>;
198
- /** Mark a replacement finished and name the box that took over. */
203
+ }) => Promise<WorkspaceSandboxRecoveryState<Snapshot> | undefined>;
204
+ /** Only a started replacement with a chosen key may be completed. */
199
205
  complete: (args: {
200
206
  workspaceId: string;
201
207
  replacementSandboxId: string;
202
- }) => Promise<WorkspaceSandboxRecoveryState | undefined>;
208
+ }) => Promise<WorkspaceSandboxRecoveryState<Snapshot> | undefined>;
203
209
  }
204
- /**
205
- * Bind the recovery bookkeeping to an app's storage.
206
- *
207
- * The app owns persistence — a D1 column, a KV key, a Postgres row — and
208
- * nothing else. Every rule about which action means what stays here, so it
209
- * cannot drift between apps.
210
- */
211
- export declare function createWorkspaceSandboxRecoveryManager(store: WorkspaceSandboxRecoveryStore): WorkspaceSandboxRecoveryManager;
210
+ /** Bind canonical recovery policy to the application's existing storage. */
211
+ export declare function createWorkspaceSandboxRecoveryManager<Snapshot extends WorkspaceSandboxSnapshot>(store: WorkspaceSandboxRecoveryStore<Snapshot>): WorkspaceSandboxRecoveryManager<Snapshot>;
212
212
  /** Every declared action, for exhaustiveness tests in apps and here. */
213
213
  export declare const WORKSPACE_SANDBOX_RECOVERY_ACTIONS: readonly WorkspaceSandboxRecoveryAction[];
214
214
  /** Every declared cause. */
@@ -16,7 +16,7 @@ import {
16
16
  resolveAsyncValue,
17
17
  useAsyncResource,
18
18
  useConfirmedMutation
19
- } from "../../chunk-3UBAO3N5.js";
19
+ } from "../../chunk-Q3ZHNN5X.js";
20
20
  export {
21
21
  AsyncRequestError,
22
22
  AsyncView,
@@ -35,7 +35,7 @@ export interface UseAsyncResourceOptions<T> {
35
35
  * empty list;
36
36
  * - `empty` is only reachable from a load that actually succeeded;
37
37
  * - a superseded load (inputs changed, retry pressed, component unmounted) is
38
- * aborted and its late result is dropped by a monotonic sequence guard, so it
39
- * cannot repaint a newer view.
38
+ * aborted and its late result is discarded; resolutions are bound to their
39
+ * input identity, including the render before the next effect runs.
40
40
  */
41
41
  export declare function useAsyncResource<T>({ load, deps, enabled, initialValue, isEmpty, errorMessage, }: UseAsyncResourceOptions<T>): AsyncResourceState<T>;
@@ -51,6 +51,9 @@ export type MutationState<T> = {
51
51
  readonly error: unknown;
52
52
  };
53
53
  export interface UseConfirmedMutationOptions<TInput, TValue> {
54
+ /** Default replaces the observed run. `reject` keeps the current request
55
+ * and refuses another invocation before any second write can start. */
56
+ concurrency?: 'replace' | 'reject';
54
57
  /**
55
58
  * Performs the write and returns a confirmation. Anything else — including a
56
59
  * hand-written `{ succeeded: true }` — is treated as a failed write, because
@@ -72,8 +75,8 @@ export interface UseConfirmedMutationOptions<TInput, TValue> {
72
75
  export interface ConfirmedMutation<TInput, TValue> {
73
76
  readonly state: MutationState<TValue>;
74
77
  /** Runs the write. Never rejects — the outcome is returned and mirrored into
75
- * `state`. Concurrent runs are last-write-wins; disable the control while
76
- * `state.status === 'pending'`. */
78
+ * `state`. Concurrent runs are last-write-wins unless `concurrency: 'reject'`
79
+ * is configured. Server-side idempotency is still required. */
77
80
  readonly run: (input: TInput) => Promise<MutationOutcome<TValue>>;
78
81
  /** Back to `idle` (dismisses a "Saved" or error affordance). */
79
82
  readonly reset: () => void;
@@ -87,4 +90,4 @@ export interface ConfirmedMutation<TInput, TValue> {
87
90
  * `failed` carrying the contract violation rather than a success it never
88
91
  * earned.
89
92
  */
90
- export declare function useConfirmedMutation<TInput, TValue>({ mutate, onSucceeded, onFailed, errorMessage, }: UseConfirmedMutationOptions<TInput, TValue>): ConfirmedMutation<TInput, TValue>;
93
+ export declare function useConfirmedMutation<TInput, TValue>({ mutate, onSucceeded, onFailed, errorMessage, concurrency, }: UseConfirmedMutationOptions<TInput, TValue>): ConfirmedMutation<TInput, TValue>;