@edgestore/server 0.2.1 → 0.3.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/adapters/start/index.d.ts +1 -0
- package/adapters/start/index.js +1 -0
- package/dist/adapters/start/index.d.ts +18 -0
- package/dist/adapters/start/index.d.ts.map +1 -0
- package/dist/adapters/start/index.js +190 -0
- package/dist/adapters/start/index.mjs +186 -0
- package/dist/providers/azure/index.d.ts +19 -0
- package/dist/providers/azure/index.d.ts.map +1 -1
- package/dist/providers/azure/index.js +2 -2
- package/dist/providers/azure/index.mjs +2 -2
- package/package.json +8 -3
- package/src/adapters/start/index.ts +208 -0
- package/src/providers/azure/index.ts +22 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../../dist/adapters/start';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../../dist/adapters/start');
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type EdgeStoreRouter, type MaybePromise, type Provider } from '@edgestore/shared';
|
|
2
|
+
import { type LogLevel } from '../../libs/logger';
|
|
3
|
+
export type CreateContextOptions = {
|
|
4
|
+
req: Request;
|
|
5
|
+
};
|
|
6
|
+
export type Config<TCtx> = {
|
|
7
|
+
provider?: Provider;
|
|
8
|
+
router: EdgeStoreRouter<TCtx>;
|
|
9
|
+
logLevel?: LogLevel;
|
|
10
|
+
} & (TCtx extends Record<string, never> ? object : {
|
|
11
|
+
provider?: Provider;
|
|
12
|
+
router: EdgeStoreRouter<TCtx>;
|
|
13
|
+
createContext: (opts: CreateContextOptions) => MaybePromise<TCtx>;
|
|
14
|
+
});
|
|
15
|
+
export declare function createEdgeStoreStartHandler<TCtx>(config: Config<TCtx>): ({ request }: {
|
|
16
|
+
request: Request;
|
|
17
|
+
}) => Promise<Response>;
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/start/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACd,MAAM,mBAAmB,CAAC;AAC3B,OAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAiB1D,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,MAAM,CAAC,IAAI,IAAI;IACzB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,GAAG,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GACnC,MAAM,GACN;IACE,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC;IAC9B,aAAa,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,YAAY,CAAC,IAAI,CAAC,CAAC;CACnE,CAAC,CAAC;AAsBP,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC;aAM9B,OAAO;wBA4I9C"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var shared = require('@edgestore/shared');
|
|
6
|
+
var utils = require('../../utils-5819d5e1.js');
|
|
7
|
+
var providers_edgestore_index = require('../../providers/edgestore/index.js');
|
|
8
|
+
var shared$1 = require('../../shared-7c700083.js');
|
|
9
|
+
require('../../index-4491caf0.js');
|
|
10
|
+
require('@panva/hkdf');
|
|
11
|
+
require('cookie');
|
|
12
|
+
require('jose');
|
|
13
|
+
require('uuid');
|
|
14
|
+
|
|
15
|
+
// Helper to extract a cookie from the request's cookie header
|
|
16
|
+
function getCookie(req, cookieName) {
|
|
17
|
+
const cookieHeader = req.headers.get('cookie');
|
|
18
|
+
if (!cookieHeader) return undefined;
|
|
19
|
+
return cookieHeader.split(';').map((cookieStr)=>cookieStr.trim()).reduce((acc, cookieStr)=>{
|
|
20
|
+
const [name, ...rest] = cookieStr.split('=');
|
|
21
|
+
if (name && rest.length > 0) {
|
|
22
|
+
acc[name] = rest.join('=');
|
|
23
|
+
}
|
|
24
|
+
return acc;
|
|
25
|
+
}, {})[cookieName];
|
|
26
|
+
}
|
|
27
|
+
function createEdgeStoreStartHandler(config) {
|
|
28
|
+
const { provider = providers_edgestore_index.EdgeStoreProvider() } = config;
|
|
29
|
+
const log = new utils.Logger(config.logLevel);
|
|
30
|
+
globalThis._EDGE_STORE_LOGGER = log;
|
|
31
|
+
log.debug('Creating Edge Store TanStack Start handler');
|
|
32
|
+
return async ({ request })=>{
|
|
33
|
+
try {
|
|
34
|
+
const { pathname } = new URL(request.url);
|
|
35
|
+
if (utils.matchPath(pathname, '/health')) {
|
|
36
|
+
return new Response('OK', {
|
|
37
|
+
status: 200
|
|
38
|
+
});
|
|
39
|
+
} else if (utils.matchPath(pathname, '/init')) {
|
|
40
|
+
let ctx = {};
|
|
41
|
+
try {
|
|
42
|
+
ctx = 'createContext' in config ? await config.createContext({
|
|
43
|
+
req: request
|
|
44
|
+
}) : {};
|
|
45
|
+
} catch (err) {
|
|
46
|
+
throw new shared.EdgeStoreError({
|
|
47
|
+
message: 'Error creating context',
|
|
48
|
+
code: 'CREATE_CONTEXT_ERROR',
|
|
49
|
+
cause: err instanceof Error ? err : undefined
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const { newCookies, token, baseUrl } = await shared$1.init({
|
|
53
|
+
ctx,
|
|
54
|
+
provider,
|
|
55
|
+
router: config.router
|
|
56
|
+
});
|
|
57
|
+
const headers = new Headers();
|
|
58
|
+
newCookies.forEach((cookie)=>headers.append('Set-Cookie', cookie));
|
|
59
|
+
headers.set('Content-Type', 'application/json');
|
|
60
|
+
return new Response(JSON.stringify({
|
|
61
|
+
token,
|
|
62
|
+
baseUrl
|
|
63
|
+
}), {
|
|
64
|
+
status: 200,
|
|
65
|
+
headers
|
|
66
|
+
});
|
|
67
|
+
} else if (utils.matchPath(pathname, '/request-upload')) {
|
|
68
|
+
const body = await request.json();
|
|
69
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
70
|
+
const result = await shared$1.requestUpload({
|
|
71
|
+
provider,
|
|
72
|
+
router: config.router,
|
|
73
|
+
body: body,
|
|
74
|
+
ctxToken
|
|
75
|
+
});
|
|
76
|
+
return new Response(JSON.stringify(result), {
|
|
77
|
+
status: 200,
|
|
78
|
+
headers: {
|
|
79
|
+
'Content-Type': 'application/json'
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
} else if (utils.matchPath(pathname, '/request-upload-parts')) {
|
|
83
|
+
const body = await request.json();
|
|
84
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
85
|
+
const result = await shared$1.requestUploadParts({
|
|
86
|
+
provider,
|
|
87
|
+
router: config.router,
|
|
88
|
+
body: body,
|
|
89
|
+
ctxToken
|
|
90
|
+
});
|
|
91
|
+
return new Response(JSON.stringify(result), {
|
|
92
|
+
status: 200,
|
|
93
|
+
headers: {
|
|
94
|
+
'Content-Type': 'application/json'
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
} else if (utils.matchPath(pathname, '/complete-multipart-upload')) {
|
|
98
|
+
const body = await request.json();
|
|
99
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
100
|
+
await shared$1.completeMultipartUpload({
|
|
101
|
+
provider,
|
|
102
|
+
router: config.router,
|
|
103
|
+
body: body,
|
|
104
|
+
ctxToken
|
|
105
|
+
});
|
|
106
|
+
return new Response(null, {
|
|
107
|
+
status: 200
|
|
108
|
+
});
|
|
109
|
+
} else if (utils.matchPath(pathname, '/confirm-upload')) {
|
|
110
|
+
const body = await request.json();
|
|
111
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
112
|
+
const result = await shared$1.confirmUpload({
|
|
113
|
+
provider,
|
|
114
|
+
router: config.router,
|
|
115
|
+
body: body,
|
|
116
|
+
ctxToken
|
|
117
|
+
});
|
|
118
|
+
return new Response(JSON.stringify(result), {
|
|
119
|
+
status: 200,
|
|
120
|
+
headers: {
|
|
121
|
+
'Content-Type': 'application/json'
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
} else if (utils.matchPath(pathname, '/delete-file')) {
|
|
125
|
+
const body = await request.json();
|
|
126
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
127
|
+
const result = await shared$1.deleteFile({
|
|
128
|
+
provider,
|
|
129
|
+
router: config.router,
|
|
130
|
+
body: body,
|
|
131
|
+
ctxToken
|
|
132
|
+
});
|
|
133
|
+
return new Response(JSON.stringify(result), {
|
|
134
|
+
status: 200,
|
|
135
|
+
headers: {
|
|
136
|
+
'Content-Type': 'application/json'
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
} else if (utils.matchPath(pathname, '/proxy-file')) {
|
|
140
|
+
const urlParam = new URL(request.url).searchParams.get('url');
|
|
141
|
+
if (typeof urlParam === 'string') {
|
|
142
|
+
const proxyRes = await fetch(urlParam, {
|
|
143
|
+
headers: {
|
|
144
|
+
cookie: request.headers.get('cookie') ?? ''
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
const data = await proxyRes.arrayBuffer();
|
|
148
|
+
const headers = new Headers();
|
|
149
|
+
headers.set('Content-Type', proxyRes.headers.get('Content-Type') ?? 'application/octet-stream');
|
|
150
|
+
return new Response(data, {
|
|
151
|
+
status: proxyRes.status,
|
|
152
|
+
headers
|
|
153
|
+
});
|
|
154
|
+
} else {
|
|
155
|
+
return new Response(null, {
|
|
156
|
+
status: 400
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
return new Response(null, {
|
|
161
|
+
status: 404
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
} catch (err) {
|
|
165
|
+
if (err instanceof shared.EdgeStoreError) {
|
|
166
|
+
log[err.level](err.formattedMessage());
|
|
167
|
+
if (err.cause) log[err.level](err.cause);
|
|
168
|
+
const status = shared.EDGE_STORE_ERROR_CODES[err.code] || 500;
|
|
169
|
+
return new Response(JSON.stringify(err.formattedJson()), {
|
|
170
|
+
status,
|
|
171
|
+
headers: {
|
|
172
|
+
'Content-Type': 'application/json'
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
log.error(err);
|
|
177
|
+
return new Response(JSON.stringify(new shared.EdgeStoreError({
|
|
178
|
+
message: 'Internal server error',
|
|
179
|
+
code: 'SERVER_ERROR'
|
|
180
|
+
}).formattedJson()), {
|
|
181
|
+
status: 500,
|
|
182
|
+
headers: {
|
|
183
|
+
'Content-Type': 'application/json'
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
exports.createEdgeStoreStartHandler = createEdgeStoreStartHandler;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { EdgeStoreError, EDGE_STORE_ERROR_CODES } from '@edgestore/shared';
|
|
2
|
+
import { L as Logger, m as matchPath } from '../../utils-f6f56d38.mjs';
|
|
3
|
+
import { EdgeStoreProvider } from '../../providers/edgestore/index.mjs';
|
|
4
|
+
import { i as init, r as requestUpload, a as requestUploadParts, c as completeMultipartUpload, d as confirmUpload, e as deleteFile } from '../../shared-039276af.mjs';
|
|
5
|
+
import '../../index-28efdacf.mjs';
|
|
6
|
+
import '@panva/hkdf';
|
|
7
|
+
import 'cookie';
|
|
8
|
+
import 'jose';
|
|
9
|
+
import 'uuid';
|
|
10
|
+
|
|
11
|
+
// Helper to extract a cookie from the request's cookie header
|
|
12
|
+
function getCookie(req, cookieName) {
|
|
13
|
+
const cookieHeader = req.headers.get('cookie');
|
|
14
|
+
if (!cookieHeader) return undefined;
|
|
15
|
+
return cookieHeader.split(';').map((cookieStr)=>cookieStr.trim()).reduce((acc, cookieStr)=>{
|
|
16
|
+
const [name, ...rest] = cookieStr.split('=');
|
|
17
|
+
if (name && rest.length > 0) {
|
|
18
|
+
acc[name] = rest.join('=');
|
|
19
|
+
}
|
|
20
|
+
return acc;
|
|
21
|
+
}, {})[cookieName];
|
|
22
|
+
}
|
|
23
|
+
function createEdgeStoreStartHandler(config) {
|
|
24
|
+
const { provider = EdgeStoreProvider() } = config;
|
|
25
|
+
const log = new Logger(config.logLevel);
|
|
26
|
+
globalThis._EDGE_STORE_LOGGER = log;
|
|
27
|
+
log.debug('Creating Edge Store TanStack Start handler');
|
|
28
|
+
return async ({ request })=>{
|
|
29
|
+
try {
|
|
30
|
+
const { pathname } = new URL(request.url);
|
|
31
|
+
if (matchPath(pathname, '/health')) {
|
|
32
|
+
return new Response('OK', {
|
|
33
|
+
status: 200
|
|
34
|
+
});
|
|
35
|
+
} else if (matchPath(pathname, '/init')) {
|
|
36
|
+
let ctx = {};
|
|
37
|
+
try {
|
|
38
|
+
ctx = 'createContext' in config ? await config.createContext({
|
|
39
|
+
req: request
|
|
40
|
+
}) : {};
|
|
41
|
+
} catch (err) {
|
|
42
|
+
throw new EdgeStoreError({
|
|
43
|
+
message: 'Error creating context',
|
|
44
|
+
code: 'CREATE_CONTEXT_ERROR',
|
|
45
|
+
cause: err instanceof Error ? err : undefined
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const { newCookies, token, baseUrl } = await init({
|
|
49
|
+
ctx,
|
|
50
|
+
provider,
|
|
51
|
+
router: config.router
|
|
52
|
+
});
|
|
53
|
+
const headers = new Headers();
|
|
54
|
+
newCookies.forEach((cookie)=>headers.append('Set-Cookie', cookie));
|
|
55
|
+
headers.set('Content-Type', 'application/json');
|
|
56
|
+
return new Response(JSON.stringify({
|
|
57
|
+
token,
|
|
58
|
+
baseUrl
|
|
59
|
+
}), {
|
|
60
|
+
status: 200,
|
|
61
|
+
headers
|
|
62
|
+
});
|
|
63
|
+
} else if (matchPath(pathname, '/request-upload')) {
|
|
64
|
+
const body = await request.json();
|
|
65
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
66
|
+
const result = await requestUpload({
|
|
67
|
+
provider,
|
|
68
|
+
router: config.router,
|
|
69
|
+
body: body,
|
|
70
|
+
ctxToken
|
|
71
|
+
});
|
|
72
|
+
return new Response(JSON.stringify(result), {
|
|
73
|
+
status: 200,
|
|
74
|
+
headers: {
|
|
75
|
+
'Content-Type': 'application/json'
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
} else if (matchPath(pathname, '/request-upload-parts')) {
|
|
79
|
+
const body = await request.json();
|
|
80
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
81
|
+
const result = await requestUploadParts({
|
|
82
|
+
provider,
|
|
83
|
+
router: config.router,
|
|
84
|
+
body: body,
|
|
85
|
+
ctxToken
|
|
86
|
+
});
|
|
87
|
+
return new Response(JSON.stringify(result), {
|
|
88
|
+
status: 200,
|
|
89
|
+
headers: {
|
|
90
|
+
'Content-Type': 'application/json'
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
} else if (matchPath(pathname, '/complete-multipart-upload')) {
|
|
94
|
+
const body = await request.json();
|
|
95
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
96
|
+
await completeMultipartUpload({
|
|
97
|
+
provider,
|
|
98
|
+
router: config.router,
|
|
99
|
+
body: body,
|
|
100
|
+
ctxToken
|
|
101
|
+
});
|
|
102
|
+
return new Response(null, {
|
|
103
|
+
status: 200
|
|
104
|
+
});
|
|
105
|
+
} else if (matchPath(pathname, '/confirm-upload')) {
|
|
106
|
+
const body = await request.json();
|
|
107
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
108
|
+
const result = await confirmUpload({
|
|
109
|
+
provider,
|
|
110
|
+
router: config.router,
|
|
111
|
+
body: body,
|
|
112
|
+
ctxToken
|
|
113
|
+
});
|
|
114
|
+
return new Response(JSON.stringify(result), {
|
|
115
|
+
status: 200,
|
|
116
|
+
headers: {
|
|
117
|
+
'Content-Type': 'application/json'
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
} else if (matchPath(pathname, '/delete-file')) {
|
|
121
|
+
const body = await request.json();
|
|
122
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
123
|
+
const result = await deleteFile({
|
|
124
|
+
provider,
|
|
125
|
+
router: config.router,
|
|
126
|
+
body: body,
|
|
127
|
+
ctxToken
|
|
128
|
+
});
|
|
129
|
+
return new Response(JSON.stringify(result), {
|
|
130
|
+
status: 200,
|
|
131
|
+
headers: {
|
|
132
|
+
'Content-Type': 'application/json'
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
} else if (matchPath(pathname, '/proxy-file')) {
|
|
136
|
+
const urlParam = new URL(request.url).searchParams.get('url');
|
|
137
|
+
if (typeof urlParam === 'string') {
|
|
138
|
+
const proxyRes = await fetch(urlParam, {
|
|
139
|
+
headers: {
|
|
140
|
+
cookie: request.headers.get('cookie') ?? ''
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
const data = await proxyRes.arrayBuffer();
|
|
144
|
+
const headers = new Headers();
|
|
145
|
+
headers.set('Content-Type', proxyRes.headers.get('Content-Type') ?? 'application/octet-stream');
|
|
146
|
+
return new Response(data, {
|
|
147
|
+
status: proxyRes.status,
|
|
148
|
+
headers
|
|
149
|
+
});
|
|
150
|
+
} else {
|
|
151
|
+
return new Response(null, {
|
|
152
|
+
status: 400
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
return new Response(null, {
|
|
157
|
+
status: 404
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
} catch (err) {
|
|
161
|
+
if (err instanceof EdgeStoreError) {
|
|
162
|
+
log[err.level](err.formattedMessage());
|
|
163
|
+
if (err.cause) log[err.level](err.cause);
|
|
164
|
+
const status = EDGE_STORE_ERROR_CODES[err.code] || 500;
|
|
165
|
+
return new Response(JSON.stringify(err.formattedJson()), {
|
|
166
|
+
status,
|
|
167
|
+
headers: {
|
|
168
|
+
'Content-Type': 'application/json'
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
log.error(err);
|
|
173
|
+
return new Response(JSON.stringify(new EdgeStoreError({
|
|
174
|
+
message: 'Internal server error',
|
|
175
|
+
code: 'SERVER_ERROR'
|
|
176
|
+
}).formattedJson()), {
|
|
177
|
+
status: 500,
|
|
178
|
+
headers: {
|
|
179
|
+
'Content-Type': 'application/json'
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export { createEdgeStoreStartHandler };
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import { type Provider } from '@edgestore/shared';
|
|
2
|
+
/**
|
|
3
|
+
* Options for the Azure provider. Compatible with Azure Blob Storage and Azurite.
|
|
4
|
+
* Use Azure Storage Explorer for local development with Azurite.
|
|
5
|
+
* @see https://azure.microsoft.com/de-de/products/storage/storage-explorer
|
|
6
|
+
* @category Providers
|
|
7
|
+
* @example
|
|
8
|
+
* AzureProvider({
|
|
9
|
+
* storageAccountName: 'devstoreaccount1',
|
|
10
|
+
* sasToken: 'some-generated-token-from-azure-storage-explorer',
|
|
11
|
+
* containerName: 'some-container-name',
|
|
12
|
+
* customBaseUrl: 'http://localhost:10000/devstoreaccount1',
|
|
13
|
+
* })
|
|
14
|
+
*/
|
|
2
15
|
export type AzureProviderOptions = {
|
|
3
16
|
/**
|
|
4
17
|
* The storage account name for Azure Blob Storage
|
|
@@ -15,6 +28,12 @@ export type AzureProviderOptions = {
|
|
|
15
28
|
* Can also be set via the `ES_AZURE_CONTAINER_NAME` environment variable.
|
|
16
29
|
*/
|
|
17
30
|
containerName?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Optional base URL for the Azure Blob Storage.
|
|
33
|
+
* Useful for local development with Azurite. For example: `http://localhost:10000/devstoreaccount1`
|
|
34
|
+
* Can also be set via the `ES_AZURE_BASE_URL` environment variable.
|
|
35
|
+
*/
|
|
36
|
+
customBaseUrl?: string;
|
|
18
37
|
};
|
|
19
38
|
export declare function AzureProvider(options?: AzureProviderOptions): Provider;
|
|
20
39
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/azure/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGlD,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/azure/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGlD;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,QAAQ,CAoEtE"}
|
|
@@ -6,8 +6,8 @@ var storageBlob = require('@azure/storage-blob');
|
|
|
6
6
|
var uuid = require('uuid');
|
|
7
7
|
|
|
8
8
|
function AzureProvider(options) {
|
|
9
|
-
const { storageAccountName = process.env.ES_AZURE_ACCOUNT_NAME, sasToken = process.env.ES_AZURE_SAS_TOKEN, containerName = process.env.ES_AZURE_CONTAINER_NAME } = options ?? {};
|
|
10
|
-
const baseUrl = `https://${storageAccountName}.blob.core.windows.net`;
|
|
9
|
+
const { storageAccountName = process.env.ES_AZURE_ACCOUNT_NAME, sasToken = process.env.ES_AZURE_SAS_TOKEN, containerName = process.env.ES_AZURE_CONTAINER_NAME, customBaseUrl = process.env.ES_AZURE_BASE_URL } = options ?? {};
|
|
10
|
+
const baseUrl = customBaseUrl ?? `https://${storageAccountName}.blob.core.windows.net`;
|
|
11
11
|
const blobServiceClient = new storageBlob.BlobServiceClient(`${baseUrl}?${sasToken}`);
|
|
12
12
|
const containerClient = blobServiceClient.getContainerClient(containerName ?? '');
|
|
13
13
|
return {
|
|
@@ -2,8 +2,8 @@ import { BlobServiceClient } from '@azure/storage-blob';
|
|
|
2
2
|
import { v4 } from 'uuid';
|
|
3
3
|
|
|
4
4
|
function AzureProvider(options) {
|
|
5
|
-
const { storageAccountName = process.env.ES_AZURE_ACCOUNT_NAME, sasToken = process.env.ES_AZURE_SAS_TOKEN, containerName = process.env.ES_AZURE_CONTAINER_NAME } = options ?? {};
|
|
6
|
-
const baseUrl = `https://${storageAccountName}.blob.core.windows.net`;
|
|
5
|
+
const { storageAccountName = process.env.ES_AZURE_ACCOUNT_NAME, sasToken = process.env.ES_AZURE_SAS_TOKEN, containerName = process.env.ES_AZURE_CONTAINER_NAME, customBaseUrl = process.env.ES_AZURE_BASE_URL } = options ?? {};
|
|
6
|
+
const baseUrl = customBaseUrl ?? `https://${storageAccountName}.blob.core.windows.net`;
|
|
7
7
|
const blobServiceClient = new BlobServiceClient(`${baseUrl}?${sasToken}`);
|
|
8
8
|
const containerClient = blobServiceClient.getContainerClient(containerName ?? '');
|
|
9
9
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edgestore/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Upload files with ease from React/Next.js",
|
|
5
5
|
"homepage": "https://edgestore.dev",
|
|
6
6
|
"repository": "https://github.com/edgestorejs/edgestore.git",
|
|
@@ -52,6 +52,11 @@
|
|
|
52
52
|
"require": "./dist/adapters/next/app/index.js",
|
|
53
53
|
"default": "./dist/adapters/next/app/index.js"
|
|
54
54
|
},
|
|
55
|
+
"./adapters/start": {
|
|
56
|
+
"import": "./dist/adapters/start/index.mjs",
|
|
57
|
+
"require": "./dist/adapters/start/index.js",
|
|
58
|
+
"default": "./dist/adapters/start/index.js"
|
|
59
|
+
},
|
|
55
60
|
"./providers/aws": {
|
|
56
61
|
"import": "./dist/providers/aws/index.mjs",
|
|
57
62
|
"require": "./dist/providers/aws/index.js",
|
|
@@ -84,7 +89,7 @@
|
|
|
84
89
|
},
|
|
85
90
|
"license": "MIT",
|
|
86
91
|
"dependencies": {
|
|
87
|
-
"@edgestore/shared": "0.
|
|
92
|
+
"@edgestore/shared": "0.3.0",
|
|
88
93
|
"@panva/hkdf": "^1.0.4",
|
|
89
94
|
"cookie": "^0.5.0",
|
|
90
95
|
"jose": "^4.13.1",
|
|
@@ -123,5 +128,5 @@
|
|
|
123
128
|
"typescript": "^5.1.6",
|
|
124
129
|
"zod": "3.21.4"
|
|
125
130
|
},
|
|
126
|
-
"gitHead": "
|
|
131
|
+
"gitHead": "68417701e181eebb273a312b5f954fb65b325fe5"
|
|
127
132
|
}
|
|
@@ -0,0 +1,208 @@
|
|
|
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 extract a cookie from the request's cookie header
|
|
47
|
+
function getCookie(req: Request, cookieName: string): string | undefined {
|
|
48
|
+
const cookieHeader = req.headers.get('cookie');
|
|
49
|
+
if (!cookieHeader) return undefined;
|
|
50
|
+
return cookieHeader
|
|
51
|
+
.split(';')
|
|
52
|
+
.map((cookieStr) => cookieStr.trim())
|
|
53
|
+
.reduce((acc: Record<string, string>, cookieStr) => {
|
|
54
|
+
const [name, ...rest] = cookieStr.split('=');
|
|
55
|
+
if (name && rest.length > 0) {
|
|
56
|
+
acc[name] = rest.join('=');
|
|
57
|
+
}
|
|
58
|
+
return acc;
|
|
59
|
+
}, {})[cookieName];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function createEdgeStoreStartHandler<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 Edge Store TanStack Start handler');
|
|
67
|
+
|
|
68
|
+
return async ({ request }: { request: Request }) => {
|
|
69
|
+
try {
|
|
70
|
+
const { pathname } = new URL(request.url);
|
|
71
|
+
if (matchPath(pathname, '/health')) {
|
|
72
|
+
return new Response('OK', { status: 200 });
|
|
73
|
+
} else if (matchPath(pathname, '/init')) {
|
|
74
|
+
let ctx = {} as TCtx;
|
|
75
|
+
try {
|
|
76
|
+
ctx =
|
|
77
|
+
'createContext' in config
|
|
78
|
+
? await config.createContext({ req: request })
|
|
79
|
+
: ({} as TCtx);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
throw new EdgeStoreError({
|
|
82
|
+
message: 'Error creating context',
|
|
83
|
+
code: 'CREATE_CONTEXT_ERROR',
|
|
84
|
+
cause: err instanceof Error ? err : undefined,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const { newCookies, token, baseUrl } = await init({
|
|
88
|
+
ctx,
|
|
89
|
+
provider,
|
|
90
|
+
router: config.router,
|
|
91
|
+
});
|
|
92
|
+
const headers = new Headers();
|
|
93
|
+
newCookies.forEach((cookie) => headers.append('Set-Cookie', cookie));
|
|
94
|
+
headers.set('Content-Type', 'application/json');
|
|
95
|
+
return new Response(JSON.stringify({ token, baseUrl }), {
|
|
96
|
+
status: 200,
|
|
97
|
+
headers,
|
|
98
|
+
});
|
|
99
|
+
} else if (matchPath(pathname, '/request-upload')) {
|
|
100
|
+
const body = await request.json();
|
|
101
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
102
|
+
const result = await requestUpload({
|
|
103
|
+
provider,
|
|
104
|
+
router: config.router,
|
|
105
|
+
body: body as RequestUploadBody,
|
|
106
|
+
ctxToken,
|
|
107
|
+
});
|
|
108
|
+
return new Response(JSON.stringify(result), {
|
|
109
|
+
status: 200,
|
|
110
|
+
headers: { 'Content-Type': 'application/json' },
|
|
111
|
+
});
|
|
112
|
+
} else if (matchPath(pathname, '/request-upload-parts')) {
|
|
113
|
+
const body = await request.json();
|
|
114
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
115
|
+
const result = await requestUploadParts({
|
|
116
|
+
provider,
|
|
117
|
+
router: config.router,
|
|
118
|
+
body: body as RequestUploadPartsParams,
|
|
119
|
+
ctxToken,
|
|
120
|
+
});
|
|
121
|
+
return new Response(JSON.stringify(result), {
|
|
122
|
+
status: 200,
|
|
123
|
+
headers: { 'Content-Type': 'application/json' },
|
|
124
|
+
});
|
|
125
|
+
} else if (matchPath(pathname, '/complete-multipart-upload')) {
|
|
126
|
+
const body = await request.json();
|
|
127
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
128
|
+
await completeMultipartUpload({
|
|
129
|
+
provider,
|
|
130
|
+
router: config.router,
|
|
131
|
+
body: body as CompleteMultipartUploadBody,
|
|
132
|
+
ctxToken,
|
|
133
|
+
});
|
|
134
|
+
return new Response(null, { status: 200 });
|
|
135
|
+
} else if (matchPath(pathname, '/confirm-upload')) {
|
|
136
|
+
const body = await request.json();
|
|
137
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
138
|
+
const result = await confirmUpload({
|
|
139
|
+
provider,
|
|
140
|
+
router: config.router,
|
|
141
|
+
body: body as ConfirmUploadBody,
|
|
142
|
+
ctxToken,
|
|
143
|
+
});
|
|
144
|
+
return new Response(JSON.stringify(result), {
|
|
145
|
+
status: 200,
|
|
146
|
+
headers: { 'Content-Type': 'application/json' },
|
|
147
|
+
});
|
|
148
|
+
} else if (matchPath(pathname, '/delete-file')) {
|
|
149
|
+
const body = await request.json();
|
|
150
|
+
const ctxToken = getCookie(request, 'edgestore-ctx');
|
|
151
|
+
const result = await deleteFile({
|
|
152
|
+
provider,
|
|
153
|
+
router: config.router,
|
|
154
|
+
body: body as DeleteFileBody,
|
|
155
|
+
ctxToken,
|
|
156
|
+
});
|
|
157
|
+
return new Response(JSON.stringify(result), {
|
|
158
|
+
status: 200,
|
|
159
|
+
headers: { 'Content-Type': 'application/json' },
|
|
160
|
+
});
|
|
161
|
+
} else if (matchPath(pathname, '/proxy-file')) {
|
|
162
|
+
const urlParam = new URL(request.url).searchParams.get('url');
|
|
163
|
+
if (typeof urlParam === 'string') {
|
|
164
|
+
const proxyRes = await fetch(urlParam, {
|
|
165
|
+
headers: {
|
|
166
|
+
cookie: request.headers.get('cookie') ?? '',
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
const data = await proxyRes.arrayBuffer();
|
|
170
|
+
const headers = new Headers();
|
|
171
|
+
headers.set(
|
|
172
|
+
'Content-Type',
|
|
173
|
+
proxyRes.headers.get('Content-Type') ?? 'application/octet-stream',
|
|
174
|
+
);
|
|
175
|
+
return new Response(data, { status: proxyRes.status, 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
|
+
const status =
|
|
187
|
+
EDGE_STORE_ERROR_CODES[err.code as EdgeStoreErrorCodeKey] || 500;
|
|
188
|
+
return new Response(JSON.stringify(err.formattedJson()), {
|
|
189
|
+
status,
|
|
190
|
+
headers: { 'Content-Type': 'application/json' },
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
log.error(err);
|
|
194
|
+
return new Response(
|
|
195
|
+
JSON.stringify(
|
|
196
|
+
new EdgeStoreError({
|
|
197
|
+
message: 'Internal server error',
|
|
198
|
+
code: 'SERVER_ERROR',
|
|
199
|
+
}).formattedJson(),
|
|
200
|
+
),
|
|
201
|
+
{
|
|
202
|
+
status: 500,
|
|
203
|
+
headers: { 'Content-Type': 'application/json' },
|
|
204
|
+
},
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
@@ -2,6 +2,19 @@ import { BlobServiceClient } from '@azure/storage-blob';
|
|
|
2
2
|
import { type Provider } from '@edgestore/shared';
|
|
3
3
|
import { v4 as uuidv4 } from 'uuid';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Options for the Azure provider. Compatible with Azure Blob Storage and Azurite.
|
|
7
|
+
* Use Azure Storage Explorer for local development with Azurite.
|
|
8
|
+
* @see https://azure.microsoft.com/de-de/products/storage/storage-explorer
|
|
9
|
+
* @category Providers
|
|
10
|
+
* @example
|
|
11
|
+
* AzureProvider({
|
|
12
|
+
* storageAccountName: 'devstoreaccount1',
|
|
13
|
+
* sasToken: 'some-generated-token-from-azure-storage-explorer',
|
|
14
|
+
* containerName: 'some-container-name',
|
|
15
|
+
* customBaseUrl: 'http://localhost:10000/devstoreaccount1',
|
|
16
|
+
* })
|
|
17
|
+
*/
|
|
5
18
|
export type AzureProviderOptions = {
|
|
6
19
|
/**
|
|
7
20
|
* The storage account name for Azure Blob Storage
|
|
@@ -18,6 +31,12 @@ export type AzureProviderOptions = {
|
|
|
18
31
|
* Can also be set via the `ES_AZURE_CONTAINER_NAME` environment variable.
|
|
19
32
|
*/
|
|
20
33
|
containerName?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Optional base URL for the Azure Blob Storage.
|
|
36
|
+
* Useful for local development with Azurite. For example: `http://localhost:10000/devstoreaccount1`
|
|
37
|
+
* Can also be set via the `ES_AZURE_BASE_URL` environment variable.
|
|
38
|
+
*/
|
|
39
|
+
customBaseUrl?: string;
|
|
21
40
|
};
|
|
22
41
|
|
|
23
42
|
export function AzureProvider(options?: AzureProviderOptions): Provider {
|
|
@@ -25,9 +44,11 @@ export function AzureProvider(options?: AzureProviderOptions): Provider {
|
|
|
25
44
|
storageAccountName = process.env.ES_AZURE_ACCOUNT_NAME,
|
|
26
45
|
sasToken = process.env.ES_AZURE_SAS_TOKEN,
|
|
27
46
|
containerName = process.env.ES_AZURE_CONTAINER_NAME,
|
|
47
|
+
customBaseUrl = process.env.ES_AZURE_BASE_URL,
|
|
28
48
|
} = options ?? {};
|
|
29
49
|
|
|
30
|
-
const baseUrl =
|
|
50
|
+
const baseUrl =
|
|
51
|
+
customBaseUrl ?? `https://${storageAccountName}.blob.core.windows.net`;
|
|
31
52
|
const blobServiceClient = new BlobServiceClient(`${baseUrl}?${sasToken}`);
|
|
32
53
|
const containerClient = blobServiceClient.getContainerClient(
|
|
33
54
|
containerName ?? '',
|