@pyreon/permissions 0.5.0 → 0.7.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/lib/analysis/index.js.html +5406 -0
- package/lib/index.js +132 -0
- package/lib/index.js.map +1 -0
- package/lib/types/index.d.ts +169 -0
- package/lib/types/index.d.ts.map +1 -0
- package/package.json +1 -7
- package/src/context.ts +3 -13
package/lib/index.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { computed, signal } from "@pyreon/reactivity";
|
|
2
|
+
import { createContext, provide, useContext } from "@pyreon/core";
|
|
3
|
+
|
|
4
|
+
//#region src/permissions.ts
|
|
5
|
+
/**
|
|
6
|
+
* Resolve a permission key against the map.
|
|
7
|
+
* Resolution order: exact match → wildcard (e.g., 'posts.*') → global wildcard ('*') → false.
|
|
8
|
+
*/
|
|
9
|
+
function resolve(map, key, context) {
|
|
10
|
+
const exact = map.get(key);
|
|
11
|
+
if (exact !== void 0) return typeof exact === "function" ? exact(context) : exact;
|
|
12
|
+
const dotIndex = key.lastIndexOf(".");
|
|
13
|
+
if (dotIndex !== -1) {
|
|
14
|
+
const prefix = key.slice(0, dotIndex);
|
|
15
|
+
const wildcard = map.get(`${prefix}.*`);
|
|
16
|
+
if (wildcard !== void 0) return typeof wildcard === "function" ? wildcard(context) : wildcard;
|
|
17
|
+
}
|
|
18
|
+
const global = map.get("*");
|
|
19
|
+
if (global !== void 0) return typeof global === "function" ? global(context) : global;
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a reactive permissions instance.
|
|
24
|
+
*
|
|
25
|
+
* The returned `can` function checks permissions reactively —
|
|
26
|
+
* reads update automatically when permissions change via `set()` or `patch()`.
|
|
27
|
+
*
|
|
28
|
+
* @param initial - Optional initial permission map
|
|
29
|
+
* @returns A callable `Permissions` instance
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```tsx
|
|
33
|
+
* const can = createPermissions({
|
|
34
|
+
* 'posts.read': true,
|
|
35
|
+
* 'posts.update': (post: Post) => post.authorId === userId(),
|
|
36
|
+
* 'users.manage': false,
|
|
37
|
+
* })
|
|
38
|
+
*
|
|
39
|
+
* // Check (reactive in effects/computeds/JSX)
|
|
40
|
+
* can('posts.read') // true
|
|
41
|
+
* can('posts.update', myPost) // evaluates predicate
|
|
42
|
+
*
|
|
43
|
+
* // JSX
|
|
44
|
+
* {() => can('posts.delete') && <DeleteButton />}
|
|
45
|
+
*
|
|
46
|
+
* // Update
|
|
47
|
+
* can.set({ 'posts.read': true, 'admin': true })
|
|
48
|
+
* can.patch({ 'users.manage': true })
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
function createPermissions(initial) {
|
|
52
|
+
const store = signal(toMap(initial));
|
|
53
|
+
const version = signal(0);
|
|
54
|
+
function toMap(obj) {
|
|
55
|
+
if (!obj) return /* @__PURE__ */ new Map();
|
|
56
|
+
return new Map(Object.entries(obj));
|
|
57
|
+
}
|
|
58
|
+
function can(key, context) {
|
|
59
|
+
version();
|
|
60
|
+
return resolve(store.peek(), key, context);
|
|
61
|
+
}
|
|
62
|
+
can.not = (key, context) => {
|
|
63
|
+
return !can(key, context);
|
|
64
|
+
};
|
|
65
|
+
can.all = (...keys) => {
|
|
66
|
+
return keys.every((key) => can(key));
|
|
67
|
+
};
|
|
68
|
+
can.any = (...keys) => {
|
|
69
|
+
return keys.some((key) => can(key));
|
|
70
|
+
};
|
|
71
|
+
can.set = (permissions) => {
|
|
72
|
+
store.set(toMap(permissions));
|
|
73
|
+
version.update((v) => v + 1);
|
|
74
|
+
};
|
|
75
|
+
can.patch = (permissions) => {
|
|
76
|
+
const current = store.peek();
|
|
77
|
+
for (const [key, value] of Object.entries(permissions)) current.set(key, value);
|
|
78
|
+
store.set(current);
|
|
79
|
+
version.update((v) => v + 1);
|
|
80
|
+
};
|
|
81
|
+
can.granted = computed(() => {
|
|
82
|
+
version();
|
|
83
|
+
const keys = [];
|
|
84
|
+
for (const [key, value] of store.peek()) if (value === true || typeof value === "function") keys.push(key);
|
|
85
|
+
return keys;
|
|
86
|
+
});
|
|
87
|
+
can.entries = computed(() => {
|
|
88
|
+
version();
|
|
89
|
+
return [...store.peek().entries()];
|
|
90
|
+
});
|
|
91
|
+
return can;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region src/context.ts
|
|
96
|
+
const PermissionsContext = createContext(null);
|
|
97
|
+
/**
|
|
98
|
+
* Provide a permissions instance to descendant components.
|
|
99
|
+
* Use this for SSR isolation or testing — each request/test gets its own instance.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```tsx
|
|
103
|
+
* const can = createPermissions({ ... })
|
|
104
|
+
*
|
|
105
|
+
* <PermissionsProvider instance={can}>
|
|
106
|
+
* <App />
|
|
107
|
+
* </PermissionsProvider>
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
function PermissionsProvider(props) {
|
|
111
|
+
provide(PermissionsContext, props.instance);
|
|
112
|
+
return props.children ?? null;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Access the nearest permissions instance from context.
|
|
116
|
+
* Must be used within a `<PermissionsProvider>`.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```tsx
|
|
120
|
+
* const can = usePermissions()
|
|
121
|
+
* {() => can('posts.read') && <PostList />}
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
function usePermissions() {
|
|
125
|
+
const instance = useContext(PermissionsContext);
|
|
126
|
+
if (!instance) throw new Error("[@pyreon/permissions] usePermissions() must be used within <PermissionsProvider>.");
|
|
127
|
+
return instance;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
//#endregion
|
|
131
|
+
export { PermissionsProvider, createPermissions, usePermissions };
|
|
132
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/permissions.ts","../src/context.ts"],"sourcesContent":["import { computed, signal } from '@pyreon/reactivity'\nimport type { PermissionMap, PermissionValue, Permissions } from './types'\n\n/**\n * Resolve a permission key against the map.\n * Resolution order: exact match → wildcard (e.g., 'posts.*') → global wildcard ('*') → false.\n */\nfunction resolve(\n map: Map<string, PermissionValue>,\n key: string,\n context?: unknown,\n): boolean {\n // 1. Exact match\n const exact = map.get(key)\n if (exact !== undefined) {\n return typeof exact === 'function' ? exact(context) : exact\n }\n\n // 2. Wildcard match — 'posts.read' matches 'posts.*'\n const dotIndex = key.lastIndexOf('.')\n if (dotIndex !== -1) {\n const prefix = key.slice(0, dotIndex)\n const wildcard = map.get(`${prefix}.*`)\n if (wildcard !== undefined) {\n return typeof wildcard === 'function' ? wildcard(context) : wildcard\n }\n }\n\n // 3. Global wildcard\n const global = map.get('*')\n if (global !== undefined) {\n return typeof global === 'function' ? global(context) : global\n }\n\n // 4. No match → denied\n return false\n}\n\n/**\n * Create a reactive permissions instance.\n *\n * The returned `can` function checks permissions reactively —\n * reads update automatically when permissions change via `set()` or `patch()`.\n *\n * @param initial - Optional initial permission map\n * @returns A callable `Permissions` instance\n *\n * @example\n * ```tsx\n * const can = createPermissions({\n * 'posts.read': true,\n * 'posts.update': (post: Post) => post.authorId === userId(),\n * 'users.manage': false,\n * })\n *\n * // Check (reactive in effects/computeds/JSX)\n * can('posts.read') // true\n * can('posts.update', myPost) // evaluates predicate\n *\n * // JSX\n * {() => can('posts.delete') && <DeleteButton />}\n *\n * // Update\n * can.set({ 'posts.read': true, 'admin': true })\n * can.patch({ 'users.manage': true })\n * ```\n */\nexport function createPermissions(initial?: PermissionMap): Permissions {\n // Internal reactive state — a signal holding the permission map\n const store = signal(toMap(initial))\n // Version counter — incremented on every set/patch to trigger reactive updates\n const version = signal(0)\n\n function toMap(obj?: PermissionMap): Map<string, PermissionValue> {\n if (!obj) return new Map()\n return new Map(Object.entries(obj))\n }\n\n // The main check function — reads `version` to subscribe in reactive contexts\n function can(key: string, context?: unknown): boolean {\n // Reading version subscribes this call to reactive updates\n version()\n return resolve(store.peek(), key, context)\n }\n\n can.not = (key: string, context?: unknown): boolean => {\n return !can(key, context)\n }\n\n can.all = (...keys: string[]): boolean => {\n return keys.every((key) => can(key))\n }\n\n can.any = (...keys: string[]): boolean => {\n return keys.some((key) => can(key))\n }\n\n can.set = (permissions: PermissionMap): void => {\n store.set(toMap(permissions))\n version.update((v) => v + 1)\n }\n\n can.patch = (permissions: PermissionMap): void => {\n const current = store.peek()\n for (const [key, value] of Object.entries(permissions)) {\n current.set(key, value)\n }\n store.set(current)\n version.update((v) => v + 1)\n }\n\n can.granted = computed(() => {\n version()\n const keys: string[] = []\n for (const [key, value] of store.peek()) {\n // Static true or predicate (capability exists)\n if (value === true || typeof value === 'function') {\n keys.push(key)\n }\n }\n return keys\n })\n\n can.entries = computed(() => {\n version()\n return [...store.peek().entries()]\n })\n\n return can as Permissions\n}\n","import { createContext, provide, useContext } from '@pyreon/core'\nimport type { VNodeChild } from '@pyreon/core'\nimport type { Permissions } from './types'\n\nconst PermissionsContext = createContext<Permissions | null>(null)\n\n/**\n * Provide a permissions instance to descendant components.\n * Use this for SSR isolation or testing — each request/test gets its own instance.\n *\n * @example\n * ```tsx\n * const can = createPermissions({ ... })\n *\n * <PermissionsProvider instance={can}>\n * <App />\n * </PermissionsProvider>\n * ```\n */\nexport function PermissionsProvider(props: {\n instance: Permissions\n children?: VNodeChild\n}): VNodeChild {\n provide(PermissionsContext, props.instance)\n\n return props.children ?? null\n}\n\n/**\n * Access the nearest permissions instance from context.\n * Must be used within a `<PermissionsProvider>`.\n *\n * @example\n * ```tsx\n * const can = usePermissions()\n * {() => can('posts.read') && <PostList />}\n * ```\n */\nexport function usePermissions(): Permissions {\n const instance = useContext(PermissionsContext)\n if (!instance) {\n throw new Error(\n '[@pyreon/permissions] usePermissions() must be used within <PermissionsProvider>.',\n )\n }\n return instance\n}\n"],"mappings":";;;;;;;;AAOA,SAAS,QACP,KACA,KACA,SACS;CAET,MAAM,QAAQ,IAAI,IAAI,IAAI;AAC1B,KAAI,UAAU,OACZ,QAAO,OAAO,UAAU,aAAa,MAAM,QAAQ,GAAG;CAIxD,MAAM,WAAW,IAAI,YAAY,IAAI;AACrC,KAAI,aAAa,IAAI;EACnB,MAAM,SAAS,IAAI,MAAM,GAAG,SAAS;EACrC,MAAM,WAAW,IAAI,IAAI,GAAG,OAAO,IAAI;AACvC,MAAI,aAAa,OACf,QAAO,OAAO,aAAa,aAAa,SAAS,QAAQ,GAAG;;CAKhE,MAAM,SAAS,IAAI,IAAI,IAAI;AAC3B,KAAI,WAAW,OACb,QAAO,OAAO,WAAW,aAAa,OAAO,QAAQ,GAAG;AAI1D,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCT,SAAgB,kBAAkB,SAAsC;CAEtE,MAAM,QAAQ,OAAO,MAAM,QAAQ,CAAC;CAEpC,MAAM,UAAU,OAAO,EAAE;CAEzB,SAAS,MAAM,KAAmD;AAChE,MAAI,CAAC,IAAK,wBAAO,IAAI,KAAK;AAC1B,SAAO,IAAI,IAAI,OAAO,QAAQ,IAAI,CAAC;;CAIrC,SAAS,IAAI,KAAa,SAA4B;AAEpD,WAAS;AACT,SAAO,QAAQ,MAAM,MAAM,EAAE,KAAK,QAAQ;;AAG5C,KAAI,OAAO,KAAa,YAA+B;AACrD,SAAO,CAAC,IAAI,KAAK,QAAQ;;AAG3B,KAAI,OAAO,GAAG,SAA4B;AACxC,SAAO,KAAK,OAAO,QAAQ,IAAI,IAAI,CAAC;;AAGtC,KAAI,OAAO,GAAG,SAA4B;AACxC,SAAO,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC;;AAGrC,KAAI,OAAO,gBAAqC;AAC9C,QAAM,IAAI,MAAM,YAAY,CAAC;AAC7B,UAAQ,QAAQ,MAAM,IAAI,EAAE;;AAG9B,KAAI,SAAS,gBAAqC;EAChD,MAAM,UAAU,MAAM,MAAM;AAC5B,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,YAAY,CACpD,SAAQ,IAAI,KAAK,MAAM;AAEzB,QAAM,IAAI,QAAQ;AAClB,UAAQ,QAAQ,MAAM,IAAI,EAAE;;AAG9B,KAAI,UAAU,eAAe;AAC3B,WAAS;EACT,MAAM,OAAiB,EAAE;AACzB,OAAK,MAAM,CAAC,KAAK,UAAU,MAAM,MAAM,CAErC,KAAI,UAAU,QAAQ,OAAO,UAAU,WACrC,MAAK,KAAK,IAAI;AAGlB,SAAO;GACP;AAEF,KAAI,UAAU,eAAe;AAC3B,WAAS;AACT,SAAO,CAAC,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC;GAClC;AAEF,QAAO;;;;;AC5HT,MAAM,qBAAqB,cAAkC,KAAK;;;;;;;;;;;;;;AAelE,SAAgB,oBAAoB,OAGrB;AACb,SAAQ,oBAAoB,MAAM,SAAS;AAE3C,QAAO,MAAM,YAAY;;;;;;;;;;;;AAa3B,SAAgB,iBAA8B;CAC5C,MAAM,WAAW,WAAW,mBAAmB;AAC/C,KAAI,CAAC,SACH,OAAM,IAAI,MACR,oFACD;AAEH,QAAO"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Computed } from "@pyreon/reactivity";
|
|
2
|
+
import { VNodeChild } from "@pyreon/core";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* A permission predicate — receives optional context and returns a boolean.
|
|
7
|
+
* Used for instance-level checks (e.g., "can update THIS post?").
|
|
8
|
+
*/
|
|
9
|
+
type PermissionPredicate<TContext = unknown> = (context?: TContext) => boolean;
|
|
10
|
+
/**
|
|
11
|
+
* A permission value is either a static boolean or a predicate function.
|
|
12
|
+
* - `true` / `false` — static grant or denial
|
|
13
|
+
* - `(context?) => boolean` — dynamic, evaluated per-check
|
|
14
|
+
*/
|
|
15
|
+
type PermissionValue<TContext = unknown> = boolean | PermissionPredicate<TContext>;
|
|
16
|
+
/**
|
|
17
|
+
* A map of permission keys to their values.
|
|
18
|
+
* Keys are dot-separated strings (e.g., 'posts.read', 'users.manage').
|
|
19
|
+
* Wildcards are supported: 'posts.*' matches any 'posts.X' key.
|
|
20
|
+
*/
|
|
21
|
+
type PermissionMap = Record<string, PermissionValue>;
|
|
22
|
+
/**
|
|
23
|
+
* The permissions instance returned by `createPermissions()`.
|
|
24
|
+
* Callable — `can('posts.read')` returns a boolean, reactive in effects/computeds/JSX.
|
|
25
|
+
*/
|
|
26
|
+
interface Permissions {
|
|
27
|
+
/**
|
|
28
|
+
* Check if a permission is granted.
|
|
29
|
+
* Returns a boolean — reactive when read inside effects, computeds, or JSX `{() => ...}`.
|
|
30
|
+
*
|
|
31
|
+
* @param key - Permission key (e.g., 'posts.read')
|
|
32
|
+
* @param context - Optional context for predicate evaluation (e.g., a post instance)
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* can('posts.read') // static check
|
|
37
|
+
* can('posts.update', post) // instance check
|
|
38
|
+
* {() => can('posts.delete') && <DeleteButton />}
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
(key: string, context?: unknown): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Inverse check — returns true when the permission is denied.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* can.not('billing.export') // true if user cannot export
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
not: (key: string, context?: unknown) => boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Check if ALL listed permissions are granted.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* can.all('posts.read', 'posts.create')
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
all: (...keys: string[]) => boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Check if ANY of the listed permissions is granted.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```tsx
|
|
65
|
+
* can.any('posts.update', 'posts.delete')
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
any: (...keys: string[]) => boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Replace all permissions. All reactive reads update automatically.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```tsx
|
|
74
|
+
* can.set({ 'posts.read': true, 'users.manage': false })
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
set: (permissions: PermissionMap) => void;
|
|
78
|
+
/**
|
|
79
|
+
* Merge permissions into the current map.
|
|
80
|
+
* Existing keys are overwritten, new keys are added.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```tsx
|
|
84
|
+
* can.patch({ 'billing.export': true })
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
patch: (permissions: PermissionMap) => void;
|
|
88
|
+
/**
|
|
89
|
+
* All currently granted permission keys (static true + predicates that exist).
|
|
90
|
+
* Reactive signal — updates when permissions change.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```tsx
|
|
94
|
+
* // For help dialogs or admin dashboards
|
|
95
|
+
* can.granted() // ['posts.read', 'posts.create', 'users.manage']
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
granted: Computed<string[]>;
|
|
99
|
+
/**
|
|
100
|
+
* All permission entries as [key, value] pairs.
|
|
101
|
+
* Reactive signal — updates when permissions change.
|
|
102
|
+
*/
|
|
103
|
+
entries: Computed<[string, PermissionValue][]>;
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/permissions.d.ts
|
|
107
|
+
/**
|
|
108
|
+
* Create a reactive permissions instance.
|
|
109
|
+
*
|
|
110
|
+
* The returned `can` function checks permissions reactively —
|
|
111
|
+
* reads update automatically when permissions change via `set()` or `patch()`.
|
|
112
|
+
*
|
|
113
|
+
* @param initial - Optional initial permission map
|
|
114
|
+
* @returns A callable `Permissions` instance
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```tsx
|
|
118
|
+
* const can = createPermissions({
|
|
119
|
+
* 'posts.read': true,
|
|
120
|
+
* 'posts.update': (post: Post) => post.authorId === userId(),
|
|
121
|
+
* 'users.manage': false,
|
|
122
|
+
* })
|
|
123
|
+
*
|
|
124
|
+
* // Check (reactive in effects/computeds/JSX)
|
|
125
|
+
* can('posts.read') // true
|
|
126
|
+
* can('posts.update', myPost) // evaluates predicate
|
|
127
|
+
*
|
|
128
|
+
* // JSX
|
|
129
|
+
* {() => can('posts.delete') && <DeleteButton />}
|
|
130
|
+
*
|
|
131
|
+
* // Update
|
|
132
|
+
* can.set({ 'posts.read': true, 'admin': true })
|
|
133
|
+
* can.patch({ 'users.manage': true })
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
declare function createPermissions(initial?: PermissionMap): Permissions;
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region src/context.d.ts
|
|
139
|
+
/**
|
|
140
|
+
* Provide a permissions instance to descendant components.
|
|
141
|
+
* Use this for SSR isolation or testing — each request/test gets its own instance.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```tsx
|
|
145
|
+
* const can = createPermissions({ ... })
|
|
146
|
+
*
|
|
147
|
+
* <PermissionsProvider instance={can}>
|
|
148
|
+
* <App />
|
|
149
|
+
* </PermissionsProvider>
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
declare function PermissionsProvider(props: {
|
|
153
|
+
instance: Permissions;
|
|
154
|
+
children?: VNodeChild;
|
|
155
|
+
}): VNodeChild;
|
|
156
|
+
/**
|
|
157
|
+
* Access the nearest permissions instance from context.
|
|
158
|
+
* Must be used within a `<PermissionsProvider>`.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```tsx
|
|
162
|
+
* const can = usePermissions()
|
|
163
|
+
* {() => can('posts.read') && <PostList />}
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
declare function usePermissions(): Permissions;
|
|
167
|
+
//#endregion
|
|
168
|
+
export { type PermissionMap, type PermissionPredicate, type PermissionValue, type Permissions, PermissionsProvider, createPermissions, usePermissions };
|
|
169
|
+
//# sourceMappingURL=index2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../../src/types.ts","../../../src/permissions.ts","../../../src/context.ts"],"mappings":";;;;;;;AAQA;KAAY,mBAAA,wBACV,OAAA,GAAU,QAAA;;;;;;KAQA,eAAA,iCAER,mBAAA,CAAoB,QAAA;;AAFxB;;;;KAWY,aAAA,GAAgB,MAAA,SAAe,eAAA;;;;;UAQ1B,WAAA;EARQ;;;;AAQzB;;;;;;;;;;EARyB,CAuBtB,GAAA,UAAa,OAAA;EAAA;;;;;;;;EAUd,GAAA,GAAM,GAAA,UAAa,OAAA;EA8BA;;;;;;;;EApBnB,GAAA,MAAS,IAAA;EAiDkB;;;;;;ACrD7B;;EDcE,GAAA,MAAS,IAAA;ECd4D;;;;;;;;EDwBrE,GAAA,GAAM,WAAA,EAAa,aAAA;EExEL;;;;;;;;;EFmFd,KAAA,GAAQ,WAAA,EAAa,aAAA;EEjFrB;;;;;;AAiBF;;;;EF4EE,OAAA,EAAS,QAAA;;;;;EAMT,OAAA,EAAS,QAAA,UAAkB,eAAA;AAAA;;;;;;AAhH7B;;;;;;;;;AASA;;;;;;;;;AAWA;;;;;AAQA;;;iBC+BgB,iBAAA,CAAkB,OAAA,GAAU,aAAA,GAAgB,WAAA;;;;;AD3D5D;;;;;;;;;AASA;;iBEEgB,mBAAA,CAAoB,KAAA;EAClC,QAAA,EAAU,WAAA;EACV,QAAA,GAAW,UAAA;AAAA,IACT,UAAA;;;;AFMJ;;;;;AAQA;;iBEEgB,cAAA,CAAA,GAAkB,WAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/permissions",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Reactive permissions for Pyreon — type-safe, signal-driven, universal",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -42,11 +42,5 @@
|
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@pyreon/core": ">=0.5.0 <1.0.0",
|
|
44
44
|
"@pyreon/reactivity": ">=0.5.0 <1.0.0"
|
|
45
|
-
},
|
|
46
|
-
"devDependencies": {
|
|
47
|
-
"@happy-dom/global-registrator": "^20.8.3",
|
|
48
|
-
"@pyreon/core": ">=0.5.0 <1.0.0",
|
|
49
|
-
"@pyreon/reactivity": ">=0.5.0 <1.0.0",
|
|
50
|
-
"@vitus-labs/tools-lint": "^1.11.0"
|
|
51
45
|
}
|
|
52
46
|
}
|
package/src/context.ts
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createContext,
|
|
3
|
-
onUnmount,
|
|
4
|
-
popContext,
|
|
5
|
-
pushContext,
|
|
6
|
-
useContext,
|
|
7
|
-
} from '@pyreon/core'
|
|
1
|
+
import { createContext, provide, useContext } from '@pyreon/core'
|
|
8
2
|
import type { VNodeChild } from '@pyreon/core'
|
|
9
3
|
import type { Permissions } from './types'
|
|
10
4
|
|
|
@@ -27,11 +21,7 @@ export function PermissionsProvider(props: {
|
|
|
27
21
|
instance: Permissions
|
|
28
22
|
children?: VNodeChild
|
|
29
23
|
}): VNodeChild {
|
|
30
|
-
|
|
31
|
-
[PermissionsContext.id, props.instance],
|
|
32
|
-
])
|
|
33
|
-
pushContext(frame)
|
|
34
|
-
onUnmount(() => popContext())
|
|
24
|
+
provide(PermissionsContext, props.instance)
|
|
35
25
|
|
|
36
26
|
return props.children ?? null
|
|
37
27
|
}
|
|
@@ -50,7 +40,7 @@ export function usePermissions(): Permissions {
|
|
|
50
40
|
const instance = useContext(PermissionsContext)
|
|
51
41
|
if (!instance) {
|
|
52
42
|
throw new Error(
|
|
53
|
-
'[@pyreon/permissions] usePermissions() must be used within <PermissionsProvider
|
|
43
|
+
'[@pyreon/permissions] usePermissions() must be used within <PermissionsProvider>.',
|
|
54
44
|
)
|
|
55
45
|
}
|
|
56
46
|
return instance
|