@oneblink/storage 1.0.0-beta.4 → 1.0.0-beta.5
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/dist/OneBlinkStorageError.d.ts +19 -0
- package/dist/OneBlinkStorageError.js +19 -0
- package/dist/OneBlinkStorageError.js.map +1 -0
- package/dist/OneBlinkUploader.d.ts +87 -1
- package/dist/OneBlinkUploader.js +109 -0
- package/dist/OneBlinkUploader.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.js.map +1 -1
- package/dist/uploadToS3.js +35 -10
- package/dist/uploadToS3.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** An error class that extends `Error` */
|
|
2
|
+
export default class OneBlinkStorageError extends Error {
|
|
3
|
+
/** The http status code associated with the error */
|
|
4
|
+
httpStatusCode: number;
|
|
5
|
+
/** The original error that was thrown */
|
|
6
|
+
originalError?: Error;
|
|
7
|
+
/**
|
|
8
|
+
* Used to create an instance of the `OneBlinkStorageError` class.
|
|
9
|
+
*
|
|
10
|
+
* @param message The message associated with the error
|
|
11
|
+
* @param options The options associated with the error
|
|
12
|
+
*/
|
|
13
|
+
constructor(message: string, options: {
|
|
14
|
+
/** The http status code associated with the error */
|
|
15
|
+
httpStatusCode: number;
|
|
16
|
+
/** The original error that was thrown */
|
|
17
|
+
originalError?: Error;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/** An error class that extends `Error` */
|
|
4
|
+
class OneBlinkStorageError extends Error {
|
|
5
|
+
/**
|
|
6
|
+
* Used to create an instance of the `OneBlinkStorageError` class.
|
|
7
|
+
*
|
|
8
|
+
* @param message The message associated with the error
|
|
9
|
+
* @param options The options associated with the error
|
|
10
|
+
*/
|
|
11
|
+
constructor(message, options) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = 'OneBlinkStorageError';
|
|
14
|
+
this.originalError = options.originalError;
|
|
15
|
+
this.httpStatusCode = options.httpStatusCode;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.default = OneBlinkStorageError;
|
|
19
|
+
//# sourceMappingURL=OneBlinkStorageError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OneBlinkStorageError.js","sourceRoot":"","sources":["../src/OneBlinkStorageError.ts"],"names":[],"mappings":";;AAAA,0CAA0C;AAC1C,MAAqB,oBAAqB,SAAQ,KAAK;IAMrD;;;;;OAKG;IACH,YACE,OAAe,EACf,OAKC;QAED,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAA;QAElC,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAA;QAC1C,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,CAAA;IAC9C,CAAC;CACF;AA3BD,uCA2BC","sourcesContent":["/** An error class that extends `Error` */\nexport default class OneBlinkStorageError extends Error {\n /** The http status code associated with the error */\n httpStatusCode: number\n /** The original error that was thrown */\n originalError?: Error\n\n /**\n * Used to create an instance of the `OneBlinkStorageError` class.\n *\n * @param message The message associated with the error\n * @param options The options associated with the error\n */\n constructor(\n message: string,\n options: {\n /** The http status code associated with the error */\n httpStatusCode: number\n /** The original error that was thrown */\n originalError?: Error\n },\n ) {\n super(message)\n this.name = 'OneBlinkStorageError'\n\n this.originalError = options.originalError\n this.httpStatusCode = options.httpStatusCode\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AttachmentUploadData, StorageConstructorOptions, UploadFormSubmissionOptions, UploadOptions } from './types';
|
|
1
|
+
import { AttachmentUploadData, StorageConstructorOptions, UploadAssetOptions, UploadFormSubmissionOptions, UploadOptions } from './types';
|
|
2
2
|
import { SubmissionTypes } from '@oneblink/types';
|
|
3
3
|
/**
|
|
4
4
|
* Used to create an instance of the OneBlinkUploader, exposing methods to
|
|
@@ -136,4 +136,90 @@ export default class OneBlinkUploader {
|
|
|
136
136
|
submissionTimestamp: string;
|
|
137
137
|
draftDataId: string;
|
|
138
138
|
} & import("./types").BaseResponse>;
|
|
139
|
+
/**
|
|
140
|
+
* Upload an asset file. Asset files are always public.
|
|
141
|
+
*
|
|
142
|
+
* #### Example
|
|
143
|
+
*
|
|
144
|
+
* ```ts
|
|
145
|
+
* const abortController = new AbortController()
|
|
146
|
+
* const result = await uploader.uploadAttachment({
|
|
147
|
+
* onProgress: (progress) => {
|
|
148
|
+
* // ...
|
|
149
|
+
* },
|
|
150
|
+
* data: new Blob(['a string of data'], {
|
|
151
|
+
* type: 'text/plain',
|
|
152
|
+
* }),
|
|
153
|
+
* fileName: 'file.txt',
|
|
154
|
+
* contentType: 'text/plain',
|
|
155
|
+
* abortSignal: abortController.signal,
|
|
156
|
+
* organisatsionId: 'abc123',
|
|
157
|
+
* })
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @param data The asset upload data and options
|
|
161
|
+
* @returns The upload result
|
|
162
|
+
*/
|
|
163
|
+
uploadAsset({ onProgress, abortSignal, data, contentType, fileName, organisationId, }: UploadOptions & UploadAssetOptions & {
|
|
164
|
+
/** The identifier for the organisation that owns the asset */
|
|
165
|
+
organisationId: string;
|
|
166
|
+
}): Promise<{
|
|
167
|
+
url: string;
|
|
168
|
+
} & import("./types").BaseResponse>;
|
|
169
|
+
/**
|
|
170
|
+
* Upload an asset file for a product service such as Product Notifications.
|
|
171
|
+
* Asset files are always public.
|
|
172
|
+
*
|
|
173
|
+
* #### Example
|
|
174
|
+
*
|
|
175
|
+
* ```ts
|
|
176
|
+
* const abortController = new AbortController()
|
|
177
|
+
* const result = await uploader.uploadAttachment({
|
|
178
|
+
* onProgress: (progress) => {
|
|
179
|
+
* // ...
|
|
180
|
+
* },
|
|
181
|
+
* data: new Blob(['a string of data'], {
|
|
182
|
+
* type: 'text/plain',
|
|
183
|
+
* }),
|
|
184
|
+
* fileName: 'file.txt',
|
|
185
|
+
* contentType: 'text/plain',
|
|
186
|
+
* abortSignal: abortController.signal,
|
|
187
|
+
* })
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* @param data The asset upload data and options
|
|
191
|
+
* @returns The upload result
|
|
192
|
+
*/
|
|
193
|
+
uploadProductAsset({ onProgress, abortSignal, data, contentType, fileName, }: UploadOptions & UploadAssetOptions): Promise<{
|
|
194
|
+
url: string;
|
|
195
|
+
} & import("./types").BaseResponse>;
|
|
196
|
+
/**
|
|
197
|
+
* Upload form prefill data.
|
|
198
|
+
*
|
|
199
|
+
* #### Example
|
|
200
|
+
*
|
|
201
|
+
* ```ts
|
|
202
|
+
* const abortController = new AbortController()
|
|
203
|
+
* const result = await uploader.uploadPrefillData({
|
|
204
|
+
* onProgress: (progress) => {
|
|
205
|
+
* // ...
|
|
206
|
+
* },
|
|
207
|
+
* data: {
|
|
208
|
+
* field1: 'abc',
|
|
209
|
+
* field2: 123,
|
|
210
|
+
* },
|
|
211
|
+
* formId: 12,
|
|
212
|
+
* abortSignal: abortController.signal,
|
|
213
|
+
* })
|
|
214
|
+
* ```
|
|
215
|
+
*
|
|
216
|
+
* @param data The prefill upload data and options
|
|
217
|
+
* @returns The upload result
|
|
218
|
+
*/
|
|
219
|
+
uploadPrefillData({ formId, prefillData, onProgress, abortSignal, }: UploadOptions & {
|
|
220
|
+
/** The identifier for the form that the prefill data is associated with */
|
|
221
|
+
formId: number;
|
|
222
|
+
/** The prefill data to upload */
|
|
223
|
+
prefillData: SubmissionTypes.NewS3SubmissionData['submission'];
|
|
224
|
+
}): Promise<import("./types").BaseResponse>;
|
|
139
225
|
}
|
package/dist/OneBlinkUploader.js
CHANGED
|
@@ -165,6 +165,115 @@ class OneBlinkUploader {
|
|
|
165
165
|
onProgress,
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Upload an asset file. Asset files are always public.
|
|
170
|
+
*
|
|
171
|
+
* #### Example
|
|
172
|
+
*
|
|
173
|
+
* ```ts
|
|
174
|
+
* const abortController = new AbortController()
|
|
175
|
+
* const result = await uploader.uploadAttachment({
|
|
176
|
+
* onProgress: (progress) => {
|
|
177
|
+
* // ...
|
|
178
|
+
* },
|
|
179
|
+
* data: new Blob(['a string of data'], {
|
|
180
|
+
* type: 'text/plain',
|
|
181
|
+
* }),
|
|
182
|
+
* fileName: 'file.txt',
|
|
183
|
+
* contentType: 'text/plain',
|
|
184
|
+
* abortSignal: abortController.signal,
|
|
185
|
+
* organisatsionId: 'abc123',
|
|
186
|
+
* })
|
|
187
|
+
* ```
|
|
188
|
+
*
|
|
189
|
+
* @param data The asset upload data and options
|
|
190
|
+
* @returns The upload result
|
|
191
|
+
*/
|
|
192
|
+
async uploadAsset({ onProgress, abortSignal, data, contentType, fileName, organisationId, }) {
|
|
193
|
+
return await (0, uploadToS3_1.default)({
|
|
194
|
+
...this,
|
|
195
|
+
contentType,
|
|
196
|
+
body: data,
|
|
197
|
+
key: `organisations/${organisationId}/assets`,
|
|
198
|
+
abortSignal,
|
|
199
|
+
onProgress,
|
|
200
|
+
requestBodyHeader: {
|
|
201
|
+
fileName,
|
|
202
|
+
},
|
|
203
|
+
isPublic: true,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Upload an asset file for a product service such as Product Notifications.
|
|
208
|
+
* Asset files are always public.
|
|
209
|
+
*
|
|
210
|
+
* #### Example
|
|
211
|
+
*
|
|
212
|
+
* ```ts
|
|
213
|
+
* const abortController = new AbortController()
|
|
214
|
+
* const result = await uploader.uploadAttachment({
|
|
215
|
+
* onProgress: (progress) => {
|
|
216
|
+
* // ...
|
|
217
|
+
* },
|
|
218
|
+
* data: new Blob(['a string of data'], {
|
|
219
|
+
* type: 'text/plain',
|
|
220
|
+
* }),
|
|
221
|
+
* fileName: 'file.txt',
|
|
222
|
+
* contentType: 'text/plain',
|
|
223
|
+
* abortSignal: abortController.signal,
|
|
224
|
+
* })
|
|
225
|
+
* ```
|
|
226
|
+
*
|
|
227
|
+
* @param data The asset upload data and options
|
|
228
|
+
* @returns The upload result
|
|
229
|
+
*/
|
|
230
|
+
async uploadProductAsset({ onProgress, abortSignal, data, contentType, fileName, }) {
|
|
231
|
+
return await (0, uploadToS3_1.default)({
|
|
232
|
+
...this,
|
|
233
|
+
contentType,
|
|
234
|
+
body: data,
|
|
235
|
+
key: `administration/assets`,
|
|
236
|
+
abortSignal,
|
|
237
|
+
onProgress,
|
|
238
|
+
requestBodyHeader: {
|
|
239
|
+
fileName,
|
|
240
|
+
},
|
|
241
|
+
isPublic: true,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Upload form prefill data.
|
|
246
|
+
*
|
|
247
|
+
* #### Example
|
|
248
|
+
*
|
|
249
|
+
* ```ts
|
|
250
|
+
* const abortController = new AbortController()
|
|
251
|
+
* const result = await uploader.uploadPrefillData({
|
|
252
|
+
* onProgress: (progress) => {
|
|
253
|
+
* // ...
|
|
254
|
+
* },
|
|
255
|
+
* data: {
|
|
256
|
+
* field1: 'abc',
|
|
257
|
+
* field2: 123,
|
|
258
|
+
* },
|
|
259
|
+
* formId: 12,
|
|
260
|
+
* abortSignal: abortController.signal,
|
|
261
|
+
* })
|
|
262
|
+
* ```
|
|
263
|
+
*
|
|
264
|
+
* @param data The prefill upload data and options
|
|
265
|
+
* @returns The upload result
|
|
266
|
+
*/
|
|
267
|
+
async uploadPrefillData({ formId, prefillData, onProgress, abortSignal, }) {
|
|
268
|
+
return await (0, uploadToS3_1.default)({
|
|
269
|
+
...this,
|
|
270
|
+
contentType: 'application/json',
|
|
271
|
+
body: JSON.stringify(prefillData),
|
|
272
|
+
key: `forms/${formId}/pre-fill`,
|
|
273
|
+
abortSignal,
|
|
274
|
+
onProgress,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
168
277
|
}
|
|
169
278
|
exports.default = OneBlinkUploader;
|
|
170
279
|
//# sourceMappingURL=OneBlinkUploader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OneBlinkUploader.js","sourceRoot":"","sources":["../src/OneBlinkUploader.ts"],"names":[],"mappings":";;;;;AAAA,8DAAqC;AAQrC,8FAAqE;AAErE;;;GAGG;AACH,MAAqB,gBAAgB;IAKnC;;;;;;;;;;;;OAYG;IACH,YAAY,KAAgC;QAC1C,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAA;QAChC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAA;QAC1B,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAA;IACpC,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,KAAK,CAAC,gBAAgB,CAAC,EACrB,UAAU,EACV,UAAU,EACV,MAAM,EACN,SAAS,EACT,gCAAgC,EAChC,KAAK,EACL,UAAU,EACV,UAAU,EACV,MAAM,EACN,YAAY,EACZ,mBAAmB,EACnB,UAAU,EACV,UAAU,EACV,WAAW,GAgBZ;QACC,MAAM,mBAAmB,GAAwC;YAC/D,UAAU;YACV,UAAU;YACV,MAAM;SACP,CAAA;QACD,MAAM,IAAI,GAAG,IAAA,oCAA0B,EAAC;YACtC,SAAS;YACT,gCAAgC;YAChC,KAAK;SACN,CAAC,CAAA;QAEF,OAAO,MAAM,IAAA,oBAAU,EAKpB;YACD,GAAG,IAAI;YACP,WAAW,EAAE,kBAAkB;YAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,mBAAmB,CAAC;YACzC,GAAG,EAAE,SAAS,UAAU,CAAC,EAAE,cAAc;YACzC,IAAI;YACJ,WAAW;YACX,UAAU;YACV,iBAAiB,EAAE;gBACjB,UAAU;gBACV,UAAU;gBACV,MAAM;gBACN,YAAY;gBACZ,mBAAmB;gBACnB,UAAU,EAAE,UAAU,IAAI,EAAE;gBAC5B,KAAK;gBACL,gCAAgC;aACjC;SACF,CAAC,CAAA;IACJ,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAK,CAAC,gBAAgB,CAAC,EACrB,MAAM,EACN,QAAQ,EACR,WAAW,EACX,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,WAAW,GAcZ;QACC,OAAO,MAAM,IAAA,oBAAU,EAIpB;YACD,GAAG,IAAI;YACP,WAAW;YACX,IAAI,EAAE,IAAI;YACV,GAAG,EAAE,SAAS,MAAM,cAAc;YAClC,WAAW;YACX,UAAU;YACV,QAAQ,EAAE,CAAC,SAAS;YACpB,kBAAkB,EAAE,gCAAgC,kBAAkB,CAAC,QAAQ,CAAC,EAAE;YAClF,iBAAiB,EAAE;gBACjB,QAAQ;gBACR,QAAQ;aACT;SACF,CAAC,CAAA;IACJ,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,KAAK,CAAC,qBAAqB,CAAC,EAC1B,UAAU,EACV,UAAU,EACV,MAAM,EACN,SAAS,EACT,gCAAgC,EAChC,KAAK,EACL,UAAU,EACV,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,WAAW,GAIZ;QACC,OAAO,MAAM,IAAA,oBAAU,EAGpB;YACD,GAAG,IAAI;YACP,WAAW,EAAE,kBAAkB;YAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,UAAU;gBACV,UAAU;gBACV,UAAU;gBACV,kBAAkB;gBAClB,UAAU;gBACV,MAAM;aACP,CAAC;YACF,GAAG,EAAE,SAAS,UAAU,CAAC,EAAE,SAAS;YACpC,IAAI,EAAE,IAAA,oCAA0B,EAAC;gBAC/B,SAAS;gBACT,KAAK;gBACL,gCAAgC;aACjC,CAAC;YACF,WAAW;YACX,UAAU;SACX,CAAC,CAAA;IACJ,CAAC;CACF;AAnPD,mCAmPC","sourcesContent":["import uploadToS3 from './uploadToS3'\nimport {\n AttachmentUploadData,\n StorageConstructorOptions,\n UploadFormSubmissionOptions,\n UploadOptions,\n} from './types'\nimport { SubmissionTypes } from '@oneblink/types'\nimport generateFormSubmissionTags from './generateFormSubmissionTags'\n\n/**\n * Used to create an instance of the OneBlinkUploader, exposing methods to\n * upload submissions and other types of files\n */\nexport default class OneBlinkUploader {\n apiOrigin: StorageConstructorOptions['apiOrigin']\n region: StorageConstructorOptions['region']\n getIdToken: StorageConstructorOptions['getIdToken']\n\n /**\n * #### Example\n *\n * ```typescript\n * import { OneBlinkUploader } from '@oneblink/uploads'\n *\n * const uploader = new OneBlinkUploader({\n * apiOrigin: 'https://auth-api.blinkm.io',\n * region: 'ap-southeast-2',\n * getIdToken: () => getAccessToken(),\n * })\n * ```\n */\n constructor(props: StorageConstructorOptions) {\n this.apiOrigin = props.apiOrigin\n this.region = props.region\n this.getIdToken = props.getIdToken\n }\n\n /**\n * Upload a submission.\n *\n * #### Example\n *\n * ```ts\n * const result = await uploader.uploadSubmission({\n * submission: {\n * // ...\n * },\n * definition: {\n * // ...\n * },\n * formsAppId: 1,\n * onProgress: (progress) => {\n * // ...\n * },\n * })\n * ```\n *\n * @param data The submission upload data and options\n * @returns The upload result\n */\n async uploadSubmission({\n submission,\n definition,\n device,\n userToken,\n previousFormSubmissionApprovalId,\n jobId,\n formsAppId,\n externalId,\n taskId,\n taskActionId,\n taskGroupInstanceId,\n recaptchas,\n onProgress,\n abortSignal,\n }: UploadFormSubmissionOptions & {\n /** The identifier of the task that will be marked as completed */\n taskId?: string\n /** The identifier of the task action that was used to complete the task */\n taskActionId?: string\n /**\n * The identifier of the task group instance that the completed task is\n * associated with\n */\n taskGroupInstanceId?: string\n /** The reCAPTCHA tokens to validate the submission */\n recaptchas?: {\n /** A reCAPTCHA token */\n token: string\n }[]\n }) {\n const newS3SubmissionData: SubmissionTypes.NewS3SubmissionData = {\n submission,\n definition,\n device,\n }\n const tags = generateFormSubmissionTags({\n userToken,\n previousFormSubmissionApprovalId,\n jobId,\n })\n\n return await uploadToS3<{\n submissionTimestamp: string\n submissionId: string\n pdfAccessToken?: string\n preventPayment: boolean\n }>({\n ...this,\n contentType: 'application/json',\n body: JSON.stringify(newS3SubmissionData),\n key: `forms/${definition.id}/submissions`,\n tags,\n abortSignal,\n onProgress,\n requestBodyHeader: {\n formsAppId,\n externalId,\n taskId,\n taskActionId,\n taskGroupInstanceId,\n recaptchas: recaptchas || [],\n jobId,\n previousFormSubmissionApprovalId,\n },\n })\n }\n\n /**\n * Upload an form submission attachment.\n *\n * #### Example\n *\n * ```ts\n * const abortController = new AbortController()\n * const result = await uploader.uploadAttachment({\n * formId: 1,\n * data: new Blob(['a string of data'], {\n * type: 'text/plain',\n * }),\n * fileName: 'file.txt',\n * contentType: 'text/plain',\n * isPrivate: true,\n * abortSignal: abortController.signal,\n * })\n * ```\n *\n * @param data The attachment upload data and options\n * @returns The upload result\n */\n async uploadAttachment({\n formId,\n fileName,\n contentType,\n isPrivate,\n data,\n username,\n onProgress,\n abortSignal,\n }: UploadOptions & {\n /** The identifier for the form that is being completed */\n formId: number\n /** The name of the file being uploaded */\n fileName: string\n /** A standard MIME type describing the format of the contents */\n contentType: string\n /** Set to `true` to prevent the file from being downloaded publicly */\n isPrivate: boolean\n /** The file data to upload */\n data: AttachmentUploadData\n /** A username to allow a single user to download the attachment file */\n username?: string\n }) {\n return await uploadToS3<{\n url: string\n attachmentDataId: string\n uploadedAt: string\n }>({\n ...this,\n contentType,\n body: data,\n key: `forms/${formId}/attachments`,\n abortSignal,\n onProgress,\n isPublic: !isPrivate,\n contentDisposition: `attachment; filename*=UTF-8''${encodeURIComponent(fileName)}`,\n requestBodyHeader: {\n username,\n fileName,\n },\n })\n }\n\n /**\n * Upload a draft submission.\n *\n * #### Example\n *\n * ```ts\n * const result = await uploader.uploadDraftSubmission({\n * submission: {\n * // ...\n * },\n * definition: {\n * // ...\n * },\n * formsAppId: 1,\n * onProgress: (progress) => {\n * // ...\n * },\n * })\n * ```\n *\n * @param data The submission upload data and options\n * @returns The upload result\n */\n async uploadDraftSubmission({\n submission,\n definition,\n device,\n userToken,\n previousFormSubmissionApprovalId,\n jobId,\n formsAppId,\n externalId,\n lastElementUpdated,\n onProgress,\n abortSignal,\n }: UploadFormSubmissionOptions & {\n /** The identifier for the last element that was used before saving draft */\n lastElementUpdated?: SubmissionTypes.NewS3SubmissionData['lastElementUpdated']\n }) {\n return await uploadToS3<{\n submissionTimestamp: string\n draftDataId: string\n }>({\n ...this,\n contentType: 'application/json',\n body: JSON.stringify({\n definition,\n submission,\n formsAppId,\n lastElementUpdated,\n externalId,\n device,\n }),\n key: `forms/${definition.id}/drafts`,\n tags: generateFormSubmissionTags({\n userToken,\n jobId,\n previousFormSubmissionApprovalId,\n }),\n abortSignal,\n onProgress,\n })\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"OneBlinkUploader.js","sourceRoot":"","sources":["../src/OneBlinkUploader.ts"],"names":[],"mappings":"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","sourcesContent":["import uploadToS3 from './uploadToS3'\nimport {\n AttachmentUploadData,\n StorageConstructorOptions,\n UploadAssetOptions,\n UploadFormSubmissionOptions,\n UploadOptions,\n} from './types'\nimport { SubmissionTypes } from '@oneblink/types'\nimport generateFormSubmissionTags from './generateFormSubmissionTags'\n/**\n * Used to create an instance of the OneBlinkUploader, exposing methods to\n * upload submissions and other types of files\n */\nexport default class OneBlinkUploader {\n apiOrigin: StorageConstructorOptions['apiOrigin']\n region: StorageConstructorOptions['region']\n getIdToken: StorageConstructorOptions['getIdToken']\n\n /**\n * #### Example\n *\n * ```typescript\n * import { OneBlinkUploader } from '@oneblink/uploads'\n *\n * const uploader = new OneBlinkUploader({\n * apiOrigin: 'https://auth-api.blinkm.io',\n * region: 'ap-southeast-2',\n * getIdToken: () => getAccessToken(),\n * })\n * ```\n */\n constructor(props: StorageConstructorOptions) {\n this.apiOrigin = props.apiOrigin\n this.region = props.region\n this.getIdToken = props.getIdToken\n }\n\n /**\n * Upload a submission.\n *\n * #### Example\n *\n * ```ts\n * const result = await uploader.uploadSubmission({\n * submission: {\n * // ...\n * },\n * definition: {\n * // ...\n * },\n * formsAppId: 1,\n * onProgress: (progress) => {\n * // ...\n * },\n * })\n * ```\n *\n * @param data The submission upload data and options\n * @returns The upload result\n */\n async uploadSubmission({\n submission,\n definition,\n device,\n userToken,\n previousFormSubmissionApprovalId,\n jobId,\n formsAppId,\n externalId,\n taskId,\n taskActionId,\n taskGroupInstanceId,\n recaptchas,\n onProgress,\n abortSignal,\n }: UploadFormSubmissionOptions & {\n /** The identifier of the task that will be marked as completed */\n taskId?: string\n /** The identifier of the task action that was used to complete the task */\n taskActionId?: string\n /**\n * The identifier of the task group instance that the completed task is\n * associated with\n */\n taskGroupInstanceId?: string\n /** The reCAPTCHA tokens to validate the submission */\n recaptchas?: {\n /** A reCAPTCHA token */\n token: string\n }[]\n }) {\n const newS3SubmissionData: SubmissionTypes.NewS3SubmissionData = {\n submission,\n definition,\n device,\n }\n const tags = generateFormSubmissionTags({\n userToken,\n previousFormSubmissionApprovalId,\n jobId,\n })\n\n return await uploadToS3<{\n submissionTimestamp: string\n submissionId: string\n pdfAccessToken?: string\n preventPayment: boolean\n }>({\n ...this,\n contentType: 'application/json',\n body: JSON.stringify(newS3SubmissionData),\n key: `forms/${definition.id}/submissions`,\n tags,\n abortSignal,\n onProgress,\n requestBodyHeader: {\n formsAppId,\n externalId,\n taskId,\n taskActionId,\n taskGroupInstanceId,\n recaptchas: recaptchas || [],\n jobId,\n previousFormSubmissionApprovalId,\n },\n })\n }\n\n /**\n * Upload an form submission attachment.\n *\n * #### Example\n *\n * ```ts\n * const abortController = new AbortController()\n * const result = await uploader.uploadAttachment({\n * formId: 1,\n * data: new Blob(['a string of data'], {\n * type: 'text/plain',\n * }),\n * fileName: 'file.txt',\n * contentType: 'text/plain',\n * isPrivate: true,\n * abortSignal: abortController.signal,\n * })\n * ```\n *\n * @param data The attachment upload data and options\n * @returns The upload result\n */\n async uploadAttachment({\n formId,\n fileName,\n contentType,\n isPrivate,\n data,\n username,\n onProgress,\n abortSignal,\n }: UploadOptions & {\n /** The identifier for the form that is being completed */\n formId: number\n /** The name of the file being uploaded */\n fileName: string\n /** A standard MIME type describing the format of the contents */\n contentType: string\n /** Set to `true` to prevent the file from being downloaded publicly */\n isPrivate: boolean\n /** The file data to upload */\n data: AttachmentUploadData\n /** A username to allow a single user to download the attachment file */\n username?: string\n }) {\n return await uploadToS3<{\n url: string\n attachmentDataId: string\n uploadedAt: string\n }>({\n ...this,\n contentType,\n body: data,\n key: `forms/${formId}/attachments`,\n abortSignal,\n onProgress,\n isPublic: !isPrivate,\n contentDisposition: `attachment; filename*=UTF-8''${encodeURIComponent(fileName)}`,\n requestBodyHeader: {\n username,\n fileName,\n },\n })\n }\n\n /**\n * Upload a draft submission.\n *\n * #### Example\n *\n * ```ts\n * const result = await uploader.uploadDraftSubmission({\n * submission: {\n * // ...\n * },\n * definition: {\n * // ...\n * },\n * formsAppId: 1,\n * onProgress: (progress) => {\n * // ...\n * },\n * })\n * ```\n *\n * @param data The submission upload data and options\n * @returns The upload result\n */\n async uploadDraftSubmission({\n submission,\n definition,\n device,\n userToken,\n previousFormSubmissionApprovalId,\n jobId,\n formsAppId,\n externalId,\n lastElementUpdated,\n onProgress,\n abortSignal,\n }: UploadFormSubmissionOptions & {\n /** The identifier for the last element that was used before saving draft */\n lastElementUpdated?: SubmissionTypes.NewS3SubmissionData['lastElementUpdated']\n }) {\n return await uploadToS3<{\n submissionTimestamp: string\n draftDataId: string\n }>({\n ...this,\n contentType: 'application/json',\n body: JSON.stringify({\n definition,\n submission,\n formsAppId,\n lastElementUpdated,\n externalId,\n device,\n }),\n key: `forms/${definition.id}/drafts`,\n tags: generateFormSubmissionTags({\n userToken,\n jobId,\n previousFormSubmissionApprovalId,\n }),\n abortSignal,\n onProgress,\n })\n }\n\n /**\n * Upload an asset file. Asset files are always public.\n *\n * #### Example\n *\n * ```ts\n * const abortController = new AbortController()\n * const result = await uploader.uploadAttachment({\n * onProgress: (progress) => {\n * // ...\n * },\n * data: new Blob(['a string of data'], {\n * type: 'text/plain',\n * }),\n * fileName: 'file.txt',\n * contentType: 'text/plain',\n * abortSignal: abortController.signal,\n * organisatsionId: 'abc123',\n * })\n * ```\n *\n * @param data The asset upload data and options\n * @returns The upload result\n */\n async uploadAsset({\n onProgress,\n abortSignal,\n data,\n contentType,\n fileName,\n organisationId,\n }: UploadOptions &\n UploadAssetOptions & {\n /** The identifier for the organisation that owns the asset */\n organisationId: string\n }) {\n return await uploadToS3<{\n url: string\n }>({\n ...this,\n contentType,\n body: data,\n key: `organisations/${organisationId}/assets`,\n abortSignal,\n onProgress,\n requestBodyHeader: {\n fileName,\n },\n isPublic: true,\n })\n }\n\n /**\n * Upload an asset file for a product service such as Product Notifications.\n * Asset files are always public.\n *\n * #### Example\n *\n * ```ts\n * const abortController = new AbortController()\n * const result = await uploader.uploadAttachment({\n * onProgress: (progress) => {\n * // ...\n * },\n * data: new Blob(['a string of data'], {\n * type: 'text/plain',\n * }),\n * fileName: 'file.txt',\n * contentType: 'text/plain',\n * abortSignal: abortController.signal,\n * })\n * ```\n *\n * @param data The asset upload data and options\n * @returns The upload result\n */\n async uploadProductAsset({\n onProgress,\n abortSignal,\n data,\n contentType,\n fileName,\n }: UploadOptions & UploadAssetOptions) {\n return await uploadToS3<{\n url: string\n }>({\n ...this,\n contentType,\n body: data,\n key: `administration/assets`,\n abortSignal,\n onProgress,\n requestBodyHeader: {\n fileName,\n },\n isPublic: true,\n })\n }\n\n /**\n * Upload form prefill data.\n *\n * #### Example\n *\n * ```ts\n * const abortController = new AbortController()\n * const result = await uploader.uploadPrefillData({\n * onProgress: (progress) => {\n * // ...\n * },\n * data: {\n * field1: 'abc',\n * field2: 123,\n * },\n * formId: 12,\n * abortSignal: abortController.signal,\n * })\n * ```\n *\n * @param data The prefill upload data and options\n * @returns The upload result\n */\n async uploadPrefillData({\n formId,\n prefillData,\n onProgress,\n abortSignal,\n }: UploadOptions & {\n /** The identifier for the form that the prefill data is associated with */\n formId: number\n /** The prefill data to upload */\n prefillData: SubmissionTypes.NewS3SubmissionData['submission']\n }) {\n return await uploadToS3({\n ...this,\n contentType: 'application/json',\n body: JSON.stringify(prefillData),\n key: `forms/${formId}/pre-fill`,\n abortSignal,\n onProgress,\n })\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -17,7 +17,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.OneBlinkUploader = void 0;
|
|
20
|
+
exports.OneBlinkUploader = exports.OneBlinkStorageError = void 0;
|
|
21
|
+
var OneBlinkStorageError_1 = require("./OneBlinkStorageError");
|
|
22
|
+
Object.defineProperty(exports, "OneBlinkStorageError", { enumerable: true, get: function () { return __importDefault(OneBlinkStorageError_1).default; } });
|
|
21
23
|
var OneBlinkUploader_1 = require("./OneBlinkUploader");
|
|
22
24
|
Object.defineProperty(exports, "OneBlinkUploader", { enumerable: true, get: function () { return __importDefault(OneBlinkUploader_1).default; } });
|
|
23
25
|
__exportStar(require("./types"), exports);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,uDAAgE;AAAvD,qIAAA,OAAO,OAAoB;AACpC,0CAAuB","sourcesContent":["export { default as OneBlinkUploader } from './OneBlinkUploader'\nexport * from './types'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,+DAAwE;AAA/D,6IAAA,OAAO,OAAwB;AACxC,uDAAgE;AAAvD,qIAAA,OAAO,OAAoB;AACpC,0CAAuB","sourcesContent":["export { default as OneBlinkStorageError } from './OneBlinkStorageError'\nexport { default as OneBlinkUploader } from './OneBlinkUploader'\nexport * from './types'\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -49,3 +49,11 @@ export type UploadFormSubmissionOptions = UploadOptions & {
|
|
|
49
49
|
/** The identifier of the job that will be marked as submitted */
|
|
50
50
|
jobId?: string;
|
|
51
51
|
};
|
|
52
|
+
export type UploadAssetOptions = UploadOptions & {
|
|
53
|
+
/** The file data to upload */
|
|
54
|
+
data: AttachmentUploadData;
|
|
55
|
+
/** A standard MIME type describing the format of the contents */
|
|
56
|
+
contentType: string;
|
|
57
|
+
/** The name of the file being uploaded */
|
|
58
|
+
fileName: string;
|
|
59
|
+
};
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import { PutObjectCommandInput } from '@aws-sdk/client-s3'\nimport { AWSTypes, SubmissionTypes } from '@oneblink/types'\n\nexport type ProgressListenerEvent = { progress: number; total: number }\nexport type ProgressListener = (progress: ProgressListenerEvent) => void\n\n/** The properties to be passed to the Storage class constructors */\nexport type StorageConstructorOptions = {\n /** The API origin URL used to communicate with the OneBlink API */\n apiOrigin: string\n /** The AWS region to upload the submission to */\n region: string\n /**\n * A function that returns a promise resolving to an access token. If the\n * promise resolves to a truthy value, the `x-oneblink-authorization` header\n * will be set with the value.\n */\n getIdToken: () => Promise<string | undefined>\n}\n\nexport type BaseResponse = {\n s3: AWSTypes.S3Configuration\n}\n\nexport type UploadOptions = {\n /** An optional progress listener for tracking the progress of the upload */\n onProgress?: ProgressListener\n /** An optional AbortSignal that can be used to abort the upload */\n abortSignal?: AbortSignal\n}\n\nexport type AttachmentUploadData = NonNullable<PutObjectCommandInput['Body']>\n\nexport type UploadFormSubmissionOptions = UploadOptions & {\n /** The submission data */\n submission: SubmissionTypes.NewS3SubmissionData['submission']\n /** The form that is being submitted */\n definition: SubmissionTypes.NewS3SubmissionData['definition']\n /** The device the form is being submitted */\n device?: SubmissionTypes.NewS3SubmissionData['device']\n /** The identifier for the forms app that is being submitted from */\n formsAppId: number\n /** An encrypted token that repraesents the user */\n userToken?: string\n /** The external identifier that represents the submission */\n externalId?: string\n /**\n * The identifier for the previous FormSubmissionApproval that lead to a\n * clarification request\n */\n previousFormSubmissionApprovalId?: string\n /** The identifier of the job that will be marked as submitted */\n jobId?: string\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import { PutObjectCommandInput } from '@aws-sdk/client-s3'\nimport { AWSTypes, SubmissionTypes } from '@oneblink/types'\n\nexport type ProgressListenerEvent = { progress: number; total: number }\nexport type ProgressListener = (progress: ProgressListenerEvent) => void\n\n/** The properties to be passed to the Storage class constructors */\nexport type StorageConstructorOptions = {\n /** The API origin URL used to communicate with the OneBlink API */\n apiOrigin: string\n /** The AWS region to upload the submission to */\n region: string\n /**\n * A function that returns a promise resolving to an access token. If the\n * promise resolves to a truthy value, the `x-oneblink-authorization` header\n * will be set with the value.\n */\n getIdToken: () => Promise<string | undefined>\n}\n\nexport type BaseResponse = {\n s3: AWSTypes.S3Configuration\n}\n\nexport type UploadOptions = {\n /** An optional progress listener for tracking the progress of the upload */\n onProgress?: ProgressListener\n /** An optional AbortSignal that can be used to abort the upload */\n abortSignal?: AbortSignal\n}\n\nexport type AttachmentUploadData = NonNullable<PutObjectCommandInput['Body']>\n\nexport type UploadFormSubmissionOptions = UploadOptions & {\n /** The submission data */\n submission: SubmissionTypes.NewS3SubmissionData['submission']\n /** The form that is being submitted */\n definition: SubmissionTypes.NewS3SubmissionData['definition']\n /** The device the form is being submitted */\n device?: SubmissionTypes.NewS3SubmissionData['device']\n /** The identifier for the forms app that is being submitted from */\n formsAppId: number\n /** An encrypted token that repraesents the user */\n userToken?: string\n /** The external identifier that represents the submission */\n externalId?: string\n /**\n * The identifier for the previous FormSubmissionApproval that lead to a\n * clarification request\n */\n previousFormSubmissionApprovalId?: string\n /** The identifier of the job that will be marked as submitted */\n jobId?: string\n}\n\nexport type UploadAssetOptions = UploadOptions & {\n /** The file data to upload */\n data: AttachmentUploadData\n /** A standard MIME type describing the format of the contents */\n contentType: string\n /** The name of the file being uploaded */\n fileName: string\n}\n"]}
|
package/dist/uploadToS3.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.determineUploadProgressAsPercentage = exports.determineQueueSize = void 0;
|
|
4
7
|
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
5
8
|
const lib_storage_1 = require("@aws-sdk/lib-storage");
|
|
6
9
|
const fetch_http_handler_1 = require("@smithy/fetch-http-handler");
|
|
10
|
+
const OneBlinkStorageError_1 = __importDefault(require("./OneBlinkStorageError"));
|
|
7
11
|
const RETRY_ATTEMPTS = 3;
|
|
8
12
|
// Our own custom request handler to allow setting customer headers for
|
|
9
13
|
// authentication. Also allow the response header which includes dynamic
|
|
@@ -23,14 +27,18 @@ class OBRequestHandler extends fetch_http_handler_1.FetchHttpHandler {
|
|
|
23
27
|
if (this.requestBodyHeader) {
|
|
24
28
|
request.headers['x-oneblink-request-body'] = JSON.stringify(this.requestBodyHeader);
|
|
25
29
|
}
|
|
26
|
-
if (this.
|
|
27
|
-
request.query['key'] = this.
|
|
30
|
+
if (this.successResponse) {
|
|
31
|
+
request.query['key'] = this.successResponse.s3.key;
|
|
28
32
|
}
|
|
29
33
|
const result = await super.handle(request, options);
|
|
30
|
-
|
|
34
|
+
if (result.response.headers['content-type'] === 'application/json' &&
|
|
35
|
+
result.response.statusCode >= 400) {
|
|
36
|
+
const fetchResponse = new Response(result.response.body);
|
|
37
|
+
this.failResponse = await fetchResponse.json();
|
|
38
|
+
}
|
|
31
39
|
const response = result.response.headers['x-oneblink-response'];
|
|
32
|
-
if (response) {
|
|
33
|
-
this.
|
|
40
|
+
if (typeof response === 'string') {
|
|
41
|
+
this.successResponse = JSON.parse(response);
|
|
34
42
|
}
|
|
35
43
|
return result;
|
|
36
44
|
}
|
|
@@ -55,6 +63,12 @@ async function uploadToS3({ region, apiOrigin, key, body, requestBodyHeader, tag
|
|
|
55
63
|
},
|
|
56
64
|
maxAttempts: RETRY_ATTEMPTS,
|
|
57
65
|
});
|
|
66
|
+
if (isPublic) {
|
|
67
|
+
if (!tags) {
|
|
68
|
+
tags = new URLSearchParams();
|
|
69
|
+
}
|
|
70
|
+
tags === null || tags === void 0 ? void 0 : tags.append('public-read', 'yes');
|
|
71
|
+
}
|
|
58
72
|
const managedUpload = new lib_storage_1.Upload({
|
|
59
73
|
client: s3Client,
|
|
60
74
|
partSize: 5 * 1024 * 1024,
|
|
@@ -77,7 +91,7 @@ async function uploadToS3({ region, apiOrigin, key, body, requestBodyHeader, tag
|
|
|
77
91
|
ServerSideEncryption: 'AES256',
|
|
78
92
|
Expires: new Date(new Date().setFullYear(new Date().getFullYear() + 1)), // Max 1 year
|
|
79
93
|
CacheControl: 'max-age=31536000', // Max 1 year(365 days),
|
|
80
|
-
ACL:
|
|
94
|
+
ACL: 'bucket-owner-full-control',
|
|
81
95
|
Tagging: tags === null || tags === void 0 ? void 0 : tags.toString(),
|
|
82
96
|
},
|
|
83
97
|
});
|
|
@@ -94,11 +108,22 @@ async function uploadToS3({ region, apiOrigin, key, body, requestBodyHeader, tag
|
|
|
94
108
|
abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.addEventListener('abort', () => {
|
|
95
109
|
managedUpload.abort();
|
|
96
110
|
});
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
111
|
+
try {
|
|
112
|
+
await managedUpload.done();
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
if (requestHandler.failResponse) {
|
|
116
|
+
throw new OneBlinkStorageError_1.default(requestHandler.failResponse.message, {
|
|
117
|
+
httpStatusCode: requestHandler.failResponse.statusCode,
|
|
118
|
+
originalError: error instanceof Error ? error : undefined,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
if (!requestHandler.successResponse) {
|
|
124
|
+
throw new Error('No response from server. Something went wrong in "@oneBlink/uploads".');
|
|
100
125
|
}
|
|
101
|
-
return requestHandler.
|
|
126
|
+
return requestHandler.successResponse;
|
|
102
127
|
}
|
|
103
128
|
exports.default = uploadToS3;
|
|
104
129
|
const determineQueueSize = () => {
|
package/dist/uploadToS3.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uploadToS3.js","sourceRoot":"","sources":["../src/uploadToS3.ts"],"names":[],"mappings":"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","sourcesContent":["import { PutObjectCommandInput, S3Client } from '@aws-sdk/client-s3'\nimport { Upload, Progress } from '@aws-sdk/lib-storage'\nimport { HttpHandlerOptions } from '@smithy/types'\nimport { HttpRequest } from '@smithy/protocol-http'\nimport { FetchHttpHandler } from '@smithy/fetch-http-handler'\nimport { StorageConstructorOptions, BaseResponse, UploadOptions } from './types'\n\nconst RETRY_ATTEMPTS = 3\n\ntype RequestBodyHeader = Record<string, unknown>\n// Our own custom request handler to allow setting customer headers for\n// authentication. Also allow the response header which includes dynamic\n// data from the lambda at edge to be retrieved and held for later when\n// the upload has completed.\nclass OBRequestHandler<T> extends FetchHttpHandler {\n constructor({\n getIdToken,\n requestBodyHeader,\n }: {\n getIdToken: StorageConstructorOptions['getIdToken']\n requestBodyHeader?: RequestBodyHeader\n }) {\n super()\n this.getIdToken = getIdToken\n this.requestBodyHeader = requestBodyHeader\n }\n\n getIdToken: StorageConstructorOptions['getIdToken']\n requestBodyHeader?: RequestBodyHeader\n response?: T & BaseResponse\n\n async handle(request: HttpRequest, options?: HttpHandlerOptions) {\n const token = await this.getIdToken()\n if (token) {\n request.headers['x-oneblink-authorization'] = 'Bearer ' + token\n }\n if (this.requestBodyHeader) {\n request.headers['x-oneblink-request-body'] = JSON.stringify(\n this.requestBodyHeader,\n )\n }\n if (this.response) {\n request.query['key'] = this.response.s3.key\n }\n const result = await super.handle(request, options)\n console.log('result', result)\n const response = result.response.headers['x-oneblink-response'] as\n | string\n | undefined\n if (response) {\n this.response = JSON.parse(response)\n }\n return result\n }\n}\n\nconst endpointSuffix = '/storage'\n\n/** The properties to be passed to the uploadToS3 function */\ninterface UploadToS3Props extends UploadOptions, StorageConstructorOptions {\n /** The key of the file that is being uploaded. */\n key: string\n /**\n * The body of the request. This can be a string, a Buffer, a Blob, a\n * ReadableStream, or a Readable.\n */\n body: PutObjectCommandInput['Body']\n /** Optional header to be included in the request to the OneBlink API */\n requestBodyHeader?: RequestBodyHeader\n /** An optional set of tags that will be applied to the uploaded file */\n tags?: URLSearchParams\n /** A standard MIME type describing the format of the contents */\n contentType: PutObjectCommandInput['ContentType']\n /** Set to `true` to make the upload available to download publicly */\n isPublic?: boolean\n}\n\nasync function uploadToS3<T>({\n region,\n apiOrigin,\n key,\n body,\n requestBodyHeader,\n tags,\n getIdToken,\n onProgress,\n abortSignal,\n contentType,\n isPublic,\n}: UploadToS3Props) {\n const requestHandler = new OBRequestHandler<T>({\n getIdToken,\n requestBodyHeader,\n })\n\n const s3Client = new S3Client({\n // The suffix on the end is important as it will allow us to route\n // traffic to S3 via lambda at edge instead of going to our API\n endpoint: `${apiOrigin}${endpointSuffix}`,\n region: region,\n requestHandler,\n // Have to put something here otherwise the SDK throws errors.\n // Might be able to remove the validation from the middleware somehow?\n credentials: {\n accessKeyId: 'AWS_ACCESS_KEY_ID',\n secretAccessKey: 'AWS_SECRET_ACCESS_KEY',\n },\n maxAttempts: RETRY_ATTEMPTS,\n })\n\n const managedUpload = new Upload({\n client: s3Client,\n partSize: 5 * 1024 * 1024,\n queueSize: determineQueueSize(),\n //Related github issue: https://github.com/aws/aws-sdk-js-v3/issues/2311\n //This is a variable that is set to false by default, setting it to true\n //means that it will force the upload to fail when one part fails on\n //an upload. The S3 client has built in retry logic to retry uploads by default\n leavePartsOnError: true,\n params: {\n // Bucket needs to have something to avoid client side errors\n // Also needs to have a `.` in it to prevent SDK from using the\n // new S3 bucket domain concept with includes the bucket in the\n // domain instead of the path. We need it in the path to use the\n // API as the domain.\n Bucket: 'storage.oneblink.io',\n Key: key,\n Body: body,\n ContentType: contentType,\n ServerSideEncryption: 'AES256',\n Expires: new Date(new Date().setFullYear(new Date().getFullYear() + 1)), // Max 1 year\n CacheControl: 'max-age=31536000', // Max 1 year(365 days),\n ACL: isPublic ? 'public-read' : 'bucket-owner-full-control',\n Tagging: tags?.toString(),\n },\n })\n\n managedUpload.on('httpUploadProgress', (progress) => {\n console.log('Progress', progress)\n if (onProgress && progress.total) {\n const percent = determineUploadProgressAsPercentage({\n ...progress,\n total: progress.total,\n })\n onProgress({ progress: percent, total: 100 })\n }\n })\n\n abortSignal?.addEventListener('abort', () => {\n managedUpload.abort()\n })\n\n await managedUpload.done()\n\n if (!requestHandler.response) {\n throw new Error(\n 'No response from server. Something went wrong in the OneBlink/uploads SDK.',\n )\n }\n return requestHandler.response\n}\n\nexport default uploadToS3\n\nexport const determineQueueSize = () => {\n let queueSize = 1 // default to 1 as the lowest common denominator\n // Return as though using highest speed for Node environments\n if (!window) return 10\n if (\n window.navigator &&\n 'connection' in window.navigator &&\n !!window.navigator.connection &&\n // @ts-expect-error effectiveType prop is still in draft\n window.navigator.connection.effectiveType\n ) {\n // @ts-expect-error effectiveType prop is still in draft\n switch (window.navigator.connection.effectiveType) {\n case 'slow-2g':\n case '2g':\n queueSize = 1\n break\n case '3g':\n queueSize = 2\n break\n case '4g':\n queueSize = 10\n break\n }\n }\n\n return queueSize\n}\n\nexport const determineUploadProgressAsPercentage = (\n progress: Required<Pick<Progress, 'total'>> & Omit<Progress, 'total'>,\n) => {\n const percent = ((progress.loaded || 0) / progress.total) * 100\n return Math.floor(percent)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"uploadToS3.js","sourceRoot":"","sources":["../src/uploadToS3.ts"],"names":[],"mappings":"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","sourcesContent":["import { PutObjectCommandInput, S3Client } from '@aws-sdk/client-s3'\nimport { Upload, Progress } from '@aws-sdk/lib-storage'\nimport { HttpHandlerOptions } from '@smithy/types'\nimport { HttpRequest } from '@smithy/protocol-http'\nimport { FetchHttpHandler } from '@smithy/fetch-http-handler'\nimport { StorageConstructorOptions, BaseResponse, UploadOptions } from './types'\nimport OneBlinkStorageError from './OneBlinkStorageError'\n\nconst RETRY_ATTEMPTS = 3\n\ntype RequestBodyHeader = Record<string, unknown>\n// Our own custom request handler to allow setting customer headers for\n// authentication. Also allow the response header which includes dynamic\n// data from the lambda at edge to be retrieved and held for later when\n// the upload has completed.\nclass OBRequestHandler<T> extends FetchHttpHandler {\n constructor({\n getIdToken,\n requestBodyHeader,\n }: {\n getIdToken: StorageConstructorOptions['getIdToken']\n requestBodyHeader?: RequestBodyHeader\n }) {\n super()\n this.getIdToken = getIdToken\n this.requestBodyHeader = requestBodyHeader\n }\n\n getIdToken: StorageConstructorOptions['getIdToken']\n requestBodyHeader?: RequestBodyHeader\n successResponse?: T & BaseResponse\n failResponse?: {\n statusCode: number\n message: string\n }\n\n async handle(request: HttpRequest, options?: HttpHandlerOptions) {\n const token = await this.getIdToken()\n if (token) {\n request.headers['x-oneblink-authorization'] = 'Bearer ' + token\n }\n if (this.requestBodyHeader) {\n request.headers['x-oneblink-request-body'] = JSON.stringify(\n this.requestBodyHeader,\n )\n }\n if (this.successResponse) {\n request.query['key'] = this.successResponse.s3.key\n }\n const result = await super.handle(request, options)\n if (\n result.response.headers['content-type'] === 'application/json' &&\n result.response.statusCode >= 400\n ) {\n const fetchResponse = new Response(result.response.body)\n this.failResponse = await fetchResponse.json()\n }\n const response = result.response.headers['x-oneblink-response']\n if (typeof response === 'string') {\n this.successResponse = JSON.parse(response)\n }\n return result\n }\n}\n\nconst endpointSuffix = '/storage'\n\n/** The properties to be passed to the uploadToS3 function */\ninterface UploadToS3Props extends UploadOptions, StorageConstructorOptions {\n /** The key of the file that is being uploaded. */\n key: string\n /**\n * The body of the request. This can be a string, a Buffer, a Blob, a\n * ReadableStream, or a Readable.\n */\n body: PutObjectCommandInput['Body']\n /** Optional header to be included in the request to the OneBlink API */\n requestBodyHeader?: RequestBodyHeader\n /** An optional set of tags that will be applied to the uploaded file */\n tags?: URLSearchParams\n /** A standard MIME type describing the format of the contents */\n contentType: PutObjectCommandInput['ContentType']\n /** Set to `true` to make the upload available to download publicly */\n isPublic?: boolean\n}\n\nasync function uploadToS3<T>({\n region,\n apiOrigin,\n key,\n body,\n requestBodyHeader,\n tags,\n getIdToken,\n onProgress,\n abortSignal,\n contentType,\n isPublic,\n}: UploadToS3Props) {\n const requestHandler = new OBRequestHandler<T>({\n getIdToken,\n requestBodyHeader,\n })\n\n const s3Client = new S3Client({\n // The suffix on the end is important as it will allow us to route\n // traffic to S3 via lambda at edge instead of going to our API\n endpoint: `${apiOrigin}${endpointSuffix}`,\n region: region,\n requestHandler,\n // Have to put something here otherwise the SDK throws errors.\n // Might be able to remove the validation from the middleware somehow?\n credentials: {\n accessKeyId: 'AWS_ACCESS_KEY_ID',\n secretAccessKey: 'AWS_SECRET_ACCESS_KEY',\n },\n maxAttempts: RETRY_ATTEMPTS,\n })\n\n if (isPublic) {\n if (!tags) {\n tags = new URLSearchParams()\n }\n tags?.append('public-read', 'yes')\n }\n\n const managedUpload = new Upload({\n client: s3Client,\n partSize: 5 * 1024 * 1024,\n queueSize: determineQueueSize(),\n //Related github issue: https://github.com/aws/aws-sdk-js-v3/issues/2311\n //This is a variable that is set to false by default, setting it to true\n //means that it will force the upload to fail when one part fails on\n //an upload. The S3 client has built in retry logic to retry uploads by default\n leavePartsOnError: true,\n params: {\n // Bucket needs to have something to avoid client side errors\n // Also needs to have a `.` in it to prevent SDK from using the\n // new S3 bucket domain concept with includes the bucket in the\n // domain instead of the path. We need it in the path to use the\n // API as the domain.\n Bucket: 'storage.oneblink.io',\n Key: key,\n Body: body,\n ContentType: contentType,\n ServerSideEncryption: 'AES256',\n Expires: new Date(new Date().setFullYear(new Date().getFullYear() + 1)), // Max 1 year\n CacheControl: 'max-age=31536000', // Max 1 year(365 days),\n ACL: 'bucket-owner-full-control',\n Tagging: tags?.toString(),\n },\n })\n\n managedUpload.on('httpUploadProgress', (progress) => {\n console.log('Progress', progress)\n if (onProgress && progress.total) {\n const percent = determineUploadProgressAsPercentage({\n ...progress,\n total: progress.total,\n })\n onProgress({ progress: percent, total: 100 })\n }\n })\n\n abortSignal?.addEventListener('abort', () => {\n managedUpload.abort()\n })\n\n try {\n await managedUpload.done()\n } catch (error) {\n if (requestHandler.failResponse) {\n throw new OneBlinkStorageError(requestHandler.failResponse.message, {\n httpStatusCode: requestHandler.failResponse.statusCode,\n originalError: error instanceof Error ? error : undefined,\n })\n }\n throw error\n }\n\n if (!requestHandler.successResponse) {\n throw new Error(\n 'No response from server. Something went wrong in \"@oneBlink/uploads\".',\n )\n }\n return requestHandler.successResponse\n}\n\nexport default uploadToS3\n\nexport const determineQueueSize = () => {\n let queueSize = 1 // default to 1 as the lowest common denominator\n // Return as though using highest speed for Node environments\n if (!window) return 10\n if (\n window.navigator &&\n 'connection' in window.navigator &&\n !!window.navigator.connection &&\n // @ts-expect-error effectiveType prop is still in draft\n window.navigator.connection.effectiveType\n ) {\n // @ts-expect-error effectiveType prop is still in draft\n switch (window.navigator.connection.effectiveType) {\n case 'slow-2g':\n case '2g':\n queueSize = 1\n break\n case '3g':\n queueSize = 2\n break\n case '4g':\n queueSize = 10\n break\n }\n }\n\n return queueSize\n}\n\nexport const determineUploadProgressAsPercentage = (\n progress: Required<Pick<Progress, 'total'>> & Omit<Progress, 'total'>,\n) => {\n const percent = ((progress.loaded || 0) / progress.total) * 100\n return Math.floor(percent)\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oneblink/storage",
|
|
3
3
|
"description": "SDK for managing storage files in the OneBlink ecosystem",
|
|
4
|
-
"version": "1.0.0-beta.
|
|
4
|
+
"version": "1.0.0-beta.5",
|
|
5
5
|
"author": "OneBlink <developers@oneblink.io> (https://oneblink.io)",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/oneblink/storage/issues"
|