@mahiframework/permissions 0.1.4
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 +21 -0
- package/README.md +7 -0
- package/dist/assignee.d.ts +57 -0
- package/dist/assignee.d.ts.map +1 -0
- package/dist/assignee.js +46 -0
- package/dist/assignee.js.map +1 -0
- package/dist/commands/permissions-cache-reset.d.ts +20 -0
- package/dist/commands/permissions-cache-reset.d.ts.map +1 -0
- package/dist/commands/permissions-cache-reset.js +24 -0
- package/dist/commands/permissions-cache-reset.js.map +1 -0
- package/dist/commands/permissions-check.d.ts +37 -0
- package/dist/commands/permissions-check.d.ts.map +1 -0
- package/dist/commands/permissions-check.js +92 -0
- package/dist/commands/permissions-check.js.map +1 -0
- package/dist/commands/permissions-show.d.ts +20 -0
- package/dist/commands/permissions-show.d.ts.map +1 -0
- package/dist/commands/permissions-show.js +49 -0
- package/dist/commands/permissions-show.js.map +1 -0
- package/dist/errors.d.ts +77 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +106 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/listeners/invalidate-permission-cache.listener.d.ts +39 -0
- package/dist/listeners/invalidate-permission-cache.listener.d.ts.map +1 -0
- package/dist/listeners/invalidate-permission-cache.listener.js +50 -0
- package/dist/listeners/invalidate-permission-cache.listener.js.map +1 -0
- package/dist/middleware/current-subject.d.ts +23 -0
- package/dist/middleware/current-subject.d.ts.map +1 -0
- package/dist/middleware/current-subject.js +31 -0
- package/dist/middleware/current-subject.js.map +1 -0
- package/dist/middleware/permission.d.ts +19 -0
- package/dist/middleware/permission.d.ts.map +1 -0
- package/dist/middleware/permission.js +34 -0
- package/dist/middleware/permission.js.map +1 -0
- package/dist/middleware/role-or-permission.d.ts +29 -0
- package/dist/middleware/role-or-permission.d.ts.map +1 -0
- package/dist/middleware/role-or-permission.js +45 -0
- package/dist/middleware/role-or-permission.js.map +1 -0
- package/dist/middleware/role.d.ts +21 -0
- package/dist/middleware/role.d.ts.map +1 -0
- package/dist/middleware/role.js +36 -0
- package/dist/middleware/role.js.map +1 -0
- package/dist/migrations/0001_create_permission_tables.d.ts +63 -0
- package/dist/migrations/0001_create_permission_tables.d.ts.map +1 -0
- package/dist/migrations/0001_create_permission_tables.js +113 -0
- package/dist/migrations/0001_create_permission_tables.js.map +1 -0
- package/dist/models/permission.model.d.ts +58 -0
- package/dist/models/permission.model.d.ts.map +1 -0
- package/dist/models/permission.model.js +18 -0
- package/dist/models/permission.model.js.map +1 -0
- package/dist/models/role.model.d.ts +60 -0
- package/dist/models/role.model.d.ts.map +1 -0
- package/dist/models/role.model.js +18 -0
- package/dist/models/role.model.js.map +1 -0
- package/dist/permission-map.d.ts +97 -0
- package/dist/permission-map.d.ts.map +1 -0
- package/dist/permission-map.js +93 -0
- package/dist/permission-map.js.map +1 -0
- package/dist/permission-registrar.d.ts +183 -0
- package/dist/permission-registrar.d.ts.map +1 -0
- package/dist/permission-registrar.js +573 -0
- package/dist/permission-registrar.js.map +1 -0
- package/dist/permissions-config.d.ts +80 -0
- package/dist/permissions-config.d.ts.map +1 -0
- package/dist/permissions-config.js +22 -0
- package/dist/permissions-config.js.map +1 -0
- package/dist/permissions-facade.d.ts +74 -0
- package/dist/permissions-facade.d.ts.map +1 -0
- package/dist/permissions-facade.js +131 -0
- package/dist/permissions-facade.js.map +1 -0
- package/dist/permissions-service-provider.d.ts +91 -0
- package/dist/permissions-service-provider.d.ts.map +1 -0
- package/dist/permissions-service-provider.js +137 -0
- package/dist/permissions-service-provider.js.map +1 -0
- package/dist/relations.d.ts +63 -0
- package/dist/relations.d.ts.map +1 -0
- package/dist/relations.js +62 -0
- package/dist/relations.js.map +1 -0
- package/dist/request-cache.d.ts +50 -0
- package/dist/request-cache.d.ts.map +1 -0
- package/dist/request-cache.js +40 -0
- package/dist/request-cache.js.map +1 -0
- package/dist/tokens.d.ts +15 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +15 -0
- package/dist/tokens.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { morphToMany } from "@mahiframework/database";
|
|
2
|
+
import { Permission } from "./models/permission.model.js";
|
|
3
|
+
import { Role } from "./models/role.model.js";
|
|
4
|
+
/**
|
|
5
|
+
* The `roles` relation, for an app model that wants to eager-load them.
|
|
6
|
+
*
|
|
7
|
+
* Opt-in per model rather than shipped on anything, because the package
|
|
8
|
+
* owns neither the app's models nor its attribute interfaces:
|
|
9
|
+
*
|
|
10
|
+
* export interface UserAttributes {
|
|
11
|
+
* // ...
|
|
12
|
+
* roles: MorphToMany<Role>;
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* export class User extends Model<UserAttributes>()({ ... }) {
|
|
16
|
+
* static override relationships = {
|
|
17
|
+
* roles: rolesRelation(),
|
|
18
|
+
* };
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* That buys `User.query().with("roles.permissions")` and
|
|
22
|
+
* `whereHas("roles", (q) => q.where("name", "admin"))`.
|
|
23
|
+
*
|
|
24
|
+
* READ-ONLY, in practice. `Permissions.assignRole()` writes the pivot
|
|
25
|
+
* directly (it takes a subject, not a relation handle, so it can also
|
|
26
|
+
* work from a `{ type, id }` descriptor in a job), so a collection
|
|
27
|
+
* loaded by `with("roles")` will not reflect an assignment made later in
|
|
28
|
+
* the same request. Re-`load()` it if that matters.
|
|
29
|
+
*
|
|
30
|
+
* `type` is deliberately omitted so it defaults to the DECLARING model's
|
|
31
|
+
* `morphAlias()` — which is what a `morphToMany` wants, and the opposite
|
|
32
|
+
* of what `morphedByMany` would. Note that `morphAlias()` falls back to
|
|
33
|
+
* the table name, so an app without a `Relation.morphMap()` entry has
|
|
34
|
+
* made its assignment rows depend on its table name.
|
|
35
|
+
*/
|
|
36
|
+
export function rolesRelation() {
|
|
37
|
+
return morphToMany(() => Role, {
|
|
38
|
+
pivotTable: "model_has_roles",
|
|
39
|
+
morphType: "model_type",
|
|
40
|
+
morphId: "model_id",
|
|
41
|
+
relatedPivotKey: "role_id",
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The `permissions` relation: permissions granted to this model
|
|
46
|
+
* DIRECTLY, never those inherited from its roles.
|
|
47
|
+
*
|
|
48
|
+
* The inherited ones have no relation to declare — they are two hops
|
|
49
|
+
* through `model_has_roles` and `role_has_permissions`, which is a
|
|
50
|
+
* `hasManyThrough` the ORM cannot express across a polymorphic pivot.
|
|
51
|
+
* `Permissions.getAllPermissions(user)` is the union, and it answers
|
|
52
|
+
* from the cached map rather than a join.
|
|
53
|
+
*/
|
|
54
|
+
export function permissionsRelation() {
|
|
55
|
+
return morphToMany(() => Permission, {
|
|
56
|
+
pivotTable: "model_has_permissions",
|
|
57
|
+
morphType: "model_type",
|
|
58
|
+
morphId: "model_id",
|
|
59
|
+
relatedPivotKey: "permission_id",
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=relations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relations.js","sourceRoot":"","sources":["../src/relations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE;QAC7B,UAAU,EAAE,iBAAiB;QAC7B,SAAS,EAAE,YAAY;QACvB,OAAO,EAAE,UAAU;QACnB,eAAe,EAAE,SAAS;KAC3B,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,WAAW,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE;QACnC,UAAU,EAAE,uBAAuB;QACnC,SAAS,EAAE,YAAY;QACvB,OAAO,EAAE,UAAU;QACnB,eAAe,EAAE,eAAe;KACjC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A per-request memo of each subject's raw assignments.
|
|
3
|
+
*
|
|
4
|
+
* This exists because of how the gate hook works, not as a general
|
|
5
|
+
* optimisation. `GateRegistry.before()` callbacks run on EVERY
|
|
6
|
+
* authorization check, so a controller doing five `can()` calls would
|
|
7
|
+
* otherwise issue ten queries (roles and direct permissions, twice per
|
|
8
|
+
* call) against rows that cannot have changed mid-request unless this
|
|
9
|
+
* request changed them.
|
|
10
|
+
*
|
|
11
|
+
* Scoped rather than global for the obvious reason: a long-lived worker
|
|
12
|
+
* process would otherwise serve one request's answers to the next, and
|
|
13
|
+
* "why does this user still have admin" is not a bug anybody enjoys.
|
|
14
|
+
*
|
|
15
|
+
* The provider's `middleware()` pipe opens a scope per request. Outside
|
|
16
|
+
* one, `assignmentMemo()` returns null and every read goes to the
|
|
17
|
+
* database — correct by default, since a queue job or a CLI command has
|
|
18
|
+
* no natural boundary at which the memo should expire. A job that wants
|
|
19
|
+
* one wraps itself in `withPermissionCache()`.
|
|
20
|
+
*
|
|
21
|
+
* Writes through the registrar clear the memo rather than patching it:
|
|
22
|
+
* patching means keeping two representations in step, and clearing costs
|
|
23
|
+
* one query on the next check.
|
|
24
|
+
*/
|
|
25
|
+
export interface AssignmentRecord {
|
|
26
|
+
roleIds: bigint[];
|
|
27
|
+
permissionIds: bigint[];
|
|
28
|
+
}
|
|
29
|
+
/** Run `fn` inside a memo scope. Called once per request by the provider's pipe. */
|
|
30
|
+
export declare function runWithPermissionCache<T>(fn: () => T): T;
|
|
31
|
+
/**
|
|
32
|
+
* Open a memo scope around a job, command, or test.
|
|
33
|
+
*
|
|
34
|
+
* Async-returning so a caller cannot forget to await it, and so the scope
|
|
35
|
+
* genuinely covers the whole callback rather than just its synchronous
|
|
36
|
+
* prefix.
|
|
37
|
+
*/
|
|
38
|
+
export declare function withPermissionCache<T>(callback: () => T | Promise<T>): Promise<T>;
|
|
39
|
+
/** The active memo, or null outside a scope. */
|
|
40
|
+
export declare function assignmentMemo(): Map<string, AssignmentRecord> | null;
|
|
41
|
+
/**
|
|
42
|
+
* Drop memoised assignments.
|
|
43
|
+
*
|
|
44
|
+
* With no argument, clears everything: a role's permissions changing
|
|
45
|
+
* affects every subject holding it, and the registrar has no index from
|
|
46
|
+
* role to subject. Pass a key to drop just one subject, which is what an
|
|
47
|
+
* assignment write does.
|
|
48
|
+
*/
|
|
49
|
+
export declare function forgetMemoisedAssignments(cacheKey?: string): void;
|
|
50
|
+
//# sourceMappingURL=request-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-cache.d.ts","sourceRoot":"","sources":["../src/request-cache.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAID,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAExD;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAEjF;AAED,gDAAgD;AAChD,wBAAgB,cAAc,IAAI,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,IAAI,CAErE;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAcjE"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
const storage = new AsyncLocalStorage();
|
|
3
|
+
/** Run `fn` inside a memo scope. Called once per request by the provider's pipe. */
|
|
4
|
+
export function runWithPermissionCache(fn) {
|
|
5
|
+
return storage.run(new Map(), fn);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Open a memo scope around a job, command, or test.
|
|
9
|
+
*
|
|
10
|
+
* Async-returning so a caller cannot forget to await it, and so the scope
|
|
11
|
+
* genuinely covers the whole callback rather than just its synchronous
|
|
12
|
+
* prefix.
|
|
13
|
+
*/
|
|
14
|
+
export function withPermissionCache(callback) {
|
|
15
|
+
return storage.run(new Map(), async () => callback());
|
|
16
|
+
}
|
|
17
|
+
/** The active memo, or null outside a scope. */
|
|
18
|
+
export function assignmentMemo() {
|
|
19
|
+
return storage.getStore() ?? null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Drop memoised assignments.
|
|
23
|
+
*
|
|
24
|
+
* With no argument, clears everything: a role's permissions changing
|
|
25
|
+
* affects every subject holding it, and the registrar has no index from
|
|
26
|
+
* role to subject. Pass a key to drop just one subject, which is what an
|
|
27
|
+
* assignment write does.
|
|
28
|
+
*/
|
|
29
|
+
export function forgetMemoisedAssignments(cacheKey) {
|
|
30
|
+
const memo = storage.getStore();
|
|
31
|
+
if (memo === undefined) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (cacheKey === undefined) {
|
|
35
|
+
memo.clear();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
memo.delete(cacheKey);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=request-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-cache.js","sourceRoot":"","sources":["../src/request-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AA+BrD,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAiC,CAAC;AAEvE,oFAAoF;AACpF,MAAM,UAAU,sBAAsB,CAAI,EAAW;IACnD,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,EAA4B,EAAE,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAI,QAA8B;IACnE,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,EAA4B,EAAE,KAAK,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;AAClF,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC;AACpC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAiB;IACzD,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAEhC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO;IACT,CAAC;IAED,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,OAAO;IACT,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACxB,CAAC"}
|
package/dist/tokens.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `PermissionRegistrar` singleton.
|
|
3
|
+
*
|
|
4
|
+
* NOT in `@mahiframework/core`'s `well-known-tokens.ts`. That file is
|
|
5
|
+
* explicitly for tokens referenced ACROSS package boundaries by packages
|
|
6
|
+
* that deliberately avoid a compile-time dependency; nothing outside this
|
|
7
|
+
* package resolves this one by string. A local literal is correct until
|
|
8
|
+
* that changes.
|
|
9
|
+
*
|
|
10
|
+
* A separate module from the provider so the facade and the middleware
|
|
11
|
+
* can import the token without importing the provider, which would be a
|
|
12
|
+
* cycle.
|
|
13
|
+
*/
|
|
14
|
+
export declare const PERMISSIONS_TOKEN = "permissions";
|
|
15
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,gBAAgB,CAAC"}
|
package/dist/tokens.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `PermissionRegistrar` singleton.
|
|
3
|
+
*
|
|
4
|
+
* NOT in `@mahiframework/core`'s `well-known-tokens.ts`. That file is
|
|
5
|
+
* explicitly for tokens referenced ACROSS package boundaries by packages
|
|
6
|
+
* that deliberately avoid a compile-time dependency; nothing outside this
|
|
7
|
+
* package resolves this one by string. A local literal is correct until
|
|
8
|
+
* that changes.
|
|
9
|
+
*
|
|
10
|
+
* A separate module from the provider so the facade and the middleware
|
|
11
|
+
* can import the token without importing the provider, which would be a
|
|
12
|
+
* cycle.
|
|
13
|
+
*/
|
|
14
|
+
export const PERMISSIONS_TOKEN = "permissions";
|
|
15
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mahiframework/permissions",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"commander": "^12.1.0",
|
|
15
|
+
"@mahiframework/auth": "0.1.4",
|
|
16
|
+
"@mahiframework/cli": "0.1.4",
|
|
17
|
+
"@mahiframework/core": "0.1.4",
|
|
18
|
+
"@mahiframework/database": "0.1.4",
|
|
19
|
+
"@mahiframework/events": "0.1.4",
|
|
20
|
+
"@mahiframework/datetime": "0.1.4",
|
|
21
|
+
"@mahiframework/http": "0.1.4",
|
|
22
|
+
"@mahiframework/facades": "0.1.4",
|
|
23
|
+
"@mahiframework/cache": "0.1.4",
|
|
24
|
+
"@mahiframework/authorization": "0.1.4",
|
|
25
|
+
"@mahiframework/snowflake": "0.1.4"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"typescript": "^5.7.2",
|
|
29
|
+
"vite": "^8.0.0",
|
|
30
|
+
"vitest": "^4.1.11"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"author": "Bradie Tilley",
|
|
34
|
+
"homepage": "https://github.com/mahiframework/mahi#readme",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/mahiframework/mahi.git",
|
|
38
|
+
"directory": "framework/permissions"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/mahiframework/mahi/issues"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=26"
|
|
45
|
+
},
|
|
46
|
+
"sideEffects": false,
|
|
47
|
+
"description": "Permissions — roles, permissions, and cached authorization checks for Mahi.",
|
|
48
|
+
"keywords": [
|
|
49
|
+
"mahi",
|
|
50
|
+
"permissions",
|
|
51
|
+
"roles",
|
|
52
|
+
"authorization",
|
|
53
|
+
"acl"
|
|
54
|
+
],
|
|
55
|
+
"files": [
|
|
56
|
+
"dist",
|
|
57
|
+
"README.md",
|
|
58
|
+
"LICENSE"
|
|
59
|
+
],
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsc -b && node ../../scripts/prune-dist.mjs",
|
|
65
|
+
"typecheck": "tsc -b && tsc -p tsconfig.test.json",
|
|
66
|
+
"lint": "eslint src tests",
|
|
67
|
+
"test": "vitest run"
|
|
68
|
+
}
|
|
69
|
+
}
|