@bleedingdev/modern-js-ultramodern-create 3.9.0-ultramodern.2 → 3.9.0-ultramodern.4

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.
Files changed (93) hide show
  1. package/dist/cjs/ultramodern-package-source.cjs +2 -1
  2. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-build-identity.cjs +5 -2
  3. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-modern-configs.cjs +5 -0
  4. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-typescript.cjs +1 -0
  5. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/package-cohort.cjs +30 -9
  6. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/pnpm-policy.cjs +9 -13
  7. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/pnpm-yaml.cjs +30 -7
  8. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/shared-api-infrastructure.cjs +99 -0
  9. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/toolchain-pins.cjs +14 -5
  10. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/workspace-artifact-ownership.cjs +215 -0
  11. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect.cjs +72 -8
  12. package/dist/cjs/ultramodern-workspace/api/client.cjs +2 -2
  13. package/dist/cjs/ultramodern-workspace/api/service.cjs +45 -16
  14. package/dist/cjs/ultramodern-workspace/api/shared.cjs +26 -16
  15. package/dist/cjs/ultramodern-workspace/mf-validation/inspect.cjs +6 -2
  16. package/dist/cjs/ultramodern-workspace/module-federation/reexport-module.cjs +18 -51
  17. package/dist/cjs/ultramodern-workspace/package-json.cjs +13 -1
  18. package/dist/cjs/ultramodern-workspace/policy.cjs +1 -0
  19. package/dist/cjs/ultramodern-workspace/tsconfigs.cjs +3 -0
  20. package/dist/cjs/ultramodern-workspace/workspace-script-plan.cjs +1 -1
  21. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +5 -0
  22. package/dist/cjs/ultramodern-workspace/workspace-validation-contract.cjs +2 -1
  23. package/dist/cjs/ultramodern-workspace/write-app.cjs +10 -4
  24. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +5 -3
  25. package/dist/esm/ultramodern-package-source.js +2 -1
  26. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-build-identity.js +5 -2
  27. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-modern-configs.js +5 -0
  28. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-typescript.js +1 -0
  29. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/package-cohort.js +30 -9
  30. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/pnpm-policy.js +9 -13
  31. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/pnpm-yaml.js +30 -7
  32. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/shared-api-infrastructure.js +50 -0
  33. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/toolchain-pins.js +14 -5
  34. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/workspace-artifact-ownership.js +166 -0
  35. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect.js +73 -9
  36. package/dist/esm/ultramodern-workspace/api/client.js +2 -2
  37. package/dist/esm/ultramodern-workspace/api/service.js +45 -16
  38. package/dist/esm/ultramodern-workspace/api/shared.js +27 -17
  39. package/dist/esm/ultramodern-workspace/mf-validation/inspect.js +6 -2
  40. package/dist/esm/ultramodern-workspace/module-federation/reexport-module.js +18 -51
  41. package/dist/esm/ultramodern-workspace/package-json.js +13 -1
  42. package/dist/esm/ultramodern-workspace/policy.js +1 -0
  43. package/dist/esm/ultramodern-workspace/tsconfigs.js +3 -0
  44. package/dist/esm/ultramodern-workspace/workspace-script-plan.js +1 -1
  45. package/dist/esm/ultramodern-workspace/workspace-scripts.js +5 -0
  46. package/dist/esm/ultramodern-workspace/workspace-validation-contract.js +2 -1
  47. package/dist/esm/ultramodern-workspace/write-app.js +10 -4
  48. package/dist/esm/ultramodern-workspace/write-workspace.js +6 -4
  49. package/dist/esm-node/ultramodern-package-source.js +2 -1
  50. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-build-identity.js +5 -2
  51. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-modern-configs.js +5 -0
  52. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-typescript.js +1 -0
  53. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/package-cohort.js +30 -9
  54. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/pnpm-policy.js +9 -13
  55. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/pnpm-yaml.js +30 -7
  56. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/shared-api-infrastructure.js +51 -0
  57. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/toolchain-pins.js +14 -5
  58. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/workspace-artifact-ownership.js +167 -0
  59. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect.js +73 -9
  60. package/dist/esm-node/ultramodern-workspace/api/client.js +2 -2
  61. package/dist/esm-node/ultramodern-workspace/api/service.js +45 -16
  62. package/dist/esm-node/ultramodern-workspace/api/shared.js +27 -17
  63. package/dist/esm-node/ultramodern-workspace/mf-validation/inspect.js +6 -2
  64. package/dist/esm-node/ultramodern-workspace/module-federation/reexport-module.js +18 -51
  65. package/dist/esm-node/ultramodern-workspace/package-json.js +13 -1
  66. package/dist/esm-node/ultramodern-workspace/policy.js +1 -0
  67. package/dist/esm-node/ultramodern-workspace/tsconfigs.js +3 -0
  68. package/dist/esm-node/ultramodern-workspace/workspace-script-plan.js +1 -1
  69. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +5 -0
  70. package/dist/esm-node/ultramodern-workspace/workspace-validation-contract.js +2 -1
  71. package/dist/esm-node/ultramodern-workspace/write-app.js +10 -4
  72. package/dist/esm-node/ultramodern-workspace/write-workspace.js +6 -4
  73. package/dist/types/ultramodern-package-source.d.ts +1 -1
  74. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/package-cohort.d.ts +3 -1
  75. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/pnpm-yaml.d.ts +7 -0
  76. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/shared-api-infrastructure.d.ts +4 -0
  77. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/workspace-artifact-ownership.d.ts +27 -0
  78. package/dist/types/ultramodern-workspace/api/client.d.ts +3 -1
  79. package/dist/types/ultramodern-workspace/api/service.d.ts +3 -1
  80. package/dist/types/ultramodern-workspace/api/shared.d.ts +2 -0
  81. package/dist/types/ultramodern-workspace/module-federation/reexport-module.d.ts +2 -2
  82. package/dist/types/ultramodern-workspace/package-json.d.ts +1 -1
  83. package/dist/types/ultramodern-workspace/policy.d.ts +2 -0
  84. package/dist/types/ultramodern-workspace/workspace-validation-contract.d.ts +1 -1
  85. package/package.json +5 -4
  86. package/template-workspace/.modernjs/release-cohort.json +40 -40
  87. package/template-workspace/scripts/bootstrap-agent-skills.mjs +4 -4
  88. package/templates/packages/effect-bff-runtime.ts +50 -0
  89. package/templates/packages/microvertical-api-baseline.ts +102 -0
  90. package/templates/workspace-scripts/check-ultramodern-api-boundaries.mts +49 -28
  91. package/templates/workspace-scripts/microvertical-api-baseline-boundary.mts +944 -0
  92. package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +25 -7
  93. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +1 -1
