@ctil/gql 1.1.7 → 1.1.9

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.
package/dist/index.d.cts CHANGED
@@ -93,6 +93,8 @@ declare class CCRequest {
93
93
  private headers;
94
94
  private deviceInfoPromise;
95
95
  private interceptors;
96
+ private refreshPromise;
97
+ private logoutPromise;
96
98
  constructor(config: RequestConfig);
97
99
  /** 注册一个拦截器(支持多个) */
98
100
  use(interceptor: RequestInterceptor): void;
@@ -117,10 +119,11 @@ declare class CCRequest {
117
119
  getHeaders(): Record<string, string>;
118
120
  removeHeader(key: string): void;
119
121
  clearHeaders(): void;
120
- private refreshPromise;
122
+ private logoutOnce;
121
123
  /** 无感刷新 token */
122
124
  private ensureTokenValid;
123
- request<T = any>(query: string | DocumentNode, variables?: Record<string, any>): Promise<T>;
125
+ private refreshToken;
126
+ request<T = any>(query: string | DocumentNode, variables?: Record<string, any>, _retry?: boolean): Promise<T>;
124
127
  }
125
128
 
126
129
  /** 初始化全局客户端 */
package/dist/index.d.ts CHANGED
@@ -93,6 +93,8 @@ declare class CCRequest {
93
93
  private headers;
94
94
  private deviceInfoPromise;
95
95
  private interceptors;
96
+ private refreshPromise;
97
+ private logoutPromise;
96
98
  constructor(config: RequestConfig);
97
99
  /** 注册一个拦截器(支持多个) */
98
100
  use(interceptor: RequestInterceptor): void;
@@ -117,10 +119,11 @@ declare class CCRequest {
117
119
  getHeaders(): Record<string, string>;
118
120
  removeHeader(key: string): void;
119
121
  clearHeaders(): void;
120
- private refreshPromise;
122
+ private logoutOnce;
121
123
  /** 无感刷新 token */
122
124
  private ensureTokenValid;
123
- request<T = any>(query: string | DocumentNode, variables?: Record<string, any>): Promise<T>;
125
+ private refreshToken;
126
+ request<T = any>(query: string | DocumentNode, variables?: Record<string, any>, _retry?: boolean): Promise<T>;
124
127
  }
125
128
 
126
129
  /** 初始化全局客户端 */
package/dist/index.js CHANGED
@@ -1680,6 +1680,7 @@ var CCRequest = class {
1680
1680
  this._remember = false;
1681
1681
  this.interceptors = [];
1682
1682
  this.refreshPromise = null;
1683
+ this.logoutPromise = null;
1683
1684
  this.deviceInfoPromise = getDeviceInfo();
1684
1685
  this.headers = this.buildHeaders(config);
1685
1686
  const loginInfo = this.loadLoginInfo();
@@ -1821,65 +1822,79 @@ var CCRequest = class {
1821
1822
  clearHeaders() {
1822
1823
  this.headers = { "Content-Type": "application/json" };
1823
1824
  }
1824
- //无感刷新
1825
+ async logoutOnce() {
1826
+ if (!this.logoutPromise) {
1827
+ this.logoutPromise = (async () => {
1828
+ await this.removeLoginInfo();
1829
+ })();
1830
+ }
1831
+ return this.logoutPromise;
1832
+ }
1825
1833
  /** 无感刷新 token */
1826
1834
  async ensureTokenValid() {
1827
- const loginInfo = this.getLoginInfo();
1835
+ const loginInfo = await this.getLoginInfo();
1828
1836
  if (!loginInfo) return;
1829
1837
  const now = Date.now();
1830
- const accessExpired = new Date(loginInfo.expireAt).getTime() - now <= 6e5;
1838
+ const accessExpire = new Date(loginInfo.expireAt).getTime() <= now + 6e5;
1831
1839
  const refreshExpired = new Date(loginInfo.refreshExpireAt).getTime() <= now;
1832
1840
  if (refreshExpired) {
1833
- this.removeLoginInfo();
1841
+ await this.logoutOnce();
1834
1842
  throw new Error("Login expired. Please login again.");
1835
1843
  }
1836
- if (!accessExpired) return;
1837
- if (this.refreshPromise) {
1838
- return this.refreshPromise;
1844
+ if (accessExpire) {
1845
+ await this.refreshToken();
1846
+ }
1847
+ }
1848
+ async refreshToken() {
1849
+ const loginInfo = await this.getLoginInfo();
1850
+ if (!loginInfo) return;
1851
+ if (!this.refreshPromise) {
1852
+ this.refreshPromise = (async () => {
1853
+ try {
1854
+ const newToken = await auth.refreshToken({
1855
+ refreshToken: loginInfo.refreshToken,
1856
+ remember: this._remember
1857
+ });
1858
+ this.setToken(newToken.refreshToken.token);
1859
+ } catch (e) {
1860
+ await this.logoutOnce();
1861
+ throw e;
1862
+ } finally {
1863
+ this.refreshPromise = null;
1864
+ }
1865
+ })();
1839
1866
  }
1840
- this.refreshPromise = (async () => {
1841
- try {
1842
- const result = await auth.refreshToken({
1843
- refreshToken: loginInfo.refreshToken,
1844
- remember: this._remember
1845
- });
1846
- const newInfo = result.refreshToken ?? result;
1847
- this.setLoginInfo(newInfo, this._remember);
1848
- } finally {
1849
- this.refreshPromise = null;
1850
- }
1851
- })();
1852
1867
  return this.refreshPromise;
1853
1868
  }
1854
1869
  // ===== 请求逻辑 =====
1855
- async request(query2, variables) {
1870
+ async request(query2, variables, _retry = false) {
1856
1871
  let queryStr = typeof query2 === "string" ? query2 : print(query2);
1857
- const { deviceId, deviceName } = await this.deviceInfoPromise;
1858
- let headersWithDevice = Object.fromEntries(
1859
- Object.entries({
1860
- ...this.headers,
1861
- "X-Device-Id": deviceId,
1862
- "X-Device-Name": deviceName
1863
- }).filter(([_, v]) => v !== void 0)
1864
- );
1865
- for (const interceptor of this.interceptors) {
1866
- if (interceptor.onRequest) {
1867
- const result = await interceptor.onRequest({
1868
- query: queryStr,
1869
- variables,
1870
- headers: headersWithDevice
1871
- });
1872
- queryStr = result.query;
1873
- variables = result.variables;
1874
- headersWithDevice = Object.fromEntries(
1875
- Object.entries(result.headers).filter(([_, v]) => v !== void 0)
1876
- );
1877
- }
1878
- }
1879
1872
  try {
1880
1873
  if (!/refreshToken/i.test(queryStr)) {
1881
1874
  await this.ensureTokenValid();
1882
1875
  }
1876
+ const { deviceId, deviceName } = await this.deviceInfoPromise;
1877
+ let headersWithDevice = Object.fromEntries(
1878
+ Object.entries({
1879
+ ...this.headers,
1880
+ "X-Device-Id": deviceId,
1881
+ "X-Device-Name": deviceName
1882
+ }).filter(([_, v]) => v !== void 0)
1883
+ );
1884
+ for (const interceptor of this.interceptors) {
1885
+ if (interceptor.onRequest) {
1886
+ const result = await interceptor.onRequest({
1887
+ query: queryStr,
1888
+ variables,
1889
+ headers: headersWithDevice
1890
+ });
1891
+ queryStr = result.query;
1892
+ variables = result.variables;
1893
+ headersWithDevice = Object.fromEntries(
1894
+ Object.entries(result.headers).filter(([_, v]) => v !== void 0)
1895
+ );
1896
+ }
1897
+ }
1883
1898
  const res = await this.client.rawRequest(
1884
1899
  queryStr,
1885
1900
  variables,
@@ -1895,6 +1910,15 @@ var CCRequest = class {
1895
1910
  } catch (err) {
1896
1911
  const message = err.response?.errors?.[0]?.message ?? err.message;
1897
1912
  const status = err.response?.errors?.[0]?.extensions?.code ?? 500;
1913
+ if (status === 401 && !_retry && !/refreshToken/i.test(queryStr)) {
1914
+ try {
1915
+ await this.refreshToken();
1916
+ return this.request(queryStr, variables);
1917
+ } catch {
1918
+ await this.logoutOnce();
1919
+ throw err;
1920
+ }
1921
+ }
1898
1922
  const formattedError = {
1899
1923
  message,
1900
1924
  status,