mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
update binding for API types, add ARCHITECTURE
This commit is contained in:
89
web/ARCHITECTURE.md
Normal file
89
web/ARCHITECTURE.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Web Architecture
|
||||
|
||||
Angular 20 + TypeScript workspace using [Taiga UI](https://taiga-ui.dev/) component library.
|
||||
|
||||
## API Layer (JSON-RPC)
|
||||
|
||||
All backend communication uses JSON-RPC, not REST.
|
||||
|
||||
- **`HttpService`** (`shared/src/services/http.service.ts`) — Low-level HTTP wrapper. Sends JSON-RPC POST requests via `rpcRequest()`.
|
||||
- **`ApiService`** (`ui/src/app/services/api/embassy-api.service.ts`) — Abstract class defining 100+ RPC methods. Two implementations:
|
||||
- `LiveApiService` — Production, calls the real backend
|
||||
- `MockApiService` — Development with mocks
|
||||
- **`api.types.ts`** (`ui/src/app/services/api/api.types.ts`) — Namespace `RR` with all request/response type pairs.
|
||||
|
||||
**Calling an RPC endpoint from a component:**
|
||||
|
||||
```typescript
|
||||
private readonly api = inject(ApiService)
|
||||
|
||||
async doSomething() {
|
||||
await this.api.someMethod({ param: value })
|
||||
}
|
||||
```
|
||||
|
||||
The live API handles `x-patch-sequence` headers — after a mutating call, it waits for the PatchDB WebSocket to catch up before resolving. This ensures the UI always reflects the result of the call.
|
||||
|
||||
## PatchDB (Reactive State)
|
||||
|
||||
The backend pushes state diffs to the frontend via WebSocket. This is the primary way components get data.
|
||||
|
||||
- **`PatchDbSource`** (`ui/src/app/services/patch-db/patch-db-source.ts`) — Establishes a WebSocket subscription when authenticated. Buffers updates every 250ms.
|
||||
- **`DataModel`** (`ui/src/app/services/patch-db/data-model.ts`) — TypeScript type for the full database shape (`ui`, `serverInfo`, `packageData`).
|
||||
- **`PatchDB<DataModel>`** — Injected service. Use `watch$()` to observe specific paths.
|
||||
|
||||
**Watching data in a component:**
|
||||
|
||||
```typescript
|
||||
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
|
||||
|
||||
// Watch a specific path — returns Observable, convert to Signal with toSignal()
|
||||
readonly name = toSignal(this.patch.watch$('ui', 'name'))
|
||||
readonly status = toSignal(this.patch.watch$('serverInfo', 'statusInfo'))
|
||||
readonly packages = toSignal(this.patch.watch$('packageData'))
|
||||
```
|
||||
|
||||
**In templates:** `{{ name() }}` — signals are called as functions.
|
||||
|
||||
## WebSockets
|
||||
|
||||
Three WebSocket use cases, all opened via `api.openWebsocket$<T>(guid)`:
|
||||
|
||||
1. **PatchDB** — Continuous state patches (managed by `PatchDbSource`)
|
||||
2. **Logs** — Streamed via `followServerLogs` / `followPackageLogs`, buffered every 1s
|
||||
3. **Metrics** — Real-time server metrics via `followServerMetrics`
|
||||
|
||||
## Navigation & Routing
|
||||
|
||||
- **Main app** (`ui/src/app/routing.module.ts`) — NgModule-based with guards (`AuthGuard`, `UnauthGuard`, `stateNot()`), lazy loading via `loadChildren`, `PreloadAllModules`.
|
||||
- **Portal routes** (`ui/src/app/routes/portal/portal.routes.ts`) — Modern array-based routes with `loadChildren` and `loadComponent`.
|
||||
- **Setup wizard** (`setup-wizard/src/app/app.routes.ts`) — Standalone `loadComponent()` per step.
|
||||
- Route config uses `bindToComponentInputs: true` — route params bind directly to component `@Input()`.
|
||||
|
||||
## Forms
|
||||
|
||||
Two patterns:
|
||||
|
||||
1. **Dynamic (spec-driven)** — `FormService` (`ui/src/app/services/form.service.ts`) generates `FormGroup` from IST (Input Specification Type) schemas. Supports text, textarea, number, color, datetime, object, list, union, toggle, select, multiselect, file. Used for service configuration forms.
|
||||
|
||||
2. **Manual** — Standard Angular `FormGroup`/`FormControl` with validators. Used for login, setup wizard, system settings.
|
||||
|
||||
Form controls live in `ui/src/app/routes/portal/components/form/controls/` — each extends a base `Control<Spec, Value>` class and uses Taiga input components.
|
||||
|
||||
**Dialog-based forms** use `PolymorpheusComponent` + `TuiDialogContext` for modal rendering.
|
||||
|
||||
## i18n
|
||||
|
||||
- **`i18nPipe`** (`shared/src/i18n/i18n.pipe.ts`) — Translates English keys to the active language.
|
||||
- **Dictionaries** live in `shared/src/i18n/dictionaries/` (en, es, de, fr, pl).
|
||||
- Usage in templates: `{{ 'Some English Text' | i18n }}`
|
||||
|
||||
## Services & State
|
||||
|
||||
Services often extend `Observable` and expose reactive streams via DI:
|
||||
|
||||
- **`ConnectionService`** — Combines network status + WebSocket readiness
|
||||
- **`StateService`** — Polls server availability, manages app state (`running`, `initializing`, etc.)
|
||||
- **`AuthService`** — Tracks `isVerified$`, triggers PatchDB start/stop
|
||||
- **`PatchMonitorService`** — Starts/stops PatchDB based on auth state
|
||||
- **`PatchDataService`** — Watches entire DB, updates localStorage bootstrap
|
||||
@@ -37,98 +37,16 @@ WebFetch url=https://taiga-ui.dev/llms-full.txt prompt="How to use TuiTextfield
|
||||
|
||||
When implementing something with Taiga, **also check existing code in this project** for local patterns and conventions — Taiga usage here may have project-specific wrappers or style choices.
|
||||
|
||||
## Architecture Overview
|
||||
## Architecture
|
||||
|
||||
### API Layer (JSON-RPC)
|
||||
|
||||
All backend communication uses JSON-RPC, not REST.
|
||||
|
||||
- **`HttpService`** (`shared/src/services/http.service.ts`) — Low-level HTTP wrapper. Sends JSON-RPC POST requests via `rpcRequest()`.
|
||||
- **`ApiService`** (`ui/src/app/services/api/embassy-api.service.ts`) — Abstract class defining 100+ RPC methods. Two implementations:
|
||||
- `LiveApiService` — Production, calls the real backend
|
||||
- `MockApiService` — Development with mocks
|
||||
- **`api.types.ts`** (`ui/src/app/services/api/api.types.ts`) — Namespace `RR` with all request/response type pairs.
|
||||
|
||||
**Calling an RPC endpoint from a component:**
|
||||
```typescript
|
||||
private readonly api = inject(ApiService)
|
||||
|
||||
async doSomething() {
|
||||
await this.api.someMethod({ param: value })
|
||||
}
|
||||
```
|
||||
|
||||
The live API handles `x-patch-sequence` headers — after a mutating call, it waits for the PatchDB WebSocket to catch up before resolving. This ensures the UI always reflects the result of the call.
|
||||
|
||||
### PatchDB (Reactive State)
|
||||
|
||||
The backend pushes state diffs to the frontend via WebSocket. This is the primary way components get data.
|
||||
|
||||
- **`PatchDbSource`** (`ui/src/app/services/patch-db/patch-db-source.ts`) — Establishes a WebSocket subscription when authenticated. Buffers updates every 250ms.
|
||||
- **`DataModel`** (`ui/src/app/services/patch-db/data-model.ts`) — TypeScript type for the full database shape (`ui`, `serverInfo`, `packageData`).
|
||||
- **`PatchDB<DataModel>`** — Injected service. Use `watch$()` to observe specific paths.
|
||||
|
||||
**Watching data in a component:**
|
||||
```typescript
|
||||
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
|
||||
|
||||
// Watch a specific path — returns Observable, convert to Signal with toSignal()
|
||||
readonly name = toSignal(this.patch.watch$('ui', 'name'))
|
||||
readonly status = toSignal(this.patch.watch$('serverInfo', 'statusInfo'))
|
||||
readonly packages = toSignal(this.patch.watch$('packageData'))
|
||||
```
|
||||
|
||||
**In templates:** `{{ name() }}` — signals are called as functions.
|
||||
|
||||
### WebSockets
|
||||
|
||||
Three WebSocket use cases, all opened via `api.openWebsocket$<T>(guid)`:
|
||||
|
||||
1. **PatchDB** — Continuous state patches (managed by `PatchDbSource`)
|
||||
2. **Logs** — Streamed via `followServerLogs` / `followPackageLogs`, buffered every 1s
|
||||
3. **Metrics** — Real-time server metrics via `followServerMetrics`
|
||||
|
||||
### Navigation & Routing
|
||||
|
||||
- **Main app** (`ui/src/app/routing.module.ts`) — NgModule-based with guards (`AuthGuard`, `UnauthGuard`, `stateNot()`), lazy loading via `loadChildren`, `PreloadAllModules`.
|
||||
- **Portal routes** (`ui/src/app/routes/portal/portal.routes.ts`) — Modern array-based routes with `loadChildren` and `loadComponent`.
|
||||
- **Setup wizard** (`setup-wizard/src/app/app.routes.ts`) — Standalone `loadComponent()` per step.
|
||||
- Route config uses `bindToComponentInputs: true` — route params bind directly to component `@Input()`.
|
||||
|
||||
### Forms
|
||||
|
||||
Two patterns:
|
||||
|
||||
1. **Dynamic (spec-driven)** — `FormService` (`ui/src/app/services/form.service.ts`) generates `FormGroup` from IST (Input Specification Type) schemas. Supports text, textarea, number, color, datetime, object, list, union, toggle, select, multiselect, file. Used for service configuration forms.
|
||||
|
||||
2. **Manual** — Standard Angular `FormGroup`/`FormControl` with validators. Used for login, setup wizard, system settings.
|
||||
|
||||
Form controls live in `ui/src/app/routes/portal/components/form/controls/` — each extends a base `Control<Spec, Value>` class and uses Taiga input components.
|
||||
|
||||
**Dialog-based forms** use `PolymorpheusComponent` + `TuiDialogContext` for modal rendering.
|
||||
|
||||
### i18n
|
||||
|
||||
- **`i18nPipe`** (`shared/src/i18n/i18n.pipe.ts`) — Translates English keys to the active language.
|
||||
- **Dictionaries** live in `shared/src/i18n/dictionaries/` (en, es, de, fr, pl).
|
||||
- Usage in templates: `{{ 'Some English Text' | i18n }}`
|
||||
|
||||
### Services & State
|
||||
|
||||
Services often extend `Observable` and expose reactive streams via DI:
|
||||
|
||||
- **`ConnectionService`** — Combines network status + WebSocket readiness
|
||||
- **`StateService`** — Polls server availability, manages app state (`running`, `initializing`, etc.)
|
||||
- **`AuthService`** — Tracks `isVerified$`, triggers PatchDB start/stop
|
||||
- **`PatchMonitorService`** — Starts/stops PatchDB based on auth state
|
||||
- **`PatchDataService`** — Watches entire DB, updates localStorage bootstrap
|
||||
See [ARCHITECTURE.md](ARCHITECTURE.md) for the web architecture: API layer, PatchDB state, WebSockets, routing, forms, i18n, and services.
|
||||
|
||||
## Component Conventions
|
||||
|
||||
- **Standalone components** preferred (no NgModule). Use `imports` array in `@Component`.
|
||||
- **`export default class`** for route components (enables direct `loadComponent` import).
|
||||
- **`inject()`** function for DI (not constructor injection).
|
||||
- **`signal()`** and `computed()`** for local reactive state.
|
||||
- **`signal()`** and `computed()`\*\* for local reactive state.
|
||||
- **`toSignal()`** to convert Observables (e.g., PatchDB watches) to signals.
|
||||
- **`ChangeDetectionStrategy.OnPush`** on almost all components.
|
||||
- **`takeUntilDestroyed(inject(DestroyRef))`** for subscription cleanup.
|
||||
@@ -136,6 +54,7 @@ Services often extend `Observable` and expose reactive streams via DI:
|
||||
## Common Taiga Patterns
|
||||
|
||||
### Textfield + Select (dropdown)
|
||||
|
||||
```html
|
||||
<tui-textfield tuiChevron>
|
||||
<label tuiLabel>Label</label>
|
||||
@@ -145,12 +64,15 @@ Services often extend `Observable` and expose reactive streams via DI:
|
||||
</tui-data-list>
|
||||
</tui-textfield>
|
||||
```
|
||||
|
||||
Provider to remove the X clear button:
|
||||
|
||||
```typescript
|
||||
providers: [tuiTextfieldOptionsProvider({ cleaner: signal(false) })]
|
||||
```
|
||||
|
||||
### Buttons
|
||||
|
||||
```html
|
||||
<button tuiButton appearance="primary">Submit</button>
|
||||
<button tuiButton appearance="secondary">Cancel</button>
|
||||
@@ -158,6 +80,7 @@ providers: [tuiTextfieldOptionsProvider({ cleaner: signal(false) })]
|
||||
```
|
||||
|
||||
### Dialogs
|
||||
|
||||
```typescript
|
||||
// Confirmation
|
||||
this.dialog.openConfirm({ label: 'Warning', data: { content: '...', yes: 'Confirm', no: 'Cancel' } })
|
||||
@@ -167,17 +90,20 @@ this.dialog.openComponent(new PolymorpheusComponent(MyComponent, injector), { la
|
||||
```
|
||||
|
||||
### Toggle
|
||||
|
||||
```html
|
||||
<input tuiSwitch type="checkbox" size="m" [showIcons]="false" [(ngModel)]="value" />
|
||||
```
|
||||
|
||||
### Errors & Tooltips
|
||||
|
||||
```html
|
||||
<tui-error [error]="[] | tuiFieldError | async" />
|
||||
<tui-icon [tuiTooltip]="'Hint text'" />
|
||||
```
|
||||
|
||||
### Layout
|
||||
|
||||
```html
|
||||
<tui-elastic-container><!-- dynamic height --></tui-elastic-container>
|
||||
<tui-scrollbar><!-- scrollable content --></tui-scrollbar>
|
||||
|
||||
21
web/package-lock.json
generated
21
web/package-lock.json
generated
@@ -867,6 +867,7 @@
|
||||
"integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
@@ -8041,6 +8042,7 @@
|
||||
"integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cli-truncate": "^4.0.0",
|
||||
"colorette": "^2.0.20",
|
||||
@@ -11910,6 +11912,7 @@
|
||||
"integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -12217,24 +12220,6 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
|
||||
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/eemeli"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as jose from 'node-jose'
|
||||
import {
|
||||
DiskInfo,
|
||||
FollowLogsRes,
|
||||
FullKeyboard,
|
||||
SetLanguageParams,
|
||||
StartOSDiskInfo,
|
||||
@@ -49,7 +48,7 @@ export abstract class ApiService {
|
||||
abstract shutdown(): Promise<void> // setup.shutdown
|
||||
|
||||
// Logs & Progress
|
||||
abstract initFollowLogs(): Promise<FollowLogsRes> // setup.logs.follow
|
||||
abstract initFollowLogs(): Promise<T.LogFollowResponse> // setup.logs.follow
|
||||
abstract openWebsocket$<T>(guid: string): Observable<T>
|
||||
|
||||
// Restart (for error recovery)
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Inject, Injectable, DOCUMENT } from '@angular/core'
|
||||
import {
|
||||
DiskInfo,
|
||||
encodeBase64,
|
||||
FollowLogsRes,
|
||||
FullKeyboard,
|
||||
HttpService,
|
||||
isRpcError,
|
||||
@@ -124,7 +123,7 @@ export class LiveApiService extends ApiService {
|
||||
}
|
||||
|
||||
async initFollowLogs() {
|
||||
return this.rpcRequest<FollowLogsRes>({
|
||||
return this.rpcRequest<T.LogFollowResponse>({
|
||||
method: 'setup.logs.follow',
|
||||
params: {},
|
||||
})
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Injectable } from '@angular/core'
|
||||
import {
|
||||
DiskInfo,
|
||||
encodeBase64,
|
||||
FollowLogsRes,
|
||||
FullKeyboard,
|
||||
pauseFor,
|
||||
SetLanguageParams,
|
||||
@@ -166,7 +165,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async initFollowLogs(): Promise<FollowLogsRes> {
|
||||
async initFollowLogs(): Promise<T.LogFollowResponse> {
|
||||
await pauseFor(500)
|
||||
return {
|
||||
startCursor: 'fakestartcursor',
|
||||
|
||||
@@ -12,13 +12,13 @@ import {
|
||||
switchMap,
|
||||
timer,
|
||||
} from 'rxjs'
|
||||
import { FollowLogsReq, FollowLogsRes, Log } from '../types/api'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { Constructor } from '../types/constructor'
|
||||
import { convertAnsi } from '../util/convert-ansi'
|
||||
|
||||
interface Api {
|
||||
initFollowLogs: (params: FollowLogsReq) => Promise<FollowLogsRes>
|
||||
openWebsocket$: (guid: string) => Observable<Log>
|
||||
initFollowLogs: (params: {}) => Promise<T.LogFollowResponse>
|
||||
openWebsocket$: (guid: string) => Observable<T.LogEntry>
|
||||
}
|
||||
|
||||
export function provideSetupLogsService(
|
||||
|
||||
@@ -1,27 +1,3 @@
|
||||
export type FollowLogsReq = {}
|
||||
export type FollowLogsRes = {
|
||||
startCursor: string
|
||||
guid: string
|
||||
}
|
||||
|
||||
export type FetchLogsReq = {
|
||||
before: boolean
|
||||
cursor?: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export type FetchLogsRes = {
|
||||
entries: Log[]
|
||||
startCursor?: string
|
||||
endCursor?: string
|
||||
}
|
||||
|
||||
export interface Log {
|
||||
timestamp: string
|
||||
message: string
|
||||
bootId: string
|
||||
}
|
||||
|
||||
export type DiskListResponse = DiskInfo[]
|
||||
|
||||
export interface DiskInfo {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Log } from '../types/api'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { toLocalIsoString } from './to-local-iso-string'
|
||||
import Convert from 'ansi-to-html'
|
||||
|
||||
@@ -8,7 +8,7 @@ const CONVERT = new Convert({
|
||||
escapeXML: true,
|
||||
})
|
||||
|
||||
export function convertAnsi(entries: readonly Log[]): string {
|
||||
export function convertAnsi(entries: readonly T.LogEntry[]): string {
|
||||
return entries
|
||||
.map(
|
||||
({ timestamp, message }) =>
|
||||
|
||||
@@ -12,7 +12,7 @@ import { TuiCell } from '@taiga-ui/layout'
|
||||
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { map } from 'rxjs'
|
||||
import { BackupReport } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { getManifest } from '../utils/get-package-data'
|
||||
import { DataModel } from '../services/patch-db/data-model'
|
||||
|
||||
@@ -60,7 +60,7 @@ export class BackupsReportModal {
|
||||
|
||||
readonly data =
|
||||
injectContext<
|
||||
TuiDialogContext<void, { content: BackupReport; createdAt: string }>
|
||||
TuiDialogContext<void, { content: T.BackupReport; createdAt: string }>
|
||||
>().data
|
||||
|
||||
readonly pkgTitles = toSignal(
|
||||
|
||||
@@ -69,7 +69,7 @@ export default class LogsPage implements OnInit {
|
||||
private readonly api = inject(ApiService)
|
||||
private readonly errorService = inject(ErrorService)
|
||||
|
||||
startCursor?: string
|
||||
startCursor?: string | null
|
||||
loading = false
|
||||
logs: string[] = []
|
||||
scrollTop = 0
|
||||
@@ -98,7 +98,7 @@ export default class LogsPage implements OnInit {
|
||||
|
||||
try {
|
||||
const response = await this.api.diagnosticGetLogs({
|
||||
cursor: this.startCursor,
|
||||
cursor: this.startCursor ?? undefined,
|
||||
before: !!this.startCursor,
|
||||
limit: 200,
|
||||
})
|
||||
|
||||
@@ -216,17 +216,19 @@ export class InterfaceAddressesComponent {
|
||||
|
||||
private async savePrivateDomain(fqdn: string): Promise<boolean> {
|
||||
const iface = this.value()
|
||||
const gatewayId = this.gatewayGroup().gatewayId
|
||||
const loader = this.loader.open('Saving').subscribe()
|
||||
|
||||
try {
|
||||
if (this.packageId()) {
|
||||
await this.api.pkgAddPrivateDomain({
|
||||
fqdn,
|
||||
gateway: gatewayId,
|
||||
package: this.packageId(),
|
||||
host: iface?.addressInfo.hostId || '',
|
||||
})
|
||||
} else {
|
||||
await this.api.osUiAddPrivateDomain({ fqdn })
|
||||
await this.api.osUiAddPrivateDomain({ fqdn, gateway: gatewayId })
|
||||
}
|
||||
return true
|
||||
} catch (e: any) {
|
||||
|
||||
@@ -3,10 +3,9 @@ import {
|
||||
convertAnsi,
|
||||
DownloadHTMLService,
|
||||
ErrorService,
|
||||
FetchLogsReq,
|
||||
FetchLogsRes,
|
||||
LoadingService,
|
||||
} from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { LogsComponent } from './logs.component'
|
||||
|
||||
@Directive({
|
||||
@@ -19,7 +18,7 @@ export class LogsDownloadDirective {
|
||||
private readonly downloadHtml = inject(DownloadHTMLService)
|
||||
|
||||
@Input({ required: true })
|
||||
logsDownload!: (params: FetchLogsReq) => Promise<FetchLogsRes>
|
||||
logsDownload!: (params: T.LogsParams) => Promise<T.LogResponse>
|
||||
|
||||
@HostListener('click')
|
||||
async download() {
|
||||
|
||||
@@ -18,7 +18,7 @@ export class LogsFetchDirective {
|
||||
switchMap(() =>
|
||||
from(
|
||||
this.component.fetchLogs({
|
||||
cursor: this.component.startCursor,
|
||||
cursor: this.component.startCursor ?? undefined,
|
||||
before: true,
|
||||
limit: 400,
|
||||
}),
|
||||
|
||||
@@ -5,11 +5,12 @@ import {
|
||||
WaIntersectionObserver,
|
||||
} from '@ng-web-apis/intersection-observer'
|
||||
import { WaMutationObserver } from '@ng-web-apis/mutation-observer'
|
||||
import { FetchLogsReq, FetchLogsRes, i18nPipe } from '@start9labs/shared'
|
||||
import { i18nPipe } from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { TuiButton, TuiLoader, TuiScrollbar } from '@taiga-ui/core'
|
||||
import { NgDompurifyPipe } from '@taiga-ui/dompurify'
|
||||
import { BehaviorSubject } from 'rxjs'
|
||||
import { RR } from 'src/app/services/api/api.types'
|
||||
import { FollowServerLogsReq } from 'src/app/services/api/api.types'
|
||||
import { LogsDownloadDirective } from './logs-download.directive'
|
||||
import { LogsFetchDirective } from './logs-fetch.directive'
|
||||
import { LogsPipe } from './logs.pipe'
|
||||
@@ -41,17 +42,17 @@ export class LogsComponent {
|
||||
private readonly scrollbar?: ElementRef<HTMLElement>
|
||||
|
||||
@Input({ required: true }) followLogs!: (
|
||||
params: RR.FollowServerLogsReq,
|
||||
) => Promise<RR.FollowServerLogsRes>
|
||||
params: FollowServerLogsReq,
|
||||
) => Promise<T.LogFollowResponse>
|
||||
|
||||
@Input({ required: true }) fetchLogs!: (
|
||||
params: FetchLogsReq,
|
||||
) => Promise<FetchLogsRes>
|
||||
params: T.LogsParams,
|
||||
) => Promise<T.LogResponse>
|
||||
|
||||
@Input({ required: true }) context!: string
|
||||
|
||||
scrollTop = 0
|
||||
startCursor?: string
|
||||
startCursor?: string | null
|
||||
scroll = true
|
||||
loading = false
|
||||
previous: readonly string[] = []
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { inject, Pipe, PipeTransform } from '@angular/core'
|
||||
import {
|
||||
convertAnsi,
|
||||
i18nPipe,
|
||||
Log,
|
||||
toLocalIsoString,
|
||||
} from '@start9labs/shared'
|
||||
import { convertAnsi, i18nPipe, toLocalIsoString } from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import {
|
||||
bufferTime,
|
||||
catchError,
|
||||
@@ -25,7 +21,7 @@ import {
|
||||
take,
|
||||
tap,
|
||||
} from 'rxjs'
|
||||
import { RR } from 'src/app/services/api/api.types'
|
||||
import { FollowServerLogsReq } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ConnectionService } from 'src/app/services/connection.service'
|
||||
import { LogsComponent } from './logs.component'
|
||||
@@ -40,9 +36,7 @@ export class LogsPipe implements PipeTransform {
|
||||
private readonly i18n = inject(i18nPipe)
|
||||
|
||||
transform(
|
||||
followLogs: (
|
||||
params: RR.FollowServerLogsReq,
|
||||
) => Promise<RR.FollowServerLogsRes>,
|
||||
followLogs: (params: FollowServerLogsReq) => Promise<T.LogFollowResponse>,
|
||||
): Observable<readonly string[]> {
|
||||
return merge(
|
||||
this.logs.status$.pipe(
|
||||
@@ -53,7 +47,7 @@ export class LogsPipe implements PipeTransform {
|
||||
defer(() => followLogs(this.options)).pipe(
|
||||
tap(r => this.logs.setCursor(r.startCursor)),
|
||||
switchMap(r =>
|
||||
this.api.openWebsocket$<Log>(r.guid, {
|
||||
this.api.openWebsocket$<T.LogEntry>(r.guid, {
|
||||
openObserver: {
|
||||
next: () => this.logs.status$.next('connected'),
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from '@taiga-ui/core'
|
||||
import { TuiConfirmData, TUI_CONFIRM, TuiSkeleton } from '@taiga-ui/kit'
|
||||
import { filter, map, Subject, switchMap } from 'rxjs'
|
||||
import { BackupTarget } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { GetBackupIconPipe } from '../pipes/get-backup-icon.pipe'
|
||||
|
||||
@Component({
|
||||
@@ -140,7 +140,7 @@ export class BackupsTargetsComponent {
|
||||
readonly delete$ = new Subject<string>()
|
||||
|
||||
@Input()
|
||||
backupsTargets: Record<string, BackupTarget> | null = null
|
||||
backupsTargets: Record<string, T.BackupTarget> | null = null
|
||||
|
||||
@Output()
|
||||
readonly update = new EventEmitter<string>()
|
||||
|
||||
@@ -11,7 +11,8 @@ import {
|
||||
import { TuiBadge, TuiSwitch } from '@taiga-ui/kit'
|
||||
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||
import { from, map } from 'rxjs'
|
||||
import { BackupJob, BackupTarget } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { BackupJob } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ToHumanCronPipe } from '../pipes/to-human-cron.pipe'
|
||||
import { BackupJobBuilder } from '../utils/job-builder'
|
||||
@@ -149,7 +150,7 @@ export class BackupsEditModal {
|
||||
|
||||
selectTarget() {
|
||||
this.dialogs
|
||||
.open<BackupTarget & { id: string }>(TARGET, TARGET_CREATE)
|
||||
.open<T.BackupTarget & { id: string }>(TARGET, TARGET_CREATE)
|
||||
.subscribe(({ id }) => {
|
||||
this.job.targetId = id
|
||||
})
|
||||
|
||||
@@ -8,7 +8,7 @@ import { TuiBlock, TuiCheckbox } from '@taiga-ui/kit'
|
||||
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { take } from 'rxjs'
|
||||
import { PackageBackupInfo } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { ToOptionsPipe } from '../pipes/to-options.pipe'
|
||||
@@ -98,7 +98,7 @@ export class BackupsRecoverModal {
|
||||
}
|
||||
}
|
||||
|
||||
get backups(): Record<string, PackageBackupInfo> {
|
||||
get backups(): Record<string, T.PackageBackupInfo> {
|
||||
return this.context.data.backupInfo.packageBackups
|
||||
}
|
||||
|
||||
@@ -110,13 +110,12 @@ export class BackupsRecoverModal {
|
||||
const ids = options.filter(({ checked }) => !!checked).map(({ id }) => id)
|
||||
const loader = this.loader.open('Initializing').subscribe()
|
||||
|
||||
const { targetId, serverId, password } = this.context.data
|
||||
const { targetId, password } = this.context.data
|
||||
|
||||
try {
|
||||
await this.api.restorePackages({
|
||||
ids,
|
||||
targetId,
|
||||
serverId,
|
||||
password,
|
||||
})
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
signal,
|
||||
} from '@angular/core'
|
||||
import { ErrorService, Exver } from '@start9labs/shared'
|
||||
import { Version } from '@start9labs/start-sdk'
|
||||
import { T, Version } from '@start9labs/start-sdk'
|
||||
import {
|
||||
TuiButton,
|
||||
TuiDialogContext,
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
import { TuiCell } from '@taiga-ui/layout'
|
||||
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { BackupTarget } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { getServerInfo } from 'src/app/utils/get-server-info'
|
||||
@@ -81,7 +80,7 @@ export class BackupsTargetModal {
|
||||
|
||||
readonly context =
|
||||
injectContext<
|
||||
TuiDialogContext<BackupTarget & { id: string }, { type: BackupType }>
|
||||
TuiDialogContext<T.BackupTarget & { id: string }, { type: BackupType }>
|
||||
>()
|
||||
|
||||
readonly loading = signal(true)
|
||||
@@ -91,7 +90,7 @@ export class BackupsTargetModal {
|
||||
: 'Loading Backup Sources'
|
||||
|
||||
serverId = ''
|
||||
targets: Record<string, BackupTarget> = {}
|
||||
targets: Record<string, T.BackupTarget> = {}
|
||||
|
||||
async ngOnInit() {
|
||||
try {
|
||||
@@ -104,14 +103,14 @@ export class BackupsTargetModal {
|
||||
}
|
||||
}
|
||||
|
||||
isDisabled(target: BackupTarget): boolean {
|
||||
isDisabled(target: T.BackupTarget): boolean {
|
||||
return (
|
||||
!target.mountable ||
|
||||
(this.context.data.type === 'restore' && !this.hasBackup(target))
|
||||
)
|
||||
}
|
||||
|
||||
hasBackup(target: BackupTarget): boolean {
|
||||
hasBackup(target: T.BackupTarget): boolean {
|
||||
return (
|
||||
target.startOs?.[this.serverId] &&
|
||||
Version.parse(target.startOs[this.serverId].version).compare(
|
||||
@@ -127,7 +126,7 @@ export class BackupsTargetModal {
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
select(target: BackupTarget, id: string) {
|
||||
select(target: T.BackupTarget, id: string) {
|
||||
this.context.completeWith({ ...target, id })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ import { ErrorService, LoadingService } from '@start9labs/shared'
|
||||
import { TuiButton, TuiLink, TuiNotification } from '@taiga-ui/core'
|
||||
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||
import { FormComponent } from 'src/app/routes/portal/components/form.component'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import {
|
||||
BackupTarget,
|
||||
BackupTargetType,
|
||||
RR,
|
||||
UnknownDisk,
|
||||
@@ -188,7 +188,7 @@ export class BackupsTargetsModal implements OnInit {
|
||||
}
|
||||
|
||||
private async add(
|
||||
type: BackupTargetType,
|
||||
type: T.BackupTargetType,
|
||||
value:
|
||||
| RR.AddCifsBackupTargetReq
|
||||
| RR.AddCloudBackupTargetReq
|
||||
@@ -204,7 +204,7 @@ export class BackupsTargetsModal implements OnInit {
|
||||
}
|
||||
|
||||
private async update(
|
||||
type: BackupTargetType,
|
||||
type: T.BackupTargetType,
|
||||
value:
|
||||
| RR.UpdateCifsBackupTargetReq
|
||||
| RR.UpdateCloudBackupTargetReq
|
||||
@@ -220,13 +220,13 @@ export class BackupsTargetsModal implements OnInit {
|
||||
}
|
||||
|
||||
private setTargets(
|
||||
saved: Record<string, BackupTarget> = this.targets()?.saved || {},
|
||||
saved: Record<string, T.BackupTarget> = this.targets()?.saved || {},
|
||||
unknownDisks: UnknownDisk[] = this.targets()?.unknownDisks || [],
|
||||
) {
|
||||
this.targets.set({ unknownDisks, saved })
|
||||
}
|
||||
|
||||
private async getSpec(target: BackupTarget) {
|
||||
private async getSpec(target: T.BackupTarget) {
|
||||
switch (target.type) {
|
||||
case 'cifs':
|
||||
return await configBuilderToSpec(cifsSpec)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core'
|
||||
import { BackupTarget } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { DisplayInfo } from '../types/display-info'
|
||||
import { GetBackupIconPipe } from './get-backup-icon.pipe'
|
||||
|
||||
@@ -9,7 +9,7 @@ import { GetBackupIconPipe } from './get-backup-icon.pipe'
|
||||
export class GetDisplayInfoPipe implements PipeTransform {
|
||||
readonly icon = new GetBackupIconPipe()
|
||||
|
||||
transform(target: BackupTarget): DisplayInfo {
|
||||
transform(target: T.BackupTarget): DisplayInfo {
|
||||
const result = {
|
||||
name: target.name,
|
||||
path: `Path: ${target.path}`,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core'
|
||||
import { BackupReport } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
|
||||
@Pipe({
|
||||
name: 'hasError',
|
||||
})
|
||||
export class HasErrorPipe implements PipeTransform {
|
||||
transform(report: BackupReport): boolean {
|
||||
transform(report: T.BackupReport): boolean {
|
||||
return (
|
||||
!!report.server.error ||
|
||||
!!Object.values(report.packages).find(({ error }) => error)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { inject, Pipe, PipeTransform } from '@angular/core'
|
||||
import { map, Observable } from 'rxjs'
|
||||
import { PackageBackupInfo } from 'src/app/services/api/api.types'
|
||||
import { T, Version } from '@start9labs/start-sdk'
|
||||
import { ConfigService } from 'src/app/services/config.service'
|
||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||
import { RecoverOption } from '../types/recover-option'
|
||||
import { Version } from '@start9labs/start-sdk'
|
||||
|
||||
@Pipe({
|
||||
name: 'toOptions',
|
||||
@@ -14,7 +13,7 @@ export class ToOptionsPipe implements PipeTransform {
|
||||
|
||||
transform(
|
||||
packageData$: Observable<Record<string, PackageDataEntry>>,
|
||||
packageBackups: Record<string, PackageBackupInfo> = {},
|
||||
packageBackups: Record<string, T.PackageBackupInfo> = {},
|
||||
): Observable<RecoverOption[]> {
|
||||
return packageData$.pipe(
|
||||
map(packageData =>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { inject, Injectable } from '@angular/core'
|
||||
import { LoadingService } from '@start9labs/shared'
|
||||
import { TuiDialogOptions, TuiDialogService } from '@taiga-ui/core'
|
||||
import { from, switchMap } from 'rxjs'
|
||||
import { BackupTarget } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { TARGET, TARGET_CREATE } from '../modals/target.component'
|
||||
import { BACKUP, BACKUP_OPTIONS } from '../modals/backup.component'
|
||||
@@ -17,7 +17,7 @@ export class BackupsCreateService {
|
||||
|
||||
readonly handle = () => {
|
||||
this.dialogs
|
||||
.open<BackupTarget & { id: string }>(TARGET, TARGET_CREATE)
|
||||
.open<T.BackupTarget & { id: string }>(TARGET, TARGET_CREATE)
|
||||
.pipe(
|
||||
switchMap(({ id }) =>
|
||||
this.dialogs
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
PROMPT,
|
||||
PromptOptions,
|
||||
} from 'src/app/routes/portal/modals/prompt.component'
|
||||
import { BackupTarget } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { RECOVER } from '../modals/recover.component'
|
||||
import { SERVERS } from '../modals/servers.component'
|
||||
@@ -41,7 +41,7 @@ export class BackupsRestoreService {
|
||||
|
||||
readonly handle = () => {
|
||||
this.dialogs
|
||||
.open<BackupTarget & { id: string }>(TARGET, TARGET_RESTORE)
|
||||
.open<T.BackupTarget & { id: string }>(TARGET, TARGET_RESTORE)
|
||||
.pipe(
|
||||
switchMap(target =>
|
||||
this.dialogs
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { BackupInfo } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
|
||||
export interface RecoverData {
|
||||
targetId: string
|
||||
serverId: string
|
||||
backupInfo: BackupInfo
|
||||
backupInfo: T.BackupInfo
|
||||
password: string
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PackageBackupInfo } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
|
||||
export interface RecoverOption extends PackageBackupInfo {
|
||||
export interface RecoverOption extends T.PackageBackupInfo {
|
||||
id: string
|
||||
checked: boolean
|
||||
installed: boolean
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BackupJob, BackupTarget, RR } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { BackupJob, RR } from 'src/app/services/api/api.types'
|
||||
|
||||
export class BackupJobBuilder {
|
||||
name: string
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
|
||||
import { i18nPipe } from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { LogsComponent } from 'src/app/routes/portal/components/logs/logs.component'
|
||||
import { RR } from 'src/app/services/api/api.types'
|
||||
import { FollowServerLogsReq } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { LogsHeaderComponent } from '../components/header.component'
|
||||
|
||||
@@ -24,9 +25,9 @@ import { LogsHeaderComponent } from '../components/header.component'
|
||||
export default class SystemKernelComponent {
|
||||
private readonly api = inject(ApiService)
|
||||
|
||||
protected readonly follow = (params: RR.FollowServerLogsReq) =>
|
||||
protected readonly follow = (params: FollowServerLogsReq) =>
|
||||
this.api.followKernelLogs(params)
|
||||
|
||||
protected readonly fetch = (params: RR.GetServerLogsReq) =>
|
||||
protected readonly fetch = (params: T.LogsParams) =>
|
||||
this.api.getKernelLogs(params)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
|
||||
import { i18nPipe } from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { LogsComponent } from 'src/app/routes/portal/components/logs/logs.component'
|
||||
import { LogsHeaderComponent } from 'src/app/routes/portal/routes/logs/components/header.component'
|
||||
import { RR } from 'src/app/services/api/api.types'
|
||||
import { FollowServerLogsReq } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
|
||||
@Component({
|
||||
@@ -24,9 +25,9 @@ import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
export default class SystemOSComponent {
|
||||
private readonly api = inject(ApiService)
|
||||
|
||||
protected readonly follow = (params: RR.FollowServerLogsReq) =>
|
||||
protected readonly follow = (params: FollowServerLogsReq) =>
|
||||
this.api.followServerLogs(params)
|
||||
|
||||
protected readonly fetch = (params: RR.GetServerLogsReq) =>
|
||||
protected readonly fetch = (params: T.LogsParams) =>
|
||||
this.api.getServerLogs(params)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
computed,
|
||||
input,
|
||||
} from '@angular/core'
|
||||
import { ServerMetrics } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { DataComponent } from './data.component'
|
||||
import { i18nKey } from '@start9labs/shared'
|
||||
|
||||
@@ -86,7 +86,7 @@ const LABELS: Record<string, i18nKey> = {
|
||||
imports: [DataComponent],
|
||||
})
|
||||
export class CpuComponent {
|
||||
readonly value = input<ServerMetrics['cpu']>()
|
||||
readonly value = input<T.Metrics['cpu']>()
|
||||
|
||||
readonly transform = computed(
|
||||
(value = this.value()?.percentageUsed?.value || '0') =>
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from '@angular/core'
|
||||
import { TuiTitle } from '@taiga-ui/core'
|
||||
import { TuiCell } from '@taiga-ui/layout'
|
||||
import { ServerMetrics } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { ValuePipe } from './value.pipe'
|
||||
import { i18nKey, i18nPipe } from '@start9labs/shared'
|
||||
|
||||
@@ -43,8 +43,8 @@ import { i18nKey, i18nPipe } from '@start9labs/shared'
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [TuiCell, TuiTitle, ValuePipe, i18nPipe],
|
||||
})
|
||||
export class DataComponent<T extends ServerMetrics[keyof ServerMetrics]> {
|
||||
readonly labels = input.required<Record<keyof T, i18nKey>>()
|
||||
readonly value = input<T>()
|
||||
readonly keys = computed(() => Object.keys(this.labels()) as Array<keyof T>)
|
||||
export class DataComponent<M extends T.Metrics[keyof T.Metrics]> {
|
||||
readonly labels = input.required<Record<keyof M, i18nKey>>()
|
||||
readonly value = input<M>()
|
||||
readonly keys = computed(() => Object.keys(this.labels()) as Array<keyof M>)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
input,
|
||||
} from '@angular/core'
|
||||
import { TuiProgress } from '@taiga-ui/kit'
|
||||
import { ServerMetrics } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { DataComponent } from './data.component'
|
||||
import { ValuePipe } from './value.pipe'
|
||||
import { i18nKey } from '@start9labs/shared'
|
||||
@@ -40,7 +40,7 @@ const LABELS: Record<string, i18nKey> = {
|
||||
imports: [DataComponent, TuiProgress, ValuePipe],
|
||||
})
|
||||
export class MemoryComponent {
|
||||
readonly value = input<ServerMetrics['memory']>()
|
||||
readonly value = input<T.Metrics['memory']>()
|
||||
|
||||
readonly used = computed(
|
||||
(value = this.value()?.percentageUsed.value || '0') =>
|
||||
|
||||
@@ -13,14 +13,14 @@ import {
|
||||
take,
|
||||
tap,
|
||||
} from 'rxjs'
|
||||
import { ServerMetrics } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ConnectionService } from 'src/app/services/connection.service'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class MetricsService extends Observable<ServerMetrics> {
|
||||
export class MetricsService extends Observable<T.Metrics> {
|
||||
private readonly connection = inject(ConnectionService)
|
||||
private readonly api = inject(ApiService)
|
||||
|
||||
@@ -28,7 +28,7 @@ export class MetricsService extends Observable<ServerMetrics> {
|
||||
this.api.followServerMetrics({}),
|
||||
).pipe(
|
||||
switchMap(({ guid, metrics }) =>
|
||||
this.api.openWebsocket$<ServerMetrics>(guid).pipe(startWith(metrics)),
|
||||
this.api.openWebsocket$<T.Metrics>(guid).pipe(startWith(metrics)),
|
||||
),
|
||||
catchError(() =>
|
||||
this.connection.pipe(filter(Boolean), take(1), ignoreElements()),
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
input,
|
||||
} from '@angular/core'
|
||||
import { TuiProgress } from '@taiga-ui/kit'
|
||||
import { ServerMetrics } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { DataComponent } from './data.component'
|
||||
import { i18nKey } from '@start9labs/shared'
|
||||
|
||||
@@ -41,7 +41,7 @@ const LABELS: Record<string, i18nKey> = {
|
||||
imports: [TuiProgress, DataComponent],
|
||||
})
|
||||
export class StorageComponent {
|
||||
readonly value = input<ServerMetrics['disk']>()
|
||||
readonly value = input<T.Metrics['disk']>()
|
||||
|
||||
readonly used = computed(
|
||||
(
|
||||
|
||||
@@ -17,11 +17,8 @@ import {
|
||||
import { TuiButton } from '@taiga-ui/core'
|
||||
import { filter } from 'rxjs'
|
||||
import { distinctUntilChanged, skip } from 'rxjs/operators'
|
||||
import {
|
||||
RR,
|
||||
ServerNotification,
|
||||
ServerNotifications,
|
||||
} from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { ServerNotification } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { BadgeService } from 'src/app/services/badge.service'
|
||||
import { NotificationService } from 'src/app/services/notification.service'
|
||||
@@ -66,7 +63,7 @@ export default class NotificationsComponent implements OnInit {
|
||||
readonly service = inject(NotificationService)
|
||||
readonly api = inject(ApiService)
|
||||
readonly errorService = inject(ErrorService)
|
||||
readonly notifications = signal<ServerNotifications | null>(null)
|
||||
readonly notifications = signal<T.NotificationWithId[] | null>(null)
|
||||
|
||||
protected readonly table = viewChild<
|
||||
NotificationsTableComponent<ServerNotification<number>>
|
||||
@@ -92,7 +89,7 @@ export default class NotificationsComponent implements OnInit {
|
||||
})
|
||||
}
|
||||
|
||||
async getMore(params: RR.GetNotificationsReq) {
|
||||
async getMore(params: T.ListNotificationParams) {
|
||||
try {
|
||||
this.notifications.set(null)
|
||||
this.notifications.set(await this.api.getNotifications(params))
|
||||
@@ -101,7 +98,7 @@ export default class NotificationsComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
async remove(all: ServerNotifications) {
|
||||
async remove(all: T.NotificationWithId[]) {
|
||||
const ids =
|
||||
this.table()
|
||||
?.selected()
|
||||
@@ -119,7 +116,7 @@ export default class NotificationsComponent implements OnInit {
|
||||
}
|
||||
|
||||
private init() {
|
||||
this.getMore({}).then(() => {
|
||||
this.getMore({ before: null, limit: null }).then(() => {
|
||||
const latest = this.notifications()?.at(0)
|
||||
if (latest) {
|
||||
this.service.markSeenAll(latest.id)
|
||||
|
||||
@@ -144,7 +144,7 @@ export class ServiceTaskComponent {
|
||||
.subscribe(async () => {
|
||||
const loader = this.loader.open().subscribe()
|
||||
try {
|
||||
await this.api.clearTask({ packageId, replayId })
|
||||
await this.api.clearTask({ packageId, replayId, force: false })
|
||||
} catch (e: any) {
|
||||
this.errorService.handleError(e)
|
||||
} finally {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RR } from 'src/app/services/api/api.types'
|
||||
import { ActionRes } from 'src/app/services/api/api.types'
|
||||
|
||||
type ActionResponse = NonNullable<RR.ActionRes>
|
||||
type ActionResponse = NonNullable<ActionRes>
|
||||
type ActionResult = NonNullable<ActionResponse['result']>
|
||||
export type ActionResponseWithResult = ActionResponse & { result: ActionResult }
|
||||
export type SingleResult = ActionResult & { type: 'single' }
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
|
||||
import { getPkgId } from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { LogsComponent } from 'src/app/routes/portal/components/logs/logs.component'
|
||||
import { RR } from 'src/app/services/api/api.types'
|
||||
import { FollowServerLogsReq } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
|
||||
@Component({
|
||||
@@ -24,9 +25,9 @@ export default class ServiceLogsRoute {
|
||||
|
||||
readonly id = getPkgId()
|
||||
|
||||
readonly follow = async (params: RR.FollowServerLogsReq) =>
|
||||
readonly follow = async (params: FollowServerLogsReq) =>
|
||||
this.api.followPackageLogs({ id: this.id, ...params })
|
||||
|
||||
readonly fetch = async (params: RR.GetServerLogsReq) =>
|
||||
readonly fetch = async (params: T.LogsParams) =>
|
||||
this.api.getPackageLogs({ id: this.id, ...params })
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { inject, Injectable, signal } from '@angular/core'
|
||||
import { ErrorService, getErrorMessage } from '@start9labs/shared'
|
||||
import { Version } from '@start9labs/start-sdk'
|
||||
import { T, Version } from '@start9labs/start-sdk'
|
||||
import {
|
||||
BackupTarget,
|
||||
CifsBackupTarget,
|
||||
DiskBackupTarget,
|
||||
} from 'src/app/services/api/api.types'
|
||||
@@ -61,13 +60,13 @@ export class BackupService {
|
||||
}
|
||||
}
|
||||
|
||||
hasAnyBackup({ startOs }: BackupTarget): boolean {
|
||||
hasAnyBackup({ startOs }: T.BackupTarget): boolean {
|
||||
return Object.values(startOs).some(
|
||||
s => Version.parse(s.version).compare(Version.parse('0.3.6')) !== 'less',
|
||||
)
|
||||
}
|
||||
|
||||
hasThisBackup({ startOs }: BackupTarget, id: string): boolean {
|
||||
hasThisBackup({ startOs }: T.BackupTarget, id: string): boolean {
|
||||
const item = startOs[id]
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { TuiDialogContext } from '@taiga-ui/core'
|
||||
import {
|
||||
BackupInfo,
|
||||
CifsBackupTarget,
|
||||
DiskBackupTarget,
|
||||
PackageBackupInfo,
|
||||
} from 'src/app/services/api/api.types'
|
||||
import { MappedBackupTarget } from './backup.service'
|
||||
|
||||
@@ -12,7 +11,7 @@ export type BackupContext = TuiDialogContext<
|
||||
MappedBackupTarget<CifsBackupTarget | DiskBackupTarget>
|
||||
>
|
||||
|
||||
export interface RecoverOption extends PackageBackupInfo {
|
||||
export interface RecoverOption extends T.PackageBackupInfo {
|
||||
id: string
|
||||
checked: boolean
|
||||
installed: boolean
|
||||
@@ -22,6 +21,6 @@ export interface RecoverOption extends PackageBackupInfo {
|
||||
export interface RecoverData {
|
||||
targetId: string
|
||||
serverId: string
|
||||
backupInfo: BackupInfo
|
||||
backupInfo: T.BackupInfo
|
||||
password: string
|
||||
}
|
||||
|
||||
@@ -11,14 +11,14 @@ import {
|
||||
i18nPipe,
|
||||
LoadingService,
|
||||
} from '@start9labs/shared'
|
||||
import { ISB } from '@start9labs/start-sdk'
|
||||
import { ISB, T } from '@start9labs/start-sdk'
|
||||
import { TuiButton, TuiIcon } from '@taiga-ui/core'
|
||||
import { TuiTooltip } from '@taiga-ui/kit'
|
||||
import { filter } from 'rxjs'
|
||||
import { FormComponent } from 'src/app/routes/portal/components/form.component'
|
||||
import { PlaceholderComponent } from 'src/app/routes/portal/components/placeholder.component'
|
||||
import { TableComponent } from 'src/app/routes/portal/components/table.component'
|
||||
import { CifsBackupTarget, RR } from 'src/app/services/api/api.types'
|
||||
import { CifsBackupTarget } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { FormDialogService } from 'src/app/services/form-dialog.service'
|
||||
import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec'
|
||||
@@ -211,7 +211,7 @@ export class BackupNetworkComponent {
|
||||
buttons: [
|
||||
{
|
||||
text: this.i18n.transform('Connect'),
|
||||
handler: (value: RR.AddBackupTargetReq) => this.addTarget(value),
|
||||
handler: (value: T.CifsAddParams) => this.addTarget(value),
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -226,7 +226,7 @@ export class BackupNetworkComponent {
|
||||
buttons: [
|
||||
{
|
||||
text: this.i18n.transform('Connect'),
|
||||
handler: async (value: RR.AddBackupTargetReq) => {
|
||||
handler: async (value: T.CifsAddParams) => {
|
||||
const loader = this.loader
|
||||
.open('Testing connectivity to shared folder')
|
||||
.subscribe()
|
||||
@@ -272,7 +272,7 @@ export class BackupNetworkComponent {
|
||||
})
|
||||
}
|
||||
|
||||
private async addTarget(v: RR.AddBackupTargetReq): Promise<boolean> {
|
||||
private async addTarget(v: T.CifsAddParams): Promise<boolean> {
|
||||
const loader = this.loader
|
||||
.open('Testing connectivity to shared folder')
|
||||
.subscribe()
|
||||
|
||||
@@ -148,8 +148,8 @@ export class BackupsRecoverComponent {
|
||||
|
||||
async restore(options: RecoverOption[]): Promise<void> {
|
||||
const ids = options.filter(({ checked }) => !!checked).map(({ id }) => id)
|
||||
const { targetId, serverId, password } = this.context.data
|
||||
const params = { ids, targetId, serverId, password }
|
||||
const { targetId, password } = this.context.data
|
||||
const params = { ids, targetId, password }
|
||||
const loader = this.loader.open('Initializing').subscribe()
|
||||
|
||||
try {
|
||||
|
||||
@@ -181,7 +181,11 @@ export default class SystemEmailComponent {
|
||||
`${this.i18n.transform('A test email has been sent to')} ${this.testAddress}. <i>${this.i18n.transform('Check your spam folder and mark as not spam.')}</i>` as i18nKey
|
||||
|
||||
try {
|
||||
await this.api.testSmtp({ to: this.testAddress, ...value })
|
||||
await this.api.testSmtp({
|
||||
...value,
|
||||
password: value.password || '',
|
||||
to: this.testAddress,
|
||||
})
|
||||
this.dialog
|
||||
.openAlert(success, { label: 'Success', size: 's' })
|
||||
.subscribe()
|
||||
|
||||
@@ -134,6 +134,7 @@ export default class GatewaysComponent {
|
||||
input.config.selection === 'paste'
|
||||
? input.config.value.file
|
||||
: await (input.config.value.file as any as File).text(),
|
||||
type: null, // @TODO Aiden why is attr here?
|
||||
setAsDefaultOutbound: input.setAsDefaultOutbound,
|
||||
})
|
||||
return true
|
||||
|
||||
@@ -7,9 +7,9 @@ import {
|
||||
} from '@angular/core'
|
||||
import { RouterLink } from '@angular/router'
|
||||
import { ErrorService, i18nPipe, LoadingService } from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { TuiButton } from '@taiga-ui/core'
|
||||
import { from, map, merge, Observable, Subject } from 'rxjs'
|
||||
import { Session } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { TitleDirective } from 'src/app/services/title.service'
|
||||
import { SessionsTableComponent } from './table.component'
|
||||
@@ -72,7 +72,7 @@ export default class SystemSessionsComponent {
|
||||
|
||||
readonly current$ = this.sessions$.pipe(
|
||||
map(s => {
|
||||
const current = s.sessions[s.current]
|
||||
const current = s.current ? s.sessions[s.current] : undefined
|
||||
|
||||
return current ? [current] : []
|
||||
}),
|
||||
@@ -115,6 +115,6 @@ export default class SystemSessionsComponent {
|
||||
}
|
||||
}
|
||||
|
||||
interface SessionWithId extends Session {
|
||||
interface SessionWithId extends T.Session {
|
||||
id: string
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { FormsModule } from '@angular/forms'
|
||||
import { TuiIcon } from '@taiga-ui/core'
|
||||
import { TuiCheckbox, TuiFade, TuiSkeleton } from '@taiga-ui/kit'
|
||||
import { TableComponent } from 'src/app/routes/portal/components/table.component'
|
||||
import { Session } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { PlatformInfoPipe } from './platform-info.pipe'
|
||||
import { i18nPipe } from '@start9labs/shared'
|
||||
|
||||
@@ -165,11 +165,11 @@ import { i18nPipe } from '@start9labs/shared'
|
||||
i18nPipe,
|
||||
],
|
||||
})
|
||||
export class SessionsTableComponent<T extends Session> implements OnChanges {
|
||||
readonly sessions = input<readonly T[] | null>(null)
|
||||
export class SessionsTableComponent<S extends T.Session> implements OnChanges {
|
||||
readonly sessions = input<readonly S[] | null>(null)
|
||||
readonly single = input(false)
|
||||
|
||||
readonly selected = signal<readonly T[]>([])
|
||||
readonly selected = signal<readonly S[]>([])
|
||||
readonly all = computed(
|
||||
() =>
|
||||
!!this.selected()?.length &&
|
||||
@@ -180,7 +180,7 @@ export class SessionsTableComponent<T extends Session> implements OnChanges {
|
||||
this.selected.set([])
|
||||
}
|
||||
|
||||
onToggle(session: T) {
|
||||
onToggle(session: S) {
|
||||
if (this.selected().includes(session)) {
|
||||
this.selected.update(selected => selected.filter(s => s !== session))
|
||||
} else {
|
||||
|
||||
@@ -13,11 +13,10 @@ import {
|
||||
i18nPipe,
|
||||
LoadingService,
|
||||
} from '@start9labs/shared'
|
||||
import { ISB } from '@start9labs/start-sdk'
|
||||
import { ISB, T } from '@start9labs/start-sdk'
|
||||
import { TuiButton, TuiHint } from '@taiga-ui/core'
|
||||
import { filter, from, merge, Subject } from 'rxjs'
|
||||
import { FormComponent } from 'src/app/routes/portal/components/form.component'
|
||||
import { SSHKey } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { FormDialogService } from 'src/app/services/form-dialog.service'
|
||||
import { TitleDirective } from 'src/app/services/title.service'
|
||||
@@ -101,13 +100,13 @@ export default class SystemSSHComponent {
|
||||
private readonly i18n = inject(i18nPipe)
|
||||
private readonly dialogs = inject(DialogService)
|
||||
|
||||
private readonly local$ = new Subject<readonly SSHKey[]>()
|
||||
private readonly local$ = new Subject<readonly T.SshKeyResponse[]>()
|
||||
|
||||
readonly keys$ = merge(from(this.api.getSshKeys({})), this.local$)
|
||||
|
||||
protected tableKeys = viewChild<SSHTableComponent<SSHKey>>('table')
|
||||
protected tableKeys = viewChild<SSHTableComponent<T.SshKeyResponse>>('table')
|
||||
|
||||
async add(all: readonly SSHKey[]) {
|
||||
async add(all: readonly T.SshKeyResponse[]) {
|
||||
const spec = ISB.InputSpec.of({
|
||||
key: ISB.Value.text({
|
||||
name: this.i18n.transform('Public Key'),
|
||||
@@ -150,7 +149,7 @@ export default class SystemSSHComponent {
|
||||
})
|
||||
}
|
||||
|
||||
remove(all: readonly SSHKey[]) {
|
||||
remove(all: readonly T.SshKeyResponse[]) {
|
||||
this.dialogs
|
||||
.openConfirm({ label: 'Are you sure?', size: 's' })
|
||||
.pipe(filter(Boolean))
|
||||
|
||||
@@ -11,7 +11,7 @@ import { FormsModule } from '@angular/forms'
|
||||
import { i18nPipe } from '@start9labs/shared'
|
||||
import { TuiCheckbox, TuiFade, TuiSkeleton } from '@taiga-ui/kit'
|
||||
import { TableComponent } from 'src/app/routes/portal/components/table.component'
|
||||
import { SSHKey } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
|
||||
@Component({
|
||||
selector: '[keys]',
|
||||
@@ -151,10 +151,12 @@ import { SSHKey } from 'src/app/services/api/api.types'
|
||||
i18nPipe,
|
||||
],
|
||||
})
|
||||
export class SSHTableComponent<T extends SSHKey> implements OnChanges {
|
||||
readonly keys = input<readonly T[] | null>(null)
|
||||
export class SSHTableComponent<
|
||||
K extends T.SshKeyResponse,
|
||||
> implements OnChanges {
|
||||
readonly keys = input<readonly K[] | null>(null)
|
||||
|
||||
readonly selected = signal<readonly T[]>([])
|
||||
readonly selected = signal<readonly K[]>([])
|
||||
readonly all = computed(
|
||||
() =>
|
||||
!!this.selected()?.length &&
|
||||
@@ -165,7 +167,7 @@ export class SSHTableComponent<T extends SSHKey> implements OnChanges {
|
||||
this.selected.set([])
|
||||
}
|
||||
|
||||
onToggle(key: T) {
|
||||
onToggle(key: K) {
|
||||
if (this.selected().includes(key)) {
|
||||
this.selected.update(selected => selected.filter(s => s !== key))
|
||||
} else {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { AvailableWifi } from 'src/app/services/api/api.types'
|
||||
import { RR } from 'src/app/services/api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
|
||||
export interface WiFiForm {
|
||||
ssid: string
|
||||
password: string
|
||||
}
|
||||
|
||||
export interface Wifi extends AvailableWifi {
|
||||
export interface Wifi extends T.WifiListOut {
|
||||
readonly connected?: boolean
|
||||
}
|
||||
|
||||
@@ -15,7 +14,7 @@ export interface WifiData {
|
||||
available: readonly Wifi[]
|
||||
}
|
||||
|
||||
export function parseWifi(res: RR.GetWifiRes): WifiData {
|
||||
export function parseWifi(res: T.WifiListInfo): WifiData {
|
||||
return {
|
||||
available: res.availableWifi,
|
||||
known: Object.entries(res.ssids).map(([ssid, strength]) => ({
|
||||
|
||||
@@ -148,7 +148,7 @@ export default class SystemWifiComponent {
|
||||
.subscribe()
|
||||
|
||||
try {
|
||||
await this.api.enableWifi({ enable })
|
||||
await this.api.enableWifi({ enabled: enable })
|
||||
} catch (e: any) {
|
||||
this.errorService.handleError(e)
|
||||
} finally {
|
||||
@@ -187,9 +187,8 @@ export default class SystemWifiComponent {
|
||||
await this.api.addWifi({
|
||||
ssid,
|
||||
password,
|
||||
priority: 0,
|
||||
connect: true,
|
||||
})
|
||||
await this.api.connectWifi({ ssid })
|
||||
} else {
|
||||
await this.api.connectWifi({ ssid })
|
||||
}
|
||||
@@ -263,8 +262,6 @@ export default class SystemWifiComponent {
|
||||
await this.api.addWifi({
|
||||
ssid,
|
||||
password,
|
||||
priority: 0,
|
||||
connect: false,
|
||||
})
|
||||
wifi.known = wifi.known.concat({
|
||||
ssid,
|
||||
|
||||
@@ -64,9 +64,9 @@ export class ActionService {
|
||||
try {
|
||||
const res = await this.api.runAction({
|
||||
packageId,
|
||||
eventId,
|
||||
actionId,
|
||||
input: input ?? null,
|
||||
eventId,
|
||||
})
|
||||
|
||||
if (!res) return
|
||||
|
||||
@@ -2,9 +2,8 @@ import {
|
||||
InstalledState,
|
||||
PackageDataEntry,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { RR, ServerMetrics, ServerNotifications } from './api.types'
|
||||
import { ActionRes } from './api.types'
|
||||
import { BTC_ICON, LND_ICON, PROXY_ICON, REGISTRY_ICON } from './api-icons'
|
||||
import { Log } from '@start9labs/shared'
|
||||
import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec'
|
||||
import { T, ISB, IST } from '@start9labs/start-sdk'
|
||||
import { GetPackagesRes } from '@start9labs/marketplace'
|
||||
@@ -30,7 +29,7 @@ export namespace Mock {
|
||||
shuttingDown: false,
|
||||
}
|
||||
|
||||
export const RegistryOSUpdate: RR.CheckOsUpdateRes = {
|
||||
export const RegistryOSUpdate: T.OsVersionInfoMap = {
|
||||
'0.4.1': {
|
||||
headline: 'v0.4.1',
|
||||
releaseNotes: 'Testing some release notes',
|
||||
@@ -899,7 +898,7 @@ export namespace Mock {
|
||||
},
|
||||
}
|
||||
|
||||
export const Notifications: ServerNotifications = [
|
||||
export const Notifications: T.NotificationWithId[] = [
|
||||
{
|
||||
id: 1,
|
||||
packageId: null,
|
||||
@@ -974,7 +973,7 @@ export namespace Mock {
|
||||
},
|
||||
]
|
||||
|
||||
export function getMetrics(): ServerMetrics {
|
||||
export function getMetrics(): T.Metrics {
|
||||
return {
|
||||
general: {
|
||||
temperature: {
|
||||
@@ -1055,7 +1054,7 @@ export namespace Mock {
|
||||
}
|
||||
}
|
||||
|
||||
export const ServerLogs: Log[] = [
|
||||
export const ServerLogs: T.LogEntry[] = [
|
||||
{
|
||||
timestamp: '2022-07-28T03:52:54.808769Z',
|
||||
message: '****** START *****',
|
||||
@@ -1079,7 +1078,7 @@ export namespace Mock {
|
||||
},
|
||||
]
|
||||
|
||||
export const Sessions: RR.GetSessionsRes = {
|
||||
export const Sessions: T.SessionList = {
|
||||
current: 'b7b1a9cef4284f00af9e9dda6e676177',
|
||||
sessions: {
|
||||
'9513226517c54ddd8107d6d7b9d8aed7': {
|
||||
@@ -1101,7 +1100,7 @@ export namespace Mock {
|
||||
},
|
||||
}
|
||||
|
||||
export const SshKeys: RR.GetSSHKeysRes = [
|
||||
export const SshKeys: T.SshKeyResponse[] = [
|
||||
{
|
||||
createdAt: new Date().toISOString(),
|
||||
alg: 'ed25519',
|
||||
@@ -1116,14 +1115,14 @@ export namespace Mock {
|
||||
},
|
||||
]
|
||||
|
||||
export const SshKey: RR.AddSSHKeyRes = {
|
||||
export const SshKey: T.SshKeyResponse = {
|
||||
createdAt: new Date().toISOString(),
|
||||
alg: 'ed25519',
|
||||
hostname: 'Lucy Key',
|
||||
fingerprint: '44:44:7e:78:61:b4:bf:g2:de:24:15:96:4e:d4:15:53',
|
||||
}
|
||||
|
||||
export const Wifi: RR.GetWifiRes = {
|
||||
export const Wifi: T.WifiListInfo = {
|
||||
ethernet: true,
|
||||
ssids: {
|
||||
Goosers: 50,
|
||||
@@ -1150,7 +1149,7 @@ export namespace Mock {
|
||||
],
|
||||
}
|
||||
|
||||
export const BackupTargets: RR.GetBackupTargetsRes = {
|
||||
export const BackupTargets: { [id: string]: T.BackupTarget } = {
|
||||
hsbdjhasbasda: {
|
||||
type: 'cifs',
|
||||
hostname: 'smb://192.169.10.0',
|
||||
@@ -1195,6 +1194,7 @@ export namespace Mock {
|
||||
used: 100000000000,
|
||||
model: null,
|
||||
vendor: 'SSK',
|
||||
guid: null,
|
||||
startOs: {
|
||||
'1234-5678-9876-5432': {
|
||||
hostname: 'adjective-noun',
|
||||
@@ -1338,7 +1338,7 @@ export namespace Mock {
|
||||
// },
|
||||
// ]
|
||||
|
||||
export const BackupInfo: RR.GetBackupInfoRes = {
|
||||
export const BackupInfo: T.BackupInfo = {
|
||||
version: '0.3.6',
|
||||
timestamp: new Date().toISOString(),
|
||||
packageBackups: {
|
||||
@@ -1357,7 +1357,7 @@ export namespace Mock {
|
||||
},
|
||||
}
|
||||
|
||||
export const ActionResMessage: RR.ActionRes = {
|
||||
export const ActionResMessage: ActionRes = {
|
||||
version: '1',
|
||||
title: 'New Password',
|
||||
message:
|
||||
@@ -1365,7 +1365,7 @@ export namespace Mock {
|
||||
result: null,
|
||||
}
|
||||
|
||||
export const ActionResSingle: RR.ActionRes = {
|
||||
export const ActionResSingle: ActionRes = {
|
||||
version: '1',
|
||||
title: 'New Password',
|
||||
message:
|
||||
@@ -1379,7 +1379,7 @@ export namespace Mock {
|
||||
},
|
||||
}
|
||||
|
||||
export const ActionResGroup: RR.ActionRes = {
|
||||
export const ActionResGroup: ActionRes = {
|
||||
version: '1',
|
||||
title: 'Properties',
|
||||
message:
|
||||
@@ -2180,6 +2180,7 @@ export namespace Mock {
|
||||
},
|
||||
publicDomains: {},
|
||||
privateDomains: {},
|
||||
portForwards: [],
|
||||
},
|
||||
bcdefgh: {
|
||||
bindings: {
|
||||
@@ -2203,6 +2204,7 @@ export namespace Mock {
|
||||
},
|
||||
publicDomains: {},
|
||||
privateDomains: {},
|
||||
portForwards: [],
|
||||
},
|
||||
cdefghi: {
|
||||
bindings: {
|
||||
@@ -2226,6 +2228,7 @@ export namespace Mock {
|
||||
},
|
||||
publicDomains: {},
|
||||
privateDomains: {},
|
||||
portForwards: [],
|
||||
},
|
||||
},
|
||||
storeExposedDependents: [],
|
||||
|
||||
@@ -1,521 +1,99 @@
|
||||
import { Dump } from 'patch-db-client'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import {
|
||||
FetchLogsReq,
|
||||
FetchLogsRes,
|
||||
FullKeyboard,
|
||||
SetLanguageParams,
|
||||
StartOSDiskInfo,
|
||||
} from '@start9labs/shared'
|
||||
import { IST, T } from '@start9labs/start-sdk'
|
||||
import { WebSocketSubjectConfig } from 'rxjs/webSocket'
|
||||
import {
|
||||
GetPackageReq,
|
||||
GetPackageRes,
|
||||
GetPackagesReq,
|
||||
GetPackagesRes,
|
||||
} from '@start9labs/marketplace'
|
||||
import { GetPackageReq, GetPackagesReq } from '@start9labs/marketplace'
|
||||
|
||||
export namespace RR {
|
||||
// websocket
|
||||
// websocket
|
||||
|
||||
export type WebsocketConfig<T> = Omit<WebSocketSubjectConfig<T>, 'url'>
|
||||
export type WebsocketConfig<U> = Omit<WebSocketSubjectConfig<U>, 'url'>
|
||||
|
||||
// state
|
||||
// state
|
||||
|
||||
export type EchoReq = { message: string } // server.echo
|
||||
export type EchoRes = string
|
||||
export type ServerState = 'initializing' | 'error' | 'running'
|
||||
|
||||
export type ServerState = 'initializing' | 'error' | 'running'
|
||||
// diagnostic
|
||||
|
||||
// DB
|
||||
|
||||
export type SubscribePatchReq = {}
|
||||
export type SubscribePatchRes = {
|
||||
dump: Dump<DataModel>
|
||||
guid: string
|
||||
}
|
||||
|
||||
export type SetDBValueReq<T> = { pointer: string; value: T } // db.put.ui
|
||||
export type SetDBValueRes = null
|
||||
|
||||
// auth
|
||||
|
||||
export type LoginReq = {
|
||||
password: string
|
||||
ephemeral?: boolean
|
||||
} // auth.login - unauthed
|
||||
export type loginRes = null
|
||||
|
||||
export type LogoutReq = {} // auth.logout
|
||||
export type LogoutRes = null
|
||||
|
||||
export type ResetPasswordReq = {
|
||||
oldPassword: string
|
||||
newPassword: string
|
||||
} // auth.reset-password
|
||||
export type ResetPasswordRes = null
|
||||
|
||||
// diagnostic
|
||||
|
||||
export type DiagnosticErrorRes = {
|
||||
code: number
|
||||
message: string
|
||||
data: { details: string }
|
||||
}
|
||||
|
||||
// init
|
||||
|
||||
export type InitFollowProgressRes = {
|
||||
progress: T.FullProgress
|
||||
guid: string
|
||||
}
|
||||
|
||||
// server
|
||||
|
||||
export type GetSystemTimeReq = {} // server.time
|
||||
export type GetSystemTimeRes = {
|
||||
now: string
|
||||
uptime: number // seconds
|
||||
}
|
||||
|
||||
export type GetServerLogsReq = FetchLogsReq // server.logs & server.kernel-logs
|
||||
export type GetServerLogsRes = FetchLogsRes
|
||||
|
||||
export type FollowServerLogsReq = {
|
||||
limit?: number // (optional) default is 50. Ignored if cursor provided
|
||||
boot?: number | string | null // (optional) number is offset (0: current, -1 prev, +1 first), string is a specific boot id, null is all. Default is undefined
|
||||
cursor?: string // the last known log. Websocket will return all logs since this log
|
||||
} // server.logs.follow & server.kernel-logs.follow
|
||||
export type FollowServerLogsRes = {
|
||||
startCursor: string
|
||||
guid: string
|
||||
}
|
||||
|
||||
export type FollowServerMetricsReq = {} // server.metrics.follow
|
||||
export type FollowServerMetricsRes = {
|
||||
guid: string
|
||||
metrics: ServerMetrics
|
||||
}
|
||||
|
||||
export type UpdateServerReq = { registry: string; targetVersion: string } // server.update
|
||||
export type UpdateServerRes = 'updating' | 'no-updates'
|
||||
|
||||
export type RestartServerReq = {} // server.restart
|
||||
export type RestartServerRes = null
|
||||
|
||||
export type ShutdownServerReq = {} // server.shutdown
|
||||
export type ShutdownServerRes = null
|
||||
|
||||
export type DiskRepairReq = {} // server.disk.repair
|
||||
export type DiskRepairRes = null
|
||||
|
||||
export type SetDnsReq = {
|
||||
servers: string[] | null
|
||||
} // net.dns.set-static
|
||||
export type SetDnsRes = null
|
||||
|
||||
export type QueryDnsReq = {
|
||||
fqdn: string
|
||||
} // net.dns.query
|
||||
export type QueryDnsRes = string | null
|
||||
|
||||
export type TestPortForwardReq = {
|
||||
gateway: string
|
||||
port: number
|
||||
} // net.port-forward.test
|
||||
export type TestPortForwardRes = boolean
|
||||
|
||||
export type SetKeyboardReq = FullKeyboard // server.set-keyboard
|
||||
export type SetKeyboardRes = null
|
||||
|
||||
export type SetLanguageReq = SetLanguageParams // server.set-language
|
||||
export type SetLanguageRes = null
|
||||
|
||||
// smtp
|
||||
|
||||
export type SetSMTPReq = T.SmtpValue // server.set-smtp
|
||||
export type SetSMTPRes = null
|
||||
|
||||
export type ClearSMTPReq = {} // server.clear-smtp
|
||||
export type ClearSMTPRes = null
|
||||
|
||||
export type TestSMTPReq = SetSMTPReq & { to: string } // server.test-smtp
|
||||
export type TestSMTPRes = null
|
||||
|
||||
// sessions
|
||||
|
||||
export type GetSessionsReq = {} // sessions.list
|
||||
export type GetSessionsRes = {
|
||||
current: string
|
||||
sessions: { [hash: string]: Session }
|
||||
}
|
||||
|
||||
export type KillSessionsReq = { ids: string[] } // sessions.kill
|
||||
export type KillSessionsRes = null
|
||||
|
||||
// notification
|
||||
|
||||
export type GetNotificationsReq = {
|
||||
before?: number
|
||||
limit?: number
|
||||
} // notification.list
|
||||
export type GetNotificationsRes = ServerNotification<number>[]
|
||||
|
||||
export type DeleteNotificationsReq = { ids: number[] } // notification.remove
|
||||
export type DeleteNotificationsRes = null
|
||||
|
||||
export type MarkSeenNotificationReq = DeleteNotificationsReq // notification.mark-seen
|
||||
export type MarkSeenNotificationRes = null
|
||||
|
||||
export type MarkSeenAllNotificationsReq = { before: number } // notification.mark-seen-before
|
||||
export type MarkSeenAllNotificationsRes = null
|
||||
|
||||
export type MarkUnseenNotificationReq = DeleteNotificationsReq // notification.mark-unseen
|
||||
export type MarkUnseenNotificationRes = null
|
||||
|
||||
// wifi
|
||||
|
||||
export type GetWifiReq = {}
|
||||
export type GetWifiRes = {
|
||||
ssids: {
|
||||
[ssid: string]: number
|
||||
}
|
||||
connected: string | null
|
||||
country: string | null
|
||||
ethernet: boolean
|
||||
availableWifi: AvailableWifi[]
|
||||
}
|
||||
|
||||
export type AddWifiReq = {
|
||||
// wifi.add
|
||||
ssid: string
|
||||
password: string
|
||||
priority: number
|
||||
connect: boolean
|
||||
}
|
||||
export type AddWifiRes = null
|
||||
|
||||
export type EnabledWifiReq = { enable: boolean } // wifi.set-enabled
|
||||
export type EnabledWifiRes = null
|
||||
|
||||
export type SetWifiCountryReq = { country: string } // wifi.country.set
|
||||
export type SetWifiCountryRes = null
|
||||
|
||||
export type ConnectWifiReq = { ssid: string } // wifi.connect
|
||||
export type ConnectWifiRes = null
|
||||
|
||||
export type DeleteWifiReq = { ssid: string } // wifi.remove
|
||||
export type DeleteWifiRes = null
|
||||
|
||||
// ssh
|
||||
|
||||
export type GetSSHKeysReq = {} // ssh.list
|
||||
export type GetSSHKeysRes = SSHKey[]
|
||||
|
||||
export type AddSSHKeyReq = { key: string } // ssh.add
|
||||
export type AddSSHKeyRes = SSHKey
|
||||
|
||||
export type DeleteSSHKeyReq = { fingerprint: string } // ssh.remove
|
||||
export type DeleteSSHKeyRes = null
|
||||
|
||||
// backup
|
||||
|
||||
export type GetBackupTargetsReq = {} // backup.target.list
|
||||
export type GetBackupTargetsRes = { [id: string]: BackupTarget }
|
||||
|
||||
export type AddBackupTargetReq = {
|
||||
// backup.target.cifs.add
|
||||
hostname: string
|
||||
path: string
|
||||
username: string
|
||||
password: string | null
|
||||
}
|
||||
export type AddBackupTargetRes = { [id: string]: CifsBackupTarget }
|
||||
|
||||
export type UpdateBackupTargetReq = AddBackupTargetReq & { id: string } // backup.target.cifs.update
|
||||
export type UpdateBackupTargetRes = AddBackupTargetRes
|
||||
|
||||
export type RemoveBackupTargetReq = { id: string } // backup.target.cifs.remove
|
||||
export type RemoveBackupTargetRes = null
|
||||
|
||||
export type GetBackupInfoReq = {
|
||||
// backup.target.info
|
||||
targetId: string
|
||||
serverId: string
|
||||
password: string
|
||||
}
|
||||
export type GetBackupInfoRes = BackupInfo
|
||||
|
||||
export type CreateBackupReq = {
|
||||
// backup.create
|
||||
targetId: string
|
||||
packageIds: string[]
|
||||
oldPassword: string | null
|
||||
password: string
|
||||
}
|
||||
export type CreateBackupRes = null
|
||||
|
||||
// network
|
||||
|
||||
export type GatewayType = 'inbound-outbound' | 'outbound-only'
|
||||
|
||||
export type AddTunnelReq = {
|
||||
name: string
|
||||
config: string // file contents
|
||||
setAsDefaultOutbound?: boolean
|
||||
} // net.tunnel.add
|
||||
export type AddTunnelRes = {
|
||||
id: string
|
||||
}
|
||||
|
||||
export type UpdateTunnelReq = {
|
||||
id: string
|
||||
name: string
|
||||
} // net.gateway.set-name
|
||||
export type UpdateTunnelRes = null
|
||||
|
||||
export type RemoveTunnelReq = { id: string } // net.tunnel.remove
|
||||
export type RemoveTunnelRes = null
|
||||
|
||||
// Set default outbound gateway
|
||||
export type SetDefaultOutboundReq = { gateway: string | null } // net.gateway.set-default-outbound
|
||||
export type SetDefaultOutboundRes = null
|
||||
|
||||
// Set service outbound gateway
|
||||
export type SetServiceOutboundReq = {
|
||||
packageId: string
|
||||
gateway: string | null
|
||||
} // package.set-outbound-gateway
|
||||
export type SetServiceOutboundRes = null
|
||||
|
||||
export type InitAcmeReq = {
|
||||
provider: string
|
||||
contact: string[]
|
||||
}
|
||||
export type InitAcmeRes = null
|
||||
|
||||
export type RemoveAcmeReq = {
|
||||
provider: string
|
||||
}
|
||||
export type RemoveAcmeRes = null
|
||||
|
||||
export type ServerBindingSetAddressEnabledReq = {
|
||||
// server.host.binding.set-address-enabled
|
||||
internalPort: 80
|
||||
address: string // JSON-serialized HostnameInfo
|
||||
enabled: boolean | null // null = reset to default
|
||||
}
|
||||
export type ServerBindingSetAddressEnabledRes = null
|
||||
|
||||
export type OsUiAddPublicDomainReq = {
|
||||
// server.host.address.domain.public.add
|
||||
fqdn: string // FQDN
|
||||
gateway: T.GatewayId
|
||||
acme: string | null // URL. null means local Root CA
|
||||
}
|
||||
export type OsUiAddPublicDomainRes = QueryDnsRes
|
||||
|
||||
export type OsUiRemovePublicDomainReq = {
|
||||
// server.host.address.domain.public.remove
|
||||
fqdn: string // FQDN
|
||||
}
|
||||
export type OsUiRemovePublicDomainRes = null
|
||||
|
||||
export type OsUiAddPrivateDomainReq = {
|
||||
// server.host.address.domain.private.add
|
||||
fqdn: string // FQDN
|
||||
}
|
||||
export type OsUiAddPrivateDomainRes = null
|
||||
|
||||
export type OsUiRemovePrivateDomainReq = {
|
||||
// server.host.address.domain.private.remove
|
||||
fqdn: string // FQDN
|
||||
}
|
||||
export type OsUiRemovePrivateDomainRes = null
|
||||
|
||||
export type PkgBindingSetAddressEnabledReq = Omit<
|
||||
ServerBindingSetAddressEnabledReq,
|
||||
'internalPort'
|
||||
> & {
|
||||
// package.host.binding.set-address-enabled
|
||||
internalPort: number
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
export type PkgBindingSetAddressEnabledRes = null
|
||||
|
||||
export type PkgAddPublicDomainReq = OsUiAddPublicDomainReq & {
|
||||
// package.host.address.domain.public.add
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
export type PkgAddPublicDomainRes = OsUiAddPublicDomainRes
|
||||
|
||||
export type PkgRemovePublicDomainReq = OsUiRemovePublicDomainReq & {
|
||||
// package.host.address.domain.public.remove
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
export type PkgRemovePublicDomainRes = OsUiRemovePublicDomainRes
|
||||
|
||||
export type PkgAddPrivateDomainReq = OsUiAddPrivateDomainReq & {
|
||||
// package.host.address.domain.private.add
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
export type PkgAddPrivateDomainRes = OsUiAddPrivateDomainRes
|
||||
|
||||
export type PkgRemovePrivateDomainReq = PkgAddPrivateDomainReq
|
||||
export type PkgRemovePrivateDomainRes = OsUiRemovePrivateDomainRes
|
||||
|
||||
export type GetPackageLogsReq = FetchLogsReq & { id: string } // package.logs
|
||||
export type GetPackageLogsRes = FetchLogsRes
|
||||
|
||||
export type FollowPackageLogsReq = FollowServerLogsReq & { id: string } // package.logs.follow
|
||||
export type FollowPackageLogsRes = FollowServerLogsRes
|
||||
|
||||
export type InstallPackageReq = T.InstallParams
|
||||
export type InstallPackageRes = null
|
||||
|
||||
export type CancelInstallPackageReq = { id: string }
|
||||
export type CancelInstallPackageRes = null
|
||||
|
||||
export type GetActionInputReq = { packageId: string; actionId: string } // package.action.get-input
|
||||
export type GetActionInputRes = {
|
||||
eventId: string
|
||||
spec: IST.InputSpec
|
||||
value: object | null
|
||||
}
|
||||
|
||||
export type ActionReq = {
|
||||
packageId: string
|
||||
eventId: string | null
|
||||
actionId: string
|
||||
input: object | null
|
||||
} // package.action.run
|
||||
export type ActionRes = (T.ActionResult & { version: '1' }) | null
|
||||
|
||||
export type ClearTaskReq = {
|
||||
packageId: string
|
||||
replayId: string
|
||||
} // package.action.clear-task
|
||||
export type ClearTaskRes = null
|
||||
|
||||
export type RestorePackagesReq = {
|
||||
// package.backup.restore
|
||||
ids: string[]
|
||||
targetId: string
|
||||
serverId: string
|
||||
password: string
|
||||
}
|
||||
export type RestorePackagesRes = null
|
||||
|
||||
export type StartPackageReq = { id: string } // package.start
|
||||
export type StartPackageRes = null
|
||||
|
||||
export type RestartPackageReq = { id: string } // package.restart
|
||||
export type RestartPackageRes = null
|
||||
|
||||
export type StopPackageReq = { id: string } // package.stop
|
||||
export type StopPackageRes = null
|
||||
|
||||
export type RebuildPackageReq = { id: string } // package.rebuild
|
||||
export type RebuildPackageRes = null
|
||||
|
||||
export type UninstallPackageReq = {
|
||||
id: string
|
||||
force: boolean
|
||||
soft: boolean
|
||||
} // package.uninstall
|
||||
export type UninstallPackageRes = null
|
||||
|
||||
export type SideloadPackageReq = {
|
||||
manifest: T.Manifest
|
||||
icon: string // base64
|
||||
}
|
||||
export type SideloadPackageRes = {
|
||||
upload: string
|
||||
progress: string // guid
|
||||
}
|
||||
|
||||
// registry
|
||||
|
||||
/** these are returned in ASCENDING order. the newest available version will be the LAST in the object */
|
||||
export type CheckOsUpdateReq = { registry: string; serverId: string }
|
||||
export type CheckOsUpdateRes = { [version: string]: T.OsVersionInfo }
|
||||
|
||||
export type GetRegistryInfoReq = { registry: string }
|
||||
export type GetRegistryInfoRes = T.RegistryInfo
|
||||
|
||||
export type GetRegistryPackageReq = GetPackageReq & { registry: string }
|
||||
export type GetRegistryPackageRes = GetPackageRes
|
||||
|
||||
export type GetRegistryPackagesReq = GetPackagesReq & { registry: string }
|
||||
export type GetRegistryPackagesRes = GetPackagesRes
|
||||
export type DiagnosticErrorRes = {
|
||||
code: number
|
||||
message: string
|
||||
data: { details: string }
|
||||
}
|
||||
|
||||
interface MetricData {
|
||||
value: string
|
||||
unit: string
|
||||
// logs
|
||||
|
||||
export type FollowServerLogsReq = Omit<T.LogsParams, 'before'>
|
||||
|
||||
// bindings
|
||||
|
||||
export type ServerBindingSetAddressEnabledReq = {
|
||||
// server.host.binding.set-address-enabled
|
||||
internalPort: 80
|
||||
address: string // JSON-serialized HostnameInfo
|
||||
enabled: boolean | null // null = reset to default
|
||||
}
|
||||
|
||||
export type ServerMetrics = {
|
||||
general: {
|
||||
temperature: MetricData | null
|
||||
}
|
||||
memory: {
|
||||
total: MetricData
|
||||
percentageUsed: MetricData
|
||||
used: MetricData
|
||||
available: MetricData
|
||||
zramTotal: MetricData
|
||||
zramUsed: MetricData
|
||||
zramAvailable: MetricData
|
||||
}
|
||||
cpu: {
|
||||
percentageUsed: MetricData
|
||||
idle: MetricData
|
||||
userSpace: MetricData
|
||||
kernelSpace: MetricData
|
||||
wait: MetricData
|
||||
}
|
||||
disk: {
|
||||
capacity: MetricData
|
||||
percentageUsed: MetricData
|
||||
used: MetricData
|
||||
available: MetricData
|
||||
}
|
||||
export type PkgBindingSetAddressEnabledReq = Omit<
|
||||
ServerBindingSetAddressEnabledReq,
|
||||
'internalPort'
|
||||
> & {
|
||||
// package.host.binding.set-address-enabled
|
||||
internalPort: number
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
|
||||
export type Session = {
|
||||
loggedIn: string
|
||||
lastActive: string
|
||||
userAgent: string
|
||||
// package domains
|
||||
|
||||
export type PkgAddPublicDomainReq = T.AddPublicDomainParams & {
|
||||
// package.host.address.domain.public.add
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
|
||||
export type BackupTarget = DiskBackupTarget | CifsBackupTarget
|
||||
|
||||
export interface DiskBackupTarget {
|
||||
type: 'disk'
|
||||
vendor: string | null
|
||||
model: string | null
|
||||
logicalname: string | null
|
||||
label: string | null
|
||||
capacity: number
|
||||
used: number | null
|
||||
startOs: Record<string, StartOSDiskInfo>
|
||||
export type PkgRemovePublicDomainReq = T.RemoveDomainParams & {
|
||||
// package.host.address.domain.public.remove
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
|
||||
export interface CifsBackupTarget {
|
||||
type: 'cifs'
|
||||
hostname: string
|
||||
path: string
|
||||
username: string
|
||||
mountable: boolean
|
||||
startOs: Record<string, StartOSDiskInfo>
|
||||
export type PkgAddPrivateDomainReq = T.AddPrivateDomainParams & {
|
||||
// package.host.address.domain.private.add
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
|
||||
export type PkgRemovePrivateDomainReq = T.RemoveDomainParams & {
|
||||
// package.host.address.domain.private.remove
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
|
||||
// package logs
|
||||
|
||||
export type GetPackageLogsReq = T.LogsParams & { id: string } // package.logs
|
||||
|
||||
export type FollowPackageLogsReq = FollowServerLogsReq & { id: string } // package.logs.follow
|
||||
|
||||
// actions
|
||||
|
||||
export type GetActionInputRes = {
|
||||
eventId: string
|
||||
spec: IST.InputSpec
|
||||
value: object | null
|
||||
}
|
||||
|
||||
export type ActionRes = (T.ActionResult & { version: '1' }) | null
|
||||
|
||||
// registry
|
||||
|
||||
export type GetRegistryPackageReq = GetPackageReq & { registry: string }
|
||||
|
||||
export type GetRegistryPackagesReq = GetPackagesReq & { registry: string }
|
||||
|
||||
// backup
|
||||
|
||||
export type DiskBackupTarget = Extract<T.BackupTarget, { type: 'disk' }>
|
||||
export type CifsBackupTarget = T.CifsBackupTarget & { type: 'cifs' }
|
||||
|
||||
export type RecoverySource = DiskRecoverySource | CifsRecoverySource
|
||||
|
||||
export interface DiskRecoverySource {
|
||||
@@ -531,74 +109,28 @@ export interface CifsRecoverySource {
|
||||
password: string
|
||||
}
|
||||
|
||||
export type BackupInfo = {
|
||||
version: string
|
||||
timestamp: string
|
||||
packageBackups: {
|
||||
[id: string]: PackageBackupInfo
|
||||
}
|
||||
}
|
||||
// notifications
|
||||
|
||||
export type PackageBackupInfo = {
|
||||
title: string
|
||||
version: string
|
||||
osVersion: string
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
export type ServerSpecs = {
|
||||
[key: string]: string | number
|
||||
}
|
||||
|
||||
export type SSHKey = {
|
||||
createdAt: string
|
||||
alg: string
|
||||
hostname: string
|
||||
fingerprint: string
|
||||
}
|
||||
|
||||
export type ServerNotifications = ServerNotification<number>[]
|
||||
|
||||
export type ServerNotification<T extends number> = {
|
||||
export type ServerNotification<N extends number> = {
|
||||
id: number
|
||||
packageId: string | null
|
||||
createdAt: string
|
||||
code: T
|
||||
level: NotificationLevel
|
||||
code: N
|
||||
level: T.NotificationLevel
|
||||
title: string
|
||||
message: string
|
||||
data: NotificationData<T>
|
||||
data: NotificationData<N>
|
||||
seen: boolean
|
||||
}
|
||||
|
||||
export type NotificationLevel = 'success' | 'info' | 'warning' | 'error'
|
||||
|
||||
export type NotificationData<T> = T extends 0
|
||||
export type NotificationData<N> = N extends 0
|
||||
? null
|
||||
: T extends 1
|
||||
? BackupReport
|
||||
: T extends 2
|
||||
: N extends 1
|
||||
? T.BackupReport
|
||||
: N extends 2
|
||||
? string
|
||||
: any
|
||||
|
||||
export type BackupReport = {
|
||||
server: {
|
||||
attempted: boolean
|
||||
error: string | null
|
||||
}
|
||||
packages: {
|
||||
[id: string]: {
|
||||
error: string | null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type AvailableWifi = {
|
||||
ssid: string
|
||||
strength: number
|
||||
security: string[]
|
||||
}
|
||||
|
||||
declare global {
|
||||
type Stringified<T> = string & {
|
||||
[P in keyof T]: T[P]
|
||||
@@ -614,10 +146,6 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
export type Encrypted = {
|
||||
encrypted: string
|
||||
}
|
||||
|
||||
// @TODO 041
|
||||
|
||||
// export namespace RR041 {
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
import { RR } from './api.types'
|
||||
import { FullKeyboard, SetLanguageParams } from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { GetPackageRes, GetPackagesRes } from '@start9labs/marketplace'
|
||||
import { Dump } from 'patch-db-client'
|
||||
import { WebSocketSubject } from 'rxjs/webSocket'
|
||||
import { DataModel } from '../patch-db/data-model'
|
||||
import {
|
||||
ActionRes,
|
||||
CifsBackupTarget,
|
||||
DiagnosticErrorRes,
|
||||
FollowPackageLogsReq,
|
||||
FollowServerLogsReq,
|
||||
GetActionInputRes,
|
||||
GetPackageLogsReq,
|
||||
GetRegistryPackageReq,
|
||||
GetRegistryPackagesReq,
|
||||
PkgAddPrivateDomainReq,
|
||||
PkgAddPublicDomainReq,
|
||||
PkgBindingSetAddressEnabledReq,
|
||||
PkgRemovePrivateDomainReq,
|
||||
PkgRemovePublicDomainReq,
|
||||
ServerBindingSetAddressEnabledReq,
|
||||
ServerState,
|
||||
WebsocketConfig,
|
||||
} from './api.types'
|
||||
|
||||
export abstract class ApiService {
|
||||
// http
|
||||
@@ -17,226 +40,206 @@ export abstract class ApiService {
|
||||
|
||||
abstract openWebsocket$<T>(
|
||||
guid: string,
|
||||
config?: RR.WebsocketConfig<T>,
|
||||
config?: WebsocketConfig<T>,
|
||||
): WebSocketSubject<T>
|
||||
|
||||
// state
|
||||
|
||||
abstract echo(params: RR.EchoReq, url: string): Promise<RR.EchoRes>
|
||||
abstract echo(params: T.EchoParams, url: string): Promise<string>
|
||||
|
||||
abstract getState(): Promise<RR.ServerState>
|
||||
abstract getState(): Promise<ServerState>
|
||||
|
||||
// db
|
||||
|
||||
abstract subscribeToPatchDB(
|
||||
params: RR.SubscribePatchReq,
|
||||
): Promise<RR.SubscribePatchRes>
|
||||
abstract subscribeToPatchDB(params: {}): Promise<{
|
||||
dump: Dump<DataModel>
|
||||
guid: string
|
||||
}>
|
||||
|
||||
abstract setDbValue<T>(
|
||||
pathArr: Array<string | number>,
|
||||
value: T,
|
||||
): Promise<RR.SetDBValueRes>
|
||||
): Promise<null>
|
||||
|
||||
// auth
|
||||
|
||||
abstract login(params: RR.LoginReq): Promise<RR.loginRes>
|
||||
abstract login(params: T.LoginParams): Promise<null>
|
||||
|
||||
abstract logout(params: RR.LogoutReq): Promise<RR.LogoutRes>
|
||||
abstract logout(params: {}): Promise<null>
|
||||
|
||||
abstract getSessions(params: RR.GetSessionsReq): Promise<RR.GetSessionsRes>
|
||||
abstract getSessions(params: {}): Promise<T.SessionList>
|
||||
|
||||
abstract killSessions(params: RR.KillSessionsReq): Promise<RR.KillSessionsRes>
|
||||
abstract killSessions(params: T.KillParams): Promise<null>
|
||||
|
||||
abstract resetPassword(
|
||||
params: RR.ResetPasswordReq,
|
||||
): Promise<RR.ResetPasswordRes>
|
||||
abstract resetPassword(params: T.ResetPasswordParams): Promise<null>
|
||||
|
||||
// diagnostic
|
||||
|
||||
abstract diagnosticGetError(): Promise<RR.DiagnosticErrorRes>
|
||||
abstract diagnosticGetError(): Promise<DiagnosticErrorRes>
|
||||
abstract diagnosticRestart(): Promise<void>
|
||||
abstract diagnosticForgetDrive(): Promise<void>
|
||||
abstract diagnosticRepairDisk(): Promise<void>
|
||||
abstract diagnosticGetLogs(
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes>
|
||||
abstract diagnosticGetLogs(params: T.LogsParams): Promise<T.LogResponse>
|
||||
|
||||
// init
|
||||
|
||||
abstract initFollowProgress(): Promise<RR.InitFollowProgressRes>
|
||||
abstract initFollowProgress(): Promise<T.SetupProgress>
|
||||
|
||||
abstract initFollowLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes>
|
||||
params: FollowServerLogsReq,
|
||||
): Promise<T.LogFollowResponse>
|
||||
|
||||
// server
|
||||
|
||||
abstract getSystemTime(
|
||||
params: RR.GetSystemTimeReq,
|
||||
): Promise<RR.GetSystemTimeRes>
|
||||
abstract getSystemTime(params: {}): Promise<T.TimeInfo>
|
||||
|
||||
abstract getServerLogs(
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes>
|
||||
abstract getServerLogs(params: T.LogsParams): Promise<T.LogResponse>
|
||||
|
||||
abstract getKernelLogs(
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes>
|
||||
abstract getKernelLogs(params: T.LogsParams): Promise<T.LogResponse>
|
||||
|
||||
abstract followServerLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes>
|
||||
params: FollowServerLogsReq,
|
||||
): Promise<T.LogFollowResponse>
|
||||
|
||||
abstract followKernelLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes>
|
||||
params: FollowServerLogsReq,
|
||||
): Promise<T.LogFollowResponse>
|
||||
|
||||
abstract followServerMetrics(
|
||||
params: RR.FollowServerMetricsReq,
|
||||
): Promise<RR.FollowServerMetricsRes>
|
||||
abstract followServerMetrics(params: {}): Promise<T.MetricsFollowResponse>
|
||||
|
||||
abstract updateServer(params: RR.UpdateServerReq): Promise<RR.UpdateServerRes>
|
||||
abstract updateServer(params: {
|
||||
registry: string
|
||||
targetVersion: string
|
||||
}): Promise<'updating' | 'no-updates'>
|
||||
|
||||
abstract restartServer(
|
||||
params: RR.RestartServerReq,
|
||||
): Promise<RR.RestartServerRes>
|
||||
abstract restartServer(params: {}): Promise<null>
|
||||
|
||||
abstract shutdownServer(
|
||||
params: RR.ShutdownServerReq,
|
||||
): Promise<RR.ShutdownServerRes>
|
||||
abstract shutdownServer(params: {}): Promise<null>
|
||||
|
||||
abstract repairDisk(params: RR.DiskRepairReq): Promise<RR.DiskRepairRes>
|
||||
abstract repairDisk(params: {}): Promise<null>
|
||||
|
||||
abstract toggleKiosk(enable: boolean): Promise<null>
|
||||
|
||||
abstract setKeyboard(params: RR.SetKeyboardReq): Promise<RR.SetKeyboardRes>
|
||||
abstract setKeyboard(params: FullKeyboard): Promise<null>
|
||||
|
||||
abstract setLanguage(params: RR.SetLanguageReq): Promise<RR.SetLanguageRes>
|
||||
abstract setLanguage(params: SetLanguageParams): Promise<null>
|
||||
|
||||
abstract setDns(params: RR.SetDnsReq): Promise<RR.SetDnsRes>
|
||||
abstract setDns(params: T.SetStaticDnsParams): Promise<null>
|
||||
|
||||
abstract queryDns(params: RR.QueryDnsReq): Promise<RR.QueryDnsRes>
|
||||
abstract queryDns(params: T.QueryDnsParams): Promise<string | null>
|
||||
|
||||
abstract testPortForward(
|
||||
params: RR.TestPortForwardReq,
|
||||
): Promise<RR.TestPortForwardRes>
|
||||
abstract testPortForward(params: {
|
||||
gateway: string
|
||||
port: number
|
||||
}): Promise<boolean>
|
||||
|
||||
// smtp
|
||||
|
||||
abstract setSmtp(params: RR.SetSMTPReq): Promise<RR.SetSMTPRes>
|
||||
abstract setSmtp(params: T.SmtpValue): Promise<null>
|
||||
|
||||
abstract clearSmtp(params: RR.ClearSMTPReq): Promise<RR.ClearSMTPRes>
|
||||
abstract clearSmtp(params: {}): Promise<null>
|
||||
|
||||
abstract testSmtp(params: RR.TestSMTPReq): Promise<RR.TestSMTPRes>
|
||||
abstract testSmtp(params: T.TestSmtpParams): Promise<null>
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
abstract checkOSUpdate(
|
||||
params: RR.CheckOsUpdateReq,
|
||||
): Promise<RR.CheckOsUpdateRes>
|
||||
abstract checkOSUpdate(params: {
|
||||
registry: string
|
||||
serverId: string
|
||||
}): Promise<T.OsVersionInfoMap>
|
||||
|
||||
abstract getRegistryInfo(
|
||||
params: RR.GetRegistryInfoReq,
|
||||
): Promise<RR.GetRegistryInfoRes>
|
||||
abstract getRegistryInfo(params: {
|
||||
registry: string
|
||||
}): Promise<T.RegistryInfo>
|
||||
|
||||
abstract getRegistryPackage(
|
||||
params: RR.GetRegistryPackageReq,
|
||||
): Promise<RR.GetRegistryPackageRes>
|
||||
params: GetRegistryPackageReq,
|
||||
): Promise<GetPackageRes>
|
||||
|
||||
abstract getRegistryPackages(
|
||||
params: RR.GetRegistryPackagesReq,
|
||||
): Promise<RR.GetRegistryPackagesRes>
|
||||
params: GetRegistryPackagesReq,
|
||||
): Promise<GetPackagesRes>
|
||||
|
||||
// notification
|
||||
|
||||
abstract getNotifications(
|
||||
params: RR.GetNotificationsReq,
|
||||
): Promise<RR.GetNotificationsRes>
|
||||
params: T.ListNotificationParams,
|
||||
): Promise<T.NotificationWithId[]>
|
||||
|
||||
abstract markSeenNotifications(
|
||||
params: RR.MarkSeenNotificationReq,
|
||||
): Promise<RR.MarkSeenNotificationRes>
|
||||
params: T.ModifyNotificationParams,
|
||||
): Promise<null>
|
||||
|
||||
abstract markSeenAllNotifications(
|
||||
params: RR.MarkSeenAllNotificationsReq,
|
||||
): Promise<RR.MarkSeenAllNotificationsRes>
|
||||
params: T.ModifyNotificationBeforeParams,
|
||||
): Promise<null>
|
||||
|
||||
abstract markUnseenNotifications(
|
||||
params: RR.DeleteNotificationsReq,
|
||||
): Promise<RR.DeleteNotificationsRes>
|
||||
params: T.ModifyNotificationParams,
|
||||
): Promise<null>
|
||||
|
||||
abstract deleteNotifications(
|
||||
params: RR.DeleteNotificationsReq,
|
||||
): Promise<RR.DeleteNotificationsRes>
|
||||
params: T.ModifyNotificationParams,
|
||||
): Promise<null>
|
||||
|
||||
// ** proxies **
|
||||
|
||||
abstract addTunnel(params: RR.AddTunnelReq): Promise<RR.AddTunnelRes>
|
||||
abstract addTunnel(params: T.AddTunnelParams): Promise<{ id: string }>
|
||||
|
||||
abstract updateTunnel(params: RR.UpdateTunnelReq): Promise<RR.UpdateTunnelRes>
|
||||
abstract updateTunnel(params: T.RenameGatewayParams): Promise<null>
|
||||
|
||||
abstract removeTunnel(params: RR.RemoveTunnelReq): Promise<RR.RemoveTunnelRes>
|
||||
abstract removeTunnel(params: T.RemoveTunnelParams): Promise<null>
|
||||
|
||||
abstract setDefaultOutbound(
|
||||
params: RR.SetDefaultOutboundReq,
|
||||
): Promise<RR.SetDefaultOutboundRes>
|
||||
abstract setDefaultOutbound(params: { gateway: string | null }): Promise<null>
|
||||
|
||||
abstract setServiceOutbound(
|
||||
params: RR.SetServiceOutboundReq,
|
||||
): Promise<RR.SetServiceOutboundRes>
|
||||
abstract setServiceOutbound(params: {
|
||||
packageId: string
|
||||
gateway: string | null
|
||||
}): Promise<null>
|
||||
|
||||
// ** domains **
|
||||
|
||||
// wifi
|
||||
|
||||
abstract enableWifi(params: RR.EnabledWifiReq): Promise<RR.EnabledWifiRes>
|
||||
abstract enableWifi(params: T.SetWifiEnabledParams): Promise<null>
|
||||
|
||||
abstract setWifiCountry(
|
||||
params: RR.SetWifiCountryReq,
|
||||
): Promise<RR.SetWifiCountryRes>
|
||||
abstract setWifiCountry(params: T.SetCountryParams): Promise<null>
|
||||
|
||||
abstract getWifi(
|
||||
params: RR.GetWifiReq,
|
||||
timeout: number,
|
||||
): Promise<RR.GetWifiRes>
|
||||
abstract getWifi(params: {}, timeout: number): Promise<T.WifiListInfo>
|
||||
|
||||
abstract addWifi(params: RR.AddWifiReq): Promise<RR.AddWifiRes>
|
||||
abstract addWifi(params: T.WifiAddParams): Promise<null>
|
||||
|
||||
abstract connectWifi(params: RR.ConnectWifiReq): Promise<RR.ConnectWifiRes>
|
||||
abstract connectWifi(params: T.WifiSsidParams): Promise<null>
|
||||
|
||||
abstract deleteWifi(params: RR.DeleteWifiReq): Promise<RR.DeleteWifiRes>
|
||||
abstract deleteWifi(params: T.WifiSsidParams): Promise<null>
|
||||
|
||||
// ssh
|
||||
|
||||
abstract getSshKeys(params: RR.GetSSHKeysReq): Promise<RR.GetSSHKeysRes>
|
||||
abstract getSshKeys(params: {}): Promise<T.SshKeyResponse[]>
|
||||
|
||||
abstract addSshKey(params: RR.AddSSHKeyReq): Promise<RR.AddSSHKeyRes>
|
||||
abstract addSshKey(params: T.SshAddParams): Promise<T.SshKeyResponse>
|
||||
|
||||
abstract deleteSshKey(params: RR.DeleteSSHKeyReq): Promise<RR.DeleteSSHKeyRes>
|
||||
abstract deleteSshKey(params: T.SshDeleteParams): Promise<null>
|
||||
|
||||
// backup
|
||||
|
||||
abstract getBackupTargets(
|
||||
params: RR.GetBackupTargetsReq,
|
||||
): Promise<RR.GetBackupTargetsRes>
|
||||
abstract getBackupTargets(params: {}): Promise<{
|
||||
[id: string]: T.BackupTarget
|
||||
}>
|
||||
|
||||
abstract addBackupTarget(
|
||||
params: RR.AddBackupTargetReq,
|
||||
): Promise<RR.AddBackupTargetRes>
|
||||
params: T.CifsAddParams,
|
||||
): Promise<{ [id: string]: CifsBackupTarget }>
|
||||
|
||||
abstract updateBackupTarget(
|
||||
params: RR.UpdateBackupTargetReq,
|
||||
): Promise<RR.UpdateBackupTargetRes>
|
||||
params: T.CifsUpdateParams,
|
||||
): Promise<{ [id: string]: CifsBackupTarget }>
|
||||
|
||||
abstract removeBackupTarget(
|
||||
params: RR.RemoveBackupTargetReq,
|
||||
): Promise<RR.RemoveBackupTargetRes>
|
||||
abstract removeBackupTarget(params: T.CifsRemoveParams): Promise<null>
|
||||
|
||||
abstract getBackupInfo(
|
||||
params: RR.GetBackupInfoReq,
|
||||
): Promise<RR.GetBackupInfoRes>
|
||||
abstract getBackupInfo(params: T.InfoParams): Promise<T.BackupInfo>
|
||||
|
||||
abstract createBackup(params: RR.CreateBackupReq): Promise<RR.CreateBackupRes>
|
||||
abstract createBackup(params: T.BackupParams): Promise<null>
|
||||
|
||||
// @TODO 041
|
||||
|
||||
@@ -288,51 +291,37 @@ export abstract class ApiService {
|
||||
|
||||
// package
|
||||
|
||||
abstract getPackageLogs(
|
||||
params: RR.GetPackageLogsReq,
|
||||
): Promise<RR.GetPackageLogsRes>
|
||||
abstract getPackageLogs(params: GetPackageLogsReq): Promise<T.LogResponse>
|
||||
|
||||
abstract followPackageLogs(
|
||||
params: RR.FollowPackageLogsReq,
|
||||
): Promise<RR.FollowPackageLogsRes>
|
||||
params: FollowPackageLogsReq,
|
||||
): Promise<T.LogFollowResponse>
|
||||
|
||||
abstract installPackage(
|
||||
params: RR.InstallPackageReq,
|
||||
): Promise<RR.InstallPackageRes>
|
||||
abstract installPackage(params: T.InstallParams): Promise<null>
|
||||
|
||||
abstract cancelInstallPackage(
|
||||
params: RR.CancelInstallPackageReq,
|
||||
): Promise<RR.CancelInstallPackageRes>
|
||||
abstract cancelInstallPackage(params: T.CancelInstallParams): Promise<null>
|
||||
|
||||
abstract getActionInput(
|
||||
params: RR.GetActionInputReq,
|
||||
): Promise<RR.GetActionInputRes>
|
||||
params: T.GetActionInputParams,
|
||||
): Promise<GetActionInputRes>
|
||||
|
||||
abstract runAction(params: RR.ActionReq): Promise<RR.ActionRes>
|
||||
abstract runAction(params: T.RunActionParams): Promise<ActionRes>
|
||||
|
||||
abstract clearTask(params: RR.ClearTaskReq): Promise<RR.ClearTaskRes>
|
||||
abstract clearTask(params: T.ClearTaskParams): Promise<null>
|
||||
|
||||
abstract restorePackages(
|
||||
params: RR.RestorePackagesReq,
|
||||
): Promise<RR.RestorePackagesRes>
|
||||
abstract restorePackages(params: T.RestorePackageParams): Promise<null>
|
||||
|
||||
abstract startPackage(params: RR.StartPackageReq): Promise<RR.StartPackageRes>
|
||||
abstract startPackage(params: T.ControlParams): Promise<null>
|
||||
|
||||
abstract restartPackage(
|
||||
params: RR.RestartPackageReq,
|
||||
): Promise<RR.RestartPackageRes>
|
||||
abstract restartPackage(params: T.ControlParams): Promise<null>
|
||||
|
||||
abstract stopPackage(params: RR.StopPackageReq): Promise<RR.StopPackageRes>
|
||||
abstract stopPackage(params: T.ControlParams): Promise<null>
|
||||
|
||||
abstract rebuildPackage(
|
||||
params: RR.RebuildPackageReq,
|
||||
): Promise<RR.RebuildPackageRes>
|
||||
abstract rebuildPackage(params: T.RebuildParams): Promise<null>
|
||||
|
||||
abstract uninstallPackage(
|
||||
params: RR.UninstallPackageReq,
|
||||
): Promise<RR.UninstallPackageRes>
|
||||
abstract uninstallPackage(params: T.UninstallParams): Promise<null>
|
||||
|
||||
abstract sideloadPackage(): Promise<RR.SideloadPackageRes>
|
||||
abstract sideloadPackage(): Promise<T.SideloadResponse>
|
||||
|
||||
// @TODO 041
|
||||
|
||||
@@ -342,47 +331,39 @@ export abstract class ApiService {
|
||||
// params: RR.SetServiceOutboundTunnelReq,
|
||||
// ): Promise<RR.SetServiceOutboundTunnelRes>
|
||||
|
||||
abstract initAcme(params: RR.InitAcmeReq): Promise<RR.InitAcmeRes>
|
||||
abstract initAcme(params: T.InitAcmeParams): Promise<null>
|
||||
|
||||
abstract removeAcme(params: RR.RemoveAcmeReq): Promise<RR.RemoveAcmeRes>
|
||||
abstract removeAcme(params: T.RemoveAcmeParams): Promise<null>
|
||||
|
||||
abstract serverBindingSetAddressEnabled(
|
||||
params: RR.ServerBindingSetAddressEnabledReq,
|
||||
): Promise<RR.ServerBindingSetAddressEnabledRes>
|
||||
params: ServerBindingSetAddressEnabledReq,
|
||||
): Promise<null>
|
||||
|
||||
abstract osUiAddPublicDomain(
|
||||
params: RR.OsUiAddPublicDomainReq,
|
||||
): Promise<RR.OsUiAddPublicDomainRes>
|
||||
params: T.AddPublicDomainParams,
|
||||
): Promise<string | null>
|
||||
|
||||
abstract osUiRemovePublicDomain(
|
||||
params: RR.OsUiRemovePublicDomainReq,
|
||||
): Promise<RR.OsUiRemovePublicDomainRes>
|
||||
abstract osUiRemovePublicDomain(params: T.RemoveDomainParams): Promise<null>
|
||||
|
||||
abstract osUiAddPrivateDomain(
|
||||
params: RR.OsUiAddPrivateDomainReq,
|
||||
): Promise<RR.OsUiAddPrivateDomainRes>
|
||||
abstract osUiAddPrivateDomain(params: T.AddPrivateDomainParams): Promise<null>
|
||||
|
||||
abstract osUiRemovePrivateDomain(
|
||||
params: RR.OsUiRemovePrivateDomainReq,
|
||||
): Promise<RR.OsUiRemovePrivateDomainRes>
|
||||
abstract osUiRemovePrivateDomain(params: T.RemoveDomainParams): Promise<null>
|
||||
|
||||
abstract pkgBindingSetAddressEnabled(
|
||||
params: RR.PkgBindingSetAddressEnabledReq,
|
||||
): Promise<RR.PkgBindingSetAddressEnabledRes>
|
||||
params: PkgBindingSetAddressEnabledReq,
|
||||
): Promise<null>
|
||||
|
||||
abstract pkgAddPublicDomain(
|
||||
params: RR.PkgAddPublicDomainReq,
|
||||
): Promise<RR.PkgAddPublicDomainRes>
|
||||
params: PkgAddPublicDomainReq,
|
||||
): Promise<string | null>
|
||||
|
||||
abstract pkgRemovePublicDomain(
|
||||
params: RR.PkgRemovePublicDomainReq,
|
||||
): Promise<RR.PkgRemovePublicDomainRes>
|
||||
params: PkgRemovePublicDomainReq,
|
||||
): Promise<null>
|
||||
|
||||
abstract pkgAddPrivateDomain(
|
||||
params: RR.PkgAddPrivateDomainReq,
|
||||
): Promise<RR.PkgAddPrivateDomainRes>
|
||||
abstract pkgAddPrivateDomain(params: PkgAddPrivateDomainReq): Promise<null>
|
||||
|
||||
abstract pkgRemovePrivateDomain(
|
||||
params: RR.PkgRemovePrivateDomainReq,
|
||||
): Promise<RR.PkgRemovePrivateDomainRes>
|
||||
params: PkgRemovePrivateDomainReq,
|
||||
): Promise<null>
|
||||
}
|
||||
|
||||
@@ -1,19 +1,41 @@
|
||||
import { DOCUMENT, Inject, Injectable } from '@angular/core'
|
||||
import { blake3 } from '@noble/hashes/blake3'
|
||||
import {
|
||||
FullKeyboard,
|
||||
HttpOptions,
|
||||
HttpService,
|
||||
isRpcError,
|
||||
RpcError,
|
||||
RPCOptions,
|
||||
SetLanguageParams,
|
||||
} from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { GetPackageRes, GetPackagesRes } from '@start9labs/marketplace'
|
||||
import { Dump, pathFromArray } from 'patch-db-client'
|
||||
import { filter, firstValueFrom, Observable } from 'rxjs'
|
||||
import { webSocket, WebSocketSubject } from 'rxjs/webSocket'
|
||||
import { PATCH_CACHE } from 'src/app/services/patch-db/patch-db-source'
|
||||
import { AuthService } from '../auth.service'
|
||||
import { DataModel } from '../patch-db/data-model'
|
||||
import { RR } from './api.types'
|
||||
import {
|
||||
ActionRes,
|
||||
CifsBackupTarget,
|
||||
DiagnosticErrorRes,
|
||||
FollowPackageLogsReq,
|
||||
FollowServerLogsReq,
|
||||
GetActionInputRes,
|
||||
GetPackageLogsReq,
|
||||
GetRegistryPackageReq,
|
||||
GetRegistryPackagesReq,
|
||||
PkgAddPrivateDomainReq,
|
||||
PkgAddPublicDomainReq,
|
||||
PkgBindingSetAddressEnabledReq,
|
||||
PkgRemovePrivateDomainReq,
|
||||
PkgRemovePublicDomainReq,
|
||||
ServerBindingSetAddressEnabledReq,
|
||||
ServerState,
|
||||
WebsocketConfig,
|
||||
} from './api.types'
|
||||
import { ApiService } from './embassy-api.service'
|
||||
|
||||
@Injectable()
|
||||
@@ -65,7 +87,7 @@ export class LiveApiService extends ApiService {
|
||||
|
||||
openWebsocket$<T>(
|
||||
guid: string,
|
||||
config: RR.WebsocketConfig<T> = {},
|
||||
config: WebsocketConfig<T> = {},
|
||||
): WebSocketSubject<T> {
|
||||
const { location } = this.document.defaultView!
|
||||
const protocol = location.protocol === 'http:' ? 'ws' : 'wss'
|
||||
@@ -79,59 +101,58 @@ export class LiveApiService extends ApiService {
|
||||
|
||||
// state
|
||||
|
||||
async echo(params: RR.EchoReq, url: string): Promise<RR.EchoRes> {
|
||||
async echo(params: T.EchoParams, url: string): Promise<string> {
|
||||
return this.rpcRequest({ method: 'echo', params }, url)
|
||||
}
|
||||
|
||||
async getState(): Promise<RR.ServerState> {
|
||||
async getState(): Promise<ServerState> {
|
||||
return this.rpcRequest({ method: 'state', params: {}, timeout: 10000 })
|
||||
}
|
||||
|
||||
// db
|
||||
|
||||
async subscribeToPatchDB(
|
||||
params: RR.SubscribePatchReq,
|
||||
): Promise<RR.SubscribePatchRes> {
|
||||
async subscribeToPatchDB(params: {}): Promise<{
|
||||
dump: Dump<DataModel>
|
||||
guid: string
|
||||
}> {
|
||||
return this.rpcRequest({ method: 'db.subscribe', params })
|
||||
}
|
||||
|
||||
async setDbValue<T>(
|
||||
pathArr: Array<string | number>,
|
||||
value: T,
|
||||
): Promise<RR.SetDBValueRes> {
|
||||
): Promise<null> {
|
||||
const pointer = pathFromArray(pathArr)
|
||||
const params: RR.SetDBValueReq<T> = { pointer, value }
|
||||
const params = { pointer, value }
|
||||
return this.rpcRequest({ method: 'db.put.ui', params })
|
||||
}
|
||||
|
||||
// auth
|
||||
|
||||
async login(params: RR.LoginReq): Promise<RR.loginRes> {
|
||||
async login(params: T.LoginParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'auth.login', params })
|
||||
}
|
||||
|
||||
async logout(params: RR.LogoutReq): Promise<RR.LogoutRes> {
|
||||
async logout(params: {}): Promise<null> {
|
||||
return this.rpcRequest({ method: 'auth.logout', params })
|
||||
}
|
||||
|
||||
async getSessions(params: RR.GetSessionsReq): Promise<RR.GetSessionsRes> {
|
||||
async getSessions(params: {}): Promise<T.SessionList> {
|
||||
return this.rpcRequest({ method: 'auth.session.list', params })
|
||||
}
|
||||
|
||||
async killSessions(params: RR.KillSessionsReq): Promise<RR.KillSessionsRes> {
|
||||
async killSessions(params: T.KillParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'auth.session.kill', params })
|
||||
}
|
||||
|
||||
async resetPassword(
|
||||
params: RR.ResetPasswordReq,
|
||||
): Promise<RR.ResetPasswordRes> {
|
||||
async resetPassword(params: T.ResetPasswordParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'auth.reset-password', params })
|
||||
}
|
||||
|
||||
// diagnostic
|
||||
|
||||
async diagnosticGetError(): Promise<RR.DiagnosticErrorRes> {
|
||||
return this.rpcRequest<RR.DiagnosticErrorRes>({
|
||||
async diagnosticGetError(): Promise<DiagnosticErrorRes> {
|
||||
return this.rpcRequest<DiagnosticErrorRes>({
|
||||
method: 'diagnostic.error',
|
||||
params: {},
|
||||
})
|
||||
@@ -158,10 +179,8 @@ export class LiveApiService extends ApiService {
|
||||
})
|
||||
}
|
||||
|
||||
async diagnosticGetLogs(
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes> {
|
||||
return this.rpcRequest<RR.GetServerLogsRes>({
|
||||
async diagnosticGetLogs(params: T.LogsParams): Promise<T.LogResponse> {
|
||||
return this.rpcRequest<T.LogResponse>({
|
||||
method: 'diagnostic.logs',
|
||||
params,
|
||||
})
|
||||
@@ -169,71 +188,62 @@ export class LiveApiService extends ApiService {
|
||||
|
||||
// init
|
||||
|
||||
async initFollowProgress(): Promise<RR.InitFollowProgressRes> {
|
||||
async initFollowProgress(): Promise<T.SetupProgress> {
|
||||
return this.rpcRequest({ method: 'init.subscribe', params: {} })
|
||||
}
|
||||
|
||||
async initFollowLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes> {
|
||||
params: FollowServerLogsReq,
|
||||
): Promise<T.LogFollowResponse> {
|
||||
return this.rpcRequest({ method: 'init.logs.follow', params })
|
||||
}
|
||||
|
||||
// server
|
||||
|
||||
async getSystemTime(
|
||||
params: RR.GetSystemTimeReq,
|
||||
): Promise<RR.GetSystemTimeRes> {
|
||||
async getSystemTime(params: {}): Promise<T.TimeInfo> {
|
||||
return this.rpcRequest({ method: 'server.time', params })
|
||||
}
|
||||
|
||||
async getServerLogs(
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes> {
|
||||
async getServerLogs(params: T.LogsParams): Promise<T.LogResponse> {
|
||||
return this.rpcRequest({ method: 'server.logs', params })
|
||||
}
|
||||
|
||||
async getKernelLogs(
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes> {
|
||||
async getKernelLogs(params: T.LogsParams): Promise<T.LogResponse> {
|
||||
return this.rpcRequest({ method: 'server.kernel-logs', params })
|
||||
}
|
||||
|
||||
async followServerLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes> {
|
||||
params: FollowServerLogsReq,
|
||||
): Promise<T.LogFollowResponse> {
|
||||
return this.rpcRequest({ method: 'server.logs.follow', params })
|
||||
}
|
||||
|
||||
async followKernelLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes> {
|
||||
params: FollowServerLogsReq,
|
||||
): Promise<T.LogFollowResponse> {
|
||||
return this.rpcRequest({ method: 'server.kernel-logs.follow', params })
|
||||
}
|
||||
|
||||
async followServerMetrics(
|
||||
params: RR.FollowServerMetricsReq,
|
||||
): Promise<RR.FollowServerMetricsRes> {
|
||||
async followServerMetrics(params: {}): Promise<T.MetricsFollowResponse> {
|
||||
return this.rpcRequest({ method: 'server.metrics.follow', params })
|
||||
}
|
||||
|
||||
async updateServer(params: RR.UpdateServerReq): Promise<RR.UpdateServerRes> {
|
||||
async updateServer(params: {
|
||||
registry: string
|
||||
targetVersion: string
|
||||
}): Promise<'updating' | 'no-updates'> {
|
||||
return this.rpcRequest({ method: 'server.update', params })
|
||||
}
|
||||
|
||||
async restartServer(
|
||||
params: RR.RestartServerReq,
|
||||
): Promise<RR.RestartServerRes> {
|
||||
async restartServer(params: {}): Promise<null> {
|
||||
return this.rpcRequest({ method: 'server.restart', params })
|
||||
}
|
||||
|
||||
async shutdownServer(
|
||||
params: RR.ShutdownServerReq,
|
||||
): Promise<RR.ShutdownServerRes> {
|
||||
async shutdownServer(params: {}): Promise<null> {
|
||||
return this.rpcRequest({ method: 'server.shutdown', params })
|
||||
}
|
||||
|
||||
async repairDisk(params: RR.RestartServerReq): Promise<RR.RestartServerRes> {
|
||||
async repairDisk(params: {}): Promise<null> {
|
||||
return this.rpcRequest({ method: 'disk.repair', params })
|
||||
}
|
||||
|
||||
@@ -244,51 +254,51 @@ export class LiveApiService extends ApiService {
|
||||
})
|
||||
}
|
||||
|
||||
async setKeyboard(params: RR.SetKeyboardReq): Promise<RR.SetKeyboardRes> {
|
||||
async setKeyboard(params: FullKeyboard): Promise<null> {
|
||||
return this.rpcRequest({ method: 'server.set-keyboard', params })
|
||||
}
|
||||
|
||||
async setLanguage(params: RR.SetLanguageReq): Promise<RR.SetLanguageRes> {
|
||||
async setLanguage(params: SetLanguageParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'server.set-language', params })
|
||||
}
|
||||
|
||||
async setDns(params: RR.SetDnsReq): Promise<RR.SetDnsRes> {
|
||||
async setDns(params: T.SetStaticDnsParams): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'net.dns.set-static',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async queryDns(params: RR.QueryDnsReq): Promise<RR.QueryDnsRes> {
|
||||
async queryDns(params: T.QueryDnsParams): Promise<string | null> {
|
||||
return this.rpcRequest({
|
||||
method: 'net.dns.query',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async testPortForward(
|
||||
params: RR.TestPortForwardReq,
|
||||
): Promise<RR.TestPortForwardRes> {
|
||||
async testPortForward(params: {
|
||||
gateway: string
|
||||
port: number
|
||||
}): Promise<boolean> {
|
||||
return this.rpcRequest({
|
||||
method: 'net.port-forward.test',
|
||||
method: 'net.gateway.check-port',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
async checkOSUpdate(
|
||||
params: RR.CheckOsUpdateReq,
|
||||
): Promise<RR.CheckOsUpdateRes> {
|
||||
async checkOSUpdate(params: {
|
||||
registry: string
|
||||
serverId: string
|
||||
}): Promise<T.OsVersionInfoMap> {
|
||||
return this.rpcRequest({
|
||||
method: 'registry.os.version.get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async getRegistryInfo(
|
||||
params: RR.GetRegistryInfoReq,
|
||||
): Promise<RR.GetRegistryInfoRes> {
|
||||
async getRegistryInfo(params: { registry: string }): Promise<T.RegistryInfo> {
|
||||
return this.rpcRequest({
|
||||
method: 'registry.info',
|
||||
params,
|
||||
@@ -296,8 +306,8 @@ export class LiveApiService extends ApiService {
|
||||
}
|
||||
|
||||
async getRegistryPackage(
|
||||
params: RR.GetRegistryPackageReq,
|
||||
): Promise<RR.GetRegistryPackageRes> {
|
||||
params: GetRegistryPackageReq,
|
||||
): Promise<GetPackageRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'registry.package.get',
|
||||
params,
|
||||
@@ -305,8 +315,8 @@ export class LiveApiService extends ApiService {
|
||||
}
|
||||
|
||||
async getRegistryPackages(
|
||||
params: RR.GetRegistryPackagesReq,
|
||||
): Promise<RR.GetRegistryPackagesRes> {
|
||||
params: GetRegistryPackagesReq,
|
||||
): Promise<GetPackagesRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'registry.package.get',
|
||||
params,
|
||||
@@ -316,26 +326,24 @@ export class LiveApiService extends ApiService {
|
||||
// notification
|
||||
|
||||
async getNotifications(
|
||||
params: RR.GetNotificationsReq,
|
||||
): Promise<RR.GetNotificationsRes> {
|
||||
params: T.ListNotificationParams,
|
||||
): Promise<T.NotificationWithId[]> {
|
||||
return this.rpcRequest({ method: 'notification.list', params })
|
||||
}
|
||||
|
||||
async deleteNotifications(
|
||||
params: RR.DeleteNotificationsReq,
|
||||
): Promise<RR.DeleteNotificationsRes> {
|
||||
async deleteNotifications(params: T.ModifyNotificationParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'notification.remove', params })
|
||||
}
|
||||
|
||||
async markSeenNotifications(
|
||||
params: RR.MarkSeenNotificationReq,
|
||||
): Promise<RR.MarkSeenNotificationRes> {
|
||||
params: T.ModifyNotificationParams,
|
||||
): Promise<null> {
|
||||
return this.rpcRequest({ method: 'notification.mark-seen', params })
|
||||
}
|
||||
|
||||
async markSeenAllNotifications(
|
||||
params: RR.MarkSeenAllNotificationsReq,
|
||||
): Promise<RR.MarkSeenAllNotificationsRes> {
|
||||
params: T.ModifyNotificationBeforeParams,
|
||||
): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'notification.mark-seen-before',
|
||||
params,
|
||||
@@ -343,133 +351,123 @@ export class LiveApiService extends ApiService {
|
||||
}
|
||||
|
||||
async markUnseenNotifications(
|
||||
params: RR.MarkUnseenNotificationReq,
|
||||
): Promise<RR.MarkUnseenNotificationRes> {
|
||||
params: T.ModifyNotificationParams,
|
||||
): Promise<null> {
|
||||
return this.rpcRequest({ method: 'notification.mark-unseen', params })
|
||||
}
|
||||
|
||||
// proxies
|
||||
|
||||
async addTunnel(params: RR.AddTunnelReq): Promise<RR.AddTunnelRes> {
|
||||
async addTunnel(params: T.AddTunnelParams): Promise<{ id: string }> {
|
||||
return this.rpcRequest({ method: 'net.tunnel.add', params })
|
||||
}
|
||||
|
||||
async updateTunnel(params: RR.UpdateTunnelReq): Promise<RR.UpdateTunnelRes> {
|
||||
async updateTunnel(params: T.RenameGatewayParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'net.gateway.set-name', params })
|
||||
}
|
||||
|
||||
async removeTunnel(params: RR.RemoveTunnelReq): Promise<RR.RemoveTunnelRes> {
|
||||
async removeTunnel(params: T.RemoveTunnelParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'net.tunnel.remove', params })
|
||||
}
|
||||
|
||||
async setDefaultOutbound(
|
||||
params: RR.SetDefaultOutboundReq,
|
||||
): Promise<RR.SetDefaultOutboundRes> {
|
||||
async setDefaultOutbound(params: { gateway: string | null }): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'net.gateway.set-default-outbound',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async setServiceOutbound(
|
||||
params: RR.SetServiceOutboundReq,
|
||||
): Promise<RR.SetServiceOutboundRes> {
|
||||
async setServiceOutbound(params: {
|
||||
packageId: string
|
||||
gateway: string | null
|
||||
}): Promise<null> {
|
||||
return this.rpcRequest({ method: 'package.set-outbound-gateway', params })
|
||||
}
|
||||
|
||||
// wifi
|
||||
|
||||
async enableWifi(params: RR.EnabledWifiReq): Promise<RR.EnabledWifiRes> {
|
||||
async enableWifi(params: T.SetWifiEnabledParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'wifi.enable', params })
|
||||
}
|
||||
|
||||
async getWifi(
|
||||
params: RR.GetWifiReq,
|
||||
timeout?: number,
|
||||
): Promise<RR.GetWifiRes> {
|
||||
async getWifi(params: {}, timeout?: number): Promise<T.WifiListInfo> {
|
||||
return this.rpcRequest({ method: 'wifi.get', params, timeout })
|
||||
}
|
||||
|
||||
async setWifiCountry(
|
||||
params: RR.SetWifiCountryReq,
|
||||
): Promise<RR.SetWifiCountryRes> {
|
||||
async setWifiCountry(params: T.SetCountryParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'wifi.country.set', params })
|
||||
}
|
||||
|
||||
async addWifi(params: RR.AddWifiReq): Promise<RR.AddWifiRes> {
|
||||
async addWifi(params: T.WifiAddParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'wifi.add', params })
|
||||
}
|
||||
|
||||
async connectWifi(params: RR.ConnectWifiReq): Promise<RR.ConnectWifiRes> {
|
||||
async connectWifi(params: T.WifiSsidParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'wifi.connect', params })
|
||||
}
|
||||
|
||||
async deleteWifi(params: RR.DeleteWifiReq): Promise<RR.DeleteWifiRes> {
|
||||
async deleteWifi(params: T.WifiSsidParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'wifi.remove', params })
|
||||
}
|
||||
|
||||
// smtp
|
||||
|
||||
async setSmtp(params: RR.SetSMTPReq): Promise<RR.SetSMTPRes> {
|
||||
async setSmtp(params: T.SmtpValue): Promise<null> {
|
||||
return this.rpcRequest({ method: 'server.set-smtp', params })
|
||||
}
|
||||
|
||||
async clearSmtp(params: RR.ClearSMTPReq): Promise<RR.ClearSMTPRes> {
|
||||
async clearSmtp(params: {}): Promise<null> {
|
||||
return this.rpcRequest({ method: 'server.clear-smtp', params })
|
||||
}
|
||||
|
||||
async testSmtp(params: RR.TestSMTPReq): Promise<RR.TestSMTPRes> {
|
||||
async testSmtp(params: T.TestSmtpParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'server.test-smtp', params })
|
||||
}
|
||||
|
||||
// ssh
|
||||
|
||||
async getSshKeys(params: RR.GetSSHKeysReq): Promise<RR.GetSSHKeysRes> {
|
||||
async getSshKeys(params: {}): Promise<T.SshKeyResponse[]> {
|
||||
return this.rpcRequest({ method: 'ssh.list', params })
|
||||
}
|
||||
|
||||
async addSshKey(params: RR.AddSSHKeyReq): Promise<RR.AddSSHKeyRes> {
|
||||
async addSshKey(params: T.SshAddParams): Promise<T.SshKeyResponse> {
|
||||
return this.rpcRequest({ method: 'ssh.add', params })
|
||||
}
|
||||
|
||||
async deleteSshKey(params: RR.DeleteSSHKeyReq): Promise<RR.DeleteSSHKeyRes> {
|
||||
async deleteSshKey(params: T.SshDeleteParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'ssh.remove', params })
|
||||
}
|
||||
|
||||
// backup
|
||||
|
||||
async getBackupTargets(
|
||||
params: RR.GetBackupTargetsReq,
|
||||
): Promise<RR.GetBackupTargetsRes> {
|
||||
async getBackupTargets(params: {}): Promise<{
|
||||
[id: string]: T.BackupTarget
|
||||
}> {
|
||||
return this.rpcRequest({ method: 'backup.target.list', params })
|
||||
}
|
||||
|
||||
async addBackupTarget(
|
||||
params: RR.AddBackupTargetReq,
|
||||
): Promise<RR.AddBackupTargetRes> {
|
||||
params: T.CifsAddParams,
|
||||
): Promise<{ [id: string]: CifsBackupTarget }> {
|
||||
params.path = params.path.replace('/\\/g', '/')
|
||||
return this.rpcRequest({ method: 'backup.target.cifs.add', params })
|
||||
}
|
||||
|
||||
async updateBackupTarget(
|
||||
params: RR.UpdateBackupTargetReq,
|
||||
): Promise<RR.UpdateBackupTargetRes> {
|
||||
params: T.CifsUpdateParams,
|
||||
): Promise<{ [id: string]: CifsBackupTarget }> {
|
||||
return this.rpcRequest({ method: 'backup.target.cifs.update', params })
|
||||
}
|
||||
|
||||
async removeBackupTarget(
|
||||
params: RR.RemoveBackupTargetReq,
|
||||
): Promise<RR.RemoveBackupTargetRes> {
|
||||
async removeBackupTarget(params: T.CifsRemoveParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'backup.target.cifs.remove', params })
|
||||
}
|
||||
|
||||
async getBackupInfo(
|
||||
params: RR.GetBackupInfoReq,
|
||||
): Promise<RR.GetBackupInfoRes> {
|
||||
async getBackupInfo(params: T.InfoParams): Promise<T.BackupInfo> {
|
||||
return this.rpcRequest({ method: 'backup.target.info', params })
|
||||
}
|
||||
|
||||
async createBackup(params: RR.CreateBackupReq): Promise<RR.CreateBackupRes> {
|
||||
async createBackup(params: T.BackupParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'backup.create', params })
|
||||
}
|
||||
|
||||
@@ -532,77 +530,63 @@ export class LiveApiService extends ApiService {
|
||||
|
||||
// package
|
||||
|
||||
async getPackageLogs(
|
||||
params: RR.GetPackageLogsReq,
|
||||
): Promise<RR.GetPackageLogsRes> {
|
||||
async getPackageLogs(params: GetPackageLogsReq): Promise<T.LogResponse> {
|
||||
return this.rpcRequest({ method: 'package.logs', params })
|
||||
}
|
||||
|
||||
async followPackageLogs(
|
||||
params: RR.FollowPackageLogsReq,
|
||||
): Promise<RR.FollowPackageLogsRes> {
|
||||
params: FollowPackageLogsReq,
|
||||
): Promise<T.LogFollowResponse> {
|
||||
return this.rpcRequest({ method: 'package.logs.follow', params })
|
||||
}
|
||||
|
||||
async installPackage(
|
||||
params: RR.InstallPackageReq,
|
||||
): Promise<RR.InstallPackageRes> {
|
||||
async installPackage(params: T.InstallParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'package.install', params })
|
||||
}
|
||||
|
||||
async cancelInstallPackage(
|
||||
params: RR.CancelInstallPackageReq,
|
||||
): Promise<RR.CancelInstallPackageRes> {
|
||||
async cancelInstallPackage(params: T.CancelInstallParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'package.cancel-install', params })
|
||||
}
|
||||
|
||||
async getActionInput(
|
||||
params: RR.GetActionInputReq,
|
||||
): Promise<RR.GetActionInputRes> {
|
||||
params: T.GetActionInputParams,
|
||||
): Promise<GetActionInputRes> {
|
||||
return this.rpcRequest({ method: 'package.action.get-input', params })
|
||||
}
|
||||
|
||||
async runAction(params: RR.ActionReq): Promise<RR.ActionRes> {
|
||||
async runAction(params: T.RunActionParams): Promise<ActionRes> {
|
||||
return this.rpcRequest({ method: 'package.action.run', params })
|
||||
}
|
||||
|
||||
async clearTask(params: RR.ClearTaskReq): Promise<RR.ClearTaskRes> {
|
||||
async clearTask(params: T.ClearTaskParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'package.action.clear-task', params })
|
||||
}
|
||||
|
||||
async restorePackages(
|
||||
params: RR.RestorePackagesReq,
|
||||
): Promise<RR.RestorePackagesRes> {
|
||||
async restorePackages(params: T.RestorePackageParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'package.backup.restore', params })
|
||||
}
|
||||
|
||||
async startPackage(params: RR.StartPackageReq): Promise<RR.StartPackageRes> {
|
||||
async startPackage(params: T.ControlParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'package.start', params })
|
||||
}
|
||||
|
||||
async restartPackage(
|
||||
params: RR.RestartPackageReq,
|
||||
): Promise<RR.RestartPackageRes> {
|
||||
async restartPackage(params: T.ControlParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'package.restart', params })
|
||||
}
|
||||
|
||||
async stopPackage(params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
||||
async stopPackage(params: T.ControlParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'package.stop', params })
|
||||
}
|
||||
|
||||
async rebuildPackage(
|
||||
params: RR.RebuildPackageReq,
|
||||
): Promise<RR.RebuildPackageRes> {
|
||||
async rebuildPackage(params: T.RebuildParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'package.rebuild', params })
|
||||
}
|
||||
|
||||
async uninstallPackage(
|
||||
params: RR.UninstallPackageReq,
|
||||
): Promise<RR.UninstallPackageRes> {
|
||||
async uninstallPackage(params: T.UninstallParams): Promise<null> {
|
||||
return this.rpcRequest({ method: 'package.uninstall', params })
|
||||
}
|
||||
|
||||
async sideloadPackage(): Promise<RR.SideloadPackageRes> {
|
||||
async sideloadPackage(): Promise<T.SideloadResponse> {
|
||||
return this.rpcRequest({
|
||||
method: 'package.sideload',
|
||||
params: {},
|
||||
@@ -615,14 +599,14 @@ export class LiveApiService extends ApiService {
|
||||
// return this.rpcRequest({ method: 'package.proxy.set-outbound', params })
|
||||
// }
|
||||
|
||||
async removeAcme(params: RR.RemoveAcmeReq): Promise<RR.RemoveAcmeRes> {
|
||||
async removeAcme(params: T.RemoveAcmeParams): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'net.acme.remove',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async initAcme(params: RR.InitAcmeReq): Promise<RR.InitAcmeRes> {
|
||||
async initAcme(params: T.InitAcmeParams): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'net.acme.init',
|
||||
params,
|
||||
@@ -630,8 +614,8 @@ export class LiveApiService extends ApiService {
|
||||
}
|
||||
|
||||
async serverBindingSetAddressEnabled(
|
||||
params: RR.ServerBindingSetAddressEnabledReq,
|
||||
): Promise<RR.ServerBindingSetAddressEnabledRes> {
|
||||
params: ServerBindingSetAddressEnabledReq,
|
||||
): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'server.host.binding.set-address-enabled',
|
||||
params,
|
||||
@@ -639,35 +623,29 @@ export class LiveApiService extends ApiService {
|
||||
}
|
||||
|
||||
async osUiAddPublicDomain(
|
||||
params: RR.OsUiAddPublicDomainReq,
|
||||
): Promise<RR.OsUiAddPublicDomainRes> {
|
||||
params: T.AddPublicDomainParams,
|
||||
): Promise<string | null> {
|
||||
return this.rpcRequest({
|
||||
method: 'server.host.address.domain.public.add',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async osUiRemovePublicDomain(
|
||||
params: RR.OsUiRemovePublicDomainReq,
|
||||
): Promise<RR.OsUiRemovePublicDomainRes> {
|
||||
async osUiRemovePublicDomain(params: T.RemoveDomainParams): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'server.host.address.domain.public.remove',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async osUiAddPrivateDomain(
|
||||
params: RR.OsUiAddPrivateDomainReq,
|
||||
): Promise<RR.OsUiAddPrivateDomainRes> {
|
||||
async osUiAddPrivateDomain(params: T.AddPrivateDomainParams): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'server.host.address.domain.private.add',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async osUiRemovePrivateDomain(
|
||||
params: RR.OsUiRemovePrivateDomainReq,
|
||||
): Promise<RR.OsUiRemovePrivateDomainRes> {
|
||||
async osUiRemovePrivateDomain(params: T.RemoveDomainParams): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'server.host.address.domain.private.remove',
|
||||
params,
|
||||
@@ -675,8 +653,8 @@ export class LiveApiService extends ApiService {
|
||||
}
|
||||
|
||||
async pkgBindingSetAddressEnabled(
|
||||
params: RR.PkgBindingSetAddressEnabledReq,
|
||||
): Promise<RR.PkgBindingSetAddressEnabledRes> {
|
||||
params: PkgBindingSetAddressEnabledReq,
|
||||
): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'package.host.binding.set-address-enabled',
|
||||
params,
|
||||
@@ -684,26 +662,22 @@ export class LiveApiService extends ApiService {
|
||||
}
|
||||
|
||||
async pkgAddPublicDomain(
|
||||
params: RR.PkgAddPublicDomainReq,
|
||||
): Promise<RR.PkgAddPublicDomainRes> {
|
||||
params: PkgAddPublicDomainReq,
|
||||
): Promise<string | null> {
|
||||
return this.rpcRequest({
|
||||
method: 'package.host.address.domain.public.add',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async pkgRemovePublicDomain(
|
||||
params: RR.PkgRemovePublicDomainReq,
|
||||
): Promise<RR.PkgRemovePublicDomainRes> {
|
||||
async pkgRemovePublicDomain(params: PkgRemovePublicDomainReq): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'package.host.address.domain.public.remove',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async pkgAddPrivateDomain(
|
||||
params: RR.PkgAddPrivateDomainReq,
|
||||
): Promise<RR.PkgAddPrivateDomainRes> {
|
||||
async pkgAddPrivateDomain(params: PkgAddPrivateDomainReq): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'package.host.address.domain.private.add',
|
||||
params,
|
||||
@@ -711,8 +685,8 @@ export class LiveApiService extends ApiService {
|
||||
}
|
||||
|
||||
async pkgRemovePrivateDomain(
|
||||
params: RR.PkgRemovePrivateDomainReq,
|
||||
): Promise<RR.PkgRemovePrivateDomainRes> {
|
||||
params: PkgRemovePrivateDomainReq,
|
||||
): Promise<null> {
|
||||
return this.rpcRequest({
|
||||
method: 'package.host.address.domain.private.remove',
|
||||
params,
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { pauseFor, Log, RPCErrorDetails } from '@start9labs/shared'
|
||||
import {
|
||||
FullKeyboard,
|
||||
pauseFor,
|
||||
RPCErrorDetails,
|
||||
SetLanguageParams,
|
||||
} from '@start9labs/shared'
|
||||
import { ApiService } from './embassy-api.service'
|
||||
import {
|
||||
AddOperation,
|
||||
Dump,
|
||||
Operation,
|
||||
PatchOp,
|
||||
pathFromArray,
|
||||
@@ -11,12 +17,32 @@ import {
|
||||
Revision,
|
||||
} from 'patch-db-client'
|
||||
import {
|
||||
DataModel,
|
||||
InstallingState,
|
||||
PackageDataEntry,
|
||||
StateInfo,
|
||||
UpdatingState,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { CifsBackupTarget, RR } from './api.types'
|
||||
import { GetPackageRes, GetPackagesRes } from '@start9labs/marketplace'
|
||||
import {
|
||||
ActionRes,
|
||||
CifsBackupTarget,
|
||||
DiagnosticErrorRes,
|
||||
FollowPackageLogsReq,
|
||||
FollowServerLogsReq,
|
||||
GetActionInputRes,
|
||||
GetPackageLogsReq,
|
||||
GetRegistryPackageReq,
|
||||
GetRegistryPackagesReq,
|
||||
PkgAddPrivateDomainReq,
|
||||
PkgAddPublicDomainReq,
|
||||
PkgBindingSetAddressEnabledReq,
|
||||
PkgRemovePrivateDomainReq,
|
||||
PkgRemovePublicDomainReq,
|
||||
ServerBindingSetAddressEnabledReq,
|
||||
ServerState,
|
||||
WebsocketConfig,
|
||||
} from './api.types'
|
||||
import { Mock } from './api.fixures'
|
||||
import { from, interval, map, shareReplay, startWith, Subject, tap } from 'rxjs'
|
||||
import { mockPatchData } from './mock-patch'
|
||||
@@ -86,7 +112,7 @@ export class MockApiService extends ApiService {
|
||||
|
||||
openWebsocket$<T>(
|
||||
guid: string,
|
||||
config: RR.WebsocketConfig<T> = {},
|
||||
config: WebsocketConfig<T> = {},
|
||||
): WebSocketSubject<T> {
|
||||
if (guid === 'db-guid') {
|
||||
return this.mockWsSource$.pipe<any>(
|
||||
@@ -121,7 +147,7 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// state
|
||||
|
||||
async echo(params: RR.EchoReq, url: string): Promise<RR.EchoRes> {
|
||||
async echo(params: T.EchoParams, url: string): Promise<string> {
|
||||
if (url) {
|
||||
const num = Math.floor(Math.random() * 10) + 1
|
||||
if (num > 8) return params.message
|
||||
@@ -132,7 +158,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
private stateIndex = 0
|
||||
async getState(): Promise<RR.ServerState> {
|
||||
async getState(): Promise<ServerState> {
|
||||
await pauseFor(1000)
|
||||
|
||||
this.stateIndex++
|
||||
@@ -142,9 +168,10 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// db
|
||||
|
||||
async subscribeToPatchDB(
|
||||
params: RR.SubscribePatchReq,
|
||||
): Promise<RR.SubscribePatchRes> {
|
||||
async subscribeToPatchDB(params: {}): Promise<{
|
||||
dump: Dump<DataModel>
|
||||
guid: string
|
||||
}> {
|
||||
await pauseFor(2000)
|
||||
return {
|
||||
dump: { id: 1, value: mockPatchData },
|
||||
@@ -155,9 +182,9 @@ export class MockApiService extends ApiService {
|
||||
async setDbValue<T>(
|
||||
pathArr: Array<string | number>,
|
||||
value: T,
|
||||
): Promise<RR.SetDBValueRes> {
|
||||
): Promise<null> {
|
||||
const pointer = pathFromArray(pathArr)
|
||||
const params: RR.SetDBValueReq<T> = { pointer, value }
|
||||
const params = { pointer, value }
|
||||
await pauseFor(2000)
|
||||
const patch = [
|
||||
{
|
||||
@@ -173,29 +200,27 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// auth
|
||||
|
||||
async login(params: RR.LoginReq): Promise<RR.loginRes> {
|
||||
async login(params: T.LoginParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async logout(params: RR.LogoutReq): Promise<RR.LogoutRes> {
|
||||
async logout(params: {}): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async getSessions(params: RR.GetSessionsReq): Promise<RR.GetSessionsRes> {
|
||||
async getSessions(params: {}): Promise<T.SessionList> {
|
||||
await pauseFor(2000)
|
||||
return Mock.Sessions
|
||||
}
|
||||
|
||||
async killSessions(params: RR.KillSessionsReq): Promise<RR.KillSessionsRes> {
|
||||
async killSessions(params: T.KillParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async resetPassword(
|
||||
params: RR.ResetPasswordReq,
|
||||
): Promise<RR.ResetPasswordRes> {
|
||||
async resetPassword(params: T.ResetPasswordParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
@@ -211,7 +236,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async diagnosticGetError(): Promise<RR.DiagnosticErrorRes> {
|
||||
async diagnosticGetError(): Promise<DiagnosticErrorRes> {
|
||||
await pauseFor(1000)
|
||||
return {
|
||||
code: 15,
|
||||
@@ -232,15 +257,13 @@ export class MockApiService extends ApiService {
|
||||
await pauseFor(1000)
|
||||
}
|
||||
|
||||
async diagnosticGetLogs(
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes> {
|
||||
async diagnosticGetLogs(params: T.LogsParams): Promise<T.LogResponse> {
|
||||
return this.getServerLogs(params)
|
||||
}
|
||||
|
||||
// init
|
||||
|
||||
async initFollowProgress(): Promise<RR.InitFollowProgressRes> {
|
||||
async initFollowProgress(): Promise<T.SetupProgress> {
|
||||
await pauseFor(250)
|
||||
return {
|
||||
progress: PROGRESS,
|
||||
@@ -248,7 +271,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async initFollowLogs(): Promise<RR.FollowServerLogsRes> {
|
||||
async initFollowLogs(): Promise<T.LogFollowResponse> {
|
||||
await pauseFor(2000)
|
||||
return {
|
||||
startCursor: 'start-cursor',
|
||||
@@ -258,19 +281,15 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// server
|
||||
|
||||
async getSystemTime(
|
||||
params: RR.GetSystemTimeReq,
|
||||
): Promise<RR.GetSystemTimeRes> {
|
||||
async getSystemTime(params: {}): Promise<T.TimeInfo> {
|
||||
await pauseFor(2000)
|
||||
return {
|
||||
now: new Date().toUTCString(),
|
||||
uptime: 1234567,
|
||||
uptime: 1234567n,
|
||||
}
|
||||
}
|
||||
|
||||
async getServerLogs(
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes> {
|
||||
async getServerLogs(params: T.LogsParams): Promise<T.LogResponse> {
|
||||
await pauseFor(2000)
|
||||
const entries = this.randomLogs(params.limit)
|
||||
|
||||
@@ -281,9 +300,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async getKernelLogs(
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes> {
|
||||
async getKernelLogs(params: T.LogsParams): Promise<T.LogResponse> {
|
||||
await pauseFor(2000)
|
||||
const entries = this.randomLogs(params.limit)
|
||||
|
||||
@@ -295,8 +312,8 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
async followServerLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes> {
|
||||
params: FollowServerLogsReq,
|
||||
): Promise<T.LogFollowResponse> {
|
||||
await pauseFor(2000)
|
||||
return {
|
||||
startCursor: 'start-cursor',
|
||||
@@ -305,8 +322,8 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
async followKernelLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes> {
|
||||
params: FollowServerLogsReq,
|
||||
): Promise<T.LogFollowResponse> {
|
||||
await pauseFor(2000)
|
||||
return {
|
||||
startCursor: 'start-cursor',
|
||||
@@ -314,7 +331,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
private randomLogs(limit = 1): Log[] {
|
||||
private randomLogs(limit = 1): T.LogEntry[] {
|
||||
const arrLength = Math.ceil(limit / Mock.ServerLogs.length)
|
||||
const logs = new Array(arrLength)
|
||||
.fill(Mock.ServerLogs)
|
||||
@@ -323,9 +340,7 @@ export class MockApiService extends ApiService {
|
||||
return logs
|
||||
}
|
||||
|
||||
async followServerMetrics(
|
||||
params: RR.FollowServerMetricsReq,
|
||||
): Promise<RR.FollowServerMetricsRes> {
|
||||
async followServerMetrics(params: {}): Promise<T.MetricsFollowResponse> {
|
||||
await pauseFor(2000)
|
||||
return {
|
||||
guid: 'metrics-guid',
|
||||
@@ -333,7 +348,10 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async updateServer(params?: RR.UpdateServerReq): Promise<RR.UpdateServerRes> {
|
||||
async updateServer(params?: {
|
||||
registry: string
|
||||
targetVersion: string
|
||||
}): Promise<'updating' | 'no-updates'> {
|
||||
await pauseFor(2000)
|
||||
const initialProgress = {
|
||||
size: null,
|
||||
@@ -356,9 +374,7 @@ export class MockApiService extends ApiService {
|
||||
return 'updating'
|
||||
}
|
||||
|
||||
async restartServer(
|
||||
params: RR.RestartServerReq,
|
||||
): Promise<RR.RestartServerRes> {
|
||||
async restartServer(params: {}): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch = [
|
||||
@@ -384,9 +400,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async shutdownServer(
|
||||
params: RR.ShutdownServerReq,
|
||||
): Promise<RR.ShutdownServerRes> {
|
||||
async shutdownServer(params: {}): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch = [
|
||||
@@ -412,7 +426,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async repairDisk(params: RR.RestartServerReq): Promise<RR.RestartServerRes> {
|
||||
async repairDisk(params: {}): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
@@ -432,7 +446,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async setKeyboard(params: RR.SetKeyboardReq): Promise<RR.SetKeyboardRes> {
|
||||
async setKeyboard(params: FullKeyboard): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
|
||||
const patch = [
|
||||
@@ -447,7 +461,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async setLanguage(params: RR.SetLanguageReq): Promise<RR.SetLanguageRes> {
|
||||
async setLanguage(params: SetLanguageParams): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
|
||||
const patch = [
|
||||
@@ -462,7 +476,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async setDns(params: RR.SetDnsReq): Promise<RR.SetDnsRes> {
|
||||
async setDns(params: T.SetStaticDnsParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: ReplaceOperation<T.DnsSettings['staticServers']>[] = [
|
||||
@@ -477,15 +491,16 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async queryDns(params: RR.QueryDnsReq): Promise<RR.QueryDnsRes> {
|
||||
async queryDns(params: T.QueryDnsParams): Promise<string | null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async testPortForward(
|
||||
params: RR.TestPortForwardReq,
|
||||
): Promise<RR.TestPortForwardRes> {
|
||||
async testPortForward(params: {
|
||||
gateway: string
|
||||
port: number
|
||||
}): Promise<boolean> {
|
||||
await pauseFor(2000)
|
||||
|
||||
return false
|
||||
@@ -493,23 +508,22 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
async checkOSUpdate(
|
||||
params: RR.CheckOsUpdateReq,
|
||||
): Promise<RR.CheckOsUpdateRes> {
|
||||
async checkOSUpdate(params: {
|
||||
registry: string
|
||||
serverId: string
|
||||
}): Promise<T.OsVersionInfoMap> {
|
||||
await pauseFor(2000)
|
||||
return Mock.RegistryOSUpdate
|
||||
}
|
||||
|
||||
async getRegistryInfo(
|
||||
params: RR.GetRegistryInfoReq,
|
||||
): Promise<RR.GetRegistryInfoRes> {
|
||||
async getRegistryInfo(params: { registry: string }): Promise<T.RegistryInfo> {
|
||||
await pauseFor(2000)
|
||||
return Mock.RegistryInfo
|
||||
}
|
||||
|
||||
async getRegistryPackage(
|
||||
params: RR.GetRegistryPackageReq,
|
||||
): Promise<RR.GetRegistryPackageRes> {
|
||||
params: GetRegistryPackageReq,
|
||||
): Promise<GetPackageRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const { targetVersion, id } = params
|
||||
@@ -522,8 +536,8 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
async getRegistryPackages(
|
||||
params: RR.GetRegistryPackagesReq,
|
||||
): Promise<RR.GetRegistryPackagesRes> {
|
||||
params: GetRegistryPackagesReq,
|
||||
): Promise<GetPackagesRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.RegistryPackages
|
||||
}
|
||||
@@ -531,37 +545,35 @@ export class MockApiService extends ApiService {
|
||||
// notification
|
||||
|
||||
async getNotifications(
|
||||
params: RR.GetNotificationsReq,
|
||||
): Promise<RR.GetNotificationsRes> {
|
||||
params: T.ListNotificationParams,
|
||||
): Promise<T.NotificationWithId[]> {
|
||||
await pauseFor(2000)
|
||||
|
||||
return Mock.Notifications
|
||||
}
|
||||
|
||||
async deleteNotifications(
|
||||
params: RR.DeleteNotificationsReq,
|
||||
): Promise<RR.DeleteNotificationsRes> {
|
||||
async deleteNotifications(params: T.ModifyNotificationParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async markSeenNotifications(
|
||||
params: RR.MarkSeenNotificationReq,
|
||||
): Promise<RR.MarkSeenNotificationRes> {
|
||||
params: T.ModifyNotificationParams,
|
||||
): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async markSeenAllNotifications(
|
||||
params: RR.MarkSeenAllNotificationsReq,
|
||||
): Promise<RR.MarkSeenAllNotificationsRes> {
|
||||
params: T.ModifyNotificationBeforeParams,
|
||||
): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async markUnseenNotifications(
|
||||
params: RR.MarkUnseenNotificationReq,
|
||||
): Promise<RR.MarkUnseenNotificationRes> {
|
||||
params: T.ModifyNotificationParams,
|
||||
): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
@@ -569,7 +581,7 @@ export class MockApiService extends ApiService {
|
||||
// proxies
|
||||
|
||||
private proxyId = 0
|
||||
async addTunnel(params: RR.AddTunnelReq): Promise<RR.AddTunnelRes> {
|
||||
async addTunnel(params: T.AddTunnelParams): Promise<{ id: string }> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const id = `wg${this.proxyId++}`
|
||||
@@ -609,7 +621,7 @@ export class MockApiService extends ApiService {
|
||||
return { id }
|
||||
}
|
||||
|
||||
async updateTunnel(params: RR.UpdateTunnelReq): Promise<RR.UpdateTunnelRes> {
|
||||
async updateTunnel(params: T.RenameGatewayParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: ReplaceOperation<string>[] = [
|
||||
@@ -624,7 +636,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async removeTunnel(params: RR.RemoveTunnelReq): Promise<RR.RemoveTunnelRes> {
|
||||
async removeTunnel(params: T.RemoveTunnelParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
const patch: RemoveOperation[] = [
|
||||
{
|
||||
@@ -637,9 +649,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async setDefaultOutbound(
|
||||
params: RR.SetDefaultOutboundReq,
|
||||
): Promise<RR.SetDefaultOutboundRes> {
|
||||
async setDefaultOutbound(params: { gateway: string | null }): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
const patch = [
|
||||
{
|
||||
@@ -653,9 +663,10 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async setServiceOutbound(
|
||||
params: RR.SetServiceOutboundReq,
|
||||
): Promise<RR.SetServiceOutboundRes> {
|
||||
async setServiceOutbound(params: {
|
||||
packageId: string
|
||||
gateway: string | null
|
||||
}): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
const patch = [
|
||||
{
|
||||
@@ -671,13 +682,13 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// wifi
|
||||
|
||||
async enableWifi(params: RR.EnabledWifiReq): Promise<RR.EnabledWifiRes> {
|
||||
async enableWifi(params: T.SetWifiEnabledParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
const patch = [
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: '/serverInfo/network/wifi/enabled',
|
||||
value: params.enable,
|
||||
value: params.enabled,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
@@ -685,36 +696,34 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async setWifiCountry(
|
||||
params: RR.SetWifiCountryReq,
|
||||
): Promise<RR.SetWifiCountryRes> {
|
||||
async setWifiCountry(params: T.SetCountryParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async getWifi(params: RR.GetWifiReq): Promise<RR.GetWifiRes> {
|
||||
async getWifi(params: {}, timeout: number): Promise<T.WifiListInfo> {
|
||||
await pauseFor(2000)
|
||||
return Mock.Wifi
|
||||
}
|
||||
|
||||
async addWifi(params: RR.AddWifiReq): Promise<RR.AddWifiRes> {
|
||||
async addWifi(params: T.WifiAddParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async connectWifi(params: RR.ConnectWifiReq): Promise<RR.ConnectWifiRes> {
|
||||
async connectWifi(params: T.WifiSsidParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async deleteWifi(params: RR.DeleteWifiReq): Promise<RR.DeleteWifiRes> {
|
||||
async deleteWifi(params: T.WifiSsidParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
// smtp
|
||||
|
||||
async setSmtp(params: RR.SetSMTPReq): Promise<RR.SetSMTPRes> {
|
||||
async setSmtp(params: T.SmtpValue): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
const patch = [
|
||||
{
|
||||
@@ -728,7 +737,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async clearSmtp(params: RR.ClearSMTPReq): Promise<RR.ClearSMTPRes> {
|
||||
async clearSmtp(params: {}): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
const patch = [
|
||||
{
|
||||
@@ -742,40 +751,40 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async testSmtp(params: RR.TestSMTPReq): Promise<RR.TestSMTPRes> {
|
||||
async testSmtp(params: T.TestSmtpParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
// ssh
|
||||
|
||||
async getSshKeys(params: RR.GetSSHKeysReq): Promise<RR.GetSSHKeysRes> {
|
||||
async getSshKeys(params: {}): Promise<T.SshKeyResponse[]> {
|
||||
await pauseFor(2000)
|
||||
return Mock.SshKeys
|
||||
}
|
||||
|
||||
async addSshKey(params: RR.AddSSHKeyReq): Promise<RR.AddSSHKeyRes> {
|
||||
async addSshKey(params: T.SshAddParams): Promise<T.SshKeyResponse> {
|
||||
await pauseFor(2000)
|
||||
return Mock.SshKey
|
||||
}
|
||||
|
||||
async deleteSshKey(params: RR.DeleteSSHKeyReq): Promise<RR.DeleteSSHKeyRes> {
|
||||
async deleteSshKey(params: T.SshDeleteParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
// backup
|
||||
|
||||
async getBackupTargets(
|
||||
params: RR.GetBackupTargetsReq,
|
||||
): Promise<RR.GetBackupTargetsRes> {
|
||||
async getBackupTargets(params: {}): Promise<{
|
||||
[id: string]: T.BackupTarget
|
||||
}> {
|
||||
await pauseFor(2000)
|
||||
return Mock.BackupTargets
|
||||
}
|
||||
|
||||
async addBackupTarget(
|
||||
params: RR.AddBackupTargetReq,
|
||||
): Promise<RR.AddBackupTargetRes> {
|
||||
params: T.CifsAddParams,
|
||||
): Promise<{ [id: string]: CifsBackupTarget }> {
|
||||
await pauseFor(2000)
|
||||
const { hostname, path, username } = params
|
||||
return {
|
||||
@@ -791,8 +800,8 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
async updateBackupTarget(
|
||||
params: RR.UpdateBackupTargetReq,
|
||||
): Promise<RR.UpdateBackupTargetRes> {
|
||||
params: T.CifsUpdateParams,
|
||||
): Promise<{ [id: string]: CifsBackupTarget }> {
|
||||
await pauseFor(2000)
|
||||
const { id, hostname, path, username } = params
|
||||
return {
|
||||
@@ -805,24 +814,20 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async removeBackupTarget(
|
||||
params: RR.RemoveBackupTargetReq,
|
||||
): Promise<RR.RemoveBackupTargetRes> {
|
||||
async removeBackupTarget(params: T.CifsRemoveParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async getBackupInfo(
|
||||
params: RR.GetBackupInfoReq,
|
||||
): Promise<RR.GetBackupInfoRes> {
|
||||
async getBackupInfo(params: T.InfoParams): Promise<T.BackupInfo> {
|
||||
await pauseFor(2000)
|
||||
return Mock.BackupInfo
|
||||
}
|
||||
|
||||
async createBackup(params: RR.CreateBackupReq): Promise<RR.CreateBackupRes> {
|
||||
async createBackup(params: T.BackupParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
const serverPath = '/serverInfo/statusInfo/backupProgress'
|
||||
const ids = params.packageIds
|
||||
const ids = params.packageIds || []
|
||||
|
||||
setTimeout(async () => {
|
||||
for (let i = 0; i < ids.length; i++) {
|
||||
@@ -978,9 +983,7 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// package
|
||||
|
||||
async getPackageLogs(
|
||||
params: RR.GetPackageLogsReq,
|
||||
): Promise<RR.GetPackageLogsRes> {
|
||||
async getPackageLogs(params: GetPackageLogsReq): Promise<T.LogResponse> {
|
||||
await pauseFor(2000)
|
||||
let entries
|
||||
if (Math.random() < 0.2) {
|
||||
@@ -1001,8 +1004,8 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
async followPackageLogs(
|
||||
params: RR.FollowPackageLogsReq,
|
||||
): Promise<RR.FollowPackageLogsRes> {
|
||||
params: FollowPackageLogsReq,
|
||||
): Promise<T.LogFollowResponse> {
|
||||
await pauseFor(2000)
|
||||
return {
|
||||
startCursor: 'start-cursor',
|
||||
@@ -1010,9 +1013,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async installPackage(
|
||||
params: RR.InstallPackageReq,
|
||||
): Promise<RR.InstallPackageRes> {
|
||||
async installPackage(params: T.InstallParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
setTimeout(async () => {
|
||||
@@ -1049,9 +1050,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async cancelInstallPackage(
|
||||
params: RR.CancelInstallPackageReq,
|
||||
): Promise<RR.CancelInstallPackageRes> {
|
||||
async cancelInstallPackage(params: T.CancelInstallParams): Promise<null> {
|
||||
await pauseFor(500)
|
||||
|
||||
const patch: RemoveOperation[] = [
|
||||
@@ -1066,8 +1065,8 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
async getActionInput(
|
||||
params: RR.GetActionInputReq,
|
||||
): Promise<RR.GetActionInputRes> {
|
||||
params: T.GetActionInputParams,
|
||||
): Promise<GetActionInputRes> {
|
||||
await pauseFor(2000)
|
||||
return {
|
||||
eventId: 'ANZXNWIFRTTBZ6T52KQPZILIQQODDHXQ',
|
||||
@@ -1076,7 +1075,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async runAction(params: RR.ActionReq): Promise<RR.ActionRes> {
|
||||
async runAction(params: T.RunActionParams): Promise<ActionRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: ReplaceOperation<{ [key: string]: T.TaskEntry }>[] = [
|
||||
@@ -1093,7 +1092,7 @@ export class MockApiService extends ApiService {
|
||||
// return Mock.ActionResSingle
|
||||
}
|
||||
|
||||
async clearTask(params: RR.ClearTaskReq): Promise<RR.ClearTaskRes> {
|
||||
async clearTask(params: T.ClearTaskParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: RemoveOperation[] = [
|
||||
@@ -1107,9 +1106,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async restorePackages(
|
||||
params: RR.RestorePackagesReq,
|
||||
): Promise<RR.RestorePackagesRes> {
|
||||
async restorePackages(params: T.RestorePackageParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
const patch: AddOperation<PackageDataEntry>[] = params.ids.map(id => {
|
||||
setTimeout(async () => {
|
||||
@@ -1137,7 +1134,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async startPackage(params: RR.StartPackageReq): Promise<RR.StartPackageRes> {
|
||||
async startPackage(params: T.ControlParams): Promise<null> {
|
||||
const path = `/packageData/${params.id}/statusInfo`
|
||||
|
||||
await pauseFor(2000)
|
||||
@@ -1202,9 +1199,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async restartPackage(
|
||||
params: RR.RestartPackageReq,
|
||||
): Promise<RR.RestartPackageRes> {
|
||||
async restartPackage(params: T.ControlParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
const path = `/packageData/${params.id}/statusInfo`
|
||||
|
||||
@@ -1268,7 +1263,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async stopPackage(params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
||||
async stopPackage(params: T.ControlParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
const path = `/packageData/${params.id}/statusInfo`
|
||||
|
||||
@@ -1306,15 +1301,11 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async rebuildPackage(
|
||||
params: RR.RebuildPackageReq,
|
||||
): Promise<RR.RebuildPackageRes> {
|
||||
async rebuildPackage(params: T.RebuildParams): Promise<null> {
|
||||
return this.restartPackage(params)
|
||||
}
|
||||
|
||||
async uninstallPackage(
|
||||
params: RR.UninstallPackageReq,
|
||||
): Promise<RR.UninstallPackageRes> {
|
||||
async uninstallPackage(params: T.UninstallParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
setTimeout(async () => {
|
||||
@@ -1340,7 +1331,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async sideloadPackage(): Promise<RR.SideloadPackageRes> {
|
||||
async sideloadPackage(): Promise<T.SideloadResponse> {
|
||||
await pauseFor(2000)
|
||||
return {
|
||||
upload: 'sideload-upload-guid', // no significance, randomly generated
|
||||
@@ -1364,7 +1355,7 @@ export class MockApiService extends ApiService {
|
||||
// return null
|
||||
// }
|
||||
|
||||
async initAcme(params: RR.InitAcmeReq): Promise<RR.InitAcmeRes> {
|
||||
async initAcme(params: T.InitAcmeParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch = [
|
||||
@@ -1381,7 +1372,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async removeAcme(params: RR.RemoveAcmeReq): Promise<RR.RemoveAcmeRes> {
|
||||
async removeAcme(params: T.RemoveAcmeParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const regex = new RegExp('/', 'g')
|
||||
@@ -1398,8 +1389,8 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
async serverBindingSetAddressEnabled(
|
||||
params: RR.ServerBindingSetAddressEnabledReq,
|
||||
): Promise<RR.ServerBindingSetAddressEnabledRes> {
|
||||
params: ServerBindingSetAddressEnabledReq,
|
||||
): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const basePath = `/serverInfo/network/host/bindings/${params.internalPort}/addresses`
|
||||
@@ -1409,8 +1400,8 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
async osUiAddPublicDomain(
|
||||
params: RR.OsUiAddPublicDomainReq,
|
||||
): Promise<RR.OsUiAddPublicDomainRes> {
|
||||
params: T.AddPublicDomainParams,
|
||||
): Promise<string | null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: Operation<any>[] = [
|
||||
@@ -1438,9 +1429,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async osUiRemovePublicDomain(
|
||||
params: RR.OsUiRemovePublicDomainReq,
|
||||
): Promise<RR.OsUiRemovePublicDomainRes> {
|
||||
async osUiRemovePublicDomain(params: T.RemoveDomainParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: RemoveOperation[] = [
|
||||
@@ -1454,9 +1443,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async osUiAddPrivateDomain(
|
||||
params: RR.OsUiAddPrivateDomainReq,
|
||||
): Promise<RR.OsUiAddPrivateDomainRes> {
|
||||
async osUiAddPrivateDomain(params: T.AddPrivateDomainParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: Operation<any>[] = [
|
||||
@@ -1482,9 +1469,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async osUiRemovePrivateDomain(
|
||||
params: RR.OsUiRemovePrivateDomainReq,
|
||||
): Promise<RR.OsUiRemovePrivateDomainRes> {
|
||||
async osUiRemovePrivateDomain(params: T.RemoveDomainParams): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: RemoveOperation[] = [
|
||||
@@ -1499,8 +1484,8 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
async pkgBindingSetAddressEnabled(
|
||||
params: RR.PkgBindingSetAddressEnabledReq,
|
||||
): Promise<RR.PkgBindingSetAddressEnabledRes> {
|
||||
params: PkgBindingSetAddressEnabledReq,
|
||||
): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const basePath = `/packageData/${params.package}/hosts/${params.host}/bindings/${params.internalPort}/addresses`
|
||||
@@ -1510,8 +1495,8 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
async pkgAddPublicDomain(
|
||||
params: RR.PkgAddPublicDomainReq,
|
||||
): Promise<RR.PkgAddPublicDomainRes> {
|
||||
params: PkgAddPublicDomainReq,
|
||||
): Promise<string | null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: Operation<any>[] = [
|
||||
@@ -1539,9 +1524,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async pkgRemovePublicDomain(
|
||||
params: RR.PkgRemovePublicDomainReq,
|
||||
): Promise<RR.PkgRemovePublicDomainRes> {
|
||||
async pkgRemovePublicDomain(params: PkgRemovePublicDomainReq): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: RemoveOperation[] = [
|
||||
@@ -1555,9 +1538,7 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async pkgAddPrivateDomain(
|
||||
params: RR.PkgAddPrivateDomainReq,
|
||||
): Promise<RR.PkgAddPrivateDomainRes> {
|
||||
async pkgAddPrivateDomain(params: PkgAddPrivateDomainReq): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: Operation<any>[] = [
|
||||
@@ -1584,8 +1565,8 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
async pkgRemovePrivateDomain(
|
||||
params: RR.PkgRemovePrivateDomainReq,
|
||||
): Promise<RR.PkgRemovePrivateDomainRes> {
|
||||
params: PkgRemovePrivateDomainReq,
|
||||
): Promise<null> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: RemoveOperation[] = [
|
||||
|
||||
@@ -110,6 +110,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
publicDomains: {},
|
||||
privateDomains: {},
|
||||
portForwards: [],
|
||||
},
|
||||
gateways: {
|
||||
eth0: {
|
||||
@@ -607,6 +608,7 @@ export const mockPatchData: DataModel = {
|
||||
privateDomains: {
|
||||
'my-bitcoin.home': ['wlan0'],
|
||||
},
|
||||
portForwards: [],
|
||||
},
|
||||
bcdefgh: {
|
||||
bindings: {
|
||||
@@ -648,6 +650,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
publicDomains: {},
|
||||
privateDomains: {},
|
||||
portForwards: [],
|
||||
},
|
||||
cdefghi: {
|
||||
bindings: {
|
||||
@@ -671,6 +674,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
publicDomains: {},
|
||||
privateDomains: {},
|
||||
portForwards: [],
|
||||
},
|
||||
},
|
||||
storeExposedDependents: [],
|
||||
|
||||
@@ -28,7 +28,6 @@ import {
|
||||
switchMap,
|
||||
tap,
|
||||
} from 'rxjs'
|
||||
import { RR } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
|
||||
@@ -247,7 +246,7 @@ export class MarketplaceService {
|
||||
version: string,
|
||||
url: string,
|
||||
): Promise<void> {
|
||||
const params: RR.InstallPackageReq = {
|
||||
const params: T.InstallParams = {
|
||||
id,
|
||||
version,
|
||||
registry: url,
|
||||
|
||||
@@ -10,8 +10,7 @@ import {
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { getServerInfo } from 'src/app/utils/get-server-info'
|
||||
import { DataModel } from './patch-db/data-model'
|
||||
import { Version } from '@start9labs/start-sdk'
|
||||
import { RR } from './api/api.types'
|
||||
import { T, Version } from '@start9labs/start-sdk'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -20,7 +19,7 @@ export class OSService {
|
||||
private readonly api = inject(ApiService)
|
||||
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
|
||||
|
||||
osUpdate?: RR.CheckOsUpdateRes
|
||||
osUpdate?: T.OsVersionInfoMap
|
||||
readonly updateAvailable$ = new BehaviorSubject<boolean>(false)
|
||||
|
||||
readonly updating$ = this.patch.watch$('serverInfo', 'statusInfo').pipe(
|
||||
|
||||
@@ -15,7 +15,6 @@ import { getAllPackages } from '../utils/get-package-data'
|
||||
import { hasCurrentDeps } from '../utils/has-deps'
|
||||
import { ApiService } from './api/embassy-api.service'
|
||||
import { DataModel } from './patch-db/data-model'
|
||||
import { RR } from './api/api.types'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -78,7 +77,7 @@ export class StandardActionsService {
|
||||
.subscribe(() => this.doUninstall({ id, force, soft }))
|
||||
}
|
||||
|
||||
private async doUninstall(options: RR.UninstallPackageReq) {
|
||||
private async doUninstall(options: T.UninstallParams) {
|
||||
const loader = this.loader.open('Beginning uninstall').subscribe()
|
||||
|
||||
try {
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
takeUntil,
|
||||
tap,
|
||||
} from 'rxjs/operators'
|
||||
import { RR } from 'src/app/services/api/api.types'
|
||||
import { ServerState } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { NetworkService } from 'src/app/services/network.service'
|
||||
|
||||
@@ -56,7 +56,7 @@ class DisconnectedToast {}
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class StateService extends Observable<RR.ServerState | null> {
|
||||
export class StateService extends Observable<ServerState | null> {
|
||||
private readonly alerts = inject(TuiAlertService)
|
||||
private readonly i18n = inject(i18nPipe)
|
||||
private readonly api = inject(ApiService)
|
||||
@@ -115,7 +115,7 @@ export class StateService extends Observable<RR.ServerState | null> {
|
||||
setTimeout(() => this.trigger$.next(gracefully), delay)
|
||||
}
|
||||
|
||||
private handleState(state: RR.ServerState): void {
|
||||
private handleState(state: ServerState): void {
|
||||
switch (state) {
|
||||
case 'initializing':
|
||||
this.router.navigate(['initializing'], { replaceUrl: true })
|
||||
@@ -136,7 +136,7 @@ export class StateService extends Observable<RR.ServerState | null> {
|
||||
}
|
||||
}
|
||||
|
||||
export function stateNot(state: RR.ServerState[]): CanActivateFn {
|
||||
export function stateNot(state: ServerState[]): CanActivateFn {
|
||||
return () =>
|
||||
inject(StateService).pipe(
|
||||
filter(current => !current || !state.includes(current)),
|
||||
|
||||
@@ -12,14 +12,15 @@ export class TimeService {
|
||||
private readonly time$ = defer(() =>
|
||||
inject(ApiService).getSystemTime({}),
|
||||
).pipe(
|
||||
switchMap(({ now, uptime }) =>
|
||||
timer(0, 1000).pipe(
|
||||
switchMap(({ now, uptime }) => {
|
||||
const uptimeSecs = Number(uptime)
|
||||
return timer(0, 1000).pipe(
|
||||
map(index => ({
|
||||
now: new Date(now).valueOf() + 1000 * index,
|
||||
uptime: uptime + index,
|
||||
uptime: uptimeSecs + index,
|
||||
})),
|
||||
),
|
||||
),
|
||||
)
|
||||
}),
|
||||
shareReplay(1),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user