@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.
- package/dist/chunks/{codex-electron-preload-DupT4aeD.js → codex-electron-preload-C6b3Tzd7.js} +10 -1
- package/dist/chunks/codex-electron-preload-C6b3Tzd7.js.map +1 -0
- package/dist/codex-native-ipc.d.ts +3 -0
- package/dist/codex-native-ipc.d.ts.map +1 -1
- package/dist/codex-speech-sessions.d.ts +4 -0
- package/dist/codex-speech-sessions.d.ts.map +1 -1
- package/dist/codex-surface-ipc.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +103 -84
- package/dist/index.js.map +1 -1
- package/dist/preload.js +1 -1
- package/package.json +3 -3
- package/dist/chunks/codex-electron-preload-DupT4aeD.js.map +0 -1
package/dist/chunks/{codex-electron-preload-DupT4aeD.js → codex-electron-preload-C6b3Tzd7.js}
RENAMED
|
@@ -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-
|
|
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;
|
|
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;
|
|
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,
|
|
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';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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-
|
|
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(
|
|
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
|
|
99
|
-
let
|
|
100
|
-
if (!a || a.owner.sender !==
|
|
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
|
|
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 (
|
|
109
|
-
let
|
|
110
|
-
if (!
|
|
111
|
-
let
|
|
112
|
-
if (t.has(
|
|
113
|
-
let
|
|
114
|
-
|
|
115
|
-
},
|
|
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 ===
|
|
121
|
-
},
|
|
122
|
-
owner:
|
|
123
|
-
abort:
|
|
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(
|
|
126
|
-
if (t.get(
|
|
136
|
+
session: Promise.resolve().then(() => r("start", () => n(l, (e) => {
|
|
137
|
+
if (t.get(d) === h) {
|
|
127
138
|
try {
|
|
128
|
-
|
|
139
|
+
u.senderFrame.send(c, e);
|
|
129
140
|
} catch {
|
|
130
|
-
|
|
141
|
+
p();
|
|
131
142
|
}
|
|
132
|
-
e.type === "error" &&
|
|
143
|
+
e.type === "error" && p();
|
|
133
144
|
}
|
|
134
145
|
}, {
|
|
135
146
|
assetsPath: e.appleSpeechAssetsPath,
|
|
136
|
-
signal:
|
|
137
|
-
})),
|
|
147
|
+
signal: f.signal
|
|
148
|
+
}), () => f.signal.aborted)),
|
|
138
149
|
cleanup: () => {
|
|
139
|
-
for (let e of ["destroyed", "render-process-gone"])
|
|
140
|
-
|
|
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(
|
|
144
|
-
for (let e of ["destroyed", "render-process-gone"])
|
|
145
|
-
|
|
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
|
|
158
|
+
await h.session;
|
|
148
159
|
} catch (e) {
|
|
149
|
-
throw await
|
|
160
|
+
throw await s(d, h), e;
|
|
150
161
|
}
|
|
151
|
-
if (
|
|
162
|
+
if (f.signal.aborted) throw Error("Speech recording cancelled.");
|
|
152
163
|
},
|
|
153
164
|
[o.appendSpeech]: async (t, n, r) => {
|
|
154
|
-
let
|
|
155
|
-
if (
|
|
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 (
|
|
158
|
-
await (await
|
|
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
|
|
162
|
-
return
|
|
163
|
-
t.delete(n),
|
|
164
|
-
}),
|
|
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
|
|
178
|
+
t.has(n) && await s(n, a(e, n));
|
|
168
179
|
}
|
|
169
180
|
},
|
|
170
181
|
dispose: () => {
|
|
171
|
-
for (let [e, n] of t)
|
|
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
|
|
178
|
-
function
|
|
179
|
-
let i =
|
|
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 =
|
|
204
|
+
let r = P(n);
|
|
186
205
|
e.clipboard.write(r);
|
|
187
206
|
},
|
|
188
207
|
[o.ingestAttachments]: async (e, t) => {
|
|
189
|
-
let n =
|
|
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}-${
|
|
194
|
-
return await f.writeFile(n, i, { mode: 384 }),
|
|
195
|
-
mimeType: e.mimeType ??
|
|
196
|
-
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(
|
|
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 =
|
|
221
|
-
l && (o += l.byteLength), n.push(
|
|
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 =
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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:
|
|
285
|
+
...i.mimeType === void 0 ? {} : { mimeType: z(i.mimeType, "Attachment MIME type") }
|
|
267
286
|
};
|
|
268
287
|
});
|
|
269
288
|
}
|
|
270
|
-
function
|
|
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 <=
|
|
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
|
|
282
|
-
let t =
|
|
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
|
|
290
|
-
let 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
|
|
318
|
+
function I(e) {
|
|
300
319
|
if (e === void 0) return;
|
|
301
|
-
let t =
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
339
|
+
function B(e) {
|
|
321
340
|
return !!(e && typeof e == "object" && "code" in e && e.code === "ENOENT");
|
|
322
341
|
}
|
|
323
|
-
function
|
|
342
|
+
function V(e) {
|
|
324
343
|
return m.basename(e).replace(/[\u0000-\u001f\u007f]/g, "").trim() || "attachment";
|
|
325
344
|
}
|
|
326
|
-
function
|
|
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
|
|
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
|
|
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
|
|
369
|
+
function G(e) {
|
|
351
370
|
throw TypeError(e);
|
|
352
371
|
}
|
|
353
372
|
//#endregion
|
|
354
373
|
//#region src/codex-electron-integration.ts
|
|
355
|
-
function
|
|
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 =
|
|
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,
|
|
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-
|
|
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.
|
|
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.
|
|
41
|
-
"@codex-app-sdk/core": "0.
|
|
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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"}
|