@aiquants/authz-react-router 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2,10 +2,36 @@ import * as react_router from 'react-router';
2
2
  import * as react from 'react';
3
3
  import { ReactNode, CSSProperties } from 'react';
4
4
  import * as _aiquants_authz_core from '@aiquants/authz-core';
5
- import { EffectivePermission, DenyInfo, AuthzAction, GuardResult, AuthzGrant, AuthzUser, AuthzRole, AuthzResource, AuthzAssignment, AuthzGroupRoleAssignment, AuthzGroupSummary, AuthzAdminStore } from '@aiquants/authz-core';
5
+ import { EffectivePermission, DenyInfo, AuthzAction, MergedScope, AuthzGrant, AuthzUser, AuthzRole, AuthzResource, AuthzAssignment, AuthzGroupRoleAssignment, AuthzGroupSummary, AuthzAdminStore } from '@aiquants/authz-core';
6
+
7
+ /**
8
+ * React Router (v7) adapter: binds `appKey` + the DI ports and exposes the loader/action authorization API.
9
+ * React Router (v7) 向けアダプタ。`appKey` と DI ポートを束ね、loader/action 用の認可 API を公開するモジュール。
10
+ *
11
+ * 設計上の中心的な不変条件は **判定は 1 回だけ** ということ。ガード (`requirePermission`) と
12
+ * UI 表示用の権限ビューは同一の実効権限から導出されるため、「画面は開けるのに一覧では false」
13
+ * という乖離が構造的に起こり得ない。
14
+ */
6
15
 
7
16
  type Awaitable<T> = T | Promise<T>;
8
17
  type AuthzUserId = string | number;
