@appxdigital/appx-core 0.1.122 → 0.1.124

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +50 -1
  2. package/README.md +35 -3
  3. package/dist/appx-core.module.d.ts +1 -0
  4. package/dist/appx-core.module.d.ts.map +1 -1
  5. package/dist/appx-core.module.js +1 -0
  6. package/dist/common/bigint-serializer.d.ts +1 -0
  7. package/dist/common/bigint-serializer.d.ts.map +1 -0
  8. package/dist/common/bigint-serializer.js +18 -0
  9. package/dist/common/decorators/scalar-field.decorator.d.ts +22 -0
  10. package/dist/common/decorators/scalar-field.decorator.d.ts.map +1 -0
  11. package/dist/common/decorators/scalar-field.decorator.js +103 -0
  12. package/dist/config/generate-all.js +22 -55
  13. package/dist/config/generate-controllers.d.ts +2 -1
  14. package/dist/config/generate-controllers.d.ts.map +1 -1
  15. package/dist/config/generate-controllers.js +7 -22
  16. package/dist/config/generate-dtos.d.ts +14 -1
  17. package/dist/config/generate-dtos.d.ts.map +1 -1
  18. package/dist/config/generate-dtos.js +85 -28
  19. package/dist/config/generate-models.d.ts +3 -0
  20. package/dist/config/generate-models.d.ts.map +1 -0
  21. package/dist/config/generate-models.js +107 -0
  22. package/dist/config/generate-modules.d.ts +30 -1
  23. package/dist/config/generate-modules.d.ts.map +1 -1
  24. package/dist/config/generate-modules.js +145 -86
  25. package/dist/config/generate-resolvers.d.ts +7 -1
  26. package/dist/config/generate-resolvers.d.ts.map +1 -1
  27. package/dist/config/generate-resolvers.js +10 -17
  28. package/dist/config/generate-services.d.ts +2 -1
  29. package/dist/config/generate-services.d.ts.map +1 -1
  30. package/dist/config/generate-services.js +7 -16
  31. package/dist/config/utils.d.ts +53 -1
  32. package/dist/config/utils.d.ts.map +1 -1
  33. package/dist/config/utils.js +124 -11
  34. package/dist/index.d.ts +1 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +1 -0
  37. package/docs/README.md +1 -0
  38. package/docs/dtos.md +13 -1
  39. package/docs/generate.md +57 -0
  40. package/package.json +4 -2
package/CHANGELOG.md CHANGED
@@ -14,6 +14,55 @@ This project follows the `MAJOR.MINOR.PATCH` scheme in `package.json`.
14
14
 
15
15
  ---
16
16
 
