@remotion/lambda 4.0.0-preload.17 → 4.0.0-reorg.10

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 (158) hide show
  1. package/dist/admin/bundle-lambda.js +1 -0
  2. package/dist/admin/make-layer-public.js +3 -3
  3. package/dist/api/bucket-exists.d.ts +1 -1
  4. package/dist/api/clean-items.d.ts +1 -1
  5. package/dist/api/create-bucket.d.ts +1 -1
  6. package/dist/api/create-function.d.ts +4 -3
  7. package/dist/api/create-function.js +3 -2
  8. package/dist/api/delete-function.d.ts +1 -1
  9. package/dist/api/delete-site.d.ts +1 -1
  10. package/dist/api/deploy-function.d.ts +3 -2
  11. package/dist/api/deploy-function.js +3 -0
  12. package/dist/api/deploy-site.d.ts +3 -3
  13. package/dist/api/deploy-site.js +2 -3
  14. package/dist/api/download-media.d.ts +2 -2
  15. package/dist/api/enable-s3-website.d.ts +1 -1
  16. package/dist/api/estimate-price.d.ts +2 -2
  17. package/dist/api/get-aws-client.d.ts +2 -2
  18. package/dist/api/get-aws-client.js +5 -1
  19. package/dist/api/get-buckets.d.ts +1 -1
  20. package/dist/api/get-function-info.d.ts +2 -2
  21. package/dist/api/get-functions.d.ts +2 -2
  22. package/dist/api/get-or-create-bucket.d.ts +1 -1
  23. package/dist/api/get-regions.d.ts +1 -1
  24. package/dist/api/get-render-progress.d.ts +2 -2
  25. package/dist/api/get-sites.d.ts +2 -2
  26. package/dist/api/iam-validation/role-permissions.d.ts +2 -1
  27. package/dist/api/iam-validation/simulate-rule.d.ts +1 -1
  28. package/dist/api/iam-validation/simulate.d.ts +2 -2
  29. package/dist/api/mock-functions.d.ts +3 -3
  30. package/dist/api/presign-url.d.ts +3 -2
  31. package/dist/api/render-media-on-lambda.d.ts +13 -8
  32. package/dist/api/render-media-on-lambda.js +12 -5
  33. package/dist/api/render-still-on-lambda.d.ts +7 -6
  34. package/dist/api/render-still-on-lambda.js +4 -4
  35. package/dist/api/upload-dir.d.ts +2 -2
  36. package/dist/api/upload-dir.js +2 -1
  37. package/dist/cli/args.d.ts +5 -3
  38. package/dist/cli/commands/functions/deploy.js +6 -2
  39. package/dist/cli/commands/render/progress.d.ts +4 -4
  40. package/dist/cli/commands/render/progress.js +11 -3
  41. package/dist/cli/commands/render/render.js +13 -3
  42. package/dist/cli/commands/sites/create.js +2 -3
  43. package/dist/cli/commands/sites/ls.js +1 -2
  44. package/dist/cli/commands/sites/rm.js +2 -3
  45. package/dist/cli/commands/sites/rmall.js +2 -3
  46. package/dist/cli/commands/still.js +1 -2
  47. package/dist/cli/get-aws-region.d.ts +1 -1
  48. package/dist/cli/helpers/get-cloudwatch-stream-url.d.ts +2 -2
  49. package/dist/cli/helpers/progress-bar.js +1 -2
  50. package/dist/cli/index.js +11 -1
  51. package/dist/defaults.js +5 -1
  52. package/dist/functions/chunk-optimization/can-use-optimization.d.ts +1 -1
  53. package/dist/functions/chunk-optimization/collect-data.d.ts +1 -1
  54. package/dist/functions/chunk-optimization/get-frame-ranges-from-profile.d.ts +1 -1
  55. package/dist/functions/chunk-optimization/get-profile-duration.d.ts +1 -1
  56. package/dist/functions/chunk-optimization/is-valid-profile.d.ts +1 -1
  57. package/dist/functions/chunk-optimization/is-valid-profile.js +2 -2
  58. package/dist/functions/chunk-optimization/optimize-invocation-order.d.ts +1 -1
  59. package/dist/functions/chunk-optimization/optimize-profile.d.ts +1 -1
  60. package/dist/functions/chunk-optimization/plan-frame-ranges.d.ts +7 -4
  61. package/dist/functions/chunk-optimization/plan-frame-ranges.js +7 -6
  62. package/dist/functions/chunk-optimization/s3-optimization-file.d.ts +2 -2
  63. package/dist/functions/chunk-optimization/s3-optimization-file.js +1 -0
  64. package/dist/functions/chunk-optimization/simulate-frame-ranges.d.ts +1 -1
  65. package/dist/functions/chunk-optimization/sort-by-duration.d.ts +1 -1
  66. package/dist/functions/chunk-optimization/types.d.ts +2 -1
  67. package/dist/functions/helpers/calculate-chunk-times.d.ts +1 -1
  68. package/dist/functions/helpers/calculate-price-from-bucket.d.ts +4 -4
  69. package/dist/functions/helpers/concat-videos.d.ts +6 -4
  70. package/dist/functions/helpers/concat-videos.js +8 -2
  71. package/dist/functions/helpers/create-post-render-data.d.ts +6 -6
  72. package/dist/functions/helpers/create-post-render-data.js +5 -5
  73. package/dist/functions/helpers/delete-chunks.d.ts +3 -3
  74. package/dist/functions/helpers/expected-out-name.d.ts +1 -1
  75. package/dist/functions/helpers/find-output-file-in-bucket.d.ts +2 -2
  76. package/dist/functions/helpers/format-costs-info.d.ts +1 -1
  77. package/dist/functions/helpers/get-browser-instance.d.ts +2 -1
  78. package/dist/functions/helpers/get-cleanup-progress.d.ts +2 -2
  79. package/dist/functions/helpers/get-current-architecture.d.ts +1 -1
  80. package/dist/functions/helpers/get-encoding-metadata.d.ts +2 -2
  81. package/dist/functions/helpers/get-files-to-delete.js +2 -2
  82. package/dist/functions/helpers/get-final-encoding-status.d.ts +2 -2
  83. package/dist/functions/helpers/get-lambdas-invoked-stats.d.ts +1 -1
  84. package/dist/functions/helpers/get-output-url-from-metadata.d.ts +1 -1
  85. package/dist/functions/helpers/get-post-render-data.d.ts +2 -2
  86. package/dist/functions/helpers/get-progress.d.ts +2 -2
  87. package/dist/functions/helpers/get-progress.js +12 -10
  88. package/dist/functions/helpers/get-render-metadata.d.ts +2 -2
  89. package/dist/functions/helpers/get-retry-stats.d.ts +1 -1
  90. package/dist/functions/helpers/get-time-to-finish.d.ts +1 -1
  91. package/dist/functions/helpers/inspect-errors.d.ts +3 -3
  92. package/dist/functions/helpers/io.d.ts +8 -6
  93. package/dist/functions/helpers/io.js +3 -1
  94. package/dist/functions/helpers/print-cloudwatch-helper.d.ts +1 -1
  95. package/dist/functions/helpers/read-with-progress.d.ts +3 -2
  96. package/dist/functions/helpers/read-with-progress.js +13 -1
  97. package/dist/functions/helpers/validate-composition.d.ts +5 -4
  98. package/dist/functions/helpers/validate-composition.js +2 -1
  99. package/dist/functions/helpers/write-lambda-error.d.ts +1 -1
  100. package/dist/functions/helpers/write-lambda-error.js +1 -0
  101. package/dist/functions/helpers/write-post-render-data.d.ts +2 -2
  102. package/dist/functions/helpers/write-post-render-data.js +1 -0
  103. package/dist/functions/index.d.ts +3 -2
  104. package/dist/functions/index.js +4 -4
  105. package/dist/functions/info.d.ts +1 -1
  106. package/dist/functions/launch.d.ts +1 -1
  107. package/dist/functions/launch.js +28 -16
  108. package/dist/functions/progress.d.ts +1 -1
  109. package/dist/functions/renderer.d.ts +1 -1
  110. package/dist/functions/renderer.js +16 -11
  111. package/dist/functions/start.d.ts +1 -1
  112. package/dist/functions/start.js +5 -2
  113. package/dist/functions/still.d.ts +1 -1
  114. package/dist/functions/still.js +10 -6
  115. package/dist/index.d.ts +33 -18
  116. package/dist/pricing/price-per-1-s.d.ts +1 -1
  117. package/dist/shared/aws-clients.d.ts +1 -1
  118. package/dist/shared/bundle-site.d.ts +1 -6
  119. package/dist/shared/call-lambda.d.ts +3 -3
  120. package/dist/shared/check-credentials.js +2 -2
  121. package/dist/shared/constants.d.ts +27 -11
  122. package/dist/shared/constants.js +1 -1
  123. package/dist/shared/content-disposition-header.d.ts +7 -0
  124. package/dist/shared/content-disposition-header.js +19 -0
  125. package/dist/shared/convert-to-serve-url.d.ts +1 -1
  126. package/dist/shared/get-account-id.d.ts +1 -1
  127. package/dist/shared/get-function-version.d.ts +2 -2
  128. package/dist/shared/get-most-expensive-chunks.d.ts +8 -0
  129. package/dist/shared/get-most-expensive-chunks.js +25 -0
  130. package/dist/shared/hosted-layers.d.ts +2 -2
  131. package/dist/shared/hosted-layers.js +80 -80
  132. package/dist/shared/make-s3-key.d.ts +1 -0
  133. package/dist/shared/make-s3-key.js +11 -0
  134. package/dist/shared/make-s3-url.d.ts +1 -1
  135. package/dist/shared/random-hash.d.ts +2 -2
  136. package/dist/shared/random-hash.js +1 -1
  137. package/dist/shared/return-values.d.ts +7 -7
  138. package/dist/shared/return-values.js +0 -1
  139. package/dist/shared/stream-to-string.d.ts +2 -1
  140. package/dist/shared/truthy.d.ts +3 -0
  141. package/dist/shared/truthy.js +7 -0
  142. package/dist/shared/validate-aws-region.d.ts +1 -1
  143. package/dist/shared/validate-custom-role-arn.d.ts +1 -0
  144. package/dist/shared/validate-custom-role-arn.js +11 -0
  145. package/dist/shared/validate-download-behavior.d.ts +1 -0
  146. package/dist/shared/validate-download-behavior.js +21 -0
  147. package/dist/shared/validate-lambda-codec.d.ts +4 -0
  148. package/dist/shared/validate-lambda-codec.js +29 -0
  149. package/dist/shared/validate-outname.d.ts +1 -1
  150. package/dist/shared/validate-presign-expiration.d.ts +0 -2
  151. package/dist/shared/validate-presign-expiration.js +7 -7
  152. package/dist/shared/validate-privacy.d.ts +1 -1
  153. package/package.json +10 -12
  154. package/remotionlambda.zip +0 -0
  155. package/dist/cli/helpers/format-bytes.d.ts +0 -6
  156. package/dist/cli/helpers/format-bytes.js +0 -103
  157. package/dist/shared/chunk.d.ts +0 -1
  158. package/dist/shared/chunk.js +0 -11
