@homecloud-platform/sdk 0.4.9 → 0.5.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/README.md +69 -65
- package/package.json +30 -30
- package/src/client.js +458 -0
- package/src/credentials.js +101 -0
- package/src/defaults.js +47 -0
- package/src/errors.js +166 -0
- package/src/index.d.ts +67 -35
- package/src/index.js +54 -274
- package/src/mail.js +89 -0
- package/src/management.js +128 -0
- package/src/mq.js +112 -0
- package/src/secrets.js +27 -0
- package/src/signing.js +54 -0
- package/src/so.js +225 -0
package/src/index.js
CHANGED
|
@@ -1,274 +1,54 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
super(message);
|
|
56
|
-
this.name = "HomeCloudError";
|
|
57
|
-
this.statusCode = statusCode;
|
|
58
|
-
this.detail = detail;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
class HomeCloud {
|
|
63
|
-
constructor({
|
|
64
|
-
accessKeyId,
|
|
65
|
-
secretAccessKey,
|
|
66
|
-
accountId,
|
|
67
|
-
apex = DEFAULT_APEX,
|
|
68
|
-
sessionToken,
|
|
69
|
-
dataPlaneBases,
|
|
70
|
-
}) {
|
|
71
|
-
this.accessKeyId = accessKeyId;
|
|
72
|
-
this.secretAccessKey = secretAccessKey;
|
|
73
|
-
this.accountId = accountId;
|
|
74
|
-
this.apex = apex || DEFAULT_APEX;
|
|
75
|
-
this.sessionToken = sessionToken || null;
|
|
76
|
-
this.dataPlaneBases = dataPlaneBases || {};
|
|
77
|
-
this.so = new SoAPI(this);
|
|
78
|
-
this.mq = new MqAPI(this);
|
|
79
|
-
this.secrets = new SecretsAPI(this);
|
|
80
|
-
this.mail = new MailAPI(this);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
static fromSts(sts, { accountId, apex } = {}) {
|
|
84
|
-
const aid = accountId || process.env.HC_ACCOUNT_ID || "";
|
|
85
|
-
let base = String(sts.base_url || sts.mail_base_url || "").replace(/\/$/, "");
|
|
86
|
-
const resourceType = String(sts.resource_type || "").trim().toLowerCase();
|
|
87
|
-
let resolvedApex = apex || process.env.HC_APEX || DEFAULT_APEX;
|
|
88
|
-
const dataPlaneBases = {};
|
|
89
|
-
if (base) {
|
|
90
|
-
let host = "";
|
|
91
|
-
try {
|
|
92
|
-
host = new URL(base).hostname || "";
|
|
93
|
-
} catch (_) {
|
|
94
|
-
host = "";
|
|
95
|
-
}
|
|
96
|
-
if (resourceType === "mail") {
|
|
97
|
-
if (host.startsWith("console.") || base.includes("/api/v1")) {
|
|
98
|
-
if (host.startsWith("console.")) resolvedApex = resolvedApex || host.slice("console.".length);
|
|
99
|
-
dataPlaneBases.mail = mailApiUrl(resolvedApex).replace(/\/$/, "");
|
|
100
|
-
} else {
|
|
101
|
-
dataPlaneBases.mail = base;
|
|
102
|
-
if (host.startsWith("mailapi.")) resolvedApex = resolvedApex || host.slice("mailapi.".length);
|
|
103
|
-
}
|
|
104
|
-
} else if (["so", "mq", "secrets"].includes(resourceType)) {
|
|
105
|
-
dataPlaneBases[resourceType] = base;
|
|
106
|
-
const prefix = `${resourceType}.`;
|
|
107
|
-
if (host.startsWith(prefix)) resolvedApex = resolvedApex || host.slice(prefix.length);
|
|
108
|
-
}
|
|
109
|
-
} else if (resourceType === "mail") {
|
|
110
|
-
dataPlaneBases.mail = mailApiUrl(resolvedApex).replace(/\/$/, "");
|
|
111
|
-
}
|
|
112
|
-
return new HomeCloud({
|
|
113
|
-
accessKeyId: String(sts.access_key_id),
|
|
114
|
-
secretAccessKey: String(sts.secret_access_key),
|
|
115
|
-
accountId: aid,
|
|
116
|
-
apex: resolvedApex || DEFAULT_APEX,
|
|
117
|
-
sessionToken: sts.session_token ? String(sts.session_token) : null,
|
|
118
|
-
dataPlaneBases,
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
static fromFunctionContext(context, { binding }) {
|
|
123
|
-
const ctx = context || {};
|
|
124
|
-
let stsMap = Object.assign({}, ctx.sts || {});
|
|
125
|
-
if (!Object.keys(stsMap).length && process.env.HC_STS_JSON) {
|
|
126
|
-
try {
|
|
127
|
-
stsMap = JSON.parse(process.env.HC_STS_JSON);
|
|
128
|
-
} catch (_) {
|
|
129
|
-
stsMap = {};
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
const entry = stsMap[binding];
|
|
133
|
-
if (!entry || !entry.access_key_id) {
|
|
134
|
-
throw new HomeCloudError(`STS binding '${binding}' not found in context.sts`);
|
|
135
|
-
}
|
|
136
|
-
return HomeCloud.fromSts(entry, {
|
|
137
|
-
accountId: ctx.account_id || ctx.accountId || process.env.HC_ACCOUNT_ID,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
baseUrl(service) {
|
|
142
|
-
if (this.dataPlaneBases[service]) return this.dataPlaneBases[service].replace(/\/$/, "");
|
|
143
|
-
if (service === "so") return soUrl(this.apex);
|
|
144
|
-
if (service === "mq") return mqUrl(this.apex);
|
|
145
|
-
if (service === "secrets") return secretsUrl(this.apex);
|
|
146
|
-
if (service === "mail") return mailApiUrl(this.apex);
|
|
147
|
-
throw new HomeCloudError(`Unknown data-plane service: ${service}`);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
async dataPlaneRequest(service, method, reqPath, { json, formData, body, headers } = {}) {
|
|
151
|
-
const base = this.baseUrl(service);
|
|
152
|
-
const url = new URL(reqPath.startsWith("http") ? reqPath : `${base}${reqPath}`);
|
|
153
|
-
const signPath = url.pathname + (url.search || "");
|
|
154
|
-
const auth = signRequestHeaders({
|
|
155
|
-
accessKeyId: this.accessKeyId,
|
|
156
|
-
secret: this.secretAccessKey,
|
|
157
|
-
method,
|
|
158
|
-
path: url.pathname,
|
|
159
|
-
accountId: this.accountId,
|
|
160
|
-
sessionToken: this.sessionToken,
|
|
161
|
-
});
|
|
162
|
-
const init = {
|
|
163
|
-
method,
|
|
164
|
-
headers: { ...auth, ...(headers || {}) },
|
|
165
|
-
};
|
|
166
|
-
if (formData) {
|
|
167
|
-
init.body = formData;
|
|
168
|
-
} else if (json !== undefined) {
|
|
169
|
-
init.headers["Content-Type"] = "application/json";
|
|
170
|
-
init.body = JSON.stringify(json);
|
|
171
|
-
} else if (body !== undefined) {
|
|
172
|
-
init.body = body;
|
|
173
|
-
}
|
|
174
|
-
const res = await fetch(url, init);
|
|
175
|
-
const text = await res.text();
|
|
176
|
-
let data = null;
|
|
177
|
-
if (text) {
|
|
178
|
-
try {
|
|
179
|
-
data = JSON.parse(text);
|
|
180
|
-
} catch (_) {
|
|
181
|
-
data = { raw: text };
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
if (!res.ok) {
|
|
185
|
-
throw new HomeCloudError(
|
|
186
|
-
(data && (data.detail || data.message || data.error)) || `HTTP ${res.status}`,
|
|
187
|
-
{ statusCode: res.status, detail: data }
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
return data;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
class SoAPI {
|
|
195
|
-
constructor(client) {
|
|
196
|
-
this._c = client;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
async upload(bucketName, filePath, { key } = {}) {
|
|
200
|
-
const objectKey = key || path.basename(filePath);
|
|
201
|
-
const accountId = this._c.accountId;
|
|
202
|
-
const uploadPath = `/${accountId}/${bucketName}/objects`;
|
|
203
|
-
const blob = fs.readFileSync(filePath);
|
|
204
|
-
const form = new FormData();
|
|
205
|
-
form.append("key", objectKey);
|
|
206
|
-
form.append("file", new Blob([blob]), path.basename(filePath));
|
|
207
|
-
return this._c.dataPlaneRequest("so", "POST", uploadPath, { formData: form });
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async putJson(bucketName, objectKey, value) {
|
|
211
|
-
const tmp = path.join(
|
|
212
|
-
require("os").tmpdir(),
|
|
213
|
-
`hc-sdk-${Date.now()}-${Math.random().toString(16).slice(2)}.json`
|
|
214
|
-
);
|
|
215
|
-
fs.writeFileSync(tmp, JSON.stringify(value, null, 2), "utf8");
|
|
216
|
-
try {
|
|
217
|
-
return await this.upload(bucketName, tmp, { key: objectKey });
|
|
218
|
-
} finally {
|
|
219
|
-
try {
|
|
220
|
-
fs.unlinkSync(tmp);
|
|
221
|
-
} catch (_) {}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
class MqAPI {
|
|
227
|
-
constructor(client) {
|
|
228
|
-
this._c = client;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
async send(queueName, body, { headers } = {}) {
|
|
232
|
-
const accountId = this._c.accountId;
|
|
233
|
-
const reqPath = `/${accountId}/${queueName}/messages`;
|
|
234
|
-
const bodyStr = typeof body === "string" ? body : JSON.stringify(body);
|
|
235
|
-
const payload = { body: bodyStr };
|
|
236
|
-
if (headers) payload.headers = headers;
|
|
237
|
-
return this._c.dataPlaneRequest("mq", "POST", reqPath, { json: payload });
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
class SecretsAPI {
|
|
242
|
-
constructor(client) {
|
|
243
|
-
this._c = client;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
async get(secretName) {
|
|
247
|
-
const accountId = this._c.accountId;
|
|
248
|
-
const reqPath = `/${accountId}/secrets/${encodeURIComponent(secretName)}`;
|
|
249
|
-
return this._c.dataPlaneRequest("secrets", "GET", reqPath);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
class MailAPI {
|
|
254
|
-
constructor(client) {
|
|
255
|
-
this._c = client;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
async listMessages({ mailbox = "INBOX", limit = 20 } = {}) {
|
|
259
|
-
const accountId = this._c.accountId;
|
|
260
|
-
const reqPath = `/${accountId}/mailboxes/${encodeURIComponent(mailbox)}/messages?limit=${limit}`;
|
|
261
|
-
return this._c.dataPlaneRequest("mail", "GET", reqPath);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
module.exports = {
|
|
266
|
-
HomeCloud,
|
|
267
|
-
HomeCloudError,
|
|
268
|
-
signRequestHeaders,
|
|
269
|
-
soUrl,
|
|
270
|
-
mqUrl,
|
|
271
|
-
secretsUrl,
|
|
272
|
-
mailApiUrl,
|
|
273
|
-
DEFAULT_APEX,
|
|
274
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { HomeCloud, AsyncHomeCloud } = require("./client");
|
|
4
|
+
const {
|
|
5
|
+
HomeCloudError,
|
|
6
|
+
NotConfiguredError,
|
|
7
|
+
NotLoggedInError,
|
|
8
|
+
ApiError,
|
|
9
|
+
BadRequestError,
|
|
10
|
+
UnauthorizedError,
|
|
11
|
+
PermissionDeniedError,
|
|
12
|
+
NotFoundError,
|
|
13
|
+
ConflictError,
|
|
14
|
+
RateLimitError,
|
|
15
|
+
ServiceUnavailableError,
|
|
16
|
+
errorFromStatus,
|
|
17
|
+
} = require("./errors");
|
|
18
|
+
const { signRequestHeaders, buildStringToSign, soObjectPaths } = require("./signing");
|
|
19
|
+
const {
|
|
20
|
+
DEFAULT_APEX,
|
|
21
|
+
soUrl,
|
|
22
|
+
mqUrl,
|
|
23
|
+
secretsUrl,
|
|
24
|
+
mailApiUrl,
|
|
25
|
+
consoleUrl,
|
|
26
|
+
functionUrl,
|
|
27
|
+
} = require("./defaults");
|
|
28
|
+
|
|
29
|
+
module.exports = {
|
|
30
|
+
HomeCloud,
|
|
31
|
+
AsyncHomeCloud,
|
|
32
|
+
HomeCloudError,
|
|
33
|
+
NotConfiguredError,
|
|
34
|
+
NotLoggedInError,
|
|
35
|
+
ApiError,
|
|
36
|
+
BadRequestError,
|
|
37
|
+
UnauthorizedError,
|
|
38
|
+
PermissionDeniedError,
|
|
39
|
+
NotFoundError,
|
|
40
|
+
ConflictError,
|
|
41
|
+
RateLimitError,
|
|
42
|
+
ServiceUnavailableError,
|
|
43
|
+
errorFromStatus,
|
|
44
|
+
signRequestHeaders,
|
|
45
|
+
buildStringToSign,
|
|
46
|
+
soObjectPaths,
|
|
47
|
+
soUrl,
|
|
48
|
+
mqUrl,
|
|
49
|
+
secretsUrl,
|
|
50
|
+
mailApiUrl,
|
|
51
|
+
consoleUrl,
|
|
52
|
+
functionUrl,
|
|
53
|
+
DEFAULT_APEX,
|
|
54
|
+
};
|
package/src/mail.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { HomeCloudError } = require("./errors");
|
|
4
|
+
|
|
5
|
+
function mailConsolePathToDataPlane(p, accountId) {
|
|
6
|
+
const raw = String(p).replace(/^\/+/, "");
|
|
7
|
+
const prefix = `accounts/${accountId}/mail/`;
|
|
8
|
+
if (raw.startsWith(prefix)) return `/${accountId}/${raw.slice(prefix.length)}`;
|
|
9
|
+
if (raw.startsWith(`${accountId}/`)) return `/${raw}`;
|
|
10
|
+
throw new HomeCloudError(`Unexpected mail path for data plane: ${p}`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class MailAPI {
|
|
14
|
+
constructor(client) {
|
|
15
|
+
this._c = client;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
_useMailDataPlane() {
|
|
19
|
+
return Boolean(this._c.accessKeyId && this._c.dataPlaneBases.mail);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async _mailRequest(method, consolePath, { params } = {}) {
|
|
23
|
+
const accountId = this._c.accountId;
|
|
24
|
+
if (this._useMailDataPlane()) {
|
|
25
|
+
const dpPath = mailConsolePathToDataPlane(consolePath, accountId);
|
|
26
|
+
return this._c.dataPlaneRequest("mail", method, dpPath, { params });
|
|
27
|
+
}
|
|
28
|
+
this._c.requireConsole();
|
|
29
|
+
return this._c.consoleRequest(method, consolePath, { params });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async _mailRequestBytes(method, consolePath) {
|
|
33
|
+
const accountId = this._c.accountId;
|
|
34
|
+
if (this._useMailDataPlane()) {
|
|
35
|
+
const dpPath = mailConsolePathToDataPlane(consolePath, accountId);
|
|
36
|
+
return this._c.dataPlaneRequestBytes("mail", method, dpPath);
|
|
37
|
+
}
|
|
38
|
+
this._c.requireConsole();
|
|
39
|
+
return this._c.consoleRequestBytes(method, consolePath);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async listMailboxes() {
|
|
43
|
+
const accountId = this._c.accountId;
|
|
44
|
+
const data = await this._mailRequest("GET", `accounts/${accountId}/mail/mailboxes`);
|
|
45
|
+
return data.items || [];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async listMessages({
|
|
49
|
+
mailboxId = null,
|
|
50
|
+
folder = null,
|
|
51
|
+
direction = null,
|
|
52
|
+
status = null,
|
|
53
|
+
search = null,
|
|
54
|
+
limit = 50,
|
|
55
|
+
cursor = null,
|
|
56
|
+
// legacy helper used by early smoke
|
|
57
|
+
mailbox = null,
|
|
58
|
+
} = {}) {
|
|
59
|
+
const accountId = this._c.accountId;
|
|
60
|
+
if (mailbox && !mailboxId && this._useMailDataPlane()) {
|
|
61
|
+
// Early MVP path: /{account}/mailboxes/{name}/messages
|
|
62
|
+
const reqPath = `/${accountId}/mailboxes/${encodeURIComponent(mailbox)}/messages`;
|
|
63
|
+
return this._c.dataPlaneRequest("mail", "GET", reqPath, { params: { limit } });
|
|
64
|
+
}
|
|
65
|
+
const params = { limit };
|
|
66
|
+
if (mailboxId) params.mailbox_id = mailboxId;
|
|
67
|
+
if (folder) params.folder = folder;
|
|
68
|
+
if (direction) params.direction = direction;
|
|
69
|
+
if (status) params.status = status;
|
|
70
|
+
if (search) params.search = search;
|
|
71
|
+
if (cursor) params.cursor = cursor;
|
|
72
|
+
return this._mailRequest("GET", `accounts/${accountId}/mail/messages`, { params });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async getMessage(messageId) {
|
|
76
|
+
const accountId = this._c.accountId;
|
|
77
|
+
return this._mailRequest("GET", `accounts/${accountId}/mail/messages/${messageId}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async downloadAttachment(messageId, partId) {
|
|
81
|
+
const accountId = this._c.accountId;
|
|
82
|
+
return this._mailRequestBytes(
|
|
83
|
+
"GET",
|
|
84
|
+
`accounts/${accountId}/mail/messages/${messageId}/attachments/${partId}`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = { MailAPI };
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
class AccountsAPI {
|
|
4
|
+
constructor(client) {
|
|
5
|
+
this._c = client;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async list() {
|
|
9
|
+
this._c.requireConsole();
|
|
10
|
+
const data = await this._c.consoleRequest("GET", "accounts");
|
|
11
|
+
return data.items || data || [];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async switch(accountRef) {
|
|
15
|
+
this._c.requireConsole();
|
|
16
|
+
return this._c.consoleRequest("POST", "accounts/switch", {
|
|
17
|
+
json: { account: accountRef },
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class AppsAPI {
|
|
23
|
+
constructor(client) {
|
|
24
|
+
this._c = client;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async list() {
|
|
28
|
+
this._c.requireConsole();
|
|
29
|
+
const data = await this._c.consoleRequest(
|
|
30
|
+
"GET",
|
|
31
|
+
`accounts/${this._c.accountId}/applications`
|
|
32
|
+
);
|
|
33
|
+
return data.items || [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class QueuesAPI {
|
|
38
|
+
constructor(client) {
|
|
39
|
+
this._c = client;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async list({ live = false } = {}) {
|
|
43
|
+
this._c.requireConsole();
|
|
44
|
+
const data = await this._c.consoleRequest(
|
|
45
|
+
"GET",
|
|
46
|
+
`accounts/${this._c.accountId}/queues`,
|
|
47
|
+
{ params: live ? { live: "true" } : undefined }
|
|
48
|
+
);
|
|
49
|
+
return data.items || [];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async get(queueName) {
|
|
53
|
+
this._c.requireConsole();
|
|
54
|
+
return this._c.consoleRequest(
|
|
55
|
+
"GET",
|
|
56
|
+
`accounts/${this._c.accountId}/queues/${encodeURIComponent(queueName)}`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
class FunctionsAPI {
|
|
62
|
+
constructor(client) {
|
|
63
|
+
this._c = client;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async list() {
|
|
67
|
+
this._c.requireConsole();
|
|
68
|
+
const data = await this._c.consoleRequest(
|
|
69
|
+
"GET",
|
|
70
|
+
`accounts/${this._c.accountId}/functions`
|
|
71
|
+
);
|
|
72
|
+
return data.items || [];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async url(name) {
|
|
76
|
+
this._c.requireConsole();
|
|
77
|
+
return this._c.consoleRequest(
|
|
78
|
+
"GET",
|
|
79
|
+
`accounts/${this._c.accountId}/functions/${name}/url`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async enableUrl(name, { publicUrl = false, rateLimitPerMinute = 60 } = {}) {
|
|
84
|
+
this._c.requireConsole();
|
|
85
|
+
return this._c.consoleRequest(
|
|
86
|
+
"POST",
|
|
87
|
+
`accounts/${this._c.accountId}/functions/${name}/url/enable`,
|
|
88
|
+
{
|
|
89
|
+
json: {
|
|
90
|
+
public_url_enabled: publicUrl,
|
|
91
|
+
rate_limit_per_minute: rateLimitPerMinute,
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async disableUrl(name) {
|
|
98
|
+
this._c.requireConsole();
|
|
99
|
+
return this._c.consoleRequest(
|
|
100
|
+
"POST",
|
|
101
|
+
`accounts/${this._c.accountId}/functions/${name}/url/disable`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async invoke(name, payload = {}) {
|
|
106
|
+
this._c.requireAccessKey();
|
|
107
|
+
return this._c.functionUrlRequest(name, payload);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async logs(name) {
|
|
111
|
+
this._c.requireConsole();
|
|
112
|
+
const data = await this._c.consoleRequest(
|
|
113
|
+
"GET",
|
|
114
|
+
`accounts/${this._c.accountId}/functions/${name}/invocations`
|
|
115
|
+
);
|
|
116
|
+
return data.items || [];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async getInvocation(name, invocationId) {
|
|
120
|
+
this._c.requireConsole();
|
|
121
|
+
return this._c.consoleRequest(
|
|
122
|
+
"GET",
|
|
123
|
+
`accounts/${this._c.accountId}/functions/${name}/invocations/${invocationId}`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
module.exports = { AccountsAPI, AppsAPI, QueuesAPI, FunctionsAPI };
|
package/src/mq.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const MQ_BATCH_MAX = 10;
|
|
4
|
+
|
|
5
|
+
function entryBodyStr(value) {
|
|
6
|
+
if (typeof value === "string") {
|
|
7
|
+
if (!value) throw new Error("mq.send batch entry body must be non-empty");
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
return JSON.stringify(value);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function buildMqBatchEntries(items) {
|
|
14
|
+
if (!Array.isArray(items) || items.length < 1 || items.length > MQ_BATCH_MAX) {
|
|
15
|
+
throw new Error(`mq.send batch requires 1–${MQ_BATCH_MAX} messages`);
|
|
16
|
+
}
|
|
17
|
+
const entries = [];
|
|
18
|
+
const seenIds = new Set();
|
|
19
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
20
|
+
const item = items[index];
|
|
21
|
+
let entry;
|
|
22
|
+
if (item && typeof item === "object" && typeof item.body === "string") {
|
|
23
|
+
const entryId = item.id != null ? String(item.id) : String(index);
|
|
24
|
+
if (!item.body) throw new Error("mq.send batch entry body must be non-empty");
|
|
25
|
+
entry = { id: entryId, body: item.body };
|
|
26
|
+
if (item.headers) entry.headers = item.headers;
|
|
27
|
+
} else {
|
|
28
|
+
entry = { id: String(index), body: entryBodyStr(item) };
|
|
29
|
+
}
|
|
30
|
+
if (seenIds.has(entry.id)) {
|
|
31
|
+
throw new Error("mq.send batch entry ids must be unique");
|
|
32
|
+
}
|
|
33
|
+
seenIds.add(entry.id);
|
|
34
|
+
entries.push(entry);
|
|
35
|
+
}
|
|
36
|
+
return entries;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class MqAPI {
|
|
40
|
+
constructor(client) {
|
|
41
|
+
this._c = client;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async send(queueName, body, { headers } = {}) {
|
|
45
|
+
this._c.requireAccessKey();
|
|
46
|
+
const accountId = this._c.accountId;
|
|
47
|
+
if (Array.isArray(body)) {
|
|
48
|
+
if (headers != null) {
|
|
49
|
+
throw new Error("headers is only supported for single mq.send, not batch");
|
|
50
|
+
}
|
|
51
|
+
const reqPath = `/${accountId}/${queueName}/messages/batch`;
|
|
52
|
+
return this._c.dataPlaneRequest("mq", "POST", reqPath, {
|
|
53
|
+
json: { entries: buildMqBatchEntries(body) },
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const reqPath = `/${accountId}/${queueName}/messages`;
|
|
57
|
+
const bodyStr = typeof body === "string" ? body : JSON.stringify(body);
|
|
58
|
+
const payload = { body: bodyStr };
|
|
59
|
+
if (headers) payload.headers = headers;
|
|
60
|
+
return this._c.dataPlaneRequest("mq", "POST", reqPath, { json: payload });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async receive(queueName, { maxMessages = 1, waitSeconds = 20 } = {}) {
|
|
64
|
+
this._c.requireAccessKey();
|
|
65
|
+
const accountId = this._c.accountId;
|
|
66
|
+
const reqPath = `/${accountId}/${queueName}/messages`;
|
|
67
|
+
const data = await this._c.dataPlaneRequest("mq", "GET", reqPath, {
|
|
68
|
+
params: { max_messages: maxMessages, wait_seconds: waitSeconds },
|
|
69
|
+
});
|
|
70
|
+
return data.items || [];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async delete(queueName, sequence) {
|
|
74
|
+
this._c.requireAccessKey();
|
|
75
|
+
const accountId = this._c.accountId;
|
|
76
|
+
const reqPath = `/${accountId}/${queueName}/messages/${sequence}`;
|
|
77
|
+
await this._c.dataPlaneRequest("mq", "DELETE", reqPath);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async purge(queueName) {
|
|
81
|
+
this._c.requireAccessKey();
|
|
82
|
+
const accountId = this._c.accountId;
|
|
83
|
+
const reqPath = `/${accountId}/${queueName}/purge`;
|
|
84
|
+
await this._c.dataPlaneRequest("mq", "POST", reqPath);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async receiveDlq(queueName, { maxMessages = 1, waitSeconds = 20 } = {}) {
|
|
88
|
+
this._c.requireAccessKey();
|
|
89
|
+
const accountId = this._c.accountId;
|
|
90
|
+
const reqPath = `/${accountId}/${queueName}/dlq/messages`;
|
|
91
|
+
const data = await this._c.dataPlaneRequest("mq", "GET", reqPath, {
|
|
92
|
+
params: { max_messages: maxMessages, wait_seconds: waitSeconds },
|
|
93
|
+
});
|
|
94
|
+
return data.items || [];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async deleteDlq(queueName, sequence) {
|
|
98
|
+
this._c.requireAccessKey();
|
|
99
|
+
const accountId = this._c.accountId;
|
|
100
|
+
const reqPath = `/${accountId}/${queueName}/dlq/messages/${sequence}`;
|
|
101
|
+
await this._c.dataPlaneRequest("mq", "DELETE", reqPath);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async purgeDlq(queueName) {
|
|
105
|
+
this._c.requireAccessKey();
|
|
106
|
+
const accountId = this._c.accountId;
|
|
107
|
+
const reqPath = `/${accountId}/${queueName}/dlq/purge`;
|
|
108
|
+
await this._c.dataPlaneRequest("mq", "POST", reqPath);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = { MqAPI, buildMqBatchEntries, MQ_BATCH_MAX };
|
package/src/secrets.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
class SecretsAPI {
|
|
4
|
+
constructor(client) {
|
|
5
|
+
this._c = client;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Console JWT — list secret metadata. */
|
|
9
|
+
async list() {
|
|
10
|
+
this._c.requireConsole();
|
|
11
|
+
const data = await this._c.consoleRequest(
|
|
12
|
+
"GET",
|
|
13
|
+
`accounts/${this._c.accountId}/secrets`
|
|
14
|
+
);
|
|
15
|
+
return data.items || [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Data plane — fetch secret payload by name (Access Key). */
|
|
19
|
+
async get(secretName) {
|
|
20
|
+
this._c.requireAccessKey();
|
|
21
|
+
const accountId = this._c.accountId;
|
|
22
|
+
const reqPath = `/${accountId}/secrets/${encodeURIComponent(secretName)}`;
|
|
23
|
+
return this._c.dataPlaneRequest("secrets", "GET", reqPath);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { SecretsAPI };
|