@learnorama/mozaik-sdk 0.1.0 → 0.5.0-staging.22.1
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 +186 -5
- package/dist/api/account.d.ts +2 -2
- package/dist/api/account.js +1 -1
- package/dist/api/account.js.map +1 -1
- package/dist/api/admin-catalogue.d.ts +2 -2
- package/dist/api/admin-catalogue.js +1 -1
- package/dist/api/admin-catalogue.js.map +1 -1
- package/dist/api/admin-consumption.d.ts +7 -2
- package/dist/api/admin-consumption.js +6 -1
- package/dist/api/admin-consumption.js.map +1 -1
- package/dist/api/admin-licenses.d.ts +2 -2
- package/dist/api/admin-licenses.js +1 -1
- package/dist/api/admin-licenses.js.map +1 -1
- package/dist/api/admin-patrons.d.ts +3 -3
- package/dist/api/admin-patrons.js +2 -2
- package/dist/api/admin-patrons.js.map +1 -1
- package/dist/api/admin-reviews.d.ts +2 -2
- package/dist/api/admin-reviews.js +1 -1
- package/dist/api/admin-reviews.js.map +1 -1
- package/dist/api/admin-roles.d.ts +3 -3
- package/dist/api/admin-roles.js +2 -2
- package/dist/api/admin-roles.js.map +1 -1
- package/dist/api/admin-support.d.ts +2 -2
- package/dist/api/admin-support.js +1 -1
- package/dist/api/admin-support.js.map +1 -1
- package/dist/api/admin-tenants.d.ts +14 -2
- package/dist/api/admin-tenants.js +38 -2
- package/dist/api/admin-tenants.js.map +1 -1
- package/dist/api/admin-tutoring.d.ts +2 -2
- package/dist/api/admin-tutoring.js +1 -1
- package/dist/api/admin-tutoring.js.map +1 -1
- package/dist/api/auth.d.ts +2 -2
- package/dist/api/auth.js +1 -1
- package/dist/api/auth.js.map +1 -1
- package/dist/api/biblio-catalogue.d.ts +2 -2
- package/dist/api/biblio-catalogue.js +1 -1
- package/dist/api/biblio-catalogue.js.map +1 -1
- package/dist/api/biblio-home.d.ts +2 -2
- package/dist/api/biblio-home.js +1 -1
- package/dist/api/biblio-home.js.map +1 -1
- package/dist/api/biblio-library.d.ts +2 -2
- package/dist/api/biblio-library.js +1 -1
- package/dist/api/biblio-library.js.map +1 -1
- package/dist/api/biblio-nextory.d.ts +2 -2
- package/dist/api/biblio-nextory.js +1 -1
- package/dist/api/biblio-nextory.js.map +1 -1
- package/dist/api/biblio-press.d.ts +2 -2
- package/dist/api/biblio-press.js +1 -1
- package/dist/api/biblio-press.js.map +1 -1
- package/dist/api/biblio-search.d.ts +2 -2
- package/dist/api/biblio-search.js +1 -1
- package/dist/api/biblio-search.js.map +1 -1
- package/dist/api/biblio-telemetry.d.ts +2 -2
- package/dist/api/biblio-telemetry.js +1 -1
- package/dist/api/biblio-telemetry.js.map +1 -1
- package/dist/api/consumption.d.ts +2 -2
- package/dist/api/consumption.js +1 -1
- package/dist/api/consumption.js.map +1 -1
- package/dist/api/cvs-app.d.ts +2 -2
- package/dist/api/cvs-app.js +1 -1
- package/dist/api/cvs-app.js.map +1 -1
- package/dist/api/cvs-documents.d.ts +16 -4
- package/dist/api/cvs-documents.js +22 -5
- package/dist/api/cvs-documents.js.map +1 -1
- package/dist/api/cvs-favorites.d.ts +2 -2
- package/dist/api/cvs-favorites.js +1 -1
- package/dist/api/cvs-favorites.js.map +1 -1
- package/dist/api/cvs-ils.d.ts +167 -0
- package/dist/api/cvs-ils.js +362 -0
- package/dist/api/cvs-ils.js.map +1 -0
- package/dist/api/cvs-loans.d.ts +2 -2
- package/dist/api/cvs-loans.js +1 -1
- package/dist/api/cvs-loans.js.map +1 -1
- package/dist/api/cvs-payments.d.ts +49 -0
- package/dist/api/cvs-payments.js +84 -0
- package/dist/api/cvs-payments.js.map +1 -0
- package/dist/api/cvs-streaming.d.ts +2 -2
- package/dist/api/cvs-streaming.js +1 -1
- package/dist/api/cvs-streaming.js.map +1 -1
- package/dist/api/index.d.ts +5 -2
- package/dist/api/index.js +7 -4
- package/dist/api/partner-catalogue.d.ts +2 -2
- package/dist/api/partner-catalogue.js +1 -1
- package/dist/api/partner-catalogue.js.map +1 -1
- package/dist/api/partner-reader.d.ts +2 -2
- package/dist/api/partner-reader.js +1 -1
- package/dist/api/partner-reader.js.map +1 -1
- package/dist/api/profiles.d.ts +2 -2
- package/dist/api/profiles.js +1 -1
- package/dist/api/profiles.js.map +1 -1
- package/dist/api/search.d.ts +18 -0
- package/dist/api/search.js +37 -0
- package/dist/api/search.js.map +1 -0
- package/dist/api/tutoring-catalogue.d.ts +2 -2
- package/dist/api/tutoring-catalogue.js +1 -1
- package/dist/api/tutoring-catalogue.js.map +1 -1
- package/dist/api/tutoring-chat.d.ts +2 -2
- package/dist/api/tutoring-chat.js +1 -1
- package/dist/api/tutoring-chat.js.map +1 -1
- package/dist/api/tutoring-dispatch.d.ts +2 -2
- package/dist/api/tutoring-dispatch.js +1 -1
- package/dist/api/tutoring-dispatch.js.map +1 -1
- package/dist/api/tutoring-practitioner.d.ts +2 -2
- package/dist/api/tutoring-practitioner.js +1 -1
- package/dist/api/tutoring-practitioner.js.map +1 -1
- package/dist/api/tutoring-requests.d.ts +2 -2
- package/dist/api/tutoring-requests.js +1 -1
- package/dist/api/tutoring-requests.js.map +1 -1
- package/dist/auth.d.ts +10 -0
- package/dist/auth.js +451 -0
- package/dist/auth.js.map +1 -0
- package/dist/chat.d.ts +3 -0
- package/dist/chat.js +3 -0
- package/dist/{client-BDwBZYB0.d.ts → chunks/client.d.ts} +1 -1
- package/dist/{client-D3kMOcIr.js → chunks/client.js} +1 -1
- package/dist/chunks/client.js.map +1 -0
- package/dist/chunks/client2.d.ts +53 -0
- package/dist/chunks/connection.d.ts +28 -0
- package/dist/chunks/connection.js +141 -0
- package/dist/chunks/connection.js.map +1 -0
- package/dist/{index-wL_20vR8.d.ts → chunks/index.d.ts} +922 -128
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +2 -2
- package/dist/models.js +44 -1
- package/dist/models.js.map +1 -1
- package/dist/react/account.d.ts +2 -2
- package/dist/react/account.js +2 -2
- package/dist/react/account.js.map +1 -1
- package/dist/react/admin-catalogue.d.ts +2 -2
- package/dist/react/admin-catalogue.js +2 -2
- package/dist/react/admin-catalogue.js.map +1 -1
- package/dist/react/admin-consumption.d.ts +7 -2
- package/dist/react/admin-consumption.js +7 -2
- package/dist/react/admin-consumption.js.map +1 -1
- package/dist/react/admin-licenses.d.ts +2 -2
- package/dist/react/admin-licenses.js +2 -2
- package/dist/react/admin-licenses.js.map +1 -1
- package/dist/react/admin-patrons.d.ts +3 -3
- package/dist/react/admin-patrons.js +3 -3
- package/dist/react/admin-patrons.js.map +1 -1
- package/dist/react/admin-reviews.d.ts +2 -2
- package/dist/react/admin-reviews.js +2 -2
- package/dist/react/admin-reviews.js.map +1 -1
- package/dist/react/admin-roles.d.ts +3 -3
- package/dist/react/admin-roles.js +3 -3
- package/dist/react/admin-roles.js.map +1 -1
- package/dist/react/admin-support.d.ts +2 -2
- package/dist/react/admin-support.js +2 -2
- package/dist/react/admin-support.js.map +1 -1
- package/dist/react/admin-tenants.d.ts +68 -2
- package/dist/react/admin-tenants.js +87 -3
- package/dist/react/admin-tenants.js.map +1 -1
- package/dist/react/admin-tutoring.d.ts +2 -2
- package/dist/react/admin-tutoring.js +2 -2
- package/dist/react/admin-tutoring.js.map +1 -1
- package/dist/react/auth.d.ts +2 -2
- package/dist/react/auth.js +2 -2
- package/dist/react/auth.js.map +1 -1
- package/dist/react/biblio-catalogue.d.ts +2 -2
- package/dist/react/biblio-catalogue.js +2 -2
- package/dist/react/biblio-catalogue.js.map +1 -1
- package/dist/react/biblio-home.d.ts +2 -2
- package/dist/react/biblio-home.js +2 -2
- package/dist/react/biblio-home.js.map +1 -1
- package/dist/react/biblio-library.d.ts +2 -2
- package/dist/react/biblio-library.js +2 -2
- package/dist/react/biblio-library.js.map +1 -1
- package/dist/react/biblio-nextory.d.ts +2 -2
- package/dist/react/biblio-nextory.js +2 -2
- package/dist/react/biblio-nextory.js.map +1 -1
- package/dist/react/biblio-press.d.ts +2 -2
- package/dist/react/biblio-press.js +2 -2
- package/dist/react/biblio-press.js.map +1 -1
- package/dist/react/biblio-search.d.ts +2 -2
- package/dist/react/biblio-search.js +2 -2
- package/dist/react/biblio-search.js.map +1 -1
- package/dist/react/biblio-telemetry.d.ts +2 -2
- package/dist/react/biblio-telemetry.js +2 -2
- package/dist/react/biblio-telemetry.js.map +1 -1
- package/dist/react/chat.d.ts +36 -0
- package/dist/react/chat.js +234 -0
- package/dist/react/chat.js.map +1 -0
- package/dist/react/consumption.d.ts +2 -2
- package/dist/react/consumption.js +2 -2
- package/dist/react/consumption.js.map +1 -1
- package/dist/react/cvs-app.d.ts +2 -2
- package/dist/react/cvs-app.js +2 -2
- package/dist/react/cvs-app.js.map +1 -1
- package/dist/react/cvs-documents.d.ts +17 -4
- package/dist/react/cvs-documents.js +25 -8
- package/dist/react/cvs-documents.js.map +1 -1
- package/dist/react/cvs-favorites.d.ts +2 -2
- package/dist/react/cvs-favorites.js +2 -2
- package/dist/react/cvs-favorites.js.map +1 -1
- package/dist/react/cvs-ils.d.ts +552 -0
- package/dist/react/cvs-ils.js +822 -0
- package/dist/react/cvs-ils.js.map +1 -0
- package/dist/react/cvs-loans.d.ts +2 -2
- package/dist/react/cvs-loans.js +2 -2
- package/dist/react/cvs-loans.js.map +1 -1
- package/dist/react/cvs-payments.d.ts +123 -0
- package/dist/react/cvs-payments.js +181 -0
- package/dist/react/cvs-payments.js.map +1 -0
- package/dist/react/cvs-streaming.d.ts +2 -2
- package/dist/react/cvs-streaming.js +2 -2
- package/dist/react/cvs-streaming.js.map +1 -1
- package/dist/react/index.d.ts +5 -2
- package/dist/react/index.js +5 -2
- package/dist/react/partner-catalogue.d.ts +2 -2
- package/dist/react/partner-catalogue.js +2 -2
- package/dist/react/partner-catalogue.js.map +1 -1
- package/dist/react/partner-reader.d.ts +2 -2
- package/dist/react/partner-reader.js +2 -2
- package/dist/react/partner-reader.js.map +1 -1
- package/dist/react/profiles.d.ts +2 -2
- package/dist/react/profiles.js +2 -2
- package/dist/react/profiles.js.map +1 -1
- package/dist/react/search.d.ts +47 -0
- package/dist/react/search.js +81 -0
- package/dist/react/search.js.map +1 -0
- package/dist/react/sso.d.ts +15 -0
- package/dist/react/sso.js +48 -0
- package/dist/react/sso.js.map +1 -0
- package/dist/react/tutoring-catalogue.d.ts +2 -2
- package/dist/react/tutoring-catalogue.js +2 -2
- package/dist/react/tutoring-catalogue.js.map +1 -1
- package/dist/react/tutoring-chat.d.ts +2 -2
- package/dist/react/tutoring-chat.js +2 -2
- package/dist/react/tutoring-chat.js.map +1 -1
- package/dist/react/tutoring-dispatch.d.ts +2 -2
- package/dist/react/tutoring-dispatch.js +2 -2
- package/dist/react/tutoring-dispatch.js.map +1 -1
- package/dist/react/tutoring-practitioner.d.ts +2 -2
- package/dist/react/tutoring-practitioner.js +2 -2
- package/dist/react/tutoring-practitioner.js.map +1 -1
- package/dist/react/tutoring-requests.d.ts +2 -2
- package/dist/react/tutoring-requests.js +2 -2
- package/dist/react/tutoring-requests.js.map +1 -1
- package/package.json +29 -1
- package/dist/client-D3kMOcIr.js.map +0 -1
package/README.md
CHANGED
|
@@ -35,9 +35,123 @@ The token getter runs for every request, so refreshing a token does not require
|
|
|
35
35
|
recreating the client. Clients can also supply default headers and a custom fetch
|
|
36
36
|
implementation. Request options accept headers and an AbortSignal.
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
The basic `createClient` transport uses the token getter you provide. For managed
|
|
39
|
+
PKCE and session refresh, use the SSO client below. Neither transport automatically
|
|
40
|
+
replays failed application writes. Backend-owned Keycloak client secrets must
|
|
41
|
+
never be supplied to this SDK.
|
|
42
|
+
|
|
43
|
+
## Google Workspace and partner SSO
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
// auth.ts — one instance for the browser application
|
|
47
|
+
import { createMozaikAuth } from '@learnorama/mozaik-sdk/auth';
|
|
48
|
+
|
|
49
|
+
export const auth = createMozaikAuth({
|
|
50
|
+
baseUrl: 'https://api.stg.mozaik.co',
|
|
51
|
+
redirectUri: 'https://your-app.example/auth/callback',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// A click handler: prepare returns a URL; navigation stays under your control.
|
|
55
|
+
const { url } = await auth.prepareInternalSso({ returnTo: '/requests' });
|
|
56
|
+
window.location.assign(url);
|
|
57
|
+
|
|
58
|
+
// On /auth/callback, pass your SPA router's replace-navigation function:
|
|
59
|
+
async function finishSso(navigate: (path: string) => void) {
|
|
60
|
+
const { returnTo } = await auth.completeSso();
|
|
61
|
+
navigate(returnTo);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Register the application's callback URL in Keycloak and allow its origin in the
|
|
66
|
+
backend's `AUTH_ALLOWED_REDIRECT_ORIGINS`. Replace `your-app.example` with your
|
|
67
|
+
frontend origin. Start login on that origin so the callback can read the same
|
|
68
|
+
tab's transaction storage.
|
|
69
|
+
|
|
70
|
+
| Method | Behavior |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| `prepareInternalSso({ returnTo? })` | Selects the existing `google` Workspace staff provider. |
|
|
73
|
+
| `prepareProviderSso(alias, { returnTo? })` | Selects a registered, brokered partner; the backend validates the alias. |
|
|
74
|
+
| `prepareSso({ returnTo? })` | Lets the backend resolve the provider from the configured API hostname. |
|
|
75
|
+
| `completeSso(callbackUrl?)` | Validates and consumes the transaction, exchanges the code through the backend, and returns account, principal and return path. Defaults to the current browser URL. |
|
|
76
|
+
| `refresh()` | Refreshes the session; concurrent callers share one exchange. |
|
|
77
|
+
| `logout()` | Clears local authentication immediately and revokes the refresh token. |
|
|
78
|
+
| `dispose()` | Local teardown for the application owner; does not revoke the server session. |
|
|
79
|
+
|
|
80
|
+
Preparation also accepts `prompt: 'login' | 'none' | 'consent'`. Return paths must
|
|
81
|
+
be local absolute paths such as `/requests`, never an external URL. PKCE uses
|
|
82
|
+
S256; state, callback address, transaction expiry, expected provider and any
|
|
83
|
+
returned issuer are checked. The code exchange stays on our backend so first
|
|
84
|
+
login provisions the local account. Google Workspace membership and permissions
|
|
85
|
+
remain enforced by Keycloak and the backend.
|
|
86
|
+
|
|
87
|
+
Only short-lived PKCE transactions are saved to per-tab `sessionStorage` (ten
|
|
88
|
+
minutes). Access and refresh tokens stay in memory and are absent from the auth
|
|
89
|
+
snapshot. **Reloading the page starts without a local session**: initiate SSO again;
|
|
90
|
+
an existing Keycloak/Workspace session may complete it without another credential
|
|
91
|
+
prompt. This implementation uses full-page redirects, not popup messaging or
|
|
92
|
+
silent iframe authentication. After completing the callback, use your SPA router
|
|
93
|
+
to navigate locally: `location.replace()` would reload and lose the new session.
|
|
94
|
+
|
|
95
|
+
The client refreshes before expiry and on demand, coordinating token rotation.
|
|
96
|
+
Transient refresh failures may use an access token only until its expiry; rejected
|
|
97
|
+
or expired sessions clear local authentication. Remote logout errors reject the
|
|
98
|
+
promise while leaving the application signed out. Tokens are attached through
|
|
99
|
+
`auth.client`; its identity changes on login/logout and stays stable across
|
|
100
|
+
refreshes. Old client instances reject requests after a session change.
|
|
101
|
+
|
|
102
|
+
## React SSO shortcut
|
|
103
|
+
|
|
104
|
+
`MozaikAuthProvider` supplies both authentication and its own TanStack Query
|
|
105
|
+
provider. Put SDK consumers inside it; an additional QueryClientProvider is not
|
|
106
|
+
needed for that subtree. `/react/auth` still contains the generated HTTP hooks;
|
|
107
|
+
the handwritten SSO integration is `/react/sso`.
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import { useEffect } from 'react';
|
|
111
|
+
import { MozaikAuthProvider, useMozaikAuth } from '@learnorama/mozaik-sdk/react/sso';
|
|
112
|
+
import { useReadMe } from '@learnorama/mozaik-sdk/react/auth';
|
|
113
|
+
import { auth } from './auth';
|
|
114
|
+
|
|
115
|
+
export function Root() {
|
|
116
|
+
return <MozaikAuthProvider auth={auth}><Account /></MozaikAuthProvider>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function Account() {
|
|
120
|
+
const { client, isAuthenticated, isLoading, error, prepareInternalSso, logout } = useMozaikAuth();
|
|
121
|
+
const me = useReadMe({ request: { client }, query: { enabled: isAuthenticated } });
|
|
122
|
+
async function signIn() {
|
|
123
|
+
try {
|
|
124
|
+
const { url } = await prepareInternalSso({ returnTo: '/requests' });
|
|
125
|
+
window.location.assign(url);
|
|
126
|
+
} catch { /* error is exposed by useMozaikAuth */ }
|
|
127
|
+
}
|
|
128
|
+
if (isAuthenticated) return <button onClick={() => { void logout().catch(() => {}); }}>Sign out {me.data?.account.email}</button>;
|
|
129
|
+
return <><button disabled={isLoading} onClick={() => { void signIn(); }}>Sign in with Google Workspace</button>{error && <p role="alert">{error.message}</p>}</>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Render this at /auth/callback, also inside MozaikAuthProvider.
|
|
133
|
+
export function SsoCallback({ navigate }: { navigate: (path: string) => void }) {
|
|
134
|
+
const { completeSso, error } = useMozaikAuth();
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
void completeSso().then(({ returnTo }) => navigate(returnTo)).catch(() => {});
|
|
137
|
+
}, [completeSso, navigate]);
|
|
138
|
+
return <p>{error ? error.message : 'Completing sign-in…'}</p>;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Concurrent callback completions share one exchange. The callback parameters are
|
|
143
|
+
removed from browser history; repeated default completion calls on that cleaned
|
|
144
|
+
URL are safe during React remounts. Replaying an explicit consumed callback is
|
|
145
|
+
rejected. Login/logout replace the query cache and remount the session subtree,
|
|
146
|
+
preventing previous-account results from appearing. Refresh retains the cache.
|
|
147
|
+
For chat, use the same auth `client` and `enabled: isAuthenticated` with
|
|
148
|
+
`useTutoringChat`; session changes close the previous connection automatically.
|
|
149
|
+
|
|
150
|
+
Create the auth instance outside component renders, once per browser application
|
|
151
|
+
or per server request. The provider does not call `dispose()` on unmount: this
|
|
152
|
+
would invalidate the shared controller during Strict Mode's cleanup/re-setup.
|
|
153
|
+
The application owner may dispose it on permanent teardown. Browser operations
|
|
154
|
+
require Web Crypto and sessionStorage in a secure context.
|
|
41
155
|
|
|
42
156
|
## React
|
|
43
157
|
|
|
@@ -64,6 +178,73 @@ Create a separate client and QueryClient for each server-side request. Clear the
|
|
|
64
178
|
query cache on logout, account change, or a change of acting-as/tenant context;
|
|
65
179
|
generated query keys do not contain credentials or identify the current user.
|
|
66
180
|
|
|
181
|
+
## ProfExpress student/teacher chat
|
|
182
|
+
|
|
183
|
+
The handwritten chat hook is published alongside the generated HTTP hooks:
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
import type { Client } from '@learnorama/mozaik-sdk';
|
|
187
|
+
import { useTutoringChat } from '@learnorama/mozaik-sdk/react/chat';
|
|
188
|
+
|
|
189
|
+
export function TutoringRoom({ client, requestId }: { client: Client; requestId: number }) {
|
|
190
|
+
const chat = useTutoringChat({ client, requestId });
|
|
191
|
+
|
|
192
|
+
async function send(body: string) {
|
|
193
|
+
try {
|
|
194
|
+
await chat.sendMessage({ body });
|
|
195
|
+
} catch {
|
|
196
|
+
// chat.sendError exposes the error; keep the draft for an explicit retry.
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<section>
|
|
202
|
+
<p>Connection: {chat.status}</p>
|
|
203
|
+
{chat.error && <p role="alert">Chat connection interrupted.</p>}
|
|
204
|
+
{chat.hasMore && (
|
|
205
|
+
<button disabled={chat.isLoadingOlder} onClick={() => { void chat.loadOlder().catch(() => {}); }}>
|
|
206
|
+
Older messages
|
|
207
|
+
</button>
|
|
208
|
+
)}
|
|
209
|
+
{chat.messages.map(message => <p key={message.id}>{message.body ?? 'Message removed'}</p>)}
|
|
210
|
+
<button disabled={chat.isSending} onClick={() => { void send('Bonjour !'); }}>Send</button>
|
|
211
|
+
{chat.sendError && <p role="alert">Message not confirmed. Please retry.</p>}
|
|
212
|
+
</section>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Use this inside `QueryClientProvider`. Keep `client` stable; create a new client
|
|
218
|
+
when switching signed-in accounts. Pass `requestId: null` or `enabled: false`
|
|
219
|
+
on logout/when no room is selected. The hook closes its connection, cancels
|
|
220
|
+
requests and clears its private history on cleanup, including React Strict Mode.
|
|
221
|
+
Messages are ordered oldest first and deduplicated by ID.
|
|
222
|
+
|
|
223
|
+
The hook obtains a fresh single-use ticket for every connection; the OAuth access
|
|
224
|
+
token never enters the WebSocket URL. The server acknowledges the Redis
|
|
225
|
+
subscription before accepting the socket. The hook then loads history while
|
|
226
|
+
buffering live messages and retrieves missed pages after reconnecting. Network
|
|
227
|
+
failures reconnect with backoff; HTTP 401/403/404 and socket policy refusal stop
|
|
228
|
+
retries. Refresh authentication/access before enabling the hook again.
|
|
229
|
+
|
|
230
|
+
`sendMessage` uses the HTTP endpoint so success confirms persistence. Each send
|
|
231
|
+
gets a `clientKey`; writes are not automatically retried. For a failed send, pass
|
|
232
|
+
`chat.lastSend` back to `chat.sendMessage` to retain that key and avoid duplication.
|
|
233
|
+
For multiple simultaneous drafts, supply and retain a separate `clientKey` for
|
|
234
|
+
each draft yourself. `loadOlderError`, `sendError` and the connection `error` are
|
|
235
|
+
separate; `isSending`, `isLoading`, and `isLoadingOlder` support the corresponding UI.
|
|
236
|
+
|
|
237
|
+
Without React, import `connectTutoringChat` from `@learnorama/mozaik-sdk/chat`.
|
|
238
|
+
Provide `client`, `requestId`, and `onMessage`; call the returned `close()` on
|
|
239
|
+
cleanup. Its optional async `onConnect(signal)` callback can retrieve history;
|
|
240
|
+
incoming messages are buffered until it resolves. Sending and history are the
|
|
241
|
+
generated functions under `/api/tutoring-chat`.
|
|
242
|
+
|
|
243
|
+
Live chat messages are validated at runtime against the generated message kind
|
|
244
|
+
and the expected room/message shape. The chat module uses native WebSocket,
|
|
245
|
+
AbortSignal and secure-context `crypto.randomUUID()` APIs. It introduces no
|
|
246
|
+
additional production dependencies.
|
|
247
|
+
|
|
67
248
|
## Models and errors
|
|
68
249
|
|
|
69
250
|
```ts
|
|
@@ -89,6 +270,6 @@ are required; the backend commit SHA is metadata, not the package version.
|
|
|
89
270
|
import { apiVersion, backendRevision, schemaSha256 } from '@learnorama/mozaik-sdk';
|
|
90
271
|
```
|
|
91
272
|
|
|
92
|
-
TypeScript types describe the API contract; they do not validate
|
|
93
|
-
at runtime. The package contains the client and type declarations, not application
|
|
273
|
+
Generated HTTP TypeScript types describe the API contract; they do not validate
|
|
274
|
+
response bodies at runtime. The package contains the client and type declarations, not application
|
|
94
275
|
credentials or backend implementation code.
|
package/dist/api/account.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
import { c as request } from "../client
|
|
2
|
+
import { Li as AccountUpdateWrite, U as ServiceListRead, zi as AccountDetailRead } from "../chunks/index.js";
|
|
3
|
+
import { c as request } from "../chunks/client.js";
|
|
4
4
|
//#region src/api/account/account.d.ts
|
|
5
5
|
export declare const getDeleteAccountUrl: () => string;
|
|
6
6
|
/**
|
package/dist/api/account.js
CHANGED
package/dist/api/account.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account.js","names":[],"sources":["../../src/api/account/account.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.
|
|
1
|
+
{"version":3,"file":"account.js","names":[],"sources":["../../src/api/account/account.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.5.0\n */\nimport type {\n AccountDetailRead,\n AccountUpdateWrite,\n ServiceListRead\n} from '../../models';\n\nimport { request } from '../../client';\n\nexport const getDeleteAccountUrl = () => {\n\n\n\n\n return `/me`\n}\n\n/**\n * Close the account (E17). Anonymises; does not erase.\n *\n * The spec asked for the password to be re-submitted. We do not hold one, and\n * assurance is the better guard anyway: a password check would have passed for a\n * session that arrived through a partner handing over a static key in a URL,\n * and ``RequireHighAssurance`` refuses exactly that. The legacy required no\n * confirmation of any kind and accepted the call from a sub-profile (defect D8).\n *\n * **What survives, and why.** The row stays, with identity cleared and\n * ``is_anonymous`` set. Consumption history, loans and billing records point at\n * this user, and deleting the row would either cascade them away — destroying\n * the library's statutory reporting — or orphan them. Clearing the identifying\n * columns satisfies erasure of personal data while leaving the countable facts\n * countable. The retained set is: which tenant, when they registered, and what\n * they consumed, with no name, login, email, birth date or member number.\n *\n * Sub-profiles go with the holder: they are people on the same membership and\n * cannot outlive it. Their rows are anonymised too, not deleted, for the same\n * reason.\n *\n * **The broker is disabled first, and a failure aborts the whole thing.** The\n * credential lives in Keycloak, so anonymising locally while leaving it enabled\n * would let the same person sign in tomorrow and be provisioned a fresh account\n * — erasure that erases nothing. Disabling before any local write means the\n * failure mode is \"nothing happened\", which is recoverable, rather than \"half\n * happened\", which is not.\n *\n * Still missing, and not safe to ship without: no audit record is written.\n * @summary Delete Account\n */\nexport const deleteAccount = async ( options?: Parameters<typeof request>[1]): Promise<void> => {\n\n return request<void>(getDeleteAccountUrl(),\n {\n ...options,\n method: 'DELETE'\n\n\n }\n);}\n\n\nexport const getReadAccountUrl = () => {\n\n\n\n\n return `/me`\n}\n\n/**\n * The authenticated account (E15).\n *\n * No query, no join: ``CurrentUserDep`` has already resolved the row behind the\n * token. The endpoint the legacy should have had here has been returning ``500``\n * on every request for as long as anyone has looked (defect D1).\n * @summary Read Account\n */\nexport const readAccount = async ( options?: Parameters<typeof request>[1]): Promise<AccountDetailRead> => {\n\n return request<AccountDetailRead>(getReadAccountUrl(),\n {\n ...options,\n method: 'GET'\n\n\n }\n);}\n\n\nexport const getUpdateAccountUrl = () => {\n\n\n\n\n return `/me`\n}\n\n/**\n * Partially update the account (E16).\n *\n * ``exclude_unset`` is what separates PATCH from PUT here: a field the client\n * omitted is left alone, which is not the same as a field it sent as null. The\n * response is built from the persisted row rather than the submitted body.\n * @summary Update Account\n */\nexport const updateAccount = async (accountUpdateWrite: AccountUpdateWrite, options?: Parameters<typeof request>[1]): Promise<AccountDetailRead> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nreturn request<AccountDetailRead>(getUpdateAccountUrl(),\n {\n ...options,\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(accountUpdateWrite)\n }\n);}\n\n\nexport const getListServicesUrl = () => {\n\n\n\n\n return `/me/services`\n}\n\n/**\n * Third-party services this account's establishment offers (E27).\n *\n * Under ``/me`` rather than ``/biblio/me`` because it is not a catalogue: these\n * are the establishment's own service tiles, and they belong to the tenant\n * whichever catalogue that tenant reads from. It is also the one place the\n * biblio spec describes something the *CVS* schema models, which is why it sat\n * in the wrong module until the prefixes made the mismatch visible.\n *\n * Date-windowed. A service outside its window is absent rather than disabled:\n * the client should not have to know the difference, and a visible dead link is\n * worse than no link.\n * @summary List Services\n */\nexport const listServices = async ( options?: Parameters<typeof request>[1]): Promise<ServiceListRead> => {\n\n return request<ServiceListRead>(getListServicesUrl(),\n {\n ...options,\n method: 'GET'\n\n\n }\n);}\n\n\n"],"mappings":";;;AAeA,MAAa,4BAA4B;CAKvC,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,MAAa,gBAAgB,OAAQ,YAA2D;CAE9F,OAAO,QAAc,oBAAoB,GACzC;EACE,GAAG;EACH,QAAQ;CAGV,CACF;AAAE;AAGF,MAAa,0BAA0B;CAKrC,OAAO;AACT;;;;;;;;;AAUA,MAAa,cAAc,OAAQ,YAAwE;CAEzG,OAAO,QAA2B,kBAAkB,GACpD;EACE,GAAG;EACH,QAAQ;CAGV,CACF;AAAE;AAGF,MAAa,4BAA4B;CAKvC,OAAO;AACT;;;;;;;;;AAUA,MAAa,gBAAgB,OAAO,oBAAwC,YAAwE;CAEhJ,MAAM,cAAc,MAAwF;EAC5G,IAAI,CAAC,GAAG,OAAO,CAAC;EAChB,IAAI,aAAa,SAAS,OAAO,OAAO,YAAY,EAAE,QAAQ,CAAC;EAC/D,IAAI,OAAO,YAAY,GACrB,OAAO,OAAO,YACZ,MAAM,KAAK,IAAkC,UAAU,MAAM,KAAK,KAAK,CAAqB,CAC9F;EAEF,MAAM,UAAsD,CAAC;EAC7D,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAgD,CAAC,GAClF,IAAI,UAAU,KAAA,GAAW,QAAQ,QAAQ;EAE3C,OAAO;CACT;CACF,OAAO,QAA2B,oBAAoB,GACpD;EACE,GAAG;EACH,QAAQ;EACR,SAAS;GAAE,gBAAgB;GAAoB,GAAG,WAAW,SAAS,OAAO;EAAE;EAC/E,MAAM,KAAK,UAAU,kBAAkB;CACzC,CACF;AAAE;AAGF,MAAa,2BAA2B;CAKtC,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,MAAa,eAAe,OAAQ,YAAsE;CAExG,OAAO,QAAyB,mBAAmB,GACnD;EACE,GAAG;EACH,QAAQ;CAGV,CACF;AAAE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import { C as ThemeWrite, E as ThemeRead, T as ThemeListRead,
|
|
3
|
-
import { c as request } from "../client
|
|
2
|
+
import { C as ThemeWrite, E as ThemeRead, T as ThemeListRead, w as ThemeOrderWrite, xn as ListThemesParams } from "../chunks/index.js";
|
|
3
|
+
import { c as request } from "../chunks/client.js";
|
|
4
4
|
//#region src/api/admin-catalogue/admin-catalogue.d.ts
|
|
5
5
|
export declare const getListThemesUrl: (params?: ListThemesParams) => string;
|
|
6
6
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-catalogue.js","names":[],"sources":["../../src/api/admin-catalogue/admin-catalogue.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.
|
|
1
|
+
{"version":3,"file":"admin-catalogue.js","names":[],"sources":["../../src/api/admin-catalogue/admin-catalogue.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.5.0\n */\nimport type {\n ListThemesParams,\n ThemeListRead,\n ThemeOrderWrite,\n ThemeRead,\n ThemeWrite\n} from '../../models';\n\nimport { request } from '../../client';\n\nexport const getListThemesUrl = (params?: ListThemesParams,) => {\n const normalizedParams = new URLSearchParams();\n\n Object.entries(params || {}).forEach(([key, value]) => {\n\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : String(value))\n }\n });\n\n const stringifiedParams = normalizedParams.toString();\n\n return stringifiedParams.length > 0 ? `/admin/themes?${stringifiedParams}` : `/admin/themes`\n}\n\n/**\n * Every theme, or one pillar's, in display order.\n *\n * Not paginated. There are 27 of them, and a client that has to page through\n * a list it is about to reorder cannot reorder it.\n * @summary List Themes\n */\nexport const listThemes = async (params?: ListThemesParams, options?: Parameters<typeof request>[1]): Promise<ThemeListRead> => {\n\n return request<ThemeListRead>(getListThemesUrl(params),\n {\n ...options,\n method: 'GET'\n\n\n }\n);}\n\n\nexport const getCreateThemeUrl = () => {\n\n\n\n\n return `/admin/themes`\n}\n\n/**\n * Add a theme.\n *\n * ``409`` on a duplicate ``(pillar, title)``: that pair is unique in the\n * schema, and two themes with the same name in the same pillar are\n * indistinguishable to everyone downstream.\n *\n * With no ``sortOrder`` it goes last, which is what the legacy's form does by\n * defaulting the field to the current maximum plus one.\n * @summary Create Theme\n */\nexport const createTheme = async (themeWrite: ThemeWrite, options?: Parameters<typeof request>[1]): Promise<ThemeRead> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nreturn request<ThemeRead>(getCreateThemeUrl(),\n {\n ...options,\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(themeWrite)\n }\n);}\n\n\nexport const getReorderThemesUrl = () => {\n\n\n\n\n return `/admin/themes/order`\n}\n\n/**\n * Set the display order for a set of themes, in one transaction.\n *\n * The legacy renumbers one theme per request, so dragging an item in a list of\n * thirty was thirty requests — and closing the tab halfway left the order\n * half-applied, with two themes claiming the same position and the listing\n * silently choosing between them.\n *\n * Ids not named keep their relative order after the ones that are, so a client\n * may send only what moved. An unknown id is ``404`` and nothing is written:\n * a partially applied reorder is the failure this endpoint exists to prevent.\n * @summary Reorder Themes\n */\nexport const reorderThemes = async (themeOrderWrite: ThemeOrderWrite, options?: Parameters<typeof request>[1]): Promise<void> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nreturn request<void>(getReorderThemesUrl(),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(themeOrderWrite)\n }\n);}\n\n\nexport const getDeleteThemeUrl = (themeId: number,) => {\n\n\n\n\n return `/admin/themes/${themeId}`\n}\n\n/**\n * Remove a theme.\n *\n * ``409`` when works still carry it. The legacy deletes and leaves the\n * references dangling, which is how a catalogue ends up with items filed under\n * a theme that no longer exists and no screen that can find them.\n *\n * Idempotent otherwise: deleting something already gone is ``204``, because\n * the caller wanted it gone and it is gone.\n * @summary Delete Theme\n */\nexport const deleteTheme = async (themeId: number, options?: Parameters<typeof request>[1]): Promise<void> => {\n\n return request<void>(getDeleteThemeUrl(themeId),\n {\n ...options,\n method: 'DELETE'\n\n\n }\n);}\n\n\nexport const getReadThemeUrl = (themeId: number,) => {\n\n\n\n\n return `/admin/themes/${themeId}`\n}\n\n/**\n * One theme.\n * @summary Read Theme\n */\nexport const readTheme = async (themeId: number, options?: Parameters<typeof request>[1]): Promise<ThemeRead> => {\n\n return request<ThemeRead>(getReadThemeUrl(themeId),\n {\n ...options,\n method: 'GET'\n\n\n }\n);}\n\n\nexport const getAmendThemeUrl = (themeId: number,) => {\n\n\n\n\n return `/admin/themes/${themeId}`\n}\n\n/**\n * Amend a theme. Same uniqueness rule as creating one.\n * @summary Amend Theme\n */\nexport const amendTheme = async (themeId: number,\n themeWrite: ThemeWrite, options?: Parameters<typeof request>[1]): Promise<ThemeRead> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nreturn request<ThemeRead>(getAmendThemeUrl(themeId),\n {\n ...options,\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(themeWrite)\n }\n);}\n\n\n"],"mappings":";;;AAiBA,MAAa,oBAAoB,WAA+B;CAC9D,MAAM,mBAAmB,IAAI,gBAAgB;CAE7C,OAAO,QAAQ,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;EAErD,IAAI,UAAU,KAAA,GACZ,iBAAiB,OAAO,KAAK,UAAU,OAAO,SAAS,OAAO,KAAK,CAAC;CAExE,CAAC;CAED,MAAM,oBAAoB,iBAAiB,SAAS;CAEpD,OAAO,kBAAkB,SAAS,IAAI,iBAAiB,sBAAsB;AAC/E;;;;;;;;AASA,MAAa,aAAa,OAAO,QAA2B,YAAoE;CAE9H,OAAO,QAAuB,iBAAiB,MAAM,GACrD;EACE,GAAG;EACH,QAAQ;CAGV,CACF;AAAE;AAGF,MAAa,0BAA0B;CAKrC,OAAO;AACT;;;;;;;;;;;;AAaA,MAAa,cAAc,OAAO,YAAwB,YAAgE;CAEtH,MAAM,cAAc,MAAwF;EAC5G,IAAI,CAAC,GAAG,OAAO,CAAC;EAChB,IAAI,aAAa,SAAS,OAAO,OAAO,YAAY,EAAE,QAAQ,CAAC;EAC/D,IAAI,OAAO,YAAY,GACrB,OAAO,OAAO,YACZ,MAAM,KAAK,IAAkC,UAAU,MAAM,KAAK,KAAK,CAAqB,CAC9F;EAEF,MAAM,UAAsD,CAAC;EAC7D,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAgD,CAAC,GAClF,IAAI,UAAU,KAAA,GAAW,QAAQ,QAAQ;EAE3C,OAAO;CACT;CACF,OAAO,QAAmB,kBAAkB,GAC1C;EACE,GAAG;EACH,QAAQ;EACR,SAAS;GAAE,gBAAgB;GAAoB,GAAG,WAAW,SAAS,OAAO;EAAE;EAC/E,MAAM,KAAK,UAAU,UAAU;CACjC,CACF;AAAE;AAGF,MAAa,4BAA4B;CAKvC,OAAO;AACT;;;;;;;;;;;;;;AAeA,MAAa,gBAAgB,OAAO,iBAAkC,YAA2D;CAE7H,MAAM,cAAc,MAAwF;EAC5G,IAAI,CAAC,GAAG,OAAO,CAAC;EAChB,IAAI,aAAa,SAAS,OAAO,OAAO,YAAY,EAAE,QAAQ,CAAC;EAC/D,IAAI,OAAO,YAAY,GACrB,OAAO,OAAO,YACZ,MAAM,KAAK,IAAkC,UAAU,MAAM,KAAK,KAAK,CAAqB,CAC9F;EAEF,MAAM,UAAsD,CAAC;EAC7D,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAgD,CAAC,GAClF,IAAI,UAAU,KAAA,GAAW,QAAQ,QAAQ;EAE3C,OAAO;CACT;CACF,OAAO,QAAc,oBAAoB,GACvC;EACE,GAAG;EACH,QAAQ;EACR,SAAS;GAAE,gBAAgB;GAAoB,GAAG,WAAW,SAAS,OAAO;EAAE;EAC/E,MAAM,KAAK,UAAU,eAAe;CACtC,CACF;AAAE;AAGF,MAAa,qBAAqB,YAAqB;CAKrD,OAAO,iBAAiB;AAC1B;;;;;;;;;;;;AAaA,MAAa,cAAc,OAAO,SAAiB,YAA2D;CAE5G,OAAO,QAAc,kBAAkB,OAAO,GAC9C;EACE,GAAG;EACH,QAAQ;CAGV,CACF;AAAE;AAGF,MAAa,mBAAmB,YAAqB;CAKnD,OAAO,iBAAiB;AAC1B;;;;;AAMA,MAAa,YAAY,OAAO,SAAiB,YAAgE;CAE/G,OAAO,QAAmB,gBAAgB,OAAO,GACjD;EACE,GAAG;EACH,QAAQ;CAGV,CACF;AAAE;AAGF,MAAa,oBAAoB,YAAqB;CAKpD,OAAO,iBAAiB;AAC1B;;;;;AAMA,MAAa,aAAa,OAAO,SAC7B,YAAwB,YAAgE;CAExF,MAAM,cAAc,MAAwF;EAC5G,IAAI,CAAC,GAAG,OAAO,CAAC;EAChB,IAAI,aAAa,SAAS,OAAO,OAAO,YAAY,EAAE,QAAQ,CAAC;EAC/D,IAAI,OAAO,YAAY,GACrB,OAAO,OAAO,YACZ,MAAM,KAAK,IAAkC,UAAU,MAAM,KAAK,KAAK,CAAqB,CAC9F;EAEF,MAAM,UAAsD,CAAC;EAC7D,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAgD,CAAC,GAClF,IAAI,UAAU,KAAA,GAAW,QAAQ,QAAQ;EAE3C,OAAO;CACT;CACF,OAAO,QAAmB,iBAAiB,OAAO,GAChD;EACE,GAAG;EACH,QAAQ;EACR,SAAS;GAAE,gBAAgB;GAAoB,GAAG,WAAW,SAAS,OAAO;EAAE;EAC/E,MAAM,KAAK,UAAU,UAAU;CACjC,CACF;AAAE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
import { c as request } from "../client
|
|
2
|
+
import { er as LeaseCloseWrite, vn as LiveLeaseListRead } from "../chunks/index.js";
|
|
3
|
+
import { c as request } from "../chunks/client.js";
|
|
4
4
|
//#region src/api/admin-consumption/admin-consumption.d.ts
|
|
5
5
|
export declare const getListLiveLeasesUrl: () => string;
|
|
6
6
|
/**
|
|
@@ -9,6 +9,11 @@ export declare const getListLiveLeasesUrl: () => string;
|
|
|
9
9
|
* Read from the ledger rather than the Redis live set: this is a diagnostic and
|
|
10
10
|
* must show the truth even when the cache is cold, and it runs once when
|
|
11
11
|
* somebody opens a screen rather than on every read.
|
|
12
|
+
*
|
|
13
|
+
* Shares :func:`~app.services.entitlement.is_live` with the two seat counts.
|
|
14
|
+
* An earlier version of this route filtered on ``returned_at`` alone and so
|
|
15
|
+
* listed every lapsed-but-unreaped lease as live — which made the screen look
|
|
16
|
+
* exactly like a stuck reaper even when the reaper was fine.
|
|
12
17
|
* @summary List Live Leases
|
|
13
18
|
*/
|
|
14
19
|
export declare const listLiveLeases: (options?: Parameters<typeof request>[1]) => Promise<LiveLeaseListRead>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { r as request } from "../client
|
|
2
|
+
import { r as request } from "../chunks/client.js";
|
|
3
3
|
//#region src/api/admin-consumption/admin-consumption.ts
|
|
4
4
|
const getListLiveLeasesUrl = () => {
|
|
5
5
|
return `/admin/consumption/live`;
|
|
@@ -10,6 +10,11 @@ const getListLiveLeasesUrl = () => {
|
|
|
10
10
|
* Read from the ledger rather than the Redis live set: this is a diagnostic and
|
|
11
11
|
* must show the truth even when the cache is cold, and it runs once when
|
|
12
12
|
* somebody opens a screen rather than on every read.
|
|
13
|
+
*
|
|
14
|
+
* Shares :func:`~app.services.entitlement.is_live` with the two seat counts.
|
|
15
|
+
* An earlier version of this route filtered on ``returned_at`` alone and so
|
|
16
|
+
* listed every lapsed-but-unreaped lease as live — which made the screen look
|
|
17
|
+
* exactly like a stuck reaper even when the reaper was fine.
|
|
13
18
|
* @summary List Live Leases
|
|
14
19
|
*/
|
|
15
20
|
const listLiveLeases = async (options) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-consumption.js","names":[],"sources":["../../src/api/admin-consumption/admin-consumption.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.
|
|
1
|
+
{"version":3,"file":"admin-consumption.js","names":[],"sources":["../../src/api/admin-consumption/admin-consumption.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.5.0\n */\nimport type {\n LeaseCloseWrite,\n LiveLeaseListRead\n} from '../../models';\n\nimport { request } from '../../client';\n\nexport const getListLiveLeasesUrl = () => {\n\n\n\n\n return `/admin/consumption/live`\n}\n\n/**\n * What is open right now, within the caller's tenant scope.\n *\n * Read from the ledger rather than the Redis live set: this is a diagnostic and\n * must show the truth even when the cache is cold, and it runs once when\n * somebody opens a screen rather than on every read.\n *\n * Shares :func:`~app.services.entitlement.is_live` with the two seat counts.\n * An earlier version of this route filtered on ``returned_at`` alone and so\n * listed every lapsed-but-unreaped lease as live — which made the screen look\n * exactly like a stuck reaper even when the reaper was fine.\n * @summary List Live Leases\n */\nexport const listLiveLeases = async ( options?: Parameters<typeof request>[1]): Promise<LiveLeaseListRead> => {\n\n return request<LiveLeaseListRead>(getListLiveLeasesUrl(),\n {\n ...options,\n method: 'GET'\n\n\n }\n);}\n\n\nexport const getForceCloseLeaseUrl = (eventId: number,) => {\n\n\n\n\n return `/admin/consumption/${eventId}`\n}\n\n/**\n * Force-close somebody else's lease. The legacy's ``FermeSessionAdherent``.\n *\n * Audited, which the legacy's was not: a button that ends a stranger's reading\n * session and leaves no trace is indistinguishable from abuse of the same\n * button. Tenant-scoped like every staff action, so a lease outside the\n * caller's scope is ``404`` rather than ``403``.\n * @summary Force Close Lease\n */\nexport const forceCloseLease = async (eventId: number,\n leaseCloseWrite: LeaseCloseWrite, options?: Parameters<typeof request>[1]): Promise<void> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nreturn request<void>(getForceCloseLeaseUrl(eventId),\n {\n ...options,\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(leaseCloseWrite)\n }\n);}\n\n\n"],"mappings":";;;AAcA,MAAa,6BAA6B;CAKxC,OAAO;AACT;;;;;;;;;;;;;;AAeA,MAAa,iBAAiB,OAAQ,YAAwE;CAE5G,OAAO,QAA2B,qBAAqB,GACvD;EACE,GAAG;EACH,QAAQ;CAGV,CACF;AAAE;AAGF,MAAa,yBAAyB,YAAqB;CAKzD,OAAO,sBAAsB;AAC/B;;;;;;;;;;AAWA,MAAa,kBAAkB,OAAO,SAClC,iBAAkC,YAA2D;CAE7F,MAAM,cAAc,MAAwF;EAC5G,IAAI,CAAC,GAAG,OAAO,CAAC;EAChB,IAAI,aAAa,SAAS,OAAO,OAAO,YAAY,EAAE,QAAQ,CAAC;EAC/D,IAAI,OAAO,YAAY,GACrB,OAAO,OAAO,YACZ,MAAM,KAAK,IAAkC,UAAU,MAAM,KAAK,KAAK,CAAqB,CAC9F;EAEF,MAAM,UAAsD,CAAC;EAC7D,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAgD,CAAC,GAClF,IAAI,UAAU,KAAA,GAAW,QAAQ,QAAQ;EAE3C,OAAO;CACT;CACF,OAAO,QAAc,sBAAsB,OAAO,GAChD;EACE,GAAG;EACH,QAAQ;EACR,SAAS;GAAE,gBAAgB;GAAoB,GAAG,WAAW,SAAS,OAAO;EAAE;EAC/E,MAAM,KAAK,UAAU,eAAe;CACtC,CACF;AAAE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
import { c as request } from "../client
|
|
2
|
+
import { V as StaffLicenseRead, it as ReadPatronLicenseParams } from "../chunks/index.js";
|
|
3
|
+
import { c as request } from "../chunks/client.js";
|
|
4
4
|
//#region src/api/admin-licenses/admin-licenses.d.ts
|
|
5
5
|
export declare const getReadPatronLicenseUrl: (params: ReadPatronLicenseParams) => string;
|
|
6
6
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-licenses.js","names":[],"sources":["../../src/api/admin-licenses/admin-licenses.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.
|
|
1
|
+
{"version":3,"file":"admin-licenses.js","names":[],"sources":["../../src/api/admin-licenses/admin-licenses.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.5.0\n */\nimport type {\n ReadPatronLicenseParams,\n StaffLicenseRead\n} from '../../models';\n\nimport { request } from '../../client';\n\nexport const getReadPatronLicenseUrl = (params: ReadPatronLicenseParams,) => {\n const normalizedParams = new URLSearchParams();\n\n Object.entries(params || {}).forEach(([key, value]) => {\n\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : String(value))\n }\n });\n\n const stringifiedParams = normalizedParams.toString();\n\n return stringifiedParams.length > 0 ? `/admin/nextory-licenses?${stringifiedParams}` : `/admin/nextory-licenses`\n}\n\n/**\n * Report one account's licence state. Never allocates, never repairs.\n *\n * Scoped like every other staff read: an agent who cannot see the account gets\n * ``404``, the same answer as for an address nobody holds, so the endpoint\n * cannot be used to test whether a member exists elsewhere.\n *\n * ``partner_active`` is ``None`` when the partner could not be reached. That is\n * deliberately distinct from ``False`` — \"we could not ask\" and \"they said the\n * subscription is closed\" lead a support agent to different actions, and\n * collapsing them is how a working account gets re-provisioned.\n * @summary Read Patron License\n */\nexport const readPatronLicense = async (params: ReadPatronLicenseParams, options?: Parameters<typeof request>[1]): Promise<StaffLicenseRead> => {\n\n return request<StaffLicenseRead>(getReadPatronLicenseUrl(params),\n {\n ...options,\n method: 'GET'\n\n\n }\n);}\n\n\n"],"mappings":";;;AAcA,MAAa,2BAA2B,WAAqC;CAC3E,MAAM,mBAAmB,IAAI,gBAAgB;CAE7C,OAAO,QAAQ,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;EAErD,IAAI,UAAU,KAAA,GACZ,iBAAiB,OAAO,KAAK,UAAU,OAAO,SAAS,OAAO,KAAK,CAAC;CAExE,CAAC;CAED,MAAM,oBAAoB,iBAAiB,SAAS;CAEpD,OAAO,kBAAkB,SAAS,IAAI,2BAA2B,sBAAsB;AACzF;;;;;;;;;;;;;;AAeA,MAAa,oBAAoB,OAAO,QAAiC,YAAuE;CAE9I,OAAO,QAA0B,wBAAwB,MAAM,GAC/D;EACE,GAAG;EACH,QAAQ;CAGV,CACF;AAAE"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
import { c as request } from "../client
|
|
2
|
+
import { Dn as ListPatronsParams, Gt as PatronUpdateWrite, Jt as PatronDetailRead, Kt as PatronPage } from "../chunks/index.js";
|
|
3
|
+
import { c as request } from "../chunks/client.js";
|
|
4
4
|
//#region src/api/admin-patrons/admin-patrons.d.ts
|
|
5
5
|
export declare const getListPatronsUrl: (params?: ListPatronsParams) => string;
|
|
6
6
|
/**
|
|
7
7
|
* Patrons of the libraries this caller administers.
|
|
8
8
|
*
|
|
9
|
-
* ``q`` matches login, name and email
|
|
9
|
+
* ``q`` matches login, name and email as a literal case-insensitive substring.
|
|
10
10
|
* Deliberately not a full-text search: an operator looking somebody up has a
|
|
11
11
|
* surname or a card number, and ranking would only make the exact match harder
|
|
12
12
|
* to find.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { r as request } from "../client
|
|
2
|
+
import { r as request } from "../chunks/client.js";
|
|
3
3
|
//#region src/api/admin-patrons/admin-patrons.ts
|
|
4
4
|
const getListPatronsUrl = (params) => {
|
|
5
5
|
const normalizedParams = new URLSearchParams();
|
|
@@ -12,7 +12,7 @@ const getListPatronsUrl = (params) => {
|
|
|
12
12
|
/**
|
|
13
13
|
* Patrons of the libraries this caller administers.
|
|
14
14
|
*
|
|
15
|
-
* ``q`` matches login, name and email
|
|
15
|
+
* ``q`` matches login, name and email as a literal case-insensitive substring.
|
|
16
16
|
* Deliberately not a full-text search: an operator looking somebody up has a
|
|
17
17
|
* surname or a card number, and ranking would only make the exact match harder
|
|
18
18
|
* to find.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-patrons.js","names":[],"sources":["../../src/api/admin-patrons/admin-patrons.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.
|
|
1
|
+
{"version":3,"file":"admin-patrons.js","names":[],"sources":["../../src/api/admin-patrons/admin-patrons.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.5.0\n */\nimport type {\n ListPatronsParams,\n PatronDetailRead,\n PatronPage,\n PatronUpdateWrite\n} from '../../models';\n\nimport { request } from '../../client';\n\nexport const getListPatronsUrl = (params?: ListPatronsParams,) => {\n const normalizedParams = new URLSearchParams();\n\n Object.entries(params || {}).forEach(([key, value]) => {\n\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : String(value))\n }\n });\n\n const stringifiedParams = normalizedParams.toString();\n\n return stringifiedParams.length > 0 ? `/admin/patrons?${stringifiedParams}` : `/admin/patrons`\n}\n\n/**\n * Patrons of the libraries this caller administers.\n *\n * ``q`` matches login, name and email as a literal case-insensitive substring.\n * Deliberately not a full-text search: an operator looking somebody up has a\n * surname or a card number, and ranking would only make the exact match harder\n * to find.\n * @summary List Patrons\n */\nexport const listPatrons = async (params?: ListPatronsParams, options?: Parameters<typeof request>[1]): Promise<PatronPage> => {\n\n return request<PatronPage>(getListPatronsUrl(params),\n {\n ...options,\n method: 'GET'\n\n\n }\n);}\n\n\nexport const getReadPatronUrl = (patronId: number,) => {\n\n\n\n\n return `/admin/patrons/${patronId}`\n}\n\n/**\n * One patron, including the email the listing withholds.\n * @summary Read Patron\n */\nexport const readPatron = async (patronId: number, options?: Parameters<typeof request>[1]): Promise<PatronDetailRead> => {\n\n return request<PatronDetailRead>(getReadPatronUrl(patronId),\n {\n ...options,\n method: 'GET'\n\n\n }\n);}\n\n\nexport const getUpdatePatronUrl = (patronId: number,) => {\n\n\n\n\n return `/admin/patrons/${patronId}`\n}\n\n/**\n * Change what staff may change about a patron.\n *\n * Audited, because these are the changes somebody may have to account for:\n * suspending an account, raising an access level, extending a subscription past\n * what was paid for. The legacy records none of them.\n *\n * Nothing here can move a patron between tenants — see\n * :class:`~app.datamodels.admin.patrons.PatronUpdateWrite`.\n * @summary Update Patron\n */\nexport const updatePatron = async (patronId: number,\n patronUpdateWrite: PatronUpdateWrite, options?: Parameters<typeof request>[1]): Promise<PatronDetailRead> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nreturn request<PatronDetailRead>(getUpdatePatronUrl(patronId),\n {\n ...options,\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(patronUpdateWrite)\n }\n);}\n\n\n"],"mappings":";;;AAgBA,MAAa,qBAAqB,WAAgC;CAChE,MAAM,mBAAmB,IAAI,gBAAgB;CAE7C,OAAO,QAAQ,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;EAErD,IAAI,UAAU,KAAA,GACZ,iBAAiB,OAAO,KAAK,UAAU,OAAO,SAAS,OAAO,KAAK,CAAC;CAExE,CAAC;CAED,MAAM,oBAAoB,iBAAiB,SAAS;CAEpD,OAAO,kBAAkB,SAAS,IAAI,kBAAkB,sBAAsB;AAChF;;;;;;;;;;AAWA,MAAa,cAAc,OAAO,QAA4B,YAAiE;CAE7H,OAAO,QAAoB,kBAAkB,MAAM,GACnD;EACE,GAAG;EACH,QAAQ;CAGV,CACF;AAAE;AAGF,MAAa,oBAAoB,aAAsB;CAKrD,OAAO,kBAAkB;AAC3B;;;;;AAMA,MAAa,aAAa,OAAO,UAAkB,YAAuE;CAExH,OAAO,QAA0B,iBAAiB,QAAQ,GAC1D;EACE,GAAG;EACH,QAAQ;CAGV,CACF;AAAE;AAGF,MAAa,sBAAsB,aAAsB;CAKvD,OAAO,kBAAkB;AAC3B;;;;;;;;;;;;AAaA,MAAa,eAAe,OAAO,UAC/B,mBAAsC,YAAuE;CAE7G,MAAM,cAAc,MAAwF;EAC5G,IAAI,CAAC,GAAG,OAAO,CAAC;EAChB,IAAI,aAAa,SAAS,OAAO,OAAO,YAAY,EAAE,QAAQ,CAAC;EAC/D,IAAI,OAAO,YAAY,GACrB,OAAO,OAAO,YACZ,MAAM,KAAK,IAAkC,UAAU,MAAM,KAAK,KAAK,CAAqB,CAC9F;EAEF,MAAM,UAAsD,CAAC;EAC7D,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAgD,CAAC,GAClF,IAAI,UAAU,KAAA,GAAW,QAAQ,QAAQ;EAE3C,OAAO;CACT;CACF,OAAO,QAA0B,mBAAmB,QAAQ,GAC1D;EACE,GAAG;EACH,QAAQ;EACR,SAAS;GAAE,gBAAgB;GAAoB,GAAG,WAAW,SAAS,OAAO;EAAE;EAC/E,MAAM,KAAK,UAAU,iBAAiB;CACxC,CACF;AAAE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
import { c as request } from "../client
|
|
2
|
+
import { $ as ReviewModerationRead, Q as ReviewPage, Sn as ListReviewsParams, cn as ModerationWrite } from "../chunks/index.js";
|
|
3
|
+
import { c as request } from "../chunks/client.js";
|
|
4
4
|
//#region src/api/admin-reviews/admin-reviews.d.ts
|
|
5
5
|
export declare const getListReviewsUrl: (params?: ListReviewsParams) => string;
|
|
6
6
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-reviews.js","names":[],"sources":["../../src/api/admin-reviews/admin-reviews.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.
|
|
1
|
+
{"version":3,"file":"admin-reviews.js","names":[],"sources":["../../src/api/admin-reviews/admin-reviews.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.5.0\n */\nimport type {\n ListReviewsParams,\n ModerationWrite,\n ReviewModerationRead,\n ReviewPage\n} from '../../models';\n\nimport { request } from '../../client';\n\nexport const getListReviewsUrl = (params?: ListReviewsParams,) => {\n const normalizedParams = new URLSearchParams();\n\n Object.entries(params || {}).forEach(([key, value]) => {\n\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : String(value))\n }\n });\n\n const stringifiedParams = normalizedParams.toString();\n\n return stringifiedParams.length > 0 ? `/admin/reviews?${stringifiedParams}` : `/admin/reviews`\n}\n\n/**\n * Reviews awaiting a decision, oldest first.\n *\n * Oldest first on purpose: a moderation queue sorted newest-first starves its\n * tail, and the review that has waited longest is the one whose author is\n * wondering what happened.\n * @summary List Reviews\n */\nexport const listReviews = async (params?: ListReviewsParams, options?: Parameters<typeof request>[1]): Promise<ReviewPage> => {\n\n return request<ReviewPage>(getListReviewsUrl(params),\n {\n ...options,\n method: 'GET'\n\n\n }\n);}\n\n\nexport const getModerateReviewUrl = (reviewId: number,) => {\n\n\n\n\n return `/admin/reviews/${reviewId}/moderation`\n}\n\n/**\n * Publish or reject one review.\n *\n * ``PUT`` on a moderation sub-resource rather than ``POST /approve`` and\n * ``POST /reject``: the outcome is a state the review is *in*, not two different\n * events, and a repeated decision must be harmless.\n *\n * Rejecting requires a reason. The author is owed one, and the moderator is the\n * only person who has it — the audit row is where it survives after the queue\n * has moved on.\n * @summary Moderate Review\n */\nexport const moderateReview = async (reviewId: number,\n moderationWrite: ModerationWrite, options?: Parameters<typeof request>[1]): Promise<ReviewModerationRead> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nreturn request<ReviewModerationRead>(getModerateReviewUrl(reviewId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(moderationWrite)\n }\n);}\n\n\n"],"mappings":";;;AAgBA,MAAa,qBAAqB,WAAgC;CAChE,MAAM,mBAAmB,IAAI,gBAAgB;CAE7C,OAAO,QAAQ,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;EAErD,IAAI,UAAU,KAAA,GACZ,iBAAiB,OAAO,KAAK,UAAU,OAAO,SAAS,OAAO,KAAK,CAAC;CAExE,CAAC;CAED,MAAM,oBAAoB,iBAAiB,SAAS;CAEpD,OAAO,kBAAkB,SAAS,IAAI,kBAAkB,sBAAsB;AAChF;;;;;;;;;AAUA,MAAa,cAAc,OAAO,QAA4B,YAAiE;CAE7H,OAAO,QAAoB,kBAAkB,MAAM,GACnD;EACE,GAAG;EACH,QAAQ;CAGV,CACF;AAAE;AAGF,MAAa,wBAAwB,aAAsB;CAKzD,OAAO,kBAAkB,SAAS;AACpC;;;;;;;;;;;;;AAcA,MAAa,iBAAiB,OAAO,UACjC,iBAAkC,YAA2E;CAE7G,MAAM,cAAc,MAAwF;EAC5G,IAAI,CAAC,GAAG,OAAO,CAAC;EAChB,IAAI,aAAa,SAAS,OAAO,OAAO,YAAY,EAAE,QAAQ,CAAC;EAC/D,IAAI,OAAO,YAAY,GACrB,OAAO,OAAO,YACZ,MAAM,KAAK,IAAkC,UAAU,MAAM,KAAK,KAAK,CAAqB,CAC9F;EAEF,MAAM,UAAsD,CAAC;EAC7D,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAgD,CAAC,GAClF,IAAI,UAAU,KAAA,GAAW,QAAQ,QAAQ;EAE3C,OAAO;CACT;CACF,OAAO,QAA8B,qBAAqB,QAAQ,GAChE;EACE,GAAG;EACH,QAAQ;EACR,SAAS;GAAE,gBAAgB;GAAoB,GAAG,WAAW,SAAS,OAAO;EAAE;EAC/E,MAAM,KAAK,UAAU,eAAe;CACtC,CACF;AAAE"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
import { c as request } from "../client
|
|
2
|
+
import { Ct as ProductGrantWrite, wt as ProductGrantListRead } from "../chunks/index.js";
|
|
3
|
+
import { c as request } from "../chunks/client.js";
|
|
4
4
|
//#region src/api/admin-roles/admin-roles.d.ts
|
|
5
5
|
export declare const getListGrantsUrl: (userId: number) => string;
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* This account's grants within the caller's organisation scope.
|
|
8
8
|
*
|
|
9
9
|
* Readable by SUPPORT as well as ADMIN: knowing what somebody is, is part of
|
|
10
10
|
* helping them. Changing it is not.
|
package/dist/api/admin-roles.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
|
|
2
|
-
import { r as request } from "../client
|
|
2
|
+
import { r as request } from "../chunks/client.js";
|
|
3
3
|
//#region src/api/admin-roles/admin-roles.ts
|
|
4
4
|
const getListGrantsUrl = (userId) => {
|
|
5
5
|
return `/admin/users/${userId}/product-roles`;
|
|
6
6
|
};
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* This account's grants within the caller's organisation scope.
|
|
9
9
|
*
|
|
10
10
|
* Readable by SUPPORT as well as ADMIN: knowing what somebody is, is part of
|
|
11
11
|
* helping them. Changing it is not.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-roles.js","names":[],"sources":["../../src/api/admin-roles/admin-roles.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.
|
|
1
|
+
{"version":3,"file":"admin-roles.js","names":[],"sources":["../../src/api/admin-roles/admin-roles.ts"],"sourcesContent":["/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Mozaik backend\n * Four products behind one API — Biblio, Médiathèques, the partner catalogues (Nextory and YouScribe) and Prof Express. Authentication is Keycloak SSO only, once, for all of them: see the **auth** section below for the browser flow and the three failure modes.\n * OpenAPI spec version: 0.5.0\n */\nimport type {\n ProductGrantListRead,\n ProductGrantWrite\n} from '../../models';\n\nimport { request } from '../../client';\n\nexport const getListGrantsUrl = (userId: number,) => {\n\n\n\n\n return `/admin/users/${userId}/product-roles`\n}\n\n/**\n * This account's grants within the caller's organisation scope.\n *\n * Readable by SUPPORT as well as ADMIN: knowing what somebody is, is part of\n * helping them. Changing it is not.\n * @summary List Grants\n */\nexport const listGrants = async (userId: number, options?: Parameters<typeof request>[1]): Promise<ProductGrantListRead> => {\n\n return request<ProductGrantListRead>(getListGrantsUrl(userId),\n {\n ...options,\n method: 'GET'\n\n\n }\n);}\n\n\nexport const getReplaceGrantsUrl = (userId: number,) => {\n\n\n\n\n return `/admin/users/${userId}/product-roles`\n}\n\n/**\n * Replace this account's roles for one product at one organisation.\n *\n * ``PUT`` because it is idempotent and the body is the whole desired state for\n * that ``(tenant, product)`` slice — sending it twice leaves the same grants.\n *\n * Two scope checks, and both are needed. The *subject* must be an account the\n * operator reaches, and the ``tenantId`` being granted at must be one they\n * reach too: without the second, an operator could grant a remit at an\n * organisation they have no authority over, which is how a scoped\n * administrator becomes an unscoped one.\n *\n * ``422`` for a role the product does not recognise —\n * :data:`~app.models.enums.PRODUCT_ROLES` decides, so ``student`` for biblio is\n * refused rather than stored and puzzled over later.\n * @summary Replace Grants\n */\nexport const replaceGrants = async (userId: number,\n productGrantWrite: ProductGrantWrite, options?: Parameters<typeof request>[1]): Promise<ProductGrantListRead> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nreturn request<ProductGrantListRead>(getReplaceGrantsUrl(userId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(productGrantWrite)\n }\n);}\n\n\n"],"mappings":";;;AAcA,MAAa,oBAAoB,WAAoB;CAKnD,OAAO,gBAAgB,OAAO;AAChC;;;;;;;;AASA,MAAa,aAAa,OAAO,QAAgB,YAA2E;CAE1H,OAAO,QAA8B,iBAAiB,MAAM,GAC5D;EACE,GAAG;EACH,QAAQ;CAGV,CACF;AAAE;AAGF,MAAa,uBAAuB,WAAoB;CAKtD,OAAO,gBAAgB,OAAO;AAChC;;;;;;;;;;;;;;;;;;AAmBA,MAAa,gBAAgB,OAAO,QAChC,mBAAsC,YAA2E;CAEjH,MAAM,cAAc,MAAwF;EAC5G,IAAI,CAAC,GAAG,OAAO,CAAC;EAChB,IAAI,aAAa,SAAS,OAAO,OAAO,YAAY,EAAE,QAAQ,CAAC;EAC/D,IAAI,OAAO,YAAY,GACrB,OAAO,OAAO,YACZ,MAAM,KAAK,IAAkC,UAAU,MAAM,KAAK,KAAK,CAAqB,CAC9F;EAEF,MAAM,UAAsD,CAAC;EAC7D,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAgD,CAAC,GAClF,IAAI,UAAU,KAAA,GAAW,QAAQ,QAAQ;EAE3C,OAAO;CACT;CACF,OAAO,QAA8B,oBAAoB,MAAM,GAC7D;EACE,GAAG;EACH,QAAQ;EACR,SAAS;GAAE,gBAAgB;GAAoB,GAAG,WAAW,SAAS,OAAO;EAAE;EAC/E,MAAM,KAAK,UAAU,iBAAiB;CACxC,CACF;AAAE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
import { c as request } from "../client
|
|
2
|
+
import { P as SupportSessionRead, ar as ImpersonationWrite, ii as DemoUserRead, ri as DemoUserWrite } from "../chunks/index.js";
|
|
3
|
+
import { c as request } from "../chunks/client.js";
|
|
4
4
|
//#region src/api/admin-support/admin-support.d.ts
|
|
5
5
|
export declare const getCreateDemoUserUrl: () => string;
|
|
6
6
|
/**
|