@edgestore/server 0.0.0-alpha.12

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.
Files changed (83) hide show
  1. package/README.md +86 -0
  2. package/adapters/next/app/index.d.ts +1 -0
  3. package/adapters/next/app/index.js +1 -0
  4. package/adapters/next/index.d.ts +1 -0
  5. package/adapters/next/index.js +1 -0
  6. package/adapters/next/pages/index.d.ts +1 -0
  7. package/adapters/next/pages/index.js +1 -0
  8. package/core/index.d.ts +1 -0
  9. package/core/index.js +1 -0
  10. package/dist/adapters/imageTypes.d.ts +2 -0
  11. package/dist/adapters/imageTypes.d.ts.map +1 -0
  12. package/dist/adapters/next/app/index.d.ts +14 -0
  13. package/dist/adapters/next/app/index.d.ts.map +1 -0
  14. package/dist/adapters/next/app/index.js +95 -0
  15. package/dist/adapters/next/app/index.mjs +91 -0
  16. package/dist/adapters/next/pages/index.d.ts +15 -0
  17. package/dist/adapters/next/pages/index.d.ts.map +1 -0
  18. package/dist/adapters/next/pages/index.js +69 -0
  19. package/dist/adapters/next/pages/index.mjs +65 -0
  20. package/dist/adapters/shared.d.ts +79 -0
  21. package/dist/adapters/shared.d.ts.map +1 -0
  22. package/dist/core/client/index.d.ts +81 -0
  23. package/dist/core/client/index.d.ts.map +1 -0
  24. package/dist/core/index.d.ts +6 -0
  25. package/dist/core/index.d.ts.map +1 -0
  26. package/dist/core/index.js +96 -0
  27. package/dist/core/index.mjs +91 -0
  28. package/dist/core/internals/bucketBuilder.d.ts +199 -0
  29. package/dist/core/internals/bucketBuilder.d.ts.map +1 -0
  30. package/dist/core/internals/createPathParamProxy.d.ts +21 -0
  31. package/dist/core/internals/createPathParamProxy.d.ts.map +1 -0
  32. package/dist/core/sdk/index.d.ts +200 -0
  33. package/dist/core/sdk/index.d.ts.map +1 -0
  34. package/dist/index-3999aae6.js +187 -0
  35. package/dist/index-3cc4d530.js +183 -0
  36. package/dist/index-ca41982b.mjs +183 -0
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +213 -0
  40. package/dist/index.mjs +209 -0
  41. package/dist/libs/errors/EdgeStoreCredentialsError.d.ts +5 -0
  42. package/dist/libs/errors/EdgeStoreCredentialsError.d.ts.map +1 -0
  43. package/dist/libs/errors/EdgeStoreError.d.ts +16 -0
  44. package/dist/libs/errors/EdgeStoreError.d.ts.map +1 -0
  45. package/dist/providers/aws/index.d.ts +9 -0
  46. package/dist/providers/aws/index.d.ts.map +1 -0
  47. package/dist/providers/aws/index.js +81 -0
  48. package/dist/providers/aws/index.mjs +77 -0
  49. package/dist/providers/edgestore/index.d.ts +8 -0
  50. package/dist/providers/edgestore/index.d.ts.map +1 -0
  51. package/dist/providers/edgestore/index.js +121 -0
  52. package/dist/providers/edgestore/index.mjs +117 -0
  53. package/dist/providers/index.d.ts +3 -0
  54. package/dist/providers/index.d.ts.map +1 -0
  55. package/dist/providers/types.d.ts +91 -0
  56. package/dist/providers/types.d.ts.map +1 -0
  57. package/dist/shared-43667670.mjs +232 -0
  58. package/dist/shared-6bef8919.js +227 -0
  59. package/dist/shared-f7607e44.js +239 -0
  60. package/dist/types.d.ts +88 -0
  61. package/dist/types.d.ts.map +1 -0
  62. package/package.json +96 -0
  63. package/providers/aws/index.d.ts +1 -0
  64. package/providers/aws/index.js +1 -0
  65. package/providers/edgestore/index.d.ts +1 -0
  66. package/providers/edgestore/index.js +1 -0
  67. package/src/adapters/imageTypes.ts +10 -0
  68. package/src/adapters/next/app/index.ts +111 -0
  69. package/src/adapters/next/pages/index.ts +84 -0
  70. package/src/adapters/shared.ts +306 -0
  71. package/src/core/client/index.ts +202 -0
  72. package/src/core/index.ts +10 -0
  73. package/src/core/internals/bucketBuilder.ts +462 -0
  74. package/src/core/internals/createPathParamProxy.ts +40 -0
  75. package/src/core/sdk/index.ts +381 -0
  76. package/src/index.ts +1 -0
  77. package/src/libs/errors/EdgeStoreCredentialsError.ts +12 -0
  78. package/src/libs/errors/EdgeStoreError.ts +25 -0
  79. package/src/providers/aws/index.ts +109 -0
  80. package/src/providers/edgestore/index.ts +140 -0
  81. package/src/providers/index.ts +2 -0
  82. package/src/providers/types.ts +107 -0
  83. package/src/types.ts +139 -0
