@centia-io/sdk 0.2.14 → 0.2.16

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/README.md CHANGED
@@ -602,6 +602,88 @@ await features.deleteFeature('my_schema', 'my_table', [1, 2, 3])
602
602
 
603
603
  `srs` on `postFeature`/`patchFeature` declares the SRID of the *incoming* geometry. Reading requires a key — use the SQL or WFS APIs to query whole collections. PUT is not supported.
604
604
 
605
+ ## Snapshots (GeoParquet exports)
606
+
607
+ `Snapshots` wraps the snapshot API: asynchronous GeoParquet exports of a table or view to S3, and read access to the published snapshot files. It takes a `CentiaHttpClient` and requires a Bearer token:
608
+
609
+ ```ts
610
+ import { createCentiaClient, Snapshots } from '@centia-io/sdk'
611
+
612
+ const snapshots = new Snapshots(http)
613
+
614
+ // Queue an export (202; super-user only). The export runs asynchronously.
615
+ const { id } = await snapshots.postSnapshot({ schema: 'geodanmark', relation: 'bygning', srs: 25832 })
616
+
617
+ // Or queue several at once (all-or-nothing; accepted jobs come back in request order).
618
+ // getSnapshot also accepts an array of ids.
619
+ const accepted = await snapshots.postSnapshot([
620
+ { schema: 'geodanmark', relation: 'bygning' },
621
+ { schema: 'geodanmark', relation: 'vej' },
622
+ ])
623
+ const both = await snapshots.getSnapshot(accepted.map((a) => a.id))
624
+
625
+ // Poll until it finishes (succeeded/failed/superseded) — or use getSnapshot(id) yourself
626
+ const job = await snapshots.waitForSnapshot(id, { intervalMs: 2000, timeoutMs: 300_000 })
627
+ if (job.status === 'failed') throw new Error(job.error ?? 'export failed')
628
+
629
+ // List jobs, optionally filtered (super-user only)
630
+ const jobs = await snapshots.getSnapshots({ schema: 'geodanmark', relation: 'bygning' })
631
+
632
+ // Read API — any user with read access to the relation:
633
+ const published = await snapshots.getRelationSnapshots('geodanmark', 'bygning') // newest first
634
+ const meta = await snapshots.getRelationSnapshot('geodanmark', 'bygning', '2026-09-16')
635
+
636
+ // The Parquet file itself. dataUrl for DuckDB/GDAL/plain fetch; the data
637
+ // methods return the raw Response (stream or buffer it yourself) and follow
638
+ // the 302 redirect to presigned storage URLs.
639
+ const url = snapshots.getRelationSnapshotDataUrl('geodanmark', 'bygning', '2026-09-16')
640
+ const head = await snapshots.headRelationSnapshotData('geodanmark', 'bygning', '2026-09-16') // Content-Length/ETag
641
+ const part = await snapshots.getRelationSnapshotData('geodanmark', 'bygning', '2026-09-16', { range: [0, 1023] })
642
+ const file = await snapshots.getRelationSnapshotFile('geodanmark', 'bygning', '2026-09-16', 'metadata-<id>.json')
643
+ ```
644
+
645
+ The job API is super-user only (403 `SUPER_USER_ONLY`); creating throws 404 (relation not found), 409 (a snapshot of the relation is already pending or running) or 501 (snapshot storage not configured). The read API needs read access to the relation — sub-users with a deny/limit geofence rule get 403 `GEOFENCE_RULES_APPLY`. A snapshot with several data files answers 409 `MULTI_FILE_SNAPSHOT` on `/data`; list `files` in the metadata and fetch them with `getRelationSnapshotFile`.
646
+
647
+ ## Scheduler (recurring imports)
648
+
649
+ `Scheduler` wraps the scheduler API: cron-scheduled data-import jobs and their runs. Super-user only. It takes a `CentiaHttpClient` and requires a Bearer token:
650
+
651
+ ```ts
652
+ import { createCentiaClient, Scheduler } from '@centia-io/sdk'
653
+
654
+ const scheduler = new Scheduler(http)
655
+
656
+ // Create one or more jobs (201; arrays are all-or-nothing). The new ids are
657
+ // parsed from the Location header, in request order.
658
+ const { ids } = await scheduler.postSchedulerJob({
659
+ name: 'import buildings',
660
+ schema: 'geodanmark',
661
+ url: 'https://example.com/data.zip',
662
+ schedule: '0 3 * * *', // 5-field cron
663
+ epsg: 25832, // defaults: epsg 4326, type "AUTO", encoding "UTF8",
664
+ }) // delete_append false, download_schema true, active true, snapshot false
665
+
666
+ // Read jobs — a single id returns one job, an array returns an array
667
+ const jobs = await scheduler.getSchedulerJobs()
668
+ const job = await scheduler.getSchedulerJob(ids[0])
669
+ const some = await scheduler.getSchedulerJob([5497, 5498])
670
+
671
+ // Update / delete (delete is all-or-nothing; 409 if a run is in progress)
672
+ await scheduler.patchSchedulerJob(ids[0], { active: false })
673
+ await scheduler.deleteSchedulerJob([5497, 5498])
674
+
675
+ // Runs. Starting is asynchronous (202) — poll getSchedulerRuns until it finishes.
676
+ await scheduler.postSchedulerRun({ job: ids[0], force: true }) // force ignores delete_append and overwrites
677
+ const runs = await scheduler.getSchedulerRuns({ job: ids[0], status: 'running' })
678
+ const run = await scheduler.getSchedulerRun(runs[0].uuid)
679
+
680
+ // Stop a running run: SIGINT, escalated to SIGKILL by the server after 30 s.
681
+ // The request itself can take up to ~30 s — do not use a short timeout.
682
+ const { signal } = await scheduler.deleteSchedulerRun(runs[0].uuid)
683
+ ```
684
+
685
+ Errors throw `CentiaApiError` with status/code: 400 `INVALID_CRON_FIELD`/`INPUT_VALIDATION_ERROR`, 404 `JOB_NOT_FOUND`/`RUN_NOT_FOUND`, 409 `JOB_RUNNING`.
686
+
605
687
  ## Error handling
