@homeflare/distilled-proxmox 0.3.0 → 0.3.1
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/README.md +15 -10
- package/dist/config-not-found.test.d.ts +2 -0
- package/dist/config-not-found.test.d.ts.map +1 -0
- package/dist/config-not-found.test.js +96 -0
- package/dist/config-not-found.test.js.map +1 -0
- package/dist/errors.d.ts +2 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/protocol-form.d.ts +18 -0
- package/dist/protocol-form.d.ts.map +1 -0
- package/dist/protocol-form.js +37 -0
- package/dist/protocol-form.js.map +1 -0
- package/dist/protocol-form.test.d.ts +2 -0
- package/dist/protocol-form.test.d.ts.map +1 -0
- package/dist/protocol-form.test.js +68 -0
- package/dist/protocol-form.test.js.map +1 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +19 -2
- package/dist/protocol.js.map +1 -1
- package/dist/services/cluster.d.ts +25 -5
- package/dist/services/cluster.d.ts.map +1 -1
- package/dist/services/cluster.js +26 -5
- package/dist/services/cluster.js.map +1 -1
- package/dist/services/pools.d.ts +16 -6
- package/dist/services/pools.d.ts.map +1 -1
- package/dist/services/pools.js +18 -6
- package/dist/services/pools.js.map +1 -1
- package/package.json +1 -1
- package/src/config-not-found.test.ts +153 -0
- package/src/errors.ts +4 -12
- package/src/protocol-form.test.ts +102 -0
- package/src/protocol-form.ts +49 -0
- package/src/protocol.ts +22 -2
- package/src/services/cluster.ts +46 -10
- package/src/services/pools.ts +27 -12
package/dist/services/pools.d.ts
CHANGED
|
@@ -2,6 +2,16 @@ import * as S from "@distilled.cloud/core/schema";
|
|
|
2
2
|
import * as API from "@distilled.cloud/core/api";
|
|
3
3
|
import { type ProxmoxOpError, type ProxmoxOpContext } from "../protocol.ts";
|
|
4
4
|
export type { ProxmoxOpError, ProxmoxOpContext };
|
|
5
|
+
declare const PoolNotFound_base: S.Class<PoolNotFound, S.TaggedStruct<"PoolNotFound", {
|
|
6
|
+
readonly message: any;
|
|
7
|
+
}>, import("effect/Cause").YieldableError> & (new (...args: any[]) => {
|
|
8
|
+
"@distilled.cloud/error/categories": {
|
|
9
|
+
BadRequestError: true;
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
/** The resource pool does not exist. pve-manager 9.2.11, f6997e698c7933ea8e62319e2bf1bf7262daa56a, PVE/API2/Pool.pm:106,327,512 throws pool '<poolid>' does not exist in the read, update and delete handlers. Deprecated item routes delegate to them. The wire status is 500; a nonempty pool refusal or missing parent during create is a different error and must not match. */
|
|
13
|
+
export declare class PoolNotFound extends /*@__PURE__*/ PoolNotFound_base {
|
|
14
|
+
}
|
|
5
15
|
export interface CreatePoolRequest {
|
|
6
16
|
comment?: string;
|
|
7
17
|
poolid: string;
|
|
@@ -112,22 +122,22 @@ export declare const PutPoolsResponse: S.Schema<PutPoolsResponse>;
|
|
|
112
122
|
export type CreatePoolError = ProxmoxOpError;
|
|
113
123
|
/** Create new pool. (root-privileged endpoint) */
|
|
114
124
|
export declare const createPool: API.OperationMethod<CreatePoolRequest, CreatePoolResponse, CreatePoolError, ProxmoxOpContext>;
|
|
115
|
-
export type DeletePoolError = ProxmoxOpError;
|
|
125
|
+
export type DeletePoolError = PoolNotFound | ProxmoxOpError;
|
|
116
126
|
/** Delete pool (deprecated, no support for nested pools, use 'DELETE /pools/?poolid={poolid}'). (root-privileged endpoint) */
|
|
117
127
|
export declare const deletePool: API.OperationMethod<DeletePoolRequest, DeletePoolResponse, DeletePoolError, ProxmoxOpContext>;
|
|
118
|
-
export type DeletePoolsError = ProxmoxOpError;
|
|
128
|
+
export type DeletePoolsError = PoolNotFound | ProxmoxOpError;
|
|
119
129
|
/** Delete pool. (root-privileged endpoint) */
|
|
120
130
|
export declare const deletePools: API.OperationMethod<DeletePoolsRequest, DeletePoolsResponse, DeletePoolsError, ProxmoxOpContext>;
|
|
121
|
-
export type GetPoolError = ProxmoxOpError;
|
|
131
|
+
export type GetPoolError = PoolNotFound | ProxmoxOpError;
|
|
122
132
|
/** Get pool configuration (deprecated, no support for nested pools, use 'GET /pools/?poolid={poolid}'). */
|
|
123
133
|
export declare const getPool: API.OperationMethod<GetPoolRequest, GetPoolResponse, GetPoolError, ProxmoxOpContext>;
|
|
124
|
-
export type ListPoolsError = ProxmoxOpError;
|
|
134
|
+
export type ListPoolsError = PoolNotFound | ProxmoxOpError;
|
|
125
135
|
/** List pools or get pool configuration. */
|
|
126
136
|
export declare const listPools: API.OperationMethod<ListPoolsRequest, ListPoolsResponse, ListPoolsError, ProxmoxOpContext>;
|
|
127
|
-
export type PutPoolError = ProxmoxOpError;
|
|
137
|
+
export type PutPoolError = PoolNotFound | ProxmoxOpError;
|
|
128
138
|
/** Update pool data (deprecated, no support for nested pools - use 'PUT /pools/?poolid={poolid}' instead). (root-privileged endpoint) */
|
|
129
139
|
export declare const putPool: API.OperationMethod<PutPoolRequest, PutPoolResponse, PutPoolError, ProxmoxOpContext>;
|
|
130
|
-
export type PutPoolsError = ProxmoxOpError;
|
|
140
|
+
export type PutPoolsError = PoolNotFound | ProxmoxOpError;
|
|
131
141
|
/** Update pool. (root-privileged endpoint) */
|
|
132
142
|
export declare const putPools: API.OperationMethod<PutPoolsRequest, PutPoolsResponse, PutPoolsError, ProxmoxOpContext>;
|
|
133
143
|
//# sourceMappingURL=pools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pools.d.ts","sourceRoot":"","sources":["../../src/services/pools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,8BAA8B,CAAC;AAClD,OAAO,KAAK,GAAG,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"pools.d.ts","sourceRoot":"","sources":["../../src/services/pools.ts"],"names":[],"mappings":"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"}
|
package/dist/services/pools.js
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
// AUTO-GENERATED by scripts/generate.ts from .generated-specs (apidata.js, via scripts/apidoc.ts — see its header). Do not edit.
|
|
2
2
|
import * as S from "@distilled.cloud/core/schema";
|
|
3
3
|
import * as API from "@distilled.cloud/core/api";
|
|
4
|
+
import * as C from "@distilled.cloud/core/category";
|
|
4
5
|
import * as T from "../traits.js";
|
|
5
6
|
import { ProxmoxProtocol, } from "../protocol.js";
|
|
6
7
|
import * as Retry from "../retry.js";
|
|
8
|
+
/** The resource pool does not exist. pve-manager 9.2.11, f6997e698c7933ea8e62319e2bf1bf7262daa56a, PVE/API2/Pool.pm:106,327,512 throws pool '<poolid>' does not exist in the read, update and delete handlers. Deprecated item routes delegate to them. The wire status is 500; a nonempty pool refusal or missing parent during create is a different error and must not match. */
|
|
9
|
+
export class PoolNotFound extends /*@__PURE__*/ /*@__PURE__*/ T.applyErrorMatchers(
|
|
10
|
+
/*@__PURE__*/ S.TaggedError()("PoolNotFound", {
|
|
11
|
+
message: S.String,
|
|
12
|
+
}).pipe(C.withBadRequestError), [
|
|
13
|
+
{
|
|
14
|
+
status: 500,
|
|
15
|
+
message: { matches: "^pool '[^']+' does not exist\\n?$" },
|
|
16
|
+
},
|
|
17
|
+
]) {
|
|
18
|
+
}
|
|
7
19
|
export const CreatePoolRequest = /*@__PURE__*/ S.suspend(() => S.Struct({
|
|
8
20
|
comment: S.optional(S.String),
|
|
9
21
|
poolid: S.String,
|
|
@@ -131,7 +143,7 @@ export const createPool = /*@__PURE__*/ API.make(() => ({
|
|
|
131
143
|
export const deletePool = /*@__PURE__*/ API.make(() => ({
|
|
132
144
|
input: DeletePoolRequest,
|
|
133
145
|
output: DeletePoolResponse,
|
|
134
|
-
errors: [],
|
|
146
|
+
errors: [PoolNotFound],
|
|
135
147
|
protocol: ProxmoxProtocol,
|
|
136
148
|
retry: Retry.Retry,
|
|
137
149
|
}));
|
|
@@ -139,7 +151,7 @@ export const deletePool = /*@__PURE__*/ API.make(() => ({
|
|
|
139
151
|
export const deletePools = /*@__PURE__*/ API.make(() => ({
|
|
140
152
|
input: DeletePoolsRequest,
|
|
141
153
|
output: DeletePoolsResponse,
|
|
142
|
-
errors: [],
|
|
154
|
+
errors: [PoolNotFound],
|
|
143
155
|
protocol: ProxmoxProtocol,
|
|
144
156
|
retry: Retry.Retry,
|
|
145
157
|
}));
|
|
@@ -147,7 +159,7 @@ export const deletePools = /*@__PURE__*/ API.make(() => ({
|
|
|
147
159
|
export const getPool = /*@__PURE__*/ API.make(() => ({
|
|
148
160
|
input: GetPoolRequest,
|
|
149
161
|
output: GetPoolResponse,
|
|
150
|
-
errors: [],
|
|
162
|
+
errors: [PoolNotFound],
|
|
151
163
|
protocol: ProxmoxProtocol,
|
|
152
164
|
retry: Retry.Retry,
|
|
153
165
|
}));
|
|
@@ -155,7 +167,7 @@ export const getPool = /*@__PURE__*/ API.make(() => ({
|
|
|
155
167
|
export const listPools = /*@__PURE__*/ API.make(() => ({
|
|
156
168
|
input: ListPoolsRequest,
|
|
157
169
|
output: ListPoolsResponse,
|
|
158
|
-
errors: [],
|
|
170
|
+
errors: [PoolNotFound],
|
|
159
171
|
protocol: ProxmoxProtocol,
|
|
160
172
|
retry: Retry.Retry,
|
|
161
173
|
}));
|
|
@@ -163,7 +175,7 @@ export const listPools = /*@__PURE__*/ API.make(() => ({
|
|
|
163
175
|
export const putPool = /*@__PURE__*/ API.make(() => ({
|
|
164
176
|
input: PutPoolRequest,
|
|
165
177
|
output: PutPoolResponse,
|
|
166
|
-
errors: [],
|
|
178
|
+
errors: [PoolNotFound],
|
|
167
179
|
protocol: ProxmoxProtocol,
|
|
168
180
|
retry: Retry.Retry,
|
|
169
181
|
}));
|
|
@@ -171,7 +183,7 @@ export const putPool = /*@__PURE__*/ API.make(() => ({
|
|
|
171
183
|
export const putPools = /*@__PURE__*/ API.make(() => ({
|
|
172
184
|
input: PutPoolsRequest,
|
|
173
185
|
output: PutPoolsResponse,
|
|
174
|
-
errors: [],
|
|
186
|
+
errors: [PoolNotFound],
|
|
175
187
|
protocol: ProxmoxProtocol,
|
|
176
188
|
retry: Retry.Retry,
|
|
177
189
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pools.js","sourceRoot":"","sources":["../../src/services/pools.ts"],"names":[],"mappings":"AAAA,iIAAiI;AACjI,OAAO,KAAK,CAAC,MAAM,8BAA8B,CAAC;AAClD,OAAO,KAAK,GAAG,MAAM,2BAA2B,CAAC;AACjD,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,EACL,eAAe,GAGhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,KAAK,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"pools.js","sourceRoot":"","sources":["../../src/services/pools.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@homeflare/distilled-proxmox",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Interim npm home for @distilled.cloud/proxmox — see docs/distilled-interim.md. Not published upstream yet; the kit aliases @distilled.cloud/proxmox onto this package until it is.",
|
|
5
5
|
"homepage": "https://github.com/taslabs-net/homeflare-kit/tree/main/packages/distilled-proxmox#readme",
|
|
6
6
|
"bugs": "https://github.com/taslabs-net/homeflare-kit/issues",
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/** PVE 9.2.11 vendor-source fixtures; missing BackupJob GET also measured 2026-09-24. */
|
|
2
|
+
import { describe, expect, test } from "bun:test";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
|
+
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
6
|
+
import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse";
|
|
7
|
+
import { credentials } from "./credentials.ts";
|
|
8
|
+
import type { ProxmoxOpContext } from "./protocol.ts";
|
|
9
|
+
import * as Retry from "./retry.ts";
|
|
10
|
+
import * as pools from "./services/pools.ts";
|
|
11
|
+
import * as cluster from "./services/cluster.ts";
|
|
12
|
+
|
|
13
|
+
const call = <A, E>(
|
|
14
|
+
op: Effect.Effect<A, E, ProxmoxOpContext>,
|
|
15
|
+
status: number,
|
|
16
|
+
body: unknown,
|
|
17
|
+
) =>
|
|
18
|
+
Effect.runPromise(
|
|
19
|
+
op.pipe(
|
|
20
|
+
Retry.none,
|
|
21
|
+
Effect.provide(
|
|
22
|
+
credentials({
|
|
23
|
+
baseUrl: "https://pve.test:8006",
|
|
24
|
+
tokenId: "test@pve!test",
|
|
25
|
+
secret: "fake",
|
|
26
|
+
}),
|
|
27
|
+
),
|
|
28
|
+
Effect.provide(
|
|
29
|
+
Layer.succeed(
|
|
30
|
+
HttpClient.HttpClient,
|
|
31
|
+
HttpClient.make((request) =>
|
|
32
|
+
Effect.succeed(
|
|
33
|
+
HttpClientResponse.fromWeb(
|
|
34
|
+
request,
|
|
35
|
+
Response.json(body, { status }),
|
|
36
|
+
),
|
|
37
|
+
),
|
|
38
|
+
),
|
|
39
|
+
),
|
|
40
|
+
),
|
|
41
|
+
Effect.flip,
|
|
42
|
+
),
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
describe("precise config absence tags", () => {
|
|
46
|
+
for (const [name, op] of [
|
|
47
|
+
["item read", pools.getPool({ poolid: "absent" })],
|
|
48
|
+
["index read", pools.listPools({ poolid: "absent" })],
|
|
49
|
+
["item update", pools.putPool({ poolid: "absent" })],
|
|
50
|
+
["collection update", pools.putPools({ poolid: "absent" })],
|
|
51
|
+
["item delete", pools.deletePool({ poolid: "absent" })],
|
|
52
|
+
["collection delete", pools.deletePools({ poolid: "absent" })],
|
|
53
|
+
] as const) {
|
|
54
|
+
test(`Pool ${name}`, async () => {
|
|
55
|
+
expect(
|
|
56
|
+
await call(op, 500, {
|
|
57
|
+
data: null,
|
|
58
|
+
message: "pool 'absent' does not exist\n",
|
|
59
|
+
}),
|
|
60
|
+
).toMatchObject({ _tag: "PoolNotFound" });
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
for (const [name, op] of [
|
|
64
|
+
["read", cluster.getClusterBackup({ id: "absent" })],
|
|
65
|
+
["delete", cluster.deleteClusterBackup({ id: "absent" })],
|
|
66
|
+
["volumes", cluster.getClusterBackupIncludedVolumes({ id: "absent" })],
|
|
67
|
+
] as const) {
|
|
68
|
+
test(`BackupJob ${name}`, async () => {
|
|
69
|
+
expect(
|
|
70
|
+
await call(op, 400, {
|
|
71
|
+
data: null,
|
|
72
|
+
message: "Parameter verification failed.\n",
|
|
73
|
+
errors: { id: "No such job 'absent'" },
|
|
74
|
+
}),
|
|
75
|
+
).toMatchObject({ _tag: "BackupJobNotFound" });
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
test("common HTTP failures remain in every operation's typed error union", async () => {
|
|
79
|
+
const op = pools.getPool({ poolid: "absent" }).pipe(
|
|
80
|
+
Effect.catchTag("NotFound", () =>
|
|
81
|
+
Effect.fail({ _tag: "HandledNotFound" } as const),
|
|
82
|
+
),
|
|
83
|
+
Effect.catchTag("Forbidden", () =>
|
|
84
|
+
Effect.fail({ _tag: "HandledForbidden" } as const),
|
|
85
|
+
),
|
|
86
|
+
);
|
|
87
|
+
expect(
|
|
88
|
+
await call(op, 404, { message: "missing", data: null }),
|
|
89
|
+
).toMatchObject({ _tag: "HandledNotFound" });
|
|
90
|
+
expect(
|
|
91
|
+
await call(op, 403, { message: "denied", data: null }),
|
|
92
|
+
).toMatchObject({ _tag: "HandledForbidden" });
|
|
93
|
+
});
|
|
94
|
+
test("MetricServer read and update have distinct absence messages", async () => {
|
|
95
|
+
expect(
|
|
96
|
+
await call(cluster.getClusterMetricsServer({ id: "absent" }), 500, {
|
|
97
|
+
data: null,
|
|
98
|
+
message: "status server entry 'absent' does not exist\n",
|
|
99
|
+
}),
|
|
100
|
+
).toMatchObject({ _tag: "MetricServerNotFound" });
|
|
101
|
+
expect(
|
|
102
|
+
await call(
|
|
103
|
+
cluster.putClusterMetricsServer({
|
|
104
|
+
id: "absent",
|
|
105
|
+
server: "localhost",
|
|
106
|
+
port: "8086",
|
|
107
|
+
}),
|
|
108
|
+
500,
|
|
109
|
+
{
|
|
110
|
+
data: null,
|
|
111
|
+
message: "no such server 'absent'\n",
|
|
112
|
+
},
|
|
113
|
+
),
|
|
114
|
+
).toMatchObject({ _tag: "MetricServerNotFound" });
|
|
115
|
+
});
|
|
116
|
+
test("unrelated, multi-field, and differently named validation are not absence", async () => {
|
|
117
|
+
for (const errors of [
|
|
118
|
+
{ id: "invalid configuration ID" },
|
|
119
|
+
{ id: "No such job 'absent'", schedule: "invalid schedule" },
|
|
120
|
+
{ comment: "No such job 'absent'" },
|
|
121
|
+
]) {
|
|
122
|
+
expect(
|
|
123
|
+
await call(cluster.getClusterBackup({ id: "absent" }), 400, {
|
|
124
|
+
data: null,
|
|
125
|
+
message: "Parameter verification failed.\n",
|
|
126
|
+
errors,
|
|
127
|
+
}),
|
|
128
|
+
).toMatchObject({ _tag: "ParameterVerificationFailed", errors });
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
test("a pool containing guests and a generic server failure propagate", async () => {
|
|
132
|
+
for (const message of [
|
|
133
|
+
"pool 'absent' is not empty (contains VM 100)\n",
|
|
134
|
+
"unrelated failure",
|
|
135
|
+
]) {
|
|
136
|
+
expect(
|
|
137
|
+
await call(pools.deletePool({ poolid: "absent" }), 500, {
|
|
138
|
+
data: null,
|
|
139
|
+
message,
|
|
140
|
+
}),
|
|
141
|
+
).toMatchObject({ _tag: "InternalServerError" });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
test("missing backup text is not attached to unrelated operations", async () => {
|
|
145
|
+
expect(
|
|
146
|
+
await call(cluster.deleteClusterMetricsServer({ id: "absent" }), 400, {
|
|
147
|
+
data: null,
|
|
148
|
+
message: "Parameter verification failed.\n",
|
|
149
|
+
errors: { id: "No such job 'absent'" },
|
|
150
|
+
}),
|
|
151
|
+
).toMatchObject({ _tag: "ParameterVerificationFailed" });
|
|
152
|
+
});
|
|
153
|
+
});
|
package/src/errors.ts
CHANGED
|
@@ -52,16 +52,9 @@ export {
|
|
|
52
52
|
DEFAULT_ERRORS,
|
|
53
53
|
API_ERRORS,
|
|
54
54
|
} from "@distilled.cloud/core/errors";
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
// of this package typechecking under `verbatimModuleSyntax`, not by this
|
|
59
|
-
// package's own `tsc -b` — see `docs/distilled-interim.md`'s "prove it in
|
|
60
|
-
// both places" step for why that gap exists at all.
|
|
61
|
-
import type {
|
|
62
|
-
BadRequest,
|
|
63
|
-
DefaultErrors as CoreDefaultErrors,
|
|
64
|
-
} from "@distilled.cloud/core/errors";
|
|
55
|
+
// Re-exports do not bind names locally. The operation union must cover every
|
|
56
|
+
// class the package protocol can return through core's HTTP_STATUS_MAP.
|
|
57
|
+
import type { API_ERRORS } from "@distilled.cloud/core/errors";
|
|
65
58
|
|
|
66
59
|
import * as Schema from "effect/Schema";
|
|
67
60
|
import * as Category from "@distilled.cloud/core/category";
|
|
@@ -153,7 +146,6 @@ export type ClientErrors = UnknownProxmoxError | ProxmoxParseError;
|
|
|
153
146
|
* task-polling.json` adds it to.
|
|
154
147
|
*/
|
|
155
148
|
export type DefaultErrors =
|
|
156
|
-
|
|
|
157
|
-
| BadRequest
|
|
149
|
+
| InstanceType<(typeof API_ERRORS)[number]>
|
|
158
150
|
| ParameterVerificationFailed
|
|
159
151
|
| ClientErrors;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/** PVE 9.2.11 schema arrays must survive the vendor's repeated-key decoder. */
|
|
2
|
+
import { expect, test } from "bun:test";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
|
+
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
6
|
+
import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
|
|
7
|
+
import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse";
|
|
8
|
+
import { credentials } from "./credentials.ts";
|
|
9
|
+
import type { ProxmoxOpContext } from "./protocol.ts";
|
|
10
|
+
import * as Retry from "./retry.ts";
|
|
11
|
+
import * as cluster from "./services/cluster.ts";
|
|
12
|
+
import * as nodes from "./services/nodes.ts";
|
|
13
|
+
|
|
14
|
+
const capture = async <A, E>(op: Effect.Effect<A, E, ProxmoxOpContext>) => {
|
|
15
|
+
const requests: HttpClientRequest.HttpClientRequest[] = [];
|
|
16
|
+
await Effect.runPromise(
|
|
17
|
+
op.pipe(
|
|
18
|
+
Retry.none,
|
|
19
|
+
Effect.provide(
|
|
20
|
+
credentials({
|
|
21
|
+
baseUrl: "https://pve.test:8006",
|
|
22
|
+
tokenId: "test@pve!test",
|
|
23
|
+
secret: "fake",
|
|
24
|
+
}),
|
|
25
|
+
),
|
|
26
|
+
Effect.provide(
|
|
27
|
+
Layer.succeed(
|
|
28
|
+
HttpClient.HttpClient,
|
|
29
|
+
HttpClient.make((request) => {
|
|
30
|
+
requests.push(request);
|
|
31
|
+
return Effect.succeed(
|
|
32
|
+
HttpClientResponse.fromWeb(
|
|
33
|
+
request,
|
|
34
|
+
Response.json({ data: null }),
|
|
35
|
+
),
|
|
36
|
+
);
|
|
37
|
+
}),
|
|
38
|
+
),
|
|
39
|
+
),
|
|
40
|
+
),
|
|
41
|
+
);
|
|
42
|
+
const request = requests[0]!;
|
|
43
|
+
const form =
|
|
44
|
+
request.body._tag === "Uint8Array"
|
|
45
|
+
? new URLSearchParams(new TextDecoder().decode(request.body.body))
|
|
46
|
+
: new URLSearchParams();
|
|
47
|
+
return { request, form };
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
test("matcher arrays repeat the wire key; commas within a rule stay inside that item", async () => {
|
|
51
|
+
const { request, form } = await capture(
|
|
52
|
+
cluster.createClusterNotificationMatcher({
|
|
53
|
+
name: "matcher",
|
|
54
|
+
target: ["mail", "webhook"],
|
|
55
|
+
match_field: ["exact:type=vzdump", "regex:hostname=one,two"],
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
expect(request.method).toBe("POST");
|
|
59
|
+
expect(form.getAll("target")).toEqual(["mail", "webhook"]);
|
|
60
|
+
expect(form.getAll("match-field")).toEqual([
|
|
61
|
+
"exact:type=vzdump",
|
|
62
|
+
"regex:hostname=one,two",
|
|
63
|
+
]);
|
|
64
|
+
expect([...form.keys()].some((key) => key.includes("["))).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("webhook property-string headers remain separate values", async () => {
|
|
68
|
+
const headers = ["name=X-One,value=YQ==", "name=X-Two,value=Yg=="];
|
|
69
|
+
const { form } = await capture(
|
|
70
|
+
cluster.createClusterNotificationEndpointWebhook({
|
|
71
|
+
name: "webhook",
|
|
72
|
+
method: "post",
|
|
73
|
+
url: "https://example.com/hook",
|
|
74
|
+
header: headers,
|
|
75
|
+
}),
|
|
76
|
+
);
|
|
77
|
+
expect(form.getAll("header")).toEqual(headers);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("array delete fields repeat while scalar comma lists remain scalar", async () => {
|
|
81
|
+
const { form } = await capture(
|
|
82
|
+
cluster.putClusterNotificationMatcher({
|
|
83
|
+
name: "matcher",
|
|
84
|
+
delete: ["match-field", "match-calendar"],
|
|
85
|
+
}),
|
|
86
|
+
);
|
|
87
|
+
expect(form.getAll("delete")).toEqual(["match-field", "match-calendar"]);
|
|
88
|
+
const scalar = await capture(
|
|
89
|
+
cluster.putClusterBackup({ id: "job", vmid: "100,101" }),
|
|
90
|
+
);
|
|
91
|
+
expect(scalar.form.getAll("vmid")).toEqual(["100,101"]);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("DELETE stays bodyless and its flags stay query parameters", async () => {
|
|
95
|
+
const { request, form } = await capture(
|
|
96
|
+
nodes.deleteNodeCephFs({ node: "node", name: "fs", remove_pools: "1" }),
|
|
97
|
+
);
|
|
98
|
+
expect(request.method).toBe("DELETE");
|
|
99
|
+
expect(request.body._tag).toBe("Empty");
|
|
100
|
+
expect(new URL(request.url).searchParams.get("remove-pools")).toBe("1");
|
|
101
|
+
expect([...form]).toEqual([]);
|
|
102
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PVE's form arrays use repeated keys, never Stripe's indexed fields.
|
|
3
|
+
*
|
|
4
|
+
* PVE 9.2.11 notification schemas declare arrays (mailto, header, target,
|
|
5
|
+
* match-field, delete). The vendor UI submits repeated keys; its Perl
|
|
6
|
+
* URL-encoded decoder joins them with NUL before schema validation. The
|
|
7
|
+
* existing kit notification-target-form.ts records that decoder/UI evidence
|
|
8
|
+
* (2026-09-14); no production multi-header write was made for this fix.
|
|
9
|
+
*
|
|
10
|
+
* Keep core's credentials, labels, schema key mapping, and query encoding.
|
|
11
|
+
* Only top-level scalar list entries in a form body change: header[0]=a
|
|
12
|
+
* becomes header=a. A property-string item's commas remain inside the item.
|
|
13
|
+
* A scalar comma list, an embedded NUL, or a GET/DELETE query is unchanged.
|
|
14
|
+
*/
|
|
15
|
+
import * as API from "@distilled.cloud/core/api";
|
|
16
|
+
import * as Effect from "effect/Effect";
|
|
17
|
+
import * as Layer from "effect/Layer";
|
|
18
|
+
import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
|
|
19
|
+
|
|
20
|
+
const repeatedFormKeys = (request: HttpClientRequest.HttpClientRequest) => {
|
|
21
|
+
if (
|
|
22
|
+
request.body._tag !== "Uint8Array" ||
|
|
23
|
+
request.body.contentType !== "application/x-www-form-urlencoded"
|
|
24
|
+
)
|
|
25
|
+
return request;
|
|
26
|
+
const fields = new URLSearchParams(
|
|
27
|
+
new TextDecoder().decode(request.body.body),
|
|
28
|
+
);
|
|
29
|
+
const repeated: [string, string][] = [];
|
|
30
|
+
for (const [key, value] of fields) {
|
|
31
|
+
repeated.push([key.replace(/^([^\[\]]+)\[\d+\]$/, "$1"), value]);
|
|
32
|
+
}
|
|
33
|
+
return HttpClientRequest.bodyUrlParams(request, repeated);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const withPveFormArrays = (
|
|
37
|
+
base: Layer.Layer<API.Protocol>,
|
|
38
|
+
): Layer.Layer<API.Protocol> =>
|
|
39
|
+
Layer.effect(
|
|
40
|
+
API.Protocol,
|
|
41
|
+
Effect.gen(function* () {
|
|
42
|
+
const protocol = yield* API.Protocol;
|
|
43
|
+
return API.Protocol.of({
|
|
44
|
+
...protocol,
|
|
45
|
+
encode: (args) =>
|
|
46
|
+
protocol.encode(args).pipe(Effect.map(repeatedFormKeys)),
|
|
47
|
+
});
|
|
48
|
+
}),
|
|
49
|
+
).pipe(Layer.provide(base));
|
package/src/protocol.ts
CHANGED
|
@@ -81,6 +81,7 @@ import {
|
|
|
81
81
|
type RestErrorEnvelope,
|
|
82
82
|
} from "@distilled.cloud/core/protocol-rest";
|
|
83
83
|
import { Credentials, type Config } from "./credentials.ts";
|
|
84
|
+
import { withPveFormArrays } from "./protocol-form.ts";
|
|
84
85
|
import {
|
|
85
86
|
ParameterVerificationFailed,
|
|
86
87
|
UnknownProxmoxError,
|
|
@@ -112,6 +113,24 @@ export type ProxmoxOpContext = Credentials | HttpClient.HttpClient;
|
|
|
112
113
|
const errorEnvelope = (body: unknown): RestErrorEnvelope | undefined => {
|
|
113
114
|
if (body === null || typeof body !== "object") return undefined;
|
|
114
115
|
const b = body as Record<string, unknown>;
|
|
116
|
+
// PVE's backup read/delete missing-id exception is a 400 with the useful
|
|
117
|
+
// message in errors.id (Backup.pm:406,458 at pve-manager 9.2.11). Expose
|
|
118
|
+
// ONLY that exact sole-field detail to the operation's typed matcher.
|
|
119
|
+
// Multiple errors, other fields, and unrelated validation stay unchanged.
|
|
120
|
+
const errors = b.errors;
|
|
121
|
+
if (
|
|
122
|
+
(b.message === "Parameter verification failed." ||
|
|
123
|
+
b.message === "Parameter verification failed.\n") &&
|
|
124
|
+
errors !== null &&
|
|
125
|
+
typeof errors === "object" &&
|
|
126
|
+
!Array.isArray(errors) &&
|
|
127
|
+
Object.keys(errors).length === 1 &&
|
|
128
|
+
"id" in errors &&
|
|
129
|
+
typeof errors.id === "string" &&
|
|
130
|
+
/^No such job '[^']+'$/.test(errors.id)
|
|
131
|
+
) {
|
|
132
|
+
return { message: errors.id };
|
|
133
|
+
}
|
|
115
134
|
return { message: typeof b.message === "string" ? b.message : undefined };
|
|
116
135
|
};
|
|
117
136
|
|
|
@@ -128,7 +147,7 @@ const PROXMOX_STATUS_MAP: Record<number, new (args: any) => unknown> = {
|
|
|
128
147
|
};
|
|
129
148
|
delete (PROXMOX_STATUS_MAP as Record<number, unknown>)[400];
|
|
130
149
|
|
|
131
|
-
export const ProxmoxProtocol: Layer.Layer<API.Protocol> =
|
|
150
|
+
export const ProxmoxProtocol: Layer.Layer<API.Protocol> = withPveFormArrays(
|
|
132
151
|
makeRestProtocol<Config>({
|
|
133
152
|
// Resolved on the CALLING fiber per request (the layer is memoized per
|
|
134
153
|
// process); the Credentials service holds an effect, so a token rotated
|
|
@@ -203,4 +222,5 @@ export const ProxmoxProtocol: Layer.Layer<API.Protocol> =
|
|
|
203
222
|
}
|
|
204
223
|
return new UnknownProxmoxError({ status, message, body });
|
|
205
224
|
},
|
|
206
|
-
})
|
|
225
|
+
}),
|
|
226
|
+
);
|