@pickleball/server-sdk 0.1.1 → 0.3.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.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  type SdkErrorCode = "PERMISSION_DENIED" | "NETWORK_UNAVAILABLE" | "TOKEN_EXPIRED" | "SDK_UPGRADE_REQUIRED" | "SESSION_CONFLICT" | "RECORDING_FAILED" | "CONSENT_REQUIRED" | "SDK_DISABLED" | "UNKNOWN";
2
- type ServerSdkErrorCode = SdkErrorCode | "CONFIGURATION_ERROR" | "TIMEOUT" | "NETWORK_ERROR" | "HTTP_ERROR" | "INVALID_RESPONSE" | "WEBHOOK_VERIFICATION_FAILED";
2
+ type ServerSdkErrorCode = SdkErrorCode | "CONFIGURATION_ERROR" | "TIMEOUT" | "NETWORK_ERROR" | "HTTP_ERROR" | "INVALID_RESPONSE" | "PARTNER_API_ERROR" | "WEBHOOK_VERIFICATION_FAILED";
3
3
  declare class PickleballLiveError extends Error {
4
4
  readonly code: ServerSdkErrorCode;
5
5
  constructor(message: string, code: ServerSdkErrorCode, options?: ErrorOptions);
@@ -13,6 +13,19 @@ declare class PickleballApiError extends PickleballLiveError {
13
13
  /** Stable allowlisted code. Unknown server codes are normalized to UNKNOWN. */
14
14
  code: SdkErrorCode, status: number);
15
15
  }
