@edgestore/react 0.6.0-canary.1 → 0.6.0-canary.2

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 (64) hide show
  1. package/dist/contextProvider.d.ts +65 -0
  2. package/dist/contextProvider.d.ts.map +1 -0
  3. package/dist/createNextProxy.d.ts +71 -0
  4. package/dist/createNextProxy.d.ts.map +1 -0
  5. package/dist/errors/index.d.ts +3 -0
  6. package/dist/errors/index.d.ts.map +1 -0
  7. package/dist/errors/index.js +14 -0
  8. package/dist/errors/index.mjs +2 -4
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +488 -0
  12. package/dist/index.mjs +436 -369
  13. package/dist/libs/errors/EdgeStoreClientError.d.ts +5 -0
  14. package/dist/libs/errors/EdgeStoreClientError.d.ts.map +1 -0
  15. package/dist/libs/errors/handleError.d.ts +2 -0
  16. package/dist/libs/errors/handleError.d.ts.map +1 -0
  17. package/dist/libs/errors/uploadAbortedError.d.ts +4 -0
  18. package/dist/libs/errors/uploadAbortedError.d.ts.map +1 -0
  19. package/dist/shared/index.d.ts +7 -0
  20. package/dist/shared/index.d.ts.map +1 -0
  21. package/dist/shared/index.js +13 -0
  22. package/dist/shared/index.mjs +5 -7
  23. package/dist/uploadAbortedError-a628b025.js +8 -0
  24. package/dist/uploadAbortedError-e1379bb0.mjs +8 -0
  25. package/dist/uploadAbortedError-fbfcc57b.js +10 -0
  26. package/dist/utils/{index.d.cts → index.d.ts} +3 -6
  27. package/dist/utils/index.d.ts.map +1 -0
  28. package/dist/utils/index.js +39 -0
  29. package/dist/utils/index.mjs +28 -33
  30. package/errors/index.d.ts +1 -0
  31. package/errors/index.js +1 -0
  32. package/package.json +24 -43
  33. package/shared/index.d.ts +1 -0
  34. package/shared/index.js +1 -0
  35. package/utils/index.d.ts +1 -0
  36. package/utils/index.js +1 -0
  37. package/dist/errors/index.cjs +0 -11
  38. package/dist/errors/index.d.cts +0 -9
  39. package/dist/errors/index.d.cts.map +0 -1
  40. package/dist/errors/index.d.mts +0 -9
  41. package/dist/errors/index.d.mts.map +0 -1
  42. package/dist/index.cjs +0 -425
  43. package/dist/index.d.cts +0 -131
  44. package/dist/index.d.cts.map +0 -1
  45. package/dist/index.d.mts +0 -131
  46. package/dist/index.d.mts.map +0 -1
  47. package/dist/index.mjs.map +0 -1
  48. package/dist/shared/index.cjs +0 -11
  49. package/dist/shared/index.d.cts +0 -11
  50. package/dist/shared/index.d.cts.map +0 -1
  51. package/dist/shared/index.d.mts +0 -11
  52. package/dist/shared/index.d.mts.map +0 -1
  53. package/dist/shared/index.mjs.map +0 -1
  54. package/dist/uploadAbortedError-1Hka0_24.mjs +0 -11
  55. package/dist/uploadAbortedError-1Hka0_24.mjs.map +0 -1
  56. package/dist/uploadAbortedError-CyhLukhg.cjs +0 -16
  57. package/dist/utils/index.cjs +0 -40
  58. package/dist/utils/index.d.cts.map +0 -1
  59. package/dist/utils/index.d.mts +0 -17
  60. package/dist/utils/index.d.mts.map +0 -1
  61. package/dist/utils/index.mjs.map +0 -1
  62. package/errors/package.json +0 -1
  63. package/shared/package.json +0 -1
  64. package/utils/package.json +0 -1
