tina4-nodejs 3.13.137 → 3.13.139
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 +33 -3
- package/COMMERCIAL-LICENSE.md +8 -0
- package/LICENSE +373 -0
- package/NOTICE +11 -0
- package/README.md +24 -2
- package/package.json +44 -6
- package/packages/cli/dist/bin.js +19979 -18102
- package/packages/cli/src/bin.ts +8 -0
- package/packages/cli/src/commands/build.ts +8 -0
- package/packages/cli/src/commands/generate.ts +8 -0
- package/packages/cli/src/commands/init.ts +8 -0
- package/packages/cli/src/commands/lint.ts +8 -0
- package/packages/cli/src/commands/migrate.ts +8 -0
- package/packages/cli/src/commands/migrateCreate.ts +8 -0
- package/packages/cli/src/commands/migrateRollback.ts +8 -0
- package/packages/cli/src/commands/migrateStatus.ts +8 -0
- package/packages/cli/src/commands/queue.ts +8 -0
- package/packages/cli/src/commands/routes.ts +8 -0
- package/packages/cli/src/commands/seed.ts +8 -0
- package/packages/cli/src/commands/serve.ts +11 -0
- package/packages/cli/src/commands/test.ts +8 -0
- package/packages/core/dist/index.js +19976 -18097
- package/packages/core/gallery/auth/src/routes/api/gallery/auth/login/post.ts +8 -0
- package/packages/core/gallery/auth/src/routes/api/gallery/auth/verify/get.ts +8 -0
- package/packages/core/gallery/auth/src/routes/gallery/auth/get.ts +8 -0
- package/packages/core/gallery/database/src/routes/api/gallery/db/notes/get.ts +8 -0
- package/packages/core/gallery/database/src/routes/api/gallery/db/notes/post.ts +8 -0
- package/packages/core/gallery/database/src/routes/api/gallery/db/tables/get.ts +8 -0
- package/packages/core/gallery/error-overlay/src/routes/api/gallery/crash/get.ts +8 -0
- package/packages/core/gallery/orm/src/routes/api/gallery/products/get.ts +8 -0
- package/packages/core/gallery/orm/src/routes/api/gallery/products/post.ts +8 -0
- package/packages/core/gallery/queue/src/lib/queueDb.ts +8 -0
- package/packages/core/gallery/queue/src/routes/api/gallery/queue/consume/post.ts +8 -0
- package/packages/core/gallery/queue/src/routes/api/gallery/queue/fail/post.ts +8 -0
- package/packages/core/gallery/queue/src/routes/api/gallery/queue/produce/post.ts +8 -0
- package/packages/core/gallery/queue/src/routes/api/gallery/queue/retry/post.ts +8 -0
- package/packages/core/gallery/queue/src/routes/api/gallery/queue/status/get.ts +8 -0
- package/packages/core/gallery/queue/src/routes/gallery/queue/get.ts +8 -0
- package/packages/core/gallery/rest-api/src/routes/api/gallery/hello/get.ts +8 -0
- package/packages/core/gallery/rest-api/src/routes/api/gallery/hello/post.ts +8 -0
- package/packages/core/gallery/templates/src/routes/gallery/page/get.ts +8 -0
- package/packages/core/gallery/templates/src/templates/gallery_page.twig +8 -0
- package/packages/core/public/THIRD-PARTY-NOTICES.md +55 -0
- package/packages/core/public/bundled-component-provenance.json +48 -0
- package/packages/core/public/js/tina4js.min.js +13 -3
- package/packages/core/public/licenses/swagger-ui-3.10.0-original-notice.txt +11 -0
- package/packages/core/public/licenses/swagger-ui-5.17.14-NOTICE.txt +2 -0
- package/packages/core/public/licenses/swagger-ui-Apache-2.0.txt +202 -0
- package/packages/core/public/licenses/tina4-css-MIT.txt +21 -0
- package/packages/core/public/licenses/tina4-dev-admin-components.json +240 -0
- package/packages/core/public/licenses/tina4-dev-admin-third-party.txt +919 -0
- package/packages/core/public/licenses/tina4-js-MIT.txt +20 -0
- package/packages/core/src/__feedback/widget.js +8 -0
- package/packages/core/src/_missing.ts +8 -0
- package/packages/core/src/ai.ts +8 -0
- package/packages/core/src/aiClient.ts +8 -0
- package/packages/core/src/api.ts +48 -7
- package/packages/core/src/auth.ts +94 -14
- package/packages/core/src/authGate.ts +35 -20
- package/packages/core/src/background.ts +8 -0
- package/packages/core/src/cache.ts +43 -4
- package/packages/core/src/constants.ts +8 -0
- package/packages/core/src/container.ts +8 -0
- package/packages/core/src/context/chunker.ts +8 -0
- package/packages/core/src/context/index.ts +8 -0
- package/packages/core/src/devAdmin.ts +185 -59
- package/packages/core/src/devMailbox.ts +8 -0
- package/packages/core/src/dispatchPipeline.ts +8 -0
- package/packages/core/src/docs.ts +8 -0
- package/packages/core/src/docsAutoDiscovery.ts +8 -0
- package/packages/core/src/docsParser.ts +8 -0
- package/packages/core/src/docsScanner.ts +44 -0
- package/packages/core/src/docsSignatures.ts +8 -0
- package/packages/core/src/dotenv.ts +8 -0
- package/packages/core/src/env.ts +8 -0
- package/packages/core/src/errorOverlay.ts +8 -0
- package/packages/core/src/events.ts +8 -0
- package/packages/core/src/fakeData.ts +8 -0
- package/packages/core/src/feedback.ts +8 -0
- package/packages/core/src/graphql.ts +108 -5
- package/packages/core/src/health.ts +8 -0
- package/packages/core/src/htmlElement.ts +8 -0
- package/packages/core/src/i18n.ts +8 -0
- package/packages/core/src/index.ts +9 -0
- package/packages/core/src/job.ts +16 -1
- package/packages/core/src/logger.ts +8 -0
- package/packages/core/src/mcp.test.ts +8 -0
- package/packages/core/src/mcp.ts +11 -1
- package/packages/core/src/messenger.ts +143 -86
- package/packages/core/src/metrics.ts +13 -0
- package/packages/core/src/middleware.ts +1181 -1097
- package/packages/core/src/mqtt.ts +8 -0
- package/packages/core/src/mqttMessage.ts +8 -0
- package/packages/core/src/optionalPackage.ts +48 -0
- package/packages/core/src/plan.ts +8 -0
- package/packages/core/src/portTakeover.ts +8 -0
- package/packages/core/src/projectIndex.ts +8 -0
- package/packages/core/src/projectIndexExtractors.ts +8 -0
- package/packages/core/src/projectIndexStorage.ts +8 -0
- package/packages/core/src/push.ts +24 -0
- package/packages/core/src/queue.ts +23 -2
- package/packages/core/src/queueBackends/kafkaBackend.ts +8 -0
- package/packages/core/src/queueBackends/liteBackend.ts +23 -0
- package/packages/core/src/queueBackends/mongoBackend.ts +61 -14
- package/packages/core/src/queueBackends/rabbitmqBackend.ts +8 -0
- package/packages/core/src/rateLimiter.ts +8 -0
- package/packages/core/src/request.ts +59 -10
- package/packages/core/src/response.ts +79 -5
- package/packages/core/src/routeDiscovery.ts +8 -0
- package/packages/core/src/router.ts +8 -0
- package/packages/core/src/server.ts +79 -25
- package/packages/core/src/service.ts +8 -0
- package/packages/core/src/session.ts +8 -0
- package/packages/core/src/sessionHandlers/childError.ts +8 -0
- package/packages/core/src/sessionHandlers/databaseHandler.ts +68 -3
- package/packages/core/src/sessionHandlers/memcachedHandler.ts +8 -0
- package/packages/core/src/sessionHandlers/mongoClient.ts +8 -0
- package/packages/core/src/sessionHandlers/mongoHandler.ts +8 -0
- package/packages/core/src/sessionHandlers/respClient.ts +8 -0
- package/packages/core/src/sessionHandlers/sqlClient.ts +8 -0
- package/packages/core/src/sessionHandlers/syncBridge.ts +8 -0
- package/packages/core/src/sessionHandlers/syncSocket.ts +8 -0
- package/packages/core/src/sessionHandlers/valkeyHandler.ts +8 -0
- package/packages/core/src/sso.ts +20 -4
- package/packages/core/src/ssoIdentity.ts +19 -0
- package/packages/core/src/ssrf.ts +221 -0
- package/packages/core/src/static.ts +8 -0
- package/packages/core/src/test.ts +8 -0
- package/packages/core/src/testClient.ts +11 -0
- package/packages/core/src/testing.ts +8 -0
- package/packages/core/src/transport.ts +369 -0
- package/packages/core/src/trustedProxy.ts +8 -0
- package/packages/core/src/types.ts +13 -0
- package/packages/core/src/validator.ts +8 -0
- package/packages/core/src/version.ts +8 -0
- package/packages/core/src/websocket.ts +12 -2
- package/packages/core/src/websocketBackplane.ts +49 -32
- package/packages/core/src/websocketConnection.ts +8 -0
- package/packages/core/src/wsdl.ts +197 -115
- package/packages/core/templates/errors/302.twig +8 -0
- package/packages/core/templates/errors/401.twig +8 -0
- package/packages/core/templates/errors/403.twig +8 -0
- package/packages/core/templates/errors/404.twig +8 -0
- package/packages/core/templates/errors/500.twig +8 -0
- package/packages/core/templates/errors/502.twig +8 -0
- package/packages/core/templates/errors/503.twig +8 -0
- package/packages/core/templates/errors/base.twig +8 -0
- package/packages/frond/dist/index.js +157 -17
- package/packages/frond/src/engine.ts +186 -17
- package/packages/frond/src/index.ts +8 -0
- package/packages/orm/dist/index.js +8641 -6765
- package/packages/orm/src/adapters/firebird.ts +50 -3
- package/packages/orm/src/adapters/mongodb.ts +8 -0
- package/packages/orm/src/adapters/mssql.ts +29 -7
- package/packages/orm/src/adapters/mysql.ts +17 -1
- package/packages/orm/src/adapters/odbc.ts +11 -0
- package/packages/orm/src/adapters/pg-types.d.ts +8 -0
- package/packages/orm/src/adapters/postgres.ts +34 -8
- package/packages/orm/src/adapters/sqlDialect.ts +57 -0
- package/packages/orm/src/adapters/sqlite.ts +26 -0
- package/packages/orm/src/autoCrud.ts +78 -36
- package/packages/orm/src/baseModel.ts +61 -29
- package/packages/orm/src/cachedDatabase.ts +67 -1
- package/packages/orm/src/connectTimeout.ts +8 -0
- package/packages/orm/src/database.ts +649 -401
- package/packages/orm/src/databaseResult.ts +8 -0
- package/packages/orm/src/databaseUrl.ts +8 -0
- package/packages/orm/src/docstore.ts +23 -1
- package/packages/orm/src/fakeData.ts +8 -0
- package/packages/orm/src/graph/adapters/arango.ts +8 -0
- package/packages/orm/src/graph/adapters/bolt.ts +8 -0
- package/packages/orm/src/graph/adapters/ultipa.ts +8 -0
- package/packages/orm/src/graph/connectTimeout.ts +8 -0
- package/packages/orm/src/graph/errors.ts +8 -0
- package/packages/orm/src/graph/graphAdapter.ts +8 -0
- package/packages/orm/src/graph/graphDatabase.ts +8 -0
- package/packages/orm/src/graph/graphUrl.ts +10 -1
- package/packages/orm/src/graph/shapes.ts +8 -0
- package/packages/orm/src/index.ts +147 -139
- package/packages/orm/src/migration.ts +8 -0
- package/packages/orm/src/model.ts +8 -0
- package/packages/orm/src/modelCollection.ts +8 -0
- package/packages/orm/src/point.ts +8 -0
- package/packages/orm/src/query.ts +149 -33
- package/packages/orm/src/queryBuilder.ts +8 -0
- package/packages/orm/src/realtime/index.ts +8 -0
- package/packages/orm/src/realtime/models/attachment.ts +8 -0
- package/packages/orm/src/realtime/models/channel.ts +8 -0
- package/packages/orm/src/realtime/models/channelMember.ts +8 -0
- package/packages/orm/src/realtime/models/message.ts +8 -0
- package/packages/orm/src/realtime/models/workspace.ts +8 -0
- package/packages/orm/src/realtime/realtime.ts +8 -0
- package/packages/orm/src/realtime/storage.ts +43 -12
- package/packages/orm/src/seeder.ts +8 -0
- package/packages/orm/src/seederTable.ts +8 -0
- package/packages/orm/src/seederTypes.ts +8 -0
- package/packages/orm/src/sqlTranslator.ts +185 -8
- package/packages/orm/src/types.ts +15 -0
- package/packages/orm/src/validation.ts +8 -0
- package/packages/swagger/src/generator.ts +8 -0
- package/packages/swagger/src/index.ts +8 -0
- package/packages/swagger/src/ui.ts +8 -0
- package/types/core/src/api.d.ts +6 -0
- package/types/core/src/auth.d.ts +30 -0
- package/types/core/src/background.d.ts +0 -16
- package/types/core/src/cache.d.ts +6 -0
- package/types/core/src/devAdmin.d.ts +18 -12
- package/types/core/src/docs.d.ts +0 -17
- package/types/core/src/errorOverlay.d.ts +0 -24
- package/types/core/src/events.d.ts +0 -12
- package/types/core/src/feedback.d.ts +0 -23
- package/types/core/src/graphql.d.ts +25 -21
- package/types/core/src/htmlElement.d.ts +0 -15
- package/types/core/src/index.d.ts +1 -0
- package/types/core/src/job.d.ts +1 -0
- package/types/core/src/messenger.d.ts +12 -1
- package/types/core/src/metrics.d.ts +2 -0
- package/types/core/src/middleware.d.ts +45 -1
- package/types/core/src/mqtt.d.ts +0 -33
- package/types/core/src/optionalPackage.d.ts +25 -0
- package/types/core/src/plan.d.ts +0 -10
- package/types/core/src/projectIndex.d.ts +0 -10
- package/types/core/src/push.d.ts +5 -0
- package/types/core/src/queue.d.ts +7 -1
- package/types/core/src/queueBackends/liteBackend.d.ts +9 -0
- package/types/core/src/queueBackends/mongoBackend.d.ts +10 -1
- package/types/core/src/request.d.ts +12 -0
- package/types/core/src/response.d.ts +13 -0
- package/types/core/src/server.d.ts +19 -0
- package/types/core/src/sessionHandlers/childError.d.ts +0 -15
- package/types/core/src/sessionHandlers/databaseHandler.d.ts +25 -1
- package/types/core/src/sso.d.ts +1 -0
- package/types/core/src/ssoIdentity.d.ts +10 -0
- package/types/core/src/ssrf.d.ts +19 -0
- package/types/core/src/transport.d.ts +28 -0
- package/types/core/src/trustedProxy.d.ts +0 -16
- package/types/core/src/types.d.ts +5 -0
- package/types/core/src/websocketBackplane.d.ts +1 -0
- package/types/core/src/wsdl.d.ts +8 -22
- package/types/frond/src/engine.d.ts +7 -1
- package/types/orm/src/adapters/firebird.d.ts +12 -0
- package/types/orm/src/adapters/mssql.d.ts +11 -0
- package/types/orm/src/adapters/mysql.d.ts +2 -0
- package/types/orm/src/adapters/postgres.d.ts +11 -0
- package/types/orm/src/adapters/sqlDialect.d.ts +25 -0
- package/types/orm/src/adapters/sqlite.d.ts +7 -0
- package/types/orm/src/baseModel.d.ts +5 -0
- package/types/orm/src/cachedDatabase.d.ts +27 -0
- package/types/orm/src/database.d.ts +46 -7
- package/types/orm/src/graph/graphUrl.d.ts +0 -8
- package/types/orm/src/index.d.ts +1 -1
- package/types/orm/src/query.d.ts +48 -2
- package/types/orm/src/realtime/storage.d.ts +2 -1
- package/types/orm/src/sqlTranslator.d.ts +70 -18
- package/types/orm/src/types.d.ts +6 -0
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* Zero-dependency MQTT 3.1.1 client — the protocol every broker and every IoT
|
|
3
11
|
* device already speaks.
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* One MQTT 3.1.1 application message as delivered by the broker.
|
|
3
11
|
*
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Optional peer packages: the database drivers and service clients an
|
|
11
|
+
* APPLICATION installs, never the framework (ADR-0067).
|
|
12
|
+
*
|
|
13
|
+
* tina4-nodejs installs as exactly one package. `pg`, `mongodb`, `redis` and
|
|
14
|
+
* the `@aws-sdk` S3 client are optional peerDependencies, which npm does not
|
|
15
|
+
* install, so for most apps "missing" is the normal state. Every feature that
|
|
16
|
+
* reaches for one must therefore fail at the point of use with the exact
|
|
17
|
+
* command that fixes it - never a bare MODULE_NOT_FOUND, never a silent no-op.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** The actionable "install it" error, one wording for every optional peer. */
|
|
21
|
+
export function optionalPackageMissing(feature: string, packageNames: string[]): Error {
|
|
22
|
+
const quoted = packageNames.map((name) => `'${name}'`).join(" and ");
|
|
23
|
+
const [noun, pronoun] = packageNames.length === 1 ? ["package is", "it"] : ["packages are", "them"];
|
|
24
|
+
return new Error(
|
|
25
|
+
`The ${quoted} ${noun} required for ${feature}. ` +
|
|
26
|
+
`Install ${pronoun} with: npm install ${packageNames.join(" ")}`,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Resolve an optional peer from the FRAMEWORK's location and return its module
|
|
32
|
+
* URL, or throw the actionable error. Synchronous, so a constructor can refuse
|
|
33
|
+
* immediately (parity with the Python master, which raises ImportError in the
|
|
34
|
+
* constructor) instead of leaving a rejected promise for later.
|
|
35
|
+
*
|
|
36
|
+
* Resolving from here rather than from process.cwd() is what finds the peer an
|
|
37
|
+
* app installed, wherever the server was started from.
|
|
38
|
+
*
|
|
39
|
+
* @param installTogether packages the feature needs as a set (S3 needs the
|
|
40
|
+
* client AND the presigner), all named in the one install command.
|
|
41
|
+
*/
|
|
42
|
+
export function resolveOptionalPackage(packageName: string, feature: string, installTogether: string[] = [packageName]): string {
|
|
43
|
+
try {
|
|
44
|
+
return import.meta.resolve(packageName);
|
|
45
|
+
} catch {
|
|
46
|
+
throw optionalPackageMissing(feature, installTogether);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* Project plan management — persistent, human-readable task state.
|
|
3
11
|
*
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* Identity-checked port takeover, shared by the CLI and the runtime paths.
|
|
3
11
|
*
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* Project index — lightweight, persistent "where is what" map.
|
|
3
11
|
*
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import * as path from "node:path";
|
|
2
10
|
import type { FileEntry, FileRoute } from "./projectIndex.js";
|
|
3
11
|
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import * as fs from "node:fs";
|
|
2
10
|
import * as path from "node:path";
|
|
3
11
|
import * as crypto from "node:crypto";
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* Provider-neutral Web Push delivery using Node's built-in crypto and fetch.
|
|
3
11
|
*
|
|
@@ -13,6 +21,7 @@ import {
|
|
|
13
21
|
createSign,
|
|
14
22
|
randomBytes,
|
|
15
23
|
} from "node:crypto";
|
|
24
|
+
import { guardUrl, SsrfError } from "./ssrf.js";
|
|
16
25
|
|
|
17
26
|
const CURVE = "prime256v1";
|
|
18
27
|
const RECORD_SIZE = 4096;
|
|
@@ -32,6 +41,11 @@ export interface PushOptions {
|
|
|
32
41
|
privateKey?: string;
|
|
33
42
|
ttl?: number;
|
|
34
43
|
urgency?: "very-low" | "low" | "normal" | "high";
|
|
44
|
+
/**
|
|
45
|
+
* SSRF guard (ADR-0084): an explicit allow-list of hosts / host:port / CIDRs
|
|
46
|
+
* that bypass the private-endpoint refusal even with the opt-out off.
|
|
47
|
+
*/
|
|
48
|
+
allowHosts?: string[];
|
|
35
49
|
}
|
|
36
50
|
|
|
37
51
|
export interface PushResult {
|
|
@@ -259,10 +273,20 @@ export class Push {
|
|
|
259
273
|
}
|
|
260
274
|
|
|
261
275
|
private async deliver(endpoint: URL, config: { subject: string; publicKey: string; privateKey: string }, keys: { rawPublic: Buffer; rawPrivate: Buffer }, body: Buffer): Promise<PushResult> {
|
|
276
|
+
// SSRF guard (ADR-0084): refuse a private/internal push endpoint.
|
|
277
|
+
try {
|
|
278
|
+
await guardUrl(endpoint.toString(), this.options.allowHosts);
|
|
279
|
+
} catch (error) {
|
|
280
|
+
if (error instanceof SsrfError) throw new PushError(error.message);
|
|
281
|
+
throw error;
|
|
282
|
+
}
|
|
262
283
|
let response: Response;
|
|
263
284
|
try {
|
|
264
285
|
response = await fetch(endpoint, {
|
|
265
286
|
method: "POST",
|
|
287
|
+
// A real push service answers the POST directly; a redirect from a push
|
|
288
|
+
// endpoint is not followed to a private address (ADR-0084).
|
|
289
|
+
redirect: "manual",
|
|
266
290
|
headers: {
|
|
267
291
|
Authorization: `vapid t=${vapidToken(endpoint.toString(), config.subject, keys.rawPrivate, keys.rawPublic)}, k=${config.publicKey}`,
|
|
268
292
|
"Content-Encoding": "aes128gcm",
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* Tina4 Queue — Unified job queue with pluggable backends, zero dependencies.
|
|
3
11
|
*
|
|
@@ -119,7 +127,7 @@ export interface ConsumeOptions {
|
|
|
119
127
|
export interface QueueBackendInterface {
|
|
120
128
|
push(queue: string, payload: unknown, delay?: number, priority?: number): string;
|
|
121
129
|
pop(queue: string): QueueJob | null;
|
|
122
|
-
size(queue: string): number;
|
|
130
|
+
size(queue: string, status?: string): number;
|
|
123
131
|
clear(queue: string): void;
|
|
124
132
|
/**
|
|
125
133
|
* Release whatever connection the backend holds, and be safe to call twice.
|
|
@@ -144,6 +152,7 @@ export interface QueueBackendInterface {
|
|
|
144
152
|
// persistent-connection rewrite lands.
|
|
145
153
|
complete?(queue: string, id: string): void;
|
|
146
154
|
fail?(queue: string, id: string, error: string, maxRetries: number, retryBackoff: number): void;
|
|
155
|
+
reject?(queue: string, id: string, reason: string, maxRetries: number): void;
|
|
147
156
|
/**
|
|
148
157
|
* Explicit manual re-queue: returns true if the id was found and revived,
|
|
149
158
|
* false otherwise (parity with Python's backend.retry_job()). A backend may
|
|
@@ -424,7 +433,7 @@ export class Queue {
|
|
|
424
433
|
const q = this.topic;
|
|
425
434
|
|
|
426
435
|
if (this.externalBackend) {
|
|
427
|
-
return this.externalBackend.size(q);
|
|
436
|
+
return this.externalBackend.size(q, status);
|
|
428
437
|
}
|
|
429
438
|
return this.liteBackend.size(q, status);
|
|
430
439
|
}
|
|
@@ -750,6 +759,18 @@ export class Queue {
|
|
|
750
759
|
this.liteBackend.failJob(queue, job, error, maxRetries, this._retryBackoff);
|
|
751
760
|
}
|
|
752
761
|
|
|
762
|
+
/**
|
|
763
|
+
* Dead-letter a job immediately — no retry (ADR-0023 reject()). Distinct from
|
|
764
|
+
* _failJob, which retries until maxRetries is spent.
|
|
765
|
+
*/
|
|
766
|
+
_rejectJob(queue: string, job: QueueJob, reason: string, maxRetries: number): void {
|
|
767
|
+
if (this.externalBackend?.reject) {
|
|
768
|
+
this.externalBackend.reject(queue, job.id, reason, maxRetries);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
this.liteBackend.rejectJob(queue, job, reason, maxRetries);
|
|
772
|
+
}
|
|
773
|
+
|
|
753
774
|
/**
|
|
754
775
|
* Re-queue a job back to the main queue directory with incremented attempts.
|
|
755
776
|
*/
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* Tina4 Kafka Queue Backend — Kafka protocol via raw TCP, zero dependencies.
|
|
3
11
|
*
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* LiteBackend — file-based queue backend for Tina4 Queue.
|
|
3
11
|
* Stores jobs as JSON files on disk. Zero dependencies.
|
|
@@ -685,6 +693,21 @@ export class LiteBackend {
|
|
|
685
693
|
* dead-letter file -- two spellings of the same intent that previously
|
|
686
694
|
* diverged.
|
|
687
695
|
*/
|
|
696
|
+
/**
|
|
697
|
+
* Reject a job permanently — dead-letter it NOW, no retry (ADR-0023).
|
|
698
|
+
*
|
|
699
|
+
* Unlike failJob(), which requeues until maxRetries is spent, rejectJob()
|
|
700
|
+
* moves a known-poison job straight to the dead-letter store. attempts is
|
|
701
|
+
* floored at maxRetries so deadLetters() (attempts >= maxRetries) returns it
|
|
702
|
+
* and size("dead") agrees.
|
|
703
|
+
*/
|
|
704
|
+
rejectJob(queue: string, job: QueueJob, reason: string, maxRetries: number): void {
|
|
705
|
+
this.clearReservation(queue, job.id);
|
|
706
|
+
job.attempts = Math.max((job.attempts || 0) + 1, maxRetries);
|
|
707
|
+
job.error = reason;
|
|
708
|
+
this.deadLetter(queue, job, reason);
|
|
709
|
+
}
|
|
710
|
+
|
|
688
711
|
retryJob(queue: string, job: QueueJob, delaySeconds?: number): void {
|
|
689
712
|
// Clear the reservation — the consumer acknowledged (with an explicit retry).
|
|
690
713
|
this.clearReservation(queue, job.id);
|
|
@@ -1,5 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
|
-
* Tina4 MongoDB Queue Backend — uses `mongodb` npm package
|
|
10
|
+
* Tina4 MongoDB Queue Backend — uses the `mongodb` npm package, which the app
|
|
11
|
+
* installs (`npm install mongodb`; an optional peer, ADR-0067).
|
|
3
12
|
*
|
|
4
13
|
* Implements the same interface as the file-based queue but uses MongoDB
|
|
5
14
|
* for message storage and delivery. Atomic pop via findOneAndUpdate.
|
|
@@ -21,6 +30,7 @@
|
|
|
21
30
|
import { randomUUID } from "node:crypto";
|
|
22
31
|
import { execFileSync } from "node:child_process";
|
|
23
32
|
import type { QueueJob } from "../queue.js";
|
|
33
|
+
import { resolveOptionalPackage } from "../optionalPackage.js";
|
|
24
34
|
|
|
25
35
|
// ── Types ────────────────────────────────────────────────────
|
|
26
36
|
|
|
@@ -71,8 +81,17 @@ export class MongoBackend implements QueueBackend {
|
|
|
71
81
|
private collection: string;
|
|
72
82
|
private visibilityTimeout: number;
|
|
73
83
|
private maxRetries: number;
|
|
84
|
+
/** Module URL of the app-installed `mongodb` driver, resolved once. */
|
|
85
|
+
private driverUrl: string;
|
|
74
86
|
|
|
75
87
|
constructor(config?: MongoConfig) {
|
|
88
|
+
// Optional peer (ADR-0067), resolved HERE, on the main thread. Every
|
|
89
|
+
// operation runs in a child process that swallows its own failures, so a
|
|
90
|
+
// driver missing there used to surface as "MongoDB push failed" and a pop
|
|
91
|
+
// that silently returned nothing. The Python master raises in its
|
|
92
|
+
// constructor; so does this. Resolving from the framework's location also
|
|
93
|
+
// means the child finds the driver whatever directory the server runs in.
|
|
94
|
+
this.driverUrl = resolveOptionalPackage("mongodb", "the MongoDB queue backend");
|
|
76
95
|
this.host = config?.host ?? process.env.TINA4_MONGO_HOST ?? "localhost";
|
|
77
96
|
this.port = config?.port
|
|
78
97
|
?? (process.env.TINA4_MONGO_PORT ? parseInt(process.env.TINA4_MONGO_PORT, 10) : 27017);
|
|
@@ -136,13 +155,7 @@ export class MongoBackend implements QueueBackend {
|
|
|
136
155
|
buildScript(operation: string, queue: string, data?: string): string {
|
|
137
156
|
return `
|
|
138
157
|
async function main() {
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
mongodb = await import("mongodb");
|
|
142
|
-
} catch {
|
|
143
|
-
process.stderr.write("mongodb package not installed — run: npm install mongodb");
|
|
144
|
-
process.exit(1);
|
|
145
|
-
}
|
|
158
|
+
const mongodb = await import(${JSON.stringify(this.driverUrl)});
|
|
146
159
|
|
|
147
160
|
const { MongoClient } = mongodb;
|
|
148
161
|
const uri = ${JSON.stringify(this.uri)};
|
|
@@ -294,12 +307,36 @@ export class MongoBackend implements QueueBackend {
|
|
|
294
307
|
}
|
|
295
308
|
}
|
|
296
309
|
else if (operation === "size") {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
310
|
+
// ADR-0022 dec 7: size(status) must not answer a different question.
|
|
311
|
+
// The dead aliases count the .dead_letter store (== deadLetters().length);
|
|
312
|
+
// reserved/completed count by status; else pending. data = status.
|
|
313
|
+
const status = data || "pending";
|
|
314
|
+
let count: number;
|
|
315
|
+
if (status === "dead" || status === "failed" || status === "dead_letter") {
|
|
316
|
+
count = await col.countDocuments({ queue: queueName + ".dead_letter" });
|
|
317
|
+
} else if (status === "reserved" || status === "completed") {
|
|
318
|
+
count = await col.countDocuments({ queue: queueName, status });
|
|
319
|
+
} else {
|
|
320
|
+
count = await col.countDocuments({ queue: queueName, status: "pending" });
|
|
321
|
+
}
|
|
301
322
|
process.stdout.write(String(count));
|
|
302
323
|
}
|
|
324
|
+
else if (operation === "reject") {
|
|
325
|
+
// Dead-letter NOW, no retry (ADR-0023). Floor attempts at maxRetries
|
|
326
|
+
// so it reads as exhausted (parity with fail()'s dead-letter branch
|
|
327
|
+
// and size("dead")). data = JSON { id, reason, maxRetries }.
|
|
328
|
+
const info = JSON.parse(data);
|
|
329
|
+
const doc = await col.findOne({ queue: queueName, id: info.id });
|
|
330
|
+
if (doc) {
|
|
331
|
+
const attempts = Math.max((doc.attempts || 0) + 1, info.maxRetries);
|
|
332
|
+
await col.insertOne({
|
|
333
|
+
...doc, _id: undefined, attempts,
|
|
334
|
+
status: "dead", queue: queueName + ".dead_letter", error: info.reason,
|
|
335
|
+
});
|
|
336
|
+
await col.deleteOne({ _id: doc._id, queue: queueName });
|
|
337
|
+
}
|
|
338
|
+
process.stdout.write("__OK__");
|
|
339
|
+
}
|
|
303
340
|
else if (operation === "clear") {
|
|
304
341
|
await col.deleteMany({ queue: queueName });
|
|
305
342
|
process.stdout.write("__CLEARED__");
|
|
@@ -546,12 +583,22 @@ export class MongoBackend implements QueueBackend {
|
|
|
546
583
|
}
|
|
547
584
|
}
|
|
548
585
|
|
|
549
|
-
size(queue: string): number {
|
|
550
|
-
const result = this.execSync("size", queue);
|
|
586
|
+
size(queue: string, status: string = "pending"): number {
|
|
587
|
+
const result = this.execSync("size", queue, status);
|
|
551
588
|
const num = parseInt(result, 10);
|
|
552
589
|
return isNaN(num) ? 0 : num;
|
|
553
590
|
}
|
|
554
591
|
|
|
592
|
+
/**
|
|
593
|
+
* Dead-letter a job immediately — no retry (ADR-0023 reject()). Distinct from
|
|
594
|
+
* fail(): fail() requeues until maxRetries is spent. attempts is floored at
|
|
595
|
+
* maxRetries so deadLetters()/size("dead") (which filter/scope to the
|
|
596
|
+
* dead-letter store) see it.
|
|
597
|
+
*/
|
|
598
|
+
reject(queue: string, id: string, reason: string, maxRetries: number): void {
|
|
599
|
+
this.execSync("reject", queue, JSON.stringify({ id, reason, maxRetries }));
|
|
600
|
+
}
|
|
601
|
+
|
|
555
602
|
clear(queue: string): void {
|
|
556
603
|
this.execSync("clear", queue);
|
|
557
604
|
}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* Tina4 RabbitMQ Queue Backend — AMQP 0-9-1 via raw TCP, zero dependencies.
|
|
3
11
|
*
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import type { Middleware, Tina4Request, Tina4Response } from "./types.js";
|
|
2
10
|
import { resolveClientIp } from "./trustedProxy.js";
|
|
3
11
|
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Code Infinity
|
|
3
|
+
SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import type { IncomingMessage, IncomingHttpHeaders } from "node:http";
|
|
2
10
|
import { mkdirSync, realpathSync, writeFileSync } from "node:fs";
|
|
3
11
|
import { dirname, join } from "node:path";
|
|
4
12
|
import type { Tina4Request, UploadedFile } from "./types.js";
|
|
5
|
-
import { resolveClientIp } from "./trustedProxy.js";
|
|
13
|
+
import { resolveClientIp, isTrustedProxy } from "./trustedProxy.js";
|
|
14
|
+
import { Log } from "./logger.js";
|
|
6
15
|
|
|
7
16
|
/**
|
|
8
17
|
* Wrap Node's `IncomingHttpHeaders` in a Proxy so mixed-case lookups
|
|
@@ -53,10 +62,11 @@ export function createRequest(req: IncomingMessage): Tina4Request {
|
|
|
53
62
|
makeCaseInsensitiveHeaders(req.headers);
|
|
54
63
|
|
|
55
64
|
// Resolve scheme + host honouring proxy headers — parity with PHP/Python/Ruby.
|
|
56
|
-
const
|
|
65
|
+
const trustedPeer = isTrustedProxy(req.socket?.remoteAddress ?? "");
|
|
66
|
+
const xfProto = trustedPeer ? req.headers["x-forwarded-proto"] : undefined;
|
|
57
67
|
const proto = (Array.isArray(xfProto) ? xfProto[0] : xfProto)
|
|
58
68
|
?? ((req.socket as { encrypted?: boolean })?.encrypted ? "https" : "http");
|
|
59
|
-
const xfHost = req.headers["x-forwarded-host"];
|
|
69
|
+
const xfHost = trustedPeer ? req.headers["x-forwarded-host"] : undefined;
|
|
60
70
|
const host = (Array.isArray(xfHost) ? xfHost[0] : xfHost)
|
|
61
71
|
?? (req.headers.host ?? "localhost");
|
|
62
72
|
|
|
@@ -148,13 +158,50 @@ export function createRequest(req: IncomingMessage): Tina4Request {
|
|
|
148
158
|
return tReq;
|
|
149
159
|
}
|
|
150
160
|
|
|
151
|
-
|
|
152
|
-
|
|
161
|
+
|
|
162
|
+
// ── Request limits (ADR-0068) ────────────────────────────────────────────────
|
|
163
|
+
// Here rather than in a module of their own: request.ts sits below the server
|
|
164
|
+
// and transport.ts, so both can read them without an import cycle, and the
|
|
165
|
+
// core barrel's eager module graph stays one module smaller.
|
|
166
|
+
|
|
167
|
+
export const DEFAULT_MAX_UPLOAD_SIZE = 10_485_760;
|
|
168
|
+
|
|
169
|
+
const warnedLimits = new Set<string>();
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Read a numeric limit from the environment. A value that is not a usable
|
|
173
|
+
* number falls back to the default with a warning naming the variable (the
|
|
174
|
+
* same rule as PHP's Server::resolveLimit) - a typo must never be what
|
|
175
|
+
* disables a DoS guard.
|
|
176
|
+
*/
|
|
177
|
+
export function resolveLimit(name: string, fallback: number, zeroAllowed = false): number {
|
|
178
|
+
const raw = (process.env[name] ?? "").trim();
|
|
179
|
+
if (raw === "") return fallback;
|
|
180
|
+
const value = /^[0-9]+$/.test(raw) ? Number(raw) : NaN;
|
|
181
|
+
if (Number.isSafeInteger(value) && (value > 0 || (value === 0 && zeroAllowed))) return value;
|
|
182
|
+
if (!warnedLimits.has(`${name}=${raw}`)) {
|
|
183
|
+
warnedLimits.add(`${name}=${raw}`);
|
|
184
|
+
Log.warning(`${name}=${raw} is not a usable limit - using ${fallback}`);
|
|
185
|
+
}
|
|
186
|
+
return fallback;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** TINA4_MAX_UPLOAD_SIZE, read when it is needed so a value from .env counts. */
|
|
190
|
+
export function maxUploadSize(): number {
|
|
191
|
+
return resolveLimit("TINA4_MAX_UPLOAD_SIZE", DEFAULT_MAX_UPLOAD_SIZE);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** The one 413 wording (ADR-0068 section 4). */
|
|
195
|
+
export function bodyTooLargeMessage(bytes: number | bigint | string, limit: number): string {
|
|
196
|
+
return `Request body (${bytes} bytes) exceeds TINA4_MAX_UPLOAD_SIZE (${limit} bytes)`;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
153
200
|
|
|
154
201
|
export class PayloadTooLargeError extends Error {
|
|
155
202
|
public statusCode = 413;
|
|
156
203
|
constructor(actual: number, limit: number) {
|
|
157
|
-
super(
|
|
204
|
+
super(bodyTooLargeMessage(actual, limit));
|
|
158
205
|
this.name = "PayloadTooLargeError";
|
|
159
206
|
}
|
|
160
207
|
}
|
|
@@ -164,9 +211,11 @@ async function parseBody(req: Tina4Request): Promise<void> {
|
|
|
164
211
|
if (method === "GET" || method === "HEAD" || method === "OPTIONS") return;
|
|
165
212
|
|
|
166
213
|
// Check content-length header against upload size limit before reading body
|
|
214
|
+
const uploadLimit = maxUploadSize();
|
|
215
|
+
|
|
167
216
|
const declaredLength = parseInt(req.headers["content-length"] ?? "0", 10);
|
|
168
|
-
if (declaredLength >
|
|
169
|
-
throw new PayloadTooLargeError(declaredLength,
|
|
217
|
+
if (declaredLength > uploadLimit) {
|
|
218
|
+
throw new PayloadTooLargeError(declaredLength, uploadLimit);
|
|
170
219
|
}
|
|
171
220
|
|
|
172
221
|
const contentType = req.headers["content-type"] ?? "";
|
|
@@ -190,10 +239,10 @@ async function parseBody(req: Tina4Request): Promise<void> {
|
|
|
190
239
|
req.on("data", (chunk: Buffer) => {
|
|
191
240
|
if (refused) return;
|
|
192
241
|
received += chunk.length;
|
|
193
|
-
if (received >
|
|
242
|
+
if (received > uploadLimit) {
|
|
194
243
|
refused = true;
|
|
195
244
|
chunks.length = 0; // drop what we have; the request is dead
|
|
196
|
-
reject(new PayloadTooLargeError(received,
|
|
245
|
+
reject(new PayloadTooLargeError(received, uploadLimit));
|
|
197
246
|
return;
|
|
198
247
|
}
|
|
199
248
|
chunks.push(chunk);
|