@lighthouse/common 6.10.0-canary.0 → 6.10.0-canary.2

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/errors/FetchImageError.js +19 -0
  3. package/dist/helpers/build-fetch-url/index.js +26 -1
  4. package/dist/helpers/fetch-image/index.js +37 -8
  5. package/dist/helpers/fetch-image-for-pdf-generator-service/index.js +19 -13
  6. package/dist/helpers/fetch-image-for-web/index.js +36 -5
  7. package/dist/helpers/validate-url/index.js +15 -0
  8. package/dist/pdf/helpers/default-header/index.js +11 -1
  9. package/dist/pdf/helpers/fields/index.js +66 -9
  10. package/dist/pdf/helpers/generate-definition/index.js +10 -2
  11. package/dist/scheduling/helpers/generateRepeatingSchedule.js +1 -37
  12. package/dist/scheduling/helpers/generateScheduleEnd.js +1 -13
  13. package/dist/scheduling/strategies/getNext.js +0 -25
  14. package/dist/scheduling/strategies/getNextWeekday.js +0 -31
  15. package/lib/errors/FetchImageError.js +27 -0
  16. package/lib/errors/FetchImageError.js.map +1 -0
  17. package/lib/helpers/build-fetch-url/index.js +26 -1
  18. package/lib/helpers/build-fetch-url/index.js.map +1 -1
  19. package/lib/helpers/fetch-image/index.js +39 -7
  20. package/lib/helpers/fetch-image/index.js.map +1 -1
  21. package/lib/helpers/fetch-image-for-pdf-generator-service/index.js +50 -32
  22. package/lib/helpers/fetch-image-for-pdf-generator-service/index.js.map +1 -1
  23. package/lib/helpers/fetch-image-for-web/index.js +56 -22
  24. package/lib/helpers/fetch-image-for-web/index.js.map +1 -1
  25. package/lib/helpers/validate-url/index.js +10 -0
  26. package/lib/helpers/validate-url/index.js.map +1 -0
  27. package/lib/pdf/helpers/default-header/index.js +11 -1
  28. package/lib/pdf/helpers/default-header/index.js.map +1 -1
  29. package/lib/pdf/helpers/fields/index.js +65 -9
  30. package/lib/pdf/helpers/fields/index.js.map +1 -1
  31. package/lib/pdf/helpers/generate-definition/index.js +10 -2
  32. package/lib/pdf/helpers/generate-definition/index.js.map +1 -1
  33. package/lib/scheduling/helpers/generateRepeatingSchedule.js +21 -59
  34. package/lib/scheduling/helpers/generateRepeatingSchedule.js.map +1 -1
  35. package/lib/scheduling/helpers/generateScheduleEnd.js +1 -13
  36. package/lib/scheduling/helpers/generateScheduleEnd.js.map +1 -1
  37. package/lib/scheduling/strategies/getNext.js +4 -31
  38. package/lib/scheduling/strategies/getNext.js.map +1 -1
  39. package/lib/scheduling/strategies/getNextWeekday.js +1 -33
  40. package/lib/scheduling/strategies/getNextWeekday.js.map +1 -1
  41. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ # 6.9.3 (Wed Feb 26 2026)
