@bleedingdev/modern-js-create 3.5.0-ultramodern.3 → 3.5.0-ultramodern.30
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/README.md +21 -17
- package/dist/cjs/ultramodern-tooling/commands.cjs +772 -75
- package/dist/cjs/ultramodern-tooling/config.cjs +149 -8
- package/dist/cjs/ultramodern-workspace/add-vertical.cjs +25 -0
- package/dist/cjs/ultramodern-workspace/api.cjs +44 -0
- package/dist/cjs/ultramodern-workspace/app-files.cjs +8 -11
- package/dist/cjs/ultramodern-workspace/backend-federation.cjs +282 -0
- package/dist/cjs/ultramodern-workspace/contracts.cjs +24 -8
- package/dist/cjs/ultramodern-workspace/delivery-unit-sync.cjs +157 -0
- package/dist/cjs/ultramodern-workspace/delivery-unit.cjs +88 -0
- package/dist/cjs/ultramodern-workspace/descriptors.cjs +24 -0
- package/dist/cjs/ultramodern-workspace/module-federation.cjs +161 -50
- package/dist/cjs/ultramodern-workspace/package-json.cjs +26 -43
- package/dist/cjs/ultramodern-workspace/pnpm-workspace-policy-plan.cjs +166 -0
- package/dist/cjs/ultramodern-workspace/tooling-command-catalog.cjs +153 -0
- package/dist/cjs/ultramodern-workspace/versions.cjs +8 -3
- package/dist/cjs/ultramodern-workspace/workspace-script-plan.cjs +175 -0
- package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +104 -63
- package/dist/cjs/ultramodern-workspace/workspace-validation-contract.cjs +97 -0
- package/dist/cjs/ultramodern-workspace/write-workspace.cjs +11 -3
- package/dist/cjs/ultramodern-workspace/zerops.cjs +100 -0
- package/dist/esm/ultramodern-tooling/commands.js +775 -78
- package/dist/esm/ultramodern-tooling/config.js +144 -9
- package/dist/esm/ultramodern-workspace/add-vertical.js +26 -1
- package/dist/esm/ultramodern-workspace/api.js +43 -2
- package/dist/esm/ultramodern-workspace/app-files.js +8 -11
- package/dist/esm/ultramodern-workspace/backend-federation.js +217 -0
- package/dist/esm/ultramodern-workspace/contracts.js +24 -8
- package/dist/esm/ultramodern-workspace/delivery-unit-sync.js +108 -0
- package/dist/esm/ultramodern-workspace/delivery-unit.js +31 -0
- package/dist/esm/ultramodern-workspace/descriptors.js +13 -1
- package/dist/esm/ultramodern-workspace/module-federation.js +160 -42
- package/dist/esm/ultramodern-workspace/package-json.js +16 -40
- package/dist/esm/ultramodern-workspace/pnpm-workspace-policy-plan.js +113 -0
- package/dist/esm/ultramodern-workspace/tooling-command-catalog.js +100 -0
- package/dist/esm/ultramodern-workspace/versions.js +6 -4
- package/dist/esm/ultramodern-workspace/workspace-script-plan.js +110 -0
- package/dist/esm/ultramodern-workspace/workspace-scripts.js +88 -65
- package/dist/esm/ultramodern-workspace/workspace-validation-contract.js +59 -0
- package/dist/esm/ultramodern-workspace/write-workspace.js +14 -6
- package/dist/esm/ultramodern-workspace/zerops.js +62 -0
- package/dist/esm-node/ultramodern-tooling/commands.js +775 -78
- package/dist/esm-node/ultramodern-tooling/config.js +144 -9
- package/dist/esm-node/ultramodern-workspace/add-vertical.js +26 -1
- package/dist/esm-node/ultramodern-workspace/api.js +43 -2
- package/dist/esm-node/ultramodern-workspace/app-files.js +8 -11
- package/dist/esm-node/ultramodern-workspace/backend-federation.js +218 -0
- package/dist/esm-node/ultramodern-workspace/contracts.js +24 -8
- package/dist/esm-node/ultramodern-workspace/delivery-unit-sync.js +109 -0
- package/dist/esm-node/ultramodern-workspace/delivery-unit.js +32 -0
- package/dist/esm-node/ultramodern-workspace/descriptors.js +13 -1
- package/dist/esm-node/ultramodern-workspace/module-federation.js +160 -42
- package/dist/esm-node/ultramodern-workspace/package-json.js +16 -40
- package/dist/esm-node/ultramodern-workspace/pnpm-workspace-policy-plan.js +114 -0
- package/dist/esm-node/ultramodern-workspace/tooling-command-catalog.js +101 -0
- package/dist/esm-node/ultramodern-workspace/versions.js +6 -4
- package/dist/esm-node/ultramodern-workspace/workspace-script-plan.js +111 -0
- package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +88 -65
- package/dist/esm-node/ultramodern-workspace/workspace-validation-contract.js +60 -0
- package/dist/esm-node/ultramodern-workspace/write-workspace.js +14 -6
- package/dist/esm-node/ultramodern-workspace/zerops.js +63 -0
- package/dist/types/ultramodern-tooling/config.d.ts +6 -0
- package/dist/types/ultramodern-workspace/api.d.ts +1 -0
- package/dist/types/ultramodern-workspace/backend-federation.d.ts +11 -0
- package/dist/types/ultramodern-workspace/contracts.d.ts +1 -1
- package/dist/types/ultramodern-workspace/delivery-unit-sync.d.ts +6 -0
- package/dist/types/ultramodern-workspace/delivery-unit.d.ts +27 -0
- package/dist/types/ultramodern-workspace/descriptors.d.ts +4 -0
- package/dist/types/ultramodern-workspace/module-federation.d.ts +4 -9
- package/dist/types/ultramodern-workspace/package-json.d.ts +0 -1
- package/dist/types/ultramodern-workspace/pnpm-workspace-policy-plan.d.ts +39 -0
- package/dist/types/ultramodern-workspace/tooling-command-catalog.d.ts +18 -0
- package/dist/types/ultramodern-workspace/versions.d.ts +5 -3
- package/dist/types/ultramodern-workspace/workspace-script-plan.d.ts +72 -0
- package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +13 -0
- package/dist/types/ultramodern-workspace/workspace-validation-contract.d.ts +42 -0
- package/dist/types/ultramodern-workspace/zerops.d.ts +2 -0
- package/package.json +3 -3
- package/template-workspace/.gitignore.handlebars +4 -0
- package/template-workspace/README.md.handlebars +18 -15
- package/template-workspace/patches/@module-federation__bridge-react@2.6.0.patch +140 -0
- package/template-workspace/patches/@module-federation__modern-js-v3@2.6.0.patch +57 -0
- package/template-workspace/patches/drizzle-orm-ts7-strict-declarations.patch +452 -0
- package/template-workspace/patches/effect-schema-error-type-id.patch +18 -0
- package/template-workspace/pnpm-workspace.yaml.handlebars +8 -0
- package/template-workspace/scripts/bootstrap-agent-skills.mjs +11 -3
- package/templates/workspace-scripts/check-ultramodern-api-boundaries.mts +40 -2
- package/templates/workspace-scripts/generate-node-backend-federation.mjs +270 -0
- package/templates/workspace-scripts/materialize-zerops-runtime.mjs +448 -0
- package/templates/workspace-scripts/proof-cloudflare-version.mjs +237 -9
- package/templates/workspace-scripts/proof-node-backend-federation.mjs +729 -0
- package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +188 -2
- package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +434 -18
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
diff --git a/dist/internal/schema/schema.d.ts b/dist/internal/schema/schema.d.ts
|
|
2
|
+
index 7fbeec1a56a85ab1569f8b80e319fb4638a91615..21d38f72238f748d989d3080f77d0edfc63c0e16 100644
|
|
3
|
+
--- a/dist/internal/schema/schema.d.ts
|
|
4
|
+
+++ b/dist/internal/schema/schema.d.ts
|
|
5
|
+
@@ -3,0 +4 @@
|
|
6
|
+
+export declare const SchemaErrorTypeId: "~effect/Schema/SchemaError";
|
|
7
|
+
diff --git a/dist/unstable/http/internal/preResponseHandler.d.ts b/dist/unstable/http/internal/preResponseHandler.d.ts
|
|
8
|
+
index 81e81e744fa55db2647a8483991db403d451e7dd..040d6c97b85d0c01d4a477013010b9f54d462de8 100644
|
|
9
|
+
--- a/dist/unstable/http/internal/preResponseHandler.d.ts
|
|
10
|
+
+++ b/dist/unstable/http/internal/preResponseHandler.d.ts
|
|
11
|
+
@@ -1 +1,6 @@
|
|
12
|
+
-export {};
|
|
13
|
+
+import type * as Effect from "../../../Effect.ts";
|
|
14
|
+
+import type { HttpServerError } from "../HttpServerError.ts";
|
|
15
|
+
+import type { HttpServerRequest } from "../HttpServerRequest.ts";
|
|
16
|
+
+import type { HttpServerResponse } from "../HttpServerResponse.ts";
|
|
17
|
+
+export declare const requestPreResponseHandlers: WeakMap<object, (request: HttpServerRequest, response: HttpServerResponse) => Effect.Effect<HttpServerResponse, HttpServerError>>;
|
|
18
|
+
+export declare const appendPreResponseHandlerUnsafe: (request: HttpServerRequest, handler: (request: HttpServerRequest, response: HttpServerResponse) => Effect.Effect<HttpServerResponse, HttpServerError>) => void;
|
|
@@ -8,6 +8,8 @@ minimumReleaseAgeStrict: true
|
|
|
8
8
|
minimumReleaseAgeIgnoreMissingTime: false
|
|
9
9
|
minimumReleaseAgeExclude:
|
|
10
10
|
- '@bleedingdev/modern-js-*'
|
|
11
|
+
- 'effect@{{effectVersion}}'
|
|
12
|
+
- '@effect/opentelemetry@{{effectVersion}}'
|
|
11
13
|
- '@tanstack/react-router'
|
|
12
14
|
- '@tanstack/router-core'
|
|
13
15
|
- 'typescript'
|
|
@@ -25,6 +27,7 @@ minimumReleaseAgeExclude:
|
|
|
25
27
|
trustPolicy: no-downgrade
|
|
26
28
|
trustPolicyIgnoreAfter: 1440
|
|
27
29
|
trustPolicyExclude:
|
|
30
|
+
- 'effect@{{effectVersion}}'
|
|
28
31
|
- '@effect/opentelemetry@{{effectVersion}}'
|
|
29
32
|
blockExoticSubdeps: true
|
|
30
33
|
engineStrict: true
|
|
@@ -45,11 +48,13 @@ peerDependencyRules:
|
|
|
45
48
|
overrides:
|
|
46
49
|
'@tanstack/react-router': {{tanstackRouterVersion}}
|
|
47
50
|
'@tanstack/router-core': {{tanstackRouterCoreVersion}}
|
|
51
|
+
'@effect/opentelemetry': {{effectVersion}}
|
|
48
52
|
'@effect/vitest': {{effectVitestVersion}}
|
|
49
53
|
effect: {{effectVersion}}
|
|
50
54
|
node-fetch: '{{nodeFetchVersion}}'
|
|
51
55
|
|
|
52
56
|
allowBuilds:
|
|
57
|
+
'@parcel/watcher': true
|
|
53
58
|
'@swc/core': true
|
|
54
59
|
core-js: true
|
|
55
60
|
esbuild: true
|
|
@@ -59,4 +64,7 @@ allowBuilds:
|
|
|
59
64
|
workerd: true
|
|
60
65
|
|
|
61
66
|
patchedDependencies:
|
|
67
|
+
'@module-federation/modern-js-v3@{{moduleFederationVersion}}': patches/@module-federation__modern-js-v3@{{moduleFederationVersion}}.patch
|
|
68
|
+
'@module-federation/bridge-react@{{moduleFederationVersion}}': patches/@module-federation__bridge-react@{{moduleFederationVersion}}.patch
|
|
62
69
|
'@tanstack/router-core@{{tanstackRouterCoreVersion}}': patches/@tanstack__router-core@{{tanstackRouterCoreVersion}}.patch
|
|
70
|
+
'effect@{{effectVersion}}': patches/effect-schema-error-type-id.patch
|
|
@@ -7,8 +7,14 @@ import { fileURLToPath } from 'node:url';
|
|
|
7
7
|
const root = process.cwd();
|
|
8
8
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
9
9
|
const templateWorkspaceDir = path.resolve(scriptDir, '..');
|
|
10
|
+
// Vendored skills always ship under template-workspace/.codex/skills; the
|
|
11
|
+
// workspace-side lockfile may live under .agents/ (agents-standard layout) or
|
|
12
|
+
// .codex/ (legacy default).
|
|
10
13
|
const vendoredSkillsDir = path.join(templateWorkspaceDir, '.codex/skills');
|
|
11
|
-
const
|
|
14
|
+
const lockRoot = fs.existsSync(path.join(root, '.agents/skills-lock.json'))
|
|
15
|
+
? '.agents'
|
|
16
|
+
: '.codex';
|
|
17
|
+
const lockPath = path.join(root, `${lockRoot}/skills-lock.json`);
|
|
12
18
|
const checkOnly = process.argv.includes('--check');
|
|
13
19
|
const postinstall = process.argv.includes('--postinstall');
|
|
14
20
|
const truthy = value => /^(1|true|yes|on)$/i.test(String(value ?? ''));
|
|
@@ -175,12 +181,14 @@ const resolveSkillDir = (sourceRoot, skillName) => {
|
|
|
175
181
|
};
|
|
176
182
|
|
|
177
183
|
if (!fs.existsSync(lockPath)) {
|
|
178
|
-
console.error(
|
|
184
|
+
console.error(
|
|
185
|
+
'Missing skills-lock.json: expected .agents/skills-lock.json or .codex/skills-lock.json',
|
|
186
|
+
);
|
|
179
187
|
process.exit(1);
|
|
180
188
|
}
|
|
181
189
|
|
|
182
190
|
const lock = readJson(lockPath);
|
|
183
|
-
const installDir = path.join(root, lock.installDir ??
|
|
191
|
+
const installDir = path.join(root, lock.installDir ?? `${lockRoot}/skills`);
|
|
184
192
|
const sources = lock.sources ?? [];
|
|
185
193
|
const vendoredSources = sources.filter(source => source.install === 'vendored');
|
|
186
194
|
const cloneSources = sources.filter(source => source.install === 'clone');
|
|
@@ -189,6 +189,7 @@ if (exists('apps/shell-super-app') && verticalDirectories.length > 0) {
|
|
|
189
189
|
|
|
190
190
|
function assertApiSurface(appPath) {
|
|
191
191
|
const apiEntry = `${appPath}/api/index.ts`;
|
|
192
|
+
const backendEffectExpose = `${appPath}/api/effect-api.ts`;
|
|
192
193
|
const sharedApi = `${appPath}/shared/api.ts`;
|
|
193
194
|
const srcApiDirectory = `${appPath}/src/api`;
|
|
194
195
|
const modernConfig = `${appPath}/modern.config.ts`;
|
|
@@ -235,8 +236,45 @@ function assertApiSurface(appPath) {
|
|
|
235
236
|
'must import the contract from ../shared/api.ts.',
|
|
236
237
|
);
|
|
237
238
|
}
|
|
238
|
-
|
|
239
|
-
|
|
239
|
+
if (exists(backendEffectExpose)) {
|
|
240
|
+
const backendExpose = readText(backendEffectExpose);
|
|
241
|
+
assertContains(
|
|
242
|
+
backendEffectExpose,
|
|
243
|
+
backendExpose,
|
|
244
|
+
/backendFederationContract/u,
|
|
245
|
+
'must export backendFederationContract metadata.',
|
|
246
|
+
);
|
|
247
|
+
assertContains(
|
|
248
|
+
backendEffectExpose,
|
|
249
|
+
backendExpose,
|
|
250
|
+
/role:\s*['"]microvertical-server['"]/u,
|
|
251
|
+
'must describe the MicroVertical server role.',
|
|
252
|
+
);
|
|
253
|
+
assertContains(
|
|
254
|
+
backendEffectExpose,
|
|
255
|
+
backendExpose,
|
|
256
|
+
/strictEffectApproach:\s*true/u,
|
|
257
|
+
'must preserve strict Effect backend execution.',
|
|
258
|
+
);
|
|
259
|
+
assertContains(
|
|
260
|
+
backendEffectExpose,
|
|
261
|
+
backendExpose,
|
|
262
|
+
/contractVersion:\s*['"]microvertical-server-effect-v1['"]/u,
|
|
263
|
+
'must preserve the MicroVertical server contract version.',
|
|
264
|
+
);
|
|
265
|
+
assertContains(
|
|
266
|
+
backendEffectExpose,
|
|
267
|
+
backendExpose,
|
|
268
|
+
/runtime\s*=\s*apiRuntime/u,
|
|
269
|
+
'must export the generated Effect BFF runtime.',
|
|
270
|
+
);
|
|
271
|
+
assert(
|
|
272
|
+
!/\b(request|handler)\s*:\s*async\s*\(/u.test(backendExpose),
|
|
273
|
+
`${backendEffectExpose}: must not expose raw request handlers.`,
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (exists(sharedApi)) {
|
|
240
278
|
const contract = readText(sharedApi);
|
|
241
279
|
assertContains(
|
|
242
280
|
sharedApi,
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
6
|
+
const workspaceRoot = path.resolve(
|
|
7
|
+
process.env.ULTRAMODERN_WORKSPACE_ROOT ??
|
|
8
|
+
path.join(path.dirname(fileURLToPath(import.meta.url)), '../..'),
|
|
9
|
+
);
|
|
10
|
+
const configPath = path.join(workspaceRoot, '.modernjs/ultramodern.json');
|
|
11
|
+
const contractVersion = 'microvertical-server-effect-v1';
|
|
12
|
+
const nodeAdapterVersion = 'backend-mf-effect-v1';
|
|
13
|
+
|
|
14
|
+
function readJson(filePath) {
|
|
15
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function readBuildIdentity(app) {
|
|
19
|
+
const buildModulePath = path.join(
|
|
20
|
+
workspaceRoot,
|
|
21
|
+
app.path,
|
|
22
|
+
'shared/ultramodern-build.ts',
|
|
23
|
+
);
|
|
24
|
+
if (!fs.existsSync(buildModulePath)) {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const source = fs.readFileSync(buildModulePath, 'utf8');
|
|
29
|
+
return {
|
|
30
|
+
buildVersion: source.match(/\bbuild:\s*['"]([^'"]+)['"]/u)?.[1],
|
|
31
|
+
packageName: source.match(/\bpackageName:\s*['"]([^'"]+)['"]/u)?.[1],
|
|
32
|
+
version: source.match(/\bversion:\s*['"]([^'"]+)['"]/u)?.[1],
|
|
33
|
+
unitId: source.match(/\bunitId:\s*['"]([^'"]+)['"]/u)?.[1],
|
|
34
|
+
sourceRevision: source.match(/\bsourceRevision:\s*['"]([^'"]+)['"]/u)?.[1],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function parseArgs(argv) {
|
|
39
|
+
const options = {
|
|
40
|
+
app: undefined,
|
|
41
|
+
target: 'dist',
|
|
42
|
+
};
|
|
43
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
44
|
+
const arg = argv[index];
|
|
45
|
+
if (arg === '--app') {
|
|
46
|
+
options.app = argv[index + 1];
|
|
47
|
+
index += 1;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (arg === '--target') {
|
|
51
|
+
options.target = argv[index + 1] ?? options.target;
|
|
52
|
+
index += 1;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (arg === '--help' || arg === '-h') {
|
|
56
|
+
console.log(
|
|
57
|
+
'Usage: node scripts/generate-node-backend-federation.mts [--app <id>] [--target dist|dist-cloudflare]',
|
|
58
|
+
);
|
|
59
|
+
process.exit(0);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return options;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function backendApps(config, appFilter) {
|
|
66
|
+
return (config.topology?.apps ?? []).filter(app => {
|
|
67
|
+
if (app.kind !== 'vertical') {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
if (!backendFederationMetadata(app)) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return appFilter ? app.id === appFilter : true;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function backendFederationMetadata(app) {
|
|
78
|
+
return app.backendFederation ?? app.api?.backendFederation;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function backendFederationExposes(app) {
|
|
82
|
+
const backend = backendFederationMetadata(app);
|
|
83
|
+
const exposes = Array.isArray(backend.exposes)
|
|
84
|
+
? backend.exposes.filter(expose => typeof expose === 'string')
|
|
85
|
+
: backend.exposes &&
|
|
86
|
+
typeof backend.exposes === 'object' &&
|
|
87
|
+
!Array.isArray(backend.exposes)
|
|
88
|
+
? Object.keys(backend.exposes)
|
|
89
|
+
: [];
|
|
90
|
+
|
|
91
|
+
if (exposes.length > 0) {
|
|
92
|
+
return exposes;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (typeof backend.expose === 'string') {
|
|
96
|
+
return [backend.expose];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
throw new Error(`${app.id} backend federation expose metadata is missing`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function normalizeBackendFederation(app) {
|
|
103
|
+
const backend = backendFederationMetadata(app);
|
|
104
|
+
const nodeSurface = backend.executionSurfaces?.node ?? {};
|
|
105
|
+
const exposes = backendFederationExposes(app);
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
...backend,
|
|
109
|
+
name: backend.name ?? nodeSurface.remoteName,
|
|
110
|
+
remoteType: backend.remoteType ?? nodeSurface.remoteType ?? 'module',
|
|
111
|
+
manifestUrl: backend.manifestUrl ?? nodeSurface.manifestUrl,
|
|
112
|
+
containerEntry: backend.containerEntry ?? nodeSurface.containerEntry,
|
|
113
|
+
runtimePackage: backend.runtimePackage ?? nodeSurface.runtimePackage,
|
|
114
|
+
contractVersion:
|
|
115
|
+
backend.contractVersion ??
|
|
116
|
+
backend.compatibility?.contractVersion ??
|
|
117
|
+
contractVersion,
|
|
118
|
+
nodeAdapterVersion:
|
|
119
|
+
backend.nodeAdapterVersion ?? nodeSurface.adapterVersion ?? nodeAdapterVersion,
|
|
120
|
+
expose:
|
|
121
|
+
typeof backend.expose === 'string'
|
|
122
|
+
? backend.expose
|
|
123
|
+
: (nodeSurface.expose ?? exposes[0]),
|
|
124
|
+
exposes,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function createRemoteEntrySource(app) {
|
|
129
|
+
const exposes = backendFederationExposes(app);
|
|
130
|
+
return `const factories = {
|
|
131
|
+
${exposes
|
|
132
|
+
.map(
|
|
133
|
+
expose => `${JSON.stringify(expose)}: async () =>
|
|
134
|
+
import(new URL('../api/backend-federation.ts', import.meta.url).href),
|
|
135
|
+
`,
|
|
136
|
+
)
|
|
137
|
+
.join('')}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export async function init() {}
|
|
141
|
+
|
|
142
|
+
export function get(id) {
|
|
143
|
+
const factory = factories[id];
|
|
144
|
+
if (!factory) {
|
|
145
|
+
throw new Error(\`Unknown backend federation expose \${id}\`);
|
|
146
|
+
}
|
|
147
|
+
return factory;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export default { init, get };
|
|
151
|
+
`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function createManifest(app) {
|
|
155
|
+
const backend = normalizeBackendFederation(app);
|
|
156
|
+
const buildIdentity = readBuildIdentity(app);
|
|
157
|
+
const compactDeliveryUnit =
|
|
158
|
+
app.deliveryUnit && typeof app.deliveryUnit === 'object'
|
|
159
|
+
? app.deliveryUnit
|
|
160
|
+
: undefined;
|
|
161
|
+
const unitId = compactDeliveryUnit?.unitId ?? buildIdentity.unitId;
|
|
162
|
+
const sourceRevision =
|
|
163
|
+
compactDeliveryUnit?.sourceRevision ?? buildIdentity.sourceRevision;
|
|
164
|
+
return {
|
|
165
|
+
schemaVersion: 1,
|
|
166
|
+
name: backend.name,
|
|
167
|
+
id: backend.name,
|
|
168
|
+
version: buildIdentity.version,
|
|
169
|
+
buildVersion: buildIdentity.buildVersion,
|
|
170
|
+
type: backend.remoteType,
|
|
171
|
+
entry: {
|
|
172
|
+
url: backend.containerEntry,
|
|
173
|
+
type: backend.remoteType,
|
|
174
|
+
},
|
|
175
|
+
metaData: {
|
|
176
|
+
name: backend.name,
|
|
177
|
+
type: backend.remoteType,
|
|
178
|
+
buildInfo: {
|
|
179
|
+
buildName: buildIdentity.packageName,
|
|
180
|
+
buildVersion: buildIdentity.buildVersion,
|
|
181
|
+
},
|
|
182
|
+
remoteEntry: {
|
|
183
|
+
name: 'backendRemoteEntry.mjs',
|
|
184
|
+
path: '',
|
|
185
|
+
type: backend.remoteType,
|
|
186
|
+
},
|
|
187
|
+
exposes: backend.exposes.map(expose => ({
|
|
188
|
+
id: expose,
|
|
189
|
+
name: expose,
|
|
190
|
+
path: expose,
|
|
191
|
+
})),
|
|
192
|
+
},
|
|
193
|
+
exposes: backend.exposes.map(expose => ({
|
|
194
|
+
id: expose,
|
|
195
|
+
name: expose,
|
|
196
|
+
path: expose,
|
|
197
|
+
})),
|
|
198
|
+
backendFederation: {
|
|
199
|
+
role: backend.role ?? 'microvertical-server',
|
|
200
|
+
name: backend.name,
|
|
201
|
+
runtimeFramework: backend.runtimeFramework ?? 'effect',
|
|
202
|
+
strictEffectApproach: backend.strictEffectApproach ?? true,
|
|
203
|
+
contractVersion: backend.contractVersion,
|
|
204
|
+
nodeAdapterVersion: backend.nodeAdapterVersion,
|
|
205
|
+
manifestUrl: backend.manifestUrl,
|
|
206
|
+
containerEntry: backend.containerEntry,
|
|
207
|
+
expose: backend.expose,
|
|
208
|
+
runtimePackage: backend.runtimePackage,
|
|
209
|
+
...(unitId && buildIdentity.buildVersion
|
|
210
|
+
? {
|
|
211
|
+
deliveryUnit: {
|
|
212
|
+
schemaVersion: 1,
|
|
213
|
+
kind: 'microvertical-delivery-unit',
|
|
214
|
+
unitId,
|
|
215
|
+
packageName: buildIdentity.packageName,
|
|
216
|
+
version: buildIdentity.version,
|
|
217
|
+
buildMarker: buildIdentity.buildVersion,
|
|
218
|
+
sourceRevision,
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
: {}),
|
|
222
|
+
versionBoundary: {
|
|
223
|
+
packageName: buildIdentity.packageName,
|
|
224
|
+
version: buildIdentity.version,
|
|
225
|
+
buildVersion: buildIdentity.buildVersion,
|
|
226
|
+
...(unitId && buildIdentity.buildVersion
|
|
227
|
+
? {
|
|
228
|
+
deliveryUnit: {
|
|
229
|
+
unitId,
|
|
230
|
+
buildMarker: buildIdentity.buildVersion,
|
|
231
|
+
},
|
|
232
|
+
}
|
|
233
|
+
: {}),
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const options = parseArgs(process.argv.slice(2));
|
|
240
|
+
const config = readJson(configPath);
|
|
241
|
+
const apps = backendApps(config, options.app);
|
|
242
|
+
|
|
243
|
+
if (options.app && apps.length === 0) {
|
|
244
|
+
throw new Error(`No generated backend federation app matched ${options.app}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
for (const app of apps) {
|
|
248
|
+
const outputDir = path.join(workspaceRoot, app.path, options.target);
|
|
249
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
250
|
+
fs.writeFileSync(
|
|
251
|
+
path.join(outputDir, 'backendRemoteEntry.mjs'),
|
|
252
|
+
createRemoteEntrySource(app),
|
|
253
|
+
'utf-8',
|
|
254
|
+
);
|
|
255
|
+
fs.writeFileSync(
|
|
256
|
+
path.join(outputDir, 'backend-mf-manifest.json'),
|
|
257
|
+
`${JSON.stringify(createManifest(app), null, 2)}\n`,
|
|
258
|
+
'utf-8',
|
|
259
|
+
);
|
|
260
|
+
console.log(
|
|
261
|
+
`[ultramodern] generated backend federation artifacts for ${app.id} in ${path.relative(
|
|
262
|
+
workspaceRoot,
|
|
263
|
+
outputDir,
|
|
264
|
+
)}`,
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (apps.length === 0) {
|
|
269
|
+
console.log('[ultramodern] no backend federation apps to generate');
|
|
270
|
+
}
|