@codex-app-sdk/electron 0.0.0-stage → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,41 @@
1
+ import { type AppleSpeechTranscriptionOptions, type AppleSpeechTranscriptionResult } from '@codex-app-sdk/backend';
2
+ import { type IpcMainPort, type IpcSenderPolicy } from './typed-ipc';
3
+ import { CodexElectronAttachmentRegistry } from './codex-attachment-registry';
4
+ export type CodexNativeDialog = {
5
+ showOpenDialog(options: {
6
+ filters?: {
7
+ name: string;
8
+ extensions: string[];
9
+ }[];
10
+ properties: Array<'multiSelections' | 'openFile'>;
11
+ title: string;
12
+ }): Promise<{
13
+ canceled: boolean;
14
+ filePaths: string[];
15
+ }>;
16
+ };
17
+ export type CodexNativeClipboard = {
18
+ write(content: {
19
+ html?: string;
20
+ text: string;
21
+ }): void;
22
+ };
23
+ export type CodexNativeShell = {
24
+ openExternal(href: string): Promise<void>;
25
+ };
26
+ export type CodexNativeMainOptions = IpcSenderPolicy & {
27
+ appleSpeechAssetsPath?: string;
28
+ maxAttachmentBytes?: number;
29
+ maxTotalAttachmentBytes?: number;
30
+ maxAudioBytes?: number;
31
+ maxImagePreviewBytes?: number;
32
+ transcribeAudio?: (audioData: Buffer, options?: AppleSpeechTranscriptionOptions) => Promise<AppleSpeechTranscriptionResult>;
33
+ };
34
+ export type CodexNativeMainDependencies = {
35
+ clipboard: CodexNativeClipboard;
36
+ dialog: CodexNativeDialog;
37
+ ipcMain: IpcMainPort;
38
+ shell: CodexNativeShell;
39
+ };
40
+ export declare function registerCodexNativeIpc(dependencies: CodexNativeMainDependencies, options?: CodexNativeMainOptions, attachments?: CodexElectronAttachmentRegistry): () => void;
41
+ //# sourceMappingURL=codex-native-ipc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-native-ipc.d.ts","sourceRoot":"","sources":["../src/codex-native-ipc.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,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;AAE9E,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,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,CA2HZ"}
@@ -0,0 +1,36 @@
1
+ import type { CodexNativeAttachment, CodexNativeAttachmentInput, CodexNativeClipboardContent, CodexNativeRendererApi, CodexSpeechTranscriptionResult } from '@codex-app-sdk/core/native';
2
+ import { type IpcRendererPort, type IpcRequest } from './typed-ipc';
3
+ export declare const codexNativeChannels: {
4
+ readonly copyToClipboard: "codex-native:copy-to-clipboard";
5
+ readonly ingestAttachments: "codex-native:ingest-attachments";
6
+ readonly openExternal: "codex-native:open-external";
7
+ readonly pickAttachments: "codex-native:pick-attachments";
8
+ readonly readImagePreview: "codex-native:read-image-preview";
9
+ readonly transcribeAudio: "codex-native:transcribe-audio";
10
+ };
11
+ export type CodexNativeRequests = {
12
+ [codexNativeChannels.copyToClipboard]: IpcRequest<[content: CodexNativeClipboardContent], void>;
13
+ [codexNativeChannels.ingestAttachments]: IpcRequest<[
14
+ files: readonly CodexNativeAttachmentInput[]
15
+ ], CodexNativeAttachment[]>;
16
+ [codexNativeChannels.openExternal]: IpcRequest<[href: string], void>;
17
+ [codexNativeChannels.pickAttachments]: IpcRequest<[], CodexNativeAttachment[]>;
18
+ [codexNativeChannels.readImagePreview]: IpcRequest<[path: string], string | null>;
19
+ [codexNativeChannels.transcribeAudio]: IpcRequest<[
20
+ audioData: ArrayBuffer,
21
+ options?: {
22
+ locale?: string;
23
+ live?: boolean;
24
+ }
25
+ ], CodexSpeechTranscriptionResult>;
26
+ };
27
+ export type CodexContextBridge = {
28
+ exposeInMainWorld(key: string, api: unknown): void;
29
+ };
30
+ export declare function createCodexNativeRendererApi(port: IpcRendererPort, options?: {
31
+ transcription?: boolean;
32
+ }): CodexNativeRendererApi;
33
+ export declare function exposeCodexNativeRendererApi(contextBridge: CodexContextBridge, port: IpcRendererPort, options?: {
34
+ transcription?: boolean;
35
+ }): CodexNativeRendererApi;
36
+ //# sourceMappingURL=codex-native-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-native-renderer.d.ts","sourceRoot":"","sources":["../src/codex-native-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,EAC3B,sBAAsB,EACtB,8BAA8B,EAC/B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAErB,eAAO,MAAM,mBAAmB;;;;;;;CAOtB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG;IAChC,CAAC,mBAAmB,CAAC,eAAe,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,EAAE,2BAA2B,CAAC,EAAE,IAAI,CAAC,CAAC;IAChG,CAAC,mBAAmB,CAAC,iBAAiB,CAAC,EAAE,UAAU,CAAC;QAClD,KAAK,EAAE,SAAS,0BAA0B,EAAE;KAC7C,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAC5B,CAAC,mBAAmB,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;IACrE,CAAC,mBAAmB,CAAC,eAAe,CAAC,EAAE,UAAU,CAAC,EAAE,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAC/E,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAClF,CAAC,mBAAmB,CAAC,eAAe,CAAC,EAAE,UAAU,CAAC;QAChD,SAAS,EAAE,WAAW;QACtB,OAAO,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,OAAO,CAAA;SAAE;KAC9C,EAAE,8BAA8B,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;CACpD,CAAC;AAEF,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,eAAe,EACrB,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAO,GACxC,sBAAsB,CAkBxB;AAED,wBAAgB,4BAA4B,CAC1C,aAAa,EAAE,kBAAkB,EACjC,IAAI,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,GACpC,sBAAsB,CAIxB"}
@@ -0,0 +1,12 @@
1
+ import { type CodexSurfaceBridgeTarget } from '@codex-app-sdk/core/surface-bridge';
2
+ import type { CodexSurfaceRendererApi } from '@codex-app-sdk/core/surface';
3
+ import { type CodexSurfaceStatePatchSource } from '@codex-app-sdk/core/surface-bridge';
4
+ import { type IpcEventSender, type IpcMainPort, type IpcRendererPort, type IpcSenderPolicy } from './typed-ipc';
5
+ export type CodexSurfaceIpcOptions = IpcSenderPolicy & {
6
+ resolveAttachment?: import('@codex-app-sdk/core/surface-bridge').CodexSurfaceBridgeAttachmentResolver;
7
+ };
8
+ export type { CodexSurfaceRendererApi } from '@codex-app-sdk/core/surface';
9
+ type OptionalSurfaceOperation = 'loadOlderConversationHistory' | 'startLiveChat' | 'stopLiveChat';
10
+ export declare function registerCodexSurfaceIpc(port: IpcMainPort, sender: IpcEventSender, surface: Omit<CodexSurfaceBridgeTarget, OptionalSurfaceOperation> & Partial<Pick<CodexSurfaceBridgeTarget, OptionalSurfaceOperation>> & Partial<CodexSurfaceStatePatchSource>, options?: CodexSurfaceIpcOptions): () => void;
11
+ export declare function createCodexSurfaceRendererApi(port: IpcRendererPort): CodexSurfaceRendererApi;
12
+ //# sourceMappingURL=codex-surface-ipc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-surface-ipc.d.ts","sourceRoot":"","sources":["../src/codex-surface-ipc.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAWV,uBAAuB,EAWxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAGL,KAAK,4BAA4B,EAClC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,eAAe,EAEpB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,sBAAsB,GAAG,eAAe,GAAG;IACrD,iBAAiB,CAAC,EAAE,OAAO,oCAAoC,EAAE,oCAAoC,CAAC;CACvG,CAAC;AA4GF,YAAY,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAE3E,KAAK,wBAAwB,GAAG,8BAA8B,GAAG,eAAe,GAAG,cAAc,CAAC;AAElG,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,IAAI,CAAC,wBAAwB,EAAE,wBAAwB,CAAC,GAC7D,OAAO,CAAC,IAAI,CAAC,wBAAwB,EAAE,wBAAwB,CAAC,CAAC,GACjE,OAAO,CAAC,4BAA4B,CAAC,EACzC,OAAO,GAAE,sBAA2B,GACnC,MAAM,IAAI,CAuFZ;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,eAAe,GAAG,uBAAuB,CA+D5F"}
@@ -0,0 +1,40 @@
1
+ type CodexNavigationEvent = {
2
+ url: string;
3
+ preventDefault(): void;
4
+ };
5
+ /** The `WebContents` subset used by `installCodexWindowPolicy`. */
6
+ export type CodexWindowPolicyTarget = {
7
+ on(event: 'will-navigate', listener: (event: CodexNavigationEvent) => void): unknown;
8
+ setWindowOpenHandler(handler: (details: {
9
+ url: string;
10
+ }) => {
11
+ action: 'deny';
12
+ }): void;
13
+ };
14
+ export type CodexWindowPolicyOptions = {
15
+ /** The URL loaded into the window: the dev server URL or the packaged renderer's `file:` URL. */
16
+ rendererUrl: string;
17
+ /** Usually Electron's `shell.openExternal`. Receives only http(s), mailto, and tel URLs. */
18
+ openExternal(url: string): Promise<void> | void;
19
+ };
20
+ /** Returns a normalized http(s), mailto, or tel URL that is safe to hand to the OS, otherwise null. */
21
+ export declare function codexExternalUrl(value: string): string | null;
22
+ /**
23
+ * True when `url` is the app's own renderer: the same origin as an http(s)
24
+ * dev server, or the same document as a packaged `file:` renderer.
25
+ */
26
+ export declare function isCodexRendererUrl(url: string | null | undefined, rendererUrl: string): boolean;
27
+ /**
28
+ * Keeps a window on the app renderer. Electron re-runs the preload script on
29
+ * every navigation, so any other page the window reached would receive the
30
+ * full Codex bridge. New windows and foreign navigations are denied; safe
31
+ * external URLs open in the system browser instead.
32
+ */
33
+ export declare function installCodexWindowPolicy(webContents: CodexWindowPolicyTarget, options: CodexWindowPolicyOptions): void;
34
+ /**
35
+ * IPC sender predicate for `registerCodexElectronMain`: accepts only the main
36
+ * frame of a window that is currently showing the app renderer.
37
+ */
38
+ export declare function isCodexRendererSender(event: unknown, rendererUrl: string): boolean;
39
+ export {};
40
+ //# sourceMappingURL=codex-window-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-window-policy.d.ts","sourceRoot":"","sources":["../src/codex-window-policy.ts"],"names":[],"mappings":"AAAA,KAAK,oBAAoB,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,IAAI,IAAI,CAAC;CACxB,CAAC;AAEF,mEAAmE;AACnE,MAAM,MAAM,uBAAuB,GAAG;IACpC,EAAE,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC;IACrF,oBAAoB,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACvF,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,iGAAiG;IACjG,WAAW,EAAE,MAAM,CAAC;IACpB,4FAA4F;IAC5F,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACjD,CAAC;AAIF,uGAAuG;AACvG,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO7D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAY/F;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,uBAAuB,EACpC,OAAO,EAAE,wBAAwB,GAChC,IAAI,CAcN;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAGlF"}
@@ -0,0 +1,10 @@
1
+ export { connectIpcEventsToBus, registerIpcMainHandlers, sendIpcEvent, TypedIpcMain, TypedIpcRenderer, type IpcEventSender, type IpcMainHandlers, type IpcMainPort, type IpcRendererPort, type IpcRequest, type IpcRequestArguments, type IpcRequestResult, type IpcSenderPolicy, } from './typed-ipc';
2
+ export { codexExternalUrl, installCodexWindowPolicy, isCodexRendererSender, isCodexRendererUrl, type CodexWindowPolicyOptions, type CodexWindowPolicyTarget, } from './codex-window-policy';
3
+ export { createCodexSurfaceRendererApi, registerCodexSurfaceIpc, type CodexSurfaceRendererApi, } from './codex-surface-ipc';
4
+ export { createCodexNativeRendererApi, exposeCodexNativeRendererApi, type CodexContextBridge, } from './codex-native-renderer';
5
+ export { registerCodexNativeIpc, type CodexNativeClipboard, type CodexNativeDialog, type CodexNativeMainDependencies, type CodexNativeMainOptions, type CodexNativeShell, } from './codex-native-ipc';
6
+ export { CodexElectronAttachmentRegistry, type CodexElectronAttachmentRegistration, } from './codex-attachment-registry';
7
+ export type { CodexHostAttachment, CodexHostAttachmentInput, CodexNativeAttachment, CodexNativeAttachmentInput, CodexNativeClipboardContent, CodexNativeRendererApi, CodexSpeechTranscriptionResult, } from '@codex-app-sdk/core/native';
8
+ export { exposeCodexElectronPreload, type CodexElectronRendererApis, } from './codex-electron-preload';
9
+ export { registerCodexElectronMain, type CodexElectronMainOptions, } from './codex-electron-integration';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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"}
package/dist/index.js ADDED
@@ -0,0 +1,282 @@
1
+ import { a as e, c as t, d as n, i as r, l as i, n as a, o, r as s, s as c, t as l, u } from "./chunks/codex-electron-preload-z_8XhSEC.js";
2
+ import { promises as d } from "node:fs";
3
+ import f from "node:os";
4
+ import p from "node:path";
5
+ import { transcribeWithAppleSpeechAnalyzer as m } from "@codex-app-sdk/backend";
6
+ import { randomUUID as h } from "node:crypto";
7
+ //#region src/codex-window-policy.ts
8
+ var g = /* @__PURE__ */ new Set([
9
+ "http:",
10
+ "https:",
11
+ "mailto:",
12
+ "tel:"
13
+ ]);
14
+ function _(e) {
15
+ try {
16
+ let t = new URL(e);
17
+ return g.has(t.protocol) ? t.href : null;
18
+ } catch {
19
+ return null;
20
+ }
21
+ }
22
+ function v(e, t) {
23
+ if (!e) return !1;
24
+ try {
25
+ let n = new URL(e), r = new URL(t);
26
+ return r.protocol === "file:" ? n.protocol === "file:" && n.pathname === r.pathname : n.origin === r.origin;
27
+ } catch {
28
+ return !1;
29
+ }
30
+ }
31
+ function y(e, t) {
32
+ let n = (e) => {
33
+ let n = _(e);
34
+ n && Promise.resolve(t.openExternal(n)).catch(() => void 0);
35
+ };
36
+ e.setWindowOpenHandler(({ url: e }) => (n(e), { action: "deny" })), e.on("will-navigate", (e) => {
37
+ v(e.url, t.rendererUrl) || (e.preventDefault(), n(e.url));
38
+ });
39
+ }
40
+ function b(e, t) {
41
+ let n = e?.senderFrame;
42
+ return !!n && n.parent === null && v(n.url, t);
43
+ }
44
+ //#endregion
45
+ //#region src/codex-attachment-registry.ts
46
+ var x = class {
47
+ #e = /* @__PURE__ */ new Map();
48
+ register(e) {
49
+ let t = `electron-attachment:${h()}`;
50
+ return this.#e.set(t, {
51
+ type: e.type,
52
+ path: e.path,
53
+ name: e.name,
54
+ mimeType: e.mimeType,
55
+ ...e.previewUrl === void 0 ? {} : { previewUrl: e.previewUrl }
56
+ }), {
57
+ id: t,
58
+ reference: t,
59
+ type: e.type,
60
+ name: e.name,
61
+ mimeType: e.mimeType,
62
+ size: e.size,
63
+ ...e.previewUrl === void 0 ? {} : { previewUrl: e.previewUrl }
64
+ };
65
+ }
66
+ resolve(e) {
67
+ let t = this.#t(e.reference);
68
+ if (t.type !== e.type) throw TypeError("Attachment reference type does not match");
69
+ return {
70
+ type: t.type,
71
+ path: t.path,
72
+ name: t.name,
73
+ mimeType: t.mimeType,
74
+ ...t.type === "image" && t.previewUrl ? { previewUrl: t.previewUrl } : {}
75
+ };
76
+ }
77
+ path(e) {
78
+ return this.#t(e).path;
79
+ }
80
+ clear() {
81
+ this.#e.clear();
82
+ }
83
+ #t(e) {
84
+ let t = this.#e.get(e);
85
+ if (!t) throw TypeError("Attachment reference is invalid or expired");
86
+ return t;
87
+ }
88
+ }, S = 25 * 1024 * 1024, C = 100 * 1024 * 1024, w = 25 * 1024 * 1024, T = 8 * 1024 * 1024, E = 16 * 1024 * 1024;
89
+ function D(e, t = {}, n = new x()) {
90
+ let r = z(t.maxAttachmentBytes, S, "Attachment byte limit"), i = z(t.maxAudioBytes, w, "Audio byte limit"), o = z(t.maxTotalAttachmentBytes, C, "Total attachment byte limit"), s = z(t.maxImagePreviewBytes, T, "Image preview byte limit"), c = u(e.ipcMain, {
91
+ [a.copyToClipboard]: (t, n) => {
92
+ let r = A(n);
93
+ e.clipboard.write(r);
94
+ },
95
+ [a.ingestAttachments]: async (e, t) => {
96
+ let i = O(t, r, o);
97
+ if (i.length === 0) return [];
98
+ let a = await d.mkdtemp(p.join(f.tmpdir(), "codex-app-sdk-attachments-"));
99
+ return Promise.all(i.map(async (e, t) => {
100
+ let r = p.join(a, `${t}-${L(e.name)}`), i = Buffer.from(e.data);
101
+ return await d.writeFile(r, i, { mode: 384 }), k(n, r, {
102
+ mimeType: e.mimeType ?? B(e.name),
103
+ name: L(e.name),
104
+ previewData: i
105
+ });
106
+ }));
107
+ },
108
+ [a.openExternal]: async (t, n) => {
109
+ await e.shell.openExternal(j(n));
110
+ },
111
+ [a.pickAttachments]: async () => {
112
+ let t = await e.dialog.showOpenDialog({
113
+ title: "Add Files & Photos",
114
+ properties: ["openFile", "multiSelections"],
115
+ filters: [{
116
+ name: "Files and photos",
117
+ extensions: ["*"]
118
+ }]
119
+ });
120
+ if (t.canceled) return [];
121
+ let i = [], a = 0, s = 0;
122
+ for (let e of t.filePaths) {
123
+ let t = await d.stat(e);
124
+ if (!t.isFile()) throw TypeError(`Attachment is not a file: ${e}`);
125
+ if (t.size > r) throw RangeError(`Attachment exceeds the ${r} byte limit: ${e}`);
126
+ if (a += t.size, a > o) throw RangeError(`Attachments exceed the ${o} total byte limit`);
127
+ let c = B(e), l = c.startsWith("image/") && c !== "image/svg+xml" && t.size <= T && s + t.size <= E ? await d.readFile(e) : void 0;
128
+ l && (s += l.byteLength), i.push(k(n, e, {
129
+ mimeType: c,
130
+ name: p.basename(e),
131
+ previewData: l,
132
+ size: t.size
133
+ }));
134
+ }
135
+ return i;
136
+ },
137
+ [a.readImagePreview]: async (e, t) => {
138
+ let r = F(t, "Image preview attachment reference"), i = R(r) ?? n.path(r), a = B(i);
139
+ if (!a.startsWith("image/") || a === "image/svg+xml") return null;
140
+ let o;
141
+ try {
142
+ o = await d.lstat(i);
143
+ } catch (e) {
144
+ if (I(e)) return null;
145
+ throw e;
146
+ }
147
+ if (!o.isFile() || o.size > s) return null;
148
+ let c = await d.readFile(i);
149
+ return c.byteLength > s ? null : `data:${a};base64,${c.toString("base64")}`;
150
+ },
151
+ [a.transcribeAudio]: async (e, n, r) => {
152
+ let a = N(n, "Audio data");
153
+ if (a.byteLength > i) throw RangeError(`Audio data exceeds the ${i} byte limit`);
154
+ let o = M(r);
155
+ return (t.transcribeAudio ?? ((e, n) => m(e, n, { ...t.appleSpeechAssetsPath ? { assetsPath: t.appleSpeechAssetsPath } : {} })))(Buffer.from(a), o);
156
+ }
157
+ }, t);
158
+ return () => {
159
+ c(), n.clear();
160
+ };
161
+ }
162
+ function O(e, t, n) {
163
+ if (!Array.isArray(e)) throw TypeError("Attachments must be an array");
164
+ if (e.length > 20) throw RangeError("At most 20 attachments can be added at once");
165
+ let r = 0;
166
+ return e.map((e) => {
167
+ let i = P(e, "Attachment"), a = F(i.name, "Attachment name"), o = N(i.data, "Attachment data");
168
+ if (o.byteLength > t) throw RangeError(`Attachment '${a}' exceeds the ${t} byte limit`);
169
+ if (r += o.byteLength, r > n) throw RangeError(`Attachments exceed the ${n} total byte limit`);
170
+ return {
171
+ name: a,
172
+ data: o,
173
+ ...i.mimeType === void 0 ? {} : { mimeType: F(i.mimeType, "Attachment MIME type") }
174
+ };
175
+ });
176
+ }
177
+ function k(e, t, n) {
178
+ let r = n.size ?? n.previewData?.byteLength ?? 0;
179
+ return e.register({
180
+ type: n.mimeType.startsWith("image/") ? "image" : "file",
181
+ path: t,
182
+ name: n.name,
183
+ mimeType: n.mimeType,
184
+ size: r,
185
+ ...n.previewData && n.mimeType !== "image/svg+xml" && n.previewData.byteLength <= T ? { previewUrl: `data:${n.mimeType};base64,${Buffer.from(n.previewData).toString("base64")}` } : {}
186
+ });
187
+ }
188
+ function A(e) {
189
+ let t = P(e, "Clipboard content"), n = typeof t.text == "string" ? t.text : V("Clipboard text must be a string"), r = t.html === void 0 ? void 0 : typeof t.html == "string" ? t.html : V("Clipboard HTML must be a string");
190
+ if (n.length > 5e6 || (r?.length ?? 0) > 1e7) throw RangeError("Clipboard content is too large");
191
+ return {
192
+ text: n,
193
+ ...r ? { html: r } : {}
194
+ };
195
+ }
196
+ function j(e) {
197
+ let t = F(e, "External URL"), n = new URL(t);
198
+ if (![
199
+ "http:",
200
+ "https:",
201
+ "mailto:",
202
+ "tel:"
203
+ ].includes(n.protocol.toLowerCase())) throw TypeError(`Unsupported external URL protocol: ${n.protocol}`);
204
+ return n.href;
205
+ }
206
+ function M(e) {
207
+ if (e === void 0) return;
208
+ let t = P(e, "Speech transcription options");
209
+ if (t.live !== void 0 && typeof t.live != "boolean") throw TypeError("Speech transcription live mode must be a boolean");
210
+ return {
211
+ ...t.locale === void 0 ? {} : { locale: F(t.locale, "Speech transcription locale") },
212
+ ...t.live === void 0 ? {} : { live: t.live }
213
+ };
214
+ }
215
+ function N(e, t) {
216
+ if (!(e instanceof ArrayBuffer)) throw TypeError(`${t} must be an ArrayBuffer`);
217
+ return e;
218
+ }
219
+ function P(e, t) {
220
+ if (!e || typeof e != "object" || Array.isArray(e)) throw TypeError(`${t} must be an object`);
221
+ return e;
222
+ }
223
+ function F(e, t) {
224
+ if (typeof e != "string" || !e.trim()) throw TypeError(`${t} must be a non-empty string`);
225
+ return e.trim();
226
+ }
227
+ function I(e) {
228
+ return !!(e && typeof e == "object" && "code" in e && e.code === "ENOENT");
229
+ }
230
+ function L(e) {
231
+ return p.basename(e).replace(/[\u0000-\u001f\u007f]/g, "").trim() || "attachment";
232
+ }
233
+ function R(e) {
234
+ if (!p.isAbsolute(e)) return null;
235
+ let t = p.resolve(e), n = p.dirname(t);
236
+ return p.dirname(n) === p.resolve(f.tmpdir()) && /^codex-app-sdk-attachments-[a-z\d_-]+$/i.test(p.basename(n)) ? t : null;
237
+ }
238
+ function z(e, t, n) {
239
+ if (e === void 0) return t;
240
+ if (!Number.isSafeInteger(e) || e <= 0) throw TypeError(`${n} must be a positive integer`);
241
+ return e;
242
+ }
243
+ function B(e) {
244
+ return {
245
+ avif: "image/avif",
246
+ bmp: "image/bmp",
247
+ gif: "image/gif",
248
+ heic: "image/heic",
249
+ heif: "image/heif",
250
+ jpeg: "image/jpeg",
251
+ jpg: "image/jpeg",
252
+ png: "image/png",
253
+ svg: "image/svg+xml",
254
+ webp: "image/webp"
255
+ }[p.extname(e).slice(1).toLowerCase()] ?? "application/octet-stream";
256
+ }
257
+ function V(e) {
258
+ throw TypeError(e);
259
+ }
260
+ //#endregion
261
+ //#region src/codex-electron-integration.ts
262
+ function H(e) {
263
+ let t = new x(), n = e.isTrustedSender ? { isTrustedSender: e.isTrustedSender } : {}, r = o(e.ipcMain, e.sender, e.surface, {
264
+ ...n,
265
+ resolveAttachment: (e) => t.resolve(e)
266
+ });
267
+ try {
268
+ let i = D(e, {
269
+ ...e.native,
270
+ ...n
271
+ }, t);
272
+ return () => {
273
+ i(), r();
274
+ };
275
+ } catch (e) {
276
+ throw r(), e;
277
+ }
278
+ }
279
+ //#endregion
280
+ export { x as CodexElectronAttachmentRegistry, c as TypedIpcMain, t as TypedIpcRenderer, _ as codexExternalUrl, i as connectIpcEventsToBus, s as createCodexNativeRendererApi, e as createCodexSurfaceRendererApi, l as exposeCodexElectronPreload, r as exposeCodexNativeRendererApi, y as installCodexWindowPolicy, b as isCodexRendererSender, v as isCodexRendererUrl, H as registerCodexElectronMain, D as registerCodexNativeIpc, o as registerCodexSurfaceIpc, u as registerIpcMainHandlers, n as sendIpcEvent };
281
+
282
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["#attachments","#registered"],"sources":["../src/codex-window-policy.ts","../src/codex-attachment-registry.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 { 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 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';\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 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 unregister = registerIpcMainHandlers<NativeRequests>(dependencies.ipcMain, {\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 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":";;;;;;;AAkBA,IAAM,oBAAoB,IAAI,IAAI;CAAC;CAAS;CAAU;CAAW;AAAM,CAAC;AAGxE,SAAgB,EAAiB,GAA8B;CAC7D,IAAI;EACF,IAAM,IAAM,IAAI,IAAI,CAAK;EACzB,OAAO,EAAkB,IAAI,EAAI,QAAQ,IAAI,EAAI,OAAO;CAC1D,QAAQ;EACN,OAAO;CACT;AACF;AAMA,SAAgB,EAAmB,GAAgC,GAA8B;CAC/F,IAAI,CAAC,GAAK,OAAO;CACjB,IAAI;EACF,IAAM,IAAS,IAAI,IAAI,CAAG,GACpB,IAAW,IAAI,IAAI,CAAW;EAIpC,OAHI,EAAS,aAAa,UACjB,EAAO,aAAa,WAAW,EAAO,aAAa,EAAS,WAE9D,EAAO,WAAW,EAAS;CACpC,QAAQ;EACN,OAAO;CACT;AACF;AAQA,SAAgB,EACd,GACA,GACM;CACN,IAAM,KAAgB,MAAkB;EACtC,IAAM,IAAM,EAAiB,CAAK;EAClC,AAAI,KAAK,QAAa,QAAQ,EAAQ,aAAa,CAAG,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;CAChF;CAKA,AAJA,EAAY,sBAAsB,EAAE,cAClC,EAAa,CAAG,GACT,EAAE,QAAQ,OAAO,EACzB,GACD,EAAY,GAAG,kBAAkB,MAAU;EACrC,EAAmB,EAAM,KAAK,EAAQ,WAAW,MACrD,EAAM,eAAe,GACrB,EAAa,EAAM,GAAG;CACxB,CAAC;AACH;AAMA,SAAgB,EAAsB,GAAgB,GAA8B;CAClF,IAAM,IAAS,GAA4E;CAC3F,OAAO,EAAQ,KAAU,EAAO,WAAW,QAAQ,EAAmB,EAAO,KAAK,CAAW;AAC/F;;;AC7DA,IAAa,IAAb,MAA6C;CAC3C,qBAAwB,IAAI,IAAkC;CAE9D,SAAS,GAAiE;EACxE,IAAM,IAAY,uBAAuB,EAAW;EAQpD,OAPA,KAAKA,GAAa,IAAI,GAAW;GAC/B,MAAM,EAAM;GACZ,MAAM,EAAM;GACZ,MAAM,EAAM;GACZ,UAAU,EAAM;GAChB,GAAI,EAAM,eAAe,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY,EAAM,WAAW;EAC3E,CAAC,GACM;GACL,IAAI;GACJ;GACA,MAAM,EAAM;GACZ,MAAM,EAAM;GACZ,UAAU,EAAM;GAChB,MAAM,EAAM;GACZ,GAAI,EAAM,eAAe,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY,EAAM,WAAW;EAC3E;CACF;CAEA,QAAQ,GAA6D;EACnE,IAAM,IAAa,KAAKC,GAAY,EAAW,SAAS;EACxD,IAAI,EAAW,SAAS,EAAW,MACjC,MAAU,UAAU,0CAA0C;EAEhE,OAAO;GACL,MAAM,EAAW;GACjB,MAAM,EAAW;GACjB,MAAM,EAAW;GACjB,UAAU,EAAW;GACrB,GAAI,EAAW,SAAS,WAAW,EAAW,aAC1C,EAAE,YAAY,EAAW,WAAW,IACpC,CAAC;EACP;CACF;CAEA,KAAK,GAA2B;EAC9B,OAAO,KAAKA,GAAY,CAAS,CAAC,CAAC;CACrC;CAEA,QAAc;EACZ,KAAKD,GAAa,MAAM;CAC1B;CAEA,GAAY,GAAyC;EACnD,IAAM,IAAa,KAAKA,GAAa,IAAI,CAAS;EAClD,IAAI,CAAC,GAAY,MAAU,UAAU,4CAA4C;EACjF,OAAO;CACT;AACF,GCZM,IAA4B,KAAK,OAAO,MACxC,IAAiC,MAAM,OAAO,MAC9C,IAAuB,KAAK,OAAO,MACnC,IAAkB,IAAI,OAAO,MAC7B,IAAuB,KAAK,OAAO;AAEzC,SAAgB,EACd,GACA,IAAkC,CAAC,GACnC,IAAc,IAAI,EAAgC,GACtC;CACZ,IAAM,IAAqB,EACzB,EAAQ,oBACR,GACA,uBACF,GACM,IAAgB,EACpB,EAAQ,eACR,GACA,kBACF,GACM,IAA0B,EAC9B,EAAQ,yBACR,GACA,6BACF,GACM,IAAuB,EAC3B,EAAQ,sBACR,GACA,0BACF,GAEM,IAAa,EAAwC,EAAa,SAAS;GAC9E,EAAS,mBAAmB,GAAQ,MAAU;GAC7C,IAAM,IAAU,EAAiB,CAAK;GACtC,EAAa,UAAU,MAAM,CAAO;EACtC;GACC,EAAS,oBAAoB,OAAO,GAAQ,MAAU;GACrD,IAAM,IAAS,EAAiB,GAAO,GAAoB,CAAuB;GAClF,IAAI,EAAO,WAAW,GAAG,OAAO,CAAC;GACjC,IAAM,IAAqB,MAAM,EAAG,QAAQ,EAAK,KAAK,EAAG,OAAO,GAAG,4BAA4B,CAAC;GAChG,OAAO,QAAQ,IAAI,EAAO,IAAI,OAAO,GAAO,MAAU;IACpD,IAAM,IAAW,EAAK,KAAK,GAAoB,GAAG,EAAM,GAAG,EAAa,EAAM,IAAI,GAAG,GAC/E,IAAO,OAAO,KAAK,EAAM,IAAI;IAEnC,OADA,MAAM,EAAG,UAAU,GAAU,GAAM,EAAE,MAAM,IAAM,CAAC,GAC3C,EAAmB,GAAa,GAAU;KAC/C,UAAU,EAAM,YAAY,EAAgB,EAAM,IAAI;KACtD,MAAM,EAAa,EAAM,IAAI;KAC7B,aAAa;IACf,CAAC;GACH,CAAC,CAAC;EACJ;GACC,EAAS,eAAe,OAAO,GAAQ,MAAU;GAChD,MAAM,EAAa,MAAM,aAAa,EAAa,CAAK,CAAC;EAC3D;GACC,EAAS,kBAAkB,YAAY;GACtC,IAAM,IAAS,MAAM,EAAa,OAAO,eAAe;IACtD,OAAO;IACP,YAAY,CAAC,YAAY,iBAAiB;IAC1C,SAAS,CACP;KAAE,MAAM;KAAoB,YAAY,CAAC,GAAG;IAAE,CAChD;GACF,CAAC;GACD,IAAI,EAAO,UAAU,OAAO,CAAC;GAC7B,IAAM,IAA2C,CAAC,GAC9C,IAAa,GACb,IAAe;GACnB,KAAK,IAAM,KAAY,EAAO,WAAW;IACvC,IAAM,IAAW,MAAM,EAAG,KAAK,CAAQ;IACvC,IAAI,CAAC,EAAS,OAAO,GAAG,MAAU,UAAU,6BAA6B,GAAU;IACnF,IAAI,EAAS,OAAO,GAClB,MAAU,WAAW,0BAA0B,EAAmB,eAAe,GAAU;IAG7F,IADA,KAAc,EAAS,MACnB,IAAa,GACf,MAAU,WAAW,0BAA0B,EAAwB,kBAAkB;IAE3F,IAAM,IAAW,EAAgB,CAAQ,GACnC,IAAc,EAAS,WAAW,QAAQ,KAC3C,MAAa,mBACb,EAAS,QAAQ,KACjB,IAAe,EAAS,QAAQ,IACjC,MAAM,EAAG,SAAS,CAAQ,IAC1B,KAAA;IAEJ,AADI,MAAa,KAAgB,EAAY,aAC7C,EAAkB,KAAK,EAAmB,GAAa,GAAU;KAC/D;KACA,MAAM,EAAK,SAAS,CAAQ;KAC5B;KACA,MAAM,EAAS;IACjB,CAAC,CAAC;GACJ;GACA,OAAO;EACT;GACC,EAAS,mBAAmB,OAAO,GAAQ,MAAU;GACpD,IAAM,IAAY,EAAe,GAAO,oCAAoC,GACtE,IAAW,EAA+B,CAAS,KAAK,EAAY,KAAK,CAAS,GAClF,IAAW,EAAgB,CAAQ;GACzC,IAAI,CAAC,EAAS,WAAW,QAAQ,KAAK,MAAa,iBAAiB,OAAO;GAC3E,IAAI;GACJ,IAAI;IACF,IAAW,MAAM,EAAG,MAAM,CAAQ;GACpC,SAAS,GAAO;IACd,IAAI,EAAmB,CAAK,GAAG,OAAO;IACtC,MAAM;GACR;GACA,IAAI,CAAC,EAAS,OAAO,KAAK,EAAS,OAAO,GAAsB,OAAO;GACvE,IAAM,IAAO,MAAM,EAAG,SAAS,CAAQ;GAEvC,OADI,EAAK,aAAa,IAA6B,OAC5C,QAAQ,EAAS,UAAU,EAAK,SAAS,QAAQ;EAC1D;GACC,EAAS,kBAAkB,OAAO,GAAQ,GAAO,MAAe;GAC/D,IAAM,IAAY,EAAY,GAAO,YAAY;GACjD,IAAI,EAAU,aAAa,GACzB,MAAU,WAAW,0BAA0B,EAAc,YAAY;GAE3E,IAAM,IAAuB,EAAmB,CAAU;GAS1D,QARmB,EAAQ,qBACpB,GAAc,MACjB,EAAkC,GAAM,GAAc,EACpD,GAAI,EAAQ,wBACR,EAAE,YAAY,EAAQ,sBAAsB,IAC5C,CAAC,EACP,CAAC,GAAA,CAEa,OAAO,KAAK,CAAS,GAAG,CAAoB;EAChE;CACF,GAAG,CAAO;CAEV,aAAa;EAEX,AADA,EAAW,GACX,EAAY,MAAM;CACpB;AACF;AAEA,SAAS,EACP,GACA,GACA,GAC8B;CAC9B,IAAI,CAAC,MAAM,QAAQ,CAAK,GAAG,MAAU,UAAU,8BAA8B;CAC7E,IAAI,EAAM,SAAS,IAAI,MAAU,WAAW,6CAA6C;CACzF,IAAI,IAAa;CACjB,OAAO,EAAM,KAAK,MAAU;EAC1B,IAAM,IAAS,EAAa,GAAO,YAAY,GACzC,IAAO,EAAe,EAAO,MAAM,iBAAiB,GACpD,IAAO,EAAY,EAAO,MAAM,iBAAiB;EACvD,IAAI,EAAK,aAAa,GACpB,MAAU,WAAW,eAAe,EAAK,gBAAgB,EAAS,YAAY;EAGhF,IADA,KAAc,EAAK,YACf,IAAa,GACf,MAAU,WAAW,0BAA0B,EAAc,kBAAkB;EAEjF,OAAO;GACL;GACA;GACA,GAAI,EAAO,aAAa,KAAA,IACpB,CAAC,IACD,EAAE,UAAU,EAAe,EAAO,UAAU,sBAAsB,EAAE;EAC1E;CACF,CAAC;AACH;AAEA,SAAS,EACP,GACA,GACA,GAMqB;CACrB,IAAM,IAAO,EAAS,QAAQ,EAAS,aAAa,cAAc;CAClE,OAAO,EAAY,SAAS;EAC1B,MAAM,EAAS,SAAS,WAAW,QAAQ,IAAI,UAAU;EACzD,MAAM;EACN,MAAM,EAAS;EACf,UAAU,EAAS;EACnB;EACA,GAAI,EAAS,eACR,EAAS,aAAa,mBACtB,EAAS,YAAY,cAAc,IACpC,EAAE,YAAY,QAAQ,EAAS,SAAS,UAAU,OAAO,KAAK,EAAS,WAAW,CAAC,CAAC,SAAS,QAAQ,IAAI,IACzG,CAAC;CACP,CAAC;AACH;AAEA,SAAS,EAAiB,GAA6C;CACrE,IAAM,IAAS,EAAa,GAAO,mBAAmB,GAChD,IAAO,OAAO,EAAO,QAAS,WAAW,EAAO,OAAO,EAAQ,iCAAiC,GAChG,IAAO,EAAO,SAAS,KAAA,IACzB,KAAA,IACA,OAAO,EAAO,QAAS,WACrB,EAAO,OACP,EAAQ,iCAAiC;CAC/C,IAAI,EAAK,SAAS,QAAc,GAAM,UAAU,KAAK,KACnD,MAAU,WAAW,gCAAgC;CAEvD,OAAO;EAAE;EAAM,GAAI,IAAO,EAAE,QAAK,IAAI,CAAC;CAAG;AAC3C;AAEA,SAAS,EAAa,GAAwB;CAC5C,IAAM,IAAO,EAAe,GAAO,cAAc,GAC3C,IAAM,IAAI,IAAI,CAAI;CACxB,IAAI,CAAC;EAAC;EAAS;EAAU;EAAW;CAAM,CAAC,CAAC,SAAS,EAAI,SAAS,YAAY,CAAC,GAC7E,MAAU,UAAU,sCAAsC,EAAI,UAAU;CAE1E,OAAO,EAAI;AACb;AAEA,SAAS,EAAmB,GAA6D;CACvF,IAAI,MAAU,KAAA,GAAW;CACzB,IAAM,IAAS,EAAa,GAAO,8BAA8B;CACjE,IAAI,EAAO,SAAS,KAAA,KAAa,OAAO,EAAO,QAAS,WACtD,MAAU,UAAU,kDAAkD;CAExE,OAAO;EACL,GAAI,EAAO,WAAW,KAAA,IAClB,CAAC,IACD,EAAE,QAAQ,EAAe,EAAO,QAAQ,6BAA6B,EAAE;EAC3E,GAAI,EAAO,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,EAAO,KAAK;CAC3D;AACF;AAEA,SAAS,EAAY,GAAgB,GAA4B;CAC/D,IAAI,EAAE,aAAiB,cAAc,MAAU,UAAU,GAAG,EAAM,wBAAwB;CAC1F,OAAO;AACT;AAEA,SAAS,EAAa,GAAgB,GAAwC;CAC5E,IAAI,CAAC,KAAS,OAAO,KAAU,YAAY,MAAM,QAAQ,CAAK,GAC5D,MAAU,UAAU,GAAG,EAAM,mBAAmB;CAElD,OAAO;AACT;AAEA,SAAS,EAAe,GAAgB,GAAuB;CAC7D,IAAI,OAAO,KAAU,YAAY,CAAC,EAAM,KAAK,GAAG,MAAU,UAAU,GAAG,EAAM,4BAA4B;CACzG,OAAO,EAAM,KAAK;AACpB;AAEA,SAAS,EAAmB,GAAyB;CACnD,OAAO,GAAQ,KAAS,OAAO,KAAU,YAAY,UAAU,KAAS,EAAM,SAAS;AACzF;AAEA,SAAS,EAAa,GAAuB;CAE3C,OADa,EAAK,SAAS,CAAK,CAAC,CAAC,QAAQ,0BAA0B,EAAE,CAAC,CAAC,KACjE,KAAQ;AACjB;AAEA,SAAS,EAA+B,GAA8B;CACpE,IAAI,CAAC,EAAK,WAAW,CAAK,GAAG,OAAO;CACpC,IAAM,IAAW,EAAK,QAAQ,CAAK,GAC7B,IAAY,EAAK,QAAQ,CAAQ;CAEvC,OADI,EAAK,QAAQ,CAAS,MAAM,EAAK,QAAQ,EAAG,OAAO,CAAC,KACjD,0CAA0C,KAAK,EAAK,SAAS,CAAS,CAAC,IAC1E,IACA;AACN;AAEA,SAAS,EAAkB,GAA2B,GAAkB,GAAuB;CAC7F,IAAI,MAAU,KAAA,GAAW,OAAO;CAChC,IAAI,CAAC,OAAO,cAAc,CAAK,KAAK,KAAS,GAAG,MAAU,UAAU,GAAG,EAAM,4BAA4B;CACzG,OAAO;AACT;AAEA,SAAS,EAAgB,GAA0B;CAEjD,OAAQ;EACN,MAAM;EACN,KAAK;EACL,KAAK;EACL,MAAM;EACN,MAAM;EACN,MAAM;EACN,KAAK;EACL,KAAK;EACL,KAAK;EACL,MAAM;CACR,EAZkB,EAAK,QAAQ,CAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAYrB,MAAc;AAC7C;AAEA,SAAS,EAAQ,GAAwB;CACvC,MAAU,UAAU,CAAO;AAC7B;;;ACxUA,SAAgB,EAA0B,GAA+C;CACvF,IAAM,IAAc,IAAI,EAAgC,GAClD,IAAe,EAAQ,kBAAkB,EAAE,iBAAiB,EAAQ,gBAAgB,IAAI,CAAC,GACzF,IAAoB,EACxB,EAAQ,SACR,EAAQ,QACR,EAAQ,SACR;EAAE,GAAG;EAAc,oBAAoB,MAAe,EAAY,QAAQ,CAAU;CAAE,CACxF;CACA,IAAI;EACF,IAAM,IAAmB,EAAuB,GAAS;GAAE,GAAG,EAAQ;GAAQ,GAAG;EAAa,GAAG,CAAW;EAC5G,aAAa;GAEX,AADA,EAAiB,GACjB,EAAkB;EACpB;CACF,SAAS,GAAO;EAEd,MADA,EAAkB,GACZ;CACR;AACF"}
@@ -0,0 +1,7 @@
1
+ export { exposeCodexElectronPreload, type CodexElectronRendererApis, } from './codex-electron-preload';
2
+ export { createCodexNativeRendererApi, exposeCodexNativeRendererApi, type CodexContextBridge, } from './codex-native-renderer';
3
+ export { createCodexSurfaceRendererApi, } from './codex-surface-ipc';
4
+ export { TypedIpcRenderer, type IpcRendererPort, type IpcRequest, type IpcRequestArguments, type IpcRequestResult, } from './typed-ipc';
5
+ export type { CodexNativeRendererApi, } from '@codex-app-sdk/core/native';
6
+ export type { CodexSurfaceRendererApi, } from '@codex-app-sdk/core/surface';
7
+ //# sourceMappingURL=preload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preload.d.ts","sourceRoot":"","sources":["../src/preload.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,KAAK,yBAAyB,GAC/B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,4BAA4B,EAC5B,4BAA4B,EAC5B,KAAK,kBAAkB,GACxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,6BAA6B,GAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,sBAAsB,GACvB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,uBAAuB,GACxB,MAAM,6BAA6B,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { a as e, c as t, i as n, r, t as i } from "./chunks/codex-electron-preload-z_8XhSEC.js";
2
+ export { t as TypedIpcRenderer, r as createCodexNativeRendererApi, e as createCodexSurfaceRendererApi, i as exposeCodexElectronPreload, n as exposeCodexNativeRendererApi };
@@ -0,0 +1,47 @@
1
+ import type { TypedEventBus } from '@codex-app-sdk/core/events';
2
+ export type IpcRequest<Arguments extends unknown[] = unknown[], Result = unknown> = {
3
+ args: Arguments;
4
+ result: Result;
5
+ };
6
+ export type IpcRequestArguments<Request> = Request extends IpcRequest<infer Arguments, unknown> ? Arguments : never;
7
+ export type IpcRequestResult<Request> = Request extends IpcRequest<unknown[], infer Result> ? Result : never;
8
+ export type IpcRendererPort = {
9
+ invoke(channel: string, ...args: unknown[]): Promise<unknown>;
10
+ on(channel: string, listener: (event: unknown, payload: unknown) => void): void;
11
+ off(channel: string, listener: (event: unknown, payload: unknown) => void): void;
12
+ };
13
+ export type IpcMainPort = {
14
+ handle(channel: string, handler: (event: unknown, ...args: unknown[]) => unknown): void;
15
+ removeHandler(channel: string): void;
16
+ };
17
+ export type IpcEventSender = {
18
+ send(channel: string, payload: unknown): void;
19
+ };
20
+ type RequestName<Requests> = keyof Requests & string;
21
+ type EventName<Events> = keyof Events & string;
22
+ export declare class TypedIpcRenderer<Requests extends object, Events extends object> {
23
+ private readonly port;
24
+ constructor(port: IpcRendererPort);
25
+ invoke<Name extends RequestName<Requests>>(channel: Name, ...args: IpcRequestArguments<Requests[Name]>): Promise<IpcRequestResult<Requests[Name]>>;
26
+ on<Name extends EventName<Events>>(channel: Name, listener: (payload: Events[Name]) => void): () => void;
27
+ }
28
+ export type IpcMainHandlers<Requests extends object> = {
29
+ [Name in keyof Requests]: (event: unknown, ...args: IpcRequestArguments<Requests[Name]>) => IpcRequestResult<Requests[Name]> | Promise<IpcRequestResult<Requests[Name]>>;
30
+ };
31
+ export declare class TypedIpcMain<Requests extends object> {
32
+ private readonly port;
33
+ private readonly registeredChannels;
34
+ constructor(port: IpcMainPort);
35
+ handle<Name extends RequestName<Requests>>(channel: Name, handler: IpcMainHandlers<Pick<Requests, Name>>[Name]): void;
36
+ removeHandler<Name extends RequestName<Requests>>(channel: Name): void;
37
+ dispose(): void;
38
+ }
39
+ export type IpcSenderPolicy = {
40
+ /** Rejects an invocation before its handler runs when this returns false. */
41
+ isTrustedSender?: (event: unknown) => boolean;
42
+ };
43
+ export declare function registerIpcMainHandlers<Requests extends object>(port: IpcMainPort, handlers: IpcMainHandlers<Requests>, policy?: IpcSenderPolicy): () => void;
44
+ export declare function sendIpcEvent<Events extends object, Name extends EventName<Events>>(sender: IpcEventSender, channel: Name, payload: Events[Name]): void;
45
+ export declare function connectIpcEventsToBus<Events extends object>(renderer: Pick<TypedIpcRenderer<object, Events>, 'on'>, bus: TypedEventBus<Events>, channels: ReadonlyArray<EventName<Events>>): () => void;
46
+ export {};
47
+ //# sourceMappingURL=typed-ipc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-ipc.d.ts","sourceRoot":"","sources":["../src/typed-ipc.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,49 @@
1
1
  {
2
2
  "name": "@codex-app-sdk/electron",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.14.1",
4
+ "description": "Electron main, preload, IPC, and native capability adapter for Codex applications.",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/codex-app-sdk/codex-app-sdk.git",
10
+ "directory": "packages/electron"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public",
14
+ "registry": "https://registry.npmjs.org"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js"
24
+ },
25
+ "./preload": {
26
+ "types": "./dist/preload.d.ts",
27
+ "import": "./dist/preload.js"
28
+ }
29
+ },
30
+ "scripts": {
31
+ "build": "vite build && tsc -p tsconfig.build.json --declaration --emitDeclarationOnly",
32
+ "check": "npm run lint && npm run test:coverage && npm run build",
33
+ "lint": "tsc -p tsconfig.test.json --noEmit",
34
+ "test": "vitest run",
35
+ "test:coverage": "vitest run --coverage",
36
+ "test:mutation": "cd ../.. && stryker run packages/electron/stryker.config.mjs",
37
+ "typecheck": "tsc -p tsconfig.json --noEmit"
38
+ },
39
+ "dependencies": {
40
+ "@codex-app-sdk/backend": "0.14.1",
41
+ "@codex-app-sdk/core": "0.14.1"
42
+ },
43
+ "peerDependencies": {
44
+ "electron": ">=30"
45
+ },
46
+ "engines": {
47
+ "node": ">=22"
48
+ }
49
+ }