@aiquants/auth-react-router 0.15.1 → 0.16.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 +83 -6
- package/dist/admin.d.mts +10 -5
- package/dist/admin.d.ts +10 -5
- package/dist/admin.js +1 -1
- package/dist/admin.mjs +1 -1
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -81,15 +81,86 @@ export const userAdminApp = createUserAdminApp({
|
|
|
81
81
|
import { AuthUserAdminAppView } from "@aiquants/auth-react-router/admin"
|
|
82
82
|
export const loader = userAdminApp.loader
|
|
83
83
|
export const action = userAdminApp.action
|
|
84
|
-
|
|
84
|
+
// mounted as the splat route "/users/*"
|
|
85
|
+
export default () => <AuthUserAdminAppView basePath="/users" />
|
|
85
86
|
```
|
|
86
87
|
|
|
88
|
+
- **`basePath` is required** (`AuthUserAdminAppView` / `UserAdminShell`): the absolute path the console is mounted at,
|
|
89
|
+
without a trailing slash (`"/users"` for a `/users/*` route). The five tabs and the per-row "members" links of the
|
|
90
|
+
groups tab are built from it. There is no default: the host decides where the console lives, and a built-in default
|
|
91
|
+
would keep drawing links to that default after the mount moves — the routes still resolve and the build still
|
|
92
|
+
passes, only the links point at a place that is not served.
|
|
93
|
+
|
|
87
94
|
- **`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.
|
|
88
95
|
- **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.
|
|
89
96
|
- Unknown intents reach neither the guard nor the store (the intent table is a `Map`, so prototype keys such as `constructor` do not resolve).
|
|
90
97
|
- Store errors (e.g. "cannot remove the last administrator") are returned as `{ ok: false, error }` and rendered by the views; guard rejections propagate untouched.
|
|
91
98
|
- Labels default to **English** (`defaultUserAdminLabels`); inject `jaUserAdminLabels` or a partial override via `resolveUserAdminLabels`.
|
|
92
99
|
|
|
100
|
+
### Localization (`labels.locale` vs `labels.formatLocale`)
|
|
101
|
+
|
|
102
|
+
Every string this package draws lives in `UserAdminLabels`, and a host picks the language by injecting a whole catalog
|
|
103
|
+
(`defaultUserAdminLabels` for English, the package default, or `jaUserAdminLabels`) or a partial override. Two keys
|
|
104
|
+
carry language, and they are **different axes**:
|
|
105
|
+
|
|
106
|
+
| Key | Type | `defaultUserAdminLabels` | `jaUserAdminLabels` | Drives |
|
|
107
|
+
| --- | --- | --- | --- | --- |
|
|
108
|
+
| `locale` | `UserAdminLocale` (`"en"` \| `"ja"`) | `"en"` | `"ja"` | UI chrome language of both upstream-group pickers (`SelectBox` `locale`) |
|
|
109
|
+
| `formatLocale` | BCP 47 `string` | `"en-US"` | `"ja-JP"` | `Intl.DateTimeFormat` (with `timeZone`) and the user-list `Intl.Collator` |
|
|
110
|
+
|
|
111
|
+
- **`locale`** is forwarded to both `@aiquants/select-box` pickers (the create-group dialog and the directory link
|
|
112
|
+
form). The picker strings this package owns (`directoryView.pickerNoOptions` / `pickerClear` / `pickerToggle` /
|
|
113
|
+
`pickerSelected` / `pickerAvailable`) are passed as the picker's `labels`, the placeholder is the per-instance
|
|
114
|
+
`placeholder` prop, and every other key comes from the select-box catalog of `locale` (the values below are those of
|
|
115
|
+
`defaultUserAdminLabels` / `jaUserAdminLabels` and of select-box 0.10.0):
|
|
116
|
+
|
|
117
|
+
| select-box key | Source | `"en"` | `"ja"` |
|
|
118
|
+
| --- | --- | --- | --- |
|
|
119
|
+
| `noOptions` | `directoryView.pickerNoOptions` | No matching group | 一致するグループがありません |
|
|
120
|
+
| `clear` | `directoryView.pickerClear` | Clear the selection | 選択を解除 |
|
|
121
|
+
| `toggle` | `directoryView.pickerToggle` | Show the group list | グループ一覧を開く |
|
|
122
|
+
| `selection` | `directoryView.pickerSelected` (`{value}` = the picked option's label) | Selected: {value} | 選択中: {value} |
|
|
123
|
+
| `status` | `directoryView.pickerAvailable` (`{count}` = options shown) | {count} groups available | 候補 {count} 件 |
|
|
124
|
+
| `placeholder` | `placeholder` prop: `groupsView.pickUpstreamPlaceholder` (dialog) / `directoryView.pickUpstreamPlaceholder` (link form) | Search by name or address... | 名前かアドレスで検索... |
|
|
125
|
+
| `scrollUp` | select-box catalog | Scroll up | 上へスクロール |
|
|
126
|
+
| `scrollDown` | select-box catalog | Scroll down | 下へスクロール |
|
|
127
|
+
| `scrollLeft` | select-box catalog | Scroll left | 左へスクロール |
|
|
128
|
+
| `scrollRight` | select-box catalog | Scroll right | 右へスクロール |
|
|
129
|
+
| `scrollToTop` | select-box catalog | Top | 先頭へ |
|
|
130
|
+
| `scrollToBottom` | select-box catalog | Bottom | 末尾へ |
|
|
131
|
+
| `noItems` | select-box catalog | No items | 項目がありません |
|
|
132
|
+
| `removeTag` | select-box catalog (multi-select chips; both pickers are single-select) | Remove {label} | 「{label}」を削除 |
|
|
133
|
+
| `resizeHandle` | select-box catalog (tooltip of the option list's resize handle) | Resize handle | サイズ変更ハンドル |
|
|
134
|
+
|
|
135
|
+
To change a catalog-sourced string, there is no per-key override here: pick the `locale` whose catalog you want.
|
|
136
|
+
|
|
137
|
+
- `resolveUserAdminLabels` (run once when `createUserAdminApp` is built) **validates `locale`**: an omitted value keeps
|
|
138
|
+
the English default `"en"`; `"en"` / `"ja"` pass; anything else (`"ja-JP"`, `"EN"`, `""`, `null`, ...) throws
|
|
139
|
+
`RangeError` naming `labels.formatLocale`, so a mistake stops the app at startup instead of crashing the picker on
|
|
140
|
+
first render. There is no language negotiation — map `navigator.language` or a user setting to `"en"` / `"ja"`
|
|
141
|
+
yourself.
|
|
142
|
+
- **`formatLocale` is not validated**: an unreadable tag degrades (dates fall back to the raw ISO string, sorting to the
|
|
143
|
+
runtime collator) instead of throwing, because formatting must never take the screen down.
|
|
144
|
+
|
|
145
|
+
#### Migrating from 0.15.x (breaking changes in 0.16.0)
|
|
146
|
+
|
|
147
|
+
1. **`basePath` is now required** on `AuthUserAdminAppView` / `UserAdminShell` (see above). Pass the absolute mount
|
|
148
|
+
path, without a trailing slash: `<AuthUserAdminAppView basePath="/users" />`. Omitting it fails type-checking
|
|
149
|
+
(TS2741); an untyped caller would draw links such as `undefined/groups`.
|
|
150
|
+
2. **`labels.locale` changed meaning**: the old `labels.locale` (a BCP 47 tag for dates and sorting) is now
|
|
151
|
+
`labels.formatLocale` — no alias. The new `labels.locale` (type `UserAdminLocale` = `"en"` | `"ja"`) is the UI
|
|
152
|
+
language of the pickers, validated at startup.
|
|
153
|
+
- Hosts that inject `jaUserAdminLabels` whole, or spread it (`{ ...jaUserAdminLabels, heading: "" }`), need no
|
|
154
|
+
change: it carries `locale: "ja"` and `formatLocale: "ja-JP"`.
|
|
155
|
+
- A host that overrode `locale: "ja-JP"` must write `formatLocale: "ja-JP"`, and add `locale: "ja"` if it relies
|
|
156
|
+
on Japanese picker chrome (without it the pickers' catalog-sourced strings, such as the scroll-arrow names, are
|
|
157
|
+
English).
|
|
158
|
+
- A host that builds a full `UserAdminLabels` literal must add both keys.
|
|
159
|
+
3. **`@aiquants/select-box` `texts` is gone**: the pickers take select-box 0.10.0 `locale` / `labels`
|
|
160
|
+
(`SelectBoxLabelOverrides`) instead of `texts` / `SelectBoxTexts`. This is internal to the views — hosts that only
|
|
161
|
+
render `AuthUserAdminAppView` do nothing — but a host must install `@aiquants/select-box` >= 0.10.0 and
|
|
162
|
+
`@aiquants/virtualscroll` >= 3.7.0 (the new peer floors).
|
|
163
|
+
|
|
93
164
|
### Upstream group catalog (optional port)
|
|
94
165
|
|
|
95
166
|
The groups and directory tabs let the operator **pick** an upstream group instead of spelling its address. Wire the optional
|
|
@@ -180,11 +251,17 @@ the host, or the group picker's dropdown renders unstyled:
|
|
|
180
251
|
@import "@aiquants/select-box/styles/select-box.css";
|
|
181
252
|
```
|
|
182
253
|
|
|
183
|
-
|
|
184
|
-
installs this package is told what the picker needs rather than discovering it
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
254
|
+
`@aiquants/fuzzy-search` is a transitive peer (the picker's search index, reached only through select-box) and is
|
|
255
|
+
declared here as well, so a host that installs this package is told what the picker needs rather than discovering it
|
|
256
|
+
as a runtime resolution failure. `@aiquants/virtualscroll` is both: select-box renders its option list with it, and
|
|
257
|
+
this package imports it **directly** — `src/admin/labels.ts` resolves the UI language with
|
|
258
|
+
`resolveVirtualScrollLocale`, so `dist/admin.mjs` carries its specifier. The pickers use the `locale` / `labels` props
|
|
259
|
+
of `@aiquants/select-box` 0.10.0 and the locale resolution of `@aiquants/virtualscroll` 3.7.0, so those are the peer
|
|
260
|
+
floors.
|
|
261
|
+
|
|
262
|
+
All three are **required** peers, not optional. `src/admin/views.tsx` imports `@aiquants/select-box` and
|
|
263
|
+
`src/admin/labels.ts` imports `@aiquants/virtualscroll` at the top level, and `./admin` re-exports both modules, so the
|
|
264
|
+
specifiers survive into `dist/admin.mjs`: a host without them does not get a degraded
|
|
188
265
|
picker, it gets `ERR_MODULE_NOT_FOUND` for the whole admin surface — including the groups and allowlist tabs, which have
|
|
189
266
|
nothing to do with the picker. Marking them optional would suppress the install warning that is the only thing standing
|
|
190
267
|
between a consumer and that failure. Note also that `@aiquants/select-box` pins React 19, which is stricter than this
|
package/dist/admin.d.mts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { VirtualScrollLocale } from "@aiquants/virtualscroll";
|
|
1
2
|
import * as react_router from "react-router";
|
|
2
3
|
import { AuthUser, AuthGroup, AuthGroupMember, AuthAllowlistEntry, AuthDirectoryMembershipMode, AuthDirectoryStatus, AuthDirectoryCatalogSnapshot, AuthDirectoryCatalogGroup } from "@aiquants/auth-core";
|
|
3
4
|
import React__default from "react";
|
|
5
|
+
type UserAdminLocale = VirtualScrollLocale;
|
|
4
6
|
type UserAdminLabels = {
|
|
5
7
|
title: string;
|
|
6
|
-
locale:
|
|
8
|
+
locale: UserAdminLocale;
|
|
9
|
+
formatLocale: string;
|
|
7
10
|
timeZone: string;
|
|
8
11
|
common: {
|
|
9
12
|
create: string;
|
|
@@ -211,7 +214,8 @@ declare const defaultUserAdminLabels: UserAdminLabels;
|
|
|
211
214
|
declare const jaUserAdminLabels: UserAdminLabels;
|
|
212
215
|
type PartialUserAdminLabels = {
|
|
213
216
|
title?: string;
|
|
214
|
-
locale?:
|
|
217
|
+
locale?: UserAdminLocale;
|
|
218
|
+
formatLocale?: string;
|
|
215
219
|
timeZone?: string;
|
|
216
220
|
common?: Partial<UserAdminLabels["common"]>;
|
|
217
221
|
errors?: Partial<UserAdminLabels["errors"]>;
|
|
@@ -382,9 +386,10 @@ type UserAdminShellProps = {
|
|
|
382
386
|
title: string;
|
|
383
387
|
annotation: React__default.ReactNode;
|
|
384
388
|
}) => React__default.ReactNode;
|
|
389
|
+
basePath: string;
|
|
385
390
|
pendingSyncPolling?: PendingSyncPolling;
|
|
386
391
|
};
|
|
387
|
-
declare function UserAdminShell({ children, renderHeader, pendingSyncPolling }: UserAdminShellProps): React__default.JSX.Element;
|
|
392
|
+
declare function UserAdminShell({ children, renderHeader, pendingSyncPolling, basePath }: UserAdminShellProps): React__default.JSX.Element;
|
|
388
393
|
type UserAdminLoaderData = {
|
|
389
394
|
segment: string;
|
|
390
395
|
users: AuthUser[];
|
|
@@ -401,5 +406,5 @@ declare function GroupMembersView(): React__default.JSX.Element;
|
|
|
401
406
|
declare function AllowlistView(): React__default.JSX.Element;
|
|
402
407
|
declare function DirectoryView(): React__default.JSX.Element;
|
|
403
408
|
type AuthUserAdminAppViewProps = UserAdminShellProps;
|
|
404
|
-
declare function AuthUserAdminAppView({ renderHeader, pendingSyncPolling }
|
|
405
|
-
export { AllowlistView, AuthUserAdminAppView, type AuthUserAdminAppViewProps, DEFAULT_PENDING_SYNC_POLLING, DirectoryView, GroupMembersView, GroupsView, type PartialUserAdminLabels, type PendingSyncPolling, type UserAdminAccess, type UserAdminAppConfig, type UserAdminCatalog, type UserAdminCatalogFailure, type UserAdminCatalogGroup, type UserAdminCatalogSnapshot, type UserAdminGuards, UserAdminInputError, type UserAdminLabels, type UserAdminLinkSyncOutcome, type UserAdminLoaderData, UserAdminOperatorError, type UserAdminPermission, UserAdminShell, type UserAdminShellProps, type UserAdminStore, type UserAdminSyncRequestOutcome, UsersView, createInMemoryUserAdminStore, createUserAdminApp, defaultUserAdminLabels, jaUserAdminLabels, normalizeUpstreamKey, resolveUserAdminLabels, userAdminAccessFor, userAdminIntents };
|
|
409
|
+
declare function AuthUserAdminAppView({ renderHeader, pendingSyncPolling, basePath }: AuthUserAdminAppViewProps): React__default.JSX.Element;
|
|
410
|
+
export { AllowlistView, AuthUserAdminAppView, type AuthUserAdminAppViewProps, DEFAULT_PENDING_SYNC_POLLING, DirectoryView, GroupMembersView, GroupsView, type PartialUserAdminLabels, type PendingSyncPolling, type UserAdminAccess, type UserAdminAppConfig, type UserAdminCatalog, type UserAdminCatalogFailure, type UserAdminCatalogGroup, type UserAdminCatalogSnapshot, type UserAdminGuards, UserAdminInputError, type UserAdminLabels, type UserAdminLinkSyncOutcome, type UserAdminLoaderData, type UserAdminLocale, UserAdminOperatorError, type UserAdminPermission, UserAdminShell, type UserAdminShellProps, type UserAdminStore, type UserAdminSyncRequestOutcome, UsersView, createInMemoryUserAdminStore, createUserAdminApp, defaultUserAdminLabels, jaUserAdminLabels, normalizeUpstreamKey, resolveUserAdminLabels, userAdminAccessFor, userAdminIntents };
|
package/dist/admin.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { VirtualScrollLocale } from "@aiquants/virtualscroll";
|
|
1
2
|
import * as react_router from "react-router";
|
|
2
3
|
import { AuthUser, AuthGroup, AuthGroupMember, AuthAllowlistEntry, AuthDirectoryMembershipMode, AuthDirectoryStatus, AuthDirectoryCatalogSnapshot, AuthDirectoryCatalogGroup } from "@aiquants/auth-core";
|
|
3
4
|
import React__default from "react";
|
|
5
|
+
type UserAdminLocale = VirtualScrollLocale;
|
|
4
6
|
type UserAdminLabels = {
|
|
5
7
|
title: string;
|
|
6
|
-
locale:
|
|
8
|
+
locale: UserAdminLocale;
|
|
9
|
+
formatLocale: string;
|
|
7
10
|
timeZone: string;
|
|
8
11
|
common: {
|
|
9
12
|
create: string;
|
|
@@ -211,7 +214,8 @@ declare const defaultUserAdminLabels: UserAdminLabels;
|
|
|
211
214
|
declare const jaUserAdminLabels: UserAdminLabels;
|
|
212
215
|
type PartialUserAdminLabels = {
|
|
213
216
|
title?: string;
|
|
214
|
-
locale?:
|
|
217
|
+
locale?: UserAdminLocale;
|
|
218
|
+
formatLocale?: string;
|
|
215
219
|
timeZone?: string;
|
|
216
220
|
common?: Partial<UserAdminLabels["common"]>;
|
|
217
221
|
errors?: Partial<UserAdminLabels["errors"]>;
|
|
@@ -382,9 +386,10 @@ type UserAdminShellProps = {
|
|
|
382
386
|
title: string;
|
|
383
387
|
annotation: React__default.ReactNode;
|
|
384
388
|
}) => React__default.ReactNode;
|
|
389
|
+
basePath: string;
|
|
385
390
|
pendingSyncPolling?: PendingSyncPolling;
|
|
386
391
|
};
|
|
387
|
-
declare function UserAdminShell({ children, renderHeader, pendingSyncPolling }: UserAdminShellProps): React__default.JSX.Element;
|
|
392
|
+
declare function UserAdminShell({ children, renderHeader, pendingSyncPolling, basePath }: UserAdminShellProps): React__default.JSX.Element;
|
|
388
393
|
type UserAdminLoaderData = {
|
|
389
394
|
segment: string;
|
|
390
395
|
users: AuthUser[];
|
|
@@ -401,5 +406,5 @@ declare function GroupMembersView(): React__default.JSX.Element;
|
|
|
401
406
|
declare function AllowlistView(): React__default.JSX.Element;
|
|
402
407
|
declare function DirectoryView(): React__default.JSX.Element;
|
|
403
408
|
type AuthUserAdminAppViewProps = UserAdminShellProps;
|
|
404
|
-
declare function AuthUserAdminAppView({ renderHeader, pendingSyncPolling }
|
|
405
|
-
export { AllowlistView, AuthUserAdminAppView, type AuthUserAdminAppViewProps, DEFAULT_PENDING_SYNC_POLLING, DirectoryView, GroupMembersView, GroupsView, type PartialUserAdminLabels, type PendingSyncPolling, type UserAdminAccess, type UserAdminAppConfig, type UserAdminCatalog, type UserAdminCatalogFailure, type UserAdminCatalogGroup, type UserAdminCatalogSnapshot, type UserAdminGuards, UserAdminInputError, type UserAdminLabels, type UserAdminLinkSyncOutcome, type UserAdminLoaderData, UserAdminOperatorError, type UserAdminPermission, UserAdminShell, type UserAdminShellProps, type UserAdminStore, type UserAdminSyncRequestOutcome, UsersView, createInMemoryUserAdminStore, createUserAdminApp, defaultUserAdminLabels, jaUserAdminLabels, normalizeUpstreamKey, resolveUserAdminLabels, userAdminAccessFor, userAdminIntents };
|
|
409
|
+
declare function AuthUserAdminAppView({ renderHeader, pendingSyncPolling, basePath }: AuthUserAdminAppViewProps): React__default.JSX.Element;
|
|
410
|
+
export { AllowlistView, AuthUserAdminAppView, type AuthUserAdminAppViewProps, DEFAULT_PENDING_SYNC_POLLING, DirectoryView, GroupMembersView, GroupsView, type PartialUserAdminLabels, type PendingSyncPolling, type UserAdminAccess, type UserAdminAppConfig, type UserAdminCatalog, type UserAdminCatalogFailure, type UserAdminCatalogGroup, type UserAdminCatalogSnapshot, type UserAdminGuards, UserAdminInputError, type UserAdminLabels, type UserAdminLinkSyncOutcome, type UserAdminLoaderData, type UserAdminLocale, UserAdminOperatorError, type UserAdminPermission, UserAdminShell, type UserAdminShellProps, type UserAdminStore, type UserAdminSyncRequestOutcome, UsersView, createInMemoryUserAdminStore, createUserAdminApp, defaultUserAdminLabels, jaUserAdminLabels, normalizeUpstreamKey, resolveUserAdminLabels, userAdminAccessFor, userAdminIntents };
|