You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

@netlify/blobs

Package Overview
Dependencies
Maintainers
20
Versions
73
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@netlify/blobs - npm Package Compare versions

Comparing version

to
1.4.0

10

dist/main.d.ts

@@ -22,2 +22,5 @@ interface APICredentials {

}
interface SetOptions {
ttl?: Date | number;
}
type BlobInput = ReadableStream | string | ArrayBuffer | Blob;

@@ -31,2 +34,3 @@ export declare class Blobs {

private getFinalRequest;
private static getTTLHeaders;
private isConfigured;

@@ -48,7 +52,5 @@ private makeStoreRequest;

}): Promise<string>;
set(key: string, data: BlobInput, { ttl }?: {
ttl?: Date | number;
}): Promise<void>;
setJSON(key: string, data: unknown): Promise<void>;
set(key: string, data: BlobInput, { ttl }?: SetOptions): Promise<void>;
setJSON(key: string, data: unknown, { ttl }?: SetOptions): Promise<void>;
}
export {};

42

dist/main.js

@@ -41,3 +41,2 @@ var HTTPMethod;

async getFinalRequest(key, method) {
const finalMethod = method;
if ('contextURL' in this.authentication) {

@@ -48,3 +47,2 @@ return {

},
method: finalMethod,
url: `${this.authentication.contextURL}/${this.siteID}/${this.context}/${key}`,

@@ -61,6 +59,21 @@ };

return {
method: finalMethod,
url,
};
}
static getTTLHeaders(ttl) {
if (typeof ttl === 'number') {
return {
[EXPIRY_HEADER]: (Date.now() + ttl).toString(),
};
}
if (ttl instanceof Date) {
return {
[EXPIRY_HEADER]: ttl.getTime().toString(),
};
}
if (ttl === undefined) {
return {};
}
throw new TypeError(`'ttl' value must be a number or a Date, ${typeof ttl} found.`);
}
isConfigured() {

@@ -73,3 +86,3 @@ return Boolean(this.authentication?.token) && Boolean(this.siteID);

}
const { headers: baseHeaders = {}, method: finalMethod, url } = await this.getFinalRequest(key, method);
const { headers: baseHeaders = {}, url } = await this.getFinalRequest(key, method);
const headers = {

@@ -82,9 +95,8 @@ ...baseHeaders,

}
const res = await this.fetcher(url, { body, headers, method: finalMethod });
if (res.status === 404 && finalMethod === HTTPMethod.Get) {
const res = await this.fetcher(url, { body, headers, method });
if (res.status === 404 && method === HTTPMethod.Get) {
return null;
}
if (res.status !== 200) {
const details = await res.text();
throw new Error(`${method} operation has failed: ${details}`);
throw new Error(`${method} operation has failed: store returned a ${res.status} response`);
}

@@ -127,17 +139,9 @@ return res;

async set(key, data, { ttl } = {}) {
const headers = {};
if (typeof ttl === 'number') {
headers[EXPIRY_HEADER] = (Date.now() + ttl).toString();
}
else if (ttl instanceof Date) {
headers[EXPIRY_HEADER] = ttl.getTime().toString();
}
else if (ttl !== undefined) {
throw new TypeError(`'ttl' value must be a number or a Date, ${typeof ttl} found.`);
}
const headers = Blobs.getTTLHeaders(ttl);
await this.makeStoreRequest(key, HTTPMethod.Put, headers, data);
}
async setJSON(key, data) {
async setJSON(key, data, { ttl } = {}) {
const payload = JSON.stringify(data);
const headers = {
...Blobs.getTTLHeaders(ttl),
'content-type': 'application/json',

@@ -144,0 +148,0 @@ };

@@ -114,3 +114,3 @@ import { version as nodeVersion } from 'process';

});
expect(async () => await blobs.get(key)).rejects.toThrowError('get operation has failed: Something went wrong');
expect(async () => await blobs.get(key)).rejects.toThrowError('get operation has failed: store returned a 401 response');
});

@@ -268,2 +268,60 @@ test('Returns `null` when the blob entry contains an expiry date in the past', async () => {

});
describe('setJSON', () => {
test('Writes to the blob store using API credentials', async () => {
expect.assertions(5);
const fetcher = async (...args) => {
const [url, options] = args;
const headers = options?.headers;
expect(options?.method).toBe('put');
if (url === `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`) {
const data = JSON.stringify({ url: signedURL });
expect(headers.authorization).toBe(`Bearer ${apiToken}`);
return new Response(data);
}
if (url === signedURL) {
expect(options?.body).toBe(JSON.stringify({ value }));
expect(headers['cache-control']).toBe('max-age=0, stale-while-revalidate=60');
return new Response(value);
}
throw new Error(`Unexpected fetch call: ${url}`);
};
const blobs = new Blobs({
authentication: {
token: apiToken,
},
fetcher,
siteID,
});
await blobs.setJSON(key, { value });
});
test('Accepts a TTL parameter', async () => {
expect.assertions(6);
const ttl = new Date(Date.now() + 15000);
const fetcher = async (...args) => {
const [url, options] = args;
const headers = options?.headers;
expect(options?.method).toBe('put');
if (url === `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`) {
const data = JSON.stringify({ url: signedURL });
expect(headers.authorization).toBe(`Bearer ${apiToken}`);
return new Response(data);
}
if (url === signedURL) {
expect(options?.body).toBe(JSON.stringify({ value }));
expect(headers['cache-control']).toBe('max-age=0, stale-while-revalidate=60');
expect(headers['x-nf-expires-at']).toBe(ttl.getTime().toString());
return new Response(value);
}
throw new Error(`Unexpected fetch call: ${url}`);
};
const blobs = new Blobs({
authentication: {
token: apiToken,
},
fetcher,
siteID,
});
await blobs.setJSON(key, { value }, { ttl });
});
});
describe('delete', () => {

@@ -270,0 +328,0 @@ test('Deletes from the blob store using API credentials', async () => {

{
"name": "@netlify/blobs",
"version": "1.3.0",
"version": "1.4.0",
"description": "A JavaScript client for the Netlify Blob Store",

@@ -5,0 +5,0 @@ "type": "module",