@bleedingdev/modern-js-create-request 3.2.0-ultramodern.5 → 3.2.0-ultramodern.51

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.
@@ -52,6 +52,25 @@ function parseTraceparent(traceparent) {
52
52
  spanId: spanId.toLowerCase()
53
53
  };
54
54
  }
55
+ function createOperationContextSnapshot(operationContext, safeContext) {
56
+ if (!operationContext) return;
57
+ const snapshot = {
58
+ ...operationContext,
59
+ ...safeContext.locale || operationContext?.locale ? {
60
+ locale: safeContext.locale || operationContext?.locale
61
+ } : {},
62
+ ...safeContext.traceparent || operationContext?.traceparent ? {
63
+ traceparent: safeContext.traceparent || operationContext?.traceparent
64
+ } : {},
65
+ ...safeContext.traceId || operationContext?.traceId ? {
66
+ traceId: safeContext.traceId || operationContext?.traceId
67
+ } : {},
68
+ ...safeContext.spanId || operationContext?.spanId ? {
69
+ spanId: safeContext.spanId || operationContext?.spanId
70
+ } : {}
71
+ };
72
+ return Object.keys(snapshot).some((key)=>void 0 !== snapshot[key]) ? snapshot : void 0;
73
+ }
55
74
  function createRequestContextSnapshot(input = {}) {
56
75
  const locale = readString(input.locale) || readString(readHeader(input.headers, BFF_LOCALE_HEADER));
57
76
  const traceparent = readString(input.traceparent) || readString(input.operationContext?.traceparent) || readString(readHeader(input.headers, BFF_TRACEPARENT_HEADER));
@@ -62,6 +81,18 @@ function createRequestContextSnapshot(input = {}) {
62
81
  const headers = {};
63
82
  if (locale) headers[BFF_LOCALE_HEADER] = locale;
64
83
  if (traceparent) headers[BFF_TRACEPARENT_HEADER] = traceparent;
84
+ const operationContext = createOperationContextSnapshot(input.operationContext, {
85
+ ...locale ? {
86
+ locale
87
+ } : {},
88
+ ...traceparent ? {
89
+ traceparent
90
+ } : {},
91
+ ...parsedTraceparent ? {
92
+ traceId: parsedTraceparent.traceId,
93
+ spanId: parsedTraceparent.spanId
94
+ } : {}
95
+ });
65
96
  return {
66
97
  headers,
67
98
  ...locale ? {
@@ -73,6 +104,9 @@ function createRequestContextSnapshot(input = {}) {
73
104
  ...parsedTraceparent ? {
74
105
  traceId: parsedTraceparent.traceId,
75
106
  spanId: parsedTraceparent.spanId
107
+ } : {},
108
+ ...operationContext ? {
109
+ operationContext
76
110
  } : {}
77
111
  };
78
112
  }
@@ -21,6 +21,25 @@ function parseTraceparent(traceparent) {
21
21
  spanId: spanId.toLowerCase()
22
22
  };
23
23
  }
24
+ function createOperationContextSnapshot(operationContext, safeContext) {
25
+ if (!operationContext) return;
26
+ const snapshot = {
27
+ ...operationContext,
28
+ ...safeContext.locale || operationContext?.locale ? {
29
+ locale: safeContext.locale || operationContext?.locale
30
+ } : {},
31
+ ...safeContext.traceparent || operationContext?.traceparent ? {
32
+ traceparent: safeContext.traceparent || operationContext?.traceparent
33
+ } : {},
34
+ ...safeContext.traceId || operationContext?.traceId ? {
35
+ traceId: safeContext.traceId || operationContext?.traceId
36
+ } : {},
37
+ ...safeContext.spanId || operationContext?.spanId ? {
38
+ spanId: safeContext.spanId || operationContext?.spanId
39
+ } : {}
40
+ };
41
+ return Object.keys(snapshot).some((key)=>void 0 !== snapshot[key]) ? snapshot : void 0;
42
+ }
24
43
  function createRequestContextSnapshot(input = {}) {
25
44
  const locale = readString(input.locale) || readString(readHeader(input.headers, BFF_LOCALE_HEADER));
26
45
  const traceparent = readString(input.traceparent) || readString(input.operationContext?.traceparent) || readString(readHeader(input.headers, BFF_TRACEPARENT_HEADER));
@@ -31,6 +50,18 @@ function createRequestContextSnapshot(input = {}) {
31
50
  const headers = {};
32
51
  if (locale) headers[BFF_LOCALE_HEADER] = locale;
33
52
  if (traceparent) headers[BFF_TRACEPARENT_HEADER] = traceparent;
53
+ const operationContext = createOperationContextSnapshot(input.operationContext, {
54
+ ...locale ? {
55
+ locale
56
+ } : {},
57
+ ...traceparent ? {
58
+ traceparent
59
+ } : {},
60
+ ...parsedTraceparent ? {
61
+ traceId: parsedTraceparent.traceId,
62
+ spanId: parsedTraceparent.spanId
63
+ } : {}
64
+ });
34
65
  return {
35
66
  headers,
36
67
  ...locale ? {
@@ -42,6 +73,9 @@ function createRequestContextSnapshot(input = {}) {
42
73
  ...parsedTraceparent ? {
43
74
  traceId: parsedTraceparent.traceId,
44
75
  spanId: parsedTraceparent.spanId
76
+ } : {},
77
+ ...operationContext ? {
78
+ operationContext
45
79
  } : {}
46
80
  };
47
81
  }
@@ -22,6 +22,25 @@ function parseTraceparent(traceparent) {
22
22
  spanId: spanId.toLowerCase()
23
23
  };
24
24
  }
25
+ function createOperationContextSnapshot(operationContext, safeContext) {
26
+ if (!operationContext) return;
27
+ const snapshot = {
28
+ ...operationContext,
29
+ ...safeContext.locale || operationContext?.locale ? {
30
+ locale: safeContext.locale || operationContext?.locale
31
+ } : {},
32
+ ...safeContext.traceparent || operationContext?.traceparent ? {
33
+ traceparent: safeContext.traceparent || operationContext?.traceparent
34
+ } : {},
35
+ ...safeContext.traceId || operationContext?.traceId ? {
36
+ traceId: safeContext.traceId || operationContext?.traceId
37
+ } : {},
38
+ ...safeContext.spanId || operationContext?.spanId ? {
39
+ spanId: safeContext.spanId || operationContext?.spanId
40
+ } : {}
41
+ };
42
+ return Object.keys(snapshot).some((key)=>void 0 !== snapshot[key]) ? snapshot : void 0;
43
+ }
25
44
  function createRequestContextSnapshot(input = {}) {
26
45
  const locale = readString(input.locale) || readString(readHeader(input.headers, BFF_LOCALE_HEADER));
27
46
  const traceparent = readString(input.traceparent) || readString(input.operationContext?.traceparent) || readString(readHeader(input.headers, BFF_TRACEPARENT_HEADER));
@@ -32,6 +51,18 @@ function createRequestContextSnapshot(input = {}) {
32
51
  const headers = {};
33
52
  if (locale) headers[BFF_LOCALE_HEADER] = locale;
34
53
  if (traceparent) headers[BFF_TRACEPARENT_HEADER] = traceparent;
54
+ const operationContext = createOperationContextSnapshot(input.operationContext, {
55
+ ...locale ? {
56
+ locale
57
+ } : {},
58
+ ...traceparent ? {
59
+ traceparent
60
+ } : {},
61
+ ...parsedTraceparent ? {
62
+ traceId: parsedTraceparent.traceId,
63
+ spanId: parsedTraceparent.spanId
64
+ } : {}
65
+ });
35
66
  return {
36
67
  headers,
37
68
  ...locale ? {
@@ -43,6 +74,9 @@ function createRequestContextSnapshot(input = {}) {
43
74
  ...parsedTraceparent ? {
44
75
  traceId: parsedTraceparent.traceId,
45
76
  spanId: parsedTraceparent.spanId
77
+ } : {},
78
+ ...operationContext ? {
79
+ operationContext
46
80
  } : {}
47
81
  };
48
82
  }
@@ -0,0 +1,28 @@
1
+ import type { IdentityBindingViolation, IOptions, OperationContractViolation, RequestCreator, UploadCreator } from './types';
2
+ export declare class ProducerClientNotInitializedError extends Error {
3
+ readonly code = "BFF_PRODUCER_CLIENT_NOT_INITIALIZED";
4
+ constructor(requestId: string);
5
+ }
6
+ export declare class ProducerDomainNotConfiguredError extends Error {
7
+ readonly code = "BFF_PRODUCER_DOMAIN_NOT_CONFIGURED";
8
+ constructor(requestId: string);
9
+ }
10
+ export declare class CrossOriginEnvelopePolicyError extends Error {
11
+ readonly code = "BFF_CROSS_ORIGIN_ENVELOPE_NOT_ALLOWED";
12
+ constructor(requestId: string, sourceOrigin?: string, targetOrigin?: string);
13
+ }
14
+ export declare class IdentityBindingViolationError extends Error {
15
+ readonly code = "BFF_IDENTITY_BINDING_VIOLATION";
16
+ readonly violation: IdentityBindingViolation;
17
+ constructor(violation: IdentityBindingViolation);
18
+ }
19
+ export declare class OperationContractViolationError extends Error {
20
+ readonly code = "BFF_OPERATION_CONTRACT_VIOLATION";
21
+ readonly violation: OperationContractViolation;
22
+ constructor(violation: OperationContractViolation);
23
+ }
24
+ export declare const configure: (options: IOptions) => void;
25
+ export declare const createRequest: RequestCreator;
26
+ export declare const createUploader: UploadCreator;
27
+ export * from './requestContext';
28
+ export * from './types';
@@ -0,0 +1,2 @@
1
+ declare const handleRes: (res: Response) => Promise<any>;
2
+ export { handleRes };
@@ -0,0 +1,29 @@
1
+ import type { IdentityBindingViolation, IOptions, OperationContractViolation, RequestCreator, UploadCreator } from './types';
2
+ type Fetch = typeof fetch;
3
+ export declare class ProducerClientNotInitializedError extends Error {
4
+ readonly code = "BFF_PRODUCER_CLIENT_NOT_INITIALIZED";
5
+ constructor(requestId: string);
6
+ }
7
+ export declare class ProducerDomainNotConfiguredError extends Error {
8
+ readonly code = "BFF_PRODUCER_DOMAIN_NOT_CONFIGURED";
9
+ constructor(requestId: string);
10
+ }
11
+ export declare class CrossOriginEnvelopePolicyError extends Error {
12
+ readonly code = "BFF_CROSS_ORIGIN_ENVELOPE_NOT_ALLOWED";
13
+ constructor(requestId: string, sourceOrigin?: string, targetOrigin?: string);
14
+ }
15
+ export declare class IdentityBindingViolationError extends Error {
16
+ readonly code = "BFF_IDENTITY_BINDING_VIOLATION";
17
+ readonly violation: IdentityBindingViolation;
18
+ constructor(violation: IdentityBindingViolation);
19
+ }
20
+ export declare class OperationContractViolationError extends Error {
21
+ readonly code = "BFF_OPERATION_CONTRACT_VIOLATION";
22
+ readonly violation: OperationContractViolation;
23
+ constructor(violation: OperationContractViolation);
24
+ }
25
+ export declare const configure: (options: IOptions<Fetch>) => void;
26
+ export declare const createRequest: RequestCreator<Fetch>;
27
+ export declare const createUploader: UploadCreator;
28
+ export * from './requestContext';
29
+ export * from './types';
@@ -0,0 +1 @@
1
+ export { parse, stringify } from 'qs';
@@ -0,0 +1,19 @@
1
+ import type { OperationContext } from './types';
2
+ export declare const BFF_LOCALE_HEADER = "accept-language";
3
+ export declare const BFF_TRACEPARENT_HEADER = "traceparent";
4
+ export type RequestContextInput = {
5
+ headers?: Record<string, unknown>;
6
+ locale?: string;
7
+ traceparent?: string;
8
+ operationContext?: OperationContext;
9
+ };
10
+ export type RequestContextSnapshot = {
11
+ headers: Record<string, string>;
12
+ locale?: string;
13
+ traceparent?: string;
14
+ traceId?: string;
15
+ spanId?: string;
16
+ operationContext?: OperationContext;
17
+ };
18
+ export declare function createRequestContextSnapshot(input?: RequestContextInput): RequestContextSnapshot;
19
+ export declare function createRequestContextHeaders(input?: RequestContextInput): Record<string, string>;
@@ -0,0 +1,12 @@
1
+ import type { TransportResilienceOptions, TransportTarget } from './types';
2
+ type ExecuteWithResilienceOptions = {
3
+ requestId: string;
4
+ target: TransportTarget;
5
+ method: string;
6
+ url: string;
7
+ init: Record<string, any>;
8
+ fetcher: (...args: any[]) => Promise<any>;
9
+ transport?: TransportResilienceOptions;
10
+ };
11
+ export declare const executeWithResilience: ({ requestId, target, method, url, init, fetcher, transport, }: ExecuteWithResilienceOptions) => Promise<any>;
12
+ export {};
@@ -0,0 +1,174 @@
1
+ import type { HttpMethodDecider } from '@modern-js/types';
2
+ export declare const BFF_ENVELOPE_HEADER = "x-modernjs-bff-envelope";
3
+ export declare const BFF_OPERATION_CONTEXT_HEADER = "x-operation-id";
4
+ export declare const BFF_OPERATION_CONTEXT_DETAIL_HEADER = "x-modernjs-bff-operation-context";
5
+ export declare const BFF_DEFAULT_PROTECTED_IDENTITY_HEADERS: readonly ['x-tenant-id', 'x-subject-id', 'x-user-id', "x-operation-id"];
6
+ export type BFFRequestPayload = {
7
+ params?: Record<string, any>;
8
+ query?: Record<string, any>;
9
+ body?: string;
10
+ formUrlencoded?: string | Record<string, any> | URLSearchParams;
11
+ formData?: FormData;
12
+ data?: Record<string, any>;
13
+ headers?: Record<string, any>;
14
+ cookies?: Record<string, any>;
15
+ files?: Record<string, any>;
16
+ };
17
+ export type Sender<F = typeof fetch> = ((...args: any[]) => Promise<any>) & {
18
+ fetch?: F;
19
+ };
20
+ export type ResolveHeadersOptions = {
21
+ requestId: string;
22
+ allowedHeaders: string[];
23
+ incomingHeaders: Record<string, any>;
24
+ };
25
+ export type ResolveHeaders = (options: ResolveHeadersOptions) => Record<string, any> | void;
26
+ export type AllowCrossOriginEnvelopeOptions = {
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;
56
+ method: string;
57
+ url: string;
58
+ reason: DegradedModeReason;
59
+ attempt: number;
60
+ maxAttempts: number;
61
+ timeoutMs?: number;
62
+ backoffMs?: number;
63
+ statusCode?: number;
64
+ error?: unknown;
65
+ };
66
+ export type TransportResilienceOptions = {
67
+ timeoutMs?: number;
68
+ retry?: RetryBackoffOptions;
69
+ onDegraded?: (event: DegradedModeEvent) => void;
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';
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>;
138
+ };
139
+ export type RequestCreatorOptions<F = typeof fetch> = {
140
+ path: string;
141
+ method: string;
142
+ port: number;
143
+ httpMethodDecider?: HttpMethodDecider;
144
+ fetch?: F;
145
+ domain?: string;
146
+ requestId?: string;
147
+ operationContext?: OperationContext;
148
+ };
149
+ export type RequestCreator<F = typeof fetch> = {
150
+ (options: RequestCreatorOptions<F>): Sender;
151
+ (path: string, method: string, port: number, httpMethodDecider?: HttpMethodDecider, fetch?: F, requestId?: string, operationContext?: OperationContext): Sender;
152
+ };
153
+ export type UploadCreatorOptions = {
154
+ path: string;
155
+ domain?: string;
156
+ requestId?: string;
157
+ };
158
+ export type UploadCreator = (options: UploadCreatorOptions) => Sender;
159
+ export type IOptions<F = typeof fetch> = {
160
+ request?: F;
161
+ interceptor?: (request: F) => F;
162
+ allowedHeaders?: string[];
163
+ resolveHeaders?: ResolveHeaders;
164
+ transport?: TransportResilienceOptions;
165
+ requireEnvelope?: boolean;
166
+ allowCrossOriginEnvelope?: AllowCrossOriginEnvelope;
167
+ identityBinding?: IdentityBindingOptions;
168
+ operationContract?: OperationContractOptions;
169
+ setDomain?: (ops?: {
170
+ target: 'server' | 'browser';
171
+ requestId?: string;
172
+ }) => string;
173
+ requestId?: string;
174
+ };
@@ -0,0 +1,5 @@
1
+ export declare const getUploadPayload: (args: any) => {
2
+ body: any;
3
+ headers: Record<string, any> | undefined;
4
+ params: Record<string, any> | undefined;
5
+ };
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.2.0-ultramodern.5",
20
+ "version": "3.2.0-ultramodern.51",
21
21
  "modern:source": "./src/node.ts",
22
22
  "types": "./dist/types/browser.d.ts",
23
23
  "main": "./dist/cjs/node.js",
@@ -60,18 +60,18 @@
60
60
  "@swc/helpers": "^0.5.21",
61
61
  "encoding": "^0.1.13",
62
62
  "path-to-regexp": "^8.4.2",
63
- "qs": "^6.15.1",
64
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.5",
65
- "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.2.0-ultramodern.5"
63
+ "qs": "^6.15.2",
64
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.51",
65
+ "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.2.0-ultramodern.51"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@rslib/core": "0.21.5",
69
- "@types/node": "^25.8.0",
69
+ "@types/node": "^25.9.1",
70
70
  "@types/qs": "^6.15.1",
71
- "@typescript/native-preview": "7.0.0-dev.20260516.1",
71
+ "@typescript/native-preview": "7.0.0-dev.20260527.2",
72
72
  "nock": "^14.0.15",
73
- "@scripts/rstest-config": "2.66.0",
74
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.2.0-ultramodern.5"
73
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.2.0-ultramodern.51",
74
+ "@scripts/rstest-config": "2.66.0"
75
75
  },
76
76
  "sideEffects": false,
77
77
  "publishConfig": {