@symbo.ls/sdk 2.32.0 → 2.32.2

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.
Files changed (82) hide show
  1. package/dist/cjs/config/environment.js +8 -43
  2. package/dist/cjs/index.js +4 -12
  3. package/dist/cjs/services/AdminService.js +4 -4
  4. package/dist/cjs/services/AuthService.js +149 -36
  5. package/dist/cjs/services/BaseService.js +18 -5
  6. package/dist/cjs/services/BranchService.js +10 -10
  7. package/dist/cjs/services/CollabService.js +18 -114
  8. package/dist/cjs/services/CoreService.js +19 -19
  9. package/dist/cjs/services/DnsService.js +4 -4
  10. package/dist/cjs/services/FileService.js +2 -2
  11. package/dist/cjs/services/PaymentService.js +2 -2
  12. package/dist/cjs/services/PlanService.js +12 -12
  13. package/dist/cjs/services/ProjectService.js +34 -39
  14. package/dist/cjs/services/PullRequestService.js +7 -7
  15. package/dist/cjs/services/SubscriptionService.js +14 -14
  16. package/dist/cjs/services/index.js +0 -4
  17. package/dist/cjs/utils/TokenManager.js +5 -16
  18. package/dist/cjs/utils/services.js +1 -14
  19. package/dist/esm/config/environment.js +8 -43
  20. package/dist/esm/index.js +300 -907
  21. package/dist/esm/services/AdminService.js +35 -68
  22. package/dist/esm/services/AuthService.js +168 -100
  23. package/dist/esm/services/BaseService.js +31 -64
  24. package/dist/esm/services/BranchService.js +41 -74
  25. package/dist/esm/services/CollabService.js +50 -452
  26. package/dist/esm/services/CoreService.js +50 -83
  27. package/dist/esm/services/DnsService.js +35 -68
  28. package/dist/esm/services/FileService.js +33 -66
  29. package/dist/esm/services/PaymentService.js +33 -66
  30. package/dist/esm/services/PlanService.js +43 -76
  31. package/dist/esm/services/ProjectService.js +65 -375
  32. package/dist/esm/services/PullRequestService.js +38 -71
  33. package/dist/esm/services/SubscriptionService.js +45 -78
  34. package/dist/esm/services/index.js +295 -884
  35. package/dist/esm/utils/CollabClient.js +8 -43
  36. package/dist/esm/utils/TokenManager.js +5 -16
  37. package/dist/esm/utils/services.js +1 -14
  38. package/dist/node/config/environment.js +8 -43
  39. package/dist/node/index.js +5 -14
  40. package/dist/node/services/AdminService.js +4 -4
  41. package/dist/node/services/AuthService.js +139 -36
  42. package/dist/node/services/BaseService.js +18 -5
  43. package/dist/node/services/BranchService.js +10 -10
  44. package/dist/node/services/CollabService.js +19 -115
  45. package/dist/node/services/CoreService.js +19 -19
  46. package/dist/node/services/DnsService.js +4 -4
  47. package/dist/node/services/FileService.js +2 -2
  48. package/dist/node/services/PaymentService.js +2 -2
  49. package/dist/node/services/PlanService.js +12 -12
  50. package/dist/node/services/ProjectService.js +34 -39
  51. package/dist/node/services/PullRequestService.js +7 -7
  52. package/dist/node/services/SubscriptionService.js +14 -14
  53. package/dist/node/services/index.js +0 -4
  54. package/dist/node/utils/TokenManager.js +5 -16
  55. package/dist/node/utils/services.js +1 -14
  56. package/package.json +6 -7
  57. package/src/config/environment.js +9 -48
  58. package/src/index.js +22 -38
  59. package/src/services/AdminService.js +4 -4
  60. package/src/services/AuthService.js +175 -42
  61. package/src/services/BaseService.js +24 -7
  62. package/src/services/BranchService.js +10 -10
  63. package/src/services/CollabService.js +19 -142
  64. package/src/services/CoreService.js +19 -19
  65. package/src/services/DnsService.js +4 -4
  66. package/src/services/FileService.js +2 -2
  67. package/src/services/PaymentService.js +2 -2
  68. package/src/services/PlanService.js +12 -12
  69. package/src/services/ProjectService.js +34 -41
  70. package/src/services/PullRequestService.js +7 -7
  71. package/src/services/SubscriptionService.js +14 -14
  72. package/src/services/index.js +1 -6
  73. package/src/utils/TokenManager.js +5 -19
  74. package/src/utils/services.js +1 -15
  75. package/dist/cjs/services/ScreenshotService.js +0 -304
  76. package/dist/cjs/utils/ordering.js +0 -295
  77. package/dist/esm/services/ScreenshotService.js +0 -992
  78. package/dist/esm/utils/ordering.js +0 -277
  79. package/dist/node/services/ScreenshotService.js +0 -285
  80. package/dist/node/utils/ordering.js +0 -276
  81. package/src/services/ScreenshotService.js +0 -258
  82. package/src/utils/ordering.js +0 -240
