@bizapps/design-system-testing 1.0.11 → 1.6.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/dist/editor.cjs +1242 -0
- package/dist/editor.cjs.map +1 -0
- package/dist/editor.d.cts +318 -0
- package/dist/editor.d.ts +318 -0
- package/dist/editor.js +1231 -0
- package/dist/editor.js.map +1 -0
- package/dist/main.cjs +1663 -462
- package/dist/main.cjs.map +1 -1
- package/dist/main.css +1 -1
- package/dist/main.d.cts +283 -64
- package/dist/main.d.ts +283 -64
- package/dist/main.js +1628 -464
- package/dist/main.js.map +1 -1
- package/dist/phone.cjs +18 -0
- package/dist/phone.cjs.map +1 -0
- package/dist/phone.d.cts +28 -0
- package/dist/phone.d.ts +28 -0
- package/dist/phone.js +16 -0
- package/dist/phone.js.map +1 -0
- package/dist/policy-DPpMNLiO.d.cts +75 -0
- package/dist/policy-DPpMNLiO.d.ts +75 -0
- package/dist/policy.cjs +33 -0
- package/dist/policy.cjs.map +1 -0
- package/dist/policy.d.cts +1 -0
- package/dist/policy.d.ts +1 -0
- package/dist/policy.js +29 -0
- package/dist/policy.js.map +1 -0
- package/package.json +85 -15
package/dist/phone.cjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var libphonenumberJs = require('libphonenumber-js');
|
|
4
|
+
|
|
5
|
+
// src/lib/phone.ts
|
|
6
|
+
function validatePhone(value) {
|
|
7
|
+
if (!value) {
|
|
8
|
+
return { isValid: false };
|
|
9
|
+
}
|
|
10
|
+
if (libphonenumberJs.isValidPhoneNumber(value)) {
|
|
11
|
+
return { isValid: true };
|
|
12
|
+
}
|
|
13
|
+
return { isValid: false, problem: libphonenumberJs.validatePhoneNumberLength(value) ?? "INVALID" };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
exports.validatePhone = validatePhone;
|
|
17
|
+
//# sourceMappingURL=phone.cjs.map
|
|
18
|
+
//# sourceMappingURL=phone.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/phone.ts"],"names":["isValidPhoneNumber","validatePhoneNumberLength"],"mappings":";;;;;AAmCO,SAAS,cAAc,KAAA,EAAmC;AAC7D,EAAA,IAAI,CAAC,KAAA,EAAO;AACR,IAAA,OAAO,EAAE,SAAS,KAAA,EAAM;AAAA,EAC5B;AACA,EAAA,IAAIA,mCAAA,CAAmB,KAAK,CAAA,EAAG;AAC3B,IAAA,OAAO,EAAE,SAAS,IAAA,EAAK;AAAA,EAC3B;AACA,EAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,SAASC,0CAAA,CAA0B,KAAK,KAAK,SAAA,EAAU;AACpF","file":"phone.cjs","sourcesContent":["import { isValidPhoneNumber, validatePhoneNumberLength } from 'libphonenumber-js';\n\n/**\n * Why a value is not a valid phone number. Mirrors `libphonenumber-js`'\n * `validatePhoneNumberLength` result, plus `'INVALID'` for a value whose length\n * IS possible for its calling code but which is not a real number (e.g. an\n * 8-digit Colombian value: 8 is a possible fixed-line length, yet `3008...` is\n * not an assignable fixed-line prefix).\n *\n * The design system emits this code, never a message: the copy belongs to the\n * consumer's i18n catalog.\n */\nexport type PhoneFieldProblem =\n | 'TOO_SHORT'\n | 'TOO_LONG'\n | 'INVALID_LENGTH'\n | 'INVALID_COUNTRY'\n | 'NOT_A_NUMBER'\n | 'INVALID';\n\nexport interface PhoneFieldValidity {\n /** True only when the value is a valid, assignable number. */\n isValid: boolean;\n /** Why it is invalid. Absent for a valid value AND for an empty one. */\n problem?: PhoneFieldProblem;\n}\n\n/**\n * Validates an E.164 phone value. Pure and stateless — safe to share between\n * the field, a Zod schema and a server route handler so the rule is written\n * once.\n *\n * An empty value reports `{ isValid: false }` with no `problem`: emptiness is\n * the consumer's `required` rule, not a phone problem.\n */\nexport function validatePhone(value: string): PhoneFieldValidity {\n if (!value) {\n return { isValid: false };\n }\n if (isValidPhoneNumber(value)) {\n return { isValid: true };\n }\n return { isValid: false, problem: validatePhoneNumberLength(value) ?? 'INVALID' };\n}\n"]}
|
package/dist/phone.d.cts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why a value is not a valid phone number. Mirrors `libphonenumber-js`'
|
|
3
|
+
* `validatePhoneNumberLength` result, plus `'INVALID'` for a value whose length
|
|
4
|
+
* IS possible for its calling code but which is not a real number (e.g. an
|
|
5
|
+
* 8-digit Colombian value: 8 is a possible fixed-line length, yet `3008...` is
|
|
6
|
+
* not an assignable fixed-line prefix).
|
|
7
|
+
*
|
|
8
|
+
* The design system emits this code, never a message: the copy belongs to the
|
|
9
|
+
* consumer's i18n catalog.
|
|
10
|
+
*/
|
|
11
|
+
type PhoneFieldProblem = 'TOO_SHORT' | 'TOO_LONG' | 'INVALID_LENGTH' | 'INVALID_COUNTRY' | 'NOT_A_NUMBER' | 'INVALID';
|
|
12
|
+
interface PhoneFieldValidity {
|
|
13
|
+
/** True only when the value is a valid, assignable number. */
|
|
14
|
+
isValid: boolean;
|
|
15
|
+
/** Why it is invalid. Absent for a valid value AND for an empty one. */
|
|
16
|
+
problem?: PhoneFieldProblem;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Validates an E.164 phone value. Pure and stateless — safe to share between
|
|
20
|
+
* the field, a Zod schema and a server route handler so the rule is written
|
|
21
|
+
* once.
|
|
22
|
+
*
|
|
23
|
+
* An empty value reports `{ isValid: false }` with no `problem`: emptiness is
|
|
24
|
+
* the consumer's `required` rule, not a phone problem.
|
|
25
|
+
*/
|
|
26
|
+
declare function validatePhone(value: string): PhoneFieldValidity;
|
|
27
|
+
|
|
28
|
+
export { type PhoneFieldProblem, type PhoneFieldValidity, validatePhone };
|
package/dist/phone.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why a value is not a valid phone number. Mirrors `libphonenumber-js`'
|
|
3
|
+
* `validatePhoneNumberLength` result, plus `'INVALID'` for a value whose length
|
|
4
|
+
* IS possible for its calling code but which is not a real number (e.g. an
|
|
5
|
+
* 8-digit Colombian value: 8 is a possible fixed-line length, yet `3008...` is
|
|
6
|
+
* not an assignable fixed-line prefix).
|
|
7
|
+
*
|
|
8
|
+
* The design system emits this code, never a message: the copy belongs to the
|
|
9
|
+
* consumer's i18n catalog.
|
|
10
|
+
*/
|
|
11
|
+
type PhoneFieldProblem = 'TOO_SHORT' | 'TOO_LONG' | 'INVALID_LENGTH' | 'INVALID_COUNTRY' | 'NOT_A_NUMBER' | 'INVALID';
|
|
12
|
+
interface PhoneFieldValidity {
|
|
13
|
+
/** True only when the value is a valid, assignable number. */
|
|
14
|
+
isValid: boolean;
|
|
15
|
+
/** Why it is invalid. Absent for a valid value AND for an empty one. */
|
|
16
|
+
problem?: PhoneFieldProblem;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Validates an E.164 phone value. Pure and stateless — safe to share between
|
|
20
|
+
* the field, a Zod schema and a server route handler so the rule is written
|
|
21
|
+
* once.
|
|
22
|
+
*
|
|
23
|
+
* An empty value reports `{ isValid: false }` with no `problem`: emptiness is
|
|
24
|
+
* the consumer's `required` rule, not a phone problem.
|
|
25
|
+
*/
|
|
26
|
+
declare function validatePhone(value: string): PhoneFieldValidity;
|
|
27
|
+
|
|
28
|
+
export { type PhoneFieldProblem, type PhoneFieldValidity, validatePhone };
|
package/dist/phone.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { isValidPhoneNumber, validatePhoneNumberLength } from 'libphonenumber-js';
|
|
2
|
+
|
|
3
|
+
// src/lib/phone.ts
|
|
4
|
+
function validatePhone(value) {
|
|
5
|
+
if (!value) {
|
|
6
|
+
return { isValid: false };
|
|
7
|
+
}
|
|
8
|
+
if (isValidPhoneNumber(value)) {
|
|
9
|
+
return { isValid: true };
|
|
10
|
+
}
|
|
11
|
+
return { isValid: false, problem: validatePhoneNumberLength(value) ?? "INVALID" };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { validatePhone };
|
|
15
|
+
//# sourceMappingURL=phone.js.map
|
|
16
|
+
//# sourceMappingURL=phone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/phone.ts"],"names":[],"mappings":";;;AAmCO,SAAS,cAAc,KAAA,EAAmC;AAC7D,EAAA,IAAI,CAAC,KAAA,EAAO;AACR,IAAA,OAAO,EAAE,SAAS,KAAA,EAAM;AAAA,EAC5B;AACA,EAAA,IAAI,kBAAA,CAAmB,KAAK,CAAA,EAAG;AAC3B,IAAA,OAAO,EAAE,SAAS,IAAA,EAAK;AAAA,EAC3B;AACA,EAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,SAAS,yBAAA,CAA0B,KAAK,KAAK,SAAA,EAAU;AACpF","file":"phone.js","sourcesContent":["import { isValidPhoneNumber, validatePhoneNumberLength } from 'libphonenumber-js';\n\n/**\n * Why a value is not a valid phone number. Mirrors `libphonenumber-js`'\n * `validatePhoneNumberLength` result, plus `'INVALID'` for a value whose length\n * IS possible for its calling code but which is not a real number (e.g. an\n * 8-digit Colombian value: 8 is a possible fixed-line length, yet `3008...` is\n * not an assignable fixed-line prefix).\n *\n * The design system emits this code, never a message: the copy belongs to the\n * consumer's i18n catalog.\n */\nexport type PhoneFieldProblem =\n | 'TOO_SHORT'\n | 'TOO_LONG'\n | 'INVALID_LENGTH'\n | 'INVALID_COUNTRY'\n | 'NOT_A_NUMBER'\n | 'INVALID';\n\nexport interface PhoneFieldValidity {\n /** True only when the value is a valid, assignable number. */\n isValid: boolean;\n /** Why it is invalid. Absent for a valid value AND for an empty one. */\n problem?: PhoneFieldProblem;\n}\n\n/**\n * Validates an E.164 phone value. Pure and stateless — safe to share between\n * the field, a Zod schema and a server route handler so the rule is written\n * once.\n *\n * An empty value reports `{ isValid: false }` with no `problem`: emptiness is\n * the consumer's `required` rule, not a phone problem.\n */\nexport function validatePhone(value: string): PhoneFieldValidity {\n if (!value) {\n return { isValid: false };\n }\n if (isValidPhoneNumber(value)) {\n return { isValid: true };\n }\n return { isValid: false, problem: validatePhoneNumberLength(value) ?? 'INVALID' };\n}\n"]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUTO-GENERATED — do not edit by hand.
|
|
3
|
+
*
|
|
4
|
+
* Regenerate with `pnpm generate-permissions`, which reads the catalog from the
|
|
5
|
+
* Nexus backend. The list is committed so the library build never depends on a
|
|
6
|
+
* live backend call.
|
|
7
|
+
*
|
|
8
|
+
* While this list is empty, `Permission` degrades to plain `string` and the
|
|
9
|
+
* development-time unknown-permission warning is skipped entirely — an empty
|
|
10
|
+
* catalog must never produce false positives.
|
|
11
|
+
*/
|
|
12
|
+
declare const KNOWN_PERMISSIONS: readonly [];
|
|
13
|
+
type KnownPermission = (typeof KNOWN_PERMISSIONS)[number];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A permission string in `resource.action` or `module.resource.action`
|
|
17
|
+
* dot-notation, lowercase, with `*` as a segment wildcard and a bare `*` as the
|
|
18
|
+
* super-grant.
|
|
19
|
+
*
|
|
20
|
+
* Known catalog entries are suggested by autocomplete; any other string is still
|
|
21
|
+
* accepted, so a permission the catalog has not caught up with never blocks a
|
|
22
|
+
* build. The `(string & {})` half is the TypeScript idiom that keeps the literal
|
|
23
|
+
* suggestions from collapsing into plain `string`.
|
|
24
|
+
*/
|
|
25
|
+
type Permission = KnownPermission | (string & {});
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The server-safe half of the authorization system.
|
|
29
|
+
*
|
|
30
|
+
* Everything in this module is a pure function over plain data: no React, no hooks, no
|
|
31
|
+
* context, no module-level mutable state. That is not incidental — it is the contract.
|
|
32
|
+
* `src/policy.ts` re-exports this file as the `@bizapps/ui/policy` entry point, which
|
|
33
|
+
* tsup deliberately does NOT stamp with `"use client"`, so a Next.js Server Component,
|
|
34
|
+
* Route Handler or Server Action can import it and evaluate permissions on the server.
|
|
35
|
+
*
|
|
36
|
+
* **Never import React (or anything that transitively does) into this file.** The build
|
|
37
|
+
* asserts it: `tsup.config.ts` fails if `dist/policy.js` contains a react import or a
|
|
38
|
+
* `"use client"` directive. Breaking that turns every server-side caller into a client
|
|
39
|
+
* reference, silently.
|
|
40
|
+
*
|
|
41
|
+
* The client half — `AbilityProvider`, `useAbility`, `useCan`, `Can` — consumes these
|
|
42
|
+
* same functions, so there is exactly one implementation of the matching rules. Two
|
|
43
|
+
* implementations of an authorization primitive drift, and drift on a security boundary
|
|
44
|
+
* is invisible until it matters.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Tests one entry of the user's grant set against one requested permission.
|
|
49
|
+
*
|
|
50
|
+
* @param pattern - an entry from the user's grant set; may contain `*` as a segment
|
|
51
|
+
* wildcard, or be a bare `*` meaning "everything"
|
|
52
|
+
* @param permission - the concrete permission being requested
|
|
53
|
+
*
|
|
54
|
+
* Matching is arity-strict: a grant of `users.*` covers `users.delete`, but a grant of
|
|
55
|
+
* `users` does NOT, and neither covers `users.delete.confirm`. That rules out the
|
|
56
|
+
* ambiguity of whether `users` names the resource or the namespace.
|
|
57
|
+
*/
|
|
58
|
+
declare function matchPermission(pattern: string, permission: string): boolean;
|
|
59
|
+
/** Whether any entry in the grant set covers the requested permission. */
|
|
60
|
+
declare function matchesAny(permissionSet: Set<string>, permission: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Evaluates a permission requirement against a grant set.
|
|
63
|
+
*
|
|
64
|
+
* The order of the first two checks is load-bearing and must not be swapped: an empty
|
|
65
|
+
* required list denies **even for a super-grant holder**, because an empty list means
|
|
66
|
+
* "nothing satisfies this", not "anything does".
|
|
67
|
+
*
|
|
68
|
+
* @param permissionSet - the user's grants
|
|
69
|
+
* @param perms - the permission(s) required
|
|
70
|
+
* @param mode - with an array, `'any'` (default) passes when at least one matches,
|
|
71
|
+
* `'all'` requires every one
|
|
72
|
+
*/
|
|
73
|
+
declare function can(permissionSet: Set<string>, perms: Permission | Permission[], mode?: 'any' | 'all'): boolean;
|
|
74
|
+
|
|
75
|
+
export { KNOWN_PERMISSIONS as K, type Permission as P, type KnownPermission as a, matchesAny as b, can as c, matchPermission as m };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUTO-GENERATED — do not edit by hand.
|
|
3
|
+
*
|
|
4
|
+
* Regenerate with `pnpm generate-permissions`, which reads the catalog from the
|
|
5
|
+
* Nexus backend. The list is committed so the library build never depends on a
|
|
6
|
+
* live backend call.
|
|
7
|
+
*
|
|
8
|
+
* While this list is empty, `Permission` degrades to plain `string` and the
|
|
9
|
+
* development-time unknown-permission warning is skipped entirely — an empty
|
|
10
|
+
* catalog must never produce false positives.
|
|
11
|
+
*/
|
|
12
|
+
declare const KNOWN_PERMISSIONS: readonly [];
|
|
13
|
+
type KnownPermission = (typeof KNOWN_PERMISSIONS)[number];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A permission string in `resource.action` or `module.resource.action`
|
|
17
|
+
* dot-notation, lowercase, with `*` as a segment wildcard and a bare `*` as the
|
|
18
|
+
* super-grant.
|
|
19
|
+
*
|
|
20
|
+
* Known catalog entries are suggested by autocomplete; any other string is still
|
|
21
|
+
* accepted, so a permission the catalog has not caught up with never blocks a
|
|
22
|
+
* build. The `(string & {})` half is the TypeScript idiom that keeps the literal
|
|
23
|
+
* suggestions from collapsing into plain `string`.
|
|
24
|
+
*/
|
|
25
|
+
type Permission = KnownPermission | (string & {});
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The server-safe half of the authorization system.
|
|
29
|
+
*
|
|
30
|
+
* Everything in this module is a pure function over plain data: no React, no hooks, no
|
|
31
|
+
* context, no module-level mutable state. That is not incidental — it is the contract.
|
|
32
|
+
* `src/policy.ts` re-exports this file as the `@bizapps/ui/policy` entry point, which
|
|
33
|
+
* tsup deliberately does NOT stamp with `"use client"`, so a Next.js Server Component,
|
|
34
|
+
* Route Handler or Server Action can import it and evaluate permissions on the server.
|
|
35
|
+
*
|
|
36
|
+
* **Never import React (or anything that transitively does) into this file.** The build
|
|
37
|
+
* asserts it: `tsup.config.ts` fails if `dist/policy.js` contains a react import or a
|
|
38
|
+
* `"use client"` directive. Breaking that turns every server-side caller into a client
|
|
39
|
+
* reference, silently.
|
|
40
|
+
*
|
|
41
|
+
* The client half — `AbilityProvider`, `useAbility`, `useCan`, `Can` — consumes these
|
|
42
|
+
* same functions, so there is exactly one implementation of the matching rules. Two
|
|
43
|
+
* implementations of an authorization primitive drift, and drift on a security boundary
|
|
44
|
+
* is invisible until it matters.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Tests one entry of the user's grant set against one requested permission.
|
|
49
|
+
*
|
|
50
|
+
* @param pattern - an entry from the user's grant set; may contain `*` as a segment
|
|
51
|
+
* wildcard, or be a bare `*` meaning "everything"
|
|
52
|
+
* @param permission - the concrete permission being requested
|
|
53
|
+
*
|
|
54
|
+
* Matching is arity-strict: a grant of `users.*` covers `users.delete`, but a grant of
|
|
55
|
+
* `users` does NOT, and neither covers `users.delete.confirm`. That rules out the
|
|
56
|
+
* ambiguity of whether `users` names the resource or the namespace.
|
|
57
|
+
*/
|
|
58
|
+
declare function matchPermission(pattern: string, permission: string): boolean;
|
|
59
|
+
/** Whether any entry in the grant set covers the requested permission. */
|
|
60
|
+
declare function matchesAny(permissionSet: Set<string>, permission: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Evaluates a permission requirement against a grant set.
|
|
63
|
+
*
|
|
64
|
+
* The order of the first two checks is load-bearing and must not be swapped: an empty
|
|
65
|
+
* required list denies **even for a super-grant holder**, because an empty list means
|
|
66
|
+
* "nothing satisfies this", not "anything does".
|
|
67
|
+
*
|
|
68
|
+
* @param permissionSet - the user's grants
|
|
69
|
+
* @param perms - the permission(s) required
|
|
70
|
+
* @param mode - with an array, `'any'` (default) passes when at least one matches,
|
|
71
|
+
* `'all'` requires every one
|
|
72
|
+
*/
|
|
73
|
+
declare function can(permissionSet: Set<string>, perms: Permission | Permission[], mode?: 'any' | 'all'): boolean;
|
|
74
|
+
|
|
75
|
+
export { KNOWN_PERMISSIONS as K, type Permission as P, type KnownPermission as a, matchesAny as b, can as c, matchPermission as m };
|
package/dist/policy.cjs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/components/authorization/policy.ts
|
|
4
|
+
function matchPermission(pattern, permission) {
|
|
5
|
+
if (pattern === "*") return true;
|
|
6
|
+
if (pattern === permission) return true;
|
|
7
|
+
const patternParts = pattern.split(".");
|
|
8
|
+
const permParts = permission.split(".");
|
|
9
|
+
if (patternParts.length !== permParts.length) return false;
|
|
10
|
+
return patternParts.every((part, i) => part === "*" || part === permParts[i]);
|
|
11
|
+
}
|
|
12
|
+
function matchesAny(permissionSet, permission) {
|
|
13
|
+
if (permissionSet.has(permission)) return true;
|
|
14
|
+
for (const pattern of permissionSet) {
|
|
15
|
+
if (matchPermission(pattern, permission)) return true;
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
function can(permissionSet, perms, mode = "any") {
|
|
20
|
+
const list = Array.isArray(perms) ? perms : [perms];
|
|
21
|
+
if (list.length === 0) return false;
|
|
22
|
+
if (permissionSet.has("*")) return true;
|
|
23
|
+
if (mode === "all") {
|
|
24
|
+
return list.every((p) => matchesAny(permissionSet, p));
|
|
25
|
+
}
|
|
26
|
+
return list.some((p) => matchesAny(permissionSet, p));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.can = can;
|
|
30
|
+
exports.matchPermission = matchPermission;
|
|
31
|
+
exports.matchesAny = matchesAny;
|
|
32
|
+
//# sourceMappingURL=policy.cjs.map
|
|
33
|
+
//# sourceMappingURL=policy.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/authorization/policy.ts"],"names":[],"mappings":";;;AAgCA,SAAS,eAAA,CAAgB,SAAiB,UAAA,EAA6B;AACnE,EAAA,IAAI,OAAA,KAAY,KAAK,OAAO,IAAA;AAC5B,EAAA,IAAI,OAAA,KAAY,YAAY,OAAO,IAAA;AACnC,EAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,KAAA,CAAM,GAAG,CAAA;AACtC,EAAA,MAAM,SAAA,GAAY,UAAA,CAAW,KAAA,CAAM,GAAG,CAAA;AACtC,EAAA,IAAI,YAAA,CAAa,MAAA,KAAW,SAAA,CAAU,MAAA,EAAQ,OAAO,KAAA;AACrD,EAAA,OAAO,YAAA,CAAa,KAAA,CAAM,CAAC,IAAA,EAAM,CAAA,KAAM,SAAS,GAAA,IAAO,IAAA,KAAS,SAAA,CAAU,CAAC,CAAC,CAAA;AAChF;AAGA,SAAS,UAAA,CAAW,eAA4B,UAAA,EAA6B;AACzE,EAAA,IAAI,aAAA,CAAc,GAAA,CAAI,UAAU,CAAA,EAAG,OAAO,IAAA;AAC1C,EAAA,KAAA,MAAW,WAAW,aAAA,EAAe;AACjC,IAAA,IAAI,eAAA,CAAgB,OAAA,EAAS,UAAU,CAAA,EAAG,OAAO,IAAA;AAAA,EACrD;AACA,EAAA,OAAO,KAAA;AACX;AAcA,SAAS,GAAA,CACL,aAAA,EACA,KAAA,EACA,IAAA,GAAsB,KAAA,EACf;AACP,EAAA,MAAM,OAAO,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAAI,KAAA,GAAQ,CAAC,KAAK,CAAA;AAClD,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AAC9B,EAAA,IAAI,aAAA,CAAc,GAAA,CAAI,GAAG,CAAA,EAAG,OAAO,IAAA;AACnC,EAAA,IAAI,SAAS,KAAA,EAAO;AAChB,IAAA,OAAO,KAAK,KAAA,CAAM,CAAC,MAAM,UAAA,CAAW,aAAA,EAAe,CAAC,CAAC,CAAA;AAAA,EACzD;AACA,EAAA,OAAO,KAAK,IAAA,CAAK,CAAC,MAAM,UAAA,CAAW,aAAA,EAAe,CAAC,CAAC,CAAA;AACxD","file":"policy.cjs","sourcesContent":["/**\n * The server-safe half of the authorization system.\n *\n * Everything in this module is a pure function over plain data: no React, no hooks, no\n * context, no module-level mutable state. That is not incidental — it is the contract.\n * `src/policy.ts` re-exports this file as the `@bizapps/ui/policy` entry point, which\n * tsup deliberately does NOT stamp with `\"use client\"`, so a Next.js Server Component,\n * Route Handler or Server Action can import it and evaluate permissions on the server.\n *\n * **Never import React (or anything that transitively does) into this file.** The build\n * asserts it: `tsup.config.ts` fails if `dist/policy.js` contains a react import or a\n * `\"use client\"` directive. Breaking that turns every server-side caller into a client\n * reference, silently.\n *\n * The client half — `AbilityProvider`, `useAbility`, `useCan`, `Can` — consumes these\n * same functions, so there is exactly one implementation of the matching rules. Two\n * implementations of an authorization primitive drift, and drift on a security boundary\n * is invisible until it matters.\n */\nimport type { Permission } from './permission-catalog';\n\n/**\n * Tests one entry of the user's grant set against one requested permission.\n *\n * @param pattern - an entry from the user's grant set; may contain `*` as a segment\n * wildcard, or be a bare `*` meaning \"everything\"\n * @param permission - the concrete permission being requested\n *\n * Matching is arity-strict: a grant of `users.*` covers `users.delete`, but a grant of\n * `users` does NOT, and neither covers `users.delete.confirm`. That rules out the\n * ambiguity of whether `users` names the resource or the namespace.\n */\nfunction matchPermission(pattern: string, permission: string): boolean {\n if (pattern === '*') return true;\n if (pattern === permission) return true;\n const patternParts = pattern.split('.');\n const permParts = permission.split('.');\n if (patternParts.length !== permParts.length) return false;\n return patternParts.every((part, i) => part === '*' || part === permParts[i]);\n}\n\n/** Whether any entry in the grant set covers the requested permission. */\nfunction matchesAny(permissionSet: Set<string>, permission: string): boolean {\n if (permissionSet.has(permission)) return true;\n for (const pattern of permissionSet) {\n if (matchPermission(pattern, permission)) return true;\n }\n return false;\n}\n\n/**\n * Evaluates a permission requirement against a grant set.\n *\n * The order of the first two checks is load-bearing and must not be swapped: an empty\n * required list denies **even for a super-grant holder**, because an empty list means\n * \"nothing satisfies this\", not \"anything does\".\n *\n * @param permissionSet - the user's grants\n * @param perms - the permission(s) required\n * @param mode - with an array, `'any'` (default) passes when at least one matches,\n * `'all'` requires every one\n */\nfunction can(\n permissionSet: Set<string>,\n perms: Permission | Permission[],\n mode: 'any' | 'all' = 'any',\n): boolean {\n const list = Array.isArray(perms) ? perms : [perms];\n if (list.length === 0) return false;\n if (permissionSet.has('*')) return true;\n if (mode === 'all') {\n return list.every((p) => matchesAny(permissionSet, p));\n }\n return list.some((p) => matchesAny(permissionSet, p));\n}\n\nexport { can, matchPermission, matchesAny };\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { P as Permission, c as can, m as matchPermission, b as matchesAny } from './policy-DPpMNLiO.cjs';
|
package/dist/policy.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { P as Permission, c as can, m as matchPermission, b as matchesAny } from './policy-DPpMNLiO.js';
|
package/dist/policy.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// src/components/authorization/policy.ts
|
|
2
|
+
function matchPermission(pattern, permission) {
|
|
3
|
+
if (pattern === "*") return true;
|
|
4
|
+
if (pattern === permission) return true;
|
|
5
|
+
const patternParts = pattern.split(".");
|
|
6
|
+
const permParts = permission.split(".");
|
|
7
|
+
if (patternParts.length !== permParts.length) return false;
|
|
8
|
+
return patternParts.every((part, i) => part === "*" || part === permParts[i]);
|
|
9
|
+
}
|
|
10
|
+
function matchesAny(permissionSet, permission) {
|
|
11
|
+
if (permissionSet.has(permission)) return true;
|
|
12
|
+
for (const pattern of permissionSet) {
|
|
13
|
+
if (matchPermission(pattern, permission)) return true;
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
function can(permissionSet, perms, mode = "any") {
|
|
18
|
+
const list = Array.isArray(perms) ? perms : [perms];
|
|
19
|
+
if (list.length === 0) return false;
|
|
20
|
+
if (permissionSet.has("*")) return true;
|
|
21
|
+
if (mode === "all") {
|
|
22
|
+
return list.every((p) => matchesAny(permissionSet, p));
|
|
23
|
+
}
|
|
24
|
+
return list.some((p) => matchesAny(permissionSet, p));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { can, matchPermission, matchesAny };
|
|
28
|
+
//# sourceMappingURL=policy.js.map
|
|
29
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/authorization/policy.ts"],"names":[],"mappings":";AAgCA,SAAS,eAAA,CAAgB,SAAiB,UAAA,EAA6B;AACnE,EAAA,IAAI,OAAA,KAAY,KAAK,OAAO,IAAA;AAC5B,EAAA,IAAI,OAAA,KAAY,YAAY,OAAO,IAAA;AACnC,EAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,KAAA,CAAM,GAAG,CAAA;AACtC,EAAA,MAAM,SAAA,GAAY,UAAA,CAAW,KAAA,CAAM,GAAG,CAAA;AACtC,EAAA,IAAI,YAAA,CAAa,MAAA,KAAW,SAAA,CAAU,MAAA,EAAQ,OAAO,KAAA;AACrD,EAAA,OAAO,YAAA,CAAa,KAAA,CAAM,CAAC,IAAA,EAAM,CAAA,KAAM,SAAS,GAAA,IAAO,IAAA,KAAS,SAAA,CAAU,CAAC,CAAC,CAAA;AAChF;AAGA,SAAS,UAAA,CAAW,eAA4B,UAAA,EAA6B;AACzE,EAAA,IAAI,aAAA,CAAc,GAAA,CAAI,UAAU,CAAA,EAAG,OAAO,IAAA;AAC1C,EAAA,KAAA,MAAW,WAAW,aAAA,EAAe;AACjC,IAAA,IAAI,eAAA,CAAgB,OAAA,EAAS,UAAU,CAAA,EAAG,OAAO,IAAA;AAAA,EACrD;AACA,EAAA,OAAO,KAAA;AACX;AAcA,SAAS,GAAA,CACL,aAAA,EACA,KAAA,EACA,IAAA,GAAsB,KAAA,EACf;AACP,EAAA,MAAM,OAAO,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAAI,KAAA,GAAQ,CAAC,KAAK,CAAA;AAClD,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AAC9B,EAAA,IAAI,aAAA,CAAc,GAAA,CAAI,GAAG,CAAA,EAAG,OAAO,IAAA;AACnC,EAAA,IAAI,SAAS,KAAA,EAAO;AAChB,IAAA,OAAO,KAAK,KAAA,CAAM,CAAC,MAAM,UAAA,CAAW,aAAA,EAAe,CAAC,CAAC,CAAA;AAAA,EACzD;AACA,EAAA,OAAO,KAAK,IAAA,CAAK,CAAC,MAAM,UAAA,CAAW,aAAA,EAAe,CAAC,CAAC,CAAA;AACxD","file":"policy.js","sourcesContent":["/**\n * The server-safe half of the authorization system.\n *\n * Everything in this module is a pure function over plain data: no React, no hooks, no\n * context, no module-level mutable state. That is not incidental — it is the contract.\n * `src/policy.ts` re-exports this file as the `@bizapps/ui/policy` entry point, which\n * tsup deliberately does NOT stamp with `\"use client\"`, so a Next.js Server Component,\n * Route Handler or Server Action can import it and evaluate permissions on the server.\n *\n * **Never import React (or anything that transitively does) into this file.** The build\n * asserts it: `tsup.config.ts` fails if `dist/policy.js` contains a react import or a\n * `\"use client\"` directive. Breaking that turns every server-side caller into a client\n * reference, silently.\n *\n * The client half — `AbilityProvider`, `useAbility`, `useCan`, `Can` — consumes these\n * same functions, so there is exactly one implementation of the matching rules. Two\n * implementations of an authorization primitive drift, and drift on a security boundary\n * is invisible until it matters.\n */\nimport type { Permission } from './permission-catalog';\n\n/**\n * Tests one entry of the user's grant set against one requested permission.\n *\n * @param pattern - an entry from the user's grant set; may contain `*` as a segment\n * wildcard, or be a bare `*` meaning \"everything\"\n * @param permission - the concrete permission being requested\n *\n * Matching is arity-strict: a grant of `users.*` covers `users.delete`, but a grant of\n * `users` does NOT, and neither covers `users.delete.confirm`. That rules out the\n * ambiguity of whether `users` names the resource or the namespace.\n */\nfunction matchPermission(pattern: string, permission: string): boolean {\n if (pattern === '*') return true;\n if (pattern === permission) return true;\n const patternParts = pattern.split('.');\n const permParts = permission.split('.');\n if (patternParts.length !== permParts.length) return false;\n return patternParts.every((part, i) => part === '*' || part === permParts[i]);\n}\n\n/** Whether any entry in the grant set covers the requested permission. */\nfunction matchesAny(permissionSet: Set<string>, permission: string): boolean {\n if (permissionSet.has(permission)) return true;\n for (const pattern of permissionSet) {\n if (matchPermission(pattern, permission)) return true;\n }\n return false;\n}\n\n/**\n * Evaluates a permission requirement against a grant set.\n *\n * The order of the first two checks is load-bearing and must not be swapped: an empty\n * required list denies **even for a super-grant holder**, because an empty list means\n * \"nothing satisfies this\", not \"anything does\".\n *\n * @param permissionSet - the user's grants\n * @param perms - the permission(s) required\n * @param mode - with an array, `'any'` (default) passes when at least one matches,\n * `'all'` requires every one\n */\nfunction can(\n permissionSet: Set<string>,\n perms: Permission | Permission[],\n mode: 'any' | 'all' = 'any',\n): boolean {\n const list = Array.isArray(perms) ? perms : [perms];\n if (list.length === 0) return false;\n if (permissionSet.has('*')) return true;\n if (mode === 'all') {\n return list.every((p) => matchesAny(permissionSet, p));\n }\n return list.some((p) => matchesAny(permissionSet, p));\n}\n\nexport { can, matchPermission, matchesAny };\n"]}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.0
|
|
6
|
+
"version": "1.6.0",
|
|
7
7
|
"description": "This package provides reusable UI components to ensure consistency across all CRM frontend applications",
|
|
8
8
|
"author": "BizAppsTotal <bizapps@tcce.biz>",
|
|
9
9
|
"type": "module",
|
|
@@ -19,17 +19,24 @@
|
|
|
19
19
|
"import": "./dist/main.js",
|
|
20
20
|
"require": "./dist/main.cjs"
|
|
21
21
|
},
|
|
22
|
+
"./policy": {
|
|
23
|
+
"types": "./dist/policy.d.ts",
|
|
24
|
+
"import": "./dist/policy.js",
|
|
25
|
+
"require": "./dist/policy.cjs"
|
|
26
|
+
},
|
|
27
|
+
"./phone": {
|
|
28
|
+
"types": "./dist/phone.d.ts",
|
|
29
|
+
"import": "./dist/phone.js",
|
|
30
|
+
"require": "./dist/phone.cjs"
|
|
31
|
+
},
|
|
32
|
+
"./editor": {
|
|
33
|
+
"types": "./dist/editor.d.ts",
|
|
34
|
+
"import": "./dist/editor.js",
|
|
35
|
+
"require": "./dist/editor.cjs"
|
|
36
|
+
},
|
|
22
37
|
"./styles": "./dist/main.css"
|
|
23
38
|
},
|
|
24
39
|
"peerDependencies": {
|
|
25
|
-
"@tanstack/react-table": "^8.21.3",
|
|
26
|
-
"motion": "^12.23.13",
|
|
27
|
-
"react": "^19.1.1",
|
|
28
|
-
"react-dom": "^19.1.1",
|
|
29
|
-
"react-hook-form": "^7.77.0",
|
|
30
|
-
"radix-ui": "^1.4.3",
|
|
31
|
-
"lucide-react": "^1.16.0",
|
|
32
|
-
"next-themes": "^0.4.6",
|
|
33
40
|
"@hookform/resolvers": "^5.4.0",
|
|
34
41
|
"@schedule-x/calendar": "4.6.0",
|
|
35
42
|
"@schedule-x/calendar-controls": "4.6.0",
|
|
@@ -37,10 +44,26 @@
|
|
|
37
44
|
"@schedule-x/events-service": "4.6.0",
|
|
38
45
|
"@schedule-x/react": "4.1.0",
|
|
39
46
|
"@schedule-x/theme-default": "4.6.0",
|
|
40
|
-
"react-
|
|
47
|
+
"@tanstack/react-table": "^8.21.3",
|
|
48
|
+
"@tiptap/core": "^3.29.2",
|
|
49
|
+
"@tiptap/extension-highlight": "^3.29.2",
|
|
50
|
+
"@tiptap/extension-image": "^3.29.2",
|
|
51
|
+
"@tiptap/extension-link": "^3.29.2",
|
|
52
|
+
"@tiptap/extension-table": "^3.29.2",
|
|
53
|
+
"@tiptap/pm": "^3.29.2",
|
|
54
|
+
"@tiptap/react": "^3.29.2",
|
|
55
|
+
"@tiptap/starter-kit": "^3.29.2",
|
|
41
56
|
"embla-carousel-react": "^8.6.0",
|
|
42
|
-
"
|
|
43
|
-
"
|
|
57
|
+
"lucide-react": "^1.16.0",
|
|
58
|
+
"motion": "^12.23.13",
|
|
59
|
+
"next-themes": "^0.4.6",
|
|
60
|
+
"radix-ui": "^1.4.3",
|
|
61
|
+
"react": "^19.1.1",
|
|
62
|
+
"react-day-picker": "^10.0.1",
|
|
63
|
+
"react-dom": "^19.1.1",
|
|
64
|
+
"react-hook-form": "^7.77.0",
|
|
65
|
+
"sonner": "^2.0.7",
|
|
66
|
+
"zod": "^4.4.3"
|
|
44
67
|
},
|
|
45
68
|
"peerDependenciesMeta": {
|
|
46
69
|
"@hookform/resolvers": {
|
|
@@ -67,6 +90,30 @@
|
|
|
67
90
|
"@tanstack/react-table": {
|
|
68
91
|
"optional": true
|
|
69
92
|
},
|
|
93
|
+
"@tiptap/core": {
|
|
94
|
+
"optional": true
|
|
95
|
+
},
|
|
96
|
+
"@tiptap/extension-highlight": {
|
|
97
|
+
"optional": true
|
|
98
|
+
},
|
|
99
|
+
"@tiptap/extension-image": {
|
|
100
|
+
"optional": true
|
|
101
|
+
},
|
|
102
|
+
"@tiptap/extension-link": {
|
|
103
|
+
"optional": true
|
|
104
|
+
},
|
|
105
|
+
"@tiptap/extension-table": {
|
|
106
|
+
"optional": true
|
|
107
|
+
},
|
|
108
|
+
"@tiptap/pm": {
|
|
109
|
+
"optional": true
|
|
110
|
+
},
|
|
111
|
+
"@tiptap/react": {
|
|
112
|
+
"optional": true
|
|
113
|
+
},
|
|
114
|
+
"@tiptap/starter-kit": {
|
|
115
|
+
"optional": true
|
|
116
|
+
},
|
|
70
117
|
"embla-carousel-react": {
|
|
71
118
|
"optional": true
|
|
72
119
|
},
|
|
@@ -102,10 +149,23 @@
|
|
|
102
149
|
"@storybook/react-vite": "^10.2.17",
|
|
103
150
|
"@tailwindcss/vite": "^4.2.1",
|
|
104
151
|
"@tanstack/react-table": "^8.21.3",
|
|
152
|
+
"@testing-library/jest-dom": "^7.0.0",
|
|
153
|
+
"@testing-library/react": "^16.3.2",
|
|
154
|
+
"@testing-library/user-event": "^14.6.1",
|
|
155
|
+
"@tiptap/core": "3.29.2",
|
|
156
|
+
"@tiptap/extension-highlight": "3.29.2",
|
|
157
|
+
"@tiptap/extension-image": "3.29.2",
|
|
158
|
+
"@tiptap/extension-link": "3.29.2",
|
|
159
|
+
"@tiptap/extension-table": "3.29.2",
|
|
160
|
+
"@tiptap/pm": "3.29.2",
|
|
161
|
+
"@tiptap/react": "3.29.2",
|
|
162
|
+
"@tiptap/starter-kit": "3.29.2",
|
|
105
163
|
"@types/node": "^24.12.0",
|
|
106
164
|
"@types/react": "^19.2.14",
|
|
107
165
|
"@types/react-dom": "^19.2.3",
|
|
108
166
|
"@vitejs/plugin-react": "^5.1.4",
|
|
167
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
168
|
+
"axe-core": "^4.12.1",
|
|
109
169
|
"eslint": "^9.39.4",
|
|
110
170
|
"eslint-config-prettier": "^10.1.8",
|
|
111
171
|
"eslint-plugin-react": "^7.37.5",
|
|
@@ -113,6 +173,7 @@
|
|
|
113
173
|
"eslint-plugin-react-refresh": "^0.4.26",
|
|
114
174
|
"eslint-plugin-storybook": "^10.2.17",
|
|
115
175
|
"globals": "^16.5.0",
|
|
176
|
+
"jsdom": "^30.0.1",
|
|
116
177
|
"motion": "^12.40.0",
|
|
117
178
|
"prettier": "^3.8.1",
|
|
118
179
|
"prettier-plugin-tailwindcss": "^0.6.14",
|
|
@@ -123,19 +184,24 @@
|
|
|
123
184
|
"storybook": "^10.2.17",
|
|
124
185
|
"tailwindcss": "^4.2.1",
|
|
125
186
|
"ts-morph": "^24.0.0",
|
|
126
|
-
"tsx": "^4.19.4",
|
|
127
187
|
"tsup": "^8.5.1",
|
|
188
|
+
"tsx": "^4.19.4",
|
|
128
189
|
"typescript": "~5.8.3",
|
|
129
190
|
"typescript-eslint": "8.53.0",
|
|
130
191
|
"vite": "^7.3.1",
|
|
131
|
-
"vite-plugin-dts": "^4.5.4"
|
|
192
|
+
"vite-plugin-dts": "^4.5.4",
|
|
193
|
+
"vitest": "^4.1.10",
|
|
194
|
+
"vitest-axe": "^0.1.0",
|
|
195
|
+
"zod": "^4.4.3"
|
|
132
196
|
},
|
|
133
197
|
"dependencies": {
|
|
134
198
|
"class-variance-authority": "^0.7.1",
|
|
135
199
|
"clsx": "^2.1.1",
|
|
136
200
|
"cmdk": "^1.1.1",
|
|
137
201
|
"color": "^5.0.3",
|
|
202
|
+
"country-flag-icons": "^1.6.20",
|
|
138
203
|
"date-fns": "^4.4.0",
|
|
204
|
+
"libphonenumber-js": "^1.13.10",
|
|
139
205
|
"react-dropzone": "^15.0.0",
|
|
140
206
|
"tailwind-merge": "^3.6.0",
|
|
141
207
|
"temporal-polyfill": "0.3.2",
|
|
@@ -146,12 +212,16 @@
|
|
|
146
212
|
"build": "tsup && vite build --config vite.lib.config.ts",
|
|
147
213
|
"build:storybook": "storybook build",
|
|
148
214
|
"generate-catalog": "tsx scripts/generate-catalog.ts",
|
|
215
|
+
"generate-permissions": "tsx scripts/generate-permissions.ts",
|
|
149
216
|
"type-check": "tsc -p tsconfig.build.json --noEmit",
|
|
150
217
|
"lint": "eslint .",
|
|
151
218
|
"lint:fix": "eslint . --fix",
|
|
152
219
|
"format": "prettier --write .",
|
|
153
220
|
"preview": "vite preview",
|
|
154
221
|
"storybook": "storybook dev -p 6006 --host 0.0.0.0 --no-open",
|
|
155
|
-
"build-storybook": "storybook build"
|
|
222
|
+
"build-storybook": "storybook build",
|
|
223
|
+
"test": "vitest run",
|
|
224
|
+
"test:watch": "vitest",
|
|
225
|
+
"test:coverage": "vitest run --coverage"
|
|
156
226
|
}
|
|
157
227
|
}
|