tina4-nodejs 3.13.91 → 3.13.94

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 (135) hide show
  1. package/CLAUDE.md +16 -3
  2. package/README.md +1 -1
  3. package/package.json +12 -9
  4. package/packages/cli/dist/bin.js +1312 -987
  5. package/packages/core/dist/index.js +1312 -987
  6. package/packages/core/src/auth.ts +141 -21
  7. package/packages/core/src/devMailbox.ts +20 -44
  8. package/packages/core/src/index.ts +2 -2
  9. package/packages/core/src/messenger.ts +72 -0
  10. package/packages/core/src/queueBackends/kafkaBackend.ts +108 -12
  11. package/packages/core/src/sessionHandlers/childError.ts +72 -0
  12. package/packages/core/src/sessionHandlers/mongoClient.ts +9 -3
  13. package/packages/core/src/sessionHandlers/redisHandler.ts +18 -5
  14. package/packages/core/src/sessionHandlers/respClient.ts +5 -1
  15. package/packages/frond/dist/index.js +74 -31
  16. package/packages/frond/src/engine.ts +99 -33
  17. package/packages/orm/dist/index.js +3102 -2777
  18. package/packages/orm/src/adapters/sqlite.ts +4 -1
  19. package/packages/orm/src/database.ts +108 -8
  20. package/types/cli/src/bin.d.ts +92 -0
  21. package/types/cli/src/commands/build.d.ts +2 -0
  22. package/types/cli/src/commands/generate.d.ts +47 -0
  23. package/types/cli/src/commands/init.d.ts +1 -0
  24. package/types/cli/src/commands/metrics.d.ts +6 -0
  25. package/types/cli/src/commands/migrate.d.ts +1 -0
  26. package/types/cli/src/commands/migrateCreate.d.ts +1 -0
  27. package/types/cli/src/commands/migrateRollback.d.ts +1 -0
  28. package/types/cli/src/commands/migrateStatus.d.ts +1 -0
  29. package/types/cli/src/commands/queue.d.ts +20 -0
  30. package/types/cli/src/commands/routes.d.ts +1 -0
  31. package/types/cli/src/commands/seed.d.ts +1 -0
  32. package/types/cli/src/commands/serve.d.ts +6 -0
  33. package/types/cli/src/commands/test.d.ts +1 -0
  34. package/types/core/src/ai.d.ts +64 -0
  35. package/types/core/src/api.d.ts +262 -0
  36. package/types/core/src/auth.d.ts +154 -0
  37. package/types/core/src/authGate.d.ts +20 -0
  38. package/types/core/src/background.d.ts +34 -0
  39. package/types/core/src/cache.d.ts +160 -0
  40. package/types/core/src/constants.d.ts +38 -0
  41. package/types/core/src/container.d.ts +44 -0
  42. package/types/core/src/context/chunker.d.ts +31 -0
  43. package/types/core/src/context/index.d.ts +93 -0
  44. package/types/core/src/devAdmin.d.ts +179 -0
  45. package/types/core/src/devMailbox.d.ts +54 -0
  46. package/types/core/src/docs.d.ts +141 -0
  47. package/types/core/src/docsAutoDiscovery.d.ts +6 -0
  48. package/types/core/src/dotenv.d.ts +65 -0
  49. package/types/core/src/env.d.ts +28 -0
  50. package/types/core/src/errorOverlay.d.ts +36 -0
  51. package/types/core/src/events.d.ts +75 -0
  52. package/types/core/src/fakeData.d.ts +55 -0
  53. package/types/core/src/feedback.d.ts +90 -0
  54. package/types/core/src/graphql.d.ts +207 -0
  55. package/types/core/src/health.d.ts +22 -0
  56. package/types/core/src/htmlElement.d.ts +75 -0
  57. package/types/core/src/i18n.d.ts +37 -0
  58. package/types/core/src/index.d.ts +93 -0
  59. package/types/core/src/job.d.ts +39 -0
  60. package/types/core/src/logger.d.ts +123 -0
  61. package/types/core/src/mcp.d.ts +248 -0
  62. package/types/core/src/messenger.d.ts +191 -0
  63. package/types/core/src/metrics.d.ts +77 -0
  64. package/types/core/src/middleware.d.ts +207 -0
  65. package/types/core/src/mqtt.d.ts +257 -0
  66. package/types/core/src/mqttMessage.d.ts +67 -0
  67. package/types/core/src/plan.d.ts +96 -0
  68. package/types/core/src/projectIndex.d.ts +56 -0
  69. package/types/core/src/queue.d.ts +219 -0
  70. package/types/core/src/queueBackends/kafkaBackend.d.ts +117 -0
  71. package/types/core/src/queueBackends/liteBackend.d.ts +119 -0
  72. package/types/core/src/queueBackends/mongoBackend.d.ts +97 -0
  73. package/types/core/src/queueBackends/rabbitmqBackend.d.ts +55 -0
  74. package/types/core/src/rateLimiter.d.ts +49 -0
  75. package/types/core/src/request.d.ts +25 -0
  76. package/types/core/src/response.d.ts +28 -0
  77. package/types/core/src/routeDiscovery.d.ts +12 -0
  78. package/types/core/src/router.d.ts +355 -0
  79. package/types/core/src/scss.d.ts +19 -0
  80. package/types/core/src/server.d.ts +131 -0
  81. package/types/core/src/service.d.ts +115 -0
  82. package/types/core/src/session.d.ts +256 -0
  83. package/types/core/src/sessionHandlers/childError.d.ts +34 -0
  84. package/types/core/src/sessionHandlers/databaseHandler.d.ts +42 -0
  85. package/types/core/src/sessionHandlers/mongoClient.d.ts +24 -0
  86. package/types/core/src/sessionHandlers/mongoHandler.d.ts +61 -0
  87. package/types/core/src/sessionHandlers/redisHandler.d.ts +60 -0
  88. package/types/core/src/sessionHandlers/respClient.d.ts +22 -0
  89. package/types/core/src/sessionHandlers/valkeyHandler.d.ts +65 -0
  90. package/types/core/src/static.d.ts +2 -0
  91. package/types/core/src/test.d.ts +94 -0
  92. package/types/core/src/testClient.d.ts +36 -0
  93. package/types/core/src/testing.d.ts +58 -0
  94. package/types/core/src/types.d.ts +219 -0
  95. package/types/core/src/validator.d.ts +52 -0
  96. package/types/core/src/websocket.d.ts +376 -0
  97. package/types/core/src/websocketBackplane.d.ts +166 -0
  98. package/types/core/src/websocketConnection.d.ts +54 -0
  99. package/types/core/src/wsdl.d.ts +101 -0
  100. package/types/frond/src/engine.d.ts +263 -0
  101. package/types/frond/src/index.d.ts +2 -0
  102. package/types/orm/src/adapters/firebird.d.ts +138 -0
  103. package/types/orm/src/adapters/mongodb.d.ts +81 -0
  104. package/types/orm/src/adapters/mssql.d.ts +70 -0
  105. package/types/orm/src/adapters/mysql.d.ts +66 -0
  106. package/types/orm/src/adapters/odbc.d.ts +97 -0
  107. package/types/orm/src/adapters/postgres.d.ts +85 -0
  108. package/types/orm/src/adapters/sqlite.d.ts +56 -0
  109. package/types/orm/src/autoCrud.d.ts +73 -0
  110. package/types/orm/src/baseModel.d.ts +391 -0
  111. package/types/orm/src/cachedDatabase.d.ts +177 -0
  112. package/types/orm/src/database.d.ts +609 -0
  113. package/types/orm/src/databaseResult.d.ts +85 -0
  114. package/types/orm/src/docstore.d.ts +182 -0
  115. package/types/orm/src/fakeData.d.ts +22 -0
  116. package/types/orm/src/index.d.ts +40 -0
  117. package/types/orm/src/migration.d.ts +275 -0
  118. package/types/orm/src/model.d.ts +7 -0
  119. package/types/orm/src/query.d.ts +14 -0
  120. package/types/orm/src/queryBuilder.d.ts +173 -0
  121. package/types/orm/src/realtime/index.d.ts +7 -0
  122. package/types/orm/src/realtime/models/attachment.d.ts +43 -0
  123. package/types/orm/src/realtime/models/channel.d.ts +32 -0
  124. package/types/orm/src/realtime/models/channelMember.d.ts +32 -0
  125. package/types/orm/src/realtime/models/message.d.ts +36 -0
  126. package/types/orm/src/realtime/models/workspace.d.ts +26 -0
  127. package/types/orm/src/realtime/realtime.d.ts +24 -0
  128. package/types/orm/src/realtime/storage.d.ts +61 -0
  129. package/types/orm/src/seeder.d.ts +118 -0
  130. package/types/orm/src/sqlTranslator.d.ts +134 -0
  131. package/types/orm/src/types.d.ts +138 -0
  132. package/types/orm/src/validation.d.ts +6 -0
  133. package/types/swagger/src/generator.d.ts +46 -0
  134. package/types/swagger/src/index.d.ts +2 -0
  135. package/types/swagger/src/ui.d.ts +11 -0
