@shopware/api-client 0.4.0 → 1.0.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 +209 -85
- package/{admin-api-types/apiSchema-6.5.3.0.json → api-types/adminApiSchema.json} +62470 -25854
- package/api-types/adminApiTypes.d.ts +84322 -0
- package/api-types/{apiSchema-6.4.19.0.json → storeApiSchema.json} +15295 -11433
- package/api-types/storeApiSchema.overrides.json +674 -0
- package/api-types/storeApiTypes.d.ts +8512 -0
- package/api-types/storeApiTypes.overrides.ts +182 -0
- package/dist/index.cjs +170 -104
- package/dist/index.d.cts +89259 -62605
- package/dist/index.d.mts +89259 -62605
- package/dist/index.d.ts +89259 -62605
- package/dist/index.mjs +166 -104
- package/package.json +20 -14
- package/admin-api-types/apiTypes-6.5.3.0.d.ts +0 -59568
- package/admin-api-types/index.d.ts +0 -1
- package/api-types/apiSchema-6.4.20.0.json +0 -13830
- package/api-types/apiSchema-6.5.0.0.json +0 -16669
- package/api-types/apiSchema-6.5.2.0.json +0 -12154
- package/api-types/apiSchema-6.5.3.0.json +0 -12154
- package/api-types/apiTypes-6.4.19.0.d.ts +0 -8170
- package/api-types/apiTypes-6.4.20.0.d.ts +0 -8168
- package/api-types/apiTypes-6.5.0.0.d.ts +0 -7244
- package/api-types/apiTypes-6.5.2.0.d.ts +0 -7738
- package/api-types/apiTypes-6.5.3.0.d.ts +0 -7738
- package/api-types/index.d.ts +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,41 @@
|
|
|
1
1
|
import { ofetch } from 'ofetch';
|
|
2
|
+
import { createHooks } from 'hookable';
|
|
3
|
+
import defu from 'defu';
|
|
4
|
+
|
|
5
|
+
function createHeaders(init) {
|
|
6
|
+
const _headers = {
|
|
7
|
+
"Content-Type": "application/json"
|
|
8
|
+
};
|
|
9
|
+
const handler = {
|
|
10
|
+
get: (target, prop) => {
|
|
11
|
+
if (prop === "apply") {
|
|
12
|
+
return apply;
|
|
13
|
+
}
|
|
14
|
+
return Reflect.get(target, prop);
|
|
15
|
+
},
|
|
16
|
+
set: (target, prop, value) => {
|
|
17
|
+
if (prop === "apply") {
|
|
18
|
+
throw new Error("Cannot override apply method");
|
|
19
|
+
}
|
|
20
|
+
return Reflect.set(target, prop, value);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const headersProxy = new Proxy(
|
|
24
|
+
_headers,
|
|
25
|
+
handler
|
|
26
|
+
);
|
|
27
|
+
function apply(headers) {
|
|
28
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
29
|
+
if (value) {
|
|
30
|
+
headersProxy[key] = value;
|
|
31
|
+
} else {
|
|
32
|
+
delete headersProxy[key];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
headersProxy.apply({ ...init });
|
|
37
|
+
return headersProxy;
|
|
38
|
+
}
|
|
2
39
|
|
|
3
40
|
var __defProp = Object.defineProperty;
|
|
4
41
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -9,14 +46,23 @@ var __publicField = (obj, key, value) => {
|
|
|
9
46
|
class ApiClientError extends Error {
|
|
10
47
|
constructor(response) {
|
|
11
48
|
let message = "Failed request";
|
|
12
|
-
|
|
49
|
+
const errorDetails = response._data || {
|
|
50
|
+
errors: [
|
|
51
|
+
{
|
|
52
|
+
title: "Unknown error",
|
|
53
|
+
detail: "API did not return errors, but request failed. Please check the network tab."
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
};
|
|
57
|
+
message += errorDetails.errors?.reduce((message2, error) => {
|
|
13
58
|
let pointer = "";
|
|
14
59
|
if (error.source?.pointer) {
|
|
15
60
|
pointer = `[${error.source.pointer}]`;
|
|
16
61
|
}
|
|
62
|
+
const details = error.detail ?? "No error details provided.";
|
|
17
63
|
return `${message2}
|
|
18
|
-
- [${error.title}]${pointer} ${
|
|
19
|
-
}, "");
|
|
64
|
+
- [${error.title}]${pointer} ${details}`;
|
|
65
|
+
}, "") ?? "";
|
|
20
66
|
super(message);
|
|
21
67
|
/**
|
|
22
68
|
* Flag to indicate if the request was successful.
|
|
@@ -43,9 +89,7 @@ class ApiClientError extends Error {
|
|
|
43
89
|
*/
|
|
44
90
|
__publicField(this, "headers");
|
|
45
91
|
this.name = "ApiClientError";
|
|
46
|
-
this.details =
|
|
47
|
-
errors: [{ title: "Unknown error", detail: "" }]
|
|
48
|
-
};
|
|
92
|
+
this.details = errorDetails;
|
|
49
93
|
this.ok = response.ok;
|
|
50
94
|
this.status = response.status;
|
|
51
95
|
this.statusText = response.statusText;
|
|
@@ -53,185 +97,203 @@ class ApiClientError extends Error {
|
|
|
53
97
|
this.headers = response.headers;
|
|
54
98
|
}
|
|
55
99
|
}
|
|
100
|
+
|
|
56
101
|
function errorInterceptor(response) {
|
|
57
102
|
throw new ApiClientError(response);
|
|
58
103
|
}
|
|
59
104
|
|
|
60
|
-
function
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const pathParams = requestPath.match(/{[^}]+}/g)?.map((param) => param.substring(1, param.length - 1)) || [];
|
|
64
|
-
const requestPathWithParams = pathParams.reduce((acc, paramName) => {
|
|
65
|
-
return acc.replace(`{${paramName}}`, params[paramName]);
|
|
105
|
+
function createPathWithParams(requestPath, pathParams) {
|
|
106
|
+
return Object.keys(pathParams || {}).reduce((acc, paramName) => {
|
|
107
|
+
return acc.replace(`{${paramName}}`, pathParams[paramName]);
|
|
66
108
|
}, requestPath);
|
|
67
|
-
const queryParamNames = queryParams?.split(",") || [];
|
|
68
|
-
const headerParamnames = headerParams?.split(",") || [];
|
|
69
|
-
const headers = {};
|
|
70
|
-
headerParamnames.forEach((paramName) => {
|
|
71
|
-
headers[paramName] = params[paramName];
|
|
72
|
-
});
|
|
73
|
-
const query = {};
|
|
74
|
-
queryParamNames.forEach((paramName) => {
|
|
75
|
-
let queryParamName = paramName;
|
|
76
|
-
if (Array.isArray(params[paramName]) && !queryParamName.includes("[]")) {
|
|
77
|
-
queryParamName += "[]";
|
|
78
|
-
}
|
|
79
|
-
query[queryParamName] = params[paramName];
|
|
80
|
-
});
|
|
81
|
-
const returnOptions = {
|
|
82
|
-
method: method.toUpperCase(),
|
|
83
|
-
headers,
|
|
84
|
-
query
|
|
85
|
-
};
|
|
86
|
-
Object.keys(params).forEach((key) => {
|
|
87
|
-
if (!pathParams.includes(key) && !queryParamNames.includes(key) && !headerParamnames.includes(key)) {
|
|
88
|
-
returnOptions.body ?? (returnOptions.body = {});
|
|
89
|
-
Reflect.set(returnOptions.body, key, params[key]);
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
return [requestPathWithParams, returnOptions];
|
|
93
109
|
}
|
|
94
110
|
|
|
95
111
|
function createAPIClient(params) {
|
|
96
|
-
const defaultHeaders = {
|
|
97
|
-
"sw-access-key": params.accessToken
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
112
|
+
const defaultHeaders = createHeaders({
|
|
113
|
+
"sw-access-key": params.accessToken,
|
|
114
|
+
Accept: "application/json",
|
|
115
|
+
"sw-context-token": params.contextToken,
|
|
116
|
+
...params.defaultHeaders
|
|
117
|
+
});
|
|
118
|
+
const apiClientHooks = createHooks();
|
|
102
119
|
const apiFetch = ofetch.create({
|
|
103
120
|
baseURL: params.baseURL,
|
|
104
121
|
// async onRequest({ request, options }) {},
|
|
105
122
|
// async onRequestError({ request, options, error }) {},
|
|
106
123
|
async onResponse(context) {
|
|
107
|
-
|
|
108
|
-
|
|
124
|
+
apiClientHooks.callHook("onSuccessResponse", context.response);
|
|
125
|
+
if (context.response.headers.has("sw-context-token") && defaultHeaders["sw-context-token"] !== context.response.headers.get("sw-context-token")) {
|
|
126
|
+
const newContextToken = context.response.headers.get(
|
|
127
|
+
"sw-context-token"
|
|
128
|
+
);
|
|
109
129
|
defaultHeaders["sw-context-token"] = newContextToken;
|
|
110
|
-
|
|
130
|
+
apiClientHooks.callHook("onContextChanged", newContextToken);
|
|
111
131
|
}
|
|
112
132
|
},
|
|
113
|
-
async onResponseError({
|
|
133
|
+
async onResponseError({ response }) {
|
|
134
|
+
apiClientHooks.callHook("onResponseError", response);
|
|
114
135
|
errorInterceptor(response);
|
|
115
136
|
}
|
|
116
137
|
});
|
|
117
|
-
async function invoke(pathParam, params2) {
|
|
118
|
-
const [
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
);
|
|
122
|
-
return apiFetch(
|
|
138
|
+
async function invoke(pathParam, ...params2) {
|
|
139
|
+
const [, method, requestPath] = pathParam.split(" ");
|
|
140
|
+
const currentParams = params2[0] || {};
|
|
141
|
+
const requestPathWithParams = createPathWithParams(
|
|
123
142
|
requestPath,
|
|
124
|
-
|
|
125
|
-
...options,
|
|
126
|
-
headers: {
|
|
127
|
-
...defaultHeaders,
|
|
128
|
-
...options.headers
|
|
129
|
-
}
|
|
130
|
-
}
|
|
143
|
+
currentParams.pathParams
|
|
131
144
|
);
|
|
145
|
+
const fetchOptions = {
|
|
146
|
+
...currentParams.fetchOptions || {}
|
|
147
|
+
};
|
|
148
|
+
const resp = await apiFetch.raw(requestPathWithParams, {
|
|
149
|
+
...fetchOptions,
|
|
150
|
+
method,
|
|
151
|
+
body: currentParams.body,
|
|
152
|
+
headers: defu(defaultHeaders, currentParams.headers),
|
|
153
|
+
query: currentParams.query
|
|
154
|
+
});
|
|
155
|
+
return {
|
|
156
|
+
data: resp._data,
|
|
157
|
+
status: resp.status
|
|
158
|
+
};
|
|
132
159
|
}
|
|
133
160
|
return {
|
|
134
|
-
invoke
|
|
161
|
+
invoke,
|
|
162
|
+
/**
|
|
163
|
+
* Default headers used in every client request (if not overriden in specific request).
|
|
164
|
+
*/
|
|
165
|
+
defaultHeaders,
|
|
166
|
+
hook: apiClientHooks.hook
|
|
135
167
|
};
|
|
136
168
|
}
|
|
169
|
+
|
|
137
170
|
function createAuthorizationHeader(token) {
|
|
138
171
|
if (!token)
|
|
139
|
-
return
|
|
172
|
+
return "";
|
|
140
173
|
if (token.startsWith("Bearer "))
|
|
141
174
|
return token;
|
|
142
175
|
return `Bearer ${token}`;
|
|
143
176
|
}
|
|
144
177
|
function createAdminAPIClient(params) {
|
|
178
|
+
const isTokenBasedAuth = params.credentials?.grant_type === "client_credentials";
|
|
145
179
|
const sessionData = {
|
|
146
180
|
accessToken: params.sessionData?.accessToken || "",
|
|
147
181
|
refreshToken: params.sessionData?.refreshToken || "",
|
|
148
182
|
expirationTime: Number(params.sessionData?.expirationTime || 0)
|
|
149
183
|
};
|
|
184
|
+
const defaultHeaders = createHeaders({
|
|
185
|
+
Authorization: createAuthorizationHeader(sessionData.accessToken),
|
|
186
|
+
Accept: "application/json"
|
|
187
|
+
});
|
|
188
|
+
const apiClientHooks = createHooks();
|
|
189
|
+
function getSessionData() {
|
|
190
|
+
return { ...sessionData };
|
|
191
|
+
}
|
|
192
|
+
function setSessionData(data) {
|
|
193
|
+
sessionData.accessToken = data.accessToken;
|
|
194
|
+
sessionData.refreshToken = data.refreshToken || "";
|
|
195
|
+
sessionData.expirationTime = data.expirationTime;
|
|
196
|
+
return getSessionData();
|
|
197
|
+
}
|
|
150
198
|
function updateSessionData(responseData) {
|
|
151
199
|
if (responseData?.access_token) {
|
|
152
200
|
defaultHeaders.Authorization = createAuthorizationHeader(
|
|
153
201
|
responseData.access_token
|
|
154
202
|
);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
...sessionData
|
|
203
|
+
const dataCopy = setSessionData({
|
|
204
|
+
accessToken: responseData.access_token,
|
|
205
|
+
refreshToken: responseData.refresh_token,
|
|
206
|
+
expirationTime: Date.now() + responseData.expires_in * 1e3
|
|
160
207
|
});
|
|
208
|
+
apiClientHooks.callHook("onAuthChange", dataCopy);
|
|
161
209
|
}
|
|
162
210
|
}
|
|
163
|
-
function setSessionData(data) {
|
|
164
|
-
sessionData.accessToken = data.accessToken;
|
|
165
|
-
sessionData.refreshToken = data.refreshToken;
|
|
166
|
-
sessionData.expirationTime = data.expirationTime;
|
|
167
|
-
return getSessionData();
|
|
168
|
-
}
|
|
169
|
-
function getSessionData() {
|
|
170
|
-
return { ...sessionData };
|
|
171
|
-
}
|
|
172
|
-
const defaultHeaders = {
|
|
173
|
-
Authorization: createAuthorizationHeader(sessionData.accessToken)
|
|
174
|
-
};
|
|
175
211
|
const apiFetch = ofetch.create({
|
|
176
212
|
baseURL: params.baseURL,
|
|
177
213
|
async onRequest({ request, options }) {
|
|
178
214
|
const isExpired = sessionData.expirationTime <= Date.now();
|
|
179
215
|
if (isExpired && !request.toString().includes("/oauth/token")) {
|
|
216
|
+
if (!params.credentials && !isTokenBasedAuth && !sessionData.refreshToken) {
|
|
217
|
+
console.warn(
|
|
218
|
+
"[ApiClientWarning] No `credentials` or `sessionData` provided. Provide at least one of them to ensure authentication."
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
const body = params.credentials && !sessionData.refreshToken ? params.credentials : {
|
|
222
|
+
grant_type: "refresh_token",
|
|
223
|
+
client_id: "administration",
|
|
224
|
+
refresh_token: sessionData.refreshToken
|
|
225
|
+
};
|
|
180
226
|
await ofetch("/oauth/token", {
|
|
181
227
|
baseURL: params.baseURL,
|
|
182
228
|
method: "POST",
|
|
183
|
-
body
|
|
184
|
-
grant_type: "refresh_token",
|
|
185
|
-
client_id: "administration",
|
|
186
|
-
refresh_token: sessionData.refreshToken || ""
|
|
187
|
-
},
|
|
229
|
+
body,
|
|
188
230
|
headers: defaultHeaders,
|
|
189
231
|
onResponseError({ response }) {
|
|
190
232
|
errorInterceptor(response);
|
|
191
233
|
},
|
|
192
234
|
onResponse(context) {
|
|
235
|
+
if (!context.response._data)
|
|
236
|
+
return;
|
|
193
237
|
updateSessionData(context.response._data);
|
|
238
|
+
options.headers = {
|
|
239
|
+
...options.headers,
|
|
240
|
+
Authorization: createAuthorizationHeader(
|
|
241
|
+
context.response._data.access_token
|
|
242
|
+
)
|
|
243
|
+
};
|
|
194
244
|
}
|
|
195
245
|
});
|
|
196
246
|
}
|
|
197
247
|
},
|
|
198
248
|
async onResponse(context) {
|
|
249
|
+
apiClientHooks.callHook("onSuccessResponse", context.response);
|
|
199
250
|
updateSessionData(context.response._data);
|
|
200
251
|
},
|
|
201
|
-
async onResponseError({
|
|
252
|
+
async onResponseError({ response }) {
|
|
253
|
+
apiClientHooks.callHook("onResponseError", response);
|
|
202
254
|
errorInterceptor(response);
|
|
203
255
|
}
|
|
204
256
|
});
|
|
205
|
-
async function invoke(pathParam, params2) {
|
|
206
|
-
const [
|
|
207
|
-
|
|
208
|
-
params2
|
|
209
|
-
);
|
|
210
|
-
return apiFetch(
|
|
257
|
+
async function invoke(pathParam, ...params2) {
|
|
258
|
+
const [, method, requestPath] = pathParam.split(" ");
|
|
259
|
+
const requestPathWithParams = createPathWithParams(
|
|
211
260
|
requestPath,
|
|
212
|
-
|
|
213
|
-
...options,
|
|
214
|
-
headers: {
|
|
215
|
-
...defaultHeaders,
|
|
216
|
-
...options.headers
|
|
217
|
-
}
|
|
218
|
-
}
|
|
261
|
+
params2[0]?.pathParams
|
|
219
262
|
);
|
|
263
|
+
const fetchOptions = {
|
|
264
|
+
...params2[0]?.fetchOptions || {}
|
|
265
|
+
};
|
|
266
|
+
const resp = await apiFetch.raw(requestPathWithParams, {
|
|
267
|
+
...fetchOptions,
|
|
268
|
+
method,
|
|
269
|
+
body: params2[0]?.body,
|
|
270
|
+
headers: defu(defaultHeaders, params2[0]?.headers),
|
|
271
|
+
query: params2[0]?.query
|
|
272
|
+
});
|
|
273
|
+
return {
|
|
274
|
+
data: resp._data,
|
|
275
|
+
status: resp.status
|
|
276
|
+
};
|
|
220
277
|
}
|
|
221
278
|
return {
|
|
222
|
-
/**
|
|
223
|
-
* Invoke API request based on provided path definition.
|
|
224
|
-
*/
|
|
225
279
|
invoke,
|
|
226
280
|
/**
|
|
227
281
|
* Enables to change session data in runtime. Useful for testing purposes.
|
|
228
|
-
* Setting session data with this
|
|
282
|
+
* Setting session data with this method will **not** fire `onAuthChange` hook.
|
|
229
283
|
*/
|
|
230
284
|
setSessionData,
|
|
231
285
|
/**
|
|
232
286
|
* Returns current session data. Useful for testing purposes, as in most cases you'll want to use `onAuthChange` hook for that.
|
|
233
287
|
*/
|
|
234
|
-
getSessionData
|
|
288
|
+
getSessionData,
|
|
289
|
+
/**
|
|
290
|
+
* Default headers used in every client request (if not overriden in specific request).
|
|
291
|
+
*/
|
|
292
|
+
defaultHeaders,
|
|
293
|
+
/**
|
|
294
|
+
* Available hooks for the client.
|
|
295
|
+
*/
|
|
296
|
+
hook: apiClientHooks.hook
|
|
235
297
|
};
|
|
236
298
|
}
|
|
237
299
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shopware/api-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Shopware client for API connection.",
|
|
5
5
|
"author": "Shopware",
|
|
6
|
+
"type": "module",
|
|
6
7
|
"repository": {
|
|
7
8
|
"type": "git",
|
|
8
9
|
"url": "git+https://github.com/shopware/frontends.git"
|
|
@@ -35,31 +36,36 @@
|
|
|
35
36
|
"types": "./dist/index.d.mts",
|
|
36
37
|
"default": "./dist/index.mjs"
|
|
37
38
|
}
|
|
38
|
-
}
|
|
39
|
+
},
|
|
40
|
+
"./api-types": "./api-types/storeApiTypes.d.ts",
|
|
41
|
+
"./store-api-types": "./api-types/storeApiTypes.d.ts",
|
|
42
|
+
"./admin-api-types": "./api-types/adminApiTypes.d.ts"
|
|
39
43
|
},
|
|
40
44
|
"devDependencies": {
|
|
41
|
-
"@
|
|
42
|
-
"@
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"eslint-config-shopware": "0.0.
|
|
45
|
+
"@codspeed/vitest-plugin": "3.1.0",
|
|
46
|
+
"@types/prettier": "3.0.0",
|
|
47
|
+
"@vitest/coverage-v8": "1.6.0",
|
|
48
|
+
"prettier": "3.3.2",
|
|
49
|
+
"unbuild": "2.0.0",
|
|
50
|
+
"vitest": "1.6.0",
|
|
51
|
+
"eslint-config-shopware": "0.0.9",
|
|
48
52
|
"tsconfig": "0.0.0"
|
|
49
53
|
},
|
|
50
54
|
"dependencies": {
|
|
51
|
-
"
|
|
55
|
+
"defu": "6.1.4",
|
|
56
|
+
"hookable": "5.5.3",
|
|
57
|
+
"ofetch": "1.3.4"
|
|
52
58
|
},
|
|
53
59
|
"scripts": {
|
|
54
60
|
"build": "export NODE_ENV=production && unbuild && pnpm build:types",
|
|
55
61
|
"build:types": "tsc ./src/*.ts --declaration --allowJs --emitDeclarationOnly --outDir ./temp --skipLibCheck",
|
|
56
62
|
"dev": "export NODE_ENV=development && unbuild --stub",
|
|
57
|
-
"generate": "esno ../api-gen/src/cli.ts generate",
|
|
58
63
|
"lint": "eslint src/**/*.ts* --fix --max-warnings=0 && pnpm run typecheck",
|
|
59
64
|
"typecheck": "tsc --noEmit",
|
|
60
|
-
"test": "vitest run
|
|
61
|
-
"test:types": "vitest typecheck --run",
|
|
65
|
+
"test": "vitest run --typecheck",
|
|
62
66
|
"test:bench": "vitest bench",
|
|
63
|
-
"test:watch": "vitest"
|
|
67
|
+
"test:watch": "vitest --typecheck",
|
|
68
|
+
"generate-types": "esno ../api-gen/src/cli.ts generate --apiType=store",
|
|
69
|
+
"generate-admin-types": "esno ../api-gen/src/cli.ts generate --apiType=admin"
|
|
64
70
|
}
|
|
65
71
|
}
|