@adminide-stack/yantra-mobile 12.0.113 → 12.0.115-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -119,6 +119,10 @@ function createRemoteConnectorExec(token, indexUrl) {
119
119
  const backend = deriveBackendGraphqlUrl(indexUrl);
120
120
  return (connector, action, params, options) => execAction(agent, backend, token, connector, action, params, options);
121
121
  }
122
+ function createAgentConnectorExec(token, agentEndpoint, backendGraphqlUrl = null) {
123
+ const agent = agentEndpoint.trim().replace(/\/+$/, "");
124
+ return (connector, action, params, options) => execAction(agent, backendGraphqlUrl, token, connector, action, params, options);
125
+ }
122
126
  function createRemoteUploadMedia(token, indexUrl) {
123
127
  const agent = deriveAgentEndpoint(indexUrl);
124
128
  return async (localUri) => {
@@ -153,4 +157,4 @@ function proxiedMediaUrl(indexUrl, uri) {
153
157
  if (!uri || uri.includes("/v1/files/proxy")) return uri;
154
158
  if (!/generativelanguage\.googleapis|googleusercontent\.com/i.test(uri)) return uri;
155
159
  return `${deriveAgentEndpoint(indexUrl)}/v1/files/proxy?url=${encodeURIComponent(uri)}`;
156
- }export{createRemoteConnectorExec,createRemoteRunAction,createRemoteUploadMedia,deriveAgentEndpoint,deriveBackendGraphqlUrl,parseTokenResult,proxiedMediaUrl,unwrapProxyUrl};//# sourceMappingURL=remoteMediaClient.js.map
160
+ }export{createAgentConnectorExec,createRemoteConnectorExec,createRemoteRunAction,createRemoteUploadMedia,deriveAgentEndpoint,deriveBackendGraphqlUrl,parseTokenResult,proxiedMediaUrl,unwrapProxyUrl};//# sourceMappingURL=remoteMediaClient.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"remoteMediaClient.js","sources":["../../../../src/features/canvas/videoEditor/remoteMediaClient.ts"],"sourcesContent":["/**\n * REMOTE-SIDE media-connector client - the fallback that makes editors work\n * on app binaries that predate the host seams.\n *\n * The connector transport is plain fetch with a bearer the remote already\n * receives (the same system JWT the surface index accepts), so nothing here\n * needs the host: the agent endpoint and backend GraphQL URL derive from the\n * environment the indexUrl names (…cdebase.dev -> cdecli-agent.cdebase.dev,\n * …yantra.app -> cdecli-agent.yantra.app; surface-index-backend.X ->\n * ideback.X). A host-provided seam still wins when present - it can carry\n * better auth refresh - this only fills the gap.\n *\n * Transport contract == the hosts' clients (exec/stream body, data: frame\n * parsing, /v1/files/upload) - keep the three in lockstep.\n */\nimport type { RunMediaAction } from './mediaActions';\nimport { uploadFilenameFor } from './solidColorPng';\n\nconst OP_TIMEOUT_MS = 900_000; // clips (yantra-video-clip) is the long pole (~15 min)\n\nfunction indexHost(indexUrl: string): string {\n return indexUrl.replace(/^https?:\\/\\//, '').split('/')[0] ?? '';\n}\n\nexport function deriveAgentEndpoint(indexUrl: string): string {\n const host = indexHost(indexUrl);\n if (host.endsWith('.yantra.app')) return 'https://cdecli-agent.yantra.app';\n return 'https://cdecli-agent.cdebase.dev';\n}\n\nexport function deriveBackendGraphqlUrl(indexUrl: string): string | null {\n const host = indexHost(indexUrl);\n if (!host.startsWith('surface-index-backend.')) return null;\n return `https://ideback.${host.slice('surface-index-backend.'.length)}/graphql`;\n}\n\n/** Grace on top of the agent's own timeout before the phone gives up on the request. */\nconst CLIENT_ABORT_GRACE_MS = 30_000;\n\ninterface ExecFrame {\n type?: string;\n data?: unknown;\n error?: string;\n exit_code?: number;\n}\n\nconst RESULT_SENTINEL = '__CDECLI_RESULT__';\n\n/**\n * The action's JSON from streamed stdout when no `result` frame came. Connectors\n * wrap it as `__CDECLI_RESULT__{json}__CDECLI_RESULT__` after any progress text;\n * a bare object after progress text is the older form.\n */\nexport function parseTokenResult(joined: string): Record<string, unknown> | null {\n const parse = (text: string): Record<string, unknown> | null => {\n try {\n const value: unknown = JSON.parse(text);\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n } catch {\n return null;\n }\n };\n const end = joined.lastIndexOf(RESULT_SENTINEL);\n const start = end > 0 ? joined.lastIndexOf(RESULT_SENTINEL, end - 1) : -1;\n if (start >= 0) return parse(joined.slice(start + RESULT_SENTINEL.length, end));\n const brace = joined.indexOf('{');\n return brace >= 0 ? parse(joined.slice(brace)) : null;\n}\n\nexport interface RemoteExecOptions {\n /** Vault credential the action runs with (`--credential-id`), e.g. a connected mailbox. */\n credentialId?: string;\n /** Agent-side timeout; the request is aborted on the phone shortly after it. */\n timeoutMs?: number;\n}\n\nasync function execAction(\n agentEndpoint: string,\n backendGraphqlUrl: string | null,\n token: string,\n connector: string,\n action: string,\n params: Record<string, unknown>,\n options: RemoteExecOptions = {},\n): Promise<Record<string, unknown>> {\n const timeoutMs = options.timeoutMs ?? OP_TIMEOUT_MS;\n const credentialId = options.credentialId?.trim();\n const body = {\n args: [\n 'connector',\n 'run',\n '-c',\n connector,\n '-a',\n action,\n ...(credentialId ? ['--credential-id', credentialId] : []),\n '--params',\n JSON.stringify(params),\n ],\n stream: true,\n timeout_ms: timeoutMs,\n ...(backendGraphqlUrl ? { backend_graphql_url: backendGraphqlUrl } : {}),\n };\n // Without an abort a stalled agent leaves the caller waiting forever: the\n // screen keeps its spinner and nothing ever replaces it.\n const controller = new AbortController();\n const abortTimer = setTimeout(() => controller.abort(), timeoutMs + CLIENT_ABORT_GRACE_MS);\n let resp: Response;\n let text: string;\n try {\n resp = await fetch(`${agentEndpoint}/v1/cdecli/exec/stream`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n text = await resp.text();\n } catch (err) {\n if (controller.signal.aborted) throw new Error(`${action} timed out`);\n throw err;\n } finally {\n clearTimeout(abortTimer);\n }\n if (!resp.ok) throw new Error(`${action} failed (HTTP ${resp.status}): ${text.slice(0, 200)}`);\n\n let result: Record<string, unknown> | null = null;\n let stderr = '';\n let exitCode: number | undefined;\n const jsonTokens: string[] = [];\n for (const rawLine of text.split('\\n')) {\n const line = rawLine.startsWith('data: ') ? rawLine.slice(6).trim() : rawLine.trim();\n if (!line) continue;\n let frame: ExecFrame;\n try {\n frame = JSON.parse(line) as ExecFrame;\n } catch {\n continue;\n }\n if (typeof frame.exit_code === 'number') exitCode = frame.exit_code;\n if (frame.error) stderr += frame.error;\n if (frame.type === 'result' && frame.data && typeof frame.data === 'object') {\n result = frame.data as Record<string, unknown>;\n } else if ((frame.type === 'stderr' || frame.type === 'error') && typeof frame.data === 'string') {\n stderr += frame.data;\n } else if (frame.type === 'token' && typeof frame.data === 'string') {\n jsonTokens.push(frame.data);\n }\n }\n if (!result) result = parseTokenResult(jsonTokens.join(''));\n if ((exitCode !== undefined && exitCode !== 0) || (!result && stderr)) {\n throw new Error(`${action} failed: ${stderr.slice(0, 300) || `exit ${exitCode}`}`);\n }\n if (!result) throw new Error(`${action} returned no result`);\n return result;\n}\n\n/** Connector runner from what the remote already holds - token + indexUrl. */\nexport function createRemoteRunAction(token: string, indexUrl: string): RunMediaAction {\n const agent = deriveAgentEndpoint(indexUrl);\n const backend = deriveBackendGraphqlUrl(indexUrl);\n return (connector, action, params) => execAction(agent, backend, token, connector, action, params);\n}\n\nexport type RemoteConnectorExec = (\n connector: string,\n action: string,\n params: Record<string, unknown>,\n options?: RemoteExecOptions,\n) => Promise<Record<string, unknown>>;\n\n/** Same transport as createRemoteRunAction, for any connector, with a credential and timeout per call. */\nexport function createRemoteConnectorExec(token: string, indexUrl: string): RemoteConnectorExec {\n const agent = deriveAgentEndpoint(indexUrl);\n const backend = deriveBackendGraphqlUrl(indexUrl);\n return (connector, action, params, options) =>\n execAction(agent, backend, token, connector, action, params, options);\n}\n\n/** file:// -> store URL via the agent's upload endpoint. */\nexport function createRemoteUploadMedia(token: string, indexUrl: string): (localUri: string) => Promise<string> {\n const agent = deriveAgentEndpoint(indexUrl);\n return async (localUri: string) => {\n const blob = await (await fetch(localUri)).blob();\n const filename = uploadFilenameFor(localUri);\n const resp = await fetch(`${agent}/v1/files/upload?filename=${encodeURIComponent(filename)}`, {\n method: 'POST',\n headers: { 'content-type': blob.type || 'application/octet-stream', authorization: `Bearer ${token}` },\n body: blob,\n });\n if (!resp.ok) throw new Error(`Upload failed (HTTP ${resp.status}): ${(await resp.text()).slice(0, 160)}`);\n const result = (await resp.json()) as { url?: string };\n if (!result.url) throw new Error('Upload returned no URL');\n return result.url;\n };\n}\n\n/**\n * Twin of web canvas `unwrapProxyUrl`: the connector fetches the reference\n * server-side, so pass the inner Google/store URL, not the agent proxy wrap.\n */\nexport function unwrapProxyUrl(src: string): string {\n try {\n const u = new URL(src);\n if (u.pathname.includes('/v1/files/proxy')) {\n const inner = u.searchParams.get('url');\n if (inner) return inner;\n }\n } catch {\n /* not a URL */\n }\n return src;\n}\n\n/** Google Veo URIs are not fetchable on device — route them through the agent proxy. */\nexport function proxiedMediaUrl(indexUrl: string, uri: string): string {\n if (!uri || uri.includes('/v1/files/proxy')) return uri;\n if (!/generativelanguage\\.googleapis|googleusercontent\\.com/i.test(uri)) return uri;\n return `${deriveAgentEndpoint(indexUrl)}/v1/files/proxy?url=${encodeURIComponent(uri)}`;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAiBA,MAAM,aAAgB,GAAA,GAAA;AAEtB,SAAS,UAAU,QAA0B,EAAA;AAnB7C,EAAA,IAAA,EAAA;AAoBE,EAAO,OAAA,CAAA,EAAA,GAAA,QAAA,CAAS,OAAQ,CAAA,cAAA,EAAgB,EAAE,CAAA,CAAE,MAAM,GAAG,CAAA,CAAE,CAAC,CAAA,KAAjD,IAAsD,GAAA,EAAA,GAAA,EAAA;AAC/D;AACO,SAAS,oBAAoB,QAA0B,EAAA;AAC5D,EAAM,MAAA,IAAA,GAAO,UAAU,QAAQ,CAAA;AAC/B,EAAA,IAAI,IAAK,CAAA,QAAA,CAAS,aAAa,CAAA,EAAU,OAAA,iCAAA;AACzC,EAAO,OAAA,kCAAA;AACT;AACO,SAAS,wBAAwB,QAAiC,EAAA;AACvE,EAAM,MAAA,IAAA,GAAO,UAAU,QAAQ,CAAA;AAC/B,EAAA,IAAI,CAAC,IAAA,CAAK,UAAW,CAAA,wBAAwB,GAAU,OAAA,IAAA;AACvD,EAAA,OAAO,CAAmB,gBAAA,EAAA,IAAA,CAAK,KAAM,CAAA,wBAAA,CAAyB,MAAM,CAAC,CAAA,QAAA,CAAA;AACvE;AAGA,MAAM,qBAAwB,GAAA,GAAA;AAO9B,MAAM,eAAkB,GAAA,mBAAA;AAOjB,SAAS,iBAAiB,MAAgD,EAAA;AAC/E,EAAM,MAAA,KAAA,GAAQ,CAAC,IAAiD,KAAA;AAC9D,IAAI,IAAA;AACF,MAAM,MAAA,KAAA,GAAiB,IAAK,CAAA,KAAA,CAAM,IAAI,CAAA;AACtC,MAAO,OAAA,KAAA,IAAS,OAAO,KAAU,KAAA,QAAA,IAAY,CAAC,KAAM,CAAA,OAAA,CAAQ,KAAK,CAAA,GAAI,KAAmC,GAAA,IAAA;AAAA,KAClG,CAAA,OAAA,CAAA,EAAA;AACN,MAAO,OAAA,IAAA;AAAA;AACT,GACF;AACA,EAAM,MAAA,GAAA,GAAM,MAAO,CAAA,WAAA,CAAY,eAAe,CAAA;AAC9C,EAAM,MAAA,KAAA,GAAQ,MAAM,CAAI,GAAA,MAAA,CAAO,YAAY,eAAiB,EAAA,GAAA,GAAM,CAAC,CAAI,GAAA,EAAA;AACvE,EAAI,IAAA,KAAA,IAAS,CAAG,EAAA,OAAO,KAAM,CAAA,MAAA,CAAO,MAAM,KAAQ,GAAA,eAAA,CAAgB,MAAQ,EAAA,GAAG,CAAC,CAAA;AAC9E,EAAM,MAAA,KAAA,GAAQ,MAAO,CAAA,OAAA,CAAQ,GAAG,CAAA;AAChC,EAAA,OAAO,SAAS,CAAI,GAAA,KAAA,CAAM,OAAO,KAAM,CAAA,KAAK,CAAC,CAAI,GAAA,IAAA;AACnD;AAOA,eAAe,UAAA,CAAW,eAAuB,iBAAkC,EAAA,KAAA,EAAe,WAAmB,MAAgB,EAAA,MAAA,EAAiC,OAA6B,GAAA,EAAsC,EAAA;AArEzO,EAAA,IAAA,EAAA,EAAA,EAAA;AAsEE,EAAM,MAAA,SAAA,GAAA,CAAY,EAAQ,GAAA,OAAA,CAAA,SAAA,KAAR,IAAqB,GAAA,EAAA,GAAA,aAAA;AACvC,EAAM,MAAA,YAAA,GAAA,CAAe,EAAQ,GAAA,OAAA,CAAA,YAAA,KAAR,IAAsB,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,EAAA;AAC3C,EAAA,MAAM,IAAO,GAAA,cAAA,CAAA;AAAA,IACX,IAAA,EAAM,CAAC,WAAa,EAAA,KAAA,EAAO,MAAM,SAAW,EAAA,IAAA,EAAM,QAAQ,GAAI,YAAA,GAAe,CAAC,iBAAmB,EAAA,YAAY,IAAI,EAAC,EAAI,YAAY,IAAK,CAAA,SAAA,CAAU,MAAM,CAAC,CAAA;AAAA,IACxJ,MAAQ,EAAA,IAAA;AAAA,IACR,UAAY,EAAA;AAAA,GAAA,EACR,iBAAoB,GAAA;AAAA,IACtB,mBAAqB,EAAA;AAAA,MACnB,EAAC,CAAA;AAIP,EAAM,MAAA,UAAA,GAAa,IAAI,eAAgB,EAAA;AACvC,EAAA,MAAM,aAAa,UAAW,CAAA,MAAM,WAAW,KAAM,EAAA,EAAG,YAAY,qBAAqB,CAAA;AACzF,EAAI,IAAA,IAAA;AACJ,EAAI,IAAA,IAAA;AACJ,EAAI,IAAA;AACF,IAAA,IAAA,GAAO,MAAM,KAAA,CAAM,CAAG,EAAA,aAAa,CAA0B,sBAAA,CAAA,EAAA;AAAA,MAC3D,MAAQ,EAAA,MAAA;AAAA,MACR,OAAS,EAAA;AAAA,QACP,cAAgB,EAAA,kBAAA;AAAA,QAChB,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA,OAChC;AAAA,MACA,IAAA,EAAM,IAAK,CAAA,SAAA,CAAU,IAAI,CAAA;AAAA,MACzB,QAAQ,UAAW,CAAA;AAAA,KACpB,CAAA;AACD,IAAO,IAAA,GAAA,MAAM,KAAK,IAAK,EAAA;AAAA,WAChB,GAAK,EAAA;AACZ,IAAI,IAAA,UAAA,CAAW,OAAO,OAAS,EAAA,MAAM,IAAI,KAAM,CAAA,CAAA,EAAG,MAAM,CAAY,UAAA,CAAA,CAAA;AACpE,IAAM,MAAA,GAAA;AAAA,GACN,SAAA;AACA,IAAA,YAAA,CAAa,UAAU,CAAA;AAAA;AAEzB,EAAA,IAAI,CAAC,IAAK,CAAA,EAAA,EAAU,MAAA,IAAI,MAAM,CAAG,EAAA,MAAM,CAAiB,cAAA,EAAA,IAAA,CAAK,MAAM,CAAM,GAAA,EAAA,IAAA,CAAK,MAAM,CAAG,EAAA,GAAG,CAAC,CAAE,CAAA,CAAA;AAC7F,EAAA,IAAI,MAAyC,GAAA,IAAA;AAC7C,EAAA,IAAI,MAAS,GAAA,EAAA;AACb,EAAI,IAAA,QAAA;AACJ,EAAA,MAAM,aAAuB,EAAC;AAC9B,EAAA,KAAA,MAAW,OAAW,IAAA,IAAA,CAAK,KAAM,CAAA,IAAI,CAAG,EAAA;AACtC,IAAA,MAAM,IAAO,GAAA,OAAA,CAAQ,UAAW,CAAA,QAAQ,CAAI,GAAA,OAAA,CAAQ,KAAM,CAAA,CAAC,CAAE,CAAA,IAAA,EAAS,GAAA,OAAA,CAAQ,IAAK,EAAA;AACnF,IAAA,IAAI,CAAC,IAAM,EAAA;AACX,IAAI,IAAA,KAAA;AACJ,IAAI,IAAA;AACF,MAAQ,KAAA,GAAA,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,KACjB,CAAA,OAAA,CAAA,EAAA;AACN,MAAA;AAAA;AAEF,IAAA,IAAI,OAAO,KAAA,CAAM,SAAc,KAAA,QAAA,aAAqB,KAAM,CAAA,SAAA;AAC1D,IAAI,IAAA,KAAA,CAAM,KAAO,EAAA,MAAA,IAAU,KAAM,CAAA,KAAA;AACjC,IAAI,IAAA,KAAA,CAAM,SAAS,QAAY,IAAA,KAAA,CAAM,QAAQ,OAAO,KAAA,CAAM,SAAS,QAAU,EAAA;AAC3E,MAAA,MAAA,GAAS,KAAM,CAAA,IAAA;AAAA,KACjB,MAAA,IAAA,CAAY,KAAM,CAAA,IAAA,KAAS,QAAY,IAAA,KAAA,CAAM,SAAS,OAAY,KAAA,OAAO,KAAM,CAAA,IAAA,KAAS,QAAU,EAAA;AAChG,MAAA,MAAA,IAAU,KAAM,CAAA,IAAA;AAAA,eACP,KAAM,CAAA,IAAA,KAAS,WAAW,OAAO,KAAA,CAAM,SAAS,QAAU,EAAA;AACnE,MAAW,UAAA,CAAA,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA;AAC5B;AAEF,EAAA,IAAI,CAAC,MAAQ,EAAA,MAAA,GAAS,iBAAiB,UAAW,CAAA,IAAA,CAAK,EAAE,CAAC,CAAA;AAC1D,EAAA,IAAI,aAAa,MAAa,IAAA,QAAA,KAAa,CAAK,IAAA,CAAC,UAAU,MAAQ,EAAA;AACjE,IAAA,MAAM,IAAI,KAAA,CAAM,CAAG,EAAA,MAAM,CAAY,SAAA,EAAA,MAAA,CAAO,KAAM,CAAA,CAAA,EAAG,GAAG,CAAA,IAAK,CAAQ,KAAA,EAAA,QAAQ,EAAE,CAAE,CAAA,CAAA;AAAA;AAEnF,EAAA,IAAI,CAAC,MAAQ,EAAA,MAAM,IAAI,KAAM,CAAA,CAAA,EAAG,MAAM,CAAqB,mBAAA,CAAA,CAAA;AAC3D,EAAO,OAAA,MAAA;AACT;AAGgB,SAAA,qBAAA,CAAsB,OAAe,QAAkC,EAAA;AACrF,EAAM,MAAA,KAAA,GAAQ,oBAAoB,QAAQ,CAAA;AAC1C,EAAM,MAAA,OAAA,GAAU,wBAAwB,QAAQ,CAAA;AAChD,EAAO,OAAA,CAAC,SAAW,EAAA,MAAA,EAAQ,MAAW,KAAA,UAAA,CAAW,OAAO,OAAS,EAAA,KAAA,EAAO,SAAW,EAAA,MAAA,EAAQ,MAAM,CAAA;AACnG;AAIgB,SAAA,yBAAA,CAA0B,OAAe,QAAuC,EAAA;AAC9F,EAAM,MAAA,KAAA,GAAQ,oBAAoB,QAAQ,CAAA;AAC1C,EAAM,MAAA,OAAA,GAAU,wBAAwB,QAAQ,CAAA;AAChD,EAAA,OAAO,CAAC,SAAA,EAAW,MAAQ,EAAA,MAAA,EAAQ,OAAY,KAAA,UAAA,CAAW,KAAO,EAAA,OAAA,EAAS,KAAO,EAAA,SAAA,EAAW,MAAQ,EAAA,MAAA,EAAQ,OAAO,CAAA;AACrH;AAGgB,SAAA,uBAAA,CAAwB,OAAe,QAAyD,EAAA;AAC9G,EAAM,MAAA,KAAA,GAAQ,oBAAoB,QAAQ,CAAA;AAC1C,EAAA,OAAO,OAAO,QAAqB,KAAA;AACjC,IAAA,MAAM,OAAO,MAAO,CAAA,MAAM,KAAM,CAAA,QAAQ,GAAG,IAAK,EAAA;AAChD,IAAM,MAAA,QAAA,GAAW,kBAAkB,QAAQ,CAAA;AAC3C,IAAM,MAAA,IAAA,GAAO,MAAM,KAAM,CAAA,CAAA,EAAG,KAAK,CAA6B,0BAAA,EAAA,kBAAA,CAAmB,QAAQ,CAAC,CAAI,CAAA,EAAA;AAAA,MAC5F,MAAQ,EAAA,MAAA;AAAA,MACR,OAAS,EAAA;AAAA,QACP,cAAA,EAAgB,KAAK,IAAQ,IAAA,0BAAA;AAAA,QAC7B,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA,OAChC;AAAA,MACA,IAAM,EAAA;AAAA,KACP,CAAA;AACD,IAAA,IAAI,CAAC,IAAK,CAAA,EAAA,QAAU,IAAI,KAAA,CAAM,uBAAuB,IAAK,CAAA,MAAM,CAAO,GAAA,EAAA,CAAA,MAAM,KAAK,IAAK,EAAA,EAAG,MAAM,CAAG,EAAA,GAAG,CAAC,CAAE,CAAA,CAAA;AACzG,IAAM,MAAA,MAAA,GAAU,MAAM,IAAA,CAAK,IAAK,EAAA;AAGhC,IAAA,IAAI,CAAC,MAAO,CAAA,GAAA,EAAW,MAAA,IAAI,MAAM,wBAAwB,CAAA;AACzD,IAAA,OAAO,MAAO,CAAA,GAAA;AAAA,GAChB;AACF;AAMO,SAAS,eAAe,GAAqB,EAAA;AAClD,EAAI,IAAA;AACF,IAAM,MAAA,CAAA,GAAI,IAAI,GAAA,CAAI,GAAG,CAAA;AACrB,IAAA,IAAI,CAAE,CAAA,QAAA,CAAS,QAAS,CAAA,iBAAiB,CAAG,EAAA;AAC1C,MAAA,MAAM,KAAQ,GAAA,CAAA,CAAE,YAAa,CAAA,GAAA,CAAI,KAAK,CAAA;AACtC,MAAA,IAAI,OAAc,OAAA,KAAA;AAAA;AACpB,GACM,CAAA,OAAA,CAAA,EAAA;AAAA;AAGR,EAAO,OAAA,GAAA;AACT;AAGgB,SAAA,eAAA,CAAgB,UAAkB,GAAqB,EAAA;AACrE,EAAA,IAAI,CAAC,GAAO,IAAA,GAAA,CAAI,QAAS,CAAA,iBAAiB,GAAU,OAAA,GAAA;AACpD,EAAA,IAAI,CAAC,wDAAA,CAAyD,IAAK,CAAA,GAAG,GAAU,OAAA,GAAA;AAChF,EAAA,OAAO,GAAG,mBAAoB,CAAA,QAAQ,CAAC,CAAuB,oBAAA,EAAA,kBAAA,CAAmB,GAAG,CAAC,CAAA,CAAA;AACvF"}
1
+ {"version":3,"file":"remoteMediaClient.js","sources":["../../../../src/features/canvas/videoEditor/remoteMediaClient.ts"],"sourcesContent":["/**\n * REMOTE-SIDE media-connector client - the fallback that makes editors work\n * on app binaries that predate the host seams.\n *\n * The connector transport is plain fetch with a bearer the remote already\n * receives (the same system JWT the surface index accepts), so nothing here\n * needs the host: the agent endpoint and backend GraphQL URL derive from the\n * environment the indexUrl names (…cdebase.dev -> cdecli-agent.cdebase.dev,\n * …yantra.app -> cdecli-agent.yantra.app; surface-index-backend.X ->\n * ideback.X). A host-provided seam still wins when present - it can carry\n * better auth refresh - this only fills the gap.\n *\n * Transport contract == the hosts' clients (exec/stream body, data: frame\n * parsing, /v1/files/upload) - keep the three in lockstep.\n */\nimport type { RunMediaAction } from './mediaActions';\nimport { uploadFilenameFor } from './solidColorPng';\n\nconst OP_TIMEOUT_MS = 900_000; // clips (yantra-video-clip) is the long pole (~15 min)\n\nfunction indexHost(indexUrl: string): string {\n return indexUrl.replace(/^https?:\\/\\//, '').split('/')[0] ?? '';\n}\n\nexport function deriveAgentEndpoint(indexUrl: string): string {\n const host = indexHost(indexUrl);\n if (host.endsWith('.yantra.app')) return 'https://cdecli-agent.yantra.app';\n return 'https://cdecli-agent.cdebase.dev';\n}\n\nexport function deriveBackendGraphqlUrl(indexUrl: string): string | null {\n const host = indexHost(indexUrl);\n if (!host.startsWith('surface-index-backend.')) return null;\n return `https://ideback.${host.slice('surface-index-backend.'.length)}/graphql`;\n}\n\n/** Grace on top of the agent's own timeout before the phone gives up on the request. */\nconst CLIENT_ABORT_GRACE_MS = 30_000;\n\ninterface ExecFrame {\n type?: string;\n data?: unknown;\n error?: string;\n exit_code?: number;\n}\n\nconst RESULT_SENTINEL = '__CDECLI_RESULT__';\n\n/**\n * The action's JSON from streamed stdout when no `result` frame came. Connectors\n * wrap it as `__CDECLI_RESULT__{json}__CDECLI_RESULT__` after any progress text;\n * a bare object after progress text is the older form.\n */\nexport function parseTokenResult(joined: string): Record<string, unknown> | null {\n const parse = (text: string): Record<string, unknown> | null => {\n try {\n const value: unknown = JSON.parse(text);\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n } catch {\n return null;\n }\n };\n const end = joined.lastIndexOf(RESULT_SENTINEL);\n const start = end > 0 ? joined.lastIndexOf(RESULT_SENTINEL, end - 1) : -1;\n if (start >= 0) return parse(joined.slice(start + RESULT_SENTINEL.length, end));\n const brace = joined.indexOf('{');\n return brace >= 0 ? parse(joined.slice(brace)) : null;\n}\n\nexport interface RemoteExecOptions {\n /** Vault credential the action runs with (`--credential-id`), e.g. a connected mailbox. */\n credentialId?: string;\n /** Agent-side timeout; the request is aborted on the phone shortly after it. */\n timeoutMs?: number;\n}\n\nasync function execAction(\n agentEndpoint: string,\n backendGraphqlUrl: string | null,\n token: string,\n connector: string,\n action: string,\n params: Record<string, unknown>,\n options: RemoteExecOptions = {},\n): Promise<Record<string, unknown>> {\n const timeoutMs = options.timeoutMs ?? OP_TIMEOUT_MS;\n const credentialId = options.credentialId?.trim();\n const body = {\n args: [\n 'connector',\n 'run',\n '-c',\n connector,\n '-a',\n action,\n ...(credentialId ? ['--credential-id', credentialId] : []),\n '--params',\n JSON.stringify(params),\n ],\n stream: true,\n timeout_ms: timeoutMs,\n ...(backendGraphqlUrl ? { backend_graphql_url: backendGraphqlUrl } : {}),\n };\n // Without an abort a stalled agent leaves the caller waiting forever: the\n // screen keeps its spinner and nothing ever replaces it.\n const controller = new AbortController();\n const abortTimer = setTimeout(() => controller.abort(), timeoutMs + CLIENT_ABORT_GRACE_MS);\n let resp: Response;\n let text: string;\n try {\n resp = await fetch(`${agentEndpoint}/v1/cdecli/exec/stream`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n text = await resp.text();\n } catch (err) {\n if (controller.signal.aborted) throw new Error(`${action} timed out`);\n throw err;\n } finally {\n clearTimeout(abortTimer);\n }\n if (!resp.ok) throw new Error(`${action} failed (HTTP ${resp.status}): ${text.slice(0, 200)}`);\n\n let result: Record<string, unknown> | null = null;\n let stderr = '';\n let exitCode: number | undefined;\n const jsonTokens: string[] = [];\n for (const rawLine of text.split('\\n')) {\n const line = rawLine.startsWith('data: ') ? rawLine.slice(6).trim() : rawLine.trim();\n if (!line) continue;\n let frame: ExecFrame;\n try {\n frame = JSON.parse(line) as ExecFrame;\n } catch {\n continue;\n }\n if (typeof frame.exit_code === 'number') exitCode = frame.exit_code;\n if (frame.error) stderr += frame.error;\n if (frame.type === 'result' && frame.data && typeof frame.data === 'object') {\n result = frame.data as Record<string, unknown>;\n } else if ((frame.type === 'stderr' || frame.type === 'error') && typeof frame.data === 'string') {\n stderr += frame.data;\n } else if (frame.type === 'token' && typeof frame.data === 'string') {\n jsonTokens.push(frame.data);\n }\n }\n if (!result) result = parseTokenResult(jsonTokens.join(''));\n if ((exitCode !== undefined && exitCode !== 0) || (!result && stderr)) {\n throw new Error(`${action} failed: ${stderr.slice(0, 300) || `exit ${exitCode}`}`);\n }\n if (!result) throw new Error(`${action} returned no result`);\n return result;\n}\n\n/** Connector runner from what the remote already holds - token + indexUrl. */\nexport function createRemoteRunAction(token: string, indexUrl: string): RunMediaAction {\n const agent = deriveAgentEndpoint(indexUrl);\n const backend = deriveBackendGraphqlUrl(indexUrl);\n return (connector, action, params) => execAction(agent, backend, token, connector, action, params);\n}\n\nexport type RemoteConnectorExec = (\n connector: string,\n action: string,\n params: Record<string, unknown>,\n options?: RemoteExecOptions,\n) => Promise<Record<string, unknown>>;\n\n/** Same transport as createRemoteRunAction, for any connector, with a credential and timeout per call. */\nexport function createRemoteConnectorExec(token: string, indexUrl: string): RemoteConnectorExec {\n const agent = deriveAgentEndpoint(indexUrl);\n const backend = deriveBackendGraphqlUrl(indexUrl);\n return (connector, action, params, options) =>\n execAction(agent, backend, token, connector, action, params, options);\n}\n\n/**\n * Same transport against an agent the caller names. The host knows the agent its own chat session talks to\n * (CDECLI_AGENT_ENDPOINT); a remote only has the index URL to derive one from. A call that must reach the same\n * per-user state the chat's agent works on (the person's Computer) goes there, with the token that session uses.\n */\nexport function createAgentConnectorExec(\n token: string,\n agentEndpoint: string,\n backendGraphqlUrl: string | null = null,\n): RemoteConnectorExec {\n const agent = agentEndpoint.trim().replace(/\\/+$/, '');\n return (connector, action, params, options) =>\n execAction(agent, backendGraphqlUrl, token, connector, action, params, options);\n}\n\n/** file:// -> store URL via the agent's upload endpoint. */\nexport function createRemoteUploadMedia(token: string, indexUrl: string): (localUri: string) => Promise<string> {\n const agent = deriveAgentEndpoint(indexUrl);\n return async (localUri: string) => {\n const blob = await (await fetch(localUri)).blob();\n const filename = uploadFilenameFor(localUri);\n const resp = await fetch(`${agent}/v1/files/upload?filename=${encodeURIComponent(filename)}`, {\n method: 'POST',\n headers: { 'content-type': blob.type || 'application/octet-stream', authorization: `Bearer ${token}` },\n body: blob,\n });\n if (!resp.ok) throw new Error(`Upload failed (HTTP ${resp.status}): ${(await resp.text()).slice(0, 160)}`);\n const result = (await resp.json()) as { url?: string };\n if (!result.url) throw new Error('Upload returned no URL');\n return result.url;\n };\n}\n\n/**\n * Twin of web canvas `unwrapProxyUrl`: the connector fetches the reference\n * server-side, so pass the inner Google/store URL, not the agent proxy wrap.\n */\nexport function unwrapProxyUrl(src: string): string {\n try {\n const u = new URL(src);\n if (u.pathname.includes('/v1/files/proxy')) {\n const inner = u.searchParams.get('url');\n if (inner) return inner;\n }\n } catch {\n /* not a URL */\n }\n return src;\n}\n\n/** Google Veo URIs are not fetchable on device — route them through the agent proxy. */\nexport function proxiedMediaUrl(indexUrl: string, uri: string): string {\n if (!uri || uri.includes('/v1/files/proxy')) return uri;\n if (!/generativelanguage\\.googleapis|googleusercontent\\.com/i.test(uri)) return uri;\n return `${deriveAgentEndpoint(indexUrl)}/v1/files/proxy?url=${encodeURIComponent(uri)}`;\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import {jsx}from'react/jsx-runtime';import {useMemo,useState,useCallback,useRef,useEffect}from'react';import {View}from'react-native';import*as WebBrowser from'expo-web-browser';import {buildConnectorReply,vaultKindOf,connectorCredentialsVariables,credentialsOfOrg,CONNECTOR_CONNECT_APP_RETURN_URL,parseConnectorConnectAppReturnUrl}from'common';import {useFormBuilderCredentialsQuery}from'common/graphql';import {config}from'../../config/env-config.js';import {resolveMobileWebUrl,getPackagerHost}from'../../bridge/resolveMobileWebUrl.js';import {usePrerequisiteIds}from'../../hooks/usePrerequisiteIds.js';import {ConnectorConnectCard}from'./ConnectorConnectCard.js';import {pendingConnectorConnect,connectorConnectKey,pickConnectorConnectCredential,connectorConnectName,decideConnectorConnectOutcome,snapshotConnectorCredentials,buildConnectorConnectUrl,parkedHandbackCredential,connectorConnectActionLabel,connectorConnectReason}from'./connectorConnect.js';import {beginConnectorConnectSession,endConnectorConnectSession,peekConnectorConnectHandback,takeConnectorConnectHandback,subscribeConnectorConnectHandbacks}from'./connectorConnectHandbacks.js';var __defProp = Object.defineProperty;
1
+ import {jsx}from'react/jsx-runtime';import {useMemo,useState,useCallback,useRef,useEffect}from'react';import {View}from'react-native';import*as WebBrowser from'expo-web-browser';import {buildConnectorReply,isOneTimeCodeRequest,vaultKindOf,connectorCredentialsVariables,credentialsOfOrg,CONNECTOR_CONNECT_APP_RETURN_URL,parseConnectorConnectAppReturnUrl}from'common';import {useFormBuilderCredentialsQuery}from'common/graphql';import {config}from'../../config/env-config.js';import {resolveMobileWebUrl,getPackagerHost}from'../../bridge/resolveMobileWebUrl.js';import {usePrerequisiteIds}from'../../hooks/usePrerequisiteIds.js';import {ConnectorConnectCard}from'./ConnectorConnectCard.js';import {pendingConnectorConnect,connectorConnectKey,pickConnectorConnectCredential,connectorConnectName,decideConnectorConnectOutcome,snapshotConnectorCredentials,buildConnectorConnectUrl,parkedHandbackCredential,connectorConnectActionLabel,connectorConnectReason}from'./connectorConnect.js';import {beginConnectorConnectSession,endConnectorConnectSession,peekConnectorConnectHandback,takeConnectorConnectHandback,subscribeConnectorConnectHandbacks}from'./connectorConnectHandbacks.js';import {OneTimeCodePrompt}from'./OneTimeCodePrompt.js';var __defProp = Object.defineProperty;
2
2
  var __defProps = Object.defineProperties;
3
3
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
@@ -21,7 +21,7 @@ const STATUS_FAILED_NOTE = "Could not check your saved logins. Tap Try again.";
21
21
  const READ_FAILED_NOTE = "Could not reach your vault. Try again.";
22
22
  const VERIFY_FAILED_NOTE = "Could not check whether it saved. Tap Check to look again.";
23
23
  const SEND_FAILED_NOTE = "Could not reach the chat. Try again.";
24
- function ConnectorConnectPrompt({
24
+ function CredentialConnectPrompt({
25
25
  payload,
26
26
  isDark = false,
27
27
  onResolve
@@ -249,6 +249,10 @@ function ConnectorConnectPrompt({
249
249
  }
250
250
  );
251
251
  }
252
+ function ConnectorConnectPrompt(props) {
253
+ if (isOneTimeCodeRequest(props.payload)) return /* @__PURE__ */ jsx(OneTimeCodePrompt, __spreadValues({}, props));
254
+ return /* @__PURE__ */ jsx(CredentialConnectPrompt, __spreadValues({}, props));
255
+ }
252
256
  function PendingConnectorConnectCard({
253
257
  messages,
254
258
  send,
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectorConnectPrompt.js","sources":["../../../src/features/chat/ConnectorConnectPrompt.tsx"],"sourcesContent":["/**\n * <ConnectorConnectPrompt> - owns one `[CONNECTOR_CONNECT]` card: whether the\n * connection is already saved, the web page the action opens, and the reply.\n *\n * The phone cannot host the web's inline vault / connector forms, so the action\n * opens the web page in an in-app browser session (expo-web-browser's auth\n * session, which shares the system browser's sign-in with the web app). The vault\n * form's page (a login, a card, an address) hands the saved credential back\n * through the app's scheme URL (see common's CONNECTOR_CONNECT_APP_RETURN_URL);\n * any other connector's page has no way back, so once the browser closes the card\n * re-reads the vault and only a credential the session created or updated counts.\n * Only then does it reply `[CONNECTOR_CONNECTED:<requestId>:<credentialId>]` -\n * never on a closed browser.\n *\n * The action never runs on a guess about what is saved. It stays disabled until\n * the status read has come back from the server, and at the tap the vault is read\n * once more: the form opens ON the saved login (\"Update\", so an email / username\n * or password edit lands on it) or, only when the server says there is none, as a\n * new one. A read that fails opens nothing - offering \"Save login\" then would save\n * a duplicate next to the login the user meant to edit.\n *\n * Status is the same query (the org's credentials, most recently updated first)\n * and the same match (common's matchConnectorCredentials) the web card uses, so a\n * site login's \"Update\" edits the login the web would edit - and the agent signs in\n * with: the one the agent named when it is the org's and fits, else the most\n * recently updated login for the site. An autofill entry's \"Update\" is only ever\n * the entry the agent named; without one the card adds a new entry. Either is\n * edited in the project it lives in. A catalog connector's page is the web card\n * itself, which picks with the template's formId the phone cannot resolve; the\n * phone sends it only the agent's credentialId.\n *\n * Host-only (Apollo, redux, expo-web-browser): a surface remote gets this card as\n * a render prop from its host screen (useHostConnectorCard), never by import.\n */\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { View, type StyleProp, type ViewStyle } from 'react-native';\nimport * as WebBrowser from 'expo-web-browser';\nimport {\n buildConnectorReply,\n CONNECTOR_CONNECT_APP_RETURN_URL,\n connectorCredentialsVariables,\n credentialsOfOrg,\n parseConnectorConnectAppReturnUrl,\n vaultKindOf,\n type ConnectorConnectHandback,\n type ConnectorConnectOutcome,\n type ConnectorConnectPayload,\n} from 'common';\nimport { useFormBuilderCredentialsQuery } from 'common/graphql';\nimport { config } from '../../config/env-config';\nimport { getPackagerHost, resolveMobileWebUrl } from '../../bridge/resolveMobileWebUrl';\nimport { usePrerequisiteIds } from '../../hooks/usePrerequisiteIds';\nimport { ConnectorConnectCard } from './ConnectorConnectCard';\nimport {\n buildConnectorConnectUrl,\n connectorConnectActionLabel,\n connectorConnectKey,\n connectorConnectName,\n connectorConnectReason,\n decideConnectorConnectOutcome,\n parkedHandbackCredential,\n pendingConnectorConnect,\n pickConnectorConnectCredential,\n snapshotConnectorCredentials,\n type ConnectorConnectBefore,\n type CredentialVersionRow,\n} from './connectorConnect';\nimport {\n beginConnectorConnectSession,\n endConnectorConnectSession,\n peekConnectorConnectHandback,\n subscribeConnectorConnectHandbacks,\n takeConnectorConnectHandback,\n} from './connectorConnectHandbacks';\n\n/** The vault as one read returned it; `ok: false` when the read failed. */\ntype VaultRead = { ok: true; rows: CredentialVersionRow[] } | { ok: false };\n\n/** Where the status read stands: the action waits for `ready`. */\ntype StatusState = 'checking' | 'ready' | 'failed';\n\nconst STATUS_FAILED_NOTE = 'Could not check your saved logins. Tap Try again.';\nconst READ_FAILED_NOTE = 'Could not reach your vault. Try again.';\nconst VERIFY_FAILED_NOTE = 'Could not check whether it saved. Tap Check to look again.';\nconst SEND_FAILED_NOTE = 'Could not reach the chat. Try again.';\n\nexport function ConnectorConnectPrompt({\n payload,\n isDark = false,\n onResolve,\n}: {\n payload: ConnectorConnectPayload;\n isDark?: boolean;\n /** Send the reply for this request; resolves false when it could not go out. */\n onResolve: (outcome: ConnectorConnectOutcome, credentialId?: string) => Promise<boolean>;\n}) {\n const { orgName, projectId, loading: idsLoading } = usePrerequisiteIds();\n // A website login or an autofill entry (a card, an address): the web vault form for that kind.\n const vaultKind = vaultKindOf(payload.connector);\n\n // Same query and variables as the web card's useConnectorCredentialMatch (common's\n // connectorCredentialsVariables: the whole org, most recently updated first), so the\n // Apollo cache and the pick agree across the two.\n const variables = useMemo(() => (orgName ? connectorCredentialsVariables(orgName) : null), [orgName]);\n const { data, loading, error, refetch } = useFormBuilderCredentialsQuery({\n variables: variables ?? undefined,\n skip: !variables,\n fetchPolicy: 'cache-and-network',\n });\n // Only this org's rows (credentialsOfOrg): the server deployed today can answer with the caller's rows of\n // every org, and another org's same-named login must never be the one this card edits.\n const listed = data?.formBuilderCredentials?.data as ReadonlyArray<CredentialVersionRow | null> | undefined;\n const cachedRows = useMemo(() => (listed ? credentialsOfOrg(listed, orgName) : undefined), [listed, orgName]);\n\n // `cache-and-network` paints a cached answer first and keeps `loading` until the\n // server answers; a cached \"not saved\" can be stale, so only the server's\n // answer makes the action live.\n let status: StatusState = 'ready';\n if (!variables) status = idsLoading ? 'checking' : 'failed';\n else if (error) status = 'failed';\n else if (loading || !cachedRows) status = 'checking';\n\n const existing = useMemo(\n () => (status === 'ready' && cachedRows ? (pickConnectorConnectCredential(cachedRows, payload) ?? null) : null),\n [status, cachedRows, payload],\n );\n const connected = Boolean(existing);\n const name = connectorConnectName(payload, connected);\n\n const [busy, setBusy] = useState(false);\n const [note, setNote] = useState<string | null>(null);\n // The vault changed but the reply did not go out: the next tap resends the\n // reply instead of reopening the browser.\n const [unsent, setUnsent] = useState<{ credentialId?: string } | null>(null);\n // The browser closed but the vault could not be re-read: the next tap checks\n // again against the same \"before\", instead of reopening the browser.\n const [unverified, setUnverified] = useState<ConnectorConnectBefore | null>(null);\n const mountedRef = useRef(true);\n useEffect(\n () => () => {\n mountedRef.current = false;\n },\n [],\n );\n\n /** The vault as the server has it now (not the cache). */\n const readVault = useCallback(async (): Promise<VaultRead> => {\n if (!variables) return { ok: false };\n try {\n const result = await refetch(variables);\n const rows = result.data?.formBuilderCredentials?.data;\n if (result.error || !Array.isArray(rows)) return { ok: false };\n return { ok: true, rows: credentialsOfOrg(rows as ReadonlyArray<CredentialVersionRow | null>, orgName) };\n } catch {\n return { ok: false };\n }\n }, [variables, refetch, orgName]);\n\n /** Send the reply; a send that throws counts as not sent, so the card stays. */\n const sendReply = useCallback(\n async (outcome: ConnectorConnectOutcome, credentialId?: string): Promise<boolean> => {\n try {\n return await onResolve(outcome, credentialId);\n } catch {\n return false;\n }\n },\n [onResolve],\n );\n\n /** Reply `connected`; on failure keep the result so the next tap only resends. */\n const replyConnected = useCallback(\n async (credentialId: string | undefined): Promise<string | null> => {\n if (await sendReply('connected', credentialId)) return null;\n if (mountedRef.current) setUnsent({ credentialId });\n return 'Saved, but the chat did not get it. Tap Send to try again.';\n },\n [sendReply],\n );\n\n /** Leave the busy state with `text` under the actions (null clears it). */\n const settle = useCallback((text: string | null) => {\n if (!mountedRef.current) return;\n setNote(text);\n setBusy(false);\n }, []);\n\n /** Decide from a hand-back and a fresh read against `before`, then reply or say why not. */\n const conclude = useCallback(\n async (\n before: ConnectorConnectBefore,\n handback: ConnectorConnectHandback | null,\n wasConnected: boolean,\n ): Promise<void> => {\n const after = await readVault();\n const decision = decideConnectorConnectOutcome({\n requestId: payload.requestId,\n handback,\n before,\n after: after.ok\n ? { rows: after.rows, match: pickConnectorConnectCredential(after.rows, payload) ?? null }\n : null,\n kind: vaultKind?.id,\n });\n if (decision.kind === 'connected') {\n if (mountedRef.current) setUnverified(null);\n settle(await replyConnected(decision.credentialId));\n return;\n }\n if (!after.ok) {\n if (mountedRef.current) setUnverified(before);\n settle(VERIFY_FAILED_NOTE);\n return;\n }\n if (mountedRef.current) setUnverified(null);\n if (wasConnected) settle('No changes were saved.');\n else if (vaultKind) settle(`The ${vaultKind.noun} was not saved.`);\n else settle(`${name} is not connected yet.`);\n },\n [readVault, payload, replyConnected, settle, vaultKind, name],\n );\n\n const handleAction = useCallback(async () => {\n if (busy) return;\n setBusy(true);\n setNote(null);\n if (unsent) {\n setUnsent(null);\n settle(await replyConnected(unsent.credentialId));\n return;\n }\n if (unverified) {\n await conclude(unverified, null, Boolean(unverified.targetId));\n return;\n }\n if (status === 'failed') {\n // \"Try again\": re-read the status; the action goes live once it answers.\n settle((await readVault()).ok ? null : STATUS_FAILED_NOTE);\n return;\n }\n // Read the vault as it is NOW: the form opens on the credential the server\n // has, and the same read is the \"before\" the result is measured against.\n const now = await readVault();\n if (!now.ok) {\n settle(READ_FAILED_NOTE);\n return;\n }\n const current = pickConnectorConnectCredential(now.rows, payload) ?? null;\n const before = snapshotConnectorCredentials(now.rows, current?.id);\n const url = buildConnectorConnectUrl({\n origin: resolveMobileWebUrl(config.CLIENT_URL, getPackagerHost()),\n payload,\n name,\n // A saved login or entry: open the vault form ON it so the edit (email, username or password, a card's\n // expiry) lands on it instead of on a new duplicate, in the project it lives in (the form refuses an entry\n // from another). A catalog connector's page makes this pick itself, with the template's formId.\n credentialId: vaultKind ? current?.id : undefined,\n projectId: vaultKind ? current?.project?.projectId || projectId : undefined,\n });\n let result: WebBrowser.WebBrowserAuthSessionResult;\n beginConnectorConnectSession(payload.requestId);\n try {\n result = await WebBrowser.openAuthSessionAsync(url, CONNECTOR_CONNECT_APP_RETURN_URL);\n } catch {\n settle('Could not open the page. Try again.');\n return;\n } finally {\n endConnectorConnectSession(payload.requestId);\n }\n const handback = result.type === 'success' ? parseConnectorConnectAppReturnUrl(result.url) : null;\n await conclude(before, handback, Boolean(current));\n }, [\n busy,\n unsent,\n unverified,\n status,\n readVault,\n payload,\n name,\n vaultKind,\n projectId,\n conclude,\n replyConnected,\n settle,\n ]);\n\n /**\n * A hand-back that reached the app while no browser session of this card was\n * waiting for it: Android can kill the app behind Custom Tabs, and the return\n * page then cold-starts it with the scheme URL. Anyone can open that URL, so\n * the credential it names is only taken once a fresh read shows it is one this\n * request could have saved, saved just now (parkedHandbackCredential).\n *\n * On a cold start the card mounts before the org is known and cannot read the\n * vault yet, so the hand-back stays parked until a read answers: it is looked\n * at again whenever the status read settles.\n */\n const adoptingRef = useRef(false);\n const adoptParkedHandback = useCallback(async () => {\n if (busy || unsent || !variables || adoptingRef.current) return;\n const handback = peekConnectorConnectHandback(payload.requestId);\n if (!handback?.credentialId) return;\n adoptingRef.current = true;\n try {\n setBusy(true);\n setNote(null);\n const now = await readVault();\n if (!now.ok) {\n // Left parked: the next settled status read tries again.\n settle(null);\n return;\n }\n takeConnectorConnectHandback(payload.requestId);\n if (!parkedHandbackCredential(now.rows, payload, handback.credentialId, Date.now())) {\n settle(null);\n return;\n }\n settle(await replyConnected(handback.credentialId));\n } finally {\n adoptingRef.current = false;\n }\n }, [busy, unsent, variables, payload, readVault, replyConnected, settle]);\n\n const adoptRef = useRef(adoptParkedHandback);\n useEffect(() => {\n adoptRef.current = adoptParkedHandback;\n }, [adoptParkedHandback]);\n useEffect(\n () =>\n subscribeConnectorConnectHandbacks(() => {\n adoptRef.current().catch(() => undefined);\n }),\n [],\n );\n useEffect(() => {\n if (status === 'checking') return;\n adoptRef.current().catch(() => undefined);\n }, [status]);\n\n const handleDismiss = useCallback(async () => {\n if (busy) return;\n setBusy(true);\n settle((await sendReply('declined')) ? null : SEND_FAILED_NOTE);\n }, [busy, sendReply, settle]);\n\n const onActionPress = useCallback(() => {\n handleAction().catch(() => settle(READ_FAILED_NOTE));\n }, [handleAction, settle]);\n const onDismissPress = useCallback(() => {\n handleDismiss().catch(() => settle(SEND_FAILED_NOTE));\n }, [handleDismiss, settle]);\n\n let actionLabel = connectorConnectActionLabel(payload, connected);\n if (unsent) actionLabel = 'Send';\n else if (unverified) actionLabel = 'Check';\n else if (status === 'failed') actionLabel = 'Try again';\n const statusNote = status === 'failed' && !unsent && !unverified ? STATUS_FAILED_NOTE : null;\n\n return (\n <ConnectorConnectCard\n name={name}\n reason={connectorConnectReason(payload, name, connected)}\n icon={vaultKind?.mobileIcon ?? 'power-plug-outline'}\n connected={connected}\n // A saved card or address is not a connection.\n connectedLabel={vaultKind?.autofill ? 'Saved' : undefined}\n actionLabel={actionLabel}\n busy={busy}\n actionPending={!busy && !unsent && !unverified && status === 'checking'}\n note={note ?? statusNote}\n isDark={isDark}\n onAction={onActionPress}\n onDismiss={onDismissPress}\n />\n );\n}\n\n/**\n * The card for the connect request still waiting in `messages`, if any - the\n * one piece both chat screens (the main chat, and the host screens of the native\n * surface chats) render above their composer.\n *\n * The reply goes out through the screen's ordinary send path, as an ASK_USER\n * answer does, and lands in the thread as a user message; that message is what\n * settles the request, so a reloaded thread does not bring the card back\n * (pendingConnectorConnect). The local mark only bridges the moment between the\n * send and the reply showing up, and is keyed on the message as well as the\n * request id, so the same id-less marker in a later turn still gets its card.\n */\nexport function PendingConnectorConnectCard({\n messages,\n send,\n isDark = false,\n style,\n}: {\n /** The raw thread, outbox rows included - a queued reply settles its request too. */\n messages: ReadonlyArray<{ role: string; content: string }>;\n /** Send `text` as the user's next message; resolves false when it could not go out. */\n send: (text: string) => Promise<boolean>;\n isDark?: boolean;\n style?: StyleProp<ViewStyle>;\n}) {\n const pending = useMemo(() => pendingConnectorConnect(messages), [messages]);\n const key = pending ? connectorConnectKey(pending) : null;\n const [resolved, setResolved] = useState<Record<string, boolean>>({});\n\n const handleResolve = useCallback(\n async (outcome: ConnectorConnectOutcome, credentialId?: string): Promise<boolean> => {\n if (!pending || !key) return false;\n const sent = await send(buildConnectorReply(pending.payload.requestId, outcome, credentialId));\n if (!sent) return false;\n setResolved((prev) => ({ ...prev, [key]: true }));\n return true;\n },\n [pending, key, send],\n );\n\n if (!pending || !key || resolved[key]) return null;\n return (\n <View style={style}>\n <ConnectorConnectPrompt key={key} payload={pending.payload} isDark={isDark} onResolve={handleResolve} />\n </View>\n );\n}\n"],"names":["_a","_b"],"mappings":"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"}
1
+ {"version":3,"file":"ConnectorConnectPrompt.js","sources":["../../../src/features/chat/ConnectorConnectPrompt.tsx"],"sourcesContent":["/**\n * <ConnectorConnectPrompt> - owns one `[CONNECTOR_CONNECT]` card: whether the\n * connection is already saved, the web page the action opens, and the reply.\n *\n * The phone cannot host the web's inline vault / connector forms, so the action\n * opens the web page in an in-app browser session (expo-web-browser's auth\n * session, which shares the system browser's sign-in with the web app). The vault\n * form's page (a login, a card, an address) hands the saved credential back\n * through the app's scheme URL (see common's CONNECTOR_CONNECT_APP_RETURN_URL);\n * any other connector's page has no way back, so once the browser closes the card\n * re-reads the vault and only a credential the session created or updated counts.\n * Only then does it reply `[CONNECTOR_CONNECTED:<requestId>:<credentialId>]` -\n * never on a closed browser.\n *\n * The action never runs on a guess about what is saved. It stays disabled until\n * the status read has come back from the server, and at the tap the vault is read\n * once more: the form opens ON the saved login (\"Update\", so an email / username\n * or password edit lands on it) or, only when the server says there is none, as a\n * new one. A read that fails opens nothing - offering \"Save login\" then would save\n * a duplicate next to the login the user meant to edit.\n *\n * Status is the same query (the org's credentials, most recently updated first)\n * and the same match (common's matchConnectorCredentials) the web card uses, so a\n * site login's \"Update\" edits the login the web would edit - and the agent signs in\n * with: the one the agent named when it is the org's and fits, else the most\n * recently updated login for the site. An autofill entry's \"Update\" is only ever\n * the entry the agent named; without one the card adds a new entry. Either is\n * edited in the project it lives in. A catalog connector's page is the web card\n * itself, which picks with the template's formId the phone cannot resolve; the\n * phone sends it only the agent's credentialId.\n *\n * A `one-time-code` request is not a connection at all: nothing is saved and no\n * vault is read. It gets its own card (OneTimeCodePrompt), which types the code\n * straight into the page on the person's Computer and answers with the same\n * `[CONNECTOR_CONNECTED:<requestId>]` reply.\n *\n * Host-only (Apollo, redux, expo-web-browser): a surface remote gets this card as\n * a render prop from its host screen (useHostConnectorCard), never by import.\n */\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { View, type StyleProp, type ViewStyle } from 'react-native';\nimport * as WebBrowser from 'expo-web-browser';\nimport {\n buildConnectorReply,\n CONNECTOR_CONNECT_APP_RETURN_URL,\n connectorCredentialsVariables,\n credentialsOfOrg,\n isOneTimeCodeRequest,\n parseConnectorConnectAppReturnUrl,\n vaultKindOf,\n type ConnectorConnectHandback,\n type ConnectorConnectOutcome,\n type ConnectorConnectPayload,\n} from 'common';\nimport { useFormBuilderCredentialsQuery } from 'common/graphql';\nimport { config } from '../../config/env-config';\nimport { getPackagerHost, resolveMobileWebUrl } from '../../bridge/resolveMobileWebUrl';\nimport { usePrerequisiteIds } from '../../hooks/usePrerequisiteIds';\nimport { ConnectorConnectCard } from './ConnectorConnectCard';\nimport {\n buildConnectorConnectUrl,\n connectorConnectActionLabel,\n connectorConnectKey,\n connectorConnectName,\n connectorConnectReason,\n decideConnectorConnectOutcome,\n parkedHandbackCredential,\n pendingConnectorConnect,\n pickConnectorConnectCredential,\n snapshotConnectorCredentials,\n type ConnectorConnectBefore,\n type CredentialVersionRow,\n} from './connectorConnect';\nimport {\n beginConnectorConnectSession,\n endConnectorConnectSession,\n peekConnectorConnectHandback,\n subscribeConnectorConnectHandbacks,\n takeConnectorConnectHandback,\n} from './connectorConnectHandbacks';\nimport { OneTimeCodePrompt } from './OneTimeCodePrompt';\n\n/** The vault as one read returned it; `ok: false` when the read failed. */\ntype VaultRead = { ok: true; rows: CredentialVersionRow[] } | { ok: false };\n\n/** Where the status read stands: the action waits for `ready`. */\ntype StatusState = 'checking' | 'ready' | 'failed';\n\nconst STATUS_FAILED_NOTE = 'Could not check your saved logins. Tap Try again.';\nconst READ_FAILED_NOTE = 'Could not reach your vault. Try again.';\nconst VERIFY_FAILED_NOTE = 'Could not check whether it saved. Tap Check to look again.';\nconst SEND_FAILED_NOTE = 'Could not reach the chat. Try again.';\n\ninterface ConnectorConnectPromptProps {\n payload: ConnectorConnectPayload;\n isDark?: boolean;\n /** Send the reply for this request; resolves false when it could not go out. */\n onResolve: (outcome: ConnectorConnectOutcome, credentialId?: string) => Promise<boolean>;\n}\n\n/** A login, an autofill entry or a catalog connector: what is saved, the page that saves it, and the reply. */\nfunction CredentialConnectPrompt({ payload, isDark = false, onResolve }: ConnectorConnectPromptProps) {\n const { orgName, projectId, loading: idsLoading } = usePrerequisiteIds();\n // A website login or an autofill entry (a card, an address): the web vault form for that kind.\n const vaultKind = vaultKindOf(payload.connector);\n\n // Same query and variables as the web card's useConnectorCredentialMatch (common's\n // connectorCredentialsVariables: the whole org, most recently updated first), so the\n // Apollo cache and the pick agree across the two.\n const variables = useMemo(() => (orgName ? connectorCredentialsVariables(orgName) : null), [orgName]);\n const { data, loading, error, refetch } = useFormBuilderCredentialsQuery({\n variables: variables ?? undefined,\n skip: !variables,\n fetchPolicy: 'cache-and-network',\n });\n // Only this org's rows (credentialsOfOrg): the server deployed today can answer with the caller's rows of\n // every org, and another org's same-named login must never be the one this card edits.\n const listed = data?.formBuilderCredentials?.data as ReadonlyArray<CredentialVersionRow | null> | undefined;\n const cachedRows = useMemo(() => (listed ? credentialsOfOrg(listed, orgName) : undefined), [listed, orgName]);\n\n // `cache-and-network` paints a cached answer first and keeps `loading` until the\n // server answers; a cached \"not saved\" can be stale, so only the server's\n // answer makes the action live.\n let status: StatusState = 'ready';\n if (!variables) status = idsLoading ? 'checking' : 'failed';\n else if (error) status = 'failed';\n else if (loading || !cachedRows) status = 'checking';\n\n const existing = useMemo(\n () => (status === 'ready' && cachedRows ? (pickConnectorConnectCredential(cachedRows, payload) ?? null) : null),\n [status, cachedRows, payload],\n );\n const connected = Boolean(existing);\n const name = connectorConnectName(payload, connected);\n\n const [busy, setBusy] = useState(false);\n const [note, setNote] = useState<string | null>(null);\n // The vault changed but the reply did not go out: the next tap resends the\n // reply instead of reopening the browser.\n const [unsent, setUnsent] = useState<{ credentialId?: string } | null>(null);\n // The browser closed but the vault could not be re-read: the next tap checks\n // again against the same \"before\", instead of reopening the browser.\n const [unverified, setUnverified] = useState<ConnectorConnectBefore | null>(null);\n const mountedRef = useRef(true);\n useEffect(\n () => () => {\n mountedRef.current = false;\n },\n [],\n );\n\n /** The vault as the server has it now (not the cache). */\n const readVault = useCallback(async (): Promise<VaultRead> => {\n if (!variables) return { ok: false };\n try {\n const result = await refetch(variables);\n const rows = result.data?.formBuilderCredentials?.data;\n if (result.error || !Array.isArray(rows)) return { ok: false };\n return { ok: true, rows: credentialsOfOrg(rows as ReadonlyArray<CredentialVersionRow | null>, orgName) };\n } catch {\n return { ok: false };\n }\n }, [variables, refetch, orgName]);\n\n /** Send the reply; a send that throws counts as not sent, so the card stays. */\n const sendReply = useCallback(\n async (outcome: ConnectorConnectOutcome, credentialId?: string): Promise<boolean> => {\n try {\n return await onResolve(outcome, credentialId);\n } catch {\n return false;\n }\n },\n [onResolve],\n );\n\n /** Reply `connected`; on failure keep the result so the next tap only resends. */\n const replyConnected = useCallback(\n async (credentialId: string | undefined): Promise<string | null> => {\n if (await sendReply('connected', credentialId)) return null;\n if (mountedRef.current) setUnsent({ credentialId });\n return 'Saved, but the chat did not get it. Tap Send to try again.';\n },\n [sendReply],\n );\n\n /** Leave the busy state with `text` under the actions (null clears it). */\n const settle = useCallback((text: string | null) => {\n if (!mountedRef.current) return;\n setNote(text);\n setBusy(false);\n }, []);\n\n /** Decide from a hand-back and a fresh read against `before`, then reply or say why not. */\n const conclude = useCallback(\n async (\n before: ConnectorConnectBefore,\n handback: ConnectorConnectHandback | null,\n wasConnected: boolean,\n ): Promise<void> => {\n const after = await readVault();\n const decision = decideConnectorConnectOutcome({\n requestId: payload.requestId,\n handback,\n before,\n after: after.ok\n ? { rows: after.rows, match: pickConnectorConnectCredential(after.rows, payload) ?? null }\n : null,\n kind: vaultKind?.id,\n });\n if (decision.kind === 'connected') {\n if (mountedRef.current) setUnverified(null);\n settle(await replyConnected(decision.credentialId));\n return;\n }\n if (!after.ok) {\n if (mountedRef.current) setUnverified(before);\n settle(VERIFY_FAILED_NOTE);\n return;\n }\n if (mountedRef.current) setUnverified(null);\n if (wasConnected) settle('No changes were saved.');\n else if (vaultKind) settle(`The ${vaultKind.noun} was not saved.`);\n else settle(`${name} is not connected yet.`);\n },\n [readVault, payload, replyConnected, settle, vaultKind, name],\n );\n\n const handleAction = useCallback(async () => {\n if (busy) return;\n setBusy(true);\n setNote(null);\n if (unsent) {\n setUnsent(null);\n settle(await replyConnected(unsent.credentialId));\n return;\n }\n if (unverified) {\n await conclude(unverified, null, Boolean(unverified.targetId));\n return;\n }\n if (status === 'failed') {\n // \"Try again\": re-read the status; the action goes live once it answers.\n settle((await readVault()).ok ? null : STATUS_FAILED_NOTE);\n return;\n }\n // Read the vault as it is NOW: the form opens on the credential the server\n // has, and the same read is the \"before\" the result is measured against.\n const now = await readVault();\n if (!now.ok) {\n settle(READ_FAILED_NOTE);\n return;\n }\n const current = pickConnectorConnectCredential(now.rows, payload) ?? null;\n const before = snapshotConnectorCredentials(now.rows, current?.id);\n const url = buildConnectorConnectUrl({\n origin: resolveMobileWebUrl(config.CLIENT_URL, getPackagerHost()),\n payload,\n name,\n // A saved login or entry: open the vault form ON it so the edit (email, username or password, a card's\n // expiry) lands on it instead of on a new duplicate, in the project it lives in (the form refuses an entry\n // from another). A catalog connector's page makes this pick itself, with the template's formId.\n credentialId: vaultKind ? current?.id : undefined,\n projectId: vaultKind ? current?.project?.projectId || projectId : undefined,\n });\n let result: WebBrowser.WebBrowserAuthSessionResult;\n beginConnectorConnectSession(payload.requestId);\n try {\n result = await WebBrowser.openAuthSessionAsync(url, CONNECTOR_CONNECT_APP_RETURN_URL);\n } catch {\n settle('Could not open the page. Try again.');\n return;\n } finally {\n endConnectorConnectSession(payload.requestId);\n }\n const handback = result.type === 'success' ? parseConnectorConnectAppReturnUrl(result.url) : null;\n await conclude(before, handback, Boolean(current));\n }, [\n busy,\n unsent,\n unverified,\n status,\n readVault,\n payload,\n name,\n vaultKind,\n projectId,\n conclude,\n replyConnected,\n settle,\n ]);\n\n /**\n * A hand-back that reached the app while no browser session of this card was\n * waiting for it: Android can kill the app behind Custom Tabs, and the return\n * page then cold-starts it with the scheme URL. Anyone can open that URL, so\n * the credential it names is only taken once a fresh read shows it is one this\n * request could have saved, saved just now (parkedHandbackCredential).\n *\n * On a cold start the card mounts before the org is known and cannot read the\n * vault yet, so the hand-back stays parked until a read answers: it is looked\n * at again whenever the status read settles.\n */\n const adoptingRef = useRef(false);\n const adoptParkedHandback = useCallback(async () => {\n if (busy || unsent || !variables || adoptingRef.current) return;\n const handback = peekConnectorConnectHandback(payload.requestId);\n if (!handback?.credentialId) return;\n adoptingRef.current = true;\n try {\n setBusy(true);\n setNote(null);\n const now = await readVault();\n if (!now.ok) {\n // Left parked: the next settled status read tries again.\n settle(null);\n return;\n }\n takeConnectorConnectHandback(payload.requestId);\n if (!parkedHandbackCredential(now.rows, payload, handback.credentialId, Date.now())) {\n settle(null);\n return;\n }\n settle(await replyConnected(handback.credentialId));\n } finally {\n adoptingRef.current = false;\n }\n }, [busy, unsent, variables, payload, readVault, replyConnected, settle]);\n\n const adoptRef = useRef(adoptParkedHandback);\n useEffect(() => {\n adoptRef.current = adoptParkedHandback;\n }, [adoptParkedHandback]);\n useEffect(\n () =>\n subscribeConnectorConnectHandbacks(() => {\n adoptRef.current().catch(() => undefined);\n }),\n [],\n );\n useEffect(() => {\n if (status === 'checking') return;\n adoptRef.current().catch(() => undefined);\n }, [status]);\n\n const handleDismiss = useCallback(async () => {\n if (busy) return;\n setBusy(true);\n settle((await sendReply('declined')) ? null : SEND_FAILED_NOTE);\n }, [busy, sendReply, settle]);\n\n const onActionPress = useCallback(() => {\n handleAction().catch(() => settle(READ_FAILED_NOTE));\n }, [handleAction, settle]);\n const onDismissPress = useCallback(() => {\n handleDismiss().catch(() => settle(SEND_FAILED_NOTE));\n }, [handleDismiss, settle]);\n\n let actionLabel = connectorConnectActionLabel(payload, connected);\n if (unsent) actionLabel = 'Send';\n else if (unverified) actionLabel = 'Check';\n else if (status === 'failed') actionLabel = 'Try again';\n const statusNote = status === 'failed' && !unsent && !unverified ? STATUS_FAILED_NOTE : null;\n\n return (\n <ConnectorConnectCard\n name={name}\n reason={connectorConnectReason(payload, name, connected)}\n icon={vaultKind?.mobileIcon ?? 'power-plug-outline'}\n connected={connected}\n // A saved card or address is not a connection.\n connectedLabel={vaultKind?.autofill ? 'Saved' : undefined}\n actionLabel={actionLabel}\n busy={busy}\n actionPending={!busy && !unsent && !unverified && status === 'checking'}\n note={note ?? statusNote}\n isDark={isDark}\n onAction={onActionPress}\n onDismiss={onDismissPress}\n />\n );\n}\n\nexport function ConnectorConnectPrompt(props: ConnectorConnectPromptProps) {\n // A code saves nothing and is never matched against the vault: its card only types it into the page.\n if (isOneTimeCodeRequest(props.payload)) return <OneTimeCodePrompt {...props} />;\n return <CredentialConnectPrompt {...props} />;\n}\n\n/**\n * The card for the connect request still waiting in `messages`, if any - the\n * one piece both chat screens (the main chat, and the host screens of the native\n * surface chats) render above their composer.\n *\n * The reply goes out through the screen's ordinary send path, as an ASK_USER\n * answer does, and lands in the thread as a user message; that message is what\n * settles the request, so a reloaded thread does not bring the card back\n * (pendingConnectorConnect). The local mark only bridges the moment between the\n * send and the reply showing up, and is keyed on the message as well as the\n * request id, so the same id-less marker in a later turn still gets its card.\n */\nexport function PendingConnectorConnectCard({\n messages,\n send,\n isDark = false,\n style,\n}: {\n /** The raw thread, outbox rows included - a queued reply settles its request too. */\n messages: ReadonlyArray<{ role: string; content: string }>;\n /** Send `text` as the user's next message; resolves false when it could not go out. */\n send: (text: string) => Promise<boolean>;\n isDark?: boolean;\n style?: StyleProp<ViewStyle>;\n}) {\n const pending = useMemo(() => pendingConnectorConnect(messages), [messages]);\n const key = pending ? connectorConnectKey(pending) : null;\n const [resolved, setResolved] = useState<Record<string, boolean>>({});\n\n const handleResolve = useCallback(\n async (outcome: ConnectorConnectOutcome, credentialId?: string): Promise<boolean> => {\n if (!pending || !key) return false;\n const sent = await send(buildConnectorReply(pending.payload.requestId, outcome, credentialId));\n if (!sent) return false;\n setResolved((prev) => ({ ...prev, [key]: true }));\n return true;\n },\n [pending, key, send],\n );\n\n if (!pending || !key || resolved[key]) return null;\n return (\n <View style={style}>\n <ConnectorConnectPrompt key={key} payload={pending.payload} isDark={isDark} onResolve={handleResolve} />\n </View>\n );\n}\n"],"names":["_a","_b"],"mappings":"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"}
@@ -0,0 +1,286 @@
1
+ import {jsx,jsxs}from'react/jsx-runtime';import {memo,useMemo}from'react';import {Pressable,StyleSheet,ActivityIndicator,Text,View,TextInput}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {ONE_TIME_CODE_MAX_LENGTH}from'common';const ACCENT = "#2563eb";
2
+ const styles = StyleSheet.create({
3
+ card: {
4
+ width: "100%",
5
+ borderWidth: 1,
6
+ borderRadius: 16,
7
+ padding: 14,
8
+ marginTop: 4,
9
+ marginBottom: 8
10
+ },
11
+ row: {
12
+ flexDirection: "row",
13
+ alignItems: "flex-start",
14
+ gap: 12
15
+ },
16
+ icon: {
17
+ width: 36,
18
+ height: 36,
19
+ borderRadius: 10,
20
+ alignItems: "center",
21
+ justifyContent: "center"
22
+ },
23
+ body: {
24
+ flex: 1,
25
+ minWidth: 0
26
+ },
27
+ title: {
28
+ fontSize: 15,
29
+ fontWeight: "700",
30
+ lineHeight: 20
31
+ },
32
+ reason: {
33
+ fontSize: 13,
34
+ lineHeight: 18,
35
+ marginTop: 2
36
+ },
37
+ close: {
38
+ width: 32,
39
+ height: 32,
40
+ borderRadius: 16,
41
+ alignItems: "center",
42
+ justifyContent: "center",
43
+ marginTop: -2,
44
+ marginRight: -4
45
+ },
46
+ input: {
47
+ borderWidth: 1,
48
+ borderRadius: 12,
49
+ paddingHorizontal: 14,
50
+ marginTop: 12,
51
+ minHeight: 48,
52
+ fontSize: 17,
53
+ fontWeight: "600",
54
+ fontVariant: ["tabular-nums"]
55
+ },
56
+ inputSpaced: {
57
+ letterSpacing: 3
58
+ },
59
+ problemRow: {
60
+ flexDirection: "row",
61
+ flexWrap: "wrap",
62
+ alignItems: "center",
63
+ marginTop: 8,
64
+ columnGap: 8
65
+ },
66
+ problem: {
67
+ fontSize: 12.5,
68
+ lineHeight: 17,
69
+ flexShrink: 1
70
+ },
71
+ link: {
72
+ flexDirection: "row",
73
+ alignItems: "center",
74
+ gap: 4,
75
+ minHeight: 32
76
+ },
77
+ linkText: {
78
+ fontSize: 12.5,
79
+ fontWeight: "700"
80
+ },
81
+ actions: {
82
+ flexDirection: "row",
83
+ alignItems: "center",
84
+ justifyContent: "flex-end",
85
+ marginTop: 12,
86
+ gap: 4
87
+ },
88
+ secondary: {
89
+ paddingHorizontal: 12,
90
+ minHeight: 44,
91
+ justifyContent: "center",
92
+ marginRight: "auto"
93
+ },
94
+ secondaryText: {
95
+ fontSize: 13,
96
+ fontWeight: "600"
97
+ },
98
+ primary: {
99
+ paddingHorizontal: 18,
100
+ borderRadius: 12,
101
+ minHeight: 44,
102
+ minWidth: 104,
103
+ flexDirection: "row",
104
+ gap: 6,
105
+ alignItems: "center",
106
+ justifyContent: "center"
107
+ },
108
+ primaryText: {
109
+ fontSize: 14,
110
+ fontWeight: "700",
111
+ color: "#ffffff"
112
+ },
113
+ dimmed: {
114
+ opacity: 0.45
115
+ },
116
+ pressed: {
117
+ opacity: 0.75
118
+ },
119
+ note: {
120
+ fontSize: 12,
121
+ lineHeight: 16,
122
+ marginTop: 6,
123
+ textAlign: "right"
124
+ },
125
+ // Left-aligned beside the shield: on a phone the line wraps, and a centred two-line block beside an icon reads
126
+ // as two things.
127
+ hintRow: {
128
+ flexDirection: "row",
129
+ alignItems: "flex-start",
130
+ gap: 6,
131
+ marginTop: 12,
132
+ paddingTop: 10,
133
+ borderTopWidth: StyleSheet.hairlineWidth
134
+ },
135
+ hintIcon: {
136
+ marginTop: 1
137
+ },
138
+ hint: {
139
+ fontSize: 11.5,
140
+ lineHeight: 16,
141
+ flexShrink: 1
142
+ }
143
+ });
144
+ function OneTimeCodeCardView({
145
+ title,
146
+ reason,
147
+ hint,
148
+ enterable,
149
+ code,
150
+ codeEditable = true,
151
+ onChangeCode,
152
+ digits,
153
+ ready,
154
+ actionLabel,
155
+ busy,
156
+ problem,
157
+ note,
158
+ canOpenComputer,
159
+ showDone,
160
+ isDark = false,
161
+ onSubmit,
162
+ onOpenComputer,
163
+ onDone,
164
+ onDismiss
165
+ }) {
166
+ const palette = useMemo(() => ({
167
+ card: isDark ? "#111827" : "#ffffff",
168
+ border: isDark ? "#1f2937" : "#e5e7eb",
169
+ title: isDark ? "#f1f5f9" : "#111827",
170
+ muted: isDark ? "#94a3b8" : "#6b7280",
171
+ iconBg: isDark ? "#1e293b" : "#f3f4f6",
172
+ fieldBg: isDark ? "#0b1220" : "#f9fafb",
173
+ fieldBorder: isDark ? "#243045" : "#e5e7eb",
174
+ danger: isDark ? "#fca5a5" : "#b91c1c",
175
+ dangerBorder: isDark ? "#f87171" : "#dc2626"
176
+ }), [isDark]);
177
+ const numeric = Boolean(digits);
178
+ const primaryDisabled = busy || enterable && !ready;
179
+ const placeholder = digits ? `${digits}-digit code` : "Code";
180
+ let primary = null;
181
+ if (enterable) {
182
+ primary = /* @__PURE__ */ jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: busy ? "Entering the code" : `${actionLabel}, ${title}`, accessibilityState: {
183
+ disabled: primaryDisabled,
184
+ busy
185
+ }, onPress: onSubmit, disabled: primaryDisabled, style: ({
186
+ pressed
187
+ }) => [styles.primary, {
188
+ backgroundColor: ACCENT
189
+ }, pressed && styles.pressed, primaryDisabled && !busy && styles.dimmed], children: busy ? /* @__PURE__ */ jsx(ActivityIndicator, { size: "small", color: "#ffffff" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryText, children: actionLabel }) });
190
+ } else if (canOpenComputer) {
191
+ primary = /* @__PURE__ */ jsxs(Pressable, { accessibilityRole: "button", onPress: onOpenComputer, disabled: busy, style: ({
192
+ pressed
193
+ }) => [styles.primary, {
194
+ backgroundColor: ACCENT
195
+ }, pressed && styles.pressed], children: [
196
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "monitor", size: 16, color: "#ffffff" }),
197
+ /* @__PURE__ */ jsx(Text, { style: styles.primaryText, children: "Open my Computer" })
198
+ ] });
199
+ }
200
+ return /* @__PURE__ */ jsxs(View, { style: [styles.card, {
201
+ backgroundColor: palette.card,
202
+ borderColor: palette.border
203
+ }], children: [
204
+ /* @__PURE__ */ jsxs(View, { style: styles.row, children: [
205
+ /* @__PURE__ */ jsx(View, { style: [styles.icon, {
206
+ backgroundColor: palette.iconBg
207
+ }], children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "lock-outline", size: 18, color: palette.muted }) }),
208
+ /* @__PURE__ */ jsxs(View, { style: styles.body, children: [
209
+ /* @__PURE__ */ jsx(Text, { style: [styles.title, {
210
+ color: palette.title
211
+ }], numberOfLines: 2, children: title }),
212
+ reason ? /* @__PURE__ */ jsx(Text, { style: [styles.reason, {
213
+ color: palette.muted
214
+ }], children: reason }) : null
215
+ ] }),
216
+ /* @__PURE__ */ jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Close", accessibilityState: {
217
+ disabled: busy
218
+ }, onPress: onDismiss, disabled: busy, hitSlop: 8, style: ({
219
+ pressed
220
+ }) => [styles.close, {
221
+ backgroundColor: palette.iconBg
222
+ }, (pressed || busy) && styles.pressed], children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "close", size: 16, color: palette.muted }) })
223
+ ] }),
224
+ enterable ? /* @__PURE__ */ jsx(
225
+ TextInput,
226
+ {
227
+ value: code,
228
+ onChangeText: onChangeCode,
229
+ editable: !busy && codeEditable,
230
+ accessibilityLabel: title,
231
+ accessibilityHint: reason,
232
+ placeholder,
233
+ placeholderTextColor: palette.muted,
234
+ textContentType: "oneTimeCode",
235
+ autoComplete: "sms-otp",
236
+ importantForAutofill: "yes",
237
+ keyboardType: numeric ? "number-pad" : "default",
238
+ autoCapitalize: numeric ? "none" : "characters",
239
+ autoCorrect: false,
240
+ spellCheck: false,
241
+ maxLength: ONE_TIME_CODE_MAX_LENGTH + 8,
242
+ returnKeyType: "go",
243
+ enablesReturnKeyAutomatically: true,
244
+ onSubmitEditing: onSubmit,
245
+ style: [styles.input, code ? styles.inputSpaced : null, {
246
+ backgroundColor: palette.fieldBg,
247
+ borderColor: problem ? palette.dangerBorder : palette.fieldBorder,
248
+ color: palette.title
249
+ }]
250
+ }
251
+ ) : null,
252
+ problem ? /* @__PURE__ */ jsxs(View, { style: styles.problemRow, accessibilityLiveRegion: "polite", children: [
253
+ /* @__PURE__ */ jsx(Text, { accessibilityRole: "alert", style: [styles.problem, {
254
+ color: palette.danger
255
+ }], children: problem }),
256
+ enterable && canOpenComputer ? /* @__PURE__ */ jsxs(Pressable, { accessibilityRole: "button", onPress: onOpenComputer, disabled: busy, hitSlop: 6, style: ({
257
+ pressed
258
+ }) => [styles.link, pressed && styles.pressed], children: [
259
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "monitor", size: 14, color: palette.title }),
260
+ /* @__PURE__ */ jsx(Text, { style: [styles.linkText, {
261
+ color: palette.title
262
+ }], children: "Open my Computer" })
263
+ ] }) : null
264
+ ] }) : null,
265
+ /* @__PURE__ */ jsxs(View, { style: styles.actions, children: [
266
+ showDone ? /* @__PURE__ */ jsx(Pressable, { accessibilityRole: "button", accessibilityHint: "Tells your assistant to check the page again", onPress: onDone, disabled: busy, hitSlop: 6, style: ({
267
+ pressed
268
+ }) => [styles.secondary, pressed && styles.pressed], children: /* @__PURE__ */ jsx(Text, { style: [styles.secondaryText, {
269
+ color: palette.muted
270
+ }], children: "Done on my Computer" }) }) : null,
271
+ primary
272
+ ] }),
273
+ note ? /* @__PURE__ */ jsx(Text, { style: [styles.note, {
274
+ color: palette.muted
275
+ }], children: note }) : null,
276
+ /* @__PURE__ */ jsxs(View, { style: [styles.hintRow, {
277
+ borderTopColor: palette.border
278
+ }], children: [
279
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "shield-check-outline", size: 14, color: palette.muted, style: styles.hintIcon }),
280
+ /* @__PURE__ */ jsx(Text, { style: [styles.hint, {
281
+ color: palette.muted
282
+ }], children: hint })
283
+ ] })
284
+ ] });
285
+ }
286
+ const OneTimeCodeCard = memo(OneTimeCodeCardView);export{OneTimeCodeCard};//# sourceMappingURL=OneTimeCodeCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OneTimeCodeCard.js","sources":["../../../src/features/chat/OneTimeCodeCard.tsx"],"sourcesContent":["/**\n * <OneTimeCodeCard> - a `one-time-code` request as a touch card.\n *\n * Phone twin of the web OneTimeCodeCard, in the house look of the connect card\n * beside it: a lock, the agent's title (\"Amazon.in email OTP\"), the page's own\n * hint (\"Sent to s******@gmail.com\"), one code field, Continue, and a close\n * button that declines. The field is the OS's one-time-code field, so iOS\n * offers the code from Messages above the keyboard and Android's SMS autofill\n * fills it; a number pad when the page says the code is all digits.\n *\n * When the code could not be entered the reason sits under the field, the code\n * stays typed, and \"Open my Computer\" offers the page itself. Once the person\n * has been there, \"Done on my Computer\" tells the agent to look again.\n *\n * Presentational only: the code, the Computer call and the reply live in\n * OneTimeCodePrompt.\n */\nimport React, { memo, useMemo } from 'react';\nimport { ActivityIndicator, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { ONE_TIME_CODE_MAX_LENGTH } from 'common';\n\nconst ACCENT = '#2563eb';\n\nconst styles = StyleSheet.create({\n card: {\n width: '100%',\n borderWidth: 1,\n borderRadius: 16,\n padding: 14,\n marginTop: 4,\n marginBottom: 8,\n },\n row: { flexDirection: 'row', alignItems: 'flex-start', gap: 12 },\n icon: { width: 36, height: 36, borderRadius: 10, alignItems: 'center', justifyContent: 'center' },\n body: { flex: 1, minWidth: 0 },\n title: { fontSize: 15, fontWeight: '700', lineHeight: 20 },\n reason: { fontSize: 13, lineHeight: 18, marginTop: 2 },\n close: {\n width: 32,\n height: 32,\n borderRadius: 16,\n alignItems: 'center',\n justifyContent: 'center',\n marginTop: -2,\n marginRight: -4,\n },\n input: {\n borderWidth: 1,\n borderRadius: 12,\n paddingHorizontal: 14,\n marginTop: 12,\n minHeight: 48,\n fontSize: 17,\n fontWeight: '600',\n fontVariant: ['tabular-nums'],\n },\n inputSpaced: { letterSpacing: 3 },\n problemRow: { flexDirection: 'row', flexWrap: 'wrap', alignItems: 'center', marginTop: 8, columnGap: 8 },\n problem: { fontSize: 12.5, lineHeight: 17, flexShrink: 1 },\n link: { flexDirection: 'row', alignItems: 'center', gap: 4, minHeight: 32 },\n linkText: { fontSize: 12.5, fontWeight: '700' },\n actions: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'flex-end',\n marginTop: 12,\n gap: 4,\n },\n secondary: { paddingHorizontal: 12, minHeight: 44, justifyContent: 'center', marginRight: 'auto' },\n secondaryText: { fontSize: 13, fontWeight: '600' },\n primary: {\n paddingHorizontal: 18,\n borderRadius: 12,\n minHeight: 44,\n minWidth: 104,\n flexDirection: 'row',\n gap: 6,\n alignItems: 'center',\n justifyContent: 'center',\n },\n primaryText: { fontSize: 14, fontWeight: '700', color: '#ffffff' },\n dimmed: { opacity: 0.45 },\n pressed: { opacity: 0.75 },\n note: { fontSize: 12, lineHeight: 16, marginTop: 6, textAlign: 'right' },\n // Left-aligned beside the shield: on a phone the line wraps, and a centred two-line block beside an icon reads\n // as two things.\n hintRow: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n gap: 6,\n marginTop: 12,\n paddingTop: 10,\n borderTopWidth: StyleSheet.hairlineWidth,\n },\n hintIcon: { marginTop: 1 },\n hint: { fontSize: 11.5, lineHeight: 16, flexShrink: 1 },\n});\n\nexport interface OneTimeCodeCardProps {\n title: string;\n /** The page's own hint, as the agent copied it (\"Sent to s******@gmail.com\"). */\n reason?: string;\n /** Where the code goes and where it never goes, one line at the foot of the card. */\n hint: string;\n /** The card can type the code for the person; false = the Computer is the only way to finish. */\n enterable: boolean;\n code: string;\n /** False once the code is on the page: only the reply is left. */\n codeEditable?: boolean;\n onChangeCode: (code: string) => void;\n /** The code has this many characters (the page says so): a number pad, and the placeholder says how many. */\n digits?: number;\n /** What was typed is a code: Continue can go. */\n ready: boolean;\n /** \"Continue\", or \"Send\" when the code is on the page but the reply still has to go out. */\n actionLabel: string;\n busy: boolean;\n /** Why the code could not be entered, under the field. */\n problem: string | null;\n /** One line under the actions, e.g. why the reply did not reach the chat. */\n note?: string | null;\n /** Offer the Computer itself: after a failure, or as the only action when the card cannot type. */\n canOpenComputer: boolean;\n /** The person went to the Computer: offer \"Done on my Computer\". */\n showDone: boolean;\n isDark?: boolean;\n onSubmit: () => void;\n onOpenComputer: () => void;\n onDone: () => void;\n onDismiss: () => void;\n}\n\nfunction OneTimeCodeCardView({\n title,\n reason,\n hint,\n enterable,\n code,\n codeEditable = true,\n onChangeCode,\n digits,\n ready,\n actionLabel,\n busy,\n problem,\n note,\n canOpenComputer,\n showDone,\n isDark = false,\n onSubmit,\n onOpenComputer,\n onDone,\n onDismiss,\n}: OneTimeCodeCardProps) {\n const palette = useMemo(\n () => ({\n card: isDark ? '#111827' : '#ffffff',\n border: isDark ? '#1f2937' : '#e5e7eb',\n title: isDark ? '#f1f5f9' : '#111827',\n muted: isDark ? '#94a3b8' : '#6b7280',\n iconBg: isDark ? '#1e293b' : '#f3f4f6',\n fieldBg: isDark ? '#0b1220' : '#f9fafb',\n fieldBorder: isDark ? '#243045' : '#e5e7eb',\n danger: isDark ? '#fca5a5' : '#b91c1c',\n dangerBorder: isDark ? '#f87171' : '#dc2626',\n }),\n [isDark],\n );\n const numeric = Boolean(digits);\n const primaryDisabled = busy || (enterable && !ready);\n const placeholder = digits ? `${digits}-digit code` : 'Code';\n\n // Without the page coordinates the card cannot type: opening the Computer is the action.\n let primary: React.ReactNode = null;\n if (enterable) {\n primary = (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={busy ? 'Entering the code' : `${actionLabel}, ${title}`}\n accessibilityState={{ disabled: primaryDisabled, busy }}\n onPress={onSubmit}\n disabled={primaryDisabled}\n style={({ pressed }) => [\n styles.primary,\n { backgroundColor: ACCENT },\n pressed && styles.pressed,\n primaryDisabled && !busy && styles.dimmed,\n ]}\n >\n {busy ? (\n <ActivityIndicator size=\"small\" color=\"#ffffff\" />\n ) : (\n <Text style={styles.primaryText}>{actionLabel}</Text>\n )}\n </Pressable>\n );\n } else if (canOpenComputer) {\n primary = (\n <Pressable\n accessibilityRole=\"button\"\n onPress={onOpenComputer}\n disabled={busy}\n style={({ pressed }) => [styles.primary, { backgroundColor: ACCENT }, pressed && styles.pressed]}\n >\n <MaterialCommunityIcons name=\"monitor\" size={16} color=\"#ffffff\" />\n <Text style={styles.primaryText}>Open my Computer</Text>\n </Pressable>\n );\n }\n\n return (\n <View style={[styles.card, { backgroundColor: palette.card, borderColor: palette.border }]}>\n <View style={styles.row}>\n <View style={[styles.icon, { backgroundColor: palette.iconBg }]}>\n <MaterialCommunityIcons name=\"lock-outline\" size={18} color={palette.muted} />\n </View>\n <View style={styles.body}>\n <Text style={[styles.title, { color: palette.title }]} numberOfLines={2}>\n {title}\n </Text>\n {reason ? <Text style={[styles.reason, { color: palette.muted }]}>{reason}</Text> : null}\n </View>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Close\"\n accessibilityState={{ disabled: busy }}\n onPress={onDismiss}\n disabled={busy}\n hitSlop={8}\n style={({ pressed }) => [\n styles.close,\n { backgroundColor: palette.iconBg },\n (pressed || busy) && styles.pressed,\n ]}\n >\n <MaterialCommunityIcons name=\"close\" size={16} color={palette.muted} />\n </Pressable>\n </View>\n\n {enterable ? (\n <TextInput\n value={code}\n onChangeText={onChangeCode}\n editable={!busy && codeEditable}\n accessibilityLabel={title}\n accessibilityHint={reason}\n placeholder={placeholder}\n placeholderTextColor={palette.muted}\n // The OS's one-time-code field: iOS offers the code from Messages above the keyboard, Android's\n // SMS autofill fills it.\n textContentType=\"oneTimeCode\"\n autoComplete=\"sms-otp\"\n importantForAutofill=\"yes\"\n keyboardType={numeric ? 'number-pad' : 'default'}\n autoCapitalize={numeric ? 'none' : 'characters'}\n autoCorrect={false}\n spellCheck={false}\n // Room for the spaces and dashes a code is read out with; they come out before it is typed.\n maxLength={ONE_TIME_CODE_MAX_LENGTH + 8}\n returnKeyType=\"go\"\n enablesReturnKeyAutomatically\n onSubmitEditing={onSubmit}\n style={[\n styles.input,\n code ? styles.inputSpaced : null,\n {\n backgroundColor: palette.fieldBg,\n borderColor: problem ? palette.dangerBorder : palette.fieldBorder,\n color: palette.title,\n },\n ]}\n />\n ) : null}\n\n {problem ? (\n <View style={styles.problemRow} accessibilityLiveRegion=\"polite\">\n <Text accessibilityRole=\"alert\" style={[styles.problem, { color: palette.danger }]}>\n {problem}\n </Text>\n {enterable && canOpenComputer ? (\n <Pressable\n accessibilityRole=\"button\"\n onPress={onOpenComputer}\n disabled={busy}\n hitSlop={6}\n style={({ pressed }) => [styles.link, pressed && styles.pressed]}\n >\n <MaterialCommunityIcons name=\"monitor\" size={14} color={palette.title} />\n <Text style={[styles.linkText, { color: palette.title }]}>Open my Computer</Text>\n </Pressable>\n ) : null}\n </View>\n ) : null}\n\n <View style={styles.actions}>\n {showDone ? (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityHint=\"Tells your assistant to check the page again\"\n onPress={onDone}\n disabled={busy}\n hitSlop={6}\n style={({ pressed }) => [styles.secondary, pressed && styles.pressed]}\n >\n <Text style={[styles.secondaryText, { color: palette.muted }]}>Done on my Computer</Text>\n </Pressable>\n ) : null}\n {primary}\n </View>\n {note ? <Text style={[styles.note, { color: palette.muted }]}>{note}</Text> : null}\n\n <View style={[styles.hintRow, { borderTopColor: palette.border }]}>\n <MaterialCommunityIcons\n name=\"shield-check-outline\"\n size={14}\n color={palette.muted}\n style={styles.hintIcon}\n />\n <Text style={[styles.hint, { color: palette.muted }]}>{hint}</Text>\n </View>\n </View>\n );\n}\n\nexport const OneTimeCodeCard = memo(OneTimeCodeCardView);\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ import {jsx}from'react/jsx-runtime';import {useMemo,useState,useRef,useEffect,useCallback}from'react';import {useNavigation}from'@react-navigation/native';import {config}from'../../config/env-config.js';import {openSurfaceInApp}from'../links/openInApp.js';import {OneTimeCodeCard}from'./OneTimeCodeCard.js';import {oneTimeCodeTitle,canEnterOneTimeCode,computerHandoffUrl,oneTimeCodeReady,enterOneTimeCode,COMPUTER_SURFACE_SLUG,oneTimeCodeHint,ONE_TIME_CODE_HANDOFF_REASON}from'./oneTimeCode.js';import {useComputerAction}from'./useComputerAction.js';const SEND_FAILED_NOTE = "Could not reach the chat. Try again.";
2
+ const UNSENT_NOTE = "The code is on the page, but the chat did not get word. Tap Send to try again.";
3
+ function OneTimeCodePrompt({
4
+ payload,
5
+ isDark = false,
6
+ onResolve
7
+ }) {
8
+ var _a, _b;
9
+ const runComputer = useComputerAction();
10
+ const navigation = useNavigation();
11
+ const {
12
+ form
13
+ } = payload;
14
+ const title = oneTimeCodeTitle(payload);
15
+ const enterable = canEnterOneTimeCode(form);
16
+ const handoffUrl = useMemo(() => computerHandoffUrl(config.SURFACE_URL_TEMPLATE, ONE_TIME_CODE_HANDOFF_REASON), []);
17
+ const [code, setCode] = useState("");
18
+ const [busy, setBusy] = useState(false);
19
+ const [feedback, setFeedback] = useState(null);
20
+ const [visitedComputer, setVisitedComputer] = useState(false);
21
+ const [entered, setEntered] = useState(false);
22
+ const inFlight = useRef(false);
23
+ const mounted = useRef(true);
24
+ useEffect(() => () => {
25
+ mounted.current = false;
26
+ }, []);
27
+ const guarded = useCallback(async (work) => {
28
+ if (inFlight.current) return;
29
+ inFlight.current = true;
30
+ setBusy(true);
31
+ setFeedback(null);
32
+ let next;
33
+ try {
34
+ next = await work();
35
+ } catch (e) {
36
+ next = {
37
+ note: SEND_FAILED_NOTE
38
+ };
39
+ }
40
+ inFlight.current = false;
41
+ if (!mounted.current) return;
42
+ setFeedback(next);
43
+ setBusy(false);
44
+ }, []);
45
+ const reply = useCallback(async (outcome) => {
46
+ try {
47
+ return await onResolve(outcome);
48
+ } catch (e) {
49
+ return false;
50
+ }
51
+ }, [onResolve]);
52
+ const handleSubmit = useCallback(() => {
53
+ if (!enterable || !entered && !oneTimeCodeReady(code, form)) return;
54
+ void guarded(async () => {
55
+ if (!entered) {
56
+ const problem = await enterOneTimeCode(runComputer, form, code);
57
+ if (problem) return {
58
+ problem
59
+ };
60
+ if (mounted.current) setEntered(true);
61
+ }
62
+ return await reply("connected") ? null : {
63
+ note: UNSENT_NOTE
64
+ };
65
+ });
66
+ }, [enterable, entered, code, form, guarded, runComputer, reply]);
67
+ const handleDone = useCallback(() => {
68
+ void guarded(async () => await reply("connected") ? null : {
69
+ note: SEND_FAILED_NOTE
70
+ });
71
+ }, [guarded, reply]);
72
+ const handleDismiss = useCallback(() => {
73
+ void guarded(async () => await reply("declined") ? null : {
74
+ note: SEND_FAILED_NOTE
75
+ });
76
+ }, [guarded, reply]);
77
+ const handleOpenComputer = useCallback(() => {
78
+ if (!handoffUrl) return;
79
+ openSurfaceInApp(navigation, {
80
+ surface: COMPUTER_SURFACE_SLUG,
81
+ url: handoffUrl
82
+ });
83
+ setVisitedComputer(true);
84
+ }, [handoffUrl, navigation]);
85
+ const handleChangeCode = useCallback((next) => {
86
+ setCode(next);
87
+ setFeedback((prev) => (prev == null ? void 0 : prev.problem) ? null : prev);
88
+ }, []);
89
+ return /* @__PURE__ */ jsx(
90
+ OneTimeCodeCard,
91
+ {
92
+ title,
93
+ reason: payload.reason,
94
+ hint: oneTimeCodeHint(form),
95
+ enterable,
96
+ code,
97
+ codeEditable: !entered,
98
+ onChangeCode: handleChangeCode,
99
+ digits: form == null ? void 0 : form.digits,
100
+ ready: entered || oneTimeCodeReady(code, form),
101
+ actionLabel: entered ? "Send" : "Continue",
102
+ busy,
103
+ problem: (_a = feedback == null ? void 0 : feedback.problem) != null ? _a : null,
104
+ note: (_b = feedback == null ? void 0 : feedback.note) != null ? _b : null,
105
+ canOpenComputer: Boolean(handoffUrl),
106
+ showDone: visitedComputer && !entered,
107
+ isDark,
108
+ onSubmit: handleSubmit,
109
+ onOpenComputer: handleOpenComputer,
110
+ onDone: handleDone,
111
+ onDismiss: handleDismiss
112
+ }
113
+ );
114
+ }export{OneTimeCodePrompt};//# sourceMappingURL=OneTimeCodePrompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OneTimeCodePrompt.js","sources":["../../../src/features/chat/OneTimeCodePrompt.tsx"],"sourcesContent":["/**\n * <OneTimeCodePrompt> - owns one `one-time-code` card: what the person typed,\n * entering it on their Computer, and the reply.\n *\n * It is the one place a code is typed, and the code never goes where a chat\n * message goes. Continue enters it straight into the page on the person's\n * Computer (common's oneTimeCodeEntry: one YANTRA_COMPUTER_ACT that first\n * proves the page is still on the site the code was sent for, then types it\n * and presses the button the agent named, or Enter), as the signed-in person\n * (useComputerAction). Only then does it answer the agent, with\n * `[CONNECTOR_CONNECTED:<requestId>]` - the request's id and nothing else. The\n * agent reads the page to see whether it worked, so it never learns the code;\n * the transcript never holds it, and nothing here logs it.\n *\n * When the page has moved on (the code box is gone, another site is open)\n * nothing is typed: the card says why, keeps the code, and offers the Computer\n * itself, where the person can finish by hand and then tap \"Done on my\n * Computer\", which sends the same reply - the agent checks the page either way.\n * Close declines (`[CONNECTOR_DECLINED:<requestId>]`), and the agent hands the\n * Computer over instead.\n *\n * Host-only (the agent connection, navigation): rendered by\n * ConnectorConnectPrompt for a code request, never imported by a remote.\n */\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useNavigation, type NavigationProp, type ParamListBase } from '@react-navigation/native';\nimport type { ConnectorConnectOutcome, ConnectorConnectPayload } from 'common';\nimport { config } from '../../config/env-config';\nimport { openSurfaceInApp } from '../links/openInApp';\nimport { OneTimeCodeCard } from './OneTimeCodeCard';\nimport {\n canEnterOneTimeCode,\n COMPUTER_SURFACE_SLUG,\n computerHandoffUrl,\n enterOneTimeCode,\n ONE_TIME_CODE_HANDOFF_REASON,\n oneTimeCodeHint,\n oneTimeCodeReady,\n oneTimeCodeTitle,\n} from './oneTimeCode';\nimport { useComputerAction } from './useComputerAction';\n\nconst SEND_FAILED_NOTE = 'Could not reach the chat. Try again.';\nconst UNSENT_NOTE = 'The code is on the page, but the chat did not get word. Tap Send to try again.';\n\n/** What the card says after a tap: why the code could not be entered, or why the reply did not go out. */\ntype Feedback = { problem?: string; note?: string } | null;\n\nexport function OneTimeCodePrompt({\n payload,\n isDark = false,\n onResolve,\n}: {\n payload: ConnectorConnectPayload;\n isDark?: boolean;\n /** Send the reply for this request; resolves false when it could not go out. */\n onResolve: (outcome: ConnectorConnectOutcome) => Promise<boolean>;\n}) {\n const runComputer = useComputerAction();\n const navigation = useNavigation<NavigationProp<ParamListBase>>();\n const { form } = payload;\n const title = oneTimeCodeTitle(payload);\n const enterable = canEnterOneTimeCode(form);\n const handoffUrl = useMemo(() => computerHandoffUrl(config.SURFACE_URL_TEMPLATE, ONE_TIME_CODE_HANDOFF_REASON), []);\n\n const [code, setCode] = useState('');\n const [busy, setBusy] = useState(false);\n const [feedback, setFeedback] = useState<Feedback>(null);\n const [visitedComputer, setVisitedComputer] = useState(false);\n // The code is on the page but the reply did not go out: the next tap only resends it, and never types twice.\n const [entered, setEntered] = useState(false);\n const inFlight = useRef(false);\n const mounted = useRef(true);\n useEffect(\n () => () => {\n mounted.current = false;\n },\n [],\n );\n\n /**\n * One tap at a time. `work` returns what the card says afterwards: a `problem` with entering the code (under\n * the field, beside \"Open my Computer\"), or a `note` about the reply (under the actions); null clears both.\n */\n const guarded = useCallback(async (work: () => Promise<Feedback>) => {\n if (inFlight.current) return;\n inFlight.current = true;\n setBusy(true);\n setFeedback(null);\n let next: Feedback;\n try {\n next = await work();\n } catch {\n next = { note: SEND_FAILED_NOTE };\n }\n inFlight.current = false;\n if (!mounted.current) return;\n setFeedback(next);\n setBusy(false);\n }, []);\n\n /** Send the reply; a send that throws counts as not sent, so the card stays. */\n const reply = useCallback(\n async (outcome: ConnectorConnectOutcome): Promise<boolean> => {\n try {\n return await onResolve(outcome);\n } catch {\n return false;\n }\n },\n [onResolve],\n );\n\n const handleSubmit = useCallback(() => {\n if (!enterable || (!entered && !oneTimeCodeReady(code, form))) return;\n void guarded(async () => {\n if (!entered) {\n const problem = await enterOneTimeCode(runComputer, form, code);\n if (problem) return { problem };\n if (mounted.current) setEntered(true);\n }\n return (await reply('connected')) ? null : { note: UNSENT_NOTE };\n });\n }, [enterable, entered, code, form, guarded, runComputer, reply]);\n\n const handleDone = useCallback(() => {\n void guarded(async () => ((await reply('connected')) ? null : { note: SEND_FAILED_NOTE }));\n }, [guarded, reply]);\n\n const handleDismiss = useCallback(() => {\n void guarded(async () => ((await reply('declined')) ? null : { note: SEND_FAILED_NOTE }));\n }, [guarded, reply]);\n\n const handleOpenComputer = useCallback(() => {\n if (!handoffUrl) return;\n openSurfaceInApp(navigation, { surface: COMPUTER_SURFACE_SLUG, url: handoffUrl });\n setVisitedComputer(true);\n }, [handoffUrl, navigation]);\n\n const handleChangeCode = useCallback((next: string) => {\n setCode(next);\n // A new code is a new attempt: the reason the last one failed no longer applies.\n setFeedback((prev) => (prev?.problem ? null : prev));\n }, []);\n\n return (\n <OneTimeCodeCard\n title={title}\n reason={payload.reason}\n hint={oneTimeCodeHint(form)}\n enterable={enterable}\n code={code}\n // Once the code is on the page only the reply is left; another code would not be typed.\n codeEditable={!entered}\n onChangeCode={handleChangeCode}\n digits={form?.digits}\n ready={entered || oneTimeCodeReady(code, form)}\n actionLabel={entered ? 'Send' : 'Continue'}\n busy={busy}\n problem={feedback?.problem ?? null}\n note={feedback?.note ?? null}\n canOpenComputer={Boolean(handoffUrl)}\n showDone={visitedComputer && !entered}\n isDark={isDark}\n onSubmit={handleSubmit}\n onOpenComputer={handleOpenComputer}\n onDone={handleDone}\n onDismiss={handleDismiss}\n />\n );\n}\n"],"names":[],"mappings":"siBAgCA,MAAM,gBAAmB,GAAA,sCAAA;AACzB,MAAM,WAAc,GAAA,gFAAA;AAOb,SAAS,iBAAkB,CAAA;AAAA,EAChC,OAAA;AAAA,EACA,MAAS,GAAA,KAAA;AAAA,EACT;AACF,CAKG,EAAA;AAjDH,EAAA,IAAA,EAAA,EAAA,EAAA;AAkDE,EAAA,MAAM,cAAc,iBAAkB,EAAA;AACtC,EAAA,MAAM,aAAa,aAA6C,EAAA;AAChE,EAAM,MAAA;AAAA,IACJ;AAAA,GACE,GAAA,OAAA;AACJ,EAAM,MAAA,KAAA,GAAQ,iBAAiB,OAAO,CAAA;AACtC,EAAM,MAAA,SAAA,GAAY,oBAAoB,IAAI,CAAA;AAC1C,EAAM,MAAA,UAAA,GAAa,QAAQ,MAAM,kBAAA,CAAmB,OAAO,oBAAsB,EAAA,4BAA4B,CAAG,EAAA,EAAE,CAAA;AAClH,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,EAAE,CAAA;AACnC,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AACtC,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAmB,IAAI,CAAA;AACvD,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,SAAS,KAAK,CAAA;AAE5D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5C,EAAM,MAAA,QAAA,GAAW,OAAO,KAAK,CAAA;AAC7B,EAAM,MAAA,OAAA,GAAU,OAAO,IAAI,CAAA;AAC3B,EAAA,SAAA,CAAU,MAAM,MAAM;AACpB,IAAA,OAAA,CAAQ,OAAU,GAAA,KAAA;AAAA,GACpB,EAAG,EAAE,CAAA;AAML,EAAM,MAAA,OAAA,GAAU,WAAY,CAAA,OAAO,IAAkC,KAAA;AACnE,IAAA,IAAI,SAAS,OAAS,EAAA;AACtB,IAAA,QAAA,CAAS,OAAU,GAAA,IAAA;AACnB,IAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,IAAA,WAAA,CAAY,IAAI,CAAA;AAChB,IAAI,IAAA,IAAA;AACJ,IAAI,IAAA;AACF,MAAA,IAAA,GAAO,MAAM,IAAK,EAAA;AAAA,KACZ,CAAA,OAAA,CAAA,EAAA;AACN,MAAO,IAAA,GAAA;AAAA,QACL,IAAM,EAAA;AAAA,OACR;AAAA;AAEF,IAAA,QAAA,CAAS,OAAU,GAAA,KAAA;AACnB,IAAI,IAAA,CAAC,QAAQ,OAAS,EAAA;AACtB,IAAA,WAAA,CAAY,IAAI,CAAA;AAChB,IAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,GACf,EAAG,EAAE,CAAA;AAGL,EAAM,MAAA,KAAA,GAAQ,WAAY,CAAA,OAAO,OAAuD,KAAA;AACtF,IAAI,IAAA;AACF,MAAO,OAAA,MAAM,UAAU,OAAO,CAAA;AAAA,KACxB,CAAA,OAAA,CAAA,EAAA;AACN,MAAO,OAAA,KAAA;AAAA;AACT,GACF,EAAG,CAAC,SAAS,CAAC,CAAA;AACd,EAAM,MAAA,YAAA,GAAe,YAAY,MAAM;AACrC,IAAI,IAAA,CAAC,aAAa,CAAC,OAAA,IAAW,CAAC,gBAAiB,CAAA,IAAA,EAAM,IAAI,CAAG,EAAA;AAC7D,IAAA,KAAK,QAAQ,YAAY;AACvB,MAAA,IAAI,CAAC,OAAS,EAAA;AACZ,QAAA,MAAM,OAAU,GAAA,MAAM,gBAAiB,CAAA,WAAA,EAAa,MAAM,IAAI,CAAA;AAC9D,QAAA,IAAI,SAAgB,OAAA;AAAA,UAClB;AAAA,SACF;AACA,QAAI,IAAA,OAAA,CAAQ,OAAS,EAAA,UAAA,CAAW,IAAI,CAAA;AAAA;AAEtC,MAAA,OAAQ,MAAM,KAAA,CAAM,WAAW,CAAA,GAAK,IAAO,GAAA;AAAA,QACzC,IAAM,EAAA;AAAA,OACR;AAAA,KACD,CAAA;AAAA,GACH,EAAG,CAAC,SAAW,EAAA,OAAA,EAAS,MAAM,IAAM,EAAA,OAAA,EAAS,WAAa,EAAA,KAAK,CAAC,CAAA;AAChE,EAAM,MAAA,UAAA,GAAa,YAAY,MAAM;AACnC,IAAA,KAAK,QAAQ,YAAa,MAAM,KAAM,CAAA,WAAW,IAAK,IAAO,GAAA;AAAA,MAC3D,IAAM,EAAA;AAAA,KACP,CAAA;AAAA,GACA,EAAA,CAAC,OAAS,EAAA,KAAK,CAAC,CAAA;AACnB,EAAM,MAAA,aAAA,GAAgB,YAAY,MAAM;AACtC,IAAA,KAAK,QAAQ,YAAa,MAAM,KAAM,CAAA,UAAU,IAAK,IAAO,GAAA;AAAA,MAC1D,IAAM,EAAA;AAAA,KACP,CAAA;AAAA,GACA,EAAA,CAAC,OAAS,EAAA,KAAK,CAAC,CAAA;AACnB,EAAM,MAAA,kBAAA,GAAqB,YAAY,MAAM;AAC3C,IAAA,IAAI,CAAC,UAAY,EAAA;AACjB,IAAA,gBAAA,CAAiB,UAAY,EAAA;AAAA,MAC3B,OAAS,EAAA,qBAAA;AAAA,MACT,GAAK,EAAA;AAAA,KACN,CAAA;AACD,IAAA,kBAAA,CAAmB,IAAI,CAAA;AAAA,GACtB,EAAA,CAAC,UAAY,EAAA,UAAU,CAAC,CAAA;AAC3B,EAAM,MAAA,gBAAA,GAAmB,WAAY,CAAA,CAAC,IAAiB,KAAA;AACrD,IAAA,OAAA,CAAQ,IAAI,CAAA;AAEZ,IAAA,WAAA,CAAY,CAAQ,IAAA,KAAA,CAAA,IAAA,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAM,OAAU,IAAA,IAAA,GAAO,IAAI,CAAA;AAAA,GACjD,EAAG,EAAE,CAAA;AACL,EAAO,uBAAA,GAAA;AAAA,IAAC,eAAA;AAAA,IAAA;AAAA,MAAgB,KAAA;AAAA,MAAc,QAAQ,OAAQ,CAAA,MAAA;AAAA,MAAQ,IAAA,EAAM,gBAAgB,IAAI,CAAA;AAAA,MAAG,SAAA;AAAA,MAAsB,IAAA;AAAA,MAEjH,cAAc,CAAC,OAAA;AAAA,MAAS,YAAc,EAAA,gBAAA;AAAA,MAAkB,QAAQ,IAAM,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAA,MAAA;AAAA,MAAQ,KAAO,EAAA,OAAA,IAAW,gBAAiB,CAAA,IAAA,EAAM,IAAI,CAAA;AAAA,MAAG,WAAA,EAAa,UAAU,MAAS,GAAA,UAAA;AAAA,MAAY,IAAA;AAAA,MAAY,OAAA,EAAA,CAAS,EAAU,GAAA,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAA,OAAA,KAAV,IAAqB,GAAA,EAAA,GAAA,IAAA;AAAA,MAAM,IAAA,EAAA,CAAM,EAAU,GAAA,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAA,IAAA,KAAV,IAAkB,GAAA,EAAA,GAAA,IAAA;AAAA,MAAM,eAAA,EAAiB,QAAQ,UAAU,CAAA;AAAA,MAAG,QAAA,EAAU,mBAAmB,CAAC,OAAA;AAAA,MAAS,MAAA;AAAA,MAAgB,QAAU,EAAA,YAAA;AAAA,MAAc,cAAgB,EAAA,kBAAA;AAAA,MAAoB,MAAQ,EAAA,UAAA;AAAA,MAAY,SAAW,EAAA;AAAA;AAAA,GAAe;AACjc"}
@@ -0,0 +1,71 @@
1
+ import {oneTimeCodeEntry,cleanOneTimeCode}from'common';const ONE_TIME_CODE_ACT = "YANTRA_COMPUTER_ACT";
2
+ const ONE_TIME_CODE_INPUT = "YANTRA_COMPUTER_INPUT";
3
+ const ONE_TIME_CODE_TIMEOUT_MS = 9e4;
4
+ function oneTimeCodeTitle(payload) {
5
+ var _a;
6
+ return ((_a = payload.title) == null ? void 0 : _a.trim()) || "Verification code";
7
+ }
8
+ function canEnterOneTimeCode(form) {
9
+ return oneTimeCodeEntry(form, "0") !== null;
10
+ }
11
+ function oneTimeCodeReady(raw, form) {
12
+ return cleanOneTimeCode(raw, form == null ? void 0 : form.digits) !== "";
13
+ }
14
+ function oneTimeCodeHint(form) {
15
+ var _a;
16
+ if (!canEnterOneTimeCode(form)) return "Type it on the page yourself - it never goes into the chat";
17
+ return `Goes straight to ${(_a = form == null ? void 0 : form.site) != null ? _a : "the page"} on your Computer, never into the chat`;
18
+ }
19
+ function connectorResultFailure(result) {
20
+ var _a, _b;
21
+ if (!result || typeof result !== "object") return null;
22
+ const envelope = result;
23
+ if (envelope.successful === false || envelope.success === false) {
24
+ return String((_a = envelope.error) != null ? _a : "The Computer did not answer.");
25
+ }
26
+ const data = envelope.data;
27
+ if (data && typeof data === "object" && data.ok === false) {
28
+ return String((_b = data.error) != null ? _b : "The page did not take the code.");
29
+ }
30
+ return null;
31
+ }
32
+ function oneTimeCodeProblem(raw, site) {
33
+ const where = site != null ? site : "the page";
34
+ if (/is not on .+ any more/i.test(raw)) {
35
+ return `Your Computer is not on ${where} any more. Open your Computer to finish there.`;
36
+ }
37
+ if (/no element|not found|matched|selector|no such/i.test(raw)) {
38
+ return `The code box is no longer on ${where}. Open your Computer to finish there.`;
39
+ }
40
+ if (/timed? ?out|timeout|ETIMEDOUT/i.test(raw)) return "Your Computer took too long to answer. Try again.";
41
+ if (/HTTP 401|authenticat|unauthori[sz]ed|session expired/i.test(raw)) {
42
+ return "Could not sign in to your Computer. Try again in a moment.";
43
+ }
44
+ if (/network request failed|failed to fetch|network/i.test(raw)) {
45
+ return "Could not reach your Computer. Check your connection, then try again.";
46
+ }
47
+ return "Could not enter the code on your Computer. Try again, or open your Computer to finish there.";
48
+ }
49
+ async function enterOneTimeCode(run, form, code) {
50
+ const entry = oneTimeCodeEntry(form, code);
51
+ if (!entry) return "Type the code first.";
52
+ try {
53
+ let failure = connectorResultFailure(await run(ONE_TIME_CODE_ACT, entry.act));
54
+ if (!failure && entry.pressEnter) {
55
+ failure = connectorResultFailure(await run(ONE_TIME_CODE_INPUT, entry.pressEnter));
56
+ }
57
+ return failure ? oneTimeCodeProblem(failure, form == null ? void 0 : form.site) : null;
58
+ } catch (error) {
59
+ const raw = error instanceof Error ? error.message : String(error);
60
+ return oneTimeCodeProblem(raw, form == null ? void 0 : form.site);
61
+ }
62
+ }
63
+ const COMPUTER_SURFACE_SLUG = "computer";
64
+ const ONE_TIME_CODE_HANDOFF_REASON = "Type the code on the page, then come back to the chat.";
65
+ function computerHandoffUrl(surfaceUrlTemplate, reason) {
66
+ const template = surfaceUrlTemplate == null ? void 0 : surfaceUrlTemplate.trim();
67
+ if (!template || !template.includes("{slug}")) return null;
68
+ const base = template.replace(/\{slug\}/g, COMPUTER_SURFACE_SLUG);
69
+ const sep = base.includes("?") ? "&" : "?";
70
+ return `${base}${sep}view=mobile&mode=handoff&reason=${encodeURIComponent(reason)}`;
71
+ }export{COMPUTER_SURFACE_SLUG,ONE_TIME_CODE_ACT,ONE_TIME_CODE_HANDOFF_REASON,ONE_TIME_CODE_INPUT,ONE_TIME_CODE_TIMEOUT_MS,canEnterOneTimeCode,computerHandoffUrl,connectorResultFailure,enterOneTimeCode,oneTimeCodeHint,oneTimeCodeProblem,oneTimeCodeReady,oneTimeCodeTitle};//# sourceMappingURL=oneTimeCode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oneTimeCode.js","sources":["../../../src/features/chat/oneTimeCode.ts"],"sourcesContent":["/**\n * The `one-time-code` connect request, phone side: a site sent the person a\n * code (an email or text OTP, a 2-step code) and their Computer is parked on\n * the page that asks for it.\n *\n * The request and the calls that enter the code come from common's\n * CONNECTOR_CONNECT_PROTOCOL (isOneTimeCodeRequest, oneTimeCodeEntry), the same\n * module the web card reads, so both type the code the same way: one\n * YANTRA_COMPUTER_ACT that first proves the page is still on the site the code\n * was sent for, then types it and presses the button the agent named (Enter\n * when it named none). This file holds what is specific to the phone: the\n * card's copy, how a failure reads to the person, and where \"Open my Computer\"\n * goes.\n *\n * The code itself only ever goes to the Computer: never into the chat, a URL,\n * or a log line. Nothing here keeps it.\n */\nimport { cleanOneTimeCode, oneTimeCodeEntry, type ConnectorConnectForm, type ConnectorConnectPayload } from 'common';\nimport { COMPUTER_CONNECTOR } from './toolActivity';\n\n/** The connector action that types and submits, and the keypress that submits when the page has no button. */\nexport const ONE_TIME_CODE_ACT = 'YANTRA_COMPUTER_ACT';\nexport const ONE_TIME_CODE_INPUT = 'YANTRA_COMPUTER_INPUT';\n\n/**\n * Budget for one call: the ACT waits on the page (typing, the submit's navigation, reading the page after), and a\n * Computer that went to sleep while the person fetched the code adds its wake-up. Same as the web card.\n */\nexport const ONE_TIME_CODE_TIMEOUT_MS = 90_000;\n\n/** Runs one yantra-computer action as the signed-in person; resolves the connector's result, throws when it failed. */\nexport type ComputerAction = (action: string, params: Record<string, unknown>) => Promise<unknown>;\n\n/** The card's title: the agent's (\"Amazon.in email OTP\"), else what it is. */\nexport function oneTimeCodeTitle(payload: Pick<ConnectorConnectPayload, 'title'>): string {\n return payload.title?.trim() || 'Verification code';\n}\n\n/**\n * Whether the card can type the code for the person. A request without the page coordinates (the site, the code\n * box) cannot be: the Computer is then the only way to finish.\n */\nexport function canEnterOneTimeCode(form: ConnectorConnectForm | undefined): boolean {\n return oneTimeCodeEntry(form, '0') !== null;\n}\n\n/** What the Continue button may send: nothing until what was typed is a code. */\nexport function oneTimeCodeReady(raw: string, form: ConnectorConnectForm | undefined): boolean {\n return cleanOneTimeCode(raw, form?.digits) !== '';\n}\n\n/** The fine print under the card: where the code goes, and where it never goes. */\nexport function oneTimeCodeHint(form: ConnectorConnectForm | undefined): string {\n if (!canEnterOneTimeCode(form)) return 'Type it on the page yourself - it never goes into the chat';\n return `Goes straight to ${form?.site ?? 'the page'} on your Computer, never into the chat`;\n}\n\n/**\n * The failure a connector result reports, or null when it worked. The agent's exec lane answers with the\n * connector's envelope (`{ successful, data, error }`, older ones `{ success, ... }`), and a page step can report\n * its own failure as a value (`data.ok === false`).\n */\nexport function connectorResultFailure(result: unknown): string | null {\n if (!result || typeof result !== 'object') return null;\n const envelope = result as { successful?: boolean; success?: boolean; error?: unknown; data?: unknown };\n if (envelope.successful === false || envelope.success === false) {\n return String(envelope.error ?? 'The Computer did not answer.');\n }\n const data = envelope.data as { ok?: boolean; error?: unknown } | null | undefined;\n if (data && typeof data === 'object' && data.ok === false) {\n return String(data.error ?? 'The page did not take the code.');\n }\n return null;\n}\n\n/**\n * What the person reads when the code could not be entered. The connector's own words name a selector or a CDP\n * step; what matters to them is whether the page moved on, and that their Computer is where to finish. The raw\n * text is never shown: it is the connector's, and it can quote what was sent.\n */\nexport function oneTimeCodeProblem(raw: string, site: string | undefined): string {\n const where = site ?? 'the page';\n // The site guard's own sentence (\"The page is not on amazon.in any more\"), minus the transport's prefix.\n if (/is not on .+ any more/i.test(raw)) {\n return `Your Computer is not on ${where} any more. Open your Computer to finish there.`;\n }\n if (/no element|not found|matched|selector|no such/i.test(raw)) {\n return `The code box is no longer on ${where}. Open your Computer to finish there.`;\n }\n if (/timed? ?out|timeout|ETIMEDOUT/i.test(raw)) return 'Your Computer took too long to answer. Try again.';\n if (/HTTP 401|authenticat|unauthori[sz]ed|session expired/i.test(raw)) {\n return 'Could not sign in to your Computer. Try again in a moment.';\n }\n if (/network request failed|failed to fetch|network/i.test(raw)) {\n return 'Could not reach your Computer. Check your connection, then try again.';\n }\n return 'Could not enter the code on your Computer. Try again, or open your Computer to finish there.';\n}\n\n/**\n * Type `code` into the page on the person's Computer: the ACT that checks the site, types and clicks, then Enter\n * when the request named no button. Resolves null once the code is on the page, else what the card shows; never\n * throws, and never echoes the code.\n */\nexport async function enterOneTimeCode(\n run: ComputerAction,\n form: ConnectorConnectForm | undefined,\n code: string,\n): Promise<string | null> {\n const entry = oneTimeCodeEntry(form, code);\n if (!entry) return 'Type the code first.';\n try {\n let failure = connectorResultFailure(await run(ONE_TIME_CODE_ACT, entry.act));\n if (!failure && entry.pressEnter) {\n failure = connectorResultFailure(await run(ONE_TIME_CODE_INPUT, entry.pressEnter));\n }\n return failure ? oneTimeCodeProblem(failure, form?.site) : null;\n } catch (error) {\n const raw = error instanceof Error ? error.message : String(error);\n return oneTimeCodeProblem(raw, form?.site);\n }\n}\n\n/** The Computer surface's slug: `computer-surface.<env>` through SURFACE_URL_TEMPLATE. */\nexport const COMPUTER_SURFACE_SLUG = 'computer';\n\n/** The banner the Computer opens with when the person goes there to finish. */\nexport const ONE_TIME_CODE_HANDOFF_REASON = 'Type the code on the page, then come back to the chat.';\n\n/**\n * Where \"Open my Computer\" goes: the Computer surface in its phone handoff layout (the live page, control already\n * on, the reason as a banner), opened in the app's surface screen, which signs the page in with this device's\n * session - the same identity the agent drives the Computer with. Null when the template has no `{slug}`, which\n * would point at some other surface.\n */\nexport function computerHandoffUrl(surfaceUrlTemplate: string | undefined, reason: string): string | null {\n const template = surfaceUrlTemplate?.trim();\n if (!template || !template.includes('{slug}')) return null;\n const base = template.replace(/\\{slug\\}/g, COMPUTER_SURFACE_SLUG);\n const sep = base.includes('?') ? '&' : '?';\n return `${base}${sep}view=mobile&mode=handoff&reason=${encodeURIComponent(reason)}`;\n}\n\nexport { COMPUTER_CONNECTOR };\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import {useCallback}from'react';import {useCdecliConnection}from'../../contexts/CdecliConnectionContext.js';import {resolveMobileWebUrl,getPackagerHost}from'../../bridge/resolveMobileWebUrl.js';import {createAgentConnectorExec}from'../canvas/videoEditor/remoteMediaClient.js';import {ONE_TIME_CODE_TIMEOUT_MS}from'./oneTimeCode.js';import {COMPUTER_CONNECTOR}from'./toolActivity.js';const REFUSED = /HTTP 401/;
2
+ function useComputerAction(timeoutMs = ONE_TIME_CODE_TIMEOUT_MS) {
3
+ const {
4
+ obtainAgentToken,
5
+ recoverAgentAuth,
6
+ agentEndpoint
7
+ } = useCdecliConnection();
8
+ return useCallback(async (action, params) => {
9
+ const endpoint = resolveMobileWebUrl(agentEndpoint, getPackagerHost());
10
+ const run = (token2) => createAgentConnectorExec(token2, endpoint)(COMPUTER_CONNECTOR, action, params, {
11
+ timeoutMs
12
+ });
13
+ const token = await obtainAgentToken();
14
+ if (!token) throw new Error(`${action} failed (HTTP 401): no session for the agent yet`);
15
+ try {
16
+ return await run(token);
17
+ } catch (error) {
18
+ if (!(error instanceof Error) || !REFUSED.test(error.message)) throw error;
19
+ if (!await recoverAgentAuth()) throw error;
20
+ const fresh = await obtainAgentToken();
21
+ if (!fresh) throw error;
22
+ return run(fresh);
23
+ }
24
+ }, [agentEndpoint, obtainAgentToken, recoverAgentAuth, timeoutMs]);
25
+ }export{useComputerAction};//# sourceMappingURL=useComputerAction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useComputerAction.js","sources":["../../../src/features/chat/useComputerAction.ts"],"sourcesContent":["/**\n * Run a yantra-computer action on the person's own Computer, from the phone.\n *\n * WHICH Computer is decided by an identity, and it must be the one the agent\n * uses: cdecli runs every connector action as the token's subject\n * (`CDECLI_USER_ID`) and the connector resolves the caller's Computer from it,\n * so the call names no workspace. The phone has no gateway exec lane, and one\n * would not do: the gateway runs as nobody, which the agent refuses for\n * per-user work. So this goes to the agent's direct exec lane (the transport\n * the native surfaces use, remoteMediaClient) at the endpoint the chat's own\n * session connects to, with the very token that session hands the agent\n * (CdecliConnection's obtainAgentToken) - the Computer this types on is the one\n * the agent is parked on, not a lookalike resolved from another identity.\n *\n * A 401 means the agent refused the token before running anything, so after\n * the connection re-mints (recoverAgentAuth, which also moves the chat's\n * session onto the new token) the call is sent once more; nothing can be\n * typed twice. Any other failure is the caller's to explain.\n */\nimport { useCallback } from 'react';\nimport { useCdecliConnection } from '../../contexts/CdecliConnectionContext';\nimport { getPackagerHost, resolveMobileWebUrl } from '../../bridge/resolveMobileWebUrl';\nimport { createAgentConnectorExec } from '../canvas/videoEditor/remoteMediaClient';\nimport { COMPUTER_CONNECTOR, ONE_TIME_CODE_TIMEOUT_MS, type ComputerAction } from './oneTimeCode';\n\n/** What the transport says when the agent refused the bearer (see remoteMediaClient's execAction). */\nconst REFUSED = /HTTP 401/;\n\nexport function useComputerAction(timeoutMs: number = ONE_TIME_CODE_TIMEOUT_MS): ComputerAction {\n const { obtainAgentToken, recoverAgentAuth, agentEndpoint } = useCdecliConnection();\n\n return useCallback(\n async (action: string, params: Record<string, unknown>) => {\n // A local agent endpoint is the Mac's; a device reaches it through the packager host.\n const endpoint = resolveMobileWebUrl(agentEndpoint, getPackagerHost());\n const run = (token: string) =>\n createAgentConnectorExec(token, endpoint)(COMPUTER_CONNECTOR, action, params, { timeoutMs });\n const token = await obtainAgentToken();\n if (!token) throw new Error(`${action} failed (HTTP 401): no session for the agent yet`);\n try {\n return await run(token);\n } catch (error) {\n if (!(error instanceof Error) || !REFUSED.test(error.message)) throw error;\n if (!(await recoverAgentAuth())) throw error;\n const fresh = await obtainAgentToken();\n if (!fresh) throw error;\n return run(fresh);\n }\n },\n [agentEndpoint, obtainAgentToken, recoverAgentAuth, timeoutMs],\n );\n}\n"],"names":["token"],"mappings":"+XA0BA,MAAM,OAAU,GAAA,UAAA;AACA,SAAA,iBAAA,CAAkB,YAAoB,wBAA0C,EAAA;AAC9F,EAAM,MAAA;AAAA,IACJ,gBAAA;AAAA,IACA,gBAAA;AAAA,IACA;AAAA,MACE,mBAAoB,EAAA;AACxB,EAAO,OAAA,WAAA,CAAY,OAAO,MAAA,EAAgB,MAAoC,KAAA;AAE5E,IAAA,MAAM,QAAW,GAAA,mBAAA,CAAoB,aAAe,EAAA,eAAA,EAAiB,CAAA;AACrE,IAAM,MAAA,GAAA,GAAM,CAACA,MAAkB,KAAA,wBAAA,CAAyBA,QAAO,QAAQ,CAAA,CAAE,kBAAoB,EAAA,MAAA,EAAQ,MAAQ,EAAA;AAAA,MAC3G;AAAA,KACD,CAAA;AACD,IAAM,MAAA,KAAA,GAAQ,MAAM,gBAAiB,EAAA;AACrC,IAAA,IAAI,CAAC,KAAO,EAAA,MAAM,IAAI,KAAM,CAAA,CAAA,EAAG,MAAM,CAAkD,gDAAA,CAAA,CAAA;AACvF,IAAI,IAAA;AACF,MAAO,OAAA,MAAM,IAAI,KAAK,CAAA;AAAA,aACf,KAAO,EAAA;AACd,MAAI,IAAA,EAAE,iBAAiB,KAAU,CAAA,IAAA,CAAC,QAAQ,IAAK,CAAA,KAAA,CAAM,OAAO,CAAA,EAAS,MAAA,KAAA;AACrE,MAAA,IAAI,CAAE,MAAM,gBAAiB,EAAA,EAAU,MAAA,KAAA;AACvC,MAAM,MAAA,KAAA,GAAQ,MAAM,gBAAiB,EAAA;AACrC,MAAI,IAAA,CAAC,OAAa,MAAA,KAAA;AAClB,MAAA,OAAO,IAAI,KAAK,CAAA;AAAA;AAClB,KACC,CAAC,aAAA,EAAe,gBAAkB,EAAA,gBAAA,EAAkB,SAAS,CAAC,CAAA;AACnE"}
@@ -231,6 +231,7 @@ function useCdecliAutoConnect(isSelected, channelId) {
231
231
  return false;
232
232
  }