2
+
3
+ #### 🐛 Bug Fix
4
+
5
+ - 🐛 Fix - Cross-region S3/Lambda access for image transformer cache ([@AndrewFinlay](https://github.com/AndrewFinlay))
6
+ - Hardcode IMAGE_CACHE_REGION to us-east-1 for Lambda and S3 clients
7
+ - Fixes NoSuchBucket errors when generating PDFs with images in non-us-east-1 regions
8
+ - Image transformer Lambda and cache bucket only exist in us-east-1
9
+
10
+ #### Authors: 1
11
+
12
+ - Andrew Finlay ([@AndrewFinlay](https://github.com/AndrewFinlay))
13
+
14
+ ---
15
+
1
16
  # 4.27.5 (Fri May 12 2023)
2
17
 
3
18
  #### 🐛 Bug Fix
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.FetchImageError = void 0;
7
+ /**
8
+ * Custom error class for image fetching operations
9
+ * Includes context information for better debugging
10
+ */
11
+ class FetchImageError extends Error {
12
+ constructor(message, context = {}) {
13
+ super(message);
14
+ this.name = 'FetchImageError';
15
+ this.context = context;
16
+ this.url = context.url;
17
+ }
18
+ }
19
+ exports.FetchImageError = FetchImageError;
@@ -4,7 +4,12 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.buildFetchUrl = buildFetchUrl;
7
+ var _index = require("../validate-url/index.js");
7
8
  function buildFetchUrl(url, options) {
9
+ // Validate url parameter
10
+ if (!url || typeof url !== 'string') {
11
+ throw new Error(`buildFetchUrl: Invalid url parameter. url=${JSON.stringify(url)}`);
12
+ }
8
13
  const {
9
14
  awsS3BaseUrl,
10
15
  cloudfrontBaseUrl = '',
@@ -19,6 +24,10 @@ function buildFetchUrl(url, options) {
19
24
  Signature
20
25
  } = options;
21
26
  if (shouldUseCloudfront) {
27
+ // Validate cloudfrontBaseUrl when using CloudFront
28
+ if (!cloudfrontBaseUrl) {
29
+ throw new Error(`buildFetchUrl: cloudfrontBaseUrl is required when shouldUseCloudfront=true. cloudfrontBaseUrl=${JSON.stringify(cloudfrontBaseUrl)}`);
30
+ }
22
31
  const isWebContext = shouldUseCloudfront && typeof window === 'object';
23
32
  const paramMap = {
24
33
  width,
@@ -33,7 +42,18 @@ function buildFetchUrl(url, options) {
33
42
  }
34
43
  const params = Object.entries(paramMap).filter(([, value]) => value != null).map(([key, value]) => `${key}=${String(value)}`);
35
44
  const paramsString = params.join('&');
36
- return `${cloudfrontBaseUrl}/${url}?${paramsString}`;
45
+ const result = `${cloudfrontBaseUrl}/${url}?${paramsString}`;
46
+
47
+ // Validate output is absolute URL
48
+ if (!(0, _index.isAbsoluteUrl)(result)) {
49
+ throw new Error(`buildFetchUrl: Constructed URL is not absolute. cloudfrontBaseUrl=${JSON.stringify(cloudfrontBaseUrl)}, url=${JSON.stringify(url)}, result=${JSON.stringify(result)}`);
50
+ }
51
+ return result;
52
+ }
53
+
54
+ // Validate required base URLs for Cloudinary path
55
+ if (!cloudinaryBaseUrl || !awsS3BaseUrl) {
56
+ throw new Error(`buildFetchUrl: cloudinaryBaseUrl and awsS3BaseUrl are required. cloudinaryBaseUrl=${JSON.stringify(cloudinaryBaseUrl)}, awsS3BaseUrl=${JSON.stringify(awsS3BaseUrl)}`);
37
57
  }
38
58
  const transformations = [];
39
59
  let transformationsString = '';
@@ -43,5 +63,10 @@ function buildFetchUrl(url, options) {
43
63
  if (fit) transformations.push('c_fit');
44
64
  transformationsString = `${transformations.join(',')}/`;
45
65
  const fetchUrl = `${cloudinaryBaseUrl}/${transformationsString}${awsS3BaseUrl}/${url}`;
66
+
67
+ // Validate output is absolute URL
68
+ if (!(0, _index.isAbsoluteUrl)(fetchUrl)) {
69
+ throw new Error(`buildFetchUrl: Constructed URL is not absolute. cloudinaryBaseUrl=${JSON.stringify(cloudinaryBaseUrl)}, awsS3BaseUrl=${JSON.stringify(awsS3BaseUrl)}, url=${JSON.stringify(url)}, result=${JSON.stringify(fetchUrl)}`);
70
+ }
46
71
  return fetchUrl;
47
72
  }
@@ -15,6 +15,7 @@ var _constants = require("../../constants");
15
15
  var _images = require("../../images");
16
16
  var _fetchImageForPdfGeneratorService = require("../fetch-image-for-pdf-generator-service");
17
17
  var _fetchImageForWeb = require("../fetch-image-for-web");
18
+ var _index = require("../validate-url/index.js");
18
19
  // NOTE use the native fetch if it's available in the browser, because the
19
20
  // ponyfill (which actually uses the github polyfill) does not support all the
20
21
  // same options as native fetch
@@ -37,8 +38,29 @@ const defaultOptions = {
37
38
  };
38
39
  function fetchImage(url, options = {}) {
39
40
  const {
40
- shouldUseCloudfront
41
+ shouldUseCloudfront,
42
+ isHeader = false,
43
+ context = {}
41
44
  } = options;
45
+
46
+ // Validate url parameter
47
+ if (!url || typeof url !== 'string') {
48
+ const error = new Error(`fetchImage: Invalid url parameter. url=${JSON.stringify(url)}`);
49
+ if (isHeader) {
50
+ console.error('FetchImageHeaderError', {
51
+ message: error.message,
52
+ url,
53
+ context
54
+ });
55
+ return fetchImage(_constants.LIGHTHOUSE_LOGO_URL, defaultOptions);
56
+ }
57
+ console.error('FetchImageError', {
58
+ message: error.message,
59
+ url,
60
+ context
61
+ });
62
+ return _bluebird.default.resolve(_images.imageNotFound);
63
+ }
42
64
  if (shouldUseCloudfront) {
43
65
  const isWebContext = typeof window === 'object';
44
66
  return isWebContext ?
@@ -50,9 +72,6 @@ function fetchImage(url, options = {}) {
50
72
  ...defaultOptions,
51
73
  ...options
52
74
  };
53
- const {
54
- isHeader = false
55
- } = options;
56
75
  return fetch(encodedUrl, fetchOptions).then(response => {
57
76
  const contentHeader = response.headers.get('content-length');
58
77
  const contentType = response.headers.get('content-type');
@@ -60,10 +79,10 @@ function fetchImage(url, options = {}) {
60
79
  // NOTE: the response will be ok but we won't be able to render any
61
80
  // image meaning pdfmake will error. Raise error here and return early.
62
81
  if (contentHeader === '0') {
63
- return _bluebird.default.reject(new Error(`Failed to fetch image as no content length: ${encodedUrl}`));
82
+ return _bluebird.default.reject(new Error(`Failed to fetch image as no content length: ${url}`));
64
83
  }
65
84
  if (!response.ok) {
66
- return _bluebird.default.reject(new Error(`Failed to fetch image: ${encodedUrl}`));
85
+ return _bluebird.default.reject(new Error(`Failed to fetch image: ${url}`));
67
86
  }
68
87
  const imageType = contentTypes[contentType];
69
88
  return response.arrayBuffer().then(buffer => ({
@@ -85,10 +104,20 @@ function fetchImage(url, options = {}) {
85
104
  }).catch(error => {
86
105
  if (isHeader) {
87
106
  // NOTE: Replace failed headers with LH logo
88
- console.error('FetchImageHeaderError', error);
107
+ console.error('FetchImageHeaderError', {
108
+ url,
109
+ message: error.message,
110
+ context,
111
+ stack: error.stack
112
+ });
89
113
  return fetchImage(_constants.LIGHTHOUSE_LOGO_URL, defaultOptions);
90
114
  }
91
- console.error(error);
115
+ console.error('FetchImageError', {
116
+ url,
117
+ message: error.message,
118
+ context,
119
+ stack: error.stack
120
+ });
92
121
  return _images.imageNotFound;
93
122
  });
94
123
  }
@@ -10,12 +10,14 @@ exports.formatBase64Image = formatBase64Image;
10
10
  exports.requestImageTransformation = requestImageTransformation;
11
11
  var _imageValidators = require("../image-validators");
12
12
  var _awsSdk = _interopRequireDefault(require("aws-sdk"));
13
- const REGION = process.env.AWS_REGION;
13
+ // Image transformer and cache are always in us-east-1 (shared across all regions)
14
+ // The image-optimisation-image-processing Lambda only exists in us-east-1
15
+ const IMAGE_CACHE_REGION = 'us-east-1';
14
16
  const lambda = new _awsSdk.default.Lambda({
15
- region: REGION
17
+ region: IMAGE_CACHE_REGION
16
18
  });
17
19
  const s3 = new _awsSdk.default.S3({
18
- region: REGION
20
+ region: IMAGE_CACHE_REGION
19
21
  });
20
22
  const fetchImageForPdfGeneratorService = async function (url) {
21
23
  console.debug('Fetching image via CloudFront For Serverless Pdf Generator Service');
@@ -46,6 +48,7 @@ const fetchImageForPdfGeneratorService = async function (url) {
46
48
  }
47
49
  const transformerResponse = await requestImageTransformation(`/${path}`, searchParamsObject);
48
50
  const statusCode = transformerResponse.statusCode;
51
+ const redirectLocation = transformerResponse.headers?.Location;
49
52
  switch (statusCode) {
50
53
  case 200:
51
54
  {
@@ -58,21 +61,24 @@ const fetchImageForPdfGeneratorService = async function (url) {
58
61
  }
59
62
  case 302:
60
63
  {
61
- console.debug('Image transformation successful but image is too big for lambda delivery, fetching directly from S3');
62
- const redirectLocation = transformerResponse.headers.Location;
64
+ console.debug('Image transformation successful but image is too big for lambda delivery, fetching directly via redirect URL');
63
65
  if (!redirectLocation) {
64
66
  throw new Error('Redirect response received but no location provided');
65
67
  }
66
- const newlyTransformedImage = await fetchResourceFromS3({
67
- bucketName: process.env.S3_BUCKET_IMAGE_TRANSFORMER_CACHE,
68
- key: transformedBucketImagePath
69
- });
70
- console.debug('Image successfully fetched from S3 at:', redirectLocation);
71
- const fullDataUrl = formatBase64Image({
72
- base64String: newlyTransformedImage.body.toString('base64'),
68
+ let response;
69
+ try {
70
+ response = await fetch(redirectLocation);
71
+ } catch (error) {
72
+ throw new Error(`Failed to fetch image from redirect URL: ${error.message}`);
73
+ }
74
+ if (!response.ok) {
75
+ throw new Error(`Failed to fetch image from redirect: ${response.status}`);
76
+ }
77
+ const buffer = Buffer.from(await response.arrayBuffer());
78
+ return formatBase64Image({
79
+ base64String: buffer.toString('base64'),
73
80
  key: transformedBucketImagePath
74
81
  });
75
- return fullDataUrl;
76
82
  }
77
83
  case 400:
78
84
  throw new Error(`Bad request to image transformer: ${transformerResponse.body}`);
@@ -6,13 +6,34 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.fetchImageForWeb = void 0;
7
7
  var _images = require("../../images");
8
8
  var _fetchLighthouseLogo = require("../fetch-lighthouse-logo");
9
+ var _index = require("../validate-url/index.js");
9
10
  const fetchImageForWeb = async function (url, options) {
10
11
  const {
11
12
  isHeader = false,
12
13
  Signature,
13
14
  Policy,
14
- KeyPairId
15
+ KeyPairId,
16
+ context = {}
15
17
  } = options;
18
+
19
+ // Validate url parameter
20
+ if (!url || typeof url !== 'string') {
21
+ const error = new Error(`fetchImageForWeb: Invalid url parameter. url=${JSON.stringify(url)}`);
22
+ if (isHeader) {
23
+ console.error('FetchImageHeaderError', {
24
+ message: error.message,
25
+ url,
26
+ context
27
+ });
28
+ return (0, _fetchLighthouseLogo.fetchLighthouseLogo)();
29
+ }
30
+ console.error('FetchImageError', {
31
+ message: error.message,
32
+ url,
33
+ context
34
+ });
35
+ return _images.imageNotFound;
36
+ }
16
37
  try {
17
38
  const firstParamConnector = url.indexOf('?') > -1 ? '&' : '?';
18
39
  const hasSignatureParams = url.includes('Signature=') && url.includes('Policy=') && url.includes('Key-Pair-Id=');
@@ -21,19 +42,29 @@ const fetchImageForWeb = async function (url, options) {
21
42
  const imageResponse = await fetch(constructedUrl);
22
43
  const contentLengthHeader = imageResponse.headers.get('content-length');
23
44
  if (contentLengthHeader === '0') {
24
- return Promise.reject(new Error(`Failed to fetch image as no content length: ${encodedUrl}`));
45
+ return Promise.reject(new Error(`Failed to fetch image as no content length: ${url}`));
25
46
  }
26
47
  if (!imageResponse.ok) {
27
- return Promise.reject(new Error(`Failed to fetch image: ${encodedUrl}`));
48
+ return Promise.reject(new Error(`Failed to fetch image: ${url}`));
28
49
  }
29
50
  return await imageResponse.arrayBuffer();
30
51
  } catch (error) {
31
52
  if (isHeader) {
32
53
  // NOTE: Replace failed headers with LH logo
33
- console.error('FetchImageHeaderError', error);
54
+ console.error('FetchImageHeaderError', {
55
+ url,
56
+ message: error.message,
57
+ context,
58
+ stack: error.stack
59
+ });
34
60
  return (0, _fetchLighthouseLogo.fetchLighthouseLogo)();
35
61
  }
36
- console.error(error);
62
+ console.error('FetchImageError', {
63
+ url,
64
+ message: error.message,
65
+ context,
66
+ stack: error.stack
67
+ });
37
68
  return _images.imageNotFound;
38
69
  }
39
70
  };
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isAbsoluteUrl = isAbsoluteUrl;
7
+ /**
8
+ * Checks if a URL is absolute (starts with http:// or https://)
9
+ * @param {string} url - The URL to validate
10
+ * @returns {boolean} - True if URL is absolute, false otherwise
11
+ */
12
+ function isAbsoluteUrl(url) {
13
+ if (!url || typeof url !== 'string') return false;
14
+ return url.startsWith('http://') || url.startsWith('https://');
15
+ }
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.defaultHeader = defaultHeader;
7
7
  var _helpers = require("../../../helpers");
8
+ var _constants = require("../../../constants");
9
+ var _index = require("../../../helpers/validate-url/index.js");
8
10
  function defaultHeader({
9
11
  Signature,
10
12
  Policy,
@@ -19,7 +21,15 @@ function defaultHeader({
19
21
  timestamp,
20
22
  timezone
21
23
  });
22
- return (0, _helpers.fetchImage)(logoUrl, {
24
+
25
+ // Validate logoUrl and use fallback if invalid
26
+ const effectiveLogoUrl = (0, _index.isAbsoluteUrl)(logoUrl) ? logoUrl : _constants.LIGHTHOUSE_LOGO_URL;
27
+ if (!(0, _index.isAbsoluteUrl)(logoUrl)) {
28
+ console.warn('defaultHeader: Invalid logoUrl, using Lighthouse logo', {
29
+ providedLogoUrl: logoUrl
30
+ });
31
+ }
32
+ return (0, _helpers.fetchImage)(effectiveLogoUrl, {
23
33
  Signature,
24
34
  Policy,
25
35
  KeyPairId,
@@ -13,6 +13,18 @@ var _momentTimezone = _interopRequireDefault(require("moment-timezone"));
13
13
  var _helpers = require("../../../helpers");
14
14
  var _images = require("../../../images");
15
15
  var _ = require("../");
16
+ function rewriteS3UrlToCloudfront(url, settings) {
17
+ const {
18
+ shouldUseCloudfront,
19
+ cloudfrontBaseUrl,
20
+ awsS3BaseUrl
21
+ } = settings;
22
+ if (!shouldUseCloudfront || !cloudfrontBaseUrl || !awsS3BaseUrl) return url;
23
+ if (typeof url === 'string' && url.startsWith(awsS3BaseUrl)) {
24
+ return url.replace(awsS3BaseUrl, cloudfrontBaseUrl);
25
+ }
26
+ return url;
27
+ }
16
28
  function buildFile({
17
29
  file,
18
30
  settings,
@@ -41,7 +53,9 @@ function buildImage(options) {
41
53
  height = 210,
42
54
  settings = {},
43
55
  signedAsset,
44
- width = 210
56
+ width = 210,
57
+ fieldLabel,
58
+ fieldType = 'image'
45
59
  } = options;
46
60
  const {
47
61
  awsS3BaseUrl,
@@ -71,7 +85,15 @@ function buildImage(options) {
71
85
  });
72
86
 
73
87
  // NOTE: shouldUseCloudfront, Signature, Policy and KeyPairId from settings are used in this context
74
- return (0, _helpers.fetchImage)(url, settings).then(base64String => ({
88
+ return (0, _helpers.fetchImage)(url, {
89
+ ...settings,
90
+ context: {
91
+ stage: 'field',
92
+ fieldLabel,
93
+ fieldType,
94
+ filepath
95
+ }
96
+ }).then(base64String => ({
75
97
  alignment,
76
98
  fit: [width, height],
77
99
  image: base64String,
@@ -121,7 +143,15 @@ function buildSummaryField({
121
143
  };
122
144
  }
123
145
  // NOTE: shouldUseCloudfront, Signature, Policy and KeyPairId from settings are used in this context
124
- return (0, _helpers.fetchImage)(value, settings).then(base64String => {
146
+ const signatureUrl = rewriteS3UrlToCloudfront(value, settings);
147
+ return (0, _helpers.fetchImage)(signatureUrl, {
148
+ ...settings,
149
+ context: {
150
+ stage: 'field',
151
+ fieldLabel: field.label,
152
+ fieldType: 'signature'
153
+ }
154
+ }).then(base64String => {
125
155
  return {
126
156
  alignment: 'left',
127
157
  image: base64String,
@@ -145,7 +175,9 @@ function buildSummaryField({
145
175
  height: 140,
146
176
  width: 140,
147
177
  settings,
148
- signedAsset: signedAssets && (0, _lodash.isArray)(signedAssets) ? signedAssets[0] : null
178
+ signedAsset: signedAssets && (0, _lodash.isArray)(signedAssets) ? signedAssets[0] : null,
179
+ fieldLabel: field.label,
180
+ fieldType: 'media'
149
181
  });
150
182
  return image;
151
183
  }
@@ -244,7 +276,15 @@ function buildTemplateFieldRow({
244
276
  if (isSignatureField) {
245
277
  if (!value) return [labelText, ''];
246
278
  // NOTE: shouldUseCloudfront, Signature, Policy and KeyPairId from settings are used in this context
247
- return (0, _helpers.fetchImage)(value, settings).then(base64String => {
279
+ const signatureUrl = rewriteS3UrlToCloudfront(value, settings);
280
+ return (0, _helpers.fetchImage)(signatureUrl, {
281
+ ...settings,
282
+ context: {
283
+ stage: 'field',
284
+ fieldLabel: label,
285
+ fieldType: 'signature'
286
+ }
287
+ }).then(base64String => {
248
288
  const values = {
249
289
  alignment: 'left',
250
290
  image: base64String,
@@ -254,22 +294,39 @@ function buildTemplateFieldRow({
254
294
  });
255
295
  }
256
296
  if (isDisplayImageField) {
257
- return _bluebird.default.map([value], (filepath, index) => {
297
+ // Guard against nullish values
298
+ if (!value) {
299
+ return [[], {}];
300
+ }
301
+
302
+ // Ensure value is always treated as an array of filepaths
303
+ const filepaths = (0, _lodash.isArray)(value) ? value : [value];
304
+ return _bluebird.default.map(filepaths, (filepath, index) => {
258
305
  const signedAssetValue = (0, _lodash.isArray)(signedAssets) ? signedAssets[index] : signedAssets;
259
306
  return buildImage({
260
307
  filepath,
261
308
  settings,
262
- signedAsset: signedAssetValue
309
+ signedAsset: signedAssetValue,
310
+ fieldLabel: label,
311
+ fieldType: 'image-display'
263
312
  });
264
313
  }).then(fieldImages => [fieldImages, {}]);
265
314
  }
266
315
  if (isPhotoField) {
316
+ // Guard against nullish values
317
+ if (!value || (0, _lodash.isArray)(value) && value.length === 0) {
318
+ return [labelText, {
319
+ text: ''
320
+ }];
321
+ }
267
322
  return _bluebird.default.map(value, (filepath, index) => {
268
323
  const signedAssetValue = (0, _lodash.isArray)(signedAssets) ? signedAssets[index] : signedAssets;
269
324
  return buildImage({
270
325
  filepath,
271
326
  settings,
272
- signedAsset: signedAssetValue
327
+ signedAsset: signedAssetValue,
328
+ fieldLabel: label,
329
+ fieldType: 'media'
273
330
  });
274
331
  }).then(fieldImages => {
275
332
  const tables = !(0, _lodash.isEmpty)(fieldImages) ? (0, _.imageTables)(fieldImages) : [];
@@ -298,7 +355,7 @@ function buildTemplateFieldRow({
298
355
  }
299
356
  if (isFileField) {
300
357
  const fileList = (0, _lodash.map)(value, (file, index) => {
301
- const signedAsset = signedAssets[index];
358
+ const signedAsset = signedAssets?.[index];
302
359
  return buildFile({
303
360
  file,
304
361
  settings,
@@ -52,8 +52,16 @@ function generateDefinition(options) {
52
52
  pageOrientation,
53
53
  pageSize,
54
54
  styles: pdfStyles
55
- })).catch(err => {
56
- throw new Error(`GenerateDefinitionError: ${err.message}`);
55
+ })).catch(error => {
56
+ // Preserve structured error information for better debugging
57
+ console.error('GenerateDefinitionError', {
58
+ message: error.message,
59
+ context: error.context,
60
+ url: error.url,
61
+ type: options.type,
62
+ stack: error.stack
63
+ });
64
+ throw error; // Preserve original error instead of wrapping
57
65
  });
58
66
  }
59
67
  function pdfHeader(header) {
@@ -1,13 +1,11 @@
1
1
  "use strict";
2
2
 
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
3
  Object.defineProperty(exports, "__esModule", {
5
4
  value: true
6
5
  });
7
6
  exports.complyingServiceIntervalUnits = void 0;
8
7
  exports.generateRepeatingSchedule = generateRepeatingSchedule;
9
8
  var _fp = require("lodash/fp");
10
- var _momentTimezone = _interopRequireDefault(require("moment-timezone"));
11
9
  var _ = require(".");
12
10
  var _scheduling = require("../scheduling.types");
13
11
  var _generators = require("../generators");
@@ -49,17 +47,7 @@ function* generateRepeatingSchedule(props) {
49
47
  end,
50
48
  start
51
49
  });
52
- console.log('[generateRepeatingSchedule] INIT:', {
53
- start: _momentTimezone.default.tz(start, timezone).format('YYYY-MM-DD HH:mm:ss Z'),
54
- end: _momentTimezone.default.tz(end, timezone).format('YYYY-MM-DD HH:mm:ss Z'),
55
- isStartAndEndValid,
56
- frequencyUnit,
57
- timezone
58
- });
59
- if (!isStartAndEndValid) {
60
- console.log('[generateRepeatingSchedule] INVALID START/END - RETURNING EARLY');
61
- return [];
62
- }
50
+ if (!isStartAndEndValid) return [];
63
51
  const serviceIntervalSequence = (0, _generators.serviceIntervalsGenerator)({
64
52
  end,
65
53
  serviceHours,
@@ -70,20 +58,7 @@ function* generateRepeatingSchedule(props) {
70
58
  // all service intervals otherwise service interval is from the start and end
71
59
  const complyToServiceHours = (0, _fp.includes)(frequencyUnit, complyingServiceIntervalUnits);
72
60
  const serviceIntervals = complyToServiceHours ? [...serviceIntervalSequence] : [[start, end]];
73
- console.log('[generateRepeatingSchedule] SERVICE_INTERVALS:', {
74
- count: serviceIntervals.length,
75
- complyToServiceHours,
76
- intervals: serviceIntervals.slice(0, 3).map(interval => ({
77
- start: _momentTimezone.default.tz(interval[0], timezone).format('YYYY-MM-DD HH:mm:ss Z'),
78
- end: _momentTimezone.default.tz(interval[1], timezone).format('YYYY-MM-DD HH:mm:ss Z')
79
- }))
80
- });
81
- let serviceIntervalIndex = 0;
82
61
  for (const serviceInterval of serviceIntervals) {
83
- console.log(`[generateRepeatingSchedule] PROCESSING_SERVICE_INTERVAL[${serviceIntervalIndex}]:`, {
84
- start: _momentTimezone.default.tz(serviceInterval[0], timezone).format('YYYY-MM-DD HH:mm:ss Z'),
85
- end: _momentTimezone.default.tz(serviceInterval[1], timezone).format('YYYY-MM-DD HH:mm:ss Z')
86
- });
87
62
  yield {
88
63
  interval: serviceInterval,
89
64
  type: _scheduling.IntervalTypes.Service
@@ -94,27 +69,16 @@ function* generateRepeatingSchedule(props) {
94
69
  strategy,
95
70
  timezone
96
71
  });
97
- let occurrenceCount = 0;
98
72
  for (const occurrenceInterval of occurrenceIntervalsSequence) {
99
- console.log(`[generateRepeatingSchedule] OCCURRENCE[${occurrenceCount}]:`, {
100
- start: _momentTimezone.default.tz(occurrenceInterval[0], timezone).format('YYYY-MM-DD HH:mm:ss Z'),
101
- end: _momentTimezone.default.tz(occurrenceInterval[1], timezone).format('YYYY-MM-DD HH:mm:ss Z')
102
- });
103
73
  yield {
104
74
  interval: occurrenceInterval,
105
75
  type: _scheduling.IntervalTypes.Occurrence
106
76
  };
107
- occurrenceCount++;
108
77
  }
109
- console.log(`[generateRepeatingSchedule] SERVICE_INTERVAL[${serviceIntervalIndex}] COMPLETED:`, {
110
- occurrenceCount
111
- });
112
78
 
113
79
  // NOTE: we must reset isInitial to true following the first service
114
80
  // interval otherwise the occurrence will not start exactly on the next
115
81
  // service interval start time
116
82
  isInitial = true;
117
- serviceIntervalIndex++;
118
83
  }
119
- console.log('[generateRepeatingSchedule] COMPLETE');
120
84
  }
@@ -26,18 +26,6 @@ function generateScheduleEnd({
26
26
  // NOTE: if frequency unit less than a week we must set end to jump a week
27
27
  // plus the interval length of the schedule frequency
28
28
  // so that we can ensure that we are within a service interval
29
- // MODIFIED FOR TESTING: Changed from 2 weeks to 1 hour for testing endless generation bug
30
- const end = isFrequencyLessThanWeek ? mStart.add(1, _scheduling.Unit.Hour).valueOf() : mStart.add(frequencyValue * 2, frequencyUnit).valueOf();
31
- console.log('[generateScheduleEnd] START:', {
32
- start: _momentTimezone.default.tz(start, timezone).format('YYYY-MM-DD HH:mm:ss Z'),
33
- frequency: `${frequencyValue}${frequencyUnit}`,
34
- isFrequencyLessThanWeek,
35
- timezone
36
- });
37
- console.log('[generateScheduleEnd] END CALCULATED:', {
38
- end: _momentTimezone.default.tz(end, timezone).format('YYYY-MM-DD HH:mm:ss Z'),
39
- endTimestamp: end,
40
- durationFromStart: `${(0, _momentTimezone.default)(end).diff((0, _momentTimezone.default)(start), 'hours')} hours`
41
- });
29
+ const end = isFrequencyLessThanWeek ? mStart.add(2, _scheduling.Unit.Week).valueOf() : mStart.add(frequencyValue * 2, frequencyUnit).valueOf();
42
30
  return end;
43
31
  }
@@ -32,16 +32,6 @@ function* getNext({
32
32
  } = frequency;
33
33
  let initial = isInitial;
34
34
  let dateCursor = initial ? _momentTimezone.default.tz(start, timezone).valueOf() : _momentTimezone.default.tz(start, timezone).add(1, _scheduling.Unit.Millisecond).valueOf();
35
- console.log('[getNext] START:', {
36
- strategy: type,
37
- start: _momentTimezone.default.tz(start, timezone).format('YYYY-MM-DD HH:mm:ss Z'),
38
- end: _momentTimezone.default.tz(end, timezone).format('YYYY-MM-DD HH:mm:ss Z'),
39
- dateCursor: _momentTimezone.default.tz(dateCursor, timezone).format('YYYY-MM-DD HH:mm:ss Z'),
40
- isInitial,
41
- frequency: `${frequencyValue}${frequencyUnit}`,
42
- duration: `${durationValue}${durationUnit}`
43
- });
44
- let occurrenceCount = 0;
45
35
  while (dateCursor < end) {
46
36
  let nextOccurrenceStart;
47
37
  let nextOccurrenceEnd;
@@ -59,27 +49,12 @@ function* getNext({
59
49
  nextOccurrenceStart = _momentTimezone.default.max(earliestNextOccurrenceStart, nextOccurrenceStartByBackCalculation).valueOf();
60
50
  }
61
51
  if (nextOccurrenceEnd <= nextOccurrenceStart || nextOccurrenceEnd > end) {
62
- console.log('[getNext] BOUNDARY CHECK FAILED:', {
63
- occurrenceCount,
64
- nextOccurrenceStart: _momentTimezone.default.tz(nextOccurrenceStart, timezone).format('YYYY-MM-DD HH:mm:ss Z'),
65
- nextOccurrenceEnd: _momentTimezone.default.tz(nextOccurrenceEnd, timezone).format('YYYY-MM-DD HH:mm:ss Z'),
66
- end: _momentTimezone.default.tz(end, timezone).format('YYYY-MM-DD HH:mm:ss Z'),
67
- condition: `(${nextOccurrenceEnd} <= ${nextOccurrenceStart}) || (${nextOccurrenceEnd} > ${end})`
68
- });
69
52
  return;
70
53
  }
71
54
  if (nextOccurrenceStart >= start) {
72
55
  const nextOccurrence = [nextOccurrenceStart, nextOccurrenceEnd - 1];
73
- console.log(`[getNext] OCCURRENCE[${occurrenceCount}]:`, {
74
- start: _momentTimezone.default.tz(nextOccurrenceStart, timezone).format('YYYY-MM-DD HH:mm:ss Z'),
75
- end: _momentTimezone.default.tz(nextOccurrenceEnd - 1, timezone).format('YYYY-MM-DD HH:mm:ss Z')
76
- });
77
56
  yield nextOccurrence;
78
- occurrenceCount++;
79
57
  }
80
58
  dateCursor = nextOccurrenceEnd;
81
59
  }
82
- console.log('[getNext] COMPLETE:', {
83
- occurrenceCount
84
- });
85
60
  }