@cat-factory/contracts 0.333.0 → 0.335.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/binary-generators.d.ts +4 -4
- package/dist/cache-policy.d.ts +22 -0
- package/dist/cache-policy.d.ts.map +1 -0
- package/dist/cache-policy.js +111 -0
- package/dist/cache-policy.js.map +1 -0
- package/dist/errors.d.ts +24 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +27 -1
- package/dist/errors.js.map +1 -1
- package/dist/foundational-services.d.ts +16 -9
- package/dist/foundational-services.d.ts.map +1 -1
- package/dist/foundational-services.js +20 -1
- package/dist/foundational-services.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/observability.d.ts +57 -0
- package/dist/observability.d.ts.map +1 -1
- package/dist/observability.js +19 -0
- package/dist/observability.js.map +1 -1
- package/dist/openrouter.d.ts +111 -4
- package/dist/openrouter.d.ts.map +1 -1
- package/dist/openrouter.js +39 -1
- package/dist/openrouter.js.map +1 -1
- package/dist/reports.d.ts +70 -1
- package/dist/reports.d.ts.map +1 -1
- package/dist/reports.js +55 -1
- package/dist/reports.js.map +1 -1
- package/dist/reserved-env-keys.d.ts.map +1 -1
- package/dist/reserved-env-keys.js +6 -0
- package/dist/reserved-env-keys.js.map +1 -1
- package/dist/routes/accounts.d.ts +15 -0
- package/dist/routes/accounts.d.ts.map +1 -1
- package/dist/routes/accounts.js +6 -4
- package/dist/routes/accounts.js.map +1 -1
- package/dist/routes/execution.d.ts +4 -0
- package/dist/routes/execution.d.ts.map +1 -1
- package/dist/routes/foundational-services.d.ts +8 -8
- package/dist/routes/index.d.ts +1 -0
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +1 -0
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/openrouter.d.ts +16 -0
- package/dist/routes/openrouter.d.ts.map +1 -1
- package/dist/routes/service-catalog.d.ts +298 -0
- package/dist/routes/service-catalog.d.ts.map +1 -0
- package/dist/routes/service-catalog.js +77 -0
- package/dist/routes/service-catalog.js.map +1 -0
- package/dist/service-catalog.d.ts +223 -0
- package/dist/service-catalog.d.ts.map +1 -0
- package/dist/service-catalog.js +234 -0
- package/dist/service-catalog.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { ContractNoBody } from '@toad-contracts/valibot';
|
|
2
|
+
import * as v from 'valibot';
|
|
3
|
+
/**
|
|
4
|
+
* The connection, or null when the workspace has none.
|
|
5
|
+
*
|
|
6
|
+
* Null rather than a 404, because the SPA renders the connect FORM off this read: a 404 there
|
|
7
|
+
* would make "not connected yet" indistinguishable from "wrong workspace id" at exactly the
|
|
8
|
+
* moment the panel has to decide which of the two to show.
|
|
9
|
+
*/
|
|
10
|
+
export declare const getServiceCatalogContract: {
|
|
11
|
+
readonly method: "get";
|
|
12
|
+
readonly pathResolver: () => string;
|
|
13
|
+
readonly responsesByStatusCode: {
|
|
14
|
+
readonly '4xx': v.ObjectSchema<{
|
|
15
|
+
readonly error: v.ObjectSchema<{
|
|
16
|
+
readonly code: v.StringSchema<undefined>;
|
|
17
|
+
readonly message: v.StringSchema<undefined>;
|
|
18
|
+
readonly details: v.OptionalSchema<v.UnknownSchema, undefined>;
|
|
19
|
+
readonly issues: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
20
|
+
readonly path: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
21
|
+
readonly message: v.StringSchema<undefined>;
|
|
22
|
+
}, undefined>, undefined>, undefined>;
|
|
23
|
+
}, undefined>;
|
|
24
|
+
}, undefined>;
|
|
25
|
+
readonly '5xx': v.ObjectSchema<{
|
|
26
|
+
readonly error: v.ObjectSchema<{
|
|
27
|
+
readonly code: v.StringSchema<undefined>;
|
|
28
|
+
readonly message: v.StringSchema<undefined>;
|
|
29
|
+
readonly details: v.OptionalSchema<v.UnknownSchema, undefined>;
|
|
30
|
+
readonly issues: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
31
|
+
readonly path: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
32
|
+
readonly message: v.StringSchema<undefined>;
|
|
33
|
+
}, undefined>, undefined>, undefined>;
|
|
34
|
+
}, undefined>;
|
|
35
|
+
}, undefined>;
|
|
36
|
+
readonly 200: v.NullableSchema<v.ObjectSchema<{
|
|
37
|
+
readonly provider: v.PicklistSchema<["backstage"], undefined>;
|
|
38
|
+
readonly baseUrl: v.StringSchema<undefined>;
|
|
39
|
+
readonly authMode: v.PicklistSchema<["none", "static-token", "legacy-shared-secret", "oauth2-client-credentials", "basic", "headers"], undefined>;
|
|
40
|
+
readonly entityFilter: v.ArraySchema<v.StringSchema<undefined>, undefined>;
|
|
41
|
+
readonly includeApis: v.BooleanSchema<undefined>;
|
|
42
|
+
readonly maxServices: v.NumberSchema<undefined>;
|
|
43
|
+
readonly lastSyncedAt: v.NullableSchema<v.NumberSchema<undefined>, undefined>;
|
|
44
|
+
readonly lastSyncStatus: v.NullableSchema<v.PicklistSchema<["ok", "partial", "failed"], undefined>, undefined>;
|
|
45
|
+
readonly lastSyncMessage: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
46
|
+
readonly connectedAt: v.NumberSchema<undefined>;
|
|
47
|
+
}, undefined>, undefined>;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Connect or REPLACE the workspace's catalog connection.
|
|
52
|
+
*
|
|
53
|
+
* `PUT` rather than `POST`, because a credential has no meaningful partial edit and a second
|
|
54
|
+
* connection has no meaning: the workspace either points at a portal or it does not. Replacing
|
|
55
|
+
* deliberately does NOT drop what a prior connection imported: the next import reconciles
|
|
56
|
+
* against it, so re-entering a rotated token costs no catalog.
|
|
57
|
+
*/
|
|
58
|
+
export declare const connectServiceCatalogContract: {
|
|
59
|
+
readonly method: "put";
|
|
60
|
+
readonly pathResolver: () => string;
|
|
61
|
+
readonly requestBodySchema: v.ObjectSchema<{
|
|
62
|
+
readonly provider: v.OptionalSchema<v.PicklistSchema<["backstage"], undefined>, undefined>;
|
|
63
|
+
readonly baseUrl: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 500, undefined>]>;
|
|
64
|
+
readonly auth: v.VariantSchema<"mode", [v.ObjectSchema<{
|
|
65
|
+
readonly mode: v.LiteralSchema<"none", undefined>;
|
|
66
|
+
}, undefined>, v.ObjectSchema<{
|
|
67
|
+
readonly mode: v.LiteralSchema<"static-token", undefined>;
|
|
68
|
+
readonly token: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
69
|
+
}, undefined>, v.ObjectSchema<{
|
|
70
|
+
readonly mode: v.LiteralSchema<"legacy-shared-secret", undefined>;
|
|
71
|
+
readonly sharedSecret: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
72
|
+
}, undefined>, v.ObjectSchema<{
|
|
73
|
+
readonly mode: v.LiteralSchema<"oauth2-client-credentials", undefined>;
|
|
74
|
+
readonly tokenUrl: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 500, undefined>]>;
|
|
75
|
+
readonly clientId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
|
|
76
|
+
readonly clientSecret: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
77
|
+
readonly scope: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 500, undefined>]>, undefined>;
|
|
78
|
+
readonly audience: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 500, undefined>]>, undefined>;
|
|
79
|
+
}, undefined>, v.ObjectSchema<{
|
|
80
|
+
readonly mode: v.LiteralSchema<"basic", undefined>;
|
|
81
|
+
readonly username: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
|
|
82
|
+
readonly password: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
83
|
+
}, undefined>, v.ObjectSchema<{
|
|
84
|
+
readonly mode: v.LiteralSchema<"headers", undefined>;
|
|
85
|
+
readonly headers: v.SchemaWithPipe<readonly [v.ArraySchema<v.ObjectSchema<{
|
|
86
|
+
readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 100, undefined>, v.RegexAction<string, "must be a valid HTTP header name">]>;
|
|
87
|
+
readonly value: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>, v.RegexAction<string, "must not contain a line break">]>;
|
|
88
|
+
}, undefined>, undefined>, v.MinLengthAction<{
|
|
89
|
+
name: string;
|
|
90
|
+
value: string;
|
|
91
|
+
}[], 1, undefined>, v.MaxLengthAction<{
|
|
92
|
+
name: string;
|
|
93
|
+
value: string;
|
|
94
|
+
}[], 5, undefined>]>;
|
|
95
|
+
}, undefined>], undefined>;
|
|
96
|
+
readonly entityFilter: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 3, undefined>, v.MaxLengthAction<string, 200, undefined>, v.RegexAction<string, "must be a single `key=value` term (letters, digits and `_.-:/@`)">]>, undefined>, v.MaxLengthAction<string[], 10, undefined>]>, undefined>;
|
|
97
|
+
readonly includeApis: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
98
|
+
readonly maxServices: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>, v.MaxValueAction<number, 1000, undefined>]>, undefined>;
|
|
99
|
+
}, undefined>;
|
|
100
|
+
readonly responsesByStatusCode: {
|
|
101
|
+
readonly '4xx': v.ObjectSchema<{
|
|
102
|
+
readonly error: v.ObjectSchema<{
|
|
103
|
+
readonly code: v.StringSchema<undefined>;
|
|
104
|
+
readonly message: v.StringSchema<undefined>;
|
|
105
|
+
readonly details: v.OptionalSchema<v.UnknownSchema, undefined>;
|
|
106
|
+
readonly issues: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
107
|
+
readonly path: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
108
|
+
readonly message: v.StringSchema<undefined>;
|
|
109
|
+
}, undefined>, undefined>, undefined>;
|
|
110
|
+
}, undefined>;
|
|
111
|
+
}, undefined>;
|
|
112
|
+
readonly '5xx': v.ObjectSchema<{
|
|
113
|
+
readonly error: v.ObjectSchema<{
|
|
114
|
+
readonly code: v.StringSchema<undefined>;
|
|
115
|
+
readonly message: v.StringSchema<undefined>;
|
|
116
|
+
readonly details: v.OptionalSchema<v.UnknownSchema, undefined>;
|
|
117
|
+
readonly issues: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
118
|
+
readonly path: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
119
|
+
readonly message: v.StringSchema<undefined>;
|
|
120
|
+
}, undefined>, undefined>, undefined>;
|
|
121
|
+
}, undefined>;
|
|
122
|
+
}, undefined>;
|
|
123
|
+
readonly 200: v.ObjectSchema<{
|
|
124
|
+
readonly provider: v.PicklistSchema<["backstage"], undefined>;
|
|
125
|
+
readonly baseUrl: v.StringSchema<undefined>;
|
|
126
|
+
readonly authMode: v.PicklistSchema<["none", "static-token", "legacy-shared-secret", "oauth2-client-credentials", "basic", "headers"], undefined>;
|
|
127
|
+
readonly entityFilter: v.ArraySchema<v.StringSchema<undefined>, undefined>;
|
|
128
|
+
readonly includeApis: v.BooleanSchema<undefined>;
|
|
129
|
+
readonly maxServices: v.NumberSchema<undefined>;
|
|
130
|
+
readonly lastSyncedAt: v.NullableSchema<v.NumberSchema<undefined>, undefined>;
|
|
131
|
+
readonly lastSyncStatus: v.NullableSchema<v.PicklistSchema<["ok", "partial", "failed"], undefined>, undefined>;
|
|
132
|
+
readonly lastSyncMessage: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
133
|
+
readonly connectedAt: v.NumberSchema<undefined>;
|
|
134
|
+
}, undefined>;
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Disconnect: forget the credential AND tombstone every foundational service the connection
|
|
139
|
+
* produced.
|
|
140
|
+
*
|
|
141
|
+
* Tombstoning is the point rather than a side effect. Leaving the imported services behind
|
|
142
|
+
* would keep handing agents an estate nothing refreshes and nothing can explain the provenance
|
|
143
|
+
* of, which is worse than an empty catalog because it still reads as current.
|
|
144
|
+
*/
|
|
145
|
+
export declare const disconnectServiceCatalogContract: {
|
|
146
|
+
readonly method: "delete";
|
|
147
|
+
readonly pathResolver: () => string;
|
|
148
|
+
readonly responsesByStatusCode: {
|
|
149
|
+
readonly '4xx': v.ObjectSchema<{
|
|
150
|
+
readonly error: v.ObjectSchema<{
|
|
151
|
+
readonly code: v.StringSchema<undefined>;
|
|
152
|
+
readonly message: v.StringSchema<undefined>;
|
|
153
|
+
readonly details: v.OptionalSchema<v.UnknownSchema, undefined>;
|
|
154
|
+
readonly issues: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
155
|
+
readonly path: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
156
|
+
readonly message: v.StringSchema<undefined>;
|
|
157
|
+
}, undefined>, undefined>, undefined>;
|
|
158
|
+
}, undefined>;
|
|
159
|
+
}, undefined>;
|
|
160
|
+
readonly '5xx': v.ObjectSchema<{
|
|
161
|
+
readonly error: v.ObjectSchema<{
|
|
162
|
+
readonly code: v.StringSchema<undefined>;
|
|
163
|
+
readonly message: v.StringSchema<undefined>;
|
|
164
|
+
readonly details: v.OptionalSchema<v.UnknownSchema, undefined>;
|
|
165
|
+
readonly issues: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
166
|
+
readonly path: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
167
|
+
readonly message: v.StringSchema<undefined>;
|
|
168
|
+
}, undefined>, undefined>, undefined>;
|
|
169
|
+
}, undefined>;
|
|
170
|
+
}, undefined>;
|
|
171
|
+
readonly 204: typeof ContractNoBody;
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Probe the portal with the SUBMITTED credentials, before they are stored.
|
|
176
|
+
*
|
|
177
|
+
* Takes a body rather than reading the stored row, so the operator finds out that a token is
|
|
178
|
+
* wrong while they still have it on screen. It answers a result rather than throwing for the
|
|
179
|
+
* same reason every other connection test does: a refused connection is the answer.
|
|
180
|
+
*/
|
|
181
|
+
export declare const probeServiceCatalogContract: {
|
|
182
|
+
readonly method: "post";
|
|
183
|
+
readonly pathResolver: () => string;
|
|
184
|
+
readonly requestBodySchema: v.ObjectSchema<{
|
|
185
|
+
readonly provider: v.OptionalSchema<v.PicklistSchema<["backstage"], undefined>, undefined>;
|
|
186
|
+
readonly baseUrl: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 500, undefined>]>;
|
|
187
|
+
readonly auth: v.VariantSchema<"mode", [v.ObjectSchema<{
|
|
188
|
+
readonly mode: v.LiteralSchema<"none", undefined>;
|
|
189
|
+
}, undefined>, v.ObjectSchema<{
|
|
190
|
+
readonly mode: v.LiteralSchema<"static-token", undefined>;
|
|
191
|
+
readonly token: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
192
|
+
}, undefined>, v.ObjectSchema<{
|
|
193
|
+
readonly mode: v.LiteralSchema<"legacy-shared-secret", undefined>;
|
|
194
|
+
readonly sharedSecret: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
195
|
+
}, undefined>, v.ObjectSchema<{
|
|
196
|
+
readonly mode: v.LiteralSchema<"oauth2-client-credentials", undefined>;
|
|
197
|
+
readonly tokenUrl: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 500, undefined>]>;
|
|
198
|
+
readonly clientId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
|
|
199
|
+
readonly clientSecret: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
200
|
+
readonly scope: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 500, undefined>]>, undefined>;
|
|
201
|
+
readonly audience: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 500, undefined>]>, undefined>;
|
|
202
|
+
}, undefined>, v.ObjectSchema<{
|
|
203
|
+
readonly mode: v.LiteralSchema<"basic", undefined>;
|
|
204
|
+
readonly username: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
|
|
205
|
+
readonly password: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
206
|
+
}, undefined>, v.ObjectSchema<{
|
|
207
|
+
readonly mode: v.LiteralSchema<"headers", undefined>;
|
|
208
|
+
readonly headers: v.SchemaWithPipe<readonly [v.ArraySchema<v.ObjectSchema<{
|
|
209
|
+
readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 100, undefined>, v.RegexAction<string, "must be a valid HTTP header name">]>;
|
|
210
|
+
readonly value: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>, v.RegexAction<string, "must not contain a line break">]>;
|
|
211
|
+
}, undefined>, undefined>, v.MinLengthAction<{
|
|
212
|
+
name: string;
|
|
213
|
+
value: string;
|
|
214
|
+
}[], 1, undefined>, v.MaxLengthAction<{
|
|
215
|
+
name: string;
|
|
216
|
+
value: string;
|
|
217
|
+
}[], 5, undefined>]>;
|
|
218
|
+
}, undefined>], undefined>;
|
|
219
|
+
readonly entityFilter: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 3, undefined>, v.MaxLengthAction<string, 200, undefined>, v.RegexAction<string, "must be a single `key=value` term (letters, digits and `_.-:/@`)">]>, undefined>, v.MaxLengthAction<string[], 10, undefined>]>, undefined>;
|
|
220
|
+
readonly includeApis: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
221
|
+
readonly maxServices: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>, v.MaxValueAction<number, 1000, undefined>]>, undefined>;
|
|
222
|
+
}, undefined>;
|
|
223
|
+
readonly responsesByStatusCode: {
|
|
224
|
+
readonly '4xx': v.ObjectSchema<{
|
|
225
|
+
readonly error: v.ObjectSchema<{
|
|
226
|
+
readonly code: v.StringSchema<undefined>;
|
|
227
|
+
readonly message: v.StringSchema<undefined>;
|
|
228
|
+
readonly details: v.OptionalSchema<v.UnknownSchema, undefined>;
|
|
229
|
+
readonly issues: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
230
|
+
readonly path: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
231
|
+
readonly message: v.StringSchema<undefined>;
|
|
232
|
+
}, undefined>, undefined>, undefined>;
|
|
233
|
+
}, undefined>;
|
|
234
|
+
}, undefined>;
|
|
235
|
+
readonly '5xx': v.ObjectSchema<{
|
|
236
|
+
readonly error: v.ObjectSchema<{
|
|
237
|
+
readonly code: v.StringSchema<undefined>;
|
|
238
|
+
readonly message: v.StringSchema<undefined>;
|
|
239
|
+
readonly details: v.OptionalSchema<v.UnknownSchema, undefined>;
|
|
240
|
+
readonly issues: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
241
|
+
readonly path: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
242
|
+
readonly message: v.StringSchema<undefined>;
|
|
243
|
+
}, undefined>, undefined>, undefined>;
|
|
244
|
+
}, undefined>;
|
|
245
|
+
}, undefined>;
|
|
246
|
+
readonly 200: v.ObjectSchema<{
|
|
247
|
+
readonly ok: v.BooleanSchema<undefined>;
|
|
248
|
+
readonly message: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
249
|
+
readonly failureCause: v.OptionalSchema<v.PicklistSchema<["refused", "dns", "timeout", "aborted", "unreachable", "reset", "tls-untrusted", "tls-expired", "tls-hostname", "tls-protocol", "invalid-header", "unknown"], undefined>, undefined>;
|
|
250
|
+
readonly warnings: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
251
|
+
readonly code: v.PicklistSchema<["runner_manifest_no_release", "runner_manifest_no_status_path", "github_pat_classic_account_wide", "github_pat_scopes_beyond_need", "github_pat_scope_unreadable", "github_pat_no_scopes"], undefined>;
|
|
252
|
+
readonly message: v.StringSchema<undefined>;
|
|
253
|
+
}, undefined>, undefined>, undefined>;
|
|
254
|
+
}, undefined>;
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
/** Import now, rather than waiting out the autorefresh sweep's staleness window. */
|
|
258
|
+
export declare const syncServiceCatalogContract: {
|
|
259
|
+
readonly method: "post";
|
|
260
|
+
readonly pathResolver: () => string;
|
|
261
|
+
readonly requestBodySchema: typeof ContractNoBody;
|
|
262
|
+
readonly responsesByStatusCode: {
|
|
263
|
+
readonly '4xx': v.ObjectSchema<{
|
|
264
|
+
readonly error: v.ObjectSchema<{
|
|
265
|
+
readonly code: v.StringSchema<undefined>;
|
|
266
|
+
readonly message: v.StringSchema<undefined>;
|
|
267
|
+
readonly details: v.OptionalSchema<v.UnknownSchema, undefined>;
|
|
268
|
+
readonly issues: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
269
|
+
readonly path: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
270
|
+
readonly message: v.StringSchema<undefined>;
|
|
271
|
+
}, undefined>, undefined>, undefined>;
|
|
272
|
+
}, undefined>;
|
|
273
|
+
}, undefined>;
|
|
274
|
+
readonly '5xx': v.ObjectSchema<{
|
|
275
|
+
readonly error: v.ObjectSchema<{
|
|
276
|
+
readonly code: v.StringSchema<undefined>;
|
|
277
|
+
readonly message: v.StringSchema<undefined>;
|
|
278
|
+
readonly details: v.OptionalSchema<v.UnknownSchema, undefined>;
|
|
279
|
+
readonly issues: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
280
|
+
readonly path: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
281
|
+
readonly message: v.StringSchema<undefined>;
|
|
282
|
+
}, undefined>, undefined>, undefined>;
|
|
283
|
+
}, undefined>;
|
|
284
|
+
}, undefined>;
|
|
285
|
+
readonly 200: v.ObjectSchema<{
|
|
286
|
+
readonly upserted: v.NumberSchema<undefined>;
|
|
287
|
+
readonly tombstoned: v.NumberSchema<undefined>;
|
|
288
|
+
readonly unchanged: v.NumberSchema<undefined>;
|
|
289
|
+
readonly contracts: v.NumberSchema<undefined>;
|
|
290
|
+
readonly coverage: v.PicklistSchema<["complete", "truncated", "empty"], undefined>;
|
|
291
|
+
readonly skippedServices: v.NumberSchema<undefined>;
|
|
292
|
+
readonly skippedConflicts: v.NumberSchema<undefined>;
|
|
293
|
+
readonly skippedApis: v.NumberSchema<undefined>;
|
|
294
|
+
readonly status: v.PicklistSchema<["ok", "partial", "failed"], undefined>;
|
|
295
|
+
}, undefined>;
|
|
296
|
+
};
|
|
297
|
+
};
|
|
298
|
+
//# sourceMappingURL=service-catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-catalog.d.ts","sourceRoot":"","sources":["../../src/routes/service-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAqB,MAAM,yBAAyB,CAAA;AAC3E,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAmB5B;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAOpC,CAAA;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKxC,CAAA;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAI3C,CAAA;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKtC,CAAA;AAEF,oFAAoF;AACpF,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKrC,CAAA"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { ContractNoBody, defineApiContract } from '@toad-contracts/valibot';
|
|
2
|
+
import * as v from 'valibot';
|
|
3
|
+
import { connectionTestResultSchema } from '../provider-config.js';
|
|
4
|
+
import { connectServiceCatalogSchema, serviceCatalogConnectionSchema, serviceCatalogSyncResultSchema, } from '../service-catalog.js';
|
|
5
|
+
import { errorResponses } from './_shared.js';
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Service-catalog route contracts. See ServiceCatalogController in
|
|
8
|
+
// @cat-factory/server. Mounted under `/workspaces/:workspaceId` only, so these literals
|
|
9
|
+
// are relative to that prefix and the workspace id is read by the handler.
|
|
10
|
+
//
|
|
11
|
+
// One connection per workspace, so the resource is a SINGLETON: `PUT` replaces it, `GET`
|
|
12
|
+
// reads it, `DELETE` disconnects. There is no id in any path, which is what keeps the
|
|
13
|
+
// import's provenance a fact about the workspace rather than a row a caller has to track.
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
/**
|
|
16
|
+
* The connection, or null when the workspace has none.
|
|
17
|
+
*
|
|
18
|
+
* Null rather than a 404, because the SPA renders the connect FORM off this read: a 404 there
|
|
19
|
+
* would make "not connected yet" indistinguishable from "wrong workspace id" at exactly the
|
|
20
|
+
* moment the panel has to decide which of the two to show.
|
|
21
|
+
*/
|
|
22
|
+
export const getServiceCatalogContract = defineApiContract({
|
|
23
|
+
method: 'get',
|
|
24
|
+
pathResolver: () => '/service-catalog',
|
|
25
|
+
responsesByStatusCode: {
|
|
26
|
+
200: v.nullable(serviceCatalogConnectionSchema),
|
|
27
|
+
...errorResponses,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* Connect or REPLACE the workspace's catalog connection.
|
|
32
|
+
*
|
|
33
|
+
* `PUT` rather than `POST`, because a credential has no meaningful partial edit and a second
|
|
34
|
+
* connection has no meaning: the workspace either points at a portal or it does not. Replacing
|
|
35
|
+
* deliberately does NOT drop what a prior connection imported: the next import reconciles
|
|
36
|
+
* against it, so re-entering a rotated token costs no catalog.
|
|
37
|
+
*/
|
|
38
|
+
export const connectServiceCatalogContract = defineApiContract({
|
|
39
|
+
method: 'put',
|
|
40
|
+
pathResolver: () => '/service-catalog',
|
|
41
|
+
requestBodySchema: connectServiceCatalogSchema,
|
|
42
|
+
responsesByStatusCode: { 200: serviceCatalogConnectionSchema, ...errorResponses },
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* Disconnect: forget the credential AND tombstone every foundational service the connection
|
|
46
|
+
* produced.
|
|
47
|
+
*
|
|
48
|
+
* Tombstoning is the point rather than a side effect. Leaving the imported services behind
|
|
49
|
+
* would keep handing agents an estate nothing refreshes and nothing can explain the provenance
|
|
50
|
+
* of, which is worse than an empty catalog because it still reads as current.
|
|
51
|
+
*/
|
|
52
|
+
export const disconnectServiceCatalogContract = defineApiContract({
|
|
53
|
+
method: 'delete',
|
|
54
|
+
pathResolver: () => '/service-catalog',
|
|
55
|
+
responsesByStatusCode: { 204: ContractNoBody, ...errorResponses },
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Probe the portal with the SUBMITTED credentials, before they are stored.
|
|
59
|
+
*
|
|
60
|
+
* Takes a body rather than reading the stored row, so the operator finds out that a token is
|
|
61
|
+
* wrong while they still have it on screen. It answers a result rather than throwing for the
|
|
62
|
+
* same reason every other connection test does: a refused connection is the answer.
|
|
63
|
+
*/
|
|
64
|
+
export const probeServiceCatalogContract = defineApiContract({
|
|
65
|
+
method: 'post',
|
|
66
|
+
pathResolver: () => '/service-catalog/probe',
|
|
67
|
+
requestBodySchema: connectServiceCatalogSchema,
|
|
68
|
+
responsesByStatusCode: { 200: connectionTestResultSchema, ...errorResponses },
|
|
69
|
+
});
|
|
70
|
+
/** Import now, rather than waiting out the autorefresh sweep's staleness window. */
|
|
71
|
+
export const syncServiceCatalogContract = defineApiContract({
|
|
72
|
+
method: 'post',
|
|
73
|
+
pathResolver: () => '/service-catalog/sync',
|
|
74
|
+
requestBodySchema: ContractNoBody,
|
|
75
|
+
responsesByStatusCode: { 200: serviceCatalogSyncResultSchema, ...errorResponses },
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=service-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-catalog.js","sourceRoot":"","sources":["../../src/routes/service-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3E,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAA;AAClE,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,EAC9B,8BAA8B,GAC/B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE7C,8EAA8E;AAC9E,mEAAmE;AACnE,wFAAwF;AACxF,2EAA2E;AAC3E,EAAE;AACF,yFAAyF;AACzF,sFAAsF;AACtF,0FAA0F;AAC1F,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,iBAAiB,CAAC;IACzD,MAAM,EAAE,KAAK;IACb,YAAY,EAAE,GAAG,EAAE,CAAC,kBAAkB;IACtC,qBAAqB,EAAE;QACrB,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,8BAA8B,CAAC;QAC/C,GAAG,cAAc;KAClB;CACF,CAAC,CAAA;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,iBAAiB,CAAC;IAC7D,MAAM,EAAE,KAAK;IACb,YAAY,EAAE,GAAG,EAAE,CAAC,kBAAkB;IACtC,iBAAiB,EAAE,2BAA2B;IAC9C,qBAAqB,EAAE,EAAE,GAAG,EAAE,8BAA8B,EAAE,GAAG,cAAc,EAAE;CAClF,CAAC,CAAA;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,iBAAiB,CAAC;IAChE,MAAM,EAAE,QAAQ;IAChB,YAAY,EAAE,GAAG,EAAE,CAAC,kBAAkB;IACtC,qBAAqB,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE;CAClE,CAAC,CAAA;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,iBAAiB,CAAC;IAC3D,MAAM,EAAE,MAAM;IACd,YAAY,EAAE,GAAG,EAAE,CAAC,wBAAwB;IAC5C,iBAAiB,EAAE,2BAA2B;IAC9C,qBAAqB,EAAE,EAAE,GAAG,EAAE,0BAA0B,EAAE,GAAG,cAAc,EAAE;CAC9E,CAAC,CAAA;AAEF,oFAAoF;AACpF,MAAM,CAAC,MAAM,0BAA0B,GAAG,iBAAiB,CAAC;IAC1D,MAAM,EAAE,MAAM;IACd,YAAY,EAAE,GAAG,EAAE,CAAC,uBAAuB;IAC3C,iBAAiB,EAAE,cAAc;IACjC,qBAAqB,EAAE,EAAE,GAAG,EAAE,8BAA8B,EAAE,GAAG,cAAc,EAAE;CAClF,CAAC,CAAA"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
/**
|
|
3
|
+
* Which developer-portal product a connection talks to.
|
|
4
|
+
*
|
|
5
|
+
* A picklist with one member rather than a bare literal, because the read surface, the SPA and
|
|
6
|
+
* the stored row all name it: adding Port / Cortex / OpsLevel later is a member plus an adapter,
|
|
7
|
+
* and every `Record<ServiceCatalogProvider, …>` fails to compile until it is mapped. The
|
|
8
|
+
* platform-neutral vocabulary below (`ServiceCatalogEntry` in the kernel) is what the importer
|
|
9
|
+
* consumes, so nothing downstream of the adapter knows the word "Backstage".
|
|
10
|
+
*/
|
|
11
|
+
export declare const serviceCatalogProviderSchema: v.PicklistSchema<["backstage"], undefined>;
|
|
12
|
+
export type ServiceCatalogProvider = v.InferOutput<typeof serviceCatalogProviderSchema>;
|
|
13
|
+
/**
|
|
14
|
+
* How the platform authenticates to a SELF-HOSTED portal.
|
|
15
|
+
*
|
|
16
|
+
* These are the shapes organisations actually run Backstage behind, and each needs a different
|
|
17
|
+
* request built, which is why this is a closed vocabulary rather than a free-form header bag:
|
|
18
|
+
*
|
|
19
|
+
* - `none`: no auth on the catalog API. Real, and common on an instance reachable only inside a
|
|
20
|
+
* VPN. It is admissible ONLY because the base URL is held to the deployment's
|
|
21
|
+
* `UrlSafetyPolicy`, so reaching a private host is an operator decision already made.
|
|
22
|
+
* - `static-token`: a service-to-service token from Backstage's `backend.auth.externalAccess`
|
|
23
|
+
* (`type: static`), sent as `Authorization: Bearer <token>`. The vendor's own recommended
|
|
24
|
+
* way for an external system to read the catalog.
|
|
25
|
+
* - `legacy-shared-secret`: the older external-access route, still what a great many
|
|
26
|
+
* self-hosted instances are configured for: a short-lived HS256 JWT signed with a secret
|
|
27
|
+
* from `backend.auth.keys[]`. The platform MINTS the token per request rather than storing
|
|
28
|
+
* one, which is why the stored credential is the secret and not a bearer value.
|
|
29
|
+
* - `oauth2-client-credentials`: the portal sits behind an IdP or an identity-aware proxy
|
|
30
|
+
* (Keycloak, Okta, Entra, Google IAP). The platform exchanges a client id/secret at the
|
|
31
|
+
* token endpoint and sends the result as a bearer token.
|
|
32
|
+
* - `basic`: HTTP Basic, i.e. a reverse proxy in front of the portal.
|
|
33
|
+
* - `headers`: an explicit header list, for a gateway that authenticates on its own header
|
|
34
|
+
* names. A LIST rather than one pair because the common case needs two (a Cloudflare Access
|
|
35
|
+
* service token is `CF-Access-Client-Id` plus `CF-Access-Client-Secret`), and a single-pair
|
|
36
|
+
* shape would have sent half a credential.
|
|
37
|
+
*/
|
|
38
|
+
export declare const serviceCatalogAuthModeSchema: v.PicklistSchema<["none", "static-token", "legacy-shared-secret", "oauth2-client-credentials", "basic", "headers"], undefined>;
|
|
39
|
+
export type ServiceCatalogAuthMode = v.InferOutput<typeof serviceCatalogAuthModeSchema>;
|
|
40
|
+
/** The credential half of a connection, discriminated by the auth mode it belongs to. */
|
|
41
|
+
export declare const serviceCatalogAuthSchema: v.VariantSchema<"mode", [v.ObjectSchema<{
|
|
42
|
+
readonly mode: v.LiteralSchema<"none", undefined>;
|
|
43
|
+
}, undefined>, v.ObjectSchema<{
|
|
44
|
+
readonly mode: v.LiteralSchema<"static-token", undefined>;
|
|
45
|
+
readonly token: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
46
|
+
}, undefined>, v.ObjectSchema<{
|
|
47
|
+
readonly mode: v.LiteralSchema<"legacy-shared-secret", undefined>;
|
|
48
|
+
readonly sharedSecret: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
49
|
+
}, undefined>, v.ObjectSchema<{
|
|
50
|
+
readonly mode: v.LiteralSchema<"oauth2-client-credentials", undefined>;
|
|
51
|
+
/** The IdP's token endpoint. Held to the same URL policy as the portal's own base URL. */
|
|
52
|
+
readonly tokenUrl: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 500, undefined>]>;
|
|
53
|
+
readonly clientId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
|
|
54
|
+
readonly clientSecret: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
55
|
+
/** Optional `scope` / `audience` request parameters some IdPs require. */
|
|
56
|
+
readonly scope: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 500, undefined>]>, undefined>;
|
|
57
|
+
readonly audience: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 500, undefined>]>, undefined>;
|
|
58
|
+
}, undefined>, v.ObjectSchema<{
|
|
59
|
+
readonly mode: v.LiteralSchema<"basic", undefined>;
|
|
60
|
+
readonly username: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
|
|
61
|
+
readonly password: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
62
|
+
}, undefined>, v.ObjectSchema<{
|
|
63
|
+
readonly mode: v.LiteralSchema<"headers", undefined>;
|
|
64
|
+
readonly headers: v.SchemaWithPipe<readonly [v.ArraySchema<v.ObjectSchema<{
|
|
65
|
+
readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 100, undefined>, v.RegexAction<string, "must be a valid HTTP header name">]>;
|
|
66
|
+
readonly value: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>, v.RegexAction<string, "must not contain a line break">]>;
|
|
67
|
+
}, undefined>, undefined>, v.MinLengthAction<{
|
|
68
|
+
name: string;
|
|
69
|
+
value: string;
|
|
70
|
+
}[], 1, undefined>, v.MaxLengthAction<{
|
|
71
|
+
name: string;
|
|
72
|
+
value: string;
|
|
73
|
+
}[], 5, undefined>]>;
|
|
74
|
+
}, undefined>], undefined>;
|
|
75
|
+
export type ServiceCatalogAuth = v.InferOutput<typeof serviceCatalogAuthSchema>;
|
|
76
|
+
/**
|
|
77
|
+
* The default filter, applied when a connection names none: the portal's SERVICE-like
|
|
78
|
+
* components.
|
|
79
|
+
*
|
|
80
|
+
* A default rather than a required field, because the honest alternative is worse in both
|
|
81
|
+
* directions. Importing the WHOLE catalog would fold a thousand-entity estate into every
|
|
82
|
+
* design prompt (the exact cost ADR 0031 split the catalog and contract reads to avoid), while
|
|
83
|
+
* refusing to import without a filter makes the first connection fail on a vendor query language
|
|
84
|
+
* the operator has no reason to know yet. `kind=component` is the one term that is right for
|
|
85
|
+
* every Backstage instance, and a narrower estate (a tag, a system, an owner) is one term more.
|
|
86
|
+
*/
|
|
87
|
+
export declare const DEFAULT_SERVICE_CATALOG_FILTER: readonly string[];
|
|
88
|
+
/** How many services ONE import may bring in, and the ceiling on that number. */
|
|
89
|
+
export declare const DEFAULT_MAX_CATALOG_SERVICES = 200;
|
|
90
|
+
export declare const MAX_CATALOG_SERVICES_CEILING = 1000;
|
|
91
|
+
/** Connect (or re-connect) the workspace's service catalog. Replaces any prior connection. */
|
|
92
|
+
export declare const connectServiceCatalogSchema: v.ObjectSchema<{
|
|
93
|
+
readonly provider: v.OptionalSchema<v.PicklistSchema<["backstage"], undefined>, undefined>;
|
|
94
|
+
/** The portal's base URL, e.g. `https://backstage.corp.internal`. */
|
|
95
|
+
readonly baseUrl: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 500, undefined>]>;
|
|
96
|
+
readonly auth: v.VariantSchema<"mode", [v.ObjectSchema<{
|
|
97
|
+
readonly mode: v.LiteralSchema<"none", undefined>;
|
|
98
|
+
}, undefined>, v.ObjectSchema<{
|
|
99
|
+
readonly mode: v.LiteralSchema<"static-token", undefined>;
|
|
100
|
+
readonly token: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
101
|
+
}, undefined>, v.ObjectSchema<{
|
|
102
|
+
readonly mode: v.LiteralSchema<"legacy-shared-secret", undefined>;
|
|
103
|
+
readonly sharedSecret: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
104
|
+
}, undefined>, v.ObjectSchema<{
|
|
105
|
+
readonly mode: v.LiteralSchema<"oauth2-client-credentials", undefined>;
|
|
106
|
+
/** The IdP's token endpoint. Held to the same URL policy as the portal's own base URL. */
|
|
107
|
+
readonly tokenUrl: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 500, undefined>]>;
|
|
108
|
+
readonly clientId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
|
|
109
|
+
readonly clientSecret: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
110
|
+
/** Optional `scope` / `audience` request parameters some IdPs require. */
|
|
111
|
+
readonly scope: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 500, undefined>]>, undefined>;
|
|
112
|
+
readonly audience: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 500, undefined>]>, undefined>;
|
|
113
|
+
}, undefined>, v.ObjectSchema<{
|
|
114
|
+
readonly mode: v.LiteralSchema<"basic", undefined>;
|
|
115
|
+
readonly username: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
|
|
116
|
+
readonly password: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
|
|
117
|
+
}, undefined>, v.ObjectSchema<{
|
|
118
|
+
readonly mode: v.LiteralSchema<"headers", undefined>;
|
|
119
|
+
readonly headers: v.SchemaWithPipe<readonly [v.ArraySchema<v.ObjectSchema<{
|
|
120
|
+
readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 100, undefined>, v.RegexAction<string, "must be a valid HTTP header name">]>;
|
|
121
|
+
readonly value: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>, v.RegexAction<string, "must not contain a line break">]>;
|
|
122
|
+
}, undefined>, undefined>, v.MinLengthAction<{
|
|
123
|
+
name: string;
|
|
124
|
+
value: string;
|
|
125
|
+
}[], 1, undefined>, v.MaxLengthAction<{
|
|
126
|
+
name: string;
|
|
127
|
+
value: string;
|
|
128
|
+
}[], 5, undefined>]>;
|
|
129
|
+
}, undefined>], undefined>;
|
|
130
|
+
/**
|
|
131
|
+
* Portal-side filter terms, ANDed. Empty/absent ⇒ {@link DEFAULT_SERVICE_CATALOG_FILTER}.
|
|
132
|
+
* Filtering AT THE PORTAL rather than after the fetch is what keeps a large estate from being
|
|
133
|
+
* paged through in full on every refresh.
|
|
134
|
+
*/
|
|
135
|
+
readonly entityFilter: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 3, undefined>, v.MaxLengthAction<string, 200, undefined>, v.RegexAction<string, "must be a single `key=value` term (letters, digits and `_.-:/@`)">]>, undefined>, v.MaxLengthAction<string[], 10, undefined>]>, undefined>;
|
|
136
|
+
/**
|
|
137
|
+
* Whether to import the API definitions each service publishes (`spec.providesApis`).
|
|
138
|
+
* Defaults to true, being the half of the ask that lets a consumer call a shared service
|
|
139
|
+
* rather than merely know it exists.
|
|
140
|
+
*/
|
|
141
|
+
readonly includeApis: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
142
|
+
/** Cap on imported services. Defaults to {@link DEFAULT_MAX_CATALOG_SERVICES}. */
|
|
143
|
+
readonly maxServices: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>, v.MaxValueAction<number, 1000, undefined>]>, undefined>;
|
|
144
|
+
}, undefined>;
|
|
145
|
+
export type ConnectServiceCatalogInput = v.InferOutput<typeof connectServiceCatalogSchema>;
|
|
146
|
+
/**
|
|
147
|
+
* How much of the portal's matching estate one import covered.
|
|
148
|
+
*
|
|
149
|
+
* Three states rather than a count, for the reason the repo-source `folderScan` coverage has
|
|
150
|
+
* three: each needs a different fix from the person who connected it, and `truncated` must never
|
|
151
|
+
* read as `complete`. An importer that reported only "42 services" would leave an operator with
|
|
152
|
+
* a 300-service estate believing the catalog is the estate.
|
|
153
|
+
*/
|
|
154
|
+
export declare const serviceCatalogCoverageSchema: v.PicklistSchema<["complete", "truncated", "empty"], undefined>;
|
|
155
|
+
export type ServiceCatalogCoverage = v.InferOutput<typeof serviceCatalogCoverageSchema>;
|
|
156
|
+
/** What the LAST import concluded, as the management surface reports it. */
|
|
157
|
+
export declare const serviceCatalogSyncStatusSchema: v.PicklistSchema<["ok", "partial", "failed"], undefined>;
|
|
158
|
+
export type ServiceCatalogSyncStatus = v.InferOutput<typeof serviceCatalogSyncStatusSchema>;
|
|
159
|
+
/**
|
|
160
|
+
* The connection as the management surface sees it: never a credential, not even a masked one.
|
|
161
|
+
*
|
|
162
|
+
* `authMode` is here because it is the one part of the credential that is configuration rather
|
|
163
|
+
* than secret, because the operator has to see WHICH scheme a stored connection uses to know whether
|
|
164
|
+
* it still matches how the portal is deployed.
|
|
165
|
+
*/
|
|
166
|
+
export declare const serviceCatalogConnectionSchema: v.ObjectSchema<{
|
|
167
|
+
readonly provider: v.PicklistSchema<["backstage"], undefined>;
|
|
168
|
+
readonly baseUrl: v.StringSchema<undefined>;
|
|
169
|
+
readonly authMode: v.PicklistSchema<["none", "static-token", "legacy-shared-secret", "oauth2-client-credentials", "basic", "headers"], undefined>;
|
|
170
|
+
readonly entityFilter: v.ArraySchema<v.StringSchema<undefined>, undefined>;
|
|
171
|
+
readonly includeApis: v.BooleanSchema<undefined>;
|
|
172
|
+
readonly maxServices: v.NumberSchema<undefined>;
|
|
173
|
+
readonly lastSyncedAt: v.NullableSchema<v.NumberSchema<undefined>, undefined>;
|
|
174
|
+
readonly lastSyncStatus: v.NullableSchema<v.PicklistSchema<["ok", "partial", "failed"], undefined>, undefined>;
|
|
175
|
+
/**
|
|
176
|
+
* What the last import wants a human to know: the truncation, the unreadable definitions, or
|
|
177
|
+
* the transport failure. Null when the last pass had nothing to report, which is the only
|
|
178
|
+
* state that needs no sentence.
|
|
179
|
+
*/
|
|
180
|
+
readonly lastSyncMessage: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
181
|
+
readonly connectedAt: v.NumberSchema<undefined>;
|
|
182
|
+
}, undefined>;
|
|
183
|
+
export type ServiceCatalogConnection = v.InferOutput<typeof serviceCatalogConnectionSchema>;
|
|
184
|
+
/** Outcome of one import: what changed in the catalog, and what the pass could not do. */
|
|
185
|
+
export declare const serviceCatalogSyncResultSchema: v.ObjectSchema<{
|
|
186
|
+
readonly upserted: v.NumberSchema<undefined>;
|
|
187
|
+
/** Services this connection produced before and the portal no longer offers. */
|
|
188
|
+
readonly tombstoned: v.NumberSchema<undefined>;
|
|
189
|
+
readonly unchanged: v.NumberSchema<undefined>;
|
|
190
|
+
/** API definitions stored across every imported service. */
|
|
191
|
+
readonly contracts: v.NumberSchema<undefined>;
|
|
192
|
+
readonly coverage: v.PicklistSchema<["complete", "truncated", "empty"], undefined>;
|
|
193
|
+
/**
|
|
194
|
+
* Entities the filter matched that did NOT become a service: no usable identity, or a name
|
|
195
|
+
* that yields no slug. Zero and "nothing matched" are told apart by {@link coverage}, and a
|
|
196
|
+
* non-zero value here is the only thing that explains a catalog thinner than the portal's
|
|
197
|
+
* own entity count.
|
|
198
|
+
*/
|
|
199
|
+
readonly skippedServices: v.NumberSchema<undefined>;
|
|
200
|
+
/**
|
|
201
|
+
* Portal services this pass REFUSED to write because the workspace already registers a service
|
|
202
|
+
* under that id by another route (an upload, a linked repo).
|
|
203
|
+
*
|
|
204
|
+
* Its own count rather than folded into {@link skippedServices}, because the two name opposite
|
|
205
|
+
* faults with opposite remedies: a skipped service is an entity the PORTAL describes in a way
|
|
206
|
+
* this platform cannot use, and this is a collision between two things the workspace itself
|
|
207
|
+
* did. Refusing is the only safe disposition, since overwriting would silently replace a
|
|
208
|
+
* hand-authored service (and its uploaded contracts, and any platform capability it was granted)
|
|
209
|
+
* with the portal's row, and disconnecting would then tombstone the original.
|
|
210
|
+
*/
|
|
211
|
+
readonly skippedConflicts: v.NumberSchema<undefined>;
|
|
212
|
+
/**
|
|
213
|
+
* API definitions a service DECLARES that this pass could not store: a type the platform
|
|
214
|
+
* serves no format for, an entity the portal would not return, an empty or oversized
|
|
215
|
+
* definition, or an id that collides with another interface of the same service. Reported
|
|
216
|
+
* rather than dropped, because a service listed with no interface reads to an agent as a
|
|
217
|
+
* service that publishes none.
|
|
218
|
+
*/
|
|
219
|
+
readonly skippedApis: v.NumberSchema<undefined>;
|
|
220
|
+
readonly status: v.PicklistSchema<["ok", "partial", "failed"], undefined>;
|
|
221
|
+
}, undefined>;
|
|
222
|
+
export type ServiceCatalogSyncResult = v.InferOutput<typeof serviceCatalogSyncResultSchema>;
|
|
223
|
+
//# sourceMappingURL=service-catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-catalog.d.ts","sourceRoot":"","sources":["../src/service-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAqB5B;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,4CAA4B,CAAA;AACrE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,4BAA4B,CAAC,CAAA;AAEvF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,4BAA4B,gIAOvC,CAAA;AACF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,4BAA4B,CAAC,CAAA;AA0BvF,yFAAyF;AACzF,eAAO,MAAM,wBAAwB;;;;;;;;;;IAMjC,0FAA0F;;;;IAI1F,0EAA0E;;;;;;;;;;;;;;;;;;;0BAa5E,CAAA;AACF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,wBAAwB,CAAC,CAAA;AAqB/E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,EAAE,SAAS,MAAM,EAAuB,CAAA;AAEnF,iFAAiF;AACjF,eAAO,MAAM,4BAA4B,MAAM,CAAA;AAC/C,eAAO,MAAM,4BAA4B,OAAQ,CAAA;AAEjD,8FAA8F;AAC9F,eAAO,MAAM,2BAA2B;;IAEtC,qEAAqE;;;;;;;;;;;;QA3DnE,0FAA0F;;;;QAI1F,0EAA0E;;;;;;;;;;;;;;;;;;;;IA0D5E;;;;OAIG;;IAEH;;;;OAIG;;IAEH,kFAAkF;;aAIlF,CAAA;AACF,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAE1F;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,iEAWvC,CAAA;AACF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,4BAA4B,CAAC,CAAA;AAEvF,4EAA4E;AAC5E,eAAO,MAAM,8BAA8B,0DAWzC,CAAA;AACF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,8BAA8B,CAAC,CAAA;AAE3F;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B;;;;;;;;;IASzC;;;;OAIG;;;aAGH,CAAA;AACF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,8BAA8B,CAAC,CAAA;AAE3F,0FAA0F;AAC1F,eAAO,MAAM,8BAA8B;;IAEzC,gFAAgF;;;IAGhF,4DAA4D;;;IAG5D;;;;;OAKG;;IAEH;;;;;;;;;;OAUG;;IAEH;;;;;;OAMG;;;aAGH,CAAA;AACF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,8BAA8B,CAAC,CAAA"}
|