@tribecloud/sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,52 @@
1
+ import type { TribeConfig, TribeSDK, User, Announcement, FeedbackOptions, ApiKey, ApiKeyResult, ActiveDevice, ForgotPasswordOptions, ResendVerificationOptions, MagicLinkOptions, AuthConfig } from "./types";
2
+ export declare class Tribe implements TribeSDK {
3
+ private siteId;
4
+ private baseUrl;
5
+ private sessionId;
6
+ private pageStart;
7
+ private currentPath;
8
+ private tokenKey;
9
+ private anonIdKey;
10
+ private autoTrackingActive;
11
+ private originalPushState;
12
+ private popstateHandler;
13
+ private visibilityHandler;
14
+ constructor(config: TribeConfig);
15
+ static init(config: TribeConfig): Tribe;
16
+ startAutoTracking(): void;
17
+ stopAutoTracking(): void;
18
+ private sendEvent;
19
+ private gql;
20
+ private getAnonymousId;
21
+ register(email: string, password: string): Promise<{
22
+ user: User;
23
+ }>;
24
+ login(email: string, password: string): Promise<{
25
+ user: User;
26
+ }>;
27
+ logout(): Promise<void>;
28
+ getSession(): Promise<{
29
+ user: User;
30
+ } | null>;
31
+ track(eventName: string, data?: Record<string, unknown>): void;
32
+ feedback(message: string, options?: FeedbackOptions): Promise<void>;
33
+ getFeatureFlag(key: string): Promise<boolean>;
34
+ getAnnouncements(): Promise<Announcement[]>;
35
+ ackAnnouncement(announcementId: string): Promise<void>;
36
+ verifyEmail(token: string): Promise<void>;
37
+ resendVerification(options?: ResendVerificationOptions): Promise<void>;
38
+ forgotPassword(email: string, options?: ForgotPasswordOptions): Promise<void>;
39
+ resetPassword(token: string, newPassword: string): Promise<void>;
40
+ requestMagicLink(email: string, options?: MagicLinkOptions): Promise<void>;
41
+ verifyMagicLink(token: string): Promise<{
42
+ user: User;
43
+ }>;
44
+ getAuthConfig(): Promise<AuthConfig>;
45
+ setRole(role: string): Promise<User>;
46
+ createApiKey(name: string, scopes: string[]): Promise<ApiKeyResult>;
47
+ listApiKeys(): Promise<ApiKey[]>;
48
+ deleteApiKey(id: string): Promise<void>;
49
+ invalidateAllSessions(): Promise<void>;
50
+ getActiveDevices(): Promise<ActiveDevice[]>;
51
+ revokeSession(sessionId: string): Promise<void>;
52
+ }
@@ -0,0 +1,3 @@
1
+ export { Tribe } from "./core";
2
+ export { Tribe as default } from "./core";
3
+ export type { TribeConfig, TribeSDK, User, Announcement, FeedbackOptions, ApiKey, ApiKeyResult, ActiveDevice, ForgotPasswordOptions, ResendVerificationOptions, MagicLinkOptions, AuthConfig, } from "./types";
@@ -0,0 +1,326 @@
1
+ // src/core.ts
2
+ class Tribe {
3
+ siteId;
4
+ baseUrl;
5
+ sessionId;
6
+ pageStart;
7
+ currentPath;
8
+ tokenKey;
9
+ anonIdKey;
10
+ autoTrackingActive = false;
11
+ originalPushState = null;
12
+ popstateHandler = null;
13
+ visibilityHandler = null;
14
+ constructor(config) {
15
+ this.siteId = config.siteId;
16
+ this.baseUrl = config.baseUrl;
17
+ this.sessionId = Math.random().toString(36).slice(2);
18
+ this.pageStart = Date.now();
19
+ this.currentPath = location.pathname;
20
+ this.tokenKey = `__tribe_${config.siteId}`;
21
+ this.anonIdKey = `__tribe_anon_${config.siteId}`;
22
+ if (config.autoTrack !== false) {
23
+ this.startAutoTracking();
24
+ }
25
+ }
26
+ static init(config) {
27
+ return new Tribe(config);
28
+ }
29
+ startAutoTracking() {
30
+ if (this.autoTrackingActive)
31
+ return;
32
+ this.autoTrackingActive = true;
33
+ this.sendEvent("pageview");
34
+ this.visibilityHandler = () => {
35
+ if (document.visibilityState === "hidden") {
36
+ this.sendEvent("leave", { d: Date.now() - this.pageStart });
37
+ }
38
+ };
39
+ document.addEventListener("visibilitychange", this.visibilityHandler);
40
+ this.originalPushState = history.pushState;
41
+ history.pushState = (...args) => {
42
+ this.sendEvent("leave", { d: Date.now() - this.pageStart });
43
+ this.originalPushState.apply(history, args);
44
+ this.pageStart = Date.now();
45
+ this.currentPath = location.pathname;
46
+ this.sendEvent("pageview");
47
+ };
48
+ this.popstateHandler = () => {
49
+ this.sendEvent("leave", { d: Date.now() - this.pageStart });
50
+ this.pageStart = Date.now();
51
+ this.currentPath = location.pathname;
52
+ this.sendEvent("pageview");
53
+ };
54
+ window.addEventListener("popstate", this.popstateHandler);
55
+ }
56
+ stopAutoTracking() {
57
+ if (!this.autoTrackingActive)
58
+ return;
59
+ this.autoTrackingActive = false;
60
+ if (this.visibilityHandler) {
61
+ document.removeEventListener("visibilitychange", this.visibilityHandler);
62
+ this.visibilityHandler = null;
63
+ }
64
+ if (this.originalPushState) {
65
+ history.pushState = this.originalPushState;
66
+ this.originalPushState = null;
67
+ }
68
+ if (this.popstateHandler) {
69
+ window.removeEventListener("popstate", this.popstateHandler);
70
+ this.popstateHandler = null;
71
+ }
72
+ }
73
+ sendEvent(type, extra = {}) {
74
+ const data = {
75
+ s: this.siteId,
76
+ t: type,
77
+ p: this.currentPath,
78
+ r: document.referrer || null,
79
+ sid: this.sessionId,
80
+ w: screen.width,
81
+ ...extra
82
+ };
83
+ if (navigator.sendBeacon) {
84
+ const blob = new Blob([JSON.stringify(data)], { type: "application/json" });
85
+ navigator.sendBeacon(`${this.baseUrl}/collect`, blob);
86
+ } else {
87
+ fetch(`${this.baseUrl}/collect`, {
88
+ method: "POST",
89
+ body: JSON.stringify(data),
90
+ keepalive: true,
91
+ headers: { "Content-Type": "application/json" }
92
+ }).catch(() => {});
93
+ }
94
+ }
95
+ async gql(query, variables) {
96
+ const token = localStorage.getItem(this.tokenKey);
97
+ const headers = {
98
+ "Content-Type": "application/json"
99
+ };
100
+ if (token) {
101
+ headers["Authorization"] = `Bearer ${token}`;
102
+ } else {
103
+ headers["X-Tribe-Anonymous-Id"] = this.getAnonymousId();
104
+ }
105
+ const response = await fetch(`${this.baseUrl}/graphql`, {
106
+ method: "POST",
107
+ headers,
108
+ body: JSON.stringify({ query, variables })
109
+ });
110
+ const json = await response.json();
111
+ if (json.errors) {
112
+ throw new Error(json.errors[0].message);
113
+ }
114
+ return json.data;
115
+ }
116
+ getAnonymousId() {
117
+ let anonId = localStorage.getItem(this.anonIdKey);
118
+ if (!anonId) {
119
+ anonId = crypto.randomUUID();
120
+ localStorage.setItem(this.anonIdKey, anonId);
121
+ }
122
+ return anonId;
123
+ }
124
+ async register(email, password) {
125
+ const data = await this.gql(`mutation($siteId: ID!, $email: String!, $password: String!) {
126
+ sdkRegister(siteId: $siteId, email: $email, password: $password) {
127
+ token
128
+ user { id email }
129
+ }
130
+ }`, { siteId: this.siteId, email, password });
131
+ localStorage.setItem(this.tokenKey, data.sdkRegister.token);
132
+ return { user: data.sdkRegister.user };
133
+ }
134
+ async login(email, password) {
135
+ const data = await this.gql(`mutation($siteId: ID!, $email: String!, $password: String!) {
136
+ sdkLogin(siteId: $siteId, email: $email, password: $password) {
137
+ token
138
+ user { id email }
139
+ }
140
+ }`, { siteId: this.siteId, email, password });
141
+ localStorage.setItem(this.tokenKey, data.sdkLogin.token);
142
+ return { user: data.sdkLogin.user };
143
+ }
144
+ async logout() {
145
+ try {
146
+ await this.gql(`mutation { sdkLogout }`);
147
+ } catch {}
148
+ localStorage.removeItem(this.tokenKey);
149
+ }
150
+ async getSession() {
151
+ const token = localStorage.getItem(this.tokenKey);
152
+ if (!token)
153
+ return null;
154
+ try {
155
+ const data = await this.gql(`query { sdkSession { user { id email } } }`);
156
+ return data.sdkSession;
157
+ } catch {
158
+ localStorage.removeItem(this.tokenKey);
159
+ return null;
160
+ }
161
+ }
162
+ track(eventName, data) {
163
+ this.sendEvent("custom", { e: eventName, ed: data });
164
+ }
165
+ async feedback(message, options) {
166
+ const url = this.currentPath;
167
+ await this.gql(`mutation($siteId: ID!, $message: String!, $type: String, $email: String, $url: String) {
168
+ submitFeedback(siteId: $siteId, message: $message, type: $type, email: $email, url: $url)
169
+ }`, {
170
+ siteId: this.siteId,
171
+ message,
172
+ url,
173
+ type: options?.type,
174
+ email: options?.email
175
+ });
176
+ }
177
+ async getFeatureFlag(key) {
178
+ const data = await this.gql(`query($siteId: ID!) {
179
+ sdkFeatureFlags(siteId: $siteId) {
180
+ key
181
+ enabled
182
+ }
183
+ }`, { siteId: this.siteId });
184
+ const flag = data.sdkFeatureFlags.find((f) => f.key === key);
185
+ return flag?.enabled ?? false;
186
+ }
187
+ async getAnnouncements() {
188
+ const data = await this.gql(`query($siteId: ID!) {
189
+ activeAnnouncements(siteId: $siteId) {
190
+ id
191
+ title
192
+ message
193
+ type
194
+ }
195
+ }`, { siteId: this.siteId });
196
+ const dismissedKey = `__tribe_dismissed_${this.siteId}`;
197
+ const dismissed = JSON.parse(localStorage.getItem(dismissedKey) || "[]");
198
+ return data.activeAnnouncements.filter((a) => !dismissed.includes(a.id));
199
+ }
200
+ async ackAnnouncement(announcementId) {
201
+ const dismissedKey = `__tribe_dismissed_${this.siteId}`;
202
+ const dismissed = JSON.parse(localStorage.getItem(dismissedKey) || "[]");
203
+ if (!dismissed.includes(announcementId)) {
204
+ dismissed.push(announcementId);
205
+ localStorage.setItem(dismissedKey, JSON.stringify(dismissed));
206
+ }
207
+ try {
208
+ await this.gql(`mutation($announcementId: ID!) {
209
+ ackAnnouncement(announcementId: $announcementId)
210
+ }`, { announcementId });
211
+ } catch {}
212
+ }
213
+ async verifyEmail(token) {
214
+ await this.gql(`mutation($token: String!) {
215
+ verifyEmail(token: $token)
216
+ }`, { token });
217
+ }
218
+ async resendVerification(options) {
219
+ await this.gql(`mutation($verifyEmailUrl: String) {
220
+ resendVerification(verifyEmailUrl: $verifyEmailUrl)
221
+ }`, { verifyEmailUrl: options?.verifyEmailUrl });
222
+ }
223
+ async forgotPassword(email, options) {
224
+ await this.gql(`mutation($siteId: ID!, $email: String!, $resetPasswordUrl: String) {
225
+ forgotPassword(siteId: $siteId, email: $email, resetPasswordUrl: $resetPasswordUrl)
226
+ }`, { siteId: this.siteId, email, resetPasswordUrl: options?.resetPasswordUrl });
227
+ }
228
+ async resetPassword(token, newPassword) {
229
+ await this.gql(`mutation($token: String!, $newPassword: String!) {
230
+ resetPassword(token: $token, newPassword: $newPassword)
231
+ }`, { token, newPassword });
232
+ }
233
+ async requestMagicLink(email, options) {
234
+ await this.gql(`mutation($siteId: ID!, $email: String!, $magicLinkUrl: String) {
235
+ requestMagicLink(siteId: $siteId, email: $email, magicLinkUrl: $magicLinkUrl)
236
+ }`, { siteId: this.siteId, email, magicLinkUrl: options?.magicLinkUrl });
237
+ }
238
+ async verifyMagicLink(token) {
239
+ const data = await this.gql(`mutation($token: String!) {
240
+ verifyMagicLink(token: $token) {
241
+ token
242
+ user { id email }
243
+ }
244
+ }`, { token });
245
+ localStorage.setItem(this.tokenKey, data.verifyMagicLink.token);
246
+ return { user: data.verifyMagicLink.user };
247
+ }
248
+ async getAuthConfig() {
249
+ const data = await this.gql(`query($siteId: ID!) {
250
+ siteAuthConfig(siteId: $siteId) {
251
+ authEnabled
252
+ magicLinkEnabled
253
+ captchaEnabled
254
+ captchaProvider
255
+ captchaSiteKey
256
+ captchaRequiredForRegistration
257
+ captchaRequiredForLogin
258
+ breachedPasswordPolicy
259
+ }
260
+ }`, { siteId: this.siteId });
261
+ return data.siteAuthConfig;
262
+ }
263
+ async setRole(role) {
264
+ const data = await this.gql(`mutation($role: String!) {
265
+ setRole(role: $role) {
266
+ id
267
+ email
268
+ }
269
+ }`, { role });
270
+ return data.setRole;
271
+ }
272
+ async createApiKey(name, scopes) {
273
+ const data = await this.gql(`mutation($name: String!, $scopes: [String!]!) {
274
+ createApiKey(name: $name, scopes: $scopes) {
275
+ id
276
+ key
277
+ name
278
+ scopes
279
+ }
280
+ }`, { name, scopes });
281
+ return data.createApiKey;
282
+ }
283
+ async listApiKeys() {
284
+ const data = await this.gql(`query {
285
+ myApiKeys {
286
+ id
287
+ name
288
+ keyPrefix
289
+ scopes
290
+ createdAt
291
+ }
292
+ }`);
293
+ return data.myApiKeys;
294
+ }
295
+ async deleteApiKey(id) {
296
+ await this.gql(`mutation($id: ID!) {
297
+ deleteApiKey(id: $id)
298
+ }`, { id });
299
+ }
300
+ async invalidateAllSessions() {
301
+ await this.gql(`mutation { invalidateAllSessions }`);
302
+ }
303
+ async getActiveDevices() {
304
+ const data = await this.gql(`query {
305
+ sdkActiveDevices {
306
+ id
307
+ browser
308
+ os
309
+ deviceType
310
+ lastActiveAt
311
+ createdAt
312
+ isCurrent
313
+ }
314
+ }`);
315
+ return data.sdkActiveDevices;
316
+ }
317
+ async revokeSession(sessionId) {
318
+ await this.gql(`mutation($sessionId: ID!) {
319
+ sdkRevokeSession(sessionId: $sessionId)
320
+ }`, { sessionId });
321
+ }
322
+ }
323
+ export {
324
+ Tribe as default,
325
+ Tribe
326
+ };
@@ -0,0 +1,94 @@
1
+ export interface User {
2
+ id: string;
3
+ email: string;
4
+ }
5
+ export interface Announcement {
6
+ id: string;
7
+ title: string;
8
+ message: string;
9
+ type: string;
10
+ }
11
+ export interface FeedbackOptions {
12
+ type?: string;
13
+ email?: string;
14
+ }
15
+ export interface ApiKey {
16
+ id: string;
17
+ name: string;
18
+ keyPrefix: string;
19
+ scopes: string[];
20
+ createdAt: string;
21
+ }
22
+ export interface ApiKeyResult {
23
+ id: string;
24
+ key: string;
25
+ name: string;
26
+ scopes: string[];
27
+ }
28
+ export interface ActiveDevice {
29
+ id: string;
30
+ browser: string;
31
+ os: string;
32
+ deviceType: string;
33
+ lastActiveAt: string;
34
+ createdAt: string;
35
+ isCurrent: boolean;
36
+ }
37
+ export interface ForgotPasswordOptions {
38
+ resetPasswordUrl?: string;
39
+ }
40
+ export interface ResendVerificationOptions {
41
+ verifyEmailUrl?: string;
42
+ }
43
+ export interface MagicLinkOptions {
44
+ magicLinkUrl?: string;
45
+ }
46
+ export interface AuthConfig {
47
+ authEnabled: boolean;
48
+ magicLinkEnabled: boolean;
49
+ captchaEnabled: boolean;
50
+ captchaProvider: string | null;
51
+ captchaSiteKey: string | null;
52
+ captchaRequiredForRegistration: boolean;
53
+ captchaRequiredForLogin: boolean;
54
+ breachedPasswordPolicy: string;
55
+ }
56
+ export interface TribeSDK {
57
+ register(email: string, password: string): Promise<{
58
+ user: User;
59
+ }>;
60
+ login(email: string, password: string): Promise<{
61
+ user: User;
62
+ }>;
63
+ logout(): Promise<void>;
64
+ getSession(): Promise<{
65
+ user: User;
66
+ } | null>;
67
+ track(eventName: string, data?: Record<string, unknown>): void;
68
+ feedback(message: string, options?: FeedbackOptions): Promise<void>;
69
+ getFeatureFlag(key: string): Promise<boolean>;
70
+ getAnnouncements(): Promise<Announcement[]>;
71
+ ackAnnouncement(announcementId: string): Promise<void>;
72
+ verifyEmail(token: string): Promise<void>;
73
+ resendVerification(options?: ResendVerificationOptions): Promise<void>;
74
+ forgotPassword(email: string, options?: ForgotPasswordOptions): Promise<void>;
75
+ resetPassword(token: string, newPassword: string): Promise<void>;
76
+ requestMagicLink(email: string, options?: MagicLinkOptions): Promise<void>;
77
+ verifyMagicLink(token: string): Promise<{
78
+ user: User;
79
+ }>;
80
+ getAuthConfig(): Promise<AuthConfig>;
81
+ getActiveDevices(): Promise<ActiveDevice[]>;
82
+ revokeSession(sessionId: string): Promise<void>;
83
+ setRole(role: string): Promise<User>;
84
+ createApiKey(name: string, scopes: string[]): Promise<ApiKeyResult>;
85
+ listApiKeys(): Promise<ApiKey[]>;
86
+ deleteApiKey(id: string): Promise<void>;
87
+ invalidateAllSessions(): Promise<void>;
88
+ }
89
+ export interface TribeConfig {
90
+ siteId: string;
91
+ baseUrl: string;
92
+ /** Whether to auto-track pageviews and navigation. Defaults to true. */
93
+ autoTrack?: boolean;
94
+ }
@@ -0,0 +1,87 @@
1
+ class A{siteId;baseUrl;sessionId;pageStart;currentPath;tokenKey;anonIdKey;autoTrackingActive=!1;originalPushState=null;popstateHandler=null;visibilityHandler=null;constructor(T){if(this.siteId=T.siteId,this.baseUrl=T.baseUrl,this.sessionId=Math.random().toString(36).slice(2),this.pageStart=Date.now(),this.currentPath=location.pathname,this.tokenKey=`__tribe_${T.siteId}`,this.anonIdKey=`__tribe_anon_${T.siteId}`,T.autoTrack!==!1)this.startAutoTracking()}static init(T){return new A(T)}startAutoTracking(){if(this.autoTrackingActive)return;this.autoTrackingActive=!0,this.sendEvent("pageview"),this.visibilityHandler=()=>{if(document.visibilityState==="hidden")this.sendEvent("leave",{d:Date.now()-this.pageStart})},document.addEventListener("visibilitychange",this.visibilityHandler),this.originalPushState=history.pushState,history.pushState=(...T)=>{this.sendEvent("leave",{d:Date.now()-this.pageStart}),this.originalPushState.apply(history,T),this.pageStart=Date.now(),this.currentPath=location.pathname,this.sendEvent("pageview")},this.popstateHandler=()=>{this.sendEvent("leave",{d:Date.now()-this.pageStart}),this.pageStart=Date.now(),this.currentPath=location.pathname,this.sendEvent("pageview")},window.addEventListener("popstate",this.popstateHandler)}stopAutoTracking(){if(!this.autoTrackingActive)return;if(this.autoTrackingActive=!1,this.visibilityHandler)document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null;if(this.originalPushState)history.pushState=this.originalPushState,this.originalPushState=null;if(this.popstateHandler)window.removeEventListener("popstate",this.popstateHandler),this.popstateHandler=null}sendEvent(T,E={}){let U={s:this.siteId,t:T,p:this.currentPath,r:document.referrer||null,sid:this.sessionId,w:screen.width,...E};if(navigator.sendBeacon){let _=new Blob([JSON.stringify(U)],{type:"application/json"});navigator.sendBeacon(`${this.baseUrl}/collect`,_)}else fetch(`${this.baseUrl}/collect`,{method:"POST",body:JSON.stringify(U),keepalive:!0,headers:{"Content-Type":"application/json"}}).catch(()=>{})}async gql(T,E){let U=localStorage.getItem(this.tokenKey),_={"Content-Type":"application/json"};if(U)_.Authorization=`Bearer ${U}`;else _["X-Tribe-Anonymous-Id"]=this.getAnonymousId();let B=await(await fetch(`${this.baseUrl}/graphql`,{method:"POST",headers:_,body:JSON.stringify({query:T,variables:E})})).json();if(B.errors)throw Error(B.errors[0].message);return B.data}getAnonymousId(){let T=localStorage.getItem(this.anonIdKey);if(!T)T=crypto.randomUUID(),localStorage.setItem(this.anonIdKey,T);return T}async register(T,E){let U=await this.gql(`mutation($siteId: ID!, $email: String!, $password: String!) {
2
+ sdkRegister(siteId: $siteId, email: $email, password: $password) {
3
+ token
4
+ user { id email }
5
+ }
6
+ }`,{siteId:this.siteId,email:T,password:E});return localStorage.setItem(this.tokenKey,U.sdkRegister.token),{user:U.sdkRegister.user}}async login(T,E){let U=await this.gql(`mutation($siteId: ID!, $email: String!, $password: String!) {
7
+ sdkLogin(siteId: $siteId, email: $email, password: $password) {
8
+ token
9
+ user { id email }
10
+ }
11
+ }`,{siteId:this.siteId,email:T,password:E});return localStorage.setItem(this.tokenKey,U.sdkLogin.token),{user:U.sdkLogin.user}}async logout(){try{await this.gql("mutation { sdkLogout }")}catch{}localStorage.removeItem(this.tokenKey)}async getSession(){if(!localStorage.getItem(this.tokenKey))return null;try{return(await this.gql("query { sdkSession { user { id email } } }")).sdkSession}catch{return localStorage.removeItem(this.tokenKey),null}}track(T,E){this.sendEvent("custom",{e:T,ed:E})}async feedback(T,E){let U=this.currentPath;await this.gql(`mutation($siteId: ID!, $message: String!, $type: String, $email: String, $url: String) {
12
+ submitFeedback(siteId: $siteId, message: $message, type: $type, email: $email, url: $url)
13
+ }`,{siteId:this.siteId,message:T,url:U,type:E?.type,email:E?.email})}async getFeatureFlag(T){return(await this.gql(`query($siteId: ID!) {
14
+ sdkFeatureFlags(siteId: $siteId) {
15
+ key
16
+ enabled
17
+ }
18
+ }`,{siteId:this.siteId})).sdkFeatureFlags.find((_)=>_.key===T)?.enabled??!1}async getAnnouncements(){let T=await this.gql(`query($siteId: ID!) {
19
+ activeAnnouncements(siteId: $siteId) {
20
+ id
21
+ title
22
+ message
23
+ type
24
+ }
25
+ }`,{siteId:this.siteId}),E=`__tribe_dismissed_${this.siteId}`,U=JSON.parse(localStorage.getItem(E)||"[]");return T.activeAnnouncements.filter((_)=>!U.includes(_.id))}async ackAnnouncement(T){let E=`__tribe_dismissed_${this.siteId}`,U=JSON.parse(localStorage.getItem(E)||"[]");if(!U.includes(T))U.push(T),localStorage.setItem(E,JSON.stringify(U));try{await this.gql(`mutation($announcementId: ID!) {
26
+ ackAnnouncement(announcementId: $announcementId)
27
+ }`,{announcementId:T})}catch{}}async verifyEmail(T){await this.gql(`mutation($token: String!) {
28
+ verifyEmail(token: $token)
29
+ }`,{token:T})}async resendVerification(T){await this.gql(`mutation($verifyEmailUrl: String) {
30
+ resendVerification(verifyEmailUrl: $verifyEmailUrl)
31
+ }`,{verifyEmailUrl:T?.verifyEmailUrl})}async forgotPassword(T,E){await this.gql(`mutation($siteId: ID!, $email: String!, $resetPasswordUrl: String) {
32
+ forgotPassword(siteId: $siteId, email: $email, resetPasswordUrl: $resetPasswordUrl)
33
+ }`,{siteId:this.siteId,email:T,resetPasswordUrl:E?.resetPasswordUrl})}async resetPassword(T,E){await this.gql(`mutation($token: String!, $newPassword: String!) {
34
+ resetPassword(token: $token, newPassword: $newPassword)
35
+ }`,{token:T,newPassword:E})}async requestMagicLink(T,E){await this.gql(`mutation($siteId: ID!, $email: String!, $magicLinkUrl: String) {
36
+ requestMagicLink(siteId: $siteId, email: $email, magicLinkUrl: $magicLinkUrl)
37
+ }`,{siteId:this.siteId,email:T,magicLinkUrl:E?.magicLinkUrl})}async verifyMagicLink(T){let E=await this.gql(`mutation($token: String!) {
38
+ verifyMagicLink(token: $token) {
39
+ token
40
+ user { id email }
41
+ }
42
+ }`,{token:T});return localStorage.setItem(this.tokenKey,E.verifyMagicLink.token),{user:E.verifyMagicLink.user}}async getAuthConfig(){return(await this.gql(`query($siteId: ID!) {
43
+ siteAuthConfig(siteId: $siteId) {
44
+ authEnabled
45
+ magicLinkEnabled
46
+ captchaEnabled
47
+ captchaProvider
48
+ captchaSiteKey
49
+ captchaRequiredForRegistration
50
+ captchaRequiredForLogin
51
+ breachedPasswordPolicy
52
+ }
53
+ }`,{siteId:this.siteId})).siteAuthConfig}async setRole(T){return(await this.gql(`mutation($role: String!) {
54
+ setRole(role: $role) {
55
+ id
56
+ email
57
+ }
58
+ }`,{role:T})).setRole}async createApiKey(T,E){return(await this.gql(`mutation($name: String!, $scopes: [String!]!) {
59
+ createApiKey(name: $name, scopes: $scopes) {
60
+ id
61
+ key
62
+ name
63
+ scopes
64
+ }
65
+ }`,{name:T,scopes:E})).createApiKey}async listApiKeys(){return(await this.gql(`query {
66
+ myApiKeys {
67
+ id
68
+ name
69
+ keyPrefix
70
+ scopes
71
+ createdAt
72
+ }
73
+ }`)).myApiKeys}async deleteApiKey(T){await this.gql(`mutation($id: ID!) {
74
+ deleteApiKey(id: $id)
75
+ }`,{id:T})}async invalidateAllSessions(){await this.gql("mutation { invalidateAllSessions }")}async getActiveDevices(){return(await this.gql(`query {
76
+ sdkActiveDevices {
77
+ id
78
+ browser
79
+ os
80
+ deviceType
81
+ lastActiveAt
82
+ createdAt
83
+ isCurrent
84
+ }
85
+ }`)).sdkActiveDevices}async revokeSession(T){await this.gql(`mutation($sessionId: ID!) {
86
+ sdkRevokeSession(sessionId: $sessionId)
87
+ }`,{sessionId:T})}}var D="SITE_ID",L="BASE_URL",R=new A({siteId:D,baseUrl:L,autoTrack:!0});window.Tribe=R;
@@ -0,0 +1,87 @@
1
+ (function(X,G,V){let $=Math.random().toString(36).slice(2),M=Date.now(),Q=location.pathname,J=`__tribe_${G}`,Z=`__tribe_anon_${G}`;function R(){let z=localStorage.getItem(Z);if(!z)z=crypto.randomUUID(),localStorage.setItem(Z,z);return z}function L(z,B={}){let F={s:G,t:z,p:Q,r:document.referrer||null,sid:$,w:screen.width,...B};if(navigator.sendBeacon){let H=new Blob([JSON.stringify(F)],{type:"application/json"});navigator.sendBeacon(`${V}/collect`,H)}else fetch(`${V}/collect`,{method:"POST",body:JSON.stringify(F),keepalive:!0,headers:{"Content-Type":"application/json"}}).catch(()=>{})}L("pageview"),document.addEventListener("visibilitychange",()=>{if(document.visibilityState==="hidden")L("leave",{d:Date.now()-M})});let f=history.pushState;history.pushState=function(...z){L("leave",{d:Date.now()-M}),f.apply(history,z),M=Date.now(),Q=location.pathname,L("pageview")},X.addEventListener("popstate",()=>{L("leave",{d:Date.now()-M}),M=Date.now(),Q=location.pathname,L("pageview")});async function C(z,B){let F=localStorage.getItem(J),H={"Content-Type":"application/json"};if(F)H.Authorization=`Bearer ${F}`;else H["X-Tribe-Anonymous-Id"]=R();let W=await(await fetch(`${V}/graphql`,{method:"POST",headers:H,body:JSON.stringify({query:z,variables:B})})).json();if(W.errors)throw Error(W.errors[0].message);return W.data}let x={async register(z,B){let F=await C(`mutation($siteId: ID!, $email: String!, $password: String!) {
2
+ sdkRegister(siteId: $siteId, email: $email, password: $password) {
3
+ token
4
+ user { id email }
5
+ }
6
+ }`,{siteId:G,email:z,password:B});return localStorage.setItem(J,F.sdkRegister.token),{user:F.sdkRegister.user}},async login(z,B){let F=await C(`mutation($siteId: ID!, $email: String!, $password: String!) {
7
+ sdkLogin(siteId: $siteId, email: $email, password: $password) {
8
+ token
9
+ user { id email }
10
+ }
11
+ }`,{siteId:G,email:z,password:B});return localStorage.setItem(J,F.sdkLogin.token),{user:F.sdkLogin.user}},async logout(){try{await C("mutation { sdkLogout }")}catch{}localStorage.removeItem(J)},async getSession(){if(!localStorage.getItem(J))return null;try{return(await C("query { sdkSession { user { id email } } }")).sdkSession}catch{return localStorage.removeItem(J),null}},track(z,B){L("custom",{e:z,ed:B})},async feedback(z,B){await C(`mutation($siteId: ID!, $message: String!, $type: String, $email: String, $url: String) {
12
+ submitFeedback(siteId: $siteId, message: $message, type: $type, email: $email, url: $url)
13
+ }`,{siteId:G,message:z,url:Q,type:B?.type,email:B?.email})},async getFeatureFlag(z){return(await C(`query($siteId: ID!) {
14
+ sdkFeatureFlags(siteId: $siteId) {
15
+ key
16
+ enabled
17
+ }
18
+ }`,{siteId:G})).sdkFeatureFlags.find((H)=>H.key===z)?.enabled??!1},async getAnnouncements(){let z=await C(`query($siteId: ID!) {
19
+ activeAnnouncements(siteId: $siteId) {
20
+ id
21
+ title
22
+ message
23
+ type
24
+ }
25
+ }`,{siteId:G}),B=`__tribe_dismissed_${G}`,F=JSON.parse(localStorage.getItem(B)||"[]");return z.activeAnnouncements.filter((H)=>!F.includes(H.id))},async ackAnnouncement(z){let B=`__tribe_dismissed_${G}`,F=JSON.parse(localStorage.getItem(B)||"[]");if(!F.includes(z))F.push(z),localStorage.setItem(B,JSON.stringify(F));try{await C(`mutation($announcementId: ID!) {
26
+ ackAnnouncement(announcementId: $announcementId)
27
+ }`,{announcementId:z})}catch{}},async verifyEmail(z){await C(`mutation($token: String!) {
28
+ verifyEmail(token: $token)
29
+ }`,{token:z})},async resendVerification(z){await C(`mutation($verifyEmailUrl: String) {
30
+ resendVerification(verifyEmailUrl: $verifyEmailUrl)
31
+ }`,{verifyEmailUrl:z?.verifyEmailUrl})},async forgotPassword(z,B){await C(`mutation($siteId: ID!, $email: String!, $resetPasswordUrl: String) {
32
+ forgotPassword(siteId: $siteId, email: $email, resetPasswordUrl: $resetPasswordUrl)
33
+ }`,{siteId:G,email:z,resetPasswordUrl:B?.resetPasswordUrl})},async resetPassword(z,B){await C(`mutation($token: String!, $newPassword: String!) {
34
+ resetPassword(token: $token, newPassword: $newPassword)
35
+ }`,{token:z,newPassword:B})},async requestMagicLink(z,B){await C(`mutation($siteId: ID!, $email: String!, $magicLinkUrl: String) {
36
+ requestMagicLink(siteId: $siteId, email: $email, magicLinkUrl: $magicLinkUrl)
37
+ }`,{siteId:G,email:z,magicLinkUrl:B?.magicLinkUrl})},async verifyMagicLink(z){let B=await C(`mutation($token: String!) {
38
+ verifyMagicLink(token: $token) {
39
+ token
40
+ user { id email }
41
+ }
42
+ }`,{token:z});return localStorage.setItem(J,B.verifyMagicLink.token),{user:B.verifyMagicLink.user}},async getAuthConfig(){return(await C(`query($siteId: ID!) {
43
+ siteAuthConfig(siteId: $siteId) {
44
+ authEnabled
45
+ magicLinkEnabled
46
+ captchaEnabled
47
+ captchaProvider
48
+ captchaSiteKey
49
+ captchaRequiredForRegistration
50
+ captchaRequiredForLogin
51
+ breachedPasswordPolicy
52
+ }
53
+ }`,{siteId:G})).siteAuthConfig},async setRole(z){return(await C(`mutation($role: String!) {
54
+ setRole(role: $role) {
55
+ id
56
+ email
57
+ }
58
+ }`,{role:z})).setRole},async createApiKey(z,B){return(await C(`mutation($name: String!, $scopes: [String!]!) {
59
+ createApiKey(name: $name, scopes: $scopes) {
60
+ id
61
+ key
62
+ name
63
+ scopes
64
+ }
65
+ }`,{name:z,scopes:B})).createApiKey},async listApiKeys(){return(await C(`query {
66
+ myApiKeys {
67
+ id
68
+ name
69
+ keyPrefix
70
+ scopes
71
+ createdAt
72
+ }
73
+ }`)).myApiKeys},async deleteApiKey(z){await C(`mutation($id: ID!) {
74
+ deleteApiKey(id: $id)
75
+ }`,{id:z})},async invalidateAllSessions(){await C("mutation { invalidateAllSessions }")},async getActiveDevices(){return(await C(`query {
76
+ sdkActiveDevices {
77
+ id
78
+ browser
79
+ os
80
+ deviceType
81
+ lastActiveAt
82
+ createdAt
83
+ isCurrent
84
+ }
85
+ }`)).sdkActiveDevices},async revokeSession(z){await C(`mutation($sessionId: ID!) {
86
+ sdkRevokeSession(sessionId: $sessionId)
87
+ }`,{sessionId:z})}};X.Tribe=x})(window,"SITE_ID","BASE_URL");
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@tribecloud/sdk",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "dist/esm/index.js",
6
+ "module": "dist/esm/index.js",
7
+ "types": "dist/esm/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/esm/index.d.ts",
12
+ "default": "./dist/esm/index.js"
13
+ }
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "bun run build:iife && bun run build:esm && bun run build:types",
21
+ "build:iife": "bun build src/iife.ts --outfile dist/iife/sdk.min.js --minify --target browser",
22
+ "build:esm": "bun build src/index.ts --outfile dist/esm/index.js --target browser --format esm",
23
+ "build:types": "bunx tsc --project tsconfig.build.json",
24
+ "dev": "bun build src/iife.ts --outfile dist/iife/sdk.min.js --target browser --watch",
25
+ "test": "bun test",
26
+ "test:watch": "bun test --watch"
27
+ },
28
+ "devDependencies": {
29
+ "@types/bun": "latest",
30
+ "typescript": "^5"
31
+ }
32
+ }