0

Propose an App Spec

by
Published Dec 20, 2024

To propose and validate a spec for a new or existing app, send a POST request to the `/v2/apps/propose` endpoint. The request returns some information about the proposed app, including app cost and upgrade cost. If an existing app ID is specified, the app spec is treated as a proposed update to the existing app.

Script digitalocean Verified

The script

Submitted by hugo697 Bun
Verified 536 days ago
1
//native
2
type Digitalocean = {
3
  token: string;
4
};
5
/**
6
 * Propose an App Spec
7
 * To propose and validate a spec for a new or existing app, send a POST request to the `/v2/apps/propose` endpoint. The request returns some information about the proposed app, including app cost and upgrade cost. If an existing app ID is specified, the app spec is treated as a proposed update to the existing app.
8
 */
9
export async function main(
10
  auth: Digitalocean,
11
  body: {
12
    spec: {
13
      name: string;
14
      region?:
15
        | "ams"
16
        | "nyc"
17
        | "fra"
18
        | "sfo"
19
        | "sgp"
20
        | "blr"
21
        | "tor"
22
        | "lon"
23
        | "syd";
24
      domains?: {
25
        domain: string;
26
        type?: "UNSPECIFIED" | "DEFAULT" | "PRIMARY" | "ALIAS";
27
        wildcard?: false | true;
28
        zone?: string;
29
        minimum_tls_version?: "1.2" | "1.3";
30
      }[];
31
      services?: {
32
        name?: string;
33
        git?: { branch?: string; repo_clone_url?: string };
34
        github?: {
35
          branch?: string;
36
          deploy_on_push?: false | true;
37
          repo?: string;
38
        };
39
        gitlab?: {
40
          branch?: string;
41
          deploy_on_push?: false | true;
42
          repo?: string;
43
        };
44
        image?: {
45
          registry?: string;
46
          registry_type?: "DOCKER_HUB" | "DOCR" | "GHCR";
47
          registry_credentials?: string;
48
          repository?: string;
49
          tag?: string;
50
          digest?: string;
51
          deploy_on_push?: { enabled?: false | true };
52
        };
53
        dockerfile_path?: string;
54
        build_command?: string;
55
        run_command?: string;
56
        source_dir?: string;
57
        envs?: {
58
          key: string;
59
          scope?: "UNSET" | "RUN_TIME" | "BUILD_TIME" | "RUN_AND_BUILD_TIME";
60
          type?: "GENERAL" | "SECRET";
61
          value?: string;
62
        }[];
63
        environment_slug?: string;
64
        log_destinations?: {
65
          name: string;
66
          papertrail?: { endpoint: string };
67
          datadog?: { endpoint?: string; api_key: string };
68
          logtail?: { token?: string };
69
          open_search?: {
70
            endpoint?: string;
71
            basic_auth?: { user?: string; password?: {} };
72
            index_name?: string;
73
            cluster_name?: string;
74
          };
75
        }[];
76
      } & {
77
        instance_count?: number;
78
        instance_size_slug?:
79
          | "apps-s-1vcpu-0.5gb"
80
          | "apps-s-1vcpu-1gb-fixed"
81
          | "apps-s-1vcpu-1gb"
82
          | "apps-s-1vcpu-2gb"
83
          | "apps-s-2vcpu-4gb"
84
          | "apps-d-1vcpu-0.5gb"
85
          | "apps-d-1vcpu-1gb"
86
          | "apps-d-1vcpu-2gb"
87
          | "apps-d-1vcpu-4gb"
88
          | "apps-d-2vcpu-4gb"
89
          | "apps-d-2vcpu-8gb"
90
          | "apps-d-4vcpu-8gb"
91
          | "apps-d-4vcpu-16gb"
92
          | "apps-d-8vcpu-32gb"
93
          | "basic-xxs"
94
          | "basic-xs"
95
          | "basic-s"
96
          | "basic-m"
97
          | "professional-xs"
98
          | "professional-s"
99
          | "professional-m"
100
          | "professional-1l"
101
          | "professional-l"
102
          | "professional-xl";
103
        autoscaling?: {
104
          min_instance_count?: number;
105
          max_instance_count?: number;
106
          metrics?: { cpu?: { percent?: number } };
107
        };
108
      } & {
109
          cors?: {
110
            allow_origins?: {
111
              exact?: string;
112
              prefix?: string;
113
              regex?: string;
114
            }[];
115
            allow_methods?: string[];
116
            allow_headers?: string[];
117
            expose_headers?: string[];
118
            max_age?: string;
119
            allow_credentials?: false | true;
120
          } & {} & {};
121
          health_check?: {
122
            failure_threshold?: number;
123
            port?: number;
124
            http_path?: string;
125
            initial_delay_seconds?: number;
126
            period_seconds?: number;
127
            success_threshold?: number;
128
            timeout_seconds?: number;
129
          };
130
          protocol?: "HTTP" | "HTTP2";
131
          http_port?: number;
132
          internal_ports?: number[];
133
          routes?: { path?: string; preserve_path_prefix?: false | true }[];
134
          termination?: {
135
            drain_seconds?: number;
136
            grace_period_seconds?: number;
137
          };
138
        }[];
139
      static_sites?: {
140
        name?: string;
141
        git?: { branch?: string; repo_clone_url?: string };
142
        github?: {
143
          branch?: string;
144
          deploy_on_push?: false | true;
145
          repo?: string;
146
        };
147
        gitlab?: {
148
          branch?: string;
149
          deploy_on_push?: false | true;
150
          repo?: string;
151
        };
152
        image?: {
153
          registry?: string;
154
          registry_type?: "DOCKER_HUB" | "DOCR" | "GHCR";
155
          registry_credentials?: string;
156
          repository?: string;
157
          tag?: string;
158
          digest?: string;
159
          deploy_on_push?: { enabled?: false | true };
160
        };
161
        dockerfile_path?: string;
162
        build_command?: string;
163
        run_command?: string;
164
        source_dir?: string;
165
        envs?: {
166
          key: string;
167
          scope?: "UNSET" | "RUN_TIME" | "BUILD_TIME" | "RUN_AND_BUILD_TIME";
168
          type?: "GENERAL" | "SECRET";
169
          value?: string;
170
        }[];
171
        environment_slug?: string;
172
        log_destinations?: {
173
          name: string;
174
          papertrail?: { endpoint: string };
175
          datadog?: { endpoint?: string; api_key: string };
176
          logtail?: { token?: string };
177
          open_search?: {
178
            endpoint?: string;
179
            basic_auth?: { user?: string; password?: {} };
180
            index_name?: string;
181
            cluster_name?: string;
182
          };
183
        }[];
184
      } & {
185
        index_document?: string;
186
        error_document?: string;
187
        catchall_document?: string;
188
        output_dir?: string;
189
        cors?: {
190
          allow_origins?: { exact?: string; prefix?: string; regex?: string }[];
191
          allow_methods?: string[];
192
          allow_headers?: string[];
193
          expose_headers?: string[];
194
          max_age?: string;
195
          allow_credentials?: false | true;
196
        } & {} & {};
197
        routes?: { path?: string; preserve_path_prefix?: false | true }[];
198
      }[];
199
      jobs?: {
200
        name?: string;
201
        git?: { branch?: string; repo_clone_url?: string };
202
        github?: {
203
          branch?: string;
204
          deploy_on_push?: false | true;
205
          repo?: string;
206
        };
207
        gitlab?: {
208
          branch?: string;
209
          deploy_on_push?: false | true;
210
          repo?: string;
211
        };
212
        image?: {
213
          registry?: string;
214
          registry_type?: "DOCKER_HUB" | "DOCR" | "GHCR";
215
          registry_credentials?: string;
216
          repository?: string;
217
          tag?: string;
218
          digest?: string;
219
          deploy_on_push?: { enabled?: false | true };
220
        };
221
        dockerfile_path?: string;
222
        build_command?: string;
223
        run_command?: string;
224
        source_dir?: string;
225
        envs?: {
226
          key: string;
227
          scope?: "UNSET" | "RUN_TIME" | "BUILD_TIME" | "RUN_AND_BUILD_TIME";
228
          type?: "GENERAL" | "SECRET";
229
          value?: string;
230
        }[];
231
        environment_slug?: string;
232
        log_destinations?: {
233
          name: string;
234
          papertrail?: { endpoint: string };
235
          datadog?: { endpoint?: string; api_key: string };
236
          logtail?: { token?: string };
237
          open_search?: {
238
            endpoint?: string;
239
            basic_auth?: { user?: string; password?: {} };
240
            index_name?: string;
241
            cluster_name?: string;
242
          };
243
        }[];
244
      } & {
245
        instance_count?: number;
246
        instance_size_slug?:
247
          | "apps-s-1vcpu-0.5gb"
248
          | "apps-s-1vcpu-1gb-fixed"
249
          | "apps-s-1vcpu-1gb"
250
          | "apps-s-1vcpu-2gb"
251
          | "apps-s-2vcpu-4gb"
252
          | "apps-d-1vcpu-0.5gb"
253
          | "apps-d-1vcpu-1gb"
254
          | "apps-d-1vcpu-2gb"
255
          | "apps-d-1vcpu-4gb"
256
          | "apps-d-2vcpu-4gb"
257
          | "apps-d-2vcpu-8gb"
258
          | "apps-d-4vcpu-8gb"
259
          | "apps-d-4vcpu-16gb"
260
          | "apps-d-8vcpu-32gb"
261
          | "basic-xxs"
262
          | "basic-xs"
263
          | "basic-s"
264
          | "basic-m"
265
          | "professional-xs"
266
          | "professional-s"
267
          | "professional-m"
268
          | "professional-1l"
269
          | "professional-l"
270
          | "professional-xl";
271
        autoscaling?: {
272
          min_instance_count?: number;
273
          max_instance_count?: number;
274
          metrics?: { cpu?: { percent?: number } };
275
        };
276
      } & {
277
          kind?: "UNSPECIFIED" | "PRE_DEPLOY" | "POST_DEPLOY" | "FAILED_DEPLOY";
278
          termination?: { grace_period_seconds?: number };
279
        }[];
280
      workers?: {
281
        name?: string;
282
        git?: { branch?: string; repo_clone_url?: string };
283
        github?: {
284
          branch?: string;
285
          deploy_on_push?: false | true;
286
          repo?: string;
287
        };
288
        gitlab?: {
289
          branch?: string;
290
          deploy_on_push?: false | true;
291
          repo?: string;
292
        };
293
        image?: {
294
          registry?: string;
295
          registry_type?: "DOCKER_HUB" | "DOCR" | "GHCR";
296
          registry_credentials?: string;
297
          repository?: string;
298
          tag?: string;
299
          digest?: string;
300
          deploy_on_push?: { enabled?: false | true };
301
        };
302
        dockerfile_path?: string;
303
        build_command?: string;
304
        run_command?: string;
305
        source_dir?: string;
306
        envs?: {
307
          key: string;
308
          scope?: "UNSET" | "RUN_TIME" | "BUILD_TIME" | "RUN_AND_BUILD_TIME";
309
          type?: "GENERAL" | "SECRET";
310
          value?: string;
311
        }[];
312
        environment_slug?: string;
313
        log_destinations?: {
314
          name: string;
315
          papertrail?: { endpoint: string };
316
          datadog?: { endpoint?: string; api_key: string };
317
          logtail?: { token?: string };
318
          open_search?: {
319
            endpoint?: string;
320
            basic_auth?: { user?: string; password?: {} };
321
            index_name?: string;
322
            cluster_name?: string;
323
          };
324
        }[];
325
      } & {
326
        instance_count?: number;
327
        instance_size_slug?:
328
          | "apps-s-1vcpu-0.5gb"
329
          | "apps-s-1vcpu-1gb-fixed"
330
          | "apps-s-1vcpu-1gb"
331
          | "apps-s-1vcpu-2gb"
332
          | "apps-s-2vcpu-4gb"
333
          | "apps-d-1vcpu-0.5gb"
334
          | "apps-d-1vcpu-1gb"
335
          | "apps-d-1vcpu-2gb"
336
          | "apps-d-1vcpu-4gb"
337
          | "apps-d-2vcpu-4gb"
338
          | "apps-d-2vcpu-8gb"
339
          | "apps-d-4vcpu-8gb"
340
          | "apps-d-4vcpu-16gb"
341
          | "apps-d-8vcpu-32gb"
342
          | "basic-xxs"
343
          | "basic-xs"
344
          | "basic-s"
345
          | "basic-m"
346
          | "professional-xs"
347
          | "professional-s"
348
          | "professional-m"
349
          | "professional-1l"
350
          | "professional-l"
351
          | "professional-xl";
352
        autoscaling?: {
353
          min_instance_count?: number;
354
          max_instance_count?: number;
355
          metrics?: { cpu?: { percent?: number } };
356
        };
357
      } & { termination?: { grace_period_seconds?: number } }[];
358
      functions?: {
359
        cors?: {
360
          allow_origins?: { exact?: string; prefix?: string; regex?: string }[];
361
          allow_methods?: string[];
362
          allow_headers?: string[];
363
          expose_headers?: string[];
364
          max_age?: string;
365
          allow_credentials?: false | true;
366
        } & {} & {};
367
        routes?: { path?: string; preserve_path_prefix?: false | true }[];
368
        name: string;
369
        source_dir?: string;
370
        alerts?: {
371
          rule?:
372
            | "UNSPECIFIED_RULE"
373
            | "CPU_UTILIZATION"
374
            | "MEM_UTILIZATION"
375
            | "RESTART_COUNT"
376
            | "DEPLOYMENT_FAILED"
377
            | "DEPLOYMENT_LIVE"
378
            | "DOMAIN_FAILED"
379
            | "DOMAIN_LIVE"
380
            | "FUNCTIONS_ACTIVATION_COUNT"
381
            | "FUNCTIONS_AVERAGE_DURATION_MS"
382
            | "FUNCTIONS_ERROR_RATE_PER_MINUTE"
383
            | "FUNCTIONS_AVERAGE_WAIT_TIME_MS"
384
            | "FUNCTIONS_ERROR_COUNT"
385
            | "FUNCTIONS_GB_RATE_PER_SECOND";
386
          disabled?: false | true;
387
          operator?: "UNSPECIFIED_OPERATOR" | "GREATER_THAN" | "LESS_THAN";
388
          value?: number;
389
          window?:
390
            | "UNSPECIFIED_WINDOW"
391
            | "FIVE_MINUTES"
392
            | "TEN_MINUTES"
393
            | "THIRTY_MINUTES"
394
            | "ONE_HOUR";
395
        }[];
396
        envs?: {
397
          key: string;
398
          scope?: "UNSET" | "RUN_TIME" | "BUILD_TIME" | "RUN_AND_BUILD_TIME";
399
          type?: "GENERAL" | "SECRET";
400
          value?: string;
401
        }[];
402
        git?: { branch?: string; repo_clone_url?: string };
403
        github?: {
404
          branch?: string;
405
          deploy_on_push?: false | true;
406
          repo?: string;
407
        };
408
        gitlab?: {
409
          branch?: string;
410
          deploy_on_push?: false | true;
411
          repo?: string;
412
        };
413
        log_destinations?: {
414
          name: string;
415
          papertrail?: { endpoint: string };
416
          datadog?: { endpoint?: string; api_key: string };
417
          logtail?: { token?: string };
418
          open_search?: {
419
            endpoint?: string;
420
            basic_auth?: { user?: string; password?: {} };
421
            index_name?: string;
422
            cluster_name?: string;
423
          };
424
        }[];
425
      }[];
426
      databases?: {
427
        cluster_name?: string;
428
        db_name?: string;
429
        db_user?: string;
430
        engine?:
431
          | "UNSET"
432
          | "MYSQL"
433
          | "PG"
434
          | "REDIS"
435
          | "MONGODB"
436
          | "KAFKA"
437
          | "OPENSEARCH";
438
        name: string;
439
        production?: false | true;
440
        version?: string;
441
      }[];
442
      ingress?: {
443
        rules?: {
444
          match?: { path: { prefix: string } };
445
          cors?: {
446
            allow_origins?: {
447
              exact?: string;
448
              prefix?: string;
449
              regex?: string;
450
            }[];
451
            allow_methods?: string[];
452
            allow_headers?: string[];
453
            expose_headers?: string[];
454
            max_age?: string;
455
            allow_credentials?: false | true;
456
          };
457
          component?: {
458
            name: string;
459
            preserve_path_prefix?: string;
460
            rewrite?: string;
461
          };
462
          redirect?: {
463
            uri?: string;
464
            authority?: string;
465
            port?: number;
466
            scheme?: string;
467
            redirect_code?: number;
468
          };
469
        }[];
470
      };
471
      egress?: { type?: "AUTOASSIGN" | "DEDICATED_IP" };
472
      maintenance?: { enabled?: false | true; archive?: false | true };
473
    };
474
    app_id?: string;
475
  },
476
) {
477
  const url = new URL(`https://api.digitalocean.com/v2/apps/propose`);
478

479
  const response = await fetch(url, {
480
    method: "POST",
481
    headers: {
482
      "Content-Type": "application/json",
483
      Authorization: "Bearer " + auth.token,
484
    },
485
    body: JSON.stringify(body),
486
  });
487
  if (!response.ok) {
488
    const text = await response.text();
489
    throw new Error(`${response.status} ${text}`);
490
  }
491
  return await response.json();
492
}
493