@bleedingdev/modern-js-create 3.5.0-ultramodern.28 → 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
|
@@ -27,6 +27,10 @@ export declare function remoteDependencyAlias(remote: WorkspaceApp): string;
|
|
|
27
27
|
export declare function zephyrRemoteDependency(scope: string, remote: WorkspaceApp): string;
|
|
28
28
|
export declare function resolveRemoteRefs(app: WorkspaceApp, remotes?: WorkspaceApp[]): WorkspaceApp[];
|
|
29
29
|
export declare function createRemoteManifestEnv(remote: WorkspaceApp): string;
|
|
30
|
+
export declare function createBackendFederationManifestEnv(remote: WorkspaceApp): string;
|
|
31
|
+
export declare function createBackendFederationName(app: WorkspaceApp): string;
|
|
32
|
+
export declare function createBackendFederationManifestUrl(app: WorkspaceApp): string;
|
|
33
|
+
export declare function createBackendFederationContainerEntry(app: WorkspaceApp): string;
|
|
30
34
|
export declare function createModuleFederationRemoteContracts(app: WorkspaceApp, remotes?: WorkspaceApp[]): {
|
|
31
35
|
id: string;
|
|
32
36
|
alias: string;
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import type { WorkspaceApp } from './types';
|
|
2
|
-
export declare function createAppModernConfig(scope: string, app: WorkspaceApp): string;
|
|
2
|
+
export declare function createAppModernConfig(scope: string, app: WorkspaceApp, remotes?: WorkspaceApp[]): string;
|
|
3
3
|
export declare function createSharedModuleFederationConfig(): string;
|
|
4
4
|
export declare function formatTsObjectLiteral(value: Record<string, string>): string;
|
|
5
5
|
export declare function createModuleFederationRemoteUrlHelpers(app: WorkspaceApp, remotes?: WorkspaceApp[]): string;
|
|
6
6
|
export declare function createModuleFederationRemotesConfig(scope: string, app: WorkspaceApp, remotes?: WorkspaceApp[]): string;
|
|
7
7
|
export declare function createShellModuleFederationConfig(scope: string, remotes?: WorkspaceApp[]): string;
|
|
8
|
-
export declare function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}): any;
|
|
12
|
-
export declare function createUltramodernBuildModule(scope: string, app: {
|
|
13
|
-
id: string;
|
|
14
|
-
packageSuffix: string;
|
|
15
|
-
}): string;
|
|
8
|
+
export declare function createBackendModuleFederationConfig(app: WorkspaceApp): string;
|
|
9
|
+
export { createBuildMarker } from './delivery-unit';
|
|
10
|
+
export declare function createUltramodernBuildModule(scope: string, app: WorkspaceApp): string;
|
|
16
11
|
export declare function createUltramodernBuildReexportModule(): string;
|
|
17
12
|
export declare function createRemoteModuleFederationConfig(scope: string, app: WorkspaceApp, remotes?: WorkspaceApp[]): string;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { UltramodernBridgeConfig } from './bridge-config';
|
|
2
2
|
import type { JsonValue, ResolvedPackageSource, WorkspaceApp } from './types';
|
|
3
|
-
export declare const createStrictTsgoTypecheckCommand: (packageDir: string) => string;
|
|
4
3
|
export declare const effectDiagnostics: string[];
|
|
5
4
|
export declare function appDependencies(scope: string, packageSource: ResolvedPackageSource, app: WorkspaceApp, remotes?: WorkspaceApp[], bridge?: UltramodernBridgeConfig): Record<string, string>;
|
|
6
5
|
export declare function appDevDependencies(packageSource: ResolvedPackageSource, enableTailwind: boolean): Record<string, string>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export declare const strictEffectPackageVersionPolicyExclusions: string[];
|
|
2
|
+
export declare const moduleFederationModernJsPatchPath = "patches/@module-federation__modern-js-v3@2.6.0.patch";
|
|
3
|
+
export declare const moduleFederationBridgeReactPatchPath = "patches/@module-federation__bridge-react@2.6.0.patch";
|
|
4
|
+
export declare const effectDeclarationPatchPath = "patches/effect-schema-error-type-id.patch";
|
|
5
|
+
export declare const drizzleOrmDeclarationPatchPath = "patches/drizzle-orm-ts7-strict-declarations.patch";
|
|
6
|
+
export type PnpmWorkspaceYamlAction = {
|
|
7
|
+
kind: 'replace-line';
|
|
8
|
+
pattern: RegExp;
|
|
9
|
+
replacement: string;
|
|
10
|
+
} | {
|
|
11
|
+
kind: 'ensure-scalar-map-entry';
|
|
12
|
+
key: string;
|
|
13
|
+
entryKey: string;
|
|
14
|
+
value: string;
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'ensure-list-item';
|
|
17
|
+
key: string;
|
|
18
|
+
item: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'ensure-map-entry';
|
|
21
|
+
key: string;
|
|
22
|
+
entryKey: string;
|
|
23
|
+
value: string;
|
|
24
|
+
} | {
|
|
25
|
+
kind: 'remove-map-entry';
|
|
26
|
+
entryKey: string;
|
|
27
|
+
};
|
|
28
|
+
export type GeneratedDeclarationPatchAction = {
|
|
29
|
+
kind: 'ensure' | 'remove-if-unchanged';
|
|
30
|
+
relativePatchPath: string;
|
|
31
|
+
};
|
|
32
|
+
export type PnpmWorkspacePolicyPlan = {
|
|
33
|
+
yamlActions: PnpmWorkspaceYamlAction[];
|
|
34
|
+
declarationPatchActions: GeneratedDeclarationPatchAction[];
|
|
35
|
+
requiresInstallOnChange: boolean;
|
|
36
|
+
};
|
|
37
|
+
export declare function createPnpmWorkspacePolicyPlan(options: {
|
|
38
|
+
usesDrizzleOrm: boolean;
|
|
39
|
+
}): PnpmWorkspacePolicyPlan;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type GeneratedToolingCommandId = 'validate' | 'typecheck' | 'mfTypes' | 'publicSurface' | 'backendFederationGenerate' | 'backendFederationProof' | 'cloudflareProof' | 'cloudflareOutputVerify' | 'performanceReadiness' | 'migrateStrictEffect' | 'routesGenerate';
|
|
2
|
+
export type GeneratedToolingCommandKey = GeneratedToolingCommandId;
|
|
3
|
+
export interface GeneratedToolingCommand {
|
|
4
|
+
id: GeneratedToolingCommandId;
|
|
5
|
+
command: string;
|
|
6
|
+
wrapperName: string;
|
|
7
|
+
wrapperPath: `scripts/${string}.mts`;
|
|
8
|
+
contractKey: string;
|
|
9
|
+
rootScript?: string;
|
|
10
|
+
templatePath?: `templates/workspace-scripts/${string}.mjs`;
|
|
11
|
+
cwd?: 'invocation';
|
|
12
|
+
}
|
|
13
|
+
export declare const generatedToolingCommands: readonly [GeneratedToolingCommand, GeneratedToolingCommand, GeneratedToolingCommand, GeneratedToolingCommand, GeneratedToolingCommand, GeneratedToolingCommand, GeneratedToolingCommand, GeneratedToolingCommand, GeneratedToolingCommand, GeneratedToolingCommand, GeneratedToolingCommand];
|
|
14
|
+
export declare const toolingCommandById: Record<GeneratedToolingCommandId, GeneratedToolingCommand>;
|
|
15
|
+
export declare const GENERATED_TOOLING_COMMANDS: Record<GeneratedToolingCommandId, GeneratedToolingCommand>;
|
|
16
|
+
export declare const generatedToolingCommandList: () => string[];
|
|
17
|
+
export declare const createToolingWrapperContract: () => Record<GeneratedToolingCommandKey, GeneratedToolingCommand['wrapperPath']>;
|
|
18
|
+
export declare const createGeneratedToolingWrapperMap: () => Record<GeneratedToolingCommandKey, GeneratedToolingCommand['wrapperPath']>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type GeneratedToolingCommandKey } from './tooling-command-catalog';
|
|
2
|
+
import type { WorkspaceApp } from './types';
|
|
3
|
+
export declare const rootToolingScriptName: (key: GeneratedToolingCommandKey) => string;
|
|
4
|
+
export declare const rootToolingWrapperCommand: (key: GeneratedToolingCommandKey) => string;
|
|
5
|
+
export declare const packageToolingWrapperCommand: (packageDir: string, key: GeneratedToolingCommandKey) => string;
|
|
6
|
+
export interface WorkspaceRootScriptPlan {
|
|
7
|
+
build: string;
|
|
8
|
+
cloudflareBuild: string;
|
|
9
|
+
cloudflareDeploy: string;
|
|
10
|
+
cloudflareProof: string;
|
|
11
|
+
cloudflareOutputVerify: string;
|
|
12
|
+
backendFederationGenerate: string;
|
|
13
|
+
nodeProof: string;
|
|
14
|
+
mfTypes: string;
|
|
15
|
+
performanceReadiness: string;
|
|
16
|
+
migrateStrictEffect: string;
|
|
17
|
+
zeropsMaterialize: string;
|
|
18
|
+
contractCheck: string;
|
|
19
|
+
typecheck: string;
|
|
20
|
+
check: string;
|
|
21
|
+
}
|
|
22
|
+
export declare const workspaceRootPackageScriptNames: {
|
|
23
|
+
readonly build: 'build';
|
|
24
|
+
readonly cloudflareBuild: 'cloudflare:build';
|
|
25
|
+
readonly cloudflareDeploy: 'cloudflare:deploy';
|
|
26
|
+
readonly cloudflareProof: string;
|
|
27
|
+
readonly cloudflareOutputVerify: string;
|
|
28
|
+
readonly backendFederationGenerate: string;
|
|
29
|
+
readonly nodeProof: string;
|
|
30
|
+
readonly mfTypes: string;
|
|
31
|
+
readonly performanceReadiness: string;
|
|
32
|
+
readonly migrateStrictEffect: string;
|
|
33
|
+
readonly zeropsMaterialize: 'zerops:materialize';
|
|
34
|
+
readonly contractCheck: string;
|
|
35
|
+
readonly typecheck: 'typecheck';
|
|
36
|
+
readonly check: 'check';
|
|
37
|
+
};
|
|
38
|
+
export type WorkspaceRootPackageScriptName = (typeof workspaceRootPackageScriptNames)[keyof typeof workspaceRootPackageScriptNames];
|
|
39
|
+
export type WorkspaceRootPackageScripts = Record<WorkspaceRootPackageScriptName, string>;
|
|
40
|
+
export interface WorkspaceAppScriptPlan {
|
|
41
|
+
dev: string;
|
|
42
|
+
build: string;
|
|
43
|
+
cloudflareBuild: string;
|
|
44
|
+
cloudflareDeploy: string;
|
|
45
|
+
cloudflarePreview: string;
|
|
46
|
+
cloudflareProof: string;
|
|
47
|
+
serve: string;
|
|
48
|
+
typecheck: string;
|
|
49
|
+
}
|
|
50
|
+
export declare const workspaceAppPackageScriptNames: {
|
|
51
|
+
readonly dev: 'dev';
|
|
52
|
+
readonly build: 'build';
|
|
53
|
+
readonly cloudflareBuild: 'cloudflare:build';
|
|
54
|
+
readonly cloudflareDeploy: 'cloudflare:deploy';
|
|
55
|
+
readonly cloudflarePreview: 'cloudflare:preview';
|
|
56
|
+
readonly cloudflareProof: 'cloudflare:proof';
|
|
57
|
+
readonly serve: 'serve';
|
|
58
|
+
readonly typecheck: 'typecheck';
|
|
59
|
+
};
|
|
60
|
+
export type WorkspaceAppPackageScriptName = (typeof workspaceAppPackageScriptNames)[keyof typeof workspaceAppPackageScriptNames];
|
|
61
|
+
export type WorkspaceAppPackageScripts = Record<WorkspaceAppPackageScriptName, string>;
|
|
62
|
+
export declare const createStrictTsgoTypecheckCommand: (packageDir: string) => string;
|
|
63
|
+
export declare function createWorkspaceAppScriptPlan(app: WorkspaceApp): WorkspaceAppScriptPlan;
|
|
64
|
+
export declare function createWorkspaceAppPackageScripts(app: WorkspaceApp): WorkspaceAppPackageScripts;
|
|
65
|
+
export declare function createWorkspaceRootScriptPlan(remotes?: WorkspaceApp[], options?: {
|
|
66
|
+
bridgeCheck?: string;
|
|
67
|
+
typecheck?: string;
|
|
68
|
+
}): WorkspaceRootScriptPlan;
|
|
69
|
+
export declare function createWorkspaceRootPackageScripts(remotes?: WorkspaceApp[], options?: {
|
|
70
|
+
bridgeCheck?: string;
|
|
71
|
+
typecheck?: string;
|
|
72
|
+
}): WorkspaceRootPackageScripts;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { WorkspaceApp } from './types';
|
|
2
|
+
export declare function writeGeneratedToolWrapperScripts(targetDir: string): void;
|
|
2
3
|
export declare function createWorkspaceValidationScript(scope: string, enableTailwind: boolean, remotes?: WorkspaceApp[]): string;
|
|
3
4
|
export declare function createWorkspaceI18nBoundaryValidationScript(): string;
|
|
4
5
|
export declare function createWorkspaceApiBoundaryValidationScript(): string;
|
|
5
6
|
export declare function createPerformanceReadinessConfigScript(): string;
|
|
7
|
+
export declare function createNodeBackendFederationProofScript(): string;
|
|
8
|
+
export declare function createZeropsRuntimeMaterializationScript(): string;
|
|
6
9
|
export declare function writeGeneratedWorkspaceScripts(targetDir: string, _scope: string, _enableTailwind: boolean, _remotes?: WorkspaceApp[]): void;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { WorkspaceApp } from './types';
|
|
2
|
+
export type WorkspaceValidationContract = ReturnType<typeof createWorkspaceValidationContract>;
|
|
3
|
+
export declare function createWorkspaceValidationContract(scope: string, enableTailwind: boolean, remotes?: WorkspaceApp[]): {
|
|
4
|
+
packageScope: string;
|
|
5
|
+
versions: {
|
|
6
|
+
cloudflareCompatibilityDate: string;
|
|
7
|
+
effect: string;
|
|
8
|
+
moduleFederation: string;
|
|
9
|
+
node: string;
|
|
10
|
+
pnpm: string;
|
|
11
|
+
};
|
|
12
|
+
tailwindEnabled: boolean;
|
|
13
|
+
fullStackVerticals: {
|
|
14
|
+
id: string;
|
|
15
|
+
domain: string | undefined;
|
|
16
|
+
stem: string;
|
|
17
|
+
group: string;
|
|
18
|
+
path: string;
|
|
19
|
+
port: number;
|
|
20
|
+
mfName: string;
|
|
21
|
+
apiPrefix: string;
|
|
22
|
+
tailwindPrefix: string;
|
|
23
|
+
zephyrAlias: string;
|
|
24
|
+
packageName: string;
|
|
25
|
+
backendFederation: import("./types").JsonValue | undefined;
|
|
26
|
+
deliveryUnit: import("./delivery-unit").DeliveryUnitRecord;
|
|
27
|
+
exposes: string[];
|
|
28
|
+
componentPaths: string[];
|
|
29
|
+
namespace: string;
|
|
30
|
+
routePagePaths: string[];
|
|
31
|
+
routeMetaPaths: string[];
|
|
32
|
+
localisedUrls: Record<string, import("./types").JsonValue>;
|
|
33
|
+
verticalRefs: string[];
|
|
34
|
+
}[];
|
|
35
|
+
shellNamespace: string;
|
|
36
|
+
oldRemotePaths: string[];
|
|
37
|
+
scripts: import("./workspace-script-plan").WorkspaceRootScriptPlan;
|
|
38
|
+
packageScripts: import("./workspace-script-plan").WorkspaceRootPackageScripts;
|
|
39
|
+
cloudflareSecurity: import("./types").JsonValue;
|
|
40
|
+
publicSurfaceManagedSourceAssetPaths: ("config/public/robots.txt" | "config/public/site.webmanifest" | "config/public/sitemap.xml")[];
|
|
41
|
+
shellRouteMetaPaths: string[];
|
|
42
|
+
};
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"engines": {
|
|
22
22
|
"node": ">=20"
|
|
23
23
|
},
|
|
24
|
-
"version": "3.5.0-ultramodern.
|
|
24
|
+
"version": "3.5.0-ultramodern.29",
|
|
25
25
|
"types": "./dist/types/index.d.ts",
|
|
26
26
|
"main": "./dist/esm-node/index.js",
|
|
27
27
|
"bin": {
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"@modern-js/codesmith": "2.6.9",
|
|
78
78
|
"oxfmt": "0.56.0",
|
|
79
79
|
"ultracite": "7.8.3",
|
|
80
|
-
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.
|
|
80
|
+
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.29"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
83
|
"@rslib/core": "0.23.1",
|
|
@@ -99,6 +99,6 @@
|
|
|
99
99
|
"test": "rm -rf dist && rslib build -c rslibconfig.mts && rstest --passWithNoTests"
|
|
100
100
|
},
|
|
101
101
|
"ultramodern": {
|
|
102
|
-
"frameworkVersion": "3.5.0-ultramodern.
|
|
102
|
+
"frameworkVersion": "3.5.0-ultramodern.29"
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -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
|
+
}
|