@edgestore/server 0.4.0 → 0.5.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/adapters/astro/index.d.ts +1 -0
- package/adapters/astro/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 +3 -3
- package/dist/adapters/express/index.mjs +3 -3
- package/dist/adapters/fastify/index.js +3 -3
- package/dist/adapters/fastify/index.mjs +3 -3
- 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 +3 -3
- package/dist/adapters/next/app/index.mjs +3 -3
- package/dist/adapters/next/pages/index.js +3 -3
- package/dist/adapters/next/pages/index.mjs +3 -3
- 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.js +3 -3
- package/dist/adapters/start/index.mjs +3 -3
- package/dist/core/index.js +3 -3
- package/dist/core/index.mjs +4 -4
- package/dist/core/sdk/index.d.ts.map +1 -1
- package/dist/{index-a7cc3cd3.mjs → index-2848cb40.mjs} +3 -2
- package/dist/{index-474a21c4.js → index-421c502f.js} +3 -2
- package/dist/{index-b689bf59.js → index-7b259533.js} +5 -4
- package/dist/libs/logger.d.ts +1 -1
- package/dist/libs/logger.d.ts.map +1 -1
- package/dist/providers/aws/index.d.ts +15 -1
- package/dist/providers/aws/index.d.ts.map +1 -1
- package/dist/providers/aws/index.js +28 -8
- package/dist/providers/aws/index.mjs +28 -8
- 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-d27101a7.js → shared-25dbfab4.js} +17 -4
- package/dist/{shared-c9442cbb.mjs → shared-4b199b96.mjs} +16 -4
- package/dist/{shared-6f6fd0bd.js → shared-685c8a0c.js} +17 -3
- 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 +20 -3
- package/src/adapters/astro/index.ts +222 -0
- package/src/adapters/hono/index.ts +195 -0
- package/src/adapters/remix/index.ts +201 -0
- package/src/adapters/shared.ts +20 -3
- package/src/core/client/index.ts +2 -2
- package/src/core/sdk/index.ts +4 -3
- package/src/libs/logger.ts +4 -3
- package/src/providers/aws/index.ts +66 -14
- 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,201 @@
|
|
|
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 Logger, { type LogLevel } from '../../libs/logger';
|
|
10
|
+
import { matchPath } from '../../libs/utils';
|
|
11
|
+
import { EdgeStoreProvider } from '../../providers/edgestore';
|
|
12
|
+
import {
|
|
13
|
+
completeMultipartUpload,
|
|
14
|
+
confirmUpload,
|
|
15
|
+
deleteFile,
|
|
16
|
+
init,
|
|
17
|
+
requestUpload,
|
|
18
|
+
requestUploadParts,
|
|
19
|
+
type CompleteMultipartUploadBody,
|
|
20
|
+
type ConfirmUploadBody,
|
|
21
|
+
type DeleteFileBody,
|
|
22
|
+
type RequestUploadBody,
|
|
23
|
+
type RequestUploadPartsParams,
|
|
24
|
+
} from '../shared';
|
|
25
|
+
|
|
26
|
+
export type CreateContextOptions = {
|
|
27
|
+
req: Request;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type Config<TCtx> = {
|
|
31
|
+
provider?: Provider;
|
|
32
|
+
router: EdgeStoreRouter<TCtx>;
|
|
33
|
+
logLevel?: LogLevel;
|
|
34
|
+
} & (TCtx extends Record<string, never>
|
|
35
|
+
? object
|
|
36
|
+
: {
|
|
37
|
+
provider?: Provider;
|
|
38
|
+
router: EdgeStoreRouter<TCtx>;
|
|
39
|
+
createContext: (opts: CreateContextOptions) => MaybePromise<TCtx>;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
declare const globalThis: {
|
|
43
|
+
_EDGE_STORE_LOGGER: Logger;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Helper to safely get cookies from Remix request
|
|
47
|
+
function getCookie(req: Request, name: string): string | undefined {
|
|
48
|
+
const cookieHeader = req.headers.get('cookie');
|
|
49
|
+
if (!cookieHeader) return undefined;
|
|
50
|
+
|
|
51
|
+
const cookies = cookieHeader
|
|
52
|
+
.split(';')
|
|
53
|
+
.reduce<Record<string, string>>((acc, cookie) => {
|
|
54
|
+
const [key, value] = cookie.trim().split('=');
|
|
55
|
+
if (key && value) acc[key] = value;
|
|
56
|
+
return acc;
|
|
57
|
+
}, {});
|
|
58
|
+
|
|
59
|
+
return cookies[name];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function createEdgeStoreRemixHandler<TCtx>(config: Config<TCtx>) {
|
|
63
|
+
const { provider = EdgeStoreProvider() } = config;
|
|
64
|
+
const log = new Logger(config.logLevel);
|
|
65
|
+
globalThis._EDGE_STORE_LOGGER = log;
|
|
66
|
+
log.debug('Creating EdgeStore Remix handler');
|
|
67
|
+
|
|
68
|
+
return async ({ request: req }: { request: Request }) => {
|
|
69
|
+
try {
|
|
70
|
+
const url = new URL(req.url);
|
|
71
|
+
const pathname = url.pathname;
|
|
72
|
+
|
|
73
|
+
if (matchPath(pathname, '/health')) {
|
|
74
|
+
return new Response('OK');
|
|
75
|
+
} else if (matchPath(pathname, '/init')) {
|
|
76
|
+
let ctx = {} as TCtx;
|
|
77
|
+
try {
|
|
78
|
+
ctx =
|
|
79
|
+
'createContext' in config
|
|
80
|
+
? await config.createContext({ req })
|
|
81
|
+
: ({} as TCtx);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
throw new EdgeStoreError({
|
|
84
|
+
message: 'Error creating context',
|
|
85
|
+
code: 'CREATE_CONTEXT_ERROR',
|
|
86
|
+
cause: err instanceof Error ? err : undefined,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const { newCookies, token, baseUrl } = await init({
|
|
90
|
+
ctx,
|
|
91
|
+
provider,
|
|
92
|
+
router: config.router,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Create response with cookies and token
|
|
96
|
+
const responseHeaders = new Headers();
|
|
97
|
+
|
|
98
|
+
if (Array.isArray(newCookies)) {
|
|
99
|
+
for (const cookie of newCookies) {
|
|
100
|
+
responseHeaders.append('Set-Cookie', cookie);
|
|
101
|
+
}
|
|
102
|
+
} else if (newCookies) {
|
|
103
|
+
responseHeaders.append('Set-Cookie', newCookies);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return new Response(JSON.stringify({ token, baseUrl }), {
|
|
107
|
+
headers: responseHeaders,
|
|
108
|
+
status: 200,
|
|
109
|
+
});
|
|
110
|
+
} else if (matchPath(pathname, '/request-upload')) {
|
|
111
|
+
const body = (await req.json()) as RequestUploadBody;
|
|
112
|
+
return Response.json(
|
|
113
|
+
await requestUpload({
|
|
114
|
+
provider,
|
|
115
|
+
router: config.router,
|
|
116
|
+
body,
|
|
117
|
+
ctxToken: getCookie(req, 'edgestore-ctx'),
|
|
118
|
+
}),
|
|
119
|
+
);
|
|
120
|
+
} else if (matchPath(pathname, '/request-upload-parts')) {
|
|
121
|
+
const body = (await req.json()) as RequestUploadPartsParams;
|
|
122
|
+
return Response.json(
|
|
123
|
+
await requestUploadParts({
|
|
124
|
+
provider,
|
|
125
|
+
router: config.router,
|
|
126
|
+
body,
|
|
127
|
+
ctxToken: getCookie(req, 'edgestore-ctx'),
|
|
128
|
+
}),
|
|
129
|
+
);
|
|
130
|
+
} else if (matchPath(pathname, '/complete-multipart-upload')) {
|
|
131
|
+
const body = (await req.json()) as CompleteMultipartUploadBody;
|
|
132
|
+
await completeMultipartUpload({
|
|
133
|
+
provider,
|
|
134
|
+
router: config.router,
|
|
135
|
+
body,
|
|
136
|
+
ctxToken: getCookie(req, 'edgestore-ctx'),
|
|
137
|
+
});
|
|
138
|
+
return new Response(null, { status: 200 });
|
|
139
|
+
} else if (matchPath(pathname, '/confirm-upload')) {
|
|
140
|
+
const body = (await req.json()) as ConfirmUploadBody;
|
|
141
|
+
return Response.json(
|
|
142
|
+
await confirmUpload({
|
|
143
|
+
provider,
|
|
144
|
+
router: config.router,
|
|
145
|
+
body,
|
|
146
|
+
ctxToken: getCookie(req, 'edgestore-ctx'),
|
|
147
|
+
}),
|
|
148
|
+
);
|
|
149
|
+
} else if (matchPath(pathname, '/delete-file')) {
|
|
150
|
+
const body = (await req.json()) as DeleteFileBody;
|
|
151
|
+
return Response.json(
|
|
152
|
+
await deleteFile({
|
|
153
|
+
provider,
|
|
154
|
+
router: config.router,
|
|
155
|
+
body,
|
|
156
|
+
ctxToken: getCookie(req, 'edgestore-ctx'),
|
|
157
|
+
}),
|
|
158
|
+
);
|
|
159
|
+
} else if (matchPath(pathname, '/proxy-file')) {
|
|
160
|
+
const url = new URL(req.url).searchParams.get('url');
|
|
161
|
+
if (typeof url === 'string') {
|
|
162
|
+
const proxyRes = await fetch(url, {
|
|
163
|
+
headers: {
|
|
164
|
+
cookie: req.headers.get('cookie') ?? '',
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const data = await proxyRes.arrayBuffer();
|
|
169
|
+
const headers = new Headers();
|
|
170
|
+
headers.set(
|
|
171
|
+
'Content-Type',
|
|
172
|
+
proxyRes.headers.get('Content-Type') ?? 'application/octet-stream',
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
return new Response(data, { headers });
|
|
176
|
+
} else {
|
|
177
|
+
return new Response(null, { status: 400 });
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
return new Response(null, { status: 404 });
|
|
181
|
+
}
|
|
182
|
+
} catch (err) {
|
|
183
|
+
if (err instanceof EdgeStoreError) {
|
|
184
|
+
log[err.level](err.formattedMessage());
|
|
185
|
+
if (err.cause) log[err.level](err.cause);
|
|
186
|
+
return Response.json(err.formattedJson(), {
|
|
187
|
+
status: EDGE_STORE_ERROR_CODES[err.code as EdgeStoreErrorCodeKey],
|
|
188
|
+
});
|
|
189
|
+
} else {
|
|
190
|
+
log.error(err);
|
|
191
|
+
return Response.json(
|
|
192
|
+
new EdgeStoreError({
|
|
193
|
+
message: 'Internal Server Error',
|
|
194
|
+
code: 'SERVER_ERROR',
|
|
195
|
+
}).formattedJson(),
|
|
196
|
+
{ status: 500 },
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
package/src/adapters/shared.ts
CHANGED
|
@@ -434,7 +434,7 @@ export async function deleteFile<TCtx>(params: {
|
|
|
434
434
|
|
|
435
435
|
async function encryptJWT(ctx: any) {
|
|
436
436
|
const secret =
|
|
437
|
-
|
|
437
|
+
getEnv('EDGE_STORE_JWT_SECRET') ?? getEnv('EDGE_STORE_SECRET_KEY');
|
|
438
438
|
if (!secret) {
|
|
439
439
|
throw new EdgeStoreError({
|
|
440
440
|
message: 'EDGE_STORE_JWT_SECRET or EDGE_STORE_SECRET_KEY is not defined',
|
|
@@ -452,7 +452,7 @@ async function encryptJWT(ctx: any) {
|
|
|
452
452
|
|
|
453
453
|
async function decryptJWT(token: string) {
|
|
454
454
|
const secret =
|
|
455
|
-
|
|
455
|
+
getEnv('EDGE_STORE_JWT_SECRET') ?? getEnv('EDGE_STORE_SECRET_KEY');
|
|
456
456
|
if (!secret) {
|
|
457
457
|
throw new EdgeStoreError({
|
|
458
458
|
message: 'EDGE_STORE_JWT_SECRET or EDGE_STORE_SECRET_KEY is not defined',
|
|
@@ -539,7 +539,7 @@ async function getContext(token: string) {
|
|
|
539
539
|
* so that we can delete or confirm the upload.
|
|
540
540
|
*/
|
|
541
541
|
function unproxyUrl(url: string) {
|
|
542
|
-
if (
|
|
542
|
+
if (isDev() && url.startsWith('http://')) {
|
|
543
543
|
// get the url param from the query string
|
|
544
544
|
const urlParam = new URL(url).searchParams.get('url');
|
|
545
545
|
if (urlParam) {
|
|
@@ -548,3 +548,20 @@ function unproxyUrl(url: string) {
|
|
|
548
548
|
}
|
|
549
549
|
return url;
|
|
550
550
|
}
|
|
551
|
+
|
|
552
|
+
export function getEnv(key: string): string | undefined {
|
|
553
|
+
if (typeof process !== 'undefined' && process.env) {
|
|
554
|
+
// @ts-expect-error - In Vite/Astro, the env variables are available on `import.meta`.
|
|
555
|
+
return process.env[key] ?? import.meta.env?.[key];
|
|
556
|
+
}
|
|
557
|
+
// @ts-expect-error - In Vite/Astro, the env variables are available on `import.meta`.
|
|
558
|
+
return import.meta.env?.[key];
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
export function isDev(): boolean {
|
|
562
|
+
return (
|
|
563
|
+
process?.env?.NODE_ENV === 'development' ||
|
|
564
|
+
// @ts-expect-error - In Vite/Astro, the env variables are available on `import.meta`.
|
|
565
|
+
import.meta.env?.DEV
|
|
566
|
+
);
|
|
567
|
+
}
|
package/src/core/client/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from '@edgestore/shared';
|
|
11
11
|
import { type z, type ZodNever } from 'zod';
|
|
12
12
|
import { type Comparison } from '..';
|
|
13
|
-
import { buildPath, parsePath } from '../../adapters/shared';
|
|
13
|
+
import { buildPath, isDev, parsePath } from '../../adapters/shared';
|
|
14
14
|
import { initEdgeStoreSdk } from '../sdk';
|
|
15
15
|
|
|
16
16
|
export type GetFileRes<TBucket extends AnyBuilder> = {
|
|
@@ -408,7 +408,7 @@ export function initEdgeStoreClient<TRouter extends AnyRouter>(config: {
|
|
|
408
408
|
* we need to proxy the file through the server.
|
|
409
409
|
*/
|
|
410
410
|
function getUrl(url: string, baseUrl?: string) {
|
|
411
|
-
if (
|
|
411
|
+
if (isDev() && !url.includes('/_public/')) {
|
|
412
412
|
if (!baseUrl) {
|
|
413
413
|
throw new Error(
|
|
414
414
|
'Missing baseUrl. You need to pass the baseUrl to `initEdgeStoreClient` to get protected files in development.',
|
package/src/core/sdk/index.ts
CHANGED
|
@@ -4,10 +4,11 @@ import {
|
|
|
4
4
|
type AnyMetadata,
|
|
5
5
|
type AnyRouter,
|
|
6
6
|
} from '@edgestore/shared';
|
|
7
|
+
import { getEnv } from '../../adapters/shared';
|
|
7
8
|
import EdgeStoreCredentialsError from '../../libs/errors/EdgeStoreCredentialsError';
|
|
8
9
|
|
|
9
10
|
const API_ENDPOINT =
|
|
10
|
-
|
|
11
|
+
getEnv('EDGE_STORE_API_ENDPOINT') ?? 'https://api.edgestore.dev';
|
|
11
12
|
|
|
12
13
|
type FileInfoForUpload = {
|
|
13
14
|
size: number;
|
|
@@ -359,8 +360,8 @@ export function initEdgeStoreSdk(params: {
|
|
|
359
360
|
secretKey?: string;
|
|
360
361
|
}) {
|
|
361
362
|
const {
|
|
362
|
-
accessKey =
|
|
363
|
-
secretKey =
|
|
363
|
+
accessKey = getEnv('EDGE_STORE_ACCESS_KEY'),
|
|
364
|
+
secretKey = getEnv('EDGE_STORE_SECRET_KEY'),
|
|
364
365
|
} = params ?? {};
|
|
365
366
|
|
|
366
367
|
if (!accessKey || !secretKey) {
|
package/src/libs/logger.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
|
|
3
|
+
import { isDev } from '../adapters/shared';
|
|
4
|
+
|
|
3
5
|
const logLevel = ['debug', 'info', 'warn', 'error', 'none'] as const;
|
|
4
6
|
|
|
5
|
-
export type LogLevel = typeof logLevel[number];
|
|
7
|
+
export type LogLevel = (typeof logLevel)[number];
|
|
6
8
|
|
|
7
9
|
class Logger {
|
|
8
10
|
private logLevel: LogLevel;
|
|
9
11
|
|
|
10
12
|
constructor(logLevel?: LogLevel) {
|
|
11
|
-
this.logLevel =
|
|
12
|
-
logLevel ?? (process.env.NODE_ENV === 'production' ? 'error' : 'info');
|
|
13
|
+
this.logLevel = logLevel ?? (isDev() ? 'info' : 'error');
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
private shouldLog(level: LogLevel): boolean {
|
|
@@ -5,8 +5,29 @@ import {
|
|
|
5
5
|
S3Client,
|
|
6
6
|
} from '@aws-sdk/client-s3';
|
|
7
7
|
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
type MaybePromise,
|
|
10
|
+
type Provider,
|
|
11
|
+
type RequestUploadParams,
|
|
12
|
+
} from '@edgestore/shared';
|
|
9
13
|
import { v4 as uuidv4 } from 'uuid';
|
|
14
|
+
import { getEnv } from '../../adapters/shared';
|
|
15
|
+
|
|
16
|
+
// FileInfo type as received by the provider's requestUpload, part of RequestUploadParams
|
|
17
|
+
type ProviderUploadedFileInfo = RequestUploadParams['fileInfo'];
|
|
18
|
+
|
|
19
|
+
export type AWSOverwritePathFnArgs = {
|
|
20
|
+
/* EdgeStore bucket name */
|
|
21
|
+
esBucketName: string;
|
|
22
|
+
/* File info after path generation and metadata by EdgeStore */
|
|
23
|
+
fileInfo: ProviderUploadedFileInfo;
|
|
24
|
+
/* The S3 key that would be generated by default by this provider */
|
|
25
|
+
defaultAccessPath: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type AWSOverwritePathFn = (
|
|
29
|
+
args: AWSOverwritePathFnArgs,
|
|
30
|
+
) => MaybePromise<string>;
|
|
10
31
|
|
|
11
32
|
export type AWSProviderOptions = {
|
|
12
33
|
/**
|
|
@@ -58,21 +79,28 @@ export type AWSProviderOptions = {
|
|
|
58
79
|
* It can also be set via the `EDGE_STORE_JWT_SECRET` environment variable.
|
|
59
80
|
*/
|
|
60
81
|
jwtSecret?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Optional function to overwrite the S3 key (object path) for uploads.
|
|
84
|
+
* This function receives the EdgeStore bucket name, fileInfo and the default S3 key
|
|
85
|
+
* and should return the desired S3 key string.
|
|
86
|
+
*/
|
|
87
|
+
overwritePath?: AWSOverwritePathFn;
|
|
61
88
|
};
|
|
62
89
|
|
|
63
90
|
export function AWSProvider(options?: AWSProviderOptions): Provider {
|
|
64
91
|
const {
|
|
65
|
-
accessKeyId =
|
|
66
|
-
secretAccessKey =
|
|
67
|
-
region =
|
|
68
|
-
bucketName =
|
|
69
|
-
endpoint =
|
|
70
|
-
forcePathStyle =
|
|
92
|
+
accessKeyId = getEnv('ES_AWS_ACCESS_KEY_ID'),
|
|
93
|
+
secretAccessKey = getEnv('ES_AWS_SECRET_ACCESS_KEY'),
|
|
94
|
+
region = getEnv('ES_AWS_REGION'),
|
|
95
|
+
bucketName = getEnv('ES_AWS_BUCKET_NAME'),
|
|
96
|
+
endpoint = getEnv('ES_AWS_ENDPOINT'),
|
|
97
|
+
forcePathStyle = getEnv('ES_AWS_FORCE_PATH_STYLE') === 'true',
|
|
98
|
+
overwritePath,
|
|
71
99
|
} = options ?? {};
|
|
72
100
|
|
|
73
101
|
const baseUrl =
|
|
74
102
|
options?.baseUrl ??
|
|
75
|
-
|
|
103
|
+
getEnv('EDGE_STORE_BASE_URL') ??
|
|
76
104
|
(endpoint
|
|
77
105
|
? `${endpoint}/${bucketName}`
|
|
78
106
|
: `https://${bucketName}.s3.${region}.amazonaws.com`);
|
|
@@ -119,7 +147,16 @@ export function AWSProvider(options?: AWSProviderOptions): Provider {
|
|
|
119
147
|
uploadedAt: LastModified,
|
|
120
148
|
};
|
|
121
149
|
},
|
|
122
|
-
async requestUpload(
|
|
150
|
+
async requestUpload(params: RequestUploadParams) {
|
|
151
|
+
const { bucketName: esBucketName, fileInfo } = params;
|
|
152
|
+
|
|
153
|
+
if (!bucketName) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
'S3 bucketName is not configured in AWSProviderOptions.',
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Default S3 key (accessPath) construction logic
|
|
123
160
|
const pathPrefix = `${esBucketName}${
|
|
124
161
|
fileInfo.isPublic ? '/_public' : ''
|
|
125
162
|
}`;
|
|
@@ -127,11 +164,21 @@ export function AWSProvider(options?: AWSProviderOptions): Provider {
|
|
|
127
164
|
const extension = fileInfo.extension
|
|
128
165
|
? `.${fileInfo.extension.replace('.', '')}`
|
|
129
166
|
: '';
|
|
130
|
-
const
|
|
131
|
-
|
|
167
|
+
const defaultResolvedFileName =
|
|
168
|
+
fileInfo.fileName ?? `${nameId}${extension}`;
|
|
169
|
+
const defaultFilePathFromMetadata = fileInfo.path.reduce((acc, item) => {
|
|
132
170
|
return `${acc}/${item.value}`;
|
|
133
171
|
}, '');
|
|
134
|
-
|
|
172
|
+
|
|
173
|
+
let accessPath = `${pathPrefix}${defaultFilePathFromMetadata}/${defaultResolvedFileName}`;
|
|
174
|
+
|
|
175
|
+
if (overwritePath) {
|
|
176
|
+
accessPath = await overwritePath({
|
|
177
|
+
esBucketName,
|
|
178
|
+
fileInfo,
|
|
179
|
+
defaultAccessPath: accessPath,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
135
182
|
|
|
136
183
|
const command = new PutObjectCommand({
|
|
137
184
|
Bucket: bucketName,
|
|
@@ -142,10 +189,10 @@ export function AWSProvider(options?: AWSProviderOptions): Provider {
|
|
|
142
189
|
expiresIn: 60 * 60, // 1 hour
|
|
143
190
|
});
|
|
144
191
|
|
|
145
|
-
const
|
|
192
|
+
const finalAccessUrl = `${baseUrl}/${accessPath.startsWith('/') ? accessPath.substring(1) : accessPath}`;
|
|
146
193
|
return {
|
|
147
194
|
uploadUrl: signedUrl,
|
|
148
|
-
accessUrl:
|
|
195
|
+
accessUrl: finalAccessUrl,
|
|
149
196
|
};
|
|
150
197
|
},
|
|
151
198
|
async requestUploadParts() {
|
|
@@ -158,6 +205,11 @@ export function AWSProvider(options?: AWSProviderOptions): Provider {
|
|
|
158
205
|
throw new Error('Not implemented');
|
|
159
206
|
},
|
|
160
207
|
async deleteFile({ url }) {
|
|
208
|
+
if (!bucketName) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
'S3 bucketName is not configured in AWSProviderOptions for deleteFile.',
|
|
211
|
+
);
|
|
212
|
+
}
|
|
161
213
|
const path = url.replace(`${baseUrl}/`, '');
|
|
162
214
|
await s3Client.send(
|
|
163
215
|
new DeleteObjectCommand({
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BlobServiceClient } from '@azure/storage-blob';
|
|
2
2
|
import { type Provider } from '@edgestore/shared';
|
|
3
3
|
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import { getEnv } from '../../adapters/shared';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Options for the Azure provider. Compatible with Azure Blob Storage and Azurite.
|
|
@@ -41,10 +42,10 @@ export type AzureProviderOptions = {
|
|
|
41
42
|
|
|
42
43
|
export function AzureProvider(options?: AzureProviderOptions): Provider {
|
|
43
44
|
const {
|
|
44
|
-
storageAccountName =
|
|
45
|
-
sasToken =
|
|
46
|
-
containerName =
|
|
47
|
-
customBaseUrl =
|
|
45
|
+
storageAccountName = getEnv('ES_AZURE_ACCOUNT_NAME'),
|
|
46
|
+
sasToken = getEnv('ES_AZURE_SAS_TOKEN'),
|
|
47
|
+
containerName = getEnv('ES_AZURE_CONTAINER_NAME'),
|
|
48
|
+
customBaseUrl = getEnv('ES_AZURE_BASE_URL'),
|
|
48
49
|
} = options ?? {};
|
|
49
50
|
|
|
50
51
|
const baseUrl =
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
type Provider,
|
|
4
4
|
type RequestUploadRes,
|
|
5
5
|
} from '@edgestore/shared';
|
|
6
|
+
import { getEnv } from '../../adapters/shared';
|
|
6
7
|
import { initEdgeStoreSdk } from '../../core/sdk';
|
|
7
8
|
import EdgeStoreCredentialsError from '../../libs/errors/EdgeStoreCredentialsError';
|
|
8
9
|
|
|
@@ -29,11 +30,15 @@ export function EdgeStoreProvider(
|
|
|
29
30
|
options?: EdgeStoreProviderOptions,
|
|
30
31
|
): Provider {
|
|
31
32
|
const {
|
|
32
|
-
accessKey =
|
|
33
|
-
|
|
33
|
+
accessKey = getEnv('EDGE_STORE_ACCESS_KEY') ??
|
|
34
|
+
// @ts-expect-error - In Vite/Astro, the env variables are available on `import.meta`.
|
|
35
|
+
import.meta.env?.EDGE_STORE_ACCESS_KEY,
|
|
36
|
+
secretKey = getEnv('EDGE_STORE_SECRET_KEY') ??
|
|
37
|
+
// @ts-expect-error - In Vite/Astro, the env variables are available on `import.meta`.
|
|
38
|
+
import.meta.env?.EDGE_STORE_SECRET_KEY,
|
|
34
39
|
} = options ?? {};
|
|
35
40
|
|
|
36
|
-
const baseUrl =
|
|
41
|
+
const baseUrl = getEnv('EDGE_STORE_BASE_URL') ?? DEFAULT_BASE_URL;
|
|
37
42
|
|
|
38
43
|
if (!accessKey || !secretKey) {
|
|
39
44
|
throw new EdgeStoreCredentialsError();
|
package/adapters/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '../dist/adapters';
|
package/adapters/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = require('../dist/adapters');
|
package/providers/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '../dist/providers';
|
package/providers/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = require('../dist/providers');
|