17
+ ## [0.1.124] — 2026-07-23
18
+
19
+ ### Fixed
20
+
21
+ - **`appx-core generate` and `generate models` now run the project's own Prisma.** Both shelled out to a bare `prisma generate`, which resolves from `PATH`. With the CLI installed **globally** the project's `node_modules/.bin` is not on `PATH`, so Prisma resolved to a *global* install — a different version than the project's — or was not found at all. The executable is now resolved inside the project (walking up from the working directory, so hoisted / monorepo layouts work), and its `.bin` is prepended to `PATH` so the generator binaries Prisma spawns (`prisma-nestjs-graphql`, …) also resolve from the project. A project with no local Prisma now fails with an actionable message instead of silently generating against a global one.
22
+
23
+ Drop-in: no changes required in your project.
24
+
25
+ ---
26
+
27
+ ## [0.1.123] — 2026-07-22
28
+
29
+ Two changes: the `generate` command is split into a deploy-safe pass + a module wizard, and generated CRUD DTOs now type each scalar column to match its Prisma model type.
30
+
31
+ ### Generate command split
32
+
33
+ Regenerating types no longer mutates your code.
34
+
35
+ - **`appx-core generate`** — regenerates only the overwrite-safe artifacts under the gitignored `src/generated/**` (Prisma client, GraphQL types, DTO **base** classes). It **no longer** writes `src/modules/**` or edits `src/app.module.ts`. Idempotent and safe for CI / postinstall / predeploy.
36
+ - **`appx-core generate models`** — new interactive wizard that scaffolds CRUD (module/service/controller/resolver + DTO subclass) for the models you choose and registers them in `app.module.ts`, then runs the safe pass. Non-interactive: `appx-core generate models <Name…>` and `--all`. Only models **without** an existing module are offered; if there are none it prints `No modules available to generate`.
37
+ - Model discovery is driven by the Prisma **DMMF** (the schema), not by scanning the GraphQL plugin's output folders.
38
+ - The **`User`** model is framework-owned (auth already serves user endpoints; generic User CRUD is a mass-assignment surface) and is no longer scaffolded.
39
+ - Module-registration in `app.module.ts` finds the `@Module` `imports` array's real closing bracket (skipping strings/comments/nested arrays) and **appends** there, preserving order — it no longer breaks on a nested array literal like `ThrottlerModule.forRoot([...])`, never double-registers, and never adds a duplicate import.
40
+ - "Already has a module" is detected by the model a module serves (`CoreController<Model>` / `CoreService<Model>`), not by folder name — so a hand-written module under a non-canonical (e.g. pluralised) folder isn't duplicated.
41
+ - Full reference: [`docs/generate.md`](./docs/generate.md). GraphQL stays **read-only**; every scaffolded module still gets its resolver.
42
+
43
+ ### Generated-CRUD DTO scalar typing
44
+
45
+ Generated CRUD DTOs now type each scalar column to match its Prisma model type, so a controller override type-checks:
46
+
47
+ - **`DateTime` → `Date`** (was `string`), via `@Type(() => Date)`.
48
+ - **`Decimal` → `Prisma.Decimal`** (was `number`), via the new `@DecimalField()`.
49
+ - **`BigInt` → `bigint`** (was `number`), via the new `@BigIntField()`.
50
+
51
+ `@DecimalField()` / `@BigIntField()` accept a **string or number** on the wire and coerce/validate it (bad input → `400`), so there is no API change. `BigInt` columns serialize as a **string** in JSON responses (JSON has no bigint), pairing with the string-accepting input.
52
+
53
+ ### Migration
54
+
55
+ > **Behaviour change — a bare `appx-core generate` no longer creates modules or edits `app.module.ts`.** Intentional (it makes the command CI-safe), but new tables are not auto-exposed.
56
+
57
+ 1. Keep running `appx-core generate` after every schema change — it refreshes the Prisma client, GraphQL types and DTO bases, and is now guaranteed not to touch your committed code.
58
+ 2. **To expose a new table** as CRUD, run `appx-core generate models` and pick it (or `appx-core generate models <Name>`) — the only command that scaffolds `src/modules/**` and registers a module.
59
+ 3. **Existing modules are unaffected.** To reproduce the old "expose every table" behaviour in one shot, run `appx-core generate models --all`.
60
+ 4. If you relied on the generated **`/users`** CRUD, it is no longer scaffolded (auth owns `/auth/*`) — re-create it by hand only if you truly need generic user CRUD.
61
+ 5. **`Decimal` columns + GraphQL:** the GraphQL generator emits imports of `prisma-graphql-type-decimal` — a **peer dependency**, so `npm install` pulls it in (npm 7+ auto-installs peers); confirm with `npm ls prisma-graphql-type-decimal` if your package manager doesn't.
62
+ 6. If you hand-typed an `OmitType(...)` override to re-type a `DateTime` / `Decimal` / `BigInt` field (because the old type made your controller override fail with `TS2416`), delete it, let the generated base DTO stand, and regenerate. No wire change.
63
+
64
+ ---
65
+
17
66
  ## [0.1.122] — 2026-07-21
18
67
 
19
68
  **No migration necessary.**
@@ -70,7 +119,7 @@ import { setupCoreSecurity } from '@appxdigital/appx-core';
70
119
  const corsOrigin = configService.get<string>('CORS_ORIGIN') ?? 'http://localhost:3000';
71
120
  setupCoreSecurity(app, { cors: { origin: corsOrigin, credentials: true } });
