@lenne.tech/cli 1.9.5 → 1.10.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/README.md +83 -0
- package/build/cli.js +0 -1
- package/build/commands/blocks/add.js +0 -1
- package/build/commands/blocks/blocks.js +0 -1
- package/build/commands/claude/claude.js +0 -1
- package/build/commands/claude/plugins.js +0 -1
- package/build/commands/claude/shortcuts.js +0 -1
- package/build/commands/cli/cli.js +0 -1
- package/build/commands/cli/create.js +0 -1
- package/build/commands/cli/rename.js +0 -1
- package/build/commands/completion.js +34 -2
- package/build/commands/components/add.js +0 -1
- package/build/commands/components/components.js +0 -1
- package/build/commands/config/config.js +0 -1
- package/build/commands/config/help.js +0 -1
- package/build/commands/config/init.js +0 -1
- package/build/commands/config/show.js +0 -1
- package/build/commands/config/validate.js +0 -1
- package/build/commands/deployment/create.js +0 -1
- package/build/commands/deployment/deployment.js +0 -1
- package/build/commands/directus/directus.js +0 -1
- package/build/commands/directus/docker-setup.js +35 -3
- package/build/commands/directus/remove.js +0 -1
- package/build/commands/directus/typegen.js +0 -1
- package/build/commands/docs/docs.js +0 -1
- package/build/commands/docs/open.js +34 -2
- package/build/commands/doctor.js +0 -1
- package/build/commands/frontend/angular.js +0 -1
- package/build/commands/frontend/frontend.js +0 -1
- package/build/commands/frontend/nuxt.js +0 -1
- package/build/commands/fullstack/fullstack.js +0 -1
- package/build/commands/fullstack/init.js +119 -6
- package/build/commands/fullstack/update.js +129 -0
- package/build/commands/git/clean.js +0 -1
- package/build/commands/git/clear.js +0 -1
- package/build/commands/git/create.js +0 -1
- package/build/commands/git/force-pull.js +0 -1
- package/build/commands/git/get.js +0 -1
- package/build/commands/git/git.js +0 -1
- package/build/commands/git/install-scripts.js +0 -1
- package/build/commands/git/rebase.js +0 -1
- package/build/commands/git/rename.js +0 -1
- package/build/commands/git/reset.js +0 -1
- package/build/commands/git/squash.js +0 -1
- package/build/commands/git/undo.js +0 -1
- package/build/commands/git/update.js +0 -1
- package/build/commands/history.js +0 -1
- package/build/commands/lt.js +0 -1
- package/build/commands/mongodb/collection-export.js +35 -3
- package/build/commands/mongodb/mongodb.js +0 -1
- package/build/commands/mongodb/s3-restore.js +35 -3
- package/build/commands/npm/npm.js +0 -1
- package/build/commands/npm/reinit.js +0 -1
- package/build/commands/npm/update.js +0 -1
- package/build/commands/qdrant/delete.js +0 -1
- package/build/commands/qdrant/qdrant.js +0 -1
- package/build/commands/qdrant/stats.js +0 -1
- package/build/commands/redis/redis.js +0 -1
- package/build/commands/server/add-property.js +34 -5
- package/build/commands/server/create-secret.js +34 -2
- package/build/commands/server/create.js +41 -4
- package/build/commands/server/module.js +62 -27
- package/build/commands/server/object.js +30 -7
- package/build/commands/server/permissions.js +20 -7
- package/build/commands/server/server.js +0 -1
- package/build/commands/server/set-secrets.js +0 -1
- package/build/commands/server/test.js +7 -2
- package/build/commands/starter/chrome-extension.js +0 -1
- package/build/commands/starter/starter.js +0 -1
- package/build/commands/status.js +13 -2
- package/build/commands/templates/list.js +0 -1
- package/build/commands/templates/llm.js +0 -1
- package/build/commands/templates/templates.js +0 -1
- package/build/commands/tools/crypt.js +0 -1
- package/build/commands/tools/install-scripts.js +0 -1
- package/build/commands/tools/jwt-read.js +0 -1
- package/build/commands/tools/regex.js +34 -2
- package/build/commands/tools/sha256.js +0 -1
- package/build/commands/tools/tools.js +0 -1
- package/build/commands/typescript/create.js +0 -1
- package/build/commands/typescript/playground.js +0 -1
- package/build/commands/typescript/typescript.js +0 -1
- package/build/commands/update.js +0 -1
- package/build/config/vendor-runtime-deps.json +9 -0
- package/build/extensions/api-mode.js +19 -4
- package/build/extensions/config.js +35 -3
- package/build/extensions/frontend-helper.js +0 -1
- package/build/extensions/git.js +0 -1
- package/build/extensions/history.js +0 -1
- package/build/extensions/logger.js +0 -1
- package/build/extensions/package-manager.js +0 -1
- package/build/extensions/parse-properties.js +0 -1
- package/build/extensions/server.js +1095 -6
- package/build/extensions/template.js +0 -1
- package/build/extensions/tools.js +0 -1
- package/build/extensions/typescript.js +35 -3
- package/build/interfaces/ServerProps.interface.js +0 -1
- package/build/interfaces/extended-gluegun-command.js +0 -1
- package/build/interfaces/extended-gluegun-toolbox.js +0 -1
- package/build/interfaces/lt-config.interface.js +0 -1
- package/build/lib/claude-cli.js +0 -1
- package/build/lib/fallback-scanner.js +0 -1
- package/build/lib/framework-detection.js +167 -0
- package/build/lib/json-utils.js +0 -1
- package/build/lib/marketplace.js +0 -1
- package/build/lib/nuxt-base-components.js +40 -5
- package/build/lib/plugin-utils.js +0 -1
- package/build/lib/shell-config.js +0 -1
- package/build/lib/validation.js +0 -1
- package/build/templates/nest-server-module/inputs/template-create.input.ts.ejs +1 -1
- package/build/templates/nest-server-module/inputs/template.input.ts.ejs +1 -1
- package/build/templates/nest-server-module/outputs/template-fac-result.output.ts.ejs +1 -1
- package/build/templates/nest-server-module/template.controller.ts.ejs +1 -1
- package/build/templates/nest-server-module/template.model.ts.ejs +1 -1
- package/build/templates/nest-server-module/template.module.ts.ejs +1 -1
- package/build/templates/nest-server-module/template.resolver.ts.ejs +1 -1
- package/build/templates/nest-server-module/template.service.ts.ejs +1 -1
- package/build/templates/nest-server-object/template-create.input.ts.ejs +1 -1
- package/build/templates/nest-server-object/template.input.ts.ejs +1 -1
- package/build/templates/nest-server-object/template.object.ts.ejs +1 -1
- package/build/templates/nest-server-tests/tests.e2e-spec.ts.ejs +1 -1
- package/build/templates/vendor-scripts/check-vendor-freshness.mjs +131 -0
- package/build/templates/vendor-scripts/propose-upstream-pr.ts +269 -0
- package/build/templates/vendor-scripts/sync-from-upstream.ts +250 -0
- package/docs/commands.md +13 -0
- package/package.json +22 -13
- package/tsconfig.json +4 -2
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
36
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
37
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -10,9 +43,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
43
|
};
|
|
11
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
45
|
exports.Server = void 0;
|
|
13
|
-
const crypto = require("crypto");
|
|
46
|
+
const crypto = __importStar(require("crypto"));
|
|
14
47
|
const path_1 = require("path");
|
|
15
|
-
const ts = require("typescript");
|
|
48
|
+
const ts = __importStar(require("typescript"));
|
|
16
49
|
/**
|
|
17
50
|
* Server helper functions
|
|
18
51
|
*/
|
|
@@ -222,7 +255,25 @@ class Server {
|
|
|
222
255
|
}
|
|
223
256
|
useDefineForClassFieldsActivated() {
|
|
224
257
|
var _a;
|
|
225
|
-
|
|
258
|
+
// Walk UP from the current working directory to find the nearest
|
|
259
|
+
// tsconfig.json. gluegun's `filesystem.resolve('tsconfig.json')` resolves
|
|
260
|
+
// relative to cwd without checking existence, so it breaks when `lt
|
|
261
|
+
// server module` is invoked from inside `src/` (where no tsconfig lives)
|
|
262
|
+
// — it would then silently return `false`, causing the generator to
|
|
263
|
+
// emit class fields without the `override` modifier that the project's
|
|
264
|
+
// `noImplicitOverride` rule requires.
|
|
265
|
+
const path = require('path');
|
|
266
|
+
let current = this.filesystem.cwd();
|
|
267
|
+
const root = path.parse(current).root;
|
|
268
|
+
let tsConfigPath = null;
|
|
269
|
+
while (current && current !== root) {
|
|
270
|
+
const candidate = path.join(current, 'tsconfig.json');
|
|
271
|
+
if (this.filesystem.exists(candidate)) {
|
|
272
|
+
tsConfigPath = candidate;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
current = path.dirname(current);
|
|
276
|
+
}
|
|
226
277
|
if (tsConfigPath) {
|
|
227
278
|
const readConfig = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
|
|
228
279
|
if (!readConfig.error) {
|
|
@@ -581,7 +632,7 @@ class Server {
|
|
|
581
632
|
setupServer(dest, options) {
|
|
582
633
|
return __awaiter(this, void 0, void 0, function* () {
|
|
583
634
|
const { apiMode: apiModeHelper, patching, system, template, templateHelper } = this.toolbox;
|
|
584
|
-
const { apiMode, author = '', branch, copyPath, description = '', linkPath, name, projectDir, skipInstall = false, skipPatching = false, } = options;
|
|
635
|
+
const { apiMode, author = '', branch, copyPath, description = '', frameworkMode = 'npm', frameworkUpstreamBranch, linkPath, name, projectDir, skipInstall = false, skipPatching = false, } = options;
|
|
585
636
|
// Setup template
|
|
586
637
|
const result = yield templateHelper.setup(dest, {
|
|
587
638
|
branch,
|
|
@@ -644,6 +695,27 @@ class Server {
|
|
|
644
695
|
this.filesystem.remove(`${dest}/.yalc`);
|
|
645
696
|
this.filesystem.remove(`${dest}/yalc.lock`);
|
|
646
697
|
}
|
|
698
|
+
// Vendor-mode transformation — identical to setupServerForFullstack, so
|
|
699
|
+
// a standalone `lt server create --framework-mode vendor` produces the
|
|
700
|
+
// same project layout as `lt fullstack init --framework-mode vendor`.
|
|
701
|
+
// Essentials list is captured BEFORE processApiMode deletes the
|
|
702
|
+
// manifest (same dance as in setupServerForFullstack).
|
|
703
|
+
let standaloneVendorUpstreamDeps = {};
|
|
704
|
+
let standaloneVendorCoreEssentials = [];
|
|
705
|
+
if (frameworkMode === 'vendor') {
|
|
706
|
+
try {
|
|
707
|
+
const converted = yield this.convertCloneToVendored({
|
|
708
|
+
dest,
|
|
709
|
+
projectName: name,
|
|
710
|
+
upstreamBranch: frameworkUpstreamBranch,
|
|
711
|
+
});
|
|
712
|
+
standaloneVendorUpstreamDeps = converted.upstreamDeps;
|
|
713
|
+
}
|
|
714
|
+
catch (err) {
|
|
715
|
+
return { method: result.method, path: dest, success: false };
|
|
716
|
+
}
|
|
717
|
+
standaloneVendorCoreEssentials = this.readApiModeGraphqlEssentials(dest);
|
|
718
|
+
}
|
|
647
719
|
// Process API mode (before install so package.json is correct)
|
|
648
720
|
if (apiMode) {
|
|
649
721
|
try {
|
|
@@ -653,6 +725,21 @@ class Server {
|
|
|
653
725
|
return { method: result.method, path: dest, success: false };
|
|
654
726
|
}
|
|
655
727
|
}
|
|
728
|
+
// Restore core essentials after processApiMode stripped them (vendor + REST only).
|
|
729
|
+
if (frameworkMode === 'vendor' && apiMode === 'Rest') {
|
|
730
|
+
try {
|
|
731
|
+
this.restoreVendorCoreEssentials({
|
|
732
|
+
dest,
|
|
733
|
+
essentials: standaloneVendorCoreEssentials,
|
|
734
|
+
upstreamDeps: standaloneVendorUpstreamDeps,
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
catch (_a) {
|
|
738
|
+
// Non-fatal.
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
// Patch CLAUDE.md with API mode info
|
|
742
|
+
this.patchClaudeMdApiMode(dest, apiMode);
|
|
656
743
|
// Install packages
|
|
657
744
|
if (!skipInstall) {
|
|
658
745
|
try {
|
|
@@ -676,7 +763,21 @@ class Server {
|
|
|
676
763
|
setupServerForFullstack(dest, options) {
|
|
677
764
|
return __awaiter(this, void 0, void 0, function* () {
|
|
678
765
|
const { apiMode: apiModeHelper, templateHelper } = this.toolbox;
|
|
679
|
-
const { apiMode, branch, copyPath, linkPath, name, projectDir } = options;
|
|
766
|
+
const { apiMode, branch, copyPath, frameworkMode = 'npm', frameworkUpstreamBranch, linkPath, name, projectDir, } = options;
|
|
767
|
+
// Both npm and vendor mode clone nest-server-starter as the base. The
|
|
768
|
+
// starter ships the minimal consumer conventions a project needs
|
|
769
|
+
// (src/server/common/models/persistence.model.ts, src/server/modules/user/,
|
|
770
|
+
// file/, meta/, tests/, migrations/, env files, etc.).
|
|
771
|
+
//
|
|
772
|
+
// In vendor mode we additionally clone @lenne.tech/nest-server to
|
|
773
|
+
// obtain the framework `core/` tree, copy it into the project at
|
|
774
|
+
// src/core/ (with the flatten-fix), remove the `@lenne.tech/nest-server`
|
|
775
|
+
// npm dependency, merge its transitive deps into the project
|
|
776
|
+
// package.json, and run a codemod that rewrites every
|
|
777
|
+
// `from '@lenne.tech/nest-server'` import to a relative path pointing
|
|
778
|
+
// at the vendored core.
|
|
779
|
+
//
|
|
780
|
+
// See convertCloneToVendored() below for the exact transformation.
|
|
680
781
|
// Setup template
|
|
681
782
|
const result = yield templateHelper.setup(dest, {
|
|
682
783
|
branch,
|
|
@@ -714,6 +815,38 @@ class Server {
|
|
|
714
815
|
this.filesystem.remove(`${dest}/.yalc`);
|
|
715
816
|
this.filesystem.remove(`${dest}/yalc.lock`);
|
|
716
817
|
}
|
|
818
|
+
// Vendor-mode transformation: strip framework-internal content and wire
|
|
819
|
+
// the remaining files so they behave like a project that consumed the
|
|
820
|
+
// framework's core/ directory directly. Idempotent; safe to skip in
|
|
821
|
+
// npm mode.
|
|
822
|
+
//
|
|
823
|
+
// We capture the framework package.json snapshot from the temp clone so
|
|
824
|
+
// the post-apiMode step can restore upstream-declared core essentials
|
|
825
|
+
// without hard-coding package lists.
|
|
826
|
+
let vendorUpstreamDeps = {};
|
|
827
|
+
let vendorCoreEssentials = [];
|
|
828
|
+
if (frameworkMode === 'vendor') {
|
|
829
|
+
try {
|
|
830
|
+
const converted = yield this.convertCloneToVendored({
|
|
831
|
+
dest,
|
|
832
|
+
projectName: name,
|
|
833
|
+
upstreamBranch: frameworkUpstreamBranch,
|
|
834
|
+
});
|
|
835
|
+
vendorUpstreamDeps = converted.upstreamDeps;
|
|
836
|
+
}
|
|
837
|
+
catch (err) {
|
|
838
|
+
return { method: result.method, path: dest, success: false };
|
|
839
|
+
}
|
|
840
|
+
// Read the graphql-only package list from the starter's
|
|
841
|
+
// api-mode.manifest.json BEFORE processApiMode runs and deletes it.
|
|
842
|
+
// These are exactly the packages processApiMode will strip in REST
|
|
843
|
+
// mode — and in vendor mode they must come back afterwards, because
|
|
844
|
+
// src/core/** still imports them even when the consumer project is
|
|
845
|
+
// REST-only (e.g. PubSub in core-auth.module.ts, GraphQLUpload in
|
|
846
|
+
// core-file.service.ts). List is dynamic; new additions surface
|
|
847
|
+
// automatically.
|
|
848
|
+
vendorCoreEssentials = this.readApiModeGraphqlEssentials(dest);
|
|
849
|
+
}
|
|
717
850
|
// Process API mode (before install which happens at monorepo level)
|
|
718
851
|
if (apiMode) {
|
|
719
852
|
try {
|
|
@@ -723,9 +856,938 @@ class Server {
|
|
|
723
856
|
return { method: result.method, path: dest, success: false };
|
|
724
857
|
}
|
|
725
858
|
}
|
|
859
|
+
// In vendor mode + REST, re-add the graphql essentials that
|
|
860
|
+
// processApiMode just stripped. Both and GraphQL keep all packages
|
|
861
|
+
// by construction and don't need restoration.
|
|
862
|
+
if (frameworkMode === 'vendor' && apiMode === 'Rest') {
|
|
863
|
+
try {
|
|
864
|
+
this.restoreVendorCoreEssentials({
|
|
865
|
+
dest,
|
|
866
|
+
essentials: vendorCoreEssentials,
|
|
867
|
+
upstreamDeps: vendorUpstreamDeps,
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
catch (err) {
|
|
871
|
+
// Non-fatal — install may still succeed if the core never imports
|
|
872
|
+
// the restored packages at the current version.
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
// Patch CLAUDE.md with API mode info
|
|
876
|
+
this.patchClaudeMdApiMode(dest, apiMode);
|
|
726
877
|
return { method: result.method, path: dest, success: true };
|
|
727
878
|
});
|
|
728
879
|
}
|
|
880
|
+
/**
|
|
881
|
+
* Converts a freshly cloned `nest-server-starter` working tree into a
|
|
882
|
+
* vendored-mode consumer project.
|
|
883
|
+
*
|
|
884
|
+
* The starter ships all consumer conventions a project needs (a
|
|
885
|
+
* working `src/server/` with `common/models/persistence.model.ts`,
|
|
886
|
+
* `modules/user/`, `modules/file/`, `modules/meta/`, sample tests,
|
|
887
|
+
* migrations, env files). In npm mode it relies on the
|
|
888
|
+
* `@lenne.tech/nest-server` npm dependency to provide the framework
|
|
889
|
+
* source via `node_modules/@lenne.tech/nest-server/dist/**`.
|
|
890
|
+
*
|
|
891
|
+
* In vendor mode we additionally clone `@lenne.tech/nest-server` to
|
|
892
|
+
* /tmp, copy its framework kernel (`src/core/`, `src/index.ts`,
|
|
893
|
+
* `src/core.module.ts`, `src/test/`, `src/templates/`, `src/types/`,
|
|
894
|
+
* `LICENSE`, `bin/migrate.js`) into the project at `src/core/`
|
|
895
|
+
* applying the flatten-fix, remove `@lenne.tech/nest-server` from the
|
|
896
|
+
* project's `package.json`, merge the framework's transitive deps into
|
|
897
|
+
* the project's own deps, and run an AST-based codemod that rewrites
|
|
898
|
+
* every `from '@lenne.tech/nest-server'` import in consumer code
|
|
899
|
+
* (src/server, src/main.ts, tests/, migrations/, scripts/) to a
|
|
900
|
+
* relative path pointing at the vendored `src/core/`.
|
|
901
|
+
*
|
|
902
|
+
* The resulting tree matches the layout produced by the imo vendoring
|
|
903
|
+
* pilot, so the `nest-server-core-updater` and
|
|
904
|
+
* `nest-server-core-contributor` agents work without any further
|
|
905
|
+
* post-processing.
|
|
906
|
+
*
|
|
907
|
+
* Idempotent — running twice is a no-op.
|
|
908
|
+
*/
|
|
909
|
+
convertCloneToVendored(options) {
|
|
910
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
911
|
+
const { dest, upstreamBranch, upstreamRepoUrl = 'https://github.com/lenneTech/nest-server.git' } = options;
|
|
912
|
+
const filesystem = this.filesystem;
|
|
913
|
+
const { system } = this.toolbox;
|
|
914
|
+
const os = require('os');
|
|
915
|
+
const path = require('path');
|
|
916
|
+
const { Project, SyntaxKind } = require('ts-morph');
|
|
917
|
+
const srcDir = `${dest}/src`;
|
|
918
|
+
const coreDir = `${srcDir}/core`;
|
|
919
|
+
// ── 1. Clone @lenne.tech/nest-server into a temp directory ───────────
|
|
920
|
+
//
|
|
921
|
+
// We clone the framework repo shallowly to get the `src/core/` tree,
|
|
922
|
+
// `bin/migrate.js`, and associated meta files. The clone lives in a
|
|
923
|
+
// throw-away tmp dir that gets cleaned up at the end.
|
|
924
|
+
const tmpClone = path.join(os.tmpdir(), `lt-vendor-nest-server-${Date.now()}`);
|
|
925
|
+
const branchArg = upstreamBranch ? `--branch ${upstreamBranch} ` : '';
|
|
926
|
+
try {
|
|
927
|
+
yield system.run(`git clone --depth 1 ${branchArg}${upstreamRepoUrl} ${tmpClone}`);
|
|
928
|
+
}
|
|
929
|
+
catch (err) {
|
|
930
|
+
// Clone failures usually boil down to one of four causes — network,
|
|
931
|
+
// auth, unknown ref, or a pre-existing tmp dir. Give the user a
|
|
932
|
+
// pointed error message rather than the raw `git clone` stderr.
|
|
933
|
+
const raw = err.message || '';
|
|
934
|
+
const hints = [];
|
|
935
|
+
if (/Could not resolve host|getaddrinfo|ECONNREFUSED|Network is unreachable/i.test(raw)) {
|
|
936
|
+
hints.push('Network issue reaching github.com — check your connection or proxy settings.');
|
|
937
|
+
}
|
|
938
|
+
if (/Permission denied|authentication failed|publickey|403|401/i.test(raw)) {
|
|
939
|
+
hints.push('Authentication issue — the CLI uses an anonymous HTTPS clone; verify GitHub is reachable.');
|
|
940
|
+
}
|
|
941
|
+
if (upstreamBranch && /Remote branch .* not found|did not match any file\(s\) known to git/i.test(raw)) {
|
|
942
|
+
hints.push(`Upstream ref "${upstreamBranch}" does not exist. Check ${upstreamRepoUrl}/tags or /branches for valid refs. ` +
|
|
943
|
+
'Note: nest-server tags have NO "v" prefix — use e.g. "11.24.1", not "v11.24.1".');
|
|
944
|
+
}
|
|
945
|
+
if (/already exists and is not an empty/i.test(raw)) {
|
|
946
|
+
hints.push(`Target directory ${tmpClone} already exists. This usually indicates a stale previous run — rm -rf /tmp/lt-vendor-nest-server-* and retry.`);
|
|
947
|
+
}
|
|
948
|
+
const hintBlock = hints.length > 0 ? `\n Hints:\n - ${hints.join('\n - ')}` : '';
|
|
949
|
+
throw new Error(`Failed to clone ${upstreamRepoUrl}${upstreamBranch ? ` (branch/tag: ${upstreamBranch})` : ''}.\n Raw git error: ${raw.trim()}${hintBlock}`);
|
|
950
|
+
}
|
|
951
|
+
// Snapshot upstream package.json before cleanup so we can merge its
|
|
952
|
+
// transitive deps into the project's package.json (step 5 below).
|
|
953
|
+
let upstreamDeps = {};
|
|
954
|
+
let upstreamDevDeps = {};
|
|
955
|
+
let upstreamVersion = '';
|
|
956
|
+
try {
|
|
957
|
+
const upstreamPkg = filesystem.read(`${tmpClone}/package.json`, 'json');
|
|
958
|
+
if (upstreamPkg && typeof upstreamPkg === 'object') {
|
|
959
|
+
upstreamDeps = upstreamPkg.dependencies || {};
|
|
960
|
+
upstreamDevDeps = upstreamPkg.devDependencies || {};
|
|
961
|
+
upstreamVersion = upstreamPkg.version || '';
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
catch (_a) {
|
|
965
|
+
// Best-effort — if we can't read upstream pkg, the starter's own
|
|
966
|
+
// deps should still cover most of the framework's needs.
|
|
967
|
+
}
|
|
968
|
+
// Snapshot the upstream commit SHA for traceability in VENDOR.md.
|
|
969
|
+
let upstreamCommit = '';
|
|
970
|
+
try {
|
|
971
|
+
const sha = yield system.run(`git -C ${tmpClone} rev-parse HEAD`);
|
|
972
|
+
upstreamCommit = (sha || '').trim();
|
|
973
|
+
}
|
|
974
|
+
catch (_b) {
|
|
975
|
+
// Non-fatal — VENDOR.md will just show an empty SHA.
|
|
976
|
+
}
|
|
977
|
+
try {
|
|
978
|
+
// ── 2. Copy framework kernel into project src/core/ (flatten-fix) ──
|
|
979
|
+
//
|
|
980
|
+
// Upstream layout: src/core/ (framework sub-dir) + src/index.ts +
|
|
981
|
+
// src/core.module.ts + src/test/ + src/templates/ + src/types/.
|
|
982
|
+
// Target layout: everything flat under <project>/src/core/.
|
|
983
|
+
//
|
|
984
|
+
// We WIPE the starter's (non-existent in npm mode) src/core/ first
|
|
985
|
+
// just to guarantee idempotency when users run this twice.
|
|
986
|
+
if (filesystem.exists(coreDir)) {
|
|
987
|
+
filesystem.remove(coreDir);
|
|
988
|
+
}
|
|
989
|
+
const copies = [
|
|
990
|
+
[`${tmpClone}/src/core`, coreDir],
|
|
991
|
+
[`${tmpClone}/src/index.ts`, `${coreDir}/index.ts`],
|
|
992
|
+
[`${tmpClone}/src/core.module.ts`, `${coreDir}/core.module.ts`],
|
|
993
|
+
[`${tmpClone}/src/test`, `${coreDir}/test`],
|
|
994
|
+
[`${tmpClone}/src/templates`, `${coreDir}/templates`],
|
|
995
|
+
[`${tmpClone}/src/types`, `${coreDir}/types`],
|
|
996
|
+
[`${tmpClone}/LICENSE`, `${coreDir}/LICENSE`],
|
|
997
|
+
];
|
|
998
|
+
for (const [from, to] of copies) {
|
|
999
|
+
if (filesystem.exists(from)) {
|
|
1000
|
+
filesystem.copy(from, to);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
// Copy bin/migrate.js so the project has a working migrate CLI
|
|
1004
|
+
// independent of node_modules/@lenne.tech/nest-server.
|
|
1005
|
+
if (filesystem.exists(`${tmpClone}/bin/migrate.js`)) {
|
|
1006
|
+
filesystem.copy(`${tmpClone}/bin/migrate.js`, `${dest}/bin/migrate.js`);
|
|
1007
|
+
}
|
|
1008
|
+
// Copy migration-guides for vendor-sync agent reference (optional
|
|
1009
|
+
// but useful — small overhead, big value for the updater agent).
|
|
1010
|
+
if (filesystem.exists(`${tmpClone}/migration-guides`)) {
|
|
1011
|
+
filesystem.copy(`${tmpClone}/migration-guides`, `${dest}/migration-guides`);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
finally {
|
|
1015
|
+
// Always clean up the temp clone, even if copy fails midway.
|
|
1016
|
+
if (filesystem.exists(tmpClone)) {
|
|
1017
|
+
filesystem.remove(tmpClone);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
// ── 3. Apply flatten-fix rewrites on the vendored files ──────────────
|
|
1021
|
+
//
|
|
1022
|
+
// In `src/core/index.ts` and `src/core/core.module.ts` every relative
|
|
1023
|
+
// specifier that used to be `./core/…` (when the file lived on src/)
|
|
1024
|
+
// must now drop the `./core/` prefix. All OTHER internal imports
|
|
1025
|
+
// within common/, modules/, etc. stay identical because their
|
|
1026
|
+
// relative structure is preserved by the copy.
|
|
1027
|
+
//
|
|
1028
|
+
// Known edge cases from the imo pilot:
|
|
1029
|
+
// - src/core/test/test.helper.ts references '../core/common/helpers/db.helper'
|
|
1030
|
+
// which must become '../common/helpers/db.helper' after the flatten.
|
|
1031
|
+
// - src/core/common/interfaces/core-persistence-model.interface.ts
|
|
1032
|
+
// references '../../..' (three levels up to src/index.ts), which
|
|
1033
|
+
// must become '../..' (two levels up to src/core/index.ts).
|
|
1034
|
+
const tsMorphProject = new Project({ skipAddingFilesFromTsConfig: true });
|
|
1035
|
+
const flattenTargets = [`${coreDir}/index.ts`, `${coreDir}/core.module.ts`];
|
|
1036
|
+
for (const target of flattenTargets) {
|
|
1037
|
+
if (!filesystem.exists(target))
|
|
1038
|
+
continue;
|
|
1039
|
+
const sourceFile = tsMorphProject.addSourceFileAtPath(target);
|
|
1040
|
+
for (const decl of sourceFile.getImportDeclarations()) {
|
|
1041
|
+
const spec = decl.getModuleSpecifierValue();
|
|
1042
|
+
if (spec && spec.startsWith('./core/')) {
|
|
1043
|
+
decl.setModuleSpecifier(spec.replace(/^\.\/core\//, './'));
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
for (const decl of sourceFile.getExportDeclarations()) {
|
|
1047
|
+
const spec = decl.getModuleSpecifierValue();
|
|
1048
|
+
if (spec && spec.startsWith('./core/')) {
|
|
1049
|
+
decl.setModuleSpecifier(spec.replace(/^\.\/core\//, './'));
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
sourceFile.saveSync();
|
|
1053
|
+
}
|
|
1054
|
+
const testHelperPath = `${coreDir}/test/test.helper.ts`;
|
|
1055
|
+
if (filesystem.exists(testHelperPath)) {
|
|
1056
|
+
const sourceFile = tsMorphProject.addSourceFileAtPath(testHelperPath);
|
|
1057
|
+
for (const decl of sourceFile.getImportDeclarations()) {
|
|
1058
|
+
const spec = decl.getModuleSpecifierValue();
|
|
1059
|
+
if (spec && spec.startsWith('../core/')) {
|
|
1060
|
+
decl.setModuleSpecifier(spec.replace(/^\.\.\/core\//, '../'));
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
sourceFile.saveSync();
|
|
1064
|
+
}
|
|
1065
|
+
const persistenceIfacePath = `${coreDir}/common/interfaces/core-persistence-model.interface.ts`;
|
|
1066
|
+
if (filesystem.exists(persistenceIfacePath)) {
|
|
1067
|
+
const sourceFile = tsMorphProject.addSourceFileAtPath(persistenceIfacePath);
|
|
1068
|
+
for (const decl of sourceFile.getImportDeclarations()) {
|
|
1069
|
+
const spec = decl.getModuleSpecifierValue();
|
|
1070
|
+
if (spec === '../../..') {
|
|
1071
|
+
decl.setModuleSpecifier('../..');
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
sourceFile.saveSync();
|
|
1075
|
+
}
|
|
1076
|
+
// Edge: core-better-auth-user.mapper.ts uses `ScryptOptions` as a type
|
|
1077
|
+
// annotation without an explicit import. Upstream relies on older
|
|
1078
|
+
// @types/node versions where ScryptOptions was a global. With newer
|
|
1079
|
+
// @types/node (25+) it must be imported from 'crypto'. Add the import.
|
|
1080
|
+
const betterAuthMapperPath = `${coreDir}/modules/better-auth/core-better-auth-user.mapper.ts`;
|
|
1081
|
+
if (filesystem.exists(betterAuthMapperPath)) {
|
|
1082
|
+
const raw = filesystem.read(betterAuthMapperPath) || '';
|
|
1083
|
+
if (raw.includes('ScryptOptions') && !raw.includes('type ScryptOptions')) {
|
|
1084
|
+
// Replace the bare `randomBytes, scrypt` crypto import with one
|
|
1085
|
+
// that also pulls in the ScryptOptions type.
|
|
1086
|
+
const patched = raw.replace(/import\s+\{\s*randomBytes\s*,\s*scrypt\s*\}\s+from\s+['"]crypto['"]\s*;/, "import { randomBytes, scrypt, type ScryptOptions } from 'crypto';");
|
|
1087
|
+
if (patched !== raw) {
|
|
1088
|
+
filesystem.write(betterAuthMapperPath, patched);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
// ── 4. Rewrite consumer imports: '@lenne.tech/nest-server' → relative ─
|
|
1093
|
+
//
|
|
1094
|
+
// Every .ts file in the starter's src/server/, src/main.ts, tests/,
|
|
1095
|
+
// migrations/, scripts/, migrations-utils/ currently imports from
|
|
1096
|
+
// '@lenne.tech/nest-server'. After vendoring, these must use a
|
|
1097
|
+
// relative path to src/core whose depth depends on the file location.
|
|
1098
|
+
// We handle static imports, dynamic imports, and CJS require() calls.
|
|
1099
|
+
const codemodGlobs = [
|
|
1100
|
+
`${dest}/src/server/**/*.ts`,
|
|
1101
|
+
`${dest}/src/main.ts`,
|
|
1102
|
+
`${dest}/src/config.env.ts`,
|
|
1103
|
+
`${dest}/tests/**/*.ts`,
|
|
1104
|
+
`${dest}/migrations/**/*.ts`,
|
|
1105
|
+
`${dest}/migrations-utils/*.ts`,
|
|
1106
|
+
`${dest}/scripts/**/*.ts`,
|
|
1107
|
+
];
|
|
1108
|
+
tsMorphProject.addSourceFilesAtPaths(codemodGlobs);
|
|
1109
|
+
for (const file of tsMorphProject.getSourceFiles()) {
|
|
1110
|
+
const filePath = file.getFilePath();
|
|
1111
|
+
// Skip files inside src/core/ — those are the framework itself.
|
|
1112
|
+
if (filePath.startsWith(coreDir))
|
|
1113
|
+
continue;
|
|
1114
|
+
const fromDir = path.dirname(filePath);
|
|
1115
|
+
let relToCore = path.relative(fromDir, coreDir).split(path.sep).join('/');
|
|
1116
|
+
if (!relToCore.startsWith('.')) {
|
|
1117
|
+
relToCore = `./${relToCore}`;
|
|
1118
|
+
}
|
|
1119
|
+
let touched = false;
|
|
1120
|
+
// Static import declarations
|
|
1121
|
+
for (const decl of file.getImportDeclarations()) {
|
|
1122
|
+
if (decl.getModuleSpecifierValue() === '@lenne.tech/nest-server') {
|
|
1123
|
+
decl.setModuleSpecifier(relToCore);
|
|
1124
|
+
touched = true;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
// Static export declarations (re-exports)
|
|
1128
|
+
for (const decl of file.getExportDeclarations()) {
|
|
1129
|
+
if (decl.getModuleSpecifierValue() === '@lenne.tech/nest-server') {
|
|
1130
|
+
decl.setModuleSpecifier(relToCore);
|
|
1131
|
+
touched = true;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
// Dynamic imports + CJS require('@lenne.tech/nest-server')
|
|
1135
|
+
file.forEachDescendant((node) => {
|
|
1136
|
+
if (node.getKind() !== SyntaxKind.CallExpression)
|
|
1137
|
+
return;
|
|
1138
|
+
const call = node;
|
|
1139
|
+
const expr = call.getExpression();
|
|
1140
|
+
const exprText = expr.getText();
|
|
1141
|
+
const args = call.getArguments();
|
|
1142
|
+
if (args.length === 0)
|
|
1143
|
+
return;
|
|
1144
|
+
const firstArg = args[0];
|
|
1145
|
+
if (firstArg.getKind() !== SyntaxKind.StringLiteral)
|
|
1146
|
+
return;
|
|
1147
|
+
if (firstArg.getLiteralText() !== '@lenne.tech/nest-server')
|
|
1148
|
+
return;
|
|
1149
|
+
if (exprText === 'require' || exprText === 'import' || expr.getKind() === SyntaxKind.ImportKeyword) {
|
|
1150
|
+
firstArg.replaceWithText(`'${relToCore}'`);
|
|
1151
|
+
touched = true;
|
|
1152
|
+
}
|
|
1153
|
+
});
|
|
1154
|
+
if (touched) {
|
|
1155
|
+
file.saveSync();
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
// Also patch migrations-utils/*.js (CJS require) via raw string replace
|
|
1159
|
+
// because ts-morph doesn't load .js files in our Project instance.
|
|
1160
|
+
const migrationsUtilsDir = `${dest}/migrations-utils`;
|
|
1161
|
+
if (filesystem.exists(migrationsUtilsDir)) {
|
|
1162
|
+
const jsFiles = filesystem.find(migrationsUtilsDir, { matching: '*.js', recursive: false });
|
|
1163
|
+
for (const f of jsFiles || []) {
|
|
1164
|
+
try {
|
|
1165
|
+
const content = filesystem.read(f);
|
|
1166
|
+
if (content && content.includes('@lenne.tech/nest-server')) {
|
|
1167
|
+
// The migrate helper path is at core/modules/migrate/helpers/migration.helper
|
|
1168
|
+
// regardless of mode, so we replace the package root reference
|
|
1169
|
+
// with the relative path to the vendored core.
|
|
1170
|
+
const fromDir = path.dirname(f);
|
|
1171
|
+
let relToCore = path.relative(fromDir, coreDir).split(path.sep).join('/');
|
|
1172
|
+
if (!relToCore.startsWith('.')) {
|
|
1173
|
+
relToCore = `./${relToCore}`;
|
|
1174
|
+
}
|
|
1175
|
+
const patched = content
|
|
1176
|
+
.replace(/require\(['"]@lenne\.tech\/nest-server['"]\)/g, `require('${relToCore}')`)
|
|
1177
|
+
.replace(/require\(['"]@lenne\.tech\/nest-server\/dist\/([^'"]+)['"]\)/g, (_m, sub) => `require('${relToCore}/${sub}')`);
|
|
1178
|
+
if (patched !== content) {
|
|
1179
|
+
filesystem.write(f, patched);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
catch (_c) {
|
|
1184
|
+
// skip unreadable file
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
// Explicit rewrite of migrations-utils/migrate.js — the generic codemod
|
|
1189
|
+
// above works indirectly (via `bin/migrate.js` loading ts-node first),
|
|
1190
|
+
// but it's fragile: if somebody invokes migrate.js standalone, `require
|
|
1191
|
+
// ('../src/core')` would crash because Node cannot load TypeScript.
|
|
1192
|
+
// Replace the file with the explicit, imo-pilot-proven variant that
|
|
1193
|
+
// registers ts-node itself BEFORE requiring the vendored core and
|
|
1194
|
+
// points at the specific migration.helper path (not the index hub).
|
|
1195
|
+
const migrateJsPath = `${dest}/migrations-utils/migrate.js`;
|
|
1196
|
+
filesystem.write(migrateJsPath, [
|
|
1197
|
+
'// The vendored core is TypeScript-only (no prebuilt dist/). Register ts-node (via our',
|
|
1198
|
+
'// custom bootstrap) before requiring any vendor module, so that .ts source files are',
|
|
1199
|
+
'// transparently compiled on demand. Uses the same compiler config as the migrate CLI.',
|
|
1200
|
+
"require('./ts-compiler');",
|
|
1201
|
+
'',
|
|
1202
|
+
"const { createMigrationStore } = require('../src/core/modules/migrate/helpers/migration.helper');",
|
|
1203
|
+
"const config = require('../src/config.env');",
|
|
1204
|
+
'',
|
|
1205
|
+
'module.exports = createMigrationStore(',
|
|
1206
|
+
' config.default.mongoose.uri,',
|
|
1207
|
+
" 'migrations' // optional, default is 'migrations'",
|
|
1208
|
+
');',
|
|
1209
|
+
'',
|
|
1210
|
+
].join('\n'));
|
|
1211
|
+
// ── 4b. Copy vendor maintenance scripts ──────────────────────────────
|
|
1212
|
+
//
|
|
1213
|
+
// These scripts are consumed by the `nest-server-core-updater` and
|
|
1214
|
+
// `nest-server-core-contributor` Claude Code agents and by the
|
|
1215
|
+
// `check`/`check:fix`/`check:naf` pipelines below. They live at
|
|
1216
|
+
// `scripts/vendor/` in every vendored project:
|
|
1217
|
+
//
|
|
1218
|
+
// check-vendor-freshness.mjs — non-blocking warning that the
|
|
1219
|
+
// vendored core is behind the latest upstream release. Hooked
|
|
1220
|
+
// into `check` / `check:fix` / `check:naf`.
|
|
1221
|
+
//
|
|
1222
|
+
// sync-from-upstream.ts — produces a structured diff (upstream
|
|
1223
|
+
// delta vs. baseline, local changes, conflict map) that the
|
|
1224
|
+
// updater agent parses when pulling a new upstream version.
|
|
1225
|
+
//
|
|
1226
|
+
// propose-upstream-pr.ts — scans local commits that touched
|
|
1227
|
+
// src/core/ and emits per-commit patch files the contributor
|
|
1228
|
+
// agent uses to open upstream PRs.
|
|
1229
|
+
//
|
|
1230
|
+
// Templates live at `src/templates/vendor-scripts/` in the CLI and
|
|
1231
|
+
// are copied into the new project's `scripts/vendor/`.
|
|
1232
|
+
const vendorScriptsSrc = path.join(__dirname, '..', 'templates', 'vendor-scripts');
|
|
1233
|
+
const vendorScriptsDest = `${dest}/scripts/vendor`;
|
|
1234
|
+
if (filesystem.exists(vendorScriptsSrc)) {
|
|
1235
|
+
if (!filesystem.exists(vendorScriptsDest)) {
|
|
1236
|
+
filesystem.dir(vendorScriptsDest);
|
|
1237
|
+
}
|
|
1238
|
+
const vendorScriptFiles = filesystem.find(vendorScriptsSrc, { matching: '*' });
|
|
1239
|
+
for (const src of vendorScriptFiles || []) {
|
|
1240
|
+
const base = path.basename(src);
|
|
1241
|
+
filesystem.copy(src, `${vendorScriptsDest}/${base}`, { overwrite: true });
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
// ── 4c. .gitignore: ignore transient vendor script outputs ──────────
|
|
1245
|
+
//
|
|
1246
|
+
// sync-from-upstream.ts writes diffs to scripts/vendor/sync-results/
|
|
1247
|
+
// and propose-upstream-pr.ts writes patches to
|
|
1248
|
+
// scripts/vendor/upstream-candidates/. Both are throw-away analysis
|
|
1249
|
+
// artifacts and must not be committed.
|
|
1250
|
+
const gitignorePath = `${dest}/.gitignore`;
|
|
1251
|
+
if (filesystem.exists(gitignorePath)) {
|
|
1252
|
+
const raw = filesystem.read(gitignorePath) || '';
|
|
1253
|
+
const entries = ['scripts/vendor/sync-results/', 'scripts/vendor/upstream-candidates/'];
|
|
1254
|
+
const missing = entries.filter((e) => !raw.includes(e));
|
|
1255
|
+
if (missing.length > 0) {
|
|
1256
|
+
const block = `\n# Vendor-sync / upstream-contribute output (transient analysis artifacts)\n${missing.join('\n')}\n`;
|
|
1257
|
+
filesystem.write(gitignorePath, raw.trimEnd() + block);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
// ── 5. package.json: remove @lenne.tech/nest-server, add migrate/bin ─
|
|
1261
|
+
//
|
|
1262
|
+
// Delete the framework dep — it's no longer needed since src/core/
|
|
1263
|
+
// carries the code inline. Leave the starter's other deps alone (they
|
|
1264
|
+
// already cover everything `@lenne.tech/nest-server` pulled in
|
|
1265
|
+
// transitively because the starter pins them via pnpm overrides / direct
|
|
1266
|
+
// deps already; see nest-server-starter/package.json).
|
|
1267
|
+
const pkgPath = `${dest}/package.json`;
|
|
1268
|
+
if (filesystem.exists(pkgPath)) {
|
|
1269
|
+
const pkg = filesystem.read(pkgPath, 'json');
|
|
1270
|
+
if (pkg && typeof pkg === 'object') {
|
|
1271
|
+
if (pkg.dependencies && typeof pkg.dependencies === 'object') {
|
|
1272
|
+
delete pkg.dependencies['@lenne.tech/nest-server'];
|
|
1273
|
+
}
|
|
1274
|
+
if (pkg.devDependencies && typeof pkg.devDependencies === 'object') {
|
|
1275
|
+
delete pkg.devDependencies['@lenne.tech/nest-server'];
|
|
1276
|
+
}
|
|
1277
|
+
// Merge the framework's transitive deps into the project's own deps.
|
|
1278
|
+
// The starter lists a minimal subset (express, mongoose, class-validator,
|
|
1279
|
+
// etc.) and previously relied on @lenne.tech/nest-server to pull in
|
|
1280
|
+
// all the other framework dependencies (@apollo/server, @nestjs/jwt,
|
|
1281
|
+
// @nestjs/passport, bcrypt, better-auth, ejs, @tus/server, etc.) as
|
|
1282
|
+
// transitive deps. After vendoring we lose that automatic transitivity,
|
|
1283
|
+
// so we must add those deps explicitly to the project package.json.
|
|
1284
|
+
//
|
|
1285
|
+
// Fully dynamic: we pull in EVERY upstream dependency that the
|
|
1286
|
+
// project doesn't already have. No hard-coded package lists —
|
|
1287
|
+
// additions to upstream's package.json surface automatically on
|
|
1288
|
+
// the next vendor-init or vendor-sync.
|
|
1289
|
+
if (!pkg.dependencies)
|
|
1290
|
+
pkg.dependencies = {};
|
|
1291
|
+
const deps = pkg.dependencies;
|
|
1292
|
+
for (const [depName, depVersion] of Object.entries(upstreamDeps)) {
|
|
1293
|
+
if (depName === '@lenne.tech/nest-server')
|
|
1294
|
+
continue;
|
|
1295
|
+
if (!(depName in deps)) {
|
|
1296
|
+
deps[depName] = depVersion;
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
// Merge upstream devDependencies that a consumer project actually
|
|
1300
|
+
// needs at compile time. Rather than hard-coding a list of types
|
|
1301
|
+
// packages (which would drift as upstream evolves), we accept any
|
|
1302
|
+
// `@types/*` package whose base package is present in the merged
|
|
1303
|
+
// runtime deps (e.g. if `bcrypt` is in deps, `@types/bcrypt` is
|
|
1304
|
+
// accepted). This scales to new upstream additions automatically.
|
|
1305
|
+
//
|
|
1306
|
+
// Additionally, any upstream devDependency that the CLI knows is
|
|
1307
|
+
// used at runtime by the framework (via the dedicated
|
|
1308
|
+
// `vendorRuntimeDevDeps` predicate below) is promoted into
|
|
1309
|
+
// `dependencies`, because after vendoring the framework code lives
|
|
1310
|
+
// in the project and needs its runtime helpers available in prod.
|
|
1311
|
+
if (!pkg.devDependencies)
|
|
1312
|
+
pkg.devDependencies = {};
|
|
1313
|
+
const devDeps = pkg.devDependencies;
|
|
1314
|
+
for (const [depName, depVersion] of Object.entries(upstreamDevDeps)) {
|
|
1315
|
+
// Runtime-needed devDeps → promote to dependencies
|
|
1316
|
+
if (this.isVendorRuntimeDep(depName) && !(depName in deps)) {
|
|
1317
|
+
deps[depName] = depVersion;
|
|
1318
|
+
continue;
|
|
1319
|
+
}
|
|
1320
|
+
// @types/<pkg> where <pkg> is a runtime dep → accept as devDep
|
|
1321
|
+
if (depName.startsWith('@types/')) {
|
|
1322
|
+
const basePkg = depName.slice('@types/'.length);
|
|
1323
|
+
const matchesRuntime = basePkg in deps ||
|
|
1324
|
+
basePkg === 'node' ||
|
|
1325
|
+
// scoped types: @types/foo__bar ↔ @foo/bar
|
|
1326
|
+
(basePkg.includes('__') && `@${basePkg.replace('__', '/')}` in deps);
|
|
1327
|
+
if (matchesRuntime && !(depName in devDeps) && !(depName in deps)) {
|
|
1328
|
+
devDeps[depName] = depVersion;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
// Add a script to run the local bin/migrate.js. The starter's
|
|
1333
|
+
// existing migrate:* scripts are already correct for npm mode; we
|
|
1334
|
+
// need them pointing at the local bin + local ts-compiler.
|
|
1335
|
+
//
|
|
1336
|
+
// Also wire the vendor maintenance scripts (check-vendor-freshness,
|
|
1337
|
+
// vendor:sync, vendor:propose-upstream) and hook the freshness
|
|
1338
|
+
// check into `check` / `check:fix` / `check:naf` as a non-blocking
|
|
1339
|
+
// first step.
|
|
1340
|
+
if (pkg.scripts && typeof pkg.scripts === 'object') {
|
|
1341
|
+
const scripts = pkg.scripts;
|
|
1342
|
+
const migrateArgs = '--store ./migrations-utils/migrate.js --migrations-dir ./migrations --compiler ts:./migrations-utils/ts-compiler.js';
|
|
1343
|
+
scripts['migrate:create'] =
|
|
1344
|
+
`f() { node ./bin/migrate.js create "$1" --template-file ./src/core/modules/migrate/templates/migration-project.template.ts --migrations-dir ./migrations --compiler ts:./migrations-utils/ts-compiler.js; }; f`;
|
|
1345
|
+
scripts['migrate:up'] = `node ./bin/migrate.js up ${migrateArgs}`;
|
|
1346
|
+
scripts['migrate:down'] = `node ./bin/migrate.js down ${migrateArgs}`;
|
|
1347
|
+
scripts['migrate:list'] = `node ./bin/migrate.js list ${migrateArgs}`;
|
|
1348
|
+
scripts['migrate:develop:up'] = `NODE_ENV=develop node ./bin/migrate.js up ${migrateArgs}`;
|
|
1349
|
+
scripts['migrate:test:up'] = `NODE_ENV=test node ./bin/migrate.js up ${migrateArgs}`;
|
|
1350
|
+
scripts['migrate:preview:up'] = `NODE_ENV=preview node ./bin/migrate.js up ${migrateArgs}`;
|
|
1351
|
+
scripts['migrate:prod:up'] = `NODE_ENV=production node ./bin/migrate.js up ${migrateArgs}`;
|
|
1352
|
+
// Vendor maintenance scripts
|
|
1353
|
+
scripts['check:vendor-freshness'] = 'node scripts/vendor/check-vendor-freshness.mjs';
|
|
1354
|
+
scripts['vendor:sync'] = 'node -r ./migrations-utils/ts-compiler scripts/vendor/sync-from-upstream.ts';
|
|
1355
|
+
scripts['vendor:propose-upstream'] =
|
|
1356
|
+
'node -r ./migrations-utils/ts-compiler scripts/vendor/propose-upstream-pr.ts';
|
|
1357
|
+
// Hook vendor-freshness as the first step of check / check:fix /
|
|
1358
|
+
// check:naf. Non-blocking (exit 0 even on mismatch), so it just
|
|
1359
|
+
// surfaces the warning at the top of the log.
|
|
1360
|
+
const hookFreshness = (scriptName) => {
|
|
1361
|
+
const existing = scripts[scriptName];
|
|
1362
|
+
if (!existing)
|
|
1363
|
+
return;
|
|
1364
|
+
if (existing.includes('check:vendor-freshness'))
|
|
1365
|
+
return;
|
|
1366
|
+
// Inject the freshness check right after the initial `pnpm install`
|
|
1367
|
+
// or at the very beginning of the chain. Looks for a leading
|
|
1368
|
+
// `pnpm install && ` and inserts after it; otherwise prepends.
|
|
1369
|
+
const installPrefix = 'pnpm install && ';
|
|
1370
|
+
if (existing.startsWith(installPrefix)) {
|
|
1371
|
+
scripts[scriptName] = `${installPrefix}pnpm run check:vendor-freshness && ${existing.slice(installPrefix.length)}`;
|
|
1372
|
+
}
|
|
1373
|
+
else {
|
|
1374
|
+
scripts[scriptName] = `pnpm run check:vendor-freshness && ${existing}`;
|
|
1375
|
+
}
|
|
1376
|
+
};
|
|
1377
|
+
hookFreshness('check');
|
|
1378
|
+
hookFreshness('check:fix');
|
|
1379
|
+
hookFreshness('check:naf');
|
|
1380
|
+
}
|
|
1381
|
+
filesystem.write(pkgPath, pkg, { jsonIndent: 2 });
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
// ── 6. migrations-utils/ts-compiler.js bootstrap ─────────────────────
|
|
1385
|
+
//
|
|
1386
|
+
// The project's tsconfig.json restricts `types` to vitest/globals
|
|
1387
|
+
// which hides Node globals (__dirname, require, exports). This
|
|
1388
|
+
// bootstrap registers ts-node with an explicit Node-aware config.
|
|
1389
|
+
// Always write it fresh in vendor mode — overwrites whatever the
|
|
1390
|
+
// starter shipped (which relies on node_modules/@lenne.tech/nest-server).
|
|
1391
|
+
const tsCompilerPath = `${dest}/migrations-utils/ts-compiler.js`;
|
|
1392
|
+
filesystem.write(tsCompilerPath, [
|
|
1393
|
+
'/**',
|
|
1394
|
+
' * ts-node bootstrap for the migrate CLI (vendor mode).',
|
|
1395
|
+
' *',
|
|
1396
|
+
" * The project's tsconfig.json restricts `types` to vitest/globals",
|
|
1397
|
+
' * which hides Node globals (__dirname, require, exports). This',
|
|
1398
|
+
' * bootstrap registers ts-node with an explicit Node-aware config.',
|
|
1399
|
+
' */',
|
|
1400
|
+
"const tsNode = require('ts-node');",
|
|
1401
|
+
'',
|
|
1402
|
+
'tsNode.register({',
|
|
1403
|
+
' transpileOnly: true,',
|
|
1404
|
+
' compilerOptions: {',
|
|
1405
|
+
" module: 'commonjs',",
|
|
1406
|
+
" target: 'es2022',",
|
|
1407
|
+
' esModuleInterop: true,',
|
|
1408
|
+
' experimentalDecorators: true,',
|
|
1409
|
+
' emitDecoratorMetadata: true,',
|
|
1410
|
+
' skipLibCheck: true,',
|
|
1411
|
+
" types: ['node'],",
|
|
1412
|
+
' },',
|
|
1413
|
+
'});',
|
|
1414
|
+
'',
|
|
1415
|
+
].join('\n'));
|
|
1416
|
+
// ── 6b. extras/sync-packages.mjs: replace with vendor-aware stub ─────
|
|
1417
|
+
//
|
|
1418
|
+
// The starter's `extras/sync-packages.mjs` pulls the latest deps of
|
|
1419
|
+
// `@lenne.tech/nest-server` from the npm registry and merges them into
|
|
1420
|
+
// the project's package.json. In vendor mode the framework is no
|
|
1421
|
+
// longer an npm dependency, so the script has nothing meaningful to
|
|
1422
|
+
// sync and would either no-op or error out.
|
|
1423
|
+
//
|
|
1424
|
+
// Replace it with a small informational stub that points the user at
|
|
1425
|
+
// the canonical vendor-update path (the `nest-server-core-updater`
|
|
1426
|
+
// Claude Code agent / `pnpm run vendor:sync` if the project has that
|
|
1427
|
+
// script). Keeps `pnpm run update` from dead-exiting with a confusing
|
|
1428
|
+
// message.
|
|
1429
|
+
const syncPackagesPath = `${dest}/extras/sync-packages.mjs`;
|
|
1430
|
+
if (filesystem.exists(syncPackagesPath)) {
|
|
1431
|
+
filesystem.write(syncPackagesPath, [
|
|
1432
|
+
'#!/usr/bin/env node',
|
|
1433
|
+
'',
|
|
1434
|
+
"'use strict';",
|
|
1435
|
+
'',
|
|
1436
|
+
'/**',
|
|
1437
|
+
' * Vendor-mode stub for extras/sync-packages.mjs.',
|
|
1438
|
+
' *',
|
|
1439
|
+
' * The original script is designed for npm-mode projects where',
|
|
1440
|
+
" * `@lenne.tech/nest-server` is an installed dependency and",
|
|
1441
|
+
' * `pnpm run update` pulls the latest upstream deps into the',
|
|
1442
|
+
' * project package.json.',
|
|
1443
|
+
' *',
|
|
1444
|
+
' * This project runs in VENDOR mode: the framework core/ tree is',
|
|
1445
|
+
' * copied directly into src/core/ and there is no framework npm',
|
|
1446
|
+
' * dep to sync. To update the vendored core, use the',
|
|
1447
|
+
' * `nest-server-core-updater` Claude Code agent or run the',
|
|
1448
|
+
' * project-local vendor:sync script once it has been added.',
|
|
1449
|
+
' */',
|
|
1450
|
+
'',
|
|
1451
|
+
"console.warn('');",
|
|
1452
|
+
"console.warn('⚠ pnpm run update is a no-op in vendor mode.');",
|
|
1453
|
+
"console.warn(' Framework source lives directly in src/core/ and is updated');",
|
|
1454
|
+
"console.warn(' via the nest-server-core-updater agent:');",
|
|
1455
|
+
"console.warn('');",
|
|
1456
|
+
"console.warn(' /lt-dev:backend:update-nest-server-core');",
|
|
1457
|
+
"console.warn('');",
|
|
1458
|
+
"console.warn(' See src/core/VENDOR.md for the current baseline and sync history.');",
|
|
1459
|
+
"console.warn('');",
|
|
1460
|
+
'process.exit(0);',
|
|
1461
|
+
'',
|
|
1462
|
+
].join('\n'));
|
|
1463
|
+
}
|
|
1464
|
+
// ── 7. tsconfig.json excludes + Node types ───────────────────────────
|
|
1465
|
+
//
|
|
1466
|
+
// The vendored migrate template references `from '@lenne.tech/nest-server'`
|
|
1467
|
+
// as a placeholder that only makes sense in the *generated* migration
|
|
1468
|
+
// file's context. Exclude it from compilation.
|
|
1469
|
+
//
|
|
1470
|
+
// The starter's tsconfig.json restricts `types` to `['vitest/globals']`
|
|
1471
|
+
// because the shipped framework dist was pre-compiled with Node types
|
|
1472
|
+
// baked in. In vendor mode we compile the framework source directly,
|
|
1473
|
+
// so we MUST also load `@types/node` — otherwise types like
|
|
1474
|
+
// `ScryptOptions` in core-better-auth-user.mapper.ts break the build.
|
|
1475
|
+
this.widenTsconfigExcludes(`${dest}/tsconfig.json`);
|
|
1476
|
+
this.widenTsconfigExcludes(`${dest}/tsconfig.build.json`);
|
|
1477
|
+
this.widenTsconfigTypes(`${dest}/tsconfig.json`);
|
|
1478
|
+
this.widenTsconfigTypes(`${dest}/tsconfig.build.json`);
|
|
1479
|
+
// ── 9b. Prepend a vendor-mode block to projects/api/CLAUDE.md ────────
|
|
1480
|
+
//
|
|
1481
|
+
// Claude Code's project-level CLAUDE.md is the single source of truth
|
|
1482
|
+
// for "what kind of project is this". Prepending a short vendor block
|
|
1483
|
+
// tells any downstream agent (backend-dev, generating-nest-servers,
|
|
1484
|
+
// nest-server-updater, …) that the framework lives at src/core/ and
|
|
1485
|
+
// that generated imports must use relative paths, before they even
|
|
1486
|
+
// read the rest of the file.
|
|
1487
|
+
const apiClaudeMdPath = `${dest}/CLAUDE.md`;
|
|
1488
|
+
if (filesystem.exists(apiClaudeMdPath)) {
|
|
1489
|
+
const existing = filesystem.read(apiClaudeMdPath) || '';
|
|
1490
|
+
const marker = '<!-- lt-vendor-marker -->';
|
|
1491
|
+
if (!existing.includes(marker)) {
|
|
1492
|
+
const vendorBlock = [
|
|
1493
|
+
marker,
|
|
1494
|
+
'',
|
|
1495
|
+
'# Vendor-Mode Notice',
|
|
1496
|
+
'',
|
|
1497
|
+
'This api project runs in **vendor mode**: the `@lenne.tech/nest-server`',
|
|
1498
|
+
'core/ tree has been copied directly into `src/core/` as first-class',
|
|
1499
|
+
'project code. There is **no** `@lenne.tech/nest-server` npm dependency.',
|
|
1500
|
+
'',
|
|
1501
|
+
'- **Read framework code from `src/core/**`** — not from `node_modules/`.',
|
|
1502
|
+
'- **Generated imports use relative paths** to `src/core`, e.g.',
|
|
1503
|
+
' `import { CrudService } from \'../../../core\';`',
|
|
1504
|
+
' The exact depth depends on the file location. `lt server module`',
|
|
1505
|
+
' computes it automatically.',
|
|
1506
|
+
'- **Baseline + patch log** live in `src/core/VENDOR.md`. Log any',
|
|
1507
|
+
' substantial local change there so the `nest-server-core-updater`',
|
|
1508
|
+
' agent can classify it at sync time.',
|
|
1509
|
+
'- **Update flow:** run `/lt-dev:backend:update-nest-server-core` (the',
|
|
1510
|
+
' agent clones upstream, computes a delta, and presents a review).',
|
|
1511
|
+
'- **Contribute back:** run `/lt-dev:backend:contribute-nest-server-core`',
|
|
1512
|
+
' to propose local fixes as upstream PRs.',
|
|
1513
|
+
'- **Freshness check:** `pnpm run check:vendor-freshness` warns (non-',
|
|
1514
|
+
' blockingly) when upstream has a newer release than the baseline.',
|
|
1515
|
+
'',
|
|
1516
|
+
'---',
|
|
1517
|
+
'',
|
|
1518
|
+
].join('\n');
|
|
1519
|
+
filesystem.write(apiClaudeMdPath, vendorBlock + existing);
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
// ── 10. VENDOR.md baseline ───────────────────────────────────────────
|
|
1523
|
+
//
|
|
1524
|
+
// Record the exact upstream version + commit SHA we vendored from, so
|
|
1525
|
+
// the `nest-server-core-updater` agent has a reliable base for
|
|
1526
|
+
// computing upstream deltas on the next sync.
|
|
1527
|
+
const vendorMdPath = `${dest}/src/core/VENDOR.md`;
|
|
1528
|
+
if (!filesystem.exists(vendorMdPath)) {
|
|
1529
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
1530
|
+
const versionLine = upstreamVersion
|
|
1531
|
+
? `- **Baseline-Version:** ${upstreamVersion}`
|
|
1532
|
+
: '- **Baseline-Version:** (not detected — run `vendor:sync` to record)';
|
|
1533
|
+
const commitLine = upstreamCommit
|
|
1534
|
+
? `- **Baseline-Commit:** \`${upstreamCommit}\``
|
|
1535
|
+
: '- **Baseline-Commit:** (not detected)';
|
|
1536
|
+
const syncHistoryTo = upstreamVersion
|
|
1537
|
+
? `${upstreamVersion}${upstreamCommit ? ` (\`${upstreamCommit.slice(0, 10)}\`)` : ''}`
|
|
1538
|
+
: 'initial import';
|
|
1539
|
+
filesystem.write(vendorMdPath, [
|
|
1540
|
+
'# @lenne.tech/nest-server – core (vendored)',
|
|
1541
|
+
'',
|
|
1542
|
+
'This directory is a curated vendor copy of the `core/` tree from',
|
|
1543
|
+
'@lenne.tech/nest-server. It is first-class project code, not a',
|
|
1544
|
+
'node_modules shadow copy. Edit freely; log substantial changes in',
|
|
1545
|
+
'the "Local changes" table below so the `nest-server-core-updater`',
|
|
1546
|
+
'agent can classify them at sync time.',
|
|
1547
|
+
'',
|
|
1548
|
+
'The flatten-fix was applied during `lt fullstack init`: the',
|
|
1549
|
+
'upstream `src/index.ts`, `src/core.module.ts`, `src/test/`,',
|
|
1550
|
+
'`src/templates/`, `src/types/`, and `LICENSE` were moved under',
|
|
1551
|
+
'`src/core/` and their relative `./core/…` specifiers were',
|
|
1552
|
+
'stripped. See the init code in',
|
|
1553
|
+
'`lenneTech/cli/src/extensions/server.ts#convertCloneToVendored`.',
|
|
1554
|
+
'',
|
|
1555
|
+
'## Baseline',
|
|
1556
|
+
'',
|
|
1557
|
+
'- **Upstream-Repo:** https://github.com/lenneTech/nest-server',
|
|
1558
|
+
versionLine,
|
|
1559
|
+
commitLine,
|
|
1560
|
+
`- **Vendored am:** ${today}`,
|
|
1561
|
+
`- **Vendored von:** lt CLI (\`lt fullstack init --framework-mode vendor\`)`,
|
|
1562
|
+
'',
|
|
1563
|
+
'## Sync history',
|
|
1564
|
+
'',
|
|
1565
|
+
'| Date | From | To | Notes |',
|
|
1566
|
+
'| ---- | ---- | -- | ----- |',
|
|
1567
|
+
`| ${today} | — | ${syncHistoryTo} | scaffolded by lt CLI |`,
|
|
1568
|
+
'',
|
|
1569
|
+
'## Local changes',
|
|
1570
|
+
'',
|
|
1571
|
+
'| Date | Commit | Scope | Reason | Status |',
|
|
1572
|
+
'| ---- | ------ | ----- | ------ | ------ |',
|
|
1573
|
+
'| — | — | (none, pristine) | initial vendor | — |',
|
|
1574
|
+
'',
|
|
1575
|
+
'## Upstream PRs',
|
|
1576
|
+
'',
|
|
1577
|
+
'| PR | Title | Commits | Status |',
|
|
1578
|
+
'| -- | ----- | ------- | ------ |',
|
|
1579
|
+
'| — | (none yet) | — | — |',
|
|
1580
|
+
'',
|
|
1581
|
+
].join('\n'));
|
|
1582
|
+
}
|
|
1583
|
+
return { upstreamDeps, upstreamDevDeps };
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
/**
|
|
1587
|
+
* Predicate: is a given upstream `devDependencies` key actually a runtime
|
|
1588
|
+
* dep in disguise that needs to live in `dependencies` after vendoring?
|
|
1589
|
+
*
|
|
1590
|
+
* `@lenne.tech/nest-server` keeps a few packages in devDependencies that
|
|
1591
|
+
* the framework code imports at runtime (e.g. `find-file-up` in its
|
|
1592
|
+
* config loader). When we vendor the framework source into a consumer
|
|
1593
|
+
* project, those must end up in `dependencies` so the compiled/dist
|
|
1594
|
+
* runtime has them available.
|
|
1595
|
+
*
|
|
1596
|
+
* The list of such helpers lives in `src/config/vendor-runtime-deps.json`
|
|
1597
|
+
* under the `runtimeHelpers` key. Adding a new helper is a data-only
|
|
1598
|
+
* change (no CLI release required). If the config file is missing or
|
|
1599
|
+
* unreadable, the predicate safely returns `false` for everything.
|
|
1600
|
+
*/
|
|
1601
|
+
isVendorRuntimeDep(pkgName) {
|
|
1602
|
+
if (!this._vendorRuntimeHelpers) {
|
|
1603
|
+
try {
|
|
1604
|
+
const path = require('path');
|
|
1605
|
+
const configPath = path.join(__dirname, '..', 'config', 'vendor-runtime-deps.json');
|
|
1606
|
+
const raw = this.filesystem.read(configPath, 'json');
|
|
1607
|
+
const list = Array.isArray(raw === null || raw === void 0 ? void 0 : raw.runtimeHelpers) ? raw.runtimeHelpers : [];
|
|
1608
|
+
this._vendorRuntimeHelpers = new Set(list.filter((e) => typeof e === 'string'));
|
|
1609
|
+
}
|
|
1610
|
+
catch (_a) {
|
|
1611
|
+
this._vendorRuntimeHelpers = new Set();
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
return this._vendorRuntimeHelpers.has(pkgName);
|
|
1615
|
+
}
|
|
1616
|
+
/**
|
|
1617
|
+
* Reads the GraphQL-only package list from the starter's
|
|
1618
|
+
* `api-mode.manifest.json`. Must be called BEFORE `processApiMode`
|
|
1619
|
+
* runs, because `processApiMode` deletes the manifest at the end of
|
|
1620
|
+
* its REST-mode pass.
|
|
1621
|
+
*
|
|
1622
|
+
* Returns a flat list of package names that the manifest declares as
|
|
1623
|
+
* GraphQL-specific (both `packages` and `devPackages` arrays from the
|
|
1624
|
+
* `graphql` mode config). Empty list if the manifest is missing or
|
|
1625
|
+
* malformed.
|
|
1626
|
+
*/
|
|
1627
|
+
readApiModeGraphqlEssentials(dest) {
|
|
1628
|
+
var _a;
|
|
1629
|
+
const manifestPath = `${dest}/api-mode.manifest.json`;
|
|
1630
|
+
if (!this.filesystem.exists(manifestPath))
|
|
1631
|
+
return [];
|
|
1632
|
+
try {
|
|
1633
|
+
const manifest = this.filesystem.read(manifestPath, 'json');
|
|
1634
|
+
const gqlMode = (_a = manifest === null || manifest === void 0 ? void 0 : manifest.modes) === null || _a === void 0 ? void 0 : _a.graphql;
|
|
1635
|
+
if (!gqlMode || typeof gqlMode !== 'object')
|
|
1636
|
+
return [];
|
|
1637
|
+
const packages = [];
|
|
1638
|
+
if (Array.isArray(gqlMode.packages))
|
|
1639
|
+
packages.push(...gqlMode.packages);
|
|
1640
|
+
if (Array.isArray(gqlMode.devPackages))
|
|
1641
|
+
packages.push(...gqlMode.devPackages);
|
|
1642
|
+
return packages.filter((p) => typeof p === 'string' && p.length > 0);
|
|
1643
|
+
}
|
|
1644
|
+
catch (_b) {
|
|
1645
|
+
return [];
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
/**
|
|
1649
|
+
* Restores framework-core-essential dependencies that the
|
|
1650
|
+
* `api-mode.manifest.json` of the starter strips when running in
|
|
1651
|
+
* REST-only mode. The vendored framework core at `src/core/` always
|
|
1652
|
+
* imports these packages (e.g. `core-auth.module.ts` imports
|
|
1653
|
+
* `graphql-subscriptions`), so even a pure REST project needs them
|
|
1654
|
+
* available at compile time.
|
|
1655
|
+
*
|
|
1656
|
+
* The essentials list is captured BEFORE `processApiMode` runs (via
|
|
1657
|
+
* `readApiModeGraphqlEssentials`) and passed in here. Versions come
|
|
1658
|
+
* from the upstream `@lenne.tech/nest-server` package.json snapshot
|
|
1659
|
+
* (passed in via `upstreamDeps`). No hard-coded package lists or
|
|
1660
|
+
* versions — drift between starter and upstream is handled automatically
|
|
1661
|
+
* at the next init.
|
|
1662
|
+
*/
|
|
1663
|
+
restoreVendorCoreEssentials(options) {
|
|
1664
|
+
var _a;
|
|
1665
|
+
const { dest, essentials, upstreamDeps = {} } = options;
|
|
1666
|
+
if (!essentials || essentials.length === 0)
|
|
1667
|
+
return;
|
|
1668
|
+
const pkgPath = `${dest}/package.json`;
|
|
1669
|
+
if (!this.filesystem.exists(pkgPath))
|
|
1670
|
+
return;
|
|
1671
|
+
const pkg = this.filesystem.read(pkgPath, 'json');
|
|
1672
|
+
if (!pkg || typeof pkg !== 'object')
|
|
1673
|
+
return;
|
|
1674
|
+
if (!pkg.dependencies)
|
|
1675
|
+
pkg.dependencies = {};
|
|
1676
|
+
const deps = pkg.dependencies;
|
|
1677
|
+
for (const name of essentials) {
|
|
1678
|
+
if (deps[name])
|
|
1679
|
+
continue;
|
|
1680
|
+
// Prefer the upstream-pinned version when available, else leave
|
|
1681
|
+
// unversioned (`latest`) — install will resolve either way.
|
|
1682
|
+
const version = (_a = upstreamDeps[name]) !== null && _a !== void 0 ? _a : 'latest';
|
|
1683
|
+
deps[name] = version;
|
|
1684
|
+
}
|
|
1685
|
+
this.filesystem.write(pkgPath, pkg, { jsonIndent: 2 });
|
|
1686
|
+
}
|
|
1687
|
+
/**
|
|
1688
|
+
* Ensures the given tsconfig contains both `node` and `vitest/globals`
|
|
1689
|
+
* in its `types` array.
|
|
1690
|
+
*
|
|
1691
|
+
* - `node` is required because the vendored framework source uses Node
|
|
1692
|
+
* globals / types like `ScryptOptions` (from `node:crypto`), which
|
|
1693
|
+
* the starter's compiled dist never needed.
|
|
1694
|
+
* - `vitest/globals` is required because `src/core/test/test.helper.ts`
|
|
1695
|
+
* uses the global `expect` from vitest, and that file is transitively
|
|
1696
|
+
* pulled into the build via TestHelper consumers. tsconfig `exclude`
|
|
1697
|
+
* doesn't help because exclude is a non-transitive filter.
|
|
1698
|
+
*
|
|
1699
|
+
* Idempotent. Handles both bracketed arrays and absent keys, and
|
|
1700
|
+
* leaves the file untouched if both types are already listed.
|
|
1701
|
+
*/
|
|
1702
|
+
widenTsconfigTypes(tsconfigPath) {
|
|
1703
|
+
if (!this.filesystem.exists(tsconfigPath))
|
|
1704
|
+
return;
|
|
1705
|
+
try {
|
|
1706
|
+
let raw = this.filesystem.read(tsconfigPath) || '';
|
|
1707
|
+
const needed = ['node', 'vitest/globals'];
|
|
1708
|
+
for (const type of needed) {
|
|
1709
|
+
// Already contains this type in some types array — skip it.
|
|
1710
|
+
const alreadyRegex = new RegExp(`"types"\\s*:\\s*\\[[^\\]]*"${type.replace(/\//g, '\\/')}"`);
|
|
1711
|
+
if (alreadyRegex.test(raw))
|
|
1712
|
+
continue;
|
|
1713
|
+
const typesRegex = /("types"\s*:\s*\[)([^\]]*)(\])/;
|
|
1714
|
+
if (typesRegex.test(raw)) {
|
|
1715
|
+
raw = raw.replace(typesRegex, (_m, head, body, tail) => {
|
|
1716
|
+
const trimmed = body.trim();
|
|
1717
|
+
const joiner = trimmed.length > 0 ? ', ' : '';
|
|
1718
|
+
return `${head}${body}${joiner}"${type}"${tail}`;
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
else {
|
|
1722
|
+
const compilerOptionsRegex = /("compilerOptions"\s*:\s*\{)/;
|
|
1723
|
+
if (compilerOptionsRegex.test(raw)) {
|
|
1724
|
+
raw = raw.replace(compilerOptionsRegex, `$1\n "types": ["${type}"],`);
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
this.filesystem.write(tsconfigPath, raw);
|
|
1729
|
+
}
|
|
1730
|
+
catch (_a) {
|
|
1731
|
+
// best-effort
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
/**
|
|
1735
|
+
* Adds the vendored migrate template file AND the vendored `src/core/test/`
|
|
1736
|
+
* directory to the `exclude` array of a tsconfig (build or base).
|
|
1737
|
+
*
|
|
1738
|
+
* - The migrate template file is a text template that references
|
|
1739
|
+
* `@lenne.tech/nest-server` as a placeholder — only meaningful in the
|
|
1740
|
+
* *generated* migration file's context. Exclude from compilation.
|
|
1741
|
+
* - `src/core/test/` contains `TestHelper`, which uses vitest globals
|
|
1742
|
+
* (`expect`, etc.) and is not intended for production dist. The
|
|
1743
|
+
* starter's `tsconfig.build.json` overrides `types` to `["node"]`,
|
|
1744
|
+
* which strips vitest globals; compiling `test.helper.ts` there
|
|
1745
|
+
* breaks. Exclude the whole `src/core/test/` subtree from the build.
|
|
1746
|
+
*
|
|
1747
|
+
* Handles both arrays with pre-existing entries and absent `exclude`
|
|
1748
|
+
* keys. Idempotent.
|
|
1749
|
+
*/
|
|
1750
|
+
widenTsconfigExcludes(tsconfigPath) {
|
|
1751
|
+
if (!this.filesystem.exists(tsconfigPath)) {
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
const EXCLUDE_ENTRIES = [
|
|
1755
|
+
'src/core/modules/migrate/templates/**/*.template.ts',
|
|
1756
|
+
'src/core/test/**/*.ts',
|
|
1757
|
+
];
|
|
1758
|
+
try {
|
|
1759
|
+
// The upstream tsconfig files may contain comments — standard JSON parse
|
|
1760
|
+
// breaks on them. Use a regex-based patch as a fallback.
|
|
1761
|
+
let raw = this.filesystem.read(tsconfigPath) || '';
|
|
1762
|
+
for (const entry of EXCLUDE_ENTRIES) {
|
|
1763
|
+
if (raw.includes(entry))
|
|
1764
|
+
continue;
|
|
1765
|
+
const excludeRegex = /("exclude"\s*:\s*\[)([^\]]*)(\])/;
|
|
1766
|
+
if (excludeRegex.test(raw)) {
|
|
1767
|
+
raw = raw.replace(excludeRegex, (_match, head, body, tail) => {
|
|
1768
|
+
const trimmed = body.trim();
|
|
1769
|
+
const joiner = trimmed.length > 0 ? ', ' : '';
|
|
1770
|
+
return `${head}${body}${joiner}"${entry}"${tail}`;
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
else {
|
|
1774
|
+
// No exclude key at all — add one before the closing brace.
|
|
1775
|
+
const lastBrace = raw.lastIndexOf('}');
|
|
1776
|
+
if (lastBrace === -1)
|
|
1777
|
+
continue;
|
|
1778
|
+
const before = raw.slice(0, lastBrace);
|
|
1779
|
+
const after = raw.slice(lastBrace);
|
|
1780
|
+
const separator = before.trimEnd().endsWith(',') || before.trimEnd().endsWith('{') ? '' : ',';
|
|
1781
|
+
raw = `${before.trimEnd()}${separator}\n "exclude": ["${entry}"]\n${after}`;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
this.filesystem.write(tsconfigPath, raw);
|
|
1785
|
+
}
|
|
1786
|
+
catch (_a) {
|
|
1787
|
+
// Best-effort; the project will still work, it just may need a
|
|
1788
|
+
// manual `tsconfig.json` exclude when building.
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
729
1791
|
/**
|
|
730
1792
|
* Patch config.env.ts using TypeScript AST manipulation
|
|
731
1793
|
* - Replace SECRET_OR_PRIVATE_KEY placeholders with random secrets
|
|
@@ -768,6 +1830,34 @@ class Server {
|
|
|
768
1830
|
this.filesystem.write(configPath, content);
|
|
769
1831
|
}
|
|
770
1832
|
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Patch CLAUDE.md with API mode information
|
|
1835
|
+
* Replaces the generic "API Mode" line with the selected mode and removes the
|
|
1836
|
+
* API Mode System section when not in "Both" mode (markers already stripped).
|
|
1837
|
+
* @param dest - Target directory containing the CLAUDE.md file
|
|
1838
|
+
* @param apiMode - Selected API mode (Rest, GraphQL, or Both)
|
|
1839
|
+
*/
|
|
1840
|
+
patchClaudeMdApiMode(dest, apiMode) {
|
|
1841
|
+
const claudeMdPath = `${dest}/CLAUDE.md`;
|
|
1842
|
+
if (!this.filesystem.exists(claudeMdPath) || !apiMode) {
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
let content = this.filesystem.read(claudeMdPath);
|
|
1846
|
+
if (!content) {
|
|
1847
|
+
return;
|
|
1848
|
+
}
|
|
1849
|
+
// Replace generic API mode placeholder or description
|
|
1850
|
+
content = content.replace(/- \*\*API Mode:\*\* REST \(default\) or GraphQL or Both/, `- **API Mode:** ${apiMode}`);
|
|
1851
|
+
// When not in "Both" mode, the region markers have been stripped by processApiMode.
|
|
1852
|
+
// Replace the API Mode System section with a short note.
|
|
1853
|
+
// Lookahead anchors (## Tooling, ## Framework:) match the known next-section headers in the
|
|
1854
|
+
// nest-server-starter CLAUDE.md template. The $ fallback ensures the regex terminates even if
|
|
1855
|
+
// neither header exists (e.g., template was customized).
|
|
1856
|
+
if (apiMode !== 'Both') {
|
|
1857
|
+
content = content.replace(/## API Mode System[\s\S]*?(?=## Tooling|## Framework:|$)/, `## API Mode\n\nThis project uses **${apiMode}** mode (configured during \`lt fullstack init\` / \`lt server create\`).\n\n`);
|
|
1858
|
+
}
|
|
1859
|
+
this.filesystem.write(claudeMdPath, content);
|
|
1860
|
+
}
|
|
771
1861
|
/**
|
|
772
1862
|
* Replace secret or private keys in string (e.g. for config files)
|
|
773
1863
|
*/
|
|
@@ -800,4 +1890,3 @@ exports.Server = Server;
|
|
|
800
1890
|
exports.default = (toolbox) => {
|
|
801
1891
|
toolbox.server = new Server(toolbox);
|
|
802
1892
|
};
|
|
803
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2V4dGVuc2lvbnMvc2VydmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQUFBLGlDQUFpQztBQUlqQywrQkFBNEI7QUFDNUIsaUNBQWlDO0FBYWpDOztHQUVHO0FBQ0gsTUFBYSxNQUFNO0lBOEZqQjs7T0FFRztJQUNILFlBQXNCLE9BQStCO1FBQS9CLFlBQU8sR0FBUCxPQUFPLENBQXdCO1FBckZyRCx1Q0FBdUM7UUFDdkMsWUFBTyxHQUEyQjtZQUNoQyxZQUFZLEVBQUUseURBQXlEO1lBQ3ZFLFVBQVUsRUFBRSxxRUFBcUU7WUFDakYsYUFBYSxFQUFFLG1FQUFtRTtZQUNsRix5QkFBeUIsRUFBRSxpREFBaUQ7U0FDN0UsQ0FBQztRQUVGLGdEQUFnRDtRQUNoRCxvQkFBZSxHQUEyQjtZQUN4QyxPQUFPLEVBQUUsU0FBUztZQUNsQixJQUFJLEVBQUUsTUFBTTtZQUNaLElBQUksRUFBRSxlQUFlO1lBQ3JCLFFBQVEsRUFBRSxlQUFlO1lBQ3pCLEVBQUUsRUFBRSxRQUFRO1lBQ1osRUFBRSxFQUFFLFFBQVE7WUFDWixJQUFJLEVBQUUsTUFBTTtZQUNaLElBQUksRUFBRSxNQUFNO1lBQ1osTUFBTSxFQUFFLFFBQVE7WUFDaEIsUUFBUSxFQUFFLFFBQVE7WUFDbEIsTUFBTSxFQUFFLFFBQVE7WUFDaEIsTUFBTSxFQUFFLGVBQWU7U0FDeEIsQ0FBQztRQUVGLGlEQUFpRDtRQUNqRCxvQkFBZSxHQUEyQjtZQUN4QyxPQUFPLEVBQUUsU0FBUztZQUNsQixJQUFJLEVBQUUsTUFBTTtZQUNaLElBQUksRUFBRSxZQUFZO1lBQ2xCLFFBQVEsRUFBRSxZQUFZO1lBQ3RCLEVBQUUsRUFBRSxRQUFRO1lBQ1osRUFBRSxFQUFFLFFBQVE7WUFDWixJQUFJLEVBQUUseUJBQXlCO1lBQy9CLElBQUksRUFBRSx5QkFBeUI7WUFDL0IsTUFBTSxFQUFFLFFBQVE7WUFDaEIs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
|