tina4-nodejs 3.10.68 → 3.10.70

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 CHANGED
@@ -1,10 +1,10 @@
1
- # CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.10.42)
1
+ # CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.10.70)
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.10.42 — The Intelligent Native Application 4ramework. A convention-over-configuration structural paradigm. The developer writes TypeScript; Tina4 is invisible infrastructure.
7
+ Tina4 for Node.js/TypeScript v3.10.70 — 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
 
@@ -240,6 +240,7 @@ req.cookies: Record<string, string> // parsed from Cookie header
240
240
  req.contentType: string // from content-type header
241
241
  req.query: Record<string, string> // query string params
242
242
  response.xml(content, status?): Tina4Response
243
+ response.stream(generator, contentType?: string, status?: number): void // SSE/streaming
243
244
  ```
244
245
 
245
246
  ### Queue
@@ -677,7 +678,7 @@ When adding new features, add a corresponding `test/<feature>.test.ts` file.
677
678
 
678
679
  ## v3 Features Summary
679
680
 
680
- - **44 built-in features**, zero third-party dependencies
681
+ - **45 built-in features**, zero third-party dependencies
681
682
  - **1,812 tests** passing across all modules
682
683
  - **Race-safe `getNextId()`** with atomic sequence table (`tina4_sequences`) for SQLite/MySQL/MSSQL; PostgreSQL auto-creates sequences
683
684
  - **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)
@@ -695,6 +696,7 @@ When adding new features, add a corresponding `test/<feature>.test.ts` file.
695
696
  - **SameSite=Lax** default on session cookies (`TINA4_SESSION_SAMESITE`)
696
697
  - **`tina4 init`** generates Dockerfile and .dockerignore
697
698
  - **Gallery**: 7 interactive examples with Try It deploy at `/_dev/`
699
+ - **SSE/Streaming**: `response.stream()` for Server-Sent Events — pass an async generator, framework handles chunked transfer encoding and keep-alive
698
700
 
699
701
  ## Don'ts
700
702
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tina4-nodejs",
3
- "version": "3.10.68",
3
+ "version": "3.10.70",
4
4
  "type": "module",
5
5
  "description": "Tina4 for Node.js/TypeScript — 54 built-in features, zero dependencies",
6
6
  "keywords": ["tina4", "framework", "web", "api", "orm", "graphql", "websocket", "typescript"],
@@ -242,6 +242,40 @@ export function createResponse(res: ServerResponse): Tina4Response {
242
242
  return response.render(name, data, status, templateDir);
243
243
  };
244
244
 
245
+ /**
246
+ * Stream response from an async generator for Server-Sent Events (SSE).
247
+ *
248
+ * Usage:
249
+ * export default async function (req, res) {
250
+ * res.stream(async function* () {
251
+ * for (let i = 0; i < 10; i++) {
252
+ * yield `data: message ${i}\n\n`;
253
+ * await new Promise(r => setTimeout(r, 1000));
254
+ * }
255
+ * }());
256
+ * }
257
+ */
258
+ (response as any).stream = async function (
259
+ source: AsyncIterable<string | Buffer>,
260
+ contentType: string = "text/event-stream",
261
+ ): Promise<Tina4Response> {
262
+ if (res.headersSent) return response;
263
+ res.writeHead(200, {
264
+ "Content-Type": contentType,
265
+ "Cache-Control": "no-cache",
266
+ "Connection": "keep-alive",
267
+ "X-Accel-Buffering": "no",
268
+ });
269
+
270
+ for await (const chunk of source) {
271
+ const data = typeof chunk === "string" ? chunk : chunk.toString();
272
+ res.write(data);
273
+ }
274
+
275
+ res.end();
276
+ return response;
277
+ };
278
+
245
279
  return response;
246
280
  }
247
281
 
@@ -54,6 +54,8 @@ export interface Tina4ResponseMethods {
54
54
  error(code: string, message: string, status?: number): Tina4Response;
55
55
  render(template: string, data?: Record<string, unknown>, status?: number, templateDir?: string): Promise<Tina4Response>;
56
56
  template(name: string, data?: Record<string, unknown>, status?: number, templateDir?: string): Promise<Tina4Response>;
57
+ /** Stream response from an async generator (SSE or chunked). */
58
+ stream(source: AsyncIterable<string | Buffer>, contentType?: string): Promise<Tina4Response>;
57
59
  /** The underlying ServerResponse for advanced use */
58
60
  raw: ServerResponse;
59
61
  }