@bleedingdev/modern-js-create 3.5.0-ultramodern.27 → 3.5.0-ultramodern.29
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/ultramodern-tooling/commands.cjs +497 -155
- 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/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 +122 -44
- package/dist/cjs/ultramodern-workspace/package-json.cjs +11 -34
- 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/workspace-script-plan.cjs +175 -0
- package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +43 -62
- package/dist/cjs/ultramodern-workspace/workspace-validation-contract.cjs +97 -0
- package/dist/cjs/ultramodern-workspace/write-workspace.cjs +9 -3
- package/dist/cjs/ultramodern-workspace/zerops.cjs +100 -0
- package/dist/esm/ultramodern-tooling/commands.js +500 -158
- 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/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 +121 -36
- package/dist/esm/ultramodern-workspace/package-json.js +11 -31
- 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/workspace-script-plan.js +110 -0
- package/dist/esm/ultramodern-workspace/workspace-scripts.js +35 -63
- package/dist/esm/ultramodern-workspace/workspace-validation-contract.js +59 -0
- package/dist/esm/ultramodern-workspace/write-workspace.js +11 -5
- package/dist/esm/ultramodern-workspace/zerops.js +62 -0
- package/dist/esm-node/ultramodern-tooling/commands.js +500 -158
- 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/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 +121 -36
- package/dist/esm-node/ultramodern-workspace/package-json.js +11 -31
- 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/workspace-script-plan.js +111 -0
- package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +35 -63
- package/dist/esm-node/ultramodern-workspace/workspace-validation-contract.js +60 -0
- package/dist/esm-node/ultramodern-workspace/write-workspace.js +11 -5
- 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/workspace-script-plan.d.ts +72 -0
- package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +3 -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 +1 -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 +234 -8
- 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 +322 -8
|
@@ -4,6 +4,9 @@ import node_path from "node:path";
|
|
|
4
4
|
import { normalizeUltramodernBridgeConfig } from "../ultramodern-workspace/bridge-config.js";
|
|
5
5
|
import { ULTRAMODERN_CONFIG_PATH, createNeutralOwnership, shellApp } from "../ultramodern-workspace/descriptors.js";
|
|
6
6
|
import { toKebabCase } from "../ultramodern-workspace/naming.js";
|
|
7
|
+
const LEGACY_GENERATED_CONTRACT_PATH = '.modernjs/ultramodern-generated-contract.json';
|
|
8
|
+
const LEGACY_PACKAGE_SOURCE_METADATA_PATH = '.modernjs/ultramodern-package-source.json';
|
|
9
|
+
const LEGACY_DEVELOPMENT_OVERLAY_PATH = 'topology/local-overlays/development.json';
|
|
7
10
|
function readJsonObject(filePath) {
|
|
8
11
|
const value = JSON.parse(node_fs.readFileSync(filePath, 'utf-8'));
|
|
9
12
|
if (null === value || 'object' != typeof value || Array.isArray(value)) throw new Error(`UltraModern config must contain a JSON object: ${filePath}`);
|
|
@@ -12,11 +15,39 @@ function readJsonObject(filePath) {
|
|
|
12
15
|
function readOptionalJsonObject(filePath) {
|
|
13
16
|
return node_fs.existsSync(filePath) ? readJsonObject(filePath) : {};
|
|
14
17
|
}
|
|
15
|
-
function packageScopeFromRoot(
|
|
16
|
-
const rootPackage = readOptionalJsonObject(node_path.join(
|
|
17
|
-
return 'string' == typeof rootPackage.name && rootPackage.name.length > 0 ? rootPackage.name : node_path.basename(
|
|
18
|
+
function packageScopeFromRoot(workspaceRoot) {
|
|
19
|
+
const rootPackage = readOptionalJsonObject(node_path.join(workspaceRoot, 'package.json'));
|
|
20
|
+
return 'string' == typeof rootPackage.name && rootPackage.name.length > 0 ? rootPackage.name : node_path.basename(workspaceRoot);
|
|
18
21
|
}
|
|
19
|
-
function
|
|
22
|
+
function packageSourceFromMetadata(workspaceRoot) {
|
|
23
|
+
const metadataPath = node_path.join(workspaceRoot, LEGACY_PACKAGE_SOURCE_METADATA_PATH);
|
|
24
|
+
if (!node_fs.existsSync(metadataPath)) return;
|
|
25
|
+
const metadata = readJsonObject(metadataPath);
|
|
26
|
+
const aliases = metadata.modernPackages?.aliases ?? {};
|
|
27
|
+
const firstAliasEntry = Object.entries(aliases).find((entry)=>'string' == typeof entry[1]);
|
|
28
|
+
const firstPackage = firstAliasEntry?.[0];
|
|
29
|
+
const firstAlias = firstAliasEntry?.[1];
|
|
30
|
+
const aliasScope = firstAlias?.match(/^@([^/]+)\//u)?.[1];
|
|
31
|
+
const unscopedName = firstPackage?.split('/').at(-1) ?? '';
|
|
32
|
+
const aliasUnscopedName = firstAlias?.split('/').at(-1) ?? '';
|
|
33
|
+
const aliasPackageNamePrefix = aliasUnscopedName && unscopedName && aliasUnscopedName.endsWith(unscopedName) ? aliasUnscopedName.slice(0, -unscopedName.length) : void 0;
|
|
34
|
+
return {
|
|
35
|
+
strategy: 'install' === metadata.strategy ? 'install' : 'workspace',
|
|
36
|
+
modernPackageVersion: 'string' == typeof metadata.modernPackages?.specifier ? metadata.modernPackages.specifier : 'workspace:*',
|
|
37
|
+
registry: 'string' == typeof metadata.modernPackages?.registry ? metadata.modernPackages.registry : void 0,
|
|
38
|
+
aliasScope,
|
|
39
|
+
aliasPackageNamePrefix
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function readOverlayPorts(workspaceRoot) {
|
|
43
|
+
const overlayPath = node_path.join(workspaceRoot, LEGACY_DEVELOPMENT_OVERLAY_PATH);
|
|
44
|
+
if (!node_fs.existsSync(overlayPath)) return {};
|
|
45
|
+
const overlay = readJsonObject(overlayPath);
|
|
46
|
+
const ports = overlay.ports;
|
|
47
|
+
if (null === ports || 'object' != typeof ports || Array.isArray(ports)) return {};
|
|
48
|
+
return Object.fromEntries(Object.entries(ports).filter((entry)=>'number' == typeof entry[1]));
|
|
49
|
+
}
|
|
50
|
+
function normalizeCompactConfig(workspaceRoot, sourcePath, config) {
|
|
20
51
|
const packageSource = config.packageSource && 'object' == typeof config.packageSource ? {
|
|
21
52
|
strategy: 'install' === config.packageSource.strategy ? 'install' : 'workspace',
|
|
22
53
|
modernPackageVersion: 'string' == typeof config.packageSource.modernPackageVersion ? config.packageSource.modernPackageVersion : 'workspace:*',
|
|
@@ -69,10 +100,114 @@ function normalizeCompactConfig(sourcePath, config) {
|
|
|
69
100
|
}
|
|
70
101
|
};
|
|
71
102
|
}
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
103
|
+
function normalizeCompactUltramodernConfig(workspaceRoot, compact) {
|
|
104
|
+
return normalizeCompactConfig(workspaceRoot, node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH), compact);
|
|
105
|
+
}
|
|
106
|
+
function synthesizeCompactUltramodernConfig(workspaceRoot) {
|
|
107
|
+
const contractPath = node_path.join(workspaceRoot, LEGACY_GENERATED_CONTRACT_PATH);
|
|
108
|
+
if (!node_fs.existsSync(contractPath)) return;
|
|
109
|
+
const contract = readJsonObject(contractPath);
|
|
110
|
+
const sources = [
|
|
111
|
+
LEGACY_GENERATED_CONTRACT_PATH
|
|
112
|
+
];
|
|
113
|
+
const missing = [];
|
|
114
|
+
const packageSource = packageSourceFromMetadata(workspaceRoot);
|
|
115
|
+
if (packageSource) sources.push(LEGACY_PACKAGE_SOURCE_METADATA_PATH);
|
|
116
|
+
else missing.push(LEGACY_PACKAGE_SOURCE_METADATA_PATH);
|
|
117
|
+
const ports = readOverlayPorts(workspaceRoot);
|
|
118
|
+
if (node_fs.existsSync(node_path.join(workspaceRoot, LEGACY_DEVELOPMENT_OVERLAY_PATH))) sources.push(LEGACY_DEVELOPMENT_OVERLAY_PATH);
|
|
119
|
+
else missing.push(LEGACY_DEVELOPMENT_OVERLAY_PATH);
|
|
120
|
+
const apps = Array.isArray(contract.apps) ? contract.apps : [];
|
|
121
|
+
const shell = apps.find((app)=>app?.id === shellApp.id);
|
|
122
|
+
const compact = {
|
|
123
|
+
schemaVersion: 'number' == typeof contract.schemaVersion ? contract.schemaVersion : 1,
|
|
124
|
+
...'string' == typeof contract.profile ? {
|
|
125
|
+
profile: contract.profile
|
|
126
|
+
} : {},
|
|
127
|
+
workspace: {
|
|
128
|
+
packageScope: packageScopeFromRoot(workspaceRoot)
|
|
129
|
+
},
|
|
130
|
+
...packageSource ? {
|
|
131
|
+
packageSource: {
|
|
132
|
+
strategy: packageSource.strategy,
|
|
133
|
+
modernPackageVersion: packageSource.modernPackageVersion,
|
|
134
|
+
...packageSource.registry ? {
|
|
135
|
+
registry: packageSource.registry
|
|
136
|
+
} : {},
|
|
137
|
+
...packageSource.aliasScope ? {
|
|
138
|
+
aliasScope: packageSource.aliasScope
|
|
139
|
+
} : {},
|
|
140
|
+
...packageSource.aliasPackageNamePrefix ? {
|
|
141
|
+
aliasPackageNamePrefix: packageSource.aliasPackageNamePrefix
|
|
142
|
+
} : {}
|
|
143
|
+
}
|
|
144
|
+
} : {},
|
|
145
|
+
features: {
|
|
146
|
+
tailwind: shell?.styling?.tailwind !== false
|
|
147
|
+
},
|
|
148
|
+
topology: {
|
|
149
|
+
apps: apps.map((app)=>{
|
|
150
|
+
const id = String(app.id);
|
|
151
|
+
const appPath = 'string' == typeof app.path ? app.path : id === shellApp.id ? shellApp.directory : `verticals/${toKebabCase(id)}`;
|
|
152
|
+
const domain = 'string' == typeof app.i18n?.namespace && 'shell' !== app.i18n.namespace ? app.i18n.namespace : appPath.split('/').at(-1);
|
|
153
|
+
const moduleFederation = app.moduleFederation && 'object' == typeof app.moduleFederation ? {
|
|
154
|
+
role: 'vertical' === app.kind ? 'remote' : 'host',
|
|
155
|
+
...'string' == typeof app.moduleFederation.name ? {
|
|
156
|
+
name: app.moduleFederation.name
|
|
157
|
+
} : {},
|
|
158
|
+
...Array.isArray(app.moduleFederation.exposes) ? {
|
|
159
|
+
exposes: app.moduleFederation.exposes.filter((expose)=>'string' == typeof expose)
|
|
160
|
+
} : {},
|
|
161
|
+
...Array.isArray(app.moduleFederation.verticalRefs) ? {
|
|
162
|
+
verticalRefs: app.moduleFederation.verticalRefs.filter((ref)=>'string' == typeof ref)
|
|
163
|
+
} : {}
|
|
164
|
+
} : void 0;
|
|
165
|
+
const api = app.effect && 'object' == typeof app.effect ? {
|
|
166
|
+
stem: 'string' == typeof app.effect.prefix ? app.effect.prefix.split('/').filter(Boolean).at(-1) ?? domain ?? id : domain ?? id,
|
|
167
|
+
prefix: 'string' == typeof app.effect.prefix ? app.effect.prefix : `/${domain ?? id}-api`,
|
|
168
|
+
consumedBy: [
|
|
169
|
+
shellApp.id,
|
|
170
|
+
id
|
|
171
|
+
]
|
|
172
|
+
} : void 0;
|
|
173
|
+
return {
|
|
174
|
+
id,
|
|
175
|
+
kind: 'vertical' === app.kind ? 'vertical' : 'shell',
|
|
176
|
+
path: appPath,
|
|
177
|
+
...'string' == typeof app.package ? {
|
|
178
|
+
package: app.package
|
|
179
|
+
} : {},
|
|
180
|
+
packageSuffix: 'string' == typeof app.package ? app.package.split('/').at(-1) : appPath.split('/').at(-1),
|
|
181
|
+
...id === shellApp.id ? {
|
|
182
|
+
displayName: shellApp.displayName
|
|
183
|
+
} : {},
|
|
184
|
+
...domain ? {
|
|
185
|
+
domain
|
|
186
|
+
} : {},
|
|
187
|
+
...'number' == typeof ports[id] ? {
|
|
188
|
+
port: ports[id]
|
|
189
|
+
} : {},
|
|
190
|
+
...moduleFederation ? {
|
|
191
|
+
moduleFederation
|
|
192
|
+
} : {},
|
|
193
|
+
...api ? {
|
|
194
|
+
api
|
|
195
|
+
} : {}
|
|
196
|
+
};
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
compact,
|
|
202
|
+
missing,
|
|
203
|
+
sources
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function readUltramodernConfig(workspaceRoot = process.cwd()) {
|
|
207
|
+
const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
|
|
208
|
+
if (node_fs.existsSync(compactPath)) return normalizeCompactConfig(workspaceRoot, compactPath, readJsonObject(compactPath));
|
|
209
|
+
if (node_fs.existsSync(node_path.join(workspaceRoot, LEGACY_GENERATED_CONTRACT_PATH))) throw new Error(`Missing ${ULTRAMODERN_CONFIG_PATH}. Legacy UltraModern metadata detected — run \`modern-js-create ultramodern migrate-strict-effect\` to synthesize it.`);
|
|
210
|
+
throw new Error(`Missing UltraModern config. Expected ${ULTRAMODERN_CONFIG_PATH}. Run \`modern-js-create ultramodern migrate-strict-effect\` if you have legacy UltraModern metadata to migrate.`);
|
|
76
211
|
}
|
|
77
212
|
function workspaceAppsFromToolingConfig(config) {
|
|
78
213
|
return config.topology.apps.map((app)=>{
|
|
@@ -118,4 +253,4 @@ function workspaceAppsFromToolingConfig(config) {
|
|
|
118
253
|
};
|
|
119
254
|
});
|
|
120
255
|
}
|
|
121
|
-
export { readUltramodernConfig, workspaceAppsFromToolingConfig };
|
|
256
|
+
export { normalizeCompactUltramodernConfig, readUltramodernConfig, synthesizeCompactUltramodernConfig, workspaceAppsFromToolingConfig };
|
|
@@ -6,12 +6,14 @@ import { WORKSPACE_PACKAGE_VERSION } from "../ultramodern-package-source.js";
|
|
|
6
6
|
import { readUltramodernConfig } from "../ultramodern-tooling/config.js";
|
|
7
7
|
import { apiTopologyMetadata, createShellApiClient } from "./api.js";
|
|
8
8
|
import { createAppEnvDts, createAppRuntimeConfig, createShellFrameComponent } from "./app-files.js";
|
|
9
|
+
import { createBackendFederationContract, createServerExecutionOverlay } from "./backend-federation.js";
|
|
10
|
+
import { createDeliveryUnitRecord, deliveryUnitContractBlock } from "./delivery-unit.js";
|
|
9
11
|
import { createShellPage, createShellRemoteComponents } from "./demo-components.js";
|
|
10
12
|
import { ULTRAMODERN_CONFIG_PATH, appHasApi, appI18nNamespace, createModuleFederationRemoteContracts, createNeutralOwnership, createRemoteManifestEnv, createShellHost, createVerticalDescriptor, remoteDependencyAlias, resolveApiPrefix, shellApp, zephyrRemoteDependency } from "./descriptors.js";
|
|
11
13
|
import { formatGeneratedWorkspaceFiles, readJsonFile, writeFileReplacing, writeJsonFile } from "./fs-io.js";
|
|
12
14
|
import { createFileSnapshot, createGenerationResult, diffFileSnapshots } from "./generation-result.js";
|
|
13
15
|
import { createAppPublicLocaleMessages } from "./locales.js";
|
|
14
|
-
import { createShellModuleFederationConfig } from "./module-federation.js";
|
|
16
|
+
import { createAppModernConfig, createShellModuleFederationConfig } from "./module-federation.js";
|
|
15
17
|
import { assertUniqueTailwindPrefixes, normalizePath, packageName, toEnvSegment, toKebabCase, toPackageScope, toPascalCase } from "./naming.js";
|
|
16
18
|
import { runCodeSmithOverlays } from "./overlays.js";
|
|
17
19
|
import { createAppMfTypesTsConfig, createAppPackage, createAppTsConfig, createRootPackageJson, createRootTsConfig } from "./package-json.js";
|
|
@@ -21,6 +23,7 @@ import { createPublicWebAppArtifacts, rewriteWorkspaceAssetsForApp } from "./pub
|
|
|
21
23
|
import { isRecord } from "./types.js";
|
|
22
24
|
import { writeGeneratedWorkspaceScripts } from "./workspace-scripts.js";
|
|
23
25
|
import { createCompactUltramodernConfig, writeApp } from "./write-workspace.js";
|
|
26
|
+
import { createZeropsYaml } from "./zerops.js";
|
|
24
27
|
const FIRST_VERTICAL_PORT = 4101;
|
|
25
28
|
const TOPOLOGY_PATH = 'topology/reference-topology.json';
|
|
26
29
|
const OWNERSHIP_PATH = 'topology/ownership.json';
|
|
@@ -74,6 +77,7 @@ function rewriteShellAppFiles(workspaceRoot, scope, packageSource, enableTailwin
|
|
|
74
77
|
writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/tsconfig.json`), createAppTsConfig(shellHost, remotes));
|
|
75
78
|
writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/tsconfig.mf-types.json`), createAppMfTypesTsConfig(shellHost));
|
|
76
79
|
writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/modern-app-env.d.ts`, createAppEnvDts(shellHost, remotes));
|
|
80
|
+
writeFileReplacing(workspaceRoot, `${shellApp.directory}/modern.config.ts`, createAppModernConfig(scope, shellHost, remotes));
|
|
77
81
|
writeFileReplacing(workspaceRoot, publicWeb.jsonLdHelperFile.path, publicWeb.jsonLdHelperFile.content);
|
|
78
82
|
writeFileReplacing(workspaceRoot, publicWeb.routeMetadataFile.path, publicWeb.routeMetadataFile.content);
|
|
79
83
|
writeFileReplacing(workspaceRoot, publicWeb.routeHeadFile.path, publicWeb.routeHeadFile.content);
|
|
@@ -125,6 +129,12 @@ function verticalTopologyEntry(scope, vertical, remotes = []) {
|
|
|
125
129
|
fallbackTelemetryEvent: 'modernjs:mv-runtime-parity',
|
|
126
130
|
sharedContractVersion: 'mf-ssr-contract-v1'
|
|
127
131
|
},
|
|
132
|
+
...createBackendFederationContract(scope, vertical) ? {
|
|
133
|
+
backendFederation: createBackendFederationContract(scope, vertical)
|
|
134
|
+
} : {},
|
|
135
|
+
...vertical.api ? {
|
|
136
|
+
deliveryUnit: deliveryUnitContractBlock(createDeliveryUnitRecord(scope, vertical))
|
|
137
|
+
} : {},
|
|
128
138
|
...apiTopologyMetadata(vertical) ? {
|
|
129
139
|
api: apiTopologyMetadata(vertical)
|
|
130
140
|
} : {},
|
|
@@ -365,6 +375,12 @@ function createDryRunJsonMutations(preflight, manifestUrl) {
|
|
|
365
375
|
pointer: `/apis/${vertical.id}`,
|
|
366
376
|
description: `Add local API URL for ${vertical.id}`,
|
|
367
377
|
value: `http://localhost:${vertical.port}${resolveApiPrefix(vertical)}`
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
path: DEVELOPMENT_OVERLAY_PATH,
|
|
381
|
+
pointer: `/serverExecution/${vertical.id}`,
|
|
382
|
+
description: `Add local MicroVertical server execution metadata for ${vertical.id}`,
|
|
383
|
+
value: createServerExecutionOverlay(scope, vertical)
|
|
368
384
|
}
|
|
369
385
|
] : [];
|
|
370
386
|
return [
|
|
@@ -480,6 +496,8 @@ function addUltramodernVertical(options) {
|
|
|
480
496
|
overlay.ports[vertical.id] = vertical.port;
|
|
481
497
|
overlay.manifests ??= {};
|
|
482
498
|
overlay.manifests[vertical.id] = `http://localhost:${vertical.port}/mf-manifest.json`;
|
|
499
|
+
overlay.serverExecution ??= {};
|
|
500
|
+
overlay.serverExecution[vertical.id] = createServerExecutionOverlay(scope, vertical);
|
|
483
501
|
overlay.apis ??= {};
|
|
484
502
|
overlay.apis[vertical.id] = `http://localhost:${vertical.port}${resolveApiPrefix(vertical)}`;
|
|
485
503
|
writeJsonFile(topologyPath, topology);
|
|
@@ -492,6 +510,13 @@ function addUltramodernVertical(options) {
|
|
|
492
510
|
},
|
|
493
511
|
...updatedVerticals
|
|
494
512
|
], enableTailwind, bridge));
|
|
513
|
+
writeFileReplacing(options.workspaceRoot, 'zerops.yaml', `${createZeropsYaml(scope, [
|
|
514
|
+
{
|
|
515
|
+
...shellApp,
|
|
516
|
+
verticalRefs: updatedVerticals.map((vertical)=>vertical.id)
|
|
517
|
+
},
|
|
518
|
+
...updatedVerticals
|
|
519
|
+
])}\n`);
|
|
495
520
|
rewriteShellAppFiles(options.workspaceRoot, scope, packageSource, enableTailwind, updatedVerticals, bridge);
|
|
496
521
|
writeGeneratedWorkspaceScripts(options.workspaceRoot, scope, enableTailwind, updatedVerticals);
|
|
497
522
|
addShellZephyrDependency(options.workspaceRoot, scope, vertical);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import {
|
|
2
|
+
import { BACKEND_FEDERATION_CONTRACT_VERSION, BACKEND_FEDERATION_NODE_ADAPTER_VERSION } from "./backend-federation.js";
|
|
3
|
+
import { appHasApi, createBackendFederationName, resolveApiPrefix, resolveApiStem, verticalApiApps } from "./descriptors.js";
|
|
3
4
|
import { packageName, toCamelCase, toPascalCase } from "./naming.js";
|
|
4
5
|
function verticalApiExport(service) {
|
|
5
6
|
return `${toCamelCase(resolveApiStem(service))}Api`;
|
|
@@ -640,6 +641,46 @@ const apiRuntime: EffectBffDefinition<typeof ${apiExport}, EffectRuntimeLayer> &
|
|
|
640
641
|
layer,
|
|
641
642
|
});
|
|
642
643
|
|
|
644
|
+
export default apiRuntime;
|
|
645
|
+
`;
|
|
646
|
+
}
|
|
647
|
+
function createBackendEffectApiExpose(scope, service) {
|
|
648
|
+
const apiExport = verticalApiExport(service);
|
|
649
|
+
const groupName = verticalApiGroupName(service);
|
|
650
|
+
const apiPrefix = resolveApiPrefix(service);
|
|
651
|
+
const stem = resolveApiStem(service);
|
|
652
|
+
return `import apiRuntime from './index.ts';
|
|
653
|
+
import { ultramodernApiMarker } from '../shared/ultramodern-build.ts';
|
|
654
|
+
import {
|
|
655
|
+
${apiExport},
|
|
656
|
+
${groupName}ApiContract,
|
|
657
|
+
${groupName}OperationContexts,
|
|
658
|
+
} from '../shared/api.ts';
|
|
659
|
+
|
|
660
|
+
export const backendFederationContract = {
|
|
661
|
+
compatibility: {
|
|
662
|
+
build: ultramodernApiMarker.build,
|
|
663
|
+
contractVersion: '${BACKEND_FEDERATION_CONTRACT_VERSION}',
|
|
664
|
+
nodeAdapterVersion: '${BACKEND_FEDERATION_NODE_ADAPTER_VERSION}',
|
|
665
|
+
packageName: '${packageName(scope, service.packageSuffix)}',
|
|
666
|
+
sourceRevision: ultramodernApiMarker.sourceRevision,
|
|
667
|
+
unitId: ultramodernApiMarker.unitId,
|
|
668
|
+
},
|
|
669
|
+
executionSurfaces: ['node-mf-runtime'],
|
|
670
|
+
exposes: ['./effect-api'],
|
|
671
|
+
name: '${createBackendFederationName(service)}',
|
|
672
|
+
openapiPath: '${apiPrefix}/openapi.json',
|
|
673
|
+
readinessPath: '${apiPrefix}/${stem}/readiness',
|
|
674
|
+
role: 'microvertical-server',
|
|
675
|
+
runtimeFramework: 'effect',
|
|
676
|
+
strictEffectApproach: true,
|
|
677
|
+
} as const;
|
|
678
|
+
|
|
679
|
+
export const api: unknown = ${apiExport};
|
|
680
|
+
export const contract = ${groupName}ApiContract;
|
|
681
|
+
export const operationContexts = ${groupName}OperationContexts;
|
|
682
|
+
export const runtime = apiRuntime;
|
|
683
|
+
|
|
643
684
|
export default apiRuntime;
|
|
644
685
|
`;
|
|
645
686
|
}
|
|
@@ -982,4 +1023,4 @@ function createApiOperationContract(target) {
|
|
|
982
1023
|
}
|
|
983
1024
|
};
|
|
984
1025
|
}
|
|
985
|
-
export { apiTopologyMetadata, createApiClient, createApiDomainOperations, createApiOperationContract, createApiReadinessContract, createApiRequestContextContract, createApiServiceEntry, createSharedApi, createSharedApiContract, createSharedApiImports, createShellApiClient, verticalApiCreatePayloadSchemaExport, verticalApiErrorStem, verticalApiExport, verticalApiGroupName, verticalApiMarkerSchemaExport, verticalApiName, verticalApiNotFoundErrorExport, verticalApiNotFoundSchemaExport, verticalApiReadinessSchemaExport, verticalApiSchemaExport };
|
|
1026
|
+
export { apiTopologyMetadata, createApiClient, createApiDomainOperations, createApiOperationContract, createApiReadinessContract, createApiRequestContextContract, createApiServiceEntry, createBackendEffectApiExpose, createSharedApi, createSharedApiContract, createSharedApiImports, createShellApiClient, verticalApiCreatePayloadSchemaExport, verticalApiErrorStem, verticalApiExport, verticalApiGroupName, verticalApiMarkerSchemaExport, verticalApiName, verticalApiNotFoundErrorExport, verticalApiNotFoundSchemaExport, verticalApiReadinessSchemaExport, verticalApiSchemaExport };
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { verticalApiExport, verticalApiGroupName } from "./api.js";
|
|
3
|
+
import { createDeliveryUnitRecord, deliveryUnitContractBlock } from "./delivery-unit.js";
|
|
4
|
+
import { appHasApi, createBackendFederationContainerEntry, createBackendFederationManifestEnv, createBackendFederationManifestUrl, createBackendFederationName, createCloudflarePublicUrlEnv, createCloudflareWorkerName, createRemoteManifestEnv, resolveApiPrefix, resolveApiStem } from "./descriptors.js";
|
|
5
|
+
import { packageName, toEnvSegment } from "./naming.js";
|
|
6
|
+
import { EFFECT_VERSION, MODULE_FEDERATION_VERSION } from "./versions.js";
|
|
7
|
+
const BACKEND_FEDERATION_CONTRACT_VERSION = 'microvertical-server-effect-v1';
|
|
8
|
+
const BACKEND_FEDERATION_NODE_ADAPTER_VERSION = 'backend-mf-effect-v1';
|
|
9
|
+
function createZephyrEnv(app, suffix) {
|
|
10
|
+
return `ZEPHYR_${toEnvSegment(app.domain ?? app.id)}_${suffix}`;
|
|
11
|
+
}
|
|
12
|
+
function createWorkerBindingName(app) {
|
|
13
|
+
return `VERTICAL_${toEnvSegment(app.domain ?? app.id)}_WORKER`;
|
|
14
|
+
}
|
|
15
|
+
function createWorkerBindingEnv(app) {
|
|
16
|
+
return `VERTICAL_${toEnvSegment(app.domain ?? app.id)}_WORKER_BINDING`;
|
|
17
|
+
}
|
|
18
|
+
function createDispatchNamespaceEnv(app) {
|
|
19
|
+
return `VERTICAL_${toEnvSegment(app.domain ?? app.id)}_DISPATCH_NAMESPACE`;
|
|
20
|
+
}
|
|
21
|
+
function createDispatchWorkerNameEnv(app) {
|
|
22
|
+
return `VERTICAL_${toEnvSegment(app.domain ?? app.id)}_WORKER_NAME`;
|
|
23
|
+
}
|
|
24
|
+
function createEffectExpose(app) {
|
|
25
|
+
const apiStem = resolveApiStem(app);
|
|
26
|
+
return {
|
|
27
|
+
contract: `${app.directory}/shared/api.ts`,
|
|
28
|
+
runtime: `${app.directory}/api/index.ts`,
|
|
29
|
+
client: `${app.directory}/src/api/${app.api.stem}-client.ts`,
|
|
30
|
+
openapi: `${app.api.prefix}/openapi.json`,
|
|
31
|
+
readiness: `${app.api.prefix}/${apiStem}/readiness`
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function createCloudflareExecutionSurface(scope, app) {
|
|
35
|
+
return {
|
|
36
|
+
kind: 'cloudflare-worker-snapshot',
|
|
37
|
+
workerName: createCloudflareWorkerName(scope, app),
|
|
38
|
+
publicUrlEnv: createCloudflarePublicUrlEnv(app),
|
|
39
|
+
ssr: {
|
|
40
|
+
workerEntry: '.output/server/index.mjs',
|
|
41
|
+
workerManifest: '.output/server/modern-worker-manifest.json',
|
|
42
|
+
routeManifest: '.output/server/route.json',
|
|
43
|
+
ssrBundle: '.output/worker/index.js',
|
|
44
|
+
effectBffBundle: '.output/worker/__modern_bff_effect.js',
|
|
45
|
+
assetsBinding: 'ASSETS'
|
|
46
|
+
},
|
|
47
|
+
zephyr: {
|
|
48
|
+
runtime: 'ssr-worker',
|
|
49
|
+
integration: 'managed-cloudflare',
|
|
50
|
+
snapshotIdEnv: createZephyrEnv(app, 'SNAPSHOT_ID'),
|
|
51
|
+
versionIdEnv: createZephyrEnv(app, 'VERSION_ID'),
|
|
52
|
+
applicationUidEnv: createZephyrEnv(app, 'APPLICATION_UID')
|
|
53
|
+
},
|
|
54
|
+
workerDispatch: {
|
|
55
|
+
preferred: 'service-binding',
|
|
56
|
+
serviceBinding: createWorkerBindingName(app),
|
|
57
|
+
serviceBindingEnv: createWorkerBindingEnv(app),
|
|
58
|
+
dispatchNamespaceEnv: createDispatchNamespaceEnv(app),
|
|
59
|
+
dispatchWorkerNameEnv: createDispatchWorkerNameEnv(app),
|
|
60
|
+
requestInterface: 'fetch'
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function createNodeExecutionSurface(app) {
|
|
65
|
+
return {
|
|
66
|
+
kind: 'node-mf-runtime',
|
|
67
|
+
adapterVersion: BACKEND_FEDERATION_NODE_ADAPTER_VERSION,
|
|
68
|
+
remoteName: createBackendFederationName(app),
|
|
69
|
+
manifestEnv: createBackendFederationManifestEnv(app),
|
|
70
|
+
manifestUrl: createBackendFederationManifestUrl(app),
|
|
71
|
+
containerEntry: createBackendFederationContainerEntry(app),
|
|
72
|
+
remoteType: 'module',
|
|
73
|
+
expose: './effect-api',
|
|
74
|
+
runtimePackage: '@modern-js/plugin-bff/effect'
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function createServerExecutionOverlay(scope, app) {
|
|
78
|
+
if (!appHasApi(app)) return;
|
|
79
|
+
const deliveryUnit = createDeliveryUnitRecord(scope, app);
|
|
80
|
+
return {
|
|
81
|
+
apiBaseUrl: `http://localhost:${app.port}${resolveApiPrefix(app)}`,
|
|
82
|
+
versionBoundary: 'web-and-api-same-build',
|
|
83
|
+
deliveryUnit: {
|
|
84
|
+
unitId: deliveryUnit.unitId,
|
|
85
|
+
buildMarker: deliveryUnit.buildMarker
|
|
86
|
+
},
|
|
87
|
+
cloudflare: createCloudflareExecutionSurface(scope, app),
|
|
88
|
+
node: createNodeExecutionSurface(app)
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function createBackendFederationContract(scope, app) {
|
|
92
|
+
if (!appHasApi(app)) return;
|
|
93
|
+
const readiness = `${app.api.prefix}/${resolveApiStem(app)}/readiness`;
|
|
94
|
+
const deliveryUnit = createDeliveryUnitRecord(scope, app);
|
|
95
|
+
return {
|
|
96
|
+
role: 'microvertical-server',
|
|
97
|
+
name: createBackendFederationName(app),
|
|
98
|
+
runtimeFramework: 'effect',
|
|
99
|
+
strictEffectApproach: true,
|
|
100
|
+
deliveryUnit: deliveryUnitContractBlock(deliveryUnit),
|
|
101
|
+
exposes: {
|
|
102
|
+
'./effect-api': createEffectExpose(app)
|
|
103
|
+
},
|
|
104
|
+
versionBoundary: {
|
|
105
|
+
invariant: 'web-and-api-same-build',
|
|
106
|
+
identityRoot: 'deliveryUnit',
|
|
107
|
+
packageName: packageName(scope, app.packageSuffix),
|
|
108
|
+
ui: {
|
|
109
|
+
manifestEnv: createRemoteManifestEnv(app),
|
|
110
|
+
manifestUrl: `http://localhost:${app.port}/mf-manifest.json`,
|
|
111
|
+
buildMarker: `${app.directory}/src/routes/ultramodern-route-metadata.ts`
|
|
112
|
+
},
|
|
113
|
+
api: {
|
|
114
|
+
readiness,
|
|
115
|
+
buildMarker: `${app.directory}/shared/ultramodern-build.ts`,
|
|
116
|
+
publicUrlEnv: createCloudflarePublicUrlEnv(app)
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
executionSurfaces: {
|
|
120
|
+
cloudflare: createCloudflareExecutionSurface(scope, app),
|
|
121
|
+
node: createNodeExecutionSurface(app)
|
|
122
|
+
},
|
|
123
|
+
compatibility: {
|
|
124
|
+
contractVersion: BACKEND_FEDERATION_CONTRACT_VERSION,
|
|
125
|
+
packageName: packageName(scope, app.packageSuffix),
|
|
126
|
+
effectVersion: EFFECT_VERSION,
|
|
127
|
+
moduleFederationVersion: MODULE_FEDERATION_VERSION
|
|
128
|
+
},
|
|
129
|
+
cache: {
|
|
130
|
+
cloudflareSnapshot: 'immutable',
|
|
131
|
+
nodeManifest: 'no-store',
|
|
132
|
+
nodeVersionedContainer: 'immutable',
|
|
133
|
+
nodeUnpinnedContainer: 'revalidate'
|
|
134
|
+
},
|
|
135
|
+
fallback: {
|
|
136
|
+
timeoutMs: 1500,
|
|
137
|
+
failureEvent: 'modernjs:microvertical-server-fallback',
|
|
138
|
+
strategy: 'typed-effect-error'
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function createBackendFederationMetadata(scope, app) {
|
|
143
|
+
if (!appHasApi(app)) return;
|
|
144
|
+
return {
|
|
145
|
+
contractVersion: BACKEND_FEDERATION_CONTRACT_VERSION,
|
|
146
|
+
deliveryUnit: deliveryUnitContractBlock(createDeliveryUnitRecord(scope, app)),
|
|
147
|
+
executionSurfaces: [
|
|
148
|
+
'node-mf-runtime'
|
|
149
|
+
],
|
|
150
|
+
exposes: [
|
|
151
|
+
'./effect-api'
|
|
152
|
+
],
|
|
153
|
+
name: createBackendFederationName(app),
|
|
154
|
+
nodeAdapterVersion: BACKEND_FEDERATION_NODE_ADAPTER_VERSION,
|
|
155
|
+
openapiPath: `${app.api.prefix}/openapi.json`,
|
|
156
|
+
readinessPath: `${app.api.prefix}/${resolveApiStem(app)}/readiness`,
|
|
157
|
+
role: 'microvertical-server',
|
|
158
|
+
runtimeFramework: 'effect',
|
|
159
|
+
strictEffectApproach: true
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function createBackendFederationContractFile(app) {
|
|
163
|
+
if (!app.api) throw new Error(`App ${app.id} does not define an Effect API.`);
|
|
164
|
+
const apiExport = verticalApiExport(app);
|
|
165
|
+
const groupName = verticalApiGroupName(app);
|
|
166
|
+
const readinessPath = `${app.api.prefix}/${resolveApiStem(app)}/readiness`;
|
|
167
|
+
return `import runtime from './index.ts';
|
|
168
|
+
import { ultramodernApiMarker } from '../shared/ultramodern-build.ts';
|
|
169
|
+
import {
|
|
170
|
+
${apiExport} as api,
|
|
171
|
+
${groupName}ApiContract as contract,
|
|
172
|
+
${groupName}OperationContexts as operationContexts,
|
|
173
|
+
} from '../shared/api.ts';
|
|
174
|
+
|
|
175
|
+
export const backendFederationContract = {
|
|
176
|
+
compatibility: {
|
|
177
|
+
build: ultramodernApiMarker.build,
|
|
178
|
+
contractVersion: '${BACKEND_FEDERATION_CONTRACT_VERSION}',
|
|
179
|
+
nodeAdapterVersion: '${BACKEND_FEDERATION_NODE_ADAPTER_VERSION}',
|
|
180
|
+
packageName: ultramodernApiMarker.packageName,
|
|
181
|
+
sourceRevision: ultramodernApiMarker.sourceRevision,
|
|
182
|
+
unitId: ultramodernApiMarker.unitId,
|
|
183
|
+
},
|
|
184
|
+
contractVersion: '${BACKEND_FEDERATION_CONTRACT_VERSION}',
|
|
185
|
+
executionSurfaces: ['node-mf-runtime'],
|
|
186
|
+
exposes: ['./effect-api'],
|
|
187
|
+
name: '${createBackendFederationName(app)}',
|
|
188
|
+
nodeAdapterVersion: '${BACKEND_FEDERATION_NODE_ADAPTER_VERSION}',
|
|
189
|
+
openapiPath: '${app.api.prefix}/openapi.json',
|
|
190
|
+
readinessPath: '${readinessPath}',
|
|
191
|
+
role: 'microvertical-server',
|
|
192
|
+
runtimeFramework: 'effect',
|
|
193
|
+
strictEffectApproach: true,
|
|
194
|
+
} as const;
|
|
195
|
+
|
|
196
|
+
export { api, contract, operationContexts, runtime };
|
|
197
|
+
|
|
198
|
+
export default runtime;
|
|
199
|
+
`;
|
|
200
|
+
}
|
|
201
|
+
function createBackendFederationSummary(scope, app) {
|
|
202
|
+
if (!appHasApi(app)) return;
|
|
203
|
+
return {
|
|
204
|
+
id: app.id,
|
|
205
|
+
path: app.directory,
|
|
206
|
+
role: 'microvertical-server',
|
|
207
|
+
name: createBackendFederationName(app),
|
|
208
|
+
runtimeFramework: 'effect',
|
|
209
|
+
strictEffectApproach: true,
|
|
210
|
+
contractVersion: BACKEND_FEDERATION_CONTRACT_VERSION,
|
|
211
|
+
deliveryUnit: deliveryUnitContractBlock(createDeliveryUnitRecord(scope, app)),
|
|
212
|
+
executionSurfaces: {
|
|
213
|
+
cloudflare: createCloudflareExecutionSurface(scope, app),
|
|
214
|
+
node: createNodeExecutionSurface(app)
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
export { BACKEND_FEDERATION_CONTRACT_VERSION, BACKEND_FEDERATION_NODE_ADAPTER_VERSION, createBackendFederationContract, createBackendFederationContractFile, createBackendFederationMetadata, createBackendFederationSummary, createDispatchWorkerNameEnv, createServerExecutionOverlay, createWorkerBindingEnv, createWorkerBindingName };
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import { apiTopologyMetadata } from "./api.js";
|
|
3
|
+
import { createBackendFederationContract, createBackendFederationSummary, createServerExecutionOverlay } from "./backend-federation.js";
|
|
4
|
+
import { createDeliveryUnitRecord, deliveryUnitContractBlock } from "./delivery-unit.js";
|
|
3
5
|
import { createModuleFederationRemoteContracts, createShellHost, resolveApiPrefix, sharedPackages, shellApp, verticalApiApps } from "./descriptors.js";
|
|
4
6
|
import { packageName } from "./naming.js";
|
|
5
7
|
import { createCloudflareDeployContract } from "./policy.js";
|
|
8
|
+
import { createGeneratedToolingWrapperMap } from "./tooling-command-catalog.js";
|
|
6
9
|
import { CLOUDFLARE_COMPATIBILITY_DATE, NODE_VERSION, PNPM_VERSION } from "./versions.js";
|
|
7
10
|
function createTopology(scope, remotes = []) {
|
|
8
11
|
const shellHost = createShellHost(remotes);
|
|
@@ -45,6 +48,12 @@ function createTopology(scope, remotes = []) {
|
|
|
45
48
|
fallbackTelemetryEvent: 'modernjs:mv-runtime-parity',
|
|
46
49
|
sharedContractVersion: 'mf-ssr-contract-v1'
|
|
47
50
|
},
|
|
51
|
+
...createBackendFederationContract(scope, vertical) ? {
|
|
52
|
+
backendFederation: createBackendFederationContract(scope, vertical)
|
|
53
|
+
} : {},
|
|
54
|
+
...vertical.api ? {
|
|
55
|
+
deliveryUnit: deliveryUnitContractBlock(createDeliveryUnitRecord(scope, vertical))
|
|
56
|
+
} : {},
|
|
48
57
|
...apiTopologyMetadata(vertical) ? {
|
|
49
58
|
api: apiTopologyMetadata(vertical)
|
|
50
59
|
} : {},
|
|
@@ -100,7 +109,7 @@ function createOwnership(scope, remotes = []) {
|
|
|
100
109
|
}))
|
|
101
110
|
};
|
|
102
111
|
}
|
|
103
|
-
function createDevelopmentOverlay(remotes = []) {
|
|
112
|
+
function createDevelopmentOverlay(scope, remotes = []) {
|
|
104
113
|
return {
|
|
105
114
|
schemaVersion: 1,
|
|
106
115
|
environment: 'development',
|
|
@@ -116,6 +125,10 @@ function createDevelopmentOverlay(remotes = []) {
|
|
|
116
125
|
remote.id,
|
|
117
126
|
`http://localhost:${remote.port}/mf-manifest.json`
|
|
118
127
|
])),
|
|
128
|
+
serverExecution: Object.fromEntries(verticalApiApps(remotes).map((app)=>[
|
|
129
|
+
app.id,
|
|
130
|
+
createServerExecutionOverlay(scope, app)
|
|
131
|
+
])),
|
|
119
132
|
apis: Object.fromEntries(verticalApiApps(remotes).map((app)=>[
|
|
120
133
|
app.id,
|
|
121
134
|
`http://localhost:${app.port}${resolveApiPrefix(app)}`
|
|
@@ -192,6 +205,12 @@ function createUltramodernConfig(scope, modernVersion, packageSource, apps = [
|
|
|
192
205
|
tsConfigPath: './tsconfig.mf-types.json'
|
|
193
206
|
}
|
|
194
207
|
},
|
|
208
|
+
...createBackendFederationContract(scope, app) ? {
|
|
209
|
+
backendFederation: createBackendFederationContract(scope, app)
|
|
210
|
+
} : {},
|
|
211
|
+
...app.api ? {
|
|
212
|
+
deliveryUnit: deliveryUnitContractBlock(createDeliveryUnitRecord(scope, app))
|
|
213
|
+
} : {},
|
|
195
214
|
...app.api ? {
|
|
196
215
|
api: {
|
|
197
216
|
stem: app.api.stem,
|
|
@@ -235,6 +254,9 @@ function createUltramodernConfig(scope, modernVersion, packageSource, apps = [
|
|
|
235
254
|
hostOnly: 'shell' === app.kind && 0 === Object.keys(app.exposes ?? {}).length
|
|
236
255
|
}))
|
|
237
256
|
},
|
|
257
|
+
backendFederation: {
|
|
258
|
+
apps: verticalApiApps(remotes).map((app)=>createBackendFederationSummary(scope, app))
|
|
259
|
+
},
|
|
238
260
|
agentSkills: {
|
|
239
261
|
target: 'codex',
|
|
240
262
|
lockfile: './.codex/skills-lock.json',
|
|
@@ -249,13 +271,7 @@ function createUltramodernConfig(scope, modernVersion, packageSource, apps = [
|
|
|
249
271
|
tooling: {
|
|
250
272
|
command: 'modern-js-create ultramodern',
|
|
251
273
|
wrappers: {
|
|
252
|
-
|
|
253
|
-
typecheck: "scripts/ultramodern-typecheck.mts",
|
|
254
|
-
mfTypes: "scripts/assert-mf-types.mts",
|
|
255
|
-
publicSurface: "scripts/generate-public-surface-assets.mts",
|
|
256
|
-
cloudflareProof: "scripts/proof-cloudflare-version.mts",
|
|
257
|
-
performanceReadiness: "scripts/ultramodern-performance-readiness.mts",
|
|
258
|
-
migrateStrictEffect: "scripts/migrate-strict-effect.mts",
|
|
274
|
+
...createGeneratedToolingWrapperMap(),
|
|
259
275
|
apiBoundaries: "scripts/check-ultramodern-api-boundaries.mts",
|
|
260
276
|
skills: "scripts/bootstrap-agent-skills.mts"
|
|
261
277
|
}
|