@vercel/build-utils 14.6.1 → 14.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @vercel/build-utils
2
2
 
3
+ ## 14.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a652a99: Propagate top-level `schedules` from vercel.json into the Build Output API `config.json` during `vercel build`, and validate the property against the schedules schema
8
+
9
+ ## 14.7.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 37ff9da: Add build type to deploy manifest.
14
+
15
+ ### Patch Changes
16
+
17
+ - 26b891e: Accept `schedule/v1beta` triggers in the `Lambda` runtime validation and the functions config schema
18
+
3
19
  ## 14.6.1
4
20
 
5
21
  ### Patch Changes
package/dist/index.js CHANGED
@@ -35182,61 +35182,63 @@ var Lambda = class {
35182
35182
  `${prefix} is not an object`
35183
35183
  );
35184
35184
  (0, import_assert4.default)(
35185
- trigger.type === "queue/v1beta" || trigger.type === "queue/v2beta",
35186
- `${prefix}.type must be "queue/v1beta" or "queue/v2beta"`
35185
+ trigger.type === "queue/v1beta" || trigger.type === "queue/v2beta" || trigger.type === "schedule/v1beta",
35186
+ `${prefix}.type must be "queue/v1beta", "queue/v2beta", or "schedule/v1beta"`
35187
35187
  );
35188
- (0, import_assert4.default)(
35189
- typeof trigger.topic === "string",
35190
- `${prefix}.topic is required and must be a string`
35191
- );
35192
- (0, import_assert4.default)(trigger.topic.length > 0, `${prefix}.topic cannot be empty`);
35193
- (0, import_assert4.default)(
35194
- typeof trigger.consumer === "string",
35195
- `${prefix}.consumer is required and must be a string`
35196
- );
35197
- (0, import_assert4.default)(
35198
- trigger.consumer.length > 0,
35199
- `${prefix}.consumer cannot be empty`
35200
- );
35201
- if (trigger.maxDeliveries !== void 0) {
35188
+ if (trigger.type === "queue/v1beta" || trigger.type === "queue/v2beta") {
35202
35189
  (0, import_assert4.default)(
35203
- typeof trigger.maxDeliveries === "number",
35204
- `${prefix}.maxDeliveries must be a number`
35190
+ typeof trigger.topic === "string",
35191
+ `${prefix}.topic is required and must be a string`
35205
35192
  );
35193
+ (0, import_assert4.default)(trigger.topic.length > 0, `${prefix}.topic cannot be empty`);
35206
35194
  (0, import_assert4.default)(
35207
- Number.isInteger(trigger.maxDeliveries) && trigger.maxDeliveries >= 1,
35208
- `${prefix}.maxDeliveries must be at least 1`
35195
+ typeof trigger.consumer === "string",
35196
+ `${prefix}.consumer is required and must be a string`
35209
35197
  );
35210
- }
35211
- if (trigger.retryAfterSeconds !== void 0) {
35212
- (0, import_assert4.default)(
35213
- typeof trigger.retryAfterSeconds === "number",
35214
- `${prefix}.retryAfterSeconds must be a number`
35215
- );
35216
- (0, import_assert4.default)(
35217
- trigger.retryAfterSeconds > 0,
35218
- `${prefix}.retryAfterSeconds must be a positive number`
35219
- );
35220
- }
35221
- if (trigger.initialDelaySeconds !== void 0) {
35222
35198
  (0, import_assert4.default)(
35223
- typeof trigger.initialDelaySeconds === "number",
35224
- `${prefix}.initialDelaySeconds must be a number`
35225
- );
35226
- (0, import_assert4.default)(
35227
- trigger.initialDelaySeconds >= 0,
35228
- `${prefix}.initialDelaySeconds must be a non-negative number`
35229
- );
35230
- }
35231
- if (trigger.maxConcurrency !== void 0) {
35232
- (0, import_assert4.default)(
35233
- typeof trigger.maxConcurrency === "number",
35234
- `${prefix}.maxConcurrency must be a number`
35235
- );
35236
- (0, import_assert4.default)(
35237
- Number.isInteger(trigger.maxConcurrency) && trigger.maxConcurrency >= 1,
35238
- `${prefix}.maxConcurrency must be at least 1`
35199
+ trigger.consumer.length > 0,
35200
+ `${prefix}.consumer cannot be empty`
35239
35201
  );
35202
+ if (trigger.maxDeliveries !== void 0) {
35203
+ (0, import_assert4.default)(
35204
+ typeof trigger.maxDeliveries === "number",
35205
+ `${prefix}.maxDeliveries must be a number`
35206
+ );
35207
+ (0, import_assert4.default)(
35208
+ Number.isInteger(trigger.maxDeliveries) && trigger.maxDeliveries >= 1,
35209
+ `${prefix}.maxDeliveries must be at least 1`
35210
+ );
35211
+ }
35212
+ if (trigger.retryAfterSeconds !== void 0) {
35213
+ (0, import_assert4.default)(
35214
+ typeof trigger.retryAfterSeconds === "number",
35215
+ `${prefix}.retryAfterSeconds must be a number`
35216
+ );
35217
+ (0, import_assert4.default)(
35218
+ trigger.retryAfterSeconds > 0,
35219
+ `${prefix}.retryAfterSeconds must be a positive number`
35220
+ );
35221
+ }
35222
+ if (trigger.initialDelaySeconds !== void 0) {
35223
+ (0, import_assert4.default)(
35224
+ typeof trigger.initialDelaySeconds === "number",
35225
+ `${prefix}.initialDelaySeconds must be a number`
35226
+ );
35227
+ (0, import_assert4.default)(
35228
+ trigger.initialDelaySeconds >= 0,
35229
+ `${prefix}.initialDelaySeconds must be a non-negative number`
35230
+ );
35231
+ }
35232
+ if (trigger.maxConcurrency !== void 0) {
35233
+ (0, import_assert4.default)(
35234
+ typeof trigger.maxConcurrency === "number",
35235
+ `${prefix}.maxConcurrency must be a number`
35236
+ );
35237
+ (0, import_assert4.default)(
35238
+ Number.isInteger(trigger.maxConcurrency) && trigger.maxConcurrency >= 1,
35239
+ `${prefix}.maxConcurrency must be at least 1`
35240
+ );
35241
+ }
35240
35242
  }
35241
35243
  }
