react-shopwave-connect 0.1.2 → 0.3.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 +281 -39
- package/dist/core/index.cjs +435 -93
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +241 -28
- package/dist/core/index.d.ts +241 -28
- package/dist/core/index.js +405 -94
- package/dist/core/index.js.map +1 -1
- package/dist/hooks/index.cjs +328 -116
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +57 -12
- package/dist/hooks/index.d.ts +57 -12
- package/dist/hooks/index.js +329 -118
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +553 -112
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +265 -29
- package/dist/index.d.ts +265 -29
- package/dist/index.js +523 -114
- package/dist/index.js.map +1 -1
- package/dist/next/index.cjs +1019 -0
- package/dist/next/index.cjs.map +1 -0
- package/dist/next/index.d.cts +423 -0
- package/dist/next/index.d.ts +423 -0
- package/dist/next/index.js +987 -0
- package/dist/next/index.js.map +1 -0
- package/dist/server/index.cjs +670 -0
- package/dist/server/index.cjs.map +1 -0
- package/dist/server/index.d.cts +346 -0
- package/dist/server/index.d.ts +346 -0
- package/dist/server/index.js +650 -0
- package/dist/server/index.js.map +1 -0
- package/package.json +41 -8
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
//#region src/server/token.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Token model + helpers shared by every server-side integration.
|
|
4
|
+
*
|
|
5
|
+
* The Shopwave auth server returns (snake_case):
|
|
6
|
+
* { access_token, refresh_token, token_type: "OAuth", expires_in: 43200 }
|
|
7
|
+
*
|
|
8
|
+
* We store a normalised, camelCase shape with an absolute expiry so any
|
|
9
|
+
* request can decide whether the token is still usable without extra state.
|
|
10
|
+
*/
|
|
11
|
+
interface ShopwaveToken {
|
|
12
|
+
accessToken: string;
|
|
13
|
+
/** Long-lived; the Shopwave server does not rotate it on refresh. */
|
|
14
|
+
refreshToken?: string;
|
|
15
|
+
/** Scheme used in the Authorization header. Shopwave uses "OAuth". */
|
|
16
|
+
tokenType: string;
|
|
17
|
+
/** Absolute expiry, epoch milliseconds. Undefined if the server didn't say. */
|
|
18
|
+
expiresAt?: number;
|
|
19
|
+
}
|
|
20
|
+
/** Raw token response from `POST {authServer}/oauth/token`. */
|
|
21
|
+
interface ShopwaveTokenResponse {
|
|
22
|
+
access_token?: string;
|
|
23
|
+
refresh_token?: string;
|
|
24
|
+
token_type?: string;
|
|
25
|
+
expires_in?: number | string;
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
/** Shopwave API error id meaning "access token expired / invalid". */
|
|
29
|
+
declare const SHOPWAVE_TOKEN_EXPIRED_ERROR_ID = 908;
|
|
30
|
+
/**
|
|
31
|
+
* Converts a token-endpoint response into a {@link ShopwaveToken}.
|
|
32
|
+
* Returns `null` when the response has no access token.
|
|
33
|
+
*
|
|
34
|
+
* @param previous the token being refreshed; its refresh token is kept when
|
|
35
|
+
* the server doesn't send a new one.
|
|
36
|
+
*/
|
|
37
|
+
declare function tokenFromResponse(response: ShopwaveTokenResponse, previous?: ShopwaveToken, now?: number): ShopwaveToken | null;
|
|
38
|
+
/**
|
|
39
|
+
* Reads a token from session storage. Accepts both the current shape and the
|
|
40
|
+
* legacy raw response that older apps (e.g. AdminUI ≤ 0.1) stored directly in
|
|
41
|
+
* the session, so existing sessions survive an upgrade.
|
|
42
|
+
*/
|
|
43
|
+
declare function normalizeStoredToken(raw: unknown): ShopwaveToken | null;
|
|
44
|
+
/**
|
|
45
|
+
* True when the token has passed its expiry (minus `skewSeconds`).
|
|
46
|
+
* Tokens without a known expiry are treated as valid.
|
|
47
|
+
*
|
|
48
|
+
* Shopwave only issues a new access token once the old one has actually
|
|
49
|
+
* expired, so the default skew is 0 — refreshing early just returns the same
|
|
50
|
+
* token.
|
|
51
|
+
*/
|
|
52
|
+
declare function isTokenExpired(token: ShopwaveToken, {
|
|
53
|
+
skewSeconds,
|
|
54
|
+
now
|
|
55
|
+
}?: {
|
|
56
|
+
skewSeconds?: number;
|
|
57
|
+
now?: number;
|
|
58
|
+
}): boolean;
|
|
59
|
+
/** `Authorization` header value, e.g. `OAuth 111ad…`. */
|
|
60
|
+
declare function authorizationHeader(token: ShopwaveToken): string;
|
|
61
|
+
/**
|
|
62
|
+
* True when a Shopwave API response means "your access token is no longer
|
|
63
|
+
* valid": HTTP 401, or the API error 908 in the response envelope.
|
|
64
|
+
* Use it to trigger a forced refresh + a single retry.
|
|
65
|
+
*/
|
|
66
|
+
declare function isExpiredTokenResponse(status: number, body?: unknown): boolean;
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/server/oauth.d.ts
|
|
69
|
+
/**
|
|
70
|
+
* Per-app OAuth settings. Everything that differs between Shopwave apps lives
|
|
71
|
+
* here; the flow itself is identical for all of them.
|
|
72
|
+
*/
|
|
73
|
+
interface ShopwaveOAuthConfig {
|
|
74
|
+
/** e.g. `https://secure.merchantstack.com` (no trailing slash needed). */
|
|
75
|
+
authServerUrl: string;
|
|
76
|
+
clientId: string;
|
|
77
|
+
/** Server-side only. Never expose it to the browser. */
|
|
78
|
+
clientSecret: string;
|
|
79
|
+
/**
|
|
80
|
+
* The callback URL registered for this client on the auth server, e.g.
|
|
81
|
+
* `https://admin.example.com/auth`. Must match exactly.
|
|
82
|
+
*/
|
|
83
|
+
redirectUri: string;
|
|
84
|
+
/** Where the auth server sends the user after logout. Defaults to `redirectUri`. */
|
|
85
|
+
postLogoutRedirectUri?: string;
|
|
86
|
+
/** Defaults to `"application"`. */
|
|
87
|
+
scope?: string;
|
|
88
|
+
/** Defaults to `"online"`. */
|
|
89
|
+
accessType?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Body encoding for `POST /oauth/token`. Defaults to standard
|
|
92
|
+
* `application/x-www-form-urlencoded`; `"multipart"` sends `FormData`.
|
|
93
|
+
*/
|
|
94
|
+
tokenRequestFormat?: "urlencoded" | "multipart";
|
|
95
|
+
/** Auth-server paths. Defaults match Shopwave: `/login`, `/oauth/token`, `/logout`. */
|
|
96
|
+
endpoints?: {
|
|
97
|
+
login?: string;
|
|
98
|
+
token?: string;
|
|
99
|
+
logout?: string;
|
|
100
|
+
};
|
|
101
|
+
/** Custom fetch (tests, proxies). Defaults to global `fetch`. */
|
|
102
|
+
fetch?: typeof fetch;
|
|
103
|
+
}
|
|
104
|
+
interface ShopwaveOAuthClient {
|
|
105
|
+
readonly config: Readonly<ShopwaveOAuthConfig>;
|
|
106
|
+
/** URL to send the browser to so the user can sign in. */
|
|
107
|
+
buildLoginUrl(params?: {
|
|
108
|
+
state?: string;
|
|
109
|
+
}): string;
|
|
110
|
+
/** URL to send the browser to so the auth server ends its own session. */
|
|
111
|
+
buildLogoutUrl(params?: {
|
|
112
|
+
redirectUri?: string;
|
|
113
|
+
}): string;
|
|
114
|
+
/** Exchanges the `?code=` from the callback for tokens (server-to-server). */
|
|
115
|
+
exchangeCode(code: string): Promise<ShopwaveToken>;
|
|
116
|
+
/**
|
|
117
|
+
* Gets a fresh access token. Shopwave keeps the same refresh token, so the
|
|
118
|
+
* returned token carries the previous refresh token when none is sent back.
|
|
119
|
+
*/
|
|
120
|
+
refreshToken(token: ShopwaveToken | string): Promise<ShopwaveToken>;
|
|
121
|
+
}
|
|
122
|
+
/** Throws a readable error when required settings are missing. */
|
|
123
|
+
declare function assertOAuthConfig(config: Partial<ShopwaveOAuthConfig>): asserts config is ShopwaveOAuthConfig;
|
|
124
|
+
/**
|
|
125
|
+
* Creates a framework-agnostic Shopwave OAuth client (authorization-code flow
|
|
126
|
+
* with a client secret — the Shopwave auth server does not support PKCE, so
|
|
127
|
+
* this must run on a server).
|
|
128
|
+
*
|
|
129
|
+
* Config is validated lazily on first use, so creating the client at module
|
|
130
|
+
* scope doesn't break builds where env vars aren't present.
|
|
131
|
+
*/
|
|
132
|
+
declare function createShopwaveOAuth(config: ShopwaveOAuthConfig): ShopwaveOAuthClient;
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/server/returnTo.d.ts
|
|
135
|
+
/**
|
|
136
|
+
* Helpers for the round trip through the auth server.
|
|
137
|
+
*/
|
|
138
|
+
/**
|
|
139
|
+
* Only allows same-origin relative paths ("/products?tab=1"). Anything that
|
|
140
|
+
* could send the user to another site after login — absolute URLs,
|
|
141
|
+
* protocol-relative "//evil.com", backslash tricks, control characters —
|
|
142
|
+
* falls back to `fallback`.
|
|
143
|
+
*/
|
|
144
|
+
declare function sanitizeReturnTo(value: unknown, fallback?: string): string;
|
|
145
|
+
/** Random, URL-safe value for the OAuth `state` parameter (128 bits, hex). */
|
|
146
|
+
declare function createState(): string;
|
|
147
|
+
/** Constant-time string comparison for state values. */
|
|
148
|
+
declare function safeEqual(a: string, b: string): boolean;
|
|
149
|
+
//#endregion
|
|
150
|
+
//#region src/server/errors.d.ts
|
|
151
|
+
/**
|
|
152
|
+
* Error thrown by the server-side auth helpers.
|
|
153
|
+
*
|
|
154
|
+
* `code` is stable and safe to branch on; `status` is the HTTP status returned
|
|
155
|
+
* by the Shopwave auth server when there was one.
|
|
156
|
+
*/
|
|
157
|
+
type ShopwaveAuthErrorCode = "config_invalid" | "token_exchange_failed" | "token_refresh_failed" | "token_response_invalid" | "network_error";
|
|
158
|
+
declare class ShopwaveAuthError extends Error {
|
|
159
|
+
readonly code: ShopwaveAuthErrorCode;
|
|
160
|
+
readonly status?: number;
|
|
161
|
+
/** Raw response body from the auth server, if any. Never contains our secret. */
|
|
162
|
+
readonly body?: string;
|
|
163
|
+
constructor(code: ShopwaveAuthErrorCode, message: string, details?: {
|
|
164
|
+
status?: number;
|
|
165
|
+
body?: string;
|
|
166
|
+
cause?: unknown;
|
|
167
|
+
});
|
|
168
|
+
/**
|
|
169
|
+
* True when the auth server rejected the grant itself (bad/expired code or
|
|
170
|
+
* refresh token) rather than failing for a transient reason. Callers should
|
|
171
|
+
* treat the user as logged out.
|
|
172
|
+
*/
|
|
173
|
+
get isInvalidGrant(): boolean;
|
|
174
|
+
}
|
|
175
|
+
//#endregion
|
|
176
|
+
//#region src/core/entities.d.ts
|
|
177
|
+
/**
|
|
178
|
+
* How each Shopwave entity is addressed, shared by the client functions below
|
|
179
|
+
* and the server route handlers in `react-shopwave-connect/next`, so the two
|
|
180
|
+
* halves of the contract can't drift apart.
|
|
181
|
+
*/
|
|
182
|
+
interface EntityDefinition {
|
|
183
|
+
/** App route segment: `/api/<route>` and `/api/<route>/<id>`. */
|
|
184
|
+
route: string;
|
|
185
|
+
/** Key of the entity map in requests and responses (`{ products: { … } }`). */
|
|
186
|
+
collection: string;
|
|
187
|
+
/** Shopwave API path (`GET/POST/DELETE {apiUrl}/<upstream>`). */
|
|
188
|
+
upstream: string;
|
|
189
|
+
/** Header that filters reads by id (`productIds: 1,2`). */
|
|
190
|
+
idsHeader: string;
|
|
191
|
+
/** Header that names the record to delete (`productId: 1`). */
|
|
192
|
+
idHeader: string;
|
|
193
|
+
/** False for read-only entities (the API has no POST for them). */
|
|
194
|
+
writable: boolean;
|
|
195
|
+
/**
|
|
196
|
+
* How a delete is done upstream:
|
|
197
|
+
* - `"delete"`: `DELETE {apiUrl}/<upstream>` with the `idHeader` (205, empty body)
|
|
198
|
+
* - `"retire"`: the API has no DELETE; the record is retired by POSTing
|
|
199
|
+
* `{ id, [retireField]: <now> }` (employees: `exitDate`, promotions: `endDate`)
|
|
200
|
+
* - `"none"`: can't be deleted
|
|
201
|
+
*/
|
|
202
|
+
deleteMode: "delete" | "retire" | "none";
|
|
203
|
+
/** Date field set to "now" when `deleteMode` is `"retire"`. */
|
|
204
|
+
retireField?: string;
|
|
205
|
+
}
|
|
206
|
+
type EntityKind = "product" | "category" | "store" | "promotion" | "employee" | "consumer";
|
|
207
|
+
/** Entities that can be created/updated through the API. */
|
|
208
|
+
type WritableEntityKind = Exclude<EntityKind, "consumer">;
|
|
209
|
+
/** Entities that can be deleted (or retired) through the API. */
|
|
210
|
+
type DeletableEntityKind = Exclude<EntityKind, "consumer">;
|
|
211
|
+
/**
|
|
212
|
+
* Addressing per entity, following the Shopwave API reference
|
|
213
|
+
* (https://developer.merchantstack.com/api-reference.html) and checked against
|
|
214
|
+
* the live API where noted:
|
|
215
|
+
* - category/product/store: GET filtered by `<x>Ids`, POST upsert, DELETE with `<x>Id` → 205.
|
|
216
|
+
* - promotion: no DELETE; "deleting" a promotion ends it by setting `endDate` to now.
|
|
217
|
+
* - employee: POST updates `roleId`, `joinedDate`, `exitDate` (names can't be
|
|
218
|
+
* changed); no DELETE (live API: "Cannot DELETE /employee") → retired via `exitDate`.
|
|
219
|
+
* - consumer: read-only (`GET` with `ids`, comma-separated); live POST → 404.
|
|
220
|
+
*/
|
|
221
|
+
declare const SHOPWAVE_ENTITIES: Readonly<Record<EntityKind, EntityDefinition>>;
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region src/server/api.d.ts
|
|
224
|
+
/**
|
|
225
|
+
* The OAuth token a caller sent with the request, without its scheme, or `null`.
|
|
226
|
+
*
|
|
227
|
+
* Reads, in order: `Authorization: OAuth|Bearer <token>` (what the SDK sends
|
|
228
|
+
* from 0.3), the `token` header (SDK ≤ 0.2 writes), and `extras.token`
|
|
229
|
+
* (SDK ≤ 0.2 reads).
|
|
230
|
+
*/
|
|
231
|
+
declare function readRequestToken(request: Request): string | null;
|
|
232
|
+
/**
|
|
233
|
+
* `extras` keys that are never forwarded upstream (case-insensitive).
|
|
234
|
+
* `Content-Type` is allowed (SDK clients have always sent `application/json`
|
|
235
|
+
* on reads) but is replaced by the form content type on writes.
|
|
236
|
+
*/
|
|
237
|
+
declare const BLOCKED_EXTRAS: ReadonlySet<string>;
|
|
238
|
+
/**
|
|
239
|
+
* Parses the `extras` request header into upstream headers.
|
|
240
|
+
* Returns `null` when the header isn't a JSON object.
|
|
241
|
+
*/
|
|
242
|
+
declare function parseExtras(raw: string | null, blocked?: ReadonlySet<string>): Record<string, string> | null;
|
|
243
|
+
declare class RequestBodyError extends Error {}
|
|
244
|
+
/**
|
|
245
|
+
* Normalises a write request body into the Shopwave envelope
|
|
246
|
+
* `{ <collection>: { <ref>: entity, … } }`.
|
|
247
|
+
*
|
|
248
|
+
* Accepts:
|
|
249
|
+
* - the SDK ≥ 0.3 shape `{ <collection>: { "0": {...}, "1": {...} } }` (refs kept),
|
|
250
|
+
* - the older AdminUI shapes `{ <collection>: { new: {...} } }` / `{ updated: {...} }`,
|
|
251
|
+
* - a bare entity object `{ title: … }`.
|
|
252
|
+
*
|
|
253
|
+
* With `forcedId` (item routes) exactly one entity is allowed and its `id` is
|
|
254
|
+
* set from the URL.
|
|
255
|
+
*/
|
|
256
|
+
declare function normalizeWriteBody(def: Pick<EntityDefinition, "collection">, body: unknown, forcedId?: string): Record<string, Record<string, Record<string, unknown>>>;
|
|
257
|
+
interface ShopwaveApiConfig {
|
|
258
|
+
/** Shopwave API base URL, e.g. `process.env.SHOPWAVE_API_SERVER_URL`. */
|
|
259
|
+
apiUrl: string;
|
|
260
|
+
/**
|
|
261
|
+
* `Authorization` header value for the logged-in user (`"OAuth <token>"`),
|
|
262
|
+
* or `null` when logged out. Called again with `forceRefresh: true` when the
|
|
263
|
+
* API reports the token expired.
|
|
264
|
+
*/
|
|
265
|
+
getAuthorization?: (options?: {
|
|
266
|
+
forceRefresh?: boolean;
|
|
267
|
+
}) => Promise<string | null>;
|
|
268
|
+
/**
|
|
269
|
+
* Accept a token sent by the caller (`Authorization: OAuth <token>`, or the
|
|
270
|
+
* legacy `token` header / `extras.token`) instead of the session. The token
|
|
271
|
+
* is only forwarded to the Shopwave API, which validates it. Defaults to `true`
|
|
272
|
+
* (SDK integration tests, scripts and server-to-server calls rely on it).
|
|
273
|
+
*/
|
|
274
|
+
allowRequestToken?: boolean;
|
|
275
|
+
/** `x-accept-version` sent upstream. Defaults to `"2.0"`. */
|
|
276
|
+
apiVersion?: string;
|
|
277
|
+
/** Custom fetch for the upstream call. */
|
|
278
|
+
fetch?: typeof fetch;
|
|
279
|
+
/** Override how an entity is addressed (e.g. a different id header). */
|
|
280
|
+
entities?: Partial<Record<EntityKind, Partial<EntityDefinition>>>;
|
|
281
|
+
/** Extra `extras` keys to drop, on top of {@link BLOCKED_EXTRAS}. */
|
|
282
|
+
blockedExtras?: string[];
|
|
283
|
+
/**
|
|
284
|
+
* Called when the upstream call throws (network error). Defaults to a
|
|
285
|
+
* `console.error` with the method and path only — never headers or tokens.
|
|
286
|
+
*/
|
|
287
|
+
onError?: (error: unknown, context: {
|
|
288
|
+
method: string;
|
|
289
|
+
path: string;
|
|
290
|
+
}) => void;
|
|
291
|
+
}
|
|
292
|
+
interface ForwardInit {
|
|
293
|
+
/** HTTP method sent upstream. Defaults to `GET`. */
|
|
294
|
+
method?: string;
|
|
295
|
+
/** Shopwave API path, e.g. `"product"`. */
|
|
296
|
+
path: string;
|
|
297
|
+
/** Extra upstream headers; they win over `extras`. */
|
|
298
|
+
headers?: Record<string, string>;
|
|
299
|
+
/** Sent as the form field `postBody=<JSON>`. */
|
|
300
|
+
postBody?: unknown;
|
|
301
|
+
/** Forward the caller's `extras` header as upstream headers. Defaults to `true`. */
|
|
302
|
+
forwardExtras?: boolean;
|
|
303
|
+
}
|
|
304
|
+
/** Second argument Next.js (and similar) pass to dynamic route handlers. */
|
|
305
|
+
interface RouteContext {
|
|
306
|
+
params?: Promise<Record<string, string | string[] | undefined>> | Record<string, string | string[] | undefined>;
|
|
307
|
+
}
|
|
308
|
+
type RouteHandler = (request: Request, context?: RouteContext) => Promise<Response>;
|
|
309
|
+
interface CollectionHandlers {
|
|
310
|
+
/** List/filter via `extras` (e.g. `productIds`, `deleted`). */
|
|
311
|
+
GET: RouteHandler;
|
|
312
|
+
/** Create or update (Shopwave upserts: an `id` means update). */
|
|
313
|
+
POST: RouteHandler;
|
|
314
|
+
/** Same as POST (kept for older clients). */
|
|
315
|
+
PUT: RouteHandler;
|
|
316
|
+
}
|
|
317
|
+
interface ItemHandlers {
|
|
318
|
+
/** Read one record by the `[id]` route param. */
|
|
319
|
+
GET: RouteHandler;
|
|
320
|
+
/** Update the record at `[id]` (the id in the URL wins). */
|
|
321
|
+
PUT: RouteHandler;
|
|
322
|
+
/** Delete the record at `[id]`. Shopwave answers 205 with an empty body. */
|
|
323
|
+
DELETE: RouteHandler;
|
|
324
|
+
}
|
|
325
|
+
interface ShopwaveApiHandlers {
|
|
326
|
+
/** Calls the Shopwave API for this request (token, extras, refresh-retry) and returns its answer. */
|
|
327
|
+
forward(request: Request, init: ForwardInit): Promise<Response>;
|
|
328
|
+
/** Handlers for `app/api/<route>/route.ts`. */
|
|
329
|
+
collection(kind: EntityKind): CollectionHandlers;
|
|
330
|
+
/** Handlers for `app/api/<route>/[id]/route.ts`. */
|
|
331
|
+
item(kind: EntityKind, options?: {
|
|
332
|
+
param?: string;
|
|
333
|
+
}): ItemHandlers;
|
|
334
|
+
/** GET-only proxy for a Shopwave path (e.g. `"report"`, `"user"`, `"merchant"`). */
|
|
335
|
+
passthrough(path: string): {
|
|
336
|
+
GET: RouteHandler;
|
|
337
|
+
};
|
|
338
|
+
/** The entity table in use (defaults merged with `config.entities`). */
|
|
339
|
+
entity(kind: EntityKind): EntityDefinition;
|
|
340
|
+
}
|
|
341
|
+
/** `YYYY-MM-DD HH:mm:ss` in UTC, the datetime format Shopwave writes use (e.g. promotions). */
|
|
342
|
+
declare function shopwaveDateTime(date?: Date): string;
|
|
343
|
+
declare function createShopwaveApiHandlers(config: ShopwaveApiConfig): ShopwaveApiHandlers;
|
|
344
|
+
//#endregion
|
|
345
|
+
export { BLOCKED_EXTRAS, type CollectionHandlers, type DeletableEntityKind, type EntityDefinition, type EntityKind, type ForwardInit, type ItemHandlers, RequestBodyError, type RouteContext, type RouteHandler, SHOPWAVE_ENTITIES, SHOPWAVE_TOKEN_EXPIRED_ERROR_ID, type ShopwaveApiConfig, type ShopwaveApiHandlers, ShopwaveAuthError, type ShopwaveAuthErrorCode, type ShopwaveOAuthClient, type ShopwaveOAuthConfig, type ShopwaveToken, type ShopwaveTokenResponse, type WritableEntityKind, assertOAuthConfig, authorizationHeader, createShopwaveApiHandlers, createShopwaveOAuth, createState, isExpiredTokenResponse, isTokenExpired, normalizeStoredToken, normalizeWriteBody, parseExtras, readRequestToken, safeEqual, sanitizeReturnTo, shopwaveDateTime, tokenFromResponse };
|
|
346
|
+
//# sourceMappingURL=index.d.ts.map
|