tina4-nodejs 3.13.97 → 3.13.99
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/CLAUDE.md +60 -25
- package/package.json +1 -2
- package/packages/cli/dist/bin.js +20620 -18995
- package/packages/cli/src/bin.ts +28 -71
- package/packages/cli/src/commands/migrate.ts +36 -75
- package/packages/cli/src/commands/migrateRollback.ts +10 -1
- package/packages/cli/src/commands/test.ts +92 -21
- package/packages/core/dist/index.js +20459 -18815
- package/packages/core/public/js/tina4-dev-admin.min.js +23 -19
- package/packages/core/src/ai.ts +28 -12
- package/packages/core/src/api.ts +13 -5
- package/packages/core/src/background.ts +9 -3
- package/packages/core/src/devAdmin.ts +135 -20
- package/packages/core/src/dispatchPipeline.ts +185 -1
- package/packages/core/src/docs.ts +33 -5
- package/packages/core/src/env.ts +1 -1
- package/packages/core/src/errorOverlay.ts +39 -48
- package/packages/core/src/fakeData.ts +15 -0
- package/packages/core/src/index.ts +17 -6
- package/packages/core/src/logger.ts +892 -572
- package/packages/core/src/mcp.ts +9 -1
- package/packages/core/src/messenger.ts +31 -4
- package/packages/core/src/middleware.ts +169 -43
- package/packages/core/src/portTakeover.ts +232 -0
- package/packages/core/src/request.ts +57 -8
- package/packages/core/src/response.ts +67 -0
- package/packages/core/src/router.ts +35 -7
- package/packages/core/src/server.ts +450 -190
- package/packages/core/src/static.ts +81 -12
- package/packages/core/src/testClient.ts +126 -137
- package/packages/core/src/testing.ts +16 -12
- package/packages/core/src/types.ts +21 -9
- package/packages/core/src/version.ts +66 -0
- package/packages/core/src/websocket.ts +2 -2
- package/packages/core/src/websocketBackplane.ts +2 -2
- package/packages/frond/dist/index.js +31 -13
- package/packages/frond/src/engine.ts +39 -7
- package/packages/orm/dist/index.js +10879 -9258
- package/packages/orm/src/adapters/firebird.ts +200 -27
- package/packages/orm/src/adapters/mongodb.ts +160 -10
- package/packages/orm/src/adapters/mssql.ts +38 -11
- package/packages/orm/src/adapters/mysql.ts +24 -1
- package/packages/orm/src/adapters/odbc.ts +127 -29
- package/packages/orm/src/adapters/postgres.ts +18 -0
- package/packages/orm/src/adapters/sqlite.ts +93 -14
- package/packages/orm/src/autoCrud.ts +72 -8
- package/packages/orm/src/baseModel.ts +323 -71
- package/packages/orm/src/cachedDatabase.ts +48 -1
- package/packages/orm/src/database.ts +162 -59
- package/packages/orm/src/fakeData.ts +6 -2
- package/packages/orm/src/index.ts +4 -1
- package/packages/orm/src/migration.ts +95 -52
- package/packages/orm/src/query.ts +16 -4
- package/packages/orm/src/seeder.ts +43 -25
- package/packages/orm/src/sqlTranslator.ts +104 -19
- package/packages/orm/src/types.ts +97 -21
- package/packages/orm/src/validation.ts +5 -1
- package/packages/swagger/dist/index.js +3 -2
- package/packages/swagger/src/generator.ts +19 -4
- package/packages/swagger/src/ui.ts +6 -4
- package/types/cli/src/bin.d.ts +0 -22
- package/types/core/src/api.d.ts +11 -4
- package/types/core/src/background.d.ts +5 -2
- package/types/core/src/devAdmin.d.ts +35 -0
- package/types/core/src/dispatchPipeline.d.ts +41 -1
- package/types/core/src/errorOverlay.d.ts +13 -13
- package/types/core/src/index.d.ts +9 -6
- package/types/core/src/logger.d.ts +111 -185
- package/types/core/src/middleware.d.ts +40 -5
- package/types/core/src/portTakeover.d.ts +50 -0
- package/types/core/src/request.d.ts +15 -0
- package/types/core/src/response.d.ts +29 -0
- package/types/core/src/server.d.ts +92 -0
- package/types/core/src/testClient.d.ts +29 -3
- package/types/core/src/testing.d.ts +16 -12
- package/types/core/src/types.d.ts +21 -9
- package/types/core/src/version.d.ts +11 -0
- package/types/core/src/websocketBackplane.d.ts +1 -1
- package/types/frond/src/engine.d.ts +10 -0
- package/types/orm/src/adapters/firebird.d.ts +61 -2
- package/types/orm/src/adapters/mongodb.d.ts +20 -0
- package/types/orm/src/adapters/mssql.d.ts +11 -0
- package/types/orm/src/adapters/mysql.d.ts +11 -0
- package/types/orm/src/adapters/odbc.d.ts +35 -4
- package/types/orm/src/adapters/postgres.d.ts +11 -0
- package/types/orm/src/adapters/sqlite.d.ts +23 -4
- package/types/orm/src/baseModel.d.ts +45 -25
- package/types/orm/src/cachedDatabase.d.ts +27 -1
- package/types/orm/src/database.d.ts +56 -6
- package/types/orm/src/index.d.ts +3 -2
- package/types/orm/src/migration.d.ts +23 -5
- package/types/orm/src/query.d.ts +3 -0
- package/types/orm/src/seeder.d.ts +15 -2
- package/types/orm/src/sqlTranslator.d.ts +17 -4
- package/types/orm/src/types.d.ts +75 -16
- package/packages/core/src/errorOverlay.test.ts +0 -122
package/CLAUDE.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# CLAUDE.md - AI Developer Guide for tina4-nodejs (v3.13.
|
|
1
|
+
# CLAUDE.md - AI Developer Guide for tina4-nodejs (v3.13.99)
|
|
2
2
|
|
|
3
3
|
> This file helps AI assistants (Claude, Copilot, Cursor, etc.) understand and work on this codebase effectively.
|
|
4
4
|
|
|
5
5
|
## What This Project Is
|
|
6
6
|
|
|
7
|
-
Tina4 for Node.js/TypeScript v3.13.
|
|
7
|
+
Tina4 for Node.js/TypeScript v3.13.99 - The Intelligent Native Application 4ramework. A convention-over-configuration structural paradigm. The developer writes TypeScript; Tina4 is invisible infrastructure.
|
|
8
8
|
|
|
9
9
|
The philosophy: zero ceremony, batteries included, file system as source of truth.
|
|
10
10
|
|
|
@@ -110,9 +110,9 @@ The HTTP foundation. Handles request/response lifecycle, route matching, middlew
|
|
|
110
110
|
- `types.ts` — All shared type definitions (`Tina4Request`, `Tina4Response`, `RouteHandler`, etc.)
|
|
111
111
|
- `events.ts` — Observer-pattern event system (`Events.on`, `emit`, `once`, `off`, `clear`)
|
|
112
112
|
- `ai.ts` — AI coding tool context installer (`AI_TOOLS`, `isInstalled`, `showMenu`, `installSelected`, `installAll`, `generateContext`)
|
|
113
|
-
- `errorOverlay.ts` — Rich debug error page for dev mode (`renderErrorOverlay`, `
|
|
113
|
+
- `errorOverlay.ts` — Rich debug error page for dev mode (`renderErrorOverlay`, `isDebugMode`)
|
|
114
114
|
- `htmlElement.ts` — Programmatic HTML builder (`HtmlElement`, `htmlElement`, `addHtmlHelpers`)
|
|
115
|
-
- `testing.ts` — Inline testing framework (`tests`, `
|
|
115
|
+
- `testing.ts` — Inline testing framework (`tests`, `expectEqual`, `expectRaises`, `runAll`)
|
|
116
116
|
- `fakeData.ts` — Core fake data generator (names, emails, addresses, UUIDs, etc.)
|
|
117
117
|
- `constants.ts` — HTTP status codes (`HTTP_OK`, `HTTP_NOT_FOUND`, etc.) and content types (`APPLICATION_JSON`, `TEXT_HTML`, etc.)
|
|
118
118
|
- `devAdmin.ts` — Dev toolbar (fixed bottom bar injected into HTML pages) and admin dashboard at `/_dev/`
|
|
@@ -157,7 +157,7 @@ Database layer with auto-CRUD generation, seeding, fake data, and SQL translatio
|
|
|
157
157
|
- `sqlTranslator.ts` — Cross-engine SQL translator (`SQLTranslator`) and TTL query cache (`QueryCache`)
|
|
158
158
|
- **Instance methods:** `save(): this|false` (fluent, false on failure), `delete()`, `forceDelete()`, `restore()`, `load(sql, params?, include?): boolean`, `validate(): string[]`, `toDict(include?)`, `toAssoc(include?)`, `toObject()`, `toArray(): unknown[]`, `toList()`, `toJson(include?)`, `hasOne(class, fk)`, `hasMany(class, fk, limit?, offset?)`, `belongsTo(class, fk)`
|
|
159
159
|
- **Static methods:** `find(id, include?)`, `findById(id, include?)`, `findOrFail(id)`, `create(data)`, `all(limit=100, offset=0, include?, orderBy?)`, `select(sql, params?, limit=100, offset=0)`, `selectOne(sql, params?, include?)`, `where(conditions, params?, limit=100, offset=0, include?, orderBy?)`, `count(conditions?, params?)`, `withTrashed(conditions?, params?, limit=100, offset=0)`, `scope(name, filterSql, params?)` (registers reusable method), `createTable()`, `query()`, `_processForeignKeys()`, `_applyFkRegistry()`
|
|
160
|
-
- **Foreign key auto-wire:** Declare a field with `type: "foreignKey"` and `references: "ModelName"` to auto-wire both `belongsTo` on the declaring model and `hasMany` on the referenced model. Optional `relatedName` overrides the has-many key. Models must be registered via `BaseModel.registerModel(name, class)` for name-based resolution. Example: `
|
|
160
|
+
- **Foreign key auto-wire (declarative, read-side-only):** Declare a field with `type: "foreignKey"` and `references: "ModelName"` to auto-wire both `belongsTo` on the declaring model and `hasMany` on the referenced model. Optional `relatedName` overrides the has-many key. Models must be registered via `BaseModel.registerModel(name, class)` for name-based resolution. Example: `author_id: { type: "foreignKey", references: "Author", relatedName: "posts" }` attaches LAZY accessors on both sides — `await post.author` (belongsTo) and `await author.posts` (hasMany) resolve on attribute access (async, cached), and `include: ["posts"]` on `find`/`all`/`where` eager-loads them in ONE query per relation. A soft-deleted child is excluded from traversal, and the has-many read is uncapped. The auto-wire emits NO DB-level FK / ON DELETE clause (REL-DEC-01, read-side-only): referential integrity is the migration/DDL's job, so deleting a parent does not cascade to children at the engine level. (Before 3.13.99 the declarative accessors did not attach and lazy load did not exist — only the imperative `post.belongsTo(Author, "author_id")` / `author.hasMany(Post, "author_id")` worked.)
|
|
161
161
|
- QueryBuilder supports `toMongo()` for generating MongoDB query documents from the same fluent API
|
|
162
162
|
- `getNextId(table: string, pkColumn?: string, generatorName?: string): Promise<number>` — Race-safe ID generation using atomic sequence table (`tina4_sequences`). SQLite/MySQL/MSSQL use `tina4_sequences` with atomic UPDATE+SELECT. PostgreSQL auto-creates sequences if missing. Firebird uses existing generators (unchanged).
|
|
163
163
|
|
|
@@ -321,7 +321,7 @@ Auto-generates OpenAPI 3.0.3 docs.
|
|
|
321
321
|
**Environment (read by `generator.ts` / `ui.ts`):**
|
|
322
322
|
- `TINA4_SWAGGER_ENABLED` - turns the `/swagger` UI + `/swagger/openapi.json` endpoints on/off (`ui.ts`). Explicit `true`/`false` wins; unset falls back to `TINA4_DEBUG`. Set `false` to DISABLE swagger in ANY environment (including dev); set `true` to expose it in production. This is the documented production on/off switch (wired for real in 3.13.40 - previously ignored). **This is how you disable swagger.**
|
|
323
323
|
- `TINA4_SWAGGER_SERVERS` - comma-separated list of server URLs for the OpenAPI `servers[]` block (multi-server / multi-environment). Falls back to `SWAGGER_DEV_URL`, else the framework default.
|
|
324
|
-
- `TINA4_SWAGGER_UI_CDN` - base URL for the Swagger UI assets (`swagger-ui.css` + `swagger-ui-bundle.js`). Defaults to the public CDN (`https://
|
|
324
|
+
- `TINA4_SWAGGER_UI_CDN` - base URL for the Swagger UI assets (`swagger-ui.css` + `swagger-ui-bundle.js`). Defaults to the public CDN (`https://cdn.jsdelivr.net/npm/swagger-ui-dist@5`, matching python/php/ruby); point it at a self-hosted mirror for air-gapped deployments.
|
|
325
325
|
- Info block: `TINA4_SWAGGER_TITLE`, `TINA4_SWAGGER_VERSION`, `TINA4_SWAGGER_DESCRIPTION`, `TINA4_SWAGGER_CONTACT_EMAIL`, `TINA4_SWAGGER_CONTACT_TEAM`, `TINA4_SWAGGER_CONTACT_URL`, `TINA4_SWAGGER_LICENSE`.
|
|
326
326
|
|
|
327
327
|
**Configurability (v3.13.42):**
|
|
@@ -409,21 +409,20 @@ const doc = generateContext("cursor");
|
|
|
409
409
|
Rich HTML error page for development mode. Uses Catppuccin Mocha colour palette, shows syntax-highlighted source context around the error line, stack trace with source preview, request details, and environment info. Controlled by `TINA4_DEBUG` env var.
|
|
410
410
|
|
|
411
411
|
```typescript
|
|
412
|
-
import { renderErrorOverlay,
|
|
412
|
+
import { renderErrorOverlay, isDebugMode } from "@tina4/core";
|
|
413
413
|
|
|
414
|
-
// In a route error handler:
|
|
414
|
+
// In a route error handler — dev only:
|
|
415
415
|
try {
|
|
416
416
|
await handler(req, res);
|
|
417
417
|
} catch (err) {
|
|
418
|
-
|
|
419
|
-
? renderErrorOverlay(err as Error, req) // full debug overlay
|
|
420
|
-
: renderProductionError(500, "Internal Server Error"); // safe production page
|
|
421
|
-
res.html(html, 500);
|
|
418
|
+
if (isDebugMode()) res.html(renderErrorOverlay(err as Error, req), 500);
|
|
422
419
|
}
|
|
423
420
|
|
|
424
421
|
// isDebugMode() returns true when TINA4_DEBUG is "true"
|
|
425
422
|
```
|
|
426
423
|
|
|
424
|
+
The overlay is dev-only (gated on `isDebugMode()`/`TINA4_DEBUG`). The production 500 is NOT rendered here — the server dispatch renders `errors/500.twig` with an empty `error_message` (CWE-209), so the exception detail stays in the server log only. Sensitive request fields (Authorization / Cookie / Set-Cookie headers and password-like body/param keys) are redacted even in the overlay, the frame count is capped, and the dispatch guards the render.
|
|
425
|
+
|
|
427
426
|
## Module: HtmlElement (`packages/core/src/htmlElement.ts`)
|
|
428
427
|
|
|
429
428
|
Programmatic HTML builder that avoids string concatenation. Three usage patterns: direct construction, builder-pattern functions, and helper injection.
|
|
@@ -461,16 +460,16 @@ Void tags (`br`, `hr`, `img`, `input`, `meta`, etc.) render without closing tags
|
|
|
461
460
|
|
|
462
461
|
## Module: Inline Testing (`packages/core/src/testing.ts`)
|
|
463
462
|
|
|
464
|
-
Attach test
|
|
463
|
+
Attach inline test expectations directly to functions with the `expect*` DESCRIPTOR builders — named apart from the xUnit `assert*` on `Tina4Test` (test.ts) so the two surfaces never collide. `npx tsx packages/cli/src/bin.ts test` (or `npx tina4nodejs test`) discovers `tests()`-decorated functions under `src/` and runs them with a real exit code (non-zero on any failure), then runs the file-based `test/` suite.
|
|
465
464
|
|
|
466
465
|
```typescript
|
|
467
|
-
import { tests,
|
|
466
|
+
import { tests, expectEqual, expectRaises, expectTrue, expectFalse, runAll, reset } from "@tina4/core";
|
|
468
467
|
|
|
469
|
-
// Decorate a function with inline
|
|
468
|
+
// Decorate a function with inline expectations
|
|
470
469
|
const add = tests(
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
470
|
+
expectEqual([5, 3], 8), // add(5, 3) === 8
|
|
471
|
+
expectEqual([0, 0], 0), // add(0, 0) === 0
|
|
472
|
+
expectRaises(Error, [null]), // add(null) throws Error
|
|
474
473
|
)(function add(a: number, b: number | null = null): number {
|
|
475
474
|
if (b === null) throw new Error("b required");
|
|
476
475
|
return a + b;
|
|
@@ -483,9 +482,9 @@ add(2, 3); // 5
|
|
|
483
482
|
const results = runAll({ quiet: false, failfast: false });
|
|
484
483
|
// → { passed: 3, failed: 0, errors: 0, details: [...] }
|
|
485
484
|
|
|
486
|
-
// Additional
|
|
487
|
-
|
|
488
|
-
|
|
485
|
+
// Additional expectation types
|
|
486
|
+
expectTrue([someArgs]); // result is truthy
|
|
487
|
+
expectFalse([someArgs]); // result is falsy
|
|
489
488
|
|
|
490
489
|
// Reset registry between test runs
|
|
491
490
|
reset();
|
|
@@ -823,7 +822,7 @@ bindDatabase(await createAdapterFromUrl("postgres://localhost:5432/analytics"),
|
|
|
823
822
|
// silently falling back to the default. (initDatabase / the internal setAdapter are unchanged.)
|
|
824
823
|
```
|
|
825
824
|
|
|
826
|
-
**Soft delete:** set `static softDelete = true`. Server boot (`syncModels()`)
|
|
825
|
+
**Soft delete:** set `static softDelete = true`. Server boot (`syncModels()`) AND `Model.createTable()` both add the `is_deleted` INTEGER column (0/1) automatically for a soft-delete model that does not declare it (SOFTDEL-DEC-02, 3.13.99). `delete()` flips the flag, `forceDelete()` removes the row, `restore()` clears it.
|
|
827
826
|
|
|
828
827
|
## Module: QueryBuilder (`packages/orm/src/queryBuilder.ts`)
|
|
829
828
|
|
|
@@ -887,7 +886,7 @@ syncModels(discoveredModels); // auto-create tables / add columns
|
|
|
887
886
|
- Files are applied in **numeric-prefix order** (`9_` before `10_` — a plain lexical sort misorders unpadded prefixes because `"10" < "9"`). A file with no numeric/timestamp prefix sorts **after** the numbered ones (lexically) and logs a `Log.warning` — its order is undefined.
|
|
888
887
|
- State is tracked in the `tina4_migration` table (auto-created per engine, canonical columns `id, migration_name VARCHAR(500) NOT NULL UNIQUE, description VARCHAR(500), batch INTEGER NOT NULL DEFAULT 1, executed_at VARCHAR(50) NOT NULL, passed INTEGER NOT NULL DEFAULT 1` - identical across all four frameworks). A migration is **applied** when a row exists for it with `passed = 1` (the applied-read is `WHERE passed = 1`). `migrate()` writes **only `passed = 1` rows**, and it does so **delete-before-insert**: on success it DELETEs any existing row for that `migration_name` and then INSERTs the fresh `passed = 1` row (the shared `recordApplied()` helper, mirroring the Python master's `_record_applied()`), so the table holds **at most one row per `migration_name`** - latest state wins. A FAILED migration file is rolled back and **no row is written** for it (it is NOT recorded as `passed = 0`; the record step is never reached), and the run STOPS (the `migrate()` summary's `failed[]` carries the failure). The public `recordMigration(name, batch, passed)` API can write a `passed = 0` row (and one may be carried over from an older table); any `passed = 0` row is treated as **not applied**. Because the success path deletes any existing row for the `migration_name` before the `passed = 1` INSERT, a leftover `passed = 0` row **re-applies cleanly** on the next `migrate()` - the stale row is superseded rather than colliding on the UNIQUE `migration_name` (that collision previously wedged a re-run). Fix the bad file and re-run.
|
|
889
888
|
- **Each migration FILE is wrapped in its own transaction.** On a failure the file rolls back and `migrate()` **STOPS** — later files are never applied on top of a missing earlier one (parity with Python/PHP/Ruby). Already-applied files stay applied. The explicit `tina4 migrate` CLI surfaces a non-empty `failed[]` as a non-zero exit; startup auto-migration logs it and the service still boots (see `TINA4_AUTO_MIGRATE` above).
|
|
890
|
-
- **Atomicity caveat:** per-file transactions are truly atomic
|
|
889
|
+
- **Atomicity caveat:** per-file transactions are truly atomic on engines with **transactional DDL (PostgreSQL, and SQLite)**. SQLite's DDL is transactional too (autocommit is off inside `adapterStartTransaction`), so a multi-statement migration that fails midway on SQLite rolls back cleanly, including any `CREATE TABLE` that already ran earlier in the same file — proven by `test/migrationContract.test.ts`. MySQL and Firebird **auto-commit DDL**, so the same failure on those two engines leaves earlier statements applied — keep one logical change per file there. `CREATE TABLE` and `ALTER TABLE ... ADD` are made idempotent on Firebird/MSSQL (existence-checked via `RDB$RELATION_FIELDS` / `tableExists`) so a re-run with a raw `CREATE`/`ADD` does not error "object already exists"; SQLite/MySQL/PostgreSQL support `IF NOT EXISTS` and are left to the engine. Only a genuine already-exists is skipped — every other error still raises.
|
|
891
890
|
- The stored-proc block delimiters (`$$ … $$` / `// … //`) are extracted before splitting, but a `//` preceded by a colon is **not** treated as a delimiter, so a URL (`https://…`) or any `://` literal inside a migration is never swallowed as an opaque block.
|
|
892
891
|
|
|
893
892
|
Schema sync (`syncModels`) runs alongside SQL migrations on boot.
|
|
@@ -1204,7 +1203,7 @@ import { Router } from "./router.js"; // .js even though the file is .ts
|
|
|
1204
1203
|
1. **Native `node:http`** — No framework dependency. Zero overhead.
|
|
1205
1204
|
2. **`tsx` for dev** — No build step needed during development. TypeScript runs directly.
|
|
1206
1205
|
3. **Convention-based models** — `static fields = {}` over decorators. No special TypeScript config needed.
|
|
1207
|
-
4. **CDN for Swagger UI** — Keeps install under 8MB. Single HTML file loads from
|
|
1206
|
+
4. **CDN for Swagger UI** — Keeps install under 8MB. Single HTML file loads from jsdelivr.net (the same default across all four frameworks).
|
|
1208
1207
|
5. **Browser reload, not process restart** — The `tina4` Rust CLI watches `src/`, `migrations/`, `.env` and POSTs `/__dev/api/reload` to the running server. The server stays up; only the browser reloads (via WS on `/__dev_reload`, polling fallback on `GET /__dev/api/mtime`). No ESM HMR gymnastics, no server restart, no framework-side watcher.
|
|
1209
1208
|
6. **SQLite default** — `node:sqlite` is synchronous and fast. Full adapters for Postgres, MySQL, MSSQL/SQL Server, and Firebird.
|
|
1210
1209
|
7. **CLI named `tina4nodejs`** (primary) with `tina4` as alias — So `npx tina4nodejs init` or `npx tina4 init` both work.
|
|
@@ -1385,7 +1384,7 @@ When adding new features, add a corresponding `test/<feature>.test.ts` file.
|
|
|
1385
1384
|
## v3 Features Summary
|
|
1386
1385
|
|
|
1387
1386
|
- **98 built-in features**, zero third-party dependencies
|
|
1388
|
-
- **7,537 tests** passing, 0 failed, **0 skipped** across 262 files (typecheck exit 0) - measured 2026-08-06 on the lab host (Ubuntu 24.04.4 LTS x86_64, Node v24.18.0) against live services with TINA4_REQUIRE_SERVICES=1. **Firebird
|
|
1387
|
+
- **7,537 tests** passing, 0 failed, **0 skipped** across 262 files (typecheck exit 0) - measured 2026-08-06 on the lab host (Ubuntu 24.04.4 LTS x86_64, Node v24.18.0) against live services with TINA4_REQUIRE_SERVICES=1. **Firebird runs on the lab but IS excluded from the require-services gate** - `test/_serviceGate.ts` lists `firebird` in `EXCLUDED_KEYWORDS` because GitHub CI provisions no Firebird, so a Firebird skip has to stay green there; the lab provisions a live Firebird 5 (`TINA4_TEST_FIREBIRD_URL`) and `test/firebird*.test.ts` (plus the feature-12 `test/firebirdProviderContract.test.ts`) runs against it. Those are two different things: real-Firebird coverage is enforced on the LAB, not by CI (FB-GATE-EXCLUDED). `node-firebird` is an optionalDependency of `@tina4/orm`, not a devDependency. The last six skips are closed, each by giving it the environment its condition needs rather than by relaxing what it asserts: the four missing-driver cases run in a child process that genuinely cannot resolve the driver (the source is copied out of the repo to a tree with no `node_modules` above it and run with plain `node` - `test/_driverlessTree.ts`, no resolver shim); the strict-mode write failure drops the effective uid so a 0400 file really denies root; and the RabbitMQ default-config round-trip clears the per-framework isolation overrides for that one case so "default" means the default. Every one was proven able to FAIL by mutating the code it guards.
|
|
1389
1388
|
- **Race-safe `getNextId()`** with atomic sequence table (`tina4_sequences`) for SQLite/MySQL/MSSQL; PostgreSQL auto-creates sequences
|
|
1390
1389
|
- **Frond template engine optimizations**: pre-compiled regexes, lazy loop context (copy-on-write), filter chain caching, path split caching, inline common filters (11-15% speedup)
|
|
1391
1390
|
- **Production server auto-detect**: `npx tina4nodejs serve --production` auto-uses cluster mode
|
|
@@ -1426,6 +1425,42 @@ Always read and follow the instructions in .claude/skills/tina4-developer-nodejs
|
|
|
1426
1425
|
## Tina4-js Frontend Skill
|
|
1427
1426
|
Always read and follow the instructions in .claude/skills/tina4-js/SKILL.md when working with tina4-js frontend code. Read its referenced files in .claude/skills/tina4-js/references/ as needed.
|
|
1428
1427
|
|
|
1428
|
+
## The Uniform Plan (cross-framework audit + consolidations)
|
|
1429
|
+
|
|
1430
|
+
Tina4 is one framework in four languages, so the feature-by-feature audit and the
|
|
1431
|
+
contract-fixture consolidations live in ONE framework-agnostic place, not per
|
|
1432
|
+
repo: **`tina4-documentation/plan/v3/`** (the `tina4-documentation` repo, `main`
|
|
1433
|
+
branch). Cite plan docs by repo-prefixed path.
|
|
1434
|
+
|
|
1435
|
+
- `plan/v3/98-feature-audit.md` - the master audit tracker: audit every feature,
|
|
1436
|
+
pick the best implementation (ADR-0004 "best implementation prevails"), park a
|
|
1437
|
+
plan. Planning first; implementation follows per feature.
|
|
1438
|
+
- `plan/v3/features/NNN-*.md` - one parked plan per feature: the chosen pattern,
|
|
1439
|
+
the methodology, and the tests to write.
|
|
1440
|
+
- `plan/v3/fixtures/*_contract.json` + `plan/v3/CONTRACT-MAP.md` - the executable
|
|
1441
|
+
consolidations. The SAME bytes drive the contract runners in all four
|
|
1442
|
+
frameworks, mapped feature -> fixture -> ADR -> proven/owed.
|
|
1443
|
+
- `plan/v3/DECISIONS.md` + `plan/v3/decisions/` - the ADR log. Consult it before
|
|
1444
|
+
changing any cross-framework contract, and supersede an ADR explicitly rather
|
|
1445
|
+
than silently. `MASTER-SPEC.md` is the feature source-of-truth, but its NUMBERS
|
|
1446
|
+
are stale; the fixtures, `CONTRACT-MAP.md`, and
|
|
1447
|
+
`scripts/audit-contract-fixtures.py` carry current truth.
|
|
1448
|
+
|
|
1449
|
+
This repo's own `plan/` holds LANGUAGE-SPECIFIC task plans (`PARITY.md`,
|
|
1450
|
+
`SCAFFOLDING.md`, `TESTS.md`, `AI-CONTEXT.md`, and per-task files). The
|
|
1451
|
+
CROSS-framework audit and consolidation work is the central plan above.
|
|
1452
|
+
|
|
1453
|
+
**To advance a feature (the update loop):** pick the next feature from the parity
|
|
1454
|
+
backlog -> MEASURE all four side by side (assume no parity; no mocks, real
|
|
1455
|
+
services on the lab) -> DECIDE the best implementation, writing or superseding an
|
|
1456
|
+
ADR when the contract changes -> write the executable
|
|
1457
|
+
`fixtures/<feature>_contract.json` and fix the divergences in ALL FOUR with named
|
|
1458
|
+
positive and negative regressions -> flip owed->proven, run
|
|
1459
|
+
`scripts/audit-contract-fixtures.py`, and update the `CONTRACT-MAP.md` row from
|
|
1460
|
+
those counts -> verify yourself at HEAD on the lab -> ship `feature/release<ver>`
|
|
1461
|
+
-> `v3` -> tag. Pushing plan edits into tina4-documentation is a MERGE, never a
|
|
1462
|
+
rebase (the subtree graft + the PDF-sync bot).
|
|
1463
|
+
|
|
1429
1464
|
## First Principle: Documentation Matches Code Reality
|
|
1430
1465
|
|
|
1431
1466
|
**This rule overrides everything else in this file.**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tina4-nodejs",
|
|
3
|
-
"version": "3.13.
|
|
3
|
+
"version": "3.13.99",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Tina4 for Node.js/TypeScript - 54 built-in features, zero dependencies",
|
|
6
6
|
"keywords": [
|
|
@@ -99,7 +99,6 @@
|
|
|
99
99
|
"@types/pg": "^8.20.0",
|
|
100
100
|
"esbuild": "^0.24.0",
|
|
101
101
|
"mongodb": "^6.0.0",
|
|
102
|
-
"node-firebird": "^2.14.3",
|
|
103
102
|
"tsx": "^4.19.0",
|
|
104
103
|
"typescript": "^5.7.0",
|
|
105
104
|
"vitest": "^4.1.9"
|