@shadowob/sdk 0.2.2 → 0.2.3

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/src/client.ts CHANGED
@@ -1,14 +1,31 @@
1
1
  import type {
2
+ ShadowApp,
3
+ ShadowCartItem,
4
+ ShadowCategory,
2
5
  ShadowChannel,
6
+ ShadowContract,
3
7
  ShadowDmChannel,
8
+ ShadowFriendship,
4
9
  ShadowInviteCode,
10
+ ShadowListing,
5
11
  ShadowMember,
6
12
  ShadowMessage,
7
13
  ShadowNotification,
14
+ ShadowNotificationPreferences,
15
+ ShadowOAuthApp,
16
+ ShadowOAuthConsent,
17
+ ShadowOAuthToken,
18
+ ShadowOrder,
19
+ ShadowProduct,
8
20
  ShadowRemoteConfig,
21
+ ShadowReview,
9
22
  ShadowServer,
23
+ ShadowShop,
24
+ ShadowTask,
10
25
  ShadowThread,
26
+ ShadowTransaction,
11
27
  ShadowUser,
28
+ ShadowWallet,
12
29
  } from './types'
13
30
 
14
31
  /**
@@ -328,14 +345,18 @@ export class ShadowClient {
328
345
  serverId: string,
329
346
  data: { name: string; type?: string; description?: string },
330
347
  ): Promise<ShadowChannel> {
331
- return this.request(`/api/servers/${serverId}/channels`, {
348
+ const { description, ...rest } = data
349
+ const body = { ...rest, ...(description !== undefined ? { topic: description } : {}) }
350
+ const ch = await this.request<Record<string, unknown>>(`/api/servers/${serverId}/channels`, {
332
351
  method: 'POST',
333
- body: JSON.stringify(data),
352
+ body: JSON.stringify(body),
334
353
  })
354
+ return { ...ch, description: ch.topic } as unknown as ShadowChannel
335
355
  }
336
356
 
337
357
  async getChannel(channelId: string): Promise<ShadowChannel> {
338
- return this.request(`/api/channels/${channelId}`)
358
+ const ch = await this.request<Record<string, unknown>>(`/api/channels/${channelId}`)
359
+ return { ...ch, description: ch.topic } as unknown as ShadowChannel
339
360
  }
340
361
 
341
362
  async getChannelMembers(channelId: string): Promise<ShadowMember[]> {
@@ -346,10 +367,13 @@ export class ShadowClient {
346
367
  channelId: string,
347
368
  data: { name?: string; description?: string | null },
348
369
  ): Promise<ShadowChannel> {
349
- return this.request(`/api/channels/${channelId}`, {
370
+ const { description, ...rest } = data
371
+ const body = { ...rest, ...(description !== undefined ? { topic: description } : {}) }
372
+ const ch = await this.request<Record<string, unknown>>(`/api/channels/${channelId}`, {
350
373
  method: 'PATCH',
351
- body: JSON.stringify(data),
374
+ body: JSON.stringify(body),
352
375
  })
376
+ return { ...ch, description: ch.topic } as unknown as ShadowChannel
353
377
  }
354
378
 
355
379
  async deleteChannel(channelId: string): Promise<{ success: boolean }> {
@@ -440,11 +464,17 @@ export class ShadowClient {
440
464
 
441
465
  // ── Pins ──────────────────────────────────────────────────────────────
442
466
 
443
- async pinMessage(messageId: string): Promise<{ success: boolean }> {
467
+ async pinMessage(messageId: string, channelId?: string): Promise<{ success: boolean }> {
468
+ if (channelId) {
469
+ return this.request(`/api/channels/${channelId}/pins/${messageId}`, { method: 'PUT' })
470
+ }
444
471
  return this.request(`/api/messages/${messageId}/pin`, { method: 'POST' })
445
472
  }
446
473
 
447
- async unpinMessage(messageId: string): Promise<{ success: boolean }> {
474
+ async unpinMessage(messageId: string, channelId?: string): Promise<{ success: boolean }> {
475
+ if (channelId) {
476
+ return this.request(`/api/channels/${channelId}/pins/${messageId}`, { method: 'DELETE' })
477
+ }
448
478
  return this.request(`/api/messages/${messageId}/pin`, { method: 'DELETE' })
449
479
  }
450
480
 
@@ -537,10 +567,14 @@ export class ShadowClient {
537
567
  return this.request(`/api/dm/channels/${channelId}/messages?${params}`)
538
568
  }
539
569
 
540
- async sendDmMessage(channelId: string, content: string): Promise<ShadowMessage> {
570
+ async sendDmMessage(
571
+ channelId: string,
572
+ content: string,
573
+ options?: { replyToId?: string },
574
+ ): Promise<ShadowMessage> {
541
575
  return this.request(`/api/dm/channels/${channelId}/messages`, {
542
576
  method: 'POST',
543
- body: JSON.stringify({ content }),
577
+ body: JSON.stringify({ content, replyToId: options?.replyToId }),
544
578
  })
545
579
  }
546
580
 
@@ -556,7 +590,7 @@ export class ShadowClient {
556
590
  }
557
591
 
558
592
  async markAllNotificationsRead(): Promise<{ success: boolean }> {
559
- return this.request('/api/notifications/read-all', { method: 'PATCH' })
593
+ return this.request('/api/notifications/read-all', { method: 'POST' })
560
594
  }
561
595
 
562
596
  async getUnreadCount(): Promise<{ count: number }> {
@@ -573,34 +607,40 @@ export class ShadowClient {
573
607
  limit?: number
574
608
  offset?: number
575
609
  }): Promise<{ messages: ShadowMessage[]; total: number }> {
576
- const params = new URLSearchParams({ q: query.q })
610
+ const params = new URLSearchParams({ query: query.q })
577
611
  if (query.serverId) params.set('serverId', query.serverId)
578
612
  if (query.channelId) params.set('channelId', query.channelId)
579
- if (query.authorId) params.set('authorId', query.authorId)
613
+ if (query.authorId) params.set('from', query.authorId)
580
614
  if (query.limit) params.set('limit', String(query.limit))
581
615
  if (query.offset) params.set('offset', String(query.offset))
582
- return this.request(`/api/search/messages?${params}`)
616
+ const result = await this.request<
617
+ ShadowMessage[] | { messages: ShadowMessage[]; total: number }
618
+ >(`/api/search/messages?${params}`)
619
+ if (Array.isArray(result)) {
620
+ return { messages: result, total: result.length }
621
+ }
622
+ return result
583
623
  }
584
624
 
585
625
  // ── Invites ───────────────────────────────────────────────────────────
586
626
 
587
627
  async listInvites(): Promise<ShadowInviteCode[]> {
588
- return this.request('/api/invites')
628
+ return this.request('/api/invite-codes')
589
629
  }
590
630
 
591
631
  async createInvites(count: number, note?: string): Promise<ShadowInviteCode[]> {
592
- return this.request('/api/invites', {
632
+ return this.request('/api/invite-codes', {
593
633
  method: 'POST',
594
634
  body: JSON.stringify({ count, ...(note ? { note } : {}) }),
595
635
  })
596
636
  }
597
637
 
598
638
  async deactivateInvite(inviteId: string): Promise<ShadowInviteCode> {
599
- return this.request(`/api/invites/${inviteId}/deactivate`, { method: 'PATCH' })
639
+ return this.request(`/api/invite-codes/${inviteId}/deactivate`, { method: 'PATCH' })
600
640
  }
601
641
 
602
642
  async deleteInvite(inviteId: string): Promise<{ success: boolean }> {
603
- return this.request(`/api/invites/${inviteId}`, { method: 'DELETE' })
643
+ return this.request(`/api/invite-codes/${inviteId}`, { method: 'DELETE' })
604
644
  }
605
645
 
606
646
  // ── Media ─────────────────────────────────────────────────────────────
@@ -965,4 +1005,566 @@ export class ShadowClient {
965
1005
  )
966
1006
  return res.arrayBuffer()
967
1007
  }
1008
+
1009
+ // ── Auth (extended) ───────────────────────────────────────────────────
1010
+
1011
+ async getUserProfile(userId: string): Promise<ShadowUser> {
1012
+ return this.request(`/api/auth/users/${userId}`)
1013
+ }
1014
+
1015
+ async listOAuthAccounts(): Promise<
1016
+ { id: string; provider: string; providerAccountId: string }[]
1017
+ > {
1018
+ return this.request('/api/auth/oauth/accounts')
1019
+ }
1020
+
1021
+ async unlinkOAuthAccount(accountId: string): Promise<{ success: boolean }> {
1022
+ return this.request(`/api/auth/oauth/accounts/${accountId}`, { method: 'DELETE' })
1023
+ }
1024
+
1025
+ // ── Friendships ───────────────────────────────────────────────────────
1026
+
1027
+ async sendFriendRequest(username: string): Promise<ShadowFriendship> {
1028
+ return this.request('/api/friends/request', {
1029
+ method: 'POST',
1030
+ body: JSON.stringify({ username }),
1031
+ })
1032
+ }
1033
+
1034
+ async acceptFriendRequest(requestId: string): Promise<ShadowFriendship> {
1035
+ return this.request(`/api/friends/${requestId}/accept`, { method: 'POST' })
1036
+ }
1037
+
1038
+ async rejectFriendRequest(requestId: string): Promise<ShadowFriendship> {
1039
+ return this.request(`/api/friends/${requestId}/reject`, { method: 'POST' })
1040
+ }
1041
+
1042
+ async removeFriend(friendshipId: string): Promise<{ success: boolean }> {
1043
+ return this.request(`/api/friends/${friendshipId}`, { method: 'DELETE' })
1044
+ }
1045
+
1046
+ async listFriends(): Promise<ShadowFriendship[]> {
1047
+ return this.request('/api/friends')
1048
+ }
1049
+
1050
+ async listPendingFriendRequests(): Promise<ShadowFriendship[]> {
1051
+ return this.request('/api/friends/pending')
1052
+ }
1053
+
1054
+ async listSentFriendRequests(): Promise<ShadowFriendship[]> {
1055
+ return this.request('/api/friends/sent')
1056
+ }
1057
+
1058
+ // ── Notifications (extended) ──────────────────────────────────────────
1059
+
1060
+ async markScopeRead(scope: {
1061
+ serverId?: string
1062
+ channelId?: string
1063
+ }): Promise<{ success: boolean }> {
1064
+ return this.request('/api/notifications/read-scope', {
1065
+ method: 'POST',
1066
+ body: JSON.stringify(scope),
1067
+ })
1068
+ }
1069
+
1070
+ async getScopedUnread(): Promise<Record<string, number>> {
1071
+ return this.request('/api/notifications/scoped-unread')
1072
+ }
1073
+
1074
+ async getNotificationPreferences(): Promise<ShadowNotificationPreferences> {
1075
+ return this.request('/api/notifications/preferences')
1076
+ }
1077
+
1078
+ async updateNotificationPreferences(
1079
+ data: Partial<ShadowNotificationPreferences>,
1080
+ ): Promise<ShadowNotificationPreferences> {
1081
+ return this.request('/api/notifications/preferences', {
1082
+ method: 'PATCH',
1083
+ body: JSON.stringify(data),
1084
+ })
1085
+ }
1086
+
1087
+ // ── OAuth Apps ────────────────────────────────────────────────────────
1088
+
1089
+ async createOAuthApp(data: {
1090
+ name: string
1091
+ redirectUris: string[]
1092
+ scopes?: string[]
1093
+ }): Promise<ShadowOAuthApp> {
1094
+ return this.request('/api/oauth/apps', {
1095
+ method: 'POST',
1096
+ body: JSON.stringify(data),
1097
+ })
1098
+ }
1099
+
1100
+ async listOAuthApps(): Promise<ShadowOAuthApp[]> {
1101
+ return this.request('/api/oauth/apps')
1102
+ }
1103
+
1104
+ async updateOAuthApp(
1105
+ appId: string,
1106
+ data: { name?: string; redirectUris?: string[]; scopes?: string[] },
1107
+ ): Promise<ShadowOAuthApp> {
1108
+ return this.request(`/api/oauth/apps/${appId}`, {
1109
+ method: 'PATCH',
1110
+ body: JSON.stringify(data),
1111
+ })
1112
+ }
1113
+
1114
+ async deleteOAuthApp(appId: string): Promise<{ success: boolean }> {
1115
+ return this.request(`/api/oauth/apps/${appId}`, { method: 'DELETE' })
1116
+ }
1117
+
1118
+ async resetOAuthAppSecret(appId: string): Promise<{ clientSecret: string }> {
1119
+ return this.request(`/api/oauth/apps/${appId}/reset-secret`, { method: 'POST' })
1120
+ }
1121
+
1122
+ async getOAuthAuthorization(params: {
1123
+ client_id: string
1124
+ redirect_uri: string
1125
+ scope?: string
1126
+ state?: string
1127
+ }): Promise<{ app: ShadowOAuthApp }> {
1128
+ const qs = new URLSearchParams(params)
1129
+ return this.request(`/api/oauth/authorize?${qs}`)
1130
+ }
1131
+
1132
+ async approveOAuthAuthorization(data: {
1133
+ client_id: string
1134
+ redirect_uri: string
1135
+ scope?: string
1136
+ state?: string
1137
+ }): Promise<{ redirectUrl: string }> {
1138
+ return this.request('/api/oauth/authorize', {
1139
+ method: 'POST',
1140
+ body: JSON.stringify(data),
1141
+ })
1142
+ }
1143
+
1144
+ async exchangeOAuthToken(data: {
1145
+ grant_type: 'authorization_code' | 'refresh_token'
1146
+ code?: string
1147
+ refresh_token?: string
1148
+ client_id: string
1149
+ client_secret: string
1150
+ redirect_uri?: string
1151
+ }): Promise<ShadowOAuthToken> {
1152
+ return this.request('/api/oauth/token', {
1153
+ method: 'POST',
1154
+ body: JSON.stringify(data),
1155
+ })
1156
+ }
1157
+
1158
+ async listOAuthConsents(): Promise<ShadowOAuthConsent[]> {
1159
+ return this.request('/api/oauth/consents')
1160
+ }
1161
+
1162
+ async revokeOAuthConsent(appId: string): Promise<{ success: boolean }> {
1163
+ return this.request('/api/oauth/revoke', {
1164
+ method: 'POST',
1165
+ body: JSON.stringify({ appId }),
1166
+ })
1167
+ }
1168
+
1169
+ // ── Marketplace / Rentals ─────────────────────────────────────────────
1170
+
1171
+ async browseListings(params?: {
1172
+ search?: string
1173
+ tags?: string[]
1174
+ minPrice?: number
1175
+ maxPrice?: number
1176
+ limit?: number
1177
+ offset?: number
1178
+ }): Promise<{ listings: ShadowListing[]; total: number }> {
1179
+ const qs = new URLSearchParams()
1180
+ if (params?.search) qs.set('search', params.search)
1181
+ if (params?.tags) for (const t of params.tags) qs.append('tags', t)
1182
+ if (params?.minPrice != null) qs.set('minPrice', String(params.minPrice))
1183
+ if (params?.maxPrice != null) qs.set('maxPrice', String(params.maxPrice))
1184
+ if (params?.limit) qs.set('limit', String(params.limit))
1185
+ if (params?.offset) qs.set('offset', String(params.offset))
1186
+ return this.request(`/api/marketplace/listings?${qs}`)
1187
+ }
1188
+
1189
+ async getListing(listingId: string): Promise<ShadowListing> {
1190
+ return this.request(`/api/marketplace/listings/${listingId}`)
1191
+ }
1192
+
1193
+ async estimateRentalCost(
1194
+ listingId: string,
1195
+ hours: number,
1196
+ ): Promise<{ totalCost: number; currency: string }> {
1197
+ const qs = new URLSearchParams({ hours: String(hours) })
1198
+ return this.request(`/api/marketplace/listings/${listingId}/estimate?${qs}`)
1199
+ }
1200
+
1201
+ async listMyListings(): Promise<ShadowListing[]> {
1202
+ return this.request('/api/marketplace/my-listings')
1203
+ }
1204
+
1205
+ async createListing(data: {
1206
+ agentId: string
1207
+ title: string
1208
+ description: string
1209
+ pricePerHour: number
1210
+ currency?: string
1211
+ tags?: string[]
1212
+ }): Promise<ShadowListing> {
1213
+ return this.request('/api/marketplace/listings', {
1214
+ method: 'POST',
1215
+ body: JSON.stringify(data),
1216
+ })
1217
+ }
1218
+
1219
+ async updateListing(
1220
+ listingId: string,
1221
+ data: Partial<{ title: string; description: string; pricePerHour: number; tags: string[] }>,
1222
+ ): Promise<ShadowListing> {
1223
+ return this.request(`/api/marketplace/listings/${listingId}`, {
1224
+ method: 'PUT',
1225
+ body: JSON.stringify(data),
1226
+ })
1227
+ }
1228
+
1229
+ async toggleListing(listingId: string): Promise<ShadowListing> {
1230
+ return this.request(`/api/marketplace/listings/${listingId}/toggle`, { method: 'PUT' })
1231
+ }
1232
+
1233
+ async deleteListing(listingId: string): Promise<{ success: boolean }> {
1234
+ return this.request(`/api/marketplace/listings/${listingId}`, { method: 'DELETE' })
1235
+ }
1236
+
1237
+ async signContract(data: { listingId: string; hours: number }): Promise<ShadowContract> {
1238
+ return this.request('/api/marketplace/contracts', {
1239
+ method: 'POST',
1240
+ body: JSON.stringify(data),
1241
+ })
1242
+ }
1243
+
1244
+ async listContracts(params?: {
1245
+ role?: 'tenant' | 'owner'
1246
+ status?: string
1247
+ }): Promise<ShadowContract[]> {
1248
+ const qs = new URLSearchParams()
1249
+ if (params?.role) qs.set('role', params.role)
1250
+ if (params?.status) qs.set('status', params.status)
1251
+ return this.request(`/api/marketplace/contracts?${qs}`)
1252
+ }
1253
+
1254
+ async getContract(contractId: string): Promise<ShadowContract> {
1255
+ return this.request(`/api/marketplace/contracts/${contractId}`)
1256
+ }
1257
+
1258
+ async terminateContract(contractId: string): Promise<ShadowContract> {
1259
+ return this.request(`/api/marketplace/contracts/${contractId}/terminate`, { method: 'POST' })
1260
+ }
1261
+
1262
+ async recordUsageSession(
1263
+ contractId: string,
1264
+ data: { durationMinutes: number; description?: string },
1265
+ ): Promise<{ success: boolean }> {
1266
+ return this.request(`/api/marketplace/contracts/${contractId}/usage`, {
1267
+ method: 'POST',
1268
+ body: JSON.stringify(data),
1269
+ })
1270
+ }
1271
+
1272
+ async reportViolation(
1273
+ contractId: string,
1274
+ data: { reason: string },
1275
+ ): Promise<{ success: boolean }> {
1276
+ return this.request(`/api/marketplace/contracts/${contractId}/violate`, {
1277
+ method: 'POST',
1278
+ body: JSON.stringify(data),
1279
+ })
1280
+ }
1281
+
1282
+ // ── Shop ──────────────────────────────────────────────────────────────
1283
+
1284
+ async getShop(serverId: string): Promise<ShadowShop> {
1285
+ return this.request(`/api/servers/${serverId}/shop`)
1286
+ }
1287
+
1288
+ async updateShop(
1289
+ serverId: string,
1290
+ data: Partial<{ name: string; description: string | null; isEnabled: boolean }>,
1291
+ ): Promise<ShadowShop> {
1292
+ return this.request(`/api/servers/${serverId}/shop`, {
1293
+ method: 'PUT',
1294
+ body: JSON.stringify(data),
1295
+ })
1296
+ }
1297
+
1298
+ async listCategories(serverId: string): Promise<ShadowCategory[]> {
1299
+ return this.request(`/api/servers/${serverId}/shop/categories`)
1300
+ }
1301
+
1302
+ async createCategory(
1303
+ serverId: string,
1304
+ data: { name: string; description?: string },
1305
+ ): Promise<ShadowCategory> {
1306
+ return this.request(`/api/servers/${serverId}/shop/categories`, {
1307
+ method: 'POST',
1308
+ body: JSON.stringify(data),
1309
+ })
1310
+ }
1311
+
1312
+ async updateCategory(
1313
+ serverId: string,
1314
+ categoryId: string,
1315
+ data: Partial<{ name: string; description: string | null; position: number }>,
1316
+ ): Promise<ShadowCategory> {
1317
+ return this.request(`/api/servers/${serverId}/shop/categories/${categoryId}`, {
1318
+ method: 'PUT',
1319
+ body: JSON.stringify(data),
1320
+ })
1321
+ }
1322
+
1323
+ async deleteCategory(serverId: string, categoryId: string): Promise<{ success: boolean }> {
1324
+ return this.request(`/api/servers/${serverId}/shop/categories/${categoryId}`, {
1325
+ method: 'DELETE',
1326
+ })
1327
+ }
1328
+
1329
+ async listProducts(
1330
+ serverId: string,
1331
+ params?: {
1332
+ status?: string
1333
+ categoryId?: string
1334
+ keyword?: string
1335
+ limit?: number
1336
+ offset?: number
1337
+ },
1338
+ ): Promise<{ products: ShadowProduct[]; total: number }> {
1339
+ const qs = new URLSearchParams()
1340
+ if (params?.status) qs.set('status', params.status)
1341
+ if (params?.categoryId) qs.set('categoryId', params.categoryId)
1342
+ if (params?.keyword) qs.set('keyword', params.keyword)
1343
+ if (params?.limit) qs.set('limit', String(params.limit))
1344
+ if (params?.offset) qs.set('offset', String(params.offset))
1345
+ return this.request(`/api/servers/${serverId}/shop/products?${qs}`)
1346
+ }
1347
+
1348
+ async getProduct(serverId: string, productId: string): Promise<ShadowProduct> {
1349
+ return this.request(`/api/servers/${serverId}/shop/products/${productId}`)
1350
+ }
1351
+
1352
+ async createProduct(
1353
+ serverId: string,
1354
+ data: {
1355
+ name: string
1356
+ description?: string
1357
+ price: number
1358
+ currency?: string
1359
+ stock: number
1360
+ categoryId?: string
1361
+ images?: string[]
1362
+ },
1363
+ ): Promise<ShadowProduct> {
1364
+ return this.request(`/api/servers/${serverId}/shop/products`, {
1365
+ method: 'POST',
1366
+ body: JSON.stringify(data),
1367
+ })
1368
+ }
1369
+
1370
+ async updateProduct(
1371
+ serverId: string,
1372
+ productId: string,
1373
+ data: Partial<{
1374
+ name: string
1375
+ description: string | null
1376
+ price: number
1377
+ stock: number
1378
+ status: string
1379
+ categoryId: string | null
1380
+ images: string[]
1381
+ }>,
1382
+ ): Promise<ShadowProduct> {
1383
+ return this.request(`/api/servers/${serverId}/shop/products/${productId}`, {
1384
+ method: 'PUT',
1385
+ body: JSON.stringify(data),
1386
+ })
1387
+ }
1388
+
1389
+ async deleteProduct(serverId: string, productId: string): Promise<{ success: boolean }> {
1390
+ return this.request(`/api/servers/${serverId}/shop/products/${productId}`, { method: 'DELETE' })
1391
+ }
1392
+
1393
+ async getCart(serverId: string): Promise<ShadowCartItem[]> {
1394
+ return this.request(`/api/servers/${serverId}/shop/cart`)
1395
+ }
1396
+
1397
+ async addToCart(
1398
+ serverId: string,
1399
+ data: { productId: string; quantity: number },
1400
+ ): Promise<ShadowCartItem> {
1401
+ return this.request(`/api/servers/${serverId}/shop/cart`, {
1402
+ method: 'POST',
1403
+ body: JSON.stringify(data),
1404
+ })
1405
+ }
1406
+
1407
+ async updateCartItem(
1408
+ serverId: string,
1409
+ itemId: string,
1410
+ quantity: number,
1411
+ ): Promise<ShadowCartItem> {
1412
+ return this.request(`/api/servers/${serverId}/shop/cart/${itemId}`, {
1413
+ method: 'PUT',
1414
+ body: JSON.stringify({ quantity }),
1415
+ })
1416
+ }
1417
+
1418
+ async removeCartItem(serverId: string, itemId: string): Promise<{ success: boolean }> {
1419
+ return this.request(`/api/servers/${serverId}/shop/cart/${itemId}`, { method: 'DELETE' })
1420
+ }
1421
+
1422
+ async createOrder(
1423
+ serverId: string,
1424
+ data?: { items?: { productId: string; quantity: number }[] },
1425
+ ): Promise<ShadowOrder> {
1426
+ return this.request(`/api/servers/${serverId}/shop/orders`, {
1427
+ method: 'POST',
1428
+ body: JSON.stringify(data ?? {}),
1429
+ })
1430
+ }
1431
+
1432
+ async listOrders(serverId: string): Promise<ShadowOrder[]> {
1433
+ return this.request(`/api/servers/${serverId}/shop/orders`)
1434
+ }
1435
+
1436
+ async listShopOrders(serverId: string): Promise<ShadowOrder[]> {
1437
+ return this.request(`/api/servers/${serverId}/shop/orders/manage`)
1438
+ }
1439
+
1440
+ async getOrder(serverId: string, orderId: string): Promise<ShadowOrder> {
1441
+ return this.request(`/api/servers/${serverId}/shop/orders/${orderId}`)
1442
+ }
1443
+
1444
+ async updateOrderStatus(serverId: string, orderId: string, status: string): Promise<ShadowOrder> {
1445
+ return this.request(`/api/servers/${serverId}/shop/orders/${orderId}/status`, {
1446
+ method: 'PUT',
1447
+ body: JSON.stringify({ status }),
1448
+ })
1449
+ }
1450
+
1451
+ async cancelOrder(serverId: string, orderId: string): Promise<ShadowOrder> {
1452
+ return this.request(`/api/servers/${serverId}/shop/orders/${orderId}/cancel`, {
1453
+ method: 'POST',
1454
+ })
1455
+ }
1456
+
1457
+ async getProductReviews(serverId: string, productId: string): Promise<ShadowReview[]> {
1458
+ return this.request(`/api/servers/${serverId}/shop/products/${productId}/reviews`)
1459
+ }
1460
+
1461
+ async createReview(
1462
+ serverId: string,
1463
+ orderId: string,
1464
+ data: { productId: string; rating: number; content: string },
1465
+ ): Promise<ShadowReview> {
1466
+ return this.request(`/api/servers/${serverId}/shop/orders/${orderId}/review`, {
1467
+ method: 'POST',
1468
+ body: JSON.stringify(data),
1469
+ })
1470
+ }
1471
+
1472
+ async replyToReview(serverId: string, reviewId: string, reply: string): Promise<ShadowReview> {
1473
+ return this.request(`/api/servers/${serverId}/shop/reviews/${reviewId}/reply`, {
1474
+ method: 'PUT',
1475
+ body: JSON.stringify({ reply }),
1476
+ })
1477
+ }
1478
+
1479
+ async getWallet(): Promise<ShadowWallet> {
1480
+ return this.request('/api/wallet')
1481
+ }
1482
+
1483
+ async topUpWallet(amount: number): Promise<ShadowWallet> {
1484
+ return this.request('/api/wallet/topup', {
1485
+ method: 'POST',
1486
+ body: JSON.stringify({ amount }),
1487
+ })
1488
+ }
1489
+
1490
+ async getWalletTransactions(): Promise<ShadowTransaction[]> {
1491
+ return this.request('/api/wallet/transactions')
1492
+ }
1493
+
1494
+ async getEntitlements(serverId: string): Promise<Record<string, unknown>[]> {
1495
+ return this.request(`/api/servers/${serverId}/shop/entitlements`)
1496
+ }
1497
+
1498
+ // ── Task Center ───────────────────────────────────────────────────────
1499
+
1500
+ async getTaskCenter(): Promise<{ tasks: ShadowTask[] }> {
1501
+ return this.request('/api/tasks')
1502
+ }
1503
+
1504
+ async claimTask(taskKey: string): Promise<{ success: boolean; reward: number }> {
1505
+ return this.request(`/api/tasks/${taskKey}/claim`, { method: 'POST' })
1506
+ }
1507
+
1508
+ async getReferralSummary(): Promise<{ count: number; rewards: number }> {
1509
+ return this.request('/api/tasks/referral-summary')
1510
+ }
1511
+
1512
+ async getRewardHistory(): Promise<{
1513
+ rewards: { amount: number; reason: string; createdAt: string }[]
1514
+ }> {
1515
+ return this.request('/api/tasks/rewards')
1516
+ }
1517
+
1518
+ // ── Server Apps ───────────────────────────────────────────────────────
1519
+
1520
+ async listApps(
1521
+ serverId: string,
1522
+ params?: { status?: string; limit?: number; offset?: number },
1523
+ ): Promise<{ apps: ShadowApp[]; total: number }> {
1524
+ const qs = new URLSearchParams()
1525
+ if (params?.status) qs.set('status', params.status)
1526
+ if (params?.limit) qs.set('limit', String(params.limit))
1527
+ if (params?.offset) qs.set('offset', String(params.offset))
1528
+ return this.request(`/api/servers/${serverId}/apps?${qs}`)
1529
+ }
1530
+
1531
+ async getHomepageApp(serverId: string): Promise<ShadowApp | null> {
1532
+ return this.request(`/api/servers/${serverId}/apps/homepage`)
1533
+ }
1534
+
1535
+ async getApp(serverId: string, appId: string): Promise<ShadowApp> {
1536
+ return this.request(`/api/servers/${serverId}/apps/${appId}`)
1537
+ }
1538
+
1539
+ async createApp(
1540
+ serverId: string,
1541
+ data: { name: string; slug: string; type: string; url?: string },
1542
+ ): Promise<ShadowApp> {
1543
+ return this.request(`/api/servers/${serverId}/apps`, {
1544
+ method: 'POST',
1545
+ body: JSON.stringify(data),
1546
+ })
1547
+ }
1548
+
1549
+ async updateApp(
1550
+ serverId: string,
1551
+ appId: string,
1552
+ data: Partial<{ name: string; slug: string; type: string; url: string; status: string }>,
1553
+ ): Promise<ShadowApp> {
1554
+ return this.request(`/api/servers/${serverId}/apps/${appId}`, {
1555
+ method: 'PATCH',
1556
+ body: JSON.stringify(data),
1557
+ })
1558
+ }
1559
+
1560
+ async deleteApp(serverId: string, appId: string): Promise<{ success: boolean }> {
1561
+ return this.request(`/api/servers/${serverId}/apps/${appId}`, { method: 'DELETE' })
1562
+ }
1563
+
1564
+ async publishApp(serverId: string, data: { name: string; slug: string }): Promise<ShadowApp> {
1565
+ return this.request(`/api/servers/${serverId}/apps/publish`, {
1566
+ method: 'POST',
1567
+ body: JSON.stringify(data),
1568
+ })
1569
+ }
968
1570
  }