72
121
  ```
73
- - Install Helmet: `npm install helmet@^8.0.0` (applied automatically by `setupCoreSecurity`; tune with `{ helmet: {...} }`, disable with `{ helmet: false }`).
122
+ - Helmet is applied automatically by `setupCoreSecurity` (tune with `{ helmet: {...} }`, disable with `{ helmet: false }`). It's a peer dependency, so `npm install` pulls it in for you (npm 7+ auto-installs peers) — just confirm it's present with `npm ls helmet`. Only if your package manager doesn't auto-install peers (or reports it missing) add it explicitly.
74
123
  - If you register a `ValidationPipe` with custom options, pass them through: `setupCoreSecurity(app, { validationPipe: { /* overrides */ } })`.
75
124
  - With `whitelist` + `forbidNonWhitelisted`, body properties not declared on a `class-validator` DTO are rejected (`400`). Confirm every DTO declares every field it legitimately accepts before deploying.
76
125
  - Set `CORS_ORIGIN` to your real front-end origin in production. Do not combine `'*'` with credentials — the helper throws at boot. For a public credential-less API pass `{ cors: { origin: '*', credentials: false } }`.
package/README.md CHANGED
@@ -124,12 +124,22 @@ npm install -g @appxdigital/appx-core-cli
124
124
  npm install -g @appxdigital/appx-core-cli@beta # CLI prerelease
125
125
  ```
126
126
 
127
- `appx-core create` scaffolds a project that depends on the **stable** library. To test a library prerelease in that project, install it there:
127
+ `appx-core create` pins the library to **the CLI's own channel** — a stable CLI scaffolds a project depending on the stable library, a beta CLI (`@beta`) one depending on the beta library. To move an existing project across channels, install it there directly:
128
128
 
129
129
  ```bash
130
130
  npm install @appxdigital/appx-core@beta # inside your project
131
131
  ```
132
132
 
133
+ **Staying up to date (automatic).** The CLI keeps itself current. On each run it checks the registry in the background (throttled), and when a newer version is published **on your channel** it installs it before your *next* command and re-launches into the new binary — so a beta install stays on `beta`, a stable install stays on `latest`. The check never blocks your command, and a failed/offline check is silently ignored.
134
+
135
+ ```bash
136
+ appx-core update # update now, on your current channel
137
+ appx-core update --channel beta # switch to the beta channel (or --channel production to switch back)
138
+ APPX_CORE_NO_AUTO_UPDATE=1 … # disable the background auto-update entirely
139
+ ```
140
+
141
+ Install logs (only written when an update runs) go to `~/.appx-core/last-install.log`.
142
+
133
143
  ### 2) Create a New Project
134
144
 
135
145
  ```bash
@@ -202,13 +212,35 @@ npx prisma db pull
202
212
 
203
213
  ### 5) Generate Modules and CRUD
204
214
 
205
- After you edit `schema.prisma`, run:
215
+ There are two generation commands, split by what they touch:
206
216
 
207
217
  ```bash
218
+ # Deploy-safe: regenerate the Prisma client, GraphQL types and DTO base classes
219
+ # under src/generated/ (gitignored). Never writes src/modules/ or app.module.ts,
220
+ # so it is safe in CI / postinstall / predeploy. Run it every time the schema
221
+ # changes (no need to run `prisma generate` separately).
208
222
  appx-core generate
