@adobe/spacecat-shared-project-engine-client 1.12.0 → 1.14.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/package.json +1 -1
- package/src/errors.js +48 -0
- package/src/index.d.ts +306 -1
- package/src/index.js +2 -0
- package/src/rest-transport.js +238 -0
package/package.json
CHANGED
package/src/errors.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// @ts-check
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The single typed error the transport facade throws from its `unwrap` seam. It carries the
|
|
17
|
+
* failing HTTP `method`, the response `status` (or `undefined` when there was no HTTP response —
|
|
18
|
+
* i.e. an exhausted-network / per-attempt-timeout failure), and the normalized parsed error
|
|
19
|
+
* `body`. On the network/timeout path the original thrown error is preserved as `cause`.
|
|
20
|
+
*
|
|
21
|
+
* This class does NOT translate the failure into an HTTP status for the consumer, redact the
|
|
22
|
+
* body, or map it onto a domain error — those are consumer-owned per ADR-0001. It exists only to
|
|
23
|
+
* give consumers a single `instanceof`-checkable type with the raw `{ status, method, body }`.
|
|
24
|
+
*/
|
|
25
|
+
export class ProjectEngineApiError extends Error {
|
|
26
|
+
/**
|
|
27
|
+
* @param {number | undefined} status the HTTP response status, or `undefined` when there was no
|
|
28
|
+
* HTTP response (network / timeout failure)
|
|
29
|
+
* @param {string} method the HTTP method of the failing request
|
|
30
|
+
* @param {unknown} body the normalized parsed error body (`null` when empty/absent)
|
|
31
|
+
* @param {{ cause?: unknown }} [options] optional `{ cause }` forwarded to `super`, so a wrapped
|
|
32
|
+
* network/timeout error keeps its original as `.cause`
|
|
33
|
+
*/
|
|
34
|
+
constructor(status, method, body, options) {
|
|
35
|
+
const message = status === undefined
|
|
36
|
+
? `Project Engine ${method} request failed`
|
|
37
|
+
: `Project Engine ${method} request failed with status ${status}`;
|
|
38
|
+
super(message, options);
|
|
39
|
+
/** @type {string} */
|
|
40
|
+
this.name = 'ProjectEngineApiError';
|
|
41
|
+
/** @type {number | undefined} */
|
|
42
|
+
this.status = status;
|
|
43
|
+
/** @type {string} */
|
|
44
|
+
this.method = method;
|
|
45
|
+
/** @type {unknown} */
|
|
46
|
+
this.body = body;
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import type { Client } from 'openapi-fetch';
|
|
13
|
+
import type { Client, FetchResponse, MaybeOptionalInit, MediaType } from 'openapi-fetch';
|
|
14
|
+
import type { RequiredKeysOf } from 'openapi-typescript-helpers';
|
|
14
15
|
import type { paths, components } from './generated/types.js';
|
|
15
16
|
|
|
16
17
|
/** Supplies the caller's IMS JWT — forwarded verbatim, never minted or exchanged. */
|
|
@@ -73,5 +74,309 @@ export declare function createSerenityProjectEngineApiClient(
|
|
|
73
74
|
options: SerenityProjectEngineApiClientOptions,
|
|
74
75
|
): SerenityProjectEngineApiClient;
|
|
75
76
|
|
|
77
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
78
|
+
// Intent-named facade (transport) over the raw client.
|
|
79
|
+
//
|
|
80
|
+
// The three helpers below derive every facade method's parameter and return type
|
|
81
|
+
// straight from the generated `paths` contract, so the surface stays strictly
|
|
82
|
+
// in-spec and never degrades to `any`. They are internal to this declaration.
|
|
83
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The openapi-fetch `init` argument (params.path/query, body) accepted for a given
|
|
87
|
+
* path `P` + HTTP method `M`, derived from the generated contract.
|
|
88
|
+
*/
|
|
89
|
+
type TransportInit<P extends keyof paths, M extends keyof paths[P]> = MaybeOptionalInit<
|
|
90
|
+
paths[P],
|
|
91
|
+
M
|
|
92
|
+
>;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Mirror of openapi-fetch's own (unexported) `InitParam`: the `init` argument is
|
|
96
|
+
* OPTIONAL when nothing in it is required (no path/query params, no required body),
|
|
97
|
+
* and REQUIRED otherwise — so `listLanguages()` needs no argument while
|
|
98
|
+
* `createProject({ params, body })` enforces its params + body at the call site.
|
|
99
|
+
*/
|
|
100
|
+
type TransportInitParam<Init> = RequiredKeysOf<Init> extends never
|
|
101
|
+
? [init?: Init]
|
|
102
|
+
: [init: Init];
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The value a facade method resolves with: the parsed 2xx body for path `P` +
|
|
106
|
+
* method `M`, or `null` for an empty body (e.g. a 204 / empty-body ack). Non-2xx
|
|
107
|
+
* responses never resolve — they throw at the single `unwrap` error seam.
|
|
108
|
+
*/
|
|
109
|
+
type TransportData<P extends keyof paths, M extends keyof paths[P]> =
|
|
110
|
+
| NonNullable<FetchResponse<paths[P][M], TransportInit<P, M>, MediaType>['data']>
|
|
111
|
+
| null;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Intent-named facade over {@link SerenityProjectEngineApiClient}. Wraps the 28 in-spec
|
|
115
|
+
* Project Engine operations spacecat-api-service consumes behind verb+resource methods, so
|
|
116
|
+
* consumers depend on this seam rather than the raw client's literal path strings. Each method
|
|
117
|
+
* is THIN: it forwards the caller's openapi-fetch `init` to the underlying client and resolves
|
|
118
|
+
* with the unwrapped 2xx body (or throws on a non-2xx / network error at a single seam). No
|
|
119
|
+
* caching, redaction, error→HTTP translation, or composite methods — all consumer-owned per
|
|
120
|
+
* ADR-0001. The remaining generated operations stay reachable via the raw client.
|
|
121
|
+
*/
|
|
122
|
+
export interface SerenityProjectEngineTransport {
|
|
123
|
+
/** GET /v1/languages — projects-admin-list-languages */
|
|
124
|
+
listLanguages(
|
|
125
|
+
...init: TransportInitParam<TransportInit<'/v1/languages', 'get'>>
|
|
126
|
+
): Promise<TransportData<'/v1/languages', 'get'>>;
|
|
127
|
+
/** GET /v1/ai_models — ai-list-global-models */
|
|
128
|
+
listGlobalAiModels(
|
|
129
|
+
...init: TransportInitParam<TransportInit<'/v1/ai_models', 'get'>>
|
|
130
|
+
): Promise<TransportData<'/v1/ai_models', 'get'>>;
|
|
131
|
+
|
|
132
|
+
/** GET /v1/workspaces/{id}/projects — projects-list-projects */
|
|
133
|
+
listProjects(
|
|
134
|
+
...init: TransportInitParam<TransportInit<'/v1/workspaces/{id}/projects', 'get'>>
|
|
135
|
+
): Promise<TransportData<'/v1/workspaces/{id}/projects', 'get'>>;
|
|
136
|
+
/** POST /v1/workspaces/{id}/projects — projects-post-project */
|
|
137
|
+
createProject(
|
|
138
|
+
...init: TransportInitParam<TransportInit<'/v1/workspaces/{id}/projects', 'post'>>
|
|
139
|
+
): Promise<TransportData<'/v1/workspaces/{id}/projects', 'post'>>;
|
|
140
|
+
/** GET /v1/workspaces/{id}/projects/{project_id} — projects-get-project */
|
|
141
|
+
getProject(
|
|
142
|
+
...init: TransportInitParam<TransportInit<'/v1/workspaces/{id}/projects/{project_id}', 'get'>>
|
|
143
|
+
): Promise<TransportData<'/v1/workspaces/{id}/projects/{project_id}', 'get'>>;
|
|
144
|
+
/** PATCH /v1/workspaces/{id}/projects/{project_id} — projects-patch-project */
|
|
145
|
+
updateProject(
|
|
146
|
+
...init: TransportInitParam<TransportInit<'/v1/workspaces/{id}/projects/{project_id}', 'patch'>>
|
|
147
|
+
): Promise<TransportData<'/v1/workspaces/{id}/projects/{project_id}', 'patch'>>;
|
|
148
|
+
/** DELETE /v1/workspaces/{id}/projects/{project_id} — projects-delete-project */
|
|
149
|
+
deleteProject(
|
|
150
|
+
...init: TransportInitParam<
|
|
151
|
+
TransportInit<'/v1/workspaces/{id}/projects/{project_id}', 'delete'>
|
|
152
|
+
>
|
|
153
|
+
): Promise<TransportData<'/v1/workspaces/{id}/projects/{project_id}', 'delete'>>;
|
|
154
|
+
/** POST /v1/workspaces/{id}/projects/{project_id}/publish — projects-publish-project */
|
|
155
|
+
publishProject(
|
|
156
|
+
...init: TransportInitParam<
|
|
157
|
+
TransportInit<'/v1/workspaces/{id}/projects/{project_id}/publish', 'post'>
|
|
158
|
+
>
|
|
159
|
+
): Promise<TransportData<'/v1/workspaces/{id}/projects/{project_id}/publish', 'post'>>;
|
|
160
|
+
|
|
161
|
+
/** GET /v1/workspaces/{id}/projects/{project_id}/ai_models — ai-list-models */
|
|
162
|
+
listAiModels(
|
|
163
|
+
...init: TransportInitParam<
|
|
164
|
+
TransportInit<'/v1/workspaces/{id}/projects/{project_id}/ai_models', 'get'>
|
|
165
|
+
>
|
|
166
|
+
): Promise<TransportData<'/v1/workspaces/{id}/projects/{project_id}/ai_models', 'get'>>;
|
|
167
|
+
/** DELETE /v1/workspaces/{id}/projects/{project_id}/ai_models — ai-delete-models */
|
|
168
|
+
deleteAiModels(
|
|
169
|
+
...init: TransportInitParam<
|
|
170
|
+
TransportInit<'/v1/workspaces/{id}/projects/{project_id}/ai_models', 'delete'>
|
|
171
|
+
>
|
|
172
|
+
): Promise<TransportData<'/v1/workspaces/{id}/projects/{project_id}/ai_models', 'delete'>>;
|
|
173
|
+
/** GET /v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks — ai-list-benchmarks */
|
|
174
|
+
listBenchmarks(
|
|
175
|
+
...init: TransportInitParam<
|
|
176
|
+
TransportInit<'/v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks', 'get'>
|
|
177
|
+
>
|
|
178
|
+
): Promise<
|
|
179
|
+
TransportData<'/v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks', 'get'>
|
|
180
|
+
>;
|
|
181
|
+
/** DELETE /v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks — ai-delete-benchmarks */
|
|
182
|
+
deleteBenchmarks(
|
|
183
|
+
...init: TransportInitParam<
|
|
184
|
+
TransportInit<'/v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks', 'delete'>
|
|
185
|
+
>
|
|
186
|
+
): Promise<
|
|
187
|
+
TransportData<'/v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks', 'delete'>
|
|
188
|
+
>;
|
|
189
|
+
/**
|
|
190
|
+
* PUT /v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks/{benchmark_id}
|
|
191
|
+
* — ai-update-benchmark
|
|
192
|
+
*/
|
|
193
|
+
updateBenchmark(
|
|
194
|
+
...init: TransportInitParam<
|
|
195
|
+
TransportInit<
|
|
196
|
+
'/v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks/{benchmark_id}',
|
|
197
|
+
'put'
|
|
198
|
+
>
|
|
199
|
+
>
|
|
200
|
+
): Promise<
|
|
201
|
+
TransportData<
|
|
202
|
+
'/v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks/{benchmark_id}',
|
|
203
|
+
'put'
|
|
204
|
+
>
|
|
205
|
+
>;
|
|
206
|
+
/** PUT /v1/workspaces/{id}/projects/{project_id}/ci/competitors — ci-update-competitors */
|
|
207
|
+
updateCompetitors(
|
|
208
|
+
...init: TransportInitParam<
|
|
209
|
+
TransportInit<'/v1/workspaces/{id}/projects/{project_id}/ci/competitors', 'put'>
|
|
210
|
+
>
|
|
211
|
+
): Promise<TransportData<'/v1/workspaces/{id}/projects/{project_id}/ci/competitors', 'put'>>;
|
|
212
|
+
|
|
213
|
+
/** POST /v2/workspaces/{id}/projects/{project_id}/ai_models — aio-project-create-model */
|
|
214
|
+
createAioModel(
|
|
215
|
+
...init: TransportInitParam<
|
|
216
|
+
TransportInit<'/v2/workspaces/{id}/projects/{project_id}/ai_models', 'post'>
|
|
217
|
+
>
|
|
218
|
+
): Promise<TransportData<'/v2/workspaces/{id}/projects/{project_id}/ai_models', 'post'>>;
|
|
219
|
+
/** POST /v2/workspaces/{id}/projects/{project_id}/ai_models/benchmarks — ai-create-benchmarks-v2 */
|
|
220
|
+
createBenchmarks(
|
|
221
|
+
...init: TransportInitParam<
|
|
222
|
+
TransportInit<'/v2/workspaces/{id}/projects/{project_id}/ai_models/benchmarks', 'post'>
|
|
223
|
+
>
|
|
224
|
+
): Promise<
|
|
225
|
+
TransportData<'/v2/workspaces/{id}/projects/{project_id}/ai_models/benchmarks', 'post'>
|
|
226
|
+
>;
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* GET /v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls
|
|
230
|
+
* — aio-list-brand-urls
|
|
231
|
+
*/
|
|
232
|
+
listBrandUrls(
|
|
233
|
+
...init: TransportInitParam<
|
|
234
|
+
TransportInit<
|
|
235
|
+
'/v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls',
|
|
236
|
+
'get'
|
|
237
|
+
>
|
|
238
|
+
>
|
|
239
|
+
): Promise<
|
|
240
|
+
TransportData<
|
|
241
|
+
'/v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls',
|
|
242
|
+
'get'
|
|
243
|
+
>
|
|
244
|
+
>;
|
|
245
|
+
/**
|
|
246
|
+
* POST /v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls
|
|
247
|
+
* — aio-create-brand-urls
|
|
248
|
+
*/
|
|
249
|
+
createBrandUrls(
|
|
250
|
+
...init: TransportInitParam<
|
|
251
|
+
TransportInit<
|
|
252
|
+
'/v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls',
|
|
253
|
+
'post'
|
|
254
|
+
>
|
|
255
|
+
>
|
|
256
|
+
): Promise<
|
|
257
|
+
TransportData<
|
|
258
|
+
'/v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls',
|
|
259
|
+
'post'
|
|
260
|
+
>
|
|
261
|
+
>;
|
|
262
|
+
/**
|
|
263
|
+
* DELETE /v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls
|
|
264
|
+
* — aio-delete-brand-urls
|
|
265
|
+
*/
|
|
266
|
+
deleteBrandUrls(
|
|
267
|
+
...init: TransportInitParam<
|
|
268
|
+
TransportInit<
|
|
269
|
+
'/v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls',
|
|
270
|
+
'delete'
|
|
271
|
+
>
|
|
272
|
+
>
|
|
273
|
+
): Promise<
|
|
274
|
+
TransportData<
|
|
275
|
+
'/v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls',
|
|
276
|
+
'delete'
|
|
277
|
+
>
|
|
278
|
+
>;
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* GET /v2/workspaces/{id}/projects/{project_id}/aio/init_status
|
|
282
|
+
* — aio-get-project-init-status-v2
|
|
283
|
+
*/
|
|
284
|
+
getProjectInitStatus(
|
|
285
|
+
...init: TransportInitParam<
|
|
286
|
+
TransportInit<'/v2/workspaces/{id}/projects/{project_id}/aio/init_status', 'get'>
|
|
287
|
+
>
|
|
288
|
+
): Promise<TransportData<'/v2/workspaces/{id}/projects/{project_id}/aio/init_status', 'get'>>;
|
|
289
|
+
/** POST /v2/workspaces/{id}/projects/{project_id}/aio/prompts — aio-create-prompt-v2 */
|
|
290
|
+
createPrompts(
|
|
291
|
+
...init: TransportInitParam<
|
|
292
|
+
TransportInit<'/v2/workspaces/{id}/projects/{project_id}/aio/prompts', 'post'>
|
|
293
|
+
>
|
|
294
|
+
): Promise<TransportData<'/v2/workspaces/{id}/projects/{project_id}/aio/prompts', 'post'>>;
|
|
295
|
+
/** DELETE /v2/workspaces/{id}/projects/{project_id}/aio/prompts — aio-delete-prompt-by-ids-v2 */
|
|
296
|
+
deletePromptsByIds(
|
|
297
|
+
...init: TransportInitParam<
|
|
298
|
+
TransportInit<'/v2/workspaces/{id}/projects/{project_id}/aio/prompts', 'delete'>
|
|
299
|
+
>
|
|
300
|
+
): Promise<TransportData<'/v2/workspaces/{id}/projects/{project_id}/aio/prompts', 'delete'>>;
|
|
301
|
+
/**
|
|
302
|
+
* POST /v2/workspaces/{id}/projects/{project_id}/aio/prompts/by_tags
|
|
303
|
+
* — aio-list-prompts-by-tag-ids
|
|
304
|
+
*/
|
|
305
|
+
listPromptsByTagIds(
|
|
306
|
+
...init: TransportInitParam<
|
|
307
|
+
TransportInit<'/v2/workspaces/{id}/projects/{project_id}/aio/prompts/by_tags', 'post'>
|
|
308
|
+
>
|
|
309
|
+
): Promise<TransportData<'/v2/workspaces/{id}/projects/{project_id}/aio/prompts/by_tags', 'post'>>;
|
|
310
|
+
/** PUT /v2/workspaces/{id}/projects/{project_id}/aio/prompts/tags — aio-update-prompts-batch */
|
|
311
|
+
updatePromptTags(
|
|
312
|
+
...init: TransportInitParam<
|
|
313
|
+
TransportInit<'/v2/workspaces/{id}/projects/{project_id}/aio/prompts/tags', 'put'>
|
|
314
|
+
>
|
|
315
|
+
): Promise<TransportData<'/v2/workspaces/{id}/projects/{project_id}/aio/prompts/tags', 'put'>>;
|
|
316
|
+
/**
|
|
317
|
+
* POST /v2/workspaces/{id}/projects/{project_id}/aio/prompts/{prompt_id}/rename
|
|
318
|
+
* — aio-rename-prompt
|
|
319
|
+
*/
|
|
320
|
+
renamePrompt(
|
|
321
|
+
...init: TransportInitParam<
|
|
322
|
+
TransportInit<'/v2/workspaces/{id}/projects/{project_id}/aio/prompts/{prompt_id}/rename', 'post'>
|
|
323
|
+
>
|
|
324
|
+
): Promise<
|
|
325
|
+
TransportData<'/v2/workspaces/{id}/projects/{project_id}/aio/prompts/{prompt_id}/rename', 'post'>
|
|
326
|
+
>;
|
|
327
|
+
/** GET /v2/workspaces/{id}/projects/{project_id}/aio/tags — aio-get-project-tags */
|
|
328
|
+
listProjectTags(
|
|
329
|
+
...init: TransportInitParam<
|
|
330
|
+
TransportInit<'/v2/workspaces/{id}/projects/{project_id}/aio/tags', 'get'>
|
|
331
|
+
>
|
|
332
|
+
): Promise<TransportData<'/v2/workspaces/{id}/projects/{project_id}/aio/tags', 'get'>>;
|
|
333
|
+
/** POST /v2/workspaces/{id}/projects/{project_id}/aio/tags — aio-create-project-tags */
|
|
334
|
+
createProjectTags(
|
|
335
|
+
...init: TransportInitParam<
|
|
336
|
+
TransportInit<'/v2/workspaces/{id}/projects/{project_id}/aio/tags', 'post'>
|
|
337
|
+
>
|
|
338
|
+
): Promise<TransportData<'/v2/workspaces/{id}/projects/{project_id}/aio/tags', 'post'>>;
|
|
339
|
+
/** PATCH /v2/workspaces/{id}/projects/{project_id}/aio/tags/{tag_id} — aio-update-tag */
|
|
340
|
+
updateProjectTag(
|
|
341
|
+
...init: TransportInitParam<
|
|
342
|
+
TransportInit<'/v2/workspaces/{id}/projects/{project_id}/aio/tags/{tag_id}', 'patch'>
|
|
343
|
+
>
|
|
344
|
+
): Promise<TransportData<'/v2/workspaces/{id}/projects/{project_id}/aio/tags/{tag_id}', 'patch'>>;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Builds the {@link SerenityProjectEngineTransport} facade. Takes the SAME options as
|
|
349
|
+
* {@link createSerenityProjectEngineApiClient} (it builds that client internally and adds no
|
|
350
|
+
* options of its own).
|
|
351
|
+
*/
|
|
352
|
+
export declare function createSerenityProjectEngineTransport(
|
|
353
|
+
options: SerenityProjectEngineApiClientOptions,
|
|
354
|
+
): SerenityProjectEngineTransport;
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* The single typed error the transport facade throws from its `unwrap` seam. It carries the
|
|
358
|
+
* failing HTTP `method`, the response `status` (or `undefined` when there was no HTTP response —
|
|
359
|
+
* an exhausted-network / per-attempt-timeout failure), and the normalized parsed error `body`.
|
|
360
|
+
* On the network/timeout path the original thrown error is preserved as `cause`. No error→HTTP
|
|
361
|
+
* translation or redaction — consumer-owned per ADR-0001.
|
|
362
|
+
*
|
|
363
|
+
* NOTE: the `readonly` modifiers below are a type-system-only guarantee; the runtime class
|
|
364
|
+
* (`errors.js`) sets these fields with plain assignment in the constructor.
|
|
365
|
+
*/
|
|
366
|
+
export declare class ProjectEngineApiError extends Error {
|
|
367
|
+
/** The HTTP response status, or `undefined` when there was no HTTP response. */
|
|
368
|
+
readonly status: number | undefined;
|
|
369
|
+
/** The HTTP method of the failing request. */
|
|
370
|
+
readonly method: string;
|
|
371
|
+
/** The normalized parsed error body (`null` when empty/absent). */
|
|
372
|
+
readonly body: unknown;
|
|
373
|
+
constructor(
|
|
374
|
+
status: number | undefined,
|
|
375
|
+
method: string,
|
|
376
|
+
body: unknown,
|
|
377
|
+
options?: { cause?: unknown },
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
76
381
|
// Re-export the generated contract types for consumers that want them directly.
|
|
77
382
|
export type { paths, components };
|
package/src/index.js
CHANGED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// @ts-check
|
|
14
|
+
|
|
15
|
+
import { createSerenityProjectEngineApiClient } from './client.js';
|
|
16
|
+
import { ProjectEngineApiError } from './errors.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {import('./client.js').SerenityProjectEngineApiClientOptions}
|
|
20
|
+
* SerenityProjectEngineApiClientOptions
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Intent-named facade over the raw {@link createSerenityProjectEngineApiClient} openapi-fetch
|
|
25
|
+
* client. It wraps ONLY the 28 in-spec Project Engine operations that spacecat-api-service
|
|
26
|
+
* consumes, behind verb+resource method names, so consumers depend on this seam rather than the
|
|
27
|
+
* raw client and its literal path strings. Each method is THIN: it forwards the caller's
|
|
28
|
+
* openapi-fetch `init` (params.path/query, body) to `client.<METHOD>('<literal path>', init)` and
|
|
29
|
+
* routes the result through the single {@link unwrap} error seam. There is deliberately NO caching,
|
|
30
|
+
* redaction, error→HTTP translation, or composite/convenience method here — all consumer-owned per
|
|
31
|
+
* ADR-0001. The remaining generated operations stay reachable via the raw client; add a facade
|
|
32
|
+
* method only when a real second consumer needs one.
|
|
33
|
+
*
|
|
34
|
+
* @param {SerenityProjectEngineApiClientOptions} options The SAME options as the raw client — the
|
|
35
|
+
* facade adds none of its own. Builds the underlying client via
|
|
36
|
+
* {@link createSerenityProjectEngineApiClient}.
|
|
37
|
+
* @returns {import('./index.js').SerenityProjectEngineTransport}
|
|
38
|
+
*/
|
|
39
|
+
export function createSerenityProjectEngineTransport(options) {
|
|
40
|
+
const client = createSerenityProjectEngineApiClient(options);
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The SINGLE seam where a failed call becomes a throw. It awaits the openapi-fetch result
|
|
44
|
+
* promise here (so a network/timeout rejection also flows through this one point), and turns
|
|
45
|
+
* both failure paths into a {@link ProjectEngineApiError}:
|
|
46
|
+
*
|
|
47
|
+
* - a non-2xx HTTP response: the typed client never throws on an HTTP error — it resolves to
|
|
48
|
+
* `{ data, error, response }` with the parsed error body in `error` — so the non-2xx is turned
|
|
49
|
+
* into a throw here carrying `response.status` + the normalized `body`;
|
|
50
|
+
* - an exhausted-network / per-attempt-timeout failure: `createRetryingFetch` rethrew the last
|
|
51
|
+
* raw error after the retry budget, so the awaited promise rejects. There is no HTTP response
|
|
52
|
+
* ⇒ `status` is `undefined`; the original error is preserved as `cause`.
|
|
53
|
+
*
|
|
54
|
+
* A 2xx returns the parsed body (or null for an empty body).
|
|
55
|
+
*
|
|
56
|
+
* @template T
|
|
57
|
+
* @param {string} method the HTTP method, for the error message
|
|
58
|
+
* @param {Promise<{ data?: T, error?: unknown, response: Response }>} resultPromise the pending
|
|
59
|
+
* openapi-fetch result
|
|
60
|
+
* @returns {Promise<NonNullable<T> | null>} the parsed success body, or null for an empty body
|
|
61
|
+
* (an empty-body operation resolves with null, never undefined)
|
|
62
|
+
* @throws {import('./errors.js').ProjectEngineApiError} on a non-2xx response or an
|
|
63
|
+
* exhausted-network / per-attempt-timeout failure
|
|
64
|
+
*/
|
|
65
|
+
async function unwrap(method, resultPromise) {
|
|
66
|
+
let result;
|
|
67
|
+
try {
|
|
68
|
+
result = await resultPromise;
|
|
69
|
+
} catch (cause) {
|
|
70
|
+
// exhausted-network / per-attempt-timeout path: createRetryingFetch rethrew the last raw
|
|
71
|
+
// error after the retry budget. No HTTP response ⇒ status undefined; preserve the original
|
|
72
|
+
// as `cause`.
|
|
73
|
+
throw new ProjectEngineApiError(undefined, method, null, { cause });
|
|
74
|
+
}
|
|
75
|
+
const { data, error, response } = result;
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
// openapi-fetch puts the parsed error body in `error`; fall back to `data`, then null.
|
|
78
|
+
const rawBody = error ?? data ?? null;
|
|
79
|
+
// openapi-fetch surfaces an empty error body as '' (not undefined); normalise it to null.
|
|
80
|
+
const body = rawBody === '' ? null : rawBody;
|
|
81
|
+
throw new ProjectEngineApiError(response.status, method, body);
|
|
82
|
+
}
|
|
83
|
+
return data ?? null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
// ─── /v1 catalog ────────────────────────────────────────────────────────
|
|
88
|
+
/** GET /v1/languages — projects-admin-list-languages */
|
|
89
|
+
listLanguages(init) {
|
|
90
|
+
return unwrap('GET', client.GET('/v1/languages', init));
|
|
91
|
+
},
|
|
92
|
+
/** GET /v1/ai_models — ai-list-global-models */
|
|
93
|
+
listGlobalAiModels(init) {
|
|
94
|
+
return unwrap('GET', client.GET('/v1/ai_models', init));
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
// ─── /v1 projects ───────────────────────────────────────────────────────
|
|
98
|
+
/** GET /v1/workspaces/{id}/projects — projects-list-projects */
|
|
99
|
+
listProjects(init) {
|
|
100
|
+
return unwrap('GET', client.GET('/v1/workspaces/{id}/projects', init));
|
|
101
|
+
},
|
|
102
|
+
/** POST /v1/workspaces/{id}/projects — projects-post-project */
|
|
103
|
+
createProject(init) {
|
|
104
|
+
return unwrap('POST', client.POST('/v1/workspaces/{id}/projects', init));
|
|
105
|
+
},
|
|
106
|
+
/** GET /v1/workspaces/{id}/projects/{project_id} — projects-get-project */
|
|
107
|
+
getProject(init) {
|
|
108
|
+
return unwrap('GET', client.GET('/v1/workspaces/{id}/projects/{project_id}', init));
|
|
109
|
+
},
|
|
110
|
+
/** PATCH /v1/workspaces/{id}/projects/{project_id} — projects-patch-project */
|
|
111
|
+
updateProject(init) {
|
|
112
|
+
return unwrap('PATCH', client.PATCH('/v1/workspaces/{id}/projects/{project_id}', init));
|
|
113
|
+
},
|
|
114
|
+
/** DELETE /v1/workspaces/{id}/projects/{project_id} — projects-delete-project */
|
|
115
|
+
deleteProject(init) {
|
|
116
|
+
return unwrap('DELETE', client.DELETE('/v1/workspaces/{id}/projects/{project_id}', init));
|
|
117
|
+
},
|
|
118
|
+
/** POST /v1/workspaces/{id}/projects/{project_id}/publish — projects-publish-project */
|
|
119
|
+
publishProject(init) {
|
|
120
|
+
return unwrap('POST', client.POST('/v1/workspaces/{id}/projects/{project_id}/publish', init));
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// ─── /v1 AI models + benchmarks ───────────────────────────────────────────
|
|
124
|
+
/** GET /v1/workspaces/{id}/projects/{project_id}/ai_models — ai-list-models */
|
|
125
|
+
listAiModels(init) {
|
|
126
|
+
return unwrap('GET', client.GET('/v1/workspaces/{id}/projects/{project_id}/ai_models', init));
|
|
127
|
+
},
|
|
128
|
+
/** DELETE /v1/workspaces/{id}/projects/{project_id}/ai_models — ai-delete-models */
|
|
129
|
+
deleteAiModels(init) {
|
|
130
|
+
return unwrap('DELETE', client.DELETE('/v1/workspaces/{id}/projects/{project_id}/ai_models', init));
|
|
131
|
+
},
|
|
132
|
+
/** GET /v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks — ai-list-benchmarks */
|
|
133
|
+
listBenchmarks(init) {
|
|
134
|
+
return unwrap('GET', client.GET('/v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks', init));
|
|
135
|
+
},
|
|
136
|
+
/**
|
|
137
|
+
* DELETE /v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks — ai-delete-benchmarks
|
|
138
|
+
*/
|
|
139
|
+
deleteBenchmarks(init) {
|
|
140
|
+
return unwrap('DELETE', client.DELETE('/v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks', init));
|
|
141
|
+
},
|
|
142
|
+
/**
|
|
143
|
+
* PUT /v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks/{benchmark_id}
|
|
144
|
+
* — ai-update-benchmark
|
|
145
|
+
*/
|
|
146
|
+
updateBenchmark(init) {
|
|
147
|
+
return unwrap('PUT', client.PUT('/v1/workspaces/{id}/projects/{project_id}/ai_models/benchmarks/{benchmark_id}', init));
|
|
148
|
+
},
|
|
149
|
+
/** PUT /v1/workspaces/{id}/projects/{project_id}/ci/competitors — ci-update-competitors */
|
|
150
|
+
updateCompetitors(init) {
|
|
151
|
+
return unwrap('PUT', client.PUT('/v1/workspaces/{id}/projects/{project_id}/ci/competitors', init));
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
// ─── /v2 AI models + benchmarks ───────────────────────────────────────────
|
|
155
|
+
/** POST /v2/workspaces/{id}/projects/{project_id}/ai_models — aio-project-create-model */
|
|
156
|
+
createAioModel(init) {
|
|
157
|
+
return unwrap('POST', client.POST('/v2/workspaces/{id}/projects/{project_id}/ai_models', init));
|
|
158
|
+
},
|
|
159
|
+
/**
|
|
160
|
+
* POST /v2/workspaces/{id}/projects/{project_id}/ai_models/benchmarks — ai-create-benchmarks-v2
|
|
161
|
+
*/
|
|
162
|
+
createBenchmarks(init) {
|
|
163
|
+
return unwrap('POST', client.POST('/v2/workspaces/{id}/projects/{project_id}/ai_models/benchmarks', init));
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
// ─── /v2 brand URLs ───────────────────────────────────────────────────────
|
|
167
|
+
/**
|
|
168
|
+
* GET /v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls
|
|
169
|
+
* — aio-list-brand-urls
|
|
170
|
+
*/
|
|
171
|
+
listBrandUrls(init) {
|
|
172
|
+
return unwrap('GET', client.GET('/v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls', init));
|
|
173
|
+
},
|
|
174
|
+
/**
|
|
175
|
+
* POST /v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls
|
|
176
|
+
* — aio-create-brand-urls
|
|
177
|
+
*/
|
|
178
|
+
createBrandUrls(init) {
|
|
179
|
+
return unwrap('POST', client.POST('/v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls', init));
|
|
180
|
+
},
|
|
181
|
+
/**
|
|
182
|
+
* DELETE /v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls
|
|
183
|
+
* — aio-delete-brand-urls
|
|
184
|
+
*/
|
|
185
|
+
deleteBrandUrls(init) {
|
|
186
|
+
return unwrap('DELETE', client.DELETE('/v2/workspaces/{id}/projects/{project_id}/aio/benchmarks/{benchmark_id}/brand_urls', init));
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
// ─── /v2 AIO project state, prompts, tags ─────────────────────────────────
|
|
190
|
+
/**
|
|
191
|
+
* GET /v2/workspaces/{id}/projects/{project_id}/aio/init_status
|
|
192
|
+
* — aio-get-project-init-status-v2
|
|
193
|
+
*/
|
|
194
|
+
getProjectInitStatus(init) {
|
|
195
|
+
return unwrap('GET', client.GET('/v2/workspaces/{id}/projects/{project_id}/aio/init_status', init));
|
|
196
|
+
},
|
|
197
|
+
/** POST /v2/workspaces/{id}/projects/{project_id}/aio/prompts — aio-create-prompt-v2 */
|
|
198
|
+
createPrompts(init) {
|
|
199
|
+
return unwrap('POST', client.POST('/v2/workspaces/{id}/projects/{project_id}/aio/prompts', init));
|
|
200
|
+
},
|
|
201
|
+
/**
|
|
202
|
+
* DELETE /v2/workspaces/{id}/projects/{project_id}/aio/prompts — aio-delete-prompt-by-ids-v2
|
|
203
|
+
*/
|
|
204
|
+
deletePromptsByIds(init) {
|
|
205
|
+
return unwrap('DELETE', client.DELETE('/v2/workspaces/{id}/projects/{project_id}/aio/prompts', init));
|
|
206
|
+
},
|
|
207
|
+
/**
|
|
208
|
+
* POST /v2/workspaces/{id}/projects/{project_id}/aio/prompts/by_tags
|
|
209
|
+
* — aio-list-prompts-by-tag-ids
|
|
210
|
+
*/
|
|
211
|
+
listPromptsByTagIds(init) {
|
|
212
|
+
return unwrap('POST', client.POST('/v2/workspaces/{id}/projects/{project_id}/aio/prompts/by_tags', init));
|
|
213
|
+
},
|
|
214
|
+
/** PUT /v2/workspaces/{id}/projects/{project_id}/aio/prompts/tags — aio-update-prompts-batch */
|
|
215
|
+
updatePromptTags(init) {
|
|
216
|
+
return unwrap('PUT', client.PUT('/v2/workspaces/{id}/projects/{project_id}/aio/prompts/tags', init));
|
|
217
|
+
},
|
|
218
|
+
/**
|
|
219
|
+
* POST /v2/workspaces/{id}/projects/{project_id}/aio/prompts/{prompt_id}/rename
|
|
220
|
+
* — aio-rename-prompt
|
|
221
|
+
*/
|
|
222
|
+
renamePrompt(init) {
|
|
223
|
+
return unwrap('POST', client.POST('/v2/workspaces/{id}/projects/{project_id}/aio/prompts/{prompt_id}/rename', init));
|
|
224
|
+
},
|
|
225
|
+
/** GET /v2/workspaces/{id}/projects/{project_id}/aio/tags — aio-get-project-tags */
|
|
226
|
+
listProjectTags(init) {
|
|
227
|
+
return unwrap('GET', client.GET('/v2/workspaces/{id}/projects/{project_id}/aio/tags', init));
|
|
228
|
+
},
|
|
229
|
+
/** POST /v2/workspaces/{id}/projects/{project_id}/aio/tags — aio-create-project-tags */
|
|
230
|
+
createProjectTags(init) {
|
|
231
|
+
return unwrap('POST', client.POST('/v2/workspaces/{id}/projects/{project_id}/aio/tags', init));
|
|
232
|
+
},
|
|
233
|
+
/** PATCH /v2/workspaces/{id}/projects/{project_id}/aio/tags/{tag_id} — aio-update-tag */
|
|
234
|
+
updateProjectTag(init) {
|
|
235
|
+
return unwrap('PATCH', client.PATCH('/v2/workspaces/{id}/projects/{project_id}/aio/tags/{tag_id}', init));
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
}
|