@@ -0,0 +1,256 @@
1
+ export interface SessionConfig {
2
+ /** Session backend type: "file", "redis", "valkey", "mongo", "database" (or "db") */
3
+ backend?: string;
4
+ /** File storage path (default: "data/sessions") */
5
+ path?: string;
6
+ /** Time-to-live in seconds (default: 3600) */
7
+ ttl?: number;
8
+ /** Redis host (default: "127.0.0.1") */
9
+ redisHost?: string;
10
+ /** Redis port (default: 6379) */
11
+ redisPort?: number;
12
+ /** Redis password (optional) */
13
+ redisPassword?: string;
14
+ /** Redis key prefix (default: "tina4:session:") */
15
+ redisPrefix?: string;
16
+ /** Redis database index (default: 0) */
17
+ redisDb?: number;
18
+ }
19
+ interface SessionData {
20
+ _created: number;
21
+ _accessed: number;
22
+ [key: string]: unknown;
23
+ }
24
+ /**
25
+ * Base interface for session storage backends.
26
+ * Implementations must provide read, write, and destroy.
27
+ */
28
+ export interface SessionHandler {
29
+ read(sessionId: string): SessionData | null;
30
+ write(sessionId: string, data: SessionData, ttl?: number): void;
31
+ destroy(sessionId: string): void;
32
+ /** Garbage-collect expired sessions. Optional — Redis/Valkey/Mongo handle TTL natively. */
33
+ gc?(maxLifetime: number): void;
34
+ }
35
+ export declare class FileSessionHandler implements SessionHandler {
36
+ private storagePath;
37
+ constructor(storagePath?: string);
38
+ private ensureDir;
39
+ private filePath;
40
+ read(sessionId: string): SessionData | null;
41
+ write(sessionId: string, data: SessionData, ttl?: number): void;
42
+ destroy(sessionId: string): void;
43
+ gc(maxLifetime?: number): void;
44
+ }
45
+ /**
46
+ * Redis session handler using raw TCP (RESP protocol).
47
+ *
48
+ * Uses synchronous socket communication — no external Redis client required.
49
+ * Stores session data as JSON strings with Redis TTL for automatic expiry.
50
+ *
51
+ * Configure via environment variables:
52
+ * TINA4_SESSION_REDIS_HOST (default: "127.0.0.1")
53
+ * TINA4_SESSION_REDIS_PORT (default: 6379)
54
+ * TINA4_SESSION_REDIS_PASSWORD (optional)
55
+ * TINA4_SESSION_REDIS_PREFIX (default: "tina4:session:")
56
+ * TINA4_SESSION_REDIS_DB (default: 0)
57
+ *
58
+ * Or pass via SessionConfig.
59
+ */
60
+ export declare class RedisSessionHandler implements SessionHandler {
61
+ private host;
62
+ private port;
63
+ private password;
64
+ private prefix;
65
+ private db;
66
+ constructor(config?: SessionConfig);
67
+ /**
68
+ * Execute a Redis command synchronously against the live server.
69
+ *
70
+ * Delegates to the shared {@link respCommandSync} transport: a genuine key miss
71
+ * yields `""`, and a transport/connection FAILURE (server unreachable, rejected
72
+ * AUTH, timeout) THROWS so the Session boundary can distinguish "not found"
73
+ * (silent) from "backend failed" (log-loud + degrade). Backend-failure parity.
74
+ */
75
+ private execSync;
76
+ private key;
77
+ read(sessionId: string): SessionData | null;
78
+ write(sessionId: string, data: SessionData, ttl?: number): void;
79
+ destroy(sessionId: string): void;
80
+ }
81
+ export declare class Session {
82
+ private handler;
83
+ private ttl;
84
+ private sessionId;
85
+ private data;
86
+ /**
87
+ * Dirty flag — set when data changes, cleared only on a successful write.
88
+ * Retained on a failed write so a later save() retries once the backend
89
+ * recovers (mirrors the Python `_dirty` semantics).
90
+ */
91
+ private dirty;
92
+ /**
93
+ * Backend-failure policy: log-loud + degrade (default), or re-raise when
94
+ * TINA4_SESSION_STRICT is truthy. A read failure logs + yields an empty
95
+ * session, a write failure logs + returns false (best-effort, dirty
96
+ * retained), destroy/gc failures log + swallow. Parity across all four
97
+ * frameworks. Strict mode is the escape hatch (same as events/seeding).
98
+ */
99
+ private strict;
100
+ constructor(backend?: string, config?: SessionConfig);
101
+ /**
102
+ * Use a custom session handler (for advanced use cases).
103
+ */
104
+ setHandler(handler: SessionHandler): void;
105
+ private logBackendError;
106
+ /** Read through the backend; on FAILURE log + degrade to empty (or re-throw under strict). */
107
+ private safeRead;
108
+ /** Write through the backend; on FAILURE log + return false (or re-throw under strict). */
109
+ private safeWrite;
110
+ /** Destroy through the backend; on FAILURE log + swallow (or re-throw under strict). */
111
+ private safeDestroy;
112
+ /**
113
+ * Start or resume a session.
114
+ * @param sessionId - Existing session ID to resume (optional)
115
+ * @returns The session ID
116
+ */
117
+ start(sessionId?: string): string;
118
+ /**
119
+ * Get a value from the session.
120
+ */
121
+ get(key: string, defaultValue?: unknown): unknown;
122
+ /**
123
+ * Set a value in the session.
124
+ */
125
+ set(key: string, value: unknown): void;
126
+ /**
127
+ * Delete a key from the session.
128
+ */
129
+ delete(key: string): void;
130
+ /**
131
+ * Destroy the entire session.
132
+ *
133
+ * A backend failure is logged (never silent) but does not throw under the
134
+ * default policy — local state is cleared regardless so the request proceeds.
135
+ */
136
+ destroy(): void;
137
+ /**
138
+ * Get all session data (excluding internal keys).
139
+ */
140
+ all(): Record<string, unknown>;
141
+ /**
142
+ * Clear all session data (but keep the session alive).
143
+ */
144
+ clear(): void;
145
+ /**
146
+ * Check if a key exists in the session.
147
+ */
148
+ has(key: string): boolean;
149
+ /**
150
+ * Regenerate the session ID (keeps data, new ID).
151
+ *
152
+ * Call this right after a successful login or any privilege change to defeat
153
+ * session fixation — the pre-auth ID is destroyed and the data is carried
154
+ * onto a fresh, unguessable ID. A backend destroy/write failure is logged
155
+ * (never silent) but does not throw under the default policy.
156
+ */
157
+ regenerate(): string;
158
+ /**
159
+ * Dual-mode flash: set with value, get+remove without.
160
+ *
161
+ * session.flash("message", "Saved!") // set
162
+ * session.flash("message") // get + auto-remove → "Saved!"
163
+ */
164
+ flash(key: string, value?: unknown): unknown;
165
+ /**
166
+ * Get flash data by key (alias for flash(key) without value).
167
+ */
168
+ getFlash(key: string, defaultValue?: unknown): unknown;
169
+ /**
170
+ * Get the current session ID.
171
+ */
172
+ getSessionId(): string | null;
173
+ /**
174
+ * Return a Set-Cookie header value for this session.
175
+ *
176
+ * Honours these env vars (cross-framework parity):
177
+ * TINA4_SESSION_NAME — cookie name (default: "tina4_session")
178
+ * TINA4_SESSION_SAMESITE — SameSite attribute (default: "Lax")
179
+ * TINA4_SESSION_HTTPONLY — emit HttpOnly (default: true)
180
+ * TINA4_SESSION_SECURE — emit Secure (default: false)
181
+ */
182
+ cookieHeader(cookieName?: string): string;
183
+ /**
184
+ * Run garbage collection on the session backend.
185
+ * Removes expired file/database sessions. Redis/Valkey/Mongo handle TTL natively.
186
+ *
187
+ * A backend failure is logged (never silent) but does not throw under the
188
+ * default policy (re-raises under TINA4_SESSION_STRICT=true).
189
+ */
190
+ gc(): void;
191
+ /**
192
+ * Persist session data to the backend.
193
+ *
194
+ * Returns true on a successful persist, false if the backend was unreachable
195
+ * (logged). The dirty flag is cleared only on success so a later save()
196
+ * retries once the backend recovers. A nothing-to-persist call returns true.
197
+ */
198
+ save(): boolean;
199
+ }
200
+ /**
201
+ * Is the client's scheme HTTPS? Proxy-aware.
202
+ *
203
+ * TLS is normally terminated at a proxy (nginx, HAProxy, ALB, Cloudflare, most
204
+ * container deploys) which then forwards plain HTTP to Node — so the native
205
+ * socket is NOT encrypted on exactly the deployments that ARE https, and it
206
+ * cannot be the only signal. `x-forwarded-proto` carries the scheme the client
207
+ * actually used; a chain of proxies appends each hop ("https, http") and the
208
+ * FIRST is the client-facing one, which is the scheme the browser used.
209
+ *
210
+ * Parity with PHP `Request::isSecureScheme` (tina4-php#175). Spoofable when the
211
+ * app is directly reachable, but the failure mode is self-limiting: a spoofed
212
+ * `https` only makes the cookie MORE restrictive, and `request.ts` already
213
+ * trusts the same header for URL construction — honouring it here is consistent.
214
+ *
215
+ * @param forwardedProto Raw `x-forwarded-proto` value (or a resolved scheme like
216
+ * "https"/"http"); "" / undefined means "absent".
217
+ * @param socketEncrypted True when Node terminated TLS itself (direct https, no
218
+ * proxy) — the native fallback when no forwarded header.
219
+ */
220
+ export declare function isSecureScheme(forwardedProto?: string, socketEncrypted?: boolean): boolean;
221
+ /**
222
+ * Resolve the session cookie name — the single source of truth shared by the
223
+ * WRITE side (`buildSessionCookie` / `Session.cookieHeader`) and the READ side
224
+ * (the auto-session cookie parse in `server.ts`), so a cookie written under a
225
+ * renamed name is read back on the next request.
226
+ *
227
+ * TINA4_SESSION_NAME Cookie name (default: "tina4_session")
228
+ *
229
+ * Keeping this in one place means the default can never drift between the two
230
+ * sides: an operator who sets `TINA4_SESSION_NAME` renames the cookie on both
231
+ * the emit and the parse paths at once. Parity with Python
232
+ * `session.session_cookie_name()`.
233
+ */
234
+ export declare function sessionCookieName(): string;
235
+ /**
236
+ * Build the `Set-Cookie` header value for a Tina4 session. Centralised so
237
+ * the auto-cookie path in server.ts and `Session.cookieHeader()` agree on
238
+ * which env vars are honoured and what the defaults are.
239
+ *
240
+ * Env vars (Python parity):
241
+ * TINA4_SESSION_NAME — cookie name (default: "tina4_session")
242
+ * TINA4_SESSION_SAMESITE — SameSite attribute (default: "Lax")
243
+ * TINA4_SESSION_HTTPONLY — emit HttpOnly (default: true)
244
+ * TINA4_SESSION_SECURE — emit Secure (default: false; SameSite=None forces it on)
245
+ *
246
+ * `Secure` is emitted when ANY of: TINA4_SESSION_SECURE is truthy; SameSite is
247
+ * `None` (browsers reject a None cookie without Secure); OR the request scheme
248
+ * is https, detected proxy-aware from `forwardedProto` / `socketEncrypted`. The
249
+ * auto-cookie path in server.ts threads the request's scheme in so an HTTPS
250
+ * deploy behind a TLS-terminating proxy ships Secure without the operator
251
+ * having to know about TINA4_SESSION_SECURE (nodejs#34). Plain HTTP with no
252
+ * proxy header and no native TLS stays NOT Secure — an eager Secure would make
253
+ * http://localhost dev cookies undeliverable.
254
+ */
255
+ export declare function buildSessionCookie(sessionId: string | null, ttl: number, cookieName?: string, forwardedProto?: string, socketEncrypted?: boolean): string;
256
+ export {};
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Tina4 session handlers — turn a failed `execFileSync` child into a readable cause.
3
+ *
4
+ * The session-handler interface is synchronous but every backend client is async,
5
+ * so each command runs in a short-lived `node -e` child. When that child fails,
6
+ * `execFileSync` throws an error whose `.message` begins "Command failed:" and
7
+ * then embeds THE ENTIRE GENERATED SCRIPT — kilobytes of source with the real
8
+ * reason nowhere in it. Every handler used to throw exactly that, so an
9
+ * operator debugging a Redis outage got a wall of JavaScript instead of
10
+ * "connect ECONNREFUSED 127.0.0.1:6379".
11
+ *
12
+ * The children already write the real reason to stderr; `execFileSync` captures
13
+ * it on `err.stderr`. This module is the ONE place that prefers it, so the three
14
+ * call sites (respClient, mongoClient, redisHandler's npm path) cannot drift.
15
+ */
16
+ /**
17
+ * Extract the most useful one-line cause from a thrown `execFileSync` error.
18
+ *
19
+ * Order of preference:
20
+ * 1. the child's own stderr — what it actually reported;
21
+ * 2. a timeout, named as such (a SIGTERM kill leaves stderr empty, so without
22
+ * this the caller would see the useless generic message);
23
+ * 3. a non-zero exit code with no output at all;
24
+ * 4. the error's own message, first line only and length-capped, so the
25
+ * generated script can never be dumped into a log.
26
+ */
27
+ export declare function childFailureReason(err: unknown): string;
28
+ /**
29
+ * Build the Error a session handler throws when its child command failed.
30
+ *
31
+ * `label` names the backend ("Redis", "Valkey", "MongoDB") so the message says
32
+ * which one broke; the wording is shared so all three read alike.
33
+ */
34
+ export declare function childFailureError(label: string, err: unknown): Error;
@@ -0,0 +1,42 @@
1
+ import type { SessionHandler } from "../session.js";
2
+ interface SessionData {
3
+ _created: number;
4
+ _accessed: number;
5
+ [key: string]: unknown;
6
+ }
7
+ export interface DatabaseSessionConfig {
8
+ /** SQLite database file path (default: extracted from TINA4_DATABASE_URL or "data/tina4_sessions.db") */
9
+ dbPath?: string;
10
+ backend?: string;
11
+ path?: string;
12
+ ttl?: number;
13
+ redisHost?: string;
14
+ redisPort?: number;
15
+ redisPassword?: string;
16
+ redisPrefix?: string;
17
+ redisDb?: number;
18
+ }
19
+ /**
20
+ * Database session handler using node:sqlite (synchronous SQLite).
21
+ *
22
+ * Stores session data as JSON in a `tina4_session` table.
23
+ * Expiry is checked on read; expired rows are cleaned up lazily.
24
+ */
25
+ export declare class DatabaseSessionHandler implements SessionHandler {
26
+ private db;
27
+ private initialized;
28
+ constructor(config?: DatabaseSessionConfig);
29
+ /**
30
+ * Resolve the database file path from TINA4_DATABASE_URL or use the default.
31
+ */
32
+ private resolveDbPath;
33
+ /**
34
+ * Ensure the session table exists (called once on first use).
35
+ */
36
+ private ensureTable;
37
+ read(sessionId: string): SessionData | null;
38
+ write(sessionId: string, data: SessionData, ttl: number): void;
39
+ destroy(sessionId: string): void;
40
+ gc(_maxLifetime: number): void;
41
+ }
42
+ export {};
@@ -0,0 +1,24 @@
1
+ export interface MongoTarget {
2
+ host: string;
3
+ port: number;
4
+ database: string;
5
+ collection: string;
6
+ }
7
+ /** Command args: `filter` (always), plus `data`/`last_accessed` for an update. */
8
+ export interface MongoCommandArgs {
9
+ filter: Record<string, unknown>;
10
+ data?: unknown;
11
+ last_accessed?: number;
12
+ }
13
+ /**
14
+ * Run a session Mongo command synchronously and return the raw child stdout.
15
+ *
16
+ * - command "find" -> the matched document as a JSON string, or "__EMPTY__".
17
+ * - command "update" -> "__OK__" (upsert of `{_id, data, last_accessed}`).
18
+ * - command "delete" -> "__OK__".
19
+ *
20
+ * THROWS `<label> command failed: ...` on a transport failure (server unreachable,
21
+ * timeout) OR a Mongo command error (`ok != 1`), so the Session boundary can
22
+ * log-loud + degrade (or re-throw under strict mode).
23
+ */
24
+ export declare function mongoCommandSync(target: MongoTarget, command: "find" | "update" | "delete", args: MongoCommandArgs, label?: string): string;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Tina4 MongoDB Session Handler — MongoDB wire protocol via raw TCP, zero dependencies.
3
+ *
4
+ * Stores session data in MongoDB using the MongoDB wire protocol directly.
5
+ * No `mongodb` or `mongoose` npm package required.
6
+ *
7
+ * Configure via environment variables:
8
+ * TINA4_SESSION_MONGO_HOST (default: "127.0.0.1")
9
+ * TINA4_SESSION_MONGO_PORT (default: 27017)
10
+ * TINA4_SESSION_MONGO_URI (overrides host/port if set)
11
+ * TINA4_SESSION_MONGO_USERNAME (optional)
12
+ * TINA4_SESSION_MONGO_PASSWORD (optional)
13
+ * TINA4_SESSION_MONGO_DB (default: "tina4_sessions")
14
+ * TINA4_SESSION_MONGO_COLLECTION (default: "sessions")
15
+ */
16
+ import type { SessionHandler } from "../session.js";
17
+ interface SessionData {
18
+ _created: number;
19
+ _accessed: number;
20
+ [key: string]: unknown;
21
+ }
22
+ export interface MongoSessionConfig {
23
+ host?: string;
24
+ port?: number;
25
+ uri?: string;
26
+ username?: string;
27
+ password?: string;
28
+ database?: string;
29
+ collection?: string;
30
+ backend?: string;
31
+ path?: string;
32
+ ttl?: number;
33
+ redisHost?: string;
34
+ redisPort?: number;
35
+ redisPassword?: string;
36
+ redisPrefix?: string;
37
+ redisDb?: number;
38
+ }
39
+ /**
40
+ * MongoDB session handler using raw TCP (MongoDB wire protocol).
41
+ *
42
+ * Uses synchronous socket communication via child process — no external
43
+ * MongoDB client library required. Stores session data as BSON documents
44
+ * with TTL index support.
45
+ */
46
+ export declare class MongoSessionHandler implements SessionHandler {
47
+ private host;
48
+ private port;
49
+ private uri;
50
+ private username;
51
+ private password;
52
+ private database;
53
+ private collection;
54
+ constructor(config?: MongoSessionConfig);
55
+ /** Resolve the effective host/port (honours a configured mongodb:// URI). */
56
+ private target;
57
+ read(sessionId: string): SessionData | null;
58
+ write(sessionId: string, data: SessionData, _ttl: number): void;
59
+ destroy(sessionId: string): void;
60
+ }
61
+ export {};
@@ -0,0 +1,60 @@
1
+ import type { SessionHandler } from "../session.js";
2
+ interface SessionData {
3
+ _created: number;
4
+ _accessed: number;
5
+ [key: string]: unknown;
6
+ }
7
+ export interface RedisNpmSessionConfig {
8
+ host?: string;
9
+ port?: number;
10
+ url?: string;
11
+ password?: string;
12
+ prefix?: string;
13
+ db?: number;
14
+ backend?: string;
15
+ path?: string;
16
+ ttl?: number;
17
+ redisHost?: string;
18
+ redisPort?: number;
19
+ redisPassword?: string;
20
+ redisPrefix?: string;
21
+ redisDb?: number;
22
+ }
23
+ /**
24
+ * Redis session handler using the `redis` npm package.
25
+ *
26
+ * Falls back to raw TCP (RESP protocol) if the `redis` package is not
27
+ * installed, matching the approach used by the Valkey handler.
28
+ *
29
+ * Stores session data as JSON strings with Redis TTL for automatic expiry.
30
+ */
31
+ export declare class RedisNpmSessionHandler implements SessionHandler {
32
+ private host;
33
+ private port;
34
+ private url;
35
+ private password;
36
+ private prefix;
37
+ private db;
38
+ constructor(config?: RedisNpmSessionConfig);
39
+ /** Resolve a host/port for the raw-RESP path (parses TINA4_SESSION_REDIS_URL if set). */
40
+ private resolveHostPort;
41
+ /**
42
+ * Execute a Redis command synchronously.
43
+ *
44
+ * Prefers the official `redis` driver when it is installed (the class's reason
45
+ * to exist); otherwise speaks raw RESP via the shared {@link respCommandSync}
46
+ * transport — same correct path as the Valkey handler, no `redis` dependency.
47
+ *
48
+ * A genuine key miss yields `""`; a transport/connection FAILURE (server
49
+ * unreachable, rejected AUTH, timeout) THROWS so the Session boundary can
50
+ * distinguish "not found" (silent) from "backend failed" (log-loud + degrade).
51
+ */
52
+ private execSync;
53
+ /** Drive the command through the `redis` npm client in a short-lived child. */
54
+ private execViaNpm;
55
+ private key;
56
+ read(sessionId: string): SessionData | null;
57
+ write(sessionId: string, data: SessionData, ttl: number): void;
58
+ destroy(sessionId: string): void;
59
+ }
60
+ export {};
@@ -0,0 +1,22 @@
1
+ export interface RespTarget {
2
+ host: string;
3
+ port: number;
4
+ /** AUTH password (empty/undefined = no AUTH sent). */
5
+ password?: string;
6
+ /** SELECT db index (0/undefined = no SELECT sent). */
7
+ db?: number;
8
+ }
9
+ /**
10
+ * Run a single RESP command synchronously against host:port and return the reply.
11
+ *
12
+ * - A genuine nil / key-miss returns `""` (callers treat "" as "no session yet").
13
+ * - A transport FAILURE (server unreachable, timeout, connection closed before a
14
+ * reply) THROWS `<label> command failed: ...`.
15
+ * - A RESP error reply — including a rejected AUTH/SELECT handshake — THROWS
16
+ * `<label> error: ...`. A rejected handshake is a transport failure, not a
17
+ * result, so it is surfaced ahead of the command reply.
18
+ *
19
+ * Session values are JSON strings (they start with `{`), so they never collide
20
+ * with the `__NULL__` / `__ERR__` sentinels the child uses on stdout.
21
+ */
22
+ export declare function respCommandSync(target: RespTarget, args: string[], label?: string): string;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Tina4 Valkey Session Handler — Valkey (Redis-compatible) via raw TCP, zero dependencies.
3
+ *
4
+ * Same as the Redis handler but uses VALKEY-prefixed configuration variables.
5
+ * Valkey is a Redis-compatible key-value store fork.
6
+ *
7
+ * Configure via environment variables:
8
+ * TINA4_SESSION_VALKEY_HOST (default: "127.0.0.1")
9
+ * TINA4_SESSION_VALKEY_PORT (default: 6379)
10
+ * TINA4_SESSION_VALKEY_PASSWORD (optional)
11
+ * TINA4_SESSION_VALKEY_PREFIX (default: "tina4:session:")
12
+ * TINA4_SESSION_VALKEY_DB (default: 0)
13
+ */
14
+ import type { SessionHandler } from "../session.js";
15
+ interface SessionData {
16
+ _created: number;
17
+ _accessed: number;
18
+ [key: string]: unknown;
19
+ }
20
+ export interface ValkeySessionConfig {
21
+ host?: string;
22
+ port?: number;
23
+ password?: string;
24
+ prefix?: string;
25
+ db?: number;
26
+ backend?: string;
27
+ path?: string;
28
+ ttl?: number;
29
+ redisHost?: string;
30
+ redisPort?: number;
31
+ redisPassword?: string;
32
+ redisPrefix?: string;
33
+ redisDb?: number;
34
+ }
35
+ /**
36
+ * Valkey session handler using raw TCP (RESP protocol).
37
+ *
38
+ * Uses synchronous socket communication — no external Valkey/Redis client required.
39
+ * Stores session data as JSON strings with Valkey TTL for automatic expiry.
40
+ *
41
+ * Valkey uses the same RESP protocol as Redis, so this handler is functionally
42
+ * identical to RedisSessionHandler but with VALKEY config variable names.
43
+ */
44
+ export declare class ValkeySessionHandler implements SessionHandler {
45
+ private host;
46
+ private port;
47
+ private password;
48
+ private prefix;
49
+ private db;
50
+ constructor(config?: ValkeySessionConfig);
51
+ /**
52
+ * Execute a RESP command synchronously against the live Valkey server.
53
+ *
54
+ * Delegates to the shared {@link respCommandSync} transport: a genuine key miss
55
+ * yields `""`, and a transport/connection FAILURE (server unreachable, rejected
56
+ * AUTH, timeout) THROWS so the Session boundary can distinguish "not found"
57
+ * (silent) from "backend failed" (log-loud + degrade). Backend-failure parity.
58
+ */
59
+ private execSync;
60
+ private key;
61
+ read(sessionId: string): SessionData | null;
62
+ write(sessionId: string, data: SessionData, ttl: number): void;
63
+ destroy(sessionId: string): void;
64
+ }
65
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { Tina4Request, Tina4Response } from "./types.js";
2
+ export declare function tryServeStatic(staticDir: string, req: Tina4Request, res: Tina4Response): boolean;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Tina4 — The Intelligent Native Application 4ramework
3
+ * Copyright 2007 - current Tina4
4
+ * License: MIT https://opensource.org/licenses/MIT
5
+ *
6
+ * Tina4 xUnit-style Test base class.
7
+ *
8
+ * Chapter 18 of the documentation has long shown:
9
+ *
10
+ * class UserApiTest extends Tina4Test {
11
+ * async testHealth() {
12
+ * const resp = await this.get("/health");
13
+ * this.assertEqual(resp.status, 200);
14
+ * }
15
+ * }
16
+ *
17
+ * Until 3.13.0 this class did not exist — examples crashed with
18
+ * "ReferenceError: Tina4Test is not defined". This is the Node.js
19
+ * parity of the Python `tina4_python.test.Test`, PHP `Tina4\Test`,
20
+ * and Ruby `Tina4::Test` classes shipped at the same time.
21
+ *
22
+ * The class has a built-in runner (`Tina4Test.runAll`) so the docs'
23
+ * `npx tina4nodejs test` flow can discover every subclass without
24
+ * an external test framework. HTTP helpers (get/post/put/patch/delete)
25
+ * delegate to a lazy TestClient. Positional assertions match the
26
+ * cross-framework (actual, expected, message) shape.
27
+ */
28
+ import { TestClient, type TestResponse, type RequestOptions } from "./testClient.js";
29
+ /** Raised by Tina4Test assertion helpers when an assertion fails. */
30
+ export declare class AssertionError extends Error {
31
+ constructor(message: string);
32
+ }
33
+ /** Result of running a Tina4Test subclass (or all subclasses). */
34
+ export interface TestRunResults {
35
+ passed: number;
36
+ failed: number;
37
+ errors: number;
38
+ details: Array<{
39
+ suite: string;
40
+ test: string;
41
+ status: "passed" | "failed" | "error";
42
+ message?: string;
43
+ }>;
44
+ }
45
+ /**
46
+ * Tina4 xUnit-style test base class — class-based suites with HTTP
47
+ * helpers and positional assertions, zero external deps.
48
+ *
49
+ * Subclass and define `test*` methods:
50
+ *
51
+ * class BasicTest extends Tina4Test {
52
+ * async testAddition() {
53
+ * this.assertEqual(2 + 2, 4, "addition works");
54
+ * }
55
+ * async testHttpHealth() {
56
+ * const resp = await this.get("/health");
57
+ * this.assertEqual(resp.status, 200);
58
+ * }
59
+ * }
60
+ *
61
+ * const results = await Tina4Test.runAll();
62
+ * // → { passed, failed, errors, details }
63
+ */
64
+ export declare class Tina4Test {
65
+ private _client;
66
+ /** snake_case lifecycle hook — runs before each test. Override in subclasses. */
67
+ setUp(): Promise<void>;
68
+ /** snake_case lifecycle hook — runs after each test. Override in subclasses. */
69
+ tearDown(): Promise<void>;
70
+ /** The lazily-created TestClient instance shared by this suite's tests. */
71
+ protected get client(): TestClient;
72
+ get(path: string, options?: RequestOptions): Promise<TestResponse>;
73
+ post(path: string, options?: RequestOptions): Promise<TestResponse>;
74
+ put(path: string, options?: RequestOptions): Promise<TestResponse>;
75
+ patch(path: string, options?: RequestOptions): Promise<TestResponse>;
76
+ delete(path: string, options?: RequestOptions): Promise<TestResponse>;
77
+ assertEqual(actual: unknown, expected: unknown, message?: string): void;
78
+ assertNotEqual(actual: unknown, expected: unknown, message?: string): void;
79
+ assertTrue(value: unknown, message?: string): void;
80
+ assertFalse(value: unknown, message?: string): void;
81
+ assertNull(value: unknown, message?: string): void;
82
+ assertNotNull(value: unknown, message?: string): void;
83
+ assertRaises(expectedClass: new (...args: never[]) => Error, fn: () => unknown | Promise<unknown>, message?: string): Promise<void>;
84
+ /** Register a subclass for discovery. Called automatically via `extends Tina4Test`. */
85
+ static register(klass: typeof Tina4Test): void;
86
+ /** Run every `test*` method on this class. Returns counts and per-test details. */
87
+ static run(this: typeof Tina4Test): Promise<TestRunResults>;
88
+ /** Run every Tina4Test subclass discovered via auto-registration. */
89
+ static runAll(options?: {
90
+ quiet?: boolean;
91
+ }): Promise<TestRunResults>;
92
+ /** Subclasses array — read-only view used by tests. */
93
+ static get subclasses(): ReadonlyArray<typeof Tina4Test>;
94
+ }