@bleedingdev/modern-js-create-request 3.8.3-ultramodern.6 → 3.9.0-ultramodern.10
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/cjs/browser.js +22 -79
- package/dist/cjs/{traceparent.js → headers.js} +24 -21
- package/dist/cjs/node.js +21 -87
- package/dist/cjs/requestFactory.js +58 -166
- package/dist/cjs/types.js +1 -40
- package/dist/esm/browser.mjs +13 -18
- package/dist/esm/headers.mjs +15 -0
- package/dist/esm/node.mjs +11 -25
- package/dist/esm/requestFactory.mjs +50 -160
- package/dist/esm/types.mjs +0 -10
- package/dist/esm-node/browser.mjs +13 -18
- package/dist/esm-node/headers.mjs +16 -0
- package/dist/esm-node/node.mjs +11 -25
- package/dist/esm-node/requestFactory.mjs +50 -160
- package/dist/esm-node/types.mjs +0 -10
- package/dist/types/browser.d.ts +3 -5
- package/dist/types/headers.d.ts +3 -0
- package/dist/types/node.d.ts +3 -5
- package/dist/types/requestFactory.d.ts +5 -9
- package/dist/types/types.d.ts +38 -127
- package/package.json +7 -7
- package/dist/cjs/policyCore.js +0 -272
- package/dist/cjs/requestContext.js +0 -121
- package/dist/cjs/transport.js +0 -234
- package/dist/esm/policyCore.mjs +0 -174
- package/dist/esm/requestContext.mjs +0 -74
- package/dist/esm/traceparent.mjs +0 -18
- package/dist/esm/transport.mjs +0 -196
- package/dist/esm-node/policyCore.mjs +0 -175
- package/dist/esm-node/requestContext.mjs +0 -75
- package/dist/esm-node/traceparent.mjs +0 -19
- package/dist/esm-node/transport.mjs +0 -197
- package/dist/types/policyCore.d.ts +0 -108
- package/dist/types/requestContext.d.ts +0 -19
- package/dist/types/traceparent.d.ts +0 -10
- package/dist/types/transport.d.ts +0 -12
|
@@ -1,151 +1,54 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import { compile } from "path-to-regexp";
|
|
3
3
|
import { stringify } from "qs";
|
|
4
|
-
import {
|
|
5
|
-
import { executeWithResilience } from "./transport.mjs";
|
|
6
|
-
import { BFF_DEFAULT_PROTECTED_IDENTITY_HEADERS, BFF_ENVELOPE_HEADER, BFF_OPERATION_CONTEXT_DETAIL_HEADER, BFF_OPERATION_CONTEXT_HEADER } from "./types.mjs";
|
|
4
|
+
import { readHeader, writeHeader } from "./headers.mjs";
|
|
7
5
|
import { getUploadPayload } from "./utiles.mjs";
|
|
8
|
-
const
|
|
6
|
+
const extractPathParamNames = (path)=>Array.from(path.matchAll(/:([A-Za-z0-9_]+)/g)).flatMap(([, key])=>key ? [
|
|
7
|
+
key
|
|
8
|
+
] : []);
|
|
9
9
|
const createRequestFactory = (environment)=>{
|
|
10
10
|
const isServerTarget = 'server' === environment.target;
|
|
11
11
|
const realRequest = new Map();
|
|
12
12
|
const realAllowedHeaders = new Map();
|
|
13
|
-
const realResolveHeaders = new Map();
|
|
14
|
-
const realRequireEnvelope = new Map();
|
|
15
|
-
const realAllowCrossOriginEnvelope = new Map();
|
|
16
|
-
const realTransportResilience = new Map();
|
|
17
|
-
const realIdentityBinding = new Map();
|
|
18
|
-
const realOperationContract = new Map();
|
|
19
13
|
const domainMap = new Map();
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
if (!shouldRequireEnvelope) return;
|
|
23
|
-
headers[BFF_ENVELOPE_HEADER] = buildEnvelopeHeaderValue({
|
|
14
|
+
const startRequest = (requestId, hooks)=>{
|
|
15
|
+
const context = {
|
|
24
16
|
requestId,
|
|
25
17
|
target: environment.target,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const attachSecuredOperationHeaders = (headers, requestId, method, path, operationContext)=>{
|
|
33
|
-
if (!isSecuredRequestId(requestId)) return;
|
|
34
|
-
attachOperationContextHeaders({
|
|
35
|
-
headers,
|
|
36
|
-
requestId,
|
|
37
|
-
target: environment.target,
|
|
38
|
-
method,
|
|
39
|
-
path,
|
|
40
|
-
operationContext,
|
|
41
|
-
operationContract: realOperationContract.get(requestId),
|
|
42
|
-
operationContextHeader: BFF_OPERATION_CONTEXT_HEADER,
|
|
43
|
-
operationContextDetailHeader: OPERATION_CONTEXT_DETAIL_HEADER
|
|
44
|
-
});
|
|
18
|
+
incomingHeaders: environment.readIncomingHeaders(),
|
|
19
|
+
configured: realRequest.has(requestId),
|
|
20
|
+
configuredDomain: domainMap.get(requestId)
|
|
21
|
+
};
|
|
22
|
+
hooks?.onStart?.(context);
|
|
23
|
+
return context;
|
|
45
24
|
};
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const identityBindingEnabled = identityBinding?.enabled ?? isSecuredRequestId(requestId);
|
|
49
|
-
const identityBindingStrict = identityBinding?.strict ?? isSecuredRequestId(requestId);
|
|
50
|
-
const protectedIdentityHeaders = (identityBinding?.protectedHeaders || BFF_DEFAULT_PROTECTED_IDENTITY_HEADERS).map((header)=>header.toLowerCase());
|
|
51
|
-
const targetAllowedHeaders = realAllowedHeaders.get(requestId) || [];
|
|
25
|
+
const prepareHeaders = (headers, context, hooks)=>{
|
|
26
|
+
const allowedHeaders = realAllowedHeaders.get(context.requestId) || [];
|
|
52
27
|
const forwardedHeaders = {};
|
|
53
|
-
if (isServerTarget) for (const key of
|
|
54
|
-
const
|
|
55
|
-
if (void 0 !==
|
|
56
|
-
}
|
|
57
|
-
if (identityBindingEnabled) {
|
|
58
|
-
const derivedIdentityHeaders = {};
|
|
59
|
-
if (isServerTarget) for (const header of protectedIdentityHeaders){
|
|
60
|
-
const incomingHeaderValue = readHeader(incomingHeaders, header);
|
|
61
|
-
if (void 0 !== incomingHeaderValue) writeHeader(derivedIdentityHeaders, header, incomingHeaderValue);
|
|
62
|
-
}
|
|
63
|
-
const customDerivedHeaders = identityBinding?.deriveHeaders?.({
|
|
64
|
-
requestId,
|
|
65
|
-
target: environment.target,
|
|
66
|
-
incomingHeaders: isServerTarget ? {
|
|
67
|
-
...incomingHeaders
|
|
68
|
-
} : {},
|
|
69
|
-
protectedHeaders: [
|
|
70
|
-
...protectedIdentityHeaders
|
|
71
|
-
]
|
|
72
|
-
});
|
|
73
|
-
if (customDerivedHeaders && 'object' == typeof customDerivedHeaders) for (const header of protectedIdentityHeaders){
|
|
74
|
-
const customValue = readHeader(customDerivedHeaders, header);
|
|
75
|
-
if (void 0 !== customValue) writeHeader(derivedIdentityHeaders, header, customValue);
|
|
76
|
-
}
|
|
77
|
-
for (const header of protectedIdentityHeaders){
|
|
78
|
-
const attemptedValue = readHeader(headers, header);
|
|
79
|
-
if (void 0 === attemptedValue) continue;
|
|
80
|
-
const violation = {
|
|
81
|
-
requestId,
|
|
82
|
-
target: environment.target,
|
|
83
|
-
header,
|
|
84
|
-
attemptedValue,
|
|
85
|
-
derivedValue: readHeader(derivedIdentityHeaders, header),
|
|
86
|
-
reason: 'client_override_blocked'
|
|
87
|
-
};
|
|
88
|
-
identityBinding?.onViolation?.(violation);
|
|
89
|
-
if (identityBindingStrict) throw new IdentityBindingViolationError(violation);
|
|
90
|
-
deleteHeader(headers, header);
|
|
91
|
-
}
|
|
92
|
-
Object.keys(derivedIdentityHeaders).forEach((header)=>{
|
|
93
|
-
isServerTarget ? writeHeader(forwardedHeaders, header, derivedIdentityHeaders[header]) : writeHeader(headers, header, derivedIdentityHeaders[header]);
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
if (isServerTarget) {
|
|
97
|
-
const resolveHeaders = realResolveHeaders.get(requestId);
|
|
98
|
-
if (resolveHeaders) {
|
|
99
|
-
const resolvedHeaders = resolveHeaders({
|
|
100
|
-
requestId,
|
|
101
|
-
allowedHeaders: targetAllowedHeaders,
|
|
102
|
-
incomingHeaders: {
|
|
103
|
-
...forwardedHeaders
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
if (resolvedHeaders && 'object' == typeof resolvedHeaders) for (const key of targetAllowedHeaders){
|
|
107
|
-
const resolvedValue = readHeader(resolvedHeaders, key);
|
|
108
|
-
if (void 0 !== resolvedValue) {
|
|
109
|
-
if (identityBindingEnabled && protectedIdentityHeaders.includes(key.toLowerCase())) {
|
|
110
|
-
writeHeader(forwardedHeaders, key.toLowerCase(), resolvedValue);
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
writeHeader(forwardedHeaders, key, resolvedValue);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
28
|
+
if (isServerTarget) for (const key of allowedHeaders){
|
|
29
|
+
const value = readHeader(context.incomingHeaders, key);
|
|
30
|
+
if (void 0 !== value) writeHeader(forwardedHeaders, key, value);
|
|
117
31
|
}
|
|
32
|
+
hooks?.prepareHeaders?.({
|
|
33
|
+
...context,
|
|
34
|
+
headers,
|
|
35
|
+
forwardedHeaders,
|
|
36
|
+
allowedHeaders
|
|
37
|
+
});
|
|
118
38
|
if (isServerTarget) for (const [header, value] of Object.entries(forwardedHeaders))writeHeader(headers, header, value);
|
|
119
39
|
return headers;
|
|
120
40
|
};
|
|
41
|
+
const dispatch = (context, hooks)=>hooks?.dispatch ? hooks.dispatch(context) : context.fetcher(context.url, context.init);
|
|
121
42
|
const configure = (options)=>{
|
|
122
|
-
const { request, interceptor, allowedHeaders,
|
|
123
|
-
const hasExistingDomain = domainMap.has(requestId);
|
|
124
|
-
if ('default' !== requestId && !setDomain && !hasExistingDomain) throw new ProducerDomainNotConfiguredError(requestId);
|
|
43
|
+
const { request, interceptor, allowedHeaders, setDomain, requestId = 'default' } = options;
|
|
125
44
|
let configuredRequest = request || environment.originFetch;
|
|
126
45
|
if (interceptor && !request) configuredRequest = interceptor(environment.getFetch());
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
requestId
|
|
132
|
-
});
|
|
133
|
-
if ('default' !== requestId && isEmptyDomain(resolvedDomain)) throw new ProducerDomainNotConfiguredError(requestId);
|
|
134
|
-
}
|
|
46
|
+
const resolvedDomain = setDomain?.({
|
|
47
|
+
target: environment.target,
|
|
48
|
+
requestId
|
|
49
|
+
});
|
|
135
50
|
realAllowedHeaders.delete(requestId);
|
|
136
|
-
realResolveHeaders.delete(requestId);
|
|
137
|
-
realTransportResilience.delete(requestId);
|
|
138
|
-
realIdentityBinding.delete(requestId);
|
|
139
|
-
realOperationContract.delete(requestId);
|
|
140
|
-
realRequireEnvelope.delete(requestId);
|
|
141
|
-
realAllowCrossOriginEnvelope.delete(requestId);
|
|
142
51
|
if (Array.isArray(allowedHeaders)) realAllowedHeaders.set(requestId, allowedHeaders);
|
|
143
|
-
if (isServerTarget && 'function' == typeof resolveHeaders) realResolveHeaders.set(requestId, resolveHeaders);
|
|
144
|
-
if (transport && 'object' == typeof transport) realTransportResilience.set(requestId, transport);
|
|
145
|
-
if (identityBinding && 'object' == typeof identityBinding) realIdentityBinding.set(requestId, identityBinding);
|
|
146
|
-
if (operationContract && 'object' == typeof operationContract) realOperationContract.set(requestId, operationContract);
|
|
147
|
-
if ('boolean' == typeof requireEnvelope) realRequireEnvelope.set(requestId, requireEnvelope);
|
|
148
|
-
if ('boolean' == typeof allowCrossOriginEnvelope || 'function' == typeof allowCrossOriginEnvelope) realAllowCrossOriginEnvelope.set(requestId, allowCrossOriginEnvelope);
|
|
149
52
|
if ('string' == typeof resolvedDomain) domainMap.set(requestId, resolvedDomain);
|
|
150
53
|
realRequest.set(requestId, configuredRequest);
|
|
151
54
|
};
|
|
@@ -157,22 +60,21 @@ const createRequestFactory = (environment)=>{
|
|
|
157
60
|
httpMethodDecider: args[3],
|
|
158
61
|
fetch: args[4],
|
|
159
62
|
requestId: args[5],
|
|
160
|
-
|
|
63
|
+
hooks: args[6]
|
|
161
64
|
};
|
|
162
|
-
const { path, method, port, httpMethodDecider = 'functionName', fetch = environment.originFetch, domain, requestId = 'default',
|
|
65
|
+
const { path, method, port, httpMethodDecider = 'functionName', fetch = environment.originFetch, domain, requestId = 'default', hooks } = options;
|
|
163
66
|
const getFinalPath = compile(path, {
|
|
164
67
|
encode: encodeURIComponent
|
|
165
68
|
});
|
|
166
69
|
const keyNames = extractPathParamNames(path);
|
|
167
70
|
const send = (...senderArgs)=>{
|
|
168
|
-
const
|
|
169
|
-
const
|
|
71
|
+
const context = startRequest(requestId, hooks);
|
|
72
|
+
const fetcher = realRequest.get(requestId) || fetch;
|
|
170
73
|
let body;
|
|
171
74
|
let headers;
|
|
172
75
|
let url;
|
|
173
76
|
if ('inputParams' === httpMethodDecider) {
|
|
174
77
|
const configDomain = domainMap.get(requestId);
|
|
175
|
-
if ('default' !== requestId && isEmptyDomain(configDomain)) throw new ProducerDomainNotConfiguredError(requestId);
|
|
176
78
|
url = environment.resolveRequestUrl({
|
|
177
79
|
configDomain,
|
|
178
80
|
domain,
|
|
@@ -183,7 +85,7 @@ const createRequestFactory = (environment)=>{
|
|
|
183
85
|
headers = {
|
|
184
86
|
'Content-Type': 'application/json'
|
|
185
87
|
};
|
|
186
|
-
headers =
|
|
88
|
+
headers = prepareHeaders(headers, context, hooks);
|
|
187
89
|
} else {
|
|
188
90
|
const payload = 'object' == typeof senderArgs[senderArgs.length - 1] ? senderArgs[senderArgs.length - 1] : {};
|
|
189
91
|
payload.params = payload.params || {};
|
|
@@ -201,7 +103,7 @@ const createRequestFactory = (environment)=>{
|
|
|
201
103
|
headers = payload.headers ? {
|
|
202
104
|
...payload.headers
|
|
203
105
|
} : {};
|
|
204
|
-
headers =
|
|
106
|
+
headers = prepareHeaders(headers, context, hooks);
|
|
205
107
|
if (payload.data) {
|
|
206
108
|
headers['Content-Type'] = 'application/json';
|
|
207
109
|
body = 'object' == typeof payload.data ? JSON.stringify(payload.data) : payload.body;
|
|
@@ -214,7 +116,6 @@ const createRequestFactory = (environment)=>{
|
|
|
214
116
|
body = !isServerTarget && "u" > typeof URLSearchParams && payload.formUrlencoded instanceof URLSearchParams ? payload.formUrlencoded : 'object' == typeof payload.formUrlencoded ? stringify(payload.formUrlencoded) : payload.formUrlencoded;
|
|
215
117
|
}
|
|
216
118
|
const configDomain = domainMap.get(requestId);
|
|
217
|
-
if ('default' !== requestId && isEmptyDomain(configDomain)) throw new ProducerDomainNotConfiguredError(requestId);
|
|
218
119
|
url = environment.resolveRequestUrl({
|
|
219
120
|
configDomain,
|
|
220
121
|
domain,
|
|
@@ -223,20 +124,12 @@ const createRequestFactory = (environment)=>{
|
|
|
223
124
|
});
|
|
224
125
|
}
|
|
225
126
|
if (!isServerTarget) writeHeader(headers, 'accept', "application/json,*/*;q=0.8");
|
|
226
|
-
if (isServerTarget) {
|
|
227
|
-
if (void 0 === readHeader(headers, TRACEPARENT_HEADER)) {
|
|
228
|
-
const incomingTraceparent = firstHeaderValue(readHeader(incomingHeaders, TRACEPARENT_HEADER));
|
|
229
|
-
if ('string' == typeof incomingTraceparent) writeHeader(headers, TRACEPARENT_HEADER, incomingTraceparent);
|
|
230
|
-
}
|
|
231
|
-
if (void 0 === readHeader(headers, TRACEPARENT_HEADER) && operationContext?.traceparent) writeHeader(headers, TRACEPARENT_HEADER, operationContext.traceparent);
|
|
232
|
-
}
|
|
233
|
-
attachEnvelopeHeaderIfRequired(headers, requestId, url, incomingHeaders);
|
|
234
|
-
attachSecuredOperationHeaders(headers, requestId, method, path, operationContext);
|
|
235
127
|
if ('get' === method.toLowerCase()) body = void 0;
|
|
236
128
|
if (isServerTarget) writeHeader(headers, 'accept', "application/json,*/*;q=0.8");
|
|
237
|
-
return
|
|
129
|
+
return dispatch({
|
|
130
|
+
...context,
|
|
131
|
+
path,
|
|
238
132
|
requestId,
|
|
239
|
-
target: environment.target,
|
|
240
133
|
method,
|
|
241
134
|
url,
|
|
242
135
|
init: {
|
|
@@ -244,19 +137,19 @@ const createRequestFactory = (environment)=>{
|
|
|
244
137
|
body,
|
|
245
138
|
headers
|
|
246
139
|
},
|
|
247
|
-
fetcher: fetcher
|
|
248
|
-
|
|
249
|
-
});
|
|
140
|
+
fetcher: fetcher
|
|
141
|
+
}, hooks);
|
|
250
142
|
};
|
|
251
143
|
const sender = isServerTarget ? send : async (...senderArgs)=>send(...senderArgs);
|
|
252
144
|
return sender;
|
|
253
145
|
};
|
|
254
|
-
const createUploader = ({ path, domain, requestId = 'default',
|
|
146
|
+
const createUploader = ({ path, domain, requestId = 'default', hooks })=>{
|
|
255
147
|
const getUploadPath = isServerTarget ? void 0 : compile(path, {
|
|
256
148
|
encode: encodeURIComponent
|
|
257
149
|
});
|
|
258
150
|
const sender = (...args)=>{
|
|
259
|
-
const
|
|
151
|
+
const context = startRequest(requestId, hooks);
|
|
152
|
+
const fetcher = realRequest.get(requestId) || environment.originFetch;
|
|
260
153
|
const { body, headers: uploadHeaders, params } = getUploadPayload(args);
|
|
261
154
|
let headers = {
|
|
262
155
|
...uploadHeaders
|
|
@@ -268,13 +161,11 @@ const createRequestFactory = (environment)=>{
|
|
|
268
161
|
domain,
|
|
269
162
|
path: finalPath
|
|
270
163
|
});
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
return executeWithResilience({
|
|
164
|
+
headers = prepareHeaders(headers, context, hooks);
|
|
165
|
+
return dispatch({
|
|
166
|
+
...context,
|
|
167
|
+
path,
|
|
276
168
|
requestId,
|
|
277
|
-
target: environment.target,
|
|
278
169
|
method: 'POST',
|
|
279
170
|
url: finalURL,
|
|
280
171
|
init: {
|
|
@@ -282,9 +173,8 @@ const createRequestFactory = (environment)=>{
|
|
|
282
173
|
body,
|
|
283
174
|
headers
|
|
284
175
|
},
|
|
285
|
-
fetcher: fetcher
|
|
286
|
-
|
|
287
|
-
});
|
|
176
|
+
fetcher: fetcher
|
|
177
|
+
}, hooks);
|
|
288
178
|
};
|
|
289
179
|
return sender;
|
|
290
180
|
};
|
|
@@ -294,4 +184,4 @@ const createRequestFactory = (environment)=>{
|
|
|
294
184
|
createUploader
|
|
295
185
|
};
|
|
296
186
|
};
|
|
297
|
-
export { createRequestFactory };
|
|
187
|
+
export { createRequestFactory, extractPathParamNames };
|
package/dist/esm-node/types.mjs
CHANGED
|
@@ -1,11 +1 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
const BFF_ENVELOPE_HEADER = 'x-modernjs-bff-envelope';
|
|
3
|
-
const BFF_OPERATION_CONTEXT_HEADER = 'x-operation-id';
|
|
4
|
-
const BFF_OPERATION_CONTEXT_DETAIL_HEADER = 'x-modernjs-bff-operation-context';
|
|
5
|
-
const BFF_DEFAULT_PROTECTED_IDENTITY_HEADERS = [
|
|
6
|
-
'x-tenant-id',
|
|
7
|
-
'x-subject-id',
|
|
8
|
-
'x-user-id',
|
|
9
|
-
BFF_OPERATION_CONTEXT_HEADER
|
|
10
|
-
];
|
|
11
|
-
export { BFF_DEFAULT_PROTECTED_IDENTITY_HEADERS, BFF_ENVELOPE_HEADER, BFF_OPERATION_CONTEXT_DETAIL_HEADER, BFF_OPERATION_CONTEXT_HEADER };
|
package/dist/types/browser.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
export
|
|
2
|
-
export declare const configure: (options: import("./types").IOptions<typeof fetch>) => void, createRequest: import("./types").RequestCreator<typeof fetch>, createUploader: import("./types").UploadCreator;
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './traceparent';
|
|
5
|
-
export * from './types';
|
|
1
|
+
export declare const createClient: () => import("./types.js").RequestClient<typeof fetch>;
|
|
2
|
+
export declare const configure: (options: import("./types.js").IOptions<typeof fetch>) => void, createRequest: import("./types.js").RequestCreator<typeof fetch>, createUploader: import("./types.js").UploadCreator;
|
|
3
|
+
export * from './types.js';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const findHeaderKey: (headers: Record<string, any>, header: string) => string | undefined;
|
|
2
|
+
export declare const readHeader: (headers: Record<string, any>, header: string) => any;
|
|
3
|
+
export declare const writeHeader: (headers: Record<string, any>, header: string, value: unknown) => void;
|
package/dist/types/node.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
export
|
|
2
|
-
export declare const configure: (options: import("./types").IOptions<typeof fetch>) => void, createRequest: import("./types").RequestCreator<typeof fetch>, createUploader: import("./types").UploadCreator;
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './traceparent';
|
|
5
|
-
export * from './types';
|
|
1
|
+
export declare const createClient: () => import("./types.js").RequestClient<typeof fetch>;
|
|
2
|
+
export declare const configure: (options: import("./types.js").IOptions<typeof fetch>) => void, createRequest: import("./types.js").RequestCreator<typeof fetch>, createUploader: import("./types.js").UploadCreator;
|
|
3
|
+
export * from './types.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
type HeaderMap =
|
|
1
|
+
import type { RequestClient, RequestHeaders, RequestTarget } from './types.js';
|
|
2
|
+
type HeaderMap = RequestHeaders;
|
|
3
3
|
type RequestUrlOptions = {
|
|
4
4
|
configDomain: string | undefined;
|
|
5
5
|
domain: string | undefined;
|
|
@@ -12,18 +12,14 @@ type UploadUrlOptions = {
|
|
|
12
12
|
path: string;
|
|
13
13
|
};
|
|
14
14
|
type RequestFactoryEnvironment<F> = {
|
|
15
|
-
target:
|
|
15
|
+
target: RequestTarget;
|
|
16
16
|
getFetch: () => F;
|
|
17
17
|
originFetch: F;
|
|
18
18
|
readIncomingHeaders: () => HeaderMap;
|
|
19
|
-
resolveSourceOrigin: (incomingHeaders: HeaderMap) => string | undefined;
|
|
20
19
|
createInputParamsBody: (args: any[]) => any;
|
|
21
20
|
resolveRequestUrl: (options: RequestUrlOptions) => string;
|
|
22
21
|
resolveUploadUrl: (options: UploadUrlOptions) => string;
|
|
23
22
|
};
|
|
24
|
-
export declare const
|
|
25
|
-
|
|
26
|
-
createRequest: RequestCreator<F>;
|
|
27
|
-
createUploader: UploadCreator;
|
|
28
|
-
};
|
|
23
|
+
export declare const extractPathParamNames: (path: string) => string[];
|
|
24
|
+
export declare const createRequestFactory: <F>(environment: RequestFactoryEnvironment<F>) => RequestClient<F>;
|
|
29
25
|
export {};
|
package/dist/types/types.d.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
export declare const BFF_ENVELOPE_HEADER = "x-modernjs-bff-envelope";
|
|
2
|
-
export declare const BFF_OPERATION_CONTEXT_HEADER = "x-operation-id";
|
|
3
|
-
export declare const BFF_OPERATION_CONTEXT_DETAIL_HEADER = "x-modernjs-bff-operation-context";
|
|
4
|
-
export declare const BFF_DEFAULT_PROTECTED_IDENTITY_HEADERS: readonly ['x-tenant-id', 'x-subject-id', 'x-user-id', "x-operation-id"];
|
|
5
1
|
export type BFFRequestPayload = {
|
|
6
2
|
params?: Record<string, any>;
|
|
7
3
|
query?: Record<string, any>;
|
|
@@ -17,124 +13,40 @@ export type Sender<F = typeof fetch> = ((...args: any[]) => Promise<any>) & {
|
|
|
17
13
|
fetch?: F;
|
|
18
14
|
};
|
|
19
15
|
export type HttpMethodDecider = 'functionName' | 'inputParams';
|
|
20
|
-
|
|
16
|
+
/** Target selected by the native browser/server entry. */
|
|
17
|
+
export type RequestTarget = 'server' | 'browser';
|
|
18
|
+
export type RequestHeaders = Record<string, any>;
|
|
19
|
+
export type RequestFetcher = (url: string, init: Record<string, any>) => Promise<any>;
|
|
20
|
+
/** A snapshot of the native configuration at the start of one send. */
|
|
21
|
+
export type RequestStartContext = {
|
|
21
22
|
requestId: string;
|
|
23
|
+
target: RequestTarget;
|
|
24
|
+
incomingHeaders: RequestHeaders;
|
|
25
|
+
configured: boolean;
|
|
26
|
+
configuredDomain: string | undefined;
|
|
27
|
+
};
|
|
28
|
+
/** Header maps before native allowlisted forwarding is merged into the request. */
|
|
29
|
+
export type RequestHeadersContext = RequestStartContext & {
|
|
30
|
+
headers: RequestHeaders;
|
|
31
|
+
forwardedHeaders: RequestHeaders;
|
|
22
32
|
allowedHeaders: string[];
|
|
23
|
-
incomingHeaders: Record<string, any>;
|
|
24
33
|
};
|
|
25
|
-
export type
|
|
26
|
-
|
|
27
|
-
requestId: string;
|
|
28
|
-
sourceOrigin?: string;
|
|
29
|
-
targetOrigin?: string;
|
|
30
|
-
target: 'server' | 'browser';
|
|
31
|
-
};
|
|
32
|
-
export type AllowCrossOriginEnvelope = boolean | ((options: AllowCrossOriginEnvelopeOptions) => boolean);
|
|
33
|
-
export type TransportTarget = 'server' | 'browser';
|
|
34
|
-
export type RetryDecisionContext = {
|
|
35
|
-
requestId: string;
|
|
36
|
-
target: TransportTarget;
|
|
37
|
-
method: string;
|
|
38
|
-
url: string;
|
|
39
|
-
attempt: number;
|
|
40
|
-
maxAttempts: number;
|
|
41
|
-
error: unknown;
|
|
42
|
-
statusCode?: number;
|
|
43
|
-
};
|
|
44
|
-
export type RetryBackoffOptions = {
|
|
45
|
-
retries?: number;
|
|
46
|
-
baseDelayMs?: number;
|
|
47
|
-
maxDelayMs?: number;
|
|
48
|
-
jitterRatio?: number;
|
|
49
|
-
retryableStatusCodes?: number[];
|
|
50
|
-
shouldRetry?: (context: RetryDecisionContext) => boolean;
|
|
51
|
-
};
|
|
52
|
-
export type DegradedModeReason = 'timeout' | 'retry' | 'retry_exhausted';
|
|
53
|
-
export type DegradedModeEvent = {
|
|
54
|
-
requestId: string;
|
|
55
|
-
target: TransportTarget;
|
|
34
|
+
export type RequestDispatchContext = RequestStartContext & {
|
|
35
|
+
path: string;
|
|
56
36
|
method: string;
|
|
57
37
|
url: string;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
export type
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
};
|
|
71
|
-
export type IdentityBindingViolationReason = 'client_override_blocked' | 'client_override_rejected';
|
|
72
|
-
export type IdentityBindingViolation = {
|
|
73
|
-
requestId: string;
|
|
74
|
-
target: TransportTarget;
|
|
75
|
-
header: string;
|
|
76
|
-
reason: IdentityBindingViolationReason;
|
|
77
|
-
attemptedValue?: unknown;
|
|
78
|
-
derivedValue?: unknown;
|
|
79
|
-
};
|
|
80
|
-
export type DeriveIdentityHeadersOptions = {
|
|
81
|
-
requestId: string;
|
|
82
|
-
target: TransportTarget;
|
|
83
|
-
incomingHeaders: Record<string, any>;
|
|
84
|
-
protectedHeaders: string[];
|
|
85
|
-
};
|
|
86
|
-
export type IdentityBindingOptions = {
|
|
87
|
-
enabled?: boolean;
|
|
88
|
-
strict?: boolean;
|
|
89
|
-
protectedHeaders?: string[];
|
|
90
|
-
deriveHeaders?: (options: DeriveIdentityHeadersOptions) => Record<string, any> | void;
|
|
91
|
-
onViolation?: (violation: IdentityBindingViolation) => void;
|
|
92
|
-
};
|
|
93
|
-
export type OperationContractViolationReason = 'missing_schema_hash' | 'missing_operation_version';
|
|
94
|
-
export type OperationContractViolation = {
|
|
95
|
-
requestId: string;
|
|
96
|
-
target: TransportTarget;
|
|
97
|
-
operationId: string;
|
|
98
|
-
reason: OperationContractViolationReason;
|
|
99
|
-
routePath?: string;
|
|
100
|
-
method?: string;
|
|
101
|
-
schemaHash?: string;
|
|
102
|
-
operationVersion?: number;
|
|
103
|
-
};
|
|
104
|
-
export type CrossProjectOperationContract = {
|
|
105
|
-
schemaHash?: string;
|
|
106
|
-
operationVersion?: number;
|
|
107
|
-
};
|
|
108
|
-
export type CrossProjectPolicyViolationReason = 'missing_envelope' | 'invalid_envelope' | 'missing_request_id' | 'namespace_not_allowed' | 'missing_operation_context' | 'operation_context_mismatch' | 'missing_operation_context_details' | 'invalid_operation_context_details' | 'operation_context_details_request_id_mismatch' | 'missing_operation_schema_hash' | 'missing_operation_version' | 'unknown_operation_contract' | 'operation_schema_hash_mismatch' | 'operation_version_mismatch' | 'producer_identity_mismatch';
|
|
109
|
-
export type CrossProjectPolicyViolation = {
|
|
110
|
-
code: 'BFF_CROSS_PROJECT_POLICY_DENIED';
|
|
111
|
-
reason: CrossProjectPolicyViolationReason;
|
|
112
|
-
message: string;
|
|
113
|
-
status: number;
|
|
114
|
-
};
|
|
115
|
-
export type OperationContractOptions = {
|
|
116
|
-
enabled?: boolean;
|
|
117
|
-
strict?: boolean;
|
|
118
|
-
requireSchemaHash?: boolean;
|
|
119
|
-
requireOperationVersion?: boolean;
|
|
120
|
-
onViolation?: (violation: OperationContractViolation) => void;
|
|
121
|
-
};
|
|
122
|
-
export type OperationContextSource = 'client' | 'server' | 'generated-client' | 'effect-adapter' | 'data-platform' | 'unknown';
|
|
123
|
-
export type OperationContext = {
|
|
124
|
-
requestId?: string;
|
|
125
|
-
operationId?: string;
|
|
126
|
-
routePath?: string;
|
|
127
|
-
method?: string;
|
|
128
|
-
schemaHash?: string;
|
|
129
|
-
operationVersion?: number;
|
|
130
|
-
locale?: string;
|
|
131
|
-
traceparent?: string;
|
|
132
|
-
traceId?: string;
|
|
133
|
-
spanId?: string;
|
|
134
|
-
source?: OperationContextSource;
|
|
135
|
-
scope?: Record<string, unknown>;
|
|
136
|
-
sessionClaims?: Record<string, unknown>;
|
|
137
|
-
attributes?: Record<string, unknown>;
|
|
38
|
+
init: {
|
|
39
|
+
method: string;
|
|
40
|
+
body: any;
|
|
41
|
+
headers: RequestHeaders;
|
|
42
|
+
};
|
|
43
|
+
fetcher: RequestFetcher;
|
|
44
|
+
};
|
|
45
|
+
/** Optional, instance-local callbacks around native request construction. */
|
|
46
|
+
export type RequestHooks = {
|
|
47
|
+
onStart?: (context: RequestStartContext) => void;
|
|
48
|
+
prepareHeaders?: (context: RequestHeadersContext) => void;
|
|
49
|
+
dispatch?: (context: RequestDispatchContext) => Promise<any>;
|
|
138
50
|
};
|
|
139
51
|
export type RequestCreatorOptions<F = typeof fetch> = {
|
|
140
52
|
path: string;
|
|
@@ -144,32 +56,31 @@ export type RequestCreatorOptions<F = typeof fetch> = {
|
|
|
144
56
|
fetch?: F;
|
|
145
57
|
domain?: string;
|
|
146
58
|
requestId?: string;
|
|
147
|
-
|
|
59
|
+
hooks?: RequestHooks;
|
|
148
60
|
};
|
|
149
61
|
export type RequestCreator<F = typeof fetch> = {
|
|
150
62
|
(options: RequestCreatorOptions<F>): Sender;
|
|
151
|
-
(path: string, method: string, port: number, httpMethodDecider?: HttpMethodDecider, fetch?: F, requestId?: string,
|
|
63
|
+
(path: string, method: string, port: number, httpMethodDecider?: HttpMethodDecider, fetch?: F, requestId?: string, hooks?: RequestHooks): Sender;
|
|
152
64
|
};
|
|
153
65
|
export type UploadCreatorOptions = {
|
|
154
66
|
path: string;
|
|
155
67
|
domain?: string;
|
|
156
68
|
requestId?: string;
|
|
157
|
-
|
|
69
|
+
hooks?: RequestHooks;
|
|
158
70
|
};
|
|
159
71
|
export type UploadCreator = (options: UploadCreatorOptions) => Sender;
|
|
160
72
|
export type IOptions<F = typeof fetch> = {
|
|
161
73
|
request?: F;
|
|
162
74
|
interceptor?: (request: F) => F;
|
|
163
75
|
allowedHeaders?: string[];
|
|
164
|
-
resolveHeaders?: ResolveHeaders;
|
|
165
|
-
transport?: TransportResilienceOptions;
|
|
166
|
-
requireEnvelope?: boolean;
|
|
167
|
-
allowCrossOriginEnvelope?: AllowCrossOriginEnvelope;
|
|
168
|
-
identityBinding?: IdentityBindingOptions;
|
|
169
|
-
operationContract?: OperationContractOptions;
|
|
170
76
|
setDomain?: (ops?: {
|
|
171
|
-
target:
|
|
77
|
+
target: RequestTarget;
|
|
172
78
|
requestId?: string;
|
|
173
79
|
}) => string;
|
|
174
80
|
requestId?: string;
|
|
175
81
|
};
|
|
82
|
+
export type RequestClient<F = typeof fetch> = {
|
|
83
|
+
configure: (options: IOptions<F>) => void;
|
|
84
|
+
createRequest: RequestCreator<F>;
|
|
85
|
+
createUploader: UploadCreator;
|
|
86
|
+
};
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"modern",
|
|
18
18
|
"modern.js"
|
|
19
19
|
],
|
|
20
|
-
"version": "3.
|
|
20
|
+
"version": "3.9.0-ultramodern.10",
|
|
21
21
|
"modern:source": "./src/node.ts",
|
|
22
22
|
"types": "./dist/types/browser.d.ts",
|
|
23
23
|
"main": "./dist/cjs/node.js",
|
|
@@ -65,18 +65,18 @@
|
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.
|
|
69
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.
|
|
68
|
+
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.9.0-ultramodern.10",
|
|
69
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.10",
|
|
70
70
|
"@swc/helpers": "^0.5.23",
|
|
71
71
|
"encoding": "^0.1.13",
|
|
72
72
|
"path-to-regexp": "^8.4.2",
|
|
73
|
-
"qs": "^6.
|
|
73
|
+
"qs": "^6.16.0"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.
|
|
77
|
-
"@rslib/core": "0.
|
|
76
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.10",
|
|
77
|
+
"@rslib/core": "1.0.0",
|
|
78
78
|
"@scripts/rstest-config": "2.66.0",
|
|
79
|
-
"@types/node": "^26.
|
|
79
|
+
"@types/node": "^26.4.1",
|
|
80
80
|
"@types/qs": "^6.15.1",
|
|
81
81
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
82
82
|
"nock": "^14.0.17",
|