@oneblink/storage 1.0.0-beta.4 → 1.0.0-beta.6

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.
@@ -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, UploadEmailAttachmentOptions } from './types';
2
2
  import { SubmissionTypes } from '@oneblink/types';
3
3
  /**
4
4
  * Used to create an instance of the OneBlinkUploader, exposing methods to
@@ -60,12 +60,12 @@ export default class OneBlinkUploader {
60
60
  /** A reCAPTCHA token */
61
61
  token: string;
62
62
  }[];
63
- }): Promise<{
63
+ }): Promise<import("./http-handlers/types").OneBlinkResponse<{
64
64
  submissionTimestamp: string;
65
65
  submissionId: string;
66
66
  pdfAccessToken?: string | undefined;
67
67
  preventPayment: boolean;
68
- } & import("./types").BaseResponse>;
68
+ }>>;
69
69
  /**
70
70
  * Upload an form submission attachment.
71
71
  *
@@ -101,11 +101,11 @@ export default class OneBlinkUploader {
101
101
  data: AttachmentUploadData;
102
102
  /** A username to allow a single user to download the attachment file */
103
103
  username?: string;
104
- }): Promise<{
104
+ }): Promise<import("./http-handlers/types").OneBlinkResponse<{
105
105
  url: string;
106
106
  attachmentDataId: string;
107
107
  uploadedAt: string;
108
- } & import("./types").BaseResponse>;
108
+ }>>;
109
109
  /**
110
110
  * Upload a draft submission.
111
111
  *
@@ -132,8 +132,122 @@ export default class OneBlinkUploader {
132
132
  uploadDraftSubmission({ submission, definition, device, userToken, previousFormSubmissionApprovalId, jobId, formsAppId, externalId, lastElementUpdated, onProgress, abortSignal, }: UploadFormSubmissionOptions & {
133
133
  /** The identifier for the last element that was used before saving draft */
134
134
  lastElementUpdated?: SubmissionTypes.NewS3SubmissionData['lastElementUpdated'];
135
- }): Promise<{
135
+ }): Promise<import("./http-handlers/types").OneBlinkResponse<{
136
136
  submissionTimestamp: string;
137
137
  draftDataId: string;
138
- } & import("./types").BaseResponse>;
138
+ }>>;
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<import("./http-handlers/types").OneBlinkResponse<{
167
+ url: string;
168
+ }>>;
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<import("./http-handlers/types").OneBlinkResponse<{
194
+ url: string;
195
+ }>>;
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("./http-handlers/types").OneBlinkResponse<{
225
+ preFillFormDataId: string;
226
+ }>>;
227
+ /**
228
+ * Upload an email attachment. Email attachments are always private.
229
+ *
230
+ * #### Example
231
+ *
232
+ * ```ts
233
+ * const abortController = new AbortController()
234
+ * const result = await uploader.uploadEmailAttachment({
235
+ * onProgress: (progress) => {
236
+ * // ...
237
+ * },
238
+ * data: new Blob(['a string of data'], {
239
+ * type: 'text/plain',
240
+ * }),
241
+ * fileName: 'file.txt',
242
+ * contentType: 'text/plain',
243
+ * abortSignal: abortController.signal,
244
+ * })
245
+ * ```
246
+ *
247
+ * @param data The email attachment data and options
248
+ * @returns The upload result
249
+ */
250
+ uploadEmailAttachment({ onProgress, abortSignal, data, contentType, fileName, }: UploadOptions & UploadEmailAttachmentOptions): Promise<{
251
+ s3: import("@oneblink/types/typescript/aws").S3Configuration;
252
+ }>;
139
253
  }
@@ -165,6 +165,152 @@ 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
+ }
277
+ /**
278
+ * Upload an email attachment. Email attachments are always private.
279
+ *
280
+ * #### Example
281
+ *
282
+ * ```ts
283
+ * const abortController = new AbortController()
284
+ * const result = await uploader.uploadEmailAttachment({
285
+ * onProgress: (progress) => {
286
+ * // ...
287
+ * },
288
+ * data: new Blob(['a string of data'], {
289
+ * type: 'text/plain',
290
+ * }),
291
+ * fileName: 'file.txt',
292
+ * contentType: 'text/plain',
293
+ * abortSignal: abortController.signal,
294
+ * })
295
+ * ```
296
+ *
297
+ * @param data The email attachment data and options
298
+ * @returns The upload result
299
+ */
300
+ async uploadEmailAttachment({ onProgress, abortSignal, data, contentType, fileName, }) {
301
+ return await (0, uploadToS3_1.default)({
302
+ ...this,
303
+ contentType,
304
+ body: data,
305
+ key: 'email-attachments',
306
+ abortSignal,
307
+ onProgress,
308
+ requestBodyHeader: {
309
+ fileName,
310
+ },
311
+ isPublic: false,
312
+ });
313
+ }
168
314
  }
169
315
  exports.default = OneBlinkUploader;
170
316
  //# 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 UploadEmailAttachmentOptions,\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 preFillFormDataId: string\n }>({\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 /**\n * Upload an email attachment. Email attachments are always private.\n *\n * #### Example\n *\n * ```ts\n * const abortController = new AbortController()\n * const result = await uploader.uploadEmailAttachment({\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 email attachment data and options\n * @returns The upload result\n */\n async uploadEmailAttachment({\n onProgress,\n abortSignal,\n data,\n contentType,\n fileName,\n }: UploadOptions & UploadEmailAttachmentOptions) {\n return await uploadToS3({\n ...this,\n contentType,\n body: data,\n key: 'email-attachments',\n abortSignal,\n onProgress,\n requestBodyHeader: {\n fileName,\n },\n isPublic: false,\n })\n }\n}\n"]}