233
233
  }, [obtainTokenForAgent, runConnect]);
234
+ const obtainAgentToken = useCallback(() => obtainTokenForAgent(false), [obtainTokenForAgent]);
234
235
  return {
235
236
  channelConnected: status === "connected",
236
237
  status,
@@ -239,6 +240,8 @@ function useCdecliAutoConnect(isSelected, channelId) {
239
240
  activeSkill,
240
241
  accountId,
241
242
  connectWithSkill,
242
- recoverAgentAuth
243
+ recoverAgentAuth,
244
+ obtainAgentToken,
245
+ agentEndpoint: endpoint
243
246
  };
244
247
  }export{useCdecliAutoConnect};//# sourceMappingURL=useCdecliAutoConnect.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useCdecliAutoConnect.js","sources":["../../src/hooks/useCdecliAutoConnect.ts"],"sourcesContent":["/**\n * Auto-connects the cdecli-serve messenger-gateway channel when the CDeCLI\n * gateway is selected from the dropdown. Obtains/creates a system token and\n * calls the `gatewayConnect` mutation so the backend provider has a live\n * session with the cdecli-agent endpoint.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useGatewayConnectMutation } from 'common/graphql';\nimport { config } from '../config/env-config';\nimport { usePrerequisiteIds } from './usePrerequisiteIds';\nimport { mintSurfaceSystemToken } from './mintSurfaceSystemToken';\nimport { useObtainSystemToken } from './useObtainSystemToken';\nimport { resolveCdecliAgentTokenGraphqlUrl } from './systemTokenJwt';\nimport { isWorkspaceBootstrapPending } from './workspaceBootstrapPending';\n\n// ─── Types ───────────────────────────────────────────────────────\n\nexport type CdecliAutoConnectStatus = 'idle' | 'connecting' | 'connected' | 'error';\n\nexport interface UseCdecliAutoConnectResult {\n /** Whether the backend cdecli-serve channel is connected. */\n channelConnected: boolean;\n /** Current connection status. */\n status: CdecliAutoConnectStatus;\n /** Error message if status is 'error'. */\n error: string | null;\n /** Persistence mode reported by the backend provider ('backend' | 'frontend'). */\n persistenceMode: 'backend' | 'frontend' | undefined;\n /** Active skill name on the current CDeCLI session (null if none). */\n activeSkill: string | null;\n /** Per-user accountId used for this gateway connection. */\n accountId: string;\n /** Reconnect the CDeCLI session with a specific skill pre-activated. */\n connectWithSkill: (skill: string, model?: string, systemPrompt?: string, skillId?: string) => Promise<void>;\n /**\n * Revoke the dead system JWT, remint against the agent-trusted backend, and\n * reconnect. Used when cdecli-agent 401s session create (invalid HS256 signature).\n */\n recoverAgentAuth: () => Promise<boolean>;\n}\n\n// ─── Constants ───────────────────────────────────────────────────\n\nconst CHANNEL_TYPE = 'cdecli-serve';\n\nfunction normalizeGraphqlUrl(url: string): string {\n return url.trim().replace(/\\/$/, '');\n}\n\n// ─── Hook ────────────────────────────────────────────────────────\n\n/**\n * When `isSelected` is true, auto-connects the cdecli-serve channel on the\n * messenger-gateway backend using the hosted endpoint and a system token.\n */\nexport function useCdecliAutoConnect(isSelected: boolean, channelId?: string): UseCdecliAutoConnectResult {\n const [status, setStatus] = useState<CdecliAutoConnectStatus>('idle');\n const [error, setError] = useState<string | null>(null);\n const [persistenceMode, setPersistenceMode] = useState<'backend' | 'frontend' | undefined>(undefined);\n const [activeSkill, setActiveSkill] = useState<string | null>(null);\n const connectingRef = useRef(false);\n const connectedRef = useRef(false);\n\n const { accountUserId, orgName, projectId, tagId, loading: prerequisitesLoading } = usePrerequisiteIds();\n\n // Per-user accountId so each user gets their own cdecli-agent session.\n // Wait for the profile query to load before connecting — otherwise all\n // users fall back to 'default' and share a single cdecli-agent session.\n const accountId = accountUserId ?? 'default';\n\n const prevChannelIdRef = useRef<string | undefined>(channelId);\n /** Why the last cluster mint returned null, so callers can show the real reason. */\n const mintErrorRef = useRef<string | null>(null);\n\n const [connectMutation] = useGatewayConnectMutation();\n\n const endpoint = (config.CDECLI_AGENT_ENDPOINT || 'https://cdecli-agent.cdebase.dev').trim();\n const tokenGraphqlUrl = useMemo(\n () => resolveCdecliAgentTokenGraphqlUrl(config.GRAPHQL_URL, endpoint, config.CANVAS_BACKEND_GRAPHQL_URL),\n [endpoint],\n );\n const mintOnCluster = normalizeGraphqlUrl(tokenGraphqlUrl) !== normalizeGraphqlUrl(config.GRAPHQL_URL);\n\n const {\n loading: localTokenLoading,\n obtainSystemToken,\n regenerateSystemToken,\n } = useObtainSystemToken(isSelected && !mintOnCluster);\n\n const obtainTokenForAgent = useCallback(\n async (discardExistingRow = false): Promise<string | null> => {\n if (mintOnCluster) {\n // Same gate web applies before minting (browser useCdecliAutoConnect):\n // no org/project yet means the workspace bootstrap is still running and\n // scope discovery would fail. Skip quietly - the effect re-runs once\n // usePrerequisiteIds resolves them.\n if (!orgName || !projectId) {\n mintErrorRef.current = 'Your workspace is still being set up - this will connect once it finishes.';\n return null;\n }\n try {\n const minted = await mintSurfaceSystemToken({\n graphqlUrl: tokenGraphqlUrl,\n // Preferred scope: kept whenever the cluster knows it (see mintScope.ts).\n orgName,\n projectId,\n tagId,\n discoverScope: true,\n forceRemint: discardExistingRow,\n });\n mintErrorRef.current = null;\n return minted.token?.trim() || null;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const pending = isWorkspaceBootstrapPending(msg);\n // Keep the specific reason. The generic caller message used to hide\n // genuinely actionable text like \"No organization on the canvas\n // backend. Sign in once in the canvas harness, then retry.\"\n mintErrorRef.current = pending ? `${msg} (minting against ${tokenGraphqlUrl})` : msg;\n if (pending) {\n console.warn('[useCdecliAutoConnect] cluster system-token mint not ready yet:', msg);\n } else {\n console.error('[useCdecliAutoConnect] cluster system-token mint failed:', err);\n }\n return null;\n }\n }\n return discardExistingRow ? regenerateSystemToken() : obtainSystemToken();\n },\n [mintOnCluster, tokenGraphqlUrl, orgName, projectId, tagId, obtainSystemToken, regenerateSystemToken],\n );\n\n const applyConnectResult = useCallback((data: { gatewayConnect?: unknown } | null | undefined) => {\n const result = data?.gatewayConnect as\n | {\n persistenceMode?: string | null;\n state?: string | null;\n connected?: boolean | null;\n lastError?: string | null;\n }\n | undefined;\n if (result?.persistenceMode) {\n setPersistenceMode(result.persistenceMode as 'backend' | 'frontend');\n }\n if (result?.state === 'ERROR') {\n setStatus('error');\n setError(result.lastError ?? 'Failed to connect to CDeCLI agent');\n connectedRef.current = false;\n return false;\n }\n setStatus('connected');\n connectedRef.current = true;\n return true;\n }, []);\n\n const runConnect = useCallback(\n async (opts: {\n token: string | null;\n skill?: string;\n skillId?: string;\n model?: string;\n systemPrompt?: string;\n }) => {\n const { data } = await connectMutation({\n variables: {\n input: {\n channelType: CHANNEL_TYPE,\n accountId,\n options: {\n endpoint,\n ...(opts.token ? { token: opts.token } : {}),\n ...(channelId ? { chatId: channelId } : {}),\n ...(opts.skill ? { skill: opts.skill } : {}),\n ...(opts.skillId ? { skillId: opts.skillId } : {}),\n ...(opts.model ? { model: opts.model } : {}),\n ...(opts.systemPrompt ? { systemPrompt: opts.systemPrompt } : {}),\n },\n },\n },\n });\n return applyConnectResult(data);\n },\n [connectMutation, accountId, endpoint, channelId, applyConnectResult],\n );\n\n // Auto-connect when CDeCLI gateway is selected\n useEffect(() => {\n if (!isSelected) {\n connectingRef.current = false;\n return;\n }\n\n if (prerequisitesLoading || !accountUserId) return;\n\n if (!mintOnCluster && localTokenLoading) return;\n\n let isSilentReconnect = false;\n if (connectedRef.current || connectingRef.current) {\n if (channelId && prevChannelIdRef.current !== channelId) {\n isSilentReconnect = connectedRef.current;\n prevChannelIdRef.current = channelId;\n connectedRef.current = false;\n } else {\n return;\n }\n }\n\n const doConnect = async () => {\n connectingRef.current = true;\n if (!isSilentReconnect) setStatus('connecting');\n setError(null);\n\n try {\n const token = await obtainTokenForAgent(false);\n if (!token) {\n if (mintOnCluster) {\n setStatus('error');\n setError(mintErrorRef.current ?? 'Could not mint a system token for the hosted CDeCLI agent.');\n connectedRef.current = false;\n return;\n }\n console.warn('[useCdecliAutoConnect] No system token, connecting without auth');\n }\n\n const { data } = await connectMutation({\n variables: {\n input: {\n channelType: CHANNEL_TYPE,\n accountId,\n options: {\n endpoint,\n ...(token ? { token } : {}),\n ...(channelId ? { chatId: channelId } : {}),\n },\n },\n },\n });\n\n console.log(\n '[useCdecliAutoConnect] connectMutation result (account=%s mintOnCluster=%s):',\n accountId,\n mintOnCluster,\n JSON.stringify(data),\n );\n applyConnectResult(data);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliAutoConnect] connect error:', msg);\n setStatus('error');\n setError(msg);\n connectedRef.current = false;\n } finally {\n connectingRef.current = false;\n }\n };\n\n doConnect();\n }, [\n isSelected,\n obtainTokenForAgent,\n connectMutation,\n applyConnectResult,\n accountId,\n prerequisitesLoading,\n accountUserId,\n channelId,\n localTokenLoading,\n mintOnCluster,\n endpoint,\n ]);\n\n const connectWithSkill = useCallback(\n async (skill: string, model?: string, systemPrompt?: string, skillId?: string) => {\n console.log(\n '[useCdecliAutoConnect] connectWithSkill called with skill=%s skillId=%s model=%s systemPrompt=%d chars',\n skill,\n skillId ?? '',\n model,\n systemPrompt?.length ?? 0,\n );\n setStatus('connecting');\n setError(null);\n\n try {\n const token = await obtainTokenForAgent(false);\n await runConnect({ token, skill, skillId, model, systemPrompt });\n setActiveSkill(skill);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliAutoConnect] connectWithSkill error:', msg);\n setStatus('error');\n setError(msg);\n }\n },\n [obtainTokenForAgent, runConnect],\n );\n\n const recoverAgentAuth = useCallback(async (): Promise<boolean> => {\n try {\n const token = await obtainTokenForAgent(true);\n if (!token) {\n setStatus('error');\n setError(\n mintErrorRef.current ?? 'Could not remint the CDeCLI system token. Sign in again, then retry.',\n );\n connectedRef.current = false;\n return false;\n }\n const ok = await runConnect({ token });\n if (ok) setError(null);\n return ok;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliAutoConnect] recoverAgentAuth error:', msg);\n setStatus('error');\n setError(msg);\n connectedRef.current = false;\n return false;\n }\n }, [obtainTokenForAgent, runConnect]);\n\n return {\n channelConnected: status === 'connected',\n status,\n error,\n persistenceMode,\n activeSkill,\n accountId,\n connectWithSkill,\n recoverAgentAuth,\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useCdecliAutoConnect.js","sources":["../../src/hooks/useCdecliAutoConnect.ts"],"sourcesContent":["/**\n * Auto-connects the cdecli-serve messenger-gateway channel when the CDeCLI\n * gateway is selected from the dropdown. Obtains/creates a system token and\n * calls the `gatewayConnect` mutation so the backend provider has a live\n * session with the cdecli-agent endpoint.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useGatewayConnectMutation } from 'common/graphql';\nimport { config } from '../config/env-config';\nimport { usePrerequisiteIds } from './usePrerequisiteIds';\nimport { mintSurfaceSystemToken } from './mintSurfaceSystemToken';\nimport { useObtainSystemToken } from './useObtainSystemToken';\nimport { resolveCdecliAgentTokenGraphqlUrl } from './systemTokenJwt';\nimport { isWorkspaceBootstrapPending } from './workspaceBootstrapPending';\n\n// ─── Types ───────────────────────────────────────────────────────\n\nexport type CdecliAutoConnectStatus = 'idle' | 'connecting' | 'connected' | 'error';\n\nexport interface UseCdecliAutoConnectResult {\n /** Whether the backend cdecli-serve channel is connected. */\n channelConnected: boolean;\n /** Current connection status. */\n status: CdecliAutoConnectStatus;\n /** Error message if status is 'error'. */\n error: string | null;\n /** Persistence mode reported by the backend provider ('backend' | 'frontend'). */\n persistenceMode: 'backend' | 'frontend' | undefined;\n /** Active skill name on the current CDeCLI session (null if none). */\n activeSkill: string | null;\n /** Per-user accountId used for this gateway connection. */\n accountId: string;\n /** Reconnect the CDeCLI session with a specific skill pre-activated. */\n connectWithSkill: (skill: string, model?: string, systemPrompt?: string, skillId?: string) => Promise<void>;\n /**\n * Revoke the dead system JWT, remint against the agent-trusted backend, and\n * reconnect. Used when cdecli-agent 401s session create (invalid HS256 signature).\n */\n recoverAgentAuth: () => Promise<boolean>;\n /**\n * The token this connection hands the agent: cdecli names the caller by its subject, and the person's Computer\n * is resolved from that. A call the app makes on that Computer itself (the one-time code card typing into the\n * page) carries the same token, so it reaches the Computer the agent is driving - another token's subject is a\n * different Computer, or none. Null when it cannot be had (not signed in yet, mint failed).\n */\n obtainAgentToken: () => Promise<string | null>;\n /** The cdecli-agent this connection talks to (CDECLI_AGENT_ENDPOINT). */\n agentEndpoint: string;\n}\n\n// ─── Constants ───────────────────────────────────────────────────\n\nconst CHANNEL_TYPE = 'cdecli-serve';\n\nfunction normalizeGraphqlUrl(url: string): string {\n return url.trim().replace(/\\/$/, '');\n}\n\n// ─── Hook ────────────────────────────────────────────────────────\n\n/**\n * When `isSelected` is true, auto-connects the cdecli-serve channel on the\n * messenger-gateway backend using the hosted endpoint and a system token.\n */\nexport function useCdecliAutoConnect(isSelected: boolean, channelId?: string): UseCdecliAutoConnectResult {\n const [status, setStatus] = useState<CdecliAutoConnectStatus>('idle');\n const [error, setError] = useState<string | null>(null);\n const [persistenceMode, setPersistenceMode] = useState<'backend' | 'frontend' | undefined>(undefined);\n const [activeSkill, setActiveSkill] = useState<string | null>(null);\n const connectingRef = useRef(false);\n const connectedRef = useRef(false);\n\n const { accountUserId, orgName, projectId, tagId, loading: prerequisitesLoading } = usePrerequisiteIds();\n\n // Per-user accountId so each user gets their own cdecli-agent session.\n // Wait for the profile query to load before connecting — otherwise all\n // users fall back to 'default' and share a single cdecli-agent session.\n const accountId = accountUserId ?? 'default';\n\n const prevChannelIdRef = useRef<string | undefined>(channelId);\n /** Why the last cluster mint returned null, so callers can show the real reason. */\n const mintErrorRef = useRef<string | null>(null);\n\n const [connectMutation] = useGatewayConnectMutation();\n\n const endpoint = (config.CDECLI_AGENT_ENDPOINT || 'https://cdecli-agent.cdebase.dev').trim();\n const tokenGraphqlUrl = useMemo(\n () => resolveCdecliAgentTokenGraphqlUrl(config.GRAPHQL_URL, endpoint, config.CANVAS_BACKEND_GRAPHQL_URL),\n [endpoint],\n );\n const mintOnCluster = normalizeGraphqlUrl(tokenGraphqlUrl) !== normalizeGraphqlUrl(config.GRAPHQL_URL);\n\n const {\n loading: localTokenLoading,\n obtainSystemToken,\n regenerateSystemToken,\n } = useObtainSystemToken(isSelected && !mintOnCluster);\n\n const obtainTokenForAgent = useCallback(\n async (discardExistingRow = false): Promise<string | null> => {\n if (mintOnCluster) {\n // Same gate web applies before minting (browser useCdecliAutoConnect):\n // no org/project yet means the workspace bootstrap is still running and\n // scope discovery would fail. Skip quietly - the effect re-runs once\n // usePrerequisiteIds resolves them.\n if (!orgName || !projectId) {\n mintErrorRef.current = 'Your workspace is still being set up - this will connect once it finishes.';\n return null;\n }\n try {\n const minted = await mintSurfaceSystemToken({\n graphqlUrl: tokenGraphqlUrl,\n // Preferred scope: kept whenever the cluster knows it (see mintScope.ts).\n orgName,\n projectId,\n tagId,\n discoverScope: true,\n forceRemint: discardExistingRow,\n });\n mintErrorRef.current = null;\n return minted.token?.trim() || null;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const pending = isWorkspaceBootstrapPending(msg);\n // Keep the specific reason. The generic caller message used to hide\n // genuinely actionable text like \"No organization on the canvas\n // backend. Sign in once in the canvas harness, then retry.\"\n mintErrorRef.current = pending ? `${msg} (minting against ${tokenGraphqlUrl})` : msg;\n if (pending) {\n console.warn('[useCdecliAutoConnect] cluster system-token mint not ready yet:', msg);\n } else {\n console.error('[useCdecliAutoConnect] cluster system-token mint failed:', err);\n }\n return null;\n }\n }\n return discardExistingRow ? regenerateSystemToken() : obtainSystemToken();\n },\n [mintOnCluster, tokenGraphqlUrl, orgName, projectId, tagId, obtainSystemToken, regenerateSystemToken],\n );\n\n const applyConnectResult = useCallback((data: { gatewayConnect?: unknown } | null | undefined) => {\n const result = data?.gatewayConnect as\n | {\n persistenceMode?: string | null;\n state?: string | null;\n connected?: boolean | null;\n lastError?: string | null;\n }\n | undefined;\n if (result?.persistenceMode) {\n setPersistenceMode(result.persistenceMode as 'backend' | 'frontend');\n }\n if (result?.state === 'ERROR') {\n setStatus('error');\n setError(result.lastError ?? 'Failed to connect to CDeCLI agent');\n connectedRef.current = false;\n return false;\n }\n setStatus('connected');\n connectedRef.current = true;\n return true;\n }, []);\n\n const runConnect = useCallback(\n async (opts: {\n token: string | null;\n skill?: string;\n skillId?: string;\n model?: string;\n systemPrompt?: string;\n }) => {\n const { data } = await connectMutation({\n variables: {\n input: {\n channelType: CHANNEL_TYPE,\n accountId,\n options: {\n endpoint,\n ...(opts.token ? { token: opts.token } : {}),\n ...(channelId ? { chatId: channelId } : {}),\n ...(opts.skill ? { skill: opts.skill } : {}),\n ...(opts.skillId ? { skillId: opts.skillId } : {}),\n ...(opts.model ? { model: opts.model } : {}),\n ...(opts.systemPrompt ? { systemPrompt: opts.systemPrompt } : {}),\n },\n },\n },\n });\n return applyConnectResult(data);\n },\n [connectMutation, accountId, endpoint, channelId, applyConnectResult],\n );\n\n // Auto-connect when CDeCLI gateway is selected\n useEffect(() => {\n if (!isSelected) {\n connectingRef.current = false;\n return;\n }\n\n if (prerequisitesLoading || !accountUserId) return;\n\n if (!mintOnCluster && localTokenLoading) return;\n\n let isSilentReconnect = false;\n if (connectedRef.current || connectingRef.current) {\n if (channelId && prevChannelIdRef.current !== channelId) {\n isSilentReconnect = connectedRef.current;\n prevChannelIdRef.current = channelId;\n connectedRef.current = false;\n } else {\n return;\n }\n }\n\n const doConnect = async () => {\n connectingRef.current = true;\n if (!isSilentReconnect) setStatus('connecting');\n setError(null);\n\n try {\n const token = await obtainTokenForAgent(false);\n if (!token) {\n if (mintOnCluster) {\n setStatus('error');\n setError(mintErrorRef.current ?? 'Could not mint a system token for the hosted CDeCLI agent.');\n connectedRef.current = false;\n return;\n }\n console.warn('[useCdecliAutoConnect] No system token, connecting without auth');\n }\n\n const { data } = await connectMutation({\n variables: {\n input: {\n channelType: CHANNEL_TYPE,\n accountId,\n options: {\n endpoint,\n ...(token ? { token } : {}),\n ...(channelId ? { chatId: channelId } : {}),\n },\n },\n },\n });\n\n console.log(\n '[useCdecliAutoConnect] connectMutation result (account=%s mintOnCluster=%s):',\n accountId,\n mintOnCluster,\n JSON.stringify(data),\n );\n applyConnectResult(data);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliAutoConnect] connect error:', msg);\n setStatus('error');\n setError(msg);\n connectedRef.current = false;\n } finally {\n connectingRef.current = false;\n }\n };\n\n doConnect();\n }, [\n isSelected,\n obtainTokenForAgent,\n connectMutation,\n applyConnectResult,\n accountId,\n prerequisitesLoading,\n accountUserId,\n channelId,\n localTokenLoading,\n mintOnCluster,\n endpoint,\n ]);\n\n const connectWithSkill = useCallback(\n async (skill: string, model?: string, systemPrompt?: string, skillId?: string) => {\n console.log(\n '[useCdecliAutoConnect] connectWithSkill called with skill=%s skillId=%s model=%s systemPrompt=%d chars',\n skill,\n skillId ?? '',\n model,\n systemPrompt?.length ?? 0,\n );\n setStatus('connecting');\n setError(null);\n\n try {\n const token = await obtainTokenForAgent(false);\n await runConnect({ token, skill, skillId, model, systemPrompt });\n setActiveSkill(skill);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliAutoConnect] connectWithSkill error:', msg);\n setStatus('error');\n setError(msg);\n }\n },\n [obtainTokenForAgent, runConnect],\n );\n\n const recoverAgentAuth = useCallback(async (): Promise<boolean> => {\n try {\n const token = await obtainTokenForAgent(true);\n if (!token) {\n setStatus('error');\n setError(\n mintErrorRef.current ?? 'Could not remint the CDeCLI system token. Sign in again, then retry.',\n );\n connectedRef.current = false;\n return false;\n }\n const ok = await runConnect({ token });\n if (ok) setError(null);\n return ok;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliAutoConnect] recoverAgentAuth error:', msg);\n setStatus('error');\n setError(msg);\n connectedRef.current = false;\n return false;\n }\n }, [obtainTokenForAgent, runConnect]);\n\n // The same token the connect above hands the agent (a reveal of the one system token row, or the cluster mint),\n // never a fresh one: rotating it here would leave the chat's session on a revoked token.\n const obtainAgentToken = useCallback(() => obtainTokenForAgent(false), [obtainTokenForAgent]);\n\n return {\n channelConnected: status === 'connected',\n status,\n error,\n persistenceMode,\n activeSkill,\n accountId,\n connectWithSkill,\n recoverAgentAuth,\n obtainAgentToken,\n agentEndpoint: endpoint,\n };\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminide-stack/yantra-mobile",