@@ -1,10 +1,15 @@
1
1
  import node_fs from "node:fs";
2
2
  import node_path from "node:path";
3
+ import { semver } from "@modern-js/utils";
3
4
  import { ULTRAMODERN_PACKAGE_PINS, ULTRAMODERN_WORKSPACE_POLICY } from "../../../ultramodern-workspace/policy.js";
4
5
  const { toolchain: toolchain } = ULTRAMODERN_WORKSPACE_POLICY;
5
6
  const retiredRootToolingDependencies = [
6
7
  "@typescript/typescript6"
7
8
  ];
9
+ function migrationPnpmVersion(value) {
10
+ const baseline = toolchain.packageManager.version;
11
+ return 'string' == typeof value && semver.valid(value) && semver.major(value) === semver.major(baseline) && semver.gte(value, baseline) ? value : baseline;
12
+ }
8
13
  function isRecord(value) {
9
14
  return Boolean(value) && 'object' == typeof value && !Array.isArray(value);
10
15
  }
@@ -22,22 +27,24 @@ function updateUltramodernConfigToolchain(config) {
22
27
  const workspace = ensureRecord(config, 'workspace', 'workspace');
23
28
  const packageManager = ensureRecord(workspace, 'packageManager', 'workspace.packageManager');
24
29
  packageManager.name = toolchain.packageManager.name;
25
- packageManager.version = toolchain.packageManager.version;
30
+ packageManager.version = migrationPnpmVersion(packageManager.version);
26
31
  const node = ensureRecord(workspace, 'node', 'workspace.node');
27
32
  node.version = toolchain.node.version;
28
33
  node.engineRange = toolchain.node.engineRange;
29
34
  }
30
35
  function updateRootPackageToolchain(packageJson) {
31
- packageJson.packageManager = `${toolchain.packageManager.name}@${toolchain.packageManager.version}`;
36
+ const currentVersion = 'string' == typeof packageJson.packageManager ? packageJson.packageManager.match(/^pnpm@([^+]+)(?:\+.*)?$/u)?.[1] : void 0;
37
+ packageJson.packageManager = `${toolchain.packageManager.name}@${migrationPnpmVersion(currentVersion)}`;
32
38
  const engines = ensureRecord(packageJson, 'engines', 'package.json engines');
33
39
  engines.node = toolchain.node.engineRange;
34
40
  engines.pnpm = toolchain.packageManager.engineRange;
35
41
  const devDependencies = ensureRecord(packageJson, 'devDependencies', 'package.json devDependencies');
36
42
  for (const packageName of retiredRootToolingDependencies)delete devDependencies[packageName];
37
43
  devDependencies["@typescript/native"] = ULTRAMODERN_PACKAGE_PINS.rootDevDependencies["@typescript/native"];
44
+ devDependencies['@types/node'] = ULTRAMODERN_PACKAGE_PINS.rootDevDependencies["@types/node"];
38
45
  devDependencies.miniflare = ULTRAMODERN_PACKAGE_PINS.rootDevDependencies.miniflare;
39
46
  }