@@ -0,0 +1,121 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var index = require('../../index-3999aae6.js');
6
+
7
+ const DEFAULT_BASE_URL = process.env.EDGE_STORE_BASE_URL ?? 'https://files.edge-store.com';
8
+ function EdgeStoreProvider(options) {
9
+ const { accessKey = process.env.EDGE_STORE_ACCESS_KEY, secretKey = process.env.EDGE_STORE_SECRET_KEY, baseUrl = process.env.EDGE_STORE_BASE_URL ?? DEFAULT_BASE_URL } = options ?? {};
10
+ if (!accessKey || !secretKey) {
11
+ throw new index.EdgeStoreCredentialsError();
12
+ }
13
+ const edgeStoreSdk = index.initEdgeStoreSdk({
14
+ accessKey,
15
+ secretKey
16
+ });
17
+ return {
18
+ init: async ({ ctx, router })=>{
19
+ const token = await edgeStoreSdk.getToken({
20
+ ctx,
21
+ router
22
+ });
23
+ return {
24
+ token
25
+ };
26
+ },
27
+ getBaseUrl () {
28
+ return baseUrl;
29
+ },
30
+ getFile: async ({ url })=>{
31
+ const { uploadedAt, ...rest } = await edgeStoreSdk.getFile({
32
+ url
33
+ });
34
+ return {
35
+ uploadedAt: new Date(uploadedAt),
36
+ ...rest
37
+ };
38
+ },
39
+ async requestUpload ({ bucketName, bucketType, fileInfo }) {
40
+ // multiplart upload if file is bigger than a certain size
41
+ const MULTIPART_THRESHOLD = 10 * 1024 * 1024; // 10MB
42
+ const CONCURRENCY = 3;
43
+ let partSize = 5 * 1024 * 1024; // 5MB
44
+ if (fileInfo.size > MULTIPART_THRESHOLD) {
45
+ let totalParts = Math.ceil(fileInfo.size / partSize);
46
+ if (totalParts > 10000) {
47
+ // the maximum number of parts is 10000
48
+ totalParts = 10000;
49
+ partSize = Math.ceil(fileInfo.size / totalParts);
50
+ }
51
+ const requestParts = totalParts > CONCURRENCY ? CONCURRENCY : totalParts;
52
+ const res = await edgeStoreSdk.requestUpload({
53
+ bucketName,
54
+ bucketType,
55
+ fileInfo,
56
+ multipart: {
57
+ parts: Array.from({
58
+ length: requestParts
59
+ }).map((_, index)=>index + 1)
60
+ }
61
+ });
62
+ const multipart = res.multipart ? {
63
+ uploadId: res.multipart.uploadId,
64
+ parts: res.multipart.parts.map((part)=>({
65
+ partNumber: part.partNumber,
66
+ uploadUrl: part.signedUrl
67
+ })),
68
+ partSize,
69
+ totalParts
70
+ } : undefined;
71
+ if (multipart) {
72
+ return {
73
+ accessUrl: res.accessUrl,
74
+ multipart
75
+ };
76
+ } else if (res.signedUrl) {
77
+ return {
78
+ accessUrl: res.accessUrl,
79
+ uploadUrl: res.signedUrl
80
+ };
81
+ } else {
82
+ throw new Error('Could not get upload url');
83
+ }
84
+ }
85
+ const res = await edgeStoreSdk.requestUpload({
86
+ bucketName,
87
+ bucketType,
88
+ fileInfo
89
+ });
90
+ if (res.signedUrl) {
91
+ return {
92
+ accessUrl: res.accessUrl,
93
+ uploadUrl: res.signedUrl
94
+ };
95
+ }
96
+ throw new Error('Could not get upload url');
97
+ },
98
+ requestUploadParts: async ({ multipart, path })=>{
99
+ const res = await edgeStoreSdk.requestUploadParts({
100
+ multipart,
101
+ key: path
102
+ });
103
+ return {
104
+ multipart: {
105
+ uploadId: res.multipart.uploadId,
106
+ parts: res.multipart.parts.map((part)=>({
107
+ partNumber: part.partNumber,
108
+ uploadUrl: part.signedUrl
109
+ }))
110
+ }
111
+ };
112
+ },
113
+ deleteFile: async ({ url })=>{
114
+ return await edgeStoreSdk.deleteFile({
115
+ url
116
+ });
117
+ }
118
+ };
119
+ }
120
+
121
+ exports.EdgeStoreProvider = EdgeStoreProvider;
@@ -0,0 +1,117 @@
1
+ import { E as EdgeStoreCredentialsError, i as initEdgeStoreSdk } from '../../index-ca41982b.mjs';
2
+
3
+ const DEFAULT_BASE_URL = process.env.EDGE_STORE_BASE_URL ?? 'https://files.edge-store.com';
4
+ function EdgeStoreProvider(options) {
5
+ const { accessKey = process.env.EDGE_STORE_ACCESS_KEY, secretKey = process.env.EDGE_STORE_SECRET_KEY, baseUrl = process.env.EDGE_STORE_BASE_URL ?? DEFAULT_BASE_URL } = options ?? {};
6
+ if (!accessKey || !secretKey) {
7
+ throw new EdgeStoreCredentialsError();
8
+ }
9
+ const edgeStoreSdk = initEdgeStoreSdk({
10
+ accessKey,
11
+ secretKey
12
+ });
13
+ return {
14
+ init: async ({ ctx, router })=>{
15
+ const token = await edgeStoreSdk.getToken({
16
+ ctx,
17
+ router
18
+ });
19
+ return {
20
+ token
21
+ };
22
+ },
23
+ getBaseUrl () {
24
+ return baseUrl;
25
+ },
26
+ getFile: async ({ url })=>{
27
+ const { uploadedAt, ...rest } = await edgeStoreSdk.getFile({
28
+ url
29
+ });
30
+ return {
31
+ uploadedAt: new Date(uploadedAt),
32
+ ...rest
33
+ };
34
+ },
35
+ async requestUpload ({ bucketName, bucketType, fileInfo }) {
36
+ // multiplart upload if file is bigger than a certain size
37
+ const MULTIPART_THRESHOLD = 10 * 1024 * 1024; // 10MB
38
+ const CONCURRENCY = 3;
39
+ let partSize = 5 * 1024 * 1024; // 5MB
40
+ if (fileInfo.size > MULTIPART_THRESHOLD) {
41
+ let totalParts = Math.ceil(fileInfo.size / partSize);
42
+ if (totalParts > 10000) {
43
+ // the maximum number of parts is 10000
44
+ totalParts = 10000;
45
+ partSize = Math.ceil(fileInfo.size / totalParts);
46
+ }
47
+ const requestParts = totalParts > CONCURRENCY ? CONCURRENCY : totalParts;
48
+ const res = await edgeStoreSdk.requestUpload({
49
+ bucketName,
50
+ bucketType,
51
+ fileInfo,
52
+ multipart: {
53
+ parts: Array.from({
54
+ length: requestParts
55
+ }).map((_, index)=>index + 1)
56
+ }
57
+ });
58
+ const multipart = res.multipart ? {
59
+ uploadId: res.multipart.uploadId,
60
+ parts: res.multipart.parts.map((part)=>({
61
+ partNumber: part.partNumber,
62
+ uploadUrl: part.signedUrl
63
+ })),
64
+ partSize,
65
+ totalParts
66
+ } : undefined;
67
+ if (multipart) {
68
+ return {
69
+ accessUrl: res.accessUrl,
70
+ multipart
71
+ };
72
+ } else if (res.signedUrl) {
73
+ return {
74
+ accessUrl: res.accessUrl,
75
+ uploadUrl: res.signedUrl
76
+ };
77
+ } else {
78
+ throw new Error('Could not get upload url');
79
+ }
80
+ }
81
+ const res = await edgeStoreSdk.requestUpload({
82
+ bucketName,
83
+ bucketType,
84
+ fileInfo
85
+ });
86
+ if (res.signedUrl) {
87
+ return {
88
+ accessUrl: res.accessUrl,
89
+ uploadUrl: res.signedUrl
90
+ };
91
+ }
92
+ throw new Error('Could not get upload url');
93
+ },
94
+ requestUploadParts: async ({ multipart, path })=>{
95
+ const res = await edgeStoreSdk.requestUploadParts({
96
+ multipart,
97
+ key: path
98
+ });
99
+ return {
100
+ multipart: {
101
+ uploadId: res.multipart.uploadId,
102
+ parts: res.multipart.parts.map((part)=>({
103
+ partNumber: part.partNumber,
104
+ uploadUrl: part.signedUrl
105
+ }))
106
+ }
107
+ };
108
+ },
109
+ deleteFile: async ({ url })=>{
110
+ return await edgeStoreSdk.deleteFile({
111
+ url
112
+ });
113
+ }
114
+ };
115
+ }
116
+
117
+ export { EdgeStoreProvider };
@@ -0,0 +1,3 @@
1
+ export * from './aws';
2
+ export * from './edgestore';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,aAAa,CAAC"}
@@ -0,0 +1,91 @@
1
+ import { AnyBuilder, EdgeStoreRouter } from '../core/internals/bucketBuilder';
2
+ import { MaybePromise } from '../types';
3
+ export type InitParams = {
4
+ ctx: any;
5
+ router: EdgeStoreRouter<any>;
6
+ };
7
+ export type InitRes = {
8
+ token?: string;
9
+ };
10
+ export type GetFileParams = {
11
+ url: string;
12
+ };
13
+ export type GetFileRes = {
14
+ url: string;
15
+ size: number;
16
+ uploadedAt: Date;
17
+ path: {
18
+ [key: string]: string;
19
+ };
20
+ metadata: {
21
+ [key: string]: string;
22
+ };
23
+ };
24
+ export type RequestUploadParams = {
25
+ multipart?: {
26
+ uploadId?: string;
27
+ parts: number[];
28
+ };
29
+ bucketName: string;
30
+ bucketType: string;
31
+ fileInfo: {
32
+ size: number;
33
+ extension: string;
34
+ isPublic: boolean;
35
+ path: {
36
+ key: string;
37
+ value: string;
38
+ }[];
39
+ metadata?: {
40
+ [key: string]: string;
41
+ };
42
+ replaceTargetUrl?: string;
43
+ };
44
+ };
45
+ export type RequestUploadPartsParams = {
46
+ multipart: {
47
+ uploadId: string;
48
+ parts: number[];
49
+ };
50
+ path: string;
51
+ };
52
+ export type RequestUploadPartsRes = {
53
+ multipart: {
54
+ uploadId: string;
55
+ parts: {
56
+ partNumber: number;
57
+ uploadUrl: string;
58
+ }[];
59
+ };
60
+ };
61
+ export type RequestUploadRes = {
62
+ uploadUrl: string;
63
+ accessUrl: string;
64
+ } | {
65
+ multipart: {
66
+ uploadId: string;
67
+ partSize: number;
68
+ totalParts: number;
69
+ parts: {
70
+ partNumber: number;
71
+ uploadUrl: string;
72
+ }[];
73
+ };
74
+ accessUrl: string;
75
+ };
76
+ export type DeleteFileParams = {
77
+ bucket: AnyBuilder;
78
+ url: string;
79
+ };
80
+ export type DeleteFileRes = {
81
+ success: boolean;
82
+ };
83
+ export type Provider = {
84
+ init: (params: InitParams) => MaybePromise<InitRes>;
85
+ getBaseUrl: () => MaybePromise<string>;
86
+ getFile: (params: GetFileParams) => MaybePromise<GetFileRes>;
87
+ requestUpload: (params: RequestUploadParams) => MaybePromise<RequestUploadRes>;
88
+ requestUploadParts: (params: RequestUploadPartsParams) => MaybePromise<RequestUploadPartsRes>;
89
+ deleteFile: (params: DeleteFileParams) => MaybePromise<DeleteFileRes>;
90
+ };
91
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,232 @@
1
+ import { hkdf } from '@panva/hkdf';
2
+ import { serialize } from 'cookie';
3
+ import { EncryptJWT, jwtDecrypt } from 'jose';
4
+ import { v4 } from 'uuid';
5
+ import { _ } from '@swc/helpers/_/_define_property';
6
+
7
+ const EDGE_STORE_ERROR_CODES = {
8
+ BAD_REQUEST: 400,
9
+ UNAUTHORIZED: 401
10
+ };
11
+ class EdgeStoreError extends Error {
12
+ constructor(opts){
13
+ super(opts.message);
14
+ _(this, "cause", void 0);
15
+ _(this, "code", void 0);
16
+ this.name = 'EdgeStoreError';
17
+ this.code = opts.code;
18
+ this.cause = opts.cause;
19
+ }
20
+ }
21
+
22
+ const IMAGE_MIME_TYPES = [
23
+ 'image/jpeg',
24
+ 'image/png',
25
+ 'image/gif',
26
+ 'image/webp',
27
+ 'image/svg+xml',
28
+ 'image/tiff',
29
+ 'image/bmp',
30
+ 'image/x-icon'
31
+ ];
32
+
33
+ // TODO: change it to 1 hour when we have a way to refresh the token
34
+ const DEFAULT_MAX_AGE = 30 * 24 * 60 * 60; // 30 days
35
+ async function init(params) {
36
+ const { ctx, provider, router } = params;
37
+ const ctxToken = await encryptJWT(ctx);
38
+ const { token } = await provider.init({
39
+ ctx,
40
+ router: router
41
+ });
42
+ const newCookies = [
43
+ serialize('edgestore-ctx', ctxToken, {
44
+ path: '/',
45
+ maxAge: DEFAULT_MAX_AGE
46
+ })
47
+ ];
48
+ if (token) {
49
+ newCookies.push(serialize('edgestore-token', token, {
50
+ path: '/',
51
+ maxAge: DEFAULT_MAX_AGE
52
+ }));
53
+ }
54
+ const baseUrl = provider.getBaseUrl();
55
+ return {
56
+ newCookies,
57
+ token,
58
+ baseUrl
59
+ };
60
+ }
61
+ async function requestUpload(params) {
62
+ const { provider, router, ctxToken, body: { bucketName, input, fileInfo } } = params;
63
+ if (!ctxToken) {
64
+ throw new EdgeStoreError({
65
+ message: 'Missing edgestore-ctx cookie',
66
+ code: 'UNAUTHORIZED'
67
+ });
68
+ }
69
+ const ctx = await getContext(ctxToken);
70
+ const bucket = router.buckets[bucketName];
71
+ if (!bucket) {
72
+ throw new Error(`Bucket ${bucketName} not found`);
73
+ }
74
+ if (bucket._def.beforeUpload) {
75
+ const canUpload = await bucket._def.beforeUpload?.({
76
+ ctx,
77
+ input,
78
+ fileInfo: {
79
+ size: fileInfo.size,
80
+ type: fileInfo.type,
81
+ extension: fileInfo.extension,
82
+ replaceTargetUrl: fileInfo.replaceTargetUrl
83
+ }
84
+ });
85
+ if (!canUpload) {
86
+ throw new Error('Upload not allowed');
87
+ }
88
+ }
89
+ if (bucket._def.type === 'IMAGE') {
90
+ if (!IMAGE_MIME_TYPES.includes(fileInfo.type)) {
91
+ throw new EdgeStoreError({
92
+ code: 'BAD_REQUEST',
93
+ message: 'Only images are allowed in this bucket'
94
+ });
95
+ }
96
+ }
97
+ const path = buildPath({
98
+ fileInfo,
99
+ bucket,
100
+ pathAttrs: {
101
+ ctx,
102
+ input
103
+ }
104
+ });
105
+ const metadata = await bucket._def.metadata?.({
106
+ ctx,
107
+ input
108
+ });
109
+ const isPublic = bucket._def.accessControl === undefined;
110
+ const requestUploadRes = await provider.requestUpload({
111
+ bucketName,
112
+ bucketType: bucket._def.type,
113
+ fileInfo: {
114
+ ...fileInfo,
115
+ path,
116
+ isPublic,
117
+ metadata
118
+ }
119
+ });
120
+ return {
121
+ ...requestUploadRes,
122
+ size: fileInfo.size,
123
+ uploadedAt: new Date().toISOString(),
124
+ path,
125
+ metadata
126
+ };
127
+ }
128
+ async function requestUploadParts(params) {
129
+ const { provider, router, ctxToken, body: { multipart, path } } = params;
130
+ if (!ctxToken) {
131
+ throw new EdgeStoreError({
132
+ message: 'Missing edgestore-ctx cookie',
133
+ code: 'UNAUTHORIZED'
134
+ });
135
+ }
136
+ await getContext(ctxToken); // just to check if the token is valid
137
+ const bucket = router.buckets[multipart.uploadId];
138
+ if (!bucket) {
139
+ throw new Error(`Bucket ${multipart.uploadId} not found`);
140
+ }
141
+ return await provider.requestUploadParts({
142
+ multipart,
143
+ path
144
+ });
145
+ }
146
+ async function deleteFile(params) {
147
+ const { provider, router, ctxToken, body: { bucketName, url } } = params;
148
+ if (!ctxToken) {
149
+ throw new EdgeStoreError({
150
+ message: 'Missing edgestore-ctx cookie',
151
+ code: 'UNAUTHORIZED'
152
+ });
153
+ }
154
+ const ctx = await getContext(ctxToken);
155
+ const bucket = router.buckets[bucketName];
156
+ if (!bucket) {
157
+ throw new Error(`Bucket ${bucketName} not found`);
158
+ }
159
+ if (!bucket._def.beforeDelete) {
160
+ throw new Error('You need to define beforeDelete if you want to delete files directly from the frontend.');
161
+ }
162
+ const file = await provider.getFile({
163
+ url
164
+ });
165
+ const canDelete = await bucket._def.beforeDelete({
166
+ ctx,
167
+ file
168
+ });
169
+ if (!canDelete) {
170
+ throw new Error('Delete not allowed');
171
+ }
172
+ await provider.deleteFile({
173
+ bucket,
174
+ url
175
+ });
176
+ }
177
+ async function encryptJWT(ctx) {
178
+ const secret = process.env.EDGE_STORE_JWT_SECRET ?? process.env.EDGE_STORE_SECRET_KEY;
179
+ if (!secret) {
180
+ throw new Error('EDGE_STORE_JWT_SECRET or EDGE_STORE_SECRET_KEY is not defined');
181
+ }
182
+ const encryptionSecret = await getDerivedEncryptionKey(secret);
183
+ return await new EncryptJWT(ctx).setProtectedHeader({
184
+ alg: 'dir',
185
+ enc: 'A256GCM'
186
+ }).setIssuedAt().setExpirationTime(Date.now() / 1000 + DEFAULT_MAX_AGE).setJti(v4()).encrypt(encryptionSecret);
187
+ }
188
+ async function decryptJWT(token) {
189
+ const secret = process.env.EDGE_STORE_JWT_SECRET ?? process.env.EDGE_STORE_SECRET_KEY;
190
+ if (!secret) {
191
+ throw new Error('EDGE_STORE_JWT_SECRET or EDGE_STORE_SECRET_KEY is not set');
192
+ }
193
+ const encryptionSecret = await getDerivedEncryptionKey(secret);
194
+ const { payload } = await jwtDecrypt(token, encryptionSecret, {
195
+ clockTolerance: 15
196
+ });
197
+ return payload;
198
+ }
199
+ async function getDerivedEncryptionKey(secret) {
200
+ return await hkdf('sha256', secret, '', 'Edge Store Generated Encryption Key', 32);
201
+ }
202
+ function buildPath(params) {
203
+ const { bucket } = params;
204
+ const pathParams = bucket._def.path;
205
+ const path = pathParams.map((param)=>{
206
+ const paramEntries = Object.entries(param);
207
+ if (paramEntries[0] === undefined) {
208
+ throw new Error('Missing path param');
209
+ }
210
+ const [key, value] = paramEntries[0];
211
+ // this is a string like: "ctx.xxx" or "input.yyy.zzz"
212
+ const currParamVal = value().split('.').reduce((acc2, key)=>{
213
+ if (acc2[key] === undefined) {
214
+ throw new Error(`Missing key ${key} in ${JSON.stringify(acc2)}`);
215
+ }
216
+ return acc2[key];
217
+ }, params.pathAttrs);
218
+ return {
219
+ key,
220
+ value: currParamVal
221
+ };
222
+ });
223
+ return path;
224
+ }
225
+ async function getContext(token) {
226
+ if (!token) {
227
+ throw new Error('No token');
228
+ }
229
+ return await decryptJWT(token);
230
+ }
231
+
232
+ export { EdgeStoreError as E, requestUploadParts as a, EDGE_STORE_ERROR_CODES as b, deleteFile as d, init as i, requestUpload as r };