@ninedeploy/sdk 0.18.4 → 0.18.11

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.
Files changed (54) hide show
  1. package/dist/index.d.ts +2 -2
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/resources/auth.d.ts +20 -1
  4. package/dist/resources/auth.d.ts.map +1 -1
  5. package/dist/resources/auth.js +9 -0
  6. package/dist/resources/auth.js.map +1 -1
  7. package/dist/resources/databases.d.ts +6 -1
  8. package/dist/resources/databases.d.ts.map +1 -1
  9. package/dist/resources/databases.js +4 -0
  10. package/dist/resources/databases.js.map +1 -1
  11. package/dist/resources/deploys.d.ts +34 -1
  12. package/dist/resources/deploys.d.ts.map +1 -1
  13. package/dist/resources/deploys.js +11 -0
  14. package/dist/resources/deploys.js.map +1 -1
  15. package/dist/resources/domains.d.ts +16 -1
  16. package/dist/resources/domains.d.ts.map +1 -1
  17. package/dist/resources/domains.js +9 -0
  18. package/dist/resources/domains.js.map +1 -1
  19. package/dist/resources/servers.d.ts +65 -1
  20. package/dist/resources/servers.d.ts.map +1 -1
  21. package/dist/resources/servers.js +35 -0
  22. package/dist/resources/servers.js.map +1 -1
  23. package/dist/resources/services.d.ts +78 -1
  24. package/dist/resources/services.d.ts.map +1 -1
  25. package/dist/resources/services.js +47 -0
  26. package/dist/resources/services.js.map +1 -1
  27. package/dist/resources/settings.d.ts +47 -2
  28. package/dist/resources/settings.d.ts.map +1 -1
  29. package/dist/resources/settings.js +6 -0
  30. package/dist/resources/settings.js.map +1 -1
  31. package/dist/resources/sources.d.ts +6 -1
  32. package/dist/resources/sources.d.ts.map +1 -1
  33. package/dist/resources/sources.js +5 -0
  34. package/dist/resources/sources.js.map +1 -1
  35. package/dist/resources/system.d.ts +30 -1
  36. package/dist/resources/system.d.ts.map +1 -1
  37. package/dist/resources/system.js +13 -0
  38. package/dist/resources/system.js.map +1 -1
  39. package/dist/resources/traefik.d.ts +9 -0
  40. package/dist/resources/traefik.d.ts.map +1 -1
  41. package/dist/resources/traefik.js +4 -0
  42. package/dist/resources/traefik.js.map +1 -1
  43. package/package.json +2 -2
  44. package/src/index.ts +2 -2
  45. package/src/resources/auth.ts +25 -0
  46. package/src/resources/databases.ts +11 -0
  47. package/src/resources/deploys.ts +37 -0
  48. package/src/resources/domains.ts +30 -0
  49. package/src/resources/servers.ts +102 -0
  50. package/src/resources/services.ts +138 -0
  51. package/src/resources/settings.ts +45 -1
  52. package/src/resources/sources.ts +12 -0
  53. package/src/resources/system.ts +41 -1
  54. package/src/resources/traefik.ts +9 -0