40
- function updateMiseTools(content) {
47
+ function updateMiseTools(content, pnpmVersion) {
41
48
  const lines = content.replace(/\r\n/gu, '\n').split('\n');
42
49
  if ('' === lines.at(-1)) lines.pop();
43
50
  let toolsStart = lines.findIndex((line)=>/^\s*\[tools\]\s*(?:#.*)?$/u.test(line));
@@ -64,13 +71,15 @@ function updateMiseTools(content) {
64
71
  lines[index] = line;
65
72
  };
66
73
  upsertTool('node', toolchain.node.version);
67
- upsertTool('pnpm', toolchain.packageManager.version);
74
+ upsertTool('pnpm', pnpmVersion);
68
75
  return `${lines.join('\n')}\n`;
69
76
  }
70
77
  function updateGeneratedToolchainFiles(io) {
71
78
  const misePath = node_path.join(io.workspaceRoot, '.mise.toml');
72
79
  const miseContent = node_fs.existsSync(misePath) ? node_fs.readFileSync(misePath, 'utf-8') : '';
73
- io.write(misePath, updateMiseTools(miseContent));
80
+ const packageJson = JSON.parse(node_fs.readFileSync(node_path.join(io.workspaceRoot, 'package.json'), 'utf8'));
81
+ const pnpmVersion = migrationPnpmVersion(packageJson.packageManager?.match(/^pnpm@([^+]+)(?:\+.*)?$/u)?.[1]);
82
+ io.write(misePath, updateMiseTools(miseContent, pnpmVersion));
74
83
  const workflowPath = node_path.join(io.workspaceRoot, '.github/workflows/ultramodern-workspace-gates.yml');
75
84
  if (!node_fs.existsSync(workflowPath)) return;
76
85
  const workflow = node_fs.readFileSync(workflowPath, 'utf-8');
@@ -0,0 +1,166 @@
1
+ import node_fs from "node:fs";
2
+ import node_path from "node:path";
3
+ import { parse } from "@babel/parser";
4
+ import { formatGeneratedSourceCandidates } from "../../../ultramodern-workspace/fs-io.js";
5
+ function isLiteralData(node, literalIdentifiers) {
6
+ if (!node) return false;
7
+ if ('Identifier' === node.type) return literalIdentifiers?.has(node.name) ?? false;
8
+ if ([
9
+ 'StringLiteral',
10
+ 'NumericLiteral',
11
+ 'BooleanLiteral',
12
+ 'NullLiteral'
13
+ ].includes(node.type)) return true;
14
+ if ('UnaryExpression' === node.type) return '-' === node.operator && 'NumericLiteral' === node.argument.type;
15
+ if ('ArrayExpression' === node.type) return node.elements.every((element)=>isLiteralData(element, literalIdentifiers));
16
+ return 'ObjectExpression' === node.type && node.properties.every((property)=>'ObjectProperty' === property.type && !property.computed && !property.shorthand && [
17
+ 'Identifier',
18
+ 'StringLiteral',
19
+ 'NumericLiteral'
20
+ ].includes(property.key.type) && isLiteralData(property.value, literalIdentifiers));
21
+ }
22
+ function withoutGeneratedData(source, binding) {
23
+ if (!binding) return source;
24
+ const parsed = parse(source, {
25
+ sourceType: 'module',
26
+ plugins: [
27
+ "typescript"
28
+ ]
29
+ });
30
+ for (const statement of parsed.program.body)if ('VariableDeclaration' === statement.type && 'const' === statement.kind) {
31
+ for (const declaration of statement.declarations)if ('Identifier' === declaration.id.type && declaration.id.name === binding && declaration.init && isLiteralData(declaration.init)) return source.slice(0, declaration.init.start) + '{}' + source.slice(declaration.init.end);
32
+ }
33
+ return source;
34
+ }
35
+ function staticPropertyValue(node, name) {
36
+ if (node?.type !== 'ObjectExpression') return;
37
+ const keys = new Set();
38
+ let value;
39
+ for (const property of node.properties){
40
+ if ('ObjectProperty' !== property.type || property.computed || property.shorthand || ![
41
+ 'Identifier',
42
+ 'StringLiteral'
43
+ ].includes(property.key.type)) return;
44
+ const key = property.key.name ?? property.key.value;
45
+ if (keys.has(key)) return;
46
+ keys.add(key);
47
+ if (key === name) value = property.value;
48
+ }
49
+ return value;
50
+ }
51
+ function refreshValidatorReleaseCohort(source, releaseCohort) {
52
+ try {
53
+ const parsed = parse(source, {
54
+ sourceType: 'module',
55
+ plugins: [
56
+ "typescript"
57
+ ],
58
+ tokens: true
59
+ });
60
+ const constants = parsed.program.body.flatMap((statement)=>'VariableDeclaration' === statement.type && 'const' === statement.kind ? statement.declarations : []);
61
+ const matches = [];
62
+ for (const statement of parsed.program.body)if ('VariableDeclaration' === statement.type && 'const' === statement.kind) for (const declaration of statement.declarations){
63
+ const kind = staticPropertyValue(declaration.init, 'kind');
64
+ if (kind?.type !== 'StringLiteral' || 'modernjs.ultramodern-workspace-validation-contract' !== kind.value) continue;
65
+ const cohort = staticPropertyValue(staticPropertyValue(declaration.init, 'cohort'), 'releaseCohort');
66
+ const schema = staticPropertyValue(cohort, 'schema');
67
+ const schemaVersion = staticPropertyValue(cohort, 'schemaVersion');
68
+ const version = staticPropertyValue(staticPropertyValue(cohort, 'release'), 'version');
69
+ const versionConstant = version?.type === 'Identifier' ? constants.find((declaration)=>'Identifier' === declaration.id.type && declaration.id.name === version.name && declaration.init?.type === 'StringLiteral') : void 0;
70
+ if (schema?.type === 'StringLiteral' && 'bleedingdev.ultramodern.release-cohort' === schema.value && schemaVersion?.type === 'NumericLiteral' && 1 === schemaVersion.value && isLiteralData(cohort, versionConstant ? new Set([
71
+ version.name
72
+ ]) : void 0)) matches.push({
73
+ cohort,
74
+ version,
75
+ versionConstant
76
+ });
77
+ }
78
+ if (1 !== matches.length) return source;
79
+ const { cohort, version, versionConstant } = matches[0];
80
+ let content = JSON.stringify(releaseCohort, null, 2);
81
+ const edits = [];
82
+ if (versionConstant && !parsed.tokens?.some((token)=>'name' === token.type.label && token.value === version.name && token.start !== versionConstant.id.start && (token.start < cohort.start || token.end > cohort.end))) {
83
+ content = content.replaceAll(`"version": ${JSON.stringify(releaseCohort.release.version)}`, `"version": ${version.name}`);
84
+ edits.push({
85
+ start: versionConstant.init.start,
86
+ end: versionConstant.init.end,
87
+ content: JSON.stringify(releaseCohort.release.version)
88
+ });
89
+ }
90
+ edits.push({
91
+ start: cohort.start,
92
+ end: cohort.end,
93
+ content
94
+ });
95
+ for (const edit of edits.toSorted((left, right)=>right.start - left.start))source = source.slice(0, edit.start) + edit.content + source.slice(edit.end);
96
+ return source;
97
+ } catch {
98
+ return source;
99
+ }
100
+ }
101
+ function preserveConsumerWorkspaceArtifacts(io, candidates) {
102
+ const preservedPaths = new Set();
103
+ const physicalRoot = node_fs.realpathSync(io.workspaceRoot);
104
+ const canonicalSources = formatGeneratedSourceCandidates(candidates.map((candidate, index)=>[
105
+ `canonical/${index}/${candidate.relativePath}`,
106
+ withoutGeneratedData(candidate.content, candidate.generatedDataBinding)
107
+ ]));
108
+ for (const [index, candidate] of candidates.entries()){
109
+ const paths = [
110
+ candidate.relativePath,
111
+ candidate.legacyPath
112
+ ].filter((value)=>void 0 !== value);
113
+ for (const relativePath of paths){
114
+ const filePath = node_path.join(io.workspaceRoot, relativePath);
115
+ if (!node_fs.existsSync(filePath)) continue;
116
+ const physicalRelative = node_path.relative(physicalRoot, node_fs.realpathSync(filePath));
117
+ if ('..' === physicalRelative || physicalRelative.startsWith(`..${node_path.sep}`) || node_path.isAbsolute(physicalRelative)) throw new Error(`Refusing to inspect an artifact outside the workspace: ${relativePath}`);
118
+ const source = node_fs.readFileSync(filePath, 'utf8');
119
+ let recognized = source === candidate.content;
120
+ if (!recognized) try {
121
+ const normalized = withoutGeneratedData(source, candidate.generatedDataBinding);
122
+ const canonical = canonicalSources[index];
123
+ recognized = normalized === canonical || formatGeneratedSourceCandidates([
124
+ [
125
+ relativePath,
126
+ normalized
127
+ ]
128
+ ])[0] === canonical;
129
+ } catch {}
130
+ if (!recognized) for (const pairedPath of paths)preservedPaths.add(pairedPath);
131
+ }
132
+ }
133
+ const reported = new Set();
134
+ const isPreserved = (filePath)=>{
135
+ const relativePath = node_path.relative(io.workspaceRoot, filePath).split(node_path.sep).join('/');
136
+ if (!preservedPaths.has(relativePath)) return false;
137
+ if (!reported.has(relativePath)) {
138
+ io.log(`${relativePath} preserved consumer-owned artifact: its canonical generated source does not match.`);
139
+ reported.add(relativePath);
140
+ }
141
+ return true;
142
+ };
143
+ return {
144
+ preservedPaths,
145
+ refreshReleaseCohort (releaseCohort) {
146
+ if (!releaseCohort) return;
147
+ for (const candidate of candidates)if ('workspaceValidationContract' === candidate.generatedDataBinding) for (const relativePath of [
148
+ candidate.relativePath,
149
+ candidate.legacyPath
150
+ ]){
151
+ if (!relativePath || !preservedPaths.has(relativePath)) continue;
152
+ const filePath = node_path.join(io.workspaceRoot, relativePath);
153
+ if (!node_fs.existsSync(filePath)) continue;
154
+ const source = node_fs.readFileSync(filePath, 'utf8');
155
+ io.write(filePath, refreshValidatorReleaseCohort(source, releaseCohort));
156
+ }
157
+ },
158
+ io: {
159
+ ...io,
160
+ write: (filePath, content)=>isPreserved(filePath) ? false : io.write(filePath, content),
161
+ writeGenerated: (filePath, content)=>isPreserved(filePath) ? false : io.writeGenerated(filePath, content),
162
+ remove: (filePath)=>isPreserved(filePath) ? false : io.remove(filePath)
163
+ }
164
+ };
165
+ }
166
+ export { preserveConsumerWorkspaceArtifacts };
@@ -1,11 +1,13 @@
1
1
  import node_fs from "node:fs";
2
2
  import node_path from "node:path";
3
3
  import { RELEASE_COHORT_PROJECTION_PATH, readCreateReleaseCohort } from "../../ultramodern-release-cohort.js";
4
+ import { createAppEnvDts } from "../../ultramodern-workspace/app-files.js";
4
5
  import { createDevelopmentOverlay, createTopology, createUltramodernConfig } from "../../ultramodern-workspace/contracts.js";
5
6
  import { stampDeliveryUnitIdentity } from "../../ultramodern-workspace/delivery-unit-stamp.js";
6
7
  import { ULTRAMODERN_WORKSPACE_POLICY } from "../../ultramodern-workspace/policy.js";
7
8
  import { createAdditionalShellConfigEntry } from "../../ultramodern-workspace/shells.js";
8
- import { createWorkspaceValidationScript, migratedWorkspaceScriptArtifacts } from "../../ultramodern-workspace/workspace-scripts.js";
9
+ import { createWorkspaceValidationScript, createZeropsRuntimeMaterializationScript, migratedWorkspaceScriptArtifacts } from "../../ultramodern-workspace/workspace-scripts.js";
10
+ import { createZeropsYaml } from "../../ultramodern-workspace/zerops.js";
9
11
  import { additionalShellsFromToolingConfig, allWorkspaceAppsFromToolingConfig, normalizeCompactUltramodernConfig, synthesizeCompactUltramodernConfig, workspaceAppsFromToolingConfig } from "../config.js";
10
12
  import { reconcileCompactPackageSourceMetadata, reconcilePackageSourceMetadata, updateReferenceTopology, updateUltramodernConfig } from "./migrate-strict-effect/api-metadata.js";
11
13
  import { ensureGeneratedDeclarationPatches } from "./migrate-strict-effect/declaration-patches.js";
@@ -18,7 +20,9 @@ import { ensureBffEffectDependencies, updateGeneratedPackageScripts, updateGener
18
20
  import { createMigrationPackageSource } from "./migrate-strict-effect/package-source.js";
19
21
  import { updateGeneratedPnpmWorkspacePolicy, validateGeneratedPnpmLockReleaseAgePolicy } from "./migrate-strict-effect/pnpm-policy.js";
20
22
  import { ensureGeneratedModuleFederationBridgeRouterOptOut, preflightModuleFederationBridgeRouter, removeRetiredReactRouterDependency } from "./migrate-strict-effect/react-router-retirement.js";
23
+ import { ensureSharedApiInfrastructure } from "./migrate-strict-effect/shared-api-infrastructure.js";
21
24
  import { updateGeneratedToolchainFiles, updateRootPackageToolchain } from "./migrate-strict-effect/toolchain-pins.js";
25
+ import { preserveConsumerWorkspaceArtifacts } from "./migrate-strict-effect/workspace-artifact-ownership.js";
22
26
  import { hasFlag } from "./options.js";
23
27
  const retiredMetadataPaths = [
24
28
  '.modernjs/ultramodern-generated-contract.json',
@@ -74,10 +78,24 @@ function synchronizeMigrationDeliveryUnitMetadata(io, raw, packageSource) {
74
78
  'schemaVersion',
75
79
  'id',
76
80
  "description",
77
- 'preset',
78
- 'sharedPackages',
79
- 'validation'
80
- ])topology[key] = canonicalTopology[key];
81
+ 'preset'
82
+ ])if ('id' === key || "description" === key) topology[key] ??= canonicalTopology[key];
83
+ else topology[key] = canonicalTopology[key];
84
+ const existingSharedPackages = Array.isArray(topology.sharedPackages) ? topology.sharedPackages : [];
85
+ topology.sharedPackages = [
86
+ ...existingSharedPackages,
87
+ ...canonicalTopology.sharedPackages.filter((candidate)=>!existingSharedPackages.some((existing)=>existing.id === candidate.id))
88
+ ];
89
+ topology.validation = {
90
+ ...canonicalTopology.validation,
91
+ ...topology.validation,
92
+ commands: [
93
+ ...new Set([
94
+ ...topology.validation?.commands ?? [],
95
+ ...canonicalTopology.validation.commands
96
+ ])
97
+ ]
98
+ };
81
99
  const canonicalTopologyApps = new Map([
82
100
  canonicalTopology.shell,
83
101
  ...canonicalTopology.verticals ?? []
@@ -100,8 +118,21 @@ function synchronizeMigrationDeliveryUnitMetadata(io, raw, packageSource) {
100
118
  'api',
101
119
  'cloudflare',
102
120
  'ownership'
103
- ])if (Object.hasOwn(canonicalEntry, key)) entry[key] = canonicalEntry[key];
104
- else delete entry[key];
121
+ ])if (Object.hasOwn(canonicalEntry, key)) {
122
+ const canonicalValue = canonicalEntry[key];
123
+ if ('api' === key && entry.api && canonicalValue && 'object' == typeof canonicalValue) {
124
+ const nextApi = {
125
+ ...entry.api,
126
+ ...canonicalValue
127
+ };
128
+ if (!Object.hasOwn(entry.api, 'domainOperations')) delete nextApi.domainOperations;
129
+ entry.api = nextApi;
130
+ } else if ('cloudflare' === key && entry.cloudflare && canonicalValue && 'object' == typeof canonicalValue) entry.cloudflare = {
131
+ ...canonicalValue,
132
+ ...entry.cloudflare
133
+ };
134
+ else entry[key] = canonicalValue;
135
+ } else delete entry[key];
105
136
  }
106
137
  }
