@serve.zone/interfaces 32.69.0 → 32.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +6 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/data/backup.d.ts +55 -0
- package/dist_ts/data/backup.js +16 -2
- package/dist_ts/requests/backup.d.ts +8 -0
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/data/backup.ts +57 -0
- package/ts/requests/backup.ts +8 -0
package/changelog.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-11-05 - 32.70.0
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Partial restore of an incomplete backup (Linus 2026-11-05 ruling): a `failed` backup record can name its failure's kind, `data.IBackupRecord.failure` (`data.TBackupFailure`): `incomplete` with `uncaptured`, each resource its service declares that the backup did not capture (`data.TBackupUncapturedResource`: a volume by mount path, always with reason `volume-capture-unavailable`, or a binding by id, always with reason `binding-not-snapshotted`; `data.TBackupUncapturedReason` names either), or `archive-unreadable`. `requests.backup.IReq_Any_Cloudly_RestoreServiceBackup` takes `confirmPartialRestore`, which an administrator sets to restore what an `incomplete` backup captured: `resourceTypes` is required and names only captured types, nothing in `uncaptured` is restored, so the service then holds data from two points in time, and the backup stays `failed`; it is refused for any other backup. `data.readPartialRestoreResourceTypes` answers the types such a restore may name: those the backup holds a snapshot of, except `volume` (a `volume` snapshot captures no service volume) and the type of any uncaptured resource; none for any other backup. A restore event (`data.IBackupRestoreEvent`) states the `resourceTypes` it was limited to and `partial` for such a restore. Additive: no validator reads these shapes. Spec: `test.backuppartialrestore`.
|
|
8
|
+
|
|
3
9
|
## 2026-11-05 - 32.69.0
|
|
4
10
|
|
|
5
11
|
### Features
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@serve.zone/interfaces',
|
|
6
|
-
version: '32.
|
|
6
|
+
version: '32.70.0',
|
|
7
7
|
description: 'Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLFNBQVM7SUFDbEIsV0FBVyxFQUFFLHVGQUF1RjtDQUNyRyxDQUFBIn0=
|
package/dist_ts/data/backup.d.ts
CHANGED
|
@@ -48,10 +48,52 @@ export interface IBackupReplicationResult {
|
|
|
48
48
|
totalSize: number;
|
|
49
49
|
completedAt: number;
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* One resource a service declares that a backup of it did not capture, with why; each kind of
|
|
53
|
+
* resource has its own reason.
|
|
54
|
+
*
|
|
55
|
+
* `volume-capture-unavailable`: a service volume is a node-local storage claim on its Pallet node,
|
|
56
|
+
* which no relay can capture yet; a `volume` snapshot is a Corestore Docker volume and captures no
|
|
57
|
+
* service volume. `binding-not-snapshotted`: the backup holds no snapshot of the Corestore resource
|
|
58
|
+
* the binding names.
|
|
59
|
+
*/
|
|
60
|
+
export type TBackupUncapturedResource = {
|
|
61
|
+
type: 'volume';
|
|
62
|
+
mountPath: string;
|
|
63
|
+
reason: 'volume-capture-unavailable';
|
|
64
|
+
} | {
|
|
65
|
+
type: 'database' | 'objectstorage';
|
|
66
|
+
bindingId: string;
|
|
67
|
+
reason: 'binding-not-snapshotted';
|
|
68
|
+
};
|
|
69
|
+
/** Why a resource a service declares is not in one of its backups (`TBackupUncapturedResource`). */
|
|
70
|
+
export type TBackupUncapturedReason = TBackupUncapturedResource['reason'];
|
|
71
|
+
/**
|
|
72
|
+
* The named kind of a `failed` backup's failure; a failure without one is named only in `errorText`.
|
|
73
|
+
*
|
|
74
|
+
* `incomplete`: the backup did not capture every resource its service declares, and `uncaptured`
|
|
75
|
+
* names each one it missed. What it did capture is restored only by a partial restore an
|
|
76
|
+
* administrator confirms (`IReq_Any_Cloudly_RestoreServiceBackup` `confirmPartialRestore`), which
|
|
77
|
+
* restores none of `uncaptured`, and the backup stays `failed`.
|
|
78
|
+
* `archive-unreadable`: its stored archive is missing or damaged, so it restores nothing.
|
|
79
|
+
*/
|
|
80
|
+
export type TBackupFailure = {
|
|
81
|
+
kind: 'incomplete';
|
|
82
|
+
uncaptured: TBackupUncapturedResource[];
|
|
83
|
+
} | {
|
|
84
|
+
kind: 'archive-unreadable';
|
|
85
|
+
};
|
|
51
86
|
export interface IBackupRestoreEvent {
|
|
52
87
|
restoredAt: number;
|
|
53
88
|
status: 'restored' | 'failed';
|
|
54
89
|
errorText?: string;
|
|
90
|
+
/** The resource types the restore was limited to; absent when it restored every snapshot. */
|
|
91
|
+
resourceTypes?: TBackupResourceType[];
|
|
92
|
+
/**
|
|
93
|
+
* A confirmed partial restore of an `incomplete` backup: it restored only `resourceTypes`, and
|
|
94
|
+
* none of the backup's `failure.uncaptured`.
|
|
95
|
+
*/
|
|
96
|
+
partial?: true;
|
|
55
97
|
}
|
|
56
98
|
/**
|
|
57
99
|
* Durable retention hold owned by one isolated restore. An entry is active
|
|
@@ -88,6 +130,8 @@ export interface IBackupRecord {
|
|
|
88
130
|
completedAt?: number;
|
|
89
131
|
requestedBy?: string;
|
|
90
132
|
errorText?: string;
|
|
133
|
+
/** The named kind of a `failed` backup's failure (`TBackupFailure`). */
|
|
134
|
+
failure?: TBackupFailure;
|
|
91
135
|
restoreHistory?: IBackupRestoreEvent[];
|
|
92
136
|
/**
|
|
93
137
|
* Authoritative isolated-restore holds. Cloudly atomically appends the
|
|
@@ -97,6 +141,17 @@ export interface IBackupRecord {
|
|
|
97
141
|
restoreHolds?: IBackupRestoreHold[];
|
|
98
142
|
tags?: Record<string, string>;
|
|
99
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* The resource types a partial restore of a backup may name (`confirmPartialRestore`).
|
|
146
|
+
*
|
|
147
|
+
* For a `failed` backup whose failure is `incomplete`: every type it holds a snapshot of, except
|
|
148
|
+
* `volume` (a `volume` snapshot is a Corestore Docker volume and captures no service volume) and the
|
|
149
|
+
* type of any resource it did not capture, so a partial restore never restores a snapshot standing
|
|
150
|
+
* for a resource the backup missed. For every other backup: none. Database before object storage.
|
|
151
|
+
*/
|
|
152
|
+
export declare const readPartialRestoreResourceTypes: (backupArg: Pick<IBackupRecord, 'status' | 'failure'> & {
|
|
153
|
+
snapshots: ReadonlyArray<Pick<TBackupSnapshot, 'type'>>;
|
|
154
|
+
}) => Array<Exclude<TBackupResourceType, 'volume'>>;
|
|
100
155
|
/** Retention policy understood by containerarchive prune. */
|
|
101
156
|
export interface IArchiveRetentionPolicy {
|
|
102
157
|
keepLast?: number;
|
package/dist_ts/data/backup.js
CHANGED
|
@@ -1,2 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The resource types a partial restore of a backup may name (`confirmPartialRestore`).
|
|
3
|
+
*
|
|
4
|
+
* For a `failed` backup whose failure is `incomplete`: every type it holds a snapshot of, except
|
|
5
|
+
* `volume` (a `volume` snapshot is a Corestore Docker volume and captures no service volume) and the
|
|
6
|
+
* type of any resource it did not capture, so a partial restore never restores a snapshot standing
|
|
7
|
+
* for a resource the backup missed. For every other backup: none. Database before object storage.
|
|
8
|
+
*/
|
|
9
|
+
export const readPartialRestoreResourceTypes = (backupArg) => {
|
|
10
|
+
const failure = backupArg.failure;
|
|
11
|
+
if (backupArg.status !== 'failed' || failure?.kind !== 'incomplete')
|
|
12
|
+
return [];
|
|
13
|
+
const uncapturedTypes = new Set(failure.uncaptured.map((resourceArg) => resourceArg.type));
|
|
14
|
+
return ['database', 'objectstorage'].filter((typeArg) => (!uncapturedTypes.has(typeArg) && backupArg.snapshots.some((snapshotArg) => snapshotArg.type === typeArg)));
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja3VwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvZGF0YS9iYWNrdXAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBb0tBOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLENBQUMsTUFBTSwrQkFBK0IsR0FBRyxDQUM3QyxTQUFrSCxFQUNuRSxFQUFFO0lBQ2pELE1BQU0sT0FBTyxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUM7SUFDbEMsSUFBSSxTQUFTLENBQUMsTUFBTSxLQUFLLFFBQVEsSUFBSSxPQUFPLEVBQUUsSUFBSSxLQUFLLFlBQVk7UUFBRSxPQUFPLEVBQUUsQ0FBQztJQUMvRSxNQUFNLGVBQWUsR0FBRyxJQUFJLEdBQUcsQ0FBc0IsT0FBTyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ2hILE9BQVEsQ0FBQyxVQUFVLEVBQUUsZUFBZSxDQUFXLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUNsRSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksU0FBUyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEtBQUssT0FBTyxDQUFDLENBQ3pHLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyJ9
|
|
@@ -45,6 +45,14 @@ export interface IReq_Any_Cloudly_RestoreServiceBackup extends plugins.typedrequ
|
|
|
45
45
|
backupId: string;
|
|
46
46
|
clear?: boolean;
|
|
47
47
|
resourceTypes?: Array<TBackupSnapshot['type']>;
|
|
48
|
+
/**
|
|
49
|
+
* Must be `true` to restore a `failed` backup whose failure is `incomplete`, and is refused for
|
|
50
|
+
* any other backup. Such a restore restores what the backup captured: `resourceTypes` is
|
|
51
|
+
* required and names only types it captured, none of the resources it did not capture
|
|
52
|
+
* (`failure.uncaptured`) is restored, so the service then holds data from two points in time,
|
|
53
|
+
* and the backup stays `failed`.
|
|
54
|
+
*/
|
|
55
|
+
confirmPartialRestore?: boolean;
|
|
48
56
|
};
|
|
49
57
|
response: {
|
|
50
58
|
backup: IBackupRecord;
|
package/package.json
CHANGED
package/ts/00_commitinfo_data.ts
CHANGED
package/ts/data/backup.ts
CHANGED
|
@@ -72,10 +72,46 @@ export interface IBackupReplicationResult {
|
|
|
72
72
|
completedAt: number;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* One resource a service declares that a backup of it did not capture, with why; each kind of
|
|
77
|
+
* resource has its own reason.
|
|
78
|
+
*
|
|
79
|
+
* `volume-capture-unavailable`: a service volume is a node-local storage claim on its Pallet node,
|
|
80
|
+
* which no relay can capture yet; a `volume` snapshot is a Corestore Docker volume and captures no
|
|
81
|
+
* service volume. `binding-not-snapshotted`: the backup holds no snapshot of the Corestore resource
|
|
82
|
+
* the binding names.
|
|
83
|
+
*/
|
|
84
|
+
export type TBackupUncapturedResource =
|
|
85
|
+
| { type: 'volume'; mountPath: string; reason: 'volume-capture-unavailable' }
|
|
86
|
+
| { type: 'database' | 'objectstorage'; bindingId: string; reason: 'binding-not-snapshotted' };
|
|
87
|
+
|
|
88
|
+
/** Why a resource a service declares is not in one of its backups (`TBackupUncapturedResource`). */
|
|
89
|
+
export type TBackupUncapturedReason = TBackupUncapturedResource['reason'];
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The named kind of a `failed` backup's failure; a failure without one is named only in `errorText`.
|
|
93
|
+
*
|
|
94
|
+
* `incomplete`: the backup did not capture every resource its service declares, and `uncaptured`
|
|
95
|
+
* names each one it missed. What it did capture is restored only by a partial restore an
|
|
96
|
+
* administrator confirms (`IReq_Any_Cloudly_RestoreServiceBackup` `confirmPartialRestore`), which
|
|
97
|
+
* restores none of `uncaptured`, and the backup stays `failed`.
|
|
98
|
+
* `archive-unreadable`: its stored archive is missing or damaged, so it restores nothing.
|
|
99
|
+
*/
|
|
100
|
+
export type TBackupFailure =
|
|
101
|
+
| { kind: 'incomplete'; uncaptured: TBackupUncapturedResource[] }
|
|
102
|
+
| { kind: 'archive-unreadable' };
|
|
103
|
+
|
|
75
104
|
export interface IBackupRestoreEvent {
|
|
76
105
|
restoredAt: number;
|
|
77
106
|
status: 'restored' | 'failed';
|
|
78
107
|
errorText?: string;
|
|
108
|
+
/** The resource types the restore was limited to; absent when it restored every snapshot. */
|
|
109
|
+
resourceTypes?: TBackupResourceType[];
|
|
110
|
+
/**
|
|
111
|
+
* A confirmed partial restore of an `incomplete` backup: it restored only `resourceTypes`, and
|
|
112
|
+
* none of the backup's `failure.uncaptured`.
|
|
113
|
+
*/
|
|
114
|
+
partial?: true;
|
|
79
115
|
}
|
|
80
116
|
|
|
81
117
|
/**
|
|
@@ -114,6 +150,8 @@ export interface IBackupRecord {
|
|
|
114
150
|
completedAt?: number;
|
|
115
151
|
requestedBy?: string;
|
|
116
152
|
errorText?: string;
|
|
153
|
+
/** The named kind of a `failed` backup's failure (`TBackupFailure`). */
|
|
154
|
+
failure?: TBackupFailure;
|
|
117
155
|
restoreHistory?: IBackupRestoreEvent[];
|
|
118
156
|
/**
|
|
119
157
|
* Authoritative isolated-restore holds. Cloudly atomically appends the
|
|
@@ -124,6 +162,25 @@ export interface IBackupRecord {
|
|
|
124
162
|
tags?: Record<string, string>;
|
|
125
163
|
}
|
|
126
164
|
|
|
165
|
+
/**
|
|
166
|
+
* The resource types a partial restore of a backup may name (`confirmPartialRestore`).
|
|
167
|
+
*
|
|
168
|
+
* For a `failed` backup whose failure is `incomplete`: every type it holds a snapshot of, except
|
|
169
|
+
* `volume` (a `volume` snapshot is a Corestore Docker volume and captures no service volume) and the
|
|
170
|
+
* type of any resource it did not capture, so a partial restore never restores a snapshot standing
|
|
171
|
+
* for a resource the backup missed. For every other backup: none. Database before object storage.
|
|
172
|
+
*/
|
|
173
|
+
export const readPartialRestoreResourceTypes = (
|
|
174
|
+
backupArg: Pick<IBackupRecord, 'status' | 'failure'> & { snapshots: ReadonlyArray<Pick<TBackupSnapshot, 'type'>> },
|
|
175
|
+
): Array<Exclude<TBackupResourceType, 'volume'>> => {
|
|
176
|
+
const failure = backupArg.failure;
|
|
177
|
+
if (backupArg.status !== 'failed' || failure?.kind !== 'incomplete') return [];
|
|
178
|
+
const uncapturedTypes = new Set<TBackupResourceType>(failure.uncaptured.map((resourceArg) => resourceArg.type));
|
|
179
|
+
return (['database', 'objectstorage'] as const).filter((typeArg) => (
|
|
180
|
+
!uncapturedTypes.has(typeArg) && backupArg.snapshots.some((snapshotArg) => snapshotArg.type === typeArg)
|
|
181
|
+
));
|
|
182
|
+
};
|
|
183
|
+
|
|
127
184
|
/** Retention policy understood by containerarchive prune. */
|
|
128
185
|
export interface IArchiveRetentionPolicy {
|
|
129
186
|
keepLast?: number;
|
package/ts/requests/backup.ts
CHANGED
|
@@ -81,6 +81,14 @@ extends plugins.typedrequestInterfaces.implementsTR<
|
|
|
81
81
|
backupId: string;
|
|
82
82
|
clear?: boolean;
|
|
83
83
|
resourceTypes?: Array<TBackupSnapshot['type']>;
|
|
84
|
+
/**
|
|
85
|
+
* Must be `true` to restore a `failed` backup whose failure is `incomplete`, and is refused for
|
|
86
|
+
* any other backup. Such a restore restores what the backup captured: `resourceTypes` is
|
|
87
|
+
* required and names only types it captured, none of the resources it did not capture
|
|
88
|
+
* (`failure.uncaptured`) is restored, so the service then holds data from two points in time,
|
|
89
|
+
* and the backup stays `failed`.
|
|
90
|
+
*/
|
|
91
|
+
confirmPartialRestore?: boolean;
|
|
84
92
|
};
|
|
85
93
|
response: {
|
|
86
94
|
backup: IBackupRecord;
|