@coffre/client 0.1.10 → 0.1.12

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/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as RemovedMember, C as DryRunResult, D as Member, E as Me, F as SessionRow, I as SetResult, L as SyncField, M as SecretKey, N as SecretVersion, O as OffboardingReport, P as ServiceTokenRow, R as SyncProviderInfo, S as DryRunOutcome, T as Json, _ as isAsked, a as Params, b as AuditEntryView, c as RouteOutput, d as planImport, f as FormValues, g as initialValues, h as firstMissing, i as ImportAction, j as RunOutcome, k as ProjectSummary, l as Transport, m as configFromForm, n as CoffreClient, o as RouteInput, p as configFromArguments, r as CoffreError, s as RouteKey, t as ClientOptions, u as createClient, v as AccessValue, w as IdentityRow, x as AuthInfo, y as Api, z as SyncView } from "./index-BJZEgxE8.js";
2
- export { type AccessValue, type Api, type AuditEntryView, type AuthInfo, ClientOptions, CoffreClient, CoffreError, type DryRunOutcome, type DryRunResult, type FormValues, type IdentityRow, ImportAction, type Json, type Me, type Member, type OffboardingReport, Params, type ProjectSummary, type RemovedMember, RouteInput, RouteKey, RouteOutput, type RunOutcome, type SecretKey, type SecretVersion, type ServiceTokenRow, type SessionRow, type SetResult, type SyncField, type SyncProviderInfo, type SyncView, Transport, configFromArguments, configFromForm, createClient, firstMissing, initialValues, isAsked, planImport };
1
+ import { C as RemovedMember, D as SessionRow, E as ServiceTokenRow, O as SetResult, S as ProjectSummary, T as SecretVersion, _ as DryRunResult, a as Params, b as Member, c as RouteOutput, d as planImport, f as AccessValue, g as DryRunOutcome, h as AuthInfo, i as ImportAction, l as Transport, m as AuditEntryView, n as CoffreClient, o as RouteInput, p as Api, r as CoffreError, s as RouteKey, t as ClientOptions, u as createClient, v as IdentityRow, w as SecretKey, x as OffboardingReport, y as Me } from "./index-BOnwnquP.js";
2
+ export { type AccessValue, type Api, type AuditEntryView, type AuthInfo, ClientOptions, CoffreClient, CoffreError, type DryRunOutcome, type DryRunResult, type IdentityRow, ImportAction, type Me, type Member, type OffboardingReport, Params, type ProjectSummary, type RemovedMember, RouteInput, RouteKey, RouteOutput, type SecretKey, type SecretVersion, type ServiceTokenRow, type SessionRow, type SetResult, Transport, createClient, planImport };
package/dist/index.js CHANGED
@@ -1,67 +1,3 @@
1
- //#region src/sync-fields.ts
2
- function initialValues(provider) {
3
- return Object.fromEntries(provider.fields.map((field) => [field.name, field.type === "text" ? "" : field.initial]));
4
- }
5
- /** Whether the rest of the form makes the field meaningful. */
6
- function isAsked(field, values) {
7
- if (field.type === "options" || field.when === void 0) return true;
8
- const picked = values[field.when.field];
9
- const list = Array.isArray(picked) ? picked : [];
10
- return list.length === field.when.is.length && field.when.is.every((value) => list.includes(value));
11
- }
12
- /** The label of the first required field left empty, or null when the form can be sent. */
13
- function firstMissing(provider, values) {
14
- for (const field of provider.fields) {
15
- if (!isAsked(field, values)) continue;
16
- const value = values[field.name];
17
- if ((typeof value === "string" ? value.trim() === "" : (value ?? []).length === 0) && (field.type === "options" || field.optional !== true)) return field.label;
18
- }
19
- return null;
20
- }
21
- /**
22
- * The provider's config. Text is trimmed, and an optional field left empty
23
- * is left out rather than sent as "", which the server rightly refuses.
24
- */
25
- function configFromForm(provider, values) {
26
- const config = {};
27
- for (const field of provider.fields) {
28
- if (!isAsked(field, values)) continue;
29
- const value = values[field.name];
30
- if (field.type === "options") {
31
- const picked = Array.isArray(value) ? value : [];
32
- config[field.name] = field.multiple ? picked : picked[0];
33
- } else {
34
- const text = typeof value === "string" ? value.trim() : "";
35
- if (text !== "") config[field.name] = text;
36
- }
37
- }
38
- return config;
39
- }
40
- /**
41
- * The config from `name=value` arguments, as the CLI takes them. A field with
42
- * several options takes them comma-separated, and one left out gets what the
43
- * form preselects. Text goes as typed, for the server to check.
44
- */
45
- function configFromArguments(provider, assignments) {
46
- const config = {};
47
- for (const assignment of assignments) {
48
- const equals = assignment.indexOf("=");
49
- const name = equals === -1 ? assignment : assignment.slice(0, equals);
50
- const field = provider.fields.find((candidate) => candidate.name === name);
51
- if (equals === -1 || field === void 0) {
52
- const names = provider.fields.map((candidate) => candidate.name).join(", ");
53
- throw new Error(`${provider.label} takes ${names} as name=value; got ${JSON.stringify(assignment)}`);
54
- }
55
- if (Object.hasOwn(config, name)) throw new Error(`${name} is given twice`);
56
- const value = assignment.slice(equals + 1);
57
- if (field.type === "text") config[name] = value;
58
- else if (field.multiple) config[name] = value.split(",").map((item) => item.trim()).filter((item) => item !== "");
59
- else config[name] = value;
60
- }
61
- for (const field of provider.fields) if (field.type === "options" && !Object.hasOwn(config, field.name)) config[field.name] = field.multiple ? field.initial : field.initial[0];
62
- return config;
63
- }
64
- //#endregion
65
1
  //#region src/index.ts
