@dexto/storage 1.6.0
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/LICENSE +44 -0
- package/README.md +80 -0
- package/dist/blob/factories/index.cjs +31 -0
- package/dist/blob/factories/index.d.cts +6 -0
- package/dist/blob/factories/index.d.ts +6 -0
- package/dist/blob/factories/index.d.ts.map +1 -0
- package/dist/blob/factories/index.js +6 -0
- package/dist/blob/factories/local.cjs +38 -0
- package/dist/blob/factories/local.d.cts +21 -0
- package/dist/blob/factories/local.d.ts +17 -0
- package/dist/blob/factories/local.d.ts.map +1 -0
- package/dist/blob/factories/local.js +14 -0
- package/dist/blob/factories/memory.cjs +44 -0
- package/dist/blob/factories/memory.d.cts +21 -0
- package/dist/blob/factories/memory.d.ts +17 -0
- package/dist/blob/factories/memory.d.ts.map +1 -0
- package/dist/blob/factories/memory.js +20 -0
- package/dist/blob/factory.cjs +16 -0
- package/dist/blob/factory.d.cts +36 -0
- package/dist/blob/factory.d.ts +35 -0
- package/dist/blob/factory.d.ts.map +1 -0
- package/dist/blob/factory.js +0 -0
- package/dist/blob/index.cjs +45 -0
- package/dist/blob/index.d.cts +8 -0
- package/dist/blob/index.d.ts +26 -0
- package/dist/blob/index.d.ts.map +1 -0
- package/dist/blob/index.js +19 -0
- package/dist/blob/local-blob-store.cjs +532 -0
- package/dist/blob/local-blob-store.d.cts +56 -0
- package/dist/blob/local-blob-store.d.ts +54 -0
- package/dist/blob/local-blob-store.d.ts.map +1 -0
- package/dist/blob/local-blob-store.js +498 -0
- package/dist/blob/memory-blob-store.cjs +327 -0
- package/dist/blob/memory-blob-store.d.cts +69 -0
- package/dist/blob/memory-blob-store.d.ts +67 -0
- package/dist/blob/memory-blob-store.d.ts.map +1 -0
- package/dist/blob/memory-blob-store.js +303 -0
- package/dist/blob/schemas.cjs +52 -0
- package/dist/blob/schemas.d.cts +87 -0
- package/dist/blob/schemas.d.ts +86 -0
- package/dist/blob/schemas.d.ts.map +1 -0
- package/dist/blob/schemas.js +25 -0
- package/dist/blob/types.cjs +16 -0
- package/dist/blob/types.d.cts +1 -0
- package/dist/blob/types.d.ts +2 -0
- package/dist/blob/types.d.ts.map +1 -0
- package/dist/blob/types.js +0 -0
- package/dist/cache/factories/index.cjs +31 -0
- package/dist/cache/factories/index.d.cts +6 -0
- package/dist/cache/factories/index.d.ts +6 -0
- package/dist/cache/factories/index.d.ts.map +1 -0
- package/dist/cache/factories/index.js +6 -0
- package/dist/cache/factories/memory.cjs +39 -0
- package/dist/cache/factories/memory.d.cts +21 -0
- package/dist/cache/factories/memory.d.ts +17 -0
- package/dist/cache/factories/memory.d.ts.map +1 -0
- package/dist/cache/factories/memory.js +15 -0
- package/dist/cache/factories/redis.cjs +65 -0
- package/dist/cache/factories/redis.d.cts +24 -0
- package/dist/cache/factories/redis.d.ts +20 -0
- package/dist/cache/factories/redis.d.ts.map +1 -0
- package/dist/cache/factories/redis.js +31 -0
- package/dist/cache/factory.cjs +16 -0
- package/dist/cache/factory.d.cts +42 -0
- package/dist/cache/factory.d.ts +41 -0
- package/dist/cache/factory.d.ts.map +1 -0
- package/dist/cache/factory.js +0 -0
- package/dist/cache/index.cjs +42 -0
- package/dist/cache/index.d.cts +7 -0
- package/dist/cache/index.d.ts +25 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +17 -0
- package/dist/cache/memory-cache-store.cjs +106 -0
- package/dist/cache/memory-cache-store.d.cts +27 -0
- package/dist/cache/memory-cache-store.d.ts +25 -0
- package/dist/cache/memory-cache-store.d.ts.map +1 -0
- package/dist/cache/memory-cache-store.js +82 -0
- package/dist/cache/redis-store.cjs +176 -0
- package/dist/cache/redis-store.d.cts +34 -0
- package/dist/cache/redis-store.d.ts +32 -0
- package/dist/cache/redis-store.d.ts.map +1 -0
- package/dist/cache/redis-store.js +152 -0
- package/dist/cache/schemas.cjs +70 -0
- package/dist/cache/schemas.d.cts +93 -0
- package/dist/cache/schemas.d.ts +91 -0
- package/dist/cache/schemas.d.ts.map +1 -0
- package/dist/cache/schemas.js +43 -0
- package/dist/cache/types.cjs +16 -0
- package/dist/cache/types.d.cts +1 -0
- package/dist/cache/types.d.ts +2 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +0 -0
- package/dist/database/factories/index.cjs +34 -0
- package/dist/database/factories/index.d.cts +7 -0
- package/dist/database/factories/index.d.ts +7 -0
- package/dist/database/factories/index.d.ts.map +1 -0
- package/dist/database/factories/index.js +8 -0
- package/dist/database/factories/memory.cjs +39 -0
- package/dist/database/factories/memory.d.cts +20 -0
- package/dist/database/factories/memory.d.ts +16 -0
- package/dist/database/factories/memory.d.ts.map +1 -0
- package/dist/database/factories/memory.js +15 -0
- package/dist/database/factories/postgres.cjs +61 -0
- package/dist/database/factories/postgres.d.cts +23 -0
- package/dist/database/factories/postgres.d.ts +19 -0
- package/dist/database/factories/postgres.d.ts.map +1 -0
- package/dist/database/factories/postgres.js +27 -0
- package/dist/database/factories/sqlite.cjs +65 -0
- package/dist/database/factories/sqlite.d.cts +24 -0
- package/dist/database/factories/sqlite.d.ts +20 -0
- package/dist/database/factories/sqlite.d.ts.map +1 -0
- package/dist/database/factories/sqlite.js +31 -0
- package/dist/database/factory.cjs +16 -0
- package/dist/database/factory.d.cts +42 -0
- package/dist/database/factory.d.ts +41 -0
- package/dist/database/factory.d.ts.map +1 -0
- package/dist/database/factory.js +0 -0
- package/dist/database/index.cjs +46 -0
- package/dist/database/index.d.cts +8 -0
- package/dist/database/index.d.ts +26 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +24 -0
- package/dist/database/memory-database-store.cjs +121 -0
- package/dist/database/memory-database-store.d.cts +30 -0
- package/dist/database/memory-database-store.d.ts +28 -0
- package/dist/database/memory-database-store.d.ts.map +1 -0
- package/dist/database/memory-database-store.js +97 -0
- package/dist/database/postgres-store.cjs +342 -0
- package/dist/database/postgres-store.d.cts +57 -0
- package/dist/database/postgres-store.d.ts +55 -0
- package/dist/database/postgres-store.d.ts.map +1 -0
- package/dist/database/postgres-store.js +318 -0
- package/dist/database/schemas.cjs +82 -0
- package/dist/database/schemas.d.cts +127 -0
- package/dist/database/schemas.d.ts +125 -0
- package/dist/database/schemas.d.ts.map +1 -0
- package/dist/database/schemas.js +54 -0
- package/dist/database/sqlite-store.cjs +270 -0
- package/dist/database/sqlite-store.d.cts +35 -0
- package/dist/database/sqlite-store.d.ts +33 -0
- package/dist/database/sqlite-store.d.ts.map +1 -0
- package/dist/database/sqlite-store.js +236 -0
- package/dist/database/types.cjs +16 -0
- package/dist/database/types.d.cts +1 -0
- package/dist/database/types.d.ts +2 -0
- package/dist/database/types.d.ts.map +1 -0
- package/dist/database/types.js +0 -0
- package/dist/index.cjs +82 -0
- package/dist/index.d.cts +24 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +50 -0
- package/dist/schemas.cjs +67 -0
- package/dist/schemas.d.cts +72 -0
- package/dist/schemas.d.ts +70 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +46 -0
- package/package.json +55 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var memory_blob_store_exports = {};
|
|
20
|
+
__export(memory_blob_store_exports, {
|
|
21
|
+
MemoryBlobStore: () => MemoryBlobStore
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(memory_blob_store_exports);
|
|
24
|
+
var import_crypto = require("crypto");
|
|
25
|
+
var import_stream = require("stream");
|
|
26
|
+
var import_core = require("@dexto/core");
|
|
27
|
+
var import_schemas = require("./schemas.js");
|
|
28
|
+
const MemoryBlobStoreOptionsSchema = import_schemas.InMemoryBlobStoreSchema.omit({ type: true });
|
|
29
|
+
class MemoryBlobStore {
|
|
30
|
+
config;
|
|
31
|
+
blobs = /* @__PURE__ */ new Map();
|
|
32
|
+
connected = false;
|
|
33
|
+
logger;
|
|
34
|
+
constructor(options, logger) {
|
|
35
|
+
this.config = MemoryBlobStoreOptionsSchema.parse(options);
|
|
36
|
+
this.logger = logger.createChild(import_core.DextoLogComponent.STORAGE);
|
|
37
|
+
}
|
|
38
|
+
async connect() {
|
|
39
|
+
if (this.connected) return;
|
|
40
|
+
this.connected = true;
|
|
41
|
+
this.logger.debug("MemoryBlobStore connected");
|
|
42
|
+
}
|
|
43
|
+
async disconnect() {
|
|
44
|
+
this.blobs.clear();
|
|
45
|
+
this.connected = false;
|
|
46
|
+
this.logger.debug("MemoryBlobStore disconnected");
|
|
47
|
+
}
|
|
48
|
+
isConnected() {
|
|
49
|
+
return this.connected;
|
|
50
|
+
}
|
|
51
|
+
getStoreType() {
|
|
52
|
+
return "in-memory";
|
|
53
|
+
}
|
|
54
|
+
async store(input, metadata = {}) {
|
|
55
|
+
if (!this.connected) {
|
|
56
|
+
throw import_core.StorageError.blobBackendNotConnected("in-memory");
|
|
57
|
+
}
|
|
58
|
+
const buffer = await this.inputToBuffer(input);
|
|
59
|
+
if (buffer.length > this.config.maxBlobSize) {
|
|
60
|
+
throw import_core.StorageError.blobSizeExceeded(buffer.length, this.config.maxBlobSize);
|
|
61
|
+
}
|
|
62
|
+
const hash = (0, import_crypto.createHash)("sha256").update(buffer).digest("hex").substring(0, 16);
|
|
63
|
+
const id = hash;
|
|
64
|
+
const existing = this.blobs.get(id);
|
|
65
|
+
if (existing) {
|
|
66
|
+
this.logger.debug(
|
|
67
|
+
`Blob ${id} already exists, returning existing reference (deduplication)`
|
|
68
|
+
);
|
|
69
|
+
return {
|
|
70
|
+
id,
|
|
71
|
+
uri: `blob:${id}`,
|
|
72
|
+
metadata: existing.metadata
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const currentSize = this.getTotalSize();
|
|
76
|
+
if (currentSize + buffer.length > this.config.maxTotalSize) {
|
|
77
|
+
throw import_core.StorageError.blobTotalSizeExceeded(
|
|
78
|
+
currentSize + buffer.length,
|
|
79
|
+
this.config.maxTotalSize
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
const storedMetadata = {
|
|
83
|
+
id,
|
|
84
|
+
mimeType: metadata.mimeType || this.detectMimeType(buffer, metadata.originalName),
|
|
85
|
+
originalName: metadata.originalName,
|
|
86
|
+
createdAt: metadata.createdAt || /* @__PURE__ */ new Date(),
|
|
87
|
+
source: metadata.source || "system",
|
|
88
|
+
size: buffer.length,
|
|
89
|
+
hash
|
|
90
|
+
};
|
|
91
|
+
this.blobs.set(id, { data: buffer, metadata: storedMetadata });
|
|
92
|
+
this.logger.debug(`Stored blob ${id} (${buffer.length} bytes, ${storedMetadata.mimeType})`);
|
|
93
|
+
return {
|
|
94
|
+
id,
|
|
95
|
+
uri: `blob:${id}`,
|
|
96
|
+
metadata: storedMetadata
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
async retrieve(reference, format = "base64") {
|
|
100
|
+
if (!this.connected) {
|
|
101
|
+
throw import_core.StorageError.blobBackendNotConnected("in-memory");
|
|
102
|
+
}
|
|
103
|
+
const id = this.parseReference(reference);
|
|
104
|
+
const blob = this.blobs.get(id);
|
|
105
|
+
if (!blob) {
|
|
106
|
+
throw import_core.StorageError.blobNotFound(reference);
|
|
107
|
+
}
|
|
108
|
+
switch (format) {
|
|
109
|
+
case "base64":
|
|
110
|
+
return {
|
|
111
|
+
format: "base64",
|
|
112
|
+
data: blob.data.toString("base64"),
|
|
113
|
+
metadata: blob.metadata
|
|
114
|
+
};
|
|
115
|
+
case "buffer":
|
|
116
|
+
return {
|
|
117
|
+
format: "buffer",
|
|
118
|
+
data: Buffer.from(blob.data),
|
|
119
|
+
metadata: { ...blob.metadata }
|
|
120
|
+
};
|
|
121
|
+
case "path":
|
|
122
|
+
throw new Error(
|
|
123
|
+
"Path format not supported for in-memory blobs. Use local blob storage for filesystem paths."
|
|
124
|
+
);
|
|
125
|
+
case "stream": {
|
|
126
|
+
const stream = import_stream.Readable.from(blob.data);
|
|
127
|
+
return {
|
|
128
|
+
format: "stream",
|
|
129
|
+
data: stream,
|
|
130
|
+
metadata: blob.metadata
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
case "url": {
|
|
134
|
+
const base64 = blob.data.toString("base64");
|
|
135
|
+
const mimeType = blob.metadata.mimeType || "application/octet-stream";
|
|
136
|
+
const dataUrl = `data:${mimeType};base64,${base64}`;
|
|
137
|
+
return {
|
|
138
|
+
format: "url",
|
|
139
|
+
data: dataUrl,
|
|
140
|
+
metadata: blob.metadata
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
default:
|
|
144
|
+
throw import_core.StorageError.blobInvalidInput(format, `Unsupported format: ${format}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async exists(reference) {
|
|
148
|
+
if (!this.connected) {
|
|
149
|
+
throw import_core.StorageError.blobBackendNotConnected("in-memory");
|
|
150
|
+
}
|
|
151
|
+
const id = this.parseReference(reference);
|
|
152
|
+
return this.blobs.has(id);
|
|
153
|
+
}
|
|
154
|
+
async delete(reference) {
|
|
155
|
+
if (!this.connected) {
|
|
156
|
+
throw import_core.StorageError.blobBackendNotConnected("in-memory");
|
|
157
|
+
}
|
|
158
|
+
const id = this.parseReference(reference);
|
|
159
|
+
if (!this.blobs.has(id)) {
|
|
160
|
+
throw import_core.StorageError.blobNotFound(reference);
|
|
161
|
+
}
|
|
162
|
+
this.blobs.delete(id);
|
|
163
|
+
this.logger.debug(`Deleted blob: ${id}`);
|
|
164
|
+
}
|
|
165
|
+
async cleanup(olderThan) {
|
|
166
|
+
if (!this.connected) {
|
|
167
|
+
throw import_core.StorageError.blobBackendNotConnected("in-memory");
|
|
168
|
+
}
|
|
169
|
+
const cutoffDate = olderThan || new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
170
|
+
let deletedCount = 0;
|
|
171
|
+
for (const [id, { metadata }] of this.blobs.entries()) {
|
|
172
|
+
if (metadata.createdAt < cutoffDate) {
|
|
173
|
+
this.blobs.delete(id);
|
|
174
|
+
deletedCount++;
|
|
175
|
+
this.logger.debug(`Cleaned up old blob: ${id}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (deletedCount > 0) {
|
|
179
|
+
this.logger.info(`Blob cleanup: removed ${deletedCount} old blobs from memory`);
|
|
180
|
+
}
|
|
181
|
+
return deletedCount;
|
|
182
|
+
}
|
|
183
|
+
async getStats() {
|
|
184
|
+
if (!this.connected) {
|
|
185
|
+
throw import_core.StorageError.blobBackendNotConnected("in-memory");
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
count: this.blobs.size,
|
|
189
|
+
totalSize: this.getTotalSize(),
|
|
190
|
+
backendType: "in-memory",
|
|
191
|
+
storePath: "memory://"
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
async listBlobs() {
|
|
195
|
+
if (!this.connected) {
|
|
196
|
+
throw import_core.StorageError.blobBackendNotConnected("in-memory");
|
|
197
|
+
}
|
|
198
|
+
return Array.from(this.blobs.entries()).map(([id, { metadata }]) => ({
|
|
199
|
+
id,
|
|
200
|
+
uri: `blob:${id}`,
|
|
201
|
+
metadata
|
|
202
|
+
}));
|
|
203
|
+
}
|
|
204
|
+
getStoragePath() {
|
|
205
|
+
return void 0;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Calculate total size of all blobs in memory
|
|
209
|
+
*/
|
|
210
|
+
getTotalSize() {
|
|
211
|
+
return Array.from(this.blobs.values()).reduce((sum, { data }) => sum + data.length, 0);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Convert various input types to Buffer.
|
|
215
|
+
* Copied from LocalBlobStore with minor adaptations.
|
|
216
|
+
*/
|
|
217
|
+
async inputToBuffer(input) {
|
|
218
|
+
if (Buffer.isBuffer(input)) {
|
|
219
|
+
return input;
|
|
220
|
+
}
|
|
221
|
+
if (input instanceof Uint8Array) {
|
|
222
|
+
return Buffer.from(input);
|
|
223
|
+
}
|
|
224
|
+
if (input instanceof ArrayBuffer) {
|
|
225
|
+
return Buffer.from(new Uint8Array(input));
|
|
226
|
+
}
|
|
227
|
+
if (typeof input === "string") {
|
|
228
|
+
if (input.startsWith("data:")) {
|
|
229
|
+
const commaIndex = input.indexOf(",");
|
|
230
|
+
if (commaIndex !== -1 && input.includes(";base64,")) {
|
|
231
|
+
const base64Data = input.substring(commaIndex + 1);
|
|
232
|
+
return Buffer.from(base64Data, "base64");
|
|
233
|
+
}
|
|
234
|
+
throw import_core.StorageError.blobEncodingError(
|
|
235
|
+
"inputToBuffer",
|
|
236
|
+
"Unsupported data URI format"
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
return Buffer.from(input, "base64");
|
|
241
|
+
} catch {
|
|
242
|
+
throw import_core.StorageError.blobEncodingError("inputToBuffer", "Invalid base64 string");
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
throw import_core.StorageError.blobInvalidInput(input, `Unsupported input type: ${typeof input}`);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Parse blob reference to extract ID.
|
|
249
|
+
* Copied from LocalBlobStore.
|
|
250
|
+
*/
|
|
251
|
+
parseReference(reference) {
|
|
252
|
+
if (!reference) {
|
|
253
|
+
throw import_core.StorageError.blobInvalidReference(reference, "Empty reference");
|
|
254
|
+
}
|
|
255
|
+
if (reference.startsWith("blob:")) {
|
|
256
|
+
const id = reference.substring(5);
|
|
257
|
+
if (!id) {
|
|
258
|
+
throw import_core.StorageError.blobInvalidReference(reference, "Empty blob ID after prefix");
|
|
259
|
+
}
|
|
260
|
+
return id;
|
|
261
|
+
}
|
|
262
|
+
return reference;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Detect MIME type from buffer content and/or filename.
|
|
266
|
+
* Copied from LocalBlobStore.
|
|
267
|
+
*/
|
|
268
|
+
detectMimeType(buffer, filename) {
|
|
269
|
+
const header = buffer.subarray(0, 16);
|
|
270
|
+
if (header.length >= 3) {
|
|
271
|
+
const jpegSignature = header.subarray(0, 3);
|
|
272
|
+
if (jpegSignature.equals(Buffer.from([255, 216, 255]))) {
|
|
273
|
+
return "image/jpeg";
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (header.length >= 4) {
|
|
277
|
+
const signature = header.subarray(0, 4);
|
|
278
|
+
if (signature.equals(Buffer.from([137, 80, 78, 71]))) return "image/png";
|
|
279
|
+
if (signature.equals(Buffer.from([71, 73, 70, 56]))) return "image/gif";
|
|
280
|
+
if (signature.equals(Buffer.from([37, 80, 68, 70]))) return "application/pdf";
|
|
281
|
+
}
|
|
282
|
+
if (filename) {
|
|
283
|
+
const ext = filename.split(".").pop()?.toLowerCase();
|
|
284
|
+
const mimeTypes = {
|
|
285
|
+
jpg: "image/jpeg",
|
|
286
|
+
jpeg: "image/jpeg",
|
|
287
|
+
png: "image/png",
|
|
288
|
+
gif: "image/gif",
|
|
289
|
+
pdf: "application/pdf",
|
|
290
|
+
txt: "text/plain",
|
|
291
|
+
json: "application/json",
|
|
292
|
+
xml: "text/xml",
|
|
293
|
+
html: "text/html",
|
|
294
|
+
css: "text/css",
|
|
295
|
+
js: "text/javascript",
|
|
296
|
+
md: "text/markdown",
|
|
297
|
+
mp3: "audio/mpeg",
|
|
298
|
+
mp4: "video/mp4",
|
|
299
|
+
wav: "audio/wav"
|
|
300
|
+
};
|
|
301
|
+
if (ext && mimeTypes[ext]) return mimeTypes[ext];
|
|
302
|
+
}
|
|
303
|
+
if (this.isTextBuffer(buffer)) {
|
|
304
|
+
return "text/plain";
|
|
305
|
+
}
|
|
306
|
+
return "application/octet-stream";
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Check if buffer contains text content.
|
|
310
|
+
* Copied from LocalBlobStore.
|
|
311
|
+
*/
|
|
312
|
+
isTextBuffer(buffer) {
|
|
313
|
+
let printableCount = 0;
|
|
314
|
+
const sampleSize = Math.min(512, buffer.length);
|
|
315
|
+
for (let i = 0; i < sampleSize; i++) {
|
|
316
|
+
const byte = buffer[i];
|
|
317
|
+
if (byte !== void 0 && (byte >= 32 && byte <= 126 || byte === 9 || byte === 10 || byte === 13)) {
|
|
318
|
+
printableCount++;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return printableCount / sampleSize > 0.7;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
325
|
+
0 && (module.exports = {
|
|
326
|
+
MemoryBlobStore
|
|
327
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { BlobStore, Logger, BlobInput, BlobMetadata, BlobReference, BlobData, BlobStats } from '@dexto/core';
|
|
2
|
+
import { InMemoryBlobStoreConfigInput } from './schemas.cjs';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* In-memory blob store implementation.
|
|
7
|
+
*
|
|
8
|
+
* Stores blobs in memory with content-based deduplication and size limits.
|
|
9
|
+
* Suitable for development, testing, and scenarios where blob persistence
|
|
10
|
+
* across restarts is not required.
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - Content-based deduplication (same as LocalBlobStore)
|
|
14
|
+
* - Configurable size limits (per-blob and total)
|
|
15
|
+
* - Automatic cleanup of old blobs
|
|
16
|
+
* - MIME type detection
|
|
17
|
+
* - Multi-format retrieval (base64, buffer, stream, data URI)
|
|
18
|
+
*
|
|
19
|
+
* Limitations:
|
|
20
|
+
* - Data lost on restart (no persistence)
|
|
21
|
+
* - Path format not supported (no filesystem)
|
|
22
|
+
* - Memory usage proportional to blob size
|
|
23
|
+
*/
|
|
24
|
+
type MemoryBlobStoreOptions = Omit<InMemoryBlobStoreConfigInput, 'type'>;
|
|
25
|
+
declare class MemoryBlobStore implements BlobStore {
|
|
26
|
+
private config;
|
|
27
|
+
private blobs;
|
|
28
|
+
private connected;
|
|
29
|
+
private logger;
|
|
30
|
+
constructor(options: MemoryBlobStoreOptions, logger: Logger);
|
|
31
|
+
connect(): Promise<void>;
|
|
32
|
+
disconnect(): Promise<void>;
|
|
33
|
+
isConnected(): boolean;
|
|
34
|
+
getStoreType(): string;
|
|
35
|
+
store(input: BlobInput, metadata?: BlobMetadata): Promise<BlobReference>;
|
|
36
|
+
retrieve(reference: string, format?: 'base64' | 'buffer' | 'path' | 'stream' | 'url'): Promise<BlobData>;
|
|
37
|
+
exists(reference: string): Promise<boolean>;
|
|
38
|
+
delete(reference: string): Promise<void>;
|
|
39
|
+
cleanup(olderThan?: Date): Promise<number>;
|
|
40
|
+
getStats(): Promise<BlobStats>;
|
|
41
|
+
listBlobs(): Promise<BlobReference[]>;
|
|
42
|
+
getStoragePath(): string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Calculate total size of all blobs in memory
|
|
45
|
+
*/
|
|
46
|
+
private getTotalSize;
|
|
47
|
+
/**
|
|
48
|
+
* Convert various input types to Buffer.
|
|
49
|
+
* Copied from LocalBlobStore with minor adaptations.
|
|
50
|
+
*/
|
|
51
|
+
private inputToBuffer;
|
|
52
|
+
/**
|
|
53
|
+
* Parse blob reference to extract ID.
|
|
54
|
+
* Copied from LocalBlobStore.
|
|
55
|
+
*/
|
|
56
|
+
private parseReference;
|
|
57
|
+
/**
|
|
58
|
+
* Detect MIME type from buffer content and/or filename.
|
|
59
|
+
* Copied from LocalBlobStore.
|
|
60
|
+
*/
|
|
61
|
+
private detectMimeType;
|
|
62
|
+
/**
|
|
63
|
+
* Check if buffer contains text content.
|
|
64
|
+
* Copied from LocalBlobStore.
|
|
65
|
+
*/
|
|
66
|
+
private isTextBuffer;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { MemoryBlobStore, type MemoryBlobStoreOptions };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Logger } from '@dexto/core';
|
|
2
|
+
import type { BlobStore, BlobInput, BlobMetadata, BlobReference, BlobData, BlobStats } from './types.js';
|
|
3
|
+
import type { InMemoryBlobStoreConfigInput } from './schemas.js';
|
|
4
|
+
/**
|
|
5
|
+
* In-memory blob store implementation.
|
|
6
|
+
*
|
|
7
|
+
* Stores blobs in memory with content-based deduplication and size limits.
|
|
8
|
+
* Suitable for development, testing, and scenarios where blob persistence
|
|
9
|
+
* across restarts is not required.
|
|
10
|
+
*
|
|
11
|
+
* Features:
|
|
12
|
+
* - Content-based deduplication (same as LocalBlobStore)
|
|
13
|
+
* - Configurable size limits (per-blob and total)
|
|
14
|
+
* - Automatic cleanup of old blobs
|
|
15
|
+
* - MIME type detection
|
|
16
|
+
* - Multi-format retrieval (base64, buffer, stream, data URI)
|
|
17
|
+
*
|
|
18
|
+
* Limitations:
|
|
19
|
+
* - Data lost on restart (no persistence)
|
|
20
|
+
* - Path format not supported (no filesystem)
|
|
21
|
+
* - Memory usage proportional to blob size
|
|
22
|
+
*/
|
|
23
|
+
export type MemoryBlobStoreOptions = Omit<InMemoryBlobStoreConfigInput, 'type'>;
|
|
24
|
+
export declare class MemoryBlobStore implements BlobStore {
|
|
25
|
+
private config;
|
|
26
|
+
private blobs;
|
|
27
|
+
private connected;
|
|
28
|
+
private logger;
|
|
29
|
+
constructor(options: MemoryBlobStoreOptions, logger: Logger);
|
|
30
|
+
connect(): Promise<void>;
|
|
31
|
+
disconnect(): Promise<void>;
|
|
32
|
+
isConnected(): boolean;
|
|
33
|
+
getStoreType(): string;
|
|
34
|
+
store(input: BlobInput, metadata?: BlobMetadata): Promise<BlobReference>;
|
|
35
|
+
retrieve(reference: string, format?: 'base64' | 'buffer' | 'path' | 'stream' | 'url'): Promise<BlobData>;
|
|
36
|
+
exists(reference: string): Promise<boolean>;
|
|
37
|
+
delete(reference: string): Promise<void>;
|
|
38
|
+
cleanup(olderThan?: Date): Promise<number>;
|
|
39
|
+
getStats(): Promise<BlobStats>;
|
|
40
|
+
listBlobs(): Promise<BlobReference[]>;
|
|
41
|
+
getStoragePath(): string | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Calculate total size of all blobs in memory
|
|
44
|
+
*/
|
|
45
|
+
private getTotalSize;
|
|
46
|
+
/**
|
|
47
|
+
* Convert various input types to Buffer.
|
|
48
|
+
* Copied from LocalBlobStore with minor adaptations.
|
|
49
|
+
*/
|
|
50
|
+
private inputToBuffer;
|
|
51
|
+
/**
|
|
52
|
+
* Parse blob reference to extract ID.
|
|
53
|
+
* Copied from LocalBlobStore.
|
|
54
|
+
*/
|
|
55
|
+
private parseReference;
|
|
56
|
+
/**
|
|
57
|
+
* Detect MIME type from buffer content and/or filename.
|
|
58
|
+
* Copied from LocalBlobStore.
|
|
59
|
+
*/
|
|
60
|
+
private detectMimeType;
|
|
61
|
+
/**
|
|
62
|
+
* Check if buffer contains text content.
|
|
63
|
+
* Copied from LocalBlobStore.
|
|
64
|
+
*/
|
|
65
|
+
private isTextBuffer;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=memory-blob-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-blob-store.d.ts","sourceRoot":"","sources":["../../src/blob/memory-blob-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EACR,SAAS,EACT,SAAS,EACT,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,SAAS,EAEZ,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,cAAc,CAAC;AAEjE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,4BAA4B,EAAE,MAAM,CAAC,CAAC;AAIhF,qBAAa,eAAgB,YAAW,SAAS;IAC7C,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,KAAK,CAA0E;IACvF,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,EAAE,sBAAsB,EAAE,MAAM,EAAE,MAAM;IAKrD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAOjC,WAAW,IAAI,OAAO;IAItB,YAAY,IAAI,MAAM;IAIhB,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,GAAE,YAAiB,GAAG,OAAO,CAAC,aAAa,CAAC;IA8D5E,QAAQ,CACV,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAgB,GACnE,OAAO,CAAC,QAAQ,CAAC;IA6Dd,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS3C,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAexC,OAAO,CAAC,SAAS,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAwB1C,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC;IAc9B,SAAS,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAY3C,cAAc,IAAI,MAAM,GAAG,SAAS;IAKpC;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;;OAGG;YACW,aAAa;IAuC3B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAgBtB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAkDtB;;;OAGG;IACH,OAAO,CAAC,YAAY;CAiBvB"}
|