@0xobelisk/graphql-client 1.2.0-pre.123 → 1.2.0-pre.125
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/client.d.ts +83 -1
- package/dist/decoders.d.ts +24 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +434 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +421 -15
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.ts +63 -0
- package/package.json +1 -1
- package/src/client.ts +432 -18
- package/src/decoders.ts +100 -0
- package/src/index.ts +1 -0
- package/src/types.ts +66 -0
package/dist/types.d.ts
CHANGED
|
@@ -118,6 +118,48 @@ export interface DubheUserStorageRow {
|
|
|
118
118
|
lastUpdateDigest: string;
|
|
119
119
|
lastEventSeq: string;
|
|
120
120
|
}
|
|
121
|
+
export interface SceneStorageRow {
|
|
122
|
+
sceneId: string;
|
|
123
|
+
dappKey: string;
|
|
124
|
+
sceneType: string;
|
|
125
|
+
sceneTypeRaw: string;
|
|
126
|
+
authorizationKind?: string | null;
|
|
127
|
+
authorizationKindRaw?: string | null;
|
|
128
|
+
authorizedPermitId?: string | null;
|
|
129
|
+
isDestroyed: boolean;
|
|
130
|
+
createdAtCheckpoint: string;
|
|
131
|
+
destroyedAtCheckpoint?: string | null;
|
|
132
|
+
updatedAtCheckpoint: string;
|
|
133
|
+
lastUpdateDigest: string;
|
|
134
|
+
lastEventSeq: string;
|
|
135
|
+
}
|
|
136
|
+
export interface SceneStorageFieldRow {
|
|
137
|
+
sceneId: string;
|
|
138
|
+
fieldNameRaw: string;
|
|
139
|
+
dappKey: string;
|
|
140
|
+
sceneType: string;
|
|
141
|
+
sceneTypeRaw: string;
|
|
142
|
+
fieldName: string;
|
|
143
|
+
fieldValueRaw?: string | null;
|
|
144
|
+
isDeleted: boolean;
|
|
145
|
+
deletedAtCheckpoint?: string | null;
|
|
146
|
+
updatedAtCheckpoint: string;
|
|
147
|
+
lastUpdateDigest: string;
|
|
148
|
+
lastEventSeq: string;
|
|
149
|
+
}
|
|
150
|
+
export interface ObjectStorageRow {
|
|
151
|
+
objectId: string;
|
|
152
|
+
dappKey: string;
|
|
153
|
+
objectType: string;
|
|
154
|
+
objectTypeRaw: string;
|
|
155
|
+
entityIdRaw: string;
|
|
156
|
+
isDestroyed: boolean;
|
|
157
|
+
createdAtCheckpoint: string;
|
|
158
|
+
destroyedAtCheckpoint?: string | null;
|
|
159
|
+
updatedAtCheckpoint: string;
|
|
160
|
+
lastUpdateDigest: string;
|
|
161
|
+
lastEventSeq: string;
|
|
162
|
+
}
|
|
121
163
|
export interface DubheDappRuntimeStateRow {
|
|
122
164
|
dappKey: string;
|
|
123
165
|
admin?: string | null;
|
|
@@ -254,6 +296,27 @@ export interface DubheClientConfig {
|
|
|
254
296
|
fetchOptions?: RequestInit;
|
|
255
297
|
retryOptions?: RetryOptions;
|
|
256
298
|
dubheMetadata?: any;
|
|
299
|
+
/**
|
|
300
|
+
* When true, outgoing HTTP queries are collected within `batchInterval` ms
|
|
301
|
+
* and sent as a single batched POST request. The server must have
|
|
302
|
+
* `enableQueryBatching` / `allowBatchedHttpRequests` enabled (PostGraphile
|
|
303
|
+
* already sets this by default).
|
|
304
|
+
*
|
|
305
|
+
* Default: false
|
|
306
|
+
*/
|
|
307
|
+
batchRequests?: boolean;
|
|
308
|
+
/**
|
|
309
|
+
* Time window (ms) to collect queries before flushing a batch.
|
|
310
|
+
* Only used when `batchRequests` is true.
|
|
311
|
+
* Default: 10
|
|
312
|
+
*/
|
|
313
|
+
batchInterval?: number;
|
|
314
|
+
/**
|
|
315
|
+
* Maximum number of operations per batch.
|
|
316
|
+
* Only used when `batchRequests` is true.
|
|
317
|
+
* Default: 20
|
|
318
|
+
*/
|
|
319
|
+
batchMax?: number;
|
|
257
320
|
cacheConfig?: {
|
|
258
321
|
paginatedTables?: string[];
|
|
259
322
|
strategy?: PaginationCacheStrategy;
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -11,12 +11,98 @@ import {
|
|
|
11
11
|
FetchPolicy,
|
|
12
12
|
OperationVariables
|
|
13
13
|
} from '@apollo/client';
|
|
14
|
+
import { BatchHttpLink } from '@apollo/client/link/batch-http';
|
|
14
15
|
import { RetryLink } from '@apollo/client/link/retry';
|
|
15
16
|
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
|
|
16
17
|
import { getMainDefinition } from '@apollo/client/utilities';
|
|
17
18
|
import { createClient } from 'graphql-ws';
|
|
18
19
|
import pluralize from 'pluralize';
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Static field registry for Dubhe system tables.
|
|
23
|
+
*
|
|
24
|
+
* These tables are exposed via `store_dubhe_*` views in the graphql-server.
|
|
25
|
+
* They are NOT in the DApp's dubhe.config schema, so `convertTableFields`
|
|
26
|
+
* cannot auto-discover their fields. Registering them here means callers
|
|
27
|
+
* can use `getAllTables('dubheDappMarketplaceFees', ...)` without passing
|
|
28
|
+
* `fields` explicitly.
|
|
29
|
+
*
|
|
30
|
+
* Key: the simplified GraphQL field name (after SimpleNamingPlugin strips
|
|
31
|
+
* the `storeDubhe` prefix and removes the `all` prefix).
|
|
32
|
+
* Value: camelCase GraphQL field names matching the PostGraphile schema.
|
|
33
|
+
*/
|
|
34
|
+
const SYSTEM_TABLE_FIELDS: Record<string, string[]> = {
|
|
35
|
+
dubheDappMarketplaceFees: [
|
|
36
|
+
'dappKey',
|
|
37
|
+
'listingId',
|
|
38
|
+
'coinType',
|
|
39
|
+
'totalFee',
|
|
40
|
+
'treasuryAmount',
|
|
41
|
+
'dappAmount',
|
|
42
|
+
'updatedAtCheckpoint',
|
|
43
|
+
'lastUpdateDigest'
|
|
44
|
+
],
|
|
45
|
+
dubheDappRuntimeState: [
|
|
46
|
+
'dappKey',
|
|
47
|
+
'admin',
|
|
48
|
+
'paused',
|
|
49
|
+
'settlementMode',
|
|
50
|
+
'creditPool',
|
|
51
|
+
'writeFeeShareBps',
|
|
52
|
+
'lastRuntimeEvent',
|
|
53
|
+
'lastRuntimeActor',
|
|
54
|
+
'lastRuntimeAmount',
|
|
55
|
+
'updatedAtCheckpoint',
|
|
56
|
+
'lastUpdateDigest'
|
|
57
|
+
],
|
|
58
|
+
dubheDappFeeState: [
|
|
59
|
+
'entityId',
|
|
60
|
+
'baseFeePerWrite',
|
|
61
|
+
'bytesFeePerByte',
|
|
62
|
+
'freeCredit',
|
|
63
|
+
'creditPool',
|
|
64
|
+
'totalSettled',
|
|
65
|
+
'updatedAtTimestampMs',
|
|
66
|
+
'lastUpdateDigest'
|
|
67
|
+
],
|
|
68
|
+
dubheDappRevenueState: [
|
|
69
|
+
'entityId',
|
|
70
|
+
'dappRevenue',
|
|
71
|
+
'coinType',
|
|
72
|
+
'updatedAtTimestampMs',
|
|
73
|
+
'lastUpdateDigest'
|
|
74
|
+
],
|
|
75
|
+
dubheMarketplaceListings: [
|
|
76
|
+
'dappKey',
|
|
77
|
+
'listingId',
|
|
78
|
+
'seller',
|
|
79
|
+
'recordType',
|
|
80
|
+
'price',
|
|
81
|
+
'coinType',
|
|
82
|
+
'isFungible',
|
|
83
|
+
'listedUntil',
|
|
84
|
+
'status',
|
|
85
|
+
'updatedAtCheckpoint',
|
|
86
|
+
'lastUpdateDigest'
|
|
87
|
+
],
|
|
88
|
+
dubheSessions: [
|
|
89
|
+
'dappKey',
|
|
90
|
+
'canonical',
|
|
91
|
+
'sessionWallet',
|
|
92
|
+
'expiresAt',
|
|
93
|
+
'active',
|
|
94
|
+
'updatedAtCheckpoint',
|
|
95
|
+
'lastUpdateDigest'
|
|
96
|
+
],
|
|
97
|
+
dubheUserStorages: [
|
|
98
|
+
'dappKey',
|
|
99
|
+
'canonicalOwner',
|
|
100
|
+
'userStorageId',
|
|
101
|
+
'updatedAtCheckpoint',
|
|
102
|
+
'lastUpdateDigest'
|
|
103
|
+
]
|
|
104
|
+
};
|
|
105
|
+
|
|
20
106
|
import {
|
|
21
107
|
DubheClientConfig,
|
|
22
108
|
Connection,
|
|
@@ -36,7 +122,10 @@ import {
|
|
|
36
122
|
MarketplaceListingRow,
|
|
37
123
|
DubheSessionRow,
|
|
38
124
|
DubheUserStorageRow,
|
|
39
|
-
DubheDappRuntimeStateRow
|
|
125
|
+
DubheDappRuntimeStateRow,
|
|
126
|
+
SceneStorageRow,
|
|
127
|
+
SceneStorageFieldRow,
|
|
128
|
+
ObjectStorageRow
|
|
40
129
|
} from './types';
|
|
41
130
|
|
|
42
131
|
// Convert cache policy type
|
|
@@ -57,6 +146,37 @@ function mapCachePolicyToFetchPolicy(cachePolicy: CachePolicy): FetchPolicy {
|
|
|
57
146
|
}
|
|
58
147
|
}
|
|
59
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Build the HTTP transport link.
|
|
151
|
+
*
|
|
152
|
+
* When `config.batchRequests` is true, returns a `BatchHttpLink` that collects
|
|
153
|
+
* queries fired within `batchInterval` ms (default 10 ms) and sends them as a
|
|
154
|
+
* single POST request. The PostGraphile server already has `enableQueryBatching`
|
|
155
|
+
* enabled, so no server-side changes are needed.
|
|
156
|
+
*
|
|
157
|
+
* Falls back to the standard `createHttpLink` when batching is disabled.
|
|
158
|
+
*/
|
|
159
|
+
function buildHttpLink(config: DubheClientConfig): ApolloLink {
|
|
160
|
+
const fetchFn = (input: RequestInfo | URL, init?: RequestInit) =>
|
|
161
|
+
fetch(input, { ...config.fetchOptions, ...(init ?? {}) });
|
|
162
|
+
|
|
163
|
+
if (config.batchRequests) {
|
|
164
|
+
return new BatchHttpLink({
|
|
165
|
+
uri: config.endpoint,
|
|
166
|
+
headers: config.headers,
|
|
167
|
+
fetch: fetchFn,
|
|
168
|
+
batchInterval: config.batchInterval ?? 10,
|
|
169
|
+
batchMax: config.batchMax ?? 20
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return createHttpLink({
|
|
174
|
+
uri: config.endpoint,
|
|
175
|
+
headers: config.headers,
|
|
176
|
+
fetch: fetchFn
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
60
180
|
export class DubheGraphqlClient {
|
|
61
181
|
private apolloClient: ApolloClient<NormalizedCacheObject>;
|
|
62
182
|
private subscriptionClient?: any;
|
|
@@ -77,12 +197,8 @@ export class DubheGraphqlClient {
|
|
|
77
197
|
this.parseTableInfoFromConfig();
|
|
78
198
|
}
|
|
79
199
|
|
|
80
|
-
// Create HTTP
|
|
81
|
-
const httpLink =
|
|
82
|
-
uri: config.endpoint,
|
|
83
|
-
headers: config.headers,
|
|
84
|
-
fetch: (input, init) => fetch(input, { ...config.fetchOptions, ...init })
|
|
85
|
-
});
|
|
200
|
+
// Create HTTP link (batched or standard depending on config.batchRequests)
|
|
201
|
+
const httpLink = buildHttpLink(config);
|
|
86
202
|
|
|
87
203
|
// Create retry link
|
|
88
204
|
const retryLink = new RetryLink({
|
|
@@ -248,12 +364,8 @@ export class DubheGraphqlClient {
|
|
|
248
364
|
this.subscriptionClient = undefined;
|
|
249
365
|
}
|
|
250
366
|
|
|
251
|
-
// Recreate HTTP
|
|
252
|
-
const httpLink =
|
|
253
|
-
uri: this.currentConfig.endpoint,
|
|
254
|
-
headers: this.currentConfig.headers,
|
|
255
|
-
fetch: (input, init) => fetch(input, { ...this.currentConfig.fetchOptions, ...init })
|
|
256
|
-
});
|
|
367
|
+
// Recreate HTTP link (batched or standard depending on config)
|
|
368
|
+
const httpLink = buildHttpLink(this.currentConfig);
|
|
257
369
|
|
|
258
370
|
// Recreate retry link with current config
|
|
259
371
|
const retryLink = new RetryLink({
|
|
@@ -1099,6 +1211,228 @@ export class DubheGraphqlClient {
|
|
|
1099
1211
|
);
|
|
1100
1212
|
}
|
|
1101
1213
|
|
|
1214
|
+
/**
|
|
1215
|
+
* Query SceneStorage system rows indexed by the Dubhe indexer
|
|
1216
|
+
* (scene_storages table, exposed as dubheSceneStorages in GraphQL).
|
|
1217
|
+
* Field values live in the companion scene_storage_fields table —
|
|
1218
|
+
* see getSceneStorageFields.
|
|
1219
|
+
*/
|
|
1220
|
+
async getSceneStorages(options?: {
|
|
1221
|
+
dappKey?: string;
|
|
1222
|
+
sceneType?: string;
|
|
1223
|
+
sceneId?: string;
|
|
1224
|
+
isDestroyed?: boolean;
|
|
1225
|
+
first?: number;
|
|
1226
|
+
after?: string;
|
|
1227
|
+
}): Promise<Connection<SceneStorageRow>> {
|
|
1228
|
+
const filter: Record<string, any> = {};
|
|
1229
|
+
if (options?.dappKey) filter.dappKey = { equalTo: options.dappKey };
|
|
1230
|
+
if (options?.sceneType) filter.sceneType = { equalTo: options.sceneType };
|
|
1231
|
+
if (options?.sceneId) filter.sceneId = { equalTo: options.sceneId };
|
|
1232
|
+
if (options?.isDestroyed !== undefined) filter.isDestroyed = { equalTo: options.isDestroyed };
|
|
1233
|
+
|
|
1234
|
+
const query = gql`
|
|
1235
|
+
query GetSceneStorages(
|
|
1236
|
+
$first: Int
|
|
1237
|
+
$after: Cursor
|
|
1238
|
+
$filter: StoreDubheSceneStorageFilter
|
|
1239
|
+
$orderBy: [StoreDubheSceneStoragesOrderBy!]
|
|
1240
|
+
) {
|
|
1241
|
+
dubheSceneStorages(first: $first, after: $after, filter: $filter, orderBy: $orderBy) {
|
|
1242
|
+
totalCount
|
|
1243
|
+
pageInfo {
|
|
1244
|
+
hasNextPage
|
|
1245
|
+
hasPreviousPage
|
|
1246
|
+
startCursor
|
|
1247
|
+
endCursor
|
|
1248
|
+
}
|
|
1249
|
+
edges {
|
|
1250
|
+
cursor
|
|
1251
|
+
node {
|
|
1252
|
+
sceneId
|
|
1253
|
+
dappKey
|
|
1254
|
+
sceneType
|
|
1255
|
+
authorizationKind
|
|
1256
|
+
authorizedPermitId
|
|
1257
|
+
isDestroyed
|
|
1258
|
+
createdAtCheckpoint
|
|
1259
|
+
updatedAtCheckpoint
|
|
1260
|
+
lastUpdateDigest
|
|
1261
|
+
lastEventSeq
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
`;
|
|
1267
|
+
|
|
1268
|
+
const result = await this.apolloClient.query({
|
|
1269
|
+
query,
|
|
1270
|
+
variables: {
|
|
1271
|
+
first: options?.first ?? 100,
|
|
1272
|
+
after: options?.after,
|
|
1273
|
+
filter: Object.keys(filter).length > 0 ? filter : undefined,
|
|
1274
|
+
orderBy: ['UPDATED_AT_CHECKPOINT_DESC']
|
|
1275
|
+
},
|
|
1276
|
+
fetchPolicy: 'network-only'
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
if (result.error) throw result.error;
|
|
1280
|
+
return (
|
|
1281
|
+
(result.data as any)?.dubheSceneStorages ?? {
|
|
1282
|
+
edges: [],
|
|
1283
|
+
pageInfo: { hasNextPage: false, hasPreviousPage: false },
|
|
1284
|
+
totalCount: 0
|
|
1285
|
+
}
|
|
1286
|
+
);
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
/**
|
|
1290
|
+
* Query raw field rows of SceneStorages (scene_storage_fields table,
|
|
1291
|
+
* exposed as dubheSceneStorageFields in GraphQL). Values are hex-encoded
|
|
1292
|
+
* BCS — decode with the decoders exported from this package.
|
|
1293
|
+
*/
|
|
1294
|
+
async getSceneStorageFields(options?: {
|
|
1295
|
+
dappKey?: string;
|
|
1296
|
+
sceneIds?: string[];
|
|
1297
|
+
sceneId?: string;
|
|
1298
|
+
fieldName?: string;
|
|
1299
|
+
isDeleted?: boolean;
|
|
1300
|
+
first?: number;
|
|
1301
|
+
after?: string;
|
|
1302
|
+
}): Promise<Connection<SceneStorageFieldRow>> {
|
|
1303
|
+
const filter: Record<string, any> = {};
|
|
1304
|
+
if (options?.dappKey) filter.dappKey = { equalTo: options.dappKey };
|
|
1305
|
+
if (options?.sceneIds && options.sceneIds.length > 0) filter.sceneId = { in: options.sceneIds };
|
|
1306
|
+
if (options?.sceneId) filter.sceneId = { equalTo: options.sceneId };
|
|
1307
|
+
if (options?.fieldName) filter.fieldName = { equalTo: options.fieldName };
|
|
1308
|
+
if (options?.isDeleted !== undefined) filter.isDeleted = { equalTo: options.isDeleted };
|
|
1309
|
+
|
|
1310
|
+
const query = gql`
|
|
1311
|
+
query GetSceneStorageFields(
|
|
1312
|
+
$first: Int
|
|
1313
|
+
$after: Cursor
|
|
1314
|
+
$filter: StoreDubheSceneStorageFieldFilter
|
|
1315
|
+
$orderBy: [StoreDubheSceneStorageFieldsOrderBy!]
|
|
1316
|
+
) {
|
|
1317
|
+
dubheSceneStorageFields(first: $first, after: $after, filter: $filter, orderBy: $orderBy) {
|
|
1318
|
+
totalCount
|
|
1319
|
+
pageInfo {
|
|
1320
|
+
hasNextPage
|
|
1321
|
+
hasPreviousPage
|
|
1322
|
+
startCursor
|
|
1323
|
+
endCursor
|
|
1324
|
+
}
|
|
1325
|
+
edges {
|
|
1326
|
+
cursor
|
|
1327
|
+
node {
|
|
1328
|
+
sceneId
|
|
1329
|
+
dappKey
|
|
1330
|
+
sceneType
|
|
1331
|
+
fieldName
|
|
1332
|
+
fieldValueRaw
|
|
1333
|
+
isDeleted
|
|
1334
|
+
updatedAtCheckpoint
|
|
1335
|
+
lastUpdateDigest
|
|
1336
|
+
lastEventSeq
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
`;
|
|
1342
|
+
|
|
1343
|
+
const result = await this.apolloClient.query({
|
|
1344
|
+
query,
|
|
1345
|
+
variables: {
|
|
1346
|
+
first: options?.first ?? 1000,
|
|
1347
|
+
after: options?.after,
|
|
1348
|
+
filter: Object.keys(filter).length > 0 ? filter : undefined,
|
|
1349
|
+
orderBy: ['UPDATED_AT_CHECKPOINT_DESC']
|
|
1350
|
+
},
|
|
1351
|
+
fetchPolicy: 'network-only'
|
|
1352
|
+
});
|
|
1353
|
+
|
|
1354
|
+
if (result.error) throw result.error;
|
|
1355
|
+
return (
|
|
1356
|
+
(result.data as any)?.dubheSceneStorageFields ?? {
|
|
1357
|
+
edges: [],
|
|
1358
|
+
pageInfo: { hasNextPage: false, hasPreviousPage: false },
|
|
1359
|
+
totalCount: 0
|
|
1360
|
+
}
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* Query ObjectStorage system rows indexed by the Dubhe indexer
|
|
1366
|
+
* (object_storages table, exposed as dubheObjectStorages in GraphQL).
|
|
1367
|
+
*/
|
|
1368
|
+
async getObjectStorages(options?: {
|
|
1369
|
+
dappKey?: string;
|
|
1370
|
+
objectType?: string;
|
|
1371
|
+
objectId?: string;
|
|
1372
|
+
isDestroyed?: boolean;
|
|
1373
|
+
first?: number;
|
|
1374
|
+
after?: string;
|
|
1375
|
+
}): Promise<Connection<ObjectStorageRow>> {
|
|
1376
|
+
const filter: Record<string, any> = {};
|
|
1377
|
+
if (options?.dappKey) filter.dappKey = { equalTo: options.dappKey };
|
|
1378
|
+
if (options?.objectType) filter.objectType = { equalTo: options.objectType };
|
|
1379
|
+
if (options?.objectId) filter.objectId = { equalTo: options.objectId };
|
|
1380
|
+
if (options?.isDestroyed !== undefined) filter.isDestroyed = { equalTo: options.isDestroyed };
|
|
1381
|
+
|
|
1382
|
+
const query = gql`
|
|
1383
|
+
query GetObjectStorages(
|
|
1384
|
+
$first: Int
|
|
1385
|
+
$after: Cursor
|
|
1386
|
+
$filter: StoreDubheObjectStorageFilter
|
|
1387
|
+
$orderBy: [StoreDubheObjectStoragesOrderBy!]
|
|
1388
|
+
) {
|
|
1389
|
+
dubheObjectStorages(first: $first, after: $after, filter: $filter, orderBy: $orderBy) {
|
|
1390
|
+
totalCount
|
|
1391
|
+
pageInfo {
|
|
1392
|
+
hasNextPage
|
|
1393
|
+
hasPreviousPage
|
|
1394
|
+
startCursor
|
|
1395
|
+
endCursor
|
|
1396
|
+
}
|
|
1397
|
+
edges {
|
|
1398
|
+
cursor
|
|
1399
|
+
node {
|
|
1400
|
+
objectId
|
|
1401
|
+
dappKey
|
|
1402
|
+
objectType
|
|
1403
|
+
entityIdRaw
|
|
1404
|
+
isDestroyed
|
|
1405
|
+
createdAtCheckpoint
|
|
1406
|
+
updatedAtCheckpoint
|
|
1407
|
+
lastUpdateDigest
|
|
1408
|
+
lastEventSeq
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
`;
|
|
1414
|
+
|
|
1415
|
+
const result = await this.apolloClient.query({
|
|
1416
|
+
query,
|
|
1417
|
+
variables: {
|
|
1418
|
+
first: options?.first ?? 100,
|
|
1419
|
+
after: options?.after,
|
|
1420
|
+
filter: Object.keys(filter).length > 0 ? filter : undefined,
|
|
1421
|
+
orderBy: ['UPDATED_AT_CHECKPOINT_DESC']
|
|
1422
|
+
},
|
|
1423
|
+
fetchPolicy: 'network-only'
|
|
1424
|
+
});
|
|
1425
|
+
|
|
1426
|
+
if (result.error) throw result.error;
|
|
1427
|
+
return (
|
|
1428
|
+
(result.data as any)?.dubheObjectStorages ?? {
|
|
1429
|
+
edges: [],
|
|
1430
|
+
pageInfo: { hasNextPage: false, hasPreviousPage: false },
|
|
1431
|
+
totalCount: 0
|
|
1432
|
+
}
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1102
1436
|
/**
|
|
1103
1437
|
* Query DApp runtime state (credit pool, admin, package version, etc.).
|
|
1104
1438
|
* Exposed as dubheDappRuntimeStates in GraphQL.
|
|
@@ -1491,12 +1825,24 @@ export class DubheGraphqlClient {
|
|
|
1491
1825
|
if (customFields && customFields.length > 0) {
|
|
1492
1826
|
fields = customFields;
|
|
1493
1827
|
} else {
|
|
1494
|
-
//
|
|
1495
|
-
const
|
|
1496
|
-
if (
|
|
1497
|
-
fields =
|
|
1828
|
+
// 1. Check system table registry first
|
|
1829
|
+
const systemFields = SYSTEM_TABLE_FIELDS[tableName];
|
|
1830
|
+
if (systemFields) {
|
|
1831
|
+
fields = systemFields;
|
|
1498
1832
|
} else {
|
|
1499
|
-
fields
|
|
1833
|
+
// 2. Try to get fields from dubhe configuration (DApp store tables)
|
|
1834
|
+
const autoFields = this.getTableFields(tableName);
|
|
1835
|
+
if (autoFields.length > 0) {
|
|
1836
|
+
fields = autoFields;
|
|
1837
|
+
} else {
|
|
1838
|
+
// 3. Generic fallback for store_* tables
|
|
1839
|
+
fields = [
|
|
1840
|
+
'createdAtTimestampMs',
|
|
1841
|
+
'updatedAtTimestampMs',
|
|
1842
|
+
'isDeleted',
|
|
1843
|
+
'lastUpdateDigest'
|
|
1844
|
+
];
|
|
1845
|
+
}
|
|
1500
1846
|
}
|
|
1501
1847
|
}
|
|
1502
1848
|
|
|
@@ -1504,6 +1850,74 @@ export class DubheGraphqlClient {
|
|
|
1504
1850
|
|
|
1505
1851
|
return fields.join('\n ');
|
|
1506
1852
|
}
|
|
1853
|
+
|
|
1854
|
+
// ── Typed system-table query methods ─────────────────────────────────────
|
|
1855
|
+
|
|
1856
|
+
/** Latest DApp fee state snapshot (credit_pool, total_settled, fee rates). */
|
|
1857
|
+
async getDappFeeState(): Promise<{
|
|
1858
|
+
entityId: string;
|
|
1859
|
+
baseFeePerWrite: string;
|
|
1860
|
+
bytesFeePerByte: string;
|
|
1861
|
+
freeCredit: string;
|
|
1862
|
+
creditPool: string;
|
|
1863
|
+
totalSettled: string;
|
|
1864
|
+
updatedAtTimestampMs: string;
|
|
1865
|
+
} | null> {
|
|
1866
|
+
const result = await this.getAllTables<any>('dubheDappFeeState', { first: 1 }).catch(
|
|
1867
|
+
() => null
|
|
1868
|
+
);
|
|
1869
|
+
return result?.edges?.[0]?.node ?? null;
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
/** Latest DApp revenue balance (USER_PAYS mode collected revenue). */
|
|
1873
|
+
async getDappRevenueState(): Promise<{
|
|
1874
|
+
entityId: string;
|
|
1875
|
+
dappRevenue: string;
|
|
1876
|
+
coinType: string;
|
|
1877
|
+
updatedAtTimestampMs: string;
|
|
1878
|
+
} | null> {
|
|
1879
|
+
const result = await this.getAllTables<any>('dubheDappRevenueState', { first: 1 }).catch(
|
|
1880
|
+
() => null
|
|
1881
|
+
);
|
|
1882
|
+
return result?.edges?.[0]?.node ?? null;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
/** Latest DApp runtime state (admin, settlement mode, last event). */
|
|
1886
|
+
async getDappRuntimeState(): Promise<{
|
|
1887
|
+
dappKey: string;
|
|
1888
|
+
admin: string;
|
|
1889
|
+
paused: boolean;
|
|
1890
|
+
settlementMode: number;
|
|
1891
|
+
creditPool: string;
|
|
1892
|
+
writeFeeShareBps: number;
|
|
1893
|
+
lastRuntimeEvent: string;
|
|
1894
|
+
lastRuntimeActor: string;
|
|
1895
|
+
lastRuntimeAmount: string;
|
|
1896
|
+
} | null> {
|
|
1897
|
+
const result = await this.getAllTables<any>('dubheDappRuntimeState', { first: 1 }).catch(
|
|
1898
|
+
() => null
|
|
1899
|
+
);
|
|
1900
|
+
return result?.edges?.[0]?.node ?? null;
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
/** Marketplace fee records (one row per listing sold). */
|
|
1904
|
+
async getDappMarketplaceFees(options?: { first?: number; after?: string }): Promise<
|
|
1905
|
+
Connection<{
|
|
1906
|
+
dappKey: string;
|
|
1907
|
+
listingId: string;
|
|
1908
|
+
coinType: string;
|
|
1909
|
+
totalFee: string;
|
|
1910
|
+
treasuryAmount: string;
|
|
1911
|
+
dappAmount: string;
|
|
1912
|
+
updatedAtCheckpoint: string;
|
|
1913
|
+
}>
|
|
1914
|
+
> {
|
|
1915
|
+
return this.getAllTables<any>('dubheDappMarketplaceFees', {
|
|
1916
|
+
first: options?.first ?? 20,
|
|
1917
|
+
after: options?.after,
|
|
1918
|
+
orderBy: [{ field: 'updatedAtCheckpoint', direction: 'DESC' }]
|
|
1919
|
+
});
|
|
1920
|
+
}
|
|
1507
1921
|
}
|
|
1508
1922
|
|
|
1509
1923
|
// Export convenience function
|
package/src/decoders.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal BCS decoders for indexer raw values.
|
|
3
|
+
*
|
|
4
|
+
* The Dubhe indexer stores scene/object field values and marketplace record
|
|
5
|
+
* data as hex-encoded BCS bytes (e.g. "0x0c00000000000000" for u64 12).
|
|
6
|
+
* These helpers decode the primitive types commonly stored in system tables.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export const ZERO_ADDRESS = '0x' + '0'.repeat(64);
|
|
10
|
+
|
|
11
|
+
export function hexToBytes(hex: string): Uint8Array {
|
|
12
|
+
const clean = hex.replace(/^0x/i, '');
|
|
13
|
+
const pairs = clean.match(/../g) ?? [];
|
|
14
|
+
return Uint8Array.from(pairs.map((b) => parseInt(b, 16)));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function readUIntLE(bytes: Uint8Array, offset: number, width: number): bigint {
|
|
18
|
+
let n = 0n;
|
|
19
|
+
for (let i = width - 1; i >= 0; i--) {
|
|
20
|
+
n = (n << 8n) | BigInt(bytes[offset + i] ?? 0);
|
|
21
|
+
}
|
|
22
|
+
return n;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Read a ULEB128-encoded length prefix. Returns [value, bytesConsumed]. */
|
|
26
|
+
function readUleb(bytes: Uint8Array, offset: number): [number, number] {
|
|
27
|
+
let value = 0;
|
|
28
|
+
let shift = 0;
|
|
29
|
+
let consumed = 0;
|
|
30
|
+
for (;;) {
|
|
31
|
+
const byte = bytes[offset + consumed] ?? 0;
|
|
32
|
+
value |= (byte & 0x7f) << shift;
|
|
33
|
+
consumed++;
|
|
34
|
+
if ((byte & 0x80) === 0) break;
|
|
35
|
+
shift += 7;
|
|
36
|
+
}
|
|
37
|
+
return [value, consumed];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function decodeU8(hex: string): number {
|
|
41
|
+
return Number(readUIntLE(hexToBytes(hex), 0, 1));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function decodeU16(hex: string): number {
|
|
45
|
+
return Number(readUIntLE(hexToBytes(hex), 0, 2));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function decodeU32(hex: string): number {
|
|
49
|
+
return Number(readUIntLE(hexToBytes(hex), 0, 4));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function decodeU64(hex: string): bigint {
|
|
53
|
+
return readUIntLE(hexToBytes(hex), 0, 8);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function decodeU128(hex: string): bigint {
|
|
57
|
+
return readUIntLE(hexToBytes(hex), 0, 16);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function decodeBool(hex: string): boolean {
|
|
61
|
+
return (hexToBytes(hex)[0] ?? 0) !== 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function decodeAddress(hex: string): string {
|
|
65
|
+
const bytes = hexToBytes(hex);
|
|
66
|
+
return '0x' + Array.from(bytes.slice(0, 32), (b) => b.toString(16).padStart(2, '0')).join('');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function decodeVectorAddress(hex: string): string[] {
|
|
70
|
+
const bytes = hexToBytes(hex);
|
|
71
|
+
const [len, consumed] = readUleb(bytes, 0);
|
|
72
|
+
const out: string[] = [];
|
|
73
|
+
for (let i = 0; i < len; i++) {
|
|
74
|
+
const start = consumed + i * 32;
|
|
75
|
+
out.push(
|
|
76
|
+
'0x' +
|
|
77
|
+
Array.from(bytes.slice(start, start + 32), (b) => b.toString(16).padStart(2, '0')).join('')
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Decode a BCS ascii/utf8 String (ULEB length prefix + bytes). */
|
|
84
|
+
export function decodeString(hex: string): string {
|
|
85
|
+
const bytes = hexToBytes(hex);
|
|
86
|
+
const [len, consumed] = readUleb(bytes, 0);
|
|
87
|
+
return new TextDecoder().decode(bytes.slice(consumed, consumed + len));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Marketplace recordDataRaw is a JSON array of per-field hex strings
|
|
92
|
+
* (non-key fields, in schema order).
|
|
93
|
+
*/
|
|
94
|
+
export function parseRecordData(recordDataRaw: string): string[] {
|
|
95
|
+
try {
|
|
96
|
+
return JSON.parse(recordDataRaw) as string[];
|
|
97
|
+
} catch {
|
|
98
|
+
return [recordDataRaw];
|
|
99
|
+
}
|
|
100
|
+
}
|
package/src/index.ts
CHANGED