rastack 0.0.52 → 0.0.54
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/CHANGELOG.md +4 -0
- package/auth/index.ts +22 -9
- package/auth/provider.ts +486 -0
- package/dist/admin.js +13 -13
- package/dist/auth/cognito.d.ts +169 -0
- package/dist/auth/cognito.js +296 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +18 -0
- package/dist/entity-generation/get-method.js +4 -4
- package/dist/entity-generation/imports.js +1 -1
- package/dist/wasm/rastack_wasm.d.ts +2 -2
- package/dist/wasm/rastack_wasm.js +6 -6
- package/dist/wasm/rastack_wasm_bg.wasm +0 -0
- package/dist/wasm/rastack_wasm_bg.wasm.d.ts +2 -2
- package/package.json +1 -1
- package/src/auth/cognito.ts +410 -0
- package/src/auth/index.ts +2 -0
- package/src/entity-generation/get-method.ts +4 -4
- package/src/entity-generation/imports.ts +1 -1
- package/test/cognito.spec.ts +281 -0
- package/wasm/rastack_wasm.d.ts +2 -2
- package/wasm/rastack_wasm.js +6 -6
- package/wasm/rastack_wasm_bg.wasm +0 -0
- package/wasm/rastack_wasm_bg.wasm.d.ts +2 -2
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `rastack/auth` — the framework-free Cognito auth core.
|
|
3
|
+
*
|
|
4
|
+
* React API Stack verifies Cognito RS256 JWTs on the server (`rastack-server
|
|
5
|
+
* --jwks --issuer --audience`) and scopes row-level security by the token's
|
|
6
|
+
* `sub` / `cognito:groups`. This module is the *client* half: the pure,
|
|
7
|
+
* dependency-free logic for the standard browser sign-in flow — **Cognito
|
|
8
|
+
* Hosted UI, OAuth 2.0 Authorization Code + PKCE** — that produces exactly the
|
|
9
|
+
* `identity` (`sub`), `groups`, and bearer `getToken` the `<RAStackProvider>`
|
|
10
|
+
* consumes.
|
|
11
|
+
*
|
|
12
|
+
* Everything here is a pure function (no React, no `window`, no network): URL
|
|
13
|
+
* builders, PKCE (S256 over Web Crypto), the `/oauth2/token` request body,
|
|
14
|
+
* JWT decoding, expiry checks, redirect parsing, and session shaping. The React
|
|
15
|
+
* layer (`tools/auth/provider.tsx`) is a thin wrapper over these; the tests
|
|
16
|
+
* (`tools/test/auth.spec.ts`) drive them directly.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** Static configuration of a Cognito Hosted UI app client (public SPA client). */
|
|
20
|
+
export interface CognitoAuthConfig {
|
|
21
|
+
/**
|
|
22
|
+
* The Hosted UI domain, without a scheme — either the Cognito prefix domain
|
|
23
|
+
* (`myapp.auth.us-east-1.amazoncognito.com`) or a custom domain
|
|
24
|
+
* (`auth.example.com`).
|
|
25
|
+
*/
|
|
26
|
+
domain: string;
|
|
27
|
+
/** The app client id (a public SPA client, *no* client secret). */
|
|
28
|
+
clientId: string;
|
|
29
|
+
/** An allowed callback URL — where Cognito redirects back after sign-in. */
|
|
30
|
+
redirectUri: string;
|
|
31
|
+
/**
|
|
32
|
+
* An allowed sign-out URL — where Cognito redirects after sign-out. Defaults
|
|
33
|
+
* to `redirectUri`.
|
|
34
|
+
*/
|
|
35
|
+
logoutUri?: string;
|
|
36
|
+
/** OAuth scopes to request. Defaults to `["openid", "email", "profile"]`. */
|
|
37
|
+
scopes?: string[];
|
|
38
|
+
/** AWS region — used only to derive the default issuer for reference. */
|
|
39
|
+
region?: string;
|
|
40
|
+
/** The Cognito user pool id — used only to derive the default issuer. */
|
|
41
|
+
userPoolId?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** The claims we read off a decoded Cognito ID/access token. */
|
|
45
|
+
export interface CognitoClaims {
|
|
46
|
+
sub: string;
|
|
47
|
+
exp?: number;
|
|
48
|
+
iat?: number;
|
|
49
|
+
iss?: string;
|
|
50
|
+
aud?: string;
|
|
51
|
+
token_use?: string;
|
|
52
|
+
email?: string;
|
|
53
|
+
email_verified?: boolean;
|
|
54
|
+
"cognito:username"?: string;
|
|
55
|
+
"cognito:groups"?: string[];
|
|
56
|
+
[claim: string]: unknown;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** The signed-in user, projected from the ID token's claims. */
|
|
60
|
+
export interface CognitoUser {
|
|
61
|
+
/** The Cognito `sub` — the stable identity the framework stamps rows with. */
|
|
62
|
+
sub: string;
|
|
63
|
+
email?: string;
|
|
64
|
+
username?: string;
|
|
65
|
+
/** `cognito:groups` — the verified group claims (empty array if none). */
|
|
66
|
+
groups: string[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** A live session: the tokens plus the decoded user and its expiry. */
|
|
70
|
+
export interface CognitoSession {
|
|
71
|
+
idToken: string;
|
|
72
|
+
accessToken: string;
|
|
73
|
+
refreshToken?: string;
|
|
74
|
+
/** Absolute expiry, epoch milliseconds. */
|
|
75
|
+
expiresAt: number;
|
|
76
|
+
user: CognitoUser;
|
|
77
|
+
claims: CognitoClaims;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** The raw shape of a Cognito `/oauth2/token` JSON response. */
|
|
81
|
+
export interface CognitoTokenResponse {
|
|
82
|
+
id_token: string;
|
|
83
|
+
access_token: string;
|
|
84
|
+
refresh_token?: string;
|
|
85
|
+
expires_in?: number;
|
|
86
|
+
token_type?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** What `parseRedirect` recovers from a callback URL's query string. */
|
|
90
|
+
export interface RedirectParams {
|
|
91
|
+
code?: string;
|
|
92
|
+
state?: string;
|
|
93
|
+
error?: string;
|
|
94
|
+
errorDescription?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const DEFAULT_SCOPES = ["openid", "email", "profile"];
|
|
98
|
+
|
|
99
|
+
/** Strip any scheme/trailing slash a caller may have included in `domain`. */
|
|
100
|
+
function normalizeDomain(domain: string): string {
|
|
101
|
+
return domain.replace(/^https?:\/\//, "").replace(/\/+$/, "");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** The Hosted UI origin, e.g. `https://myapp.auth.us-east-1.amazoncognito.com`. */
|
|
105
|
+
export function hostedUiOrigin(config: CognitoAuthConfig): string {
|
|
106
|
+
return `https://${normalizeDomain(config.domain)}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** The issuer a Cognito user pool signs tokens with (for server verification). */
|
|
110
|
+
export function issuerUrl(config: CognitoAuthConfig): string | undefined {
|
|
111
|
+
if (!config.region || !config.userPoolId) return undefined;
|
|
112
|
+
return `https://cognito-idp.${config.region}.amazonaws.com/${config.userPoolId}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Build the Hosted UI `/oauth2/authorize` URL to redirect the browser to. */
|
|
116
|
+
export function authorizeUrl(
|
|
117
|
+
config: CognitoAuthConfig,
|
|
118
|
+
params: { state: string; codeChallenge: string },
|
|
119
|
+
): string {
|
|
120
|
+
const query = new URLSearchParams({
|
|
121
|
+
response_type: "code",
|
|
122
|
+
client_id: config.clientId,
|
|
123
|
+
redirect_uri: config.redirectUri,
|
|
124
|
+
scope: (config.scopes ?? DEFAULT_SCOPES).join(" "),
|
|
125
|
+
state: params.state,
|
|
126
|
+
code_challenge: params.codeChallenge,
|
|
127
|
+
code_challenge_method: "S256",
|
|
128
|
+
});
|
|
129
|
+
return `${hostedUiOrigin(config)}/oauth2/authorize?${query.toString()}`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Build the Hosted UI `/logout` URL that clears the Cognito session cookie. */
|
|
133
|
+
export function logoutUrl(config: CognitoAuthConfig): string {
|
|
134
|
+
const query = new URLSearchParams({
|
|
135
|
+
client_id: config.clientId,
|
|
136
|
+
logout_uri: config.logoutUri ?? config.redirectUri,
|
|
137
|
+
});
|
|
138
|
+
return `${hostedUiOrigin(config)}/logout?${query.toString()}`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** The token endpoint the authorization code is exchanged at. */
|
|
142
|
+
export function tokenEndpoint(config: CognitoAuthConfig): string {
|
|
143
|
+
return `${hostedUiOrigin(config)}/oauth2/token`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The `application/x-www-form-urlencoded` body for a `/oauth2/token` call —
|
|
148
|
+
* either exchanging an authorization `code` or a `refresh_token` grant.
|
|
149
|
+
*/
|
|
150
|
+
export function tokenRequestBody(
|
|
151
|
+
config: CognitoAuthConfig,
|
|
152
|
+
grant:
|
|
153
|
+
| { grantType: "authorization_code"; code: string; codeVerifier: string }
|
|
154
|
+
| { grantType: "refresh_token"; refreshToken: string },
|
|
155
|
+
): string {
|
|
156
|
+
const body = new URLSearchParams({
|
|
157
|
+
client_id: config.clientId,
|
|
158
|
+
});
|
|
159
|
+
if (grant.grantType === "authorization_code") {
|
|
160
|
+
body.set("grant_type", "authorization_code");
|
|
161
|
+
body.set("code", grant.code);
|
|
162
|
+
body.set("redirect_uri", config.redirectUri);
|
|
163
|
+
body.set("code_verifier", grant.codeVerifier);
|
|
164
|
+
} else {
|
|
165
|
+
body.set("grant_type", "refresh_token");
|
|
166
|
+
body.set("refresh_token", grant.refreshToken);
|
|
167
|
+
}
|
|
168
|
+
return body.toString();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// -- base64url ---------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
/** Encode raw bytes as base64url (no padding). Browser + Node safe. */
|
|
174
|
+
export function base64UrlEncode(bytes: Uint8Array): string {
|
|
175
|
+
let base64: string;
|
|
176
|
+
if (typeof btoa === "function") {
|
|
177
|
+
let binary = "";
|
|
178
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
179
|
+
base64 = btoa(binary);
|
|
180
|
+
} else {
|
|
181
|
+
base64 = Buffer.from(bytes).toString("base64");
|
|
182
|
+
}
|
|
183
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Decode a base64url string to bytes. */
|
|
187
|
+
export function base64UrlDecodeToBytes(input: string): Uint8Array {
|
|
188
|
+
const base64 = input
|
|
189
|
+
.replace(/-/g, "+")
|
|
190
|
+
.replace(/_/g, "/")
|
|
191
|
+
.padEnd(Math.ceil(input.length / 4) * 4, "=");
|
|
192
|
+
if (typeof atob === "function") {
|
|
193
|
+
const binary = atob(base64);
|
|
194
|
+
const bytes = new Uint8Array(binary.length);
|
|
195
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
196
|
+
return bytes;
|
|
197
|
+
}
|
|
198
|
+
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Decode a base64url string to a UTF-8 string. */
|
|
202
|
+
export function base64UrlDecode(input: string): string {
|
|
203
|
+
const bytes = base64UrlDecodeToBytes(input);
|
|
204
|
+
if (typeof TextDecoder !== "undefined") {
|
|
205
|
+
return new TextDecoder().decode(bytes);
|
|
206
|
+
}
|
|
207
|
+
return Buffer.from(bytes).toString("utf-8");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** UTF-8 encode a string to bytes. */
|
|
211
|
+
function utf8Bytes(input: string): Uint8Array {
|
|
212
|
+
if (typeof TextEncoder !== "undefined") return new TextEncoder().encode(input);
|
|
213
|
+
return new Uint8Array(Buffer.from(input, "utf-8"));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// -- PKCE --------------------------------------------------------------------
|
|
217
|
+
|
|
218
|
+
function subtleCrypto(subtle?: SubtleCrypto): SubtleCrypto {
|
|
219
|
+
const s = subtle ?? (globalThis.crypto && globalThis.crypto.subtle);
|
|
220
|
+
if (!s) {
|
|
221
|
+
throw new Error(
|
|
222
|
+
"Web Crypto (crypto.subtle) is required for PKCE; pass a SubtleCrypto explicitly.",
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
return s;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** A cryptographically random PKCE `code_verifier` (43–128 chars, base64url). */
|
|
229
|
+
export function randomCodeVerifier(random?: Uint8Array): string {
|
|
230
|
+
let bytes = random;
|
|
231
|
+
if (!bytes) {
|
|
232
|
+
bytes = new Uint8Array(new ArrayBuffer(32));
|
|
233
|
+
if (globalThis.crypto?.getRandomValues) {
|
|
234
|
+
globalThis.crypto.getRandomValues(bytes as any);
|
|
235
|
+
} else {
|
|
236
|
+
throw new Error(
|
|
237
|
+
"crypto.getRandomValues is required to generate a code verifier.",
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return base64UrlEncode(bytes);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** The S256 `code_challenge` derived from a verifier (SHA-256 → base64url). */
|
|
245
|
+
export async function codeChallengeFromVerifier(
|
|
246
|
+
verifier: string,
|
|
247
|
+
subtle?: SubtleCrypto,
|
|
248
|
+
): Promise<string> {
|
|
249
|
+
const digest = await subtleCrypto(subtle).digest(
|
|
250
|
+
"SHA-256",
|
|
251
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
252
|
+
utf8Bytes(verifier) as any,
|
|
253
|
+
);
|
|
254
|
+
return base64UrlEncode(new Uint8Array(digest));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** Generate a fresh PKCE `{ verifier, challenge }` pair. */
|
|
258
|
+
export async function createPkcePair(
|
|
259
|
+
random?: Uint8Array,
|
|
260
|
+
subtle?: SubtleCrypto,
|
|
261
|
+
): Promise<{ verifier: string; challenge: string }> {
|
|
262
|
+
const verifier = randomCodeVerifier(random);
|
|
263
|
+
const challenge = await codeChallengeFromVerifier(verifier, subtle);
|
|
264
|
+
return { verifier, challenge };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** A random opaque `state` value to correlate the redirect (CSRF guard). */
|
|
268
|
+
export function randomState(random?: Uint8Array): string {
|
|
269
|
+
return randomCodeVerifier(random ?? undefined);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// -- JWT ---------------------------------------------------------------------
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Decode a JWT's payload **without verifying its signature** — the client only
|
|
276
|
+
* reads claims for UX; the server is the sole authority that *verifies* the
|
|
277
|
+
* token (RS256 against the pinned JWKS). Throws on a malformed token.
|
|
278
|
+
*/
|
|
279
|
+
export function decodeJwt<T = CognitoClaims>(token: string): T {
|
|
280
|
+
const parts = token.split(".");
|
|
281
|
+
if (parts.length < 2) throw new Error("Malformed JWT: expected 3 segments.");
|
|
282
|
+
try {
|
|
283
|
+
return JSON.parse(base64UrlDecode(parts[1])) as T;
|
|
284
|
+
} catch (error) {
|
|
285
|
+
throw new Error(`Malformed JWT payload: ${(error as Error).message}`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Project a decoded ID token's claims into the app-facing `CognitoUser`. */
|
|
290
|
+
export function userFromClaims(claims: CognitoClaims): CognitoUser {
|
|
291
|
+
const groups = claims["cognito:groups"];
|
|
292
|
+
return {
|
|
293
|
+
sub: claims.sub,
|
|
294
|
+
email: claims.email,
|
|
295
|
+
username: claims["cognito:username"] ?? claims.email ?? claims.sub,
|
|
296
|
+
groups: Array.isArray(groups) ? groups : [],
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** Build a `CognitoSession` from a token response, decoding the ID token. */
|
|
301
|
+
export function sessionFromTokens(
|
|
302
|
+
tokens: CognitoTokenResponse,
|
|
303
|
+
now: number = Date.now(),
|
|
304
|
+
): CognitoSession {
|
|
305
|
+
const claims = decodeJwt<CognitoClaims>(tokens.id_token);
|
|
306
|
+
// Prefer the token's own `exp`; fall back to `expires_in` from the response.
|
|
307
|
+
const expiresAt = claims.exp
|
|
308
|
+
? claims.exp * 1000
|
|
309
|
+
: now + (tokens.expires_in ?? 3600) * 1000;
|
|
310
|
+
return {
|
|
311
|
+
idToken: tokens.id_token,
|
|
312
|
+
accessToken: tokens.access_token,
|
|
313
|
+
refreshToken: tokens.refresh_token,
|
|
314
|
+
expiresAt,
|
|
315
|
+
user: userFromClaims(claims),
|
|
316
|
+
claims,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Whether a session is still usable — present and not within `skewMs` of its
|
|
322
|
+
* expiry (so callers refresh a little early rather than mid-request).
|
|
323
|
+
*/
|
|
324
|
+
export function isSessionValid(
|
|
325
|
+
session: CognitoSession | null | undefined,
|
|
326
|
+
now: number = Date.now(),
|
|
327
|
+
skewMs = 30_000,
|
|
328
|
+
): boolean {
|
|
329
|
+
return !!session && session.expiresAt - skewMs > now;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// -- Redirect parsing --------------------------------------------------------
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Parse the callback URL's query string into the OAuth params. Accepts a full
|
|
336
|
+
* URL, a bare search string (`?code=…`), or a `URLSearchParams`.
|
|
337
|
+
*/
|
|
338
|
+
export function parseRedirect(
|
|
339
|
+
input: string | URLSearchParams,
|
|
340
|
+
): RedirectParams {
|
|
341
|
+
let params: URLSearchParams;
|
|
342
|
+
if (input instanceof URLSearchParams) {
|
|
343
|
+
params = input;
|
|
344
|
+
} else {
|
|
345
|
+
const q = input.includes("?") ? input.slice(input.indexOf("?") + 1) : input;
|
|
346
|
+
params = new URLSearchParams(q);
|
|
347
|
+
}
|
|
348
|
+
return {
|
|
349
|
+
code: params.get("code") ?? undefined,
|
|
350
|
+
state: params.get("state") ?? undefined,
|
|
351
|
+
error: params.get("error") ?? undefined,
|
|
352
|
+
errorDescription: params.get("error_description") ?? undefined,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// -- Local (server-less) sessions -------------------------------------------
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Base64url-encode a JSON value — the building block of the unsigned tokens the
|
|
360
|
+
* local session mode mints.
|
|
361
|
+
*/
|
|
362
|
+
function encodeSegment(value: unknown): string {
|
|
363
|
+
return base64UrlEncode(utf8Bytes(JSON.stringify(value)));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Mint a **local, unsigned** session for server-less development.
|
|
368
|
+
* `<RAStackProvider mode="local">` runs the whole API in the browser with no
|
|
369
|
+
* identity provider to redirect to, so `mode: "local"` on the auth provider
|
|
370
|
+
* grants a simulated Cognito session on sign-in: a real-shaped
|
|
371
|
+
* (header.payload.signature) JWT carrying `sub` / `cognito:groups`, so
|
|
372
|
+
* `decodeJwt`, owner stamping, and the write-gating UI all behave exactly as
|
|
373
|
+
* they would against a real pool — the server-less dev shim.
|
|
374
|
+
* **Never trust these tokens on a server** — they carry a literal `"local"`
|
|
375
|
+
* signature; swap `mode` to `"hosted-ui"` for a deployed, Cognito-protected
|
|
376
|
+
* backend.
|
|
377
|
+
*/
|
|
378
|
+
export function localSession(
|
|
379
|
+
user: {
|
|
380
|
+
sub?: string;
|
|
381
|
+
email?: string;
|
|
382
|
+
username?: string;
|
|
383
|
+
groups?: string[];
|
|
384
|
+
} = {},
|
|
385
|
+
now: number = Date.now(),
|
|
386
|
+
ttlMs = 3600_000,
|
|
387
|
+
): CognitoSession {
|
|
388
|
+
const sub = user.sub ?? "local-dev";
|
|
389
|
+
const exp = Math.floor((now + ttlMs) / 1000);
|
|
390
|
+
const claims: CognitoClaims = {
|
|
391
|
+
sub,
|
|
392
|
+
email: user.email,
|
|
393
|
+
email_verified: true,
|
|
394
|
+
"cognito:username": user.username ?? user.email ?? sub,
|
|
395
|
+
"cognito:groups": user.groups ?? [],
|
|
396
|
+
token_use: "id",
|
|
397
|
+
iss: "rastack:local",
|
|
398
|
+
iat: Math.floor(now / 1000),
|
|
399
|
+
exp,
|
|
400
|
+
};
|
|
401
|
+
const header = { alg: "none", typ: "JWT", kid: "rastack-local" };
|
|
402
|
+
const token = `${encodeSegment(header)}.${encodeSegment(claims)}.local`;
|
|
403
|
+
return {
|
|
404
|
+
idToken: token,
|
|
405
|
+
accessToken: token,
|
|
406
|
+
expiresAt: exp * 1000,
|
|
407
|
+
user: userFromClaims(claims),
|
|
408
|
+
claims,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
@@ -36,7 +36,7 @@ export function generateGetAPIMethod(
|
|
|
36
36
|
export function use${operationIdUpper}(
|
|
37
37
|
options?: ListQueryOptions<${paramNames}, ${responseBody}>
|
|
38
38
|
) {
|
|
39
|
-
const {
|
|
39
|
+
const { isReady } = useCognitoAuth();
|
|
40
40
|
const pathParameters: (keyof ${paramNames})[] = [${pathParameters.map((item) => `'${item}'`).join(", ")}]
|
|
41
41
|
${pathParameterString.join("\n")}
|
|
42
42
|
|
|
@@ -44,7 +44,7 @@ export function generateGetAPIMethod(
|
|
|
44
44
|
${method}Url: \`${url}\`,
|
|
45
45
|
queryKey: ${modelCamel}QueriesKeys.${operationId},
|
|
46
46
|
pathParameters,
|
|
47
|
-
isAuthenticated,
|
|
47
|
+
isAuthenticated: isReady,
|
|
48
48
|
options,
|
|
49
49
|
});
|
|
50
50
|
}`,
|
|
@@ -59,7 +59,7 @@ export function generateGetAPIMethod(
|
|
|
59
59
|
export function use${operationIdUpper}(
|
|
60
60
|
options?: GetQueryOptions<${paramNames}>
|
|
61
61
|
) {
|
|
62
|
-
const {
|
|
62
|
+
const { isReady } = useCognitoAuth();
|
|
63
63
|
const pathParameters: string[] = [${pathParameters.map((item) => `'${item}'`).join(", ")}]
|
|
64
64
|
${pathParameterString.join("\n")}
|
|
65
65
|
const requiredParams: string[] = [${requiredParameters.map((item) => `'${item}'`).join(", ")}]
|
|
@@ -70,7 +70,7 @@ export function use${operationIdUpper}(
|
|
|
70
70
|
pathParameters,
|
|
71
71
|
//@ts-ignore
|
|
72
72
|
requiredParams,
|
|
73
|
-
isAuthenticated,
|
|
73
|
+
isAuthenticated: isReady,
|
|
74
74
|
options,
|
|
75
75
|
});
|
|
76
76
|
}`,
|
|
@@ -73,7 +73,7 @@ export function generateImportStatements(
|
|
|
73
73
|
|
|
74
74
|
let importData =
|
|
75
75
|
"import { useForm, FormProps, FormUpdate, useUpdateQuery } from 'rastack/hooks';\n";
|
|
76
|
-
importData = importData + 'import {
|
|
76
|
+
importData = importData + 'import { useCognitoAuth } from "rastack/auth";\n';
|
|
77
77
|
if (queryImports) {
|
|
78
78
|
importData += `import { ${queryImports} } from 'rastack/hooks';\n`;
|
|
79
79
|
}
|