@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/client.cjs.map +1 -1
- package/out/client.mjs.map +1 -1
- package/out/index.cjs +232 -4
- package/out/index.cjs.map +1 -1
- package/out/index.d.cts +41 -78
- package/out/index.d.cts.map +1 -1
- package/out/index.d.mts +41 -78
- package/out/index.d.mts.map +1 -1
- package/out/index.mjs +232 -4
- package/out/index.mjs.map +1 -1
- package/package.json +18 -17
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.
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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
|