@ninedeploy/sdk 0.10.5 → 0.16.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/LICENSE +21 -21
- package/dist/apiPath.d.ts +5 -0
- package/dist/apiPath.d.ts.map +1 -0
- package/dist/apiPath.js +18 -0
- package/dist/apiPath.js.map +1 -0
- package/dist/client.d.ts +29 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +51 -0
- package/dist/client.js.map +1 -0
- package/dist/databaseImport.d.ts +138 -0
- package/dist/databaseImport.d.ts.map +1 -0
- package/dist/databaseImport.js +126 -0
- package/dist/databaseImport.js.map +1 -0
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +12 -1973
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -641
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +25 -21
- package/dist/manifest.js.map +1 -1
- package/dist/resources/auth.d.ts +282 -0
- package/dist/resources/auth.d.ts.map +1 -0
- package/dist/resources/auth.js +111 -0
- package/dist/resources/auth.js.map +1 -0
- package/dist/resources/databases.d.ts +178 -0
- package/dist/resources/databases.d.ts.map +1 -0
- package/dist/resources/databases.js +82 -0
- package/dist/resources/databases.js.map +1 -0
- package/dist/resources/deploys.d.ts +125 -0
- package/dist/resources/deploys.d.ts.map +1 -0
- package/dist/resources/deploys.js +46 -0
- package/dist/resources/deploys.js.map +1 -0
- package/dist/resources/domains.d.ts +101 -0
- package/dist/resources/domains.d.ts.map +1 -0
- package/dist/resources/domains.js +28 -0
- package/dist/resources/domains.js.map +1 -0
- package/dist/resources/env.d.ts +55 -0
- package/dist/resources/env.d.ts.map +1 -0
- package/dist/resources/env.js +33 -0
- package/dist/resources/env.js.map +1 -0
- package/dist/resources/logs.d.ts +27 -0
- package/dist/resources/logs.d.ts.map +1 -0
- package/dist/resources/logs.js +18 -0
- package/dist/resources/logs.js.map +1 -0
- package/dist/resources/network.d.ts +134 -0
- package/dist/resources/network.d.ts.map +1 -0
- package/dist/resources/network.js +33 -0
- package/dist/resources/network.js.map +1 -0
- package/dist/resources/plugins.d.ts +42 -0
- package/dist/resources/plugins.d.ts.map +1 -0
- package/dist/resources/plugins.js +22 -0
- package/dist/resources/plugins.js.map +1 -0
- package/dist/resources/servers.d.ts +130 -0
- package/dist/resources/servers.d.ts.map +1 -0
- package/dist/resources/servers.js +37 -0
- package/dist/resources/servers.js.map +1 -0
- package/dist/resources/services.d.ts +185 -0
- package/dist/resources/services.d.ts.map +1 -0
- package/dist/resources/services.js +83 -0
- package/dist/resources/services.js.map +1 -0
- package/dist/resources/settings.d.ts +312 -0
- package/dist/resources/settings.d.ts.map +1 -0
- package/dist/resources/settings.js +85 -0
- package/dist/resources/settings.js.map +1 -0
- package/dist/resources/sources.d.ts +87 -0
- package/dist/resources/sources.d.ts.map +1 -0
- package/dist/resources/sources.js +39 -0
- package/dist/resources/sources.js.map +1 -0
- package/dist/resources/system.d.ts +240 -0
- package/dist/resources/system.d.ts.map +1 -0
- package/dist/resources/system.js +86 -0
- package/dist/resources/system.js.map +1 -0
- package/dist/resources/templates.d.ts +36 -0
- package/dist/resources/templates.d.ts.map +1 -0
- package/dist/resources/templates.js +17 -0
- package/dist/resources/templates.js.map +1 -0
- package/dist/resources/terminals.d.ts +60 -0
- package/dist/resources/terminals.d.ts.map +1 -0
- package/dist/resources/terminals.js +35 -0
- package/dist/resources/terminals.js.map +1 -0
- package/dist/resources/traefik.d.ts +84 -0
- package/dist/resources/traefik.d.ts.map +1 -0
- package/dist/resources/traefik.js +35 -0
- package/dist/resources/traefik.js.map +1 -0
- package/dist/resources/volumes.d.ts +114 -0
- package/dist/resources/volumes.d.ts.map +1 -0
- package/dist/resources/volumes.js +47 -0
- package/dist/resources/volumes.js.map +1 -0
- package/dist/terminal.d.ts +98 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +180 -0
- package/dist/terminal.js.map +1 -0
- package/dist/transport.d.ts +61 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +90 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +539 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +5 -4
- package/src/apiPath.ts +23 -0
- package/src/client.ts +70 -0
- package/src/databaseImport.ts +174 -0
- package/src/errors.ts +27 -0
- package/src/index.ts +118 -0
- package/src/manifest.ts +414 -0
- package/src/resources/auth.ts +357 -0
- package/src/resources/databases.ts +227 -0
- package/src/resources/deploys.ts +161 -0
- package/src/resources/domains.ts +142 -0
- package/src/resources/env.ts +84 -0
- package/src/resources/logs.ts +48 -0
- package/src/resources/network.ts +126 -0
- package/src/resources/plugins.ts +52 -0
- package/src/resources/servers.ts +141 -0
- package/src/resources/services.ts +250 -0
- package/src/resources/settings.ts +275 -0
- package/src/resources/sources.ts +131 -0
- package/src/resources/system.ts +281 -0
- package/src/resources/templates.ts +55 -0
- package/src/resources/terminals.ts +112 -0
- package/src/resources/traefik.ts +116 -0
- package/src/resources/volumes.ts +138 -0
- package/src/terminal.ts +254 -0
- package/src/transport.ts +154 -0
- package/src/types.ts +588 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// Client surface: system, health, about, dashboard, stats, topology, activity, alerts, metricHistory, buildCache, housekeeping, doctor, demo.
|
|
2
|
+
// Split out of the former single-file SDK entry (src/index.ts); the public
|
|
3
|
+
// surface is re-exported unchanged from there.
|
|
4
|
+
import type {
|
|
5
|
+
ActivityEntry,
|
|
6
|
+
AlertRule,
|
|
7
|
+
CreateAlertRuleInput,
|
|
8
|
+
DoctorFixRequestInput,
|
|
9
|
+
DoctorFixResponse,
|
|
10
|
+
DoctorReport,
|
|
11
|
+
DemoSeedResult,
|
|
12
|
+
DockerResources,
|
|
13
|
+
MetricSeries,
|
|
14
|
+
StatsSnapshot,
|
|
15
|
+
TopologyGraph,
|
|
16
|
+
UpdateCheckResult,
|
|
17
|
+
SelfUpdateStatus,
|
|
18
|
+
AutoPruneConfigUpdateInput,
|
|
19
|
+
AutoPruneStatus,
|
|
20
|
+
AutoPruneRunResult,
|
|
21
|
+
PanelBackupObject,
|
|
22
|
+
PanelBackupRestore,
|
|
23
|
+
PanelBackupSettingsPatch,
|
|
24
|
+
PanelBackupStatus,
|
|
25
|
+
} from '@ninedeploy/schemas';
|
|
26
|
+
import type { HealthStatus, ImageInfo, PruneImagesInput, PruneImagesResult } from '../types.js';
|
|
27
|
+
import type { Transport } from '../transport.js';
|
|
28
|
+
|
|
29
|
+
export interface SystemApi {
|
|
30
|
+
system: {
|
|
31
|
+
resources: () => Promise<DockerResources>;
|
|
32
|
+
pruneImages: () => Promise<{ ok: boolean }>;
|
|
33
|
+
exportUrl: () => string;
|
|
34
|
+
/** Latest-release check (admin). updateAvailable is null when offline/disabled. */
|
|
35
|
+
updateCheck: (force?: boolean) => Promise<UpdateCheckResult>;
|
|
36
|
+
/** State of a panel-initiated upgrade (idle/running/success/failed/unsupported). */
|
|
37
|
+
updateStatus: () => Promise<SelfUpdateStatus>;
|
|
38
|
+
/**
|
|
39
|
+
* Start upgrading the panel itself to an exact release tag; the updater survives the restart it performs.
|
|
40
|
+
* Refused with 409 `deploys_in_flight` while deployments are executing unless `force` is set (r572).
|
|
41
|
+
*/
|
|
42
|
+
updateStart: (version: string, opts?: { force?: boolean }) => Promise<{ ok: boolean }>;
|
|
43
|
+
/** Recent docker daemon events (single-shot, for the Docker dashboard feed). */
|
|
44
|
+
dockerEvents: (minutes?: number) => Promise<{ events: Array<{ time: string; type: string; action: string; name: string }> }>;
|
|
45
|
+
/**
|
|
46
|
+
* Panel self-backup (0.12, operator-only): the `/system/export` archive sealed with a
|
|
47
|
+
* recovery passphrase and written to a backup destination on a schedule.
|
|
48
|
+
*/
|
|
49
|
+
panelBackup: {
|
|
50
|
+
/** Settings, last run, next run (passphrase never returned — only `hasPassphrase`). */
|
|
51
|
+
get: () => Promise<PanelBackupStatus>;
|
|
52
|
+
/** Omitted fields keep their stored value; `passphrase` omitted = keep the stored one. */
|
|
53
|
+
update: (input: PanelBackupSettingsPatch) => Promise<PanelBackupStatus>;
|
|
54
|
+
/** "Back up now": starts a run in the background (409 while one is running); poll `get()`. */
|
|
55
|
+
run: () => Promise<{ ok: boolean; started: boolean }>;
|
|
56
|
+
/** Panel backups in a destination (default: the configured one), newest first. */
|
|
57
|
+
list: (destinationId?: number) => Promise<{ destinationId: number; items: PanelBackupObject[] }>;
|
|
58
|
+
/**
|
|
59
|
+
* DESTRUCTIVE: replaces this panel's database, master key, .env and Traefik config with
|
|
60
|
+
* the backup's. `confirm` must repeat the object's file name. Restart the panel afterwards.
|
|
61
|
+
*/
|
|
62
|
+
restore: (input: PanelBackupRestore) => Promise<{ ok: boolean; message: string; meta: unknown; backupPath: string }>;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
health: () => Promise<HealthStatus>;
|
|
66
|
+
about: {
|
|
67
|
+
get: () => Promise<{
|
|
68
|
+
name: string; version: string; description: string; license: string; repo: string; docs: string;
|
|
69
|
+
techStack: Array<{ category: string; items: string[] }>;
|
|
70
|
+
changelog: Array<{ version: string; date: string; title: string; changes: string[] }>;
|
|
71
|
+
/** Instance counts are only returned for authenticated requests. */
|
|
72
|
+
stats?: { services: number; databases: number; deployments: number; users: number };
|
|
73
|
+
}>;
|
|
74
|
+
};
|
|
75
|
+
dashboard: {
|
|
76
|
+
get: () => Promise<{
|
|
77
|
+
stats: { services: number; databases: number; deployments: number; domains: number; webhooks: number; running: number; stopped: number; errored: number; dbRunning: number; /** Whole-node count — operators only, null for members (r470). */ containers: number | null };
|
|
78
|
+
health: Array<{ serviceId: number; name: string; slug: string; type: string; status: string; healthy: boolean | null; responseMs: number | null; port: number | null; runtimeId: string | null; commitSha: string | null; lastDeploy: string | null }>;
|
|
79
|
+
recentDeploys: Array<{ id: number; serviceId: number; serviceName: string; status: string; commitSha: string | null; message: string | null; trigger: string; finishedAt: string | null; createdAt: string }>;
|
|
80
|
+
}>;
|
|
81
|
+
};
|
|
82
|
+
stats: {
|
|
83
|
+
snapshot: () => Promise<StatsSnapshot>;
|
|
84
|
+
metrics: (serviceId: number, opts?: { kind?: 'cpu' | 'memory'; minutes?: number }) => Promise<MetricSeries>;
|
|
85
|
+
};
|
|
86
|
+
topology: {
|
|
87
|
+
get: () => Promise<TopologyGraph>;
|
|
88
|
+
};
|
|
89
|
+
activity: {
|
|
90
|
+
/**
|
|
91
|
+
* Filter + paginate the audit trail. Omitted filters return the newest page.
|
|
92
|
+
* `entity` matches the bare name and `<name> #<id>`; `serviceId` (with the
|
|
93
|
+
* service name as `entity`) narrows to one service's trail.
|
|
94
|
+
*/
|
|
95
|
+
list: (query?: { entity?: string; serviceId?: number; action?: string; userId?: number; before?: number }) => Promise<{ entries: ActivityEntry[]; nextCursor: number | null }>;
|
|
96
|
+
};
|
|
97
|
+
alerts: {
|
|
98
|
+
list: () => Promise<AlertRule[]>;
|
|
99
|
+
create: (input: CreateAlertRuleInput) => Promise<AlertRule>;
|
|
100
|
+
update: (id: number, input: Partial<CreateAlertRuleInput>) => Promise<AlertRule>;
|
|
101
|
+
remove: (id: number) => Promise<void>;
|
|
102
|
+
};
|
|
103
|
+
metricHistory: {
|
|
104
|
+
/** Current configuration snapshot (backend choice, enabled flag, retention, last-flush). */
|
|
105
|
+
get: () => Promise<{
|
|
106
|
+
enabled: boolean;
|
|
107
|
+
backend: 'builtin' | 'prometheus' | 'influxdb';
|
|
108
|
+
events: string[];
|
|
109
|
+
retentionDays: number;
|
|
110
|
+
lastFlush: { ts: number; backend: string; count: number };
|
|
111
|
+
}>;
|
|
112
|
+
/** Run the built-in backend's retention sweep. Returns the row count trimmed. */
|
|
113
|
+
flush: () => Promise<{ ok: boolean; backend: 'builtin'; deleted: number }>;
|
|
114
|
+
};
|
|
115
|
+
buildCache: {
|
|
116
|
+
/** Per-backend counters + merged totals. G-01 PR-A. */
|
|
117
|
+
stats: () => Promise<{
|
|
118
|
+
backends: Array<{
|
|
119
|
+
name: string;
|
|
120
|
+
entries: number;
|
|
121
|
+
totalBytes: number;
|
|
122
|
+
hits: number;
|
|
123
|
+
misses: number;
|
|
124
|
+
stores: number;
|
|
125
|
+
evictions: number;
|
|
126
|
+
}>;
|
|
127
|
+
totals: {
|
|
128
|
+
entries: number;
|
|
129
|
+
totalBytes: number;
|
|
130
|
+
hits: number;
|
|
131
|
+
misses: number;
|
|
132
|
+
stores: number;
|
|
133
|
+
evictions: number;
|
|
134
|
+
};
|
|
135
|
+
}>;
|
|
136
|
+
};
|
|
137
|
+
housekeeping: {
|
|
138
|
+
getAutoPrune: () => Promise<AutoPruneStatus>;
|
|
139
|
+
updateAutoPrune: (input: AutoPruneConfigUpdateInput) => Promise<AutoPruneStatus>;
|
|
140
|
+
runPrune: () => Promise<AutoPruneRunResult>;
|
|
141
|
+
/**
|
|
142
|
+
* List every image on the host with repo / tag / size /
|
|
143
|
+
* created / dangling / inUse metadata. The companion to
|
|
144
|
+
* the auto-prune cron: this is what the operator
|
|
145
|
+
* inspects before `pruneImages({ keepLast: 5 })`.
|
|
146
|
+
*/
|
|
147
|
+
listImages: () => Promise<{ images: ImageInfo[]; totalCount: number; totalBytes: number }>;
|
|
148
|
+
/**
|
|
149
|
+
* Prune images with operator-supplied filters. `dryRun`
|
|
150
|
+
* returns the candidate set without deleting. Refused
|
|
151
|
+
* when no filter is supplied (a naked prune would
|
|
152
|
+
* delete every unused image).
|
|
153
|
+
*/
|
|
154
|
+
pruneImages: (input: PruneImagesInput) => Promise<PruneImagesResult>;
|
|
155
|
+
};
|
|
156
|
+
/** Host-wide analysis + guarded cleanup. */
|
|
157
|
+
doctor: {
|
|
158
|
+
scan: () => Promise<DoctorReport>;
|
|
159
|
+
fix: (input: DoctorFixRequestInput) => Promise<DoctorFixResponse>;
|
|
160
|
+
};
|
|
161
|
+
demo: {
|
|
162
|
+
seed: () => Promise<DemoSeedResult>;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function systemApi(t: Transport): SystemApi {
|
|
167
|
+
const { get, send, request } = t;
|
|
168
|
+
return {
|
|
169
|
+
system: {
|
|
170
|
+
resources: () => get<DockerResources>('/v1/system/resources'),
|
|
171
|
+
pruneImages: () => send<{ ok: boolean }>('POST', '/v1/system/prune-images'),
|
|
172
|
+
updateCheck: (force) => get<UpdateCheckResult>(`/v1/system/update-check${force ? '?force=1' : ''}`),
|
|
173
|
+
updateStatus: () => get<SelfUpdateStatus>('/v1/system/update-status'),
|
|
174
|
+
updateStart: (version, opts) => send<{ ok: boolean }>('POST', '/v1/system/update-start', { version, ...opts }),
|
|
175
|
+
exportUrl: () => '/v1/system/export',
|
|
176
|
+
dockerEvents: (minutes) =>
|
|
177
|
+
get<{ events: Array<{ time: string; type: string; action: string; name: string }> }>(
|
|
178
|
+
`/v1/system/docker-events?minutes=${minutes ?? 60}`,
|
|
179
|
+
),
|
|
180
|
+
panelBackup: {
|
|
181
|
+
get: () => get<PanelBackupStatus>('/v1/system/panel-backup'),
|
|
182
|
+
update: (input) => send<PanelBackupStatus>('PUT', '/v1/system/panel-backup', input),
|
|
183
|
+
run: () => send<{ ok: boolean; started: boolean }>('POST', '/v1/system/panel-backup/run'),
|
|
184
|
+
list: (destinationId) =>
|
|
185
|
+
get<{ destinationId: number; items: PanelBackupObject[] }>(
|
|
186
|
+
`/v1/system/panel-backup/remote${destinationId != null ? `?destinationId=${destinationId}` : ''}`,
|
|
187
|
+
),
|
|
188
|
+
restore: (input) =>
|
|
189
|
+
send<{ ok: boolean; message: string; meta: unknown; backupPath: string }>('POST', '/v1/system/panel-backup/restore', input),
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
health: () => get<HealthStatus>('/health'),
|
|
193
|
+
about: {
|
|
194
|
+
get: () => get('/v1/about'),
|
|
195
|
+
},
|
|
196
|
+
dashboard: {
|
|
197
|
+
get: () => get('/v1/dashboard'),
|
|
198
|
+
},
|
|
199
|
+
stats: {
|
|
200
|
+
snapshot: () => get<StatsSnapshot>('/v1/stats'),
|
|
201
|
+
metrics: (serviceId, opts) =>
|
|
202
|
+
get<MetricSeries>(
|
|
203
|
+
`/v1/services/${serviceId}/metrics?kind=${opts?.kind ?? 'cpu'}&minutes=${opts?.minutes ?? 60}`,
|
|
204
|
+
),
|
|
205
|
+
},
|
|
206
|
+
topology: {
|
|
207
|
+
get: () => get<TopologyGraph>('/v1/topology'),
|
|
208
|
+
},
|
|
209
|
+
activity: {
|
|
210
|
+
list: (query) => {
|
|
211
|
+
const parts: string[] = [];
|
|
212
|
+
if (query?.entity) parts.push(`entity=${encodeURIComponent(query.entity)}`);
|
|
213
|
+
if (query?.serviceId) parts.push(`serviceId=${query.serviceId}`);
|
|
214
|
+
if (query?.action) parts.push(`action=${encodeURIComponent(query.action)}`);
|
|
215
|
+
if (query?.userId) parts.push(`userId=${query.userId}`);
|
|
216
|
+
if (query?.before) parts.push(`before=${query.before}`);
|
|
217
|
+
const qs = parts.join('&');
|
|
218
|
+
return get<{ entries: ActivityEntry[]; nextCursor: number | null }>(`/v1/activity${qs ? `?${qs}` : ''}`);
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
alerts: {
|
|
222
|
+
list: () => get('/v1/alerts'),
|
|
223
|
+
create: (input) => send('POST', '/v1/alerts', input),
|
|
224
|
+
update: (id, input) => send('PATCH', `/v1/alerts/${id}`, input),
|
|
225
|
+
remove: async (id) => {
|
|
226
|
+
await request(`/v1/alerts/${id}`, { method: 'DELETE' });
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
metricHistory: {
|
|
230
|
+
get: () => get<{
|
|
231
|
+
enabled: boolean;
|
|
232
|
+
backend: 'builtin' | 'prometheus' | 'influxdb';
|
|
233
|
+
events: string[];
|
|
234
|
+
retentionDays: number;
|
|
235
|
+
lastFlush: { ts: number; backend: string; count: number };
|
|
236
|
+
}>('/v1/metric-history'),
|
|
237
|
+
flush: () => send<{ ok: boolean; backend: 'builtin'; deleted: number }>('POST', '/v1/metric-history/flush'),
|
|
238
|
+
},
|
|
239
|
+
buildCache: {
|
|
240
|
+
stats: () => get<{
|
|
241
|
+
backends: Array<{
|
|
242
|
+
name: string;
|
|
243
|
+
entries: number;
|
|
244
|
+
totalBytes: number;
|
|
245
|
+
hits: number;
|
|
246
|
+
misses: number;
|
|
247
|
+
stores: number;
|
|
248
|
+
evictions: number;
|
|
249
|
+
}>;
|
|
250
|
+
totals: {
|
|
251
|
+
entries: number;
|
|
252
|
+
totalBytes: number;
|
|
253
|
+
hits: number;
|
|
254
|
+
misses: number;
|
|
255
|
+
stores: number;
|
|
256
|
+
evictions: number;
|
|
257
|
+
};
|
|
258
|
+
}>('/v1/build-cache/stats'),
|
|
259
|
+
},
|
|
260
|
+
housekeeping: {
|
|
261
|
+
getAutoPrune: () => get<AutoPruneStatus>('/v1/housekeeping/prune/config'),
|
|
262
|
+
updateAutoPrune: (input) => send<AutoPruneStatus>('PATCH', '/v1/housekeeping/prune/config', input),
|
|
263
|
+
runPrune: () => send<AutoPruneRunResult>('POST', '/v1/housekeeping/prune'),
|
|
264
|
+
listImages: () =>
|
|
265
|
+
get<{ images: ImageInfo[]; totalCount: number; totalBytes: number }>('/v1/housekeeping/images'),
|
|
266
|
+
pruneImages: (input) =>
|
|
267
|
+
send<PruneImagesResult>('POST', '/v1/housekeeping/images/prune', input),
|
|
268
|
+
},
|
|
269
|
+
doctor: {
|
|
270
|
+
/** Full host scan: dead containers, orphan volumes/networks, row-vs-runtime
|
|
271
|
+
* desyncs, dangling images, disk pressure — with guarded repair actions. */
|
|
272
|
+
scan: () => get<DoctorReport>('/v1/doctor'),
|
|
273
|
+
/** Execute one finding's repair. The server re-scans and re-locates the
|
|
274
|
+
* finding first; a stale finding answers 409 instead of acting. */
|
|
275
|
+
fix: (input: DoctorFixRequestInput) => send<DoctorFixResponse>('POST', '/v1/doctor/fix', input),
|
|
276
|
+
},
|
|
277
|
+
demo: {
|
|
278
|
+
seed: () => send<DemoSeedResult>('POST', '/v1/demo/seed'),
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Client surface: templates.
|
|
2
|
+
// Split out of the former single-file SDK entry (src/index.ts); the public
|
|
3
|
+
// surface is re-exported unchanged from there.
|
|
4
|
+
import type {
|
|
5
|
+
DeployTemplateInput,
|
|
6
|
+
Template,
|
|
7
|
+
TemplateSummary,
|
|
8
|
+
CommunityTemplateListResult,
|
|
9
|
+
} from '@ninedeploy/schemas';
|
|
10
|
+
import type { TemplateDeployResult, TemplatePrepareResult } from '../types.js';
|
|
11
|
+
import type { Transport } from '../transport.js';
|
|
12
|
+
|
|
13
|
+
export interface TemplatesApi {
|
|
14
|
+
templates: {
|
|
15
|
+
list: () => Promise<TemplateSummary[]>;
|
|
16
|
+
get: (id: string) => Promise<Template>;
|
|
17
|
+
prepare: (id: string, input?: DeployTemplateInput) => Promise<TemplatePrepareResult>;
|
|
18
|
+
deploy: (id: string, input?: DeployTemplateInput) => Promise<TemplateDeployResult>;
|
|
19
|
+
/**
|
|
20
|
+
* Community contributions (G-13). The `list` call
|
|
21
|
+
* already merges community entries with the curated
|
|
22
|
+
* catalog; the dedicated `community` namespace lets
|
|
23
|
+
* the panel surface errors and the operator import
|
|
24
|
+
* a new template from a PR comment or a file.
|
|
25
|
+
*/
|
|
26
|
+
community: {
|
|
27
|
+
list: () => Promise<CommunityTemplateListResult>;
|
|
28
|
+
import: (content: string, opts?: { replace?: boolean }) => Promise<{ ok: boolean; id: string; file: string; bytes: number }>;
|
|
29
|
+
remove: (id: string) => Promise<{ ok: boolean; id: string; removed: boolean }>;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function templatesApi(t: Transport): TemplatesApi {
|
|
35
|
+
const { get, send } = t;
|
|
36
|
+
return {
|
|
37
|
+
templates: {
|
|
38
|
+
list: () => get<TemplateSummary[]>('/v1/templates'),
|
|
39
|
+
get: (id) => get<Template>(`/v1/templates/${encodeURIComponent(id)}`),
|
|
40
|
+
prepare: (id, input) => send<TemplatePrepareResult>('POST', `/v1/templates/${encodeURIComponent(id)}/prepare`, input ?? {}),
|
|
41
|
+
deploy: (id, input) => send<TemplateDeployResult>('POST', `/v1/templates/${encodeURIComponent(id)}/deploy`, input ?? {}),
|
|
42
|
+
community: {
|
|
43
|
+
list: () => get<CommunityTemplateListResult>('/v1/templates/community'),
|
|
44
|
+
import: (content, opts) =>
|
|
45
|
+
send<{ ok: boolean; id: string; file: string; bytes: number }>(
|
|
46
|
+
'POST',
|
|
47
|
+
'/v1/templates/community/import',
|
|
48
|
+
{ content, ...(opts ?? {}) },
|
|
49
|
+
),
|
|
50
|
+
remove: (id) =>
|
|
51
|
+
send<{ ok: boolean; id: string; removed: boolean }>('DELETE', `/v1/templates/community/${encodeURIComponent(id)}`),
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Client surface: terminals, traffic, api.
|
|
2
|
+
// Split out of the former single-file SDK entry (src/index.ts); the public
|
|
3
|
+
// surface is re-exported unchanged from there.
|
|
4
|
+
import type {
|
|
5
|
+
CreateTerminalSessionInput,
|
|
6
|
+
ServiceTrafficSummary,
|
|
7
|
+
TerminalSession,
|
|
8
|
+
TerminalSessionCreated,
|
|
9
|
+
TerminalSessionList,
|
|
10
|
+
TerminalSettingsInput,
|
|
11
|
+
TerminalSettingsView,
|
|
12
|
+
TerminalTerminateResult,
|
|
13
|
+
TrafficSettingsUpdate,
|
|
14
|
+
TrafficSettingsView,
|
|
15
|
+
TrafficSummary,
|
|
16
|
+
} from '@ninedeploy/schemas';
|
|
17
|
+
import { apiGetUrl, type ApiQuery } from '../apiPath.js';
|
|
18
|
+
import { terminalAttachInfo, connectTerminal, type TerminalAttachSource, type WebSocketLocation, type TerminalAttachInfo, type TerminalHandlers, type TerminalConnectOptions, type TerminalConnection } from '../terminal.js';
|
|
19
|
+
import type { TerminalListQuery, TrafficQuery } from '../types.js';
|
|
20
|
+
import type { Transport } from '../transport.js';
|
|
21
|
+
|
|
22
|
+
export interface TerminalsApi {
|
|
23
|
+
// ── end 0.15 T4 ──
|
|
24
|
+
// ── 0.15 T6 surfaces ──
|
|
25
|
+
/**
|
|
26
|
+
* Interactive terminals (0.15, operator only). A session is created over
|
|
27
|
+
* HTTP and attached over a WebSocket with its single-use ticket (valid 30s).
|
|
28
|
+
* Host shells (`target.kind: 'host'`) are off by default and need an
|
|
29
|
+
* interactive session plus the account password in `password`.
|
|
30
|
+
*/
|
|
31
|
+
terminals: {
|
|
32
|
+
create: (input: CreateTerminalSessionInput) => Promise<TerminalSessionCreated>;
|
|
33
|
+
/** History, newest first; page back with `before: list.nextBefore`. */
|
|
34
|
+
list: (query?: TerminalListQuery) => Promise<TerminalSessionList>;
|
|
35
|
+
get: (id: number) => Promise<TerminalSession>;
|
|
36
|
+
/** Close a live session (close 4410) or revoke a pending ticket. */
|
|
37
|
+
terminate: (id: number) => Promise<TerminalTerminateResult>;
|
|
38
|
+
settings: {
|
|
39
|
+
get: () => Promise<TerminalSettingsView>;
|
|
40
|
+
/** Partial. Turning host shells on needs `password` (step-up). */
|
|
41
|
+
set: (input: TerminalSettingsInput) => Promise<TerminalSettingsView>;
|
|
42
|
+
};
|
|
43
|
+
/** The WebSocket URL and subprotocols that attach a created session. */
|
|
44
|
+
attachInfo: (created: TerminalAttachSource, location?: WebSocketLocation) => TerminalAttachInfo;
|
|
45
|
+
/** Attach a created session over protocol v1 (see `connectTerminal`). */
|
|
46
|
+
connect: (created: TerminalAttachSource, handlers?: TerminalHandlers, options?: TerminalConnectOptions) => TerminalConnection;
|
|
47
|
+
};
|
|
48
|
+
/** Traffic analytics (0.15, opt-in). Settings and the summary are operator only. */
|
|
49
|
+
traffic: {
|
|
50
|
+
settings: {
|
|
51
|
+
get: () => Promise<TrafficSettingsView>;
|
|
52
|
+
/**
|
|
53
|
+
* Enabling or disabling recreates Traefik once (about 1–2s of refused
|
|
54
|
+
* connections). A browser behind Traefik may lose this response; read
|
|
55
|
+
* `settings.get()` again on a network error.
|
|
56
|
+
*/
|
|
57
|
+
set: (input: TrafficSettingsUpdate) => Promise<TrafficSettingsView>;
|
|
58
|
+
};
|
|
59
|
+
summary: (query?: TrafficQuery) => Promise<TrafficSummary>;
|
|
60
|
+
/** One service's series (any seat on the service). Empty series, never 404, without data. */
|
|
61
|
+
service: (serviceId: number, query?: TrafficQuery) => Promise<ServiceTrafficSummary>;
|
|
62
|
+
};
|
|
63
|
+
// ── 0.15 T4 api ──
|
|
64
|
+
/**
|
|
65
|
+
* Raw access to the documented API (0.15, see `GET /v1/openapi.json`).
|
|
66
|
+
* Read-only on purpose: there is no generic write method. The generated MCP
|
|
67
|
+
* read tools call through here.
|
|
68
|
+
*/
|
|
69
|
+
api: {
|
|
70
|
+
/**
|
|
71
|
+
* GET any `/v1/…` route. The path must match `^/v1/[A-Za-z0-9/_.-]+$` and
|
|
72
|
+
* may not contain a `..` segment; query values are URL-encoded and
|
|
73
|
+
* `undefined` values are dropped.
|
|
74
|
+
*/
|
|
75
|
+
get: <T = unknown>(path: `/v1/${string}`, query?: ApiQuery) => Promise<T>;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function terminalsApi(t: Transport): TerminalsApi {
|
|
80
|
+
const { get, send, baseUrl } = t;
|
|
81
|
+
return {
|
|
82
|
+
// ── end 0.15 T4 ──
|
|
83
|
+
// ── 0.15 T6 surfaces ──
|
|
84
|
+
terminals: {
|
|
85
|
+
create: (input) => send<TerminalSessionCreated>('POST', '/v1/terminals', input),
|
|
86
|
+
list: (query) => get<TerminalSessionList>(apiGetUrl('/v1/terminals', { ...query })),
|
|
87
|
+
get: (id) => get<TerminalSession>(`/v1/terminals/${id}`),
|
|
88
|
+
terminate: (id) => send<TerminalTerminateResult>('DELETE', `/v1/terminals/${id}`),
|
|
89
|
+
settings: {
|
|
90
|
+
get: () => get<TerminalSettingsView>('/v1/terminals/settings'),
|
|
91
|
+
set: (input) => send<TerminalSettingsView>('PUT', '/v1/terminals/settings', input),
|
|
92
|
+
},
|
|
93
|
+
attachInfo: (created, location) => terminalAttachInfo(baseUrl, created, location),
|
|
94
|
+
connect: (created, handlers, options) =>
|
|
95
|
+
connectTerminal(terminalAttachInfo(baseUrl, created, options?.location), handlers, options),
|
|
96
|
+
},
|
|
97
|
+
traffic: {
|
|
98
|
+
settings: {
|
|
99
|
+
get: () => get<TrafficSettingsView>('/v1/traffic/settings'),
|
|
100
|
+
set: (input) => send<TrafficSettingsView>('PUT', '/v1/traffic/settings', input),
|
|
101
|
+
},
|
|
102
|
+
summary: (query) => get<TrafficSummary>(apiGetUrl('/v1/traffic/summary', { ...query })),
|
|
103
|
+
service: (serviceId, query) =>
|
|
104
|
+
get<ServiceTrafficSummary>(apiGetUrl(`/v1/services/${serviceId}/traffic`, { ...query })),
|
|
105
|
+
},
|
|
106
|
+
// ── 0.15 T4 api ──
|
|
107
|
+
api: {
|
|
108
|
+
// async: a refused path rejects like any other failed call, never throws synchronously.
|
|
109
|
+
get: async <T = unknown>(path: `/v1/${string}`, query?: ApiQuery) => get<T>(apiGetUrl(path, query)),
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Client surface: traefik.
|
|
2
|
+
// Split out of the former single-file SDK entry (src/index.ts); the public
|
|
3
|
+
// surface is re-exported unchanged from there.
|
|
4
|
+
import type {
|
|
5
|
+
TraefikCertificate,
|
|
6
|
+
CertificateInventoryEntry,
|
|
7
|
+
CertificateInventoryReport,
|
|
8
|
+
TraefikInfo,
|
|
9
|
+
TraefikStatus,
|
|
10
|
+
TraefikCustomConfig,
|
|
11
|
+
TraefikCustomConfigApplied,
|
|
12
|
+
TraefikCustomConfigValidation,
|
|
13
|
+
CustomCertificate,
|
|
14
|
+
CustomCertificateReplace,
|
|
15
|
+
CustomCertificateSaved,
|
|
16
|
+
CustomCertificateUpload,
|
|
17
|
+
} from '@ninedeploy/schemas';
|
|
18
|
+
import type { TraefikVersionInfo, TraefikRoutingConfig } from '../types.js';
|
|
19
|
+
import type { Transport } from '../transport.js';
|
|
20
|
+
|
|
21
|
+
export interface TraefikApi {
|
|
22
|
+
traefik: {
|
|
23
|
+
get: () => Promise<TraefikInfo>;
|
|
24
|
+
status: () => Promise<TraefikStatus>;
|
|
25
|
+
certificates: () => Promise<TraefikCertificate[]>;
|
|
26
|
+
/**
|
|
27
|
+
* Richer certificate inventory (G-15). Same
|
|
28
|
+
* underlying data as `certificates()` but adds a
|
|
29
|
+
* `status` classification (valid / expiring-soon /
|
|
30
|
+
* expired), a `summary` block, and the full set of
|
|
31
|
+
* fields the Certificates page renders.
|
|
32
|
+
* `threshold` is the days-out cutoff for the
|
|
33
|
+
* `expiring-soon` bucket; default 30.
|
|
34
|
+
*/
|
|
35
|
+
certificateInventory: (opts?: { threshold?: number }) => Promise<CertificateInventoryReport>;
|
|
36
|
+
/**
|
|
37
|
+
* Focused "expiring within N days" filter. Default
|
|
38
|
+
* 30. Used by the alert engine and by the panel's
|
|
39
|
+
* "About to expire" widget.
|
|
40
|
+
*/
|
|
41
|
+
expiringCertificates: (opts?: { days?: number }) => Promise<{ threshold: number; count: number; certificates: CertificateInventoryEntry[] }>;
|
|
42
|
+
logs: (lines?: number) => Promise<{ logs: string[] }>;
|
|
43
|
+
restart: () => Promise<{ ok: boolean; message?: string }>;
|
|
44
|
+
/** r334: the server answers the host path of the copied acme.json. */
|
|
45
|
+
backupCerts: () => Promise<{ ok: boolean; backupPath: string }>;
|
|
46
|
+
/** r557: routers / services / middlewares from the dynamic config (operator-only). */
|
|
47
|
+
config: () => Promise<TraefikRoutingConfig>;
|
|
48
|
+
/** r557: running vs latest Traefik version (operator-only). */
|
|
49
|
+
version: () => Promise<TraefikVersionInfo>;
|
|
50
|
+
/**
|
|
51
|
+
* r557: pull the pinned Traefik image and recreate the proxy container
|
|
52
|
+
* (operator-only). An image pull outlasts the default request budget, so
|
|
53
|
+
* this call allows up to 10 minutes unless the client disabled timeouts.
|
|
54
|
+
*/
|
|
55
|
+
update: () => Promise<{ ok: boolean; newVersion: string | null }>;
|
|
56
|
+
/**
|
|
57
|
+
* 0.14: the operator's custom dynamic config (`custom.yml`). `set` throws
|
|
58
|
+
* a NineDeployError whose `details` is `{ errors, warnings }` on a refusal.
|
|
59
|
+
*/
|
|
60
|
+
customConfig: {
|
|
61
|
+
get: () => Promise<TraefikCustomConfig>;
|
|
62
|
+
/** No state change. */
|
|
63
|
+
validate: (content: string) => Promise<TraefikCustomConfigValidation>;
|
|
64
|
+
set: (content: string) => Promise<TraefikCustomConfigApplied>;
|
|
65
|
+
clear: () => Promise<{ ok: boolean; cleared: boolean }>;
|
|
66
|
+
};
|
|
67
|
+
/** 0.14: uploaded TLS certificates (operator-only). No response carries a private key. */
|
|
68
|
+
customCertificates: {
|
|
69
|
+
list: () => Promise<CustomCertificate[]>;
|
|
70
|
+
upload: (input: CustomCertificateUpload) => Promise<CustomCertificateSaved>;
|
|
71
|
+
replace: (id: number, input: CustomCertificateReplace) => Promise<CustomCertificateSaved>;
|
|
72
|
+
delete: (id: number) => Promise<{ ok: boolean }>;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function traefikApi(t: Transport): TraefikApi {
|
|
78
|
+
const { get, send, request } = t;
|
|
79
|
+
return {
|
|
80
|
+
traefik: {
|
|
81
|
+
get: () => get<TraefikInfo>('/v1/traefik'),
|
|
82
|
+
status: () => get<TraefikStatus>('/v1/traefik/status'),
|
|
83
|
+
certificates: () => get<TraefikCertificate[]>('/v1/traefik/certificates'),
|
|
84
|
+
certificateInventory: (opts) =>
|
|
85
|
+
get<CertificateInventoryReport>(
|
|
86
|
+
// `!= null` (not truthiness): 0 ("only already-expired") is a real
|
|
87
|
+
// threshold and must reach the server, not silently become the
|
|
88
|
+
// server-side default of 30.
|
|
89
|
+
`/v1/traefik/certificates/inventory${opts?.threshold != null ? `?threshold=${opts.threshold}` : ''}`,
|
|
90
|
+
),
|
|
91
|
+
expiringCertificates: (opts) =>
|
|
92
|
+
get<{ threshold: number; count: number; certificates: CertificateInventoryEntry[] }>(
|
|
93
|
+
`/v1/traefik/certificates/expiring${opts?.days != null ? `?days=${opts.days}` : ''}`,
|
|
94
|
+
),
|
|
95
|
+
logs: (lines = 50) => get<{ logs: string[] }>(`/v1/traefik/logs?lines=${lines}`),
|
|
96
|
+
restart: () => send<{ ok: boolean; message: string }>('POST', '/v1/traefik/restart'),
|
|
97
|
+
backupCerts: () => send<{ ok: boolean; backupPath: string }>('POST', '/v1/traefik/backup-certs'),
|
|
98
|
+
config: () => get<TraefikRoutingConfig>('/v1/traefik/config'),
|
|
99
|
+
version: () => get<TraefikVersionInfo>('/v1/traefik/version'),
|
|
100
|
+
update: () => request<{ ok: boolean; newVersion: string | null }>('/v1/traefik/update', { method: 'POST' }, 10 * 60_000),
|
|
101
|
+
customConfig: {
|
|
102
|
+
get: () => get<TraefikCustomConfig>('/v1/traefik/custom-config'),
|
|
103
|
+
validate: (content) => send<TraefikCustomConfigValidation>('POST', '/v1/traefik/custom-config/validate', { content }),
|
|
104
|
+
set: (content) =>
|
|
105
|
+
request<TraefikCustomConfigApplied>('/v1/traefik/custom-config', { method: 'PUT', body: { content }, findings: true }),
|
|
106
|
+
clear: () => send<{ ok: boolean; cleared: boolean }>('DELETE', '/v1/traefik/custom-config'),
|
|
107
|
+
},
|
|
108
|
+
customCertificates: {
|
|
109
|
+
list: () => get<CustomCertificate[]>('/v1/traefik/certificates/custom'),
|
|
110
|
+
upload: (input) => send<CustomCertificateSaved>('POST', '/v1/traefik/certificates/custom', input),
|
|
111
|
+
replace: (id, input) => send<CustomCertificateSaved>('PUT', `/v1/traefik/certificates/custom/${id}`, input),
|
|
112
|
+
delete: (id) => send<{ ok: boolean }>('DELETE', `/v1/traefik/certificates/custom/${id}`),
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|