@0xobelisk/graphql-client 1.2.0-pre.123 → 1.2.0-pre.124

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
@@ -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,
@@ -57,6 +143,37 @@ function mapCachePolicyToFetchPolicy(cachePolicy: CachePolicy): FetchPolicy {
57
143
  }
58
144
  }
59
145
 
146
+ /**
147
+ * Build the HTTP transport link.
148
+ *
149
+ * When `config.batchRequests` is true, returns a `BatchHttpLink` that collects
150
+ * queries fired within `batchInterval` ms (default 10 ms) and sends them as a
151
+ * single POST request. The PostGraphile server already has `enableQueryBatching`
152
+ * enabled, so no server-side changes are needed.
153
+ *
154
+ * Falls back to the standard `createHttpLink` when batching is disabled.
155
+ */
156
+ function buildHttpLink(config: DubheClientConfig): ApolloLink {
157
+ const fetchFn = (input: RequestInfo | URL, init?: RequestInit) =>
158
+ fetch(input, { ...config.fetchOptions, ...(init ?? {}) });
159
+
160
+ if (config.batchRequests) {
161
+ return new BatchHttpLink({
162
+ uri: config.endpoint,
163
+ headers: config.headers,
164
+ fetch: fetchFn,
165
+ batchInterval: config.batchInterval ?? 10,
166
+ batchMax: config.batchMax ?? 20
167
+ });
168
+ }
169
+
170
+ return createHttpLink({
171
+ uri: config.endpoint,
172
+ headers: config.headers,
173
+ fetch: fetchFn
174
+ });
175
+ }
176
+
60
177
  export class DubheGraphqlClient {
61
178
  private apolloClient: ApolloClient<NormalizedCacheObject>;
62
179
  private subscriptionClient?: any;
@@ -77,12 +194,8 @@ export class DubheGraphqlClient {
77
194
  this.parseTableInfoFromConfig();
78
195
  }
79
196
 
80
- // Create HTTP Link
81
- const httpLink = createHttpLink({
82
- uri: config.endpoint,
83
- headers: config.headers,
84
- fetch: (input, init) => fetch(input, { ...config.fetchOptions, ...init })
85
- });
197
+ // Create HTTP link (batched or standard depending on config.batchRequests)
198
+ const httpLink = buildHttpLink(config);
86
199
 
87
200
  // Create retry link
88
201
  const retryLink = new RetryLink({
@@ -248,12 +361,8 @@ export class DubheGraphqlClient {
248
361
  this.subscriptionClient = undefined;
249
362
  }
250
363
 
251
- // Recreate HTTP Link
252
- const httpLink = createHttpLink({
253
- uri: this.currentConfig.endpoint,
254
- headers: this.currentConfig.headers,
255
- fetch: (input, init) => fetch(input, { ...this.currentConfig.fetchOptions, ...init })
256
- });
364
+ // Recreate HTTP link (batched or standard depending on config)
365
+ const httpLink = buildHttpLink(this.currentConfig);
257
366
 
258
367
  // Recreate retry link with current config
259
368
  const retryLink = new RetryLink({
@@ -1491,12 +1600,24 @@ export class DubheGraphqlClient {
1491
1600
  if (customFields && customFields.length > 0) {
1492
1601
  fields = customFields;
1493
1602
  } else {
1494
- // Try to get fields from dubhe configuration
1495
- const autoFields = this.getTableFields(tableName);
1496
- if (autoFields.length > 0) {
1497
- fields = autoFields;
1603
+ // 1. Check system table registry first
1604
+ const systemFields = SYSTEM_TABLE_FIELDS[tableName];
1605
+ if (systemFields) {
1606
+ fields = systemFields;
1498
1607
  } else {
1499
- fields = ['createdAtTimestampMs', 'updatedAtTimestampMs', 'isDeleted', 'lastUpdateDigest'];
1608
+ // 2. Try to get fields from dubhe configuration (DApp store tables)
1609
+ const autoFields = this.getTableFields(tableName);
1610
+ if (autoFields.length > 0) {
1611
+ fields = autoFields;
1612
+ } else {
1613
+ // 3. Generic fallback for store_* tables
1614
+ fields = [
1615
+ 'createdAtTimestampMs',
1616
+ 'updatedAtTimestampMs',
1617
+ 'isDeleted',
1618
+ 'lastUpdateDigest'
1619
+ ];
1620
+ }
1500
1621
  }
1501
1622
  }
1502
1623
 
@@ -1504,6 +1625,74 @@ export class DubheGraphqlClient {
1504
1625
 
1505
1626
  return fields.join('\n ');
1506
1627
  }
1628
+
1629
+ // ── Typed system-table query methods ─────────────────────────────────────
1630
+
1631
+ /** Latest DApp fee state snapshot (credit_pool, total_settled, fee rates). */
1632
+ async getDappFeeState(): Promise<{
1633
+ entityId: string;
1634
+ baseFeePerWrite: string;
1635
+ bytesFeePerByte: string;
1636
+ freeCredit: string;
1637
+ creditPool: string;
1638
+ totalSettled: string;
1639
+ updatedAtTimestampMs: string;
1640
+ } | null> {
1641
+ const result = await this.getAllTables<any>('dubheDappFeeState', { first: 1 }).catch(
1642
+ () => null
1643
+ );
1644
+ return result?.edges?.[0]?.node ?? null;
1645
+ }
1646
+
1647
+ /** Latest DApp revenue balance (USER_PAYS mode collected revenue). */
1648
+ async getDappRevenueState(): Promise<{
1649
+ entityId: string;
1650
+ dappRevenue: string;
1651
+ coinType: string;
1652
+ updatedAtTimestampMs: string;
1653
+ } | null> {
1654
+ const result = await this.getAllTables<any>('dubheDappRevenueState', { first: 1 }).catch(
1655
+ () => null
1656
+ );
1657
+ return result?.edges?.[0]?.node ?? null;
1658
+ }
1659
+
1660
+ /** Latest DApp runtime state (admin, settlement mode, last event). */
1661
+ async getDappRuntimeState(): Promise<{
1662
+ dappKey: string;
1663
+ admin: string;
1664
+ paused: boolean;
1665
+ settlementMode: number;
1666
+ creditPool: string;
1667
+ writeFeeShareBps: number;
1668
+ lastRuntimeEvent: string;
1669
+ lastRuntimeActor: string;
1670
+ lastRuntimeAmount: string;
1671
+ } | null> {
1672
+ const result = await this.getAllTables<any>('dubheDappRuntimeState', { first: 1 }).catch(
1673
+ () => null
1674
+ );
1675
+ return result?.edges?.[0]?.node ?? null;
1676
+ }
1677
+
1678
+ /** Marketplace fee records (one row per listing sold). */
1679
+ async getDappMarketplaceFees(options?: { first?: number; after?: string }): Promise<
1680
+ Connection<{
1681
+ dappKey: string;
1682
+ listingId: string;
1683
+ coinType: string;
1684
+ totalFee: string;
1685
+ treasuryAmount: string;
1686
+ dappAmount: string;
1687
+ updatedAtCheckpoint: string;
1688
+ }>
1689
+ > {
1690
+ return this.getAllTables<any>('dubheDappMarketplaceFees', {
1691
+ first: options?.first ?? 20,
1692
+ after: options?.after,
1693
+ orderBy: [{ field: 'updatedAtCheckpoint', direction: 'DESC' }]
1694
+ });
1695
+ }
1507
1696
  }
1508
1697
 
1509
1698
  // Export convenience function
package/src/types.ts CHANGED
@@ -328,6 +328,27 @@ export interface DubheClientConfig {
328
328
  fetchOptions?: RequestInit;
329
329
  retryOptions?: RetryOptions;
330
330
  dubheMetadata?: any;
331
+ /**
332
+ * When true, outgoing HTTP queries are collected within `batchInterval` ms
333
+ * and sent as a single batched POST request. The server must have
334
+ * `enableQueryBatching` / `allowBatchedHttpRequests` enabled (PostGraphile
335
+ * already sets this by default).
336
+ *
337
+ * Default: false
338
+ */
339
+ batchRequests?: boolean;
340
+ /**
341
+ * Time window (ms) to collect queries before flushing a batch.
342
+ * Only used when `batchRequests` is true.
343
+ * Default: 10
344
+ */
345
+ batchInterval?: number;
346
+ /**
347
+ * Maximum number of operations per batch.
348
+ * Only used when `batchRequests` is true.
349
+ * Default: 20
350
+ */
351
+ batchMax?: number;
331
352
  cacheConfig?: {
332
353
  paginatedTables?: string[];
333
354
  strategy?: PaginationCacheStrategy;