@rudderjs/cli 4.4.0 → 4.6.0
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/commands/doctor.d.ts +12 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +83 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/tinker.d.ts +48 -0
- package/dist/commands/tinker.d.ts.map +1 -0
- package/dist/commands/tinker.js +192 -0
- package/dist/commands/tinker.js.map +1 -0
- package/dist/doctor/boot-status.d.ts +10 -0
- package/dist/doctor/boot-status.d.ts.map +1 -0
- package/dist/doctor/boot-status.js +15 -0
- package/dist/doctor/boot-status.js.map +1 -0
- package/dist/doctor/built-in/_fs.d.ts +11 -0
- package/dist/doctor/built-in/_fs.d.ts.map +1 -0
- package/dist/doctor/built-in/_fs.js +53 -0
- package/dist/doctor/built-in/_fs.js.map +1 -0
- package/dist/doctor/built-in/deps.d.ts +2 -0
- package/dist/doctor/built-in/deps.d.ts.map +1 -0
- package/dist/doctor/built-in/deps.js +81 -0
- package/dist/doctor/built-in/deps.js.map +1 -0
- package/dist/doctor/built-in/env-vars.d.ts +2 -0
- package/dist/doctor/built-in/env-vars.d.ts.map +1 -0
- package/dist/doctor/built-in/env-vars.js +99 -0
- package/dist/doctor/built-in/env-vars.js.map +1 -0
- package/dist/doctor/built-in/index.d.ts +13 -0
- package/dist/doctor/built-in/index.d.ts.map +1 -0
- package/dist/doctor/built-in/index.js +18 -0
- package/dist/doctor/built-in/index.js.map +1 -0
- package/dist/doctor/built-in/node-version.d.ts +2 -0
- package/dist/doctor/built-in/node-version.d.ts.map +1 -0
- package/dist/doctor/built-in/node-version.js +72 -0
- package/dist/doctor/built-in/node-version.js.map +1 -0
- package/dist/doctor/built-in/package-manager.d.ts +2 -0
- package/dist/doctor/built-in/package-manager.d.ts.map +1 -0
- package/dist/doctor/built-in/package-manager.js +55 -0
- package/dist/doctor/built-in/package-manager.js.map +1 -0
- package/dist/doctor/built-in/runtime.d.ts +2 -0
- package/dist/doctor/built-in/runtime.d.ts.map +1 -0
- package/dist/doctor/built-in/runtime.js +82 -0
- package/dist/doctor/built-in/runtime.js.map +1 -0
- package/dist/doctor/built-in/structure.d.ts +2 -0
- package/dist/doctor/built-in/structure.d.ts.map +1 -0
- package/dist/doctor/built-in/structure.js +93 -0
- package/dist/doctor/built-in/structure.js.map +1 -0
- package/dist/doctor/fixer.d.ts +39 -0
- package/dist/doctor/fixer.d.ts.map +1 -0
- package/dist/doctor/fixer.js +80 -0
- package/dist/doctor/fixer.js.map +1 -0
- package/dist/doctor/load-package-checks.d.ts +2 -0
- package/dist/doctor/load-package-checks.d.ts.map +1 -0
- package/dist/doctor/load-package-checks.js +53 -0
- package/dist/doctor/load-package-checks.js.map +1 -0
- package/dist/doctor/orchestrator.d.ts +34 -0
- package/dist/doctor/orchestrator.d.ts.map +1 -0
- package/dist/doctor/orchestrator.js +65 -0
- package/dist/doctor/orchestrator.js.map +1 -0
- package/dist/doctor/reporter.d.ts +21 -0
- package/dist/doctor/reporter.d.ts.map +1 -0
- package/dist/doctor/reporter.js +151 -0
- package/dist/doctor/reporter.js.map +1 -0
- package/dist/index.js +52 -2
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Command as CommanderCommand } from 'commander';
|
|
2
|
+
export interface DoctorCommandDeps {
|
|
3
|
+
/**
|
|
4
|
+
* Inject the CLI's bootApp so the doctor command can boot the app under
|
|
5
|
+
* `--deep`. Passed by reference rather than imported because the CLI's
|
|
6
|
+
* bootApp suppresses console output (provider chatter is noise here too)
|
|
7
|
+
* and the doctor command shouldn't reimplement that.
|
|
8
|
+
*/
|
|
9
|
+
bootApp: () => Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export declare function doctorCommand(program: CommanderCommand, deps: DoctorCommandDeps): void;
|
|
12
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAQ5D,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAmFtF"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { runChecks } from '../doctor/orchestrator.js';
|
|
2
|
+
import { renderReport, renderFixReport, exitCodeFor } from '../doctor/reporter.js';
|
|
3
|
+
import { loadPackageChecks } from '../doctor/load-package-checks.js';
|
|
4
|
+
import { loadBuiltInChecks } from '../doctor/built-in/index.js';
|
|
5
|
+
import { setBootStatus } from '../doctor/boot-status.js';
|
|
6
|
+
import { applyFixes } from '../doctor/fixer.js';
|
|
7
|
+
export function doctorCommand(program, deps) {
|
|
8
|
+
program
|
|
9
|
+
.command('doctor')
|
|
10
|
+
.description('Diagnose common setup issues in a RudderJS app')
|
|
11
|
+
.option('--deep', 'Also run checks that require booting the app (DB connect, port, …)')
|
|
12
|
+
.option('--fix', 'Auto-apply safe fixes for any failures that declare a fixer')
|
|
13
|
+
.option('--yes', 'Skip fix-mode prompts and apply every fixable failure')
|
|
14
|
+
.option('--verbose', 'Show detail block under each check (not just failures)')
|
|
15
|
+
.option('--json', 'Reserved for a future machine-readable output mode')
|
|
16
|
+
.option('--only <substring>', 'Only run checks whose id contains <substring>')
|
|
17
|
+
.action(async (opts) => {
|
|
18
|
+
if (opts.json) {
|
|
19
|
+
console.error('rudder doctor: --json is reserved for a future release (v1 has no JSON output).');
|
|
20
|
+
process.exit(2);
|
|
21
|
+
}
|
|
22
|
+
// Built-in CLI-owned checks (env, structure, deps, runtime) — registered
|
|
23
|
+
// eagerly via side-effect imports so they're present even if no framework
|
|
24
|
+
// package contributed any.
|
|
25
|
+
loadBuiltInChecks();
|
|
26
|
+
// Lazy-load package-contributed checks.
|
|
27
|
+
await loadPackageChecks();
|
|
28
|
+
// --deep boots the app once so runtime checks can interrogate the live
|
|
29
|
+
// DI container (DB client, queue connection, mail transport, etc.).
|
|
30
|
+
// Boot failure is captured as a check result, not a crash — the rest
|
|
31
|
+
// of the runtime suite then short-circuits to skipped, but the user
|
|
32
|
+
// still sees the boot error verbatim with the failing provider.
|
|
33
|
+
if (opts.deep) {
|
|
34
|
+
const t0 = performance.now();
|
|
35
|
+
try {
|
|
36
|
+
await deps.bootApp();
|
|
37
|
+
setBootStatus({ ok: true, durationMs: performance.now() - t0 });
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
setBootStatus({
|
|
41
|
+
ok: false,
|
|
42
|
+
error: e instanceof Error ? `${e.message}\n${e.stack ?? ''}` : String(e),
|
|
43
|
+
durationMs: performance.now() - t0,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const runOpts = {};
|
|
48
|
+
if (opts.deep)
|
|
49
|
+
runOpts.deep = true;
|
|
50
|
+
if (opts.only !== undefined)
|
|
51
|
+
runOpts.filter = opts.only;
|
|
52
|
+
const reportOpts = {};
|
|
53
|
+
if (opts.verbose)
|
|
54
|
+
reportOpts.verbose = true;
|
|
55
|
+
// First pass — surface every failure to the user before touching anything.
|
|
56
|
+
const result = await runChecks(runOpts);
|
|
57
|
+
console.log(renderReport(result, reportOpts));
|
|
58
|
+
if (!opts.fix) {
|
|
59
|
+
process.exit(exitCodeFor(result));
|
|
60
|
+
}
|
|
61
|
+
// ── --fix path ──────────────────────────────────────
|
|
62
|
+
// Only fixable checks (warn/error with a fixer) are eligible. Prompt
|
|
63
|
+
// each unless --yes; never modify .env or package.json — fixers are
|
|
64
|
+
// idempotent regenerate-style operations only.
|
|
65
|
+
const fixOpts = {};
|
|
66
|
+
if (opts.yes)
|
|
67
|
+
fixOpts.yes = true;
|
|
68
|
+
const fixResult = await applyFixes(result.outcomes, fixOpts);
|
|
69
|
+
console.log('');
|
|
70
|
+
console.log(renderFixReport(fixResult, reportOpts));
|
|
71
|
+
// Second pass — confirm the fixers actually resolved the issues so
|
|
72
|
+
// the user doesn't have to eyeball it. Same runOpts so deep/only flags
|
|
73
|
+
// carry through.
|
|
74
|
+
if (fixResult.applied > 0) {
|
|
75
|
+
console.log('');
|
|
76
|
+
const second = await runChecks(runOpts);
|
|
77
|
+
console.log(renderReport(second, reportOpts));
|
|
78
|
+
process.exit(exitCodeFor(second));
|
|
79
|
+
}
|
|
80
|
+
process.exit(exitCodeFor(result));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAY/C,MAAM,UAAU,aAAa,CAAC,OAAyB,EAAE,IAAuB;IAC9E,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,gDAAgD,CAAC;SAC7D,MAAM,CAAC,QAAQ,EAAK,oEAAoE,CAAC;SACzF,MAAM,CAAC,OAAO,EAAM,6DAA6D,CAAC;SAClF,MAAM,CAAC,OAAO,EAAM,uDAAuD,CAAC;SAC5E,MAAM,CAAC,WAAW,EAAE,wDAAwD,CAAC;SAC7E,MAAM,CAAC,QAAQ,EAAK,oDAAoD,CAAC;SACzE,MAAM,CAAC,oBAAoB,EAAE,+CAA+C,CAAC;SAC7E,MAAM,CAAC,KAAK,EAAE,IAGd,EAAE,EAAE;QACH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,CAAC,KAAK,CAAC,iFAAiF,CAAC,CAAA;YAChG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QAED,yEAAyE;QACzE,0EAA0E;QAC1E,2BAA2B;QAC3B,iBAAiB,EAAE,CAAA;QAEnB,wCAAwC;QACxC,MAAM,iBAAiB,EAAE,CAAA;QAEzB,uEAAuE;QACvE,oEAAoE;QACpE,qEAAqE;QACrE,oEAAoE;QACpE,gEAAgE;QAChE,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;YAC5B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;gBACpB,aAAa,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAA;YACjE,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,aAAa,CAAC;oBACZ,EAAE,EAAK,KAAK;oBACZ,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;oBACxE,UAAU,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE;iBACnC,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAwC,EAAE,CAAA;QACvD,IAAI,IAAI,CAAC,IAAI;YAAgB,OAAO,CAAC,IAAI,GAAK,IAAI,CAAA;QAClD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAA;QAEvD,MAAM,UAAU,GAA0B,EAAE,CAAA;QAC5C,IAAI,IAAI,CAAC,OAAO;YAAE,UAAU,CAAC,OAAO,GAAG,IAAI,CAAA;QAE3C,2EAA2E;QAC3E,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,CAAA;QACvC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAA;QAE7C,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAA;QACnC,CAAC;QAED,uDAAuD;QACvD,qEAAqE;QACrE,oEAAoE;QACpE,+CAA+C;QAC/C,MAAM,OAAO,GAAsB,EAAE,CAAA;QACrC,IAAI,IAAI,CAAC,GAAG;YAAE,OAAO,CAAC,GAAG,GAAG,IAAI,CAAA;QAChC,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QAE5D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACf,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAA;QAEnD,mEAAmE;QACnE,uEAAuE;QACvE,iBAAiB;QACjB,IAAI,SAAS,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YACf,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,CAAA;YACvC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAA;YAC7C,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAA;QACnC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;AACN,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `rudder tinker` — interactive REPL with the app booted.
|
|
3
|
+
*
|
|
4
|
+
* Laravel's `php artisan tinker` equivalent. Drops into a Node REPL after the
|
|
5
|
+
* full app boot completes; pre-populates the REPL context with the DI
|
|
6
|
+
* container accessor, `Route` alias, `rudder` registry, and every model
|
|
7
|
+
* discovered under `app/Models/`. Top-level await works (Node 16+ REPL).
|
|
8
|
+
*
|
|
9
|
+
* The cli sets `RUDDERJS_TINKER=1` before booting so providers can short-
|
|
10
|
+
* circuit anything that would otherwise open a network listener / poll loop.
|
|
11
|
+
* Most providers don't need this — Prisma + BullMQ + ORM clients are already
|
|
12
|
+
* lazy-construct, and network listeners only start on `app.listen()`/`app.serve()`
|
|
13
|
+
* which tinker never calls — but the sentinel exists for providers that DO
|
|
14
|
+
* actively poll/connect on `boot()` (horizon's WorkerCollector is the
|
|
15
|
+
* canonical example; same pattern as `RUDDERJS_QUEUE_WORKER`).
|
|
16
|
+
*/
|
|
17
|
+
import type { Command as CommanderCommand } from 'commander';
|
|
18
|
+
/**
|
|
19
|
+
* Globals injected into the REPL context. Each entry is dynamic-imported so
|
|
20
|
+
* tinker degrades gracefully when a peer isn't installed (router is an
|
|
21
|
+
* optional peer of cli, for instance).
|
|
22
|
+
*/
|
|
23
|
+
interface TinkerContext {
|
|
24
|
+
[name: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
export declare function tinkerCommand(program: CommanderCommand): void;
|
|
27
|
+
/**
|
|
28
|
+
* Build the seed object for the REPL context. Each entry is dynamic-imported
|
|
29
|
+
* so a missing optional peer (router, mcp, …) doesn't crash tinker — the
|
|
30
|
+
* key just doesn't show up in the welcome list.
|
|
31
|
+
*
|
|
32
|
+
* Exported (@internal) for unit testing — the REPL loop itself opens stdin
|
|
33
|
+
* and is hard to drive in-process; the context builder is the testable piece.
|
|
34
|
+
*/
|
|
35
|
+
export declare function buildTinkerContext(modelsDir?: string): Promise<TinkerContext>;
|
|
36
|
+
/**
|
|
37
|
+
* Walk `app/Models/` (single level — nested model dirs are rare and add
|
|
38
|
+
* disambiguation cost). Each file is dynamic-imported; named exports that
|
|
39
|
+
* start with an uppercase letter are registered by name, and the default
|
|
40
|
+
* export is registered under the filename stem.
|
|
41
|
+
*
|
|
42
|
+
* A broken model file (syntax error, missing import) emits one warning and
|
|
43
|
+
* doesn't take down the REPL — tinker stays usable for the user's other
|
|
44
|
+
* models. Same forgiving spirit as `pnpm rudder providers:discover`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function loadModels(ctx: TinkerContext, modelsDir: string): Promise<void>;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=tinker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tinker.d.ts","sourceRoot":"","sources":["../../src/commands/tinker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAc5D;;;;GAIG;AACH,UAAU,aAAa;IACrB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;CACxB;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAuF7D;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA4BnF;AAoBD;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCrF"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import * as nodeRepl from 'node:repl';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
6
|
+
const C = {
|
|
7
|
+
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
8
|
+
cyan: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
9
|
+
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
10
|
+
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
11
|
+
};
|
|
12
|
+
export function tinkerCommand(program) {
|
|
13
|
+
program
|
|
14
|
+
.command('tinker')
|
|
15
|
+
.description('Interactive REPL with the app booted (Laravel artisan tinker equivalent)')
|
|
16
|
+
.option('--no-history', 'Disable persistent ~/.rudder-tinker-history')
|
|
17
|
+
.option('--no-banner', 'Suppress the welcome banner (useful for piping or scripting)')
|
|
18
|
+
.action(async (opts) => {
|
|
19
|
+
const showBanner = opts.banner !== false;
|
|
20
|
+
const useHistory = opts.history !== false;
|
|
21
|
+
if (showBanner) {
|
|
22
|
+
const env = process.env['APP_ENV'] ?? 'local';
|
|
23
|
+
console.log('');
|
|
24
|
+
console.log(` ${C.bold('RudderJS Tinker')} ${C.dim(`— node ${process.version}, env=${env}`)}`);
|
|
25
|
+
console.log('');
|
|
26
|
+
}
|
|
27
|
+
// Build the REPL's seed context — app's DI accessor, Route alias, model
|
|
28
|
+
// classes from app/Models/, plus a few facades when their providers booted.
|
|
29
|
+
const context = await buildTinkerContext();
|
|
30
|
+
if (showBanner) {
|
|
31
|
+
const names = Object.keys(context).sort();
|
|
32
|
+
if (names.length > 0) {
|
|
33
|
+
console.log(` ${C.dim('Available:')}`);
|
|
34
|
+
// Wrap so a long list doesn't blow past the terminal width
|
|
35
|
+
const chunks = [[]];
|
|
36
|
+
let len = 0;
|
|
37
|
+
for (const n of names) {
|
|
38
|
+
if (len + n.length + 2 > 72) {
|
|
39
|
+
chunks.push([]);
|
|
40
|
+
len = 0;
|
|
41
|
+
}
|
|
42
|
+
chunks[chunks.length - 1].push(n);
|
|
43
|
+
len += n.length + 2;
|
|
44
|
+
}
|
|
45
|
+
for (const row of chunks) {
|
|
46
|
+
console.log(` ${row.map(n => C.cyan(n)).join(C.dim(', '))}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
console.log('');
|
|
50
|
+
console.log(` ${C.dim('Top-level await is enabled. Type')} ${C.green('.help')} ${C.dim('for commands.')}`);
|
|
51
|
+
console.log('');
|
|
52
|
+
}
|
|
53
|
+
const replServer = nodeRepl.start({
|
|
54
|
+
prompt: '> ',
|
|
55
|
+
useColors: true,
|
|
56
|
+
terminal: process.stdout.isTTY,
|
|
57
|
+
// The default `eval` already supports top-level await on Node 16+.
|
|
58
|
+
// useGlobal:false (the default) keeps user assignments scoped to
|
|
59
|
+
// the REPL's context, not leaking into globalThis.
|
|
60
|
+
});
|
|
61
|
+
// History persistence — best-effort. setupHistory is callback-style;
|
|
62
|
+
// we ignore errors so a read-only home dir doesn't break tinker.
|
|
63
|
+
if (useHistory) {
|
|
64
|
+
const historyPath = path.join(os.homedir(), '.rudder-tinker-history');
|
|
65
|
+
replServer.setupHistory(historyPath, () => { });
|
|
66
|
+
}
|
|
67
|
+
// Seed the context — assign AFTER setupHistory so the REPL's own
|
|
68
|
+
// `_` placeholder, `module`, `require`, etc are already in place
|
|
69
|
+
// (defineCommand uses some of those internally).
|
|
70
|
+
Object.assign(replServer.context, context);
|
|
71
|
+
// .boot — reload providers + remerge models. Useful after editing a
|
|
72
|
+
// model class without restarting tinker. Best-effort: doesn't try to
|
|
73
|
+
// tear down provider connections; existing references in user-defined
|
|
74
|
+
// variables still point at the old instances.
|
|
75
|
+
replServer.defineCommand('boot', {
|
|
76
|
+
help: 'Re-boot the app to pick up code changes (does not invalidate user-held references)',
|
|
77
|
+
action: async () => {
|
|
78
|
+
try {
|
|
79
|
+
const fresh = await buildTinkerContext();
|
|
80
|
+
Object.assign(replServer.context, fresh);
|
|
81
|
+
console.log(C.dim(` reloaded ${Object.keys(fresh).length} context entries`));
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
console.error(C.dim(' reload failed: ') + (err instanceof Error ? err.message : String(err)));
|
|
85
|
+
}
|
|
86
|
+
replServer.displayPrompt();
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
// Block until the user exits — `.exit` or Ctrl-D.
|
|
90
|
+
await new Promise((resolve) => {
|
|
91
|
+
replServer.on('exit', () => resolve());
|
|
92
|
+
});
|
|
93
|
+
process.exit(0);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Build the seed object for the REPL context. Each entry is dynamic-imported
|
|
98
|
+
* so a missing optional peer (router, mcp, …) doesn't crash tinker — the
|
|
99
|
+
* key just doesn't show up in the welcome list.
|
|
100
|
+
*
|
|
101
|
+
* Exported (@internal) for unit testing — the REPL loop itself opens stdin
|
|
102
|
+
* and is hard to drive in-process; the context builder is the testable piece.
|
|
103
|
+
*/
|
|
104
|
+
export async function buildTinkerContext(modelsDir) {
|
|
105
|
+
const ctx = {};
|
|
106
|
+
// `app()` — DI container accessor (re-exported from @rudderjs/core)
|
|
107
|
+
await tryAdd(ctx, '@rudderjs/core', (mod) => {
|
|
108
|
+
if (typeof mod['app'] === 'function') {
|
|
109
|
+
ctx['app'] = mod.app;
|
|
110
|
+
ctx['config'] = mod.config;
|
|
111
|
+
}
|
|
112
|
+
if (typeof mod['rudder'] !== 'undefined') {
|
|
113
|
+
ctx['rudder'] = mod.rudder;
|
|
114
|
+
ctx['Rudder'] = mod.Rudder;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
// `Route` + `route()` URL generator + `Url` signed-URL helper
|
|
118
|
+
await tryAdd(ctx, '@rudderjs/router', (mod) => {
|
|
119
|
+
const m = mod;
|
|
120
|
+
if (m['Route'])
|
|
121
|
+
ctx['Route'] = m['Route'];
|
|
122
|
+
if (m['route'])
|
|
123
|
+
ctx['route'] = m['route'];
|
|
124
|
+
if (m['Url'])
|
|
125
|
+
ctx['Url'] = m['Url'];
|
|
126
|
+
});
|
|
127
|
+
// Models from app/Models/ — every named export that looks like a class,
|
|
128
|
+
// plus the default export keyed by the filename.
|
|
129
|
+
await loadModels(ctx, modelsDir ?? path.join(process.cwd(), 'app', 'Models'));
|
|
130
|
+
return ctx;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Dynamic-import a package; if it resolves, hand it to the visitor. Swallow
|
|
134
|
+
* any error (peer not installed, broken subpath, etc) — tinker should keep
|
|
135
|
+
* going even if a peer fails to load.
|
|
136
|
+
*/
|
|
137
|
+
async function tryAdd(ctx, pkg, visit) {
|
|
138
|
+
try {
|
|
139
|
+
const mod = await import(/* @vite-ignore */ pkg);
|
|
140
|
+
visit(mod);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
/* peer not installed */
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Walk `app/Models/` (single level — nested model dirs are rare and add
|
|
148
|
+
* disambiguation cost). Each file is dynamic-imported; named exports that
|
|
149
|
+
* start with an uppercase letter are registered by name, and the default
|
|
150
|
+
* export is registered under the filename stem.
|
|
151
|
+
*
|
|
152
|
+
* A broken model file (syntax error, missing import) emits one warning and
|
|
153
|
+
* doesn't take down the REPL — tinker stays usable for the user's other
|
|
154
|
+
* models. Same forgiving spirit as `pnpm rudder providers:discover`.
|
|
155
|
+
*/
|
|
156
|
+
export async function loadModels(ctx, modelsDir) {
|
|
157
|
+
if (!fs.existsSync(modelsDir))
|
|
158
|
+
return;
|
|
159
|
+
for (const file of fs.readdirSync(modelsDir)) {
|
|
160
|
+
if (!file.endsWith('.ts') && !file.endsWith('.js') && !file.endsWith('.mts') && !file.endsWith('.mjs'))
|
|
161
|
+
continue;
|
|
162
|
+
const abs = path.join(modelsDir, file);
|
|
163
|
+
const stem = path.basename(file, path.extname(file));
|
|
164
|
+
// On Windows, Node's ESM loader refuses `import('C:\\path\\file.js')` —
|
|
165
|
+
// absolute paths must be file:// URLs. macOS/Linux accept either form;
|
|
166
|
+
// pathToFileURL is the portable normalizer (same pattern as the doctor's
|
|
167
|
+
// load-package-checks.ts).
|
|
168
|
+
const href = pathToFileURL(abs).href;
|
|
169
|
+
try {
|
|
170
|
+
const mod = await import(/* @vite-ignore */ href);
|
|
171
|
+
let registered = 0;
|
|
172
|
+
for (const [key, val] of Object.entries(mod)) {
|
|
173
|
+
if (key === 'default') {
|
|
174
|
+
ctx[stem] = val;
|
|
175
|
+
registered++;
|
|
176
|
+
}
|
|
177
|
+
else if (key[0] && key[0] === key[0].toUpperCase() && typeof val === 'function') {
|
|
178
|
+
// Uppercase-starting function exports (i.e. classes)
|
|
179
|
+
ctx[key] = val;
|
|
180
|
+
registered++;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Files that exported nothing usable — silently skip (helpers, types, …).
|
|
184
|
+
void registered;
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
188
|
+
console.warn(`${C.dim('[tinker]')} could not load ${file}: ${msg.split('\n')[0]}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=tinker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tinker.js","sourceRoot":"","sources":["../../src/commands/tinker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface BootStatus {
|
|
2
|
+
ok: boolean;
|
|
3
|
+
error?: string;
|
|
4
|
+
/** Wall-clock ms the bootApp() call took (success or failure). */
|
|
5
|
+
durationMs: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function setBootStatus(status: BootStatus): void;
|
|
8
|
+
export declare function getBootStatus(): BootStatus | null;
|
|
9
|
+
export declare function clearBootStatus(): void;
|
|
10
|
+
//# sourceMappingURL=boot-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot-status.d.ts","sourceRoot":"","sources":["../../src/doctor/boot-status.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAK,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAA;CACnB;AAID,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAEtD;AAED,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Boot status singleton — set by the doctor command's --deep path, read by
|
|
2
|
+
// runtime checks. Lives on globalThis so per-package checks (which import
|
|
3
|
+
// from @rudderjs/cli's dist subpath) see the same value.
|
|
4
|
+
const KEY = '__rudderjs_doctor_boot_status__';
|
|
5
|
+
export function setBootStatus(status) {
|
|
6
|
+
;
|
|
7
|
+
globalThis[KEY] = status;
|
|
8
|
+
}
|
|
9
|
+
export function getBootStatus() {
|
|
10
|
+
return globalThis[KEY];
|
|
11
|
+
}
|
|
12
|
+
export function clearBootStatus() {
|
|
13
|
+
delete globalThis[KEY];
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=boot-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot-status.js","sourceRoot":"","sources":["../../src/doctor/boot-status.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,0EAA0E;AAC1E,yDAAyD;AASzD,MAAM,GAAG,GAAG,iCAAiC,CAAA;AAE7C,MAAM,UAAU,aAAa,CAAC,MAAkB;IAC9C,CAAC;IAAC,UAAsC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAA;AACxD,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAQ,UAAsC,CAAC,GAAG,CAAsB,CAAA;AAC1E,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAQ,UAAsC,CAAC,GAAG,CAAC,CAAA;AACrD,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** True if `<cwd>/<rel>` exists and is a file. */
|
|
2
|
+
export declare function fileExists(rel: string): boolean;
|
|
3
|
+
/** Read `<cwd>/<rel>` as a UTF-8 string. Returns null on any error. */
|
|
4
|
+
export declare function readFileSafe(rel: string): string | null;
|
|
5
|
+
/** `fs.stat(<cwd>/<rel>).mtimeMs` or null on error. */
|
|
6
|
+
export declare function mtimeMs(rel: string): number | null;
|
|
7
|
+
/** True if any of the given relative paths exists (file or dir). */
|
|
8
|
+
export declare function anyExists(rels: string[]): boolean;
|
|
9
|
+
/** Read JSON file at `<cwd>/<rel>` or null on error. */
|
|
10
|
+
export declare function readJsonSafe<T = unknown>(rel: string): T | null;
|
|
11
|
+
//# sourceMappingURL=_fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_fs.d.ts","sourceRoot":"","sources":["../../../src/doctor/built-in/_fs.ts"],"names":[],"mappings":"AAGA,kDAAkD;AAClD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAM/C;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMvD;AAED,uDAAuD;AACvD,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMlD;AAED,oEAAoE;AACpE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAQjD;AAED,wDAAwD;AACxD,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAQ/D"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/** True if `<cwd>/<rel>` exists and is a file. */
|
|
4
|
+
export function fileExists(rel) {
|
|
5
|
+
try {
|
|
6
|
+
return fs.statSync(path.join(process.cwd(), rel)).isFile();
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/** Read `<cwd>/<rel>` as a UTF-8 string. Returns null on any error. */
|
|
13
|
+
export function readFileSafe(rel) {
|
|
14
|
+
try {
|
|
15
|
+
return fs.readFileSync(path.join(process.cwd(), rel), 'utf-8');
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** `fs.stat(<cwd>/<rel>).mtimeMs` or null on error. */
|
|
22
|
+
export function mtimeMs(rel) {
|
|
23
|
+
try {
|
|
24
|
+
return fs.statSync(path.join(process.cwd(), rel)).mtimeMs;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** True if any of the given relative paths exists (file or dir). */
|
|
31
|
+
export function anyExists(rels) {
|
|
32
|
+
for (const rel of rels) {
|
|
33
|
+
try {
|
|
34
|
+
fs.statSync(path.join(process.cwd(), rel));
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch { /* keep looking */ }
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
/** Read JSON file at `<cwd>/<rel>` or null on error. */
|
|
42
|
+
export function readJsonSafe(rel) {
|
|
43
|
+
const text = readFileSafe(rel);
|
|
44
|
+
if (text === null)
|
|
45
|
+
return null;
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(text);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=_fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_fs.js","sourceRoot":"","sources":["../../../src/doctor/built-in/_fs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,kDAAkD;AAClD,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAA;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,CAAA;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAA;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,CAAA;YAC1C,OAAO,IAAI,CAAA;QACb,CAAC;QAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,YAAY,CAAc,GAAW;IACnD,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;IAC9B,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAC9B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../../src/doctor/built-in/deps.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { registerDoctorCheck } from '@rudderjs/console';
|
|
4
|
+
import { fileExists, mtimeMs, readJsonSafe } from './_fs.js';
|
|
5
|
+
function isResolvable(pkg) {
|
|
6
|
+
const target = path.join(process.cwd(), 'node_modules', pkg, 'package.json');
|
|
7
|
+
try {
|
|
8
|
+
return fs.statSync(target).isFile();
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
registerDoctorCheck({
|
|
15
|
+
id: 'deps:providers-manifest',
|
|
16
|
+
category: 'deps',
|
|
17
|
+
title: 'providers manifest',
|
|
18
|
+
run() {
|
|
19
|
+
const manifest = 'bootstrap/cache/providers.json';
|
|
20
|
+
if (!fileExists(manifest)) {
|
|
21
|
+
return {
|
|
22
|
+
status: 'warn',
|
|
23
|
+
message: 'missing — providers won\'t auto-discover',
|
|
24
|
+
fix: 'pnpm rudder providers:discover',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const manifestMtime = mtimeMs(manifest);
|
|
28
|
+
const pkgMtime = mtimeMs('package.json');
|
|
29
|
+
if (manifestMtime !== null && pkgMtime !== null && manifestMtime < pkgMtime) {
|
|
30
|
+
return {
|
|
31
|
+
status: 'warn',
|
|
32
|
+
message: 'older than package.json — packages added since last refresh',
|
|
33
|
+
fix: 'pnpm rudder providers:discover',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return { status: 'ok', message: 'present and current' };
|
|
37
|
+
},
|
|
38
|
+
async fixer() {
|
|
39
|
+
// Same logic as `rudder providers:discover` but invoked in-process so
|
|
40
|
+
// --fix doesn't shell out. `@rudderjs/core/commands/providers-discover`
|
|
41
|
+
// re-exports the two pure pieces — scanner + writer.
|
|
42
|
+
try {
|
|
43
|
+
const { scanProviders, writeProviderManifest } = await import(
|
|
44
|
+
/* @vite-ignore */ '@rudderjs/core/commands/providers-discover');
|
|
45
|
+
const sorted = scanProviders(process.cwd());
|
|
46
|
+
writeProviderManifest(process.cwd(), sorted);
|
|
47
|
+
return { status: 'ok', message: `regenerated (${sorted.length} provider${sorted.length === 1 ? '' : 's'})` };
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
51
|
+
return { status: 'error', message: `could not regenerate: ${msg}` };
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
registerDoctorCheck({
|
|
56
|
+
id: 'deps:declared-installed',
|
|
57
|
+
category: 'deps',
|
|
58
|
+
title: '@rudderjs/* installed',
|
|
59
|
+
run() {
|
|
60
|
+
const pkg = readJsonSafe('package.json');
|
|
61
|
+
if (!pkg) {
|
|
62
|
+
return { status: 'error', message: 'package.json unreadable', fix: 'Check the file exists and is valid JSON' };
|
|
63
|
+
}
|
|
64
|
+
const declared = [
|
|
65
|
+
...Object.keys(pkg.dependencies ?? {}),
|
|
66
|
+
...Object.keys(pkg.devDependencies ?? {}),
|
|
67
|
+
].filter(name => name.startsWith('@rudderjs/') || name === 'create-rudder-app');
|
|
68
|
+
const missing = declared.filter(name => !isResolvable(name));
|
|
69
|
+
if (missing.length > 0) {
|
|
70
|
+
return {
|
|
71
|
+
status: 'error',
|
|
72
|
+
message: `${missing.length} declared but not in node_modules: ${missing.join(', ')}`,
|
|
73
|
+
fix: 'Run your package manager install (e.g. `pnpm install`)',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return { status: 'ok', message: `${declared.length} declared, all resolvable` };
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
// `deps:auth-views` moved to @rudderjs/auth/doctor in Phase 3 — it's a
|
|
80
|
+
// package-specific concern that lives with the package that owns it.
|
|
81
|
+
//# sourceMappingURL=deps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../../../src/doctor/built-in/deps.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-vars.d.ts","sourceRoot":"","sources":["../../../src/doctor/built-in/env-vars.ts"],"names":[],"mappings":""}
|