@bleedingdev/modern-js-code-tools 3.9.0-ultramodern.8 → 3.9.3-ultramodern.1
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/bin/modern-api-check-files.mjs +4 -1
- package/bin/modern-api-check.mjs +1 -1
- package/bin/modern-i18n-check.mjs +4 -0
- package/dist/cjs/cli/microvertical-api-check.cjs +36 -7
- package/dist/cjs/cli/workspace-source-check.cjs +90 -17
- package/dist/cjs/microvertical-api-baseline.cjs +81 -244
- package/dist/cjs/microvertical-api-boundary.cjs +116 -38
- package/dist/cjs/microvertical-api-owner.cjs +5 -2
- package/dist/cjs/module-graph.cjs +1820 -0
- package/dist/cjs/oxlint-plugin/rules/strict-effect-api-boundaries.cjs +1 -1
- package/dist/cjs/source-analysis.cjs +108 -0
- package/dist/cjs/strict-effect-runtime.cjs +16 -51
- package/dist/esm/cli/microvertical-api-check.js +26 -7
- package/dist/esm/cli/workspace-source-check.js +86 -13
- package/dist/esm/microvertical-api-baseline.js +66 -214
- package/dist/esm/microvertical-api-boundary.js +114 -39
- package/dist/esm/microvertical-api-owner.js +5 -2
- package/dist/esm/module-graph.js +1762 -0
- package/dist/esm/oxlint-plugin/rules/strict-effect-api-boundaries.js +1 -1
- package/dist/esm/source-analysis.js +48 -0
- package/dist/esm/strict-effect-runtime.js +16 -50
- package/dist/esm-node/cli/microvertical-api-check.js +26 -7
- package/dist/esm-node/cli/workspace-source-check.js +86 -13
- package/dist/esm-node/microvertical-api-baseline.js +66 -214
- package/dist/esm-node/microvertical-api-boundary.js +114 -39
- package/dist/esm-node/microvertical-api-owner.js +5 -2
- package/dist/esm-node/module-graph.js +1763 -0
- package/dist/esm-node/oxlint-plugin/rules/strict-effect-api-boundaries.js +1 -1
- package/dist/esm-node/source-analysis.js +49 -0
- package/dist/esm-node/strict-effect-runtime.js +16 -50
- package/dist/types/cli/microvertical-api-check.d.ts +1 -1
- package/dist/types/cli/workspace-source-check.d.ts +1 -1
- package/dist/types/microvertical-api-baseline.d.ts +0 -5
- package/dist/types/microvertical-api-boundary.d.ts +15 -1
- package/dist/types/microvertical-api-owner.d.ts +1 -1
- package/dist/types/module-graph.d.ts +92 -0
- package/dist/types/source-analysis.d.ts +13 -0
- package/package.json +17 -13
|
@@ -40,6 +40,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
40
40
|
checkMicroVerticalApiBoundaries: ()=>checkMicroVerticalApiBoundaries,
|
|
41
41
|
checkMicroVerticalApiConsumerFiles: ()=>checkMicroVerticalApiConsumerFiles,
|
|
42
42
|
configuredMicroVerticalApiStem: ()=>external_microvertical_api_baseline_cjs_namespaceObject.configuredMicroVerticalApiStem,
|
|
43
|
+
createModuleGraph: ()=>external_module_graph_cjs_namespaceObject.createModuleGraph,
|
|
43
44
|
microVerticalApiBaselineViolation: ()=>external_microvertical_api_baseline_cjs_namespaceObject.microVerticalApiBaselineViolation
|
|
44
45
|
});
|
|
45
46
|
const external_node_fs_namespaceObject = require("node:fs");
|
|
@@ -50,6 +51,8 @@ const parser_namespaceObject = require("@babel/parser");
|
|
|
50
51
|
const types_namespaceObject = require("@babel/types");
|
|
51
52
|
const external_microvertical_api_baseline_cjs_namespaceObject = require("./microvertical-api-baseline.cjs");
|
|
52
53
|
const external_microvertical_api_owner_cjs_namespaceObject = require("./microvertical-api-owner.cjs");
|
|
54
|
+
const external_module_graph_cjs_namespaceObject = require("./module-graph.cjs");
|
|
55
|
+
const external_source_analysis_cjs_namespaceObject = require("./source-analysis.cjs");
|
|
53
56
|
const external_strict_effect_runtime_cjs_namespaceObject = require("./strict-effect-runtime.cjs");
|
|
54
57
|
const ignored = new Set([
|
|
55
58
|
'.git',
|
|
@@ -65,13 +68,42 @@ const normalize = (file)=>file.split(external_node_path_default().sep).join('/')
|
|
|
65
68
|
const errorMessage = (error)=>error instanceof Error ? error.message : String(error);
|
|
66
69
|
const apiApp = (app)=>'vertical' === app.kind && 'ui-only' !== app.surfaceProfile && 'horizontal-remote' !== app.deliveryUnitKind;
|
|
67
70
|
function configuredApps(root, supplied) {
|
|
68
|
-
const
|
|
69
|
-
if (!Array.isArray(
|
|
71
|
+
const topology = supplied ? void 0 : JSON.parse(external_node_fs_default().readFileSync(external_node_path_default().join(root, 'topology/reference-topology.json'), 'utf8'));
|
|
72
|
+
if (topology && (!topology.shell || !Array.isArray(topology.verticals) || void 0 !== topology.shells && !Array.isArray(topology.shells))) throw new Error('topology/reference-topology.json: shell and verticals must be present');
|
|
73
|
+
const entries = topology?.shell ? [
|
|
74
|
+
topology.shell,
|
|
75
|
+
...topology.shells ?? [],
|
|
76
|
+
...topology.verticals ?? []
|
|
77
|
+
] : void 0;
|
|
78
|
+
const source = supplied ?? entries?.map((entry)=>{
|
|
79
|
+
if (!entry || 'string' != typeof entry.path || !entry.path || external_node_path_default().isAbsolute(entry.path) || entry.path.split(/[\\/]/u).includes('..')) throw new Error('topology/reference-topology.json: each app must have an explicit workspace path');
|
|
80
|
+
const packageFile = external_node_path_default().join(root, entry.path, 'package.json');
|
|
81
|
+
const manifest = JSON.parse(external_node_fs_default().readFileSync(packageFile, 'utf8'));
|
|
82
|
+
if ('string' != typeof manifest.name || !manifest.name || void 0 !== entry.package && entry.package !== manifest.name) throw new Error(`${entry.path}/package.json: package name must match topology`);
|
|
83
|
+
const api = entry.api;
|
|
84
|
+
const stem = api?.stem ?? api?.readiness?.endpoint?.match(/^\/([a-z0-9]+(?:-[a-z0-9]+)*)\/readiness$/u)?.[1];
|
|
85
|
+
return {
|
|
86
|
+
id: entry.id,
|
|
87
|
+
kind: entry.kind,
|
|
88
|
+
path: entry.path,
|
|
89
|
+
package: manifest.name,
|
|
90
|
+
surfaceProfile: entry.surfaceProfile,
|
|
91
|
+
deliveryUnitKind: entry.deliveryUnitKind,
|
|
92
|
+
...void 0 === api ? {} : {
|
|
93
|
+
api: {
|
|
94
|
+
stem,
|
|
95
|
+
prefix: api.bff?.prefix,
|
|
96
|
+
protocol: api.protocol
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
if (!Array.isArray(source)) throw new Error('topology/reference-topology.json: shell and verticals must describe apps');
|
|
70
102
|
const paths = new Set();
|
|
71
103
|
for (const app of source){
|
|
72
|
-
if (!app || 'object' != typeof app || 'string' != typeof app.path || !app.path || external_node_path_default().isAbsolute(app.path) || app.path.split(/[\\/]/u).includes('..')) throw new Error('
|
|
104
|
+
if (!app || 'object' != typeof app || 'string' != typeof app.path || !app.path || external_node_path_default().isAbsolute(app.path) || app.path.split(/[\\/]/u).includes('..')) throw new Error('topology/reference-topology.json: each app must have a relative workspace path');
|
|
73
105
|
const key = normalize(app.path);
|
|
74
|
-
if (paths.has(key)) throw new Error(
|
|
106
|
+
if (paths.has(key)) throw new Error(`topology/reference-topology.json: duplicate app path ${key}`);
|
|
75
107
|
paths.add(key);
|
|
76
108
|
for (const name of [
|
|
77
109
|
'id',
|
|
@@ -80,7 +112,7 @@ function configuredApps(root, supplied) {
|
|
|
80
112
|
'surfaceProfile',
|
|
81
113
|
'deliveryUnitKind'
|
|
82
114
|
])if (void 0 !== app[name] && 'string' != typeof app[name]) throw new Error(`${key}: ${name} must be a string`);
|
|
83
|
-
|
|
115
|
+
const allowedFields = {
|
|
84
116
|
kind: [
|
|
85
117
|
'shell',
|
|
86
118
|
'vertical'
|
|
@@ -94,7 +126,11 @@ function configuredApps(root, supplied) {
|
|
|
94
126
|
'microvertical',
|
|
95
127
|
'horizontal-remote'
|
|
96
128
|
]
|
|
97
|
-
}
|
|
129
|
+
};
|
|
130
|
+
for (const field of Object.keys(allowedFields)){
|
|
131
|
+
const value = app[field];
|
|
132
|
+
if (void 0 !== value && !allowedFields[field].includes(value)) throw new Error(`${key}: invalid ${field}`);
|
|
133
|
+
}
|
|
98
134
|
if (void 0 !== app.api) {
|
|
99
135
|
if (!app.api || 'object' != typeof app.api || Array.isArray(app.api)) throw new Error(`${key}: api must be an object`);
|
|
100
136
|
if (void 0 !== app.api.protocol && ![
|
|
@@ -159,7 +195,7 @@ function check(options, topology) {
|
|
|
159
195
|
const ast = (0, parser_namespaceObject.parse)(read(file), {
|
|
160
196
|
sourceType: 'module',
|
|
161
197
|
sourceFilename: file,
|
|
162
|
-
plugins: (0,
|
|
198
|
+
plugins: (0, external_source_analysis_cjs_namespaceObject.consumerParserPlugins)(file)
|
|
163
199
|
});
|
|
164
200
|
parsed.set(file, ast);
|
|
165
201
|
return ast;
|
|
@@ -182,12 +218,27 @@ function check(options, topology) {
|
|
|
182
218
|
`${base}/index.tsx`
|
|
183
219
|
].find((candidate)=>exists(candidate));
|
|
184
220
|
};
|
|
185
|
-
const
|
|
221
|
+
const clientExportFile = (appPath, exported)=>{
|
|
222
|
+
if ('string' != typeof exported || !exported.startsWith('./') || exported.split(/[\\/]/u).includes('..') || !/\.[cm]?[jt]sx?$/u.test(exported)) return;
|
|
223
|
+
const appDirectory = absolute(appPath);
|
|
224
|
+
const candidate = external_node_path_default().resolve(appDirectory, exported);
|
|
225
|
+
try {
|
|
226
|
+
const workspace = external_node_fs_default().realpathSync(root);
|
|
227
|
+
const owner = external_node_fs_default().realpathSync(appDirectory);
|
|
228
|
+
const real = external_node_fs_default().realpathSync(candidate);
|
|
229
|
+
if (!owner.startsWith(`${workspace}${external_node_path_default().sep}`) || !real.startsWith(`${owner}${external_node_path_default().sep}`) || !external_node_fs_default().statSync(real).isFile()) return;
|
|
230
|
+
} catch {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
return normalize(external_node_path_default().relative(root, candidate));
|
|
234
|
+
};
|
|
235
|
+
const composedModules = (file, appPath)=>{
|
|
186
236
|
const order = [];
|
|
187
237
|
const seen = new Set();
|
|
188
238
|
const queue = [
|
|
189
239
|
file
|
|
190
240
|
];
|
|
241
|
+
const owner = external_node_fs_default().realpathSync(absolute(appPath));
|
|
191
242
|
while(queue.length > 0 && order.length < 128){
|
|
192
243
|
const current = queue.shift();
|
|
193
244
|
if (seen.has(current)) continue;
|
|
@@ -198,16 +249,19 @@ function check(options, topology) {
|
|
|
198
249
|
for (const statement of ast.program.body){
|
|
199
250
|
const source = (types_namespaceObject.isImportDeclaration(statement) || types_namespaceObject.isExportNamedDeclaration(statement) || types_namespaceObject.isExportAllDeclaration(statement)) && statement.source ? statement.source.value : void 0;
|
|
200
251
|
const resolved = void 0 === source ? void 0 : resolveRelative(current, source);
|
|
201
|
-
if (void 0 !== resolved && !seen.has(resolved))
|
|
252
|
+
if (void 0 !== resolved && !seen.has(resolved)) {
|
|
253
|
+
const real = external_node_fs_default().realpathSync(absolute(resolved));
|
|
254
|
+
if (real.startsWith(`${owner}${external_node_path_default().sep}`)) queue.push(resolved);
|
|
255
|
+
}
|
|
202
256
|
}
|
|
203
257
|
}
|
|
204
258
|
return order;
|
|
205
259
|
};
|
|
206
|
-
const moduleShape = (file, imports, calls, patterns = [], defaultExport,
|
|
260
|
+
const moduleShape = (file, imports, calls, patterns = [], defaultExport, composedAppPath)=>{
|
|
207
261
|
if (!exists(file)) return;
|
|
208
262
|
const ast = parseFile(file);
|
|
209
263
|
if (!ast) return;
|
|
210
|
-
const shapeFiles =
|
|
264
|
+
const shapeFiles = composedAppPath ? composedModules(file, composedAppPath) : [
|
|
211
265
|
file
|
|
212
266
|
];
|
|
213
267
|
const body = shapeFiles.flatMap((shapeFile)=>parseFile(shapeFile)?.program.body ?? []);
|
|
@@ -300,7 +354,6 @@ function check(options, topology) {
|
|
|
300
354
|
if (violation) diagnostics.push(`${file}: ${violation}`);
|
|
301
355
|
}
|
|
302
356
|
});
|
|
303
|
-
let owner;
|
|
304
357
|
for (const appPath of appDirectories)guarded(appPath, ()=>{
|
|
305
358
|
const app = byPath.get(appPath);
|
|
306
359
|
const emits = app ? apiApp(app) || 'vertical' !== app.kind && void 0 !== app.api : appPath.startsWith('verticals/') || exists(`${appPath}/api/index.ts`) || exists(`${appPath}/shared/api.ts`);
|
|
@@ -317,19 +370,25 @@ function check(options, topology) {
|
|
|
317
370
|
}
|
|
318
371
|
return;
|
|
319
372
|
}
|
|
320
|
-
if (app?.kind === 'vertical') assert(void 0 !== app.api, `${appPath}: vertical must declare its Effect API in
|
|
373
|
+
if (app?.kind === 'vertical') assert(void 0 !== app.api, `${appPath}: vertical must declare its Effect API in topology/reference-topology.json`);
|
|
321
374
|
const stem = app?.api?.stem ?? external_node_path_default().posix.basename(appPath);
|
|
322
375
|
const rpc = app?.api?.protocol === 'rpc';
|
|
323
376
|
const contract = `${appPath}/shared/${rpc ? 'rpc' : 'api'}.ts`;
|
|
324
|
-
const client = `${appPath}/src/api/${stem}-${rpc ? 'rpc-client' : 'client'}.ts`;
|
|
325
377
|
const entry = `${appPath}/api/index.ts`;
|
|
326
378
|
for (const file of [
|
|
327
379
|
entry,
|
|
328
|
-
contract
|
|
329
|
-
client
|
|
380
|
+
contract
|
|
330
381
|
])assert(exists(file), `${file}: required API surface is missing`);
|
|
382
|
+
const packageFile = `${appPath}/package.json`;
|
|
383
|
+
assert(exists(packageFile), `${packageFile}: required API package is missing`);
|
|
384
|
+
if (!exists(packageFile)) return;
|
|
385
|
+
const manifest = JSON.parse(read(packageFile));
|
|
386
|
+
assert(manifest.exports?.['./api'] === `./shared/${rpc ? 'rpc' : 'api'}.ts`, `${packageFile}: invalid ./api export`);
|
|
387
|
+
const clientKey = `./api/${rpc ? 'rpc-client' : 'client'}`;
|
|
388
|
+
const client = clientExportFile(appPath, manifest.exports?.[clientKey]);
|
|
389
|
+
assert(void 0 !== client, `${packageFile}: invalid API client export`);
|
|
390
|
+
assert(manifest.exports?.[`./api/${rpc ? 'client' : 'rpc-client'}`] === void 0, `${packageFile}: forbidden opposite protocol client export`);
|
|
331
391
|
noPath(`${appPath}/shared/${rpc ? 'api' : 'rpc'}.ts`, `must not emit a ${rpc ? 'REST' : 'RPC'} contract`);
|
|
332
|
-
noPath(`${appPath}/src/api/${stem}-${rpc ? 'client' : 'rpc-client'}.ts`, `must not emit a ${rpc ? 'REST' : 'RPC'} client`);
|
|
333
392
|
if (rpc) {
|
|
334
393
|
moduleShape(entry, [
|
|
335
394
|
[
|
|
@@ -360,7 +419,7 @@ function check(options, topology) {
|
|
|
360
419
|
], 'apiRuntime');
|
|
361
420
|
moduleShape(contract, [
|
|
362
421
|
[
|
|
363
|
-
'effect/
|
|
422
|
+
'effect/rpc',
|
|
364
423
|
[
|
|
365
424
|
'Rpc',
|
|
366
425
|
'RpcGroup'
|
|
@@ -378,7 +437,7 @@ function check(options, topology) {
|
|
|
378
437
|
'Schema.Struct'
|
|
379
438
|
]);
|
|
380
439
|
} else if (exists(contract)) {
|
|
381
|
-
owner
|
|
440
|
+
const owner = options.baselinePackageDirectory ?? (0, external_microvertical_api_owner_cjs_namespaceObject.resolveBaselinePackageDirectory)(absolute(contract));
|
|
382
441
|
const apiPrefix = app?.api?.prefix ?? `/${stem}-api`;
|
|
383
442
|
const basePath = `${apiPrefix}/${stem}`;
|
|
384
443
|
const expectation = {
|
|
@@ -395,21 +454,24 @@ function check(options, topology) {
|
|
|
395
454
|
const violation = (0, external_microvertical_api_baseline_cjs_namespaceObject.microVerticalApiBaselineViolation)(stem, absolute(contract), expectation);
|
|
396
455
|
if (violation) diagnostics.push(`${contract}: ${violation}`);
|
|
397
456
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
457
|
+
if (client) {
|
|
458
|
+
const relativeContract = external_node_path_default().posix.relative(external_node_path_default().posix.dirname(client), contract);
|
|
459
|
+
moduleShape(client, [
|
|
401
460
|
[
|
|
402
|
-
|
|
403
|
-
|
|
461
|
+
effect,
|
|
462
|
+
[
|
|
463
|
+
'Effect',
|
|
464
|
+
rpc ? 'makeEffectRpcClient' : 'makeEffectHttpApiClient'
|
|
465
|
+
]
|
|
466
|
+
],
|
|
467
|
+
[
|
|
468
|
+
relativeContract.startsWith('.') ? relativeContract : `./${relativeContract}`,
|
|
469
|
+
[]
|
|
404
470
|
]
|
|
405
|
-
],
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
]
|
|
410
|
-
], [
|
|
411
|
-
rpc ? 'makeEffectRpcClient' : 'makeEffectHttpApiClient'
|
|
412
|
-
], [], void 0, true);
|
|
471
|
+
], [
|
|
472
|
+
rpc ? 'makeEffectRpcClient' : 'makeEffectHttpApiClient'
|
|
473
|
+
], [], void 0, appPath);
|
|
474
|
+
}
|
|
413
475
|
moduleShape(`${appPath}/api/effect-api.ts`, [], [], [
|
|
414
476
|
[
|
|
415
477
|
/\bbackendFederationContract\b/u,
|
|
@@ -450,12 +512,26 @@ function check(options, topology) {
|
|
|
450
512
|
'must enable strictEffectApproach'
|
|
451
513
|
]
|
|
452
514
|
]);
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
515
|
+
});
|
|
516
|
+
const sourceRules = options.sourceRules ?? [];
|
|
517
|
+
const graph = (0, external_module_graph_cjs_namespaceObject.createModuleGraph)();
|
|
518
|
+
for (const file of sourceRules.length ? sourceFiles : [])if (/\.[cm]?[jt]sx?$/u.test(file)) guarded(file, ()=>{
|
|
519
|
+
let module;
|
|
520
|
+
try {
|
|
521
|
+
module = graph.module(absolute(file));
|
|
522
|
+
} catch (error) {
|
|
523
|
+
if (!(error instanceof external_source_analysis_cjs_namespaceObject.SourceSyntaxError)) throw error;
|
|
524
|
+
diagnostics.push(`${file}: source rules need parseable source (${error.message})`);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
for (const rule of sourceRules){
|
|
528
|
+
const messages = rule({
|
|
529
|
+
file,
|
|
530
|
+
module,
|
|
531
|
+
graph
|
|
532
|
+
});
|
|
533
|
+
if (!Array.isArray(messages) || !messages.every((message)=>'string' == typeof message)) throw new Error(`rule ${rule.name || 'anonymous'} must return an array of violation messages (return [] when the file passes)`);
|
|
534
|
+
for (const message of messages)diagnostics.push(`${file}: ${message}`);
|
|
459
535
|
}
|
|
460
536
|
});
|
|
461
537
|
const shell = 'apps/shell-super-app';
|
|
@@ -495,11 +571,13 @@ const checkMicroVerticalApiConsumerFiles = (options)=>check(options, false);
|
|
|
495
571
|
exports.checkMicroVerticalApiBoundaries = __webpack_exports__.checkMicroVerticalApiBoundaries;
|
|
496
572
|
exports.checkMicroVerticalApiConsumerFiles = __webpack_exports__.checkMicroVerticalApiConsumerFiles;
|
|
497
573
|
exports.configuredMicroVerticalApiStem = __webpack_exports__.configuredMicroVerticalApiStem;
|
|
574
|
+
exports.createModuleGraph = __webpack_exports__.createModuleGraph;
|
|
498
575
|
exports.microVerticalApiBaselineViolation = __webpack_exports__.microVerticalApiBaselineViolation;
|
|
499
576
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
500
577
|
"checkMicroVerticalApiBoundaries",
|
|
501
578
|
"checkMicroVerticalApiConsumerFiles",
|
|
502
579
|
"configuredMicroVerticalApiStem",
|
|
580
|
+
"createModuleGraph",
|
|
503
581
|
"microVerticalApiBaselineViolation"
|
|
504
582
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
505
583
|
Object.defineProperty(exports, '__esModule', {
|
|
@@ -81,7 +81,7 @@ function importTarget(value) {
|
|
|
81
81
|
if (resolved) return resolved;
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
-
function baselinePublicIdentityIsExact(fromFile, expectation) {
|
|
84
|
+
function baselinePublicIdentityIsExact(fromFile, expectation, reportMismatch) {
|
|
85
85
|
const owner = external_node_fs_default().realpathSync(expectation.baselinePackageDirectory);
|
|
86
86
|
const manifest = JSON.parse(external_node_fs_default().readFileSync(external_node_path_default().join(owner, 'package.json'), 'utf8'));
|
|
87
87
|
if (expectation.baselinePackage !== baselinePackage || ![
|
|
@@ -95,7 +95,10 @@ function baselinePublicIdentityIsExact(fromFile, expectation) {
|
|
|
95
95
|
if (error instanceof Error && error.message.includes('resolved to unrelated package')) return false;
|
|
96
96
|
throw error;
|
|
97
97
|
}
|
|
98
|
-
if (resolvedOwner !== owner)
|
|
98
|
+
if (resolvedOwner !== owner) {
|
|
99
|
+
reportMismatch?.(`selected owner ${owner}; consumer resolves ${resolvedOwner}`);
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
99
102
|
const target = importTarget(manifest.exports?.['./microvertical-api']);
|
|
100
103
|
if (!target?.startsWith('./')) return false;
|
|
101
104
|
const modules = new Map();
|