@adobe/spacecat-shared-project-engine-client 1.18.0 → 1.19.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/README.md CHANGED
@@ -47,8 +47,9 @@ const { data, error } = await client.GET('/v1/countries');
47
47
 
48
48
  The spec is a **vendored file** — `spec/projectengine_swagger_public.yaml` — kept under
49
49
  version control. Semrush only provides the file (no endpoint access in the near term), and
50
- it's **Swagger 2.0** (no v3/v3.1 on offer). The vendored file is **never edited**; where it
51
- diverges from the live API, a generation-time overlay corrects the converted artifact instead (see
50
+ it's **Swagger 2.0** (no v3/v3.1 on offer). The vendored file is **never hand-authored** the only
51
+ thing that ever lands in it is what Semrush ships; where it diverges from the live API, a
52
+ generation-time overlay corrects the converted artifact instead (see
52
53
  [Spec corrections](#spec-corrections)). Refresh is **manual**: drop in the newer file, re-run
53
54
  `npm run generate`, and review the diff. A committed checksum lock
54
55
  (`spec/projectengine_swagger_public.yaml.sha256`) is verified by `npm run spec:verify` (wired into
@@ -56,6 +57,18 @@ diverges from the live API, a generation-time overlay corrects the converted art
56
57
  explicitly regenerated with `npm run spec:lock` and reviewed. A true live-drift contract test
57
58
  against Semrush remains blocked on endpoint access.
58
59
 
60
+ Semrush sometimes delivers a **delta** instead of a whole document — a short YAML carrying only the
61
+ paths a release added. Splice those paths into the vendored file verbatim, in sorted position and in
62
+ the file's own block style (sequences flush with their key), leaving every other byte untouched, then
63
+ re-lock. Nothing is hand-authored, so the review evidence is a deep-compare of the spliced paths
64
+ against the delivered YAML:
65
+
66
+ ```bash
67
+ node -e "const y=require('js-yaml'),f=require('fs');
68
+ const a=y.load(f.readFileSync('<delivered>.yaml','utf8')),b=y.load(f.readFileSync('spec/projectengine_swagger_public.yaml','utf8'));
69
+ for (const p of Object.keys(a.paths)) console.log(p, JSON.stringify(a.paths[p])===JSON.stringify(b.paths[p]));"
70
+ ```
71
+
59
72
  Both scripts use a **package-root-relative** path and assume the working directory is this
60
73
  package root — always invoke them via `npm run spec:verify` / `npm run spec:lock`, which npm
61
74
  runs from the package root, rather than calling `shasum -c` by hand from the monorepo root or a
@@ -101,13 +114,20 @@ pip install datamodel-code-generator
101
114
 
102
115
  ## Spec corrections
103
116
 
104
- The vendored swagger diverges from the live API in three places. A small OpenAPI Overlay
117
+ The vendored swagger diverges from the live API in a number of places. A small OpenAPI Overlay
105
118
  (`spec/overlays/corrections.yaml`), applied to the converted OAS3 artifact at generation time by
106
- `scripts/apply-overlay.mjs`, corrects them; the vendored `spec/projectengine_swagger_public.yaml`
107
- is never touched.
119
+ `scripts/apply-overlay.mjs`, corrects them; no correction is ever written into the vendored
120
+ `spec/projectengine_swagger_public.yaml`.
108
121
 
109
122
  - **CR1 — missing endpoint.** Adds `GET /v1/ai_models` (the live global model catalog), which is
110
123
  absent from the upstream swagger.
124
+ - **CR23 — missing response field.** Adds `is_paused` to `model.ProjectResponse`. The swagger
125
+ delta that shipped `pause`/`resume` added the two action paths but left the response schema
126
+ alone, so the generated type had no way to express whether a project is paused. Live returns the
127
+ key on every project read.
128
+ - **CR24 — missing status.** Declares the `404` that `pause`/`resume` return for an unknown project
129
+ id. Live pause is idempotent (a second pause is another `202`); only `resume` uses the declared
130
+ `409`, and it does so with `{"message": "project is not paused"}`.
111
131
  - **CR2 — auth.** The spec models a required `Auth-Data-Jwt` header, but the live API authenticates
112
132
  on `Authorization: Bearer <IMS>` only — Semrush accepts the IMS bearer directly. The overlay
113
133
  removes `Auth-Data-Jwt` from every operation and adds an `imsBearer` security scheme.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-project-engine-client",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
4
  "description": "Shared modules of the Spacecat Services - Semrush Project Engine client and generated types",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -63,7 +63,7 @@
63
63
  "c8": "11.0.0",
64
64
  "chai": "6.2.2",
65
65
  "counterfact": "2.14.0",
66
- "js-yaml": "4.3.0",
66
+ "js-yaml": "4.3.1",
67
67
  "mocha": "11.7.6",
68
68
  "mocha-multi-reporters": "1.5.1",
69
69
  "openapi-typescript": "7.13.0",
package/src/client.js CHANGED
@@ -28,7 +28,7 @@ import { createRetryingFetch, toTokenGetter } from './internal.js';
28
28
  /**
29
29
  * @typedef {object} SerenityProjectEngineApiClientOptions
30
30
  * @property {string} baseUrl Base URL of the Project Engine API — the origin of
31
- * `SEMRUSH_PROJECTS_BASE_URL` (e.g. `https://adobe-hackathon.semrush.com`), or the Counterfact
31
+ * `SEMRUSH_PROJECTS_BASE_URL` (e.g. `https://www.semrush.com`), or the Counterfact
32
32
  * mock's origin for E2E / local dev. Only `protocol//host` is used; any path is dropped and the
33
33
  * client appends the fixed `/enterprise/projects/api` prefix itself, matching the deployed
34
34
  * api-service transport (`rest-transport.js`).
@@ -883,6 +883,26 @@ export interface paths {
883
883
  patch?: never;
884
884
  trace?: never;
885
885
  };
886
+ "/v1/workspaces/{id}/projects/{project_id}/pause": {
887
+ parameters: {
888
+ query?: never;
889
+ header?: never;
890
+ path?: never;
891
+ cookie?: never;
892
+ };
893
+ get?: never;
894
+ put?: never;
895
+ /**
896
+ * pause a project
897
+ * @description pause an AIO project: prompt limits are released and data collection stops while configuration and historical data are preserved
898
+ */
899
+ post: operations["projects-pause-project"];
900
+ delete?: never;
901
+ options?: never;
902
+ head?: never;
903
+ patch?: never;
904
+ trace?: never;
905
+ };
886
906
  "/v1/workspaces/{id}/projects/{project_id}/publish": {
887
907
  parameters: {
888
908
  query?: never;
@@ -903,6 +923,26 @@ export interface paths {
903
923
  patch?: never;
904
924
  trace?: never;
905
925
  };
926
+ "/v1/workspaces/{id}/projects/{project_id}/resume": {
927
+ parameters: {
928
+ query?: never;
929
+ header?: never;
930
+ path?: never;
931
+ cookie?: never;
932
+ };
933
+ get?: never;
934
+ put?: never;
935
+ /**
936
+ * resume a paused project
937
+ * @description resume a paused AIO project: re-consumes prompt limits (subject to the same quota check as publishing) and data collection continues
938
+ */
939
+ post: operations["projects-resume-project"];
940
+ delete?: never;
941
+ options?: never;
942
+ head?: never;
943
+ patch?: never;
944
+ trace?: never;
945
+ };
906
946
  "/v1/workspaces/{id}/projects/{project_id}/segments": {
907
947
  parameters: {
908
948
  query?: never;
@@ -2385,6 +2425,8 @@ export interface components {
2385
2425
  /** @description enum: aio,mfour,ci */
2386
2426
  type?: string;
2387
2427
  updated_at?: string;
2428
+ /** @description whether the project is paused: prompt limits released and data collection stopped, configuration and historical data preserved */
2429
+ is_paused: boolean;
2388
2430
  };
2389
2431
  "model.ProjectUpdateRequest": {
2390
2432
  brand_name_display?: string;
@@ -5790,6 +5832,74 @@ export interface operations {
5790
5832
  };
5791
5833
  };
5792
5834
  };
5835
+ "projects-pause-project": {
5836
+ parameters: {
5837
+ query?: never;
5838
+ header?: never;
5839
+ path: {
5840
+ /** @description workspace ID */
5841
+ id: string;
5842
+ /** @description project ID */
5843
+ project_id: string;
5844
+ };
5845
+ cookie?: never;
5846
+ };
5847
+ requestBody?: never;
5848
+ responses: {
5849
+ /** @description Accepted */
5850
+ 202: {
5851
+ headers: {
5852
+ [name: string]: unknown;
5853
+ };
5854
+ content?: never;
5855
+ };
5856
+ /** @description Unauthorized */
5857
+ 401: {
5858
+ headers: {
5859
+ [name: string]: unknown;
5860
+ };
5861
+ content: {
5862
+ "application/json": components["schemas"]["http_server.BasicResponse"];
5863
+ };
5864
+ };
5865
+ /** @description Forbidden */
5866
+ 403: {
5867
+ headers: {
5868
+ [name: string]: unknown;
5869
+ };
5870
+ content: {
5871
+ "application/json": components["schemas"]["http_server.BasicResponse"];
5872
+ };
5873
+ };
5874
+ /** @description Not Found */
5875
+ 404: {
5876
+ headers: {
5877
+ [name: string]: unknown;
5878
+ };
5879
+ content: {
5880
+ "application/json": components["schemas"]["http_server.BasicResponse"];
5881
+ };
5882
+ };
5883
+ /** @description Conflict */
5884
+ 409: {
5885
+ headers: {
5886
+ [name: string]: unknown;
5887
+ };
5888
+ content: {
5889
+ "application/json": components["schemas"]["http_server.BasicResponse"];
5890
+ };
5891
+ };
5892
+ /** @description Internal Server Error */
5893
+ 500: {
5894
+ headers: {
5895
+ [name: string]: unknown;
5896
+ };
5897
+ content: {
5898
+ "application/json": components["schemas"]["http_server.BasicResponse"];
5899
+ };
5900
+ };
5901
+ };
5902
+ };
5793
5903
  "projects-publish-project": {
5794
5904
  parameters: {
5795
5905
  query?: never;
@@ -5840,6 +5950,74 @@ export interface operations {
5840
5950
  };
5841
5951
  };
5842
5952
  };
5953
+ "projects-resume-project": {
5954
+ parameters: {
5955
+ query?: never;
5956
+ header?: never;
5957
+ path: {
5958
+ /** @description workspace ID */
5959
+ id: string;
5960
+ /** @description project ID */
5961
+ project_id: string;
5962
+ };
5963
+ cookie?: never;
5964
+ };
5965
+ requestBody?: never;
5966
+ responses: {
5967
+ /** @description Accepted */
5968
+ 202: {
5969
+ headers: {
5970
+ [name: string]: unknown;
5971
+ };
5972
+ content?: never;
5973
+ };
5974
+ /** @description Unauthorized */
5975
+ 401: {
5976
+ headers: {
5977
+ [name: string]: unknown;
5978
+ };
5979
+ content: {
5980
+ "application/json": components["schemas"]["http_server.BasicResponse"];
5981
+ };
5982
+ };
5983
+ /** @description Forbidden */
5984
+ 403: {
5985
+ headers: {
5986
+ [name: string]: unknown;
5987
+ };
5988
+ content: {
5989
+ "application/json": components["schemas"]["http_server.BasicResponse"];
5990
+ };
5991
+ };
5992
+ /** @description Not Found */
5993
+ 404: {
5994
+ headers: {
5995
+ [name: string]: unknown;
5996
+ };
5997
+ content: {
5998
+ "application/json": components["schemas"]["http_server.BasicResponse"];
5999
+ };
6000
+ };
6001
+ /** @description Conflict */
6002
+ 409: {
6003
+ headers: {
6004
+ [name: string]: unknown;
6005
+ };
6006
+ content: {
6007
+ "application/json": components["schemas"]["http_server.BasicResponse"];
6008
+ };
6009
+ };
6010
+ /** @description Internal Server Error */
6011
+ 500: {
6012
+ headers: {
6013
+ [name: string]: unknown;
6014
+ };
6015
+ content: {
6016
+ "application/json": components["schemas"]["http_server.BasicResponse"];
6017
+ };
6018
+ };
6019
+ };
6020
+ };
5843
6021
  "project-list-segments": {
5844
6022
  parameters: {
5845
6023
  query?: {
package/src/index.d.ts CHANGED
@@ -111,7 +111,7 @@ type TransportData<P extends keyof paths, M extends keyof paths[P]> =
111
111
  | null;
112
112
 
113
113
  /**
114
- * Intent-named facade over {@link SerenityProjectEngineApiClient}. Wraps the 32 in-spec
114
+ * Intent-named facade over {@link SerenityProjectEngineApiClient}. Wraps the 34 in-spec
115
115
  * Project Engine operations spacecat-api-service consumes behind verb+resource methods, so
116
116
  * consumers depend on this seam rather than the raw client's literal path strings. Each method
117
117
  * is THIN: it forwards the caller's openapi-fetch `init` to the underlying client and resolves
@@ -157,6 +157,18 @@ export interface SerenityProjectEngineTransport {
157
157
  TransportInit<'/v1/workspaces/{id}/projects/{project_id}/publish', 'post'>
158
158
  >
159
159
  ): Promise<TransportData<'/v1/workspaces/{id}/projects/{project_id}/publish', 'post'>>;
160
+ /** POST /v1/workspaces/{id}/projects/{project_id}/pause — projects-pause-project */
161
+ pauseProject(
162
+ ...init: TransportInitParam<
163
+ TransportInit<'/v1/workspaces/{id}/projects/{project_id}/pause', 'post'>
164
+ >
165
+ ): Promise<TransportData<'/v1/workspaces/{id}/projects/{project_id}/pause', 'post'>>;
166
+ /** POST /v1/workspaces/{id}/projects/{project_id}/resume — projects-resume-project */
167
+ resumeProject(
168
+ ...init: TransportInitParam<
169
+ TransportInit<'/v1/workspaces/{id}/projects/{project_id}/resume', 'post'>
170
+ >
171
+ ): Promise<TransportData<'/v1/workspaces/{id}/projects/{project_id}/resume', 'post'>>;
160
172
 
161
173
  /** GET /v1/workspaces/{id}/projects/{project_id}/ai_models — ai-list-models */
162
174
  listAiModels(
@@ -22,7 +22,7 @@ import { ProjectEngineApiError } from './errors.js';
22
22
 
23
23
  /**
24
24
  * Intent-named facade over the raw {@link createSerenityProjectEngineApiClient} openapi-fetch
25
- * client. It wraps ONLY the 32 in-spec Project Engine operations that spacecat-api-service
25
+ * client. It wraps ONLY the 34 in-spec Project Engine operations that spacecat-api-service
26
26
  * consumes, behind verb+resource method names, so consumers depend on this seam rather than the
27
27
  * raw client and its literal path strings. Each method is THIN: it forwards the caller's
28
28
  * openapi-fetch `init` (params.path/query, body) to `client.<METHOD>('<literal path>', init)` and
@@ -119,6 +119,14 @@ export function createSerenityProjectEngineTransport(options) {
119
119
  publishProject(init) {
120
120
  return unwrap('POST', client.POST('/v1/workspaces/{id}/projects/{project_id}/publish', init));
121
121
  },
122
+ /** POST /v1/workspaces/{id}/projects/{project_id}/pause — projects-pause-project */
123
+ pauseProject(init) {
124
+ return unwrap('POST', client.POST('/v1/workspaces/{id}/projects/{project_id}/pause', init));
125
+ },
126
+ /** POST /v1/workspaces/{id}/projects/{project_id}/resume — projects-resume-project */
127
+ resumeProject(init) {
128
+ return unwrap('POST', client.POST('/v1/workspaces/{id}/projects/{project_id}/resume', init));
129
+ },
122
130
 
123
131
  // ─── /v1 AI models + benchmarks ───────────────────────────────────────────
124
132
  /** GET /v1/workspaces/{id}/projects/{project_id}/ai_models — ai-list-models */