toride 0.1.0 → 0.2.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/{chunk-QE4FJZEG.js → chunk-24PMDTLE.js} +61 -22
- package/dist/chunk-475CNU63.js +37 -0
- package/dist/cli.js +1 -1
- package/dist/client-RqwW0K_-.d.ts +368 -0
- package/dist/client.d.ts +1 -33
- package/dist/client.js +4 -32
- package/dist/index.d.ts +15 -240
- package/dist/index.js +5 -1
- package/package.json +7 -3
- package/dist/snapshot-CcCYeU0Q.d.ts +0 -8
|
@@ -54,6 +54,7 @@ var FieldAccessDefSchema = v.object({
|
|
|
54
54
|
var ResourceBlockSchema = v.object({
|
|
55
55
|
roles: v.array(v.string()),
|
|
56
56
|
permissions: v.array(v.string()),
|
|
57
|
+
attributes: v.optional(v.record(v.string(), AttributeTypeSchema)),
|
|
57
58
|
relations: v.optional(v.record(v.string(), v.string())),
|
|
58
59
|
grants: v.optional(v.record(v.string(), v.array(v.string()))),
|
|
59
60
|
derived_roles: v.optional(v.array(DerivedRoleEntrySchema)),
|
|
@@ -2031,8 +2032,11 @@ var Toride = class {
|
|
|
2031
2032
|
* Default-deny: returns false if resource type is unknown or no grants match.
|
|
2032
2033
|
*/
|
|
2033
2034
|
async can(actor, action, resource, options) {
|
|
2034
|
-
const
|
|
2035
|
-
|
|
2035
|
+
const a = actor;
|
|
2036
|
+
const r = resource;
|
|
2037
|
+
const act = action;
|
|
2038
|
+
const result = await this.evaluateInternal(a, act, r, options);
|
|
2039
|
+
this.fireDecisionEvent(a, act, r, result);
|
|
2036
2040
|
return result.allowed;
|
|
2037
2041
|
}
|
|
2038
2042
|
/**
|
|
@@ -2048,8 +2052,11 @@ var Toride = class {
|
|
|
2048
2052
|
* granted permissions, matched rules, and human-readable final decision.
|
|
2049
2053
|
*/
|
|
2050
2054
|
async explain(actor, action, resource, options) {
|
|
2051
|
-
const
|
|
2052
|
-
|
|
2055
|
+
const a = actor;
|
|
2056
|
+
const r = resource;
|
|
2057
|
+
const act = action;
|
|
2058
|
+
const result = await this.evaluateInternal(a, act, r, options);
|
|
2059
|
+
this.fireDecisionEvent(a, act, r, result);
|
|
2053
2060
|
return result;
|
|
2054
2061
|
}
|
|
2055
2062
|
/**
|
|
@@ -2057,7 +2064,9 @@ var Toride = class {
|
|
|
2057
2064
|
* Uses a shared cache across all per-action evaluations.
|
|
2058
2065
|
*/
|
|
2059
2066
|
async permittedActions(actor, resource, options) {
|
|
2060
|
-
const
|
|
2067
|
+
const a = actor;
|
|
2068
|
+
const r = resource;
|
|
2069
|
+
const resourceBlock = this.policy.resources[r.type];
|
|
2061
2070
|
if (!resourceBlock) {
|
|
2062
2071
|
return [];
|
|
2063
2072
|
}
|
|
@@ -2065,9 +2074,9 @@ var Toride = class {
|
|
|
2065
2074
|
const permitted = [];
|
|
2066
2075
|
for (const action of resourceBlock.permissions) {
|
|
2067
2076
|
const result = await this.evaluateInternal(
|
|
2068
|
-
|
|
2077
|
+
a,
|
|
2069
2078
|
action,
|
|
2070
|
-
|
|
2079
|
+
r,
|
|
2071
2080
|
options,
|
|
2072
2081
|
sharedCache
|
|
2073
2082
|
);
|
|
@@ -2084,7 +2093,12 @@ var Toride = class {
|
|
|
2084
2093
|
* Suitable for serializing to the client via TorideClient.
|
|
2085
2094
|
*/
|
|
2086
2095
|
async snapshot(actor, resources, options) {
|
|
2087
|
-
return snapshot(
|
|
2096
|
+
return snapshot(
|
|
2097
|
+
this,
|
|
2098
|
+
actor,
|
|
2099
|
+
resources,
|
|
2100
|
+
options
|
|
2101
|
+
);
|
|
2088
2102
|
}
|
|
2089
2103
|
/**
|
|
2090
2104
|
* T095: Check if an actor can perform a field-level operation on a specific field.
|
|
@@ -2092,33 +2106,52 @@ var Toride = class {
|
|
|
2092
2106
|
* Unlisted fields are unrestricted: any actor with the resource-level permission can access them.
|
|
2093
2107
|
*/
|
|
2094
2108
|
async canField(actor, operation, resource, field, options) {
|
|
2095
|
-
const
|
|
2109
|
+
const r = resource;
|
|
2110
|
+
const resourceBlock = this.policy.resources[r.type];
|
|
2096
2111
|
if (!resourceBlock) {
|
|
2097
2112
|
return false;
|
|
2098
2113
|
}
|
|
2099
|
-
return canField(
|
|
2114
|
+
return canField(
|
|
2115
|
+
this,
|
|
2116
|
+
actor,
|
|
2117
|
+
operation,
|
|
2118
|
+
r,
|
|
2119
|
+
field,
|
|
2120
|
+
resourceBlock.field_access,
|
|
2121
|
+
options
|
|
2122
|
+
);
|
|
2100
2123
|
}
|
|
2101
2124
|
/**
|
|
2102
2125
|
* T095: Return the list of declared field_access field names the actor can access
|
|
2103
2126
|
* for the given operation. Only returns explicitly declared fields.
|
|
2104
2127
|
*/
|
|
2105
2128
|
async permittedFields(actor, operation, resource, options) {
|
|
2106
|
-
const
|
|
2129
|
+
const r = resource;
|
|
2130
|
+
const resourceBlock = this.policy.resources[r.type];
|
|
2107
2131
|
if (!resourceBlock) {
|
|
2108
2132
|
return [];
|
|
2109
2133
|
}
|
|
2110
|
-
return permittedFields(
|
|
2134
|
+
return permittedFields(
|
|
2135
|
+
this,
|
|
2136
|
+
actor,
|
|
2137
|
+
operation,
|
|
2138
|
+
r,
|
|
2139
|
+
resourceBlock.field_access,
|
|
2140
|
+
options
|
|
2141
|
+
);
|
|
2111
2142
|
}
|
|
2112
2143
|
/**
|
|
2113
2144
|
* T070: Return flat deduplicated list of all resolved roles (direct + derived).
|
|
2114
2145
|
*/
|
|
2115
2146
|
async resolvedRoles(actor, resource, options) {
|
|
2116
|
-
const
|
|
2147
|
+
const a = actor;
|
|
2148
|
+
const r = resource;
|
|
2149
|
+
const resourceBlock = this.policy.resources[r.type];
|
|
2117
2150
|
if (!resourceBlock) {
|
|
2118
2151
|
return [];
|
|
2119
2152
|
}
|
|
2120
2153
|
const action = resourceBlock.permissions[0] ?? "__resolvedRoles__";
|
|
2121
|
-
const result = await this.evaluateInternal(
|
|
2154
|
+
const result = await this.evaluateInternal(a, action, r, options);
|
|
2122
2155
|
const directRoles = result.resolvedRoles.direct;
|
|
2123
2156
|
const derivedRoleNames = result.resolvedRoles.derived.map((d) => d.role);
|
|
2124
2157
|
return [.../* @__PURE__ */ new Set([...directRoles, ...derivedRoleNames])];
|
|
@@ -2131,17 +2164,20 @@ var Toride = class {
|
|
|
2131
2164
|
if (checks.length === 0) {
|
|
2132
2165
|
return [];
|
|
2133
2166
|
}
|
|
2167
|
+
const a = actor;
|
|
2134
2168
|
const sharedCache = new AttributeCache(this.resolvers);
|
|
2135
2169
|
const results = [];
|
|
2136
2170
|
for (const check of checks) {
|
|
2171
|
+
const r = check.resource;
|
|
2172
|
+
const act = check.action;
|
|
2137
2173
|
const result = await this.evaluateInternal(
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2174
|
+
a,
|
|
2175
|
+
act,
|
|
2176
|
+
r,
|
|
2141
2177
|
options,
|
|
2142
2178
|
sharedCache
|
|
2143
2179
|
);
|
|
2144
|
-
this.fireDecisionEvent(
|
|
2180
|
+
this.fireDecisionEvent(a, act, r, result);
|
|
2145
2181
|
results.push(result.allowed);
|
|
2146
2182
|
}
|
|
2147
2183
|
return results;
|
|
@@ -2151,11 +2187,14 @@ var Toride = class {
|
|
|
2151
2187
|
* Returns ConstraintResult with unrestricted/forbidden sentinels or constraint AST.
|
|
2152
2188
|
*/
|
|
2153
2189
|
async buildConstraints(actor, action, resourceType, options) {
|
|
2190
|
+
const a = actor;
|
|
2191
|
+
const act = action;
|
|
2192
|
+
const rt = resourceType;
|
|
2154
2193
|
const cache = new AttributeCache(this.resolvers);
|
|
2155
2194
|
const constraintResult = await buildConstraints(
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2195
|
+
a,
|
|
2196
|
+
act,
|
|
2197
|
+
rt,
|
|
2159
2198
|
cache,
|
|
2160
2199
|
this.policy,
|
|
2161
2200
|
{
|
|
@@ -2164,7 +2203,7 @@ var Toride = class {
|
|
|
2164
2203
|
customEvaluators: this.options.customEvaluators
|
|
2165
2204
|
}
|
|
2166
2205
|
);
|
|
2167
|
-
this.fireQueryEvent(
|
|
2206
|
+
this.fireQueryEvent(a, act, rt, constraintResult);
|
|
2168
2207
|
return constraintResult;
|
|
2169
2208
|
}
|
|
2170
2209
|
/**
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
var CLIENT_VERSION = "0.0.1";
|
|
3
|
+
var TorideClient = class {
|
|
4
|
+
permissions;
|
|
5
|
+
constructor(snapshot) {
|
|
6
|
+
this.permissions = /* @__PURE__ */ new Map();
|
|
7
|
+
for (const [key, actions] of Object.entries(snapshot)) {
|
|
8
|
+
this.permissions.set(key, new Set(actions));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Synchronous permission check.
|
|
13
|
+
* Returns true if the action is permitted for the resource, false otherwise.
|
|
14
|
+
* Unknown resources return false (default-deny).
|
|
15
|
+
*/
|
|
16
|
+
can(action, resource) {
|
|
17
|
+
const key = `${resource.type}:${resource.id}`;
|
|
18
|
+
const actions = this.permissions.get(key);
|
|
19
|
+
if (!actions) return false;
|
|
20
|
+
return actions.has(action);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Return the list of permitted actions for a resource.
|
|
24
|
+
* Returns empty array for unknown resources.
|
|
25
|
+
*/
|
|
26
|
+
permittedActions(resource) {
|
|
27
|
+
const key = `${resource.type}:${resource.id}`;
|
|
28
|
+
const actions = this.permissions.get(key);
|
|
29
|
+
if (!actions) return [];
|
|
30
|
+
return [...actions];
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export {
|
|
35
|
+
CLIENT_VERSION,
|
|
36
|
+
TorideClient
|
|
37
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shape constraint for Toride's type parameter.
|
|
3
|
+
* Each property is a union or mapped type that codegen fills with literals.
|
|
4
|
+
*/
|
|
5
|
+
interface TorideSchema {
|
|
6
|
+
/** Union of all resource type names (e.g., "Document" | "Organization") */
|
|
7
|
+
resources: string;
|
|
8
|
+
/** Global union of all action/permission names across all resources */
|
|
9
|
+
actions: string;
|
|
10
|
+
/** Union of all actor type names (e.g., "User" | "ServiceAccount") */
|
|
11
|
+
actorTypes: string;
|
|
12
|
+
/** Per-resource permission unions: { Document: "read" | "write"; ... } */
|
|
13
|
+
permissionMap: {
|
|
14
|
+
[R in string]: string;
|
|
15
|
+
};
|
|
16
|
+
/** Per-resource role unions: { Document: "admin" | "editor"; ... } */
|
|
17
|
+
roleMap: {
|
|
18
|
+
[R in string]: string;
|
|
19
|
+
};
|
|
20
|
+
/** Per-resource attribute shapes: { Document: { status: string; ownerId: string }; ... } */
|
|
21
|
+
resourceAttributeMap: {
|
|
22
|
+
[R in string]: Record<string, unknown>;
|
|
23
|
+
};
|
|
24
|
+
/** Per-actor attribute shapes: { User: { email: string; is_admin: boolean }; ... } */
|
|
25
|
+
actorAttributeMap: {
|
|
26
|
+
[A in string]: Record<string, unknown>;
|
|
27
|
+
};
|
|
28
|
+
/** Per-resource relation maps: { Document: { org: "Organization" }; ... } */
|
|
29
|
+
relationMap: {
|
|
30
|
+
[R in string]: Record<string, string>;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Default schema where everything is string / Record<string, unknown>.
|
|
35
|
+
* Used when Toride is instantiated without a type parameter.
|
|
36
|
+
* Provides full backward compatibility with the current untyped API.
|
|
37
|
+
*/
|
|
38
|
+
interface DefaultSchema extends TorideSchema {
|
|
39
|
+
resources: string;
|
|
40
|
+
actions: string;
|
|
41
|
+
actorTypes: string;
|
|
42
|
+
permissionMap: Record<string, string>;
|
|
43
|
+
roleMap: Record<string, string>;
|
|
44
|
+
resourceAttributeMap: Record<string, Record<string, unknown>>;
|
|
45
|
+
actorAttributeMap: Record<string, Record<string, unknown>>;
|
|
46
|
+
relationMap: Record<string, Record<string, string>>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Represents an entity performing actions.
|
|
50
|
+
* Generic discriminated union over actor types in S.
|
|
51
|
+
* When S = DefaultSchema, collapses to the original untyped shape.
|
|
52
|
+
*/
|
|
53
|
+
type ActorRef<S extends TorideSchema = DefaultSchema> = {
|
|
54
|
+
[A in S["actorTypes"]]: {
|
|
55
|
+
readonly type: A;
|
|
56
|
+
readonly id: string;
|
|
57
|
+
readonly attributes: S["actorAttributeMap"][A];
|
|
58
|
+
};
|
|
59
|
+
}[S["actorTypes"]];
|
|
60
|
+
/**
|
|
61
|
+
* Represents a protected entity being accessed.
|
|
62
|
+
* Generic over schema S and resource type R.
|
|
63
|
+
* When S = DefaultSchema, collapses to the original untyped shape.
|
|
64
|
+
*/
|
|
65
|
+
type ResourceRef<S extends TorideSchema = DefaultSchema, R extends S["resources"] = S["resources"]> = {
|
|
66
|
+
readonly type: R;
|
|
67
|
+
readonly id: string;
|
|
68
|
+
/** Pre-fetched attributes. Inline values take precedence over resolver results. */
|
|
69
|
+
readonly attributes?: S["resourceAttributeMap"][R];
|
|
70
|
+
};
|
|
71
|
+
/** Optional per-check configuration. */
|
|
72
|
+
interface CheckOptions {
|
|
73
|
+
readonly env?: Record<string, unknown>;
|
|
74
|
+
}
|
|
75
|
+
/** A single item in a canBatch() call. Action narrowed to global actions union. */
|
|
76
|
+
interface BatchCheckItem<S extends TorideSchema = DefaultSchema> {
|
|
77
|
+
readonly action: S["actions"];
|
|
78
|
+
readonly resource: ResourceRef<S>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Per-type resolver function.
|
|
82
|
+
* Called when the engine needs attributes not available inline.
|
|
83
|
+
* Called at most once per unique resource per evaluation (cached).
|
|
84
|
+
*
|
|
85
|
+
* Registering a resolver is **optional** per resource type. When no resolver is
|
|
86
|
+
* registered, inline {@link ResourceRef.attributes} are used as the sole data
|
|
87
|
+
* source — this is referred to as "default resolver" behavior (analogous to
|
|
88
|
+
* GraphQL's default field resolver, which returns `parent[fieldName]`).
|
|
89
|
+
*
|
|
90
|
+
* A resolver is only needed when attributes must be fetched from an external
|
|
91
|
+
* source (e.g., a database). When both inline attributes and a resolver are
|
|
92
|
+
* present, inline attributes take precedence field-by-field over resolver
|
|
93
|
+
* results.
|
|
94
|
+
*/
|
|
95
|
+
type ResourceResolver<S extends TorideSchema = DefaultSchema, R extends S["resources"] = S["resources"]> = (ref: ResourceRef<S, R>) => Promise<Record<string, unknown>>;
|
|
96
|
+
/**
|
|
97
|
+
* Map of resource type names to their resolver functions.
|
|
98
|
+
*
|
|
99
|
+
* Not all types need resolvers. Types without a registered resolver use
|
|
100
|
+
* **default resolver** behavior (also called "trivial resolution"): the engine
|
|
101
|
+
* reads attribute values directly from the inline {@link ResourceRef.attributes}
|
|
102
|
+
* passed at the call site. Fields not present inline resolve to `undefined`,
|
|
103
|
+
* causing conditions that reference them to fail (default-deny).
|
|
104
|
+
*
|
|
105
|
+
* This mirrors GraphQL's default field resolver pattern, where an unresolved
|
|
106
|
+
* field simply returns `parent[fieldName]` — here, inline attributes play the
|
|
107
|
+
* role of the `parent` object.
|
|
108
|
+
*/
|
|
109
|
+
type Resolvers<S extends TorideSchema = DefaultSchema> = {
|
|
110
|
+
[R in S["resources"]]?: ResourceResolver<S, R>;
|
|
111
|
+
};
|
|
112
|
+
/** Custom evaluator function signature. */
|
|
113
|
+
type EvaluatorFn = (actor: ActorRef, resource: ResourceRef, env: Record<string, unknown>) => Promise<boolean>;
|
|
114
|
+
/** Engine construction options. */
|
|
115
|
+
interface TorideOptions<S extends TorideSchema = DefaultSchema> {
|
|
116
|
+
readonly policy: Policy;
|
|
117
|
+
/**
|
|
118
|
+
* Per-type resolver map.
|
|
119
|
+
*
|
|
120
|
+
* Optional — the engine works without any resolvers when all required data is
|
|
121
|
+
* provided inline via {@link ResourceRef.attributes}. This "default resolver"
|
|
122
|
+
* mode is the simplest way to use toride and requires no async data fetching.
|
|
123
|
+
*
|
|
124
|
+
* When both inline attributes and a resolver are present for the same resource
|
|
125
|
+
* type, **inline attributes take precedence** over resolver results on a
|
|
126
|
+
* field-by-field basis.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* // Inline-only mode — no resolvers needed
|
|
131
|
+
* const toride = new Toride({ policy });
|
|
132
|
+
*
|
|
133
|
+
* const allowed = await toride.can(actor, "read", {
|
|
134
|
+
* type: "Document",
|
|
135
|
+
* id: "doc-1",
|
|
136
|
+
* attributes: { status: "published", ownerId: "user-42" },
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
readonly resolvers?: Resolvers<S>;
|
|
141
|
+
readonly maxConditionDepth?: number;
|
|
142
|
+
readonly maxDerivedRoleDepth?: number;
|
|
143
|
+
readonly customEvaluators?: Record<string, EvaluatorFn>;
|
|
144
|
+
readonly onDecision?: (event: DecisionEvent) => void;
|
|
145
|
+
readonly onQuery?: (event: QueryEvent) => void;
|
|
146
|
+
}
|
|
147
|
+
/** Attribute type for actor declarations. */
|
|
148
|
+
type AttributeType = "string" | "number" | "boolean";
|
|
149
|
+
/** Actor type declaration with attribute schema. */
|
|
150
|
+
interface ActorDeclaration {
|
|
151
|
+
readonly attributes: Record<string, AttributeType>;
|
|
152
|
+
}
|
|
153
|
+
/** Global role definition derived from actor attributes. */
|
|
154
|
+
interface GlobalRole {
|
|
155
|
+
readonly actor_type: string;
|
|
156
|
+
readonly when: ConditionExpression;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Derived role entry. Exactly one derivation pattern per entry.
|
|
160
|
+
* Patterns:
|
|
161
|
+
* 1. from_global_role
|
|
162
|
+
* 2. from_role + on_relation
|
|
163
|
+
* 3. from_relation
|
|
164
|
+
* 4. actor_type + when (conditional)
|
|
165
|
+
* 5. when only
|
|
166
|
+
*/
|
|
167
|
+
interface DerivedRoleEntry {
|
|
168
|
+
readonly role: string;
|
|
169
|
+
readonly from_global_role?: string;
|
|
170
|
+
readonly from_role?: string;
|
|
171
|
+
readonly on_relation?: string;
|
|
172
|
+
readonly from_relation?: string;
|
|
173
|
+
readonly actor_type?: string;
|
|
174
|
+
readonly when?: ConditionExpression;
|
|
175
|
+
}
|
|
176
|
+
/** Conditional rule (permit or forbid). */
|
|
177
|
+
interface Rule {
|
|
178
|
+
readonly effect: "permit" | "forbid";
|
|
179
|
+
readonly roles?: string[];
|
|
180
|
+
readonly permissions: string[];
|
|
181
|
+
readonly when: ConditionExpression;
|
|
182
|
+
}
|
|
183
|
+
/** Field-level access control definition. */
|
|
184
|
+
interface FieldAccessDef {
|
|
185
|
+
readonly read?: string[];
|
|
186
|
+
readonly update?: string[];
|
|
187
|
+
}
|
|
188
|
+
/** Resource block definition. */
|
|
189
|
+
interface ResourceBlock {
|
|
190
|
+
readonly roles: string[];
|
|
191
|
+
readonly permissions: string[];
|
|
192
|
+
/** Optional typed attribute declarations for this resource type. */
|
|
193
|
+
readonly attributes?: Record<string, AttributeType>;
|
|
194
|
+
/** Relations map field names to target resource type names (simplified). */
|
|
195
|
+
readonly relations?: Record<string, string>;
|
|
196
|
+
readonly grants?: Record<string, string[]>;
|
|
197
|
+
readonly derived_roles?: DerivedRoleEntry[];
|
|
198
|
+
readonly rules?: Rule[];
|
|
199
|
+
readonly field_access?: Record<string, FieldAccessDef>;
|
|
200
|
+
}
|
|
201
|
+
/** Operator-based condition value. */
|
|
202
|
+
type ConditionOperator = {
|
|
203
|
+
readonly eq: unknown;
|
|
204
|
+
} | {
|
|
205
|
+
readonly neq: unknown;
|
|
206
|
+
} | {
|
|
207
|
+
readonly gt: unknown;
|
|
208
|
+
} | {
|
|
209
|
+
readonly gte: unknown;
|
|
210
|
+
} | {
|
|
211
|
+
readonly lt: unknown;
|
|
212
|
+
} | {
|
|
213
|
+
readonly lte: unknown;
|
|
214
|
+
} | {
|
|
215
|
+
readonly in: unknown[] | string;
|
|
216
|
+
} | {
|
|
217
|
+
readonly includes: unknown;
|
|
218
|
+
} | {
|
|
219
|
+
readonly exists: boolean;
|
|
220
|
+
} | {
|
|
221
|
+
readonly startsWith: string;
|
|
222
|
+
} | {
|
|
223
|
+
readonly endsWith: string;
|
|
224
|
+
} | {
|
|
225
|
+
readonly contains: string;
|
|
226
|
+
} | {
|
|
227
|
+
readonly custom: string;
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* Condition value: either a primitive (equality shorthand),
|
|
231
|
+
* a cross-reference string ($actor.x, $resource.x, $env.x),
|
|
232
|
+
* or an operator object.
|
|
233
|
+
*/
|
|
234
|
+
type ConditionValue = string | number | boolean | ConditionOperator;
|
|
235
|
+
/** Simple conditions: all key-value pairs ANDed together. */
|
|
236
|
+
type SimpleConditions = Record<string, ConditionValue>;
|
|
237
|
+
/**
|
|
238
|
+
* Recursive condition expression.
|
|
239
|
+
* Either simple conditions (Record<string, ConditionValue>),
|
|
240
|
+
* or a logical combinator ({ any: ... } or { all: ... }).
|
|
241
|
+
*/
|
|
242
|
+
type ConditionExpression = SimpleConditions | {
|
|
243
|
+
readonly any: ConditionExpression[];
|
|
244
|
+
} | {
|
|
245
|
+
readonly all: ConditionExpression[];
|
|
246
|
+
};
|
|
247
|
+
/** Test case for declarative YAML tests. */
|
|
248
|
+
interface TestCase {
|
|
249
|
+
readonly name: string;
|
|
250
|
+
readonly actor: ActorRef;
|
|
251
|
+
/** Mock resolver data: keyed by "Type:id", values are attribute objects. */
|
|
252
|
+
readonly resolvers?: Record<string, Record<string, unknown>>;
|
|
253
|
+
readonly action: string;
|
|
254
|
+
readonly resource: ResourceRef;
|
|
255
|
+
readonly expected: "allow" | "deny";
|
|
256
|
+
}
|
|
257
|
+
/** Top-level policy object. */
|
|
258
|
+
interface Policy {
|
|
259
|
+
readonly version: "1";
|
|
260
|
+
readonly actors: Record<string, ActorDeclaration>;
|
|
261
|
+
readonly global_roles?: Record<string, GlobalRole>;
|
|
262
|
+
readonly resources: Record<string, ResourceBlock>;
|
|
263
|
+
readonly tests?: TestCase[];
|
|
264
|
+
}
|
|
265
|
+
/** Trace for a derived role showing derivation path. */
|
|
266
|
+
interface DerivedRoleTrace {
|
|
267
|
+
readonly role: string;
|
|
268
|
+
readonly via: string;
|
|
269
|
+
}
|
|
270
|
+
/** Resolved roles detail with direct and derived breakdown. */
|
|
271
|
+
interface ResolvedRolesDetail {
|
|
272
|
+
readonly direct: string[];
|
|
273
|
+
readonly derived: DerivedRoleTrace[];
|
|
274
|
+
}
|
|
275
|
+
/** A matched rule with evaluation context. */
|
|
276
|
+
interface MatchedRule {
|
|
277
|
+
readonly effect: "permit" | "forbid";
|
|
278
|
+
readonly matched: boolean;
|
|
279
|
+
readonly rule: Rule;
|
|
280
|
+
readonly resolvedValues: Record<string, unknown>;
|
|
281
|
+
}
|
|
282
|
+
/** Full decision trace from explain(). */
|
|
283
|
+
interface ExplainResult<S extends TorideSchema = DefaultSchema, R extends S["resources"] = S["resources"]> {
|
|
284
|
+
readonly allowed: boolean;
|
|
285
|
+
readonly resolvedRoles: ResolvedRolesDetail;
|
|
286
|
+
readonly grantedPermissions: S["permissionMap"][R][];
|
|
287
|
+
readonly matchedRules: MatchedRule[];
|
|
288
|
+
readonly finalDecision: string;
|
|
289
|
+
}
|
|
290
|
+
/** Audit event for authorization checks. */
|
|
291
|
+
interface DecisionEvent {
|
|
292
|
+
readonly actor: ActorRef;
|
|
293
|
+
readonly action: string;
|
|
294
|
+
readonly resource: ResourceRef;
|
|
295
|
+
readonly allowed: boolean;
|
|
296
|
+
readonly resolvedRoles: string[];
|
|
297
|
+
readonly matchedRules: {
|
|
298
|
+
effect: string;
|
|
299
|
+
matched: boolean;
|
|
300
|
+
}[];
|
|
301
|
+
readonly timestamp: Date;
|
|
302
|
+
}
|
|
303
|
+
/** Audit event for constraint queries. */
|
|
304
|
+
interface QueryEvent {
|
|
305
|
+
readonly actor: ActorRef;
|
|
306
|
+
readonly action: string;
|
|
307
|
+
readonly resourceType: string;
|
|
308
|
+
readonly resultType: "unrestricted" | "forbidden" | "constrained";
|
|
309
|
+
readonly timestamp: Date;
|
|
310
|
+
}
|
|
311
|
+
/** Thrown when policy validation fails. */
|
|
312
|
+
declare class ValidationError extends Error {
|
|
313
|
+
readonly path: string;
|
|
314
|
+
constructor(message: string, path: string);
|
|
315
|
+
}
|
|
316
|
+
/** Thrown when a cycle is detected in relation traversal. */
|
|
317
|
+
declare class CycleError extends Error {
|
|
318
|
+
readonly path: string[];
|
|
319
|
+
constructor(message: string, path: string[]);
|
|
320
|
+
}
|
|
321
|
+
/** Thrown when depth limit is exceeded. */
|
|
322
|
+
declare class DepthLimitError extends Error {
|
|
323
|
+
readonly limit: number;
|
|
324
|
+
readonly limitType: "condition" | "derivation";
|
|
325
|
+
constructor(message: string, limit: number, limitType: "condition" | "derivation");
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* A serializable map of permissions keyed by "Type:id".
|
|
330
|
+
* Values are arrays of permitted action strings.
|
|
331
|
+
* Suitable for JSON transport to client-side TorideClient.
|
|
332
|
+
*/
|
|
333
|
+
type PermissionSnapshot = Record<string, string[]>;
|
|
334
|
+
|
|
335
|
+
declare const CLIENT_VERSION = "0.0.1";
|
|
336
|
+
|
|
337
|
+
/** Minimal resource reference for client-side lookups. Generic over S for type narrowing. */
|
|
338
|
+
interface ClientResourceRef<S extends TorideSchema = DefaultSchema> {
|
|
339
|
+
readonly type: S["resources"];
|
|
340
|
+
readonly id: string;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Client-side permission checker that provides instant synchronous checks
|
|
344
|
+
* against a PermissionSnapshot received from the server.
|
|
345
|
+
*
|
|
346
|
+
* Generic over TorideSchema so that action names and resource types
|
|
347
|
+
* are validated at compile time when a concrete schema is provided.
|
|
348
|
+
*
|
|
349
|
+
* Default-deny: unknown resources or actions return false.
|
|
350
|
+
* The snapshot is defensively copied to prevent external mutation.
|
|
351
|
+
*/
|
|
352
|
+
declare class TorideClient<S extends TorideSchema = DefaultSchema> {
|
|
353
|
+
private readonly permissions;
|
|
354
|
+
constructor(snapshot: PermissionSnapshot);
|
|
355
|
+
/**
|
|
356
|
+
* Synchronous permission check.
|
|
357
|
+
* Returns true if the action is permitted for the resource, false otherwise.
|
|
358
|
+
* Unknown resources return false (default-deny).
|
|
359
|
+
*/
|
|
360
|
+
can(action: S["actions"], resource: ClientResourceRef<S>): boolean;
|
|
361
|
+
/**
|
|
362
|
+
* Return the list of permitted actions for a resource.
|
|
363
|
+
* Returns empty array for unknown resources.
|
|
364
|
+
*/
|
|
365
|
+
permittedActions(resource: ClientResourceRef<S>): S["actions"][];
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export { type ActorRef as A, type BatchCheckItem as B, type CheckOptions as C, type DefaultSchema as D, type ExplainResult as E, type FieldAccessDef as F, type GlobalRole as G, type MatchedRule as M, type Policy as P, type QueryEvent as Q, type ResourceRef as R, type SimpleConditions as S, type TorideSchema as T, ValidationError as V, type TorideOptions as a, type PermissionSnapshot as b, type TestCase as c, type Resolvers as d, type ActorDeclaration as e, type AttributeType as f, type ClientResourceRef as g, type ConditionExpression as h, type ConditionOperator as i, type ConditionValue as j, CycleError as k, type DecisionEvent as l, DepthLimitError as m, type DerivedRoleEntry as n, type DerivedRoleTrace as o, type EvaluatorFn as p, type ResolvedRolesDetail as q, type ResourceBlock as r, type ResourceResolver as s, type Rule as t, TorideClient as u, CLIENT_VERSION as v };
|
package/dist/client.d.ts
CHANGED
|
@@ -1,33 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
declare const CLIENT_VERSION = "0.0.1";
|
|
4
|
-
|
|
5
|
-
/** Minimal resource reference for client-side lookups. */
|
|
6
|
-
interface ClientResourceRef {
|
|
7
|
-
readonly type: string;
|
|
8
|
-
readonly id: string;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Client-side permission checker that provides instant synchronous checks
|
|
12
|
-
* against a PermissionSnapshot received from the server.
|
|
13
|
-
*
|
|
14
|
-
* Default-deny: unknown resources or actions return false.
|
|
15
|
-
* The snapshot is defensively copied to prevent external mutation.
|
|
16
|
-
*/
|
|
17
|
-
declare class TorideClient {
|
|
18
|
-
private readonly permissions;
|
|
19
|
-
constructor(snapshot: PermissionSnapshot);
|
|
20
|
-
/**
|
|
21
|
-
* Synchronous permission check.
|
|
22
|
-
* Returns true if the action is permitted for the resource, false otherwise.
|
|
23
|
-
* Unknown resources return false (default-deny).
|
|
24
|
-
*/
|
|
25
|
-
can(action: string, resource: ClientResourceRef): boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Return the list of permitted actions for a resource.
|
|
28
|
-
* Returns empty array for unknown resources.
|
|
29
|
-
*/
|
|
30
|
-
permittedActions(resource: ClientResourceRef): string[];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export { CLIENT_VERSION, type ClientResourceRef, PermissionSnapshot, TorideClient };
|
|
1
|
+
export { v as CLIENT_VERSION, g as ClientResourceRef, b as PermissionSnapshot, u as TorideClient } from './client-RqwW0K_-.js';
|
package/dist/client.js
CHANGED
|
@@ -1,35 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
constructor(snapshot) {
|
|
6
|
-
this.permissions = /* @__PURE__ */ new Map();
|
|
7
|
-
for (const [key, actions] of Object.entries(snapshot)) {
|
|
8
|
-
this.permissions.set(key, new Set(actions));
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Synchronous permission check.
|
|
13
|
-
* Returns true if the action is permitted for the resource, false otherwise.
|
|
14
|
-
* Unknown resources return false (default-deny).
|
|
15
|
-
*/
|
|
16
|
-
can(action, resource) {
|
|
17
|
-
const key = `${resource.type}:${resource.id}`;
|
|
18
|
-
const actions = this.permissions.get(key);
|
|
19
|
-
if (!actions) return false;
|
|
20
|
-
return actions.has(action);
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Return the list of permitted actions for a resource.
|
|
24
|
-
* Returns empty array for unknown resources.
|
|
25
|
-
*/
|
|
26
|
-
permittedActions(resource) {
|
|
27
|
-
const key = `${resource.type}:${resource.id}`;
|
|
28
|
-
const actions = this.permissions.get(key);
|
|
29
|
-
if (!actions) return [];
|
|
30
|
-
return [...actions];
|
|
31
|
-
}
|
|
32
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
CLIENT_VERSION,
|
|
3
|
+
TorideClient
|
|
4
|
+
} from "./chunk-475CNU63.js";
|
|
33
5
|
export {
|
|
34
6
|
CLIENT_VERSION,
|
|
35
7
|
TorideClient
|
package/dist/index.d.ts
CHANGED
|
@@ -1,230 +1,5 @@
|
|
|
1
|
-
import { P as PermissionSnapshot } from './
|
|
2
|
-
|
|
3
|
-
/** Represents an entity performing actions. */
|
|
4
|
-
interface ActorRef {
|
|
5
|
-
readonly type: string;
|
|
6
|
-
readonly id: string;
|
|
7
|
-
readonly attributes: Record<string, unknown>;
|
|
8
|
-
}
|
|
9
|
-
/** Represents a protected entity being accessed. */
|
|
10
|
-
interface ResourceRef {
|
|
11
|
-
readonly type: string;
|
|
12
|
-
readonly id: string;
|
|
13
|
-
/** Pre-fetched attributes. Inline values take precedence over resolver results. */
|
|
14
|
-
readonly attributes?: Record<string, unknown>;
|
|
15
|
-
}
|
|
16
|
-
/** Optional per-check configuration. */
|
|
17
|
-
interface CheckOptions {
|
|
18
|
-
readonly env?: Record<string, unknown>;
|
|
19
|
-
}
|
|
20
|
-
/** A single item in a canBatch() call. */
|
|
21
|
-
interface BatchCheckItem {
|
|
22
|
-
readonly action: string;
|
|
23
|
-
readonly resource: ResourceRef;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Per-type resolver function.
|
|
27
|
-
* Called when the engine needs attributes not available inline.
|
|
28
|
-
* Called at most once per unique resource per evaluation (cached).
|
|
29
|
-
*/
|
|
30
|
-
type ResourceResolver = (ref: ResourceRef) => Promise<Record<string, unknown>>;
|
|
31
|
-
/**
|
|
32
|
-
* Map of resource type names to their resolver functions.
|
|
33
|
-
* Not all types need resolvers — types without resolvers use trivial resolution
|
|
34
|
-
* (fields are undefined unless provided inline).
|
|
35
|
-
*/
|
|
36
|
-
type Resolvers = Record<string, ResourceResolver>;
|
|
37
|
-
/** Custom evaluator function signature. */
|
|
38
|
-
type EvaluatorFn = (actor: ActorRef, resource: ResourceRef, env: Record<string, unknown>) => Promise<boolean>;
|
|
39
|
-
/** Engine construction options. */
|
|
40
|
-
interface TorideOptions {
|
|
41
|
-
readonly policy: Policy;
|
|
42
|
-
/** Per-type resolver map. Optional — engine works without resolvers if all data is inline. */
|
|
43
|
-
readonly resolvers?: Resolvers;
|
|
44
|
-
readonly maxConditionDepth?: number;
|
|
45
|
-
readonly maxDerivedRoleDepth?: number;
|
|
46
|
-
readonly customEvaluators?: Record<string, EvaluatorFn>;
|
|
47
|
-
readonly onDecision?: (event: DecisionEvent) => void;
|
|
48
|
-
readonly onQuery?: (event: QueryEvent) => void;
|
|
49
|
-
}
|
|
50
|
-
/** Attribute type for actor declarations. */
|
|
51
|
-
type AttributeType = "string" | "number" | "boolean";
|
|
52
|
-
/** Actor type declaration with attribute schema. */
|
|
53
|
-
interface ActorDeclaration {
|
|
54
|
-
readonly attributes: Record<string, AttributeType>;
|
|
55
|
-
}
|
|
56
|
-
/** Global role definition derived from actor attributes. */
|
|
57
|
-
interface GlobalRole {
|
|
58
|
-
readonly actor_type: string;
|
|
59
|
-
readonly when: ConditionExpression;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Derived role entry. Exactly one derivation pattern per entry.
|
|
63
|
-
* Patterns:
|
|
64
|
-
* 1. from_global_role
|
|
65
|
-
* 2. from_role + on_relation
|
|
66
|
-
* 3. from_relation
|
|
67
|
-
* 4. actor_type + when (conditional)
|
|
68
|
-
* 5. when only
|
|
69
|
-
*/
|
|
70
|
-
interface DerivedRoleEntry {
|
|
71
|
-
readonly role: string;
|
|
72
|
-
readonly from_global_role?: string;
|
|
73
|
-
readonly from_role?: string;
|
|
74
|
-
readonly on_relation?: string;
|
|
75
|
-
readonly from_relation?: string;
|
|
76
|
-
readonly actor_type?: string;
|
|
77
|
-
readonly when?: ConditionExpression;
|
|
78
|
-
}
|
|
79
|
-
/** Conditional rule (permit or forbid). */
|
|
80
|
-
interface Rule {
|
|
81
|
-
readonly effect: "permit" | "forbid";
|
|
82
|
-
readonly roles?: string[];
|
|
83
|
-
readonly permissions: string[];
|
|
84
|
-
readonly when: ConditionExpression;
|
|
85
|
-
}
|
|
86
|
-
/** Field-level access control definition. */
|
|
87
|
-
interface FieldAccessDef {
|
|
88
|
-
readonly read?: string[];
|
|
89
|
-
readonly update?: string[];
|
|
90
|
-
}
|
|
91
|
-
/** Resource block definition. */
|
|
92
|
-
interface ResourceBlock {
|
|
93
|
-
readonly roles: string[];
|
|
94
|
-
readonly permissions: string[];
|
|
95
|
-
/** Relations map field names to target resource type names (simplified). */
|
|
96
|
-
readonly relations?: Record<string, string>;
|
|
97
|
-
readonly grants?: Record<string, string[]>;
|
|
98
|
-
readonly derived_roles?: DerivedRoleEntry[];
|
|
99
|
-
readonly rules?: Rule[];
|
|
100
|
-
readonly field_access?: Record<string, FieldAccessDef>;
|
|
101
|
-
}
|
|
102
|
-
/** Operator-based condition value. */
|
|
103
|
-
type ConditionOperator = {
|
|
104
|
-
readonly eq: unknown;
|
|
105
|
-
} | {
|
|
106
|
-
readonly neq: unknown;
|
|
107
|
-
} | {
|
|
108
|
-
readonly gt: unknown;
|
|
109
|
-
} | {
|
|
110
|
-
readonly gte: unknown;
|
|
111
|
-
} | {
|
|
112
|
-
readonly lt: unknown;
|
|
113
|
-
} | {
|
|
114
|
-
readonly lte: unknown;
|
|
115
|
-
} | {
|
|
116
|
-
readonly in: unknown[] | string;
|
|
117
|
-
} | {
|
|
118
|
-
readonly includes: unknown;
|
|
119
|
-
} | {
|
|
120
|
-
readonly exists: boolean;
|
|
121
|
-
} | {
|
|
122
|
-
readonly startsWith: string;
|
|
123
|
-
} | {
|
|
124
|
-
readonly endsWith: string;
|
|
125
|
-
} | {
|
|
126
|
-
readonly contains: string;
|
|
127
|
-
} | {
|
|
128
|
-
readonly custom: string;
|
|
129
|
-
};
|
|
130
|
-
/**
|
|
131
|
-
* Condition value: either a primitive (equality shorthand),
|
|
132
|
-
* a cross-reference string ($actor.x, $resource.x, $env.x),
|
|
133
|
-
* or an operator object.
|
|
134
|
-
*/
|
|
135
|
-
type ConditionValue = string | number | boolean | ConditionOperator;
|
|
136
|
-
/** Simple conditions: all key-value pairs ANDed together. */
|
|
137
|
-
type SimpleConditions = Record<string, ConditionValue>;
|
|
138
|
-
/**
|
|
139
|
-
* Recursive condition expression.
|
|
140
|
-
* Either simple conditions (Record<string, ConditionValue>),
|
|
141
|
-
* or a logical combinator ({ any: ... } or { all: ... }).
|
|
142
|
-
*/
|
|
143
|
-
type ConditionExpression = SimpleConditions | {
|
|
144
|
-
readonly any: ConditionExpression[];
|
|
145
|
-
} | {
|
|
146
|
-
readonly all: ConditionExpression[];
|
|
147
|
-
};
|
|
148
|
-
/** Test case for declarative YAML tests. */
|
|
149
|
-
interface TestCase {
|
|
150
|
-
readonly name: string;
|
|
151
|
-
readonly actor: ActorRef;
|
|
152
|
-
/** Mock resolver data: keyed by "Type:id", values are attribute objects. */
|
|
153
|
-
readonly resolvers?: Record<string, Record<string, unknown>>;
|
|
154
|
-
readonly action: string;
|
|
155
|
-
readonly resource: ResourceRef;
|
|
156
|
-
readonly expected: "allow" | "deny";
|
|
157
|
-
}
|
|
158
|
-
/** Top-level policy object. */
|
|
159
|
-
interface Policy {
|
|
160
|
-
readonly version: "1";
|
|
161
|
-
readonly actors: Record<string, ActorDeclaration>;
|
|
162
|
-
readonly global_roles?: Record<string, GlobalRole>;
|
|
163
|
-
readonly resources: Record<string, ResourceBlock>;
|
|
164
|
-
readonly tests?: TestCase[];
|
|
165
|
-
}
|
|
166
|
-
/** Trace for a derived role showing derivation path. */
|
|
167
|
-
interface DerivedRoleTrace {
|
|
168
|
-
readonly role: string;
|
|
169
|
-
readonly via: string;
|
|
170
|
-
}
|
|
171
|
-
/** Resolved roles detail with direct and derived breakdown. */
|
|
172
|
-
interface ResolvedRolesDetail {
|
|
173
|
-
readonly direct: string[];
|
|
174
|
-
readonly derived: DerivedRoleTrace[];
|
|
175
|
-
}
|
|
176
|
-
/** A matched rule with evaluation context. */
|
|
177
|
-
interface MatchedRule {
|
|
178
|
-
readonly effect: "permit" | "forbid";
|
|
179
|
-
readonly matched: boolean;
|
|
180
|
-
readonly rule: Rule;
|
|
181
|
-
readonly resolvedValues: Record<string, unknown>;
|
|
182
|
-
}
|
|
183
|
-
/** Full decision trace from explain(). */
|
|
184
|
-
interface ExplainResult {
|
|
185
|
-
readonly allowed: boolean;
|
|
186
|
-
readonly resolvedRoles: ResolvedRolesDetail;
|
|
187
|
-
readonly grantedPermissions: string[];
|
|
188
|
-
readonly matchedRules: MatchedRule[];
|
|
189
|
-
readonly finalDecision: string;
|
|
190
|
-
}
|
|
191
|
-
/** Audit event for authorization checks. */
|
|
192
|
-
interface DecisionEvent {
|
|
193
|
-
readonly actor: ActorRef;
|
|
194
|
-
readonly action: string;
|
|
195
|
-
readonly resource: ResourceRef;
|
|
196
|
-
readonly allowed: boolean;
|
|
197
|
-
readonly resolvedRoles: string[];
|
|
198
|
-
readonly matchedRules: {
|
|
199
|
-
effect: string;
|
|
200
|
-
matched: boolean;
|
|
201
|
-
}[];
|
|
202
|
-
readonly timestamp: Date;
|
|
203
|
-
}
|
|
204
|
-
/** Audit event for constraint queries. */
|
|
205
|
-
interface QueryEvent {
|
|
206
|
-
readonly actor: ActorRef;
|
|
207
|
-
readonly action: string;
|
|
208
|
-
readonly resourceType: string;
|
|
209
|
-
readonly resultType: "unrestricted" | "forbidden" | "constrained";
|
|
210
|
-
readonly timestamp: Date;
|
|
211
|
-
}
|
|
212
|
-
/** Thrown when policy validation fails. */
|
|
213
|
-
declare class ValidationError extends Error {
|
|
214
|
-
readonly path: string;
|
|
215
|
-
constructor(message: string, path: string);
|
|
216
|
-
}
|
|
217
|
-
/** Thrown when a cycle is detected in relation traversal. */
|
|
218
|
-
declare class CycleError extends Error {
|
|
219
|
-
readonly path: string[];
|
|
220
|
-
constructor(message: string, path: string[]);
|
|
221
|
-
}
|
|
222
|
-
/** Thrown when depth limit is exceeded. */
|
|
223
|
-
declare class DepthLimitError extends Error {
|
|
224
|
-
readonly limit: number;
|
|
225
|
-
readonly limitType: "condition" | "derivation";
|
|
226
|
-
constructor(message: string, limit: number, limitType: "condition" | "derivation");
|
|
227
|
-
}
|
|
1
|
+
import { P as Policy, T as TorideSchema, D as DefaultSchema, a as TorideOptions, A as ActorRef, R as ResourceRef, C as CheckOptions, E as ExplainResult, b as PermissionSnapshot, B as BatchCheckItem, c as TestCase, d as Resolvers } from './client-RqwW0K_-.js';
|
|
2
|
+
export { e as ActorDeclaration, f as AttributeType, g as ClientResourceRef, h as ConditionExpression, i as ConditionOperator, j as ConditionValue, k as CycleError, l as DecisionEvent, m as DepthLimitError, n as DerivedRoleEntry, o as DerivedRoleTrace, p as EvaluatorFn, F as FieldAccessDef, G as GlobalRole, M as MatchedRule, Q as QueryEvent, q as ResolvedRolesDetail, r as ResourceBlock, s as ResourceResolver, t as Rule, S as SimpleConditions, u as TorideClient, V as ValidationError } from './client-RqwW0K_-.js';
|
|
228
3
|
|
|
229
4
|
/**
|
|
230
5
|
* Parse and validate a YAML string into a typed Policy object.
|
|
@@ -398,16 +173,16 @@ interface ConstraintAdapter<TQuery> {
|
|
|
398
173
|
* Creates a per-check cache, resolves direct roles, checks grants,
|
|
399
174
|
* and returns boolean with default-deny semantics.
|
|
400
175
|
*/
|
|
401
|
-
declare class Toride {
|
|
176
|
+
declare class Toride<S extends TorideSchema = DefaultSchema> {
|
|
402
177
|
private policy;
|
|
403
178
|
private readonly resolvers;
|
|
404
179
|
private readonly options;
|
|
405
|
-
constructor(options: TorideOptions);
|
|
180
|
+
constructor(options: TorideOptions<S>);
|
|
406
181
|
/**
|
|
407
182
|
* Check if an actor can perform an action on a resource.
|
|
408
183
|
* Default-deny: returns false if resource type is unknown or no grants match.
|
|
409
184
|
*/
|
|
410
|
-
can(actor: ActorRef
|
|
185
|
+
can<R extends S["resources"]>(actor: ActorRef<S>, action: S["permissionMap"][R], resource: ResourceRef<S, R>, options?: CheckOptions): Promise<boolean>;
|
|
411
186
|
/**
|
|
412
187
|
* T097: Atomic policy swap. In-flight checks capture the resource block
|
|
413
188
|
* at the start of evaluateInternal, so they complete with the old policy.
|
|
@@ -418,44 +193,44 @@ declare class Toride {
|
|
|
418
193
|
* T068: Return full ExplainResult with role derivation traces,
|
|
419
194
|
* granted permissions, matched rules, and human-readable final decision.
|
|
420
195
|
*/
|
|
421
|
-
explain(actor: ActorRef
|
|
196
|
+
explain<R extends S["resources"]>(actor: ActorRef<S>, action: S["permissionMap"][R], resource: ResourceRef<S, R>, options?: CheckOptions): Promise<ExplainResult<S, R>>;
|
|
422
197
|
/**
|
|
423
198
|
* T069: Check all declared permissions for a resource and return permitted ones.
|
|
424
199
|
* Uses a shared cache across all per-action evaluations.
|
|
425
200
|
*/
|
|
426
|
-
permittedActions(actor: ActorRef
|
|
201
|
+
permittedActions<R extends S["resources"]>(actor: ActorRef<S>, resource: ResourceRef<S, R>, options?: CheckOptions): Promise<S["permissionMap"][R][]>;
|
|
427
202
|
/**
|
|
428
203
|
* T083: Generate a PermissionSnapshot for a list of resources.
|
|
429
204
|
* Calls permittedActions() for each resource and returns a map
|
|
430
205
|
* keyed by "Type:id" with arrays of permitted action strings.
|
|
431
206
|
* Suitable for serializing to the client via TorideClient.
|
|
432
207
|
*/
|
|
433
|
-
snapshot(actor: ActorRef
|
|
208
|
+
snapshot(actor: ActorRef<S>, resources: ResourceRef<S>[], options?: CheckOptions): Promise<PermissionSnapshot>;
|
|
434
209
|
/**
|
|
435
210
|
* T095: Check if an actor can perform a field-level operation on a specific field.
|
|
436
211
|
* Restricted fields require the actor to have a role listed in field_access.
|
|
437
212
|
* Unlisted fields are unrestricted: any actor with the resource-level permission can access them.
|
|
438
213
|
*/
|
|
439
|
-
canField(actor: ActorRef
|
|
214
|
+
canField<R extends S["resources"]>(actor: ActorRef<S>, operation: "read" | "update", resource: ResourceRef<S, R>, field: string, options?: CheckOptions): Promise<boolean>;
|
|
440
215
|
/**
|
|
441
216
|
* T095: Return the list of declared field_access field names the actor can access
|
|
442
217
|
* for the given operation. Only returns explicitly declared fields.
|
|
443
218
|
*/
|
|
444
|
-
permittedFields(actor: ActorRef
|
|
219
|
+
permittedFields<R extends S["resources"]>(actor: ActorRef<S>, operation: "read" | "update", resource: ResourceRef<S, R>, options?: CheckOptions): Promise<string[]>;
|
|
445
220
|
/**
|
|
446
221
|
* T070: Return flat deduplicated list of all resolved roles (direct + derived).
|
|
447
222
|
*/
|
|
448
|
-
resolvedRoles(actor: ActorRef
|
|
223
|
+
resolvedRoles<R extends S["resources"]>(actor: ActorRef<S>, resource: ResourceRef<S, R>, options?: CheckOptions): Promise<string[]>;
|
|
449
224
|
/**
|
|
450
225
|
* T071: Evaluate multiple checks for the same actor with a shared resolver cache.
|
|
451
226
|
* Returns boolean[] in the same order as the input checks.
|
|
452
227
|
*/
|
|
453
|
-
canBatch(actor: ActorRef
|
|
228
|
+
canBatch(actor: ActorRef<S>, checks: BatchCheckItem<S>[], options?: CheckOptions): Promise<boolean[]>;
|
|
454
229
|
/**
|
|
455
230
|
* T064: Build constraint AST for partial evaluation / data filtering.
|
|
456
231
|
* Returns ConstraintResult with unrestricted/forbidden sentinels or constraint AST.
|
|
457
232
|
*/
|
|
458
|
-
buildConstraints(actor: ActorRef
|
|
233
|
+
buildConstraints<R extends S["resources"]>(actor: ActorRef<S>, action: S["permissionMap"][R], resourceType: R, options?: CheckOptions): Promise<ConstraintResult>;
|
|
459
234
|
/**
|
|
460
235
|
* T064: Translate constraint AST using an adapter.
|
|
461
236
|
* Dispatches each constraint node to the adapter's methods.
|
|
@@ -480,7 +255,7 @@ declare class Toride {
|
|
|
480
255
|
/**
|
|
481
256
|
* Typed factory function for creating a Toride instance.
|
|
482
257
|
*/
|
|
483
|
-
declare function createToride(options: TorideOptions): Toride
|
|
258
|
+
declare function createToride<S extends TorideSchema = DefaultSchema>(options: TorideOptions<S>): Toride<S>;
|
|
484
259
|
|
|
485
260
|
/**
|
|
486
261
|
* Constructs a Resolvers map from test case mock data.
|
|
@@ -531,4 +306,4 @@ declare function runTestCases(policy: Policy, tests: TestCase[]): Promise<TestRe
|
|
|
531
306
|
|
|
532
307
|
declare const VERSION = "0.0.1";
|
|
533
308
|
|
|
534
|
-
export {
|
|
309
|
+
export { ActorRef, BatchCheckItem, CheckOptions, type Constraint, type ConstraintAdapter, type ConstraintResult, DefaultSchema, ExplainResult, type LeafConstraint, PermissionSnapshot, Policy, Resolvers, ResourceRef, type StrictValidationResult, TestCase, type TestFileResult, type TestResult, Toride, TorideOptions, TorideSchema, VERSION, type ValidationDiagnostic, type ValidationResult, createMockResolver, createToride, loadJson, loadYaml, mergePolicies, parseInlineTests, parseTestFile, runTestCases, validatePolicy, validatePolicyResult, validatePolicyStrict };
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,10 @@ import {
|
|
|
12
12
|
validatePolicy,
|
|
13
13
|
validatePolicyResult,
|
|
14
14
|
validatePolicyStrict
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-24PMDTLE.js";
|
|
16
|
+
import {
|
|
17
|
+
TorideClient
|
|
18
|
+
} from "./chunk-475CNU63.js";
|
|
16
19
|
|
|
17
20
|
// src/policy/parser.ts
|
|
18
21
|
import * as YAML from "yaml";
|
|
@@ -226,6 +229,7 @@ export {
|
|
|
226
229
|
CycleError,
|
|
227
230
|
DepthLimitError,
|
|
228
231
|
Toride,
|
|
232
|
+
TorideClient,
|
|
229
233
|
VERSION,
|
|
230
234
|
ValidationError,
|
|
231
235
|
createMockResolver,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toride",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Relation-aware authorization engine for TypeScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
]
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"
|
|
31
|
-
"
|
|
30
|
+
"valibot": "^1.2.0",
|
|
31
|
+
"yaml": "^2.3.0"
|
|
32
32
|
},
|
|
33
33
|
"keywords": [
|
|
34
34
|
"authorization",
|
|
@@ -42,9 +42,13 @@
|
|
|
42
42
|
"type": "git",
|
|
43
43
|
"url": "https://github.com/toride-auth/toride"
|
|
44
44
|
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"tsd": "^0.33.0"
|
|
47
|
+
},
|
|
45
48
|
"scripts": {
|
|
46
49
|
"build": "tsup",
|
|
47
50
|
"test": "vitest run",
|
|
51
|
+
"typetest": "tsd --files 'src/__typetests__/*.test-d.ts'",
|
|
48
52
|
"lint": "tsc --noEmit",
|
|
49
53
|
"bench": "vitest bench"
|
|
50
54
|
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A serializable map of permissions keyed by "Type:id".
|
|
3
|
-
* Values are arrays of permitted action strings.
|
|
4
|
-
* Suitable for JSON transport to client-side TorideClient.
|
|
5
|
-
*/
|
|
6
|
-
type PermissionSnapshot = Record<string, string[]>;
|
|
7
|
-
|
|
8
|
-
export type { PermissionSnapshot as P };
|