16
+ /**
17
+ * Lỗi của REST v1 (đường đối tác: /api/v1/live-sessions, camera grant). Thân
18
+ * lỗi là `{error, code, ...extra}` — `partnerCode` là mã máy đọc (VD
19
+ * COURT_HAS_DEVICE, CAPACITY, SESSION_EXPIRED), `details` là các field kèm
20
+ * (activeSessionId, deviceId, retryAfterMs, retryable…). Đối tác switch theo
21
+ * `partnerCode`, KHÔNG parse message.
22
+ */
23
+ declare class PickleballPartnerApiError extends PickleballLiveError {
24
+ readonly partnerCode: string;
25
+ readonly status: number;
26
+ readonly details: Record<string, unknown>;
27
+ constructor(message: string, partnerCode: string, status: number, details?: Record<string, unknown>);
28
+ }
16
29
  declare class PickleballHttpError extends PickleballLiveError {
17
30
  readonly status: number;
18
31
  constructor(status: number);
@@ -66,6 +79,13 @@ interface StartLivestreamInput {
66
79
  * "scheduled" và KHÔNG khởi động recording egress cho tới khi publish.
67
80
  */
68
81
  standby?: boolean;
82
+ /**
83
+ * Độ phân giải app THỰC SỰ quay, để server ghi đúng vào phiên. Chỉ app biết
84
+ * con số này: nó là lựa chọn local và app còn override `config.videoQuality`
85
+ * mà server trả về. Không khai thì server dùng mặc định của nó (1080) và bản
86
+ * ghi phiên nói dối.
87
+ */
88
+ quality?: 720 | 1080;
69
89
  }
70
90
  interface SdkTelemetryCredentials {
71
91
  endpoint: string;
@@ -96,6 +116,64 @@ interface SdkPublishState {
96
116
  sessionId: string;
97
117
  status: "scheduled" | "live";
98
118
  }
119
+ type CameraGrantStatus = "scheduled" | "live";
120
+ /**
121
+ * Camera grant — điện thoại của user ĐỐI TÁC lên sóng (ADR-0002). Backend đối
122
+ * tác nhận từ REST v1 (POST /api/v1/live-sessions {cameraGrant:true} hoặc
123
+ * POST /api/v1/live-sessions/{id}/camera-grant) và chuyển NGUYÊN TRẠNG cho app;
124
+ * app dùng `telemetry.token` làm Bearer với namespace /api/v2/camera/sessions.
125
+ *
126
+ * Superset nghiêm ngặt của SdkSessionGrant: `serverUrl` là RTMP ingest
127
+ * (`rtmp://host:1935/`), `participantToken` là stream key — SDK 0.2 đã nhận
128
+ * hình dạng này qua isSessionGrant nên không cần validator mới ở lớp engine.
129
+ */
130
+ interface CameraGrant extends SdkSessionGrant {
131
+ /** Không bao giờ "ended" — endpoint trả 409 thay vì grant. */
132
+ status: CameraGrantStatus;
133
+ matchRef: string | null;
134
+ courtRef: string | null;
135
+ watchUrl: string | null;
136
+ /**
137
+ * Origin websocket Convex (https://<dep>.convex.cloud) để SDK subscribe lệnh
138
+ * thay vì poll HTTP 2s; null khi deployment không lộ origin chuẩn → SDK poll.
139
+ */
140
+ convexUrl: string | null;
141
+ issuedAt: number;
142
+ /**
143
+ * Hạn dùng của grant. Phiên chờ mà app CHƯA từng kết nối bị dọn sau 30 phút
144
+ * (RTMP_STANDBY_SILENT_MS) — xin grant đúng lúc user mở camera, đừng cấp sớm
145
+ * hàng giờ trước trận.
146
+ */
147
+ expiresAt: number;
148
+ }
149
+ /** Thân POST /api/v1/live-sessions với cameraGrant:true (phiên điện thoại đối tác). */
150
+ interface CreateCameraSessionInput {
151
+ /** Định danh trận phía đối tác — phiên khoá theo trận, gọi lại cùng matchRef là idempotent. */
152
+ matchRef: string;
153
+ title: string;
154
+ visibility?: SessionVisibility;
155
+ description?: string;
156
+ /** Độ phân giải app sẽ quay; mặc định 720 cho điện thoại. */
157
+ quality?: 720 | 1080;
158
+ /** Đậu phiên vào sân giải để dùng match-start/match-end như camera cố định. */
159
+ courtRef?: string;
160
+ }
161
+ /** Phản hồi tạo phiên điện thoại: phiên + grant chuyển cho app. */
162
+ interface CameraSessionCreated {
163
+ id: string;
164
+ status: SessionStatus;
165
+ visibility: SessionVisibility;
166
+ quality: number;
167
+ deliveryMode: string;
168
+ matchRef: string | null;
169
+ courtRef: string | null;
170
+ playbackUrl: string | null;
171
+ whepUrl: string | null;
172
+ watchUrl: string | null;
173
+ /** true = phiên cũ cùng matchRef còn sống được dùng lại (grant vẫn MỚI). */
174
+ reused: boolean;
175
+ cameraGrant: CameraGrant;
176
+ }
99
177
  type SessionStatus = "scheduled" | "live" | "ended";
100
178
  type SessionVisibility = "public" | "private";
101
179
  type RecordingType = "clean" | "derived" | "device";
@@ -108,6 +186,11 @@ interface ApiLiveSession {
108
186
  playbackUrl: string | null;
109
187
  /** Link trang xem web (`/watch/{id}`); null nếu chưa cấu hình WEB_PUBLIC_BASE_URL. */
110
188
  watchUrl: string | null;
189
+ /**
190
+ * Endpoint WebRTC/WHEP độ trễ <1s — chỉ khác null khi phiên ĐANG live ở mode
191
+ * device-rtmp. Chết ngay khi phiên kết thúc, đừng lưu; null = dùng playbackUrl.
192
+ */
193
+ whepUrl: string | null;
111
194
  scheduledAt: number | null;
112
195
  startedAt: number | null;
113
196
  endedAt: number | null;
@@ -126,6 +209,46 @@ interface ApiRecording {
126
209
  type StartSdkSessionInput = BootstrapInput & StartLivestreamInput & {
127
210
  idempotencyKey: string;
128
211
  };
212
+ /** Thông tin thiết bị kèm khi đăng ký (từ expo-device). */
213
+ interface DeviceInfoInput {
214
+ appVersion?: string;
215
+ deviceName?: string;
216
+ deviceModel?: string;
217
+ osVersion?: string;
218
+ }
219
+ interface DeviceMetricsInput {
220
+ ramFreeMb?: number;
221
+ ramTotalMb?: number;
222
+ storageFreeGb?: number;
223
+ batteryPct?: number;
224
+ batteryTempC?: number;
225
+ thermal?: number;
226
+ netType?: string;
227
+ linkMbps?: number;
228
+ rssi?: number;
229
+ connQuality?: string;
230
+ }
231
+ interface DeviceRegisterResult {
232
+ deviceId: string;
233
+ heartbeatIntervalMs: number;
234
+ }
235
+ interface DeviceHeartbeatInput {
236
+ /** Trạng thái engine hiện tại (idle|standby|live|...). */
237
+ agentState?: string;
238
+ /** Id phiên live đang giữ — null = không có phiên (server clear link). */
239
+ currentSessionId?: string | null;
240
+ appVersion?: string;
241
+ metrics?: DeviceMetricsInput;
242
+ }
243
+ /** Kênh điều khiển được dashboard yêu cầu — app dùng token mở Convex websocket. */
244
+ interface DeviceControlSessionGrant {
245
+ id: string;
246
+ token: string;
247
+ convexUrl: string;
248
+ }
249
+ interface DeviceHeartbeatResult {
250
+ controlSession: DeviceControlSessionGrant | null;
251
+ }
129
252
  declare const SDK_TELEMETRY_EVENT_NAMES: readonly ["state_changed", "connection_quality", "reconnect", "error", "heartbeat", "session_ended"];
130
253
  type SdkTelemetryEventName = (typeof SDK_TELEMETRY_EVENT_NAMES)[number];
131
254
  interface SdkTelemetryEvent {
@@ -149,9 +272,20 @@ interface LivestreamSessionProvider {
149
272
  unpublish?(sessionId: string): Promise<void>;
150
273
  }
151
274
  type LivestreamState = "idle" | "preparing" | "preview" | "connecting" | "standby" | "live" | "reconnecting" | "ending" | "ended" | "error";
275
+ /**
276
+ * Vì sao 409 SESSION_CONFLICT bị nhận trên namespace /api/v2/camera — mirror
277
+ * của packages/shared (type-test Equal ghim): superseded = grant bị grant mới
278
+ * thay (app dừng tại chỗ), ended = phiên đã kết thúc, expired = quá trần
279
+ * thời lượng credential (xin grant/phiên mới).
280
+ */
281
+ type SdkConflictReason = "superseded" | "ended" | "expired";
152
282
  interface SdkError {
153
283
  code: SdkErrorCode;
154
284
  message: string;
285
+ /** Chỉ có ở 409 SESSION_CONFLICT của namespace /api/v2/camera. */
286
+ reason?: SdkConflictReason;
287
+ /** Chỉ có ở 429 — cùng số với header `Retry-After` (giây, làm tròn lên). */
288
+ retryAfterMs?: number;
155
289
  }
156
290
 
157
291
  type WebhookRawBody = string | Uint8Array;
@@ -178,7 +312,11 @@ declare function verifyWebhook<T extends WebhookPayload = WebhookPayload>(rawBod
178
312
 
179
313
  interface PickleballLiveClientOptions {
180
314
  baseUrl: string;
181
- appId: string;
315
+ /**
316
+ * Chỉ cần cho các thao tác `/api/v2/sdk/*` (mô hình proxy cũ). Đường
317
+ * `liveSessions.*` (camera grant, REST v1) không dùng appId — bỏ trống được.
318
+ */
319
+ appId?: string;
182
320
  apiKey: string;
183
321
  fetch?: typeof globalThis.fetch;
184
322
  timeoutMs?: number;
@@ -186,21 +324,48 @@ interface PickleballLiveClientOptions {
186
324
  }
187
325
  interface PickleballLiveClient {
188
326
  apps: {
327
+ /** @deprecated Mô hình proxy SDK v2 — dùng `liveSessions.createCameraSession` (ADR-0002). */
189
328
  bootstrap(input: BootstrapInput): Promise<SdkBootstrap>;
190
329
  };
191
330
  sessions: {
331
+ /** @deprecated Mô hình proxy SDK v2 — dùng `liveSessions.createCameraSession` (ADR-0002). */
192
332
  start(input: StartSdkSessionInput): Promise<SdkSessionGrant>;
333
+ /** @deprecated Mô hình proxy SDK v2 — app tự refresh bằng Bearer grant ở /api/v2/camera. */
193
334
  refresh(sessionId: string, input: BootstrapInput): Promise<SdkSessionRefresh>;
335
+ /** @deprecated Mô hình proxy SDK v2 — dùng `liveSessions.end`. */
194
336
  end(input: EndLivestreamInput): Promise<void>;
337
+ /** @deprecated Mô hình proxy SDK v2 — app tự publish bằng Bearer grant ở /api/v2/camera. */
195
338
  publish(sessionId: string): Promise<SdkPublishState>;
339
+ /** @deprecated Mô hình proxy SDK v2 — app tự unpublish bằng Bearer grant ở /api/v2/camera. */
196
340
  unpublish(sessionId: string): Promise<SdkPublishState>;
197
341
  get(sessionId: string): Promise<ApiLiveSession>;
198
342
  getRecordings(sessionId: string): Promise<ApiRecording[]>;
199
343
  };
344
+ /**
345
+ * REST v1 — đường của backend đối tác (x-api-key), không cần appId.
346
+ * Camera grant (ADR-0002): tạo phiên theo matchRef rồi chuyển `cameraGrant`
347
+ * nguyên trạng cho app; app dùng @pickleball/expo-sdk nói thẳng với Picklive.
348
+ */
349
+ liveSessions: {
350
+ /** POST /api/v1/live-sessions {cameraGrant:true} — idempotent theo (host, matchRef). */
351
+ createCameraSession(input: CreateCameraSessionInput): Promise<CameraSessionCreated>;
352
+ /** POST /api/v1/live-sessions/{id}/camera-grant — cấp lại grant, thu hồi grant cũ. */
353
+ cameraGrant(sessionId: string): Promise<CameraGrant>;
354
+ /** POST /api/v1/live-sessions/{id}/end — kết thúc phiên từ backend đối tác. */
355
+ end(sessionId: string): Promise<{
356
+ status: "ended";
357
+ }>;
358
+ get(sessionId: string): Promise<ApiLiveSession>;
359
+ getRecordings(sessionId: string): Promise<ApiRecording[]>;
360
+ };
361
+ devices: {
362
+ register(input: BootstrapInput & DeviceInfoInput): Promise<DeviceRegisterResult>;
363
+ heartbeat(input: BootstrapInput & DeviceHeartbeatInput): Promise<DeviceHeartbeatResult>;
364
+ };
200
365
  webhooks: {
201
366
  verify<T extends WebhookPayload = WebhookPayload>(rawBody: WebhookRawBody, headers: WebhookHeaders, secret: string, options?: VerifyWebhookOptions): Promise<VerifiedWebhook<T>>;
202
367
  };
203
368
  }
204
369
  declare function createPickleballLiveClient(options: PickleballLiveClientOptions): PickleballLiveClient;
205
370
 
206
- export { type ApiLiveSession, type ApiRecording, type BootstrapInput, type EndLivestreamInput, type LivestreamSessionProvider, type LivestreamState, PickleballApiError, PickleballConfigurationError, PickleballHttpError, PickleballInvalidResponseError, type PickleballLiveClient, type PickleballLiveClientOptions, PickleballLiveError, PickleballNetworkError, PickleballTimeoutError, PickleballWebhookVerificationError, type RecordingType, SDK_TELEMETRY_EVENT_NAMES, type SdkBootstrap, type SdkError, type SdkErrorCode, type SdkPublishState, type SdkRemoteConfig, type SdkSessionGrant, type SdkSessionRefresh, type SdkTelemetryCredentials, type SdkTelemetryEvent, type SdkTelemetryEventName, type ServerSdkErrorCode, type SessionStatus, type SessionVisibility, type StartLivestreamInput, type StartSdkSessionInput, type VerifiedWebhook, type VerifyWebhookOptions, type WebhookHeaders, type WebhookPayload, type WebhookRawBody, createPickleballLiveClient, verifyWebhook };
371
+ export { type ApiLiveSession, type ApiRecording, type BootstrapInput, type CameraGrant, type CameraGrantStatus, type CameraSessionCreated, type CreateCameraSessionInput, type DeviceControlSessionGrant, type DeviceHeartbeatInput, type DeviceHeartbeatResult, type DeviceInfoInput, type DeviceMetricsInput, type DeviceRegisterResult, type EndLivestreamInput, type LivestreamSessionProvider, type LivestreamState, PickleballApiError, PickleballConfigurationError, PickleballHttpError, PickleballInvalidResponseError, type PickleballLiveClient, type PickleballLiveClientOptions, PickleballLiveError, PickleballNetworkError, PickleballPartnerApiError, PickleballTimeoutError, PickleballWebhookVerificationError, type RecordingType, SDK_TELEMETRY_EVENT_NAMES, type SdkBootstrap, type SdkConflictReason, type SdkError, type SdkErrorCode, type SdkPublishState, type SdkRemoteConfig, type SdkSessionGrant, type SdkSessionRefresh, type SdkTelemetryCredentials, type SdkTelemetryEvent, type SdkTelemetryEventName, type ServerSdkErrorCode, type SessionStatus, type SessionVisibility, type StartLivestreamInput, type StartSdkSessionInput, type VerifiedWebhook, type VerifyWebhookOptions, type WebhookHeaders, type WebhookPayload, type WebhookRawBody, createPickleballLiveClient, verifyWebhook };
package/dist/index.js CHANGED
@@ -5,12 +5,13 @@ import {
5
5
  PickleballInvalidResponseError,
6
6
  PickleballLiveError,
7
7
  PickleballNetworkError,
8
+ PickleballPartnerApiError,
8
9
  PickleballTimeoutError,
9
10
  PickleballWebhookVerificationError,
10
11
  SDK_TELEMETRY_EVENT_NAMES,
11
12
  createPickleballLiveClient,
12
13
  verifyWebhook
13
- } from "./chunk-HBTNLURN.js";
14
+ } from "./chunk-UPS4VFER.js";
14
15
  export {
15
16
  PickleballApiError,
16
17
  PickleballConfigurationError,
@@ -18,6 +19,7 @@ export {
18
19
  PickleballInvalidResponseError,
19
20
  PickleballLiveError,
20
21
  PickleballNetworkError,
22
+ PickleballPartnerApiError,
21
23
  PickleballTimeoutError,
22
24
  PickleballWebhookVerificationError,
23
25
  SDK_TELEMETRY_EVENT_NAMES,