@@ -1,992 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
-
5
- // src/config/environment.js
6
- import { isDevelopment } from "@domql/utils";
7
- var CONFIG = {
8
- // Common defaults for all environments
9
- common: {
10
- // NOTE: Google client id for google auth, need to configure URLs for each environment in Google console
11
- googleClientId: "686286207466-bvd2fqs31rlm64fgich7rtpnc8ns2tqg.apps.googleusercontent.com",
12
- // Feature toggles that apply across all environments by default
13
- features: {
14
- newUserOnboarding: true,
15
- betaFeatures: false
16
- }
17
- },
18
- // Environment-specific configurations
19
- local: {
20
- // local
21
- socketUrl: "http://localhost:8080",
22
- // For socket api
23
- apiUrl: "http://localhost:8080",
24
- // For server api
25
- basedEnv: "development",
26
- // For based api
27
- basedProject: "platform-v2-sm",
28
- // For based api
29
- basedOrg: "symbols",
30
- // For based api
31
- githubClientId: "Ov23liAFrsR0StbAO6PO",
32
- // For github api
33
- // Environment-specific feature toggles (override common)
34
- features: {
35
- betaFeatures: true
36
- // Enable beta features in local dev
37
- },
38
- typesenseCollectionName: "docs",
39
- typesenseApiKey: "vZya3L2zpq8L6iI5WWMUZJZABvT63VDb",
40
- typesenseHost: "localhost",
41
- typesensePort: "8108",
42
- typesenseProtocol: "http"
43
- },
44
- development: {
45
- socketUrl: "https://dev.api.symbols.app",
46
- apiUrl: "https://dev.api.symbols.app",
47
- githubClientId: "Ov23liHxyWFBxS8f1gnF",
48
- typesenseCollectionName: "docs",
49
- typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
50
- typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
51
- typesensePort: "443",
52
- typesenseProtocol: "https"
53
- },
54
- testing: {
55
- socketUrl: "https://test.api.symbols.app",
56
- apiUrl: "https://test.api.symbols.app",
57
- basedEnv: "testing",
58
- basedProject: "platform-v2-sm",
59
- basedOrg: "symbols",
60
- githubClientId: "Ov23liHxyWFBxS8f1gnF",
61
- typesenseCollectionName: "docs",
62
- typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
63
- typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
64
- typesensePort: "443",
65
- typesenseProtocol: "https"
66
- },
67
- upcoming: {
68
- socketUrl: "https://upcoming.api.symbols.app",
69
- apiUrl: "https://upcoming.api.symbols.app",
70
- githubClientId: "Ov23liWF7NvdZ056RV5J",
71
- typesenseCollectionName: "docs",
72
- typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
73
- typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
74
- typesensePort: "443",
75
- typesenseProtocol: "https"
76
- },
77
- staging: {
78
- socketUrl: "https://staging.api.symbols.app",
79
- apiUrl: "https://staging.api.symbols.app",
80
- basedEnv: "staging",
81
- basedProject: "platform-v2-sm",
82
- basedOrg: "symbols",
83
- githubClientId: "Ov23ligwZDQVD0VfuWNa",
84
- typesenseCollectionName: "docs",
85
- typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
86
- typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
87
- typesensePort: "443",
88
- typesenseProtocol: "https"
89
- },
90
- production: {
91
- socketUrl: "https://api.symbols.app",
92
- apiUrl: "https://api.symbols.app",
93
- basedEnv: "production",
94
- basedProject: "platform-v2-sm",
95
- basedOrg: "symbols",
96
- githubClientId: "Ov23liFAlOEIXtX3dBtR",
97
- typesenseCollectionName: "docs",
98
- typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
99
- typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
100
- typesensePort: "443",
101
- typesenseProtocol: "https"
102
- }
103
- };
104
- var getEnvironment = () => {
105
- const env = process.env.SYMBOLS_APP_ENV || process.env.NODE_ENV;
106
- if (!CONFIG[env]) {
107
- throw new Error(`Unknown environment "${env}"`);
108
- }
109
- return env;
110
- };
111
- var getConfig = () => {
112
- try {
113
- const env = getEnvironment();
114
- const envConfig = { ...CONFIG.common, ...CONFIG[env] };
115
- const finalConfig = {
116
- ...envConfig,
117
- socketUrl: process.env.SYMBOLS_APP_SOCKET_URL || envConfig.socketUrl,
118
- apiUrl: process.env.SYMBOLS_APP_API_URL || envConfig.apiUrl,
119
- basedEnv: process.env.SYMBOLS_APP_BASED_ENV || envConfig.basedEnv,
120
- basedProject: process.env.SYMBOLS_APP_BASED_PROJECT || envConfig.basedProject,
121
- basedOrg: process.env.SYMBOLS_APP_BASED_ORG || envConfig.basedOrg,
122
- githubClientId: process.env.SYMBOLS_APP_GITHUB_CLIENT_ID || envConfig.githubClientId,
123
- typesenseCollectionName: process.env.TYPESENSE_COLLECTION_NAME || envConfig.typesenseCollectionName,
124
- typesenseApiKey: process.env.TYPESENSE_API_KEY || envConfig.typesenseApiKey,
125
- typesenseHost: process.env.TYPESENSE_HOST || envConfig.typesenseHost,
126
- typesensePort: process.env.TYPESENSE_PORT || envConfig.typesensePort,
127
- typesenseProtocol: process.env.TYPESENSE_PROTOCOL || envConfig.typesenseProtocol,
128
- isDevelopment: isDevelopment(env),
129
- isTesting: env === "testing",
130
- isStaging: env === "staging",
131
- isProduction: env === "production"
132
- // Store all environment variables for potential future use
133
- };
134
- const requiredFields = [
135
- "socketUrl",
136
- "apiUrl",
137
- "githubClientId",
138
- "googleClientId"
139
- ];
140
- const missingFields = requiredFields.filter((field) => !finalConfig[field]);
141
- if (missingFields.length > 0) {
142
- console.error(
143
- `Missing required configuration: ${missingFields.join(", ")}`
144
- );
145
- }
146
- if (finalConfig.isDevelopment) {
147
- console.warn(
148
- "environment in SDK:",
149
- env || process.env.NODE_ENV || process.env.NODE_ENV
150
- );
151
- console.log(finalConfig);
152
- } else if (global.window) {
153
- global.window.finalConfig = finalConfig;
154
- }
155
- return finalConfig;
156
- } catch (error) {
157
- console.error("Failed to load environment configuration:", error);
158
- return {
159
- ...CONFIG.development
160
- };
161
- }
162
- };
163
- var environment_default = getConfig();
164
-
165
- // src/utils/TokenManager.js
166
- var TokenManager = class {
167
- constructor(options = {}) {
168
- /**
169
- * Memory storage fallback for server-side rendering
170
- */
171
- __publicField(this, "_memoryStorage", {
172
- _data: {},
173
- getItem: (key) => this._memoryStorage._data[key] || null,
174
- setItem: (key, value) => {
175
- this._memoryStorage._data[key] = value;
176
- },
177
- removeItem: (key) => {
178
- delete this._memoryStorage._data[key];
179
- },
180
- clear: () => {
181
- this._memoryStorage._data = {};
182
- }
183
- });
184
- this.config = {
185
- storagePrefix: "symbols_",
186
- storageType: typeof window === "undefined" || process.env.NODE_ENV === "test" || process.env.NODE_ENV === "testing" ? "memory" : "localStorage",
187
- // 'localStorage' | 'sessionStorage' | 'memory'
188
- refreshBuffer: 60 * 1e3,
189
- // Refresh 1 minute before expiry
190
- maxRetries: 3,
191
- apiUrl: options.apiUrl || "/api",
192
- onTokenRefresh: options.onTokenRefresh || null,
193
- onTokenExpired: options.onTokenExpired || null,
194
- onTokenError: options.onTokenError || null,
195
- ...options
196
- };
197
- this.tokens = {
198
- accessToken: null,
199
- refreshToken: null,
200
- expiresAt: null,
201
- expiresIn: null
202
- };
203
- this.refreshPromise = null;
204
- this.refreshTimeout = null;
205
- this.retryCount = 0;
206
- this.loadTokens();
207
- }
208
- /**
209
- * Storage keys
210
- */
211
- get storageKeys() {
212
- return {
213
- accessToken: `${this.config.storagePrefix}access_token`,
214
- refreshToken: `${this.config.storagePrefix}refresh_token`,
215
- expiresAt: `${this.config.storagePrefix}expires_at`,
216
- expiresIn: `${this.config.storagePrefix}expires_in`
217
- };
218
- }
219
- /**
220
- * Get storage instance based on configuration
221
- */
222
- get storage() {
223
- if (typeof window === "undefined") {
224
- return this._memoryStorage;
225
- }
226
- const safeGetStorage = (provider) => {
227
- try {
228
- const storage = provider();
229
- const testKey = `${this.config.storagePrefix}__tm_test__`;
230
- storage.setItem(testKey, "1");
231
- storage.removeItem(testKey);
232
- return storage;
233
- } catch {
234
- return null;
235
- }
236
- };
237
- const localStorageInstance = safeGetStorage(() => window.localStorage);
238
- const sessionStorageInstance = safeGetStorage(() => window.sessionStorage);
239
- switch (this.config.storageType) {
240
- case "sessionStorage":
241
- return sessionStorageInstance || this._memoryStorage;
242
- case "memory":
243
- return this._memoryStorage;
244
- default:
245
- return localStorageInstance || this._memoryStorage;
246
- }
247
- }
248
- /**
249
- * Set tokens and persist to storage
250
- */
251
- setTokens(tokenData) {
252
- const {
253
- access_token: accessToken,
254
- refresh_token: refreshToken,
255
- expires_in: expiresIn,
256
- token_type: tokenType = "Bearer"
257
- } = tokenData;
258
- if (!accessToken) {
259
- throw new Error("Access token is required");
260
- }
261
- const now = Date.now();
262
- const expiresAt = expiresIn ? now + expiresIn * 1e3 : null;
263
- this.tokens = {
264
- accessToken,
265
- refreshToken: refreshToken || this.tokens.refreshToken,
266
- expiresAt,
267
- expiresIn,
268
- tokenType
269
- };
270
- this.saveTokens();
271
- this.scheduleRefresh();
272
- if (this.config.onTokenRefresh) {
273
- this.config.onTokenRefresh(this.tokens);
274
- }
275
- return this.tokens;
276
- }
277
- /**
278
- * Get current access token
279
- */
280
- getAccessToken() {
281
- return this.tokens.accessToken;
282
- }
283
- /**
284
- * Get current refresh token
285
- */
286
- getRefreshToken() {
287
- return this.tokens.refreshToken;
288
- }
289
- /**
290
- * Get authorization header value
291
- */
292
- getAuthHeader() {
293
- const token = this.getAccessToken();
294
- if (!token) {
295
- return null;
296
- }
297
- return `${this.tokens.tokenType || "Bearer"} ${token}`;
298
- }
299
- /**
300
- * Check if access token is valid and not expired
301
- */
302
- isAccessTokenValid() {
303
- if (!this.tokens.accessToken) {
304
- return false;
305
- }
306
- if (!this.tokens.expiresAt) {
307
- return true;
308
- }
309
- const now = Date.now();
310
- const isValid = now < this.tokens.expiresAt - this.config.refreshBuffer;
311
- if (!isValid) {
312
- console.log("[TokenManager] Access token is expired or near expiry:", {
313
- now: new Date(now).toISOString(),
314
- expiresAt: new Date(this.tokens.expiresAt).toISOString(),
315
- refreshBuffer: this.config.refreshBuffer
316
- });
317
- }
318
- return isValid;
319
- }
320
- /**
321
- * Check if access token exists and is not expired (without refresh buffer)
322
- */
323
- isAccessTokenActuallyValid() {
324
- if (!this.tokens.accessToken) {
325
- return false;
326
- }
327
- if (!this.tokens.expiresAt) {
328
- return true;
329
- }
330
- const now = Date.now();
331
- return now < this.tokens.expiresAt;
332
- }
333
- /**
334
- * Check if tokens exist (regardless of expiry)
335
- */
336
- hasTokens() {
337
- return Boolean(this.tokens.accessToken);
338
- }
339
- /**
340
- * Check if refresh token exists
341
- */
342
- hasRefreshToken() {
343
- return Boolean(this.tokens.refreshToken);
344
- }
345
- /**
346
- * Automatically refresh tokens if needed
347
- */
348
- async ensureValidToken() {
349
- if (!this.hasTokens()) {
350
- return null;
351
- }
352
- if (this.isAccessTokenValid()) {
353
- return this.getAccessToken();
354
- }
355
- if (!this.hasRefreshToken()) {
356
- this.clearTokens();
357
- if (this.config.onTokenExpired) {
358
- this.config.onTokenExpired();
359
- }
360
- return null;
361
- }
362
- try {
363
- await this.refreshTokens();
364
- return this.getAccessToken();
365
- } catch (error) {
366
- this.clearTokens();
367
- if (this.config.onTokenError) {
368
- this.config.onTokenError(error);
369
- }
370
- throw error;
371
- }
372
- }
373
- /**
374
- * Refresh access token using refresh token
375
- */
376
- async refreshTokens() {
377
- if (this.refreshPromise) {
378
- return this.refreshPromise;
379
- }
380
- if (!this.hasRefreshToken()) {
381
- throw new Error("No refresh token available");
382
- }
383
- if (this.retryCount >= this.config.maxRetries) {
384
- throw new Error("Max refresh retries exceeded");
385
- }
386
- this.refreshPromise = this._performRefresh();
387
- try {
388
- const result = await this.refreshPromise;
389
- this.retryCount = 0;
390
- return result;
391
- } catch (error) {
392
- this.retryCount++;
393
- throw error;
394
- } finally {
395
- this.refreshPromise = null;
396
- }
397
- }
398
- /**
399
- * Perform the actual token refresh request
400
- */
401
- async _performRefresh() {
402
- var _a;
403
- const refreshToken = this.getRefreshToken();
404
- const response = await fetch(`${this.config.apiUrl}/core/auth/refresh`, {
405
- method: "POST",
406
- headers: {
407
- "Content-Type": "application/json"
408
- },
409
- body: JSON.stringify({ refreshToken })
410
- });
411
- if (!response.ok) {
412
- const errorData = await response.json().catch(() => ({}));
413
- throw new Error(errorData.message || `Token refresh failed: ${response.status}`);
414
- }
415
- const responseData = await response.json();
416
- if (responseData.success && responseData.data && responseData.data.tokens) {
417
- const { tokens } = responseData.data;
418
- const tokenData = {
419
- access_token: tokens.accessToken,
420
- refresh_token: tokens.refreshToken,
421
- expires_in: (_a = tokens.accessTokenExp) == null ? void 0 : _a.expiresIn,
422
- token_type: "Bearer"
423
- };
424
- return this.setTokens(tokenData);
425
- }
426
- return this.setTokens(responseData);
427
- }
428
- /**
429
- * Schedule automatic token refresh
430
- */
431
- scheduleRefresh() {
432
- if (this.refreshTimeout) {
433
- clearTimeout(this.refreshTimeout);
434
- this.refreshTimeout = null;
435
- }
436
- if (!this.tokens.expiresAt || !this.hasRefreshToken()) {
437
- return;
438
- }
439
- const now = Date.now();
440
- const refreshTime = this.tokens.expiresAt - this.config.refreshBuffer;
441
- const delay = Math.max(0, refreshTime - now);
442
- this.refreshTimeout = setTimeout(async () => {
443
- try {
444
- await this.refreshTokens();
445
- } catch (error) {
446
- console.error("Automatic token refresh failed:", error);
447
- if (this.config.onTokenError) {
448
- this.config.onTokenError(error);
449
- }
450
- }
451
- }, delay);
452
- }
453
- /**
454
- * Save tokens to storage
455
- */
456
- saveTokens() {
457
- try {
458
- const { storage } = this;
459
- const keys = this.storageKeys;
460
- if (this.tokens.accessToken) {
461
- storage.setItem(keys.accessToken, this.tokens.accessToken);
462
- }
463
- if (this.tokens.refreshToken) {
464
- storage.setItem(keys.refreshToken, this.tokens.refreshToken);
465
- }
466
- if (this.tokens.expiresAt) {
467
- storage.setItem(keys.expiresAt, this.tokens.expiresAt.toString());
468
- }
469
- if (this.tokens.expiresIn) {
470
- storage.setItem(keys.expiresIn, this.tokens.expiresIn.toString());
471
- }
472
- } catch (error) {
473
- console.error("[TokenManager] Error saving tokens to storage:", error);
474
- }
475
- }
476
- /**
477
- * Load tokens from storage
478
- */
479
- loadTokens() {
480
- try {
481
- const { storage } = this;
482
- const keys = this.storageKeys;
483
- const accessToken = storage.getItem(keys.accessToken);
484
- const refreshToken = storage.getItem(keys.refreshToken);
485
- const expiresAt = storage.getItem(keys.expiresAt);
486
- const expiresIn = storage.getItem(keys.expiresIn);
487
- if (accessToken) {
488
- this.tokens = {
489
- accessToken,
490
- refreshToken,
491
- expiresAt: expiresAt ? parseInt(expiresAt, 10) : null,
492
- expiresIn: expiresIn ? parseInt(expiresIn, 10) : null,
493
- tokenType: "Bearer"
494
- };
495
- this.scheduleRefresh();
496
- }
497
- } catch (error) {
498
- console.error("[TokenManager] Error loading tokens from storage:", error);
499
- this.tokens = {
500
- accessToken: null,
501
- refreshToken: null,
502
- expiresAt: null,
503
- expiresIn: null
504
- };
505
- }
506
- }
507
- /**
508
- * Clear all tokens
509
- */
510
- clearTokens() {
511
- this.tokens = {
512
- accessToken: null,
513
- refreshToken: null,
514
- expiresAt: null,
515
- expiresIn: null
516
- };
517
- const { storage } = this;
518
- const keys = this.storageKeys;
519
- Object.values(keys).forEach((key) => {
520
- storage.removeItem(key);
521
- });
522
- if (this.refreshTimeout) {
523
- clearTimeout(this.refreshTimeout);
524
- this.refreshTimeout = null;
525
- }
526
- this.retryCount = 0;
527
- }
528
- /**
529
- * Get token status information
530
- */
531
- getTokenStatus() {
532
- const hasTokens = this.hasTokens();
533
- const isValid = this.isAccessTokenValid();
534
- const { expiresAt } = this.tokens;
535
- const timeToExpiry = expiresAt ? expiresAt - Date.now() : null;
536
- return {
537
- hasTokens,
538
- isValid,
539
- hasRefreshToken: this.hasRefreshToken(),
540
- expiresAt,
541
- timeToExpiry,
542
- willExpireSoon: timeToExpiry ? timeToExpiry < this.config.refreshBuffer : false
543
- };
544
- }
545
- /**
546
- * Cleanup resources
547
- */
548
- destroy() {
549
- if (this.refreshTimeout) {
550
- clearTimeout(this.refreshTimeout);
551
- this.refreshTimeout = null;
552
- }
553
- this.refreshPromise = null;
554
- }
555
- };
556
- var defaultTokenManager = null;
557
- var getTokenManager = (options) => {
558
- if (!defaultTokenManager) {
559
- defaultTokenManager = new TokenManager(options);
560
- }
561
- return defaultTokenManager;
562
- };
563
-
564
- // src/services/BaseService.js
565
- var BaseService = class {
566
- constructor({ context, options } = {}) {
567
- this._context = context || {};
568
- this._options = options || {};
569
- this._ready = false;
570
- this._error = null;
571
- this._apiUrl = null;
572
- this._tokenManager = null;
573
- }
574
- // Initialize service
575
- init({ context }) {
576
- try {
577
- const { apiUrl } = context || this._context;
578
- this._apiUrl = apiUrl || environment_default.apiUrl;
579
- if (!this._apiUrl) {
580
- throw new Error("Service base URL not configured");
581
- }
582
- this._tokenManager = getTokenManager({
583
- apiUrl: this._apiUrl,
584
- onTokenError: (error) => {
585
- console.error("Token management error:", error);
586
- }
587
- });
588
- this._setReady();
589
- } catch (error) {
590
- this._setError(error);
591
- throw error;
592
- }
593
- }
594
- // Update context
595
- updateContext(context) {
596
- if (context && typeof context === "object") {
597
- Object.assign(this._context, context);
598
- }
599
- }
600
- // Get service status
601
- getStatus() {
602
- return {
603
- ready: this._ready,
604
- error: this._error,
605
- context: { ...this._context }
606
- };
607
- }
608
- // Check if service is ready
609
- isReady() {
610
- return this._ready;
611
- }
612
- // Protected helper methods
613
- _setReady(ready = true) {
614
- this._ready = ready;
615
- this._error = null;
616
- }
617
- _setError(error) {
618
- this._ready = false;
619
- this._error = error;
620
- }
621
- _requireAuth() {
622
- if (!this._context.authToken) {
623
- throw new Error("Authentication required");
624
- }
625
- }
626
- _requireReady(methodName = "unknown") {
627
- if (!this.isReady()) {
628
- throw new Error(`Service not initialized for method: ${methodName}`);
629
- }
630
- }
631
- // Shared HTTP request method
632
- async _request(endpoint, options = {}) {
633
- const url = `${this._apiUrl}/core${endpoint}`;
634
- const defaultHeaders = {};
635
- if (!(options.body instanceof FormData)) {
636
- defaultHeaders["Content-Type"] = "application/json";
637
- }
638
- if (this._requiresInit(options.methodName) && this._tokenManager) {
639
- try {
640
- const validToken = await this._tokenManager.ensureValidToken();
641
- if (validToken) {
642
- const authHeader = this._tokenManager.getAuthHeader();
643
- if (authHeader) {
644
- defaultHeaders.Authorization = authHeader;
645
- }
646
- }
647
- } catch (error) {
648
- console.warn(
649
- "Token management failed, proceeding without authentication:",
650
- error
651
- );
652
- }
653
- }
654
- try {
655
- const response = await fetch(url, {
656
- ...options,
657
- headers: {
658
- ...defaultHeaders,
659
- ...options.headers
660
- }
661
- });
662
- if (!response.ok) {
663
- let error = {
664
- message: `HTTP ${response.status}: ${response.statusText}`
665
- };
666
- try {
667
- error = await response.json();
668
- } catch {
669
- }
670
- throw new Error(error.message || error.error || "Request failed", { cause: error });
671
- }
672
- return response.status === 204 ? null : response.json();
673
- } catch (error) {
674
- throw new Error(`Request failed: ${error.message}`, { cause: error });
675
- }
676
- }
677
- // Helper method to determine if a method requires initialization
678
- _requiresInit(methodName) {
679
- const noInitMethods = /* @__PURE__ */ new Set([
680
- "register",
681
- "login",
682
- "googleAuth",
683
- "googleAuthCallback",
684
- "githubAuth",
685
- "requestPasswordReset",
686
- "confirmPasswordReset",
687
- "confirmRegistration",
688
- "verifyEmail",
689
- "getPlans",
690
- "getPlan",
691
- "listPublicProjects",
692
- "getPublicProject"
693
- ]);
694
- return !noInitMethods.has(methodName);
695
- }
696
- // Cleanup method
697
- destroy() {
698
- if (this._tokenManager) {
699
- this._tokenManager.destroy();
700
- this._tokenManager = null;
701
- }
702
- this._ready = false;
703
- this._setReady(false);
704
- }
705
- };
706
-
707
- // src/services/ScreenshotService.js
708
- var ScreenshotService = class extends BaseService {
709
- constructor(config) {
710
- super(config);
711
- this._debounceTimers = /* @__PURE__ */ new Map();
712
- this._inflightRefreshes = /* @__PURE__ */ new Map();
713
- }
714
- // ==================== PROJECT-LEVEL OPERATIONS ====================
715
- async createScreenshotProject(payload) {
716
- this._requireReady("createScreenshotProject");
717
- try {
718
- const response = await this._request("/screenshots/projects", {
719
- method: "POST",
720
- body: JSON.stringify(payload),
721
- methodName: "createScreenshotProject"
722
- });
723
- if (response.success) {
724
- return response;
725
- }
726
- throw new Error(response.message);
727
- } catch (error) {
728
- throw new Error(`Failed to create screenshot project: ${error.message}`, { cause: error });
729
- }
730
- }
731
- async getProjectScreenshots(projectKey, params = {}) {
732
- this._requireReady("getProjectScreenshots");
733
- if (!projectKey) {
734
- throw new Error("projectKey is required");
735
- }
736
- const { type = "all", status, limit = 50, offset = 0 } = params;
737
- const qs = new URLSearchParams();
738
- if (type) {
739
- qs.set("type", type);
740
- }
741
- if (status) {
742
- qs.set("status", status);
743
- }
744
- if (limit != null) {
745
- qs.set("limit", String(limit));
746
- }
747
- if (offset != null) {
748
- qs.set("offset", String(offset));
749
- }
750
- try {
751
- const response = await this._request(
752
- `/screenshots/projects/${encodeURIComponent(projectKey)}${qs.toString() ? `?${qs.toString()}` : ""}`,
753
- { method: "GET", methodName: "getProjectScreenshots" }
754
- );
755
- if (response.success) {
756
- return response;
757
- }
758
- throw new Error(response.message);
759
- } catch (error) {
760
- throw new Error(`Failed to get project screenshots: ${error.message}`, { cause: error });
761
- }
762
- }
763
- async reprocessProjectScreenshots(projectKey, body = {}) {
764
- this._requireReady("reprocessProjectScreenshots");
765
- if (!projectKey) {
766
- throw new Error("projectKey is required");
767
- }
768
- try {
769
- const response = await this._request(
770
- `/screenshots/projects/${encodeURIComponent(projectKey)}/reprocess`,
771
- { method: "POST", body: JSON.stringify(body), methodName: "reprocessProjectScreenshots" }
772
- );
773
- if (response.success) {
774
- return response;
775
- }
776
- throw new Error(response.message);
777
- } catch (error) {
778
- throw new Error(`Failed to reprocess screenshots: ${error.message}`, { cause: error });
779
- }
780
- }
781
- async recreateProjectScreenshots(projectKey, body = {}) {
782
- this._requireReady("recreateProjectScreenshots");
783
- if (!projectKey) {
784
- throw new Error("projectKey is required");
785
- }
786
- try {
787
- const response = await this._request(
788
- `/screenshots/projects/${encodeURIComponent(projectKey)}/recreate`,
789
- { method: "POST", body: JSON.stringify(body), methodName: "recreateProjectScreenshots" }
790
- );
791
- if (response.success) {
792
- return response;
793
- }
794
- throw new Error(response.message);
795
- } catch (error) {
796
- throw new Error(`Failed to recreate screenshots: ${error.message}`, { cause: error });
797
- }
798
- }
799
- async deleteProjectScreenshots(projectKey) {
800
- this._requireReady("deleteProjectScreenshots");
801
- if (!projectKey) {
802
- throw new Error("projectKey is required");
803
- }
804
- try {
805
- const response = await this._request(
806
- `/screenshots/projects/${encodeURIComponent(projectKey)}`,
807
- { method: "DELETE", methodName: "deleteProjectScreenshots" }
808
- );
809
- if (response.success) {
810
- return response;
811
- }
812
- throw new Error(response.message);
813
- } catch (error) {
814
- throw new Error(`Failed to delete project screenshots: ${error.message}`, { cause: error });
815
- }
816
- }
817
- // ==================== THUMBNAIL ====================
818
- async getThumbnailCandidate(projectKey, options = {}) {
819
- this._requireReady("getThumbnailCandidate");
820
- if (!projectKey) {
821
- throw new Error("projectKey is required");
822
- }
823
- const { includeData = false } = options;
824
- const qs = new URLSearchParams();
825
- if (includeData) {
826
- qs.set("include_data", "true");
827
- }
828
- try {
829
- const response = await this._request(
830
- `/screenshots/projects/${encodeURIComponent(projectKey)}/thumbnail/candidate${qs.toString() ? `?${qs.toString()}` : ""}`,
831
- { method: "GET", methodName: "getThumbnailCandidate" }
832
- );
833
- if (response.success) {
834
- return response;
835
- }
836
- throw new Error(response.message);
837
- } catch (error) {
838
- throw new Error(`Failed to get thumbnail candidate: ${error.message}`, { cause: error });
839
- }
840
- }
841
- async updateProjectThumbnail(projectKey, body = {}) {
842
- this._requireReady("updateProjectThumbnail");
843
- if (!projectKey) {
844
- throw new Error("projectKey is required");
845
- }
846
- try {
847
- const response = await this._request(
848
- `/screenshots/projects/${encodeURIComponent(projectKey)}/thumbnail`,
849
- { method: "POST", body: JSON.stringify(body), methodName: "updateProjectThumbnail" }
850
- );
851
- if (response.success) {
852
- return response;
853
- }
854
- throw new Error(response.message);
855
- } catch (error) {
856
- throw new Error(`Failed to update project thumbnail: ${error.message}`, { cause: error });
857
- }
858
- }
859
- // ==================== INDIVIDUAL SHOTS ====================
860
- async getPageScreenshot(screenshotId, format = "json") {
861
- this._requireReady("getPageScreenshot");
862
- if (!screenshotId) {
863
- throw new Error("screenshotId is required");
864
- }
865
- const qs = new URLSearchParams();
866
- if (format) {
867
- qs.set("format", format);
868
- }
869
- try {
870
- return await this._request(
871
- `/screenshots/pages/${encodeURIComponent(screenshotId)}${qs.toString() ? `?${qs.toString()}` : ""}`,
872
- { method: "GET", methodName: "getPageScreenshot" }
873
- );
874
- } catch (error) {
875
- throw new Error(`Failed to get page screenshot: ${error.message}`, { cause: error });
876
- }
877
- }
878
- async getComponentScreenshot(screenshotId, format = "json") {
879
- this._requireReady("getComponentScreenshot");
880
- if (!screenshotId) {
881
- throw new Error("screenshotId is required");
882
- }
883
- const qs = new URLSearchParams();
884
- if (format) {
885
- qs.set("format", format);
886
- }
887
- try {
888
- return await this._request(
889
- `/screenshots/components/${encodeURIComponent(screenshotId)}${qs.toString() ? `?${qs.toString()}` : ""}`,
890
- { method: "GET", methodName: "getComponentScreenshot" }
891
- );
892
- } catch (error) {
893
- throw new Error(`Failed to get component screenshot: ${error.message}`, { cause: error });
894
- }
895
- }
896
- async getScreenshotByKey(projectKey, type, key, format = "json") {
897
- this._requireReady("getScreenshotByKey");
898
- if (!projectKey) {
899
- throw new Error("projectKey is required");
900
- }
901
- if (!type || !["component", "page"].includes(String(type))) {
902
- throw new Error("type must be 'component' or 'page'");
903
- }
904
- if (!key) {
905
- throw new Error("key is required");
906
- }
907
- const qs = new URLSearchParams();
908
- if (format) {
909
- qs.set("format", format);
910
- }
911
- const sub = type === "component" ? "components" : "pages";
912
- try {
913
- return await this._request(
914
- `/screenshots/projects/${encodeURIComponent(projectKey)}/${sub}/${encodeURIComponent(key)}${qs.toString() ? `?${qs.toString()}` : ""}`,
915
- { method: "GET", methodName: "getScreenshotByKey" }
916
- );
917
- } catch (error) {
918
- throw new Error(`Failed to get screenshot by key: ${error.message}`, { cause: error });
919
- }
920
- }
921
- async getQueueStatistics() {
922
- this._requireReady("getQueueStatistics");
923
- try {
924
- const response = await this._request("/screenshots/queue/stats", {
925
- method: "GET",
926
- methodName: "getQueueStatistics"
927
- });
928
- if (response.success) {
929
- return response;
930
- }
931
- throw new Error(response.message);
932
- } catch (error) {
933
- throw new Error(`Failed to get queue statistics: ${error.message}`, { cause: error });
934
- }
935
- }
936
- // ==================== COMBINATION/DEBOUNCED ====================
937
- /**
938
- * Debounced thumbnail refresh that recreates screenshots and then updates thumbnail.
939
- * Subsequent calls within debounce window reset the timer.
940
- */
941
- async refreshThumbnail(projectKey, options = {}) {
942
- this._requireReady("refreshThumbnail");
943
- if (!projectKey) {
944
- throw new Error("projectKey is required");
945
- }
946
- const {
947
- debounceMs = 15e3,
948
- waitAfterRecreateMs = 2e4,
949
- recreate = {
950
- process_pages: true,
951
- process_components: true,
952
- process_descriptions: true,
953
- force: false,
954
- priority: 5
955
- },
956
- thumbnail = {
957
- strategy: "auto",
958
- force: true
959
- }
960
- } = options;
961
- const existingTimer = this._debounceTimers.get(projectKey);
962
- if (existingTimer) {
963
- clearTimeout(existingTimer);
964
- }
965
- const executionPromise = await new Promise((resolve) => {
966
- const timer = setTimeout(async () => {
967
- try {
968
- await this.recreateProjectScreenshots(projectKey, recreate);
969
- await new Promise((resolveDelay) => {
970
- setTimeout(resolveDelay, waitAfterRecreateMs);
971
- });
972
- const result = await this.updateProjectThumbnail(projectKey, thumbnail);
973
- resolve(result);
974
- } catch (e) {
975
- resolve({ success: false, error: (e == null ? void 0 : e.message) || String(e) });
976
- } finally {
977
- this._debounceTimers.delete(projectKey);
978
- this._inflightRefreshes.delete(projectKey);
979
- }
980
- }, debounceMs);
981
- this._debounceTimers.set(projectKey, timer);
982
- });
983
- this._inflightRefreshes.set(projectKey, executionPromise);
984
- return executionPromise;
985
- }
986
- };
987
- var ScreenshotService_default = ScreenshotService;
988
- export {
989
- ScreenshotService,
990
- ScreenshotService_default as default
991
- };
992
- // @preserve-env