35242
35244
  }
@@ -38500,8 +38502,23 @@ var triggerEventSchemaV2 = {
38500
38502
  required: ["type", "topic"],
38501
38503
  additionalProperties: false
38502
38504
  };
38505
+ var scheduleTriggerEventSchemaV1 = {
38506
+ type: "object",
38507
+ properties: {
38508
+ type: {
38509
+ type: "string",
38510
+ const: "schedule/v1beta"
38511
+ }
38512
+ },
38513
+ required: ["type"],
38514
+ additionalProperties: false
38515
+ };
38503
38516
  var triggerEventSchema = {
38504
- oneOf: [triggerEventSchemaV1, triggerEventSchemaV2]
38517
+ oneOf: [
38518
+ triggerEventSchemaV1,
38519
+ triggerEventSchemaV2,
38520
+ scheduleTriggerEventSchemaV1
38521
+ ]
38505
38522
  };
38506
38523
  var getFunctionsSchema = () => ({
38507
38524
  type: "object",
@@ -38615,7 +38632,12 @@ var packageManifestSchema = {
38615
38632
  },
38616
38633
  serviceType: {
38617
38634
  type: "string",
38618
- description: 'Service type: one of "web", "schedule", "queue", "workflow".'
38635
+ description: 'Deployment topology for service builds: "web", "schedule", "queue", or "workflow".'
38636
+ },
38637
+ buildType: {
38638
+ type: "string",
38639
+ enum: ["app", "api-dir", "middleware"],
38640
+ description: 'What triggered this build: "app" (full application build), "api-dir" (api/ directory build), or "middleware" (middleware build).'
38619
38641
  },
38620
38642
  runtimeVersion: {
38621
38643
  type: "object",
@@ -39059,8 +39081,21 @@ async function generateProjectManifest({
39059
39081
  }) {
39060
39082
  try {
39061
39083
  const pkgJson = await readPackageJson(workPath);
39062
- if (!pkgJson)
39084
+ if (!pkgJson) {
39085
+ await writeProjectManifest(
39086
+ {
39087
+ version: MANIFEST_VERSION,
39088
+ runtime: "node",
39089
+ ...framework ? { framework } : {},
39090
+ ...serviceType ? { serviceType } : {},
39091
+ runtimeVersion: { resolved: String(nodeVersion.major) },
39092
+ dependencies: []
39093
+ },
39094
+ workPath,
39095
+ outputRuntime
39096
+ );
39063
39097
  return;
39098
+ }
39064
39099
  const { directScopes, directRequested } = buildDirectMaps(pkgJson);
39065
39100
  const lockMap = lockfilePath ? await parseLockfile(cliType, lockfilePath, lockfileVersion) : /* @__PURE__ */ new Map();
39066
39101
  const directDeps = [];
package/dist/lambda.js CHANGED
@@ -208,61 +208,63 @@ class Lambda {
208
208
  `${prefix} is not an object`
209
209
  );
210
210
  (0, import_assert.default)(
211
- trigger.type === "queue/v1beta" || trigger.type === "queue/v2beta",
212
- `${prefix}.type must be "queue/v1beta" or "queue/v2beta"`
211
+ trigger.type === "queue/v1beta" || trigger.type === "queue/v2beta" || trigger.type === "schedule/v1beta",
212
+ `${prefix}.type must be "queue/v1beta", "queue/v2beta", or "schedule/v1beta"`
213
213
  );
214
- (0, import_assert.default)(
215
- typeof trigger.topic === "string",
216
- `${prefix}.topic is required and must be a string`
217
- );
218
- (0, import_assert.default)(trigger.topic.length > 0, `${prefix}.topic cannot be empty`);
219
- (0, import_assert.default)(
220
- typeof trigger.consumer === "string",
221
- `${prefix}.consumer is required and must be a string`
222
- );
223
- (0, import_assert.default)(
224
- trigger.consumer.length > 0,
225
- `${prefix}.consumer cannot be empty`
226
- );
227
- if (trigger.maxDeliveries !== void 0) {
214
+ if (trigger.type === "queue/v1beta" || trigger.type === "queue/v2beta") {
228
215
  (0, import_assert.default)(
229
- typeof trigger.maxDeliveries === "number",
230
- `${prefix}.maxDeliveries must be a number`
216
+ typeof trigger.topic === "string",
217
+ `${prefix}.topic is required and must be a string`
231
218
  );
219
+ (0, import_assert.default)(trigger.topic.length > 0, `${prefix}.topic cannot be empty`);
232
220
  (0, import_assert.default)(
233
- Number.isInteger(trigger.maxDeliveries) && trigger.maxDeliveries >= 1,
234
- `${prefix}.maxDeliveries must be at least 1`
221
+ typeof trigger.consumer === "string",
222
+ `${prefix}.consumer is required and must be a string`
235
223
  );
236
- }
237
- if (trigger.retryAfterSeconds !== void 0) {
238
- (0, import_assert.default)(
239
- typeof trigger.retryAfterSeconds === "number",
240
- `${prefix}.retryAfterSeconds must be a number`
241
- );
242
- (0, import_assert.default)(
243
- trigger.retryAfterSeconds > 0,
244
- `${prefix}.retryAfterSeconds must be a positive number`
245
- );
246
- }
247
- if (trigger.initialDelaySeconds !== void 0) {
248
224
  (0, import_assert.default)(
249
- typeof trigger.initialDelaySeconds === "number",
250
- `${prefix}.initialDelaySeconds must be a number`
251
- );
252
- (0, import_assert.default)(
253
- trigger.initialDelaySeconds >= 0,
254
- `${prefix}.initialDelaySeconds must be a non-negative number`
255
- );
256
- }
257
- if (trigger.maxConcurrency !== void 0) {
258
- (0, import_assert.default)(
259
- typeof trigger.maxConcurrency === "number",
260
- `${prefix}.maxConcurrency must be a number`
261
- );
262
- (0, import_assert.default)(
263
- Number.isInteger(trigger.maxConcurrency) && trigger.maxConcurrency >= 1,
264
- `${prefix}.maxConcurrency must be at least 1`
225
+ trigger.consumer.length > 0,
226
+ `${prefix}.consumer cannot be empty`
265
227
  );
228
+ if (trigger.maxDeliveries !== void 0) {
229
+ (0, import_assert.default)(
230
+ typeof trigger.maxDeliveries === "number",
231
+ `${prefix}.maxDeliveries must be a number`
232
+ );
233
+ (0, import_assert.default)(
234
+ Number.isInteger(trigger.maxDeliveries) && trigger.maxDeliveries >= 1,
235
+ `${prefix}.maxDeliveries must be at least 1`
236
+ );
237
+ }
238
+ if (trigger.retryAfterSeconds !== void 0) {
239
+ (0, import_assert.default)(
240
+ typeof trigger.retryAfterSeconds === "number",
241
+ `${prefix}.retryAfterSeconds must be a number`
242
+ );
243
+ (0, import_assert.default)(
244
+ trigger.retryAfterSeconds > 0,
245
+ `${prefix}.retryAfterSeconds must be a positive number`
246
+ );
247
+ }
248
+ if (trigger.initialDelaySeconds !== void 0) {
249
+ (0, import_assert.default)(
250
+ typeof trigger.initialDelaySeconds === "number",
251
+ `${prefix}.initialDelaySeconds must be a number`
252
+ );
253
+ (0, import_assert.default)(
254
+ trigger.initialDelaySeconds >= 0,
255
+ `${prefix}.initialDelaySeconds must be a non-negative number`
256
+ );
257
+ }
258
+ if (trigger.maxConcurrency !== void 0) {
259
+ (0, import_assert.default)(
260
+ typeof trigger.maxConcurrency === "number",
261
+ `${prefix}.maxConcurrency must be a number`
262
+ );
263
+ (0, import_assert.default)(
264
+ Number.isInteger(trigger.maxConcurrency) && trigger.maxConcurrency >= 1,
265
+ `${prefix}.maxConcurrency must be at least 1`
266
+ );
267
+ }
266
268
  }
267
269
  }
268
270
  }
@@ -392,8 +392,21 @@ async function generateProjectManifest({
392
392
  }) {
393
393
  try {
394
394
  const pkgJson = await readPackageJson(workPath);
395
- if (!pkgJson)
395
+ if (!pkgJson) {
396
+ await (0, import_package_manifest.writeProjectManifest)(
397
+ {
398
+ version: import_package_manifest.MANIFEST_VERSION,
399
+ runtime: "node",
400
+ ...framework ? { framework } : {},
401
+ ...serviceType ? { serviceType } : {},
402
+ runtimeVersion: { resolved: String(nodeVersion.major) },
403
+ dependencies: []
404
+ },
405
+ workPath,
406
+ outputRuntime
407
+ );
396
408
  return;
409
+ }
397
410
  const { directScopes, directRequested } = buildDirectMaps(pkgJson);
398
411
  const lockMap = lockfilePath ? await parseLockfile(cliType, lockfilePath, lockfileVersion) : /* @__PURE__ */ new Map();
399
412
  const directDeps = [];
@@ -8,11 +8,20 @@ export interface PackageManifestDependency {
8
8
  source?: string;
9
9
  sourceUrl?: string;
10
10
  }
11
+ /**
12
+ * What triggered this build pipeline entry.
13
+ *
14
+ * - `'app'` — full application build
15
+ * - `'api-dir'` — api/ directory build
16
+ * - `'middleware'` — middleware build
17
+ */
18
+ export type BuildType = 'app' | 'api-dir' | 'middleware';
11
19
  export interface PackageManifest {
12
20
  version?: string;
13
21
  runtime: string;
14
22
  framework?: string;
15
23
  serviceType?: string;
24
+ buildType?: BuildType;
16
25
  runtimeVersion?: {
17
26
  requested?: string;
18
27
  requestedSource?: string;
package/dist/schemas.d.ts CHANGED
@@ -76,26 +76,6 @@ export declare const getFunctionsSchema: () => {
76
76
  type: string;
77
77
  const: string;
78
78
  };
79
- topic: {
80
- type: string;
81
- minLength: number;
82
- };
83
- maxDeliveries: {
84
- type: string;
85
- minimum: number;
86
- };
87
- retryAfterSeconds: {
88
- type: string;
89
- exclusiveMinimum: number;
90
- };
91
- initialDelaySeconds: {
92
- type: string;
93
- minimum: number;
94
- };
95
- maxConcurrency: {
96
- type: string;
97
- minimum: number;
98
- };
99
79
  };
100
80
  required: string[];
101
81
  additionalProperties: boolean;
@@ -193,26 +173,6 @@ export declare const functionsSchema: {
193
173
  type: string;
194
174
  const: string;
195
175
  };
196
- topic: {
197
- type: string;
198
- minLength: number;
199
- };
200
- maxDeliveries: {
201
- type: string;
202
- minimum: number;
203
- };
204
- retryAfterSeconds: {
205
- type: string;
206
- exclusiveMinimum: number;
207
- };
208
- initialDelaySeconds: {
209
- type: string;
210
- minimum: number;
211
- };
212
- maxConcurrency: {
213
- type: string;
214
- minimum: number;
215
- };
216
176
  };
217
177
  required: string[];
218
178
  additionalProperties: boolean;
@@ -276,7 +236,12 @@ export declare const packageManifestSchema: {
276
236
  };
277
237
  readonly serviceType: {
278
238
  readonly type: "string";
279
- readonly description: "Service type: one of \"web\", \"schedule\", \"queue\", \"workflow\".";
239
+ readonly description: "Deployment topology for service builds: \"web\", \"schedule\", \"queue\", or \"workflow\".";
240
+ };
241
+ readonly buildType: {
242
+ readonly type: "string";
243
+ readonly enum: readonly ["app", "api-dir", "middleware"];
244
+ readonly description: "What triggered this build: \"app\" (full application build), \"api-dir\" (api/ directory build), or \"middleware\" (middleware build).";
280
245
  };
281
246
  readonly runtimeVersion: {
282
247
  readonly type: "object";
package/dist/schemas.js CHANGED
@@ -91,8 +91,23 @@ const triggerEventSchemaV2 = {
91
91
  required: ["type", "topic"],
92
92
  additionalProperties: false
93
93
  };
94
+ const scheduleTriggerEventSchemaV1 = {
95
+ type: "object",
96
+ properties: {
97
+ type: {
98
+ type: "string",
99
+ const: "schedule/v1beta"
100
+ }
101
+ },
102
+ required: ["type"],
103
+ additionalProperties: false
104
+ };
94
105
  const triggerEventSchema = {
95
- oneOf: [triggerEventSchemaV1, triggerEventSchemaV2]
106
+ oneOf: [
107
+ triggerEventSchemaV1,
108
+ triggerEventSchemaV2,
109
+ scheduleTriggerEventSchemaV1
110
+ ]
96
111
  };
97
112
  const getFunctionsSchema = () => ({
98
113
  type: "object",
@@ -206,7 +221,12 @@ const packageManifestSchema = {
206
221
  },
207
222
  serviceType: {
208
223
  type: "string",
209
- description: 'Service type: one of "web", "schedule", "queue", "workflow".'
224
+ description: 'Deployment topology for service builds: "web", "schedule", "queue", or "workflow".'
225
+ },
226
+ buildType: {
227
+ type: "string",
228
+ enum: ["app", "api-dir", "middleware"],
229
+ description: 'What triggered this build: "app" (full application build), "api-dir" (api/ directory build), or "middleware" (middleware build).'
210
230
  },
211
231
  runtimeVersion: {
212
232
  type: "object",
package/dist/types.d.ts CHANGED
@@ -565,6 +565,27 @@ export interface Cron {
565
565
  path: string;
566
566
  schedule: string;
567
567
  }
568
+ export interface ScheduleExpression {
569
+ /** Cron expression describing when the schedule fires (REQUIRED) */
570
+ cron: string;
571
+ /** Maximum random delay applied to each firing, e.g. "5m" (OPTIONAL) */
572
+ jitter?: string;
573
+ }
574
+ export type ScheduleTarget = {
575
+ /** Build output path of the function to invoke, e.g. "api/cron" */
576
+ function: string;
577
+ } | {
578
+ /** Name of the queue topic to publish to */
579
+ topic: string;
580
+ };
581
+ export interface Schedule {
582
+ /** Unique name of the schedule within the deployment (REQUIRED) */
583
+ name: string;
584
+ expression: ScheduleExpression;
585
+ target: ScheduleTarget;
586
+ /** Payload delivered with each firing (OPTIONAL) */
587
+ payload?: unknown;
588
+ }
568
589
  export interface ServiceQueueTopic {
569
590
  topic: string;
570
591
  retryAfterSeconds?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/build-utils",
3
- "version": "14.6.1",
3
+ "version": "14.8.0",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.js",
@@ -52,8 +52,8 @@
52
52
  "vitest": "4.1.10",
53
53
  "typescript": "4.9.5",
54
54
  "yazl": "2.5.1",
55
- "@vercel/routing-utils": "6.5.0",
56
- "@vercel/error-utils": "2.2.1"
55
+ "@vercel/error-utils": "2.2.1",
56
+ "@vercel/routing-utils": "6.5.0"
57
57
  },
58
58
  "scripts": {
59
59
  "build": "node build.mjs",