@m1212e/rumble 0.16.15 → 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 CHANGED
@@ -31,6 +31,7 @@ const require_generate = require('./generate-9zSO5f7n.cjs');
31
31
  let graphql = require("graphql");
32
32
  let _escape_tech_graphql_armor = require("@escape.tech/graphql-armor");
33
33
  let _graphql_yoga_plugin_disable_introspection = require("@graphql-yoga/plugin-disable-introspection");
34
+ let _pothos_tracing_opentelemetry = require("@pothos/tracing-opentelemetry");
34
35
  let es_toolkit = require("es-toolkit");
35
36
  let graphql_yoga = require("graphql-yoga");
36
37
  let sofa_api = require("sofa-api");
@@ -47,6 +48,8 @@ let _pothos_plugin_drizzle = require("@pothos/plugin-drizzle");
47
48
  _pothos_plugin_drizzle = __toESM(_pothos_plugin_drizzle);
48
49
  let _pothos_plugin_smart_subscriptions = require("@pothos/plugin-smart-subscriptions");
49
50
  _pothos_plugin_smart_subscriptions = __toESM(_pothos_plugin_smart_subscriptions);
51
+ let _pothos_plugin_tracing = require("@pothos/plugin-tracing");
52
+ _pothos_plugin_tracing = __toESM(_pothos_plugin_tracing);
50
53
  let graphql_scalars = require("graphql-scalars");
51
54
 
52
55
  //#region lib/types/rumbleError.ts
@@ -374,7 +377,7 @@ Warning! No abilities have been registered for
374
377
  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.
