@raybase/openai-subscription 0.0.0 → 0.1.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.
Files changed (73) hide show
  1. package/ARCHITECTURE.md +80 -0
  2. package/LICENSE +21 -0
  3. package/README.md +198 -2
  4. package/compatibility/fixtures/device-usercode.json +5 -0
  5. package/compatibility/fixtures/responses-function-call.sse +23 -0
  6. package/compatibility/fixtures/responses-image-input.sse +15 -0
  7. package/compatibility/fixtures/responses-image-request.json +32 -0
  8. package/compatibility/fixtures/responses-invalid-function-parameters.json +8 -0
  9. package/compatibility/fixtures/responses-invalid-json-schema.json +8 -0
  10. package/compatibility/fixtures/responses-mixed.sse +41 -0
  11. package/compatibility/fixtures/responses-multi-tool.sse +35 -0
  12. package/compatibility/fixtures/responses.sse +26 -0
  13. package/compatibility/manifest.json +50 -0
  14. package/dist/crypto.d.ts +12 -0
  15. package/dist/crypto.d.ts.map +1 -0
  16. package/dist/crypto.js +86 -0
  17. package/dist/crypto.js.map +1 -0
  18. package/dist/health.d.ts +9 -0
  19. package/dist/health.d.ts.map +1 -0
  20. package/dist/health.js +22 -0
  21. package/dist/health.js.map +1 -0
  22. package/dist/index.d.ts +8 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +8 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/module.d.ts +6 -0
  27. package/dist/module.d.ts.map +1 -0
  28. package/dist/module.js +341 -0
  29. package/dist/module.js.map +1 -0
  30. package/dist/provider.d.ts +8 -0
  31. package/dist/provider.d.ts.map +1 -0
  32. package/dist/provider.js +361 -0
  33. package/dist/provider.js.map +1 -0
  34. package/dist/store.d.ts +51 -0
  35. package/dist/store.d.ts.map +1 -0
  36. package/dist/store.js +342 -0
  37. package/dist/store.js.map +1 -0
  38. package/dist/system-tables.d.ts +7 -0
  39. package/dist/system-tables.d.ts.map +1 -0
  40. package/dist/system-tables.js +59 -0
  41. package/dist/system-tables.js.map +1 -0
  42. package/dist/testing.d.ts +4 -0
  43. package/dist/testing.d.ts.map +1 -0
  44. package/dist/testing.js +4 -0
  45. package/dist/testing.js.map +1 -0
  46. package/dist/transport.d.ts +104 -0
  47. package/dist/transport.d.ts.map +1 -0
  48. package/dist/transport.js +1115 -0
  49. package/dist/transport.js.map +1 -0
  50. package/dist/types.d.ts +89 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +29 -0
  53. package/dist/types.js.map +1 -0
  54. package/package.json +39 -8
  55. package/skills/raybase-openai-subscription/SKILL.md +57 -0
  56. package/skills/raybase-openai-subscription/references/compatibility-and-testing.md +129 -0
  57. package/skills/raybase-openai-subscription/references/module-contract.md +133 -0
  58. package/skills/raybase-openai-subscription/references/structured-outputs.md +159 -0
  59. package/templates/astro-emdash/.agents/skills/raybase-openai-subscription/SKILL.md +57 -0
  60. package/templates/astro-emdash/.agents/skills/raybase-openai-subscription/references/compatibility-and-testing.md +129 -0
  61. package/templates/astro-emdash/.agents/skills/raybase-openai-subscription/references/module-contract.md +133 -0
  62. package/templates/astro-emdash/.agents/skills/raybase-openai-subscription/references/structured-outputs.md +159 -0
  63. package/templates/astro-emdash/src/openai-subscription.ts +11 -0
  64. package/templates/react-router/.agents/skills/raybase-openai-subscription/SKILL.md +57 -0
  65. package/templates/react-router/.agents/skills/raybase-openai-subscription/references/compatibility-and-testing.md +129 -0
  66. package/templates/react-router/.agents/skills/raybase-openai-subscription/references/module-contract.md +133 -0
  67. package/templates/react-router/.agents/skills/raybase-openai-subscription/references/structured-outputs.md +159 -0
  68. package/templates/react-router/app/openai-subscription.ts +11 -0
  69. package/templates/tanstack-start/.agents/skills/raybase-openai-subscription/SKILL.md +57 -0
  70. package/templates/tanstack-start/.agents/skills/raybase-openai-subscription/references/compatibility-and-testing.md +129 -0
  71. package/templates/tanstack-start/.agents/skills/raybase-openai-subscription/references/module-contract.md +133 -0
  72. package/templates/tanstack-start/.agents/skills/raybase-openai-subscription/references/structured-outputs.md +159 -0
  73. package/templates/tanstack-start/src/openai-subscription.ts +11 -0
