@symbo.ls/sdk 3.2.3 → 3.2.7

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 (183) hide show
  1. package/README.md +141 -0
  2. package/dist/cjs/config/environment.js +94 -10
  3. package/dist/cjs/index.js +152 -12
  4. package/dist/cjs/services/AdminService.js +351 -0
  5. package/dist/cjs/services/AuthService.js +738 -305
  6. package/dist/cjs/services/BaseService.js +158 -6
  7. package/dist/cjs/services/BranchService.js +484 -0
  8. package/dist/cjs/services/CollabService.js +439 -116
  9. package/dist/cjs/services/DnsService.js +340 -0
  10. package/dist/cjs/services/FeatureFlagService.js +175 -0
  11. package/dist/cjs/services/FileService.js +201 -0
  12. package/dist/cjs/services/IntegrationService.js +538 -0
  13. package/dist/cjs/services/MetricsService.js +62 -0
  14. package/dist/cjs/services/PaymentService.js +271 -0
  15. package/dist/cjs/services/PlanService.js +426 -0
  16. package/dist/cjs/services/ProjectService.js +1207 -0
  17. package/dist/cjs/services/PullRequestService.js +503 -0
  18. package/dist/cjs/services/ScreenshotService.js +304 -0
  19. package/dist/cjs/services/SubscriptionService.js +396 -0
  20. package/dist/cjs/services/TrackingService.js +661 -0
  21. package/dist/cjs/services/WaitlistService.js +148 -0
  22. package/dist/cjs/services/index.js +60 -4
  23. package/dist/cjs/state/RootStateManager.js +2 -23
  24. package/dist/cjs/state/rootEventBus.js +9 -0
  25. package/dist/cjs/utils/CollabClient.js +78 -12
  26. package/dist/cjs/utils/TokenManager.js +16 -3
  27. package/dist/cjs/utils/changePreprocessor.js +199 -0
  28. package/dist/cjs/utils/jsonDiff.js +46 -4
  29. package/dist/cjs/utils/ordering.js +309 -0
  30. package/dist/cjs/utils/services.js +285 -128
  31. package/dist/cjs/utils/validation.js +0 -3
  32. package/dist/esm/config/environment.js +94 -10
  33. package/dist/esm/index.js +47862 -18248
  34. package/dist/esm/services/AdminService.js +1132 -0
  35. package/dist/esm/services/AuthService.js +1493 -386
  36. package/dist/esm/services/BaseService.js +757 -6
  37. package/dist/esm/services/BranchService.js +1265 -0
  38. package/dist/esm/services/CollabService.js +24956 -16089
  39. package/dist/esm/services/DnsService.js +1121 -0
  40. package/dist/esm/services/FeatureFlagService.js +956 -0
  41. package/dist/esm/services/FileService.js +982 -0
  42. package/dist/esm/services/IntegrationService.js +1319 -0
  43. package/dist/esm/services/MetricsService.js +843 -0
  44. package/dist/esm/services/PaymentService.js +1052 -0
  45. package/dist/esm/services/PlanService.js +1207 -0
  46. package/dist/esm/services/ProjectService.js +2526 -0
  47. package/dist/esm/services/PullRequestService.js +1284 -0
  48. package/dist/esm/services/ScreenshotService.js +1085 -0
  49. package/dist/esm/services/SubscriptionService.js +1177 -0
  50. package/dist/esm/services/TrackingService.js +18454 -0
  51. package/dist/esm/services/WaitlistService.js +929 -0
  52. package/dist/esm/services/index.js +47373 -18027
  53. package/dist/esm/state/RootStateManager.js +11 -23
  54. package/dist/esm/state/rootEventBus.js +9 -0
  55. package/dist/esm/utils/CollabClient.js +17526 -16120
  56. package/dist/esm/utils/TokenManager.js +16 -3
  57. package/dist/esm/utils/changePreprocessor.js +542 -0
  58. package/dist/esm/utils/jsonDiff.js +958 -43
  59. package/dist/esm/utils/ordering.js +291 -0
  60. package/dist/esm/utils/services.js +285 -128
  61. package/dist/esm/utils/validation.js +116 -50
  62. package/dist/node/config/environment.js +94 -10
  63. package/dist/node/index.js +183 -16
  64. package/dist/node/services/AdminService.js +332 -0
  65. package/dist/node/services/AuthService.js +742 -310
  66. package/dist/node/services/BaseService.js +148 -6
  67. package/dist/node/services/BranchService.js +465 -0
  68. package/dist/node/services/CollabService.js +439 -116
  69. package/dist/node/services/DnsService.js +321 -0
  70. package/dist/node/services/FeatureFlagService.js +156 -0
  71. package/dist/node/services/FileService.js +182 -0
  72. package/dist/node/services/IntegrationService.js +519 -0
  73. package/dist/node/services/MetricsService.js +43 -0
  74. package/dist/node/services/PaymentService.js +252 -0
  75. package/dist/node/services/PlanService.js +407 -0
  76. package/dist/node/services/ProjectService.js +1188 -0
  77. package/dist/node/services/PullRequestService.js +484 -0
  78. package/dist/node/services/ScreenshotService.js +285 -0
  79. package/dist/node/services/SubscriptionService.js +377 -0
  80. package/dist/node/services/TrackingService.js +632 -0
  81. package/dist/node/services/WaitlistService.js +129 -0
  82. package/dist/node/services/index.js +60 -4
  83. package/dist/node/state/RootStateManager.js +2 -23
  84. package/dist/node/state/rootEventBus.js +9 -0
  85. package/dist/node/utils/CollabClient.js +77 -11
  86. package/dist/node/utils/TokenManager.js +16 -3
  87. package/dist/node/utils/changePreprocessor.js +180 -0
  88. package/dist/node/utils/jsonDiff.js +46 -4
  89. package/dist/node/utils/ordering.js +290 -0
  90. package/dist/node/utils/services.js +285 -128
  91. package/dist/node/utils/validation.js +0 -3
  92. package/package.json +30 -18
  93. package/src/config/environment.js +95 -10
  94. package/src/index.js +190 -23
  95. package/src/services/AdminService.js +374 -0
  96. package/src/services/AuthService.js +874 -328
  97. package/src/services/BaseService.js +166 -6
  98. package/src/services/BranchService.js +536 -0
  99. package/src/services/CollabService.js +557 -148
  100. package/src/services/DnsService.js +366 -0
  101. package/src/services/FeatureFlagService.js +174 -0
  102. package/src/services/FileService.js +213 -0
  103. package/src/services/IntegrationService.js +548 -0
  104. package/src/services/MetricsService.js +40 -0
  105. package/src/services/PaymentService.js +287 -0
  106. package/src/services/PlanService.js +468 -0
  107. package/src/services/ProjectService.js +1366 -0
  108. package/src/services/PullRequestService.js +537 -0
  109. package/src/services/ScreenshotService.js +258 -0
  110. package/src/services/SubscriptionService.js +425 -0
  111. package/src/services/TrackingService.js +853 -0
  112. package/src/services/WaitlistService.js +130 -0
  113. package/src/services/index.js +79 -5
  114. package/src/services/tests/BranchService/createBranch.test.js +153 -0
  115. package/src/services/tests/BranchService/deleteBranch.test.js +173 -0
  116. package/src/services/tests/BranchService/getBranchChanges.test.js +146 -0
  117. package/src/services/tests/BranchService/listBranches.test.js +87 -0
  118. package/src/services/tests/BranchService/mergeBranch.test.js +210 -0
  119. package/src/services/tests/BranchService/publishVersion.test.js +183 -0
  120. package/src/services/tests/BranchService/renameBranch.test.js +240 -0
  121. package/src/services/tests/BranchService/resetBranch.test.js +152 -0
  122. package/src/services/tests/FeatureFlagService/adminFeatureFlags.test.js +67 -0
  123. package/src/services/tests/FeatureFlagService/getFeatureFlags.test.js +75 -0
  124. package/src/services/tests/FileService/createFileFormData.test.js +74 -0
  125. package/src/services/tests/FileService/getFileUrl.test.js +69 -0
  126. package/src/services/tests/FileService/updateProjectIcon.test.js +109 -0
  127. package/src/services/tests/FileService/uploadDocument.test.js +36 -0
  128. package/src/services/tests/FileService/uploadFile.test.js +78 -0
  129. package/src/services/tests/FileService/uploadFileWithValidation.test.js +114 -0
  130. package/src/services/tests/FileService/uploadImage.test.js +36 -0
  131. package/src/services/tests/FileService/uploadMultipleFiles.test.js +111 -0
  132. package/src/services/tests/FileService/validateFile.test.js +63 -0
  133. package/src/services/tests/PlanService/createPlan.test.js +104 -0
  134. package/src/services/tests/PlanService/createPlanWithValidation.test.js +523 -0
  135. package/src/services/tests/PlanService/deletePlan.test.js +92 -0
  136. package/src/services/tests/PlanService/getActivePlans.test.js +123 -0
  137. package/src/services/tests/PlanService/getAdminPlans.test.js +84 -0
  138. package/src/services/tests/PlanService/getPlan.test.js +50 -0
  139. package/src/services/tests/PlanService/getPlanByKey.test.js +109 -0
  140. package/src/services/tests/PlanService/getPlanWithValidation.test.js +85 -0
  141. package/src/services/tests/PlanService/getPlans.test.js +53 -0
  142. package/src/services/tests/PlanService/getPlansByPriceRange.test.js +109 -0
  143. package/src/services/tests/PlanService/getPlansWithValidation.test.js +48 -0
  144. package/src/services/tests/PlanService/initializePlans.test.js +75 -0
  145. package/src/services/tests/PlanService/updatePlan.test.js +111 -0
  146. package/src/services/tests/PlanService/updatePlanWithValidation.test.js +556 -0
  147. package/src/state/RootStateManager.js +37 -32
  148. package/src/state/rootEventBus.js +19 -0
  149. package/src/utils/CollabClient.js +99 -12
  150. package/src/utils/TokenManager.js +20 -3
  151. package/src/utils/changePreprocessor.js +239 -0
  152. package/src/utils/jsonDiff.js +40 -5
  153. package/src/utils/ordering.js +271 -0
  154. package/src/utils/services.js +306 -139
  155. package/src/utils/validation.js +0 -3
  156. package/dist/cjs/services/AIService.js +0 -155
  157. package/dist/cjs/services/BasedService.js +0 -1185
  158. package/dist/cjs/services/CoreService.js +0 -2295
  159. package/dist/cjs/services/SocketService.js +0 -309
  160. package/dist/cjs/services/SymstoryService.js +0 -571
  161. package/dist/cjs/utils/basedQuerys.js +0 -181
  162. package/dist/cjs/utils/symstoryClient.js +0 -259
  163. package/dist/esm/services/AIService.js +0 -185
  164. package/dist/esm/services/BasedService.js +0 -5262
  165. package/dist/esm/services/CoreService.js +0 -2827
  166. package/dist/esm/services/SocketService.js +0 -456
  167. package/dist/esm/services/SymstoryService.js +0 -7025
  168. package/dist/esm/utils/basedQuerys.js +0 -163
  169. package/dist/esm/utils/symstoryClient.js +0 -354
  170. package/dist/node/services/AIService.js +0 -136
  171. package/dist/node/services/BasedService.js +0 -1156
  172. package/dist/node/services/CoreService.js +0 -2266
  173. package/dist/node/services/SocketService.js +0 -280
  174. package/dist/node/services/SymstoryService.js +0 -542
  175. package/dist/node/utils/basedQuerys.js +0 -162
  176. package/dist/node/utils/symstoryClient.js +0 -230
  177. package/src/services/AIService.js +0 -150
  178. package/src/services/BasedService.js +0 -1302
  179. package/src/services/CoreService.js +0 -2548
  180. package/src/services/SocketService.js +0 -336
  181. package/src/services/SymstoryService.js +0 -649
  182. package/src/utils/basedQuerys.js +0 -164
  183. package/src/utils/symstoryClient.js +0 -252
