@noxify/casl-drizzle 0.0.1-beta.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Guilherme Araújo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ > work in progress :)
2
+
3
+ # casl-drizzle
4
+
5
+ CASL integration for Drizzle ORM - Add type-safe authorization to your database queries
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install ucastle @casl/ability
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ Define your abilities using Drizzle's query types directly:
16
+
17
+ ```typescript
18
+ import type { QueryInput } from "ucastle"
19
+ import { integer, pgTable, text } from "drizzle-orm/pg-core"
20
+ import { accessibleBy, defineAbility } from "ucastle"
21
+
22
+ // Define your Drizzle schema
23
+ const users = pgTable("users", {
24
+ id: integer().primaryKey(),
25
+ name: text().notNull(),
26
+ email: text().notNull(),
27
+ })
28
+
29
+ const schema = { users }
30
+
31
+ // Extract query types for your tables
32
+ type UserQuery = QueryInput<typeof schema, "users">
33
+
34
+ // Create abilities with subject-specific autocomplete
35
+ const ability = defineAbility<{ users: UserQuery }>((can, cannot) => {
36
+ can("read", "users", { id: 1 }) // ✅ Autocomplete shows only user fields!
37
+ can("update", "users", { id: 1 })
38
+ cannot("delete", "users")
39
+ })
40
+
41
+ // Use with accessibleBy to get database filters
42
+ const filters = accessibleBy(ability, "read")
43
+ const readableUsers = await db.query.users.findMany({ where: filters.users })
44
+ ```
45
+
46
+ ## Features
47
+
48
+ - 🔒 **Type-safe authorization** - Full TypeScript support with Drizzle types
49
+ - 🎯 **CASL integration** - Leverage CASL's powerful rule system
50
+ - 🗄️ **DB agnostic** - Works with PostgreSQL, MySQL, SQLite, etc.
51
+ - 🔗 **Relation support** - Filter by related table conditions
52
+ - 📦 **Zero overhead** - Direct type composition, no runtime wrappers
53
+ - 💡 **Smart autocomplete** - Subject-specific field suggestions with `defineAbility()`
54
+
55
+ ## With Relations
56
+
57
+ For schemas with relations, use `RelationalQueryInput`:
58
+
59
+ ```typescript
60
+ import type { RelationalQueryInput } from "ucastle"
61
+ import { defineRelations } from "drizzle-orm"
62
+
63
+ const posts = pgTable("posts", {
64
+ id: integer().primaryKey(),
65
+ title: text().notNull(),
66
+ authorId: integer().notNull(),
67
+ })
68
+
69
+ const relations = defineRelations({ users, posts }, (r) => ({
70
+ users: { posts: r.many(posts) },
71
+ posts: { author: r.one(users, { fields: [posts.authorId], references: [users.id] }) },
72
+ }))
73
+
74
+ type PostQuery = RelationalQueryInput<typeof relations, "posts">
75
+
76
+ const ability = defineAbility<{ posts: PostQuery }>((can) => {
77
+ can("read", "posts", { published: true })
78
+ can("update", "posts", { authorId: 1 })
79
+ })
80
+ ```
81
+
82
+ ## Alternative: AbilityBuilder
83
+
84
+ If you prefer the traditional AbilityBuilder pattern:
85
+
86
+ ```typescript
87
+ import type { DefineAbility } from "ucastle"
88
+ import { AbilityBuilder } from "@casl/ability"
89
+ import { createDrizzleAbilityFor } from "ucastle"
90
+
91
+ type AppAbility = DefineAbility<{ users: UserQuery }>
92
+
93
+ const { can, cannot, build } = new AbilityBuilder<AppAbility>(createDrizzleAbilityFor())
94
+
95
+ can("read", "users", { id: 1 })
96
+ cannot("delete", "users")
97
+
98
+ const ability = build()
99
+ ```
100
+
101
+ ## Documentation
102
+
103
+ See [SIMPLIFIED_API.md](./SIMPLIFIED_API.md) for detailed examples and patterns.
104
+
105
+ ## License
106
+
107
+ MIT
@@ -0,0 +1,214 @@
1
+ import { AbilityOptions, AbilityOptionsOf, AbilityTuple, AnyAbility, ForcedSubject, PureAbility, RawRuleFrom, RawRuleOf, hkt } from "@casl/ability";
2
+ import * as _ucast_core0 from "@ucast/core";
3
+ import { DBQueryConfig, SchemaEntry, TablesRelationalConfig } from "drizzle-orm/relations";
4
+ import { KnownKeysOnly } from "drizzle-orm/utils";
5
+
6
+ //#region src/drizzle-query.d.ts
7
+ declare const drizzleQuery: (query: Record<string, unknown>, ...args: unknown[]) => {
8
+ (...args: any[]): any;
9
+ ast: _ucast_core0.Condition;
10
+ };
11
+ type Model<T, TName extends string> = T & ForcedSubject<TName>;
12
+ type Subjects<T extends Partial<Record<string, Record<string, unknown>>>> = keyof T | { [K in keyof T]: Model<T[K], K & string> }[keyof T];
13
+ /**
14
+ * Extracts Drizzle model name from given object and possible list of all subjects
15
+ */
16
+ type ExtractModelName<TObject, TModelName extends PropertyKey> = TObject extends {
17
+ kind: TModelName;
18
+ } ? TObject["kind"] : TObject extends ForcedSubject<TModelName> ? TObject["__caslSubjectType__"] : TObject extends {
19
+ __typename: TModelName;
20
+ } ? TObject["__typename"] : TModelName;
21
+ //#endregion
22
+ //#region src/types.d.ts
23
+ interface BaseDrizzleQuery {
24
+ [ɵdrizzleTypes]?: Record<string, unknown>;
25
+ }
26
+ declare const ɵdrizzleTypes: unique symbol;
27
+ type DrizzleQueryFactory = Record<string, unknown> & hkt.Container<hkt.GenericFactory> & BaseDrizzleQuery;
28
+ type DrizzleModel = Model<Record<string, unknown>, string>;
29
+ type WhereInput = Record<string, unknown>;
30
+ /**
31
+ * Utility type to recursively remove the RAW property from Drizzle query types.
32
+ * RAW is used internally by Drizzle for SQL functions but shouldn't be exposed in our API.
33
+ */
34
+ type OmitRaw<T> = T extends object ? { [K in keyof T as K extends "RAW" ? never : K]: T[K] extends object ? T[K] extends any[] ? OmitRaw<T[K][number]>[] : OmitRaw<T[K]> : T[K] } : T;
35
+ /**
36
+ * Query input for tables WITH relations.
37
+ * Extracts the complete where type including relation filters from Drizzle's DBQueryConfig.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * import { defineRelations } from "drizzle-orm"
42
+ * import type { RelationalQueryInput } from "ucastle"
43
+ *
44
+ * const relations = defineRelations({ users, posts }, ...)
45
+ * type UserQuery = RelationalQueryInput<typeof relations, "users">
46
+ *
47
+ * // Now includes: field conditions + relation filters + AND/OR/NOT
48
+ * ```
49
+ */
50
+ type RelationalQueryInput<TSchema extends TablesRelationalConfig, TTableName extends keyof TSchema> = OmitRaw<Exclude<KnownKeysOnly<DBQueryConfig<"many", TSchema, TSchema[TTableName]>, DBQueryConfig<"many", TSchema, TSchema[TTableName]>>["where"], undefined>>;
51
+ /**
52
+ * Query input for tables WITHOUT relations.
53
+ * Supports both field conditions and compound operators (AND/OR/NOT) at root level.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * import type { QueryInput } from "ucastle"
58
+ *
59
+ * const schema = { users, posts }
60
+ * type UserQuery = QueryInput<typeof schema, "users">
61
+ *
62
+ * // Field conditions
63
+ * const q1: UserQuery = { id: 1, name: "John" }
64
+ *
65
+ * // With operators
66
+ * const q2: UserQuery = { id: { gte: 1 }, AND: [{ name: "John" }] }
67
+ *
68
+ * // Compound operators
69
+ * const q3: UserQuery = { OR: [{ age: 18 }, { role: "admin" }] }
70
+ * ```
71
+ */
72
+ type QueryInput<TSchema extends Record<string, SchemaEntry>, TTableName extends keyof TSchema> = OmitRaw<{ [K in keyof (TSchema[TTableName] extends {
73
+ $inferSelect: infer S;
74
+ } ? S : never)]?: any } & {
75
+ AND?: QueryInput<TSchema, TTableName>[];
76
+ OR?: QueryInput<TSchema, TTableName>[];
77
+ NOT?: QueryInput<TSchema, TTableName>;
78
+ }>;
79
+ /**
80
+ * Helper type to create CASL subjects from a mapping of table names to query types.
81
+ * Similar to @casl/prisma's Subjects pattern.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * import { PureAbility } from "@casl/ability"
86
+ * import type { RelationalQueryInput, Subjects } from "ucastle"
87
+ *
88
+ * type UserQuery = RelationalQueryInput<typeof relations, "users">
89
+ * type PostQuery = RelationalQueryInput<typeof relations, "posts">
90
+ *
91
+ * type AppAbility = PureAbility<[string, Subjects<{
92
+ * users: UserQuery,
93
+ * posts: PostQuery
94
+ * }>]>
95
+ * ```
96
+ */
97
+ type Subjects$1<T> = { [K in keyof T]: Model<T[K], K & string> }[keyof T] | Extract<keyof T, string>;
98
+ /**
99
+ * Custom Ability type with subject-specific conditions.
100
+ * Similar to @casl/prisma's PrismaAbility.
101
+ *
102
+ * This type ensures that conditions are properly typed based on the subject mapping.
103
+ *
104
+ * @example
105
+ * ```ts
106
+ * import type { DrizzleAbility } from "ucastle"
107
+ *
108
+ * type SubjectMap = {
109
+ * users: UserQuery
110
+ * posts: PostQuery
111
+ * }
112
+ *
113
+ * type AppAbility = DrizzleAbility<SubjectMap>
114
+ * ```
115
+ */
116
+ type DrizzleAbility$1<T> = PureAbility<[string, Subjects$1<T>], T[keyof T]>;
117
+ /**
118
+ * Helper type to create a fully-typed DrizzleAbility from a subject mapping.
119
+ * Provides subject-specific autocomplete in `can()` and `cannot()` methods
120
+ * when used with `defineAbility()`.
121
+ * Works with both `type` and `interface`.
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * import { defineAbility, type DefineAbility } from "ucastle"
126
+ *
127
+ * // Works with type
128
+ * type SubjectMap = {
129
+ * users: UserQuery
130
+ * posts: PostQuery
131
+ * }
132
+ *
133
+ * // Also works with interface
134
+ * interface SubjectMap {
135
+ * users: UserQuery
136
+ * posts: PostQuery
137
+ * }
138
+ *
139
+ * // Use with defineAbility for subject-specific autocomplete:
140
+ * const ability = defineAbility<SubjectMap>((can, cannot) => {
141
+ * can("read", "users", { id: 1 }) // ✅ Only user fields!
142
+ * can("read", "posts", { authorId: 1 }) // ✅ Only post fields!
143
+ * })
144
+ * ```
145
+ */
146
+ type DefineAbility<T> = DrizzleAbility$1<T>;
147
+ //#endregion
148
+ //#region src/factories/accessible-by.d.ts
149
+ /**
150
+ * @deprecated use accessibleBy directly instead. It will infer the types from passed Ability instance.
151
+ */
152
+ declare const createAccessibleByFactory: <TResult extends Record<string, unknown>, TDrizzleQuery>() => <TAbility extends PureAbility<any, TDrizzleQuery>>(ability: TAbility, action?: TAbility["rules"][number]["action"]) => TResult;
153
+ declare function accessibleBy<TAbility extends PureAbility<any, any>>(ability: TAbility, action?: TAbility["rules"][number]["action"]): Record<string, WhereInput>;
154
+ //#endregion
155
+ //#region src/factories/create-ability.d.ts
156
+ declare function createAbilityFactory<TModelName extends string, TDrizzleQuery extends Record<string, any>>(): {
157
+ <T extends PureAbility<any, TDrizzleQuery>>(rules?: RawRuleOf<T>[], options?: AbilityOptionsOf<T>): T;
158
+ <A extends AbilityTuple = [string, TModelName], C extends TDrizzleQuery = TDrizzleQuery>(rules?: RawRuleFrom<A, C>[], options?: AbilityOptions<A, C>): PureAbility<A, C>;
159
+ };
160
+ //#endregion
161
+ //#region src/query-error.d.ts
162
+ declare class ParsingQueryError extends Error {
163
+ static invalidArgument(operatorName: string, value: unknown, expectValueType: string): ParsingQueryError;
164
+ }
165
+ //#endregion
166
+ //#region src/index.d.ts
167
+ /**
168
+ * Factory function to create a DrizzleAbility instance.
169
+ * Use with AbilityBuilder for type-safe ability definitions.
170
+ *
171
+ * @example
172
+ * ```ts
173
+ * import { AbilityBuilder } from "@casl/ability"
174
+ * import { createDrizzleAbilityFor, type DefineAbility } from "ucastle"
175
+ *
176
+ * type AppAbility = DefineAbility<{
177
+ * users: UserQuery
178
+ * posts: PostQuery
179
+ * }>
180
+ *
181
+ * const { can, build } = new AbilityBuilder<AppAbility>(createDrizzleAbilityFor())
182
+ * ```
183
+ */
184
+ declare function createDrizzleAbilityFor(): new (...args: ConstructorParameters<typeof PureAbility>) => AnyAbility;
185
+ /**
186
+ * Create a type-safe ability with subject-specific conditions.
187
+ * This provides better autocomplete than using AbilityBuilder directly.
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * import { defineAbility } from "ucastle"
192
+ *
193
+ * const ability = defineAbility<{
194
+ * users: UserQuery
195
+ * posts: PostQuery
196
+ * }>((can, cannot) => {
197
+ * can("read", "users", { id: 1 }) // ✅ Only user fields
198
+ * can("read", "posts", { authorId: 1 }) // ✅ Only post fields
199
+ * })
200
+ * ```
201
+ */
202
+ declare function defineAbility<T>(define: (can: <S extends keyof T & string>(action: string, subject: S, conditions?: T[S]) => void, cannot: <S extends keyof T & string>(action: string, subject: S, conditions?: T[S]) => void) => void): PureAbility<[string, any], T[keyof T]>;
203
+ /**
204
+ * Uses conditional type to support union distribution
205
+ */
206
+ type ExtendedAbilityTuple<T extends AbilityTuple> = T extends AbilityTuple ? [T[0], "all" | T[1]] : never;
207
+ /**
208
+ * @deprecated use createDrizzleAbilityFor instead
209
+ */
210
+ declare class DrizzleAbility<A extends AbilityTuple = [string, string], C extends Record<string, unknown> = Record<string, unknown>> extends PureAbility<ExtendedAbilityTuple<A>, C> {
211
+ constructor(rules?: RawRuleFrom<ExtendedAbilityTuple<A>, C>[], options?: AbilityOptions<ExtendedAbilityTuple<A>, C>);
212
+ }
213
+ //#endregion
214
+ export { type BaseDrizzleQuery, type DefineAbility, DrizzleAbility, type DrizzleModel, type DrizzleQueryFactory, type Subjects as DrizzleSubjects, type ExtractModelName, type Model, ParsingQueryError, type QueryInput, type RelationalQueryInput, type Subjects$1 as Subjects, type WhereInput, accessibleBy, createAbilityFactory, createAccessibleByFactory, createDrizzleAbilityFor, defineAbility, drizzleQuery };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ import{AbilityBuilder as e,ForbiddenError as t,PureAbility as n,fieldPatternMatcher as r}from"@casl/ability";import{CompoundCondition as i,FieldCondition as a,NULL_CONDITION as o,ObjectQueryParser as s,buildAnd as c,createTranslatorFactory as l}from"@ucast/core";import{and as u,compare as d,createJsInterpreter as f,eq as p,gt as m,gte as h,lt as ee,lte as te,ne as g,or as _,within as v}from"@ucast/js";import{rulesToQuery as y}from"@casl/ability/extra";const b=(e,t,{get:n})=>n(t,e.field).startsWith(e.value),x=(e,t,{get:n})=>n(t,e.field).toLowerCase().startsWith(e.value.toLowerCase()),ne=(e,t,{get:n})=>n(t,e.field).endsWith(e.value),S=(e,t,{get:n})=>n(t,e.field).toLowerCase().endsWith(e.value.toLowerCase()),C=(e,t,{get:n})=>n(t,e.field).includes(e.value),w=(e,t,{get:n})=>n(t,e.field).toLowerCase().includes(e.value.toLowerCase()),T=(e,t,{get:n})=>{let r=n(t,e.field);return(Array.isArray(r)&&r.length===0)===e.value},E=(e,t,{get:n})=>{let r=n(t,e.field);return Array.isArray(r)&&r.includes(e.value)},D=(e,t,{get:n})=>{let r=n(t,e.field);return Array.isArray(r)&&e.value.some(e=>r.includes(e))},O=(e,t,{get:n})=>{let r=n(t,e.field);return Array.isArray(r)&&e.value.every(e=>r.includes(e))},k=(e,t,{get:n,interpret:r})=>{let i=n(t,e.field);return Array.isArray(i)&&i.length>0&&i.every(t=>r(e.value,t))},A=(e,t,{get:n,interpret:r})=>{let i=n(t,e.field);return Array.isArray(i)&&i.some(t=>r(e.value,t))},j=(e,t,{get:n,interpret:r})=>{let i=n(t,e.field);return typeof i==`object`&&!!i&&r(e.value,i)},M=(e,t,{interpret:n})=>e.value.every(e=>!n(e,t)),N=(e,t,{get:n})=>n(t,e.field)!==void 0;function P(e){return e&&typeof e==`object`?e.valueOf():e}const F=f({equals:p,notEquals:g,in:v,lt:ee,lte:te,gt:m,gte:h,startsWith:b,istartsWith:x,endsWith:ne,iendsWith:S,contains:C,icontains:w,isEmpty:T,has:E,hasSome:D,hasEvery:O,and:u,or:_,AND:u,OR:_,NOT:M,every:k,some:A,is:j,isSet:N},{get:(e,t)=>e[t],compare:(e,t)=>d(P(e),P(t))});var I=class extends Error{static invalidArgument(e,t,n){let r=`${typeof t}(${JSON.stringify(t,null,2)})`;return new this(`"${e}" expects to receive ${n} but instead got "${r}"`)}};const L=e=>typeof e==`object`&&!!e&&(Object.getPrototypeOf(e)===Object.prototype||Object.getPrototypeOf(e)===null),re={type:`field`,validate(e,t){if(Array.isArray(t)||L(t))throw new I(`"${e.name}" does not supports comparison of arrays and objects`)}},R={type:`field`,parse:((e,t,{hasOperators:n,field:r,parse:o})=>{if(L(t)&&!n(t)||Array.isArray(t))throw new I(`"${e.name}" does not supports comparison of arrays and objects`);return L(t)?new i(`NOT`,[o(t,{field:r})]):new a(`notEquals`,r,t)})},z={type:`field`,validate(e,t){if(!Array.isArray(t))throw I.invalidArgument(e.name,t,`an array`)}},B={type:`field`,validate(e,t){let n=typeof t;if(!(n===`string`||n===`number`&&Number.isFinite(t)||t instanceof Date))throw I.invalidArgument(e.name,t,`comparable value`)}},V=new Set([`insensitive`,`default`]),H={type:`field`,validate(e,t){if(!V.has(t))throw I.invalidArgument(e.name,t,`one of ${Array.from(V).join(`, `)}`)},parse:()=>o},U={type:`field`,validate(e,t){if(typeof t!=`string`)throw I.invalidArgument(e.name,t,`string`)},parse(e,t,{query:n,field:r}){return new a(n.mode===`insensitive`?`i${e.name}`:e.name,r,t)}},W={type:`compound`,validate(e,t){if(!t||typeof t!=`object`)throw I.invalidArgument(e.name,t,`an array or object`)},parse(e,t,{parse:n}){let r=(Array.isArray(t)?t:[t]).map(e=>n(e));return new i(e.name,r)}},G={type:`field`,validate(e,t){if(typeof t!=`boolean`)throw I.invalidArgument(e.name,t,`a boolean`)}},K={type:`field`},q={type:`field`,validate(e,t){if(!Array.isArray(t))throw I.invalidArgument(e.name,t,`an array`)}},J={type:`field`,parse(e,t,{field:n,parse:r}){if(!L(t))throw I.invalidArgument(e.name,t,`a query for nested relation`);return new a(e.name,n,r(t))}},Y=(e,t)=>{let n=t.parse?.bind(t);return n?{...t,parse(t,r,a){let o=n(t,r,a);if(o.operator!==t.name)throw Error(`Cannot invert "${e}" operator parser because it returns a complex Condition`);return o.operator=e,new i(`NOT`,[o])}}:{...t,parse(t,n,r){return new i(`NOT`,[new a(e,r.field,n)])}}},X={equals:re,not:R,in:z,notIn:Y(`in`,z),lt:B,lte:B,gt:B,gte:B,$lt:B,$lte:B,$gt:B,$gte:B,$in:z,$nin:Y(`in`,z),mode:H,startsWith:U,endsWith:U,contains:U,isEmpty:G,has:K,hasSome:q,hasEvery:q,NOT:W,AND:W,OR:W,every:J,some:J,none:Y(`some`,J),is:J,isNot:Y(`is`,J),isSet:G},Z=l(new class extends s{constructor(){super(X,{defaultOperatorName:`equals`})}parse(e,t){return t?.field?c(this.parseFieldOperators(t.field,e)):super.parse(e)}}().parse,F);function Q(e){if(typeof e!=`object`||!e)return e;if(Array.isArray(e))return e.map(Q);let t={};for(let[n,r]of Object.entries(e)){if(n===`OR`||n===`AND`){t[n]=Q(r);continue}if(n.startsWith(`$`)){let e=n.substring(1);t[e]=Q(r);continue}typeof r==`object`&&r&&!Array.isArray(r)?t[n]=Q(r):t[n]=r}return t}const ie={get(e,n){let r=y(e._ability,e._action,n,e=>e.inverted?{NOT:e.conditions}:e.conditions);if(r===null){let r=t.from(e._ability).setMessage(`It's not allowed to run "${e._action}" on "${n}"`);throw r.action=e._action,r.subjectType=r.subject=n,r}let i=Object.create(null);if(r.$or&&Array.isArray(r.$or)&&r.$or.length===1){let e=r.$or[0];Object.assign(i,e)}else r.$or&&(i.OR=r.$or);return r.$and&&(i.AND=r.$and),Q(i)}};function ae(e,t=`read`){return new Proxy({_ability:e,_action:t},ie)}function $(){function e(e=[],t={}){return new n(e,{...t,conditionsMatcher:Z,fieldMatcher:r})}return e}function oe(){return $()}function se(t){let n=new e($());return t((e,t,r)=>n.can(e,t,r),(e,t,r)=>n.cannot(e,t,r)),n.build()}var ce=class extends n{constructor(e,t){super(e,{conditionsMatcher:Z,fieldMatcher:r,...t})}};export{ce as DrizzleAbility,I as ParsingQueryError,ae as accessibleBy,oe as createDrizzleAbilityFor,se as defineAbility,Z as drizzleQuery};
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@noxify/casl-drizzle",
3
+ "version": "0.0.1-beta.0",
4
+ "description": "Drizzle-ORM adapter for CASL - generate Drizzle where inputs from CASL abilities",
5
+ "keywords": [
6
+ "drizzle",
7
+ "drizzle-orm",
8
+ "casl",
9
+ "ucast"
10
+ ],
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/noxify/casl-drizzle"
14
+ },
15
+ "license": "MIT",
16
+ "authors": [
17
+ {
18
+ "name": "Marcus Reinhardt",
19
+ "email": "webstone@gmail.com"
20
+ },
21
+ {
22
+ "name": "Guilherme Araújo",
23
+ "email": "arauujogui@gmail.com"
24
+ }
25
+ ],
26
+ "type": "module",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.mts",
30
+ "import": "./dist/index.mjs",
31
+ "default": "./src/index.ts"
32
+ }
33
+ },
34
+ "types": "./dist/index.d.mts",
35
+ "files": [
36
+ "dist"
37
+ ],
38
+ "dependencies": {
39
+ "@ucast/core": "^1.10.2",
40
+ "@ucast/js": "3.1.0"
41
+ },
42
+ "prettier": "./prettier.config.mjs",
43
+ "devDependencies": {
44
+ "@casl/ability": "^6.8.0",
45
+ "@changesets/cli": "2.29.8",
46
+ "@eslint/compat": "2.0.2",
47
+ "@eslint/js": "9.39.2",
48
+ "@ianvs/prettier-plugin-sort-imports": "4.7.1",
49
+ "@testcontainers/postgresql": "^11.11.0",
50
+ "@types/js-yaml": "4.0.9",
51
+ "@types/node": "24.10.13",
52
+ "@vitest/coverage-v8": "4.0.18",
53
+ "dedent": "1.7.1",
54
+ "drizzle-kit": "beta",
55
+ "drizzle-orm": "beta",
56
+ "eslint": "9.39.2",
57
+ "eslint-plugin-import": "2.32.0",
58
+ "eslint-plugin-package-json": "0.88.2",
59
+ "json-schema-to-typescript": "15.0.4",
60
+ "jsonc-eslint-parser": "2.4.2",
61
+ "node-pty": "1.1.0",
62
+ "postgres": "3.4.8",
63
+ "prettier": "3.8.1",
64
+ "tsdown": "0.20.3",
65
+ "tsx": "4.21.0",
66
+ "typescript": "^5.9.3",
67
+ "typescript-eslint": "8.55.0",
68
+ "vitest": "4.0.18"
69
+ },
70
+ "peerDependencies": {
71
+ "@casl/ability": "^6.8.0",
72
+ "drizzle-orm": ">=1.0.0-beta.15"
73
+ },
74
+ "engines": {
75
+ "node": ">=22"
76
+ },
77
+ "scripts": {
78
+ "build": "tsdown",
79
+ "ci:publish": "pnpm build && pnpm publish -r --access public --publish-branch main && pnpm changeset tag",
80
+ "ci:version": "pnpm changeset version && pnpm install --no-frozen-lockfile && git add .",
81
+ "cs": "changeset",
82
+ "format": "prettier --check . --ignore-path ./.gitignore --ignore-path ./.prettierignore",
83
+ "format:fix": "prettier --write . --ignore-path ./.gitignore --ignore-path ./.prettierignore",
84
+ "lint": "eslint .",
85
+ "lint:fix": "eslint . --fix",
86
+ "test": "vitest --run",
87
+ "test:coverage": "vitest --coverage",
88
+ "test:watch": "vitest",
89
+ "typecheck": "tsc --noEmit"
90
+ }
91
+ }