@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/README.md +667 -0
- package/dist/index.d.mts +9856 -0
- package/dist/index.d.ts +9856 -0
- package/dist/index.js +1493 -0
- package/dist/index.mjs +1463 -0
- package/package.json +51 -0
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
|
+
});
|