@@ -1,3 +1,613 @@
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
+ // Tracking is enabled by default unless overridden per environment
17
+ trackingEnabled: true
18
+ }
19
+ },
20
+ // Environment-specific configurations
21
+ local: {
22
+ // local
23
+ socketUrl: "http://localhost:8080",
24
+ // For socket api
25
+ apiUrl: "http://localhost:8080",
26
+ // For server api
27
+ basedEnv: "development",
28
+ // For based api
29
+ basedProject: "platform-v2-sm",
30
+ // For based api
31
+ basedOrg: "symbols",
32
+ // For based api
33
+ githubClientId: "Ov23liAFrsR0StbAO6PO",
34
+ // For github api
35
+ grafanaUrl: "",
36
+ // For grafana tracing
37
+ grafanaAppName: "Symbols Localhost",
38
+ // Environment-specific feature toggles (override common)
39
+ features: {
40
+ // Disable tracking by default on localhost/dev machines
41
+ trackingEnabled: false,
42
+ // Enable beta features in local dev
43
+ betaFeatures: true,
44
+ // Preserve common defaults explicitly for local
45
+ newUserOnboarding: true
46
+ },
47
+ typesenseCollectionName: "docs",
48
+ typesenseApiKey: "vZya3L2zpq8L6iI5WWMUZJZABvT63VDb",
49
+ typesenseHost: "localhost",
50
+ typesensePort: "8108",
51
+ typesenseProtocol: "http"
52
+ },
53
+ development: {
54
+ socketUrl: "https://dev.api.symbols.app",
55
+ apiUrl: "https://dev.api.symbols.app",
56
+ githubClientId: "Ov23liHxyWFBxS8f1gnF",
57
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
58
+ // For grafana tracing
59
+ grafanaAppName: "Symbols Dev",
60
+ typesenseCollectionName: "docs",
61
+ typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
62
+ typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
63
+ typesensePort: "443",
64
+ typesenseProtocol: "https"
65
+ },
66
+ testing: {
67
+ socketUrl: "https://test.api.symbols.app",
68
+ apiUrl: "https://test.api.symbols.app",
69
+ basedEnv: "testing",
70
+ basedProject: "platform-v2-sm",
71
+ basedOrg: "symbols",
72
+ githubClientId: "Ov23liHxyWFBxS8f1gnF",
73
+ grafanaUrl: "",
74
+ // For grafana tracing
75
+ grafanaAppName: "Symbols Test",
76
+ typesenseCollectionName: "docs",
77
+ typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
78
+ typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
79
+ typesensePort: "443",
80
+ typesenseProtocol: "https"
81
+ },
82
+ upcoming: {
83
+ socketUrl: "https://upcoming.api.symbols.app",
84
+ apiUrl: "https://upcoming.api.symbols.app",
85
+ githubClientId: "Ov23liWF7NvdZ056RV5J",
86
+ grafanaUrl: "",
87
+ // For grafana tracing
88
+ grafanaAppName: "Symbols Upcoming",
89
+ typesenseCollectionName: "docs",
90
+ typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
91
+ typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
92
+ typesensePort: "443",
93
+ typesenseProtocol: "https"
94
+ },
95
+ staging: {
96
+ socketUrl: "https://staging.api.symbols.app",
97
+ apiUrl: "https://staging.api.symbols.app",
98
+ basedEnv: "staging",
99
+ basedProject: "platform-v2-sm",
100
+ basedOrg: "symbols",
101
+ githubClientId: "Ov23ligwZDQVD0VfuWNa",
102
+ grafanaUrl: "",
103
+ // For grafana tracing
104
+ grafanaAppName: "Symbols Staging",
105
+ typesenseCollectionName: "docs",
106
+ typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
107
+ typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
108
+ typesensePort: "443",
109
+ typesenseProtocol: "https"
110
+ },
111
+ preview: {
112
+ socketUrl: "https://api.symbols.app",
113
+ apiUrl: "https://api.symbols.app",
114
+ basedEnv: "production",
115
+ basedProject: "platform-v2-sm",
116
+ basedOrg: "symbols",
117
+ githubClientId: "Ov23liFAlOEIXtX3dBtR",
118
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/5c1089f3c3eea4ec5658e05c3f53baae",
119
+ // For grafana tracing
120
+ grafanaAppName: "Symbols Preview",
121
+ typesenseCollectionName: "docs",
122
+ typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
123
+ typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
124
+ typesensePort: "443",
125
+ typesenseProtocol: "https"
126
+ },
127
+ production: {
128
+ socketUrl: "https://api.symbols.app",
129
+ apiUrl: "https://api.symbols.app",
130
+ basedEnv: "production",
131
+ basedProject: "platform-v2-sm",
132
+ basedOrg: "symbols",
133
+ githubClientId: "Ov23liFAlOEIXtX3dBtR",
134
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/5c1089f3c3eea4ec5658e05c3f53baae",
135
+ // For grafana tracing
136
+ grafanaAppName: "Symbols",
137
+ typesenseCollectionName: "docs",
138
+ typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
139
+ typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
140
+ typesensePort: "443",
141
+ typesenseProtocol: "https"
142
+ }
143
+ };
144
+ var getEnvironment = () => {
145
+ const env = process.env.SYMBOLS_APP_ENV || process.env.NODE_ENV;
146
+ if (!CONFIG[env]) {
147
+ throw new Error(`Unknown environment "${env}"`);
148
+ }
149
+ return env;
150
+ };
151
+ var getConfig = () => {
152
+ try {
153
+ const env = getEnvironment();
154
+ const envConfig = { ...CONFIG.common, ...CONFIG[env] };
155
+ const finalConfig = {
156
+ ...envConfig,
157
+ // Deep-merge feature flags so env-specific overrides don't drop common defaults
158
+ features: {
159
+ ...CONFIG.common.features || {},
160
+ ...CONFIG[env] && CONFIG[env].features || {}
161
+ },
162
+ socketUrl: process.env.SYMBOLS_APP_SOCKET_URL || envConfig.socketUrl,
163
+ apiUrl: process.env.SYMBOLS_APP_API_URL || envConfig.apiUrl,
164
+ basedEnv: process.env.SYMBOLS_APP_BASED_ENV || envConfig.basedEnv,
165
+ basedProject: process.env.SYMBOLS_APP_BASED_PROJECT || envConfig.basedProject,
166
+ basedOrg: process.env.SYMBOLS_APP_BASED_ORG || envConfig.basedOrg,
167
+ githubClientId: process.env.SYMBOLS_APP_GITHUB_CLIENT_ID || envConfig.githubClientId,
168
+ grafanaUrl: process.env.SYMBOLS_APP_GRAFANA_URL || envConfig.grafanaUrl,
169
+ typesenseCollectionName: process.env.TYPESENSE_COLLECTION_NAME || envConfig.typesenseCollectionName,
170
+ typesenseApiKey: process.env.TYPESENSE_API_KEY || envConfig.typesenseApiKey,
171
+ typesenseHost: process.env.TYPESENSE_HOST || envConfig.typesenseHost,
172
+ typesensePort: process.env.TYPESENSE_PORT || envConfig.typesensePort,
173
+ typesenseProtocol: process.env.TYPESENSE_PROTOCOL || envConfig.typesenseProtocol,
174
+ isDevelopment: isDevelopment(env),
175
+ isTesting: env === "testing",
176
+ isStaging: env === "staging",
177
+ isPreview: env === "preview",
178
+ isProduction: env === "production"
179
+ // Store all environment variables for potential future use
180
+ };
181
+ const requiredFields = [
182
+ "socketUrl",
183
+ "apiUrl",
184
+ "githubClientId",
185
+ "googleClientId"
186
+ ];
187
+ const missingFields = requiredFields.filter((field) => !finalConfig[field]);
188
+ if (missingFields.length > 0) {
189
+ console.error(
190
+ `Missing required configuration: ${missingFields.join(", ")}`
191
+ );
192
+ }
193
+ if (finalConfig.isDevelopment) {
194
+ console.warn(
195
+ "environment in SDK:",
196
+ env || process.env.NODE_ENV || process.env.NODE_ENV
197
+ );
198
+ console.log(finalConfig);
199
+ } else if (global.window) {
200
+ global.window.finalConfig = finalConfig;
201
+ }
202
+ return finalConfig;
203
+ } catch (error) {
204
+ console.error("Failed to load environment configuration:", error);
205
+ return {
206
+ ...CONFIG.development
207
+ };
208
+ }
209
+ };
210
+ var environment_default = getConfig();
211
+
212
+ // src/utils/TokenManager.js
213
+ var TokenManager = class {
214
+ constructor(options = {}) {
215
+ /**
216
+ * Memory storage fallback for server-side rendering
217
+ */
218
+ __publicField(this, "_memoryStorage", {
219
+ _data: {},
220
+ getItem: (key) => this._memoryStorage._data[key] || null,
221
+ setItem: (key, value) => {
222
+ this._memoryStorage._data[key] = value;
223
+ },
224
+ removeItem: (key) => {
225
+ delete this._memoryStorage._data[key];
226
+ },
227
+ clear: () => {
228
+ this._memoryStorage._data = {};
229
+ }
230
+ });
231
+ this.config = {
232
+ storagePrefix: "symbols_",
233
+ storageType: typeof window === "undefined" || process.env.NODE_ENV === "test" || process.env.NODE_ENV === "testing" ? "memory" : "localStorage",
234
+ // 'localStorage' | 'sessionStorage' | 'memory'
235
+ refreshBuffer: 60 * 1e3,
236
+ // Refresh 1 minute before expiry
237
+ maxRetries: 3,
238
+ apiUrl: options.apiUrl || "/api",
239
+ onTokenRefresh: options.onTokenRefresh || null,
240
+ onTokenExpired: options.onTokenExpired || null,
241
+ onTokenError: options.onTokenError || null,
242
+ ...options
243
+ };
244
+ this.tokens = {
245
+ accessToken: null,
246
+ refreshToken: null,
247
+ expiresAt: null,
248
+ expiresIn: null
249
+ };
250
+ this.refreshPromise = null;
251
+ this.refreshTimeout = null;
252
+ this.retryCount = 0;
253
+ this.loadTokens();
254
+ }
255
+ /**
256
+ * Storage keys
257
+ */
258
+ get storageKeys() {
259
+ return {
260
+ accessToken: `${this.config.storagePrefix}access_token`,
261
+ refreshToken: `${this.config.storagePrefix}refresh_token`,
262
+ expiresAt: `${this.config.storagePrefix}expires_at`,
263
+ expiresIn: `${this.config.storagePrefix}expires_in`
264
+ };
265
+ }
266
+ /**
267
+ * Get storage instance based on configuration
268
+ */
269
+ get storage() {
270
+ if (typeof window === "undefined") {
271
+ return this._memoryStorage;
272
+ }
273
+ const safeGetStorage = (provider) => {
274
+ try {
275
+ const storage = provider();
276
+ const testKey = `${this.config.storagePrefix}__tm_test__`;
277
+ storage.setItem(testKey, "1");
278
+ storage.removeItem(testKey);
279
+ return storage;
280
+ } catch {
281
+ return null;
282
+ }
283
+ };
284
+ const localStorageInstance = safeGetStorage(() => window.localStorage);
285
+ const sessionStorageInstance = safeGetStorage(() => window.sessionStorage);
286
+ switch (this.config.storageType) {
287
+ case "sessionStorage":
288
+ return sessionStorageInstance || this._memoryStorage;
289
+ case "memory":
290
+ return this._memoryStorage;
291
+ default:
292
+ return localStorageInstance || this._memoryStorage;
293
+ }
294
+ }
295
+ /**
296
+ * Set tokens and persist to storage
297
+ */
298
+ setTokens(tokenData) {
299
+ const {
300
+ access_token: accessToken,
301
+ refresh_token: refreshToken,
302
+ expires_in: expiresIn,
303
+ token_type: tokenType = "Bearer"
304
+ } = tokenData;
305
+ if (!accessToken) {
306
+ throw new Error("Access token is required");
307
+ }
308
+ const now = Date.now();
309
+ const expiresAt = expiresIn ? now + expiresIn * 1e3 : null;
310
+ this.tokens = {
311
+ accessToken,
312
+ refreshToken: refreshToken || this.tokens.refreshToken,
313
+ expiresAt,
314
+ expiresIn,
315
+ tokenType
316
+ };
317
+ this.saveTokens();
318
+ this.scheduleRefresh();
319
+ if (this.config.onTokenRefresh) {
320
+ this.config.onTokenRefresh(this.tokens);
321
+ }
322
+ return this.tokens;
323
+ }
324
+ /**
325
+ * Get current access token
326
+ */
327
+ getAccessToken() {
328
+ return this.tokens.accessToken;
329
+ }
330
+ /**
331
+ * Get current refresh token
332
+ */
333
+ getRefreshToken() {
334
+ return this.tokens.refreshToken;
335
+ }
336
+ /**
337
+ * Get authorization header value
338
+ */
339
+ getAuthHeader() {
340
+ const token = this.getAccessToken();
341
+ if (!token) {
342
+ return null;
343
+ }
344
+ return `${this.tokens.tokenType || "Bearer"} ${token}`;
345
+ }
346
+ /**
347
+ * Check if access token is valid and not expired
348
+ */
349
+ isAccessTokenValid() {
350
+ if (!this.tokens.accessToken) {
351
+ return false;
352
+ }
353
+ if (!this.tokens.expiresAt) {
354
+ return true;
355
+ }
356
+ const now = Date.now();
357
+ const isValid = now < this.tokens.expiresAt - this.config.refreshBuffer;
358
+ if (!isValid) {
359
+ console.log("[TokenManager] Access token is expired or near expiry:", {
360
+ now: new Date(now).toISOString(),
361
+ expiresAt: new Date(this.tokens.expiresAt).toISOString(),
362
+ refreshBuffer: this.config.refreshBuffer
363
+ });
364
+ }
365
+ return isValid;
366
+ }
367
+ /**
368
+ * Check if access token exists and is not expired (without refresh buffer)
369
+ */
370
+ isAccessTokenActuallyValid() {
371
+ if (!this.tokens.accessToken) {
372
+ return false;
373
+ }
374
+ if (!this.tokens.expiresAt) {
375
+ return true;
376
+ }
377
+ const now = Date.now();
378
+ return now < this.tokens.expiresAt;
379
+ }
380
+ /**
381
+ * Check if tokens exist (regardless of expiry)
382
+ */
383
+ hasTokens() {
384
+ return Boolean(this.tokens.accessToken);
385
+ }
386
+ /**
387
+ * Check if refresh token exists
388
+ */
389
+ hasRefreshToken() {
390
+ return Boolean(this.tokens.refreshToken);
391
+ }
392
+ /**
393
+ * Automatically refresh tokens if needed
394
+ */
395
+ async ensureValidToken() {
396
+ if (!this.hasTokens()) {
397
+ return null;
398
+ }
399
+ if (this.isAccessTokenValid()) {
400
+ return this.getAccessToken();
401
+ }
402
+ if (!this.hasRefreshToken()) {
403
+ this.clearTokens();
404
+ if (this.config.onTokenExpired) {
405
+ this.config.onTokenExpired();
406
+ }
407
+ return null;
408
+ }
409
+ try {
410
+ await this.refreshTokens();
411
+ return this.getAccessToken();
412
+ } catch (error) {
413
+ this.clearTokens();
414
+ if (this.config.onTokenError) {
415
+ this.config.onTokenError(error);
416
+ }
417
+ throw error;
418
+ }
419
+ }
420
+ /**
421
+ * Refresh access token using refresh token
422
+ */
423
+ async refreshTokens() {
424
+ if (this.refreshPromise) {
425
+ return this.refreshPromise;
426
+ }
427
+ if (!this.hasRefreshToken()) {
428
+ throw new Error("No refresh token available");
429
+ }
430
+ if (this.retryCount >= this.config.maxRetries) {
431
+ throw new Error("Max refresh retries exceeded");
432
+ }
433
+ this.refreshPromise = this._performRefresh();
434
+ try {
435
+ const result = await this.refreshPromise;
436
+ this.retryCount = 0;
437
+ return result;
438
+ } catch (error) {
439
+ this.retryCount++;
440
+ throw error;
441
+ } finally {
442
+ this.refreshPromise = null;
443
+ }
444
+ }
445
+ /**
446
+ * Perform the actual token refresh request
447
+ */
448
+ async _performRefresh() {
449
+ var _a;
450
+ const refreshToken = this.getRefreshToken();
451
+ const response = await fetch(`${this.config.apiUrl}/core/auth/refresh`, {
452
+ method: "POST",
453
+ headers: {
454
+ "Content-Type": "application/json"
455
+ },
456
+ body: JSON.stringify({ refreshToken })
457
+ });
458
+ if (!response.ok) {
459
+ const errorData = await response.json().catch(() => ({}));
460
+ throw new Error(errorData.message || `Token refresh failed: ${response.status}`);
461
+ }
462
+ const responseData = await response.json();
463
+ if (responseData.success && responseData.data && responseData.data.tokens) {
464
+ const { tokens } = responseData.data;
465
+ const tokenData = {
466
+ access_token: tokens.accessToken,
467
+ refresh_token: tokens.refreshToken,
468
+ expires_in: (_a = tokens.accessTokenExp) == null ? void 0 : _a.expiresIn,
469
+ token_type: "Bearer"
470
+ };
471
+ return this.setTokens(tokenData);
472
+ }
473
+ return this.setTokens(responseData);
474
+ }
475
+ /**
476
+ * Schedule automatic token refresh
477
+ */
478
+ scheduleRefresh() {
479
+ if (this.refreshTimeout) {
480
+ clearTimeout(this.refreshTimeout);
481
+ this.refreshTimeout = null;
482
+ }
483
+ if (!this.tokens.expiresAt || !this.hasRefreshToken()) {
484
+ return;
485
+ }
486
+ const now = Date.now();
487
+ const refreshTime = this.tokens.expiresAt - this.config.refreshBuffer;
488
+ const delay = Math.max(0, refreshTime - now);
489
+ this.refreshTimeout = setTimeout(async () => {
490
+ try {
491
+ await this.refreshTokens();
492
+ } catch (error) {
493
+ console.error("Automatic token refresh failed:", error);
494
+ if (this.config.onTokenError) {
495
+ this.config.onTokenError(error);
496
+ }
497
+ }
498
+ }, delay);
499
+ }
500
+ /**
501
+ * Save tokens to storage
502
+ */
503
+ saveTokens() {
504
+ try {
505
+ const { storage } = this;
506
+ const keys = this.storageKeys;
507
+ if (this.tokens.accessToken) {
508
+ storage.setItem(keys.accessToken, this.tokens.accessToken);
509
+ }
510
+ if (this.tokens.refreshToken) {
511
+ storage.setItem(keys.refreshToken, this.tokens.refreshToken);
512
+ }
513
+ if (this.tokens.expiresAt) {
514
+ storage.setItem(keys.expiresAt, this.tokens.expiresAt.toString());
515
+ }
516
+ if (this.tokens.expiresIn) {
517
+ storage.setItem(keys.expiresIn, this.tokens.expiresIn.toString());
518
+ }
519
+ } catch (error) {
520
+ console.error("[TokenManager] Error saving tokens to storage:", error);
521
+ }
522
+ }
523
+ /**
524
+ * Load tokens from storage
525
+ */
526
+ loadTokens() {
527
+ try {
528
+ const { storage } = this;
529
+ const keys = this.storageKeys;
530
+ const accessToken = storage.getItem(keys.accessToken);
531
+ const refreshToken = storage.getItem(keys.refreshToken);
532
+ const expiresAt = storage.getItem(keys.expiresAt);
533
+ const expiresIn = storage.getItem(keys.expiresIn);
534
+ if (accessToken) {
535
+ this.tokens = {
536
+ accessToken,
537
+ refreshToken,
538
+ expiresAt: expiresAt ? parseInt(expiresAt, 10) : null,
539
+ expiresIn: expiresIn ? parseInt(expiresIn, 10) : null,
540
+ tokenType: "Bearer"
541
+ };
542
+ this.scheduleRefresh();
543
+ }
544
+ } catch (error) {
545
+ console.error("[TokenManager] Error loading tokens from storage:", error);
546
+ this.tokens = {
547
+ accessToken: null,
548
+ refreshToken: null,
549
+ expiresAt: null,
550
+ expiresIn: null
551
+ };
552
+ }
553
+ }
554
+ /**
555
+ * Clear all tokens
556
+ */
557
+ clearTokens() {
558
+ this.tokens = {
559
+ accessToken: null,
560
+ refreshToken: null,
561
+ expiresAt: null,
562
+ expiresIn: null
563
+ };
564
+ const { storage } = this;
565
+ const keys = this.storageKeys;
566
+ Object.values(keys).forEach((key) => {
567
+ storage.removeItem(key);
568
+ });
569
+ if (this.refreshTimeout) {
570
+ clearTimeout(this.refreshTimeout);
571
+ this.refreshTimeout = null;
572
+ }
573
+ this.retryCount = 0;
574
+ }
575
+ /**
576
+ * Get token status information
577
+ */
578
+ getTokenStatus() {
579
+ const hasTokens = this.hasTokens();
580
+ const isValid = this.isAccessTokenValid();
581
+ const { expiresAt } = this.tokens;
582
+ const timeToExpiry = expiresAt ? expiresAt - Date.now() : null;
583
+ return {
584
+ hasTokens,
585
+ isValid,
586
+ hasRefreshToken: this.hasRefreshToken(),
587
+ expiresAt,
588
+ timeToExpiry,
589
+ willExpireSoon: timeToExpiry ? timeToExpiry < this.config.refreshBuffer : false
590
+ };
591
+ }
592
+ /**
593
+ * Cleanup resources
594
+ */
595
+ destroy() {
596
+ if (this.refreshTimeout) {
597
+ clearTimeout(this.refreshTimeout);
598
+ this.refreshTimeout = null;
599
+ }
600
+ this.refreshPromise = null;
601
+ }
602
+ };
603
+ var defaultTokenManager = null;
604
+ var getTokenManager = (options) => {
605
+ if (!defaultTokenManager) {
606
+ defaultTokenManager = new TokenManager(options);
607
+ }
608
+ return defaultTokenManager;
609
+ };
610
+
1
611
  // src/services/BaseService.js