107
138
  writeJsonFile(io, topologyPath, topology);
@@ -122,7 +153,10 @@ function synchronizeMigrationCompactPolicy(io, raw, packageSource) {
122
153
  const apps = workspaceAppsFromToolingConfig(migrated);
123
154
  apps.filter((app)=>'shell' !== app.kind);
124
155
  const canonical = requireRecord(createUltramodernConfig(migrated.workspace.packageScope, packageSource.modernPackageVersion, packageSource, apps, migrated.features.tailwind, migrated.bridge, additionalShellsFromToolingConfig(migrated), apps.find((app)=>'shell' === app.kind)), 'Generated compact policy');
125
- for (const key of compactPolicyKeys)raw[key] = canonical[key];
156
+ for (const key of compactPolicyKeys){
157
+ if ('workspace' === key) canonical.workspace.packageManager.version = raw.workspace.packageManager.version;
158
+ raw[key] = canonical[key];
159
+ }
126
160
  writeJsonFile(io, node_path.join(io.workspaceRoot, '.modernjs/ultramodern.json'), raw);
127
161
  }
128
162
  function reconcileRootPackageSourceMetadata(packageJson, packageSource) {
@@ -262,6 +296,33 @@ function migrateStrictEffect(args, context, io, dryRun, skipInstall) {
262
296
  version: packageSource.modernPackageVersion
263
297
  });
