@blamejs/core 0.4.1
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/CHANGELOG.md +230 -0
- package/LICENSE +201 -0
- package/LTS-CALENDAR.md +29 -0
- package/MIGRATING.md +7 -0
- package/NOTICE +59 -0
- package/README.md +100 -0
- package/bin/blamejs.js +13 -0
- package/index.js +253 -0
- package/lib/api-key.js +705 -0
- package/lib/api-snapshot.js +335 -0
- package/lib/app-shutdown.js +381 -0
- package/lib/app.js +364 -0
- package/lib/atomic-file.js +525 -0
- package/lib/audit-chain.js +168 -0
- package/lib/audit-sign.js +319 -0
- package/lib/audit-tools.js +682 -0
- package/lib/audit.js +753 -0
- package/lib/auth/jwt.js +280 -0
- package/lib/auth/oauth.js +691 -0
- package/lib/auth/passkey.js +185 -0
- package/lib/auth/password.js +139 -0
- package/lib/auth/totp.js +17 -0
- package/lib/auth-header.js +81 -0
- package/lib/backup/bundle.js +219 -0
- package/lib/backup/crypto.js +174 -0
- package/lib/backup/index.js +490 -0
- package/lib/backup/manifest.js +275 -0
- package/lib/bundler.js +295 -0
- package/lib/cache.js +819 -0
- package/lib/chain-writer.js +234 -0
- package/lib/cli-helpers.js +201 -0
- package/lib/cli.js +1377 -0
- package/lib/cluster-provider-db.js +245 -0
- package/lib/cluster-storage.js +166 -0
- package/lib/cluster.js +691 -0
- package/lib/consent.js +222 -0
- package/lib/constants.js +186 -0
- package/lib/cookies.js +293 -0
- package/lib/credential-hash.js +303 -0
- package/lib/crypto-field.js +159 -0
- package/lib/crypto.js +250 -0
- package/lib/db-query.js +297 -0
- package/lib/db-schema.js +250 -0
- package/lib/db.js +1054 -0
- package/lib/deprecate.js +226 -0
- package/lib/dev.js +324 -0
- package/lib/error-page.js +424 -0
- package/lib/events.js +135 -0
- package/lib/external-db.js +422 -0
- package/lib/forms.js +378 -0
- package/lib/framework-error.js +189 -0
- package/lib/framework-schema.js +604 -0
- package/lib/handlers.js +350 -0
- package/lib/html-balance.js +227 -0
- package/lib/http-client.js +615 -0
- package/lib/i18n.js +780 -0
- package/lib/jobs.js +181 -0
- package/lib/lazy-require.js +48 -0
- package/lib/log-stream-local.js +137 -0
- package/lib/log-stream-webhook.js +170 -0
- package/lib/log-stream.js +211 -0
- package/lib/log.js +355 -0
- package/lib/mail-bounce.js +507 -0
- package/lib/mail.js +701 -0
- package/lib/metrics.js +647 -0
- package/lib/middleware/api-encrypt.js +553 -0
- package/lib/middleware/attach-user.js +156 -0
- package/lib/middleware/body-parser.js +883 -0
- package/lib/middleware/bot-guard.js +148 -0
- package/lib/middleware/compression.js +436 -0
- package/lib/middleware/cors.js +236 -0
- package/lib/middleware/csp-nonce.js +332 -0
- package/lib/middleware/csrf-protect.js +275 -0
- package/lib/middleware/error-handler.js +46 -0
- package/lib/middleware/health.js +358 -0
- package/lib/middleware/index.js +52 -0
- package/lib/middleware/rate-limit.js +319 -0
- package/lib/middleware/request-id.js +53 -0
- package/lib/middleware/require-auth.js +95 -0
- package/lib/middleware/security-headers.js +91 -0
- package/lib/migrations.js +353 -0
- package/lib/mtls-ca.js +333 -0
- package/lib/mtls-engine-default.js +285 -0
- package/lib/nonce-store.js +177 -0
- package/lib/notify.js +643 -0
- package/lib/ntp-check.js +178 -0
- package/lib/object-store/azure-blob.js +467 -0
- package/lib/object-store/gcs.js +469 -0
- package/lib/object-store/http-put.js +153 -0
- package/lib/object-store/index.js +140 -0
- package/lib/object-store/local.js +163 -0
- package/lib/object-store/retry.js +15 -0
- package/lib/object-store/sigv4.js +535 -0
- package/lib/observability.js +114 -0
- package/lib/pagination.js +371 -0
- package/lib/parsers/index.js +64 -0
- package/lib/parsers/safe-csv.js +224 -0
- package/lib/parsers/safe-env.js +614 -0
- package/lib/parsers/safe-toml.js +745 -0
- package/lib/parsers/safe-xml.js +379 -0
- package/lib/parsers/safe-yaml.js +977 -0
- package/lib/permissions.js +430 -0
- package/lib/pqc-agent.js +85 -0
- package/lib/pqc-gate.js +266 -0
- package/lib/protocol-dispatcher.js +144 -0
- package/lib/queue-local.js +327 -0
- package/lib/queue.js +430 -0
- package/lib/redact.js +192 -0
- package/lib/render.js +193 -0
- package/lib/request-helpers.js +178 -0
- package/lib/restore-bundle.js +239 -0
- package/lib/restore-rollback.js +254 -0
- package/lib/restore.js +301 -0
- package/lib/retry.js +329 -0
- package/lib/router.js +437 -0
- package/lib/safe-async.js +520 -0
- package/lib/safe-buffer.js +162 -0
- package/lib/safe-json.js +532 -0
- package/lib/safe-schema.js +1176 -0
- package/lib/safe-sql.js +157 -0
- package/lib/safe-url.js +109 -0
- package/lib/scheduler.js +680 -0
- package/lib/seeders.js +622 -0
- package/lib/session.js +304 -0
- package/lib/slug.js +243 -0
- package/lib/static.js +268 -0
- package/lib/storage.js +470 -0
- package/lib/subject.js +281 -0
- package/lib/template.js +781 -0
- package/lib/testing.js +621 -0
- package/lib/totp.js +285 -0
- package/lib/tracing.js +484 -0
- package/lib/validate-opts.js +56 -0
- package/lib/vault/index.js +299 -0
- package/lib/vault/passphrase-ops.js +311 -0
- package/lib/vault/passphrase-source.js +198 -0
- package/lib/vault/rotate.js +761 -0
- package/lib/vault/wrap.js +289 -0
- package/lib/vendor/MANIFEST.json +84 -0
- package/lib/vendor/argon2/argon2.cjs +466 -0
- package/lib/vendor/argon2/argon2.d.cts +62 -0
- package/lib/vendor/argon2/package.json +1 -0
- package/lib/vendor/argon2/prebuilds/darwin-arm64/argon2.armv8.glibc.node +0 -0
- package/lib/vendor/argon2/prebuilds/darwin-x64/argon2.glibc.node +0 -0
- package/lib/vendor/argon2/prebuilds/freebsd-arm64/argon2.armv8.glibc.node +0 -0
- package/lib/vendor/argon2/prebuilds/freebsd-x64/argon2.glibc.node +0 -0
- package/lib/vendor/argon2/prebuilds/linux-arm/argon2.armv7.glibc.node +0 -0
- package/lib/vendor/argon2/prebuilds/linux-arm/argon2.armv7.musl.node +0 -0
- package/lib/vendor/argon2/prebuilds/linux-arm64/argon2.armv8.glibc.node +0 -0
- package/lib/vendor/argon2/prebuilds/linux-arm64/argon2.armv8.musl.node +0 -0
- package/lib/vendor/argon2/prebuilds/linux-x64/argon2.glibc.node +0 -0
- package/lib/vendor/argon2/prebuilds/linux-x64/argon2.musl.node +0 -0
- package/lib/vendor/argon2/prebuilds/win32-x64/argon2.glibc.node +0 -0
- package/lib/vendor/noble-ciphers.cjs +9 -0
- package/lib/vendor/pki.cjs +181 -0
- package/lib/vendor/simplewebauthn-server.cjs +328 -0
- package/lib/webhook.js +632 -0
- package/lib/websocket-channels.js +413 -0
- package/lib/websocket.js +833 -0
- package/package.json +39 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Object-store dispatcher — protocol-agnostic remote (and local) storage.
|
|
4
|
+
*
|
|
5
|
+
* The framework's storage abstraction (lib/storage.js) routes per-classification
|
|
6
|
+
* requests to one or more configured backends. Each backend is constructed
|
|
7
|
+
* here from a config object that picks a protocol and provides its options:
|
|
8
|
+
*
|
|
9
|
+
* protocol: 'local' → lib/object-store/local.js
|
|
10
|
+
* protocol: 'http-put' → lib/object-store/http-put.js
|
|
11
|
+
* protocol: 'sigv4' (S3 / R2 / B2 / MinIO / Wasabi / Tigris / DO Spaces /
|
|
12
|
+
* IDrive e2 / Linode Object Storage / Storj / etc.)
|
|
13
|
+
* → lib/object-store/sigv4.js
|
|
14
|
+
* protocol: 'gcs' (Google Cloud Storage native — HMAC + native API)
|
|
15
|
+
* → lib/object-store/gcs.js
|
|
16
|
+
* protocol: 'azure-blob' → lib/object-store/azure-blob.js
|
|
17
|
+
*
|
|
18
|
+
* Every backend is wrapped with retry + circuit-breaker so transient
|
|
19
|
+
* failures don't surface as call-site errors and persistent failures
|
|
20
|
+
* don't pile up retry storms.
|
|
21
|
+
*
|
|
22
|
+
* Common API across protocols:
|
|
23
|
+
* put(key, body, opts?) → { size, etag? }
|
|
24
|
+
* get(key) → Buffer
|
|
25
|
+
* getStream(key) → Readable
|
|
26
|
+
* head(key) → { size, etag?, lastModified? }
|
|
27
|
+
* delete(key) → boolean (true if deleted, false if missing)
|
|
28
|
+
* list(prefix, opts?) → { items: [{ key, size, lastModified }], truncated }
|
|
29
|
+
*/
|
|
30
|
+
var localProto = require("./local");
|
|
31
|
+
var httpPutProto = require("./http-put");
|
|
32
|
+
var sigv4Proto = require("./sigv4");
|
|
33
|
+
var gcsProto = require("./gcs");
|
|
34
|
+
var azureBlobProto = require("./azure-blob");
|
|
35
|
+
var retryHelper = require("./retry");
|
|
36
|
+
var protocolDispatcher = require("../protocol-dispatcher");
|
|
37
|
+
var { ObjectStoreError } = require("../framework-error");
|
|
38
|
+
|
|
39
|
+
// All currently advertised protocols are bundled. The dispatcher's
|
|
40
|
+
// `deferred` slot is the hook for adding deferred ones later.
|
|
41
|
+
var dispatcher = protocolDispatcher.create({
|
|
42
|
+
name: "object-store",
|
|
43
|
+
errorClass: ObjectStoreError,
|
|
44
|
+
protocols: {
|
|
45
|
+
"local": localProto,
|
|
46
|
+
"http-put": httpPutProto,
|
|
47
|
+
"sigv4": sigv4Proto,
|
|
48
|
+
"gcs": gcsProto,
|
|
49
|
+
"azure-blob": azureBlobProto,
|
|
50
|
+
},
|
|
51
|
+
deferred: {},
|
|
52
|
+
fallbackProtocol: "local",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
var _err = ObjectStoreError.factory;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Build a backend instance from a backend config block.
|
|
59
|
+
*
|
|
60
|
+
* config:
|
|
61
|
+
* {
|
|
62
|
+
* protocol: 'local' | 'http-put' | 'sigv4' | 'gcs' | 'azure-blob',
|
|
63
|
+
* // protocol-specific config (rootDir for local, baseUrl for http-put, etc.)
|
|
64
|
+
* classifications: ['personal' | 'operational' | 'public' | <custom>],
|
|
65
|
+
* residencyTag: 'EU' | 'US' | 'UK' | 'CA' | 'unrestricted' | <custom>,
|
|
66
|
+
* retry: { maxAttempts, baseDelayMs, maxDelayMs, jitterFactor },
|
|
67
|
+
* breaker: { failureThreshold, cooldownMs, successThreshold },
|
|
68
|
+
* name: <stable-id-for-circuit-breaker>,
|
|
69
|
+
* }
|
|
70
|
+
*/
|
|
71
|
+
function buildBackend(config) {
|
|
72
|
+
if (!config) {
|
|
73
|
+
throw new Error("object-store backend requires { protocol }");
|
|
74
|
+
}
|
|
75
|
+
var proto = dispatcher.resolve(config.protocol);
|
|
76
|
+
var raw = proto.create(config);
|
|
77
|
+
|
|
78
|
+
// Validate classifications + residencyTag
|
|
79
|
+
var classifications = Array.isArray(config.classifications) && config.classifications.length > 0
|
|
80
|
+
? config.classifications.slice()
|
|
81
|
+
: ["*"]; // wildcard: backend serves any classification
|
|
82
|
+
var residencyTag = config.residencyTag || "unrestricted";
|
|
83
|
+
|
|
84
|
+
// Wrap protocol calls with retry + circuit breaker
|
|
85
|
+
var breaker = new retryHelper.CircuitBreaker(
|
|
86
|
+
config.name || (config.protocol + ":" + (raw.rootDir || raw.baseUrl || "anonymous")),
|
|
87
|
+
config.breaker
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
function wrap(name) {
|
|
91
|
+
var inner = raw[name];
|
|
92
|
+
if (typeof inner !== "function") return inner;
|
|
93
|
+
return function () {
|
|
94
|
+
var args = Array.prototype.slice.call(arguments);
|
|
95
|
+
// For sync methods (getStream returns a Readable directly, not a Promise):
|
|
96
|
+
if (name === "getStream") {
|
|
97
|
+
// Apply circuit breaker only — getStream is sync, retry doesn't apply.
|
|
98
|
+
// The Readable will surface its own errors as the consumer reads it.
|
|
99
|
+
return inner.apply(raw, args);
|
|
100
|
+
}
|
|
101
|
+
return retryHelper.withRetry(function () {
|
|
102
|
+
return breaker.wrap(function () {
|
|
103
|
+
return inner.apply(raw, args);
|
|
104
|
+
});
|
|
105
|
+
}, config.retry);
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
name: config.name || config.protocol,
|
|
111
|
+
protocol: config.protocol,
|
|
112
|
+
classifications: classifications,
|
|
113
|
+
residencyTag: residencyTag,
|
|
114
|
+
breaker: breaker,
|
|
115
|
+
raw: raw,
|
|
116
|
+
put: wrap("put"),
|
|
117
|
+
get: wrap("get"),
|
|
118
|
+
getStream: wrap("getStream"),
|
|
119
|
+
head: wrap("head"),
|
|
120
|
+
delete: wrap("delete"),
|
|
121
|
+
list: wrap("list"),
|
|
122
|
+
// presigned*Url are sync URL-builders (no network call), so they
|
|
123
|
+
// bypass retry + circuit-breaker — propagate any throw directly.
|
|
124
|
+
presignedUploadUrl: typeof raw.presignedUploadUrl === "function"
|
|
125
|
+
? raw.presignedUploadUrl.bind(raw) : null,
|
|
126
|
+
presignedDownloadUrl: typeof raw.presignedDownloadUrl === "function"
|
|
127
|
+
? raw.presignedDownloadUrl.bind(raw) : null,
|
|
128
|
+
presignedUploadPolicy: typeof raw.presignedUploadPolicy === "function"
|
|
129
|
+
? raw.presignedUploadPolicy.bind(raw) : null,
|
|
130
|
+
servesClassification: function (cls) {
|
|
131
|
+
return classifications.indexOf("*") !== -1 || classifications.indexOf(cls) !== -1;
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = {
|
|
137
|
+
buildBackend: buildBackend,
|
|
138
|
+
PROTOCOLS: dispatcher.protocols,
|
|
139
|
+
DEFERRED_PROTOCOLS: dispatcher.deferred,
|
|
140
|
+
};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Local-filesystem protocol adapter for object-store.
|
|
4
|
+
*
|
|
5
|
+
* Implements the uniform protocol surface (put / get / getStream / delete /
|
|
6
|
+
* head / list) against a directory tree. Streaming is via Node's native
|
|
7
|
+
* fs.createReadStream / createWriteStream — no in-memory buffering of
|
|
8
|
+
* full files.
|
|
9
|
+
*
|
|
10
|
+
* Path safety: every key resolves under the configured rootDir, with an
|
|
11
|
+
* alphanumeric + `_-./` charset whitelist and explicit rejection of any
|
|
12
|
+
* path that escapes rootDir after resolution.
|
|
13
|
+
*/
|
|
14
|
+
var fs = require("fs");
|
|
15
|
+
var path = require("path");
|
|
16
|
+
var atomicFile = require("../atomic-file");
|
|
17
|
+
var cluster = require("../cluster");
|
|
18
|
+
var { ObjectStoreError } = require("../framework-error");
|
|
19
|
+
|
|
20
|
+
var SAFE_KEY = /^[A-Za-z0-9_\-./]+$/;
|
|
21
|
+
|
|
22
|
+
function _resolveSafe(rootDir, key) {
|
|
23
|
+
if (typeof key !== "string" || key.length === 0) {
|
|
24
|
+
throw _err("INVALID_KEY", "key must be a non-empty string", true);
|
|
25
|
+
}
|
|
26
|
+
if (key.includes("\0")) throw _err("INVALID_KEY", "null byte in key", true);
|
|
27
|
+
if (path.isAbsolute(key)) throw _err("INVALID_KEY", "absolute key not allowed", true);
|
|
28
|
+
if (!SAFE_KEY.test(key)) throw _err("INVALID_KEY", "invalid characters in key", true);
|
|
29
|
+
var full = path.resolve(rootDir, key);
|
|
30
|
+
var withSep = rootDir.endsWith(path.sep) ? rootDir : rootDir + path.sep;
|
|
31
|
+
if (full !== rootDir && !full.startsWith(withSep)) {
|
|
32
|
+
throw _err("INVALID_KEY", "key escapes rootDir", true);
|
|
33
|
+
}
|
|
34
|
+
return full;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var _err = ObjectStoreError.factory;
|
|
38
|
+
|
|
39
|
+
function create(config) {
|
|
40
|
+
if (!config || !config.rootDir) {
|
|
41
|
+
throw new Error("local protocol requires { rootDir }");
|
|
42
|
+
}
|
|
43
|
+
var rootDir = path.resolve(config.rootDir);
|
|
44
|
+
if (!fs.existsSync(rootDir)) fs.mkdirSync(rootDir, { recursive: true });
|
|
45
|
+
|
|
46
|
+
function put(key, body, _opts) {
|
|
47
|
+
cluster.requireLeader();
|
|
48
|
+
var full = _resolveSafe(rootDir, key);
|
|
49
|
+
var dir = path.dirname(full);
|
|
50
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
51
|
+
|
|
52
|
+
if (Buffer.isBuffer(body)) {
|
|
53
|
+
atomicFile.writeSync(full, body);
|
|
54
|
+
return Promise.resolve({ size: body.length });
|
|
55
|
+
}
|
|
56
|
+
if (body && typeof body.pipe === "function") {
|
|
57
|
+
// Streaming put — pipe directly to disk
|
|
58
|
+
return new Promise(function (resolve, reject) {
|
|
59
|
+
var ws = fs.createWriteStream(full);
|
|
60
|
+
var bytes = 0;
|
|
61
|
+
body.on("data", function (chunk) { bytes += chunk.length; });
|
|
62
|
+
body.pipe(ws);
|
|
63
|
+
ws.on("finish", function () { resolve({ size: bytes }); });
|
|
64
|
+
ws.on("error", reject);
|
|
65
|
+
body.on("error", reject);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (typeof body === "string") {
|
|
69
|
+
var buf = Buffer.from(body, "utf8");
|
|
70
|
+
atomicFile.writeSync(full, buf);
|
|
71
|
+
return Promise.resolve({ size: buf.length });
|
|
72
|
+
}
|
|
73
|
+
return Promise.reject(_err("INVALID_BODY", "put body must be Buffer, Readable, or string", true));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function get(key) {
|
|
77
|
+
var full = _resolveSafe(rootDir, key);
|
|
78
|
+
if (!fs.existsSync(full)) {
|
|
79
|
+
return Promise.reject(_err("NOT_FOUND", "key not found: " + key, true));
|
|
80
|
+
}
|
|
81
|
+
return Promise.resolve(fs.readFileSync(full));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function getStream(key) {
|
|
85
|
+
var full = _resolveSafe(rootDir, key);
|
|
86
|
+
if (!fs.existsSync(full)) {
|
|
87
|
+
throw _err("NOT_FOUND", "key not found: " + key, true);
|
|
88
|
+
}
|
|
89
|
+
return fs.createReadStream(full);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function head(key) {
|
|
93
|
+
var full = _resolveSafe(rootDir, key);
|
|
94
|
+
if (!fs.existsSync(full)) {
|
|
95
|
+
return Promise.reject(_err("NOT_FOUND", "key not found: " + key, true));
|
|
96
|
+
}
|
|
97
|
+
var stat = fs.statSync(full);
|
|
98
|
+
return Promise.resolve({
|
|
99
|
+
size: stat.size,
|
|
100
|
+
lastModified: stat.mtimeMs,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function deleteKey(key) {
|
|
105
|
+
cluster.requireLeader();
|
|
106
|
+
var full = _resolveSafe(rootDir, key);
|
|
107
|
+
if (!fs.existsSync(full)) return Promise.resolve(false);
|
|
108
|
+
fs.unlinkSync(full);
|
|
109
|
+
return Promise.resolve(true);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function list(prefix, opts) {
|
|
113
|
+
opts = opts || {};
|
|
114
|
+
var max = opts.maxResults || 1000;
|
|
115
|
+
var prefixDir = prefix ? _resolveSafe(rootDir, prefix.replace(/\/$/, "")) : rootDir;
|
|
116
|
+
var results = [];
|
|
117
|
+
function walk(dir, base) {
|
|
118
|
+
if (results.length >= max) return;
|
|
119
|
+
var entries = atomicFile.listDir(dir, { includeStat: true });
|
|
120
|
+
for (var i = 0; i < entries.length; i++) {
|
|
121
|
+
if (results.length >= max) break;
|
|
122
|
+
var entry = entries[i];
|
|
123
|
+
var rel = base ? base + "/" + entry.name : entry.name;
|
|
124
|
+
if (entry.isDirectory) walk(entry.fullPath, rel);
|
|
125
|
+
else results.push({ key: rel, size: entry.sizeBytes, lastModified: entry.mtimeMs });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
var basePrefix = prefix ? prefix.replace(/\/$/, "") : "";
|
|
129
|
+
walk(prefixDir, basePrefix);
|
|
130
|
+
return Promise.resolve({ items: results, truncated: results.length >= max });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function _presignNotSupported(direction) {
|
|
134
|
+
return function (_opts) {
|
|
135
|
+
throw _err("PRESIGN_NOT_SUPPORTED",
|
|
136
|
+
"local backend does not issue presigned " + direction + " URLs — " +
|
|
137
|
+
"clients on the same host should call storage." +
|
|
138
|
+
(direction === "upload" ? "saveFile" : "getFileBuffer") + "() directly",
|
|
139
|
+
true);
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
protocol: "local",
|
|
145
|
+
rootDir: rootDir,
|
|
146
|
+
put: put,
|
|
147
|
+
get: get,
|
|
148
|
+
getStream: getStream,
|
|
149
|
+
head: head,
|
|
150
|
+
delete: deleteKey,
|
|
151
|
+
list: list,
|
|
152
|
+
presignedUploadUrl: _presignNotSupported("upload"),
|
|
153
|
+
presignedDownloadUrl: _presignNotSupported("download"),
|
|
154
|
+
presignedUploadPolicy: function () {
|
|
155
|
+
throw _err("PRESIGN_NOT_SUPPORTED",
|
|
156
|
+
"local backend does not issue presigned upload policies — " +
|
|
157
|
+
"clients on the same host should call storage.saveFile() directly " +
|
|
158
|
+
"with their own size validation", true);
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
module.exports = { create: create };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Thin re-export of the top-level `lib/retry.js` primitive.
|
|
4
|
+
*
|
|
5
|
+
* The retry + circuit breaker primitive used to live here for historical
|
|
6
|
+
* reasons (it was built alongside the object-store dispatcher). It graduated
|
|
7
|
+
* to a top-level primitive in v0.2.24 so other framework consumers (queue,
|
|
8
|
+
* external-db, log-stream-webhook, atomic-file, handlers) and operator code
|
|
9
|
+
* via `b.retry` share one canonical implementation.
|
|
10
|
+
*
|
|
11
|
+
* This module is preserved as a re-export so existing internal requires
|
|
12
|
+
* keep working without churn.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
module.exports = require("../retry");
|