tina4-nodejs 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -371,7 +371,7 @@ export default class User {
|
|
|
371
371
|
};
|
|
372
372
|
}
|
|
373
373
|
|
|
374
|
-
// Auto-generates: GET/POST /api/users, GET/PUT/DELETE /api/users
|
|
374
|
+
// Auto-generates: GET/POST /api/users, GET/PUT/DELETE /api/users/{id}
|
|
375
375
|
// With filtering, sorting, pagination, and validation built in
|
|
376
376
|
```
|
|
377
377
|
|
|
@@ -409,10 +409,10 @@ get("/protected", async (request, response) => {
|
|
|
409
409
|
### JWT Authentication
|
|
410
410
|
|
|
411
411
|
```typescript
|
|
412
|
-
import {
|
|
412
|
+
import { getToken, validToken } from "tina4-nodejs";
|
|
413
413
|
|
|
414
|
-
const token =
|
|
415
|
-
const payload =
|
|
414
|
+
const token = getToken({userId: 42}, "your-secret");
|
|
415
|
+
const payload = validToken(token, "your-secret");
|
|
416
416
|
```
|
|
417
417
|
|
|
418
418
|
POST/PUT/PATCH/DELETE routes require `Authorization: Bearer <token>` by default. Use `noauth()` to make public, `secured()` to protect GET routes.
|
|
@@ -643,7 +643,7 @@ DATABASE_USERNAME=admin # Separate credentials for networked databa
|
|
|
643
643
|
DATABASE_PASSWORD=secret
|
|
644
644
|
TINA4_DEBUG=true # Enable dev toolbar, error overlay
|
|
645
645
|
TINA4_LOG_LEVEL=ALL # ALL, DEBUG, INFO, WARNING, ERROR
|
|
646
|
-
|
|
646
|
+
TINA4_LOCALE=en # en, fr, af, zh, ja, es
|
|
647
647
|
TINA4_SESSION_HANDLER=SessionFileHandler
|
|
648
648
|
SWAGGER_TITLE=My API
|
|
649
649
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tina4-nodejs",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "This is not a framework. Tina4 for Node.js/TypeScript — zero deps, 38 built-in features.",
|
|
6
6
|
"keywords": ["tina4", "framework", "web", "api", "orm", "graphql", "websocket", "typescript"],
|
|
@@ -10,11 +10,12 @@ export async function serveProject(options: ServeOptions): Promise<void> {
|
|
|
10
10
|
const cwd = process.cwd();
|
|
11
11
|
|
|
12
12
|
const routesDir = resolve(cwd, "src/routes");
|
|
13
|
+
const ormDir = resolve(cwd, "src/orm");
|
|
13
14
|
const modelsDir = resolve(cwd, "src/models");
|
|
14
15
|
const templatesDir = resolve(cwd, "src/templates");
|
|
15
16
|
const staticDir = resolve(cwd, "public");
|
|
16
17
|
|
|
17
|
-
if (!existsSync(routesDir) && !existsSync(modelsDir)) {
|
|
18
|
+
if (!existsSync(routesDir) && !existsSync(modelsDir) && !existsSync(ormDir)) {
|
|
18
19
|
console.error(" Error: Not a Tina4 project. Run this from a project created with 'tina4 init'.");
|
|
19
20
|
process.exit(1);
|
|
20
21
|
}
|
|
@@ -31,7 +32,8 @@ export async function serveProject(options: ServeOptions): Promise<void> {
|
|
|
31
32
|
});
|
|
32
33
|
|
|
33
34
|
// Watch for file changes and reload routes
|
|
34
|
-
const
|
|
35
|
+
const watchDirs = [routesDir, ormDir, modelsDir, templatesDir].filter((d) => existsSync(d));
|
|
36
|
+
const watcher = watchForChanges(watchDirs, async () => {
|
|
35
37
|
try {
|
|
36
38
|
const { discoverRoutes } = await import("@tina4/core");
|
|
37
39
|
const routes = await discoverRoutes(routesDir);
|
|
@@ -383,6 +383,7 @@ ${reset}
|
|
|
383
383
|
const base = config?.basePath ? resolve(config.basePath) : process.cwd();
|
|
384
384
|
const routesDir = resolve(base, config?.routesDir ?? "src/routes");
|
|
385
385
|
const modelsDir = resolve(base, config?.modelsDir ?? "src/models");
|
|
386
|
+
const ormDir = resolve(base, "src/orm");
|
|
386
387
|
const staticDir = resolve(base, config?.staticDir ?? "public");
|
|
387
388
|
const templatesDir = resolve(base, config?.templatesDir ?? "src/templates");
|
|
388
389
|
|
|
@@ -429,8 +430,10 @@ ${reset}
|
|
|
429
430
|
console.log(`\n No routes directory found at ${routesDir}`);
|
|
430
431
|
}
|
|
431
432
|
|
|
432
|
-
// Initialize ORM if models directory exists
|
|
433
|
-
|
|
433
|
+
// Initialize ORM if models directory exists (check src/orm/ first, then src/models/)
|
|
434
|
+
const hasOrmDir = existsSync(ormDir);
|
|
435
|
+
const hasModelsDir = existsSync(modelsDir);
|
|
436
|
+
if (hasOrmDir || hasModelsDir) {
|
|
434
437
|
try {
|
|
435
438
|
const orm = await import("@tina4/orm");
|
|
436
439
|
const dbConfig = config?.database ?? {};
|
|
@@ -439,7 +442,18 @@ ${reset}
|
|
|
439
442
|
path: dbConfig.path ?? "./data/tina4.db",
|
|
440
443
|
});
|
|
441
444
|
|
|
442
|
-
|
|
445
|
+
// Discover from src/orm/ (primary) and src/models/ (fallback), merge results
|
|
446
|
+
let models = hasOrmDir ? await orm.discoverModels(ormDir) : [];
|
|
447
|
+
if (hasModelsDir) {
|
|
448
|
+
const extraModels = await orm.discoverModels(modelsDir);
|
|
449
|
+
// Only add models not already discovered (src/orm/ takes priority)
|
|
450
|
+
const existingTables = new Set(models.map((m: any) => m.definition.tableName));
|
|
451
|
+
for (const m of extraModels) {
|
|
452
|
+
if (!existingTables.has(m.definition.tableName)) {
|
|
453
|
+
models.push(m);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
443
457
|
if (models.length > 0) {
|
|
444
458
|
console.log(`\n Models discovered:`);
|
|
445
459
|
orm.syncModels(models);
|
|
@@ -476,9 +490,16 @@ ${reset}
|
|
|
476
490
|
let modelDefs: Array<{ tableName: string; fields: Record<string, unknown> }> = [];
|
|
477
491
|
try {
|
|
478
492
|
const orm = await import("@tina4/orm");
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
493
|
+
const allModelDirs = [ormDir, modelsDir].filter((d) => existsSync(d));
|
|
494
|
+
const seenTables = new Set<string>();
|
|
495
|
+
for (const dir of allModelDirs) {
|
|
496
|
+
const discovered = await orm.discoverModels(dir);
|
|
497
|
+
for (const m of discovered) {
|
|
498
|
+
if (!seenTables.has(m.definition.tableName)) {
|
|
499
|
+
modelDefs.push(m.definition);
|
|
500
|
+
seenTables.add(m.definition.tableName);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
482
503
|
}
|
|
483
504
|
} catch {
|
|
484
505
|
// ORM not available, swagger will work without model schemas
|