@bobbykim/manguito-cms-api 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/dist/codegen/index.d.mts +7 -0
- package/dist/codegen/index.d.ts +7 -0
- package/dist/codegen/index.js +701 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/codegen/index.mjs +672 -0
- package/dist/codegen/index.mjs.map +1 -0
- package/dist/index.d.mts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +3228 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3189 -0
- package/dist/index.mjs.map +1 -0
- package/dist/runtime/index.d.mts +29 -0
- package/dist/runtime/index.d.ts +29 -0
- package/dist/runtime/index.js +118 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/index.mjs +86 -0
- package/dist/runtime/index.mjs.map +1 -0
- package/dist/storage/index.d.mts +25 -0
- package/dist/storage/index.d.ts +25 -0
- package/dist/storage/index.js +287 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/index.mjs +253 -0
- package/dist/storage/index.mjs.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { ServerAdapter } from '@bobbykim/manguito-cms-core';
|
|
3
|
+
import { handle } from 'hono/aws-lambda';
|
|
4
|
+
import { handle as handle$1 } from 'hono/vercel';
|
|
5
|
+
|
|
6
|
+
declare function createServer(app: Hono, options?: {
|
|
7
|
+
port?: number;
|
|
8
|
+
}): ServerAdapter;
|
|
9
|
+
|
|
10
|
+
declare function createLambdaHandler(app: Hono): ServerAdapter & {
|
|
11
|
+
handler: ReturnType<typeof handle>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
declare function createVercelHandler(app: Hono): ServerAdapter & {
|
|
15
|
+
handler: ReturnType<typeof handle$1>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Resolve a request sub-path against a base directory, returning the absolute
|
|
20
|
+
* path only when it stays inside baseDir. Returns null for any path that
|
|
21
|
+
* escapes (traversal, sibling-prefix). Pure — performs no filesystem access.
|
|
22
|
+
*/
|
|
23
|
+
declare function resolveStaticFile(baseDir: string, urlSubPath: string): string | null;
|
|
24
|
+
/** Extensions safe to serve inline for untrusted user uploads (Finding #2). */
|
|
25
|
+
declare const SAFE_INLINE_MIME: Record<string, string>;
|
|
26
|
+
/** MIME map for trusted, build-produced admin SPA assets. */
|
|
27
|
+
declare const ADMIN_MIME: Record<string, string>;
|
|
28
|
+
|
|
29
|
+
export { ADMIN_MIME, SAFE_INLINE_MIME, createLambdaHandler, createServer, createVercelHandler, resolveStaticFile };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { ServerAdapter } from '@bobbykim/manguito-cms-core';
|
|
3
|
+
import { handle } from 'hono/aws-lambda';
|
|
4
|
+
import { handle as handle$1 } from 'hono/vercel';
|
|
5
|
+
|
|
6
|
+
declare function createServer(app: Hono, options?: {
|
|
7
|
+
port?: number;
|
|
8
|
+
}): ServerAdapter;
|
|
9
|
+
|
|
10
|
+
declare function createLambdaHandler(app: Hono): ServerAdapter & {
|
|
11
|
+
handler: ReturnType<typeof handle>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
declare function createVercelHandler(app: Hono): ServerAdapter & {
|
|
15
|
+
handler: ReturnType<typeof handle$1>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Resolve a request sub-path against a base directory, returning the absolute
|
|
20
|
+
* path only when it stays inside baseDir. Returns null for any path that
|
|
21
|
+
* escapes (traversal, sibling-prefix). Pure — performs no filesystem access.
|
|
22
|
+
*/
|
|
23
|
+
declare function resolveStaticFile(baseDir: string, urlSubPath: string): string | null;
|
|
24
|
+
/** Extensions safe to serve inline for untrusted user uploads (Finding #2). */
|
|
25
|
+
declare const SAFE_INLINE_MIME: Record<string, string>;
|
|
26
|
+
/** MIME map for trusted, build-produced admin SPA assets. */
|
|
27
|
+
declare const ADMIN_MIME: Record<string, string>;
|
|
28
|
+
|
|
29
|
+
export { ADMIN_MIME, SAFE_INLINE_MIME, createLambdaHandler, createServer, createVercelHandler, resolveStaticFile };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/runtime/index.ts
|
|
21
|
+
var runtime_exports = {};
|
|
22
|
+
__export(runtime_exports, {
|
|
23
|
+
ADMIN_MIME: () => ADMIN_MIME,
|
|
24
|
+
SAFE_INLINE_MIME: () => SAFE_INLINE_MIME,
|
|
25
|
+
createLambdaHandler: () => createLambdaHandler,
|
|
26
|
+
createServer: () => createServer,
|
|
27
|
+
createVercelHandler: () => createVercelHandler,
|
|
28
|
+
resolveStaticFile: () => resolveStaticFile
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(runtime_exports);
|
|
31
|
+
|
|
32
|
+
// src/runtime/server.ts
|
|
33
|
+
var import_node_server = require("@hono/node-server");
|
|
34
|
+
var DEFAULT_CORS = { origin: "*" };
|
|
35
|
+
function createServer(app, options) {
|
|
36
|
+
const port = options?.port ?? Number(process.env["PORT"] ?? 3e3);
|
|
37
|
+
(0, import_node_server.serve)({ fetch: app.fetch, port }, (info) => {
|
|
38
|
+
console.log(`Server listening on http://localhost:${info.port}`);
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
type: "node",
|
|
42
|
+
cors: DEFAULT_CORS,
|
|
43
|
+
getEntryPoint: () => "node"
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/runtime/lambda.ts
|
|
48
|
+
var import_aws_lambda = require("hono/aws-lambda");
|
|
49
|
+
var DEFAULT_CORS2 = { origin: "*" };
|
|
50
|
+
function createLambdaHandler(app) {
|
|
51
|
+
return {
|
|
52
|
+
type: "lambda",
|
|
53
|
+
cors: DEFAULT_CORS2,
|
|
54
|
+
getEntryPoint: () => "lambda",
|
|
55
|
+
handler: (0, import_aws_lambda.handle)(app)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/runtime/vercel.ts
|
|
60
|
+
var import_vercel = require("hono/vercel");
|
|
61
|
+
var DEFAULT_CORS3 = { origin: "*" };
|
|
62
|
+
function createVercelHandler(app) {
|
|
63
|
+
return {
|
|
64
|
+
type: "vercel",
|
|
65
|
+
cors: DEFAULT_CORS3,
|
|
66
|
+
getEntryPoint: () => "vercel",
|
|
67
|
+
handler: (0, import_vercel.handle)(app)
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/runtime/static.ts
|
|
72
|
+
var import_node_path = require("path");
|
|
73
|
+
function resolveStaticFile(baseDir, urlSubPath) {
|
|
74
|
+
const base = (0, import_node_path.resolve)(baseDir);
|
|
75
|
+
const rel = urlSubPath.startsWith("/") ? "." + urlSubPath : "./" + urlSubPath;
|
|
76
|
+
const candidate = (0, import_node_path.resolve)(base, rel);
|
|
77
|
+
if (candidate === base || candidate.startsWith(base + import_node_path.sep)) {
|
|
78
|
+
return candidate;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
var SAFE_INLINE_MIME = {
|
|
83
|
+
png: "image/png",
|
|
84
|
+
jpg: "image/jpeg",
|
|
85
|
+
jpeg: "image/jpeg",
|
|
86
|
+
gif: "image/gif",
|
|
87
|
+
webp: "image/webp",
|
|
88
|
+
mp4: "video/mp4",
|
|
89
|
+
webm: "video/webm",
|
|
90
|
+
mov: "video/quicktime",
|
|
91
|
+
pdf: "application/pdf"
|
|
92
|
+
};
|
|
93
|
+
var ADMIN_MIME = {
|
|
94
|
+
html: "text/html; charset=utf-8",
|
|
95
|
+
js: "application/javascript",
|
|
96
|
+
mjs: "application/javascript",
|
|
97
|
+
css: "text/css",
|
|
98
|
+
json: "application/json",
|
|
99
|
+
png: "image/png",
|
|
100
|
+
jpg: "image/jpeg",
|
|
101
|
+
jpeg: "image/jpeg",
|
|
102
|
+
gif: "image/gif",
|
|
103
|
+
svg: "image/svg+xml",
|
|
104
|
+
ico: "image/x-icon",
|
|
105
|
+
woff: "font/woff",
|
|
106
|
+
woff2: "font/woff2",
|
|
107
|
+
webp: "image/webp"
|
|
108
|
+
};
|
|
109
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
110
|
+
0 && (module.exports = {
|
|
111
|
+
ADMIN_MIME,
|
|
112
|
+
SAFE_INLINE_MIME,
|
|
113
|
+
createLambdaHandler,
|
|
114
|
+
createServer,
|
|
115
|
+
createVercelHandler,
|
|
116
|
+
resolveStaticFile
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/index.ts","../../src/runtime/server.ts","../../src/runtime/lambda.ts","../../src/runtime/vercel.ts","../../src/runtime/static.ts"],"sourcesContent":["export { createServer } from './server.js'\nexport { createLambdaHandler } from './lambda.js'\nexport { createVercelHandler } from './vercel.js'\nexport { resolveStaticFile, SAFE_INLINE_MIME, ADMIN_MIME } from './static.js'\n","import { serve } from '@hono/node-server'\nimport type { Hono } from 'hono'\nimport type { ServerAdapter, CorsConfig } from '@bobbykim/manguito-cms-core'\n\nconst DEFAULT_CORS: CorsConfig = { origin: '*' }\n\nexport function createServer(app: Hono, options?: { port?: number }): ServerAdapter {\n const port = options?.port ?? Number(process.env['PORT'] ?? 3000)\n\n serve({ fetch: app.fetch, port }, (info: { port: number }) => {\n console.log(`Server listening on http://localhost:${info.port}`)\n })\n\n return {\n type: 'node',\n cors: DEFAULT_CORS,\n getEntryPoint: () => 'node',\n }\n}\n","import { handle } from 'hono/aws-lambda'\nimport type { Hono } from 'hono'\nimport type { ServerAdapter, CorsConfig } from '@bobbykim/manguito-cms-core'\n\nconst DEFAULT_CORS: CorsConfig = { origin: '*' }\n\nexport function createLambdaHandler(app: Hono): ServerAdapter & { handler: ReturnType<typeof handle> } {\n return {\n type: 'lambda',\n cors: DEFAULT_CORS,\n getEntryPoint: () => 'lambda',\n handler: handle(app),\n }\n}\n","import { handle } from 'hono/vercel'\nimport type { Hono } from 'hono'\nimport type { ServerAdapter, CorsConfig } from '@bobbykim/manguito-cms-core'\n\nconst DEFAULT_CORS: CorsConfig = { origin: '*' }\n\nexport function createVercelHandler(app: Hono): ServerAdapter & { handler: ReturnType<typeof handle> } {\n return {\n type: 'vercel',\n cors: DEFAULT_CORS,\n getEntryPoint: () => 'vercel',\n handler: handle(app),\n }\n}\n","import { resolve, sep } from 'node:path'\n\n/**\n * Resolve a request sub-path against a base directory, returning the absolute\n * path only when it stays inside baseDir. Returns null for any path that\n * escapes (traversal, sibling-prefix). Pure — performs no filesystem access.\n */\nexport function resolveStaticFile(baseDir: string, urlSubPath: string): string | null {\n const base = resolve(baseDir)\n const rel = urlSubPath.startsWith('/') ? '.' + urlSubPath : './' + urlSubPath\n const candidate = resolve(base, rel)\n if (candidate === base || candidate.startsWith(base + sep)) {\n return candidate\n }\n return null\n}\n\n/** Extensions safe to serve inline for untrusted user uploads (Finding #2). */\nexport const SAFE_INLINE_MIME: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n pdf: 'application/pdf',\n}\n\n/** MIME map for trusted, build-produced admin SPA assets. */\nexport const ADMIN_MIME: Record<string, string> = {\n html: 'text/html; charset=utf-8',\n js: 'application/javascript',\n mjs: 'application/javascript',\n css: 'text/css',\n json: 'application/json',\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n woff: 'font/woff',\n woff2: 'font/woff2',\n webp: 'image/webp',\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,yBAAsB;AAItB,IAAM,eAA2B,EAAE,QAAQ,IAAI;AAExC,SAAS,aAAa,KAAW,SAA4C;AAClF,QAAM,OAAO,SAAS,QAAQ,OAAO,QAAQ,IAAI,MAAM,KAAK,GAAI;AAEhE,gCAAM,EAAE,OAAO,IAAI,OAAO,KAAK,GAAG,CAAC,SAA2B;AAC5D,YAAQ,IAAI,wCAAwC,KAAK,IAAI,EAAE;AAAA,EACjE,CAAC;AAED,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe,MAAM;AAAA,EACvB;AACF;;;AClBA,wBAAuB;AAIvB,IAAMA,gBAA2B,EAAE,QAAQ,IAAI;AAExC,SAAS,oBAAoB,KAAmE;AACrG,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAMA;AAAA,IACN,eAAe,MAAM;AAAA,IACrB,aAAS,0BAAO,GAAG;AAAA,EACrB;AACF;;;ACbA,oBAAuB;AAIvB,IAAMC,gBAA2B,EAAE,QAAQ,IAAI;AAExC,SAAS,oBAAoB,KAAmE;AACrG,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAMA;AAAA,IACN,eAAe,MAAM;AAAA,IACrB,aAAS,sBAAO,GAAG;AAAA,EACrB;AACF;;;ACbA,uBAA6B;AAOtB,SAAS,kBAAkB,SAAiB,YAAmC;AACpF,QAAM,WAAO,0BAAQ,OAAO;AAC5B,QAAM,MAAM,WAAW,WAAW,GAAG,IAAI,MAAM,aAAa,OAAO;AACnE,QAAM,gBAAY,0BAAQ,MAAM,GAAG;AACnC,MAAI,cAAc,QAAQ,UAAU,WAAW,OAAO,oBAAG,GAAG;AAC1D,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGO,IAAM,mBAA2C;AAAA,EACtD,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AACP;AAGO,IAAM,aAAqC;AAAA,EAChD,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AACR;","names":["DEFAULT_CORS","DEFAULT_CORS"]}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// src/runtime/server.ts
|
|
2
|
+
import { serve } from "@hono/node-server";
|
|
3
|
+
var DEFAULT_CORS = { origin: "*" };
|
|
4
|
+
function createServer(app, options) {
|
|
5
|
+
const port = options?.port ?? Number(process.env["PORT"] ?? 3e3);
|
|
6
|
+
serve({ fetch: app.fetch, port }, (info) => {
|
|
7
|
+
console.log(`Server listening on http://localhost:${info.port}`);
|
|
8
|
+
});
|
|
9
|
+
return {
|
|
10
|
+
type: "node",
|
|
11
|
+
cors: DEFAULT_CORS,
|
|
12
|
+
getEntryPoint: () => "node"
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/runtime/lambda.ts
|
|
17
|
+
import { handle } from "hono/aws-lambda";
|
|
18
|
+
var DEFAULT_CORS2 = { origin: "*" };
|
|
19
|
+
function createLambdaHandler(app) {
|
|
20
|
+
return {
|
|
21
|
+
type: "lambda",
|
|
22
|
+
cors: DEFAULT_CORS2,
|
|
23
|
+
getEntryPoint: () => "lambda",
|
|
24
|
+
handler: handle(app)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/runtime/vercel.ts
|
|
29
|
+
import { handle as handle2 } from "hono/vercel";
|
|
30
|
+
var DEFAULT_CORS3 = { origin: "*" };
|
|
31
|
+
function createVercelHandler(app) {
|
|
32
|
+
return {
|
|
33
|
+
type: "vercel",
|
|
34
|
+
cors: DEFAULT_CORS3,
|
|
35
|
+
getEntryPoint: () => "vercel",
|
|
36
|
+
handler: handle2(app)
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/runtime/static.ts
|
|
41
|
+
import { resolve, sep } from "path";
|
|
42
|
+
function resolveStaticFile(baseDir, urlSubPath) {
|
|
43
|
+
const base = resolve(baseDir);
|
|
44
|
+
const rel = urlSubPath.startsWith("/") ? "." + urlSubPath : "./" + urlSubPath;
|
|
45
|
+
const candidate = resolve(base, rel);
|
|
46
|
+
if (candidate === base || candidate.startsWith(base + sep)) {
|
|
47
|
+
return candidate;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
var SAFE_INLINE_MIME = {
|
|
52
|
+
png: "image/png",
|
|
53
|
+
jpg: "image/jpeg",
|
|
54
|
+
jpeg: "image/jpeg",
|
|
55
|
+
gif: "image/gif",
|
|
56
|
+
webp: "image/webp",
|
|
57
|
+
mp4: "video/mp4",
|
|
58
|
+
webm: "video/webm",
|
|
59
|
+
mov: "video/quicktime",
|
|
60
|
+
pdf: "application/pdf"
|
|
61
|
+
};
|
|
62
|
+
var ADMIN_MIME = {
|
|
63
|
+
html: "text/html; charset=utf-8",
|
|
64
|
+
js: "application/javascript",
|
|
65
|
+
mjs: "application/javascript",
|
|
66
|
+
css: "text/css",
|
|
67
|
+
json: "application/json",
|
|
68
|
+
png: "image/png",
|
|
69
|
+
jpg: "image/jpeg",
|
|
70
|
+
jpeg: "image/jpeg",
|
|
71
|
+
gif: "image/gif",
|
|
72
|
+
svg: "image/svg+xml",
|
|
73
|
+
ico: "image/x-icon",
|
|
74
|
+
woff: "font/woff",
|
|
75
|
+
woff2: "font/woff2",
|
|
76
|
+
webp: "image/webp"
|
|
77
|
+
};
|
|
78
|
+
export {
|
|
79
|
+
ADMIN_MIME,
|
|
80
|
+
SAFE_INLINE_MIME,
|
|
81
|
+
createLambdaHandler,
|
|
82
|
+
createServer,
|
|
83
|
+
createVercelHandler,
|
|
84
|
+
resolveStaticFile
|
|
85
|
+
};
|
|
86
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/server.ts","../../src/runtime/lambda.ts","../../src/runtime/vercel.ts","../../src/runtime/static.ts"],"sourcesContent":["import { serve } from '@hono/node-server'\nimport type { Hono } from 'hono'\nimport type { ServerAdapter, CorsConfig } from '@bobbykim/manguito-cms-core'\n\nconst DEFAULT_CORS: CorsConfig = { origin: '*' }\n\nexport function createServer(app: Hono, options?: { port?: number }): ServerAdapter {\n const port = options?.port ?? Number(process.env['PORT'] ?? 3000)\n\n serve({ fetch: app.fetch, port }, (info: { port: number }) => {\n console.log(`Server listening on http://localhost:${info.port}`)\n })\n\n return {\n type: 'node',\n cors: DEFAULT_CORS,\n getEntryPoint: () => 'node',\n }\n}\n","import { handle } from 'hono/aws-lambda'\nimport type { Hono } from 'hono'\nimport type { ServerAdapter, CorsConfig } from '@bobbykim/manguito-cms-core'\n\nconst DEFAULT_CORS: CorsConfig = { origin: '*' }\n\nexport function createLambdaHandler(app: Hono): ServerAdapter & { handler: ReturnType<typeof handle> } {\n return {\n type: 'lambda',\n cors: DEFAULT_CORS,\n getEntryPoint: () => 'lambda',\n handler: handle(app),\n }\n}\n","import { handle } from 'hono/vercel'\nimport type { Hono } from 'hono'\nimport type { ServerAdapter, CorsConfig } from '@bobbykim/manguito-cms-core'\n\nconst DEFAULT_CORS: CorsConfig = { origin: '*' }\n\nexport function createVercelHandler(app: Hono): ServerAdapter & { handler: ReturnType<typeof handle> } {\n return {\n type: 'vercel',\n cors: DEFAULT_CORS,\n getEntryPoint: () => 'vercel',\n handler: handle(app),\n }\n}\n","import { resolve, sep } from 'node:path'\n\n/**\n * Resolve a request sub-path against a base directory, returning the absolute\n * path only when it stays inside baseDir. Returns null for any path that\n * escapes (traversal, sibling-prefix). Pure — performs no filesystem access.\n */\nexport function resolveStaticFile(baseDir: string, urlSubPath: string): string | null {\n const base = resolve(baseDir)\n const rel = urlSubPath.startsWith('/') ? '.' + urlSubPath : './' + urlSubPath\n const candidate = resolve(base, rel)\n if (candidate === base || candidate.startsWith(base + sep)) {\n return candidate\n }\n return null\n}\n\n/** Extensions safe to serve inline for untrusted user uploads (Finding #2). */\nexport const SAFE_INLINE_MIME: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n pdf: 'application/pdf',\n}\n\n/** MIME map for trusted, build-produced admin SPA assets. */\nexport const ADMIN_MIME: Record<string, string> = {\n html: 'text/html; charset=utf-8',\n js: 'application/javascript',\n mjs: 'application/javascript',\n css: 'text/css',\n json: 'application/json',\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n woff: 'font/woff',\n woff2: 'font/woff2',\n webp: 'image/webp',\n}\n"],"mappings":";AAAA,SAAS,aAAa;AAItB,IAAM,eAA2B,EAAE,QAAQ,IAAI;AAExC,SAAS,aAAa,KAAW,SAA4C;AAClF,QAAM,OAAO,SAAS,QAAQ,OAAO,QAAQ,IAAI,MAAM,KAAK,GAAI;AAEhE,QAAM,EAAE,OAAO,IAAI,OAAO,KAAK,GAAG,CAAC,SAA2B;AAC5D,YAAQ,IAAI,wCAAwC,KAAK,IAAI,EAAE;AAAA,EACjE,CAAC;AAED,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe,MAAM;AAAA,EACvB;AACF;;;AClBA,SAAS,cAAc;AAIvB,IAAMA,gBAA2B,EAAE,QAAQ,IAAI;AAExC,SAAS,oBAAoB,KAAmE;AACrG,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAMA;AAAA,IACN,eAAe,MAAM;AAAA,IACrB,SAAS,OAAO,GAAG;AAAA,EACrB;AACF;;;ACbA,SAAS,UAAAC,eAAc;AAIvB,IAAMC,gBAA2B,EAAE,QAAQ,IAAI;AAExC,SAAS,oBAAoB,KAAmE;AACrG,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAMA;AAAA,IACN,eAAe,MAAM;AAAA,IACrB,SAASD,QAAO,GAAG;AAAA,EACrB;AACF;;;ACbA,SAAS,SAAS,WAAW;AAOtB,SAAS,kBAAkB,SAAiB,YAAmC;AACpF,QAAM,OAAO,QAAQ,OAAO;AAC5B,QAAM,MAAM,WAAW,WAAW,GAAG,IAAI,MAAM,aAAa,OAAO;AACnE,QAAM,YAAY,QAAQ,MAAM,GAAG;AACnC,MAAI,cAAc,QAAQ,UAAU,WAAW,OAAO,GAAG,GAAG;AAC1D,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGO,IAAM,mBAA2C;AAAA,EACtD,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AACP;AAGO,IAAM,aAAqC;AAAA,EAChD,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AACR;","names":["DEFAULT_CORS","handle","DEFAULT_CORS"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { StorageAdapter } from '@bobbykim/manguito-cms-core';
|
|
2
|
+
|
|
3
|
+
type LocalAdapterOptions = {
|
|
4
|
+
upload_dir?: string;
|
|
5
|
+
};
|
|
6
|
+
declare function createLocalAdapter(options?: LocalAdapterOptions): StorageAdapter;
|
|
7
|
+
|
|
8
|
+
type S3AdapterOptions = {
|
|
9
|
+
bucket: string;
|
|
10
|
+
region: string;
|
|
11
|
+
prefix?: string;
|
|
12
|
+
access_key_id?: string;
|
|
13
|
+
secret_access_key?: string;
|
|
14
|
+
};
|
|
15
|
+
declare function createS3Adapter(options: S3AdapterOptions): StorageAdapter;
|
|
16
|
+
|
|
17
|
+
type CloudinaryAdapterOptions = {
|
|
18
|
+
cloud_name?: string;
|
|
19
|
+
folder?: string;
|
|
20
|
+
access_key_id?: string;
|
|
21
|
+
secret_access_key?: string;
|
|
22
|
+
};
|
|
23
|
+
declare function createCloudinaryAdapter(options?: CloudinaryAdapterOptions): StorageAdapter;
|
|
24
|
+
|
|
25
|
+
export { type CloudinaryAdapterOptions, type LocalAdapterOptions, type S3AdapterOptions, createCloudinaryAdapter, createLocalAdapter, createS3Adapter };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { StorageAdapter } from '@bobbykim/manguito-cms-core';
|
|
2
|
+
|
|
3
|
+
type LocalAdapterOptions = {
|
|
4
|
+
upload_dir?: string;
|
|
5
|
+
};
|
|
6
|
+
declare function createLocalAdapter(options?: LocalAdapterOptions): StorageAdapter;
|
|
7
|
+
|
|
8
|
+
type S3AdapterOptions = {
|
|
9
|
+
bucket: string;
|
|
10
|
+
region: string;
|
|
11
|
+
prefix?: string;
|
|
12
|
+
access_key_id?: string;
|
|
13
|
+
secret_access_key?: string;
|
|
14
|
+
};
|
|
15
|
+
declare function createS3Adapter(options: S3AdapterOptions): StorageAdapter;
|
|
16
|
+
|
|
17
|
+
type CloudinaryAdapterOptions = {
|
|
18
|
+
cloud_name?: string;
|
|
19
|
+
folder?: string;
|
|
20
|
+
access_key_id?: string;
|
|
21
|
+
secret_access_key?: string;
|
|
22
|
+
};
|
|
23
|
+
declare function createCloudinaryAdapter(options?: CloudinaryAdapterOptions): StorageAdapter;
|
|
24
|
+
|
|
25
|
+
export { type CloudinaryAdapterOptions, type LocalAdapterOptions, type S3AdapterOptions, createCloudinaryAdapter, createLocalAdapter, createS3Adapter };
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/storage/index.ts
|
|
31
|
+
var storage_exports = {};
|
|
32
|
+
__export(storage_exports, {
|
|
33
|
+
createCloudinaryAdapter: () => createCloudinaryAdapter,
|
|
34
|
+
createLocalAdapter: () => createLocalAdapter,
|
|
35
|
+
createS3Adapter: () => createS3Adapter
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(storage_exports);
|
|
38
|
+
|
|
39
|
+
// src/storage/adapters/local.ts
|
|
40
|
+
var import_node_fs = require("fs");
|
|
41
|
+
var import_node_path = __toESM(require("path"));
|
|
42
|
+
var import_node_crypto = __toESM(require("crypto"));
|
|
43
|
+
function createLocalAdapter(options = {}) {
|
|
44
|
+
if (process.env["NODE_ENV"] === "production") {
|
|
45
|
+
console.warn(
|
|
46
|
+
"\u26A0 Warning: Local storage adapter is not recommended for production.\n Files will not persist across container restarts or serverless invocations.\n Consider createS3Adapter() or createCloudinaryAdapter() for production."
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
const upload_dir = options.upload_dir ?? "./uploads";
|
|
50
|
+
const pending = /* @__PURE__ */ new Map();
|
|
51
|
+
return {
|
|
52
|
+
type: "local",
|
|
53
|
+
async getPresignedUploadUrl(opts) {
|
|
54
|
+
const raw_ext = import_node_path.default.extname(opts.filename);
|
|
55
|
+
const ext = raw_ext.startsWith(".") ? raw_ext.slice(1) : raw_ext;
|
|
56
|
+
const uuid = import_node_crypto.default.randomUUID();
|
|
57
|
+
const key = ext ? `${opts.folder}/${uuid}.${ext}` : `${opts.folder}/${uuid}`;
|
|
58
|
+
const token = import_node_crypto.default.randomUUID();
|
|
59
|
+
const expires_in = opts.expires_in ?? 3600;
|
|
60
|
+
const expires_at = Math.floor(Date.now() / 1e3) + expires_in;
|
|
61
|
+
pending.set(token, { key, expires_at, folder: opts.folder });
|
|
62
|
+
return {
|
|
63
|
+
upload_url: `http://localhost:3000/_local_upload/${key}?token=${token}`,
|
|
64
|
+
key,
|
|
65
|
+
expires_at
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
getUrl(key) {
|
|
69
|
+
return `http://localhost:3000/uploads/${key}`;
|
|
70
|
+
},
|
|
71
|
+
async upload(key, data) {
|
|
72
|
+
const filepath = import_node_path.default.join(upload_dir, key);
|
|
73
|
+
await import_node_fs.promises.mkdir(import_node_path.default.dirname(filepath), { recursive: true });
|
|
74
|
+
await import_node_fs.promises.writeFile(filepath, data);
|
|
75
|
+
},
|
|
76
|
+
async delete(key) {
|
|
77
|
+
const normalizedKey = key.startsWith("uploads/") ? key.slice("uploads/".length) : key;
|
|
78
|
+
const filepath = import_node_path.default.join(upload_dir, normalizedKey);
|
|
79
|
+
try {
|
|
80
|
+
await import_node_fs.promises.unlink(filepath);
|
|
81
|
+
} catch (err) {
|
|
82
|
+
if (err.code !== "ENOENT") {
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
async stat(key) {
|
|
88
|
+
const filepath = import_node_path.default.join(upload_dir, key.startsWith("uploads/") ? key.slice("uploads/".length) : key);
|
|
89
|
+
try {
|
|
90
|
+
const s = await import_node_fs.promises.stat(filepath);
|
|
91
|
+
return { size: s.size };
|
|
92
|
+
} catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/storage/adapters/s3.ts
|
|
100
|
+
var import_node_path2 = __toESM(require("path"));
|
|
101
|
+
var import_node_crypto2 = __toESM(require("crypto"));
|
|
102
|
+
var import_client_s3 = require("@aws-sdk/client-s3");
|
|
103
|
+
var import_s3_request_presigner = require("@aws-sdk/s3-request-presigner");
|
|
104
|
+
function createS3Adapter(options) {
|
|
105
|
+
const { bucket, region, prefix, access_key_id, secret_access_key } = options;
|
|
106
|
+
const client = new import_client_s3.S3Client({
|
|
107
|
+
region,
|
|
108
|
+
// AWS SDK v3 (>= ~3.729) adds a CRC32 checksum to PutObject by default. For
|
|
109
|
+
// presigned URLs that bakes the *empty-body* checksum into the signed URL,
|
|
110
|
+
// so the browser's real upload fails the check with 403. Only checksum when
|
|
111
|
+
// an operation actually requires it, which excludes presigned PUTs.
|
|
112
|
+
requestChecksumCalculation: "WHEN_REQUIRED",
|
|
113
|
+
// Only override credentials when explicitly configured. Otherwise fall back
|
|
114
|
+
// to the SDK's default provider chain, which resolves the Lambda/Fargate
|
|
115
|
+
// execution role *including the AWS_SESSION_TOKEN that temporary credentials
|
|
116
|
+
// require*. Hand-reading only AWS_ACCESS_KEY_ID/SECRET dropped the session
|
|
117
|
+
// token, so presigned URLs 403'd on Lambda (works on Fargate, whose role
|
|
118
|
+
// credentials don't arrive via those env vars).
|
|
119
|
+
...access_key_id && secret_access_key ? { credentials: { accessKeyId: access_key_id, secretAccessKey: secret_access_key } } : {}
|
|
120
|
+
});
|
|
121
|
+
return {
|
|
122
|
+
type: "s3",
|
|
123
|
+
async getPresignedUploadUrl(opts) {
|
|
124
|
+
const raw_ext = import_node_path2.default.extname(opts.filename);
|
|
125
|
+
const ext = raw_ext.startsWith(".") ? raw_ext.slice(1) : raw_ext;
|
|
126
|
+
const uuid = import_node_crypto2.default.randomUUID();
|
|
127
|
+
const segment = ext ? `${uuid}.${ext}` : uuid;
|
|
128
|
+
const parts = [prefix, opts.folder, segment].filter(Boolean);
|
|
129
|
+
const key = parts.join("/");
|
|
130
|
+
const expires_in = opts.expires_in ?? 3600;
|
|
131
|
+
const expires_at = Math.floor(Date.now() / 1e3) + expires_in;
|
|
132
|
+
const command = new import_client_s3.PutObjectCommand({
|
|
133
|
+
Bucket: bucket,
|
|
134
|
+
Key: key,
|
|
135
|
+
ContentType: opts.mime_type
|
|
136
|
+
});
|
|
137
|
+
const upload_url = await (0, import_s3_request_presigner.getSignedUrl)(client, command, { expiresIn: expires_in });
|
|
138
|
+
return { upload_url, key, expires_at };
|
|
139
|
+
},
|
|
140
|
+
getUrl(key) {
|
|
141
|
+
return `https://${bucket}.s3.${region}.amazonaws.com/${key}`;
|
|
142
|
+
},
|
|
143
|
+
async upload(key, data, mimeType) {
|
|
144
|
+
const command = new import_client_s3.PutObjectCommand({
|
|
145
|
+
Bucket: bucket,
|
|
146
|
+
Key: key,
|
|
147
|
+
Body: data,
|
|
148
|
+
ContentType: mimeType
|
|
149
|
+
});
|
|
150
|
+
await client.send(command);
|
|
151
|
+
},
|
|
152
|
+
async delete(key) {
|
|
153
|
+
const command = new import_client_s3.DeleteObjectCommand({ Bucket: bucket, Key: key });
|
|
154
|
+
await client.send(command);
|
|
155
|
+
},
|
|
156
|
+
async stat(key) {
|
|
157
|
+
try {
|
|
158
|
+
const head = await client.send(new import_client_s3.HeadObjectCommand({ Bucket: bucket, Key: key }));
|
|
159
|
+
return {
|
|
160
|
+
size: head.ContentLength ?? 0,
|
|
161
|
+
...head.ContentType !== void 0 && { content_type: head.ContentType }
|
|
162
|
+
};
|
|
163
|
+
} catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
getUploadOrigins() {
|
|
168
|
+
return [`https://${bucket}.s3.${region}.amazonaws.com`];
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// src/storage/adapters/cloudinary.ts
|
|
174
|
+
var import_node_crypto3 = __toESM(require("crypto"));
|
|
175
|
+
function toCloudinaryResourceType(folder) {
|
|
176
|
+
if (folder === "video") return "video";
|
|
177
|
+
if (folder === "file") return "raw";
|
|
178
|
+
return "image";
|
|
179
|
+
}
|
|
180
|
+
function resourceTypeFromKey(key) {
|
|
181
|
+
for (const part of key.split("/")) {
|
|
182
|
+
if (part === "video") return "video";
|
|
183
|
+
if (part === "file") return "raw";
|
|
184
|
+
}
|
|
185
|
+
return "image";
|
|
186
|
+
}
|
|
187
|
+
function signParams(params, secret) {
|
|
188
|
+
const to_sign = Object.keys(params).sort().map((k) => `${k}=${params[k]}`).join("&");
|
|
189
|
+
return import_node_crypto3.default.createHash("sha1").update(to_sign + secret).digest("hex");
|
|
190
|
+
}
|
|
191
|
+
function createCloudinaryAdapter(options = {}) {
|
|
192
|
+
const cloud_name = options.cloud_name ?? process.env["CLOUDINARY_CLOUD_NAME"] ?? "";
|
|
193
|
+
const folder_prefix = options.folder;
|
|
194
|
+
const access_key_id = options.access_key_id ?? process.env["CLOUDINARY_API_KEY"] ?? "";
|
|
195
|
+
const secret_access_key = options.secret_access_key ?? process.env["CLOUDINARY_API_SECRET"] ?? "";
|
|
196
|
+
return {
|
|
197
|
+
type: "cloudinary",
|
|
198
|
+
async getPresignedUploadUrl(opts) {
|
|
199
|
+
const uuid = import_node_crypto3.default.randomUUID();
|
|
200
|
+
const public_id_parts = [folder_prefix, opts.folder, uuid].filter(Boolean);
|
|
201
|
+
const public_id = public_id_parts.join("/");
|
|
202
|
+
const key = public_id;
|
|
203
|
+
const expires_in = opts.expires_in ?? 3600;
|
|
204
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
205
|
+
const expires_at = timestamp + expires_in;
|
|
206
|
+
const params_to_sign = {
|
|
207
|
+
public_id,
|
|
208
|
+
timestamp
|
|
209
|
+
};
|
|
210
|
+
const signature = signParams(params_to_sign, secret_access_key);
|
|
211
|
+
const resource_type = toCloudinaryResourceType(opts.folder);
|
|
212
|
+
const upload_url = `https://api.cloudinary.com/v1_1/${cloud_name}/${resource_type}/upload`;
|
|
213
|
+
return {
|
|
214
|
+
upload_url,
|
|
215
|
+
key,
|
|
216
|
+
expires_at,
|
|
217
|
+
method: "POST",
|
|
218
|
+
fields: {
|
|
219
|
+
public_id,
|
|
220
|
+
timestamp: String(timestamp),
|
|
221
|
+
signature,
|
|
222
|
+
api_key: access_key_id
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
},
|
|
226
|
+
getUrl(key) {
|
|
227
|
+
const resource_type = resourceTypeFromKey(key);
|
|
228
|
+
return `https://res.cloudinary.com/${cloud_name}/${resource_type}/upload/${key}`;
|
|
229
|
+
},
|
|
230
|
+
async upload(key, data, mimeType) {
|
|
231
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
232
|
+
const params_to_sign = { public_id: key, timestamp };
|
|
233
|
+
const signature = signParams(params_to_sign, secret_access_key);
|
|
234
|
+
const resource_type = resourceTypeFromKey(key);
|
|
235
|
+
const form = new FormData();
|
|
236
|
+
form.append("file", new Blob([new Uint8Array(data)], { type: mimeType }), "upload");
|
|
237
|
+
form.append("public_id", key);
|
|
238
|
+
form.append("timestamp", String(timestamp));
|
|
239
|
+
form.append("api_key", access_key_id);
|
|
240
|
+
form.append("signature", signature);
|
|
241
|
+
const res = await fetch(
|
|
242
|
+
`https://api.cloudinary.com/v1_1/${cloud_name}/${resource_type}/upload`,
|
|
243
|
+
{ method: "POST", body: form }
|
|
244
|
+
);
|
|
245
|
+
if (!res.ok) {
|
|
246
|
+
const text = await res.text();
|
|
247
|
+
throw new Error(`Cloudinary upload failed: ${res.status} ${res.statusText} \u2014 ${text}`);
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
async delete(key) {
|
|
251
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
252
|
+
const params_to_sign = {
|
|
253
|
+
public_id: key,
|
|
254
|
+
timestamp
|
|
255
|
+
};
|
|
256
|
+
const signature = signParams(params_to_sign, secret_access_key);
|
|
257
|
+
const resource_type = resourceTypeFromKey(key);
|
|
258
|
+
const endpoint = `https://api.cloudinary.com/v1_1/${cloud_name}/${resource_type}/destroy`;
|
|
259
|
+
const body = new URLSearchParams({
|
|
260
|
+
public_id: key,
|
|
261
|
+
signature,
|
|
262
|
+
timestamp: String(timestamp),
|
|
263
|
+
api_key: access_key_id
|
|
264
|
+
});
|
|
265
|
+
const res = await fetch(endpoint, {
|
|
266
|
+
method: "POST",
|
|
267
|
+
body,
|
|
268
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" }
|
|
269
|
+
});
|
|
270
|
+
const json = await res.json();
|
|
271
|
+
if (json.result === "ok" || json.result === "not found") return;
|
|
272
|
+
throw new Error(
|
|
273
|
+
`Cloudinary delete failed: ${json.error?.message ?? json.result ?? res.statusText}`
|
|
274
|
+
);
|
|
275
|
+
},
|
|
276
|
+
getUploadOrigins() {
|
|
277
|
+
return ["https://api.cloudinary.com"];
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
282
|
+
0 && (module.exports = {
|
|
283
|
+
createCloudinaryAdapter,
|
|
284
|
+
createLocalAdapter,
|
|
285
|
+
createS3Adapter
|
|
286
|
+
});
|
|
287
|
+
//# sourceMappingURL=index.js.map
|