@hot-updater/aws 0.0.1 → 0.1.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/dist/index.cjs +184 -0
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +155 -0
- package/package.json +10 -4
- package/src/aws.ts +173 -0
- package/src/index.ts +1 -0
- package/src/utils/readDir.ts +11 -0
- package/src/utils/streamToString.ts +8 -0
- package/tsconfig.json +3 -17
- package/global.d.ts +0 -1
- package/lib/read.d.ts +0 -3
- package/lib/read.js +0 -23
- package/src/read.ts +0 -28
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
aws: () => aws
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(src_exports);
|
|
36
|
+
|
|
37
|
+
// src/aws.ts
|
|
38
|
+
var import_path = __toESM(require("path"), 1);
|
|
39
|
+
var import_client_s3 = require("@aws-sdk/client-s3");
|
|
40
|
+
var import_lib_storage = require("@aws-sdk/lib-storage");
|
|
41
|
+
var import_plugin_core = require("@hot-updater/plugin-core");
|
|
42
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
43
|
+
var import_mime = __toESM(require("mime"), 1);
|
|
44
|
+
|
|
45
|
+
// src/utils/streamToString.ts
|
|
46
|
+
var streamToString = (stream) => {
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
const chunks = [];
|
|
49
|
+
stream.on("data", (chunk) => chunks.push(chunk));
|
|
50
|
+
stream.on("error", reject);
|
|
51
|
+
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// src/aws.ts
|
|
56
|
+
var aws = (config) => (_) => {
|
|
57
|
+
const { bucketName, ...s3Config } = config;
|
|
58
|
+
const client = new import_client_s3.S3Client(s3Config);
|
|
59
|
+
let updateSources = [];
|
|
60
|
+
return {
|
|
61
|
+
async commitUpdateSource() {
|
|
62
|
+
try {
|
|
63
|
+
const command = new import_client_s3.GetObjectCommand({
|
|
64
|
+
Bucket: bucketName,
|
|
65
|
+
Key: "update.json"
|
|
66
|
+
});
|
|
67
|
+
await client.send(command);
|
|
68
|
+
} catch (e) {
|
|
69
|
+
if (e instanceof import_client_s3.NoSuchKey) {
|
|
70
|
+
import_plugin_core.log.info("Creating new update.json");
|
|
71
|
+
} else {
|
|
72
|
+
throw e;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
import_plugin_core.log.info("Uploading update.json");
|
|
76
|
+
const Key = "update.json";
|
|
77
|
+
const Body = JSON.stringify(updateSources);
|
|
78
|
+
const ContentType = import_mime.default.getType(Key) ?? void 0;
|
|
79
|
+
const upload = new import_lib_storage.Upload({
|
|
80
|
+
client,
|
|
81
|
+
params: {
|
|
82
|
+
ContentType,
|
|
83
|
+
Bucket: bucketName,
|
|
84
|
+
Key,
|
|
85
|
+
Body
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
await upload.done();
|
|
89
|
+
},
|
|
90
|
+
async updateUpdateSource(targetBundleVersion, newSource) {
|
|
91
|
+
updateSources = await this.getUpdateSources();
|
|
92
|
+
const targetIndex = updateSources.findIndex(
|
|
93
|
+
(u) => u.bundleVersion === targetBundleVersion
|
|
94
|
+
);
|
|
95
|
+
if (targetIndex === -1) {
|
|
96
|
+
throw new Error("target bundle version not found");
|
|
97
|
+
}
|
|
98
|
+
Object.assign(updateSources[targetIndex], newSource);
|
|
99
|
+
},
|
|
100
|
+
async appendUpdateSource(source) {
|
|
101
|
+
updateSources = await this.getUpdateSources();
|
|
102
|
+
updateSources.unshift(source);
|
|
103
|
+
},
|
|
104
|
+
async setUpdateSources(sources) {
|
|
105
|
+
updateSources = sources;
|
|
106
|
+
},
|
|
107
|
+
async getUpdateSources(refresh = false) {
|
|
108
|
+
if (updateSources.length > 0 && !refresh) {
|
|
109
|
+
return updateSources;
|
|
110
|
+
}
|
|
111
|
+
import_plugin_core.log.info("Getting update.json");
|
|
112
|
+
try {
|
|
113
|
+
const command = new import_client_s3.GetObjectCommand({
|
|
114
|
+
Bucket: bucketName,
|
|
115
|
+
Key: "update.json"
|
|
116
|
+
});
|
|
117
|
+
const { Body: UpdateJsonBody } = await client.send(command);
|
|
118
|
+
const bodyContents = await streamToString(UpdateJsonBody);
|
|
119
|
+
const _updateSource = JSON.parse(bodyContents);
|
|
120
|
+
updateSources = _updateSource;
|
|
121
|
+
return _updateSource;
|
|
122
|
+
} catch (e) {
|
|
123
|
+
if (e instanceof import_client_s3.NoSuchKey) {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
throw e;
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
async deleteBundle(platform, bundleVersion) {
|
|
130
|
+
const Key = [bundleVersion, platform].join("/");
|
|
131
|
+
const listCommand = new import_client_s3.ListObjectsV2Command({
|
|
132
|
+
Bucket: bucketName,
|
|
133
|
+
Prefix: `${bundleVersion}/${platform}`
|
|
134
|
+
});
|
|
135
|
+
const listResponse = await client.send(listCommand);
|
|
136
|
+
if (listResponse.Contents && listResponse.Contents.length > 0) {
|
|
137
|
+
const objectsToDelete = listResponse.Contents.map((obj) => ({
|
|
138
|
+
Key: obj.Key
|
|
139
|
+
}));
|
|
140
|
+
const deleteParams = {
|
|
141
|
+
Bucket: bucketName,
|
|
142
|
+
Delete: {
|
|
143
|
+
Objects: objectsToDelete,
|
|
144
|
+
Quiet: true
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
const deleteCommand = new import_client_s3.DeleteObjectsCommand(deleteParams);
|
|
148
|
+
await client.send(deleteCommand);
|
|
149
|
+
return Key;
|
|
150
|
+
}
|
|
151
|
+
import_plugin_core.log.error("Bundle Not Found");
|
|
152
|
+
throw new Error("Bundle Not Found");
|
|
153
|
+
},
|
|
154
|
+
async uploadBundle(platform, bundleVersion, bundlePath) {
|
|
155
|
+
import_plugin_core.log.info("Uploading Bundle");
|
|
156
|
+
const Body = await import_promises.default.readFile(bundlePath);
|
|
157
|
+
const ContentType = import_mime.default.getType(bundlePath) ?? void 0;
|
|
158
|
+
const filename = import_path.default.basename(bundlePath);
|
|
159
|
+
const Key = [bundleVersion, platform, filename].join("/");
|
|
160
|
+
const upload = new import_lib_storage.Upload({
|
|
161
|
+
client,
|
|
162
|
+
params: {
|
|
163
|
+
ContentType,
|
|
164
|
+
Bucket: bucketName,
|
|
165
|
+
Key,
|
|
166
|
+
Body
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
const response = await upload.done();
|
|
170
|
+
if (!response.Location) {
|
|
171
|
+
import_plugin_core.log.error("Upload Failed");
|
|
172
|
+
throw new Error("Upload Failed");
|
|
173
|
+
}
|
|
174
|
+
import_plugin_core.log?.info(`Uploaded: ${Key}`);
|
|
175
|
+
return {
|
|
176
|
+
file: response.Location
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
182
|
+
0 && (module.exports = {
|
|
183
|
+
aws
|
|
184
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { S3ClientConfig } from '@aws-sdk/client-s3';
|
|
2
|
+
import { BasePluginArgs, DeployPlugin } from '@hot-updater/plugin-core';
|
|
3
|
+
|
|
4
|
+
interface AwsConfig extends Pick<S3ClientConfig, "credentials" | "region"> {
|
|
5
|
+
bucketName: string;
|
|
6
|
+
}
|
|
7
|
+
declare const aws: (config: AwsConfig) => (_: BasePluginArgs) => DeployPlugin;
|
|
8
|
+
|
|
9
|
+
export { type AwsConfig, aws };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { S3ClientConfig } from '@aws-sdk/client-s3';
|
|
2
|
+
import { BasePluginArgs, DeployPlugin } from '@hot-updater/plugin-core';
|
|
3
|
+
|
|
4
|
+
interface AwsConfig extends Pick<S3ClientConfig, "credentials" | "region"> {
|
|
5
|
+
bucketName: string;
|
|
6
|
+
}
|
|
7
|
+
declare const aws: (config: AwsConfig) => (_: BasePluginArgs) => DeployPlugin;
|
|
8
|
+
|
|
9
|
+
export { type AwsConfig, aws };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// src/aws.ts
|
|
2
|
+
import path from "path";
|
|
3
|
+
import {
|
|
4
|
+
DeleteObjectsCommand,
|
|
5
|
+
GetObjectCommand,
|
|
6
|
+
ListObjectsV2Command,
|
|
7
|
+
NoSuchKey,
|
|
8
|
+
S3Client
|
|
9
|
+
} from "@aws-sdk/client-s3";
|
|
10
|
+
import { Upload } from "@aws-sdk/lib-storage";
|
|
11
|
+
import {
|
|
12
|
+
log
|
|
13
|
+
} from "@hot-updater/plugin-core";
|
|
14
|
+
import fs from "fs/promises";
|
|
15
|
+
import mime from "mime";
|
|
16
|
+
|
|
17
|
+
// src/utils/streamToString.ts
|
|
18
|
+
var streamToString = (stream) => {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
const chunks = [];
|
|
21
|
+
stream.on("data", (chunk) => chunks.push(chunk));
|
|
22
|
+
stream.on("error", reject);
|
|
23
|
+
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// src/aws.ts
|
|
28
|
+
var aws = (config) => (_) => {
|
|
29
|
+
const { bucketName, ...s3Config } = config;
|
|
30
|
+
const client = new S3Client(s3Config);
|
|
31
|
+
let updateSources = [];
|
|
32
|
+
return {
|
|
33
|
+
async commitUpdateSource() {
|
|
34
|
+
try {
|
|
35
|
+
const command = new GetObjectCommand({
|
|
36
|
+
Bucket: bucketName,
|
|
37
|
+
Key: "update.json"
|
|
38
|
+
});
|
|
39
|
+
await client.send(command);
|
|
40
|
+
} catch (e) {
|
|
41
|
+
if (e instanceof NoSuchKey) {
|
|
42
|
+
log.info("Creating new update.json");
|
|
43
|
+
} else {
|
|
44
|
+
throw e;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
log.info("Uploading update.json");
|
|
48
|
+
const Key = "update.json";
|
|
49
|
+
const Body = JSON.stringify(updateSources);
|
|
50
|
+
const ContentType = mime.getType(Key) ?? void 0;
|
|
51
|
+
const upload = new Upload({
|
|
52
|
+
client,
|
|
53
|
+
params: {
|
|
54
|
+
ContentType,
|
|
55
|
+
Bucket: bucketName,
|
|
56
|
+
Key,
|
|
57
|
+
Body
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
await upload.done();
|
|
61
|
+
},
|
|
62
|
+
async updateUpdateSource(targetBundleVersion, newSource) {
|
|
63
|
+
updateSources = await this.getUpdateSources();
|
|
64
|
+
const targetIndex = updateSources.findIndex(
|
|
65
|
+
(u) => u.bundleVersion === targetBundleVersion
|
|
66
|
+
);
|
|
67
|
+
if (targetIndex === -1) {
|
|
68
|
+
throw new Error("target bundle version not found");
|
|
69
|
+
}
|
|
70
|
+
Object.assign(updateSources[targetIndex], newSource);
|
|
71
|
+
},
|
|
72
|
+
async appendUpdateSource(source) {
|
|
73
|
+
updateSources = await this.getUpdateSources();
|
|
74
|
+
updateSources.unshift(source);
|
|
75
|
+
},
|
|
76
|
+
async setUpdateSources(sources) {
|
|
77
|
+
updateSources = sources;
|
|
78
|
+
},
|
|
79
|
+
async getUpdateSources(refresh = false) {
|
|
80
|
+
if (updateSources.length > 0 && !refresh) {
|
|
81
|
+
return updateSources;
|
|
82
|
+
}
|
|
83
|
+
log.info("Getting update.json");
|
|
84
|
+
try {
|
|
85
|
+
const command = new GetObjectCommand({
|
|
86
|
+
Bucket: bucketName,
|
|
87
|
+
Key: "update.json"
|
|
88
|
+
});
|
|
89
|
+
const { Body: UpdateJsonBody } = await client.send(command);
|
|
90
|
+
const bodyContents = await streamToString(UpdateJsonBody);
|
|
91
|
+
const _updateSource = JSON.parse(bodyContents);
|
|
92
|
+
updateSources = _updateSource;
|
|
93
|
+
return _updateSource;
|
|
94
|
+
} catch (e) {
|
|
95
|
+
if (e instanceof NoSuchKey) {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
throw e;
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
async deleteBundle(platform, bundleVersion) {
|
|
102
|
+
const Key = [bundleVersion, platform].join("/");
|
|
103
|
+
const listCommand = new ListObjectsV2Command({
|
|
104
|
+
Bucket: bucketName,
|
|
105
|
+
Prefix: `${bundleVersion}/${platform}`
|
|
106
|
+
});
|
|
107
|
+
const listResponse = await client.send(listCommand);
|
|
108
|
+
if (listResponse.Contents && listResponse.Contents.length > 0) {
|
|
109
|
+
const objectsToDelete = listResponse.Contents.map((obj) => ({
|
|
110
|
+
Key: obj.Key
|
|
111
|
+
}));
|
|
112
|
+
const deleteParams = {
|
|
113
|
+
Bucket: bucketName,
|
|
114
|
+
Delete: {
|
|
115
|
+
Objects: objectsToDelete,
|
|
116
|
+
Quiet: true
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const deleteCommand = new DeleteObjectsCommand(deleteParams);
|
|
120
|
+
await client.send(deleteCommand);
|
|
121
|
+
return Key;
|
|
122
|
+
}
|
|
123
|
+
log.error("Bundle Not Found");
|
|
124
|
+
throw new Error("Bundle Not Found");
|
|
125
|
+
},
|
|
126
|
+
async uploadBundle(platform, bundleVersion, bundlePath) {
|
|
127
|
+
log.info("Uploading Bundle");
|
|
128
|
+
const Body = await fs.readFile(bundlePath);
|
|
129
|
+
const ContentType = mime.getType(bundlePath) ?? void 0;
|
|
130
|
+
const filename = path.basename(bundlePath);
|
|
131
|
+
const Key = [bundleVersion, platform, filename].join("/");
|
|
132
|
+
const upload = new Upload({
|
|
133
|
+
client,
|
|
134
|
+
params: {
|
|
135
|
+
ContentType,
|
|
136
|
+
Bucket: bucketName,
|
|
137
|
+
Key,
|
|
138
|
+
Body
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
const response = await upload.done();
|
|
142
|
+
if (!response.Location) {
|
|
143
|
+
log.error("Upload Failed");
|
|
144
|
+
throw new Error("Upload Failed");
|
|
145
|
+
}
|
|
146
|
+
log?.info(`Uploaded: ${Key}`);
|
|
147
|
+
return {
|
|
148
|
+
file: response.Location
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
export {
|
|
154
|
+
aws
|
|
155
|
+
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/aws",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0
|
|
4
|
+
"version": "0.1.0",
|
|
5
5
|
"description": "React Native OTA solution for self-hosted",
|
|
6
|
-
"main": "index.
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
7
9
|
"license": "MIT",
|
|
8
10
|
"repository": "https://github.com/gronxb/hot-updater",
|
|
9
11
|
"author": "gronxb <gron1gh1@gmail.com> (https://github.com/gronxb)",
|
|
@@ -15,9 +17,13 @@
|
|
|
15
17
|
"access": "public"
|
|
16
18
|
},
|
|
17
19
|
"dependencies": {
|
|
18
|
-
"@
|
|
20
|
+
"@hot-updater/plugin-core": "0.1.0",
|
|
21
|
+
"@aws-sdk/client-s3": "^3.685.0",
|
|
22
|
+
"@aws-sdk/lib-storage": "^3.685.0",
|
|
23
|
+
"mime": "^4.0.4"
|
|
19
24
|
},
|
|
20
25
|
"scripts": {
|
|
21
|
-
"build": "
|
|
26
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
27
|
+
"test:type": "tsc --noEmit"
|
|
22
28
|
}
|
|
23
29
|
}
|
package/src/aws.ts
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import {
|
|
3
|
+
DeleteObjectsCommand,
|
|
4
|
+
GetObjectCommand,
|
|
5
|
+
ListObjectsV2Command,
|
|
6
|
+
NoSuchKey,
|
|
7
|
+
S3Client,
|
|
8
|
+
type S3ClientConfig,
|
|
9
|
+
} from "@aws-sdk/client-s3";
|
|
10
|
+
import { Upload } from "@aws-sdk/lib-storage";
|
|
11
|
+
import {
|
|
12
|
+
type BasePluginArgs,
|
|
13
|
+
type DeployPlugin,
|
|
14
|
+
type UpdateSource,
|
|
15
|
+
log,
|
|
16
|
+
} from "@hot-updater/plugin-core";
|
|
17
|
+
import fs from "fs/promises";
|
|
18
|
+
import mime from "mime";
|
|
19
|
+
import { streamToString } from "./utils/streamToString";
|
|
20
|
+
|
|
21
|
+
export interface AwsConfig
|
|
22
|
+
extends Pick<S3ClientConfig, "credentials" | "region"> {
|
|
23
|
+
bucketName: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const aws =
|
|
27
|
+
(config: AwsConfig) =>
|
|
28
|
+
(_: BasePluginArgs): DeployPlugin => {
|
|
29
|
+
const { bucketName, ...s3Config } = config;
|
|
30
|
+
const client = new S3Client(s3Config);
|
|
31
|
+
|
|
32
|
+
let updateSources: UpdateSource[] = [];
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
async commitUpdateSource() {
|
|
36
|
+
try {
|
|
37
|
+
const command = new GetObjectCommand({
|
|
38
|
+
Bucket: bucketName,
|
|
39
|
+
Key: "update.json",
|
|
40
|
+
});
|
|
41
|
+
await client.send(command);
|
|
42
|
+
} catch (e) {
|
|
43
|
+
if (e instanceof NoSuchKey) {
|
|
44
|
+
log.info("Creating new update.json");
|
|
45
|
+
} else {
|
|
46
|
+
throw e;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
log.info("Uploading update.json");
|
|
51
|
+
const Key = "update.json";
|
|
52
|
+
const Body = JSON.stringify(updateSources);
|
|
53
|
+
const ContentType = mime.getType(Key) ?? void 0;
|
|
54
|
+
|
|
55
|
+
const upload = new Upload({
|
|
56
|
+
client,
|
|
57
|
+
params: {
|
|
58
|
+
ContentType,
|
|
59
|
+
Bucket: bucketName,
|
|
60
|
+
Key,
|
|
61
|
+
Body,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
await upload.done();
|
|
65
|
+
},
|
|
66
|
+
async updateUpdateSource(
|
|
67
|
+
targetBundleVersion: number,
|
|
68
|
+
newSource: Partial<UpdateSource>,
|
|
69
|
+
) {
|
|
70
|
+
updateSources = await this.getUpdateSources();
|
|
71
|
+
|
|
72
|
+
const targetIndex = updateSources.findIndex(
|
|
73
|
+
(u) => u.bundleVersion === targetBundleVersion,
|
|
74
|
+
);
|
|
75
|
+
if (targetIndex === -1) {
|
|
76
|
+
throw new Error("target bundle version not found");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
Object.assign(updateSources[targetIndex], newSource);
|
|
80
|
+
},
|
|
81
|
+
async appendUpdateSource(source) {
|
|
82
|
+
updateSources = await this.getUpdateSources();
|
|
83
|
+
updateSources.unshift(source);
|
|
84
|
+
},
|
|
85
|
+
async setUpdateSources(sources) {
|
|
86
|
+
updateSources = sources;
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
async getUpdateSources(refresh = false) {
|
|
90
|
+
if (updateSources.length > 0 && !refresh) {
|
|
91
|
+
return updateSources;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
log.info("Getting update.json");
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const command = new GetObjectCommand({
|
|
98
|
+
Bucket: bucketName,
|
|
99
|
+
Key: "update.json",
|
|
100
|
+
});
|
|
101
|
+
const { Body: UpdateJsonBody } = await client.send(command);
|
|
102
|
+
const bodyContents = await streamToString(UpdateJsonBody);
|
|
103
|
+
const _updateSource = JSON.parse(bodyContents);
|
|
104
|
+
updateSources = _updateSource;
|
|
105
|
+
return _updateSource as UpdateSource[];
|
|
106
|
+
} catch (e) {
|
|
107
|
+
if (e instanceof NoSuchKey) {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
throw e;
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
async deleteBundle(platform, bundleVersion) {
|
|
114
|
+
const Key = [bundleVersion, platform].join("/");
|
|
115
|
+
|
|
116
|
+
const listCommand = new ListObjectsV2Command({
|
|
117
|
+
Bucket: bucketName,
|
|
118
|
+
Prefix: `${bundleVersion}/${platform}`,
|
|
119
|
+
});
|
|
120
|
+
const listResponse = await client.send(listCommand);
|
|
121
|
+
|
|
122
|
+
if (listResponse.Contents && listResponse.Contents.length > 0) {
|
|
123
|
+
const objectsToDelete = listResponse.Contents.map((obj) => ({
|
|
124
|
+
Key: obj.Key,
|
|
125
|
+
}));
|
|
126
|
+
|
|
127
|
+
const deleteParams = {
|
|
128
|
+
Bucket: bucketName,
|
|
129
|
+
Delete: {
|
|
130
|
+
Objects: objectsToDelete,
|
|
131
|
+
Quiet: true,
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const deleteCommand = new DeleteObjectsCommand(deleteParams);
|
|
136
|
+
await client.send(deleteCommand);
|
|
137
|
+
return Key;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
log.error("Bundle Not Found");
|
|
141
|
+
throw new Error("Bundle Not Found");
|
|
142
|
+
},
|
|
143
|
+
async uploadBundle(platform, bundleVersion, bundlePath) {
|
|
144
|
+
log.info("Uploading Bundle");
|
|
145
|
+
|
|
146
|
+
const Body = await fs.readFile(bundlePath);
|
|
147
|
+
const ContentType = mime.getType(bundlePath) ?? void 0;
|
|
148
|
+
|
|
149
|
+
const filename = path.basename(bundlePath);
|
|
150
|
+
|
|
151
|
+
const Key = [bundleVersion, platform, filename].join("/");
|
|
152
|
+
const upload = new Upload({
|
|
153
|
+
client,
|
|
154
|
+
params: {
|
|
155
|
+
ContentType,
|
|
156
|
+
Bucket: bucketName,
|
|
157
|
+
Key,
|
|
158
|
+
Body,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
const response = await upload.done();
|
|
162
|
+
if (!response.Location) {
|
|
163
|
+
log.error("Upload Failed");
|
|
164
|
+
throw new Error("Upload Failed");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
log?.info(`Uploaded: ${Key}`);
|
|
168
|
+
return {
|
|
169
|
+
file: response.Location,
|
|
170
|
+
};
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./aws";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { lstatSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { readdir } from "fs/promises";
|
|
4
|
+
|
|
5
|
+
export const readDir = async (dir: string) => {
|
|
6
|
+
const files = await readdir(dir, {
|
|
7
|
+
recursive: true,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
return files.filter((file) => !lstatSync(path.join(dir, file)).isDirectory());
|
|
11
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const streamToString = (stream: any): Promise<string> => {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
const chunks: Uint8Array[] = [];
|
|
4
|
+
stream.on("data", (chunk: Uint8Array) => chunks.push(chunk));
|
|
5
|
+
stream.on("error", reject);
|
|
6
|
+
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
7
|
+
});
|
|
8
|
+
};
|
package/tsconfig.json
CHANGED
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
"outDir": "./lib",
|
|
6
|
-
"strict": true,
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
"forceConsistentCasingInFileNames": true,
|
|
10
|
-
"resolveJsonModule": true,
|
|
11
|
-
"declaration": true,
|
|
12
|
-
"baseUrl": ".",
|
|
13
|
-
"paths": {
|
|
14
|
-
"@/package.json": ["package.json"],
|
|
15
|
-
"@/*": ["src/*"]
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
"include": ["src", "global.d.ts"]
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"include": ["src"],
|
|
4
|
+
"exclude": ["lib"]
|
|
19
5
|
}
|
package/global.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference path="../types/strategy.d.ts" />
|
package/lib/read.d.ts
DELETED
package/lib/read.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.S3Client = exports.aws = void 0;
|
|
4
|
-
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
5
|
-
Object.defineProperty(exports, "S3Client", { enumerable: true, get: function () { return client_s3_1.S3Client; } });
|
|
6
|
-
const aws = (s3Client, bucketName, baseUrl) => {
|
|
7
|
-
return {
|
|
8
|
-
async getListObjects(prefix) {
|
|
9
|
-
/**
|
|
10
|
-
* Uses ListObjectsV2Command to fetch a list of objects from an S3 bucket.
|
|
11
|
-
* Note: A single invocation of ListObjectsV2Command can retrieve a maximum of 1,000 objects.
|
|
12
|
-
*/
|
|
13
|
-
const command = new client_s3_1.ListObjectsV2Command({
|
|
14
|
-
Bucket: bucketName,
|
|
15
|
-
Prefix: prefix,
|
|
16
|
-
});
|
|
17
|
-
const data = await s3Client.send(command);
|
|
18
|
-
const files = data.Contents?.filter(({ Key }) => Key !== prefix).map((content) => [baseUrl, content.Key].join("/"));
|
|
19
|
-
return files ?? [];
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
};
|
|
23
|
-
exports.aws = aws;
|
package/src/read.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { S3Client, ListObjectsV2Command } from "@aws-sdk/client-s3";
|
|
2
|
-
|
|
3
|
-
export const aws = (
|
|
4
|
-
s3Client: S3Client,
|
|
5
|
-
bucketName: string,
|
|
6
|
-
baseUrl: string
|
|
7
|
-
): HotUpdaterReadStrategy => {
|
|
8
|
-
return {
|
|
9
|
-
async getListObjects(prefix?: string) {
|
|
10
|
-
/**
|
|
11
|
-
* Uses ListObjectsV2Command to fetch a list of objects from an S3 bucket.
|
|
12
|
-
* Note: A single invocation of ListObjectsV2Command can retrieve a maximum of 1,000 objects.
|
|
13
|
-
*/
|
|
14
|
-
const command = new ListObjectsV2Command({
|
|
15
|
-
Bucket: bucketName,
|
|
16
|
-
Prefix: prefix,
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const data = await s3Client.send(command);
|
|
20
|
-
const files = data.Contents?.filter(({ Key }) => Key !== prefix).map(
|
|
21
|
-
(content) => [baseUrl, content.Key].join("/")
|
|
22
|
-
);
|
|
23
|
-
return files ?? [];
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export { S3Client };
|