@forgecart/sdk 1.2.5 → 1.2.6
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 +2 -87
- package/dist/admin-types.generated.d.ts +9884 -0
- package/dist/admin.d.ts +55 -8
- package/dist/admin.generated.d.ts +790 -0
- package/dist/admin.generated.js +1801 -0
- package/dist/admin.js +112 -23
- package/dist/client.generated.d.ts +251 -0
- package/dist/client.generated.js +757 -0
- package/dist/documents.generated.d.ts +465 -0
- package/dist/documents.generated.js +24283 -0
- package/dist/error-utils.d.ts +25 -0
- package/dist/error-utils.js +59 -0
- package/dist/hook-event-map.generated.d.ts +243 -0
- package/dist/hook-event-map.generated.js +9 -0
- package/dist/index.d.ts +23 -59
- package/dist/index.js +35 -83
- package/dist/sdk-hook-subscription.generated.d.ts +29 -0
- package/dist/sdk-hook-subscription.generated.js +73 -0
- package/dist/sdk-plugin.generated.d.ts +38 -0
- package/dist/sdk-plugin.generated.js +31 -0
- package/dist/sdk-types.generated.d.ts +56 -0
- package/dist/sdk-types.generated.js +28 -0
- package/dist/shop-types.generated.d.ts +4776 -0
- package/dist/shop.d.ts +18 -8
- package/dist/shop.generated.d.ts +213 -0
- package/dist/shop.generated.js +465 -0
- package/dist/shop.js +37 -23
- package/dist/upload.d.ts +14 -0
- package/dist/upload.js +163 -0
- package/package.json +10 -25
- package/src/admin-types.generated.ts +28377 -0
- package/src/admin.generated.ts +1771 -0
- package/src/admin.ts +55 -9
- package/src/client.generated.ts +845 -0
- package/src/documents.generated.ts +24730 -0
- package/src/error-utils.ts +74 -0
- package/src/hook-event-map.generated.ts +252 -0
- package/src/index.ts +23 -115
- package/src/sdk-hook-subscription.generated.ts +93 -0
- package/src/sdk-plugin.generated.ts +59 -0
- package/src/sdk-types.generated.ts +79 -0
- package/src/shop-types.generated.ts +10400 -0
- package/src/shop.generated.ts +452 -0
- package/src/shop.ts +18 -9
- package/src/upload.ts +211 -0
- package/LICENSE +0 -21
- package/dist/admin-namespace.d.ts +0 -2688
- package/dist/admin-namespace.js +0 -9691
- package/dist/admin-types.d.ts +0 -16195
- package/dist/shop-namespace.d.ts +0 -718
- package/dist/shop-namespace.js +0 -3124
- package/dist/shop-types.d.ts +0 -6310
- package/src/admin-namespace.ts +0 -11428
- package/src/admin-types.ts +0 -10809
- package/src/shop-namespace.ts +0 -3547
- package/src/shop-types.ts +0 -4684
- /package/dist/{admin-types.js → admin-types.generated.js} +0 -0
- /package/dist/{shop-types.js → shop-types.generated.js} +0 -0
|
@@ -0,0 +1,845 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
/**
|
|
3
|
+
* AUTO-GENERATED FILE — DO NOT EDIT
|
|
4
|
+
*
|
|
5
|
+
* This file was generated by @forgecart/client-sdk-generators.
|
|
6
|
+
* Any manual changes will be overwritten on the next generation run.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
import { Observable, firstValueFrom } from 'rxjs';
|
|
11
|
+
import { createClient as createWsClient, type Client as WsClient } from 'graphql-ws';
|
|
12
|
+
import { uploadViaFetch } from './upload';
|
|
13
|
+
import { HookSubscriptionManager, hookDispatchDocument, hookRespondDocument } from './sdk-hook-subscription.generated';
|
|
14
|
+
import type { HookDispatchEvent, HookSubscription } from './sdk-hook-subscription.generated';
|
|
15
|
+
import type { AdminHookPoint, AdminHookHandler } from './hook-event-map.generated';
|
|
16
|
+
import { AdminNamespace } from './admin.generated';
|
|
17
|
+
import type * as Admin from './admin.generated';
|
|
18
|
+
import { ShopNamespace } from './shop.generated';
|
|
19
|
+
import type * as Shop from './shop.generated';
|
|
20
|
+
|
|
21
|
+
export interface ForgeCartAdminClientConfig {
|
|
22
|
+
endpoint: string;
|
|
23
|
+
channelToken: string;
|
|
24
|
+
adminSecret?: string;
|
|
25
|
+
uploadEndpoint?: string;
|
|
26
|
+
headers?: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ForgeCartShopClientConfig {
|
|
30
|
+
endpoint: string;
|
|
31
|
+
channelToken: string;
|
|
32
|
+
uploadEndpoint?: string;
|
|
33
|
+
headers?: Record<string, string>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ForgeCartClientConfig {
|
|
37
|
+
endpoint: string;
|
|
38
|
+
channelToken: string;
|
|
39
|
+
adminSecret?: string;
|
|
40
|
+
uploadEndpoint?: string;
|
|
41
|
+
headers?: Record<string, string>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class SDKLogger {
|
|
45
|
+
private readonly prefix = "[ForgeCartSDK]";
|
|
46
|
+
|
|
47
|
+
info(message: string, data?: Record<string, unknown>): void {
|
|
48
|
+
console.log(this.prefix, message, data ?? "");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
warn(message: string, data?: Record<string, unknown>): void {
|
|
52
|
+
console.warn(this.prefix, message, data ?? "");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
error(message: string, data?: Record<string, unknown>): void {
|
|
56
|
+
console.error(this.prefix, message, data ?? "");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface GraphQLErrorResponse {
|
|
61
|
+
errors: Array<{ message: string; extensions?: Record<string, unknown> }>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export class ClientError extends Error {
|
|
65
|
+
readonly response: GraphQLErrorResponse;
|
|
66
|
+
|
|
67
|
+
constructor(response: GraphQLErrorResponse, message: string) {
|
|
68
|
+
super(message);
|
|
69
|
+
this.response = response;
|
|
70
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type ErrorHandler = (error: ClientError) => void;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* An Observable that is also PromiseLike, so `await` resolves the first emitted value.
|
|
78
|
+
* Use `.subscribe()` for streaming, `await` for single-shot request-response.
|
|
79
|
+
*/
|
|
80
|
+
export class QueryObservable<T> extends Observable<T> implements PromiseLike<T> {
|
|
81
|
+
then<TResult1 = T, TResult2 = never>(
|
|
82
|
+
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
|
|
83
|
+
onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,
|
|
84
|
+
): PromiseLike<TResult1 | TResult2> {
|
|
85
|
+
return firstValueFrom(this).then(onfulfilled, onrejected);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface LoginSessionChannel {
|
|
90
|
+
id: string;
|
|
91
|
+
token: string;
|
|
92
|
+
code: string;
|
|
93
|
+
permissions: string[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface LoginSession {
|
|
97
|
+
id: string;
|
|
98
|
+
token: string;
|
|
99
|
+
channels: LoginSessionChannel[];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface AdminLoginAdministrator {
|
|
103
|
+
id: string;
|
|
104
|
+
firstName: string;
|
|
105
|
+
lastName: string;
|
|
106
|
+
emailAddress: string;
|
|
107
|
+
avatarUrl: string | null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface AdminExternalAuthResult {
|
|
111
|
+
session: LoginSession;
|
|
112
|
+
administrator: AdminLoginAdministrator;
|
|
113
|
+
requiresOnboarding: boolean;
|
|
114
|
+
}
|
|
115
|
+
export class BaseGraphQLClient {
|
|
116
|
+
private readonly logger = new SDKLogger();
|
|
117
|
+
private readonly endpoint: string;
|
|
118
|
+
private wsClient: WsClient | null = null;
|
|
119
|
+
private ownsWsClient = true;
|
|
120
|
+
private wsClientStale = false;
|
|
121
|
+
private authToken: string | null = null;
|
|
122
|
+
private transactionToken: string | null = null;
|
|
123
|
+
private errorHandler: ErrorHandler | null = null;
|
|
124
|
+
|
|
125
|
+
constructor(
|
|
126
|
+
endpoint: string,
|
|
127
|
+
private readonly baseHeaders: Record<string, string>,
|
|
128
|
+
private readonly uploadEndpoint?: string,
|
|
129
|
+
) {
|
|
130
|
+
this.endpoint = endpoint.replace(/^http:/, "ws:").replace(/^https:/, "wss:");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private getWsClient(): WsClient {
|
|
134
|
+
if (this.wsClient && this.wsClientStale) {
|
|
135
|
+
this.disposeWsClient();
|
|
136
|
+
this.wsClientStale = false;
|
|
137
|
+
}
|
|
138
|
+
if (!this.wsClient) {
|
|
139
|
+
this.wsClient = createWsClient({
|
|
140
|
+
url: this.endpoint,
|
|
141
|
+
webSocketImpl: typeof WebSocket !== 'undefined'
|
|
142
|
+
? WebSocket
|
|
143
|
+
: require('ws'),
|
|
144
|
+
connectionParams: () => ({
|
|
145
|
+
headers: this.getHeaders(),
|
|
146
|
+
}),
|
|
147
|
+
lazyCloseTimeout: 15_000,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return this.wsClient;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private getHeaders(): Record<string, string> {
|
|
154
|
+
const headers: Record<string, string> = { ...this.baseHeaders };
|
|
155
|
+
if (this.authToken) {
|
|
156
|
+
headers["Authorization"] = `Bearer ${this.authToken}`;
|
|
157
|
+
}
|
|
158
|
+
if (this.transactionToken) {
|
|
159
|
+
headers["forgecart-transaction-token"] = this.transactionToken;
|
|
160
|
+
}
|
|
161
|
+
return headers;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
setAuthToken(token: string): void {
|
|
165
|
+
if (this.authToken === token) return;
|
|
166
|
+
this.authToken = token;
|
|
167
|
+
this.disposeWsClient();
|
|
168
|
+
this.logger.info("Auth token set");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
clearAuthToken(): void {
|
|
172
|
+
this.authToken = null;
|
|
173
|
+
this.disposeWsClient();
|
|
174
|
+
this.logger.info("Auth token cleared");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
setTransactionToken(token: string): void {
|
|
178
|
+
this.transactionToken = token;
|
|
179
|
+
this.logger.info("Transaction token set");
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
clearTransactionToken(): void {
|
|
183
|
+
this.transactionToken = null;
|
|
184
|
+
this.logger.info("Transaction token cleared");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
setErrorHandler(handler: ErrorHandler): void {
|
|
188
|
+
this.errorHandler = handler;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private notifyErrorHandler(error: ClientError): void {
|
|
192
|
+
if (this.errorHandler) {
|
|
193
|
+
this.errorHandler(error);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
query<T>(document: string, variables?: Record<string, unknown>): QueryObservable<T> {
|
|
198
|
+
return new QueryObservable<T>((subscriber) => {
|
|
199
|
+
const client = this.getWsClient();
|
|
200
|
+
let disposed = false;
|
|
201
|
+
|
|
202
|
+
const cleanup = client.subscribe<Record<string, unknown>>(
|
|
203
|
+
{
|
|
204
|
+
query: document,
|
|
205
|
+
variables,
|
|
206
|
+
extensions: this.getPerOperationExtensions(),
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
next: (result) => {
|
|
210
|
+
if (disposed) return;
|
|
211
|
+
if (result.errors && result.errors.length > 0) {
|
|
212
|
+
const response: GraphQLErrorResponse = {
|
|
213
|
+
errors: result.errors.map((e) => ({
|
|
214
|
+
message: e.message,
|
|
215
|
+
extensions: e.extensions as Record<string, unknown> | undefined,
|
|
216
|
+
})),
|
|
217
|
+
};
|
|
218
|
+
const error = new ClientError(response, result.errors[0].message);
|
|
219
|
+
this.notifyErrorHandler(error);
|
|
220
|
+
subscriber.error(error);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (result.data) {
|
|
224
|
+
this.captureSessionToken(result as { extensions?: Record<string, unknown> });
|
|
225
|
+
subscriber.next(result.data as T);
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
error: (err) => {
|
|
229
|
+
if (disposed) return;
|
|
230
|
+
subscriber.error(err);
|
|
231
|
+
},
|
|
232
|
+
complete: () => {
|
|
233
|
+
if (disposed) return;
|
|
234
|
+
subscriber.complete();
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
return () => {
|
|
240
|
+
disposed = true;
|
|
241
|
+
cleanup();
|
|
242
|
+
};
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
mutate<T>(document: string, variables?: Record<string, unknown>): QueryObservable<T> {
|
|
247
|
+
if (variables && this.containsFiles(variables)) {
|
|
248
|
+
return this.upload<T>(document, variables);
|
|
249
|
+
}
|
|
250
|
+
return this.query<T>(document, variables);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
subscribe<T>(document: string, variables?: Record<string, unknown>): Observable<T> {
|
|
254
|
+
return this.query<T>(document, variables);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
upload<T>(document: string, variables: Record<string, unknown>): QueryObservable<T> {
|
|
258
|
+
return new QueryObservable<T>((subscriber) => {
|
|
259
|
+
const endpoint = this.resolveUploadEndpoint();
|
|
260
|
+
uploadViaFetch<T>(endpoint, document, variables, this.getHeaders())
|
|
261
|
+
.then((result) => {
|
|
262
|
+
this.captureSessionTokenFromUpload(result);
|
|
263
|
+
subscriber.next(result.data);
|
|
264
|
+
subscriber.complete();
|
|
265
|
+
})
|
|
266
|
+
.catch((err) => subscriber.error(err));
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private getPerOperationExtensions(): Record<string, unknown> | undefined {
|
|
271
|
+
if (!this.transactionToken) return undefined;
|
|
272
|
+
return { "forgecart-transaction-token": this.transactionToken };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
private captureSessionToken(result: { extensions?: Record<string, unknown> }): void {
|
|
276
|
+
if (!result.extensions) return;
|
|
277
|
+
const token = result.extensions["forgecart-auth-token"] as string | undefined;
|
|
278
|
+
if (token && !this.authToken) {
|
|
279
|
+
this.authToken = token;
|
|
280
|
+
this.wsClientStale = true;
|
|
281
|
+
this.logger.info("Session token captured from extensions");
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
private captureSessionTokenFromUpload(result: { extensions?: Record<string, unknown> }): void {
|
|
286
|
+
if (!result.extensions) return;
|
|
287
|
+
const token = result.extensions["forgecart-auth-token"] as string | undefined;
|
|
288
|
+
if (token && !this.authToken) {
|
|
289
|
+
this.authToken = token;
|
|
290
|
+
this.wsClientStale = true;
|
|
291
|
+
this.logger.info("Session token captured from upload response");
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
private containsFiles(obj: unknown): boolean {
|
|
296
|
+
if (obj === null || obj === undefined) return false;
|
|
297
|
+
if (typeof obj !== "object") return false;
|
|
298
|
+
if (typeof File !== "undefined" && obj instanceof File) return true;
|
|
299
|
+
if (typeof Blob !== "undefined" && obj instanceof Blob) return true;
|
|
300
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(obj)) return true;
|
|
301
|
+
if (Array.isArray(obj)) return obj.some((item) => this.containsFiles(item));
|
|
302
|
+
return Object.values(obj as Record<string, unknown>).some((val) => this.containsFiles(val));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
private resolveUploadEndpoint(): string {
|
|
306
|
+
if (this.uploadEndpoint) return this.uploadEndpoint;
|
|
307
|
+
return this.endpoint.replace(/^ws:/, "http:").replace(/^wss:/, "https:");
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
private disposeWsClient(): void {
|
|
311
|
+
if (this.wsClient && this.ownsWsClient) {
|
|
312
|
+
this.wsClient.dispose();
|
|
313
|
+
this.wsClient = null;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
dispose(): void {
|
|
318
|
+
this.disposeWsClient();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
fork(transactionToken: string): BaseGraphQLClient {
|
|
322
|
+
const forked = new BaseGraphQLClient(this.endpoint, this.baseHeaders, this.uploadEndpoint);
|
|
323
|
+
forked.authToken = this.authToken;
|
|
324
|
+
forked.transactionToken = transactionToken;
|
|
325
|
+
forked.wsClient = this.wsClient;
|
|
326
|
+
forked.ownsWsClient = false;
|
|
327
|
+
return forked;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export function setAuthToken(client: BaseGraphQLClient, token: string): void {
|
|
332
|
+
client.setAuthToken(token);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export function clearAuthToken(client: BaseGraphQLClient): void {
|
|
336
|
+
client.clearAuthToken();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export function setTransactionToken(client: BaseGraphQLClient, token: string): void {
|
|
340
|
+
client.setTransactionToken(token);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export function clearTransactionToken(client: BaseGraphQLClient): void {
|
|
344
|
+
client.clearTransactionToken();
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export class TransactionContext {
|
|
348
|
+
private readonly _admin: AdminNamespace;
|
|
349
|
+
private readonly _shop: ShopNamespace | undefined;
|
|
350
|
+
|
|
351
|
+
constructor(admin: AdminNamespace, shop?: ShopNamespace) {
|
|
352
|
+
this._admin = admin;
|
|
353
|
+
this._shop = shop;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
get admin(): AdminNamespace {
|
|
357
|
+
return this._admin;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
get shop(): ShopNamespace {
|
|
361
|
+
if (!this._shop) {
|
|
362
|
+
throw new Error('SHOP_NAMESPACE_NOT_AVAILABLE');
|
|
363
|
+
}
|
|
364
|
+
return this._shop;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export class ForgeCartAdminClient {
|
|
369
|
+
private readonly client: BaseGraphQLClient;
|
|
370
|
+
private readonly _namespace: AdminNamespace;
|
|
371
|
+
|
|
372
|
+
constructor(config: ForgeCartAdminClientConfig) {
|
|
373
|
+
const headers: Record<string, string> = { 'forgecart-token': config.channelToken, ...config.headers };
|
|
374
|
+
if (config.adminSecret) {
|
|
375
|
+
headers['forgecart-secret'] = config.adminSecret;
|
|
376
|
+
}
|
|
377
|
+
this.client = new BaseGraphQLClient(config.endpoint, headers, config.uploadEndpoint);
|
|
378
|
+
this._namespace = new AdminNamespace(this.client);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
setAuthToken(token: string): void {
|
|
382
|
+
this.client.setAuthToken(token);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
clearAuthToken(): void {
|
|
386
|
+
this.client.clearAuthToken();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
setTransactionToken(token: string): void {
|
|
390
|
+
this.client.setTransactionToken(token);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
clearTransactionToken(): void {
|
|
394
|
+
this.client.clearTransactionToken();
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
setErrorHandler(handler: ErrorHandler): void {
|
|
398
|
+
this.client.setErrorHandler(handler);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
dispose(): void {
|
|
402
|
+
this.client.dispose();
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
query<T>(document: string, variables?: Record<string, unknown>): QueryObservable<T> {
|
|
406
|
+
return this.client.query<T>(document, variables);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
mutate<T>(document: string, variables?: Record<string, unknown>): QueryObservable<T> {
|
|
410
|
+
return this.client.mutate<T>(document, variables);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
private shopPeer: ForgeCartShopClient | null = null;
|
|
414
|
+
|
|
415
|
+
setShopPeer(shop: ForgeCartShopClient): void {
|
|
416
|
+
this.shopPeer = shop;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
createScopedNamespace(transactionToken: string): AdminNamespace {
|
|
420
|
+
return new AdminNamespace(this.client.fork(transactionToken));
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async withTransaction<T>(fn: (ctx: TransactionContext) => Promise<T>): Promise<T> {
|
|
424
|
+
const result = await firstValueFrom(this.transaction.beginTransaction()) as { beginTransaction: { token: string } };
|
|
425
|
+
const token = result.beginTransaction.token;
|
|
426
|
+
const adminNs = this.createScopedNamespace(token);
|
|
427
|
+
const shopNs = this.shopPeer?.createScopedNamespace(token);
|
|
428
|
+
const ctx = new TransactionContext(adminNs, shopNs);
|
|
429
|
+
try {
|
|
430
|
+
const value = await fn(ctx);
|
|
431
|
+
await firstValueFrom(this.transaction.commitTransaction({ token }));
|
|
432
|
+
return value;
|
|
433
|
+
} catch (error) {
|
|
434
|
+
await firstValueFrom(this.transaction.rollbackTransaction({ token })).catch(() => {});
|
|
435
|
+
throw error;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
private hookManager: HookSubscriptionManager<TransactionContext> | null = null;
|
|
440
|
+
|
|
441
|
+
on<K extends AdminHookPoint>(
|
|
442
|
+
hookPoints: K[],
|
|
443
|
+
handler: AdminHookHandler<K>,
|
|
444
|
+
): HookSubscription {
|
|
445
|
+
if (!this.hookManager) {
|
|
446
|
+
this.hookManager = new HookSubscriptionManager<TransactionContext>(
|
|
447
|
+
(hp) => this.client.subscribe<{ hookDispatched: HookDispatchEvent }>(hookDispatchDocument, { hookPoints: hp }),
|
|
448
|
+
(id, subscriberId, error) => this.client.mutate(hookRespondDocument, { input: { id, subscriberId, error } }),
|
|
449
|
+
(token) => {
|
|
450
|
+
const adminNs = this.createScopedNamespace(token);
|
|
451
|
+
const shopNs = this.shopPeer?.createScopedNamespace(token);
|
|
452
|
+
return new TransactionContext(adminNs, shopNs);
|
|
453
|
+
},
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
return this.hookManager.on(
|
|
457
|
+
hookPoints as string[],
|
|
458
|
+
handler as unknown as (ctx: TransactionContext, payload?: unknown) => Promise<void>,
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
async login(emailAddress: string, password: string): Promise<LoginSession> {
|
|
463
|
+
const result = await firstValueFrom(this.auth.login({ input: { emailAddress, password } })) as {
|
|
464
|
+
login: LoginSession;
|
|
465
|
+
};
|
|
466
|
+
this.client.setAuthToken(result.login.token);
|
|
467
|
+
if (this.shopPeer) {
|
|
468
|
+
this.shopPeer.setAuthToken(result.login.token);
|
|
469
|
+
}
|
|
470
|
+
return result.login;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
async loginWithExternalStrategy(strategyCode: string, data: Record<string, unknown>): Promise<AdminExternalAuthResult> {
|
|
474
|
+
const result = await firstValueFrom(this.auth.authenticateWithExternalStrategy({ input: { strategyCode, data } })) as {
|
|
475
|
+
authenticateWithExternalStrategy: AdminExternalAuthResult;
|
|
476
|
+
};
|
|
477
|
+
this.client.setAuthToken(result.authenticateWithExternalStrategy.session.token);
|
|
478
|
+
if (this.shopPeer) {
|
|
479
|
+
this.shopPeer.setAuthToken(result.authenticateWithExternalStrategy.session.token);
|
|
480
|
+
}
|
|
481
|
+
return result.authenticateWithExternalStrategy;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
async logout(): Promise<void> {
|
|
485
|
+
await firstValueFrom(this.auth.logout());
|
|
486
|
+
this.client.clearAuthToken();
|
|
487
|
+
if (this.shopPeer) {
|
|
488
|
+
this.shopPeer.clearAuthToken();
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
get entry(): Admin.EntryCategory {
|
|
492
|
+
return this._namespace.entry;
|
|
493
|
+
}
|
|
494
|
+
get fieldDefinition(): Admin.FieldDefinitionCategory {
|
|
495
|
+
return this._namespace.fieldDefinition;
|
|
496
|
+
}
|
|
497
|
+
get publish(): Admin.PublishCategory {
|
|
498
|
+
return this._namespace.publish;
|
|
499
|
+
}
|
|
500
|
+
get acfSchema(): Admin.AcfSchemaCategory {
|
|
501
|
+
return this._namespace.acfSchema;
|
|
502
|
+
}
|
|
503
|
+
get acf(): Admin.AcfCategory {
|
|
504
|
+
return this._namespace.acf;
|
|
505
|
+
}
|
|
506
|
+
get administrator(): Admin.AdministratorCategory {
|
|
507
|
+
return this._namespace.administrator;
|
|
508
|
+
}
|
|
509
|
+
get analyticsGateway(): Admin.AnalyticsGatewayCategory {
|
|
510
|
+
return this._namespace.analyticsGateway;
|
|
511
|
+
}
|
|
512
|
+
get asset(): Admin.AssetCategory {
|
|
513
|
+
return this._namespace.asset;
|
|
514
|
+
}
|
|
515
|
+
get audienceMembership(): Admin.AudienceMembershipCategory {
|
|
516
|
+
return this._namespace.audienceMembership;
|
|
517
|
+
}
|
|
518
|
+
get audienceSegment(): Admin.AudienceSegmentCategory {
|
|
519
|
+
return this._namespace.audienceSegment;
|
|
520
|
+
}
|
|
521
|
+
get auth(): Admin.AuthCategory {
|
|
522
|
+
return this._namespace.auth;
|
|
523
|
+
}
|
|
524
|
+
get settings(): Admin.SettingsCategory {
|
|
525
|
+
return this._namespace.settings;
|
|
526
|
+
}
|
|
527
|
+
get channel(): Admin.ChannelCategory {
|
|
528
|
+
return this._namespace.channel;
|
|
529
|
+
}
|
|
530
|
+
get collection(): Admin.CollectionCategory {
|
|
531
|
+
return this._namespace.collection;
|
|
532
|
+
}
|
|
533
|
+
get country(): Admin.CountryCategory {
|
|
534
|
+
return this._namespace.country;
|
|
535
|
+
}
|
|
536
|
+
get address(): Admin.AddressCategory {
|
|
537
|
+
return this._namespace.address;
|
|
538
|
+
}
|
|
539
|
+
get group(): Admin.GroupCategory {
|
|
540
|
+
return this._namespace.group;
|
|
541
|
+
}
|
|
542
|
+
get customerGroup(): Admin.CustomerGroupCategory {
|
|
543
|
+
return this._namespace.customerGroup;
|
|
544
|
+
}
|
|
545
|
+
get customer(): Admin.CustomerCategory {
|
|
546
|
+
return this._namespace.customer;
|
|
547
|
+
}
|
|
548
|
+
get deployment(): Admin.DeploymentCategory {
|
|
549
|
+
return this._namespace.deployment;
|
|
550
|
+
}
|
|
551
|
+
get facet(): Admin.FacetCategory {
|
|
552
|
+
return this._namespace.facet;
|
|
553
|
+
}
|
|
554
|
+
get fulfillmentRequest(): Admin.FulfillmentRequestCategory {
|
|
555
|
+
return this._namespace.fulfillmentRequest;
|
|
556
|
+
}
|
|
557
|
+
get fulfillment(): Admin.FulfillmentCategory {
|
|
558
|
+
return this._namespace.fulfillment;
|
|
559
|
+
}
|
|
560
|
+
get hookDispatch(): Admin.HookDispatchCategory {
|
|
561
|
+
return this._namespace.hookDispatch;
|
|
562
|
+
}
|
|
563
|
+
get hook(): Admin.HookCategory {
|
|
564
|
+
return this._namespace.hook;
|
|
565
|
+
}
|
|
566
|
+
get marketingAttribution(): Admin.MarketingAttributionCategory {
|
|
567
|
+
return this._namespace.marketingAttribution;
|
|
568
|
+
}
|
|
569
|
+
get marketingEvent(): Admin.MarketingEventCategory {
|
|
570
|
+
return this._namespace.marketingEvent;
|
|
571
|
+
}
|
|
572
|
+
get marketingIdentity(): Admin.MarketingIdentityCategory {
|
|
573
|
+
return this._namespace.marketingIdentity;
|
|
574
|
+
}
|
|
575
|
+
get onboarding(): Admin.OnboardingCategory {
|
|
576
|
+
return this._namespace.onboarding;
|
|
577
|
+
}
|
|
578
|
+
get coupon(): Admin.CouponCategory {
|
|
579
|
+
return this._namespace.coupon;
|
|
580
|
+
}
|
|
581
|
+
get draft(): Admin.DraftCategory {
|
|
582
|
+
return this._namespace.draft;
|
|
583
|
+
}
|
|
584
|
+
get modification(): Admin.ModificationCategory {
|
|
585
|
+
return this._namespace.modification;
|
|
586
|
+
}
|
|
587
|
+
get note(): Admin.NoteCategory {
|
|
588
|
+
return this._namespace.note;
|
|
589
|
+
}
|
|
590
|
+
get orderModification(): Admin.OrderModificationCategory {
|
|
591
|
+
return this._namespace.orderModification;
|
|
592
|
+
}
|
|
593
|
+
get order(): Admin.OrderCategory {
|
|
594
|
+
return this._namespace.order;
|
|
595
|
+
}
|
|
596
|
+
get payment(): Admin.PaymentCategory {
|
|
597
|
+
return this._namespace.payment;
|
|
598
|
+
}
|
|
599
|
+
get manageable(): Admin.ManageableCategory {
|
|
600
|
+
return this._namespace.manageable;
|
|
601
|
+
}
|
|
602
|
+
get plugin(): Admin.PluginCategory {
|
|
603
|
+
return this._namespace.plugin;
|
|
604
|
+
}
|
|
605
|
+
get optionGroup(): Admin.OptionGroupCategory {
|
|
606
|
+
return this._namespace.optionGroup;
|
|
607
|
+
}
|
|
608
|
+
get option(): Admin.OptionCategory {
|
|
609
|
+
return this._namespace.option;
|
|
610
|
+
}
|
|
611
|
+
get productOption(): Admin.ProductOptionCategory {
|
|
612
|
+
return this._namespace.productOption;
|
|
613
|
+
}
|
|
614
|
+
get productVariant(): Admin.ProductVariantCategory {
|
|
615
|
+
return this._namespace.productVariant;
|
|
616
|
+
}
|
|
617
|
+
get product(): Admin.ProductCategory {
|
|
618
|
+
return this._namespace.product;
|
|
619
|
+
}
|
|
620
|
+
get promotion(): Admin.PromotionCategory {
|
|
621
|
+
return this._namespace.promotion;
|
|
622
|
+
}
|
|
623
|
+
get role(): Admin.RoleCategory {
|
|
624
|
+
return this._namespace.role;
|
|
625
|
+
}
|
|
626
|
+
get scheduledJob(): Admin.ScheduledJobCategory {
|
|
627
|
+
return this._namespace.scheduledJob;
|
|
628
|
+
}
|
|
629
|
+
get search(): Admin.SearchCategory {
|
|
630
|
+
return this._namespace.search;
|
|
631
|
+
}
|
|
632
|
+
get seller(): Admin.SellerCategory {
|
|
633
|
+
return this._namespace.seller;
|
|
634
|
+
}
|
|
635
|
+
get shipping(): Admin.ShippingCategory {
|
|
636
|
+
return this._namespace.shipping;
|
|
637
|
+
}
|
|
638
|
+
get stock(): Admin.StockCategory {
|
|
639
|
+
return this._namespace.stock;
|
|
640
|
+
}
|
|
641
|
+
get subscription(): Admin.SubscriptionCategory {
|
|
642
|
+
return this._namespace.subscription;
|
|
643
|
+
}
|
|
644
|
+
get tax(): Admin.TaxCategory {
|
|
645
|
+
return this._namespace.tax;
|
|
646
|
+
}
|
|
647
|
+
get transaction(): Admin.TransactionCategory {
|
|
648
|
+
return this._namespace.transaction;
|
|
649
|
+
}
|
|
650
|
+
get zone(): Admin.ZoneCategory {
|
|
651
|
+
return this._namespace.zone;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
export class ForgeCartShopClient {
|
|
656
|
+
private readonly client: BaseGraphQLClient;
|
|
657
|
+
private readonly _namespace: ShopNamespace;
|
|
658
|
+
|
|
659
|
+
constructor(config: ForgeCartShopClientConfig) {
|
|
660
|
+
const headers: Record<string, string> = { 'forgecart-token': config.channelToken, ...config.headers };
|
|
661
|
+
this.client = new BaseGraphQLClient(config.endpoint, headers, config.uploadEndpoint);
|
|
662
|
+
this._namespace = new ShopNamespace(this.client);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
setAuthToken(token: string): void {
|
|
666
|
+
this.client.setAuthToken(token);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
clearAuthToken(): void {
|
|
670
|
+
this.client.clearAuthToken();
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
setTransactionToken(token: string): void {
|
|
674
|
+
this.client.setTransactionToken(token);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
clearTransactionToken(): void {
|
|
678
|
+
this.client.clearTransactionToken();
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
setErrorHandler(handler: ErrorHandler): void {
|
|
682
|
+
this.client.setErrorHandler(handler);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
dispose(): void {
|
|
686
|
+
this.client.dispose();
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
query<T>(document: string, variables?: Record<string, unknown>): QueryObservable<T> {
|
|
690
|
+
return this.client.query<T>(document, variables);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
mutate<T>(document: string, variables?: Record<string, unknown>): QueryObservable<T> {
|
|
694
|
+
return this.client.mutate<T>(document, variables);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
createScopedNamespace(transactionToken: string): ShopNamespace {
|
|
698
|
+
return new ShopNamespace(this.client.fork(transactionToken));
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
async login(emailAddress: string, password: string): Promise<LoginSession> {
|
|
702
|
+
const result = await firstValueFrom(this.auth.login({ input: { emailAddress, password } })) as {
|
|
703
|
+
login: LoginSession;
|
|
704
|
+
};
|
|
705
|
+
this.client.setAuthToken(result.login.token);
|
|
706
|
+
return result.login;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
async loginWithExternalStrategy(strategyCode: string, data: Record<string, unknown>): Promise<LoginSession> {
|
|
710
|
+
const result = await firstValueFrom(this.auth.authenticateWithExternalStrategy({ input: { strategyCode, data } })) as {
|
|
711
|
+
authenticateWithExternalStrategy: LoginSession;
|
|
712
|
+
};
|
|
713
|
+
this.client.setAuthToken(result.authenticateWithExternalStrategy.token);
|
|
714
|
+
return result.authenticateWithExternalStrategy;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
async logout(): Promise<void> {
|
|
718
|
+
await firstValueFrom(this.auth.logout());
|
|
719
|
+
this.client.clearAuthToken();
|
|
720
|
+
}
|
|
721
|
+
get acf(): Shop.AcfCategory {
|
|
722
|
+
return this._namespace.acf;
|
|
723
|
+
}
|
|
724
|
+
get auth(): Shop.AuthCategory {
|
|
725
|
+
return this._namespace.auth;
|
|
726
|
+
}
|
|
727
|
+
get cart(): Shop.CartCategory {
|
|
728
|
+
return this._namespace.cart;
|
|
729
|
+
}
|
|
730
|
+
get checkout(): Shop.CheckoutCategory {
|
|
731
|
+
return this._namespace.checkout;
|
|
732
|
+
}
|
|
733
|
+
get collection(): Shop.CollectionCategory {
|
|
734
|
+
return this._namespace.collection;
|
|
735
|
+
}
|
|
736
|
+
get customer(): Shop.CustomerCategory {
|
|
737
|
+
return this._namespace.customer;
|
|
738
|
+
}
|
|
739
|
+
get facet(): Shop.FacetCategory {
|
|
740
|
+
return this._namespace.facet;
|
|
741
|
+
}
|
|
742
|
+
get hookDispatch(): Shop.HookDispatchCategory {
|
|
743
|
+
return this._namespace.hookDispatch;
|
|
744
|
+
}
|
|
745
|
+
get hook(): Shop.HookCategory {
|
|
746
|
+
return this._namespace.hook;
|
|
747
|
+
}
|
|
748
|
+
get marketingEvent(): Shop.MarketingEventCategory {
|
|
749
|
+
return this._namespace.marketingEvent;
|
|
750
|
+
}
|
|
751
|
+
get marketingIdentity(): Shop.MarketingIdentityCategory {
|
|
752
|
+
return this._namespace.marketingIdentity;
|
|
753
|
+
}
|
|
754
|
+
get order(): Shop.OrderCategory {
|
|
755
|
+
return this._namespace.order;
|
|
756
|
+
}
|
|
757
|
+
get payment(): Shop.PaymentCategory {
|
|
758
|
+
return this._namespace.payment;
|
|
759
|
+
}
|
|
760
|
+
get product(): Shop.ProductCategory {
|
|
761
|
+
return this._namespace.product;
|
|
762
|
+
}
|
|
763
|
+
get search(): Shop.SearchCategory {
|
|
764
|
+
return this._namespace.search;
|
|
765
|
+
}
|
|
766
|
+
get shipping(): Shop.ShippingCategory {
|
|
767
|
+
return this._namespace.shipping;
|
|
768
|
+
}
|
|
769
|
+
get subscription(): Shop.SubscriptionCategory {
|
|
770
|
+
return this._namespace.subscription;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
export class ForgeCartClient {
|
|
775
|
+
private readonly _admin: ForgeCartAdminClient;
|
|
776
|
+
private readonly _shop: ForgeCartShopClient;
|
|
777
|
+
|
|
778
|
+
constructor(config: ForgeCartClientConfig) {
|
|
779
|
+
this._admin = new ForgeCartAdminClient({ endpoint: config.endpoint + '/admin-api', channelToken: config.channelToken, adminSecret: config.adminSecret, uploadEndpoint: config.uploadEndpoint ? config.uploadEndpoint + '/admin-api' : undefined, headers: config.headers });
|
|
780
|
+
this._shop = new ForgeCartShopClient({ endpoint: config.endpoint + '/shop-api', channelToken: config.channelToken, uploadEndpoint: config.uploadEndpoint ? config.uploadEndpoint + '/shop-api' : undefined, headers: config.headers });
|
|
781
|
+
this._admin.setShopPeer(this._shop);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
setAuthToken(token: string): void {
|
|
785
|
+
this._admin.setAuthToken(token);
|
|
786
|
+
this._shop.setAuthToken(token);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
clearAuthToken(): void {
|
|
790
|
+
this._admin.clearAuthToken();
|
|
791
|
+
this._shop.clearAuthToken();
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
setTransactionToken(token: string): void {
|
|
795
|
+
this._admin.setTransactionToken(token);
|
|
796
|
+
this._shop.setTransactionToken(token);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
clearTransactionToken(): void {
|
|
800
|
+
this._admin.clearTransactionToken();
|
|
801
|
+
this._shop.clearTransactionToken();
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
get admin(): ForgeCartAdminClient {
|
|
805
|
+
return this._admin;
|
|
806
|
+
}
|
|
807
|
+
get shop(): ForgeCartShopClient {
|
|
808
|
+
return this._shop;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
import { Module, type DynamicModule } from '@nestjs/common';
|
|
813
|
+
|
|
814
|
+
@Module({})
|
|
815
|
+
export class ForgeCartGraphQLModule {
|
|
816
|
+
static forAdmin(config: ForgeCartAdminClientConfig): DynamicModule {
|
|
817
|
+
const client = new ForgeCartAdminClient(config);
|
|
818
|
+
return {
|
|
819
|
+
module: ForgeCartGraphQLModule,
|
|
820
|
+
providers: [{ provide: ForgeCartAdminClient, useValue: client }],
|
|
821
|
+
exports: [ForgeCartAdminClient],
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
static forShop(config: ForgeCartShopClientConfig): DynamicModule {
|
|
825
|
+
const client = new ForgeCartShopClient(config);
|
|
826
|
+
return {
|
|
827
|
+
module: ForgeCartGraphQLModule,
|
|
828
|
+
providers: [{ provide: ForgeCartShopClient, useValue: client }],
|
|
829
|
+
exports: [ForgeCartShopClient],
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
static forRoot(config: ForgeCartClientConfig): DynamicModule {
|
|
834
|
+
const client = new ForgeCartClient(config);
|
|
835
|
+
return {
|
|
836
|
+
module: ForgeCartGraphQLModule,
|
|
837
|
+
providers: [
|
|
838
|
+
{ provide: ForgeCartClient, useValue: client },
|
|
839
|
+
{ provide: ForgeCartAdminClient, useValue: client.admin },
|
|
840
|
+
{ provide: ForgeCartShopClient, useValue: client.shop },
|
|
841
|
+
],
|
|
842
|
+
exports: [ForgeCartClient, ForgeCartAdminClient, ForgeCartShopClient],
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
}
|