66
2
  /** The API's error shape, `{ error, message }`, with the HTTP status. */
67
3
  const COFFRE_ERROR = Symbol.for("@coffre/client:CoffreError");
@@ -205,15 +141,6 @@ set: (member, access) => call("PATCH /access/:member", { member }, access) },
205
141
  get: (code) => call("GET /device-logins/:code", { code }),
206
142
  decide: (code, approve) => call("POST /device-logins/:code", { code }, { approve })
207
143
  },
208
- syncs: {
209
- /** Where a sync can push on this instance, and what each asks for. */
210
- providers: () => call("GET /syncs/providers", {}),
211
- list: (path) => call("GET /syncs/:project/:environment", place(path)),
212
- add: (path, input) => call("POST /syncs/:project/:environment", place(path), input),
213
- update: (id, patch) => call("PATCH /syncs/by-id/:id", { id }, patch),
214
- remove: (id) => call("DELETE /syncs/by-id/:id", { id }),
215
- run: (id) => call("POST /syncs/by-id/:id/runs", { id })
216
- },
217
144
  audit: {
218
145
  list: (query = {}) => call("GET /audit", {}, query),
219
146
  verify: () => call("GET /audit/verification", {}),
@@ -254,4 +181,4 @@ async function planImport(coffre, path, entries) {
254
181
  };
255
182
  }
256
183
  //#endregion
257
- export { CoffreError, configFromArguments, configFromForm, createClient, firstMissing, initialValues, isAsked, planImport };
184
+ export { CoffreError, createClient, planImport };
package/dist/routes.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as Params, o as RouteInput, s as RouteKey } from "./index-BJZEgxE8.js";
1
+ import { a as Params, o as RouteInput, s as RouteKey } from "./index-BOnwnquP.js";
2
2
  //#region src/routes.d.ts
3
3
  export type GetKey = Extract<RouteKey, `GET ${string}`>;
4
4
  /** Each GET route, with what to ask it. */
