@dimah-s3/server 1.0.2 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/dist/adapters/express.js +16 -9
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/fastify.js +16 -9
- package/dist/adapters/fastify.js.map +1 -1
- package/dist/adapters/hono.d.ts +1 -1
- package/dist/adapters/hono.js.map +1 -1
- package/dist/adapters/node.d.ts +1 -1
- package/dist/adapters/node.js +16 -9
- package/dist/adapters/node.js.map +1 -1
- package/dist/api/index.js +742 -388
- package/dist/api/index.js.map +1 -1
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/routes/catalog.d.ts +9 -0
- package/dist/api/routes/catalog.d.ts.map +1 -0
- package/dist/api/routes/confirm.d.ts +3 -4
- package/dist/api/routes/confirm.d.ts.map +1 -1
- package/dist/api/routes/delete-batch.d.ts +14 -0
- package/dist/api/routes/delete-batch.d.ts.map +1 -0
- package/dist/api/routes/delete.d.ts +2 -2
- package/dist/api/routes/delete.d.ts.map +1 -1
- package/dist/api/routes/download.d.ts +8 -8
- package/dist/api/routes/download.d.ts.map +1 -1
- package/dist/api/routes/file.d.ts +20 -0
- package/dist/api/routes/file.d.ts.map +1 -0
- package/dist/api/routes/index.d.ts +76 -50
- package/dist/api/routes/index.d.ts.map +1 -1
- package/dist/api/routes/multipart/abort.d.ts +2 -2
- package/dist/api/routes/multipart/abort.d.ts.map +1 -1
- package/dist/api/routes/multipart/complete.d.ts +2 -2
- package/dist/api/routes/multipart/complete.d.ts.map +1 -1
- package/dist/api/routes/multipart/init.d.ts +10 -12
- package/dist/api/routes/multipart/init.d.ts.map +1 -1
- package/dist/api/routes/multipart/list-parts.d.ts +2 -2
- package/dist/api/routes/multipart/list-parts.d.ts.map +1 -1
- package/dist/api/routes/multipart/part.d.ts +4 -6
- package/dist/api/routes/multipart/part.d.ts.map +1 -1
- package/dist/api/routes/upload.d.ts +10 -14
- package/dist/api/routes/upload.d.ts.map +1 -1
- package/dist/dimah-s3.d.ts +19 -8
- package/dist/dimah-s3.d.ts.map +1 -1
- package/dist/errors.d.ts +5 -4
- package/dist/errors.d.ts.map +1 -1
- package/dist/helpers/best-effort.d.ts +6 -0
- package/dist/helpers/best-effort.d.ts.map +1 -0
- package/dist/helpers/constraints.d.ts +16 -0
- package/dist/helpers/constraints.d.ts.map +1 -0
- package/dist/helpers/expires.d.ts +2 -2
- package/dist/helpers/features.d.ts +12 -29
- package/dist/helpers/features.d.ts.map +1 -1
- package/dist/helpers/finalize-confirmed.d.ts +19 -0
- package/dist/helpers/finalize-confirmed.d.ts.map +1 -0
- package/dist/helpers/head-object.d.ts.map +1 -1
- package/dist/helpers/hooks.d.ts +7 -1
- package/dist/helpers/hooks.d.ts.map +1 -1
- package/dist/helpers/index.d.ts +12 -9
- package/dist/helpers/index.d.ts.map +1 -1
- package/dist/helpers/list-parts.d.ts +5 -0
- package/dist/helpers/list-parts.d.ts.map +1 -1
- package/dist/helpers/logger.d.ts +4 -0
- package/dist/helpers/logger.d.ts.map +1 -0
- package/dist/helpers/previous-key.d.ts +5 -0
- package/dist/helpers/previous-key.d.ts.map +1 -0
- package/dist/helpers/resolve-route.d.ts +36 -0
- package/dist/helpers/resolve-route.d.ts.map +1 -0
- package/dist/helpers/resolve-target.d.ts +25 -14
- package/dist/helpers/resolve-target.d.ts.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1017 -477
- package/dist/index.js.map +1 -1
- package/dist/plugin/apply-plugins.d.ts +9 -4
- package/dist/plugin/apply-plugins.d.ts.map +1 -1
- package/dist/plugin/hook-registry.d.ts +13 -4
- package/dist/plugin/hook-registry.d.ts.map +1 -1
- package/dist/plugin/index.d.ts +1 -2
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/types.d.ts +12 -7
- package/dist/plugin/types.d.ts.map +1 -1
- package/dist/plugins.d.ts +5 -3
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +951 -475
- package/dist/plugins.js.map +1 -1
- package/dist/put.d.ts +15 -0
- package/dist/put.d.ts.map +1 -0
- package/dist/route.d.ts +13 -0
- package/dist/route.d.ts.map +1 -0
- package/dist/types/config.d.ts +190 -95
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/hook-contexts.d.ts +124 -87
- package/dist/types/hook-contexts.d.ts.map +1 -1
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +11 -11
- package/dist/api/assert-feature-enabled.d.ts +0 -5
- package/dist/api/assert-feature-enabled.d.ts.map +0 -1
- package/dist/helpers/resolve-object-acl.d.ts +0 -10
- package/dist/helpers/resolve-object-acl.d.ts.map +0 -1
- package/dist/helpers/resolve-request-acl.d.ts +0 -10
- package/dist/helpers/resolve-request-acl.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -15,14 +15,18 @@ pnpm add @dimah-s3/server @aws-sdk/client-s3
|
|
|
15
15
|
|
|
16
16
|
```ts
|
|
17
17
|
import { S3Client } from "@aws-sdk/client-s3";
|
|
18
|
-
import { dimahS3 } from "@dimah-s3/server";
|
|
18
|
+
import { dimahS3, route } from "@dimah-s3/server";
|
|
19
19
|
|
|
20
20
|
export const awsS3 = new S3Client({/* env */});
|
|
21
21
|
|
|
22
22
|
export const s3 = dimahS3({
|
|
23
23
|
client: awsS3,
|
|
24
24
|
bucket: process.env.S3_BUCKET!,
|
|
25
|
-
|
|
25
|
+
routes: {
|
|
26
|
+
uploads: route({
|
|
27
|
+
upload: { fileTypes: ["image/*"] },
|
|
28
|
+
}),
|
|
29
|
+
},
|
|
26
30
|
});
|
|
27
31
|
```
|
|
28
32
|
|
|
@@ -46,7 +50,7 @@ See [Server setup](https://dimah-s3.vercel.app/docs/server/setup) for full examp
|
|
|
46
50
|
Server-side (no HTTP):
|
|
47
51
|
|
|
48
52
|
```ts
|
|
49
|
-
await s3.api.download({ query: { key }, headers: await headers() });
|
|
53
|
+
await s3.api.download({ query: { route, key }, headers: await headers() });
|
|
50
54
|
```
|
|
51
55
|
|
|
52
56
|
Optional persistence: add `db()` from [`@dimah-s3/db`](../db) to `plugins`.
|
package/dist/adapters/express.js
CHANGED
|
@@ -18,10 +18,18 @@ var errors = {
|
|
|
18
18
|
params: { feature }
|
|
19
19
|
}),
|
|
20
20
|
invalidKey: () => DimahS3Error.from("BAD_REQUEST", S3_ERROR_CODES.INVALID_KEY),
|
|
21
|
-
|
|
22
|
-
code: S3_ERROR_CODES.
|
|
23
|
-
message: S3_ERROR_CODES.
|
|
24
|
-
params: {
|
|
21
|
+
unknownRoute: (route) => DimahS3Error.from("NOT_FOUND", {
|
|
22
|
+
code: S3_ERROR_CODES.UNKNOWN_ROUTE.code,
|
|
23
|
+
message: S3_ERROR_CODES.UNKNOWN_ROUTE.message,
|
|
24
|
+
params: { route }
|
|
25
|
+
}),
|
|
26
|
+
fileTypeNotAllowed: (fileName, contentType) => DimahS3Error.from("BAD_REQUEST", {
|
|
27
|
+
code: S3_ERROR_CODES.FILE_TYPE_NOT_ALLOWED.code,
|
|
28
|
+
message: S3_ERROR_CODES.FILE_TYPE_NOT_ALLOWED.message,
|
|
29
|
+
params: {
|
|
30
|
+
fileName,
|
|
31
|
+
...contentType ? { contentType } : {}
|
|
32
|
+
}
|
|
25
33
|
}),
|
|
26
34
|
s3NetworkError: (code) => DimahS3Error.from("BAD_GATEWAY", {
|
|
27
35
|
code: S3_ERROR_CODES.S3_NETWORK_ERROR.code,
|
|
@@ -31,11 +39,6 @@ var errors = {
|
|
|
31
39
|
),
|
|
32
40
|
params: { code }
|
|
33
41
|
}),
|
|
34
|
-
fileSizeRequiredUpload: () => DimahS3Error.from("BAD_REQUEST", S3_ERROR_CODES.FILE_SIZE_REQUIRED_UPLOAD),
|
|
35
|
-
fileSizeRequiredMultipart: () => DimahS3Error.from(
|
|
36
|
-
"BAD_REQUEST",
|
|
37
|
-
S3_ERROR_CODES.FILE_SIZE_REQUIRED_MULTIPART
|
|
38
|
-
),
|
|
39
42
|
multipartPartMissing: (partNumber) => DimahS3Error.from("BAD_REQUEST", {
|
|
40
43
|
code: S3_ERROR_CODES.MULTIPART_PART_MISSING.code,
|
|
41
44
|
message: S3_ERROR_CODES.MULTIPART_PART_MISSING.message.replaceAll(
|
|
@@ -48,6 +51,10 @@ var errors = {
|
|
|
48
51
|
...S3_ERROR_CODES.PAYLOAD_TOO_LARGE,
|
|
49
52
|
message
|
|
50
53
|
}),
|
|
54
|
+
quotaExceeded: (message = S3_ERROR_CODES.QUOTA_EXCEEDED.message) => DimahS3Error.from("PAYLOAD_TOO_LARGE", {
|
|
55
|
+
...S3_ERROR_CODES.QUOTA_EXCEEDED,
|
|
56
|
+
message
|
|
57
|
+
}),
|
|
51
58
|
validationError: (message) => DimahS3Error.from("BAD_REQUEST", {
|
|
52
59
|
code: S3_ERROR_CODES.VALIDATION_ERROR.code,
|
|
53
60
|
message
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/errors.ts","../../src/adapters/node.ts","../../src/adapters/express.ts"],"names":[],"mappings":"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","file":"express.js","sourcesContent":["import {\n DimahS3Error,\n S3_ERROR_CODES,\n isAPIError,\n isDimahS3Error,\n isS3ErrorCode,\n} from \"@dimah-s3/core\";\n\nexport {\n DimahS3Error,\n S3_ERROR_CODES,\n isAPIError,\n isDimahS3Error,\n isS3ErrorCode,\n};\n\n/** English API errors with stable codes for client-side localization. */\nexport const errors = {\n notFound: () => DimahS3Error.from(\"NOT_FOUND\", S3_ERROR_CODES.NOT_FOUND),\n\n unauthorized: () =>\n DimahS3Error.from(\"UNAUTHORIZED\", S3_ERROR_CODES.UNAUTHORIZED),\n\n forbidden: () => DimahS3Error.from(\"FORBIDDEN\", S3_ERROR_CODES.FORBIDDEN),\n\n conflict: () => DimahS3Error.from(\"CONFLICT\", S3_ERROR_CODES.CONFLICT),\n\n internalError: () =>\n DimahS3Error.from(\"INTERNAL_SERVER_ERROR\", S3_ERROR_CODES.INTERNAL_ERROR),\n\n objectNotFound: () =>\n DimahS3Error.from(\"NOT_FOUND\", S3_ERROR_CODES.OBJECT_NOT_FOUND),\n\n featureDisabled: (feature: string) =>\n DimahS3Error.from(\"NOT_FOUND\", {\n code: S3_ERROR_CODES.FEATURE_DISABLED.code,\n message: S3_ERROR_CODES.FEATURE_DISABLED.message.replaceAll(\n \"{feature}\",\n feature,\n ),\n params: { feature },\n }),\n\n invalidKey: () =>\n DimahS3Error.from(\"BAD_REQUEST\", S3_ERROR_CODES.INVALID_KEY),\n\n invalidBucket: (bucket: string) =>\n DimahS3Error.from(\"FORBIDDEN\", {\n code: S3_ERROR_CODES.INVALID_BUCKET.code,\n message: S3_ERROR_CODES.INVALID_BUCKET.message,\n params: { bucket },\n }),\n\n s3NetworkError: (code: string) =>\n DimahS3Error.from(\"BAD_GATEWAY\", {\n code: S3_ERROR_CODES.S3_NETWORK_ERROR.code,\n message: S3_ERROR_CODES.S3_NETWORK_ERROR.message.replaceAll(\n \"{code}\",\n code,\n ),\n params: { code },\n }),\n\n fileSizeRequiredUpload: () =>\n DimahS3Error.from(\"BAD_REQUEST\", S3_ERROR_CODES.FILE_SIZE_REQUIRED_UPLOAD),\n\n fileSizeRequiredMultipart: () =>\n DimahS3Error.from(\n \"BAD_REQUEST\",\n S3_ERROR_CODES.FILE_SIZE_REQUIRED_MULTIPART,\n ),\n\n multipartPartMissing: (partNumber: number) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.MULTIPART_PART_MISSING.code,\n message: S3_ERROR_CODES.MULTIPART_PART_MISSING.message.replaceAll(\n \"{partNumber}\",\n String(partNumber),\n ),\n params: { partNumber },\n }),\n\n payloadTooLarge: (\n message: string = S3_ERROR_CODES.PAYLOAD_TOO_LARGE.message,\n ) =>\n DimahS3Error.from(\"PAYLOAD_TOO_LARGE\", {\n ...S3_ERROR_CODES.PAYLOAD_TOO_LARGE,\n message,\n }),\n\n validationError: (message: string) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.VALIDATION_ERROR.code,\n message,\n }),\n} as const;\n\nexport type ServerErrors = typeof errors;\n","import { toResponse } from \"better-call\";\nimport type {\n IncomingHttpHeaders,\n IncomingMessage,\n ServerResponse,\n} from \"node:http\";\nimport { errors } from \"@/errors\";\nimport type { DimahS3HandlerSource } from \"./types\";\n\n/**\n * Convert Node.js / Express request headers into a Web {@link Headers} object.\n * Useful when calling `s3.api.*` from a Node handler.\n *\n * @example\n * ```ts\n * import { fromNodeHeaders } from \"@dimah-s3/server/node\";\n *\n * await s3.api.download({ query: { key }, headers: fromNodeHeaders(req.headers) });\n * ```\n */\nexport function fromNodeHeaders(nodeHeaders: IncomingHttpHeaders): Headers {\n const headers = new Headers();\n for (const [key, value] of Object.entries(nodeHeaders)) {\n if (value == null) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n return headers;\n}\n\nfunction collectBody(req: IncomingMessage): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer | string) => {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n req.on(\"end\", () => resolve(Buffer.concat(chunks)));\n req.on(\"error\", reject);\n });\n}\n\nfunction toWebRequest(req: IncomingMessage, body: Buffer): Request {\n const host = req.headers.host ?? \"localhost\";\n const protocol =\n (req.socket as { encrypted?: boolean }).encrypted === true\n ? \"https\"\n : \"http\";\n const url = new URL(req.url ?? \"/\", `${protocol}://${host}`);\n\n const headers = fromNodeHeaders(req.headers);\n const method = (req.method ?? \"GET\").toUpperCase();\n const init: RequestInit = { method, headers };\n if (method !== \"GET\" && method !== \"HEAD\") {\n init.body = new Uint8Array(body);\n // @ts-expect-error Node fetch duplex for streaming bodies\n init.duplex = \"half\";\n }\n\n return new Request(url, init);\n}\n\nasync function writeWebResponse(\n res: ServerResponse,\n response: Response,\n): Promise<void> {\n res.statusCode = response.status;\n response.headers.forEach((value, key) => {\n res.setHeader(key, value);\n });\n const buffer = Buffer.from(await response.arrayBuffer());\n res.end(buffer);\n}\n\n/**\n * Adapt a dimah-s3 instance to Node.js `http` / Express-style handlers.\n *\n * @example\n * ```ts\n * import { createServer } from \"node:http\";\n * import { toNodeHandler } from \"@dimah-s3/server/node\";\n * import { s3 } from \"./s3\";\n *\n * createServer(toNodeHandler(s3)).listen(3000);\n * ```\n */\nexport function toNodeHandler(s3: DimahS3HandlerSource) {\n return async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n try {\n const body = await collectBody(req);\n const request = toWebRequest(req, body);\n const response = await s3.handler(request);\n await writeWebResponse(res, response);\n } catch (err) {\n console.error(\"[S3 API]\", err);\n if (!res.headersSent) {\n await writeWebResponse(res, toResponse(errors.internalError()));\n }\n }\n };\n}\n","import { fromNodeHeaders, toNodeHandler } from \"./node\";\nimport type { DimahS3HandlerSource } from \"./types\";\n\nexport { fromNodeHeaders };\n\n/**\n * Adapt a dimah-s3 instance to an Express / Connect handler.\n *\n * Mount **before** `express.json()` so the request body is not consumed early.\n *\n * @example\n * ```ts\n * import express from \"express\";\n * import { toExpressHandler } from \"@dimah-s3/server/express\";\n * import { s3 } from \"./s3\";\n *\n * const app = express();\n * // Express 4\n * app.all(\"/api/s3/*\", toExpressHandler(s3));\n * // Express 5 — named wildcard\n * // app.all(\"/api/s3/*splat\", toExpressHandler(s3));\n * app.use(express.json());\n * ```\n */\nexport function toExpressHandler(s3: DimahS3HandlerSource) {\n return toNodeHandler(s3);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/errors.ts","../../src/adapters/node.ts","../../src/adapters/express.ts"],"names":[],"mappings":"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","file":"express.js","sourcesContent":["import {\n DimahS3Error,\n S3_ERROR_CODES,\n isAPIError,\n isDimahS3Error,\n isS3ErrorCode,\n} from \"@dimah-s3/core\";\nimport type { RouteOperation } from \"@/types/config\";\n\nexport {\n DimahS3Error,\n S3_ERROR_CODES,\n isAPIError,\n isDimahS3Error,\n isS3ErrorCode,\n};\n\n/** English API errors with stable codes for client-side localization. */\nexport const errors = {\n notFound: () => DimahS3Error.from(\"NOT_FOUND\", S3_ERROR_CODES.NOT_FOUND),\n\n unauthorized: () =>\n DimahS3Error.from(\"UNAUTHORIZED\", S3_ERROR_CODES.UNAUTHORIZED),\n\n forbidden: () => DimahS3Error.from(\"FORBIDDEN\", S3_ERROR_CODES.FORBIDDEN),\n\n conflict: () => DimahS3Error.from(\"CONFLICT\", S3_ERROR_CODES.CONFLICT),\n\n internalError: () =>\n DimahS3Error.from(\"INTERNAL_SERVER_ERROR\", S3_ERROR_CODES.INTERNAL_ERROR),\n\n objectNotFound: () =>\n DimahS3Error.from(\"NOT_FOUND\", S3_ERROR_CODES.OBJECT_NOT_FOUND),\n\n featureDisabled: (feature: RouteOperation) =>\n DimahS3Error.from(\"NOT_FOUND\", {\n code: S3_ERROR_CODES.FEATURE_DISABLED.code,\n message: S3_ERROR_CODES.FEATURE_DISABLED.message.replaceAll(\n \"{feature}\",\n feature,\n ),\n params: { feature },\n }),\n\n invalidKey: () =>\n DimahS3Error.from(\"BAD_REQUEST\", S3_ERROR_CODES.INVALID_KEY),\n\n unknownRoute: (route: string) =>\n DimahS3Error.from(\"NOT_FOUND\", {\n code: S3_ERROR_CODES.UNKNOWN_ROUTE.code,\n message: S3_ERROR_CODES.UNKNOWN_ROUTE.message,\n params: { route },\n }),\n\n fileTypeNotAllowed: (fileName: string, contentType?: string) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.FILE_TYPE_NOT_ALLOWED.code,\n message: S3_ERROR_CODES.FILE_TYPE_NOT_ALLOWED.message,\n params: {\n fileName,\n ...(contentType ? { contentType } : {}),\n },\n }),\n\n s3NetworkError: (code: string) =>\n DimahS3Error.from(\"BAD_GATEWAY\", {\n code: S3_ERROR_CODES.S3_NETWORK_ERROR.code,\n message: S3_ERROR_CODES.S3_NETWORK_ERROR.message.replaceAll(\n \"{code}\",\n code,\n ),\n params: { code },\n }),\n\n multipartPartMissing: (partNumber: number) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.MULTIPART_PART_MISSING.code,\n message: S3_ERROR_CODES.MULTIPART_PART_MISSING.message.replaceAll(\n \"{partNumber}\",\n String(partNumber),\n ),\n params: { partNumber },\n }),\n\n payloadTooLarge: (\n message: string = S3_ERROR_CODES.PAYLOAD_TOO_LARGE.message,\n ) =>\n DimahS3Error.from(\"PAYLOAD_TOO_LARGE\", {\n ...S3_ERROR_CODES.PAYLOAD_TOO_LARGE,\n message,\n }),\n\n quotaExceeded: (message: string = S3_ERROR_CODES.QUOTA_EXCEEDED.message) =>\n DimahS3Error.from(\"PAYLOAD_TOO_LARGE\", {\n ...S3_ERROR_CODES.QUOTA_EXCEEDED,\n message,\n }),\n\n validationError: (message: string) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.VALIDATION_ERROR.code,\n message,\n }),\n} as const;\n\nexport type ServerErrors = typeof errors;\n","import { toResponse } from \"better-call\";\nimport type {\n IncomingHttpHeaders,\n IncomingMessage,\n ServerResponse,\n} from \"node:http\";\nimport { errors } from \"@/errors\";\nimport type { DimahS3HandlerSource } from \"./types\";\n\n/**\n * Convert Node.js / Express request headers into a Web {@link Headers} object.\n * Useful when calling `s3.api.*` from a Node handler.\n *\n * @example\n * ```ts\n * import { fromNodeHeaders } from \"@dimah-s3/server/node\";\n *\n * await s3.api.download({ query: { route, key }, headers: fromNodeHeaders(req.headers) });\n * ```\n */\nexport function fromNodeHeaders(nodeHeaders: IncomingHttpHeaders): Headers {\n const headers = new Headers();\n for (const [key, value] of Object.entries(nodeHeaders)) {\n if (value == null) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n return headers;\n}\n\nfunction collectBody(req: IncomingMessage): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer | string) => {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n req.on(\"end\", () => resolve(Buffer.concat(chunks)));\n req.on(\"error\", reject);\n });\n}\n\nfunction toWebRequest(req: IncomingMessage, body: Buffer): Request {\n const host = req.headers.host ?? \"localhost\";\n const protocol =\n (req.socket as { encrypted?: boolean }).encrypted === true\n ? \"https\"\n : \"http\";\n const url = new URL(req.url ?? \"/\", `${protocol}://${host}`);\n\n const headers = fromNodeHeaders(req.headers);\n const method = (req.method ?? \"GET\").toUpperCase();\n const init: RequestInit = { method, headers };\n if (method !== \"GET\" && method !== \"HEAD\") {\n init.body = new Uint8Array(body);\n // @ts-expect-error Node fetch duplex for streaming bodies\n init.duplex = \"half\";\n }\n\n return new Request(url, init);\n}\n\nasync function writeWebResponse(\n res: ServerResponse,\n response: Response,\n): Promise<void> {\n res.statusCode = response.status;\n response.headers.forEach((value, key) => {\n res.setHeader(key, value);\n });\n const buffer = Buffer.from(await response.arrayBuffer());\n res.end(buffer);\n}\n\n/**\n * Adapt a dimah-s3 instance to Node.js `http` / Express-style handlers.\n *\n * @example\n * ```ts\n * import { createServer } from \"node:http\";\n * import { toNodeHandler } from \"@dimah-s3/server/node\";\n * import { s3 } from \"./s3\";\n *\n * createServer(toNodeHandler(s3)).listen(3000);\n * ```\n */\nexport function toNodeHandler(s3: DimahS3HandlerSource) {\n return async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n try {\n const body = await collectBody(req);\n const request = toWebRequest(req, body);\n const response = await s3.handler(request);\n await writeWebResponse(res, response);\n } catch (err) {\n console.error(\"[S3 API]\", err);\n if (!res.headersSent) {\n await writeWebResponse(res, toResponse(errors.internalError()));\n }\n }\n };\n}\n","import { fromNodeHeaders, toNodeHandler } from \"./node\";\nimport type { DimahS3HandlerSource } from \"./types\";\n\nexport { fromNodeHeaders };\n\n/**\n * Adapt a dimah-s3 instance to an Express / Connect handler.\n *\n * Mount **before** `express.json()` so the request body is not consumed early.\n *\n * @example\n * ```ts\n * import express from \"express\";\n * import { toExpressHandler } from \"@dimah-s3/server/express\";\n * import { s3 } from \"./s3\";\n *\n * const app = express();\n * // Express 4\n * app.all(\"/api/s3/*\", toExpressHandler(s3));\n * // Express 5 — named wildcard\n * // app.all(\"/api/s3/*splat\", toExpressHandler(s3));\n * app.use(express.json());\n * ```\n */\nexport function toExpressHandler(s3: DimahS3HandlerSource) {\n return toNodeHandler(s3);\n}\n"]}
|
package/dist/adapters/fastify.js
CHANGED
|
@@ -18,10 +18,18 @@ var errors = {
|
|
|
18
18
|
params: { feature }
|
|
19
19
|
}),
|
|
20
20
|
invalidKey: () => DimahS3Error.from("BAD_REQUEST", S3_ERROR_CODES.INVALID_KEY),
|
|
21
|
-
|
|
22
|
-
code: S3_ERROR_CODES.
|
|
23
|
-
message: S3_ERROR_CODES.
|
|
24
|
-
params: {
|
|
21
|
+
unknownRoute: (route) => DimahS3Error.from("NOT_FOUND", {
|
|
22
|
+
code: S3_ERROR_CODES.UNKNOWN_ROUTE.code,
|
|
23
|
+
message: S3_ERROR_CODES.UNKNOWN_ROUTE.message,
|
|
24
|
+
params: { route }
|
|
25
|
+
}),
|
|
26
|
+
fileTypeNotAllowed: (fileName, contentType) => DimahS3Error.from("BAD_REQUEST", {
|
|
27
|
+
code: S3_ERROR_CODES.FILE_TYPE_NOT_ALLOWED.code,
|
|
28
|
+
message: S3_ERROR_CODES.FILE_TYPE_NOT_ALLOWED.message,
|
|
29
|
+
params: {
|
|
30
|
+
fileName,
|
|
31
|
+
...contentType ? { contentType } : {}
|
|
32
|
+
}
|
|
25
33
|
}),
|
|
26
34
|
s3NetworkError: (code) => DimahS3Error.from("BAD_GATEWAY", {
|
|
27
35
|
code: S3_ERROR_CODES.S3_NETWORK_ERROR.code,
|
|
@@ -31,11 +39,6 @@ var errors = {
|
|
|
31
39
|
),
|
|
32
40
|
params: { code }
|
|
33
41
|
}),
|
|
34
|
-
fileSizeRequiredUpload: () => DimahS3Error.from("BAD_REQUEST", S3_ERROR_CODES.FILE_SIZE_REQUIRED_UPLOAD),
|
|
35
|
-
fileSizeRequiredMultipart: () => DimahS3Error.from(
|
|
36
|
-
"BAD_REQUEST",
|
|
37
|
-
S3_ERROR_CODES.FILE_SIZE_REQUIRED_MULTIPART
|
|
38
|
-
),
|
|
39
42
|
multipartPartMissing: (partNumber) => DimahS3Error.from("BAD_REQUEST", {
|
|
40
43
|
code: S3_ERROR_CODES.MULTIPART_PART_MISSING.code,
|
|
41
44
|
message: S3_ERROR_CODES.MULTIPART_PART_MISSING.message.replaceAll(
|
|
@@ -48,6 +51,10 @@ var errors = {
|
|
|
48
51
|
...S3_ERROR_CODES.PAYLOAD_TOO_LARGE,
|
|
49
52
|
message
|
|
50
53
|
}),
|
|
54
|
+
quotaExceeded: (message = S3_ERROR_CODES.QUOTA_EXCEEDED.message) => DimahS3Error.from("PAYLOAD_TOO_LARGE", {
|
|
55
|
+
...S3_ERROR_CODES.QUOTA_EXCEEDED,
|
|
56
|
+
message
|
|
57
|
+
}),
|
|
51
58
|
validationError: (message) => DimahS3Error.from("BAD_REQUEST", {
|
|
52
59
|
code: S3_ERROR_CODES.VALIDATION_ERROR.code,
|
|
53
60
|
message
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/errors.ts","../../src/adapters/node.ts","../../src/adapters/fastify.ts"],"names":[],"mappings":"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","file":"fastify.js","sourcesContent":["import {\n DimahS3Error,\n S3_ERROR_CODES,\n isAPIError,\n isDimahS3Error,\n isS3ErrorCode,\n} from \"@dimah-s3/core\";\n\nexport {\n DimahS3Error,\n S3_ERROR_CODES,\n isAPIError,\n isDimahS3Error,\n isS3ErrorCode,\n};\n\n/** English API errors with stable codes for client-side localization. */\nexport const errors = {\n notFound: () => DimahS3Error.from(\"NOT_FOUND\", S3_ERROR_CODES.NOT_FOUND),\n\n unauthorized: () =>\n DimahS3Error.from(\"UNAUTHORIZED\", S3_ERROR_CODES.UNAUTHORIZED),\n\n forbidden: () => DimahS3Error.from(\"FORBIDDEN\", S3_ERROR_CODES.FORBIDDEN),\n\n conflict: () => DimahS3Error.from(\"CONFLICT\", S3_ERROR_CODES.CONFLICT),\n\n internalError: () =>\n DimahS3Error.from(\"INTERNAL_SERVER_ERROR\", S3_ERROR_CODES.INTERNAL_ERROR),\n\n objectNotFound: () =>\n DimahS3Error.from(\"NOT_FOUND\", S3_ERROR_CODES.OBJECT_NOT_FOUND),\n\n featureDisabled: (feature: string) =>\n DimahS3Error.from(\"NOT_FOUND\", {\n code: S3_ERROR_CODES.FEATURE_DISABLED.code,\n message: S3_ERROR_CODES.FEATURE_DISABLED.message.replaceAll(\n \"{feature}\",\n feature,\n ),\n params: { feature },\n }),\n\n invalidKey: () =>\n DimahS3Error.from(\"BAD_REQUEST\", S3_ERROR_CODES.INVALID_KEY),\n\n invalidBucket: (bucket: string) =>\n DimahS3Error.from(\"FORBIDDEN\", {\n code: S3_ERROR_CODES.INVALID_BUCKET.code,\n message: S3_ERROR_CODES.INVALID_BUCKET.message,\n params: { bucket },\n }),\n\n s3NetworkError: (code: string) =>\n DimahS3Error.from(\"BAD_GATEWAY\", {\n code: S3_ERROR_CODES.S3_NETWORK_ERROR.code,\n message: S3_ERROR_CODES.S3_NETWORK_ERROR.message.replaceAll(\n \"{code}\",\n code,\n ),\n params: { code },\n }),\n\n fileSizeRequiredUpload: () =>\n DimahS3Error.from(\"BAD_REQUEST\", S3_ERROR_CODES.FILE_SIZE_REQUIRED_UPLOAD),\n\n fileSizeRequiredMultipart: () =>\n DimahS3Error.from(\n \"BAD_REQUEST\",\n S3_ERROR_CODES.FILE_SIZE_REQUIRED_MULTIPART,\n ),\n\n multipartPartMissing: (partNumber: number) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.MULTIPART_PART_MISSING.code,\n message: S3_ERROR_CODES.MULTIPART_PART_MISSING.message.replaceAll(\n \"{partNumber}\",\n String(partNumber),\n ),\n params: { partNumber },\n }),\n\n payloadTooLarge: (\n message: string = S3_ERROR_CODES.PAYLOAD_TOO_LARGE.message,\n ) =>\n DimahS3Error.from(\"PAYLOAD_TOO_LARGE\", {\n ...S3_ERROR_CODES.PAYLOAD_TOO_LARGE,\n message,\n }),\n\n validationError: (message: string) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.VALIDATION_ERROR.code,\n message,\n }),\n} as const;\n\nexport type ServerErrors = typeof errors;\n","import { toResponse } from \"better-call\";\nimport type {\n IncomingHttpHeaders,\n IncomingMessage,\n ServerResponse,\n} from \"node:http\";\nimport { errors } from \"@/errors\";\nimport type { DimahS3HandlerSource } from \"./types\";\n\n/**\n * Convert Node.js / Express request headers into a Web {@link Headers} object.\n * Useful when calling `s3.api.*` from a Node handler.\n *\n * @example\n * ```ts\n * import { fromNodeHeaders } from \"@dimah-s3/server/node\";\n *\n * await s3.api.download({ query: { key }, headers: fromNodeHeaders(req.headers) });\n * ```\n */\nexport function fromNodeHeaders(nodeHeaders: IncomingHttpHeaders): Headers {\n const headers = new Headers();\n for (const [key, value] of Object.entries(nodeHeaders)) {\n if (value == null) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n return headers;\n}\n\nfunction collectBody(req: IncomingMessage): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer | string) => {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n req.on(\"end\", () => resolve(Buffer.concat(chunks)));\n req.on(\"error\", reject);\n });\n}\n\nfunction toWebRequest(req: IncomingMessage, body: Buffer): Request {\n const host = req.headers.host ?? \"localhost\";\n const protocol =\n (req.socket as { encrypted?: boolean }).encrypted === true\n ? \"https\"\n : \"http\";\n const url = new URL(req.url ?? \"/\", `${protocol}://${host}`);\n\n const headers = fromNodeHeaders(req.headers);\n const method = (req.method ?? \"GET\").toUpperCase();\n const init: RequestInit = { method, headers };\n if (method !== \"GET\" && method !== \"HEAD\") {\n init.body = new Uint8Array(body);\n // @ts-expect-error Node fetch duplex for streaming bodies\n init.duplex = \"half\";\n }\n\n return new Request(url, init);\n}\n\nasync function writeWebResponse(\n res: ServerResponse,\n response: Response,\n): Promise<void> {\n res.statusCode = response.status;\n response.headers.forEach((value, key) => {\n res.setHeader(key, value);\n });\n const buffer = Buffer.from(await response.arrayBuffer());\n res.end(buffer);\n}\n\n/**\n * Adapt a dimah-s3 instance to Node.js `http` / Express-style handlers.\n *\n * @example\n * ```ts\n * import { createServer } from \"node:http\";\n * import { toNodeHandler } from \"@dimah-s3/server/node\";\n * import { s3 } from \"./s3\";\n *\n * createServer(toNodeHandler(s3)).listen(3000);\n * ```\n */\nexport function toNodeHandler(s3: DimahS3HandlerSource) {\n return async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n try {\n const body = await collectBody(req);\n const request = toWebRequest(req, body);\n const response = await s3.handler(request);\n await writeWebResponse(res, response);\n } catch (err) {\n console.error(\"[S3 API]\", err);\n if (!res.headersSent) {\n await writeWebResponse(res, toResponse(errors.internalError()));\n }\n }\n };\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { toNodeHandler } from \"./node\";\nimport type { DimahS3HandlerSource } from \"./types\";\n\n/** Structural Fastify request/reply — avoids a hard dependency on `fastify`. */\ntype FastifyRequestLike = {\n raw: IncomingMessage;\n};\n\ntype FastifyReplyLike = {\n raw: ServerResponse;\n hijack: () => void;\n};\n\n/**\n * Adapt a dimah-s3 instance to a Fastify route handler.\n *\n * Uses `reply.hijack()` and the Node adapter so Fastify does not touch the\n * response stream. Mount this route **before** body parsers (or disable JSON\n * parsing for `/api/s3/*`) so the request body stays readable.\n *\n * @example\n * ```ts\n * import Fastify from \"fastify\";\n * import { toFastifyHandler } from \"@dimah-s3/server/fastify\";\n * import { s3 } from \"./s3\";\n *\n * const app = Fastify();\n * app.all(\"/api/s3/*\", toFastifyHandler(s3));\n * ```\n */\nexport function toFastifyHandler(s3: DimahS3HandlerSource) {\n const handler = toNodeHandler(s3);\n return async (req: FastifyRequestLike, reply: FastifyReplyLike) => {\n reply.hijack();\n await handler(req.raw, reply.raw);\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/errors.ts","../../src/adapters/node.ts","../../src/adapters/fastify.ts"],"names":[],"mappings":"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","file":"fastify.js","sourcesContent":["import {\n DimahS3Error,\n S3_ERROR_CODES,\n isAPIError,\n isDimahS3Error,\n isS3ErrorCode,\n} from \"@dimah-s3/core\";\nimport type { RouteOperation } from \"@/types/config\";\n\nexport {\n DimahS3Error,\n S3_ERROR_CODES,\n isAPIError,\n isDimahS3Error,\n isS3ErrorCode,\n};\n\n/** English API errors with stable codes for client-side localization. */\nexport const errors = {\n notFound: () => DimahS3Error.from(\"NOT_FOUND\", S3_ERROR_CODES.NOT_FOUND),\n\n unauthorized: () =>\n DimahS3Error.from(\"UNAUTHORIZED\", S3_ERROR_CODES.UNAUTHORIZED),\n\n forbidden: () => DimahS3Error.from(\"FORBIDDEN\", S3_ERROR_CODES.FORBIDDEN),\n\n conflict: () => DimahS3Error.from(\"CONFLICT\", S3_ERROR_CODES.CONFLICT),\n\n internalError: () =>\n DimahS3Error.from(\"INTERNAL_SERVER_ERROR\", S3_ERROR_CODES.INTERNAL_ERROR),\n\n objectNotFound: () =>\n DimahS3Error.from(\"NOT_FOUND\", S3_ERROR_CODES.OBJECT_NOT_FOUND),\n\n featureDisabled: (feature: RouteOperation) =>\n DimahS3Error.from(\"NOT_FOUND\", {\n code: S3_ERROR_CODES.FEATURE_DISABLED.code,\n message: S3_ERROR_CODES.FEATURE_DISABLED.message.replaceAll(\n \"{feature}\",\n feature,\n ),\n params: { feature },\n }),\n\n invalidKey: () =>\n DimahS3Error.from(\"BAD_REQUEST\", S3_ERROR_CODES.INVALID_KEY),\n\n unknownRoute: (route: string) =>\n DimahS3Error.from(\"NOT_FOUND\", {\n code: S3_ERROR_CODES.UNKNOWN_ROUTE.code,\n message: S3_ERROR_CODES.UNKNOWN_ROUTE.message,\n params: { route },\n }),\n\n fileTypeNotAllowed: (fileName: string, contentType?: string) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.FILE_TYPE_NOT_ALLOWED.code,\n message: S3_ERROR_CODES.FILE_TYPE_NOT_ALLOWED.message,\n params: {\n fileName,\n ...(contentType ? { contentType } : {}),\n },\n }),\n\n s3NetworkError: (code: string) =>\n DimahS3Error.from(\"BAD_GATEWAY\", {\n code: S3_ERROR_CODES.S3_NETWORK_ERROR.code,\n message: S3_ERROR_CODES.S3_NETWORK_ERROR.message.replaceAll(\n \"{code}\",\n code,\n ),\n params: { code },\n }),\n\n multipartPartMissing: (partNumber: number) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.MULTIPART_PART_MISSING.code,\n message: S3_ERROR_CODES.MULTIPART_PART_MISSING.message.replaceAll(\n \"{partNumber}\",\n String(partNumber),\n ),\n params: { partNumber },\n }),\n\n payloadTooLarge: (\n message: string = S3_ERROR_CODES.PAYLOAD_TOO_LARGE.message,\n ) =>\n DimahS3Error.from(\"PAYLOAD_TOO_LARGE\", {\n ...S3_ERROR_CODES.PAYLOAD_TOO_LARGE,\n message,\n }),\n\n quotaExceeded: (message: string = S3_ERROR_CODES.QUOTA_EXCEEDED.message) =>\n DimahS3Error.from(\"PAYLOAD_TOO_LARGE\", {\n ...S3_ERROR_CODES.QUOTA_EXCEEDED,\n message,\n }),\n\n validationError: (message: string) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.VALIDATION_ERROR.code,\n message,\n }),\n} as const;\n\nexport type ServerErrors = typeof errors;\n","import { toResponse } from \"better-call\";\nimport type {\n IncomingHttpHeaders,\n IncomingMessage,\n ServerResponse,\n} from \"node:http\";\nimport { errors } from \"@/errors\";\nimport type { DimahS3HandlerSource } from \"./types\";\n\n/**\n * Convert Node.js / Express request headers into a Web {@link Headers} object.\n * Useful when calling `s3.api.*` from a Node handler.\n *\n * @example\n * ```ts\n * import { fromNodeHeaders } from \"@dimah-s3/server/node\";\n *\n * await s3.api.download({ query: { route, key }, headers: fromNodeHeaders(req.headers) });\n * ```\n */\nexport function fromNodeHeaders(nodeHeaders: IncomingHttpHeaders): Headers {\n const headers = new Headers();\n for (const [key, value] of Object.entries(nodeHeaders)) {\n if (value == null) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n return headers;\n}\n\nfunction collectBody(req: IncomingMessage): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer | string) => {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n req.on(\"end\", () => resolve(Buffer.concat(chunks)));\n req.on(\"error\", reject);\n });\n}\n\nfunction toWebRequest(req: IncomingMessage, body: Buffer): Request {\n const host = req.headers.host ?? \"localhost\";\n const protocol =\n (req.socket as { encrypted?: boolean }).encrypted === true\n ? \"https\"\n : \"http\";\n const url = new URL(req.url ?? \"/\", `${protocol}://${host}`);\n\n const headers = fromNodeHeaders(req.headers);\n const method = (req.method ?? \"GET\").toUpperCase();\n const init: RequestInit = { method, headers };\n if (method !== \"GET\" && method !== \"HEAD\") {\n init.body = new Uint8Array(body);\n // @ts-expect-error Node fetch duplex for streaming bodies\n init.duplex = \"half\";\n }\n\n return new Request(url, init);\n}\n\nasync function writeWebResponse(\n res: ServerResponse,\n response: Response,\n): Promise<void> {\n res.statusCode = response.status;\n response.headers.forEach((value, key) => {\n res.setHeader(key, value);\n });\n const buffer = Buffer.from(await response.arrayBuffer());\n res.end(buffer);\n}\n\n/**\n * Adapt a dimah-s3 instance to Node.js `http` / Express-style handlers.\n *\n * @example\n * ```ts\n * import { createServer } from \"node:http\";\n * import { toNodeHandler } from \"@dimah-s3/server/node\";\n * import { s3 } from \"./s3\";\n *\n * createServer(toNodeHandler(s3)).listen(3000);\n * ```\n */\nexport function toNodeHandler(s3: DimahS3HandlerSource) {\n return async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n try {\n const body = await collectBody(req);\n const request = toWebRequest(req, body);\n const response = await s3.handler(request);\n await writeWebResponse(res, response);\n } catch (err) {\n console.error(\"[S3 API]\", err);\n if (!res.headersSent) {\n await writeWebResponse(res, toResponse(errors.internalError()));\n }\n }\n };\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { toNodeHandler } from \"./node\";\nimport type { DimahS3HandlerSource } from \"./types\";\n\n/** Structural Fastify request/reply — avoids a hard dependency on `fastify`. */\ntype FastifyRequestLike = {\n raw: IncomingMessage;\n};\n\ntype FastifyReplyLike = {\n raw: ServerResponse;\n hijack: () => void;\n};\n\n/**\n * Adapt a dimah-s3 instance to a Fastify route handler.\n *\n * Uses `reply.hijack()` and the Node adapter so Fastify does not touch the\n * response stream. Mount this route **before** body parsers (or disable JSON\n * parsing for `/api/s3/*`) so the request body stays readable.\n *\n * @example\n * ```ts\n * import Fastify from \"fastify\";\n * import { toFastifyHandler } from \"@dimah-s3/server/fastify\";\n * import { s3 } from \"./s3\";\n *\n * const app = Fastify();\n * app.all(\"/api/s3/*\", toFastifyHandler(s3));\n * ```\n */\nexport function toFastifyHandler(s3: DimahS3HandlerSource) {\n const handler = toNodeHandler(s3);\n return async (req: FastifyRequestLike, reply: FastifyReplyLike) => {\n reply.hijack();\n await handler(req.raw, reply.raw);\n };\n}\n"]}
|
package/dist/adapters/hono.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ type HonoContext = {
|
|
|
15
15
|
* import { s3 } from "./s3";
|
|
16
16
|
*
|
|
17
17
|
* const app = new Hono();
|
|
18
|
-
* app.on(["GET", "POST", "DELETE"], "/api/s3/*", toHonoHandler(s3));
|
|
18
|
+
* app.on(["GET", "POST", "PUT", "PATCH", "DELETE"], "/api/s3/*", toHonoHandler(s3));
|
|
19
19
|
* ```
|
|
20
20
|
*/
|
|
21
21
|
export declare function toHonoHandler(s3: DimahS3HandlerSource): (c: HonoContext) => Promise<Response>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/hono.ts"],"names":[],"mappings":";AAoBO,SAAS,cAAc,EAAA,EAA0B;AACtD,EAAA,OAAO,CAAC,CAAA,KAAmB,EAAA,CAAG,OAAA,CAAQ,CAAA,CAAE,IAAI,GAAG,CAAA;AACjD","file":"hono.js","sourcesContent":["import type { DimahS3HandlerSource } from \"./types\";\n\n/** Structural Hono context — avoids a hard dependency on `hono`. */\ntype HonoContext = {\n req: { raw: Request };\n};\n\n/**\n * Adapt a dimah-s3 instance to a Hono route handler.\n *\n * @example\n * ```ts\n * import { Hono } from \"hono\";\n * import { toHonoHandler } from \"@dimah-s3/server/hono\";\n * import { s3 } from \"./s3\";\n *\n * const app = new Hono();\n * app.on([\"GET\", \"POST\", \"DELETE\"], \"/api/s3/*\", toHonoHandler(s3));\n * ```\n */\nexport function toHonoHandler(s3: DimahS3HandlerSource) {\n return (c: HonoContext) => s3.handler(c.req.raw);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/hono.ts"],"names":[],"mappings":";AAoBO,SAAS,cAAc,EAAA,EAA0B;AACtD,EAAA,OAAO,CAAC,CAAA,KAAmB,EAAA,CAAG,OAAA,CAAQ,CAAA,CAAE,IAAI,GAAG,CAAA;AACjD","file":"hono.js","sourcesContent":["import type { DimahS3HandlerSource } from \"./types\";\n\n/** Structural Hono context — avoids a hard dependency on `hono`. */\ntype HonoContext = {\n req: { raw: Request };\n};\n\n/**\n * Adapt a dimah-s3 instance to a Hono route handler.\n *\n * @example\n * ```ts\n * import { Hono } from \"hono\";\n * import { toHonoHandler } from \"@dimah-s3/server/hono\";\n * import { s3 } from \"./s3\";\n *\n * const app = new Hono();\n * app.on([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"], \"/api/s3/*\", toHonoHandler(s3));\n * ```\n */\nexport function toHonoHandler(s3: DimahS3HandlerSource) {\n return (c: HonoContext) => s3.handler(c.req.raw);\n}\n"]}
|
package/dist/adapters/node.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { DimahS3HandlerSource } from "./types";
|
|
|
8
8
|
* ```ts
|
|
9
9
|
* import { fromNodeHeaders } from "@dimah-s3/server/node";
|
|
10
10
|
*
|
|
11
|
-
* await s3.api.download({ query: { key }, headers: fromNodeHeaders(req.headers) });
|
|
11
|
+
* await s3.api.download({ query: { route, key }, headers: fromNodeHeaders(req.headers) });
|
|
12
12
|
* ```
|
|
13
13
|
*/
|
|
14
14
|
export declare function fromNodeHeaders(nodeHeaders: IncomingHttpHeaders): Headers;
|
package/dist/adapters/node.js
CHANGED
|
@@ -18,10 +18,18 @@ var errors = {
|
|
|
18
18
|
params: { feature }
|
|
19
19
|
}),
|
|
20
20
|
invalidKey: () => DimahS3Error.from("BAD_REQUEST", S3_ERROR_CODES.INVALID_KEY),
|
|
21
|
-
|
|
22
|
-
code: S3_ERROR_CODES.
|
|
23
|
-
message: S3_ERROR_CODES.
|
|
24
|
-
params: {
|
|
21
|
+
unknownRoute: (route) => DimahS3Error.from("NOT_FOUND", {
|
|
22
|
+
code: S3_ERROR_CODES.UNKNOWN_ROUTE.code,
|
|
23
|
+
message: S3_ERROR_CODES.UNKNOWN_ROUTE.message,
|
|
24
|
+
params: { route }
|
|
25
|
+
}),
|
|
26
|
+
fileTypeNotAllowed: (fileName, contentType) => DimahS3Error.from("BAD_REQUEST", {
|
|
27
|
+
code: S3_ERROR_CODES.FILE_TYPE_NOT_ALLOWED.code,
|
|
28
|
+
message: S3_ERROR_CODES.FILE_TYPE_NOT_ALLOWED.message,
|
|
29
|
+
params: {
|
|
30
|
+
fileName,
|
|
31
|
+
...contentType ? { contentType } : {}
|
|
32
|
+
}
|
|
25
33
|
}),
|
|
26
34
|
s3NetworkError: (code) => DimahS3Error.from("BAD_GATEWAY", {
|
|
27
35
|
code: S3_ERROR_CODES.S3_NETWORK_ERROR.code,
|
|
@@ -31,11 +39,6 @@ var errors = {
|
|
|
31
39
|
),
|
|
32
40
|
params: { code }
|
|
33
41
|
}),
|
|
34
|
-
fileSizeRequiredUpload: () => DimahS3Error.from("BAD_REQUEST", S3_ERROR_CODES.FILE_SIZE_REQUIRED_UPLOAD),
|
|
35
|
-
fileSizeRequiredMultipart: () => DimahS3Error.from(
|
|
36
|
-
"BAD_REQUEST",
|
|
37
|
-
S3_ERROR_CODES.FILE_SIZE_REQUIRED_MULTIPART
|
|
38
|
-
),
|
|
39
42
|
multipartPartMissing: (partNumber) => DimahS3Error.from("BAD_REQUEST", {
|
|
40
43
|
code: S3_ERROR_CODES.MULTIPART_PART_MISSING.code,
|
|
41
44
|
message: S3_ERROR_CODES.MULTIPART_PART_MISSING.message.replaceAll(
|
|
@@ -48,6 +51,10 @@ var errors = {
|
|
|
48
51
|
...S3_ERROR_CODES.PAYLOAD_TOO_LARGE,
|
|
49
52
|
message
|
|
50
53
|
}),
|
|
54
|
+
quotaExceeded: (message = S3_ERROR_CODES.QUOTA_EXCEEDED.message) => DimahS3Error.from("PAYLOAD_TOO_LARGE", {
|
|
55
|
+
...S3_ERROR_CODES.QUOTA_EXCEEDED,
|
|
56
|
+
message
|
|
57
|
+
}),
|
|
51
58
|
validationError: (message) => DimahS3Error.from("BAD_REQUEST", {
|
|
52
59
|
code: S3_ERROR_CODES.VALIDATION_ERROR.code,
|
|
53
60
|
message
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/errors.ts","../../src/adapters/node.ts"],"names":[],"mappings":"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","file":"node.js","sourcesContent":["import {\n DimahS3Error,\n S3_ERROR_CODES,\n isAPIError,\n isDimahS3Error,\n isS3ErrorCode,\n} from \"@dimah-s3/core\";\n\nexport {\n DimahS3Error,\n S3_ERROR_CODES,\n isAPIError,\n isDimahS3Error,\n isS3ErrorCode,\n};\n\n/** English API errors with stable codes for client-side localization. */\nexport const errors = {\n notFound: () => DimahS3Error.from(\"NOT_FOUND\", S3_ERROR_CODES.NOT_FOUND),\n\n unauthorized: () =>\n DimahS3Error.from(\"UNAUTHORIZED\", S3_ERROR_CODES.UNAUTHORIZED),\n\n forbidden: () => DimahS3Error.from(\"FORBIDDEN\", S3_ERROR_CODES.FORBIDDEN),\n\n conflict: () => DimahS3Error.from(\"CONFLICT\", S3_ERROR_CODES.CONFLICT),\n\n internalError: () =>\n DimahS3Error.from(\"INTERNAL_SERVER_ERROR\", S3_ERROR_CODES.INTERNAL_ERROR),\n\n objectNotFound: () =>\n DimahS3Error.from(\"NOT_FOUND\", S3_ERROR_CODES.OBJECT_NOT_FOUND),\n\n featureDisabled: (feature: string) =>\n DimahS3Error.from(\"NOT_FOUND\", {\n code: S3_ERROR_CODES.FEATURE_DISABLED.code,\n message: S3_ERROR_CODES.FEATURE_DISABLED.message.replaceAll(\n \"{feature}\",\n feature,\n ),\n params: { feature },\n }),\n\n invalidKey: () =>\n DimahS3Error.from(\"BAD_REQUEST\", S3_ERROR_CODES.INVALID_KEY),\n\n invalidBucket: (bucket: string) =>\n DimahS3Error.from(\"FORBIDDEN\", {\n code: S3_ERROR_CODES.INVALID_BUCKET.code,\n message: S3_ERROR_CODES.INVALID_BUCKET.message,\n params: { bucket },\n }),\n\n s3NetworkError: (code: string) =>\n DimahS3Error.from(\"BAD_GATEWAY\", {\n code: S3_ERROR_CODES.S3_NETWORK_ERROR.code,\n message: S3_ERROR_CODES.S3_NETWORK_ERROR.message.replaceAll(\n \"{code}\",\n code,\n ),\n params: { code },\n }),\n\n fileSizeRequiredUpload: () =>\n DimahS3Error.from(\"BAD_REQUEST\", S3_ERROR_CODES.FILE_SIZE_REQUIRED_UPLOAD),\n\n fileSizeRequiredMultipart: () =>\n DimahS3Error.from(\n \"BAD_REQUEST\",\n S3_ERROR_CODES.FILE_SIZE_REQUIRED_MULTIPART,\n ),\n\n multipartPartMissing: (partNumber: number) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.MULTIPART_PART_MISSING.code,\n message: S3_ERROR_CODES.MULTIPART_PART_MISSING.message.replaceAll(\n \"{partNumber}\",\n String(partNumber),\n ),\n params: { partNumber },\n }),\n\n payloadTooLarge: (\n message: string = S3_ERROR_CODES.PAYLOAD_TOO_LARGE.message,\n ) =>\n DimahS3Error.from(\"PAYLOAD_TOO_LARGE\", {\n ...S3_ERROR_CODES.PAYLOAD_TOO_LARGE,\n message,\n }),\n\n validationError: (message: string) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.VALIDATION_ERROR.code,\n message,\n }),\n} as const;\n\nexport type ServerErrors = typeof errors;\n","import { toResponse } from \"better-call\";\nimport type {\n IncomingHttpHeaders,\n IncomingMessage,\n ServerResponse,\n} from \"node:http\";\nimport { errors } from \"@/errors\";\nimport type { DimahS3HandlerSource } from \"./types\";\n\n/**\n * Convert Node.js / Express request headers into a Web {@link Headers} object.\n * Useful when calling `s3.api.*` from a Node handler.\n *\n * @example\n * ```ts\n * import { fromNodeHeaders } from \"@dimah-s3/server/node\";\n *\n * await s3.api.download({ query: { key }, headers: fromNodeHeaders(req.headers) });\n * ```\n */\nexport function fromNodeHeaders(nodeHeaders: IncomingHttpHeaders): Headers {\n const headers = new Headers();\n for (const [key, value] of Object.entries(nodeHeaders)) {\n if (value == null) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n return headers;\n}\n\nfunction collectBody(req: IncomingMessage): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer | string) => {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n req.on(\"end\", () => resolve(Buffer.concat(chunks)));\n req.on(\"error\", reject);\n });\n}\n\nfunction toWebRequest(req: IncomingMessage, body: Buffer): Request {\n const host = req.headers.host ?? \"localhost\";\n const protocol =\n (req.socket as { encrypted?: boolean }).encrypted === true\n ? \"https\"\n : \"http\";\n const url = new URL(req.url ?? \"/\", `${protocol}://${host}`);\n\n const headers = fromNodeHeaders(req.headers);\n const method = (req.method ?? \"GET\").toUpperCase();\n const init: RequestInit = { method, headers };\n if (method !== \"GET\" && method !== \"HEAD\") {\n init.body = new Uint8Array(body);\n // @ts-expect-error Node fetch duplex for streaming bodies\n init.duplex = \"half\";\n }\n\n return new Request(url, init);\n}\n\nasync function writeWebResponse(\n res: ServerResponse,\n response: Response,\n): Promise<void> {\n res.statusCode = response.status;\n response.headers.forEach((value, key) => {\n res.setHeader(key, value);\n });\n const buffer = Buffer.from(await response.arrayBuffer());\n res.end(buffer);\n}\n\n/**\n * Adapt a dimah-s3 instance to Node.js `http` / Express-style handlers.\n *\n * @example\n * ```ts\n * import { createServer } from \"node:http\";\n * import { toNodeHandler } from \"@dimah-s3/server/node\";\n * import { s3 } from \"./s3\";\n *\n * createServer(toNodeHandler(s3)).listen(3000);\n * ```\n */\nexport function toNodeHandler(s3: DimahS3HandlerSource) {\n return async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n try {\n const body = await collectBody(req);\n const request = toWebRequest(req, body);\n const response = await s3.handler(request);\n await writeWebResponse(res, response);\n } catch (err) {\n console.error(\"[S3 API]\", err);\n if (!res.headersSent) {\n await writeWebResponse(res, toResponse(errors.internalError()));\n }\n }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/errors.ts","../../src/adapters/node.ts"],"names":[],"mappings":"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","file":"node.js","sourcesContent":["import {\n DimahS3Error,\n S3_ERROR_CODES,\n isAPIError,\n isDimahS3Error,\n isS3ErrorCode,\n} from \"@dimah-s3/core\";\nimport type { RouteOperation } from \"@/types/config\";\n\nexport {\n DimahS3Error,\n S3_ERROR_CODES,\n isAPIError,\n isDimahS3Error,\n isS3ErrorCode,\n};\n\n/** English API errors with stable codes for client-side localization. */\nexport const errors = {\n notFound: () => DimahS3Error.from(\"NOT_FOUND\", S3_ERROR_CODES.NOT_FOUND),\n\n unauthorized: () =>\n DimahS3Error.from(\"UNAUTHORIZED\", S3_ERROR_CODES.UNAUTHORIZED),\n\n forbidden: () => DimahS3Error.from(\"FORBIDDEN\", S3_ERROR_CODES.FORBIDDEN),\n\n conflict: () => DimahS3Error.from(\"CONFLICT\", S3_ERROR_CODES.CONFLICT),\n\n internalError: () =>\n DimahS3Error.from(\"INTERNAL_SERVER_ERROR\", S3_ERROR_CODES.INTERNAL_ERROR),\n\n objectNotFound: () =>\n DimahS3Error.from(\"NOT_FOUND\", S3_ERROR_CODES.OBJECT_NOT_FOUND),\n\n featureDisabled: (feature: RouteOperation) =>\n DimahS3Error.from(\"NOT_FOUND\", {\n code: S3_ERROR_CODES.FEATURE_DISABLED.code,\n message: S3_ERROR_CODES.FEATURE_DISABLED.message.replaceAll(\n \"{feature}\",\n feature,\n ),\n params: { feature },\n }),\n\n invalidKey: () =>\n DimahS3Error.from(\"BAD_REQUEST\", S3_ERROR_CODES.INVALID_KEY),\n\n unknownRoute: (route: string) =>\n DimahS3Error.from(\"NOT_FOUND\", {\n code: S3_ERROR_CODES.UNKNOWN_ROUTE.code,\n message: S3_ERROR_CODES.UNKNOWN_ROUTE.message,\n params: { route },\n }),\n\n fileTypeNotAllowed: (fileName: string, contentType?: string) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.FILE_TYPE_NOT_ALLOWED.code,\n message: S3_ERROR_CODES.FILE_TYPE_NOT_ALLOWED.message,\n params: {\n fileName,\n ...(contentType ? { contentType } : {}),\n },\n }),\n\n s3NetworkError: (code: string) =>\n DimahS3Error.from(\"BAD_GATEWAY\", {\n code: S3_ERROR_CODES.S3_NETWORK_ERROR.code,\n message: S3_ERROR_CODES.S3_NETWORK_ERROR.message.replaceAll(\n \"{code}\",\n code,\n ),\n params: { code },\n }),\n\n multipartPartMissing: (partNumber: number) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.MULTIPART_PART_MISSING.code,\n message: S3_ERROR_CODES.MULTIPART_PART_MISSING.message.replaceAll(\n \"{partNumber}\",\n String(partNumber),\n ),\n params: { partNumber },\n }),\n\n payloadTooLarge: (\n message: string = S3_ERROR_CODES.PAYLOAD_TOO_LARGE.message,\n ) =>\n DimahS3Error.from(\"PAYLOAD_TOO_LARGE\", {\n ...S3_ERROR_CODES.PAYLOAD_TOO_LARGE,\n message,\n }),\n\n quotaExceeded: (message: string = S3_ERROR_CODES.QUOTA_EXCEEDED.message) =>\n DimahS3Error.from(\"PAYLOAD_TOO_LARGE\", {\n ...S3_ERROR_CODES.QUOTA_EXCEEDED,\n message,\n }),\n\n validationError: (message: string) =>\n DimahS3Error.from(\"BAD_REQUEST\", {\n code: S3_ERROR_CODES.VALIDATION_ERROR.code,\n message,\n }),\n} as const;\n\nexport type ServerErrors = typeof errors;\n","import { toResponse } from \"better-call\";\nimport type {\n IncomingHttpHeaders,\n IncomingMessage,\n ServerResponse,\n} from \"node:http\";\nimport { errors } from \"@/errors\";\nimport type { DimahS3HandlerSource } from \"./types\";\n\n/**\n * Convert Node.js / Express request headers into a Web {@link Headers} object.\n * Useful when calling `s3.api.*` from a Node handler.\n *\n * @example\n * ```ts\n * import { fromNodeHeaders } from \"@dimah-s3/server/node\";\n *\n * await s3.api.download({ query: { route, key }, headers: fromNodeHeaders(req.headers) });\n * ```\n */\nexport function fromNodeHeaders(nodeHeaders: IncomingHttpHeaders): Headers {\n const headers = new Headers();\n for (const [key, value] of Object.entries(nodeHeaders)) {\n if (value == null) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n return headers;\n}\n\nfunction collectBody(req: IncomingMessage): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer | string) => {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n req.on(\"end\", () => resolve(Buffer.concat(chunks)));\n req.on(\"error\", reject);\n });\n}\n\nfunction toWebRequest(req: IncomingMessage, body: Buffer): Request {\n const host = req.headers.host ?? \"localhost\";\n const protocol =\n (req.socket as { encrypted?: boolean }).encrypted === true\n ? \"https\"\n : \"http\";\n const url = new URL(req.url ?? \"/\", `${protocol}://${host}`);\n\n const headers = fromNodeHeaders(req.headers);\n const method = (req.method ?? \"GET\").toUpperCase();\n const init: RequestInit = { method, headers };\n if (method !== \"GET\" && method !== \"HEAD\") {\n init.body = new Uint8Array(body);\n // @ts-expect-error Node fetch duplex for streaming bodies\n init.duplex = \"half\";\n }\n\n return new Request(url, init);\n}\n\nasync function writeWebResponse(\n res: ServerResponse,\n response: Response,\n): Promise<void> {\n res.statusCode = response.status;\n response.headers.forEach((value, key) => {\n res.setHeader(key, value);\n });\n const buffer = Buffer.from(await response.arrayBuffer());\n res.end(buffer);\n}\n\n/**\n * Adapt a dimah-s3 instance to Node.js `http` / Express-style handlers.\n *\n * @example\n * ```ts\n * import { createServer } from \"node:http\";\n * import { toNodeHandler } from \"@dimah-s3/server/node\";\n * import { s3 } from \"./s3\";\n *\n * createServer(toNodeHandler(s3)).listen(3000);\n * ```\n */\nexport function toNodeHandler(s3: DimahS3HandlerSource) {\n return async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n try {\n const body = await collectBody(req);\n const request = toWebRequest(req, body);\n const response = await s3.handler(request);\n await writeWebResponse(res, response);\n } catch (err) {\n console.error(\"[S3 API]\", err);\n if (!res.headersSent) {\n await writeWebResponse(res, toResponse(errors.internalError()));\n }\n }\n };\n}\n"]}
|