cauthy-auth 0.28.0 → 0.30.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.
Files changed (45) hide show
  1. package/README.md +52 -1
  2. package/dist/{cauthy-XkIbG5gE.d.mts → cauthy-BXgsZ-Um.d.mts} +19 -1
  3. package/dist/{cauthy-DGAy45G2.d.ts → cauthy-CHENs452.d.ts} +19 -1
  4. package/dist/cli.js +155 -54
  5. package/dist/client.d.mts +47 -7
  6. package/dist/client.d.ts +47 -7
  7. package/dist/client.js +23 -1
  8. package/dist/client.js.map +1 -1
  9. package/dist/client.mjs +23 -1
  10. package/dist/client.mjs.map +1 -1
  11. package/dist/express.d.mts +2 -2
  12. package/dist/express.d.ts +2 -2
  13. package/dist/fastify.d.mts +2 -2
  14. package/dist/fastify.d.ts +2 -2
  15. package/dist/hono.d.mts +2 -2
  16. package/dist/hono.d.ts +2 -2
  17. package/dist/index.d.mts +2 -2
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.js +352 -131
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +350 -131
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/next.d.mts +2 -2
  24. package/dist/next.d.ts +2 -2
  25. package/dist/react.d.mts +214 -18
  26. package/dist/react.d.ts +214 -18
  27. package/dist/react.js +129 -32
  28. package/dist/react.js.map +1 -1
  29. package/dist/react.mjs +129 -32
  30. package/dist/react.mjs.map +1 -1
  31. package/dist/svelte.d.mts +2 -2
  32. package/dist/svelte.d.ts +2 -2
  33. package/dist/svelte.js +37 -2
  34. package/dist/svelte.js.map +1 -1
  35. package/dist/svelte.mjs +37 -2
  36. package/dist/svelte.mjs.map +1 -1
  37. package/dist/{system-BxMsSIu1.d.mts → system-0mHrdAgO.d.mts} +312 -112
  38. package/dist/{system-DTIeDXDP.d.ts → system-BIYbS7h2.d.ts} +312 -112
  39. package/dist/vue.d.mts +2 -2
  40. package/dist/vue.d.ts +2 -2
  41. package/dist/vue.js +37 -2
  42. package/dist/vue.js.map +1 -1
  43. package/dist/vue.mjs +37 -2
  44. package/dist/vue.mjs.map +1 -1
  45. package/package.json +1 -1
@@ -1,113 +1,6 @@
1
1
  import { JWK } from 'jose';
2
2
  import { CauthyTheme } from './theme.js';
3
3
 