18
+ /**
19
+ * Thrown when the API itself is called incorrectly (bad arguments, missing port) — a programmer error,
20
+ * never an authorization decision. It is deliberately NOT an `AuthzDeniedError`: a misuse must surface as a
21
+ * loud 500, not as a silent 403 that looks like a permission problem.
22
+ * API の使い方が誤っている場合に送出される例外。認可拒否 (403) とは明確に区別されるプログラマ向けエラー。
23
+ */
24
+ declare class AuthzUsageError extends Error {
25
+ constructor(message: string);
26
+ }
27
+ /** Arguments handed to the {@link AuthzConfig.getEffectivePermissions} port. 実効権限ポートへ渡す引数。 */
28
+ type EffectivePermissionsQuery = {
29
+ userId: AuthzUserId | null;
30
+ groupIds?: (string | number)[];
31
+ appKey: string;
32
+ /** Always a de-duplicated, non-empty list — the port may load them all in one round-trip. Read-only: the adapter reports on exactly these keys. */
33
+ resourceKeys: readonly string[];
34
+ };
9
35
  type AuthzConfig = {
10
36
  /** Stable app identifier (e.g. "quants"). Bound into every permission query. */
11
37
  appKey: string;
@@ -13,13 +39,18 @@ type AuthzConfig = {
13
39
  resolveUserId: (request: Request) => Awaitable<AuthzUserId | null | undefined>;
14
40
  /** Optionally resolve acting user's group IDs from the request or session. */
15
41
  resolveGroupIds?: (request: Request) => Awaitable<(string | number)[] | null | undefined>;
16
- /** Load effective permissions for (user, app, resource) — typically via @aiquants/authz-drizzle. */
17
- getEffectivePermissions: (args: {
18
- userId: AuthzUserId | null;
19
- groupIds?: (string | number)[];
20
- appKey: string;
21
- resourceKey: string;
22
- }) => Awaitable<EffectivePermission | null | undefined>;
42
+ /**
43
+ * Load effective permissions for (user, app, resources) — **one call, many resources** (typically
44
+ * `getEffectivePermissionsMany` from `@aiquants/authz-drizzle`). A key with no grants may be omitted or
45
+ * mapped to `null`; both mean "no permission" (fail-close).
46
+ */
47
+ getEffectivePermissions: (args: EffectivePermissionsQuery) => Awaitable<Record<string, EffectivePermission | null | undefined> | null | undefined>;
48
+ /**
49
+ * Optional: every resource key registered for this app (typically `listResourceKeys` from
50
+ * `@aiquants/authz-drizzle`). Configuring it is what makes `getMyPermissions(request)` — with no resource
51
+ * list — legal; without it that call throws {@link AuthzUsageError} instead of guessing.
52
+ */
53
+ listResourceKeys?: (request: Request) => Awaitable<readonly string[] | null | undefined>;
23
54
  /** Default deny handler. If omitted, denies throw AuthzDeniedError (403). */
24
55
  onDeny?: (info: DenyInfo) => void;
25
56
  };
@@ -27,41 +58,82 @@ type RequirePermissionOptions = {
27
58
  /** When set, denials `throw redirect(failureRedirect)` instead of throwing 403. */
28
59
  failureRedirect?: string;
29
60
  };
30
- /** Serializable per-resource permission summary for UI (loader → component). */
31
- type PermissionView = {
32
- resourceKey: string;
33
- read: boolean;
34
- create: boolean;
35
- update: boolean;
36
- delete: boolean;
61
+ /**
62
+ * Serializable per-resource permission summary for UI (loader → component).
63
+ * UI 向けの直列化可能なリソース単位権限サマリ (loader からコンポーネントへ受け渡す形)。
64
+ *
65
+ * 真偽値は `can` 接頭辞で統一されている。`delete` のような素の動詞名は分割代入できず
66
+ * (`const { delete } = view` は構文エラー)、フックの戻り値との二重語彙も生むため採用しない。
67
+ */
68
+ type PermissionView<K extends string = string> = {
69
+ resourceKey: K;
70
+ canRead: boolean;
71
+ canCreate: boolean;
72
+ canUpdate: boolean;
73
+ canDelete: boolean;
37
74
  /** create ∪ update */
38
- write: boolean;
75
+ canWrite: boolean;
39
76
  /** read granted but row and/or column restricted (→ △ partial). */
40
77
  readPartial: boolean;
41
78
  actions: AuthzAction[];
42
79
  };
43
- /** Map an EffectivePermission to a serializable {@link PermissionView}. */
44
- declare function toPermissionView(resourceKey: string, perm: EffectivePermission | null | undefined): PermissionView;
80
+ /** Result of a successful {@link createAuthz} guard. ガード成功時の戻り値。 */
81
+ type RequirePermissionResult<K extends string = string> = {
82
+ userId: AuthzUserId | null;
83
+ /** Effective row/column scope for the guarded action — apply as WHERE / column mask. */
84
+ scope: MergedScope;
85
+ /** UI view derived from the **same** evaluation as the guard decision (no second lookup). */
86
+ permission: PermissionView<K>;
87
+ };
88
+ /**
89
+ * Permission views keyed by the exact resource keys that were requested.
90
+ * 要求したキーで型付けした権限ビュー群。
91
+ *
92
+ * リテラルのキーを渡した場合だけ「そのキーは必ず存在する」形になる。`string[]` のようにキーが実行時に
93
+ * しか分からない場合は `| undefined` を含む索引型へ落ち、存在チェックを強制する (総和型の索引を
94
+ * 名乗ると、要求していないキーが型の上では必ず存在することになり、元の不具合と同じ罠に戻る)。
95
+ *
96
+ * ⚠️ キーは配列の **要素型** から導かれる。`flag ? ["a"] : ["b"]` のように要素型が合併になる式では、
97
+ * 実行時に片方しか無くても型の上では両方が存在する扱いになる。リテラル配列を直接渡すか
98
+ * `resourceKeysOf(registry)` を使うこと。
99
+ * ⚠️ 戻り値を `Record<string, …>` 型の変数へ代入すると、その文脈から `K` が `string` へ広がり
100
+ * 索引型 (値は `| undefined`) に落ちる。リテラルキーの保証が要る箇所では代入先を広げないこと。
101
+ * ⚠️ 戻り値は素のオブジェクト。要求していない `toString` などのキーを読むと `Object.prototype` の
102
+ * メンバが返る (索引型の `| undefined` とは一致しない)。要求したキーだけを読むこと。
103
+ */
104
+ type PermissionViewMap<K extends string> = string extends K ? Record<string, PermissionView | undefined> : {
105
+ [P in K]: PermissionView<P>;
106
+ };
107
+ /**
108
+ * Map an EffectivePermission to a serializable {@link PermissionView}.
109
+ * 実効権限を直列化可能な {@link PermissionView} へ変換する処理。
110
+ *
111
+ * @returns The UI-facing permission summary (all-false when `perm` is absent). UI 表示用の権限サマリ。
112
+ */
113
+ declare function toPermissionView<K extends string>(resourceKey: K, perm: EffectivePermission | null | undefined): PermissionView<K>;
45
114
  /**
46
115
  * React Router adapter. Binds `appKey` and the DI deps, exposing:
47
- * - `requirePermission(request, {resourceKey, action}, options?)` → `{ userId, scope }` on allow
48
- * (apply row WHERE / column mask with the returned scope); denies throw 403 or redirect.
49
- * - `getMyPermissions(request, {resourceKeys})` → `Record<resourceKey, PermissionView>` for the UI.
116
+ * - `requirePermission(request, {resourceKey, action}, options?)` → `{ userId, scope, permission }` on allow
117
+ * (apply row WHERE / column mask with `scope`; render `permission` in the UI); denies throw 403 or redirect.
118
+ * - `getMyPermissions(request, {resourceKeys})` → `Record<resourceKey, PermissionView>` for the UI,
119
+ * or `getMyPermissions(request)` for every registered resource when `listResourceKeys` is configured.
120
+ * `appKey` と DI ポートを束ね、ガードと自己権限取得の 2 面だけを公開するファクトリ。
121
+ *
122
+ * @returns The bound `requirePermission` / `getMyPermissions` pair. 結線済みの認可 API 一式。
50
123
  */
51
124
  declare function createAuthz(config: AuthzConfig): {
52
- requirePermission: (request: Request, query: {
53
- resourceKey: string;
125
+ requirePermission: <K extends string>(request: Request, query: {
126
+ resourceKey: K;
54
127
  action: AuthzAction;
55
- }, options?: RequirePermissionOptions) => Promise<GuardResult<AuthzUserId>>;
56
- getMyPermissions: (request: Request, query: {
57
- resourceKeys: string[];
58
- }) => Promise<Record<string, PermissionView>>;
59
- requireAndGetPermission: (request: Request, query: {
60
- resourceKey: string;
61
- action: AuthzAction;
62
- }, options?: RequirePermissionOptions) => Promise<GuardResult<AuthzUserId> & {
63
- permission: PermissionView;
64
- }>;
128
+ }, options?: RequirePermissionOptions) => Promise<RequirePermissionResult<K>>;
129
+ getMyPermissions: {
130
+ <K extends string>(request: Request, options: {
131
+ resourceKeys: readonly K[];
132
+ }): Promise<PermissionViewMap<K>>;
133
+ (request: Request, options?: {
134
+ resourceKeys?: readonly string[];
135
+ }): Promise<Record<string, PermissionView | undefined>>;
136
+ };
65
137
  };
66
138
 
67
139
  /** Authz admin UI strings (i18n). Defaults are English; override per-section via `createAuthzAdminRoutes(..., { labels })`. */
@@ -182,7 +254,7 @@ type WithLabels = {
182
254
  labels: AuthzAdminLabels;
183
255
  };
184
256
  type AuthzLayoutData = WithLabels & {
185
- myPermissions: Record<string, PermissionView>;
257
+ myPermissions: Record<string, PermissionView | undefined>;
186
258
  adminResourceKey: string;
187
259
  basePath?: string;
188
260
  };
@@ -286,18 +358,17 @@ type CreateAuthzAdminServerOptions = {
286
358
  /** 未ログインをログインへ誘導する(例: throw redirect(...))。 */
287
359
  requireUser: (request: Request) => Promise<unknown>;
288
360
  /**
289
- * 認可ガード(アプリの createAuthz 由来)。allow { userId } を返す。
290
- * 0.2.0GuardResult.userId nullable 化したため、戻り型も null を受ける。
291
- * userId==null(未解決/万一の public 付与)createAuthzAdminServer 内で deny する
361
+ * Authorization guard supplied by the app (from `createAuthz`); allow `{ userId, permission }`.
362
+ * 認可ガード (アプリの createAuthz 由来)。allow { userId, permission } を返すポート。
363
+ * `userId` は nullable(未解決/万一の public 付与)であり、createAuthzAdminServer 内で deny する
292
364
  * (管理経路は監査・自己権限計算に実 id が必須のため非 null を保証)。
365
+ * `permission` は **同一判定から導かれた** 自己権限ビューであり、表示用に再取得しない
366
+ * (再取得は「ガードは通るのにバッジは権限なし」という乖離の温床)。
293
367
  */
294
368
  requirePermission: (request: Request, query: PermissionQuery) => Promise<{
295
369
  userId: string | number | null;
370
+ permission: PermissionView;
296
371
  }>;
297
- /** 自己権限表示用(アプリの createAuthz 由来)。 */
298
- getMyPermissions: (request: Request, args: {
299
- resourceKeys: string[];
300
- }) => Promise<Record<string, PermissionView>>;
301
372
  /** 文言の部分上書き(既定は日本語)。 */
302
373
  labels?: PartialAuthzAdminLabels;
303
374
  };
@@ -307,9 +378,9 @@ declare function createAuthzAdminServer(opts: CreateAuthzAdminServerOptions): {
307
378
  resourceKey: string;
308
379
  layoutGuard: (request: Request) => Promise<{
309
380
  userId: string | number;
381
+ myPermissions: Record<string, PermissionView | undefined>;
310
382
  }>;
311
- loadMyPermissions: (request: Request) => Promise<Record<string, PermissionView>>;
312
- /** /authz レイアウト: requireUser(302) → requirePermission(read, 403) → 自己権限取得。 */
383
+ /** /authz レイアウト: requireUser(302) requirePermission(read, 403)。自己権限はガードの戻り値から得る。 */
313
384
  layout: {
314
385
  loader({ request }: Req): Promise<AuthzLayoutData>;
315
386
  };
@@ -376,6 +447,12 @@ type CreateAuthzAdminAppOptions = CreateAuthzAdminServerOptions & {
376
447
  /** マウントのベースパス(タブリンク/未指定セグメントのリダイレクト先)。既定 `/authz`。 */
377
448
  basePath?: string;
378
449
  };
450
+ /**
451
+ * Build the loader/action pair that serves the whole authorization admin UI from one splat route.
452
+ * 認可管理 UI 全体を 1 本のスプラットルートで提供する loader/action 対を生成するファクトリ。
453
+ *
454
+ * @returns The route `loader` / `action` plus the underlying server for direct use. ルートの loader/action と内部サーバ。
455
+ */
379
456
  declare function createAuthzAdminApp(opts: CreateAuthzAdminAppOptions): {
380
457
  loader: (args: RouteArgs) => Promise<{
381
458
  labels: AuthzAdminLabels;
@@ -383,14 +460,14 @@ declare function createAuthzAdminApp(opts: CreateAuthzAdminAppOptions): {
383
460
  selfAdminRoleIds?: number[];
384
461
  segment: string;
385
462
  basePath: string;
386
- myPermissions: Record<string, PermissionView>;
463
+ myPermissions: Record<string, PermissionView | undefined>;
387
464
  adminResourceKey: string;
388
465
  } | {
389
466
  labels: AuthzAdminLabels;
390
467
  resources: _aiquants_authz_core.AuthzResource[];
391
468
  segment: string;
392
469
  basePath: string;
393
- myPermissions: Record<string, PermissionView>;
470
+ myPermissions: Record<string, PermissionView | undefined>;
394
471
  adminResourceKey: string;
395
472
  } | {
396
473
  labels: AuthzAdminLabels;
@@ -406,7 +483,7 @@ declare function createAuthzAdminApp(opts: CreateAuthzAdminAppOptions): {
406
483
  }>;
407
484
  segment: string;
408
485
  basePath: string;
409
- myPermissions: Record<string, PermissionView>;
486
+ myPermissions: Record<string, PermissionView | undefined>;
410
487
  adminResourceKey: string;
411
488
  } | {
412
489
  labels: AuthzAdminLabels;
@@ -420,7 +497,7 @@ declare function createAuthzAdminApp(opts: CreateAuthzAdminAppOptions): {
420
497
  selfAdminRoleIds?: number[];
421
498
  segment: string;
422
499
  basePath: string;
423
- myPermissions: Record<string, PermissionView>;
500
+ myPermissions: Record<string, PermissionView | undefined>;
424
501
  adminResourceKey: string;
425
502
  } | {
426
503
  labels: AuthzAdminLabels;
@@ -429,7 +506,7 @@ declare function createAuthzAdminApp(opts: CreateAuthzAdminAppOptions): {
429
506
  groups: _aiquants_authz_core.AuthzGroupSummary[];
430
507
  segment: string;
431
508
  basePath: string;
432
- myPermissions: Record<string, PermissionView>;
509
+ myPermissions: Record<string, PermissionView | undefined>;
433
510
  adminResourceKey: string;
434
511
  }>;
435
512
  action: (args: RouteArgs) => Promise<unknown>;
@@ -438,8 +515,8 @@ declare function createAuthzAdminApp(opts: CreateAuthzAdminAppOptions): {
438
515
  resourceKey: string;
439
516
  layoutGuard: (request: Request) => Promise<{
440
517
  userId: string | number;
518
+ myPermissions: Record<string, PermissionView | undefined>;
441
519
  }>;
442
- loadMyPermissions: (request: Request) => Promise<Record<string, PermissionView>>;
443
520
  layout: {
444
521
  loader({ request }: {
445
522
  request: Request;
@@ -608,12 +685,16 @@ declare function getPermissionSummary(permission: PermissionView | null | undefi
608
685
  */
609
686
  declare function MyPermissionGroupStatus({ items, prefixLabel, variant, size, labels, className, style }: MyPermissionGroupStatusProps): react.JSX.Element;
610
687
 
611
- type MyPermissionIndicatorProps = {
612
- permission: PermissionView | null | undefined;
688
+ type MyPermissionIndicatorProps<K extends string = string> = {
689
+ permission: PermissionView<K> | null | undefined;
613
690
  /** Human-readable resource display name (e.g. "文書データ"). Falls back to permission.resourceKey. */
614
691
  resourceName?: string;
615
- /** Expected resource key to detect mismatches with permission.resourceKey during development. */
616
- expectedResourceKey?: string;
692
+ /**
693
+ * Expected resource key. Typed as `NoInfer<K>`, so when the permission carries a literal key
694
+ * (`getMyPermissions` / `requirePermission` both do) a mismatch is a **compile error**; the runtime
695
+ * detector below stays for dynamically-keyed and JavaScript callers.
696
+ */
697
+ expectedResourceKey?: NoInfer<K>;
617
698
  /** Whether to include resource name/key tooltip. Default true. */
618
699
  showResourceTooltip?: boolean;
619
700
  labels?: {
@@ -625,7 +706,7 @@ type MyPermissionIndicatorProps = {
625
706
  showScopeSummary?: boolean;
626
707
  className?: string;
627
708
  };
628
- type MyPermissionStatusProps = MyPermissionIndicatorProps & {
709
+ type MyPermissionStatusProps<K extends string = string> = MyPermissionIndicatorProps<K> & {
629
710
  /** Label prefix shown before the indicator badges. Default: "あなたの権限" */
630
711
  prefixLabel?: string;
631
712
  /** Whether to display the prefix label. Default: true */
@@ -642,12 +723,12 @@ declare function formatResourceTooltip(resourceKey?: string, resourceName?: stri
642
723
  * Display permission indicator badges for read, write, and delete capabilities.
643
724
  * 閲覧・編集・削除の権限状態バッジ群を描画。
644
725
  */
645
- declare function MyPermissionIndicator({ permission, resourceName, expectedResourceKey, showResourceTooltip, labels, showScopeSummary, className }: MyPermissionIndicatorProps): react.JSX.Element;
726
+ declare function MyPermissionIndicator<K extends string = string>({ permission, resourceName, expectedResourceKey, showResourceTooltip, labels, showScopeSummary, className }: MyPermissionIndicatorProps<K>): react.JSX.Element;
646
727
  /**
647
728
  * Reusable "Your Permissions" status bar component suitable for any application page.
648
729
  * 「あなたの権限」ラベルと権限状態インジケータを束ねた再利用可能なコンポーネント。
649
730
  */
650
- declare function MyPermissionStatus({ permission, resourceName, expectedResourceKey, prefixLabel, showPrefixLabel, showResourceTooltip, labels, showScopeSummary, className, style }: MyPermissionStatusProps): react.JSX.Element;
731
+ declare function MyPermissionStatus<K extends string = string>({ permission, resourceName, expectedResourceKey, prefixLabel, showPrefixLabel, showResourceTooltip, labels, showScopeSummary, className, style, }: MyPermissionStatusProps<K>): react.JSX.Element;
651
732
 
652
733
  /**
653
734
  * Resource definition and registry utilities for preventing page-resource mismatches.
@@ -670,19 +751,66 @@ type ResourceDefinitionInput = {
670
751
  description?: string;
671
752
  };
672
753
  type ResourceRegistry<T extends Record<string, ResourceDefinition>> = T;
754
+ /**
755
+ * The resource key an entry resolves to: its explicit `key`, otherwise the property name.
756
+ * `key` を明示していればそれ、無ければプロパティ名。
757
+ *
758
+ * `Extract<…, string>` を挟むのは `key?: string` (省略可) が `string | undefined` になり、素の
759
+ * `extends string` では偽になってプロパティ名を名乗ってしまうため (実行時は `key` を使うので型が嘘になる)。
760
+ * `key` を書いていないエントリでは `Extract` が `never` になり、プロパティ名へ落ちる。
761
+ */
762
+ type ResolvedResourceKey<PropertyName extends string, Input extends ResourceDefinitionInput> = [Extract<Input["key"], string>] extends [never] ? PropertyName : Extract<Input["key"], string>;
673
763
  /**
674
764
  * Define type-safe resource registry for an application.
675
765
  * アプリ全体のリソース定義(キー・表示名・説明)を一元管理するヘルパー。
766
+ *
767
+ * 各エントリの `key` はリテラル型のまま保持する。`Record<string, …>` へ広げてしまうと
768
+ * {@link resourceKeysOf} が `string[]` に落ち、権限マップのキー型検査が効かなくなるため。
769
+ *
770
+ * @returns The registry with literal-typed resource keys. リソースキーをリテラル型で保持したレジストリ。
676
771
  */
677
- declare function defineResources<T extends Record<string, ResourceDefinitionInput>>(resources: T): {
678
- [K in keyof T & string]: ResourceDefinition;
772
+ declare function defineResources<const T extends Record<string, ResourceDefinitionInput>>(resources: T): {
773
+ [K in keyof T & string]: {
774
+ key: ResolvedResourceKey<K, T[K]>;
775
+ name: string;
776
+ description?: string;
777
+ };
679
778
  };
779
+ /**
780
+ * Extract a registry's resource keys with their literal types preserved.
781
+ * レジストリのリソースキーをリテラル型を保ったまま取り出す処理。
782
+ *
783
+ * `Object.keys(registry)` は `string[]` になり、`getMyPermissions` の戻り値も索引型へ落ちてキーの誤りを
784
+ * 検出できなくなる。加えて `Object.keys` は **プロパティ名** を返すため、`key` を明示したエントリでは
785
+ * 実際のリソースキーと食い違う。
786
+ *
787
+ * ⚠️ 1 エントリでもリテラルでない `key` (例: 変数由来の `string`) を持つと、合併の性質上レジストリ全体の
788
+ * キー型が `string` へ広がり、他のエントリ分のコンパイル時検査も無効になる。`key` は必ずリテラルで書くこと。
789
+ *
790
+ * @returns The registry's resource keys as a literal union array. リテラル合併型のリソースキー配列。
791
+ */
792
+ declare function resourceKeysOf<T extends Record<string, {
793
+ key: string;
794
+ }>>(registry: T): Array<T[keyof T & string]["key"]>;
795
+
796
+ /**
797
+ * Display-state derivation for a {@link PermissionView} (pure, no React state involved).
798
+ * {@link PermissionView} から表示状態を導出するモジュール (React の状態は一切持たない純粋関数)。
799
+ */
680
800
 
681
801
  type PermState = "full" | "partial" | "none";
802
+ /**
803
+ * Display-oriented reading of a {@link PermissionView}: the same `can*` booleans (safe defaults when the
804
+ * view is absent) plus the ○△× tri-state used by the indicator components.
805
+ * {@link PermissionView} の表示向け読み取り結果。同名の `can*` 真偽値と ○△× の三値状態を併せ持つ形。
806
+ */
682
807
  type UsePermission = {
683
808
  canRead: boolean;
684
- canWrite: boolean;
809
+ canCreate: boolean;
810
+ canUpdate: boolean;
685
811
  canDelete: boolean;
812
+ /** create ∪ update */
813
+ canWrite: boolean;
686
814
  /** read: none(×) / partial(△, row|col restricted) / full(○). */
687
815
  readState: PermState;
688
816
  /** write = create ∪ update: full(○ both) / partial(△ one) / none(×). */
@@ -692,7 +820,10 @@ type UsePermission = {
692
820
  /**
693
821
  * Derive ○△× display states from a {@link PermissionView}. Pure (safe to call in render);
694
822
  * named `usePermission` for ergonomic call-sites.
823
+ * {@link PermissionView} から ○△× の表示状態を導出する純粋関数 (レンダー内から安全に呼べる形)。
824
+ *
825
+ * @returns The permission booleans plus their display states. 権限の真偽値と表示状態の組。
695
826
  */
696
827
  declare function usePermission(view: PermissionView | null | undefined): UsePermission;
697
828
 
698
- export { AuthzAdminAppView, type AuthzAdminAppViewProps, type AuthzAdminLabels, type AuthzConfig, AuthzErrorBoundary, type AuthzGrantsData, AuthzGrantsView, type AuthzGraphData, AuthzGraphView, type AuthzGroupRolesData, AuthzGroupRolesView, AuthzLayout, type AuthzLayoutData, type AuthzLayoutProps, type AuthzLayoutShellProps, type AuthzNodeType, type AuthzResourcesData, AuthzResourcesView, type AuthzRolesData, AuthzRolesView, type AuthzUserId, type AuthzUserRolesData, AuthzUserRolesView, type CreateAuthzAdminAppOptions, type CreateAuthzAdminServerOptions, ErrorAlert, Field, type MyPermissionGroupItem, MyPermissionGroupStatus, type MyPermissionGroupStatusProps, MyPermissionIndicator, type MyPermissionIndicatorProps, MyPermissionStatus, type MyPermissionStatusProps, type PartialAuthzAdminLabels, type PermState, type PermissionView, type RequirePermissionOptions, type ResourceDefinition, type ResourceDefinitionInput, type ResourceRegistry, type UsePermission, createAuthz, createAuthzAdminApp, createAuthzAdminServer, defaultAuthzAdminLabels, defineResources, flattenGroupItems, formatResourceTooltip, getPermissionSummary, makeAuthzErrorBoundary, resolveLabels, toPermissionView, ui, usePermission };
829
+ export { AuthzAdminAppView, type AuthzAdminAppViewProps, type AuthzAdminLabels, type AuthzConfig, AuthzErrorBoundary, type AuthzGrantsData, AuthzGrantsView, type AuthzGraphData, AuthzGraphView, type AuthzGroupRolesData, AuthzGroupRolesView, AuthzLayout, type AuthzLayoutData, type AuthzLayoutProps, type AuthzLayoutShellProps, type AuthzNodeType, type AuthzResourcesData, AuthzResourcesView, type AuthzRolesData, AuthzRolesView, AuthzUsageError, type AuthzUserId, type AuthzUserRolesData, AuthzUserRolesView, type CreateAuthzAdminAppOptions, type CreateAuthzAdminServerOptions, type EffectivePermissionsQuery, ErrorAlert, Field, type MyPermissionGroupItem, MyPermissionGroupStatus, type MyPermissionGroupStatusProps, MyPermissionIndicator, type MyPermissionIndicatorProps, MyPermissionStatus, type MyPermissionStatusProps, type PartialAuthzAdminLabels, type PermState, type PermissionView, type PermissionViewMap, type RequirePermissionOptions, type RequirePermissionResult, type ResourceDefinition, type ResourceDefinitionInput, type ResourceRegistry, type UsePermission, createAuthz, createAuthzAdminApp, createAuthzAdminServer, defaultAuthzAdminLabels, defineResources, flattenGroupItems, formatResourceTooltip, getPermissionSummary, makeAuthzErrorBoundary, resolveLabels, resourceKeysOf, toPermissionView, ui, usePermission };