264
298
  const releaseCohort = 'install' === packageSource.strategy ? readCreateReleaseCohort() : void 0;
299
+ const currentApps = workspaceAppsFromToolingConfig(current);
300
+ const allCurrentApps = allWorkspaceAppsFromToolingConfig(current);
301
+ const artifactOwnership = preserveConsumerWorkspaceArtifacts(io, [
302
+ ...allCurrentApps.map((app)=>({
303
+ relativePath: `${app.directory}/src/modern-app-env.d.ts`,
304
+ content: createAppEnvDts(app, allCurrentApps.filter((remote)=>'shell' !== remote.kind), current.workspace.packageScope)
305
+ })),
306
+ ...migratedWorkspaceScriptArtifacts({
307
+ shellOnly: false,
308
+ hasBackendSurface: true
309
+ }).filter((artifact)=>"scripts/validate-ultramodern-workspace.mts" !== artifact.relativePath),
310
+ {
311
+ relativePath: "scripts/validate-ultramodern-workspace.mts",
312
+ legacyPath: "scripts/validate-ultramodern-workspace.mjs",
313
+ generatedDataBinding: 'workspaceValidationContract',
314
+ content: createWorkspaceValidationScript(current.workspace.packageScope, current.features.tailwind, currentApps.filter((app)=>'shell' !== app.kind), void 0, additionalShellsFromToolingConfig(current), currentApps.find((app)=>'shell' === app.kind))
315
+ },
316
+ {
317
+ relativePath: 'zerops.yaml',
318
+ content: `${createZeropsYaml(current.workspace.packageScope, allWorkspaceAppsFromToolingConfig(current))}\n`
319
+ },
320
+ {
321
+ relativePath: "scripts/materialize-zerops-runtime.mjs",
322
+ content: createZeropsRuntimeMaterializationScript()
323
+ }
324
+ ]);
325
+ io = artifactOwnership.io;
265
326
  reconcileCompactPackageSourceMetadata(raw.packageSource, packageSource);
266
327
  reconcileRootPackageSourceMetadata(readJsonFile(node_path.join(io.workspaceRoot, 'package.json')), packageSource);
