@aiquants/auth-react-router 0.4.0 → 0.5.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/README.md +39 -1
- package/dist/admin.d.mts +268 -0
- package/dist/admin.d.ts +268 -0
- package/dist/admin.js +2 -0
- package/dist/admin.js.map +1 -0
- package/dist/admin.mjs +2 -0
- package/dist/admin.mjs.map +1 -0
- package/dist/client.d.mts +2 -2
- package/dist/client.d.ts +2 -2
- package/dist/server.d.mts +23 -4
- package/dist/server.d.ts +23 -4
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +1 -1
- package/dist/server.mjs.map +1 -1
- package/dist/styles/auth-react-router.standalone.css +1 -1
- package/package.json +10 -3
- package/src/admin/app.ts +4 -0
- package/src/admin/labels.ts +274 -0
- package/src/admin/server.spec.ts +300 -0
- package/src/admin/server.ts +345 -0
- package/src/admin/ui.tsx +71 -0
- package/src/admin/views.spec.tsx +307 -0
- package/src/admin/views.tsx +696 -0
- package/src/admin.ts +5 -0
- package/src/server/auth-server.ts +1 -0
- package/src/server/google-strategy-impl.spec.ts +8 -0
- package/src/server/google-strategy-impl.ts +7 -1
- package/src/server/google-strategy.spec.ts +56 -0
- package/src/server/google-strategy.ts +10 -1
- package/src/server/ports.ts +22 -4
- package/src/server/session.spec.ts +52 -0
- package/src/server/session.ts +7 -2
package/README.md
CHANGED
|
@@ -20,8 +20,9 @@ export const authServer = createAuthServer({
|
|
|
20
20
|
google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, redirectURI: env.GOOGLE_OAUTH_REDIRECT_URL },
|
|
21
21
|
session: { secrets: [env.REMIX_SESSION_SECRET] },
|
|
22
22
|
isEmailAllowed: emailDomainAllowlist(parseAllowlistCsv(env.ALLOWED_EMAILS), parseAllowlistCsv(env.ALLOWED_DOMAINS)),
|
|
23
|
+
isUserActive: async (profile) => isAccountEnabled(profile), // optional: deactivation revokes live sessions
|
|
23
24
|
backendAuth: { verify: verifyBackend, signup: (p, t) => signupBackend(p, t) }, // FastAPI verify/signup
|
|
24
|
-
getUserPhoto: async (openid) => (await getOpenids({ openid }))[0]?.picture ?? "", //
|
|
25
|
+
getUserPhoto: async (openid) => (await getOpenids({ openid }))[0]?.picture ?? "", // your identity store
|
|
25
26
|
warmup: async () => { await Promise.all([ensurePrimaryConnection(), ensureSecondaryConnection()]) },
|
|
26
27
|
mockUser: mockUserPort, // test backdoor (E2E) — omit in production-only apps
|
|
27
28
|
})
|
|
@@ -35,6 +36,38 @@ import { GoogleForm } from "@aiquants/auth-react-router/client"
|
|
|
35
36
|
<GoogleForm /> // <Form method="POST"> + _action="Sign In with Google"
|
|
36
37
|
```
|
|
37
38
|
|
|
39
|
+
## User administration surface (`/admin`)
|
|
40
|
+
|
|
41
|
+
A splat-mounted admin UI for users, groups, group members, and the sign-in allowlist — the identity-side counterpart to `@aiquants/authz-react-router`.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { createUserAdminApp, jaUserAdminLabels } from "@aiquants/auth-react-router/admin"
|
|
45
|
+
|
|
46
|
+
export const userAdminApp = createUserAdminApp({
|
|
47
|
+
store: myUserAdminStore, // you implement UserAdminStore against your DB
|
|
48
|
+
labels: jaUserAdminLabels, // optional; package default is English
|
|
49
|
+
guards: { // REQUIRED — see below
|
|
50
|
+
requireAccess: async (request, { action }) => {
|
|
51
|
+
await requireUser(request)
|
|
52
|
+
await requirePermission(request, { resourceKey: "user_admin", action })
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { AuthUserAdminAppView } from "@aiquants/auth-react-router/admin"
|
|
60
|
+
export const loader = userAdminApp.loader
|
|
61
|
+
export const action = userAdminApp.action
|
|
62
|
+
export default () => <AuthUserAdminAppView />
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- **`guards` is mandatory** — this surface lists every user and mutates group membership, so an unguarded mount is an account-enumeration and privilege-escalation path. Allow by returning, deny by throwing (`Response` / `redirect` / `Error`); the return value is `void` by contract, so a predicate-style guard that returns `false` cannot silently fail open.
|
|
66
|
+
- **Per-operation authorization**: the guard receives the CRUD verb each intent actually performs (`read` / `create` / `update` / `delete`), so a principal holding only `update` cannot delete. Membership add/remove map to `create`/`delete` because they add and remove rows.
|
|
67
|
+
- Unknown intents reach neither the guard nor the store (the intent table is a `Map`, so prototype keys such as `constructor` do not resolve).
|
|
68
|
+
- Store errors (e.g. "cannot remove the last administrator") are returned as `{ ok: false, error }` and rendered by the views; guard rejections propagate untouched.
|
|
69
|
+
- Labels default to **English** (`defaultUserAdminLabels`); inject `jaUserAdminLabels` or a partial override via `resolveUserAdminLabels`.
|
|
70
|
+
|
|
38
71
|
Styling: this package has **no hand-written component CSS** (the `GoogleForm` classes are plain Tailwind utilities), so it ships **no components-only artifact** — only a standalone build. Two consumption modes, never mixed:
|
|
39
72
|
|
|
40
73
|
- **Tailwind v4 host** — add `@source "../node_modules/@aiquants/auth-react-router/src/**/*.{ts,tsx}";` (monorepo: `../../../../packages/auth-react-router/src/**/*.{ts,tsx}`) so the `GoogleForm` classes are generated in the host's own canonical build; `src` ships in the published package.
|
|
@@ -61,6 +94,11 @@ Never mix the two: importing the standalone utility CSS next to a host Tailwind
|
|
|
61
94
|
| `mockUser` | `mock_user_id` cookie parse + name map | fixed id |
|
|
62
95
|
| `warmup` | 2 pools | 1 pool |
|
|
63
96
|
| `backendAuth` | primary-api | secondary-api |
|
|
97
|
+
| `isUserActive` | DB lookup + allowlist re-check | omitted (always active) |
|
|
98
|
+
|
|
99
|
+
`isUserActive` is evaluated at login **and on every session resolution**, so disabling an account revokes already-issued session cookies. Return `false` only for a *known-disabled* account — returning `false` for an unknown identity would block first-time sign-up.
|
|
100
|
+
|
|
101
|
+
> ⚠️ `isEmailAllowed` may return a `Promise` (to consult a database as well as env vars). Callers **must** `await` it: a `Promise` is always truthy, so a missing `await` makes the allowlist fail **open**, and the type checker cannot catch it.
|
|
64
102
|
|
|
65
103
|
## Intentional Changes vs Original (§8, approved)
|
|
66
104
|
|
package/dist/admin.d.mts
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { AuthUser, AuthGroup, AuthGroupMember, AuthAllowlistEntry } from '@aiquants/auth-core';
|
|
2
|
+
import { LoaderFunctionArgs, ActionFunctionArgs } from 'react-router';
|
|
3
|
+
import React__default from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Labels and i18n strings for the user administration UI.
|
|
7
|
+
* ユーザー管理 UI で使用するラベルと i18n 文字列の定義。
|
|
8
|
+
*
|
|
9
|
+
* パッケージ既定は **英語** ([defaultUserAdminLabels])。日本語で使う場合はアプリ側が
|
|
10
|
+
* [jaUserAdminLabels] を明示的に注入する (認可管理 `@aiquants/authz-react-router` と同じ規約)。
|
|
11
|
+
* UI 文字列はすべて本モジュールに集約し、コンポーネント側へ直書きしないこと — 直書きすると
|
|
12
|
+
* 日本語以外の利用者がその箇所を差し替えられなくなる。
|
|
13
|
+
*/
|
|
14
|
+
type UserAdminLabels = {
|
|
15
|
+
title: string;
|
|
16
|
+
/** シェル (タブ枠) の見出し。 */
|
|
17
|
+
heading: string;
|
|
18
|
+
tabs: {
|
|
19
|
+
users: string;
|
|
20
|
+
groups: string;
|
|
21
|
+
groupMembers: string;
|
|
22
|
+
allowlist: string;
|
|
23
|
+
};
|
|
24
|
+
usersView: {
|
|
25
|
+
title: string;
|
|
26
|
+
searchPlaceholder: string;
|
|
27
|
+
addUser: string;
|
|
28
|
+
editUser: string;
|
|
29
|
+
id: string;
|
|
30
|
+
displayName: string;
|
|
31
|
+
email: string;
|
|
32
|
+
status: string;
|
|
33
|
+
active: string;
|
|
34
|
+
inactive: string;
|
|
35
|
+
actions: string;
|
|
36
|
+
edit: string;
|
|
37
|
+
activate: string;
|
|
38
|
+
deactivate: string;
|
|
39
|
+
empty: string;
|
|
40
|
+
save: string;
|
|
41
|
+
cancel: string;
|
|
42
|
+
};
|
|
43
|
+
groupsView: {
|
|
44
|
+
title: string;
|
|
45
|
+
searchPlaceholder: string;
|
|
46
|
+
addGroup: string;
|
|
47
|
+
editGroup: string;
|
|
48
|
+
id: string;
|
|
49
|
+
groupKey: string;
|
|
50
|
+
name: string;
|
|
51
|
+
description: string;
|
|
52
|
+
memberCount: string;
|
|
53
|
+
status: string;
|
|
54
|
+
actions: string;
|
|
55
|
+
edit: string;
|
|
56
|
+
delete: string;
|
|
57
|
+
confirmDelete: string;
|
|
58
|
+
noDescription: string;
|
|
59
|
+
groupKeyPlaceholder: string;
|
|
60
|
+
namePlaceholder: string;
|
|
61
|
+
empty: string;
|
|
62
|
+
save: string;
|
|
63
|
+
cancel: string;
|
|
64
|
+
};
|
|
65
|
+
groupMembersView: {
|
|
66
|
+
selectGroup: string;
|
|
67
|
+
selectPrompt: string;
|
|
68
|
+
actionAdd: string;
|
|
69
|
+
actionRemove: string;
|
|
70
|
+
};
|
|
71
|
+
allowlistView: {
|
|
72
|
+
title: string;
|
|
73
|
+
addEntry: string;
|
|
74
|
+
pattern: string;
|
|
75
|
+
type: string;
|
|
76
|
+
emailType: string;
|
|
77
|
+
domainType: string;
|
|
78
|
+
/** 一覧のバッジ表示 (短縮形)。 */
|
|
79
|
+
emailTypeShort: string;
|
|
80
|
+
domainTypeShort: string;
|
|
81
|
+
description: string;
|
|
82
|
+
actions: string;
|
|
83
|
+
/** 変更不能な供給元 (環境変数など) 由来の行に出す表示。 */
|
|
84
|
+
readOnly: string;
|
|
85
|
+
delete: string;
|
|
86
|
+
empty: string;
|
|
87
|
+
save: string;
|
|
88
|
+
cancel: string;
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Package default labels (English).
|
|
93
|
+
* パッケージ既定ラベル (英語)。
|
|
94
|
+
*/
|
|
95
|
+
declare const defaultUserAdminLabels: UserAdminLabels;
|
|
96
|
+
/**
|
|
97
|
+
* Standard Japanese labels for user administration (opt-in).
|
|
98
|
+
* ユーザー管理の標準日本語ラベル (アプリ側で明示注入して使う)。
|
|
99
|
+
*/
|
|
100
|
+
declare const jaUserAdminLabels: UserAdminLabels;
|
|
101
|
+
/** セクション単位の部分上書き。 */
|
|
102
|
+
type PartialUserAdminLabels = {
|
|
103
|
+
title?: string;
|
|
104
|
+
heading?: string;
|
|
105
|
+
tabs?: Partial<UserAdminLabels["tabs"]>;
|
|
106
|
+
usersView?: Partial<UserAdminLabels["usersView"]>;
|
|
107
|
+
groupsView?: Partial<UserAdminLabels["groupsView"]>;
|
|
108
|
+
groupMembersView?: Partial<UserAdminLabels["groupMembersView"]>;
|
|
109
|
+
allowlistView?: Partial<UserAdminLabels["allowlistView"]>;
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Shallow per-section merge over the English defaults.
|
|
113
|
+
* 英語既定に対してセクション単位で浅くマージする処理。
|
|
114
|
+
*/
|
|
115
|
+
declare function resolveUserAdminLabels(over?: PartialUserAdminLabels): UserAdminLabels;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Server store interface for managing users, groups, memberships, and allowlists.
|
|
119
|
+
* ユーザー・グループ・所属・アロワリストを管理するサーバー層ストアのインターフェース。
|
|
120
|
+
*/
|
|
121
|
+
type UserAdminStore = {
|
|
122
|
+
listUsers: () => Promise<AuthUser[]>;
|
|
123
|
+
createUser: (data: {
|
|
124
|
+
displayName: string;
|
|
125
|
+
email: string;
|
|
126
|
+
}) => Promise<AuthUser>;
|
|
127
|
+
updateUser: (id: number, data: {
|
|
128
|
+
displayName: string;
|
|
129
|
+
email: string;
|
|
130
|
+
}) => Promise<AuthUser>;
|
|
131
|
+
toggleUserActive: (id: number, isActive: boolean) => Promise<AuthUser>;
|
|
132
|
+
listGroups: () => Promise<AuthGroup[]>;
|
|
133
|
+
createGroup: (data: {
|
|
134
|
+
groupKey: string;
|
|
135
|
+
name: string;
|
|
136
|
+
description?: string;
|
|
137
|
+
}) => Promise<AuthGroup>;
|
|
138
|
+
updateGroup: (id: number, data: {
|
|
139
|
+
name: string;
|
|
140
|
+
description?: string;
|
|
141
|
+
}) => Promise<AuthGroup>;
|
|
142
|
+
deleteGroup: (id: number) => Promise<void>;
|
|
143
|
+
listGroupMembers: () => Promise<AuthGroupMember[]>;
|
|
144
|
+
addGroupMember: (groupId: number, userId: number) => Promise<AuthGroupMember>;
|
|
145
|
+
removeGroupMember: (groupId: number, userId: number) => Promise<void>;
|
|
146
|
+
listAllowlist: () => Promise<AuthAllowlistEntry[]>;
|
|
147
|
+
addAllowlistEntry: (data: {
|
|
148
|
+
pattern: string;
|
|
149
|
+
type: "email" | "domain";
|
|
150
|
+
description?: string;
|
|
151
|
+
}) => Promise<AuthAllowlistEntry>;
|
|
152
|
+
removeAllowlistEntry: (id: number) => Promise<void>;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Creates an in-memory UserAdminStore initialized with optional seed data.
|
|
156
|
+
* シードデータで初期化されるメモリ上の UserAdminStore を作成する。
|
|
157
|
+
*/
|
|
158
|
+
declare function createInMemoryUserAdminStore(initial?: {
|
|
159
|
+
users?: AuthUser[];
|
|
160
|
+
groups?: AuthGroup[];
|
|
161
|
+
groupMembers?: AuthGroupMember[];
|
|
162
|
+
allowlist?: AuthAllowlistEntry[];
|
|
163
|
+
}): UserAdminStore;
|
|
164
|
+
/**
|
|
165
|
+
* The CRUD verb an operation performs. Deliberately a plain string union so this package stays
|
|
166
|
+
* independent of any particular authorization library.
|
|
167
|
+
* 操作が行う CRUD 種別。特定の認可ライブラリに依存しないよう素の文字列 union で表現する。
|
|
168
|
+
*/
|
|
169
|
+
type UserAdminAccess = "read" | "create" | "update" | "delete";
|
|
170
|
+
/**
|
|
171
|
+
* Access guard the user-admin surface is mounted behind. Deny by throwing
|
|
172
|
+
* (a `Response`/`redirect` or an `Error`); returning normally means "allow".
|
|
173
|
+
*
|
|
174
|
+
* ユーザー管理面をマウントする際の必須アクセスガード。拒否は throw で表現する
|
|
175
|
+
* (`Response` / `redirect` / `Error`)。正常 return は「許可」を意味する。
|
|
176
|
+
*
|
|
177
|
+
* 操作ごとの CRUD 種別を受け取るため、呼び出し側は「削除だけ別権限」といった細分化ができる。
|
|
178
|
+
* `intent` は監査ログ用の補助情報(認可判断は `action` で行うこと)。
|
|
179
|
+
*/
|
|
180
|
+
type UserAdminGuards = {
|
|
181
|
+
/**
|
|
182
|
+
* 許可は「正常 return」、拒否は「throw」で表す。返り値は判定に使わない (`void` 契約)。
|
|
183
|
+
* 述語のつもりで `false` を返す実装を書くと素通りするため、返り値型で明示的に禁じる。
|
|
184
|
+
*/
|
|
185
|
+
requireAccess: (request: Request, context: {
|
|
186
|
+
action: UserAdminAccess;
|
|
187
|
+
intent: string;
|
|
188
|
+
}) => Promise<void> | void;
|
|
189
|
+
};
|
|
190
|
+
type UserAdminAppConfig = {
|
|
191
|
+
store: UserAdminStore;
|
|
192
|
+
/** セクション単位の部分上書き。既定は英語 (`defaultUserAdminLabels`)。 */
|
|
193
|
+
labels?: PartialUserAdminLabels;
|
|
194
|
+
/**
|
|
195
|
+
* Required — omitting a guard would expose the whole user directory and its write actions.
|
|
196
|
+
* 必須。省略を許すとユーザー名簿と全更新操作が無防備に露出するため、型で強制する。
|
|
197
|
+
*/
|
|
198
|
+
guards: UserAdminGuards;
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Creates React Router loader & action handler for user administration.
|
|
202
|
+
* ユーザー管理用 React Router の loader および action ハンドラーを作成する。
|
|
203
|
+
*
|
|
204
|
+
* `config.guards` は必須。loader / action の双方が、処理を始める前にガードを通過させる。
|
|
205
|
+
*/
|
|
206
|
+
declare function createUserAdminApp(config: UserAdminAppConfig): {
|
|
207
|
+
loader: ({ request }: LoaderFunctionArgs) => Promise<{
|
|
208
|
+
segment: string;
|
|
209
|
+
users: AuthUser[];
|
|
210
|
+
groups: AuthGroup[];
|
|
211
|
+
groupMembers: AuthGroupMember[];
|
|
212
|
+
allowlist: AuthAllowlistEntry[];
|
|
213
|
+
labels: UserAdminLabels;
|
|
214
|
+
}>;
|
|
215
|
+
action: ({ request }: ActionFunctionArgs) => Promise<{
|
|
216
|
+
ok: boolean;
|
|
217
|
+
error?: undefined;
|
|
218
|
+
} | {
|
|
219
|
+
ok: boolean;
|
|
220
|
+
error: string;
|
|
221
|
+
}>;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
type UserAdminShellProps = {
|
|
225
|
+
children?: React__default.ReactNode;
|
|
226
|
+
renderHeader?: (props: {
|
|
227
|
+
title: string;
|
|
228
|
+
annotation: React__default.ReactNode;
|
|
229
|
+
}) => React__default.ReactNode;
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Shell layout for user administration pages with header annotation delegation.
|
|
233
|
+
* ヘッダー注釈委譲を備えたユーザー管理ページのシェルレイアウト。
|
|
234
|
+
*/
|
|
235
|
+
declare function UserAdminShell({ children, renderHeader }: UserAdminShellProps): React__default.JSX.Element;
|
|
236
|
+
|
|
237
|
+
type UserAdminLoaderData = {
|
|
238
|
+
segment: string;
|
|
239
|
+
users: AuthUser[];
|
|
240
|
+
groups: AuthGroup[];
|
|
241
|
+
groupMembers: AuthGroupMember[];
|
|
242
|
+
allowlist: AuthAllowlistEntry[];
|
|
243
|
+
labels?: UserAdminLabels;
|
|
244
|
+
};
|
|
245
|
+
declare function UsersView(): React__default.JSX.Element;
|
|
246
|
+
/**
|
|
247
|
+
* View for managing user groups (create, edit, delete).
|
|
248
|
+
* ユーザーグループ管理ビュー (作成・編集・削除)。
|
|
249
|
+
*/
|
|
250
|
+
declare function GroupsView(): React__default.JSX.Element;
|
|
251
|
+
/**
|
|
252
|
+
* View for managing group member assignments.
|
|
253
|
+
* グループメンバー割り当て管理ビュー。
|
|
254
|
+
*/
|
|
255
|
+
declare function GroupMembersView(): React__default.JSX.Element;
|
|
256
|
+
/**
|
|
257
|
+
* View for managing authentication allowlist entries.
|
|
258
|
+
* アクセス許可リスト (Allowlist) 管理ビュー。
|
|
259
|
+
*/
|
|
260
|
+
declare function AllowlistView(): React__default.JSX.Element;
|
|
261
|
+
type AuthUserAdminAppViewProps = UserAdminShellProps;
|
|
262
|
+
/**
|
|
263
|
+
* Top-level application view component for the user administration UI (`/users/*`).
|
|
264
|
+
* ユーザー管理 UI 全体を描画するトップレベルコンポーネント。
|
|
265
|
+
*/
|
|
266
|
+
declare function AuthUserAdminAppView({ renderHeader }?: AuthUserAdminAppViewProps): React__default.JSX.Element;
|
|
267
|
+
|
|
268
|
+
export { AllowlistView, AuthUserAdminAppView, type AuthUserAdminAppViewProps, GroupMembersView, GroupsView, type PartialUserAdminLabels, type UserAdminAccess, type UserAdminAppConfig, type UserAdminGuards, type UserAdminLabels, type UserAdminLoaderData, UserAdminShell, type UserAdminShellProps, type UserAdminStore, UsersView, createInMemoryUserAdminStore, createUserAdminApp, defaultUserAdminLabels, jaUserAdminLabels, resolveUserAdminLabels };
|
package/dist/admin.d.ts
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { AuthUser, AuthGroup, AuthGroupMember, AuthAllowlistEntry } from '@aiquants/auth-core';
|
|
2
|
+
import { LoaderFunctionArgs, ActionFunctionArgs } from 'react-router';
|
|
3
|
+
import React__default from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Labels and i18n strings for the user administration UI.
|
|
7
|
+
* ユーザー管理 UI で使用するラベルと i18n 文字列の定義。
|
|
8
|
+
*
|
|
9
|
+
* パッケージ既定は **英語** ([defaultUserAdminLabels])。日本語で使う場合はアプリ側が
|
|
10
|
+
* [jaUserAdminLabels] を明示的に注入する (認可管理 `@aiquants/authz-react-router` と同じ規約)。
|
|
11
|
+
* UI 文字列はすべて本モジュールに集約し、コンポーネント側へ直書きしないこと — 直書きすると
|
|
12
|
+
* 日本語以外の利用者がその箇所を差し替えられなくなる。
|
|
13
|
+
*/
|
|
14
|
+
type UserAdminLabels = {
|
|
15
|
+
title: string;
|
|
16
|
+
/** シェル (タブ枠) の見出し。 */
|
|
17
|
+
heading: string;
|
|
18
|
+
tabs: {
|
|
19
|
+
users: string;
|
|
20
|
+
groups: string;
|
|
21
|
+
groupMembers: string;
|
|
22
|
+
allowlist: string;
|
|
23
|
+
};
|
|
24
|
+
usersView: {
|
|
25
|
+
title: string;
|
|
26
|
+
searchPlaceholder: string;
|
|
27
|
+
addUser: string;
|
|
28
|
+
editUser: string;
|
|
29
|
+
id: string;
|
|
30
|
+
displayName: string;
|
|
31
|
+
email: string;
|
|
32
|
+
status: string;
|
|
33
|
+
active: string;
|
|
34
|
+
inactive: string;
|
|
35
|
+
actions: string;
|
|
36
|
+
edit: string;
|
|
37
|
+
activate: string;
|
|
38
|
+
deactivate: string;
|
|
39
|
+
empty: string;
|
|
40
|
+
save: string;
|
|
41
|
+
cancel: string;
|
|
42
|
+
};
|
|
43
|
+
groupsView: {
|
|
44
|
+
title: string;
|
|
45
|
+
searchPlaceholder: string;
|
|
46
|
+
addGroup: string;
|
|
47
|
+
editGroup: string;
|
|
48
|
+
id: string;
|
|
49
|
+
groupKey: string;
|
|
50
|
+
name: string;
|
|
51
|
+
description: string;
|
|
52
|
+
memberCount: string;
|
|
53
|
+
status: string;
|
|
54
|
+
actions: string;
|
|
55
|
+
edit: string;
|
|
56
|
+
delete: string;
|
|
57
|
+
confirmDelete: string;
|
|
58
|
+
noDescription: string;
|
|
59
|
+
groupKeyPlaceholder: string;
|
|
60
|
+
namePlaceholder: string;
|
|
61
|
+
empty: string;
|
|
62
|
+
save: string;
|
|
63
|
+
cancel: string;
|
|
64
|
+
};
|
|
65
|
+
groupMembersView: {
|
|
66
|
+
selectGroup: string;
|
|
67
|
+
selectPrompt: string;
|
|
68
|
+
actionAdd: string;
|
|
69
|
+
actionRemove: string;
|
|
70
|
+
};
|
|
71
|
+
allowlistView: {
|
|
72
|
+
title: string;
|
|
73
|
+
addEntry: string;
|
|
74
|
+
pattern: string;
|
|
75
|
+
type: string;
|
|
76
|
+
emailType: string;
|
|
77
|
+
domainType: string;
|
|
78
|
+
/** 一覧のバッジ表示 (短縮形)。 */
|
|
79
|
+
emailTypeShort: string;
|
|
80
|
+
domainTypeShort: string;
|
|
81
|
+
description: string;
|
|
82
|
+
actions: string;
|
|
83
|
+
/** 変更不能な供給元 (環境変数など) 由来の行に出す表示。 */
|
|
84
|
+
readOnly: string;
|
|
85
|
+
delete: string;
|
|
86
|
+
empty: string;
|
|
87
|
+
save: string;
|
|
88
|
+
cancel: string;
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Package default labels (English).
|
|
93
|
+
* パッケージ既定ラベル (英語)。
|
|
94
|
+
*/
|
|
95
|
+
declare const defaultUserAdminLabels: UserAdminLabels;
|
|
96
|
+
/**
|
|
97
|
+
* Standard Japanese labels for user administration (opt-in).
|
|
98
|
+
* ユーザー管理の標準日本語ラベル (アプリ側で明示注入して使う)。
|
|
99
|
+
*/
|
|
100
|
+
declare const jaUserAdminLabels: UserAdminLabels;
|
|
101
|
+
/** セクション単位の部分上書き。 */
|
|
102
|
+
type PartialUserAdminLabels = {
|
|
103
|
+
title?: string;
|
|
104
|
+
heading?: string;
|
|
105
|
+
tabs?: Partial<UserAdminLabels["tabs"]>;
|
|
106
|
+
usersView?: Partial<UserAdminLabels["usersView"]>;
|
|
107
|
+
groupsView?: Partial<UserAdminLabels["groupsView"]>;
|
|
108
|
+
groupMembersView?: Partial<UserAdminLabels["groupMembersView"]>;
|
|
109
|
+
allowlistView?: Partial<UserAdminLabels["allowlistView"]>;
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Shallow per-section merge over the English defaults.
|
|
113
|
+
* 英語既定に対してセクション単位で浅くマージする処理。
|
|
114
|
+
*/
|
|
115
|
+
declare function resolveUserAdminLabels(over?: PartialUserAdminLabels): UserAdminLabels;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Server store interface for managing users, groups, memberships, and allowlists.
|
|
119
|
+
* ユーザー・グループ・所属・アロワリストを管理するサーバー層ストアのインターフェース。
|
|
120
|
+
*/
|
|
121
|
+
type UserAdminStore = {
|
|
122
|
+
listUsers: () => Promise<AuthUser[]>;
|
|
123
|
+
createUser: (data: {
|
|
124
|
+
displayName: string;
|
|
125
|
+
email: string;
|
|
126
|
+
}) => Promise<AuthUser>;
|
|
127
|
+
updateUser: (id: number, data: {
|
|
128
|
+
displayName: string;
|
|
129
|
+
email: string;
|
|
130
|
+
}) => Promise<AuthUser>;
|
|
131
|
+
toggleUserActive: (id: number, isActive: boolean) => Promise<AuthUser>;
|
|
132
|
+
listGroups: () => Promise<AuthGroup[]>;
|
|
133
|
+
createGroup: (data: {
|
|
134
|
+
groupKey: string;
|
|
135
|
+
name: string;
|
|
136
|
+
description?: string;
|
|
137
|
+
}) => Promise<AuthGroup>;
|
|
138
|
+
updateGroup: (id: number, data: {
|
|
139
|
+
name: string;
|
|
140
|
+
description?: string;
|
|
141
|
+
}) => Promise<AuthGroup>;
|
|
142
|
+
deleteGroup: (id: number) => Promise<void>;
|
|
143
|
+
listGroupMembers: () => Promise<AuthGroupMember[]>;
|
|
144
|
+
addGroupMember: (groupId: number, userId: number) => Promise<AuthGroupMember>;
|
|
145
|
+
removeGroupMember: (groupId: number, userId: number) => Promise<void>;
|
|
146
|
+
listAllowlist: () => Promise<AuthAllowlistEntry[]>;
|
|
147
|
+
addAllowlistEntry: (data: {
|
|
148
|
+
pattern: string;
|
|
149
|
+
type: "email" | "domain";
|
|
150
|
+
description?: string;
|
|
151
|
+
}) => Promise<AuthAllowlistEntry>;
|
|
152
|
+
removeAllowlistEntry: (id: number) => Promise<void>;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Creates an in-memory UserAdminStore initialized with optional seed data.
|
|
156
|
+
* シードデータで初期化されるメモリ上の UserAdminStore を作成する。
|
|
157
|
+
*/
|
|
158
|
+
declare function createInMemoryUserAdminStore(initial?: {
|
|
159
|
+
users?: AuthUser[];
|
|
160
|
+
groups?: AuthGroup[];
|
|
161
|
+
groupMembers?: AuthGroupMember[];
|
|
162
|
+
allowlist?: AuthAllowlistEntry[];
|
|
163
|
+
}): UserAdminStore;
|
|
164
|
+
/**
|
|
165
|
+
* The CRUD verb an operation performs. Deliberately a plain string union so this package stays
|
|
166
|
+
* independent of any particular authorization library.
|
|
167
|
+
* 操作が行う CRUD 種別。特定の認可ライブラリに依存しないよう素の文字列 union で表現する。
|
|
168
|
+
*/
|
|
169
|
+
type UserAdminAccess = "read" | "create" | "update" | "delete";
|
|
170
|
+
/**
|
|
171
|
+
* Access guard the user-admin surface is mounted behind. Deny by throwing
|
|
172
|
+
* (a `Response`/`redirect` or an `Error`); returning normally means "allow".
|
|
173
|
+
*
|
|
174
|
+
* ユーザー管理面をマウントする際の必須アクセスガード。拒否は throw で表現する
|
|
175
|
+
* (`Response` / `redirect` / `Error`)。正常 return は「許可」を意味する。
|
|
176
|
+
*
|
|
177
|
+
* 操作ごとの CRUD 種別を受け取るため、呼び出し側は「削除だけ別権限」といった細分化ができる。
|
|
178
|
+
* `intent` は監査ログ用の補助情報(認可判断は `action` で行うこと)。
|
|
179
|
+
*/
|
|
180
|
+
type UserAdminGuards = {
|
|
181
|
+
/**
|
|
182
|
+
* 許可は「正常 return」、拒否は「throw」で表す。返り値は判定に使わない (`void` 契約)。
|
|
183
|
+
* 述語のつもりで `false` を返す実装を書くと素通りするため、返り値型で明示的に禁じる。
|
|
184
|
+
*/
|
|
185
|
+
requireAccess: (request: Request, context: {
|
|
186
|
+
action: UserAdminAccess;
|
|
187
|
+
intent: string;
|
|
188
|
+
}) => Promise<void> | void;
|
|
189
|
+
};
|
|
190
|
+
type UserAdminAppConfig = {
|
|
191
|
+
store: UserAdminStore;
|
|
192
|
+
/** セクション単位の部分上書き。既定は英語 (`defaultUserAdminLabels`)。 */
|
|
193
|
+
labels?: PartialUserAdminLabels;
|
|
194
|
+
/**
|
|
195
|
+
* Required — omitting a guard would expose the whole user directory and its write actions.
|
|
196
|
+
* 必須。省略を許すとユーザー名簿と全更新操作が無防備に露出するため、型で強制する。
|
|
197
|
+
*/
|
|
198
|
+
guards: UserAdminGuards;
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Creates React Router loader & action handler for user administration.
|
|
202
|
+
* ユーザー管理用 React Router の loader および action ハンドラーを作成する。
|
|
203
|
+
*
|
|
204
|
+
* `config.guards` は必須。loader / action の双方が、処理を始める前にガードを通過させる。
|
|
205
|
+
*/
|
|
206
|
+
declare function createUserAdminApp(config: UserAdminAppConfig): {
|
|
207
|
+
loader: ({ request }: LoaderFunctionArgs) => Promise<{
|
|
208
|
+
segment: string;
|
|
209
|
+
users: AuthUser[];
|
|
210
|
+
groups: AuthGroup[];
|
|
211
|
+
groupMembers: AuthGroupMember[];
|
|
212
|
+
allowlist: AuthAllowlistEntry[];
|
|
213
|
+
labels: UserAdminLabels;
|
|
214
|
+
}>;
|
|
215
|
+
action: ({ request }: ActionFunctionArgs) => Promise<{
|
|
216
|
+
ok: boolean;
|
|
217
|
+
error?: undefined;
|
|
218
|
+
} | {
|
|
219
|
+
ok: boolean;
|
|
220
|
+
error: string;
|
|
221
|
+
}>;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
type UserAdminShellProps = {
|
|
225
|
+
children?: React__default.ReactNode;
|
|
226
|
+
renderHeader?: (props: {
|
|
227
|
+
title: string;
|
|
228
|
+
annotation: React__default.ReactNode;
|
|
229
|
+
}) => React__default.ReactNode;
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Shell layout for user administration pages with header annotation delegation.
|
|
233
|
+
* ヘッダー注釈委譲を備えたユーザー管理ページのシェルレイアウト。
|
|
234
|
+
*/
|
|
235
|
+
declare function UserAdminShell({ children, renderHeader }: UserAdminShellProps): React__default.JSX.Element;
|
|
236
|
+
|
|
237
|
+
type UserAdminLoaderData = {
|
|
238
|
+
segment: string;
|
|
239
|
+
users: AuthUser[];
|
|
240
|
+
groups: AuthGroup[];
|
|
241
|
+
groupMembers: AuthGroupMember[];
|
|
242
|
+
allowlist: AuthAllowlistEntry[];
|
|
243
|
+
labels?: UserAdminLabels;
|
|
244
|
+
};
|
|
245
|
+
declare function UsersView(): React__default.JSX.Element;
|
|
246
|
+
/**
|
|
247
|
+
* View for managing user groups (create, edit, delete).
|
|
248
|
+
* ユーザーグループ管理ビュー (作成・編集・削除)。
|
|
249
|
+
*/
|
|
250
|
+
declare function GroupsView(): React__default.JSX.Element;
|
|
251
|
+
/**
|
|
252
|
+
* View for managing group member assignments.
|
|
253
|
+
* グループメンバー割り当て管理ビュー。
|
|
254
|
+
*/
|
|
255
|
+
declare function GroupMembersView(): React__default.JSX.Element;
|
|
256
|
+
/**
|
|
257
|
+
* View for managing authentication allowlist entries.
|
|
258
|
+
* アクセス許可リスト (Allowlist) 管理ビュー。
|
|
259
|
+
*/
|
|
260
|
+
declare function AllowlistView(): React__default.JSX.Element;
|
|
261
|
+
type AuthUserAdminAppViewProps = UserAdminShellProps;
|
|
262
|
+
/**
|
|
263
|
+
* Top-level application view component for the user administration UI (`/users/*`).
|
|
264
|
+
* ユーザー管理 UI 全体を描画するトップレベルコンポーネント。
|
|
265
|
+
*/
|
|
266
|
+
declare function AuthUserAdminAppView({ renderHeader }?: AuthUserAdminAppViewProps): React__default.JSX.Element;
|
|
267
|
+
|
|
268
|
+
export { AllowlistView, AuthUserAdminAppView, type AuthUserAdminAppViewProps, GroupMembersView, GroupsView, type PartialUserAdminLabels, type UserAdminAccess, type UserAdminAppConfig, type UserAdminGuards, type UserAdminLabels, type UserAdminLoaderData, UserAdminShell, type UserAdminShellProps, type UserAdminStore, UsersView, createInMemoryUserAdminStore, createUserAdminApp, defaultUserAdminLabels, jaUserAdminLabels, resolveUserAdminLabels };
|