package/dist/routes.js CHANGED
@@ -15,8 +15,6 @@ function getCalls({ places, secrets, members, services }) {
15
15
  "GET /sessions": [{ params: {} }],
16
16
  "GET /identities": [{ params: {} }],
17
17
  "GET /device-logins/:code": [{ params: { code: "BCDF-GHJK" } }],
18
- "GET /syncs/providers": [{ params: {} }],
19
- "GET /syncs/:project/:environment": places.map((params) => ({ params })),
20
18
  "GET /audit": [{
21
19
  params: {},
22
20
  input: { limit: 500 }
@@ -68,12 +66,6 @@ const EVERY_ROUTE = {
68
66
  "DELETE /identities/:id": true,
69
67
  "GET /device-logins/:code": true,
70
68
  "POST /device-logins/:code": true,
71
- "GET /syncs/providers": true,
72
- "GET /syncs/:project/:environment": true,
73
- "POST /syncs/:project/:environment": true,
74
- "PATCH /syncs/by-id/:id": true,
75
- "DELETE /syncs/by-id/:id": true,
76
- "POST /syncs/by-id/:id/runs": true,
77
69
  "GET /audit": true,
78
70
  "GET /audit/verification": true,
79
71
  "GET /audit/keys": true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coffre/client",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "The coffre API as typed function calls.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/api.ts CHANGED
@@ -40,6 +40,7 @@ export type Api = {
40
40
  secretCount: number | null;
41
41
  };
42
42
  }[];
43
+ secretCount: number | null;
43
44
  }[];
44
45
  };
45
46
  };
@@ -236,35 +237,6 @@ export type Api = {
236
237
  expiresAt: string;
237
238
  lastUsedAt: string | null;
238
239
  }[];
239
- syncs: {
240
- id: string;
241
- provider: string;
242
- providerLabel: string;
243
- brand: "cloudflare" | "github" | "other" | "railway" | "vercel";
244
- offered: boolean;
245
- destination: string;
246
- config: {
247
- [key: string]: string | number | boolean | null | Json[] | {
248
- [key: string]: Json;
249
- };
250
- };
251
- credential: string;
252
- createdAt: string;
253
- createdBy: string;
254
- paused: boolean;
255
- running: boolean;
256
- lastRunAt: string | null;
257
- lastStatus: "failed" | "ok" | "partial" | null;
258
- lastError: string | null;
259
- synced: number;
260
- pending: number;
261
- skipped: {
262
- key: string;
263
- reason: string;
264
- }[];
265
- project: string;
266
- environment: string;
267
- }[];
268
240
  };
269
241
  };
270
242
  "PUT /members/:member": {
@@ -317,35 +289,6 @@ export type Api = {
317
289
  expiresAt: string;
318
290
  lastUsedAt: string | null;
319
291
  }[];
320
- syncs: {
321
- id: string;
322
- provider: string;
323
- providerLabel: string;
324
- brand: "cloudflare" | "github" | "other" | "railway" | "vercel";
325
- offered: boolean;
326
- destination: string;
327
- config: {
328
- [key: string]: string | number | boolean | null | Json[] | {
329
- [key: string]: Json;
330
- };
331
- };
332
- credential: string;
333
- createdAt: string;
334
- createdBy: string;
335
- paused: boolean;
336
- running: boolean;
337
- lastRunAt: string | null;
338
- lastStatus: "failed" | "ok" | "partial" | null;
339
- lastError: string | null;
340
- synced: number;
341
- pending: number;
342
- skipped: {
343
- key: string;
344
- reason: string;
345
- }[];
346
- project: string;
347
- environment: string;
348
- }[];
349
292
  };
350
293
  };
351
294
  };
@@ -456,219 +399,6 @@ export type Api = {
456
399
  decided: true;
457
400
  };
458
401
  };
