@memberjunction/metadata-sync 5.51.2 → 5.51.3

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 (67) hide show
  1. package/README.md +21 -0
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +3 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/config-manager.d.ts +11 -0
  7. package/dist/lib/config-manager.d.ts.map +1 -1
  8. package/dist/lib/config-manager.js +23 -0
  9. package/dist/lib/config-manager.js.map +1 -1
  10. package/dist/lib/dynamic-packages/discover.d.ts +38 -0
  11. package/dist/lib/dynamic-packages/discover.d.ts.map +1 -0
  12. package/dist/lib/dynamic-packages/discover.js +178 -0
  13. package/dist/lib/dynamic-packages/discover.js.map +1 -0
  14. package/dist/lib/dynamic-packages/host-import.d.ts +43 -0
  15. package/dist/lib/dynamic-packages/host-import.d.ts.map +1 -0
  16. package/dist/lib/dynamic-packages/host-import.js +170 -0
  17. package/dist/lib/dynamic-packages/host-import.js.map +1 -0
  18. package/dist/lib/dynamic-packages/index.d.ts +42 -0
  19. package/dist/lib/dynamic-packages/index.d.ts.map +1 -0
  20. package/dist/lib/dynamic-packages/index.js +6 -0
  21. package/dist/lib/dynamic-packages/index.js.map +1 -0
  22. package/dist/lib/dynamic-packages/loader.d.ts +114 -0
  23. package/dist/lib/dynamic-packages/loader.d.ts.map +1 -0
  24. package/dist/lib/dynamic-packages/loader.js +404 -0
  25. package/dist/lib/dynamic-packages/loader.js.map +1 -0
  26. package/dist/lib/dynamic-packages/mode.d.ts +27 -0
  27. package/dist/lib/dynamic-packages/mode.d.ts.map +1 -0
  28. package/dist/lib/dynamic-packages/mode.js +60 -0
  29. package/dist/lib/dynamic-packages/mode.js.map +1 -0
  30. package/dist/lib/dynamic-packages/process-id.d.ts +54 -0
  31. package/dist/lib/dynamic-packages/process-id.d.ts.map +1 -0
  32. package/dist/lib/dynamic-packages/process-id.js +104 -0
  33. package/dist/lib/dynamic-packages/process-id.js.map +1 -0
  34. package/dist/lib/dynamic-packages/types.d.ts +153 -0
  35. package/dist/lib/dynamic-packages/types.d.ts.map +1 -0
  36. package/dist/lib/dynamic-packages/types.js +14 -0
  37. package/dist/lib/dynamic-packages/types.js.map +1 -0
  38. package/dist/lib/entity-subclass-guard.d.ts +13 -0
  39. package/dist/lib/entity-subclass-guard.d.ts.map +1 -0
  40. package/dist/lib/entity-subclass-guard.js +50 -0
  41. package/dist/lib/entity-subclass-guard.js.map +1 -0
  42. package/dist/lib/file-write-batch.d.ts +0 -4
  43. package/dist/lib/file-write-batch.d.ts.map +1 -1
  44. package/dist/lib/file-write-batch.js +10 -8
  45. package/dist/lib/file-write-batch.js.map +1 -1
  46. package/dist/lib/record-primary-key.d.ts +35 -0
  47. package/dist/lib/record-primary-key.d.ts.map +1 -0
  48. package/dist/lib/record-primary-key.js +44 -0
  49. package/dist/lib/record-primary-key.js.map +1 -0
  50. package/dist/lib/sync-dynamic-packages.d.ts +23 -0
  51. package/dist/lib/sync-dynamic-packages.d.ts.map +1 -0
  52. package/dist/lib/sync-dynamic-packages.js +64 -0
  53. package/dist/lib/sync-dynamic-packages.js.map +1 -0
  54. package/dist/lib/sync-engine.d.ts.map +1 -1
  55. package/dist/lib/sync-engine.js +7 -0
  56. package/dist/lib/sync-engine.js.map +1 -1
  57. package/dist/plugins/index.d.ts.map +1 -1
  58. package/dist/plugins/index.js +8 -2
  59. package/dist/plugins/index.js.map +1 -1
  60. package/dist/services/PullService.d.ts +0 -1
  61. package/dist/services/PullService.d.ts.map +1 -1
  62. package/dist/services/PullService.js +15 -19
  63. package/dist/services/PullService.js.map +1 -1
  64. package/dist/services/PushService.d.ts.map +1 -1
  65. package/dist/services/PushService.js +8 -0
  66. package/dist/services/PushService.js.map +1 -1
  67. package/package.json +13 -13
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 5.x LTS port of `@memberjunction/dynamic-packages` (MJ `next`, PR #4201 — commits 41b0d28215,
3
+ * fd0a019b53, 3cce8940ec). The files in this directory are that package's `src/` as of 3cce8940ec,
4
+ * copied verbatim so `mj.config.cjs` `dynamicPackages` / `codeGeneration.packages` mean exactly the
5
+ * same thing on the 5.x line as on 6.x. On 5.x it is wired into `mj sync push` / `mj sync pull`
6
+ * only (see ../sync-dynamic-packages.ts); MJAPI keeps the 5.x ServerBootstrap loader, and no other
7
+ * process changes. Kept inside metadata-sync rather than published as its own package so the line
8
+ * gains no new npm package. Fix bugs here and in `packages/DynamicPackages` on `next` together.
9
+ *
10
+ * Original package documentation follows.
11
+ *
12
+ * Process-agnostic loader for packages whose names are only known at runtime: Open App server
13
+ * and client packages recorded in `mj.config.cjs` `dynamicPackages.*[]` by `mj app install`,
14
+ * a host's generated packages under `codeGeneration.packages`, and the packages of the Open App
15
+ * whose repository a process is standing in (`mj-app.json`).
16
+ *
17
+ * MJAPI loads these at boot so the ClassFactory hands back an app's entity/action/provider
18
+ * subclasses. Every other MJ process — the `mj` CLI (`sync push`, `app …`, `test`, …), the MCP
19
+ * and A2A servers, the integration-test bootstrap, an ad-hoc script — needs the same behaviour,
20
+ * and this package is where that behaviour lives so each host is one call:
21
+ *
22
+ * ```ts
23
+ * import { LoadDynamicPackages, DiscoverMJConfig } from '@memberjunction/dynamic-packages';
24
+ *
25
+ * const { config, configFilePath } = DiscoverMJConfig();
26
+ * await LoadDynamicPackages({ processId: 'mcp', config, configFilePath });
27
+ * ```
28
+ *
29
+ * Entries can be scoped per process with `Processes` / `ExcludeProcesses`, whole processes can
30
+ * be switched off with `dynamicPackages.policy`, and `MJ_DYNAMIC_PACKAGES=none` (or a host
31
+ * flag that sets it) disables loading for one invocation.
32
+ */
33
+ export type { DiscoveredDynamicPackage, DynamicPackageEntry, DynamicPackageSkipReason, DynamicPackageSource, DynamicPackageTier, DynamicPackagesConfig, DynamicPackagesLogger, DynamicPackagesMode, DynamicPackagesModeSource, DynamicPackagesReport, FailedDynamicPackage, LoadDynamicPackagesOptions, LoadedDynamicPackage, SkippedDynamicPackage, WorkspaceHome, } from './types.js';
34
+ export { importFromHost, isResolutionFailure, resolvePackageJsonFromHost } from './host-import.js';
35
+ export { ANY_PROCESS, CliProcessId, DYNAMIC_PACKAGES_PROCESS_ENV_VAR, EffectiveProcessId, MatchesProcess, NormalizeProcessId, ProcessIdMatches, ResolveMostSpecific, } from './process-id.js';
36
+ export { DYNAMIC_PACKAGES_MODE_ENV_VAR, ResolveDynamicPackagesMode } from './mode.js';
37
+ export type { ResolvedDynamicPackagesMode } from './mode.js';
38
+ export { APP_MANIFEST_FILE_NAME, DiscoverAppManifestPackages, DiscoverGeneratedPackages, FindWorkspacePackageDir, GENERATED_PACKAGE_TYPES_BY_TIER, ReadDynamicPackagesConfig, } from './discover.js';
39
+ export type { AppManifestDiscovery } from './discover.js';
40
+ export type { MJConfigSearchStrategy } from './loader.js';
41
+ export { ConsoleDynamicPackagesLogger, DiscoverMJConfig, LoadDynamicPackages, mergeCandidates, ResetLoadedDynamicPackages, SilentDynamicPackagesLogger, StderrDynamicPackagesLogger, } from './loader.js';
42
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/dynamic-packages/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,YAAY,EACR,wBAAwB,EACxB,mBAAmB,EACnB,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,yBAAyB,EACzB,qBAAqB,EACrB,oBAAoB,EACpB,0BAA0B,EAC1B,oBAAoB,EACpB,qBAAqB,EACrB,aAAa,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AACnG,OAAO,EACH,WAAW,EACX,YAAY,EACZ,gCAAgC,EAChC,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,6BAA6B,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AACtF,YAAY,EAAE,2BAA2B,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EACH,sBAAsB,EACtB,2BAA2B,EAC3B,yBAAyB,EACzB,uBAAuB,EACvB,+BAA+B,EAC/B,yBAAyB,GAC5B,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,YAAY,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EACH,4BAA4B,EAC5B,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,0BAA0B,EAC1B,2BAA2B,EAC3B,2BAA2B,GAC9B,MAAM,aAAa,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { importFromHost, isResolutionFailure, resolvePackageJsonFromHost } from './host-import.js';
2
+ export { ANY_PROCESS, CliProcessId, DYNAMIC_PACKAGES_PROCESS_ENV_VAR, EffectiveProcessId, MatchesProcess, NormalizeProcessId, ProcessIdMatches, ResolveMostSpecific, } from './process-id.js';
3
+ export { DYNAMIC_PACKAGES_MODE_ENV_VAR, ResolveDynamicPackagesMode } from './mode.js';
4
+ export { APP_MANIFEST_FILE_NAME, DiscoverAppManifestPackages, DiscoverGeneratedPackages, FindWorkspacePackageDir, GENERATED_PACKAGE_TYPES_BY_TIER, ReadDynamicPackagesConfig, } from './discover.js';
5
+ export { ConsoleDynamicPackagesLogger, DiscoverMJConfig, LoadDynamicPackages, mergeCandidates, ResetLoadedDynamicPackages, SilentDynamicPackagesLogger, StderrDynamicPackagesLogger, } from './loader.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/dynamic-packages/index.ts"],"names":[],"mappings":"AAiDA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AACnG,OAAO,EACH,WAAW,EACX,YAAY,EACZ,gCAAgC,EAChC,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,6BAA6B,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AAEtF,OAAO,EACH,sBAAsB,EACtB,2BAA2B,EAC3B,yBAAyB,EACzB,uBAAuB,EACvB,+BAA+B,EAC/B,yBAAyB,GAC5B,MAAM,eAAe,CAAC;AAGvB,OAAO,EACH,4BAA4B,EAC5B,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,0BAA0B,EAC1B,2BAA2B,EAC3B,2BAA2B,GAC9B,MAAM,aAAa,CAAC"}
@@ -0,0 +1,114 @@
1
+ import type { DiscoveredDynamicPackage, DynamicPackagesLogger, DynamicPackagesReport, LoadDynamicPackagesOptions } from './types.js';
2
+ /** Default output channel: plain console, the way MJAPI has always logged its boot. */
3
+ export declare const ConsoleDynamicPackagesLogger: DynamicPackagesLogger;
4
+ /**
5
+ * A logger that keeps stdout clean: progress and warnings go to stderr, verbose detail is dropped.
6
+ * For CLI hosts whose stdout is a machine-readable envelope (`--format=json`, `--output=json`) —
7
+ * the default console logger would print "Loading Open App server packages..." ahead of the JSON.
8
+ */
9
+ export declare const StderrDynamicPackagesLogger: DynamicPackagesLogger;
10
+ /** A logger that says nothing — for hosts that read the report and render it themselves. */
11
+ export declare const SilentDynamicPackagesLogger: DynamicPackagesLogger;
12
+ /** cosmiconfig search strategies accepted by {@link DiscoverMJConfig}. */
13
+ export type MJConfigSearchStrategy = 'none' | 'project' | 'global';
14
+ /**
15
+ * Discovers `mj.config.cjs` with cosmiconfig (module name `mj`) and returns the RAW object plus its
16
+ * path. Hosts whose own config loader Zod-strips `dynamicPackages` use this to hand the loader an
17
+ * unstripped view.
18
+ *
19
+ * @param searchFrom - Directory to start from. Defaults to `process.cwd()`.
20
+ * @param options.searchStrategy - cosmiconfig's search strategy. Defaults to `'global'` (walk up
21
+ * to the home directory — what MJAPI, the `mj` CLI and CodeGen do). A host whose own config
22
+ * loader only looks in the working directory should pass `'none'` so the packages it loads come
23
+ * from the same file its database settings came from.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const { config, configFilePath } = DiscoverMJConfig();
28
+ * await LoadDynamicPackages({ processId: 'mcp', config, configFilePath });
29
+ * ```
30
+ */
31
+ export declare function DiscoverMJConfig(searchFrom?: string, options?: {
32
+ searchStrategy?: MJConfigSearchStrategy;
33
+ }): {
34
+ config: Record<string, unknown>;
35
+ configFilePath?: string;
36
+ };
37
+ /**
38
+ * Loads every dynamic package that applies to `options.processId` and returns a report of what
39
+ * happened to each entry. This is the one call a host makes; everything else in the package is a
40
+ * primitive it composes.
41
+ *
42
+ * @remarks
43
+ * **Order of operations.** Mode is resolved first (`MJ_DYNAMIC_PACKAGES` env var → `options.mode`
44
+ * → `dynamicPackages.policy` → `'load'`). Candidates are then discovered generic-to-specific —
45
+ * the host's `codeGeneration.packages`, then `dynamicPackages.<tier>[]`, then the `mj-app.json`
46
+ * beside the config — and merged by package name ({@link mergeCandidates}). Under mode `'none'`
47
+ * every candidate is reported as skipped and nothing is imported. Otherwise each candidate is
48
+ * filtered (`Enabled === false`, then `Processes` / `ExcludeProcesses` via {@link MatchesProcess}),
49
+ * served from the per-process cache when an earlier call already loaded it (module returned,
50
+ * startup export **not** re-run), or imported through {@link importFromHost} with an on-disk
51
+ * workspace fallback for manifest entries.
52
+ *
53
+ * **Why order matters.** `@RegisterClass` resolves by load-order priority — the last registration
54
+ * for a key wins — so importing generic-to-specific is what makes an Open App's server subclass
55
+ * beat its generated one, and the app you are standing in beat an installed copy.
56
+ *
57
+ * **When to call it.** After the host's class-registration manifest has been imported (so app
58
+ * registrations land last) and before any database provider exists (a `StartupExport` may rely on
59
+ * nothing but the ClassFactory).
60
+ *
61
+ * **Failure model.** Throws only when `processId` is missing. A package that no anchor can resolve
62
+ * is `NotFound` (expected before `npm install`, or for an unbuilt workspace member); one that
63
+ * resolves but throws while loading is `Failed` with its own error, logged on the warn path and
64
+ * never masked by a resolution message. Boot never crashes because of an app package.
65
+ *
66
+ * @param options - Process identity, the raw config and its path, tier, discovery switches, a
67
+ * programmatic mode override, and the logger. See {@link LoadDynamicPackagesOptions}.
68
+ * @returns The {@link DynamicPackagesReport}: `Loaded`, `Skipped` (with a reason), `NotFound`,
69
+ * `Failed`, plus the resolved mode and where it came from.
70
+ *
71
+ * @example Minimal host
72
+ * ```ts
73
+ * const { config, configFilePath } = DiscoverMJConfig();
74
+ * const report = await LoadDynamicPackages({ processId: 'mcp', config, configFilePath });
75
+ * for (const failed of report.Failed) {
76
+ * console.error(`app package ${failed.Entry.PackageName} failed to load`, failed.Error);
77
+ * }
78
+ * ```
79
+ *
80
+ * @example Reading a convention off a loaded module (what MJAPI does for RESOLVER_PATHS)
81
+ * ```ts
82
+ * const resolverPaths = report.Loaded.flatMap((l) => {
83
+ * const paths = l.Module.RESOLVER_PATHS;
84
+ * return Array.isArray(paths) ? (paths as string[]) : [];
85
+ * });
86
+ * ```
87
+ *
88
+ * @example A nested host that inherits the outer process identity
89
+ * ```ts
90
+ * await LoadDynamicPackages({
91
+ * processId: EffectiveProcessId('ai-cli'), // 'cli:ai:agents:run' when run under `mj ai …`
92
+ * config, configFilePath,
93
+ * log: StderrDynamicPackagesLogger, // stdout may be a JSON envelope
94
+ * });
95
+ * ```
96
+ */
97
+ export declare function LoadDynamicPackages(options: LoadDynamicPackagesOptions): Promise<DynamicPackagesReport>;
98
+ /**
99
+ * Collapses candidates that name the same package into one, in discovery order.
100
+ *
101
+ * The `mj.config.cjs` entry is the operator's authority for a package: it carries `Enabled`
102
+ * (what `mj app disable` writes) and the process scoping. So when an `mj-app.json` beside the
103
+ * config names a package the config also names, the config entry decides whether and where it
104
+ * loads — but the manifest's on-disk location is kept as the resolution fallback, so a package
105
+ * the host cannot `require.resolve` still loads from the workspace. Every later duplicate is
106
+ * returned separately so the report can list it as skipped.
107
+ */
108
+ export declare function mergeCandidates(all: DiscoveredDynamicPackage[]): {
109
+ candidates: DiscoveredDynamicPackage[];
110
+ duplicates: DiscoveredDynamicPackage[];
111
+ };
112
+ /** Test seam: forget what has been loaded so a fresh process can be simulated. */
113
+ export declare function ResetLoadedDynamicPackages(): void;
114
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/lib/dynamic-packages/loader.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EACR,wBAAwB,EAExB,qBAAqB,EACrB,qBAAqB,EACrB,0BAA0B,EAE7B,MAAM,YAAY,CAAC;AAEpB,uFAAuF;AACvF,eAAO,MAAM,4BAA4B,EAAE,qBAI1C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,EAAE,qBAOzC,CAAC;AAEF,4FAA4F;AAC5F,eAAO,MAAM,2BAA2B,EAAE,qBAIzC,CAAC;AAEF,0EAA0E;AAC1E,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEnE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAC5B,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,sBAAsB,CAAA;CAAE,GACtD;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,CAO9D;AAcD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAkF7G;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,wBAAwB,EAAE,GAAG;IAC9D,UAAU,EAAE,wBAAwB,EAAE,CAAC;IACvC,UAAU,EAAE,wBAAwB,EAAE,CAAC;CAC1C,CAuBA;AAiHD,kFAAkF;AAClF,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}
@@ -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/lib/dynamic-packages/loader.ts"],"names":[],"mappings":"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"}
@@ -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/lib/dynamic-packages/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"}