@m1212e/rumble 0.16.16 → 0.16.17
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 +107 -39
- package/out/index.cjs.map +1 -1
- package/out/index.d.cts +41 -27
- package/out/index.d.cts.map +1 -1
- package/out/index.d.mts +41 -27
- package/out/index.d.mts.map +1 -1
- package/out/index.mjs +106 -39
- package/out/index.mjs.map +1 -1
- package/package.json +5 -1
package/out/index.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { t as generateFromSchema } from "./generate-PDRNfY6V.mjs";
|
|
|
3
3
|
import { GraphQLError } from "graphql";
|
|
4
4
|
import { EnvelopArmorPlugin } from "@escape.tech/graphql-armor";
|
|
5
5
|
import { useDisableIntrospection } from "@graphql-yoga/plugin-disable-introspection";
|
|
6
|
+
import { AttributeNames, SpanNames, createOpenTelemetryWrapper } from "@pothos/tracing-opentelemetry";
|
|
6
7
|
import { capitalize, cloneDeep, debounce, merge, toMerged } from "es-toolkit";
|
|
7
8
|
import { createPubSub, createYoga } from "graphql-yoga";
|
|
8
9
|
import { useSofa } from "sofa-api";
|
|
@@ -15,6 +16,7 @@ import { SQLiteTable } from "drizzle-orm/sqlite-core";
|
|
|
15
16
|
import SchemaBuilder, { BasePlugin } from "@pothos/core";
|
|
16
17
|
import DrizzlePlugin from "@pothos/plugin-drizzle";
|
|
17
18
|
import SmartSubscriptionsPlugin, { subscribeOptionsFromIterator } from "@pothos/plugin-smart-subscriptions";
|
|
19
|
+
import TracingPlugin, { isRootField } from "@pothos/plugin-tracing";
|
|
18
20
|
import { DateResolver, DateTimeISOResolver, JSONResolver } from "graphql-scalars";
|
|
19
21
|
|
|
20
22
|
//#region lib/types/rumbleError.ts
|
|
@@ -342,7 +344,7 @@ Warning! No abilities have been registered for
|
|
|
342
344
|
but has been accessed. This will block everything. If this is intended, you can ignore this warning. If not, please ensure that you register the ability in your ability builder.
|
|
343
345
|
`);
|
|
344
346
|
}, 1e3);
|
|
345
|
-
const createAbilityBuilder = ({ db, actions, defaultLimit }) => {
|
|
347
|
+
const createAbilityBuilder = ({ db, actions, defaultLimit, otel }) => {
|
|
346
348
|
let hasBeenBuilt = false;
|
|
347
349
|
const createBuilderForTable = () => {
|
|
348
350
|
const queryFilters = /* @__PURE__ */ new Map();
|
|
@@ -474,27 +476,49 @@ const createAbilityBuilder = ({ db, actions, defaultLimit }) => {
|
|
|
474
476
|
}
|
|
475
477
|
return { withContext: (userContext) => {
|
|
476
478
|
return { filter: (action) => {
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
479
|
+
const assembleAbilities = (span) => {
|
|
480
|
+
const filters = queryFilters.get(action);
|
|
481
|
+
if (filters === "unrestricted") {
|
|
482
|
+
span?.setAttribute("abilities.status", "unrestricted");
|
|
483
|
+
return transformToResponse();
|
|
484
|
+
}
|
|
485
|
+
if (!filters) {
|
|
486
|
+
span?.setAttribute("abilities.status", "blocked_everything");
|
|
487
|
+
nothingRegisteredWarningLogger(tableName.toString(), action);
|
|
488
|
+
return transformToResponse(blockEverythingFilter);
|
|
489
|
+
}
|
|
490
|
+
const dynamicResults = new Array(dynamicQueryFilters[action].length);
|
|
491
|
+
let filtersReturned = 0;
|
|
492
|
+
for (let i = 0; i < dynamicQueryFilters[action].length; i++) {
|
|
493
|
+
const func = dynamicQueryFilters[action][i];
|
|
494
|
+
const result = func(userContext);
|
|
495
|
+
if (result === "allow") return transformToResponse();
|
|
496
|
+
if (result === void 0) continue;
|
|
497
|
+
dynamicResults[filtersReturned++] = result;
|
|
498
|
+
}
|
|
499
|
+
dynamicResults.length = filtersReturned;
|
|
500
|
+
span?.setAttribute("abilities.dynamic", dynamicResults.length);
|
|
501
|
+
span?.setAttribute("abilities.static", simpleQueryFilters[action].length);
|
|
502
|
+
const allQueryFilters = [...simpleQueryFilters[action], ...dynamicResults];
|
|
503
|
+
span?.setAttribute("abilities.total", allQueryFilters.length);
|
|
504
|
+
if (allQueryFilters.length === 0) {
|
|
505
|
+
span?.setAttribute("abilities.status", "blocked_everything");
|
|
506
|
+
return transformToResponse(blockEverythingFilter);
|
|
507
|
+
}
|
|
508
|
+
const mergedFilters = allQueryFilters.length === 1 ? allQueryFilters[0] : allQueryFilters.reduce((a, b) => {
|
|
509
|
+
return mergeFilters(a, b);
|
|
510
|
+
}, {});
|
|
511
|
+
span?.setAttribute("abilities.status", "applied");
|
|
512
|
+
return transformToResponse(mergedFilters);
|
|
513
|
+
};
|
|
514
|
+
if (otel?.tracer) return otel.tracer.startActiveSpan(`prepare_query_abilities_${action}`, (span) => {
|
|
515
|
+
try {
|
|
516
|
+
return assembleAbilities(span);
|
|
517
|
+
} finally {
|
|
518
|
+
span.end();
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
else return assembleAbilities();
|
|
498
522
|
} };
|
|
499
523
|
} };
|
|
500
524
|
};
|
|
@@ -1399,22 +1423,43 @@ const applyFilters = async ({ filters, entities, context }) => {
|
|
|
1399
1423
|
//#region lib/runtimeFiltersPlugin/runtimeFiltersPlugin.ts
|
|
1400
1424
|
const applyFiltersKey = "applyFilters";
|
|
1401
1425
|
var RuntimeFiltersPlugin = class extends BasePlugin {
|
|
1426
|
+
tracer;
|
|
1427
|
+
onTypeConfig(typeConfig) {
|
|
1428
|
+
this.tracer = this.builder.options.otelTracer;
|
|
1429
|
+
return typeConfig;
|
|
1430
|
+
}
|
|
1402
1431
|
wrapResolve(resolver, fieldConfig) {
|
|
1403
1432
|
return async (parent, args, context, info) => {
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1433
|
+
const runFilters = async (span) => {
|
|
1434
|
+
let filters;
|
|
1435
|
+
const fieldType = fieldConfig?.type;
|
|
1436
|
+
if (fieldType.kind === "List") filters = fieldType.type?.ref.currentConfig.pothosOptions[applyFiltersKey];
|
|
1437
|
+
else if (fieldType.kind === "Object") filters = fieldType.ref.currentConfig.pothosOptions[applyFiltersKey];
|
|
1438
|
+
if (!filters || !Array.isArray(filters) || filters.length === 0) {
|
|
1439
|
+
span?.setAttribute("filters.status", "unrestricted");
|
|
1440
|
+
return resolver(parent, args, context, info);
|
|
1441
|
+
}
|
|
1442
|
+
const resolved = await resolver(parent, args, context, info);
|
|
1443
|
+
const allResolvedValues = Array.isArray(resolved) ? resolved : [resolved];
|
|
1444
|
+
const allFilters = Array.isArray(filters) ? filters : [filters];
|
|
1445
|
+
span?.setAttribute("filters.total", allFilters.length);
|
|
1446
|
+
const allowed = await applyFilters({
|
|
1447
|
+
filters: allFilters,
|
|
1448
|
+
entities: allResolvedValues,
|
|
1449
|
+
context
|
|
1450
|
+
});
|
|
1451
|
+
span?.setAttribute("filters.allowed", allowed.length);
|
|
1452
|
+
if (Array.isArray(resolved)) return allowed;
|
|
1453
|
+
return allowed[0] ?? null;
|
|
1454
|
+
};
|
|
1455
|
+
if (this.tracer) return this.tracer.startActiveSpan(`apply_filters_${fieldConfig.name}`, async (span) => {
|
|
1456
|
+
try {
|
|
1457
|
+
return await runFilters();
|
|
1458
|
+
} finally {
|
|
1459
|
+
span.end();
|
|
1460
|
+
}
|
|
1415
1461
|
});
|
|
1416
|
-
|
|
1417
|
-
return allowed[0] ?? null;
|
|
1462
|
+
else return runFilters();
|
|
1418
1463
|
};
|
|
1419
1464
|
}
|
|
1420
1465
|
};
|
|
@@ -1428,7 +1473,8 @@ function registerRuntimeFiltersPlugin() {
|
|
|
1428
1473
|
|
|
1429
1474
|
//#endregion
|
|
1430
1475
|
//#region lib/schemaBuilder.ts
|
|
1431
|
-
const createSchemaBuilder = ({ db, disableDefaultObjects, pubsub, pothosConfig }) => {
|
|
1476
|
+
const createSchemaBuilder = ({ db, disableDefaultObjects, pubsub, pothosConfig, otel }) => {
|
|
1477
|
+
const createSpan = otel?.tracer ? createOpenTelemetryWrapper(otel.tracer, otel.options) : void 0;
|
|
1432
1478
|
registerRuntimeFiltersPlugin();
|
|
1433
1479
|
const schemaBuilder = new SchemaBuilder({
|
|
1434
1480
|
...pothosConfig,
|
|
@@ -1436,6 +1482,7 @@ const createSchemaBuilder = ({ db, disableDefaultObjects, pubsub, pothosConfig }
|
|
|
1436
1482
|
pluginName,
|
|
1437
1483
|
DrizzlePlugin,
|
|
1438
1484
|
SmartSubscriptionsPlugin,
|
|
1485
|
+
TracingPlugin,
|
|
1439
1486
|
...pothosConfig?.plugins ?? []
|
|
1440
1487
|
],
|
|
1441
1488
|
drizzle: {
|
|
@@ -1451,7 +1498,12 @@ const createSchemaBuilder = ({ db, disableDefaultObjects, pubsub, pothosConfig }
|
|
|
1451
1498
|
smartSubscriptions: { ...subscribeOptionsFromIterator((name, _context) => {
|
|
1452
1499
|
return pubsub.subscribe(name);
|
|
1453
1500
|
}) },
|
|
1454
|
-
defaultFieldNullability: false
|
|
1501
|
+
defaultFieldNullability: false,
|
|
1502
|
+
tracing: {
|
|
1503
|
+
default: otel?.tracer ? (config) => isRootField(config) : () => false,
|
|
1504
|
+
wrap: createSpan ? (resolver, options) => createSpan(resolver, options) : (resolver) => resolver
|
|
1505
|
+
},
|
|
1506
|
+
otelTracer: otel?.tracer
|
|
1455
1507
|
});
|
|
1456
1508
|
schemaBuilder.addScalarType("JSON", JSONResolver);
|
|
1457
1509
|
schemaBuilder.addScalarType("Date", DateResolver);
|
|
@@ -1487,7 +1539,7 @@ export const db = drizzle(
|
|
|
1487
1539
|
"postgres://postgres:postgres@localhost:5432/postgres",
|
|
1488
1540
|
{
|
|
1489
1541
|
relations, // <--- add this line
|
|
1490
|
-
schema,
|
|
1542
|
+
schema,
|
|
1491
1543
|
},
|
|
1492
1544
|
);
|
|
1493
1545
|
|
|
@@ -1550,7 +1602,22 @@ export const db = drizzle(
|
|
|
1550
1602
|
return createYoga({
|
|
1551
1603
|
...args,
|
|
1552
1604
|
graphiql: enableApiDocs,
|
|
1553
|
-
plugins: [
|
|
1605
|
+
plugins: [
|
|
1606
|
+
...args?.plugins ?? [],
|
|
1607
|
+
...enableApiDocs ? [] : [useDisableIntrospection(), EnvelopArmorPlugin()],
|
|
1608
|
+
rumbleInput.otel?.tracer ? { onExecute: ({ setExecuteFn, executeFn }) => {
|
|
1609
|
+
setExecuteFn((options) => rumbleInput.otel.tracer.startActiveSpan(SpanNames.EXECUTE, { attributes: { [AttributeNames.OPERATION_NAME]: options.operationName ?? "anonymous" } }, async (span) => {
|
|
1610
|
+
try {
|
|
1611
|
+
return await executeFn(options);
|
|
1612
|
+
} catch (error) {
|
|
1613
|
+
span.recordException(error);
|
|
1614
|
+
throw error;
|
|
1615
|
+
} finally {
|
|
1616
|
+
span.end();
|
|
1617
|
+
}
|
|
1618
|
+
}));
|
|
1619
|
+
} } : false
|
|
1620
|
+
].filter(Boolean),
|
|
1554
1621
|
schema: builtSchema(),
|
|
1555
1622
|
context
|
|
1556
1623
|
});
|