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/CHANGELOG.md +52 -0
- package/dist/connect-base.umd.js +4 -4
- package/dist/index.d.mts +135 -8
- package/dist/index.d.ts +135 -8
- package/dist/index.js +99 -3
- package/dist/index.mjs +99 -3
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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);
|