@c9up/ream 0.1.7 → 0.1.9
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/dist/Application.d.ts +9 -1
- package/dist/Application.d.ts.map +1 -1
- package/dist/Application.js +35 -5
- package/dist/Application.js.map +1 -1
- package/dist/GracefulShutdown.d.ts.map +1 -1
- package/dist/GracefulShutdown.js +13 -7
- package/dist/GracefulShutdown.js.map +1 -1
- package/dist/HttpKernel.d.ts.map +1 -1
- package/dist/HttpKernel.js +43 -14
- package/dist/HttpKernel.js.map +1 -1
- package/dist/Ignitor.d.ts +10 -10
- package/dist/Ignitor.d.ts.map +1 -1
- package/dist/Ignitor.js +104 -32
- package/dist/Ignitor.js.map +1 -1
- package/dist/bodyparser/BodyParserMiddleware.d.ts +3 -0
- package/dist/bodyparser/BodyParserMiddleware.d.ts.map +1 -1
- package/dist/bodyparser/BodyParserMiddleware.js +32 -16
- package/dist/bodyparser/BodyParserMiddleware.js.map +1 -1
- package/dist/bodyparser/parseSize.d.ts +2 -1
- package/dist/bodyparser/parseSize.d.ts.map +1 -1
- package/dist/bodyparser/parseSize.js +2 -1
- package/dist/bodyparser/parseSize.js.map +1 -1
- package/dist/container/Container.d.ts.map +1 -1
- package/dist/container/Container.js +39 -9
- package/dist/container/Container.js.map +1 -1
- package/dist/decorators/Service.d.ts +4 -6
- package/dist/decorators/Service.d.ts.map +1 -1
- package/dist/decorators/Service.js +0 -1
- package/dist/decorators/Service.js.map +1 -1
- package/dist/events/Emitter.d.ts +16 -6
- package/dist/events/Emitter.d.ts.map +1 -1
- package/dist/events/Emitter.js +32 -25
- package/dist/events/Emitter.js.map +1 -1
- package/dist/events/EventsProvider.d.ts +1 -0
- package/dist/events/EventsProvider.d.ts.map +1 -1
- package/dist/events/EventsProvider.js +6 -4
- package/dist/events/EventsProvider.js.map +1 -1
- package/dist/graphql/GraphQLEngine.d.ts +16 -0
- package/dist/graphql/GraphQLEngine.d.ts.map +1 -1
- package/dist/graphql/GraphQLEngine.js +122 -4
- package/dist/graphql/GraphQLEngine.js.map +1 -1
- package/dist/graphql/GraphQLProvider.d.ts.map +1 -1
- package/dist/graphql/GraphQLProvider.js +13 -2
- package/dist/graphql/GraphQLProvider.js.map +1 -1
- package/dist/http/HttpContext.d.ts +27 -1
- package/dist/http/HttpContext.d.ts.map +1 -1
- package/dist/http/HttpContext.js +20 -1
- package/dist/http/HttpContext.js.map +1 -1
- package/dist/http/RedirectBuilder.d.ts +5 -1
- package/dist/http/RedirectBuilder.d.ts.map +1 -1
- package/dist/http/RedirectBuilder.js +26 -3
- package/dist/http/RedirectBuilder.js.map +1 -1
- package/dist/http/Request.d.ts +13 -0
- package/dist/http/Request.d.ts.map +1 -1
- package/dist/http/Request.js +18 -0
- package/dist/http/Request.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/middleware/Pipeline.d.ts +13 -0
- package/dist/middleware/Pipeline.d.ts.map +1 -1
- package/dist/middleware/Pipeline.js +43 -7
- package/dist/middleware/Pipeline.js.map +1 -1
- package/dist/router/Router.d.ts +21 -2
- package/dist/router/Router.d.ts.map +1 -1
- package/dist/router/Router.js +53 -8
- package/dist/router/Router.js.map +1 -1
- package/dist/rpc/RpcProvider.d.ts.map +1 -1
- package/dist/rpc/RpcProvider.js +11 -2
- package/dist/rpc/RpcProvider.js.map +1 -1
- package/dist/rpc/RpcRouter.d.ts +11 -3
- package/dist/rpc/RpcRouter.d.ts.map +1 -1
- package/dist/rpc/RpcRouter.js +92 -8
- package/dist/rpc/RpcRouter.js.map +1 -1
- package/dist/scheduler/ScheduleProvider.d.ts.map +1 -1
- package/dist/scheduler/ScheduleProvider.js +10 -0
- package/dist/scheduler/ScheduleProvider.js.map +1 -1
- package/dist/scheduler/locks/MemoryLockBackend.d.ts +0 -1
- package/dist/scheduler/locks/MemoryLockBackend.d.ts.map +1 -1
- package/dist/scheduler/locks/MemoryLockBackend.js +0 -1
- package/dist/scheduler/locks/MemoryLockBackend.js.map +1 -1
- package/dist/services/app.d.ts +6 -0
- package/dist/services/app.d.ts.map +1 -1
- package/dist/services/app.js +9 -0
- package/dist/services/app.js.map +1 -1
- package/dist/services/router.d.ts +5 -0
- package/dist/services/router.d.ts.map +1 -1
- package/dist/services/router.js +8 -0
- package/dist/services/router.js.map +1 -1
- package/dist/services/server.d.ts +5 -0
- package/dist/services/server.d.ts.map +1 -1
- package/dist/services/server.js +8 -0
- package/dist/services/server.js.map +1 -1
- package/dist/session/SessionMiddleware.d.ts.map +1 -1
- package/dist/session/SessionMiddleware.js +4 -0
- package/dist/session/SessionMiddleware.js.map +1 -1
- package/dist/session/drivers/MemoryDriver.d.ts +1 -1
- package/dist/session/drivers/MemoryDriver.d.ts.map +1 -1
- package/dist/session/drivers/MemoryDriver.js +14 -6
- package/dist/session/drivers/MemoryDriver.js.map +1 -1
- package/dist/testing/TestClient.d.ts +11 -5
- package/dist/testing/TestClient.d.ts.map +1 -1
- package/dist/testing/TestClient.js +9 -4
- package/dist/testing/TestClient.js.map +1 -1
- package/events.darwin-arm64.node +0 -0
- package/events.darwin-x64.node +0 -0
- package/events.linux-arm64-gnu.node +0 -0
- package/events.linux-x64-gnu.node +0 -0
- package/events.win32-x64-msvc.node +0 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
- package/scheduler.darwin-arm64.node +0 -0
- package/scheduler.darwin-x64.node +0 -0
- package/scheduler.linux-arm64-gnu.node +0 -0
- package/scheduler.linux-x64-gnu.node +0 -0
- package/scheduler.win32-x64-msvc.node +0 -0
- package/src/Application.ts +36 -5
- package/src/GracefulShutdown.ts +15 -7
- package/src/HttpKernel.ts +52 -17
- package/src/Ignitor.ts +106 -34
- package/src/bodyparser/BodyParserMiddleware.ts +43 -16
- package/src/bodyparser/parseSize.ts +2 -1
- package/src/container/Container.ts +42 -12
- package/src/decorators/Service.ts +4 -6
- package/src/events/Emitter.ts +36 -28
- package/src/events/EventsProvider.ts +6 -4
- package/src/graphql/GraphQLEngine.ts +139 -3
- package/src/graphql/GraphQLProvider.ts +17 -2
- package/src/http/HttpContext.ts +38 -1
- package/src/http/RedirectBuilder.ts +23 -3
- package/src/http/Request.ts +20 -0
- package/src/index.ts +1 -1
- package/src/middleware/Pipeline.ts +61 -8
- package/src/router/Router.ts +53 -8
- package/src/rpc/RpcProvider.ts +14 -2
- package/src/rpc/RpcRouter.ts +115 -11
- package/src/scheduler/ScheduleProvider.ts +10 -0
- package/src/scheduler/locks/MemoryLockBackend.ts +0 -2
- package/src/services/app.ts +9 -0
- package/src/services/router.ts +8 -0
- package/src/services/server.ts +8 -0
- package/src/session/SessionMiddleware.ts +6 -0
- package/src/session/drivers/MemoryDriver.ts +14 -6
- package/src/testing/TestClient.ts +18 -7
- package/dist/server/HyperServer.d.ts +0 -64
- package/dist/server/HyperServer.d.ts.map +0 -1
- package/dist/server/HyperServer.js +0 -54
- package/dist/server/HyperServer.js.map +0 -1
- package/dist/storage/S3Driver.d.ts +0 -27
- package/dist/storage/S3Driver.d.ts.map +0 -1
- package/dist/storage/S3Driver.js +0 -135
- package/dist/storage/S3Driver.js.map +0 -1
- package/dist/storage/StorageManager.d.ts +0 -31
- package/dist/storage/StorageManager.d.ts.map +0 -1
- package/dist/storage/StorageManager.js +0 -120
- package/dist/storage/StorageManager.js.map +0 -1
- package/src/server/HyperServer.ts +0 -121
- package/src/storage/S3Driver.ts +0 -171
- package/src/storage/StorageManager.ts +0 -142
|
@@ -1,27 +1,35 @@
|
|
|
1
1
|
import type { SessionDriver } from '../Session.js'
|
|
2
2
|
|
|
3
|
+
const SWEEP_THRESHOLD = 1000
|
|
4
|
+
|
|
3
5
|
export class MemoryDriver implements SessionDriver {
|
|
4
|
-
|
|
6
|
+
#store: Map<string, { data: Record<string, unknown>; expiresAt: number }> = new Map()
|
|
5
7
|
|
|
6
8
|
async read(sessionId: string): Promise<Record<string, unknown>> {
|
|
7
|
-
const entry = this
|
|
9
|
+
const entry = this.#store.get(sessionId)
|
|
8
10
|
if (!entry || entry.expiresAt < Date.now()) {
|
|
9
|
-
this
|
|
11
|
+
this.#store.delete(sessionId)
|
|
10
12
|
return {}
|
|
11
13
|
}
|
|
12
14
|
return { ...entry.data }
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
async write(sessionId: string, data: Record<string, unknown>, ttl: number): Promise<void> {
|
|
16
|
-
this
|
|
18
|
+
if (this.#store.size >= SWEEP_THRESHOLD) {
|
|
19
|
+
const now = Date.now()
|
|
20
|
+
for (const [id, entry] of this.#store) {
|
|
21
|
+
if (entry.expiresAt < now) this.#store.delete(id)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
this.#store.set(sessionId, { data, expiresAt: Date.now() + ttl * 1000 })
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
async destroy(sessionId: string): Promise<void> {
|
|
20
|
-
this
|
|
28
|
+
this.#store.delete(sessionId)
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
async touch(sessionId: string, ttl: number): Promise<void> {
|
|
24
|
-
const entry = this
|
|
32
|
+
const entry = this.#store.get(sessionId)
|
|
25
33
|
if (entry) {
|
|
26
34
|
entry.expiresAt = Date.now() + ttl * 1000
|
|
27
35
|
}
|
|
@@ -32,7 +32,13 @@ export interface TestResponse {
|
|
|
32
32
|
json<T = unknown>(): T
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Fluent request builder. Thenable like AdonisJS/japa's api-client: `await
|
|
37
|
+
* client.get('/x')` sends the request, and chaining works on every verb —
|
|
38
|
+
* `await client.get('/x').header('authorization', token)`. The explicit
|
|
39
|
+
* `.send()` is kept for callers that prefer it.
|
|
40
|
+
*/
|
|
41
|
+
export interface TestRequestBuilder extends PromiseLike<TestResponse> {
|
|
36
42
|
/** Set a request header. */
|
|
37
43
|
header(name: string, value: string): TestRequestBuilder
|
|
38
44
|
/** Set the request body as JSON. */
|
|
@@ -91,9 +97,9 @@ export class TestClient {
|
|
|
91
97
|
return this
|
|
92
98
|
}
|
|
93
99
|
|
|
94
|
-
/** GET request. */
|
|
95
|
-
get(path: string):
|
|
96
|
-
return this.request('GET', path)
|
|
100
|
+
/** GET request. Returns a chainable, awaitable builder (await sends it). */
|
|
101
|
+
get(path: string): TestRequestBuilder {
|
|
102
|
+
return this.request('GET', path)
|
|
97
103
|
}
|
|
98
104
|
|
|
99
105
|
/** POST request. */
|
|
@@ -111,9 +117,9 @@ export class TestClient {
|
|
|
111
117
|
return this.request('PATCH', path)
|
|
112
118
|
}
|
|
113
119
|
|
|
114
|
-
/** DELETE request. */
|
|
115
|
-
delete(path: string):
|
|
116
|
-
return this.request('DELETE', path)
|
|
120
|
+
/** DELETE request. Returns a chainable, awaitable builder (await sends it). */
|
|
121
|
+
delete(path: string): TestRequestBuilder {
|
|
122
|
+
return this.request('DELETE', path)
|
|
117
123
|
}
|
|
118
124
|
|
|
119
125
|
/**
|
|
@@ -165,6 +171,11 @@ export class TestClient {
|
|
|
165
171
|
}
|
|
166
172
|
return sendRequest(this.#port, method, path, headers, bodyContent)
|
|
167
173
|
},
|
|
174
|
+
// Thenable: `await client.get('/x')` (or any builder) sends the request,
|
|
175
|
+
// matching AdonisJS/japa's api-client ergonomics. The `then` IS the public
|
|
176
|
+
// contract here — awaiting the builder is the documented way to send.
|
|
177
|
+
// biome-ignore lint/suspicious/noThenProperty: thenable request builder is the intended API (AdonisJS/japa parity) — `await client.get(path)` sends
|
|
178
|
+
then: (onfulfilled, onrejected) => builder.send().then(onfulfilled, onrejected),
|
|
168
179
|
}
|
|
169
180
|
|
|
170
181
|
return builder
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { HttpKernelRequest, HttpKernelResponse } from '../HttpKernel.js';
|
|
2
|
-
/**
|
|
3
|
-
* Wire-level shield configuration handed off to the Rust filter at boot.
|
|
4
|
-
* Each flag toggles one rule on/off; they all default to true on the Rust
|
|
5
|
-
* side, so omitting `configureShield()` entirely leaves the server with no
|
|
6
|
-
* filter installed.
|
|
7
|
-
*/
|
|
8
|
-
export interface RustShieldConfig {
|
|
9
|
-
pathTraversal: boolean;
|
|
10
|
-
paramPollution: boolean;
|
|
11
|
-
}
|
|
12
|
-
export interface RustRateLimitConfig {
|
|
13
|
-
max: number;
|
|
14
|
-
windowSecs: number;
|
|
15
|
-
}
|
|
16
|
-
export interface HyperServerLike {
|
|
17
|
-
onRequest(callback: (request: HttpKernelRequest) => Promise<HttpKernelResponse>): void;
|
|
18
|
-
configureShield(config: RustShieldConfig): void;
|
|
19
|
-
configureTrustedProxies(cidrs: string[]): void;
|
|
20
|
-
configureRateLimit(config: RustRateLimitConfig | null): void;
|
|
21
|
-
listen(): Promise<void>;
|
|
22
|
-
port(): Promise<number>;
|
|
23
|
-
close(): Promise<void>;
|
|
24
|
-
/**
|
|
25
|
-
* Reserve a streaming-response slot. The handler must call this and
|
|
26
|
-
* pass the returned id back inside `HttpKernelResponse.streamId`
|
|
27
|
-
* BEFORE returning, so the hyper-side response builder can feed the
|
|
28
|
-
* body from the matching registry entry.
|
|
29
|
-
*/
|
|
30
|
-
registerStream(streamId: string): Promise<boolean>;
|
|
31
|
-
/**
|
|
32
|
-
* Push a UTF-8 chunk onto a registered stream. Returns `false` once
|
|
33
|
-
* the client has disconnected — callers stop pushing.
|
|
34
|
-
*/
|
|
35
|
-
writeStream(streamId: string, chunk: string): Promise<boolean>;
|
|
36
|
-
/**
|
|
37
|
-
* End a stream from the server side. Idempotent.
|
|
38
|
-
*/
|
|
39
|
-
closeStream(streamId: string): Promise<boolean>;
|
|
40
|
-
/**
|
|
41
|
-
* Install a one-shot callback fired the moment the matching stream
|
|
42
|
-
* receiver is dropped — i.e. the client disconnected OR
|
|
43
|
-
* `closeStream` was called. Used by the JS SDK to drop bookkeeping
|
|
44
|
-
* for subscriptions and SSE viewers.
|
|
45
|
-
*/
|
|
46
|
-
onStreamDisconnect(streamId: string, callback: () => void): void;
|
|
47
|
-
}
|
|
48
|
-
/** HyperServer — Rust-powered HTTP server. */
|
|
49
|
-
export declare class HyperServer implements HyperServerLike {
|
|
50
|
-
#private;
|
|
51
|
-
constructor(port: number);
|
|
52
|
-
onRequest(callback: (request: HttpKernelRequest) => Promise<HttpKernelResponse>): void;
|
|
53
|
-
configureShield(config: RustShieldConfig): void;
|
|
54
|
-
configureTrustedProxies(cidrs: string[]): void;
|
|
55
|
-
configureRateLimit(config: RustRateLimitConfig | null): void;
|
|
56
|
-
listen(): Promise<void>;
|
|
57
|
-
port(): Promise<number>;
|
|
58
|
-
close(): Promise<void>;
|
|
59
|
-
registerStream(streamId: string): Promise<boolean>;
|
|
60
|
-
writeStream(streamId: string, chunk: string): Promise<boolean>;
|
|
61
|
-
closeStream(streamId: string): Promise<boolean>;
|
|
62
|
-
onStreamDisconnect(streamId: string, callback: () => void): void;
|
|
63
|
-
}
|
|
64
|
-
//# sourceMappingURL=HyperServer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"HyperServer.d.ts","sourceRoot":"","sources":["../../src/server/HyperServer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAG7E;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,OAAO,CAAA;IACtB,cAAc,EAAE,OAAO,CAAA;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,kBAAkB,CAAC,GAAG,IAAI,CAAA;IACtF,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC/C,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IAC9C,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,GAAG,IAAI,CAAA;IAC5D,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IACvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB;;;;;OAKG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAClD;;;OAGG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC9D;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC/C;;;;;OAKG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;CACjE;AAkBD,8CAA8C;AAC9C,qBAAa,WAAY,YAAW,eAAe;;gBAGrC,IAAI,EAAE,MAAM;IAKxB,SAAS,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,kBAAkB,CAAC,GAAG,IAAI;IAItF,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAI/C,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAI9C,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,GAAG,IAAI;IAI5D,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAIvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIlD,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9D,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI/C,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;CAGjE"}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { loadNapi } from '../helpers/napi-loader.js';
|
|
2
|
-
let native;
|
|
3
|
-
function loadNative() {
|
|
4
|
-
if (native)
|
|
5
|
-
return native;
|
|
6
|
-
native = loadNapi({
|
|
7
|
-
binaryName: 'index',
|
|
8
|
-
callerMetaUrl: import.meta.url,
|
|
9
|
-
errorCodePrefix: 'HYPER_SERVER',
|
|
10
|
-
});
|
|
11
|
-
return native;
|
|
12
|
-
}
|
|
13
|
-
/** HyperServer — Rust-powered HTTP server. */
|
|
14
|
-
export class HyperServer {
|
|
15
|
-
#inner;
|
|
16
|
-
constructor(port) {
|
|
17
|
-
const mod = loadNative();
|
|
18
|
-
this.#inner = new mod.HyperServer(port);
|
|
19
|
-
}
|
|
20
|
-
onRequest(callback) {
|
|
21
|
-
this.#inner.onRequest(callback);
|
|
22
|
-
}
|
|
23
|
-
configureShield(config) {
|
|
24
|
-
this.#inner.configureShield(config);
|
|
25
|
-
}
|
|
26
|
-
configureTrustedProxies(cidrs) {
|
|
27
|
-
this.#inner.configureTrustedProxies(cidrs);
|
|
28
|
-
}
|
|
29
|
-
configureRateLimit(config) {
|
|
30
|
-
this.#inner.configureRateLimit(config);
|
|
31
|
-
}
|
|
32
|
-
listen() {
|
|
33
|
-
return this.#inner.listen();
|
|
34
|
-
}
|
|
35
|
-
port() {
|
|
36
|
-
return this.#inner.port();
|
|
37
|
-
}
|
|
38
|
-
close() {
|
|
39
|
-
return this.#inner.close();
|
|
40
|
-
}
|
|
41
|
-
registerStream(streamId) {
|
|
42
|
-
return this.#inner.registerStream(streamId);
|
|
43
|
-
}
|
|
44
|
-
writeStream(streamId, chunk) {
|
|
45
|
-
return this.#inner.writeStream(streamId, chunk);
|
|
46
|
-
}
|
|
47
|
-
closeStream(streamId) {
|
|
48
|
-
return this.#inner.closeStream(streamId);
|
|
49
|
-
}
|
|
50
|
-
onStreamDisconnect(streamId, callback) {
|
|
51
|
-
this.#inner.onStreamDisconnect(streamId, callback);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
//# sourceMappingURL=HyperServer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"HyperServer.js","sourceRoot":"","sources":["../../src/server/HyperServer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AAuDpD,IAAI,MAAgC,CAAA;AAEpC,SAAS,UAAU;IACjB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAA;IACzB,MAAM,GAAG,QAAQ,CAAe;QAC9B,UAAU,EAAE,OAAO;QACnB,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG;QAC9B,eAAe,EAAE,cAAc;KAChC,CAAC,CAAA;IACF,OAAO,MAAM,CAAA;AACf,CAAC;AAED,8CAA8C;AAC9C,MAAM,OAAO,WAAW;IACtB,MAAM,CAAiB;IAEvB,YAAY,IAAY;QACtB,MAAM,GAAG,GAAG,UAAU,EAAE,CAAA;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IACzC,CAAC;IAED,SAAS,CAAC,QAAqE;QAC7E,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;IACjC,CAAC;IAED,eAAe,CAAC,MAAwB;QACtC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;IACrC,CAAC;IAED,uBAAuB,CAAC,KAAe;QACrC,IAAI,CAAC,MAAM,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAA;IAC5C,CAAC;IAED,kBAAkB,CAAC,MAAkC;QACnD,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAA;IACxC,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAA;IAC7B,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;IAC3B,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;IAC5B,CAAC;IAED,cAAc,CAAC,QAAgB;QAC7B,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAA;IAC7C,CAAC;IAED,WAAW,CAAC,QAAgB,EAAE,KAAa;QACzC,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;IACjD,CAAC;IAED,WAAW,CAAC,QAAgB;QAC1B,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;IAC1C,CAAC;IAED,kBAAkB,CAAC,QAAgB,EAAE,QAAoB;QACvD,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IACpD,CAAC;CACF"}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S3Driver — S3-compatible cloud storage (AWS S3, Cloudflare R2, MinIO).
|
|
3
|
-
*
|
|
4
|
-
* Uses fetch API — no external SDK dependency.
|
|
5
|
-
* Implements the StorageDriver interface.
|
|
6
|
-
*
|
|
7
|
-
* @implements MISS-24
|
|
8
|
-
*/
|
|
9
|
-
import type { StorageDriver } from './StorageManager.js';
|
|
10
|
-
export interface S3Config {
|
|
11
|
-
bucket: string;
|
|
12
|
-
region?: string;
|
|
13
|
-
endpoint?: string;
|
|
14
|
-
accessKeyId: string;
|
|
15
|
-
secretAccessKey: string;
|
|
16
|
-
publicUrl?: string;
|
|
17
|
-
}
|
|
18
|
-
export declare class S3Driver implements StorageDriver {
|
|
19
|
-
#private;
|
|
20
|
-
constructor(config: S3Config);
|
|
21
|
-
put(filePath: string, content: Buffer | string): Promise<void>;
|
|
22
|
-
get(filePath: string): Promise<Buffer | null>;
|
|
23
|
-
delete(filePath: string): Promise<boolean>;
|
|
24
|
-
exists(filePath: string): Promise<boolean>;
|
|
25
|
-
url(filePath: string): string;
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=S3Driver.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"S3Driver.d.ts","sourceRoot":"","sources":["../../src/storage/S3Driver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AA4BxD,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,qBAAa,QAAS,YAAW,aAAa;;gBAIhC,MAAM,EAAE,QAAQ;IAKtB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY9D,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAa7C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAShD,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAuE9B"}
|
package/dist/storage/S3Driver.js
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S3Driver — S3-compatible cloud storage (AWS S3, Cloudflare R2, MinIO).
|
|
3
|
-
*
|
|
4
|
-
* Uses fetch API — no external SDK dependency.
|
|
5
|
-
* Implements the StorageDriver interface.
|
|
6
|
-
*
|
|
7
|
-
* @implements MISS-24
|
|
8
|
-
*/
|
|
9
|
-
import { createHash, createHmac } from 'node:crypto';
|
|
10
|
-
/**
|
|
11
|
-
* URI-encode an S3 object key for use in BOTH the request URL and the
|
|
12
|
-
* SigV4 canonical path. Each `/`-delimited segment is percent-encoded
|
|
13
|
-
* (so the slashes that delimit the key hierarchy survive), which means
|
|
14
|
-
* spaces, `#`, `?`, `%` and non-ASCII bytes can't slip the requested
|
|
15
|
-
* path away from the signed path — the classic "key with a space gets
|
|
16
|
-
* a SignatureDoesNotMatch / 403, or `?`/`#` truncates the path" bug.
|
|
17
|
-
*
|
|
18
|
-
* S3 expects the canonical URI encoded ONCE (unlike the generic SigV4
|
|
19
|
-
* double-encode), and `encodeURIComponent` already escapes the RFC 3986
|
|
20
|
-
* sub-delims AWS cares about. We additionally escape `!`, `'`, `(`,
|
|
21
|
-
* `)`, `*` which `encodeURIComponent` leaves untouched but AWS expects
|
|
22
|
-
* percent-encoded.
|
|
23
|
-
*/
|
|
24
|
-
function encodeS3Key(key) {
|
|
25
|
-
return key
|
|
26
|
-
.split('/')
|
|
27
|
-
.map((segment) => encodeURIComponent(segment).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`))
|
|
28
|
-
.join('/');
|
|
29
|
-
}
|
|
30
|
-
export class S3Driver {
|
|
31
|
-
#config;
|
|
32
|
-
#endpoint;
|
|
33
|
-
constructor(config) {
|
|
34
|
-
this.#config = config;
|
|
35
|
-
this.#endpoint = config.endpoint ?? `https://s3.${config.region ?? 'us-east-1'}.amazonaws.com`;
|
|
36
|
-
}
|
|
37
|
-
async put(filePath, content) {
|
|
38
|
-
const body = typeof content === 'string' ? Buffer.from(content) : content;
|
|
39
|
-
const key = encodeS3Key(filePath);
|
|
40
|
-
const url = `${this.#endpoint}/${this.#config.bucket}/${key}`;
|
|
41
|
-
const headers = this.#signRequest('PUT', key, body);
|
|
42
|
-
const res = await fetch(url, { method: 'PUT', headers, body: body });
|
|
43
|
-
if (!res.ok) {
|
|
44
|
-
throw new Error(`S3 PUT failed (${res.status}): ${await res.text()}`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
async get(filePath) {
|
|
48
|
-
const key = encodeS3Key(filePath);
|
|
49
|
-
const url = `${this.#endpoint}/${this.#config.bucket}/${key}`;
|
|
50
|
-
const headers = this.#signRequest('GET', key);
|
|
51
|
-
const res = await fetch(url, { method: 'GET', headers });
|
|
52
|
-
if (res.status === 404)
|
|
53
|
-
return null;
|
|
54
|
-
if (!res.ok)
|
|
55
|
-
throw new Error(`S3 GET failed (${res.status})`);
|
|
56
|
-
const arrayBuffer = await res.arrayBuffer();
|
|
57
|
-
return Buffer.from(arrayBuffer);
|
|
58
|
-
}
|
|
59
|
-
async delete(filePath) {
|
|
60
|
-
const key = encodeS3Key(filePath);
|
|
61
|
-
const url = `${this.#endpoint}/${this.#config.bucket}/${key}`;
|
|
62
|
-
const headers = this.#signRequest('DELETE', key);
|
|
63
|
-
const res = await fetch(url, { method: 'DELETE', headers });
|
|
64
|
-
return res.ok || res.status === 204;
|
|
65
|
-
}
|
|
66
|
-
async exists(filePath) {
|
|
67
|
-
const key = encodeS3Key(filePath);
|
|
68
|
-
const url = `${this.#endpoint}/${this.#config.bucket}/${key}`;
|
|
69
|
-
const headers = this.#signRequest('HEAD', key);
|
|
70
|
-
const res = await fetch(url, { method: 'HEAD', headers });
|
|
71
|
-
return res.ok;
|
|
72
|
-
}
|
|
73
|
-
url(filePath) {
|
|
74
|
-
const key = encodeS3Key(filePath);
|
|
75
|
-
if (this.#config.publicUrl) {
|
|
76
|
-
return `${this.#config.publicUrl}/${key}`;
|
|
77
|
-
}
|
|
78
|
-
return `${this.#endpoint}/${this.#config.bucket}/${key}`;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Sign a request with AWS Signature V4 (simplified).
|
|
82
|
-
* For production, consider using @aws-sdk/signature-v4 for full compliance.
|
|
83
|
-
*/
|
|
84
|
-
#signRequest(method, key, body) {
|
|
85
|
-
const now = new Date();
|
|
86
|
-
const dateStamp = `${now.toISOString().replace(/[-:]/g, '').split('.')[0]}Z`;
|
|
87
|
-
const shortDate = dateStamp.slice(0, 8);
|
|
88
|
-
const region = this.#config.region ?? 'us-east-1';
|
|
89
|
-
const service = 's3';
|
|
90
|
-
const payloadHash = createHash('sha256')
|
|
91
|
-
.update(body ?? '')
|
|
92
|
-
.digest('hex');
|
|
93
|
-
const headers = {
|
|
94
|
-
host: new URL(this.#endpoint).host,
|
|
95
|
-
'x-amz-date': dateStamp,
|
|
96
|
-
'x-amz-content-sha256': payloadHash,
|
|
97
|
-
};
|
|
98
|
-
if (body) {
|
|
99
|
-
headers['content-length'] = String(body.length);
|
|
100
|
-
}
|
|
101
|
-
// Canonical request
|
|
102
|
-
const signedHeaders = Object.keys(headers).sort().join(';');
|
|
103
|
-
const canonicalHeaders = Object.keys(headers)
|
|
104
|
-
.sort()
|
|
105
|
-
.map((k) => `${k}:${headers[k]}\n`)
|
|
106
|
-
.join('');
|
|
107
|
-
const canonicalRequest = [
|
|
108
|
-
method,
|
|
109
|
-
`/${this.#config.bucket}/${key}`,
|
|
110
|
-
'',
|
|
111
|
-
canonicalHeaders,
|
|
112
|
-
signedHeaders,
|
|
113
|
-
payloadHash,
|
|
114
|
-
].join('\n');
|
|
115
|
-
// String to sign
|
|
116
|
-
const scope = `${shortDate}/${region}/${service}/aws4_request`;
|
|
117
|
-
const stringToSign = [
|
|
118
|
-
'AWS4-HMAC-SHA256',
|
|
119
|
-
dateStamp,
|
|
120
|
-
scope,
|
|
121
|
-
createHash('sha256').update(canonicalRequest).digest('hex'),
|
|
122
|
-
].join('\n');
|
|
123
|
-
// Signing key
|
|
124
|
-
const kDate = createHmac('sha256', `AWS4${this.#config.secretAccessKey}`)
|
|
125
|
-
.update(shortDate)
|
|
126
|
-
.digest();
|
|
127
|
-
const kRegion = createHmac('sha256', kDate).update(region).digest();
|
|
128
|
-
const kService = createHmac('sha256', kRegion).update(service).digest();
|
|
129
|
-
const kSigning = createHmac('sha256', kService).update('aws4_request').digest();
|
|
130
|
-
const signature = createHmac('sha256', kSigning).update(stringToSign).digest('hex');
|
|
131
|
-
headers.authorization = `AWS4-HMAC-SHA256 Credential=${this.#config.accessKeyId}/${scope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
|
132
|
-
return headers;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
//# sourceMappingURL=S3Driver.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"S3Driver.js","sourceRoot":"","sources":["../../src/storage/S3Driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Storage — file storage abstraction with driver pattern.
|
|
3
|
-
*
|
|
4
|
-
* @implements MISS-24
|
|
5
|
-
*/
|
|
6
|
-
export interface StorageDriver {
|
|
7
|
-
put(filePath: string, content: Buffer | string): Promise<void>;
|
|
8
|
-
get(filePath: string): Promise<Buffer | null>;
|
|
9
|
-
delete(filePath: string): Promise<boolean>;
|
|
10
|
-
exists(filePath: string): Promise<boolean>;
|
|
11
|
-
url(filePath: string): string;
|
|
12
|
-
}
|
|
13
|
-
export declare class LocalDriver implements StorageDriver {
|
|
14
|
-
#private;
|
|
15
|
-
constructor(root: string);
|
|
16
|
-
put(filePath: string, content: Buffer | string): Promise<void>;
|
|
17
|
-
get(filePath: string): Promise<Buffer | null>;
|
|
18
|
-
delete(filePath: string): Promise<boolean>;
|
|
19
|
-
exists(filePath: string): Promise<boolean>;
|
|
20
|
-
url(filePath: string): string;
|
|
21
|
-
}
|
|
22
|
-
export declare class StorageManager {
|
|
23
|
-
#private;
|
|
24
|
-
constructor(driver: StorageDriver);
|
|
25
|
-
put(filePath: string, content: Buffer | string): Promise<void>;
|
|
26
|
-
get(filePath: string): Promise<Buffer | null>;
|
|
27
|
-
delete(filePath: string): Promise<boolean>;
|
|
28
|
-
exists(filePath: string): Promise<boolean>;
|
|
29
|
-
url(filePath: string): string;
|
|
30
|
-
}
|
|
31
|
-
//# sourceMappingURL=StorageManager.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"StorageManager.d.ts","sourceRoot":"","sources":["../../src/storage/StorageManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAsDH,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9D,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAC7C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1C,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;CAC9B;AAED,qBAAa,WAAY,YAAW,aAAa;;gBAGnC,IAAI,EAAE,MAAM;IAOlB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9D,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAM7C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO1C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYhD,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAG9B;AAED,qBAAa,cAAc;;gBAGb,MAAM,EAAE,aAAa;IAIjC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9D,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI7C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1C,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAG9B"}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Storage — file storage abstraction with driver pattern.
|
|
3
|
-
*
|
|
4
|
-
* @implements MISS-24
|
|
5
|
-
*/
|
|
6
|
-
import * as fs from 'node:fs';
|
|
7
|
-
import * as path from 'node:path';
|
|
8
|
-
/**
|
|
9
|
-
* Resolve `filePath` against `root` and reject any result that escapes
|
|
10
|
-
* the storage root. Without this guard a user-controlled path like
|
|
11
|
-
* `../secrets.env` would let put/get/delete/exists touch arbitrary
|
|
12
|
-
* files outside the configured storage root.
|
|
13
|
-
*
|
|
14
|
-
* The lexical check (`path.resolve` + `startsWith`) catches the
|
|
15
|
-
* `../` / absolute-path class. The realpath re-check catches the
|
|
16
|
-
* symlink-escape class: a symlink planted under the root (or anywhere
|
|
17
|
-
* else on the resolved path's chain) that points outside the root
|
|
18
|
-
* would pass the lexical gate but be caught here.
|
|
19
|
-
*
|
|
20
|
-
* We canonicalize the longest existing ancestor of `full` — `realpath`
|
|
21
|
-
* itself throws ENOENT on a target that doesn't exist yet (the `put`
|
|
22
|
-
* happy-path for new files). Symlinks anywhere ABOVE the leaf are
|
|
23
|
-
* still dereferenced, which is the only escape vector that matters:
|
|
24
|
-
* the driver creates the leaf itself, so no symlink can pre-exist
|
|
25
|
-
* there.
|
|
26
|
-
*/
|
|
27
|
-
function assertWithinRoot(root, filePath) {
|
|
28
|
-
const full = path.resolve(root, filePath);
|
|
29
|
-
const rootAbs = path.resolve(root);
|
|
30
|
-
if (full !== rootAbs && !full.startsWith(rootAbs + path.sep)) {
|
|
31
|
-
throw new Error(`[ream-storage] path '${filePath}' escapes the storage root (E_PATH_TRAVERSAL)`);
|
|
32
|
-
}
|
|
33
|
-
const canonicalRoot = fs.existsSync(rootAbs) ? fs.realpathSync(rootAbs) : rootAbs;
|
|
34
|
-
const ancestor = longestExistingAncestor(full);
|
|
35
|
-
const canonicalAncestor = ancestor === full ? fs.realpathSync(full) : fs.realpathSync(ancestor);
|
|
36
|
-
// Re-attach the not-yet-existing leaf to the canonicalized ancestor.
|
|
37
|
-
const canonicalFull = canonicalAncestor + full.slice(ancestor.length);
|
|
38
|
-
if (canonicalFull !== canonicalRoot && !canonicalFull.startsWith(canonicalRoot + path.sep)) {
|
|
39
|
-
throw new Error(`[ream-storage] path '${filePath}' escapes the storage root via a symlink (E_PATH_TRAVERSAL)`);
|
|
40
|
-
}
|
|
41
|
-
return full;
|
|
42
|
-
}
|
|
43
|
-
/** Walk up `full` until we find a path that exists on disk. */
|
|
44
|
-
function longestExistingAncestor(full) {
|
|
45
|
-
let current = full;
|
|
46
|
-
while (!fs.existsSync(current)) {
|
|
47
|
-
const parent = path.dirname(current);
|
|
48
|
-
if (parent === current)
|
|
49
|
-
return current;
|
|
50
|
-
current = parent;
|
|
51
|
-
}
|
|
52
|
-
return current;
|
|
53
|
-
}
|
|
54
|
-
export class LocalDriver {
|
|
55
|
-
#root;
|
|
56
|
-
constructor(root) {
|
|
57
|
-
this.#root = root;
|
|
58
|
-
if (!fs.existsSync(root)) {
|
|
59
|
-
fs.mkdirSync(root, { recursive: true });
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
async put(filePath, content) {
|
|
63
|
-
const full = assertWithinRoot(this.#root, filePath);
|
|
64
|
-
const dir = path.dirname(full);
|
|
65
|
-
if (!fs.existsSync(dir)) {
|
|
66
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
67
|
-
}
|
|
68
|
-
fs.writeFileSync(full, content);
|
|
69
|
-
}
|
|
70
|
-
async get(filePath) {
|
|
71
|
-
const full = assertWithinRoot(this.#root, filePath);
|
|
72
|
-
if (!fs.existsSync(full))
|
|
73
|
-
return null;
|
|
74
|
-
return fs.readFileSync(full);
|
|
75
|
-
}
|
|
76
|
-
async delete(filePath) {
|
|
77
|
-
const full = assertWithinRoot(this.#root, filePath);
|
|
78
|
-
if (!fs.existsSync(full))
|
|
79
|
-
return false;
|
|
80
|
-
fs.unlinkSync(full);
|
|
81
|
-
return true;
|
|
82
|
-
}
|
|
83
|
-
async exists(filePath) {
|
|
84
|
-
let full;
|
|
85
|
-
try {
|
|
86
|
-
full = assertWithinRoot(this.#root, filePath);
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
// exists() must NOT leak existence of out-of-root paths via the
|
|
90
|
-
// thrown error — quietly report "no" for any traversal attempt.
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
return fs.existsSync(full);
|
|
94
|
-
}
|
|
95
|
-
url(filePath) {
|
|
96
|
-
return `/storage/${filePath}`;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
export class StorageManager {
|
|
100
|
-
#driver;
|
|
101
|
-
constructor(driver) {
|
|
102
|
-
this.#driver = driver;
|
|
103
|
-
}
|
|
104
|
-
put(filePath, content) {
|
|
105
|
-
return this.#driver.put(filePath, content);
|
|
106
|
-
}
|
|
107
|
-
get(filePath) {
|
|
108
|
-
return this.#driver.get(filePath);
|
|
109
|
-
}
|
|
110
|
-
delete(filePath) {
|
|
111
|
-
return this.#driver.delete(filePath);
|
|
112
|
-
}
|
|
113
|
-
exists(filePath) {
|
|
114
|
-
return this.#driver.exists(filePath);
|
|
115
|
-
}
|
|
116
|
-
url(filePath) {
|
|
117
|
-
return this.#driver.url(filePath);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
//# sourceMappingURL=StorageManager.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"StorageManager.js","sourceRoot":"","sources":["../../src/storage/StorageManager.ts"],"names":[],"mappings":"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"}
|