223
+
224
+ # Scaffold CRUD for the tables you want to EXPOSE. Interactive picker listing
225
+ # models that don't yet have a module; for each selected model it creates the
226
+ # module/service/controller/resolver + DTO subclass and registers the module in
227
+ # app.module.ts, then runs the safe pass above.
228
+ appx-core generate models
229
+ # appx-core generate models Habit Log # non-interactive: named models
230
+ # appx-core generate models --all # every generatable model
209
231
  ```
210
232
 
211
- Run this **every time** you change the Prisma schema. This is the only required generation step (no need to run `prisma generate` separately).
233
+ Not every table needs its own module — because CRUD supports permission-gated
234
+ nested writes (`create` / `connect`), you can expose a parent and write related
235
+ rows through it. Scaffold modules only for the resources you actually serve.
236
+
237
+ > **`generate` is deploy-safe; `generate models` mutates code.** Only `generate
238
+ > models` writes hand-owned files and edits `app.module.ts` — run it during
239
+ > development. `generate` alone is idempotent and touches only `src/generated/`.
240
+ > The `User` model is framework-owned (auth already serves user endpoints) and is
241
+ > never offered by the wizard.
242
+
243
+ Full reference: **[docs/generate.md](./docs/generate.md)**.
212
244
 
213
245
  ### 6) Run Migrations
214
246
 
@@ -1,3 +1,4 @@
1
+ import './common/bigint-serializer';
1
2
  import { DynamicModule } from '@nestjs/common';
2
3
  import { PermissionsConfigType } from './common/config/permissionsConfigTypes';
3
4
  import { FileUploadModuleOptions } from './common/interfaces/file-upload.interface';
@@ -1 +1 @@
1
- {"version":3,"file":"appx-core.module.d.ts","sourceRoot":"","sources":["../src/appx-core.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAA2B,MAAM,gBAAgB,CAAC;AAEvE,OAAO,EAAC,qBAAqB,EAAC,MAAM,wCAAwC,CAAC;AAG7E,OAAO,EAAC,uBAAuB,EAAC,MAAM,2CAA2C,CAAC;AAElF,qBAEa,cAAc;IACvB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,qBAAqB,EAAE,gBAAgB,CAAC,EAAE,uBAAuB,GAAG,aAAa;CA6B5G"}
1
+ {"version":3,"file":"appx-core.module.d.ts","sourceRoot":"","sources":["../src/appx-core.module.ts"],"names":[],"mappings":"AAAA,OAAO,4BAA4B,CAAC;AACpC,OAAO,EAAC,aAAa,EAA2B,MAAM,gBAAgB,CAAC;AAEvE,OAAO,EAAC,qBAAqB,EAAC,MAAM,wCAAwC,CAAC;AAG7E,OAAO,EAAC,uBAAuB,EAAC,MAAM,2CAA2C,CAAC;AAElF,qBAEa,cAAc;IACvB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,qBAAqB,EAAE,gBAAgB,CAAC,EAAE,uBAAuB,GAAG,aAAa;CA6B5G"}
@@ -8,6 +8,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  var AppxCoreModule_1;
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.AppxCoreModule = void 0;
11
+ require("./common/bigint-serializer"); // side effect: BigInt → string in JSON output
11
12
  const common_1 = require("@nestjs/common");
12
13
  const permissions_config_provider_1 = require("./common/config/permissions.config.provider");
13
14
  const permissions_service_1 = require("./common/config/permissions.service");
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=bigint-serializer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bigint-serializer.d.ts","sourceRoot":"","sources":["../../src/common/bigint-serializer.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ /**
3
+ * `JSON.stringify` throws on a `bigint` ("Do not know how to serialize a
4
+ * BigInt"), so any model with a Prisma `BigInt` column would 500 when a CRUD
5
+ * endpoint serialises the row. Teach BigInt to serialise as its decimal string
6
+ * in JSON output (HTTP responses, logs). Applied once, on import — imported for
7
+ * its side effect by the core module, so it is active in every AppX Core app.
8
+ *
9
+ * String output pairs with `@BigIntField()` on the input side, which accepts a
10
+ * string (or number) — so a BigInt round-trips as a string over HTTP.
11
+ */
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ if (typeof BigInt.prototype.toJSON !== 'function') {
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, no-extend-native
15
+ BigInt.prototype.toJSON = function () {
16
+ return this.toString();
17
+ };
18
+ }
@@ -0,0 +1,22 @@
1
+ import { ValidatorConstraintInterface } from 'class-validator';
2
+ export declare class IsDecimalInputConstraint implements ValidatorConstraintInterface {
3
+ validate(value: unknown): boolean;
4
+ defaultMessage(): string;
5
+ }
6
+ export declare class IsBigIntInputConstraint implements ValidatorConstraintInterface {
7
+ validate(value: unknown): boolean;
8
+ defaultMessage(): string;
9
+ }
10
+ /**
11
+ * Marks a DTO field as a Prisma `Decimal`: accepts a string or number on the
12
+ * wire and validates it (Prisma coerces it to `Prisma.Decimal` on write). Pair
13
+ * with `@IsOptional` for optional columns.
14
+ */
15
+ export declare function DecimalField(): PropertyDecorator;
16
+ /**
17
+ * Marks a DTO field as a Prisma `BigInt`: accepts a string or number on the wire,
18
+ * coerces it to `bigint`, and validates it. Pair with `@IsOptional` for optional
19
+ * columns.
20
+ */
21
+ export declare function BigIntField(): PropertyDecorator;
22
+ //# sourceMappingURL=scalar-field.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scalar-field.decorator.d.ts","sourceRoot":"","sources":["../../../src/common/decorators/scalar-field.decorator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgC,4BAA4B,EAAC,MAAM,iBAAiB,CAAC;AAiD5F,qBACa,wBAAyB,YAAW,4BAA4B;IACzE,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAIjC,cAAc,IAAI,MAAM;CAG3B;AAED,qBACa,uBAAwB,YAAW,4BAA4B;IACxE,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAIjC,cAAc,IAAI,MAAM;CAG3B;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,iBAAiB,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,iBAAiB,CAK/C"}
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.BigIntField = exports.DecimalField = exports.IsBigIntInputConstraint = exports.IsDecimalInputConstraint = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const class_transformer_1 = require("class-transformer");
12
+ const class_validator_1 = require("class-validator");
13
+ /**
14
+ * DTO field decorators for Prisma `Decimal` and `BigInt` columns.
15
+ *
16
+ * Generated CRUD DTOs must type these columns as `Prisma.Decimal` / `bigint`
17
+ * (the Prisma model types) so a controller override type-checks against
18
+ * `CoreController<T>`. But JSON can't carry them and class-transformer doesn't
19
+ * know how to build them. These decorators accept a **string or number** on the
20
+ * wire and validate it; a value that isn't numeric yields a clean `400`.
21
+ *
22
+ * - `@DecimalField()` validates the value and passes it through unchanged —
23
+ * Prisma's create/update input accepts `string | number | Decimal` and coerces
24
+ * it to a real `Prisma.Decimal` on write. (We deliberately do NOT construct a
25
+ * `Prisma.Decimal` here: the framework's own bundled client is a stub, so a
26
+ * `require('@prisma/client').Prisma.Decimal` isn't reliably available at the
27
+ * framework's runtime location.)
28
+ * - `@BigIntField()` coerces to a real `bigint` (Prisma's BigInt input doesn't
29
+ * accept a string); `BigInt()` is a global, so no client is involved.
30
+ */
31
+ const isNullish = (v) => v === null || v === undefined;
32
+ // A finite number, or a string that is a plain/scientific decimal literal.
33
+ const DECIMAL_STRING = /^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$/;
34
+ function isDecimalWire(v) {
35
+ if (typeof v === 'number')
36
+ return Number.isFinite(v);
37
+ if (typeof v === 'string') {
38
+ const s = v.trim();
39
+ return s !== '' && DECIMAL_STRING.test(s);
40
+ }
41
+ return false;
42
+ }
43
+ function toBigInt(value) {
44
+ if (isNullish(value))
45
+ return value;
46
+ if (Array.isArray(value))
47
+ return value.map(toBigInt);
48
+ if (typeof value !== 'string' && typeof value !== 'number')
49
+ return value;
50
+ try {
51
+ return BigInt(value);
52
+ }
53
+ catch {
54
+ return value; // non-integer / garbage → validator produces a 400
55
+ }
56
+ }
57
+ // Constraints reject nullish so a missing REQUIRED column fails with a clean 400;
58
+ // optional columns carry `@IsOptional`, which short-circuits before the
59
+ // constraint runs, so null/undefined is still accepted there.
60
+ let IsDecimalInputConstraint = exports.IsDecimalInputConstraint = class IsDecimalInputConstraint {
61
+ validate(value) {
62
+ if (Array.isArray(value))
63
+ return value.every(isDecimalWire);
64
+ return isDecimalWire(value);
65
+ }
66
+ defaultMessage() {
67
+ return '$property must be a decimal (a numeric string or number)';
68
+ }
69
+ };
70
+ exports.IsDecimalInputConstraint = IsDecimalInputConstraint = __decorate([
71
+ (0, class_validator_1.ValidatorConstraint)({ name: 'isDecimalInput', async: false })
72
+ ], IsDecimalInputConstraint);
73
+ let IsBigIntInputConstraint = exports.IsBigIntInputConstraint = class IsBigIntInputConstraint {
74
+ validate(value) {
75
+ if (Array.isArray(value))
76
+ return value.every((v) => typeof v === 'bigint');
77
+ return typeof value === 'bigint';
78
+ }
79
+ defaultMessage() {
80
+ return '$property must be an integer (a numeric string or number)';
81
+ }
82
+ };
83
+ exports.IsBigIntInputConstraint = IsBigIntInputConstraint = __decorate([
84
+ (0, class_validator_1.ValidatorConstraint)({ name: 'isBigIntInput', async: false })
85
+ ], IsBigIntInputConstraint);
86
+ /**
87
+ * Marks a DTO field as a Prisma `Decimal`: accepts a string or number on the
88
+ * wire and validates it (Prisma coerces it to `Prisma.Decimal` on write). Pair
89
+ * with `@IsOptional` for optional columns.
90
+ */
91
+ function DecimalField() {
92
+ return (0, common_1.applyDecorators)((0, class_validator_1.Validate)(IsDecimalInputConstraint));
93
+ }
94
+ exports.DecimalField = DecimalField;
95
+ /**
96
+ * Marks a DTO field as a Prisma `BigInt`: accepts a string or number on the wire,
97
+ * coerces it to `bigint`, and validates it. Pair with `@IsOptional` for optional
98
+ * columns.
99
+ */
100
+ function BigIntField() {
101
+ return (0, common_1.applyDecorators)((0, class_transformer_1.Transform)(({ value }) => toBigInt(value)), (0, class_validator_1.Validate)(IsBigIntInputConstraint));
102
+ }
103
+ exports.BigIntField = BigIntField;
@@ -1,58 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
- if (k2 === undefined) k2 = k;
5
- var desc = Object.getOwnPropertyDescriptor(m, k);
6
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
- desc = { enumerable: true, get: function() { return m[k]; } };
8
- }
9
- Object.defineProperty(o, k2, desc);
10
- }) : (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- o[k2] = m[k];
13
- }));
14
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
- Object.defineProperty(o, "default", { enumerable: true, value: v });
16
- }) : function(o, v) {
17
- o["default"] = v;
18
- });
19
- var __importStar = (this && this.__importStar) || function (mod) {
20
- if (mod && mod.__esModule) return mod;
21
- var result = {};
22
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
23
- __setModuleDefault(result, mod);
24
- return result;
25
- };
26
3
  Object.defineProperty(exports, "__esModule", { value: true });
27
- const child_process_1 = require("child_process");
28
- const path = __importStar(require("path"));
29
- const scriptsDir = path.join(__dirname);
30
- console.log('Running Prisma Generate...');
31
- (0, child_process_1.execSync)(`prisma generate`, {
32
- stdio: 'inherit',
33
- });
34
- console.log('Generating Modules...');
35
- (0, child_process_1.execSync)(`node ${path.join(scriptsDir, 'generate-modules.js')}`, {
36
- stdio: 'inherit',
37
- });
38
- console.log('Generating Resolvers...');
39
- (0, child_process_1.execSync)(`node ${path.join(scriptsDir, 'generate-resolvers.js')}`, {
40
- stdio: 'inherit',
41
- });
42
- console.log('Generating Services...');
43
- (0, child_process_1.execSync)(`node ${path.join(scriptsDir, 'generate-services.js')}`, {
44
- stdio: 'inherit',
45
- });
46
- console.log('Generating DTOs...');
47
- (0, child_process_1.execSync)(`node ${path.join(scriptsDir, 'generate-dtos.js')}`, {
48
- stdio: 'inherit',
49
- });
50
- console.log('Generating Controllers...');
51
- (0, child_process_1.execSync)(`node ${path.join(scriptsDir, 'generate-controllers.js')}`, {
52
- stdio: 'inherit',
53
- });
54
- // console.log('Generating Session Schema...');
55
- // execSync(`node ${path.join(scriptsDir, 'generate-session-schema.js')}`, {
56
- // stdio: 'inherit',
57
- // });
58
- console.log('All generators ran successfully.');
4
+ /**
5
+ * `appx generate` — the DEPLOY-SAFE pass.
6
+ *
7
+ * Regenerates only the overwrite-safe artifacts under the gitignored
8
+ * `src/generated/**`:
9
+ * - the Prisma client and the prisma-nestjs-graphql outputs (`prisma generate`
10
+ * runs both generator blocks), and
11
+ * - the DTO base classes (`src/generated/dto/**`).
12
+ *
13
+ * It NEVER writes `src/modules/**` and NEVER edits `src/app.module.ts`, so it is
14
+ * safe to run in CI / postinstall / predeploy and re-run any number of times.
15
+ * Scaffolding CRUD modules (which mutates code) is the separate, interactive
16
+ * `appx generate models` wizard.
17
+ */
18
+ const utils_1 = require("./utils");
19
+ const generate_dtos_1 = require("./generate-dtos");
20
+ console.log('Running Prisma Generate (client + GraphQL artifacts)...');
21
+ // Project-local prisma: the CLI is usually global, so PATH has no project .bin.
22
+ (0, utils_1.runProjectBin)('prisma', 'generate');
23
+ console.log('Generating DTO base classes...');
24
+ (0, generate_dtos_1.generateDtoBases)((0, utils_1.loadAllModels)());
25
+ console.log('Deploy-safe generation complete — src/generated only, no code changes.');
@@ -1,2 +1,3 @@
1
- export {};
1
+ /** Scaffold the controller file for a single model (once; never overwritten). */
2
+ export declare function scaffoldController(modelName: string): void;
2
3
  //# sourceMappingURL=generate-controllers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate-controllers.d.ts","sourceRoot":"","sources":["../../src/config/generate-controllers.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"generate-controllers.d.ts","sourceRoot":"","sources":["../../src/config/generate-controllers.ts"],"names":[],"mappings":"AA6CA,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAI1D"}