@@ -0,0 +1,65 @@
1
+ import { type AnyRouter } from '@edgestore/shared';
2
+ import * as React from 'react';
3
+ import { type BucketFunctions } from './createNextProxy';
4
+ type EdgeStoreContextValue<TRouter extends AnyRouter> = {
5
+ edgestore: BucketFunctions<TRouter>;
6
+ /**
7
+ * This will re-run the EdgeStore initialization process,
8
+ * which will run the `createContext` function again.
9
+ *
10
+ * Can be used after a sign-in or sign-out, for example.
11
+ */
12
+ reset: () => Promise<void>;
13
+ /**
14
+ * The current state of the EdgeStore provider.
15
+ *
16
+ * You can use this to wait for the provider to be initialized
17
+ * before trying to show private images on your app.
18
+ */
19
+ state: ProviderState;
20
+ };
21
+ export declare function createEdgeStoreProvider<TRouter extends AnyRouter>(opts?: {
22
+ /**
23
+ * The maximum number of concurrent uploads.
24
+ *
25
+ * Uploads will automatically be queued if this limit is reached.
26
+ *
27
+ * @default 5
28
+ */
29
+ maxConcurrentUploads?: number;
30
+ /**
31
+ * Accessing EdgeStore protected files in development mode requires a proxy.
32
+ * You might want to disable this for other providers if you are overwriting the path.
33
+ *
34
+ * @default false
35
+ */
36
+ disableDevProxy?: boolean;
37
+ }): {
38
+ EdgeStoreProvider: ({ children, basePath, }: {
39
+ children: React.ReactNode;
40
+ /**
41
+ * In case your app is not hosted at the root of your domain, you can specify the base path here.
42
+ * If you set this, make sure to set the full path to the EdgeStore API.
43
+ * e.g. `/my-app/api/edgestore` or `https://example.com/my-app/api/edgestore`
44
+ *
45
+ * @example - If your app is hosted at `https://example.com/my-app`, you can set the `basePath` to `/my-app/api/edgestore`.
46
+ */
47
+ basePath?: string;
48
+ }) => React.JSX.Element;
49
+ useEdgeStore: () => EdgeStoreContextValue<TRouter>;
50
+ };
51
+ type ProviderState = {
52
+ loading: true;
53
+ initialized: false;
54
+ error: false;
55
+ } | {
56
+ loading: false;
57
+ initialized: false;
58
+ error: true;
59
+ } | {
60
+ loading: false;
61
+ initialized: true;
62
+ error: false;
63
+ };
64
+ export {};
65
+ //# sourceMappingURL=contextProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contextProvider.d.ts","sourceRoot":"","sources":["../src/contextProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAU1E,KAAK,qBAAqB,CAAC,OAAO,SAAS,SAAS,IAAI;IACtD,SAAS,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACpC;;;;;OAKG;IACH,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B;;;;;OAKG;IACH,KAAK,EAAE,aAAa,CAAC;CACtB,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,OAAO,SAAS,SAAS,EAAE,IAAI,CAAC,EAAE;IACxE;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;iDAQI;QACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;QAC1B;;;;;;WAMG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;;EA+BF;AAED,KAAK,aAAa,GACd;IACE,OAAO,EAAE,IAAI,CAAC;IACd,WAAW,EAAE,KAAK,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;CACd,GACD;IACE,OAAO,EAAE,KAAK,CAAC;IACf,WAAW,EAAE,KAAK,CAAC;IACnB,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,OAAO,EAAE,KAAK,CAAC;IACf,WAAW,EAAE,IAAI,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;CACd,CAAC"}
@@ -0,0 +1,71 @@
1
+ import { type AnyRouter, type InferBucketPathObject, type InferMetadataObject, type UploadOptions } from '@edgestore/shared';
2
+ import { type z } from 'zod';
3
+ /**
4
+ * @internal
5
+ * @see https://www.totaltypescript.com/concepts/the-prettify-helper
6
+ */
7
+ export type Prettify<TType> = {
8
+ [K in keyof TType]: TType[K];
9
+ } & {};
10
+ export type BucketFunctions<TRouter extends AnyRouter> = {
11
+ [K in keyof TRouter['buckets']]: {
12
+ /**
13
+ * Upload a file to the bucket
14
+ *
15
+ * @example
16
+ * await edgestore.myBucket.upload({
17
+ * file: file,
18
+ * signal: abortController.signal, // if you want to be able to cancel the ongoing upload
19
+ * onProgressChange: (progress) => { console.log(progress) }, // if you want to show the progress of the upload
20
+ * input: {...} // if the bucket has an input schema
21
+ * options: {
22
+ * manualFileName: file.name, // if you want to use a custom file name
23
+ * replaceTargetUrl: url, // if you want to replace an existing file
24
+ * temporary: true, // if you want to delete the file after 24 hours
25
+ * }
26
+ * })
27
+ */
28
+ upload: (params: z.infer<TRouter['buckets'][K]['_def']['input']> extends never ? {
29
+ file: File;
30
+ signal?: AbortSignal;
31
+ onProgressChange?: OnProgressChangeHandler;
32
+ options?: UploadOptions;
33
+ } : {
34
+ file: File;
35
+ signal?: AbortSignal;
36
+ input: z.infer<TRouter['buckets'][K]['_def']['input']>;
37
+ onProgressChange?: OnProgressChangeHandler;
38
+ options?: UploadOptions;
39
+ }) => Promise<TRouter['buckets'][K]['_def']['type'] extends 'IMAGE' ? {
40
+ url: string;
41
+ thumbnailUrl: string | null;
42
+ size: number;
43
+ uploadedAt: Date;
44
+ metadata: InferMetadataObject<TRouter['buckets'][K]>;
45
+ path: InferBucketPathObject<TRouter['buckets'][K]>;
46
+ pathOrder: Prettify<keyof InferBucketPathObject<TRouter['buckets'][K]>>[];
47
+ } : {
48
+ url: string;
49
+ size: number;
50
+ uploadedAt: Date;
51
+ metadata: InferMetadataObject<TRouter['buckets'][K]>;
52
+ path: InferBucketPathObject<TRouter['buckets'][K]>;
53
+ pathOrder: Prettify<keyof InferBucketPathObject<TRouter['buckets'][K]>>[];
54
+ }>;
55
+ confirmUpload: (params: {
56
+ url: string;
57
+ }) => Promise<void>;
58
+ delete: (params: {
59
+ url: string;
60
+ }) => Promise<void>;
61
+ };
62
+ };
63
+ type OnProgressChangeHandler = (progress: number) => void;
64
+ export declare function createNextProxy<TRouter extends AnyRouter>({ apiPath, uploadingCountRef, maxConcurrentUploads, disableDevProxy, }: {
65
+ apiPath: string;
66
+ uploadingCountRef: React.MutableRefObject<number>;
67
+ maxConcurrentUploads?: number;
68
+ disableDevProxy?: boolean;
69
+ }): BucketFunctions<TRouter>;
70
+ export {};
71
+ //# sourceMappingURL=createNextProxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createNextProxy.d.ts","sourceRoot":"","sources":["../src/createNextProxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { EdgeStoreApiClientError } from '@edgestore/shared';
2
+ export { UploadAbortedError } from '../libs/errors/uploadAbortedError';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC"}
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var shared = require('@edgestore/shared');
6
+ var uploadAbortedError = require('../uploadAbortedError-fbfcc57b.js');
7
+
8
+
9
+
10
+ Object.defineProperty(exports, 'EdgeStoreApiClientError', {
11
+ enumerable: true,
12
+ get: function () { return shared.EdgeStoreApiClientError; }
13
+ });
14
+ exports.UploadAbortedError = uploadAbortedError.UploadAbortedError;
@@ -1,4 +1,2 @@
1
- import { t as UploadAbortedError } from "../uploadAbortedError-1Hka0_24.mjs";
2
- import { EdgeStoreApiClientError } from "@edgestore/shared";
3
-
4
- export { EdgeStoreApiClientError, UploadAbortedError };
1
+ export { EdgeStoreApiClientError } from '@edgestore/shared';
2
+ export { U as UploadAbortedError } from '../uploadAbortedError-e1379bb0.mjs';
@@ -0,0 +1,2 @@
1
+ export * from './contextProvider';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,488 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React = require('react');
6
+ var shared = require('@edgestore/shared');
7
+ var uploadAbortedError = require('./uploadAbortedError-fbfcc57b.js');
8
+
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule) return e;
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n["default"] = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
28
+
29
+ class EdgeStoreClientError extends Error {
30
+ constructor(message){
31
+ super(message);
32
+ this.name = 'EdgeStoreError';
33
+ }
34
+ }
35
+
36
+ async function handleError(res) {
37
+ let json = {};
38
+ try {
39
+ json = await res.json();
40
+ } catch (err) {
41
+ throw new EdgeStoreClientError(`Failed to parse response. Make sure the api is correctly configured at ${res.url}`);
42
+ }
43
+ throw new shared.EdgeStoreApiClientError({
44
+ response: json
45
+ });
46
+ }
47
+
48
+ function createNextProxy({ apiPath, uploadingCountRef, maxConcurrentUploads = 5, disableDevProxy }) {
49
+ return new Proxy({}, {
50
+ get (_, prop) {
51
+ const bucketName = prop;
52
+ const bucketFunctions = {
53
+ upload: async (params)=>{
54
+ try {
55
+ params.onProgressChange?.(0);
56
+ // This handles the case where the user cancels the upload while it's waiting in the queue
57
+ const abortPromise = new Promise((resolve)=>{
58
+ params.signal?.addEventListener('abort', ()=>{
59
+ resolve();
60
+ }, {
61
+ once: true
62
+ });
63
+ });
64
+ while(uploadingCountRef.current >= maxConcurrentUploads && uploadingCountRef.current > 0){
65
+ await Promise.race([
66
+ new Promise((resolve)=>setTimeout(resolve, 300)),
67
+ abortPromise
68
+ ]);
69
+ if (params.signal?.aborted) {
70
+ throw new uploadAbortedError.UploadAbortedError('File upload aborted');
71
+ }
72
+ }
73
+ uploadingCountRef.current++;
74
+ const fileInfo = await uploadFile(params, {
75
+ bucketName: bucketName,
76
+ apiPath
77
+ }, disableDevProxy);
78
+ return fileInfo;
79
+ } finally{
80
+ uploadingCountRef.current--;
81
+ }
82
+ },
83
+ confirmUpload: async (params)=>{
84
+ const { success } = await confirmUpload(params, {
85
+ bucketName: bucketName,
86
+ apiPath
87
+ });
88
+ if (!success) {
89
+ throw new EdgeStoreClientError('Failed to confirm upload');
90
+ }
91
+ },
92
+ delete: async (params)=>{
93
+ const { success } = await deleteFile(params, {
94
+ bucketName: bucketName,
95
+ apiPath
96
+ });
97
+ if (!success) {
98
+ throw new EdgeStoreClientError('Failed to delete file');
99
+ }
100
+ }
101
+ };
102
+ return bucketFunctions;
103
+ }
104
+ });
105
+ }
106
+ async function uploadFile({ file, signal, input, onProgressChange, options }, { apiPath, bucketName }, disableDevProxy) {
107
+ try {
108
+ onProgressChange?.(0);
109
+ const res = await fetch(`${apiPath}/request-upload`, {
110
+ method: 'POST',
111
+ credentials: 'include',
112
+ signal: signal,
113
+ body: JSON.stringify({
114
+ bucketName,
115
+ input,
116
+ fileInfo: {
117
+ extension: file.name.split('.').pop(),
118
+ type: file.type,
119
+ size: file.size,
120
+ fileName: options?.manualFileName,
121
+ replaceTargetUrl: options?.replaceTargetUrl,
122
+ temporary: options?.temporary
123
+ }
124
+ }),
125
+ headers: {
126
+ 'Content-Type': 'application/json'
127
+ }
128
+ });
129
+ if (!res.ok) {
130
+ await handleError(res);
131
+ }
132
+ const json = await res.json();
133
+ if ('multipart' in json) {
134
+ await multipartUpload({
135
+ bucketName,
136
+ multipartInfo: json.multipart,
137
+ onProgressChange,
138
+ signal,
139
+ file,
140
+ apiPath
141
+ });
142
+ } else if ('uploadUrl' in json) {
143
+ // Single part upload
144
+ // Upload the file to the signed URL and get the progress
145
+ await uploadFileInner({
146
+ file,
147
+ uploadUrl: json.uploadUrl,
148
+ onProgressChange,
149
+ signal
150
+ });
151
+ } else {
152
+ throw new EdgeStoreClientError('An error occurred');
153
+ }
154
+ return {
155
+ url: getUrl(json.accessUrl, apiPath, disableDevProxy),
156
+ thumbnailUrl: json.thumbnailUrl ? getUrl(json.thumbnailUrl, apiPath, disableDevProxy) : null,
157
+ size: json.size,
158
+ uploadedAt: new Date(json.uploadedAt),
159
+ path: json.path,
160
+ pathOrder: json.pathOrder,
161
+ metadata: json.metadata
162
+ };
163
+ } catch (e) {
164
+ if (e instanceof Error && e.name === 'AbortError') {
165
+ throw new uploadAbortedError.UploadAbortedError('File upload aborted');
166
+ }
167
+ onProgressChange?.(0);
168
+ throw e;
169
+ }
170
+ }
171
+ /**
172
+ * Protected files need third-party cookies to work.
173
+ * Since third party cookies don't work on localhost,
174
+ * we need to proxy the file through the server.
175
+ */ function getUrl(url, apiPath, disableDevProxy) {
176
+ const mode = typeof process !== 'undefined' ? process.env.NODE_ENV : undefined?.DEV ? 'development' : 'production';
177
+ if (mode === 'development' && !url.includes('/_public/') && !disableDevProxy) {
178
+ const proxyUrl = new URL(window.location.origin);
179
+ proxyUrl.pathname = `${apiPath}/proxy-file`;
180
+ proxyUrl.search = new URLSearchParams({
181
+ url
182
+ }).toString();
183
+ return proxyUrl.toString();
184
+ }
185
+ return url;
186
+ }
187
+ async function uploadFileInner(props) {
188
+ const { file, uploadUrl, onProgressChange, signal } = props;
189
+ const promise = new Promise((resolve, reject)=>{
190
+ if (signal?.aborted) {
191
+ reject(new uploadAbortedError.UploadAbortedError('File upload aborted'));
192
+ return;
193
+ }
194
+ const request = new XMLHttpRequest();
195
+ request.open('PUT', uploadUrl);
196
+ // This is for Azure provider. Specifies the blob type
197
+ request.setRequestHeader('x-ms-blob-type', 'BlockBlob');
198
+ request.addEventListener('loadstart', ()=>{
199
+ onProgressChange?.(0);
200
+ });
201
+ request.upload.addEventListener('progress', (e)=>{
202
+ if (e.lengthComputable) {
203
+ // 2 decimal progress
204
+ const progress = Math.round(e.loaded / e.total * 10000) / 100;
205
+ onProgressChange?.(progress);
206
+ }
207
+ });
208
+ request.addEventListener('error', ()=>{
209
+ reject(new Error('Error uploading file'));
210
+ });
211
+ request.addEventListener('abort', ()=>{
212
+ reject(new uploadAbortedError.UploadAbortedError('File upload aborted'));
213
+ });
214
+ request.addEventListener('loadend', ()=>{
215
+ // Return the ETag header (needed to complete multipart upload)
216
+ resolve(request.getResponseHeader('ETag'));
217
+ });
218
+ if (signal) {
219
+ signal.addEventListener('abort', ()=>{
220
+ request.abort();
221
+ });
222
+ }
223
+ request.send(file);
224
+ });
225
+ return promise;
226
+ }
227
+ async function multipartUpload(params) {
228
+ const { bucketName, multipartInfo, onProgressChange, file, signal, apiPath } = params;
229
+ const { partSize, parts, totalParts, uploadId, key } = multipartInfo;
230
+ const uploadingParts = [];
231
+ const uploadPart = async (params)=>{
232
+ const { part, chunk } = params;
233
+ const { uploadUrl } = part;
234
+ const eTag = await uploadFileInner({
235
+ file: chunk,
236
+ uploadUrl,
237
+ signal,
238
+ onProgressChange: (progress)=>{
239
+ const uploadingPart = uploadingParts.find((p)=>p.partNumber === part.partNumber);
240
+ if (uploadingPart) {
241
+ uploadingPart.progress = progress;
242
+ } else {
243
+ uploadingParts.push({
244
+ partNumber: part.partNumber,
245
+ progress
246
+ });
247
+ }
248
+ const totalProgress = Math.round(uploadingParts.reduce((acc, p)=>acc + p.progress * 100, 0) / totalParts) / 100;
249
+ onProgressChange?.(totalProgress);
250
+ }
251
+ });
252
+ if (!eTag) {
253
+ throw new EdgeStoreClientError('Could not get ETag from multipart response');
254
+ }
255
+ return {
256
+ partNumber: part.partNumber,
257
+ eTag
258
+ };
259
+ };
260
+ // Upload the parts in parallel
261
+ const completedParts = await queuedPromises({
262
+ items: parts.map((part)=>({
263
+ part,
264
+ chunk: file.slice((part.partNumber - 1) * partSize, part.partNumber * partSize)
265
+ })),
266
+ fn: uploadPart,
267
+ maxParallel: 5,
268
+ maxRetries: 10
269
+ });
270
+ // Complete multipart upload
271
+ const res = await fetch(`${apiPath}/complete-multipart-upload`, {
272
+ method: 'POST',
273
+ credentials: 'include',
274
+ body: JSON.stringify({
275
+ bucketName,
276
+ uploadId,
277
+ key,
278
+ parts: completedParts
279
+ }),
280
+ headers: {
281
+ 'Content-Type': 'application/json'
282
+ }
283
+ });
284
+ if (!res.ok) {
285
+ await handleError(res);
286
+ }
287
+ }
288
+ async function confirmUpload({ url }, { apiPath, bucketName }) {
289
+ const res = await fetch(`${apiPath}/confirm-upload`, {
290
+ method: 'POST',
291
+ credentials: 'include',
292
+ body: JSON.stringify({
293
+ url,
294
+ bucketName
295
+ }),
296
+ headers: {
297
+ 'Content-Type': 'application/json'
298
+ }
299
+ });
300
+ if (!res.ok) {
301
+ await handleError(res);
302
+ }
303
+ return res.json();
304
+ }
305
+ async function deleteFile({ url }, { apiPath, bucketName }) {
306
+ const res = await fetch(`${apiPath}/delete-file`, {
307
+ method: 'POST',
308
+ credentials: 'include',
309
+ body: JSON.stringify({
310
+ url,
311
+ bucketName
312
+ }),
313
+ headers: {
314
+ 'Content-Type': 'application/json'
315
+ }
316
+ });
317
+ if (!res.ok) {
318
+ await handleError(res);
319
+ }
320
+ return res.json();
321
+ }
322
+ async function queuedPromises({ items, fn, maxParallel, maxRetries = 0 }) {
323
+ const results = new Array(items.length);
324
+ const executeWithRetry = async (func, retries)=>{
325
+ try {
326
+ return await func();
327
+ } catch (error) {
328
+ if (error instanceof uploadAbortedError.UploadAbortedError) {
329
+ throw error;
330
+ }
331
+ if (retries > 0) {
332
+ await new Promise((resolve)=>setTimeout(resolve, 5000));
333
+ return executeWithRetry(func, retries - 1);
334
+ } else {
335
+ throw error;
336
+ }
337
+ }
338
+ };
339
+ const semaphore = {
340
+ count: maxParallel,
341
+ async wait () {
342
+ // If we've reached our maximum concurrency, or it's the last item, wait
343
+ while(this.count <= 0)await new Promise((resolve)=>setTimeout(resolve, 500));
344
+ this.count--;
345
+ },
346
+ signal () {
347
+ this.count++;
348
+ }
349
+ };
350
+ const tasks = items.map((item, i)=>(async ()=>{
351
+ await semaphore.wait();
352
+ try {
353
+ const result = await executeWithRetry(()=>fn(item), maxRetries);
354
+ results[i] = result;
355
+ } finally{
356
+ semaphore.signal();
357
+ }
358
+ })());
359
+ await Promise.all(tasks);
360
+ return results;
361
+ }
362
+
363
+ const DEFAULT_BASE_URL = (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_EDGE_STORE_BASE_URL : undefined?.EDGE_STORE_BASE_URL) ?? 'https://files.edgestore.dev';
364
+ function createEdgeStoreProvider(opts) {
365
+ const EdgeStoreContext = /*#__PURE__*/ React__namespace.createContext(undefined);
366
+ const EdgeStoreProvider = ({ children, basePath })=>{
367
+ return EdgeStoreProviderInner({
368
+ children,
369
+ context: EdgeStoreContext,
370
+ basePath,
371
+ maxConcurrentUploads: opts?.maxConcurrentUploads,
372
+ disableDevProxy: opts?.disableDevProxy
373
+ });
374
+ };
375
+ function useEdgeStore() {
376
+ if (!EdgeStoreContext) {
377
+ throw new Error('React Context is unavailable in Server Components');
378
+ }
379
+ // @ts-expect-error - We know that the context value should not be undefined
380
+ const value = React__namespace.useContext(EdgeStoreContext);
381
+ if (!value && process.env.NODE_ENV !== 'production') {
382
+ throw new Error('[edgestore]: `useEdgeStore` must be wrapped in a <EdgeStoreProvider />');
383
+ }
384
+ return value;
385
+ }
386
+ return {
387
+ EdgeStoreProvider,
388
+ useEdgeStore
389
+ };
390
+ }
391
+ function EdgeStoreProviderInner({ children, context, basePath, maxConcurrentUploads, disableDevProxy }) {
392
+ const apiPath = basePath ? `${basePath}` : '/api/edgestore';
393
+ const [state, setState] = React__namespace.useState({
394
+ loading: true,
395
+ initialized: false,
396
+ error: false
397
+ });
398
+ const uploadingCountRef = React__namespace.useRef(0);
399
+ const initExecuted = React__namespace.useRef(false); // to make sure we don't run init twice
400
+ React__namespace.useEffect(()=>{
401
+ if (!initExecuted.current) {
402
+ void init();
403
+ }
404
+ return ()=>{
405
+ initExecuted.current = true;
406
+ };
407
+ // eslint-disable-next-line react-hooks/exhaustive-deps
408
+ }, []);
409
+ async function init() {
410
+ try {
411
+ setState({
412
+ loading: true,
413
+ initialized: false,
414
+ error: false
415
+ });
416
+ const res = await fetch(`${apiPath}/init`, {
417
+ method: 'POST',
418
+ credentials: 'include'
419
+ });
420
+ if (res.ok) {
421
+ const json = await res.json();
422
+ // Only call _init API if provider is edgestore
423
+ if (json.providerName === 'edgestore') {
424
+ const innerRes = await fetch(`${DEFAULT_BASE_URL}/_init`, {
425
+ method: 'GET',
426
+ credentials: 'include',
427
+ headers: {
428
+ 'x-edgestore-token': json.token
429
+ }
430
+ });
431
+ if (innerRes.ok) {
432
+ // update state
433
+ setState({
434
+ loading: false,
435
+ initialized: true,
436
+ error: false
437
+ });
438
+ } else {
439
+ setState({
440
+ loading: false,
441
+ initialized: false,
442
+ error: true
443
+ });
444
+ throw new EdgeStoreClientError("Couldn't initialize EdgeStore.");
445
+ }
446
+ } else {
447
+ // For non-edgestore providers, just update state without calling _init
448
+ setState({
449
+ loading: false,
450
+ initialized: true,
451
+ error: false
452
+ });
453
+ }
454
+ } else {
455
+ setState({
456
+ loading: false,
457
+ initialized: false,
458
+ error: true
459
+ });
460
+ await handleError(res);
461
+ }
462
+ } catch (err) {
463
+ setState({
464
+ loading: false,
465
+ initialized: false,
466
+ error: true
467
+ });
468
+ throw err;
469
+ }
470
+ }
471
+ async function reset() {
472
+ await init();
473
+ }
474
+ return /*#__PURE__*/ React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/ React__namespace.createElement(context.Provider, {
475
+ value: {
476
+ edgestore: createNextProxy({
477
+ apiPath,
478
+ uploadingCountRef,
479
+ maxConcurrentUploads,
480
+ disableDevProxy
481
+ }),
482
+ reset,
483
+ state
484
+ }
485
+ }, children));
486
+ }
487
+
488
+ exports.createEdgeStoreProvider = createEdgeStoreProvider;