@growsober/sdk 1.0.31 → 1.0.32

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,11 @@
1
+ <claude-mem-context>
2
+ # Recent Activity
3
+
4
+ <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
+
6
+ ### Jan 25, 2026
7
+
8
+ | ID | Time | T | Title | Read |
9
+ |----|------|---|-------|------|
10
+ | #1208 | 3:28 AM | 🔵 | UserResponse data structure includes comprehensive profile and notification settings | ~580 |
11
+ </claude-mem-context>
@@ -27,6 +27,8 @@ function createApiClient(sdkConfig) {
27
27
  'Content-Type': 'application/json',
28
28
  },
29
29
  });
30
+ // Track ongoing refresh to avoid duplicate calls
31
+ let refreshPromise = null;
30
32
  // Request interceptor - add auth token
31
33
  client.interceptors.request.use(async (requestConfig) => {
32
34
  const token = await sdkConfig.getAccessToken();
@@ -44,17 +46,26 @@ function createApiClient(sdkConfig) {
44
46
  }
45
47
  return response;
46
48
  }, async (error) => {
47
- if (error.response?.status === 401) {
49
+ const originalRequest = error.config;
50
+ if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
51
+ originalRequest._retry = true;
48
52
  if (sdkConfig.refreshAccessToken) {
49
53
  try {
50
- const newToken = await sdkConfig.refreshAccessToken();
51
- if (newToken && error.config) {
52
- error.config.headers.Authorization = `Bearer ${newToken}`;
53
- return client.request(error.config);
54
+ // Deduplicate concurrent refresh calls
55
+ if (!refreshPromise) {
56
+ refreshPromise = sdkConfig.refreshAccessToken().finally(() => {
57
+ refreshPromise = null;
58
+ });
59
+ }
60
+ const newToken = await refreshPromise;
61
+ if (newToken) {
62
+ originalRequest.headers.Authorization = `Bearer ${newToken}`;
63
+ return client.request(originalRequest);
54
64
  }
55
65
  }
56
66
  catch {
57
67
  sdkConfig.onUnauthorized?.();
68
+ return Promise.reject(error);
58
69
  }
59
70
  }
60
71
  else {
@@ -65,4 +76,4 @@ function createApiClient(sdkConfig) {
65
76
  });
66
77
  return client;
67
78
  }
68
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBWUEsb0NBR0M7QUFFRCxvQ0FLQztBQXRCRCxrREFBcUY7QUFTckYsSUFBSSxNQUFNLEdBQXFCLElBQUksQ0FBQztBQUNwQyxJQUFJLFNBQVMsR0FBeUIsSUFBSSxDQUFDO0FBbUVsQyw4QkFBUztBQWpFbEIsU0FBZ0IsWUFBWSxDQUFDLFNBQW9CO0lBQy9DLE1BQU0sR0FBRyxTQUFTLENBQUM7SUFDbkIsb0JBQUEsU0FBUyxHQUFHLGVBQWUsQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN6QyxDQUFDO0FBRUQsU0FBZ0IsWUFBWTtJQUMxQixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDZixNQUFNLElBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7SUFDcEUsQ0FBQztJQUNELE9BQU8sU0FBUyxDQUFDO0FBQ25CLENBQUM7QUFFRCxTQUFTLGVBQWUsQ0FBQyxTQUFvQjtJQUMzQyxNQUFNLE1BQU0sR0FBRyxlQUFLLENBQUMsTUFBTSxDQUFDO1FBQzFCLE9BQU8sRUFBRSxTQUFTLENBQUMsT0FBTztRQUMxQixPQUFPLEVBQUU7WUFDUCxjQUFjLEVBQUUsa0JBQWtCO1NBQ25DO0tBQ0YsQ0FBQyxDQUFDO0lBRUgsdUNBQXVDO0lBQ3ZDLE1BQU0sQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FDN0IsS0FBSyxFQUFFLGFBQXlDLEVBQUUsRUFBRTtRQUNsRCxNQUFNLEtBQUssR0FBRyxNQUFNLFNBQVMsQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUMvQyxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsYUFBYSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEdBQUcsVUFBVSxLQUFLLEVBQUUsQ0FBQztRQUMxRCxDQUFDO1FBQ0QsT0FBTyxhQUFhLENBQUM7SUFDdkIsQ0FBQyxFQUNELENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUNqQyxDQUFDO0lBRUYsNERBQTREO0lBQzVELE1BQU0sQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FDOUIsQ0FBQyxRQUFRLEVBQUUsRUFBRTtRQUNYLHNEQUFzRDtRQUN0RCx5Q0FBeUM7UUFDekMsSUFBSSxRQUFRLENBQUMsSUFBSSxJQUFJLE9BQU8sUUFBUSxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksTUFBTSxJQUFJLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNsRixRQUFRLENBQUMsSUFBSSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1FBQ3JDLENBQUM7UUFDRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDLEVBQ0QsS0FBSyxFQUFFLEtBQWlCLEVBQUUsRUFBRTtRQUMxQixJQUFJLEtBQUssQ0FBQyxRQUFRLEVBQUUsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQ25DLElBQUksU0FBUyxDQUFDLGtCQUFrQixFQUFFLENBQUM7Z0JBQ2pDLElBQUksQ0FBQztvQkFDSCxNQUFNLFFBQVEsR0FBRyxNQUFNLFNBQVMsQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO29CQUN0RCxJQUFJLFFBQVEsSUFBSSxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7d0JBQzdCLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLGFBQWEsR0FBRyxVQUFVLFFBQVEsRUFBRSxDQUFDO3dCQUMxRCxPQUFPLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUN0QyxDQUFDO2dCQUNILENBQUM7Z0JBQUMsTUFBTSxDQUFDO29CQUNQLFNBQVMsQ0FBQyxjQUFjLEVBQUUsRUFBRSxDQUFDO2dCQUMvQixDQUFDO1lBQ0gsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLFNBQVMsQ0FBQyxjQUFjLEVBQUUsRUFBRSxDQUFDO1lBQy9CLENBQUM7UUFDSCxDQUFDO1FBQ0QsT0FBTyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQy9CLENBQUMsQ0FDRixDQUFDO0lBRUYsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBheGlvcywgeyBBeGlvc0luc3RhbmNlLCBBeGlvc0Vycm9yLCBJbnRlcm5hbEF4aW9zUmVxdWVzdENvbmZpZyB9IGZyb20gJ2F4aW9zJztcblxuZXhwb3J0IGludGVyZmFjZSBTREtDb25maWcge1xuICBiYXNlVVJMOiBzdHJpbmc7XG4gIGdldEFjY2Vzc1Rva2VuOiAoKSA9PiBzdHJpbmcgfCBudWxsIHwgUHJvbWlzZTxzdHJpbmcgfCBudWxsPjtcbiAgcmVmcmVzaEFjY2Vzc1Rva2VuPzogKCkgPT4gUHJvbWlzZTxzdHJpbmc+O1xuICBvblVuYXV0aG9yaXplZD86ICgpID0+IHZvaWQ7XG59XG5cbmxldCBjb25maWc6IFNES0NvbmZpZyB8IG51bGwgPSBudWxsO1xubGV0IGFwaUNsaWVudDogQXhpb3NJbnN0YW5jZSB8IG51bGwgPSBudWxsO1xuXG5leHBvcnQgZnVuY3Rpb24gY29uZmlndXJlU0RLKHNka0NvbmZpZzogU0RLQ29uZmlnKTogdm9pZCB7XG4gIGNvbmZpZyA9IHNka0NvbmZpZztcbiAgYXBpQ2xpZW50ID0gY3JlYXRlQXBpQ2xpZW50KHNka0NvbmZpZyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRBcGlDbGllbnQoKTogQXhpb3NJbnN0YW5jZSB7XG4gIGlmICghYXBpQ2xpZW50KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdTREsgbm90IGNvbmZpZ3VyZWQuIENhbGwgY29uZmlndXJlU0RLKCkgZmlyc3QuJyk7XG4gIH1cbiAgcmV0dXJuIGFwaUNsaWVudDtcbn1cblxuZnVuY3Rpb24gY3JlYXRlQXBpQ2xpZW50KHNka0NvbmZpZzogU0RLQ29uZmlnKTogQXhpb3NJbnN0YW5jZSB7XG4gIGNvbnN0IGNsaWVudCA9IGF4aW9zLmNyZWF0ZSh7XG4gICAgYmFzZVVSTDogc2RrQ29uZmlnLmJhc2VVUkwsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICB9LFxuICB9KTtcblxuICAvLyBSZXF1ZXN0IGludGVyY2VwdG9yIC0gYWRkIGF1dGggdG9rZW5cbiAgY2xpZW50LmludGVyY2VwdG9ycy5yZXF1ZXN0LnVzZShcbiAgICBhc3luYyAocmVxdWVzdENvbmZpZzogSW50ZXJuYWxBeGlvc1JlcXVlc3RDb25maWcpID0+IHtcbiAgICAgIGNvbnN0IHRva2VuID0gYXdhaXQgc2RrQ29uZmlnLmdldEFjY2Vzc1Rva2VuKCk7XG4gICAgICBpZiAodG9rZW4pIHtcbiAgICAgICAgcmVxdWVzdENvbmZpZy5oZWFkZXJzLkF1dGhvcml6YXRpb24gPSBgQmVhcmVyICR7dG9rZW59YDtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXF1ZXN0Q29uZmlnO1xuICAgIH0sXG4gICAgKGVycm9yKSA9PiBQcm9taXNlLnJlamVjdChlcnJvcilcbiAgKTtcblxuICAvLyBSZXNwb25zZSBpbnRlcmNlcHRvciAtIHVud3JhcCBBUEkgcmVzcG9uc2UgYW5kIGhhbmRsZSA0MDFcbiAgY2xpZW50LmludGVyY2VwdG9ycy5yZXNwb25zZS51c2UoXG4gICAgKHJlc3BvbnNlKSA9PiB7XG4gICAgICAvLyBBUEkgd3JhcHMgYWxsIHJlc3BvbnNlcyBpbiB7ZGF0YTogLi4uLCBtZXRhOiB7Li4ufX1cbiAgICAgIC8vIFVud3JhcCB0byByZXR1cm4ganVzdCB0aGUgZGF0YSBwb3J0aW9uXG4gICAgICBpZiAocmVzcG9uc2UuZGF0YSAmJiB0eXBlb2YgcmVzcG9uc2UuZGF0YSA9PT0gJ29iamVjdCcgJiYgJ2RhdGEnIGluIHJlc3BvbnNlLmRhdGEpIHtcbiAgICAgICAgcmVzcG9uc2UuZGF0YSA9IHJlc3BvbnNlLmRhdGEuZGF0YTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXNwb25zZTtcbiAgICB9LFxuICAgIGFzeW5jIChlcnJvcjogQXhpb3NFcnJvcikgPT4ge1xuICAgICAgaWYgKGVycm9yLnJlc3BvbnNlPy5zdGF0dXMgPT09IDQwMSkge1xuICAgICAgICBpZiAoc2RrQ29uZmlnLnJlZnJlc2hBY2Nlc3NUb2tlbikge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBuZXdUb2tlbiA9IGF3YWl0IHNka0NvbmZpZy5yZWZyZXNoQWNjZXNzVG9rZW4oKTtcbiAgICAgICAgICAgIGlmIChuZXdUb2tlbiAmJiBlcnJvci5jb25maWcpIHtcbiAgICAgICAgICAgICAgZXJyb3IuY29uZmlnLmhlYWRlcnMuQXV0aG9yaXphdGlvbiA9IGBCZWFyZXIgJHtuZXdUb2tlbn1gO1xuICAgICAgICAgICAgICByZXR1cm4gY2xpZW50LnJlcXVlc3QoZXJyb3IuY29uZmlnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIHNka0NvbmZpZy5vblVuYXV0aG9yaXplZD8uKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNka0NvbmZpZy5vblVuYXV0aG9yaXplZD8uKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChlcnJvcik7XG4gICAgfVxuICApO1xuXG4gIHJldHVybiBjbGllbnQ7XG59XG5cbmV4cG9ydCB7IGFwaUNsaWVudCB9O1xuIl19
79
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBWUEsb0NBR0M7QUFFRCxvQ0FLQztBQXRCRCxrREFBcUY7QUFTckYsSUFBSSxNQUFNLEdBQXFCLElBQUksQ0FBQztBQUNwQyxJQUFJLFNBQVMsR0FBeUIsSUFBSSxDQUFDO0FBa0ZsQyw4QkFBUztBQWhGbEIsU0FBZ0IsWUFBWSxDQUFDLFNBQW9CO0lBQy9DLE1BQU0sR0FBRyxTQUFTLENBQUM7SUFDbkIsb0JBQUEsU0FBUyxHQUFHLGVBQWUsQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN6QyxDQUFDO0FBRUQsU0FBZ0IsWUFBWTtJQUMxQixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDZixNQUFNLElBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7SUFDcEUsQ0FBQztJQUNELE9BQU8sU0FBUyxDQUFDO0FBQ25CLENBQUM7QUFFRCxTQUFTLGVBQWUsQ0FBQyxTQUFvQjtJQUMzQyxNQUFNLE1BQU0sR0FBRyxlQUFLLENBQUMsTUFBTSxDQUFDO1FBQzFCLE9BQU8sRUFBRSxTQUFTLENBQUMsT0FBTztRQUMxQixPQUFPLEVBQUU7WUFDUCxjQUFjLEVBQUUsa0JBQWtCO1NBQ25DO0tBQ0YsQ0FBQyxDQUFDO0lBRUgsaURBQWlEO0lBQ2pELElBQUksY0FBYyxHQUEyQixJQUFJLENBQUM7SUFFbEQsdUNBQXVDO0lBQ3ZDLE1BQU0sQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FDN0IsS0FBSyxFQUFFLGFBQXlDLEVBQUUsRUFBRTtRQUNsRCxNQUFNLEtBQUssR0FBRyxNQUFNLFNBQVMsQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUMvQyxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsYUFBYSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEdBQUcsVUFBVSxLQUFLLEVBQUUsQ0FBQztRQUMxRCxDQUFDO1FBQ0QsT0FBTyxhQUFhLENBQUM7SUFDdkIsQ0FBQyxFQUNELENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUNqQyxDQUFDO0lBRUYsNERBQTREO0lBQzVELE1BQU0sQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FDOUIsQ0FBQyxRQUFRLEVBQUUsRUFBRTtRQUNYLHNEQUFzRDtRQUN0RCx5Q0FBeUM7UUFDekMsSUFBSSxRQUFRLENBQUMsSUFBSSxJQUFJLE9BQU8sUUFBUSxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksTUFBTSxJQUFJLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNsRixRQUFRLENBQUMsSUFBSSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1FBQ3JDLENBQUM7UUFDRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDLEVBQ0QsS0FBSyxFQUFFLEtBQWlCLEVBQUUsRUFBRTtRQUMxQixNQUFNLGVBQWUsR0FBRyxLQUFLLENBQUMsTUFBMkQsQ0FBQztRQUUxRixJQUFJLEtBQUssQ0FBQyxRQUFRLEVBQUUsTUFBTSxLQUFLLEdBQUcsSUFBSSxlQUFlLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDakYsZUFBZSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUM7WUFFOUIsSUFBSSxTQUFTLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztnQkFDakMsSUFBSSxDQUFDO29CQUNILHVDQUF1QztvQkFDdkMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO3dCQUNwQixjQUFjLEdBQUcsU0FBUyxDQUFDLGtCQUFrQixFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRTs0QkFDM0QsY0FBYyxHQUFHLElBQUksQ0FBQzt3QkFDeEIsQ0FBQyxDQUFDLENBQUM7b0JBQ0wsQ0FBQztvQkFDRCxNQUFNLFFBQVEsR0FBRyxNQUFNLGNBQWMsQ0FBQztvQkFFdEMsSUFBSSxRQUFRLEVBQUUsQ0FBQzt3QkFDYixlQUFlLENBQUMsT0FBTyxDQUFDLGFBQWEsR0FBRyxVQUFVLFFBQVEsRUFBRSxDQUFDO3dCQUM3RCxPQUFPLE1BQU0sQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUM7b0JBQ3pDLENBQUM7Z0JBQ0gsQ0FBQztnQkFBQyxNQUFNLENBQUM7b0JBQ1AsU0FBUyxDQUFDLGNBQWMsRUFBRSxFQUFFLENBQUM7b0JBQzdCLE9BQU8sT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDL0IsQ0FBQztZQUNILENBQUM7aUJBQU0sQ0FBQztnQkFDTixTQUFTLENBQUMsY0FBYyxFQUFFLEVBQUUsQ0FBQztZQUMvQixDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMvQixDQUFDLENBQ0YsQ0FBQztJQUVGLE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXhpb3MsIHsgQXhpb3NJbnN0YW5jZSwgQXhpb3NFcnJvciwgSW50ZXJuYWxBeGlvc1JlcXVlc3RDb25maWcgfSBmcm9tICdheGlvcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU0RLQ29uZmlnIHtcbiAgYmFzZVVSTDogc3RyaW5nO1xuICBnZXRBY2Nlc3NUb2tlbjogKCkgPT4gc3RyaW5nIHwgbnVsbCB8IFByb21pc2U8c3RyaW5nIHwgbnVsbD47XG4gIHJlZnJlc2hBY2Nlc3NUb2tlbj86ICgpID0+IFByb21pc2U8c3RyaW5nPjtcbiAgb25VbmF1dGhvcml6ZWQ/OiAoKSA9PiB2b2lkO1xufVxuXG5sZXQgY29uZmlnOiBTREtDb25maWcgfCBudWxsID0gbnVsbDtcbmxldCBhcGlDbGllbnQ6IEF4aW9zSW5zdGFuY2UgfCBudWxsID0gbnVsbDtcblxuZXhwb3J0IGZ1bmN0aW9uIGNvbmZpZ3VyZVNESyhzZGtDb25maWc6IFNES0NvbmZpZyk6IHZvaWQge1xuICBjb25maWcgPSBzZGtDb25maWc7XG4gIGFwaUNsaWVudCA9IGNyZWF0ZUFwaUNsaWVudChzZGtDb25maWcpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0QXBpQ2xpZW50KCk6IEF4aW9zSW5zdGFuY2Uge1xuICBpZiAoIWFwaUNsaWVudCkge1xuICAgIHRocm93IG5ldyBFcnJvcignU0RLIG5vdCBjb25maWd1cmVkLiBDYWxsIGNvbmZpZ3VyZVNESygpIGZpcnN0LicpO1xuICB9XG4gIHJldHVybiBhcGlDbGllbnQ7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUFwaUNsaWVudChzZGtDb25maWc6IFNES0NvbmZpZyk6IEF4aW9zSW5zdGFuY2Uge1xuICBjb25zdCBjbGllbnQgPSBheGlvcy5jcmVhdGUoe1xuICAgIGJhc2VVUkw6IHNka0NvbmZpZy5iYXNlVVJMLFxuICAgIGhlYWRlcnM6IHtcbiAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgfSxcbiAgfSk7XG5cbiAgLy8gVHJhY2sgb25nb2luZyByZWZyZXNoIHRvIGF2b2lkIGR1cGxpY2F0ZSBjYWxsc1xuICBsZXQgcmVmcmVzaFByb21pc2U6IFByb21pc2U8c3RyaW5nPiB8IG51bGwgPSBudWxsO1xuXG4gIC8vIFJlcXVlc3QgaW50ZXJjZXB0b3IgLSBhZGQgYXV0aCB0b2tlblxuICBjbGllbnQuaW50ZXJjZXB0b3JzLnJlcXVlc3QudXNlKFxuICAgIGFzeW5jIChyZXF1ZXN0Q29uZmlnOiBJbnRlcm5hbEF4aW9zUmVxdWVzdENvbmZpZykgPT4ge1xuICAgICAgY29uc3QgdG9rZW4gPSBhd2FpdCBzZGtDb25maWcuZ2V0QWNjZXNzVG9rZW4oKTtcbiAgICAgIGlmICh0b2tlbikge1xuICAgICAgICByZXF1ZXN0Q29uZmlnLmhlYWRlcnMuQXV0aG9yaXphdGlvbiA9IGBCZWFyZXIgJHt0b2tlbn1gO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlcXVlc3RDb25maWc7XG4gICAgfSxcbiAgICAoZXJyb3IpID0+IFByb21pc2UucmVqZWN0KGVycm9yKVxuICApO1xuXG4gIC8vIFJlc3BvbnNlIGludGVyY2VwdG9yIC0gdW53cmFwIEFQSSByZXNwb25zZSBhbmQgaGFuZGxlIDQwMVxuICBjbGllbnQuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLnVzZShcbiAgICAocmVzcG9uc2UpID0+IHtcbiAgICAgIC8vIEFQSSB3cmFwcyBhbGwgcmVzcG9uc2VzIGluIHtkYXRhOiAuLi4sIG1ldGE6IHsuLi59fVxuICAgICAgLy8gVW53cmFwIHRvIHJldHVybiBqdXN0IHRoZSBkYXRhIHBvcnRpb25cbiAgICAgIGlmIChyZXNwb25zZS5kYXRhICYmIHR5cGVvZiByZXNwb25zZS5kYXRhID09PSAnb2JqZWN0JyAmJiAnZGF0YScgaW4gcmVzcG9uc2UuZGF0YSkge1xuICAgICAgICByZXNwb25zZS5kYXRhID0gcmVzcG9uc2UuZGF0YS5kYXRhO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgIH0sXG4gICAgYXN5bmMgKGVycm9yOiBBeGlvc0Vycm9yKSA9PiB7XG4gICAgICBjb25zdCBvcmlnaW5hbFJlcXVlc3QgPSBlcnJvci5jb25maWcgYXMgSW50ZXJuYWxBeGlvc1JlcXVlc3RDb25maWcgJiB7IF9yZXRyeT86IGJvb2xlYW4gfTtcblxuICAgICAgaWYgKGVycm9yLnJlc3BvbnNlPy5zdGF0dXMgPT09IDQwMSAmJiBvcmlnaW5hbFJlcXVlc3QgJiYgIW9yaWdpbmFsUmVxdWVzdC5fcmV0cnkpIHtcbiAgICAgICAgb3JpZ2luYWxSZXF1ZXN0Ll9yZXRyeSA9IHRydWU7XG5cbiAgICAgICAgaWYgKHNka0NvbmZpZy5yZWZyZXNoQWNjZXNzVG9rZW4pIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gRGVkdXBsaWNhdGUgY29uY3VycmVudCByZWZyZXNoIGNhbGxzXG4gICAgICAgICAgICBpZiAoIXJlZnJlc2hQcm9taXNlKSB7XG4gICAgICAgICAgICAgIHJlZnJlc2hQcm9taXNlID0gc2RrQ29uZmlnLnJlZnJlc2hBY2Nlc3NUb2tlbigpLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICAgICAgICAgIHJlZnJlc2hQcm9taXNlID0gbnVsbDtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBuZXdUb2tlbiA9IGF3YWl0IHJlZnJlc2hQcm9taXNlO1xuXG4gICAgICAgICAgICBpZiAobmV3VG9rZW4pIHtcbiAgICAgICAgICAgICAgb3JpZ2luYWxSZXF1ZXN0LmhlYWRlcnMuQXV0aG9yaXphdGlvbiA9IGBCZWFyZXIgJHtuZXdUb2tlbn1gO1xuICAgICAgICAgICAgICByZXR1cm4gY2xpZW50LnJlcXVlc3Qob3JpZ2luYWxSZXF1ZXN0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIHNka0NvbmZpZy5vblVuYXV0aG9yaXplZD8uKCk7XG4gICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZXJyb3IpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZGtDb25maWcub25VbmF1dGhvcml6ZWQ/LigpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZXJyb3IpO1xuICAgIH1cbiAgKTtcblxuICByZXR1cm4gY2xpZW50O1xufVxuXG5leHBvcnQgeyBhcGlDbGllbnQgfTtcbiJdfQ==
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@growsober/sdk",
3
- "version": "1.0.31",
3
+ "version": "1.0.32",
4
4
  "description": "Shared TypeScript SDK for GrowSober API - TanStack Query hooks, API client, and utilities",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
package/src/api/CLAUDE.md CHANGED
@@ -3,10 +3,19 @@
3
3
 
4
4
  <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
5
 
6
+ ### Jan 24, 2026
7
+
8
+ | ID | Time | T | Title | Read |
9
+ |----|------|---|-------|------|
10
+ | #921 | 11:42 AM | 🟣 | Added Creator Community Management to SDK | ~466 |
11
+ | #920 | " | 🟣 | Creator Community SDK Hooks Added | ~445 |
12
+ | #583 | 8:25 AM | ✅ | DTO Renaming for Message Type Clarity | ~318 |
13
+
6
14
  ### Jan 25, 2026
7
15
 
8
16
  | ID | Time | T | Title | Read |
9
17
  |----|------|---|-------|------|
18
+ | #1778 | 12:19 PM | 🔵 | SDK Client Architecture with Token Management and Response Unwrapping | ~561 |
10
19
  | #1712 | 11:42 AM | 🟣 | Product Checkout Flow with Stripe Payment Integration Completed | ~536 |
11
20
  | #1208 | 3:28 AM | 🔵 | UserResponse data structure includes comprehensive profile and notification settings | ~580 |
12
21
  </claude-mem-context>
package/src/api/client.ts CHANGED
@@ -30,6 +30,9 @@ function createApiClient(sdkConfig: SDKConfig): AxiosInstance {
30
30
  },
31
31
  });
32
32
 
33
+ // Track ongoing refresh to avoid duplicate calls
34
+ let refreshPromise: Promise<string> | null = null;
35
+
33
36
  // Request interceptor - add auth token
34
37
  client.interceptors.request.use(
35
38
  async (requestConfig: InternalAxiosRequestConfig) => {
@@ -53,16 +56,28 @@ function createApiClient(sdkConfig: SDKConfig): AxiosInstance {
53
56
  return response;
54
57
  },
55
58
  async (error: AxiosError) => {
56
- if (error.response?.status === 401) {
59
+ const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean };
60
+
61
+ if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
62
+ originalRequest._retry = true;
63
+
57
64
  if (sdkConfig.refreshAccessToken) {
58
65
  try {
59
- const newToken = await sdkConfig.refreshAccessToken();
60
- if (newToken && error.config) {
61
- error.config.headers.Authorization = `Bearer ${newToken}`;
62
- return client.request(error.config);
66
+ // Deduplicate concurrent refresh calls
67
+ if (!refreshPromise) {
68
+ refreshPromise = sdkConfig.refreshAccessToken().finally(() => {
69
+ refreshPromise = null;
70
+ });
71
+ }
72
+ const newToken = await refreshPromise;
73
+
74
+ if (newToken) {
75
+ originalRequest.headers.Authorization = `Bearer ${newToken}`;
76
+ return client.request(originalRequest);
63
77
  }
64
78
  } catch {
65
79
  sdkConfig.onUnauthorized?.();
80
+ return Promise.reject(error);
66
81
  }
67
82
  } else {
68
83
  sdkConfig.onUnauthorized?.();