@ninedeploy/sdk 0.3.4 → 0.5.0
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 +716 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +102 -10
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts +38 -0
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +60 -13
- package/dist/manifest.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { ActiveSession, ActivityEntry, AlertRule, AnalyzeRepoInput, CreateAlertRuleInput, ApiToken, PasskeyCredential, Attachment, CreateServiceVolumeAttachmentInput, CreateVolumeBackupInput, ServiceVolumeAttachment, UpdateServiceVolumeAttachmentInput, Backup, BackupWithDb,
|
|
1
|
+
import type { ActiveSession, ActivityEntry, AlertRule, AnalyzeRepoInput, CreateAlertRuleInput, ApiToken, PasskeyCredential, Attachment, CreateServiceVolumeAttachmentInput, CreateVolumeBackupInput, ServiceVolumeAttachment, UpdateServiceVolumeAttachmentInput, Backup, BackupWithDb, CreateApiTokenInput, CreateDatabaseInput, CreateDomainInput, CreateProjectInput, CreateServiceInput, CreateSourceInput, CreateTunnelInput, CreateWebhookInput, CreatedApiToken, CreatedWebhook, ConfigItem, ConfigListResponse, SetConfigInput, DoctorFixRequestInput, DoctorFixResponse, DoctorReport, PluginListResponse, PluginInspectResponse, InstallPluginInput, MarketplaceCatalogResponse, MenuListResponse, DemoSeedResult, Deployment, QueueResponse, DeployTemplateInput, DockerResources, Domain, DomainPatch, DomainEntry, EnvVar, Label, CreateLabelInput, LabelPatchInput, Login, ManagedDatabase, DatabaseDetail, DatabaseCredentials, PasswordChange, PasswordReset, MetricSeries, ProjectEntry, ProjectPatchInput, PublicUser, Refresh, Register, RepoInsights, Service, ServiceTags, SetServiceTagsInput, Session, SetLimitsInput, Source, StatsSnapshot, Template, TemplateSummary, CommunityTemplateListResult, TopologyGraph, TraefikCertificate, CertificateInventoryEntry, CertificateInventoryReport, TraefikInfo, TraefikStatus, TunnelEntry, UserCreate, VolumeFileEntry, VolumeFileWriteInput, VolumePathCreateInput, TriggerDeploy, UpdateCheckResult, SelfUpdateStatus, UpdateServiceInput, UpsertEnvVarInput, VolumeEntry, Webhook, LogDrain, LogDrainCreateInput, LogDrainUpdateInput, LogDrainTestResult, AutoPruneConfigUpdateInput, AutoPruneStatus, AutoPruneRunResult, ServerSshTest, ServerSshTestResult, ServerSshBootstrap, ServerBootstrapResult, WorkspaceEntry, WorkspaceDetail, WorkspaceCreateInput, WorkspaceUpdateInput, WorkspaceMemberEntry, WorkspaceMemberInviteEntry, WorkspaceMemberAddInput, WorkspaceMemberRoleUpdateInput, OidcPublicProvider, NinedeployManifest, WorkspaceInvitationEntry, WorkspaceInvitationPublic, WorkspaceRole, OidcProviderEntry, OidcProviderCreateInput, OidcProviderUpdateInput } from '@ninedeploy/schemas';
|
|
2
2
|
import { NineDeployError } from './errors.js';
|
|
3
3
|
export { NineDeployError };
|
|
4
4
|
export type * from '@ninedeploy/schemas';
|
|
5
|
-
export { detectProjectKind, formatManifestYaml, ManifestParseError, ManifestValidationError, parseManifestYaml, starterManifest, } from './manifest.js';
|
|
6
|
-
export type { ProjectKind } from './manifest.js';
|
|
5
|
+
export { detectProjectKind, formatManifestYaml, ManifestParseError, ManifestValidationError, parseManifestYaml, starterManifest, buildManifestFromTemplate, } from './manifest.js';
|
|
6
|
+
export type { ProjectKind, TemplateRegistryEntry } from './manifest.js';
|
|
7
7
|
/**
|
|
8
8
|
* Minimal structural fetch type so the SDK is isomorphic (browser + Node)
|
|
9
9
|
* without pulling in DOM lib types. Both `globalThis.fetch` implementations
|
|
@@ -24,6 +24,25 @@ export interface HealthStatus {
|
|
|
24
24
|
version?: string;
|
|
25
25
|
time?: string;
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Result of `GET /v1/auth/token`. Tells the caller what
|
|
29
|
+
* the current bearer credential is and what it can do.
|
|
30
|
+
* `kind` is `'session'` for JWTs and `'api'` for opaque
|
|
31
|
+
* API tokens. `scopes` lists the resource-scoped
|
|
32
|
+
* authorities (or the legacy `read` / `write` / `operator`
|
|
33
|
+
* shorthand); an interactive session reports
|
|
34
|
+
* `['session']` which is implicit full authority.
|
|
35
|
+
*/
|
|
36
|
+
export interface TokenIntrospection {
|
|
37
|
+
kind: 'session' | 'api';
|
|
38
|
+
userId: number;
|
|
39
|
+
scopes: string[];
|
|
40
|
+
expiresAt: string | null;
|
|
41
|
+
isOperator: boolean;
|
|
42
|
+
/** API tokens only. */
|
|
43
|
+
tokenId?: number;
|
|
44
|
+
name?: string;
|
|
45
|
+
}
|
|
27
46
|
export interface TemplateDeployResult {
|
|
28
47
|
serviceId: number;
|
|
29
48
|
serviceName: string;
|
|
@@ -52,6 +71,222 @@ export interface TemplatePrepareResult {
|
|
|
52
71
|
}>;
|
|
53
72
|
stages: TemplateDeployResult['stages'];
|
|
54
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Response from `services.manifest.apply`. The server returns the
|
|
76
|
+
* subset of fields the manifest actually changed under each
|
|
77
|
+
* section; untouched fields stay in the panel-managed column
|
|
78
|
+
* and do not appear in `diff`.
|
|
79
|
+
*/
|
|
80
|
+
export interface ApplyManifestResult {
|
|
81
|
+
ok: boolean;
|
|
82
|
+
serviceId: number;
|
|
83
|
+
/** Sections the server actually wrote: `service`, `build_config`. */
|
|
84
|
+
touched: string[];
|
|
85
|
+
diff: {
|
|
86
|
+
service: {
|
|
87
|
+
port?: number;
|
|
88
|
+
healthPath?: string;
|
|
89
|
+
publishedPort?: number | null;
|
|
90
|
+
};
|
|
91
|
+
build: {
|
|
92
|
+
installCmd?: string;
|
|
93
|
+
buildCmd?: string;
|
|
94
|
+
startCmd?: string;
|
|
95
|
+
baseDir?: string;
|
|
96
|
+
dockerfilePath?: string | null;
|
|
97
|
+
restartPolicy?: string;
|
|
98
|
+
stopGraceSeconds?: number;
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** Body for `services.manifest.apply`. The manifest shape itself
|
|
103
|
+
* comes from `@ninedeploy/schemas`'s `ninedeployManifest` parser. */
|
|
104
|
+
export interface ApplyManifestInput {
|
|
105
|
+
manifest: NinedeployManifest;
|
|
106
|
+
/** `merge` (default) preserves fields the manifest omits;
|
|
107
|
+
* `replace` is per-field (not per-row) and still leaves
|
|
108
|
+
* unmentioned sections alone. */
|
|
109
|
+
strategy?: 'merge' | 'replace';
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Single row from `GET /v1/databases/:id/drills`. The drill
|
|
113
|
+
* is an engine-specific smoke check (pg_restore --list,
|
|
114
|
+
* redis-check-rdb, mysqldump header parse, ...) that proves
|
|
115
|
+
* a backup is at least parseable without spinning up a real
|
|
116
|
+
* database container. `details` is the engine-specific
|
|
117
|
+
* output (object counts, banner, ...).
|
|
118
|
+
*/
|
|
119
|
+
export interface BackupDrillResult {
|
|
120
|
+
drillId: number;
|
|
121
|
+
ok: true;
|
|
122
|
+
status: 'passed' | 'failed';
|
|
123
|
+
durationMs: number;
|
|
124
|
+
details: Record<string, unknown> | null;
|
|
125
|
+
error: string | null;
|
|
126
|
+
}
|
|
127
|
+
/** History row from `GET /v1/databases/:id/drills`. */
|
|
128
|
+
export interface BackupDrillEntry {
|
|
129
|
+
id: number;
|
|
130
|
+
databaseId: number;
|
|
131
|
+
backupId: number;
|
|
132
|
+
status: 'pending' | 'running' | 'passed' | 'failed';
|
|
133
|
+
engine: string;
|
|
134
|
+
durationMs: number;
|
|
135
|
+
error: string | null;
|
|
136
|
+
details: Record<string, unknown> | null;
|
|
137
|
+
startedAt: number;
|
|
138
|
+
completedAt: number | null;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Body for `POST /v1/log-drains/search` (G-16). The
|
|
142
|
+
* search round-trips to the configured Loki drain.
|
|
143
|
+
*/
|
|
144
|
+
export interface LogSearchInput {
|
|
145
|
+
/** Free-text search (case-insensitive substring). */
|
|
146
|
+
query: string;
|
|
147
|
+
/** Restrict to one service. */
|
|
148
|
+
serviceId?: number;
|
|
149
|
+
/** Window length in minutes (default 15). */
|
|
150
|
+
sinceMinutes?: number;
|
|
151
|
+
/** Hard cap on returned lines (default 200, max 1000). */
|
|
152
|
+
limit?: number;
|
|
153
|
+
/** Query a specific drain. */
|
|
154
|
+
drainId?: number;
|
|
155
|
+
}
|
|
156
|
+
export interface LogSearchLine {
|
|
157
|
+
ts: number;
|
|
158
|
+
line: string;
|
|
159
|
+
service: string | null;
|
|
160
|
+
}
|
|
161
|
+
export interface LogSearchResult {
|
|
162
|
+
drain: {
|
|
163
|
+
id: number;
|
|
164
|
+
name: string;
|
|
165
|
+
type: string;
|
|
166
|
+
};
|
|
167
|
+
serviceId: number | null;
|
|
168
|
+
window: {
|
|
169
|
+
since: string;
|
|
170
|
+
until: string;
|
|
171
|
+
};
|
|
172
|
+
lines: LogSearchLine[];
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Built-in email template names (G-30). The full set
|
|
176
|
+
* lives in `apps/server/src/lib/emailTemplates.ts`; the
|
|
177
|
+
* union here is the closed set the SDK can name. The
|
|
178
|
+
* server validates on the wire (zod enum) — a string
|
|
179
|
+
* the SDK does not know about returns 400.
|
|
180
|
+
*/
|
|
181
|
+
export type EmailTemplateName = 'password-reset' | 'workspace-invitation' | 'domain-transfer' | 'backup-drill-failed';
|
|
182
|
+
/** One row from `GET /v1/workspaces/:wid/email-templates`. */
|
|
183
|
+
export interface EmailTemplateEntry {
|
|
184
|
+
name: EmailTemplateName;
|
|
185
|
+
/** True when the workspace has an override for this name. */
|
|
186
|
+
overridden: boolean;
|
|
187
|
+
/** Override subject; null when the built-in default applies. */
|
|
188
|
+
subject: string | null;
|
|
189
|
+
/** Override text body; null when the built-in default applies. */
|
|
190
|
+
text: string | null;
|
|
191
|
+
}
|
|
192
|
+
/** Result of `POST /v1/workspaces/:wid/email-templates/preview`. */
|
|
193
|
+
export interface EmailTemplateRender {
|
|
194
|
+
subject: string;
|
|
195
|
+
text: string;
|
|
196
|
+
/** True when the rendered text came from a tenant override. */
|
|
197
|
+
overridden: boolean;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Result of `GET /v1/databases/:id/pgbouncer` (and the
|
|
201
|
+
* post-mutation body of the enable / disable routes).
|
|
202
|
+
* `pooledConnectionString` is non-null only when `running`
|
|
203
|
+
* is true — a `docker inspect` failure on the sidecar
|
|
204
|
+
* reports `enabled: true, running: false` so the panel
|
|
205
|
+
* can surface the discrepancy.
|
|
206
|
+
*/
|
|
207
|
+
export interface PgbouncerStatus {
|
|
208
|
+
enabled: boolean;
|
|
209
|
+
containerName: string | null;
|
|
210
|
+
port: number;
|
|
211
|
+
running: boolean;
|
|
212
|
+
poolMode: string | null;
|
|
213
|
+
pooledConnectionString: string | null;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Single image row from `GET /v1/housekeeping/images`. Both
|
|
217
|
+
* the human-readable `size` ("1.2GB") and a parsed byte
|
|
218
|
+
* count are returned so the panel can sort without
|
|
219
|
+
* re-parsing. `inUse` is true when at least one container
|
|
220
|
+
* is currently using the image id.
|
|
221
|
+
*/
|
|
222
|
+
export interface ImageInfo {
|
|
223
|
+
repository: string;
|
|
224
|
+
tag: string;
|
|
225
|
+
id: string;
|
|
226
|
+
size: string;
|
|
227
|
+
sizeBytes: number;
|
|
228
|
+
createdAt: string;
|
|
229
|
+
ageHours: number;
|
|
230
|
+
dangling: boolean;
|
|
231
|
+
inUse: boolean;
|
|
232
|
+
}
|
|
233
|
+
/** Body for `POST /v1/housekeeping/images/prune`. The server
|
|
234
|
+
* refuses the empty-options combination (it would delete
|
|
235
|
+
* every image not currently in use). */
|
|
236
|
+
export interface PruneImagesInput {
|
|
237
|
+
keepLast?: number;
|
|
238
|
+
olderThanHours?: number;
|
|
239
|
+
danglingOnly?: boolean;
|
|
240
|
+
dryRun?: boolean;
|
|
241
|
+
}
|
|
242
|
+
export interface PruneImagesResult {
|
|
243
|
+
freedBytes: number;
|
|
244
|
+
removed: string[];
|
|
245
|
+
removedLabels: string[];
|
|
246
|
+
dryRun: boolean;
|
|
247
|
+
output: string;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Result of `POST /v1/domains/:id/transfer` (start a
|
|
251
|
+
* transfer). The caller forwards `acceptUrl` to the target
|
|
252
|
+
* user out-of-band; the token is the only secret embedded
|
|
253
|
+
* in the URL.
|
|
254
|
+
*/
|
|
255
|
+
export interface StartDomainTransferResult {
|
|
256
|
+
ok: boolean;
|
|
257
|
+
transferId: number;
|
|
258
|
+
acceptUrl: string;
|
|
259
|
+
expiresAt: number;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Result of `GET /v1/domain-transfers/:token` (preview).
|
|
263
|
+
* `effectivelyExpired` is true when the row is still
|
|
264
|
+
* `pending` server-side but `expiresAt` is in the past;
|
|
265
|
+
* the route reports it as `expired` and refuses accept.
|
|
266
|
+
*/
|
|
267
|
+
export interface DomainTransferPreview {
|
|
268
|
+
id: number;
|
|
269
|
+
status: 'pending' | 'accepted' | 'cancelled' | 'expired';
|
|
270
|
+
hostname: string;
|
|
271
|
+
sourceEmail: string;
|
|
272
|
+
targetEmail: string;
|
|
273
|
+
expiresAt: number;
|
|
274
|
+
createdAt: number;
|
|
275
|
+
acceptedAt: number | null;
|
|
276
|
+
cancelledAt: number | null;
|
|
277
|
+
effectivelyExpired: boolean;
|
|
278
|
+
}
|
|
279
|
+
/** Body for `POST /v1/domain-transfers/:token/accept`. */
|
|
280
|
+
export interface AcceptDomainTransferInput {
|
|
281
|
+
targetServiceId: number;
|
|
282
|
+
}
|
|
283
|
+
export interface AcceptDomainTransferResult {
|
|
284
|
+
ok: boolean;
|
|
285
|
+
transferId: number;
|
|
286
|
+
domainId: number;
|
|
287
|
+
serviceId: number;
|
|
288
|
+
hostname: string;
|
|
289
|
+
}
|
|
55
290
|
export interface NineDeployClientOptions {
|
|
56
291
|
/** Base URL of the NineDeploy API, e.g. http://localhost:3000. */
|
|
57
292
|
baseUrl: string;
|
|
@@ -65,6 +300,15 @@ export interface NineDeployClient {
|
|
|
65
300
|
status: () => Promise<{
|
|
66
301
|
initialized: boolean;
|
|
67
302
|
}>;
|
|
303
|
+
/**
|
|
304
|
+
* Introspect the current bearer token. Returns the
|
|
305
|
+
* token's id (when opaque), name, scopes, expiry and
|
|
306
|
+
* the operator flag. Interactive sessions (JWT) report
|
|
307
|
+
* `scopes: ['session']`. The MCP server uses this to
|
|
308
|
+
* discover the token's authority before registering
|
|
309
|
+
* tools.
|
|
310
|
+
*/
|
|
311
|
+
introspectToken: () => Promise<TokenIntrospection>;
|
|
68
312
|
setup: (input: Register) => Promise<Session>;
|
|
69
313
|
register: (input: Register) => Promise<Session>;
|
|
70
314
|
login: (input: Login) => Promise<Session>;
|
|
@@ -107,7 +351,7 @@ export interface NineDeployClient {
|
|
|
107
351
|
};
|
|
108
352
|
me: () => Promise<PublicUser>;
|
|
109
353
|
tokens: {
|
|
110
|
-
create: (input?:
|
|
354
|
+
create: (input?: CreateApiTokenInput) => Promise<CreatedApiToken>;
|
|
111
355
|
list: () => Promise<ApiToken[]>;
|
|
112
356
|
remove: (id: number) => Promise<void>;
|
|
113
357
|
};
|
|
@@ -223,6 +467,23 @@ export interface NineDeployClient {
|
|
|
223
467
|
slug: string;
|
|
224
468
|
message: string;
|
|
225
469
|
}>;
|
|
470
|
+
/**
|
|
471
|
+
* `.ninedeploy` manifest endpoints. The server applies
|
|
472
|
+
* build / run / network sections to the service + build
|
|
473
|
+
* config rows (operator > manifest > DB merge semantics);
|
|
474
|
+
* routes / alerts / database reconcile happens at deploy
|
|
475
|
+
* time via the deploy pipeline and is intentionally
|
|
476
|
+
* outside this endpoint's scope.
|
|
477
|
+
*/
|
|
478
|
+
manifest: {
|
|
479
|
+
/**
|
|
480
|
+
* Push a parsed manifest to the panel and reconcile it
|
|
481
|
+
* into the service. Requires the `admin` role on the
|
|
482
|
+
* service. The response echoes the diff so the CLI can
|
|
483
|
+
* render a one-shot summary without a follow-up GET.
|
|
484
|
+
*/
|
|
485
|
+
apply: (serviceId: number, input: ApplyManifestInput) => Promise<ApplyManifestResult>;
|
|
486
|
+
};
|
|
226
487
|
};
|
|
227
488
|
labels: {
|
|
228
489
|
/** `query` is appended verbatim, e.g. `?workspaceId=1`. */
|
|
@@ -244,6 +505,13 @@ export interface NineDeployClient {
|
|
|
244
505
|
deploymentId: number;
|
|
245
506
|
}>;
|
|
246
507
|
list: (serviceId: number) => Promise<Deployment[]>;
|
|
508
|
+
/**
|
|
509
|
+
* Global deploy queue view: every in-flight (queued / building /
|
|
510
|
+
* deploying) deployment the caller can see, with service + project
|
|
511
|
+
* metadata. The optional `status` filter is a comma-separated token
|
|
512
|
+
* list (e.g. `?status=queued,building`).
|
|
513
|
+
*/
|
|
514
|
+
queue: (query?: string) => Promise<QueueResponse>;
|
|
247
515
|
rollback: (serviceId: number, deploymentId: number) => Promise<{
|
|
248
516
|
deploymentId: number;
|
|
249
517
|
}>;
|
|
@@ -252,6 +520,15 @@ export interface NineDeployClient {
|
|
|
252
520
|
ok: boolean;
|
|
253
521
|
status: string;
|
|
254
522
|
}>;
|
|
523
|
+
/**
|
|
524
|
+
* Remove a finished deployment from history, with its build log.
|
|
525
|
+
* Refused for an in-flight deployment (cancel it first) and for the one
|
|
526
|
+
* currently serving traffic. Requires the `admin` role on the service.
|
|
527
|
+
*/
|
|
528
|
+
remove: (serviceId: number, deploymentId: number) => Promise<{
|
|
529
|
+
ok: boolean;
|
|
530
|
+
id: number;
|
|
531
|
+
}>;
|
|
255
532
|
/** Build-config + env-key diff against the previous deployment. */
|
|
256
533
|
configDiff: (serviceId: number, deploymentId: number) => Promise<{
|
|
257
534
|
deploymentId: number;
|
|
@@ -271,6 +548,257 @@ export interface NineDeployClient {
|
|
|
271
548
|
id: number;
|
|
272
549
|
ssl: boolean;
|
|
273
550
|
}>;
|
|
551
|
+
/** Toggle sticky-session routing for the service (G-28). */
|
|
552
|
+
setStickySession: (serviceId: number, enabled: boolean) => Promise<{
|
|
553
|
+
id: number;
|
|
554
|
+
enabled: boolean;
|
|
555
|
+
active: boolean;
|
|
556
|
+
}>;
|
|
557
|
+
/**
|
|
558
|
+
* Start a domain transfer (G-29). The source user (admin
|
|
559
|
+
* on the source service) names the target email; the
|
|
560
|
+
* server returns a one-time `acceptUrl` to forward. The
|
|
561
|
+
* target user accepts via `acceptDomainTransfer(token,
|
|
562
|
+
* { targetServiceId })`. The transfer expires after 7
|
|
563
|
+
* days; cancelling is one call.
|
|
564
|
+
*/
|
|
565
|
+
transfer: (domainId: number, input: {
|
|
566
|
+
targetEmail: string;
|
|
567
|
+
}) => Promise<StartDomainTransferResult>;
|
|
568
|
+
/**
|
|
569
|
+
* Preview a transfer by token. Does NOT require auth
|
|
570
|
+
* (the token is the secret) — the panel uses this to
|
|
571
|
+
* render the accept page to a logged-out visitor.
|
|
572
|
+
*/
|
|
573
|
+
previewTransfer: (token: string) => Promise<DomainTransferPreview>;
|
|
574
|
+
/**
|
|
575
|
+
* Accept a transfer. The caller must be authenticated
|
|
576
|
+
* and the caller's email must equal the transfer's
|
|
577
|
+
* target email; the panel / CLI surfaces the preview
|
|
578
|
+
* first so the user knows what they're signing in to.
|
|
579
|
+
*/
|
|
580
|
+
acceptTransfer: (token: string, input: AcceptDomainTransferInput) => Promise<AcceptDomainTransferResult>;
|
|
581
|
+
/**
|
|
582
|
+
* Cancel a pending transfer. Only the source user
|
|
583
|
+
* (or an instance operator) can cancel.
|
|
584
|
+
*/
|
|
585
|
+
cancelTransfer: (token: string) => Promise<{
|
|
586
|
+
transferId: number;
|
|
587
|
+
status: 'cancelled';
|
|
588
|
+
}>;
|
|
589
|
+
};
|
|
590
|
+
domainPresets: {
|
|
591
|
+
/** Every `IDomainProvider` the running kernel has registered. */
|
|
592
|
+
list: () => Promise<{
|
|
593
|
+
providers: string[];
|
|
594
|
+
}>;
|
|
595
|
+
/**
|
|
596
|
+
* Manually create the DNS record for `hostname` via the operator's
|
|
597
|
+
* active provider. `content` is optional: when omitted the route
|
|
598
|
+
* falls back to the panel's `dns_records_content` setting, then to
|
|
599
|
+
* `detectPublicIp()`. Returns the upstream recordId so the caller
|
|
600
|
+
* can correlate.
|
|
601
|
+
*/
|
|
602
|
+
apply: (input: {
|
|
603
|
+
hostname: string;
|
|
604
|
+
content?: string;
|
|
605
|
+
}) => Promise<{
|
|
606
|
+
hostname: string;
|
|
607
|
+
provider: string;
|
|
608
|
+
zone: string;
|
|
609
|
+
recordId: string;
|
|
610
|
+
type: 'A' | 'CNAME';
|
|
611
|
+
content: string;
|
|
612
|
+
}>;
|
|
613
|
+
};
|
|
614
|
+
configPresets: {
|
|
615
|
+
/** Every preset the kernel has registered. */
|
|
616
|
+
list: () => Promise<{
|
|
617
|
+
presets: string[];
|
|
618
|
+
}>;
|
|
619
|
+
/** Fetch a single preset's values + description. */
|
|
620
|
+
get: (id: string) => Promise<{
|
|
621
|
+
id: string;
|
|
622
|
+
description: string | null;
|
|
623
|
+
values: Record<string, unknown>;
|
|
624
|
+
createdAt: string;
|
|
625
|
+
}>;
|
|
626
|
+
/** Register a new preset. Throws if `id` already exists. */
|
|
627
|
+
register: (input: {
|
|
628
|
+
id: string;
|
|
629
|
+
description?: string;
|
|
630
|
+
values: Record<string, unknown>;
|
|
631
|
+
}) => Promise<{
|
|
632
|
+
ok: boolean;
|
|
633
|
+
id: string;
|
|
634
|
+
keyCount: number;
|
|
635
|
+
}>;
|
|
636
|
+
/** Write every value in the preset to the live configCenter. */
|
|
637
|
+
apply: (id: string, opts?: {
|
|
638
|
+
override?: Record<string, unknown>;
|
|
639
|
+
}) => Promise<{
|
|
640
|
+
ok: boolean;
|
|
641
|
+
id: string;
|
|
642
|
+
keyCount: number;
|
|
643
|
+
failureCount?: number;
|
|
644
|
+
failures?: Array<{
|
|
645
|
+
key: string;
|
|
646
|
+
status: 'failed';
|
|
647
|
+
reason?: string;
|
|
648
|
+
}>;
|
|
649
|
+
}>;
|
|
650
|
+
/** Unregister a preset. Does NOT undo the apply. */
|
|
651
|
+
remove: (id: string) => Promise<{
|
|
652
|
+
ok: boolean;
|
|
653
|
+
id: string;
|
|
654
|
+
}>;
|
|
655
|
+
};
|
|
656
|
+
metricHistory: {
|
|
657
|
+
/** Current configuration snapshot (backend choice, enabled flag, retention, last-flush). */
|
|
658
|
+
get: () => Promise<{
|
|
659
|
+
enabled: boolean;
|
|
660
|
+
backend: 'builtin' | 'prometheus' | 'influxdb';
|
|
661
|
+
events: string[];
|
|
662
|
+
retentionDays: number;
|
|
663
|
+
lastFlush: {
|
|
664
|
+
ts: number;
|
|
665
|
+
backend: string;
|
|
666
|
+
count: number;
|
|
667
|
+
};
|
|
668
|
+
}>;
|
|
669
|
+
/** Run the built-in backend's retention sweep. Returns the row count trimmed. */
|
|
670
|
+
flush: () => Promise<{
|
|
671
|
+
ok: boolean;
|
|
672
|
+
backend: 'builtin';
|
|
673
|
+
deleted: number;
|
|
674
|
+
}>;
|
|
675
|
+
};
|
|
676
|
+
buildCache: {
|
|
677
|
+
/** Per-backend counters + merged totals. G-01 PR-A. */
|
|
678
|
+
stats: () => Promise<{
|
|
679
|
+
backends: Array<{
|
|
680
|
+
name: string;
|
|
681
|
+
entries: number;
|
|
682
|
+
totalBytes: number;
|
|
683
|
+
hits: number;
|
|
684
|
+
misses: number;
|
|
685
|
+
stores: number;
|
|
686
|
+
evictions: number;
|
|
687
|
+
}>;
|
|
688
|
+
totals: {
|
|
689
|
+
entries: number;
|
|
690
|
+
totalBytes: number;
|
|
691
|
+
hits: number;
|
|
692
|
+
misses: number;
|
|
693
|
+
stores: number;
|
|
694
|
+
evictions: number;
|
|
695
|
+
};
|
|
696
|
+
}>;
|
|
697
|
+
};
|
|
698
|
+
orchestrators: {
|
|
699
|
+
/** Every `IOrchestrator` the running kernel has registered. G-10 PR-A. */
|
|
700
|
+
list: () => Promise<{
|
|
701
|
+
orchestrators: Array<{
|
|
702
|
+
name: string;
|
|
703
|
+
stacks: Array<{
|
|
704
|
+
name: string;
|
|
705
|
+
serviceCount: number;
|
|
706
|
+
}>;
|
|
707
|
+
}>;
|
|
708
|
+
}>;
|
|
709
|
+
/** Stable snapshot of one stack. Returns `null` when the orchestrator has no record. */
|
|
710
|
+
stackStatus: (name: string) => Promise<{
|
|
711
|
+
name: string;
|
|
712
|
+
services: Array<{
|
|
713
|
+
name: string;
|
|
714
|
+
state: 'running' | 'stopped' | 'partial' | 'unknown';
|
|
715
|
+
replicas: number;
|
|
716
|
+
}>;
|
|
717
|
+
appliedAt: string;
|
|
718
|
+
} | null>;
|
|
719
|
+
};
|
|
720
|
+
branding: {
|
|
721
|
+
/** Read the four operator-overridable branding fields. G-30. */
|
|
722
|
+
get: () => Promise<{
|
|
723
|
+
logoUrl: string | null;
|
|
724
|
+
primaryColor: string | null;
|
|
725
|
+
supportEmail: string | null;
|
|
726
|
+
footerHtml: string | null;
|
|
727
|
+
}>;
|
|
728
|
+
/** Set one or more branding fields. Empty strings are stored as `null`. */
|
|
729
|
+
set: (input: {
|
|
730
|
+
logoUrl?: string | null;
|
|
731
|
+
primaryColor?: string | null;
|
|
732
|
+
supportEmail?: string | null;
|
|
733
|
+
footerHtml?: string | null;
|
|
734
|
+
}) => Promise<{
|
|
735
|
+
ok: boolean;
|
|
736
|
+
}>;
|
|
737
|
+
};
|
|
738
|
+
egress: {
|
|
739
|
+
/** Every egress IP rule across every registered driver. G-15. */
|
|
740
|
+
list: () => Promise<{
|
|
741
|
+
drivers: Array<{
|
|
742
|
+
name: string;
|
|
743
|
+
rules: Array<{
|
|
744
|
+
selector: {
|
|
745
|
+
projectId: number;
|
|
746
|
+
sourceCidr?: string;
|
|
747
|
+
};
|
|
748
|
+
ip: string;
|
|
749
|
+
createdAt: string;
|
|
750
|
+
}>;
|
|
751
|
+
}>;
|
|
752
|
+
}>;
|
|
753
|
+
/** Attach an egress IP to a project on the named (or first) driver. */
|
|
754
|
+
set: (input: {
|
|
755
|
+
projectId: number;
|
|
756
|
+
ip: string;
|
|
757
|
+
driver?: string;
|
|
758
|
+
}) => Promise<{
|
|
759
|
+
ok: boolean;
|
|
760
|
+
driver: string;
|
|
761
|
+
rule: {
|
|
762
|
+
selector: {
|
|
763
|
+
projectId: number;
|
|
764
|
+
sourceCidr?: string;
|
|
765
|
+
};
|
|
766
|
+
ip: string;
|
|
767
|
+
createdAt: string;
|
|
768
|
+
};
|
|
769
|
+
}>;
|
|
770
|
+
/** Detach the rule for a project. */
|
|
771
|
+
clear: (projectId: number) => Promise<{
|
|
772
|
+
ok: boolean;
|
|
773
|
+
driver: string;
|
|
774
|
+
}>;
|
|
775
|
+
};
|
|
776
|
+
sso: {
|
|
777
|
+
/** Every configured OIDC / SAML provider. G-22. */
|
|
778
|
+
listProviders: () => Promise<{
|
|
779
|
+
providers: Array<{
|
|
780
|
+
id: number;
|
|
781
|
+
type: 'oidc' | 'saml';
|
|
782
|
+
name: string;
|
|
783
|
+
createdAt: string;
|
|
784
|
+
}>;
|
|
785
|
+
}>;
|
|
786
|
+
/** Add a provider (OIDC issuer URL or SAML metadata URL lives in `config`). */
|
|
787
|
+
addProvider: (input: {
|
|
788
|
+
type: 'oidc' | 'saml';
|
|
789
|
+
name: string;
|
|
790
|
+
config: Record<string, unknown>;
|
|
791
|
+
}) => Promise<{
|
|
792
|
+
ok: boolean;
|
|
793
|
+
id?: number;
|
|
794
|
+
name?: string;
|
|
795
|
+
type?: 'oidc' | 'saml';
|
|
796
|
+
error?: string;
|
|
797
|
+
}>;
|
|
798
|
+
/** Remove a provider by id. */
|
|
799
|
+
removeProvider: (id: number) => Promise<{
|
|
800
|
+
ok: boolean;
|
|
801
|
+
}>;
|
|
274
802
|
};
|
|
275
803
|
volumes: {
|
|
276
804
|
list: () => Promise<VolumeEntry[]>;
|
|
@@ -494,6 +1022,41 @@ export interface NineDeployClient {
|
|
|
494
1022
|
error?: string;
|
|
495
1023
|
}>;
|
|
496
1024
|
};
|
|
1025
|
+
/** Namecheap DNS-record auto-provisioning for added domains (G-07 PR-A). */
|
|
1026
|
+
namecheap: {
|
|
1027
|
+
get: () => Promise<{
|
|
1028
|
+
configured: boolean;
|
|
1029
|
+
apiUser: string | null;
|
|
1030
|
+
clientIp: string | null;
|
|
1031
|
+
hasKey: boolean;
|
|
1032
|
+
}>;
|
|
1033
|
+
set: (input: {
|
|
1034
|
+
apiUser: string;
|
|
1035
|
+
apiKey: string;
|
|
1036
|
+
clientIp: string;
|
|
1037
|
+
}) => Promise<{
|
|
1038
|
+
ok: boolean;
|
|
1039
|
+
apiUser: string;
|
|
1040
|
+
}>;
|
|
1041
|
+
};
|
|
1042
|
+
/**
|
|
1043
|
+
* Master-key rotation. `rotate` re-encrypts every stored secret onto the
|
|
1044
|
+
* highest key version in `NINEDEPLOY_MASTER_KEYS`; it does NOT rewrite
|
|
1045
|
+
* backup envelopes, which is what `warning` reports.
|
|
1046
|
+
*/
|
|
1047
|
+
masterKey: {
|
|
1048
|
+
get: () => Promise<{
|
|
1049
|
+
activeVersion: number;
|
|
1050
|
+
knownVersions: number[];
|
|
1051
|
+
rotatable: boolean;
|
|
1052
|
+
}>;
|
|
1053
|
+
rotate: () => Promise<{
|
|
1054
|
+
rotated: number;
|
|
1055
|
+
activeVersion: number;
|
|
1056
|
+
backupsNotRotated: number;
|
|
1057
|
+
warning: string | null;
|
|
1058
|
+
}>;
|
|
1059
|
+
};
|
|
497
1060
|
};
|
|
498
1061
|
firewall: {
|
|
499
1062
|
status: () => Promise<{
|
|
@@ -556,6 +1119,19 @@ export interface NineDeployClient {
|
|
|
556
1119
|
url: string;
|
|
557
1120
|
expiresAt: string;
|
|
558
1121
|
}>;
|
|
1122
|
+
/**
|
|
1123
|
+
* Operator-only: grant or revoke the INSTANCE-operator flag.
|
|
1124
|
+
*
|
|
1125
|
+
* Not a workspace role — this is the flag that gates operator-only routes
|
|
1126
|
+
* and the host-privilege boundary (PM2/compose deploys, lifecycle hooks,
|
|
1127
|
+
* docker-socket templates). Creating a workspace does NOT confer it. The
|
|
1128
|
+
* last remaining operator cannot be demoted.
|
|
1129
|
+
*/
|
|
1130
|
+
setOperator: (id: number, isOperator: boolean) => Promise<{
|
|
1131
|
+
ok: boolean;
|
|
1132
|
+
id: number;
|
|
1133
|
+
isOperator: boolean;
|
|
1134
|
+
}>;
|
|
559
1135
|
};
|
|
560
1136
|
projects: {
|
|
561
1137
|
/** `query` is appended verbatim, e.g. `?workspaceId=2` (workspace scoping). */
|
|
@@ -600,6 +1176,7 @@ export interface NineDeployClient {
|
|
|
600
1176
|
type: string;
|
|
601
1177
|
eventFilter: string;
|
|
602
1178
|
active: boolean;
|
|
1179
|
+
configJson: string | null;
|
|
603
1180
|
createdAt: string;
|
|
604
1181
|
}>>;
|
|
605
1182
|
createChannel: (input: {
|
|
@@ -607,6 +1184,7 @@ export interface NineDeployClient {
|
|
|
607
1184
|
type: string;
|
|
608
1185
|
target: string;
|
|
609
1186
|
eventFilter?: string;
|
|
1187
|
+
configJson?: string | null;
|
|
610
1188
|
}) => Promise<{
|
|
611
1189
|
id: number;
|
|
612
1190
|
name: string;
|
|
@@ -617,6 +1195,7 @@ export interface NineDeployClient {
|
|
|
617
1195
|
target?: string;
|
|
618
1196
|
eventFilter?: string;
|
|
619
1197
|
active?: boolean;
|
|
1198
|
+
configJson?: string | null;
|
|
620
1199
|
}) => Promise<{
|
|
621
1200
|
id: number;
|
|
622
1201
|
active: boolean;
|
|
@@ -708,6 +1287,38 @@ export interface NineDeployClient {
|
|
|
708
1287
|
stopStudio: (id: number) => Promise<{
|
|
709
1288
|
ok: boolean;
|
|
710
1289
|
}>;
|
|
1290
|
+
/**
|
|
1291
|
+
* PgBouncer sidecar (G-32). Returns the current sidecar
|
|
1292
|
+
* state — `enabled` + `running` + the URL the services
|
|
1293
|
+
* should connect to. Use the same call after
|
|
1294
|
+
* `enablePgbouncer` / `disablePgbouncer` for a fresh
|
|
1295
|
+
* read (the route returns the post-mutation status).
|
|
1296
|
+
*/
|
|
1297
|
+
pgbouncerStatus: (id: number) => Promise<PgbouncerStatus>;
|
|
1298
|
+
/**
|
|
1299
|
+
* Spin up the sidecar. `port` is optional — the row's
|
|
1300
|
+
* existing `pgbouncerPort` (default 6432) is used
|
|
1301
|
+
* when omitted. Only `engine='postgres'` is supported;
|
|
1302
|
+
* the server returns 422 for any other engine.
|
|
1303
|
+
*/
|
|
1304
|
+
enablePgbouncer: (id: number, input?: {
|
|
1305
|
+
port?: number;
|
|
1306
|
+
}) => Promise<PgbouncerStatus>;
|
|
1307
|
+
/** Stop + remove the sidecar and clear the row's flags. */
|
|
1308
|
+
disablePgbouncer: (id: number) => Promise<PgbouncerStatus>;
|
|
1309
|
+
/**
|
|
1310
|
+
* Run an engine-specific smoke check against a backup
|
|
1311
|
+
* file (pg_restore --list, redis-check-rdb, mysqldump
|
|
1312
|
+
* header parse, ...). Returns the drill row with `status`
|
|
1313
|
+
* of `passed` or `failed`; a failed drill is a real
|
|
1314
|
+
* signal that the backup cannot be restored cleanly, not
|
|
1315
|
+
* a warning. Requires the `member` role on the database.
|
|
1316
|
+
*/
|
|
1317
|
+
drillBackup: (id: number, input: {
|
|
1318
|
+
backupId: number;
|
|
1319
|
+
}) => Promise<BackupDrillResult>;
|
|
1320
|
+
/** List the most recent drills for a database, newest first. */
|
|
1321
|
+
drills: (id: number) => Promise<BackupDrillEntry[]>;
|
|
711
1322
|
};
|
|
712
1323
|
attachments: {
|
|
713
1324
|
list: (serviceId: number) => Promise<Attachment[]>;
|
|
@@ -979,6 +1590,29 @@ export interface NineDeployClient {
|
|
|
979
1590
|
get: (id: string) => Promise<Template>;
|
|
980
1591
|
prepare: (id: string, input?: DeployTemplateInput) => Promise<TemplatePrepareResult>;
|
|
981
1592
|
deploy: (id: string, input?: DeployTemplateInput) => Promise<TemplateDeployResult>;
|
|
1593
|
+
/**
|
|
1594
|
+
* Community contributions (G-13). The `list` call
|
|
1595
|
+
* already merges community entries with the curated
|
|
1596
|
+
* catalog; the dedicated `community` namespace lets
|
|
1597
|
+
* the panel surface errors and the operator import
|
|
1598
|
+
* a new template from a PR comment or a file.
|
|
1599
|
+
*/
|
|
1600
|
+
community: {
|
|
1601
|
+
list: () => Promise<CommunityTemplateListResult>;
|
|
1602
|
+
import: (content: string, opts?: {
|
|
1603
|
+
replace?: boolean;
|
|
1604
|
+
}) => Promise<{
|
|
1605
|
+
ok: boolean;
|
|
1606
|
+
id: string;
|
|
1607
|
+
file: string;
|
|
1608
|
+
bytes: number;
|
|
1609
|
+
}>;
|
|
1610
|
+
remove: (id: string) => Promise<{
|
|
1611
|
+
ok: boolean;
|
|
1612
|
+
id: string;
|
|
1613
|
+
removed: boolean;
|
|
1614
|
+
}>;
|
|
1615
|
+
};
|
|
982
1616
|
};
|
|
983
1617
|
limits: {
|
|
984
1618
|
setService: (serviceId: number, input: SetLimitsInput) => Promise<{
|
|
@@ -994,6 +1628,30 @@ export interface NineDeployClient {
|
|
|
994
1628
|
get: () => Promise<TraefikInfo>;
|
|
995
1629
|
status: () => Promise<TraefikStatus>;
|
|
996
1630
|
certificates: () => Promise<TraefikCertificate[]>;
|
|
1631
|
+
/**
|
|
1632
|
+
* Richer certificate inventory (G-15). Same
|
|
1633
|
+
* underlying data as `certificates()` but adds a
|
|
1634
|
+
* `status` classification (valid / expiring-soon /
|
|
1635
|
+
* expired), a `summary` block, and the full set of
|
|
1636
|
+
* fields the Certificates page renders.
|
|
1637
|
+
* `threshold` is the days-out cutoff for the
|
|
1638
|
+
* `expiring-soon` bucket; default 30.
|
|
1639
|
+
*/
|
|
1640
|
+
certificateInventory: (opts?: {
|
|
1641
|
+
threshold?: number;
|
|
1642
|
+
}) => Promise<CertificateInventoryReport>;
|
|
1643
|
+
/**
|
|
1644
|
+
* Focused "expiring within N days" filter. Default
|
|
1645
|
+
* 30. Used by the alert engine and by the panel's
|
|
1646
|
+
* "About to expire" widget.
|
|
1647
|
+
*/
|
|
1648
|
+
expiringCertificates: (opts?: {
|
|
1649
|
+
days?: number;
|
|
1650
|
+
}) => Promise<{
|
|
1651
|
+
threshold: number;
|
|
1652
|
+
count: number;
|
|
1653
|
+
certificates: CertificateInventoryEntry[];
|
|
1654
|
+
}>;
|
|
997
1655
|
logs: (lines?: number) => Promise<{
|
|
998
1656
|
logs: string[];
|
|
999
1657
|
}>;
|
|
@@ -1025,7 +1683,9 @@ export interface NineDeployClient {
|
|
|
1025
1683
|
};
|
|
1026
1684
|
plugins: {
|
|
1027
1685
|
list: () => Promise<PluginListResponse>;
|
|
1028
|
-
marketplace: (
|
|
1686
|
+
marketplace: (opts?: {
|
|
1687
|
+
refresh?: boolean;
|
|
1688
|
+
}) => Promise<MarketplaceCatalogResponse>;
|
|
1029
1689
|
install: (input: InstallPluginInput) => Promise<{
|
|
1030
1690
|
ok: boolean;
|
|
1031
1691
|
id: string;
|
|
@@ -1071,11 +1731,62 @@ export interface NineDeployClient {
|
|
|
1071
1731
|
ok: boolean;
|
|
1072
1732
|
}>;
|
|
1073
1733
|
test: (id: number) => Promise<LogDrainTestResult>;
|
|
1734
|
+
/**
|
|
1735
|
+
* Search the configured Loki drain for `query` over
|
|
1736
|
+
* the last `sinceMinutes` (default 15). The route
|
|
1737
|
+
* round-trips to the drain's `url` so the upstream
|
|
1738
|
+
* does the heavy lifting; this is the same shape
|
|
1739
|
+
* the operator sees in the Loki Grafana panel.
|
|
1740
|
+
*/
|
|
1741
|
+
search: (input: LogSearchInput) => Promise<LogSearchResult>;
|
|
1742
|
+
};
|
|
1743
|
+
/**
|
|
1744
|
+
* Per-workspace email template overrides (G-30).
|
|
1745
|
+
* Read-side is open to members; write-side requires the
|
|
1746
|
+
* workspace's admin role. The list / preview are safe
|
|
1747
|
+
* to call from a CI script; `set` / `reset` mutate the
|
|
1748
|
+
* panel's outbound email and should be operator-only.
|
|
1749
|
+
*/
|
|
1750
|
+
emailTemplates: {
|
|
1751
|
+
list: (workspaceId: number) => Promise<{
|
|
1752
|
+
workspaceId: number;
|
|
1753
|
+
templates: EmailTemplateEntry[];
|
|
1754
|
+
}>;
|
|
1755
|
+
preview: (workspaceId: number, name: EmailTemplateName, vars?: Record<string, string | number | null>) => Promise<EmailTemplateRender>;
|
|
1756
|
+
set: (workspaceId: number, name: EmailTemplateName, subject: string, text: string) => Promise<{
|
|
1757
|
+
ok: boolean;
|
|
1758
|
+
}>;
|
|
1759
|
+
reset: (workspaceId: number, name: EmailTemplateName) => Promise<{
|
|
1760
|
+
ok: boolean;
|
|
1761
|
+
}>;
|
|
1074
1762
|
};
|
|
1075
1763
|
housekeeping: {
|
|
1076
1764
|
getAutoPrune: () => Promise<AutoPruneStatus>;
|
|
1077
1765
|
updateAutoPrune: (input: AutoPruneConfigUpdateInput) => Promise<AutoPruneStatus>;
|
|
1078
1766
|
runPrune: () => Promise<AutoPruneRunResult>;
|
|
1767
|
+
/**
|
|
1768
|
+
* List every image on the host with repo / tag / size /
|
|
1769
|
+
* created / dangling / inUse metadata. The companion to
|
|
1770
|
+
* the auto-prune cron: this is what the operator
|
|
1771
|
+
* inspects before `pruneImages({ keepLast: 5 })`.
|
|
1772
|
+
*/
|
|
1773
|
+
listImages: () => Promise<{
|
|
1774
|
+
images: ImageInfo[];
|
|
1775
|
+
totalCount: number;
|
|
1776
|
+
totalBytes: number;
|
|
1777
|
+
}>;
|
|
1778
|
+
/**
|
|
1779
|
+
* Prune images with operator-supplied filters. `dryRun`
|
|
1780
|
+
* returns the candidate set without deleting. Refused
|
|
1781
|
+
* when no filter is supplied (a naked prune would
|
|
1782
|
+
* delete every unused image).
|
|
1783
|
+
*/
|
|
1784
|
+
pruneImages: (input: PruneImagesInput) => Promise<PruneImagesResult>;
|
|
1785
|
+
};
|
|
1786
|
+
/** Host-wide analysis + guarded cleanup. */
|
|
1787
|
+
doctor: {
|
|
1788
|
+
scan: () => Promise<DoctorReport>;
|
|
1789
|
+
fix: (input: DoctorFixRequestInput) => Promise<DoctorFixResponse>;
|
|
1079
1790
|
};
|
|
1080
1791
|
health: () => Promise<HealthStatus>;
|
|
1081
1792
|
}
|