@shopware/api-client 0.5.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 +208 -84
- 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 +169 -106
- package/dist/index.d.cts +89259 -62623
- package/dist/index.d.mts +89259 -62623
- package/dist/index.d.ts +89259 -62623
- package/dist/index.mjs +165 -106
- 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
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { components as mainComponents } from "./storeApiTypes";
|
|
2
|
+
|
|
3
|
+
export type components = mainComponents;
|
|
4
|
+
// & {
|
|
5
|
+
// schemas: schemas;
|
|
6
|
+
// };
|
|
7
|
+
|
|
8
|
+
export type Schemas = {
|
|
9
|
+
ProductListingResult: components["schemas"]["EntitySearchResult"] & {
|
|
10
|
+
/** @enum {string} */
|
|
11
|
+
apiAlias: "product_listing";
|
|
12
|
+
/** Contains the available sorting. These can be used to show a sorting select-box in the product listing. */
|
|
13
|
+
availableSortings: {
|
|
14
|
+
/** @enum {string} */
|
|
15
|
+
apiAlias: "product_sorting";
|
|
16
|
+
key: string;
|
|
17
|
+
label: string;
|
|
18
|
+
priority: number;
|
|
19
|
+
translated: {
|
|
20
|
+
apiAlias?: string;
|
|
21
|
+
key?: string;
|
|
22
|
+
label: string;
|
|
23
|
+
};
|
|
24
|
+
}[];
|
|
25
|
+
/** Contains the state of the filters. These can be used to create listing filters. */
|
|
26
|
+
currentFilters: {
|
|
27
|
+
manufacturer: string[];
|
|
28
|
+
navigationId: string;
|
|
29
|
+
price: {
|
|
30
|
+
/** @default 0 */
|
|
31
|
+
max: number;
|
|
32
|
+
/** @default 0 */
|
|
33
|
+
min: number;
|
|
34
|
+
};
|
|
35
|
+
properties: string[];
|
|
36
|
+
rating?: number; // TODO: [OpenAPI][ProductListingResult] - rating should be defined the same as in body of the request
|
|
37
|
+
search: string; // TODO: [OpenAPI][ProductListingResult] - search should be required as is required in body of the request, otherwise everywhere optional
|
|
38
|
+
/** @default false */
|
|
39
|
+
"shipping-free": boolean;
|
|
40
|
+
};
|
|
41
|
+
elements: components["schemas"]["Product"][];
|
|
42
|
+
/** @enum {string} */
|
|
43
|
+
entity?: "product";
|
|
44
|
+
sorting?: string;
|
|
45
|
+
};
|
|
46
|
+
SwagPaypalVaultToken: {
|
|
47
|
+
// TODO: [OpenAPI][SwagPaypalVaultToken] - add SwagPaypalVaultToken definition to schema
|
|
48
|
+
/** Format: date-time */
|
|
49
|
+
createdAt: string;
|
|
50
|
+
customer?: components["schemas"]["Customer"];
|
|
51
|
+
customerId: string;
|
|
52
|
+
id?: string;
|
|
53
|
+
identifier: string;
|
|
54
|
+
mainMapping?: components["schemas"]["SwagPaypalVaultTokenMapping"];
|
|
55
|
+
paymentMethod?: components["schemas"]["PaymentMethod"];
|
|
56
|
+
paymentMethodId: string;
|
|
57
|
+
/** Format: date-time */
|
|
58
|
+
updatedAt?: string;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type operations = {
|
|
63
|
+
"register post /account/register": {
|
|
64
|
+
contentType?: "application/json";
|
|
65
|
+
accept?: "application/json";
|
|
66
|
+
body: {
|
|
67
|
+
/** Flag indicating accepted data protection */
|
|
68
|
+
acceptedDataProtection: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Account type of the customer which can be either `private` or `business`.
|
|
71
|
+
* @default private
|
|
72
|
+
*/
|
|
73
|
+
accountType?: string;
|
|
74
|
+
/** Field can be used to store an affiliate tracking code */
|
|
75
|
+
affiliateCode?: string;
|
|
76
|
+
billingAddress: Omit<
|
|
77
|
+
components["schemas"]["CustomerAddress"],
|
|
78
|
+
"createdAt" | "id" | "customerId" | "firstName" | "lastName"
|
|
79
|
+
>; // TODO: [OpenAPI][register] - omit id, createdAt, customerId, firstName, lastName while creating address (or better to reverse and pick required fields)
|
|
80
|
+
/** Birthday day */
|
|
81
|
+
birthdayDay?: number;
|
|
82
|
+
/** Birthday month */
|
|
83
|
+
birthdayMonth?: number;
|
|
84
|
+
/** Birthday year */
|
|
85
|
+
birthdayYear?: number;
|
|
86
|
+
/** Field can be used to store a campaign tracking code */
|
|
87
|
+
campaignCode?: string;
|
|
88
|
+
/** Email of the customer. Has to be unique, unless `guest` is `true` */
|
|
89
|
+
email: string;
|
|
90
|
+
/** Customer first name. Value will be reused for shipping and billing address if not provided explicitly. */
|
|
91
|
+
firstName: string;
|
|
92
|
+
/**
|
|
93
|
+
* If set, will create a guest customer. Guest customers can re-use an email address and don't need a password.
|
|
94
|
+
* @default false
|
|
95
|
+
*/
|
|
96
|
+
guest?: boolean;
|
|
97
|
+
/** Customer last name. Value will be reused for shipping and billing address if not provided explicitly. */
|
|
98
|
+
lastName: string;
|
|
99
|
+
/** Password for the customer. Required, unless `guest` is `true` */
|
|
100
|
+
password: string;
|
|
101
|
+
/** Id of the salutation for the customer account. Fetch options using `salutation` endpoint. */
|
|
102
|
+
salutationId: string;
|
|
103
|
+
shippingAddress?: components["schemas"]["CustomerAddress"];
|
|
104
|
+
/** URL of the storefront for that registration. Used in confirmation emails. Has to be one of the configured domains of the sales channel. */
|
|
105
|
+
storefrontUrl: string;
|
|
106
|
+
/** (Academic) title of the customer */
|
|
107
|
+
title?: string;
|
|
108
|
+
};
|
|
109
|
+
response: components["schemas"]["Customer"];
|
|
110
|
+
responseCode: 200;
|
|
111
|
+
};
|
|
112
|
+
"addLineItem post /checkout/cart/line-item": {
|
|
113
|
+
contentType?: "application/json";
|
|
114
|
+
accept?: "application/json";
|
|
115
|
+
headers?: {
|
|
116
|
+
/** Instructs Shopware to return the response in the given language. */
|
|
117
|
+
"sw-language-id"?: string;
|
|
118
|
+
};
|
|
119
|
+
body: {
|
|
120
|
+
// TODO: [OpenAPI][addLineItem] - add proper request body type with required fields
|
|
121
|
+
items: Array<{
|
|
122
|
+
id?: string; // TODO: [OpenAPI][addLineItem] - check if this is used at all?
|
|
123
|
+
referencedId: string;
|
|
124
|
+
quantity?: number;
|
|
125
|
+
type: "product" | "promotion" | "custom" | "credit"; // TODO: [OpenAPI][addLineItem] - add proper type -> see also #456
|
|
126
|
+
}>;
|
|
127
|
+
};
|
|
128
|
+
response: components["schemas"]["Cart"];
|
|
129
|
+
responseCode: 200;
|
|
130
|
+
};
|
|
131
|
+
"updateLineItem patch /checkout/cart/line-item": {
|
|
132
|
+
contentType?: "application/json";
|
|
133
|
+
accept?: "application/json";
|
|
134
|
+
headers?: {
|
|
135
|
+
/** Instructs Shopware to return the response in the given language. */
|
|
136
|
+
"sw-language-id"?: string;
|
|
137
|
+
};
|
|
138
|
+
body: {
|
|
139
|
+
// TODO: [OpenAPI][updateLineItem] - add proper request body type with required fields
|
|
140
|
+
items: Array<{
|
|
141
|
+
id: string;
|
|
142
|
+
quantity: number;
|
|
143
|
+
}>;
|
|
144
|
+
};
|
|
145
|
+
response: components["schemas"]["Cart"];
|
|
146
|
+
responseCode: 200;
|
|
147
|
+
};
|
|
148
|
+
"readProduct post /product": {
|
|
149
|
+
contentType?: "application/json";
|
|
150
|
+
accept?: "application/json";
|
|
151
|
+
headers?: {
|
|
152
|
+
/** Instructs Shopware to return the response in the given language. */
|
|
153
|
+
"sw-language-id"?: string;
|
|
154
|
+
};
|
|
155
|
+
body?: components["schemas"]["Criteria"];
|
|
156
|
+
response: {
|
|
157
|
+
elements: components["schemas"]["Product"][]; // TODO: [OpenAPI][readProduct]: add elements property as required
|
|
158
|
+
} & components["schemas"]["EntitySearchResult"];
|
|
159
|
+
responseCode: 200;
|
|
160
|
+
};
|
|
161
|
+
"readShippingMethod post /shipping-method": {
|
|
162
|
+
contentType?: "application/json";
|
|
163
|
+
accept?: "application/json";
|
|
164
|
+
headers?: {
|
|
165
|
+
/** Instructs Shopware to return the response in the given language. */
|
|
166
|
+
"sw-language-id"?: string;
|
|
167
|
+
};
|
|
168
|
+
query?: {
|
|
169
|
+
/** List only available shipping methods. This filters shipping methods methods which can not be used in the actual context because of their availability rule. */
|
|
170
|
+
onlyAvailable?: boolean;
|
|
171
|
+
};
|
|
172
|
+
body?: components["schemas"]["Criteria"];
|
|
173
|
+
response: {
|
|
174
|
+
/** aggregation result */
|
|
175
|
+
aggregations?: Record<string, never>;
|
|
176
|
+
elements: components["schemas"]["ShippingMethod"][]; // TODO: [OpenAPI][readShippingMethod]: response should be `EntitySearchResult` and elements should be required
|
|
177
|
+
/** Total amount */
|
|
178
|
+
total?: number;
|
|
179
|
+
};
|
|
180
|
+
responseCode: 200;
|
|
181
|
+
};
|
|
182
|
+
};
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const ofetch = require('ofetch');
|
|
4
|
+
const hookable = require('hookable');
|
|
5
|
+
const defu = require('defu');
|
|
6
|
+
|
|
7
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
8
|
+
|
|
9
|
+
const defu__default = /*#__PURE__*/_interopDefaultCompat(defu);
|
|
10
|
+
|
|
11
|
+
function createHeaders(init) {
|
|
12
|
+
const _headers = {
|
|
13
|
+
"Content-Type": "application/json"
|
|
14
|
+
};
|
|
15
|
+
const handler = {
|
|
16
|
+
get: (target, prop) => {
|
|
17
|
+
if (prop === "apply") {
|
|
18
|
+
return apply;
|
|
19
|
+
}
|
|
20
|
+
return Reflect.get(target, prop);
|
|
21
|
+
},
|
|
22
|
+
set: (target, prop, value) => {
|
|
23
|
+
if (prop === "apply") {
|
|
24
|
+
throw new Error("Cannot override apply method");
|
|
25
|
+
}
|
|
26
|
+
return Reflect.set(target, prop, value);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const headersProxy = new Proxy(
|
|
30
|
+
_headers,
|
|
31
|
+
handler
|
|
32
|
+
);
|
|
33
|
+
function apply(headers) {
|
|
34
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
35
|
+
if (value) {
|
|
36
|
+
headersProxy[key] = value;
|
|
37
|
+
} else {
|
|
38
|
+
delete headersProxy[key];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
headersProxy.apply({ ...init });
|
|
43
|
+
return headersProxy;
|
|
44
|
+
}
|
|
4
45
|
|
|
5
46
|
var __defProp = Object.defineProperty;
|
|
6
47
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -11,14 +52,23 @@ var __publicField = (obj, key, value) => {
|
|
|
11
52
|
class ApiClientError extends Error {
|
|
12
53
|
constructor(response) {
|
|
13
54
|
let message = "Failed request";
|
|
14
|
-
|
|
55
|
+
const errorDetails = response._data || {
|
|
56
|
+
errors: [
|
|
57
|
+
{
|
|
58
|
+
title: "Unknown error",
|
|
59
|
+
detail: "API did not return errors, but request failed. Please check the network tab."
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
};
|
|
63
|
+
message += errorDetails.errors?.reduce((message2, error) => {
|
|
15
64
|
let pointer = "";
|
|
16
65
|
if (error.source?.pointer) {
|
|
17
66
|
pointer = `[${error.source.pointer}]`;
|
|
18
67
|
}
|
|
68
|
+
const details = error.detail ?? "No error details provided.";
|
|
19
69
|
return `${message2}
|
|
20
|
-
- [${error.title}]${pointer} ${
|
|
21
|
-
}, "");
|
|
70
|
+
- [${error.title}]${pointer} ${details}`;
|
|
71
|
+
}, "") ?? "";
|
|
22
72
|
super(message);
|
|
23
73
|
/**
|
|
24
74
|
* Flag to indicate if the request was successful.
|
|
@@ -45,9 +95,7 @@ class ApiClientError extends Error {
|
|
|
45
95
|
*/
|
|
46
96
|
__publicField(this, "headers");
|
|
47
97
|
this.name = "ApiClientError";
|
|
48
|
-
this.details =
|
|
49
|
-
errors: [{ title: "Unknown error", detail: "" }]
|
|
50
|
-
};
|
|
98
|
+
this.details = errorDetails;
|
|
51
99
|
this.ok = response.ok;
|
|
52
100
|
this.status = response.status;
|
|
53
101
|
this.statusText = response.statusText;
|
|
@@ -55,188 +103,203 @@ class ApiClientError extends Error {
|
|
|
55
103
|
this.headers = response.headers;
|
|
56
104
|
}
|
|
57
105
|
}
|
|
106
|
+
|
|
58
107
|
function errorInterceptor(response) {
|
|
59
108
|
throw new ApiClientError(response);
|
|
60
109
|
}
|
|
61
110
|
|
|
62
|
-
function
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const pathParams = requestPath.match(/{[^}]+}/g)?.map((param) => param.substring(1, param.length - 1)) || [];
|
|
66
|
-
const requestPathWithParams = pathParams.reduce((acc, paramName) => {
|
|
67
|
-
return acc.replace(`{${paramName}}`, params[paramName]);
|
|
111
|
+
function createPathWithParams(requestPath, pathParams) {
|
|
112
|
+
return Object.keys(pathParams || {}).reduce((acc, paramName) => {
|
|
113
|
+
return acc.replace(`{${paramName}}`, pathParams[paramName]);
|
|
68
114
|
}, requestPath);
|
|
69
|
-
const queryParamNames = queryParams?.split(",") || [];
|
|
70
|
-
const headerParamnames = headerParams?.split(",") || [];
|
|
71
|
-
const headers = {};
|
|
72
|
-
headerParamnames.forEach((paramName) => {
|
|
73
|
-
headers[paramName] = params[paramName];
|
|
74
|
-
});
|
|
75
|
-
const query = {};
|
|
76
|
-
queryParamNames.forEach((paramName) => {
|
|
77
|
-
let queryParamName = paramName;
|
|
78
|
-
if (Array.isArray(params[paramName]) && !queryParamName.includes("[]")) {
|
|
79
|
-
queryParamName += "[]";
|
|
80
|
-
}
|
|
81
|
-
query[queryParamName] = params[paramName];
|
|
82
|
-
});
|
|
83
|
-
const returnOptions = {
|
|
84
|
-
method: method.toUpperCase(),
|
|
85
|
-
headers,
|
|
86
|
-
query
|
|
87
|
-
};
|
|
88
|
-
if (!params) {
|
|
89
|
-
return [requestPathWithParams, returnOptions];
|
|
90
|
-
}
|
|
91
|
-
Object.keys(params).forEach((key) => {
|
|
92
|
-
if (!pathParams.includes(key) && !queryParamNames.includes(key) && !headerParamnames.includes(key)) {
|
|
93
|
-
returnOptions.body ?? (returnOptions.body = {});
|
|
94
|
-
Reflect.set(returnOptions.body, key, params[key]);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
return [requestPathWithParams, returnOptions];
|
|
98
115
|
}
|
|
99
116
|
|
|
100
117
|
function createAPIClient(params) {
|
|
101
|
-
const defaultHeaders = {
|
|
102
|
-
"sw-access-key": params.accessToken
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
118
|
+
const defaultHeaders = createHeaders({
|
|
119
|
+
"sw-access-key": params.accessToken,
|
|
120
|
+
Accept: "application/json",
|
|
121
|
+
"sw-context-token": params.contextToken,
|
|
122
|
+
...params.defaultHeaders
|
|
123
|
+
});
|
|
124
|
+
const apiClientHooks = hookable.createHooks();
|
|
107
125
|
const apiFetch = ofetch.ofetch.create({
|
|
108
126
|
baseURL: params.baseURL,
|
|
109
127
|
// async onRequest({ request, options }) {},
|
|
110
128
|
// async onRequestError({ request, options, error }) {},
|
|
111
129
|
async onResponse(context) {
|
|
112
|
-
|
|
113
|
-
|
|
130
|
+
apiClientHooks.callHook("onSuccessResponse", context.response);
|
|
131
|
+
if (context.response.headers.has("sw-context-token") && defaultHeaders["sw-context-token"] !== context.response.headers.get("sw-context-token")) {
|
|
132
|
+
const newContextToken = context.response.headers.get(
|
|
133
|
+
"sw-context-token"
|
|
134
|
+
);
|
|
114
135
|
defaultHeaders["sw-context-token"] = newContextToken;
|
|
115
|
-
|
|
136
|
+
apiClientHooks.callHook("onContextChanged", newContextToken);
|
|
116
137
|
}
|
|
117
138
|
},
|
|
118
|
-
async onResponseError({
|
|
139
|
+
async onResponseError({ response }) {
|
|
140
|
+
apiClientHooks.callHook("onResponseError", response);
|
|
119
141
|
errorInterceptor(response);
|
|
120
142
|
}
|
|
121
143
|
});
|
|
122
144
|
async function invoke(pathParam, ...params2) {
|
|
123
|
-
const [
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
);
|
|
127
|
-
return apiFetch(
|
|
145
|
+
const [, method, requestPath] = pathParam.split(" ");
|
|
146
|
+
const currentParams = params2[0] || {};
|
|
147
|
+
const requestPathWithParams = createPathWithParams(
|
|
128
148
|
requestPath,
|
|
129
|
-
|
|
130
|
-
...options,
|
|
131
|
-
headers: {
|
|
132
|
-
...defaultHeaders,
|
|
133
|
-
...options.headers
|
|
134
|
-
}
|
|
135
|
-
}
|
|
149
|
+
currentParams.pathParams
|
|
136
150
|
);
|
|
151
|
+
const fetchOptions = {
|
|
152
|
+
...currentParams.fetchOptions || {}
|
|
153
|
+
};
|
|
154
|
+
const resp = await apiFetch.raw(requestPathWithParams, {
|
|
155
|
+
...fetchOptions,
|
|
156
|
+
method,
|
|
157
|
+
body: currentParams.body,
|
|
158
|
+
headers: defu__default(defaultHeaders, currentParams.headers),
|
|
159
|
+
query: currentParams.query
|
|
160
|
+
});
|
|
161
|
+
return {
|
|
162
|
+
data: resp._data,
|
|
163
|
+
status: resp.status
|
|
164
|
+
};
|
|
137
165
|
}
|
|
138
166
|
return {
|
|
139
|
-
invoke
|
|
167
|
+
invoke,
|
|
168
|
+
/**
|
|
169
|
+
* Default headers used in every client request (if not overriden in specific request).
|
|
170
|
+
*/
|
|
171
|
+
defaultHeaders,
|
|
172
|
+
hook: apiClientHooks.hook
|
|
140
173
|
};
|
|
141
174
|
}
|
|
175
|
+
|
|
142
176
|
function createAuthorizationHeader(token) {
|
|
143
177
|
if (!token)
|
|
144
|
-
return
|
|
178
|
+
return "";
|
|
145
179
|
if (token.startsWith("Bearer "))
|
|
146
180
|
return token;
|
|
147
181
|
return `Bearer ${token}`;
|
|
148
182
|
}
|
|
149
183
|
function createAdminAPIClient(params) {
|
|
184
|
+
const isTokenBasedAuth = params.credentials?.grant_type === "client_credentials";
|
|
150
185
|
const sessionData = {
|
|
151
186
|
accessToken: params.sessionData?.accessToken || "",
|
|
152
187
|
refreshToken: params.sessionData?.refreshToken || "",
|
|
153
188
|
expirationTime: Number(params.sessionData?.expirationTime || 0)
|
|
154
189
|
};
|
|
190
|
+
const defaultHeaders = createHeaders({
|
|
191
|
+
Authorization: createAuthorizationHeader(sessionData.accessToken),
|
|
192
|
+
Accept: "application/json"
|
|
193
|
+
});
|
|
194
|
+
const apiClientHooks = hookable.createHooks();
|
|
195
|
+
function getSessionData() {
|
|
196
|
+
return { ...sessionData };
|
|
197
|
+
}
|
|
198
|
+
function setSessionData(data) {
|
|
199
|
+
sessionData.accessToken = data.accessToken;
|
|
200
|
+
sessionData.refreshToken = data.refreshToken || "";
|
|
201
|
+
sessionData.expirationTime = data.expirationTime;
|
|
202
|
+
return getSessionData();
|
|
203
|
+
}
|
|
155
204
|
function updateSessionData(responseData) {
|
|
156
205
|
if (responseData?.access_token) {
|
|
157
206
|
defaultHeaders.Authorization = createAuthorizationHeader(
|
|
158
207
|
responseData.access_token
|
|
159
208
|
);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
...sessionData
|
|
209
|
+
const dataCopy = setSessionData({
|
|
210
|
+
accessToken: responseData.access_token,
|
|
211
|
+
refreshToken: responseData.refresh_token,
|
|
212
|
+
expirationTime: Date.now() + responseData.expires_in * 1e3
|
|
165
213
|
});
|
|
214
|
+
apiClientHooks.callHook("onAuthChange", dataCopy);
|
|
166
215
|
}
|
|
167
216
|
}
|
|
168
|
-
function setSessionData(data) {
|
|
169
|
-
sessionData.accessToken = data.accessToken;
|
|
170
|
-
sessionData.refreshToken = data.refreshToken;
|
|
171
|
-
sessionData.expirationTime = data.expirationTime;
|
|
172
|
-
return getSessionData();
|
|
173
|
-
}
|
|
174
|
-
function getSessionData() {
|
|
175
|
-
return { ...sessionData };
|
|
176
|
-
}
|
|
177
|
-
const defaultHeaders = {
|
|
178
|
-
Authorization: createAuthorizationHeader(sessionData.accessToken)
|
|
179
|
-
};
|
|
180
217
|
const apiFetch = ofetch.ofetch.create({
|
|
181
218
|
baseURL: params.baseURL,
|
|
182
219
|
async onRequest({ request, options }) {
|
|
183
220
|
const isExpired = sessionData.expirationTime <= Date.now();
|
|
184
221
|
if (isExpired && !request.toString().includes("/oauth/token")) {
|
|
222
|
+
if (!params.credentials && !isTokenBasedAuth && !sessionData.refreshToken) {
|
|
223
|
+
console.warn(
|
|
224
|
+
"[ApiClientWarning] No `credentials` or `sessionData` provided. Provide at least one of them to ensure authentication."
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
const body = params.credentials && !sessionData.refreshToken ? params.credentials : {
|
|
228
|
+
grant_type: "refresh_token",
|
|
229
|
+
client_id: "administration",
|
|
230
|
+
refresh_token: sessionData.refreshToken
|
|
231
|
+
};
|
|
185
232
|
await ofetch.ofetch("/oauth/token", {
|
|
186
233
|
baseURL: params.baseURL,
|
|
187
234
|
method: "POST",
|
|
188
|
-
body
|
|
189
|
-
grant_type: "refresh_token",
|
|
190
|
-
client_id: "administration",
|
|
191
|
-
refresh_token: sessionData.refreshToken || ""
|
|
192
|
-
},
|
|
235
|
+
body,
|
|
193
236
|
headers: defaultHeaders,
|
|
194
237
|
onResponseError({ response }) {
|
|
195
238
|
errorInterceptor(response);
|
|
196
239
|
},
|
|
197
240
|
onResponse(context) {
|
|
241
|
+
if (!context.response._data)
|
|
242
|
+
return;
|
|
198
243
|
updateSessionData(context.response._data);
|
|
244
|
+
options.headers = {
|
|
245
|
+
...options.headers,
|
|
246
|
+
Authorization: createAuthorizationHeader(
|
|
247
|
+
context.response._data.access_token
|
|
248
|
+
)
|
|
249
|
+
};
|
|
199
250
|
}
|
|
200
251
|
});
|
|
201
252
|
}
|
|
202
253
|
},
|
|
203
254
|
async onResponse(context) {
|
|
255
|
+
apiClientHooks.callHook("onSuccessResponse", context.response);
|
|
204
256
|
updateSessionData(context.response._data);
|
|
205
257
|
},
|
|
206
|
-
async onResponseError({
|
|
258
|
+
async onResponseError({ response }) {
|
|
259
|
+
apiClientHooks.callHook("onResponseError", response);
|
|
207
260
|
errorInterceptor(response);
|
|
208
261
|
}
|
|
209
262
|
});
|
|
210
|
-
async function invoke(pathParam, params2) {
|
|
211
|
-
const [
|
|
212
|
-
|
|
213
|
-
params2
|
|
214
|
-
);
|
|
215
|
-
return apiFetch(
|
|
263
|
+
async function invoke(pathParam, ...params2) {
|
|
264
|
+
const [, method, requestPath] = pathParam.split(" ");
|
|
265
|
+
const requestPathWithParams = createPathWithParams(
|
|
216
266
|
requestPath,
|
|
217
|
-
|
|
218
|
-
...options,
|
|
219
|
-
headers: {
|
|
220
|
-
...defaultHeaders,
|
|
221
|
-
...options.headers
|
|
222
|
-
}
|
|
223
|
-
}
|
|
267
|
+
params2[0]?.pathParams
|
|
224
268
|
);
|
|
269
|
+
const fetchOptions = {
|
|
270
|
+
...params2[0]?.fetchOptions || {}
|
|
271
|
+
};
|
|
272
|
+
const resp = await apiFetch.raw(requestPathWithParams, {
|
|
273
|
+
...fetchOptions,
|
|
274
|
+
method,
|
|
275
|
+
body: params2[0]?.body,
|
|
276
|
+
headers: defu__default(defaultHeaders, params2[0]?.headers),
|
|
277
|
+
query: params2[0]?.query
|
|
278
|
+
});
|
|
279
|
+
return {
|
|
280
|
+
data: resp._data,
|
|
281
|
+
status: resp.status
|
|
282
|
+
};
|
|
225
283
|
}
|
|
226
284
|
return {
|
|
227
|
-
/**
|
|
228
|
-
* Invoke API request based on provided path definition.
|
|
229
|
-
*/
|
|
230
285
|
invoke,
|
|
231
286
|
/**
|
|
232
287
|
* Enables to change session data in runtime. Useful for testing purposes.
|
|
233
|
-
* Setting session data with this
|
|
288
|
+
* Setting session data with this method will **not** fire `onAuthChange` hook.
|
|
234
289
|
*/
|
|
235
290
|
setSessionData,
|
|
236
291
|
/**
|
|
237
292
|
* Returns current session data. Useful for testing purposes, as in most cases you'll want to use `onAuthChange` hook for that.
|
|
238
293
|
*/
|
|
239
|
-
getSessionData
|
|
294
|
+
getSessionData,
|
|
295
|
+
/**
|
|
296
|
+
* Default headers used in every client request (if not overriden in specific request).
|
|
297
|
+
*/
|
|
298
|
+
defaultHeaders,
|
|
299
|
+
/**
|
|
300
|
+
* Available hooks for the client.
|
|
301
|
+
*/
|
|
302
|
+
hook: apiClientHooks.hook
|
|
240
303
|
};
|
|
241
304
|
}
|
|
242
305
|
|