@bleedingdev/modern-js-create-request 3.5.0-ultramodern.5 → 3.5.0-ultramodern.75

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/esm/node.mjs CHANGED
@@ -1,24 +1,10 @@
1
1
  import { storage } from "@modern-js/runtime-utils/node";
2
- import { compile } from "path-to-regexp";
3
- import { stringify } from "qs";
4
2
  import { handleRes } from "./handleRes.mjs";
5
- import { CrossOriginEnvelopePolicyError, IdentityBindingViolationError, OperationContractViolationError, ProducerClientNotInitializedError, ProducerDomainNotConfiguredError, TRACEPARENT_HEADER, attachOperationContextHeaders, buildEnvelopeHeaderValue, deleteHeader, extractPathParamNames, firstHeaderValue, isEmptyDomain, isSecuredRequestId, parseTraceparentValue, readHeader, resolveConfiguredRequest, toOrigin, writeHeader } from "./policyCore.mjs";
6
- import { executeWithResilience } from "./transport.mjs";
7
- import { BFF_DEFAULT_PROTECTED_IDENTITY_HEADERS, BFF_ENVELOPE_HEADER, BFF_OPERATION_CONTEXT_DETAIL_HEADER, BFF_OPERATION_CONTEXT_HEADER } from "./types.mjs";
8
- import { getUploadPayload } from "./utiles.mjs";
3
+ import { CrossOriginEnvelopePolicyError, IdentityBindingViolationError, OperationContractViolationError, ProducerClientNotInitializedError, ProducerDomainNotConfiguredError, firstHeaderValue, toOrigin } from "./policyCore.mjs";
4
+ import { createRequestFactory } from "./requestFactory.mjs";
9
5
  export * from "./requestContext.mjs";
10
6
  export * from "./traceparent.mjs";
11
7
  export * from "./types.mjs";