375
378
  `);
376
379
  }, 1e3);
377
- const createAbilityBuilder = ({ db, actions, defaultLimit }) => {
380
+ const createAbilityBuilder = ({ db, actions, defaultLimit, otel }) => {
378
381
  let hasBeenBuilt = false;
379
382
  const createBuilderForTable = () => {
380
383
  const queryFilters = /* @__PURE__ */ new Map();
@@ -506,27 +509,49 @@ const createAbilityBuilder = ({ db, actions, defaultLimit }) => {
506
509
  }
507
510
  return { withContext: (userContext) => {
508
511
  return { filter: (action) => {
509
- const filters = queryFilters.get(action);
510
- if (filters === "unrestricted") return transformToResponse();
511
- if (!filters) {
512
- nothingRegisteredWarningLogger(tableName.toString(), action);
513
- return transformToResponse(blockEverythingFilter);
514
- }
515
- const dynamicResults = new Array(dynamicQueryFilters[action].length);
516
- let filtersReturned = 0;
517
- for (let i = 0; i < dynamicQueryFilters[action].length; i++) {
518
- const func = dynamicQueryFilters[action][i];
519
- const result = func(userContext);
520
- if (result === "allow") return transformToResponse();
521
- if (result === void 0) continue;
522
- dynamicResults[filtersReturned++] = result;
523
- }
524
- dynamicResults.length = filtersReturned;
525
- const allQueryFilters = [...simpleQueryFilters[action], ...dynamicResults];
526
- if (allQueryFilters.length === 0) return transformToResponse(blockEverythingFilter);
527
- return transformToResponse(allQueryFilters.length === 1 ? allQueryFilters[0] : allQueryFilters.reduce((a, b) => {
528
- return mergeFilters(a, b);
529
- }, {}));
512
+ const assembleAbilities = (span) => {
513
+ const filters = queryFilters.get(action);
514
+ if (filters === "unrestricted") {
515
+ span?.setAttribute("abilities.status", "unrestricted");
516
+ return transformToResponse();
517
+ }
518
+ if (!filters) {
519
+ span?.setAttribute("abilities.status", "blocked_everything");
520
+ nothingRegisteredWarningLogger(tableName.toString(), action);
521
+ return transformToResponse(blockEverythingFilter);
522
+ }
523
+ const dynamicResults = new Array(dynamicQueryFilters[action].length);
524
+ let filtersReturned = 0;
525
+ for (let i = 0; i < dynamicQueryFilters[action].length; i++) {
526
+ const func = dynamicQueryFilters[action][i];
527
+ const result = func(userContext);
528
+ if (result === "allow") return transformToResponse();
529
+ if (result === void 0) continue;
530
+ dynamicResults[filtersReturned++] = result;
531
+ }
532
+ dynamicResults.length = filtersReturned;
533
+ span?.setAttribute("abilities.dynamic", dynamicResults.length);
534
+ span?.setAttribute("abilities.static", simpleQueryFilters[action].length);
535
+ const allQueryFilters = [...simpleQueryFilters[action], ...dynamicResults];
536
+ span?.setAttribute("abilities.total", allQueryFilters.length);
537
+ if (allQueryFilters.length === 0) {
538
+ span?.setAttribute("abilities.status", "blocked_everything");
539
+ return transformToResponse(blockEverythingFilter);
540
+ }
541
+ const mergedFilters = allQueryFilters.length === 1 ? allQueryFilters[0] : allQueryFilters.reduce((a, b) => {
542
+ return mergeFilters(a, b);
543
+ }, {});
544
+ span?.setAttribute("abilities.status", "applied");
545
+ return transformToResponse(mergedFilters);
546
+ };
547
+ if (otel?.tracer) return otel.tracer.startActiveSpan(`prepare_query_abilities_${action}`, (span) => {
548
+ try {
549
+ return assembleAbilities(span);
550
+ } finally {
551
+ span.end();
552
+ }
553
+ });
554
+ else return assembleAbilities();
530
555
  } };
531
556
  } };
532
557
  };
@@ -949,6 +974,10 @@ async function initSearchIfApplicable(input) {
949
974
  const dbName = (await input.db.execute(drizzle_orm.sql`SELECT current_database()`)).rows[0].current_database;
950
975
  await input.db.execute(drizzle_orm.sql.raw(`ALTER DATABASE ${dbName} SET pg_trgm.similarity_threshold = ${threshold};`));
951
976
  }
977
+ if (input.search?.cpu_operator_cost) {
978
+ if (typeof input.search.cpu_operator_cost !== "number") throw new Error(`CPU operator cost must be a number`);
979
+ if (input.search.cpu_operator_cost <= 0) throw new Error(`CPU operator cost must be a positive number`);
980
+ }
952
981
  }
953
982
  /**
954
983
  * Performs adjustments to the query args to issue a full text search in case the
@@ -1274,8 +1303,8 @@ const createQueryImplementer = ({ db, schemaBuilder, search, whereArgImplementer
1274
1303
  if (mappedArgs.orderBy) filter.orderBy = mappedArgs.orderBy;
1275
1304
  const queryInstance = query(filter);
1276
1305
  if (filter.columns) queryInstance.columns = filter.columns;
1277
- if (search?.cpu_operator_cost) return db.transaction(async (tx) => {
1278
- if (isPostgresDB(tx)) await tx.execute(drizzle_orm.sql`SET LOCAL cpu_operator_cost = ${search.cpu_operator_cost};`);
1306
+ if (search?.enabled && args.search && args.search.length > 0 && search?.cpu_operator_cost) return db.transaction(async (tx) => {
1307
+ if (isPostgresDB(tx)) await tx.execute(drizzle_orm.sql.raw(`SET cpu_operator_cost = ${search.cpu_operator_cost};`));
1279
1308
  else console.info("Database dialect is not postgresql, cannot set cpu_operator_cost.");
1280
1309
  return tx.query[table].findMany(queryInstance);
1281
1310
  });
@@ -1427,22 +1456,43 @@ const applyFilters = async ({ filters, entities, context }) => {
1427
1456
  //#region lib/runtimeFiltersPlugin/runtimeFiltersPlugin.ts
1428
1457
  const applyFiltersKey = "applyFilters";
1429
1458
  var RuntimeFiltersPlugin = class extends _pothos_core.BasePlugin {
1459
+ tracer;
1460
+ onTypeConfig(typeConfig) {
1461
+ this.tracer = this.builder.options.otelTracer;
1462
+ return typeConfig;
1463
+ }
1430
1464
  wrapResolve(resolver, fieldConfig) {
1431
1465
  return async (parent, args, context, info) => {
1432
- let filters;
1433
- const fieldType = fieldConfig?.type;
1434
- if (fieldType.kind === "List") filters = fieldType.type?.ref.currentConfig.pothosOptions[applyFiltersKey];
1435
- else if (fieldType.kind === "Object") filters = fieldType.ref.currentConfig.pothosOptions[applyFiltersKey];
1436
- if (!filters || !Array.isArray(filters) || filters.length === 0) return resolver(parent, args, context, info);
1437
- const resolved = await resolver(parent, args, context, info);
1438
- const allResolvedValues = Array.isArray(resolved) ? resolved : [resolved];
1439
- const allowed = await applyFilters({
1440
- filters: Array.isArray(filters) ? filters : [filters],
1441
- entities: allResolvedValues,
1442
- context
1466
+ const runFilters = async (span) => {
1467
+ let filters;
1468
+ const fieldType = fieldConfig?.type;
1469
+ if (fieldType.kind === "List") filters = fieldType.type?.ref.currentConfig.pothosOptions[applyFiltersKey];
1470
+ else if (fieldType.kind === "Object") filters = fieldType.ref.currentConfig.pothosOptions[applyFiltersKey];
1471
+ if (!filters || !Array.isArray(filters) || filters.length === 0) {
1472
+ span?.setAttribute("filters.status", "unrestricted");
1473
+ return resolver(parent, args, context, info);
1474
+ }
1475
+ const resolved = await resolver(parent, args, context, info);
1476
+ const allResolvedValues = Array.isArray(resolved) ? resolved : [resolved];
1477
+ const allFilters = Array.isArray(filters) ? filters : [filters];
1478
+ span?.setAttribute("filters.total", allFilters.length);
1479
+ const allowed = await applyFilters({
1480
+ filters: allFilters,
1481
+ entities: allResolvedValues,
1482
+ context
1483
+ });
1484
+ span?.setAttribute("filters.allowed", allowed.length);
1485
+ if (Array.isArray(resolved)) return allowed;
1486
+ return allowed[0] ?? null;
1487
+ };
1488
+ if (this.tracer) return this.tracer.startActiveSpan(`apply_filters_${fieldConfig.name}`, async (span) => {
1489
+ try {
1490
+ return await runFilters();
1491
+ } finally {
1492
+ span.end();
1493
+ }
1443
1494
  });
1444
- if (Array.isArray(resolved)) return allowed;
1445
- return allowed[0] ?? null;
1495
+ else return runFilters();
1446
1496
  };
1447
1497
  }
1448
1498
  };
@@ -1456,7 +1506,8 @@ function registerRuntimeFiltersPlugin() {
1456
1506
 
1457
1507
  //#endregion
1458
1508
  //#region lib/schemaBuilder.ts
1459
- const createSchemaBuilder = ({ db, disableDefaultObjects, pubsub, pothosConfig }) => {
1509
+ const createSchemaBuilder = ({ db, disableDefaultObjects, pubsub, pothosConfig, otel }) => {
1510
+ const createSpan = otel?.tracer ? (0, _pothos_tracing_opentelemetry.createOpenTelemetryWrapper)(otel.tracer, otel.options) : void 0;
1460
1511
  registerRuntimeFiltersPlugin();
1461
1512
  const schemaBuilder = new _pothos_core.default({
1462
1513
  ...pothosConfig,
@@ -1464,6 +1515,7 @@ const createSchemaBuilder = ({ db, disableDefaultObjects, pubsub, pothosConfig }
1464
1515
  pluginName,
1465
1516
  _pothos_plugin_drizzle.default,
1466
1517
  _pothos_plugin_smart_subscriptions.default,
1518
+ _pothos_plugin_tracing.default,
1467
1519
  ...pothosConfig?.plugins ?? []
1468
1520
  ],
1469
1521
  drizzle: {
@@ -1479,7 +1531,12 @@ const createSchemaBuilder = ({ db, disableDefaultObjects, pubsub, pothosConfig }
1479
1531
  smartSubscriptions: { ...(0, _pothos_plugin_smart_subscriptions.subscribeOptionsFromIterator)((name, _context) => {
1480
1532
  return pubsub.subscribe(name);
1481
1533
  }) },
1482
- defaultFieldNullability: false
1534
+ defaultFieldNullability: false,
1535
+ tracing: {
1536
+ default: otel?.tracer ? (config) => (0, _pothos_plugin_tracing.isRootField)(config) : () => false,
1537
+ wrap: createSpan ? (resolver, options) => createSpan(resolver, options) : (resolver) => resolver
1538
+ },
1539
+ otelTracer: otel?.tracer
1483
1540
  });
1484
1541
  schemaBuilder.addScalarType("JSON", graphql_scalars.JSONResolver);
1485
1542
  schemaBuilder.addScalarType("Date", graphql_scalars.DateResolver);
@@ -1515,7 +1572,7 @@ export const db = drizzle(
1515
1572
  "postgres://postgres:postgres@localhost:5432/postgres",
1516
1573
  {
1517
1574
  relations, // <--- add this line
1518
- schema,
1575
+ schema,
1519
1576
  },
1520
1577
  );
1521
1578
 
@@ -1578,7 +1635,22 @@ export const db = drizzle(
1578
1635
  return (0, graphql_yoga.createYoga)({
1579
1636
  ...args,
1580
1637
  graphiql: enableApiDocs,
1581
- plugins: [...args?.plugins ?? [], ...enableApiDocs ? [] : [(0, _graphql_yoga_plugin_disable_introspection.useDisableIntrospection)(), (0, _escape_tech_graphql_armor.EnvelopArmorPlugin)()]].filter(Boolean),
1638
+ plugins: [
1639
+ ...args?.plugins ?? [],
1640
+ ...enableApiDocs ? [] : [(0, _graphql_yoga_plugin_disable_introspection.useDisableIntrospection)(), (0, _escape_tech_graphql_armor.EnvelopArmorPlugin)()],
1641
+ rumbleInput.otel?.tracer ? { onExecute: ({ setExecuteFn, executeFn }) => {
1642
+ setExecuteFn((options) => rumbleInput.otel.tracer.startActiveSpan(_pothos_tracing_opentelemetry.SpanNames.EXECUTE, { attributes: { [_pothos_tracing_opentelemetry.AttributeNames.OPERATION_NAME]: options.operationName ?? "anonymous" } }, async (span) => {
1643
+ try {
1644
+ return await executeFn(options);
1645
+ } catch (error) {
1646
+ span.recordException(error);
1647
+ throw error;
1648
+ } finally {
1649
+ span.end();
1650
+ }
1651
+ }));
1652
+ } } : false
1653
+ ].filter(Boolean),
1582
1654
  schema: builtSchema(),
1583
1655
  context
1584
1656
  });