connectbase-client 3.11.0 → 3.12.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.
package/dist/index.mjs CHANGED
@@ -1302,23 +1302,38 @@ var DatabaseAPI = class {
1302
1302
  // ============ Batch & Transactions ============
1303
1303
  /**
1304
1304
  * 배치 쓰기 (여러 테이블 다중 문서 원자적 처리)
1305
+ *
1306
+ * 서버는 HTTP 200 + `success:false` + 개별 op `error` 로 부분 실패를 표현한다.
1307
+ * SDK 는 호출자가 silent success 로 오해하지 않도록 첫 실패 op 의 메시지로 throw 한다.
1305
1308
  */
1306
1309
  async batch(operations) {
1307
1310
  const prefix = this.getPublicPrefix();
1308
- return this.http.post(
1311
+ const response = await this.http.post(
1309
1312
  `${prefix}/batch`,
1310
1313
  { operations }
1311
1314
  );
1315
+ if (response && response.success === false) {
1316
+ const first = response.results?.find((r) => r && r.success === false);
1317
+ throw new Error(first?.error || "batch operation failed");
1318
+ }
1319
+ return response;
1312
1320
  }
1313
1321
  /**
1314
1322
  * 트랜잭션 실행 (읽기 → 쓰기 ACID)
1323
+ *
1324
+ * 서버는 부분 실패가 없는 ACID 트랜잭션을 보장하지만, 검증/RLS/충돌은
1325
+ * `success:false` + `error` 로 알린다. SDK 는 silent success 회귀 방지 차원에서 throw.
1315
1326
  */
1316
1327
  async transaction(reads, writes) {
1317
1328
  const prefix = this.getPublicPrefix();
1318
- return this.http.post(
1329
+ const response = await this.http.post(
1319
1330
  `${prefix}/transactions`,
1320
1331
  { reads, writes }
1321
1332
  );
1333
+ if (response && response.success === false) {
1334
+ throw new Error(response.error || "transaction failed");
1335
+ }
1336
+ return response;
1322
1337
  }
1323
1338
  // ============ Populate (Relation Query) ============
1324
1339
  /**
@@ -9073,6 +9088,67 @@ var SupportAPI = class {
9073
9088
  if (req.recaptchaToken) body.recaptcha_token = req.recaptchaToken;
9074
9089
  return this.http.post("/v1/public/reports", body);
9075
9090
  }
9091
+ /**
9092
+ * 다른 앱(target) 에 자기 사용자(end-user) 명의로 cross-app 위임 이슈를 발행한다.
9093
+ *
9094
+ * **사용 시나리오**: source_app(예: Makers) 의 backend 가 OAuth `authorization_code` grant 로
9095
+ * 발급받은 사용자 access_token 을 사용해, target_app(예: ai-tool) 에게 "Makers user A 가 보낸"
9096
+ * 이슈로 제보. target 측 콘솔 inbox 에는 `reporter_kind=user` + `reporter_app_id=Makers` 로 표시.
9097
+ *
9098
+ * 본 메서드는 SDK 의 publicKey/secretKey 인증 컨텍스트를 사용하지 않고, 호출자가 명시적으로 전달한
9099
+ * cross-app OAuth Bearer access_token 만 사용 (server-to-server 위임 흐름).
9100
+ *
9101
+ * @param req - 발행 본문
9102
+ * @param req.targetAppId - 수신 앱 ID (= OAuth token 의 audience `app:<uuid>` 와 일치해야 함)
9103
+ * @param req.accessToken - source_app 이 발급받은 cross-app OAuth access_token (authorization_code grant)
9104
+ *
9105
+ * @throws ApiError 401 — `delegated_user_required`: access_token 이 client_credentials grant
9106
+ * @throws ApiError 403 — `trust_chain_violation`: source_app 이 target_app 의 cross-app provider 로 등록되지 않음
9107
+ * @throws ApiError 403 — `insufficient_scope`: token 에 `issue:report:on-behalf-of-user` 미포함
9108
+ *
9109
+ * @example Makers backend → ai-tool 에 사용자 명의 제보
9110
+ * ```typescript
9111
+ * await cb.support.reportIssueOnBehalfOfUser({
9112
+ * targetAppId: 'ai-tool-uuid',
9113
+ * accessToken: makersUserAccessToken, // authorization_code grant 토큰
9114
+ * title: '생성 실패',
9115
+ * body: 'prompt X 가 5분째 응답 없음',
9116
+ * category: 'bug',
9117
+ * metadata: { prompt_id: 'p_42' },
9118
+ * })
9119
+ * ```
9120
+ */
9121
+ async reportIssueOnBehalfOfUser(req) {
9122
+ if (!req.targetAppId) throw new Error("targetAppId is required");
9123
+ if (!req.accessToken) throw new Error("accessToken is required");
9124
+ const body = {
9125
+ title: req.title,
9126
+ body: req.body
9127
+ };
9128
+ if (req.category) body.category = req.category;
9129
+ if (req.metadata) body.metadata = req.metadata;
9130
+ const url = `${this.http.getBaseUrl()}/v1/integrations/providers/${encodeURIComponent(req.targetAppId)}/issues/by-user`;
9131
+ const response = await fetch(url, {
9132
+ method: "POST",
9133
+ headers: {
9134
+ "Content-Type": "application/json",
9135
+ Authorization: `Bearer ${req.accessToken}`
9136
+ },
9137
+ body: JSON.stringify(body)
9138
+ });
9139
+ if (!response.ok) {
9140
+ let errorBody;
9141
+ try {
9142
+ errorBody = await response.json();
9143
+ } catch {
9144
+ errorBody = { error: response.statusText };
9145
+ }
9146
+ const errObj = errorBody ?? {};
9147
+ const message = errObj.error_description ?? errObj.error ?? `HTTP ${response.status}`;
9148
+ throw new Error(`reportIssueOnBehalfOfUser failed (${response.status}): ${message}`);
9149
+ }
9150
+ return await response.json();
9151
+ }
9076
9152
  /**
9077
9153
  * ConnectBase 플랫폼 자체 버그/요청/문의를 발행한다.
9078
9154
  *
@@ -9758,9 +9834,29 @@ var GameRoomTransport = class {
9758
9834
  case "error":
9759
9835
  this.handlers.onError?.({
9760
9836
  code: msg.code || "UNKNOWN",
9761
- message: msg.message || "Unknown error"
9837
+ message: msg.message || "Unknown error",
9838
+ phase: msg.phase,
9839
+ feature: msg.feature,
9840
+ roomId: msg.room_id,
9841
+ scriptId: msg.script_id
9762
9842
  });
9763
9843
  break;
9844
+ case "room_stale":
9845
+ if (this.handlers.onRoomStale) {
9846
+ this.handlers.onRoomStale({
9847
+ reason: msg.reason || "unknown",
9848
+ roomId: msg.room_id || "",
9849
+ scriptId: msg.script_id,
9850
+ scriptVersion: msg.script_version,
9851
+ serverTime: msg.server_time || 0
9852
+ });
9853
+ } else {
9854
+ console.warn(
9855
+ "[connect-base game] room_stale received but onRoomStale handler not set:",
9856
+ { reason: msg.reason, roomId: msg.room_id, scriptVersion: msg.script_version }
9857
+ );
9858
+ }
9859
+ break;
9764
9860
  }
9765
9861
  } catch {
9766
9862
  console.error("Failed to parse game message:", data);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "connectbase-client",
3
- "version": "3.11.0",
3
+ "version": "3.12.0",
4
4
  "description": "Connect Base JavaScript/TypeScript SDK for browser and Node.js",
5
5
  "repository": {
6
6
  "type": "git",