3
- "version": "12.0.113",
3
+ "version": "12.0.115-alpha.0",
4
4
  "description": "Sample core for higher packages to depend on",
5
5
  "license": "ISC",
6
6
  "author": "CDMBase LLC",
@@ -27,7 +27,7 @@
27
27
  "uuid": "^9.0.0"
28
28
  },
29
29
  "devDependencies": {
30
- "common": "12.0.112",
30
+ "common": "12.0.115-alpha.0",
31
31
  "libphonenumber-js": "^1.13.3"
32
32
  },
33
33
  "peerDependencies": {
@@ -45,7 +45,7 @@
45
45
  "@messenger-box/platform-mobile": "*",
46
46
  "@react-native-async-storage/async-storage": "*",
47
47
  "@react-navigation/native": "*",
48
- "common": "12.0.112",
48
+ "common": "12.0.112-alpha.0",
49
49
  "expo-constants": "*",
50
50
  "expo-secure-store": "*",
51
51
  "expo-web-browser": "*",
@@ -65,5 +65,5 @@
65
65
  "typescript": {
66
66
  "definition": "lib/index.d.ts"
67
67
  },
68
- "gitHead": "42f04f5d45127148b9d73a4864e6609190a3a670"
68
+ "gitHead": "54742262446b5cda81574940e18daca856b18653"
69
69
  }