create-projx 1.7.0 → 1.7.1
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 +13 -35
- package/dist/{baseline-FHOZNS4D.js → baseline-FKCXQFRD.js} +2 -2
- package/dist/{chunk-IMZKHDIL.js → chunk-N4WD4VN3.js} +15 -18
- package/dist/{chunk-HAT7D4G2.js → chunk-OLPF7FAN.js} +1 -1
- package/dist/index.js +166 -385
- package/dist/{utils-BZGSJ7XZ.js → utils-4G3HNHES.js} +1 -1
- package/package.json +2 -3
- package/src/templates/README.md.ejs +1 -1
- package/src/addons/orms/drizzle/express/src/app.ts +0 -81
- package/src/addons/orms/drizzle/express/src/modules/_base/auto-routes.ts +0 -278
- package/src/addons/orms/drizzle/express/src/modules/_base/index.ts +0 -20
- package/src/addons/orms/drizzle/express/src/server.ts +0 -32
- package/src/addons/orms/drizzle/express/tests/app.test.ts +0 -24
- package/src/addons/orms/drizzle/express/vitest.config.ts +0 -20
- package/src/addons/orms/drizzle/fastify/src/app.ts +0 -90
- package/src/addons/orms/drizzle/fastify/src/modules/_base/auto-routes.ts +0 -268
- package/src/addons/orms/drizzle/fastify/src/modules/_base/index.ts +0 -20
- package/src/addons/orms/drizzle/fastify/tests/modules/app.test.ts +0 -20
- package/src/addons/orms/drizzle/fastify/vitest.config.ts +0 -31
- package/src/addons/orms/drizzle/gen-entity/express-router.ts +0 -21
- package/src/addons/orms/drizzle/gen-entity/express-test.ts +0 -61
- package/src/addons/orms/drizzle/gen-entity/fastify-router.ts +0 -19
- package/src/addons/orms/drizzle/gen-entity/fastify-test.ts +0 -87
- package/src/addons/orms/drizzle/manifest.json +0 -52
- package/src/addons/orms/drizzle/shared/drizzle.config.ts +0 -12
- package/src/addons/orms/drizzle/shared/src/db/client.ts +0 -17
- package/src/addons/orms/drizzle/shared/src/db/schema.ts +0 -14
- package/src/addons/orms/drizzle/shared/src/modules/_base/query-engine.ts +0 -115
- package/src/addons/orms/drizzle/shared/src/modules/_base/registry.ts +0 -15
- package/src/addons/orms/sequelize/express/src/app.ts +0 -82
- package/src/addons/orms/sequelize/express/src/modules/_base/auto-routes.ts +0 -226
- package/src/addons/orms/sequelize/express/src/modules/_base/index.ts +0 -20
- package/src/addons/orms/sequelize/express/src/server.ts +0 -32
- package/src/addons/orms/sequelize/express/tests/app.test.ts +0 -24
- package/src/addons/orms/sequelize/express/vitest.config.ts +0 -20
- package/src/addons/orms/sequelize/fastify/src/app.ts +0 -83
- package/src/addons/orms/sequelize/fastify/src/modules/_base/auto-routes.ts +0 -216
- package/src/addons/orms/sequelize/fastify/src/modules/_base/index.ts +0 -20
- package/src/addons/orms/sequelize/fastify/tests/modules/app.test.ts +0 -20
- package/src/addons/orms/sequelize/fastify/vitest.config.ts +0 -31
- package/src/addons/orms/sequelize/gen-entity/express-router.ts +0 -17
- package/src/addons/orms/sequelize/gen-entity/express-test.ts +0 -65
- package/src/addons/orms/sequelize/gen-entity/fastify-router.ts +0 -19
- package/src/addons/orms/sequelize/gen-entity/fastify-test.ts +0 -89
- package/src/addons/orms/sequelize/gen-entity/model.ts +0 -21
- package/src/addons/orms/sequelize/manifest.json +0 -53
- package/src/addons/orms/sequelize/shared/scripts/db-sync.ts +0 -14
- package/src/addons/orms/sequelize/shared/src/db/client.ts +0 -19
- package/src/addons/orms/sequelize/shared/src/models/index.ts +0 -9
- package/src/addons/orms/sequelize/shared/src/modules/_base/query-engine.ts +0 -101
- package/src/addons/orms/sequelize/shared/src/modules/_base/registry.ts +0 -15
- package/src/addons/orms/typeorm/express/src/app.ts +0 -82
- package/src/addons/orms/typeorm/express/src/modules/_base/auto-routes.ts +0 -249
- package/src/addons/orms/typeorm/express/src/modules/_base/index.ts +0 -19
- package/src/addons/orms/typeorm/express/src/server.ts +0 -43
- package/src/addons/orms/typeorm/express/tests/app.test.ts +0 -24
- package/src/addons/orms/typeorm/express/vitest.config.ts +0 -20
- package/src/addons/orms/typeorm/fastify/src/app.ts +0 -86
- package/src/addons/orms/typeorm/fastify/src/modules/_base/auto-routes.ts +0 -239
- package/src/addons/orms/typeorm/fastify/src/modules/_base/index.ts +0 -19
- package/src/addons/orms/typeorm/fastify/tests/modules/app.test.ts +0 -20
- package/src/addons/orms/typeorm/fastify/vitest.config.ts +0 -31
- package/src/addons/orms/typeorm/gen-entity/entity.ts +0 -21
- package/src/addons/orms/typeorm/gen-entity/express-router.ts +0 -17
- package/src/addons/orms/typeorm/gen-entity/express-test.ts +0 -66
- package/src/addons/orms/typeorm/gen-entity/fastify-router.ts +0 -19
- package/src/addons/orms/typeorm/gen-entity/fastify-test.ts +0 -89
- package/src/addons/orms/typeorm/manifest.json +0 -53
- package/src/addons/orms/typeorm/shared/scripts/db-sync.ts +0 -14
- package/src/addons/orms/typeorm/shared/src/db/data-source.ts +0 -21
- package/src/addons/orms/typeorm/shared/src/entities/index.ts +0 -8
- package/src/addons/orms/typeorm/shared/src/modules/_base/query-engine.ts +0 -94
- package/src/addons/orms/typeorm/shared/src/modules/_base/registry.ts +0 -15
- package/src/addons/orms/typeorm/shared/tsconfig.json +0 -16
package/README.md
CHANGED
|
@@ -85,15 +85,15 @@ If this saves you even one hour, it's already paid for itself. (It's free.)
|
|
|
85
85
|
|
|
86
86
|
## What you get
|
|
87
87
|
|
|
88
|
-
| Component | Stack | What it gives you
|
|
89
|
-
| ---------- | ------------------------------------------------------------- |
|
|
90
|
-
| `fastapi` | Python, SQLAlchemy, Alembic | Auto-entity CRUD, JWT auth, migrations, OpenAPI docs
|
|
91
|
-
| `fastify` | Node.js, Prisma / Drizzle / Sequelize / TypeORM, TypeBox | Auto-entity CRUD, JWT auth, typed schemas, OpenAPI docs
|
|
92
|
-
| `express` | Express 5, TypeScript, Prisma / Drizzle / Sequelize / TypeORM | Auto-entity CRUD, validation, security middleware, health checks
|
|
93
|
-
| `frontend` | React 19, TypeScript, Vite |
|
|
94
|
-
| `mobile` | Flutter, Riverpod, GoRouter |
|
|
95
|
-
| `e2e` | Playwright | Page object model, auth fixtures, accessibility scans
|
|
96
|
-
| `infra` | Terraform, AWS | EKS, RDS, VPC, ALB, CodePipeline, multi-environment
|
|
88
|
+
| Component | Stack | What it gives you |
|
|
89
|
+
| ---------- | ------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
90
|
+
| `fastapi` | Python, SQLAlchemy, Alembic | Auto-entity CRUD, JWT auth, migrations, OpenAPI docs |
|
|
91
|
+
| `fastify` | Node.js, Prisma / Drizzle / Sequelize / TypeORM, TypeBox | Auto-entity CRUD, JWT auth, typed schemas, OpenAPI docs |
|
|
92
|
+
| `express` | Express 5, TypeScript, Prisma / Drizzle / Sequelize / TypeORM | Auto-entity CRUD, JWT auth, validation, security middleware, health checks |
|
|
93
|
+
| `frontend` | React 19, TypeScript, Vite | Auth, theming, design tokens, light/dark mode |
|
|
94
|
+
| `mobile` | Flutter, Riverpod, GoRouter | Auth, biometric, theming, GoRouter shell |
|
|
95
|
+
| `e2e` | Playwright | Page object model, auth fixtures, accessibility scans |
|
|
96
|
+
| `infra` | Terraform, AWS | EKS, RDS, VPC, ALB, CodePipeline, multi-environment |
|
|
97
97
|
|
|
98
98
|
Plus, in every project: Docker Compose for dev + prod, GitHub Actions CI per component (path-filtered), pre-commit hooks, secret detection, VS Code settings, and 80% test coverage enforced.
|
|
99
99
|
|
|
@@ -242,7 +242,6 @@ npx create-projx unpin <patterns...>
|
|
|
242
242
|
npx create-projx pin --list
|
|
243
243
|
npx create-projx doctor [--fix]
|
|
244
244
|
npx create-projx gen entity <name> [--ai | --backend]
|
|
245
|
-
npx create-projx sync [--url <url>]
|
|
246
245
|
|
|
247
246
|
--components <list> Comma-separated: fastapi,fastify,express,frontend,mobile,e2e,infra
|
|
248
247
|
--name <dir> Custom directory for `add <type>` (multi-instance)
|
|
@@ -315,7 +314,6 @@ Override with `--ai` (fastapi) or `--backend` (fastify).
|
|
|
315
314
|
| Primary backend (fastapi) | `src/entities/<name>/_model.py` + `tests/test_<name>_entity.py` — model + 11 CRUD/auth tests |
|
|
316
315
|
| Primary backend (fastify) | `src/modules/<name>/schemas.ts` + `index.ts` + Prisma model + `tests/modules/<name>.test.ts` |
|
|
317
316
|
| `frontend` | `src/types/<name>.ts` — TypeScript interface + Create/Update variants |
|
|
318
|
-
| `mobile` | `lib/entities/<name>/model.dart` — Dart class with fromJson/toJson/copyWith |
|
|
319
317
|
|
|
320
318
|
**Tests included**: every `gen entity` writes a working integration test file alongside the model — 11 tests for FastAPI (extending `BaseEntityApiTest`), 11 tests for Fastify (via `describeCrudEntity`). Both run against a real database (Postgres). New entities ship green from day one — no scrambling to bolt on tests at go-live.
|
|
321
319
|
|
|
@@ -336,26 +334,6 @@ All four ORMs scaffold equivalent runtime behavior: `_base/auto-routes.ts` wires
|
|
|
336
334
|
|
|
337
335
|
ORM-specific scaffolding lives in [cli/src/addons/orms/](cli/src/addons/orms/) — each ORM is a self-contained folder with a `manifest.json` (deps, file removals, scripts), `shared/` files, per-framework overlays, and `gen-entity/` templates. Adding a new ORM means adding a new folder there; no CLI core changes.
|
|
338
336
|
|
|
339
|
-
### Sync Types
|
|
340
|
-
|
|
341
|
-
Regenerate all frontend/mobile types from a running backend:
|
|
342
|
-
|
|
343
|
-
```bash
|
|
344
|
-
npx create-projx sync # auto-detects URL
|
|
345
|
-
npx create-projx sync --url http://localhost:8000/api/v1/_meta # explicit URL
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
Fetches `/_meta` from your backend, generates typed interfaces for every entity. Run after any backend change — new field, renamed column, new entity.
|
|
349
|
-
|
|
350
|
-
The generic `api.ts` client accepts type parameters:
|
|
351
|
-
|
|
352
|
-
```tsx
|
|
353
|
-
import type { Invoice } from "../types/invoice";
|
|
354
|
-
|
|
355
|
-
const { data } = await api.list<Invoice>("/invoices"); // data: Invoice[]
|
|
356
|
-
const item = await api.get<Invoice>("/invoices", id); // item: Invoice
|
|
357
|
-
```
|
|
358
|
-
|
|
359
337
|
## Rename Component Directories
|
|
360
338
|
|
|
361
339
|
Rename `fastapi/` to `backend/`? Just rename the folder — the `.projx-component` marker file moves with it. The `update` command auto-discovers where each component lives by scanning for these markers. No config changes needed.
|
|
@@ -373,7 +351,7 @@ CI, `scripts/setup.sh`, pre-commit hooks, and docker-compose are all regenerated
|
|
|
373
351
|
my-app/
|
|
374
352
|
├── fastapi/ # Auto-entity CRUD backend
|
|
375
353
|
│ └── .projx-component # Identifies this as the fastapi component
|
|
376
|
-
├── frontend/ #
|
|
354
|
+
├── frontend/ # React + Vite shell
|
|
377
355
|
│ └── .projx-component
|
|
378
356
|
├── e2e/ # Playwright E2E tests
|
|
379
357
|
│ └── .projx-component
|
|
@@ -393,11 +371,11 @@ The core idea: define a data model, get everything else for free.
|
|
|
393
371
|
|
|
394
372
|
**Backend** — Drop a model file. The registry auto-discovers it and generates CRUD routes, schemas, pagination, filtering, sorting, search, FK expansion, and OpenAPI docs.
|
|
395
373
|
|
|
396
|
-
**Field privacy** — Sensitive columns (`password_hash`, `secret`, `api_key`, `mfa_secret`, etc.) are automatically stripped from API responses
|
|
374
|
+
**Field privacy** — Sensitive columns (`password_hash`, `secret`, `api_key`, `mfa_secret`, etc.) are automatically stripped from API responses via a built-in baseline. Add project-specific hidden fields per entity (`__hidden_fields__` in FastAPI, `hiddenFields` in Fastify). Mark entire entities as `__private__` / `private: true` to hide them from the API entirely — no routes registered.
|
|
397
375
|
|
|
398
|
-
**Frontend** —
|
|
376
|
+
**Frontend** — Ships a React shell with auth, theming, and design tokens. Build your own pages using the generated types from `gen entity`.
|
|
399
377
|
|
|
400
|
-
**Mobile** —
|
|
378
|
+
**Mobile** — Ships a Flutter shell with auth, biometric, and GoRouter scaffolding. Build screens using the generated Dart models from `gen entity`.
|
|
401
379
|
|
|
402
380
|
## Encrypted Service Config
|
|
403
381
|
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
toSnake,
|
|
14
14
|
upsertComponentMarker,
|
|
15
15
|
writeProjxConfig
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-OLPF7FAN.js";
|
|
17
17
|
|
|
18
18
|
// src/baseline.ts
|
|
19
19
|
import { existsSync, writeFileSync, unlinkSync } from "fs";
|
|
@@ -29,7 +29,6 @@ import {
|
|
|
29
29
|
} from "fs/promises";
|
|
30
30
|
import { execSync } from "child_process";
|
|
31
31
|
import { join as join2, dirname } from "path";
|
|
32
|
-
import { fileURLToPath } from "url";
|
|
33
32
|
import { tmpdir } from "os";
|
|
34
33
|
|
|
35
34
|
// src/generators/index.ts
|
|
@@ -127,7 +126,7 @@ function generateVscodeSettings(vars) {
|
|
|
127
126
|
// src/baseline.ts
|
|
128
127
|
var BASELINE_REF = "refs/projx/baseline";
|
|
129
128
|
async function migrateComponentMarkers(cwd, components, componentPaths, applyDefaults) {
|
|
130
|
-
const { readComponentMarker: readComponentMarker2, writeComponentMarker } = await import("./utils-
|
|
129
|
+
const { readComponentMarker: readComponentMarker2, writeComponentMarker } = await import("./utils-4G3HNHES.js");
|
|
131
130
|
for (const component of components) {
|
|
132
131
|
const dir = componentPaths[component];
|
|
133
132
|
const markerDir = join2(cwd, dir);
|
|
@@ -505,7 +504,7 @@ async function writeOneInstance(inst, opts) {
|
|
|
505
504
|
[type]: targetDir
|
|
506
505
|
};
|
|
507
506
|
await renderEjsInDir(outDir, { ...vars, paths: instancePaths });
|
|
508
|
-
await applyOrmProviderToInstance(outDir, type, vars);
|
|
507
|
+
await applyOrmProviderToInstance(repoDir, outDir, type, vars);
|
|
509
508
|
await upsertComponentMarker(
|
|
510
509
|
join2(dest, targetDir),
|
|
511
510
|
type,
|
|
@@ -519,18 +518,14 @@ async function writeOneInstance(inst, opts) {
|
|
|
519
518
|
vars.nameOverrides
|
|
520
519
|
);
|
|
521
520
|
}
|
|
522
|
-
async function applyOrmProviderToInstance(dir, component, vars) {
|
|
521
|
+
async function applyOrmProviderToInstance(repoDir, dir, component, vars) {
|
|
523
522
|
const orm = typeof vars.orm === "string" ? vars.orm : void 0;
|
|
524
523
|
if (!orm || orm === "prisma") return;
|
|
525
524
|
if (component !== "fastify" && component !== "express") return;
|
|
526
|
-
await applyOrmAddon(orm, component, dir, vars);
|
|
525
|
+
await applyOrmAddon(repoDir, orm, component, dir, vars);
|
|
527
526
|
}
|
|
528
|
-
function
|
|
529
|
-
const
|
|
530
|
-
return join2(thisFile, "../../src/addons");
|
|
531
|
-
}
|
|
532
|
-
async function loadOrmManifest(orm) {
|
|
533
|
-
const path = join2(sharedAddonDir(), "orms", orm, "manifest.json");
|
|
527
|
+
async function loadOrmManifest(repoDir, orm) {
|
|
528
|
+
const path = join2(repoDir, "addons", "orms", orm, "manifest.json");
|
|
534
529
|
if (!existsSync(path)) {
|
|
535
530
|
throw new Error(
|
|
536
531
|
`ORM "${orm}" is not yet supported. No manifest found at ${path}.`
|
|
@@ -566,8 +561,8 @@ function applyPackageOverrides(pkg, overrides) {
|
|
|
566
561
|
Object.assign(devDependencies, overrides.addDevDependencies ?? {});
|
|
567
562
|
pkg.devDependencies = devDependencies;
|
|
568
563
|
}
|
|
569
|
-
async function applyOrmAddon(orm, framework, dir, vars) {
|
|
570
|
-
const manifest = await loadOrmManifest(orm);
|
|
564
|
+
async function applyOrmAddon(repoDir, orm, framework, dir, vars) {
|
|
565
|
+
const manifest = await loadOrmManifest(repoDir, orm);
|
|
571
566
|
if (!manifest.frameworks.includes(framework)) {
|
|
572
567
|
throw new Error(
|
|
573
568
|
`ORM "${orm}" does not support framework "${framework}". Supported: ${manifest.frameworks.join(", ")}`
|
|
@@ -577,10 +572,12 @@ async function applyOrmAddon(orm, framework, dir, vars) {
|
|
|
577
572
|
await rm(join2(dir, relPath), { recursive: true, force: true });
|
|
578
573
|
}
|
|
579
574
|
const pkgPath = join2(dir, "package.json");
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
575
|
+
if (existsSync(pkgPath)) {
|
|
576
|
+
const pkg = await readJsonObject(pkgPath);
|
|
577
|
+
applyPackageOverrides(pkg, manifest.packageOverrides);
|
|
578
|
+
await writeJsonObject(pkgPath, pkg);
|
|
579
|
+
}
|
|
580
|
+
const addonRoot = join2(repoDir, "addons", "orms", orm);
|
|
584
581
|
const sharedSrc = join2(addonRoot, "shared");
|
|
585
582
|
const frameworkSrc = join2(addonRoot, framework);
|
|
586
583
|
if (existsSync(sharedSrc)) {
|
|
@@ -389,7 +389,7 @@ async function discoverComponentsFromMarkers(cwd) {
|
|
|
389
389
|
}
|
|
390
390
|
function render(template, vars) {
|
|
391
391
|
const lines = template.split("\n");
|
|
392
|
-
return renderLines(lines, vars).replace(/\n{
|
|
392
|
+
return renderLines(lines, vars).replace(/\n{4,}/g, "\n\n\n");
|
|
393
393
|
}
|
|
394
394
|
function evalExpr(expr, vars) {
|
|
395
395
|
const components = vars.components;
|