@m1212e/rumble 0.23.2 → 0.23.5
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/out/index.cjs +200 -61
- package/out/index.cjs.map +1 -1
- package/out/index.d.cts +7 -0
- package/out/index.d.cts.map +1 -1
- package/out/index.d.mts +8 -1
- package/out/index.d.mts.map +1 -1
- package/out/index.mjs +201 -62
- package/out/index.mjs.map +1 -1
- package/package.json +1 -1
package/out/index.mjs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { t as lazy } from "./lazy-C7IyM4M4.mjs";
|
|
2
2
|
import { t as generateFromSchema } from "./generate-0QFVc3Sg.mjs";
|
|
3
|
-
import { GraphQLError, GraphQLSchema } from "graphql";
|
|
3
|
+
import { GraphQLError, GraphQLSchema, execute as defaultExecute, subscribe as defaultSubscribe } from "graphql";
|
|
4
4
|
import { EnvelopArmorPlugin } from "@escape.tech/graphql-armor";
|
|
5
5
|
import { useDisableIntrospection } from "@graphql-yoga/plugin-disable-introspection";
|
|
6
6
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
7
|
-
import { AttributeNames, SpanNames, createOpenTelemetryWrapper } from "@pothos/tracing-opentelemetry";
|
|
8
7
|
import { capitalize, cloneDeep, debounce, merge, toMerged } from "es-toolkit";
|
|
9
8
|
import { createPubSub, createYoga } from "graphql-yoga";
|
|
10
9
|
import { One, count, getTableColumns, getTableName, is, isTable, relationsFilterToSQL, sql } from "drizzle-orm";
|
|
@@ -12,6 +11,7 @@ import { toCamelCase } from "drizzle-orm/casing";
|
|
|
12
11
|
import { PgColumn, PgEnumColumn, PgEnumObjectColumn, PgTable, isPgEnum } from "drizzle-orm/pg-core";
|
|
13
12
|
import { MySqlEnumColumn, MySqlEnumObjectColumn, MySqlTable } from "drizzle-orm/mysql-core";
|
|
14
13
|
import pluralize from "pluralize";
|
|
14
|
+
import { AttributeNames, SpanNames, createOpenTelemetryWrapper } from "@pothos/tracing-opentelemetry";
|
|
15
15
|
import { SQLiteTable } from "drizzle-orm/sqlite-core";
|
|
16
16
|
import SchemaBuilder, { BasePlugin } from "@pothos/core";
|
|
17
17
|
import DrizzlePlugin from "@pothos/plugin-drizzle";
|
|
@@ -180,12 +180,25 @@ function mapNullFieldsToUndefined(obj) {
|
|
|
180
180
|
}
|
|
181
181
|
//#endregion
|
|
182
182
|
//#region package.json
|
|
183
|
-
var version = "0.23.
|
|
183
|
+
var version = "0.23.5";
|
|
184
184
|
//#endregion
|
|
185
185
|
//#region lib/helpers/mergeFilters.ts
|
|
186
|
+
const EmptyFilter$1 = Symbol.for("drizzle:EmptyFilter");
|
|
187
|
+
/**
|
|
188
|
+
* Normalizes drizzle-orm's `EmptyFilter` sentinel to `undefined` so it's
|
|
189
|
+
* treated as "no filter" rather than a real filter value to combine with
|
|
190
|
+
* AND/OR — otherwise merging an unrestricted (EmptyFilter) base filter with
|
|
191
|
+
* a real `where` would needlessly wrap it as `{ AND: [EmptyFilter, where] }`
|
|
192
|
+
* instead of just `where`.
|
|
193
|
+
*/
|
|
194
|
+
function realWhere(where) {
|
|
195
|
+
return where === EmptyFilter$1 ? void 0 : where;
|
|
196
|
+
}
|
|
186
197
|
function mergeFilters(filterA, filterB, mode = "AND") {
|
|
198
|
+
const filterAWhere = realWhere(filterA?.where);
|
|
199
|
+
const filterBWhere = realWhere(filterB?.where);
|
|
187
200
|
return {
|
|
188
|
-
where:
|
|
201
|
+
where: filterAWhere && filterBWhere ? mode === "OR" ? { OR: [filterAWhere, filterBWhere] } : { AND: [filterAWhere, filterBWhere] } : filterAWhere ?? filterBWhere,
|
|
189
202
|
columns: filterA?.columns || filterB?.columns ? new Set([Object.entries(filterA?.columns ?? {}), Object.entries(filterB?.columns ?? {})].flat().filter(([, v]) => v === true).map(([k]) => k)).entries().reduce((acc, [key]) => {
|
|
190
203
|
acc[key] = true;
|
|
191
204
|
return acc;
|
|
@@ -412,6 +425,21 @@ function tableHelper({ db, table }) {
|
|
|
412
425
|
}
|
|
413
426
|
//#endregion
|
|
414
427
|
//#region lib/abilityBuilder.ts
|
|
428
|
+
/**
|
|
429
|
+
* drizzle-orm's sentinel value for "this filter field is deliberately
|
|
430
|
+
* skipped", as opposed to `undefined`, which some drizzle-orm versions
|
|
431
|
+
* reject when it ends up as an explicit (present but `undefined`) `where`
|
|
432
|
+
* property nested inside a relational `with` query.
|
|
433
|
+
*
|
|
434
|
+
* drizzle-orm defines this via `Symbol.for("drizzle:EmptyFilter")` — a
|
|
435
|
+
* globally registered symbol — so recreating it the same way here yields
|
|
436
|
+
* the exact same value drizzle-orm's relational query engine checks for,
|
|
437
|
+
* without importing it directly: not every drizzle-orm version rumble
|
|
438
|
+
* supports exports it as a named export, and older versions that don't know
|
|
439
|
+
* about it at all still handle it safely (`Object.entries` on a symbol
|
|
440
|
+
* yields no entries, i.e. "no filter").
|
|
441
|
+
*/
|
|
442
|
+
const EmptyFilter = Symbol.for("drizzle:EmptyFilter");
|
|
415
443
|
function isDynamicQueryFilter(filter) {
|
|
416
444
|
return typeof filter === "function" && filter.constructor.name !== "AsyncFunction";
|
|
417
445
|
}
|
|
@@ -580,7 +608,7 @@ by: (explicitFilter) => {
|
|
|
580
608
|
*/
|
|
581
609
|
single: {
|
|
582
610
|
extras: filters?.extras,
|
|
583
|
-
where: filters?.where,
|
|
611
|
+
where: filters?.where ?? EmptyFilter,
|
|
584
612
|
columns: filters?.columns
|
|
585
613
|
},
|
|
586
614
|
/**
|
|
@@ -588,7 +616,7 @@ by: (explicitFilter) => {
|
|
|
588
616
|
*/
|
|
589
617
|
many: {
|
|
590
618
|
extras: filters?.extras,
|
|
591
|
-
where: filters?.where,
|
|
619
|
+
where: filters?.where ?? EmptyFilter,
|
|
592
620
|
columns: filters?.columns,
|
|
593
621
|
get limit() {
|
|
594
622
|
return limit();
|
|
@@ -634,14 +662,14 @@ by: (explicitFilter) => {
|
|
|
634
662
|
*/
|
|
635
663
|
single: {
|
|
636
664
|
extras: filters?.extras,
|
|
637
|
-
where: filters?.where
|
|
665
|
+
where: filters?.where ?? EmptyFilter
|
|
638
666
|
},
|
|
639
667
|
/**
|
|
640
668
|
* For find many calls
|
|
641
669
|
*/
|
|
642
670
|
many: {
|
|
643
671
|
extras: filters?.extras,
|
|
644
|
-
where: filters?.where,
|
|
672
|
+
where: filters?.where ?? EmptyFilter,
|
|
645
673
|
get limit() {
|
|
646
674
|
return limit();
|
|
647
675
|
}
|
|
@@ -1272,6 +1300,165 @@ const sofaOpenAPIWebhookDocs = {
|
|
|
1272
1300
|
} }
|
|
1273
1301
|
};
|
|
1274
1302
|
//#endregion
|
|
1303
|
+
//#region lib/helpers/tracing.ts
|
|
1304
|
+
function isAsyncIterable(value) {
|
|
1305
|
+
return typeof value === "object" && value !== null && Symbol.asyncIterator in value;
|
|
1306
|
+
}
|
|
1307
|
+
async function* wrapSubscriptionIterator(iterator, log, operationName) {
|
|
1308
|
+
let eventCount = 0;
|
|
1309
|
+
try {
|
|
1310
|
+
for await (const event of iterator) {
|
|
1311
|
+
eventCount++;
|
|
1312
|
+
if (event.errors?.length) log.error({
|
|
1313
|
+
"graphql.operation.name": operationName,
|
|
1314
|
+
eventCount,
|
|
1315
|
+
errors: event.errors.map((e) => e.message)
|
|
1316
|
+
}, "graphql subscription event error");
|
|
1317
|
+
yield event;
|
|
1318
|
+
}
|
|
1319
|
+
log.info({
|
|
1320
|
+
"graphql.operation.name": operationName,
|
|
1321
|
+
eventCount
|
|
1322
|
+
}, "graphql subscription completed");
|
|
1323
|
+
} catch (error) {
|
|
1324
|
+
log.error({
|
|
1325
|
+
"graphql.operation.name": operationName,
|
|
1326
|
+
eventCount,
|
|
1327
|
+
err: error
|
|
1328
|
+
}, "graphql subscription threw");
|
|
1329
|
+
throw error;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
function buildTracedExecute(executeFn, rumbleInput) {
|
|
1333
|
+
return async (options) => {
|
|
1334
|
+
let log = rumbleInput.logger?.enabled ? rumbleInput.logger.logger : void 0;
|
|
1335
|
+
const operationName = options.operationName ?? "anonymous";
|
|
1336
|
+
const start = Date.now();
|
|
1337
|
+
log?.info({ "graphql.operation.name": operationName }, "graphql execute start");
|
|
1338
|
+
const run = async () => {
|
|
1339
|
+
const result = await executeFn(options);
|
|
1340
|
+
if (result && "errors" in result && result.errors?.length) log?.error({
|
|
1341
|
+
"graphql.operation.name": operationName,
|
|
1342
|
+
durationMs: Date.now() - start,
|
|
1343
|
+
errors: result.errors.map((e) => e.message)
|
|
1344
|
+
}, "graphql execute completed with errors");
|
|
1345
|
+
else log?.info({
|
|
1346
|
+
"graphql.operation.name": operationName,
|
|
1347
|
+
durationMs: Date.now() - start
|
|
1348
|
+
}, "graphql execute completed");
|
|
1349
|
+
return result;
|
|
1350
|
+
};
|
|
1351
|
+
if (rumbleInput.otel?.enabled) return rumbleInput.otel.tracer.startActiveSpan(SpanNames.EXECUTE, { attributes: {
|
|
1352
|
+
[AttributeNames.OPERATION_NAME]: operationName,
|
|
1353
|
+
[AttributeNames.SOURCE]: options.document
|
|
1354
|
+
} }, async (span) => {
|
|
1355
|
+
if (log && rumbleInput.logger?.injectTraceId !== false) {
|
|
1356
|
+
const { traceId, spanId } = span.spanContext();
|
|
1357
|
+
log = log.child({
|
|
1358
|
+
traceId,
|
|
1359
|
+
spanId
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
try {
|
|
1363
|
+
const result = await run();
|
|
1364
|
+
if (result && "errors" in result && result.errors?.length) {
|
|
1365
|
+
for (const error of result.errors) span.recordException(error);
|
|
1366
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1367
|
+
}
|
|
1368
|
+
return result;
|
|
1369
|
+
} catch (error) {
|
|
1370
|
+
if (error instanceof Error) span.recordException(error);
|
|
1371
|
+
log?.error({
|
|
1372
|
+
"graphql.operation.name": operationName,
|
|
1373
|
+
durationMs: Date.now() - start,
|
|
1374
|
+
err: error
|
|
1375
|
+
}, "graphql execute threw");
|
|
1376
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1377
|
+
throw error;
|
|
1378
|
+
} finally {
|
|
1379
|
+
span.end();
|
|
1380
|
+
}
|
|
1381
|
+
});
|
|
1382
|
+
try {
|
|
1383
|
+
return await run();
|
|
1384
|
+
} catch (error) {
|
|
1385
|
+
log?.error({
|
|
1386
|
+
"graphql.operation.name": operationName,
|
|
1387
|
+
durationMs: Date.now() - start,
|
|
1388
|
+
err: error
|
|
1389
|
+
}, "graphql execute threw");
|
|
1390
|
+
throw error;
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1394
|
+
function buildTracedSubscribe(subscribeFn, rumbleInput) {
|
|
1395
|
+
return async (options) => {
|
|
1396
|
+
let log = rumbleInput.logger?.enabled ? rumbleInput.logger.logger : void 0;
|
|
1397
|
+
const operationName = options.operationName ?? "anonymous";
|
|
1398
|
+
const start = Date.now();
|
|
1399
|
+
const doSubscribe = async () => {
|
|
1400
|
+
log?.info({ "graphql.operation.name": operationName }, "graphql subscribe start");
|
|
1401
|
+
const result = await subscribeFn(options);
|
|
1402
|
+
if (!isAsyncIterable(result)) {
|
|
1403
|
+
const execResult = result;
|
|
1404
|
+
if (execResult.errors?.length) log?.error({
|
|
1405
|
+
"graphql.operation.name": operationName,
|
|
1406
|
+
durationMs: Date.now() - start,
|
|
1407
|
+
errors: execResult.errors.map((e) => e.message)
|
|
1408
|
+
}, "graphql subscribe completed with errors");
|
|
1409
|
+
return execResult;
|
|
1410
|
+
}
|
|
1411
|
+
log?.info({
|
|
1412
|
+
"graphql.operation.name": operationName,
|
|
1413
|
+
durationMs: Date.now() - start
|
|
1414
|
+
}, "graphql subscription established");
|
|
1415
|
+
if (log) return wrapSubscriptionIterator(result, log, operationName);
|
|
1416
|
+
return result;
|
|
1417
|
+
};
|
|
1418
|
+
if (rumbleInput.otel?.enabled) return rumbleInput.otel.tracer.startActiveSpan("graphql.subscribe", async (span) => {
|
|
1419
|
+
if (log && rumbleInput.logger?.injectTraceId !== false) {
|
|
1420
|
+
const { traceId, spanId } = span.spanContext();
|
|
1421
|
+
log = log.child({
|
|
1422
|
+
traceId,
|
|
1423
|
+
spanId
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1426
|
+
try {
|
|
1427
|
+
const result = await doSubscribe();
|
|
1428
|
+
if (!isAsyncIterable(result)) {
|
|
1429
|
+
const execResult = result;
|
|
1430
|
+
if (execResult.errors?.length) {
|
|
1431
|
+
for (const error of execResult.errors) span.recordException(error);
|
|
1432
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
return result;
|
|
1436
|
+
} catch (error) {
|
|
1437
|
+
if (error instanceof Error) span.recordException(error);
|
|
1438
|
+
log?.error({
|
|
1439
|
+
"graphql.operation.name": operationName,
|
|
1440
|
+
durationMs: Date.now() - start,
|
|
1441
|
+
err: error
|
|
1442
|
+
}, "graphql subscribe threw");
|
|
1443
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1444
|
+
throw error;
|
|
1445
|
+
} finally {
|
|
1446
|
+
span.end();
|
|
1447
|
+
}
|
|
1448
|
+
});
|
|
1449
|
+
try {
|
|
1450
|
+
return await doSubscribe();
|
|
1451
|
+
} catch (error) {
|
|
1452
|
+
log?.error({
|
|
1453
|
+
"graphql.operation.name": operationName,
|
|
1454
|
+
durationMs: Date.now() - start,
|
|
1455
|
+
err: error
|
|
1456
|
+
}, "graphql subscribe threw");
|
|
1457
|
+
throw error;
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
//#endregion
|
|
1275
1462
|
//#region lib/helpers/sqlTypes/mapDrizzleTypeToGraphQlType.ts
|
|
1276
1463
|
function buildPothosResponseTypeFromGraphQLType({ builder, sqlType, fieldName, nullable, isArray }) {
|
|
1277
1464
|
const gqlType = mapSQLTypeToGraphQLType({
|
|
@@ -2309,59 +2496,7 @@ export const r = rumble({
|
|
|
2309
2496
|
...args?.plugins ?? [],
|
|
2310
2497
|
...enableApiDocs ? [] : [useDisableIntrospection(), EnvelopArmorPlugin(args?.armorConfig)],
|
|
2311
2498
|
rumbleInput.otel?.enabled || rumbleInput.logger?.enabled ? { onExecute: ({ setExecuteFn, executeFn }) => {
|
|
2312
|
-
setExecuteFn(
|
|
2313
|
-
const log = rumbleInput.logger?.enabled ? rumbleInput.logger.logger : void 0;
|
|
2314
|
-
const operationName = options.operationName ?? "anonymous";
|
|
2315
|
-
const start = Date.now();
|
|
2316
|
-
log?.info({ "graphql.operation.name": operationName }, "graphql execute start");
|
|
2317
|
-
const run = async () => {
|
|
2318
|
-
const result = await executeFn(options);
|
|
2319
|
-
if (result && "errors" in result && result.errors?.length) log?.error({
|
|
2320
|
-
"graphql.operation.name": operationName,
|
|
2321
|
-
durationMs: Date.now() - start,
|
|
2322
|
-
errors: result.errors.map((e) => e.message)
|
|
2323
|
-
}, "graphql execute completed with errors");
|
|
2324
|
-
else log?.info({
|
|
2325
|
-
"graphql.operation.name": operationName,
|
|
2326
|
-
durationMs: Date.now() - start
|
|
2327
|
-
}, "graphql execute completed");
|
|
2328
|
-
return result;
|
|
2329
|
-
};
|
|
2330
|
-
if (rumbleInput.otel?.enabled) return rumbleInput.otel.tracer.startActiveSpan(SpanNames.EXECUTE, { attributes: {
|
|
2331
|
-
[AttributeNames.OPERATION_NAME]: operationName,
|
|
2332
|
-
[AttributeNames.SOURCE]: options.document
|
|
2333
|
-
} }, async (span) => {
|
|
2334
|
-
try {
|
|
2335
|
-
const result = await run();
|
|
2336
|
-
if (result && "errors" in result && result.errors?.length) {
|
|
2337
|
-
for (const error of result.errors) span.recordException(error);
|
|
2338
|
-
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
2339
|
-
}
|
|
2340
|
-
return result;
|
|
2341
|
-
} catch (error) {
|
|
2342
|
-
if (error instanceof Error) span.recordException(error);
|
|
2343
|
-
log?.error({
|
|
2344
|
-
"graphql.operation.name": operationName,
|
|
2345
|
-
durationMs: Date.now() - start,
|
|
2346
|
-
err: error
|
|
2347
|
-
}, "graphql execute threw");
|
|
2348
|
-
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
2349
|
-
throw error;
|
|
2350
|
-
} finally {
|
|
2351
|
-
span.end();
|
|
2352
|
-
}
|
|
2353
|
-
});
|
|
2354
|
-
try {
|
|
2355
|
-
return await run();
|
|
2356
|
-
} catch (error) {
|
|
2357
|
-
log?.error({
|
|
2358
|
-
"graphql.operation.name": operationName,
|
|
2359
|
-
durationMs: Date.now() - start,
|
|
2360
|
-
err: error
|
|
2361
|
-
}, "graphql execute threw");
|
|
2362
|
-
throw error;
|
|
2363
|
-
}
|
|
2364
|
-
});
|
|
2499
|
+
setExecuteFn(buildTracedExecute(executeFn, rumbleInput));
|
|
2365
2500
|
} } : false
|
|
2366
2501
|
].filter(Boolean)
|
|
2367
2502
|
});
|
|
@@ -2382,6 +2517,8 @@ export const r = rumble({
|
|
|
2382
2517
|
...args,
|
|
2383
2518
|
schema: builtSchema(),
|
|
2384
2519
|
context,
|
|
2520
|
+
execute: buildTracedExecute(args.execute ?? defaultExecute, rumbleInput),
|
|
2521
|
+
subscribe: buildTracedSubscribe(args.subscribe ?? defaultSubscribe, rumbleInput),
|
|
2385
2522
|
errorHandler(errors) {
|
|
2386
2523
|
const span = trace.getActiveSpan();
|
|
2387
2524
|
for (const error of errors) span?.recordException(error);
|
|
@@ -2394,7 +2531,9 @@ export const r = rumble({
|
|
|
2394
2531
|
return implementation({
|
|
2395
2532
|
...args,
|
|
2396
2533
|
schema: builtSchema(),
|
|
2397
|
-
context
|
|
2534
|
+
context,
|
|
2535
|
+
execute: buildTracedExecute(args.execute ?? defaultExecute, rumbleInput),
|
|
2536
|
+
subscribe: buildTracedSubscribe(args.subscribe ?? defaultSubscribe, rumbleInput)
|
|
2398
2537
|
}, ...rest);
|
|
2399
2538
|
};
|
|
2400
2539
|
return {
|