459
- "GET /syncs/providers": {
460
- input: undefined;
461
- output: {
462
- providers: {
463
- brand: "cloudflare" | "github" | "other" | "railway" | "vercel";
464
- id: string;
465
- credential: {
466
- placeholder: string;
467
- hint: string;
468
- };
469
- label: string;
470
- fields: ({
471
- type: "text";
472
- name: string;
473
- label: string;
474
- placeholder: string;
475
- optional?: boolean;
476
- hint?: string;
477
- when?: {
478
- field: string;
479
- is: string[];
480
- };
481
- } | {
482
- type: "options";
483
- name: string;
484
- label: string;
485
- options: {
486
- value: string;
487
- label: string;
488
- }[];
489
- multiple: boolean;
490
- initial: string[];
491
- hint?: string;
492
- })[];
493
- }[];
494
- };
495
- };
496
- "GET /syncs/:project/:environment": {
497
- input: undefined;
498
- output: {
499
- syncs: {
500
- id: string;
501
- provider: string;
502
- providerLabel: string;
503
- brand: "cloudflare" | "github" | "other" | "railway" | "vercel";
504
- offered: boolean;
505
- destination: string;
506
- config: {
507
- [key: string]: string | number | boolean | null | Json[] | {
508
- [key: string]: Json;
509
- };
510
- };
511
- credential: string;
512
- createdAt: string;
513
- createdBy: string;
514
- paused: boolean;
515
- running: boolean;
516
- lastRunAt: string | null;
517
- lastStatus: "failed" | "ok" | "partial" | null;
518
- lastError: string | null;
519
- synced: number;
520
- pending: number;
521
- skipped: {
522
- key: string;
523
- reason: string;
524
- }[];
525
- }[];
526
- canManage: boolean;
527
- };
528
- };
529
- "POST /syncs/:project/:environment": {
530
- input: {
531
- provider: string;
532
- config: {
533
- [key: string]: unknown;
534
- };
535
- credential: string;
536
- };
537
- output: {
538
- id: string;
539
- provider: string;
540
- providerLabel: string;
541
- brand: "cloudflare" | "github" | "other" | "railway" | "vercel";
542
- offered: boolean;
543
- destination: string;
544
- config: {
545
- [key: string]: string | number | boolean | null | Json[] | {
546
- [key: string]: Json;
547
- };
548
- };
549
- credential: string;
550
- createdAt: string;
551
- createdBy: string;
552
- paused: boolean;
553
- running: boolean;
554
- lastRunAt: string | null;
555
- lastStatus: "failed" | "ok" | "partial" | null;
556
- lastError: string | null;
557
- synced: number;
558
- pending: number;
559
- skipped: {
560
- key: string;
561
- reason: string;
562
- }[];
563
- };
564
- };
565
- "PATCH /syncs/by-id/:id": {
566
- input: {
567
- paused: boolean;
568
- };
569
- output: {
570
- id: string;
571
- provider: string;
572
- providerLabel: string;
573
- brand: "cloudflare" | "github" | "other" | "railway" | "vercel";
574
- offered: boolean;
575
- destination: string;
576
- config: {
577
- [key: string]: string | number | boolean | null | Json[] | {
578
- [key: string]: Json;
579
- };
580
- };
581
- credential: string;
582
- createdAt: string;
583
- createdBy: string;
584
- paused: boolean;
585
- running: boolean;
586
- lastRunAt: string | null;
587
- lastStatus: "failed" | "ok" | "partial" | null;
588
- lastError: string | null;
589
- synced: number;
590
- pending: number;
591
- skipped: {
592
- key: string;
593
- reason: string;
594
- }[];
595
- };
596
- };
597
- "DELETE /syncs/by-id/:id": {
598
- input: undefined;
599
- output: {
600
- id: string;
601
- provider: string;
602
- providerLabel: string;
603
- brand: "cloudflare" | "github" | "other" | "railway" | "vercel";
604
- offered: boolean;
605
- destination: string;
606
- config: {
607
- [key: string]: string | number | boolean | null | Json[] | {
608
- [key: string]: Json;
609
- };
610
- };
611
- credential: string;
612
- createdAt: string;
613
- createdBy: string;
614
- paused: boolean;
615
- running: boolean;
616
- lastRunAt: string | null;
617
- lastStatus: "failed" | "ok" | "partial" | null;
618
- lastError: string | null;
619
- synced: number;
620
- pending: number;
621
- skipped: {
622
- key: string;
623
- reason: string;
624
- }[];
625
- };
626
- };
627
- "POST /syncs/by-id/:id/runs": {
628
- input: undefined;
629
- output: {
630
- sync: {
631
- id: string;
632
- provider: string;
633
- providerLabel: string;
634
- brand: "cloudflare" | "github" | "other" | "railway" | "vercel";
635
- offered: boolean;
636
- destination: string;
637
- config: {
638
- [key: string]: string | number | boolean | null | Json[] | {
639
- [key: string]: Json;
640
- };
641
- };
642
- credential: string;
643
- createdAt: string;
644
- createdBy: string;
645
- paused: boolean;
646
- running: boolean;
647
- lastRunAt: string | null;
648
- lastStatus: "failed" | "ok" | "partial" | null;
649
- lastError: string | null;
650
- synced: number;
651
- pending: number;
652
- skipped: {
653
- key: string;
654
- reason: string;
655
- }[];
656
- };
657
- outcome: {
658
- status: "busy";
659
- } | {
660
- status: "failed" | "ok" | "partial";
661
- upserted: string[];
662
- deleted: string[];
663
- failed: {
664
- key: string;
665
- operation: "delete" | "upsert";
666
- message: string;
667
- }[];
668
- error: string | null;
669
- };
670
- };
671
- };
672
402
  "GET /audit": {
673
403
  input: {
674
404
  path?: string;
@@ -875,35 +605,6 @@ export type OffboardingReport = {
875
605
  expiresAt: string;
876
606
  lastUsedAt: string | null;
877
607
  }[];
878
- syncs: {
879
- id: string;
880
- provider: string;
881
- providerLabel: string;
882
- brand: "cloudflare" | "github" | "other" | "railway" | "vercel";
883
- offered: boolean;
884
- destination: string;
885
- config: {
886
- [key: string]: string | number | boolean | null | Json[] | {
887
- [key: string]: Json;
888
- };
889
- };
890
- credential: string;
891
- createdAt: string;
892
- createdBy: string;
893
- paused: boolean;
894
- running: boolean;
895
- lastRunAt: string | null;
896
- lastStatus: "failed" | "ok" | "partial" | null;
897
- lastError: string | null;
898
- synced: number;
899
- pending: number;
900
- skipped: {
901
- key: string;
902
- reason: string;
903
- }[];
904
- project: string;
905
- environment: string;
906
- }[];
907
608
  };
908
609
 
909
610
  export type ProjectSummary = {
@@ -920,6 +621,7 @@ export type ProjectSummary = {
920
621
  secretCount: number | null;
921
622
  };
922
623
  }[];
624
+ secretCount: number | null;
923
625
  };