@@ -4,6 +4,12 @@
4
4
  import type {
5
5
  Attachment,
6
6
  AutoscaleStatusView,
7
+ SizingReport,
8
+ RestartLimitConfig,
9
+ RestartLimitView,
10
+ PendingChangesView,
11
+ PendingApplyInput,
12
+ PendingApplyResult,
7
13
  ComposePreviewRequestInput,
8
14
  ComposePreviewResponse,
9
15
  CreateProjectInput,
@@ -42,12 +48,31 @@ import type {
42
48
  ServiceLifecycleResult,
43
49
  ServiceLifecycleView,
44
50
  ServiceLifecycleRetry,
51
+ ErrorPagesInput,
52
+ InlineDockerfileView,
53
+ ServiceMoveView,
54
+ ServiceCommitStatusView,
55
+ ErrorEventView,
56
+ ErrorIngestView,
57
+ ErrorIssueView,
58
+ ErrorPagesView,
59
+ MaintenanceInput,
60
+ MaintenanceView,
45
61
  } from '@ninedeploy/schemas';
46
62
  import { apiGetUrl } from '../apiPath.js';
47
63
  import type { ApplyManifestResult, ApplyManifestInput, ServiceDetail } from '../types.js';
48
64
  import type { Transport } from '../transport.js';
49
65
 
50
66
  /** 0.16.1: one kept upload of a service's source archive. */
67
+ /** G1.7: the registry push webhook of one service. `url` is set only in the answer that made it. */
68
+ export interface RegistryHookView {
69
+ enabled: boolean;
70
+ mine: boolean;
71
+ url: string | null;
72
+ createdAt: string | null;
73
+ lastPushAt: string | null;
74
+ }
75
+
51
76
  export interface SourceUpload {
52
77
  /** First 40 hex chars of the archive's SHA-256 (the deployment's `commitSha`). */
53
78
  sha: string;
@@ -194,6 +219,72 @@ export interface ServicesApi {
194
219
  swarmRecovery: (id: number) => Promise<SwarmRecoveryEntry | null>;
195
220
  retrySwarmRecovery: (id: number) => Promise<SwarmRecoveryResult>;
196
221
  autoscale: (id: number) => Promise<AutoscaleStatusView>;
222
+ /** G5.6: memory and CPU limit suggestions from the metric history (viewer; advisory). */
223
+ sizing: (id: number) => Promise<SizingReport>;
224
+ /** G2.2: maintenance mode (a config turns it on, null off) and custom 502/503/504 pages. */
225
+ maintenance: {
226
+ get: (id: number) => Promise<MaintenanceView>;
227
+ set: (id: number, maintenance: MaintenanceInput['maintenance']) => Promise<MaintenanceView>;
228
+ };
229
+ errorPages: {
230
+ get: (id: number) => Promise<ErrorPagesView>;
231
+ set: (id: number, pages: ErrorPagesInput['pages']) => Promise<ErrorPagesView>;
232
+ };
233
+ /** G1.1: a Dockerfile pasted in the panel (null builds from the repository again). */
234
+ /** G5.4: errors reported by Sentry SDKs, grouped into issues. */
235
+ errors: {
236
+ list: (id: number, status?: 'unresolved' | 'resolved' | 'ignored') => Promise<ErrorIssueView[]>;
237
+ get: (id: number, issueId: number) => Promise<{ issue: ErrorIssueView; events: ErrorEventView[] }>;
238
+ setStatus: (id: number, issueId: number, status: 'unresolved' | 'resolved' | 'ignored') => Promise<ErrorIssueView>;
239
+ /** The DSN: `create` answers it once and replaces any earlier one. */
240
+ ingest: {
241
+ get: (id: number) => Promise<ErrorIngestView>;
242
+ create: (id: number) => Promise<ErrorIngestView>;
243
+ remove: (id: number) => Promise<ErrorIngestView>;
244
+ };
245
+ };
246
+ /** G3.1: move a stopped docker service to another host with its data volume (operators). */
247
+ move: {
248
+ get: (id: number) => Promise<ServiceMoveView>;
249
+ /** `serverId` null = the panel host. Answers at once; follow it with `get`. */
250
+ start: (id: number, serverId: number | null) => Promise<ServiceMoveView>;
251
+ };
252
+ inlineDockerfile: {
253
+ get: (id: number) => Promise<InlineDockerfileView>;
254
+ set: (id: number, content: string | null) => Promise<InlineDockerfileView>;
255
+ };
256
+ /**
257
+ * G1.7 registry push webhook: a secret URL a registry (Docker Hub, GHCR,
258
+ * Harbor, registry:2) calls after a push; the service redeploys when the
259
+ * pushed tag is its image. The URL is returned once, by `enable`.
260
+ */
261
+ /** GitLab, Gitea and Bitbucket commit statuses (ROADMAP 0.16.8 item 8). */
262
+ commitStatus: {
263
+ get: (id: number) => Promise<ServiceCommitStatusView>;
264
+ set: (id: number, enabled: boolean) => Promise<ServiceCommitStatusView>;
265
+ };
266
+ registryHook: {
267
+ get: (id: number) => Promise<RegistryHookView>;
268
+ enable: (id: number) => Promise<RegistryHookView>;
269
+ disable: (id: number) => Promise<RegistryHookView>;
270
+ };
271
+ /** G1.3: stop the service when its containers keep restarting (opt-in; member to set). */
272
+ restartLimit: {
273
+ get: (id: number) => Promise<RestartLimitView>;
274
+ set: (id: number, limit: RestartLimitConfig | null) => Promise<RestartLimitView>;
275
+ };
276
+ /**
277
+ * G5.2 pending changes tray. With staging on, edits collect (`stage`, a
278
+ * PATCH body) instead of applying; `apply` sends them through
279
+ * `update` together, optionally with a deploy.
280
+ */
281
+ pending: {
282
+ get: (id: number) => Promise<PendingChangesView>;
283
+ stage: (id: number, patch: UpdateServiceInput) => Promise<PendingChangesView>;
284
+ setStaging: (id: number, staging: boolean) => Promise<PendingChangesView>;
285
+ discard: (id: number) => Promise<PendingChangesView>;
286
+ apply: (id: number, input?: PendingApplyInput) => Promise<PendingApplyResult>;
287
+ };
197
288
  // ── 0.16.11 scale to zero ──
198
289
  /**
199
290
  * Put a docker service to sleep now (`POST /v1/services/:id/sleep`,
@@ -337,6 +428,53 @@ export function servicesApi(t: Transport): ServicesApi {
337
428
  swarmRecovery: async id => (await get<{ entry: SwarmRecoveryEntry | null }>(`/v1/services/${id}/swarm/recovery`)).entry,
338
429
  retrySwarmRecovery: id => request<SwarmRecoveryResult>(`/v1/services/${id}/swarm/recovery`, { method: 'POST' }, 600_000),
339
430
  autoscale: (id) => get<AutoscaleStatusView>(`/v1/services/${id}/autoscale`),
431
+ sizing: (id) => get<SizingReport>(`/v1/services/${id}/sizing`),
432
+ maintenance: {
433
+ get: (id) => get<MaintenanceView>(`/v1/services/${id}/maintenance`),
434
+ set: (id, maintenance) => send<MaintenanceView>('PUT', `/v1/services/${id}/maintenance`, { maintenance }),
435
+ },
436
+ errorPages: {
437
+ get: (id) => get<ErrorPagesView>(`/v1/services/${id}/error-pages`),
438
+ set: (id, pages) => send<ErrorPagesView>('PUT', `/v1/services/${id}/error-pages`, { pages }),
439
+ },
440
+ errors: {
441
+ list: (id, status) => get<ErrorIssueView[]>(`/v1/services/${id}/errors${status ? `?status=${status}` : ''}`),
442
+ get: (id, issueId) => get<{ issue: ErrorIssueView; events: ErrorEventView[] }>(`/v1/services/${id}/errors/${issueId}`),
443
+ setStatus: (id, issueId, status) => send<ErrorIssueView>('PATCH', `/v1/services/${id}/errors/${issueId}`, { status }),
444
+ ingest: {
445
+ get: (id) => get<ErrorIngestView>(`/v1/services/${id}/error-ingest`),
446
+ create: (id) => send<ErrorIngestView>('POST', `/v1/services/${id}/error-ingest`),
447
+ remove: (id) => send<ErrorIngestView>('DELETE', `/v1/services/${id}/error-ingest`),
448
+ },
449
+ },
450
+ move: {
451
+ get: (id) => get<ServiceMoveView>(`/v1/services/${id}/move`),
452
+ start: (id, serverId) => send<ServiceMoveView>('POST', `/v1/services/${id}/move`, { serverId }),
453
+ },
454
+ inlineDockerfile: {
455
+ get: (id) => get<InlineDockerfileView>(`/v1/services/${id}/inline-dockerfile`),
456
+ set: (id, content) => send<InlineDockerfileView>('PUT', `/v1/services/${id}/inline-dockerfile`, { content }),
457
+ },
458
+ commitStatus: {
459
+ get: (id) => get<ServiceCommitStatusView>(`/v1/services/${id}/commit-status`),
460
+ set: (id, enabled) => send<ServiceCommitStatusView>('PUT', `/v1/services/${id}/commit-status`, { enabled }),
461
+ },
462
+ registryHook: {
463
+ get: (id) => get<RegistryHookView>(`/v1/services/${id}/registry-hook`),
464
+ enable: (id) => send<RegistryHookView>('POST', `/v1/services/${id}/registry-hook`),
465
+ disable: (id) => request<RegistryHookView>(`/v1/services/${id}/registry-hook`, { method: 'DELETE' }),
466
+ },
467
+ restartLimit: {
468
+ get: (id) => get<RestartLimitView>(`/v1/services/${id}/restart-limit`),
469
+ set: (id, limit) => send<RestartLimitView>('PUT', `/v1/services/${id}/restart-limit`, { limit }),
470
+ },
471
+ pending: {
472
+ get: (id) => get<PendingChangesView>(`/v1/services/${id}/pending`),
473
+ stage: (id, patch) => send<PendingChangesView>('PUT', `/v1/services/${id}/pending`, patch),
474
+ setStaging: (id, staging) => send<PendingChangesView>('PUT', `/v1/services/${id}/pending/staging`, { staging }),
475
+ discard: (id) => send<PendingChangesView>('DELETE', `/v1/services/${id}/pending`),
476
+ apply: (id, input) => send<PendingApplyResult>('POST', `/v1/services/${id}/pending/apply`, input ?? {}),
477
+ },
340
478
  sleep: (id) => send<{ ok: boolean; asleep: boolean }>('POST', `/v1/services/${id}/sleep`),
341
479
  wake: (id) => send<{ ok: boolean; status: string }>('POST', `/v1/services/${id}/wake`),
342
480
  // ── end 0.16 T8 ──
@@ -11,10 +11,36 @@ import type {
11
11
  SecretProviderView,
12
12
  VaultProviderPut,
13
13
  AwsProviderPut,
14
+ GcpProviderPut,
15
+ AzureProviderPut,
16
+ OnePasswordProviderPut,
17
+ ExecProviderPut,
14
18
  } from '@ninedeploy/schemas';
15
19
  import type { VaultAllowlistView, VaultSettings, EmailTemplateName, EmailTemplateEntry, EmailTemplateRender } from '../types.js';
16
20
  import type { Transport } from '../transport.js';
17
21
 
22
+ /** The PUT body of each secret provider kind (G3.2 added gcp, azure, onepassword, exec). */
23
+ export type SecretProviderPutFor<K extends SecretProviderKind> = {
24
+ vault: VaultProviderPut;
25
+ aws: AwsProviderPut;
26
+ gcp: GcpProviderPut;
27
+ azure: AzureProviderPut;
28
+ onepassword: OnePasswordProviderPut;
29
+ exec: ExecProviderPut;
30
+ }[K];
31
+
32
+ /** G3.5: the DNS record providers configured through `settings.dnsProvider`. */
33
+ export type DnsCredentialProviderName = 'route53' | 'ovh' | 'porkbun' | 'hetzner';
34
+ export interface DnsProviderSettings {
35
+ providers: DnsCredentialProviderName[];
36
+ /** The active `dns_records_provider` (may be cloudflare, dnsimple, …). */
37
+ provider: string | null;
38
+ /** Which of these four has credentials saved. */
39
+ configured: DnsCredentialProviderName | null;
40
+ /** The saved non-secret fields (an access key id, an OVH endpoint). */
41
+ fields: Record<string, string>;
42
+ }
43
+
18
44
  export type AutoUrlMode = 'off' | 'domain' | 'sslip';
19
45
  export interface AutoUrlEffective {
20
46
  mode: AutoUrlMode;
@@ -88,6 +114,17 @@ export interface SettingsApi {
88
114
  get: () => Promise<{ configured: boolean; apiUser: string | null; clientIp: string | null; hasKey: boolean }>;
89
115
  set: (input: { apiUser: string; apiKey: string; clientIp: string }) => Promise<{ ok: boolean; apiUser: string }>;
90
116
  };
117
+ /**
118
+ * G3.5: Route 53, OVH, Porkbun and Hetzner DNS record auto-provisioning.
119
+ * Saving credentials makes that provider the active one; `get` never
120
+ * returns a secret.
121
+ */
122
+ dnsProvider: {
123
+ get: () => Promise<DnsProviderSettings>;
124
+ set: (input: { provider: DnsCredentialProviderName; credentials: Record<string, string> }) => Promise<{ ok: boolean; provider: string }>;
125
+ clear: () => Promise<{ ok: boolean }>;
126
+ test: () => Promise<{ ok: boolean; provider?: string; zones?: string[]; zoneCount?: number; error?: string }>;
127
+ };
91
128
  /**
92
129
  * Master-key rotation. `rotate` re-encrypts every stored secret onto the
93
130
  * highest key version in `NINEDEPLOY_MASTER_KEYS`; it does NOT rewrite
@@ -114,7 +151,7 @@ export interface SettingsApi {
114
151
  */
115
152
  secretProviders: {
116
153
  list: () => Promise<SecretProviderView[]>;
117
- set: <K extends SecretProviderKind>(kind: K, input: K extends 'vault' ? VaultProviderPut : AwsProviderPut) => Promise<SecretProviderView>;
154
+ set: <K extends SecretProviderKind>(kind: K, input: SecretProviderPutFor<K>) => Promise<SecretProviderView>;
118
155
  delete: (kind: SecretProviderKind) => Promise<{ ok: boolean; deleted: boolean }>;
119
156
  test: (kind: SecretProviderKind, probe?: SecretProviderTestRequest) => Promise<SecretProviderTestResult>;
120
157
  };
@@ -237,6 +274,13 @@ export function settingsApi(t: Transport): SettingsApi {
237
274
  get: () => get<{ configured: boolean; apiUser: string | null; clientIp: string | null; hasKey: boolean }>('/v1/settings/dns-records/namecheap'),
238
275
  set: (input) => send<{ ok: boolean; apiUser: string }>('PUT', '/v1/settings/dns-records/namecheap', input),
239
276
  },
277
+ dnsProvider: {
278
+ get: () => get<DnsProviderSettings>('/v1/settings/dns-records/provider'),
279
+ set: (input) => send<{ ok: boolean; provider: string }>('PUT', '/v1/settings/dns-records/provider', input),
280
+ clear: () => send<{ ok: boolean }>('DELETE', '/v1/settings/dns-records/provider'),
281
+ test: () =>
282
+ send<{ ok: boolean; provider?: string; zones?: string[]; zoneCount?: number; error?: string }>('POST', '/v1/settings/dns-records/provider/test'),
283
+ },
240
284
  masterKey: {
241
285
  get: () => get<{ activeVersion: number; knownVersions: number[]; rotatable: boolean }>('/v1/settings/master-key'),
242
286
  rotate: () =>
@@ -10,6 +10,8 @@ import type {
10
10
  GithubAppManifestRequest,
11
11
  GithubAppManifestResponse,
12
12
  GithubAppPatch,
13
+ GithubRunnerConfig,
14
+ GithubRunnerStatus,
13
15
  } from '@ninedeploy/schemas';
14
16
  import type { GithubAppInstallationSync, SourceRepo, SourceUpdateInput } from '../types.js';
15
17
  import type { Transport } from '../transport.js';
@@ -88,6 +90,11 @@ export interface SourcesApi {
88
90
  remove: (id: number) => Promise<void>;
89
91
  syncInstallations: (id: number) => Promise<GithubAppInstallationSync>;
90
92
  installations: (id: number) => Promise<GithubAppInstallation[]>;
93
+ /** Self-hosted Actions runners (G4.5): settings, waiting jobs, running runners and what is missing. */
94
+ runners: (id: number) => Promise<GithubRunnerStatus>;
95
+ setRunners: (id: number, config: GithubRunnerConfig) => Promise<GithubRunnerStatus>;
96
+ /** Stop one runner container (and remove its registration on GitHub). */
97
+ stopRunner: (id: number, name: string) => Promise<void>;
91
98
  };
92
99
  }
93
100
 
@@ -126,6 +133,11 @@ export function sourcesApi(t: Transport): SourcesApi {
126
133
  },
127
134
  syncInstallations: (id) => send<GithubAppInstallationSync>('POST', `/v1/github-apps/${id}/installations/sync`),
128
135
  installations: (id) => get<GithubAppInstallation[]>(`/v1/github-apps/${id}/installations`),
136
+ runners: (id) => get<GithubRunnerStatus>(`/v1/github-apps/${id}/runners`),
137
+ setRunners: (id, config) => send<GithubRunnerStatus>('PUT', `/v1/github-apps/${id}/runners`, config),
138
+ stopRunner: async (id, name) => {
139
+ await request(`/v1/github-apps/${id}/runners/${encodeURIComponent(name)}`, { method: 'DELETE' });
140
+ },
129
141
  },
130
142
  };
131
143
  }
@@ -1,4 +1,4 @@
1
- // Client surface: system, health, about, dashboard, stats, topology, activity, alerts, metricHistory, buildCache, housekeeping, doctor, demo.
1
+ // Client surface: system, health, about, dashboard, stats, usage, topology, activity, alerts, metricHistory, buildCache, housekeeping, doctor, demo.
2
2
  // Split out of the former single-file SDK entry (src/index.ts); the public
3
3
  // surface is re-exported unchanged from there.
4
4
  import type {
@@ -25,11 +25,30 @@ import type {
25
25
  PanelBackupRestore,
26
26
  PanelBackupSettingsPatch,
27
27
  PanelBackupStatus,
28
+ GitopsApplyStep,
29
+ GitopsCheck,
30
+ GitopsConfigInput,
31
+ GitopsView,
32
+ UsageCosts,
33
+ UsageCostsInput,
34
+ UsageReport,
28
35
  } from '@ninedeploy/schemas';
29
36
  import type { HealthStatus, ImageInfo, PruneImagesInput, PruneImagesResult } from '../types.js';
30
37
  import type { Transport } from '../transport.js';
31
38
 
32
39
  export interface SystemApi {
40
+ /** G5.3 instance GitOps (operators): the instance as a file in a repository. */
41
+ gitops: {
42
+ get: () => Promise<GitopsView>;
43
+ configure: (input: GitopsConfigInput) => Promise<GitopsView>;
44
+ remove: () => Promise<{ ok: true }>;
45
+ /** Read the file now and report the drift. */
46
+ check: () => Promise<GitopsCheck>;
47
+ /** Create and update what the file names (never deletes). */
48
+ apply: () => Promise<{ steps: GitopsApplyStep[]; check: GitopsCheck }>;
49
+ /** The live instance as the file, to commit. */
50
+ export: () => Promise<{ file: string }>;
51
+ };
33
52
  system: {
34
53
  resources: () => Promise<DockerResources>;
35
54
  pruneImages: () => Promise<{ ok: boolean }>;
@@ -92,6 +111,14 @@ export interface SystemApi {
92
111
  snapshot: (opts?: { databaseId?: number }) => Promise<StatsSnapshot>;
93
112
  metrics: (serviceId: number, opts?: { kind?: 'cpu' | 'memory'; minutes?: number }) => Promise<MetricSeries>;
94
113
  };
114
+ /** Usage and cost (operator only): CPU-hours, memory, bandwidth and cost per service, project and workspace. */
115
+ usage: {
116
+ /** The last `days` days (1–90, default 30). */
117
+ report: (opts?: { days?: number }) => Promise<UsageReport>;
118
+ costs: () => Promise<UsageCosts>;
119
+ /** The monthly cost of each server (`serverId: null` is the panel host). */
120
+ setCosts: (input: UsageCostsInput) => Promise<UsageCosts>;
121
+ };
95
122
  topology: {
96
123
  get: () => Promise<TopologyGraph>;
97
124
  };
@@ -175,6 +202,14 @@ export interface SystemApi {
175
202
  export function systemApi(t: Transport): SystemApi {
176
203
  const { get, send, request } = t;
177
204
  return {
205
+ gitops: {
206
+ get: () => get<GitopsView>('/v1/gitops'),
207
+ configure: (input) => send<GitopsView>('PUT', '/v1/gitops', input),
208
+ remove: () => send<{ ok: true }>('DELETE', '/v1/gitops'),
209
+ check: () => send<GitopsCheck>('POST', '/v1/gitops/check'),
210
+ apply: () => send<{ steps: GitopsApplyStep[]; check: GitopsCheck }>('POST', '/v1/gitops/apply'),
211
+ export: () => get<{ file: string }>('/v1/gitops/export?format=json'),
212
+ },
178
213
  system: {
179
214
  resources: () => get<DockerResources>('/v1/system/resources'),
180
215
  pruneImages: () => send<{ ok: boolean }>('POST', '/v1/system/prune-images'),
@@ -224,6 +259,11 @@ export function systemApi(t: Transport): SystemApi {
224
259
  `/v1/services/${serviceId}/metrics?kind=${opts?.kind ?? 'cpu'}&minutes=${opts?.minutes ?? 60}`,
225
260
  ),
226
261
  },
262
+ usage: {
263
+ report: (opts) => get<UsageReport>(`/v1/usage?days=${opts?.days ?? 30}`),
264
+ costs: () => get<UsageCosts>('/v1/usage/costs'),
265
+ setCosts: (input) => send<UsageCosts>('PUT', '/v1/usage/costs', input),
266
+ },
227
267
  topology: {
228
268
  get: () => get<TopologyGraph>('/v1/topology'),
229
269
  },
@@ -76,6 +76,11 @@ export interface TraefikApi {
76
76
  replace: (id: number, input: CustomCertificateReplace) => Promise<CustomCertificateSaved>;
77
77
  delete: (id: number) => Promise<{ ok: boolean }>;
78
78
  };
79
+ /** G5.7: give node proxies the panel's ACME certificates for the hosts they route (operator; off by default). */
80
+ sharedCertificates: {
81
+ get: () => Promise<{ enabled: boolean }>;
82
+ set: (enabled: boolean) => Promise<{ enabled: boolean }>;
83
+ };
79
84
  };
80
85
  }
81
86
 
@@ -120,6 +125,10 @@ export function traefikApi(t: Transport): TraefikApi {
120
125
  replace: (id, input) => send<CustomCertificateSaved>('PUT', `/v1/traefik/certificates/custom/${id}`, input),
121
126
  delete: (id) => send<{ ok: boolean }>('DELETE', `/v1/traefik/certificates/custom/${id}`),
122
127
  },
128
+ sharedCertificates: {
129
+ get: () => get<{ enabled: boolean }>('/v1/traefik/certificates/shared'),
130
+ set: (enabled) => send<{ enabled: boolean }>('PUT', '/v1/traefik/certificates/shared', { enabled }),
131
+ },
123
132
  },
124
133
  };
125
134
  }