hydrousdb 3.5.4 → 3.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -5
- package/dist/index.cjs +62 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +62 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -706,7 +706,7 @@ await storage.uploadRaw('<html>…</html>', 'pages/home.html', { mimeType: 'text
|
|
|
706
706
|
|
|
707
707
|
### Large Files with Progress
|
|
708
708
|
|
|
709
|
-
Recommended for files > 10 MB or when you need a progress indicator (
|
|
709
|
+
Recommended for files > 10 MB or when you need a progress indicator (supported in both browser and Node.js environments).
|
|
710
710
|
|
|
711
711
|
```ts
|
|
712
712
|
// Step 1 — get a signed GCS PUT URL
|
|
@@ -719,7 +719,7 @@ const { uploadUrl, path, expiresAt, expiresIn } = await storage.getUploadUrl({
|
|
|
719
719
|
expiresInSeconds: 3600, // URL lifetime
|
|
720
720
|
});
|
|
721
721
|
|
|
722
|
-
// Step 2 — upload directly to GCS with progress callback (browser
|
|
722
|
+
// Step 2 — upload directly to GCS with progress callback (browser & Node.js)
|
|
723
723
|
await storage.uploadToSignedUrl(uploadUrl, file, 'video/mp4', (percent) => {
|
|
724
724
|
console.log(`${percent}% uploaded`);
|
|
725
725
|
});
|
|
@@ -798,7 +798,7 @@ for (const err of failed) {
|
|
|
798
798
|
|
|
799
799
|
---
|
|
800
800
|
|
|
801
|
-
### List
|
|
801
|
+
### List & Metadata
|
|
802
802
|
|
|
803
803
|
```ts
|
|
804
804
|
// List files and folders (paginated)
|
|
@@ -817,12 +817,24 @@ if (hasMore) {
|
|
|
817
817
|
// Get file metadata
|
|
818
818
|
const meta = await storage.getMetadata('avatars/alice.jpg');
|
|
819
819
|
// → { path, size, mimeType, isPublic, publicUrl, downloadUrl, createdAt, updatedAt }
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
---
|
|
823
|
+
|
|
824
|
+
### Temporary Sharing (Signed URLs)
|
|
820
825
|
|
|
821
|
-
|
|
826
|
+
Generate time-limited download URLs for temporary, unauthenticated sharing of private files. Anyone with the URL can access and download the file directly from Google Cloud Storage without needing an `X-Storage-Key` header.
|
|
827
|
+
|
|
828
|
+
*Note: Downloads via signed URLs bypass the Hydrous server entirely (client direct to GCS), meaning download statistics and monthly bandwidth quotas will not be tracked on the server for these requests.*
|
|
829
|
+
|
|
830
|
+
```ts
|
|
822
831
|
const { signedUrl, expiresAt, expiresIn } = await storage.getSignedUrl(
|
|
823
832
|
'private/report.pdf',
|
|
824
|
-
3600, // lifetime in seconds (default: 3600)
|
|
833
|
+
3600, // URL lifetime in seconds (default: 3600 = 1 hour, max: 604800 = 7 days)
|
|
825
834
|
);
|
|
835
|
+
|
|
836
|
+
console.log(signedUrl); // Direct GCS download URL
|
|
837
|
+
console.log(expiresAt); // ISO timestamp of when the link expires
|
|
826
838
|
```
|
|
827
839
|
|
|
828
840
|
---
|
package/dist/index.cjs
CHANGED
|
@@ -152,18 +152,76 @@ var HttpClient = class {
|
|
|
152
152
|
*/
|
|
153
153
|
async putToSignedUrl(signedUrl, data, mimeType, onProgress) {
|
|
154
154
|
const body = data;
|
|
155
|
-
if (typeof XMLHttpRequest !== "undefined"
|
|
155
|
+
if (typeof XMLHttpRequest !== "undefined") {
|
|
156
156
|
await new Promise((resolve, reject) => {
|
|
157
157
|
const xhr = new XMLHttpRequest();
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
if (typeof onProgress === "function") {
|
|
159
|
+
xhr.upload.onprogress = (e) => {
|
|
160
|
+
if (e.lengthComputable) onProgress(Math.round(e.loaded / e.total * 100));
|
|
161
|
+
};
|
|
162
|
+
}
|
|
161
163
|
xhr.onload = () => xhr.status >= 200 && xhr.status < 300 ? resolve() : reject(new Error(`GCS upload failed: ${xhr.status}`));
|
|
162
164
|
xhr.onerror = () => reject(new Error("GCS upload network error"));
|
|
163
165
|
xhr.open("PUT", signedUrl);
|
|
164
166
|
xhr.setRequestHeader("Content-Type", mimeType);
|
|
165
167
|
xhr.send(body);
|
|
166
168
|
});
|
|
169
|
+
} else if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
170
|
+
const https = await import('https');
|
|
171
|
+
const { URL } = await import('url');
|
|
172
|
+
let buffer;
|
|
173
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(body)) {
|
|
174
|
+
buffer = body;
|
|
175
|
+
} else if (body instanceof ArrayBuffer) {
|
|
176
|
+
buffer = Buffer.from(body);
|
|
177
|
+
} else if (body instanceof Uint8Array) {
|
|
178
|
+
buffer = Buffer.from(body.buffer, body.byteOffset, body.byteLength);
|
|
179
|
+
} else if (typeof Blob !== "undefined" && body instanceof Blob) {
|
|
180
|
+
const arrayBuffer = await body.arrayBuffer();
|
|
181
|
+
buffer = Buffer.from(arrayBuffer);
|
|
182
|
+
} else {
|
|
183
|
+
buffer = Buffer.from(String(body));
|
|
184
|
+
}
|
|
185
|
+
const urlObj = new URL(signedUrl);
|
|
186
|
+
const options = {
|
|
187
|
+
method: "PUT",
|
|
188
|
+
hostname: urlObj.hostname,
|
|
189
|
+
path: urlObj.pathname + urlObj.search,
|
|
190
|
+
headers: {
|
|
191
|
+
"Content-Type": mimeType,
|
|
192
|
+
"Content-Length": String(buffer.length)
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
await new Promise((resolve, reject) => {
|
|
196
|
+
const req = https.request(options, (res) => {
|
|
197
|
+
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
198
|
+
resolve();
|
|
199
|
+
} else {
|
|
200
|
+
reject(new Error(`GCS upload failed: ${res.statusCode}`));
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
req.on("error", (err) => {
|
|
204
|
+
reject(err);
|
|
205
|
+
});
|
|
206
|
+
const totalBytes = buffer.length;
|
|
207
|
+
let writtenBytes = 0;
|
|
208
|
+
const chunkSize = 64 * 1024;
|
|
209
|
+
const writeChunk = () => {
|
|
210
|
+
if (writtenBytes < totalBytes) {
|
|
211
|
+
const nextChunkSize = Math.min(chunkSize, totalBytes - writtenBytes);
|
|
212
|
+
const chunk = buffer.subarray(writtenBytes, writtenBytes + nextChunkSize);
|
|
213
|
+
req.write(chunk);
|
|
214
|
+
writtenBytes += nextChunkSize;
|
|
215
|
+
if (typeof onProgress === "function") {
|
|
216
|
+
onProgress(Math.round(writtenBytes / totalBytes * 100));
|
|
217
|
+
}
|
|
218
|
+
setImmediate(writeChunk);
|
|
219
|
+
} else {
|
|
220
|
+
req.end();
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
writeChunk();
|
|
224
|
+
});
|
|
167
225
|
} else {
|
|
168
226
|
const res = await fetch(signedUrl, {
|
|
169
227
|
method: "PUT",
|