@0xobelisk/graphql-client 1.2.0-pre.24
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/LICENSE +92 -0
- package/dist/client.d.ts +221 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1582 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1560 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types.d.ts +211 -0
- package/dist/utils.d.ts +2 -0
- package/package.json +154 -0
- package/src/client.ts +1209 -0
- package/src/index.ts +7 -0
- package/src/types.ts +294 -0
- package/src/utils.ts +49 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1582 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from2, except, desc) => {
|
|
14
|
+
if (from2 && typeof from2 === "object" || typeof from2 === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from2))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from2[key], enumerable: !(desc = __getOwnPropDesc(from2, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var __publicField = (obj, key, value) => {
|
|
31
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
32
|
+
return value;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// src/index.ts
|
|
36
|
+
var src_exports = {};
|
|
37
|
+
__export(src_exports, {
|
|
38
|
+
DubheGraphqlClient: () => DubheGraphqlClient,
|
|
39
|
+
QueryBuilders: () => QueryBuilders,
|
|
40
|
+
createDubheGraphqlClient: () => createDubheGraphqlClient
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(src_exports);
|
|
43
|
+
|
|
44
|
+
// src/client.ts
|
|
45
|
+
var import_client2 = require("@apollo/client");
|
|
46
|
+
var import_retry = require("@apollo/client/link/retry");
|
|
47
|
+
var import_subscriptions = require("@apollo/client/link/subscriptions");
|
|
48
|
+
var import_utilities = require("@apollo/client/utilities");
|
|
49
|
+
|
|
50
|
+
// ../../node_modules/.pnpm/graphql-ws@6.0.5_graphql@15.10.1_ws@8.18.2/node_modules/graphql-ws/dist/common-CGW11Fyb.js
|
|
51
|
+
function extendedTypeof(val) {
|
|
52
|
+
if (val === null) {
|
|
53
|
+
return "null";
|
|
54
|
+
}
|
|
55
|
+
if (Array.isArray(val)) {
|
|
56
|
+
return "array";
|
|
57
|
+
}
|
|
58
|
+
return typeof val;
|
|
59
|
+
}
|
|
60
|
+
function isObject(val) {
|
|
61
|
+
return extendedTypeof(val) === "object";
|
|
62
|
+
}
|
|
63
|
+
function areGraphQLFormattedErrors(obj) {
|
|
64
|
+
return Array.isArray(obj) && // must be at least one error
|
|
65
|
+
obj.length > 0 && // error has at least a message
|
|
66
|
+
obj.every((ob) => "message" in ob);
|
|
67
|
+
}
|
|
68
|
+
function limitCloseReason(reason, whenTooLong) {
|
|
69
|
+
return reason.length < 124 ? reason : whenTooLong;
|
|
70
|
+
}
|
|
71
|
+
var GRAPHQL_TRANSPORT_WS_PROTOCOL = "graphql-transport-ws";
|
|
72
|
+
var CloseCode = /* @__PURE__ */ ((CloseCode2) => {
|
|
73
|
+
CloseCode2[CloseCode2["InternalServerError"] = 4500] = "InternalServerError";
|
|
74
|
+
CloseCode2[CloseCode2["InternalClientError"] = 4005] = "InternalClientError";
|
|
75
|
+
CloseCode2[CloseCode2["BadRequest"] = 4400] = "BadRequest";
|
|
76
|
+
CloseCode2[CloseCode2["BadResponse"] = 4004] = "BadResponse";
|
|
77
|
+
CloseCode2[CloseCode2["Unauthorized"] = 4401] = "Unauthorized";
|
|
78
|
+
CloseCode2[CloseCode2["Forbidden"] = 4403] = "Forbidden";
|
|
79
|
+
CloseCode2[CloseCode2["SubprotocolNotAcceptable"] = 4406] = "SubprotocolNotAcceptable";
|
|
80
|
+
CloseCode2[CloseCode2["ConnectionInitialisationTimeout"] = 4408] = "ConnectionInitialisationTimeout";
|
|
81
|
+
CloseCode2[CloseCode2["ConnectionAcknowledgementTimeout"] = 4504] = "ConnectionAcknowledgementTimeout";
|
|
82
|
+
CloseCode2[CloseCode2["SubscriberAlreadyExists"] = 4409] = "SubscriberAlreadyExists";
|
|
83
|
+
CloseCode2[CloseCode2["TooManyInitialisationRequests"] = 4429] = "TooManyInitialisationRequests";
|
|
84
|
+
return CloseCode2;
|
|
85
|
+
})(CloseCode || {});
|
|
86
|
+
var MessageType = /* @__PURE__ */ ((MessageType2) => {
|
|
87
|
+
MessageType2["ConnectionInit"] = "connection_init";
|
|
88
|
+
MessageType2["ConnectionAck"] = "connection_ack";
|
|
89
|
+
MessageType2["Ping"] = "ping";
|
|
90
|
+
MessageType2["Pong"] = "pong";
|
|
91
|
+
MessageType2["Subscribe"] = "subscribe";
|
|
92
|
+
MessageType2["Next"] = "next";
|
|
93
|
+
MessageType2["Error"] = "error";
|
|
94
|
+
MessageType2["Complete"] = "complete";
|
|
95
|
+
return MessageType2;
|
|
96
|
+
})(MessageType || {});
|
|
97
|
+
function validateMessage(val) {
|
|
98
|
+
if (!isObject(val)) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Message is expected to be an object, but got ${extendedTypeof(val)}`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
if (!val.type) {
|
|
104
|
+
throw new Error(`Message is missing the 'type' property`);
|
|
105
|
+
}
|
|
106
|
+
if (typeof val.type !== "string") {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`Message is expects the 'type' property to be a string, but got ${extendedTypeof(
|
|
109
|
+
val.type
|
|
110
|
+
)}`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
switch (val.type) {
|
|
114
|
+
case "connection_init":
|
|
115
|
+
case "connection_ack":
|
|
116
|
+
case "ping":
|
|
117
|
+
case "pong": {
|
|
118
|
+
if (val.payload != null && !isObject(val.payload)) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`"${val.type}" message expects the 'payload' property to be an object or nullish or missing, but got "${val.payload}"`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case "subscribe": {
|
|
126
|
+
if (typeof val.id !== "string") {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`"${val.type}" message expects the 'id' property to be a string, but got ${extendedTypeof(
|
|
129
|
+
val.id
|
|
130
|
+
)}`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
if (!val.id) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`"${val.type}" message requires a non-empty 'id' property`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
if (!isObject(val.payload)) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
`"${val.type}" message expects the 'payload' property to be an object, but got ${extendedTypeof(
|
|
141
|
+
val.payload
|
|
142
|
+
)}`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
if (typeof val.payload.query !== "string") {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`"${val.type}" message payload expects the 'query' property to be a string, but got ${extendedTypeof(
|
|
148
|
+
val.payload.query
|
|
149
|
+
)}`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
if (val.payload.variables != null && !isObject(val.payload.variables)) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
`"${val.type}" message payload expects the 'variables' property to be a an object or nullish or missing, but got ${extendedTypeof(
|
|
155
|
+
val.payload.variables
|
|
156
|
+
)}`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
if (val.payload.operationName != null && extendedTypeof(val.payload.operationName) !== "string") {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`"${val.type}" message payload expects the 'operationName' property to be a string or nullish or missing, but got ${extendedTypeof(
|
|
162
|
+
val.payload.operationName
|
|
163
|
+
)}`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
if (val.payload.extensions != null && !isObject(val.payload.extensions)) {
|
|
167
|
+
throw new Error(
|
|
168
|
+
`"${val.type}" message payload expects the 'extensions' property to be a an object or nullish or missing, but got ${extendedTypeof(
|
|
169
|
+
val.payload.extensions
|
|
170
|
+
)}`
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
case "next": {
|
|
176
|
+
if (typeof val.id !== "string") {
|
|
177
|
+
throw new Error(
|
|
178
|
+
`"${val.type}" message expects the 'id' property to be a string, but got ${extendedTypeof(
|
|
179
|
+
val.id
|
|
180
|
+
)}`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
if (!val.id) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
`"${val.type}" message requires a non-empty 'id' property`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
if (!isObject(val.payload)) {
|
|
189
|
+
throw new Error(
|
|
190
|
+
`"${val.type}" message expects the 'payload' property to be an object, but got ${extendedTypeof(
|
|
191
|
+
val.payload
|
|
192
|
+
)}`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
case "error": {
|
|
198
|
+
if (typeof val.id !== "string") {
|
|
199
|
+
throw new Error(
|
|
200
|
+
`"${val.type}" message expects the 'id' property to be a string, but got ${extendedTypeof(
|
|
201
|
+
val.id
|
|
202
|
+
)}`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
if (!val.id) {
|
|
206
|
+
throw new Error(
|
|
207
|
+
`"${val.type}" message requires a non-empty 'id' property`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
if (!areGraphQLFormattedErrors(val.payload)) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
`"${val.type}" message expects the 'payload' property to be an array of GraphQL errors, but got ${JSON.stringify(
|
|
213
|
+
val.payload
|
|
214
|
+
)}`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
case "complete": {
|
|
220
|
+
if (typeof val.id !== "string") {
|
|
221
|
+
throw new Error(
|
|
222
|
+
`"${val.type}" message expects the 'id' property to be a string, but got ${extendedTypeof(
|
|
223
|
+
val.id
|
|
224
|
+
)}`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
if (!val.id) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`"${val.type}" message requires a non-empty 'id' property`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
default:
|
|
235
|
+
throw new Error(`Invalid message 'type' property "${val.type}"`);
|
|
236
|
+
}
|
|
237
|
+
return val;
|
|
238
|
+
}
|
|
239
|
+
function parseMessage(data, reviver) {
|
|
240
|
+
return validateMessage(
|
|
241
|
+
typeof data === "string" ? JSON.parse(data, reviver) : data
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
function stringifyMessage(msg, replacer) {
|
|
245
|
+
validateMessage(msg);
|
|
246
|
+
return JSON.stringify(msg, replacer);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ../../node_modules/.pnpm/graphql-ws@6.0.5_graphql@15.10.1_ws@8.18.2/node_modules/graphql-ws/dist/client.js
|
|
250
|
+
function createClient(options) {
|
|
251
|
+
const {
|
|
252
|
+
url,
|
|
253
|
+
connectionParams,
|
|
254
|
+
lazy = true,
|
|
255
|
+
onNonLazyError = console.error,
|
|
256
|
+
lazyCloseTimeout: lazyCloseTimeoutMs = 0,
|
|
257
|
+
keepAlive = 0,
|
|
258
|
+
disablePong,
|
|
259
|
+
connectionAckWaitTimeout = 0,
|
|
260
|
+
retryAttempts = 5,
|
|
261
|
+
retryWait = async function randomisedExponentialBackoff(retries2) {
|
|
262
|
+
const retryDelaySeconds = Math.pow(2, retries2);
|
|
263
|
+
await new Promise(
|
|
264
|
+
(resolve) => setTimeout(
|
|
265
|
+
resolve,
|
|
266
|
+
retryDelaySeconds * 1e3 + // add random timeout from 300ms to 3s
|
|
267
|
+
Math.floor(Math.random() * (3e3 - 300) + 300)
|
|
268
|
+
)
|
|
269
|
+
);
|
|
270
|
+
},
|
|
271
|
+
shouldRetry = isLikeCloseEvent,
|
|
272
|
+
on,
|
|
273
|
+
webSocketImpl,
|
|
274
|
+
/**
|
|
275
|
+
* Generates a v4 UUID to be used as the ID using `Math`
|
|
276
|
+
* as the random number generator. Supply your own generator
|
|
277
|
+
* in case you need more uniqueness.
|
|
278
|
+
*
|
|
279
|
+
* Reference: https://gist.github.com/jed/982883
|
|
280
|
+
*/
|
|
281
|
+
generateID = function generateUUID() {
|
|
282
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
283
|
+
const r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
|
|
284
|
+
return v.toString(16);
|
|
285
|
+
});
|
|
286
|
+
},
|
|
287
|
+
jsonMessageReplacer: replacer,
|
|
288
|
+
jsonMessageReviver: reviver
|
|
289
|
+
} = options;
|
|
290
|
+
let ws;
|
|
291
|
+
if (webSocketImpl) {
|
|
292
|
+
if (!isWebSocket(webSocketImpl)) {
|
|
293
|
+
throw new Error("Invalid WebSocket implementation provided");
|
|
294
|
+
}
|
|
295
|
+
ws = webSocketImpl;
|
|
296
|
+
} else if (typeof WebSocket !== "undefined") {
|
|
297
|
+
ws = WebSocket;
|
|
298
|
+
} else if (typeof global !== "undefined") {
|
|
299
|
+
ws = global.WebSocket || // @ts-expect-error: Support more browsers
|
|
300
|
+
global.MozWebSocket;
|
|
301
|
+
} else if (typeof window !== "undefined") {
|
|
302
|
+
ws = window.WebSocket || // @ts-expect-error: Support more browsers
|
|
303
|
+
window.MozWebSocket;
|
|
304
|
+
}
|
|
305
|
+
if (!ws)
|
|
306
|
+
throw new Error(
|
|
307
|
+
"WebSocket implementation missing; on Node you can `import WebSocket from 'ws';` and pass `webSocketImpl: WebSocket` to `createClient`"
|
|
308
|
+
);
|
|
309
|
+
const WebSocketImpl = ws;
|
|
310
|
+
const emitter = (() => {
|
|
311
|
+
const message = /* @__PURE__ */ (() => {
|
|
312
|
+
const listeners2 = {};
|
|
313
|
+
return {
|
|
314
|
+
on(id, listener) {
|
|
315
|
+
listeners2[id] = listener;
|
|
316
|
+
return () => {
|
|
317
|
+
delete listeners2[id];
|
|
318
|
+
};
|
|
319
|
+
},
|
|
320
|
+
emit(message2) {
|
|
321
|
+
if ("id" in message2)
|
|
322
|
+
listeners2[message2.id]?.(message2);
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
})();
|
|
326
|
+
const listeners = {
|
|
327
|
+
connecting: on?.connecting ? [on.connecting] : [],
|
|
328
|
+
opened: on?.opened ? [on.opened] : [],
|
|
329
|
+
connected: on?.connected ? [on.connected] : [],
|
|
330
|
+
ping: on?.ping ? [on.ping] : [],
|
|
331
|
+
pong: on?.pong ? [on.pong] : [],
|
|
332
|
+
message: on?.message ? [message.emit, on.message] : [message.emit],
|
|
333
|
+
closed: on?.closed ? [on.closed] : [],
|
|
334
|
+
error: on?.error ? [on.error] : []
|
|
335
|
+
};
|
|
336
|
+
return {
|
|
337
|
+
onMessage: message.on,
|
|
338
|
+
on(event, listener) {
|
|
339
|
+
const l = listeners[event];
|
|
340
|
+
l.push(listener);
|
|
341
|
+
return () => {
|
|
342
|
+
l.splice(l.indexOf(listener), 1);
|
|
343
|
+
};
|
|
344
|
+
},
|
|
345
|
+
emit(event, ...args) {
|
|
346
|
+
for (const listener of [...listeners[event]]) {
|
|
347
|
+
listener(...args);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
})();
|
|
352
|
+
function errorOrClosed(cb) {
|
|
353
|
+
const listening = [
|
|
354
|
+
// errors are fatal and more critical than close events, throw them first
|
|
355
|
+
emitter.on("error", (err) => {
|
|
356
|
+
listening.forEach((unlisten) => unlisten());
|
|
357
|
+
cb(err);
|
|
358
|
+
}),
|
|
359
|
+
// closes can be graceful and not fatal, throw them second (if error didnt throw)
|
|
360
|
+
emitter.on("closed", (event) => {
|
|
361
|
+
listening.forEach((unlisten) => unlisten());
|
|
362
|
+
cb(event);
|
|
363
|
+
})
|
|
364
|
+
];
|
|
365
|
+
}
|
|
366
|
+
let connecting, locks = 0, lazyCloseTimeout, retrying = false, retries = 0, disposed = false;
|
|
367
|
+
async function connect() {
|
|
368
|
+
clearTimeout(lazyCloseTimeout);
|
|
369
|
+
const [socket, throwOnClose] = await (connecting ?? (connecting = new Promise(
|
|
370
|
+
(connected, denied) => (async () => {
|
|
371
|
+
if (retrying) {
|
|
372
|
+
await retryWait(retries);
|
|
373
|
+
if (!locks) {
|
|
374
|
+
connecting = void 0;
|
|
375
|
+
return denied({ code: 1e3, reason: "All Subscriptions Gone" });
|
|
376
|
+
}
|
|
377
|
+
retries++;
|
|
378
|
+
}
|
|
379
|
+
emitter.emit("connecting", retrying);
|
|
380
|
+
const socket2 = new WebSocketImpl(
|
|
381
|
+
typeof url === "function" ? await url() : url,
|
|
382
|
+
GRAPHQL_TRANSPORT_WS_PROTOCOL
|
|
383
|
+
);
|
|
384
|
+
let connectionAckTimeout, queuedPing;
|
|
385
|
+
function enqueuePing() {
|
|
386
|
+
if (isFinite(keepAlive) && keepAlive > 0) {
|
|
387
|
+
clearTimeout(queuedPing);
|
|
388
|
+
queuedPing = setTimeout(() => {
|
|
389
|
+
if (socket2.readyState === WebSocketImpl.OPEN) {
|
|
390
|
+
socket2.send(stringifyMessage({ type: MessageType.Ping }));
|
|
391
|
+
emitter.emit("ping", false, void 0);
|
|
392
|
+
}
|
|
393
|
+
}, keepAlive);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
errorOrClosed((errOrEvent) => {
|
|
397
|
+
connecting = void 0;
|
|
398
|
+
clearTimeout(connectionAckTimeout);
|
|
399
|
+
clearTimeout(queuedPing);
|
|
400
|
+
denied(errOrEvent);
|
|
401
|
+
if (errOrEvent instanceof TerminatedCloseEvent) {
|
|
402
|
+
socket2.close(4499, "Terminated");
|
|
403
|
+
socket2.onerror = null;
|
|
404
|
+
socket2.onclose = null;
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
socket2.onerror = (err) => emitter.emit("error", err);
|
|
408
|
+
socket2.onclose = (event) => emitter.emit("closed", event);
|
|
409
|
+
socket2.onopen = async () => {
|
|
410
|
+
try {
|
|
411
|
+
emitter.emit("opened", socket2);
|
|
412
|
+
const payload = typeof connectionParams === "function" ? await connectionParams() : connectionParams;
|
|
413
|
+
if (socket2.readyState !== WebSocketImpl.OPEN)
|
|
414
|
+
return;
|
|
415
|
+
socket2.send(
|
|
416
|
+
stringifyMessage(
|
|
417
|
+
payload ? {
|
|
418
|
+
type: MessageType.ConnectionInit,
|
|
419
|
+
payload
|
|
420
|
+
} : {
|
|
421
|
+
type: MessageType.ConnectionInit
|
|
422
|
+
// payload is completely absent if not provided
|
|
423
|
+
},
|
|
424
|
+
replacer
|
|
425
|
+
)
|
|
426
|
+
);
|
|
427
|
+
if (isFinite(connectionAckWaitTimeout) && connectionAckWaitTimeout > 0) {
|
|
428
|
+
connectionAckTimeout = setTimeout(() => {
|
|
429
|
+
socket2.close(
|
|
430
|
+
CloseCode.ConnectionAcknowledgementTimeout,
|
|
431
|
+
"Connection acknowledgement timeout"
|
|
432
|
+
);
|
|
433
|
+
}, connectionAckWaitTimeout);
|
|
434
|
+
}
|
|
435
|
+
enqueuePing();
|
|
436
|
+
} catch (err) {
|
|
437
|
+
emitter.emit("error", err);
|
|
438
|
+
socket2.close(
|
|
439
|
+
CloseCode.InternalClientError,
|
|
440
|
+
limitCloseReason(
|
|
441
|
+
err instanceof Error ? err.message : String(err),
|
|
442
|
+
"Internal client error"
|
|
443
|
+
)
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
let acknowledged = false;
|
|
448
|
+
socket2.onmessage = ({ data }) => {
|
|
449
|
+
try {
|
|
450
|
+
const message = parseMessage(data, reviver);
|
|
451
|
+
emitter.emit("message", message);
|
|
452
|
+
if (message.type === "ping" || message.type === "pong") {
|
|
453
|
+
emitter.emit(message.type, true, message.payload);
|
|
454
|
+
if (message.type === "pong") {
|
|
455
|
+
enqueuePing();
|
|
456
|
+
} else if (!disablePong) {
|
|
457
|
+
socket2.send(
|
|
458
|
+
stringifyMessage(
|
|
459
|
+
message.payload ? {
|
|
460
|
+
type: MessageType.Pong,
|
|
461
|
+
payload: message.payload
|
|
462
|
+
} : {
|
|
463
|
+
type: MessageType.Pong
|
|
464
|
+
// payload is completely absent if not provided
|
|
465
|
+
}
|
|
466
|
+
)
|
|
467
|
+
);
|
|
468
|
+
emitter.emit("pong", false, message.payload);
|
|
469
|
+
}
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
if (acknowledged)
|
|
473
|
+
return;
|
|
474
|
+
if (message.type !== MessageType.ConnectionAck)
|
|
475
|
+
throw new Error(
|
|
476
|
+
`First message cannot be of type ${message.type}`
|
|
477
|
+
);
|
|
478
|
+
clearTimeout(connectionAckTimeout);
|
|
479
|
+
acknowledged = true;
|
|
480
|
+
emitter.emit("connected", socket2, message.payload, retrying);
|
|
481
|
+
retrying = false;
|
|
482
|
+
retries = 0;
|
|
483
|
+
connected([
|
|
484
|
+
socket2,
|
|
485
|
+
new Promise((_, reject) => errorOrClosed(reject))
|
|
486
|
+
]);
|
|
487
|
+
} catch (err) {
|
|
488
|
+
socket2.onmessage = null;
|
|
489
|
+
emitter.emit("error", err);
|
|
490
|
+
socket2.close(
|
|
491
|
+
CloseCode.BadResponse,
|
|
492
|
+
limitCloseReason(
|
|
493
|
+
err instanceof Error ? err.message : String(err),
|
|
494
|
+
"Bad response"
|
|
495
|
+
)
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
})()
|
|
500
|
+
)));
|
|
501
|
+
if (socket.readyState === WebSocketImpl.CLOSING)
|
|
502
|
+
await throwOnClose;
|
|
503
|
+
let release = () => {
|
|
504
|
+
};
|
|
505
|
+
const released = new Promise((resolve) => release = resolve);
|
|
506
|
+
return [
|
|
507
|
+
socket,
|
|
508
|
+
release,
|
|
509
|
+
Promise.race([
|
|
510
|
+
// wait for
|
|
511
|
+
released.then(() => {
|
|
512
|
+
if (!locks) {
|
|
513
|
+
const complete = () => socket.close(1e3, "Normal Closure");
|
|
514
|
+
if (isFinite(lazyCloseTimeoutMs) && lazyCloseTimeoutMs > 0) {
|
|
515
|
+
lazyCloseTimeout = setTimeout(() => {
|
|
516
|
+
if (socket.readyState === WebSocketImpl.OPEN)
|
|
517
|
+
complete();
|
|
518
|
+
}, lazyCloseTimeoutMs);
|
|
519
|
+
} else {
|
|
520
|
+
complete();
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}),
|
|
524
|
+
// or
|
|
525
|
+
throwOnClose
|
|
526
|
+
])
|
|
527
|
+
];
|
|
528
|
+
}
|
|
529
|
+
function shouldRetryConnectOrThrow(errOrCloseEvent) {
|
|
530
|
+
if (isLikeCloseEvent(errOrCloseEvent) && (isFatalInternalCloseCode(errOrCloseEvent.code) || [
|
|
531
|
+
CloseCode.InternalServerError,
|
|
532
|
+
CloseCode.InternalClientError,
|
|
533
|
+
CloseCode.BadRequest,
|
|
534
|
+
CloseCode.BadResponse,
|
|
535
|
+
CloseCode.Unauthorized,
|
|
536
|
+
// CloseCode.Forbidden, might grant access out after retry
|
|
537
|
+
CloseCode.SubprotocolNotAcceptable,
|
|
538
|
+
// CloseCode.ConnectionInitialisationTimeout, might not time out after retry
|
|
539
|
+
// CloseCode.ConnectionAcknowledgementTimeout, might not time out after retry
|
|
540
|
+
CloseCode.SubscriberAlreadyExists,
|
|
541
|
+
CloseCode.TooManyInitialisationRequests
|
|
542
|
+
// 4499, // Terminated, probably because the socket froze, we want to retry
|
|
543
|
+
].includes(errOrCloseEvent.code)))
|
|
544
|
+
throw errOrCloseEvent;
|
|
545
|
+
if (disposed)
|
|
546
|
+
return false;
|
|
547
|
+
if (isLikeCloseEvent(errOrCloseEvent) && errOrCloseEvent.code === 1e3)
|
|
548
|
+
return locks > 0;
|
|
549
|
+
if (!retryAttempts || retries >= retryAttempts)
|
|
550
|
+
throw errOrCloseEvent;
|
|
551
|
+
if (!shouldRetry(errOrCloseEvent))
|
|
552
|
+
throw errOrCloseEvent;
|
|
553
|
+
return retrying = true;
|
|
554
|
+
}
|
|
555
|
+
if (!lazy) {
|
|
556
|
+
(async () => {
|
|
557
|
+
locks++;
|
|
558
|
+
for (; ; ) {
|
|
559
|
+
try {
|
|
560
|
+
const [, , throwOnClose] = await connect();
|
|
561
|
+
await throwOnClose;
|
|
562
|
+
} catch (errOrCloseEvent) {
|
|
563
|
+
try {
|
|
564
|
+
if (!shouldRetryConnectOrThrow(errOrCloseEvent))
|
|
565
|
+
return;
|
|
566
|
+
} catch (errOrCloseEvent2) {
|
|
567
|
+
return onNonLazyError?.(errOrCloseEvent2);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
})();
|
|
572
|
+
}
|
|
573
|
+
function subscribe(payload, sink) {
|
|
574
|
+
const id = generateID(payload);
|
|
575
|
+
let done = false, errored = false, releaser = () => {
|
|
576
|
+
locks--;
|
|
577
|
+
done = true;
|
|
578
|
+
};
|
|
579
|
+
(async () => {
|
|
580
|
+
locks++;
|
|
581
|
+
for (; ; ) {
|
|
582
|
+
try {
|
|
583
|
+
const [socket, release, waitForReleaseOrThrowOnClose] = await connect();
|
|
584
|
+
if (done)
|
|
585
|
+
return release();
|
|
586
|
+
const unlisten = emitter.onMessage(id, (message) => {
|
|
587
|
+
switch (message.type) {
|
|
588
|
+
case MessageType.Next: {
|
|
589
|
+
sink.next(message.payload);
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
case MessageType.Error: {
|
|
593
|
+
errored = true, done = true;
|
|
594
|
+
sink.error(message.payload);
|
|
595
|
+
releaser();
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
case MessageType.Complete: {
|
|
599
|
+
done = true;
|
|
600
|
+
releaser();
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
socket.send(
|
|
606
|
+
stringifyMessage(
|
|
607
|
+
{
|
|
608
|
+
id,
|
|
609
|
+
type: MessageType.Subscribe,
|
|
610
|
+
payload
|
|
611
|
+
},
|
|
612
|
+
replacer
|
|
613
|
+
)
|
|
614
|
+
);
|
|
615
|
+
releaser = () => {
|
|
616
|
+
if (!done && socket.readyState === WebSocketImpl.OPEN)
|
|
617
|
+
socket.send(
|
|
618
|
+
stringifyMessage(
|
|
619
|
+
{
|
|
620
|
+
id,
|
|
621
|
+
type: MessageType.Complete
|
|
622
|
+
},
|
|
623
|
+
replacer
|
|
624
|
+
)
|
|
625
|
+
);
|
|
626
|
+
locks--;
|
|
627
|
+
done = true;
|
|
628
|
+
release();
|
|
629
|
+
};
|
|
630
|
+
await waitForReleaseOrThrowOnClose.finally(unlisten);
|
|
631
|
+
return;
|
|
632
|
+
} catch (errOrCloseEvent) {
|
|
633
|
+
if (!shouldRetryConnectOrThrow(errOrCloseEvent))
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
})().then(() => {
|
|
638
|
+
if (!errored)
|
|
639
|
+
sink.complete();
|
|
640
|
+
}).catch((err) => {
|
|
641
|
+
sink.error(err);
|
|
642
|
+
});
|
|
643
|
+
return () => {
|
|
644
|
+
if (!done)
|
|
645
|
+
releaser();
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
return {
|
|
649
|
+
on: emitter.on,
|
|
650
|
+
subscribe,
|
|
651
|
+
iterate(request) {
|
|
652
|
+
const pending = [];
|
|
653
|
+
const deferred = {
|
|
654
|
+
done: false,
|
|
655
|
+
error: null,
|
|
656
|
+
resolve: () => {
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
const dispose = subscribe(request, {
|
|
660
|
+
next(val) {
|
|
661
|
+
pending.push(val);
|
|
662
|
+
deferred.resolve();
|
|
663
|
+
},
|
|
664
|
+
error(err) {
|
|
665
|
+
deferred.done = true;
|
|
666
|
+
deferred.error = err;
|
|
667
|
+
deferred.resolve();
|
|
668
|
+
},
|
|
669
|
+
complete() {
|
|
670
|
+
deferred.done = true;
|
|
671
|
+
deferred.resolve();
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
const iterator = async function* iterator2() {
|
|
675
|
+
for (; ; ) {
|
|
676
|
+
if (!pending.length) {
|
|
677
|
+
await new Promise((resolve) => deferred.resolve = resolve);
|
|
678
|
+
}
|
|
679
|
+
while (pending.length) {
|
|
680
|
+
yield pending.shift();
|
|
681
|
+
}
|
|
682
|
+
if (deferred.error) {
|
|
683
|
+
throw deferred.error;
|
|
684
|
+
}
|
|
685
|
+
if (deferred.done) {
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}();
|
|
690
|
+
iterator.throw = async (err) => {
|
|
691
|
+
if (!deferred.done) {
|
|
692
|
+
deferred.done = true;
|
|
693
|
+
deferred.error = err;
|
|
694
|
+
deferred.resolve();
|
|
695
|
+
}
|
|
696
|
+
return { done: true, value: void 0 };
|
|
697
|
+
};
|
|
698
|
+
iterator.return = async () => {
|
|
699
|
+
dispose();
|
|
700
|
+
return { done: true, value: void 0 };
|
|
701
|
+
};
|
|
702
|
+
return iterator;
|
|
703
|
+
},
|
|
704
|
+
async dispose() {
|
|
705
|
+
disposed = true;
|
|
706
|
+
if (connecting) {
|
|
707
|
+
const [socket] = await connecting;
|
|
708
|
+
socket.close(1e3, "Normal Closure");
|
|
709
|
+
}
|
|
710
|
+
},
|
|
711
|
+
terminate() {
|
|
712
|
+
if (connecting) {
|
|
713
|
+
emitter.emit("closed", new TerminatedCloseEvent());
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
var TerminatedCloseEvent = class extends Error {
|
|
719
|
+
constructor() {
|
|
720
|
+
super(...arguments);
|
|
721
|
+
__publicField(this, "name", "TerminatedCloseEvent");
|
|
722
|
+
__publicField(this, "message", "4499: Terminated");
|
|
723
|
+
__publicField(this, "code", 4499);
|
|
724
|
+
__publicField(this, "reason", "Terminated");
|
|
725
|
+
__publicField(this, "wasClean", false);
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
function isLikeCloseEvent(val) {
|
|
729
|
+
return isObject(val) && "code" in val && "reason" in val;
|
|
730
|
+
}
|
|
731
|
+
function isFatalInternalCloseCode(code) {
|
|
732
|
+
if ([
|
|
733
|
+
1e3,
|
|
734
|
+
// Normal Closure is not an erroneous close code
|
|
735
|
+
1001,
|
|
736
|
+
// Going Away
|
|
737
|
+
1006,
|
|
738
|
+
// Abnormal Closure
|
|
739
|
+
1005,
|
|
740
|
+
// No Status Received
|
|
741
|
+
1012,
|
|
742
|
+
// Service Restart
|
|
743
|
+
1013,
|
|
744
|
+
// Try Again Later
|
|
745
|
+
1014
|
|
746
|
+
// Bad Gateway
|
|
747
|
+
].includes(code))
|
|
748
|
+
return false;
|
|
749
|
+
return code >= 1e3 && code <= 1999;
|
|
750
|
+
}
|
|
751
|
+
function isWebSocket(val) {
|
|
752
|
+
return typeof val === "function" && "constructor" in val && "CLOSED" in val && "CLOSING" in val && "CONNECTING" in val && "OPEN" in val;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// ../../node_modules/.pnpm/graphql-ws@6.0.5_graphql@15.10.1_ws@8.18.2/node_modules/graphql-ws/dist/index.js
|
|
756
|
+
var import_graphql = require("graphql");
|
|
757
|
+
|
|
758
|
+
// src/client.ts
|
|
759
|
+
var import_pluralize = __toESM(require("pluralize"));
|
|
760
|
+
function mapCachePolicyToFetchPolicy(cachePolicy) {
|
|
761
|
+
switch (cachePolicy) {
|
|
762
|
+
case "cache-first":
|
|
763
|
+
return "cache-first";
|
|
764
|
+
case "network-only":
|
|
765
|
+
return "network-only";
|
|
766
|
+
case "cache-only":
|
|
767
|
+
return "cache-only";
|
|
768
|
+
case "no-cache":
|
|
769
|
+
return "no-cache";
|
|
770
|
+
case "standby":
|
|
771
|
+
return "standby";
|
|
772
|
+
default:
|
|
773
|
+
return "cache-first";
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
var DubheGraphqlClient = class {
|
|
777
|
+
constructor(config) {
|
|
778
|
+
this.parsedTables = /* @__PURE__ */ new Map();
|
|
779
|
+
this.dubheMetadata = config.dubheMetadata;
|
|
780
|
+
if (this.dubheMetadata) {
|
|
781
|
+
this.parseTableInfoFromConfig();
|
|
782
|
+
}
|
|
783
|
+
const httpLink = (0, import_client2.createHttpLink)({
|
|
784
|
+
uri: config.endpoint,
|
|
785
|
+
headers: config.headers,
|
|
786
|
+
fetch: (input, init) => fetch(input, { ...config.fetchOptions, ...init })
|
|
787
|
+
});
|
|
788
|
+
const retryLink = new import_retry.RetryLink({
|
|
789
|
+
delay: {
|
|
790
|
+
// Initial retry delay time (milliseconds)
|
|
791
|
+
initial: config.retryOptions?.delay?.initial || 300,
|
|
792
|
+
// Maximum retry delay time (milliseconds)
|
|
793
|
+
max: config.retryOptions?.delay?.max || 5e3,
|
|
794
|
+
// Whether to add random jitter to avoid thundering herd, enabled by default
|
|
795
|
+
jitter: config.retryOptions?.delay?.jitter !== false
|
|
796
|
+
},
|
|
797
|
+
attempts: {
|
|
798
|
+
// Maximum number of attempts (including initial request)
|
|
799
|
+
max: config.retryOptions?.attempts?.max || 5,
|
|
800
|
+
// Custom retry condition function
|
|
801
|
+
retryIf: config.retryOptions?.attempts?.retryIf || ((error, _operation) => {
|
|
802
|
+
return Boolean(
|
|
803
|
+
error && (error.networkError || error.graphQLErrors && error.graphQLErrors.length === 0)
|
|
804
|
+
);
|
|
805
|
+
})
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
const httpWithRetryLink = (0, import_client2.from)([retryLink, httpLink]);
|
|
809
|
+
let link = httpWithRetryLink;
|
|
810
|
+
if (config.subscriptionEndpoint) {
|
|
811
|
+
let webSocketImpl;
|
|
812
|
+
try {
|
|
813
|
+
if (typeof window === "undefined" && typeof global !== "undefined") {
|
|
814
|
+
const wsModule = require("ws");
|
|
815
|
+
webSocketImpl = wsModule.default || wsModule;
|
|
816
|
+
if (typeof global.WebSocket === "undefined") {
|
|
817
|
+
global.WebSocket = webSocketImpl;
|
|
818
|
+
}
|
|
819
|
+
} else {
|
|
820
|
+
webSocketImpl = WebSocket;
|
|
821
|
+
}
|
|
822
|
+
} catch (error) {
|
|
823
|
+
}
|
|
824
|
+
const clientOptions = {
|
|
825
|
+
url: config.subscriptionEndpoint,
|
|
826
|
+
connectionParams: {
|
|
827
|
+
headers: config.headers
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
if (webSocketImpl && typeof window === "undefined") {
|
|
831
|
+
clientOptions.webSocketImpl = webSocketImpl;
|
|
832
|
+
}
|
|
833
|
+
this.subscriptionClient = createClient(clientOptions);
|
|
834
|
+
const wsLink = new import_subscriptions.GraphQLWsLink(this.subscriptionClient);
|
|
835
|
+
link = (0, import_client2.split)(
|
|
836
|
+
({ query }) => {
|
|
837
|
+
const definition = (0, import_utilities.getMainDefinition)(query);
|
|
838
|
+
return definition.kind === "OperationDefinition" && definition.operation === "subscription";
|
|
839
|
+
},
|
|
840
|
+
wsLink,
|
|
841
|
+
httpWithRetryLink
|
|
842
|
+
);
|
|
843
|
+
}
|
|
844
|
+
this.apolloClient = new import_client2.ApolloClient({
|
|
845
|
+
link,
|
|
846
|
+
cache: config.cacheConfig?.paginatedTables && config.cacheConfig.paginatedTables.length > 0 ? new import_client2.InMemoryCache({
|
|
847
|
+
typePolicies: {
|
|
848
|
+
// Configure cache strategy for Connection type
|
|
849
|
+
Query: {
|
|
850
|
+
fields: this.buildCacheFields(config.cacheConfig)
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}) : new import_client2.InMemoryCache(),
|
|
854
|
+
// Use simple cache by default
|
|
855
|
+
defaultOptions: {
|
|
856
|
+
watchQuery: {
|
|
857
|
+
errorPolicy: "all",
|
|
858
|
+
notifyOnNetworkStatusChange: true
|
|
859
|
+
},
|
|
860
|
+
query: {
|
|
861
|
+
errorPolicy: "all"
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Execute GraphQL query
|
|
868
|
+
*/
|
|
869
|
+
async query(query, variables, options) {
|
|
870
|
+
try {
|
|
871
|
+
const result = await this.apolloClient.query({
|
|
872
|
+
query,
|
|
873
|
+
variables,
|
|
874
|
+
fetchPolicy: options?.cachePolicy ? mapCachePolicyToFetchPolicy(options.cachePolicy) : "no-cache",
|
|
875
|
+
// : 'cache-first',
|
|
876
|
+
notifyOnNetworkStatusChange: options?.notifyOnNetworkStatusChange,
|
|
877
|
+
pollInterval: options?.pollInterval
|
|
878
|
+
});
|
|
879
|
+
return {
|
|
880
|
+
data: result.data,
|
|
881
|
+
loading: result.loading,
|
|
882
|
+
error: result.error,
|
|
883
|
+
networkStatus: result.networkStatus,
|
|
884
|
+
refetch: () => this.query(query, variables, options)
|
|
885
|
+
};
|
|
886
|
+
} catch (error) {
|
|
887
|
+
return {
|
|
888
|
+
data: void 0,
|
|
889
|
+
loading: false,
|
|
890
|
+
error,
|
|
891
|
+
networkStatus: 8,
|
|
892
|
+
// NetworkStatus.error
|
|
893
|
+
refetch: () => this.query(query, variables, options)
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Execute GraphQL subscription
|
|
899
|
+
*/
|
|
900
|
+
subscribe(subscription, variables, options) {
|
|
901
|
+
return new import_client2.Observable((observer) => {
|
|
902
|
+
const sub = this.apolloClient.subscribe({
|
|
903
|
+
query: subscription,
|
|
904
|
+
variables
|
|
905
|
+
}).subscribe({
|
|
906
|
+
next: (result) => {
|
|
907
|
+
const subscriptionResult = {
|
|
908
|
+
data: result.data,
|
|
909
|
+
loading: false,
|
|
910
|
+
error: result.errors?.[0]
|
|
911
|
+
};
|
|
912
|
+
observer.next(subscriptionResult);
|
|
913
|
+
options?.onData?.(result.data);
|
|
914
|
+
},
|
|
915
|
+
error: (error) => {
|
|
916
|
+
const subscriptionResult = {
|
|
917
|
+
data: void 0,
|
|
918
|
+
loading: false,
|
|
919
|
+
error
|
|
920
|
+
};
|
|
921
|
+
observer.next(subscriptionResult);
|
|
922
|
+
options?.onError?.(error);
|
|
923
|
+
},
|
|
924
|
+
complete: () => {
|
|
925
|
+
observer.complete();
|
|
926
|
+
options?.onComplete?.();
|
|
927
|
+
}
|
|
928
|
+
});
|
|
929
|
+
return () => sub.unsubscribe();
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Query all table data - Adapted to API without store prefix
|
|
934
|
+
*
|
|
935
|
+
* OrderBy field name support:
|
|
936
|
+
* - camelCase: { field: 'updatedAt', direction: 'DESC' } → UPDATED_AT_DESC
|
|
937
|
+
* - snake_case: { field: 'updated_at', direction: 'DESC' } → UPDATED_AT_DESC
|
|
938
|
+
*
|
|
939
|
+
* Usage examples:
|
|
940
|
+
* ```ts
|
|
941
|
+
* // Using camelCase field names
|
|
942
|
+
* const result = await client.getAllTables('account', {
|
|
943
|
+
* orderBy: [{ field: 'updatedAt', direction: 'DESC' }]
|
|
944
|
+
* });
|
|
945
|
+
*
|
|
946
|
+
* // Using snake_case field names
|
|
947
|
+
* const result = await client.getAllTables('account', {
|
|
948
|
+
* orderBy: [{ field: 'updated_at', direction: 'DESC' }]
|
|
949
|
+
* });
|
|
950
|
+
*
|
|
951
|
+
* // Mixed usage
|
|
952
|
+
* const result = await client.getAllTables('account', {
|
|
953
|
+
* orderBy: [
|
|
954
|
+
* { field: 'updatedAt', direction: 'DESC' },
|
|
955
|
+
* { field: 'created_at', direction: 'ASC' }
|
|
956
|
+
* ]
|
|
957
|
+
* });
|
|
958
|
+
* ```
|
|
959
|
+
*/
|
|
960
|
+
async getAllTables(tableName, params) {
|
|
961
|
+
const pluralTableName = this.getPluralTableName(tableName);
|
|
962
|
+
const orderByEnums = convertOrderByToEnum(params?.orderBy);
|
|
963
|
+
const query = import_client2.gql`
|
|
964
|
+
query GetAllTables(
|
|
965
|
+
$first: Int
|
|
966
|
+
$last: Int
|
|
967
|
+
$after: Cursor
|
|
968
|
+
$before: Cursor
|
|
969
|
+
$filter: ${this.getFilterTypeName(tableName)}
|
|
970
|
+
$orderBy: [${this.getOrderByTypeName(tableName)}!]
|
|
971
|
+
) {
|
|
972
|
+
${pluralTableName}(
|
|
973
|
+
first: $first
|
|
974
|
+
last: $last
|
|
975
|
+
after: $after
|
|
976
|
+
before: $before
|
|
977
|
+
filter: $filter
|
|
978
|
+
orderBy: $orderBy
|
|
979
|
+
) {
|
|
980
|
+
totalCount
|
|
981
|
+
pageInfo {
|
|
982
|
+
hasNextPage
|
|
983
|
+
hasPreviousPage
|
|
984
|
+
startCursor
|
|
985
|
+
endCursor
|
|
986
|
+
}
|
|
987
|
+
edges {
|
|
988
|
+
cursor
|
|
989
|
+
node {
|
|
990
|
+
${this.convertTableFields(tableName, params?.fields)}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
`;
|
|
996
|
+
const queryParams = {
|
|
997
|
+
first: params?.first,
|
|
998
|
+
last: params?.last,
|
|
999
|
+
after: params?.after,
|
|
1000
|
+
before: params?.before,
|
|
1001
|
+
filter: params?.filter,
|
|
1002
|
+
orderBy: orderByEnums
|
|
1003
|
+
};
|
|
1004
|
+
const result = await this.query(query, queryParams);
|
|
1005
|
+
if (result.error) {
|
|
1006
|
+
throw result.error;
|
|
1007
|
+
}
|
|
1008
|
+
return result.data?.[pluralTableName] || {
|
|
1009
|
+
edges: [],
|
|
1010
|
+
pageInfo: { hasNextPage: false, hasPreviousPage: false }
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
/**
|
|
1014
|
+
* Get single table record by condition - Adapted to API without store prefix
|
|
1015
|
+
*/
|
|
1016
|
+
async getTableByCondition(tableName, condition, fields) {
|
|
1017
|
+
const conditionKeys = Object.keys(condition);
|
|
1018
|
+
const singularTableName = this.getSingularTableName(tableName);
|
|
1019
|
+
const query = import_client2.gql`
|
|
1020
|
+
query GetTableByCondition(${conditionKeys.map((key, index) => `$${key}: String!`).join(", ")}) {
|
|
1021
|
+
${singularTableName}(${conditionKeys.map((key) => `${key}: $${key}`).join(", ")}) {
|
|
1022
|
+
${this.convertTableFields(tableName, fields)}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
`;
|
|
1026
|
+
const result = await this.query(query, condition);
|
|
1027
|
+
if (result.error) {
|
|
1028
|
+
throw result.error;
|
|
1029
|
+
}
|
|
1030
|
+
return result.data?.[singularTableName] || null;
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Subscribe to table data changes - Using PostGraphile's listen subscription feature
|
|
1034
|
+
*/
|
|
1035
|
+
subscribeToTableChanges(tableName, options) {
|
|
1036
|
+
const topic = options?.topicPrefix ? `${options.topicPrefix}${tableName}` : `store_${this.getSingularTableName(tableName)}`;
|
|
1037
|
+
const pluralTableName = this.getPluralTableName(tableName);
|
|
1038
|
+
const fields = this.convertTableFields(tableName, options?.fields);
|
|
1039
|
+
const subscription = import_client2.gql`
|
|
1040
|
+
subscription ListenToTableChanges($topic: String!, $initialEvent: Boolean) {
|
|
1041
|
+
listen(topic: $topic, initialEvent: $initialEvent) {
|
|
1042
|
+
query {
|
|
1043
|
+
${pluralTableName}(first: ${options?.first || 10}, orderBy: UPDATED_AT_DESC) {
|
|
1044
|
+
totalCount
|
|
1045
|
+
nodes {
|
|
1046
|
+
${fields}
|
|
1047
|
+
}
|
|
1048
|
+
pageInfo {
|
|
1049
|
+
hasNextPage
|
|
1050
|
+
endCursor
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
`;
|
|
1057
|
+
return this.subscribe(
|
|
1058
|
+
subscription,
|
|
1059
|
+
{
|
|
1060
|
+
topic,
|
|
1061
|
+
initialEvent: options?.initialEvent || false
|
|
1062
|
+
},
|
|
1063
|
+
options
|
|
1064
|
+
);
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Advanced listen subscription - Support custom queries
|
|
1068
|
+
*/
|
|
1069
|
+
subscribeWithListen(topic, query, options) {
|
|
1070
|
+
const subscription = import_client2.gql`
|
|
1071
|
+
subscription CustomListenSubscription($topic: String!, $initialEvent: Boolean) {
|
|
1072
|
+
listen(topic: $topic, initialEvent: $initialEvent) {
|
|
1073
|
+
query {
|
|
1074
|
+
${query}
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
`;
|
|
1079
|
+
return this.subscribe(
|
|
1080
|
+
subscription,
|
|
1081
|
+
{
|
|
1082
|
+
topic,
|
|
1083
|
+
initialEvent: options?.initialEvent || false,
|
|
1084
|
+
...options?.variables
|
|
1085
|
+
},
|
|
1086
|
+
options
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Subscribe to data changes with specific conditions
|
|
1091
|
+
*/
|
|
1092
|
+
subscribeToFilteredTableChanges(tableName, filter, options) {
|
|
1093
|
+
const topic = options?.topicPrefix ? `${options.topicPrefix}${tableName}` : `store_${this.getSingularTableName(tableName)}`;
|
|
1094
|
+
const pluralTableName = this.getPluralTableName(tableName);
|
|
1095
|
+
const fields = this.convertTableFields(tableName, options?.fields);
|
|
1096
|
+
const orderByEnum = convertOrderByToEnum(options?.orderBy);
|
|
1097
|
+
const first = options?.first || 10;
|
|
1098
|
+
const subscription = import_client2.gql`
|
|
1099
|
+
subscription FilteredListenSubscription(
|
|
1100
|
+
$topic: String!,
|
|
1101
|
+
$initialEvent: Boolean,
|
|
1102
|
+
$filter: ${this.getFilterTypeName(tableName)},
|
|
1103
|
+
$orderBy: [${this.getOrderByTypeName(tableName)}!],
|
|
1104
|
+
$first: Int
|
|
1105
|
+
) {
|
|
1106
|
+
listen(topic: $topic, initialEvent: $initialEvent) {
|
|
1107
|
+
query {
|
|
1108
|
+
${pluralTableName}(
|
|
1109
|
+
first: $first,
|
|
1110
|
+
filter: $filter,
|
|
1111
|
+
orderBy: $orderBy
|
|
1112
|
+
) {
|
|
1113
|
+
totalCount
|
|
1114
|
+
nodes {
|
|
1115
|
+
${fields}
|
|
1116
|
+
}
|
|
1117
|
+
pageInfo {
|
|
1118
|
+
hasNextPage
|
|
1119
|
+
endCursor
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
`;
|
|
1126
|
+
return this.subscribe(
|
|
1127
|
+
subscription,
|
|
1128
|
+
{
|
|
1129
|
+
topic,
|
|
1130
|
+
initialEvent: options?.initialEvent || false,
|
|
1131
|
+
filter,
|
|
1132
|
+
orderBy: orderByEnum,
|
|
1133
|
+
first
|
|
1134
|
+
},
|
|
1135
|
+
options
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
1138
|
+
/**
|
|
1139
|
+
* Subscribe to multiple table data changes - Support batch subscription of table name list
|
|
1140
|
+
*/
|
|
1141
|
+
subscribeToMultipleTables(tableConfigs, globalOptions) {
|
|
1142
|
+
return new import_client2.Observable((observer) => {
|
|
1143
|
+
const subscriptions = [];
|
|
1144
|
+
const latestData = {};
|
|
1145
|
+
tableConfigs.forEach(({ tableName, options }) => {
|
|
1146
|
+
const subscription = this.subscribeToFilteredTableChanges(
|
|
1147
|
+
tableName,
|
|
1148
|
+
options?.filter,
|
|
1149
|
+
{
|
|
1150
|
+
...options,
|
|
1151
|
+
onData: (data) => {
|
|
1152
|
+
latestData[tableName] = data;
|
|
1153
|
+
if (options?.onData) {
|
|
1154
|
+
options.onData(data);
|
|
1155
|
+
}
|
|
1156
|
+
if (globalOptions?.onData) {
|
|
1157
|
+
globalOptions.onData(latestData);
|
|
1158
|
+
}
|
|
1159
|
+
observer.next({ ...latestData });
|
|
1160
|
+
},
|
|
1161
|
+
onError: (error) => {
|
|
1162
|
+
if (options?.onError) {
|
|
1163
|
+
options.onError(error);
|
|
1164
|
+
}
|
|
1165
|
+
if (globalOptions?.onError) {
|
|
1166
|
+
globalOptions.onError(error);
|
|
1167
|
+
}
|
|
1168
|
+
observer.error(error);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
);
|
|
1172
|
+
subscriptions.push({ tableName, subscription });
|
|
1173
|
+
});
|
|
1174
|
+
const activeSubscriptions = subscriptions.map(
|
|
1175
|
+
({ subscription }) => subscription.subscribe()
|
|
1176
|
+
);
|
|
1177
|
+
return () => {
|
|
1178
|
+
activeSubscriptions.forEach((sub) => sub.unsubscribe());
|
|
1179
|
+
if (globalOptions?.onComplete) {
|
|
1180
|
+
globalOptions.onComplete();
|
|
1181
|
+
}
|
|
1182
|
+
};
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Simplified multi-table subscription - Support table name array and unified configuration
|
|
1187
|
+
*/
|
|
1188
|
+
subscribeToTableList(tableNames, options) {
|
|
1189
|
+
const tableConfigs = tableNames.map(
|
|
1190
|
+
(tableName) => ({
|
|
1191
|
+
tableName,
|
|
1192
|
+
options: {
|
|
1193
|
+
...options,
|
|
1194
|
+
// Use same configuration for each table
|
|
1195
|
+
fields: options?.fields,
|
|
1196
|
+
filter: options?.filter,
|
|
1197
|
+
initialEvent: options?.initialEvent,
|
|
1198
|
+
first: options?.first,
|
|
1199
|
+
topicPrefix: options?.topicPrefix
|
|
1200
|
+
}
|
|
1201
|
+
})
|
|
1202
|
+
);
|
|
1203
|
+
return this.subscribeToMultipleTables(tableConfigs, options);
|
|
1204
|
+
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Build dynamic query - Adapted to API without store prefix
|
|
1207
|
+
*/
|
|
1208
|
+
buildQuery(tableName, fields, params) {
|
|
1209
|
+
const pluralTableName = this.getPluralTableName(tableName);
|
|
1210
|
+
const fieldSelection = fields.join("\n ");
|
|
1211
|
+
return import_client2.gql`
|
|
1212
|
+
query DynamicQuery(
|
|
1213
|
+
$first: Int
|
|
1214
|
+
$after: Cursor
|
|
1215
|
+
$filter: ${this.getFilterTypeName(tableName)}
|
|
1216
|
+
$orderBy: [${this.getOrderByTypeName(tableName)}!]
|
|
1217
|
+
) {
|
|
1218
|
+
${pluralTableName}(
|
|
1219
|
+
first: $first
|
|
1220
|
+
after: $after
|
|
1221
|
+
filter: $filter
|
|
1222
|
+
orderBy: $orderBy
|
|
1223
|
+
) {
|
|
1224
|
+
totalCount
|
|
1225
|
+
pageInfo {
|
|
1226
|
+
hasNextPage
|
|
1227
|
+
endCursor
|
|
1228
|
+
}
|
|
1229
|
+
edges {
|
|
1230
|
+
cursor
|
|
1231
|
+
node {
|
|
1232
|
+
${fieldSelection}
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
`;
|
|
1238
|
+
}
|
|
1239
|
+
/**
|
|
1240
|
+
* Batch query multiple tables - Adapted to API without store prefix
|
|
1241
|
+
*/
|
|
1242
|
+
async batchQuery(queries) {
|
|
1243
|
+
const batchPromises = queries.map(async ({ key, tableName, params }) => {
|
|
1244
|
+
const result = await this.getAllTables(tableName, params);
|
|
1245
|
+
return { key, result };
|
|
1246
|
+
});
|
|
1247
|
+
const results = await Promise.all(batchPromises);
|
|
1248
|
+
return results.reduce(
|
|
1249
|
+
(acc, { key, result }) => {
|
|
1250
|
+
acc[key] = result;
|
|
1251
|
+
return acc;
|
|
1252
|
+
},
|
|
1253
|
+
{}
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Real-time data stream listener - Adapted to API without store prefix
|
|
1258
|
+
*/
|
|
1259
|
+
createRealTimeDataStream(tableName, initialQuery) {
|
|
1260
|
+
return new import_client2.Observable((observer) => {
|
|
1261
|
+
this.getAllTables(tableName, initialQuery).then((initialData) => {
|
|
1262
|
+
observer.next(initialData);
|
|
1263
|
+
}).catch((error) => observer.error(error));
|
|
1264
|
+
const subscription = this.subscribeToTableChanges(tableName, {
|
|
1265
|
+
onData: () => {
|
|
1266
|
+
this.getAllTables(tableName, initialQuery).then((updatedData) => {
|
|
1267
|
+
observer.next(updatedData);
|
|
1268
|
+
}).catch((error) => observer.error(error));
|
|
1269
|
+
},
|
|
1270
|
+
onError: (error) => observer.error(error)
|
|
1271
|
+
});
|
|
1272
|
+
return () => subscription.subscribe().unsubscribe();
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
// Improved table name handling methods
|
|
1276
|
+
getFilterTypeName(tableName) {
|
|
1277
|
+
const singularName = this.getSingularTableName(tableName);
|
|
1278
|
+
const pascalCaseName = this.toPascalCase(singularName);
|
|
1279
|
+
if (pascalCaseName.startsWith("Store")) {
|
|
1280
|
+
return `${pascalCaseName}Filter`;
|
|
1281
|
+
}
|
|
1282
|
+
return `Store${pascalCaseName}Filter`;
|
|
1283
|
+
}
|
|
1284
|
+
getOrderByTypeName(tableName) {
|
|
1285
|
+
const pluralName = this.getPluralTableName(tableName);
|
|
1286
|
+
const pascalCaseName = this.toPascalCase(pluralName);
|
|
1287
|
+
if (pascalCaseName.startsWith("Store")) {
|
|
1288
|
+
return `${pascalCaseName}OrderBy`;
|
|
1289
|
+
}
|
|
1290
|
+
return `Store${pascalCaseName}OrderBy`;
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Convert singular table name to plural form (using pluralize library for correctness)
|
|
1294
|
+
*/
|
|
1295
|
+
getPluralTableName(tableName) {
|
|
1296
|
+
const camelCaseName = this.toCamelCase(tableName);
|
|
1297
|
+
return import_pluralize.default.plural(camelCaseName);
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* Convert plural table name to singular form (using pluralize library for correctness)
|
|
1301
|
+
*/
|
|
1302
|
+
getSingularTableName(tableName) {
|
|
1303
|
+
const camelCaseName = this.toCamelCase(tableName);
|
|
1304
|
+
return import_pluralize.default.singular(camelCaseName);
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* Convert snake_case to camelCase
|
|
1308
|
+
*/
|
|
1309
|
+
toCamelCase(str) {
|
|
1310
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* Convert snake_case to PascalCase
|
|
1314
|
+
*/
|
|
1315
|
+
toPascalCase(str) {
|
|
1316
|
+
const camelCase = this.toCamelCase(str);
|
|
1317
|
+
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
|
1318
|
+
}
|
|
1319
|
+
/**
|
|
1320
|
+
* Convert camelCase or snake_case to SNAKE_CASE (for GraphQL enum values)
|
|
1321
|
+
* Example: updatedAt -> UPDATED_AT, updated_at -> UPDATED_AT
|
|
1322
|
+
*/
|
|
1323
|
+
toSnakeCase(str) {
|
|
1324
|
+
if (str.includes("_")) {
|
|
1325
|
+
return str.toUpperCase();
|
|
1326
|
+
}
|
|
1327
|
+
return str.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "").toUpperCase();
|
|
1328
|
+
}
|
|
1329
|
+
// private buildSingleQueryName(
|
|
1330
|
+
// tableName: string,
|
|
1331
|
+
// conditionKeys: string[]
|
|
1332
|
+
// ): string {
|
|
1333
|
+
// // Use camelCase conversion
|
|
1334
|
+
// const camelCaseTableName = this.toCamelCase(tableName);
|
|
1335
|
+
// const capitalizedKeys = conditionKeys.map(
|
|
1336
|
+
// (key) => key.charAt(0).toUpperCase() + key.slice(1)
|
|
1337
|
+
// );
|
|
1338
|
+
// return `${camelCaseTableName}By${capitalizedKeys.join('And')}`;
|
|
1339
|
+
// }
|
|
1340
|
+
/**
|
|
1341
|
+
* Clear Apollo Client cache
|
|
1342
|
+
*/
|
|
1343
|
+
async clearCache() {
|
|
1344
|
+
await this.apolloClient.clearStore();
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* Reset Apollo Client cache
|
|
1348
|
+
*/
|
|
1349
|
+
async resetCache() {
|
|
1350
|
+
await this.apolloClient.resetStore();
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* Get Apollo Client instance (for advanced usage)
|
|
1354
|
+
*/
|
|
1355
|
+
getApolloClient() {
|
|
1356
|
+
return this.apolloClient;
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Close client connection
|
|
1360
|
+
*/
|
|
1361
|
+
close() {
|
|
1362
|
+
if (this.subscriptionClient) {
|
|
1363
|
+
this.subscriptionClient.dispose();
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* Get Dubhe metadata
|
|
1368
|
+
*/
|
|
1369
|
+
getDubheMetadata() {
|
|
1370
|
+
return this.dubheMetadata;
|
|
1371
|
+
}
|
|
1372
|
+
/**
|
|
1373
|
+
* Build dynamic cache field configuration
|
|
1374
|
+
*/
|
|
1375
|
+
buildCacheFields(cacheConfig) {
|
|
1376
|
+
const fields = {};
|
|
1377
|
+
if (!cacheConfig) {
|
|
1378
|
+
return fields;
|
|
1379
|
+
}
|
|
1380
|
+
if (cacheConfig.paginatedTables) {
|
|
1381
|
+
cacheConfig.paginatedTables.forEach((tableName) => {
|
|
1382
|
+
const pluralTableName = this.getPluralTableName(tableName);
|
|
1383
|
+
const customStrategy = cacheConfig.customMergeStrategies?.[pluralTableName];
|
|
1384
|
+
fields[pluralTableName] = {
|
|
1385
|
+
keyArgs: customStrategy?.keyArgs || ["filter", "orderBy"],
|
|
1386
|
+
merge: customStrategy?.merge || this.defaultMergeStrategy
|
|
1387
|
+
};
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
if (cacheConfig.customMergeStrategies) {
|
|
1391
|
+
Object.entries(cacheConfig.customMergeStrategies).forEach(
|
|
1392
|
+
([tableName, strategy]) => {
|
|
1393
|
+
if (!fields[tableName]) {
|
|
1394
|
+
fields[tableName] = {
|
|
1395
|
+
keyArgs: strategy.keyArgs || ["filter", "orderBy"],
|
|
1396
|
+
merge: strategy.merge || this.defaultMergeStrategy
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
return fields;
|
|
1403
|
+
}
|
|
1404
|
+
/**
|
|
1405
|
+
* Default pagination merge strategy
|
|
1406
|
+
*/
|
|
1407
|
+
defaultMergeStrategy(existing = { edges: [] }, incoming) {
|
|
1408
|
+
if (!incoming || !Array.isArray(incoming.edges)) {
|
|
1409
|
+
return existing;
|
|
1410
|
+
}
|
|
1411
|
+
return {
|
|
1412
|
+
...incoming,
|
|
1413
|
+
edges: [...existing.edges || [], ...incoming.edges]
|
|
1414
|
+
};
|
|
1415
|
+
}
|
|
1416
|
+
/**
|
|
1417
|
+
* Parse table information from dubhe metadata
|
|
1418
|
+
*/
|
|
1419
|
+
parseTableInfoFromConfig() {
|
|
1420
|
+
if (!this.dubheMetadata) {
|
|
1421
|
+
return;
|
|
1422
|
+
}
|
|
1423
|
+
const { components = [], resources = [], enums = [] } = this.dubheMetadata;
|
|
1424
|
+
components.forEach((componentObj) => {
|
|
1425
|
+
Object.entries(componentObj).forEach(
|
|
1426
|
+
([componentName, componentData]) => {
|
|
1427
|
+
this.processTableData(componentName, componentData, enums);
|
|
1428
|
+
}
|
|
1429
|
+
);
|
|
1430
|
+
});
|
|
1431
|
+
resources.forEach((resourceObj) => {
|
|
1432
|
+
Object.entries(resourceObj).forEach(
|
|
1433
|
+
([resourceName, resourceData]) => {
|
|
1434
|
+
this.processTableData(resourceName, resourceData, enums);
|
|
1435
|
+
}
|
|
1436
|
+
);
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Process data for a single table
|
|
1441
|
+
*/
|
|
1442
|
+
processTableData(tableName, tableData, enums) {
|
|
1443
|
+
const snakeTableName = this.toSnakeCase(tableName);
|
|
1444
|
+
const fields = [];
|
|
1445
|
+
const enumFields = {};
|
|
1446
|
+
if (tableData.fields && Array.isArray(tableData.fields)) {
|
|
1447
|
+
tableData.fields.forEach((fieldObj) => {
|
|
1448
|
+
Object.entries(fieldObj).forEach(
|
|
1449
|
+
([fieldName, fieldType]) => {
|
|
1450
|
+
const fieldNameCamelCase = this.toCamelCase(fieldName);
|
|
1451
|
+
fields.push(fieldNameCamelCase);
|
|
1452
|
+
}
|
|
1453
|
+
);
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
fields.push("createdAt", "updatedAt");
|
|
1457
|
+
const primaryKeys = tableData.keys.map(
|
|
1458
|
+
(key) => this.toCamelCase(key)
|
|
1459
|
+
);
|
|
1460
|
+
const tableInfo = {
|
|
1461
|
+
tableName: snakeTableName,
|
|
1462
|
+
fields: [...new Set(fields)],
|
|
1463
|
+
// Remove duplicates
|
|
1464
|
+
primaryKeys,
|
|
1465
|
+
enumFields
|
|
1466
|
+
};
|
|
1467
|
+
this.parsedTables.set(snakeTableName, tableInfo);
|
|
1468
|
+
this.parsedTables.set(this.toCamelCase(snakeTableName), tableInfo);
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Get table field information
|
|
1472
|
+
*/
|
|
1473
|
+
getTableFields(tableName) {
|
|
1474
|
+
return this.getMinimalFields(tableName);
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* Get table primary key information
|
|
1478
|
+
*/
|
|
1479
|
+
getTablePrimaryKeys(tableName) {
|
|
1480
|
+
const tableInfo = this.parsedTables.get(tableName) || this.parsedTables.get(this.toSnakeCase(tableName));
|
|
1481
|
+
return tableInfo?.primaryKeys || [];
|
|
1482
|
+
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Get table enum field information
|
|
1485
|
+
*/
|
|
1486
|
+
getTableEnumFields(tableName) {
|
|
1487
|
+
const tableInfo = this.parsedTables.get(tableName) || this.parsedTables.get(this.toSnakeCase(tableName));
|
|
1488
|
+
return tableInfo?.enumFields || {};
|
|
1489
|
+
}
|
|
1490
|
+
/**
|
|
1491
|
+
* Get all parsed table information
|
|
1492
|
+
*/
|
|
1493
|
+
getAllTableInfo() {
|
|
1494
|
+
return new Map(this.parsedTables);
|
|
1495
|
+
}
|
|
1496
|
+
/**
|
|
1497
|
+
* Get table's minimal field set (for fallback)
|
|
1498
|
+
*/
|
|
1499
|
+
getMinimalFields(tableName) {
|
|
1500
|
+
const tableInfo = this.parsedTables.get(tableName) || this.parsedTables.get(this.toSnakeCase(tableName));
|
|
1501
|
+
if (tableInfo) {
|
|
1502
|
+
return tableInfo.fields;
|
|
1503
|
+
}
|
|
1504
|
+
return ["createdAt", "updatedAt"];
|
|
1505
|
+
}
|
|
1506
|
+
/**
|
|
1507
|
+
* Convert table fields to GraphQL query string
|
|
1508
|
+
*/
|
|
1509
|
+
convertTableFields(tableName, customFields) {
|
|
1510
|
+
let fields;
|
|
1511
|
+
if (customFields && customFields.length > 0) {
|
|
1512
|
+
fields = customFields;
|
|
1513
|
+
} else {
|
|
1514
|
+
const autoFields = this.getTableFields(tableName);
|
|
1515
|
+
if (autoFields.length > 0) {
|
|
1516
|
+
fields = autoFields;
|
|
1517
|
+
} else {
|
|
1518
|
+
fields = ["createdAt", "updatedAt"];
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
return fields.join("\n ");
|
|
1522
|
+
}
|
|
1523
|
+
};
|
|
1524
|
+
function createDubheGraphqlClient(config) {
|
|
1525
|
+
return new DubheGraphqlClient(config);
|
|
1526
|
+
}
|
|
1527
|
+
var QueryBuilders = {
|
|
1528
|
+
// Build basic query - Adapted to API without store prefix
|
|
1529
|
+
basic: (tableName, fields = ["createdAt", "updatedAt"]) => import_client2.gql`
|
|
1530
|
+
query Basic${tableName.charAt(0).toUpperCase() + tableName.slice(1)}Query(
|
|
1531
|
+
$first: Int
|
|
1532
|
+
$after: String
|
|
1533
|
+
$filter: ${tableName.charAt(0).toUpperCase() + tableName.slice(1)}Filter
|
|
1534
|
+
) {
|
|
1535
|
+
${tableName}(first: $first, after: $after, filter: $filter) {
|
|
1536
|
+
totalCount
|
|
1537
|
+
pageInfo {
|
|
1538
|
+
hasNextPage
|
|
1539
|
+
endCursor
|
|
1540
|
+
}
|
|
1541
|
+
edges {
|
|
1542
|
+
cursor
|
|
1543
|
+
node {
|
|
1544
|
+
${fields.join("\n ")}
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
`,
|
|
1550
|
+
// Build subscription query - Adapted to API without store prefix
|
|
1551
|
+
subscription: (tableName) => import_client2.gql`
|
|
1552
|
+
subscription ${tableName.charAt(0).toUpperCase() + tableName.slice(1)}Subscription {
|
|
1553
|
+
${tableName.charAt(0).toLowerCase() + tableName.slice(1)}Changed {
|
|
1554
|
+
createdAt
|
|
1555
|
+
updatedAt
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
`
|
|
1559
|
+
};
|
|
1560
|
+
function convertOrderByToEnum(orderBy) {
|
|
1561
|
+
if (!orderBy || orderBy.length === 0) {
|
|
1562
|
+
return ["NATURAL"];
|
|
1563
|
+
}
|
|
1564
|
+
return orderBy.map((order) => {
|
|
1565
|
+
const field = toSnakeCaseForEnum(order.field);
|
|
1566
|
+
const direction = order.direction === "DESC" ? "DESC" : "ASC";
|
|
1567
|
+
return `${field}_${direction}`;
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
function toSnakeCaseForEnum(str) {
|
|
1571
|
+
if (str.includes("_")) {
|
|
1572
|
+
return str.toUpperCase();
|
|
1573
|
+
}
|
|
1574
|
+
return str.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "").toUpperCase();
|
|
1575
|
+
}
|
|
1576
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1577
|
+
0 && (module.exports = {
|
|
1578
|
+
DubheGraphqlClient,
|
|
1579
|
+
QueryBuilders,
|
|
1580
|
+
createDubheGraphqlClient
|
|
1581
|
+
});
|
|
1582
|
+
//# sourceMappingURL=index.js.map
|