@omnicross/subscriptions 0.1.9 → 0.2.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/index.js CHANGED
@@ -1663,6 +1663,876 @@ function stripAuthHeaders(headers) {
1663
1663
  delete headers["x-goog-api-key"];
1664
1664
  delete headers["X-Goog-Api-Key"];
1665
1665
  }
1666
+
1667
+ // src/image-generation/CodexSubscriptionImageProvider.ts
1668
+ import { createHash } from "crypto";
1669
+ import {
1670
+ ImageGenerationError as ImageGenerationError4,
1671
+ normalizeImageGenerationError,
1672
+ resolveImageCapabilities,
1673
+ serializeImageGenerationError
1674
+ } from "@omnicross/core/image-generation";
1675
+ import { fetchUpstream } from "@omnicross/core/pipeline/upstreamFetch";
1676
+
1677
+ // src/image-generation/capabilityEvidence.ts
1678
+ var CODEX_IMAGE_ADAPTER_VALUES = {
1679
+ available: true,
1680
+ models: ["gpt-image-2"],
1681
+ generate: true,
1682
+ edit: true,
1683
+ maskEdit: false,
1684
+ maxInputImages: 1,
1685
+ maxOutputImages: 1,
1686
+ streaming: false,
1687
+ maxPartialImages: 0,
1688
+ transparentBackground: false,
1689
+ flexibleSizes: true,
1690
+ outputFormats: ["png", "jpeg", "webp"],
1691
+ qualityLevels: ["auto", "low", "medium", "high"],
1692
+ moderationModes: ["auto", "low"],
1693
+ outputCompression: { supported: true, formats: ["jpeg", "webp"], min: 0, max: 100 },
1694
+ responsesTool: true,
1695
+ multiTurnEdit: false,
1696
+ supportsFileId: false,
1697
+ supportsImageUrl: false
1698
+ };
1699
+ function createCodexImageAdapterEvidence(now = Date.now()) {
1700
+ return {
1701
+ kind: "adapter",
1702
+ source: "codex-image-adapter-declaration",
1703
+ verifiedAt: now,
1704
+ values: CODEX_IMAGE_ADAPTER_VALUES
1705
+ };
1706
+ }
1707
+ var UnknownCodexImageCapabilityEvidenceSource = class {
1708
+ async resolve(_request) {
1709
+ return {
1710
+ account: { kind: "account", source: "codex-image-entitlement-unknown" },
1711
+ upstream: { kind: "upstream", source: "codex-image-protocol-unverified" }
1712
+ };
1713
+ }
1714
+ };
1715
+
1716
+ // src/image-generation/privateWireErrors.ts
1717
+ import {
1718
+ ImageGenerationError
1719
+ } from "@omnicross/core/image-generation";
1720
+ function parseRetryAfter(headers, now = Date.now()) {
1721
+ const value = headers.get("retry-after");
1722
+ if (!value) return void 0;
1723
+ if (/^\d+$/.test(value)) return Math.min(604800, Number(value));
1724
+ const at = Date.parse(value);
1725
+ if (!Number.isFinite(at) || at <= now) return void 0;
1726
+ return Math.min(604800, Math.ceil((at - now) / 1e3));
1727
+ }
1728
+ function privateErrorCode(body) {
1729
+ if (!body.trim() || body.length > 1e6 || /^\s*</.test(body)) return void 0;
1730
+ try {
1731
+ const value = JSON.parse(body);
1732
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1733
+ const error = value.error;
1734
+ if (!error || typeof error !== "object" || Array.isArray(error)) return void 0;
1735
+ const code = error.code;
1736
+ return typeof code === "string" && code.length <= 80 ? code : void 0;
1737
+ } catch {
1738
+ return void 0;
1739
+ }
1740
+ }
1741
+ function mapCandidateCodexImageFailure(response, body) {
1742
+ const retryAfterSeconds = parseRetryAfter(response.headers);
1743
+ const code = privateErrorCode(body);
1744
+ const uncertain = { retryAfterSeconds, retrySafety: "unknown" };
1745
+ if (response.status === 401 || response.status === 403) {
1746
+ return new ImageGenerationError("upstream_auth_required", {
1747
+ retryAfterSeconds,
1748
+ retrySafety: "before_acceptance"
1749
+ });
1750
+ }
1751
+ if (code === "subscription_usage_limit_reached" || code === "usage_limit_reached") {
1752
+ return new ImageGenerationError("subscription_usage_limit_reached", uncertain);
1753
+ }
1754
+ if (code === "moderation_blocked") {
1755
+ return new ImageGenerationError("moderation_blocked", uncertain);
1756
+ }
1757
+ if (response.status === 429) return new ImageGenerationError("upstream_rate_limited", uncertain);
1758
+ if (response.status === 408 || response.status === 504) {
1759
+ return new ImageGenerationError("image_generation_timeout", uncertain);
1760
+ }
1761
+ if (response.status >= 500) return new ImageGenerationError("image_generation_failed", uncertain);
1762
+ return new ImageGenerationError("upstream_protocol_changed", uncertain);
1763
+ }
1764
+
1765
+ // src/image-generation/privateWireRequest.ts
1766
+ import {
1767
+ ImageGenerationError as ImageGenerationError2,
1768
+ readImageAssetBytes
1769
+ } from "@omnicross/core/image-generation";
1770
+ import {
1771
+ codexAcceptHeader,
1772
+ DEFAULT_CODEX_CLI_HEADERS,
1773
+ fillMissingHeaders
1774
+ } from "@omnicross/core/provider-proxy/identity/codexCliHeaders";
1775
+ var CANDIDATE_CODEX_IMAGE_URL = "https://chatgpt.com/backend-api/codex/responses";
1776
+ var CANDIDATE_CODEX_IMAGE_EDIT_URL = "https://chatgpt.com/backend-api/codex/images/edits";
1777
+ var CANDIDATE_CODEX_IMAGE_CARRIER_MODEL = "gpt-5.6-luna";
1778
+ var MAX_INPUT_IMAGE_BYTES = 50 * 1024 * 1024;
1779
+ function applyCandidateCodexImageHeaders(headers) {
1780
+ fillMissingHeaders(headers, DEFAULT_CODEX_CLI_HEADERS);
1781
+ fillMissingHeaders(headers, {
1782
+ accept: codexAcceptHeader(true),
1783
+ "content-type": "application/json"
1784
+ });
1785
+ }
1786
+ function candidateCodexImageUrl(action) {
1787
+ return action === "edit" ? CANDIDATE_CODEX_IMAGE_EDIT_URL : CANDIDATE_CODEX_IMAGE_URL;
1788
+ }
1789
+ function applyCandidateCodexImageActionHeaders(headers, action) {
1790
+ headers.accept = action === "edit" ? "application/json" : codexAcceptHeader(true);
1791
+ }
1792
+ async function encodeInputImage(asset, signal) {
1793
+ if (!["image/png", "image/jpeg", "image/webp"].includes(asset.mimeType)) {
1794
+ throw new ImageGenerationError2("unsupported_image_type", { param: "image" });
1795
+ }
1796
+ let bytes;
1797
+ try {
1798
+ bytes = await readImageAssetBytes(asset, MAX_INPUT_IMAGE_BYTES, signal);
1799
+ } catch (cause) {
1800
+ if (signal?.aborted) throw signal.reason;
1801
+ if (cause instanceof RangeError) {
1802
+ throw new ImageGenerationError2("image_too_large", { param: "image", cause });
1803
+ }
1804
+ throw cause;
1805
+ }
1806
+ try {
1807
+ const base64 = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
1808
+ return `data:${asset.mimeType};base64,${base64}`;
1809
+ } finally {
1810
+ bytes.fill(0);
1811
+ }
1812
+ }
1813
+ async function buildCandidateCodexImageRequest(request, signal) {
1814
+ if (request.action === "edit") {
1815
+ if (request.mask || request.images.length !== 1) {
1816
+ throw new ImageGenerationError2("unsupported_capability", { param: request.mask ? "mask" : "images" });
1817
+ }
1818
+ return JSON.stringify({
1819
+ images: [{ image_url: await encodeInputImage(request.images[0], signal) }],
1820
+ prompt: request.prompt,
1821
+ background: request.background,
1822
+ model: request.model,
1823
+ quality: request.quality,
1824
+ size: request.size.kind === "pixels" ? `${request.size.width}x${request.size.height}` : "auto"
1825
+ });
1826
+ }
1827
+ const tool = {
1828
+ type: "image_generation",
1829
+ action: request.action,
1830
+ model: request.model,
1831
+ quality: request.quality,
1832
+ background: request.background,
1833
+ output_format: request.outputFormat
1834
+ };
1835
+ if (request.size.kind === "pixels") tool.size = `${request.size.width}x${request.size.height}`;
1836
+ if (request.outputCompression !== void 0) tool.output_compression = request.outputCompression;
1837
+ if (request.moderation !== "auto") tool.moderation = request.moderation;
1838
+ const body = {
1839
+ instructions: "",
1840
+ model: CANDIDATE_CODEX_IMAGE_CARRIER_MODEL,
1841
+ input: [{
1842
+ type: "message",
1843
+ role: "user",
1844
+ content: [{ type: "input_text", text: request.prompt }]
1845
+ }],
1846
+ tools: [tool],
1847
+ tool_choice: { type: "image_generation" },
1848
+ reasoning: { effort: "medium", summary: "auto" },
1849
+ parallel_tool_calls: true,
1850
+ include: ["reasoning.encrypted_content"],
1851
+ stream: true,
1852
+ store: false
1853
+ };
1854
+ return JSON.stringify(body);
1855
+ }
1856
+
1857
+ // src/image-generation/privateWireResponse.ts
1858
+ import {
1859
+ ImageGenerationError as ImageGenerationError3,
1860
+ InMemoryImageAsset
1861
+ } from "@omnicross/core/image-generation";
1862
+ import sharp from "sharp";
1863
+ function disposeCandidateCodexImageResponse(parsed) {
1864
+ if (!parsed) return;
1865
+ for (const image of parsed.images) {
1866
+ if (image instanceof InMemoryImageAsset) image.dispose();
1867
+ }
1868
+ }
1869
+ var MAX_CANDIDATE_RESPONSE_BYTES = 7e7;
1870
+ var MAX_DECODED_IMAGE_BYTES = 50 * 1024 * 1024;
1871
+ var MAX_DECODED_IMAGE_PIXELS = 8294400;
1872
+ var MAX_DECODED_RAW_BYTES = MAX_DECODED_IMAGE_PIXELS * 4;
1873
+ async function readCandidateCodexImageResponseBody(response) {
1874
+ const declared = response.headers.get("content-length");
1875
+ if (declared && (!/^\d+$/.test(declared) || Number(declared) > MAX_CANDIDATE_RESPONSE_BYTES)) {
1876
+ return protocolChanged();
1877
+ }
1878
+ if (!response.body) return "";
1879
+ const reader = response.body.getReader();
1880
+ const decoder = new TextDecoder("utf-8", { fatal: true });
1881
+ let total = 0;
1882
+ let body = "";
1883
+ try {
1884
+ while (true) {
1885
+ const next = await reader.read();
1886
+ if (next.done) break;
1887
+ total += next.value.byteLength;
1888
+ if (total > MAX_CANDIDATE_RESPONSE_BYTES) {
1889
+ await reader.cancel();
1890
+ return protocolChanged();
1891
+ }
1892
+ body += decoder.decode(next.value, { stream: true });
1893
+ }
1894
+ body += decoder.decode();
1895
+ return body;
1896
+ } catch (cause) {
1897
+ return protocolChanged(cause);
1898
+ } finally {
1899
+ reader.releaseLock();
1900
+ }
1901
+ }
1902
+ function selectVerifiedCandidateResponseMetadata(parsed, verified) {
1903
+ return {
1904
+ ...verified?.usage && parsed.usage ? { usage: parsed.usage } : {},
1905
+ ...verified?.revisedPrompt && parsed.revisedPrompt ? { revisedPrompt: parsed.revisedPrompt } : {}
1906
+ };
1907
+ }
1908
+ function protocolChanged(cause) {
1909
+ throw new ImageGenerationError3("upstream_protocol_changed", { cause });
1910
+ }
1911
+ function decodeCandidateBase64ForTests(value) {
1912
+ if (typeof value !== "string" || value.length === 0 || value.length % 4 !== 0) {
1913
+ return protocolChanged();
1914
+ }
1915
+ const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
1916
+ const decodedLength = value.length / 4 * 3 - padding;
1917
+ if (decodedLength <= 0 || decodedLength > MAX_DECODED_IMAGE_BYTES) return protocolChanged();
1918
+ const alphabetEnd = value.length - padding;
1919
+ for (let index = 0; index < alphabetEnd; index += 1) {
1920
+ const code = value.charCodeAt(index);
1921
+ const allowed = code >= 65 && code <= 90 || code >= 97 && code <= 122 || code >= 48 && code <= 57 || code === 43 || code === 47;
1922
+ if (!allowed) return protocolChanged();
1923
+ }
1924
+ for (let index = alphabetEnd; index < value.length; index += 1) {
1925
+ if (value.charCodeAt(index) !== 61) return protocolChanged();
1926
+ }
1927
+ if (padding === 1 && value.charCodeAt(value.length - 2) === 61) return protocolChanged();
1928
+ const decoded = Buffer.from(value, "base64");
1929
+ if (decoded.byteLength !== decodedLength || decoded.toString("base64") !== value) return protocolChanged();
1930
+ return new Uint8Array(decoded);
1931
+ }
1932
+ function readU32Be(bytes, offset) {
1933
+ return (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
1934
+ }
1935
+ function readU32Le(bytes, offset) {
1936
+ return (bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24) >>> 0;
1937
+ }
1938
+ function assertCompleteContainer(bytes, format) {
1939
+ if (format === "jpeg") {
1940
+ if (bytes.byteLength < 4 || bytes.at(-2) !== 255 || bytes.at(-1) !== 217) protocolChanged();
1941
+ return;
1942
+ }
1943
+ if (format === "webp") {
1944
+ if (bytes.byteLength < 20 || Buffer.from(bytes.subarray(0, 4)).toString("ascii") !== "RIFF" || Buffer.from(bytes.subarray(8, 12)).toString("ascii") !== "WEBP" || readU32Le(bytes, 4) + 8 !== bytes.byteLength) protocolChanged();
1945
+ let offset2 = 12;
1946
+ while (offset2 < bytes.byteLength) {
1947
+ if (offset2 + 8 > bytes.byteLength) protocolChanged();
1948
+ const length = readU32Le(bytes, offset2 + 4);
1949
+ const next = offset2 + 8 + length + length % 2;
1950
+ if (next > bytes.byteLength) protocolChanged();
1951
+ offset2 = next;
1952
+ }
1953
+ if (offset2 !== bytes.byteLength) protocolChanged();
1954
+ return;
1955
+ }
1956
+ const signature = [137, 80, 78, 71, 13, 10, 26, 10];
1957
+ if (bytes.byteLength < 20 || !signature.every((value, index) => bytes[index] === value)) {
1958
+ protocolChanged();
1959
+ }
1960
+ let offset = 8;
1961
+ let sawEnd = false;
1962
+ while (offset < bytes.byteLength) {
1963
+ if (offset + 12 > bytes.byteLength) protocolChanged();
1964
+ const length = readU32Be(bytes, offset);
1965
+ const next = offset + 12 + length;
1966
+ if (next > bytes.byteLength) protocolChanged();
1967
+ const type = Buffer.from(bytes.subarray(offset + 4, offset + 8)).toString("ascii");
1968
+ if (type === "IEND") {
1969
+ if (length !== 0 || next !== bytes.byteLength) protocolChanged();
1970
+ sawEnd = true;
1971
+ }
1972
+ offset = next;
1973
+ }
1974
+ if (!sawEnd || offset !== bytes.byteLength) protocolChanged();
1975
+ }
1976
+ async function createAsset(value, format) {
1977
+ const bytes = decodeCandidateBase64ForTests(value);
1978
+ assertCompleteContainer(bytes, format);
1979
+ const input = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
1980
+ try {
1981
+ const decoder = sharp(input, {
1982
+ failOn: "warning",
1983
+ limitInputPixels: MAX_DECODED_IMAGE_PIXELS,
1984
+ sequentialRead: true
1985
+ });
1986
+ const metadata = await decoder.metadata();
1987
+ if (metadata.format !== format || !Number.isSafeInteger(metadata.width) || !Number.isSafeInteger(metadata.height) || metadata.width <= 0 || metadata.height <= 0 || metadata.width * metadata.height > MAX_DECODED_IMAGE_PIXELS) return protocolChanged();
1988
+ const decoded = await decoder.raw().toBuffer({ resolveWithObject: true });
1989
+ if (decoded.info.width !== metadata.width || decoded.info.height !== metadata.height || !Number.isSafeInteger(decoded.info.channels) || decoded.info.channels <= 0 || decoded.info.channels > 4 || decoded.data.byteLength !== decoded.info.width * decoded.info.height * decoded.info.channels || decoded.data.byteLength > MAX_DECODED_RAW_BYTES) return protocolChanged();
1990
+ return new InMemoryImageAsset(bytes, {
1991
+ mimeType: `image/${format}`,
1992
+ width: decoded.info.width,
1993
+ height: decoded.info.height,
1994
+ ...metadata.hasAlpha !== void 0 ? { hasAlpha: metadata.hasAlpha } : {}
1995
+ });
1996
+ } catch (cause) {
1997
+ return protocolChanged(cause);
1998
+ }
1999
+ }
2000
+ function parseUsage(value) {
2001
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
2002
+ const record = value;
2003
+ const read = (key) => {
2004
+ const item = record[key];
2005
+ return Number.isSafeInteger(item) && item >= 0 ? item : void 0;
2006
+ };
2007
+ const usage = {
2008
+ totalTokens: read("total_tokens"),
2009
+ inputTokens: read("input_tokens"),
2010
+ outputTokens: read("output_tokens"),
2011
+ generatedImages: read("generated_images")
2012
+ };
2013
+ return Object.values(usage).some((item) => item !== void 0) ? usage : void 0;
2014
+ }
2015
+ async function parseCandidateCodexImageResponse(body, expectedCount, expectedFormat) {
2016
+ if (!body.trim() || /^s*</.test(body)) return protocolChanged();
2017
+ if (/^\s*(?:data|event):/u.test(body)) {
2018
+ return parseCandidateCodexImageSse(body, expectedCount, expectedFormat);
2019
+ }
2020
+ let parsed;
2021
+ try {
2022
+ parsed = JSON.parse(body);
2023
+ } catch (cause) {
2024
+ return protocolChanged(cause);
2025
+ }
2026
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return protocolChanged();
2027
+ const record = parsed;
2028
+ if (Array.isArray(record.data)) {
2029
+ if (record.data.length !== expectedCount) return protocolChanged();
2030
+ const rows = record.data.map((item) => {
2031
+ if (!item || typeof item !== "object" || Array.isArray(item)) return protocolChanged();
2032
+ return item;
2033
+ });
2034
+ const images2 = await Promise.all(rows.map((item) => createAsset(item.b64_json, expectedFormat)));
2035
+ const revised2 = rows.length === 1 && typeof rows[0]?.revised_prompt === "string" ? rows[0].revised_prompt : void 0;
2036
+ return {
2037
+ images: images2,
2038
+ revisedPrompt: revised2,
2039
+ usage: parseUsage(record.usage)
2040
+ };
2041
+ }
2042
+ if (!Array.isArray(record.output)) return protocolChanged();
2043
+ const calls = record.output.filter(
2044
+ (item) => !!item && typeof item === "object" && !Array.isArray(item) && item.type === "image_generation_call"
2045
+ );
2046
+ if (calls.length !== expectedCount) return protocolChanged();
2047
+ const images = await Promise.all(calls.map(async (call) => {
2048
+ if (call.status !== "completed" || typeof call.result !== "string") return protocolChanged();
2049
+ return createAsset(call.result, expectedFormat);
2050
+ }));
2051
+ const revised = calls.length === 1 && typeof calls[0]?.revised_prompt === "string" ? calls[0].revised_prompt : void 0;
2052
+ return {
2053
+ images,
2054
+ revisedPrompt: revised,
2055
+ usage: parseUsage(record.usage)
2056
+ };
2057
+ }
2058
+ async function parseCandidateCodexImageSse(body, expectedCount, expectedFormat) {
2059
+ const best = /* @__PURE__ */ new Map();
2060
+ const completedEventResults = [];
2061
+ let completedResponse;
2062
+ for (const line of body.split(/\r?\n/u)) {
2063
+ if (!line.startsWith("data:")) continue;
2064
+ const payload = line.slice(5).trim();
2065
+ if (!payload || payload === "[DONE]") continue;
2066
+ let event;
2067
+ try {
2068
+ event = JSON.parse(payload);
2069
+ } catch {
2070
+ continue;
2071
+ }
2072
+ if (!event || typeof event !== "object" || Array.isArray(event)) continue;
2073
+ const record = event;
2074
+ if (typeof record.partial_image_b64 === "string") {
2075
+ const index = record.partial_image_index === void 0 ? 0 : record.partial_image_index;
2076
+ if (!Number.isSafeInteger(index) || index < 0 || index >= expectedCount) continue;
2077
+ const previous = best.get(index);
2078
+ if (!previous || record.partial_image_b64.length >= previous.length) {
2079
+ best.set(index, record.partial_image_b64);
2080
+ }
2081
+ }
2082
+ if (record.type === "response.completed") {
2083
+ if (!record.response || typeof record.response !== "object" || Array.isArray(record.response)) {
2084
+ return protocolChanged();
2085
+ }
2086
+ completedResponse = record.response;
2087
+ }
2088
+ if (record.type === "response.output_item.done" && record.item && typeof record.item === "object" && !Array.isArray(record.item)) {
2089
+ const item = record.item;
2090
+ if (item.type === "image_generation_call" && item.status === "completed" && typeof item.result === "string") {
2091
+ completedEventResults.push(item.result);
2092
+ }
2093
+ }
2094
+ }
2095
+ const output = completedResponse?.output;
2096
+ const calls = Array.isArray(output) ? output.filter(
2097
+ (item) => !!item && typeof item === "object" && !Array.isArray(item) && item.type === "image_generation_call"
2098
+ ) : [];
2099
+ const finalResults = calls.filter(
2100
+ (call) => call.status === "completed" && typeof call.result === "string"
2101
+ );
2102
+ if (best.size !== expectedCount && completedEventResults.length !== expectedCount && finalResults.length !== expectedCount) {
2103
+ return protocolChanged();
2104
+ }
2105
+ const images = await Promise.all(Array.from({ length: expectedCount }, async (_unused, index) => {
2106
+ const encoded = best.get(index) ?? completedEventResults[index] ?? finalResults[index]?.result;
2107
+ if (!encoded) return protocolChanged();
2108
+ return createAsset(encoded, expectedFormat);
2109
+ }));
2110
+ const revised = calls.length === 1 && typeof calls[0]?.revised_prompt === "string" ? calls[0].revised_prompt : void 0;
2111
+ return {
2112
+ images,
2113
+ revisedPrompt: revised,
2114
+ usage: parseUsage(completedResponse?.usage)
2115
+ };
2116
+ }
2117
+
2118
+ // src/image-generation/CodexSubscriptionImageProvider.ts
2119
+ var PROVIDER_ID = "codex-subscription";
2120
+ function traceAccountFingerprint(accountId) {
2121
+ return `sha256:${createHash("sha256").update(accountId, "utf8").digest("hex")}`;
2122
+ }
2123
+ function failed(error) {
2124
+ return { type: "failed", error: serializeImageGenerationError(error) };
2125
+ }
2126
+ var CodexSubscriptionImageProvider = class {
2127
+ id = PROVIDER_ID;
2128
+ #auth;
2129
+ #evidence;
2130
+ #executionScheduler;
2131
+ #generationTimeoutMs;
2132
+ #now;
2133
+ constructor(options) {
2134
+ this.#auth = options.authStrategy;
2135
+ this.#evidence = options.evidenceSource ?? new UnknownCodexImageCapabilityEvidenceSource();
2136
+ this.#executionScheduler = options.executionScheduler;
2137
+ this.#generationTimeoutMs = options.generationTimeoutMs ?? 18e4;
2138
+ this.#now = options.now ?? Date.now;
2139
+ }
2140
+ async acquire(context) {
2141
+ if (context.signal.aborted) throw new ImageGenerationError4("request_cancelled", { cause: context.signal.reason });
2142
+ if (this.#auth.providerId !== "codex") throw new ImageGenerationError4("upstream_auth_required");
2143
+ let selectedAccountId;
2144
+ const headers = {};
2145
+ applyCandidateCodexImageHeaders(headers);
2146
+ try {
2147
+ await this.#auth.applyHeaders(headers, {
2148
+ upstreamUrl: CANDIDATE_CODEX_IMAGE_URL,
2149
+ resolvedModel: CANDIDATE_CODEX_IMAGE_CARRIER_MODEL,
2150
+ sessionKey: context.sessionKey,
2151
+ preferredAccountId: context.preferredAccountId,
2152
+ preferredAccountGroup: context.preferredAccountGroup,
2153
+ boundAccountFallbackPolicy: context.boundAccountFallbackPolicy,
2154
+ reportSelection: (accountId) => {
2155
+ selectedAccountId = accountId;
2156
+ }
2157
+ });
2158
+ } catch (cause) {
2159
+ throw new ImageGenerationError4("upstream_auth_required", { cause });
2160
+ }
2161
+ if (!selectedAccountId || !/^Bearer\s+\S+$/i.test(headers.Authorization ?? "")) {
2162
+ headers.Authorization = "";
2163
+ throw new ImageGenerationError4("upstream_auth_required");
2164
+ }
2165
+ if (context.signal.aborted) {
2166
+ headers.Authorization = "";
2167
+ throw new ImageGenerationError4("request_cancelled", { cause: context.signal.reason });
2168
+ }
2169
+ let evidence;
2170
+ try {
2171
+ evidence = await this.#evidence.resolve({
2172
+ accountId: selectedAccountId,
2173
+ signal: context.signal
2174
+ });
2175
+ } catch (cause) {
2176
+ if (context.signal.aborted) {
2177
+ headers.Authorization = "";
2178
+ selectedAccountId = void 0;
2179
+ throw new ImageGenerationError4("request_cancelled", { cause: context.signal.reason });
2180
+ }
2181
+ evidence = {
2182
+ account: { kind: "account", source: "codex-image-evidence-source-failed" },
2183
+ upstream: { kind: "upstream", source: "codex-image-evidence-source-failed" }
2184
+ };
2185
+ }
2186
+ if (context.signal.aborted) {
2187
+ headers.Authorization = "";
2188
+ selectedAccountId = void 0;
2189
+ throw new ImageGenerationError4("request_cancelled", { cause: context.signal.reason });
2190
+ }
2191
+ const resolvedCapabilities = resolveImageCapabilities({
2192
+ adapter: createCodexImageAdapterEvidence(this.#now()),
2193
+ account: evidence.account,
2194
+ upstream: evidence.upstream
2195
+ }, this.#now());
2196
+ const bootstrapEligible = evidence.account.source === "codex-image-entitlement-unknown" && evidence.upstream.source === "codex-image-protocol-unverified";
2197
+ const capabilities = resolvedCapabilities.available ? resolvedCapabilities : bootstrapEligible ? Object.freeze({
2198
+ ...CODEX_IMAGE_ADAPTER_VALUES,
2199
+ resolvedAt: this.#now()
2200
+ }) : resolvedCapabilities;
2201
+ let released = false;
2202
+ let started = false;
2203
+ const release = async () => {
2204
+ if (released) return;
2205
+ released = true;
2206
+ headers.Authorization = "";
2207
+ selectedAccountId = void 0;
2208
+ };
2209
+ return {
2210
+ providerId: PROVIDER_ID,
2211
+ capabilities,
2212
+ start: (request) => {
2213
+ if (released) throw new ImageGenerationError4("upstream_auth_required");
2214
+ if (started) throw new ImageGenerationError4("invalid_image_request");
2215
+ started = true;
2216
+ if (!capabilities.available) throw new ImageGenerationError4("unsupported_capability");
2217
+ const unsupportedAction = request.action === "generate" ? !capabilities.generate : !capabilities.edit || request.images.length === 0 || request.images.length > capabilities.maxInputImages || request.mask !== void 0 && !capabilities.maskEdit;
2218
+ if (unsupportedAction || request.stream || request.partialImages > 0 || request.n !== 1 || !capabilities.models.includes(request.model) || !capabilities.outputFormats.includes(request.outputFormat) || !capabilities.qualityLevels.includes(request.quality) || !capabilities.moderationModes.includes(request.moderation) || request.outputCompression !== void 0 && (!Number.isInteger(request.outputCompression) || capabilities.outputCompression.supported !== true || !capabilities.outputCompression.formats.includes(request.outputFormat) || request.outputCompression < capabilities.outputCompression.min || request.outputCompression > capabilities.outputCompression.max)) {
2219
+ throw new ImageGenerationError4("unsupported_capability");
2220
+ }
2221
+ return this.#createJob(
2222
+ request,
2223
+ context,
2224
+ headers,
2225
+ selectedAccountId,
2226
+ evidence.verifiedResponseFields
2227
+ );
2228
+ },
2229
+ release
2230
+ };
2231
+ }
2232
+ #createJob(request, context, leaseHeaders, accountId, verifiedFields) {
2233
+ const controller = new AbortController();
2234
+ let cancelled = false;
2235
+ let queueWaitMs;
2236
+ let generationStartedAt;
2237
+ let retryCount = 0;
2238
+ let authRefreshCount = 0;
2239
+ const onCallerAbort = () => controller.abort(context.signal.reason);
2240
+ context.signal.addEventListener("abort", onCallerAbort, { once: true });
2241
+ const cancel = async () => {
2242
+ if (cancelled) return;
2243
+ cancelled = true;
2244
+ controller.abort(new Error("request_cancelled"));
2245
+ };
2246
+ const events = (async function* (self) {
2247
+ let schedulerGrant;
2248
+ let schedulerGrantReleased = false;
2249
+ let schedulerGrantSignal;
2250
+ let onSchedulerAbort;
2251
+ let timeout;
2252
+ let accepted = false;
2253
+ try {
2254
+ if (controller.signal.aborted) throw controller.signal.reason;
2255
+ if (self.#executionScheduler) {
2256
+ const queueStartedAt = self.#now();
2257
+ try {
2258
+ const accountKey = self.#executionScheduler.deriveAccountKey(accountId);
2259
+ schedulerGrant = await self.#executionScheduler.acquire({
2260
+ tenantId: context.tenantId,
2261
+ accountKey,
2262
+ signal: controller.signal
2263
+ });
2264
+ } finally {
2265
+ queueWaitMs = Math.max(0, self.#now() - queueStartedAt);
2266
+ }
2267
+ schedulerGrantSignal = schedulerGrant.signal;
2268
+ if (schedulerGrantSignal) {
2269
+ onSchedulerAbort = () => controller.abort(schedulerGrantSignal?.reason);
2270
+ if (schedulerGrantSignal.aborted) onSchedulerAbort();
2271
+ else schedulerGrantSignal.addEventListener("abort", onSchedulerAbort, { once: true });
2272
+ }
2273
+ }
2274
+ if (controller.signal.aborted) throw controller.signal.reason;
2275
+ generationStartedAt = self.#now();
2276
+ timeout = setTimeout(
2277
+ () => controller.abort(new ImageGenerationError4("image_generation_timeout")),
2278
+ self.#generationTimeoutMs
2279
+ );
2280
+ const body = await buildCandidateCodexImageRequest(request, controller.signal);
2281
+ const upstreamUrl = candidateCodexImageUrl(request.action);
2282
+ let response;
2283
+ for (let attempt = 0; attempt < 2; attempt += 1) {
2284
+ if (controller.signal.aborted) throw controller.signal.reason;
2285
+ if (attempt > 0) retryCount += 1;
2286
+ const requestHeaders = { ...leaseHeaders };
2287
+ applyCandidateCodexImageActionHeaders(requestHeaders, request.action);
2288
+ response = await fetchUpstream(
2289
+ upstreamUrl,
2290
+ {
2291
+ method: "POST",
2292
+ headers: requestHeaders,
2293
+ body,
2294
+ signal: controller.signal
2295
+ },
2296
+ {
2297
+ providerId: "codex",
2298
+ accountId,
2299
+ traceAccountFingerprint: traceAccountFingerprint(accountId),
2300
+ redactBodies: true
2301
+ }
2302
+ );
2303
+ if (response.status !== 401 || attempt === 1) break;
2304
+ const refreshed = await self.#auth.onUnauthorized(context.sessionKey);
2305
+ if (!refreshed) break;
2306
+ authRefreshCount += 1;
2307
+ let refreshedAccount;
2308
+ const refreshedHeaders = {};
2309
+ applyCandidateCodexImageHeaders(refreshedHeaders);
2310
+ await self.#auth.applyHeaders(refreshedHeaders, {
2311
+ upstreamUrl,
2312
+ resolvedModel: CANDIDATE_CODEX_IMAGE_CARRIER_MODEL,
2313
+ sessionKey: context.sessionKey,
2314
+ preferredAccountId: accountId,
2315
+ boundAccountFallbackPolicy: context.boundAccountFallbackPolicy,
2316
+ reportSelection: (id) => {
2317
+ refreshedAccount = id;
2318
+ }
2319
+ });
2320
+ if (refreshedAccount !== accountId || !/^Bearer\s+\S+$/i.test(refreshedHeaders.Authorization ?? "")) {
2321
+ throw new ImageGenerationError4("upstream_auth_required");
2322
+ }
2323
+ Object.assign(leaseHeaders, refreshedHeaders);
2324
+ }
2325
+ if (!response) throw new ImageGenerationError4("image_generation_failed", { retrySafety: "unknown" });
2326
+ const responseBody = await readCandidateCodexImageResponseBody(response);
2327
+ if (!response.ok) {
2328
+ yield failed(mapCandidateCodexImageFailure(response, responseBody));
2329
+ return;
2330
+ }
2331
+ accepted = true;
2332
+ yield { type: "accepted", acceptedAt: self.#now() };
2333
+ const parsed = await parseCandidateCodexImageResponse(responseBody, request.n, request.outputFormat);
2334
+ const verified = selectVerifiedCandidateResponseMetadata(parsed, verifiedFields);
2335
+ const completed = {
2336
+ type: "completed",
2337
+ images: parsed.images.map((artifact, index) => ({
2338
+ artifact,
2339
+ ...index === 0 && verified.revisedPrompt ? { revisedPrompt: verified.revisedPrompt } : {}
2340
+ })),
2341
+ ...verified.usage ? { usage: verified.usage } : {}
2342
+ };
2343
+ yield completed;
2344
+ } catch (cause) {
2345
+ const normalized = controller.signal.aborted ? controller.signal.reason instanceof ImageGenerationError4 ? controller.signal.reason : new ImageGenerationError4("request_cancelled", { cause: controller.signal.reason }) : normalizeImageGenerationError(cause, "image_generation_failed", {
2346
+ retrySafety: accepted ? "after_acceptance" : "unknown"
2347
+ });
2348
+ yield failed(normalized);
2349
+ } finally {
2350
+ if (timeout !== void 0) clearTimeout(timeout);
2351
+ if (schedulerGrantSignal && onSchedulerAbort) {
2352
+ schedulerGrantSignal.removeEventListener("abort", onSchedulerAbort);
2353
+ }
2354
+ if (schedulerGrant && !schedulerGrantReleased) {
2355
+ schedulerGrantReleased = true;
2356
+ await schedulerGrant.release();
2357
+ }
2358
+ context.signal.removeEventListener("abort", onCallerAbort);
2359
+ }
2360
+ })(this);
2361
+ return {
2362
+ events,
2363
+ cancel,
2364
+ observability: {
2365
+ snapshot: () => ({
2366
+ queueWaitMs,
2367
+ generationStartedAt,
2368
+ retryCount,
2369
+ authRefreshCount
2370
+ })
2371
+ }
2372
+ };
2373
+ }
2374
+ };
2375
+ function createCodexSubscriptionImageProvider(options) {
2376
+ return new CodexSubscriptionImageProvider(options);
2377
+ }
2378
+
2379
+ // src/image-generation/CodexImageLiveVerifier.ts
2380
+ import { createHash as createHash2 } from "crypto";
2381
+ import {
2382
+ ImageGenerationError as ImageGenerationError5,
2383
+ normalizeImageGenerationError as normalizeImageGenerationError2
2384
+ } from "@omnicross/core/image-generation";
2385
+ import { fetchUpstream as fetchUpstream2 } from "@omnicross/core/pipeline/upstreamFetch";
2386
+ var VERIFICATION_PROMPT = "A single solid black square.";
2387
+ var TESTED_REQUEST = Object.freeze({
2388
+ action: "generate",
2389
+ model: "gpt-image-2",
2390
+ prompt: VERIFICATION_PROMPT,
2391
+ n: 1,
2392
+ quality: "low",
2393
+ size: { kind: "auto" },
2394
+ background: "opaque",
2395
+ outputFormat: "png",
2396
+ moderation: "auto",
2397
+ stream: false,
2398
+ partialImages: 0
2399
+ });
2400
+ function traceAccountFingerprint2(accountId) {
2401
+ return `sha256:${createHash2("sha256").update(accountId, "utf8").digest("hex")}`;
2402
+ }
2403
+ function observation(accountId, parsed) {
2404
+ const responseFields = {
2405
+ ...parsed.usage ? { usage: true } : {},
2406
+ ...parsed.revisedPrompt ? { revisedPrompt: true } : {}
2407
+ };
2408
+ return Object.freeze({
2409
+ accountId,
2410
+ model: "gpt-image-2",
2411
+ request: Object.freeze({
2412
+ action: "generate",
2413
+ n: 1,
2414
+ quality: "low",
2415
+ size: "auto",
2416
+ background: "opaque",
2417
+ outputFormat: "png",
2418
+ moderation: "auto",
2419
+ stream: false,
2420
+ partialImages: 0
2421
+ }),
2422
+ ...Object.keys(responseFields).length > 0 ? { responseFields: Object.freeze(responseFields) } : {}
2423
+ });
2424
+ }
2425
+ var DefaultCodexImageLiveVerifier = class {
2426
+ #auth;
2427
+ #generationTimeoutMs;
2428
+ constructor(options) {
2429
+ if (!Number.isSafeInteger(options.generationTimeoutMs ?? 18e4) || (options.generationTimeoutMs ?? 18e4) <= 0) {
2430
+ throw new TypeError("Codex image live verification timeout must be positive");
2431
+ }
2432
+ this.#auth = options.authStrategy;
2433
+ this.#generationTimeoutMs = options.generationTimeoutMs ?? 18e4;
2434
+ }
2435
+ async verify(request) {
2436
+ if (request.signal.aborted) {
2437
+ throw new ImageGenerationError5("request_cancelled", { cause: request.signal.reason });
2438
+ }
2439
+ if (this.#auth.providerId !== "codex") {
2440
+ throw new ImageGenerationError5("upstream_auth_required");
2441
+ }
2442
+ const controller = new AbortController();
2443
+ const onCallerAbort = () => controller.abort(request.signal.reason);
2444
+ request.signal.addEventListener("abort", onCallerAbort, { once: true });
2445
+ const timeout = setTimeout(() => {
2446
+ controller.abort(new ImageGenerationError5("image_generation_timeout"));
2447
+ }, this.#generationTimeoutMs);
2448
+ timeout.unref();
2449
+ const headers = {};
2450
+ applyCandidateCodexImageHeaders(headers);
2451
+ let accountId;
2452
+ let parsed;
2453
+ let parsedEdit;
2454
+ try {
2455
+ await this.#auth.applyHeaders(headers, {
2456
+ upstreamUrl: CANDIDATE_CODEX_IMAGE_URL,
2457
+ resolvedModel: CANDIDATE_CODEX_IMAGE_CARRIER_MODEL,
2458
+ sessionKey: request.sessionKey,
2459
+ preferredAccountId: request.preferredAccountId,
2460
+ preferredAccountGroup: request.preferredAccountGroup,
2461
+ boundAccountFallbackPolicy: request.boundAccountFallbackPolicy,
2462
+ reportSelection: (selectedAccountId) => {
2463
+ accountId = selectedAccountId;
2464
+ }
2465
+ });
2466
+ if (!accountId || !/^Bearer\s+\S+$/iu.test(headers.Authorization ?? "")) {
2467
+ throw new ImageGenerationError5("upstream_auth_required");
2468
+ }
2469
+ if (controller.signal.aborted) throw controller.signal.reason;
2470
+ const response = await fetchUpstream2(
2471
+ CANDIDATE_CODEX_IMAGE_URL,
2472
+ {
2473
+ method: "POST",
2474
+ headers: { ...headers },
2475
+ body: await buildCandidateCodexImageRequest(TESTED_REQUEST, controller.signal),
2476
+ signal: controller.signal
2477
+ },
2478
+ {
2479
+ providerId: "codex",
2480
+ accountId,
2481
+ traceAccountFingerprint: traceAccountFingerprint2(accountId),
2482
+ redactBodies: true
2483
+ }
2484
+ );
2485
+ const responseBody = await readCandidateCodexImageResponseBody(response);
2486
+ if (!response.ok) throw mapCandidateCodexImageFailure(response, responseBody);
2487
+ parsed = await parseCandidateCodexImageResponse(responseBody, 1, "png");
2488
+ if (controller.signal.aborted) throw controller.signal.reason;
2489
+ const editRequest = {
2490
+ ...TESTED_REQUEST,
2491
+ action: "edit",
2492
+ images: [parsed.images[0]]
2493
+ };
2494
+ const editHeaders = { ...headers };
2495
+ applyCandidateCodexImageActionHeaders(editHeaders, "edit");
2496
+ const editResponse = await fetchUpstream2(
2497
+ candidateCodexImageUrl("edit"),
2498
+ {
2499
+ method: "POST",
2500
+ headers: editHeaders,
2501
+ body: await buildCandidateCodexImageRequest(editRequest, controller.signal),
2502
+ signal: controller.signal
2503
+ },
2504
+ {
2505
+ providerId: "codex",
2506
+ accountId,
2507
+ traceAccountFingerprint: traceAccountFingerprint2(accountId),
2508
+ redactBodies: true
2509
+ }
2510
+ );
2511
+ const editResponseBody = await readCandidateCodexImageResponseBody(editResponse);
2512
+ if (!editResponse.ok) throw mapCandidateCodexImageFailure(editResponse, editResponseBody);
2513
+ parsedEdit = await parseCandidateCodexImageResponse(editResponseBody, 1, "png");
2514
+ if (controller.signal.aborted) throw controller.signal.reason;
2515
+ return observation(accountId, parsed);
2516
+ } catch (cause) {
2517
+ if (controller.signal.aborted) {
2518
+ throw controller.signal.reason instanceof ImageGenerationError5 ? controller.signal.reason : new ImageGenerationError5("request_cancelled", { cause: controller.signal.reason });
2519
+ }
2520
+ throw normalizeImageGenerationError2(cause, "image_generation_failed", {
2521
+ retrySafety: "before_acceptance"
2522
+ });
2523
+ } finally {
2524
+ disposeCandidateCodexImageResponse(parsed);
2525
+ disposeCandidateCodexImageResponse(parsedEdit);
2526
+ headers.Authorization = "";
2527
+ accountId = void 0;
2528
+ clearTimeout(timeout);
2529
+ request.signal.removeEventListener("abort", onCallerAbort);
2530
+ }
2531
+ }
2532
+ };
2533
+ function createCodexImageLiveVerifier(options) {
2534
+ return new DefaultCodexImageLiveVerifier(options);
2535
+ }
1666
2536
  export {
1667
2537
  DEFAULT_ACCOUNT_PRIORITY,
1668
2538
  LAST_USED_PERSIST_THROTTLE_MS,
@@ -1673,6 +2543,8 @@ export {
1673
2543
  SubscriptionProviderRegistry,
1674
2544
  claude_exports as claudeOAuth,
1675
2545
  codex_exports as codexOAuth,
2546
+ createCodexImageLiveVerifier,
2547
+ createCodexSubscriptionImageProvider,
1676
2548
  gemini_exports as geminiOAuth,
1677
2549
  getSubscriptionAccountService,
1678
2550
  getSubscriptionProviderRegistry,