4
- /** The part of an organization that says what its member may do. */
5
- interface Permitted {
6
- /** "resource:action" entries the person is allowed; "*" is any. Absent when the system keeps no catalog in Cauthy. */
7
- permissions?: string[];
8
- /** Entries the person is denied whatever else allows them. */
9
- denied?: string[];
10
- }
11
- /**
12
- * Whether the person may do an action on a resource in an organization:
13
- * allowed by some entry, and denied by none. A denial wins.
14
- *
15
- * An organization of a system that keeps no catalog in Cauthy carries no
16
- * permissions, and the answer is `false`: decide by its `role` instead.
17
- *
18
- * if (!can(organization, 'invoicing', 'write')) return forbidden()
19
- */
20
- declare function can(organization: Permitted | null | undefined, resource: string, action: string): boolean;
21
- /** Something a role may do: an action on a resource, in organizations of a kind ("*", the default, is every kind). */
22
- interface PolicyPermission {
23
- kind?: string;
24
- resource: string;
25
- action: string;
26
- }
27
- interface PolicyRole {
28
- role: string;
29
- name?: string;
30
- description?: string;
31
- /** Roles whose permissions this one has as well. */
32
- inherits?: string[];
33
- permissions?: PolicyPermission[];
34
- }
35
- /** A role as `definePolicy` reads it: any `PolicyRole`, kept as written. */
36
- type RoleShape = {
37
- readonly role: string;
38
- readonly name?: string;
39
- readonly description?: string;
40
- readonly inherits?: readonly string[];
41
- readonly permissions?: readonly {
42
- readonly kind?: string;
43
- readonly resource: string;
44
- readonly action: string;
45
- }[];
46
- };
47
- type Named<S extends string> = S extends '*' ? string : S;
48
- type PermissionsIn<R> = R extends {
49
- readonly permissions: readonly (infer P)[];
50
- } ? P extends {
51
- readonly resource: infer Res extends string;
52
- readonly action: infer Act extends string;
53
- } ? `${Named<Res>}:${Named<Act>}` : never : never;
54
- /** The roles a catalog names: `RoleOf<typeof policy>`. */
55
- type RoleOf<P> = P extends Policy<infer R, string> ? R : never;
56
- /** The "resource:action" permissions a catalog names: `PermissionOf<typeof policy>`. */
57
- type PermissionOf<P> = P extends Policy<string, infer X> ? X : never;
58
- interface Policy<Role extends string = string, Permission extends string = string> {
59
- /** The catalog as Cauthy takes it: `pushPolicy({ roles: policy.roles })`. */
60
- roles: PolicyRole[];
61
- /** Every role's name. */
62
- roleNames: Role[];
63
- /** Every permission some role has, as "resource:action". */
64
- permissions: Permission[];
65
- /**
66
- * Whether the person may do this in the organization: `can(org, 'ledger:write')`.
67
- * It reads what Cauthy sent with the session, so a catalog edited in Cauthy
68
- * since this file was written is still what decides.
69
- */
70
- can(organization: Permitted | null | undefined, permission: Permission): boolean;
71
- /** Whether the person's role in the organization is one of these. */
72
- hasRole(organization: {
73
- role: string;
74
- } | null | undefined, ...roles: Role[]): boolean;
75
- /**
76
- * What a role may do by this catalog, with what it inherits: for showing a
77
- * role, never for deciding about a person (their exceptions are not here).
78
- */
79
- permissionsOf(role: Role): Permission[];
80
- }
81
- /** Gives a catalog of roles its types. See the top of this section. */
82
- declare function definePolicy<const T extends readonly RoleShape[]>(roles: T): Policy<T[number]['role'], PermissionsIn<T[number]>>;
83
- /**
84
- * A TypeScript module that defines the catalog given, for `cauthy-auth policy
85
- * --pull` to write: the application's types then come from the catalog
86
- * Cauthy has.
87
- */
88
- declare function policySource(system: string, roles: PolicyRole[]): string;
89
- /** Reads a system's catalog of roles from Cauthy, with a personal access token. */
90
- declare function pullPolicy(o?: Omit<PushPolicyOptions, 'roles'>): Promise<PolicyRole[]>;
91
- interface PushPolicyOptions {
92
- /** The system whose catalog this is. Default: `CAUTHY_SYSTEM`. */
93
- system?: string;
94
- roles: PolicyRole[];
95
- /** Cauthy's address. Default: `CAUTHY_ISSUER`. */
96
- issuer?: string;
97
- /** The workspace's slug. Default: `CAUTHY_TENANT`. */
98
- tenant?: string;
99
- /** A personal access token with `organizations:manage`. Default: `CAUTHY_TOKEN`. */
100
- token?: string;
101
- fetch?: typeof fetch;
102
- }
103
- /**
104
- * Gives Cauthy a system's catalog of roles, replacing the one it has. It is
105
- * the way to load a first catalog from what a system already had; from then on
106
- * the catalog is Cauthy's, edited in its dashboard, and pushing again would
107
- * overwrite what was edited there.
108
- */
109
- declare function pushPolicy(o: PushPolicyOptions): Promise<void>;
110
-
111
4
  /** How an application is set up to sign its people in with Cauthy. */
