@hot-updater/aws 0.30.12 → 0.31.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/dist/iac/index.cjs +0 -1
- package/dist/iac/index.mjs +0 -1
- package/dist/index.cjs +98 -62
- package/dist/index.d.cts +5 -5
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +99 -63
- package/dist/lambda/index.cjs +2411 -697
- package/package.json +8 -8
package/dist/iac/index.cjs
CHANGED
package/dist/iac/index.mjs
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -1531,7 +1531,7 @@ const s3Database = (0, _hot_updater_plugin_core.createBlobDatabasePlugin)({
|
|
|
1531
1531
|
});
|
|
1532
1532
|
//#endregion
|
|
1533
1533
|
//#region src/s3Storage.ts
|
|
1534
|
-
const s3Storage = (0, _hot_updater_plugin_core.
|
|
1534
|
+
const s3Storage = (0, _hot_updater_plugin_core.createUniversalStoragePlugin)({
|
|
1535
1535
|
name: "s3Storage",
|
|
1536
1536
|
supportedProtocol: "s3",
|
|
1537
1537
|
factory: (config) => {
|
|
@@ -1539,59 +1539,89 @@ const s3Storage = (0, _hot_updater_plugin_core.createStoragePlugin)({
|
|
|
1539
1539
|
const client = new _aws_sdk_client_s3.S3Client(applyS3RuntimeAwsConfig(s3Config));
|
|
1540
1540
|
const getStorageKey = (0, _hot_updater_plugin_core.createStorageKeyBuilder)(config.basePath);
|
|
1541
1541
|
return {
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
Prefix: key
|
|
1548
|
-
});
|
|
1549
|
-
const listResponse = await client.send(listCommand);
|
|
1550
|
-
if (listResponse.Contents && listResponse.Contents.length > 0) {
|
|
1551
|
-
const deleteCommand = new _aws_sdk_client_s3.DeleteObjectsCommand({
|
|
1542
|
+
node: {
|
|
1543
|
+
async delete(storageUri) {
|
|
1544
|
+
const { bucket, key } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "s3");
|
|
1545
|
+
if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
|
|
1546
|
+
const listCommand = new _aws_sdk_client_s3.ListObjectsV2Command({
|
|
1552
1547
|
Bucket: bucketName,
|
|
1553
|
-
|
|
1554
|
-
Objects: listResponse.Contents.map((obj) => ({ Key: obj.Key })),
|
|
1555
|
-
Quiet: true
|
|
1556
|
-
}
|
|
1548
|
+
Prefix: key
|
|
1557
1549
|
});
|
|
1558
|
-
await client.send(
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
params: {
|
|
1570
|
-
ContentType,
|
|
1571
|
-
Bucket: bucketName,
|
|
1572
|
-
Key,
|
|
1573
|
-
Body,
|
|
1574
|
-
CacheControl: "max-age=31536000"
|
|
1550
|
+
const listResponse = await client.send(listCommand);
|
|
1551
|
+
if (listResponse.Contents && listResponse.Contents.length > 0) {
|
|
1552
|
+
const deleteCommand = new _aws_sdk_client_s3.DeleteObjectsCommand({
|
|
1553
|
+
Bucket: bucketName,
|
|
1554
|
+
Delete: {
|
|
1555
|
+
Objects: listResponse.Contents.map((obj) => ({ Key: obj.Key })),
|
|
1556
|
+
Quiet: true
|
|
1557
|
+
}
|
|
1558
|
+
});
|
|
1559
|
+
await client.send(deleteCommand);
|
|
1560
|
+
return;
|
|
1575
1561
|
}
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1562
|
+
throw new Error("Bundle Not Found");
|
|
1563
|
+
},
|
|
1564
|
+
async upload(key, filePath) {
|
|
1565
|
+
const Body = await fs_promises.default.readFile(filePath);
|
|
1566
|
+
const ContentType = (0, _hot_updater_plugin_core.getContentType)(filePath);
|
|
1567
|
+
const Key = getStorageKey(key, path.default.basename(filePath));
|
|
1568
|
+
const response = await new _aws_sdk_lib_storage.Upload({
|
|
1569
|
+
client,
|
|
1570
|
+
params: {
|
|
1571
|
+
ContentType,
|
|
1572
|
+
Bucket: bucketName,
|
|
1573
|
+
Key,
|
|
1574
|
+
Body,
|
|
1575
|
+
CacheControl: "max-age=31536000"
|
|
1576
|
+
}
|
|
1577
|
+
}).done();
|
|
1578
|
+
if (!response.Bucket || !response.Key) throw new Error("Upload Failed");
|
|
1579
|
+
return { storageUri: `s3://${bucketName}/${Key}` };
|
|
1580
|
+
},
|
|
1581
|
+
async downloadFile(storageUri, filePath) {
|
|
1582
|
+
const { bucket, key } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "s3");
|
|
1583
|
+
if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
|
|
1584
|
+
const response = await client.send(new _aws_sdk_client_s3.GetObjectCommand({
|
|
1588
1585
|
Bucket: bucket,
|
|
1589
1586
|
Key: key
|
|
1590
|
-
})
|
|
1591
|
-
if (!
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1587
|
+
}));
|
|
1588
|
+
if (!response.Body) throw new Error("S3 object body is empty");
|
|
1589
|
+
await fs_promises.default.mkdir(path.default.dirname(filePath), { recursive: true });
|
|
1590
|
+
await fs_promises.default.writeFile(filePath, await response.Body.transformToByteArray());
|
|
1591
|
+
}
|
|
1592
|
+
},
|
|
1593
|
+
runtime: {
|
|
1594
|
+
async readText(storageUri) {
|
|
1595
|
+
const { bucket, key } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "s3");
|
|
1596
|
+
if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
|
|
1597
|
+
try {
|
|
1598
|
+
const response = await client.send(new _aws_sdk_client_s3.GetObjectCommand({
|
|
1599
|
+
Bucket: bucket,
|
|
1600
|
+
Key: key
|
|
1601
|
+
}));
|
|
1602
|
+
if (!response.Body) return null;
|
|
1603
|
+
return response.Body.transformToString();
|
|
1604
|
+
} catch (error) {
|
|
1605
|
+
if (error instanceof Error && error.name === "NoSuchKey") return null;
|
|
1606
|
+
throw error;
|
|
1607
|
+
}
|
|
1608
|
+
},
|
|
1609
|
+
async getDownloadUrl(storageUri) {
|
|
1610
|
+
const u = new URL(storageUri);
|
|
1611
|
+
if (u.protocol.replace(":", "") !== "s3") throw new Error("Invalid S3 storage URI protocol");
|
|
1612
|
+
const bucket = u.host;
|
|
1613
|
+
const key = u.pathname.slice(1);
|
|
1614
|
+
if (!bucket || !key) throw new Error("Invalid S3 storage URI: missing bucket or key");
|
|
1615
|
+
try {
|
|
1616
|
+
const signedUrl = await (0, _aws_sdk_s3_request_presigner.getSignedUrl)(client, new _aws_sdk_client_s3.GetObjectCommand({
|
|
1617
|
+
Bucket: bucket,
|
|
1618
|
+
Key: key
|
|
1619
|
+
}), { expiresIn: 3600 });
|
|
1620
|
+
if (!signedUrl) throw new Error("Failed to presign S3 URL");
|
|
1621
|
+
return { fileUrl: signedUrl };
|
|
1622
|
+
} catch (e) {
|
|
1623
|
+
throw new Error(e instanceof Error ? `Failed to presign S3 URL: ${e.message}` : "Failed to presign S3 URL");
|
|
1624
|
+
}
|
|
1595
1625
|
}
|
|
1596
1626
|
}
|
|
1597
1627
|
};
|
|
@@ -1643,19 +1673,25 @@ const withCloudFrontSignedUrl = (storageFactory, config) => {
|
|
|
1643
1673
|
return {
|
|
1644
1674
|
...baseStorage,
|
|
1645
1675
|
name: `${baseStorage.name}WithCloudFrontSignedUrl`,
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1676
|
+
profiles: {
|
|
1677
|
+
...baseStorage.profiles,
|
|
1678
|
+
runtime: {
|
|
1679
|
+
...baseStorage.profiles.runtime,
|
|
1680
|
+
async getDownloadUrl(storageUri, context) {
|
|
1681
|
+
const storageUrl = new URL(storageUri);
|
|
1682
|
+
if (storageUrl.protocol !== "s3:") return baseStorage.profiles.runtime.getDownloadUrl(storageUri, context);
|
|
1683
|
+
const [privateKey, publicBaseUrl] = await Promise.all([resolvePrivateKey(config), resolvePublicBaseUrl(config, context)]);
|
|
1684
|
+
const url = new URL(publicBaseUrl);
|
|
1685
|
+
url.pathname = storageUrl.pathname;
|
|
1686
|
+
url.search = "";
|
|
1687
|
+
return { fileUrl: (0, _aws_sdk_cloudfront_signer.getSignedUrl)({
|
|
1688
|
+
url: url.toString(),
|
|
1689
|
+
keyPairId: config.keyPairId,
|
|
1690
|
+
privateKey,
|
|
1691
|
+
dateLessThan: new Date(Date.now() + (config.expiresSeconds ?? ONE_YEAR_IN_SECONDS) * 1e3).toISOString()
|
|
1692
|
+
}) };
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1659
1695
|
}
|
|
1660
1696
|
};
|
|
1661
1697
|
};
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _$_hot_updater_plugin_core0 from "@hot-updater/plugin-core";
|
|
2
|
-
import { BlobDatabasePluginConfig,
|
|
2
|
+
import { BlobDatabasePluginConfig, RuntimeStoragePlugin, StoragePluginHooks, StorageResolveContext } from "@hot-updater/plugin-core";
|
|
3
3
|
import { S3ClientConfig } from "@aws-sdk/client-s3";
|
|
4
4
|
|
|
5
5
|
//#region src/s3Database.d.ts
|
|
@@ -32,7 +32,7 @@ interface S3StorageConfig extends S3ClientConfig {
|
|
|
32
32
|
*/
|
|
33
33
|
basePath?: string;
|
|
34
34
|
}
|
|
35
|
-
declare const s3Storage: (config: S3StorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.
|
|
35
|
+
declare const s3Storage: (config: S3StorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
|
|
36
36
|
//#endregion
|
|
37
37
|
//#region src/withCloudFrontSignedUrl.d.ts
|
|
38
38
|
interface CloudFrontPrivateKeyFromGetter {
|
|
@@ -52,11 +52,11 @@ type WithCloudFrontSignedUrlOptions<TContext = unknown> = CloudFrontSignedUrlCon
|
|
|
52
52
|
publicBaseUrl: string | PublicBaseUrlResolver<TContext>;
|
|
53
53
|
expiresSeconds?: number;
|
|
54
54
|
};
|
|
55
|
-
declare const withCloudFrontSignedUrl: <TContext = unknown>(storageFactory: () =>
|
|
55
|
+
declare const withCloudFrontSignedUrl: <TContext = unknown, TStorage extends RuntimeStoragePlugin<TContext> = RuntimeStoragePlugin<TContext>>(storageFactory: () => TStorage, config: WithCloudFrontSignedUrlOptions<TContext>) => () => TStorage;
|
|
56
56
|
//#endregion
|
|
57
57
|
//#region src/s3LambdaEdgeStorage.d.ts
|
|
58
58
|
type AwsLambdaEdgeStorageConfig = S3StorageConfig & WithCloudFrontSignedUrlOptions;
|
|
59
|
-
declare const awsLambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => _$_hot_updater_plugin_core0.
|
|
60
|
-
declare const s3LambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => _$_hot_updater_plugin_core0.
|
|
59
|
+
declare const awsLambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
|
|
60
|
+
declare const s3LambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
|
|
61
61
|
//#endregion
|
|
62
62
|
export { AwsLambdaEdgeStorageConfig, CloudFrontSignedUrlConfig, PublicBaseUrlResolver, S3DatabaseConfig, S3StorageConfig, WithCloudFrontSignedUrlOptions, awsLambdaEdgeStorage, s3Database, s3LambdaEdgeStorage, s3Storage, withCloudFrontSignedUrl };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S3ClientConfig } from "@aws-sdk/client-s3";
|
|
2
2
|
import * as _$_hot_updater_plugin_core0 from "@hot-updater/plugin-core";
|
|
3
|
-
import { BlobDatabasePluginConfig,
|
|
3
|
+
import { BlobDatabasePluginConfig, RuntimeStoragePlugin, StoragePluginHooks, StorageResolveContext } from "@hot-updater/plugin-core";
|
|
4
4
|
|
|
5
5
|
//#region src/s3Database.d.ts
|
|
6
6
|
interface S3DatabaseConfig extends S3ClientConfig, BlobDatabasePluginConfig {
|
|
@@ -32,7 +32,7 @@ interface S3StorageConfig extends S3ClientConfig {
|
|
|
32
32
|
*/
|
|
33
33
|
basePath?: string;
|
|
34
34
|
}
|
|
35
|
-
declare const s3Storage: (config: S3StorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.
|
|
35
|
+
declare const s3Storage: (config: S3StorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
|
|
36
36
|
//#endregion
|
|
37
37
|
//#region src/withCloudFrontSignedUrl.d.ts
|
|
38
38
|
interface CloudFrontPrivateKeyFromGetter {
|
|
@@ -52,11 +52,11 @@ type WithCloudFrontSignedUrlOptions<TContext = unknown> = CloudFrontSignedUrlCon
|
|
|
52
52
|
publicBaseUrl: string | PublicBaseUrlResolver<TContext>;
|
|
53
53
|
expiresSeconds?: number;
|
|
54
54
|
};
|
|
55
|
-
declare const withCloudFrontSignedUrl: <TContext = unknown>(storageFactory: () =>
|
|
55
|
+
declare const withCloudFrontSignedUrl: <TContext = unknown, TStorage extends RuntimeStoragePlugin<TContext> = RuntimeStoragePlugin<TContext>>(storageFactory: () => TStorage, config: WithCloudFrontSignedUrlOptions<TContext>) => () => TStorage;
|
|
56
56
|
//#endregion
|
|
57
57
|
//#region src/s3LambdaEdgeStorage.d.ts
|
|
58
58
|
type AwsLambdaEdgeStorageConfig = S3StorageConfig & WithCloudFrontSignedUrlOptions;
|
|
59
|
-
declare const awsLambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => _$_hot_updater_plugin_core0.
|
|
60
|
-
declare const s3LambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => _$_hot_updater_plugin_core0.
|
|
59
|
+
declare const awsLambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
|
|
60
|
+
declare const s3LambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
|
|
61
61
|
//#endregion
|
|
62
62
|
export { AwsLambdaEdgeStorageConfig, CloudFrontSignedUrlConfig, PublicBaseUrlResolver, S3DatabaseConfig, S3StorageConfig, WithCloudFrontSignedUrlOptions, awsLambdaEdgeStorage, s3Database, s3LambdaEdgeStorage, s3Storage, withCloudFrontSignedUrl };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CloudFrontClient, CreateInvalidationCommand, GetInvalidationCommand } from "@aws-sdk/client-cloudfront";
|
|
2
2
|
import { DeleteObjectCommand, DeleteObjectsCommand, GetObjectCommand, ListObjectsV2Command, NoSuchKey, S3Client } from "@aws-sdk/client-s3";
|
|
3
3
|
import { Upload } from "@aws-sdk/lib-storage";
|
|
4
|
-
import { createBlobDatabasePlugin, createStorageKeyBuilder,
|
|
4
|
+
import { createBlobDatabasePlugin, createStorageKeyBuilder, createUniversalStoragePlugin, getContentType, parseStorageUri } from "@hot-updater/plugin-core";
|
|
5
5
|
import fs from "fs/promises";
|
|
6
6
|
import path from "path";
|
|
7
7
|
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
@@ -1506,7 +1506,7 @@ const s3Database = createBlobDatabasePlugin({
|
|
|
1506
1506
|
});
|
|
1507
1507
|
//#endregion
|
|
1508
1508
|
//#region src/s3Storage.ts
|
|
1509
|
-
const s3Storage =
|
|
1509
|
+
const s3Storage = createUniversalStoragePlugin({
|
|
1510
1510
|
name: "s3Storage",
|
|
1511
1511
|
supportedProtocol: "s3",
|
|
1512
1512
|
factory: (config) => {
|
|
@@ -1514,59 +1514,89 @@ const s3Storage = createStoragePlugin({
|
|
|
1514
1514
|
const client = new S3Client(applyS3RuntimeAwsConfig(s3Config));
|
|
1515
1515
|
const getStorageKey = createStorageKeyBuilder(config.basePath);
|
|
1516
1516
|
return {
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
Prefix: key
|
|
1523
|
-
});
|
|
1524
|
-
const listResponse = await client.send(listCommand);
|
|
1525
|
-
if (listResponse.Contents && listResponse.Contents.length > 0) {
|
|
1526
|
-
const deleteCommand = new DeleteObjectsCommand({
|
|
1517
|
+
node: {
|
|
1518
|
+
async delete(storageUri) {
|
|
1519
|
+
const { bucket, key } = parseStorageUri(storageUri, "s3");
|
|
1520
|
+
if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
|
|
1521
|
+
const listCommand = new ListObjectsV2Command({
|
|
1527
1522
|
Bucket: bucketName,
|
|
1528
|
-
|
|
1529
|
-
Objects: listResponse.Contents.map((obj) => ({ Key: obj.Key })),
|
|
1530
|
-
Quiet: true
|
|
1531
|
-
}
|
|
1523
|
+
Prefix: key
|
|
1532
1524
|
});
|
|
1533
|
-
await client.send(
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
params: {
|
|
1545
|
-
ContentType,
|
|
1546
|
-
Bucket: bucketName,
|
|
1547
|
-
Key,
|
|
1548
|
-
Body,
|
|
1549
|
-
CacheControl: "max-age=31536000"
|
|
1525
|
+
const listResponse = await client.send(listCommand);
|
|
1526
|
+
if (listResponse.Contents && listResponse.Contents.length > 0) {
|
|
1527
|
+
const deleteCommand = new DeleteObjectsCommand({
|
|
1528
|
+
Bucket: bucketName,
|
|
1529
|
+
Delete: {
|
|
1530
|
+
Objects: listResponse.Contents.map((obj) => ({ Key: obj.Key })),
|
|
1531
|
+
Quiet: true
|
|
1532
|
+
}
|
|
1533
|
+
});
|
|
1534
|
+
await client.send(deleteCommand);
|
|
1535
|
+
return;
|
|
1550
1536
|
}
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1537
|
+
throw new Error("Bundle Not Found");
|
|
1538
|
+
},
|
|
1539
|
+
async upload(key, filePath) {
|
|
1540
|
+
const Body = await fs.readFile(filePath);
|
|
1541
|
+
const ContentType = getContentType(filePath);
|
|
1542
|
+
const Key = getStorageKey(key, path.basename(filePath));
|
|
1543
|
+
const response = await new Upload({
|
|
1544
|
+
client,
|
|
1545
|
+
params: {
|
|
1546
|
+
ContentType,
|
|
1547
|
+
Bucket: bucketName,
|
|
1548
|
+
Key,
|
|
1549
|
+
Body,
|
|
1550
|
+
CacheControl: "max-age=31536000"
|
|
1551
|
+
}
|
|
1552
|
+
}).done();
|
|
1553
|
+
if (!response.Bucket || !response.Key) throw new Error("Upload Failed");
|
|
1554
|
+
return { storageUri: `s3://${bucketName}/${Key}` };
|
|
1555
|
+
},
|
|
1556
|
+
async downloadFile(storageUri, filePath) {
|
|
1557
|
+
const { bucket, key } = parseStorageUri(storageUri, "s3");
|
|
1558
|
+
if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
|
|
1559
|
+
const response = await client.send(new GetObjectCommand({
|
|
1563
1560
|
Bucket: bucket,
|
|
1564
1561
|
Key: key
|
|
1565
|
-
})
|
|
1566
|
-
if (!
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1562
|
+
}));
|
|
1563
|
+
if (!response.Body) throw new Error("S3 object body is empty");
|
|
1564
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
1565
|
+
await fs.writeFile(filePath, await response.Body.transformToByteArray());
|
|
1566
|
+
}
|
|
1567
|
+
},
|
|
1568
|
+
runtime: {
|
|
1569
|
+
async readText(storageUri) {
|
|
1570
|
+
const { bucket, key } = parseStorageUri(storageUri, "s3");
|
|
1571
|
+
if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
|
|
1572
|
+
try {
|
|
1573
|
+
const response = await client.send(new GetObjectCommand({
|
|
1574
|
+
Bucket: bucket,
|
|
1575
|
+
Key: key
|
|
1576
|
+
}));
|
|
1577
|
+
if (!response.Body) return null;
|
|
1578
|
+
return response.Body.transformToString();
|
|
1579
|
+
} catch (error) {
|
|
1580
|
+
if (error instanceof Error && error.name === "NoSuchKey") return null;
|
|
1581
|
+
throw error;
|
|
1582
|
+
}
|
|
1583
|
+
},
|
|
1584
|
+
async getDownloadUrl(storageUri) {
|
|
1585
|
+
const u = new URL(storageUri);
|
|
1586
|
+
if (u.protocol.replace(":", "") !== "s3") throw new Error("Invalid S3 storage URI protocol");
|
|
1587
|
+
const bucket = u.host;
|
|
1588
|
+
const key = u.pathname.slice(1);
|
|
1589
|
+
if (!bucket || !key) throw new Error("Invalid S3 storage URI: missing bucket or key");
|
|
1590
|
+
try {
|
|
1591
|
+
const signedUrl = await getSignedUrl(client, new GetObjectCommand({
|
|
1592
|
+
Bucket: bucket,
|
|
1593
|
+
Key: key
|
|
1594
|
+
}), { expiresIn: 3600 });
|
|
1595
|
+
if (!signedUrl) throw new Error("Failed to presign S3 URL");
|
|
1596
|
+
return { fileUrl: signedUrl };
|
|
1597
|
+
} catch (e) {
|
|
1598
|
+
throw new Error(e instanceof Error ? `Failed to presign S3 URL: ${e.message}` : "Failed to presign S3 URL");
|
|
1599
|
+
}
|
|
1570
1600
|
}
|
|
1571
1601
|
}
|
|
1572
1602
|
};
|
|
@@ -1618,19 +1648,25 @@ const withCloudFrontSignedUrl = (storageFactory, config) => {
|
|
|
1618
1648
|
return {
|
|
1619
1649
|
...baseStorage,
|
|
1620
1650
|
name: `${baseStorage.name}WithCloudFrontSignedUrl`,
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1651
|
+
profiles: {
|
|
1652
|
+
...baseStorage.profiles,
|
|
1653
|
+
runtime: {
|
|
1654
|
+
...baseStorage.profiles.runtime,
|
|
1655
|
+
async getDownloadUrl(storageUri, context) {
|
|
1656
|
+
const storageUrl = new URL(storageUri);
|
|
1657
|
+
if (storageUrl.protocol !== "s3:") return baseStorage.profiles.runtime.getDownloadUrl(storageUri, context);
|
|
1658
|
+
const [privateKey, publicBaseUrl] = await Promise.all([resolvePrivateKey(config), resolvePublicBaseUrl(config, context)]);
|
|
1659
|
+
const url = new URL(publicBaseUrl);
|
|
1660
|
+
url.pathname = storageUrl.pathname;
|
|
1661
|
+
url.search = "";
|
|
1662
|
+
return { fileUrl: getSignedUrl$1({
|
|
1663
|
+
url: url.toString(),
|
|
1664
|
+
keyPairId: config.keyPairId,
|
|
1665
|
+
privateKey,
|
|
1666
|
+
dateLessThan: new Date(Date.now() + (config.expiresSeconds ?? ONE_YEAR_IN_SECONDS) * 1e3).toISOString()
|
|
1667
|
+
}) };
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1634
1670
|
}
|
|
1635
1671
|
};
|
|
1636
1672
|
};
|