@@ -0,0 +1,19 @@
1
+ import { FetchHttpHandler } from '@smithy/fetch-http-handler';
2
+ import { HttpRequest } from '@smithy/protocol-http';
3
+ import { HttpHandlerOptions } from '@smithy/types';
4
+ import { StorageConstructorOptions } from '../types';
5
+ import { RequestBodyHeader, IOneBlinkRequestHandler, OneBlinkResponse, FailResponse } from './types';
6
+ export declare class OneBlinkFetchHandler<T> extends FetchHttpHandler implements IOneBlinkRequestHandler<T> {
7
+ constructor({ getIdToken, requestBodyHeader, }: {
8
+ getIdToken: StorageConstructorOptions['getIdToken'];
9
+ requestBodyHeader?: RequestBodyHeader;
10
+ });
11
+ getIdToken: StorageConstructorOptions['getIdToken'];
12
+ requestBodyHeader?: RequestBodyHeader;
13
+ oneblinkResponse?: OneBlinkResponse<T>;
14
+ failResponse?: FailResponse;
15
+ handle(request: HttpRequest, options?: HttpHandlerOptions): Promise<{
16
+ response: import("@smithy/protocol-http").HttpResponse;
17
+ }>;
18
+ determineQueueSize(): 1 | 2 | 10;
19
+ }
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OneBlinkFetchHandler = void 0;
4
+ const fetch_http_handler_1 = require("@smithy/fetch-http-handler");
5
+ const handleRequest_1 = require("./handleRequest");
6
+ // Our own custom request handler to allow setting customer headers for
7
+ // authentication. Also allow the response header which includes dynamic
8
+ // data from the lambda at edge to be retrieved and held for later when
9
+ // the upload has completed.
10
+ class OneBlinkFetchHandler extends fetch_http_handler_1.FetchHttpHandler {
11
+ constructor({ getIdToken, requestBodyHeader, }) {
12
+ super();
13
+ this.getIdToken = getIdToken;
14
+ this.requestBodyHeader = requestBodyHeader;
15
+ }
16
+ async handle(request, options) {
17
+ await (0, handleRequest_1.prepareRequest)(this, request);
18
+ const result = await super.handle(request, options);
19
+ await (0, handleRequest_1.handleResponse)(this, request, result.response);
20
+ if (result.response.statusCode < 400) {
21
+ return result;
22
+ }
23
+ switch (result.response.headers['content-type']) {
24
+ case 'application/json': {
25
+ if (window.ReadableStream &&
26
+ result.response.body instanceof window.ReadableStream) {
27
+ const fetchResponse = new Response(result.response.body);
28
+ this.failResponse = {
29
+ statusCode: result.response.statusCode,
30
+ message: (await fetchResponse.json()).message,
31
+ };
32
+ }
33
+ if (typeof result.response.body === 'string') {
34
+ this.failResponse = {
35
+ statusCode: result.response.statusCode,
36
+ message: JSON.parse(result.response.body).message,
37
+ };
38
+ }
39
+ break;
40
+ }
41
+ case 'text/html': {
42
+ if (window.ReadableStream &&
43
+ result.response.body instanceof window.ReadableStream) {
44
+ const fetchResponse = new Response(result.response.body);
45
+ this.failResponse = {
46
+ statusCode: result.response.statusCode,
47
+ message: await fetchResponse.text(),
48
+ };
49
+ }
50
+ if (typeof result.response.body === 'string') {
51
+ console.log('response', result.response.body);
52
+ }
53
+ break;
54
+ }
55
+ }
56
+ return result;
57
+ }
58
+ determineQueueSize() {
59
+ const effectiveType = window.navigator &&
60
+ 'connection' in window.navigator &&
61
+ !!window.navigator.connection &&
62
+ typeof window.navigator.connection === 'object' &&
63
+ 'effectiveType' in window.navigator.connection
64
+ ? window.navigator.connection.effectiveType
65
+ : undefined;
66
+ switch (effectiveType) {
67
+ case '4g':
68
+ return 10;
69
+ case '3g':
70
+ return 2;
71
+ case 'slow-2g':
72
+ case '2g':
73
+ default: {
74
+ return 1;
75
+ }
76
+ }
77
+ }
78
+ }
79
+ exports.OneBlinkFetchHandler = OneBlinkFetchHandler;
80
+ //# sourceMappingURL=FetchHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FetchHandler.js","sourceRoot":"","sources":["../../src/http-handlers/FetchHandler.ts"],"names":[],"mappings":";;;AAAA,mEAA6D;AAU7D,mDAAgE;AAEhE,uEAAuE;AACvE,wEAAwE;AACxE,uEAAuE;AACvE,4BAA4B;AAC5B,MAAa,oBACX,SAAQ,qCAAgB;IAGxB,YAAY,EACV,UAAU,EACV,iBAAiB,GAIlB;QACC,KAAK,EAAE,CAAA;QACP,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAA;IAC5C,CAAC;IAOD,KAAK,CAAC,MAAM,CAAC,OAAoB,EAAE,OAA4B;QAC7D,MAAM,IAAA,8BAAc,EAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QAEnC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAEnD,MAAM,IAAA,8BAAc,EAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QAEpD,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC;YACrC,OAAO,MAAM,CAAA;QACf,CAAC;QAED,QAAQ,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;YAChD,KAAK,kBAAkB,CAAC,CAAC,CAAC;gBACxB,IACE,MAAM,CAAC,cAAc;oBACrB,MAAM,CAAC,QAAQ,CAAC,IAAI,YAAY,MAAM,CAAC,cAAc,EACrD,CAAC;oBACD,MAAM,aAAa,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;oBACxD,IAAI,CAAC,YAAY,GAAG;wBAClB,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU;wBACtC,OAAO,EAAE,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO;qBAC9C,CAAA;gBACH,CAAC;gBAED,IAAI,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC7C,IAAI,CAAC,YAAY,GAAG;wBAClB,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU;wBACtC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO;qBAClD,CAAA;gBACH,CAAC;gBACD,MAAK;YACP,CAAC;YACD,KAAK,WAAW,CAAC,CAAC,CAAC;gBACjB,IACE,MAAM,CAAC,cAAc;oBACrB,MAAM,CAAC,QAAQ,CAAC,IAAI,YAAY,MAAM,CAAC,cAAc,EACrD,CAAC;oBACD,MAAM,aAAa,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;oBACxD,IAAI,CAAC,YAAY,GAAG;wBAClB,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU;wBACtC,OAAO,EAAE,MAAM,aAAa,CAAC,IAAI,EAAE;qBACpC,CAAA;gBACH,CAAC;gBAED,IAAI,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC7C,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;gBAC/C,CAAC;gBACD,MAAK;YACP,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;IAED,kBAAkB;QAChB,MAAM,aAAa,GACjB,MAAM,CAAC,SAAS;YAChB,YAAY,IAAI,MAAM,CAAC,SAAS;YAChC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU;YAC7B,OAAO,MAAM,CAAC,SAAS,CAAC,UAAU,KAAK,QAAQ;YAC/C,eAAe,IAAI,MAAM,CAAC,SAAS,CAAC,UAAU;YAC5C,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,aAAa;YAC3C,CAAC,CAAC,SAAS,CAAA;QACf,QAAQ,aAAa,EAAE,CAAC;YACtB,KAAK,IAAI;gBACP,OAAO,EAAE,CAAA;YACX,KAAK,IAAI;gBACP,OAAO,CAAC,CAAA;YACV,KAAK,SAAS,CAAC;YACf,KAAK,IAAI,CAAC;YACV,OAAO,CAAC,CAAC,CAAC;gBACR,OAAO,CAAC,CAAA;YACV,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAhGD,oDAgGC","sourcesContent":["import { FetchHttpHandler } from '@smithy/fetch-http-handler'\nimport { HttpRequest } from '@smithy/protocol-http'\nimport { HttpHandlerOptions } from '@smithy/types'\nimport { StorageConstructorOptions } from '../types'\nimport {\n RequestBodyHeader,\n IOneBlinkRequestHandler,\n OneBlinkResponse,\n FailResponse,\n} from './types'\nimport { handleResponse, prepareRequest } from './handleRequest'\n\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.\nexport class OneBlinkFetchHandler<T>\n extends FetchHttpHandler\n implements IOneBlinkRequestHandler<T>\n{\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 oneblinkResponse?: OneBlinkResponse<T>\n failResponse?: FailResponse\n\n async handle(request: HttpRequest, options?: HttpHandlerOptions) {\n await prepareRequest(this, request)\n\n const result = await super.handle(request, options)\n\n await handleResponse(this, request, result.response)\n\n if (result.response.statusCode < 400) {\n return result\n }\n\n switch (result.response.headers['content-type']) {\n case 'application/json': {\n if (\n window.ReadableStream &&\n result.response.body instanceof window.ReadableStream\n ) {\n const fetchResponse = new Response(result.response.body)\n this.failResponse = {\n statusCode: result.response.statusCode,\n message: (await fetchResponse.json()).message,\n }\n }\n\n if (typeof result.response.body === 'string') {\n this.failResponse = {\n statusCode: result.response.statusCode,\n message: JSON.parse(result.response.body).message,\n }\n }\n break\n }\n case 'text/html': {\n if (\n window.ReadableStream &&\n result.response.body instanceof window.ReadableStream\n ) {\n const fetchResponse = new Response(result.response.body)\n this.failResponse = {\n statusCode: result.response.statusCode,\n message: await fetchResponse.text(),\n }\n }\n\n if (typeof result.response.body === 'string') {\n console.log('response', result.response.body)\n }\n break\n }\n }\n\n return result\n }\n\n determineQueueSize() {\n const effectiveType =\n window.navigator &&\n 'connection' in window.navigator &&\n !!window.navigator.connection &&\n typeof window.navigator.connection === 'object' &&\n 'effectiveType' in window.navigator.connection\n ? window.navigator.connection.effectiveType\n : undefined\n switch (effectiveType) {\n case '4g':\n return 10\n case '3g':\n return 2\n case 'slow-2g':\n case '2g':\n default: {\n return 1\n }\n }\n }\n}\n"]}
@@ -0,0 +1,19 @@
1
+ import { NodeHttpHandler } from '@smithy/node-http-handler';
2
+ import { HttpRequest } from '@smithy/protocol-http';
3
+ import { HttpHandlerOptions } from '@smithy/types';
4
+ import { StorageConstructorOptions } from '../types';
5
+ import { RequestBodyHeader, IOneBlinkRequestHandler, OneBlinkResponse, FailResponse } from './types';
6
+ export declare class OneBlinkNodeJsHandler<T> extends NodeHttpHandler implements IOneBlinkRequestHandler<T> {
7
+ constructor({ getIdToken, requestBodyHeader, }: {
8
+ getIdToken: StorageConstructorOptions['getIdToken'];
9
+ requestBodyHeader?: RequestBodyHeader;
10
+ });
11
+ getIdToken: StorageConstructorOptions['getIdToken'];
12
+ requestBodyHeader?: RequestBodyHeader;
13
+ oneblinkResponse?: OneBlinkResponse<T>;
14
+ failResponse?: FailResponse;
15
+ handle(request: HttpRequest, options?: HttpHandlerOptions): Promise<{
16
+ response: import("@smithy/protocol-http").HttpResponse;
17
+ }>;
18
+ determineQueueSize(): number;
19
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OneBlinkNodeJsHandler = void 0;
4
+ const node_http_handler_1 = require("@smithy/node-http-handler");
5
+ const handleRequest_1 = require("./handleRequest");
6
+ // Our own custom request handler to allow setting customer headers for
7
+ // authentication. Also allow the response header which includes dynamic
8
+ // data from the lambda at edge to be retrieved and held for later when
9
+ // the upload has completed.
10
+ class OneBlinkNodeJsHandler extends node_http_handler_1.NodeHttpHandler {
11
+ constructor({ getIdToken, requestBodyHeader, }) {
12
+ super();
13
+ this.getIdToken = getIdToken;
14
+ this.requestBodyHeader = requestBodyHeader;
15
+ }
16
+ async handle(request, options) {
17
+ await (0, handleRequest_1.prepareRequest)(this, request);
18
+ const result = await super.handle(request, options);
19
+ await (0, handleRequest_1.handleResponse)(this, request, result.response);
20
+ if (result.response.statusCode < 400) {
21
+ return result;
22
+ }
23
+ switch (result.response.headers['content-type']) {
24
+ case 'application/json; charset=utf-8':
25
+ case 'application/json': {
26
+ const { Readable } = await import('stream');
27
+ if (result.response.body instanceof Readable) {
28
+ const { json } = await import('stream/consumers');
29
+ this.failResponse = {
30
+ statusCode: result.response.statusCode,
31
+ message: (await json(result.response.body))
32
+ .message,
33
+ };
34
+ }
35
+ if (typeof result.response.body === 'string') {
36
+ this.failResponse = {
37
+ statusCode: result.response.statusCode,
38
+ message: JSON.parse(result.response.body).message,
39
+ };
40
+ }
41
+ break;
42
+ }
43
+ case 'text/html': {
44
+ const { Readable } = await import('stream');
45
+ if (result.response.body instanceof Readable) {
46
+ const { text } = await import('stream/consumers');
47
+ this.failResponse = {
48
+ statusCode: result.response.statusCode,
49
+ message: await text(result.response.body),
50
+ };
51
+ }
52
+ if (typeof result.response.body === 'string') {
53
+ console.log('response', result.response.body);
54
+ }
55
+ break;
56
+ }
57
+ }
58
+ return result;
59
+ }
60
+ determineQueueSize() {
61
+ return 10;
62
+ }
63
+ }
64
+ exports.OneBlinkNodeJsHandler = OneBlinkNodeJsHandler;
65
+ //# sourceMappingURL=NodeJsHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeJsHandler.js","sourceRoot":"","sources":["../../src/http-handlers/NodeJsHandler.ts"],"names":[],"mappings":";;;AAAA,iEAA2D;AAU3D,mDAAgE;AAEhE,uEAAuE;AACvE,wEAAwE;AACxE,uEAAuE;AACvE,4BAA4B;AAC5B,MAAa,qBACX,SAAQ,mCAAe;IAGvB,YAAY,EACV,UAAU,EACV,iBAAiB,GAIlB;QACC,KAAK,EAAE,CAAA;QACP,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAA;IAC5C,CAAC;IAOD,KAAK,CAAC,MAAM,CAAC,OAAoB,EAAE,OAA4B;QAC7D,MAAM,IAAA,8BAAc,EAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QAEnC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAEnD,MAAM,IAAA,8BAAc,EAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QAEpD,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC;YACrC,OAAO,MAAM,CAAA;QACf,CAAC;QAED,QAAQ,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;YAChD,KAAK,iCAAiC,CAAC;YACvC,KAAK,kBAAkB,CAAC,CAAC,CAAC;gBACxB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;gBAC3C,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,YAAY,QAAQ,EAAE,CAAC;oBAC7C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;oBACjD,IAAI,CAAC,YAAY,GAAG;wBAClB,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU;wBACtC,OAAO,EAAG,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAkB;6BAC1D,OAAO;qBACX,CAAA;gBACH,CAAC;gBAED,IAAI,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC7C,IAAI,CAAC,YAAY,GAAG;wBAClB,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU;wBACtC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO;qBAClD,CAAA;gBACH,CAAC;gBACD,MAAK;YACP,CAAC;YACD,KAAK,WAAW,CAAC,CAAC,CAAC;gBACjB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;gBAC3C,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,YAAY,QAAQ,EAAE,CAAC;oBAC7C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;oBACjD,IAAI,CAAC,YAAY,GAAG;wBAClB,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU;wBACtC,OAAO,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;qBAC1C,CAAA;gBACH,CAAC;gBAED,IAAI,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC7C,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;gBAC/C,CAAC;gBACD,MAAK;YACP,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;IAED,kBAAkB;QAChB,OAAO,EAAE,CAAA;IACX,CAAC;CACF;AA5ED,sDA4EC","sourcesContent":["import { NodeHttpHandler } from '@smithy/node-http-handler'\nimport { HttpRequest } from '@smithy/protocol-http'\nimport { HttpHandlerOptions } from '@smithy/types'\nimport { StorageConstructorOptions } from '../types'\nimport {\n RequestBodyHeader,\n IOneBlinkRequestHandler,\n OneBlinkResponse,\n FailResponse,\n} from './types'\nimport { handleResponse, prepareRequest } from './handleRequest'\n\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.\nexport class OneBlinkNodeJsHandler<T>\n extends NodeHttpHandler\n implements IOneBlinkRequestHandler<T>\n{\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 oneblinkResponse?: OneBlinkResponse<T>\n failResponse?: FailResponse\n\n async handle(request: HttpRequest, options?: HttpHandlerOptions) {\n await prepareRequest(this, request)\n\n const result = await super.handle(request, options)\n\n await handleResponse(this, request, result.response)\n\n if (result.response.statusCode < 400) {\n return result\n }\n\n switch (result.response.headers['content-type']) {\n case 'application/json; charset=utf-8':\n case 'application/json': {\n const { Readable } = await import('stream')\n if (result.response.body instanceof Readable) {\n const { json } = await import('stream/consumers')\n this.failResponse = {\n statusCode: result.response.statusCode,\n message: ((await json(result.response.body)) as FailResponse)\n .message,\n }\n }\n\n if (typeof result.response.body === 'string') {\n this.failResponse = {\n statusCode: result.response.statusCode,\n message: JSON.parse(result.response.body).message,\n }\n }\n break\n }\n case 'text/html': {\n const { Readable } = await import('stream')\n if (result.response.body instanceof Readable) {\n const { text } = await import('stream/consumers')\n this.failResponse = {\n statusCode: result.response.statusCode,\n message: await text(result.response.body),\n }\n }\n\n if (typeof result.response.body === 'string') {\n console.log('response', result.response.body)\n }\n break\n }\n }\n\n return result\n }\n\n determineQueueSize() {\n return 10\n }\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import { IOneBlinkRequestHandler } from './types';
2
+ import { HttpRequest, HttpResponse } from '@smithy/protocol-http';
3
+ export declare function prepareRequest<T>(oneBlinkRequestHandler: IOneBlinkRequestHandler<T>, request: HttpRequest): Promise<void>;
4
+ export declare function handleResponse<T>(oneBlinkRequestHandler: IOneBlinkRequestHandler<T>, request: HttpRequest, response: HttpResponse): Promise<void>;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleResponse = exports.prepareRequest = void 0;
4
+ async function prepareRequest(oneBlinkRequestHandler, request) {
5
+ delete request.headers['authorization'];
6
+ const token = await oneBlinkRequestHandler.getIdToken();
7
+ if (token) {
8
+ request.headers['authorization'] = 'Bearer ' + token;
9
+ }
10
+ if (oneBlinkRequestHandler.requestBodyHeader) {
11
+ request.headers['x-oneblink-request-body'] = JSON.stringify(oneBlinkRequestHandler.requestBodyHeader);
12
+ }
13
+ if (oneBlinkRequestHandler.oneblinkResponse) {
14
+ request.query['key'] = oneBlinkRequestHandler.oneblinkResponse.s3.key;
15
+ }
16
+ console.log('S3 upload request path', request.path);
17
+ }
18
+ exports.prepareRequest = prepareRequest;
19
+ async function handleResponse(oneBlinkRequestHandler, request, response) {
20
+ console.log('S3 upload result for request path', request.path);
21
+ const oneblinkResponse = response.headers['x-oneblink-response'];
22
+ if (typeof oneblinkResponse === 'string') {
23
+ oneBlinkRequestHandler.oneblinkResponse = JSON.parse(oneblinkResponse);
24
+ }
25
+ }
26
+ exports.handleResponse = handleResponse;
27
+ //# sourceMappingURL=handleRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handleRequest.js","sourceRoot":"","sources":["../../src/http-handlers/handleRequest.ts"],"names":[],"mappings":";;;AAGO,KAAK,UAAU,cAAc,CAClC,sBAAkD,EAClD,OAAoB;IAEpB,OAAO,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;IAEvC,MAAM,KAAK,GAAG,MAAM,sBAAsB,CAAC,UAAU,EAAE,CAAA;IACvD,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,SAAS,GAAG,KAAK,CAAA;IACtD,CAAC;IAED,IAAI,sBAAsB,CAAC,iBAAiB,EAAE,CAAC;QAC7C,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,GAAG,IAAI,CAAC,SAAS,CACzD,sBAAsB,CAAC,iBAAiB,CACzC,CAAA;IACH,CAAC;IAED,IAAI,sBAAsB,CAAC,gBAAgB,EAAE,CAAC;QAC5C,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,sBAAsB,CAAC,gBAAgB,CAAC,EAAE,CAAC,GAAG,CAAA;IACvE,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;AACrD,CAAC;AAtBD,wCAsBC;AAEM,KAAK,UAAU,cAAc,CAClC,sBAAkD,EAClD,OAAoB,EACpB,QAAsB;IAEtB,OAAO,CAAC,GAAG,CAAC,mCAAmC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAE9D,MAAM,gBAAgB,GAAG,QAAQ,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAChE,IAAI,OAAO,gBAAgB,KAAK,QAAQ,EAAE,CAAC;QACzC,sBAAsB,CAAC,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;IACxE,CAAC;AACH,CAAC;AAXD,wCAWC","sourcesContent":["import { IOneBlinkRequestHandler } from './types'\nimport { HttpRequest, HttpResponse } from '@smithy/protocol-http'\n\nexport async function prepareRequest<T>(\n oneBlinkRequestHandler: IOneBlinkRequestHandler<T>,\n request: HttpRequest,\n) {\n delete request.headers['authorization']\n\n const token = await oneBlinkRequestHandler.getIdToken()\n if (token) {\n request.headers['authorization'] = 'Bearer ' + token\n }\n\n if (oneBlinkRequestHandler.requestBodyHeader) {\n request.headers['x-oneblink-request-body'] = JSON.stringify(\n oneBlinkRequestHandler.requestBodyHeader,\n )\n }\n\n if (oneBlinkRequestHandler.oneblinkResponse) {\n request.query['key'] = oneBlinkRequestHandler.oneblinkResponse.s3.key\n }\n\n console.log('S3 upload request path', request.path)\n}\n\nexport async function handleResponse<T>(\n oneBlinkRequestHandler: IOneBlinkRequestHandler<T>,\n request: HttpRequest,\n response: HttpResponse,\n) {\n console.log('S3 upload result for request path', request.path)\n\n const oneblinkResponse = response.headers['x-oneblink-response']\n if (typeof oneblinkResponse === 'string') {\n oneBlinkRequestHandler.oneblinkResponse = JSON.parse(oneblinkResponse)\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { OneBlinkNodeJsHandler } from './NodeJsHandler';
2
+ import { OneBlinkFetchHandler } from './FetchHandler';
3
+ export declare function getRequestHandler(): typeof OneBlinkNodeJsHandler | typeof OneBlinkFetchHandler;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRequestHandler = void 0;
4
+ const browser_or_node_1 = require("browser-or-node");
5
+ const NodeJsHandler_1 = require("./NodeJsHandler");
6
+ const FetchHandler_1 = require("./FetchHandler");
7
+ function getRequestHandler() {
8
+ if (browser_or_node_1.isBrowser) {
9
+ return FetchHandler_1.OneBlinkFetchHandler;
10
+ }
11
+ if (browser_or_node_1.isNode) {
12
+ return NodeJsHandler_1.OneBlinkNodeJsHandler;
13
+ }
14
+ throw new Error('Could not find request handle matching current environment');
15
+ }
16
+ exports.getRequestHandler = getRequestHandler;
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http-handlers/index.ts"],"names":[],"mappings":";;;AAAA,qDAAmD;AACnD,mDAAuD;AACvD,iDAAqD;AAErD,SAAgB,iBAAiB;IAC/B,IAAI,2BAAS,EAAE,CAAC;QACd,OAAO,mCAAoB,CAAA;IAC7B,CAAC;IACD,IAAI,wBAAM,EAAE,CAAC;QACX,OAAO,qCAAqB,CAAA;IAC9B,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAA;AAC/E,CAAC;AATD,8CASC","sourcesContent":["import { isBrowser, isNode } from 'browser-or-node'\nimport { OneBlinkNodeJsHandler } from './NodeJsHandler'\nimport { OneBlinkFetchHandler } from './FetchHandler'\n\nexport function getRequestHandler() {\n if (isBrowser) {\n return OneBlinkFetchHandler\n }\n if (isNode) {\n return OneBlinkNodeJsHandler\n }\n\n throw new Error('Could not find request handle matching current environment')\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import { StorageConstructorOptions } from '../types';
2
+ import { AWSTypes } from '@oneblink/types';
3
+ export type RequestBodyHeader = Record<string, unknown>;
4
+ export type OneBlinkResponse<T> = T & {
5
+ s3: AWSTypes.S3Configuration;
6
+ };
7
+ export type FailResponse = {
8
+ statusCode: number;
9
+ message: string;
10
+ };
11
+ export interface IOneBlinkRequestHandler<T> {
12
+ getIdToken: StorageConstructorOptions['getIdToken'];
13
+ requestBodyHeader?: RequestBodyHeader;
14
+ oneblinkResponse?: OneBlinkResponse<T>;
15
+ failResponse?: {
16
+ statusCode: number;
17
+ message: string;
18
+ };
19
+ determineQueueSize: () => number;
20
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/http-handlers/types.ts"],"names":[],"mappings":"","sourcesContent":["import { StorageConstructorOptions } from '../types'\nimport { AWSTypes } from '@oneblink/types'\n\nexport type RequestBodyHeader = Record<string, unknown>\n\nexport type OneBlinkResponse<T> = T & {\n s3: AWSTypes.S3Configuration\n}\nexport type FailResponse = {\n statusCode: number\n message: string\n}\n\nexport interface IOneBlinkRequestHandler<T> {\n getIdToken: StorageConstructorOptions['getIdToken']\n requestBodyHeader?: RequestBodyHeader\n oneblinkResponse?: OneBlinkResponse<T>\n failResponse?: {\n statusCode: number\n message: string\n }\n determineQueueSize: () => number\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
+ export { default as OneBlinkStorageError } from './OneBlinkStorageError';
1
2
  export { default as OneBlinkUploader } from './OneBlinkUploader';
2
3
  export * from './types';
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
@@ -1,5 +1,5 @@
1
1
  import { PutObjectCommandInput } from '@aws-sdk/client-s3';
2
- import { AWSTypes, SubmissionTypes } from '@oneblink/types';
2
+ import { SubmissionTypes } from '@oneblink/types';
3
3
  export type ProgressListenerEvent = {
4
4
  progress: number;
5
5
  total: number;
@@ -18,9 +18,6 @@ export type StorageConstructorOptions = {
18
18
  */
19
19
  getIdToken: () => Promise<string | undefined>;
20
20
  };
21
- export type BaseResponse = {
22
- s3: AWSTypes.S3Configuration;
23
- };
24
21
  export type UploadOptions = {
25
22
  /** An optional progress listener for tracking the progress of the upload */
26
23
  onProgress?: ProgressListener;
@@ -49,3 +46,12 @@ export type UploadFormSubmissionOptions = UploadOptions & {
49
46
  /** The identifier of the job that will be marked as submitted */
50
47
  jobId?: string;
51
48
  };
49
+ export type UploadAssetOptions = UploadOptions & {
50
+ /** The file data to upload */
51
+ data: AttachmentUploadData;
52
+ /** A standard MIME type describing the format of the contents */
53
+ contentType: string;
54
+ /** The name of the file being uploaded */
55
+ fileName: string;
56
+ };
57
+ export type UploadEmailAttachmentOptions = UploadAssetOptions;
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 { 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 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\nexport type UploadEmailAttachmentOptions = UploadAssetOptions\n"]}
@@ -1,7 +1,7 @@
1
1
  import { PutObjectCommandInput } from '@aws-sdk/client-s3';
2
2
  import { Progress } from '@aws-sdk/lib-storage';
3
- import { StorageConstructorOptions, BaseResponse, UploadOptions } from './types';
4
- type RequestBodyHeader = Record<string, unknown>;
3
+ import { StorageConstructorOptions, UploadOptions } from './types';
4
+ import { RequestBodyHeader } from './http-handlers/types';
5
5
  /** The properties to be passed to the uploadToS3 function */
6
6
  interface UploadToS3Props extends UploadOptions, StorageConstructorOptions {
7
7
  /** The key of the file that is being uploaded. */
@@ -20,7 +20,6 @@ interface UploadToS3Props extends UploadOptions, StorageConstructorOptions {
20
20
  /** Set to `true` to make the upload available to download publicly */
21
21
  isPublic?: boolean;
22
22
  }
23
- declare function uploadToS3<T>({ region, apiOrigin, key, body, requestBodyHeader, tags, getIdToken, onProgress, abortSignal, contentType, isPublic, }: UploadToS3Props): Promise<T & BaseResponse>;
23
+ declare function uploadToS3<T>({ region, apiOrigin, key, body, requestBodyHeader, tags, getIdToken, onProgress, abortSignal, contentType, isPublic, }: UploadToS3Props): Promise<import("./http-handlers/types").OneBlinkResponse<T>>;
24
24
  export default uploadToS3;
25
- export declare const determineQueueSize: () => number;
26
25
  export declare const determineUploadProgressAsPercentage: (progress: Required<Pick<Progress, 'total'>> & Omit<Progress, 'total'>) => number;
@@ -1,43 +1,18 @@
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
- exports.determineUploadProgressAsPercentage = exports.determineQueueSize = void 0;
6
+ exports.determineUploadProgressAsPercentage = 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
- const fetch_http_handler_1 = require("@smithy/fetch-http-handler");
9
+ const OneBlinkStorageError_1 = __importDefault(require("./OneBlinkStorageError"));
10
+ const http_handlers_1 = require("./http-handlers");
7
11
  const RETRY_ATTEMPTS = 3;
8
- // Our own custom request handler to allow setting customer headers for
9
- // authentication. Also allow the response header which includes dynamic
10
- // data from the lambda at edge to be retrieved and held for later when
11
- // the upload has completed.
12
- class OBRequestHandler extends fetch_http_handler_1.FetchHttpHandler {
13
- constructor({ getIdToken, requestBodyHeader, }) {
14
- super();
15
- this.getIdToken = getIdToken;
16
- this.requestBodyHeader = requestBodyHeader;
17
- }
18
- async handle(request, options) {
19
- const token = await this.getIdToken();
20
- if (token) {
21
- request.headers['x-oneblink-authorization'] = 'Bearer ' + token;
22
- }
23
- if (this.requestBodyHeader) {
24
- request.headers['x-oneblink-request-body'] = JSON.stringify(this.requestBodyHeader);
25
- }
26
- if (this.response) {
27
- request.query['key'] = this.response.s3.key;
28
- }
29
- const result = await super.handle(request, options);
30
- console.log('result', result);
31
- const response = result.response.headers['x-oneblink-response'];
32
- if (response) {
33
- this.response = JSON.parse(response);
34
- }
35
- return result;
36
- }
37
- }
38
12
  const endpointSuffix = '/storage';
39
13
  async function uploadToS3({ region, apiOrigin, key, body, requestBodyHeader, tags, getIdToken, onProgress, abortSignal, contentType, isPublic, }) {
40
- const requestHandler = new OBRequestHandler({
14
+ const RequestHandler = (0, http_handlers_1.getRequestHandler)();
15
+ const requestHandler = new RequestHandler({
41
16
  getIdToken,
42
17
  requestBodyHeader,
43
18
  });
@@ -55,10 +30,16 @@ async function uploadToS3({ region, apiOrigin, key, body, requestBodyHeader, tag
55
30
  },
56
31
  maxAttempts: RETRY_ATTEMPTS,
57
32
  });
33
+ if (isPublic) {
34
+ if (!tags) {
35
+ tags = new URLSearchParams();
36
+ }
37
+ tags === null || tags === void 0 ? void 0 : tags.append('public-read', 'yes');
38
+ }
58
39
  const managedUpload = new lib_storage_1.Upload({
59
40
  client: s3Client,
60
41
  partSize: 5 * 1024 * 1024,
61
- queueSize: (0, exports.determineQueueSize)(),
42
+ queueSize: requestHandler.determineQueueSize(),
62
43
  //Related github issue: https://github.com/aws/aws-sdk-js-v3/issues/2311
63
44
  //This is a variable that is set to false by default, setting it to true
64
45
  //means that it will force the upload to fail when one part fails on
@@ -70,19 +51,19 @@ async function uploadToS3({ region, apiOrigin, key, body, requestBodyHeader, tag
70
51
  // new S3 bucket domain concept with includes the bucket in the
71
52
  // domain instead of the path. We need it in the path to use the
72
53
  // API as the domain.
73
- Bucket: 'storage.oneblink.io',
54
+ Bucket: apiOrigin.split('.').slice(-2).join('.'),
74
55
  Key: key,
75
56
  Body: body,
76
57
  ContentType: contentType,
77
58
  ServerSideEncryption: 'AES256',
78
59
  Expires: new Date(new Date().setFullYear(new Date().getFullYear() + 1)), // Max 1 year
79
60
  CacheControl: 'max-age=31536000', // Max 1 year(365 days),
80
- ACL: isPublic ? 'public-read' : 'bucket-owner-full-control',
61
+ ACL: 'bucket-owner-full-control',
81
62
  Tagging: tags === null || tags === void 0 ? void 0 : tags.toString(),
82
63
  },
83
64
  });
84
65
  managedUpload.on('httpUploadProgress', (progress) => {
85
- console.log('Progress', progress);
66
+ console.log('S3 upload progress for key', key, progress);
86
67
  if (onProgress && progress.total) {
87
68
  const percent = (0, exports.determineUploadProgressAsPercentage)({
88
69
  ...progress,
@@ -94,40 +75,24 @@ async function uploadToS3({ region, apiOrigin, key, body, requestBodyHeader, tag
94
75
  abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.addEventListener('abort', () => {
95
76
  managedUpload.abort();
96
77
  });
97
- await managedUpload.done();
98
- if (!requestHandler.response) {
99
- throw new Error('No response from server. Something went wrong in the OneBlink/uploads SDK.');
78
+ try {
79
+ await managedUpload.done();
100
80
  }
101
- return requestHandler.response;
102
- }
103
- exports.default = uploadToS3;
104
- const determineQueueSize = () => {
105
- let queueSize = 1; // default to 1 as the lowest common denominator
106
- // Return as though using highest speed for Node environments
107
- if (!window)
108
- return 10;
109
- if (window.navigator &&
110
- 'connection' in window.navigator &&
111
- !!window.navigator.connection &&
112
- // @ts-expect-error effectiveType prop is still in draft
113
- window.navigator.connection.effectiveType) {
114
- // @ts-expect-error effectiveType prop is still in draft
115
- switch (window.navigator.connection.effectiveType) {
116
- case 'slow-2g':
117
- case '2g':
118
- queueSize = 1;
119
- break;
120
- case '3g':
121
- queueSize = 2;
122
- break;
123
- case '4g':
124
- queueSize = 10;
125
- break;
81
+ catch (error) {
82
+ if (requestHandler.failResponse) {
83
+ throw new OneBlinkStorageError_1.default(requestHandler.failResponse.message, {
84
+ httpStatusCode: requestHandler.failResponse.statusCode,
85
+ originalError: error instanceof Error ? error : undefined,
86
+ });
126
87
  }
88
+ throw error;
127
89
  }
128
- return queueSize;
129
- };
130
- exports.determineQueueSize = determineQueueSize;
90
+ if (!requestHandler.oneblinkResponse) {
91
+ throw new Error('No response from server. Something went wrong in "@oneblink/uploads".');
92
+ }
93
+ return requestHandler.oneblinkResponse;
94
+ }
95
+ exports.default = uploadToS3;
131
96
  const determineUploadProgressAsPercentage = (progress) => {
132
97
  const percent = ((progress.loaded || 0) / progress.total) * 100;
133
98
  return Math.floor(percent);
@@ -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 { StorageConstructorOptions, UploadOptions } from './types'\nimport OneBlinkStorageError from './OneBlinkStorageError'\nimport { getRequestHandler } from './http-handlers'\nimport { RequestBodyHeader } from './http-handlers/types'\n\nconst RETRY_ATTEMPTS = 3\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 = getRequestHandler()\n const requestHandler = new RequestHandler<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: requestHandler.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: apiOrigin.split('.').slice(-2).join('.'),\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('S3 upload progress for key', key, 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.oneblinkResponse) {\n throw new Error(\n 'No response from server. Something went wrong in \"@oneblink/uploads\".',\n )\n }\n return requestHandler.oneblinkResponse\n}\n\nexport default uploadToS3\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,14 +1,15 @@
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",
4
+ "version": "1.0.0-beta.6",
5
5
  "author": "OneBlink <developers@oneblink.io> (https://oneblink.io)",
6
6
  "bugs": {
7
7
  "url": "https://github.com/oneblink/storage/issues"
8
8
  },
9
9
  "dependencies": {
10
10
  "@aws-sdk/client-s3": "^3.554.0",
11
- "@aws-sdk/lib-storage": "^3.554.0"
11
+ "@aws-sdk/lib-storage": "^3.554.0",
12
+ "browser-or-node": "^3.0.0"
12
13
  },
13
14
  "devDependencies": {
14
15
  "@microsoft/eslint-plugin-sdl": "^0.2.2",