12
- const realRequest = new Map();
13
- const realAllowedHeaders = new Map();
14
- const realResolveHeaders = new Map();
15
- const realRequireEnvelope = new Map();
16
- const realAllowCrossOriginEnvelope = new Map();
17
- const realTransportResilience = new Map();
18
- const realIdentityBinding = new Map();
19
- const realOperationContract = new Map();
20
- const domainMap = new Map();
21
- const OPERATION_CONTEXT_DETAIL_HEADER = BFF_OPERATION_CONTEXT_DETAIL_HEADER;
22
8
  const resolveSourceOrigin = (headers)=>{
23
9
  const origin = toOrigin(firstHeaderValue(headers.origin));
24
10
  if (origin) return origin;
@@ -41,225 +27,15 @@ const originFetch = (...params)=>{
41
27
  if (init?.method?.toLowerCase() === 'get') init.body = void 0;
42
28
  return fetch(...params).then(handleRes);
43
29
  };
44
- const attachEnvelopeHeaderIfRequired = (headers, requestId, url, webRequestHeaders)=>{
45
- const shouldRequireEnvelope = realRequireEnvelope.get(requestId) ?? isSecuredRequestId(requestId);
46
- if (!shouldRequireEnvelope) return;
47
- headers[BFF_ENVELOPE_HEADER] = buildEnvelopeHeaderValue({
48
- requestId,
49
- target: 'server',
50
- sourceOrigin: resolveSourceOrigin(webRequestHeaders),
51
- targetOrigin: toOrigin(url),
52
- traceContext: parseTraceparentValue(readHeader(headers, TRACEPARENT_HEADER)),
53
- allowCrossOriginEnvelope: realAllowCrossOriginEnvelope.get(requestId)
54
- });
55
- };
56
- const attachSecuredOperationHeaders = (headers, requestId, method, path, operationContext)=>{
57
- if (!isSecuredRequestId(requestId)) return;
58
- attachOperationContextHeaders({
59
- headers,
60
- requestId,
61
- target: 'server',
62
- method,
63
- path,
64
- operationContext,
65
- operationContract: realOperationContract.get(requestId),
66
- operationContextHeader: BFF_OPERATION_CONTEXT_HEADER,
67
- operationContextDetailHeader: OPERATION_CONTEXT_DETAIL_HEADER
68
- });
69
- };
70
- const configure = (options)=>{
71
- const { request, interceptor, allowedHeaders, resolveHeaders, transport, requireEnvelope, allowCrossOriginEnvelope, identityBinding, operationContract, setDomain, requestId = 'default' } = options;
72
- const hasExistingDomain = domainMap.has(requestId);
73
- if ('default' !== requestId && !setDomain && !hasExistingDomain) throw new ProducerDomainNotConfiguredError(requestId);
74
- let configuredRequest = request || originFetch;
75
- if (interceptor && !request) configuredRequest = interceptor(fetch);
76
- if (Array.isArray(allowedHeaders)) realAllowedHeaders.set(requestId, allowedHeaders);
77
- if ('function' == typeof resolveHeaders) realResolveHeaders.set(requestId, resolveHeaders);
78
- if (transport && 'object' == typeof transport) realTransportResilience.set(requestId, transport);
79
- if (identityBinding && 'object' == typeof identityBinding) realIdentityBinding.set(requestId, identityBinding);
80
- if (operationContract && 'object' == typeof operationContract) realOperationContract.set(requestId, operationContract);
81
- if ('boolean' == typeof requireEnvelope) realRequireEnvelope.set(requestId, requireEnvelope);
82
- if ('boolean' == typeof allowCrossOriginEnvelope || 'function' == typeof allowCrossOriginEnvelope) realAllowCrossOriginEnvelope.set(requestId, allowCrossOriginEnvelope);
83
- if (setDomain) {
84
- const resolvedDomain = setDomain({
85
- target: 'server',
86
- requestId
87
- });
88
- if ('default' !== requestId && isEmptyDomain(resolvedDomain)) throw new ProducerDomainNotConfiguredError(requestId);
89
- if ('string' == typeof resolvedDomain) domainMap.set(requestId, resolvedDomain);
90
- }
91
- realRequest.set(requestId, configuredRequest);
92
- };
93
- const normalizeRequestOptions = (...args)=>{
94
- if ('object' == typeof args[0] && null !== args[0]) return args[0];
95
- const [path, method, port, httpMethodDecider, fetch1, requestId, operationContext] = args;
96
- return {
97
- path,
98
- method,
99
- port,
100
- httpMethodDecider,
101
- fetch: fetch1,
102
- requestId,
103
- operationContext
104
- };
105
- };
106
- const createRequest = (...args)=>{
107
- const { path, method, port, httpMethodDecider = 'functionName', fetch: fetch1 = originFetch, requestId = 'default', operationContext } = normalizeRequestOptions(...args);
108
- const getFinalPath = compile(path, {
109
- encode: encodeURIComponent
110
- });
111
- const keyNames = extractPathParamNames(path);
112
- const sender = (...args)=>{
113
- const fetcher = resolveConfiguredRequest(realRequest, requestId, fetch1);
114
- const webRequestHeaders = readIncomingWebHeaders();
115
- let body;
116
- let headers;
117
- let url;
118
- if ('inputParams' === httpMethodDecider) {
119
- const configDomain = domainMap.get(requestId);
120
- if ('default' !== requestId && isEmptyDomain(configDomain)) throw new ProducerDomainNotConfiguredError(requestId);
121
- url = `${configDomain || `http://127.0.0.1:${port}`}${path}`;
122
- body = args;
123
- headers = {
124
- 'Content-Type': 'application/json'
125
- };
126
- } else {
127
- const payload = 'object' == typeof args[args.length - 1] ? args[args.length - 1] : {};
128
- payload.params = payload.params || {};
129
- const requestParams = args[0];
130
- if ('object' == typeof requestParams && requestParams.params) {
131
- const { params } = requestParams;
132
- keyNames.forEach((keyName)=>{
133
- payload.params[keyName] = params[keyName];
134
- });
135
- } else keyNames.forEach((keyName, index)=>{
136
- payload.params[keyName] = args[index];
137
- });
138
- const plainPath = getFinalPath(payload.params);
139
- const finalPath = payload.query ? `${plainPath}?${stringify(payload.query)}` : plainPath;
140
- headers = payload.headers ? {
141
- ...payload.headers
142
- } : {};
143
- const identityBinding = realIdentityBinding.get(requestId);
144
- const identityBindingEnabled = identityBinding?.enabled ?? isSecuredRequestId(requestId);
145
- const identityBindingStrict = identityBinding?.strict ?? isSecuredRequestId(requestId);
146
- const protectedIdentityHeaders = (identityBinding?.protectedHeaders || BFF_DEFAULT_PROTECTED_IDENTITY_HEADERS).map((header)=>header.toLowerCase());
147
- const targetAllowedHeaders = realAllowedHeaders.get(requestId) || [];
148
- const forwardedHeaders = {};
149
- for (const key of targetAllowedHeaders)if (void 0 !== webRequestHeaders[key]) forwardedHeaders[key] = webRequestHeaders[key];
150
- if (identityBindingEnabled) {
151
- const derivedIdentityHeaders = {};
152
- for (const header of protectedIdentityHeaders){
153
- const incomingHeaderValue = readHeader(webRequestHeaders, header);
154
- if (void 0 !== incomingHeaderValue) writeHeader(derivedIdentityHeaders, header, incomingHeaderValue);
155
- }
156
- const customDerivedHeaders = identityBinding?.deriveHeaders?.({
157
- requestId,
158
- target: 'server',
159
- incomingHeaders: {
160
- ...webRequestHeaders
161
- },
162
- protectedHeaders: [
163
- ...protectedIdentityHeaders
164
- ]
165
- });
166
- if (customDerivedHeaders && 'object' == typeof customDerivedHeaders) for (const header of protectedIdentityHeaders){
167
- const customValue = readHeader(customDerivedHeaders, header);
168
- if (void 0 !== customValue) writeHeader(derivedIdentityHeaders, header, customValue);
169
- }
170
- for (const header of protectedIdentityHeaders){
171
- const attemptedValue = readHeader(headers, header);
172
- if (void 0 === attemptedValue) continue;
173
- const violation = {
174
- requestId,
175
- target: 'server',
176
- header,
177
- attemptedValue,
178
- derivedValue: readHeader(derivedIdentityHeaders, header),
179
- reason: identityBindingStrict ? 'client_override_rejected' : 'client_override_blocked'
180
- };
181
- identityBinding?.onViolation?.(violation);
182
- if (identityBindingStrict) throw new IdentityBindingViolationError(violation);
183
- deleteHeader(headers, header);
184
- }
185
- Object.keys(derivedIdentityHeaders).forEach((header)=>{
186
- writeHeader(forwardedHeaders, header, derivedIdentityHeaders[header]);
187
- });
188
- }
189
- const resolveHeaders = realResolveHeaders.get(requestId);
190
- if (resolveHeaders) {
191
- const resolvedHeaders = resolveHeaders({
192
- requestId,
193
- allowedHeaders: targetAllowedHeaders,
194
- incomingHeaders: {
195
- ...forwardedHeaders
196
- }
197
- });
198
- if (resolvedHeaders && 'object' == typeof resolvedHeaders) {
199
- for (const key of targetAllowedHeaders)if (void 0 !== resolvedHeaders[key]) forwardedHeaders[key] = resolvedHeaders[key];
200
- }
201
- }
202
- headers = {
203
- ...headers,
204
- ...forwardedHeaders
205
- };
206
- if (payload.data) {
207
- headers['Content-Type'] = 'application/json';
208
- body = 'object' == typeof payload.data ? JSON.stringify(payload.data) : payload.body;
209
- } else if (payload.body) {
210
- headers['Content-Type'] = 'text/plain';
211
- body = payload.body;
212
- } else if (payload.formData) body = payload.formData;
213
- else if (payload.formUrlencoded) {
214
- headers['Content-Type'] = 'application/x-www-form-urlencoded';
215
- body = 'object' == typeof payload.formUrlencoded ? stringify(payload.formUrlencoded) : payload.formUrlencoded;
216
- }
217
- const configDomain = domainMap.get(requestId);
218
- if ('default' !== requestId && isEmptyDomain(configDomain)) throw new ProducerDomainNotConfiguredError(requestId);
219
- url = `${configDomain || `http://127.0.0.1:${port}`}${finalPath}`;
220
- }
221
- if (void 0 === readHeader(headers, TRACEPARENT_HEADER)) {
222
- const incomingTraceparent = firstHeaderValue(readHeader(webRequestHeaders, TRACEPARENT_HEADER));
223
- if ('string' == typeof incomingTraceparent) writeHeader(headers, TRACEPARENT_HEADER, incomingTraceparent);
224
- }
225
- if (void 0 === readHeader(headers, TRACEPARENT_HEADER) && operationContext?.traceparent) writeHeader(headers, TRACEPARENT_HEADER, operationContext.traceparent);
226
- attachEnvelopeHeaderIfRequired(headers, requestId, url, webRequestHeaders);
227
- attachSecuredOperationHeaders(headers, requestId, method, path, operationContext);
228
- if ('get' === method.toLowerCase()) body = void 0;
229
- headers.accept = "application/json,*/*;q=0.8";
230
- return executeWithResilience({
231
- requestId,
232
- target: 'server',
233
- method,
234
- url,
235
- init: {
236
- method,
237
- body,
238
- headers
239
- },
240
- fetcher,
241
- transport: realTransportResilience.get(requestId)
242
- });
243
- };
244
- return sender;
245
- };
246
- const createUploader = ({ path, requestId = 'default', operationContext })=>{
247
- const sender = (...args)=>{
248
- const fetcher = resolveConfiguredRequest(realRequest, requestId, originFetch);
249
- const { body, headers: uploadHeaders } = getUploadPayload(args);
250
- const headers = {
251
- ...uploadHeaders
252
- };
253
- const configDomain = domainMap.get(requestId);
254
- const finalURL = `${configDomain || ''}${path}`;
255
- attachEnvelopeHeaderIfRequired(headers, requestId, finalURL, readIncomingWebHeaders());
256
- attachSecuredOperationHeaders(headers, requestId, 'POST', path, operationContext);
257
- return fetcher(finalURL, {
258
- method: 'POST',
259
- body,
260
- headers
261
- });
262
- };
263
- return sender;
264
- };
30
+ const requestFactory = createRequestFactory({
31
+ target: 'server',
32
+ getFetch: ()=>fetch,
33
+ originFetch: originFetch,
34
+ readIncomingHeaders: readIncomingWebHeaders,
35
+ resolveSourceOrigin: resolveSourceOrigin,
36
+ createInputParamsBody: (args)=>args,
37
+ resolveRequestUrl: ({ configDomain, path, port })=>`${configDomain || `http://127.0.0.1:${port}`}${path}`,
38
+ resolveUploadUrl: ({ configDomain, path })=>`${configDomain || ''}${path}`
39
+ });
40
+ const { configure: configure, createRequest: createRequest, createUploader: createUploader } = requestFactory;
265
41
  export { CrossOriginEnvelopePolicyError, IdentityBindingViolationError, OperationContractViolationError, ProducerClientNotInitializedError, ProducerDomainNotConfiguredError, configure, createRequest, createUploader };
@@ -132,7 +132,7 @@ const resolveConfiguredRequest = (configuredRequests, requestId, fallback)=>{
132
132
  const buildEnvelopeHeaderValue = ({ requestId, target, sourceOrigin, targetOrigin, traceContext, allowCrossOriginEnvelope })=>{
133
133
  const isCrossOrigin = Boolean(sourceOrigin) && Boolean(targetOrigin) && sourceOrigin !== targetOrigin;
134
134
  if (isCrossOrigin) {
135
- const isAllowed = 'function' == typeof allowCrossOriginEnvelope ? allowCrossOriginEnvelope({
135
+ const isAllowed = 'function' == typeof allowCrossOriginEnvelope ? true === allowCrossOriginEnvelope({
136
136
  requestId,
137
137
  sourceOrigin,
138
138
  targetOrigin,
@@ -171,4 +171,4 @@ const attachOperationContextHeaders = ({ headers, requestId, target, method, pat
171
171
  writeHeader(headers, operationContextDetailHeader, JSON.stringify(contextPayload));
172
172
  return contextPayload;
173
173
  };
174
- export { CrossOriginEnvelopePolicyError, IdentityBindingViolationError, OperationContractViolationError, ProducerClientNotInitializedError, ProducerDomainNotConfiguredError, TRACEPARENT_HEADER, attachOperationContextHeaders, buildEnvelopeHeaderValue, buildOperationContext, deleteHeader, extractPathParamNames, findHeaderKey, firstHeaderValue, isEmptyDomain, isSecuredRequestId, isStrictDefaultRequestIdEnabled, parseTraceparentValue, readHeader, resolveConfiguredRequest, toOrigin, validateOperationContract, writeHeader };
174
+ export { CrossOriginEnvelopePolicyError, IdentityBindingViolationError, OperationContractViolationError, ProducerClientNotInitializedError, ProducerDomainNotConfiguredError, TRACEPARENT_HEADER, attachOperationContextHeaders, buildEnvelopeHeaderValue, buildOperationContext, deleteHeader, extractPathParamNames, findHeaderKey, firstHeaderValue, isEmptyDomain, isSecuredRequestId, parseTraceparentValue, readHeader, resolveConfiguredRequest, toOrigin, validateOperationContract, writeHeader };
@@ -0,0 +1,277 @@
1
+ import { compile } from "path-to-regexp";
2
+ import { stringify } from "qs";
3
+ import { IdentityBindingViolationError, ProducerDomainNotConfiguredError, TRACEPARENT_HEADER, attachOperationContextHeaders, buildEnvelopeHeaderValue, deleteHeader, extractPathParamNames, firstHeaderValue, isEmptyDomain, isSecuredRequestId, parseTraceparentValue, readHeader, resolveConfiguredRequest, toOrigin, writeHeader } from "./policyCore.mjs";
4
+ import { executeWithResilience } from "./transport.mjs";
5
+ import { BFF_DEFAULT_PROTECTED_IDENTITY_HEADERS, BFF_ENVELOPE_HEADER, BFF_OPERATION_CONTEXT_DETAIL_HEADER, BFF_OPERATION_CONTEXT_HEADER } from "./types.mjs";
6
+ import { getUploadPayload } from "./utiles.mjs";
7
+ const OPERATION_CONTEXT_DETAIL_HEADER = BFF_OPERATION_CONTEXT_DETAIL_HEADER;
8
+ const createRequestFactory = (environment)=>{
9
+ const isServerTarget = 'server' === environment.target;
10
+ const realRequest = new Map();
11
+ const realAllowedHeaders = new Map();
12
+ const realResolveHeaders = new Map();
13
+ const realRequireEnvelope = new Map();
14
+ const realAllowCrossOriginEnvelope = new Map();
15
+ const realTransportResilience = new Map();
16
+ const realIdentityBinding = new Map();
17
+ const realOperationContract = new Map();
18
+ const domainMap = new Map();
19
+ const attachEnvelopeHeaderIfRequired = (headers, requestId, url, incomingHeaders)=>{
20
+ const shouldRequireEnvelope = realRequireEnvelope.get(requestId) ?? isSecuredRequestId(requestId);
21
+ if (!shouldRequireEnvelope) return;
22
+ headers[BFF_ENVELOPE_HEADER] = buildEnvelopeHeaderValue({
23
+ requestId,
24
+ target: environment.target,
25
+ sourceOrigin: environment.resolveSourceOrigin(incomingHeaders),
26
+ targetOrigin: toOrigin(url),
27
+ traceContext: parseTraceparentValue(readHeader(headers, TRACEPARENT_HEADER)),
28
+ allowCrossOriginEnvelope: realAllowCrossOriginEnvelope.get(requestId)
29
+ });
30
+ };
31
+ const attachSecuredOperationHeaders = (headers, requestId, method, path, operationContext)=>{
32
+ if (!isSecuredRequestId(requestId)) return;
33
+ attachOperationContextHeaders({
34
+ headers,
35
+ requestId,
36
+ target: environment.target,
37
+ method,
38
+ path,
39
+ operationContext,
40
+ operationContract: realOperationContract.get(requestId),
41
+ operationContextHeader: BFF_OPERATION_CONTEXT_HEADER,
42
+ operationContextDetailHeader: OPERATION_CONTEXT_DETAIL_HEADER
43
+ });
44
+ };
45
+ const applyIdentityAndForwardedHeaders = (headers, requestId, incomingHeaders)=>{
46
+ const identityBinding = realIdentityBinding.get(requestId);
47
+ const identityBindingEnabled = identityBinding?.enabled ?? isSecuredRequestId(requestId);
48
+ const identityBindingStrict = identityBinding?.strict ?? isSecuredRequestId(requestId);
49
+ const protectedIdentityHeaders = (identityBinding?.protectedHeaders || BFF_DEFAULT_PROTECTED_IDENTITY_HEADERS).map((header)=>header.toLowerCase());
50
+ const targetAllowedHeaders = realAllowedHeaders.get(requestId) || [];
51
+ const forwardedHeaders = {};
52
+ if (isServerTarget) {
53
+ for (const key of targetAllowedHeaders)if (void 0 !== incomingHeaders[key]) forwardedHeaders[key] = incomingHeaders[key];
54
+ }
55
+ if (identityBindingEnabled) {
56
+ const derivedIdentityHeaders = {};
57
+ if (isServerTarget) for (const header of protectedIdentityHeaders){
58
+ const incomingHeaderValue = readHeader(incomingHeaders, header);
59
+ if (void 0 !== incomingHeaderValue) writeHeader(derivedIdentityHeaders, header, incomingHeaderValue);
60
+ }
61
+ const customDerivedHeaders = identityBinding?.deriveHeaders?.({
62
+ requestId,
63
+ target: environment.target,
64
+ incomingHeaders: isServerTarget ? {
65
+ ...incomingHeaders
66
+ } : {},
67
+ protectedHeaders: [
68
+ ...protectedIdentityHeaders
69
+ ]
70
+ });
71
+ if (customDerivedHeaders && 'object' == typeof customDerivedHeaders) for (const header of protectedIdentityHeaders){
72
+ const customValue = readHeader(customDerivedHeaders, header);
73
+ if (void 0 !== customValue) writeHeader(derivedIdentityHeaders, header, customValue);
74
+ }
75
+ for (const header of protectedIdentityHeaders){
76
+ const attemptedValue = readHeader(headers, header);
77
+ if (void 0 === attemptedValue) continue;
78
+ const violation = {
79
+ requestId,
80
+ target: environment.target,
81
+ header,
82
+ attemptedValue,
83
+ derivedValue: readHeader(derivedIdentityHeaders, header),
84
+ reason: 'client_override_blocked'
85
+ };
86
+ identityBinding?.onViolation?.(violation);
87
+ if (identityBindingStrict) throw new IdentityBindingViolationError(violation);
88
+ deleteHeader(headers, header);
89
+ }
90
+ Object.keys(derivedIdentityHeaders).forEach((header)=>{
91
+ isServerTarget ? writeHeader(forwardedHeaders, header, derivedIdentityHeaders[header]) : writeHeader(headers, header, derivedIdentityHeaders[header]);
92
+ });
93
+ }
94
+ if (isServerTarget) {
95
+ const resolveHeaders = realResolveHeaders.get(requestId);
96
+ if (resolveHeaders) {
97
+ const resolvedHeaders = resolveHeaders({
98
+ requestId,
99
+ allowedHeaders: targetAllowedHeaders,
100
+ incomingHeaders: {
101
+ ...forwardedHeaders
102
+ }
103
+ });
104
+ if (resolvedHeaders && 'object' == typeof resolvedHeaders) {
105
+ for (const key of targetAllowedHeaders)if (void 0 !== resolvedHeaders[key]) {
106
+ if (identityBindingEnabled && protectedIdentityHeaders.includes(key.toLowerCase())) {
107
+ writeHeader(forwardedHeaders, key.toLowerCase(), resolvedHeaders[key]);
108
+ continue;
109
+ }
110
+ forwardedHeaders[key] = resolvedHeaders[key];
111
+ }
112
+ }
113
+ }
114
+ }
115
+ if (isServerTarget) return {
116
+ ...headers,
117
+ ...forwardedHeaders
118
+ };
119
+ return headers;
120
+ };
121
+ const configure = (options)=>{
122
+ const { request, interceptor, allowedHeaders, resolveHeaders, transport, requireEnvelope, allowCrossOriginEnvelope, identityBinding, operationContract, setDomain, requestId = 'default' } = options;
123
+ const hasExistingDomain = domainMap.has(requestId);
124
+ if ('default' !== requestId && !setDomain && !hasExistingDomain) throw new ProducerDomainNotConfiguredError(requestId);
125
+ let configuredRequest = request || environment.originFetch;
126
+ if (interceptor && !request) configuredRequest = interceptor(environment.getFetch());
127
+ if (Array.isArray(allowedHeaders)) realAllowedHeaders.set(requestId, allowedHeaders);
128
+ if (isServerTarget && 'function' == typeof resolveHeaders) realResolveHeaders.set(requestId, resolveHeaders);
129
+ if (transport && 'object' == typeof transport) realTransportResilience.set(requestId, transport);
130
+ if (identityBinding && 'object' == typeof identityBinding) realIdentityBinding.set(requestId, identityBinding);
131
+ if (operationContract && 'object' == typeof operationContract) realOperationContract.set(requestId, operationContract);
132
+ if ('boolean' == typeof requireEnvelope) realRequireEnvelope.set(requestId, requireEnvelope);
133
+ if ('boolean' == typeof allowCrossOriginEnvelope || 'function' == typeof allowCrossOriginEnvelope) realAllowCrossOriginEnvelope.set(requestId, allowCrossOriginEnvelope);
134
+ if (setDomain) {
135
+ const resolvedDomain = setDomain({
136
+ target: environment.target,
137
+ requestId
138
+ });
139
+ if ('default' !== requestId && isEmptyDomain(resolvedDomain)) throw new ProducerDomainNotConfiguredError(requestId);
140
+ if ('string' == typeof resolvedDomain) domainMap.set(requestId, resolvedDomain);
141
+ }
142
+ realRequest.set(requestId, configuredRequest);
143
+ };
144
+ const createRequest = (...args)=>{
145
+ const options = 'object' == typeof args[0] && null !== args[0] ? args[0] : {
146
+ path: args[0],
147
+ method: args[1],
148
+ port: args[2],
149
+ httpMethodDecider: args[3],
150
+ fetch: args[4],
151
+ requestId: args[5],
152
+ operationContext: args[6]
153
+ };
154
+ const { path, method, port, httpMethodDecider = 'functionName', fetch = environment.originFetch, requestId = 'default', operationContext } = options;
155
+ const getFinalPath = compile(path, {
156
+ encode: encodeURIComponent
157
+ });
158
+ const keyNames = extractPathParamNames(path);
159
+ const send = (...senderArgs)=>{
160
+ const fetcher = resolveConfiguredRequest(realRequest, requestId, fetch);
161
+ const incomingHeaders = environment.readIncomingHeaders();
162
+ let body;
163
+ let headers;
164
+ let url;
165
+ if ('inputParams' === httpMethodDecider) {
166
+ const configDomain = domainMap.get(requestId);
167
+ if ('default' !== requestId && isEmptyDomain(configDomain)) throw new ProducerDomainNotConfiguredError(requestId);
168
+ url = environment.resolveRequestUrl({
169
+ configDomain,
170
+ port,
171
+ path
172
+ });
173
+ body = environment.createInputParamsBody(senderArgs);
174
+ headers = {
175
+ 'Content-Type': 'application/json'
176
+ };
177
+ } else {
178
+ const payload = 'object' == typeof senderArgs[senderArgs.length - 1] ? senderArgs[senderArgs.length - 1] : {};
179
+ payload.params = payload.params || {};
180
+ const requestParams = senderArgs[0];
181
+ if ('object' == typeof requestParams && requestParams.params) {
182
+ const { params } = requestParams;
183
+ keyNames.forEach((keyName)=>{
184
+ payload.params[keyName] = params[keyName];
185
+ });
186
+ } else keyNames.forEach((keyName, index)=>{
187
+ payload.params[keyName] = senderArgs[index];
188
+ });
189
+ const plainPath = getFinalPath(payload.params);
190
+ const finalPath = payload.query ? `${plainPath}?${stringify(payload.query)}` : plainPath;
191
+ headers = payload.headers ? {
192
+ ...payload.headers
193
+ } : {};
194
+ headers = applyIdentityAndForwardedHeaders(headers, requestId, incomingHeaders);
195
+ if (payload.data) {
196
+ headers['Content-Type'] = 'application/json';
197
+ body = 'object' == typeof payload.data ? JSON.stringify(payload.data) : payload.body;
198
+ } else if (payload.body) {
199
+ headers['Content-Type'] = 'text/plain';
200
+ body = payload.body;
201
+ } else if (payload.formData) body = payload.formData;
202
+ else if (payload.formUrlencoded) {
203
+ headers['Content-Type'] = 'application/x-www-form-urlencoded';
204
+ body = !isServerTarget && "u" > typeof URLSearchParams && payload.formUrlencoded instanceof URLSearchParams ? payload.formUrlencoded : 'object' == typeof payload.formUrlencoded ? stringify(payload.formUrlencoded) : payload.formUrlencoded;
205
+ }
206
+ const configDomain = domainMap.get(requestId);
207
+ if ('default' !== requestId && isEmptyDomain(configDomain)) throw new ProducerDomainNotConfiguredError(requestId);
208
+ url = environment.resolveRequestUrl({
209
+ configDomain,
210
+ port,
211
+ path: finalPath
212
+ });
213
+ }
214
+ if (!isServerTarget) writeHeader(headers, 'accept', "application/json,*/*;q=0.8");
215
+ if (isServerTarget) {
216
+ if (void 0 === readHeader(headers, TRACEPARENT_HEADER)) {
217
+ const incomingTraceparent = firstHeaderValue(readHeader(incomingHeaders, TRACEPARENT_HEADER));
218
+ if ('string' == typeof incomingTraceparent) writeHeader(headers, TRACEPARENT_HEADER, incomingTraceparent);
219
+ }
220
+ if (void 0 === readHeader(headers, TRACEPARENT_HEADER) && operationContext?.traceparent) writeHeader(headers, TRACEPARENT_HEADER, operationContext.traceparent);
221
+ }
222
+ attachEnvelopeHeaderIfRequired(headers, requestId, url, incomingHeaders);
223
+ attachSecuredOperationHeaders(headers, requestId, method, path, operationContext);
224
+ if ('get' === method.toLowerCase()) body = void 0;
225
+ if (isServerTarget) writeHeader(headers, 'accept', "application/json,*/*;q=0.8");
226
+ return executeWithResilience({
227
+ requestId,
228
+ target: environment.target,
229
+ method,
230
+ url,
231
+ init: {
232
+ method,
233
+ body,
234
+ headers
235
+ },
236
+ fetcher: fetcher,
237
+ transport: realTransportResilience.get(requestId)
238
+ });
239
+ };
240
+ const sender = isServerTarget ? send : async (...senderArgs)=>send(...senderArgs);
241
+ return sender;
242
+ };
243
+ const createUploader = ({ path, domain, requestId = 'default', operationContext })=>{
244
+ const getUploadPath = isServerTarget ? void 0 : compile(path, {
245
+ encode: encodeURIComponent
246
+ });
247
+ const sender = (...args)=>{
248
+ const fetcher = resolveConfiguredRequest(realRequest, requestId, environment.originFetch);
249
+ const { body, headers: uploadHeaders, params } = getUploadPayload(args);
250
+ const headers = {
251
+ ...uploadHeaders
252
+ };
253
+ const finalPath = getUploadPath ? getUploadPath(params) : path;
254
+ const configDomain = domainMap.get(requestId);
255
+ const finalURL = environment.resolveUploadUrl({
256
+ configDomain,
257
+ domain,
258
+ path: finalPath
259
+ });
260
+ const incomingHeaders = environment.readIncomingHeaders();
261
+ attachEnvelopeHeaderIfRequired(headers, requestId, finalURL, incomingHeaders);
262
+ attachSecuredOperationHeaders(headers, requestId, 'POST', path, operationContext);
263
+ return fetcher(finalURL, {
264
+ method: 'POST',
265
+ body,
266
+ headers
267
+ });
268
+ };
269
+ return sender;
270
+ };
271
+ return {
272
+ configure,
273
+ createRequest,
274
+ createUploader
275
+ };
276
+ };
277
+ export { createRequestFactory };
@@ -10,6 +10,14 @@ const DEFAULT_RETRYABLE_STATUS_CODES = [
10
10
  const DEFAULT_BASE_DELAY_MS = 100;
11
11
  const DEFAULT_MAX_DELAY_MS = 1000;
12
12
  const DEFAULT_JITTER_RATIO = 0.1;
13
+ const DEFAULT_RETRYABLE_METHODS = new Set([
14
+ 'DELETE',
15
+ 'GET',
16
+ 'HEAD',
17
+ 'OPTIONS',
18
+ 'PUT',
19
+ 'TRACE'
20
+ ]);
13
21
  const createTimeoutError = (timeoutMs)=>{
14
22
  const error = new Error(`Request timed out after ${timeoutMs}ms`);
15
23
  error.name = 'TimeoutError';
@@ -29,7 +37,7 @@ const toStatusCode = (error)=>{
29
37
  const isRetryableNetworkError = (error)=>{
30
38
  if (!error || 'object' != typeof error) return false;
31
39
  const name = error.name;
32
- if ('AbortError' === name || 'FetchError' === name || 'TimeoutError' === name || 'TypeError' === name) return true;
40
+ if ('FetchError' === name || 'TimeoutError' === name || 'TypeError' === name) return true;
33
41
  const code = error.code;
34
42
  return 'ECONNRESET' === code || 'ETIMEDOUT' === code || 'ECONNREFUSED' === code || 'EPIPE' === code;
35
43
  };
@@ -39,7 +47,8 @@ const normalizeJitterRatio = (value)=>{
39
47
  if ('number' != typeof value || !Number.isFinite(value)) return DEFAULT_JITTER_RATIO;
40
48
  return Math.max(0, Math.min(1, value));
41
49
  };
42
- const shouldRetryWithDefaults = (statusCode, error, retryableStatusCodes)=>{
50
+ const shouldRetryWithDefaults = (method, statusCode, error, retryableStatusCodes)=>{
51
+ if (!DEFAULT_RETRYABLE_METHODS.has(method.toUpperCase())) return false;
43
52
  if ('number' == typeof statusCode) return retryableStatusCodes.includes(statusCode);
44
53
  return isRetryableNetworkError(error);
45
54
  };
@@ -49,7 +58,7 @@ const shouldRetry = (retryOptions, context, retryableStatusCodes)=>{
49
58
  } catch (error) {
50
59
  return false;
51
60
  }
52
- return shouldRetryWithDefaults(context.statusCode, context.error, retryableStatusCodes);
61
+ return shouldRetryWithDefaults(context.method, context.statusCode, context.error, retryableStatusCodes);
53
62
  };
54
63
  const getBackoffMs = (retryOptions, attempt)=>{
55
64
  const baseDelayMs = normalizePositiveNumber(retryOptions?.baseDelayMs, DEFAULT_BASE_DELAY_MS);