@@ -0,0 +1,129 @@
1
+ # Compatibility and testing
2
+
3
+ Use this ladder to diagnose the narrowest failing contract without leaking
4
+ credentials or poisoning a healthy subscription lane.
5
+
6
+ ## Diagnostic ladder
7
+
8
+ 1. Start with a freshly linked eligible account and a minimal request with no
9
+ tools or response format. Confirm account/workspace/model routing and SSE.
10
+ 2. Add one known-valid strict function tool whose parameters are a closed root
11
+ object. This isolates tool transport from the app's tool catalog.
12
+ 3. Test final structured output separately with Responses `text.format`.
13
+ Function `parameters` and final response schemas share the strict subset but
14
+ occupy different request fields.
15
+ 4. Replay the exact failing app schema. Record only HTTP status, the module's
16
+ sanitized and bounded fingerprint, request ID presence, counts, and sizes.
17
+ A bounded request ID may remain on the thrown error as an opaque support
18
+ correlation handle, but do not persist it automatically. Never record
19
+ request authorization, relay secrets, cookies, account IDs, raw messages or
20
+ parameter paths, bodies containing private input, or unrelated response
21
+ headers.
22
+ 5. Classify ownership before changing health:
23
+ - auth/revocation/eligibility/account selection;
24
+ - rate limit or transient upstream failure;
25
+ - fixed transport envelope/header/stream drift;
26
+ - caller tool or response schema;
27
+ - app action validation after a valid model response.
28
+ 6. For a parseable caller schema `400`, assert the public fingerprint is
29
+ sanitized and capped, the upstream message/parameter are absent, and
30
+ subscription health stays at its previous connected state. The app may
31
+ separately record its selected model attempt as failed.
32
+ 7. After focused fixtures pass, complete a real subscription-backed app turn
33
+ through the local relay with the app's full tool catalog. Check the rendered
34
+ response and both health surfaces.
35
+
36
+ ## Minimum fixtures
37
+
38
+ Cover all of these with exact schema assertions and restoration tests:
39
+
40
+ - closed root object with every property required;
41
+ - optional scalar represented with `null` and removed for the original app
42
+ validator;
43
+ - optional `const` using `anyOf` with `null`;
44
+ - root discriminated and plain unions normalized to one object;
45
+ - nested `oneOf` policy and nested `anyOf` output;
46
+ - selected-branch recursive restoration;
47
+ - arrays containing normalized objects;
48
+ - open records encoded as JSON strings and parsed back to objects;
49
+ - unconstrained values encoded as JSON strings and parsed back to every JSON
50
+ value kind;
51
+ - malformed/non-object roots rejected before transport;
52
+ - invalid JSON encodings rejected by the original validator;
53
+ - sanitized JSON refusal fixtures for both response-format
54
+ `invalid_json_schema` and tool `invalid_function_parameters` envelopes;
55
+ - `invalid_function_parameters` mapped without upstream detail or a health
56
+ incident;
57
+ - code-first/type-fallback normalization, hostile punctuation, a 32-character
58
+ token cap, and omission of overlong request IDs;
59
+ - empty, malformed, oversized, non-object, and detail-free `400` bodies mapped
60
+ to `protocol:unexpected_http_status_400` with
61
+ `protocol_update_required`;
62
+ - provider-level proof that a connected subscription remains connected with no
63
+ incident for a parseable request rejection, while an unclassifiable `400`
64
+ still transitions health.
65
+
66
+ ## Request content verified 2026-08-11
67
+
68
+ A redacted local probe against the private subscription endpoint verified the
69
+ request-side image boundary independently of the public OpenAI API:
70
+
71
+ - Ordered image content uses `{ "type": "input_image", "image_url": ... }`.
72
+ Both an absolute HTTPS URL and a `data:image/...;base64,...` value completed.
73
+ - Inline PNG, JPEG, WEBP, and non-animated GIF samples completed.
74
+ - Omitting `detail` completed, as did explicit upstream probes for `auto`,
75
+ `low`, `high`, and `original`. Raybase's provider-neutral image contract does
76
+ not expose that knob, so the adapter always omits it; no semantic equivalence
77
+ between the values was inferred.
78
+ - `quality` is not an image-input field here. The endpoint rejected it with
79
+ `400 unknown_parameter` at the image part, and Raybase rejects it locally
80
+ rather than sending it.
81
+ - A valid 1x1 PNG carrying valid ancillary padding completed through
82
+ **19,573,864 encoded JSON request bytes** and **14,680,144 decoded image
83
+ bytes**. No rejection occurred below the probe's hard 20 MiB request-body
84
+ safety cap, so the exact private limit remains unverified. This proves a
85
+ request-body lower bound, not an image-decoding or useful-pixel bound.
86
+
87
+ Agent attachments remain deliberately more conservative: the default is 8 MiB
88
+ per file, before base64 expansion, plus the configured per-message attachment
89
+ count. Endpoint permissiveness does not widen those runtime admission limits.
90
+
91
+ Documented or adjacent content kinds that remain unsupported are Responses
92
+ `input_file` (file URL, file ID, or base64 file data), image-by-file-ID, Codex
93
+ `input_audio`/audio URLs, multimodal function-call outputs, assistant image
94
+ content, and image-generation/output-item families. Core exposes no image
95
+ result or stream event and this module does not author an image-generation
96
+ tool. The response-side test therefore asserts the gap precisely:
97
+ `image_generation_call` still fails closed as
98
+ `protocol:unknown_output_item`; it is not silently skipped.
99
+
100
+ ## Live smoke requirements
101
+
102
+ Use a disposable app copy and the candidate Core CLI/package, not an old
103
+ workspace binary. Keep existing secret files out of output and source control.
104
+ For a runtime integration:
105
+
106
+ 1. `raybase modules doctor` passes the runtime contract.
107
+ 2. `raybase doctor`/`raybase check` contain no installed-only subscription
108
+ findings.
109
+ 3. `raybase modules status --json` reports `integration: "runtime"`, enabled,
110
+ not scaffold-installed.
111
+ 4. `raybase dev` starts the loopback relay and injects both local names.
112
+ 5. A linked subscription turn reaches the expected model with the full app tool
113
+ set and renders a response.
114
+ 6. Subscription health and app model health are healthy afterward.
115
+ 7. Clean shutdown removes temporary relay values.
116
+ 8. Removing the declaration restores the non-blocking undeclared-dependency
117
+ advisory and skips relay startup.
118
+
119
+ Do not replace the real linked turn with a mock when live acceptance is part of
120
+ the plan. If linking or upstream access is unavailable, record the exact blocker
121
+ and keep the implementation partial.
122
+
123
+ ## Reconfirming Codex mapping
124
+
125
+ When Codex CLI behavior matters, inspect a pinned open-source tag. Trace
126
+ `--output-schema` from CLI configuration to the Responses request and compare it
127
+ with current official OpenAI docs. Do not infer an API parameter from an
128
+ internal Rust type name, and do not vendor a mutable Codex checkout into the
129
+ module skill.
@@ -0,0 +1,133 @@
1
+ # Module contract
2
+
3
+ This reference describes the working developer contract for Raybase's
4
+ experimental `@raybase/openai-subscription` module. Private upstream details
5
+ are observations, not a public OpenAI API guarantee.
6
+
7
+ ## Integration shapes
8
+
9
+ ### Installed
10
+
11
+ `raybase modules add openai-subscription` owns the scaffold, module lock,
12
+ selected `openai-codex-subscription` provider, credential and background
13
+ strategy, generated provider manifest, and production egress binding. An
14
+ omitted `integration` field means `"installed"`. Exact install-lock provenance
15
+ wins; it cannot be relabeled runtime to bypass drift checks.
16
+
17
+ ### Runtime-registered
18
+
19
+ An app with its own dispatcher may register the package's public runtime API
20
+ and declare:
21
+
22
+ ```json
23
+ {
24
+ "raybase": {
25
+ "modules": {
26
+ "openai-subscription": {
27
+ "enabled": true,
28
+ "package": "@raybase/openai-subscription",
29
+ "integration": "runtime"
30
+ }
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ The exact package must be a production dependency. Applicable Wrangler
37
+ `secrets.required` scopes declare `RAYBASE_OPENAI_SUBSCRIPTION_KEY`, and
38
+ `env.local-dev.secrets.required` declares `RAYBASE_LOCAL_CODEX_RELAY_URL` and
39
+ `RAYBASE_LOCAL_CODEX_RELAY_SECRET`. Runtime doctor does not require the
40
+ installed provider source, selected-provider manifest, or `CODEX_EGRESS`.
41
+
42
+ An enabled declaration of either flavor starts the dev relay. An undeclared
43
+ direct dependency does not; doctor gives a non-blocking advisory rather than
44
+ guessing from imports.
45
+
46
+ ## Credentials and scope
47
+
48
+ - `operator`: one explicitly responsible operator-linked credential scope.
49
+ - `user`: separately linked user scopes; never cross users or tenants.
50
+ - `organization`: use only with the corresponding reviewed organization
51
+ arrangement and application policy.
52
+
53
+ Store encrypted credentials in the module's durable store. Keep the encryption
54
+ key in Worker secrets only. Device codes may be shown during an active link,
55
+ but access, refresh, identity, device, relay, and encryption secrets never enter
56
+ logs, source, browser persistence, fixtures, backups, screenshots, or handoffs.
57
+ Account/workspace selection is explicit; relinking replaces the intended scope,
58
+ not an arbitrary healthy credential.
59
+
60
+ Raybase informs but does not certify subscription-plan compliance. Never pool a
61
+ personal plan across unrelated employees, customers, users, or tenants. Prefer
62
+ individually linked eligible accounts or the appropriate Business, Enterprise,
63
+ or API arrangement.
64
+
65
+ These illustrations remain explicitly non-certifying:
66
+
67
+ - Plausible personal-use example: a private, noncommercial household app
68
+ operated by the subscription holder and used within that household—
69
+ Birch-shaped, with one household, one operator, two partners, and one
70
+ subscription in the operator's name.
71
+ - Likely inappropriate: one personal subscription pooled for employees,
72
+ customers, unrelated users, or multiple tenants.
73
+ - Safer small-team pattern: each user links an eligible subscription, or the
74
+ team uses an appropriate Business, Enterprise, or API arrangement.
75
+ - Multi-tenant pattern: tenant/user-scoped credentials; never silently reuse
76
+ one tenant or operator credential in another tenant.
77
+
78
+ ## Local relay and deployed egress
79
+
80
+ Local development uses a per-boot, loopback-only relay. `raybase dev` injects a
81
+ URL and authorization secret into the local worker for that session and removes
82
+ them during cleanup. Do not print or persist the secret. A relay startup or
83
+ injection failure is fatal to dev startup and must name the consequence: the
84
+ OpenAI subscription lane is unavailable for the session.
85
+
86
+ Production uses the reviewed egress binding and fixed transport implementation.
87
+ Keep the route allowlist narrow, strip caller-supplied authorization and routing
88
+ headers, set only reviewed headers, stream without buffering the whole response,
89
+ propagate cancellation, and bound error-body reads. Do not make endpoints,
90
+ headers, or account-routing details application-configurable.
91
+
92
+ ## Health and error ownership
93
+
94
+ Persisted subscription health describes the credential/transport lane, not all
95
+ caller mistakes.
96
+
97
+ - Authentication, account eligibility, workspace selection, revocation, rate
98
+ limits, and reviewed transport compatibility map to their specific safe
99
+ health states and retry/action guidance.
100
+ - `protocol_update_required` is reserved for transport-owned drift: a fixed
101
+ endpoint, required header, request/response envelope, or streaming protocol
102
+ no longer matches the reviewed implementation.
103
+ - A parseable Codex `400` with a usable machine `error.code`, or `error.type`
104
+ as fallback, is a safe request error. Normalize it to lowercase, replace
105
+ non-`[a-z0-9_]` runs, trim separators, cap the token at 32 characters, and
106
+ emit `protocol:codex_400_<token>` without a health field.
107
+ - Preserve the exact `invalid_function_parameters` plus
108
+ `tools[n].parameters` ownership case. Free-form upstream `message` text
109
+ never participates in classification or public output; `param` participates
110
+ only in that exact tool-schema check. Leave previously connected
111
+ subscription health intact.
112
+ - Empty, malformed, oversized, non-object, and machine-detail-free `400`
113
+ bodies remain `protocol:unexpected_http_status_400` with
114
+ `protocol_update_required` because caller ownership is not established.
115
+ - A trimmed, non-empty `x-oai-request-id` of at most 128 characters may travel
116
+ as opaque `oaiRequestId` metadata on the thrown error. Keep it separate from
117
+ the fingerprint and do not automatically persist it in health, incidents,
118
+ notifications, or audits.
119
+ - App model routing may separately mark its chosen model lane unhealthy after a
120
+ bad request; that must not be confused with subscription credential health.
121
+ - Transient upstream failures use bounded retry policy and must not be relabeled
122
+ permanent protocol drift.
123
+
124
+ When genuine protocol drift occurs, update and re-review the module. Operators
125
+ must not edit fixed endpoints, allowlists, or private headers to work around it.
126
+
127
+ ## Provenance
128
+
129
+ Observed and reconfirmed 2026-08-10 against the open-source Codex CLI tag
130
+ `rust-v0.146.0-alpha.9.2` (commit
131
+ `86cc9f2177cad015befd595286d8767a650f7d13`) and live Responses behavior. Recheck
132
+ these observations during compatibility updates; do not treat the date or tag
133
+ as an upstream stability promise.
@@ -0,0 +1,159 @@
1
+ # Structured outputs and strict tool schemas
2
+
3
+ This is the self-contained schema contract developers need when sending
4
+ structured output through the module. It is the standard OpenAI Structured
5
+ Outputs subset, not a subscription-specific alternative.
6
+
7
+ ## Two request shapes, one strict subset
8
+
9
+ Final structured output in the Responses API uses `text.format`:
10
+
11
+ ```json
12
+ {
13
+ "model": "MODEL_ID",
14
+ "input": "Extract project metadata",
15
+ "text": {
16
+ "format": {
17
+ "type": "json_schema",
18
+ "name": "project_metadata",
19
+ "strict": true,
20
+ "schema": {
21
+ "type": "object",
22
+ "properties": { "name": { "type": "string" } },
23
+ "required": ["name"],
24
+ "additionalProperties": false
25
+ }
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ Codex CLI's `--output-schema` maps to this Responses shape. The internal name
32
+ `codex_output_schema` is not a top-level API request parameter.
33
+
34
+ Strict function tools put the schema in `parameters`:
35
+
36
+ ```json
37
+ {
38
+ "type": "function",
39
+ "name": "project_lookup",
40
+ "description": "Look up one project.",
41
+ "strict": true,
42
+ "parameters": {
43
+ "type": "object",
44
+ "properties": {
45
+ "projectId": { "type": "string" },
46
+ "includeArchived": { "type": ["boolean", "null"] }
47
+ },
48
+ "required": ["projectId", "includeArchived"],
49
+ "additionalProperties": false
50
+ }
51
+ }
52
+ ```
53
+
54
+ The transport forwards both shapes; it does not turn an invalid application
55
+ schema into a valid one.
56
+
57
+ ## Required subset rules
58
+
59
+ 1. The root is always `{ "type": "object" }`. Root `anyOf` and root `oneOf`
60
+ unions are rejected.
61
+ 2. Every object has `additionalProperties: false`.
62
+ 3. Every property is named in `required`. Represent model-level optionality by
63
+ allowing `null`, then remove a `null` placeholder before app validation when
64
+ the original field was optional.
65
+ 4. Nested `anyOf` is supported. Strict function parameters reject `oneOf`;
66
+ avoid it or deliberately normalize it to nested `anyOf` while keeping the
67
+ original validator authoritative.
68
+ 5. Do not send unsupported composition or conditionals such as `allOf`, `not`,
69
+ `if`, `then`, or `else` unless current official compatibility explicitly
70
+ supports them.
71
+ 6. Each schema branch must constrain a real JSON type or supported union. An
72
+ empty schema from `z.unknown()` is not a strict schema.
73
+ 7. Open-ended records using `propertyNames` or schema-valued
74
+ `additionalProperties` are outside the safe strict subset. Prefer explicit
75
+ known keys.
76
+
77
+ ## Unions and optional fields
78
+
79
+ A Zod discriminated union commonly emits a root `oneOf`; a plain union commonly
80
+ emits root `anyOf`. Neither can be sent unchanged as function parameters.
81
+ Redesign it as one root object whose branch-specific fields are nullable:
82
+
83
+ ```json
84
+ {
85
+ "type": "object",
86
+ "properties": {
87
+ "kind": { "type": "string", "enum": ["text", "count"] },
88
+ "text": { "type": ["string", "null"] },
89
+ "count": { "type": ["number", "null"] }
90
+ },
91
+ "required": ["kind", "text", "count"],
92
+ "additionalProperties": false
93
+ }
94
+ ```
95
+
96
+ After generation, select the original branch from its discriminator, remove
97
+ only the nullable padding for fields optional in that branch, and validate with
98
+ the original Zod schema. Restoration must recurse through the selected branch;
99
+ walking the union wrapper alone loses its property rules.
100
+
101
+ For an optional `const`, use a real union:
102
+
103
+ ```json
104
+ { "anyOf": [{ "type": "string", "const": "fixed" }, { "type": "null" }] }
105
+ ```
106
+
107
+ Adding `null` to a separate enum does not make a non-null `const` reachable.
108
+
109
+ ## Open records and arbitrary JSON
110
+
111
+ When the application truly needs an open record or `unknown` value, use an
112
+ explicit reversible wire representation rather than pretending it is strict:
113
+
114
+ ```json
115
+ {
116
+ "type": "string",
117
+ "description": "A JSON object encoded as a string."
118
+ }
119
+ ```
120
+
121
+ Parse the generated string as JSON, require the intended value kind, then run
122
+ the original application validator before execution. For arbitrary JSON, say
123
+ "A JSON value encoded as a string" and accept any successfully parsed JSON
124
+ kind. A parse failure remains invalid input; never execute the unparsed string
125
+ as though it satisfied the original schema.
126
+
127
+ Wire normalization may broaden what the model can generate, but it never
128
+ broadens what the action may execute. Application validation is the security
129
+ and correctness boundary.
130
+
131
+ ## Failure handling
132
+
133
+ An upstream 400 with code `invalid_function_parameters` and a parameter path
134
+ under `tools[n].parameters` identifies a caller-owned tool schema. Return the
135
+ safe app error `invalid_function_parameters`, do not retain the private schema
136
+ detail, and do not transition subscription health to
137
+ `protocol_update_required`.
138
+
139
+ An upstream response-format rejection with code `invalid_json_schema` is also
140
+ caller-owned. It produces the bounded fingerprint
141
+ `protocol:codex_400_invalid_json_schema` with no subscription-health change.
142
+ Other parseable machine codes or types use the same sanitized, 32-character
143
+ `protocol:codex_400_<token>` form. Upstream messages and parameter paths are
144
+ not exposed. If the `400` body is malformed or contains no usable machine
145
+ code/type, the transport cannot assign ownership and retains the conservative
146
+ `protocol:unexpected_http_status_400` protocol-health fallback.
147
+
148
+ ## Official provenance
149
+
150
+ Rules reconfirmed 2026-08-10:
151
+
152
+ - https://developers.openai.com/api/docs/guides/structured-outputs
153
+ - https://developers.openai.com/api/docs/guides/function-calling
154
+ - https://developers.openai.com/cookbook/examples/codex/build_code_review_with_codex_sdk#codex-structured-outputs
155
+ - https://github.com/openai/codex (reviewed tag and commit are recorded in
156
+ `module-contract.md`)
157
+
158
+ External links are provenance and update checks; the working rules are included
159
+ above so the installed skill remains usable on its own.
@@ -0,0 +1,11 @@
1
+ import { openaiSubscriptionModule, type OpenAISubscriptionFetcher } from "@raybase/openai-subscription";
2
+ import type { RaybaseEnv } from "@raybase/core/worker";
3
+
4
+ export const openaiSubscription = openaiSubscriptionModule<RaybaseEnv & { CODEX_EGRESS: OpenAISubscriptionFetcher }>({
5
+ credentialMode: "user",
6
+ background: { strategy: "disabled" },
7
+ applicationScope: "raybase-app",
8
+ codexEgress: import.meta.env.DEV
9
+ ? { strategy: "local-relay" }
10
+ : { strategy: "cloudflare-vpc", binding: "CODEX_EGRESS" }
11
+ });