606
688
 
607
689
  - Network/HTTP errors: thrown as `Error` with the status/body text when available.
@@ -707,6 +707,52 @@ var CentiaHttpClient = class {
707
707
  getHeader: (name) => response.headers.get(name)
708
708
  };
709
709
  }
710
+ /**
711
+ * Execute a request and return the raw Response without consuming the body.
712
+ * For binary endpoints (file downloads): follows redirects (a presigned
713
+ * storage URL — the fetch spec strips Authorization on cross-origin
714
+ * redirects), sends no Content-Type, and supports extra request headers
715
+ * such as Range. Throws CentiaApiError on a status not in expectedStatus.
716
+ */
717
+ async requestRaw(opts) {
718
+ var _this3 = this;
719
+ var _opts$accept, _opts$expectedStatus2;
720
+ const url = _this3.buildUrl(opts.path, opts.query);
721
+ const headers = { "Accept": (_opts$accept = opts.accept) !== null && _opts$accept !== void 0 ? _opts$accept : "*/*" };
722
+ if (_this3.auth.getAccessToken) {
723
+ const token = await _this3.auth.getAccessToken();
724
+ if (token) headers["Authorization"] = `Bearer ${token}`;
725
+ }
726
+ if (_this3.auth.getHeaders) Object.assign(headers, await _this3.auth.getHeaders());
727
+ if (_this3.userAgent && typeof navigator === "undefined") headers["User-Agent"] = _this3.userAgent;
728
+ Object.assign(headers, opts.headers);
729
+ const response = await _this3.fetchFn(url, {
730
+ method: opts.method,
731
+ headers,
732
+ redirect: "follow"
733
+ });
734
+ if (!((_opts$expectedStatus2 = opts.expectedStatus) !== null && _opts$expectedStatus2 !== void 0 ? _opts$expectedStatus2 : [200]).includes(response.status)) {
735
+ var _ref, _parsed$message, _response$headers$get;
736
+ let bodyText = "";
737
+ try {
738
+ bodyText = await response.text();
739
+ } catch (_unused) {}
740
+ let parsed = null;
741
+ if (bodyText) try {
742
+ parsed = JSON.parse(bodyText);
743
+ } catch (_unused2) {}
744
+ throw new CentiaApiError({
745
+ message: ((_ref = (_parsed$message = parsed === null || parsed === void 0 ? void 0 : parsed.message) !== null && _parsed$message !== void 0 ? _parsed$message : parsed === null || parsed === void 0 ? void 0 : parsed.error) !== null && _ref !== void 0 ? _ref : bodyText) || `Unexpected status ${response.status}`,
746
+ status: response.status,
747
+ code: parsed === null || parsed === void 0 ? void 0 : parsed.code,
748
+ details: parsed,
749
+ requestId: (_response$headers$get = response.headers.get("x-request-id")) !== null && _response$headers$get !== void 0 ? _response$headers$get : void 0,
750
+ method: opts.method,
751
+ url
752
+ });
753
+ }
754
+ return response;
755
+ }
710
756
  buildUrl(path, query) {
711
757
  const cleanPath = path.replace(/^\/+/, "");
712
758
  let url = `${this.baseUrl}/${cleanPath}`;
@@ -717,19 +763,19 @@ var CentiaHttpClient = class {
717
763
  return url;
718
764
  }
719
765
  async buildHeaders(opts) {
720
- var _this3 = this;
721
- var _opts$accept;
722
- const headers = { "Accept": (_opts$accept = opts.accept) !== null && _opts$accept !== void 0 ? _opts$accept : "application/json" };
723
- if (_this3.auth.getAccessToken) {
724
- const token = await _this3.auth.getAccessToken();
766
+ var _this4 = this;
767
+ var _opts$accept2;
768
+ const headers = { "Accept": (_opts$accept2 = opts.accept) !== null && _opts$accept2 !== void 0 ? _opts$accept2 : "application/json" };
769
+ if (_this4.auth.getAccessToken) {
770
+ const token = await _this4.auth.getAccessToken();
725
771
  if (token) headers["Authorization"] = `Bearer ${token}`;
726
772
  }
727
- if (_this3.auth.getHeaders) {
728
- const authHeaders = await _this3.auth.getHeaders();
773
+ if (_this4.auth.getHeaders) {
774
+ const authHeaders = await _this4.auth.getHeaders();
729
775
  Object.assign(headers, authHeaders);
730
776
  }
731
- if (_this3.userAgent && typeof navigator === "undefined") headers["User-Agent"] = _this3.userAgent;
732
- const ct = _this3.resolveContentType(opts.contentType);
777
+ if (_this4.userAgent && typeof navigator === "undefined") headers["User-Agent"] = _this4.userAgent;
778
+ const ct = _this4.resolveContentType(opts.contentType);
733
779
  if (ct) headers["Content-Type"] = ct;
734
780
  return headers;
735
781
  }
@@ -738,24 +784,24 @@ var CentiaHttpClient = class {
738
784
  return contentType !== null && contentType !== void 0 ? contentType : "application/json";
739
785
  }
740
786
  async handleResponse(response, opts, url) {
741
- var _opts$expectedStatus2, _parsed;
742
- const expectedStatus = (_opts$expectedStatus2 = opts.expectedStatus) !== null && _opts$expectedStatus2 !== void 0 ? _opts$expectedStatus2 : 200;
787
+ var _opts$expectedStatus3, _parsed;
788
+ const expectedStatus = (_opts$expectedStatus3 = opts.expectedStatus) !== null && _opts$expectedStatus3 !== void 0 ? _opts$expectedStatus3 : 200;
743
789
  let bodyText = "";
744
790
  try {
745
791
  bodyText = await response.text();
746
- } catch (_unused) {}
792
+ } catch (_unused3) {}
747
793
  let parsed = null;
748
794
  if (bodyText) try {
749
795
  parsed = JSON.parse(bodyText);
750
- } catch (_unused2) {}
796
+ } catch (_unused4) {}
751
797
  if (response.status !== expectedStatus) {
752
- var _ref, _parsed$message, _response$headers$get;
798
+ var _ref2, _parsed$message2, _response$headers$get2;
753
799
  throw new CentiaApiError({
754
- message: ((_ref = (_parsed$message = parsed === null || parsed === void 0 ? void 0 : parsed.message) !== null && _parsed$message !== void 0 ? _parsed$message : parsed === null || parsed === void 0 ? void 0 : parsed.error) !== null && _ref !== void 0 ? _ref : bodyText) || `Unexpected status ${response.status}`,
800
+ message: ((_ref2 = (_parsed$message2 = parsed === null || parsed === void 0 ? void 0 : parsed.message) !== null && _parsed$message2 !== void 0 ? _parsed$message2 : parsed === null || parsed === void 0 ? void 0 : parsed.error) !== null && _ref2 !== void 0 ? _ref2 : bodyText) || `Unexpected status ${response.status}`,
755
801
  status: response.status,
756
802
  code: parsed === null || parsed === void 0 ? void 0 : parsed.code,
757
803
  details: parsed,
758
- requestId: (_response$headers$get = response.headers.get("x-request-id")) !== null && _response$headers$get !== void 0 ? _response$headers$get : void 0,
804
+ requestId: (_response$headers$get2 = response.headers.get("x-request-id")) !== null && _response$headers$get2 !== void 0 ? _response$headers$get2 : void 0,
759
805
  method: opts.method,
760
806
  url
761
807
  });
@@ -3386,6 +3432,265 @@ var Features = class {
3386
3432
  }
3387
3433
  };
3388
3434
 
3435
+ //#endregion
3436
+ //#region src/snapshots/Snapshots.ts
3437
+ /**
3438
+ * Client for the snapshot API: GeoParquet exports of a relation.
3439
+ *
3440
+ * The job API (`/api/v4/snapshots`) queues and inspects exports and is
3441
+ * super-user only; exports run asynchronously — poll with `getSnapshot` or
3442
+ * use `waitForSnapshot`. The read API
3443
+ * (`/api/v4/schemas/{schema}/relations/{relation}/snapshots`) serves the
3444
+ * published snapshots to any user with read access to the relation, with
3445
+ * HEAD + byte-range support so Parquet readers can fetch footers and row
3446
+ * groups selectively.
3447
+ *
3448
+ * ```ts
3449
+ * const snapshots = new Snapshots(createCentiaClient({ baseUrl, auth }));
3450
+ * const { id } = await snapshots.postSnapshot({ schema: 'geodanmark', relation: 'bygning' });
3451
+ * const done = await snapshots.waitForSnapshot(id);
3452
+ * ```
3453
+ */
3454
+ var Snapshots = class {
3455
+ constructor(client) {
3456
+ this.client = client;
3457
+ }
3458
+ relationPath(schema, relation, rest = "") {
3459
+ return `api/v4/schemas/${encodeURIComponent(schema)}/relations/${encodeURIComponent(relation)}/snapshots${rest}`;
3460
+ }
3461
+ async postSnapshot(body) {
3462
+ return this.client.request({
3463
+ path: "api/v4/snapshots",
3464
+ method: "POST",
3465
+ body,
3466
+ expectedStatus: 202
3467
+ });
3468
+ }
3469
+ async getSnapshot(id) {
3470
+ var _this2 = this;
3471
+ const keys = Array.isArray(id) ? id : [id];
3472
+ return _this2.client.request({
3473
+ path: `api/v4/snapshots/${keys.map((k) => encodeURIComponent(k)).join(",")}`,
3474
+ method: "GET"
3475
+ });
3476
+ }
3477
+ /** List the newest snapshot jobs (50), optionally filtered by schema/relation. Super-user only. */
3478
+ async getSnapshots(options) {
3479
+ var _this3 = this;
3480
+ const query = {};
3481
+ if ((options === null || options === void 0 ? void 0 : options.schema) !== void 0) query.schema = options.schema;
3482
+ if ((options === null || options === void 0 ? void 0 : options.relation) !== void 0) query.relation = options.relation;
3483
+ return _this3.client.request({
3484
+ path: "api/v4/snapshots",
3485
+ method: "GET",
3486
+ query: Object.keys(query).length > 0 ? query : void 0
3487
+ });
3488
+ }
3489
+ /**
3490
+ * Poll a snapshot job until it reaches a terminal status (succeeded, failed
3491
+ * or superseded) and return it — check `status`/`error` on the result.
3492
+ * Throws an `Error` when `timeoutMs` elapses first.
3493
+ */
3494
+ async waitForSnapshot(id, options) {
3495
+ var _this4 = this;
3496
+ var _options$intervalMs, _options$timeoutMs;
3497
+ const intervalMs = (_options$intervalMs = options === null || options === void 0 ? void 0 : options.intervalMs) !== null && _options$intervalMs !== void 0 ? _options$intervalMs : 2e3;
3498
+ const timeoutMs = (_options$timeoutMs = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _options$timeoutMs !== void 0 ? _options$timeoutMs : 3e5;
3499
+ const deadline = Date.now() + timeoutMs;
3500
+ for (;;) {
3501
+ const job = await _this4.getSnapshot(id);
3502
+ if (job.status === "succeeded" || job.status === "failed" || job.status === "superseded") return job;
3503
+ if (Date.now() + intervalMs > deadline) throw new Error(`Timed out after ${timeoutMs} ms waiting for snapshot ${id} (status: ${job.status})`);
3504
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
3505
+ }
3506
+ }
3507
+ /** List the published snapshots of a relation, newest first. */
3508
+ async getRelationSnapshots(schema, relation) {
3509
+ var _this5 = this;
3510
+ return _this5.client.request({
3511
+ path: _this5.relationPath(schema, relation),
3512
+ method: "GET"
3513
+ });
3514
+ }
3515
+ /** Get one published snapshot (metadata) by date (`YYYY-MM-DD`). */
3516
+ async getRelationSnapshot(schema, relation, date) {
3517
+ var _this6 = this;
3518
+ return _this6.client.request({
3519
+ path: _this6.relationPath(schema, relation, `/${encodeURIComponent(date)}`),
3520
+ method: "GET"
3521
+ });
3522
+ }
3523
+ /**
3524
+ * Absolute URL of the snapshot's Parquet file, without fetching it — for
3525
+ * DuckDB/GDAL or a plain fetch. Authorization travels in the request
3526
+ * header, so protected relations need the caller to attach the token.
3527
+ */
3528
+ getRelationSnapshotDataUrl(schema, relation, date) {
3529
+ return `${this.client.baseUrl}/${this.relationPath(schema, relation, `/${encodeURIComponent(date)}/data`)}`;
3530
+ }
3531
+ /**
3532
+ * Fetch the snapshot's Parquet file and return the raw `Response` (stream
3533
+ * or buffer it yourself). Follows the 302 redirect the server answers in
3534
+ * redirect mode. Pass `range` for a single byte range (206). Throws
3535
+ * `CentiaApiError`: 403, 404, 409 (several files; use
3536
+ * getRelationSnapshotFile), 416, 502.
3537
+ */
3538
+ async getRelationSnapshotData(schema, relation, date, options) {
3539
+ var _this7 = this;
3540
+ return _this7.rawGet(_this7.relationPath(schema, relation, `/${encodeURIComponent(date)}/data`), "GET", options);
3541
+ }
3542
+ /** HEAD request for the snapshot's Parquet file — Content-Length, Accept-Ranges and ETag without the body. */
3543
+ async headRelationSnapshotData(schema, relation, date) {
3544
+ var _this8 = this;
3545
+ return _this8.rawGet(_this8.relationPath(schema, relation, `/${encodeURIComponent(date)}/data`), "HEAD");
3546
+ }
3547
+ /**
3548
+ * Fetch one file of the snapshot by catalog name (`data-<id>.parquet`,
3549
+ * `metadata-<id>.json`). Same redirect/range semantics as
3550
+ * getRelationSnapshotData.
3551
+ */
3552
+ async getRelationSnapshotFile(schema, relation, date, file, options) {
3553
+ var _this9 = this;
3554
+ return _this9.rawGet(_this9.relationPath(schema, relation, `/${encodeURIComponent(date)}/files/${encodeURIComponent(file)}`), "GET", options);
3555
+ }
3556
+ /** HEAD request for one file of the snapshot. */
3557
+ async headRelationSnapshotFile(schema, relation, date, file) {
3558
+ var _this10 = this;
3559
+ return _this10.rawGet(_this10.relationPath(schema, relation, `/${encodeURIComponent(date)}/files/${encodeURIComponent(file)}`), "HEAD");
3560
+ }
3561
+ async rawGet(path, method, options) {
3562
+ var _this11 = this;
3563
+ const headers = {};
3564
+ if (options === null || options === void 0 ? void 0 : options.range) headers["Range"] = `bytes=${options.range[0]}-${options.range[1]}`;
3565
+ return _this11.client.requestRaw({
3566
+ path,
3567
+ method,
3568
+ headers: Object.keys(headers).length > 0 ? headers : void 0,
3569
+ expectedStatus: [200, 206]
3570
+ });
3571
+ }
3572
+ };
3573
+
3574
+ //#endregion
3575
+ //#region src/scheduler/Scheduler.ts
3576
+ function idsPath(id) {
3577
+ return (Array.isArray(id) ? id : [id]).map((k) => encodeURIComponent(String(k))).join(",");
3578
+ }
3579
+ /**
3580
+ * Client for the scheduler API (`/api/v4/scheduler`). Super-user only.
3581
+ *
3582
+ * Jobs describe recurring data imports (cron-scheduled); runs are their
3583
+ * executions. Starting a run is asynchronous — poll `getSchedulerRuns`
3584
+ * (the `_links.runs` of the 202) until the run finishes.
3585
+ *
3586
+ * ```ts
3587
+ * const scheduler = new Scheduler(createCentiaClient({ baseUrl, auth }));
3588
+ * const { ids } = await scheduler.postSchedulerJob({ name, schema, url, schedule: '0 3 * * *' });
3589
+ * await scheduler.postSchedulerRun({ job: ids[0] });
3590
+ * ```
3591
+ */
3592
+ var Scheduler = class {
3593
+ constructor(client) {
3594
+ this.client = client;
3595
+ }
3596
+ /** List all scheduler jobs. */
3597
+ async getSchedulerJobs() {
3598
+ return this.client.request({
3599
+ path: "api/v4/scheduler/jobs",
3600
+ method: "GET"
3601
+ });
3602
+ }
3603
+ async getSchedulerJob(id) {
3604
+ return this.client.request({
3605
+ path: `api/v4/scheduler/jobs/${idsPath(id)}`,
3606
+ method: "GET"
3607
+ });
3608
+ }
3609
+ /**
3610
+ * Create one or more jobs (201; all-or-nothing for arrays). Returns the
3611
+ * Location header and the new ids parsed from it, in request order.
3612
+ */
3613
+ async postSchedulerJob(body) {
3614
+ var _this3 = this;
3615
+ var _res$getHeader, _location$split$pop;
3616
+ const location = (_res$getHeader = (await _this3.client.requestFull({
3617
+ path: "api/v4/scheduler/jobs",
3618
+ method: "POST",
3619
+ body,
3620
+ expectedStatus: 201
3621
+ })).getHeader("Location")) !== null && _res$getHeader !== void 0 ? _res$getHeader : "";
3622
+ return {
3623
+ location,
3624
+ ids: ((_location$split$pop = location.split("/").pop()) !== null && _location$split$pop !== void 0 ? _location$split$pop : "").split(",").map((s) => Number(s)).filter((n) => Number.isFinite(n))
3625
+ };
3626
+ }
3627
+ /** Partially update a job (303 + Location). */
3628
+ async patchSchedulerJob(id, body) {
3629
+ var _this4 = this;
3630
+ var _res$getHeader2;
3631
+ return { location: (_res$getHeader2 = (await _this4.client.requestFull({
3632
+ path: `api/v4/scheduler/jobs/${idsPath(id)}`,
3633
+ method: "PATCH",
3634
+ body,
3635
+ expectedStatus: 303
3636
+ })).getHeader("Location")) !== null && _res$getHeader2 !== void 0 ? _res$getHeader2 : "" };
3637
+ }
3638
+ /**
3639
+ * Delete one or more jobs (204). Nothing is deleted if any id fails:
3640
+ * throws 404 (unknown id) or 409 (a run is in progress).
3641
+ */
3642
+ async deleteSchedulerJob(id) {
3643
+ await this.client.request({
3644
+ path: `api/v4/scheduler/jobs/${idsPath(id)}`,
3645
+ method: "DELETE",
3646
+ expectedStatus: 204
3647
+ });
3648
+ }
3649
+ /** List runs (running plus the newest 50 finished), optionally filtered by job and status. */
3650
+ async getSchedulerRuns(options) {
3651
+ var _this6 = this;
3652
+ const query = {};
3653
+ if ((options === null || options === void 0 ? void 0 : options.job) !== void 0) query.job = String(options.job);
3654
+ if ((options === null || options === void 0 ? void 0 : options.status) !== void 0) query.status = options.status;
3655
+ return _this6.client.request({
3656
+ path: "api/v4/scheduler/runs",
3657
+ method: "GET",
3658
+ query: Object.keys(query).length > 0 ? query : void 0
3659
+ });
3660
+ }
3661
+ /** Get one run by uuid. */
3662
+ async getSchedulerRun(uuid) {
3663
+ return this.client.request({
3664
+ path: `api/v4/scheduler/runs/${encodeURIComponent(uuid)}`,
3665
+ method: "GET"
3666
+ });
3667
+ }
3668
+ /**
3669
+ * Start a run of a job (202). Throws 404 (unknown job) or 409 (a run of
3670
+ * the job is already running).
3671
+ */
3672
+ async postSchedulerRun(body) {
3673
+ return this.client.request({
3674
+ path: "api/v4/scheduler/runs",
3675
+ method: "POST",
3676
+ body,
3677
+ expectedStatus: 202
3678
+ });
3679
+ }
3680
+ /**
3681
+ * Stop a running run: sends SIGINT, which the server escalates to SIGKILL
3682
+ * after 30 s — the request itself can take up to ~30 s, so do not use a
3683
+ * short timeout. Throws 404 (no running run with that uuid) or 409 (the
3684
+ * run is on another host).
3685
+ */
3686
+ async deleteSchedulerRun(uuid) {
3687
+ return this.client.request({
3688
+ path: `api/v4/scheduler/runs/${encodeURIComponent(uuid)}`,
3689
+ method: "DELETE"
3690
+ });
3691
+ }
3692
+ };
3693
+
3389
3694
  //#endregion
3390
3695
  //#region src/auth/errors.ts
3391
3696
  /**
@@ -3523,8 +3828,10 @@ exports.Ogc = Ogc;
3523
3828
  exports.Ows = Ows;
3524
3829
  exports.PasswordFlow = PasswordFlow;
3525
3830
  exports.Rpc = Rpc;
3831
+ exports.Scheduler = Scheduler;
3526
3832
  exports.SessionExpiredError = SessionExpiredError;
3527
3833
  exports.SignUp = SignUp;
3834
+ exports.Snapshots = Snapshots;
3528
3835
  exports.Sql = Sql;
3529
3836
  exports.SqlNoToken = SqlNoToken;
3530
3837
  exports.Stats = Stats;