@beauraines/node-helpers 4.3.0 → 5.0.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/CHANGELOG.md +11 -0
- package/package.json +1 -1
- package/src/azure.js +133 -29
- package/src/azure.test.js +85 -5
- package/src/helpers.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [5.0.0](https://github.com/beauraines/node-helpers/compare/v4.3.0...v5.0.0) (2024-10-14)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### ⚠ BREAKING CHANGES
|
|
9
|
+
|
|
10
|
+
* Updates and adds Storage Queue functions (#154)
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
* Updates and adds Storage Queue functions ([#154](https://github.com/beauraines/node-helpers/issues/154)) ([7301e37](https://github.com/beauraines/node-helpers/commit/7301e37e5e819a5d9ac222602a5e4f7be8e0816c))
|
|
15
|
+
|
|
5
16
|
## [4.3.0](https://github.com/beauraines/node-helpers/compare/v4.2.1...v4.3.0) (2024-10-14)
|
|
6
17
|
|
|
7
18
|
|
package/package.json
CHANGED
package/src/azure.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const dayjs = require('dayjs')
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const { streamToBuffer } = require('./helpers.js')
|
|
4
|
-
const { BlobServiceClient, StorageSharedKeyCredential } = require("@azure/storage-blob");
|
|
5
|
-
const {
|
|
4
|
+
const { BlobServiceClient, StorageSharedKeyCredential:BlobStorageSharedKeyCredential } = require("@azure/storage-blob");
|
|
5
|
+
const { QueueServiceClient ,StorageSharedKeyCredential:QueueStorageSharedKeyCredential } = require("@azure/storage-queue");
|
|
6
6
|
var path = require('path');
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -74,44 +74,148 @@ class AzureStorage {
|
|
|
74
74
|
/**
|
|
75
75
|
* Sends a message to the specified storage queue. The messages are given a TTL based upon the
|
|
76
76
|
* class's `queueMessageTTLSeconds` value.
|
|
77
|
+
*
|
|
78
|
+
* The response includes the `expiresOn`, `messageId` and `requestId` as well as a status code in
|
|
79
|
+
* `_response.status`
|
|
80
|
+
*
|
|
77
81
|
* @param {string} queueUrl The URL to the storage queue
|
|
78
82
|
* @param {string} messageContent The message to send to the queue
|
|
83
|
+
*
|
|
84
|
+
* @returns {Object} sendMessageResponse
|
|
79
85
|
*/
|
|
80
|
-
async sendMessageToQueue(
|
|
86
|
+
async sendMessageToQueue(queueName, messageContent) {
|
|
81
87
|
try {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
new
|
|
88
|
+
const queueServiceClient = new QueueServiceClient(
|
|
89
|
+
this.host('queue',this.cloudName),
|
|
90
|
+
new QueueStorageSharedKeyCredential(this.storageAccountName, this.storageAccountKey)
|
|
85
91
|
);
|
|
92
|
+
|
|
93
|
+
const queueClient = queueServiceClient.getQueueClient(queueName);
|
|
94
|
+
|
|
86
95
|
let queueOptions = {
|
|
87
96
|
messageTimeToLive: this.queueMessageTTLSeconds
|
|
88
97
|
};
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
|
|
99
|
+
let sendMessageResponse = await queueClient.sendMessage(messageContent,queueOptions);
|
|
100
|
+
sendMessageResponse.status = sendMessageResponse._response.status;
|
|
101
|
+
delete sendMessageResponse._response;
|
|
102
|
+
return sendMessageResponse;
|
|
103
|
+
|
|
94
104
|
} catch (error) {
|
|
95
|
-
console.
|
|
105
|
+
console.log(error.message)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Gets any number of messages from the queue. The messages themselves are in the property
|
|
111
|
+
* `receivedMessageItems[]messageText` Use the options to control the number of messages returned,
|
|
112
|
+
* defaults are 1 with a 30 second timeout. You will need the `messageId` and `popReceipt` to
|
|
113
|
+
* delete the message after processing.
|
|
114
|
+
*
|
|
115
|
+
* @param {string} queueName The name of the queue
|
|
116
|
+
* @param {object} options Any options such as `numberOfMessages` or `visibilityTimeout`
|
|
117
|
+
* @returns {object} The queue messages response
|
|
118
|
+
*/
|
|
119
|
+
async getQueueMessages(queueName,options) {
|
|
120
|
+
const queueServiceClient = new QueueServiceClient(
|
|
121
|
+
this.host('queue',this.cloudName),
|
|
122
|
+
new QueueStorageSharedKeyCredential(this.storageAccountName, this.storageAccountKey)
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const queueClient = queueServiceClient.getQueueClient(queueName);
|
|
126
|
+
const receivedMessagesResponse = await queueClient.receiveMessages(options);
|
|
127
|
+
return receivedMessagesResponse;
|
|
128
|
+
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Deletes a message, by `messageId` and `popReceipt` from a named queue
|
|
134
|
+
*
|
|
135
|
+
* @param {string} queueName The name of the queue that has the message
|
|
136
|
+
* @param {string} messageId The message id to be deleted
|
|
137
|
+
* @param {string} popReceipt The popReceipt of teh message to be deleted
|
|
138
|
+
* @returns object with a nothing really useful
|
|
139
|
+
*/
|
|
140
|
+
async deleteQueueMessage(queueName,messageId,popReceipt) {
|
|
141
|
+
const queueServiceClient = new QueueServiceClient(
|
|
142
|
+
this.host('queue',this.cloudName),
|
|
143
|
+
new QueueStorageSharedKeyCredential(this.storageAccountName, this.storageAccountKey)
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
const queueClient = queueServiceClient.getQueueClient(queueName);
|
|
147
|
+
const deleteMessageResponse = await queueClient.deleteMessage(messageId,popReceipt);
|
|
148
|
+
return deleteMessageResponse
|
|
149
|
+
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Gets the named queues properties, which includes the approximateMessagesCount
|
|
154
|
+
*
|
|
155
|
+
* @param {string} queueName
|
|
156
|
+
*
|
|
157
|
+
* @returns {Object} the queues properties
|
|
158
|
+
*/
|
|
159
|
+
async getQueueProperties(queueName) {
|
|
160
|
+
const queueServiceClient = new QueueServiceClient(
|
|
161
|
+
this.host('queue',this.cloudName),
|
|
162
|
+
new QueueStorageSharedKeyCredential(this.storageAccountName, this.storageAccountKey)
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const queueClient = queueServiceClient.getQueueClient(queueName);
|
|
166
|
+
const properties = await queueClient.getProperties();
|
|
167
|
+
return properties
|
|
168
|
+
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Lists storage queues in the storage account
|
|
173
|
+
*
|
|
174
|
+
* @returns Array
|
|
175
|
+
*/
|
|
176
|
+
async listsQueues() {
|
|
177
|
+
try {
|
|
178
|
+
const queueServiceClient = new QueueServiceClient(
|
|
179
|
+
this.host('queue',this.cloudName),
|
|
180
|
+
new QueueStorageSharedKeyCredential(this.storageAccountName, this.storageAccountKey)
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
let queues = []
|
|
184
|
+
for await (const queue of queueServiceClient.listQueues()) {
|
|
185
|
+
queues.push(queue)
|
|
96
186
|
}
|
|
187
|
+
|
|
188
|
+
return queues;
|
|
189
|
+
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.log(error.message)
|
|
97
192
|
}
|
|
193
|
+
}
|
|
98
194
|
|
|
99
195
|
/**
|
|
100
|
-
* Gets a SAS
|
|
196
|
+
* Gets a SAS URL for the storage queue
|
|
101
197
|
* .
|
|
102
|
-
* @param {string}
|
|
198
|
+
* @param {string} queueName The name of the storage queue
|
|
103
199
|
* @param {object} options Should include `permissions: "raup"` or some combination thereof Any additional options supported. https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas
|
|
200
|
+
*
|
|
201
|
+
* @returns {string} SAS URL for the specified queue
|
|
104
202
|
*/
|
|
105
|
-
getStorageQueueSignedURL(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
203
|
+
getStorageQueueSignedURL(queueName,options) {
|
|
204
|
+
const queueServiceClient = new QueueServiceClient(
|
|
205
|
+
this.host('queue',this.cloudName),
|
|
206
|
+
new QueueStorageSharedKeyCredential(this.storageAccountName, this.storageAccountKey)
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const queueClient = queueServiceClient.getQueueClient(queueName);
|
|
210
|
+
|
|
112
211
|
options = {
|
|
113
|
-
|
|
114
|
-
|
|
212
|
+
startsOn: dayjs().toDate(),
|
|
213
|
+
expiresOn: dayjs().add(this.tokenExpiry,'minutes'),
|
|
214
|
+
...options
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!options.permissions || !options.expiresOn) {
|
|
218
|
+
throw new Error("Must provide 'permissions' and 'expiresOn' for Queue SAS generation when 'identifier' is not provided");
|
|
115
219
|
}
|
|
116
220
|
|
|
117
221
|
return queueClient.generateSasUrl(options)
|
|
@@ -130,7 +234,7 @@ getStorageQueueSignedURL(queueUrl,options) {
|
|
|
130
234
|
|
|
131
235
|
const blobServiceClient = new BlobServiceClient(
|
|
132
236
|
this.host('blob',this.cloudName),
|
|
133
|
-
new
|
|
237
|
+
new BlobStorageSharedKeyCredential(this.storageAccountName, this.storageAccountKey)
|
|
134
238
|
);
|
|
135
239
|
const containerClient = blobServiceClient.getContainerClient(containerName);
|
|
136
240
|
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
|
@@ -158,7 +262,7 @@ getStorageQueueSignedURL(queueUrl,options) {
|
|
|
158
262
|
async uploadBlobFromFile(containerName,file) {
|
|
159
263
|
const blobServiceClient = new BlobServiceClient(
|
|
160
264
|
this.host('blob',this.cloudName),
|
|
161
|
-
new
|
|
265
|
+
new BlobStorageSharedKeyCredential(this.storageAccountName, this.storageAccountKey)
|
|
162
266
|
);
|
|
163
267
|
const containerClient = blobServiceClient.getContainerClient(containerName);
|
|
164
268
|
|
|
@@ -194,7 +298,7 @@ getStorageQueueSignedURL(queueUrl,options) {
|
|
|
194
298
|
async downloadBlobToFile(containerName,blobName,file) {
|
|
195
299
|
const blobServiceClient = new BlobServiceClient(
|
|
196
300
|
this.host('blob',this.cloudName),
|
|
197
|
-
new
|
|
301
|
+
new BlobStorageSharedKeyCredential(this.storageAccountName, this.storageAccountKey)
|
|
198
302
|
);
|
|
199
303
|
const containerClient = blobServiceClient.getContainerClient(containerName);
|
|
200
304
|
const blobClient = containerClient.getBlobClient(blobName);
|
|
@@ -219,7 +323,7 @@ getStorageQueueSignedURL(queueUrl,options) {
|
|
|
219
323
|
async getBlob(containerName,blobName) {
|
|
220
324
|
const blobServiceClient = new BlobServiceClient(
|
|
221
325
|
this.host('blob',this.cloudName),
|
|
222
|
-
new
|
|
326
|
+
new BlobStorageSharedKeyCredential(this.storageAccountName, this.storageAccountKey)
|
|
223
327
|
);
|
|
224
328
|
const containerClient = blobServiceClient.getContainerClient(containerName);
|
|
225
329
|
const blobClient = containerClient.getBlobClient(blobName);
|
|
@@ -246,7 +350,7 @@ getStorageQueueSignedURL(queueUrl,options) {
|
|
|
246
350
|
async getBinaryBlob(containerName,blobName) {
|
|
247
351
|
const blobServiceClient = new BlobServiceClient(
|
|
248
352
|
this.host('blob',this.cloudName),
|
|
249
|
-
new
|
|
353
|
+
new BlobStorageSharedKeyCredential(this.storageAccountName, this.storageAccountKey)
|
|
250
354
|
);
|
|
251
355
|
const containerClient = blobServiceClient.getContainerClient(containerName);
|
|
252
356
|
const blobClient = containerClient.getBlobClient(blobName);
|
|
@@ -268,7 +372,7 @@ getStorageQueueSignedURL(queueUrl,options) {
|
|
|
268
372
|
async listBlobs(containerName) {
|
|
269
373
|
const blobServiceClient = new BlobServiceClient(
|
|
270
374
|
this.host('blob',this.cloudName),
|
|
271
|
-
new
|
|
375
|
+
new BlobStorageSharedKeyCredential(this.storageAccountName, this.storageAccountKey)
|
|
272
376
|
);
|
|
273
377
|
const containerClient = blobServiceClient.getContainerClient(containerName);
|
|
274
378
|
let blobs = []
|
package/src/azure.test.js
CHANGED
|
@@ -77,8 +77,6 @@ describe('Azure Storage module', () => {
|
|
|
77
77
|
expect(success)
|
|
78
78
|
})
|
|
79
79
|
|
|
80
|
-
it.todo('should send a message to the storage queue')
|
|
81
|
-
|
|
82
80
|
it.skip('should get a blob from azure storage', async () =>{
|
|
83
81
|
const account = "devstoreaccount1";
|
|
84
82
|
const accountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
|
|
@@ -102,9 +100,6 @@ describe('Azure Storage module', () => {
|
|
|
102
100
|
expect(fileExists(file))
|
|
103
101
|
})
|
|
104
102
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
103
|
it.skip('should list blobs from azure storage', async () => {
|
|
109
104
|
const account = "devstoreaccount1";
|
|
110
105
|
const accountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
|
|
@@ -118,4 +113,89 @@ describe('Azure Storage module', () => {
|
|
|
118
113
|
expect(blobs.filter(b => b.name == blobName).length).toBe(1)
|
|
119
114
|
})
|
|
120
115
|
|
|
116
|
+
it.skip('should send a message to the storage queue', async () => {
|
|
117
|
+
const account = "devstoreaccount1";
|
|
118
|
+
const accountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
|
|
119
|
+
let azure = new AzureStorage(account,accountKey,{cloudName:'Azurite'})
|
|
120
|
+
const message = {foo:"bar"}
|
|
121
|
+
const queueName = 'node-helpers-testing'
|
|
122
|
+
let response = await azure.sendMessageToQueue(queueName,JSON.stringify(message))
|
|
123
|
+
expect(response.status).toBe(201)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it.skip('should error when generating a SAS URL for the storage queue without permissions', async () => {
|
|
127
|
+
const account = "devstoreaccount1";
|
|
128
|
+
const accountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
|
|
129
|
+
let azure = new AzureStorage(account,accountKey,{cloudName:'Azurite'})
|
|
130
|
+
const queueName = 'node-helpers-testing'
|
|
131
|
+
expect(() => azure.getStorageQueueSignedURL(queueName)).toThrow();
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it.skip('should generate a SAS URL for the storage queue', async () => {
|
|
135
|
+
const account = "devstoreaccount1";
|
|
136
|
+
const accountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
|
|
137
|
+
let azure = new AzureStorage(account,accountKey,{cloudName:'Azurite'})
|
|
138
|
+
const queueName = 'node-helpers-testing'
|
|
139
|
+
const options = {permissions:"r"}
|
|
140
|
+
let response = await azure.getStorageQueueSignedURL(queueName,options)
|
|
141
|
+
expect(response.includes('sp=r')).toBe(true) // Read permissions
|
|
142
|
+
expect(response.includes('http://127.0.0.1:10001/devstoreaccount1/node-helpers-testing')).toBe(true) // Azurite URL for storage queue
|
|
143
|
+
// TODO compute the expected expiration time
|
|
144
|
+
// expect(response.includes('se=2024-10-13T23%3A59%3A02Z')).toBe(true) // Expiration time defaults to 30 minutes
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
it.skip('should list the queues in the storage account', async () => {
|
|
149
|
+
const account = "devstoreaccount1";
|
|
150
|
+
const accountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
|
|
151
|
+
let azure = new AzureStorage(account,accountKey,{cloudName:'Azurite'})
|
|
152
|
+
const queueName = 'node-helpers-testing';
|
|
153
|
+
let queues = await azure.listsQueues();
|
|
154
|
+
expect(queues.map(x => x.name).indexOf(queueName)).toBeGreaterThan(-1)
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
it.skip('should get the queue properties', async () => {
|
|
158
|
+
const account = "devstoreaccount1";
|
|
159
|
+
const accountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
|
|
160
|
+
let azure = new AzureStorage(account,accountKey,{cloudName:'Azurite'})
|
|
161
|
+
const queueName = 'node-helpers-testing';
|
|
162
|
+
let properties = await azure.getQueueProperties(queueName);
|
|
163
|
+
expect(properties.approximateMessagesCount).toBeGreaterThan(0)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
it.skip('should get a message from the queue', async () => {
|
|
167
|
+
const account = "devstoreaccount1";
|
|
168
|
+
const accountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
|
|
169
|
+
let azure = new AzureStorage(account,accountKey,{cloudName:'Azurite'})
|
|
170
|
+
const queueName = 'node-helpers-testing';
|
|
171
|
+
let response = await azure.getQueueMessages(queueName);
|
|
172
|
+
const expectedMessage = {foo:"bar"}
|
|
173
|
+
expect(response._response.status).toBe(200)
|
|
174
|
+
expect(response.receivedMessageItems.length).toBeGreaterThan(0)
|
|
175
|
+
expect(response.receivedMessageItems[0].messageText).toBe(JSON.stringify(expectedMessage))
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it.skip('should get multiple messages from the queue', async () => {
|
|
179
|
+
const account = "devstoreaccount1";
|
|
180
|
+
const accountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
|
|
181
|
+
let azure = new AzureStorage(account,accountKey,{cloudName:'Azurite'})
|
|
182
|
+
const queueName = 'node-helpers-testing';
|
|
183
|
+
let response = await azure.getQueueMessages(queueName,{numberOfMessages:5});
|
|
184
|
+
expect(response._response.status).toBe(200)
|
|
185
|
+
expect(response.receivedMessageItems.length).toBeGreaterThan(1)
|
|
186
|
+
expect(response.receivedMessageItems.length).toBeLessThan(6)
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
it.skip('should delete a message from the queue',async () => {
|
|
190
|
+
const account = "devstoreaccount1";
|
|
191
|
+
const accountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
|
|
192
|
+
let azure = new AzureStorage(account,accountKey,{cloudName:'Azurite'})
|
|
193
|
+
const queueName = 'node-helpers-testing';
|
|
194
|
+
expect(() => azure.deleteQueueMessage(queueName,undefined,undefined)).toThrow() // popReceipt cannot be null
|
|
195
|
+
let addedMessage = await azure.sendMessageToQueue(queueName,'abc123')
|
|
196
|
+
let response = await azure.deleteQueueMessage(queueName,addedMessage.messageId,addedMessage.popReceipt);
|
|
197
|
+
expect(response.errorCode).toBe(undefined)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
|
|
121
201
|
})
|