2
612
  var BaseService = class {
3
613
  constructor({ context, options } = {}) {
@@ -5,14 +615,34 @@ var BaseService = class {
5
615
  this._options = options || {};
6
616
  this._ready = false;
7
617
  this._error = null;
618
+ this._apiUrl = null;
619
+ this._tokenManager = null;
8
620
  }
9
621
  // Initialize service
10
- init() {
11
- throw new Error("init() must be implemented by service");
622
+ init({ context }) {
623
+ try {
624
+ const { apiUrl } = context || this._context;
625
+ this._apiUrl = apiUrl || environment_default.apiUrl;
626
+ if (!this._apiUrl) {
627
+ throw new Error("Service base URL not configured");
628
+ }
629
+ this._tokenManager = getTokenManager({
630
+ apiUrl: this._apiUrl,
631
+ onTokenError: (error) => {
632
+ console.error("Token management error:", error);
633
+ }
634
+ });
635
+ this._setReady();
636
+ } catch (error) {
637
+ this._setError(error);
638
+ throw error;
639
+ }
12
640
  }
13
641
  // Update context
14
642
  updateContext(context) {
15
- this._context = { ...this._context, ...context };
643
+ if (context && typeof context === "object") {
644
+ Object.assign(this._context, context);
645
+ }
16
646
  }
17
647
  // Get service status
18
648
  getStatus() {
@@ -35,96 +665,139 @@ var BaseService = class {
35
665
  this._ready = false;
36
666
  this._error = error;
37
667
  }
668
+ _getTrackingService() {
669
+ var _a;
670
+ const services = (_a = this._context) == null ? void 0 : _a.services;
671
+ const tracking = services == null ? void 0 : services.tracking;
672
+ if (!tracking || typeof tracking.trackError !== "function") {
673
+ return null;
674
+ }
675
+ return tracking;
676
+ }
677
+ _shouldTrackErrors() {
678
+ var _a;
679
+ const name = (_a = this == null ? void 0 : this.constructor) == null ? void 0 : _a.name;
680
+ return name !== "TrackingService";
681
+ }
682
+ _trackServiceError(error, details = {}) {
683
+ var _a;
684
+ if (!this._shouldTrackErrors()) {
685
+ return;
686
+ }
687
+ try {
688
+ const tracking = this._getTrackingService();
689
+ if (!tracking) {
690
+ return;
691
+ }
692
+ const context = {
693
+ service: ((_a = this == null ? void 0 : this.constructor) == null ? void 0 : _a.name) || "UnknownService",
694
+ apiUrl: this._apiUrl || null,
695
+ ...details
696
+ };
697
+ tracking.trackError(error instanceof Error ? error : new Error(String(error)), context);
698
+ } catch {
699
+ }
700
+ }
38
701
  _requireAuth() {
39
- if (!this._context.authToken) {
702
+ if (!this.getAuthToken()) {
40
703
  throw new Error("Authentication required");
41
704
  }
42
705
  }
43
- _requireReady() {
706
+ _requireReady(methodName = "unknown") {
44
707
  if (!this.isReady()) {
45
- throw new Error("Service not initialized");
708
+ throw new Error(`Service not initialized for method: ${methodName}`);
709
+ }
710
+ }
711
+ // Shared HTTP request method
712
+ async _request(endpoint, options = {}) {
713
+ const url = `${this._apiUrl}/core${endpoint}`;
714
+ const defaultHeaders = {};
715
+ if (!(options.body instanceof FormData)) {
716
+ defaultHeaders["Content-Type"] = "application/json";
717
+ }
718
+ if (this._requiresInit(options.methodName) && this._tokenManager) {
719
+ try {
720
+ const validToken = await this._tokenManager.ensureValidToken();
721
+ if (validToken) {
722
+ const authHeader = this._tokenManager.getAuthHeader();
723
+ if (authHeader) {
724
+ defaultHeaders.Authorization = authHeader;
725
+ }
726
+ }
727
+ } catch (error) {
728
+ console.warn(
729
+ "Token management failed, proceeding without authentication:",
730
+ error
731
+ );
732
+ }
733
+ }
734
+ try {
735
+ const response = await fetch(url, {
736
+ ...options,
737
+ headers: {
738
+ ...defaultHeaders,
739
+ ...options.headers
740
+ }
741
+ });
742
+ if (!response.ok) {
743
+ let error = {
744
+ message: `HTTP ${response.status}: ${response.statusText}`
745
+ };
746
+ try {
747
+ error = await response.json();
748
+ } catch {
749
+ }
750
+ this._trackServiceError(
751
+ new Error(error.message || error.error || `HTTP ${response.status}: ${response.statusText}`),
752
+ {
753
+ endpoint,
754
+ methodName: options.methodName,
755
+ status: response.status,
756
+ statusText: response.statusText
757
+ }
758
+ );
759
+ throw new Error(error.message || error.error || "Request failed", { cause: error });
760
+ }
761
+ return response.status === 204 ? null : response.json();
762
+ } catch (error) {
763
+ this._trackServiceError(error, {
764
+ endpoint,
765
+ methodName: options.methodName
766
+ });
767
+ throw new Error(`Request failed: ${error.message}`, { cause: error });
46
768
  }
47
769
  }
770
+ // Helper method to determine if a method requires initialization
771
+ _requiresInit(methodName) {
772
+ const noInitMethods = /* @__PURE__ */ new Set([
773
+ "register",
774
+ "login",
775
+ "googleAuth",
776
+ "googleAuthCallback",
777
+ "githubAuth",
778
+ "requestPasswordReset",
779
+ "confirmPasswordReset",
780
+ "confirmRegistration",
781
+ "verifyEmail",
782
+ "getPlans",
783
+ "getPlan",
784
+ "listPublicProjects",
785
+ "getPublicProject"
786
+ ]);
787
+ return !noInitMethods.has(methodName);
788
+ }
789
+ // Cleanup method
790
+ destroy() {
791
+ if (this._tokenManager) {
792
+ this._tokenManager.destroy();
793
+ this._tokenManager = null;
794
+ }
795
+ this._ready = false;
796
+ this._setReady(false);
797
+ }
48
798
  };
49
799
 
50
800
  // src/utils/permission.js
51
- var PERMISSION_MAP = {
52
- // Content & Design Operations
53
- edit: {
54
- permissions: ["editMode", "showCode"],
55
- features: ["editMode"]
56
- },
57
- view: {
58
- permissions: ["showContent", "platformSettings"],
59
- features: ["canvasPages"]
60
- },
61
- design: {
62
- permissions: ["editMode", "showCode"],
63
- features: ["accessToSymbolsLibrary", "marketplace"]
64
- },
65
- // Project Management
66
- manage: {
67
- permissions: ["projectSettings", "iam"],
68
- features: ["workspaceAdministration", "teamRolesAndPermissions"]
69
- },
70
- configure: {
71
- permissions: ["projectSettings", "branchProtection"],
72
- features: ["customBackendIntegration", "integrationsSDK"]
73
- },
74
- invite: {
75
- permissions: ["inviteMembers"],
76
- features: ["inviteMembersIAM"]
77
- },
78
- // Version Control
79
- branch: {
80
- permissions: ["versions", "branchProtection"],
81
- features: ["branching", "versionHistory"]
82
- },
83
- merge: {
84
- permissions: ["versions", "branchProtection"],
85
- features: ["branching"]
86
- },
87
- // Export & Integration
88
- export: {
89
- permissions: ["showCode"],
90
- features: ["downloadAsSVG", "downloadAsReact", "exportToFigma"]
91
- },
92
- import: {
93
- permissions: ["editMode"],
94
- features: ["importFromFigma"]
95
- },
96
- // AI Features
97
- aiCopilot: {
98
- permissions: ["editMode"],
99
- features: ["aiCopilot:3", "aiCopilot:5", "aiCopilot:15"]
100
- },
101
- aiChatbot: {
102
- permissions: ["showContent"],
103
- features: ["aiChatbot:3", "aiChatbot:5", "aiChatbot:15"]
104
- },
105
- // Advanced Features
106
- analytics: {
107
- permissions: ["projectSettings"],
108
- features: ["analytics", "crashalytics"]
109
- },
110
- payment: {
111
- permissions: ["projectSettings", "iam"],
112
- features: ["stripeConnect"]
113
- },
114
- deployment: {
115
- permissions: ["projectSettings"],
116
- features: ["dompilerCloud", "customDomain"]
117
- },
118
- // Documentation & Sharing
119
- docs: {
120
- permissions: ["showContent"],
121
- features: ["autoDesignDocs"]
122
- },
123
- share: {
124
- permissions: ["inviteMembers"],
125
- features: ["sharing", "sharedLibraries"]
126
- }
127
- };
128
801
  var ROLE_PERMISSIONS = {
129
802
  guest: ["viewPublicProjects"],
130
803
  user: ["viewPublicProjects"],
@@ -261,187 +934,742 @@ var PROJECT_ROLE_PERMISSIONS = {
261
934
  };
262
935
 
263
936
  // src/services/AuthService.js
937
+ var PLUGIN_SESSION_STORAGE_KEY = "plugin_auth_session";
264
938
  var AuthService = class extends BaseService {
265
939
  constructor(config) {
940
+ var _a, _b;
266
941
  super(config);
267
942
  this._userRoles = /* @__PURE__ */ new Set(["guest", "editor", "admin", "owner"]);
268
943
  this._projectTiers = /* @__PURE__ */ new Set([
269
944
  "ready",
270
- "free",
945
+ "starter",
271
946
  "pro1",
272
947
  "pro2",
273
948
  "enterprise"
274
949
  ]);
275
- this._initialized = false;
950
+ this._projectRoleCache = /* @__PURE__ */ new Map();
951
+ this._roleCacheExpiry = 5 * 60 * 1e3;
952
+ this._pluginSession = null;
953
+ this._resolvePluginSession(
954
+ (config == null ? void 0 : config.session) || (config == null ? void 0 : config.pluginSession) || ((_a = config == null ? void 0 : config.options) == null ? void 0 : _a.pluginSession) || ((_b = config == null ? void 0 : config.context) == null ? void 0 : _b.pluginSession) || null
955
+ );
276
956
  }
277
- // eslint-disable-next-line no-empty-pattern
278
- init({}) {
957
+ // Use BaseService.init/_request/_requireReady implementations
958
+ // ==================== AUTH METHODS ====================
959
+ async register(userData, options = {}) {
279
960
  try {
280
- const { authToken, appKey } = this._context || {};
281
- this._info = {
282
- config: {
283
- appKey: appKey ? `${appKey.substr(0, 4)}...${appKey.substr(-4)}` : void 0,
284
- // eslint-disable-line no-undefined
285
- hasToken: Boolean(authToken)
961
+ const { payload, session } = this._preparePluginPayload(
962
+ { ...userData || {} },
963
+ options.session
964
+ );
965
+ const response = await this._request("/auth/register", {
966
+ method: "POST",
967
+ body: JSON.stringify(payload),
968
+ methodName: "register"
969
+ });
970
+ if (response.success) {
971
+ if (session) {
972
+ this._clearPluginSession(session);
286
973
  }
287
- };
288
- this._initialized = true;
289
- this._setReady();
974
+ return response.data;
975
+ }
976
+ throw new Error(response.message);
290
977
  } catch (error) {
291
- this._setError(error);
292
- throw error;
978
+ throw new Error(`Registration failed: ${error.message}`, { cause: error });
293
979
  }
294
980
  }
295
- _requiresInit(methodName) {
296
- const noInitMethods = /* @__PURE__ */ new Set([
297
- "users:login",
298
- "users:register",
299
- "users:request-password-reset",
300
- "users:reset-password",
301
- "users:reset-password-confirm",
302
- "users:register-confirmation",
303
- "users:google-auth",
304
- "users:github-auth"
305
- ]);
306
- return !noInitMethods.has(methodName);
981
+ async login(email, password, options = {}) {
982
+ var _a;
983
+ try {
984
+ const { payload, session } = this._preparePluginPayload(
985
+ {
986
+ email,
987
+ password
988
+ },
989
+ options.session
990
+ );
991
+ const response = await this._request("/auth/login", {
992
+ method: "POST",
993
+ body: JSON.stringify(payload),
994
+ methodName: "login"
995
+ });
996
+ if (response.success && response.data && response.data.tokens) {
997
+ const { tokens } = response.data;
998
+ const tokenData = {
999
+ access_token: tokens.accessToken,
1000
+ refresh_token: tokens.refreshToken,
1001
+ expires_in: (_a = tokens.accessTokenExp) == null ? void 0 : _a.expiresIn,
1002
+ token_type: "Bearer"
1003
+ };
1004
+ if (this._tokenManager) {
1005
+ this._tokenManager.setTokens(tokenData);
1006
+ }
1007
+ }
1008
+ if (response.success) {
1009
+ if (session) {
1010
+ this._clearPluginSession(session);
1011
+ }
1012
+ return response.data;
1013
+ }
1014
+ throw new Error(response.message);
1015
+ } catch (error) {
1016
+ throw new Error(`Login failed: ${error.message}`, { cause: error });
1017
+ }
1018
+ }
1019
+ async logout() {
1020
+ this._requireReady("logout");
1021
+ try {
1022
+ await this._request("/auth/logout", {
1023
+ method: "POST",
1024
+ methodName: "logout"
1025
+ });
1026
+ if (this._tokenManager) {
1027
+ this._tokenManager.clearTokens();
1028
+ }
1029
+ } catch (error) {
1030
+ if (this._tokenManager) {
1031
+ this._tokenManager.clearTokens();
1032
+ }
1033
+ throw new Error(`Logout failed: ${error.message}`, { cause: error });
1034
+ }
307
1035
  }
308
- _requireReady(methodName) {
309
- if (this._requiresInit(methodName) && !this._initialized) {
310
- throw new Error("Service not initialized");
1036
+ async refreshToken(refreshToken) {
1037
+ try {
1038
+ const response = await this._request("/auth/refresh", {
1039
+ method: "POST",
1040
+ body: JSON.stringify({ refreshToken }),
1041
+ methodName: "refreshToken"
1042
+ });
1043
+ if (response.success) {
1044
+ return response.data;
1045
+ }
1046
+ throw new Error(response.message);
1047
+ } catch (error) {
1048
+ throw new Error(`Token refresh failed: ${error.message}`, { cause: error });
1049
+ }
1050
+ }
1051
+ async googleAuth(idToken, inviteToken = null, options = {}) {
1052
+ var _a;
1053
+ try {
1054
+ const { payload, session } = this._preparePluginPayload({ idToken }, options.session);
1055
+ if (inviteToken) {
1056
+ payload.inviteToken = inviteToken;
1057
+ }
1058
+ const response = await this._request("/auth/google", {
1059
+ method: "POST",
1060
+ body: JSON.stringify(payload),
1061
+ methodName: "googleAuth"
1062
+ });
1063
+ if (response.success && response.data && response.data.tokens) {
1064
+ const { tokens } = response.data;
1065
+ const tokenData = {
1066
+ access_token: tokens.accessToken,
1067
+ refresh_token: tokens.refreshToken,
1068
+ expires_in: (_a = tokens.accessTokenExp) == null ? void 0 : _a.expiresIn,
1069
+ token_type: "Bearer"
1070
+ };
1071
+ if (this._tokenManager) {
1072
+ this._tokenManager.setTokens(tokenData);
1073
+ }
1074
+ }
1075
+ if (response.success) {
1076
+ if (session) {
1077
+ this._clearPluginSession(session);
1078
+ }
1079
+ return response.data;
1080
+ }
1081
+ throw new Error(response.message);
1082
+ } catch (error) {
1083
+ throw new Error(`Google auth failed: ${error.message}`, { cause: error });
1084
+ }
1085
+ }
1086
+ async githubAuth(code, inviteToken = null, options = {}) {
1087
+ var _a;
1088
+ try {
1089
+ const { payload, session } = this._preparePluginPayload({ code }, options.session);
1090
+ if (inviteToken) {
1091
+ payload.inviteToken = inviteToken;
1092
+ }
1093
+ const response = await this._request("/auth/github", {
1094
+ method: "POST",
1095
+ body: JSON.stringify(payload),
1096
+ methodName: "githubAuth"
1097
+ });
1098
+ if (response.success && response.data && response.data.tokens) {
1099
+ const { tokens } = response.data;
1100
+ const tokenData = {
1101
+ access_token: tokens.accessToken,
1102
+ refresh_token: tokens.refreshToken,
1103
+ expires_in: (_a = tokens.accessTokenExp) == null ? void 0 : _a.expiresIn,
1104
+ token_type: "Bearer"
1105
+ };
1106
+ if (this._tokenManager) {
1107
+ this._tokenManager.setTokens(tokenData);
1108
+ }
1109
+ }
1110
+ if (response.success) {
1111
+ if (session) {
1112
+ this._clearPluginSession(session);
1113
+ }
1114
+ return response.data;
1115
+ }
1116
+ throw new Error(response.message);
1117
+ } catch (error) {
1118
+ throw new Error(`GitHub auth failed: ${error.message}`, { cause: error });
311
1119
  }
312
1120
  }
313
- _getBasedService(methodName) {
1121
+ async googleAuthCallback(code, redirectUri, inviteToken = null, options = {}) {
314
1122
  var _a;
315
- const based = (_a = this._context.services) == null ? void 0 : _a.based;
316
- if (this._requiresInit(methodName) && !based) {
317
- throw new Error("Based service not available");
1123
+ try {
1124
+ const { payload: body, session } = this._preparePluginPayload(
1125
+ { code, redirectUri },
1126
+ options.session
1127
+ );
1128
+ if (inviteToken) {
1129
+ body.inviteToken = inviteToken;
1130
+ }
1131
+ const response = await this._request("/auth/google/callback", {
1132
+ method: "POST",
1133
+ body: JSON.stringify(body),
1134
+ methodName: "googleAuthCallback"
1135
+ });
1136
+ if (response.success && response.data && response.data.tokens) {
1137
+ const { tokens } = response.data;
1138
+ const tokenData = {
1139
+ access_token: tokens.accessToken,
1140
+ refresh_token: tokens.refreshToken,
1141
+ expires_in: (_a = tokens.accessTokenExp) == null ? void 0 : _a.expiresIn,
1142
+ token_type: "Bearer"
1143
+ };
1144
+ if (this._tokenManager) {
1145
+ this._tokenManager.setTokens(tokenData);
1146
+ }
1147
+ }
1148
+ if (response.success) {
1149
+ if (session) {
1150
+ this._clearPluginSession(session);
1151
+ }
1152
+ return response.data;
1153
+ }
1154
+ throw new Error(response.message);
1155
+ } catch (error) {
1156
+ throw new Error(`Google auth callback failed: ${error.message}`, { cause: error });
318
1157
  }
319
- return based._client;
320
1158
  }
321
- async login(identifier, password) {
1159
+ async requestPasswordReset(email) {
322
1160
  try {
323
- const based = this._getBasedService("login");
324
- const response = await based.call("users:login", { identifier, password });
325
- if (this._initialized) {
326
- this.updateContext({ authToken: response.token });
327
- }
328
- based.setAuthState({
329
- token: response.token,
330
- userId: response.userId,
331
- projectRoles: response.projectRoles,
332
- globalRole: response.globalRole,
333
- persistent: true
1161
+ const response = await this._request("/auth/request-password-reset", {
1162
+ method: "POST",
1163
+ body: JSON.stringify({ email }),
1164
+ methodName: "requestPasswordReset"
334
1165
  });
335
- return response;
1166
+ if (response.success) {
1167
+ return response.data;
1168
+ }
1169
+ throw new Error(response.message);
336
1170
  } catch (error) {
337
- throw new Error(`Login failed: ${error.message}`);
1171
+ throw new Error(`Password reset request failed: ${error.message}`, { cause: error });
338
1172
  }
339
1173
  }
340
- async register(userData) {
1174
+ async confirmPasswordReset(token, password) {
341
1175
  try {
342
- const based = this._getBasedService("register");
343
- return await based.call("users:register", userData);
1176
+ const response = await this._request("/auth/reset-password-confirm", {
1177
+ method: "POST",
1178
+ body: JSON.stringify({ token, password }),
1179
+ methodName: "confirmPasswordReset"
1180
+ });
1181
+ if (response.success) {
1182
+ return response.data;
1183
+ }
1184
+ throw new Error(response.message);
344
1185
  } catch (error) {
345
- throw new Error(`Registration failed: ${error.message}`);
1186
+ throw new Error(`Password reset confirmation failed: ${error.message}`, { cause: error });
346
1187
  }
347
1188
  }
348
- async googleAuth(idToken) {
1189
+ async confirmRegistration(token) {
349
1190
  try {
350
- const based = this._getBasedService("googleAuth");
351
- const response = await based.call("users:google-auth", { idToken });
352
- if (this._initialized) {
353
- this.updateContext({ authToken: response.token });
354
- }
355
- based.setAuthState({
356
- token: response.token,
357
- userId: response.userId,
358
- persistent: true
1191
+ const response = await this._request("/auth/register-confirmation", {
1192
+ method: "POST",
1193
+ body: JSON.stringify({ token }),
1194
+ methodName: "confirmRegistration"
359
1195
  });
360
- return response;
1196
+ if (response.success) {
1197
+ return response.data;
1198
+ }
1199
+ throw new Error(response.message);
361
1200
  } catch (error) {
362
- throw new Error(`Google auth failed: ${error.message}`);
1201
+ throw new Error(`Registration confirmation failed: ${error.message}`, { cause: error });
363
1202
  }
364
1203
  }
365
- async googleAuthCallback(code, redirectUri) {
1204
+ async requestPasswordChange() {
1205
+ this._requireReady("requestPasswordChange");
366
1206
  try {
367
- const based = this._getBasedService("googleAuthCallback");
368
- const response = await based.call("users:google-auth-callback", {
369
- code,
370
- redirectUri
1207
+ const response = await this._request("/auth/request-password-change", {
1208
+ method: "POST",
1209
+ methodName: "requestPasswordChange"
371
1210
  });
372
- if (this._initialized) {
373
- this.updateContext({ authToken: response.token });
1211
+ if (response.success) {
1212
+ return response.data;
374
1213
  }
375
- based.setAuthState({
376
- token: response.token,
377
- userId: response.userId,
378
- persistent: true
1214
+ throw new Error(response.message);
1215
+ } catch (error) {
1216
+ throw new Error(`Password change request failed: ${error.message}`, { cause: error });
1217
+ }
1218
+ }
1219
+ async confirmPasswordChange(currentPassword, newPassword, code) {
1220
+ this._requireReady("confirmPasswordChange");
1221
+ try {
1222
+ const response = await this._request("/auth/confirm-password-change", {
1223
+ method: "POST",
1224
+ body: JSON.stringify({ currentPassword, newPassword, code }),
1225
+ methodName: "confirmPasswordChange"
379
1226
  });
380
- return response;
1227
+ if (response.success) {
1228
+ return response.data;
1229
+ }
1230
+ throw new Error(response.message);
381
1231
  } catch (error) {
382
- throw new Error(`Google auth callback failed: ${error.message}`);
1232
+ throw new Error(`Password change confirmation failed: ${error.message}`, { cause: error });
383
1233
  }
384
1234
  }
385
- async githubAuth(code) {
1235
+ async getMe(options = {}) {
1236
+ this._requireReady("getMe");
386
1237
  try {
387
- const based = this._getBasedService("githubAuth");
388
- const response = await based.call("users:github-auth", { code });
389
- if (this._initialized) {
390
- this.updateContext({ authToken: response.token });
391
- }
392
- based.setAuthState({
393
- token: response.token,
394
- userId: response.userId,
395
- persistent: true
1238
+ const session = this._resolvePluginSession(options.session);
1239
+ const endpoint = session ? `/auth/me?session=${encodeURIComponent(session)}` : "/auth/me";
1240
+ const response = await this._request(endpoint, {
1241
+ method: "GET",
1242
+ methodName: "getMe"
396
1243
  });
397
- return response;
1244
+ if (response.success) {
1245
+ return response.data;
1246
+ }
1247
+ throw new Error(response.message);
398
1248
  } catch (error) {
399
- throw new Error(`GitHub auth failed: ${error.message}`);
1249
+ throw new Error(`Failed to get user profile: ${error.message}`, { cause: error });
400
1250
  }
401
1251
  }
402
- async logout() {
403
- this._requireReady("logout");
1252
+ getAuthToken() {
1253
+ if (!this._tokenManager) {
1254
+ return null;
1255
+ }
1256
+ return this._tokenManager.getAccessToken();
1257
+ }
1258
+ /**
1259
+ * Get stored authentication state (backward compatibility method)
1260
+ * Replaces AuthService.getStoredAuthState()
1261
+ */
1262
+ async getStoredAuthState() {
1263
+ try {
1264
+ if (!this._tokenManager) {
1265
+ return {
1266
+ userId: false,
1267
+ authToken: false
1268
+ };
1269
+ }
1270
+ const tokenStatus = this._tokenManager.getTokenStatus();
1271
+ if (!tokenStatus.hasTokens) {
1272
+ return {
1273
+ userId: false,
1274
+ authToken: false
1275
+ };
1276
+ }
1277
+ if (!tokenStatus.isValid && tokenStatus.hasRefreshToken) {
1278
+ try {
1279
+ await this._tokenManager.ensureValidToken();
1280
+ } catch (error) {
1281
+ console.warn("[AuthService] Token refresh failed:", error.message);
1282
+ if (error.message.includes("401") || error.message.includes("403") || error.message.includes("invalid") || error.message.includes("expired")) {
1283
+ this._tokenManager.clearTokens();
1284
+ return {
1285
+ userId: false,
1286
+ authToken: false,
1287
+ error: `Authentication failed: ${error.message}`
1288
+ };
1289
+ }
1290
+ return {
1291
+ userId: false,
1292
+ authToken: this._tokenManager.getAccessToken(),
1293
+ error: `Network error during token refresh: ${error.message}`,
1294
+ hasTokens: true
1295
+ };
1296
+ }
1297
+ }
1298
+ const currentAccessToken = this._tokenManager.getAccessToken();
1299
+ if (!currentAccessToken) {
1300
+ return {
1301
+ userId: false,
1302
+ authToken: false
1303
+ };
1304
+ }
1305
+ try {
1306
+ const currentUser = await this.getMe();
1307
+ return {
1308
+ userId: currentUser.user.id,
1309
+ authToken: currentAccessToken,
1310
+ ...currentUser,
1311
+ error: null
1312
+ };
1313
+ } catch (error) {
1314
+ console.warn("[AuthService] Failed to get user data:", error.message);
1315
+ if (error.message.includes("401") || error.message.includes("403")) {
1316
+ this._tokenManager.clearTokens();
1317
+ return {
1318
+ userId: false,
1319
+ authToken: false,
1320
+ error: `Authentication failed: ${error.message}`
1321
+ };
1322
+ }
1323
+ return {
1324
+ userId: false,
1325
+ authToken: currentAccessToken,
1326
+ error: `Failed to get user data: ${error.message}`,
1327
+ hasTokens: true
1328
+ };
1329
+ }
1330
+ } catch (error) {
1331
+ console.error(
1332
+ "[AuthService] Unexpected error in getStoredAuthState:",
1333
+ error
1334
+ );
1335
+ return {
1336
+ userId: false,
1337
+ authToken: false,
1338
+ error: `Failed to get stored auth state: ${error.message}`
1339
+ };
1340
+ }
1341
+ }
1342
+ // ==================== USER METHODS ====================
1343
+ async getUserProfile() {
1344
+ this._requireReady("getUserProfile");
404
1345
  try {
405
- const based = this._getBasedService("logout");
406
- await based.call("users:logout");
407
- this.updateContext({ authToken: null });
1346
+ const response = await this._request("/users/profile", {
1347
+ method: "GET",
1348
+ methodName: "getUserProfile"
1349
+ });
1350
+ if (response.success) {
1351
+ return response.data;
1352
+ }
1353
+ throw new Error(response.message);
408
1354
  } catch (error) {
409
- throw new Error(`Logout failed: ${error.message}`);
1355
+ throw new Error(`Failed to get user profile: ${error.message}`, { cause: error });
410
1356
  }
411
1357
  }
412
- async updateUserRole(userId, newRole) {
413
- this._requireReady("updateUserRole");
1358
+ async updateUserProfile(profileData) {
1359
+ this._requireReady("updateUserProfile");
1360
+ try {
1361
+ const response = await this._request("/users/profile", {
1362
+ method: "PATCH",
1363
+ body: JSON.stringify(profileData),
1364
+ methodName: "updateUserProfile"
1365
+ });
1366
+ if (response.success) {
1367
+ return response.data;
1368
+ }
1369
+ throw new Error(response.message);
1370
+ } catch (error) {
1371
+ throw new Error(`Failed to update user profile: ${error.message}`, { cause: error });
1372
+ }
1373
+ }
1374
+ async getUserProjects() {
1375
+ this._requireReady("getUserProjects");
1376
+ try {
1377
+ const response = await this._request("/users/projects", {
1378
+ method: "GET",
1379
+ methodName: "getUserProjects"
1380
+ });
1381
+ if (response.success) {
1382
+ return response.data.map((project) => ({
1383
+ ...project,
1384
+ ...project.icon && {
1385
+ icon: {
1386
+ src: `${this._apiUrl}/core/files/public/${project.icon.id}/download`,
1387
+ ...project.icon
1388
+ }
1389
+ }
1390
+ }));
1391
+ }
1392
+ throw new Error(response.message);
1393
+ } catch (error) {
1394
+ throw new Error(`Failed to get user projects: ${error.message}`, { cause: error });
1395
+ }
1396
+ }
1397
+ async getUser(userId) {
1398
+ this._requireReady("getUser");
414
1399
  if (!userId) {
415
1400
  throw new Error("User ID is required");
416
1401
  }
417
- if (!this._userRoles.has(newRole)) {
418
- throw new Error(`Invalid role: ${newRole}`);
1402
+ try {
1403
+ const response = await this._request(`/users/${userId}`, {
1404
+ method: "GET",
1405
+ methodName: "getUser"
1406
+ });
1407
+ if (response.success) {
1408
+ return response.data;
1409
+ }
1410
+ throw new Error(response.message);
1411
+ } catch (error) {
1412
+ throw new Error(`Failed to get user: ${error.message}`, { cause: error });
1413
+ }
1414
+ }
1415
+ async getUserByEmail(email) {
1416
+ this._requireReady("getUserByEmail");
1417
+ if (!email) {
1418
+ throw new Error("Email is required");
419
1419
  }
420
1420
  try {
421
- const based = this._getBasedService("updateUserRole");
422
- return await based.call("users:update-role", { userId, role: newRole });
1421
+ const response = await this._request(`/auth/user?email=${email}`, {
1422
+ method: "GET",
1423
+ methodName: "getUserByEmail"
1424
+ });
1425
+ if (response.success) {
1426
+ return response.data.user;
1427
+ }
1428
+ throw new Error(response.message);
423
1429
  } catch (error) {
424
- throw new Error(`Failed to update user role: ${error.message}`);
1430
+ throw new Error(`Failed to get user by email: ${error.message}`, { cause: error });
425
1431
  }
426
1432
  }
427
- async updateProjectTier(projectId, newTier) {
428
- this._requireReady("updateProjectTier");
1433
+ // ==================== PROJECT ROLE METHODS ====================
1434
+ /**
1435
+ * Get the current user's role for a specific project by project ID
1436
+ * Uses caching to avoid repeated API calls
1437
+ */
1438
+ async getMyProjectRole(projectId) {
1439
+ this._requireReady("getMyProjectRole");
429
1440
  if (!projectId) {
430
1441
  throw new Error("Project ID is required");
431
1442
  }
432
- if (!this._projectTiers.has(newTier)) {
433
- throw new Error(`Invalid project tier: ${newTier}`);
1443
+ if (!this.hasValidTokens()) {
1444
+ return "guest";
1445
+ }
1446
+ const cacheKey = `role_${projectId}`;
1447
+ const cached = this._projectRoleCache.get(cacheKey);
1448
+ if (cached && Date.now() - cached.timestamp < this._roleCacheExpiry) {
1449
+ return cached.role;
1450
+ }
1451
+ try {
1452
+ const response = await this._request(`/projects/${projectId}/role`, {
1453
+ method: "GET",
1454
+ methodName: "getMyProjectRole"
1455
+ });
1456
+ if (response.success) {
1457
+ const { role } = response.data;
1458
+ this._projectRoleCache.set(cacheKey, {
1459
+ role,
1460
+ timestamp: Date.now()
1461
+ });
1462
+ return role;
1463
+ }
1464
+ throw new Error(response.message);
1465
+ } catch (error) {
1466
+ const message = (error == null ? void 0 : error.message) || "";
1467
+ if (/401|403|unauthorized|no token|invalid token/iu.test(message)) {
1468
+ return "guest";
1469
+ }
1470
+ throw new Error(`Failed to get project role: ${message}`, { cause: error });
1471
+ }
1472
+ }
1473
+ /**
1474
+ * Get the current user's role for a specific project by project key
1475
+ * Uses caching to avoid repeated API calls
1476
+ */
1477
+ async getMyProjectRoleByKey(projectKey) {
1478
+ this._requireReady("getMyProjectRoleByKey");
1479
+ if (!projectKey) {
1480
+ throw new Error("Project key is required");
1481
+ }
1482
+ if (!this.hasValidTokens()) {
1483
+ return "guest";
1484
+ }
1485
+ const cacheKey = `role_key_${projectKey}`;
1486
+ const cached = this._projectRoleCache.get(cacheKey);
1487
+ if (cached && Date.now() - cached.timestamp < this._roleCacheExpiry) {
1488
+ return cached.role;
434
1489
  }
435
1490
  try {
436
- const based = this._getBasedService("updateProjectTier");
437
- return await based.call("projects:update-tier", {
438
- projectId,
439
- tier: newTier
1491
+ const response = await this._request(`/projects/key/${projectKey}/role`, {
1492
+ method: "GET",
1493
+ methodName: "getMyProjectRoleByKey"
440
1494
  });
1495
+ if (response.success) {
1496
+ const { role } = response.data;
1497
+ this._projectRoleCache.set(cacheKey, {
1498
+ role,
1499
+ timestamp: Date.now()
1500
+ });
1501
+ return role;
1502
+ }
1503
+ throw new Error(response.message);
1504
+ } catch (error) {
1505
+ const message = (error == null ? void 0 : error.message) || "";
1506
+ if (/401|403|unauthorized|no token|invalid token/iu.test(message)) {
1507
+ return "guest";
1508
+ }
1509
+ throw new Error(`Failed to get project role by key: ${message}`, { cause: error });
1510
+ }
1511
+ }
1512
+ /**
1513
+ * Clear the project role cache for a specific project or all projects
1514
+ */
1515
+ clearProjectRoleCache(projectId = null) {
1516
+ if (projectId) {
1517
+ this._projectRoleCache.delete(`role_${projectId}`);
1518
+ for (const [key] of this._projectRoleCache) {
1519
+ if (key.startsWith("role_key_")) {
1520
+ this._projectRoleCache.delete(key);
1521
+ }
1522
+ }
1523
+ } else {
1524
+ this._projectRoleCache.clear();
1525
+ }
1526
+ }
1527
+ /**
1528
+ * Get project role with fallback to user projects list
1529
+ * This method tries to get the role from user projects first,
1530
+ * then falls back to API call if not found
1531
+ */
1532
+ async getProjectRoleWithFallback(projectId, userProjects = null) {
1533
+ this._requireReady("getProjectRoleWithFallback");
1534
+ if (!projectId) {
1535
+ throw new Error("Project ID is required");
1536
+ }
1537
+ if (userProjects && Array.isArray(userProjects)) {
1538
+ const userProject = userProjects.find((p) => p.id === projectId);
1539
+ if (userProject && userProject.role) {
1540
+ return userProject.role;
1541
+ }
1542
+ }
1543
+ return await this.getMyProjectRole(projectId);
1544
+ }
1545
+ /**
1546
+ * Get project role with fallback to user projects list (by project key)
1547
+ * This method tries to get the role from user projects first,
1548
+ * then falls back to API call if not found
1549
+ */
1550
+ async getProjectRoleByKeyWithFallback(projectKey, userProjects = null) {
1551
+ this._requireReady("getProjectRoleByKeyWithFallback");
1552
+ if (!projectKey) {
1553
+ throw new Error("Project key is required");
1554
+ }
1555
+ if (userProjects && Array.isArray(userProjects)) {
1556
+ const userProject = userProjects.find((p) => p.key === projectKey);
1557
+ if (userProject && userProject.role) {
1558
+ return userProject.role;
1559
+ }
1560
+ }
1561
+ return await this.getMyProjectRoleByKey(projectKey);
1562
+ }
1563
+ // ==================== AUTH HELPER METHODS ====================
1564
+ /**
1565
+ * Debug method to check token status
1566
+ */
1567
+ getTokenDebugInfo() {
1568
+ if (!this._tokenManager) {
1569
+ return {
1570
+ tokenManagerExists: false,
1571
+ error: "TokenManager not initialized"
1572
+ };
1573
+ }
1574
+ const tokenStatus = this._tokenManager.getTokenStatus();
1575
+ const { tokens } = this._tokenManager;
1576
+ return {
1577
+ tokenManagerExists: true,
1578
+ tokenStatus,
1579
+ hasAccessToken: Boolean(tokens.accessToken),
1580
+ hasRefreshToken: Boolean(tokens.refreshToken),
1581
+ accessTokenPreview: tokens.accessToken ? `${tokens.accessToken.substring(0, 20)}...` : null,
1582
+ expiresAt: tokens.expiresAt,
1583
+ timeToExpiry: tokenStatus.timeToExpiry,
1584
+ authHeader: this._tokenManager.getAuthHeader()
1585
+ };
1586
+ }
1587
+ /**
1588
+ * Helper method to check if user is authenticated
1589
+ */
1590
+ isAuthenticated() {
1591
+ if (!this._tokenManager) {
1592
+ return false;
1593
+ }
1594
+ return this._tokenManager.hasTokens();
1595
+ }
1596
+ /**
1597
+ * Helper method to check if user has valid tokens
1598
+ */
1599
+ hasValidTokens() {
1600
+ if (!this._tokenManager) {
1601
+ return false;
1602
+ }
1603
+ return this._tokenManager.hasTokens() && this._tokenManager.isAccessTokenValid();
1604
+ }
1605
+ /**
1606
+ * Helper method to get current user info
1607
+ */
1608
+ async getCurrentUser() {
1609
+ try {
1610
+ return await this.getMe();
441
1611
  } catch (error) {
442
- throw new Error(`Failed to update project tier: ${error.message}`);
1612
+ throw new Error(`Failed to get current user: ${error.message}`, { cause: error });
443
1613
  }
444
1614
  }
1615
+ /**
1616
+ * Helper method to validate user data for registration
1617
+ */
1618
+ validateRegistrationData(userData) {
1619
+ const errors = [];
1620
+ if (!userData.email || typeof userData.email !== "string") {
1621
+ errors.push("Email is required and must be a string");
1622
+ } else if (!this._isValidEmail(userData.email)) {
1623
+ errors.push("Email must be a valid email address");
1624
+ }
1625
+ if (!userData.password || typeof userData.password !== "string") {
1626
+ errors.push("Password is required and must be a string");
1627
+ } else if (userData.password.length < 8) {
1628
+ errors.push("Password must be at least 8 characters long");
1629
+ }
1630
+ if (userData.username && typeof userData.username !== "string") {
1631
+ errors.push("Username must be a string");
1632
+ } else if (userData.username && userData.username.length < 3) {
1633
+ errors.push("Username must be at least 3 characters long");
1634
+ }
1635
+ return {
1636
+ isValid: errors.length === 0,
1637
+ errors
1638
+ };
1639
+ }
1640
+ /**
1641
+ * Helper method to register with validation
1642
+ */
1643
+ async registerWithValidation(userData, options = {}) {
1644
+ const validation = this.validateRegistrationData(userData);
1645
+ if (!validation.isValid) {
1646
+ throw new Error(`Validation failed: ${validation.errors.join(", ")}`);
1647
+ }
1648
+ return await this.register(userData, options);
1649
+ }
1650
+ /**
1651
+ * Helper method to login with validation
1652
+ */
1653
+ async loginWithValidation(email, password, options = {}) {
1654
+ if (!email || typeof email !== "string") {
1655
+ throw new Error("Email is required and must be a string");
1656
+ }
1657
+ if (!password || typeof password !== "string") {
1658
+ throw new Error("Password is required and must be a string");
1659
+ }
1660
+ if (!this._isValidEmail(email)) {
1661
+ throw new Error("Email must be a valid email address");
1662
+ }
1663
+ return await this.login(email, password, options);
1664
+ }
1665
+ /**
1666
+ * Private helper to validate email format
1667
+ */
1668
+ _isValidEmail(email) {
1669
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/u;
1670
+ return emailRegex.test(email);
1671
+ }
1672
+ // ==================== PERMISSION METHODS (Existing) ====================
445
1673
  hasPermission(requiredPermission) {
446
1674
  var _a;
447
1675
  const authState = (_a = this._context) == null ? void 0 : _a.state;
@@ -490,23 +1718,17 @@ var AuthService = class extends BaseService {
490
1718
  if (!operationConfig) {
491
1719
  return false;
492
1720
  }
493
- if (!operationConfig) {
494
- return false;
495
- }
496
1721
  const { permissions = [], features = [] } = operationConfig;
497
1722
  try {
498
1723
  const permissionResults = await Promise.all(
499
1724
  permissions.map(
500
- (permission) => this.hasProjectPermission(projectId, permission)
1725
+ (permission) => this.checkProjectPermission(projectId, permission)
501
1726
  )
502
1727
  );
503
1728
  const hasPermissions = requireAll ? permissionResults.every(Boolean) : permissionResults.some(Boolean);
504
1729
  if (!hasPermissions) {
505
1730
  return false;
506
1731
  }
507
- if (!hasPermissions) {
508
- return false;
509
- }
510
1732
  if (checkFeatures && features.length > 0) {
511
1733
  const featureResults = features.map((feature) => {
512
1734
  const result = this.hasProjectFeature(projectId, feature);
@@ -516,9 +1738,6 @@ var AuthService = class extends BaseService {
516
1738
  if (!hasFeatures) {
517
1739
  return false;
518
1740
  }
519
- if (!hasFeatures) {
520
- return false;
521
- }
522
1741
  }
523
1742
  return true;
524
1743
  } catch (error) {
@@ -540,206 +1759,94 @@ var AuthService = class extends BaseService {
540
1759
  }
541
1760
  return action();
542
1761
  }
543
- // Project access information
544
- async getProjectAccess(projectId) {
545
- this._requireReady();
546
- if (!projectId) {
547
- throw new Error("Project ID is required");
1762
+ // Cleanup
1763
+ destroy() {
1764
+ if (this._tokenManager) {
1765
+ this._tokenManager.destroy();
1766
+ this._tokenManager = null;
548
1767
  }
549
- const operations = Object.keys(PERMISSION_MAP);
550
- const access = await Promise.all(
551
- operations.map(async (operation) => {
552
- const allowed = await this.canPerformOperation(projectId, operation);
553
- const config = PERMISSION_MAP[operation];
554
- return {
555
- operation,
556
- allowed,
557
- permissions: config.permissions,
558
- features: config.features,
559
- aiTokens: operation.startsWith("ai") ? this._getAITokens(projectId, operation.replace("ai", "")) : null
560
- };
561
- })
562
- );
563
- return {
564
- projectId,
565
- permissions: access.reduce(
566
- (acc, { operation, ...details }) => ({
567
- ...acc,
568
- [operation]: details
569
- }),
570
- {}
571
- ),
572
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
573
- };
1768
+ this._projectRoleCache.clear();
1769
+ this._setReady(false);
574
1770
  }
575
- // AI token management
576
- _getAITokens(projectId, featureType) {
577
- const tokenFeatures = [
578
- `ai${featureType}:3`,
579
- `ai${featureType}:5`,
580
- `ai${featureType}:15`
581
- ];
582
- return tokenFeatures.reduce((total, feature) => {
583
- const tokens = this.hasProjectFeature(projectId, feature);
584
- return total + (typeof tokens === "number" ? tokens : 0);
585
- }, 0);
586
- }
587
- async getProjectMembers(projectId) {
588
- var _a;
589
- this._requireReady("getProjectMembers");
590
- if (!projectId) {
591
- throw new Error("Project ID is required");
592
- }
593
- try {
594
- const based = this._getBasedService("getProjectMembers");
595
- return await based.call("projects:get-members", { projectId });
596
- } catch (error) {
597
- if ((_a = error.message) == null ? void 0 : _a.includes("Authentication failed. Please try again"))
598
- window.location.reload();
599
- throw new Error(`Failed to get project members: ${error.message}`);
600
- }
601
- }
602
- async inviteMember(projectId, email, role, name, callbackUrl) {
603
- this._requireReady("inviteMember");
604
- if (!projectId) {
605
- throw new Error("Project ID is required");
606
- }
607
- if (!email) {
608
- throw new Error("Email is required");
609
- }
610
- if (!callbackUrl || Object.keys(callbackUrl).length === 0) {
611
- throw new Error("Callback Url is required");
612
- }
613
- if (!role || !this._userRoles.has(role)) {
614
- throw new Error(`Invalid role: ${role}`);
615
- }
616
- try {
617
- const based = this._getBasedService("inviteMember");
618
- return await based.call("projects:invite-member", {
619
- projectId,
620
- email,
621
- role,
622
- name,
623
- callbackUrl
624
- });
625
- } catch (error) {
626
- throw new Error(`Failed to invite member: ${error.message}`);
1771
+ _preparePluginPayload(payload, sessionOverride = null) {
1772
+ const target = payload && typeof payload === "object" ? { ...payload } : {};
1773
+ const session = this._resolvePluginSession(sessionOverride);
1774
+ if (session && !Object.hasOwn(target, "session")) {
1775
+ target.session = session;
1776
+ return { payload: target, session };
627
1777
  }
1778
+ return { payload: target, session: null };
628
1779
  }
629
- async acceptInvite(token) {
630
- this._requireReady("acceptInvite");
631
- try {
632
- const based = this._getBasedService("acceptInvite");
633
- return await based.call("projects:accept-invite", { token });
634
- } catch (error) {
635
- throw new Error(`Failed to accept invite: ${error.message}`);
1780
+ _resolvePluginSession(sessionOverride = null) {
1781
+ var _a, _b;
1782
+ if (sessionOverride) {
1783
+ return this._cachePluginSession(sessionOverride);
636
1784
  }
637
- }
638
- async updateMemberRole(projectId, userId, role) {
639
- this._requireReady("updateMemberRole");
640
- if (!projectId) {
641
- throw new Error("Project ID is required");
1785
+ if (this._pluginSession) {
1786
+ return this._pluginSession;
642
1787
  }
643
- if (!userId) {
644
- throw new Error("User ID is required");
1788
+ const optionSession = (_a = this._options) == null ? void 0 : _a.pluginSession;
1789
+ if (optionSession) {
1790
+ return this._cachePluginSession(optionSession);
645
1791
  }
646
- if (!this._userRoles.has(role)) {
647
- throw new Error(`Invalid role: ${role}`);
1792
+ const contextSession = (_b = this._context) == null ? void 0 : _b.pluginSession;
1793
+ if (contextSession) {
1794
+ return this._cachePluginSession(contextSession);
648
1795
  }
649
- try {
650
- const based = this._getBasedService("updateMemberRole");
651
- return await based.call("projects:update-member-role", {
652
- projectId,
653
- userId,
654
- role
655
- });
656
- } catch (error) {
657
- throw new Error(`Failed to update member role: ${error.message}`);
1796
+ if (typeof window !== "undefined") {
1797
+ try {
1798
+ const sessionFromUrl = new URL(window.location.href).searchParams.get("session");
1799
+ if (sessionFromUrl) {
1800
+ return this._cachePluginSession(sessionFromUrl);
1801
+ }
1802
+ } catch {
1803
+ }
1804
+ try {
1805
+ if (window.localStorage) {
1806
+ const stored = window.localStorage.getItem(PLUGIN_SESSION_STORAGE_KEY);
1807
+ if (stored) {
1808
+ this._pluginSession = stored;
1809
+ return stored;
1810
+ }
1811
+ }
1812
+ } catch {
1813
+ }
658
1814
  }
1815
+ return null;
659
1816
  }
660
- async removeMember(projectId, userId) {
661
- this._requireReady("removeMember");
662
- if (!projectId || !userId) {
663
- throw new Error("Project ID and user ID are required");
1817
+ _cachePluginSession(session) {
1818
+ if (!session) {
1819
+ return null;
664
1820
  }
665
- try {
666
- const based = this._getBasedService("removeMember");
667
- return await based.call("projects:remove-member", { projectId, userId });
668
- } catch (error) {
669
- throw new Error(`Failed to remove member: ${error.message}`);
670
- }
671
- }
672
- async confirmRegistration(token) {
673
- try {
674
- const based = this._getBasedService("confirmRegistration");
675
- return await based.call("users:register-confirmation", { token });
676
- } catch (error) {
677
- throw new Error(`Registration confirmation failed: ${error.message}`);
1821
+ this._pluginSession = session;
1822
+ if (typeof window !== "undefined") {
1823
+ try {
1824
+ if (window.localStorage) {
1825
+ window.localStorage.setItem(PLUGIN_SESSION_STORAGE_KEY, session);
1826
+ }
1827
+ } catch {
1828
+ }
678
1829
  }
1830
+ return session;
679
1831
  }
680
- async requestPasswordReset(email, callbackUrl) {
681
- try {
682
- const based = this._getBasedService("requestPasswordReset");
683
- return await based.call("users:reset-password", { email, callbackUrl });
684
- } catch (error) {
685
- throw new Error(`Password reset request failed: ${error.message}`);
686
- }
1832
+ setPluginSession(session) {
1833
+ this._cachePluginSession(session);
687
1834
  }
688
- async confirmPasswordReset(token, newPassword) {
689
- try {
690
- const based = this._getBasedService("confirmPasswordReset");
691
- return await based.call("users:reset-password-confirm", {
692
- token,
693
- newPassword
694
- });
695
- } catch (error) {
696
- throw new Error(`Password reset confirmation failed: ${error.message}`);
1835
+ _clearPluginSession(session = null) {
1836
+ if (!session || this._pluginSession === session) {
1837
+ this._pluginSession = null;
697
1838
  }
698
- }
699
- async getStoredAuthState() {
700
- try {
701
- const based = this._getBasedService("getStoredAuthState");
702
- const { authState } = based;
703
- if (authState == null ? void 0 : authState.token) {
704
- return {
705
- userId: authState.userId,
706
- authToken: authState.token,
707
- projectRoles: authState.projectRoles,
708
- globalRole: authState.globalRole,
709
- error: null
710
- };
1839
+ if (typeof window !== "undefined") {
1840
+ try {
1841
+ if (window.localStorage) {
1842
+ window.localStorage.removeItem(PLUGIN_SESSION_STORAGE_KEY);
1843
+ }
1844
+ } catch {
711
1845
  }
712
- return {
713
- userId: false,
714
- authToken: false
715
- };
716
- } catch (error) {
717
- this._setError(error);
718
- return {
719
- userId: false,
720
- authToken: false,
721
- error: `Failed to get stored auth state: ${error.message}`
722
- };
723
1846
  }
724
1847
  }
725
- async subscribeToAuthChanges(callback) {
726
- const based = this._getBasedService("subscribeToAuthChanges");
727
- based.on("authstate-change", async (authState) => {
728
- const formattedState = (authState == null ? void 0 : authState.token) ? {
729
- userId: authState.userId,
730
- authToken: authState.token,
731
- projectRoles: authState.projectRoles,
732
- globalRole: authState.globalRole,
733
- error: null
734
- } : {
735
- userId: false,
736
- authToken: false
737
- };
738
- await callback(formattedState);
739
- });
740
- return () => based.off("authstate-change");
741
- }
742
1848
  };
743
1849
  export {
744
1850
  AuthService
745
1851
  };
1852
+ // @preserve-env