@sdg.la/wishlist-stack-sdk 0.9.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 +279 -0
- package/dist/index.cjs +371 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +348 -0
- package/dist/index.d.ts +348 -0
- package/dist/index.js +363 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
type QueryValue = string | number | boolean | null | undefined | Array<string | number | boolean | null | undefined>;
|
|
2
|
+
type Query = Record<string, QueryValue>;
|
|
3
|
+
|
|
4
|
+
type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
5
|
+
type AuthMode = "authenticated" | "merchant";
|
|
6
|
+
type RequestArgs<TBody> = {
|
|
7
|
+
method: "GET" | "POST" | "PATCH" | "DELETE";
|
|
8
|
+
path: string;
|
|
9
|
+
auth: AuthMode;
|
|
10
|
+
query?: Query;
|
|
11
|
+
body?: TBody;
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type PaginationParams = {
|
|
18
|
+
page?: number;
|
|
19
|
+
pageSize?: number;
|
|
20
|
+
};
|
|
21
|
+
declare const DEFAULT_PAGE: 1;
|
|
22
|
+
declare const DEFAULT_PAGE_SIZE: 25;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Shared query option building blocks for list/group endpoints.
|
|
26
|
+
*
|
|
27
|
+
* Keep this extendable: as we add filters/sorts, we can add additional helpers/types here
|
|
28
|
+
* and reuse them across endpoints without duplicating logic.
|
|
29
|
+
*/
|
|
30
|
+
type PaginatedQuery<TExtra extends Query = Query> = PaginationParams & TExtra;
|
|
31
|
+
/**
|
|
32
|
+
* Merge a base query with pagination parameters.
|
|
33
|
+
* (Useful when an endpoint also gains filter/sort params over time.)
|
|
34
|
+
*/
|
|
35
|
+
declare function withPagination<TExtra extends Query>(query?: TExtra, pagination?: PaginationParams): PaginatedQuery<TExtra> | undefined;
|
|
36
|
+
|
|
37
|
+
type CreateListBody = {
|
|
38
|
+
name?: string;
|
|
39
|
+
description?: string;
|
|
40
|
+
groupId?: string;
|
|
41
|
+
};
|
|
42
|
+
type UpdateListBody = {
|
|
43
|
+
name?: string;
|
|
44
|
+
description?: string;
|
|
45
|
+
};
|
|
46
|
+
type AddItemsToListBody = {
|
|
47
|
+
items?: Array<{
|
|
48
|
+
variantId?: string;
|
|
49
|
+
quantity?: number;
|
|
50
|
+
note?: string;
|
|
51
|
+
}>;
|
|
52
|
+
};
|
|
53
|
+
type UpdateListItemBody = {
|
|
54
|
+
quantity?: number;
|
|
55
|
+
note?: string;
|
|
56
|
+
groupId?: string;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
type OkResponse = {
|
|
60
|
+
ok: true;
|
|
61
|
+
};
|
|
62
|
+
type Pagination = {
|
|
63
|
+
page: number;
|
|
64
|
+
pageSize: number;
|
|
65
|
+
totalCount: number;
|
|
66
|
+
totalPages: number;
|
|
67
|
+
};
|
|
68
|
+
type Image = {
|
|
69
|
+
altText?: string | null;
|
|
70
|
+
url: string;
|
|
71
|
+
width?: number | null;
|
|
72
|
+
height?: number | null;
|
|
73
|
+
};
|
|
74
|
+
type FeaturedItem = {
|
|
75
|
+
variantId: string | number;
|
|
76
|
+
image?: Image | null;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
type Money = {
|
|
80
|
+
amount: string;
|
|
81
|
+
currencyCode: string;
|
|
82
|
+
};
|
|
83
|
+
type SelectedOption = {
|
|
84
|
+
name: string;
|
|
85
|
+
value: string;
|
|
86
|
+
};
|
|
87
|
+
type Metafield = {
|
|
88
|
+
key: string;
|
|
89
|
+
value: string;
|
|
90
|
+
};
|
|
91
|
+
type HydratedVariant = {
|
|
92
|
+
id: string | number;
|
|
93
|
+
title: string;
|
|
94
|
+
sku?: string | null;
|
|
95
|
+
price: Money;
|
|
96
|
+
compareAtPrice?: Money | null;
|
|
97
|
+
availableForSale: boolean;
|
|
98
|
+
currentlyNotInStock: boolean;
|
|
99
|
+
selectedOptions: SelectedOption[];
|
|
100
|
+
image?: Image | null;
|
|
101
|
+
metafields: Metafield[];
|
|
102
|
+
};
|
|
103
|
+
type HydratedProduct = {
|
|
104
|
+
id: string | number;
|
|
105
|
+
title: string;
|
|
106
|
+
description: string;
|
|
107
|
+
availableForSale: boolean;
|
|
108
|
+
handle: string;
|
|
109
|
+
productType: string | null;
|
|
110
|
+
category: string | null;
|
|
111
|
+
tags: string[];
|
|
112
|
+
onlineStoreUrl: string | null;
|
|
113
|
+
metafields: Metafield[];
|
|
114
|
+
variant: HydratedVariant;
|
|
115
|
+
vendor: string | null;
|
|
116
|
+
};
|
|
117
|
+
type HydratedWishlistItem = {
|
|
118
|
+
id: string;
|
|
119
|
+
userNote?: string | null;
|
|
120
|
+
quantity: number;
|
|
121
|
+
position: number;
|
|
122
|
+
product: HydratedProduct;
|
|
123
|
+
};
|
|
124
|
+
type ListSummary = {
|
|
125
|
+
id: string;
|
|
126
|
+
name: string;
|
|
127
|
+
description: string | null;
|
|
128
|
+
position: number;
|
|
129
|
+
shared: boolean;
|
|
130
|
+
itemCount: number;
|
|
131
|
+
createdAt: string;
|
|
132
|
+
updatedAt: string;
|
|
133
|
+
featuredProducts?: FeaturedItem[];
|
|
134
|
+
};
|
|
135
|
+
type ListDetail = Omit<ListSummary, "featuredProducts"> & {
|
|
136
|
+
items: HydratedWishlistItem[];
|
|
137
|
+
};
|
|
138
|
+
/** GET `/api/lists` */
|
|
139
|
+
type GetListsResponse = {
|
|
140
|
+
lists: ListSummary[];
|
|
141
|
+
pagination: Pagination;
|
|
142
|
+
};
|
|
143
|
+
/** GET `/api/lists/:listId` */
|
|
144
|
+
type GetListResponse = ListDetail;
|
|
145
|
+
type CreateListResponse = unknown;
|
|
146
|
+
type UpdateListDetailsResponse = unknown;
|
|
147
|
+
type RemoveListResponse = OkResponse;
|
|
148
|
+
type AddItemsToListResponse = unknown;
|
|
149
|
+
type UpdateListItemResponse = unknown;
|
|
150
|
+
type RemoveItemFromListResponse = OkResponse;
|
|
151
|
+
type MarkListSharedResponse = unknown;
|
|
152
|
+
type RevokeListSharedResponse = unknown;
|
|
153
|
+
|
|
154
|
+
type RequestFn$2 = <TResponse = unknown, TBody = unknown>(args: RequestArgs<TBody>) => Promise<TResponse>;
|
|
155
|
+
type GetListsQuery = PaginatedQuery;
|
|
156
|
+
type GetListQuery = PaginatedQuery;
|
|
157
|
+
declare function createListsResource(request: RequestFn$2): {
|
|
158
|
+
/** Returns all lists for the authenticated customer under the current merchant. */
|
|
159
|
+
getAll: (query?: GetListsQuery) => Promise<GetListsResponse>;
|
|
160
|
+
/** Fetch list details by id. */
|
|
161
|
+
getById: (listId: string, query?: GetListQuery) => Promise<ListDetail>;
|
|
162
|
+
/** Create a new list. */
|
|
163
|
+
create: (body: CreateListBody) => Promise<unknown>;
|
|
164
|
+
/** Update list name/description. */
|
|
165
|
+
update: (listId: string, body: UpdateListBody) => Promise<unknown>;
|
|
166
|
+
/** Remove a list. */
|
|
167
|
+
remove: (listId: string) => Promise<OkResponse>;
|
|
168
|
+
/** Add one or more items to a list. */
|
|
169
|
+
addItems: (listId: string, body: AddItemsToListBody) => Promise<unknown>;
|
|
170
|
+
/** Update an item on a list. */
|
|
171
|
+
updateItem: (listId: string, itemId: string, body: UpdateListItemBody) => Promise<unknown>;
|
|
172
|
+
/** Remove an item from a list. */
|
|
173
|
+
removeItem: (listId: string, itemId: string) => Promise<OkResponse>;
|
|
174
|
+
/** Mark list as shared (public read-only). */
|
|
175
|
+
share: (listId: string) => Promise<unknown>;
|
|
176
|
+
/** Revoke list sharing. */
|
|
177
|
+
unshare: (listId: string) => Promise<unknown>;
|
|
178
|
+
/**
|
|
179
|
+
* Legacy endpoint kept in the OpenAPI spec (`/api/wishlists/{id}/add`).
|
|
180
|
+
* Prefer `addItems(listId, body)` unless your server only supports the legacy route.
|
|
181
|
+
*/
|
|
182
|
+
addItemsLegacy: (id: string, body: AddItemsToListBody) => Promise<unknown>;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
type CreateGroupBody = {
|
|
186
|
+
name?: string;
|
|
187
|
+
description?: string;
|
|
188
|
+
};
|
|
189
|
+
type UpdateGroupBody = {
|
|
190
|
+
name?: string;
|
|
191
|
+
description?: string;
|
|
192
|
+
};
|
|
193
|
+
type ReorderGroupBody = {
|
|
194
|
+
listIds?: string[];
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
type GroupSummary = {
|
|
198
|
+
id: string;
|
|
199
|
+
name: string;
|
|
200
|
+
description: string | null;
|
|
201
|
+
position: number;
|
|
202
|
+
shared: boolean;
|
|
203
|
+
listCount: number;
|
|
204
|
+
featuredItems: FeaturedItem[];
|
|
205
|
+
createdAt: string;
|
|
206
|
+
updatedAt: string;
|
|
207
|
+
};
|
|
208
|
+
type GetGroupsResponse = {
|
|
209
|
+
groups: GroupSummary[];
|
|
210
|
+
pagination: Pagination;
|
|
211
|
+
};
|
|
212
|
+
type GroupDetailList = {
|
|
213
|
+
id: string;
|
|
214
|
+
position: number;
|
|
215
|
+
name: string;
|
|
216
|
+
description: string | null;
|
|
217
|
+
isShared: boolean;
|
|
218
|
+
itemCount: number;
|
|
219
|
+
items: string[];
|
|
220
|
+
featuredItems: FeaturedItem[];
|
|
221
|
+
};
|
|
222
|
+
type GroupDetail = {
|
|
223
|
+
id: string;
|
|
224
|
+
name: string;
|
|
225
|
+
description: string | null;
|
|
226
|
+
position: number;
|
|
227
|
+
shared: boolean;
|
|
228
|
+
listCount: number;
|
|
229
|
+
createdAt: string;
|
|
230
|
+
updatedAt: string;
|
|
231
|
+
listsCount: number;
|
|
232
|
+
lists: GroupDetailList[];
|
|
233
|
+
pagination: Pagination;
|
|
234
|
+
};
|
|
235
|
+
type GetGroupResponse = GroupDetail;
|
|
236
|
+
type CreateGroupResponse = unknown;
|
|
237
|
+
type UpdateGroupDetailsResponse = unknown;
|
|
238
|
+
type RemoveGroupResponse = OkResponse;
|
|
239
|
+
type ReorderGroupResponse = unknown;
|
|
240
|
+
type MarkGroupSharedResponse = unknown;
|
|
241
|
+
type RevokeGroupSharedResponse = unknown;
|
|
242
|
+
|
|
243
|
+
type RequestFn$1 = <TResponse = unknown, TBody = unknown>(args: RequestArgs<TBody>) => Promise<TResponse>;
|
|
244
|
+
type GetGroupsQuery = PaginatedQuery;
|
|
245
|
+
type GetGroupQuery = PaginatedQuery;
|
|
246
|
+
declare function createGroupsResource(request: RequestFn$1): {
|
|
247
|
+
/** Fetch groups for the authenticated customer. */
|
|
248
|
+
getAll: (query?: GetGroupsQuery) => Promise<GetGroupsResponse>;
|
|
249
|
+
/** Fetch group details by id. */
|
|
250
|
+
getById: (groupId: string, query?: GetGroupQuery) => Promise<GroupDetail>;
|
|
251
|
+
/** Create a new group. */
|
|
252
|
+
create: (body: CreateGroupBody) => Promise<unknown>;
|
|
253
|
+
/** Update group name/description. */
|
|
254
|
+
update: (groupId: string, body: UpdateGroupBody) => Promise<unknown>;
|
|
255
|
+
/** Remove a group. */
|
|
256
|
+
remove: (groupId: string) => Promise<OkResponse>;
|
|
257
|
+
/** Reorder a group (spec uses listIds payload). */
|
|
258
|
+
reorder: (groupId: string, body: ReorderGroupBody) => Promise<unknown>;
|
|
259
|
+
/** Mark group as shared (public read-only). */
|
|
260
|
+
share: (groupId: string) => Promise<unknown>;
|
|
261
|
+
/** Revoke group sharing. */
|
|
262
|
+
unshare: (groupId: string) => Promise<unknown>;
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
type RequestFn = <TResponse = unknown, TBody = unknown>(args: RequestArgs<TBody>) => Promise<TResponse>;
|
|
266
|
+
declare function createSharedResource(request: RequestFn): {
|
|
267
|
+
/** Public read-only view of a shared list. Requires only merchant apiKey. */
|
|
268
|
+
getSharedList: (listId: string) => Promise<ListDetail>;
|
|
269
|
+
/** Public read-only view of a shared group. Requires only merchant apiKey. */
|
|
270
|
+
getSharedGroup: (groupId: string) => Promise<GroupDetail>;
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
type CreateWishlistStackClientOptions = {
|
|
274
|
+
baseUrl?: string;
|
|
275
|
+
apiKey: string;
|
|
276
|
+
customerAccessToken?: string;
|
|
277
|
+
fetch?: FetchLike;
|
|
278
|
+
};
|
|
279
|
+
type WishlistStackClient$1 = {
|
|
280
|
+
lists: ReturnType<typeof createListsResource>;
|
|
281
|
+
groups: ReturnType<typeof createGroupsResource>;
|
|
282
|
+
shared: ReturnType<typeof createSharedResource>;
|
|
283
|
+
};
|
|
284
|
+
declare function createWishlistStackClient(opts: CreateWishlistStackClientOptions): WishlistStackClient$1;
|
|
285
|
+
|
|
286
|
+
type Id = string;
|
|
287
|
+
type ApiErrorItem = {
|
|
288
|
+
message: string;
|
|
289
|
+
field?: string;
|
|
290
|
+
};
|
|
291
|
+
type ApiErrorResponse = {
|
|
292
|
+
errors?: ApiErrorItem[];
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
type GetSharedListResponse = GetListResponse;
|
|
296
|
+
type GetSharedGroupResponse = GetGroupResponse;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Class wrapper around `createWishlistStackClient()` for users who prefer `new`.
|
|
300
|
+
* Exposes `lists`, `groups`, and `shared` resources.
|
|
301
|
+
*/
|
|
302
|
+
declare class WishlistStackClient implements WishlistStackClient$1 {
|
|
303
|
+
readonly lists: WishlistStackClient$1["lists"];
|
|
304
|
+
readonly groups: WishlistStackClient$1["groups"];
|
|
305
|
+
readonly shared: WishlistStackClient$1["shared"];
|
|
306
|
+
constructor(opts: CreateWishlistStackClientOptions);
|
|
307
|
+
/** Back-compat alias: `client.groups.getAll()` */
|
|
308
|
+
getGroups(): Promise<GetGroupsResponse>;
|
|
309
|
+
/** Back-compat alias: `client.groups.getById(groupId)` */
|
|
310
|
+
getGroupById(groupId: string): Promise<GroupDetail>;
|
|
311
|
+
/** Back-compat alias: `client.lists.getAll()` */
|
|
312
|
+
getLists(): Promise<GetListsResponse>;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
type WishlistStackApiErrorDetails<TBody = unknown> = {
|
|
316
|
+
status: number;
|
|
317
|
+
url: string;
|
|
318
|
+
method: string;
|
|
319
|
+
requestId?: string;
|
|
320
|
+
body?: TBody;
|
|
321
|
+
};
|
|
322
|
+
declare class WishlistStackApiError<TBody = unknown> extends Error {
|
|
323
|
+
readonly name = "WishlistStackApiError";
|
|
324
|
+
readonly status: number;
|
|
325
|
+
readonly url: string;
|
|
326
|
+
readonly method: string;
|
|
327
|
+
readonly requestId?: string;
|
|
328
|
+
readonly body?: TBody;
|
|
329
|
+
constructor(message: string, details: WishlistStackApiErrorDetails<TBody>);
|
|
330
|
+
/**
|
|
331
|
+
* Best-effort extraction of API error items from the response body.
|
|
332
|
+
* Useful for UI/logging without needing to know the exact response shape.
|
|
333
|
+
*/
|
|
334
|
+
get apiErrors(): Array<{
|
|
335
|
+
message: string;
|
|
336
|
+
field?: string;
|
|
337
|
+
}> | undefined;
|
|
338
|
+
/**
|
|
339
|
+
* Convenience: extracted error messages (if present).
|
|
340
|
+
*/
|
|
341
|
+
get apiErrorMessages(): string[] | undefined;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Bundler-safe type guard (prefer this over `instanceof WishlistStackApiError`).
|
|
345
|
+
*/
|
|
346
|
+
declare function isWishlistStackApiError(value: unknown): value is WishlistStackApiError<unknown>;
|
|
347
|
+
|
|
348
|
+
export { type AddItemsToListBody, type AddItemsToListResponse, type ApiErrorItem, type ApiErrorResponse, type CreateGroupBody, type CreateGroupResponse, type CreateListBody, type CreateListResponse, type CreateWishlistStackClientOptions, DEFAULT_PAGE, DEFAULT_PAGE_SIZE, type FeaturedItem, type GetGroupResponse, type GetGroupsResponse, type GetListResponse, type GetListsResponse, type GetSharedGroupResponse, type GetSharedListResponse, type GroupDetail, type GroupDetailList, type GroupSummary, type HydratedProduct, type HydratedVariant, type HydratedWishlistItem, type Id, type Image, type ListDetail, type ListSummary, type MarkGroupSharedResponse, type MarkListSharedResponse, type Metafield, type Money, type OkResponse, type PaginatedQuery, type Pagination, type PaginationParams, type RemoveGroupResponse, type RemoveItemFromListResponse, type RemoveListResponse, type ReorderGroupBody, type ReorderGroupResponse, type RevokeGroupSharedResponse, type RevokeListSharedResponse, type SelectedOption, type UpdateGroupBody, type UpdateGroupDetailsResponse, type UpdateListBody, type UpdateListDetailsResponse, type UpdateListItemBody, type UpdateListItemResponse, WishlistStackApiError, type WishlistStackClient$1 as WishlistStackClient, WishlistStackClient as WishlistStackSDK, createWishlistStackClient, isWishlistStackApiError, withPagination };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
|
|
5
|
+
// src/constants.ts
|
|
6
|
+
var MAX_PAGINATION_SIZE = 25;
|
|
7
|
+
var BASE_URL = "https://wishlist-js.fly.dev";
|
|
8
|
+
|
|
9
|
+
// src/client/query.ts
|
|
10
|
+
function toQueryString(query) {
|
|
11
|
+
if (!query) return "";
|
|
12
|
+
const params = new URLSearchParams();
|
|
13
|
+
for (const [key, value] of Object.entries(query)) {
|
|
14
|
+
if (value === void 0 || value === null) continue;
|
|
15
|
+
if (Array.isArray(value)) {
|
|
16
|
+
for (const v of value) {
|
|
17
|
+
if (v === void 0 || v === null) continue;
|
|
18
|
+
params.append(key, String(v));
|
|
19
|
+
}
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
params.set(key, String(value));
|
|
23
|
+
}
|
|
24
|
+
const qs = params.toString();
|
|
25
|
+
return qs ? `?${qs}` : "";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/client/errors.ts
|
|
29
|
+
function isRecord(value) {
|
|
30
|
+
return typeof value === "object" && value !== null;
|
|
31
|
+
}
|
|
32
|
+
function isApiErrorItemLike(value) {
|
|
33
|
+
return isRecord(value) && "message" in value;
|
|
34
|
+
}
|
|
35
|
+
function extractApiErrors(body) {
|
|
36
|
+
if (!isRecord(body)) return void 0;
|
|
37
|
+
const errors = body.errors;
|
|
38
|
+
if (!Array.isArray(errors)) return void 0;
|
|
39
|
+
const out = [];
|
|
40
|
+
for (const e of errors) {
|
|
41
|
+
if (!isApiErrorItemLike(e)) continue;
|
|
42
|
+
const msg = typeof e.message === "string" ? e.message : void 0;
|
|
43
|
+
if (!msg) continue;
|
|
44
|
+
const field = typeof e.field === "string" ? e.field : void 0;
|
|
45
|
+
out.push(field ? { message: msg, field } : { message: msg });
|
|
46
|
+
}
|
|
47
|
+
return out.length ? out : void 0;
|
|
48
|
+
}
|
|
49
|
+
var WishlistStackApiError = class extends Error {
|
|
50
|
+
constructor(message, details) {
|
|
51
|
+
super(message);
|
|
52
|
+
__publicField(this, "name", "WishlistStackApiError");
|
|
53
|
+
__publicField(this, "status");
|
|
54
|
+
__publicField(this, "url");
|
|
55
|
+
__publicField(this, "method");
|
|
56
|
+
__publicField(this, "requestId");
|
|
57
|
+
__publicField(this, "body");
|
|
58
|
+
this.status = details.status;
|
|
59
|
+
this.url = details.url;
|
|
60
|
+
this.method = details.method;
|
|
61
|
+
this.requestId = details.requestId;
|
|
62
|
+
this.body = details.body;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Best-effort extraction of API error items from the response body.
|
|
66
|
+
* Useful for UI/logging without needing to know the exact response shape.
|
|
67
|
+
*/
|
|
68
|
+
get apiErrors() {
|
|
69
|
+
return extractApiErrors(this.body);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Convenience: extracted error messages (if present).
|
|
73
|
+
*/
|
|
74
|
+
get apiErrorMessages() {
|
|
75
|
+
const errs = this.apiErrors;
|
|
76
|
+
return errs?.map((e) => e.message);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
function isWishlistStackApiError(value) {
|
|
80
|
+
if (!isRecord(value)) return false;
|
|
81
|
+
return value.name === "WishlistStackApiError" && typeof value.status === "number" && typeof value.url === "string" && typeof value.method === "string";
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/client/request.ts
|
|
85
|
+
async function safeParseJson(res) {
|
|
86
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
87
|
+
if (!contentType.toLowerCase().includes("application/json")) return void 0;
|
|
88
|
+
try {
|
|
89
|
+
return await res.json();
|
|
90
|
+
} catch {
|
|
91
|
+
return void 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function createRequest(ctx) {
|
|
95
|
+
return async function request(args) {
|
|
96
|
+
const url = `${ctx.baseUrl}${args.path}${toQueryString(args.query)}`;
|
|
97
|
+
const headers = {
|
|
98
|
+
"X-Wishlist-Stack-Api-Key": ctx.apiKey,
|
|
99
|
+
...args.headers ?? {}
|
|
100
|
+
};
|
|
101
|
+
if (args.auth === "authenticated") {
|
|
102
|
+
const token = ctx.customerAccessToken;
|
|
103
|
+
if (token) headers["X-Shopify-Customer-Access-Token"] = token;
|
|
104
|
+
}
|
|
105
|
+
let body;
|
|
106
|
+
if (args.body !== void 0) {
|
|
107
|
+
headers["content-type"] ?? (headers["content-type"] = "application/json");
|
|
108
|
+
body = JSON.stringify(args.body);
|
|
109
|
+
}
|
|
110
|
+
const controller = args.timeoutMs ? new AbortController() : void 0;
|
|
111
|
+
const timeout = args.timeoutMs && controller ? setTimeout(() => controller.abort(), args.timeoutMs) : void 0;
|
|
112
|
+
const signal = args.signal ? args.signal : controller ? controller.signal : void 0;
|
|
113
|
+
const res = await ctx.fetch(url, {
|
|
114
|
+
method: args.method,
|
|
115
|
+
headers,
|
|
116
|
+
body,
|
|
117
|
+
signal
|
|
118
|
+
});
|
|
119
|
+
if (timeout) clearTimeout(timeout);
|
|
120
|
+
if (!res.ok) {
|
|
121
|
+
const errBody = await safeParseJson(res);
|
|
122
|
+
const requestId = res.headers.get("fly-request-id") ?? res.headers.get("x-request-id") ?? void 0;
|
|
123
|
+
throw new WishlistStackApiError(`Wishlist Stack API request failed (${res.status})`, {
|
|
124
|
+
status: res.status,
|
|
125
|
+
url,
|
|
126
|
+
method: args.method,
|
|
127
|
+
requestId,
|
|
128
|
+
body: errBody
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (res.status === 204) return void 0;
|
|
132
|
+
const parsed = await safeParseJson(res);
|
|
133
|
+
if (parsed === void 0) {
|
|
134
|
+
const text = await res.text().catch(() => "");
|
|
135
|
+
return text;
|
|
136
|
+
}
|
|
137
|
+
return parsed;
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/resources/lists/index.ts
|
|
142
|
+
function createListsResource(request) {
|
|
143
|
+
return {
|
|
144
|
+
/** Returns all lists for the authenticated customer under the current merchant. */
|
|
145
|
+
getAll: (query) => request({
|
|
146
|
+
method: "GET",
|
|
147
|
+
path: "/api/lists",
|
|
148
|
+
auth: "authenticated",
|
|
149
|
+
query
|
|
150
|
+
}),
|
|
151
|
+
/** Fetch list details by id. */
|
|
152
|
+
getById: (listId, query) => request({
|
|
153
|
+
method: "GET",
|
|
154
|
+
path: `/api/lists/${encodeURIComponent(listId)}`,
|
|
155
|
+
auth: "authenticated",
|
|
156
|
+
query
|
|
157
|
+
}),
|
|
158
|
+
/** Create a new list. */
|
|
159
|
+
create: (body) => request({
|
|
160
|
+
method: "POST",
|
|
161
|
+
path: "/api/lists",
|
|
162
|
+
auth: "authenticated",
|
|
163
|
+
body
|
|
164
|
+
}),
|
|
165
|
+
/** Update list name/description. */
|
|
166
|
+
update: (listId, body) => request({
|
|
167
|
+
method: "PATCH",
|
|
168
|
+
path: `/api/lists/${encodeURIComponent(listId)}`,
|
|
169
|
+
auth: "authenticated",
|
|
170
|
+
body
|
|
171
|
+
}),
|
|
172
|
+
/** Remove a list. */
|
|
173
|
+
remove: (listId) => request({
|
|
174
|
+
method: "DELETE",
|
|
175
|
+
path: `/api/lists/${encodeURIComponent(listId)}`,
|
|
176
|
+
auth: "authenticated"
|
|
177
|
+
}),
|
|
178
|
+
/** Add one or more items to a list. */
|
|
179
|
+
addItems: (listId, body) => request({
|
|
180
|
+
method: "POST",
|
|
181
|
+
path: `/api/lists/${encodeURIComponent(listId)}/add`,
|
|
182
|
+
auth: "authenticated",
|
|
183
|
+
body
|
|
184
|
+
}),
|
|
185
|
+
/** Update an item on a list. */
|
|
186
|
+
updateItem: (listId, itemId, body) => request({
|
|
187
|
+
method: "PATCH",
|
|
188
|
+
path: `/api/lists/${encodeURIComponent(listId)}/items/${encodeURIComponent(itemId)}`,
|
|
189
|
+
auth: "authenticated",
|
|
190
|
+
body
|
|
191
|
+
}),
|
|
192
|
+
/** Remove an item from a list. */
|
|
193
|
+
removeItem: (listId, itemId) => request({
|
|
194
|
+
method: "DELETE",
|
|
195
|
+
path: `/api/lists/${encodeURIComponent(listId)}/items/${encodeURIComponent(itemId)}`,
|
|
196
|
+
auth: "authenticated"
|
|
197
|
+
}),
|
|
198
|
+
/** Mark list as shared (public read-only). */
|
|
199
|
+
share: (listId) => request({
|
|
200
|
+
method: "POST",
|
|
201
|
+
path: `/api/lists/${encodeURIComponent(listId)}/share`,
|
|
202
|
+
auth: "authenticated"
|
|
203
|
+
}),
|
|
204
|
+
/** Revoke list sharing. */
|
|
205
|
+
unshare: (listId) => request({
|
|
206
|
+
method: "DELETE",
|
|
207
|
+
path: `/api/lists/${encodeURIComponent(listId)}/share`,
|
|
208
|
+
auth: "authenticated"
|
|
209
|
+
}),
|
|
210
|
+
/**
|
|
211
|
+
* Legacy endpoint kept in the OpenAPI spec (`/api/wishlists/{id}/add`).
|
|
212
|
+
* Prefer `addItems(listId, body)` unless your server only supports the legacy route.
|
|
213
|
+
*/
|
|
214
|
+
addItemsLegacy: (id, body) => request({
|
|
215
|
+
method: "POST",
|
|
216
|
+
path: `/api/wishlists/${encodeURIComponent(id)}/add`,
|
|
217
|
+
auth: "authenticated",
|
|
218
|
+
body
|
|
219
|
+
})
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/resources/groups/index.ts
|
|
224
|
+
function createGroupsResource(request) {
|
|
225
|
+
return {
|
|
226
|
+
/** Fetch groups for the authenticated customer. */
|
|
227
|
+
getAll: (query) => request({
|
|
228
|
+
method: "GET",
|
|
229
|
+
path: "/api/groups",
|
|
230
|
+
auth: "authenticated",
|
|
231
|
+
query
|
|
232
|
+
}),
|
|
233
|
+
/** Fetch group details by id. */
|
|
234
|
+
getById: (groupId, query) => request({
|
|
235
|
+
method: "GET",
|
|
236
|
+
path: `/api/groups/${encodeURIComponent(groupId)}`,
|
|
237
|
+
auth: "authenticated",
|
|
238
|
+
query
|
|
239
|
+
}),
|
|
240
|
+
/** Create a new group. */
|
|
241
|
+
create: (body) => request({
|
|
242
|
+
method: "POST",
|
|
243
|
+
path: "/api/groups",
|
|
244
|
+
auth: "authenticated",
|
|
245
|
+
body
|
|
246
|
+
}),
|
|
247
|
+
/** Update group name/description. */
|
|
248
|
+
update: (groupId, body) => request({
|
|
249
|
+
method: "PATCH",
|
|
250
|
+
path: `/api/groups/${encodeURIComponent(groupId)}`,
|
|
251
|
+
auth: "authenticated",
|
|
252
|
+
body
|
|
253
|
+
}),
|
|
254
|
+
/** Remove a group. */
|
|
255
|
+
remove: (groupId) => request({
|
|
256
|
+
method: "DELETE",
|
|
257
|
+
path: `/api/groups/${encodeURIComponent(groupId)}`,
|
|
258
|
+
auth: "authenticated"
|
|
259
|
+
}),
|
|
260
|
+
/** Reorder a group (spec uses listIds payload). */
|
|
261
|
+
reorder: (groupId, body) => request({
|
|
262
|
+
method: "POST",
|
|
263
|
+
path: `/api/groups/${encodeURIComponent(groupId)}/reorder`,
|
|
264
|
+
auth: "authenticated",
|
|
265
|
+
body
|
|
266
|
+
}),
|
|
267
|
+
/** Mark group as shared (public read-only). */
|
|
268
|
+
share: (groupId) => request({
|
|
269
|
+
method: "POST",
|
|
270
|
+
path: `/api/groups/${encodeURIComponent(groupId)}/share`,
|
|
271
|
+
auth: "authenticated"
|
|
272
|
+
}),
|
|
273
|
+
/** Revoke group sharing. */
|
|
274
|
+
unshare: (groupId) => request({
|
|
275
|
+
method: "DELETE",
|
|
276
|
+
path: `/api/groups/${encodeURIComponent(groupId)}/share`,
|
|
277
|
+
auth: "authenticated"
|
|
278
|
+
})
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// src/resources/shared/index.ts
|
|
283
|
+
function createSharedResource(request) {
|
|
284
|
+
return {
|
|
285
|
+
/** Public read-only view of a shared list. Requires only merchant apiKey. */
|
|
286
|
+
getSharedList: (listId) => request({
|
|
287
|
+
method: "GET",
|
|
288
|
+
path: `/api/shared/list/${encodeURIComponent(listId)}`,
|
|
289
|
+
auth: "merchant"
|
|
290
|
+
}),
|
|
291
|
+
/** Public read-only view of a shared group. Requires only merchant apiKey. */
|
|
292
|
+
getSharedGroup: (groupId) => request({
|
|
293
|
+
method: "GET",
|
|
294
|
+
path: `/api/shared/group/${encodeURIComponent(groupId)}`,
|
|
295
|
+
auth: "merchant"
|
|
296
|
+
})
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/client/createWishlistStackClient.ts
|
|
301
|
+
function createWishlistStackClient(opts) {
|
|
302
|
+
if (!opts.apiKey) {
|
|
303
|
+
throw new Error(
|
|
304
|
+
"merchant api key is required. Pass it to createWishlistStackClient({ apiKey })"
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
const fetchImpl = opts.fetch ?? (typeof globalThis.fetch === "function" ? ((input, init) => globalThis.fetch(input, init)) : void 0);
|
|
308
|
+
if (!fetchImpl) {
|
|
309
|
+
throw new Error(
|
|
310
|
+
"No fetch implementation found. Provide one via createWishlistStackClient({ fetch }) or use Node 18+ / modern browsers."
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
const request = createRequest({
|
|
314
|
+
baseUrl: opts.baseUrl ?? BASE_URL,
|
|
315
|
+
apiKey: opts.apiKey,
|
|
316
|
+
customerAccessToken: opts.customerAccessToken,
|
|
317
|
+
fetch: fetchImpl
|
|
318
|
+
});
|
|
319
|
+
return {
|
|
320
|
+
lists: createListsResource(request),
|
|
321
|
+
groups: createGroupsResource(request),
|
|
322
|
+
shared: createSharedResource(request)
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// src/WishlistStackClient.ts
|
|
327
|
+
var WishlistStackClient = class {
|
|
328
|
+
constructor(opts) {
|
|
329
|
+
__publicField(this, "lists");
|
|
330
|
+
__publicField(this, "groups");
|
|
331
|
+
__publicField(this, "shared");
|
|
332
|
+
const client = createWishlistStackClient(opts);
|
|
333
|
+
this.lists = client.lists;
|
|
334
|
+
this.groups = client.groups;
|
|
335
|
+
this.shared = client.shared;
|
|
336
|
+
}
|
|
337
|
+
/** Back-compat alias: `client.groups.getAll()` */
|
|
338
|
+
getGroups() {
|
|
339
|
+
return this.groups.getAll();
|
|
340
|
+
}
|
|
341
|
+
/** Back-compat alias: `client.groups.getById(groupId)` */
|
|
342
|
+
getGroupById(groupId) {
|
|
343
|
+
return this.groups.getById(groupId);
|
|
344
|
+
}
|
|
345
|
+
/** Back-compat alias: `client.lists.getAll()` */
|
|
346
|
+
getLists() {
|
|
347
|
+
return this.lists.getAll();
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// src/types/pagination.ts
|
|
352
|
+
var DEFAULT_PAGE = 1;
|
|
353
|
+
var DEFAULT_PAGE_SIZE = MAX_PAGINATION_SIZE;
|
|
354
|
+
|
|
355
|
+
// src/types/query-options.ts
|
|
356
|
+
function withPagination(query, pagination) {
|
|
357
|
+
if (!query && !pagination) return void 0;
|
|
358
|
+
return { ...query ?? {}, ...pagination ?? {} };
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export { DEFAULT_PAGE, DEFAULT_PAGE_SIZE, WishlistStackApiError, WishlistStackClient as WishlistStackSDK, createWishlistStackClient, isWishlistStackApiError, withPagination };
|
|
362
|
+
//# sourceMappingURL=index.js.map
|
|
363
|
+
//# sourceMappingURL=index.js.map
|