@codex-app-sdk/electron 0.15.1 → 0.16.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.
@@ -74,6 +74,9 @@ var c = {
74
74
  readConversationPromptHistory: "codex-surface:read-conversation-prompt-history",
75
75
  loadOlderConversationHistory: "codex-surface:load-older-conversation-history",
76
76
  refreshAccount: "codex-surface:refresh-account",
77
+ readRateLimits: "codex-surface:read-rate-limits",
78
+ readAccountUsage: "codex-surface:read-account-usage",
79
+ consumeRateLimitResetCredit: "codex-surface:consume-rate-limit-reset-credit",
77
80
  refreshConversations: "codex-surface:refresh-conversations",
78
81
  renameConversation: "codex-surface:rename-conversation",
79
82
  respondToClientRequest: "codex-surface:respond-to-client-request",
@@ -123,6 +126,9 @@ function l(n, r, i, o = {}) {
123
126
  [c.readConversationPromptHistory]: (e, ...t) => u("readConversationPromptHistory", t),
124
127
  [c.loadOlderConversationHistory]: (e, ...t) => u("loadOlderConversationHistory", t),
125
128
  [c.refreshAccount]: (e, ...t) => u("refreshAccount", t),
129
+ [c.readRateLimits]: (e, ...t) => u("readRateLimits", t),
130
+ [c.consumeRateLimitResetCredit]: (e, ...t) => u("consumeRateLimitResetCredit", t),
131
+ [c.readAccountUsage]: (e, ...t) => u("readAccountUsage", t),
126
132
  [c.refreshConversations]: (e, ...t) => u("refreshConversations", t),
127
133
  [c.renameConversation]: (e, ...t) => u("renameConversation", t),
128
134
  [c.respondToClientRequest]: (e, ...t) => u("respondToClientRequest", t),
@@ -188,6 +194,9 @@ function u(e) {
188
194
  readConversationPromptHistory: (e) => t.invoke(c.readConversationPromptHistory, e),
189
195
  loadOlderConversationHistory: (e) => t.invoke(c.loadOlderConversationHistory, e),
190
196
  refreshAccount: () => t.invoke(c.refreshAccount),
197
+ readRateLimits: (e) => t.invoke(c.readRateLimits, e),
198
+ consumeRateLimitResetCredit: (e) => t.invoke(c.consumeRateLimitResetCredit, e),
199
+ readAccountUsage: () => t.invoke(c.readAccountUsage),
191
200
  refreshConversations: () => t.invoke(c.refreshConversations),
192
201
  renameConversation: (e) => t.invoke(c.renameConversation, e),
193
202
  respondToClientRequest: (e) => t.invoke(c.respondToClientRequest, e),
@@ -262,4 +271,4 @@ function h(e, t, n) {
262
271
  //#endregion
263
272
  export { m as a, i as c, a as d, o as f, p as i, r as l, d as n, u as o, f as r, l as s, h as t, s as u };
264
273
 
265
- //# sourceMappingURL=codex-electron-preload-DupT4aeD.js.map
274
+ //# sourceMappingURL=codex-electron-preload-C6b3Tzd7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-electron-preload-C6b3Tzd7.js","names":[],"sources":["../../src/typed-ipc.ts","../../src/codex-surface-ipc.ts","../../src/codex-native-renderer.ts","../../src/codex-electron-preload.ts"],"sourcesContent":["import type { TypedEventBus } from '@codex-app-sdk/core/events';\n\nexport type IpcRequest<Arguments extends unknown[] = unknown[], Result = unknown> = {\n args: Arguments;\n result: Result;\n};\n\nexport type IpcRequestArguments<Request> = Request extends IpcRequest<infer Arguments, unknown>\n ? Arguments\n : never;\n\nexport type IpcRequestResult<Request> = Request extends IpcRequest<unknown[], infer Result>\n ? Result\n : never;\n\nexport type IpcRendererPort = {\n invoke(channel: string, ...args: unknown[]): Promise<unknown>;\n on(channel: string, listener: (event: unknown, payload: unknown) => void): void;\n off(channel: string, listener: (event: unknown, payload: unknown) => void): void;\n};\n\nexport type IpcMainPort = {\n handle(channel: string, handler: (event: unknown, ...args: unknown[]) => unknown): void;\n removeHandler(channel: string): void;\n};\n\nexport type IpcEventSender = {\n send(channel: string, payload: unknown): void;\n};\n\ntype RequestName<Requests> = keyof Requests & string;\ntype EventName<Events> = keyof Events & string;\n\nexport class TypedIpcRenderer<Requests extends object, Events extends object> {\n constructor(private readonly port: IpcRendererPort) {}\n\n invoke<Name extends RequestName<Requests>>(\n channel: Name,\n ...args: IpcRequestArguments<Requests[Name]>\n ): Promise<IpcRequestResult<Requests[Name]>> {\n return this.port.invoke(channel, ...args) as Promise<IpcRequestResult<Requests[Name]>>;\n }\n\n on<Name extends EventName<Events>>(channel: Name, listener: (payload: Events[Name]) => void): () => void {\n const handler = (_event: unknown, payload: unknown) => listener(payload as Events[Name]);\n this.port.on(channel, handler);\n return () => this.port.off(channel, handler);\n }\n}\n\nexport type IpcMainHandlers<Requests extends object> = {\n [Name in keyof Requests]: (\n event: unknown,\n ...args: IpcRequestArguments<Requests[Name]>\n ) => IpcRequestResult<Requests[Name]> | Promise<IpcRequestResult<Requests[Name]>>;\n};\n\nexport class TypedIpcMain<Requests extends object> {\n private readonly registeredChannels = new Set<RequestName<Requests>>();\n\n constructor(private readonly port: IpcMainPort) {}\n\n handle<Name extends RequestName<Requests>>(\n channel: Name,\n handler: IpcMainHandlers<Pick<Requests, Name>>[Name],\n ): void {\n this.port.handle(channel, (event, ...args) => handler(\n event,\n ...args as IpcRequestArguments<Requests[Name]>,\n ));\n this.registeredChannels.add(channel);\n }\n\n removeHandler<Name extends RequestName<Requests>>(channel: Name): void {\n this.port.removeHandler(channel);\n this.registeredChannels.delete(channel);\n }\n\n dispose(): void {\n for (const channel of this.registeredChannels) {\n this.port.removeHandler(channel);\n }\n this.registeredChannels.clear();\n }\n}\n\nexport type IpcSenderPolicy = {\n /** Rejects an invocation before its handler runs when this returns false. */\n isTrustedSender?: (event: unknown) => boolean;\n};\n\nexport function registerIpcMainHandlers<Requests extends object>(\n port: IpcMainPort,\n handlers: IpcMainHandlers<Requests>,\n policy: IpcSenderPolicy = {},\n): () => void {\n const main = new TypedIpcMain<Requests>(port);\n const channels = Object.keys(handlers) as Array<RequestName<Requests>>;\n const { isTrustedSender } = policy;\n for (const channel of channels) {\n const handler = handlers[channel];\n main.handle(channel, isTrustedSender\n ? (event, ...args) => {\n if (!isTrustedSender(event)) throw new Error(`Rejected ${channel} from an untrusted sender`);\n return handler(event, ...args);\n }\n : handler);\n }\n return () => main.dispose();\n}\n\nexport function sendIpcEvent<Events extends object, Name extends EventName<Events>>(\n sender: IpcEventSender,\n channel: Name,\n payload: Events[Name],\n): void {\n sender.send(channel, payload);\n}\n\nexport function connectIpcEventsToBus<Events extends object>(\n renderer: Pick<TypedIpcRenderer<object, Events>, 'on'>,\n bus: TypedEventBus<Events>,\n channels: ReadonlyArray<EventName<Events>>,\n): () => void {\n const unsubscribers = channels.map((channel) => renderer.on(channel, (payload) => bus.emit(channel, payload)));\n return () => {\n for (const unsubscribe of unsubscribers) {\n unsubscribe();\n }\n };\n}\n","import {\n invokeCodexSurfaceBridgeOperation,\n type CodexSurfaceBridgeOperation,\n type CodexSurfaceBridgeTarget,\n} from '@codex-app-sdk/core/surface-bridge';\nimport type {\n CodexConversationHistory,\n CodexConversationPromptHistory,\n CodexConversationSummary,\n CodexSurfaceApprovalDecision,\n CodexSurfaceApprovalScope,\n CodexSurfaceChatGptDeviceCodeLogin,\n CodexSurfaceChatGptLogin,\n CodexSurfaceClientRequestResponse,\n CodexSurfaceEvent,\n CodexSurfaceModel,\n CodexSurfaceRateLimits,\n CodexSurfaceAccountUsage,\n ReadCodexRateLimitsOptions,\n ConsumeCodexRateLimitResetCreditOptions,\n CodexSurfaceRateLimitResetCreditResult,\n CodexSurfaceRendererApi,\n CodexSurfaceSnapshot,\n CreateCodexRendererConversationOptions,\n ListCodexConversationsOptions,\n ListCodexModelsOptions,\n CodexRendererSendMessageOptions,\n StartCodexReviewOptions,\n StartCodexLiveChatOptions,\n UpdateCodexConversationSettings,\n CodexSurfaceStatePatch,\n CodexVersionedSurfaceSnapshot,\n} from '@codex-app-sdk/core/surface';\nimport {\n isCodexSurfaceStatePatchSource,\n subscribeCodexSurfaceState,\n type CodexSurfaceStatePatchSource,\n} from '@codex-app-sdk/core/surface-bridge';\nimport {\n registerIpcMainHandlers,\n TypedIpcRenderer,\n type IpcEventSender,\n type IpcMainPort,\n type IpcRendererPort,\n type IpcRequest,\n type IpcSenderPolicy,\n} from './typed-ipc';\n\nexport type CodexSurfaceIpcOptions = IpcSenderPolicy & {\n resolveAttachment?: import('@codex-app-sdk/core/surface-bridge').CodexSurfaceBridgeAttachmentResolver;\n};\n\nconst channels = {\n archiveConversation: 'codex-surface:archive-conversation',\n cancelLogin: 'codex-surface:cancel-login',\n clearGoal: 'codex-surface:clear-goal',\n compactConversation: 'codex-surface:compact-conversation',\n connect: 'codex-surface:connect',\n continueInterruptedTurn: 'codex-surface:continue-interrupted-turn',\n createConversation: 'codex-surface:create-conversation',\n deleteConversation: 'codex-surface:delete-conversation',\n deleteTurn: 'codex-surface:delete-turn',\n deleteQueuedPrompt: 'codex-surface:delete-queued-prompt',\n editTurn: 'codex-surface:edit-turn',\n forkTurn: 'codex-surface:fork-turn',\n getSnapshot: 'codex-surface:get-snapshot',\n getVersionedSnapshot: 'codex-surface:get-versioned-snapshot',\n interrupt: 'codex-surface:interrupt',\n listConversations: 'codex-surface:list-conversations',\n listModels: 'codex-surface:list-models',\n logout: 'codex-surface:logout',\n readConversationHistory: 'codex-surface:read-conversation-history',\n readConversationPromptHistory: 'codex-surface:read-conversation-prompt-history',\n loadOlderConversationHistory: 'codex-surface:load-older-conversation-history',\n refreshAccount: 'codex-surface:refresh-account',\n readRateLimits: 'codex-surface:read-rate-limits',\n readAccountUsage: 'codex-surface:read-account-usage',\n consumeRateLimitResetCredit: 'codex-surface:consume-rate-limit-reset-credit',\n refreshConversations: 'codex-surface:refresh-conversations',\n renameConversation: 'codex-surface:rename-conversation',\n respondToClientRequest: 'codex-surface:respond-to-client-request',\n resolveApproval: 'codex-surface:resolve-approval',\n retryTurn: 'codex-surface:retry-turn',\n setGoal: 'codex-surface:set-goal',\n selectConversation: 'codex-surface:select-conversation',\n sendMessage: 'codex-surface:send-message',\n startReview: 'codex-surface:start-review',\n startLiveChat: 'codex-surface:start-live-chat',\n stopLiveChat: 'codex-surface:stop-live-chat',\n startChatGptDeviceCodeLogin: 'codex-surface:start-chatgpt-device-code-login',\n startChatGptLogin: 'codex-surface:start-chatgpt-login',\n steerMessage: 'codex-surface:steer-message',\n steerQueuedPrompt: 'codex-surface:steer-queued-prompt',\n unarchiveConversation: 'codex-surface:unarchive-conversation',\n updateConversationSettings: 'codex-surface:update-conversation-settings',\n updateQueuedPrompt: 'codex-surface:update-queued-prompt',\n stateChanged: 'codex-surface:state-changed',\n statePatch: 'codex-surface:state-patch',\n event: 'codex-surface:event',\n} as const;\n\ntype SurfaceRequests = {\n [channels.archiveConversation]: IpcRequest<[conversationId: string], CodexSurfaceSnapshot>;\n [channels.cancelLogin]: IpcRequest<[loginId?: string], CodexSurfaceSnapshot>;\n [channels.clearGoal]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.compactConversation]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.connect]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.continueInterruptedTurn]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.createConversation]: IpcRequest<[options?: CreateCodexRendererConversationOptions], CodexSurfaceSnapshot>;\n [channels.deleteConversation]: IpcRequest<[conversationId: string], CodexSurfaceSnapshot>;\n [channels.deleteTurn]: IpcRequest<[turnId: string], CodexSurfaceSnapshot>;\n [channels.deleteQueuedPrompt]: IpcRequest<[promptId: string], CodexSurfaceSnapshot>;\n [channels.editTurn]: IpcRequest<[turnId: string, content: string], CodexSurfaceSnapshot>;\n [channels.forkTurn]: IpcRequest<[turnId: string], CodexSurfaceSnapshot>;\n [channels.getSnapshot]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.getVersionedSnapshot]: IpcRequest<[], CodexVersionedSurfaceSnapshot | null>;\n [channels.interrupt]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.listConversations]: IpcRequest<[\n options?: ListCodexConversationsOptions,\n ], CodexConversationSummary[]>;\n [channels.listModels]: IpcRequest<[options?: ListCodexModelsOptions], CodexSurfaceModel[]>;\n [channels.logout]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.readConversationHistory]: IpcRequest<[conversationId?: string], CodexConversationHistory>;\n [channels.readConversationPromptHistory]: IpcRequest<[\n conversationId?: string,\n ], CodexConversationPromptHistory>;\n [channels.loadOlderConversationHistory]: IpcRequest<[conversationId?: string], import('@codex-app-sdk/core/surface').CodexConversationHistoryPage>;\n [channels.refreshAccount]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.readRateLimits]: IpcRequest<[options?: ReadCodexRateLimitsOptions], CodexSurfaceRateLimits>;\n [channels.consumeRateLimitResetCredit]: IpcRequest<[options: ConsumeCodexRateLimitResetCreditOptions], CodexSurfaceRateLimitResetCreditResult>;\n [channels.readAccountUsage]: IpcRequest<[], CodexSurfaceAccountUsage>;\n [channels.refreshConversations]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.renameConversation]: IpcRequest<[title: string], CodexSurfaceSnapshot>;\n [channels.respondToClientRequest]: IpcRequest<[response: CodexSurfaceClientRequestResponse], CodexSurfaceSnapshot>;\n [channels.resolveApproval]: IpcRequest<[\n approvalId: string,\n decision: CodexSurfaceApprovalDecision,\n scope?: CodexSurfaceApprovalScope,\n ], CodexSurfaceSnapshot>;\n [channels.retryTurn]: IpcRequest<[turnId: string], CodexSurfaceSnapshot>;\n [channels.setGoal]: IpcRequest<[objective: string, tokenBudget?: number | null], CodexSurfaceSnapshot>;\n [channels.selectConversation]: IpcRequest<[conversationId: string], CodexSurfaceSnapshot>;\n [channels.sendMessage]: IpcRequest<[prompt: string, options?: CodexRendererSendMessageOptions], CodexSurfaceSnapshot>;\n [channels.startReview]: IpcRequest<[options?: StartCodexReviewOptions], CodexSurfaceSnapshot>;\n [channels.startLiveChat]: IpcRequest<[conversationId: string, options: StartCodexLiveChatOptions], { sdp: string }>;\n [channels.stopLiveChat]: IpcRequest<[conversationId: string], void>;\n [channels.startChatGptDeviceCodeLogin]: IpcRequest<[], CodexSurfaceChatGptDeviceCodeLogin>;\n [channels.startChatGptLogin]: IpcRequest<[], CodexSurfaceChatGptLogin>;\n [channels.steerMessage]: IpcRequest<[\n prompt: string,\n options?: CodexRendererSendMessageOptions,\n ], CodexSurfaceSnapshot>;\n [channels.steerQueuedPrompt]: IpcRequest<[promptId: string, prompt?: string], CodexSurfaceSnapshot>;\n [channels.unarchiveConversation]: IpcRequest<[conversationId: string], CodexSurfaceSnapshot>;\n [channels.updateConversationSettings]: IpcRequest<[settings: UpdateCodexConversationSettings], CodexSurfaceSnapshot>;\n [channels.updateQueuedPrompt]: IpcRequest<[promptId: string, prompt: string], CodexSurfaceSnapshot>;\n};\n\ntype SurfaceEvents = {\n [channels.stateChanged]: CodexSurfaceSnapshot;\n [channels.statePatch]: CodexSurfaceStatePatch;\n [channels.event]: CodexSurfaceEvent;\n};\n\nexport type { CodexSurfaceRendererApi } from '@codex-app-sdk/core/surface';\n\ntype OptionalSurfaceOperation = 'loadOlderConversationHistory' | 'startLiveChat' | 'stopLiveChat';\n\nexport function registerCodexSurfaceIpc(\n port: IpcMainPort,\n sender: IpcEventSender,\n surface: Omit<CodexSurfaceBridgeTarget, OptionalSurfaceOperation>\n & Partial<Pick<CodexSurfaceBridgeTarget, OptionalSurfaceOperation>>\n & Partial<CodexSurfaceStatePatchSource>,\n options: CodexSurfaceIpcOptions = {},\n): () => void {\n // State crosses IPC as full snapshots until a renderer asks for a versioned\n // base; from then on it streams small patches. Older renderers never ask, and\n // surfaces without native patch support decline, so both keep snapshots.\n const patchSource = isCodexSurfaceStatePatchSource(surface) ? surface : null;\n let streamingPatches = false;\n const invoke = <Name extends CodexSurfaceBridgeOperation>(name: Name, args: readonly unknown[]) => {\n if (name === 'loadOlderConversationHistory' && !surface.loadOlderConversationHistory) {\n return Promise.reject(new Error('Conversation history paging is not available.'));\n }\n if ((name === 'startLiveChat' || name === 'stopLiveChat') && !surface[name]) {\n return Promise.reject(new Error('Live chat is not available.'));\n }\n return invokeCodexSurfaceBridgeOperation(\n surface as CodexSurfaceBridgeTarget,\n name,\n args,\n {\n operationLabel: channels[name],\n ...(options.resolveAttachment === undefined\n ? {}\n : { resolveAttachment: options.resolveAttachment }),\n },\n );\n };\n const unregisterHandlers = registerIpcMainHandlers<SurfaceRequests>(port, {\n [channels.archiveConversation]: (_event, ...args) => invoke('archiveConversation', args),\n [channels.cancelLogin]: (_event, ...args) => invoke('cancelLogin', args),\n [channels.clearGoal]: (_event, ...args) => invoke('clearGoal', args),\n [channels.compactConversation]: (_event, ...args) => invoke('compactConversation', args),\n [channels.connect]: (_event, ...args) => invoke('connect', args),\n [channels.continueInterruptedTurn]: (_event, ...args) => invoke('continueInterruptedTurn', args),\n [channels.createConversation]: (_event, ...args) => invoke('createConversation', args),\n [channels.deleteConversation]: (_event, ...args) => invoke('deleteConversation', args),\n [channels.deleteTurn]: (_event, ...args) => invoke('deleteTurn', args),\n [channels.deleteQueuedPrompt]: (_event, ...args) => invoke('deleteQueuedPrompt', args),\n [channels.editTurn]: (_event, ...args) => invoke('editTurn', args),\n [channels.forkTurn]: (_event, ...args) => invoke('forkTurn', args),\n [channels.getSnapshot]: (_event, ...args) => invoke('getSnapshot', args),\n [channels.getVersionedSnapshot]: async () => {\n if (!patchSource) return null;\n streamingPatches = true;\n return patchSource.getVersionedSnapshot();\n },\n [channels.interrupt]: (_event, ...args) => invoke('interrupt', args),\n [channels.listConversations]: (_event, ...args) => invoke('listConversations', args),\n [channels.listModels]: (_event, ...args) => invoke('listModels', args),\n [channels.logout]: (_event, ...args) => invoke('logout', args),\n [channels.readConversationHistory]: (_event, ...args) => invoke('readConversationHistory', args),\n [channels.readConversationPromptHistory]: (_event, ...args) => invoke('readConversationPromptHistory', args),\n [channels.loadOlderConversationHistory]: (_event, ...args) => invoke('loadOlderConversationHistory', args),\n [channels.refreshAccount]: (_event, ...args) => invoke('refreshAccount', args),\n [channels.readRateLimits]: (_event, ...args) => invoke('readRateLimits', args),\n [channels.consumeRateLimitResetCredit]: (_event, ...args) => invoke('consumeRateLimitResetCredit', args),\n [channels.readAccountUsage]: (_event, ...args) => invoke('readAccountUsage', args),\n [channels.refreshConversations]: (_event, ...args) => invoke('refreshConversations', args),\n [channels.renameConversation]: (_event, ...args) => invoke('renameConversation', args),\n [channels.respondToClientRequest]: (_event, ...args) => invoke('respondToClientRequest', args),\n [channels.resolveApproval]: (_event, ...args) => invoke('resolveApproval', args),\n [channels.retryTurn]: (_event, ...args) => invoke('retryTurn', args),\n [channels.setGoal]: (_event, ...args) => invoke('setGoal', args),\n [channels.selectConversation]: (_event, ...args) => invoke('selectConversation', args),\n [channels.sendMessage]: (_event, ...args) => invoke('sendMessage', args),\n [channels.startReview]: (_event, ...args) => invoke('startReview', args),\n [channels.startLiveChat]: (_event, ...args) => invoke('startLiveChat', args),\n [channels.stopLiveChat]: (_event, ...args) => invoke('stopLiveChat', args),\n [channels.startChatGptDeviceCodeLogin]: (_event, ...args) => invoke('startChatGptDeviceCodeLogin', args),\n [channels.startChatGptLogin]: (_event, ...args) => invoke('startChatGptLogin', args),\n [channels.steerMessage]: (_event, ...args) => invoke('steerMessage', args),\n [channels.steerQueuedPrompt]: (_event, ...args) => invoke('steerQueuedPrompt', args),\n [channels.unarchiveConversation]: (_event, ...args) => invoke('unarchiveConversation', args),\n [channels.updateConversationSettings]: (_event, ...args) => invoke('updateConversationSettings', args),\n [channels.updateQueuedPrompt]: (_event, ...args) => invoke('updateQueuedPrompt', args),\n }, options);\n const unsubscribeSnapshots = surface.onStateChange((snapshot) => {\n if (!streamingPatches) sender.send(channels.stateChanged, snapshot);\n });\n const unsubscribePatches = patchSource?.onStatePatch((patch) => {\n if (streamingPatches) sender.send(channels.statePatch, patch);\n });\n const unsubscribeState = () => {\n unsubscribePatches?.();\n unsubscribeSnapshots();\n };\n const unsubscribeEvents = surface.onEvent((event) => sender.send(channels.event, event));\n return () => {\n unsubscribeEvents();\n unsubscribeState();\n unregisterHandlers();\n };\n}\n\nexport function createCodexSurfaceRendererApi(port: IpcRendererPort): CodexSurfaceRendererApi {\n const renderer = new TypedIpcRenderer<SurfaceRequests, SurfaceEvents>(port);\n const getVersionedSnapshot = () => renderer.invoke(channels.getVersionedSnapshot);\n const onStatePatch = (listener: (patch: CodexSurfaceStatePatch) => void) => renderer.on(channels.statePatch, listener);\n const stateSource = { getVersionedSnapshot, onStatePatch };\n return {\n // Mirror patches in the renderer's own world: contextBridge copies every\n // value it passes, so a mirror kept in the preload would lose identity.\n getVersionedSnapshot,\n onStatePatch,\n archiveConversation: (conversationId) => renderer.invoke(channels.archiveConversation, conversationId),\n cancelLogin: (loginId) => renderer.invoke(channels.cancelLogin, loginId),\n clearGoal: () => renderer.invoke(channels.clearGoal),\n compactConversation: () => renderer.invoke(channels.compactConversation),\n connect: () => renderer.invoke(channels.connect),\n continueInterruptedTurn: () => renderer.invoke(channels.continueInterruptedTurn),\n createConversation: (options) => renderer.invoke(channels.createConversation, options),\n deleteConversation: (conversationId) => renderer.invoke(channels.deleteConversation, conversationId),\n deleteTurn: (turnId) => renderer.invoke(channels.deleteTurn, turnId),\n deleteQueuedPrompt: (promptId) => renderer.invoke(channels.deleteQueuedPrompt, promptId),\n editTurn: (turnId, content) => renderer.invoke(channels.editTurn, turnId, content),\n forkTurn: (turnId) => renderer.invoke(channels.forkTurn, turnId),\n getSnapshot: () => renderer.invoke(channels.getSnapshot),\n interrupt: () => renderer.invoke(channels.interrupt),\n listConversations: (options) => renderer.invoke(channels.listConversations, options),\n listModels: (options) => renderer.invoke(channels.listModels, options),\n logout: () => renderer.invoke(channels.logout),\n onEvent: (listener) => renderer.on(channels.event, listener),\n onStateChange: (listener) => {\n // Snapshots arrive until the main process switches to patches; the\n // switch point's base was already delivered as a snapshot, so it stays silent.\n const unsubscribeSnapshots = renderer.on(channels.stateChanged, listener);\n const unsubscribePatches = subscribeCodexSurfaceState(stateSource, listener, { emitInitialSnapshot: false });\n return () => {\n unsubscribePatches();\n unsubscribeSnapshots();\n };\n },\n readConversationHistory: (conversationId) => renderer.invoke(channels.readConversationHistory, conversationId),\n readConversationPromptHistory: (conversationId) => (\n renderer.invoke(channels.readConversationPromptHistory, conversationId)\n ),\n loadOlderConversationHistory: (conversationId) => renderer.invoke(channels.loadOlderConversationHistory, conversationId),\n refreshAccount: () => renderer.invoke(channels.refreshAccount),\n readRateLimits: (options) => renderer.invoke(channels.readRateLimits, options),\n consumeRateLimitResetCredit: (options) => renderer.invoke(channels.consumeRateLimitResetCredit, options),\n readAccountUsage: () => renderer.invoke(channels.readAccountUsage),\n refreshConversations: () => renderer.invoke(channels.refreshConversations),\n renameConversation: (title) => renderer.invoke(channels.renameConversation, title),\n respondToClientRequest: (response) => renderer.invoke(channels.respondToClientRequest, response),\n resolveApproval: (approvalId, decision, scope) => renderer.invoke(channels.resolveApproval, approvalId, decision, scope),\n retryTurn: (turnId) => renderer.invoke(channels.retryTurn, turnId),\n setGoal: (objective, tokenBudget) => renderer.invoke(channels.setGoal, objective, tokenBudget),\n selectConversation: (conversationId) => renderer.invoke(channels.selectConversation, conversationId),\n sendMessage: (prompt, options) => renderer.invoke(channels.sendMessage, prompt, options),\n startReview: (options) => renderer.invoke(channels.startReview, options),\n startLiveChat: (conversationId, options) => renderer.invoke(channels.startLiveChat, conversationId, options),\n stopLiveChat: (conversationId) => renderer.invoke(channels.stopLiveChat, conversationId),\n startChatGptDeviceCodeLogin: () => renderer.invoke(channels.startChatGptDeviceCodeLogin),\n startChatGptLogin: () => renderer.invoke(channels.startChatGptLogin),\n steerMessage: (prompt, options) => renderer.invoke(channels.steerMessage, prompt, options),\n steerQueuedPrompt: (promptId, prompt) => renderer.invoke(channels.steerQueuedPrompt, promptId, prompt),\n unarchiveConversation: (conversationId) => renderer.invoke(channels.unarchiveConversation, conversationId),\n updateConversationSettings: (settings) => renderer.invoke(channels.updateConversationSettings, settings),\n updateQueuedPrompt: (promptId, prompt) => renderer.invoke(channels.updateQueuedPrompt, promptId, prompt),\n };\n}\n","import type {\n CodexNativeAttachment,\n CodexNativeAttachmentInput,\n CodexNativeClipboardContent,\n CodexNativeRendererApi,\n CodexSpeechTranscriptionResult,\n CodexSpeechSessionOptions,\n CodexSpeechSessionEvent,\n} from '@codex-app-sdk/core/native';\nimport {\n TypedIpcRenderer,\n type IpcRendererPort,\n type IpcRequest,\n} from './typed-ipc';\n\nexport const codexNativeChannels = {\n copyToClipboard: 'codex-native:copy-to-clipboard',\n ingestAttachments: 'codex-native:ingest-attachments',\n openExternal: 'codex-native:open-external',\n pickAttachments: 'codex-native:pick-attachments',\n readImagePreview: 'codex-native:read-image-preview',\n transcribeAudio: 'codex-native:transcribe-audio',\n startSpeech: 'codex-native:start-speech',\n appendSpeech: 'codex-native:append-speech',\n stopSpeech: 'codex-native:stop-speech',\n cancelSpeech: 'codex-native:cancel-speech',\n} as const;\nexport const codexSpeechEventChannel = 'codex-native:speech-event';\n\nexport type CodexNativeRequests = {\n [codexNativeChannels.startSpeech]: IpcRequest<[options: CodexSpeechSessionOptions], void>;\n [codexNativeChannels.appendSpeech]: IpcRequest<[sessionId: string, audio: ArrayBuffer], void>;\n [codexNativeChannels.stopSpeech]: IpcRequest<[sessionId: string], CodexSpeechTranscriptionResult>;\n [codexNativeChannels.cancelSpeech]: IpcRequest<[sessionId: string], void>;\n [codexNativeChannels.copyToClipboard]: IpcRequest<[content: CodexNativeClipboardContent], void>;\n [codexNativeChannels.ingestAttachments]: IpcRequest<[\n files: readonly CodexNativeAttachmentInput[],\n ], CodexNativeAttachment[]>;\n [codexNativeChannels.openExternal]: IpcRequest<[href: string], void>;\n [codexNativeChannels.pickAttachments]: IpcRequest<[], CodexNativeAttachment[]>;\n [codexNativeChannels.readImagePreview]: IpcRequest<[path: string], string | null>;\n [codexNativeChannels.transcribeAudio]: IpcRequest<[\n audioData: ArrayBuffer,\n options?: { locale?: string; live?: boolean },\n ], CodexSpeechTranscriptionResult>;\n};\n\nexport type CodexContextBridge = {\n exposeInMainWorld(key: string, api: unknown): void;\n};\n\nexport function createCodexNativeRendererApi(\n port: IpcRendererPort,\n options: { transcription?: boolean; streamingTranscription?: boolean } = {},\n): CodexNativeRendererApi {\n const renderer = new TypedIpcRenderer<CodexNativeRequests, { [codexSpeechEventChannel]: CodexSpeechSessionEvent }>(port);\n const transcription = options.transcription ?? process.platform === 'darwin';\n return {\n capabilities: {\n attachments: true,\n clipboard: true,\n externalLinks: true,\n transcription,\n },\n ...(transcription && (options.streamingTranscription ?? process.platform === 'darwin') ? {\n streamingTranscription: {\n start: (input: CodexSpeechSessionOptions) => renderer.invoke(codexNativeChannels.startSpeech, input),\n append: (id: string, audio: ArrayBuffer) => renderer.invoke(codexNativeChannels.appendSpeech, id, audio),\n stop: (id: string) => renderer.invoke(codexNativeChannels.stopSpeech, id),\n cancel: (id: string) => renderer.invoke(codexNativeChannels.cancelSpeech, id),\n onEvent: (listener: (event: CodexSpeechSessionEvent) => void) => renderer.on(codexSpeechEventChannel, listener),\n },\n } : {}),\n copyToClipboard: (content) => renderer.invoke(codexNativeChannels.copyToClipboard, content),\n ingestAttachments: (files) => renderer.invoke(codexNativeChannels.ingestAttachments, files),\n openExternal: (href) => renderer.invoke(codexNativeChannels.openExternal, href),\n pickAttachments: () => renderer.invoke(codexNativeChannels.pickAttachments),\n readImagePreview: (path) => renderer.invoke(codexNativeChannels.readImagePreview, path),\n transcribeAudio: (audioData, transcriptionOptions) => (\n renderer.invoke(codexNativeChannels.transcribeAudio, audioData, transcriptionOptions)\n ),\n };\n}\n\nexport function exposeCodexNativeRendererApi(\n contextBridge: CodexContextBridge,\n port: IpcRendererPort,\n options?: { transcription?: boolean; streamingTranscription?: boolean },\n): CodexNativeRendererApi {\n const api = createCodexNativeRendererApi(port, options);\n contextBridge.exposeInMainWorld('codexAppSdkNative', api);\n return api;\n}\n","import type { CodexNativeRendererApi } from '@codex-app-sdk/core/native';\nimport type { CodexSurfaceRendererApi } from '@codex-app-sdk/core/surface';\nimport {\n createCodexNativeRendererApi,\n type CodexContextBridge,\n} from './codex-native-renderer';\nimport { createCodexSurfaceRendererApi } from './codex-surface-ipc';\nimport type { IpcRendererPort } from './typed-ipc';\n\nexport type CodexElectronRendererApis = {\n native: CodexNativeRendererApi;\n surface: CodexSurfaceRendererApi;\n};\n\n/** Exposes the SDK-owned renderer APIs under stable, automatically detected names. */\nexport function exposeCodexElectronPreload(\n contextBridge: CodexContextBridge,\n ipcRenderer: IpcRendererPort,\n options?: { transcription?: boolean },\n): CodexElectronRendererApis {\n const surface = createCodexSurfaceRendererApi(ipcRenderer);\n const native = createCodexNativeRendererApi(ipcRenderer, options);\n contextBridge.exposeInMainWorld('codexSurface', surface);\n contextBridge.exposeInMainWorld('codexAppSdkNative', native);\n return { native, surface };\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { startAppleSpeechSession, type AppleSpeechTranscriptionOptions, type AppleSpeechTranscriptionResult } from '@codex-app-sdk/backend';
2
2
  import { type IpcMainPort, type IpcSenderPolicy } from './typed-ipc';
3
3
  import { CodexElectronAttachmentRegistry } from './codex-attachment-registry';
4
+ import { type CodexSpeechOperationObserver } from './codex-speech-sessions';
4
5
  export type CodexNativeDialog = {
5
6
  showOpenDialog(options: {
6
7
  filters?: {
@@ -30,6 +31,8 @@ export type CodexNativeMainOptions = IpcSenderPolicy & {
30
31
  maxAudioBytes?: number;
31
32
  maxImagePreviewBytes?: number;
32
33
  startSpeechSession?: typeof startAppleSpeechSession;
34
+ /** Best-effort streaming operation observation; receives no recording content or identity. */
35
+ onSpeechOperation?: CodexSpeechOperationObserver;
33
36
  transcribeAudio?: (audioData: Buffer, options?: AppleSpeechTranscriptionOptions) => Promise<AppleSpeechTranscriptionResult>;
34
37
  };
35
38
  export type CodexNativeMainDependencies = {
@@ -1 +1 @@
1
- {"version":3,"file":"codex-native-ipc.d.ts","sourceRoot":"","sources":["../src/codex-native-ipc.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,uBAAuB,EAEvB,KAAK,+BAA+B,EACpC,KAAK,8BAA8B,EACpC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAG9E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,cAAc,CAAC,OAAO,EAAE;QACtB,OAAO,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,EAAE,CAAA;SAAE,EAAE,CAAC;QACnD,UAAU,EAAE,KAAK,CAAC,iBAAiB,GAAG,UAAU,CAAC,CAAC;QAClD,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACzD,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,CAAC,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,eAAe,GAAG;IACrD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,kBAAkB,CAAC,EAAE,OAAO,uBAAuB,CAAC;IACpD,eAAe,CAAC,EAAE,CAChB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,+BAA+B,KACtC,OAAO,CAAC,8BAA8B,CAAC,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,SAAS,EAAE,oBAAoB,CAAC;IAChC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,gBAAgB,CAAC;CACzB,CAAC;AAQF,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,2BAA2B,EACzC,OAAO,GAAE,sBAA2B,EACpC,WAAW,kCAAwC,GAClD,MAAM,IAAI,CA8HZ"}
1
+ {"version":3,"file":"codex-native-ipc.d.ts","sourceRoot":"","sources":["../src/codex-native-ipc.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,uBAAuB,EAEvB,KAAK,+BAA+B,EACpC,KAAK,8BAA8B,EACpC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAC9E,OAAO,EAA6B,KAAK,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;AAEvG,MAAM,MAAM,iBAAiB,GAAG;IAC9B,cAAc,CAAC,OAAO,EAAE;QACtB,OAAO,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,EAAE,CAAA;SAAE,EAAE,CAAC;QACnD,UAAU,EAAE,KAAK,CAAC,iBAAiB,GAAG,UAAU,CAAC,CAAC;QAClD,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACzD,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,CAAC,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,eAAe,GAAG;IACrD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,kBAAkB,CAAC,EAAE,OAAO,uBAAuB,CAAC;IACpD,8FAA8F;IAC9F,iBAAiB,CAAC,EAAE,4BAA4B,CAAC;IACjD,eAAe,CAAC,EAAE,CAChB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,+BAA+B,KACtC,OAAO,CAAC,8BAA8B,CAAC,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,SAAS,EAAE,oBAAoB,CAAC;IAChC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,gBAAgB,CAAC;CACzB,CAAC;AAQF,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,2BAA2B,EACzC,OAAO,GAAE,sBAA2B,EACpC,WAAW,kCAAwC,GAClD,MAAM,IAAI,CA8HZ"}
@@ -1,12 +1,16 @@
1
1
  import { startAppleSpeechSession } from '@codex-app-sdk/backend';
2
2
  import { codexNativeChannels as channels, type CodexNativeRequests } from './codex-native-renderer';
3
3
  import type { IpcMainHandlers } from './typed-ipc';
4
+ export type CodexSpeechOperation = 'start' | 'stop' | 'cancel';
5
+ export type CodexSpeechOperationOutcome = 'succeeded' | 'failed' | 'cancelled';
6
+ export type CodexSpeechOperationObserver = (operation: CodexSpeechOperation) => ((outcome: CodexSpeechOperationOutcome) => void) | void;
4
7
  type SpeechChannels = typeof channels.startSpeech | typeof channels.appendSpeech | typeof channels.stopSpeech | typeof channels.cancelSpeech;
5
8
  /** One bounded recording per renderer, owned by its invoking frame. */
6
9
  export declare function createCodexSpeechSessions(options: {
7
10
  maxAudioBytes: number;
8
11
  appleSpeechAssetsPath?: string;
9
12
  startSpeechSession?: typeof startAppleSpeechSession;
13
+ onSpeechOperation?: CodexSpeechOperationObserver;
10
14
  }): {
11
15
  handlers: IpcMainHandlers<Pick<CodexNativeRequests, SpeechChannels>>;
12
16
  dispose(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"codex-speech-sessions.d.ts","sourceRoot":"","sources":["../src/codex-speech-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAA2B,MAAM,wBAAwB,CAAC;AAE1F,OAAO,EAAE,mBAAmB,IAAI,QAAQ,EAA2B,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC7H,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAkBnD,KAAK,cAAc,GAAG,OAAO,QAAQ,CAAC,WAAW,GAAG,OAAO,QAAQ,CAAC,YAAY,GAAG,OAAO,QAAQ,CAAC,UAAU,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAC;AAE7I,uEAAuE;AACvE,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IACjD,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,OAAO,uBAAuB,CAAC;CACrD,GAAG;IAAE,QAAQ,EAAE,eAAe,CAAC,IAAI,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC,CAAC;IAAC,OAAO,IAAI,IAAI,CAAA;CAAE,CAkG5F"}
1
+ {"version":3,"file":"codex-speech-sessions.d.ts","sourceRoot":"","sources":["../src/codex-speech-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAA2B,MAAM,wBAAwB,CAAC;AAE1F,OAAO,EAAE,mBAAmB,IAAI,QAAQ,EAA2B,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC7H,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAC/D,MAAM,MAAM,2BAA2B,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAC/E,MAAM,MAAM,4BAA4B,GAAG,CACzC,SAAS,EAAE,oBAAoB,KAC5B,CAAC,CAAC,OAAO,EAAE,2BAA2B,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;AAiB7D,KAAK,cAAc,GAAG,OAAO,QAAQ,CAAC,WAAW,GAAG,OAAO,QAAQ,CAAC,YAAY,GAAG,OAAO,QAAQ,CAAC,UAAU,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAC;AAE7I,uEAAuE;AACvE,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IACjD,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,OAAO,uBAAuB,CAAC;IACpD,iBAAiB,CAAC,EAAE,4BAA4B,CAAC;CAClD,GAAG;IAAE,QAAQ,EAAE,eAAe,CAAC,IAAI,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC,CAAC;IAAC,OAAO,IAAI,IAAI,CAAA;CAAE,CAuH5F"}
@@ -1 +1 @@
1
- {"version":3,"file":"codex-surface-ipc.d.ts","sourceRoot":"","sources":["../src/codex-surface-ipc.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAWV,uBAAuB,EAWxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAGL,KAAK,4BAA4B,EAClC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,eAAe,EAEpB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,sBAAsB,GAAG,eAAe,GAAG;IACrD,iBAAiB,CAAC,EAAE,OAAO,oCAAoC,EAAE,oCAAoC,CAAC;CACvG,CAAC;AA4GF,YAAY,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAE3E,KAAK,wBAAwB,GAAG,8BAA8B,GAAG,eAAe,GAAG,cAAc,CAAC;AAElG,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,IAAI,CAAC,wBAAwB,EAAE,wBAAwB,CAAC,GAC7D,OAAO,CAAC,IAAI,CAAC,wBAAwB,EAAE,wBAAwB,CAAC,CAAC,GACjE,OAAO,CAAC,4BAA4B,CAAC,EACzC,OAAO,GAAE,sBAA2B,GACnC,MAAM,IAAI,CAuFZ;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,eAAe,GAAG,uBAAuB,CA+D5F"}
1
+ {"version":3,"file":"codex-surface-ipc.d.ts","sourceRoot":"","sources":["../src/codex-surface-ipc.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAgBV,uBAAuB,EAWxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAGL,KAAK,4BAA4B,EAClC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,eAAe,EAEpB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,sBAAsB,GAAG,eAAe,GAAG;IACrD,iBAAiB,CAAC,EAAE,OAAO,oCAAoC,EAAE,oCAAoC,CAAC;CACvG,CAAC;AAkHF,YAAY,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAE3E,KAAK,wBAAwB,GAAG,8BAA8B,GAAG,eAAe,GAAG,cAAc,CAAC;AAElG,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,IAAI,CAAC,wBAAwB,EAAE,wBAAwB,CAAC,GAC7D,OAAO,CAAC,IAAI,CAAC,wBAAwB,EAAE,wBAAwB,CAAC,CAAC,GACjE,OAAO,CAAC,4BAA4B,CAAC,EACzC,OAAO,GAAE,sBAA2B,GACnC,MAAM,IAAI,CA0FZ;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,eAAe,GAAG,uBAAuB,CAkE5F"}
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export { codexExternalUrl, installCodexWindowPolicy, isCodexRendererSender, isCo
3
3
  export { createCodexSurfaceRendererApi, registerCodexSurfaceIpc, type CodexSurfaceRendererApi, } from './codex-surface-ipc';
4
4
  export { createCodexNativeRendererApi, exposeCodexNativeRendererApi, type CodexContextBridge, } from './codex-native-renderer';
5
5
  export { registerCodexNativeIpc, type CodexNativeClipboard, type CodexNativeDialog, type CodexNativeMainDependencies, type CodexNativeMainOptions, type CodexNativeShell, } from './codex-native-ipc';
6
+ export type { CodexSpeechOperation, CodexSpeechOperationOutcome, CodexSpeechOperationObserver, } from './codex-speech-sessions';
6
7
  export { CodexElectronAttachmentRegistry, type CodexElectronAttachmentRegistration, } from './codex-attachment-registry';
7
8
  export type { CodexHostAttachment, CodexHostAttachmentInput, CodexNativeAttachment, CodexNativeAttachmentInput, CodexNativeClipboardContent, CodexNativeRendererApi, CodexSpeechTranscriptionResult, } from '@codex-app-sdk/core/native';
8
9
  export { exposeCodexElectronPreload, type CodexElectronRendererApis, } from './codex-electron-preload';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,GAC7B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,6BAA6B,EAC7B,uBAAuB,EACvB,KAAK,uBAAuB,GAC7B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,4BAA4B,EAC5B,4BAA4B,EAC5B,KAAK,kBAAkB,GACxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,sBAAsB,EACtB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,+BAA+B,EAC/B,KAAK,mCAAmC,GACzC,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,EAC3B,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,0BAA0B,EAC1B,KAAK,yBAAyB,GAC/B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,yBAAyB,EACzB,KAAK,wBAAwB,GAC9B,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,GAC7B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,6BAA6B,EAC7B,uBAAuB,EACvB,KAAK,uBAAuB,GAC7B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,4BAA4B,EAC5B,4BAA4B,EAC5B,KAAK,kBAAkB,GACxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,sBAAsB,EACtB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,oBAAoB,EACpB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,+BAA+B,EAC/B,KAAK,mCAAmC,GACzC,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,EAC3B,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,0BAA0B,EAC1B,KAAK,yBAAyB,GAC/B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,yBAAyB,EACzB,KAAK,wBAAwB,GAC9B,MAAM,8BAA8B,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, r as c, s as l, t as u, u as d } from "./chunks/codex-electron-preload-DupT4aeD.js";
1
+ import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, r as c, s as l, t as u, u as d } from "./chunks/codex-electron-preload-C6b3Tzd7.js";
2
2
  import { promises as f } from "node:fs";
3
3
  import p from "node:os";
4
4
  import m from "node:path";
@@ -90,116 +90,135 @@ var C = class {
90
90
  //#region src/codex-speech-sessions.ts
91
91
  function w(e) {
92
92
  let t = /* @__PURE__ */ new Map(), n = e.startSpeechSession ?? h;
93
- function r(e) {
93
+ async function r(t, n, r = () => !1, i = () => !1) {
94
+ let a = T(() => e.onSpeechOperation?.(t)), o = (e) => {
95
+ typeof a == "function" && T(() => a(e));
96
+ };
97
+ try {
98
+ let e = await n();
99
+ return o(r() || t === "cancel" ? "cancelled" : i(e) ? "failed" : "succeeded"), e;
100
+ } catch (e) {
101
+ throw o(r() ? "cancelled" : "failed"), e;
102
+ }
103
+ }
104
+ function i(e) {
94
105
  let t = e;
95
106
  if (!t?.sender?.on || !t.sender.removeListener || !t.senderFrame?.send) throw Error("Speech requires an owning renderer frame.");
96
107
  return t;
97
108
  }
98
- function i(e, n) {
99
- let i = r(e), a = t.get(n);
100
- if (!a || a.owner.sender !== i.sender || a.owner.senderFrame !== i.senderFrame) throw Error("Speech session owner does not match.");
109
+ function a(e, n) {
110
+ let r = i(e), a = t.get(n);
111
+ if (!a || a.owner.sender !== r.sender || a.owner.senderFrame !== r.senderFrame) throw Error("Speech session owner does not match.");
101
112
  return a;
102
113
  }
103
- async function a(e, n) {
104
- t.get(e) === n && (t.delete(e), n.cleanup(), n.abort.abort(), await n.session.then((e) => e.cancel()).catch(() => void 0));
114
+ async function s(e, n) {
115
+ t.get(e) === n && (t.delete(e), n.cleanup(), n.abort.abort(), await n.session.then((e) => r("cancel", () => e.cancel())).catch(() => void 0));
105
116
  }
106
117
  return {
107
118
  handlers: {
108
- [o.startSpeech]: async (i, o) => {
109
- let s = o;
110
- if (!s || typeof s.sessionId != "string" || !/^[\w-]{1,128}$/.test(s.sessionId) || !Number.isInteger(s.sampleRate) || s.sampleRate < 8e3 || s.sampleRate > 96e3 || s.locale !== void 0 && (typeof s.locale != "string" || s.locale.length > 128)) throw TypeError("Invalid speech session options.");
111
- let l = r(i);
112
- if (t.has(s.sessionId) || [...t.values()].some((e) => e.owner.sender === l.sender)) throw Error("A speech session is already active in this renderer.");
113
- let u = s.sessionId, d = new AbortController(), f = () => {
114
- a(u, m);
115
- }, p = (e, t, n, r, i, a) => {
119
+ [o.startSpeech]: async (a, o) => {
120
+ let l = o;
121
+ if (!l || typeof l.sessionId != "string" || !/^[\w-]{1,128}$/.test(l.sessionId) || !Number.isInteger(l.sampleRate) || l.sampleRate < 8e3 || l.sampleRate > 96e3 || l.locale !== void 0 && (typeof l.locale != "string" || l.locale.length > 128)) throw TypeError("Invalid speech session options.");
122
+ let u = i(a);
123
+ if (t.has(l.sessionId) || [...t.values()].some((e) => e.owner.sender === u.sender)) throw Error("A speech session is already active in this renderer.");
124
+ let d = l.sessionId, f = new AbortController(), p = () => {
125
+ s(d, h);
126
+ }, m = (e, t, n, r, i, a) => {
116
127
  let o = e, s = o.frame ?? {
117
128
  processId: i,
118
129
  routingId: a
119
130
  };
120
- !(o.isSameDocument ?? n) && ((o.isMainFrame ?? r) || s.processId === l.senderFrame.processId && s.routingId === l.senderFrame.routingId) && f();
121
- }, m = {
122
- owner: l,
123
- abort: d,
131
+ !(o.isSameDocument ?? n) && ((o.isMainFrame ?? r) || s.processId === u.senderFrame.processId && s.routingId === u.senderFrame.routingId) && p();
132
+ }, h = {
133
+ owner: u,
134
+ abort: f,
124
135
  bytes: 0,
125
- session: Promise.resolve().then(() => n(s, (e) => {
126
- if (t.get(u) === m) {
136
+ session: Promise.resolve().then(() => r("start", () => n(l, (e) => {
137
+ if (t.get(d) === h) {
127
138
  try {
128
- l.senderFrame.send(c, e);
139
+ u.senderFrame.send(c, e);
129
140
  } catch {
130
- f();
141
+ p();
131
142
  }
132
- e.type === "error" && f();
143
+ e.type === "error" && p();
133
144
  }
134
145
  }, {
135
146
  assetsPath: e.appleSpeechAssetsPath,
136
- signal: d.signal
137
- })),
147
+ signal: f.signal
148
+ }), () => f.signal.aborted)),
138
149
  cleanup: () => {
139
- for (let e of ["destroyed", "render-process-gone"]) l.sender.removeListener(e, f);
140
- l.sender.removeListener("did-start-navigation", p);
150
+ for (let e of ["destroyed", "render-process-gone"]) u.sender.removeListener(e, p);
151
+ u.sender.removeListener("did-start-navigation", m);
141
152
  }
142
153
  };
143
- t.set(u, m);
144
- for (let e of ["destroyed", "render-process-gone"]) l.sender.on(e, f);
145
- l.sender.on("did-start-navigation", p);
154
+ t.set(d, h);
155
+ for (let e of ["destroyed", "render-process-gone"]) u.sender.on(e, p);
156
+ u.sender.on("did-start-navigation", m);
146
157
  try {
147
- await m.session;
158
+ await h.session;
148
159
  } catch (e) {
149
- throw await a(u, m), e;
160
+ throw await s(d, h), e;
150
161
  }
151
- if (d.signal.aborted) throw Error("Speech recording cancelled.");
162
+ if (f.signal.aborted) throw Error("Speech recording cancelled.");
152
163
  },
153
164
  [o.appendSpeech]: async (t, n, r) => {
154
- let o = i(t, n);
155
- if (o.stopping) throw Error("Speech session is finalizing.");
165
+ let i = a(t, n);
166
+ if (i.stopping) throw Error("Speech session is finalizing.");
156
167
  if (!(r instanceof ArrayBuffer) || !r.byteLength || r.byteLength % 4 || r.byteLength > 256 * 1024) throw TypeError("Invalid PCM audio chunk.");
157
- if (o.bytes += r.byteLength, o.bytes > e.maxAudioBytes) throw await a(n, o), RangeError("Speech recording exceeds the audio byte limit.");
158
- await (await o.session).append(r);
168
+ if (i.bytes += r.byteLength, i.bytes > e.maxAudioBytes) throw await s(n, i), RangeError("Speech recording exceeds the audio byte limit.");
169
+ await (await i.session).append(r);
159
170
  },
160
171
  [o.stopSpeech]: async (e, n) => {
161
- let r = i(e, n);
162
- return r.stopping ??= r.session.then((e) => e.stop()).finally(() => {
163
- t.delete(n), r.cleanup();
164
- }), r.stopping;
172
+ let i = a(e, n);
173
+ return i.stopping ??= i.session.then((e) => r("stop", () => e.stop(), () => i.abort.signal.aborted, (e) => !!e.error)).finally(() => {
174
+ t.delete(n), i.cleanup();
175
+ }), i.stopping;
165
176
  },
166
177
  [o.cancelSpeech]: async (e, n) => {
167
- t.has(n) && await a(n, i(e, n));
178
+ t.has(n) && await s(n, a(e, n));
168
179
  }
169
180
  },
170
181
  dispose: () => {
171
- for (let [e, n] of t) a(e, n);
182
+ for (let [e, n] of t) s(e, n);
172
183
  }
173
184
  };
174
185
  }
186
+ function T(e) {
187
+ try {
188
+ let t = e();
189
+ return Promise.resolve(t).catch(() => void 0), t;
190
+ } catch {
191
+ return;
192
+ }
193
+ }
175
194
  //#endregion
176
195
  //#region src/codex-native-ipc.ts
177
- var T = 25 * 1024 * 1024, E = 100 * 1024 * 1024, D = 25 * 1024 * 1024, O = 8 * 1024 * 1024, k = 16 * 1024 * 1024;
178
- function A(e, t = {}, r = new C()) {
179
- let i = H(t.maxAttachmentBytes, T, "Attachment byte limit"), a = H(t.maxAudioBytes, D, "Audio byte limit"), s = H(t.maxTotalAttachmentBytes, E, "Total attachment byte limit"), c = H(t.maxImagePreviewBytes, O, "Image preview byte limit"), l = w({
196
+ var E = 25 * 1024 * 1024, D = 100 * 1024 * 1024, O = 25 * 1024 * 1024, k = 8 * 1024 * 1024, A = 16 * 1024 * 1024;
197
+ function j(e, t = {}, r = new C()) {
198
+ let i = U(t.maxAttachmentBytes, E, "Attachment byte limit"), a = U(t.maxAudioBytes, O, "Audio byte limit"), s = U(t.maxTotalAttachmentBytes, D, "Total attachment byte limit"), c = U(t.maxImagePreviewBytes, k, "Image preview byte limit"), l = w({
180
199
  ...t,
181
200
  maxAudioBytes: a
182
201
  }), u = n(e.ipcMain, {
183
202
  ...l.handlers,
184
203
  [o.copyToClipboard]: (t, n) => {
185
- let r = N(n);
204
+ let r = P(n);
186
205
  e.clipboard.write(r);
187
206
  },
188
207
  [o.ingestAttachments]: async (e, t) => {
189
- let n = j(t, i, s);
208
+ let n = M(t, i, s);
190
209
  if (n.length === 0) return [];
191
210
  let a = await f.mkdtemp(m.join(p.tmpdir(), "codex-app-sdk-attachments-"));
192
211
  return Promise.all(n.map(async (e, t) => {
193
- let n = m.join(a, `${t}-${B(e.name)}`), i = Buffer.from(e.data);
194
- return await f.writeFile(n, i, { mode: 384 }), M(r, n, {
195
- mimeType: e.mimeType ?? U(e.name),
196
- name: B(e.name),
212
+ let n = m.join(a, `${t}-${V(e.name)}`), i = Buffer.from(e.data);
213
+ return await f.writeFile(n, i, { mode: 384 }), N(r, n, {
214
+ mimeType: e.mimeType ?? W(e.name),
215
+ name: V(e.name),
197
216
  previewData: i
198
217
  });
199
218
  }));
200
219
  },
201
220
  [o.openExternal]: async (t, n) => {
202
- await e.shell.openExternal(P(n));
221
+ await e.shell.openExternal(F(n));
203
222
  },
204
223
  [o.pickAttachments]: async () => {
205
224
  let t = await e.dialog.showOpenDialog({
@@ -217,8 +236,8 @@ function A(e, t = {}, r = new C()) {
217
236
  if (!t.isFile()) throw TypeError(`Attachment is not a file: ${e}`);
218
237
  if (t.size > i) throw RangeError(`Attachment exceeds the ${i} byte limit: ${e}`);
219
238
  if (a += t.size, a > s) throw RangeError(`Attachments exceed the ${s} total byte limit`);
220
- let c = U(e), l = c.startsWith("image/") && c !== "image/svg+xml" && t.size <= O && o + t.size <= k ? await f.readFile(e) : void 0;
221
- l && (o += l.byteLength), n.push(M(r, e, {
239
+ let c = W(e), l = c.startsWith("image/") && c !== "image/svg+xml" && t.size <= k && o + t.size <= A ? await f.readFile(e) : void 0;
240
+ l && (o += l.byteLength), n.push(N(r, e, {
222
241
  mimeType: c,
223
242
  name: m.basename(e),
224
243
  previewData: l,
@@ -228,13 +247,13 @@ function A(e, t = {}, r = new C()) {
228
247
  return n;
229
248
  },
230
249
  [o.readImagePreview]: async (e, t) => {
231
- let n = R(t, "Image preview attachment reference"), i = V(n) ?? r.path(n), a = U(i);
250
+ let n = z(t, "Image preview attachment reference"), i = H(n) ?? r.path(n), a = W(i);
232
251
  if (!a.startsWith("image/") || a === "image/svg+xml") return null;
233
252
  let o;
234
253
  try {
235
254
  o = await f.lstat(i);
236
255
  } catch (e) {
237
- if (z(e)) return null;
256
+ if (B(e)) return null;
238
257
  throw e;
239
258
  }
240
259
  if (!o.isFile() || o.size > c) return null;
@@ -242,9 +261,9 @@ function A(e, t = {}, r = new C()) {
242
261
  return s.byteLength > c ? null : `data:${a};base64,${s.toString("base64")}`;
243
262
  },
244
263
  [o.transcribeAudio]: async (e, n, r) => {
245
- let i = I(n, "Audio data");
264
+ let i = L(n, "Audio data");
246
265
  if (i.byteLength > a) throw RangeError(`Audio data exceeds the ${a} byte limit`);
247
- let o = F(r);
266
+ let o = I(r);
248
267
  return (t.transcribeAudio ?? ((e, n) => g(e, n, { ...t.appleSpeechAssetsPath ? { assetsPath: t.appleSpeechAssetsPath } : {} })))(Buffer.from(i), o);
249
268
  }
250
269
  }, t);
@@ -252,22 +271,22 @@ function A(e, t = {}, r = new C()) {
252
271
  u(), l.dispose(), r.clear();
253
272
  };
254
273
  }
255
- function j(e, t, n) {
274
+ function M(e, t, n) {
256
275
  if (!Array.isArray(e)) throw TypeError("Attachments must be an array");
257
276
  if (e.length > 20) throw RangeError("At most 20 attachments can be added at once");
258
277
  let r = 0;
259
278
  return e.map((e) => {
260
- let i = L(e, "Attachment"), a = R(i.name, "Attachment name"), o = I(i.data, "Attachment data");
279
+ let i = R(e, "Attachment"), a = z(i.name, "Attachment name"), o = L(i.data, "Attachment data");
261
280
  if (o.byteLength > t) throw RangeError(`Attachment '${a}' exceeds the ${t} byte limit`);
262
281
  if (r += o.byteLength, r > n) throw RangeError(`Attachments exceed the ${n} total byte limit`);
263
282
  return {
264
283
  name: a,
265
284
  data: o,
266
- ...i.mimeType === void 0 ? {} : { mimeType: R(i.mimeType, "Attachment MIME type") }
285
+ ...i.mimeType === void 0 ? {} : { mimeType: z(i.mimeType, "Attachment MIME type") }
267
286
  };
268
287
  });
269
288
  }
270
- function M(e, t, n) {
289
+ function N(e, t, n) {
271
290
  let r = n.size ?? n.previewData?.byteLength ?? 0;
272
291
  return e.register({
273
292
  type: n.mimeType.startsWith("image/") ? "image" : "file",
@@ -275,19 +294,19 @@ function M(e, t, n) {
275
294
  name: n.name,
276
295
  mimeType: n.mimeType,
277
296
  size: r,
278
- ...n.previewData && n.mimeType !== "image/svg+xml" && n.previewData.byteLength <= O ? { previewUrl: `data:${n.mimeType};base64,${Buffer.from(n.previewData).toString("base64")}` } : {}
297
+ ...n.previewData && n.mimeType !== "image/svg+xml" && n.previewData.byteLength <= k ? { previewUrl: `data:${n.mimeType};base64,${Buffer.from(n.previewData).toString("base64")}` } : {}
279
298
  });
280
299
  }
281
- function N(e) {
282
- let t = L(e, "Clipboard content"), n = typeof t.text == "string" ? t.text : W("Clipboard text must be a string"), r = t.html === void 0 ? void 0 : typeof t.html == "string" ? t.html : W("Clipboard HTML must be a string");
300
+ function P(e) {
301
+ let t = R(e, "Clipboard content"), n = typeof t.text == "string" ? t.text : G("Clipboard text must be a string"), r = t.html === void 0 ? void 0 : typeof t.html == "string" ? t.html : G("Clipboard HTML must be a string");
283
302
  if (n.length > 5e6 || (r?.length ?? 0) > 1e7) throw RangeError("Clipboard content is too large");
284
303
  return {
285
304
  text: n,
286
305
  ...r ? { html: r } : {}
287
306
  };
288
307
  }
289
- function P(e) {
290
- let t = R(e, "External URL"), n = new URL(t);
308
+ function F(e) {
309
+ let t = z(e, "External URL"), n = new URL(t);
291
310
  if (![
292
311
  "http:",
293
312
  "https:",
@@ -296,44 +315,44 @@ function P(e) {
296
315
  ].includes(n.protocol.toLowerCase())) throw TypeError(`Unsupported external URL protocol: ${n.protocol}`);
297
316
  return n.href;
298
317
  }
299
- function F(e) {
318
+ function I(e) {
300
319
  if (e === void 0) return;
301
- let t = L(e, "Speech transcription options");
320
+ let t = R(e, "Speech transcription options");
302
321
  if (t.live !== void 0 && typeof t.live != "boolean") throw TypeError("Speech transcription live mode must be a boolean");
303
322
  return {
304
- ...t.locale === void 0 ? {} : { locale: R(t.locale, "Speech transcription locale") },
323
+ ...t.locale === void 0 ? {} : { locale: z(t.locale, "Speech transcription locale") },
305
324
  ...t.live === void 0 ? {} : { live: t.live }
306
325
  };
307
326
  }
308
- function I(e, t) {
327
+ function L(e, t) {
309
328
  if (!(e instanceof ArrayBuffer)) throw TypeError(`${t} must be an ArrayBuffer`);
310
329
  return e;
311
330
  }
312
- function L(e, t) {
331
+ function R(e, t) {
313
332
  if (!e || typeof e != "object" || Array.isArray(e)) throw TypeError(`${t} must be an object`);
314
333
  return e;
315
334
  }
316
- function R(e, t) {
335
+ function z(e, t) {
317
336
  if (typeof e != "string" || !e.trim()) throw TypeError(`${t} must be a non-empty string`);
318
337
  return e.trim();
319
338
  }
320
- function z(e) {
339
+ function B(e) {
321
340
  return !!(e && typeof e == "object" && "code" in e && e.code === "ENOENT");
322
341
  }
323
- function B(e) {
342
+ function V(e) {
324
343
  return m.basename(e).replace(/[\u0000-\u001f\u007f]/g, "").trim() || "attachment";
325
344
  }
326
- function V(e) {
345
+ function H(e) {
327
346
  if (!m.isAbsolute(e)) return null;
328
347
  let t = m.resolve(e), n = m.dirname(t);
329
348
  return m.dirname(n) === m.resolve(p.tmpdir()) && /^codex-app-sdk-attachments-[a-z\d_-]+$/i.test(m.basename(n)) ? t : null;
330
349
  }
331
- function H(e, t, n) {
350
+ function U(e, t, n) {
332
351
  if (e === void 0) return t;
333
352
  if (!Number.isSafeInteger(e) || e <= 0) throw TypeError(`${n} must be a positive integer`);
334
353
  return e;
335
354
  }
336
- function U(e) {
355
+ function W(e) {
337
356
  return {
338
357
  avif: "image/avif",
339
358
  bmp: "image/bmp",
@@ -347,18 +366,18 @@ function U(e) {
347
366
  webp: "image/webp"
348
367
  }[m.extname(e).slice(1).toLowerCase()] ?? "application/octet-stream";
349
368
  }
350
- function W(e) {
369
+ function G(e) {
351
370
  throw TypeError(e);
352
371
  }
353
372
  //#endregion
354
373
  //#region src/codex-electron-integration.ts
355
- function G(e) {
374
+ function K(e) {
356
375
  let t = new C(), n = e.isTrustedSender ? { isTrustedSender: e.isTrustedSender } : {}, r = l(e.ipcMain, e.sender, e.surface, {
357
376
  ...n,
358
377
  resolveAttachment: (e) => t.resolve(e)
359
378
  });
360
379
  try {
361
- let i = A(e, {
380
+ let i = j(e, {
362
381
  ...e.native,
363
382
  ...n
364
383
  }, t);
@@ -370,6 +389,6 @@ function G(e) {
370
389
  }
371
390
  }
372
391
  //#endregion
373
- export { C as CodexElectronAttachmentRegistry, t as TypedIpcMain, a as TypedIpcRenderer, y as codexExternalUrl, d as connectIpcEventsToBus, i as createCodexNativeRendererApi, s as createCodexSurfaceRendererApi, u as exposeCodexElectronPreload, e as exposeCodexNativeRendererApi, x as installCodexWindowPolicy, S as isCodexRendererSender, b as isCodexRendererUrl, G as registerCodexElectronMain, A as registerCodexNativeIpc, l as registerCodexSurfaceIpc, n as registerIpcMainHandlers, r as sendIpcEvent };
392
+ export { C as CodexElectronAttachmentRegistry, t as TypedIpcMain, a as TypedIpcRenderer, y as codexExternalUrl, d as connectIpcEventsToBus, i as createCodexNativeRendererApi, s as createCodexSurfaceRendererApi, u as exposeCodexElectronPreload, e as exposeCodexNativeRendererApi, x as installCodexWindowPolicy, S as isCodexRendererSender, b as isCodexRendererUrl, K as registerCodexElectronMain, j as registerCodexNativeIpc, l as registerCodexSurfaceIpc, n as registerIpcMainHandlers, r as sendIpcEvent };
374
393
 
375
394
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["#attachments","#registered"],"sources":["../src/codex-window-policy.ts","../src/codex-attachment-registry.ts","../src/codex-speech-sessions.ts","../src/codex-native-ipc.ts","../src/codex-electron-integration.ts"],"sourcesContent":["type CodexNavigationEvent = {\n url: string;\n preventDefault(): void;\n};\n\n/** The `WebContents` subset used by `installCodexWindowPolicy`. */\nexport type CodexWindowPolicyTarget = {\n on(event: 'will-navigate', listener: (event: CodexNavigationEvent) => void): unknown;\n setWindowOpenHandler(handler: (details: { url: string }) => { action: 'deny' }): void;\n};\n\nexport type CodexWindowPolicyOptions = {\n /** The URL loaded into the window: the dev server URL or the packaged renderer's `file:` URL. */\n rendererUrl: string;\n /** Usually Electron's `shell.openExternal`. Receives only http(s), mailto, and tel URLs. */\n openExternal(url: string): Promise<void> | void;\n};\n\nconst externalProtocols = new Set(['http:', 'https:', 'mailto:', 'tel:']);\n\n/** Returns a normalized http(s), mailto, or tel URL that is safe to hand to the OS, otherwise null. */\nexport function codexExternalUrl(value: string): string | null {\n try {\n const url = new URL(value);\n return externalProtocols.has(url.protocol) ? url.href : null;\n } catch {\n return null;\n }\n}\n\n/**\n * True when `url` is the app's own renderer: the same origin as an http(s)\n * dev server, or the same document as a packaged `file:` renderer.\n */\nexport function isCodexRendererUrl(url: string | null | undefined, rendererUrl: string): boolean {\n if (!url) return false;\n try {\n const target = new URL(url);\n const renderer = new URL(rendererUrl);\n if (renderer.protocol === 'file:') {\n return target.protocol === 'file:' && target.pathname === renderer.pathname;\n }\n return target.origin === renderer.origin;\n } catch {\n return false;\n }\n}\n\n/**\n * Keeps a window on the app renderer. Electron re-runs the preload script on\n * every navigation, so any other page the window reached would receive the\n * full Codex bridge. New windows and foreign navigations are denied; safe\n * external URLs open in the system browser instead.\n */\nexport function installCodexWindowPolicy(\n webContents: CodexWindowPolicyTarget,\n options: CodexWindowPolicyOptions,\n): void {\n const openExternal = (value: string) => {\n const url = codexExternalUrl(value);\n if (url) void Promise.resolve(options.openExternal(url)).catch(() => undefined);\n };\n webContents.setWindowOpenHandler(({ url }) => {\n openExternal(url);\n return { action: 'deny' };\n });\n webContents.on('will-navigate', (event) => {\n if (isCodexRendererUrl(event.url, options.rendererUrl)) return;\n event.preventDefault();\n openExternal(event.url);\n });\n}\n\n/**\n * IPC sender predicate for `registerCodexElectronMain`: accepts only the main\n * frame of a window that is currently showing the app renderer.\n */\nexport function isCodexRendererSender(event: unknown, rendererUrl: string): boolean {\n const frame = (event as { senderFrame?: { parent: unknown; url: string } | null } | null)?.senderFrame;\n return Boolean(frame) && frame!.parent === null && isCodexRendererUrl(frame!.url, rendererUrl);\n}\n","import { randomUUID } from 'node:crypto';\nimport type { CodexHostAttachment } from '@codex-app-sdk/core/native';\nimport type {\n CodexRendererAttachment,\n CodexSurfaceAttachment,\n} from '@codex-app-sdk/core/surface';\n\nexport type CodexElectronAttachmentRegistration = {\n type: CodexHostAttachment['type'];\n path: string;\n name: string;\n mimeType: string;\n size: number;\n previewUrl?: string;\n};\n\ntype RegisteredAttachment = Omit<CodexElectronAttachmentRegistration, 'size'>;\n\n/** Keeps trusted local paths out of the renderer and scopes references to one Electron integration. */\nexport class CodexElectronAttachmentRegistry {\n readonly #attachments = new Map<string, RegisteredAttachment>();\n\n register(input: CodexElectronAttachmentRegistration): CodexHostAttachment {\n const reference = `electron-attachment:${randomUUID()}`;\n this.#attachments.set(reference, {\n type: input.type,\n path: input.path,\n name: input.name,\n mimeType: input.mimeType,\n ...(input.previewUrl === undefined ? {} : { previewUrl: input.previewUrl }),\n });\n return {\n id: reference,\n reference,\n type: input.type,\n name: input.name,\n mimeType: input.mimeType,\n size: input.size,\n ...(input.previewUrl === undefined ? {} : { previewUrl: input.previewUrl }),\n };\n }\n\n resolve(attachment: CodexRendererAttachment): CodexSurfaceAttachment {\n const registered = this.#registered(attachment.reference);\n if (registered.type !== attachment.type) {\n throw new TypeError('Attachment reference type does not match');\n }\n return {\n type: registered.type,\n path: registered.path,\n name: registered.name,\n mimeType: registered.mimeType,\n ...(registered.type === 'image' && registered.previewUrl\n ? { previewUrl: registered.previewUrl }\n : {}),\n };\n }\n\n path(reference: string): string {\n return this.#registered(reference).path;\n }\n\n clear(): void {\n this.#attachments.clear();\n }\n\n #registered(reference: string): RegisteredAttachment {\n const attachment = this.#attachments.get(reference);\n if (!attachment) throw new TypeError('Attachment reference is invalid or expired');\n return attachment;\n }\n}\n","import { startAppleSpeechSession, type AppleSpeechSession } from '@codex-app-sdk/backend';\nimport type { CodexSpeechSessionOptions, CodexSpeechTranscriptionResult } from '@codex-app-sdk/core/native';\nimport { codexNativeChannels as channels, codexSpeechEventChannel, type CodexNativeRequests } from './codex-native-renderer';\nimport type { IpcMainHandlers } from './typed-ipc';\nimport type { WebContentsDidStartNavigationEventParams } from 'electron';\n\ntype Owner = {\n sender: {\n on(name: string, listener: (...args: unknown[]) => void): unknown;\n removeListener(name: string, listener: (...args: unknown[]) => void): unknown;\n };\n senderFrame: { processId: number; routingId: number; send(name: string, event: unknown): void };\n};\ntype Entry = {\n owner: Owner;\n abort: AbortController;\n session: Promise<AppleSpeechSession>;\n stopping?: Promise<CodexSpeechTranscriptionResult>;\n bytes: number;\n cleanup: () => void;\n};\ntype SpeechChannels = typeof channels.startSpeech | typeof channels.appendSpeech | typeof channels.stopSpeech | typeof channels.cancelSpeech;\n\n/** One bounded recording per renderer, owned by its invoking frame. */\nexport function createCodexSpeechSessions(options: {\n maxAudioBytes: number;\n appleSpeechAssetsPath?: string;\n startSpeechSession?: typeof startAppleSpeechSession;\n}): { handlers: IpcMainHandlers<Pick<CodexNativeRequests, SpeechChannels>>; dispose(): void } {\n const sessions = new Map<string, Entry>();\n const start = options.startSpeechSession ?? startAppleSpeechSession;\n function owner(value: unknown): Owner {\n const event = value as Partial<Owner> | null;\n if (!event?.sender?.on || !event.sender.removeListener || !event.senderFrame?.send) {\n throw new Error('Speech requires an owning renderer frame.');\n }\n return event as Owner;\n }\n function get(event: unknown, id: string): Entry {\n const current = owner(event);\n const entry = sessions.get(id);\n if (!entry || entry.owner.sender !== current.sender || entry.owner.senderFrame !== current.senderFrame) {\n throw new Error('Speech session owner does not match.');\n }\n return entry;\n }\n async function cancel(id: string, entry: Entry): Promise<void> {\n if (sessions.get(id) !== entry) return;\n sessions.delete(id);\n entry.cleanup();\n entry.abort.abort();\n await entry.session.then((session) => session.cancel()).catch(() => undefined);\n }\n return {\n handlers: {\n [channels.startSpeech]: async (event, raw) => {\n const input = raw as CodexSpeechSessionOptions | null;\n if (!input || typeof input.sessionId !== 'string' || !/^[\\w-]{1,128}$/.test(input.sessionId)\n || !Number.isInteger(input.sampleRate) || input.sampleRate < 8000 || input.sampleRate > 96000\n || (input.locale !== undefined && (typeof input.locale !== 'string' || input.locale.length > 128))) {\n throw new TypeError('Invalid speech session options.');\n }\n const current = owner(event);\n if (sessions.has(input.sessionId) || [...sessions.values()].some((entry) => entry.owner.sender === current.sender)) {\n throw new Error('A speech session is already active in this renderer.');\n }\n const id = input.sessionId;\n const abort = new AbortController();\n const teardown = () => { void cancel(id, entry); };\n const onNavigation = (details: unknown, _url: unknown, sameDocument: unknown, mainFrame: unknown, processId: unknown, routingId: unknown) => {\n const navigation = details as Partial<WebContentsDidStartNavigationEventParams>;\n const frame = navigation.frame ?? { processId, routingId };\n // Older Electron versions supply positional arguments instead of details.\n if (!(navigation.isSameDocument ?? sameDocument) && ((navigation.isMainFrame ?? mainFrame)\n || (frame.processId === current.senderFrame.processId && frame.routingId === current.senderFrame.routingId))) teardown();\n };\n const entry: Entry = {\n owner: current, abort, bytes: 0,\n // Defer startup until the entry exists, including synchronous custom adapters.\n session: Promise.resolve().then(() => start(input, (result) => {\n if (sessions.get(id) !== entry) return;\n try { current.senderFrame.send(codexSpeechEventChannel, result); }\n catch { teardown(); }\n if (result.type === 'error') teardown();\n }, { assetsPath: options.appleSpeechAssetsPath, signal: abort.signal })),\n cleanup: () => {\n for (const name of ['destroyed', 'render-process-gone']) current.sender.removeListener(name, teardown);\n current.sender.removeListener('did-start-navigation', onNavigation);\n },\n };\n sessions.set(id, entry);\n for (const name of ['destroyed', 'render-process-gone']) current.sender.on(name, teardown);\n current.sender.on('did-start-navigation', onNavigation);\n try { await entry.session; }\n catch (error) { await cancel(id, entry); throw error; }\n if (abort.signal.aborted) throw new Error('Speech recording cancelled.');\n },\n [channels.appendSpeech]: async (event, id, audio) => {\n const entry = get(event, id);\n if (entry.stopping) throw new Error('Speech session is finalizing.');\n if (!(audio instanceof ArrayBuffer) || !audio.byteLength || audio.byteLength % 4 || audio.byteLength > 256 * 1024) {\n throw new TypeError('Invalid PCM audio chunk.');\n }\n entry.bytes += audio.byteLength;\n if (entry.bytes > options.maxAudioBytes) {\n await cancel(id, entry);\n throw new RangeError('Speech recording exceeds the audio byte limit.');\n }\n await (await entry.session).append(audio);\n },\n [channels.stopSpeech]: async (event, id) => {\n const entry = get(event, id);\n entry.stopping ??= entry.session.then((session) => session.stop()).finally(() => {\n sessions.delete(id);\n entry.cleanup();\n });\n return entry.stopping;\n },\n [channels.cancelSpeech]: async (event, id) => {\n // A final result/error may already have removed this session.\n if (!sessions.has(id)) return;\n await cancel(id, get(event, id));\n },\n },\n dispose: () => { for (const [id, entry] of sessions) void cancel(id, entry); },\n };\n}\n","import { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type {\n CodexHostAttachment,\n CodexNativeAttachmentInput,\n CodexNativeClipboardContent,\n} from '@codex-app-sdk/core/native';\nimport {\n startAppleSpeechSession,\n transcribeWithAppleSpeechAnalyzer,\n type AppleSpeechTranscriptionOptions,\n type AppleSpeechTranscriptionResult,\n} from '@codex-app-sdk/backend';\nimport {\n registerIpcMainHandlers,\n type IpcMainPort,\n type IpcSenderPolicy,\n} from './typed-ipc';\nimport {\n codexNativeChannels as channels,\n type CodexNativeRequests as NativeRequests,\n} from './codex-native-renderer';\nimport { CodexElectronAttachmentRegistry } from './codex-attachment-registry';\nimport { createCodexSpeechSessions } from './codex-speech-sessions';\n\nexport type CodexNativeDialog = {\n showOpenDialog(options: {\n filters?: { name: string; extensions: string[] }[];\n properties: Array<'multiSelections' | 'openFile'>;\n title: string;\n }): Promise<{ canceled: boolean; filePaths: string[] }>;\n};\n\nexport type CodexNativeClipboard = {\n write(content: { html?: string; text: string }): void;\n};\n\nexport type CodexNativeShell = {\n openExternal(href: string): Promise<void>;\n};\n\nexport type CodexNativeMainOptions = IpcSenderPolicy & {\n appleSpeechAssetsPath?: string;\n maxAttachmentBytes?: number;\n maxTotalAttachmentBytes?: number;\n maxAudioBytes?: number;\n maxImagePreviewBytes?: number;\n startSpeechSession?: typeof startAppleSpeechSession;\n transcribeAudio?: (\n audioData: Buffer,\n options?: AppleSpeechTranscriptionOptions,\n ) => Promise<AppleSpeechTranscriptionResult>;\n};\n\nexport type CodexNativeMainDependencies = {\n clipboard: CodexNativeClipboard;\n dialog: CodexNativeDialog;\n ipcMain: IpcMainPort;\n shell: CodexNativeShell;\n};\n\nconst defaultMaxAttachmentBytes = 25 * 1024 * 1024;\nconst defaultMaxTotalAttachmentBytes = 100 * 1024 * 1024;\nconst defaultMaxAudioBytes = 25 * 1024 * 1024;\nconst maxPreviewBytes = 8 * 1024 * 1024;\nconst maxTotalPreviewBytes = 16 * 1024 * 1024;\n\nexport function registerCodexNativeIpc(\n dependencies: CodexNativeMainDependencies,\n options: CodexNativeMainOptions = {},\n attachments = new CodexElectronAttachmentRegistry(),\n): () => void {\n const maxAttachmentBytes = positiveByteLimit(\n options.maxAttachmentBytes,\n defaultMaxAttachmentBytes,\n 'Attachment byte limit',\n );\n const maxAudioBytes = positiveByteLimit(\n options.maxAudioBytes,\n defaultMaxAudioBytes,\n 'Audio byte limit',\n );\n const maxTotalAttachmentBytes = positiveByteLimit(\n options.maxTotalAttachmentBytes,\n defaultMaxTotalAttachmentBytes,\n 'Total attachment byte limit',\n );\n const maxImagePreviewBytes = positiveByteLimit(\n options.maxImagePreviewBytes,\n maxPreviewBytes,\n 'Image preview byte limit',\n );\n\n const speech = createCodexSpeechSessions({ ...options, maxAudioBytes });\n const unregister = registerIpcMainHandlers<NativeRequests>(dependencies.ipcMain, {\n ...speech.handlers,\n [channels.copyToClipboard]: (_event, value) => {\n const content = clipboardContent(value);\n dependencies.clipboard.write(content);\n },\n [channels.ingestAttachments]: async (_event, value) => {\n const inputs = attachmentInputs(value, maxAttachmentBytes, maxTotalAttachmentBytes);\n if (inputs.length === 0) return [];\n const temporaryDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'codex-app-sdk-attachments-'));\n return Promise.all(inputs.map(async (input, index) => {\n const filePath = path.join(temporaryDirectory, `${index}-${safeFileName(input.name)}`);\n const data = Buffer.from(input.data);\n await fs.writeFile(filePath, data, { mode: 0o600 });\n return attachmentFromPath(attachments, filePath, {\n mimeType: input.mimeType ?? mimeTypeForPath(input.name),\n name: safeFileName(input.name),\n previewData: data,\n });\n }));\n },\n [channels.openExternal]: async (_event, value) => {\n await dependencies.shell.openExternal(externalHref(value));\n },\n [channels.pickAttachments]: async () => {\n const result = await dependencies.dialog.showOpenDialog({\n title: 'Add Files & Photos',\n properties: ['openFile', 'multiSelections'],\n filters: [\n { name: 'Files and photos', extensions: ['*'] },\n ],\n });\n if (result.canceled) return [];\n const pickedAttachments: CodexHostAttachment[] = [];\n let totalBytes = 0;\n let previewBytes = 0;\n for (const filePath of result.filePaths) {\n const metadata = await fs.stat(filePath);\n if (!metadata.isFile()) throw new TypeError(`Attachment is not a file: ${filePath}`);\n if (metadata.size > maxAttachmentBytes) {\n throw new RangeError(`Attachment exceeds the ${maxAttachmentBytes} byte limit: ${filePath}`);\n }\n totalBytes += metadata.size;\n if (totalBytes > maxTotalAttachmentBytes) {\n throw new RangeError(`Attachments exceed the ${maxTotalAttachmentBytes} total byte limit`);\n }\n const mimeType = mimeTypeForPath(filePath);\n const previewData = mimeType.startsWith('image/')\n && mimeType !== 'image/svg+xml'\n && metadata.size <= maxPreviewBytes\n && previewBytes + metadata.size <= maxTotalPreviewBytes\n ? await fs.readFile(filePath)\n : undefined;\n if (previewData) previewBytes += previewData.byteLength;\n pickedAttachments.push(attachmentFromPath(attachments, filePath, {\n mimeType,\n name: path.basename(filePath),\n previewData,\n size: metadata.size,\n }));\n }\n return pickedAttachments;\n },\n [channels.readImagePreview]: async (_event, value) => {\n const reference = nonEmptyString(value, 'Image preview attachment reference');\n const filePath = managedTemporaryAttachmentPath(reference) ?? attachments.path(reference);\n const mimeType = mimeTypeForPath(filePath);\n if (!mimeType.startsWith('image/') || mimeType === 'image/svg+xml') return null;\n let metadata;\n try {\n metadata = await fs.lstat(filePath);\n } catch (error) {\n if (isMissingFileError(error)) return null;\n throw error;\n }\n if (!metadata.isFile() || metadata.size > maxImagePreviewBytes) return null;\n const data = await fs.readFile(filePath);\n if (data.byteLength > maxImagePreviewBytes) return null;\n return `data:${mimeType};base64,${data.toString('base64')}`;\n },\n [channels.transcribeAudio]: async (_event, value, rawOptions) => {\n const audioData = arrayBuffer(value, 'Audio data');\n if (audioData.byteLength > maxAudioBytes) {\n throw new RangeError(`Audio data exceeds the ${maxAudioBytes} byte limit`);\n }\n const transcriptionOptions = appleSpeechOptions(rawOptions);\n const transcribe = options.transcribeAudio\n ?? ((data: Buffer, inputOptions?: AppleSpeechTranscriptionOptions) => (\n transcribeWithAppleSpeechAnalyzer(data, inputOptions, {\n ...(options.appleSpeechAssetsPath\n ? { assetsPath: options.appleSpeechAssetsPath }\n : {}),\n })\n ));\n return transcribe(Buffer.from(audioData), transcriptionOptions);\n },\n }, options);\n\n return () => {\n unregister();\n speech.dispose();\n attachments.clear();\n };\n}\n\nfunction attachmentInputs(\n value: unknown,\n maxBytes: number,\n maxTotalBytes: number,\n): CodexNativeAttachmentInput[] {\n if (!Array.isArray(value)) throw new TypeError('Attachments must be an array');\n if (value.length > 20) throw new RangeError('At most 20 attachments can be added at once');\n let totalBytes = 0;\n return value.map((entry) => {\n const record = objectRecord(entry, 'Attachment');\n const name = nonEmptyString(record.name, 'Attachment name');\n const data = arrayBuffer(record.data, 'Attachment data');\n if (data.byteLength > maxBytes) {\n throw new RangeError(`Attachment '${name}' exceeds the ${maxBytes} byte limit`);\n }\n totalBytes += data.byteLength;\n if (totalBytes > maxTotalBytes) {\n throw new RangeError(`Attachments exceed the ${maxTotalBytes} total byte limit`);\n }\n return {\n name,\n data,\n ...(record.mimeType === undefined\n ? {}\n : { mimeType: nonEmptyString(record.mimeType, 'Attachment MIME type') }),\n };\n });\n}\n\nfunction attachmentFromPath(\n attachments: CodexElectronAttachmentRegistry,\n filePath: string,\n metadata: {\n mimeType: string;\n name: string;\n previewData?: Uint8Array;\n size?: number;\n },\n): CodexHostAttachment {\n const size = metadata.size ?? metadata.previewData?.byteLength ?? 0;\n return attachments.register({\n type: metadata.mimeType.startsWith('image/') ? 'image' : 'file',\n path: filePath,\n name: metadata.name,\n mimeType: metadata.mimeType,\n size,\n ...(metadata.previewData\n && metadata.mimeType !== 'image/svg+xml'\n && metadata.previewData.byteLength <= maxPreviewBytes\n ? { previewUrl: `data:${metadata.mimeType};base64,${Buffer.from(metadata.previewData).toString('base64')}` }\n : {}),\n });\n}\n\nfunction clipboardContent(value: unknown): CodexNativeClipboardContent {\n const record = objectRecord(value, 'Clipboard content');\n const text = typeof record.text === 'string' ? record.text : invalid('Clipboard text must be a string');\n const html = record.html === undefined\n ? undefined\n : typeof record.html === 'string'\n ? record.html\n : invalid('Clipboard HTML must be a string');\n if (text.length > 5_000_000 || (html?.length ?? 0) > 10_000_000) {\n throw new RangeError('Clipboard content is too large');\n }\n return { text, ...(html ? { html } : {}) };\n}\n\nfunction externalHref(value: unknown): string {\n const href = nonEmptyString(value, 'External URL');\n const url = new URL(href);\n if (!['http:', 'https:', 'mailto:', 'tel:'].includes(url.protocol.toLowerCase())) {\n throw new TypeError(`Unsupported external URL protocol: ${url.protocol}`);\n }\n return url.href;\n}\n\nfunction appleSpeechOptions(value: unknown): AppleSpeechTranscriptionOptions | undefined {\n if (value === undefined) return undefined;\n const record = objectRecord(value, 'Speech transcription options');\n if (record.live !== undefined && typeof record.live !== 'boolean') {\n throw new TypeError('Speech transcription live mode must be a boolean');\n }\n return {\n ...(record.locale === undefined\n ? {}\n : { locale: nonEmptyString(record.locale, 'Speech transcription locale') }),\n ...(record.live === undefined ? {} : { live: record.live }),\n };\n}\n\nfunction arrayBuffer(value: unknown, label: string): ArrayBuffer {\n if (!(value instanceof ArrayBuffer)) throw new TypeError(`${label} must be an ArrayBuffer`);\n return value;\n}\n\nfunction objectRecord(value: unknown, label: string): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new TypeError(`${label} must be an object`);\n }\n return value as Record<string, unknown>;\n}\n\nfunction nonEmptyString(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value.trim()) throw new TypeError(`${label} must be a non-empty string`);\n return value.trim();\n}\n\nfunction isMissingFileError(error: unknown): boolean {\n return Boolean(error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT');\n}\n\nfunction safeFileName(value: string): string {\n const name = path.basename(value).replace(/[\\u0000-\\u001f\\u007f]/g, '').trim();\n return name || 'attachment';\n}\n\nfunction managedTemporaryAttachmentPath(value: string): string | null {\n if (!path.isAbsolute(value)) return null;\n const resolved = path.resolve(value);\n const directory = path.dirname(resolved);\n if (path.dirname(directory) !== path.resolve(os.tmpdir())) return null;\n return /^codex-app-sdk-attachments-[a-z\\d_-]+$/i.test(path.basename(directory))\n ? resolved\n : null;\n}\n\nfunction positiveByteLimit(value: number | undefined, fallback: number, label: string): number {\n if (value === undefined) return fallback;\n if (!Number.isSafeInteger(value) || value <= 0) throw new TypeError(`${label} must be a positive integer`);\n return value;\n}\n\nfunction mimeTypeForPath(filePath: string): string {\n const extension = path.extname(filePath).slice(1).toLowerCase();\n return ({\n avif: 'image/avif',\n bmp: 'image/bmp',\n gif: 'image/gif',\n heic: 'image/heic',\n heif: 'image/heif',\n jpeg: 'image/jpeg',\n jpg: 'image/jpeg',\n png: 'image/png',\n svg: 'image/svg+xml',\n webp: 'image/webp',\n } as Record<string, string>)[extension] ?? 'application/octet-stream';\n}\n\nfunction invalid(message: string): never {\n throw new TypeError(message);\n}\n","import type { CodexSurface } from '@codex-app-sdk/backend';\nimport {\n registerCodexNativeIpc,\n type CodexNativeMainDependencies,\n type CodexNativeMainOptions,\n} from './codex-native-ipc';\nimport { registerCodexSurfaceIpc } from './codex-surface-ipc';\nimport type { IpcEventSender, IpcSenderPolicy } from './typed-ipc';\nimport { CodexElectronAttachmentRegistry } from './codex-attachment-registry';\n\nexport type CodexElectronMainOptions = CodexNativeMainDependencies & IpcSenderPolicy & {\n native?: CodexNativeMainOptions;\n sender: IpcEventSender;\n surface: CodexSurface;\n};\n\n/** Installs the complete SDK-owned surface and native capability bridge. */\nexport function registerCodexElectronMain(options: CodexElectronMainOptions): () => void {\n const attachments = new CodexElectronAttachmentRegistry();\n const senderPolicy = options.isTrustedSender ? { isTrustedSender: options.isTrustedSender } : {};\n const unregisterSurface = registerCodexSurfaceIpc(\n options.ipcMain,\n options.sender,\n options.surface,\n { ...senderPolicy, resolveAttachment: (attachment) => attachments.resolve(attachment) },\n );\n try {\n const unregisterNative = registerCodexNativeIpc(options, { ...options.native, ...senderPolicy }, attachments);\n return () => {\n unregisterNative();\n unregisterSurface();\n };\n } catch (error) {\n unregisterSurface();\n throw error;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["#attachments","#registered"],"sources":["../src/codex-window-policy.ts","../src/codex-attachment-registry.ts","../src/codex-speech-sessions.ts","../src/codex-native-ipc.ts","../src/codex-electron-integration.ts"],"sourcesContent":["type CodexNavigationEvent = {\n url: string;\n preventDefault(): void;\n};\n\n/** The `WebContents` subset used by `installCodexWindowPolicy`. */\nexport type CodexWindowPolicyTarget = {\n on(event: 'will-navigate', listener: (event: CodexNavigationEvent) => void): unknown;\n setWindowOpenHandler(handler: (details: { url: string }) => { action: 'deny' }): void;\n};\n\nexport type CodexWindowPolicyOptions = {\n /** The URL loaded into the window: the dev server URL or the packaged renderer's `file:` URL. */\n rendererUrl: string;\n /** Usually Electron's `shell.openExternal`. Receives only http(s), mailto, and tel URLs. */\n openExternal(url: string): Promise<void> | void;\n};\n\nconst externalProtocols = new Set(['http:', 'https:', 'mailto:', 'tel:']);\n\n/** Returns a normalized http(s), mailto, or tel URL that is safe to hand to the OS, otherwise null. */\nexport function codexExternalUrl(value: string): string | null {\n try {\n const url = new URL(value);\n return externalProtocols.has(url.protocol) ? url.href : null;\n } catch {\n return null;\n }\n}\n\n/**\n * True when `url` is the app's own renderer: the same origin as an http(s)\n * dev server, or the same document as a packaged `file:` renderer.\n */\nexport function isCodexRendererUrl(url: string | null | undefined, rendererUrl: string): boolean {\n if (!url) return false;\n try {\n const target = new URL(url);\n const renderer = new URL(rendererUrl);\n if (renderer.protocol === 'file:') {\n return target.protocol === 'file:' && target.pathname === renderer.pathname;\n }\n return target.origin === renderer.origin;\n } catch {\n return false;\n }\n}\n\n/**\n * Keeps a window on the app renderer. Electron re-runs the preload script on\n * every navigation, so any other page the window reached would receive the\n * full Codex bridge. New windows and foreign navigations are denied; safe\n * external URLs open in the system browser instead.\n */\nexport function installCodexWindowPolicy(\n webContents: CodexWindowPolicyTarget,\n options: CodexWindowPolicyOptions,\n): void {\n const openExternal = (value: string) => {\n const url = codexExternalUrl(value);\n if (url) void Promise.resolve(options.openExternal(url)).catch(() => undefined);\n };\n webContents.setWindowOpenHandler(({ url }) => {\n openExternal(url);\n return { action: 'deny' };\n });\n webContents.on('will-navigate', (event) => {\n if (isCodexRendererUrl(event.url, options.rendererUrl)) return;\n event.preventDefault();\n openExternal(event.url);\n });\n}\n\n/**\n * IPC sender predicate for `registerCodexElectronMain`: accepts only the main\n * frame of a window that is currently showing the app renderer.\n */\nexport function isCodexRendererSender(event: unknown, rendererUrl: string): boolean {\n const frame = (event as { senderFrame?: { parent: unknown; url: string } | null } | null)?.senderFrame;\n return Boolean(frame) && frame!.parent === null && isCodexRendererUrl(frame!.url, rendererUrl);\n}\n","import { randomUUID } from 'node:crypto';\nimport type { CodexHostAttachment } from '@codex-app-sdk/core/native';\nimport type {\n CodexRendererAttachment,\n CodexSurfaceAttachment,\n} from '@codex-app-sdk/core/surface';\n\nexport type CodexElectronAttachmentRegistration = {\n type: CodexHostAttachment['type'];\n path: string;\n name: string;\n mimeType: string;\n size: number;\n previewUrl?: string;\n};\n\ntype RegisteredAttachment = Omit<CodexElectronAttachmentRegistration, 'size'>;\n\n/** Keeps trusted local paths out of the renderer and scopes references to one Electron integration. */\nexport class CodexElectronAttachmentRegistry {\n readonly #attachments = new Map<string, RegisteredAttachment>();\n\n register(input: CodexElectronAttachmentRegistration): CodexHostAttachment {\n const reference = `electron-attachment:${randomUUID()}`;\n this.#attachments.set(reference, {\n type: input.type,\n path: input.path,\n name: input.name,\n mimeType: input.mimeType,\n ...(input.previewUrl === undefined ? {} : { previewUrl: input.previewUrl }),\n });\n return {\n id: reference,\n reference,\n type: input.type,\n name: input.name,\n mimeType: input.mimeType,\n size: input.size,\n ...(input.previewUrl === undefined ? {} : { previewUrl: input.previewUrl }),\n };\n }\n\n resolve(attachment: CodexRendererAttachment): CodexSurfaceAttachment {\n const registered = this.#registered(attachment.reference);\n if (registered.type !== attachment.type) {\n throw new TypeError('Attachment reference type does not match');\n }\n return {\n type: registered.type,\n path: registered.path,\n name: registered.name,\n mimeType: registered.mimeType,\n ...(registered.type === 'image' && registered.previewUrl\n ? { previewUrl: registered.previewUrl }\n : {}),\n };\n }\n\n path(reference: string): string {\n return this.#registered(reference).path;\n }\n\n clear(): void {\n this.#attachments.clear();\n }\n\n #registered(reference: string): RegisteredAttachment {\n const attachment = this.#attachments.get(reference);\n if (!attachment) throw new TypeError('Attachment reference is invalid or expired');\n return attachment;\n }\n}\n","import { startAppleSpeechSession, type AppleSpeechSession } from '@codex-app-sdk/backend';\nimport type { CodexSpeechSessionOptions, CodexSpeechTranscriptionResult } from '@codex-app-sdk/core/native';\nimport { codexNativeChannels as channels, codexSpeechEventChannel, type CodexNativeRequests } from './codex-native-renderer';\nimport type { IpcMainHandlers } from './typed-ipc';\nimport type { WebContentsDidStartNavigationEventParams } from 'electron';\n\nexport type CodexSpeechOperation = 'start' | 'stop' | 'cancel';\nexport type CodexSpeechOperationOutcome = 'succeeded' | 'failed' | 'cancelled';\nexport type CodexSpeechOperationObserver = (\n operation: CodexSpeechOperation,\n) => ((outcome: CodexSpeechOperationOutcome) => void) | void;\n\ntype Owner = {\n sender: {\n on(name: string, listener: (...args: unknown[]) => void): unknown;\n removeListener(name: string, listener: (...args: unknown[]) => void): unknown;\n };\n senderFrame: { processId: number; routingId: number; send(name: string, event: unknown): void };\n};\ntype Entry = {\n owner: Owner;\n abort: AbortController;\n session: Promise<AppleSpeechSession>;\n stopping?: Promise<CodexSpeechTranscriptionResult>;\n bytes: number;\n cleanup: () => void;\n};\ntype SpeechChannels = typeof channels.startSpeech | typeof channels.appendSpeech | typeof channels.stopSpeech | typeof channels.cancelSpeech;\n\n/** One bounded recording per renderer, owned by its invoking frame. */\nexport function createCodexSpeechSessions(options: {\n maxAudioBytes: number;\n appleSpeechAssetsPath?: string;\n startSpeechSession?: typeof startAppleSpeechSession;\n onSpeechOperation?: CodexSpeechOperationObserver;\n}): { handlers: IpcMainHandlers<Pick<CodexNativeRequests, SpeechChannels>>; dispose(): void } {\n const sessions = new Map<string, Entry>();\n const start = options.startSpeechSession ?? startAppleSpeechSession;\n async function observe<T>(\n operation: CodexSpeechOperation,\n execute: () => Promise<T>,\n cancelled: () => boolean = () => false,\n failed: (result: T) => boolean = () => false,\n ): Promise<T> {\n const finish = safelyObserve(() => options.onSpeechOperation?.(operation));\n const report = (outcome: CodexSpeechOperationOutcome) => {\n if (typeof finish === 'function') safelyObserve(() => finish(outcome));\n };\n try {\n const result = await execute();\n report(cancelled() || operation === 'cancel' ? 'cancelled' : failed(result) ? 'failed' : 'succeeded');\n return result;\n } catch (error) {\n report(cancelled() ? 'cancelled' : 'failed');\n throw error;\n }\n }\n function owner(value: unknown): Owner {\n const event = value as Partial<Owner> | null;\n if (!event?.sender?.on || !event.sender.removeListener || !event.senderFrame?.send) {\n throw new Error('Speech requires an owning renderer frame.');\n }\n return event as Owner;\n }\n function get(event: unknown, id: string): Entry {\n const current = owner(event);\n const entry = sessions.get(id);\n if (!entry || entry.owner.sender !== current.sender || entry.owner.senderFrame !== current.senderFrame) {\n throw new Error('Speech session owner does not match.');\n }\n return entry;\n }\n async function cancel(id: string, entry: Entry): Promise<void> {\n if (sessions.get(id) !== entry) return;\n sessions.delete(id);\n entry.cleanup();\n entry.abort.abort();\n await entry.session.then((session) => observe('cancel', () => session.cancel())).catch(() => undefined);\n }\n return {\n handlers: {\n [channels.startSpeech]: async (event, raw) => {\n const input = raw as CodexSpeechSessionOptions | null;\n if (!input || typeof input.sessionId !== 'string' || !/^[\\w-]{1,128}$/.test(input.sessionId)\n || !Number.isInteger(input.sampleRate) || input.sampleRate < 8000 || input.sampleRate > 96000\n || (input.locale !== undefined && (typeof input.locale !== 'string' || input.locale.length > 128))) {\n throw new TypeError('Invalid speech session options.');\n }\n const current = owner(event);\n if (sessions.has(input.sessionId) || [...sessions.values()].some((entry) => entry.owner.sender === current.sender)) {\n throw new Error('A speech session is already active in this renderer.');\n }\n const id = input.sessionId;\n const abort = new AbortController();\n const teardown = () => { void cancel(id, entry); };\n const onNavigation = (details: unknown, _url: unknown, sameDocument: unknown, mainFrame: unknown, processId: unknown, routingId: unknown) => {\n const navigation = details as Partial<WebContentsDidStartNavigationEventParams>;\n const frame = navigation.frame ?? { processId, routingId };\n // Older Electron versions supply positional arguments instead of details.\n if (!(navigation.isSameDocument ?? sameDocument) && ((navigation.isMainFrame ?? mainFrame)\n || (frame.processId === current.senderFrame.processId && frame.routingId === current.senderFrame.routingId))) teardown();\n };\n const entry: Entry = {\n owner: current, abort, bytes: 0,\n // Defer startup until the entry exists, including synchronous custom adapters.\n session: Promise.resolve().then(() => observe('start', () => start(input, (result) => {\n if (sessions.get(id) !== entry) return;\n try { current.senderFrame.send(codexSpeechEventChannel, result); }\n catch { teardown(); }\n if (result.type === 'error') teardown();\n }, { assetsPath: options.appleSpeechAssetsPath, signal: abort.signal }), () => abort.signal.aborted)),\n cleanup: () => {\n for (const name of ['destroyed', 'render-process-gone']) current.sender.removeListener(name, teardown);\n current.sender.removeListener('did-start-navigation', onNavigation);\n },\n };\n sessions.set(id, entry);\n for (const name of ['destroyed', 'render-process-gone']) current.sender.on(name, teardown);\n current.sender.on('did-start-navigation', onNavigation);\n try { await entry.session; }\n catch (error) { await cancel(id, entry); throw error; }\n if (abort.signal.aborted) throw new Error('Speech recording cancelled.');\n },\n [channels.appendSpeech]: async (event, id, audio) => {\n const entry = get(event, id);\n if (entry.stopping) throw new Error('Speech session is finalizing.');\n if (!(audio instanceof ArrayBuffer) || !audio.byteLength || audio.byteLength % 4 || audio.byteLength > 256 * 1024) {\n throw new TypeError('Invalid PCM audio chunk.');\n }\n entry.bytes += audio.byteLength;\n if (entry.bytes > options.maxAudioBytes) {\n await cancel(id, entry);\n throw new RangeError('Speech recording exceeds the audio byte limit.');\n }\n await (await entry.session).append(audio);\n },\n [channels.stopSpeech]: async (event, id) => {\n const entry = get(event, id);\n entry.stopping ??= entry.session.then((session) => observe(\n 'stop', () => session.stop(), () => entry.abort.signal.aborted, result => Boolean(result.error),\n )).finally(() => {\n sessions.delete(id);\n entry.cleanup();\n });\n return entry.stopping;\n },\n [channels.cancelSpeech]: async (event, id) => {\n // A final result/error may already have removed this session.\n if (!sessions.has(id)) return;\n await cancel(id, get(event, id));\n },\n },\n dispose: () => { for (const [id, entry] of sessions) void cancel(id, entry); },\n };\n}\n\n/** Observation is best-effort: never await it or let it change speech results. */\nfunction safelyObserve<T>(callback: () => T): T | undefined {\n try {\n const result = callback();\n void Promise.resolve(result).catch(() => undefined);\n return result;\n } catch {\n return undefined;\n }\n}\n","import { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type {\n CodexHostAttachment,\n CodexNativeAttachmentInput,\n CodexNativeClipboardContent,\n} from '@codex-app-sdk/core/native';\nimport {\n startAppleSpeechSession,\n transcribeWithAppleSpeechAnalyzer,\n type AppleSpeechTranscriptionOptions,\n type AppleSpeechTranscriptionResult,\n} from '@codex-app-sdk/backend';\nimport {\n registerIpcMainHandlers,\n type IpcMainPort,\n type IpcSenderPolicy,\n} from './typed-ipc';\nimport {\n codexNativeChannels as channels,\n type CodexNativeRequests as NativeRequests,\n} from './codex-native-renderer';\nimport { CodexElectronAttachmentRegistry } from './codex-attachment-registry';\nimport { createCodexSpeechSessions, type CodexSpeechOperationObserver } from './codex-speech-sessions';\n\nexport type CodexNativeDialog = {\n showOpenDialog(options: {\n filters?: { name: string; extensions: string[] }[];\n properties: Array<'multiSelections' | 'openFile'>;\n title: string;\n }): Promise<{ canceled: boolean; filePaths: string[] }>;\n};\n\nexport type CodexNativeClipboard = {\n write(content: { html?: string; text: string }): void;\n};\n\nexport type CodexNativeShell = {\n openExternal(href: string): Promise<void>;\n};\n\nexport type CodexNativeMainOptions = IpcSenderPolicy & {\n appleSpeechAssetsPath?: string;\n maxAttachmentBytes?: number;\n maxTotalAttachmentBytes?: number;\n maxAudioBytes?: number;\n maxImagePreviewBytes?: number;\n startSpeechSession?: typeof startAppleSpeechSession;\n /** Best-effort streaming operation observation; receives no recording content or identity. */\n onSpeechOperation?: CodexSpeechOperationObserver;\n transcribeAudio?: (\n audioData: Buffer,\n options?: AppleSpeechTranscriptionOptions,\n ) => Promise<AppleSpeechTranscriptionResult>;\n};\n\nexport type CodexNativeMainDependencies = {\n clipboard: CodexNativeClipboard;\n dialog: CodexNativeDialog;\n ipcMain: IpcMainPort;\n shell: CodexNativeShell;\n};\n\nconst defaultMaxAttachmentBytes = 25 * 1024 * 1024;\nconst defaultMaxTotalAttachmentBytes = 100 * 1024 * 1024;\nconst defaultMaxAudioBytes = 25 * 1024 * 1024;\nconst maxPreviewBytes = 8 * 1024 * 1024;\nconst maxTotalPreviewBytes = 16 * 1024 * 1024;\n\nexport function registerCodexNativeIpc(\n dependencies: CodexNativeMainDependencies,\n options: CodexNativeMainOptions = {},\n attachments = new CodexElectronAttachmentRegistry(),\n): () => void {\n const maxAttachmentBytes = positiveByteLimit(\n options.maxAttachmentBytes,\n defaultMaxAttachmentBytes,\n 'Attachment byte limit',\n );\n const maxAudioBytes = positiveByteLimit(\n options.maxAudioBytes,\n defaultMaxAudioBytes,\n 'Audio byte limit',\n );\n const maxTotalAttachmentBytes = positiveByteLimit(\n options.maxTotalAttachmentBytes,\n defaultMaxTotalAttachmentBytes,\n 'Total attachment byte limit',\n );\n const maxImagePreviewBytes = positiveByteLimit(\n options.maxImagePreviewBytes,\n maxPreviewBytes,\n 'Image preview byte limit',\n );\n\n const speech = createCodexSpeechSessions({ ...options, maxAudioBytes });\n const unregister = registerIpcMainHandlers<NativeRequests>(dependencies.ipcMain, {\n ...speech.handlers,\n [channels.copyToClipboard]: (_event, value) => {\n const content = clipboardContent(value);\n dependencies.clipboard.write(content);\n },\n [channels.ingestAttachments]: async (_event, value) => {\n const inputs = attachmentInputs(value, maxAttachmentBytes, maxTotalAttachmentBytes);\n if (inputs.length === 0) return [];\n const temporaryDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'codex-app-sdk-attachments-'));\n return Promise.all(inputs.map(async (input, index) => {\n const filePath = path.join(temporaryDirectory, `${index}-${safeFileName(input.name)}`);\n const data = Buffer.from(input.data);\n await fs.writeFile(filePath, data, { mode: 0o600 });\n return attachmentFromPath(attachments, filePath, {\n mimeType: input.mimeType ?? mimeTypeForPath(input.name),\n name: safeFileName(input.name),\n previewData: data,\n });\n }));\n },\n [channels.openExternal]: async (_event, value) => {\n await dependencies.shell.openExternal(externalHref(value));\n },\n [channels.pickAttachments]: async () => {\n const result = await dependencies.dialog.showOpenDialog({\n title: 'Add Files & Photos',\n properties: ['openFile', 'multiSelections'],\n filters: [\n { name: 'Files and photos', extensions: ['*'] },\n ],\n });\n if (result.canceled) return [];\n const pickedAttachments: CodexHostAttachment[] = [];\n let totalBytes = 0;\n let previewBytes = 0;\n for (const filePath of result.filePaths) {\n const metadata = await fs.stat(filePath);\n if (!metadata.isFile()) throw new TypeError(`Attachment is not a file: ${filePath}`);\n if (metadata.size > maxAttachmentBytes) {\n throw new RangeError(`Attachment exceeds the ${maxAttachmentBytes} byte limit: ${filePath}`);\n }\n totalBytes += metadata.size;\n if (totalBytes > maxTotalAttachmentBytes) {\n throw new RangeError(`Attachments exceed the ${maxTotalAttachmentBytes} total byte limit`);\n }\n const mimeType = mimeTypeForPath(filePath);\n const previewData = mimeType.startsWith('image/')\n && mimeType !== 'image/svg+xml'\n && metadata.size <= maxPreviewBytes\n && previewBytes + metadata.size <= maxTotalPreviewBytes\n ? await fs.readFile(filePath)\n : undefined;\n if (previewData) previewBytes += previewData.byteLength;\n pickedAttachments.push(attachmentFromPath(attachments, filePath, {\n mimeType,\n name: path.basename(filePath),\n previewData,\n size: metadata.size,\n }));\n }\n return pickedAttachments;\n },\n [channels.readImagePreview]: async (_event, value) => {\n const reference = nonEmptyString(value, 'Image preview attachment reference');\n const filePath = managedTemporaryAttachmentPath(reference) ?? attachments.path(reference);\n const mimeType = mimeTypeForPath(filePath);\n if (!mimeType.startsWith('image/') || mimeType === 'image/svg+xml') return null;\n let metadata;\n try {\n metadata = await fs.lstat(filePath);\n } catch (error) {\n if (isMissingFileError(error)) return null;\n throw error;\n }\n if (!metadata.isFile() || metadata.size > maxImagePreviewBytes) return null;\n const data = await fs.readFile(filePath);\n if (data.byteLength > maxImagePreviewBytes) return null;\n return `data:${mimeType};base64,${data.toString('base64')}`;\n },\n [channels.transcribeAudio]: async (_event, value, rawOptions) => {\n const audioData = arrayBuffer(value, 'Audio data');\n if (audioData.byteLength > maxAudioBytes) {\n throw new RangeError(`Audio data exceeds the ${maxAudioBytes} byte limit`);\n }\n const transcriptionOptions = appleSpeechOptions(rawOptions);\n const transcribe = options.transcribeAudio\n ?? ((data: Buffer, inputOptions?: AppleSpeechTranscriptionOptions) => (\n transcribeWithAppleSpeechAnalyzer(data, inputOptions, {\n ...(options.appleSpeechAssetsPath\n ? { assetsPath: options.appleSpeechAssetsPath }\n : {}),\n })\n ));\n return transcribe(Buffer.from(audioData), transcriptionOptions);\n },\n }, options);\n\n return () => {\n unregister();\n speech.dispose();\n attachments.clear();\n };\n}\n\nfunction attachmentInputs(\n value: unknown,\n maxBytes: number,\n maxTotalBytes: number,\n): CodexNativeAttachmentInput[] {\n if (!Array.isArray(value)) throw new TypeError('Attachments must be an array');\n if (value.length > 20) throw new RangeError('At most 20 attachments can be added at once');\n let totalBytes = 0;\n return value.map((entry) => {\n const record = objectRecord(entry, 'Attachment');\n const name = nonEmptyString(record.name, 'Attachment name');\n const data = arrayBuffer(record.data, 'Attachment data');\n if (data.byteLength > maxBytes) {\n throw new RangeError(`Attachment '${name}' exceeds the ${maxBytes} byte limit`);\n }\n totalBytes += data.byteLength;\n if (totalBytes > maxTotalBytes) {\n throw new RangeError(`Attachments exceed the ${maxTotalBytes} total byte limit`);\n }\n return {\n name,\n data,\n ...(record.mimeType === undefined\n ? {}\n : { mimeType: nonEmptyString(record.mimeType, 'Attachment MIME type') }),\n };\n });\n}\n\nfunction attachmentFromPath(\n attachments: CodexElectronAttachmentRegistry,\n filePath: string,\n metadata: {\n mimeType: string;\n name: string;\n previewData?: Uint8Array;\n size?: number;\n },\n): CodexHostAttachment {\n const size = metadata.size ?? metadata.previewData?.byteLength ?? 0;\n return attachments.register({\n type: metadata.mimeType.startsWith('image/') ? 'image' : 'file',\n path: filePath,\n name: metadata.name,\n mimeType: metadata.mimeType,\n size,\n ...(metadata.previewData\n && metadata.mimeType !== 'image/svg+xml'\n && metadata.previewData.byteLength <= maxPreviewBytes\n ? { previewUrl: `data:${metadata.mimeType};base64,${Buffer.from(metadata.previewData).toString('base64')}` }\n : {}),\n });\n}\n\nfunction clipboardContent(value: unknown): CodexNativeClipboardContent {\n const record = objectRecord(value, 'Clipboard content');\n const text = typeof record.text === 'string' ? record.text : invalid('Clipboard text must be a string');\n const html = record.html === undefined\n ? undefined\n : typeof record.html === 'string'\n ? record.html\n : invalid('Clipboard HTML must be a string');\n if (text.length > 5_000_000 || (html?.length ?? 0) > 10_000_000) {\n throw new RangeError('Clipboard content is too large');\n }\n return { text, ...(html ? { html } : {}) };\n}\n\nfunction externalHref(value: unknown): string {\n const href = nonEmptyString(value, 'External URL');\n const url = new URL(href);\n if (!['http:', 'https:', 'mailto:', 'tel:'].includes(url.protocol.toLowerCase())) {\n throw new TypeError(`Unsupported external URL protocol: ${url.protocol}`);\n }\n return url.href;\n}\n\nfunction appleSpeechOptions(value: unknown): AppleSpeechTranscriptionOptions | undefined {\n if (value === undefined) return undefined;\n const record = objectRecord(value, 'Speech transcription options');\n if (record.live !== undefined && typeof record.live !== 'boolean') {\n throw new TypeError('Speech transcription live mode must be a boolean');\n }\n return {\n ...(record.locale === undefined\n ? {}\n : { locale: nonEmptyString(record.locale, 'Speech transcription locale') }),\n ...(record.live === undefined ? {} : { live: record.live }),\n };\n}\n\nfunction arrayBuffer(value: unknown, label: string): ArrayBuffer {\n if (!(value instanceof ArrayBuffer)) throw new TypeError(`${label} must be an ArrayBuffer`);\n return value;\n}\n\nfunction objectRecord(value: unknown, label: string): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new TypeError(`${label} must be an object`);\n }\n return value as Record<string, unknown>;\n}\n\nfunction nonEmptyString(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value.trim()) throw new TypeError(`${label} must be a non-empty string`);\n return value.trim();\n}\n\nfunction isMissingFileError(error: unknown): boolean {\n return Boolean(error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT');\n}\n\nfunction safeFileName(value: string): string {\n const name = path.basename(value).replace(/[\\u0000-\\u001f\\u007f]/g, '').trim();\n return name || 'attachment';\n}\n\nfunction managedTemporaryAttachmentPath(value: string): string | null {\n if (!path.isAbsolute(value)) return null;\n const resolved = path.resolve(value);\n const directory = path.dirname(resolved);\n if (path.dirname(directory) !== path.resolve(os.tmpdir())) return null;\n return /^codex-app-sdk-attachments-[a-z\\d_-]+$/i.test(path.basename(directory))\n ? resolved\n : null;\n}\n\nfunction positiveByteLimit(value: number | undefined, fallback: number, label: string): number {\n if (value === undefined) return fallback;\n if (!Number.isSafeInteger(value) || value <= 0) throw new TypeError(`${label} must be a positive integer`);\n return value;\n}\n\nfunction mimeTypeForPath(filePath: string): string {\n const extension = path.extname(filePath).slice(1).toLowerCase();\n return ({\n avif: 'image/avif',\n bmp: 'image/bmp',\n gif: 'image/gif',\n heic: 'image/heic',\n heif: 'image/heif',\n jpeg: 'image/jpeg',\n jpg: 'image/jpeg',\n png: 'image/png',\n svg: 'image/svg+xml',\n webp: 'image/webp',\n } as Record<string, string>)[extension] ?? 'application/octet-stream';\n}\n\nfunction invalid(message: string): never {\n throw new TypeError(message);\n}\n","import type { CodexSurface } from '@codex-app-sdk/backend';\nimport {\n registerCodexNativeIpc,\n type CodexNativeMainDependencies,\n type CodexNativeMainOptions,\n} from './codex-native-ipc';\nimport { registerCodexSurfaceIpc } from './codex-surface-ipc';\nimport type { IpcEventSender, IpcSenderPolicy } from './typed-ipc';\nimport { CodexElectronAttachmentRegistry } from './codex-attachment-registry';\n\nexport type CodexElectronMainOptions = CodexNativeMainDependencies & IpcSenderPolicy & {\n native?: CodexNativeMainOptions;\n sender: IpcEventSender;\n surface: CodexSurface;\n};\n\n/** Installs the complete SDK-owned surface and native capability bridge. */\nexport function registerCodexElectronMain(options: CodexElectronMainOptions): () => void {\n const attachments = new CodexElectronAttachmentRegistry();\n const senderPolicy = options.isTrustedSender ? { isTrustedSender: options.isTrustedSender } : {};\n const unregisterSurface = registerCodexSurfaceIpc(\n options.ipcMain,\n options.sender,\n options.surface,\n { ...senderPolicy, resolveAttachment: (attachment) => attachments.resolve(attachment) },\n );\n try {\n const unregisterNative = registerCodexNativeIpc(options, { ...options.native, ...senderPolicy }, attachments);\n return () => {\n unregisterNative();\n unregisterSurface();\n };\n } catch (error) {\n unregisterSurface();\n throw error;\n }\n}\n"],"mappings":"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"}
package/dist/preload.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as e, i as t, l as n, o as r, t as i } from "./chunks/codex-electron-preload-DupT4aeD.js";
1
+ import { a as e, i as t, l as n, o as r, t as i } from "./chunks/codex-electron-preload-C6b3Tzd7.js";
2
2
  export { n as TypedIpcRenderer, t as createCodexNativeRendererApi, r as createCodexSurfaceRendererApi, i as exposeCodexElectronPreload, e as exposeCodexNativeRendererApi };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codex-app-sdk/electron",
3
- "version": "0.15.1",
3
+ "version": "0.16.0",
4
4
  "description": "Electron main, preload, IPC, and native capability adapter for Codex applications.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -37,8 +37,8 @@
37
37
  "typecheck": "tsc -p tsconfig.json --noEmit"
38
38
  },
39
39
  "dependencies": {
40
- "@codex-app-sdk/backend": "0.15.1",
41
- "@codex-app-sdk/core": "0.15.1"
40
+ "@codex-app-sdk/backend": "0.16.0",
41
+ "@codex-app-sdk/core": "0.16.0"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "electron": ">=30"
@@ -1 +0,0 @@
1
- {"version":3,"file":"codex-electron-preload-DupT4aeD.js","names":[],"sources":["../../src/typed-ipc.ts","../../src/codex-surface-ipc.ts","../../src/codex-native-renderer.ts","../../src/codex-electron-preload.ts"],"sourcesContent":["import type { TypedEventBus } from '@codex-app-sdk/core/events';\n\nexport type IpcRequest<Arguments extends unknown[] = unknown[], Result = unknown> = {\n args: Arguments;\n result: Result;\n};\n\nexport type IpcRequestArguments<Request> = Request extends IpcRequest<infer Arguments, unknown>\n ? Arguments\n : never;\n\nexport type IpcRequestResult<Request> = Request extends IpcRequest<unknown[], infer Result>\n ? Result\n : never;\n\nexport type IpcRendererPort = {\n invoke(channel: string, ...args: unknown[]): Promise<unknown>;\n on(channel: string, listener: (event: unknown, payload: unknown) => void): void;\n off(channel: string, listener: (event: unknown, payload: unknown) => void): void;\n};\n\nexport type IpcMainPort = {\n handle(channel: string, handler: (event: unknown, ...args: unknown[]) => unknown): void;\n removeHandler(channel: string): void;\n};\n\nexport type IpcEventSender = {\n send(channel: string, payload: unknown): void;\n};\n\ntype RequestName<Requests> = keyof Requests & string;\ntype EventName<Events> = keyof Events & string;\n\nexport class TypedIpcRenderer<Requests extends object, Events extends object> {\n constructor(private readonly port: IpcRendererPort) {}\n\n invoke<Name extends RequestName<Requests>>(\n channel: Name,\n ...args: IpcRequestArguments<Requests[Name]>\n ): Promise<IpcRequestResult<Requests[Name]>> {\n return this.port.invoke(channel, ...args) as Promise<IpcRequestResult<Requests[Name]>>;\n }\n\n on<Name extends EventName<Events>>(channel: Name, listener: (payload: Events[Name]) => void): () => void {\n const handler = (_event: unknown, payload: unknown) => listener(payload as Events[Name]);\n this.port.on(channel, handler);\n return () => this.port.off(channel, handler);\n }\n}\n\nexport type IpcMainHandlers<Requests extends object> = {\n [Name in keyof Requests]: (\n event: unknown,\n ...args: IpcRequestArguments<Requests[Name]>\n ) => IpcRequestResult<Requests[Name]> | Promise<IpcRequestResult<Requests[Name]>>;\n};\n\nexport class TypedIpcMain<Requests extends object> {\n private readonly registeredChannels = new Set<RequestName<Requests>>();\n\n constructor(private readonly port: IpcMainPort) {}\n\n handle<Name extends RequestName<Requests>>(\n channel: Name,\n handler: IpcMainHandlers<Pick<Requests, Name>>[Name],\n ): void {\n this.port.handle(channel, (event, ...args) => handler(\n event,\n ...args as IpcRequestArguments<Requests[Name]>,\n ));\n this.registeredChannels.add(channel);\n }\n\n removeHandler<Name extends RequestName<Requests>>(channel: Name): void {\n this.port.removeHandler(channel);\n this.registeredChannels.delete(channel);\n }\n\n dispose(): void {\n for (const channel of this.registeredChannels) {\n this.port.removeHandler(channel);\n }\n this.registeredChannels.clear();\n }\n}\n\nexport type IpcSenderPolicy = {\n /** Rejects an invocation before its handler runs when this returns false. */\n isTrustedSender?: (event: unknown) => boolean;\n};\n\nexport function registerIpcMainHandlers<Requests extends object>(\n port: IpcMainPort,\n handlers: IpcMainHandlers<Requests>,\n policy: IpcSenderPolicy = {},\n): () => void {\n const main = new TypedIpcMain<Requests>(port);\n const channels = Object.keys(handlers) as Array<RequestName<Requests>>;\n const { isTrustedSender } = policy;\n for (const channel of channels) {\n const handler = handlers[channel];\n main.handle(channel, isTrustedSender\n ? (event, ...args) => {\n if (!isTrustedSender(event)) throw new Error(`Rejected ${channel} from an untrusted sender`);\n return handler(event, ...args);\n }\n : handler);\n }\n return () => main.dispose();\n}\n\nexport function sendIpcEvent<Events extends object, Name extends EventName<Events>>(\n sender: IpcEventSender,\n channel: Name,\n payload: Events[Name],\n): void {\n sender.send(channel, payload);\n}\n\nexport function connectIpcEventsToBus<Events extends object>(\n renderer: Pick<TypedIpcRenderer<object, Events>, 'on'>,\n bus: TypedEventBus<Events>,\n channels: ReadonlyArray<EventName<Events>>,\n): () => void {\n const unsubscribers = channels.map((channel) => renderer.on(channel, (payload) => bus.emit(channel, payload)));\n return () => {\n for (const unsubscribe of unsubscribers) {\n unsubscribe();\n }\n };\n}\n","import {\n invokeCodexSurfaceBridgeOperation,\n type CodexSurfaceBridgeOperation,\n type CodexSurfaceBridgeTarget,\n} from '@codex-app-sdk/core/surface-bridge';\nimport type {\n CodexConversationHistory,\n CodexConversationPromptHistory,\n CodexConversationSummary,\n CodexSurfaceApprovalDecision,\n CodexSurfaceApprovalScope,\n CodexSurfaceChatGptDeviceCodeLogin,\n CodexSurfaceChatGptLogin,\n CodexSurfaceClientRequestResponse,\n CodexSurfaceEvent,\n CodexSurfaceModel,\n CodexSurfaceRendererApi,\n CodexSurfaceSnapshot,\n CreateCodexRendererConversationOptions,\n ListCodexConversationsOptions,\n ListCodexModelsOptions,\n CodexRendererSendMessageOptions,\n StartCodexReviewOptions,\n StartCodexLiveChatOptions,\n UpdateCodexConversationSettings,\n CodexSurfaceStatePatch,\n CodexVersionedSurfaceSnapshot,\n} from '@codex-app-sdk/core/surface';\nimport {\n isCodexSurfaceStatePatchSource,\n subscribeCodexSurfaceState,\n type CodexSurfaceStatePatchSource,\n} from '@codex-app-sdk/core/surface-bridge';\nimport {\n registerIpcMainHandlers,\n TypedIpcRenderer,\n type IpcEventSender,\n type IpcMainPort,\n type IpcRendererPort,\n type IpcRequest,\n type IpcSenderPolicy,\n} from './typed-ipc';\n\nexport type CodexSurfaceIpcOptions = IpcSenderPolicy & {\n resolveAttachment?: import('@codex-app-sdk/core/surface-bridge').CodexSurfaceBridgeAttachmentResolver;\n};\n\nconst channels = {\n archiveConversation: 'codex-surface:archive-conversation',\n cancelLogin: 'codex-surface:cancel-login',\n clearGoal: 'codex-surface:clear-goal',\n compactConversation: 'codex-surface:compact-conversation',\n connect: 'codex-surface:connect',\n continueInterruptedTurn: 'codex-surface:continue-interrupted-turn',\n createConversation: 'codex-surface:create-conversation',\n deleteConversation: 'codex-surface:delete-conversation',\n deleteTurn: 'codex-surface:delete-turn',\n deleteQueuedPrompt: 'codex-surface:delete-queued-prompt',\n editTurn: 'codex-surface:edit-turn',\n forkTurn: 'codex-surface:fork-turn',\n getSnapshot: 'codex-surface:get-snapshot',\n getVersionedSnapshot: 'codex-surface:get-versioned-snapshot',\n interrupt: 'codex-surface:interrupt',\n listConversations: 'codex-surface:list-conversations',\n listModels: 'codex-surface:list-models',\n logout: 'codex-surface:logout',\n readConversationHistory: 'codex-surface:read-conversation-history',\n readConversationPromptHistory: 'codex-surface:read-conversation-prompt-history',\n loadOlderConversationHistory: 'codex-surface:load-older-conversation-history',\n refreshAccount: 'codex-surface:refresh-account',\n refreshConversations: 'codex-surface:refresh-conversations',\n renameConversation: 'codex-surface:rename-conversation',\n respondToClientRequest: 'codex-surface:respond-to-client-request',\n resolveApproval: 'codex-surface:resolve-approval',\n retryTurn: 'codex-surface:retry-turn',\n setGoal: 'codex-surface:set-goal',\n selectConversation: 'codex-surface:select-conversation',\n sendMessage: 'codex-surface:send-message',\n startReview: 'codex-surface:start-review',\n startLiveChat: 'codex-surface:start-live-chat',\n stopLiveChat: 'codex-surface:stop-live-chat',\n startChatGptDeviceCodeLogin: 'codex-surface:start-chatgpt-device-code-login',\n startChatGptLogin: 'codex-surface:start-chatgpt-login',\n steerMessage: 'codex-surface:steer-message',\n steerQueuedPrompt: 'codex-surface:steer-queued-prompt',\n unarchiveConversation: 'codex-surface:unarchive-conversation',\n updateConversationSettings: 'codex-surface:update-conversation-settings',\n updateQueuedPrompt: 'codex-surface:update-queued-prompt',\n stateChanged: 'codex-surface:state-changed',\n statePatch: 'codex-surface:state-patch',\n event: 'codex-surface:event',\n} as const;\n\ntype SurfaceRequests = {\n [channels.archiveConversation]: IpcRequest<[conversationId: string], CodexSurfaceSnapshot>;\n [channels.cancelLogin]: IpcRequest<[loginId?: string], CodexSurfaceSnapshot>;\n [channels.clearGoal]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.compactConversation]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.connect]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.continueInterruptedTurn]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.createConversation]: IpcRequest<[options?: CreateCodexRendererConversationOptions], CodexSurfaceSnapshot>;\n [channels.deleteConversation]: IpcRequest<[conversationId: string], CodexSurfaceSnapshot>;\n [channels.deleteTurn]: IpcRequest<[turnId: string], CodexSurfaceSnapshot>;\n [channels.deleteQueuedPrompt]: IpcRequest<[promptId: string], CodexSurfaceSnapshot>;\n [channels.editTurn]: IpcRequest<[turnId: string, content: string], CodexSurfaceSnapshot>;\n [channels.forkTurn]: IpcRequest<[turnId: string], CodexSurfaceSnapshot>;\n [channels.getSnapshot]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.getVersionedSnapshot]: IpcRequest<[], CodexVersionedSurfaceSnapshot | null>;\n [channels.interrupt]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.listConversations]: IpcRequest<[\n options?: ListCodexConversationsOptions,\n ], CodexConversationSummary[]>;\n [channels.listModels]: IpcRequest<[options?: ListCodexModelsOptions], CodexSurfaceModel[]>;\n [channels.logout]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.readConversationHistory]: IpcRequest<[conversationId?: string], CodexConversationHistory>;\n [channels.readConversationPromptHistory]: IpcRequest<[\n conversationId?: string,\n ], CodexConversationPromptHistory>;\n [channels.loadOlderConversationHistory]: IpcRequest<[conversationId?: string], import('@codex-app-sdk/core/surface').CodexConversationHistoryPage>;\n [channels.refreshAccount]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.refreshConversations]: IpcRequest<[], CodexSurfaceSnapshot>;\n [channels.renameConversation]: IpcRequest<[title: string], CodexSurfaceSnapshot>;\n [channels.respondToClientRequest]: IpcRequest<[response: CodexSurfaceClientRequestResponse], CodexSurfaceSnapshot>;\n [channels.resolveApproval]: IpcRequest<[\n approvalId: string,\n decision: CodexSurfaceApprovalDecision,\n scope?: CodexSurfaceApprovalScope,\n ], CodexSurfaceSnapshot>;\n [channels.retryTurn]: IpcRequest<[turnId: string], CodexSurfaceSnapshot>;\n [channels.setGoal]: IpcRequest<[objective: string, tokenBudget?: number | null], CodexSurfaceSnapshot>;\n [channels.selectConversation]: IpcRequest<[conversationId: string], CodexSurfaceSnapshot>;\n [channels.sendMessage]: IpcRequest<[prompt: string, options?: CodexRendererSendMessageOptions], CodexSurfaceSnapshot>;\n [channels.startReview]: IpcRequest<[options?: StartCodexReviewOptions], CodexSurfaceSnapshot>;\n [channels.startLiveChat]: IpcRequest<[conversationId: string, options: StartCodexLiveChatOptions], { sdp: string }>;\n [channels.stopLiveChat]: IpcRequest<[conversationId: string], void>;\n [channels.startChatGptDeviceCodeLogin]: IpcRequest<[], CodexSurfaceChatGptDeviceCodeLogin>;\n [channels.startChatGptLogin]: IpcRequest<[], CodexSurfaceChatGptLogin>;\n [channels.steerMessage]: IpcRequest<[\n prompt: string,\n options?: CodexRendererSendMessageOptions,\n ], CodexSurfaceSnapshot>;\n [channels.steerQueuedPrompt]: IpcRequest<[promptId: string, prompt?: string], CodexSurfaceSnapshot>;\n [channels.unarchiveConversation]: IpcRequest<[conversationId: string], CodexSurfaceSnapshot>;\n [channels.updateConversationSettings]: IpcRequest<[settings: UpdateCodexConversationSettings], CodexSurfaceSnapshot>;\n [channels.updateQueuedPrompt]: IpcRequest<[promptId: string, prompt: string], CodexSurfaceSnapshot>;\n};\n\ntype SurfaceEvents = {\n [channels.stateChanged]: CodexSurfaceSnapshot;\n [channels.statePatch]: CodexSurfaceStatePatch;\n [channels.event]: CodexSurfaceEvent;\n};\n\nexport type { CodexSurfaceRendererApi } from '@codex-app-sdk/core/surface';\n\ntype OptionalSurfaceOperation = 'loadOlderConversationHistory' | 'startLiveChat' | 'stopLiveChat';\n\nexport function registerCodexSurfaceIpc(\n port: IpcMainPort,\n sender: IpcEventSender,\n surface: Omit<CodexSurfaceBridgeTarget, OptionalSurfaceOperation>\n & Partial<Pick<CodexSurfaceBridgeTarget, OptionalSurfaceOperation>>\n & Partial<CodexSurfaceStatePatchSource>,\n options: CodexSurfaceIpcOptions = {},\n): () => void {\n // State crosses IPC as full snapshots until a renderer asks for a versioned\n // base; from then on it streams small patches. Older renderers never ask, and\n // surfaces without native patch support decline, so both keep snapshots.\n const patchSource = isCodexSurfaceStatePatchSource(surface) ? surface : null;\n let streamingPatches = false;\n const invoke = <Name extends CodexSurfaceBridgeOperation>(name: Name, args: readonly unknown[]) => {\n if (name === 'loadOlderConversationHistory' && !surface.loadOlderConversationHistory) {\n return Promise.reject(new Error('Conversation history paging is not available.'));\n }\n if ((name === 'startLiveChat' || name === 'stopLiveChat') && !surface[name]) {\n return Promise.reject(new Error('Live chat is not available.'));\n }\n return invokeCodexSurfaceBridgeOperation(\n surface as CodexSurfaceBridgeTarget,\n name,\n args,\n {\n operationLabel: channels[name],\n ...(options.resolveAttachment === undefined\n ? {}\n : { resolveAttachment: options.resolveAttachment }),\n },\n );\n };\n const unregisterHandlers = registerIpcMainHandlers<SurfaceRequests>(port, {\n [channels.archiveConversation]: (_event, ...args) => invoke('archiveConversation', args),\n [channels.cancelLogin]: (_event, ...args) => invoke('cancelLogin', args),\n [channels.clearGoal]: (_event, ...args) => invoke('clearGoal', args),\n [channels.compactConversation]: (_event, ...args) => invoke('compactConversation', args),\n [channels.connect]: (_event, ...args) => invoke('connect', args),\n [channels.continueInterruptedTurn]: (_event, ...args) => invoke('continueInterruptedTurn', args),\n [channels.createConversation]: (_event, ...args) => invoke('createConversation', args),\n [channels.deleteConversation]: (_event, ...args) => invoke('deleteConversation', args),\n [channels.deleteTurn]: (_event, ...args) => invoke('deleteTurn', args),\n [channels.deleteQueuedPrompt]: (_event, ...args) => invoke('deleteQueuedPrompt', args),\n [channels.editTurn]: (_event, ...args) => invoke('editTurn', args),\n [channels.forkTurn]: (_event, ...args) => invoke('forkTurn', args),\n [channels.getSnapshot]: (_event, ...args) => invoke('getSnapshot', args),\n [channels.getVersionedSnapshot]: async () => {\n if (!patchSource) return null;\n streamingPatches = true;\n return patchSource.getVersionedSnapshot();\n },\n [channels.interrupt]: (_event, ...args) => invoke('interrupt', args),\n [channels.listConversations]: (_event, ...args) => invoke('listConversations', args),\n [channels.listModels]: (_event, ...args) => invoke('listModels', args),\n [channels.logout]: (_event, ...args) => invoke('logout', args),\n [channels.readConversationHistory]: (_event, ...args) => invoke('readConversationHistory', args),\n [channels.readConversationPromptHistory]: (_event, ...args) => invoke('readConversationPromptHistory', args),\n [channels.loadOlderConversationHistory]: (_event, ...args) => invoke('loadOlderConversationHistory', args),\n [channels.refreshAccount]: (_event, ...args) => invoke('refreshAccount', args),\n [channels.refreshConversations]: (_event, ...args) => invoke('refreshConversations', args),\n [channels.renameConversation]: (_event, ...args) => invoke('renameConversation', args),\n [channels.respondToClientRequest]: (_event, ...args) => invoke('respondToClientRequest', args),\n [channels.resolveApproval]: (_event, ...args) => invoke('resolveApproval', args),\n [channels.retryTurn]: (_event, ...args) => invoke('retryTurn', args),\n [channels.setGoal]: (_event, ...args) => invoke('setGoal', args),\n [channels.selectConversation]: (_event, ...args) => invoke('selectConversation', args),\n [channels.sendMessage]: (_event, ...args) => invoke('sendMessage', args),\n [channels.startReview]: (_event, ...args) => invoke('startReview', args),\n [channels.startLiveChat]: (_event, ...args) => invoke('startLiveChat', args),\n [channels.stopLiveChat]: (_event, ...args) => invoke('stopLiveChat', args),\n [channels.startChatGptDeviceCodeLogin]: (_event, ...args) => invoke('startChatGptDeviceCodeLogin', args),\n [channels.startChatGptLogin]: (_event, ...args) => invoke('startChatGptLogin', args),\n [channels.steerMessage]: (_event, ...args) => invoke('steerMessage', args),\n [channels.steerQueuedPrompt]: (_event, ...args) => invoke('steerQueuedPrompt', args),\n [channels.unarchiveConversation]: (_event, ...args) => invoke('unarchiveConversation', args),\n [channels.updateConversationSettings]: (_event, ...args) => invoke('updateConversationSettings', args),\n [channels.updateQueuedPrompt]: (_event, ...args) => invoke('updateQueuedPrompt', args),\n }, options);\n const unsubscribeSnapshots = surface.onStateChange((snapshot) => {\n if (!streamingPatches) sender.send(channels.stateChanged, snapshot);\n });\n const unsubscribePatches = patchSource?.onStatePatch((patch) => {\n if (streamingPatches) sender.send(channels.statePatch, patch);\n });\n const unsubscribeState = () => {\n unsubscribePatches?.();\n unsubscribeSnapshots();\n };\n const unsubscribeEvents = surface.onEvent((event) => sender.send(channels.event, event));\n return () => {\n unsubscribeEvents();\n unsubscribeState();\n unregisterHandlers();\n };\n}\n\nexport function createCodexSurfaceRendererApi(port: IpcRendererPort): CodexSurfaceRendererApi {\n const renderer = new TypedIpcRenderer<SurfaceRequests, SurfaceEvents>(port);\n const getVersionedSnapshot = () => renderer.invoke(channels.getVersionedSnapshot);\n const onStatePatch = (listener: (patch: CodexSurfaceStatePatch) => void) => renderer.on(channels.statePatch, listener);\n const stateSource = { getVersionedSnapshot, onStatePatch };\n return {\n // Mirror patches in the renderer's own world: contextBridge copies every\n // value it passes, so a mirror kept in the preload would lose identity.\n getVersionedSnapshot,\n onStatePatch,\n archiveConversation: (conversationId) => renderer.invoke(channels.archiveConversation, conversationId),\n cancelLogin: (loginId) => renderer.invoke(channels.cancelLogin, loginId),\n clearGoal: () => renderer.invoke(channels.clearGoal),\n compactConversation: () => renderer.invoke(channels.compactConversation),\n connect: () => renderer.invoke(channels.connect),\n continueInterruptedTurn: () => renderer.invoke(channels.continueInterruptedTurn),\n createConversation: (options) => renderer.invoke(channels.createConversation, options),\n deleteConversation: (conversationId) => renderer.invoke(channels.deleteConversation, conversationId),\n deleteTurn: (turnId) => renderer.invoke(channels.deleteTurn, turnId),\n deleteQueuedPrompt: (promptId) => renderer.invoke(channels.deleteQueuedPrompt, promptId),\n editTurn: (turnId, content) => renderer.invoke(channels.editTurn, turnId, content),\n forkTurn: (turnId) => renderer.invoke(channels.forkTurn, turnId),\n getSnapshot: () => renderer.invoke(channels.getSnapshot),\n interrupt: () => renderer.invoke(channels.interrupt),\n listConversations: (options) => renderer.invoke(channels.listConversations, options),\n listModels: (options) => renderer.invoke(channels.listModels, options),\n logout: () => renderer.invoke(channels.logout),\n onEvent: (listener) => renderer.on(channels.event, listener),\n onStateChange: (listener) => {\n // Snapshots arrive until the main process switches to patches; the\n // switch point's base was already delivered as a snapshot, so it stays silent.\n const unsubscribeSnapshots = renderer.on(channels.stateChanged, listener);\n const unsubscribePatches = subscribeCodexSurfaceState(stateSource, listener, { emitInitialSnapshot: false });\n return () => {\n unsubscribePatches();\n unsubscribeSnapshots();\n };\n },\n readConversationHistory: (conversationId) => renderer.invoke(channels.readConversationHistory, conversationId),\n readConversationPromptHistory: (conversationId) => (\n renderer.invoke(channels.readConversationPromptHistory, conversationId)\n ),\n loadOlderConversationHistory: (conversationId) => renderer.invoke(channels.loadOlderConversationHistory, conversationId),\n refreshAccount: () => renderer.invoke(channels.refreshAccount),\n refreshConversations: () => renderer.invoke(channels.refreshConversations),\n renameConversation: (title) => renderer.invoke(channels.renameConversation, title),\n respondToClientRequest: (response) => renderer.invoke(channels.respondToClientRequest, response),\n resolveApproval: (approvalId, decision, scope) => renderer.invoke(channels.resolveApproval, approvalId, decision, scope),\n retryTurn: (turnId) => renderer.invoke(channels.retryTurn, turnId),\n setGoal: (objective, tokenBudget) => renderer.invoke(channels.setGoal, objective, tokenBudget),\n selectConversation: (conversationId) => renderer.invoke(channels.selectConversation, conversationId),\n sendMessage: (prompt, options) => renderer.invoke(channels.sendMessage, prompt, options),\n startReview: (options) => renderer.invoke(channels.startReview, options),\n startLiveChat: (conversationId, options) => renderer.invoke(channels.startLiveChat, conversationId, options),\n stopLiveChat: (conversationId) => renderer.invoke(channels.stopLiveChat, conversationId),\n startChatGptDeviceCodeLogin: () => renderer.invoke(channels.startChatGptDeviceCodeLogin),\n startChatGptLogin: () => renderer.invoke(channels.startChatGptLogin),\n steerMessage: (prompt, options) => renderer.invoke(channels.steerMessage, prompt, options),\n steerQueuedPrompt: (promptId, prompt) => renderer.invoke(channels.steerQueuedPrompt, promptId, prompt),\n unarchiveConversation: (conversationId) => renderer.invoke(channels.unarchiveConversation, conversationId),\n updateConversationSettings: (settings) => renderer.invoke(channels.updateConversationSettings, settings),\n updateQueuedPrompt: (promptId, prompt) => renderer.invoke(channels.updateQueuedPrompt, promptId, prompt),\n };\n}\n","import type {\n CodexNativeAttachment,\n CodexNativeAttachmentInput,\n CodexNativeClipboardContent,\n CodexNativeRendererApi,\n CodexSpeechTranscriptionResult,\n CodexSpeechSessionOptions,\n CodexSpeechSessionEvent,\n} from '@codex-app-sdk/core/native';\nimport {\n TypedIpcRenderer,\n type IpcRendererPort,\n type IpcRequest,\n} from './typed-ipc';\n\nexport const codexNativeChannels = {\n copyToClipboard: 'codex-native:copy-to-clipboard',\n ingestAttachments: 'codex-native:ingest-attachments',\n openExternal: 'codex-native:open-external',\n pickAttachments: 'codex-native:pick-attachments',\n readImagePreview: 'codex-native:read-image-preview',\n transcribeAudio: 'codex-native:transcribe-audio',\n startSpeech: 'codex-native:start-speech',\n appendSpeech: 'codex-native:append-speech',\n stopSpeech: 'codex-native:stop-speech',\n cancelSpeech: 'codex-native:cancel-speech',\n} as const;\nexport const codexSpeechEventChannel = 'codex-native:speech-event';\n\nexport type CodexNativeRequests = {\n [codexNativeChannels.startSpeech]: IpcRequest<[options: CodexSpeechSessionOptions], void>;\n [codexNativeChannels.appendSpeech]: IpcRequest<[sessionId: string, audio: ArrayBuffer], void>;\n [codexNativeChannels.stopSpeech]: IpcRequest<[sessionId: string], CodexSpeechTranscriptionResult>;\n [codexNativeChannels.cancelSpeech]: IpcRequest<[sessionId: string], void>;\n [codexNativeChannels.copyToClipboard]: IpcRequest<[content: CodexNativeClipboardContent], void>;\n [codexNativeChannels.ingestAttachments]: IpcRequest<[\n files: readonly CodexNativeAttachmentInput[],\n ], CodexNativeAttachment[]>;\n [codexNativeChannels.openExternal]: IpcRequest<[href: string], void>;\n [codexNativeChannels.pickAttachments]: IpcRequest<[], CodexNativeAttachment[]>;\n [codexNativeChannels.readImagePreview]: IpcRequest<[path: string], string | null>;\n [codexNativeChannels.transcribeAudio]: IpcRequest<[\n audioData: ArrayBuffer,\n options?: { locale?: string; live?: boolean },\n ], CodexSpeechTranscriptionResult>;\n};\n\nexport type CodexContextBridge = {\n exposeInMainWorld(key: string, api: unknown): void;\n};\n\nexport function createCodexNativeRendererApi(\n port: IpcRendererPort,\n options: { transcription?: boolean; streamingTranscription?: boolean } = {},\n): CodexNativeRendererApi {\n const renderer = new TypedIpcRenderer<CodexNativeRequests, { [codexSpeechEventChannel]: CodexSpeechSessionEvent }>(port);\n const transcription = options.transcription ?? process.platform === 'darwin';\n return {\n capabilities: {\n attachments: true,\n clipboard: true,\n externalLinks: true,\n transcription,\n },\n ...(transcription && (options.streamingTranscription ?? process.platform === 'darwin') ? {\n streamingTranscription: {\n start: (input: CodexSpeechSessionOptions) => renderer.invoke(codexNativeChannels.startSpeech, input),\n append: (id: string, audio: ArrayBuffer) => renderer.invoke(codexNativeChannels.appendSpeech, id, audio),\n stop: (id: string) => renderer.invoke(codexNativeChannels.stopSpeech, id),\n cancel: (id: string) => renderer.invoke(codexNativeChannels.cancelSpeech, id),\n onEvent: (listener: (event: CodexSpeechSessionEvent) => void) => renderer.on(codexSpeechEventChannel, listener),\n },\n } : {}),\n copyToClipboard: (content) => renderer.invoke(codexNativeChannels.copyToClipboard, content),\n ingestAttachments: (files) => renderer.invoke(codexNativeChannels.ingestAttachments, files),\n openExternal: (href) => renderer.invoke(codexNativeChannels.openExternal, href),\n pickAttachments: () => renderer.invoke(codexNativeChannels.pickAttachments),\n readImagePreview: (path) => renderer.invoke(codexNativeChannels.readImagePreview, path),\n transcribeAudio: (audioData, transcriptionOptions) => (\n renderer.invoke(codexNativeChannels.transcribeAudio, audioData, transcriptionOptions)\n ),\n };\n}\n\nexport function exposeCodexNativeRendererApi(\n contextBridge: CodexContextBridge,\n port: IpcRendererPort,\n options?: { transcription?: boolean; streamingTranscription?: boolean },\n): CodexNativeRendererApi {\n const api = createCodexNativeRendererApi(port, options);\n contextBridge.exposeInMainWorld('codexAppSdkNative', api);\n return api;\n}\n","import type { CodexNativeRendererApi } from '@codex-app-sdk/core/native';\nimport type { CodexSurfaceRendererApi } from '@codex-app-sdk/core/surface';\nimport {\n createCodexNativeRendererApi,\n type CodexContextBridge,\n} from './codex-native-renderer';\nimport { createCodexSurfaceRendererApi } from './codex-surface-ipc';\nimport type { IpcRendererPort } from './typed-ipc';\n\nexport type CodexElectronRendererApis = {\n native: CodexNativeRendererApi;\n surface: CodexSurfaceRendererApi;\n};\n\n/** Exposes the SDK-owned renderer APIs under stable, automatically detected names. */\nexport function exposeCodexElectronPreload(\n contextBridge: CodexContextBridge,\n ipcRenderer: IpcRendererPort,\n options?: { transcription?: boolean },\n): CodexElectronRendererApis {\n const surface = createCodexSurfaceRendererApi(ipcRenderer);\n const native = createCodexNativeRendererApi(ipcRenderer, options);\n contextBridge.exposeInMainWorld('codexSurface', surface);\n contextBridge.exposeInMainWorld('codexAppSdkNative', native);\n return { native, surface };\n}\n"],"mappings":"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"}