112
5
  interface CauthyOptions {
113
6
  /** Cauthy's public address, e.g. `https://id.example.com`. Default: `CAUTHY_ISSUER`. */
@@ -123,7 +16,7 @@ interface CauthyOptions {
123
16
  secret?: string;
124
17
  /**
125
18
  * The system this application is, as its organizations are filed under in
126
- * Cauthy (`"pondari"`). When set, a session's organizations are that
19
+ * Cauthy (`"acme-crm"`). When set, a session's organizations are that
127
20
  * system's. Default: `CAUTHY_SYSTEM`.
128
21
  */
129
22
  system?: string;
@@ -136,9 +29,11 @@ interface CauthyOptions {
136
29
  /** Where the routes are mounted. Default: `/api/auth`. */
137
30
  basePath?: string;
138
31
  /**
139
- * The application's own public origin (`https://app.example.com`), for the
140
- * redirect URI. Default: the origin of each request, which is right unless
141
- * a proxy hides it.
32
+ * The application's own public origin (`https://app.example.com`): the
33
+ * redirect URI, the cookies' `Secure` flag and which forms are its own come
34
+ * from it. Default: `CAUTHY_BASE_URL`, else the origin of each request, with
35
+ * the scheme a proxy names in `x-forwarded-proto`. Set it whenever a proxy
36
+ * also changes the host or the port.
142
37
  */
143
38
  baseURL?: string;
144
39
  /** Where a person lands after signing in, when no `return_to` was asked. Default: `/`. */
@@ -218,6 +113,54 @@ interface SessionOrganization {
218
113
  permissions?: string[];
219
114
  /** What the person is denied here, whatever else allows it. */
220
115
  denied?: string[];
116
+ /**
117
+ * Permissions that hold only when their condition does (an amount under a
118
+ * limit, the person's own records…). They are in neither list above: `can`
119
+ * answers no for them, and `auth.check` asks Cauthy. Present, maybe empty,
120
+ * whenever `permissions` is.
121
+ */
122
+ conditional?: ConditionalPermission[];
123
+ }
124
+ /** A permission with a condition: Cauthy decides it per question (`auth.check`). */
125
+ interface ConditionalPermission {
126
+ resource: string;
127
+ action: string;
128
+ effect: 'allow' | 'deny';
129
+ }
130
+ /** What to ask Cauthy about: an action on a resource, with what the conditions read of it. */
131
+ interface CheckQuestion {
132
+ resource: string;
133
+ action: string;
134
+ /** What a condition reads as `resource.attrs`: `{ amount: 500 }`. */
135
+ attributes?: Record<string, unknown>;
136
+ /** The record's id, as a condition reads it (`resource.id`). */
137
+ resourceId?: string;
138
+ /** Whose the record is (`resource.owner_id`): `resource.owner_id == subject.id`. */
139
+ ownerId?: string;
140
+ }
141
+ /** An organization, by its id or as the session has it. */
142
+ type OrganizationRef = string | {
143
+ id: string;
144
+ };
145
+ /** The rule that decided a check. */
146
+ interface CheckRule {
147
+ /** A permission of the person's role, or an exception given to the person. */
148
+ source: 'role' | 'exception';
149
+ /** The role, when `source` is `role`. */
150
+ role?: string;
151
+ kind: string;
152
+ resource: string;
153
+ action: string;
154
+ effect: 'allow' | 'deny';
155
+ condition?: string;
156
+ }
157
+ /** Cauthy's answer to a check. */
158
+ interface CheckResult {
159
+ allowed: boolean;
160
+ /** Why, in words: "allowed by role accountant: invoices:approve". */
161
+ reason: string;
162
+ /** The rule that decided; absent when none did (nothing allows it). */
163
+ rule?: CheckRule;
221
164
  }
222
165
  /** A signed-in person, as the server sees them. */
223
166
  interface Session {
@@ -248,6 +191,242 @@ declare class CauthyConfigError extends Error {
248
191
  constructor(message: string);
249
192
  }
250
193
 
194
+ /** The part of an organization that says what its member may do. */
195
+ interface Permitted {
196
+ /** "resource:action" entries the person is allowed; "*" is any. Absent when the system keeps no catalog in Cauthy. */
197
+ permissions?: string[];
198
+ /** Entries the person is denied whatever else allows them. */
199
+ denied?: string[];
200
+ /** Permissions with a condition: in neither list, so `can` never counts them. Ask with `auth.check`. */
201
+ conditional?: ConditionalPermission[];
202
+ }
203
+ /**
204
+ * Whether the person may do an action on a resource in an organization:
205
+ * allowed by some entry, and denied by none. A denial wins.
206
+ *
207
+ * An organization of a system that keeps no catalog in Cauthy carries no
208
+ * permissions, and the answer is `false`: decide by its `role` instead.
209
+ *
210
+ * A permission with a condition (`organization.conditional`) is not in the
211
+ * lists, so `can` answers `false` for what only it allows: the condition reads
212
+ * the record at hand, which only Cauthy can weigh. Ask with `auth.check`
213
+ * (`organizations.check` in the browser).
214
+ *
215
+ * if (!can(organization, 'invoicing', 'write')) return forbidden()
216
+ */
217
+ declare function can(organization: Permitted | null | undefined, resource: string, action: string): boolean;
218
+ /** Something a role may do: an action on a resource, in organizations of a kind ("*", the default, is every kind). */
219
+ interface PolicyPermission {
220
+ kind?: string;
221
+ resource: string;
222
+ action: string;
223
+ /**
224
+ * When it holds, in CEL: `resource.attrs.amount <= 1000000`. A permission
225
+ * with one is decided by Cauthy per question (`auth.check`), never by `can`.
226
+ */
227
+ condition?: string;
228
+ }
229
+ /** The type of an attribute a condition may read: `list` is any JSON array. */
230
+ type AttributeType = 'string' | 'number' | 'bool' | 'list';
231
+ /** A resource of a system's catalog: the actions done on it and the attributes its conditions read. */
232
+ interface CatalogResource {
233
+ resource: string;
234
+ description?: string;
235
+ actions: string[];
236
+ /** Name → type, as `resource.attrs.<name>` in a condition. */
237
+ attributes?: Record<string, AttributeType>;
238
+ }
239
+ interface PolicyRole {
240
+ role: string;
241
+ name?: string;
242
+ description?: string;
243
+ /** Roles whose permissions this one has as well. */
244
+ inherits?: string[];
245
+ permissions?: PolicyPermission[];
246
+ }
247
+ type PermissionShape = {
248
+ readonly kind?: string;
249
+ readonly resource: string;
250
+ readonly action: string;
251
+ readonly condition?: string;
252
+ };
253
+ /** A role as `definePolicy` reads it: any `PolicyRole`, kept as written. */
254
+ type RoleShape = {
255
+ readonly role: string;
256
+ readonly name?: string;
257
+ readonly description?: string;
258
+ readonly inherits?: readonly string[];
259
+ readonly permissions?: readonly PermissionShape[];
260
+ };
261
+ /** A resource as `definePolicy` reads it: any `CatalogResource`, kept as written. */
262
+ type ResourceShape = {
263
+ readonly resource: string;
264
+ readonly description?: string;
265
+ readonly actions: readonly string[];
266
+ readonly attributes?: {
267
+ readonly [name: string]: AttributeType;
268
+ };
269
+ };
270
+ type Named<S extends string> = S extends '*' ? string : S;
271
+ type PermissionsIn<R> = R extends {
272
+ readonly permissions: readonly (infer P)[];
273
+ } ? P extends {
274
+ readonly resource: infer Res extends string;
275
+ readonly action: infer Act extends string;
276
+ } ? `${Named<Res>}:${Named<Act>}` : never : never;
277
+ type ValueOf<T> = T extends 'string' ? string : T extends 'number' ? number : T extends 'bool' ? boolean : T extends 'list' ? unknown[] : never;
278
+ /** What a check may say about one declared resource. */
279
+ type QuestionAbout<E> = E extends {
280
+ readonly resource: infer R extends string;
281
+ readonly actions: readonly (infer A extends string)[];
282
+ } ? {
283
+ resource: R;
284
+ action: A;
285
+ attributes?: E extends {
286
+ readonly attributes: infer T;
287
+ } ? {
288
+ [K in keyof T]?: ValueOf<T[K]>;
289
+ } : Record<string, never>;
290
+ resourceId?: string;
291
+ ownerId?: string;
292
+ } : never;
293
+ /**
294
+ * What a role of a catalog that declares its resources may name: a declared
295
+ * resource with one of its actions, or "*", or one of Cauthy's own powers.
296
+ */
297
+ type PermissionFor<C extends readonly ResourceShape[]> = {
298
+ readonly kind?: string;
299
+ readonly condition?: string;
300
+ } & ((C[number] extends infer E ? E extends {
301
+ readonly resource: infer R extends string;
302
+ readonly actions: readonly (infer A extends string)[];
303
+ } ? {
304
+ readonly resource: R;
305
+ readonly action: A | '*';
306
+ } : never : never) | {
307
+ readonly resource: '*';
308
+ readonly action: string;
309
+ } | {
310
+ readonly resource: `cauthy:${string}`;
311
+ readonly action: string;
312
+ });
313
+ type RoleFor<C extends readonly ResourceShape[]> = Omit<RoleShape, 'permissions'> & {
314
+ readonly permissions?: readonly PermissionFor<C>[];
315
+ };
316
+ /** The roles a catalog names: `RoleOf<typeof policy>`. */
317
+ type RoleOf<P> = P extends Policy<infer R, any, any> ? R : never;
318
+ /** The "resource:action" permissions a catalog names: `PermissionOf<typeof policy>`. */
319
+ type PermissionOf<P> = P extends Policy<any, infer X, any> ? X : never;
320
+ /** What a check about this catalog may ask: `CheckOf<typeof policy>`. Any resource when it declares none. */
321
+ type CheckOf<P> = P extends Policy<any, any, infer Q> ? Q : never;
322
+ /** The fields of a question: whatever else the asker takes (the organization, the person) passes through. */
323
+ type QuestionKeys = keyof CheckQuestion;
324
+ interface Policy<Role extends string = string, Permission extends string = string, Question extends CheckQuestion = CheckQuestion> {
325
+ /** The catalog as Cauthy takes it: `pushPolicy({ roles: policy.roles })`. */
326
+ roles: PolicyRole[];
327
+ /** The resources the system declares, as Cauthy takes them; empty when it declares none. */
328
+ catalog: CatalogResource[];
329
+ /** Every role's name. */
330
+ roleNames: Role[];
331
+ /** Every permission some role has, as "resource:action". */
332
+ permissions: Permission[];
333
+ /**
334
+ * Whether the person may do this in the organization: `can(org, 'ledger:write')`.
335
+ * It reads what Cauthy sent with the session, so a catalog edited in Cauthy
336
+ * since this file was written is still what decides. A permission with a
337
+ * condition is not there: ask with `check`.
338
+ */
339
+ can(organization: Permitted | null | undefined, permission: Permission): boolean;
340
+ /** Whether the person's role in the organization is one of these. */
341
+ hasRole(organization: {
342
+ role: string;
343
+ } | null | undefined, ...roles: Role[]): boolean;
344
+ /**
345
+ * What a role may do by this catalog, with what it inherits: for showing a
346
+ * role, never for deciding about a person (their exceptions are not here).
347
+ */
348
+ permissionsOf(role: Role): Permission[];
349
+ /**
350
+ * Asks Cauthy, with the resource, action and attributes typed by the
351
+ * catalog. Give it whoever asks: the server's `auth` with the request,
352
+ * the browser's `organizations`, or the application's `system`.
353
+ *
354
+ * await policy.check(auth, request, { organization, resource: 'invoices', action: 'approve', attributes: { amount: 500 } })
355
+ * await policy.check(auth.system, { organizationId, userId, resource: 'invoices', action: 'read' })
356
+ */
357
+ check<I extends CheckQuestion>(asker: {
358
+ check(input: I): Promise<CheckResult>;
359
+ }, input: Omit<I, QuestionKeys> & Question): Promise<CheckResult>;
360
+ check<R, I extends CheckQuestion>(asker: {
361
+ check(request: R, input: I): Promise<CheckResult>;
362
+ }, request: R, input: Omit<I, QuestionKeys> & Question): Promise<CheckResult>;
363
+ }
364
+ /** A catalog with its resources declared, for `definePolicy`. */
365
+ interface PolicyDefinition<C extends readonly ResourceShape[], T extends readonly RoleShape[]> {
366
+ catalog: C;
367
+ roles: T;
368
+ }
369
+ /** Gives a catalog of roles its types. See the top of this section. */
370
+ declare function definePolicy<const T extends readonly RoleShape[]>(roles: T): Policy<T[number]['role'], PermissionsIn<T[number]>>;
371
+ /** Gives a catalog of resources and roles its types: a role names only what the catalog declares. */
372
+ declare function definePolicy<const C extends readonly ResourceShape[], const T extends readonly RoleFor<C>[]>(definition: PolicyDefinition<C, T>): Policy<T[number]['role'], PermissionsIn<T[number]>, QuestionAbout<C[number]>>;
373
+ /** A system's policy as Cauthy has it: the resources it declares (maybe none) and its roles. */
374
+ interface SystemPolicy {
375
+ catalog: CatalogResource[];
376
+ roles: PolicyRole[];
377
+ }
378
+ /**
379
+ * A TypeScript module that defines the catalog given, for `cauthy-auth policy
380
+ * --pull` to write: the application's types then come from the catalog
381
+ * Cauthy has. With resources declared it is `definePolicy({ catalog, roles })`;
382
+ * without, the list of roles alone, as it always was.
383
+ */
384
+ declare function policySource(system: string, read: PolicyRole[] | {
385
+ catalog?: CatalogResource[];
386
+ roles: PolicyRole[];
387
+ }): string;
388
+ /** Reads a system's catalog of roles from Cauthy, with a personal access token. */
389
+ declare function pullPolicy(o?: Omit<PushPolicyOptions, 'roles'>): Promise<PolicyRole[]>;
390
+ /** Reads the resources a system declares (empty when it declares none), with a personal access token. */
391
+ declare function pullCatalog(o?: Omit<PushPolicyOptions, 'roles'>): Promise<CatalogResource[]>;
392
+ interface PushPolicyOptions {
393
+ /** The system whose catalog this is. Default: `CAUTHY_SYSTEM`. */
394
+ system?: string;
395
+ roles: PolicyRole[];
396
+ /**
397
+ * The resources the system declares. Given, they are sent before the roles,
398
+ * which Cauthy then checks against them; left out, the catalog Cauthy has
399
+ * stays as it is.
400
+ */
401
+ catalog?: CatalogResource[];
402
+ /** Cauthy's address. Default: `CAUTHY_ISSUER`. */
403
+ issuer?: string;
404
+ /** The workspace's slug. Default: `CAUTHY_TENANT`. */
405
+ tenant?: string;
406
+ /**
407
+ * A personal access token: `organizations:manage` reads, and changing a
408
+ * policy or a catalog takes `systems:policy`. Default: `CAUTHY_TOKEN`.
409
+ */
410
+ token?: string;
411
+ fetch?: typeof fetch;
412
+ }
413
+ /**
414
+ * Gives Cauthy a system's catalog of roles, replacing the one it has. It is
415
+ * the way to load a first catalog from what a system already had; from then on
416
+ * the catalog is Cauthy's, edited in its dashboard, and pushing again would
417
+ * overwrite what was edited there. With `catalog` the declared resources go
418
+ * first: the roles are checked against them.
419
+ */
420
+ declare function pushPolicy(o: PushPolicyOptions): Promise<void>;
421
+ /**
422
+ * Gives Cauthy the resources a system declares, replacing the ones it has.
423
+ * Cauthy refuses (`catalog_in_use`) to drop a resource or an action the
424
+ * policy still names.
425
+ */
426
+ declare function pushCatalog(o: Omit<PushPolicyOptions, 'roles' | 'catalog'> & {
427
+ resources: CatalogResource[];
428
+ }): Promise<CatalogResource[]>;
429
+
251
430
  /** The key an application signs its assertions with. */
252
431
  interface SystemKey {
253
432
  /** The private key: PKCS#8 PEM, or a JWK (as an object or its JSON). RSA, for RS256. */
@@ -267,6 +446,8 @@ interface SystemOptions {
267
446
  * Default: `CAUTHY_SYSTEM_KEY` (the private key) and `CAUTHY_SYSTEM_KEY_ID`.
268
447
  */
269
448
  key?: SystemKey;
449
+ /** The application's system, which `check` asks about. Default: `CAUTHY_SYSTEM`. */
450
+ system?: string;
270
451
  fetch?: typeof fetch;
271
452
  }
272
453
  /** Cauthy refused a request of the application's own. */
@@ -371,6 +552,25 @@ interface CauthySystem {
371
552
  policy: {
372
553
  get(system: string): Promise<PolicyRole[]>;
373
554
  };
555
+ /**
556
+ * The resources one of the application's systems declares, with their
557
+ * actions and the attributes conditions read; empty when it declares none.
558
+ */
559
+ catalog: {
560
+ get(system: string): Promise<CatalogResource[]>;
561
+ /** Replaces them. Cauthy refuses (`catalog_in_use`) to drop one the policy still names. */
562
+ set(system: string, resources: CatalogResource[]): Promise<CatalogResource[]>;
563
+ };
564
+ /**
565
+ * Asks Cauthy whether a member of one of the system's organizations may do
566
+ * an action on a resource, conditions weighed. A person who is not a member
567
+ * is a no; an organization of another system throws (`organization_not_found`).
568
+ */
569
+ check(question: CheckQuestion & {
570
+ organizationId: string;
571
+ userId: string;
572
+ system?: string;
573
+ }): Promise<CheckResult>;
374
574
  /** The public half of `key`, to serve at the address Cauthy was given (`jwks_uri`). Empty with a secret. */
375
575
  publicJwks(): Promise<{
376
576
  keys: JWK[];
@@ -378,4 +578,4 @@ interface CauthySystem {
378
578
  }
379
579
  declare function createSystem(given?: SystemOptions): CauthySystem;
380
580
 
381
- export { CauthyApiError as C, type JsonValue as J, type NewMember as N, type Organization as O, type PermissionOf as P, type RoleOf as R, type Session as S, CauthyConfigError as a, type CauthyOptions as b, type CauthySystem as c, type OrganizationMember as d, type Permitted as e, type Policy as f, type PolicyPermission as g, type PolicyRole as h, type PublicSession as i, type PushPolicyOptions as j, type SessionOrganization as k, type SessionStatus as l, type SessionUser as m, type SystemKey as n, type SystemOptions as o, can as p, createSystem as q, definePolicy as r, policySource as s, pullPolicy as t, pushPolicy as u };
581
+ export { type AttributeType as A, definePolicy as B, type CatalogResource as C, policySource as D, pullCatalog as E, pullPolicy as F, pushCatalog as G, pushPolicy as H, type JsonValue as J, type NewMember as N, type Organization as O, type PermissionOf as P, type RoleOf as R, type Session as S, CauthyApiError as a, CauthyConfigError as b, type CauthyOptions as c, type CauthySystem as d, type CheckOf as e, type CheckQuestion as f, type CheckResult as g, type CheckRule as h, type ConditionalPermission as i, type OrganizationMember as j, type OrganizationRef as k, type Permitted as l, type Policy as m, type PolicyDefinition as n, type PolicyPermission as o, type PolicyRole as p, type PublicSession as q, type PushPolicyOptions as r, type SessionOrganization as s, type SessionStatus as t, type SessionUser as u, type SystemKey as v, type SystemOptions as w, type SystemPolicy as x, can as y, createSystem as z };
package/dist/vue.d.mts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { ShallowRef, Plugin } from 'vue';
2
2
  import { SessionStore, SessionState, SessionStoreOptions, AuthClient } from './client.mjs';
3
3
  export { Account, AccountSession, AuthError, AuthMethods, AuthResult, Passkey, PasskeyKind, SSOConnection } from './client.mjs';
4
- import { i as PublicSession } from './system-BxMsSIu1.mjs';
5
- export { P as PermissionOf, f as Policy, R as RoleOf, k as SessionOrganization, m as SessionUser, p as can, r as definePolicy } from './system-BxMsSIu1.mjs';
4
+ import { q as PublicSession } from './system-0mHrdAgO.mjs';
5
+ export { P as PermissionOf, m as Policy, R as RoleOf, s as SessionOrganization, u as SessionUser, y as can, B as definePolicy } from './system-0mHrdAgO.mjs';
6
6
  import './theme.mjs';
7
7
  import './validate-sEXG82po.mjs';
8
8
  import 'jose';
package/dist/vue.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { ShallowRef, Plugin } from 'vue';
2
2
  import { SessionStore, SessionState, SessionStoreOptions, AuthClient } from './client.js';
3
3
  export { Account, AccountSession, AuthError, AuthMethods, AuthResult, Passkey, PasskeyKind, SSOConnection } from './client.js';
4
- import { i as PublicSession } from './system-DTIeDXDP.js';
5
- export { P as PermissionOf, f as Policy, R as RoleOf, k as SessionOrganization, m as SessionUser, p as can, r as definePolicy } from './system-DTIeDXDP.js';
4
+ import { q as PublicSession } from './system-BIYbS7h2.js';
5
+ export { P as PermissionOf, m as Policy, R as RoleOf, s as SessionOrganization, u as SessionUser, y as can, B as definePolicy } from './system-BIYbS7h2.js';
6
6
  import './theme.js';
7
7
  import './validate-sEXG82po.js';
8
8
  import 'jose';
package/dist/vue.js CHANGED
@@ -285,6 +285,12 @@ function checkOrganization(value, required = false) {
285
285
  if (v.length > MAX_ORGANIZATION) return { field: "organization", code: "too_long", message: `Use at most ${MAX_ORGANIZATION} characters.` };
286
286
  return null;
287
287
  }
288
+ function checkOrganizationName(value) {
289
+ const v = typeof value === "string" ? value.trim() : "";
290
+ if (v === "") return { field: "name", code: "required", message: "Enter the organization's name." };
291
+ if (v.length > MAX_ORGANIZATION) return { field: "name", code: "too_long", message: `Use at most ${MAX_ORGANIZATION} characters.` };
292
+ return null;
293
+ }
288
294
  function checkCode(value) {
289
295
  const v = typeof value === "string" ? value.trim() : "";
290
296
  if (v === "") return { field: "code", code: "required", message: "Enter the code." };
@@ -537,7 +543,23 @@ function createAuthClient(options = {}) {
537
543
  add: (id, f) => post("/me/organizations/members/add", { organizationId: id, email: f.email, role: f.role, name: f.name ?? "", locale: f.locale ?? "" }, checkEmail(f.email)),
538
544
  setRole: (id, userId, role) => post("/me/organizations/members/role", { organizationId: id, userId, role }, null),
539
545
  remove: (id, userId) => post("/me/organizations/members/remove", { organizationId: id, userId }, null),
540
- inviteAgain: (id, userId, f = {}) => post("/me/organizations/members/invite", { organizationId: id, userId, locale: f.locale ?? "" }, null)
546
+ inviteAgain: (id, userId, f = {}) => post("/me/organizations/members/invite", { organizationId: id, userId, locale: f.locale ?? "" }, null),
547
+ rename: (id, name) => post("/me/organizations/rename", { organizationId: id, name }, checkOrganizationName(name)),
548
+ archive: (id) => post("/me/organizations/archive", { organizationId: id }, null),
549
+ delete: (id) => post("/me/organizations/delete", { organizationId: id }, null),
550
+ async check(q) {
551
+ const organizationId = typeof q.organization === "string" ? q.organization : q.organization?.id ?? "";
552
+ const r = await post("/me/organizations/check", {
553
+ organizationId,
554
+ resource: q.resource,
555
+ action: q.action,
556
+ ...q.attributes !== void 0 ? { attributes: q.attributes } : {},
557
+ ...q.resourceId !== void 0 ? { resourceId: q.resourceId } : {},
558
+ ...q.ownerId !== void 0 ? { ownerId: q.ownerId } : {}
559
+ }, null);
560
+ if (!r.ok) return { allowed: false, reason: r.error.message, error: r.error };
561
+ return { allowed: r.allowed === true, reason: String(r.reason ?? ""), ...r.rule ? { rule: r.rule } : {} };
562
+ }
541
563
  },
542
564
  account: {
543
565
  async get() {
@@ -741,7 +763,9 @@ function can(organization, resource, action) {
741
763
  if ((organization.denied ?? []).some((d) => matches(d, resource, action))) return false;
742
764
  return organization.permissions.some((p) => matches(p, resource, action));
743
765
  }
744
- function definePolicy(roles) {
766
+ function definePolicy(given) {
767
+ const roles = Array.isArray(given) ? given : given.roles;
768
+ const resources = Array.isArray(given) ? [] : given.catalog ?? [];
745
769
  const entry = (p) => `${p.resource}:${p.action}`;
746
770
  const byName = new Map(roles.map((r) => [r.role, r]));
747
771
  const split = (permission) => {
@@ -756,6 +780,12 @@ function definePolicy(roles) {
756
780
  ...r.inherits ? { inherits: [...r.inherits] } : {},
757
781
  ...r.permissions ? { permissions: r.permissions.map((p) => ({ ...p })) } : {}
758
782
  })),
783
+ catalog: resources.map((c) => ({
784
+ resource: c.resource,
785
+ ...c.description !== void 0 ? { description: c.description } : {},
786
+ actions: [...c.actions],
787
+ ...c.attributes ? { attributes: { ...c.attributes } } : {}
788
+ })),
759
789
  roleNames: roles.map((r) => r.role),
760
790
  permissions: [...new Set(roles.flatMap((r) => (r.permissions ?? []).map(entry)))],
761
791
  can(organization, permission) {
@@ -777,6 +807,11 @@ function definePolicy(roles) {
777
807
  };
778
808
  walk(role);
779
809
  return [...out];
810
+ },
811
+ // The types did the work; this only hands the question on, as a method of
812
+ // the asker so it keeps its `this`.
813
+ check(asker, ...args) {
814
+ return asker.check(...args);
780
815
  }
781
816
  };
782
817
  }