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.
- package/CLAUDE.md +170 -28
- package/README.md +2 -2
- package/package.json +13 -9
- package/packages/cli/dist/bin.js +33126 -30055
- package/packages/cli/src/commands/metrics.ts +17 -11
- package/packages/cli/src/commands/serve.ts +10 -9
- package/packages/core/dist/index.js +33062 -29908
- package/packages/core/src/ai.ts +7 -1
- package/packages/core/src/auth.ts +191 -39
- package/packages/core/src/background.ts +19 -19
- package/packages/core/src/cache.ts +492 -49
- package/packages/core/src/devAdmin.ts +79 -32
- package/packages/core/src/devMailbox.ts +20 -44
- package/packages/core/src/dispatchPipeline.ts +285 -0
- package/packages/core/src/dotenv.ts +185 -40
- package/packages/core/src/index.ts +7 -6
- package/packages/core/src/logger.ts +257 -36
- package/packages/core/src/mcp.ts +1 -1
- package/packages/core/src/messenger.ts +81 -13
- package/packages/core/src/metrics.ts +199 -961
- package/packages/core/src/middleware.ts +390 -123
- package/packages/core/src/queue.ts +188 -32
- package/packages/core/src/queueBackends/kafkaBackend.ts +109 -13
- package/packages/core/src/queueBackends/liteBackend.ts +13 -0
- package/packages/core/src/queueBackends/mongoBackend.ts +101 -9
- package/packages/core/src/queueBackends/rabbitmqBackend.ts +22 -4
- package/packages/core/src/rateLimiter.ts +10 -5
- package/packages/core/src/request.ts +6 -9
- package/packages/core/src/response.ts +46 -1
- package/packages/core/src/router.ts +29 -4
- package/packages/core/src/server.ts +751 -414
- package/packages/core/src/session.ts +244 -27
- package/packages/core/src/sessionHandlers/childError.ts +72 -0
- package/packages/core/src/sessionHandlers/databaseHandler.ts +338 -48
- package/packages/core/src/sessionHandlers/memcachedHandler.ts +181 -0
- package/packages/core/src/sessionHandlers/mongoClient.ts +293 -202
- package/packages/core/src/sessionHandlers/mongoHandler.ts +88 -8
- package/packages/core/src/sessionHandlers/respClient.ts +16 -143
- package/packages/core/src/sessionHandlers/sqlClient.ts +290 -0
- package/packages/core/src/sessionHandlers/syncBridge.ts +190 -0
- package/packages/core/src/sessionHandlers/syncSocket.ts +236 -0
- package/packages/core/src/testClient.ts +18 -5
- package/packages/core/src/trustedProxy.ts +249 -0
- package/packages/core/src/types.ts +29 -5
- package/packages/core/src/websocket.ts +66 -0
- package/packages/frond/dist/index.js +74 -31
- package/packages/frond/src/engine.ts +99 -33
- package/packages/orm/dist/index.js +26554 -23400
- package/packages/orm/src/adapters/firebird.ts +183 -56
- package/packages/orm/src/adapters/mongodb.ts +25 -4
- package/packages/orm/src/adapters/mssql.ts +114 -29
- package/packages/orm/src/adapters/mysql.ts +103 -40
- package/packages/orm/src/adapters/odbc.ts +44 -21
- package/packages/orm/src/adapters/postgres.ts +118 -26
- package/packages/orm/src/adapters/sqlDialect.ts +120 -0
- package/packages/orm/src/adapters/sqlite.ts +64 -25
- package/packages/orm/src/baseModel.ts +135 -40
- package/packages/orm/src/cachedDatabase.ts +43 -19
- package/packages/orm/src/connectTimeout.ts +265 -0
- package/packages/orm/src/database.ts +338 -198
- package/packages/orm/src/databaseResult.ts +65 -13
- package/packages/orm/src/databaseUrl.ts +484 -0
- package/packages/orm/src/docstore.ts +386 -145
- package/packages/orm/src/index.ts +13 -3
- package/packages/orm/src/migration.ts +18 -3
- package/packages/orm/src/queryBuilder.ts +38 -4
- package/packages/orm/src/sqlTranslator.ts +310 -4
- package/packages/orm/src/types.ts +15 -4
- 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 +177 -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 +163 -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/dispatchPipeline.d.ts +117 -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 +87 -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 +92 -0
- package/types/core/src/job.d.ts +39 -0
- package/types/core/src/logger.d.ts +200 -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 +41 -0
- package/types/core/src/middleware.d.ts +330 -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 +268 -0
- package/types/core/src/queueBackends/kafkaBackend.d.ts +117 -0
- package/types/core/src/queueBackends/liteBackend.d.ts +128 -0
- package/types/core/src/queueBackends/mongoBackend.d.ts +119 -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 +366 -0
- package/types/core/src/scss.d.ts +19 -0
- package/types/core/src/server.d.ts +146 -0
- package/types/core/src/service.d.ts +115 -0
- package/types/core/src/session.d.ts +341 -0
- package/types/core/src/sessionHandlers/childError.d.ts +34 -0
- package/types/core/src/sessionHandlers/databaseHandler.d.ts +97 -0
- package/types/core/src/sessionHandlers/memcachedHandler.d.ts +60 -0
- package/types/core/src/sessionHandlers/mongoClient.d.ts +35 -0
- package/types/core/src/sessionHandlers/mongoHandler.d.ts +109 -0
- package/types/core/src/sessionHandlers/respClient.d.ts +22 -0
- package/types/core/src/sessionHandlers/sqlClient.d.ts +39 -0
- package/types/core/src/sessionHandlers/syncBridge.d.ts +91 -0
- package/types/core/src/sessionHandlers/syncSocket.d.ts +49 -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/trustedProxy.d.ts +44 -0
- package/types/core/src/types.d.ts +242 -0
- package/types/core/src/validator.d.ts +52 -0
- package/types/core/src/websocket.d.ts +402 -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 +183 -0
- package/types/orm/src/adapters/mongodb.d.ts +81 -0
- package/types/orm/src/adapters/mssql.d.ts +77 -0
- package/types/orm/src/adapters/mysql.d.ts +67 -0
- package/types/orm/src/adapters/odbc.d.ts +94 -0
- package/types/orm/src/adapters/postgres.d.ts +86 -0
- package/types/orm/src/adapters/sqlDialect.d.ts +71 -0
- package/types/orm/src/adapters/sqlite.d.ts +68 -0
- package/types/orm/src/autoCrud.d.ts +73 -0
- package/types/orm/src/baseModel.d.ts +427 -0
- package/types/orm/src/cachedDatabase.d.ts +190 -0
- package/types/orm/src/connectTimeout.d.ts +100 -0
- package/types/orm/src/database.d.ts +655 -0
- package/types/orm/src/databaseResult.d.ts +109 -0
- package/types/orm/src/databaseUrl.d.ts +125 -0
- package/types/orm/src/docstore.d.ts +241 -0
- package/types/orm/src/fakeData.d.ts +22 -0
- package/types/orm/src/index.d.ts +43 -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 +193 -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 +258 -0
- package/types/orm/src/types.d.ts +148 -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
- package/packages/core/src/sessionHandlers/redisHandler.ts +0 -206
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured logger for Tina4.
|
|
3
|
+
*
|
|
4
|
+
* FORMAT IS TEXT BY DEFAULT, and TINA4_LOG_FORMAT=json is the ONLY thing that
|
|
5
|
+
* selects JSON. Nothing else may. Until 3.13.95 an unset TINA4_DEBUG silently
|
|
6
|
+
* flipped BOTH sinks to JSON here, and "production" meant four different things
|
|
7
|
+
* across the four frameworks (Node: !TINA4_DEBUG; Ruby: TINA4_ENV/RACK_ENV/
|
|
8
|
+
* RUBY_ENV == "production"; Python: only configure(production=True); PHP: no
|
|
9
|
+
* switch at all, JSON always) — same machine, same .env, four log formats. That
|
|
10
|
+
* implicit switch is deleted; an object passed as the message is still
|
|
11
|
+
* JSON-encoded INLINE inside the text line, which is the only JSON a default
|
|
12
|
+
* install emits.
|
|
13
|
+
*
|
|
14
|
+
* TINA4_DEBUG still decides COLOUR — a terminal concern, not a format one — so
|
|
15
|
+
* a production pipe gets clean uncoloured bytes and a dev terminal stays
|
|
16
|
+
* readable.
|
|
17
|
+
*
|
|
18
|
+
* Default file-output rule (TINA4_LOG_OUTPUT unset): the log FILE is written
|
|
19
|
+
* only in development. An explicit TINA4_LOG_OUTPUT=file/both, OR an explicit
|
|
20
|
+
* TINA4_LOG_FILE path, always forces a file (explicit wins). stdout is ALWAYS on.
|
|
21
|
+
*
|
|
22
|
+
* Env vars:
|
|
23
|
+
* TINA4_LOG_FILE — explicit log file (absolute or relative). Setting it forces a file even in production. Empty = use TINA4_LOG_DIR + tina4.log
|
|
24
|
+
* TINA4_LOG_DIR — directory for log files (default: "logs")
|
|
25
|
+
* TINA4_LOG_FORMAT — "text" | "json" (default: "text") — the ONLY format switch
|
|
26
|
+
* TINA4_LOG_OUTPUT — "stdout" | "file" | "both" (default: "stdout" → file only in dev)
|
|
27
|
+
* TINA4_LOG_ROTATE_SIZE — bytes; 0 disables rotation (default: 10485760 = 10MB)
|
|
28
|
+
* TINA4_LOG_ROTATE_KEEP — number of historical files to keep (default: 5)
|
|
29
|
+
* TINA4_LOG_LEVEL — minimum console level: DEBUG | INFO | WARNING | ERROR | CRITICAL (default: "INFO")
|
|
30
|
+
* TINA4_LOG_STRICT — truthy: a log-write failure THROWS instead of being swallowed (default: off)
|
|
31
|
+
*
|
|
32
|
+
* Every one of these is read LAZILY, on each log() call — a script, worker, CLI
|
|
33
|
+
* tool or test that never boots a server still gets the operator's configuration.
|
|
34
|
+
*
|
|
35
|
+
* Rotation is stdlib roll-your-own:
|
|
36
|
+
* - On each write, statSync the file. If size >= TINA4_LOG_ROTATE_SIZE, rotate.
|
|
37
|
+
* - app.log.{N-1} → app.log.{N}, …, app.log → app.log.1 via fs.renameSync.
|
|
38
|
+
* - Files beyond _KEEP are dropped via fs.unlinkSync.
|
|
39
|
+
* - _SIZE=0 disables rotation entirely.
|
|
40
|
+
*/
|
|
41
|
+
export declare class Log {
|
|
42
|
+
private static requestId;
|
|
43
|
+
/**
|
|
44
|
+
* What configure() was explicitly told, held HERE rather than written back
|
|
45
|
+
* into process.env (ADR-0041).
|
|
46
|
+
*
|
|
47
|
+
* configure() used to assign to process.env.TINA4_LOG_DIR / _LOG_FILE. That
|
|
48
|
+
* reached the right answer -- the argument won -- through a mechanism no
|
|
49
|
+
* other framework has: it DESTROYED the operator's value for the rest of the
|
|
50
|
+
* process, and every child process spawned afterwards inherited the
|
|
51
|
+
* argument instead of what the operator set. Reading configuration must not
|
|
52
|
+
* write it. Keeping the explicit values in their own slot means resolution
|
|
53
|
+
* is explicit > env > default with the environment left intact and still
|
|
54
|
+
* readable.
|
|
55
|
+
*/
|
|
56
|
+
private static explicitLogDir;
|
|
57
|
+
private static explicitLogFile;
|
|
58
|
+
/**
|
|
59
|
+
* Re-read all log-related env vars. Called on every log() so tests that
|
|
60
|
+
* mutate process.env between calls see the new values without having to
|
|
61
|
+
* call configure() each time.
|
|
62
|
+
*/
|
|
63
|
+
private static readEnv;
|
|
64
|
+
/**
|
|
65
|
+
* The single console-threshold predicate: does a message at `level` clear
|
|
66
|
+
* the configured minimum console level? This is the ONE place level
|
|
67
|
+
* comparison lives — both the live log() gate and the public isEnabled()
|
|
68
|
+
* predicate call it, so they can never disagree about what actually prints.
|
|
69
|
+
*/
|
|
70
|
+
private static passesThreshold;
|
|
71
|
+
/**
|
|
72
|
+
* Return true if a message at `level` would pass the configured minimum
|
|
73
|
+
* console level (TINA4_LOG_LEVEL) — the same threshold that gates stdout.
|
|
74
|
+
*
|
|
75
|
+
* This reflects CONSOLE (stdout) visibility only. The log file always
|
|
76
|
+
* records every level regardless of this threshold, so don't use it to
|
|
77
|
+
* decide whether something gets persisted — use it to skip building an
|
|
78
|
+
* expensive payload that would not be shown:
|
|
79
|
+
*
|
|
80
|
+
* if (Log.isEnabled("debug")) {
|
|
81
|
+
* Log.debug("state", expensiveSnapshot());
|
|
82
|
+
* }
|
|
83
|
+
*
|
|
84
|
+
* `level` is case-insensitive. "critical" is the highest severity (priority
|
|
85
|
+
* 4 > error 3) and flows through the ordinary threshold check like every
|
|
86
|
+
* other level — there is no toggle. It reuses the same passesThreshold()
|
|
87
|
+
* check the logger itself uses, so it never drifts from what print does.
|
|
88
|
+
*/
|
|
89
|
+
static isEnabled(level: string): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Set the current request ID for log correlation.
|
|
92
|
+
*/
|
|
93
|
+
static setRequestId(id: string | undefined): void;
|
|
94
|
+
/**
|
|
95
|
+
* Get the current request ID.
|
|
96
|
+
*/
|
|
97
|
+
static getRequestId(): string | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* Configure where logs are written.
|
|
100
|
+
*
|
|
101
|
+
* Logs land in a `logs/` folder by default. The argument OVERRIDES that, and
|
|
102
|
+
* it accepts a DIRECTORY or a FILE PATH:
|
|
103
|
+
*
|
|
104
|
+
* configure() -> ./logs/tina4.log + ./logs/error.log
|
|
105
|
+
* configure("/var/log/myapp") -> /var/log/myapp/tina4.log + error.log
|
|
106
|
+
* configure("/var/log/myapp/app.log") -> that exact file (no error.log sibling)
|
|
107
|
+
* configure({ logDir, logFile }) -> the explicit object form still works
|
|
108
|
+
*
|
|
109
|
+
* A plain string used to be accepted and silently ignored, because only the
|
|
110
|
+
* object form was read - so the call that works in the other three
|
|
111
|
+
* frameworks produced no log file here and said nothing (feature 2 of the
|
|
112
|
+
* audit, D4). Both forms now work.
|
|
113
|
+
*/
|
|
114
|
+
static configure(options?: string | {
|
|
115
|
+
logDir?: string;
|
|
116
|
+
logFile?: string;
|
|
117
|
+
}): void;
|
|
118
|
+
/**
|
|
119
|
+
* Forget what configure() was told, so resolution falls back to the
|
|
120
|
+
* environment and then the built-in defaults. Parity with PHP's Log::reset().
|
|
121
|
+
*
|
|
122
|
+
* This exists because the explicit values are now HELD here rather than
|
|
123
|
+
* written back into process.env, and that makes them STICKY for the life of
|
|
124
|
+
* the process -- which is right for an application (configure() at boot is
|
|
125
|
+
* the operator's instruction and a later stray env write should not silently
|
|
126
|
+
* re-point the logs) and wrong for a long-lived test process that wants to
|
|
127
|
+
* drive the logger purely from the environment afterwards.
|
|
128
|
+
*
|
|
129
|
+
* I removed this method once for having no callers. That was correct about
|
|
130
|
+
* the grep and wrong about the code: the full suite is the caller. Before the
|
|
131
|
+
* explicit slots existed, configure() ASSIGNED to process.env, so a later
|
|
132
|
+
* direct assignment simply overwrote it and env-driven cases kept working by
|
|
133
|
+
* accident. test/logger.test.ts depends on exactly that -- it configures a
|
|
134
|
+
* file early, then runs the whole default-output block off the environment
|
|
135
|
+
* (see its own note: "these cases must NOT route through Log.configure").
|
|
136
|
+
* Three of those cases failed on the lab until this came back.
|
|
137
|
+
*/
|
|
138
|
+
static reset(): void;
|
|
139
|
+
/**
|
|
140
|
+
* TINA4_LOG_APPEND — append (default) or overwrite on startup.
|
|
141
|
+
*
|
|
142
|
+
* APPEND IS THE DEFAULT: a log you can lose by restarting the process is not
|
|
143
|
+
* a log. Set it false for one file per run (a short CLI, a test fixture, a
|
|
144
|
+
* container shipping logs elsewhere); the files are truncated once here at
|
|
145
|
+
* configure time, never per line.
|
|
146
|
+
*/
|
|
147
|
+
private static applyAppendMode;
|
|
148
|
+
/** Log an informational message. */
|
|
149
|
+
static info(message: unknown, data?: unknown): void;
|
|
150
|
+
/** Log a debug message. */
|
|
151
|
+
static debug(message: unknown, data?: unknown): void;
|
|
152
|
+
/** Log a warning message. */
|
|
153
|
+
static warning(message: unknown, data?: unknown): void;
|
|
154
|
+
/** Backwards-compat alias for warning(). */
|
|
155
|
+
static warn(message: unknown, data?: unknown): void;
|
|
156
|
+
/** Log an error message. */
|
|
157
|
+
static error(message: unknown, data?: unknown): void;
|
|
158
|
+
/**
|
|
159
|
+
* Log a critical message. CRITICAL is the highest severity (priority 4 >
|
|
160
|
+
* error 3) and ALWAYS emits like every other level — subject only to the
|
|
161
|
+
* console threshold, which it always passes at normal levels — and is always
|
|
162
|
+
* persisted to the log file (Node tees every level to a single tina4.log;
|
|
163
|
+
* critical 4 >= warning 2 so it would be in error.log on a split-file model).
|
|
164
|
+
* Matches Python master parity — there is no enable toggle.
|
|
165
|
+
*/
|
|
166
|
+
static critical(message: unknown, data?: unknown): void;
|
|
167
|
+
/** Check if running in production mode (TINA4_DEBUG is not truthy). */
|
|
168
|
+
private static isProduction;
|
|
169
|
+
/** Get current ISO timestamp */
|
|
170
|
+
private static timestamp;
|
|
171
|
+
/** Ensure the log directory exists */
|
|
172
|
+
private static ensureLogDir;
|
|
173
|
+
/**
|
|
174
|
+
* Roll-your-own rotation, stdlib only.
|
|
175
|
+
*
|
|
176
|
+
* Sequence on each write:
|
|
177
|
+
* 1. statSync the current file. If size < rotateSize, return.
|
|
178
|
+
* 2. Drop any file beyond keep via unlinkSync (cap the historical count).
|
|
179
|
+
* 3. Atomic shift: app.log.{N-1} → app.log.{N}, …, app.log.1 → app.log.2.
|
|
180
|
+
* 4. Rename current app.log → app.log.1.
|
|
181
|
+
* 5. Truncate via writeFileSync(path, "") so subsequent appends start fresh.
|
|
182
|
+
*
|
|
183
|
+
* Sync calls per write are fine — the worst case is contention on a single
|
|
184
|
+
* file, and the OS atomically serialises rename/unlink anyway.
|
|
185
|
+
*
|
|
186
|
+
* `rotateSize` of 0 disables rotation entirely.
|
|
187
|
+
*/
|
|
188
|
+
private static rotateIfNeeded;
|
|
189
|
+
/**
|
|
190
|
+
* Write a line to the log file, stripping ANSI codes.
|
|
191
|
+
*
|
|
192
|
+
* A failure is swallowed by default — logging must never crash the app. With
|
|
193
|
+
* TINA4_LOG_STRICT truthy it is RE-THROWN instead: an app that believes it is
|
|
194
|
+
* writing an audit trail into a read-only directory, and is not, is worse off
|
|
195
|
+
* than one that dies at the first line. Same contract in all four frameworks.
|
|
196
|
+
*/
|
|
197
|
+
private static writeToFile;
|
|
198
|
+
/** Core log method */
|
|
199
|
+
private static log;
|
|
200
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
export interface JsonRpcMessage {
|
|
2
|
+
jsonrpc: "2.0";
|
|
3
|
+
id?: number | string | null;
|
|
4
|
+
method?: string;
|
|
5
|
+
params?: Record<string, unknown>;
|
|
6
|
+
result?: unknown;
|
|
7
|
+
error?: {
|
|
8
|
+
code: number;
|
|
9
|
+
message: string;
|
|
10
|
+
data?: unknown;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface McpToolDefinition {
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
inputSchema: JsonSchema;
|
|
17
|
+
handler: (args: Record<string, unknown>) => unknown | Promise<unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface McpResourceDefinition {
|
|
20
|
+
uri: string;
|
|
21
|
+
name: string;
|
|
22
|
+
description: string;
|
|
23
|
+
mimeType: string;
|
|
24
|
+
handler: () => unknown;
|
|
25
|
+
}
|
|
26
|
+
export interface JsonSchema {
|
|
27
|
+
type: string;
|
|
28
|
+
properties: Record<string, {
|
|
29
|
+
type: string;
|
|
30
|
+
default?: unknown;
|
|
31
|
+
}>;
|
|
32
|
+
required?: string[];
|
|
33
|
+
}
|
|
34
|
+
export interface McpToolParam {
|
|
35
|
+
name: string;
|
|
36
|
+
type: "string" | "integer" | "number" | "boolean" | "array" | "object";
|
|
37
|
+
required?: boolean;
|
|
38
|
+
default?: unknown;
|
|
39
|
+
}
|
|
40
|
+
export declare const PARSE_ERROR = -32700;
|
|
41
|
+
export declare const INVALID_REQUEST = -32600;
|
|
42
|
+
export declare const METHOD_NOT_FOUND = -32601;
|
|
43
|
+
export declare const INVALID_PARAMS = -32602;
|
|
44
|
+
export declare const INTERNAL_ERROR = -32603;
|
|
45
|
+
export declare const SUPPORTED_PROTOCOL_VERSIONS: readonly ["2025-06-18", "2025-03-26", "2024-11-05"];
|
|
46
|
+
export declare const LATEST_PROTOCOL_VERSION: "2025-06-18";
|
|
47
|
+
export declare function encodeResponse(requestId: number | string | null | undefined, result: unknown): string;
|
|
48
|
+
export declare function encodeError(requestId: number | string | null | undefined, code: number, message: string, data?: unknown): string;
|
|
49
|
+
export declare function encodeNotification(method: string, params?: Record<string, unknown>): string;
|
|
50
|
+
export declare function decodeRequest(data: string | Record<string, unknown>): {
|
|
51
|
+
method: string;
|
|
52
|
+
params: Record<string, unknown>;
|
|
53
|
+
requestId: number | string | null;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Build a JSON Schema from an explicit parameter list.
|
|
57
|
+
* Since TypeScript erases types at runtime, we use explicit metadata.
|
|
58
|
+
*/
|
|
59
|
+
export declare function schemaFromParams(params: McpToolParam[]): JsonSchema;
|
|
60
|
+
/**
|
|
61
|
+
* Informational only — whether the CONFIGURED host looks local.
|
|
62
|
+
*
|
|
63
|
+
* NOT the security gate. Reads `TINA4_HOST_NAME` (the configured bind address),
|
|
64
|
+
* which on a 0.0.0.0 bind looks "local" while still accepting remote clients.
|
|
65
|
+
* Trust decisions use {@link isRequestAllowed} with the RAW socket peer instead.
|
|
66
|
+
* Kept for diagnostics / back-compat.
|
|
67
|
+
*/
|
|
68
|
+
export declare function isLocalhost(): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Whether an address is a loopback (in-process / same-host) peer.
|
|
71
|
+
*
|
|
72
|
+
* Operates on the RAW socket peer, never X-Forwarded-For. Empty/undefined means
|
|
73
|
+
* an in-process / synthetic request (no socket) and is trusted. The `::ffff:`
|
|
74
|
+
* IPv4-mapped prefix is stripped. NOTE: 0.0.0.0 is a BIND address, never a
|
|
75
|
+
* client address, so it is deliberately NOT loopback.
|
|
76
|
+
*
|
|
77
|
+
* Python master parity: tina4_python.mcp.is_loopback.
|
|
78
|
+
*/
|
|
79
|
+
export declare function isLoopback(ip: string | undefined | null): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Capability gate — whether MCP may run at all.
|
|
82
|
+
*
|
|
83
|
+
* Pure capability, host-INDEPENDENT (Python master parity):
|
|
84
|
+
* 1. `TINA4_MCP` explicit on/off override (sysadmin, any host).
|
|
85
|
+
* 2. Else `TINA4_DEBUG=true` → MCP is a capability of this deployment.
|
|
86
|
+
* 3. Otherwise off.
|
|
87
|
+
*
|
|
88
|
+
* This NO LONGER consults the host. A debug box bound to 0.0.0.0 still "has"
|
|
89
|
+
* the capability, but {@link isRequestAllowed} decides whether a given CALLER
|
|
90
|
+
* may use it — loopback always, remote only with an explicit opt-in plus a
|
|
91
|
+
* valid token. Splitting capability from per-request authorisation closes the
|
|
92
|
+
* hole where a 0.0.0.0 bind auto-exposed DB/file tools to remote
|
|
93
|
+
* unauthenticated callers (the pre-3.13.40 isLocalhost() treated 0.0.0.0 local).
|
|
94
|
+
*/
|
|
95
|
+
export declare function mcpEnabled(): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Per-request authorisation — whether THIS caller may use MCP.
|
|
98
|
+
*
|
|
99
|
+
* @param remoteIp Raw socket peer (`req.socket.remoteAddress`), never XFF.
|
|
100
|
+
* @param hasValidToken True when the request carried a token matching TINA4_MCP_TOKEN.
|
|
101
|
+
*
|
|
102
|
+
* Rules (Python master parity, tina4_python.mcp.is_request_allowed):
|
|
103
|
+
* - Capability off ({@link mcpEnabled} false) → deny.
|
|
104
|
+
* - Loopback peer → allow.
|
|
105
|
+
* - Remote peer → only when TINA4_MCP_REMOTE is truthy AND a valid token was
|
|
106
|
+
* presented. No configured token ⇒ remote can never pass.
|
|
107
|
+
*/
|
|
108
|
+
export declare function isRequestAllowed(remoteIp: string | undefined | null, hasValidToken?: boolean): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Resolve the MCP HTTP port. Default: HTTP server port + 2000.
|
|
111
|
+
*
|
|
112
|
+
* `TINA4_MCP_PORT` overrides directly. The `mainPort` argument is the
|
|
113
|
+
* primary HTTP port (the framework passes `port` from `resolvePortAndHost`).
|
|
114
|
+
*/
|
|
115
|
+
export declare function mcpPort(mainPort?: number): number;
|
|
116
|
+
export declare class McpServer {
|
|
117
|
+
static _instances: McpServer[];
|
|
118
|
+
path: string;
|
|
119
|
+
name: string;
|
|
120
|
+
version: string;
|
|
121
|
+
private _tools;
|
|
122
|
+
private _resources;
|
|
123
|
+
private _initialized;
|
|
124
|
+
private _sessions;
|
|
125
|
+
private _sseChannels;
|
|
126
|
+
constructor(mcpPath: string, name?: string, version?: string);
|
|
127
|
+
/** Mint a new session id and remember it. Called on `initialize`. */
|
|
128
|
+
openSession(): string;
|
|
129
|
+
/** True when `sessionId` was issued by this server and is still open. */
|
|
130
|
+
isValidSession(sessionId: string | undefined | null): boolean;
|
|
131
|
+
/** Forget a session (client DELETE or SSE stream close). */
|
|
132
|
+
closeSession(sessionId: string | undefined | null): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Pick the protocol version to run on. Echo the client's requested version
|
|
135
|
+
* when we support it (proper negotiation), else fall back to the newest we
|
|
136
|
+
* speak so an unversioned/old client still connects.
|
|
137
|
+
*/
|
|
138
|
+
negotiateProtocolVersion(requested: string | undefined | null): string;
|
|
139
|
+
private _peekMethod;
|
|
140
|
+
/**
|
|
141
|
+
* Streamable HTTP POST handler. initialize mints a session id (returned in
|
|
142
|
+
* the Mcp-Session-Id response header); a non-initialize request with an
|
|
143
|
+
* unknown session id is a 404 (client re-inits); a notification is 202; else
|
|
144
|
+
* 200 with the JSON-RPC response as application/json (which the spec permits
|
|
145
|
+
* for a POST that resolves to a single response).
|
|
146
|
+
*/
|
|
147
|
+
dispatchHttp(raw: string | Record<string, unknown>, sessionId?: string): Promise<{
|
|
148
|
+
status: number;
|
|
149
|
+
headers: Record<string, string>;
|
|
150
|
+
body: string;
|
|
151
|
+
}>;
|
|
152
|
+
/**
|
|
153
|
+
* Legacy HTTP+SSE POST /message handler. When a live SSE stream is open for
|
|
154
|
+
* `sessionId`, run the message and push the response down that stream (202
|
|
155
|
+
* here); with no open stream it degrades to an inline Streamable HTTP
|
|
156
|
+
* response, so the same path serves a legacy SSE client and a plain POST.
|
|
157
|
+
*/
|
|
158
|
+
dispatchSseMessage(raw: string | Record<string, unknown>, sessionId?: string): Promise<{
|
|
159
|
+
status: number;
|
|
160
|
+
headers: Record<string, string>;
|
|
161
|
+
body: string;
|
|
162
|
+
}>;
|
|
163
|
+
/**
|
|
164
|
+
* Async generator of SSE frames for the legacy HTTP+SSE transport. Emits the
|
|
165
|
+
* `endpoint` event first (naming the POST target), then each queued JSON-RPC
|
|
166
|
+
* response as it arrives, with periodic keep-alive comments. Registers the
|
|
167
|
+
* per-session channel up front and tears it down (plus the session) when the
|
|
168
|
+
* client disconnects and the generator is closed.
|
|
169
|
+
*/
|
|
170
|
+
sseStream(sessionId: string, endpointUrl: string, keepaliveMs?: number): AsyncGenerator<string>;
|
|
171
|
+
registerTool(name: string, handler: (args: Record<string, unknown>) => unknown, description?: string, schema?: JsonSchema): void;
|
|
172
|
+
registerResource(uri: string, handler: () => unknown, description?: string, mimeType?: string): void;
|
|
173
|
+
handleMessage(rawData: string | Record<string, unknown>): Promise<string>;
|
|
174
|
+
private _handleInitialize;
|
|
175
|
+
private _handleInitialized;
|
|
176
|
+
private _handlePing;
|
|
177
|
+
private _handleToolsList;
|
|
178
|
+
private _handleToolsCall;
|
|
179
|
+
private _handleResourcesList;
|
|
180
|
+
private _handleResourcesRead;
|
|
181
|
+
/** Coerce a route handler's parsed body into what the dispatchers accept. */
|
|
182
|
+
private _normalizeBody;
|
|
183
|
+
/**
|
|
184
|
+
* Register HTTP routes for this MCP server on the Tina4 router. Mounts both
|
|
185
|
+
* supported transports on `path`:
|
|
186
|
+
* POST {path} — Streamable HTTP (current transport)
|
|
187
|
+
* POST {path}/message — legacy HTTP+SSE message sink (+ inline fallback)
|
|
188
|
+
* GET {path}/sse — legacy HTTP+SSE stream (persistent)
|
|
189
|
+
*
|
|
190
|
+
* A Streamable HTTP client (Claude Code `--transport http`) POSTs to `{path}`
|
|
191
|
+
* and reads the JSON-RPC response inline, with an Mcp-Session-Id header on
|
|
192
|
+
* initialize. A legacy SSE client GETs `{path}/sse`, gets the endpoint event,
|
|
193
|
+
* and its responses stream back on that connection.
|
|
194
|
+
*/
|
|
195
|
+
registerRoutes(router: {
|
|
196
|
+
post: (pattern: string, handler: (req: unknown, res: unknown) => unknown) => {
|
|
197
|
+
noAuth: () => unknown;
|
|
198
|
+
};
|
|
199
|
+
get: (pattern: string, handler: (req: unknown, res: unknown) => unknown) => {
|
|
200
|
+
noAuth: () => unknown;
|
|
201
|
+
};
|
|
202
|
+
}): void;
|
|
203
|
+
/**
|
|
204
|
+
* Write/update .claude/settings.json with this MCP server config.
|
|
205
|
+
*/
|
|
206
|
+
writeClaudeConfig(port?: number): void;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* The default `/__dev/mcp` MCP server with the built-in dev tools registered.
|
|
210
|
+
*
|
|
211
|
+
* This is the single shared instance backing BOTH the browser REST shim
|
|
212
|
+
* (`/__dev/api/mcp/tools` + `/__dev/api/mcp/call`) and the JSON-RPC + SSE
|
|
213
|
+
* endpoints (`/__dev/mcp[/message]` + `/__dev/mcp/sse`) that real MCP clients
|
|
214
|
+
* (Claude Code/Desktop) speak. Tools are registered exactly once (idempotent).
|
|
215
|
+
* Mirrors Python's default MCP server used by `get_api_handlers()`.
|
|
216
|
+
*/
|
|
217
|
+
export declare function getDefaultDevServer(): McpServer;
|
|
218
|
+
/**
|
|
219
|
+
* Register a function as an MCP tool.
|
|
220
|
+
*
|
|
221
|
+
* Usage:
|
|
222
|
+
* const greet = mcpTool("greet", "Say hello", server, [
|
|
223
|
+
* { name: "name", type: "string" },
|
|
224
|
+
* ])((args) => `Hello, ${args.name}!`);
|
|
225
|
+
*
|
|
226
|
+
* Returns the original function with _mcpToolName attached.
|
|
227
|
+
*/
|
|
228
|
+
export declare function mcpTool(name: string, description?: string, server?: McpServer, params?: McpToolParam[]): <T extends (args: Record<string, unknown>) => unknown>(fn: T) => T & {
|
|
229
|
+
_mcpToolName: string;
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Register a function as an MCP resource.
|
|
233
|
+
*
|
|
234
|
+
* Usage:
|
|
235
|
+
* const tables = mcpResource("app://tables", "Database tables", "application/json", server)(
|
|
236
|
+
* () => ["users", "products"]
|
|
237
|
+
* );
|
|
238
|
+
*/
|
|
239
|
+
export declare function mcpResource(uri: string, description?: string, mimeType?: string, server?: McpServer): <T extends () => unknown>(fn: T) => T & {
|
|
240
|
+
_mcpResourceUri: string;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
243
|
+
* Register all built-in dev tools on the given McpServer (the api_* reflection
|
|
244
|
+
* tools plus code_search, the fuzzy FTS grounding tool).
|
|
245
|
+
*/
|
|
246
|
+
export declare function registerDevTools(server: McpServer): void;
|
|
247
|
+
/** Alias for registerDevTools — parity with PHP/Ruby/Python. */
|
|
248
|
+
export declare const register: typeof registerDevTools;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { DevMailbox } from "./devMailbox.js";
|
|
2
|
+
export interface SendResult {
|
|
3
|
+
success: boolean;
|
|
4
|
+
message: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Raised when an IMAP read fails to connect, authenticate, or speak the
|
|
9
|
+
* protocol (a `NO`/`BAD` tagged response, a refused/reset socket, a TLS or
|
|
10
|
+
* DNS failure). Distinct from a SUCCESSFUL fetch that simply has no messages —
|
|
11
|
+
* that still returns an empty result ([] / 0 / {}), NOT an error.
|
|
12
|
+
*
|
|
13
|
+
* inbox()/read()/unread()/search()/folders() LOG and then RAISE this on a
|
|
14
|
+
* connection/protocol failure so a dead mailbox is never silently mistaken for
|
|
15
|
+
* an empty one. send() is unchanged — it keeps returning { success, error }.
|
|
16
|
+
*/
|
|
17
|
+
export declare class MessengerConnectionError extends Error {
|
|
18
|
+
constructor(message: string);
|
|
19
|
+
}
|
|
20
|
+
export interface EmailMessage {
|
|
21
|
+
id: string;
|
|
22
|
+
type: "inbox" | "outbox";
|
|
23
|
+
from: string;
|
|
24
|
+
to: string[];
|
|
25
|
+
cc: string[];
|
|
26
|
+
bcc: string[];
|
|
27
|
+
reply_to?: string;
|
|
28
|
+
subject: string;
|
|
29
|
+
body: string;
|
|
30
|
+
/** Plain-text alternative. Carried on the dev path too, so the captured message
|
|
31
|
+
* is the message: a mailbox that shows you something other than what you wrote
|
|
32
|
+
* is worse than no mailbox. */
|
|
33
|
+
text?: string;
|
|
34
|
+
html: boolean;
|
|
35
|
+
attachments: string[];
|
|
36
|
+
date: string;
|
|
37
|
+
read: boolean;
|
|
38
|
+
}
|
|
39
|
+
interface MessengerOptions {
|
|
40
|
+
host?: string;
|
|
41
|
+
port?: number;
|
|
42
|
+
username?: string;
|
|
43
|
+
password?: string;
|
|
44
|
+
fromAddress?: string;
|
|
45
|
+
fromName?: string;
|
|
46
|
+
encryption?: string;
|
|
47
|
+
/** @deprecated Use encryption instead */
|
|
48
|
+
useTls?: boolean;
|
|
49
|
+
imapHost?: string;
|
|
50
|
+
imapPort?: number;
|
|
51
|
+
imapUser?: string;
|
|
52
|
+
imapPass?: string;
|
|
53
|
+
/** IMAP transport security: "tls" (default), "starttls", or "none". */
|
|
54
|
+
imapEncryption?: string;
|
|
55
|
+
}
|
|
56
|
+
export interface ImapMessage {
|
|
57
|
+
uid: string;
|
|
58
|
+
subject: string;
|
|
59
|
+
from: string;
|
|
60
|
+
to: string;
|
|
61
|
+
date: string;
|
|
62
|
+
snippet: string;
|
|
63
|
+
seen: boolean;
|
|
64
|
+
}
|
|
65
|
+
export interface ImapFullMessage {
|
|
66
|
+
uid: string;
|
|
67
|
+
subject: string;
|
|
68
|
+
from: string;
|
|
69
|
+
to: string;
|
|
70
|
+
cc: string;
|
|
71
|
+
date: string;
|
|
72
|
+
bodyText: string;
|
|
73
|
+
bodyHtml: string;
|
|
74
|
+
headers: Record<string, string>;
|
|
75
|
+
}
|
|
76
|
+
export declare class Messenger {
|
|
77
|
+
private host;
|
|
78
|
+
private port;
|
|
79
|
+
private username;
|
|
80
|
+
private password;
|
|
81
|
+
private fromAddress;
|
|
82
|
+
private fromName;
|
|
83
|
+
private encryption;
|
|
84
|
+
private useTls;
|
|
85
|
+
/** Whether an SMTP host was actually configured (see the constructor). */
|
|
86
|
+
private smtpConfigured;
|
|
87
|
+
/** The local mailbox, present only when this messenger captures. */
|
|
88
|
+
devMailbox: DevMailbox | null;
|
|
89
|
+
private imapHost;
|
|
90
|
+
private imapPort;
|
|
91
|
+
private imapUser;
|
|
92
|
+
private imapPass;
|
|
93
|
+
private imapEncryption;
|
|
94
|
+
constructor(options?: MessengerOptions);
|
|
95
|
+
/**
|
|
96
|
+
* Read-only IMAP encryption mode for inspection / tests.
|
|
97
|
+
* Returns one of "tls", "starttls", "none", "ssl".
|
|
98
|
+
*/
|
|
99
|
+
getImapEncryption(): string;
|
|
100
|
+
/**
|
|
101
|
+
* Send an email via SMTP.
|
|
102
|
+
*/
|
|
103
|
+
/**
|
|
104
|
+
* Should send() capture locally instead of talking to SMTP?
|
|
105
|
+
*
|
|
106
|
+
* Availability decides, not verbosity. With no SMTP host configured sending is
|
|
107
|
+
* impossible, so simulate it into a folder rather than failing -- that is what
|
|
108
|
+
* makes a laptop with no mail server usable. TINA4_MAIL_CAPTURE forces capture
|
|
109
|
+
* even when a host IS configured.
|
|
110
|
+
*
|
|
111
|
+
* TINA4_DEBUG deliberately does NOT gate this, and neither does NODE_ENV. Debug
|
|
112
|
+
* must still be able to send, and the old `NODE_ENV !== "production"` clause
|
|
113
|
+
* silently swallowed every staging email.
|
|
114
|
+
*/
|
|
115
|
+
private shouldCapture;
|
|
116
|
+
/** The local mailbox, created on first capture and reused after. */
|
|
117
|
+
private getDevMailbox;
|
|
118
|
+
send(to: string | string[], subject: string, body: string, html?: boolean, text?: string, cc?: string | string[], bcc?: string | string[], replyTo?: string, attachments?: string[], headers?: Record<string, string>): Promise<SendResult>;
|
|
119
|
+
/**
|
|
120
|
+
* Test the SMTP connection without sending an email.
|
|
121
|
+
*/
|
|
122
|
+
testConnection(): Promise<{
|
|
123
|
+
success: boolean;
|
|
124
|
+
message: string;
|
|
125
|
+
}>;
|
|
126
|
+
/**
|
|
127
|
+
* Connect to the IMAP server via raw TCP/TLS.
|
|
128
|
+
* Returns the socket and reads the greeting.
|
|
129
|
+
*/
|
|
130
|
+
private imapConnect;
|
|
131
|
+
/**
|
|
132
|
+
* Disconnect from IMAP cleanly.
|
|
133
|
+
*/
|
|
134
|
+
private imapDisconnect;
|
|
135
|
+
/**
|
|
136
|
+
* Fetch latest messages from a folder.
|
|
137
|
+
* Returns list of message summaries.
|
|
138
|
+
*/
|
|
139
|
+
inbox(folder?: string, limit?: number, offset?: number): Promise<ImapMessage[]>;
|
|
140
|
+
/**
|
|
141
|
+
* Read a single message by sequence number or UID.
|
|
142
|
+
*/
|
|
143
|
+
read(uid: string, folder?: string): Promise<ImapFullMessage | null>;
|
|
144
|
+
/**
|
|
145
|
+
* Search messages using IMAP search criteria.
|
|
146
|
+
*/
|
|
147
|
+
search(folder?: string, subject?: string, sender?: string, since?: string, before?: string, unseenOnly?: boolean, limit?: number): Promise<ImapMessage[]>;
|
|
148
|
+
/**
|
|
149
|
+
* Delete a message by UID.
|
|
150
|
+
*/
|
|
151
|
+
deleteMessage(uid: string, folder?: string): Promise<void>;
|
|
152
|
+
/**
|
|
153
|
+
* Mark a message as read.
|
|
154
|
+
*/
|
|
155
|
+
markRead(uid: string, folder?: string): Promise<void>;
|
|
156
|
+
/**
|
|
157
|
+
* Count unseen messages in a folder.
|
|
158
|
+
*/
|
|
159
|
+
unread(folder?: string): Promise<number>;
|
|
160
|
+
/**
|
|
161
|
+
* List available IMAP folders/mailboxes.
|
|
162
|
+
*/
|
|
163
|
+
folders(): Promise<string[]>;
|
|
164
|
+
/**
|
|
165
|
+
* Test IMAP connectivity without reading.
|
|
166
|
+
*/
|
|
167
|
+
testImapConnection(): Promise<{
|
|
168
|
+
success: boolean;
|
|
169
|
+
message: string;
|
|
170
|
+
}>;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Create a Messenger configured for the current environment.
|
|
174
|
+
*
|
|
175
|
+
* Returns ONE concrete type, always. It used to return `Messenger | DevMailbox`,
|
|
176
|
+
* and those two shared NO sending method -- DevMailbox has capture(), Messenger has
|
|
177
|
+
* send() -- so the documented call threw TypeError whenever the dev branch was
|
|
178
|
+
* taken. That is nodejs#41. Capture is now a branch inside Messenger.send(), so the
|
|
179
|
+
* object you get back has one send() with one signature either way.
|
|
180
|
+
*
|
|
181
|
+
* The gate is availability, not verbosity:
|
|
182
|
+
* - no TINA4_MAIL_HOST -> capture (sending is impossible, so simulate it)
|
|
183
|
+
* - TINA4_MAIL_CAPTURE truthy -> capture even with SMTP configured
|
|
184
|
+
* - otherwise -> send, EVEN WITH TINA4_DEBUG ON
|
|
185
|
+
*
|
|
186
|
+
* TINA4_DEBUG no longer forces capture: debug must still be able to send real mail.
|
|
187
|
+
* The `NODE_ENV !== "production"` clause is also gone -- it captured even with SMTP
|
|
188
|
+
* configured and debug off, which silently ate every staging email.
|
|
189
|
+
*/
|
|
190
|
+
export declare function createMessenger(): Messenger;
|
|
191
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare function quickMetrics(root?: string): Record<string, any>;
|
|
2
|
+
/**
|
|
3
|
+
* The native metrics engine could not produce a payload.
|
|
4
|
+
*
|
|
5
|
+
* Thrown instead of falling back to a second implementation.
|
|
6
|
+
*/
|
|
7
|
+
export declare class MetricsEngineError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
export declare const SEVERITY_RANK: Record<string, number>;
|
|
11
|
+
/**
|
|
12
|
+
* Return [directory to scan, scanMode] for any metrics producer.
|
|
13
|
+
*
|
|
14
|
+
* The engine is language-agnostic and cannot know which directory holds a
|
|
15
|
+
* framework package, so root resolution and the "framework" label stay here,
|
|
16
|
+
* shared by the census and the engine adapter so the two never disagree.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveScanTarget(root?: string): [string, string];
|
|
19
|
+
/** Absolute path to the tina4 CLI binary, or null when it is not installed. */
|
|
20
|
+
export declare function enginePath(): string | null;
|
|
21
|
+
/** Full code analysis from the native engine, shaped for the dashboard. */
|
|
22
|
+
export declare function fullAnalysis(root?: string): Record<string, any>;
|
|
23
|
+
export interface OffendersResult {
|
|
24
|
+
offenders: Record<string, any>[];
|
|
25
|
+
summary: Record<string, any>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Top code-health offenders from the native engine.
|
|
29
|
+
*
|
|
30
|
+
* The engine ranks and severity-tags them, and its own --fail-on gate reads the
|
|
31
|
+
* same list, so the CLI and the dashboard can never disagree about what counts
|
|
32
|
+
* as an offender.
|
|
33
|
+
*/
|
|
34
|
+
export declare function offenders(root?: string, top?: number): OffendersResult;
|
|
35
|
+
/**
|
|
36
|
+
* Per-file metrics from the native engine.
|
|
37
|
+
*
|
|
38
|
+
* The engine accepts a single file for --path, so one code path serves both the
|
|
39
|
+
* whole-tree scan and one file.
|
|
40
|
+
*/
|
|
41
|
+
export declare function fileDetail(filePath: string): Record<string, any>;
|