@bleedingdev/modern-js-utils 3.5.0-ultramodern.1 → 3.5.0-ultramodern.100
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/cli/modulePath.js +12 -3
- package/dist/cjs/universal/backend-federation-contract/build-artifact.js +185 -0
- package/dist/cjs/universal/backend-federation-contract/constants.js +92 -0
- package/dist/cjs/universal/backend-federation-contract/delivery-unit.js +130 -0
- package/dist/cjs/universal/backend-federation-contract/index.js +137 -0
- package/dist/cjs/universal/backend-federation-contract/metadata.js +133 -0
- package/dist/cjs/universal/backend-federation-contract/types.js +18 -0
- package/dist/cjs/universal/backend-federation-contract/validation-core.js +85 -0
- package/dist/cjs/universal/index.js +51 -6
- package/dist/cjs/universal/surface-resolution/env-static-provider.js +318 -0
- package/dist/cjs/universal/surface-resolution/index.js +69 -0
- package/dist/cjs/universal/surface-resolution/surface-ref.js +132 -0
- package/dist/cjs/universal/surface-resolution/types.js +18 -0
- package/dist/cjs/universal/surface-resolution/validation.js +202 -0
- package/dist/esm/cli/modulePath.mjs +12 -3
- package/dist/esm/universal/backend-federation-contract/build-artifact.mjs +135 -0
- package/dist/esm/universal/backend-federation-contract/constants.mjs +18 -0
- package/dist/esm/universal/backend-federation-contract/delivery-unit.mjs +74 -0
- package/dist/esm/universal/backend-federation-contract/index.mjs +5 -0
- package/dist/esm/universal/backend-federation-contract/metadata.mjs +80 -0
- package/dist/esm/universal/backend-federation-contract/types.mjs +0 -0
- package/dist/esm/universal/backend-federation-contract/validation-core.mjs +29 -0
- package/dist/esm/universal/index.mjs +2 -0
- package/dist/esm/universal/surface-resolution/env-static-provider.mjs +274 -0
- package/dist/esm/universal/surface-resolution/index.mjs +3 -0
- package/dist/esm/universal/surface-resolution/surface-ref.mjs +88 -0
- package/dist/esm/universal/surface-resolution/types.mjs +0 -0
- package/dist/esm/universal/surface-resolution/validation.mjs +155 -0
- package/dist/esm-node/cli/modulePath.mjs +12 -3
- package/dist/esm-node/universal/backend-federation-contract/build-artifact.mjs +136 -0
- package/dist/esm-node/universal/backend-federation-contract/constants.mjs +19 -0
- package/dist/esm-node/universal/backend-federation-contract/delivery-unit.mjs +75 -0
- package/dist/esm-node/universal/backend-federation-contract/index.mjs +6 -0
- package/dist/esm-node/universal/backend-federation-contract/metadata.mjs +81 -0
- package/dist/esm-node/universal/backend-federation-contract/types.mjs +1 -0
- package/dist/esm-node/universal/backend-federation-contract/validation-core.mjs +30 -0
- package/dist/esm-node/universal/index.mjs +2 -0
- package/dist/esm-node/universal/surface-resolution/env-static-provider.mjs +275 -0
- package/dist/esm-node/universal/surface-resolution/index.mjs +4 -0
- package/dist/esm-node/universal/surface-resolution/surface-ref.mjs +89 -0
- package/dist/esm-node/universal/surface-resolution/types.mjs +1 -0
- package/dist/esm-node/universal/surface-resolution/validation.mjs +156 -0
- package/dist/types/import.d.ts +1 -1
- package/dist/types/universal/backend-federation-contract/build-artifact.d.ts +9 -0
- package/dist/types/universal/backend-federation-contract/constants.d.ts +14 -0
- package/dist/types/universal/backend-federation-contract/delivery-unit.d.ts +9 -0
- package/dist/types/universal/backend-federation-contract/index.d.ts +7 -0
- package/dist/types/universal/backend-federation-contract/metadata.d.ts +7 -0
- package/dist/types/universal/backend-federation-contract/types.d.ts +60 -0
- package/dist/types/universal/backend-federation-contract/validation-core.d.ts +8 -0
- package/dist/types/universal/index.d.ts +2 -0
- package/dist/types/universal/surface-resolution/env-static-provider.d.ts +107 -0
- package/dist/types/universal/surface-resolution/index.d.ts +4 -0
- package/dist/types/universal/surface-resolution/surface-ref.d.ts +72 -0
- package/dist/types/universal/surface-resolution/types.d.ts +102 -0
- package/dist/types/universal/surface-resolution/validation.d.ts +53 -0
- package/package.json +8 -9
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
const SEGMENT_PATTERN = /^[A-Za-z0-9._-]+$/;
|
|
3
|
+
const MAJOR_PATTERN = /^v[1-9][0-9]*$/;
|
|
4
|
+
function parseSurfaceRef(input) {
|
|
5
|
+
if ('' === input) return {
|
|
6
|
+
ok: false,
|
|
7
|
+
error: {
|
|
8
|
+
code: 'empty'
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
const hashCount = countChar(input, '#');
|
|
12
|
+
if (0 === hashCount) return {
|
|
13
|
+
ok: false,
|
|
14
|
+
error: {
|
|
15
|
+
code: 'missing-surface-separator'
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
if (hashCount > 1) return {
|
|
19
|
+
ok: false,
|
|
20
|
+
error: {
|
|
21
|
+
code: 'multiple-surface-separators'
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const hashIndex = input.indexOf('#');
|
|
25
|
+
const unitPart = input.slice(0, hashIndex);
|
|
26
|
+
const rest = input.slice(hashIndex + 1);
|
|
27
|
+
const atIndex = rest.indexOf('@');
|
|
28
|
+
const surfaceId = -1 === atIndex ? rest : rest.slice(0, atIndex);
|
|
29
|
+
const ref = {
|
|
30
|
+
unitId: unitPart,
|
|
31
|
+
surfaceId
|
|
32
|
+
};
|
|
33
|
+
if (-1 !== atIndex) {
|
|
34
|
+
const majorPart = rest.slice(atIndex + 1);
|
|
35
|
+
if ('' === majorPart) return {
|
|
36
|
+
ok: false,
|
|
37
|
+
error: {
|
|
38
|
+
code: 'empty-major'
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
if (!MAJOR_PATTERN.test(majorPart)) return {
|
|
42
|
+
ok: false,
|
|
43
|
+
error: {
|
|
44
|
+
code: 'invalid-major',
|
|
45
|
+
value: majorPart
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
ref.major = Number(majorPart.slice(1));
|
|
49
|
+
}
|
|
50
|
+
const error = validateSurfaceRef(ref);
|
|
51
|
+
return void 0 === error ? {
|
|
52
|
+
ok: true,
|
|
53
|
+
ref
|
|
54
|
+
} : {
|
|
55
|
+
ok: false,
|
|
56
|
+
error
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function formatSurfaceRef(ref) {
|
|
60
|
+
const error = validateSurfaceRef(ref);
|
|
61
|
+
if (void 0 !== error) throw new TypeError(`Cannot format invalid SurfaceRef: ${error.code}.`);
|
|
62
|
+
const base = `${ref.unitId}#${ref.surfaceId}`;
|
|
63
|
+
return void 0 === ref.major ? base : `${base}@v${ref.major}`;
|
|
64
|
+
}
|
|
65
|
+
function validateSurfaceRef(ref) {
|
|
66
|
+
if ('' === ref.unitId) return {
|
|
67
|
+
code: 'empty-unit-id'
|
|
68
|
+
};
|
|
69
|
+
for (const segment of ref.unitId.split('/'))if (!SEGMENT_PATTERN.test(segment)) return {
|
|
70
|
+
code: 'invalid-unit-id',
|
|
71
|
+
segment
|
|
72
|
+
};
|
|
73
|
+
if ('' === ref.surfaceId) return {
|
|
74
|
+
code: 'empty-surface-id'
|
|
75
|
+
};
|
|
76
|
+
if (!SEGMENT_PATTERN.test(ref.surfaceId)) return {
|
|
77
|
+
code: 'invalid-surface-id'
|
|
78
|
+
};
|
|
79
|
+
if (void 0 !== ref.major && (!Number.isSafeInteger(ref.major) || ref.major < 1)) return {
|
|
80
|
+
code: 'invalid-major',
|
|
81
|
+
value: String(ref.major)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function countChar(input, char) {
|
|
85
|
+
let count = 0;
|
|
86
|
+
for (const current of input)if (current === char) count += 1;
|
|
87
|
+
return count;
|
|
88
|
+
}
|
|
89
|
+
export { formatSurfaceRef, parseSurfaceRef, validateSurfaceRef };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "node:module";
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { formatSurfaceRef } from "./surface-ref.mjs";
|
|
3
|
+
const SEGMENT_PATTERN = /^[A-Za-z0-9._-]+$/;
|
|
4
|
+
function createDiscoveryError(code, ref, message, details) {
|
|
5
|
+
const refString = 'string' == typeof ref ? ref : formatSurfaceRef(ref);
|
|
6
|
+
return void 0 === details ? {
|
|
7
|
+
code,
|
|
8
|
+
ref: refString,
|
|
9
|
+
message
|
|
10
|
+
} : {
|
|
11
|
+
code,
|
|
12
|
+
ref: refString,
|
|
13
|
+
message,
|
|
14
|
+
details
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function isNonEmptyString(value) {
|
|
18
|
+
return 'string' == typeof value && value.length > 0;
|
|
19
|
+
}
|
|
20
|
+
function isValidUnitId(unitId) {
|
|
21
|
+
return unitId.split('/').every((segment)=>SEGMENT_PATTERN.test(segment));
|
|
22
|
+
}
|
|
23
|
+
function isRecord(value) {
|
|
24
|
+
return 'object' == typeof value && null !== value && !Array.isArray(value);
|
|
25
|
+
}
|
|
26
|
+
const COMPATIBILITY_STATUSES = [
|
|
27
|
+
'compatible',
|
|
28
|
+
'incompatible',
|
|
29
|
+
'degraded'
|
|
30
|
+
];
|
|
31
|
+
const SURFACE_KINDS = [
|
|
32
|
+
'component',
|
|
33
|
+
'route',
|
|
34
|
+
'api',
|
|
35
|
+
'backend'
|
|
36
|
+
];
|
|
37
|
+
const LOCATION_PLATFORMS = [
|
|
38
|
+
'browser-mf-manifest',
|
|
39
|
+
'node-mf-manifest',
|
|
40
|
+
'http-api',
|
|
41
|
+
'cloudflare-service-binding'
|
|
42
|
+
];
|
|
43
|
+
const LOCATION_REQUIRED_FIELDS = {
|
|
44
|
+
'browser-mf-manifest': [
|
|
45
|
+
'manifestUrl'
|
|
46
|
+
],
|
|
47
|
+
'node-mf-manifest': [
|
|
48
|
+
'manifestRef'
|
|
49
|
+
],
|
|
50
|
+
'http-api': [
|
|
51
|
+
'baseUrl',
|
|
52
|
+
'prefix'
|
|
53
|
+
],
|
|
54
|
+
'cloudflare-service-binding': [
|
|
55
|
+
'serviceBinding'
|
|
56
|
+
]
|
|
57
|
+
};
|
|
58
|
+
function validateLocation(location, path, seenPlatforms, push) {
|
|
59
|
+
if (!isRecord(location)) return void push(path, 'must be an object');
|
|
60
|
+
const platform = location.platform;
|
|
61
|
+
if ('string' != typeof platform || !LOCATION_PLATFORMS.includes(platform)) return void push(`${path}.platform`, `must be one of ${LOCATION_PLATFORMS.join(', ')}`);
|
|
62
|
+
if (seenPlatforms.has(platform)) push(`${path}.platform`, `duplicate platform ${platform} within one surface`);
|
|
63
|
+
seenPlatforms.add(platform);
|
|
64
|
+
for (const field of LOCATION_REQUIRED_FIELDS[platform] ?? [])if (!isNonEmptyString(location[field])) push(`${path}.${field}`, 'must be a non-empty string');
|
|
65
|
+
if ('cloudflare-service-binding' === platform && void 0 !== location.dispatchNamespace && !isNonEmptyString(location.dispatchNamespace)) push(`${path}.dispatchNamespace`, 'must be a non-empty string when present');
|
|
66
|
+
}
|
|
67
|
+
function validateSurface(surface, path, seenSurfaceIds, push) {
|
|
68
|
+
if (!isRecord(surface)) return void push(path, 'must be an object');
|
|
69
|
+
if (isNonEmptyString(surface.surfaceId)) if (SEGMENT_PATTERN.test(surface.surfaceId)) if (seenSurfaceIds.has(surface.surfaceId)) push(`${path}.surfaceId`, 'must be unique within the record');
|
|
70
|
+
else seenSurfaceIds.add(surface.surfaceId);
|
|
71
|
+
else push(`${path}.surfaceId`, 'must match the SurfaceRef SurfaceId grammar');
|
|
72
|
+
else push(`${path}.surfaceId`, 'must be a non-empty string');
|
|
73
|
+
if ('string' != typeof surface.kind || !SURFACE_KINDS.includes(surface.kind)) push(`${path}.kind`, `must be one of ${SURFACE_KINDS.join(', ')}`);
|
|
74
|
+
if (void 0 !== surface.servedMajor && (!Number.isSafeInteger(surface.servedMajor) || surface.servedMajor < 1)) push(`${path}.servedMajor`, 'must be a positive safe integer when present');
|
|
75
|
+
if (!Array.isArray(surface.locations)) return void push(`${path}.locations`, 'must be an array of locations');
|
|
76
|
+
if (0 === surface.locations.length) push(`${path}.locations`, 'must contain at least one location (no partial records)');
|
|
77
|
+
const seenPlatforms = new Set();
|
|
78
|
+
surface.locations.forEach((location, locationIndex)=>{
|
|
79
|
+
validateLocation(location, `${path}.locations[${locationIndex}]`, seenPlatforms, push);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function validateResolvedDeliveryUnit(unit) {
|
|
83
|
+
const issues = [];
|
|
84
|
+
const push = (path, message)=>{
|
|
85
|
+
issues.push({
|
|
86
|
+
path,
|
|
87
|
+
message
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
if (!isRecord(unit)) {
|
|
91
|
+
push('', 'must be an object');
|
|
92
|
+
return {
|
|
93
|
+
ok: false,
|
|
94
|
+
issues
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const raw = unit;
|
|
98
|
+
if (isNonEmptyString(raw.unitId)) {
|
|
99
|
+
if (!isValidUnitId(raw.unitId)) push('unitId', 'must match the SurfaceRef UnitId grammar');
|
|
100
|
+
} else push('unitId', 'must be a non-empty string');
|
|
101
|
+
if (!isNonEmptyString(raw.buildMarker)) push('buildMarker', 'must be a non-empty string');
|
|
102
|
+
if (!isNonEmptyString(raw.sourceRevision)) push('sourceRevision', 'must be a non-empty string');
|
|
103
|
+
if (!isNonEmptyString(raw.baselineCohortId)) push('baselineCohortId', 'must be a non-empty string');
|
|
104
|
+
const compatibility = raw.compatibility;
|
|
105
|
+
if (isRecord(compatibility)) {
|
|
106
|
+
if ('string' != typeof compatibility.status || !COMPATIBILITY_STATUSES.includes(compatibility.status)) push('compatibility.status', `must be one of ${COMPATIBILITY_STATUSES.join(', ')}`);
|
|
107
|
+
if (compatibility.baselineCohortId !== raw.baselineCohortId) push('compatibility.baselineCohortId', 'must equal the record-level baselineCohortId (one verdict per record)');
|
|
108
|
+
if (void 0 !== compatibility.reason && !isNonEmptyString(compatibility.reason)) push('compatibility.reason', 'must be a non-empty string when present');
|
|
109
|
+
} else push('compatibility', 'must be an object');
|
|
110
|
+
if (!Array.isArray(raw.surfaces)) {
|
|
111
|
+
push('surfaces', 'must be an array of surfaces');
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
issues
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (0 === raw.surfaces.length) push('surfaces', 'must contain at least one surface');
|
|
118
|
+
const seenSurfaceIds = new Set();
|
|
119
|
+
raw.surfaces.forEach((surface, surfaceIndex)=>{
|
|
120
|
+
validateSurface(surface, `surfaces[${surfaceIndex}]`, seenSurfaceIds, push);
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
ok: 0 === issues.length,
|
|
124
|
+
issues
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function selectResolvedSurface(unit, ref) {
|
|
128
|
+
if (unit.unitId !== ref.unitId) return {
|
|
129
|
+
ok: false,
|
|
130
|
+
error: createDiscoveryError('unknown-unit', ref, `Resolved record is for unit ${unit.unitId}, not ${ref.unitId}.`, {
|
|
131
|
+
recordUnitId: unit.unitId
|
|
132
|
+
})
|
|
133
|
+
};
|
|
134
|
+
const surface = unit.surfaces.find((candidate)=>candidate.surfaceId === ref.surfaceId);
|
|
135
|
+
if (void 0 === surface) return {
|
|
136
|
+
ok: false,
|
|
137
|
+
error: createDiscoveryError('unknown-surface', ref, `Unit ${unit.unitId} (buildMarker ${unit.buildMarker}) does not publish surface ${ref.surfaceId}.`, {
|
|
138
|
+
availableSurfaces: unit.surfaces.map((entry)=>entry.surfaceId)
|
|
139
|
+
})
|
|
140
|
+
};
|
|
141
|
+
return {
|
|
142
|
+
ok: true,
|
|
143
|
+
surface
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function matchDeliveryUnitIdentity(expected, unit, ref) {
|
|
147
|
+
if (expected.unitId === unit.unitId && expected.buildMarker === unit.buildMarker) return;
|
|
148
|
+
return createDiscoveryError('identity-mismatch', ref, `Delivery-unit identity mismatch: expected ${expected.unitId}@${expected.buildMarker}, resolved ${unit.unitId}@${unit.buildMarker}.`, {
|
|
149
|
+
expected,
|
|
150
|
+
resolved: {
|
|
151
|
+
unitId: unit.unitId,
|
|
152
|
+
buildMarker: unit.buildMarker
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
export { createDiscoveryError, matchDeliveryUnitIdentity, selectResolvedSurface, validateResolvedDeliveryUnit };
|
package/dist/types/import.d.ts
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BackendFederationContractValidationResult, DeliveryUnitRecord, UltramodernBuildArtifact } from './types';
|
|
2
|
+
export declare const createUltramodernBuildArtifact: (record: DeliveryUnitRecord) => UltramodernBuildArtifact;
|
|
3
|
+
export declare const validateUltramodernBuildArtifact: (value: unknown, path?: string) => BackendFederationContractValidationResult;
|
|
4
|
+
export declare const isUltramodernBuildArtifact: (value: unknown) => value is UltramodernBuildArtifact;
|
|
5
|
+
export declare const stampUltramodernBuildArtifactIdentity: (artifact: UltramodernBuildArtifact, identity: {
|
|
6
|
+
buildMarker: string;
|
|
7
|
+
sourceRevision: string;
|
|
8
|
+
}) => UltramodernBuildArtifact;
|
|
9
|
+
export declare const stampUltramodernBuildArtifactSourceRevision: (artifact: UltramodernBuildArtifact, sourceRevision: string) => UltramodernBuildArtifact;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const BACKEND_FEDERATION_EFFECT_EXPOSE = "./effect-api";
|
|
2
|
+
export declare const BACKEND_FEDERATION_MANIFEST_FILE = "backend-mf-manifest.json";
|
|
3
|
+
export declare const BACKEND_FEDERATION_REMOTE_ENTRY_FILE = "backendRemoteEntry.cjs";
|
|
4
|
+
export declare const BACKEND_FEDERATION_CONTRACT_VERSION = "microvertical-server-effect-v1";
|
|
5
|
+
export declare const BACKEND_FEDERATION_NODE_ADAPTER_VERSION = "backend-mf-effect-v1";
|
|
6
|
+
export declare const DELIVERY_UNIT_SCHEMA_VERSION = 1;
|
|
7
|
+
export declare const DELIVERY_UNIT_KIND = "microvertical-delivery-unit";
|
|
8
|
+
export declare const DELIVERY_UNIT_DEPLOY_PROFILE = "cloudflare-ssr-mf-effect-v1";
|
|
9
|
+
export declare const DELIVERY_UNIT_IDENTITY_FIELDS: readonly ['unitId', 'buildMarker', 'sourceRevision'];
|
|
10
|
+
export type DeliveryUnitIdentityField = (typeof DELIVERY_UNIT_IDENTITY_FIELDS)[number];
|
|
11
|
+
export declare const ULTRAMODERN_BUILD_ARTIFACT_FILE = "ultramodern-build.json";
|
|
12
|
+
export declare const ULTRAMODERN_BUILD_ARTIFACT_PATH = "shared/ultramodern-build.json";
|
|
13
|
+
export declare const ULTRAMODERN_BUILD_MODULE_FILE = "ultramodern-build.ts";
|
|
14
|
+
export declare const ULTRAMODERN_BUILD_MODULE_PATH = "shared/ultramodern-build.ts";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DeliveryUnitIdentityField } from './constants';
|
|
2
|
+
import type { BackendFederationContractValidationError, BackendFederationContractValidationResult, DeliveryUnitContractBlock, DeliveryUnitIdentity, DeliveryUnitRecord, ValidateDeliveryUnitIdentityOptions } from './types';
|
|
3
|
+
export declare const deliveryUnitIdentityFieldValue: (value: unknown, field: DeliveryUnitIdentityField, options?: Pick<ValidateDeliveryUnitIdentityOptions, 'allowBuildAlias'>) => string | undefined;
|
|
4
|
+
export declare const validateDeliveryUnitIdentity: (value: unknown, options?: ValidateDeliveryUnitIdentityOptions) => BackendFederationContractValidationResult;
|
|
5
|
+
export declare const validateDeliveryUnitContractBlock: (value: unknown, options?: ValidateDeliveryUnitIdentityOptions) => BackendFederationContractValidationResult;
|
|
6
|
+
export declare const validateDeliveryUnitRecord: (value: unknown, options?: ValidateDeliveryUnitIdentityOptions) => BackendFederationContractValidationResult;
|
|
7
|
+
export declare const validateDeliveryUnitBoundaryIdentity: (value: unknown, path: string) => BackendFederationContractValidationError[];
|
|
8
|
+
export declare const deliveryUnitContractBlock: (record: DeliveryUnitRecord) => DeliveryUnitContractBlock;
|
|
9
|
+
export declare const toDeliveryUnitIdentity: (value: unknown) => DeliveryUnitIdentity | undefined;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createUltramodernBuildArtifact, isUltramodernBuildArtifact, stampUltramodernBuildArtifactIdentity, stampUltramodernBuildArtifactSourceRevision, validateUltramodernBuildArtifact, } from './build-artifact';
|
|
2
|
+
export type { DeliveryUnitIdentityField } from './constants';
|
|
3
|
+
export { BACKEND_FEDERATION_CONTRACT_VERSION, BACKEND_FEDERATION_EFFECT_EXPOSE, BACKEND_FEDERATION_MANIFEST_FILE, BACKEND_FEDERATION_NODE_ADAPTER_VERSION, BACKEND_FEDERATION_REMOTE_ENTRY_FILE, DELIVERY_UNIT_DEPLOY_PROFILE, DELIVERY_UNIT_IDENTITY_FIELDS, DELIVERY_UNIT_KIND, DELIVERY_UNIT_SCHEMA_VERSION, ULTRAMODERN_BUILD_ARTIFACT_FILE, ULTRAMODERN_BUILD_ARTIFACT_PATH, ULTRAMODERN_BUILD_MODULE_FILE, ULTRAMODERN_BUILD_MODULE_PATH, } from './constants';
|
|
4
|
+
export { deliveryUnitContractBlock, deliveryUnitIdentityFieldValue, toDeliveryUnitIdentity, validateDeliveryUnitContractBlock, validateDeliveryUnitIdentity, validateDeliveryUnitRecord, } from './delivery-unit';
|
|
5
|
+
export { backendFederationExposeNames, backendFederationMetadata, backendFederationVersionBoundary, toBackendFederationExposeNames, validateBackendFederationManifest, validateBackendFederationMetadata, } from './metadata';
|
|
6
|
+
export type { BackendFederationContractValidationError, BackendFederationContractValidationResult, DeliveryUnitContractBlock, DeliveryUnitIdentity, DeliveryUnitRecord, UltramodernBuildArtifact, UltramodernBuildDeliveryUnit, UltramodernBuildSurface, ValidateBackendFederationManifestOptions, ValidateBackendFederationMetadataOptions, ValidateDeliveryUnitIdentityOptions, } from './types';
|
|
7
|
+
export { formatBackendFederationValidationErrors, nonEmptyString, } from './validation-core';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BackendFederationContractValidationResult, ValidateBackendFederationManifestOptions, ValidateBackendFederationMetadataOptions } from './types';
|
|
2
|
+
export declare const toBackendFederationExposeNames: (value: unknown) => string[];
|
|
3
|
+
export declare const backendFederationExposeNames: (value: unknown) => string[];
|
|
4
|
+
export declare const backendFederationMetadata: (value: unknown) => Record<string, unknown> | undefined;
|
|
5
|
+
export declare const backendFederationVersionBoundary: (value: unknown) => Record<string, unknown> | undefined;
|
|
6
|
+
export declare const validateBackendFederationMetadata: (value: unknown, options?: ValidateBackendFederationMetadataOptions) => BackendFederationContractValidationResult;
|
|
7
|
+
export declare const validateBackendFederationManifest: (value: unknown, options?: ValidateBackendFederationManifestOptions) => BackendFederationContractValidationResult;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { DELIVERY_UNIT_DEPLOY_PROFILE, DELIVERY_UNIT_KIND, DELIVERY_UNIT_SCHEMA_VERSION } from './constants';
|
|
2
|
+
export type DeliveryUnitIdentity = {
|
|
3
|
+
unitId: string;
|
|
4
|
+
buildMarker: string;
|
|
5
|
+
sourceRevision: string;
|
|
6
|
+
};
|
|
7
|
+
export type DeliveryUnitRecord = DeliveryUnitIdentity & {
|
|
8
|
+
schemaVersion: typeof DELIVERY_UNIT_SCHEMA_VERSION;
|
|
9
|
+
kind: typeof DELIVERY_UNIT_KIND;
|
|
10
|
+
appId: string;
|
|
11
|
+
packageName: string;
|
|
12
|
+
version: string;
|
|
13
|
+
deployProfile: typeof DELIVERY_UNIT_DEPLOY_PROFILE;
|
|
14
|
+
};
|
|
15
|
+
export type DeliveryUnitContractBlock = Omit<DeliveryUnitRecord, 'appId' | 'deployProfile'>;
|
|
16
|
+
export type UltramodernBuildDeliveryUnit = DeliveryUnitRecord & {
|
|
17
|
+
build: string;
|
|
18
|
+
};
|
|
19
|
+
export type UltramodernBuildSurface = (UltramodernBuildDeliveryUnit & {
|
|
20
|
+
surface: 'ui';
|
|
21
|
+
}) | (UltramodernBuildDeliveryUnit & {
|
|
22
|
+
surface: 'api';
|
|
23
|
+
});
|
|
24
|
+
export type UltramodernBuildArtifact = {
|
|
25
|
+
schemaVersion: typeof DELIVERY_UNIT_SCHEMA_VERSION;
|
|
26
|
+
kind: 'ultramodern-build-artifact';
|
|
27
|
+
deliveryUnit: UltramodernBuildDeliveryUnit;
|
|
28
|
+
surfaces: {
|
|
29
|
+
ui: UltramodernBuildDeliveryUnit & {
|
|
30
|
+
surface: 'ui';
|
|
31
|
+
};
|
|
32
|
+
api: UltramodernBuildDeliveryUnit & {
|
|
33
|
+
surface: 'api';
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export type BackendFederationContractValidationError = {
|
|
38
|
+
path: string;
|
|
39
|
+
message: string;
|
|
40
|
+
};
|
|
41
|
+
export type BackendFederationContractValidationResult = {
|
|
42
|
+
ok: boolean;
|
|
43
|
+
errors: BackendFederationContractValidationError[];
|
|
44
|
+
};
|
|
45
|
+
export type ValidateDeliveryUnitIdentityOptions = {
|
|
46
|
+
path?: string;
|
|
47
|
+
allowBuildAlias?: boolean;
|
|
48
|
+
};
|
|
49
|
+
export type ValidateBackendFederationMetadataOptions = {
|
|
50
|
+
path?: string;
|
|
51
|
+
expectedContractVersion?: string | false;
|
|
52
|
+
expectedNodeAdapterVersion?: string | false;
|
|
53
|
+
validateDeliveryUnit?: boolean;
|
|
54
|
+
requireEffectExpose?: boolean;
|
|
55
|
+
requireEffectRuntime?: boolean;
|
|
56
|
+
requireVersionFields?: boolean;
|
|
57
|
+
};
|
|
58
|
+
export type ValidateBackendFederationManifestOptions = ValidateBackendFederationMetadataOptions & {
|
|
59
|
+
requireBackendFederation?: boolean;
|
|
60
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BackendFederationContractValidationError, BackendFederationContractValidationResult } from './types';
|
|
2
|
+
export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
|
|
3
|
+
export declare const nonEmptyString: (value: unknown) => string | undefined;
|
|
4
|
+
export declare const validationResult: (errors: BackendFederationContractValidationError[]) => BackendFederationContractValidationResult;
|
|
5
|
+
export declare const addError: (errors: BackendFederationContractValidationError[], path: string, message: string) => void;
|
|
6
|
+
export declare const recordField: (value: Record<string, unknown> | undefined, field: string) => Record<string, unknown> | undefined;
|
|
7
|
+
export declare const formatBackendFederationValidationErrors: (errors: BackendFederationContractValidationError[]) => string;
|
|
8
|
+
export declare const validateVersionField: (errors: BackendFederationContractValidationError[], record: Record<string, unknown>, field: 'contractVersion' | 'nodeAdapterVersion', expected: string | false, path: string, required: boolean) => void;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { EnvironmentId, ResolvedSurfaceKind, SurfaceResolutionProvider } from './types';
|
|
2
|
+
export type EnvRecord = Record<string, string | undefined>;
|
|
3
|
+
/** Which platforms a surface publishes, plus their static (non-env) inputs. */
|
|
4
|
+
export type EnvStaticSurfacePlatforms = {
|
|
5
|
+
/** Publish a `browser-mf-manifest` location (env/public/cloudflare/localhost chain). */
|
|
6
|
+
browserMfManifest?: boolean;
|
|
7
|
+
/** Publish a `node-mf-manifest` location (backend manifest env / localhost chain). */
|
|
8
|
+
nodeMfManifest?: boolean;
|
|
9
|
+
/** Publish an `http-api` location; the base URL follows the public-URL chain. */
|
|
10
|
+
httpApi?: {
|
|
11
|
+
prefix: string;
|
|
12
|
+
};
|
|
13
|
+
/** Publish a `cloudflare-service-binding` location (statically provisioned). */
|
|
14
|
+
cloudflareServiceBinding?: {
|
|
15
|
+
serviceBinding: string;
|
|
16
|
+
dispatchNamespace?: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export type EnvStaticSurfaceConfig = {
|
|
20
|
+
surfaceId: string;
|
|
21
|
+
kind: ResolvedSurfaceKind;
|
|
22
|
+
platforms: EnvStaticSurfacePlatforms;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Static configuration for one delivery unit. Identity comes from the build
|
|
26
|
+
* artifact (never from the environment); the environment only overrides
|
|
27
|
+
* addresses through the documented env-var chains.
|
|
28
|
+
*/
|
|
29
|
+
export type EnvStaticUnitConfig = {
|
|
30
|
+
unitId: string;
|
|
31
|
+
buildMarker: string;
|
|
32
|
+
sourceRevision: string;
|
|
33
|
+
baselineCohortId: string;
|
|
34
|
+
/**
|
|
35
|
+
* Env-var segment, e.g. `CHECKOUT` in `VERTICAL_CHECKOUT_MF_MANIFEST` /
|
|
36
|
+
* `ULTRAMODERN_PUBLIC_URL_CHECKOUT` (`toEnvSegment(domain ?? id)`).
|
|
37
|
+
*/
|
|
38
|
+
envSegment: string;
|
|
39
|
+
/** Module-federation container name (used to strip `mfName@` env prefixes). */
|
|
40
|
+
mfName: string;
|
|
41
|
+
/** Localhost dev fallback port. Without it, env values are mandatory. */
|
|
42
|
+
port?: number;
|
|
43
|
+
/** Cloudflare worker name for the workers.dev fallback. */
|
|
44
|
+
workerName?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Externally published majors (ADR-0020), each with its own materialization.
|
|
47
|
+
* A requested `@vN` resolves ONLY through the matching entry; a major that
|
|
48
|
+
* is not configured here is the typed `major-not-published` error.
|
|
49
|
+
*/
|
|
50
|
+
majors?: EnvStaticMajorConfig[];
|
|
51
|
+
surfaces: EnvStaticSurfaceConfig[];
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Per-major materialization (ADR-0020): where the externally published major
|
|
55
|
+
* `vN` of a unit lives. Address inputs are deliberately NOT inherited from the
|
|
56
|
+
* unversioned unit — a versioned request must never be answered with
|
|
57
|
+
* unversioned locations — so each major carries its own env segment (default
|
|
58
|
+
* `${unit.envSegment}_V${major}`) and, optionally, its own localhost port /
|
|
59
|
+
* worker name.
|
|
60
|
+
*/
|
|
61
|
+
export type EnvStaticMajorConfig = {
|
|
62
|
+
major: number;
|
|
63
|
+
/** Env-var segment for this major. Default: `${unit.envSegment}_V${major}`. */
|
|
64
|
+
envSegment?: string;
|
|
65
|
+
/** Localhost dev fallback port for this major (local environments only). */
|
|
66
|
+
port?: number;
|
|
67
|
+
/** Cloudflare worker name for this major's workers.dev fallback. */
|
|
68
|
+
workerName?: string;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* How the provider's stamped identity is to be interpreted. `static-trust`
|
|
72
|
+
* (the only mode, and the default) means identity is asserted from static
|
|
73
|
+
* config, not verified against the artifacts; the compatibility verdict then
|
|
74
|
+
* carries `reason: 'static-identity-unverified'`.
|
|
75
|
+
*/
|
|
76
|
+
export type EnvStaticIdentityVerification = 'static-trust';
|
|
77
|
+
/** Environments in which localhost dev fallbacks are allowed by default. */
|
|
78
|
+
export declare const DEFAULT_LOCAL_ENVIRONMENTS: readonly string[];
|
|
79
|
+
export type EnvStaticProviderOptions = {
|
|
80
|
+
units: EnvStaticUnitConfig[];
|
|
81
|
+
/**
|
|
82
|
+
* Environment record to read from. Universal module: `process.env` is never
|
|
83
|
+
* read implicitly; pass it explicitly in Node hosts.
|
|
84
|
+
*/
|
|
85
|
+
env?: EnvRecord;
|
|
86
|
+
/**
|
|
87
|
+
* Environments in which localhost dev fallbacks apply. Any environment NOT
|
|
88
|
+
* listed here fails closed: missing explicit configuration is the typed
|
|
89
|
+
* `provider-unavailable` error, never a localhost URL.
|
|
90
|
+
* Default: `['development', 'local']`.
|
|
91
|
+
*/
|
|
92
|
+
localEnvironments?: EnvironmentId[];
|
|
93
|
+
/**
|
|
94
|
+
* Identity-honesty mode (ADR-0019). Default `'static-trust'`: the verdict
|
|
95
|
+
* is marked `static-identity-unverified` because this provider asserts
|
|
96
|
+
* identity from static config without verifying the resolved artifacts.
|
|
97
|
+
*/
|
|
98
|
+
identityVerification?: EnvStaticIdentityVerification;
|
|
99
|
+
};
|
|
100
|
+
export declare const ENV_STATIC_PROVIDER_NAME = "env-static";
|
|
101
|
+
/**
|
|
102
|
+
* Create the baseline env/static provider. Resolution is all-or-nothing per
|
|
103
|
+
* RESOLUTION-0001: every declared platform location for every surface of the
|
|
104
|
+
* unit assembles against the unit's single static identity, or the whole
|
|
105
|
+
* resolution fails with one typed error.
|
|
106
|
+
*/
|
|
107
|
+
export declare function createEnvStaticSurfaceResolutionProvider(options: EnvStaticProviderOptions): SurfaceResolutionProvider;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createEnvStaticSurfaceResolutionProvider, DEFAULT_LOCAL_ENVIRONMENTS, ENV_STATIC_PROVIDER_NAME, type EnvRecord, type EnvStaticIdentityVerification, type EnvStaticMajorConfig, type EnvStaticProviderOptions, type EnvStaticSurfaceConfig, type EnvStaticSurfacePlatforms, type EnvStaticUnitConfig, } from './env-static-provider';
|
|
2
|
+
export { formatSurfaceRef, type ParsedSurfaceRef, parseSurfaceRef, type SurfaceRefParseError, type SurfaceRefParseResult, validateSurfaceRef, } from './surface-ref';
|
|
3
|
+
export type { CompatibilityStatus, CompatibilityVerdict, DiscoveryError, DiscoveryErrorCode, DiscoveryResult, EnvironmentId, ResolvedDeliveryUnit, ResolvedSurface, ResolvedSurfaceKind, ResolvedSurfaceLocation, ResolvedSurfaceLocationPlatform, SurfaceResolutionProvider, } from './types';
|
|
4
|
+
export { createDiscoveryError, type ExpectedDeliveryUnitIdentity, matchDeliveryUnitIdentity, type ResolvedDeliveryUnitIssue, type ResolvedDeliveryUnitValidationResult, selectResolvedSurface, validateResolvedDeliveryUnit, } from './validation';
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SurfaceRef grammar (MV-G25a).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the EBNF in `packages/toolkit/create/delivery-unit-schema-SPEC.md` §2
|
|
5
|
+
* exactly:
|
|
6
|
+
*
|
|
7
|
+
* ```ebnf
|
|
8
|
+
* SurfaceRef = UnitId , "#" , SurfaceId , [ "@" , Major ] ;
|
|
9
|
+
* UnitId = Segment , { "/" , Segment } ;
|
|
10
|
+
* SurfaceId = Segment ;
|
|
11
|
+
* Segment = SegmentChar , { SegmentChar } ;
|
|
12
|
+
* SegmentChar = letter | digit | "-" | "_" | "." ;
|
|
13
|
+
* Major = "v" , nonzero , { digit } ;
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Canonical form: `unitId#surfaceId` with optional `@vN` external-major suffix
|
|
17
|
+
* (e.g. `acme/checkout#cart`, `acme/checkout#cart@v2`). Universal module:
|
|
18
|
+
* dependency-free, runs in any JavaScript environment.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Parsed form of a SurfaceRef. Canonical string form is `unitId#surfaceId`
|
|
22
|
+
* with an optional `@vN` major suffix.
|
|
23
|
+
*/
|
|
24
|
+
export type ParsedSurfaceRef = {
|
|
25
|
+
unitId: string;
|
|
26
|
+
surfaceId: string;
|
|
27
|
+
/** External-major selector. Absent means "the coordinated-zone surface". */
|
|
28
|
+
major?: number;
|
|
29
|
+
};
|
|
30
|
+
export type SurfaceRefParseError = {
|
|
31
|
+
code: 'empty';
|
|
32
|
+
} | {
|
|
33
|
+
code: 'missing-surface-separator';
|
|
34
|
+
} | {
|
|
35
|
+
code: 'multiple-surface-separators';
|
|
36
|
+
} | {
|
|
37
|
+
code: 'empty-unit-id';
|
|
38
|
+
} | {
|
|
39
|
+
code: 'invalid-unit-id';
|
|
40
|
+
segment: string;
|
|
41
|
+
} | {
|
|
42
|
+
code: 'empty-surface-id';
|
|
43
|
+
} | {
|
|
44
|
+
code: 'invalid-surface-id';
|
|
45
|
+
} | {
|
|
46
|
+
code: 'empty-major';
|
|
47
|
+
} | {
|
|
48
|
+
code: 'invalid-major';
|
|
49
|
+
value: string;
|
|
50
|
+
};
|
|
51
|
+
export type SurfaceRefParseResult = {
|
|
52
|
+
ok: true;
|
|
53
|
+
ref: ParsedSurfaceRef;
|
|
54
|
+
} | {
|
|
55
|
+
ok: false;
|
|
56
|
+
error: SurfaceRefParseError;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Parse a canonical SurfaceRef string. Total function: every rejection is a
|
|
60
|
+
* typed {@link SurfaceRefParseError}; never throws.
|
|
61
|
+
*/
|
|
62
|
+
export declare function parseSurfaceRef(input: string): SurfaceRefParseResult;
|
|
63
|
+
/**
|
|
64
|
+
* Render a {@link ParsedSurfaceRef} back to its canonical string form.
|
|
65
|
+
*
|
|
66
|
+
* Direct inputs are checked against the same invariant as parsed references,
|
|
67
|
+
* so this formatter cannot emit a string that {@link parseSurfaceRef} rejects.
|
|
68
|
+
* Round-trip: `formatSurfaceRef(parseSurfaceRef(x).ref) === x` for valid `x`.
|
|
69
|
+
*/
|
|
70
|
+
export declare function formatSurfaceRef(ref: ParsedSurfaceRef): string;
|
|
71
|
+
/** The shared semantic invariant for parsed and directly formatted references. */
|
|
72
|
+
export declare function validateSurfaceRef(ref: ParsedSurfaceRef): SurfaceRefParseError | undefined;
|