@bleedingdev/modern-js-bff-core 3.5.0-ultramodern.35 → 3.5.0-ultramodern.37

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.
@@ -137,7 +137,8 @@ const createParityBffConfig = ()=>({
137
137
  enabled: true,
138
138
  allowedNamespaces: [
139
139
  shared_js_namespaceObject.PARITY_REQUEST_ID
140
- ]
140
+ ],
141
+ allowClientAssertedNamespace: true
141
142
  }
142
143
  });
143
144
  const getParityContracts = ()=>(0, operationContracts_js_namespaceObject.buildOperationContractMap)({
package/dist/cjs/index.js CHANGED
@@ -9,9 +9,6 @@ var __webpack_modules__ = {
9
9
  "./client" (module) {
10
10
  module.exports = require("./client/index.js");
11
11
  },
12
- "./contracts/eventContracts" (module) {
13
- module.exports = require("./contracts/eventContracts.js");
14
- },
15
12
  "./errors/http" (module) {
16
13
  module.exports = require("./errors/http.js");
17
14
  },
@@ -117,26 +114,10 @@ var __webpack_exports__ = {};
117
114
  "Api"
118
115
  ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_client__rspack_import_2[__rspack_import_key];
119
116
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
120
- var _contracts_eventContracts__rspack_import_3 = __webpack_require__("./contracts/eventContracts");
121
- var __rspack_reexport = {};
122
- for(const __rspack_import_key in _contracts_eventContracts__rspack_import_3)if ([
123
- "HttpError",
124
- "registerPaths",
125
- "createStorage",
126
- "isWithMetaHandler",
127
- "default",
128
- "HANDLER_WITH_META",
129
- "ValidationError",
130
- "getRelativeRuntimePath",
131
- "INPUT_PARAMS_DECIDER",
132
- "isInputParamsDeciderHandler",
133
- "Api"
134
- ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_contracts_eventContracts__rspack_import_3[__rspack_import_key];
135
- __webpack_require__.d(__webpack_exports__, __rspack_reexport);
136
- var _errors_http__rspack_import_4 = __webpack_require__("./errors/http");
137
- var _operators_http__rspack_import_5 = __webpack_require__("./operators/http");
117
+ var _errors_http__rspack_import_3 = __webpack_require__("./errors/http");
118
+ var _operators_http__rspack_import_4 = __webpack_require__("./operators/http");
138
119
  var __rspack_reexport = {};
139
- for(const __rspack_import_key in _operators_http__rspack_import_5)if ([
120
+ for(const __rspack_import_key in _operators_http__rspack_import_4)if ([
140
121
  "HttpError",
141
122
  "registerPaths",
142
123
  "createStorage",
@@ -148,11 +129,11 @@ var __webpack_exports__ = {};
148
129
  "INPUT_PARAMS_DECIDER",
149
130
  "isInputParamsDeciderHandler",
150
131
  "Api"
151
- ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_operators_http__rspack_import_5[__rspack_import_key];
132
+ ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_operators_http__rspack_import_4[__rspack_import_key];
152
133
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
153
- var _router__rspack_import_6 = __webpack_require__("./router");
134
+ var _router__rspack_import_5 = __webpack_require__("./router");
154
135
  var __rspack_reexport = {};
155
- for(const __rspack_import_key in _router__rspack_import_6)if ([
136
+ for(const __rspack_import_key in _router__rspack_import_5)if ([
156
137
  "HttpError",
157
138
  "registerPaths",
158
139
  "createStorage",
@@ -164,11 +145,11 @@ var __webpack_exports__ = {};
164
145
  "INPUT_PARAMS_DECIDER",
165
146
  "isInputParamsDeciderHandler",
166
147
  "Api"
167
- ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_router__rspack_import_6[__rspack_import_key];
148
+ ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_router__rspack_import_5[__rspack_import_key];
168
149
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
169
- var _security_crossProjectPolicy__rspack_import_7 = __webpack_require__("./security/crossProjectPolicy");
150
+ var _security_crossProjectPolicy__rspack_import_6 = __webpack_require__("./security/crossProjectPolicy");
170
151
  var __rspack_reexport = {};
171
- for(const __rspack_import_key in _security_crossProjectPolicy__rspack_import_7)if ([
152
+ for(const __rspack_import_key in _security_crossProjectPolicy__rspack_import_6)if ([
172
153
  "HttpError",
173
154
  "registerPaths",
174
155
  "createStorage",
@@ -180,11 +161,11 @@ var __webpack_exports__ = {};
180
161
  "INPUT_PARAMS_DECIDER",
181
162
  "isInputParamsDeciderHandler",
182
163
  "Api"
183
- ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_security_crossProjectPolicy__rspack_import_7[__rspack_import_key];
164
+ ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_security_crossProjectPolicy__rspack_import_6[__rspack_import_key];
184
165
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
185
- var _security_operationContracts__rspack_import_8 = __webpack_require__("./security/operationContracts");
166
+ var _security_operationContracts__rspack_import_7 = __webpack_require__("./security/operationContracts");
186
167
  var __rspack_reexport = {};
187
- for(const __rspack_import_key in _security_operationContracts__rspack_import_8)if ([
168
+ for(const __rspack_import_key in _security_operationContracts__rspack_import_7)if ([
188
169
  "HttpError",
189
170
  "registerPaths",
190
171
  "createStorage",
@@ -196,11 +177,11 @@ var __webpack_exports__ = {};
196
177
  "INPUT_PARAMS_DECIDER",
197
178
  "isInputParamsDeciderHandler",
198
179
  "Api"
199
- ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_security_operationContracts__rspack_import_8[__rspack_import_key];
180
+ ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_security_operationContracts__rspack_import_7[__rspack_import_key];
200
181
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
201
- var _security_resolveCrossProjectPolicy__rspack_import_9 = __webpack_require__("./security/resolveCrossProjectPolicy");
182
+ var _security_resolveCrossProjectPolicy__rspack_import_8 = __webpack_require__("./security/resolveCrossProjectPolicy");
202
183
  var __rspack_reexport = {};
203
- for(const __rspack_import_key in _security_resolveCrossProjectPolicy__rspack_import_9)if ([
184
+ for(const __rspack_import_key in _security_resolveCrossProjectPolicy__rspack_import_8)if ([
204
185
  "HttpError",
205
186
  "registerPaths",
206
187
  "createStorage",
@@ -212,11 +193,11 @@ var __webpack_exports__ = {};
212
193
  "INPUT_PARAMS_DECIDER",
213
194
  "isInputParamsDeciderHandler",
214
195
  "Api"
215
- ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_security_resolveCrossProjectPolicy__rspack_import_9[__rspack_import_key];
196
+ ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_security_resolveCrossProjectPolicy__rspack_import_8[__rspack_import_key];
216
197
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
217
- var _types__rspack_import_10 = __webpack_require__("./types");
198
+ var _types__rspack_import_9 = __webpack_require__("./types");
218
199
  var __rspack_reexport = {};
219
- for(const __rspack_import_key in _types__rspack_import_10)if ([
200
+ for(const __rspack_import_key in _types__rspack_import_9)if ([
220
201
  "HttpError",
221
202
  "registerPaths",
222
203
  "createStorage",
@@ -228,20 +209,20 @@ var __webpack_exports__ = {};
228
209
  "INPUT_PARAMS_DECIDER",
229
210
  "isInputParamsDeciderHandler",
230
211
  "Api"
231
- ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_types__rspack_import_10[__rspack_import_key];
212
+ ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_types__rspack_import_9[__rspack_import_key];
232
213
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
233
- var _utils__rspack_import_11 = __webpack_require__("./utils?637c");
214
+ var _utils__rspack_import_10 = __webpack_require__("./utils?637c");
234
215
  __webpack_require__.d(__webpack_exports__, {
235
216
  Api: ()=>_api__rspack_import_1.Api,
236
- HANDLER_WITH_META: ()=>_utils__rspack_import_11.HANDLER_WITH_META,
237
- HttpError: ()=>_errors_http__rspack_import_4.HttpError,
238
- INPUT_PARAMS_DECIDER: ()=>_utils__rspack_import_11.INPUT_PARAMS_DECIDER,
239
- ValidationError: ()=>_errors_http__rspack_import_4.ValidationError,
240
- createStorage: ()=>_utils__rspack_import_11.createStorage,
241
- getRelativeRuntimePath: ()=>_utils__rspack_import_11.getRelativeRuntimePath,
242
- isInputParamsDeciderHandler: ()=>_utils__rspack_import_11.isInputParamsDeciderHandler,
243
- isWithMetaHandler: ()=>_utils__rspack_import_11.isWithMetaHandler,
244
- registerPaths: ()=>_utils__rspack_import_11.registerPaths
217
+ HANDLER_WITH_META: ()=>_utils__rspack_import_10.HANDLER_WITH_META,
218
+ HttpError: ()=>_errors_http__rspack_import_3.HttpError,
219
+ INPUT_PARAMS_DECIDER: ()=>_utils__rspack_import_10.INPUT_PARAMS_DECIDER,
220
+ ValidationError: ()=>_errors_http__rspack_import_3.ValidationError,
221
+ createStorage: ()=>_utils__rspack_import_10.createStorage,
222
+ getRelativeRuntimePath: ()=>_utils__rspack_import_10.getRelativeRuntimePath,
223
+ isInputParamsDeciderHandler: ()=>_utils__rspack_import_10.isInputParamsDeciderHandler,
224
+ isWithMetaHandler: ()=>_utils__rspack_import_10.isWithMetaHandler,
225
+ registerPaths: ()=>_utils__rspack_import_10.registerPaths
245
226
  });
246
227
  })();
247
228
  exports.Api = __webpack_exports__.Api;
@@ -31,7 +31,7 @@ const BFF_ENVELOPE_HEADER = 'x-modernjs-bff-envelope';
31
31
  const BFF_OPERATION_CONTEXT_HEADER = 'x-operation-id';
32
32
  const BFF_OPERATION_CONTEXT_DETAIL_HEADER = 'x-modernjs-bff-operation-context';
33
33
  const DEFAULT_DENY_STATUS = 403;
34
- const NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE = 'cross-project namespace allowlist requires verifyProducerIdentity in production';
34
+ const NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE = 'cross-project namespace allowlist requires verifyProducerIdentity';
35
35
  let hasWarnedAdvisoryNamespaceAllowlist = false;
36
36
  const normalizeHeaderName = (headerName, fallback)=>(headerName || fallback).trim().toLowerCase();
37
37
  const normalizeStatusCode = (statusCode)=>{
@@ -53,11 +53,10 @@ const createViolation = (reason, message, status)=>({
53
53
  message,
54
54
  status
55
55
  });
56
- const isProductionMode = ()=>"u" > typeof process && process.env?.NODE_ENV === 'production';
57
56
  const warnAdvisoryNamespaceAllowlist = ()=>{
58
57
  if (hasWarnedAdvisoryNamespaceAllowlist) return;
59
58
  hasWarnedAdvisoryNamespaceAllowlist = true;
60
- console.warn(`[Modern.js BFF] ${NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE}. Non-production requests will continue to evaluate allowlist against client-asserted requestId namespaces only.`);
59
+ console.warn(`[Modern.js BFF] ${NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE}. allowClientAssertedNamespace=true will continue to evaluate allowlist against client-asserted requestId namespaces only.`);
61
60
  };
62
61
  const createCrossProjectPolicyEvaluationState = (headers, policy)=>({
63
62
  headers,
@@ -69,6 +68,7 @@ const createCrossProjectPolicyEvaluationState = (headers, policy)=>({
69
68
  requireOperationSchemaHash: policy.requireOperationSchemaHash ?? true,
70
69
  requireOperationVersion: policy.requireOperationVersion ?? true,
71
70
  allowUnknownOperations: policy.allowUnknownOperations ?? false,
71
+ allowClientAssertedNamespace: policy.allowClientAssertedNamespace ?? false,
72
72
  verifyProducerIdentity: 'function' == typeof policy.verifyProducerIdentity ? policy.verifyProducerIdentity : void 0,
73
73
  allowedNamespaces: (policy.allowedNamespaces || []).map((item)=>item.trim().toLowerCase()).filter(Boolean),
74
74
  envelopeHeader: normalizeHeaderName(policy.envelopeHeader, BFF_ENVELOPE_HEADER),
@@ -81,7 +81,7 @@ const createCrossProjectPolicyEvaluationState = (headers, policy)=>({
81
81
  });
82
82
  const checkNamespaceAllowlistVerifier = (state)=>{
83
83
  if (state.allowedNamespaces.length > 0 && void 0 === state.verifyProducerIdentity) {
84
- if (isProductionMode()) return createViolation('producer_identity_mismatch', NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE, state.status);
84
+ if (!state.allowClientAssertedNamespace) return createViolation('producer_identity_mismatch', NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE, state.status);
85
85
  warnAdvisoryNamespaceAllowlist();
86
86
  }
87
87
  };
@@ -99,7 +99,8 @@ const createParityBffConfig = ()=>({
99
99
  enabled: true,
100
100
  allowedNamespaces: [
101
101
  PARITY_REQUEST_ID
102
- ]
102
+ ],
103
+ allowClientAssertedNamespace: true
103
104
  }
104
105
  });
105
106
  const getParityContracts = ()=>buildOperationContractMap({
@@ -1,6 +1,5 @@
1
1
  export * from "./adapter-kit/index.mjs";
2
2
  export * from "./client/index.mjs";
3
- export * from "./contracts/eventContracts.mjs";
4
3
  export * from "./operators/http.mjs";
5
4
  export * from "./router/index.mjs";
6
5
  export * from "./security/crossProjectPolicy.mjs";
@@ -2,7 +2,7 @@ const BFF_ENVELOPE_HEADER = 'x-modernjs-bff-envelope';
2
2
  const BFF_OPERATION_CONTEXT_HEADER = 'x-operation-id';
3
3
  const BFF_OPERATION_CONTEXT_DETAIL_HEADER = 'x-modernjs-bff-operation-context';
4
4
  const DEFAULT_DENY_STATUS = 403;
5
- const NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE = 'cross-project namespace allowlist requires verifyProducerIdentity in production';
5
+ const NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE = 'cross-project namespace allowlist requires verifyProducerIdentity';
6
6
  let hasWarnedAdvisoryNamespaceAllowlist = false;
7
7
  const normalizeHeaderName = (headerName, fallback)=>(headerName || fallback).trim().toLowerCase();
8
8
  const normalizeStatusCode = (statusCode)=>{
@@ -24,11 +24,10 @@ const createViolation = (reason, message, status)=>({
24
24
  message,
25
25
  status
26
26
  });
27
- const isProductionMode = ()=>"u" > typeof process && process.env?.NODE_ENV === 'production';
28
27
  const warnAdvisoryNamespaceAllowlist = ()=>{
29
28
  if (hasWarnedAdvisoryNamespaceAllowlist) return;
30
29
  hasWarnedAdvisoryNamespaceAllowlist = true;
31
- console.warn(`[Modern.js BFF] ${NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE}. Non-production requests will continue to evaluate allowlist against client-asserted requestId namespaces only.`);
30
+ console.warn(`[Modern.js BFF] ${NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE}. allowClientAssertedNamespace=true will continue to evaluate allowlist against client-asserted requestId namespaces only.`);
32
31
  };
33
32
  const createCrossProjectPolicyEvaluationState = (headers, policy)=>({
34
33
  headers,
@@ -40,6 +39,7 @@ const createCrossProjectPolicyEvaluationState = (headers, policy)=>({
40
39
  requireOperationSchemaHash: policy.requireOperationSchemaHash ?? true,
41
40
  requireOperationVersion: policy.requireOperationVersion ?? true,
42
41
  allowUnknownOperations: policy.allowUnknownOperations ?? false,
42
+ allowClientAssertedNamespace: policy.allowClientAssertedNamespace ?? false,
43
43
  verifyProducerIdentity: 'function' == typeof policy.verifyProducerIdentity ? policy.verifyProducerIdentity : void 0,
44
44
  allowedNamespaces: (policy.allowedNamespaces || []).map((item)=>item.trim().toLowerCase()).filter(Boolean),
45
45
  envelopeHeader: normalizeHeaderName(policy.envelopeHeader, BFF_ENVELOPE_HEADER),
@@ -52,7 +52,7 @@ const createCrossProjectPolicyEvaluationState = (headers, policy)=>({
52
52
  });
53
53
  const checkNamespaceAllowlistVerifier = (state)=>{
54
54
  if (state.allowedNamespaces.length > 0 && void 0 === state.verifyProducerIdentity) {
55
- if (isProductionMode()) return createViolation('producer_identity_mismatch', NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE, state.status);
55
+ if (!state.allowClientAssertedNamespace) return createViolation('producer_identity_mismatch', NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE, state.status);
56
56
  warnAdvisoryNamespaceAllowlist();
57
57
  }
58
58
  };
@@ -4,7 +4,7 @@ import { HttpMetadata } from "../types.mjs";
4
4
  import { __webpack_require__ } from "../rslib-runtime.mjs";
5
5
  import * as __rspack_external_zod from "zod";
6
6
  __webpack_require__.add({
7
- 6284 (module) {
7
+ 7347 (module) {
8
8
  module.exports = __rspack_external_zod;
9
9
  }
10
10
  });
@@ -29,7 +29,7 @@ let cachedZodToJSONSchema;
29
29
  const resolveZodToJSONSchema = ()=>{
30
30
  if (void 0 !== cachedZodToJSONSchema) return cachedZodToJSONSchema;
31
31
  try {
32
- const zod = __webpack_require__(6284);
32
+ const zod = __webpack_require__(7347);
33
33
  const candidate = zod?.toJSONSchema ?? zod?.z?.toJSONSchema;
34
34
  cachedZodToJSONSchema = 'function' == typeof candidate ? candidate : null;
35
35
  } catch {
@@ -100,7 +100,8 @@ const createParityBffConfig = ()=>({
100
100
  enabled: true,
101
101
  allowedNamespaces: [
102
102
  PARITY_REQUEST_ID
103
- ]
103
+ ],
104
+ allowClientAssertedNamespace: true
104
105
  }
105
106
  });
106
107
  const getParityContracts = ()=>buildOperationContractMap({
@@ -1,7 +1,6 @@
1
1
  import "node:module";
2
2
  export * from "./adapter-kit/index.mjs";
3
3
  export * from "./client/index.mjs";
4
- export * from "./contracts/eventContracts.mjs";
5
4
  export * from "./operators/http.mjs";
6
5
  export * from "./router/index.mjs";
7
6
  export * from "./security/crossProjectPolicy.mjs";
@@ -3,7 +3,7 @@ const BFF_ENVELOPE_HEADER = 'x-modernjs-bff-envelope';
3
3
  const BFF_OPERATION_CONTEXT_HEADER = 'x-operation-id';
4
4
  const BFF_OPERATION_CONTEXT_DETAIL_HEADER = 'x-modernjs-bff-operation-context';
5
5
  const DEFAULT_DENY_STATUS = 403;
6
- const NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE = 'cross-project namespace allowlist requires verifyProducerIdentity in production';
6
+ const NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE = 'cross-project namespace allowlist requires verifyProducerIdentity';
7
7
  let hasWarnedAdvisoryNamespaceAllowlist = false;
8
8
  const normalizeHeaderName = (headerName, fallback)=>(headerName || fallback).trim().toLowerCase();
9
9
  const normalizeStatusCode = (statusCode)=>{
@@ -25,11 +25,10 @@ const createViolation = (reason, message, status)=>({
25
25
  message,
26
26
  status
27
27
  });
28
- const isProductionMode = ()=>"u" > typeof process && process.env?.NODE_ENV === 'production';
29
28
  const warnAdvisoryNamespaceAllowlist = ()=>{
30
29
  if (hasWarnedAdvisoryNamespaceAllowlist) return;
31
30
  hasWarnedAdvisoryNamespaceAllowlist = true;
32
- console.warn(`[Modern.js BFF] ${NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE}. Non-production requests will continue to evaluate allowlist against client-asserted requestId namespaces only.`);
31
+ console.warn(`[Modern.js BFF] ${NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE}. allowClientAssertedNamespace=true will continue to evaluate allowlist against client-asserted requestId namespaces only.`);
33
32
  };
34
33
  const createCrossProjectPolicyEvaluationState = (headers, policy)=>({
35
34
  headers,
@@ -41,6 +40,7 @@ const createCrossProjectPolicyEvaluationState = (headers, policy)=>({
41
40
  requireOperationSchemaHash: policy.requireOperationSchemaHash ?? true,
42
41
  requireOperationVersion: policy.requireOperationVersion ?? true,
43
42
  allowUnknownOperations: policy.allowUnknownOperations ?? false,
43
+ allowClientAssertedNamespace: policy.allowClientAssertedNamespace ?? false,
44
44
  verifyProducerIdentity: 'function' == typeof policy.verifyProducerIdentity ? policy.verifyProducerIdentity : void 0,
45
45
  allowedNamespaces: (policy.allowedNamespaces || []).map((item)=>item.trim().toLowerCase()).filter(Boolean),
46
46
  envelopeHeader: normalizeHeaderName(policy.envelopeHeader, BFF_ENVELOPE_HEADER),
@@ -53,7 +53,7 @@ const createCrossProjectPolicyEvaluationState = (headers, policy)=>({
53
53
  });
54
54
  const checkNamespaceAllowlistVerifier = (state)=>{
55
55
  if (state.allowedNamespaces.length > 0 && void 0 === state.verifyProducerIdentity) {
56
- if (isProductionMode()) return createViolation('producer_identity_mismatch', NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE, state.status);
56
+ if (!state.allowClientAssertedNamespace) return createViolation('producer_identity_mismatch', NAMESPACE_ALLOWLIST_REQUIRES_VERIFIER_MESSAGE, state.status);
57
57
  warnAdvisoryNamespaceAllowlist();
58
58
  }
59
59
  };
@@ -15,6 +15,7 @@ export declare const createParityBffConfig: () => {
15
15
  crossProjectPolicy: {
16
16
  enabled: boolean;
17
17
  allowedNamespaces: string[];
18
+ allowClientAssertedNamespace: boolean;
18
19
  };
19
20
  };
20
21
  export declare const createAdapterParityScenarios: () => AdapterParityScenario[];
@@ -26,7 +27,7 @@ export type ParityHttpResponse = {
26
27
  body: unknown;
27
28
  text: string;
28
29
  };
29
- export type AdapterParityResult = {
30
+ type AdapterParityResult = {
30
31
  status: number;
31
32
  payload: unknown;
32
33
  };
@@ -2,7 +2,6 @@ export * from './adapter-kit';
2
2
  export { Api } from './api';
3
3
  export * from './client';
4
4
  export type * from './compatible';
5
- export * from './contracts/eventContracts';
6
5
  export { HttpError, ValidationError } from './errors/http';
7
6
  export * from './operators/http';
8
7
  export * from './router';
@@ -10,16 +10,16 @@
10
10
  * authorization boundary: any caller can echo an allowed `requestId` and a
11
11
  * matching operation context.
12
12
  *
13
- * To use `allowedNamespaces` in production, supply
13
+ * To use `allowedNamespaces`, supply
14
14
  * {@link CrossProjectPolicyConfig.verifyProducerIdentity}: a server-side
15
15
  * hook that derives the producer namespace from a VERIFIED channel (mTLS
16
16
  * peer identity, gateway-authenticated JWT claims, service-mesh headers
17
- * stripped at the edge, ...). Production requests fail closed when a
18
- * namespace allowlist is configured without this hook. In non-production,
19
- * the evaluator logs a one-time warning and keeps the legacy advisory
20
- * behavior: the client-asserted namespace must match the allowlist. When the
21
- * hook is present, the client-asserted namespace must match the verified
22
- * namespace and the allowlist is checked against the verified value.
17
+ * stripped at the edge, ...). Requests fail closed when a namespace allowlist
18
+ * is configured without this hook unless `allowClientAssertedNamespace` is
19
+ * explicitly enabled. That escape hatch keeps legacy local/demo ergonomics:
20
+ * the client-asserted namespace must match the allowlist. When the hook is
21
+ * present, the client-asserted namespace must match the verified namespace
22
+ * and the allowlist is checked against the verified value.
23
23
  *
24
24
  * Client-side counterparts in `@modern-js/create-request` (identity binding,
25
25
  * operation contract validation) are developer-experience aids that fail
@@ -48,6 +48,12 @@ export interface CrossProjectPolicyConfig {
48
48
  requireOperationSchemaHash?: boolean;
49
49
  requireOperationVersion?: boolean;
50
50
  allowedNamespaces?: string[];
51
+ /**
52
+ * Explicit local/demo escape hatch for legacy clients that only provide
53
+ * client-built requestId namespaces. Defaults to false. Enabling this keeps
54
+ * `allowedNamespaces` advisory and must not be used as authorization.
55
+ */
56
+ allowClientAssertedNamespace?: boolean;
51
57
  envelopeHeader?: string;
52
58
  operationContextHeader?: string;
53
59
  operationContextDetailHeader?: string;
@@ -63,9 +69,9 @@ export interface CrossProjectPolicyConfig {
63
69
  * against the verified value instead of the client-asserted one. Returning
64
70
  * `undefined` (identity could not be verified) denies the request.
65
71
  *
66
- * In production, `allowedNamespaces` requires this hook and fails closed
67
- * without it. In non-production, namespace checks without this hook remain
68
- * advisory only see the module-level threat model.
72
+ * By default, `allowedNamespaces` requires this hook and fails closed
73
+ * without it. Set `allowClientAssertedNamespace` only for local/demo
74
+ * ergonomics where advisory client-asserted namespace checks are acceptable.
69
75
  */
70
76
  verifyProducerIdentity?: (headers: Record<string, unknown>) => string | undefined;
71
77
  }
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.5.0-ultramodern.35",
20
+ "version": "3.5.0-ultramodern.37",
21
21
  "types": "./dist/types/index.d.ts",
22
22
  "main": "./dist/cjs/index.js",
23
23
  "exports": {
@@ -35,19 +35,19 @@
35
35
  "@swc/helpers": "^0.5.23",
36
36
  "koa-compose": "^4.1.0",
37
37
  "reflect-metadata": "^0.2.2",
38
- "type-fest": "5.7.0",
39
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.35"
38
+ "type-fest": "5.8.0",
39
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.37"
40
40
  },
41
41
  "devDependencies": {
42
- "@rslib/core": "0.23.1",
42
+ "@rslib/core": "0.23.2",
43
43
  "@types/koa-compose": "^3.2.9",
44
- "@types/node": "^26.0.1",
45
- "@typescript/native-preview": "7.0.0-dev.20260628.1",
44
+ "@types/node": "^26.1.1",
45
+ "@typescript/native-preview": "7.0.0-dev.20260707.2",
46
46
  "tsconfig-paths": "^4.2.0",
47
47
  "zod": "^4.4.3",
48
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.35",
49
- "@scripts/rstest-config": "2.66.0",
50
- "@modern-js/bff-runtime": "npm:@bleedingdev/modern-js-bff-runtime@3.5.0-ultramodern.35"
48
+ "@modern-js/bff-runtime": "npm:@bleedingdev/modern-js-bff-runtime@3.5.0-ultramodern.37",
49
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.37",
50
+ "@scripts/rstest-config": "2.66.0"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "tsconfig-paths": "^4.2.0",
@@ -1,72 +0,0 @@
1
- "use strict";
2
- var __webpack_require__ = {};
3
- (()=>{
4
- __webpack_require__.d = (exports1, getters, values)=>{
5
- var define = (defs, kind)=>{
6
- for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
- enumerable: true,
8
- [kind]: defs[key]
9
- });
10
- };
11
- define(getters, "get");
12
- define(values, "value");
13
- };
14
- })();
15
- (()=>{
16
- __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
17
- })();
18
- (()=>{
19
- __webpack_require__.r = (exports1)=>{
20
- if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
21
- value: 'Module'
22
- });
23
- Object.defineProperty(exports1, '__esModule', {
24
- value: true
25
- });
26
- };
27
- })();
28
- var __webpack_exports__ = {};
29
- __webpack_require__.r(__webpack_exports__);
30
- const defineEventContract = (input)=>{
31
- const normalizedName = input.name.trim();
32
- if (!normalizedName) throw new Error('Event contract name must be non-empty');
33
- if (!Number.isFinite(input.version) || input.version <= 0) throw new Error('Event contract version must be a positive number');
34
- if (!input.schemaHash || !input.schemaHash.trim()) throw new Error('Event contract schemaHash must be non-empty');
35
- return {
36
- name: normalizedName,
37
- version: Math.floor(input.version),
38
- schemaHash: input.schemaHash.trim(),
39
- description: input.description
40
- };
41
- };
42
- const createEventEnvelope = (contract, payload, meta)=>({
43
- name: contract.name,
44
- version: contract.version,
45
- schemaHash: contract.schemaHash,
46
- timestamp: Date.now(),
47
- payload,
48
- ...meta ? {
49
- meta
50
- } : {}
51
- });
52
- const isEventEnvelope = (value)=>{
53
- if (!value || 'object' != typeof value || Array.isArray(value)) return false;
54
- const candidate = value;
55
- return 'string' == typeof candidate.name && candidate.name.length > 0 && 'number' == typeof candidate.version && candidate.version > 0 && 'string' == typeof candidate.schemaHash && candidate.schemaHash.length > 0 && 'number' == typeof candidate.timestamp && Number.isFinite(candidate.timestamp) && 'payload' in candidate;
56
- };
57
- __webpack_require__.d(__webpack_exports__, {}, {
58
- createEventEnvelope: createEventEnvelope,
59
- defineEventContract: defineEventContract,
60
- isEventEnvelope: isEventEnvelope
61
- });
62
- exports.createEventEnvelope = __webpack_exports__.createEventEnvelope;
63
- exports.defineEventContract = __webpack_exports__.defineEventContract;
64
- exports.isEventEnvelope = __webpack_exports__.isEventEnvelope;
65
- for(var __rspack_i in __webpack_exports__)if (-1 === [
66
- "createEventEnvelope",
67
- "defineEventContract",
68
- "isEventEnvelope"
69
- ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
70
- Object.defineProperty(exports, '__esModule', {
71
- value: true
72
- });
@@ -1,28 +0,0 @@
1
- const defineEventContract = (input)=>{
2
- const normalizedName = input.name.trim();
3
- if (!normalizedName) throw new Error('Event contract name must be non-empty');
4
- if (!Number.isFinite(input.version) || input.version <= 0) throw new Error('Event contract version must be a positive number');
5
- if (!input.schemaHash || !input.schemaHash.trim()) throw new Error('Event contract schemaHash must be non-empty');
6
- return {
7
- name: normalizedName,
8
- version: Math.floor(input.version),
9
- schemaHash: input.schemaHash.trim(),
10
- description: input.description
11
- };
12
- };
13
- const createEventEnvelope = (contract, payload, meta)=>({
14
- name: contract.name,
15
- version: contract.version,
16
- schemaHash: contract.schemaHash,
17
- timestamp: Date.now(),
18
- payload,
19
- ...meta ? {
20
- meta
21
- } : {}
22
- });
23
- const isEventEnvelope = (value)=>{
24
- if (!value || 'object' != typeof value || Array.isArray(value)) return false;
25
- const candidate = value;
26
- return 'string' == typeof candidate.name && candidate.name.length > 0 && 'number' == typeof candidate.version && candidate.version > 0 && 'string' == typeof candidate.schemaHash && candidate.schemaHash.length > 0 && 'number' == typeof candidate.timestamp && Number.isFinite(candidate.timestamp) && 'payload' in candidate;
27
- };
28
- export { createEventEnvelope, defineEventContract, isEventEnvelope };
@@ -1,29 +0,0 @@
1
- import "node:module";
2
- const defineEventContract = (input)=>{
3
- const normalizedName = input.name.trim();
4
- if (!normalizedName) throw new Error('Event contract name must be non-empty');
5
- if (!Number.isFinite(input.version) || input.version <= 0) throw new Error('Event contract version must be a positive number');
6
- if (!input.schemaHash || !input.schemaHash.trim()) throw new Error('Event contract schemaHash must be non-empty');
7
- return {
8
- name: normalizedName,
9
- version: Math.floor(input.version),
10
- schemaHash: input.schemaHash.trim(),
11
- description: input.description
12
- };
13
- };
14
- const createEventEnvelope = (contract, payload, meta)=>({
15
- name: contract.name,
16
- version: contract.version,
17
- schemaHash: contract.schemaHash,
18
- timestamp: Date.now(),
19
- payload,
20
- ...meta ? {
21
- meta
22
- } : {}
23
- });
24
- const isEventEnvelope = (value)=>{
25
- if (!value || 'object' != typeof value || Array.isArray(value)) return false;
26
- const candidate = value;
27
- return 'string' == typeof candidate.name && candidate.name.length > 0 && 'number' == typeof candidate.version && candidate.version > 0 && 'string' == typeof candidate.schemaHash && candidate.schemaHash.length > 0 && 'number' == typeof candidate.timestamp && Number.isFinite(candidate.timestamp) && 'payload' in candidate;
28
- };
29
- export { createEventEnvelope, defineEventContract, isEventEnvelope };
@@ -1,22 +0,0 @@
1
- export type EventContract<Name extends string = string, Payload = unknown> = {
2
- name: Name;
3
- version: number;
4
- schemaHash: string;
5
- description?: string;
6
- };
7
- export type EventEnvelope<TContract extends EventContract = EventContract, TMeta extends Record<string, unknown> = Record<string, unknown>> = {
8
- name: TContract['name'];
9
- version: TContract['version'];
10
- schemaHash: TContract['schemaHash'];
11
- timestamp: number;
12
- payload: TContract extends EventContract<string, infer TPayload> ? TPayload : unknown;
13
- meta?: TMeta;
14
- };
15
- export declare const defineEventContract: <Name extends string, Payload = unknown>(input: {
16
- name: Name;
17
- version: number;
18
- schemaHash: string;
19
- description?: string;
20
- }) => EventContract<Name, Payload>;
21
- export declare const createEventEnvelope: <TContract extends EventContract, TMeta extends Record<string, unknown> = Record<string, unknown>>(contract: TContract, payload: TContract extends EventContract<string, infer TPayload> ? TPayload : unknown, meta?: TMeta) => EventEnvelope<TContract, TMeta>;
22
- export declare const isEventEnvelope: (value: unknown) => value is EventEnvelope<EventContract, Record<string, unknown>>;