filestack-js
Version:
Official JavaScript library for Filestack
543 lines (504 loc) • 17.2 kB
text/typescript
/*
* Copyright (c) 2018 by Filestack
* Some rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { EventEmitter } from 'eventemitter3';
import * as Sentry from '@sentry/browser';
import { config, Hosts } from '../config';
import { FilestackError } from './../filestack_error';
import { metadata, MetadataOptions, remove, retrieve, RetrieveOptions, download } from './api/file';
import { transform, TransformOptions } from './api/transform';
import { storeURL } from './api/store';
import * as Utils from './utils';
import { Upload, InputFile, UploadOptions, StoreUploadOptions, UploadTags } from './api/upload';
import { preview, PreviewOptions } from './api/preview';
import { CloudClient } from './api/cloud';
import { Prefetch, PrefetchResponse, PrefetchOptions } from './api/prefetch';
import { FsResponse } from './request/types';
import { StoreParams } from './filelink';
import { picker, PickerInstance, PickerOptions } from './picker';
/* istanbul ignore next */
Sentry.addBreadcrumb({ category: 'sdk', message: 'filestack-js-sdk scope' });
export interface Session {
apikey: string;
urls: Hosts;
cname?: string;
policy?: string;
signature?: string;
prefetch?: PrefetchResponse;
}
export interface Security {
policy: string;
signature: string;
}
export interface ClientOptions {
[option: string]: any;
/**
* Security object with policy and signature keys.
* Can be used to limit client capabilities and protect public URLs.
* It is intended to be used with server-side policy and signature generation.
* Read about [security policies](https://www.filestack.com/docs/concepts/security).
*/
security?: Security;
/**
* Domain to use for all URLs. __Requires the custom CNAME addon__.
* If this is enabled then you must also set up your own OAuth applications
* for each cloud source you wish to use in the picker.
*/
cname?: string;
/**
* Enable/disable caching of the cloud session token. Default is false.
* This ensures that users will be remembered on your domain when calling the cloud API from the browser.
* Please be aware that tokens stored in localStorage are accessible by other scripts on the same domain.
*/
sessionCache?: boolean;
/**
* Enable forwarding error logs to sentry
* @default false
*/
forwardErrors?: boolean;
}
/**
* The Filestack client, the entry point for all public methods. Encapsulates session information.
*
* ### Example
* ```js
* // ES module
* import * as filestack from 'filestack-js';
* const client = filestack.init('apikey');
* ```
*
* ```js
* // UMD module in browser
* <script src="https://static.filestackapi.com/filestack-js/3.x.x/filestack.min.js"></script>
* const client = filestack.init('apikey');
* ```
*/
export class Client extends EventEmitter {
public session: Session;
private cloud: CloudClient;
private prefetchInstance: Prefetch;
private forwardErrors: boolean = true;
/**
* Returns filestack utils
*
* @readonly
* @memberof Client
*/
get utils() {
return Utils;
}
constructor(apikey: string, private options?: ClientOptions) {
super();
/* istanbul ignore if */
if (options && options.forwardErrors) {
this.forwardErrors = options.forwardErrors;
}
if (!apikey || typeof apikey !== 'string' || apikey.length === 0) {
throw new Error('An apikey is required to initialize the Filestack client');
}
const { urls } = config;
this.session = { apikey, urls };
if (options) {
const { cname, security } = options;
this.setSecurity(security);
this.setCname(cname);
}
this.prefetchInstance = new Prefetch(this.session);
this.cloud = new CloudClient(this.session, options);
}
/**
* Make basic prefetch request to check permissions
*
* @param params
*/
prefetch(params: PrefetchOptions) {
return this.prefetchInstance.getConfig(params);
}
/**
* Set security object
*
* @param {Security} security
* @memberof Client
*/
setSecurity(security: Security) {
if (security && !(security.policy && security.signature)) {
throw new FilestackError('Both policy and signature are required for client security');
}
if (security && security.policy && security.signature) {
this.session.policy = security.policy;
this.session.signature = security.signature;
}
}
/**
* Set custom cname
*
* @param {string} cname
* @returns
* @memberof Client
*/
setCname(cname: string) {
if (!cname || cname.length === 0) {
return;
}
this.session.cname = cname;
this.session.urls = Utils.resolveHost(this.session.urls, cname);
}
/**
* Clear all current cloud sessions in the picker.
* Optionally pass a cloud source name to only log out of that cloud source.
* This essentially clears the OAuth authorization codes from the Filestack session.
* @param name Optional cloud source name.
*/
logout(name?: string) {
return this.cloud.logout(name);
}
/**
* Retrieve detailed data of stored files.
*
* ### Example
*
* ```js
* client
* .metadata('DCL5K46FS3OIxb5iuKby')
* .then((res) => {
* console.log(res);
* })
* .catch((err) => {
* console.log(err);
* }));
* ```
* @see [File API - Metadata](https://www.filestack.com/docs/api/file#metadata).
* @param handle Valid Filestack handle.
* @param options Metadata fields to enable on response.
* @param security Optional security override.
*/
metadata(handle: string, options?: MetadataOptions, security?: Security) {
/* istanbul ignore next */
return metadata(this.session, handle, options, security);
}
/**
* Construct a new picker instance.
*/
picker(options?: PickerOptions): PickerInstance {
/* istanbul ignore next */
return picker(this, options);
}
/**
* Used for viewing files via Filestack handles or storage aliases, __requires Document Viewer addon to your Filestack application__.
* Opens document viewer in new window if id option is not provided.
*
* ### Example
*
* ```js
* // <div id="preview"></div>
*
* client.preview('DCL5K46FS3OIxb5iuKby', { id: 'preview' });
* ```
* @param handle Valid Filestack handle.
* @param options Preview options
*/
preview(handle: string, options?: PreviewOptions) {
/* istanbul ignore next */
return preview(this.session, handle, options);
}
/**
* Remove a file from storage and the Filestack system.
*
* __Requires a valid security policy and signature__. The policy and signature will be pulled from the client session, or it can be overridden with the security parameter.
*
* ### Example
*
* ```js
* client
* .remove('DCL5K46FS3OIxb5iuKby')
* .then((res) => {
* console.log(res);
* })
* .catch((err) => {
* console.log(err);
* }));
* ```
* @see [File API - Delete](https://www.filestack.com/docs/api/file#delete)
* @param handle Valid Filestack handle.
* @param security Optional security override.
*/
remove(handle: string, security?: Security): Promise<any> {
/* istanbul ignore next */
return remove(this.session, handle, false, security);
}
/**
* Remove a file **only** from the Filestack system. The file remains in storage.
*
* __Requires a valid security policy and signature__. The policy and signature will be pulled from the client session, or it can be overridden with the security parameter.
*
* ### Example
*
* ```js
* client
* .removeMetadata('DCL5K46FS3OIxb5iuKby')
* .then((res) => {
* console.log(res);
* })
* .catch((err) => {
* console.log(err);
* }));
* ```
* @see [File API - Delete](https://www.filestack.com/docs/api/file#delete)
* @param handle Valid Filestack handle.
* @param security Optional security override.
*/
removeMetadata(handle: string, security?: Security): Promise<any> {
/* istanbul ignore next */
return remove(this.session, handle, true, security);
}
/**
* Store a file from its URL.
*
* ### Example
*
* ```js
* client
* .storeURL('https://d1wtqaffaaj63z.cloudfront.net/images/NY_199_E_of_Hammertown_2014.jpg')
* .then(res => console.log(res));
* ```
* @see [File API - Store](https://www.filestack.com/docs/api/file#store)
* @param url Valid URL to a file.
* @param options Configure file storage.
* @param token Optional control token to call .cancel()
* @param security Optional security override.
* @param uploadTags Optional tags visible in webhooks.
* @param headers Optional headers to send
* @param workflowIds Optional workflowIds to send
*/
storeURL(url: string, storeParams?: StoreParams, token?: any, security?: Security, uploadTags?: UploadTags, headers?: {[key: string]: string}, workflowIds?: string[]): Promise<Object> {
return storeURL({
session: this.session,
url,
storeParams,
token,
security,
uploadTags,
headers,
workflowIds,
});
}
/**
* Access files via their Filestack handles.
*
* If head option is provided - request headers are returned in promise
* If metadata option is provided - metadata object is returned in promise
* Otherwise file blob is returned
* Metadata and head options cannot be mixed
*
* ### Example
*
* ```js
* client.retrieve('fileHandle', {
* metadata: true,
* }).then((response) => {
* console.log(response);
* }).catch((err) => {
* console.error(err);
* })
* ```
*
* @see [File API - Download](https://www.filestack.com/docs/api/file#download)
* @deprecated use metadata or download methods instead
* @param handle Valid file handle
* @param options RetrieveOptions
* @param security Optional security override.
* @throws Error
*/
retrieve(handle: string, options?: RetrieveOptions, security?: Security): Promise<Object | Blob> {
/* istanbul ignore next */
return retrieve(this.session, handle, options, security);
}
/**
* Download file by handle
*
*
* ### Browser Example
*
* ```js
* client.download('fileHandle').then((response) => {
* const img = new Image();
* img.src = URL.createObjectURL(res.data)
* document.body.appendChild(img);
* }).catch((err) => {
* console.error(err);
* })
* ```
*
* @see [File API - Download](https://www.filestack.com/docs/api/file#download)
* @param handle Valid file handle
* @throws Error
*/
download(handle: string, security?: Security): Promise<FsResponse> {
/* istanbul ignore next */
return download(this.session, handle, security);
}
/**
* Interface to the Filestack [Processing API](https://www.filestack.com/docs/api/processing).
* Convert a URL, handle, or storage alias to another URL which links to the transformed file.
* You can optionally store the returned URL with client.storeURL.
*
* Transform params can be provided in camelCase or snakeCase style ie: partial_pixelate or partialPixelate
*
* ### Example
*
* ```js
* const transformedUrl = client.transform(url, {
* crop: {
* dim: [x, y, width, height],
* },
* vignette: {
* blurmode: 'gaussian',
* amount: 50,
* },
* flip: true,
* partial_pixelate: {
* objects: [[10, 20, 200, 250], [275, 91, 500, 557]],
* },
* };
*
* // optionally store the new URL
* client.storeURL(transformedUrl).then(res => console.log(res));
* ```
* @see [Filestack Processing API](https://www.filestack.com/docs/api/processing)
* @param url Single or multiple valid URLs (http(s)://), file handles, or storage aliases (src://) to an image.
* @param options Transformations are applied in the order specified by this object.
* @param b64 Use new more safe format for generating transforms url (default=false) Note: If there will be any issues with url please test it with enabled b64 support
* @returns A new URL that points to the transformed resource.
*/
transform(url: string | string[], options: TransformOptions, b64: boolean = false) {
/* istanbul ignore next */
return transform(this.session, url, options, b64);
}
/**
* Initiates a multi-part upload flow. Use this for Filestack CIN and FII uploads.
*
* In Node runtimes the file argument is treated as a file path.
* Uploading from a Node buffer is not yet implemented.
*
* ### Example
*
* ```js
* const token = {};
* const onRetry = (obj) => {
* console.log(`Retrying ${obj.location} for ${obj.filename}. Attempt ${obj.attempt} of 10.`);
* };
*
* client.upload(file, { onRetry }, { filename: 'foobar.jpg' }, token)
* .then(res => console.log(res));
*
* client.upload({file, name}, { onRetry }, { filename: 'foobar.jpg' }, token)
* .then(res => console.log(res));
*
* token.pause(); // Pause flow
* token.resume(); // Resume flow
* token.cancel(); // Cancel flow (rejects)
* ```
* @param {InputFile} file Must be a valid [File | Blob | Buffer | string]
* @param uploadOptions Uploader options.
* @param storeOptions Storage options.
* @param token A control token that can be used to call cancel(), pause(), and resume().
* @param security Optional security policy and signature override.
*
* @returns {Promise}
*/
upload(file: InputFile, options?: UploadOptions, storeOptions?: StoreUploadOptions, token?: any, security?: Security) {
let upload = new Upload(options, storeOptions);
upload.setSession(this.session);
if (token) {
upload.setToken(token);
}
if (security) {
upload.setSecurity(security);
}
upload.on('start', () => this.emit('upload.start'));
/* istanbul ignore next */
upload.on('error', e => {
if (this.forwardErrors) {
Sentry.withScope(scope => {
scope.setTag('filestack-apikey', this.session.apikey);
scope.setTag('filestack-version', Utils.getVersion());
scope.setExtra('filestack-options', this.options);
scope.setExtras({ uploadOptions: options, storeOptions, details: e.details });
e.message = `FS-${e.message}`;
scope.captureException(e);
});
}
this.emit('upload.error', e);
});
return upload.upload(file, options && options.altText);
}
/**
* Initiates a multi-part upload flow. Use this for Filestack CIN and FII uploads.
*
* In Node runtimes the file argument is treated as a file path.
* Uploading from a Node buffer is not yet implemented.
*
* ### Example
*
* ```js
* const token = {};
* const onRetry = (obj) => {
* console.log(`Retrying ${obj.location} for ${obj.filename}. Attempt ${obj.attempt} of 10.`);
* };
*
* client.multiupload([file], { onRetry }, token)
* .then(res => console.log(res));
*
* client.multiupload([{file, name}], { onRetry }, token)
* .then(res => console.log(res));
*
* token.pause(); // Pause flow
* token.resume(); // Resume flow
* token.cancel(); // Cancel flow (rejects)
* ```
* @param {InputFile[]} file Must be a valid [File | Blob | Buffer | string (base64)]
* @param uploadOptions Upload options.
* @param storeOptions Storage options.
* @param token A control token that can be used to call cancel(), pause(), and resume().
* @param security Optional security policy and signature override.
*
* @returns {Promise}
*/
multiupload(file: InputFile[], options?: UploadOptions, storeOptions?: StoreUploadOptions, token?: any, security?: Security) {
let upload = new Upload(options, storeOptions);
upload.setSession(this.session);
if (token) {
upload.setToken(token);
}
if (security) {
upload.setSecurity(security);
}
upload.on('start', () => this.emit('upload.start'));
/* istanbul ignore next */
upload.on('error', e => {
Sentry.withScope(scope => {
scope.setTag('filestack-apikey', this.session.apikey);
scope.setTag('filestack-version', Utils.getVersion());
scope.setExtra('filestack-options', this.options);
scope.setExtras(e.details);
scope.setExtras({ uploadOptions: options, storeOptions });
scope.captureException(e);
});
this.emit('upload.error', e);
});
return upload.multiupload(file);
}
}