@m1212e/rumble 0.16.42 → 0.17.0

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.mjs CHANGED
@@ -181,7 +181,7 @@ function mapNullFieldsToUndefined(obj) {
181
181
  }
182
182
  //#endregion
183
183
  //#region package.json
184
- var version = "0.16.42";
184
+ var version = "0.17.0";
185
185
  //#endregion
186
186
  //#region lib/helpers/mergeFilters.ts
187
187
  function mergeFilters(filterA, filterB) {
@@ -347,6 +347,9 @@ const createAbilityBuilder = ({ db, actions, defaultLimit, otel }) => {
347
347
  const runtimeFilters = /* @__PURE__ */ new Map();
348
348
  for (const action of actions) if (!runtimeFilters.has(action)) runtimeFilters.set(action, []);
349
349
  return {
350
+ /**
351
+ * Allows to perform a specific action on a specific entity
352
+ */
350
353
  allow: (action) => {
351
354
  if (hasBeenBuilt) throw new RumbleError("You can't call allow() after the ability builder has been built. Please ensure that you register all abilities before accessing them.");
352
355
  const actions = Array.isArray(action) ? action : [action];
@@ -357,24 +360,58 @@ const createAbilityBuilder = ({ db, actions, defaultLimit, otel }) => {
357
360
  queryFilters.set(action, filters);
358
361
  }
359
362
  }
360
- return { when: (queryFilter) => {
363
+ return {
364
+ /**
365
+ * Restricts the allowed actions to a filter
366
+ * @example
367
+ * ```ts
368
+ * abilityBuilder.users.allow(["read", "update", "delete"]).when(({ userId }) => ({
369
+ * where: {
370
+ * id: userId,
371
+ * },
372
+ * }));
373
+ * ```
374
+ */
375
+ when: (queryFilter) => {
361
376
  for (const action of actions) {
362
377
  if (queryFilters.get(action) === "unrestricted") queryFilters.set(action, []);
363
378
  queryFilters.get(action).push(queryFilter);
364
379
  }
365
380
  } };
366
381
  },
382
+ /**
383
+ * Allows to register an application level filter to restrict some results
384
+ * which were returned by a query
385
+ */
367
386
  filter: (action) => {
368
387
  const actions = Array.isArray(action) ? action : [action];
369
388
  return {
389
+ /**
390
+ * Allows to register an application level prefetch to fetch some data
391
+ * which could be useful for later filtering the results. The prefetch
392
+ * function will be called with the user context but unlike the actual
393
+ * filter function, it will not have access to the result of the query
394
+ * and therefore can be run in parallel with underlying query resolver.
395
+ * A typical use case is to fetch some data which is not directly
396
+ * related to the query but to the context only. So e.g. fetching the
397
+ * user's permissions from an external system and then later applying
398
+ * the filter based on those permissions.
399
+ */
370
400
  prefetch: (prefetch) => {
371
- return { by: (explicitFilter) => {
401
+ return {
402
+ /**
403
+ * The actual filter function to apply. Returns the allowed values
404
+ */
405
+ by: (explicitFilter) => {
372
406
  for (const action of actions) runtimeFilters.get(action).push({
373
407
  filter: explicitFilter,
374
408
  prefetch
375
409
  });
376
410
  } };
377
411
  },
412
+ /**
413
+ * The actual filter function to apply. Returns the allowed values
414
+ */
378
415
  by: (explicitFilter) => {
379
416
  for (const action of actions) runtimeFilters.get(action).push({ filter: explicitFilter });
380
417
  }
@@ -389,6 +426,10 @@ const createAbilityBuilder = ({ db, actions, defaultLimit, otel }) => {
389
426
  const buildersPerTable = Object.fromEntries(Object.keys(db.query).map((tableName) => [tableName, createBuilderForTable()]));
390
427
  return {
391
428
  ...buildersPerTable,
429
+ /**
430
+ * @internal
431
+ * @ignore
432
+ */
392
433
  _: {
393
434
  registeredFilters({ action, table }) {
394
435
  return buildersPerTable[table]._.runtimeFilters.get(action);
@@ -433,12 +474,27 @@ const createAbilityBuilder = ({ db, actions, defaultLimit, otel }) => {
433
474
  return filters?.where ? relationsFilterToSQL(tableSchema.foundRelation.table, filters.where, tableSchema.relations, db._.relations, casing) : void 0;
434
475
  });
435
476
  if (filters?.columns) return {
477
+ /**
478
+ * Query filters for the drizzle query API.
479
+ * @example
480
+ * ```ts
481
+ * author: t.relation("author", {
482
+ * query: (_args, ctx) => ctx.abilities.users.filter("read").query.single,
483
+ * }),
484
+ * ´´´
485
+ */
436
486
  query: {
487
+ /**
488
+ * For find first calls
489
+ */
437
490
  single: {
438
491
  extras: filters?.extras,
439
492
  where: filters?.where,
440
493
  columns: filters?.columns
441
494
  },
495
+ /**
496
+ * For find many calls
497
+ */
442
498
  many: {
443
499
  extras: filters?.extras,
444
500
  where: filters?.where,
@@ -448,16 +504,50 @@ const createAbilityBuilder = ({ db, actions, defaultLimit, otel }) => {
448
504
  }
449
505
  }
450
506
  },
507
+ /**
508
+ * Query filters for the drizzle SQL API as used in e.g. updates.
509
+ * @example
510
+ *
511
+ * ```ts
512
+ * await db
513
+ * .update(schema.users)
514
+ * .set({
515
+ * name: args.newName,
516
+ * })
517
+ * .where(
518
+ * and(
519
+ * eq(schema.users.id, args.userId),
520
+ * ctx.abilities.users.filter("update").sql.where,
521
+ * ),
522
+ * );
523
+ * ```
524
+ *
525
+ */
451
526
  sql: { get where() {
452
527
  return sqlTransformedWhere();
453
528
  } }
454
529
  };
455
530
  else return {
531
+ /**
532
+ * Query filters for the drizzle query API.
533
+ * @example
534
+ * ```ts
535
+ * author: t.relation("author", {
536
+ * query: (_args, ctx) => ctx.abilities.users.filter("read").query.single,
537
+ * }),
538
+ * ´´´
539
+ */
456
540
  query: {
541
+ /**
542
+ * For find first calls
543
+ */
457
544
  single: {
458
545
  extras: filters?.extras,
459
546
  where: filters?.where
460
547
  },
548
+ /**
549
+ * For find many calls
550
+ */
461
551
  many: {
462
552
  extras: filters?.extras,
463
553
  where: filters?.where,
@@ -466,6 +556,25 @@ const createAbilityBuilder = ({ db, actions, defaultLimit, otel }) => {
466
556
  }
467
557
  }
468
558
  },
559
+ /**
560
+ * Query filters for the drizzle SQL API as used in e.g. updates.
561
+ * @example
562
+ *
563
+ * ```ts
564
+ * await db
565
+ * .update(schema.users)
566
+ * .set({
567
+ * name: args.newName,
568
+ * })
569
+ * .where(
570
+ * and(
571
+ * eq(schema.users.id, args.userId),
572
+ * ctx.abilities.users.filter("update").sql.where,
573
+ * ),
574
+ * );
575
+ * ```
576
+ *
577
+ */
469
578
  sql: { get where() {
470
579
  return sqlTransformedWhere();
471
580
  } }
@@ -1173,6 +1282,9 @@ const createPubSubInstance = ({ subscriptions }) => {
1173
1282
  return `${SUBSCRIPTION_NOTIFIER_RUMBLE_PREFIX}/${tableName}${primaryKeyValue ? `/${primaryKeyValue}` : ""}/${actionKey}`;
1174
1283
  }
1175
1284
  return {
1285
+ /**
1286
+ * Call this when you want to register a subscription on an instance to this table
1287
+ */
1176
1288
  registerOnInstance({ instance, action, primaryKeyValue }) {
1177
1289
  const key = makePubSubKey({
1178
1290
  tableName: table.toString(),
@@ -1181,6 +1293,9 @@ const createPubSubInstance = ({ subscriptions }) => {
1181
1293
  });
1182
1294
  instance.register(key);
1183
1295
  },
1296
+ /**
1297
+ * Call this when you created an entity of this table
1298
+ */
1184
1299
  created() {
1185
1300
  const key = makePubSubKey({
1186
1301
  tableName: table.toString(),
@@ -1188,6 +1303,9 @@ const createPubSubInstance = ({ subscriptions }) => {
1188
1303
  });
1189
1304
  return pubsub.publish(key);
1190
1305
  },
1306
+ /**
1307
+ * Call this when you removed one or more entities of this table
1308
+ */
1191
1309
  removed() {
1192
1310
  const key = makePubSubKey({
1193
1311
  tableName: table.toString(),
@@ -1195,6 +1313,9 @@ const createPubSubInstance = ({ subscriptions }) => {
1195
1313
  });
1196
1314
  return pubsub.publish(key);
1197
1315
  },
1316
+ /**
1317
+ * Call this when you updated one or more entities of this table
1318
+ */
1198
1319
  updated(primaryKeyValue) {
1199
1320
  const keys = (Array.isArray(primaryKeyValue) ? primaryKeyValue : [primaryKeyValue]).map((primaryKeyValue) => makePubSubKey({
1200
1321
  tableName: table.toString(),
@@ -1653,22 +1774,129 @@ export const db = drizzle(
1653
1774
  }
1654
1775
  });
1655
1776
  };
1777
+ const createWs = (implementation, args, ...rest) => {
1778
+ return implementation({
1779
+ ...args,
1780
+ schema: builtSchema(),
1781
+ context
1782
+ }, ...rest);
1783
+ };
1656
1784
  return {
1785
+ /**
1786
+ * The ability builder. Use it to declare whats allowed for each entity in your DB.
1787
+ *
1788
+ * @example
1789
+ *
1790
+ * ```ts
1791
+ * // users can edit themselves
1792
+ abilityBuilder.users
1793
+ .allow(["read", "update", "delete"])
1794
+ .when(({ userId }) => ({ where: eq(schema.users.id, userId) }));
1795
+
1796
+ // everyone can read posts
1797
+ abilityBuilder.posts.allow("read");
1798
+ *
1799
+ * ```
1800
+ */
1657
1801
  abilityBuilder,
1802
+ /**
1803
+ * The pothos schema builder. See https://pothos-graphql.dev/docs/plugins/drizzle
1804
+ */
1658
1805
  schemaBuilder,
1806
+ /**
1807
+ * Creates the native yoga instance. Can be used to run an actual HTTP server.
1808
+ *
1809
+ * @example
1810
+ *
1811
+ * ```ts
1812
+ * import { createServer } from "node:http";
1813
+ * const server = createServer(createYoga());
1814
+ * server.listen(3000, () => {
1815
+ * console.info("Visit http://localhost:3000/graphql");
1816
+ * });
1817
+ * ```
1818
+ * https://the-guild.dev/graphql/yoga-server/docs#server
1819
+ */
1659
1820
  createYoga: createYoga$1,
1821
+ /**
1822
+ * Creates a sofa instance to offer a REST API.
1823
+ *
1824
+ * ```ts
1825
+ * import express from "express";
1826
+ *
1827
+ * const app = express();
1828
+ * const sofa = createSofa(...);
1829
+ *
1830
+ * app.use("/api", useSofa({ schema }));
1831
+ * ```
1832
+ * https://the-guild.dev/graphql/sofa-api/docs#usage
1833
+ */
1660
1834
  createSofa,
1835
+ /**
1836
+ * Creates a WebSocket server handler for GraphQL subscriptions.
1837
+ * Pass the ws implementation function as the first argument and rumble will
1838
+ * inject the schema and context automatically.
1839
+ *
1840
+ * @example
1841
+ *
1842
+ * ```ts
1843
+ * // ws
1844
+ * import { useServer } from "graphql-ws/use/ws";
1845
+ * import { WebSocketServer } from "ws";
1846
+ * const wss = new WebSocketServer({ port: 4000 });
1847
+ * const disposable = createWs(useServer, { ... }, wss);
1848
+ *
1849
+ * // bun
1850
+ * import { makeHandler } from "graphql-ws/use/bun";
1851
+ * Bun.serve({ websocket: createWs(makeHandler, { ... }), ... });
1852
+ * ```
1853
+ */
1854
+ createWs,
1855
+ /**
1856
+ * A function for creating default objects for your schema
1857
+ */
1661
1858
  object,
1859
+ /**
1860
+ * A function for creating where args to filter entities
1861
+ */
1662
1862
  whereArg,
1863
+ /**
1864
+ * A function for creating order args to sort entities
1865
+ */
1663
1866
  orderArg,
1867
+ /**
1868
+ * A function for creating default READ queries.
1869
+ * Make sure the objects for the table you are creating the queries for are implemented
1870
+ */
1664
1871
  query,
1872
+ /**
1873
+ * A function for creating a pubsub instance for a table. Use this to publish or subscribe events
1874
+ */
1665
1875
  pubsub: makePubSubInstance,
1876
+ /**
1877
+ * A function to implement enums for graphql usage.
1878
+ * The other helpers use this helper internally so in most cases you do not have to
1879
+ * call this helper directly, unless you need the reference to an enum type
1880
+ */
1666
1881
  enum_,
1882
+ /**
1883
+ * Create a client to consume a rumble graphql api at the specified location.
1884
+ * Requires GraphQL, does not work with the SOFA REST API.
1885
+ */
1667
1886
  clientCreator: clientCreatorImplementer({
1668
1887
  ...rumbleInput,
1669
1888
  builtSchema
1670
1889
  }),
1671
- countQuery
1890
+ /**
1891
+ * A function for creating count queries for your tables
1892
+ */
1893
+ countQuery,
1894
+ /**
1895
+ * The generated GraphQL schema. You can use this for example to create a GraphQL server with a different library than Yoga or to generate types with codegen.
1896
+ * When calling this function, the schema will be built for the first time and cached for later usage. So you can call this function multiple times without performance issues.
1897
+ * After calling, you cannot adjust the schema via the schema builder
1898
+ */
1899
+ buildSchema: builtSchema
1672
1900
  };
1673
1901
  };
1674
1902
  //#endregion