924
626
 
925
627
  export type RemovedMember = {
@@ -928,20 +630,6 @@ export type RemovedMember = {
928
630
  toRotate: number;
929
631
  };
930
632
 
931
- export type RunOutcome = {
932
- status: "busy";
933
- } | {
934
- status: "failed" | "ok" | "partial";
935
- upserted: string[];
936
- deleted: string[];
937
- failed: {
938
- key: string;
939
- operation: "delete" | "upsert";
940
- message: string;
941
- }[];
942
- error: string | null;
943
- };
944
-
945
633
  export type SecretKey = {
946
634
  key: string;
947
635
  archived: boolean;
@@ -992,92 +680,3 @@ export type SetResult = {
992
680
  };
993
681
  };
994
682
  };
995
-
996
- export type SyncField = {
997
- type: "text";
998
- name: string;
999
- label: string;
1000
- placeholder: string;
1001
- optional?: boolean;
1002
- hint?: string;
1003
- when?: {
1004
- field: string;
1005
- is: string[];
1006
- };
1007
- } | {
1008
- type: "options";
1009
- name: string;
1010
- label: string;
1011
- options: {
1012
- value: string;
1013
- label: string;
1014
- }[];
1015
- multiple: boolean;
1016
- initial: string[];
1017
- hint?: string;
1018
- };
1019
-
1020
- export type SyncProviderInfo = {
1021
- brand: "cloudflare" | "github" | "other" | "railway" | "vercel";
1022
- id: string;
1023
- credential: {
1024
- placeholder: string;
1025
- hint: string;
1026
- };
1027
- label: string;
1028
- fields: ({
1029
- type: "text";
1030
- name: string;
1031
- label: string;
1032
- placeholder: string;
1033
- optional?: boolean;
1034
- hint?: string;
1035
- when?: {
1036
- field: string;
1037
- is: string[];
1038
- };
1039
- } | {
1040
- type: "options";
1041
- name: string;
1042
- label: string;
1043
- options: {
1044
- value: string;
1045
- label: string;
1046
- }[];
1047
- multiple: boolean;
1048
- initial: string[];
1049
- hint?: string;
1050
- })[];
1051
- };
1052
-
1053
- export type SyncView = {
1054
- id: string;
1055
- provider: string;
1056
- providerLabel: string;
1057
- brand: "cloudflare" | "github" | "other" | "railway" | "vercel";
1058
- offered: boolean;
1059
- destination: string;
1060
- config: {
1061
- [key: string]: string | number | boolean | null | Json[] | {
1062
- [key: string]: Json;
1063
- };
1064
- };
1065
- credential: string;
1066
- createdAt: string;
1067
- createdBy: string;
1068
- paused: boolean;
1069
- running: boolean;
1070
- lastRunAt: string | null;
1071
- lastStatus: "failed" | "ok" | "partial" | null;
1072
- lastError: string | null;
1073
- synced: number;
1074
- pending: number;
1075
- skipped: {
1076
- key: string;
1077
- reason: string;
1078
- }[];
1079
- };
1080
-
1081
- export type Json = string | number | boolean | null | Json[] | {
1082
- [key: string]: Json;
1083
- };
package/src/index.ts CHANGED
@@ -19,24 +19,17 @@ export type {
19
19
  DryRunOutcome,
20
20
  DryRunResult,
21
21
  IdentityRow,
22
- Json,
23
22
  Me,
24
23
  Member,
25
24
  OffboardingReport,
26
25
  ProjectSummary,
27
26
  RemovedMember,
28
- RunOutcome,
29
27
  SecretKey,
30
28
  SecretVersion,
31
29
  ServiceTokenRow,
32
30
  SessionRow,
33
31
  SetResult,
34
- SyncField,
35
- SyncProviderInfo,
36
- SyncView,
37
32
  } from './api.ts';
