@bleedingdev/modern-js-bff-core 3.5.0-ultramodern.3 → 3.5.0-ultramodern.31
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/adapter-kit/index.js +6 -2
- package/dist/cjs/adapter-kit/parity-scenarios/cross-project-denial.js +55 -0
- package/dist/cjs/adapter-kit/parity-scenarios/envelope.js +128 -0
- package/dist/cjs/adapter-kit/parity-scenarios/operation-context.js +158 -0
- package/dist/cjs/adapter-kit/parity-scenarios/schema.js +109 -0
- package/dist/cjs/adapter-kit/parity-scenarios/shared.js +71 -0
- package/dist/cjs/adapter-kit/parity.js +24 -367
- package/dist/cjs/security/crossProjectPolicy.js +123 -62
- package/dist/esm/adapter-kit/index.mjs +6 -2
- package/dist/esm/adapter-kit/parity-scenarios/cross-project-denial.mjs +17 -0
- package/dist/esm/adapter-kit/parity-scenarios/envelope.mjs +90 -0
- package/dist/esm/adapter-kit/parity-scenarios/operation-context.mjs +117 -0
- package/dist/esm/adapter-kit/parity-scenarios/schema.mjs +71 -0
- package/dist/esm/adapter-kit/parity-scenarios/shared.mjs +21 -0
- package/dist/esm/adapter-kit/parity.mjs +17 -360
- package/dist/esm/security/crossProjectPolicy.mjs +123 -62
- package/dist/esm-node/adapter-kit/index.mjs +6 -2
- package/dist/esm-node/adapter-kit/parity-scenarios/cross-project-denial.mjs +18 -0
- package/dist/esm-node/adapter-kit/parity-scenarios/envelope.mjs +91 -0
- package/dist/esm-node/adapter-kit/parity-scenarios/operation-context.mjs +118 -0
- package/dist/esm-node/adapter-kit/parity-scenarios/schema.mjs +72 -0
- package/dist/esm-node/adapter-kit/parity-scenarios/shared.mjs +22 -0
- package/dist/esm-node/adapter-kit/parity.mjs +17 -360
- package/dist/esm-node/security/crossProjectPolicy.mjs +123 -62
- package/dist/types/adapter-kit/index.d.ts +2 -2
- package/dist/types/adapter-kit/parity-scenarios/cross-project-denial.d.ts +2 -0
- package/dist/types/adapter-kit/parity-scenarios/envelope.d.ts +2 -0
- package/dist/types/adapter-kit/parity-scenarios/operation-context.d.ts +3 -0
- package/dist/types/adapter-kit/parity-scenarios/schema.d.ts +2 -0
- package/dist/types/adapter-kit/parity-scenarios/shared.d.ts +32 -0
- package/dist/types/adapter-kit/parity.d.ts +10 -70
- package/dist/types/security/crossProjectPolicy.d.ts +11 -8
- package/package.json +4 -4
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { CrossProjectOperationContract, CrossProjectPolicyViolationReason } from '../../security/crossProjectPolicy';
|
|
2
|
+
export declare const PARITY_REQUEST_ID = "crm";
|
|
3
|
+
export declare const PARITY_PRODUCER_REQUEST_ID = "crm.producer-a";
|
|
4
|
+
export type ParityExpectation = {
|
|
5
|
+
kind: 'payload';
|
|
6
|
+
status: number;
|
|
7
|
+
payload: unknown;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'denied';
|
|
10
|
+
status: number;
|
|
11
|
+
reason: CrossProjectPolicyViolationReason;
|
|
12
|
+
};
|
|
13
|
+
export type AdapterParityScenario = {
|
|
14
|
+
name: string;
|
|
15
|
+
/** Run against policy-enabled server instead of the open one. */
|
|
16
|
+
policy: boolean;
|
|
17
|
+
request: {
|
|
18
|
+
method: 'get' | 'post' | 'patch';
|
|
19
|
+
path: string;
|
|
20
|
+
headers?: Record<string, string>;
|
|
21
|
+
body?: unknown;
|
|
22
|
+
};
|
|
23
|
+
expected: ParityExpectation;
|
|
24
|
+
};
|
|
25
|
+
export type AdapterParityScenarioContext = {
|
|
26
|
+
helloContract: CrossProjectOperationContract;
|
|
27
|
+
validEnvelope: string;
|
|
28
|
+
validOperationId: string;
|
|
29
|
+
};
|
|
30
|
+
export declare const envelopeHeader: (requestId: unknown) => string;
|
|
31
|
+
export declare const detailHeader: (details: Record<string, unknown>) => string;
|
|
32
|
+
export declare const deniedScenario: (name: string, reason: CrossProjectPolicyViolationReason, headers: Record<string, string>) => AdapterParityScenario;
|
|
@@ -1,45 +1,14 @@
|
|
|
1
1
|
import type { APIHandlerInfo } from '../router';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* One shared table of scenarios executed against every BFF server adapter
|
|
7
|
-
* in its own test harness. Each scenario asserts the adapters produce
|
|
8
|
-
* identical observable results: HTTP status, payload value and
|
|
9
|
-
* policy-rejection reason.
|
|
10
|
-
*
|
|
11
|
-
* The express/koa adapters were removed from the fork, and this is internal
|
|
12
|
-
* test support rather than a package subpath. Their expectations are retained
|
|
13
|
-
* in the per-adapter drift pins as documentation of the historical behavior.
|
|
14
|
-
* The live executable consumer of this table is the hono lane test
|
|
15
|
-
* (`@modern-js/plugin-bff` runs it against `createHonoRoutes` plus the
|
|
16
|
-
* cross-project policy middleware), while bff-core tests validate the table
|
|
17
|
-
* shape and assertion helpers.
|
|
18
|
-
*
|
|
19
|
-
* Transport details intentionally NOT asserted: express serialized scalar
|
|
20
|
-
* bodies as JSON while koa sent `text/plain`; {@link toParityResult}
|
|
21
|
-
* normalizes both to the decoded payload value before comparison.
|
|
22
|
-
*
|
|
23
|
-
* Intentionally OUT OF SCOPE (known, accepted adapter drift — do not add
|
|
24
|
-
* scenarios without deciding the drift first):
|
|
25
|
-
* - operator route-middlewares: express applied them, koa ignored them;
|
|
26
|
-
* - multipart/form-data: payload shapes differ per body parser;
|
|
27
|
-
* - undefined-returning plain handlers are pinned via a per-adapter
|
|
28
|
-
* scenario below: express ended the response 200/empty, koa served its
|
|
29
|
-
* stock 404 ("Not Found"), hono serves its stock "404 Not Found";
|
|
30
|
-
* - farrow schema-mode handlers are pinned per-adapter below: express/koa
|
|
31
|
-
* unwrapped the result envelope (200/400/500), the hono lane has no
|
|
32
|
-
* schema-mode unwrapping and passes the raw envelope through.
|
|
33
|
-
*/
|
|
34
|
-
export declare const PARITY_REQUEST_ID = "crm";
|
|
35
|
-
export declare const PARITY_PRODUCER_REQUEST_ID = "crm.producer-a";
|
|
2
|
+
import type { AdapterParityScenario } from './parity-scenarios/shared';
|
|
3
|
+
export type { AdapterParityScenario, ParityExpectation, } from './parity-scenarios/shared';
|
|
4
|
+
export { PARITY_PRODUCER_REQUEST_ID, PARITY_REQUEST_ID, } from './parity-scenarios/shared';
|
|
36
5
|
/**
|
|
37
6
|
* Handler fixtures registered in both adapters before running the table.
|
|
38
7
|
*/
|
|
39
8
|
export declare const createParityApiHandlerInfos: () => APIHandlerInfo[];
|
|
40
9
|
/**
|
|
41
|
-
* `bff` config slice for
|
|
42
|
-
* switches stay at
|
|
10
|
+
* `bff` config slice for policy-enabled parity server. All `require*`
|
|
11
|
+
* switches stay at strict defaults.
|
|
43
12
|
*/
|
|
44
13
|
export declare const createParityBffConfig: () => {
|
|
45
14
|
requestId: string;
|
|
@@ -48,37 +17,8 @@ export declare const createParityBffConfig: () => {
|
|
|
48
17
|
allowedNamespaces: string[];
|
|
49
18
|
};
|
|
50
19
|
};
|
|
51
|
-
export type ParityAdapterId = 'express' | 'koa' | 'hono';
|
|
52
|
-
export type ParityExpectation = {
|
|
53
|
-
kind: 'payload';
|
|
54
|
-
status: number;
|
|
55
|
-
payload: unknown;
|
|
56
|
-
} | {
|
|
57
|
-
kind: 'denied';
|
|
58
|
-
status: number;
|
|
59
|
-
reason: CrossProjectPolicyViolationReason;
|
|
60
|
-
} | {
|
|
61
|
-
/** Pinned, intentional adapter drift: each adapter has its own expectation. */
|
|
62
|
-
kind: 'perAdapter';
|
|
63
|
-
expectations: Record<ParityAdapterId, {
|
|
64
|
-
status: number;
|
|
65
|
-
payload: unknown;
|
|
66
|
-
}>;
|
|
67
|
-
};
|
|
68
|
-
export type AdapterParityScenario = {
|
|
69
|
-
name: string;
|
|
70
|
-
/** Run against the policy-enabled server instead of the open one. */
|
|
71
|
-
policy: boolean;
|
|
72
|
-
request: {
|
|
73
|
-
method: 'get' | 'post' | 'patch';
|
|
74
|
-
path: string;
|
|
75
|
-
headers?: Record<string, string>;
|
|
76
|
-
body?: unknown;
|
|
77
|
-
};
|
|
78
|
-
expected: ParityExpectation;
|
|
79
|
-
};
|
|
80
20
|
export declare const createAdapterParityScenarios: () => AdapterParityScenario[];
|
|
81
|
-
/** Structural slice of
|
|
21
|
+
/** Structural slice of supertest response used for normalization. */
|
|
82
22
|
export type ParityHttpResponse = {
|
|
83
23
|
status: number;
|
|
84
24
|
/** Content-type mime, e.g. `application/json`. */
|
|
@@ -91,12 +31,12 @@ export type AdapterParityResult = {
|
|
|
91
31
|
payload: unknown;
|
|
92
32
|
};
|
|
93
33
|
/**
|
|
94
|
-
* Normalizes
|
|
95
|
-
*
|
|
34
|
+
* Normalizes raw HTTP response into an observable payload value so JSON and
|
|
35
|
+
* text encodings of the same scalar compare equal.
|
|
96
36
|
*/
|
|
97
37
|
export declare const toParityResult: (res: ParityHttpResponse) => AdapterParityResult;
|
|
98
38
|
/**
|
|
99
|
-
* Framework-agnostic assertion: throws a descriptive error when
|
|
39
|
+
* Framework-agnostic assertion: throws a descriptive error when adapter
|
|
100
40
|
* response deviates from the scenario expectation.
|
|
101
41
|
*/
|
|
102
|
-
export declare const assertParityResult: (scenario: AdapterParityScenario, res: ParityHttpResponse
|
|
42
|
+
export declare const assertParityResult: (scenario: AdapterParityScenario, res: ParityHttpResponse) => void;
|
|
@@ -10,14 +10,16 @@
|
|
|
10
10
|
* authorization boundary: any caller can echo an allowed `requestId` and a
|
|
11
11
|
* matching operation context.
|
|
12
12
|
*
|
|
13
|
-
* To
|
|
13
|
+
* To use `allowedNamespaces` in production, 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, ...).
|
|
18
|
-
* namespace
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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.
|
|
21
23
|
*
|
|
22
24
|
* Client-side counterparts in `@modern-js/create-request` (identity binding,
|
|
23
25
|
* operation contract validation) are developer-experience aids that fail
|
|
@@ -53,7 +55,7 @@ export interface CrossProjectPolicyConfig {
|
|
|
53
55
|
allowUnknownOperations?: boolean;
|
|
54
56
|
denyStatus?: number;
|
|
55
57
|
/**
|
|
56
|
-
* Server-side hook binding
|
|
58
|
+
* Server-side hook binding producer namespace to VERIFIED identity
|
|
57
59
|
* channel (mTLS peer, gateway-authenticated JWT, mesh identity headers).
|
|
58
60
|
*
|
|
59
61
|
* When provided, the namespace asserted by the client envelope must match
|
|
@@ -61,8 +63,9 @@ export interface CrossProjectPolicyConfig {
|
|
|
61
63
|
* against the verified value instead of the client-asserted one. Returning
|
|
62
64
|
* `undefined` (identity could not be verified) denies the request.
|
|
63
65
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
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.
|
|
66
69
|
*/
|
|
67
70
|
verifyProducerIdentity?: (headers: Record<string, unknown>) => string | undefined;
|
|
68
71
|
}
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"modern",
|
|
18
18
|
"modern.js"
|
|
19
19
|
],
|
|
20
|
-
"version": "3.5.0-ultramodern.
|
|
20
|
+
"version": "3.5.0-ultramodern.31",
|
|
21
21
|
"types": "./dist/types/index.d.ts",
|
|
22
22
|
"main": "./dist/cjs/index.js",
|
|
23
23
|
"exports": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"koa-compose": "^4.1.0",
|
|
37
37
|
"reflect-metadata": "^0.2.2",
|
|
38
38
|
"type-fest": "5.7.0",
|
|
39
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.
|
|
39
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.31"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@rslib/core": "0.23.1",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"@typescript/native-preview": "7.0.0-dev.20260628.1",
|
|
46
46
|
"tsconfig-paths": "^4.2.0",
|
|
47
47
|
"zod": "^4.4.3",
|
|
48
|
-
"@modern-js/
|
|
49
|
-
"@modern-js/
|
|
48
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.31",
|
|
49
|
+
"@modern-js/bff-runtime": "npm:@bleedingdev/modern-js-bff-runtime@3.5.0-ultramodern.31",
|
|
50
50
|
"@scripts/rstest-config": "2.66.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|