tina4-nodejs 3.13.92 → 3.13.95

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 (193) hide show
  1. package/CLAUDE.md +170 -28
  2. package/README.md +2 -2
  3. package/package.json +13 -9
  4. package/packages/cli/dist/bin.js +33126 -30055
  5. package/packages/cli/src/commands/metrics.ts +17 -11
  6. package/packages/cli/src/commands/serve.ts +10 -9
  7. package/packages/core/dist/index.js +33062 -29908
  8. package/packages/core/src/ai.ts +7 -1
  9. package/packages/core/src/auth.ts +191 -39
  10. package/packages/core/src/background.ts +19 -19
  11. package/packages/core/src/cache.ts +492 -49
  12. package/packages/core/src/devAdmin.ts +79 -32
  13. package/packages/core/src/devMailbox.ts +20 -44
  14. package/packages/core/src/dispatchPipeline.ts +285 -0
  15. package/packages/core/src/dotenv.ts +185 -40
  16. package/packages/core/src/index.ts +7 -6
  17. package/packages/core/src/logger.ts +257 -36
  18. package/packages/core/src/mcp.ts +1 -1
  19. package/packages/core/src/messenger.ts +81 -13
  20. package/packages/core/src/metrics.ts +199 -961
  21. package/packages/core/src/middleware.ts +390 -123
  22. package/packages/core/src/queue.ts +188 -32
  23. package/packages/core/src/queueBackends/kafkaBackend.ts +109 -13
  24. package/packages/core/src/queueBackends/liteBackend.ts +13 -0
  25. package/packages/core/src/queueBackends/mongoBackend.ts +101 -9
  26. package/packages/core/src/queueBackends/rabbitmqBackend.ts +22 -4
  27. package/packages/core/src/rateLimiter.ts +10 -5
  28. package/packages/core/src/request.ts +6 -9
  29. package/packages/core/src/response.ts +46 -1
  30. package/packages/core/src/router.ts +29 -4
  31. package/packages/core/src/server.ts +751 -414
  32. package/packages/core/src/session.ts +244 -27
  33. package/packages/core/src/sessionHandlers/childError.ts +72 -0
  34. package/packages/core/src/sessionHandlers/databaseHandler.ts +338 -48
  35. package/packages/core/src/sessionHandlers/memcachedHandler.ts +181 -0
  36. package/packages/core/src/sessionHandlers/mongoClient.ts +293 -202
  37. package/packages/core/src/sessionHandlers/mongoHandler.ts +88 -8
  38. package/packages/core/src/sessionHandlers/respClient.ts +16 -143
  39. package/packages/core/src/sessionHandlers/sqlClient.ts +290 -0
  40. package/packages/core/src/sessionHandlers/syncBridge.ts +190 -0
  41. package/packages/core/src/sessionHandlers/syncSocket.ts +236 -0
  42. package/packages/core/src/testClient.ts +18 -5
  43. package/packages/core/src/trustedProxy.ts +249 -0
  44. package/packages/core/src/types.ts +29 -5
  45. package/packages/core/src/websocket.ts +66 -0
  46. package/packages/frond/dist/index.js +74 -31
  47. package/packages/frond/src/engine.ts +99 -33
  48. package/packages/orm/dist/index.js +26554 -23400
  49. package/packages/orm/src/adapters/firebird.ts +183 -56
  50. package/packages/orm/src/adapters/mongodb.ts +25 -4
  51. package/packages/orm/src/adapters/mssql.ts +114 -29
  52. package/packages/orm/src/adapters/mysql.ts +103 -40
  53. package/packages/orm/src/adapters/odbc.ts +44 -21
  54. package/packages/orm/src/adapters/postgres.ts +118 -26
  55. package/packages/orm/src/adapters/sqlDialect.ts +120 -0
  56. package/packages/orm/src/adapters/sqlite.ts +64 -25
  57. package/packages/orm/src/baseModel.ts +135 -40
  58. package/packages/orm/src/cachedDatabase.ts +43 -19
  59. package/packages/orm/src/connectTimeout.ts +265 -0
  60. package/packages/orm/src/database.ts +338 -198
  61. package/packages/orm/src/databaseResult.ts +65 -13
  62. package/packages/orm/src/databaseUrl.ts +484 -0
  63. package/packages/orm/src/docstore.ts +386 -145
  64. package/packages/orm/src/index.ts +13 -3
  65. package/packages/orm/src/migration.ts +18 -3
  66. package/packages/orm/src/queryBuilder.ts +38 -4
  67. package/packages/orm/src/sqlTranslator.ts +310 -4
  68. package/packages/orm/src/types.ts +15 -4
  69. package/types/cli/src/bin.d.ts +92 -0
  70. package/types/cli/src/commands/build.d.ts +2 -0
  71. package/types/cli/src/commands/generate.d.ts +47 -0
  72. package/types/cli/src/commands/init.d.ts +1 -0
  73. package/types/cli/src/commands/metrics.d.ts +6 -0
  74. package/types/cli/src/commands/migrate.d.ts +1 -0
  75. package/types/cli/src/commands/migrateCreate.d.ts +1 -0
  76. package/types/cli/src/commands/migrateRollback.d.ts +1 -0
  77. package/types/cli/src/commands/migrateStatus.d.ts +1 -0
  78. package/types/cli/src/commands/queue.d.ts +20 -0
  79. package/types/cli/src/commands/routes.d.ts +1 -0
  80. package/types/cli/src/commands/seed.d.ts +1 -0
  81. package/types/cli/src/commands/serve.d.ts +6 -0
  82. package/types/cli/src/commands/test.d.ts +1 -0
  83. package/types/core/src/ai.d.ts +64 -0
  84. package/types/core/src/api.d.ts +262 -0
  85. package/types/core/src/auth.d.ts +177 -0
  86. package/types/core/src/authGate.d.ts +20 -0
  87. package/types/core/src/background.d.ts +34 -0
  88. package/types/core/src/cache.d.ts +163 -0
  89. package/types/core/src/constants.d.ts +38 -0
  90. package/types/core/src/container.d.ts +44 -0
  91. package/types/core/src/context/chunker.d.ts +31 -0
  92. package/types/core/src/context/index.d.ts +93 -0
  93. package/types/core/src/devAdmin.d.ts +179 -0
  94. package/types/core/src/devMailbox.d.ts +54 -0
  95. package/types/core/src/dispatchPipeline.d.ts +117 -0
  96. package/types/core/src/docs.d.ts +141 -0
  97. package/types/core/src/docsAutoDiscovery.d.ts +6 -0
  98. package/types/core/src/dotenv.d.ts +87 -0
  99. package/types/core/src/env.d.ts +28 -0
  100. package/types/core/src/errorOverlay.d.ts +36 -0
  101. package/types/core/src/events.d.ts +75 -0
  102. package/types/core/src/fakeData.d.ts +55 -0
  103. package/types/core/src/feedback.d.ts +90 -0
  104. package/types/core/src/graphql.d.ts +207 -0
  105. package/types/core/src/health.d.ts +22 -0
  106. package/types/core/src/htmlElement.d.ts +75 -0
  107. package/types/core/src/i18n.d.ts +37 -0
  108. package/types/core/src/index.d.ts +92 -0
  109. package/types/core/src/job.d.ts +39 -0
  110. package/types/core/src/logger.d.ts +200 -0
  111. package/types/core/src/mcp.d.ts +248 -0
  112. package/types/core/src/messenger.d.ts +191 -0
  113. package/types/core/src/metrics.d.ts +41 -0
  114. package/types/core/src/middleware.d.ts +330 -0
  115. package/types/core/src/mqtt.d.ts +257 -0
  116. package/types/core/src/mqttMessage.d.ts +67 -0
  117. package/types/core/src/plan.d.ts +96 -0
  118. package/types/core/src/projectIndex.d.ts +56 -0
  119. package/types/core/src/queue.d.ts +268 -0
  120. package/types/core/src/queueBackends/kafkaBackend.d.ts +117 -0
  121. package/types/core/src/queueBackends/liteBackend.d.ts +128 -0
  122. package/types/core/src/queueBackends/mongoBackend.d.ts +119 -0
  123. package/types/core/src/queueBackends/rabbitmqBackend.d.ts +55 -0
  124. package/types/core/src/rateLimiter.d.ts +49 -0
  125. package/types/core/src/request.d.ts +25 -0
  126. package/types/core/src/response.d.ts +28 -0
  127. package/types/core/src/routeDiscovery.d.ts +12 -0
  128. package/types/core/src/router.d.ts +366 -0
  129. package/types/core/src/scss.d.ts +19 -0
  130. package/types/core/src/server.d.ts +146 -0
  131. package/types/core/src/service.d.ts +115 -0
  132. package/types/core/src/session.d.ts +341 -0
  133. package/types/core/src/sessionHandlers/childError.d.ts +34 -0
  134. package/types/core/src/sessionHandlers/databaseHandler.d.ts +97 -0
  135. package/types/core/src/sessionHandlers/memcachedHandler.d.ts +60 -0
  136. package/types/core/src/sessionHandlers/mongoClient.d.ts +35 -0
  137. package/types/core/src/sessionHandlers/mongoHandler.d.ts +109 -0
  138. package/types/core/src/sessionHandlers/respClient.d.ts +22 -0
  139. package/types/core/src/sessionHandlers/sqlClient.d.ts +39 -0
  140. package/types/core/src/sessionHandlers/syncBridge.d.ts +91 -0
  141. package/types/core/src/sessionHandlers/syncSocket.d.ts +49 -0
  142. package/types/core/src/sessionHandlers/valkeyHandler.d.ts +65 -0
  143. package/types/core/src/static.d.ts +2 -0
  144. package/types/core/src/test.d.ts +94 -0
  145. package/types/core/src/testClient.d.ts +36 -0
  146. package/types/core/src/testing.d.ts +58 -0
  147. package/types/core/src/trustedProxy.d.ts +44 -0
  148. package/types/core/src/types.d.ts +242 -0
  149. package/types/core/src/validator.d.ts +52 -0
  150. package/types/core/src/websocket.d.ts +402 -0
  151. package/types/core/src/websocketBackplane.d.ts +166 -0
  152. package/types/core/src/websocketConnection.d.ts +54 -0
  153. package/types/core/src/wsdl.d.ts +101 -0
  154. package/types/frond/src/engine.d.ts +263 -0
  155. package/types/frond/src/index.d.ts +2 -0
  156. package/types/orm/src/adapters/firebird.d.ts +183 -0
  157. package/types/orm/src/adapters/mongodb.d.ts +81 -0
  158. package/types/orm/src/adapters/mssql.d.ts +77 -0
  159. package/types/orm/src/adapters/mysql.d.ts +67 -0
  160. package/types/orm/src/adapters/odbc.d.ts +94 -0
  161. package/types/orm/src/adapters/postgres.d.ts +86 -0
  162. package/types/orm/src/adapters/sqlDialect.d.ts +71 -0
  163. package/types/orm/src/adapters/sqlite.d.ts +68 -0
  164. package/types/orm/src/autoCrud.d.ts +73 -0
  165. package/types/orm/src/baseModel.d.ts +427 -0
  166. package/types/orm/src/cachedDatabase.d.ts +190 -0
  167. package/types/orm/src/connectTimeout.d.ts +100 -0
  168. package/types/orm/src/database.d.ts +655 -0
  169. package/types/orm/src/databaseResult.d.ts +109 -0
  170. package/types/orm/src/databaseUrl.d.ts +125 -0
  171. package/types/orm/src/docstore.d.ts +241 -0
  172. package/types/orm/src/fakeData.d.ts +22 -0
  173. package/types/orm/src/index.d.ts +43 -0
  174. package/types/orm/src/migration.d.ts +275 -0
  175. package/types/orm/src/model.d.ts +7 -0
  176. package/types/orm/src/query.d.ts +14 -0
  177. package/types/orm/src/queryBuilder.d.ts +193 -0
  178. package/types/orm/src/realtime/index.d.ts +7 -0
  179. package/types/orm/src/realtime/models/attachment.d.ts +43 -0
  180. package/types/orm/src/realtime/models/channel.d.ts +32 -0
  181. package/types/orm/src/realtime/models/channelMember.d.ts +32 -0
  182. package/types/orm/src/realtime/models/message.d.ts +36 -0
  183. package/types/orm/src/realtime/models/workspace.d.ts +26 -0
  184. package/types/orm/src/realtime/realtime.d.ts +24 -0
  185. package/types/orm/src/realtime/storage.d.ts +61 -0
  186. package/types/orm/src/seeder.d.ts +118 -0
  187. package/types/orm/src/sqlTranslator.d.ts +258 -0
  188. package/types/orm/src/types.d.ts +148 -0
  189. package/types/orm/src/validation.d.ts +6 -0
  190. package/types/swagger/src/generator.d.ts +46 -0
  191. package/types/swagger/src/index.d.ts +2 -0
  192. package/types/swagger/src/ui.d.ts +11 -0
  193. package/packages/core/src/sessionHandlers/redisHandler.ts +0 -206
