connectbase-client 3.47.0 → 3.48.1

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.mts CHANGED
@@ -173,13 +173,20 @@ declare class HttpClient {
173
173
  * 한 번 settle 되면 그 결과(메모리 적재 또는 미로그인)가 항상 반영되어 있다.
174
174
  */
175
175
  private bootRestorePromise;
176
+ private bootRestoreAlwaysAwait;
176
177
  constructor(config: HttpClientConfig);
177
178
  /**
178
179
  * 페이지 진입 시 fire-and-forget 으로 시작된 cookie 복구 promise 를 SDK 가 등록한다.
179
180
  * 같은 promise 가 `prepareHeaders` 에서 await 되어, 첫 인증 호출이 cookie 복구
180
181
  * 완료 후 발화한다.
182
+ *
183
+ * options.alwaysAwait=true 면 세션 힌트가 없어도 첫 인증 호출이 이 promise 를
184
+ * 기다린다 — OAuth 리다이렉트 콜백처럼 "이 부트 promise 가 곧 세션을 만든다"는 것이
185
+ * 확실한 흐름용 (일반 cookie 복구는 힌트 기반 fast-path 적용).
181
186
  */
182
- setBootRestorePromise(p: Promise<boolean>): void;
187
+ setBootRestorePromise(p: Promise<boolean>, options?: {
188
+ alwaysAwait?: boolean;
189
+ }): void;
183
190
  /** 최근 호출 ring buffer 스냅샷 (시간순). */
184
191
  getRecentCalls(): RecentApiCall[];
185
192
  /** 최근 호출 buffer clear (테스트/프라이버시 처리). */
@@ -188,6 +195,10 @@ declare class HttpClient {
188
195
  updateConfig(config: Partial<HttpClientConfig>): void;
189
196
  setTokens(accessToken: string, refreshToken: string): void;
190
197
  clearTokens(): void;
198
+ private buildSessionHintKey;
199
+ private markSessionHint;
200
+ private clearSessionHint;
201
+ private hasSessionHint;
191
202
  /**
192
203
  * OAuth redirect callback 직후 호출되어 HttpOnly cookie 를 부트스트랩한다.
193
204
  *
@@ -1174,7 +1185,12 @@ interface UpdateDataRequest {
1174
1185
  interface FetchDataResponse {
1175
1186
  /** 조회된 문서 배열 */
1176
1187
  data: DataItem[];
1177
- /** 총 매칭 문서 수 */
1188
+ /**
1189
+ * 총 매칭 문서 수.
1190
+ *
1191
+ * `count: false` 로 조회한 경우: 마지막 페이지(반환 건수 < limit)면 서버가 정확한
1192
+ * 총계를 파생해 돌려주고, 아니면 `-1` (미상) 이 반환됩니다.
1193
+ */
1178
1194
  total_count: number;
1179
1195
  }
1180
1196
  interface QueryOptions {
@@ -1187,6 +1203,14 @@ interface QueryOptions {
1187
1203
  select?: string[];
1188
1204
  /** 제외할 필드 목록 - 지정된 필드를 제외하고 반환 */
1189
1205
  exclude?: string[];
1206
+ /**
1207
+ * `false` 면 `total_count` 계산(서버측 COUNT 쿼리)을 생략합니다.
1208
+ *
1209
+ * 필터가 붙은 COUNT 는 본 조회와 같은 비용의 스캔을 한 번 더 도는 것이므로,
1210
+ * 총계가 필요 없는 목록/무한스크롤 조회는 `count: false` 로 눈에 띄게 빨라집니다.
1211
+ * 생략 시 기본값은 `true` (기존 동작 유지).
1212
+ */
1213
+ count?: boolean;
1190
1214
  }
1191
1215
  type WhereCondition = {
1192
1216
  /** OR 조건: 배열 내 조건들 중 하나 이상 만족 */
package/dist/index.d.ts CHANGED
@@ -173,13 +173,20 @@ declare class HttpClient {
173
173
  * 한 번 settle 되면 그 결과(메모리 적재 또는 미로그인)가 항상 반영되어 있다.
174
174
  */
175
175
  private bootRestorePromise;
176
+ private bootRestoreAlwaysAwait;
176
177
  constructor(config: HttpClientConfig);
177
178
  /**
178
179
  * 페이지 진입 시 fire-and-forget 으로 시작된 cookie 복구 promise 를 SDK 가 등록한다.
179
180
  * 같은 promise 가 `prepareHeaders` 에서 await 되어, 첫 인증 호출이 cookie 복구
180
181
  * 완료 후 발화한다.
182
+ *
183
+ * options.alwaysAwait=true 면 세션 힌트가 없어도 첫 인증 호출이 이 promise 를
184
+ * 기다린다 — OAuth 리다이렉트 콜백처럼 "이 부트 promise 가 곧 세션을 만든다"는 것이
185
+ * 확실한 흐름용 (일반 cookie 복구는 힌트 기반 fast-path 적용).
181
186
  */
182
- setBootRestorePromise(p: Promise<boolean>): void;
187
+ setBootRestorePromise(p: Promise<boolean>, options?: {
188
+ alwaysAwait?: boolean;
189
+ }): void;
183
190
  /** 최근 호출 ring buffer 스냅샷 (시간순). */
184
191
  getRecentCalls(): RecentApiCall[];
185
192
  /** 최근 호출 buffer clear (테스트/프라이버시 처리). */
@@ -188,6 +195,10 @@ declare class HttpClient {
188
195
  updateConfig(config: Partial<HttpClientConfig>): void;
189
196
  setTokens(accessToken: string, refreshToken: string): void;
190
197
  clearTokens(): void;
198
+ private buildSessionHintKey;
199
+ private markSessionHint;
200
+ private clearSessionHint;
201
+ private hasSessionHint;
191
202
  /**
192
203
  * OAuth redirect callback 직후 호출되어 HttpOnly cookie 를 부트스트랩한다.
193
204
  *
@@ -1174,7 +1185,12 @@ interface UpdateDataRequest {
1174
1185
  interface FetchDataResponse {
1175
1186
  /** 조회된 문서 배열 */
1176
1187
  data: DataItem[];
1177
- /** 총 매칭 문서 수 */
1188
+ /**
1189
+ * 총 매칭 문서 수.
1190
+ *
1191
+ * `count: false` 로 조회한 경우: 마지막 페이지(반환 건수 < limit)면 서버가 정확한
1192
+ * 총계를 파생해 돌려주고, 아니면 `-1` (미상) 이 반환됩니다.
1193
+ */
1178
1194
  total_count: number;
1179
1195
  }
1180
1196
  interface QueryOptions {
@@ -1187,6 +1203,14 @@ interface QueryOptions {
1187
1203
  select?: string[];
1188
1204
  /** 제외할 필드 목록 - 지정된 필드를 제외하고 반환 */
1189
1205
  exclude?: string[];
1206
+ /**
1207
+ * `false` 면 `total_count` 계산(서버측 COUNT 쿼리)을 생략합니다.
1208
+ *
1209
+ * 필터가 붙은 COUNT 는 본 조회와 같은 비용의 스캔을 한 번 더 도는 것이므로,
1210
+ * 총계가 필요 없는 목록/무한스크롤 조회는 `count: false` 로 눈에 띄게 빨라집니다.
1211
+ * 생략 시 기본값은 `true` (기존 동작 유지).
1212
+ */
1213
+ count?: boolean;
1190
1214
  }
1191
1215
  type WhereCondition = {
1192
1216
  /** OR 조건: 배열 내 조건들 중 하나 이상 만족 */
package/dist/index.js CHANGED
@@ -185,6 +185,9 @@ var HttpClient = class {
185
185
  * 한 번 settle 되면 그 결과(메모리 적재 또는 미로그인)가 항상 반영되어 있다.
186
186
  */
187
187
  this.bootRestorePromise = null;
188
+ // OAuth 콜백 부트스트랩처럼 세션 힌트 유무와 무관하게 첫 인증 호출이 반드시 기다려야
189
+ // 하는 boot promise 인지 여부 (setBootRestorePromise 의 alwaysAwait 옵션).
190
+ this.bootRestoreAlwaysAwait = false;
188
191
  this.config = { ...config };
189
192
  this.storageKey = this.buildStorageKey();
190
193
  this.warnIfUnsafePersistence();
@@ -194,9 +197,14 @@ var HttpClient = class {
194
197
  * 페이지 진입 시 fire-and-forget 으로 시작된 cookie 복구 promise 를 SDK 가 등록한다.
195
198
  * 같은 promise 가 `prepareHeaders` 에서 await 되어, 첫 인증 호출이 cookie 복구
196
199
  * 완료 후 발화한다.
200
+ *
201
+ * options.alwaysAwait=true 면 세션 힌트가 없어도 첫 인증 호출이 이 promise 를
202
+ * 기다린다 — OAuth 리다이렉트 콜백처럼 "이 부트 promise 가 곧 세션을 만든다"는 것이
203
+ * 확실한 흐름용 (일반 cookie 복구는 힌트 기반 fast-path 적용).
197
204
  */
198
- setBootRestorePromise(p) {
205
+ setBootRestorePromise(p, options) {
199
206
  this.bootRestorePromise = p.catch(() => false);
207
+ this.bootRestoreAlwaysAwait = options?.alwaysAwait === true;
200
208
  }
201
209
  /** 최근 호출 ring buffer 스냅샷 (시간순). */
202
210
  getRecentCalls() {
@@ -225,11 +233,49 @@ var HttpClient = class {
225
233
  this.config.accessToken = accessToken;
226
234
  this.config.refreshToken = refreshToken;
227
235
  this.persistTokens();
236
+ this.markSessionHint();
228
237
  }
229
238
  clearTokens() {
230
239
  this.config.accessToken = void 0;
231
240
  this.config.refreshToken = void 0;
232
241
  this.removePersistedTokens();
242
+ this.clearSessionHint();
243
+ }
244
+ // ===== 세션 힌트 =====
245
+ //
246
+ // "이 origin 에서 이 앱으로 로그인한 적이 있다"는 boolean 마커 (토큰 아님 — 민감정보 없음).
247
+ // 부트 시 cookie 복구(`/v1/auth/re-issue`)를 첫 인증 호출이 기다릴지 판단하는 데 쓴다:
248
+ // - 힌트 있음 → 기존과 동일하게 대기 (로그인 세션의 첫 호출이 익명으로 나가는 것 방지).
249
+ // - 힌트 없음 → 대기 생략. 익명 방문자(공개 사이트 첫 방문 대부분)의 첫 조회가
250
+ // re-issue 왕복만큼 빨라진다. 복구 자체는 백그라운드로 계속 진행되므로, 드물게
251
+ // 힌트가 지워졌지만 cookie 세션이 살아있는 경우도 이후 호출부터 자동 회복된다.
252
+ //
253
+ // 세션을 만드는 모든 흐름(로그인/OAuth 콜백/토큰 refresh)이 setTokens 를 경유하므로
254
+ // 그곳에서 마킹하고, clearTokens(로그아웃)에서 지운다.
255
+ buildSessionHintKey() {
256
+ return `${this.buildStorageKey()}:has_session`;
257
+ }
258
+ markSessionHint() {
259
+ if (typeof window === "undefined") return;
260
+ try {
261
+ localStorage.setItem(this.buildSessionHintKey(), "1");
262
+ } catch {
263
+ }
264
+ }
265
+ clearSessionHint() {
266
+ if (typeof window === "undefined") return;
267
+ try {
268
+ localStorage.removeItem(this.buildSessionHintKey());
269
+ } catch {
270
+ }
271
+ }
272
+ hasSessionHint() {
273
+ if (typeof window === "undefined") return false;
274
+ try {
275
+ return localStorage.getItem(this.buildSessionHintKey()) === "1";
276
+ } catch {
277
+ return true;
278
+ }
233
279
  }
234
280
  /**
235
281
  * OAuth redirect callback 직후 호출되어 HttpOnly cookie 를 부트스트랩한다.
@@ -558,7 +604,7 @@ var HttpClient = class {
558
604
  if (credential) {
559
605
  headers.set("X-Public-Key", credential);
560
606
  }
561
- if (!config?.skipAuth && !this.config.accessToken && this.config.publicKey && typeof window !== "undefined" && this.bootRestorePromise) {
607
+ if (!config?.skipAuth && !this.config.accessToken && this.config.publicKey && typeof window !== "undefined" && this.bootRestorePromise && (this.bootRestoreAlwaysAwait || this.hasSessionHint())) {
562
608
  try {
563
609
  await this.bootRestorePromise;
564
610
  } catch {
@@ -1268,6 +1314,7 @@ var DatabaseAPI = class {
1268
1314
  const params = new URLSearchParams();
1269
1315
  if (options?.limit) params.append("limit", options.limit.toString());
1270
1316
  if (options?.offset) params.append("offset", options.offset.toString());
1317
+ if (options?.count === false) params.append("count", "false");
1271
1318
  const queryString = params.toString();
1272
1319
  const url = queryString ? `${prefix}/tables/${tableId}/data?${queryString}` : `${prefix}/tables/${tableId}/data`;
1273
1320
  return this.http.get(url);
@@ -1286,7 +1333,8 @@ var DatabaseAPI = class {
1286
1333
  limit: options.limit,
1287
1334
  offset: options.offset,
1288
1335
  select: options.select,
1289
- exclude: options.exclude
1336
+ exclude: options.exclude,
1337
+ count: options.count
1290
1338
  }
1291
1339
  );
1292
1340
  }
@@ -1450,7 +1498,8 @@ var DatabaseAPI = class {
1450
1498
  offset: options.offset,
1451
1499
  select: options.select,
1452
1500
  exclude: options.exclude,
1453
- populate: options.populate
1501
+ populate: options.populate,
1502
+ count: options.count
1454
1503
  }
1455
1504
  );
1456
1505
  }
@@ -11333,7 +11382,7 @@ var ConnectBase = class {
11333
11382
  const shouldAutoRestore = config.autoRestoreSession ?? true;
11334
11383
  if (shouldAutoRestore && typeof window !== "undefined") {
11335
11384
  if (this.isOAuthRedirectCallbackUrl()) {
11336
- this.http.setBootRestorePromise(this.oauth.consumeRedirectCallbackOnBoot());
11385
+ this.http.setBootRestorePromise(this.oauth.consumeRedirectCallbackOnBoot(), { alwaysAwait: true });
11337
11386
  } else if (!this.isOAuthCallbackUrl()) {
11338
11387
  this.http.setBootRestorePromise(this.http.tryRestoreSessionFromCookie());
11339
11388
  }
package/dist/index.mjs CHANGED
@@ -139,6 +139,9 @@ var HttpClient = class {
139
139
  * 한 번 settle 되면 그 결과(메모리 적재 또는 미로그인)가 항상 반영되어 있다.
140
140
  */
141
141
  this.bootRestorePromise = null;
142
+ // OAuth 콜백 부트스트랩처럼 세션 힌트 유무와 무관하게 첫 인증 호출이 반드시 기다려야
143
+ // 하는 boot promise 인지 여부 (setBootRestorePromise 의 alwaysAwait 옵션).
144
+ this.bootRestoreAlwaysAwait = false;
142
145
  this.config = { ...config };
143
146
  this.storageKey = this.buildStorageKey();
144
147
  this.warnIfUnsafePersistence();
@@ -148,9 +151,14 @@ var HttpClient = class {
148
151
  * 페이지 진입 시 fire-and-forget 으로 시작된 cookie 복구 promise 를 SDK 가 등록한다.
149
152
  * 같은 promise 가 `prepareHeaders` 에서 await 되어, 첫 인증 호출이 cookie 복구
150
153
  * 완료 후 발화한다.
154
+ *
155
+ * options.alwaysAwait=true 면 세션 힌트가 없어도 첫 인증 호출이 이 promise 를
156
+ * 기다린다 — OAuth 리다이렉트 콜백처럼 "이 부트 promise 가 곧 세션을 만든다"는 것이
157
+ * 확실한 흐름용 (일반 cookie 복구는 힌트 기반 fast-path 적용).
151
158
  */
152
- setBootRestorePromise(p) {
159
+ setBootRestorePromise(p, options) {
153
160
  this.bootRestorePromise = p.catch(() => false);
161
+ this.bootRestoreAlwaysAwait = options?.alwaysAwait === true;
154
162
  }
155
163
  /** 최근 호출 ring buffer 스냅샷 (시간순). */
156
164
  getRecentCalls() {
@@ -179,11 +187,49 @@ var HttpClient = class {
179
187
  this.config.accessToken = accessToken;
180
188
  this.config.refreshToken = refreshToken;
181
189
  this.persistTokens();
190
+ this.markSessionHint();
182
191
  }
183
192
  clearTokens() {
184
193
  this.config.accessToken = void 0;
185
194
  this.config.refreshToken = void 0;
186
195
  this.removePersistedTokens();
196
+ this.clearSessionHint();
197
+ }
198
+ // ===== 세션 힌트 =====
199
+ //
200
+ // "이 origin 에서 이 앱으로 로그인한 적이 있다"는 boolean 마커 (토큰 아님 — 민감정보 없음).
201
+ // 부트 시 cookie 복구(`/v1/auth/re-issue`)를 첫 인증 호출이 기다릴지 판단하는 데 쓴다:
202
+ // - 힌트 있음 → 기존과 동일하게 대기 (로그인 세션의 첫 호출이 익명으로 나가는 것 방지).
203
+ // - 힌트 없음 → 대기 생략. 익명 방문자(공개 사이트 첫 방문 대부분)의 첫 조회가
204
+ // re-issue 왕복만큼 빨라진다. 복구 자체는 백그라운드로 계속 진행되므로, 드물게
205
+ // 힌트가 지워졌지만 cookie 세션이 살아있는 경우도 이후 호출부터 자동 회복된다.
206
+ //
207
+ // 세션을 만드는 모든 흐름(로그인/OAuth 콜백/토큰 refresh)이 setTokens 를 경유하므로
208
+ // 그곳에서 마킹하고, clearTokens(로그아웃)에서 지운다.
209
+ buildSessionHintKey() {
210
+ return `${this.buildStorageKey()}:has_session`;
211
+ }
212
+ markSessionHint() {
213
+ if (typeof window === "undefined") return;
214
+ try {
215
+ localStorage.setItem(this.buildSessionHintKey(), "1");
216
+ } catch {
217
+ }
218
+ }
219
+ clearSessionHint() {
220
+ if (typeof window === "undefined") return;
221
+ try {
222
+ localStorage.removeItem(this.buildSessionHintKey());
223
+ } catch {
224
+ }
225
+ }
226
+ hasSessionHint() {
227
+ if (typeof window === "undefined") return false;
228
+ try {
229
+ return localStorage.getItem(this.buildSessionHintKey()) === "1";
230
+ } catch {
231
+ return true;
232
+ }
187
233
  }
188
234
  /**
189
235
  * OAuth redirect callback 직후 호출되어 HttpOnly cookie 를 부트스트랩한다.
@@ -512,7 +558,7 @@ var HttpClient = class {
512
558
  if (credential) {
513
559
  headers.set("X-Public-Key", credential);
514
560
  }
515
- if (!config?.skipAuth && !this.config.accessToken && this.config.publicKey && typeof window !== "undefined" && this.bootRestorePromise) {
561
+ if (!config?.skipAuth && !this.config.accessToken && this.config.publicKey && typeof window !== "undefined" && this.bootRestorePromise && (this.bootRestoreAlwaysAwait || this.hasSessionHint())) {
516
562
  try {
517
563
  await this.bootRestorePromise;
518
564
  } catch {
@@ -1222,6 +1268,7 @@ var DatabaseAPI = class {
1222
1268
  const params = new URLSearchParams();
1223
1269
  if (options?.limit) params.append("limit", options.limit.toString());
1224
1270
  if (options?.offset) params.append("offset", options.offset.toString());
1271
+ if (options?.count === false) params.append("count", "false");
1225
1272
  const queryString = params.toString();
1226
1273
  const url = queryString ? `${prefix}/tables/${tableId}/data?${queryString}` : `${prefix}/tables/${tableId}/data`;
1227
1274
  return this.http.get(url);
@@ -1240,7 +1287,8 @@ var DatabaseAPI = class {
1240
1287
  limit: options.limit,
1241
1288
  offset: options.offset,
1242
1289
  select: options.select,
1243
- exclude: options.exclude
1290
+ exclude: options.exclude,
1291
+ count: options.count
1244
1292
  }
1245
1293
  );
1246
1294
  }
@@ -1404,7 +1452,8 @@ var DatabaseAPI = class {
1404
1452
  offset: options.offset,
1405
1453
  select: options.select,
1406
1454
  exclude: options.exclude,
1407
- populate: options.populate
1455
+ populate: options.populate,
1456
+ count: options.count
1408
1457
  }
1409
1458
  );
1410
1459
  }
@@ -11287,7 +11336,7 @@ var ConnectBase = class {
11287
11336
  const shouldAutoRestore = config.autoRestoreSession ?? true;
11288
11337
  if (shouldAutoRestore && typeof window !== "undefined") {
11289
11338
  if (this.isOAuthRedirectCallbackUrl()) {
11290
- this.http.setBootRestorePromise(this.oauth.consumeRedirectCallbackOnBoot());
11339
+ this.http.setBootRestorePromise(this.oauth.consumeRedirectCallbackOnBoot(), { alwaysAwait: true });
11291
11340
  } else if (!this.isOAuthCallbackUrl()) {
11292
11341
  this.http.setBootRestorePromise(this.http.tryRestoreSessionFromCookie());
11293
11342
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "connectbase-client",
3
- "version": "3.47.0",
3
+ "version": "3.48.1",
4
4
  "description": "Connect Base JavaScript/TypeScript SDK for browser and Node.js",
5
5
  "repository": {
6
6
  "type": "git",