@maestro-js/permissions 1.0.0-alpha.10
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/README.md +210 -0
- package/dist/index.d.ts +126 -0
- package/dist/index.js +82 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# @maestro-js/permissions
|
|
2
|
+
|
|
3
|
+
Subject-action authorization with type-safe action maps and profile-based rule resolution.
|
|
4
|
+
|
|
5
|
+
## Quick Setup
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Permissions } from '@maestro-js/permissions'
|
|
9
|
+
|
|
10
|
+
type ActionMap = {
|
|
11
|
+
Post: ['create', 'read', 'update', 'delete']
|
|
12
|
+
Comment: ['create', 'read', 'delete']
|
|
13
|
+
Settings: ['read', 'update']
|
|
14
|
+
}
|
|
15
|
+
type Profile = { role: 'admin' | 'editor' | 'viewer' }
|
|
16
|
+
|
|
17
|
+
// Define rules with the static driver
|
|
18
|
+
const driver = Permissions.drivers.static<Profile>((profile, allow, forbid) => {
|
|
19
|
+
if (profile.role === 'admin') {
|
|
20
|
+
allow('Post', ['create', 'read', 'update', 'delete'])
|
|
21
|
+
allow('Comment', ['create', 'read', 'delete'])
|
|
22
|
+
allow('Settings', ['read', 'update'])
|
|
23
|
+
} else if (profile.role === 'editor') {
|
|
24
|
+
allow('Post', ['create', 'read', 'update'])
|
|
25
|
+
allow('Comment', ['create', 'read'])
|
|
26
|
+
allow('Settings', 'read')
|
|
27
|
+
forbid('Settings', 'update', 'Editors cannot modify settings')
|
|
28
|
+
} else {
|
|
29
|
+
allow('Post', 'read')
|
|
30
|
+
allow('Comment', 'read')
|
|
31
|
+
allow('Settings', 'read')
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// Create and register
|
|
36
|
+
const permissions = Permissions.Provider.create<ActionMap, Profile>({ driver })
|
|
37
|
+
Permissions.Provider.register('default', permissions)
|
|
38
|
+
|
|
39
|
+
// Check permissions via the facade
|
|
40
|
+
Permissions.can({ role: 'editor' }, 'Post', 'create') // true
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Drivers
|
|
44
|
+
|
|
45
|
+
### Static
|
|
46
|
+
|
|
47
|
+
The only built-in driver. Accepts a callback that receives the profile and `allow`/`forbid` helpers
|
|
48
|
+
to declaratively define rules:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
Permissions.drivers.static<Profile>((profile, allow, forbid) => {
|
|
52
|
+
allow('Post', ['create', 'read']) // single subject, multiple actions
|
|
53
|
+
allow(['Post', 'Comment'], 'read') // multiple subjects, single action
|
|
54
|
+
forbid('Settings', 'update', 'Not allowed') // forbid with optional reason
|
|
55
|
+
})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- `allow(subject, action)` -- grant access to one or more subjects/actions
|
|
59
|
+
- `forbid(subject, action, reason?)` -- deny access, optionally with a reason string
|
|
60
|
+
|
|
61
|
+
Rules are evaluated top-to-bottom per call. A `forbid` overrides any prior `allow` for the same
|
|
62
|
+
subject/action pair.
|
|
63
|
+
|
|
64
|
+
Source: `packages/permissions/src/static-permissions-driver.ts`
|
|
65
|
+
|
|
66
|
+
## API Reference
|
|
67
|
+
|
|
68
|
+
### can
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
Permissions.can(profile: P, subject: S, action: M[S][number]): boolean
|
|
72
|
+
```
|
|
73
|
+
Return `true` if the profile is allowed to perform the action on the subject.
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
if (Permissions.can(user, 'Post', 'delete')) {
|
|
77
|
+
await deletePost(postId)
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### cannot
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
Permissions.cannot(profile: P, subject: S, action: M[S][number]): boolean
|
|
85
|
+
```
|
|
86
|
+
Return `true` if the profile is **not** allowed -- the inverse of `can`.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
if (Permissions.cannot(user, 'Settings', 'update')) {
|
|
90
|
+
showReadOnlyView()
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### gate
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
Permissions.gate(profile: P, subject: S, action: M[S][number]): void
|
|
98
|
+
```
|
|
99
|
+
Assert the profile is allowed. Throws `ForbiddenError` (from `@casl/ability`) on denial.
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
Permissions.gate(user, 'Post', 'update') // throws if denied
|
|
103
|
+
await updatePost(postId, data)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### listRules
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
Permissions.listRules(profile: P): Permissions.Rule[]
|
|
110
|
+
```
|
|
111
|
+
Return the full list of rules generated for the profile. Useful for debugging or serializing
|
|
112
|
+
permissions to a client.
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
const rules = Permissions.listRules({ role: 'editor' })
|
|
116
|
+
// [{ subject: 'Post', action: ['create', 'read', 'update'] }, ...]
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Common Patterns
|
|
120
|
+
|
|
121
|
+
### Role-based branching
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
function getNavItems(profile: Profile) {
|
|
125
|
+
const items = [{ label: 'Posts', href: '/posts' }]
|
|
126
|
+
if (Permissions.can(profile, 'Settings', 'update')) {
|
|
127
|
+
items.push({ label: 'Settings', href: '/settings' })
|
|
128
|
+
}
|
|
129
|
+
return items
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Forbid overrides allow
|
|
134
|
+
|
|
135
|
+
A `forbid` placed after a broader `allow` removes that specific permission:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
const driver = Permissions.drivers.static<Profile>((profile, allow, forbid) => {
|
|
139
|
+
allow('Post', ['create', 'read', 'update', 'delete'])
|
|
140
|
+
forbid('Post', 'delete') // everyone can CRUD except delete
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Authorization gate in a request handler
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
app.put('/posts/:id', async (req, res) => {
|
|
148
|
+
try {
|
|
149
|
+
Permissions.gate(req.user, 'Post', 'update')
|
|
150
|
+
await updatePost(req.params.id, req.body)
|
|
151
|
+
res.json({ ok: true })
|
|
152
|
+
} catch (e) {
|
|
153
|
+
if (e instanceof ForbiddenError) {
|
|
154
|
+
res.status(403).json({ error: 'Forbidden' })
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Warnings and Gotchas
|
|
161
|
+
|
|
162
|
+
- **`gate()` throws `ForbiddenError`** -- this is `ForbiddenError` from `@casl/ability`, not a
|
|
163
|
+
plain `Error`. Import it from `@casl/ability` if you need to catch it specifically.
|
|
164
|
+
- **Forbid order matters** -- `forbid` must come after a broader `allow` for the same
|
|
165
|
+
subject/action to take effect. A `forbid` with no matching `allow` has no impact.
|
|
166
|
+
- **Rules are re-evaluated per call** -- the driver callback runs on every `can`, `cannot`, `gate`,
|
|
167
|
+
or `listRules` invocation. There is no internal caching of rule sets.
|
|
168
|
+
|
|
169
|
+
## Testing
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
import { Permissions } from '@maestro-js/permissions'
|
|
173
|
+
import { test } from 'beartest-js'
|
|
174
|
+
import { expect } from 'expect'
|
|
175
|
+
|
|
176
|
+
type ActionMap = { Post: ['create', 'read'] }
|
|
177
|
+
type Profile = { role: 'admin' | 'viewer' }
|
|
178
|
+
|
|
179
|
+
const driver = Permissions.drivers.static<Profile>((profile, allow) => {
|
|
180
|
+
if (profile.role === 'admin') allow('Post', ['create', 'read'])
|
|
181
|
+
else allow('Post', 'read')
|
|
182
|
+
})
|
|
183
|
+
const permissions = Permissions.Provider.create<ActionMap, Profile>({ driver })
|
|
184
|
+
|
|
185
|
+
test('admin can create posts', () => {
|
|
186
|
+
expect(permissions.can({ role: 'admin' }, 'Post', 'create')).toBe(true)
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
test('viewer cannot create posts', () => {
|
|
190
|
+
expect(permissions.cannot({ role: 'viewer' }, 'Post', 'create')).toBe(true)
|
|
191
|
+
})
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Run tests:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
pnpm --filter @maestro-js/permissions test
|
|
198
|
+
cd packages/permissions && npx beartest ./tests/permissions.test.ts
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Cross-Package Integration
|
|
202
|
+
|
|
203
|
+
- **Depends on**: `@maestro-js/service-registry` (Provider pattern foundation),
|
|
204
|
+
`@casl/ability` (rule engine and `ForbiddenError`)
|
|
205
|
+
|
|
206
|
+
## Key Source Files
|
|
207
|
+
|
|
208
|
+
- `packages/permissions/src/index.ts` -- main export, Provider pattern, `create()`, type namespace
|
|
209
|
+
- `packages/permissions/src/static-permissions-driver.ts` -- static driver with `allow`/`forbid` helpers
|
|
210
|
+
- `packages/permissions/tests/permissions.test.ts` -- runtime and type-level tests
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { CustomErrors } from '@maestro-js/custom-errors';
|
|
2
|
+
|
|
3
|
+
interface Rule {
|
|
4
|
+
subject: string | string[];
|
|
5
|
+
action: string | string[];
|
|
6
|
+
inverted?: boolean;
|
|
7
|
+
reason?: string;
|
|
8
|
+
}
|
|
9
|
+
interface Driver<P> {
|
|
10
|
+
listRules: (profile: P) => Rule[];
|
|
11
|
+
}
|
|
12
|
+
type AllowFn<M extends Record<string, string[]> = Record<string, string[]>> = <S extends keyof M>(subject: S, action: (M[S][number] | M[S][number][]) | 'manage') => void;
|
|
13
|
+
type ForbidFn<M extends Record<string, string[]> = Record<string, string[]>> = <S extends keyof M>(subject: S, action: M[S][number] | M[S][number][], reason?: string) => void;
|
|
14
|
+
declare function staticPermissionsDriver<M extends Record<string, string[]> = Record<string, string[]>, P = unknown>(callback: (profile: P, allow: AllowFn<M>, forbid: ForbidFn) => void): Driver<P>;
|
|
15
|
+
|
|
16
|
+
declare function create<M extends Record<string, string[]> = Record<string, string[]>, P = unknown>(config: Permissions.Internal.Config<P>): Permissions.Internal.Service<M, P>;
|
|
17
|
+
declare function provider<Key extends Permissions.Provider.Key>(key: Key): Permissions.PermissionsService<Key>;
|
|
18
|
+
declare const PermissionsBase: {
|
|
19
|
+
Provider: {
|
|
20
|
+
create: typeof create;
|
|
21
|
+
register: (name: Permissions.Provider.Key, item: Permissions.AnyPermissionsService) => void;
|
|
22
|
+
};
|
|
23
|
+
drivers: {
|
|
24
|
+
static: typeof staticPermissionsDriver;
|
|
25
|
+
};
|
|
26
|
+
provider: typeof provider;
|
|
27
|
+
PermissionsError: CustomErrors.CustomErrorConstructor<{
|
|
28
|
+
action: string;
|
|
29
|
+
subject: string;
|
|
30
|
+
}, {
|
|
31
|
+
action: string;
|
|
32
|
+
subject: string;
|
|
33
|
+
}, "forbidden">;
|
|
34
|
+
};
|
|
35
|
+
type KeysWithFallback = keyof Permissions.Provider.Keys extends never ? {
|
|
36
|
+
default: {
|
|
37
|
+
ActionMap: Record<string, string[]>;
|
|
38
|
+
Profile: unknown;
|
|
39
|
+
};
|
|
40
|
+
} : Permissions.Provider.Keys;
|
|
41
|
+
/**
|
|
42
|
+
* Subject-action authorization with type-safe action maps and profile-based rule resolution.
|
|
43
|
+
* Call methods directly on the default instance, or use `Permissions.Provider.create()` for named instances.
|
|
44
|
+
*/
|
|
45
|
+
declare const Permissions: Permissions.PermissionsService<'default'> & typeof PermissionsBase;
|
|
46
|
+
/**
|
|
47
|
+
* Subject-action authorization with type-safe action maps and profile-based rule resolution.
|
|
48
|
+
*
|
|
49
|
+
* Generic `ActionMap` and `Profile` types constrain subjects, actions, and profile shapes at
|
|
50
|
+
* compile time. Rules are defined declaratively via the static driver's `allow`/`forbid`
|
|
51
|
+
* helpers and evaluated per call using CASL's `PureAbility` engine.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import { Permissions } from '@maestro-js/permissions'
|
|
56
|
+
*
|
|
57
|
+
* type ActionMap = { Post: ['create', 'read', 'update', 'delete'] }
|
|
58
|
+
* type Profile = { role: 'admin' | 'viewer' }
|
|
59
|
+
*
|
|
60
|
+
* const driver = Permissions.drivers.static<Profile>((profile, allow) => {
|
|
61
|
+
* if (profile.role === 'admin') allow('Post', ['create', 'read', 'update', 'delete'])
|
|
62
|
+
* else allow('Post', 'read')
|
|
63
|
+
* })
|
|
64
|
+
*
|
|
65
|
+
* const permissions = Permissions.Provider.create<ActionMap, Profile>({ driver })
|
|
66
|
+
* Permissions.Provider.register('default', permissions)
|
|
67
|
+
*
|
|
68
|
+
* Permissions.can({ role: 'admin' }, 'Post', 'delete') // true
|
|
69
|
+
* Permissions.gate({ role: 'viewer' }, 'Post', 'delete') // throws ForbiddenError
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare namespace Permissions {
|
|
73
|
+
type PermissionsService<ProviderKey extends Provider.Key = 'default'> = Internal.Service<KeysWithFallback[ProviderKey]['ActionMap'], KeysWithFallback[ProviderKey]['Profile']>;
|
|
74
|
+
type AnyPermissionsService = Internal.Service<any, any>;
|
|
75
|
+
type PermissionsServiceConfig<ProviderKey extends Provider.Key = 'default'> = Internal.Config<KeysWithFallback[ProviderKey]['Profile']>;
|
|
76
|
+
type Subject<ProviderKey extends Provider.Key = 'default'> = keyof KeysWithFallback[ProviderKey]['ActionMap'] & string;
|
|
77
|
+
type Action<ProviderKey extends Provider.Key = 'default'> = KeysWithFallback[ProviderKey]['ActionMap'][Subject<ProviderKey>][number];
|
|
78
|
+
/** A single permission rule — `inverted: true` marks a forbid rule */
|
|
79
|
+
interface Rule {
|
|
80
|
+
subject: string | string[];
|
|
81
|
+
action: string | string[];
|
|
82
|
+
inverted?: boolean;
|
|
83
|
+
reason?: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Core permission operations for checking and enforcing access control.
|
|
87
|
+
*
|
|
88
|
+
* Use `can`/`cannot` for boolean checks and `gate` to throw on unauthorized access.
|
|
89
|
+
* Rules are built from the configured driver each time a method is called.
|
|
90
|
+
*
|
|
91
|
+
* Returned by `Permissions.Provider.create()` or resolved via `Permissions.provider()`.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* permissions.can({ role: 'editor' }, 'Post', 'create') // true
|
|
96
|
+
* permissions.cannot({ role: 'viewer' }, 'Post', 'delete') // true
|
|
97
|
+
* permissions.gate({ role: 'admin' }, 'Settings', 'update') // void (allowed)
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
namespace Internal {
|
|
101
|
+
interface Service<M extends Record<string, string[]>, P> {
|
|
102
|
+
/** Return `true` if the profile is allowed to perform the action on the subject */
|
|
103
|
+
can<S extends keyof M & string>(profile: P, subject: S, action: M[S][number]): boolean;
|
|
104
|
+
/** Return `true` if the profile is not allowed — the inverse of `can` */
|
|
105
|
+
cannot<S extends keyof M & string>(profile: P, subject: S, action: M[S][number]): boolean;
|
|
106
|
+
/** Assert the profile is allowed — throws `ForbiddenError` on denial */
|
|
107
|
+
gate<S extends keyof M & string>(profile: P, subject: S, action: M[S][number]): void;
|
|
108
|
+
/** Return the full list of rules generated for the profile */
|
|
109
|
+
listRules(profile: P): Permissions.Rule[];
|
|
110
|
+
}
|
|
111
|
+
interface Config<P> {
|
|
112
|
+
driver: Internal.Driver<P>;
|
|
113
|
+
}
|
|
114
|
+
interface Driver<P> {
|
|
115
|
+
/** Return the full list of rules generated for the profile */
|
|
116
|
+
listRules: (profile: P) => Permissions.Rule[];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
namespace Provider {
|
|
120
|
+
type Key = keyof KeysWithFallback;
|
|
121
|
+
interface Keys {
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export { Permissions };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { PureAbility } from "@casl/ability";
|
|
3
|
+
import { CustomErrors } from "@maestro-js/custom-errors";
|
|
4
|
+
import { ServiceRegistry } from "@maestro-js/service-registry";
|
|
5
|
+
|
|
6
|
+
// src/static-permissions-driver.ts
|
|
7
|
+
function staticPermissionsDriver(callback) {
|
|
8
|
+
return {
|
|
9
|
+
listRules(profile) {
|
|
10
|
+
const rules = [];
|
|
11
|
+
const allow = (subject, action) => {
|
|
12
|
+
rules.push({ subject, action });
|
|
13
|
+
};
|
|
14
|
+
const forbid = (subject, action, reason) => {
|
|
15
|
+
rules.push({ subject, action, inverted: true, ...reason !== void 0 && { reason } });
|
|
16
|
+
};
|
|
17
|
+
callback(profile, allow, forbid);
|
|
18
|
+
return rules;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/index.ts
|
|
24
|
+
var PermissionsError = CustomErrors.create({
|
|
25
|
+
name: "PermissionsError",
|
|
26
|
+
message: (input) => `Cannot execute "${input.action}" on "${input.subject}"`,
|
|
27
|
+
additionalAttributes: (input) => ({
|
|
28
|
+
action: input.action,
|
|
29
|
+
subject: input.subject
|
|
30
|
+
}),
|
|
31
|
+
httpStatusCode: "forbidden"
|
|
32
|
+
});
|
|
33
|
+
function create(config) {
|
|
34
|
+
const driver = config.driver;
|
|
35
|
+
function buildAbility(profile) {
|
|
36
|
+
const rules = driver.listRules(profile);
|
|
37
|
+
return new PureAbility(rules);
|
|
38
|
+
}
|
|
39
|
+
function can(profile, subject, action) {
|
|
40
|
+
const ability = buildAbility(profile);
|
|
41
|
+
return ability.can(action, subject);
|
|
42
|
+
}
|
|
43
|
+
function cannot(profile, subject, action) {
|
|
44
|
+
const ability = buildAbility(profile);
|
|
45
|
+
return ability.cannot(action, subject);
|
|
46
|
+
}
|
|
47
|
+
function gate(profile, subject, action) {
|
|
48
|
+
const ability = buildAbility(profile);
|
|
49
|
+
if (ability.cannot(action, subject)) {
|
|
50
|
+
throw new PermissionsError({ action, subject });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function listRules(profile) {
|
|
54
|
+
return driver.listRules(profile);
|
|
55
|
+
}
|
|
56
|
+
return { can, cannot, gate, listRules };
|
|
57
|
+
}
|
|
58
|
+
var registry = ServiceRegistry.createRegistry(
|
|
59
|
+
ServiceRegistry.proxyFunctionsForObject
|
|
60
|
+
);
|
|
61
|
+
var Provider = {
|
|
62
|
+
create,
|
|
63
|
+
register: registry.register
|
|
64
|
+
};
|
|
65
|
+
function provider(key) {
|
|
66
|
+
const service = registry.resolve(key);
|
|
67
|
+
return { can: service.can, cannot: service.cannot, gate: service.gate, listRules: service.listRules };
|
|
68
|
+
}
|
|
69
|
+
var PermissionsBase = {
|
|
70
|
+
Provider,
|
|
71
|
+
drivers: { static: staticPermissionsDriver },
|
|
72
|
+
provider,
|
|
73
|
+
PermissionsError
|
|
74
|
+
};
|
|
75
|
+
var Permissions = {
|
|
76
|
+
...PermissionsBase,
|
|
77
|
+
PermissionsError,
|
|
78
|
+
...provider("default")
|
|
79
|
+
};
|
|
80
|
+
export {
|
|
81
|
+
Permissions
|
|
82
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@maestro-js/permissions",
|
|
3
|
+
"description": "Subject-action authorization with type-safe action maps and profile-based rule resolution. Use when you need role-based access control, permission checks (can/cannot), or authorization gates that throw on denial. Provides a static driver for declarative allow/forbid rule definitions. Built on CASL.",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"default": "./dist/index.js"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"version": "1.0.0-alpha.10",
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "restricted"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@casl/ability": "^6.7.3",
|
|
20
|
+
"@maestro-js/custom-errors": "1.0.0-alpha.10",
|
|
21
|
+
"@maestro-js/service-registry": "1.0.0-alpha.10"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^22.19.11"
|
|
25
|
+
},
|
|
26
|
+
"license": "UNLICENSED",
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=22.18.0"
|
|
29
|
+
},
|
|
30
|
+
"repository": "https://github.com/Marcato-Partners/maestro-js",
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup --config ../../tsup.config.ts",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"test": "beartest ./tests/**/*",
|
|
35
|
+
"format": "prettier --write src/ tests/",
|
|
36
|
+
"lint": "prettier --check src/ tests/"
|
|
37
|
+
}
|
|
38
|
+
}
|