UNPKG

50.1 kBJavaScriptView Raw
1/* eslint-disable max-classes-per-file */
2const axios = require('./httpclient');
3const config = require('./config');
4const Conditions = require('./conditions');
5const Headers = require('./headers');
6const AccountAPI = require('./api-account.js');
7const AuthAPI = require('./api-auth.js');
8const PurgeAPI = require('./api-purge.js');
9const DomainAPI = require('./api-domain.js');
10const HealthcheckAPI = require('./api-healthcheck');
11
12class RateLimitError extends Error {
13
14}
15
16class Fastly {
17 /**
18 * @typedef {Function} CreateFunction
19 * A function that creates a resource of a specific type. If a resource of that
20 * name already exists, it will reject the returned promise with an error.
21 * @param {string} version - The service config version to operate on. Needs to be checked out.
22 * @param {object} data - The data object describing the resource to be created.
23 * @param {string} data.name - The name of the resource to be created.
24 * @returns {Promise} The response object representing the completion or failure.
25 * @throws {FastlyError}
26 */
27
28 /**
29 * @typedef {Function} UpdateFunction
30 * A function that updates an already existing resource of a specific type.
31 * If no resource of that name exists, it will reject the returned promise with an error.
32 * @param {string} version - The service config version to operate on. Needs to be checked out.
33 * @param {string} name - The name of the resource to be updated. The old name in case of renaming
34 * something.
35 * @param {object} data - The data object describing the resource to be updated.
36 * @param {string} data.name - The new name of the resource to be updated.
37 * @returns {Promise} The response object representing the completion or failure.
38 * @throws {FastlyError}
39 */
40
41 /**
42 * @typedef {Function} ReadFunction
43 * A function that retrieves a representation of a resource of a specific type.
44 * If no resource of that name exists, it will reject the returned promise with an error.
45 * @param {string} version - The service config version to operate on. Needs to be checked out.
46 * @param {string} name - The name of the resource to be retrieved.
47 * @returns {Promise} The response object representing the completion or failure.
48 * @throws {FastlyError}
49 */
50
51 /**
52 * @typedef {Function} ListFunction
53 * A function that retrieves a list of resources of a specific type.
54 * @param {string} version - The service config version to operate on. Needs to be checked out.
55 * @returns {Promise} The response object representing the completion or failure.
56 * @throws {FastlyError}
57 */
58
59 /**
60 * Create a new function that lists all log configurations for a given service
61 * and version. The function can be parametrized with the name of the logging
62 * service.
63 *
64 * @param {string} service - The id of the logging service. Supported services are:
65 * s3, s3canary, azureblob, cloudfiles, digitalocean, ftp, bigquery, gcs, honeycomb,
66 * logshuttle, logentries, loggly, heroku, https, openstack, papertrail, scalyr, splunk,
67 * sumologic, syslog.
68 * @returns {ListFunction} A logging function.
69 */
70 readLogsFn(service) {
71 return async (version) => this.request.get(`/service/${this.service_id}/version/${await this.getVersion(version, 'latest')}/logging/${service}`);
72 }
73
74 /**
75 * Create a new function that returns a named log configuration for a given service
76 * and version. The function can be parametrized with the name of the logging
77 * service.
78 *
79 * @param {string} service - The id of the logging service. Supported services are:
80 * s3, s3canary, azureblob, cloudfiles, digitalocean, ftp, bigquery, gcs, honeycomb,
81 * logshuttle, logentries, loggly, heroku, https, openstack, papertrail, scalyr, splunk,
82 * sumologic, syslog.
83 * @returns {ReadFunction} A logging function.
84 */
85 readLogFn(service) {
86 return async (version, name) => this.request.get(`/service/${this.service_id}/version/${await this.getVersion(version, 'latest')}/logging/${service}/${name}`);
87 }
88
89 /**
90 * Create a new function that creates a named log configuration for a given service
91 * and version. The function can be parametrized with the name of the logging
92 * service.
93 *
94 * @param {string} service - The id of the logging service. Supported services are:
95 * s3, s3canary, azureblob, cloudfiles, digitalocean, ftp, bigquery, gcs, honeycomb,
96 * logshuttle, logentries, loggly, heroku, https, openstack, papertrail, scalyr, splunk,
97 * sumologic, syslog.
98 * @returns {CreateFunction} A logging function.
99 */
100 createLogFn(service) {
101 return async (version, data) => this.request.post(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/logging/${service}`, data);
102 }
103
104 /**
105 * Create a new function that updates a named log configuration for a given service
106 * and version. The function can be parametrized with the name of the logging
107 * service.
108 *
109 * @param {string} service - The id of the logging service. Supported services are:
110 * s3, s3canary, azureblob, cloudfiles, digitalocean, ftp, bigquery, gcs, honeycomb,
111 * logshuttle, logentries, loggly, heroku, https, openstack, papertrail, scalyr, splunk,
112 * sumologic, syslog.
113 * @returns {UpdateFunction} A logging function.
114 */
115 updateLogFn(service) {
116 return async (version, name, data) => this.request.put(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/logging/${service}/${name}`, data);
117 }
118
119 /**
120 * Creates an update-or-create or "safe create" function that will either create
121 * (if it does not exist) or update (if it does) a named resource. The function
122 * will attempt to check if the resource exists first (if a reader function has been
123 * provided), alternatively, it will just blindly create and fall back with an
124 * update.
125 *
126 * @param {CreateFunction} createFn - A function that creates a resource.
127 * @param {UpdateFunction} updateFn - A function that updates a resource.
128 * @param {ReadFunction} readFn - An optional function that checks for the existence
129 * of a resource.
130 * @returns {UpdateFunction} An update function that does not fail on conflict.
131 */
132 upsertFn(createFn, updateFn, readFn) {
133 if (readFn) {
134 // careful
135 return (version, name, data) => readFn.apply(this, [version, name])
136 .then(() => updateFn.apply(this, [version, name, data]))
137 .catch(() => createFn.apply(this, [version, data]));
138 }
139 // stubborn
140 return (version, name, data) => createFn.apply(this, [version, data])
141 .catch(() => updateFn.apply(this, [version, name, data]));
142 }
143
144 /* eslint-disable camelcase */
145 /**
146 * The constructor method for creating a fastly-promises instance.
147 *
148 * @param {string} token - The Fastly API token.
149 * @param {string} service_id - The Fastly service ID.
150 * @param {number} timeout - HTTP timeout for requests to the Fastly API, default: 15 seconds.
151 */
152 constructor(token, service_id, timeout = 15000) {
153 this.service_id = service_id;
154 this.request = axios.create({
155 baseURL: config.mainEntryPoint,
156 timeout,
157 headers: { 'Fastly-Key': token },
158 });
159
160 this.requestmonitor = this.request.monitor;
161
162 this.versions = {
163 current: undefined,
164 active: undefined,
165 latest: undefined,
166 };
167
168 this.readS3Logs = this.readLogsFn('s3');
169 this.readS3canaryLogs = this.readLogsFn('s3canary');
170 this.readAzureblobLogs = this.readLogsFn('azureblob');
171 this.readCloudfilesLogs = this.readLogsFn('cloudfiles');
172 this.readDigitaloceanLogs = this.readLogsFn('digitalocean');
173 this.readFtpLogs = this.readLogsFn('ftp');
174 this.readBigqueryLogs = this.readLogsFn('bigquery');
175 this.readGcsLogs = this.readLogsFn('gcs');
176 this.readHoneycombLogs = this.readLogsFn('honeycomb');
177 this.readLogshuttleLogs = this.readLogsFn('logshuttle');
178 this.readLogentriesLogs = this.readLogsFn('logentries');
179 this.readLogglyLogs = this.readLogsFn('loggly');
180 this.readHerokuLogs = this.readLogsFn('heroku');
181 this.readOpenstackLogs = this.readLogsFn('openstack');
182 this.readPapertrailLogs = this.readLogsFn('papertrail');
183 this.readScalyrLogs = this.readLogsFn('scalyr');
184 this.readSplunkLogs = this.readLogsFn('splunk');
185 this.readSumologicLogs = this.readLogsFn('sumologic');
186 this.readSyslogLogs = this.readLogsFn('syslog');
187 this.readHttpsLogs = this.readLogsFn('https');
188
189 this.readS3 = this.readLogFn('s3');
190 this.readS3canary = this.readLogFn('s3canary');
191 this.readAzureblob = this.readLogFn('azureblob');
192 this.readCloudfiles = this.readLogFn('cloudfiles');
193 this.readDigitalocean = this.readLogFn('digitalocean');
194 this.readFtp = this.readLogFn('ftp');
195 this.readBigquery = this.readLogFn('bigquery');
196 this.readGcs = this.readLogFn('gcs');
197 this.readHoneycomb = this.readLogFn('honeycomb');
198 this.readLogshuttle = this.readLogFn('logshuttle');
199 this.readLogentries = this.readLogFn('logentries');
200 this.readLoggly = this.readLogFn('loggly');
201 this.readHeroku = this.readLogFn('heroku');
202 this.readOpenstack = this.readLogFn('openstack');
203 this.readPapertrail = this.readLogFn('papertrail');
204 this.readScalyr = this.readLogFn('scalyr');
205 this.readSplunk = this.readLogFn('splunk');
206 this.readSumologic = this.readLogFn('sumologic');
207 this.readSyslog = this.readLogFn('syslog');
208 this.readHttps = this.readLogFn('https');
209
210 this.createS3 = this.createLogFn('s3');
211 this.createS3canary = this.createLogFn('s3canary');
212 this.createAzureblob = this.createLogFn('azureblob');
213 this.createCloudfiles = this.createLogFn('cloudfiles');
214 this.createDigitalocean = this.createLogFn('digitalocean');
215 this.createFtp = this.createLogFn('ftp');
216 this.createBigquery = this.createLogFn('bigquery');
217 this.createGcs = this.createLogFn('gcs');
218 this.createHoneycomb = this.createLogFn('honeycomb');
219 this.createLogshuttle = this.createLogFn('logshuttle');
220 this.createLogentries = this.createLogFn('logentries');
221 this.createLoggly = this.createLogFn('loggly');
222 this.createHeroku = this.createLogFn('heroku');
223 this.createOpenstack = this.createLogFn('openstack');
224 this.createPapertrail = this.createLogFn('papertrail');
225 this.createScalyr = this.createLogFn('scalyr');
226 this.createSplunk = this.createLogFn('splunk');
227 this.createSumologic = this.createLogFn('sumologic');
228 this.createSyslog = this.createLogFn('syslog');
229 this.createHttps = this.createLogFn('https');
230
231 this.updateS3 = this.updateLogFn('s3');
232 this.updateS3canary = this.updateLogFn('s3canary');
233 this.updateAzureblob = this.updateLogFn('azureblob');
234 this.updateCloudfiles = this.updateLogFn('cloudfiles');
235 this.updateDigitalocean = this.updateLogFn('digitalocean');
236 this.updateFtp = this.updateLogFn('ftp');
237 this.updateBigquery = this.updateLogFn('bigquery');
238 this.updateGcs = this.updateLogFn('gcs');
239 this.updateHoneycomb = this.updateLogFn('honeycomb');
240 this.updateLogshuttle = this.updateLogFn('logshuttle');
241 this.updateLogentries = this.updateLogFn('logentries');
242 this.updateLoggly = this.updateLogFn('loggly');
243 this.updateHeroku = this.updateLogFn('heroku');
244 this.updateOpenstack = this.updateLogFn('openstack');
245 this.updatePapertrail = this.updateLogFn('papertrail');
246 this.updateScalyr = this.updateLogFn('scalyr');
247 this.updateSplunk = this.updateLogFn('splunk');
248 this.updateSumologic = this.updateLogFn('sumologic');
249 this.updateSyslog = this.updateLogFn('syslog');
250 this.updateHttps = this.updateLogFn('https');
251
252 this.writeS3 = this
253 .upsertFn(this.createS3, this.updateS3, this.readS3);
254 this.writeS3canary = this
255 .upsertFn(this.createS3canary, this.updateS3canary, this.readS3canary);
256 this.writeAzureblob = this
257 .upsertFn(this.createAzureblob, this.updateAzureblob, this.readAzureblob);
258 this.writeCloudfiles = this
259 .upsertFn(this.createCloudfiles, this.updateCloudfiles, this.readCloudfiles);
260 this.writeDigitalocean = this
261 .upsertFn(this.createDigitalocean, this.updateDigitalocean, this.readDigitalocean);
262 this.writeFtp = this
263 .upsertFn(this.createFtp, this.updateFtp, this.readFtp);
264 this.writeBigquery = this
265 .upsertFn(this.createBigquery, this.updateBigquery, this.readBigquery);
266 this.writeGcs = this
267 .upsertFn(this.createGcs, this.updateGcs, this.readGcs);
268 this.writeHoneycomb = this
269 .upsertFn(this.createHoneycomb, this.updateHoneycomb, this.readHoneycomb);
270 this.writeLogshuttle = this
271 .upsertFn(this.createLogshuttle, this.updateLogshuttle, this.readLogshuttle);
272 this.writeLogentries = this
273 .upsertFn(this.createLogentries, this.updateLogentries, this.readLogentries);
274 this.writeLoggly = this
275 .upsertFn(this.createLoggly, this.updateLoggly, this.readLoggly);
276 this.writeHeroku = this
277 .upsertFn(this.createHeroku, this.updateHeroku, this.readHeroku);
278 this.writeOpenstack = this
279 .upsertFn(this.createOpenstack, this.updateOpenstack, this.readOpenstack);
280 this.writePapertrail = this
281 .upsertFn(this.createPapertrail, this.updatePapertrail, this.readPapertrail);
282 this.writeScalyr = this
283 .upsertFn(this.createScalyr, this.updateScalyr, this.readScalyr);
284 this.writeSplunk = this
285 .upsertFn(this.createSplunk, this.updateSplunk, this.readSplunk);
286 this.writeSumologic = this
287 .upsertFn(this.createSumologic, this.updateSumologic, this.readSumologic);
288 this.writeSyslog = this
289 .upsertFn(this.createSyslog, this.updateSyslog, this.readSyslog);
290 this.writeHttps = this
291 .upsertFn(this.createHttps, this.updateHttps, this.readHttps);
292
293 this.writeVCL = this.upsertFn(this.createVCL, this.updateVCL);
294 this.writeSnippet = this.upsertFn(this.createSnippet, this.updateSnippet, this.readSnippet);
295 this.writeBackend = this.upsertFn(this.createBackend, this.updateBackend);
296
297 this.writeCondition = this.upsertFn(
298 this.createCondition,
299 this.updateCondition,
300 this.readCondition,
301 );
302
303 this.writeHeader = this.upsertFn(
304 this.createHeader,
305 this.updateHeader,
306 this.readHeader,
307 );
308
309 this.conditions = new Conditions(this);
310 this.headers = new Headers(this);
311
312 // bind the methods of the API classes.
313 [AccountAPI, AuthAPI, PurgeAPI, DomainAPI, HealthcheckAPI].forEach((API) => {
314 const api = new API(this);
315 Object.getOwnPropertyNames(API.prototype).forEach((name) => {
316 const prop = api[name];
317 if (typeof prop === 'function' && !name.startsWith('_') && name !== 'constructor') {
318 this[name] = prop.bind(api);
319 }
320 });
321 });
322
323 this.writeHealthcheck = this.upsertFn(
324 this.createHealthcheck,
325 this.updateHealthcheck,
326 this.readHealtcheck,
327 );
328 }
329
330 /**
331 * @typedef {object} FastlyError
332 * The FastlyError class describes the most common errors that can occur
333 * when working with the Fastly API. Using `error.status`, the underlying
334 * HTTP status code can be retrieved. Known error status codes include:
335 * - 400: attempting to activate invalid VCL
336 * - 401: invalid credentials
337 * - 404: resource not found
338 * - 409: confict when trying to POST a resource that already exists
339 * - 422: attempting to modify a service config that is not checked out
340 * - 429: rate limit exceeded, try again later
341 * @property {number} status The HTTP status code from the server response, e.g. 200.
342 * @property {object} data The parsed body of the HTTP response.
343 * @property {string} code A short error message.
344 * @property {string} message A more detailed error message.
345 */
346
347 /**
348 * @typedef {object} Response
349 * @property {number} status The HTTP status code from the server response, e.g. 200.
350 * @property {string} statusText The HTTP status text, e.g. 'OK'.
351 * @property {object} headers The HTTP headers of the reponse.
352 * @property {object} config The original request configuration used for the HTTP client.
353 * @property {object} request The HTTP request.
354 * @property {object} data The parsed body of the HTTP response.
355 */
356
357 /**
358 * Get a list of all Fastly datacenters.
359 *
360 * @see https://docs.fastly.com/api/tools#datacenter_1c8d3b9dd035e301155b44eae05e0554
361 * @example
362 * instance.dataCenters()
363 .then(res => {
364 console.log(res.data);
365 })
366 .catch(err => {
367 console.log(err.message);
368 });
369 * @returns {Promise} The response object representing the completion or failure.
370 */
371 dataCenters() {
372 return this.request.get('/datacenters');
373 }
374
375 /**
376 * Fastly's services IP ranges.
377 *
378 * @see https://docs.fastly.com/api/tools#public_ip_list_ef2e9900a1c9522b58f5abed92ec785e
379 * @example
380 * instance.publicIpList()
381 .then(res => {
382 console.log(res.data);
383 })
384 .catch(err => {
385 console.log(err.message);
386 });
387 * @returns {Promise} The response object representing the completion or failure.
388 */
389 publicIpList() {
390 return this.request.get('/public-ip-list');
391 }
392
393 /**
394 * Retrieve headers and MD5 hash of the content for a particular URL from each Fastly edge server.
395 *
396 * @see https://docs.fastly.com/api/tools#content_4d2d4548b29c7661e17ebe7098872d6d
397 * @example
398 * instance.edgeCheck('api.example.com')
399 .then(res => {
400 console.log(res.data);
401 })
402 .catch(err => {
403 console.log(err.message);
404 });
405 * @param {string} url - Full URL (host and path) to check on all nodes. If protocol is omitted,
406 http will be assumed.
407 * @returns {Promise} The response object representing the completion or failure.
408 */
409 edgeCheck(url = '') {
410 return this.request.get(`/content/edge_check?url=${url}`);
411 }
412
413 /**
414 * List all services.
415 *
416 * @see https://docs.fastly.com/api/config#service_74d98f7e5d018256e44d1cf820388ef8
417 * @example
418 * instance.readServices()
419 .then(res => {
420 console.log(res.data);
421 })
422 .catch(err => {
423 console.log(err.message);
424 });
425 * @returns {Promise} The response object representing the completion or failure.
426 */
427 readServices() {
428 return this.request.get('/service');
429 }
430
431 /**
432 * Reads the services and returns a data object that contains a map where the service id is
433 * the key.
434 *
435 * @returns {Promise} The response object representing the completion or failure.
436 */
437 async readServicesById() {
438 const ret = await this.request.get('/service');
439 ret.data = ret.data.reduce((dat, service) => Object.assign(dat, { [service.id]: service }), {});
440 return ret;
441 }
442
443 /**
444 * Get a specific service by id.
445 *
446 * @see https://docs.fastly.com/api/config#service_a884a9abd5af9723f6fcbb1ed13ae4cc
447 * @param {string} [serviceId] - The service id.
448 * @returns {Promise} The response object representing the completion or failure.
449 */
450 async readService(serviceId = this.service_id) {
451 return this.request.get(`/service/${serviceId}`);
452 }
453
454 /**
455 * List the versions for a particular service.
456 *
457 * @see https://docs.fastly.com/api/config#version_dfde9093f4eb0aa2497bbfd1d9415987
458 * @example
459 * instance.readVersions()
460 .then(res => {
461 const active = res.data.filter(version => version.active);
462 console.log(active);
463 })
464 .catch(err => {
465 console.log(err.message);
466 });
467 * @returns {Promise} The response object representing the completion or failure.
468 */
469 readVersions() {
470 return this.request.get(`/service/${this.service_id}/version`);
471 }
472
473 /**
474 * @typedef {object} Versions
475 *
476 * Describes the most relevant versions of the service.
477 *
478 * @property {number} latest - The latest version of the service.
479 * @property {number} active - The currently active version number.
480 * @property {number} current - The latest editable version number.
481 */
482 /**
483 * Gets the version footprint for the service.
484 *
485 * @returns {Versions} The latest, current, and active versions of the service.
486 */
487 async getVersions() {
488 if (this.versions.latest) {
489 return this.versions;
490 }
491 const { data } = await this.readVersions();
492 this.versions.initial = 1;
493 this.versions.latest = data
494 .map(({ number }) => number)
495 .pop();
496 this.versions.active = data
497 .filter((version) => version.active)
498 .map(({ number }) => number)
499 .pop();
500 this.versions.current = data
501 .filter((version) => !version.locked)
502 .map(({ number }) => number)
503 .pop();
504
505 return this.versions;
506 }
507
508 async getVersion(version, ...fallbackname) {
509 if (version) {
510 return version;
511 }
512 const versions = await this.getVersions();
513 return fallbackname.map((attempt) => versions[attempt]).filter((e) => e)[0];
514 }
515
516 /**
517 * Clone the current configuration into a new version.
518 *
519 * @param {string} version - The version to be cloned.
520 * @see https://docs.fastly.com/api/config#version_7f4937d0663a27fbb765820d4c76c709
521 * @example
522 * instance.cloneVersion('45')
523 .then(res => {
524 console.log(res.data);
525 })
526 .catch(err => {
527 console.log(err.message);
528 });
529 * @returns {Promise} The response object representing the completion or failure.
530 */
531 async cloneVersion(version) {
532 const versions = await this.request.put(`/service/${this.service_id}/version/${await this.getVersion(version, 'active', 'current', 'latest', 'initial')}/clone`);
533 this.versions.current = versions.data.number;
534 this.versions.latest = versions.data.number;
535 return versions;
536 }
537
538 /**
539 * Activate the current version.
540 *
541 * @param {string} version - The version to be activated.
542 * @see https://docs.fastly.com/api/config#version_0b79ae1ba6aee61d64cc4d43fed1e0d5
543 * @example
544 * instance.activateVersion('23')
545 .then(res => {
546 console.log(res.data);
547 })
548 .catch(err => {
549 console.log(err.message);
550 });
551 * @returns {Promise} The response object representing the completion or failure.
552 */
553 async activateVersion(version) {
554 const versions = await this.request.put(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/activate`);
555 this.versions.active = versions.data.number;
556 this.versions.latest = versions.data.number;
557 return versions;
558 }
559
560 // === start ===
561
562 /**
563 * List all dictionary items for a particular service and version.
564 *
565 * @see https://docs.fastly.com/api/config#dictionary_item_a48de28cd7e76c1ea58523f39bb7204b
566 * @example
567 * instance.readDictItems(1, 'my_dictionary')
568 .then(res => {
569 console.log(res.data);
570 })
571 .catch(err => {
572 console.log(err.message);
573 });
574 * @param {string} version - The version of the dictionary.
575 * @param {string} name - The name of the dictionary.
576 * @returns {Promise} The response object representing the completion or failure.
577 */
578 async readDictItems(version, name) {
579 return this.readDictionary(
580 await this.getVersion(version, 'latest'),
581 name,
582 ).then(({ data }) => this.request.get(`/service/${this.service_id}/dictionary/${data.id}/items`));
583 }
584
585 /**
586 * Get details of a single dictionary item.
587 *
588 * @see https://docs.fastly.com/api/config#dictionary_item_08f090cd03ed4602ae63f131087e2f29
589 * @example
590 * instance.readDictItem('12', 'extensions', 'some_key')
591 .then(res => {
592 console.log(res.data);
593 })
594 .catch(err => {
595 console.log(err.message);
596 });
597 * @param {string} version - The current version of a service.
598 * @param {string} name - Name of the dictionary.
599 * @param {string} key - The key to retrieve values by.
600 * @returns {Promise} The response object representing the completion or failure.
601 */
602 async readDictItem(version, name, key) {
603 return this.readDictionary(
604 await this.getVersion(version, 'latest'),
605 name,
606 ).then(({ data }) => {
607 if (data.write_only) {
608 return {
609 status: 403, // not permitted to read from write-only dicts
610 data: {
611 dictionary_id: data.id,
612 service_id: this.service_id,
613 item_key: key,
614 item_value: undefined,
615 created_at: undefined,
616 deleted_at: undefined,
617 updated_at: undefined,
618 },
619 };
620 }
621 // always use uncached version here
622 return this.request.get.fresh(`/service/${this.service_id}/dictionary/${data.id}/item/${encodeURIComponent(key)}`);
623 });
624 }
625
626 /**
627 * Create a new dictionary item for a particular service and version.
628 *
629 * @see https://docs.fastly.com/api/config#dictionary_item_6ec455c0ba1b21671789e1362bc7fe55
630 * @param {number} version - The version number (current if omitted).
631 * @param {object} name - The dictionary definition.
632 * @param {string} key - The key.
633 * @param {string} value - The value to write.
634 * @returns {Promise} The reponse object.
635 */
636 async createDictItem(version, name, key, value) {
637 return this.readDictionary(
638 await this.getVersion(version, 'latest'),
639 name,
640 ).then(({ data }) => this.request.post(`/service/${this.service_id}/dictionary/${data.id}/item`, {
641 item_key: key,
642 item_value: value,
643 }));
644 }
645
646 /**
647 * @typedef {object} DictUpdate
648 * Specifies a dictionary update operation. In most cases, `upsert` is the best way
649 * to update values, as it will work for existing and non-existing items.
650 * @property {string} op - The operation: `create`, `update`, `delete`, or `upsert`.
651 * @property {string} item_key - The lookup key.
652 * @property {string} item_value - The dictionary value.
653 */
654 /**
655 * Updates multiple dictionary items in bulk.
656 *
657 * @param {number} version - The version numer (current if ommitted).
658 * @param {string} name - Name of the dictionary.
659 * @param {...DictUpdate} items - The dictionary update operations.
660 * @returns {Promise} The response object.
661 * @example
662 * // single item
663 * fastly.bulkUpdateDictItems(1, 'secret_dictionary',
664 * { item_key: 'some_key', item_value: 'some_value', op: 'upsert' });
665 *
666 * // multiple items
667 * fastly.bulkUpdateDictItems(1, 'secret_dictionary',
668 * { item_key: 'some_key', item_value: 'some_value', op: 'update' },
669 * { item_key: 'other_key', item_value: 'other_value', op: 'update' });
670 */
671 async bulkUpdateDictItems(version, name, ...items) {
672 return this.readDictionary(
673 await this.getVersion(version, 'latest'),
674 name,
675 ).then(({ data }) => this.request.patch(`/service/${this.service_id}/dictionary/${data.id}/items`, {
676 items,
677 }));
678 }
679
680 /**
681 * Update a dictionary item value for a particular service and version.
682 *
683 * @see https://docs.fastly.com/api/config#dictionary_item_34c884a7cdce84dfcfd38dac7a0b5bb0
684 * @example
685 * instance.updateDictItem(1, 'extensions', 'html', 'text/html')
686 .then(res => {
687 console.log(res.data);
688 })
689 .catch(err => {
690 console.log(err.message);
691 });
692 * @param {string} version - The current version of a service.
693 * @param {string} name - The name of the dictionary.
694 * @param {string} key - The key to update data under.
695 * @param {string} value - The value to update the dictionary with.
696 * @returns {Promise} The response object representing the completion or failure.
697 */
698 async updateDictItem(version, name, key, value) {
699 return this.readDictionary(
700 await this.getVersion(version, 'latest'),
701 name,
702 ).then(({ data }) => this.request.put(`/service/${this.service_id}/dictionary/${data.id}/item/${encodeURIComponent(key)}`, {
703 item_value: value,
704 }));
705 }
706
707 /**
708 * Delete a dictionary item for a particular service and version.
709 *
710 * @see https://docs.fastly.com/api/config#dictionary_item_664347e743b8eafc9a93c729d9da0427
711 * @example
712 * instance.deleteDictItem('34', 'extensions', 'html')
713 .then(res => {
714 console.log(res.data);
715 })
716 .catch(err => {
717 console.log(err.message);
718 });
719 * @param {string} version - The current version of a service.
720 * @param {string} name - The name of the dictionary.
721 * @param {string} key - The key to update data under.
722 * @returns {Promise} The response object representing the completion or failure.
723 */
724 async deleteDictItem(version, name, key) {
725 return this.readDictionary(
726 await this.getVersion(version, 'latest'),
727 name,
728 ).then(({ data }) => this.request.delete(`/service/${this.service_id}/dictionary/${data.id}/item/${encodeURIComponent(key)}`));
729 }
730
731 /**
732 * Safely create, update or delete a dictionary item in a named dictionary.
733 *
734 * @param {number} version - Service version to use for dictionary lookup.
735 * @param {string} name - Name of the dictionary (not ID).
736 * @param {string} key - Key to create, update or delete.
737 * @param {string} value - Value to update. Empty strings will delete the dictionary entry.
738 * @returns {Promise} The response object representing the completion or failure.
739 */
740 writeDictItem(version, name, key, value) {
741 return this.readDictItem(version, name, key)
742 .then(() => {
743 // the dictionary item already exists
744 if (value) {
745 // update existing value
746 return this.updateDictItem(version, name, key, value);
747 }
748 // value is undefined. Fastly does not support overwriting with empty
749 // values, so we delete the value
750 return this.deleteDictItem(version, name, key);
751 })
752 .catch(() => {
753 // the dictionary item does not exist
754 if (value) {
755 return this.createDictItem(version, name, key, value);
756 }
757 // the item does not exist and there is no data to write, we just pretend it went ok
758 return {
759 status: 200,
760 data: {
761 status: 'ok',
762 },
763 };
764 });
765 }
766
767 // === done ===
768
769 /**
770 * List all dictionaries for a particular service and version.
771 *
772 * @see https://docs.fastly.com/api/config#dictionary_6d2cc293b994eb8c16d93e92e91f3915
773 * @example
774 * instance.readDictionaries('12')
775 .then(res => {
776 console.log(res.data);
777 })
778 .catch(err => {
779 console.log(err.message);
780 });
781 * @param {string} version - The current version of a service.
782 * @returns {Promise} The response object representing the completion or failure.
783 */
784 async readDictionaries(version) {
785 return this.request.get(`/service/${this.service_id}/version/${await this.getVersion(version, 'latest')}/dictionary`);
786 }
787
788 /**
789 * Get details of a single dictionary.
790 *
791 * @see https://docs.fastly.com/api/config#dictionary_0e16df083830ed3b6c30b73dcef64014
792 * @example
793 * instance.readDictionary('12', 'extensions')
794 .then(res => {
795 console.log(res.data);
796 })
797 .catch(err => {
798 console.log(err.message);
799 });
800 * @param {string} version - The current version of a service.
801 * @param {string} name - Name of the dictionary.
802 * @returns {Promise} The response object representing the completion or failure.
803 */
804 async readDictionary(version, name) {
805 return this.request.get(`/service/${this.service_id}/version/${await this.getVersion(version, 'latest')}/dictionary/${name}`);
806 }
807
808 /**
809 * Create a new dictionary for a particular service and version.
810 *
811 * @see https://docs.fastly.com/api/config#dictionary_7d48b87bf82433162a3b209292722125
812 * @param {number} version - The version number (current if omitted).
813 * @param {object} data - The dictionary definition.
814 * @returns {Promise} The reponse object.
815 */
816 async createDictionary(version, data) {
817 return this.request.post(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/dictionary`, data);
818 }
819
820 /**
821 * Update a dictionary for a particular service and version.
822 *
823 * @see https://docs.fastly.com/api/config#dictionary_8c9da370b1591d99e5389143a5589a32
824 * @example
825 * instance.updateDictionary('34', 'old-name', { name: 'new-name' })
826 .then(res => {
827 console.log(res.data);
828 })
829 .catch(err => {
830 console.log(err.message);
831 });
832 * @param {string} version - The current version of a service.
833 * @param {string} name - The name of the dictionary.
834 * @param {object} data - The data to be sent as the request body.
835 * @returns {Promise} The response object representing the completion or failure.
836 */
837 async updateDictionary(version, name, data) {
838 return this.request.put(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/dictionary/${encodeURIComponent(name)}`, data);
839 }
840
841 async writeDictionary(version, name, data) {
842 try {
843 const existing = await this.readDictionary(version, name);
844 // keep the write-only status
845 const mydata = {
846 name: data.name,
847 write_only: existing.data.write_only,
848 };
849 if (mydata.name && mydata.name !== existing.data.name) {
850 return this.updateDictionary(version, name, mydata);
851 }
852 return existing;
853 } catch (e) {
854 return this.createDictionary(version, data);
855 }
856 }
857
858 /**
859 * Delete a dictionary for a particular service and version.
860 *
861 * @see https://docs.fastly.com/api/config#dictionary_8c9da370b1591d99e5389143a5589a32
862 * @example
863 * instance.deleteDictionary('34', 'extensions')
864 .then(res => {
865 console.log(res.data);
866 })
867 .catch(err => {
868 console.log(err.message);
869 });
870 * @param {string} version - The current version of a service.
871 * @param {string} name - The name of the dictionary.
872 * @returns {Promise} The response object representing the completion or failure.
873 */
874 async deleteDictionary(version, name) {
875 return this.request.delete(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/dictionary/${encodeURIComponent(name)}`);
876 }
877
878 /* ==CONDITIONS */
879
880 /**
881 * List all conditions for a particular service and version.
882 *
883 * @see https://docs.fastly.com/api/config#condition_b61196c572f473c89863a81cc5912861
884 * @example
885 * instance.readConditions('12')
886 .then(res => {
887 console.log(res.data);
888 })
889 .catch(err => {
890 console.log(err.message);
891 });
892 * @param {string} version - The current version of a service.
893 * @returns {Promise} The response object representing the completion or failure.
894 */
895 async readConditions(version) {
896 return this.request.get(`/service/${this.service_id}/version/${await this.getVersion(version, 'latest')}/condition`);
897 }
898
899 /**
900 * Get details of a single named condition.
901 *
902 * @see https://docs.fastly.com/api/config#condition_149a2f48485ceb335f70504e5269b77e
903 * @example
904 * instance.readCondition('12', 'returning')
905 .then(res => {
906 console.log(res.data);
907 })
908 .catch(err => {
909 console.log(err.message);
910 });
911 * @param {string} version - The current version of a service.
912 * @param {string} name - Name of the condition.
913 * @returns {Promise} The response object representing the completion or failure.
914 */
915 async readCondition(version, name) {
916 return this.request.get(`/service/${this.service_id}/version/${await this.getVersion(version, 'latest')}/condition/${name}`);
917 }
918
919 /**
920 * Get details of a single named snippet.
921 *
922 * @see https://developer.fastly.com/reference/api/vcl-services/snippet/
923 * @example
924 * instance.readSnippet('12', 'returning')
925 .then(res => {
926 console.log(res.data);
927 })
928 .catch(err => {
929 console.log(err.message);
930 });
931 * @param {string} version - The current version of a service.
932 * @param {string} name - Name of the snippet.
933 * @returns {Promise} The response object representing the completion or failure.
934 */
935 async readSnippet(version, name) {
936 return this.request.get(`/service/${this.service_id}/version/${await this.getVersion(version, 'latest')}/snippet/${name}`);
937 }
938
939 /**
940 * Create a new condition for a particular service and version.
941 *
942 * @see https://docs.fastly.com/api/config#condition_551199dbec2271195319b675d8659226
943 * @param {number} version - The version number (current if omitted).
944 * @param {object} data - The condition definition.
945 * @returns {Promise} The reponse object.
946 */
947 async createCondition(version, data) {
948 return this.request.post(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/condition`, data);
949 }
950
951 /**
952 * Update a condition for a particular service and version.
953 *
954 * @see https://docs.fastly.com/api/config#condition_01a2c4e4b44943b541e001013b665deb
955 * @example
956 * instance.updateCondition('34', 'returning', { name: 'returning-visitor' })
957 .then(res => {
958 console.log(res.data);
959 })
960 .catch(err => {
961 console.log(err.message);
962 });
963 * @param {string} version - The current version of a service.
964 * @param {string} name - The name of the condition.
965 * @param {object} data - The data to be sent as the request body.
966 * @returns {Promise} The response object representing the completion or failure.
967 */
968 async updateCondition(version, name, data) {
969 const mydata = { ...data };
970 // cannot change type of condition
971 delete mydata.type;
972 return this.request.put(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/condition/${encodeURIComponent(name)}`, data);
973 }
974
975 /**
976 * Delete a condition for a particular service and version.
977 *
978 * @see https://docs.fastly.com/api/config#condition_2b902b7649c46b4541f00a920d06c94d
979 * @example
980 * instance.deleteCondition('34', 'extensions')
981 .then(res => {
982 console.log(res.data);
983 })
984 .catch(err => {
985 console.log(err.message);
986 });
987 * @param {string} version - The current version of a service.
988 * @param {string} name - The name of the condition.
989 * @returns {Promise} The response object representing the completion or failure.
990 */
991 async deleteCondition(version, name) {
992 return this.request.delete(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/condition/${encodeURIComponent(name)}`);
993 }
994
995 /* == HEADERS */
996
997 /**
998 * List all headers for a particular service and version.
999 *
1000 * @see https://docs.fastly.com/api/config#header_dd9da0592b2f1ff8ef0a4c1943f8abff
1001 * @example
1002 * instance.readHeaders('12')
1003 .then(res => {
1004 console.log(res.data);
1005 })
1006 .catch(err => {
1007 console.log(err.message);
1008 });
1009 * @param {string} version - The current version of a service.
1010 * @returns {Promise} The response object representing the completion or failure.
1011 */
1012 async readHeaders(version) {
1013 return this.request.get(`/service/${this.service_id}/version/${await this.getVersion(version, 'latest')}/header`);
1014 }
1015
1016 /**
1017 * Get details of a single named header.
1018 *
1019 * @see https://docs.fastly.com/api/config#header_86469e5eba4e5d6b1463e81f82a847e0
1020 * @example
1021 * instance.readHeader('12', 'returning')
1022 .then(res => {
1023 console.log(res.data);
1024 })
1025 .catch(err => {
1026 console.log(err.message);
1027 });
1028 * @param {string} version - The current version of a service.
1029 * @param {string} name - Name of the header.
1030 * @returns {Promise} The response object representing the completion or failure.
1031 */
1032 async readHeader(version, name) {
1033 return this.request.get(`/service/${this.service_id}/version/${await this.getVersion(version, 'latest')}/header/${name}`);
1034 }
1035
1036 /**
1037 * Create a new header for a particular service and version.
1038 *
1039 * @see https://docs.fastly.com/api/config#header_151df4ce647a8e222e730b260287cb39
1040 * @param {number} version - The version number (current if omitted).
1041 * @param {object} data - The header definition.
1042 * @returns {Promise} The reponse object.
1043 */
1044 async createHeader(version, data) {
1045 return this.request.post(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/header`, data);
1046 }
1047
1048 /**
1049 * Update a header for a particular service and version.
1050 *
1051 * @see https://docs.fastly.com/api/config#header_c4257a0fd0eb017ea47b1fbb318fd61c
1052 * @example
1053 * instance.updateHeader('34', 'returning', { name: 'returning-visitor' })
1054 .then(res => {
1055 console.log(res.data);
1056 })
1057 .catch(err => {
1058 console.log(err.message);
1059 });
1060 * @param {string} version - The current version of a service.
1061 * @param {string} name - The name of the header.
1062 * @param {object} data - The data to be sent as the request body.
1063 * @returns {Promise} The response object representing the completion or failure.
1064 */
1065 async updateHeader(version, name, data) {
1066 return this.request.put(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/header/${encodeURIComponent(name)}`, data);
1067 }
1068
1069 /**
1070 * Delete a header for a particular service and version.
1071 *
1072 * @see https://docs.fastly.com/api/config#header_4bbb73fffda4d189bf5a19b474399a83
1073 * @example
1074 * instance.deleteHeader('34', 'extensions')
1075 .then(res => {
1076 console.log(res.data);
1077 })
1078 .catch(err => {
1079 console.log(err.message);
1080 });
1081 * @param {string} version - The current version of a service.
1082 * @param {string} name - The name of the header.
1083 * @returns {Promise} The response object representing the completion or failure.
1084 */
1085 async deleteHeader(version, name) {
1086 return this.request.delete(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/header/${encodeURIComponent(name)}`);
1087 }
1088
1089 /**
1090 * List all backends for a particular service and version.
1091 *
1092 * @see https://docs.fastly.com/api/config#backend_fb0e875c9a7669f071cbf89ca32c7f69
1093 * @example
1094 * instance.readBackends('12')
1095 .then(res => {
1096 console.log(res.data);
1097 })
1098 .catch(err => {
1099 console.log(err.message);
1100 });
1101 * @param {string} version - The current version of a service.
1102 * @returns {Promise} The response object representing the completion or failure.
1103 */
1104 async readBackends(version) {
1105 return this.request.get(`/service/${this.service_id}/version/${await this.getVersion(version, 'latest')}/backend`);
1106 }
1107
1108 /**
1109 * Update the backend for a particular service and version.
1110 *
1111 * @see https://docs.fastly.com/api/config#backend_fb3b3529417c70f57458644f7aec652e
1112 * @example
1113 * instance.updateBackend('34', 'slow-server', { name: 'fast-server' })
1114 .then(res => {
1115 console.log(res.data);
1116 })
1117 .catch(err => {
1118 console.log(err.message);
1119 });
1120 * @param {string} version - The current version of a service.
1121 * @param {string} name - The name of the backend.
1122 * @param {object} data - The data to be sent as the request body.
1123 * @returns {Promise} The response object representing the completion or failure.
1124 */
1125 async updateBackend(version, name, data) {
1126 return this.request.put(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/backend/${encodeURIComponent(name)}`, data);
1127 }
1128
1129 /**
1130 * Create a new backend for a particular service and version.
1131 *
1132 * @see https://docs.fastly.com/api/config#backend_85c170418ee71191dbb3b5046aeb6c2c
1133 * @param {number} version - The version number (current if omitted).
1134 * @param {object} data - The backend definition.
1135 * @returns {Promise} The reponse object.
1136 */
1137 async createBackend(version, data) {
1138 return this.request.post(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/backend`, data);
1139 }
1140 /**
1141 * @typedef {object} Snippet
1142 * @property {string} name The name of the snippet, as visible in the Fastly UI.
1143 * @property {string} content The VCL body of the snippet.
1144 */
1145
1146 /**
1147 * List all snippets for a particular service and version.
1148 *
1149 * @see https://docs.fastly.com/api/config#api-section-snippet
1150 * @example
1151 * instance.readSnippets('12')
1152 .then(res => {
1153 console.log(res.data);
1154 })
1155 .catch(err => {
1156 console.log(err.message);
1157 });
1158 * @param {string} version - The current version of a service.
1159 * @returns {Promise} The response object representing the completion or failure.
1160 */
1161 async readSnippets(version) {
1162 return this.request.get(`/service/${this.service_id}/version/${await this.getVersion(version, 'latest')}/snippet`);
1163 }
1164
1165 /**
1166 * Create a snippet for a particular service and version.
1167 *
1168 * @see https://docs.fastly.com/api/config#snippet_41e0e11c662d4d56adada215e707f30d
1169 * @example
1170 * instance.createSnippet('36', {
1171 name: 'your_snippet',
1172 priority: 10,
1173 dynamic: 1,
1174 content: 'table referer_blacklist {}',
1175 type: 'init'
1176 })
1177 .then(res => {
1178 console.log(res.data);
1179 })
1180 .catch(err => {
1181 console.log(err.message);
1182 });
1183 * @param {string} version - The current version of a service.
1184 * @param {Snippet} data - The data to be sent as the request body.
1185 * @returns {Promise} The response object representing the completion or failure.
1186 */
1187 async createSnippet(version, data) {
1188 return this.request.post(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/snippet`, data);
1189 }
1190
1191 /**
1192 * Update a VCL snippet for a particular service and version.
1193 *
1194 * @param {string} version - The current version of a service.
1195 * @param {string} name - The name of the snippet to update.
1196 * @param {Snippet} data - The data to be sent as the request body.
1197 * @returns {Promise} The response object representing the completion or failure.
1198 */
1199 async updateSnippet(version, name, data) {
1200 const mydata = { ...data };
1201 delete mydata.type;
1202 return this.request.put(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/snippet/${name}`, mydata);
1203 }
1204
1205 /**
1206 * @typedef {object} VCL
1207 * @property {string} name The name of the VCL, as visible in the Fastly UI.
1208 * Note: setting the name to 'main' here won't make it the main VCL,
1209 * unless you also call `setMainVCL`.
1210 * @property {string} content The VCL body of the custom VCL.
1211 */
1212
1213 /**
1214 * Create custom VCL for a particular service and version.
1215 *
1216 * @see https://docs.fastly.com/api/config#vcl_7ade6ab5926b903b6acf3335a85060cc
1217 * @param {string} version - The current version of a service.
1218 * @param {VCL} data - The data to be sent as the request body.
1219 * @returns {Promise} The response object representing the completion or failure.
1220 */
1221 async createVCL(version, data) {
1222 return this.request.post(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/vcl`, data);
1223 }
1224
1225 /**
1226 * Update custom VCL for a particular service and version.
1227 *
1228 * @see https://docs.fastly.com/api/config#vcl_0971365908e17086751c5ef2a8053087
1229 * @param {string} version - The current version of a service.
1230 * @param {string} name - The name of the VCL to update.
1231 * @param {VCL} data - The data to be sent as the request body.
1232 * @returns {Promise} The response object representing the completion or failure.
1233 */
1234 async updateVCL(version, name, data) {
1235 if (typeof name === 'object') {
1236 /* eslint-disable no-param-reassign */
1237 data = name;
1238 name = data.name;
1239 /* eslint-enable no-param-reassign */
1240 }
1241 return this.request.put(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/vcl/${name}`, data);
1242 }
1243
1244 /**
1245 * Define a custom VCL to be the main VCL for a particular service and version.
1246 *
1247 * @see https://docs.fastly.com/api/config#vcl_5576c38e7652f5a7261bfcad41c0faf1
1248 * @param {string} version - The current version of a service.
1249 * @param {string} name - The name of the VCL to declare main.
1250 * @returns {Promise} The response object representing the completion or failure.
1251 */
1252 async setMainVCL(version, name) {
1253 return this.request.put(`/service/${this.service_id}/version/${await this.getVersion(version, 'current')}/vcl/${name}/main`, {});
1254 }
1255
1256 /**
1257 * Creates a new version, runs the function `operations` and then
1258 * optionally activates the newly created version. This function
1259 * is useful for making modifications to a service config.
1260 *
1261 * You can provide a `limit` of write operations, which is an estimate
1262 * of the number of write operations that will be attempted. If the
1263 * limit is higher than the number of actions allowed by Fastly's rate
1264 * limits, the function will fail fast after cloning the service config.
1265 *
1266 * @example
1267 * ```javascript
1268 * await fastly.transact(async (newversion) => {
1269 * await fastly.doSomething(newversion);
1270 * });
1271 * // new version has been activated
1272 * ```
1273 * @param {Function} operations - A function that performs changes on the service config.
1274 * @param {boolean} activate - Set to false to prevent automatic activation.
1275 * @param {number} limit - Number of write operations that will be performed in this action.
1276 * @returns {object} The return value of the wrapped function.
1277 */
1278 async transact(operations, activate = true, limit = 0) {
1279 const newversion = (await this.cloneVersion()).data.number;
1280 if (limit > 0 && this.requestmonitor.remaining && this.requestmonitor.remaining < limit) {
1281 throw new RateLimitError(`Insufficient number of requests (${this.requestmonitor.remaining}) remaining for number of scheduled operations (${limit})`);
1282 }
1283 const result = await operations.apply(this, [newversion]);
1284 if (activate) {
1285 await this.activateVersion(newversion);
1286 }
1287 return result;
1288 }
1289
1290 /**
1291 * See `transact`, but this version does not activate the created version.
1292 *
1293 * @see #transact
1294 * @param {Function} operations - The operations that should be applied to the
1295 * cloned service config version.
1296 * @returns {object} Whatever `operations` returns.
1297 */
1298 async dryrun(operations) {
1299 return this.transact(operations, false);
1300 }
1301}
1302
1303/**
1304 * Function to create a new fastly-promises instance.
1305 *
1306 * @param {string} token - The Fastly API token.
1307 * @param {string} service_id - The Fastly service ID.
1308 * @returns {Fastly} The exported module.
1309 */
1310module.exports = (token, service_id) => new Fastly(token, service_id);