@@ -0,0 +1,36 @@
1
+ import { Router } from "./router.js";
2
+ export declare class TestResponse {
3
+ readonly status: number;
4
+ readonly body: string;
5
+ readonly headers: Record<string, string>;
6
+ readonly contentType: string;
7
+ constructor(statusCode: number, headers: Record<string, string>, body: string);
8
+ /** Parse body as JSON. */
9
+ json(): unknown;
10
+ /** Return body as a string. */
11
+ text(): string;
12
+ toString(): string;
13
+ }
14
+ export interface RequestOptions {
15
+ json?: Record<string, unknown> | unknown[];
16
+ body?: string;
17
+ headers?: Record<string, string>;
18
+ }
19
+ export declare class TestClient {
20
+ private router;
21
+ constructor(router?: Router);
22
+ /** Send a GET request. */
23
+ get(path: string, options?: RequestOptions): Promise<TestResponse>;
24
+ /** Send a POST request. */
25
+ post(path: string, options?: RequestOptions): Promise<TestResponse>;
26
+ /** Send a PUT request. */
27
+ put(path: string, options?: RequestOptions): Promise<TestResponse>;
28
+ /** Send a PATCH request. */
29
+ patch(path: string, options?: RequestOptions): Promise<TestResponse>;
30
+ /** Send a DELETE request. */
31
+ delete(path: string, options?: RequestOptions): Promise<TestResponse>;
32
+ /** Build a mock request, match the route, execute the handler. */
33
+ private _request;
34
+ /** Gather the captured status/headers/body into a TestResponse and free the socket. */
35
+ private _collect;
36
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Tina4 Node.js — Inline testing framework.
3
+ *
4
+ * Attach test assertions to functions and run them all at once.
5
+ *
6
+ * import { tests, assertEqual, assertRaises, runAll } from "./testing.js";
7
+ *
8
+ * const add = tests(
9
+ * assertEqual([5, 3], 8),
10
+ * assertRaises(Error, [null]),
11
+ * )(function add(a: number, b: number | null = null): number {
12
+ * if (b === null) throw new Error("b required");
13
+ * return a + b;
14
+ * });
15
+ *
16
+ * runAll();
17
+ */
18
+ interface Assertion {
19
+ type: "equal" | "raises" | "true" | "false";
20
+ args: unknown[];
21
+ expected?: unknown;
22
+ exception?: new (...a: unknown[]) => Error;
23
+ }
24
+ interface TestResults {
25
+ passed: number;
26
+ failed: number;
27
+ errors: number;
28
+ details: Array<{
29
+ name: string;
30
+ status: string;
31
+ message?: string;
32
+ }>;
33
+ }
34
+ /** Assert that calling the function with `args` returns `expected`. */
35
+ export declare function assertEqual(args: unknown[], expected: unknown): Assertion;
36
+ /** Assert that calling the function with `args` throws an instance of `errorClass`. */
37
+ export declare function assertRaises(errorClass: new (...a: unknown[]) => Error, args: unknown[]): Assertion;
38
+ /** Assert that calling the function with `args` returns a truthy value. */
39
+ export declare function assertTrue(args: unknown[]): Assertion;
40
+ /** Assert that calling the function with `args` returns a falsy value. */
41
+ export declare function assertFalse(args: unknown[]): Assertion;
42
+ /**
43
+ * Attach inline test assertions to a function.
44
+ *
45
+ * Returns a wrapper that accepts the function and registers it,
46
+ * then returns the original function unchanged.
47
+ *
48
+ * const myFn = tests(assertEqual([1,2], 3))(function myFn(a,b) { return a+b; });
49
+ */
50
+ export declare function tests(...assertions: Assertion[]): <T extends (...args: unknown[]) => unknown>(fn: T) => T;
51
+ /** Run all registered tests. Returns results summary. */
52
+ export declare function runAll(options?: {
53
+ quiet?: boolean;
54
+ failfast?: boolean;
55
+ }): TestResults;
56
+ /** Reset the test registry (useful between test runs). */
57
+ export declare function reset(): void;
58
+ export {};
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Which upstream hops are allowed to speak for a client (ADR-0019).
3
+ *
4
+ * X-Forwarded-For is written by whoever sends it. Reading it unconditionally
5
+ * lets any client choose its own rate-limit bucket, and - worse - choose
6
+ * SOMEONE ELSE'S, which is a starvation primitive against a third party. So
7
+ * the forwarding headers are believed only when the raw socket peer is a proxy
8
+ * the operator has explicitly declared.
9
+ *
10
+ * Configured by TINA4_TRUSTED_PROXIES: comma-separated exact addresses and/or
11
+ * CIDR ranges, IPv4 and IPv6, e.g. "10.0.0.0/8, 192.168.1.5, ::1, fd00::/8".
12
+ * Empty or unset means trust NOTHING, which is the secure default.
13
+ *
14
+ * Zero-dependency: node: has no CIDR matcher, so the packing and prefix
15
+ * comparison are done here over plain byte arrays.
16
+ */
17
+ /** [packed network address, prefix bits] */
18
+ type Network = [Uint8Array, number];
19
+ /**
20
+ * Pack an address to its bytes, unmapping IPv4-in-IPv6.
21
+ *
22
+ * A peer arriving as ::ffff:10.0.0.1 must match an allow-list entry of
23
+ * 10.0.0.0/8 - dual-stack listeners hand out the mapped form routinely, and
24
+ * Node's socket.remoteAddress is a common source of it.
25
+ */
26
+ export declare function packAddress(value: string): Uint8Array | null;
27
+ /**
28
+ * The configured trusted-proxy networks, parsed once per distinct config value.
29
+ */
30
+ export declare function trustedProxyNetworks(): Network[];
31
+ /** Is this address a configured trusted proxy? */
32
+ export declare function isTrustedProxy(address: string): boolean;
33
+ /** Reset the parsed cache. Test hook - config normally changes only at boot. */
34
+ export declare function resetTrustedProxyCache(): void;
35
+ /**
36
+ * Resolve the client IP, honouring forwarding headers ONLY behind a trusted proxy.
37
+ *
38
+ * Within the chain the RIGHTMOST entry that is not itself a trusted proxy wins.
39
+ * Taking the leftmost would be no safer than trusting the header outright: a
40
+ * client can prepend its own hop, and the proxy appends rather than replaces.
41
+ * This is the algorithm Rack uses (Rack::Request#ip).
42
+ */
43
+ export declare function resolveClientIp(headers: Record<string, string | string[] | undefined>, peer: string): string;
44
+ export {};
@@ -0,0 +1,242 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ export interface UploadedFile {
3
+ fieldName: string;
4
+ filename: string;
5
+ type: string;
6
+ content: Buffer;
7
+ size: number;
8
+ }
9
+ export interface Tina4Session {
10
+ get(key: string, defaultValue?: unknown): unknown;
11
+ set(key: string, value: unknown): void;
12
+ delete(key: string): void;
13
+ clear(): void;
14
+ save(): void;
15
+ readonly id: string;
16
+ }
17
+ export interface Tina4Request extends IncomingMessage {
18
+ /**
19
+ * Path params. Typed params arrive coerced: `{id:int}`/`{id:integer}` and
20
+ * `{p:float}`/`{p:number}` are JS `number`s; every other type and untyped
21
+ * `{id}` stay `string` (parity with Python/PHP/Ruby).
22
+ */
23
+ params: Record<string, string | number>;
24
+ query: Record<string, string>;
25
+ /**
26
+ * Request path only — no query string. Matches `request.path` in
27
+ * Python/PHP/Ruby. Example: `/users/42`.
28
+ */
29
+ path: string;
30
+ /**
31
+ * Raw query string with no leading "?". Matches `request.query_string`
32
+ * (Python/Ruby) and `request.queryString` (PHP). Example: `"page=2"`.
33
+ */
34
+ queryString: string;
35
+ /**
36
+ * Full absolute URL — `scheme://host[:port]/path[?query]`.
37
+ * Honours X-Forwarded-Proto / X-Forwarded-Host. Matches PHP/Ruby/Python parity.
38
+ *
39
+ * Note: this overrides Node's native `IncomingMessage.url` (which contains
40
+ * only path+query). Inside Tina4 handlers, `req.url` is always the full URL.
41
+ */
42
+ url: string;
43
+ body: unknown;
44
+ ip: string;
45
+ /**
46
+ * Raw socket peer address - NEVER honours X-Forwarded-For (which any
47
+ * caller can spoof), so it can be trusted for security decisions.
48
+ * Empty for in-process / synthetic requests. Parity with Python's
49
+ * request.remote_ip and PHP's Request::$remoteIp.
50
+ */
51
+ remoteIp: string;
52
+ files: Record<string, UploadedFile | UploadedFile[]>;
53
+ cookies: Record<string, string>;
54
+ contentType: string;
55
+ /**
56
+ * NULL when the session backend was unusable for this request (ADR-0021).
57
+ * The request path logs the failure and degrades rather than 500-ing, so a
58
+ * request really can arrive without a session and the type has to say so -
59
+ * `req.session?.get(...)`. Parity with Python, where `request.session` is
60
+ * `None` on the same path.
61
+ */
62
+ session: Tina4Session | null;
63
+ user?: Record<string, unknown>;
64
+ /** Get a specific header value by name (case-insensitive). */
65
+ header(name: string): string | undefined;
66
+ /** Extract the Bearer token from the Authorization header. */
67
+ bearerToken(): string | null;
68
+ /**
69
+ * Get a parameter by key from merged params (route + query). Route params
70
+ * may be coerced numbers (e.g. `{id:int}`); query params are always strings.
71
+ */
72
+ param(key: string, defaultValue?: string | number): string | number | undefined;
73
+ /** Parse the request body based on content type. */
74
+ parseBody(): Promise<void>;
75
+ }
76
+ export interface CookieOptions {
77
+ maxAge?: number;
78
+ expires?: Date;
79
+ path?: string;
80
+ domain?: string;
81
+ secure?: boolean;
82
+ httpOnly?: boolean;
83
+ sameSite?: "Strict" | "Lax" | "None";
84
+ }
85
+ export interface Tina4ResponseMethods {
86
+ json(data: unknown, status?: number): Tina4Response;
87
+ html(content: string, status?: number): Tina4Response;
88
+ text(content: string, status?: number): Tina4Response;
89
+ xml(content: string, status?: number): Tina4Response;
90
+ status(code: number): Tina4Response;
91
+ header(name: string, value: string | number | readonly string[]): Tina4Response;
92
+ addHeader(name: string, value: string): void;
93
+ send(data: unknown, statusCode?: number, contentType?: string): Tina4Response;
94
+ redirect(url: string, code?: number): Tina4Response;
95
+ cookie(name: string, value: string, options?: CookieOptions): Tina4Response;
96
+ clearCookie(name: string, options?: CookieOptions): Tina4Response;
97
+ file(path: string, options?: {
98
+ download?: boolean;
99
+ contentType?: string;
100
+ }): Tina4Response;
101
+ error(code: string, message: string, status?: number): Tina4Response;
102
+ render(template: string, data?: Record<string, unknown>, status?: number, templateDir?: string): Promise<Tina4Response>;
103
+ /** Stream response from an async generator (SSE or chunked). */
104
+ stream(source: AsyncIterable<string | Buffer>, contentType?: string): Promise<Tina4Response>;
105
+ /** The underlying ServerResponse for advanced use */
106
+ raw: ServerResponse;
107
+ }
108
+ /**
109
+ * Tina4 Response — callable AND has methods.
110
+ *
111
+ * return response({ users: [] }); // Auto-JSON
112
+ * return response({ ok: true }, HTTP_CREATED); // JSON with status
113
+ * return response("<h1>Hi</h1>"); // Auto-HTML
114
+ * return response("Not found", HTTP_NOT_FOUND); // Plain text
115
+ * return response(data, HTTP_OK, APPLICATION_JSON); // Explicit
116
+ * return response.json(data, 201); // Explicit method
117
+ * return response.redirect("/login"); // Special case
118
+ */
119
+ export type Tina4Response = ((data?: unknown, statusCode?: number, contentType?: string) => Tina4Response) & Tina4ResponseMethods;
120
+ export type RouteHandler = (req: Tina4Request, res: Tina4Response) => Tina4Response | void | Promise<Tina4Response | void>;
121
+ export interface RouteDefinition {
122
+ method: string;
123
+ pattern: string;
124
+ handler: RouteHandler;
125
+ filePath?: string;
126
+ meta?: RouteMeta;
127
+ /** Middleware functions and/or string specs (e.g. "ResponseCache:300"). */
128
+ middlewares?: MiddlewareSpec[];
129
+ /** Template file to render when handler returns a plain object */
130
+ template?: string;
131
+ /** Whether this route requires bearer-token authentication */
132
+ secure?: boolean;
133
+ /** Whether this route's response should be cached */
134
+ cached?: boolean;
135
+ /** Opt out of secure-by-default auth on write routes */
136
+ noAuth?: boolean;
137
+ }
138
+ export interface RouteMeta {
139
+ summary?: string;
140
+ description?: string;
141
+ tags?: string[];
142
+ responses?: Record<string, {
143
+ description: string;
144
+ }>;
145
+ /** Request-body example surfaced in the OpenAPI requestBody. */
146
+ example?: unknown;
147
+ /** Marks the operation deprecated in the spec. */
148
+ deprecated?: boolean;
149
+ /**
150
+ * Per-route security requirement (v3.13.42). Overrides the default scheme.
151
+ * Accepted forms (normalized by the generator into a security-requirement list):
152
+ * "bearerAuth" -> [{ bearerAuth: [] }]
153
+ * "public" | "none" | [] -> [] (explicitly no auth)
154
+ * { apiKeyAuth: [] } -> [{ apiKeyAuth: [] }] (AND within one map)
155
+ * [{ oauth2: ["read"] }, { bearerAuth: [] }] -> verbatim (OR across maps)
156
+ */
157
+ security?: string | string[] | Record<string, string[]> | Array<Record<string, string[]>>;
158
+ /** Scopes for a single named scheme passed as `security: "oauth2"` + `scopes: [...]`. */
159
+ scopes?: string[];
160
+ /**
161
+ * Reference a registered component schema as the request body (v3.13.42):
162
+ * requestSchema: "CreateUser" OR { name: "CreateUser", contentType: "application/json" }
163
+ * Emits `$ref: #/components/schemas/CreateUser` and lands the schema in components.schemas.
164
+ */
165
+ requestSchema?: string | {
166
+ name: string;
167
+ contentType?: string;
168
+ };
169
+ /**
170
+ * Reference registered component schemas as response bodies, keyed by status (v3.13.42):
171
+ * responseSchemas: { 200: "User", 201: { name: "User", isList: true } }
172
+ */
173
+ responseSchemas?: Record<string, string | {
174
+ name: string;
175
+ isList?: boolean;
176
+ }>;
177
+ }
178
+ export interface Tina4Config {
179
+ port?: number;
180
+ host?: string;
181
+ /** Base directory for the project. When set, routesDir, modelsDir, templatesDir,
182
+ * and staticDir are resolved relative to this path instead of process.cwd(). */
183
+ basePath?: string;
184
+ routesDir?: string;
185
+ modelsDir?: string;
186
+ templatesDir?: string;
187
+ staticDir?: string;
188
+ database?: {
189
+ type?: "sqlite" | "postgres" | "mysql";
190
+ path?: string;
191
+ url?: string;
192
+ };
193
+ }
194
+ export type Middleware = (req: Tina4Request, res: Tina4Response, next: () => void) => void | Promise<void>;
195
+ /**
196
+ * A class-based middleware: static `beforeX` / `afterX` hooks discovered by
197
+ * `MiddlewareRunner`. The hooks are a NAMING CONVENTION, not an interface —
198
+ * exactly as in Python/PHP/Ruby — so this is deliberately just "a class".
199
+ */
200
+ export type MiddlewareClass = abstract new (...args: never[]) => unknown;
201
+ /**
202
+ * A route middleware entry: a middleware function, a middleware CLASS, or a
203
+ * string spec resolved by the router to a built-in middleware.
204
+ *
205
+ * String forms (parity with Python/PHP/Ruby):
206
+ * "ResponseCache" → responseCache() with the default/env TTL
207
+ * "ResponseCache:300" → responseCache({ ttl: 300 })
208
+ *
209
+ * The router resolves string specs to middleware functions when the route
210
+ * runs, so callers can register a response-cache middleware without importing
211
+ * `responseCache`. A CLASS runs its beforeX/afterX hooks through the same
212
+ * `MiddlewareRunner` as global middleware — Python and PHP already ran
213
+ * per-route class hooks; Node used to invoke every spec as `mw(req, res, next)`
214
+ * and a class was therefore inert.
215
+ */
216
+ export type MiddlewareSpec = Middleware | MiddlewareClass | string;
217
+ /**
218
+ * Handler for WebSocket routes.
219
+ * connection — object with send/broadcast/close methods and route params.
220
+ * event — one of "open", "message", or "close".
221
+ * data — the incoming text message (only present for "message" events).
222
+ */
223
+ export type WebSocketRouteHandler = ((connection: import("./websocketConnection.js").WebSocketConnection, event: "open" | "message" | "close", data: string) => void | Promise<void>) & {
224
+ /**
225
+ * Decorator-style secured flag — mirrors Python's `handler._secured`. When
226
+ * truthy the WS route requires a valid JWT on the upgrade. `Router.websocket`
227
+ * reads this into the route's `authRequired`. Lets a handler be marked
228
+ * secured in EITHER order (before or after registration).
229
+ */
230
+ _secured?: boolean;
231
+ };
232
+ export interface WebSocketRouteDefinition {
233
+ pattern: string;
234
+ handler: WebSocketRouteHandler;
235
+ /**
236
+ * True when this WS route requires a valid JWT on the upgrade. Public by
237
+ * default (mirrors GET). Set imperatively via `Router.websocket(path, fn,
238
+ * { secured: true })` / the returned `.secure()`, or by a `_secured` flag on
239
+ * the handler (decorator style).
240
+ */
241
+ authRequired?: boolean;
242
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Tina4 Validator — Request body validation.
3
+ *
4
+ * Usage:
5
+ * import { Validator } from "@tina4/core";
6
+ *
7
+ * const validator = new Validator(req.body as Record<string, unknown>);
8
+ * validator.required("name", "email");
9
+ * validator.email("email");
10
+ * validator.minLength("name", 2);
11
+ * validator.maxLength("name", 100);
12
+ * validator.integer("age");
13
+ * validator.min("age", 0);
14
+ * validator.max("age", 150);
15
+ * validator.inList("role", ["admin", "user", "guest"]);
16
+ * validator.regex("phone", /^\+?[\d\s\-]+$/);
17
+ *
18
+ * if (!validator.isValid()) {
19
+ * return res.error("VALIDATION_FAILED", validator.errors()[0].message, 400);
20
+ * }
21
+ */
22
+ export interface ValidationError {
23
+ field: string;
24
+ message: string;
25
+ }
26
+ export declare class Validator {
27
+ private data;
28
+ private validationErrors;
29
+ constructor(data?: Record<string, unknown> | null);
30
+ /** Check that one or more fields are present and non-empty. */
31
+ required(...fields: string[]): this;
32
+ /** Check that a field contains a valid email address. */
33
+ email(field: string): this;
34
+ /** Check that a string field has at least `length` characters. */
35
+ minLength(field: string, length: number): this;
36
+ /** Check that a string field has at most `length` characters. */
37
+ maxLength(field: string, length: number): this;
38
+ /** Check that a field is an integer (or can be parsed as one). */
39
+ integer(field: string): this;
40
+ /** Check that a numeric field is >= `minimum`. */
41
+ min(field: string, minimum: number): this;
42
+ /** Check that a numeric field is <= `maximum`. */
43
+ max(field: string, maximum: number): this;
44
+ /** Check that a field's value is one of the allowed values. */
45
+ inList(field: string, allowed: unknown[]): this;
46
+ /** Check that a field matches a regular expression. */
47
+ regex(field: string, pattern: RegExp | string): this;
48
+ /** Return the list of validation errors (empty if valid). */
49
+ errors(): ValidationError[];
50
+ /** Return true if no validation errors have been recorded. */
51
+ isValid(): boolean;
52
+ }