267
328
  updateGeneratedPnpmWorkspacePolicy(createMigrationIo(io.workspaceRoot, true), packageSource, {
@@ -282,6 +343,7 @@ function migrateStrictEffect(args, context, io, dryRun, skipInstall) {
282
343
  const verticalApps = migrated.topology.apps.filter((app)=>'shell' !== app.kind);
283
344
  const hasBackendSurface = verticalApps.some((app)=>app.api);
284
345
  const shellOnly = 0 === verticalApps.length;
346
+ if (hasBackendSurface) ensureSharedApiInfrastructure(io, migrated.workspace.packageScope, packageSource);
285
347
  if (shellOnly) {
286
348
  io.log('Shell-only workspace: skipping backend-federation and Zerops runtime stages.');
287
349
  for (const relativePath of [
@@ -312,6 +374,7 @@ function migrateStrictEffect(args, context, io, dryRun, skipInstall) {
312
374
  io.writeGenerated(node_path.join(io.workspaceRoot, artifact.relativePath), artifact.content);
313
375
  }
314
376
  io.writeGenerated(node_path.join(io.workspaceRoot, "scripts/validate-ultramodern-workspace.mts"), createWorkspaceValidationScript(validationContractInputs.scope, validationContractInputs.enableTailwind, validationContractInputs.remotes, releaseCohort, validationContractInputs.additionalShells, validationContractInputs.primaryShell, raw, node_fs.existsSync(node_path.join(io.workspaceRoot, 'topology/ownership.json')) ? requireRecord(readJsonFile(node_path.join(io.workspaceRoot, 'topology/ownership.json')), 'Ownership topology') : void 0, developmentOverlay));
377
+ artifactOwnership.refreshReleaseCohort(releaseCohort);
315
378
  for (const relativePath of retiredMetadataPaths)io.remove(node_path.join(io.workspaceRoot, relativePath));
316
379
  updateGeneratedBuildIdentityModules(io, migrated);
317
380
  updateGeneratedTypeScriptSurfaces(io, migrated);
@@ -326,7 +389,7 @@ function migrateStrictEffect(args, context, io, dryRun, skipInstall) {
326
389
  reconcileRootPackageSourceMetadata(packageJson, packageSource);
327
390
  updateRootPackageToolchain(packageJson);
328
391
  }
329
- updateModernDependencies(packageJson, packageSource);
392
+ updateModernDependencies(packageJson, packageSource, releaseCohort);
330
393
  const ownsGeneratedScripts = 'package.json' === relativePackageFile || allMigratedApps.some((app)=>`${app.directory}/package.json` === relativePackageFile);
331
394
  updateGeneratedToolingDependencies(packageJson, {
332
395
  ownsGeneratedScripts
@@ -336,6 +399,7 @@ function migrateStrictEffect(args, context, io, dryRun, skipInstall) {
336
399
  if ('preserved' === retiredReactRouter) io.log(`${relativePackageFile} keeps its react-router dependency: authored source imports React Router directly, so its generated Module Federation config keeps bridge.enableBridgeRouter: true.`);
337
400
  else if ('removed' === retiredReactRouter) io.log(`${relativePackageFile} dropped its obsolete react-router dependency: no authored source imports React Router.`);
338
401
  updateGeneratedPackageScripts(packageJson, {
402
+ preservedArtifacts: artifactOwnership.preservedPaths,
339
403
  relativePackageFile,
340
404
  apps: allMigratedApps,
341
405
  shellOnly,
@@ -2,7 +2,7 @@ import { resolveApiProtocol, resolveApiStem, verticalApiApps } from "../descript
2
2
  import { packageName, toPascalCase } from "../naming.js";
3
3
  import { createCheckoutCartClientExports, serviceHasCheckoutCartState } from "./checkout-cart.js";
4
4
  import { verticalApiErrorStem, verticalApiExport, verticalApiGroupName, verticalApiNotFoundErrorExport } from "./names.js";
5
- function createApiClient(service, contractImportPath) {
5
+ function createApiClient(service, contractImportPath, options) {
6
6
  const apiExport = verticalApiExport(service);
7
7
  const contractExport = verticalApiGroupName(service);
8
8
  const stem = resolveApiStem(service);
@@ -118,7 +118,7 @@ export const ${readinessName} = (
118
118
  operationContext:
119
119
  options.operationContext ?? ${groupName}OperationContexts.readiness,
120
120
  }).pipe(
121
- Effect.flatMap(client => client.${groupName}.readiness({})),
121
+ Effect.flatMap(client => client.${options ? 'foundation' : groupName}.readiness({})),
122
122
  );
123
123
 
124
124
  export const ${getName} = (
@@ -4,23 +4,22 @@ import { packageName } from "../naming.js";
4
4
  import { createCheckoutCartServerHandlers, createCheckoutCartServerState } from "./checkout-cart.js";
5
5
  import { verticalApiExport, verticalApiGroupName, verticalApiNotFoundErrorExport } from "./names.js";
6
6
  import { createRpcApiServiceEntry, rpcPath, verticalRpcContractExport, verticalRpcGroupExport } from "./rpc.js";
7
- function createApiServiceEntry(service, contractImportPath) {
7
+ function createApiServiceEntry(service, contractImportPath, options) {
8
8
  if ((service.api?.protocol ?? 'rest') === 'rpc') return createRpcApiServiceEntry(service);
9
9
  const apiExport = verticalApiExport(service);
10
10
  const groupName = verticalApiGroupName(service);
11
11
  const notFoundErrorExport = verticalApiNotFoundErrorExport(service);
12
12
  const stem = resolveApiStem(service);
13
- return `import {
14
- defineEffectBff,
13
+ const assemblyImport = options ? `import { assembleEffectBffRuntime } from '${packageName(options.scope, 'shared-contracts')}/server/effect-bff-runtime';\n` : '';
14
+ return `${assemblyImport}import {
15
+ ${options ? '' : 'defineEffectBff,'}
15
16
  Effect,
16
17
  HttpApiBuilder,
17
18
  Layer,
18
19
  } from '@modern-js/plugin-bff/effect-edge';
19
- import type {
20
- EffectBffDefinition,
21
- EffectBffRuntime,
20
+ ${options ? '' : `import type {
22
21
  EffectRuntimeLayer,
23
- } from '@modern-js/plugin-bff/effect-edge';
22
+ } from '@modern-js/plugin-bff/effect-edge';`}
24
23
  import { ultramodernApiMarker } from '../shared/ultramodern-build.ts';
25
24
  import {
26
25
  ${apiExport},
@@ -50,6 +49,31 @@ const operationAttributes = (operationContext: OperationContext) => ({
50
49
  : {}),
51
50
  });
52
51
 
52
+ ${options ? `const ${groupName}ReadinessLayer = HttpApiBuilder.group(
53
+ ${apiExport},
54
+ 'foundation',
55
+ handlers => handlers
56
+ .handle('readiness', () =>
57
+ Effect.succeed({
58
+ checks: {
59
+ api: 'ready' as const,
60
+ moduleFederation: 'ready' as const,
61
+ ssr: 'ready' as const,
62
+ translations: 'ready' as const,
63
+ },
64
+ marker: ultramodernApiMarker,
65
+ status: 'ready' as const,
66
+ versionSkew: 'none' as const,
67
+ }).pipe(
68
+ Effect.withSpan('ultramodern.api.${groupName}.readiness', {
69
+ attributes: operationAttributes(${groupName}OperationContexts.readiness),
70
+ kind: 'server',
71
+ }),
72
+ ),
73
+ )
74
+ ,
75
+ );` : ''}
76
+
53
77
  const ${groupName}Layer = HttpApiBuilder.group(
54
78
  ${apiExport},
55
79
  '${groupName}',
@@ -68,7 +92,7 @@ const ${groupName}Layer = HttpApiBuilder.group(
68
92
  }),
69
93
  ),
70
94
  )
71
- .handle('readiness', () =>
95
+ ${options ? '' : ` .handle('readiness', () =>
72
96
  Effect.succeed({
73
97
  checks: {
74
98
  api: 'ready' as const,
@@ -86,6 +110,7 @@ const ${groupName}Layer = HttpApiBuilder.group(
86
110
  }),
87
111
  ),
88
112
  )
113
+ `}
89
114
  .handle('get', ({ params }) => {
90
115
  const matchedItem = ${groupName}Items.find(
91
116
  candidate => candidate.id === params.id,
@@ -125,14 +150,18 @@ const ${groupName}Layer = HttpApiBuilder.group(
125
150
  )${createCheckoutCartServerHandlers(service)},
126
151
  );
127
152
 
128
- const layer = HttpApiBuilder.layer(${apiExport}).pipe(
129
- Layer.provide(${groupName}Layer),
130
- ) satisfies EffectRuntimeLayer;
131
- const apiRuntime: EffectBffDefinition<typeof ${apiExport}, EffectRuntimeLayer> &
132
- EffectBffRuntime<typeof ${apiExport}, EffectRuntimeLayer> = defineEffectBff({
133
- api: ${apiExport},
134
- layer,
135
- });
153
+ ${options ? `const apiHandlersLive = Layer.mergeAll(${groupName}Layer, ${groupName}ReadinessLayer);
154
+ export const make${apiExport[0].toUpperCase()}${apiExport.slice(1)}Runtime = () =>
155
+ assembleEffectBffRuntime({
156
+ api: ${apiExport},
157
+ handlers: apiHandlersLive,
158
+ });` : `export const make${apiExport[0].toUpperCase()}${apiExport.slice(1)}Runtime = () => {
159
+ const layer = HttpApiBuilder.layer(${apiExport}).pipe(
160
+ Layer.provide(${groupName}Layer),
161
+ ) satisfies EffectRuntimeLayer;
162
+ return defineEffectBff({ api: ${apiExport}, layer });
163
+ };`}
164
+ const apiRuntime = make${apiExport[0].toUpperCase()}${apiExport.slice(1)}Runtime();
136
165
 
137
166
  export default apiRuntime;
138
167
  `;
@@ -1,6 +1,6 @@
1
1
  import { resolveApiPrefix, resolveApiStem } from "../descriptors.js";
2
2
  import { renderTemplate } from "../fs-io.js";
3
- import { toPascalCase } from "../naming.js";
3
+ import { packageName, toPascalCase } from "../naming.js";
4
4
  import { createCheckoutCartApiContractFields, createCheckoutCartEndpointDefinitions, createCheckoutCartOperationContexts, createCheckoutCartSharedSchemas } from "./checkout-cart.js";
5
5
  import { verticalApiCreatePayloadSchemaExport, verticalApiExport, verticalApiGroupName, verticalApiMarkerSchemaExport, verticalApiName, verticalApiNotFoundErrorExport, verticalApiNotFoundSchemaExport, verticalApiReadinessSchemaExport, verticalApiSchemaExport } from "./names.js";
6
6
  function createSharedApiImports() {
@@ -13,7 +13,7 @@ function createSharedApiImports() {
13
13
  } from '@modern-js/plugin-bff/effect-client';
14
14
  `;
15
15
  }
16
- function createSharedApiContract(service) {
16
+ function createSharedApiContract(service, shared = false) {
17
17
  const schemaExport = verticalApiSchemaExport(service);
18
18
  const markerSchemaExport = verticalApiMarkerSchemaExport(service);
19
19
  const readinessSchemaExport = verticalApiReadinessSchemaExport(service);
@@ -70,7 +70,7 @@ function createSharedApiContract(service) {
70
70
  listOperationContext,
71
71
  readinessOperationContext
72
72
  }).trim();
73
- return `export interface ${markerType} {
73
+ return `${shared ? `export type ${markerType} = MicroVerticalBuildMarker;` : `export interface ${markerType} {
74
74
  readonly appId: string;
75
75
  readonly build: string;
76
76
  readonly buildMarker: string;
@@ -80,7 +80,7 @@ function createSharedApiContract(service) {
80
80
  readonly surface: string;
81
81
  readonly unitId: string;
82
82
  readonly version: string;
83
- }
83
+ }`}
84
84
 
85
85
  export interface ${itemType} {
86
86
  readonly id: string;
@@ -88,7 +88,7 @@ export interface ${itemType} {
88
88
  readonly title: string;
89
89
  }
90
90
 
91
- export interface ${readinessType} {
91
+ ${shared ? `export type ${readinessType} = MicroVerticalReadiness;` : `export interface ${readinessType} {
92
92
  readonly checks: {
93
93
  readonly api: 'ready';
94
94
  readonly moduleFederation: 'ready';
@@ -98,7 +98,7 @@ export interface ${readinessType} {
98
98
  readonly marker: ${markerType};
99
99
  readonly status: 'ready';
100
100
  readonly versionSkew: 'none';
101
- }
101
+ }`}
102
102
 
103
103
  export interface ${createPayloadType} {
104
104
  readonly title: string;
@@ -117,7 +117,7 @@ export interface ${notFoundErrorExport} {
117
117
  readonly id: string;
118
118
  }
119
119
 
120
- export const ${markerSchemaExport}: Schema.Codec<${markerType}> = Schema.Struct({
120
+ ${shared ? `export const ${markerSchemaExport}: Schema.Codec<${markerType}> = MicroVerticalBuildMarkerSchema;` : `export const ${markerSchemaExport}: Schema.Codec<${markerType}> = Schema.Struct({
121
121
  appId: Schema.String,
122
122
  build: Schema.String,
123
123
  buildMarker: Schema.String,
@@ -127,7 +127,7 @@ export const ${markerSchemaExport}: Schema.Codec<${markerType}> = Schema.Struct(
127
127
  surface: Schema.String,
128
128
  unitId: Schema.String,
129
129
  version: Schema.String,
130
- });
130
+ });`}
131
131
 
132
132
  export const ${schemaExport}: Schema.Codec<${itemType}> = Schema.Struct({
133
133
  id: Schema.String,
@@ -135,7 +135,7 @@ export const ${schemaExport}: Schema.Codec<${itemType}> = Schema.Struct({
135
135
  title: Schema.String,
136
136
  });
137
137
 
138
- export const ${readinessSchemaExport}: Schema.Codec<${readinessType}> = Schema.Struct({
138
+ ${shared ? `export const ${readinessSchemaExport}: Schema.Codec<${readinessType}> = MicroVerticalReadinessSchema;` : `export const ${readinessSchemaExport}: Schema.Codec<${readinessType}> = Schema.Struct({
139
139
  checks: Schema.Struct({
140
140
  api: Schema.Literal('ready'),
141
141
  moduleFederation: Schema.Literal('ready'),
@@ -145,7 +145,7 @@ export const ${readinessSchemaExport}: Schema.Codec<${readinessType}> = Schema.S
145
145
  marker: ${markerSchemaExport},
146
146
  status: Schema.Literal('ready'),
147
147
  versionSkew: Schema.Literal('none'),
148
- });
148
+ });`}
149
149
 
150
150
  export const ${createPayloadSchemaExport}: Schema.Codec<${createPayloadType}> = Schema.Struct({
151
151
  title: Schema.String,
@@ -157,7 +157,7 @@ ${checkoutCartSharedSchemaSection}export const ${notFoundSchemaExport}: Schema.C
157
157
  HttpApiSchema.status(404),
158
158
  );
159
159
 
160
- export interface OperationContext {
160
+ ${shared ? 'export type OperationContext = MicroVerticalOperationContext;' : `export interface OperationContext {
161
161
  method: string;
162
162
  operationId: string;
163
163
  routePath: string;
@@ -169,9 +169,14 @@ export interface OperationContext {
169
169
  | 'data-platform'
170
170
  | 'unknown';
171
171
  traceId?: string;
172
- }
172
+ }`}
173
173
 
174
- export const ${apiExport} = HttpApi.make('${apiName}').add(
174
+ ${shared ? `export const ${groupName}FoundationApi = HttpApi.make('${apiName}Foundation').add(
175
+ HttpApiGroup.make('foundation').add(
176
+ HttpApiEndpoint.get('readiness', '/${stem}/readiness', { success: ${readinessSchemaExport} }),
177
+ ),
178
+ );` : ''}
179
+ export const ${apiExport} = HttpApi.make('${apiName}')${shared ? `.addHttpApi(${groupName}FoundationApi)` : ''}.add(
175
180
  HttpApiGroup.make('${groupName}')
176
181
  .add(
177
182
  HttpApiEndpoint.get('list', '/${stem}', {
@@ -183,11 +188,12 @@ export const ${apiExport} = HttpApi.make('${apiName}').add(
183
188
  }),
184
189
  }),
185
190
  )
186
- .add(
191
+ ${shared ? '' : ` .add(
187
192
  HttpApiEndpoint.get('readiness', '/${stem}/readiness', {
188
193
  success: ${readinessSchemaExport},
189
194
  }),
190
195
  )
196
+ `}
191
197
  .add(
192
198
  HttpApiEndpoint.get('get', '/${stem}/:id', {
193
199
  error: ${notFoundSchemaExport},
@@ -208,7 +214,7 @@ export const ${apiExport} = HttpApi.make('${apiName}').add(
208
214
  );
209
215
 
210
216
  export const ${groupName}OperationContexts = {
211
- ${operationContextEntries}
217
+ ${shared ? operationContextEntries.replaceAll(/(\w+: )\{([\s\S]*?)\},/gu, (_, key, fields)=>`${key}createMicroVerticalOperationContext({${fields.replace(/\n\s*source: 'generated-client',/u, '')}}),`) : operationContextEntries}
212
218
  } satisfies Record<string, OperationContext>;
213
219
 
214
220
  export const ${groupName}ApiContract = {
@@ -219,8 +225,12 @@ ${createCheckoutCartApiContractFields(service)} ownerId: '${service.id}',
219
225
  } as const;
220
226
  `;
221
227
  }
222
- function createSharedApi(service) {
228
+ function createSharedApi(service, options) {
229
+ const imports = options ? `import { MicroVerticalBuildMarkerSchema, MicroVerticalReadinessSchema, createMicroVerticalOperationContext } from '${packageName(options.scope, 'shared-contracts')}/microvertical-api-baseline';
230
+ import type { MicroVerticalBuildMarker, MicroVerticalReadiness, MicroVerticalOperationContext } from '${packageName(options.scope, 'shared-contracts')}/microvertical-api-baseline';
231
+ ` : '';
223
232
  return `${createSharedApiImports()}
224
- ${createSharedApiContract(service)}`;
233
+ ${imports}
234
+ ${createSharedApiContract(service, void 0 !== options)}`;
225
235
  }
226
236
  export { createSharedApi };