@@ -23,10 +23,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- const fs = __importStar(require("fs"));
26
+ exports.scaffoldController = void 0;
27
27
  const path = __importStar(require("path"));
28
28
  const utils_1 = require("./utils");
29
- const modelsPath = path.join(process.cwd(), 'src/generated');
30
29
  const modulesOutputPath = path.join(process.cwd(), 'src/modules');
31
30
  /**
32
31
  * Generic controller template for a given model
@@ -67,24 +66,10 @@ export class ${model}Controller extends CoreController<${model}> {
67
66
  }
68
67
  }
69
68
  `;
70
- /**
71
- * Generate controllers for each model
72
- */
73
- fs.readdirSync(modelsPath).forEach((folder) => {
74
- if (utils_1.IGNORE_FOLDERS.includes(folder))
75
- return;
76
- const modelName = (0, utils_1.kebabToPascalCase)(folder); // Capitalize model name e.g., 'Comment', 'Post'
77
- const modelOutputPath = path.join(modulesOutputPath, folder);
78
- if (!fs.existsSync(modelOutputPath)) {
79
- fs.mkdirSync(modelOutputPath, { recursive: true });
80
- console.log(`Folder for model ${modelName} created.`);
81
- }
82
- else {
83
- console.log(`Folder for model ${modelName} already exists, skipping creation.`);
84
- }
85
- /**
86
- * Create the controller file
87
- */
88
- const controllerPath = path.join(modelOutputPath, `${folder}.controller.ts`);
69
+ /** Scaffold the controller file for a single model (once; never overwritten). */
70
+ function scaffoldController(modelName) {
71
+ const folder = (0, utils_1.modelFolder)(modelName);
72
+ const controllerPath = path.join(modulesOutputPath, folder, `${folder}.controller.ts`);
89
73
  (0, utils_1.createFileIfNotExists)(controllerPath, genericControllerTemplate(modelName, folder));
90
- });
74
+ }
75
+ exports.scaffoldController = scaffoldController;
@@ -1,2 +1,15 @@
1
- export {};
1
+ /**
2
+ * Deploy-safe pass: (re)generate the DTO **base** classes under the gitignored
3
+ * `src/generated/dto/`, one per non-framework model. Overwrite-only — never
4
+ * touches `src/modules/`. `allModels` is the full DMMF list (framework models
5
+ * included) so relation-nested-write members can resolve their target model;
6
+ * bases are only emitted for non-framework models.
7
+ */
8
+ export declare function generateDtoBases(allModels: any[]): void;
9
+ /**
10
+ * Wizard/scaffold pass: create the hand-owned DTO **subclass** files (create +
11
+ * update) for a single model under `src/modules/<model>/dto/`. Generated once,
12
+ * never overwritten — this is where the developer adds custom validation.
13
+ */
14
+ export declare function scaffoldDtoSubclass(modelName: string): void;
2
15
  //# sourceMappingURL=generate-dtos.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate-dtos.d.ts","sourceRoot":"","sources":["../../src/config/generate-dtos.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"generate-dtos.d.ts","sourceRoot":"","sources":["../../src/config/generate-dtos.ts"],"names":[],"mappings":"AA0UA;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,IAAI,CAiBvD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAU3D"}