38
- export { configFromArguments, configFromForm, firstMissing, initialValues, isAsked } from './sync-fields.ts';
39
- export type { FormValues } from './sync-fields.ts';
40
33
 
41
34
  export type RouteKey = keyof Api;
42
35
  /** What a caller sends: the body, or the query string for a GET. */
@@ -245,18 +238,6 @@ export function createClient(options: ClientOptions) {
245
238
  decide: (code: string, approve: boolean) => call('POST /device-logins/:code', { code }, { approve }),
246
239
  },
247
240
 
248
- syncs: {
249
- /** Where a sync can push on this instance, and what each asks for. */
250
- providers: () => call('GET /syncs/providers', {}),
251
- list: (path: string) => call('GET /syncs/:project/:environment', place(path)),
252
- add: (path: string, input: RouteInput<'POST /syncs/:project/:environment'>) =>
253
- call('POST /syncs/:project/:environment', place(path), input),
254
- update: (id: string, patch: RouteInput<'PATCH /syncs/by-id/:id'>) =>
255
- call('PATCH /syncs/by-id/:id', { id }, patch),
256
- remove: (id: string) => call('DELETE /syncs/by-id/:id', { id }),
257
- run: (id: string) => call('POST /syncs/by-id/:id/runs', { id }),
258
- },
259
-
260
241
  audit: {
261
242
  list: (query: RouteInput<'GET /audit'> = {}) => call('GET /audit', {}, query),
262
243
  verify: () => call('GET /audit/verification', {}),
package/src/routes.ts CHANGED
@@ -37,8 +37,6 @@ export function getCalls({ places, secrets, members, services }: Subjects): GetC
37
37
  'GET /sessions': [{ params: {} }],
38
38
  'GET /identities': [{ params: {} }],
39
39
  'GET /device-logins/:code': [{ params: { code: 'BCDF-GHJK' } }],
40
- 'GET /syncs/providers': [{ params: {} }],
41
- 'GET /syncs/:project/:environment': places.map((params) => ({ params })),
42
40
  'GET /audit': [{ params: {}, input: { limit: 500 } }, { params: {}, input: { limit: 500, detail: '1' } }],
43
41
  'GET /audit/verification': [{ params: {} }],
44
42
  'GET /audit/keys': [{ params: {} }],
@@ -82,12 +80,6 @@ const EVERY_ROUTE: { [K in RouteKey]: true } = {
82
80
  'DELETE /identities/:id': true,
83
81
  'GET /device-logins/:code': true,
84
82
  'POST /device-logins/:code': true,
85
- 'GET /syncs/providers': true,
86
- 'GET /syncs/:project/:environment': true,
87
- 'POST /syncs/:project/:environment': true,
88
- 'PATCH /syncs/by-id/:id': true,
89
- 'DELETE /syncs/by-id/:id': true,
90
- 'POST /syncs/by-id/:id/runs': true,
91
83
  'GET /audit': true,
92
84
  'GET /audit/verification': true,
93
85
  'GET /audit/keys': true,