glitch-javascript-sdk 3.0.4 → 3.0.6

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.
@@ -1,8 +1,10 @@
1
1
  declare class Storage {
2
2
  private static rootDomain;
3
3
  private static data;
4
+ private static crossDomainKeys;
4
5
  static setRootDomain(rootDomain: string): void;
5
6
  private static getStorageKey;
7
+ private static shouldShareAcrossSubdomains;
6
8
  static set(key: string, value: any): void;
7
9
  static get(key: string): any;
8
10
  static setAuthToken(token: string | null): void;
package/dist/index.d.ts CHANGED
@@ -5488,6 +5488,15 @@ declare class Subscriptions {
5488
5488
  * @returns promise
5489
5489
  */
5490
5490
  static cancelGift<T>(gift_id: string): AxiosPromise<Response<T>>;
5491
+ /**
5492
+ * Validates a coupon code and returns the calculated discount.
5493
+ * @param data { code: string, price: number, currency?: string }
5494
+ */
5495
+ static validateCoupon<T>(data: {
5496
+ code: string;
5497
+ price: number;
5498
+ currency?: string;
5499
+ }): AxiosPromise<Response<T>>;
5491
5500
  }
5492
5501
 
5493
5502
  declare class Messages {
@@ -8070,8 +8079,10 @@ declare class Session {
8070
8079
  declare class Storage {
8071
8080
  private static rootDomain;
8072
8081
  private static data;
8082
+ private static crossDomainKeys;
8073
8083
  static setRootDomain(rootDomain: string): void;
8074
8084
  private static getStorageKey;
8085
+ private static shouldShareAcrossSubdomains;
8075
8086
  static set(key: string, value: any): void;
8076
8087
  static get(key: string): any;
8077
8088
  static setAuthToken(token: string | null): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glitch-javascript-sdk",
3
- "version": "3.0.4",
3
+ "version": "3.0.6",
4
4
  "description": "Javascript SDK for Glitch",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -175,6 +175,14 @@ class Subscriptions {
175
175
  return Requests.processRoute(SubscriptionsRoute.routes.cancelGift, {}, { gift_id });
176
176
  }
177
177
 
178
+ /**
179
+ * Validates a coupon code and returns the calculated discount.
180
+ * @param data { code: string, price: number, currency?: string }
181
+ */
182
+ public static validateCoupon<T>(data: { code: string, price: number, currency?: string }): AxiosPromise<Response<T>> {
183
+ return Requests.processRoute(SubscriptionsRoute.routes.validateCoupon, data);
184
+ }
185
+
178
186
  }
179
187
 
180
188
  export default Subscriptions;
@@ -28,6 +28,8 @@ class SubscriptionsRoute {
28
28
  redeemGift: { url: '/subscriptions/gifts/redeem', method: HTTP_METHODS.POST },
29
29
  cancelGift: { url: '/subscriptions/gifts/{gift_id}', method: HTTP_METHODS.DELETE },
30
30
 
31
+ validateCoupon: { url: '/subscriptions/coupons/validate', method: HTTP_METHODS.POST },
32
+
31
33
  };
32
34
 
33
35
  }
@@ -2,6 +2,18 @@ class Storage {
2
2
  private static rootDomain: string = '';
3
3
  private static data: { [key: string]: any } = {};
4
4
 
5
+ private static crossDomainKeys = new Set([
6
+ 'glitch_auth_token',
7
+ 'glitch_token_expiry',
8
+ 'user_id',
9
+ 'user_first_name',
10
+ 'user_last_name',
11
+ 'username',
12
+ 'email',
13
+ 'session_id',
14
+ 'community_id',
15
+ ]);
16
+
5
17
  public static setRootDomain(rootDomain: string) {
6
18
  Storage.rootDomain = rootDomain;
7
19
  }
@@ -10,11 +22,13 @@ class Storage {
10
22
  return Storage.rootDomain ? `${Storage.rootDomain}:${key}` : key;
11
23
  }
12
24
 
25
+ private static shouldShareAcrossSubdomains(key: string): boolean {
26
+ return !!Storage.rootDomain && Storage.crossDomainKeys.has(key);
27
+ }
28
+
13
29
  public static set(key: string, value: any) {
14
- // 1. Always update in-memory fallback for the current process
15
30
  Storage.data[key] = value;
16
31
 
17
- // 2. Only attempt browser storage if window exists
18
32
  if (typeof window !== 'undefined') {
19
33
  try {
20
34
  const serializedValue = JSON.stringify(value);
@@ -23,17 +37,32 @@ class Storage {
23
37
  try {
24
38
  const serializedValue = JSON.stringify(value);
25
39
  window.sessionStorage.setItem(Storage.getStorageKey(key), serializedValue);
26
- } catch (e) {
27
- try {
28
- this.setCookie(key, value, 31);
29
- } catch (e) {}
30
- }
40
+ } catch (e) {}
41
+ }
42
+ }
43
+
44
+ // Important: shared session keys must be written to a root-domain cookie.
45
+ if (Storage.shouldShareAcrossSubdomains(key)) {
46
+ if (value === null || value === undefined) {
47
+ Storage.eraseCookie(key);
48
+ } else {
49
+ Storage.setCookie(key, value, 31);
31
50
  }
32
51
  }
33
52
  }
34
53
 
35
54
  public static get(key: string): any {
36
- // 1. Try Browser Storage if available
55
+ // Important: for shared session keys, cookie must win over localStorage.
56
+ // Otherwise stale www.glitch.fun localStorage can override the real shared cookie.
57
+ if (Storage.shouldShareAcrossSubdomains(key)) {
58
+ try {
59
+ const cookieValue = Storage.getCookie(key);
60
+ if (cookieValue !== null && cookieValue !== undefined && cookieValue !== 'null') {
61
+ return cookieValue;
62
+ }
63
+ } catch (e) {}
64
+ }
65
+
37
66
  if (typeof window !== 'undefined') {
38
67
  try {
39
68
  const serializedValue = window.localStorage.getItem(Storage.getStorageKey(key));
@@ -46,98 +75,96 @@ class Storage {
46
75
  }
47
76
  }
48
77
 
49
- // 2. Try Cookie (getCookie is now SSR safe)
50
- let value = null;
51
78
  try {
52
- value = Storage.getCookie(key);
79
+ const cookieValue = Storage.getCookie(key);
80
+ if (cookieValue !== null && cookieValue !== undefined && cookieValue !== 'null') {
81
+ return cookieValue;
82
+ }
53
83
  } catch (e) {}
54
84
 
55
- // 3. Fallback to in-memory data
56
- if (!value) {
57
- value = Storage.data[key];
58
- }
59
- return value;
85
+ return Storage.data[key];
60
86
  }
61
87
 
62
88
  public static setAuthToken(token: string | null) {
63
- if (Storage.rootDomain) {
64
- if (token) {
65
- this.setCookie('glitch_auth_token', token, 31);
66
- } else {
67
- this.eraseCookie('glitch_auth_token');
68
- }
69
- }
70
89
  Storage.set('glitch_auth_token', token);
71
90
  }
72
91
 
73
92
  public static getAuthToken(): string | null {
74
- let token = Storage.getCookie('glitch_auth_token');
75
-
76
- if (!token || token === 'null') {
77
- token = Storage.get('glitch_auth_token');
78
- }
79
-
80
- return (token === 'null' || !token) ? null : token;
93
+ const token = Storage.get('glitch_auth_token');
94
+ return token === 'null' || !token ? null : token;
81
95
  }
82
96
 
83
97
  public static eraseCookie(name: string) {
84
- // Use typeof check to prevent ReferenceError
85
- if (typeof document !== 'undefined') {
98
+ if (typeof document === 'undefined') return;
99
+
100
+ // Clear host-only cookie.
101
+ document.cookie =
102
+ `${name}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax; Secure`;
103
+
104
+ // Clear root-domain cookie.
105
+ if (Storage.rootDomain) {
86
106
  document.cookie =
87
- name +
88
- '=; Secure; HttpOnly=false; SameSite=none; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
107
+ `${name}=; Path=/; Domain=${Storage.rootDomain}; Expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax; Secure`;
89
108
  }
90
109
  }
91
110
 
92
- private static setCookie(name: string, value: string, days: number) {
111
+ private static setCookie(name: string, value: any, days: number) {
93
112
  let expires = '';
113
+
94
114
  if (days) {
95
115
  const date = new Date();
96
116
  date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
97
- expires = '; expires=' + date.toUTCString();
117
+ expires = '; Expires=' + date.toUTCString();
98
118
  }
99
119
 
100
120
  if (typeof document !== 'undefined') {
121
+ const encodedValue = encodeURIComponent(JSON.stringify(value));
122
+
101
123
  document.cookie =
102
- name +
103
- '=' +
104
- (value || '') +
105
- expires +
106
- '; path=/; domain=' +
107
- Storage.rootDomain +
108
- '; SameSite=Lax; Secure';
124
+ `${name}=${encodedValue}${expires}; Path=/; Domain=${Storage.rootDomain}; SameSite=Lax; Secure`;
109
125
  }
110
126
  }
111
127
 
112
- private static getCookie(name: string): string | null {
113
- // Use typeof check to prevent ReferenceError
128
+ private static getCookie(name: string): any {
114
129
  if (typeof document !== 'undefined') {
115
130
  const nameEQ = name + '=';
116
131
  const ca = document.cookie.split(';');
132
+
117
133
  for (let i = 0; i < ca.length; i++) {
118
134
  let c = ca[i];
119
- while (c.charAt(0) == ' ') c = c.substring(1, c.length);
120
- if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
135
+
136
+ while (c.charAt(0) === ' ') {
137
+ c = c.substring(1, c.length);
138
+ }
139
+
140
+ if (c.indexOf(nameEQ) === 0) {
141
+ const rawValue = c.substring(nameEQ.length, c.length);
142
+
143
+ try {
144
+ const decodedValue = decodeURIComponent(rawValue);
145
+ return JSON.parse(decodedValue);
146
+ } catch (e) {
147
+ try {
148
+ return decodeURIComponent(rawValue);
149
+ } catch (e2) {
150
+ return rawValue;
151
+ }
152
+ }
153
+ }
121
154
  }
122
155
  }
156
+
123
157
  return null;
124
158
  }
125
159
 
126
160
  public static setTokenExpiry(expiresInSeconds: number) {
127
- const expiryTime = Date.now() + (expiresInSeconds * 1000);
161
+ const expiryTime = Date.now() + expiresInSeconds * 1000;
128
162
  Storage.set('glitch_token_expiry', expiryTime);
129
-
130
- if (Storage.rootDomain && typeof document !== 'undefined') {
131
- this.setCookie('glitch_token_expiry', expiryTime.toString(), 31);
132
- }
133
163
  }
134
164
 
135
165
  public static getTokenExpiry(): number | null {
136
- let expiry = Storage.getCookie('glitch_token_expiry');
137
- if (!expiry) {
138
- expiry = Storage.get('glitch_token_expiry');
139
- }
140
- return expiry ? parseInt(expiry) : null;
166
+ const expiry = Storage.get('glitch_token_expiry');
167
+ return expiry ? parseInt(String(expiry), 10) : null;
141
168
  }
142
169
 
143
170
  public static isTokenExpired(): boolean {