@memberjunction/dynamic-packages 0.0.0 → 6.1.0-edge.6

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/loader.js ADDED
@@ -0,0 +1,404 @@
1
+ /**
2
+ * The loader. One call per process, right after configuration is discovered and BEFORE any
3
+ * database provider is set up — so registration happens exactly where it does in MJAPI, and a
4
+ * `StartupExport` can rely on nothing but the ClassFactory (the contract MJAPI has always
5
+ * imposed: startup exports register classes, they do not touch a provider).
6
+ *
7
+ * Robustness contract, identical to the loader this replaces in @memberjunction/server-bootstrap:
8
+ * no-op when nothing is configured, per-package try/catch, a package that cannot be resolved is
9
+ * reported as not-found (expected before `npm install`, and for a workspace member found on disk
10
+ * whose entry file has not been built yet), a
11
+ * package that resolves but throws surfaces its own error on the warn path, and boot never
12
+ * crashes because of an app package.
13
+ */
14
+ import { existsSync, readFileSync } from 'node:fs';
15
+ import path from 'node:path';
16
+ import { pathToFileURL } from 'node:url';
17
+ import { cosmiconfigSync } from 'cosmiconfig';
18
+ import { DiscoverAppManifestPackages, DiscoverGeneratedPackages, FindWorkspacePackageDir, ReadDynamicPackagesConfig, } from './discover.js';
19
+ import { importFromHost, isResolutionFailure } from './host-import.js';
20
+ import { ResolveDynamicPackagesMode } from './mode.js';
21
+ import { MatchesProcess, NormalizeProcessId } from './process-id.js';
22
+ /** Default output channel: plain console, the way MJAPI has always logged its boot. */
23
+ export const ConsoleDynamicPackagesLogger = {
24
+ info: (message) => console.log(message),
25
+ warn: (message, error) => (error === undefined ? console.warn(message) : console.warn(message, error)),
26
+ verbose: () => undefined,
27
+ };
28
+ /**
29
+ * A logger that keeps stdout clean: progress and warnings go to stderr, verbose detail is dropped.
30
+ * For CLI hosts whose stdout is a machine-readable envelope (`--format=json`, `--output=json`) —
31
+ * the default console logger would print "Loading Open App server packages..." ahead of the JSON.
32
+ */
33
+ export const StderrDynamicPackagesLogger = {
34
+ info: (message) => process.stderr.write(`${message}\n`),
35
+ warn: (message, error) => {
36
+ const detail = error === undefined ? '' : ` ${error instanceof Error ? error.message : String(error)}`;
37
+ process.stderr.write(`${message}${detail}\n`);
38
+ },
39
+ verbose: () => undefined,
40
+ };
41
+ /** A logger that says nothing — for hosts that read the report and render it themselves. */
42
+ export const SilentDynamicPackagesLogger = {
43
+ info: () => undefined,
44
+ warn: () => undefined,
45
+ verbose: () => undefined,
46
+ };
47
+ /**
48
+ * Discovers `mj.config.cjs` with cosmiconfig (module name `mj`) and returns the RAW object plus its
49
+ * path. Hosts whose own config loader Zod-strips `dynamicPackages` use this to hand the loader an
50
+ * unstripped view.
51
+ *
52
+ * @param searchFrom - Directory to start from. Defaults to `process.cwd()`.
53
+ * @param options.searchStrategy - cosmiconfig's search strategy. Defaults to `'global'` (walk up
54
+ * to the home directory — what MJAPI, the `mj` CLI and CodeGen do). A host whose own config
55
+ * loader only looks in the working directory should pass `'none'` so the packages it loads come
56
+ * from the same file its database settings came from.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * const { config, configFilePath } = DiscoverMJConfig();
61
+ * await LoadDynamicPackages({ processId: 'mcp', config, configFilePath });
62
+ * ```
63
+ */
64
+ export function DiscoverMJConfig(searchFrom, options) {
65
+ const explorer = cosmiconfigSync('mj', { searchStrategy: options?.searchStrategy ?? 'global' });
66
+ const result = explorer.search(searchFrom ?? process.cwd());
67
+ return {
68
+ config: (result?.config ?? {}),
69
+ configFilePath: result?.filepath,
70
+ };
71
+ }
72
+ /** Human-readable label for a discovered entry's origin, used in log lines. */
73
+ function describeSource(pkg, tier) {
74
+ switch (pkg.Source) {
75
+ case 'generated':
76
+ return 'generated package';
77
+ case 'manifest':
78
+ return `Open App ${tier} package (from mj-app.json${pkg.Entry.AppName ? ` of ${pkg.Entry.AppName}` : ''})`;
79
+ default:
80
+ return `Open App ${tier} package`;
81
+ }
82
+ }
83
+ /**
84
+ * Loads every dynamic package that applies to `options.processId` and returns a report of what
85
+ * happened to each entry. This is the one call a host makes; everything else in the package is a
86
+ * primitive it composes.
87
+ *
88
+ * @remarks
89
+ * **Order of operations.** Mode is resolved first (`MJ_DYNAMIC_PACKAGES` env var → `options.mode`
90
+ * → `dynamicPackages.policy` → `'load'`). Candidates are then discovered generic-to-specific —
91
+ * the host's `codeGeneration.packages`, then `dynamicPackages.<tier>[]`, then the `mj-app.json`
92
+ * beside the config — and merged by package name ({@link mergeCandidates}). Under mode `'none'`
93
+ * every candidate is reported as skipped and nothing is imported. Otherwise each candidate is
94
+ * filtered (`Enabled === false`, then `Processes` / `ExcludeProcesses` via {@link MatchesProcess}),
95
+ * served from the per-process cache when an earlier call already loaded it (module returned,
96
+ * startup export **not** re-run), or imported through {@link importFromHost} with an on-disk
97
+ * workspace fallback for manifest entries.
98
+ *
99
+ * **Why order matters.** `@RegisterClass` resolves by load-order priority — the last registration
100
+ * for a key wins — so importing generic-to-specific is what makes an Open App's server subclass
101
+ * beat its generated one, and the app you are standing in beat an installed copy.
102
+ *
103
+ * **When to call it.** After the host's class-registration manifest has been imported (so app
104
+ * registrations land last) and before any database provider exists (a `StartupExport` may rely on
105
+ * nothing but the ClassFactory).
106
+ *
107
+ * **Failure model.** Throws only when `processId` is missing. A package that no anchor can resolve
108
+ * is `NotFound` (expected before `npm install`, or for an unbuilt workspace member); one that
109
+ * resolves but throws while loading is `Failed` with its own error, logged on the warn path and
110
+ * never masked by a resolution message. Boot never crashes because of an app package.
111
+ *
112
+ * @param options - Process identity, the raw config and its path, tier, discovery switches, a
113
+ * programmatic mode override, and the logger. See {@link LoadDynamicPackagesOptions}.
114
+ * @returns The {@link DynamicPackagesReport}: `Loaded`, `Skipped` (with a reason), `NotFound`,
115
+ * `Failed`, plus the resolved mode and where it came from.
116
+ *
117
+ * @example Minimal host
118
+ * ```ts
119
+ * const { config, configFilePath } = DiscoverMJConfig();
120
+ * const report = await LoadDynamicPackages({ processId: 'mcp', config, configFilePath });
121
+ * for (const failed of report.Failed) {
122
+ * console.error(`app package ${failed.Entry.PackageName} failed to load`, failed.Error);
123
+ * }
124
+ * ```
125
+ *
126
+ * @example Reading a convention off a loaded module (what MJAPI does for RESOLVER_PATHS)
127
+ * ```ts
128
+ * const resolverPaths = report.Loaded.flatMap((l) => {
129
+ * const paths = l.Module.RESOLVER_PATHS;
130
+ * return Array.isArray(paths) ? (paths as string[]) : [];
131
+ * });
132
+ * ```
133
+ *
134
+ * @example A nested host that inherits the outer process identity
135
+ * ```ts
136
+ * await LoadDynamicPackages({
137
+ * processId: EffectiveProcessId('ai-cli'), // 'cli:ai:agents:run' when run under `mj ai …`
138
+ * config, configFilePath,
139
+ * log: StderrDynamicPackagesLogger, // stdout may be a JSON envelope
140
+ * });
141
+ * ```
142
+ */
143
+ export async function LoadDynamicPackages(options) {
144
+ const processId = NormalizeProcessId(options.processId);
145
+ if (!processId) {
146
+ throw new Error('LoadDynamicPackages: processId is required (e.g. "mjapi", "cli:sync:push", "mcp").');
147
+ }
148
+ const tier = options.tier ?? 'server';
149
+ const log = options.log ?? ConsoleDynamicPackagesLogger;
150
+ const config = options.config ?? null;
151
+ const section = ReadDynamicPackagesConfig(config);
152
+ const resolved = ResolveDynamicPackagesMode({ processId, option: options.mode, policy: section.policy });
153
+ if (resolved.ignoredInvalid) {
154
+ log.warn(`[dynamic-packages] Ignoring invalid ${resolved.ignoredInvalid} (expected 'load' or 'none')`);
155
+ }
156
+ log.verbose?.(`[dynamic-packages] process '${processId}', tier '${tier}', mode '${resolved.mode}' (source: ${resolved.source})`);
157
+ const report = {
158
+ ProcessId: processId,
159
+ Tier: tier,
160
+ Mode: resolved.mode,
161
+ ModeSource: resolved.source,
162
+ Loaded: [],
163
+ Skipped: [],
164
+ NotFound: [],
165
+ Failed: [],
166
+ };
167
+ const { candidates, duplicates } = mergeCandidates(collectCandidates(options, tier, config, section, log));
168
+ for (const duplicate of duplicates) {
169
+ report.Skipped.push({ ...duplicate, Reason: 'duplicate' });
170
+ }
171
+ if (candidates.length === 0) {
172
+ return report;
173
+ }
174
+ if (resolved.mode === 'none') {
175
+ for (const candidate of candidates) {
176
+ report.Skipped.push({ ...candidate, Reason: 'mode-none' });
177
+ }
178
+ log.info(`[dynamic-packages] Skipping ${candidates.length} package(s): mode 'none' (source: ${resolved.source})`);
179
+ return report;
180
+ }
181
+ const alreadyLoaded = loadedInThisProcess();
182
+ let announcedGenerated = false;
183
+ let announcedApps = false;
184
+ for (const candidate of candidates) {
185
+ const { Entry: entry } = candidate;
186
+ // Filters first — an entry disabled or out of scope must stay skipped even when an
187
+ // earlier call in this process loaded the same package (the cache is not a bypass).
188
+ if (entry.Enabled === false) {
189
+ report.Skipped.push({ ...candidate, Reason: 'disabled' });
190
+ log.verbose?.(`[dynamic-packages] Skipping ${entry.PackageName}: disabled`);
191
+ continue;
192
+ }
193
+ if (!MatchesProcess(processId, entry)) {
194
+ report.Skipped.push({ ...candidate, Reason: 'process-filter' });
195
+ log.verbose?.(`[dynamic-packages] Skipping ${entry.PackageName}: not scoped to process '${processId}'`);
196
+ continue;
197
+ }
198
+ const cached = alreadyLoaded.get(entry.PackageName);
199
+ if (cached) {
200
+ // A second host in the same process (e.g. `mj-ai` driven by `mj`) still needs the
201
+ // module — to read RESOLVER_PATHS, MJ_SERVER_EXTENSIONS, … — but must not re-run the
202
+ // startup export. ESM caches the module anyway; this only prevents the double hook.
203
+ report.Loaded.push({ ...candidate, Module: cached, RanStartupExport: false });
204
+ log.verbose?.(`[dynamic-packages] ${entry.PackageName} already loaded in this process; startup export not re-run`);
205
+ continue;
206
+ }
207
+ // Section headers mirror the lines MJAPI has printed at boot for years.
208
+ if (candidate.Source === 'generated' && !announcedGenerated) {
209
+ log.info('Loading generated packages...');
210
+ announcedGenerated = true;
211
+ }
212
+ else if (candidate.Source !== 'generated' && !announcedApps) {
213
+ log.info(`Loading Open App ${tier} packages...`);
214
+ announcedApps = true;
215
+ }
216
+ await loadOne(candidate, options, report, log);
217
+ }
218
+ return report;
219
+ }
220
+ /**
221
+ * Collapses candidates that name the same package into one, in discovery order.
222
+ *
223
+ * The `mj.config.cjs` entry is the operator's authority for a package: it carries `Enabled`
224
+ * (what `mj app disable` writes) and the process scoping. So when an `mj-app.json` beside the
225
+ * config names a package the config also names, the config entry decides whether and where it
226
+ * loads — but the manifest's on-disk location is kept as the resolution fallback, so a package
227
+ * the host cannot `require.resolve` still loads from the workspace. Every later duplicate is
228
+ * returned separately so the report can list it as skipped.
229
+ */
230
+ export function mergeCandidates(all) {
231
+ const byName = new Map();
232
+ const candidates = [];
233
+ const duplicates = [];
234
+ for (const candidate of all) {
235
+ const name = candidate.Entry.PackageName;
236
+ const existing = byName.get(name);
237
+ if (!existing) {
238
+ const first = { ...candidate };
239
+ byName.set(name, first);
240
+ candidates.push(first);
241
+ continue;
242
+ }
243
+ if (candidate.Source === 'config' && existing.Source !== 'config') {
244
+ existing.Entry = candidate.Entry;
245
+ existing.Source = 'config';
246
+ }
247
+ if (!existing.WorkspaceHome && candidate.WorkspaceHome) {
248
+ existing.WorkspaceHome = candidate.WorkspaceHome;
249
+ }
250
+ duplicates.push(candidate);
251
+ }
252
+ return { candidates, duplicates };
253
+ }
254
+ /** Orders the three discovery sources. Manifest discovery failures are the operator's to see, not fatal. */
255
+ function collectCandidates(options, tier, config, section, log) {
256
+ const candidates = [];
257
+ if (options.includeGeneratedPackages !== false) {
258
+ candidates.push(...DiscoverGeneratedPackages(config, tier));
259
+ }
260
+ for (const entry of section[tier] ?? []) {
261
+ candidates.push({ Source: 'config', Entry: entry });
262
+ }
263
+ if (options.discoverAppManifest !== false) {
264
+ const repoDir = options.appManifestDir ?? (options.configFilePath ? path.dirname(options.configFilePath) : process.cwd());
265
+ try {
266
+ const manifest = DiscoverAppManifestPackages(repoDir, tier);
267
+ if (manifest) {
268
+ candidates.push(...manifest.Entries);
269
+ }
270
+ }
271
+ catch (error) {
272
+ log.warn(`[dynamic-packages] Could not read ${path.join(repoDir, 'mj-app.json')}:`, error);
273
+ }
274
+ }
275
+ return candidates;
276
+ }
277
+ async function loadOne(candidate, options, report, log) {
278
+ const { Entry: entry } = candidate;
279
+ const pkgName = entry.PackageName;
280
+ const label = describeSource(candidate, report.Tier);
281
+ const manifestHome = candidate.WorkspaceHome;
282
+ try {
283
+ let mod;
284
+ try {
285
+ mod = await importFromHost(pkgName, options.configFilePath);
286
+ }
287
+ catch (error) {
288
+ // A manifest-sourced package may be a workspace member nothing can require.resolve
289
+ // (pnpm strict layout, root without the package as a dependency). Find it on disk.
290
+ const onDisk = manifestHome && isOwnResolutionFailure(error, pkgName)
291
+ ? FindWorkspacePackageDir(manifestHome.RepoDir, manifestHome.SourceDirectory, pkgName)
292
+ : null;
293
+ if (!onDisk) {
294
+ throw error;
295
+ }
296
+ const entryFile = resolvePackageEntryFile(onDisk);
297
+ if (!existsSync(entryFile)) {
298
+ // The workspace member exists but has not been built (no dist yet) — the expected
299
+ // state before the app's own build, not an error. Report it as not-found, with the
300
+ // file the build is expected to produce, and never on the warn path.
301
+ report.NotFound.push(candidate);
302
+ log.info(` ${label} ${pkgName} found at ${onDisk} but not built (missing ${path.relative(onDisk, entryFile)}) — build it first`);
303
+ return;
304
+ }
305
+ mod = await importPackageDir(entryFile);
306
+ }
307
+ const startup = entry.StartupExport ? mod[entry.StartupExport] : undefined;
308
+ let ranStartupExport = false;
309
+ if (typeof startup === 'function') {
310
+ await Promise.resolve(startup());
311
+ ranStartupExport = true;
312
+ }
313
+ else if (entry.StartupExport) {
314
+ // A named export that is missing is a real mis-configuration (renamed export, stale
315
+ // config) — say so instead of silently skipping it.
316
+ log.warn(` ${label} ${pkgName} has no export named '${entry.StartupExport}' — startup hook not run`);
317
+ }
318
+ const loaded = { ...candidate, Module: mod, RanStartupExport: ranStartupExport };
319
+ report.Loaded.push(loaded);
320
+ loadedInThisProcess().set(pkgName, mod);
321
+ log.info(` Loaded ${label}: ${pkgName}${ranStartupExport ? ` (ran ${entry.StartupExport})` : ''}`);
322
+ }
323
+ catch (error) {
324
+ if (isOwnResolutionFailure(error, pkgName)) {
325
+ report.NotFound.push(candidate);
326
+ log.info(candidate.Source === 'generated'
327
+ ? ` Generated package not found (may not exist yet): ${pkgName}`
328
+ : ` Open App ${report.Tier} package not found (run 'npm install'?): ${pkgName}`);
329
+ }
330
+ else {
331
+ report.Failed.push({ ...candidate, Error: error });
332
+ log.warn(` Error loading ${label} ${pkgName}:`, error);
333
+ }
334
+ }
335
+ }
336
+ /**
337
+ * Modules already loaded by ANY copy of this module in the process, by package name. Kept on
338
+ * `globalThis` (not a module variable) because a duplicated module copy — two dist paths under
339
+ * pnpm, a bundled and an unbundled copy — must still agree on what has run.
340
+ */
341
+ const LOADED_STORE_KEY = Symbol.for('memberjunction.dynamic-packages.loaded');
342
+ function loadedInThisProcess() {
343
+ const store = globalThis;
344
+ let map = store[LOADED_STORE_KEY];
345
+ if (!map) {
346
+ map = new Map();
347
+ store[LOADED_STORE_KEY] = map;
348
+ }
349
+ return map;
350
+ }
351
+ /** Test seam: forget what has been loaded so a fresh process can be simulated. */
352
+ export function ResetLoadedDynamicPackages() {
353
+ loadedInThisProcess().clear();
354
+ }
355
+ /**
356
+ * True only when THIS package is the error's quoted subject ("Cannot find package '<name>'").
357
+ * A missing TRANSITIVE dependency of a package that WAS found quotes the transitive name
358
+ * instead (this package's name still appears unquoted in the imported-from path, which is why
359
+ * a bare `includes(pkgName)` is not enough); that message is the true cause and must reach
360
+ * the operator via the warn path.
361
+ */
362
+ function isOwnResolutionFailure(error, pkgName) {
363
+ const message = error instanceof Error ? error.message : String(error);
364
+ return isResolutionFailure(error) && message.includes(`'${pkgName}'`);
365
+ }
366
+ /**
367
+ * Resolves a package directory's entry file, honouring a string/"."/conditional `exports` map,
368
+ * else `main`, else `index.js`. Pure path work — whether the file exists is the caller's question.
369
+ */
370
+ function resolvePackageEntryFile(dir) {
371
+ const pkgJson = JSON.parse(readFileSync(path.join(dir, 'package.json'), 'utf8'));
372
+ const entry = resolveExportsEntry(pkgJson.exports) ?? (typeof pkgJson.main === 'string' ? pkgJson.main : 'index.js');
373
+ return path.resolve(dir, entry);
374
+ }
375
+ /**
376
+ * Imports a package by its resolved entry file. (Dynamic import is justified here as runtime
377
+ * plugin discovery: the path comes from a manifest on disk, not from code.)
378
+ */
379
+ async function importPackageDir(entryFile) {
380
+ return (await import(pathToFileURL(entryFile).href));
381
+ }
382
+ function resolveExportsEntry(exportsField) {
383
+ if (typeof exportsField === 'string') {
384
+ return exportsField;
385
+ }
386
+ if (!exportsField || typeof exportsField !== 'object') {
387
+ return null;
388
+ }
389
+ const rec = exportsField;
390
+ const root = '.' in rec ? rec['.'] : rec;
391
+ if (typeof root === 'string') {
392
+ return root;
393
+ }
394
+ if (root && typeof root === 'object') {
395
+ const cond = root;
396
+ for (const key of ['import', 'default', 'require', 'node']) {
397
+ if (typeof cond[key] === 'string') {
398
+ return cond[key];
399
+ }
400
+ }
401
+ }
402
+ return null;
403
+ }
404
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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"}
package/dist/mode.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import type { DynamicPackagesMode, DynamicPackagesModeSource } from './types.js';
2
+ /**
3
+ * Environment variable for a per-invocation override, e.g.
4
+ * `MJ_DYNAMIC_PACKAGES=none npx mj sync push` to push with generic BaseEntity only.
5
+ */
6
+ export declare const DYNAMIC_PACKAGES_MODE_ENV_VAR = "MJ_DYNAMIC_PACKAGES";
7
+ export interface ResolvedDynamicPackagesMode {
8
+ mode: DynamicPackagesMode;
9
+ source: DynamicPackagesModeSource;
10
+ /** Set when an env/policy value was present but unparseable — the caller should surface it. */
11
+ ignoredInvalid?: string;
12
+ }
13
+ /**
14
+ * Highest wins:
15
+ * 1. `MJ_DYNAMIC_PACKAGES` env var
16
+ * 2. `option` — programmatic override from the entry point (e.g. a CLI flag)
17
+ * 3. `policy` — `dynamicPackages.policy` from mj.config.cjs, most specific process key
18
+ * 4. `'load'`
19
+ *
20
+ * An invalid env/policy value never crashes a process; it is reported and falls through.
21
+ */
22
+ export declare function ResolveDynamicPackagesMode(args: {
23
+ processId: string;
24
+ option?: DynamicPackagesMode;
25
+ policy?: Record<string, string> | null;
26
+ }): ResolvedDynamicPackagesMode;
27
+ //# sourceMappingURL=mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mode.d.ts","sourceRoot":"","sources":["../src/mode.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAEjF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,wBAAwB,CAAC;AA0BnE,MAAM,WAAW,2BAA2B;IACxC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,MAAM,EAAE,yBAAyB,CAAC;IAClC,+FAA+F;IAC/F,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;CAC1C,GAAG,2BAA2B,CAoB9B"}
package/dist/mode.js ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Mode resolution — the same precedence shape as `ResolveStartupMode` in @memberjunction/core
3
+ * (env var > programmatic option > config > default), so an operator who already knows
4
+ * `MJ_STARTUP_MODE=task npx mj sync push` can reach for `MJ_DYNAMIC_PACKAGES=none` the same way.
5
+ */
6
+ import { ResolveMostSpecific } from './process-id.js';
7
+ /**
8
+ * Environment variable for a per-invocation override, e.g.
9
+ * `MJ_DYNAMIC_PACKAGES=none npx mj sync push` to push with generic BaseEntity only.
10
+ */
11
+ export const DYNAMIC_PACKAGES_MODE_ENV_VAR = 'MJ_DYNAMIC_PACKAGES';
12
+ const MODES = ['load', 'none'];
13
+ /** Accepts the canonical values plus the obvious spellings people will try. */
14
+ function parseMode(value) {
15
+ if (!value) {
16
+ return undefined;
17
+ }
18
+ const normalized = value.trim().toLowerCase();
19
+ if (normalized === 'off' || normalized === 'skip' || normalized === 'false' || normalized === '0') {
20
+ return 'none';
21
+ }
22
+ if (normalized === 'on' || normalized === 'true' || normalized === '1' || normalized === 'full') {
23
+ return 'load';
24
+ }
25
+ return MODES.find((m) => m === normalized);
26
+ }
27
+ function readEnv() {
28
+ if (typeof process === 'undefined' || !process.env) {
29
+ return undefined;
30
+ }
31
+ return process.env[DYNAMIC_PACKAGES_MODE_ENV_VAR];
32
+ }
33
+ /**
34
+ * Highest wins:
35
+ * 1. `MJ_DYNAMIC_PACKAGES` env var
36
+ * 2. `option` — programmatic override from the entry point (e.g. a CLI flag)
37
+ * 3. `policy` — `dynamicPackages.policy` from mj.config.cjs, most specific process key
38
+ * 4. `'load'`
39
+ *
40
+ * An invalid env/policy value never crashes a process; it is reported and falls through.
41
+ */
42
+ export function ResolveDynamicPackagesMode(args) {
43
+ const envRaw = readEnv();
44
+ const envMode = parseMode(envRaw);
45
+ if (envMode) {
46
+ return { mode: envMode, source: 'env' };
47
+ }
48
+ const ignoredInvalid = envRaw && !envMode ? `${DYNAMIC_PACKAGES_MODE_ENV_VAR}='${envRaw}'` : undefined;
49
+ if (args.option) {
50
+ return { mode: args.option, source: 'option', ignoredInvalid };
51
+ }
52
+ const policyRaw = ResolveMostSpecific(args.processId, args.policy);
53
+ const policyMode = parseMode(policyRaw);
54
+ if (policyMode) {
55
+ return { mode: policyMode, source: 'policy', ignoredInvalid };
56
+ }
57
+ const policyInvalid = policyRaw && !policyMode ? `dynamicPackages.policy value '${policyRaw}'` : undefined;
58
+ return { mode: 'load', source: 'default', ignoredInvalid: ignoredInvalid ?? policyInvalid };
59
+ }
60
+ //# sourceMappingURL=mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mode.js","sourceRoot":"","sources":["../src/mode.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAGtD;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,qBAAqB,CAAC;AAEnE,MAAM,KAAK,GAAmC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE/D,+EAA+E;AAC/E,SAAS,SAAS,CAAC,KAAgC;IAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9C,IAAI,UAAU,KAAK,KAAK,IAAI,UAAU,KAAK,MAAM,IAAI,UAAU,KAAK,OAAO,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;QAChG,OAAO,MAAM,CAAC;IAClB,CAAC;IACD,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,MAAM,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC9F,OAAO,MAAM,CAAC;IAClB,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,OAAO;IACZ,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACjD,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;AACtD,CAAC;AASD;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAI1C;IACG,MAAM,MAAM,GAAG,OAAO,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC5C,CAAC;IACD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,6BAA6B,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAEvG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;IACnE,CAAC;IAED,MAAM,SAAS,GAAG,mBAAmB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACnE,MAAM,UAAU,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,UAAU,EAAE,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;IAClE,CAAC;IACD,MAAM,aAAa,GAAG,SAAS,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,iCAAiC,SAAS,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAE3G,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,IAAI,aAAa,EAAE,CAAC;AAChG,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Process identity and prefix matching.
3
+ *
4
+ * Process IDs are hierarchical, colon-separated, lowercase strings: `mjapi`, `cli`,
5
+ * `cli:sync`, `cli:sync:push`, `mcp`. A pattern matches an ID when it equals the ID or names
6
+ * one of its ancestor segments — `cli:sync` matches `cli:sync:push` but not `cli:syncother`
7
+ * or `cli:migrate`. This is what lets a config author scope a package to "all of the CLI",
8
+ * "just mj sync", or exactly one command with the same field.
9
+ */
10
+ /** Wildcard pattern that matches every process. */
11
+ export declare const ANY_PROCESS = "*";
12
+ /** Lowercases, trims, and collapses whitespace around the colon separators. */
13
+ export declare function NormalizeProcessId(value: string): string;
14
+ /**
15
+ * Builds a CLI process ID from an oclif command ID. oclif reports IDs as either `sync:push`
16
+ * or `sync push` (with `topicSeparator: ' '`); both become `cli:sync:push`.
17
+ */
18
+ export declare function CliProcessId(commandId: string | undefined | null): string;
19
+ /** True when `pattern` equals `processId` or is an ancestor prefix of it (segment-aware). */
20
+ export declare function ProcessIdMatches(processId: string, pattern: string): boolean;
21
+ /**
22
+ * Evaluates an entry's `Processes` / `ExcludeProcesses` against a process ID.
23
+ * No `Processes` (or an empty list) means "everywhere"; `ExcludeProcesses` is applied after.
24
+ */
25
+ export declare function MatchesProcess(processId: string, filter: {
26
+ Processes?: string[] | null;
27
+ ExcludeProcesses?: string[] | null;
28
+ } | null | undefined): boolean;
29
+ /**
30
+ * Picks the value of the most specific key in `map` that matches `processId`.
31
+ * `'cli:sync'` beats `'cli'` beats `'*'`. Returns `undefined` when nothing matches.
32
+ */
33
+ export declare function ResolveMostSpecific<T>(processId: string, map: Record<string, T> | null | undefined): T | undefined;
34
+ /**
35
+ * Environment variable through which an OUTER host tells nested hosts which process they are
36
+ * running inside. The `mj` CLI's prerun hook sets it to its own ID (`cli:ai:agents:run`) before
37
+ * the command imports `@memberjunction/ai-cli` or `@memberjunction/testing-cli`; those packages'
38
+ * provider bootstraps then evaluate `Processes` / `ExcludeProcesses` / `policy` under the SAME
39
+ * ID instead of their standalone `ai-cli` / `testing-cli` identity. Without it, an entry an
40
+ * operator excluded from `cli` would be loaded by the nested host a moment later.
41
+ */
42
+ export declare const DYNAMIC_PACKAGES_PROCESS_ENV_VAR = "MJ_DYNAMIC_PACKAGES_PROCESS";
43
+ /**
44
+ * The process ID a host should load under: the one an enclosing host published through
45
+ * {@link DYNAMIC_PACKAGES_PROCESS_ENV_VAR} when there is one, else the host's own default.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * // packages/AI/AICLI — `mj-ai` standalone loads as 'ai-cli'; under `mj ai …` it inherits 'cli:ai:…'
50
+ * await LoadDynamicPackages({ processId: EffectiveProcessId('ai-cli'), ... });
51
+ * ```
52
+ */
53
+ export declare function EffectiveProcessId(hostDefault: string): string;
54
+ //# sourceMappingURL=process-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-id.d.ts","sourceRoot":"","sources":["../src/process-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,mDAAmD;AACnD,eAAO,MAAM,WAAW,MAAM,CAAC;AAE/B,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQxD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAGzE;AAED,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAU5E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC1B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GAC/F,OAAO,CAUT;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,GAAG,SAAS,CAkBlH;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,gCAAgC,gCAAgC,CAAC;AAE9E;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAI9D"}