@homecloud-platform/sdk 0.5.1 → 0.5.4

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 CHANGED
@@ -32,6 +32,11 @@ exports.handler = async (event, context) => {
32
32
  accountId: context.account_id,
33
33
  });
34
34
  await client.so.putJson("my-bucket", "proof/ok.json", { ok: true });
35
+ await client.so.upload("my-bucket", null, {
36
+ body: Buffer.from("..."),
37
+ key: "videos/clip.mp4",
38
+ contentType: "video/mp4",
39
+ });
35
40
  return { ok: true };
36
41
  };
37
42
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homecloud-platform/sdk",
3
- "version": "0.5.1",
3
+ "version": "0.5.4",
4
4
  "description": "HomeCloud Functions SDK for Node.js (ADR-033 / ADR-025e)",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
package/src/mq.js CHANGED
@@ -60,13 +60,13 @@ class MqAPI {
60
60
  return this._c.dataPlaneRequest("mq", "POST", reqPath, { json: payload });
61
61
  }
62
62
 
63
- async receive(queueName, { maxMessages = 1, waitSeconds = 20 } = {}) {
63
+ async receive(queueName, { maxMessages = 1, waitSeconds = 20, delete: shouldDelete = false } = {}) {
64
64
  this._c.requireAccessKey();
65
65
  const accountId = this._c.accountId;
66
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
- });
67
+ const params = { max_messages: maxMessages, wait_seconds: waitSeconds };
68
+ if (shouldDelete) params.delete = "true";
69
+ const data = await this._c.dataPlaneRequest("mq", "GET", reqPath, { params });
70
70
  return data.items || [];
71
71
  }
72
72
 
@@ -84,13 +84,13 @@ class MqAPI {
84
84
  await this._c.dataPlaneRequest("mq", "POST", reqPath);
85
85
  }
86
86
 
87
- async receiveDlq(queueName, { maxMessages = 1, waitSeconds = 20 } = {}) {
87
+ async receiveDlq(queueName, { maxMessages = 1, waitSeconds = 20, delete: shouldDelete = false } = {}) {
88
88
  this._c.requireAccessKey();
89
89
  const accountId = this._c.accountId;
90
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
- });
91
+ const params = { max_messages: maxMessages, wait_seconds: waitSeconds };
92
+ if (shouldDelete) params.delete = "true";
93
+ const data = await this._c.dataPlaneRequest("mq", "GET", reqPath, { params });
94
94
  return data.items || [];
95
95
  }
96
96
 
package/src/so.js CHANGED
@@ -2,10 +2,38 @@
2
2
 
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
- const os = require("os");
6
5
  const { soObjectPaths } = require("./signing");
7
6
  const { HomeCloudError } = require("./errors");
8
7
 
8
+ const MIME_BY_EXT = {
9
+ ".mp4": "video/mp4",
10
+ ".webm": "video/webm",
11
+ ".mov": "video/quicktime",
12
+ ".mp3": "audio/mpeg",
13
+ ".wav": "audio/wav",
14
+ ".ogg": "audio/ogg",
15
+ ".png": "image/png",
16
+ ".jpg": "image/jpeg",
17
+ ".jpeg": "image/jpeg",
18
+ ".gif": "image/gif",
19
+ ".webp": "image/webp",
20
+ ".pdf": "application/pdf",
21
+ ".json": "application/json",
22
+ ".txt": "text/plain",
23
+ ".html": "text/html",
24
+ ".htm": "text/html",
25
+ ".css": "text/css",
26
+ ".js": "text/javascript",
27
+ ".xml": "application/xml",
28
+ ".csv": "text/csv",
29
+ ".zip": "application/zip",
30
+ };
31
+
32
+ function _guessContentType(name) {
33
+ const ext = path.extname(String(name || "")).toLowerCase();
34
+ return MIME_BY_EXT[ext] || null;
35
+ }
36
+
9
37
  class SoAPI {
10
38
  constructor(client) {
11
39
  this._c = client;
@@ -58,34 +86,56 @@ class SoAPI {
58
86
  return items;
59
87
  }
60
88
 
61
- async upload(bucketName, filePath, { key } = {}) {
89
+ async upload(bucketName, filePath, { key, body, contentType } = {}) {
62
90
  this._c.requireAccessKey();
63
- if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
64
- throw new HomeCloudError(`File not found: ${filePath}`);
91
+ const hasBody = body !== undefined && body !== null;
92
+ if (hasBody && filePath != null && filePath !== "") {
93
+ throw new HomeCloudError("Pass either filePath or body, not both");
94
+ }
95
+ if (!hasBody && (filePath == null || filePath === "")) {
96
+ throw new HomeCloudError("filePath or body is required");
65
97
  }
66
- const objectKey = key || path.basename(filePath);
98
+ if (hasBody && (!key || !String(key).trim())) {
99
+ throw new HomeCloudError("key is required when uploading body");
100
+ }
101
+
102
+ let objectKey;
103
+ let filename;
104
+ let payload;
105
+
106
+ if (hasBody) {
107
+ objectKey = String(key).trim().replace(/^\/+/, "");
108
+ filename = path.basename(objectKey) || "object";
109
+ payload = body;
110
+ } else {
111
+ if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
112
+ throw new HomeCloudError(`File not found: ${filePath}`);
113
+ }
114
+ objectKey = key || path.basename(filePath);
115
+ filename = path.basename(filePath);
116
+ payload = fs.readFileSync(filePath);
117
+ }
118
+
119
+ const mime =
120
+ contentType ||
121
+ _guessContentType(objectKey) ||
122
+ _guessContentType(filename) ||
123
+ "application/octet-stream";
67
124
  const accountId = this._c.accountId;
68
125
  const uploadPath = `/${accountId}/${bucketName}/objects`;
69
- const blob = fs.readFileSync(filePath);
70
126
  const form = new FormData();
71
127
  form.append("key", objectKey);
72
- form.append("file", new Blob([blob]), path.basename(filePath));
128
+ form.append("file", new Blob([payload], { type: mime }), filename);
73
129
  return this._c.dataPlaneRequest("so", "POST", uploadPath, { formData: form });
74
130
  }
75
131
 
76
132
  async putJson(bucketName, objectKey, value) {
77
- const tmp = path.join(
78
- os.tmpdir(),
79
- `hc-sdk-${Date.now()}-${Math.random().toString(16).slice(2)}.json`
80
- );
81
- fs.writeFileSync(tmp, JSON.stringify(value, null, 2), "utf8");
82
- try {
83
- return await this.upload(bucketName, tmp, { key: objectKey });
84
- } finally {
85
- try {
86
- fs.unlinkSync(tmp);
87
- } catch (_) {}
88
- }
133
+ const data = Buffer.from(JSON.stringify(value, null, 2), "utf8");
134
+ return this.upload(bucketName, null, {
135
+ key: objectKey,
136
+ body: data,
137
+ contentType: "application/json",
138
+ });
89
139
  }
90
140
 
91
141
  async delete(bucketName, objectKey) {