@edgestore/server 0.3.3 → 0.5.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/README.md +3 -3
- package/adapters/astro/index.d.ts +1 -0
- package/adapters/astro/index.js +1 -0
- package/adapters/fastify/index.d.ts +1 -0
- package/adapters/fastify/index.js +1 -0
- package/adapters/hono/index.d.ts +1 -0
- package/adapters/hono/index.js +1 -0
- package/adapters/remix/index.d.ts +1 -0
- package/adapters/remix/index.js +1 -0
- package/dist/adapters/astro/index.d.ts +14 -0
- package/dist/adapters/astro/index.d.ts.map +1 -0
- package/dist/adapters/astro/index.js +183 -0
- package/dist/adapters/astro/index.mjs +179 -0
- package/dist/adapters/express/index.js +4 -4
- package/dist/adapters/express/index.mjs +4 -4
- package/dist/adapters/fastify/index.d.ts +18 -0
- package/dist/adapters/fastify/index.d.ts.map +1 -0
- package/dist/adapters/fastify/index.js +147 -0
- package/dist/adapters/fastify/index.mjs +143 -0
- package/dist/adapters/hono/index.d.ts +82 -0
- package/dist/adapters/hono/index.d.ts.map +1 -0
- package/dist/adapters/hono/index.js +137 -0
- package/dist/adapters/hono/index.mjs +133 -0
- package/dist/adapters/next/app/index.js +4 -4
- package/dist/adapters/next/app/index.mjs +4 -4
- package/dist/adapters/next/pages/index.js +4 -4
- package/dist/adapters/next/pages/index.mjs +4 -4
- package/dist/adapters/remix/index.d.ts +18 -0
- package/dist/adapters/remix/index.d.ts.map +1 -0
- package/dist/adapters/remix/index.js +158 -0
- package/dist/adapters/remix/index.mjs +154 -0
- package/dist/adapters/shared.d.ts +2 -0
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/start/index.d.ts.map +1 -1
- package/dist/adapters/start/index.js +4 -4
- package/dist/adapters/start/index.mjs +4 -4
- package/dist/core/client/index.d.ts +1 -1
- package/dist/core/client/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -3
- package/dist/core/index.mjs +4 -4
- package/dist/core/sdk/index.d.ts +4 -4
- package/dist/core/sdk/index.d.ts.map +1 -1
- package/dist/{index-28efdacf.mjs → index-2848cb40.mjs} +4 -3
- package/dist/{index-beed799d.js → index-421c502f.js} +4 -3
- package/dist/{index-4491caf0.js → index-7b259533.js} +6 -5
- package/dist/libs/logger.d.ts +1 -1
- package/dist/libs/logger.d.ts.map +1 -1
- package/dist/providers/aws/index.d.ts.map +1 -1
- package/dist/providers/aws/index.js +7 -2
- package/dist/providers/aws/index.mjs +7 -2
- package/dist/providers/azure/index.d.ts.map +1 -1
- package/dist/providers/azure/index.js +6 -1
- package/dist/providers/azure/index.mjs +6 -1
- package/dist/providers/edgestore/index.d.ts.map +1 -1
- package/dist/providers/edgestore/index.js +13 -6
- package/dist/providers/edgestore/index.mjs +10 -3
- package/dist/{shared-83f288f6.js → shared-25dbfab4.js} +19 -6
- package/dist/{shared-039276af.mjs → shared-4b199b96.mjs} +17 -5
- package/dist/{shared-7c700083.js → shared-685c8a0c.js} +18 -4
- package/dist/{utils-5819d5e1.js → utils-0aab6e3b.js} +3 -1
- package/dist/{utils-f6f56d38.mjs → utils-7349adab.mjs} +3 -1
- package/dist/{utils-461a2e3b.js → utils-b3d35894.js} +3 -2
- package/package.json +31 -8
- package/src/adapters/astro/index.ts +222 -0
- package/src/adapters/express/index.ts +1 -1
- package/src/adapters/fastify/index.ts +205 -0
- package/src/adapters/hono/index.ts +195 -0
- package/src/adapters/next/app/index.ts +1 -1
- package/src/adapters/next/pages/index.ts +1 -1
- package/src/adapters/remix/index.ts +201 -0
- package/src/adapters/shared.ts +21 -4
- package/src/adapters/start/index.ts +1 -1
- package/src/core/client/index.ts +11 -3
- package/src/core/sdk/index.ts +4 -3
- package/src/libs/errors/EdgeStoreCredentialsError.ts +1 -1
- package/src/libs/logger.ts +4 -3
- package/src/providers/aws/index.ts +8 -7
- package/src/providers/azure/index.ts +5 -4
- package/src/providers/edgestore/index.ts +8 -3
- package/adapters/index.d.ts +0 -1
- package/adapters/index.js +0 -1
- package/providers/index.d.ts +0 -1
- package/providers/index.js +0 -1
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EDGE_STORE_ERROR_CODES,
|
|
3
|
+
EdgeStoreError,
|
|
4
|
+
type EdgeStoreErrorCodeKey,
|
|
5
|
+
type EdgeStoreRouter,
|
|
6
|
+
type MaybePromise,
|
|
7
|
+
type Provider,
|
|
8
|
+
} from '@edgestore/shared';
|
|
9
|
+
import type { APIContext } from 'astro';
|
|
10
|
+
import Logger, { type LogLevel } from '../../libs/logger';
|
|
11
|
+
import { matchPath } from '../../libs/utils';
|
|
12
|
+
import { EdgeStoreProvider } from '../../providers/edgestore';
|
|
13
|
+
import {
|
|
14
|
+
completeMultipartUpload,
|
|
15
|
+
confirmUpload,
|
|
16
|
+
deleteFile,
|
|
17
|
+
init,
|
|
18
|
+
requestUpload,
|
|
19
|
+
requestUploadParts,
|
|
20
|
+
type CompleteMultipartUploadBody,
|
|
21
|
+
type ConfirmUploadBody,
|
|
22
|
+
type DeleteFileBody,
|
|
23
|
+
type RequestUploadBody,
|
|
24
|
+
type RequestUploadPartsParams,
|
|
25
|
+
} from '../shared';
|
|
26
|
+
|
|
27
|
+
export type Config<TCtx> = {
|
|
28
|
+
provider?: Provider;
|
|
29
|
+
router: EdgeStoreRouter<TCtx>;
|
|
30
|
+
logLevel?: LogLevel;
|
|
31
|
+
} & (TCtx extends Record<string, never>
|
|
32
|
+
? object
|
|
33
|
+
: {
|
|
34
|
+
provider?: Provider;
|
|
35
|
+
router: EdgeStoreRouter<TCtx>;
|
|
36
|
+
createContext: (opts: APIContext) => MaybePromise<TCtx>;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
declare const globalThis: {
|
|
40
|
+
_EDGE_STORE_LOGGER: Logger;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Helper to safely get cookies from Astro request
|
|
44
|
+
function getCookie(request: Request, name: string): string | undefined {
|
|
45
|
+
const cookieHeader = request.headers.get('cookie');
|
|
46
|
+
if (!cookieHeader) return undefined;
|
|
47
|
+
|
|
48
|
+
const cookies = cookieHeader
|
|
49
|
+
.split(';')
|
|
50
|
+
.reduce<Record<string, string>>((acc, cookie) => {
|
|
51
|
+
const [key, value] = cookie.trim().split('=');
|
|
52
|
+
if (key && value) acc[key] = value;
|
|
53
|
+
return acc;
|
|
54
|
+
}, {});
|
|
55
|
+
|
|
56
|
+
return cookies[name];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function createEdgeStoreAstroHandler<TCtx>(config: Config<TCtx>) {
|
|
60
|
+
const { provider = EdgeStoreProvider() } = config;
|
|
61
|
+
const log = new Logger(config.logLevel);
|
|
62
|
+
globalThis._EDGE_STORE_LOGGER = log;
|
|
63
|
+
log.debug('Creating EdgeStore Astro handler');
|
|
64
|
+
|
|
65
|
+
return async (context: APIContext) => {
|
|
66
|
+
try {
|
|
67
|
+
const { request } = context;
|
|
68
|
+
const url = new URL(request.url);
|
|
69
|
+
|
|
70
|
+
if (matchPath(url.pathname, 'health')) {
|
|
71
|
+
return new Response('OK');
|
|
72
|
+
} else if (matchPath(url.pathname, 'init')) {
|
|
73
|
+
let ctx = {} as TCtx;
|
|
74
|
+
try {
|
|
75
|
+
ctx =
|
|
76
|
+
'createContext' in config
|
|
77
|
+
? await config.createContext(context)
|
|
78
|
+
: ({} as TCtx);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
throw new EdgeStoreError({
|
|
81
|
+
message: 'Error creating context',
|
|
82
|
+
code: 'CREATE_CONTEXT_ERROR',
|
|
83
|
+
cause: err instanceof Error ? err : undefined,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const { newCookies, token, baseUrl } = await init({
|
|
87
|
+
ctx,
|
|
88
|
+
provider,
|
|
89
|
+
router: config.router,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const headers = new Headers();
|
|
93
|
+
headers.set('Content-Type', 'application/json');
|
|
94
|
+
|
|
95
|
+
// Set cookies
|
|
96
|
+
if (Array.isArray(newCookies)) {
|
|
97
|
+
for (const cookie of newCookies) {
|
|
98
|
+
headers.append('Set-Cookie', cookie);
|
|
99
|
+
}
|
|
100
|
+
} else if (newCookies) {
|
|
101
|
+
headers.append('Set-Cookie', newCookies);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return new Response(
|
|
105
|
+
JSON.stringify({
|
|
106
|
+
token,
|
|
107
|
+
baseUrl,
|
|
108
|
+
}),
|
|
109
|
+
{ headers },
|
|
110
|
+
);
|
|
111
|
+
} else if (matchPath(url.pathname, 'request-upload')) {
|
|
112
|
+
const body = (await request.json()) as RequestUploadBody;
|
|
113
|
+
const result = await requestUpload({
|
|
114
|
+
provider,
|
|
115
|
+
router: config.router,
|
|
116
|
+
body,
|
|
117
|
+
ctxToken: getCookie(request, 'edgestore-ctx'),
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return new Response(JSON.stringify(result), {
|
|
121
|
+
headers: { 'Content-Type': 'application/json' },
|
|
122
|
+
});
|
|
123
|
+
} else if (matchPath(url.pathname, 'request-upload-parts')) {
|
|
124
|
+
const body = (await request.json()) as RequestUploadPartsParams;
|
|
125
|
+
const result = await requestUploadParts({
|
|
126
|
+
provider,
|
|
127
|
+
router: config.router,
|
|
128
|
+
body,
|
|
129
|
+
ctxToken: getCookie(request, 'edgestore-ctx'),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return new Response(JSON.stringify(result), {
|
|
133
|
+
headers: { 'Content-Type': 'application/json' },
|
|
134
|
+
});
|
|
135
|
+
} else if (matchPath(url.pathname, 'complete-multipart-upload')) {
|
|
136
|
+
const body = (await request.json()) as CompleteMultipartUploadBody;
|
|
137
|
+
await completeMultipartUpload({
|
|
138
|
+
provider,
|
|
139
|
+
router: config.router,
|
|
140
|
+
body,
|
|
141
|
+
ctxToken: getCookie(request, 'edgestore-ctx'),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return new Response(null, { status: 200 });
|
|
145
|
+
} else if (matchPath(url.pathname, 'confirm-upload')) {
|
|
146
|
+
const body = (await request.json()) as ConfirmUploadBody;
|
|
147
|
+
const result = await confirmUpload({
|
|
148
|
+
provider,
|
|
149
|
+
router: config.router,
|
|
150
|
+
body,
|
|
151
|
+
ctxToken: getCookie(request, 'edgestore-ctx'),
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
return new Response(JSON.stringify(result), {
|
|
155
|
+
headers: { 'Content-Type': 'application/json' },
|
|
156
|
+
});
|
|
157
|
+
} else if (matchPath(url.pathname, 'delete-file')) {
|
|
158
|
+
const body = (await request.json()) as DeleteFileBody;
|
|
159
|
+
const result = await deleteFile({
|
|
160
|
+
provider,
|
|
161
|
+
router: config.router,
|
|
162
|
+
body,
|
|
163
|
+
ctxToken: getCookie(request, 'edgestore-ctx'),
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
return new Response(JSON.stringify(result), {
|
|
167
|
+
headers: { 'Content-Type': 'application/json' },
|
|
168
|
+
});
|
|
169
|
+
} else if (matchPath(url.pathname, 'proxy-file')) {
|
|
170
|
+
const url = new URL(request.url).searchParams.get('url');
|
|
171
|
+
|
|
172
|
+
if (typeof url === 'string') {
|
|
173
|
+
const cookieHeader = request.headers.get('cookie') ?? '';
|
|
174
|
+
|
|
175
|
+
const proxyRes = await fetch(url, {
|
|
176
|
+
headers: {
|
|
177
|
+
cookie: cookieHeader,
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const data = await proxyRes.arrayBuffer();
|
|
182
|
+
const headers = new Headers();
|
|
183
|
+
headers.set(
|
|
184
|
+
'Content-Type',
|
|
185
|
+
proxyRes.headers.get('Content-Type') ?? 'application/octet-stream',
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
return new Response(data, { headers });
|
|
189
|
+
} else {
|
|
190
|
+
return new Response(null, { status: 400 });
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
return new Response(null, { status: 404 });
|
|
194
|
+
}
|
|
195
|
+
} catch (err) {
|
|
196
|
+
if (err instanceof EdgeStoreError) {
|
|
197
|
+
log[err.level](err.formattedMessage());
|
|
198
|
+
if (err.cause) log[err.level](err.cause);
|
|
199
|
+
|
|
200
|
+
return new Response(JSON.stringify(err.formattedJson()), {
|
|
201
|
+
status: EDGE_STORE_ERROR_CODES[err.code as EdgeStoreErrorCodeKey],
|
|
202
|
+
headers: { 'Content-Type': 'application/json' },
|
|
203
|
+
});
|
|
204
|
+
} else {
|
|
205
|
+
log.error(err);
|
|
206
|
+
|
|
207
|
+
return new Response(
|
|
208
|
+
JSON.stringify(
|
|
209
|
+
new EdgeStoreError({
|
|
210
|
+
message: 'Internal Server Error',
|
|
211
|
+
code: 'SERVER_ERROR',
|
|
212
|
+
}).formattedJson(),
|
|
213
|
+
),
|
|
214
|
+
{
|
|
215
|
+
status: 500,
|
|
216
|
+
headers: { 'Content-Type': 'application/json' },
|
|
217
|
+
},
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
@@ -49,7 +49,7 @@ export function createEdgeStoreExpressHandler<TCtx>(config: Config<TCtx>) {
|
|
|
49
49
|
const { provider = EdgeStoreProvider() } = config;
|
|
50
50
|
const log = new Logger(config.logLevel);
|
|
51
51
|
globalThis._EDGE_STORE_LOGGER = log;
|
|
52
|
-
log.debug('Creating
|
|
52
|
+
log.debug('Creating EdgeStore Express handler');
|
|
53
53
|
|
|
54
54
|
return async (req: Request, res: Response) => {
|
|
55
55
|
try {
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EDGE_STORE_ERROR_CODES,
|
|
3
|
+
EdgeStoreError,
|
|
4
|
+
type EdgeStoreErrorCodeKey,
|
|
5
|
+
type EdgeStoreRouter,
|
|
6
|
+
type MaybePromise,
|
|
7
|
+
type Provider,
|
|
8
|
+
} from '@edgestore/shared';
|
|
9
|
+
import { type FastifyRequest, type FastifyReply } from 'fastify';
|
|
10
|
+
import Logger, { type LogLevel } from '../../libs/logger';
|
|
11
|
+
import { matchPath } from '../../libs/utils';
|
|
12
|
+
import { EdgeStoreProvider } from '../../providers/edgestore';
|
|
13
|
+
import {
|
|
14
|
+
completeMultipartUpload,
|
|
15
|
+
confirmUpload,
|
|
16
|
+
deleteFile,
|
|
17
|
+
init,
|
|
18
|
+
requestUpload,
|
|
19
|
+
requestUploadParts,
|
|
20
|
+
type CompleteMultipartUploadBody,
|
|
21
|
+
type ConfirmUploadBody,
|
|
22
|
+
type DeleteFileBody,
|
|
23
|
+
type RequestUploadBody,
|
|
24
|
+
type RequestUploadPartsParams,
|
|
25
|
+
} from '../shared';
|
|
26
|
+
|
|
27
|
+
export type CreateContextOptions = {
|
|
28
|
+
req: FastifyRequest;
|
|
29
|
+
reply: FastifyReply;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type Config<TCtx> = {
|
|
33
|
+
provider?: Provider;
|
|
34
|
+
router: EdgeStoreRouter<TCtx>;
|
|
35
|
+
logLevel?: LogLevel;
|
|
36
|
+
} & (TCtx extends Record<string, never>
|
|
37
|
+
? object
|
|
38
|
+
: {
|
|
39
|
+
provider?: Provider;
|
|
40
|
+
router: EdgeStoreRouter<TCtx>;
|
|
41
|
+
createContext: (opts: CreateContextOptions) => MaybePromise<TCtx>;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
declare const globalThis: {
|
|
45
|
+
_EDGE_STORE_LOGGER: Logger;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Helper to safely get cookies from Fastify request
|
|
49
|
+
function getCookie(req: FastifyRequest, name: string): string | undefined {
|
|
50
|
+
// Check if cookies plugin is available
|
|
51
|
+
if ('cookies' in req) {
|
|
52
|
+
// Type assertion for TypeScript
|
|
53
|
+
return (req as any).cookies[name];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Fallback to parsing cookie header
|
|
57
|
+
const cookieHeader = req.headers.cookie;
|
|
58
|
+
if (!cookieHeader) return undefined;
|
|
59
|
+
|
|
60
|
+
const cookies = cookieHeader.split(';').reduce<Record<string, string>>((acc, cookie) => {
|
|
61
|
+
const [key, value] = cookie.trim().split('=');
|
|
62
|
+
if (key && value) acc[key] = value;
|
|
63
|
+
return acc;
|
|
64
|
+
}, {});
|
|
65
|
+
|
|
66
|
+
return cookies[name];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function createEdgeStoreFastifyHandler<TCtx>(config: Config<TCtx>) {
|
|
70
|
+
const { provider = EdgeStoreProvider() } = config;
|
|
71
|
+
const log = new Logger(config.logLevel);
|
|
72
|
+
globalThis._EDGE_STORE_LOGGER = log;
|
|
73
|
+
log.debug('Creating EdgeStore Fastify handler');
|
|
74
|
+
|
|
75
|
+
return async (req: FastifyRequest, reply: FastifyReply) => {
|
|
76
|
+
try {
|
|
77
|
+
// Get the URL from the request - simplified approach
|
|
78
|
+
const pathname = req.url;
|
|
79
|
+
|
|
80
|
+
if (matchPath(pathname, '/health')) {
|
|
81
|
+
return reply.send('OK');
|
|
82
|
+
} else if (matchPath(pathname, '/init')) {
|
|
83
|
+
let ctx = {} as TCtx;
|
|
84
|
+
try {
|
|
85
|
+
ctx =
|
|
86
|
+
'createContext' in config
|
|
87
|
+
? await config.createContext({ req, reply })
|
|
88
|
+
: ({} as TCtx);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
throw new EdgeStoreError({
|
|
91
|
+
message: 'Error creating context',
|
|
92
|
+
code: 'CREATE_CONTEXT_ERROR',
|
|
93
|
+
cause: err instanceof Error ? err : undefined,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const { newCookies, token, baseUrl } = await init({
|
|
97
|
+
ctx,
|
|
98
|
+
provider,
|
|
99
|
+
router: config.router,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Set cookies more efficiently - handling them using void operator
|
|
103
|
+
// to explicitly mark these synchronous calls as intentionally not awaited
|
|
104
|
+
if (Array.isArray(newCookies)) {
|
|
105
|
+
// If it's an array of cookies, set them all
|
|
106
|
+
for (const cookie of newCookies) {
|
|
107
|
+
void reply.header('Set-Cookie', cookie);
|
|
108
|
+
}
|
|
109
|
+
} else if (newCookies) {
|
|
110
|
+
// If it's a single cookie string
|
|
111
|
+
void reply.header('Set-Cookie', newCookies);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return reply.send({
|
|
115
|
+
token,
|
|
116
|
+
baseUrl,
|
|
117
|
+
});
|
|
118
|
+
} else if (matchPath(pathname, '/request-upload')) {
|
|
119
|
+
return reply.send(
|
|
120
|
+
await requestUpload({
|
|
121
|
+
provider,
|
|
122
|
+
router: config.router,
|
|
123
|
+
body: req.body as RequestUploadBody,
|
|
124
|
+
ctxToken: getCookie(req, 'edgestore-ctx'),
|
|
125
|
+
}),
|
|
126
|
+
);
|
|
127
|
+
} else if (matchPath(pathname, '/request-upload-parts')) {
|
|
128
|
+
return reply.send(
|
|
129
|
+
await requestUploadParts({
|
|
130
|
+
provider,
|
|
131
|
+
router: config.router,
|
|
132
|
+
body: req.body as RequestUploadPartsParams,
|
|
133
|
+
ctxToken: getCookie(req, 'edgestore-ctx'),
|
|
134
|
+
}),
|
|
135
|
+
);
|
|
136
|
+
} else if (matchPath(pathname, '/complete-multipart-upload')) {
|
|
137
|
+
await completeMultipartUpload({
|
|
138
|
+
provider,
|
|
139
|
+
router: config.router,
|
|
140
|
+
body: req.body as CompleteMultipartUploadBody,
|
|
141
|
+
ctxToken: getCookie(req, 'edgestore-ctx'),
|
|
142
|
+
});
|
|
143
|
+
return reply.status(200).send();
|
|
144
|
+
} else if (matchPath(pathname, '/confirm-upload')) {
|
|
145
|
+
return reply.send(
|
|
146
|
+
await confirmUpload({
|
|
147
|
+
provider,
|
|
148
|
+
router: config.router,
|
|
149
|
+
body: req.body as ConfirmUploadBody,
|
|
150
|
+
ctxToken: getCookie(req, 'edgestore-ctx'),
|
|
151
|
+
}),
|
|
152
|
+
);
|
|
153
|
+
} else if (matchPath(pathname, '/delete-file')) {
|
|
154
|
+
return reply.send(
|
|
155
|
+
await deleteFile({
|
|
156
|
+
provider,
|
|
157
|
+
router: config.router,
|
|
158
|
+
body: req.body as DeleteFileBody,
|
|
159
|
+
ctxToken: getCookie(req, 'edgestore-ctx'),
|
|
160
|
+
}),
|
|
161
|
+
);
|
|
162
|
+
} else if (matchPath(pathname, '/proxy-file')) {
|
|
163
|
+
const url = req.query ? (req.query as Record<string, any>).url : undefined;
|
|
164
|
+
|
|
165
|
+
if (typeof url === 'string') {
|
|
166
|
+
const cookieHeader = req.headers.cookie ?? '';
|
|
167
|
+
|
|
168
|
+
const proxyRes = await fetch(url, {
|
|
169
|
+
headers: {
|
|
170
|
+
cookie: cookieHeader,
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const data = await proxyRes.arrayBuffer();
|
|
175
|
+
void reply.header(
|
|
176
|
+
'Content-Type',
|
|
177
|
+
proxyRes.headers.get('Content-Type') ?? 'application/octet-stream',
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
return reply.send(Buffer.from(data));
|
|
181
|
+
} else {
|
|
182
|
+
return reply.status(400).send();
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
return reply.status(404).send();
|
|
186
|
+
}
|
|
187
|
+
} catch (err) {
|
|
188
|
+
if (err instanceof EdgeStoreError) {
|
|
189
|
+
log[err.level](err.formattedMessage());
|
|
190
|
+
if (err.cause) log[err.level](err.cause);
|
|
191
|
+
return reply
|
|
192
|
+
.status(EDGE_STORE_ERROR_CODES[err.code as EdgeStoreErrorCodeKey])
|
|
193
|
+
.send(err.formattedJson());
|
|
194
|
+
} else {
|
|
195
|
+
log.error(err);
|
|
196
|
+
return reply.status(500).send(
|
|
197
|
+
new EdgeStoreError({
|
|
198
|
+
message: 'Internal Server Error',
|
|
199
|
+
code: 'SERVER_ERROR',
|
|
200
|
+
}).formattedJson(),
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EDGE_STORE_ERROR_CODES,
|
|
3
|
+
EdgeStoreError,
|
|
4
|
+
type EdgeStoreErrorCodeKey,
|
|
5
|
+
type EdgeStoreRouter,
|
|
6
|
+
type MaybePromise,
|
|
7
|
+
type Provider,
|
|
8
|
+
} from '@edgestore/shared';
|
|
9
|
+
import { type Context } from 'hono';
|
|
10
|
+
import Logger, { type LogLevel } from '../../libs/logger';
|
|
11
|
+
import { matchPath } from '../../libs/utils';
|
|
12
|
+
import { EdgeStoreProvider } from '../../providers/edgestore';
|
|
13
|
+
import {
|
|
14
|
+
completeMultipartUpload,
|
|
15
|
+
confirmUpload,
|
|
16
|
+
deleteFile,
|
|
17
|
+
init,
|
|
18
|
+
requestUpload,
|
|
19
|
+
requestUploadParts,
|
|
20
|
+
type CompleteMultipartUploadBody,
|
|
21
|
+
type ConfirmUploadBody,
|
|
22
|
+
type DeleteFileBody,
|
|
23
|
+
type RequestUploadBody,
|
|
24
|
+
type RequestUploadPartsParams,
|
|
25
|
+
} from '../shared';
|
|
26
|
+
|
|
27
|
+
export type CreateContextOptions = {
|
|
28
|
+
c: Context;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type Config<TCtx> = {
|
|
32
|
+
provider?: Provider;
|
|
33
|
+
router: EdgeStoreRouter<TCtx>;
|
|
34
|
+
logLevel?: LogLevel;
|
|
35
|
+
} & (TCtx extends Record<string, never>
|
|
36
|
+
? object
|
|
37
|
+
: {
|
|
38
|
+
provider?: Provider;
|
|
39
|
+
router: EdgeStoreRouter<TCtx>;
|
|
40
|
+
createContext: (opts: CreateContextOptions) => MaybePromise<TCtx>;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
declare const globalThis: {
|
|
44
|
+
_EDGE_STORE_LOGGER: Logger;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Helper to get a cookie value from Hono Context
|
|
48
|
+
function getCookie(c: Context, name: string): string | undefined {
|
|
49
|
+
const cookies = c.req.header('cookie');
|
|
50
|
+
if (!cookies) return undefined;
|
|
51
|
+
|
|
52
|
+
const match = new RegExp(`${name}=([^;]+)`).exec(cookies);
|
|
53
|
+
return match ? match[1] : undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function createEdgeStoreHonoHandler<TCtx>(config: Config<TCtx>) {
|
|
57
|
+
const { provider = EdgeStoreProvider() } = config;
|
|
58
|
+
const log = new Logger(config.logLevel);
|
|
59
|
+
globalThis._EDGE_STORE_LOGGER = log;
|
|
60
|
+
log.debug('Creating EdgeStore Hono handler');
|
|
61
|
+
|
|
62
|
+
return async (c: Context) => {
|
|
63
|
+
try {
|
|
64
|
+
const pathname = new URL(c.req.url).pathname;
|
|
65
|
+
|
|
66
|
+
if (matchPath(pathname, '/health')) {
|
|
67
|
+
return c.text('OK');
|
|
68
|
+
} else if (matchPath(pathname, '/init')) {
|
|
69
|
+
let ctx = {} as TCtx;
|
|
70
|
+
try {
|
|
71
|
+
ctx =
|
|
72
|
+
'createContext' in config
|
|
73
|
+
? await config.createContext({ c })
|
|
74
|
+
: ({} as TCtx);
|
|
75
|
+
} catch (err) {
|
|
76
|
+
throw new EdgeStoreError({
|
|
77
|
+
message: 'Error creating context',
|
|
78
|
+
code: 'CREATE_CONTEXT_ERROR',
|
|
79
|
+
cause: err instanceof Error ? err : undefined,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const { newCookies, token, baseUrl } = await init({
|
|
83
|
+
ctx,
|
|
84
|
+
provider,
|
|
85
|
+
router: config.router,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Set cookies
|
|
89
|
+
if (Array.isArray(newCookies)) {
|
|
90
|
+
for (const cookie of newCookies) {
|
|
91
|
+
c.header('Set-Cookie', cookie);
|
|
92
|
+
}
|
|
93
|
+
} else if (newCookies) {
|
|
94
|
+
c.header('Set-Cookie', newCookies);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return c.json({
|
|
98
|
+
token,
|
|
99
|
+
baseUrl,
|
|
100
|
+
});
|
|
101
|
+
} else if (matchPath(pathname, '/request-upload')) {
|
|
102
|
+
const body = await c.req.json<RequestUploadBody>();
|
|
103
|
+
return c.json(
|
|
104
|
+
await requestUpload({
|
|
105
|
+
provider,
|
|
106
|
+
router: config.router,
|
|
107
|
+
body,
|
|
108
|
+
ctxToken: getCookie(c, 'edgestore-ctx'),
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
111
|
+
} else if (matchPath(pathname, '/request-upload-parts')) {
|
|
112
|
+
const body = await c.req.json<RequestUploadPartsParams>();
|
|
113
|
+
return c.json(
|
|
114
|
+
await requestUploadParts({
|
|
115
|
+
provider,
|
|
116
|
+
router: config.router,
|
|
117
|
+
body,
|
|
118
|
+
ctxToken: getCookie(c, 'edgestore-ctx'),
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
} else if (matchPath(pathname, '/complete-multipart-upload')) {
|
|
122
|
+
const body = await c.req.json<CompleteMultipartUploadBody>();
|
|
123
|
+
await completeMultipartUpload({
|
|
124
|
+
provider,
|
|
125
|
+
router: config.router,
|
|
126
|
+
body,
|
|
127
|
+
ctxToken: getCookie(c, 'edgestore-ctx'),
|
|
128
|
+
});
|
|
129
|
+
return c.body(null, 200);
|
|
130
|
+
} else if (matchPath(pathname, '/confirm-upload')) {
|
|
131
|
+
const body = await c.req.json<ConfirmUploadBody>();
|
|
132
|
+
return c.json(
|
|
133
|
+
await confirmUpload({
|
|
134
|
+
provider,
|
|
135
|
+
router: config.router,
|
|
136
|
+
body,
|
|
137
|
+
ctxToken: getCookie(c, 'edgestore-ctx'),
|
|
138
|
+
}),
|
|
139
|
+
);
|
|
140
|
+
} else if (matchPath(pathname, '/delete-file')) {
|
|
141
|
+
const body = await c.req.json<DeleteFileBody>();
|
|
142
|
+
return c.json(
|
|
143
|
+
await deleteFile({
|
|
144
|
+
provider,
|
|
145
|
+
router: config.router,
|
|
146
|
+
body,
|
|
147
|
+
ctxToken: getCookie(c, 'edgestore-ctx'),
|
|
148
|
+
}),
|
|
149
|
+
);
|
|
150
|
+
} else if (matchPath(pathname, '/proxy-file')) {
|
|
151
|
+
const url = c.req.query('url');
|
|
152
|
+
|
|
153
|
+
if (typeof url === 'string') {
|
|
154
|
+
const cookieHeader = c.req.header('cookie') ?? '';
|
|
155
|
+
|
|
156
|
+
const proxyRes = await fetch(url, {
|
|
157
|
+
headers: {
|
|
158
|
+
cookie: cookieHeader,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const data = await proxyRes.arrayBuffer();
|
|
163
|
+
c.header(
|
|
164
|
+
'Content-Type',
|
|
165
|
+
proxyRes.headers.get('Content-Type') ?? 'application/octet-stream',
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
return c.body(Buffer.from(data));
|
|
169
|
+
} else {
|
|
170
|
+
return c.body(null, 400);
|
|
171
|
+
}
|
|
172
|
+
} else {
|
|
173
|
+
return c.body(null, 404);
|
|
174
|
+
}
|
|
175
|
+
} catch (err) {
|
|
176
|
+
if (err instanceof EdgeStoreError) {
|
|
177
|
+
log[err.level](err.formattedMessage());
|
|
178
|
+
if (err.cause) log[err.level](err.cause);
|
|
179
|
+
return c.json(
|
|
180
|
+
err.formattedJson(),
|
|
181
|
+
EDGE_STORE_ERROR_CODES[err.code as EdgeStoreErrorCodeKey],
|
|
182
|
+
);
|
|
183
|
+
} else {
|
|
184
|
+
log.error(err);
|
|
185
|
+
return c.json(
|
|
186
|
+
new EdgeStoreError({
|
|
187
|
+
message: 'Internal Server Error',
|
|
188
|
+
code: 'SERVER_ERROR',
|
|
189
|
+
}).formattedJson(),
|
|
190
|
+
500,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
@@ -48,7 +48,7 @@ export function createEdgeStoreNextHandler<TCtx>(config: Config<TCtx>) {
|
|
|
48
48
|
const { provider = EdgeStoreProvider() } = config;
|
|
49
49
|
const log = new Logger(config.logLevel);
|
|
50
50
|
globalThis._EDGE_STORE_LOGGER = log;
|
|
51
|
-
log.debug('Creating
|
|
51
|
+
log.debug('Creating EdgeStore Next handler (app adapter)');
|
|
52
52
|
|
|
53
53
|
return async (req: NextRequest) => {
|
|
54
54
|
try {
|
|
@@ -49,7 +49,7 @@ export function createEdgeStoreNextHandler<TCtx>(config: Config<TCtx>) {
|
|
|
49
49
|
const { provider = EdgeStoreProvider() } = config;
|
|
50
50
|
const log = new Logger(config.logLevel);
|
|
51
51
|
globalThis._EDGE_STORE_LOGGER = log;
|
|
52
|
-
log.debug('Creating
|
|
52
|
+
log.debug('Creating EdgeStore Next handler (pages adapter)');
|
|
53
53
|
|
|
54
54
|
return async (req: NextApiRequest, res: NextApiResponse) => {
|
|
55
55
|
try {
|