@@ -8,7 +8,6 @@ const client_lambda_1 = require("@aws-sdk/client-lambda");
8
8
  const renderer_1 = require("@remotion/renderer");
9
9
  const fs_1 = __importDefault(require("fs"));
10
10
  const path_1 = __importDefault(require("path"));
11
- const remotion_1 = require("remotion");
12
11
  const aws_clients_1 = require("../shared/aws-clients");
13
12
  const constants_1 = require("../shared/constants");
14
13
  const clean_tmpdir_1 = require("./helpers/clean-tmpdir");
@@ -23,8 +22,7 @@ const renderHandler = async (params, options, logs) => {
23
22
  if (params.type !== constants_1.LambdaRoutines.renderer) {
24
23
  throw new Error('Params must be renderer');
25
24
  }
26
- remotion_1.Internals.Logging.setLogLevel(params.logLevel);
27
- const browserInstance = await (0, get_browser_instance_1.getBrowserInstance)(remotion_1.Internals.Logging.isEqualOrBelowLogLevel(params.logLevel, 'verbose'), (_a = params.chromiumOptions) !== null && _a !== void 0 ? _a : {});
25
+ const browserInstance = await (0, get_browser_instance_1.getBrowserInstance)(renderer_1.RenderInternals.isEqualOrBelowLogLevel(params.logLevel, 'verbose'), (_a = params.chromiumOptions) !== null && _a !== void 0 ? _a : {});
28
26
  const outputPath = renderer_1.RenderInternals.tmpDir('remotion-render-');
29
27
  if (typeof params.chunk !== 'number') {
30
28
  throw new Error('must pass chunk');
@@ -41,6 +39,7 @@ const renderHandler = async (params, options, logs) => {
41
39
  };
42
40
  const outdir = renderer_1.RenderInternals.tmpDir(constants_1.RENDERER_PATH_TOKEN);
43
41
  const outputLocation = path_1.default.join(outdir, `localchunk-${String(params.chunk).padStart(8, '0')}.${renderer_1.RenderInternals.getFileExtensionFromCodec(params.codec, 'chunk')}`);
42
+ const chunkCodec = params.codec === 'gif' ? 'h264-mkv' : params.codec;
44
43
  await (0, renderer_1.renderMedia)({
45
44
  composition: {
46
45
  id: params.composition,
@@ -54,16 +53,16 @@ const renderHandler = async (params, options, logs) => {
54
53
  frameRange: params.frameRange,
55
54
  onProgress: ({ renderedFrames, encodedFrames, stitchStage }) => {
56
55
  if (renderedFrames % 10 === 0 &&
57
- remotion_1.Internals.Logging.isEqualOrBelowLogLevel(params.logLevel, 'verbose')) {
56
+ renderer_1.RenderInternals.isEqualOrBelowLogLevel(params.logLevel, 'verbose')) {
58
57
  console.log(`Rendered ${renderedFrames} frames, encoded ${encodedFrames} frames, stage = ${stitchStage}`);
59
58
  }
60
- const duration = renderer_1.RenderInternals.getDurationFromFrameRange(params.frameRange, params.durationInFrames);
61
- if (renderedFrames === duration) {
59
+ const allFrames = renderer_1.RenderInternals.getFramesToRender(params.frameRange, params.everyNthFrame);
60
+ if (renderedFrames === allFrames.length) {
62
61
  console.log('Rendered all frames!');
63
62
  }
64
63
  chunkTimingData.timings[renderedFrames] = Date.now() - start;
65
64
  },
66
- parallelism: 1,
65
+ parallelism: params.concurrencyPerLambda,
67
66
  onStart: () => {
68
67
  (0, io_1.lambdaWriteFile)({
69
68
  privacy: 'private',
@@ -83,18 +82,20 @@ const renderHandler = async (params, options, logs) => {
83
82
  }),
84
83
  region: (0, get_current_region_1.getCurrentRegionInFunction)(),
85
84
  expectedBucketOwner: options.expectedBucketOwner,
85
+ downloadBehavior: null,
86
86
  });
87
87
  },
88
88
  puppeteerInstance: browserInstance,
89
89
  serveUrl: params.serveUrl,
90
90
  quality: params.quality,
91
91
  envVariables: params.envVariables,
92
- dumpBrowserLogs: remotion_1.Internals.Logging.isEqualOrBelowLogLevel(params.logLevel, 'verbose'),
92
+ dumpBrowserLogs: renderer_1.RenderInternals.isEqualOrBelowLogLevel(params.logLevel, 'verbose'),
93
+ verbose: renderer_1.RenderInternals.isEqualOrBelowLogLevel(params.logLevel, 'verbose'),
93
94
  onBrowserLog: (log) => {
94
95
  logs.push(log);
95
96
  },
96
97
  outputLocation,
97
- codec: params.codec,
98
+ codec: chunkCodec,
98
99
  crf: (_b = params.crf) !== null && _b !== void 0 ? _b : undefined,
99
100
  ffmpegExecutable: process.env.NODE_ENV === 'test' ? null : '/opt/bin/ffmpeg',
100
101
  pixelFormat: params.pixelFormat,
@@ -108,6 +109,8 @@ const renderHandler = async (params, options, logs) => {
108
109
  scale: params.scale,
109
110
  timeoutInMilliseconds: params.timeoutInMilliseconds,
110
111
  port: null,
112
+ everyNthFrame: params.everyNthFrame,
113
+ numberOfGifLoops: null,
111
114
  });
112
115
  const endRendered = Date.now();
113
116
  console.log('Adding silent audio, chunk', params.chunk);
@@ -125,6 +128,7 @@ const renderHandler = async (params, options, logs) => {
125
128
  region: (0, get_current_region_1.getCurrentRegionInFunction)(),
126
129
  privacy: params.privacy,
127
130
  expectedBucketOwner: options.expectedBucketOwner,
131
+ downloadBehavior: null,
128
132
  });
129
133
  await Promise.all([
130
134
  fs_1.default.promises.rm(outputLocation, { recursive: true }),
@@ -132,15 +136,16 @@ const renderHandler = async (params, options, logs) => {
132
136
  (0, io_1.lambdaWriteFile)({
133
137
  bucketName: params.bucketName,
134
138
  body: JSON.stringify(condensedTimingData, null, 2),
135
- key: `${(0, constants_1.lambdaTimingsKey)({
139
+ key: (0, constants_1.lambdaTimingsKey)({
136
140
  renderId: params.renderId,
137
141
  chunk: params.chunk,
138
142
  rendered: endRendered,
139
143
  start,
140
- })}`,
144
+ }),
141
145
  region: (0, get_current_region_1.getCurrentRegionInFunction)(),
142
146
  privacy: 'private',
143
147
  expectedBucketOwner: options.expectedBucketOwner,
148
+ downloadBehavior: null,
144
149
  }),
145
150
  ]);
146
151
  };
@@ -1,4 +1,4 @@
1
- import { LambdaPayload } from '../shared/constants';
1
+ import type { LambdaPayload } from '../shared/constants';
2
2
  export declare const startHandler: (params: LambdaPayload) => Promise<{
3
3
  bucketName: string;
4
4
  renderId: string;
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.startHandler = void 0;
4
4
  const client_lambda_1 = require("@aws-sdk/client-lambda");
5
- const remotion_1 = require("remotion");
6
5
  const get_or_create_bucket_1 = require("../api/get-or-create-bucket");
7
6
  const aws_clients_1 = require("../shared/aws-clients");
8
7
  const constants_1 = require("../shared/constants");
@@ -34,12 +33,16 @@ const startHandler = async (params) => {
34
33
  quality: params.quality,
35
34
  maxRetries: params.maxRetries,
36
35
  privacy: params.privacy,
37
- logLevel: (_a = params.logLevel) !== null && _a !== void 0 ? _a : remotion_1.Internals.Logging.DEFAULT_LOG_LEVEL,
36
+ logLevel: (_a = params.logLevel) !== null && _a !== void 0 ? _a : 'info',
38
37
  frameRange: params.frameRange,
39
38
  outName: params.outName,
40
39
  timeoutInMilliseconds: params.timeoutInMilliseconds,
41
40
  chromiumOptions: params.chromiumOptions,
42
41
  scale: params.scale,
42
+ numberOfGifLoops: params.numberOfGifLoops,
43
+ everyNthFrame: params.everyNthFrame,
44
+ concurrencyPerLambda: params.concurrencyPerLambda,
45
+ downloadBehavior: params.downloadBehavior,
43
46
  };
44
47
  await (0, aws_clients_1.getLambdaClient)((0, get_current_region_1.getCurrentRegionInFunction)()).send(new client_lambda_1.InvokeCommand({
45
48
  FunctionName: process.env.AWS_LAMBDA_FUNCTION_NAME,
@@ -1,4 +1,4 @@
1
- import { LambdaPayload } from '../shared/constants';
1
+ import type { LambdaPayload } from '../shared/constants';
2
2
  declare type Options = {
3
3
  expectedBucketOwner: string;
4
4
  };
@@ -8,13 +8,13 @@ const client_lambda_1 = require("@aws-sdk/client-lambda");
8
8
  const renderer_1 = require("@remotion/renderer");
9
9
  const fs_1 = __importDefault(require("fs"));
10
10
  const path_1 = __importDefault(require("path"));
11
- const remotion_1 = require("remotion");
12
11
  const estimate_price_1 = require("../api/estimate-price");
13
12
  const get_or_create_bucket_1 = require("../api/get-or-create-bucket");
14
13
  const aws_clients_1 = require("../shared/aws-clients");
15
14
  const constants_1 = require("../shared/constants");
16
15
  const make_s3_url_1 = require("../shared/make-s3-url");
17
16
  const random_hash_1 = require("../shared/random-hash");
17
+ const validate_download_behavior_1 = require("../shared/validate-download-behavior");
18
18
  const validate_outname_1 = require("../shared/validate-outname");
19
19
  const validate_privacy_1 = require("../shared/validate-privacy");
20
20
  const expected_out_name_1 = require("./helpers/expected-out-name");
@@ -27,10 +27,11 @@ const io_1 = require("./helpers/io");
27
27
  const validate_composition_1 = require("./helpers/validate-composition");
28
28
  const write_lambda_error_1 = require("./helpers/write-lambda-error");
29
29
  const innerStillHandler = async (lambdaParams, renderId, options) => {
30
- var _a, _b, _c;
30
+ var _a, _b;
31
31
  if (lambdaParams.type !== constants_1.LambdaRoutines.still) {
32
32
  throw new TypeError('Expected still type');
33
33
  }
34
+ (0, validate_download_behavior_1.validateDownloadBehavior)(lambdaParams.downloadBehavior);
34
35
  (0, validate_privacy_1.validatePrivacy)(lambdaParams.privacy);
35
36
  (0, validate_outname_1.validateOutname)(lambdaParams.outName);
36
37
  const start = Date.now();
@@ -38,7 +39,7 @@ const innerStillHandler = async (lambdaParams, renderId, options) => {
38
39
  (0, get_or_create_bucket_1.getOrCreateBucket)({
39
40
  region: (0, get_current_region_1.getCurrentRegionInFunction)(),
40
41
  }),
41
- (0, get_browser_instance_1.getBrowserInstance)(remotion_1.Internals.Logging.isEqualOrBelowLogLevel((_a = lambdaParams.logLevel) !== null && _a !== void 0 ? _a : remotion_1.Internals.Logging.DEFAULT_LOG_LEVEL, 'verbose'), (_b = lambdaParams.chromiumOptions) !== null && _b !== void 0 ? _b : {}),
42
+ (0, get_browser_instance_1.getBrowserInstance)(renderer_1.RenderInternals.isEqualOrBelowLogLevel(lambdaParams.logLevel, 'verbose'), (_a = lambdaParams.chromiumOptions) !== null && _a !== void 0 ? _a : {}),
42
43
  ]);
43
44
  const outputDir = renderer_1.RenderInternals.tmpDir('remotion-render-');
44
45
  const outputPath = path_1.default.join(outputDir, 'output');
@@ -49,6 +50,7 @@ const innerStillHandler = async (lambdaParams, renderId, options) => {
49
50
  inputProps: lambdaParams.inputProps,
50
51
  envVariables: lambdaParams.envVariables,
51
52
  ffmpegExecutable: null,
53
+ ffprobeExecutable: null,
52
54
  chromiumOptions: lambdaParams.chromiumOptions,
53
55
  timeoutInMilliseconds: lambdaParams.timeoutInMilliseconds,
54
56
  port: null,
@@ -71,7 +73,7 @@ const innerStillHandler = async (lambdaParams, renderId, options) => {
71
73
  memorySizeInMb: Number(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE),
72
74
  region: (0, get_current_region_1.getCurrentRegionInFunction)(),
73
75
  renderId,
74
- outName: (_c = lambdaParams.outName) !== null && _c !== void 0 ? _c : undefined,
76
+ outName: (_b = lambdaParams.outName) !== null && _b !== void 0 ? _b : undefined,
75
77
  };
76
78
  await (0, io_1.lambdaWriteFile)({
77
79
  bucketName,
@@ -80,6 +82,7 @@ const innerStillHandler = async (lambdaParams, renderId, options) => {
80
82
  region: (0, get_current_region_1.getCurrentRegionInFunction)(),
81
83
  privacy: 'private',
82
84
  expectedBucketOwner: options.expectedBucketOwner,
85
+ downloadBehavior: null,
83
86
  });
84
87
  await (0, renderer_1.renderStill)({
85
88
  composition,
@@ -97,15 +100,16 @@ const innerStillHandler = async (lambdaParams, renderId, options) => {
97
100
  scale: lambdaParams.scale,
98
101
  timeoutInMilliseconds: lambdaParams.timeoutInMilliseconds,
99
102
  });
100
- const { key: outName, renderBucketName } = (0, expected_out_name_1.getExpectedOutName)(renderMetadata, bucketName);
103
+ const { key, renderBucketName } = (0, expected_out_name_1.getExpectedOutName)(renderMetadata, bucketName);
101
104
  const { size } = await fs_1.default.promises.stat(outputPath);
102
105
  await (0, io_1.lambdaWriteFile)({
103
106
  bucketName: renderBucketName,
104
- key: outName,
107
+ key,
105
108
  privacy: lambdaParams.privacy,
106
109
  body: fs_1.default.createReadStream(outputPath),
107
110
  expectedBucketOwner: options.expectedBucketOwner,
108
111
  region: (0, get_current_region_1.getCurrentRegionInFunction)(),
112
+ downloadBehavior: lambdaParams.downloadBehavior,
109
113
  });
110
114
  await fs_1.default.promises.rm(outputPath, { recursive: true });
111
115
  const estimatedPrice = (0, estimate_price_1.estimatePrice)({
package/dist/index.d.ts CHANGED
@@ -1,25 +1,40 @@
1
- import { deleteFunction, DeleteFunctionInput } from './api/delete-function';
2
- import { deleteSite, DeleteSiteInput, DeleteSiteOutput } from './api/delete-site';
3
- import { deployFunction, DeployFunctionInput, DeployFunctionOutput } from './api/deploy-function';
4
- import { deploySite, DeploySiteInput, DeploySiteOutput } from './api/deploy-site';
5
- import { downloadMedia, DownloadMediaInput, DownloadMediaOutput, downloadVideo } from './api/download-media';
6
- import { estimatePrice, EstimatePriceInput } from './api/estimate-price';
7
- import { getAwsClient, GetAwsClientInput, GetAwsClientOutput } from './api/get-aws-client';
8
- import { FunctionInfo, getFunctionInfo, GetFunctionInfoInput } from './api/get-function-info';
9
- import { getFunctions, GetFunctionsInput } from './api/get-functions';
10
- import { getOrCreateBucket, GetOrCreateBucketInput, GetOrCreateBucketOutput } from './api/get-or-create-bucket';
1
+ import type { DeleteFunctionInput } from './api/delete-function';
2
+ import { deleteFunction } from './api/delete-function';
3
+ import type { DeleteSiteInput, DeleteSiteOutput } from './api/delete-site';
4
+ import { deleteSite } from './api/delete-site';
5
+ import type { DeployFunctionInput, DeployFunctionOutput } from './api/deploy-function';
6
+ import { deployFunction } from './api/deploy-function';
7
+ import type { DeploySiteInput, DeploySiteOutput } from './api/deploy-site';
8
+ import { deploySite } from './api/deploy-site';
9
+ import type { DownloadMediaInput, DownloadMediaOutput } from './api/download-media';
10
+ import { downloadMedia, downloadVideo } from './api/download-media';
11
+ import type { EstimatePriceInput } from './api/estimate-price';
12
+ import { estimatePrice } from './api/estimate-price';
13
+ import type { GetAwsClientInput, GetAwsClientOutput } from './api/get-aws-client';
14
+ import { getAwsClient } from './api/get-aws-client';
15
+ import type { FunctionInfo, GetFunctionInfoInput } from './api/get-function-info';
16
+ import { getFunctionInfo } from './api/get-function-info';
17
+ import type { GetFunctionsInput } from './api/get-functions';
18
+ import { getFunctions } from './api/get-functions';
19
+ import type { GetOrCreateBucketInput, GetOrCreateBucketOutput } from './api/get-or-create-bucket';
20
+ import { getOrCreateBucket } from './api/get-or-create-bucket';
11
21
  import { getRegions } from './api/get-regions';
12
- import { GetRenderInput, getRenderProgress } from './api/get-render-progress';
13
- import { getSites, GetSitesInput, GetSitesOutput } from './api/get-sites';
14
- import { simulatePermissions, SimulatePermissionsInput, SimulatePermissionsOutput } from './api/iam-validation/simulate';
22
+ import type { GetRenderInput } from './api/get-render-progress';
23
+ import { getRenderProgress } from './api/get-render-progress';
24
+ import type { GetSitesInput, GetSitesOutput } from './api/get-sites';
25
+ import { getSites } from './api/get-sites';
26
+ import type { SimulatePermissionsInput, SimulatePermissionsOutput } from './api/iam-validation/simulate';
27
+ import { simulatePermissions } from './api/iam-validation/simulate';
15
28
  import { getRolePolicy, getUserPolicy } from './api/iam-validation/suggested-policy';
16
29
  import { presignUrl } from './api/presign-url';
17
- import { renderMediaOnLambda, RenderMediaOnLambdaInput, RenderMediaOnLambdaOutput, renderVideoOnLambda } from './api/render-media-on-lambda';
18
- import { renderStillOnLambda, RenderStillOnLambdaInput, RenderStillOnLambdaOutput } from './api/render-still-on-lambda';
19
- import { LambdaLSInput, LambdaLsReturnType } from './functions/helpers/io';
30
+ import type { RenderMediaOnLambdaInput, RenderMediaOnLambdaOutput } from './api/render-media-on-lambda';
31
+ import { renderMediaOnLambda, renderVideoOnLambda } from './api/render-media-on-lambda';
32
+ import type { RenderStillOnLambdaInput, RenderStillOnLambdaOutput } from './api/render-still-on-lambda';
33
+ import { renderStillOnLambda } from './api/render-still-on-lambda';
34
+ import type { LambdaLSInput, LambdaLsReturnType } from './functions/helpers/io';
20
35
  import { LambdaInternals } from './internals';
21
- import { AwsRegion } from './pricing/aws-regions';
36
+ import type { AwsRegion } from './pricing/aws-regions';
22
37
  import type { RenderProgress } from './shared/constants';
23
- import { LambdaArchitecture } from './shared/validate-architecture';
38
+ import type { LambdaArchitecture } from './shared/validate-architecture';
24
39
  export { deleteSite, deployFunction, deploySite, downloadMedia, downloadVideo, getFunctions, getUserPolicy, getRolePolicy, getSites, getOrCreateBucket, getRenderProgress, renderVideoOnLambda, renderMediaOnLambda, simulatePermissions, deleteFunction, getFunctionInfo, estimatePrice, LambdaInternals, renderStillOnLambda, getRegions, getAwsClient, presignUrl, };
25
40
  export type { AwsRegion, RenderProgress, DeploySiteInput, DeploySiteOutput, LambdaLsReturnType, LambdaLSInput, DeleteSiteInput, DeleteSiteOutput, EstimatePriceInput, DeployFunctionInput, DeployFunctionOutput, DeleteFunctionInput, GetFunctionInfoInput, FunctionInfo, GetFunctionsInput, GetSitesInput, GetSitesOutput, DownloadMediaInput, DownloadMediaOutput, GetOrCreateBucketInput, GetOrCreateBucketOutput, GetRenderInput, RenderMediaOnLambdaInput, RenderMediaOnLambdaOutput, RenderStillOnLambdaInput, RenderStillOnLambdaOutput, SimulatePermissionsInput, SimulatePermissionsOutput, GetAwsClientInput, GetAwsClientOutput, LambdaArchitecture, };
@@ -1,4 +1,4 @@
1
- import { AwsRegion } from './aws-regions';
1
+ import type { AwsRegion } from './aws-regions';
2
2
  export declare const pricing: {
3
3
  [key in AwsRegion]: {
4
4
  'Lambda Duration': {
@@ -3,7 +3,7 @@ import { IAMClient } from '@aws-sdk/client-iam';
3
3
  import { LambdaClient } from '@aws-sdk/client-lambda';
4
4
  import { S3Client } from '@aws-sdk/client-s3';
5
5
  import { ServiceQuotasClient } from '@aws-sdk/client-service-quotas';
6
- import { AwsRegion } from '../pricing/aws-regions';
6
+ import type { AwsRegion } from '../pricing/aws-regions';
7
7
  export declare type ServiceMapping = {
8
8
  s3: S3Client;
9
9
  cloudwatch: CloudWatchLogsClient;
@@ -1,6 +1 @@
1
- export declare const bundleSite: (entryPoint: string, onProgressUpdate?: ((progress: number) => void) | undefined, options?: {
2
- webpackOverride?: import("remotion").WebpackOverrideFn | undefined;
3
- outDir?: string | undefined;
4
- enableCaching?: boolean | undefined;
5
- publicPath?: string | undefined;
6
- } | undefined) => Promise<string>;
1
+ export declare const bundleSite: (entryPoint: string, onProgressUpdate?: ((progress: number) => void) | undefined, options?: import("@remotion/bundler").BundleOptions | undefined) => Promise<string>;
@@ -1,6 +1,6 @@
1
- import { AwsRegion } from '../pricing/aws-regions';
2
- import { LambdaPayloads, LambdaRoutines } from './constants';
3
- import { LambdaReturnValues } from './return-values';
1
+ import type { AwsRegion } from '../pricing/aws-regions';
2
+ import type { LambdaPayloads, LambdaRoutines } from './constants';
3
+ import type { LambdaReturnValues } from './return-values';
4
4
  export declare const callLambda: <T extends LambdaRoutines>({ functionName, type, payload, region, }: {
5
5
  functionName: string;
6
6
  type: T;
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.checkCredentials = void 0;
4
- const remotion_1 = require("remotion");
5
4
  const is_cli_1 = require("../cli/is-cli");
6
5
  const docs_url_1 = require("./docs-url");
6
+ const truthy_1 = require("./truthy");
7
7
  const messageForVariable = (variable) => {
8
8
  return [
9
9
  `You have tried to call a Remotion Lambda function, but have not set the environment variable ${variable}.`,
@@ -13,7 +13,7 @@ const messageForVariable = (variable) => {
13
13
  `- Please refer to the Remotion Lambda docs (${docs_url_1.DOCS_URL}/docs/lambda/setup) to see how to generate the credentials for your AWS account and then set the environment variables.`,
14
14
  `- For more reasons see the troubleshooting page: ${docs_url_1.DOCS_URL}/docs/lambda/troubleshooting/permissions`,
15
15
  ]
16
- .filter(remotion_1.Internals.truthy)
16
+ .filter(truthy_1.truthy)
17
17
  .join('\n');
18
18
  };
19
19
  const checkCredentials = () => {
@@ -1,9 +1,12 @@
1
- import { ChromiumOptions } from '@remotion/renderer';
2
- import { Codec, FrameRange, ImageFormat, LogLevel, PixelFormat, ProResProfile, VideoConfig } from 'remotion';
3
- import { ChunkRetry } from '../functions/helpers/get-retry-stats';
4
- import { EnhancedErrorInfo } from '../functions/helpers/write-lambda-error';
5
- import { AwsRegion } from '../pricing/aws-regions';
6
- import { LambdaArchitecture } from './validate-architecture';
1
+ import type { ChromiumOptions, Codec, FrameRange, ImageFormat, LogLevel, PixelFormat, ProResProfile } from '@remotion/renderer';
2
+ import type { VideoConfig } from 'remotion';
3
+ import type { ChunkRetry } from '../functions/helpers/get-retry-stats';
4
+ import type { EnhancedErrorInfo } from '../functions/helpers/write-lambda-error';
5
+ import type { AwsRegion } from '../pricing/aws-regions';
6
+ import type { DownloadBehavior } from './content-disposition-header';
7
+ import type { ExpensiveChunk } from './get-most-expensive-chunks';
8
+ import type { LambdaArchitecture } from './validate-architecture';
9
+ import type { LambdaCodec } from './validate-lambda-codec';
7
10
  export declare const MIN_MEMORY = 512;
8
11
  export declare const MAX_MEMORY = 10240;
9
12
  export declare const DEFAULT_MEMORY_SIZE = 2048;
@@ -91,7 +94,7 @@ export declare type LambdaPayloads = {
91
94
  composition: string;
92
95
  framesPerLambda: number | null;
93
96
  inputProps: unknown;
94
- codec: Codec;
97
+ codec: LambdaCodec;
95
98
  imageFormat: ImageFormat;
96
99
  crf: number | undefined;
97
100
  envVariables: Record<string, string> | undefined;
@@ -106,6 +109,10 @@ export declare type LambdaPayloads = {
106
109
  timeoutInMilliseconds: number;
107
110
  chromiumOptions: ChromiumOptions;
108
111
  scale: number;
112
+ everyNthFrame: number;
113
+ numberOfGifLoops: number | null;
114
+ concurrencyPerLambda: number;
115
+ downloadBehavior: DownloadBehavior;
109
116
  };
110
117
  launch: {
111
118
  type: LambdaRoutines.launch;
@@ -116,7 +123,7 @@ export declare type LambdaPayloads = {
116
123
  inputProps: unknown;
117
124
  renderId: string;
118
125
  imageFormat: ImageFormat;
119
- codec: Codec;
126
+ codec: LambdaCodec;
120
127
  crf: number | undefined;
121
128
  envVariables: Record<string, string> | undefined;
122
129
  pixelFormat: PixelFormat | undefined;
@@ -130,6 +137,10 @@ export declare type LambdaPayloads = {
130
137
  timeoutInMilliseconds: number;
131
138
  chromiumOptions: ChromiumOptions;
132
139
  scale: number;
140
+ everyNthFrame: number;
141
+ numberOfGifLoops: number | null;
142
+ concurrencyPerLambda: number;
143
+ downloadBehavior: DownloadBehavior;
133
144
  };
134
145
  status: {
135
146
  type: LambdaRoutines.status;
@@ -137,6 +148,7 @@ export declare type LambdaPayloads = {
137
148
  renderId: string;
138
149
  };
139
150
  renderer: {
151
+ concurrencyPerLambda: number;
140
152
  type: LambdaRoutines.renderer;
141
153
  serveUrl: string;
142
154
  frameRange: [number, number];
@@ -151,7 +163,7 @@ export declare type LambdaPayloads = {
151
163
  inputProps: unknown;
152
164
  renderId: string;
153
165
  imageFormat: ImageFormat;
154
- codec: Codec;
166
+ codec: Exclude<Codec, 'h264'>;
155
167
  crf: number | undefined;
156
168
  proResProfile: ProResProfile | undefined;
157
169
  pixelFormat: PixelFormat | undefined;
@@ -163,6 +175,7 @@ export declare type LambdaPayloads = {
163
175
  timeoutInMilliseconds: number;
164
176
  chromiumOptions: ChromiumOptions;
165
177
  scale: number;
178
+ everyNthFrame: number;
166
179
  };
167
180
  still: {
168
181
  type: LambdaRoutines.still;
@@ -177,10 +190,11 @@ export declare type LambdaPayloads = {
177
190
  frame: number;
178
191
  privacy: Privacy;
179
192
  logLevel: LogLevel;
180
- outName: string | null;
193
+ outName: OutNameInput | null;
181
194
  timeoutInMilliseconds: number;
182
195
  chromiumOptions: ChromiumOptions;
183
196
  scale: number;
197
+ downloadBehavior: DownloadBehavior | null;
184
198
  };
185
199
  };
186
200
  export declare type LambdaPayload = LambdaPayloads[LambdaRoutines];
@@ -210,7 +224,7 @@ export declare type RenderMetadata = {
210
224
  renderId: string;
211
225
  outName: OutNameInput | undefined;
212
226
  };
213
- export declare type LambdaVersions = '2022-05-27' | '2022-05-19' | '2022-05-16' | '2022-05-11' | '2022-05-07' | '2022-05-06' | '2022-05-03' | '2022-04-20' | '2022-04-19' | '2022-04-18' | '2022-04-09' | '2022-04-08' | '2022-04-05' | '2022-04-02' | '2022-03-29' | '2022-03-17' | '2022-03-02' | '2022-03-01' | '2022-02-27' | '2022-02-14' | '2022-02-12' | '2022-02-09' | '2022-02-08' | '2022-02-07' | '2022-02-06' | '2022-02-05' | '2022-02-04' | '2022-02-03' | '2022-01-23' | '2022-01-19' | '2022-01-11' | '2022-01-10' | '2022-01-09' | '2022-01-06' | '2022-01-05' | '2021-12-22' | '2021-12-17' | '2021-12-16' | '2021-12-15' | '2021-12-14' | '2021-12-13' | '2021-12-11' | '2021-12-10' | '2021-12-04' | '2021-11-29' | '2021-11-27' | '2021-11-24' | '2021-11-22' | '2021-11-19' | '2021-11-18' | '2021-11-15' | '2021-11-12' | '2021-11-10' | '2021-11-01' | '2021-10-29' | '2021-10-27' | '2021-10-21' | '2021-10-19' | '2021-10-07' | '2021-10-03' | '2021-10-01' | '2021-09-15' | '2021-09-06' | '2021-08-06' | '2021-07-14' | '2021-07-05' | '2021-07-02' | '2021-06-23' | 'n/a';
227
+ export declare type LambdaVersions = '2022-07-25' | '2022-07-23' | '2022-07-20' | '2022-07-18' | '2022-07-15' | '2022-07-14' | '2022-07-12' | '2022-07-10' | '2022-07-09' | '2022-07-08' | '2022-07-04' | '2022-06-30' | '2022-06-29' | '2022-06-25' | '2022-06-22' | '2022-06-21' | '2022-06-14' | '2022-06-08' | '2022-06-07' | '2022-06-02' | '2022-05-31' | '2022-05-28' | '2022-05-27' | '2022-05-19' | '2022-05-16' | '2022-05-11' | '2022-05-07' | '2022-05-06' | '2022-05-03' | '2022-04-20' | '2022-04-19' | '2022-04-18' | '2022-04-09' | '2022-04-08' | '2022-04-05' | '2022-04-02' | '2022-03-29' | '2022-03-17' | '2022-03-02' | '2022-03-01' | '2022-02-27' | '2022-02-14' | '2022-02-12' | '2022-02-09' | '2022-02-08' | '2022-02-07' | '2022-02-06' | '2022-02-05' | '2022-02-04' | '2022-02-03' | '2022-01-23' | '2022-01-19' | '2022-01-11' | '2022-01-10' | '2022-01-09' | '2022-01-06' | '2022-01-05' | '2021-12-22' | '2021-12-17' | '2021-12-16' | '2021-12-15' | '2021-12-14' | '2021-12-13' | '2021-12-11' | '2021-12-10' | '2021-12-04' | '2021-11-29' | '2021-11-27' | '2021-11-24' | '2021-11-22' | '2021-11-19' | '2021-11-18' | '2021-11-15' | '2021-11-12' | '2021-11-10' | '2021-11-01' | '2021-10-29' | '2021-10-27' | '2021-10-21' | '2021-10-19' | '2021-10-07' | '2021-10-03' | '2021-10-01' | '2021-09-15' | '2021-09-06' | '2021-08-06' | '2021-07-14' | '2021-07-05' | '2021-07-02' | '2021-06-23' | 'n/a';
214
228
  export declare const CURRENT_VERSION: LambdaVersions;
215
229
  export declare type PostRenderData = {
216
230
  cost: {
@@ -233,6 +247,7 @@ export declare type PostRenderData = {
233
247
  timeToRenderChunks: number;
234
248
  timeToInvokeLambdas: number;
235
249
  retriesInfo: ChunkRetry[];
250
+ mostExpensiveFrameRanges: ExpensiveChunk[] | undefined;
236
251
  };
237
252
  export declare type CostsInfo = {
238
253
  accruedSoFar: number;
@@ -267,6 +282,7 @@ export declare type RenderProgress = {
267
282
  timeToInvokeLambdas: number | null;
268
283
  overallProgress: number;
269
284
  retriesInfo: ChunkRetry[];
285
+ mostExpensiveFrameRanges: ExpensiveChunk[] | null;
270
286
  };
271
287
  export declare type Privacy = 'public' | 'private';
272
288
  export declare const LAMBDA_CONCURRENCY_LIMIT_QUOTA = "L-B99A9384";
@@ -84,6 +84,6 @@ var LambdaRoutines;
84
84
  LambdaRoutines["renderer"] = "renderer";
85
85
  LambdaRoutines["still"] = "still";
86
86
  })(LambdaRoutines = exports.LambdaRoutines || (exports.LambdaRoutines = {}));
87
- exports.CURRENT_VERSION = '2022-05-27';
87
+ exports.CURRENT_VERSION = '2022-07-25';
88
88
  exports.LAMBDA_CONCURRENCY_LIMIT_QUOTA = 'L-B99A9384';
89
89
  exports.LAMBDA_BURST_LIMIT_QUOTA = 'L-548AE339';
@@ -0,0 +1,7 @@
1
+ export declare type DownloadBehavior = {
2
+ type: 'play-in-browser';
3
+ } | {
4
+ type: 'download';
5
+ fileName: string | null;
6
+ };
7
+ export declare const getContentDispositionHeader: (behavior: DownloadBehavior | null) => string | undefined;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ // By setting the Content-Disposition header in an S3 object,
3
+ // you can control if the user downloads the item if you
4
+ // visit the link
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getContentDispositionHeader = void 0;
7
+ const getContentDispositionHeader = (behavior) => {
8
+ if (behavior === null) {
9
+ return undefined;
10
+ }
11
+ if (behavior.type === 'play-in-browser') {
12
+ return undefined;
13
+ }
14
+ if (behavior.fileName === null) {
15
+ return `attachment`;
16
+ }
17
+ return `attachment; filename="${behavior.fileName}"`;
18
+ };
19
+ exports.getContentDispositionHeader = getContentDispositionHeader;
@@ -1,2 +1,2 @@
1
- import { AwsRegion } from '../pricing/aws-regions';
1
+ import type { AwsRegion } from '../pricing/aws-regions';
2
2
  export declare const convertToServeUrl: (urlOrId: string, region: AwsRegion) => Promise<string>;
@@ -1,4 +1,4 @@
1
- import { AwsRegion } from '../pricing/aws-regions';
1
+ import type { AwsRegion } from '../pricing/aws-regions';
2
2
  export declare const getAccountId: (options: {
3
3
  region: AwsRegion;
4
4
  }) => Promise<string>;
@@ -1,5 +1,5 @@
1
- import { AwsRegion } from '../pricing/aws-regions';
2
- import { LambdaVersions } from './constants';
1
+ import type { AwsRegion } from '../pricing/aws-regions';
2
+ import type { LambdaVersions } from './constants';
3
3
  export declare const getFunctionVersion: ({ functionName, region, }: {
4
4
  functionName: string;
5
5
  region: AwsRegion;
@@ -0,0 +1,8 @@
1
+ import type { ParsedTiming } from './parse-lambda-timings-key';
2
+ export declare const OVERHEAD_TIME_PER_LAMBDA = 100;
3
+ export declare type ExpensiveChunk = {
4
+ chunk: number;
5
+ frameRange: [number, number];
6
+ timeInMilliseconds: number;
7
+ };
8
+ export declare const getMostExpensiveChunks: (parsedTimings: ParsedTiming[], framesPerLambda: number) => ExpensiveChunk[];
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getMostExpensiveChunks = exports.OVERHEAD_TIME_PER_LAMBDA = void 0;
4
+ exports.OVERHEAD_TIME_PER_LAMBDA = 100;
5
+ const getMostExpensiveChunks = (parsedTimings, framesPerLambda) => {
6
+ const mostExpensiveChunks = parsedTimings
7
+ .slice(0)
8
+ .sort((a, b) => {
9
+ const durA = a.rendered - a.start;
10
+ const durB = b.rendered - b.start;
11
+ return durB - durA;
12
+ })
13
+ .slice(0, 5);
14
+ return mostExpensiveChunks.map((c) => {
15
+ return {
16
+ timeInMilliseconds: c.rendered - c.start,
17
+ chunk: c.chunk,
18
+ frameRange: [
19
+ framesPerLambda * c.chunk,
20
+ framesPerLambda * (c.chunk + 1) - 1,
21
+ ],
22
+ };
23
+ });
24
+ };
25
+ exports.getMostExpensiveChunks = getMostExpensiveChunks;
@@ -1,5 +1,5 @@
1
- import { AwsRegion } from '../pricing/aws-regions';
2
- import { LambdaArchitecture } from './validate-architecture';
1
+ import type { AwsRegion } from '../pricing/aws-regions';
2
+ import type { LambdaArchitecture } from './validate-architecture';
3
3
  export declare const REMOTION_HOSTED_LAYER_ARN = "arn:aws:lambda:*:678892195805:layer:remotion-binaries-*";
4
4
  export declare type HostedLayers = {
5
5
  [architecture in LambdaArchitecture]: {