tina4-nodejs 3.13.92 → 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.
- package/CLAUDE.md +16 -3
- package/README.md +1 -1
- package/package.json +12 -9
- package/packages/cli/dist/bin.js +1260 -969
- package/packages/core/dist/index.js +1260 -969
- package/packages/core/src/devMailbox.ts +20 -44
- package/packages/core/src/index.ts +2 -2
- package/packages/core/src/messenger.ts +72 -0
- package/packages/core/src/queueBackends/kafkaBackend.ts +108 -12
- package/packages/core/src/sessionHandlers/childError.ts +72 -0
- package/packages/core/src/sessionHandlers/mongoClient.ts +9 -3
- package/packages/core/src/sessionHandlers/redisHandler.ts +18 -5
- package/packages/core/src/sessionHandlers/respClient.ts +5 -1
- package/packages/frond/dist/index.js +74 -31
- package/packages/frond/src/engine.ts +99 -33
- package/packages/orm/dist/index.js +3055 -2764
- package/packages/orm/src/adapters/sqlite.ts +4 -1
- package/packages/orm/src/database.ts +108 -8
- package/types/cli/src/bin.d.ts +92 -0
- package/types/cli/src/commands/build.d.ts +2 -0
- package/types/cli/src/commands/generate.d.ts +47 -0
- package/types/cli/src/commands/init.d.ts +1 -0
- package/types/cli/src/commands/metrics.d.ts +6 -0
- package/types/cli/src/commands/migrate.d.ts +1 -0
- package/types/cli/src/commands/migrateCreate.d.ts +1 -0
- package/types/cli/src/commands/migrateRollback.d.ts +1 -0
- package/types/cli/src/commands/migrateStatus.d.ts +1 -0
- package/types/cli/src/commands/queue.d.ts +20 -0
- package/types/cli/src/commands/routes.d.ts +1 -0
- package/types/cli/src/commands/seed.d.ts +1 -0
- package/types/cli/src/commands/serve.d.ts +6 -0
- package/types/cli/src/commands/test.d.ts +1 -0
- package/types/core/src/ai.d.ts +64 -0
- package/types/core/src/api.d.ts +262 -0
- package/types/core/src/auth.d.ts +154 -0
- package/types/core/src/authGate.d.ts +20 -0
- package/types/core/src/background.d.ts +34 -0
- package/types/core/src/cache.d.ts +160 -0
- package/types/core/src/constants.d.ts +38 -0
- package/types/core/src/container.d.ts +44 -0
- package/types/core/src/context/chunker.d.ts +31 -0
- package/types/core/src/context/index.d.ts +93 -0
- package/types/core/src/devAdmin.d.ts +179 -0
- package/types/core/src/devMailbox.d.ts +54 -0
- package/types/core/src/docs.d.ts +141 -0
- package/types/core/src/docsAutoDiscovery.d.ts +6 -0
- package/types/core/src/dotenv.d.ts +65 -0
- package/types/core/src/env.d.ts +28 -0
- package/types/core/src/errorOverlay.d.ts +36 -0
- package/types/core/src/events.d.ts +75 -0
- package/types/core/src/fakeData.d.ts +55 -0
- package/types/core/src/feedback.d.ts +90 -0
- package/types/core/src/graphql.d.ts +207 -0
- package/types/core/src/health.d.ts +22 -0
- package/types/core/src/htmlElement.d.ts +75 -0
- package/types/core/src/i18n.d.ts +37 -0
- package/types/core/src/index.d.ts +93 -0
- package/types/core/src/job.d.ts +39 -0
- package/types/core/src/logger.d.ts +123 -0
- package/types/core/src/mcp.d.ts +248 -0
- package/types/core/src/messenger.d.ts +191 -0
- package/types/core/src/metrics.d.ts +77 -0
- package/types/core/src/middleware.d.ts +207 -0
- package/types/core/src/mqtt.d.ts +257 -0
- package/types/core/src/mqttMessage.d.ts +67 -0
- package/types/core/src/plan.d.ts +96 -0
- package/types/core/src/projectIndex.d.ts +56 -0
- package/types/core/src/queue.d.ts +219 -0
- package/types/core/src/queueBackends/kafkaBackend.d.ts +117 -0
- package/types/core/src/queueBackends/liteBackend.d.ts +119 -0
- package/types/core/src/queueBackends/mongoBackend.d.ts +97 -0
- package/types/core/src/queueBackends/rabbitmqBackend.d.ts +55 -0
- package/types/core/src/rateLimiter.d.ts +49 -0
- package/types/core/src/request.d.ts +25 -0
- package/types/core/src/response.d.ts +28 -0
- package/types/core/src/routeDiscovery.d.ts +12 -0
- package/types/core/src/router.d.ts +355 -0
- package/types/core/src/scss.d.ts +19 -0
- package/types/core/src/server.d.ts +131 -0
- package/types/core/src/service.d.ts +115 -0
- package/types/core/src/session.d.ts +256 -0
- package/types/core/src/sessionHandlers/childError.d.ts +34 -0
- package/types/core/src/sessionHandlers/databaseHandler.d.ts +42 -0
- package/types/core/src/sessionHandlers/mongoClient.d.ts +24 -0
- package/types/core/src/sessionHandlers/mongoHandler.d.ts +61 -0
- package/types/core/src/sessionHandlers/redisHandler.d.ts +60 -0
- package/types/core/src/sessionHandlers/respClient.d.ts +22 -0
- package/types/core/src/sessionHandlers/valkeyHandler.d.ts +65 -0
- package/types/core/src/static.d.ts +2 -0
- package/types/core/src/test.d.ts +94 -0
- package/types/core/src/testClient.d.ts +36 -0
- package/types/core/src/testing.d.ts +58 -0
- package/types/core/src/types.d.ts +219 -0
- package/types/core/src/validator.d.ts +52 -0
- package/types/core/src/websocket.d.ts +376 -0
- package/types/core/src/websocketBackplane.d.ts +166 -0
- package/types/core/src/websocketConnection.d.ts +54 -0
- package/types/core/src/wsdl.d.ts +101 -0
- package/types/frond/src/engine.d.ts +263 -0
- package/types/frond/src/index.d.ts +2 -0
- package/types/orm/src/adapters/firebird.d.ts +138 -0
- package/types/orm/src/adapters/mongodb.d.ts +81 -0
- package/types/orm/src/adapters/mssql.d.ts +70 -0
- package/types/orm/src/adapters/mysql.d.ts +66 -0
- package/types/orm/src/adapters/odbc.d.ts +97 -0
- package/types/orm/src/adapters/postgres.d.ts +85 -0
- package/types/orm/src/adapters/sqlite.d.ts +56 -0
- package/types/orm/src/autoCrud.d.ts +73 -0
- package/types/orm/src/baseModel.d.ts +391 -0
- package/types/orm/src/cachedDatabase.d.ts +177 -0
- package/types/orm/src/database.d.ts +609 -0
- package/types/orm/src/databaseResult.d.ts +85 -0
- package/types/orm/src/docstore.d.ts +182 -0
- package/types/orm/src/fakeData.d.ts +22 -0
- package/types/orm/src/index.d.ts +40 -0
- package/types/orm/src/migration.d.ts +275 -0
- package/types/orm/src/model.d.ts +7 -0
- package/types/orm/src/query.d.ts +14 -0
- package/types/orm/src/queryBuilder.d.ts +173 -0
- package/types/orm/src/realtime/index.d.ts +7 -0
- package/types/orm/src/realtime/models/attachment.d.ts +43 -0
- package/types/orm/src/realtime/models/channel.d.ts +32 -0
- package/types/orm/src/realtime/models/channelMember.d.ts +32 -0
- package/types/orm/src/realtime/models/message.d.ts +36 -0
- package/types/orm/src/realtime/models/workspace.d.ts +26 -0
- package/types/orm/src/realtime/realtime.d.ts +24 -0
- package/types/orm/src/realtime/storage.d.ts +61 -0
- package/types/orm/src/seeder.d.ts +118 -0
- package/types/orm/src/sqlTranslator.d.ts +134 -0
- package/types/orm/src/types.d.ts +138 -0
- package/types/orm/src/validation.d.ts +6 -0
- package/types/swagger/src/generator.d.ts +46 -0
- package/types/swagger/src/index.d.ts +2 -0
- package/types/swagger/src/ui.d.ts +11 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QueryBuilder — Fluent SQL query builder for Tina4 Node.js.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* // Standalone
|
|
6
|
+
* const result = QueryBuilder.fromTable("users", db)
|
|
7
|
+
* .select("id", "name")
|
|
8
|
+
* .where("active = ?", [1])
|
|
9
|
+
* .orderBy("name ASC")
|
|
10
|
+
* .limit(10)
|
|
11
|
+
* .get();
|
|
12
|
+
*
|
|
13
|
+
* // From ORM model
|
|
14
|
+
* const result = User.query()
|
|
15
|
+
* .where("age > ?", [18])
|
|
16
|
+
* .orderBy("name")
|
|
17
|
+
* .get();
|
|
18
|
+
*/
|
|
19
|
+
import type { DatabaseAdapter } from "./types.js";
|
|
20
|
+
export declare class QueryBuilder {
|
|
21
|
+
private table;
|
|
22
|
+
private db;
|
|
23
|
+
private columns;
|
|
24
|
+
private wheres;
|
|
25
|
+
private params;
|
|
26
|
+
private joinClauses;
|
|
27
|
+
private groupByCols;
|
|
28
|
+
private havings;
|
|
29
|
+
private havingParams;
|
|
30
|
+
private orderByCols;
|
|
31
|
+
private limitVal;
|
|
32
|
+
private offsetVal;
|
|
33
|
+
/**
|
|
34
|
+
* Private constructor — use static factory methods.
|
|
35
|
+
*/
|
|
36
|
+
private constructor();
|
|
37
|
+
/**
|
|
38
|
+
* Create a QueryBuilder for a table.
|
|
39
|
+
*
|
|
40
|
+
* @param tableName - Table name.
|
|
41
|
+
* @param db - Optional database adapter.
|
|
42
|
+
* @returns A new QueryBuilder instance.
|
|
43
|
+
*/
|
|
44
|
+
static fromTable(tableName: string, db?: DatabaseAdapter): QueryBuilder;
|
|
45
|
+
/**
|
|
46
|
+
* Set the columns to select.
|
|
47
|
+
*
|
|
48
|
+
* @param cols - Column names.
|
|
49
|
+
* @returns this for chaining.
|
|
50
|
+
*/
|
|
51
|
+
select(...cols: string[]): QueryBuilder;
|
|
52
|
+
/**
|
|
53
|
+
* Add a WHERE condition (AND).
|
|
54
|
+
*
|
|
55
|
+
* @param condition - SQL condition with ? placeholders.
|
|
56
|
+
* @param params - Parameter values.
|
|
57
|
+
* @returns this for chaining.
|
|
58
|
+
*/
|
|
59
|
+
where(condition: string, params?: unknown[]): QueryBuilder;
|
|
60
|
+
/**
|
|
61
|
+
* Add a WHERE condition (OR).
|
|
62
|
+
*
|
|
63
|
+
* @param condition - SQL condition with ? placeholders.
|
|
64
|
+
* @param params - Parameter values.
|
|
65
|
+
* @returns this for chaining.
|
|
66
|
+
*/
|
|
67
|
+
orWhere(condition: string, params?: unknown[]): QueryBuilder;
|
|
68
|
+
/**
|
|
69
|
+
* Add an INNER JOIN.
|
|
70
|
+
*
|
|
71
|
+
* @param table - Table to join.
|
|
72
|
+
* @param onClause - Join condition.
|
|
73
|
+
* @returns this for chaining.
|
|
74
|
+
*/
|
|
75
|
+
join(table: string, onClause: string): QueryBuilder;
|
|
76
|
+
/**
|
|
77
|
+
* Add a LEFT JOIN.
|
|
78
|
+
*
|
|
79
|
+
* @param table - Table to join.
|
|
80
|
+
* @param onClause - Join condition.
|
|
81
|
+
* @returns this for chaining.
|
|
82
|
+
*/
|
|
83
|
+
leftJoin(table: string, onClause: string): QueryBuilder;
|
|
84
|
+
/**
|
|
85
|
+
* Add a GROUP BY column.
|
|
86
|
+
*
|
|
87
|
+
* @param column - Column name.
|
|
88
|
+
* @returns this for chaining.
|
|
89
|
+
*/
|
|
90
|
+
groupBy(column: string): QueryBuilder;
|
|
91
|
+
/**
|
|
92
|
+
* Add a HAVING clause.
|
|
93
|
+
*
|
|
94
|
+
* @param expression - HAVING expression with ? placeholders.
|
|
95
|
+
* @param params - Parameter values.
|
|
96
|
+
* @returns this for chaining.
|
|
97
|
+
*/
|
|
98
|
+
having(expression: string, params?: unknown[]): QueryBuilder;
|
|
99
|
+
/**
|
|
100
|
+
* Add an ORDER BY clause.
|
|
101
|
+
*
|
|
102
|
+
* @param expression - Column and direction (e.g. "name ASC").
|
|
103
|
+
* @returns this for chaining.
|
|
104
|
+
*/
|
|
105
|
+
orderBy(expression: string): QueryBuilder;
|
|
106
|
+
/**
|
|
107
|
+
* Set LIMIT and optional OFFSET.
|
|
108
|
+
*
|
|
109
|
+
* @param count - Maximum rows to return.
|
|
110
|
+
* @param offset - Number of rows to skip.
|
|
111
|
+
* @returns this for chaining.
|
|
112
|
+
*/
|
|
113
|
+
limit(count: number, offset?: number): QueryBuilder;
|
|
114
|
+
/**
|
|
115
|
+
* Build and return the SQL string without executing.
|
|
116
|
+
*
|
|
117
|
+
* @returns The constructed SQL query.
|
|
118
|
+
*/
|
|
119
|
+
toSql(): string;
|
|
120
|
+
/**
|
|
121
|
+
* Execute the query and return all matching rows.
|
|
122
|
+
*
|
|
123
|
+
* @returns Array of row objects.
|
|
124
|
+
*/
|
|
125
|
+
get<T = Record<string, unknown>>(): Promise<T[]>;
|
|
126
|
+
/**
|
|
127
|
+
* Execute the query and return a single row.
|
|
128
|
+
*
|
|
129
|
+
* @returns A single row object, or null.
|
|
130
|
+
*/
|
|
131
|
+
first<T = Record<string, unknown>>(): Promise<T | null>;
|
|
132
|
+
/**
|
|
133
|
+
* Execute the query and return the row count.
|
|
134
|
+
*
|
|
135
|
+
* @returns Number of matching rows.
|
|
136
|
+
*/
|
|
137
|
+
count(): Promise<number>;
|
|
138
|
+
/**
|
|
139
|
+
* Check whether any matching rows exist.
|
|
140
|
+
*
|
|
141
|
+
* @returns True if at least one row matches.
|
|
142
|
+
*/
|
|
143
|
+
exists(): Promise<boolean>;
|
|
144
|
+
/**
|
|
145
|
+
* Convert the fluent builder state into a MongoDB-compatible query document.
|
|
146
|
+
*
|
|
147
|
+
* @returns An object with filter, projection, sort, limit, skip (only non-empty keys).
|
|
148
|
+
*/
|
|
149
|
+
toMongo(): {
|
|
150
|
+
filter?: Record<string, unknown>;
|
|
151
|
+
projection?: Record<string, number>;
|
|
152
|
+
sort?: Record<string, 1 | -1>;
|
|
153
|
+
limit?: number;
|
|
154
|
+
skip?: number;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Parse a single SQL condition string into a MongoDB filter object.
|
|
158
|
+
*/
|
|
159
|
+
private parseConditionToMongo;
|
|
160
|
+
/**
|
|
161
|
+
* Merge multiple single-field mongo condition objects into one.
|
|
162
|
+
* Uses $and if field keys conflict.
|
|
163
|
+
*/
|
|
164
|
+
private mergeMongoConditions;
|
|
165
|
+
/**
|
|
166
|
+
* Build the WHERE clause from accumulated conditions.
|
|
167
|
+
*/
|
|
168
|
+
private buildWhere;
|
|
169
|
+
/**
|
|
170
|
+
* Ensure a database adapter is available.
|
|
171
|
+
*/
|
|
172
|
+
private ensureDb;
|
|
173
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { realtime, iceServers, type RealtimeOptions } from "./realtime.js";
|
|
2
|
+
export { LocalStorage, S3Storage, selectStorage, storageKey, type StorageBackend, } from "./storage.js";
|
|
3
|
+
export { default as Workspace } from "./models/workspace.js";
|
|
4
|
+
export { default as Channel } from "./models/channel.js";
|
|
5
|
+
export { default as ChannelMember } from "./models/channelMember.js";
|
|
6
|
+
export { default as Message } from "./models/message.js";
|
|
7
|
+
export { default as Attachment } from "./models/attachment.js";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { BaseModel } from "../../baseModel.js";
|
|
2
|
+
/**
|
|
3
|
+
* Attachment - a file linked to a channel (and optionally a message).
|
|
4
|
+
* channel_id scopes the file for permission checks; message_id is null until
|
|
5
|
+
* the file is attached to a posted message. storage_key is the StorageBackend
|
|
6
|
+
* key; the row carries only metadata, never the blob.
|
|
7
|
+
*/
|
|
8
|
+
export default class Attachment extends BaseModel {
|
|
9
|
+
static tableName: string;
|
|
10
|
+
static fields: {
|
|
11
|
+
id: {
|
|
12
|
+
type: "integer";
|
|
13
|
+
primaryKey: boolean;
|
|
14
|
+
autoIncrement: boolean;
|
|
15
|
+
};
|
|
16
|
+
channel_id: {
|
|
17
|
+
type: "integer";
|
|
18
|
+
};
|
|
19
|
+
message_id: {
|
|
20
|
+
type: "integer";
|
|
21
|
+
};
|
|
22
|
+
storage_key: {
|
|
23
|
+
type: "string";
|
|
24
|
+
required: boolean;
|
|
25
|
+
maxLength: number;
|
|
26
|
+
};
|
|
27
|
+
filename: {
|
|
28
|
+
type: "string";
|
|
29
|
+
maxLength: number;
|
|
30
|
+
};
|
|
31
|
+
mime: {
|
|
32
|
+
type: "string";
|
|
33
|
+
maxLength: number;
|
|
34
|
+
};
|
|
35
|
+
size: {
|
|
36
|
+
type: "integer";
|
|
37
|
+
};
|
|
38
|
+
thumb_key: {
|
|
39
|
+
type: "string";
|
|
40
|
+
maxLength: number;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { BaseModel } from "../../baseModel.js";
|
|
2
|
+
/**
|
|
3
|
+
* Channel - a conversation stream inside a workspace.
|
|
4
|
+
* kind is one of public | private | dm. workspace_id is a plain integer FK
|
|
5
|
+
* column (the realtime handlers query it directly).
|
|
6
|
+
*/
|
|
7
|
+
export default class Channel extends BaseModel {
|
|
8
|
+
static tableName: string;
|
|
9
|
+
static fields: {
|
|
10
|
+
id: {
|
|
11
|
+
type: "integer";
|
|
12
|
+
primaryKey: boolean;
|
|
13
|
+
autoIncrement: boolean;
|
|
14
|
+
};
|
|
15
|
+
workspace_id: {
|
|
16
|
+
type: "integer";
|
|
17
|
+
};
|
|
18
|
+
name: {
|
|
19
|
+
type: "string";
|
|
20
|
+
required: boolean;
|
|
21
|
+
maxLength: number;
|
|
22
|
+
};
|
|
23
|
+
kind: {
|
|
24
|
+
type: "string";
|
|
25
|
+
default: string;
|
|
26
|
+
maxLength: number;
|
|
27
|
+
};
|
|
28
|
+
created_at: {
|
|
29
|
+
type: "datetime";
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { BaseModel } from "../../baseModel.js";
|
|
2
|
+
/**
|
|
3
|
+
* ChannelMember - a user's membership of a channel plus their read cursor.
|
|
4
|
+
* user_id is a string so it holds any identity shape the app puts in the JWT
|
|
5
|
+
* (an integer id, a UUID, an email). last_read_at is the read-receipt cursor.
|
|
6
|
+
*/
|
|
7
|
+
export default class ChannelMember extends BaseModel {
|
|
8
|
+
static tableName: string;
|
|
9
|
+
static fields: {
|
|
10
|
+
id: {
|
|
11
|
+
type: "integer";
|
|
12
|
+
primaryKey: boolean;
|
|
13
|
+
autoIncrement: boolean;
|
|
14
|
+
};
|
|
15
|
+
channel_id: {
|
|
16
|
+
type: "integer";
|
|
17
|
+
};
|
|
18
|
+
user_id: {
|
|
19
|
+
type: "string";
|
|
20
|
+
required: boolean;
|
|
21
|
+
maxLength: number;
|
|
22
|
+
};
|
|
23
|
+
role: {
|
|
24
|
+
type: "string";
|
|
25
|
+
default: string;
|
|
26
|
+
maxLength: number;
|
|
27
|
+
};
|
|
28
|
+
last_read_at: {
|
|
29
|
+
type: "datetime";
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { BaseModel } from "../../baseModel.js";
|
|
2
|
+
/**
|
|
3
|
+
* Message - one posted message in a channel.
|
|
4
|
+
* thread_id is null for a top-level message, or the id of the parent message
|
|
5
|
+
* for a threaded reply. edited_at is null until an edit.
|
|
6
|
+
*/
|
|
7
|
+
export default class Message extends BaseModel {
|
|
8
|
+
static tableName: string;
|
|
9
|
+
static fields: {
|
|
10
|
+
id: {
|
|
11
|
+
type: "integer";
|
|
12
|
+
primaryKey: boolean;
|
|
13
|
+
autoIncrement: boolean;
|
|
14
|
+
};
|
|
15
|
+
channel_id: {
|
|
16
|
+
type: "integer";
|
|
17
|
+
};
|
|
18
|
+
user_id: {
|
|
19
|
+
type: "string";
|
|
20
|
+
required: boolean;
|
|
21
|
+
maxLength: number;
|
|
22
|
+
};
|
|
23
|
+
body: {
|
|
24
|
+
type: "text";
|
|
25
|
+
};
|
|
26
|
+
thread_id: {
|
|
27
|
+
type: "integer";
|
|
28
|
+
};
|
|
29
|
+
created_at: {
|
|
30
|
+
type: "datetime";
|
|
31
|
+
};
|
|
32
|
+
edited_at: {
|
|
33
|
+
type: "datetime";
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { BaseModel } from "../../baseModel.js";
|
|
2
|
+
/**
|
|
3
|
+
* Workspace - the top-level container for channels (a "team" / "org").
|
|
4
|
+
* Framework-owned table: the tina4_rt_ prefix keeps it clear of an app's own
|
|
5
|
+
* domain tables (mirrors tina4_migration / tina4_sequences + the Python
|
|
6
|
+
* master's tina4_rt_* tables). Field keys are snake_case so the columns and
|
|
7
|
+
* JSON keys stay byte-identical to the master (no camelCase mapping needed).
|
|
8
|
+
*/
|
|
9
|
+
export default class Workspace extends BaseModel {
|
|
10
|
+
static tableName: string;
|
|
11
|
+
static fields: {
|
|
12
|
+
id: {
|
|
13
|
+
type: "integer";
|
|
14
|
+
primaryKey: boolean;
|
|
15
|
+
autoIncrement: boolean;
|
|
16
|
+
};
|
|
17
|
+
name: {
|
|
18
|
+
type: "string";
|
|
19
|
+
required: boolean;
|
|
20
|
+
maxLength: number;
|
|
21
|
+
};
|
|
22
|
+
created_at: {
|
|
23
|
+
type: "datetime";
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type StorageBackend } from "./storage.js";
|
|
2
|
+
export interface RealtimeOptions {
|
|
3
|
+
prefix?: string;
|
|
4
|
+
authorize?: (identity: string, channelId: number) => boolean | Promise<boolean>;
|
|
5
|
+
storage?: StorageBackend;
|
|
6
|
+
features?: string[];
|
|
7
|
+
}
|
|
8
|
+
interface IceServer {
|
|
9
|
+
urls: string[];
|
|
10
|
+
username?: string;
|
|
11
|
+
credential?: string;
|
|
12
|
+
}
|
|
13
|
+
/** Build the ICE server list from the environment (STUN always; ephemeral TURN when configured). */
|
|
14
|
+
export declare function iceServers(): IceServer[];
|
|
15
|
+
/**
|
|
16
|
+
* Mount the realtime surface and return the resolved path map (also served
|
|
17
|
+
* from the config endpoint so the client can discover it).
|
|
18
|
+
*
|
|
19
|
+
* Returns a Promise because the framework-owned chat tables are created via the
|
|
20
|
+
* async ORM (Node's DB layer is async) - `await realtime(...)` so the tables
|
|
21
|
+
* exist before the first request. Route registration itself is synchronous.
|
|
22
|
+
*/
|
|
23
|
+
export declare function realtime(options?: RealtimeOptions): Promise<Record<string, string>>;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pluggable file storage for the realtime "files" feature. StorageBackend is
|
|
3
|
+
* the interface; LocalStorage (default, zero-dependency, filesystem) and
|
|
4
|
+
* S3Storage (opt-in, S3-compatible via @aws-sdk/client-s3) are the shipped
|
|
5
|
+
* implementations. Selection mirrors the cache/session/queue backend pattern:
|
|
6
|
+
* TINA4_STORAGE_BACKEND (local default | s3) plus per-backend env vars, with a
|
|
7
|
+
* graceful fallback to local if an s3 backend cannot be constructed - a real
|
|
8
|
+
* persistent store, never a silent no-op. Parity with Python's storage.py.
|
|
9
|
+
*/
|
|
10
|
+
export interface StorageBackend {
|
|
11
|
+
put(key: string, data: Buffer | string, mime?: string): void | Promise<void>;
|
|
12
|
+
get(key: string): Buffer | null | Promise<Buffer | null>;
|
|
13
|
+
/** A directly-fetchable URL when the backend supports one, else null. */
|
|
14
|
+
url(key: string, ttl?: number): string | null | Promise<string | null>;
|
|
15
|
+
delete(key: string): void | Promise<void>;
|
|
16
|
+
exists(key: string): boolean | Promise<boolean>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Generate an opaque, collision-free storage key, preserving the extension.
|
|
20
|
+
* The key carries no user-controlled path segment, so it can never traverse
|
|
21
|
+
* outside the storage root.
|
|
22
|
+
*/
|
|
23
|
+
export declare function storageKey(filename?: string): string;
|
|
24
|
+
/** Zero-dependency filesystem store. The default backend. */
|
|
25
|
+
export declare class LocalStorage implements StorageBackend {
|
|
26
|
+
private directory;
|
|
27
|
+
constructor(directory?: string);
|
|
28
|
+
private pathFor;
|
|
29
|
+
put(key: string, data: Buffer | string): void;
|
|
30
|
+
get(key: string): Buffer | null;
|
|
31
|
+
url(): string | null;
|
|
32
|
+
delete(key: string): void;
|
|
33
|
+
exists(key: string): boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* S3-compatible store (AWS S3, MinIO, ...). Opt-in; needs @aws-sdk/client-s3.
|
|
37
|
+
* Presigned GET URLs let clients fetch large blobs straight from object
|
|
38
|
+
* storage instead of streaming through the app.
|
|
39
|
+
*/
|
|
40
|
+
export declare class S3Storage implements StorageBackend {
|
|
41
|
+
private client;
|
|
42
|
+
private bucket;
|
|
43
|
+
constructor(opts?: {
|
|
44
|
+
endpoint?: string;
|
|
45
|
+
key?: string;
|
|
46
|
+
secret?: string;
|
|
47
|
+
bucket?: string;
|
|
48
|
+
region?: string;
|
|
49
|
+
});
|
|
50
|
+
put(key: string, data: Buffer | string, mime?: string): Promise<void>;
|
|
51
|
+
get(key: string): Promise<Buffer | null>;
|
|
52
|
+
url(key: string, ttl?: number): Promise<string | null>;
|
|
53
|
+
delete(key: string): Promise<void>;
|
|
54
|
+
exists(key: string): Promise<boolean>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Resolve the storage backend from an explicit instance or the environment.
|
|
58
|
+
* Falls back to LocalStorage (logging why) when an s3 backend cannot be built
|
|
59
|
+
* (driver missing or config incomplete) - a real store, never a silent no-op.
|
|
60
|
+
*/
|
|
61
|
+
export declare function selectStorage(storage?: StorageBackend): StorageBackend;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { FakeData } from "./fakeData.js";
|
|
2
|
+
import type { DatabaseAdapter, FieldDefinition } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Result of a seed run — `{ seeded, failed, errors }`.
|
|
5
|
+
*
|
|
6
|
+
* `errors` is a list of `{ row, message }` describing every skipped row
|
|
7
|
+
* (`row` is the 0-based index). Mirrors the Python `SeedSummary`; Node tests
|
|
8
|
+
* compare `.seeded` / `.failed` rather than the bare integer.
|
|
9
|
+
*/
|
|
10
|
+
export interface SeedSummary {
|
|
11
|
+
seeded: number;
|
|
12
|
+
failed: number;
|
|
13
|
+
errors: Array<{
|
|
14
|
+
row: number;
|
|
15
|
+
message: string;
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
/** Options shared by seedTable / seedOrm / seedModels. */
|
|
19
|
+
export interface SeedOptions {
|
|
20
|
+
/** Static values applied to every row (overrides generated values). */
|
|
21
|
+
overrides?: Record<string, unknown>;
|
|
22
|
+
/** Delete every existing row in the target before seeding (P2). */
|
|
23
|
+
clear?: boolean;
|
|
24
|
+
/** PRNG seed for reproducible FakeData output (P3). */
|
|
25
|
+
seed?: number;
|
|
26
|
+
/** Re-raise on the first failed row instead of skipping it (P1). */
|
|
27
|
+
strict?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Introspect `table`'s columns and build a column->generator field map for
|
|
31
|
+
* {@link seedTable}, skipping the auto-increment / `id` primary key (the engine
|
|
32
|
+
* assigns it). Mirrors the Python master's `auto_field_map`
|
|
33
|
+
* (tina4_python/seeder/__init__.py): the shared "seed a table I did not
|
|
34
|
+
* hand-write generators for" helper that both the dev-admin seed endpoint and
|
|
35
|
+
* the MCP `seed_table` dev tool use — `seedTable` itself stays explicit
|
|
36
|
+
* (no map = no rows), and this is how a caller opts into automatic generation.
|
|
37
|
+
*
|
|
38
|
+
* Reuses `FakeData.forField()` (column-name + type heuristics) so the generated
|
|
39
|
+
* data matches every other Tina4 seeding path. Returns an empty map when the
|
|
40
|
+
* table has no seedable columns, so `seedTable` then seeds nothing rather than
|
|
41
|
+
* crashing.
|
|
42
|
+
*
|
|
43
|
+
* @param db - A DatabaseAdapter instance (pass `getAdapter()`, NOT the Database
|
|
44
|
+
* wrapper — the wrapper has no `columns()`).
|
|
45
|
+
* @param table - The table to introspect.
|
|
46
|
+
* @param fake - Optional shared FakeData (pass one seeded via `new FakeData(n)`
|
|
47
|
+
* for reproducible output).
|
|
48
|
+
* @returns `{ column -> () => value }`, ready to hand to `seedTable`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function autoFieldMap(db: DatabaseAdapter, table: string, fake?: FakeData): Promise<Record<string, () => unknown>>;
|
|
51
|
+
/**
|
|
52
|
+
* Seed a database table with fake data using raw SQL inserts.
|
|
53
|
+
*
|
|
54
|
+
* Visible-but-resilient (P1): each row is wrapped. On a row failure the cause
|
|
55
|
+
* is logged (with the row index) and the row is skipped — unless `strict: true`,
|
|
56
|
+
* in which case the first failure RE-RAISES. At the end a one-line summary is
|
|
57
|
+
* logged ("seeded N, M failed").
|
|
58
|
+
*
|
|
59
|
+
* @param db - A DatabaseAdapter instance
|
|
60
|
+
* @param tableName - The table to insert into
|
|
61
|
+
* @param count - Number of rows to insert (default 10)
|
|
62
|
+
* @param fieldMap - Dict of column_name -> callable that generates a value
|
|
63
|
+
* (or a static value). If not provided, no rows are inserted.
|
|
64
|
+
* @param overrides - (legacy positional) Static values applied to every row.
|
|
65
|
+
* Prefer `opts.overrides`.
|
|
66
|
+
* @param opts - Seed options: `{ overrides, clear, seed, strict }`.
|
|
67
|
+
* @returns A SeedSummary `{ seeded, failed, errors }`.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* const fake = new FakeData();
|
|
71
|
+
* await seedTable(db, "users", 50, {
|
|
72
|
+
* name: () => fake.name(),
|
|
73
|
+
* email: () => fake.email(),
|
|
74
|
+
* }, undefined, { clear: true });
|
|
75
|
+
*/
|
|
76
|
+
export declare function seedTable(db: DatabaseAdapter, tableName: string, count?: number, fieldMap?: Record<string, (() => unknown) | unknown>, overrides?: Record<string, unknown>, opts?: SeedOptions): Promise<SeedSummary>;
|
|
77
|
+
/** A model-like shape the seeder can drive (real BaseModel subclass or mock). */
|
|
78
|
+
interface SeedableModel {
|
|
79
|
+
tableName: string;
|
|
80
|
+
fields: Record<string, FieldDefinition>;
|
|
81
|
+
_db?: string;
|
|
82
|
+
getDb?: () => DatabaseAdapter;
|
|
83
|
+
name?: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Seed an ORM model class with auto-generated fake data, based on field
|
|
87
|
+
* definitions. Visible-but-resilient (P1): each row is wrapped, failures are
|
|
88
|
+
* logged + counted + skipped (or re-raised under `strict`).
|
|
89
|
+
*
|
|
90
|
+
* @param ormClass - A model with static `tableName`, `fields`, and optionally
|
|
91
|
+
* `getDb`/`_db`.
|
|
92
|
+
* @param count - Number of rows to insert (default 10)
|
|
93
|
+
* @param overrides - (legacy positional) Static field overrides.
|
|
94
|
+
* @param seed - (legacy positional) PRNG seed for deterministic output.
|
|
95
|
+
* @param opts - Seed options `{ overrides, clear, seed, strict }`. Options
|
|
96
|
+
* supersede the legacy positional args when both are supplied.
|
|
97
|
+
* @param fkPools - (internal) pre-resolved FK value pools from seedModels.
|
|
98
|
+
* @returns A SeedSummary `{ seeded, failed, errors }`.
|
|
99
|
+
*/
|
|
100
|
+
export declare function seedOrm(ormClass: SeedableModel, count?: number, overrides?: Record<string, unknown>, seed?: number, opts?: SeedOptions, fkPools?: Record<string, unknown[]>): Promise<SeedSummary>;
|
|
101
|
+
/**
|
|
102
|
+
* Batch-seed several ORM models, ordering by their foreignKey dependency graph
|
|
103
|
+
* (P4a). Parent tables seed before children (topological sort); when
|
|
104
|
+
* `clear: true` the clear runs in REVERSE order so children are removed before
|
|
105
|
+
* parents — no FK violations regardless of the order the caller lists models.
|
|
106
|
+
* FK columns are resolved to real parent PKs so child rows reference an
|
|
107
|
+
* existing parent. Mirrors Python `seed_models`.
|
|
108
|
+
*
|
|
109
|
+
* @param ormClasses - List of model classes to seed.
|
|
110
|
+
* @param count - Rows per model (default 10).
|
|
111
|
+
* @param opts - Seed options. `overrides` may be a flat dict applied to every
|
|
112
|
+
* model, or a Map/record keyed by model to apply per-model overrides.
|
|
113
|
+
* @returns `{ [modelName]: SeedSummary }` for each model seeded.
|
|
114
|
+
*/
|
|
115
|
+
export declare function seedModels(ormClasses: SeedableModel[], count?: number, opts?: SeedOptions & {
|
|
116
|
+
overrides?: Record<string, unknown> | Map<SeedableModel, Record<string, unknown>>;
|
|
117
|
+
}): Promise<Record<string, SeedSummary>>;
|
|
118
|
+
export {};
|