openai 7.5.0 → 7.7.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/CHANGELOG.md +117 -0
- package/README.md +46 -2
- package/auth/index.d.mts +1 -1
- package/auth/index.d.mts.map +1 -1
- package/auth/index.d.ts +1 -1
- package/auth/index.d.ts.map +1 -1
- package/auth/index.js.map +1 -1
- package/auth/index.mjs.map +1 -1
- package/auth/subject-token-providers.d.mts.map +1 -1
- package/auth/subject-token-providers.d.ts.map +1 -1
- package/auth/subject-token-providers.js +176 -4
- package/auth/subject-token-providers.js.map +1 -1
- package/auth/subject-token-providers.mjs +176 -4
- package/auth/subject-token-providers.mjs.map +1 -1
- package/auth/types.d.mts +17 -0
- package/auth/types.d.mts.map +1 -1
- package/auth/types.d.ts +17 -0
- package/auth/types.d.ts.map +1 -1
- package/auth/workload-identity-auth.d.mts.map +1 -1
- package/auth/workload-identity-auth.d.ts.map +1 -1
- package/auth/workload-identity-auth.js +80 -7
- package/auth/workload-identity-auth.js.map +1 -1
- package/auth/workload-identity-auth.mjs +80 -7
- package/auth/workload-identity-auth.mjs.map +1 -1
- package/auth/x509-transport.d.mts +5 -0
- package/auth/x509-transport.d.mts.map +1 -0
- package/auth/x509-transport.d.ts +5 -0
- package/auth/x509-transport.d.ts.map +1 -0
- package/auth/x509-transport.js +39 -0
- package/auth/x509-transport.js.map +1 -0
- package/auth/x509-transport.mjs +36 -0
- package/auth/x509-transport.mjs.map +1 -0
- package/azure.d.mts +11 -2
- package/azure.d.mts.map +1 -1
- package/azure.d.ts +11 -2
- package/azure.d.ts.map +1 -1
- package/azure.js +7 -1
- package/azure.js.map +1 -1
- package/azure.mjs +7 -1
- package/azure.mjs.map +1 -1
- package/bedrock.d.mts +6 -2
- package/bedrock.d.mts.map +1 -1
- package/bedrock.d.ts +6 -2
- package/bedrock.d.ts.map +1 -1
- package/bedrock.js +34 -4
- package/bedrock.js.map +1 -1
- package/bedrock.mjs +35 -5
- package/bedrock.mjs.map +1 -1
- package/beta/realtime/internal-base.d.mts +2 -0
- package/beta/realtime/internal-base.d.mts.map +1 -1
- package/beta/realtime/internal-base.d.ts +2 -0
- package/beta/realtime/internal-base.d.ts.map +1 -1
- package/beta/realtime/internal-base.js +15 -0
- package/beta/realtime/internal-base.js.map +1 -1
- package/beta/realtime/internal-base.mjs +14 -0
- package/beta/realtime/internal-base.mjs.map +1 -1
- package/beta/realtime/websocket.d.mts +11 -5
- package/beta/realtime/websocket.d.mts.map +1 -1
- package/beta/realtime/websocket.d.ts +11 -5
- package/beta/realtime/websocket.d.ts.map +1 -1
- package/beta/realtime/websocket.js +106 -31
- package/beta/realtime/websocket.js.map +1 -1
- package/beta/realtime/websocket.mjs +107 -32
- package/beta/realtime/websocket.mjs.map +1 -1
- package/beta/realtime/ws.d.mts +0 -2
- package/beta/realtime/ws.d.mts.map +1 -1
- package/beta/realtime/ws.d.ts +0 -2
- package/beta/realtime/ws.d.ts.map +1 -1
- package/beta/realtime/ws.js +24 -5
- package/beta/realtime/ws.js.map +1 -1
- package/beta/realtime/ws.mjs +25 -6
- package/beta/realtime/ws.mjs.map +1 -1
- package/client.d.mts +17 -2
- package/client.d.mts.map +1 -1
- package/client.d.ts +17 -2
- package/client.d.ts.map +1 -1
- package/client.js +422 -70
- package/client.js.map +1 -1
- package/client.mjs +423 -71
- package/client.mjs.map +1 -1
- package/core/EventEmitter.d.mts.map +1 -1
- package/core/EventEmitter.d.ts.map +1 -1
- package/core/EventEmitter.js +67 -9
- package/core/EventEmitter.js.map +1 -1
- package/core/EventEmitter.mjs +68 -10
- package/core/EventEmitter.mjs.map +1 -1
- package/core/streaming.d.mts +1 -0
- package/core/streaming.d.mts.map +1 -1
- package/core/streaming.d.ts +1 -0
- package/core/streaming.d.ts.map +1 -1
- package/core/streaming.js +216 -26
- package/core/streaming.js.map +1 -1
- package/core/streaming.mjs +216 -26
- package/core/streaming.mjs.map +1 -1
- package/helpers/audio.d.mts +5 -5
- package/helpers/audio.d.mts.map +1 -1
- package/helpers/audio.d.ts +5 -5
- package/helpers/audio.d.ts.map +1 -1
- package/helpers/audio.js +93 -22
- package/helpers/audio.js.map +1 -1
- package/helpers/audio.mjs +93 -22
- package/helpers/audio.mjs.map +1 -1
- package/helpers/standard-schema.d.mts.map +1 -1
- package/helpers/standard-schema.d.ts.map +1 -1
- package/helpers/standard-schema.js +34 -14
- package/helpers/standard-schema.js.map +1 -1
- package/helpers/standard-schema.mjs +35 -15
- package/helpers/standard-schema.mjs.map +1 -1
- package/helpers/zod-v3-strict-schema.d.mts +7 -0
- package/helpers/zod-v3-strict-schema.d.mts.map +1 -0
- package/helpers/zod-v3-strict-schema.d.ts +7 -0
- package/helpers/zod-v3-strict-schema.d.ts.map +1 -0
- package/helpers/zod-v3-strict-schema.js +403 -0
- package/helpers/zod-v3-strict-schema.js.map +1 -0
- package/helpers/zod-v3-strict-schema.mjs +399 -0
- package/helpers/zod-v3-strict-schema.mjs.map +1 -0
- package/helpers/zod.d.mts.map +1 -1
- package/helpers/zod.d.ts.map +1 -1
- package/helpers/zod.js +11 -3
- package/helpers/zod.js.map +1 -1
- package/helpers/zod.mjs +12 -4
- package/helpers/zod.mjs.map +1 -1
- package/index.d.mts +1 -1
- package/index.d.mts.map +1 -1
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/index.js.map +1 -1
- package/index.mjs.map +1 -1
- package/internal/assistant-stream-delta.d.mts.map +1 -1
- package/internal/assistant-stream-delta.d.ts.map +1 -1
- package/internal/assistant-stream-delta.js +28 -8
- package/internal/assistant-stream-delta.js.map +1 -1
- package/internal/assistant-stream-delta.mjs +28 -8
- package/internal/assistant-stream-delta.mjs.map +1 -1
- package/internal/auth/x509-token-exchange.d.mts +16 -0
- package/internal/auth/x509-token-exchange.d.mts.map +1 -0
- package/internal/auth/x509-token-exchange.d.ts +16 -0
- package/internal/auth/x509-token-exchange.d.ts.map +1 -0
- package/internal/auth/x509-token-exchange.js +246 -0
- package/internal/auth/x509-token-exchange.js.map +1 -0
- package/internal/auth/x509-token-exchange.mjs +243 -0
- package/internal/auth/x509-token-exchange.mjs.map +1 -0
- package/internal/auth/x509-transport-capability.d.mts +37 -0
- package/internal/auth/x509-transport-capability.d.mts.map +1 -0
- package/internal/auth/x509-transport-capability.d.ts +37 -0
- package/internal/auth/x509-transport-capability.d.ts.map +1 -0
- package/internal/auth/x509-transport-capability.js +169 -0
- package/internal/auth/x509-transport-capability.js.map +1 -0
- package/internal/auth/x509-transport-capability.mjs +164 -0
- package/internal/auth/x509-transport-capability.mjs.map +1 -0
- package/internal/auth/x509-transport-registry.d.mts +63 -0
- package/internal/auth/x509-transport-registry.d.mts.map +1 -0
- package/internal/auth/x509-transport-registry.d.ts +63 -0
- package/internal/auth/x509-transport-registry.d.ts.map +1 -0
- package/internal/auth/x509-transport-registry.js +53 -0
- package/internal/auth/x509-transport-registry.js.map +1 -0
- package/internal/auth/x509-transport-registry.mjs +48 -0
- package/internal/auth/x509-transport-registry.mjs.map +1 -0
- package/internal/auth/x509-transport-state-browser.d.mts +21 -0
- package/internal/auth/x509-transport-state-browser.d.mts.map +1 -0
- package/internal/auth/x509-transport-state-browser.d.ts +21 -0
- package/internal/auth/x509-transport-state-browser.d.ts.map +1 -0
- package/internal/auth/x509-transport-state-browser.js +30 -0
- package/internal/auth/x509-transport-state-browser.js.map +1 -0
- package/internal/auth/x509-transport-state-browser.mjs +27 -0
- package/internal/auth/x509-transport-state-browser.mjs.map +1 -0
- package/internal/auth/x509-transport-state.cjs +30 -0
- package/internal/auth/x509-transport-state.cjs.map +1 -0
- package/internal/auth/x509-transport-state.d.cts +21 -0
- package/internal/auth/x509-transport-state.d.cts.map +1 -0
- package/internal/auth/x509-workload-identity-auth.d.mts +128 -0
- package/internal/auth/x509-workload-identity-auth.d.mts.map +1 -0
- package/internal/auth/x509-workload-identity-auth.d.ts +128 -0
- package/internal/auth/x509-workload-identity-auth.d.ts.map +1 -0
- package/internal/auth/x509-workload-identity-auth.js +767 -0
- package/internal/auth/x509-workload-identity-auth.js.map +1 -0
- package/internal/auth/x509-workload-identity-auth.mjs +757 -0
- package/internal/auth/x509-workload-identity-auth.mjs.map +1 -0
- package/internal/bedrock.d.mts +2 -0
- package/internal/bedrock.d.mts.map +1 -1
- package/internal/bedrock.d.ts +2 -0
- package/internal/bedrock.d.ts.map +1 -1
- package/internal/bedrock.js +169 -5
- package/internal/bedrock.js.map +1 -1
- package/internal/bedrock.mjs +168 -5
- package/internal/bedrock.mjs.map +1 -1
- package/internal/data-residency.d.mts +12 -0
- package/internal/data-residency.d.mts.map +1 -0
- package/internal/data-residency.d.ts +12 -0
- package/internal/data-residency.d.ts.map +1 -0
- package/internal/data-residency.js +34 -0
- package/internal/data-residency.js.map +1 -0
- package/internal/data-residency.mjs +30 -0
- package/internal/data-residency.mjs.map +1 -0
- package/internal/multipart-encoding.d.mts +8 -0
- package/internal/multipart-encoding.d.mts.map +1 -0
- package/internal/multipart-encoding.d.ts +8 -0
- package/internal/multipart-encoding.d.ts.map +1 -0
- package/internal/multipart-encoding.js +51 -0
- package/internal/multipart-encoding.js.map +1 -0
- package/internal/multipart-encoding.mjs +48 -0
- package/internal/multipart-encoding.mjs.map +1 -0
- package/internal/qs/utils.d.mts.map +1 -1
- package/internal/qs/utils.d.ts.map +1 -1
- package/internal/qs/utils.js +307 -10
- package/internal/qs/utils.js.map +1 -1
- package/internal/qs/utils.mjs +307 -10
- package/internal/qs/utils.mjs.map +1 -1
- package/internal/request-options.d.mts +7 -0
- package/internal/request-options.d.mts.map +1 -1
- package/internal/request-options.d.ts +7 -0
- package/internal/request-options.d.ts.map +1 -1
- package/internal/request-options.js +43 -1
- package/internal/request-options.js.map +1 -1
- package/internal/request-options.mjs +42 -1
- package/internal/request-options.mjs.map +1 -1
- package/internal/responses/canonical-output-text.js +3 -3
- package/internal/responses/canonical-output-text.js.map +1 -1
- package/internal/responses/canonical-output-text.mjs +3 -3
- package/internal/responses/canonical-output-text.mjs.map +1 -1
- package/internal/responses/response-accumulator.d.mts +1 -1
- package/internal/responses/response-accumulator.d.mts.map +1 -1
- package/internal/responses/response-accumulator.d.ts +1 -1
- package/internal/responses/response-accumulator.d.ts.map +1 -1
- package/internal/responses/response-accumulator.js +331 -25
- package/internal/responses/response-accumulator.js.map +1 -1
- package/internal/responses/response-accumulator.mjs +331 -25
- package/internal/responses/response-accumulator.mjs.map +1 -1
- package/internal/tslib.js +6 -0
- package/internal/tslib.mjs +6 -1
- package/internal/uploads.d.mts +10 -6
- package/internal/uploads.d.mts.map +1 -1
- package/internal/uploads.d.ts +10 -6
- package/internal/uploads.d.ts.map +1 -1
- package/internal/uploads.js +65 -24
- package/internal/uploads.js.map +1 -1
- package/internal/uploads.mjs +65 -24
- package/internal/uploads.mjs.map +1 -1
- package/internal/utils/env.d.mts.map +1 -1
- package/internal/utils/env.d.ts.map +1 -1
- package/internal/utils/env.js +9 -4
- package/internal/utils/env.js.map +1 -1
- package/internal/utils/env.mjs +9 -4
- package/internal/utils/env.mjs.map +1 -1
- package/internal/ws.d.mts.map +1 -1
- package/internal/ws.d.ts.map +1 -1
- package/internal/ws.js +23 -1
- package/internal/ws.js.map +1 -1
- package/internal/ws.mjs +23 -1
- package/internal/ws.mjs.map +1 -1
- package/lib/AbstractChatCompletionRunner.d.mts.map +1 -1
- package/lib/AbstractChatCompletionRunner.d.ts.map +1 -1
- package/lib/AbstractChatCompletionRunner.js +32 -7
- package/lib/AbstractChatCompletionRunner.js.map +1 -1
- package/lib/AbstractChatCompletionRunner.mjs +34 -9
- package/lib/AbstractChatCompletionRunner.mjs.map +1 -1
- package/lib/AssistantStream.d.mts.map +1 -1
- package/lib/AssistantStream.d.ts.map +1 -1
- package/lib/AssistantStream.js +211 -23
- package/lib/AssistantStream.js.map +1 -1
- package/lib/AssistantStream.mjs +211 -23
- package/lib/AssistantStream.mjs.map +1 -1
- package/lib/ChatCompletionStream.d.mts +1 -1
- package/lib/ChatCompletionStream.d.mts.map +1 -1
- package/lib/ChatCompletionStream.d.ts +1 -1
- package/lib/ChatCompletionStream.d.ts.map +1 -1
- package/lib/ChatCompletionStream.js +1118 -67
- package/lib/ChatCompletionStream.js.map +1 -1
- package/lib/ChatCompletionStream.mjs +1119 -68
- package/lib/ChatCompletionStream.mjs.map +1 -1
- package/lib/EventEmitter.d.mts.map +1 -1
- package/lib/EventEmitter.d.ts.map +1 -1
- package/lib/EventEmitter.js +67 -9
- package/lib/EventEmitter.js.map +1 -1
- package/lib/EventEmitter.mjs +68 -10
- package/lib/EventEmitter.mjs.map +1 -1
- package/lib/EventStream.d.mts +4 -0
- package/lib/EventStream.d.mts.map +1 -1
- package/lib/EventStream.d.ts +4 -0
- package/lib/EventStream.d.ts.map +1 -1
- package/lib/EventStream.js +1096 -11
- package/lib/EventStream.js.map +1 -1
- package/lib/EventStream.mjs +1097 -12
- package/lib/EventStream.mjs.map +1 -1
- package/lib/ResponsesParser.d.mts.map +1 -1
- package/lib/ResponsesParser.d.ts.map +1 -1
- package/lib/ResponsesParser.js +1 -1
- package/lib/ResponsesParser.js.map +1 -1
- package/lib/ResponsesParser.mjs +1 -1
- package/lib/ResponsesParser.mjs.map +1 -1
- package/lib/Util.d.mts +2 -0
- package/lib/Util.d.mts.map +1 -1
- package/lib/Util.d.ts +2 -0
- package/lib/Util.d.ts.map +1 -1
- package/lib/Util.js +7 -4
- package/lib/Util.js.map +1 -1
- package/lib/Util.mjs +7 -4
- package/lib/Util.mjs.map +1 -1
- package/lib/assistant-run-polling.d.mts +12 -0
- package/lib/assistant-run-polling.d.mts.map +1 -0
- package/lib/assistant-run-polling.d.ts +12 -0
- package/lib/assistant-run-polling.d.ts.map +1 -0
- package/lib/assistant-run-polling.js +17 -0
- package/lib/assistant-run-polling.js.map +1 -0
- package/lib/assistant-run-polling.mjs +14 -0
- package/lib/assistant-run-polling.mjs.map +1 -0
- package/lib/embeddings.d.mts +18 -0
- package/lib/embeddings.d.mts.map +1 -0
- package/lib/embeddings.d.ts +18 -0
- package/lib/embeddings.d.ts.map +1 -0
- package/lib/embeddings.js +50 -0
- package/lib/embeddings.js.map +1 -0
- package/lib/embeddings.mjs +47 -0
- package/lib/embeddings.mjs.map +1 -0
- package/lib/file-processing.d.mts +10 -0
- package/lib/file-processing.d.mts.map +1 -0
- package/lib/file-processing.d.ts +10 -0
- package/lib/file-processing.d.ts.map +1 -0
- package/lib/file-processing.js +30 -0
- package/lib/file-processing.js.map +1 -0
- package/lib/file-processing.mjs +27 -0
- package/lib/file-processing.mjs.map +1 -0
- package/lib/parser.d.mts.map +1 -1
- package/lib/parser.d.ts.map +1 -1
- package/lib/parser.js +16 -4
- package/lib/parser.js.map +1 -1
- package/lib/parser.mjs +16 -4
- package/lib/parser.mjs.map +1 -1
- package/lib/polling.d.mts +20 -0
- package/lib/polling.d.mts.map +1 -0
- package/lib/polling.d.ts +20 -0
- package/lib/polling.d.ts.map +1 -0
- package/lib/polling.js +130 -0
- package/lib/polling.js.map +1 -0
- package/lib/polling.mjs +127 -0
- package/lib/polling.mjs.map +1 -0
- package/lib/responses/ResponseStream.d.mts.map +1 -1
- package/lib/responses/ResponseStream.d.ts.map +1 -1
- package/lib/responses/ResponseStream.js +21 -11
- package/lib/responses/ResponseStream.js.map +1 -1
- package/lib/responses/ResponseStream.mjs +21 -11
- package/lib/responses/ResponseStream.mjs.map +1 -1
- package/lib/vector-store-polling.d.mts +22 -0
- package/lib/vector-store-polling.d.mts.map +1 -0
- package/lib/vector-store-polling.d.ts +22 -0
- package/lib/vector-store-polling.d.ts.map +1 -0
- package/lib/vector-store-polling.js +24 -0
- package/lib/vector-store-polling.js.map +1 -0
- package/lib/vector-store-polling.mjs +20 -0
- package/lib/vector-store-polling.mjs.map +1 -0
- package/lib/vector-store-upload.d.mts +17 -0
- package/lib/vector-store-upload.d.mts.map +1 -0
- package/lib/vector-store-upload.d.ts +17 -0
- package/lib/vector-store-upload.d.ts.map +1 -0
- package/lib/vector-store-upload.js +37 -0
- package/lib/vector-store-upload.js.map +1 -0
- package/lib/vector-store-upload.mjs +34 -0
- package/lib/vector-store-upload.mjs.map +1 -0
- package/lib/webhook-signature.d.mts +15 -0
- package/lib/webhook-signature.d.mts.map +1 -0
- package/lib/webhook-signature.d.ts +15 -0
- package/lib/webhook-signature.d.ts.map +1 -0
- package/lib/webhook-signature.js +125 -0
- package/lib/webhook-signature.js.map +1 -0
- package/lib/webhook-signature.mjs +121 -0
- package/lib/webhook-signature.mjs.map +1 -0
- package/package.json +14 -1
- package/realtime/internal-base.d.mts +2 -0
- package/realtime/internal-base.d.mts.map +1 -1
- package/realtime/internal-base.d.ts +2 -0
- package/realtime/internal-base.d.ts.map +1 -1
- package/realtime/internal-base.js +15 -0
- package/realtime/internal-base.js.map +1 -1
- package/realtime/internal-base.mjs +14 -0
- package/realtime/internal-base.mjs.map +1 -1
- package/realtime/websocket.d.mts +3 -2
- package/realtime/websocket.d.mts.map +1 -1
- package/realtime/websocket.d.ts +3 -2
- package/realtime/websocket.d.ts.map +1 -1
- package/realtime/websocket.js +90 -26
- package/realtime/websocket.js.map +1 -1
- package/realtime/websocket.mjs +91 -27
- package/realtime/websocket.mjs.map +1 -1
- package/realtime/ws.d.mts.map +1 -1
- package/realtime/ws.d.ts.map +1 -1
- package/realtime/ws.js +9 -1
- package/realtime/ws.js.map +1 -1
- package/realtime/ws.mjs +10 -2
- package/realtime/ws.mjs.map +1 -1
- package/resources/admin/organization/index.d.mts +2 -2
- package/resources/admin/organization/index.d.mts.map +1 -1
- package/resources/admin/organization/index.d.ts +2 -2
- package/resources/admin/organization/index.d.ts.map +1 -1
- package/resources/admin/organization/index.js.map +1 -1
- package/resources/admin/organization/index.mjs.map +1 -1
- package/resources/admin/organization/organization.d.mts +4 -4
- package/resources/admin/organization/organization.d.mts.map +1 -1
- package/resources/admin/organization/organization.d.ts +4 -4
- package/resources/admin/organization/organization.d.ts.map +1 -1
- package/resources/admin/organization/organization.js.map +1 -1
- package/resources/admin/organization/organization.mjs.map +1 -1
- package/resources/admin/organization/projects/index.d.mts +1 -1
- package/resources/admin/organization/projects/index.d.mts.map +1 -1
- package/resources/admin/organization/projects/index.d.ts +1 -1
- package/resources/admin/organization/projects/index.d.ts.map +1 -1
- package/resources/admin/organization/projects/index.js.map +1 -1
- package/resources/admin/organization/projects/index.mjs.map +1 -1
- package/resources/admin/organization/projects/projects.d.mts +22 -5
- package/resources/admin/organization/projects/projects.d.mts.map +1 -1
- package/resources/admin/organization/projects/projects.d.ts +22 -5
- package/resources/admin/organization/projects/projects.d.ts.map +1 -1
- package/resources/admin/organization/projects/projects.js.map +1 -1
- package/resources/admin/organization/projects/projects.mjs.map +1 -1
- package/resources/admin/organization/usage.d.mts +62 -1
- package/resources/admin/organization/usage.d.mts.map +1 -1
- package/resources/admin/organization/usage.d.ts +62 -1
- package/resources/admin/organization/usage.d.ts.map +1 -1
- package/resources/admin/organization/usage.js.map +1 -1
- package/resources/admin/organization/usage.mjs.map +1 -1
- package/resources/beta/responses/internal-base.d.mts.map +1 -1
- package/resources/beta/responses/internal-base.d.ts.map +1 -1
- package/resources/beta/responses/internal-base.js +2 -0
- package/resources/beta/responses/internal-base.js.map +1 -1
- package/resources/beta/responses/internal-base.mjs +2 -0
- package/resources/beta/responses/internal-base.mjs.map +1 -1
- package/resources/beta/responses/responses.d.mts +17 -20
- package/resources/beta/responses/responses.d.mts.map +1 -1
- package/resources/beta/responses/responses.d.ts +17 -20
- package/resources/beta/responses/responses.d.ts.map +1 -1
- package/resources/beta/responses/responses.js.map +1 -1
- package/resources/beta/responses/responses.mjs.map +1 -1
- package/resources/beta/threads/runs/index.d.mts +1 -1
- package/resources/beta/threads/runs/index.d.mts.map +1 -1
- package/resources/beta/threads/runs/index.d.ts +1 -1
- package/resources/beta/threads/runs/index.d.ts.map +1 -1
- package/resources/beta/threads/runs/runs.d.mts.map +1 -1
- package/resources/beta/threads/runs/runs.d.ts.map +1 -1
- package/resources/beta/threads/runs/runs.js +2 -43
- package/resources/beta/threads/runs/runs.js.map +1 -1
- package/resources/beta/threads/runs/runs.mjs +2 -43
- package/resources/beta/threads/runs/runs.mjs.map +1 -1
- package/resources/chat/completions/completions.d.mts +6 -0
- package/resources/chat/completions/completions.d.mts.map +1 -1
- package/resources/chat/completions/completions.d.ts +6 -0
- package/resources/chat/completions/completions.d.ts.map +1 -1
- package/resources/chat/completions/completions.js.map +1 -1
- package/resources/chat/completions/completions.mjs.map +1 -1
- package/resources/embeddings.d.mts.map +1 -1
- package/resources/embeddings.d.ts.map +1 -1
- package/resources/embeddings.js +2 -36
- package/resources/embeddings.js.map +1 -1
- package/resources/embeddings.mjs +2 -36
- package/resources/embeddings.mjs.map +1 -1
- package/resources/files.d.mts.map +1 -1
- package/resources/files.d.ts.map +1 -1
- package/resources/files.js +2 -15
- package/resources/files.js.map +1 -1
- package/resources/files.mjs +2 -15
- package/resources/files.mjs.map +1 -1
- package/resources/images.d.mts +12 -22
- package/resources/images.d.mts.map +1 -1
- package/resources/images.d.ts +12 -22
- package/resources/images.d.ts.map +1 -1
- package/resources/realtime/calls.d.mts +23 -1
- package/resources/realtime/calls.d.mts.map +1 -1
- package/resources/realtime/calls.d.ts +23 -1
- package/resources/realtime/calls.d.ts.map +1 -1
- package/resources/realtime/calls.js +24 -0
- package/resources/realtime/calls.js.map +1 -1
- package/resources/realtime/calls.mjs +24 -0
- package/resources/realtime/calls.mjs.map +1 -1
- package/resources/realtime/index.d.mts +1 -1
- package/resources/realtime/index.d.mts.map +1 -1
- package/resources/realtime/index.d.ts +1 -1
- package/resources/realtime/index.d.ts.map +1 -1
- package/resources/realtime/index.js.map +1 -1
- package/resources/realtime/index.mjs +1 -1
- package/resources/realtime/index.mjs.map +1 -1
- package/resources/realtime/realtime.d.mts +5 -4
- package/resources/realtime/realtime.d.mts.map +1 -1
- package/resources/realtime/realtime.d.ts +5 -4
- package/resources/realtime/realtime.d.ts.map +1 -1
- package/resources/realtime/realtime.js.map +1 -1
- package/resources/realtime/realtime.mjs.map +1 -1
- package/resources/responses/internal-base.d.mts.map +1 -1
- package/resources/responses/internal-base.d.ts.map +1 -1
- package/resources/responses/internal-base.js +2 -0
- package/resources/responses/internal-base.js.map +1 -1
- package/resources/responses/internal-base.mjs +2 -0
- package/resources/responses/internal-base.mjs.map +1 -1
- package/resources/responses/responses.d.mts +17 -20
- package/resources/responses/responses.d.mts.map +1 -1
- package/resources/responses/responses.d.ts +17 -20
- package/resources/responses/responses.d.ts.map +1 -1
- package/resources/responses/responses.js.map +1 -1
- package/resources/responses/responses.mjs.map +1 -1
- package/resources/vector-stores/file-batches.d.mts.map +1 -1
- package/resources/vector-stores/file-batches.d.ts.map +1 -1
- package/resources/vector-stores/file-batches.js +4 -61
- package/resources/vector-stores/file-batches.js.map +1 -1
- package/resources/vector-stores/file-batches.mjs +4 -61
- package/resources/vector-stores/file-batches.mjs.map +1 -1
- package/resources/vector-stores/files.d.mts +1 -1
- package/resources/vector-stores/files.d.mts.map +1 -1
- package/resources/vector-stores/files.d.ts +1 -1
- package/resources/vector-stores/files.d.ts.map +1 -1
- package/resources/vector-stores/files.js +2 -35
- package/resources/vector-stores/files.js.map +1 -1
- package/resources/vector-stores/files.mjs +2 -35
- package/resources/vector-stores/files.mjs.map +1 -1
- package/resources/webhooks/webhooks.d.mts.map +1 -1
- package/resources/webhooks/webhooks.d.ts.map +1 -1
- package/resources/webhooks/webhooks.js +5 -43
- package/resources/webhooks/webhooks.js.map +1 -1
- package/resources/webhooks/webhooks.mjs +5 -43
- package/resources/webhooks/webhooks.mjs.map +1 -1
- package/src/auth/index.ts +6 -1
- package/src/auth/subject-token-providers.ts +196 -4
- package/src/auth/types.ts +24 -0
- package/src/auth/workload-identity-auth.ts +104 -7
- package/src/auth/x509-transport.ts +49 -0
- package/src/azure.ts +22 -1
- package/src/bedrock.ts +49 -5
- package/src/beta/realtime/internal-base.ts +15 -0
- package/src/beta/realtime/websocket.ts +148 -40
- package/src/beta/realtime/ws.ts +31 -13
- package/src/client.ts +536 -92
- package/src/core/EventEmitter.ts +91 -7
- package/src/core/streaming.ts +226 -30
- package/src/helpers/audio.ts +93 -22
- package/src/helpers/standard-schema.ts +50 -16
- package/src/helpers/zod-v3-strict-schema.ts +514 -0
- package/src/helpers/zod.ts +17 -4
- package/src/index.ts +1 -1
- package/src/internal/assistant-stream-delta.ts +33 -10
- package/src/internal/auth/x509-token-exchange.ts +310 -0
- package/src/internal/auth/x509-transport-capability.ts +219 -0
- package/src/internal/auth/x509-transport-registry.ts +118 -0
- package/src/internal/auth/x509-transport-state-browser.ts +36 -0
- package/src/internal/auth/x509-transport-state.cts +36 -0
- package/src/internal/auth/x509-workload-identity-auth.ts +958 -0
- package/src/internal/bedrock.ts +182 -5
- package/src/internal/data-residency.ts +44 -0
- package/src/internal/multipart-encoding.ts +53 -0
- package/src/internal/qs/utils.ts +375 -13
- package/src/internal/request-options.ts +52 -1
- package/src/internal/responses/canonical-output-text.ts +3 -3
- package/src/internal/responses/response-accumulator.ts +411 -24
- package/src/internal/uploads.ts +81 -26
- package/src/internal/utils/env.ts +9 -5
- package/src/internal/ws.ts +24 -3
- package/src/lib/AbstractChatCompletionRunner.ts +33 -6
- package/src/lib/AssistantStream.ts +262 -22
- package/src/lib/ChatCompletionStream.ts +1467 -103
- package/src/lib/EventEmitter.ts +91 -7
- package/src/lib/EventStream.ts +1483 -10
- package/src/lib/ResponsesParser.ts +4 -1
- package/src/lib/Util.ts +7 -5
- package/src/lib/assistant-run-polling.ts +27 -0
- package/src/lib/embeddings.ts +65 -0
- package/src/lib/file-processing.ts +36 -0
- package/src/lib/parser.ts +19 -4
- package/src/lib/polling.ts +144 -0
- package/src/lib/responses/ResponseStream.ts +22 -10
- package/src/lib/vector-store-polling.ts +46 -0
- package/src/lib/vector-store-upload.ts +53 -0
- package/src/lib/webhook-signature.ts +164 -0
- package/src/realtime/internal-base.ts +15 -0
- package/src/realtime/websocket.ts +130 -27
- package/src/realtime/ws.ts +15 -2
- package/src/resources/admin/organization/index.ts +2 -0
- package/src/resources/admin/organization/organization.ts +4 -0
- package/src/resources/admin/organization/projects/index.ts +1 -0
- package/src/resources/admin/organization/projects/projects.ts +37 -4
- package/src/resources/admin/organization/usage.ts +83 -0
- package/src/resources/beta/responses/internal-base.ts +2 -0
- package/src/resources/beta/responses/responses.ts +19 -22
- package/src/resources/beta/threads/runs/index.ts +1 -1
- package/src/resources/beta/threads/runs/runs.ts +2 -45
- package/src/resources/chat/completions/completions.ts +7 -0
- package/src/resources/embeddings.ts +2 -42
- package/src/resources/files.ts +2 -19
- package/src/resources/images.ts +12 -22
- package/src/resources/realtime/api.md +1 -0
- package/src/resources/realtime/calls.ts +46 -0
- package/src/resources/realtime/index.ts +7 -1
- package/src/resources/realtime/realtime.ts +5 -3
- package/src/resources/responses/internal-base.ts +2 -0
- package/src/resources/responses/responses.ts +19 -22
- package/src/resources/vector-stores/file-batches.ts +8 -77
- package/src/resources/vector-stores/files.ts +3 -43
- package/src/resources/webhooks/webhooks.ts +5 -61
- package/src/version.ts +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
package/src/helpers/zod.ts
CHANGED
|
@@ -3,7 +3,12 @@ import type * as z3 from 'zod/v3';
|
|
|
3
3
|
import * as z4 from 'zod/v4';
|
|
4
4
|
import type * as z4Mini from 'zod/v4-mini';
|
|
5
5
|
import type { AutoParseableResponseFormat, AutoParseableTextFormat, AutoParseableTool } from '../lib/parser';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
makeParseableResponseFormat,
|
|
8
|
+
makeParseableTextFormat,
|
|
9
|
+
makeParseableTool,
|
|
10
|
+
parseResponseFormatContent,
|
|
11
|
+
} from '../lib/parser';
|
|
7
12
|
import { zodToJsonSchema as _zodToJsonSchema } from '../_vendor/zod-to-json-schema';
|
|
8
13
|
import type { AutoParseableResponseTool } from '../lib/ResponsesParser';
|
|
9
14
|
import { makeParseableResponseTool } from '../lib/ResponsesParser';
|
|
@@ -12,6 +17,7 @@ import type { RealtimeFunctionTool } from '../resources/realtime/realtime';
|
|
|
12
17
|
import { forEachJSONSchemaChild, toStrictJsonSchema } from '../lib/transform';
|
|
13
18
|
import type { JSONSchema } from '../lib/jsonschema';
|
|
14
19
|
import { hasOwn } from '../internal/utils/values';
|
|
20
|
+
import { assertJSONSerializableSchema, assertSupportedZodV3Schema } from './zod-v3-strict-schema';
|
|
15
21
|
|
|
16
22
|
type ZodV4Schema = z4.ZodType | z4Mini.ZodMiniType;
|
|
17
23
|
type ZodSchema = z3.ZodType | ZodV4Schema;
|
|
@@ -128,6 +134,7 @@ function zodV3ToJsonSchema(
|
|
|
128
134
|
schema: z3.ZodType,
|
|
129
135
|
options: { name: string; schemaDefinitions?: ZodSchemaDefinitions | undefined },
|
|
130
136
|
): Record<string, unknown> {
|
|
137
|
+
assertSupportedZodV3Schema(schema, options.schemaDefinitions as Record<string, z3.ZodType> | undefined);
|
|
131
138
|
const rootName = getZodV3RootName(options.name, options.schemaDefinitions);
|
|
132
139
|
const jsonSchema = _zodToJsonSchema(schema, {
|
|
133
140
|
openaiStrictMode: true,
|
|
@@ -140,7 +147,9 @@ function zodV3ToJsonSchema(
|
|
|
140
147
|
: undefined),
|
|
141
148
|
});
|
|
142
149
|
|
|
143
|
-
|
|
150
|
+
const escapedSchema = escapeSchemaDefinitionRefs(jsonSchema, options.schemaDefinitions);
|
|
151
|
+
assertJSONSerializableSchema(escapedSchema);
|
|
152
|
+
return escapedSchema;
|
|
144
153
|
}
|
|
145
154
|
|
|
146
155
|
function zodV4ToJsonSchema(
|
|
@@ -202,11 +211,15 @@ function parseZodObject<ZodInput extends ZodTypeLike>(
|
|
|
202
211
|
zodObject: ZodInput,
|
|
203
212
|
content: string,
|
|
204
213
|
): InferZodType<ZodInput> {
|
|
205
|
-
const parsed =
|
|
214
|
+
const parsed = parseResponseFormatContent({ type: 'json_schema', $parseRaw: undefined }, content);
|
|
206
215
|
const parser = (zodObject as { parse?: (data: unknown) => unknown }).parse;
|
|
207
216
|
|
|
208
217
|
if (typeof parser === 'function') {
|
|
209
|
-
|
|
218
|
+
const result = parser.call(zodObject, parsed) as InferZodType<ZodInput>;
|
|
219
|
+
if (!isZodV4(zodObject as unknown as ZodSchema)) {
|
|
220
|
+
assertJSONSerializableSchema(result);
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
210
223
|
}
|
|
211
224
|
|
|
212
225
|
return z4.parse(zodObject as unknown as ZodV4Schema, parsed) as InferZodType<ZodInput>;
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { OpenAI as default } from './client';
|
|
|
2
2
|
|
|
3
3
|
export { type Uploadable, toFile, toStreamingFile } from './core/uploads';
|
|
4
4
|
export { APIPromise } from './core/api-promise';
|
|
5
|
-
export { OpenAI, type ClientOptions } from './client';
|
|
5
|
+
export { OpenAI, type ClientOptions, type DataResidency } from './client';
|
|
6
6
|
export { PagePromise } from './core/pagination';
|
|
7
7
|
export {
|
|
8
8
|
OpenAIError,
|
|
@@ -6,6 +6,28 @@ const MAX_EXTERNALLY_MUTABLE_ASSISTANT_STREAM_ARRAY_LENGTH = 65_536;
|
|
|
6
6
|
|
|
7
7
|
type AssistantStreamRecord = Record<string, unknown>;
|
|
8
8
|
|
|
9
|
+
function getAssistantStreamDiagnosticProperty(property: string): string {
|
|
10
|
+
switch (property) {
|
|
11
|
+
case 'value':
|
|
12
|
+
case 'arguments':
|
|
13
|
+
case 'input':
|
|
14
|
+
case 'text':
|
|
15
|
+
case 'content':
|
|
16
|
+
case 'annotations':
|
|
17
|
+
case 'metadata':
|
|
18
|
+
case 'name':
|
|
19
|
+
case 'role':
|
|
20
|
+
case 'status':
|
|
21
|
+
case 'tool_calls':
|
|
22
|
+
case 'step_details': {
|
|
23
|
+
return property;
|
|
24
|
+
}
|
|
25
|
+
default: {
|
|
26
|
+
return 'unknown';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
9
31
|
interface AssistantStreamArrayState {
|
|
10
32
|
length: number;
|
|
11
33
|
ownEntryCount: number;
|
|
@@ -87,12 +109,13 @@ function getAssistantStreamDeltaIndex(
|
|
|
87
109
|
const { index } = deltaEntry;
|
|
88
110
|
|
|
89
111
|
if (kind === 'array' && (index === null || index === undefined)) {
|
|
90
|
-
console.error(deltaEntry);
|
|
91
112
|
throw new Error('Expected array delta entry to have an `index` property');
|
|
92
113
|
}
|
|
93
114
|
|
|
94
115
|
if (kind === 'array' && typeof index !== 'number') {
|
|
95
|
-
throw new TypeError(
|
|
116
|
+
throw new TypeError(
|
|
117
|
+
'Expected array delta entry `index` property to be a number but got an invalid value',
|
|
118
|
+
);
|
|
96
119
|
}
|
|
97
120
|
|
|
98
121
|
if (
|
|
@@ -101,7 +124,8 @@ function getAssistantStreamDeltaIndex(
|
|
|
101
124
|
(index as number) >= baselineLength + MAX_ASSISTANT_STREAM_ARRAY_GROWTH ||
|
|
102
125
|
(index as number) >= MAX_EXTERNALLY_MUTABLE_ASSISTANT_STREAM_ARRAY_LENGTH
|
|
103
126
|
) {
|
|
104
|
-
|
|
127
|
+
const safeIndex = typeof index === 'number' ? index : 'unknown';
|
|
128
|
+
throw new OpenAIError(`Assistant stream delta contains an invalid ${kind} index: ${safeIndex}`);
|
|
105
129
|
}
|
|
106
130
|
|
|
107
131
|
return index as number;
|
|
@@ -139,7 +163,7 @@ function assertValidAssistantStreamArrayDelta(
|
|
|
139
163
|
|
|
140
164
|
for (const deltaEntry of delta) {
|
|
141
165
|
if (!isObj(deltaEntry)) {
|
|
142
|
-
throw new Error(
|
|
166
|
+
throw new Error('Expected array delta entry to be an object but got an invalid value');
|
|
143
167
|
}
|
|
144
168
|
|
|
145
169
|
const validatedIndex = getAssistantStreamDeltaIndex(deltaEntry, kind, projectedArray.baselineLength);
|
|
@@ -259,11 +283,12 @@ export function defineAssistantStreamArrayEntry(accumulator: unknown[], index: n
|
|
|
259
283
|
function getRequiredAssistantStreamArrayIndex(deltaEntry: AssistantStreamRecord): number {
|
|
260
284
|
const { index } = deltaEntry;
|
|
261
285
|
if (index === null || index === undefined) {
|
|
262
|
-
console.error(deltaEntry);
|
|
263
286
|
throw new Error('Expected array delta entry to have an `index` property');
|
|
264
287
|
}
|
|
265
288
|
if (typeof index !== 'number') {
|
|
266
|
-
throw new TypeError(
|
|
289
|
+
throw new TypeError(
|
|
290
|
+
'Expected array delta entry `index` property to be a number but got an invalid value',
|
|
291
|
+
);
|
|
267
292
|
}
|
|
268
293
|
return index;
|
|
269
294
|
}
|
|
@@ -286,7 +311,7 @@ function applyAssistantStreamArrayDelta(
|
|
|
286
311
|
|
|
287
312
|
for (const deltaEntry of delta) {
|
|
288
313
|
if (!isObj(deltaEntry)) {
|
|
289
|
-
throw new Error(
|
|
314
|
+
throw new Error('Expected array delta entry to be an object but got an invalid value');
|
|
290
315
|
}
|
|
291
316
|
|
|
292
317
|
const index = getRequiredAssistantStreamArrayIndex(deltaEntry);
|
|
@@ -349,9 +374,7 @@ function applyAssistantStreamDelta(
|
|
|
349
374
|
applyAssistantStreamArrayDelta(accumulatedValue, deltaValue, applyAssistantStreamDelta);
|
|
350
375
|
continue;
|
|
351
376
|
} else {
|
|
352
|
-
throw new TypeError(
|
|
353
|
-
`Unhandled record type: ${key}, deltaValue: ${deltaValue}, accValue: ${accumulatedValue}`,
|
|
354
|
-
);
|
|
377
|
+
throw new TypeError(`Unhandled record type: ${getAssistantStreamDiagnosticProperty(key)}`);
|
|
355
378
|
}
|
|
356
379
|
accumulator[key] = accumulatedValue;
|
|
357
380
|
}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import {
|
|
2
|
+
APIConnectionError,
|
|
3
|
+
APIConnectionTimeoutError,
|
|
4
|
+
APIError,
|
|
5
|
+
OAuthError,
|
|
6
|
+
OpenAIError,
|
|
7
|
+
} from '../../core/error';
|
|
8
|
+
import { hasOwn } from '../utils/values';
|
|
9
|
+
import { sendX509Request } from './x509-transport-capability';
|
|
10
|
+
import { isRetryableX509TransportFailure } from './x509-transport-registry';
|
|
11
|
+
import {
|
|
12
|
+
isTransientX509ConnectionError,
|
|
13
|
+
markRetryableX509IssuerError,
|
|
14
|
+
markTransientX509ConnectionError,
|
|
15
|
+
rememberX509OAuthError,
|
|
16
|
+
} from '#x509-transport-state';
|
|
17
|
+
import type { X509ExchangedToken, X509Transport } from './x509-transport-registry';
|
|
18
|
+
|
|
19
|
+
export type { X509ExchangedToken } from './x509-transport-registry';
|
|
20
|
+
|
|
21
|
+
const TOKEN_EXCHANGE_URL = new URL('https://mtls.auth.openai.com/oauth/token');
|
|
22
|
+
const TOKEN_EXCHANGE_GRANT = 'urn:ietf:params:oauth:grant-type:token-exchange';
|
|
23
|
+
const X509_SUBJECT_TOKEN = 'urn:openai:params:oauth:token-type:x509';
|
|
24
|
+
const ACCESS_TOKEN_TYPE = 'urn:ietf:params:oauth:token-type:access_token';
|
|
25
|
+
const SAFE_ACCESS_TOKEN = /^[A-Za-z0-9._~+/-]+=*$/u;
|
|
26
|
+
const SAFE_OAUTH_ERRORS = new Set(['invalid_grant', 'invalid_subject_token', 'token_exchange_server_error']);
|
|
27
|
+
const SAFE_RESPONSE_HEADERS = ['retry-after', 'retry-after-ms', 'x-should-retry', 'x-request-id'];
|
|
28
|
+
const MAX_TOKEN_EXCHANGE_DURATION_MS = 5000;
|
|
29
|
+
|
|
30
|
+
function transientConnectionError(message: string, failure: unknown): APIConnectionError {
|
|
31
|
+
const error = new APIConnectionError({ message });
|
|
32
|
+
if (isRetryableX509TransportFailure(failure)) {
|
|
33
|
+
markTransientX509ConnectionError(error);
|
|
34
|
+
}
|
|
35
|
+
return error;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Parameters for one certificate-authenticated OAuth exchange. */
|
|
39
|
+
export interface X509TokenExchangeOptions {
|
|
40
|
+
/** Frozen, caller-owned certificate transport shared with the eventual API request. */
|
|
41
|
+
transport: X509Transport;
|
|
42
|
+
|
|
43
|
+
/** Identity provider enrolled for the workload certificate. */
|
|
44
|
+
identityProviderId: string;
|
|
45
|
+
|
|
46
|
+
/** OpenAI service account selected for the verified certificate identity. */
|
|
47
|
+
serviceAccountId: string;
|
|
48
|
+
|
|
49
|
+
/** Optional caller cancellation propagated through request and response consumption. */
|
|
50
|
+
signal?: AbortSignal | undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function cancelReader(
|
|
54
|
+
reader: ReadableStreamDefaultReader<Uint8Array>,
|
|
55
|
+
reason?: unknown,
|
|
56
|
+
): Promise<void> {
|
|
57
|
+
try {
|
|
58
|
+
await reader.cancel(reason);
|
|
59
|
+
} catch {
|
|
60
|
+
// Response retirement is best-effort and must never replace the sanitized exchange result.
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function cancelResponseBody(response: Response): void {
|
|
65
|
+
if (!response.body) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const reader = response.body.getReader();
|
|
70
|
+
try {
|
|
71
|
+
void cancelReader(reader);
|
|
72
|
+
} finally {
|
|
73
|
+
reader.releaseLock();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function readResponseBody(response: Response, signal?: AbortSignal): Promise<unknown> {
|
|
78
|
+
if (!response.body) {
|
|
79
|
+
throw new OpenAIError('X.509 workload identity token exchange returned invalid JSON.');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const reader = response.body.getReader();
|
|
83
|
+
const chunks: Uint8Array[] = [];
|
|
84
|
+
let totalBytes = 0;
|
|
85
|
+
const cancel = () => {
|
|
86
|
+
void cancelReader(reader, signal?.reason);
|
|
87
|
+
};
|
|
88
|
+
signal?.addEventListener('abort', cancel, { once: true });
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
while (true) {
|
|
92
|
+
signal?.throwIfAborted();
|
|
93
|
+
// oxlint-disable-next-line no-await-in-loop -- Token-response chunks must be consumed in wire order.
|
|
94
|
+
const chunk = await reader.read();
|
|
95
|
+
signal?.throwIfAborted();
|
|
96
|
+
if (chunk.done) {
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
chunks.push(chunk.value);
|
|
100
|
+
totalBytes += chunk.value.byteLength;
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
cancel();
|
|
104
|
+
if (signal?.aborted) {
|
|
105
|
+
signal.throwIfAborted();
|
|
106
|
+
}
|
|
107
|
+
throw transientConnectionError('X.509 workload identity token response could not be read.', error);
|
|
108
|
+
} finally {
|
|
109
|
+
signal?.removeEventListener('abort', cancel);
|
|
110
|
+
reader.releaseLock();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const bytes = new Uint8Array(totalBytes);
|
|
114
|
+
let offset = 0;
|
|
115
|
+
for (const chunk of chunks) {
|
|
116
|
+
bytes.set(chunk, offset);
|
|
117
|
+
offset += chunk.byteLength;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
|
|
122
|
+
} catch {
|
|
123
|
+
throw new OpenAIError('X.509 workload identity token exchange returned invalid JSON.');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function validateTokenResponse(value: unknown): X509ExchangedToken {
|
|
128
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
129
|
+
throw new OpenAIError('X.509 workload identity token exchange returned an invalid token response.');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const response = value as Record<string, unknown>;
|
|
133
|
+
if (
|
|
134
|
+
!hasOwn(response, 'access_token') ||
|
|
135
|
+
typeof response['access_token'] !== 'string' ||
|
|
136
|
+
!SAFE_ACCESS_TOKEN.test(response['access_token'])
|
|
137
|
+
) {
|
|
138
|
+
throw new OpenAIError('X.509 workload identity token exchange returned an invalid access token.');
|
|
139
|
+
}
|
|
140
|
+
if (!hasOwn(response, 'token_type') || !hasOwn(response, 'issued_token_type')) {
|
|
141
|
+
throw new OpenAIError('X.509 workload identity token exchange returned an invalid token type.');
|
|
142
|
+
}
|
|
143
|
+
const tokenType = response['token_type'];
|
|
144
|
+
if (
|
|
145
|
+
typeof tokenType !== 'string' ||
|
|
146
|
+
tokenType.toLowerCase() !== 'bearer' ||
|
|
147
|
+
response['issued_token_type'] !== ACCESS_TOKEN_TYPE
|
|
148
|
+
) {
|
|
149
|
+
throw new OpenAIError('X.509 workload identity token exchange returned an invalid token type.');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!hasOwn(response, 'expires_in')) {
|
|
153
|
+
throw new OpenAIError('X.509 workload identity token exchange returned an invalid token lifetime.');
|
|
154
|
+
}
|
|
155
|
+
const expiresIn = response['expires_in'];
|
|
156
|
+
if (typeof expiresIn !== 'number' || !Number.isFinite(expiresIn) || expiresIn <= 0 || expiresIn > 3600) {
|
|
157
|
+
throw new OpenAIError('X.509 workload identity token exchange returned an invalid token lifetime.');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return { accessToken: response['access_token'], expiresIn };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function safeResponseHeaders(response: Response, includeRetryHints = false): Headers {
|
|
164
|
+
const headers = new Headers();
|
|
165
|
+
for (const name of SAFE_RESPONSE_HEADERS) {
|
|
166
|
+
if (name !== 'x-request-id' && !includeRetryHints) {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
const value = response.headers.get(name);
|
|
170
|
+
if (value !== null) {
|
|
171
|
+
headers.set(name, value);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return headers;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function readOAuthErrorCode(value: unknown): string | undefined {
|
|
178
|
+
if (typeof value === 'string') {
|
|
179
|
+
return value;
|
|
180
|
+
}
|
|
181
|
+
if (typeof value === 'object' && value !== null && hasOwn(value, 'code')) {
|
|
182
|
+
const code: unknown = Object.getOwnPropertyDescriptor(value, 'code')?.value;
|
|
183
|
+
return typeof code === 'string' ? code : undefined;
|
|
184
|
+
}
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async function oauthError(
|
|
189
|
+
response: Response,
|
|
190
|
+
signal?: AbortSignal,
|
|
191
|
+
callerSignal?: AbortSignal,
|
|
192
|
+
): Promise<OAuthError> {
|
|
193
|
+
let errorCode: { error: string } | undefined;
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
const parsed = await readResponseBody(response, signal);
|
|
197
|
+
if (typeof parsed === 'object' && parsed !== null && hasOwn(parsed, 'error')) {
|
|
198
|
+
const code = readOAuthErrorCode(Object.getOwnPropertyDescriptor(parsed, 'error')?.value);
|
|
199
|
+
if (code !== undefined && SAFE_OAUTH_ERRORS.has(code)) {
|
|
200
|
+
errorCode = { error: code };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
} catch {
|
|
204
|
+
callerSignal?.throwIfAborted();
|
|
205
|
+
if (
|
|
206
|
+
signal?.aborted &&
|
|
207
|
+
!(signal.reason instanceof APIConnectionTimeoutError && isTransientX509ConnectionError(signal.reason))
|
|
208
|
+
) {
|
|
209
|
+
signal.throwIfAborted();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const { status } = response;
|
|
214
|
+
if (status !== 400 && status !== 401 && status !== 403) {
|
|
215
|
+
throw new OpenAIError('X.509 workload identity received an invalid OAuth error status.');
|
|
216
|
+
}
|
|
217
|
+
const headers = safeResponseHeaders(response);
|
|
218
|
+
const error = new OAuthError(status, errorCode, headers);
|
|
219
|
+
rememberX509OAuthError(error, { status, error: errorCode, headers });
|
|
220
|
+
return error;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Exchanges one enrolled client certificate for a validated OpenAI workload access token. */
|
|
224
|
+
export async function exchangeX509Token(options: X509TokenExchangeOptions): Promise<X509ExchangedToken> {
|
|
225
|
+
const { signal: callerSignal } = options;
|
|
226
|
+
callerSignal?.throwIfAborted();
|
|
227
|
+
const { identityProviderId, serviceAccountId, transport } = options;
|
|
228
|
+
if (
|
|
229
|
+
typeof identityProviderId !== 'string' ||
|
|
230
|
+
identityProviderId.trim().length === 0 ||
|
|
231
|
+
typeof serviceAccountId !== 'string' ||
|
|
232
|
+
serviceAccountId.trim().length === 0
|
|
233
|
+
) {
|
|
234
|
+
throw new OpenAIError(
|
|
235
|
+
'X.509 workload identity requires nonempty provider and service-account identifiers.',
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const timeoutController = new AbortController();
|
|
240
|
+
const signal = callerSignal
|
|
241
|
+
? AbortSignal.any([callerSignal, timeoutController.signal])
|
|
242
|
+
: timeoutController.signal;
|
|
243
|
+
const timeout = setTimeout(() => {
|
|
244
|
+
const error = new APIConnectionTimeoutError({
|
|
245
|
+
message: 'X.509 workload identity token exchange timed out.',
|
|
246
|
+
});
|
|
247
|
+
markTransientX509ConnectionError(error);
|
|
248
|
+
timeoutController.abort(error);
|
|
249
|
+
}, MAX_TOKEN_EXCHANGE_DURATION_MS);
|
|
250
|
+
timeout.unref();
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
const body = JSON.stringify({
|
|
254
|
+
grant_type: TOKEN_EXCHANGE_GRANT,
|
|
255
|
+
subject_token_type: X509_SUBJECT_TOKEN,
|
|
256
|
+
identity_provider_id: identityProviderId,
|
|
257
|
+
service_account_id: serviceAccountId,
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
let response: Response;
|
|
261
|
+
try {
|
|
262
|
+
response = await sendX509Request(transport, TOKEN_EXCHANGE_URL, {
|
|
263
|
+
method: 'POST',
|
|
264
|
+
headers: { 'Content-Type': 'application/json' },
|
|
265
|
+
body,
|
|
266
|
+
redirect: 'manual',
|
|
267
|
+
signal,
|
|
268
|
+
});
|
|
269
|
+
} catch (error) {
|
|
270
|
+
signal.throwIfAborted();
|
|
271
|
+
throw transientConnectionError('X.509 workload identity token exchange connection failed.', error);
|
|
272
|
+
}
|
|
273
|
+
signal.throwIfAborted();
|
|
274
|
+
|
|
275
|
+
if (response.ok) {
|
|
276
|
+
try {
|
|
277
|
+
return validateTokenResponse(await readResponseBody(response, signal));
|
|
278
|
+
} catch (error) {
|
|
279
|
+
signal.throwIfAborted();
|
|
280
|
+
if (error instanceof APIConnectionError) {
|
|
281
|
+
throw error;
|
|
282
|
+
}
|
|
283
|
+
if (error instanceof OpenAIError) {
|
|
284
|
+
throw APIError.generate(response.status, undefined, error.message, safeResponseHeaders(response));
|
|
285
|
+
}
|
|
286
|
+
throw error;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (response.status === 400 || response.status === 401 || response.status === 403) {
|
|
290
|
+
throw await oauthError(response, signal, callerSignal);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
cancelResponseBody(response);
|
|
294
|
+
const retryableStatus =
|
|
295
|
+
response.status === 408 || response.status === 409 || response.status === 429 || response.status >= 500;
|
|
296
|
+
const headers = safeResponseHeaders(response, retryableStatus);
|
|
297
|
+
const error = APIError.generate(
|
|
298
|
+
response.status,
|
|
299
|
+
undefined,
|
|
300
|
+
'X.509 workload identity token exchange failed.',
|
|
301
|
+
headers,
|
|
302
|
+
);
|
|
303
|
+
if (retryableStatus && headers.get('x-should-retry') !== 'false') {
|
|
304
|
+
markRetryableX509IssuerError(error);
|
|
305
|
+
}
|
|
306
|
+
throw error;
|
|
307
|
+
} finally {
|
|
308
|
+
clearTimeout(timeout);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { types } from 'node:util';
|
|
2
|
+
import { Agent, ProxyAgent, Request, fetch } from 'undici';
|
|
3
|
+
import { OpenAIError } from '../../core/error';
|
|
4
|
+
import { x509TransportBrand } from './x509-transport-registry';
|
|
5
|
+
import type { RegisteredX509Transport, X509Transport } from './x509-transport-registry';
|
|
6
|
+
import { findRegisteredX509Transport, rememberRegisteredX509Transport } from '#x509-transport-state';
|
|
7
|
+
|
|
8
|
+
export type { X509Transport } from './x509-transport-registry';
|
|
9
|
+
|
|
10
|
+
/** Explicitly supported, application-owned Undici proxy configurations. */
|
|
11
|
+
export type X509ProxyMode = 'direct' | 'http-connect' | 'https-connect';
|
|
12
|
+
|
|
13
|
+
/** Application attestation for one caller-owned static-certificate Undici transport. */
|
|
14
|
+
export interface X509TransportOptions {
|
|
15
|
+
/** X.509 transport currently supports genuine Node.js runtimes only. */
|
|
16
|
+
runtime: 'node';
|
|
17
|
+
|
|
18
|
+
/** Caller-owned Undici Agent or ProxyAgent; the SDK never closes or inspects it. */
|
|
19
|
+
dispatcher: Agent | ProxyAgent;
|
|
20
|
+
|
|
21
|
+
/** Attests that the dispatcher uses one static workload-certificate identity. */
|
|
22
|
+
certificateIdentity: 'static';
|
|
23
|
+
|
|
24
|
+
/** Attests that proxy TLS and CONNECT credentials are independently configured. */
|
|
25
|
+
proxy: X509ProxyMode;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const allowedOptionNames = new Set(['runtime', 'dispatcher', 'certificateIdentity', 'proxy']);
|
|
29
|
+
const transportBrand: typeof x509TransportBrand = x509TransportBrand;
|
|
30
|
+
|
|
31
|
+
class NodeX509Transport implements X509Transport {
|
|
32
|
+
declare readonly [transportBrand]: true;
|
|
33
|
+
|
|
34
|
+
readonly #dispatcher: Agent | ProxyAgent;
|
|
35
|
+
|
|
36
|
+
constructor(dispatcher: Agent | ProxyAgent) {
|
|
37
|
+
this.#dispatcher = dispatcher;
|
|
38
|
+
Object.freeze(this);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static dispatcher(value: object): Agent | ProxyAgent | undefined {
|
|
42
|
+
return #dispatcher in value ? value.#dispatcher : undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Registers only a genuine frozen capability whose JavaScript private dispatcher cannot be forged. */
|
|
47
|
+
export function registerX509Transport(transport: X509Transport, registered: RegisteredX509Transport): void {
|
|
48
|
+
if (
|
|
49
|
+
!transport ||
|
|
50
|
+
typeof transport !== 'object' ||
|
|
51
|
+
types.isProxy(transport) ||
|
|
52
|
+
!Object.isFrozen(transport) ||
|
|
53
|
+
!NodeX509Transport.dispatcher(transport)
|
|
54
|
+
) {
|
|
55
|
+
throw new OpenAIError('Only a genuine frozen X.509 transport capability can be registered.');
|
|
56
|
+
}
|
|
57
|
+
if (findRegisteredX509Transport(transport)) {
|
|
58
|
+
throw new OpenAIError('An approved X.509 transport capability cannot be registered more than once.');
|
|
59
|
+
}
|
|
60
|
+
rememberRegisteredX509Transport(transport, Object.freeze(registered));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function dataOption(options: X509TransportOptions, name: keyof X509TransportOptions): unknown {
|
|
64
|
+
const descriptor = Object.getOwnPropertyDescriptor(options, name);
|
|
65
|
+
if (!descriptor || !('value' in descriptor)) {
|
|
66
|
+
throw new Error(`X.509 transport option \`${name}\` must be an own plain data property.`);
|
|
67
|
+
}
|
|
68
|
+
return descriptor.value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function assertNodeRuntime(): void {
|
|
72
|
+
if (
|
|
73
|
+
typeof process === 'undefined' ||
|
|
74
|
+
process.release.name !== 'node' ||
|
|
75
|
+
'bun' in process.versions ||
|
|
76
|
+
'Bun' in globalThis ||
|
|
77
|
+
'Deno' in globalThis
|
|
78
|
+
) {
|
|
79
|
+
throw new Error('X.509 transport requires a genuine Node.js runtime.');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function attestedDispatcher(options: X509TransportOptions): Agent | ProxyAgent {
|
|
84
|
+
const dispatcher = dataOption(options, 'dispatcher');
|
|
85
|
+
if (!dispatcher || typeof dispatcher !== 'object') {
|
|
86
|
+
throw new Error('X.509 transport requires a caller-owned Undici Agent or ProxyAgent.');
|
|
87
|
+
}
|
|
88
|
+
if (types.isProxy(dispatcher)) {
|
|
89
|
+
throw new Error('X.509 transport does not accept a dispatcher proxy.');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const isDirect = dispatcher instanceof Agent;
|
|
93
|
+
const isConnect = dispatcher instanceof ProxyAgent;
|
|
94
|
+
if (!isDirect && !isConnect) {
|
|
95
|
+
throw new Error('X.509 transport requires a caller-owned Undici Agent or ProxyAgent.');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const proxy = dataOption(options, 'proxy');
|
|
99
|
+
if (proxy !== 'direct' && proxy !== 'http-connect' && proxy !== 'https-connect') {
|
|
100
|
+
throw new Error('X.509 transport requires an explicitly supported proxy mode.');
|
|
101
|
+
}
|
|
102
|
+
if ((proxy === 'direct') !== isDirect) {
|
|
103
|
+
throw new Error('An X.509 CONNECT proxy requires an Undici ProxyAgent.');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return dispatcher;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function assertRequestDispatcherSupport(dispatcher: Agent | ProxyAgent): void {
|
|
110
|
+
let observesRequestDispatcher = false;
|
|
111
|
+
|
|
112
|
+
// about:blank never reaches the network; the getter checks the actual fetch contract.
|
|
113
|
+
void Promise.allSettled([
|
|
114
|
+
fetch('about:blank', {
|
|
115
|
+
get dispatcher() {
|
|
116
|
+
observesRequestDispatcher = true;
|
|
117
|
+
return dispatcher;
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
if (!observesRequestDispatcher) {
|
|
123
|
+
throw new Error('X.509 transport requires Undici 5.2.0 or later with per-request dispatcher support.');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function assertConnectProxySupport(): void {
|
|
128
|
+
const targetOrigin = 'https://127.0.0.1:65535';
|
|
129
|
+
let routedOrigin: string | undefined;
|
|
130
|
+
const probe = new ProxyAgent({
|
|
131
|
+
uri: 'http://127.0.0.1:1',
|
|
132
|
+
factory(origin) {
|
|
133
|
+
routedOrigin = String(origin);
|
|
134
|
+
throw new Error('X.509 CONNECT capability probe');
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// The throwing factory reveals the actual routing decision before any socket opens.
|
|
139
|
+
const request = fetch(targetOrigin, { dispatcher: probe });
|
|
140
|
+
void Promise.allSettled([request, probe.close()]);
|
|
141
|
+
|
|
142
|
+
if (routedOrigin !== targetOrigin) {
|
|
143
|
+
throw new Error('X.509 CONNECT proxy requires Undici 5.5.1 or later with target TLS tunneling.');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Creates a frozen, opaque capability for one caller-owned Undici transport.
|
|
149
|
+
*
|
|
150
|
+
* `certificateIdentity: 'static'` is an application attestation: the SDK does
|
|
151
|
+
* not inspect certificates, private dispatcher internals, callbacks, or TLS
|
|
152
|
+
* options and cannot cryptographically prove certificate selection. Configure
|
|
153
|
+
* one static identity without custom dispatcher factories. For HTTPS CONNECT,
|
|
154
|
+
* independently configure `proxyTls` and `requestTls` so workload credentials
|
|
155
|
+
* never reach the proxy. Rotation requires creating a fresh dispatcher and
|
|
156
|
+
* capability; the application remains responsible for draining the old one.
|
|
157
|
+
*
|
|
158
|
+
* This Node-only preview entrypoint requires the optional `undici` peer at
|
|
159
|
+
* version 5.2.0 or later. CONNECT proxy modes require version 5.5.1 or
|
|
160
|
+
* later; ordinary SDK clients retain broader compatibility.
|
|
161
|
+
*/
|
|
162
|
+
export function createX509Transport(options: X509TransportOptions): X509Transport {
|
|
163
|
+
assertNodeRuntime();
|
|
164
|
+
|
|
165
|
+
if (!options || typeof options !== 'object' || types.isProxy(options)) {
|
|
166
|
+
throw new Error('X.509 transport configuration must be a non-proxy object.');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
for (const name of Reflect.ownKeys(options)) {
|
|
170
|
+
if (typeof name !== 'string' || !allowedOptionNames.has(name)) {
|
|
171
|
+
throw new Error(`Unsupported X.509 transport option: \`${String(name)}\`.`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (dataOption(options, 'runtime') !== 'node') {
|
|
176
|
+
throw new Error('X.509 transport requires an explicitly attested Node.js runtime.');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (dataOption(options, 'certificateIdentity') !== 'static') {
|
|
180
|
+
throw new Error('X.509 transport requires an explicitly attested static client certificate.');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const dispatcher = attestedDispatcher(options);
|
|
184
|
+
assertRequestDispatcherSupport(dispatcher);
|
|
185
|
+
if (dispatcher instanceof ProxyAgent) {
|
|
186
|
+
assertConnectProxySupport();
|
|
187
|
+
}
|
|
188
|
+
return new NodeX509Transport(dispatcher);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Dispatches through the opaque attested transport without accepting replacement dispatchers. */
|
|
192
|
+
export async function sendX509Request(
|
|
193
|
+
transport: X509Transport,
|
|
194
|
+
target: URL,
|
|
195
|
+
options: RequestInit,
|
|
196
|
+
): Promise<Response> {
|
|
197
|
+
if (!transport || typeof transport !== 'object' || types.isProxy(transport)) {
|
|
198
|
+
throw new Error('Invalid X.509 transport capability.');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const dispatcher = NodeX509Transport.dispatcher(transport);
|
|
202
|
+
if (!dispatcher) {
|
|
203
|
+
throw new Error('Invalid X.509 transport capability.');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const normalizedTarget = new URL(target.href);
|
|
207
|
+
if (normalizedTarget.protocol !== 'https:') {
|
|
208
|
+
throw new Error('X.509 transport requires an HTTPS destination.');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (Object.getOwnPropertyDescriptor(options, 'dispatcher')) {
|
|
212
|
+
throw new Error('X.509 transport does not allow a per-request dispatcher override.');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const requestOptions: Omit<RequestInit, 'dispatcher'> = options;
|
|
216
|
+
const request = new Request(normalizedTarget, requestOptions);
|
|
217
|
+
const response = await fetch(request, { dispatcher, redirect: 'manual' });
|
|
218
|
+
return response;
|
|
219
|
+
}
|