@diffsome/sdk 3.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/dist/index.js ADDED
@@ -0,0 +1,1493 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Diffsome: () => Diffsome,
24
+ DiffsomeError: () => DiffsomeError,
25
+ Promptly: () => Diffsome,
26
+ PromptlyError: () => DiffsomeError,
27
+ default: () => index_default
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/http.ts
32
+ var DEFAULT_META = {
33
+ current_page: 1,
34
+ last_page: 1,
35
+ per_page: 15,
36
+ total: 0,
37
+ from: null,
38
+ to: null
39
+ };
40
+ function normalizeListResponse(response) {
41
+ if (response == null) {
42
+ return { data: [], meta: { ...DEFAULT_META } };
43
+ }
44
+ if (Array.isArray(response)) {
45
+ return {
46
+ data: response,
47
+ meta: { ...DEFAULT_META, total: response.length, from: response.length > 0 ? 1 : null, to: response.length > 0 ? response.length : null }
48
+ };
49
+ }
50
+ if (typeof response === "object") {
51
+ const data = Array.isArray(response.data) ? response.data : [];
52
+ const meta = {
53
+ current_page: response.meta?.current_page ?? response.current_page ?? 1,
54
+ last_page: response.meta?.last_page ?? response.last_page ?? 1,
55
+ per_page: response.meta?.per_page ?? response.per_page ?? 15,
56
+ total: response.meta?.total ?? response.total ?? data.length,
57
+ from: response.meta?.from ?? response.from ?? (data.length > 0 ? 1 : null),
58
+ to: response.meta?.to ?? response.to ?? (data.length > 0 ? data.length : null)
59
+ };
60
+ return { data, meta };
61
+ }
62
+ return { data: [], meta: { ...DEFAULT_META } };
63
+ }
64
+ var DiffsomeError = class extends Error {
65
+ constructor(message, status, errors) {
66
+ super(message);
67
+ this.name = "DiffsomeError";
68
+ this.status = status;
69
+ this.errors = errors;
70
+ }
71
+ };
72
+ var HttpClient = class {
73
+ constructor(config) {
74
+ this.token = null;
75
+ this.apiKey = null;
76
+ this.cartSessionId = null;
77
+ // Token persistence options
78
+ this.persistToken = false;
79
+ this.storageType = "localStorage";
80
+ this.tenantId = config.tenantId;
81
+ this.baseUrl = (config.baseUrl || "https://diffsome.com").replace(/\/$/, "");
82
+ this.timeout = config.timeout || 3e4;
83
+ this.apiKey = config.apiKey || null;
84
+ this.persistToken = config.persistToken ?? false;
85
+ this.storageType = config.storageType ?? "localStorage";
86
+ this.storageKey = config.storageKey ?? `diffsome_auth_token_${this.tenantId}`;
87
+ this.onAuthStateChange = config.onAuthStateChange;
88
+ if (typeof window !== "undefined" && window.localStorage) {
89
+ this.cartSessionId = localStorage.getItem(`diffsome_cart_session_${this.tenantId}`);
90
+ }
91
+ if (this.persistToken && typeof window !== "undefined") {
92
+ const storage = this.getStorage();
93
+ if (storage) {
94
+ const savedToken = storage.getItem(this.storageKey);
95
+ if (savedToken) {
96
+ this.token = savedToken;
97
+ this.onAuthStateChange?.(savedToken, void 0);
98
+ }
99
+ }
100
+ }
101
+ if (config.token) {
102
+ this.token = config.token;
103
+ }
104
+ }
105
+ /**
106
+ * Get the storage object based on config
107
+ */
108
+ getStorage() {
109
+ if (typeof window === "undefined") return null;
110
+ return this.storageType === "sessionStorage" ? window.sessionStorage : window.localStorage;
111
+ }
112
+ /**
113
+ * Set authentication token
114
+ * If persistToken is enabled, automatically saves/removes from storage
115
+ * @param token - The auth token or null to clear
116
+ * @param user - The logged-in user (Member) for the callback
117
+ */
118
+ setToken(token, user) {
119
+ this.token = token;
120
+ if (this.persistToken) {
121
+ const storage = this.getStorage();
122
+ if (storage) {
123
+ if (token) {
124
+ storage.setItem(this.storageKey, token);
125
+ } else {
126
+ storage.removeItem(this.storageKey);
127
+ }
128
+ }
129
+ }
130
+ this.onAuthStateChange?.(token, user ?? null);
131
+ }
132
+ /**
133
+ * Get current token
134
+ */
135
+ getToken() {
136
+ return this.token;
137
+ }
138
+ /**
139
+ * Check if authenticated
140
+ */
141
+ isAuthenticated() {
142
+ return this.token !== null || this.apiKey !== null;
143
+ }
144
+ /**
145
+ * Set API key for server-to-server authentication
146
+ */
147
+ setApiKey(apiKey) {
148
+ this.apiKey = apiKey;
149
+ }
150
+ /**
151
+ * Get current API key
152
+ */
153
+ getApiKey() {
154
+ return this.apiKey;
155
+ }
156
+ /**
157
+ * Set cart session ID (for guest cart persistence)
158
+ */
159
+ setCartSessionId(sessionId) {
160
+ this.cartSessionId = sessionId;
161
+ if (typeof window !== "undefined" && window.localStorage) {
162
+ if (sessionId) {
163
+ localStorage.setItem(`diffsome_cart_session_${this.tenantId}`, sessionId);
164
+ } else {
165
+ localStorage.removeItem(`diffsome_cart_session_${this.tenantId}`);
166
+ }
167
+ }
168
+ }
169
+ /**
170
+ * Get cart session ID
171
+ */
172
+ getCartSessionId() {
173
+ return this.cartSessionId;
174
+ }
175
+ /**
176
+ * Build full URL with query params
177
+ */
178
+ buildUrl(endpoint, params) {
179
+ const url = new URL(`${this.baseUrl}/api/${this.tenantId}${endpoint}`);
180
+ if (params) {
181
+ Object.entries(params).forEach(([key, value]) => {
182
+ if (value !== void 0 && value !== null) {
183
+ url.searchParams.append(key, String(value));
184
+ }
185
+ });
186
+ }
187
+ return url.toString();
188
+ }
189
+ /**
190
+ * Build request headers
191
+ * Both API key and bearer token can be sent together
192
+ */
193
+ buildHeaders(customHeaders) {
194
+ const headers = {
195
+ "Content-Type": "application/json",
196
+ "Accept": "application/json",
197
+ ...customHeaders
198
+ };
199
+ if (this.apiKey) {
200
+ headers["X-API-Key"] = this.apiKey;
201
+ }
202
+ if (this.token) {
203
+ headers["Authorization"] = `Bearer ${this.token}`;
204
+ }
205
+ if (this.cartSessionId) {
206
+ headers["X-Cart-Session"] = this.cartSessionId;
207
+ }
208
+ return headers;
209
+ }
210
+ /**
211
+ * Make HTTP request
212
+ */
213
+ async request(endpoint, options = {}) {
214
+ const { method = "GET", body, params, headers } = options;
215
+ const url = this.buildUrl(endpoint, params);
216
+ const requestHeaders = this.buildHeaders(headers);
217
+ const controller = new AbortController();
218
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
219
+ try {
220
+ const response = await fetch(url, {
221
+ method,
222
+ headers: requestHeaders,
223
+ body: body ? JSON.stringify(body) : void 0,
224
+ signal: controller.signal
225
+ });
226
+ clearTimeout(timeoutId);
227
+ const data = await response.json();
228
+ if (!response.ok) {
229
+ throw new DiffsomeError(
230
+ data.message || "Request failed",
231
+ response.status,
232
+ data.errors
233
+ );
234
+ }
235
+ return data.data !== void 0 ? data.data : data;
236
+ } catch (error) {
237
+ clearTimeout(timeoutId);
238
+ if (error instanceof DiffsomeError) {
239
+ throw error;
240
+ }
241
+ if (error instanceof Error) {
242
+ if (error.name === "AbortError") {
243
+ throw new DiffsomeError("Request timeout", 408);
244
+ }
245
+ throw new DiffsomeError(error.message, 0);
246
+ }
247
+ throw new DiffsomeError("Unknown error", 0);
248
+ }
249
+ }
250
+ /**
251
+ * GET request
252
+ */
253
+ get(endpoint, params) {
254
+ return this.request(endpoint, { method: "GET", params });
255
+ }
256
+ /**
257
+ * GET request for list endpoints - ALWAYS returns normalized ListResponse
258
+ * Guarantees: data is always an array, meta is always present
259
+ */
260
+ async getList(endpoint, params) {
261
+ const response = await this.request(endpoint, { method: "GET", params });
262
+ return normalizeListResponse(response);
263
+ }
264
+ /**
265
+ * POST request
266
+ */
267
+ post(endpoint, body) {
268
+ return this.request(endpoint, { method: "POST", body });
269
+ }
270
+ /**
271
+ * PUT request
272
+ */
273
+ put(endpoint, body) {
274
+ return this.request(endpoint, { method: "PUT", body });
275
+ }
276
+ /**
277
+ * PATCH request
278
+ */
279
+ patch(endpoint, body) {
280
+ return this.request(endpoint, { method: "PATCH", body });
281
+ }
282
+ /**
283
+ * DELETE request
284
+ */
285
+ delete(endpoint, params) {
286
+ return this.request(endpoint, { method: "DELETE", params });
287
+ }
288
+ /**
289
+ * Upload file
290
+ */
291
+ async upload(endpoint, file, fieldName = "file") {
292
+ const url = this.buildUrl(endpoint);
293
+ const formData = new FormData();
294
+ formData.append(fieldName, file);
295
+ const headers = {
296
+ "Accept": "application/json"
297
+ };
298
+ if (this.apiKey) {
299
+ headers["X-API-Key"] = this.apiKey;
300
+ }
301
+ if (this.token) {
302
+ headers["Authorization"] = `Bearer ${this.token}`;
303
+ }
304
+ const controller = new AbortController();
305
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
306
+ try {
307
+ const response = await fetch(url, {
308
+ method: "POST",
309
+ headers,
310
+ body: formData,
311
+ signal: controller.signal
312
+ });
313
+ clearTimeout(timeoutId);
314
+ const data = await response.json();
315
+ if (!response.ok) {
316
+ throw new DiffsomeError(
317
+ data.message || "Upload failed",
318
+ response.status,
319
+ data.errors
320
+ );
321
+ }
322
+ return data.data !== void 0 ? data.data : data;
323
+ } catch (error) {
324
+ clearTimeout(timeoutId);
325
+ if (error instanceof DiffsomeError) {
326
+ throw error;
327
+ }
328
+ if (error instanceof Error) {
329
+ if (error.name === "AbortError") {
330
+ throw new DiffsomeError("Upload timeout", 408);
331
+ }
332
+ throw new DiffsomeError(error.message, 0);
333
+ }
334
+ throw new DiffsomeError("Unknown error", 0);
335
+ }
336
+ }
337
+ };
338
+
339
+ // src/resources/auth.ts
340
+ var AuthResource = class {
341
+ constructor(http) {
342
+ this.http = http;
343
+ }
344
+ /**
345
+ * Login with email and password
346
+ * Token is automatically saved if persistToken is enabled
347
+ */
348
+ async login(credentials) {
349
+ const response = await this.http.post("/auth/login", credentials);
350
+ if (response.token) {
351
+ this.http.setToken(response.token, response.user);
352
+ }
353
+ return response;
354
+ }
355
+ /**
356
+ * Register new member
357
+ * Token is automatically saved if persistToken is enabled
358
+ */
359
+ async register(data) {
360
+ const response = await this.http.post("/auth/register", data);
361
+ if (response.token) {
362
+ this.http.setToken(response.token, response.user);
363
+ }
364
+ return response;
365
+ }
366
+ /**
367
+ * Logout current user
368
+ */
369
+ async logout() {
370
+ try {
371
+ await this.http.post("/auth/logout");
372
+ } finally {
373
+ this.http.setToken(null);
374
+ }
375
+ }
376
+ /**
377
+ * Get current user profile
378
+ */
379
+ async me() {
380
+ return this.http.get("/profile");
381
+ }
382
+ /**
383
+ * Update profile
384
+ */
385
+ async updateProfile(data) {
386
+ return this.http.put("/profile", data);
387
+ }
388
+ /**
389
+ * Send password reset email
390
+ */
391
+ async forgotPassword(data) {
392
+ return this.http.post("/auth/forgot-password", data);
393
+ }
394
+ /**
395
+ * Reset password with token
396
+ */
397
+ async resetPassword(data) {
398
+ return this.http.post("/auth/reset-password", data);
399
+ }
400
+ /**
401
+ * Get available social login providers
402
+ */
403
+ async getSocialProviders() {
404
+ return this.http.get("/auth/social");
405
+ }
406
+ /**
407
+ * Get social login redirect URL
408
+ */
409
+ async getSocialAuthUrl(provider) {
410
+ return this.http.get(`/auth/social/${provider}`);
411
+ }
412
+ /**
413
+ * Handle social login callback
414
+ * Token is automatically saved if persistToken is enabled
415
+ */
416
+ async socialCallback(provider, code) {
417
+ const response = await this.http.post(`/auth/social/${provider}/callback`, { code });
418
+ if (response.token) {
419
+ this.http.setToken(response.token, response.user);
420
+ }
421
+ return response;
422
+ }
423
+ /**
424
+ * Set token manually (e.g., from localStorage)
425
+ */
426
+ setToken(token) {
427
+ this.http.setToken(token);
428
+ }
429
+ /**
430
+ * Get current token
431
+ */
432
+ getToken() {
433
+ return this.http.getToken();
434
+ }
435
+ /**
436
+ * Check if user is authenticated
437
+ */
438
+ isAuthenticated() {
439
+ return this.http.isAuthenticated();
440
+ }
441
+ };
442
+
443
+ // src/resources/boards.ts
444
+ var BoardsResource = class {
445
+ constructor(http) {
446
+ this.http = http;
447
+ }
448
+ // ============================================
449
+ // Boards (Public)
450
+ // ============================================
451
+ /**
452
+ * List all boards
453
+ * @returns ListResponse with data array (always defined) and pagination meta
454
+ */
455
+ async list(params) {
456
+ return this.http.getList("/boards", params);
457
+ }
458
+ /**
459
+ * Get board by ID or slug
460
+ */
461
+ async get(idOrSlug) {
462
+ return this.http.get(`/boards/${idOrSlug}`);
463
+ }
464
+ // ============================================
465
+ // Posts
466
+ // ============================================
467
+ /**
468
+ * List posts in a board
469
+ * @returns ListResponse with data array and pagination meta
470
+ */
471
+ async listPosts(boardIdOrSlug, params) {
472
+ return this.http.getList(`/boards/${boardIdOrSlug}/posts`, params);
473
+ }
474
+ /**
475
+ * Get post by ID
476
+ */
477
+ async getPost(postId) {
478
+ return this.http.get(`/posts/${postId}`);
479
+ }
480
+ // ============================================
481
+ // Posts (Protected - requires auth)
482
+ // ============================================
483
+ /**
484
+ * Create new post
485
+ */
486
+ async createPost(data) {
487
+ return this.http.post("/posts", data);
488
+ }
489
+ /**
490
+ * Update post
491
+ */
492
+ async updatePost(postId, data) {
493
+ return this.http.put(`/posts/${postId}`, data);
494
+ }
495
+ /**
496
+ * Delete post
497
+ */
498
+ async deletePost(postId) {
499
+ return this.http.delete(`/posts/${postId}`);
500
+ }
501
+ // ============================================
502
+ // Comments
503
+ // ============================================
504
+ /**
505
+ * List comments for a post
506
+ * @returns Array of comments (always an array, never null/undefined)
507
+ */
508
+ async listComments(postId) {
509
+ const response = await this.http.getList(`/posts/${postId}/comments`);
510
+ return response.data;
511
+ }
512
+ /**
513
+ * Create comment on a post
514
+ */
515
+ async createComment(postId, data) {
516
+ return this.http.post(`/posts/${postId}/comments`, data);
517
+ }
518
+ /**
519
+ * Update comment
520
+ */
521
+ async updateComment(commentId, data) {
522
+ return this.http.put(`/comments/${commentId}`, data);
523
+ }
524
+ /**
525
+ * Delete comment
526
+ */
527
+ async deleteComment(commentId) {
528
+ return this.http.delete(`/comments/${commentId}`);
529
+ }
530
+ };
531
+
532
+ // src/resources/blog.ts
533
+ var BlogResource = class {
534
+ constructor(http) {
535
+ this.http = http;
536
+ }
537
+ /**
538
+ * List blog posts
539
+ * @returns ListResponse with data array (always defined) and pagination meta
540
+ */
541
+ async list(params) {
542
+ return this.http.getList("/blog", params);
543
+ }
544
+ /**
545
+ * Get blog post by slug
546
+ */
547
+ async get(slug) {
548
+ return this.http.get(`/blog/${slug}`);
549
+ }
550
+ /**
551
+ * Get blog post by ID
552
+ */
553
+ async getById(id) {
554
+ return this.http.get(`/blog/id/${id}`);
555
+ }
556
+ /**
557
+ * Get featured blog posts
558
+ * @returns Array of featured posts (always an array, never null/undefined)
559
+ */
560
+ async featured(limit = 5) {
561
+ const response = await this.http.getList("/blog", {
562
+ per_page: limit,
563
+ featured: true
564
+ });
565
+ return response.data;
566
+ }
567
+ /**
568
+ * Get blog posts by category
569
+ * @returns ListResponse with data array and pagination meta
570
+ */
571
+ async byCategory(category, params) {
572
+ return this.http.getList("/blog", {
573
+ ...params,
574
+ category
575
+ });
576
+ }
577
+ /**
578
+ * Get blog posts by tag
579
+ * @returns ListResponse with data array and pagination meta
580
+ */
581
+ async byTag(tag, params) {
582
+ return this.http.getList("/blog", {
583
+ ...params,
584
+ tag
585
+ });
586
+ }
587
+ /**
588
+ * Search blog posts
589
+ * @returns ListResponse with data array and pagination meta
590
+ */
591
+ async search(query, params) {
592
+ return this.http.getList("/blog", {
593
+ ...params,
594
+ search: query
595
+ });
596
+ }
597
+ /**
598
+ * Get blog categories
599
+ * @returns Array of category names (always an array)
600
+ */
601
+ async categories() {
602
+ const response = await this.http.get("/blog/categories");
603
+ return Array.isArray(response) ? response : response?.data ?? [];
604
+ }
605
+ /**
606
+ * Get blog tags
607
+ * @returns Array of tag names (always an array)
608
+ */
609
+ async tags() {
610
+ const response = await this.http.get("/blog/tags");
611
+ return Array.isArray(response) ? response : response?.data ?? [];
612
+ }
613
+ };
614
+
615
+ // src/resources/comments.ts
616
+ var CommentsResource = class {
617
+ constructor(http) {
618
+ this.http = http;
619
+ }
620
+ /**
621
+ * Get comments for a board post
622
+ */
623
+ async boardPost(postId, params) {
624
+ return this.http.get(`/posts/${postId}/comments`, params);
625
+ }
626
+ /**
627
+ * Create a comment on a board post
628
+ */
629
+ async createBoardPost(postId, data) {
630
+ return this.http.post(`/posts/${postId}/comments`, data);
631
+ }
632
+ /**
633
+ * Get comments for a blog post
634
+ */
635
+ async blogPost(slug, params) {
636
+ return this.http.get(`/blog/${slug}/comments`, params);
637
+ }
638
+ /**
639
+ * Create a comment on a blog post
640
+ */
641
+ async createBlogPost(slug, data) {
642
+ return this.http.post(`/blog/${slug}/comments`, data);
643
+ }
644
+ /**
645
+ * Get standalone comments (guestbook, feedback, etc.)
646
+ */
647
+ async standalone(pageSlug, params) {
648
+ return this.http.get(`/comments/${pageSlug}`, params);
649
+ }
650
+ /**
651
+ * Create a standalone comment
652
+ */
653
+ async createStandalone(pageSlug, data) {
654
+ return this.http.post(`/comments/${pageSlug}`, data);
655
+ }
656
+ /**
657
+ * Update a comment
658
+ */
659
+ async update(commentId, data) {
660
+ return this.http.put(`/comments/${commentId}`, data);
661
+ }
662
+ /**
663
+ * Delete a comment
664
+ */
665
+ async delete(commentId, data) {
666
+ return this.http.delete(`/comments/${commentId}`, data);
667
+ }
668
+ /**
669
+ * Like a comment
670
+ */
671
+ async like(commentId) {
672
+ return this.http.post(`/comments/${commentId}/like`);
673
+ }
674
+ };
675
+
676
+ // src/resources/forms.ts
677
+ var FormsResource = class {
678
+ constructor(http) {
679
+ this.http = http;
680
+ }
681
+ /**
682
+ * List all forms
683
+ * @returns ListResponse with data array and pagination meta
684
+ */
685
+ async list(params) {
686
+ return this.http.getList("/forms", params);
687
+ }
688
+ /**
689
+ * Get form by ID or slug
690
+ */
691
+ async get(idOrSlug) {
692
+ return this.http.get(`/forms/${idOrSlug}`);
693
+ }
694
+ /**
695
+ * Submit form data
696
+ */
697
+ async submit(formIdOrSlug, data) {
698
+ return this.http.post(`/forms/${formIdOrSlug}/submit`, data);
699
+ }
700
+ // ============================================
701
+ // Protected endpoints (requires auth)
702
+ // ============================================
703
+ /**
704
+ * Get my form submissions
705
+ * @returns ListResponse with data array and pagination meta
706
+ */
707
+ async mySubmissions(params) {
708
+ return this.http.getList("/form-submissions", params);
709
+ }
710
+ /**
711
+ * Get specific submission
712
+ */
713
+ async getSubmission(submissionId) {
714
+ return this.http.get(`/form-submissions/${submissionId}`);
715
+ }
716
+ };
717
+
718
+ // src/resources/shop.ts
719
+ var ShopResource = class {
720
+ constructor(http) {
721
+ this.http = http;
722
+ }
723
+ // ============================================
724
+ // Products (Public)
725
+ // ============================================
726
+ /**
727
+ * List products
728
+ * @returns ListResponse with data array and pagination meta
729
+ */
730
+ async listProducts(params) {
731
+ return this.http.getList("/products", params);
732
+ }
733
+ /**
734
+ * Get product by ID or slug
735
+ */
736
+ async getProduct(idOrSlug) {
737
+ return this.http.get(`/products/${idOrSlug}`);
738
+ }
739
+ /**
740
+ * Get featured products
741
+ * @returns Array of featured products (always an array)
742
+ */
743
+ async featuredProducts(limit = 8) {
744
+ const response = await this.http.getList("/products", {
745
+ per_page: limit,
746
+ is_featured: true
747
+ });
748
+ return response.data;
749
+ }
750
+ /**
751
+ * Search products
752
+ * @returns ListResponse with data array and pagination meta
753
+ */
754
+ async searchProducts(query, params) {
755
+ return this.http.getList("/products", {
756
+ ...params,
757
+ search: query
758
+ });
759
+ }
760
+ // ============================================
761
+ // Categories (Public)
762
+ // ============================================
763
+ /**
764
+ * List product categories
765
+ * @returns ListResponse with data array and pagination meta
766
+ */
767
+ async listCategories() {
768
+ return this.http.getList("/categories");
769
+ }
770
+ /**
771
+ * Get category by ID or slug
772
+ */
773
+ async getCategory(idOrSlug) {
774
+ return this.http.get(`/categories/${idOrSlug}`);
775
+ }
776
+ /**
777
+ * Get products in category
778
+ * @returns ListResponse with data array and pagination meta
779
+ */
780
+ async categoryProducts(categoryIdOrSlug, params) {
781
+ return this.http.getList(`/categories/${categoryIdOrSlug}/products`, params);
782
+ }
783
+ // ============================================
784
+ // Cart
785
+ // ============================================
786
+ /**
787
+ * Save cart session ID from response (for guest cart persistence)
788
+ */
789
+ saveCartSession(cart) {
790
+ if (cart.session_id) {
791
+ this.http.setCartSessionId(cart.session_id);
792
+ }
793
+ return cart;
794
+ }
795
+ /**
796
+ * Get current cart
797
+ */
798
+ async getCart() {
799
+ const cart = await this.http.get("/cart");
800
+ return this.saveCartSession(cart);
801
+ }
802
+ /**
803
+ * Add item to cart
804
+ */
805
+ async addToCart(data) {
806
+ const cart = await this.http.post("/cart/items", data);
807
+ return this.saveCartSession(cart);
808
+ }
809
+ /**
810
+ * Update cart item quantity
811
+ */
812
+ async updateCartItem(itemId, data) {
813
+ const cart = await this.http.put(`/cart/items/${itemId}`, data);
814
+ return this.saveCartSession(cart);
815
+ }
816
+ /**
817
+ * Remove item from cart
818
+ */
819
+ async removeFromCart(itemId) {
820
+ const cart = await this.http.delete(`/cart/items/${itemId}`);
821
+ return this.saveCartSession(cart);
822
+ }
823
+ /**
824
+ * Clear entire cart
825
+ */
826
+ async clearCart() {
827
+ await this.http.delete("/cart");
828
+ this.http.setCartSessionId(null);
829
+ }
830
+ // ============================================
831
+ // Orders (Protected)
832
+ // ============================================
833
+ /**
834
+ * List my orders
835
+ * @returns ListResponse with data array and pagination meta
836
+ */
837
+ async listOrders(params) {
838
+ return this.http.getList("/orders", params);
839
+ }
840
+ /**
841
+ * Get order by ID or order number
842
+ */
843
+ async getOrder(idOrNumber) {
844
+ return this.http.get(`/orders/${idOrNumber}`);
845
+ }
846
+ /**
847
+ * Create order from cart
848
+ */
849
+ async createOrder(data) {
850
+ return this.http.post("/orders", data);
851
+ }
852
+ /**
853
+ * Cancel order
854
+ */
855
+ async cancelOrder(orderId) {
856
+ return this.http.post(`/orders/${orderId}/cancel`);
857
+ }
858
+ // ============================================
859
+ // Payments
860
+ // ============================================
861
+ /**
862
+ * Get payment for order
863
+ */
864
+ async getPayment(orderId) {
865
+ return this.http.get(`/orders/${orderId}/payment`);
866
+ }
867
+ /**
868
+ * Get payment status (available payment methods)
869
+ */
870
+ async getPaymentStatus() {
871
+ return this.http.get("/payments/status");
872
+ }
873
+ // ============================================
874
+ // Toss Payments
875
+ // ============================================
876
+ /**
877
+ * Prepare Toss payment (get client key and payment info)
878
+ */
879
+ async tossPaymentReady(data) {
880
+ return this.http.post("/payments/toss/ready", data);
881
+ }
882
+ /**
883
+ * Confirm Toss payment (after redirect)
884
+ */
885
+ async tossPaymentConfirm(data) {
886
+ return this.http.post("/payments/toss/confirm", data);
887
+ }
888
+ /**
889
+ * Cancel Toss payment
890
+ */
891
+ async tossPaymentCancel(orderNumber, cancelReason, cancelAmount) {
892
+ await this.http.post("/payments/toss/cancel", {
893
+ order_number: orderNumber,
894
+ cancel_reason: cancelReason,
895
+ cancel_amount: cancelAmount
896
+ });
897
+ }
898
+ // ============================================
899
+ // Stripe Payments
900
+ // ============================================
901
+ /**
902
+ * Create Stripe Checkout Session
903
+ */
904
+ async stripeCheckout(data) {
905
+ return this.http.post("/payments/stripe/checkout", data);
906
+ }
907
+ /**
908
+ * Verify Stripe payment (after redirect)
909
+ */
910
+ async stripeVerify(data) {
911
+ return this.http.post("/payments/stripe/verify", data);
912
+ }
913
+ /**
914
+ * Refund Stripe payment
915
+ */
916
+ async stripeRefund(orderNumber, reason, amount) {
917
+ await this.http.post("/payments/stripe/refund", {
918
+ order_number: orderNumber,
919
+ reason,
920
+ amount
921
+ });
922
+ }
923
+ // ============================================
924
+ // Legacy Payment Methods (deprecated)
925
+ // ============================================
926
+ /**
927
+ * @deprecated Use tossPaymentReady instead
928
+ */
929
+ async preparePayment(data) {
930
+ return this.http.post(`/payments/ready`, data);
931
+ }
932
+ /**
933
+ * @deprecated Use tossPaymentConfirm instead
934
+ */
935
+ async confirmPayment(data) {
936
+ return this.http.post("/payments/confirm", data);
937
+ }
938
+ /**
939
+ * @deprecated Use tossPaymentCancel instead
940
+ */
941
+ async cancelPayment(paymentId, data) {
942
+ return this.http.post(`/payments/${paymentId}/cancel`, data);
943
+ }
944
+ // ============================================
945
+ // Coupons
946
+ // ============================================
947
+ /**
948
+ * Validate coupon code
949
+ */
950
+ async validateCoupon(code, orderAmount) {
951
+ return this.http.post("/coupons/validate", {
952
+ code,
953
+ order_amount: orderAmount
954
+ });
955
+ }
956
+ /**
957
+ * Get available coupons for current user
958
+ * @returns Array of coupons (always an array)
959
+ */
960
+ async myCoupons() {
961
+ const response = await this.http.getList("/coupons");
962
+ return response.data;
963
+ }
964
+ // ============================================
965
+ // Product Reviews
966
+ // ============================================
967
+ /**
968
+ * Get reviews for a product
969
+ * @param productSlug - Product slug
970
+ * @param params - Optional list params (rating, sort, per_page)
971
+ * @returns Reviews with stats
972
+ */
973
+ async getProductReviews(productSlug, params) {
974
+ return this.http.get(`/products/${productSlug}/reviews`, params);
975
+ }
976
+ /**
977
+ * Check if current user can review a product
978
+ * Requires: logged in + purchased the product + not already reviewed
979
+ */
980
+ async canReviewProduct(productSlug) {
981
+ const response = await this.http.get(
982
+ `/products/${productSlug}/reviews/can-review`
983
+ );
984
+ return response;
985
+ }
986
+ /**
987
+ * Create a product review (requires purchase)
988
+ */
989
+ async createReview(productSlug, data) {
990
+ const response = await this.http.post(
991
+ `/products/${productSlug}/reviews`,
992
+ data
993
+ );
994
+ return response.data;
995
+ }
996
+ /**
997
+ * Update your own review
998
+ */
999
+ async updateReview(reviewId, data) {
1000
+ const response = await this.http.put(
1001
+ `/reviews/${reviewId}`,
1002
+ data
1003
+ );
1004
+ return response.data;
1005
+ }
1006
+ /**
1007
+ * Delete your own review
1008
+ */
1009
+ async deleteReview(reviewId) {
1010
+ await this.http.delete(`/reviews/${reviewId}`);
1011
+ }
1012
+ /**
1013
+ * Mark a review as helpful
1014
+ */
1015
+ async markReviewHelpful(reviewId) {
1016
+ return this.http.post(`/reviews/${reviewId}/helpful`);
1017
+ }
1018
+ /**
1019
+ * Get my reviews
1020
+ * @returns Array of reviews written by the current user
1021
+ */
1022
+ async myReviews(params) {
1023
+ return this.http.getList("/my/reviews", params);
1024
+ }
1025
+ };
1026
+
1027
+ // src/resources/media.ts
1028
+ var MediaResource = class {
1029
+ constructor(http) {
1030
+ this.http = http;
1031
+ }
1032
+ /**
1033
+ * List my media files
1034
+ */
1035
+ async list(params) {
1036
+ return this.http.get("/media", params);
1037
+ }
1038
+ /**
1039
+ * Get media by ID
1040
+ */
1041
+ async get(mediaId) {
1042
+ return this.http.get(`/media/${mediaId}`);
1043
+ }
1044
+ /**
1045
+ * Upload file
1046
+ */
1047
+ async upload(file) {
1048
+ return this.http.upload("/media", file, "file");
1049
+ }
1050
+ /**
1051
+ * Upload multiple files
1052
+ */
1053
+ async uploadMultiple(files) {
1054
+ const results = [];
1055
+ for (const file of files) {
1056
+ const media = await this.upload(file);
1057
+ results.push(media);
1058
+ }
1059
+ return results;
1060
+ }
1061
+ /**
1062
+ * Delete media
1063
+ */
1064
+ async delete(mediaId) {
1065
+ return this.http.delete(`/media/${mediaId}`);
1066
+ }
1067
+ };
1068
+
1069
+ // src/resources/entities.ts
1070
+ var EntitiesResource = class {
1071
+ constructor(http) {
1072
+ this.http = http;
1073
+ }
1074
+ // ============================================
1075
+ // Entity Definitions CRUD
1076
+ // ============================================
1077
+ /**
1078
+ * List all custom entities
1079
+ * @returns Array of entities
1080
+ *
1081
+ * @example
1082
+ * ```typescript
1083
+ * const entities = await client.entities.list();
1084
+ * // [{ id: 1, name: 'Customer', slug: 'customer', records_count: 150, ... }]
1085
+ * ```
1086
+ */
1087
+ async list() {
1088
+ const response = await this.http.getList("/entities");
1089
+ return response.data;
1090
+ }
1091
+ /**
1092
+ * Create a new entity definition
1093
+ *
1094
+ * @example
1095
+ * ```typescript
1096
+ * const entity = await client.entities.create({
1097
+ * name: '고객',
1098
+ * slug: 'customers', // optional, auto-generated from name
1099
+ * description: '고객 관리',
1100
+ * schema: {
1101
+ * fields: [
1102
+ * { name: 'company', label: '회사명', type: 'text', required: true },
1103
+ * { name: 'email', label: '이메일', type: 'email', required: true },
1104
+ * { name: 'status', label: '상태', type: 'select', options: [
1105
+ * { value: 'active', label: '활성' },
1106
+ * { value: 'inactive', label: '비활성' }
1107
+ * ]}
1108
+ * ]
1109
+ * },
1110
+ * icon: 'users'
1111
+ * });
1112
+ * ```
1113
+ */
1114
+ async create(data) {
1115
+ return this.http.post("/entities", data);
1116
+ }
1117
+ /**
1118
+ * Get entity definition by slug (includes schema)
1119
+ *
1120
+ * @example
1121
+ * ```typescript
1122
+ * const entity = await client.entities.get('customers');
1123
+ * console.log(entity.schema.fields);
1124
+ * ```
1125
+ */
1126
+ async get(slug) {
1127
+ return this.http.get(`/entities/${slug}`);
1128
+ }
1129
+ /**
1130
+ * Update an entity definition
1131
+ *
1132
+ * @example
1133
+ * ```typescript
1134
+ * const updated = await client.entities.update('customers', {
1135
+ * name: '고객사',
1136
+ * description: '고객사 관리'
1137
+ * });
1138
+ * ```
1139
+ */
1140
+ async update(slug, data) {
1141
+ return this.http.put(`/entities/${slug}`, data);
1142
+ }
1143
+ /**
1144
+ * Delete an entity definition
1145
+ * If entity has records, use force=true to delete anyway
1146
+ *
1147
+ * @example
1148
+ * ```typescript
1149
+ * // Will fail if entity has records
1150
+ * await client.entities.delete('customers');
1151
+ *
1152
+ * // Force delete with all records
1153
+ * await client.entities.delete('customers', true);
1154
+ * ```
1155
+ */
1156
+ async delete(slug, force = false) {
1157
+ const params = force ? { force: "true" } : void 0;
1158
+ return this.http.delete(`/entities/${slug}`, params);
1159
+ }
1160
+ /**
1161
+ * Get entity schema (convenience method)
1162
+ * @deprecated Use get(slug) instead - it includes schema
1163
+ */
1164
+ async getSchema(slug) {
1165
+ const entity = await this.get(slug);
1166
+ return entity.schema;
1167
+ }
1168
+ // ============================================
1169
+ // Records CRUD
1170
+ // ============================================
1171
+ /**
1172
+ * List records for an entity
1173
+ * @returns ListResponse with data array and pagination meta
1174
+ *
1175
+ * @example
1176
+ * ```typescript
1177
+ * // Basic listing
1178
+ * const customers = await client.entities.listRecords('customers');
1179
+ *
1180
+ * // With pagination and search
1181
+ * const customers = await client.entities.listRecords('customers', {
1182
+ * page: 1,
1183
+ * per_page: 20,
1184
+ * search: 'ACME',
1185
+ * sort: 'company',
1186
+ * dir: 'asc'
1187
+ * });
1188
+ *
1189
+ * // With filtering
1190
+ * const vipCustomers = await client.entities.listRecords('customers', {
1191
+ * filters: JSON.stringify({ tier: 'vip' })
1192
+ * });
1193
+ * ```
1194
+ */
1195
+ async listRecords(slug, params) {
1196
+ return this.http.getList(`/entities/${slug}/records`, params);
1197
+ }
1198
+ /**
1199
+ * Get a single record by ID
1200
+ *
1201
+ * @example
1202
+ * ```typescript
1203
+ * const customer = await client.entities.getRecord('customers', 1);
1204
+ * console.log(customer.data.company); // 'ABC Corp'
1205
+ * ```
1206
+ */
1207
+ async getRecord(slug, id) {
1208
+ return this.http.get(`/entities/${slug}/records/${id}`);
1209
+ }
1210
+ /**
1211
+ * Create a new record
1212
+ * Request body fields are defined by entity schema
1213
+ *
1214
+ * @example
1215
+ * ```typescript
1216
+ * const newCustomer = await client.entities.createRecord('customers', {
1217
+ * company: 'ABC Corp',
1218
+ * email: 'contact@abc.com',
1219
+ * tier: 'standard',
1220
+ * });
1221
+ * ```
1222
+ */
1223
+ async createRecord(slug, data) {
1224
+ return this.http.post(`/entities/${slug}/records`, data);
1225
+ }
1226
+ /**
1227
+ * Update a record
1228
+ * Only provided fields will be updated, existing data is preserved
1229
+ *
1230
+ * @example
1231
+ * ```typescript
1232
+ * const updated = await client.entities.updateRecord('customers', 1, {
1233
+ * tier: 'vip',
1234
+ * email: 'new@abc.com'
1235
+ * });
1236
+ * ```
1237
+ */
1238
+ async updateRecord(slug, id, data) {
1239
+ return this.http.put(`/entities/${slug}/records/${id}`, data);
1240
+ }
1241
+ /**
1242
+ * Delete a record
1243
+ *
1244
+ * @example
1245
+ * ```typescript
1246
+ * await client.entities.deleteRecord('customers', 1);
1247
+ * ```
1248
+ */
1249
+ async deleteRecord(slug, id) {
1250
+ return this.http.delete(`/entities/${slug}/records/${id}`);
1251
+ }
1252
+ // ============================================
1253
+ // Helper Methods
1254
+ // ============================================
1255
+ /**
1256
+ * Get a value from a record's data
1257
+ *
1258
+ * @example
1259
+ * ```typescript
1260
+ * const record = await client.entities.getRecord('customers', 1);
1261
+ * const company = client.entities.getValue(record, 'company');
1262
+ * ```
1263
+ */
1264
+ getValue(record, field) {
1265
+ return record.data?.[field];
1266
+ }
1267
+ /**
1268
+ * Create a typed accessor for an entity
1269
+ *
1270
+ * @example
1271
+ * ```typescript
1272
+ * interface Customer {
1273
+ * company: string;
1274
+ * email: string;
1275
+ * tier: 'standard' | 'vip';
1276
+ * }
1277
+ *
1278
+ * const customers = client.entities.typed<Customer>('customers');
1279
+ * const list = await customers.list(); // Typed records
1280
+ * const record = await customers.get(1);
1281
+ * console.log(record.data.company); // TypeScript knows this is string
1282
+ * ```
1283
+ */
1284
+ typed(slug) {
1285
+ return {
1286
+ list: async (params) => {
1287
+ const response = await this.listRecords(slug, params);
1288
+ return {
1289
+ ...response,
1290
+ data: response.data
1291
+ };
1292
+ },
1293
+ get: async (id) => {
1294
+ const record = await this.getRecord(slug, id);
1295
+ return record;
1296
+ },
1297
+ create: async (data) => {
1298
+ const record = await this.createRecord(slug, data);
1299
+ return record;
1300
+ },
1301
+ update: async (id, data) => {
1302
+ const record = await this.updateRecord(slug, id, data);
1303
+ return record;
1304
+ },
1305
+ delete: (id) => this.deleteRecord(slug, id)
1306
+ };
1307
+ }
1308
+ };
1309
+
1310
+ // src/resources/reservation.ts
1311
+ var ReservationResource = class {
1312
+ constructor(http) {
1313
+ this.http = http;
1314
+ }
1315
+ // ============================================
1316
+ // Public Endpoints
1317
+ // ============================================
1318
+ /**
1319
+ * Get reservation settings
1320
+ * @returns Reservation settings for the tenant
1321
+ */
1322
+ async getSettings() {
1323
+ return this.http.get("/reservation/settings");
1324
+ }
1325
+ /**
1326
+ * List available services
1327
+ * @returns Array of services (always an array)
1328
+ */
1329
+ async listServices() {
1330
+ const response = await this.http.getList("/reservation/services");
1331
+ return response.data;
1332
+ }
1333
+ /**
1334
+ * List available staff members
1335
+ * @param serviceId - Optional: filter staff by service
1336
+ * @returns Array of staff members (always an array)
1337
+ */
1338
+ async listStaff(serviceId) {
1339
+ const params = serviceId ? { service_id: serviceId } : void 0;
1340
+ const response = await this.http.getList("/reservation/staffs", params);
1341
+ return response.data;
1342
+ }
1343
+ /**
1344
+ * Get available dates for booking
1345
+ * @returns Array of available date strings (YYYY-MM-DD)
1346
+ */
1347
+ async getAvailableDates(params) {
1348
+ const response = await this.http.get("/reservation/available-dates", params);
1349
+ return Array.isArray(response) ? response : response?.data ?? [];
1350
+ }
1351
+ /**
1352
+ * Get available time slots for a specific date
1353
+ * @returns Array of available slots (always an array)
1354
+ */
1355
+ async getAvailableSlots(params) {
1356
+ const response = await this.http.get("/reservation/available-slots", params);
1357
+ return Array.isArray(response) ? response : response?.data ?? [];
1358
+ }
1359
+ // ============================================
1360
+ // Protected Endpoints (requires auth)
1361
+ // ============================================
1362
+ /**
1363
+ * Create a new reservation
1364
+ * @returns Created reservation with payment info
1365
+ */
1366
+ async create(data) {
1367
+ return this.http.post("/reservations", data);
1368
+ }
1369
+ /**
1370
+ * List my reservations
1371
+ * @returns ListResponse with reservations and pagination meta
1372
+ */
1373
+ async list(params) {
1374
+ return this.http.getList("/reservations", params);
1375
+ }
1376
+ /**
1377
+ * Get upcoming reservations
1378
+ * @returns Array of upcoming reservations
1379
+ */
1380
+ async upcoming(limit = 10) {
1381
+ const response = await this.http.getList("/reservations", {
1382
+ upcoming: true,
1383
+ per_page: limit
1384
+ });
1385
+ return response.data;
1386
+ }
1387
+ /**
1388
+ * Get past reservations
1389
+ * @returns Array of past reservations
1390
+ */
1391
+ async past(limit = 10) {
1392
+ const response = await this.http.getList("/reservations", {
1393
+ past: true,
1394
+ per_page: limit
1395
+ });
1396
+ return response.data;
1397
+ }
1398
+ /**
1399
+ * Get reservation by reservation number
1400
+ */
1401
+ async get(reservationNumber) {
1402
+ return this.http.get(`/reservations/${reservationNumber}`);
1403
+ }
1404
+ /**
1405
+ * Cancel a reservation
1406
+ * @param reservationNumber - Reservation number to cancel
1407
+ * @param reason - Optional cancellation reason
1408
+ */
1409
+ async cancel(reservationNumber, reason) {
1410
+ return this.http.post(`/reservations/${reservationNumber}/cancel`, { reason });
1411
+ }
1412
+ };
1413
+
1414
+ // src/index.ts
1415
+ var Diffsome = class {
1416
+ constructor(config) {
1417
+ if (!config.apiKey) {
1418
+ throw new Error("API key is required. Get your API key from Dashboard > Settings > API Tokens");
1419
+ }
1420
+ this.http = new HttpClient(config);
1421
+ this.auth = new AuthResource(this.http);
1422
+ this.boards = new BoardsResource(this.http);
1423
+ this.blog = new BlogResource(this.http);
1424
+ this.comments = new CommentsResource(this.http);
1425
+ this.forms = new FormsResource(this.http);
1426
+ this.shop = new ShopResource(this.http);
1427
+ this.media = new MediaResource(this.http);
1428
+ this.entities = new EntitiesResource(this.http);
1429
+ this.reservation = new ReservationResource(this.http);
1430
+ }
1431
+ /**
1432
+ * Get site theme settings
1433
+ */
1434
+ async getTheme() {
1435
+ return this.http.get("/public/theme");
1436
+ }
1437
+ /**
1438
+ * Get site settings
1439
+ */
1440
+ async getSettings() {
1441
+ return this.http.get("/public/settings");
1442
+ }
1443
+ /**
1444
+ * Check if user is authenticated
1445
+ */
1446
+ isAuthenticated() {
1447
+ return this.auth.isAuthenticated();
1448
+ }
1449
+ /**
1450
+ * Set authentication token manually
1451
+ */
1452
+ setToken(token) {
1453
+ this.auth.setToken(token);
1454
+ }
1455
+ /**
1456
+ * Get current authentication token
1457
+ */
1458
+ getToken() {
1459
+ return this.auth.getToken();
1460
+ }
1461
+ /**
1462
+ * Set API key for server-to-server authentication
1463
+ * Alternative to user token authentication
1464
+ *
1465
+ * @example
1466
+ * ```typescript
1467
+ * const client = new Diffsome({
1468
+ * tenantId: 'my-site',
1469
+ * apiKey: 'pky_your_api_key_here',
1470
+ * });
1471
+ *
1472
+ * // Or set later
1473
+ * client.setApiKey('pky_your_api_key_here');
1474
+ * ```
1475
+ */
1476
+ setApiKey(apiKey) {
1477
+ this.http.setApiKey(apiKey);
1478
+ }
1479
+ /**
1480
+ * Get current API key
1481
+ */
1482
+ getApiKey() {
1483
+ return this.http.getApiKey();
1484
+ }
1485
+ };
1486
+ var index_default = Diffsome;
1487
+ // Annotate the CommonJS export names for ESM import in node:
1488
+ 0 && (module.exports = {
1489
+ Diffsome,
1490
+ DiffsomeError,
1491
+ Promptly,
1492
+ PromptlyError
1493
+ });