@neutron-build/data 0.1.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 +21 -0
- package/README.md +25 -0
- package/dist/cache/index.d.ts +14 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +29 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/nucleus.d.ts +46 -0
- package/dist/cache/nucleus.d.ts.map +1 -0
- package/dist/cache/nucleus.js +50 -0
- package/dist/cache/nucleus.js.map +1 -0
- package/dist/cache/redis.d.ts +28 -0
- package/dist/cache/redis.d.ts.map +1 -0
- package/dist/cache/redis.js +52 -0
- package/dist/cache/redis.js.map +1 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +36 -0
- package/dist/config.js.map +1 -0
- package/dist/db/drizzle.d.ts +23 -0
- package/dist/db/drizzle.d.ts.map +1 -0
- package/dist/db/drizzle.js +124 -0
- package/dist/db/drizzle.js.map +1 -0
- package/dist/db/index.d.ts +7 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +32 -0
- package/dist/db/index.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/lazy-import.d.ts +2 -0
- package/dist/internal/lazy-import.d.ts.map +1 -0
- package/dist/internal/lazy-import.js +11 -0
- package/dist/internal/lazy-import.js.map +1 -0
- package/dist/jobs/index.d.ts +6 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +5 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/queue/bullmq.d.ts +42 -0
- package/dist/queue/bullmq.d.ts.map +1 -0
- package/dist/queue/bullmq.js +80 -0
- package/dist/queue/bullmq.js.map +1 -0
- package/dist/queue/index.d.ts +21 -0
- package/dist/queue/index.d.ts.map +1 -0
- package/dist/queue/index.js +43 -0
- package/dist/queue/index.js.map +1 -0
- package/dist/ratelimit/index.d.ts +12 -0
- package/dist/ratelimit/index.d.ts.map +1 -0
- package/dist/ratelimit/index.js +28 -0
- package/dist/ratelimit/index.js.map +1 -0
- package/dist/realtime/index.d.ts +12 -0
- package/dist/realtime/index.d.ts.map +1 -0
- package/dist/realtime/index.js +31 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/realtime/nucleus.d.ts +33 -0
- package/dist/realtime/nucleus.d.ts.map +1 -0
- package/dist/realtime/nucleus.js +62 -0
- package/dist/realtime/nucleus.js.map +1 -0
- package/dist/realtime/redis.d.ts +54 -0
- package/dist/realtime/redis.d.ts.map +1 -0
- package/dist/realtime/redis.js +138 -0
- package/dist/realtime/redis.js.map +1 -0
- package/dist/session/index.d.ts +19 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +31 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/redis.d.ts +12 -0
- package/dist/session/redis.d.ts.map +1 -0
- package/dist/session/redis.js +22 -0
- package/dist/session/redis.js.map +1 -0
- package/dist/storage/index.d.ts +17 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +13 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/nucleus.d.ts +40 -0
- package/dist/storage/nucleus.d.ts.map +1 -0
- package/dist/storage/nucleus.js +45 -0
- package/dist/storage/nucleus.js.map +1 -0
- package/dist/storage/s3.d.ts +30 -0
- package/dist/storage/s3.d.ts.map +1 -0
- package/dist/storage/s3.js +123 -0
- package/dist/storage/s3.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { lazyImport } from "../internal/lazy-import.js";
|
|
2
|
+
export class RedisRealtimeBus {
|
|
3
|
+
publisher;
|
|
4
|
+
subscriber = null;
|
|
5
|
+
channels = new Map();
|
|
6
|
+
channelPrefix;
|
|
7
|
+
closed = false;
|
|
8
|
+
constructor(publisher, channelPrefix = "") {
|
|
9
|
+
this.publisher = publisher;
|
|
10
|
+
this.channelPrefix = channelPrefix;
|
|
11
|
+
}
|
|
12
|
+
// ── publish ──────────────────────────────────────────────────────────
|
|
13
|
+
async publish(channel, payload) {
|
|
14
|
+
if (this.closed) {
|
|
15
|
+
throw new Error("RedisRealtimeBus is closed.");
|
|
16
|
+
}
|
|
17
|
+
await this.publisher.publish(this.prefixed(channel), JSON.stringify(payload));
|
|
18
|
+
}
|
|
19
|
+
// ── subscribe ────────────────────────────────────────────────────────
|
|
20
|
+
subscribe(channel, subscriber) {
|
|
21
|
+
if (this.closed) {
|
|
22
|
+
throw new Error("RedisRealtimeBus is closed.");
|
|
23
|
+
}
|
|
24
|
+
const prefixedChannel = this.prefixed(channel);
|
|
25
|
+
let subs = this.channels.get(prefixedChannel);
|
|
26
|
+
const isNew = !subs;
|
|
27
|
+
if (!subs) {
|
|
28
|
+
subs = new Set();
|
|
29
|
+
this.channels.set(prefixedChannel, subs);
|
|
30
|
+
}
|
|
31
|
+
subs.add(subscriber);
|
|
32
|
+
// If this is the first subscriber on this channel, tell Redis.
|
|
33
|
+
if (isNew) {
|
|
34
|
+
const sub = this.ensureSubscriber();
|
|
35
|
+
// Fire-and-forget; the subscriber will buffer messages once acked.
|
|
36
|
+
sub.subscribe(prefixedChannel).catch((err) => {
|
|
37
|
+
// If subscribing fails, clean up to avoid a dangling channel.
|
|
38
|
+
this.channels.delete(prefixedChannel);
|
|
39
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
40
|
+
console.error(`[neutron-data] RedisRealtimeBus: failed to subscribe to "${prefixedChannel}": ${msg}`);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Return an unsubscribe function (mirrors InMemoryRealtimeBus).
|
|
44
|
+
return () => {
|
|
45
|
+
const existing = this.channels.get(prefixedChannel);
|
|
46
|
+
if (!existing) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
existing.delete(subscriber);
|
|
50
|
+
if (existing.size === 0) {
|
|
51
|
+
this.channels.delete(prefixedChannel);
|
|
52
|
+
// Unsubscribe from Redis when no local handlers remain.
|
|
53
|
+
if (this.subscriber) {
|
|
54
|
+
this.subscriber.unsubscribe(prefixedChannel).catch(() => {
|
|
55
|
+
// best-effort
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// ── close ────────────────────────────────────────────────────────────
|
|
62
|
+
async close() {
|
|
63
|
+
if (this.closed) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.closed = true;
|
|
67
|
+
this.channels.clear();
|
|
68
|
+
if (this.subscriber) {
|
|
69
|
+
this.subscriber.removeAllListeners("message");
|
|
70
|
+
await this.subscriber.quit().catch(() => { });
|
|
71
|
+
this.subscriber = null;
|
|
72
|
+
}
|
|
73
|
+
await this.publisher.quit().catch(() => { });
|
|
74
|
+
}
|
|
75
|
+
// ── internals ────────────────────────────────────────────────────────
|
|
76
|
+
/**
|
|
77
|
+
* Lazily create the subscriber connection by duplicating the publisher.
|
|
78
|
+
* ioredis's `duplicate()` creates a new connection with the same options,
|
|
79
|
+
* which is exactly what we need for subscriber-mode isolation.
|
|
80
|
+
*/
|
|
81
|
+
ensureSubscriber() {
|
|
82
|
+
if (this.subscriber) {
|
|
83
|
+
return this.subscriber;
|
|
84
|
+
}
|
|
85
|
+
const sub = this.publisher.duplicate();
|
|
86
|
+
sub.on("message", (rawChannel, rawMessage) => {
|
|
87
|
+
const ch = String(rawChannel);
|
|
88
|
+
const handlers = this.channels.get(ch);
|
|
89
|
+
if (!handlers || handlers.size === 0) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
let parsed;
|
|
93
|
+
try {
|
|
94
|
+
parsed = JSON.parse(String(rawMessage));
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
parsed = rawMessage;
|
|
98
|
+
}
|
|
99
|
+
for (const handler of handlers) {
|
|
100
|
+
try {
|
|
101
|
+
handler(parsed);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
105
|
+
console.error(`[neutron-data] RedisRealtimeBus: handler error on "${ch}": ${msg}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
this.subscriber = sub;
|
|
110
|
+
return sub;
|
|
111
|
+
}
|
|
112
|
+
prefixed(channel) {
|
|
113
|
+
return this.channelPrefix ? `${this.channelPrefix}${channel}` : channel;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// ── Factory ──────────────────────────────────────────────────────────────
|
|
117
|
+
export async function createRedisRealtimeBus(options = {}) {
|
|
118
|
+
// If the caller already has an ioredis client, use it directly.
|
|
119
|
+
if (options.publisherClient) {
|
|
120
|
+
return new RedisRealtimeBus(options.publisherClient, options.channelPrefix ?? "");
|
|
121
|
+
}
|
|
122
|
+
// Otherwise, lazy-require ioredis (it's an optional peer dep).
|
|
123
|
+
const redisModule = await lazyImport("ioredis", "Install with `pnpm add ioredis` (or npm/yarn equivalent)");
|
|
124
|
+
const RedisCtor = redisModule.default;
|
|
125
|
+
if (!RedisCtor) {
|
|
126
|
+
throw new Error("Failed to resolve ioredis default export.");
|
|
127
|
+
}
|
|
128
|
+
const url = options.url ||
|
|
129
|
+
process.env.DRAGONFLY_URL ||
|
|
130
|
+
process.env.REDIS_URL ||
|
|
131
|
+
"redis://127.0.0.1:6379";
|
|
132
|
+
const publisher = new RedisCtor(url, {
|
|
133
|
+
lazyConnect: false,
|
|
134
|
+
maxRetriesPerRequest: 3,
|
|
135
|
+
});
|
|
136
|
+
return new RedisRealtimeBus(publisher, options.channelPrefix ?? "");
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=redis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/realtime/redis.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CacheClient } from "../cache/index.js";
|
|
2
|
+
export type SessionData = Record<string, unknown>;
|
|
3
|
+
export interface SessionRecord<T extends SessionData = SessionData> {
|
|
4
|
+
id: string;
|
|
5
|
+
data: T;
|
|
6
|
+
}
|
|
7
|
+
export interface SessionStore {
|
|
8
|
+
create<T extends SessionData = SessionData>(data?: T): Promise<SessionRecord<T>>;
|
|
9
|
+
get<T extends SessionData = SessionData>(id: string): Promise<SessionRecord<T> | null>;
|
|
10
|
+
set<T extends SessionData = SessionData>(id: string, data: T): Promise<void>;
|
|
11
|
+
destroy(id: string): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export interface SessionStoreOptions {
|
|
14
|
+
cache: CacheClient;
|
|
15
|
+
prefix?: string;
|
|
16
|
+
ttlSec?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function createSessionStore(options: SessionStoreOptions): SessionStore;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAElD,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,CAAC,CAAC;CACT;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IACjF,GAAG,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvF,GAAG,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CA8B7E"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
export function createSessionStore(options) {
|
|
3
|
+
const prefix = options.prefix || "session:";
|
|
4
|
+
const ttlSec = options.ttlSec ?? 60 * 60 * 24 * 7;
|
|
5
|
+
const cacheKey = (id) => `${prefix}${id}`;
|
|
6
|
+
return {
|
|
7
|
+
async create(data) {
|
|
8
|
+
const id = randomUUID();
|
|
9
|
+
const payload = (data || {});
|
|
10
|
+
await options.cache.set(cacheKey(id), JSON.stringify(payload), ttlSec);
|
|
11
|
+
return { id, data: payload };
|
|
12
|
+
},
|
|
13
|
+
async get(id) {
|
|
14
|
+
const raw = await options.cache.get(cacheKey(id));
|
|
15
|
+
if (!raw) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
id,
|
|
20
|
+
data: JSON.parse(raw),
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
async set(id, data) {
|
|
24
|
+
await options.cache.set(cacheKey(id), JSON.stringify(data), ttlSec);
|
|
25
|
+
},
|
|
26
|
+
async destroy(id) {
|
|
27
|
+
await options.cache.del(cacheKey(id));
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAuBzC,MAAM,UAAU,kBAAkB,CAAC,OAA4B;IAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,UAAU,CAAC;IAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAElD,MAAM,QAAQ,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,GAAG,MAAM,GAAG,EAAE,EAAE,CAAC;IAElD,OAAO;QACL,KAAK,CAAC,MAAM,CAAsC,IAAQ;YACxD,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,CAAC,IAAI,IAAK,EAAQ,CAAM,CAAC;YACzC,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;YACvE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC/B,CAAC;QACD,KAAK,CAAC,GAAG,CAAsC,EAAU;YACvD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;YAClD,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO;gBACL,EAAE;gBACF,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAM;aAC3B,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,GAAG,CAAsC,EAAU,EAAE,IAAO;YAChE,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QACtE,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,EAAU;YACtB,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;QACxC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type RedisCacheClient, type RedisCacheClientOptions } from "../cache/redis.js";
|
|
2
|
+
import { type SessionStore } from "./index.js";
|
|
3
|
+
export interface RedisSessionStoreOptions extends RedisCacheClientOptions {
|
|
4
|
+
sessionPrefix?: string;
|
|
5
|
+
sessionTtlSec?: number;
|
|
6
|
+
}
|
|
7
|
+
export type RedisSessionStore = SessionStore & {
|
|
8
|
+
cache: RedisCacheClient;
|
|
9
|
+
close: () => Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
export declare function createRedisSessionStore(options?: RedisSessionStoreOptions): Promise<RedisSessionStore>;
|
|
12
|
+
//# sourceMappingURL=redis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/session/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,wBAAyB,SAAQ,uBAAuB;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG;IAC7C,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAEF,wBAAsB,uBAAuB,CAC3C,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,iBAAiB,CAAC,CAoB5B"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createRedisCacheClient, } from "../cache/redis.js";
|
|
2
|
+
import { createSessionStore, } from "./index.js";
|
|
3
|
+
export async function createRedisSessionStore(options = {}) {
|
|
4
|
+
const cache = await createRedisCacheClient({
|
|
5
|
+
url: options.url,
|
|
6
|
+
keyPrefix: options.keyPrefix,
|
|
7
|
+
connectTimeoutMs: options.connectTimeoutMs,
|
|
8
|
+
});
|
|
9
|
+
const store = createSessionStore({
|
|
10
|
+
cache,
|
|
11
|
+
prefix: options.sessionPrefix,
|
|
12
|
+
ttlSec: options.sessionTtlSec,
|
|
13
|
+
});
|
|
14
|
+
return {
|
|
15
|
+
...store,
|
|
16
|
+
cache,
|
|
17
|
+
close: async () => {
|
|
18
|
+
await cache.close();
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=redis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/session/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,GAGvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,kBAAkB,GAEnB,MAAM,YAAY,CAAC;AAYpB,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,UAAoC,EAAE;IAEtC,MAAM,KAAK,GAAG,MAAM,sBAAsB,CAAC;QACzC,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;KAC3C,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,kBAAkB,CAAC;QAC/B,KAAK;QACL,MAAM,EAAE,OAAO,CAAC,aAAa;QAC7B,MAAM,EAAE,OAAO,CAAC,aAAa;KAC9B,CAAC,CAAC;IAEH,OAAO;QACL,GAAG,KAAK;QACR,KAAK;QACL,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;QACtB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface StorageObject {
|
|
2
|
+
key: string;
|
|
3
|
+
body: Uint8Array;
|
|
4
|
+
contentType?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface StorageDriver {
|
|
7
|
+
put(object: StorageObject): Promise<void>;
|
|
8
|
+
get(key: string): Promise<StorageObject | null>;
|
|
9
|
+
del(key: string): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export declare class InMemoryStorageDriver implements StorageDriver {
|
|
12
|
+
private store;
|
|
13
|
+
put(object: StorageObject): Promise<void>;
|
|
14
|
+
get(key: string): Promise<StorageObject | null>;
|
|
15
|
+
del(key: string): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAChD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAED,qBAAa,qBAAsB,YAAW,aAAa;IACzD,OAAO,CAAC,KAAK,CAAoC;IAE3C,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAI/C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGtC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class InMemoryStorageDriver {
|
|
2
|
+
store = new Map();
|
|
3
|
+
async put(object) {
|
|
4
|
+
this.store.set(object.key, object);
|
|
5
|
+
}
|
|
6
|
+
async get(key) {
|
|
7
|
+
return this.store.get(key) || null;
|
|
8
|
+
}
|
|
9
|
+
async del(key) {
|
|
10
|
+
this.store.delete(key);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,qBAAqB;IACxB,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAEjD,KAAK,CAAC,GAAG,CAAC,MAAqB;QAC7B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { StorageDriver, StorageObject } from "./index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Blob-like interface matching the subset of @neutron-build/nucleus BlobModel
|
|
4
|
+
* needed by NucleusStorageDriver.
|
|
5
|
+
*/
|
|
6
|
+
export interface NucleusBlobLike {
|
|
7
|
+
put(bucket: string, key: string, data: Uint8Array | string, opts?: {
|
|
8
|
+
contentType?: string;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
get(bucket: string, key: string): Promise<{
|
|
11
|
+
data: Uint8Array;
|
|
12
|
+
meta: unknown;
|
|
13
|
+
} | null>;
|
|
14
|
+
delete(bucket: string, key: string): Promise<boolean>;
|
|
15
|
+
}
|
|
16
|
+
export interface NucleusStorageDriverOptions {
|
|
17
|
+
/** A Blob model instance (from `@neutron-build/nucleus`). */
|
|
18
|
+
blob: NucleusBlobLike;
|
|
19
|
+
/** Bucket name for all stored objects (default `"default"`). */
|
|
20
|
+
bucket?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* StorageDriver implementation backed by Nucleus Blob.
|
|
24
|
+
*
|
|
25
|
+
* Drop-in replacement for `InMemoryStorageDriver` or `S3StorageDriver`
|
|
26
|
+
* that stores binary data directly in Nucleus.
|
|
27
|
+
*/
|
|
28
|
+
export declare class NucleusStorageDriver implements StorageDriver {
|
|
29
|
+
private readonly blob;
|
|
30
|
+
private readonly bucket;
|
|
31
|
+
constructor(options: NucleusStorageDriverOptions);
|
|
32
|
+
put(object: StorageObject): Promise<void>;
|
|
33
|
+
get(key: string): Promise<StorageObject | null>;
|
|
34
|
+
del(key: string): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Factory function matching the pattern of `createS3StorageDriver`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createNucleusStorageDriver(options: NucleusStorageDriverOptions): NucleusStorageDriver;
|
|
40
|
+
//# sourceMappingURL=nucleus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nucleus.d.ts","sourceRoot":"","sources":["../../src/storage/nucleus.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/D;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5G,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACtF,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,2BAA2B;IAC1C,6DAA6D;IAC7D,IAAI,EAAE,eAAe,CAAC;IACtB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,aAAa;IACxD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,OAAO,EAAE,2BAA2B;IAK1C,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAS/C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGtC;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,2BAA2B,GAAG,oBAAoB,CAErG"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// StorageDriver backed by Nucleus Blob model
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// When the application connects to Nucleus, this adapter bridges
|
|
6
|
+
// neutron-data's StorageDriver interface to the Blob model's SQL functions.
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
/**
|
|
9
|
+
* StorageDriver implementation backed by Nucleus Blob.
|
|
10
|
+
*
|
|
11
|
+
* Drop-in replacement for `InMemoryStorageDriver` or `S3StorageDriver`
|
|
12
|
+
* that stores binary data directly in Nucleus.
|
|
13
|
+
*/
|
|
14
|
+
export class NucleusStorageDriver {
|
|
15
|
+
blob;
|
|
16
|
+
bucket;
|
|
17
|
+
constructor(options) {
|
|
18
|
+
this.blob = options.blob;
|
|
19
|
+
this.bucket = options.bucket ?? "default";
|
|
20
|
+
}
|
|
21
|
+
async put(object) {
|
|
22
|
+
await this.blob.put(this.bucket, object.key, object.body, {
|
|
23
|
+
contentType: object.contentType,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
async get(key) {
|
|
27
|
+
const result = await this.blob.get(this.bucket, key);
|
|
28
|
+
if (!result)
|
|
29
|
+
return null;
|
|
30
|
+
return {
|
|
31
|
+
key,
|
|
32
|
+
body: result.data,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async del(key) {
|
|
36
|
+
await this.blob.delete(this.bucket, key);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Factory function matching the pattern of `createS3StorageDriver`.
|
|
41
|
+
*/
|
|
42
|
+
export function createNucleusStorageDriver(options) {
|
|
43
|
+
return new NucleusStorageDriver(options);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=nucleus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nucleus.js","sourceRoot":"","sources":["../../src/storage/nucleus.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,6CAA6C;AAC7C,8EAA8E;AAC9E,EAAE;AACF,iEAAiE;AACjE,4EAA4E;AAC5E,8EAA8E;AAqB9E;;;;;GAKG;AACH,MAAM,OAAO,oBAAoB;IACd,IAAI,CAAkB;IACtB,MAAM,CAAS;IAEhC,YAAY,OAAoC;QAC9C,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,SAAS,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,MAAqB;QAC7B,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,EAAE;YACxD,WAAW,EAAE,MAAM,CAAC,WAAW;SAChC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,OAAO;YACL,GAAG;YACH,IAAI,EAAE,MAAM,CAAC,IAAI;SAClB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3C,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,0BAA0B,CAAC,OAAoC;IAC7E,OAAO,IAAI,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { StorageDriver, StorageObject } from "./index.js";
|
|
2
|
+
export interface S3StorageDriverOptions {
|
|
3
|
+
bucket: string;
|
|
4
|
+
region?: string;
|
|
5
|
+
endpoint?: string;
|
|
6
|
+
forcePathStyle?: boolean;
|
|
7
|
+
accessKeyId?: string;
|
|
8
|
+
secretAccessKey?: string;
|
|
9
|
+
}
|
|
10
|
+
interface S3LikeClient {
|
|
11
|
+
send(command: unknown): Promise<unknown>;
|
|
12
|
+
}
|
|
13
|
+
interface S3CommandsModule {
|
|
14
|
+
S3Client?: new (options: Record<string, unknown>) => S3LikeClient;
|
|
15
|
+
PutObjectCommand?: new (input: Record<string, unknown>) => unknown;
|
|
16
|
+
GetObjectCommand?: new (input: Record<string, unknown>) => unknown;
|
|
17
|
+
DeleteObjectCommand?: new (input: Record<string, unknown>) => unknown;
|
|
18
|
+
}
|
|
19
|
+
export declare class S3StorageDriver implements StorageDriver {
|
|
20
|
+
private readonly client;
|
|
21
|
+
private readonly bucket;
|
|
22
|
+
private readonly commands;
|
|
23
|
+
constructor(client: S3LikeClient, bucket: string, commands: Required<Pick<S3CommandsModule, "PutObjectCommand" | "GetObjectCommand" | "DeleteObjectCommand">>);
|
|
24
|
+
put(object: StorageObject): Promise<void>;
|
|
25
|
+
get(key: string): Promise<StorageObject | null>;
|
|
26
|
+
del(key: string): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export declare function createS3StorageDriver(options: S3StorageDriverOptions): Promise<S3StorageDriver>;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=s3.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../src/storage/s3.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG/D,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,UAAU,YAAY;IACpB,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C;AAED,UAAU,gBAAgB;IACxB,QAAQ,CAAC,EAAE,KAAK,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,YAAY,CAAC;IAClE,gBAAgB,CAAC,EAAE,KAAK,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;IACnE,gBAAgB,CAAC,EAAE,KAAK,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;IACnE,mBAAmB,CAAC,EAAE,KAAK,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;CACvE;AAED,qBAAa,eAAgB,YAAW,aAAa;IAEjD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAFR,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,CACjC,IAAI,CAAC,gBAAgB,EAAE,kBAAkB,GAAG,kBAAkB,GAAG,qBAAqB,CAAC,CACxF;IAGG,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IA6B/C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAOtC;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC,CAsC1B"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { lazyImport } from "../internal/lazy-import.js";
|
|
2
|
+
export class S3StorageDriver {
|
|
3
|
+
client;
|
|
4
|
+
bucket;
|
|
5
|
+
commands;
|
|
6
|
+
constructor(client, bucket, commands) {
|
|
7
|
+
this.client = client;
|
|
8
|
+
this.bucket = bucket;
|
|
9
|
+
this.commands = commands;
|
|
10
|
+
}
|
|
11
|
+
async put(object) {
|
|
12
|
+
const command = new this.commands.PutObjectCommand({
|
|
13
|
+
Bucket: this.bucket,
|
|
14
|
+
Key: object.key,
|
|
15
|
+
Body: object.body,
|
|
16
|
+
ContentType: object.contentType,
|
|
17
|
+
});
|
|
18
|
+
await this.client.send(command);
|
|
19
|
+
}
|
|
20
|
+
async get(key) {
|
|
21
|
+
const command = new this.commands.GetObjectCommand({
|
|
22
|
+
Bucket: this.bucket,
|
|
23
|
+
Key: key,
|
|
24
|
+
});
|
|
25
|
+
try {
|
|
26
|
+
const result = (await this.client.send(command));
|
|
27
|
+
if (!result.Body) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const body = await toUint8Array(result.Body);
|
|
31
|
+
return {
|
|
32
|
+
key,
|
|
33
|
+
body,
|
|
34
|
+
contentType: result.ContentType,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
const statusCode = error.$metadata?.httpStatusCode;
|
|
39
|
+
if (statusCode === 404) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async del(key) {
|
|
46
|
+
const command = new this.commands.DeleteObjectCommand({
|
|
47
|
+
Bucket: this.bucket,
|
|
48
|
+
Key: key,
|
|
49
|
+
});
|
|
50
|
+
await this.client.send(command);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export async function createS3StorageDriver(options) {
|
|
54
|
+
const module = await lazyImport("@aws-sdk/client-s3", "Install with `pnpm add @aws-sdk/client-s3` (or npm/yarn equivalent)");
|
|
55
|
+
if (!module.S3Client ||
|
|
56
|
+
!module.PutObjectCommand ||
|
|
57
|
+
!module.GetObjectCommand ||
|
|
58
|
+
!module.DeleteObjectCommand) {
|
|
59
|
+
throw new Error("Failed to initialize S3 driver.");
|
|
60
|
+
}
|
|
61
|
+
const region = options.region || process.env.AWS_REGION || "auto";
|
|
62
|
+
const accessKeyId = options.accessKeyId || process.env.AWS_ACCESS_KEY_ID;
|
|
63
|
+
const secretAccessKey = options.secretAccessKey || process.env.AWS_SECRET_ACCESS_KEY;
|
|
64
|
+
const client = new module.S3Client({
|
|
65
|
+
region,
|
|
66
|
+
endpoint: options.endpoint,
|
|
67
|
+
forcePathStyle: options.forcePathStyle,
|
|
68
|
+
...(accessKeyId && secretAccessKey
|
|
69
|
+
? {
|
|
70
|
+
credentials: {
|
|
71
|
+
accessKeyId,
|
|
72
|
+
secretAccessKey,
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
: {}),
|
|
76
|
+
});
|
|
77
|
+
return new S3StorageDriver(client, options.bucket, {
|
|
78
|
+
PutObjectCommand: module.PutObjectCommand,
|
|
79
|
+
GetObjectCommand: module.GetObjectCommand,
|
|
80
|
+
DeleteObjectCommand: module.DeleteObjectCommand,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async function toUint8Array(body) {
|
|
84
|
+
if (body instanceof Uint8Array) {
|
|
85
|
+
return body;
|
|
86
|
+
}
|
|
87
|
+
if (typeof body === "object" &&
|
|
88
|
+
body !== null &&
|
|
89
|
+
"transformToByteArray" in body &&
|
|
90
|
+
typeof body.transformToByteArray === "function") {
|
|
91
|
+
const bytes = await body.transformToByteArray();
|
|
92
|
+
return bytes;
|
|
93
|
+
}
|
|
94
|
+
if (typeof body === "object" &&
|
|
95
|
+
body !== null &&
|
|
96
|
+
Symbol.asyncIterator in body) {
|
|
97
|
+
const chunks = [];
|
|
98
|
+
for await (const chunk of body) {
|
|
99
|
+
if (chunk instanceof Uint8Array) {
|
|
100
|
+
chunks.push(chunk);
|
|
101
|
+
}
|
|
102
|
+
else if (typeof chunk === "string") {
|
|
103
|
+
chunks.push(new TextEncoder().encode(chunk));
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
chunks.push(new Uint8Array(chunk));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return concatChunks(chunks);
|
|
110
|
+
}
|
|
111
|
+
throw new Error("Unsupported S3 body type.");
|
|
112
|
+
}
|
|
113
|
+
function concatChunks(chunks) {
|
|
114
|
+
const total = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
115
|
+
const out = new Uint8Array(total);
|
|
116
|
+
let offset = 0;
|
|
117
|
+
for (const chunk of chunks) {
|
|
118
|
+
out.set(chunk, offset);
|
|
119
|
+
offset += chunk.length;
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=s3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.js","sourceRoot":"","sources":["../../src/storage/s3.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@neutron-build/data",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Data layer for Neutron. Database (Drizzle), cache, sessions, queues, storage, and rate limiting.",
|
|
5
|
+
"author": "Tyler",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://neutron.build",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/neutron-build/neutron",
|
|
11
|
+
"directory": "typescript/packages/neutron-data"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"neutron",
|
|
15
|
+
"data",
|
|
16
|
+
"database",
|
|
17
|
+
"drizzle",
|
|
18
|
+
"cache",
|
|
19
|
+
"session",
|
|
20
|
+
"queue"
|
|
21
|
+
],
|
|
22
|
+
"type": "module",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"!dist/**/*.test.*"
|
|
32
|
+
],
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@aws-sdk/client-s3": "^3.883.0",
|
|
35
|
+
"@libsql/client": "^0.17.0",
|
|
36
|
+
"bullmq": "^5.58.0",
|
|
37
|
+
"drizzle-orm": "^0.44.5",
|
|
38
|
+
"ioredis": "^5.8.1",
|
|
39
|
+
"postgres": "^3.4.7",
|
|
40
|
+
"@neutron-build/nucleus": "0.1.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependenciesMeta": {
|
|
43
|
+
"@aws-sdk/client-s3": {
|
|
44
|
+
"optional": true
|
|
45
|
+
},
|
|
46
|
+
"@libsql/client": {
|
|
47
|
+
"optional": true
|
|
48
|
+
},
|
|
49
|
+
"@neutron-build/nucleus": {
|
|
50
|
+
"optional": true
|
|
51
|
+
},
|
|
52
|
+
"bullmq": {
|
|
53
|
+
"optional": true
|
|
54
|
+
},
|
|
55
|
+
"drizzle-orm": {
|
|
56
|
+
"optional": true
|
|
57
|
+
},
|
|
58
|
+
"ioredis": {
|
|
59
|
+
"optional": true
|
|
60
|
+
},
|
|
61
|
+
"postgres": {
|
|
62
|
+
"optional": true
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@types/node": "^22.10.7",
|
|
67
|
+
"typescript": "^5.7.2"
|
|
68
|
+
},
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"access": "public"
|
|
71
|
+
},
|
|
72
|
+
"engines": {
|
|
73
|
+
"node": ">=20"
|
|
74
|
+
},
|
|
75
|
+
"sideEffects": false,
|
|
76
|
+
"scripts": {
|
|
77
|
+
"build": "tsc",
|
|
78
|
+
"dev": "tsc --watch",
|
|
79
|
+
"lint": "tsc --noEmit --pretty false",
|
|
80
|
+
"test": "pnpm run build && node --test --experimental-test-isolation=none dist/ratelimit/index.test.js"
|
|
81
|
+
}
|
|
82
|
+
}
|