@bleedingdev/modern-js-app-tools-extensions 3.9.3-ultramodern.3 → 3.9.3-ultramodern.5

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.
@@ -54,7 +54,7 @@ const gitOutput = (workspaceRoot, args)=>{
54
54
  return;
55
55
  }
56
56
  };
57
- const createUltramodernReleaseBuildMarker = ({ generationBuildMarker, sourceRevision, unitId })=>(0, external_node_crypto_namespaceObject.createHash)('sha256').update(`${BUILD_MARKER_NAMESPACE}:${unitId}:${generationBuildMarker}:${sourceRevision}`).digest('hex').slice(0, 16);
57
+ const createUltramodernReleaseBuildMarker = ({ generationBuildMarker, sourceRevision, unitId })=>(0, external_node_crypto_namespaceObject.createHash)('sha256').update(`${BUILD_MARKER_NAMESPACE}:${unitId}:${generationBuildMarker}:${sourceRevision}`).digest('hex');
58
58
  const resolveUltramodernSourceRevision = (workspaceRoot = process.cwd(), configuredSourceRevision, environment = process.env)=>{
59
59
  const configuredArgumentValue = configuredSourceRevision?.trim();
60
60
  const configuredEnvironmentValue = environment.ULTRAMODERN_SOURCE_REVISION?.trim();
@@ -54,6 +54,7 @@ const LOCKFILES = [
54
54
  'bun.lock',
55
55
  'bun.lockb'
56
56
  ];
57
+ const RELEASE_BUILD_MARKER_PATTERN = /^[a-f0-9]{64}$/u;
57
58
  const processNonce = (0, external_node_crypto_namespaceObject.randomUUID)();
58
59
  const sha256 = (value)=>(0, external_node_crypto_namespaceObject.createHash)('sha256').update(value).digest('hex');
59
60
  function rendererProfileKey(profile) {
@@ -98,12 +99,21 @@ function resolveRendererBuildIdentities(options) {
98
99
  const projectRoot = external_node_path_default().resolve(options.projectRoot);
99
100
  const appId = options.appId ?? JSON.parse(external_node_fs_default().readFileSync(external_node_path_default().join(projectRoot, 'package.json'), 'utf8')).name;
100
101
  if ('string' != typeof appId || !appId || appId.trim() !== appId) throw new Error('Renderer application identity requires a delivery artifact appId or a package name.');
102
+ const { deliveryUnit } = options;
103
+ if (void 0 !== deliveryUnit && ('string' != typeof deliveryUnit.unitId || !deliveryUnit.unitId || deliveryUnit.unitId.trim() !== deliveryUnit.unitId)) throw new Error('Renderer delivery-unit identity requires a nonempty trimmed unitId.');
101
104
  const profileKey = rendererProfileKey(options.profile);
102
- const sourceRevision = (0, external_release_identity_js_namespaceObject.resolveUltramodernSourceRevision)(projectRoot, options.sourceRevision);
103
- const buildId = sha256(JSON.stringify([
105
+ const sourceRevision = (0, external_release_identity_js_namespaceObject.resolveUltramodernSourceRevision)(projectRoot, deliveryUnit ? deliveryUnit.sourceRevision : options.sourceRevision);
106
+ const promotable = 'production' === options.mode && 'workspace' !== sourceRevision;
107
+ let buildId;
108
+ if (promotable && deliveryUnit) {
109
+ if (deliveryUnit.sourceRevision !== sourceRevision || !RELEASE_BUILD_MARKER_PATTERN.test(deliveryUnit.buildMarker)) throw new Error(`Renderer delivery unit ${deliveryUnit.unitId} must carry the release identity of source revision ${sourceRevision}.`);
110
+ buildId = deliveryUnit.buildMarker;
111
+ } else buildId = sha256(JSON.stringify([
112
+ appId,
113
+ deliveryUnit?.unitId ?? null,
104
114
  profileKey,
105
115
  lockfileHash(projectRoot),
106
- 'development' === options.mode || 'workspace' === sourceRevision ? processNonce : sourceRevision
116
+ promotable ? sourceRevision : processNonce
107
117
  ]));
108
118
  const identities = Object.fromEntries(entries.map((entryName)=>[
109
119
  entryName,
@@ -20,7 +20,7 @@ const gitOutput = (workspaceRoot, args)=>{
20
20
  return;
21
21
  }
22
22
  };
23
- const createUltramodernReleaseBuildMarker = ({ generationBuildMarker, sourceRevision, unitId })=>createHash('sha256').update(`${BUILD_MARKER_NAMESPACE}:${unitId}:${generationBuildMarker}:${sourceRevision}`).digest('hex').slice(0, 16);
23
+ const createUltramodernReleaseBuildMarker = ({ generationBuildMarker, sourceRevision, unitId })=>createHash('sha256').update(`${BUILD_MARKER_NAMESPACE}:${unitId}:${generationBuildMarker}:${sourceRevision}`).digest('hex');
24
24
  const resolveUltramodernSourceRevision = (workspaceRoot = process.cwd(), configuredSourceRevision, environment = process.env)=>{
25
25
  const configuredArgumentValue = configuredSourceRevision?.trim();
26
26
  const configuredEnvironmentValue = environment.ULTRAMODERN_SOURCE_REVISION?.trim();
@@ -10,6 +10,7 @@ const LOCKFILES = [
10
10
  'bun.lock',
11
11
  'bun.lockb'
12
12
  ];
13
+ const RELEASE_BUILD_MARKER_PATTERN = /^[a-f0-9]{64}$/u;
13
14
  const processNonce = randomUUID();
14
15
  const sha256 = (value)=>createHash('sha256').update(value).digest('hex');
15
16
  function rendererProfileKey(profile) {
@@ -54,12 +55,21 @@ function resolveRendererBuildIdentities(options) {
54
55
  const projectRoot = node_path.resolve(options.projectRoot);
55
56
  const appId = options.appId ?? JSON.parse(node_fs.readFileSync(node_path.join(projectRoot, 'package.json'), 'utf8')).name;
56
57
  if ('string' != typeof appId || !appId || appId.trim() !== appId) throw new Error('Renderer application identity requires a delivery artifact appId or a package name.');
58
+ const { deliveryUnit } = options;
59
+ if (void 0 !== deliveryUnit && ('string' != typeof deliveryUnit.unitId || !deliveryUnit.unitId || deliveryUnit.unitId.trim() !== deliveryUnit.unitId)) throw new Error('Renderer delivery-unit identity requires a nonempty trimmed unitId.');
57
60
  const profileKey = rendererProfileKey(options.profile);
58
- const sourceRevision = resolveUltramodernSourceRevision(projectRoot, options.sourceRevision);
59
- const buildId = sha256(JSON.stringify([
61
+ const sourceRevision = resolveUltramodernSourceRevision(projectRoot, deliveryUnit ? deliveryUnit.sourceRevision : options.sourceRevision);
62
+ const promotable = 'production' === options.mode && 'workspace' !== sourceRevision;
63
+ let buildId;
64
+ if (promotable && deliveryUnit) {
65
+ if (deliveryUnit.sourceRevision !== sourceRevision || !RELEASE_BUILD_MARKER_PATTERN.test(deliveryUnit.buildMarker)) throw new Error(`Renderer delivery unit ${deliveryUnit.unitId} must carry the release identity of source revision ${sourceRevision}.`);
66
+ buildId = deliveryUnit.buildMarker;
67
+ } else buildId = sha256(JSON.stringify([
68
+ appId,
69
+ deliveryUnit?.unitId ?? null,
60
70
  profileKey,
61
71
  lockfileHash(projectRoot),
62
- 'development' === options.mode || 'workspace' === sourceRevision ? processNonce : sourceRevision
72
+ promotable ? sourceRevision : processNonce
63
73
  ]));
64
74
  const identities = Object.fromEntries(entries.map((entryName)=>[
65
75
  entryName,
@@ -21,7 +21,7 @@ const gitOutput = (workspaceRoot, args)=>{
21
21
  return;
22
22
  }
23
23
  };
24
- const createUltramodernReleaseBuildMarker = ({ generationBuildMarker, sourceRevision, unitId })=>createHash('sha256').update(`${BUILD_MARKER_NAMESPACE}:${unitId}:${generationBuildMarker}:${sourceRevision}`).digest('hex').slice(0, 16);
24
+ const createUltramodernReleaseBuildMarker = ({ generationBuildMarker, sourceRevision, unitId })=>createHash('sha256').update(`${BUILD_MARKER_NAMESPACE}:${unitId}:${generationBuildMarker}:${sourceRevision}`).digest('hex');
25
25
  const resolveUltramodernSourceRevision = (workspaceRoot = process.cwd(), configuredSourceRevision, environment = process.env)=>{
26
26
  const configuredArgumentValue = configuredSourceRevision?.trim();
27
27
  const configuredEnvironmentValue = environment.ULTRAMODERN_SOURCE_REVISION?.trim();
@@ -11,6 +11,7 @@ const LOCKFILES = [
11
11
  'bun.lock',
12
12
  'bun.lockb'
13
13
  ];
14
+ const RELEASE_BUILD_MARKER_PATTERN = /^[a-f0-9]{64}$/u;
14
15
  const processNonce = randomUUID();
15
16
  const sha256 = (value)=>createHash('sha256').update(value).digest('hex');
16
17
  function rendererProfileKey(profile) {
@@ -55,12 +56,21 @@ function resolveRendererBuildIdentities(options) {
55
56
  const projectRoot = node_path.resolve(options.projectRoot);
56
57
  const appId = options.appId ?? JSON.parse(node_fs.readFileSync(node_path.join(projectRoot, 'package.json'), 'utf8')).name;
57
58
  if ('string' != typeof appId || !appId || appId.trim() !== appId) throw new Error('Renderer application identity requires a delivery artifact appId or a package name.');
59
+ const { deliveryUnit } = options;
60
+ if (void 0 !== deliveryUnit && ('string' != typeof deliveryUnit.unitId || !deliveryUnit.unitId || deliveryUnit.unitId.trim() !== deliveryUnit.unitId)) throw new Error('Renderer delivery-unit identity requires a nonempty trimmed unitId.');
58
61
  const profileKey = rendererProfileKey(options.profile);
59
- const sourceRevision = resolveUltramodernSourceRevision(projectRoot, options.sourceRevision);
60
- const buildId = sha256(JSON.stringify([
62
+ const sourceRevision = resolveUltramodernSourceRevision(projectRoot, deliveryUnit ? deliveryUnit.sourceRevision : options.sourceRevision);
63
+ const promotable = 'production' === options.mode && 'workspace' !== sourceRevision;
64
+ let buildId;
65
+ if (promotable && deliveryUnit) {
66
+ if (deliveryUnit.sourceRevision !== sourceRevision || !RELEASE_BUILD_MARKER_PATTERN.test(deliveryUnit.buildMarker)) throw new Error(`Renderer delivery unit ${deliveryUnit.unitId} must carry the release identity of source revision ${sourceRevision}.`);
67
+ buildId = deliveryUnit.buildMarker;
68
+ } else buildId = sha256(JSON.stringify([
69
+ appId,
70
+ deliveryUnit?.unitId ?? null,
61
71
  profileKey,
62
72
  lockfileHash(projectRoot),
63
- 'development' === options.mode || 'workspace' === sourceRevision ? processNonce : sourceRevision
73
+ promotable ? sourceRevision : processNonce
64
74
  ]));
65
75
  const identities = Object.fromEntries(entries.map((entryName)=>[
66
76
  entryName,
@@ -8,6 +8,16 @@ export declare const createUltramodernReleaseBuildMarker: ({ generationBuildMark
8
8
  unitId: string;
9
9
  }) => string;
10
10
  export declare const resolveUltramodernSourceRevision: (workspaceRoot?: string, configuredSourceRevision?: string, environment?: Readonly<NodeJS.ProcessEnv>) => string;
11
+ /**
12
+ * The one release identity of a delivery unit, resolvable before its build.
13
+ *
14
+ * For a clean source revision the build marker is a 64-hex digest of the unit
15
+ * id, its generation marker and the revision. API bundles carry it, and a UI
16
+ * unit's renderer adopts it as its `buildId`, so contracts, release plans and
17
+ * Worker names derived from it before the build match the built
18
+ * `ultramodern-build.json`, `renderer-build.json`, chunk banners and envelope.
19
+ * A dirty or non-Git checkout yields the non-promotable `workspace` identity.
20
+ */
11
21
  export declare const resolveUltramodernReleaseIdentity: ({ generationBuildMarker, sourceRevision: configuredSourceRevision, unitId, workspaceRoot, environment, }: {
12
22
  generationBuildMarker: string;
13
23
  sourceRevision?: string;
@@ -10,7 +10,18 @@ export interface RendererBuildIdentityOptions {
10
10
  mode: 'development' | 'production';
11
11
  /** Delivery-unit app id; defaults to the application package name. */
12
12
  appId?: string;
13
- /** Externally authenticated source revision (delivery unit or CI). */
13
+ /**
14
+ * The declared delivery unit's release identity, resolved before the build
15
+ * by `resolveUltramodernReleaseIdentity`. A promotable production build
16
+ * adopts its buildMarker as the buildId, so consumers that resolve the unit
17
+ * identity before compiling see the marker the built artifacts carry.
18
+ */
19
+ deliveryUnit?: {
20
+ readonly unitId: string;
21
+ readonly buildMarker: string;
22
+ readonly sourceRevision: string;
23
+ };
24
+ /** Externally authenticated source revision (CI) for an undeclared app. */
14
25
  sourceRevision?: string;
15
26
  /** Actual final entry ownership, supplied by the selected renderer composition. */
16
27
  routerBindings: RendererRouterBindings;
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "directory": "packages/solutions/app-tools-extensions"
12
12
  },
13
13
  "license": "MIT",
14
- "version": "3.9.3-ultramodern.3",
14
+ "version": "3.9.3-ultramodern.5",
15
15
  "files": [
16
16
  "dist",
17
17
  "src"
@@ -177,16 +177,16 @@
177
177
  "dependencies": {
178
178
  "@babel/parser": "^8.0.6",
179
179
  "@babel/traverse": "^8.0.6",
180
- "@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.3-ultramodern.3",
181
- "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.9.3-ultramodern.3",
182
- "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.3-ultramodern.3",
183
- "@modern-js/prod-server": "npm:@bleedingdev/modern-js-prod-server@3.9.3-ultramodern.3",
184
- "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.9.3-ultramodern.3",
185
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.3-ultramodern.3",
186
- "@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.3-ultramodern.3",
187
- "@modern-js/surface-resolution": "npm:@bleedingdev/modern-js-surface-resolution@3.9.3-ultramodern.3",
188
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.3-ultramodern.3",
189
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.3-ultramodern.3",
180
+ "@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.3-ultramodern.5",
181
+ "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.9.3-ultramodern.5",
182
+ "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.3-ultramodern.5",
183
+ "@modern-js/prod-server": "npm:@bleedingdev/modern-js-prod-server@3.9.3-ultramodern.5",
184
+ "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.9.3-ultramodern.5",
185
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.3-ultramodern.5",
186
+ "@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.3-ultramodern.5",
187
+ "@modern-js/surface-resolution": "npm:@bleedingdev/modern-js-surface-resolution@3.9.3-ultramodern.5",
188
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.3-ultramodern.5",
189
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.3-ultramodern.5",
190
190
  "@swc/helpers": "^0.5.23",
191
191
  "@vercel/nft": "^1.11.0",
192
192
  "compression-webpack-plugin": "^12.0.0",
@@ -196,7 +196,7 @@
196
196
  },
197
197
  "peerDependencies": {
198
198
  "@loadable/component": "5.16.7",
199
- "@modern-js/runtime-renderer-extensions": "3.9.3-ultramodern.3",
199
+ "@modern-js/runtime-renderer-extensions": "3.9.3-ultramodern.5",
200
200
  "@rsbuild/core": "2.2.11",
201
201
  "react": "^19.2.8"
202
202
  },
@@ -213,10 +213,10 @@
213
213
  },
214
214
  "devDependencies": {
215
215
  "@loadable/component": "5.16.7",
216
- "@modern-js/bff-effect": "npm:@bleedingdev/modern-js-bff-effect@3.9.3-ultramodern.3",
217
- "@modern-js/plugin-bff-extensions": "npm:@bleedingdev/modern-js-plugin-bff-extensions@3.9.3-ultramodern.3",
218
- "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.9.3-ultramodern.3",
219
- "@modern-js/runtime-renderer-extensions": "npm:@bleedingdev/modern-js-runtime-renderer-extensions@3.9.3-ultramodern.3",
216
+ "@modern-js/bff-effect": "npm:@bleedingdev/modern-js-bff-effect@3.9.3-ultramodern.5",
217
+ "@modern-js/plugin-bff-extensions": "npm:@bleedingdev/modern-js-plugin-bff-extensions@3.9.3-ultramodern.5",
218
+ "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.9.3-ultramodern.5",
219
+ "@modern-js/runtime-renderer-extensions": "npm:@bleedingdev/modern-js-runtime-renderer-extensions@3.9.3-ultramodern.5",
220
220
  "@module-federation/modern-js-v3": "2.9.2",
221
221
  "@module-federation/runtime-tools": "2.9.2",
222
222
  "@rsbuild/core": "2.2.11",
@@ -51,8 +51,7 @@ export const createUltramodernReleaseBuildMarker = ({
51
51
  .update(
52
52
  `${BUILD_MARKER_NAMESPACE}:${unitId}:${generationBuildMarker}:${sourceRevision}`,
53
53
  )
54
- .digest('hex')
55
- .slice(0, 16);
54
+ .digest('hex');
56
55
 
57
56
  export const resolveUltramodernSourceRevision = (
58
57
  workspaceRoot = process.cwd(),
@@ -119,6 +118,16 @@ export const resolveUltramodernSourceRevision = (
119
118
  return revision;
120
119
  };
121
120
 
121
+ /**
122
+ * The one release identity of a delivery unit, resolvable before its build.
123
+ *
124
+ * For a clean source revision the build marker is a 64-hex digest of the unit
125
+ * id, its generation marker and the revision. API bundles carry it, and a UI
126
+ * unit's renderer adopts it as its `buildId`, so contracts, release plans and
127
+ * Worker names derived from it before the build match the built
128
+ * `ultramodern-build.json`, `renderer-build.json`, chunk banners and envelope.
129
+ * A dirty or non-Git checkout yields the non-promotable `workspace` identity.
130
+ */
122
131
  export const resolveUltramodernReleaseIdentity = ({
123
132
  generationBuildMarker,
124
133
  sourceRevision: configuredSourceRevision,
@@ -25,7 +25,18 @@ export interface RendererBuildIdentityOptions {
25
25
  mode: 'development' | 'production';
26
26
  /** Delivery-unit app id; defaults to the application package name. */
27
27
  appId?: string;
28
- /** Externally authenticated source revision (delivery unit or CI). */
28
+ /**
29
+ * The declared delivery unit's release identity, resolved before the build
30
+ * by `resolveUltramodernReleaseIdentity`. A promotable production build
31
+ * adopts its buildMarker as the buildId, so consumers that resolve the unit
32
+ * identity before compiling see the marker the built artifacts carry.
33
+ */
34
+ deliveryUnit?: {
35
+ readonly unitId: string;
36
+ readonly buildMarker: string;
37
+ readonly sourceRevision: string;
38
+ };
39
+ /** Externally authenticated source revision (CI) for an undeclared app. */
29
40
  sourceRevision?: string;
30
41
  /** Actual final entry ownership, supplied by the selected renderer composition. */
31
42
  routerBindings: RendererRouterBindings;
@@ -49,6 +60,8 @@ const LOCKFILES = [
49
60
  'bun.lockb',
50
61
  ];
51
62
 
63
+ const RELEASE_BUILD_MARKER_PATTERN = /^[a-f0-9]{64}$/u;
64
+
52
65
  /** Stable per process: one dev session or dirty build keeps one buildId. */
53
66
  const processNonce = randomUUID();
54
67
 
@@ -132,20 +145,47 @@ export function resolveRendererBuildIdentities(
132
145
  throw new Error(
133
146
  'Renderer application identity requires a delivery artifact appId or a package name.',
134
147
  );
148
+ const { deliveryUnit } = options;
149
+ if (
150
+ deliveryUnit !== undefined &&
151
+ (typeof deliveryUnit.unitId !== 'string' ||
152
+ !deliveryUnit.unitId ||
153
+ deliveryUnit.unitId.trim() !== deliveryUnit.unitId)
154
+ )
155
+ throw new Error(
156
+ 'Renderer delivery-unit identity requires a nonempty trimmed unitId.',
157
+ );
135
158
  const profileKey = rendererProfileKey(options.profile);
136
159
  const sourceRevision = resolveUltramodernSourceRevision(
137
160
  projectRoot,
138
- options.sourceRevision,
139
- );
140
- const buildId = sha256(
141
- JSON.stringify([
142
- profileKey,
143
- lockfileHash(projectRoot),
144
- options.mode === 'development' || sourceRevision === 'workspace'
145
- ? processNonce
146
- : sourceRevision,
147
- ]),
161
+ deliveryUnit ? deliveryUnit.sourceRevision : options.sourceRevision,
148
162
  );
163
+ const promotable =
164
+ options.mode === 'production' && sourceRevision !== 'workspace';
165
+ let buildId: string;
166
+ if (promotable && deliveryUnit) {
167
+ // One identity per delivery unit, known before compilation.
168
+ if (
169
+ deliveryUnit.sourceRevision !== sourceRevision ||
170
+ !RELEASE_BUILD_MARKER_PATTERN.test(deliveryUnit.buildMarker)
171
+ )
172
+ throw new Error(
173
+ `Renderer delivery unit ${deliveryUnit.unitId} must carry the release identity of source revision ${sourceRevision}.`,
174
+ );
175
+ buildId = deliveryUnit.buildMarker;
176
+ } else {
177
+ // Undeclared apps and non-promotable builds (development, dirty trees)
178
+ // keep a per-app id; non-promotable ids are unique per process.
179
+ buildId = sha256(
180
+ JSON.stringify([
181
+ appId,
182
+ deliveryUnit?.unitId ?? null,
183
+ profileKey,
184
+ lockfileHash(projectRoot),
185
+ promotable ? sourceRevision : processNonce,
186
+ ]),
187
+ );
188
+ }
149
189
  const identities = Object.fromEntries(
150
190
  entries.map(entryName => [
151
191
  entryName,