naystack 1.7.0 → 1.7.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 +39 -22
- package/dist/auth/email/client.d.mts +17 -0
- package/dist/auth/email/client.d.ts +17 -0
- package/dist/auth/email/index.cjs.js +3 -3
- package/dist/auth/email/index.d.mts +6 -6
- package/dist/auth/email/index.d.ts +6 -6
- package/dist/auth/email/index.esm.js +2 -2
- package/dist/auth/email/routes/delete.d.mts +3 -3
- package/dist/auth/email/routes/delete.d.ts +3 -3
- package/dist/auth/email/routes/get.d.mts +3 -3
- package/dist/auth/email/routes/get.d.ts +3 -3
- package/dist/auth/email/routes/post.d.mts +3 -3
- package/dist/auth/email/routes/post.d.ts +3 -3
- package/dist/auth/email/routes/put.d.mts +3 -3
- package/dist/auth/email/routes/put.d.ts +3 -3
- package/dist/auth/email/token.cjs.js +3 -3
- package/dist/auth/email/token.d.mts +2 -2
- package/dist/auth/email/token.d.ts +2 -2
- package/dist/auth/email/token.esm.js +3 -3
- package/dist/auth/email/types.d.mts +5 -4
- package/dist/auth/email/types.d.ts +5 -4
- package/dist/auth/email/utils.d.mts +3 -3
- package/dist/auth/email/utils.d.ts +3 -3
- package/dist/auth/google/get.d.mts +3 -3
- package/dist/auth/google/get.d.ts +3 -3
- package/dist/auth/google/index.cjs.js +3 -3
- package/dist/auth/google/index.d.mts +7 -7
- package/dist/auth/google/index.d.ts +7 -7
- package/dist/auth/google/index.esm.js +2 -2
- package/dist/auth/index.cjs.js +12 -12
- package/dist/auth/index.d.mts +3 -3
- package/dist/auth/index.d.ts +3 -3
- package/dist/auth/index.esm.js +9 -9
- package/dist/auth/instagram/index.cjs.js +6 -6
- package/dist/auth/instagram/index.d.mts +8 -9
- package/dist/auth/instagram/index.d.ts +8 -9
- package/dist/auth/instagram/index.esm.js +5 -5
- package/dist/auth/instagram/route.cjs.js +3 -3
- package/dist/auth/instagram/route.d.mts +3 -3
- package/dist/auth/instagram/route.d.ts +3 -3
- package/dist/auth/instagram/route.esm.js +3 -3
- package/dist/file/client.d.mts +7 -7
- package/dist/file/client.d.ts +7 -7
- package/dist/graphql/client.d.mts +5 -5
- package/dist/graphql/client.d.ts +5 -5
- package/dist/graphql/index.cjs.js +20 -6
- package/dist/graphql/index.d.mts +2 -2
- package/dist/graphql/index.d.ts +2 -2
- package/dist/graphql/index.esm.js +18 -4
- package/dist/graphql/init.cjs.js +3 -3
- package/dist/graphql/init.d.mts +4 -4
- package/dist/graphql/init.d.ts +4 -4
- package/dist/graphql/init.esm.js +2 -2
- package/dist/graphql/utils.cjs.js +17 -3
- package/dist/graphql/utils.d.mts +16 -16
- package/dist/graphql/utils.d.ts +16 -16
- package/dist/graphql/utils.esm.js +16 -2
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/socials/instagram/webhook.d.mts +2 -2
- package/dist/socials/instagram/webhook.d.ts +2 -2
- package/dist/utils/route.d.mts +20 -0
- package/dist/utils/route.d.ts +20 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,12 +24,12 @@ Naystack provides a seamless email-based authentication system with optional sup
|
|
|
24
24
|
Define your auth routes in `app/api/(auth)/email/route.ts`. The library reads `SIGNING_KEY` and `REFRESH_KEY` from environment variables automatically.
|
|
25
25
|
|
|
26
26
|
```typescript
|
|
27
|
-
import {
|
|
27
|
+
import { setupEmailAuth } from "naystack/auth";
|
|
28
28
|
import { db } from "@/app/api/lib/db";
|
|
29
29
|
import { UserTable } from "@/app/api/(graphql)/User/db";
|
|
30
30
|
import { eq } from "drizzle-orm";
|
|
31
31
|
|
|
32
|
-
export const { GET, POST, PUT, DELETE } =
|
|
32
|
+
export const { GET, POST, PUT, DELETE } = setupEmailAuth({
|
|
33
33
|
// Fetch user by request data (used for login & sign-up duplicate check)
|
|
34
34
|
getUser: async ({ email }: { email: string }) => {
|
|
35
35
|
const [user] = await db
|
|
@@ -214,9 +214,9 @@ await checkAuthStatus("/login"); // Redirects to /login if not authorized
|
|
|
214
214
|
### Google OAuth
|
|
215
215
|
|
|
216
216
|
```typescript
|
|
217
|
-
import {
|
|
217
|
+
import { setupGoogleAuth } from "naystack/auth";
|
|
218
218
|
|
|
219
|
-
export const { GET } =
|
|
219
|
+
export const { GET } = setupGoogleAuth({
|
|
220
220
|
getUserIdFromEmail: async (googleUser) => {
|
|
221
221
|
// Find or create user by Google email
|
|
222
222
|
return findOrCreateUserByEmail(googleUser.email!);
|
|
@@ -229,18 +229,27 @@ export const { GET } = initGoogleAuth({
|
|
|
229
229
|
### Instagram OAuth
|
|
230
230
|
|
|
231
231
|
```typescript
|
|
232
|
-
import {
|
|
232
|
+
import { setupInstagramAuth } from "naystack/auth";
|
|
233
233
|
|
|
234
|
-
export const { GET
|
|
234
|
+
export const { GET } = setupInstagramAuth({
|
|
235
235
|
onUser: async (igUser, appUserId, accessToken) => {
|
|
236
236
|
await saveInstagramUser(appUserId, igUser, accessToken);
|
|
237
237
|
},
|
|
238
|
-
|
|
238
|
+
redirectURL: "/dashboard",
|
|
239
239
|
errorRedirectURL: "/login",
|
|
240
|
-
refreshKey: process.env.REFRESH_KEY!,
|
|
241
240
|
});
|
|
242
241
|
```
|
|
243
242
|
|
|
243
|
+
#### `getRefreshedInstagramAccessToken(token)`
|
|
244
|
+
|
|
245
|
+
Refreshes a long-lived Instagram access token. Exported separately from `naystack/auth`.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { getRefreshedInstagramAccessToken } from "naystack/auth";
|
|
249
|
+
|
|
250
|
+
const newToken = await getRefreshedInstagramAccessToken(existingToken);
|
|
251
|
+
```
|
|
252
|
+
|
|
244
253
|
---
|
|
245
254
|
|
|
246
255
|
## 2. GraphQL
|
|
@@ -249,13 +258,13 @@ Naystack provides a type-safe GraphQL layer built on `type-graphql` and `Apollo
|
|
|
249
258
|
|
|
250
259
|
### Defining Queries and Mutations
|
|
251
260
|
|
|
252
|
-
Use `
|
|
261
|
+
Use `resolver()` to define a resolver. It returns an object with the resolver function, plus `.call()` and `.authCall()` for direct server-side invocation (e.g. in Server Components).
|
|
253
262
|
|
|
254
263
|
```typescript
|
|
255
264
|
// app/api/(graphql)/User/resolvers/get-current-user.ts
|
|
256
|
-
import {
|
|
265
|
+
import { resolver } from "naystack/graphql";
|
|
257
266
|
|
|
258
|
-
export default
|
|
267
|
+
export default resolver(
|
|
259
268
|
async (ctx) => {
|
|
260
269
|
if (!ctx.userId) return null;
|
|
261
270
|
const [user] = await db
|
|
@@ -275,9 +284,9 @@ export default query(
|
|
|
275
284
|
|
|
276
285
|
```typescript
|
|
277
286
|
// app/api/(graphql)/Feedback/resolvers/submit-feedback.ts
|
|
278
|
-
import {
|
|
287
|
+
import { resolver } from "naystack/graphql";
|
|
279
288
|
|
|
280
|
-
export default
|
|
289
|
+
export default resolver(
|
|
281
290
|
async (ctx, input: SubmitFeedbackInput) => {
|
|
282
291
|
await db.insert(FeedbackTable).values({
|
|
283
292
|
userId: ctx.userId, // guaranteed non-null when authorized: true
|
|
@@ -321,7 +330,7 @@ export default field(
|
|
|
321
330
|
|
|
322
331
|
### Registering Resolvers
|
|
323
332
|
|
|
324
|
-
Use `QueryLibrary()` for queries/mutations and `FieldLibrary()` for field resolvers. Pass the
|
|
333
|
+
Use `QueryLibrary()` for queries/mutations and `FieldLibrary()` for field resolvers. Pass the returned classes to `setupGraphQL`.
|
|
325
334
|
|
|
326
335
|
```typescript
|
|
327
336
|
// app/api/(graphql)/User/graphql.ts
|
|
@@ -349,12 +358,12 @@ export const UserFieldResolvers = FieldLibrary<UserDB>(User, {
|
|
|
349
358
|
|
|
350
359
|
```typescript
|
|
351
360
|
// app/api/(graphql)/route.ts
|
|
352
|
-
import {
|
|
361
|
+
import { setupGraphQL } from "naystack/graphql";
|
|
353
362
|
import { UserResolvers, UserFieldResolvers } from "./User/graphql";
|
|
354
363
|
import { ChatResolvers } from "./Chat/graphql";
|
|
355
364
|
import { FeedbackResolvers } from "./Feedback/graphql";
|
|
356
365
|
|
|
357
|
-
export const { GET, POST } = await
|
|
366
|
+
export const { GET, POST } = await setupGraphQL({
|
|
358
367
|
resolvers: [UserResolvers, UserFieldResolvers, ChatResolvers, FeedbackResolvers],
|
|
359
368
|
});
|
|
360
369
|
```
|
|
@@ -374,18 +383,20 @@ if (!ctx.userId) throw GQLError(403); // "You are not allowed
|
|
|
374
383
|
if (!deal) throw GQLError(404, "Deal not found"); // Custom message
|
|
375
384
|
```
|
|
376
385
|
|
|
377
|
-
### Type
|
|
386
|
+
### Type Helpers: `QueryResponseType` / `FieldResponseType`
|
|
378
387
|
|
|
379
|
-
Infer the return type of a query definition. Use
|
|
388
|
+
Infer the return type of a query or field resolver definition. Use them to type component props that receive resolver results.
|
|
380
389
|
|
|
381
390
|
```typescript
|
|
382
|
-
import type { QueryResponseType } from "naystack/graphql";
|
|
391
|
+
import type { QueryResponseType, FieldResponseType } from "naystack/graphql";
|
|
383
392
|
import type getCurrentUser from "@/app/api/(graphql)/User/resolvers/get-current-user";
|
|
384
393
|
import type getDeal from "@/app/api/(graphql)/Deal/queries/get-deal";
|
|
394
|
+
import type sellerField from "@/app/api/(graphql)/Property/resolvers/seller-field";
|
|
385
395
|
|
|
386
396
|
interface DealDetailsProps {
|
|
387
397
|
user: QueryResponseType<typeof getCurrentUser>;
|
|
388
398
|
deal: QueryResponseType<typeof getDeal>;
|
|
399
|
+
seller: FieldResponseType<typeof sellerField>;
|
|
389
400
|
}
|
|
390
401
|
```
|
|
391
402
|
|
|
@@ -571,9 +582,7 @@ function FileUploader({ dealId }: { dealId: number }) {
|
|
|
571
582
|
setUploading(true);
|
|
572
583
|
try {
|
|
573
584
|
const result = await uploadFile(file, "DealDocument", {
|
|
574
|
-
dealId,
|
|
575
|
-
fileName: file.name,
|
|
576
|
-
category: "Contract",
|
|
585
|
+
data: { dealId, fileName: file.name, category: "Contract" },
|
|
577
586
|
});
|
|
578
587
|
if (result?.url) {
|
|
579
588
|
console.log("Uploaded:", result.url);
|
|
@@ -653,6 +662,8 @@ import {
|
|
|
653
662
|
getInstagramMedia,
|
|
654
663
|
getInstagramConversations,
|
|
655
664
|
getInstagramConversation,
|
|
665
|
+
getInstagramConversationByUser,
|
|
666
|
+
getInstagramConversationsByUser,
|
|
656
667
|
getInstagramMessage,
|
|
657
668
|
sendInstagramMessage,
|
|
658
669
|
setupInstagramWebhook,
|
|
@@ -675,6 +686,12 @@ if (convos.fetchMore) {
|
|
|
675
686
|
const nextPage = await convos.fetchMore();
|
|
676
687
|
}
|
|
677
688
|
|
|
689
|
+
// Fetch conversations filtered by a specific user
|
|
690
|
+
const userConvos = await getInstagramConversationsByUser(accessToken, userId);
|
|
691
|
+
|
|
692
|
+
// Fetch the single conversation with a specific user (2-participant thread)
|
|
693
|
+
const convo = await getInstagramConversationByUser(accessToken, userId);
|
|
694
|
+
|
|
678
695
|
// Send a message
|
|
679
696
|
await sendInstagramMessage(accessToken, recipientId, "Hello!");
|
|
680
697
|
|
|
@@ -16,6 +16,7 @@ declare const TokenContext: React__default.Context<{
|
|
|
16
16
|
* Must be placed **above** `ApolloWrapper` in the component tree (since `ApolloWrapper` needs the token).
|
|
17
17
|
*
|
|
18
18
|
* @param children - React children (e.g. your app or a layout).
|
|
19
|
+
* @param onTokenUpdate - Optional callback fired whenever the token changes (after initial load). Receives `token` (string) or `null` on logout.
|
|
19
20
|
* @returns TokenContext.Provider wrapping children.
|
|
20
21
|
*
|
|
21
22
|
* @example
|
|
@@ -43,7 +44,23 @@ declare const AuthWrapper: ({ children, onTokenUpdate, }: {
|
|
|
43
44
|
children: React__default.ReactNode;
|
|
44
45
|
onTokenUpdate?: (token: string | null) => void;
|
|
45
46
|
}) => React__default.JSX.Element;
|
|
47
|
+
/**
|
|
48
|
+
* Fetches the access token on mount by calling the auth endpoint. Stores the result in TokenContext.
|
|
49
|
+
* Used internally by auth setup; prefer `AuthWrapper` for typical usage.
|
|
50
|
+
*
|
|
51
|
+
* @param getRefreshToken - Optional async function that returns a refresh token string (e.g. from cookies or storage). If omitted, the request relies on httpOnly cookies via `credentials: "include"`.
|
|
52
|
+
*
|
|
53
|
+
* @category Auth
|
|
54
|
+
*/
|
|
46
55
|
declare function useAuthFetch(getRefreshToken?: () => Promise<string | null>): void;
|
|
56
|
+
/**
|
|
57
|
+
* Component that applies a server-provided access token into TokenContext on mount.
|
|
58
|
+
* Useful for hydrating auth state from server-side rendering.
|
|
59
|
+
*
|
|
60
|
+
* @param data - The access token string to set. If falsy, no update occurs.
|
|
61
|
+
*
|
|
62
|
+
* @category Auth
|
|
63
|
+
*/
|
|
47
64
|
declare function AuthApply({ data }: {
|
|
48
65
|
data?: string | null;
|
|
49
66
|
}): null;
|
|
@@ -16,6 +16,7 @@ declare const TokenContext: React__default.Context<{
|
|
|
16
16
|
* Must be placed **above** `ApolloWrapper` in the component tree (since `ApolloWrapper` needs the token).
|
|
17
17
|
*
|
|
18
18
|
* @param children - React children (e.g. your app or a layout).
|
|
19
|
+
* @param onTokenUpdate - Optional callback fired whenever the token changes (after initial load). Receives `token` (string) or `null` on logout.
|
|
19
20
|
* @returns TokenContext.Provider wrapping children.
|
|
20
21
|
*
|
|
21
22
|
* @example
|
|
@@ -43,7 +44,23 @@ declare const AuthWrapper: ({ children, onTokenUpdate, }: {
|
|
|
43
44
|
children: React__default.ReactNode;
|
|
44
45
|
onTokenUpdate?: (token: string | null) => void;
|
|
45
46
|
}) => React__default.JSX.Element;
|
|
47
|
+
/**
|
|
48
|
+
* Fetches the access token on mount by calling the auth endpoint. Stores the result in TokenContext.
|
|
49
|
+
* Used internally by auth setup; prefer `AuthWrapper` for typical usage.
|
|
50
|
+
*
|
|
51
|
+
* @param getRefreshToken - Optional async function that returns a refresh token string (e.g. from cookies or storage). If omitted, the request relies on httpOnly cookies via `credentials: "include"`.
|
|
52
|
+
*
|
|
53
|
+
* @category Auth
|
|
54
|
+
*/
|
|
46
55
|
declare function useAuthFetch(getRefreshToken?: () => Promise<string | null>): void;
|
|
56
|
+
/**
|
|
57
|
+
* Component that applies a server-provided access token into TokenContext on mount.
|
|
58
|
+
* Useful for hydrating auth state from server-side rendering.
|
|
59
|
+
*
|
|
60
|
+
* @param data - The access token string to set. If falsy, no update occurs.
|
|
61
|
+
*
|
|
62
|
+
* @category Auth
|
|
63
|
+
*/
|
|
47
64
|
declare function AuthApply({ data }: {
|
|
48
65
|
data?: string | null;
|
|
49
66
|
}): null;
|
|
@@ -33,7 +33,7 @@ __export(email_exports, {
|
|
|
33
33
|
AuthFetch: () => AuthFetch,
|
|
34
34
|
checkAuthStatus: () => checkAuthStatus,
|
|
35
35
|
getContext: () => getContext,
|
|
36
|
-
|
|
36
|
+
setupEmailAuth: () => setupEmailAuth
|
|
37
37
|
});
|
|
38
38
|
module.exports = __toCommonJS(email_exports);
|
|
39
39
|
var import_server5 = require("next/server");
|
|
@@ -400,7 +400,7 @@ function AuthFetch() {
|
|
|
400
400
|
}
|
|
401
401
|
|
|
402
402
|
// src/auth/email/index.ts
|
|
403
|
-
function
|
|
403
|
+
function setupEmailAuth(options) {
|
|
404
404
|
const { allowedOrigins } = options;
|
|
405
405
|
return {
|
|
406
406
|
GET: withCors(getGetRoute(options), allowedOrigins),
|
|
@@ -426,5 +426,5 @@ function getEmailAuthRoutes(options) {
|
|
|
426
426
|
AuthFetch,
|
|
427
427
|
checkAuthStatus,
|
|
428
428
|
getContext,
|
|
429
|
-
|
|
429
|
+
setupEmailAuth
|
|
430
430
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import {
|
|
2
|
+
import { SetupEmailAuthOptions } from './types.mjs';
|
|
3
3
|
export { default as AuthFetch } from './server.mjs';
|
|
4
4
|
export { checkAuthStatus } from './token.mjs';
|
|
5
5
|
export { getContext } from './utils.mjs';
|
|
@@ -13,7 +13,7 @@ import '../../graphql/types.mjs';
|
|
|
13
13
|
* The library automatically hashes passwords on sign-up and reads `SIGNING_KEY` / `REFRESH_KEY` from env vars.
|
|
14
14
|
* Optionally supports Cloudflare Turnstile captcha validation when `TURNSTILE_KEY` is set.
|
|
15
15
|
*
|
|
16
|
-
* @param options - Configuration for the auth routes. See {@link
|
|
16
|
+
* @param options - Configuration for the auth routes. See {@link SetupEmailAuthOptions}.
|
|
17
17
|
* @param options.getUser - Given request body (e.g. `{ email }`), returns the user from DB or undefined. Used for login and duplicate check on sign-up.
|
|
18
18
|
* @param options.createUser - Given sign-up data with hashed password, inserts the user and returns the created record.
|
|
19
19
|
* @param options.onError - Optional. Called on validation/auth errors; return a NextResponse to customize the error response.
|
|
@@ -26,9 +26,9 @@ import '../../graphql/types.mjs';
|
|
|
26
26
|
* @example
|
|
27
27
|
* ```ts
|
|
28
28
|
* // app/api/(auth)/email/route.ts
|
|
29
|
-
* import {
|
|
29
|
+
* import { setupEmailAuth } from "naystack/auth";
|
|
30
30
|
*
|
|
31
|
-
* export const { GET, POST, PUT, DELETE } =
|
|
31
|
+
* export const { GET, POST, PUT, DELETE } = setupEmailAuth({
|
|
32
32
|
* getUser: async ({ email }: { email: string }) => {
|
|
33
33
|
* const [user] = await db.select({ id: UserTable.id, password: UserTable.password })
|
|
34
34
|
* .from(UserTable).where(eq(UserTable.email, email));
|
|
@@ -47,7 +47,7 @@ import '../../graphql/types.mjs';
|
|
|
47
47
|
*
|
|
48
48
|
* @category Auth
|
|
49
49
|
*/
|
|
50
|
-
declare function
|
|
50
|
+
declare function setupEmailAuth(options: SetupEmailAuthOptions): {
|
|
51
51
|
OPTIONS?: ((req: NextRequest) => NextResponse<unknown>) | undefined;
|
|
52
52
|
GET: (req: NextRequest) => Promise<NextResponse<{
|
|
53
53
|
accessToken: string | undefined;
|
|
@@ -61,4 +61,4 @@ declare function getEmailAuthRoutes(options: InitRoutesOptions): {
|
|
|
61
61
|
}>>;
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
-
export {
|
|
64
|
+
export { setupEmailAuth };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import {
|
|
2
|
+
import { SetupEmailAuthOptions } from './types.js';
|
|
3
3
|
export { default as AuthFetch } from './server.js';
|
|
4
4
|
export { checkAuthStatus } from './token.js';
|
|
5
5
|
export { getContext } from './utils.js';
|
|
@@ -13,7 +13,7 @@ import '../../graphql/types.js';
|
|
|
13
13
|
* The library automatically hashes passwords on sign-up and reads `SIGNING_KEY` / `REFRESH_KEY` from env vars.
|
|
14
14
|
* Optionally supports Cloudflare Turnstile captcha validation when `TURNSTILE_KEY` is set.
|
|
15
15
|
*
|
|
16
|
-
* @param options - Configuration for the auth routes. See {@link
|
|
16
|
+
* @param options - Configuration for the auth routes. See {@link SetupEmailAuthOptions}.
|
|
17
17
|
* @param options.getUser - Given request body (e.g. `{ email }`), returns the user from DB or undefined. Used for login and duplicate check on sign-up.
|
|
18
18
|
* @param options.createUser - Given sign-up data with hashed password, inserts the user and returns the created record.
|
|
19
19
|
* @param options.onError - Optional. Called on validation/auth errors; return a NextResponse to customize the error response.
|
|
@@ -26,9 +26,9 @@ import '../../graphql/types.js';
|
|
|
26
26
|
* @example
|
|
27
27
|
* ```ts
|
|
28
28
|
* // app/api/(auth)/email/route.ts
|
|
29
|
-
* import {
|
|
29
|
+
* import { setupEmailAuth } from "naystack/auth";
|
|
30
30
|
*
|
|
31
|
-
* export const { GET, POST, PUT, DELETE } =
|
|
31
|
+
* export const { GET, POST, PUT, DELETE } = setupEmailAuth({
|
|
32
32
|
* getUser: async ({ email }: { email: string }) => {
|
|
33
33
|
* const [user] = await db.select({ id: UserTable.id, password: UserTable.password })
|
|
34
34
|
* .from(UserTable).where(eq(UserTable.email, email));
|
|
@@ -47,7 +47,7 @@ import '../../graphql/types.js';
|
|
|
47
47
|
*
|
|
48
48
|
* @category Auth
|
|
49
49
|
*/
|
|
50
|
-
declare function
|
|
50
|
+
declare function setupEmailAuth(options: SetupEmailAuthOptions): {
|
|
51
51
|
OPTIONS?: ((req: NextRequest) => NextResponse<unknown>) | undefined;
|
|
52
52
|
GET: (req: NextRequest) => Promise<NextResponse<{
|
|
53
53
|
accessToken: string | undefined;
|
|
@@ -61,4 +61,4 @@ declare function getEmailAuthRoutes(options: InitRoutesOptions): {
|
|
|
61
61
|
}>>;
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
-
export {
|
|
64
|
+
export { setupEmailAuth };
|
|
@@ -367,7 +367,7 @@ function AuthFetch() {
|
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
// src/auth/email/index.ts
|
|
370
|
-
function
|
|
370
|
+
function setupEmailAuth(options) {
|
|
371
371
|
const { allowedOrigins } = options;
|
|
372
372
|
return {
|
|
373
373
|
GET: withCors(getGetRoute(options), allowedOrigins),
|
|
@@ -392,5 +392,5 @@ export {
|
|
|
392
392
|
AuthFetch,
|
|
393
393
|
checkAuthStatus,
|
|
394
394
|
getContext,
|
|
395
|
-
|
|
395
|
+
setupEmailAuth
|
|
396
396
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as next_server from 'next/server';
|
|
2
2
|
import { NextRequest } from 'next/server';
|
|
3
|
-
import {
|
|
3
|
+
import { SetupEmailAuthOptions } from '../types.mjs';
|
|
4
4
|
import '../../types.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Returns the DELETE route handler for logout.
|
|
8
|
-
* @param options -
|
|
8
|
+
* @param options - SetupEmailAuthOptions
|
|
9
9
|
* @returns Async route handler
|
|
10
10
|
*/
|
|
11
|
-
declare const getDeleteRoute: (options:
|
|
11
|
+
declare const getDeleteRoute: (options: SetupEmailAuthOptions) => (req: NextRequest) => Promise<next_server.NextResponse<{
|
|
12
12
|
accessToken: string | undefined;
|
|
13
13
|
refreshToken: string | undefined;
|
|
14
14
|
}>>;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as next_server from 'next/server';
|
|
2
2
|
import { NextRequest } from 'next/server';
|
|
3
|
-
import {
|
|
3
|
+
import { SetupEmailAuthOptions } from '../types.js';
|
|
4
4
|
import '../../types.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Returns the DELETE route handler for logout.
|
|
8
|
-
* @param options -
|
|
8
|
+
* @param options - SetupEmailAuthOptions
|
|
9
9
|
* @returns Async route handler
|
|
10
10
|
*/
|
|
11
|
-
declare const getDeleteRoute: (options:
|
|
11
|
+
declare const getDeleteRoute: (options: SetupEmailAuthOptions) => (req: NextRequest) => Promise<next_server.NextResponse<{
|
|
12
12
|
accessToken: string | undefined;
|
|
13
13
|
refreshToken: string | undefined;
|
|
14
14
|
}>>;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as next_server from 'next/server';
|
|
2
2
|
import { NextRequest } from 'next/server';
|
|
3
|
-
import {
|
|
3
|
+
import { SetupEmailAuthOptions } from '../types.mjs';
|
|
4
4
|
import '../../types.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Returns the GET route handler for token refresh (exchange refresh cookie for new tokens).
|
|
8
|
-
* @param options -
|
|
8
|
+
* @param options - SetupEmailAuthOptions
|
|
9
9
|
* @returns Async route handler
|
|
10
10
|
*/
|
|
11
|
-
declare const getGetRoute: (options:
|
|
11
|
+
declare const getGetRoute: (options: SetupEmailAuthOptions) => (req: NextRequest) => Promise<next_server.NextResponse<{
|
|
12
12
|
accessToken: string | undefined;
|
|
13
13
|
refreshToken: string | undefined;
|
|
14
14
|
}>>;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as next_server from 'next/server';
|
|
2
2
|
import { NextRequest } from 'next/server';
|
|
3
|
-
import {
|
|
3
|
+
import { SetupEmailAuthOptions } from '../types.js';
|
|
4
4
|
import '../../types.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Returns the GET route handler for token refresh (exchange refresh cookie for new tokens).
|
|
8
|
-
* @param options -
|
|
8
|
+
* @param options - SetupEmailAuthOptions
|
|
9
9
|
* @returns Async route handler
|
|
10
10
|
*/
|
|
11
|
-
declare const getGetRoute: (options:
|
|
11
|
+
declare const getGetRoute: (options: SetupEmailAuthOptions) => (req: NextRequest) => Promise<next_server.NextResponse<{
|
|
12
12
|
accessToken: string | undefined;
|
|
13
13
|
refreshToken: string | undefined;
|
|
14
14
|
}>>;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import * as next_server from 'next/server';
|
|
2
2
|
import { NextRequest } from 'next/server';
|
|
3
|
-
import {
|
|
3
|
+
import { SetupEmailAuthOptions } from '../types.mjs';
|
|
4
4
|
import '../../types.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Returns the POST route handler for sign up.
|
|
8
|
-
* @param options -
|
|
8
|
+
* @param options - SetupEmailAuthOptions
|
|
9
9
|
* @returns Async route handler
|
|
10
10
|
*/
|
|
11
|
-
declare const getPostRoute: (options:
|
|
11
|
+
declare const getPostRoute: (options: SetupEmailAuthOptions) => (req: NextRequest) => Promise<next_server.NextResponse<unknown> | undefined>;
|
|
12
12
|
|
|
13
13
|
export { getPostRoute };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import * as next_server from 'next/server';
|
|
2
2
|
import { NextRequest } from 'next/server';
|
|
3
|
-
import {
|
|
3
|
+
import { SetupEmailAuthOptions } from '../types.js';
|
|
4
4
|
import '../../types.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Returns the POST route handler for sign up.
|
|
8
|
-
* @param options -
|
|
8
|
+
* @param options - SetupEmailAuthOptions
|
|
9
9
|
* @returns Async route handler
|
|
10
10
|
*/
|
|
11
|
-
declare const getPostRoute: (options:
|
|
11
|
+
declare const getPostRoute: (options: SetupEmailAuthOptions) => (req: NextRequest) => Promise<next_server.NextResponse<unknown> | undefined>;
|
|
12
12
|
|
|
13
13
|
export { getPostRoute };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import * as next_server from 'next/server';
|
|
2
2
|
import { NextRequest } from 'next/server';
|
|
3
|
-
import {
|
|
3
|
+
import { SetupEmailAuthOptions } from '../types.mjs';
|
|
4
4
|
import '../../types.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Returns the PUT route handler for login.
|
|
8
|
-
* @param options -
|
|
8
|
+
* @param options - SetupEmailAuthOptions
|
|
9
9
|
* @returns Async route handler
|
|
10
10
|
*/
|
|
11
|
-
declare const getPutRoute: (options:
|
|
11
|
+
declare const getPutRoute: (options: SetupEmailAuthOptions) => (req: NextRequest) => Promise<next_server.NextResponse<unknown> | undefined>;
|
|
12
12
|
|
|
13
13
|
export { getPutRoute };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import * as next_server from 'next/server';
|
|
2
2
|
import { NextRequest } from 'next/server';
|
|
3
|
-
import {
|
|
3
|
+
import { SetupEmailAuthOptions } from '../types.js';
|
|
4
4
|
import '../../types.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Returns the PUT route handler for login.
|
|
8
|
-
* @param options -
|
|
8
|
+
* @param options - SetupEmailAuthOptions
|
|
9
9
|
* @returns Async route handler
|
|
10
10
|
*/
|
|
11
|
-
declare const getPutRoute: (options:
|
|
11
|
+
declare const getPutRoute: (options: SetupEmailAuthOptions) => (req: NextRequest) => Promise<next_server.NextResponse<unknown> | undefined>;
|
|
12
12
|
|
|
13
13
|
export { getPutRoute };
|
|
@@ -130,10 +130,10 @@ function getUserIdFromRefreshToken(refreshToken) {
|
|
|
130
130
|
}
|
|
131
131
|
return null;
|
|
132
132
|
}
|
|
133
|
-
function getUserIdFromAccessToken(
|
|
134
|
-
if (
|
|
133
|
+
function getUserIdFromAccessToken(accessToken) {
|
|
134
|
+
if (accessToken)
|
|
135
135
|
try {
|
|
136
|
-
const decoded = (0, import_jsonwebtoken.verify)(
|
|
136
|
+
const decoded = (0, import_jsonwebtoken.verify)(accessToken, getEnv("SIGNING_KEY" /* SIGNING_KEY */));
|
|
137
137
|
if (typeof decoded !== "string" && typeof decoded.id === "number")
|
|
138
138
|
return decoded.id;
|
|
139
139
|
} catch (e) {
|
|
@@ -42,11 +42,11 @@ declare function getTokenizedResponse(accessToken?: string, refreshToken?: strin
|
|
|
42
42
|
declare function getUserIdFromRefreshToken(refreshToken?: string): number | null;
|
|
43
43
|
/**
|
|
44
44
|
* Decodes an access token and returns the user id from the JWT payload.
|
|
45
|
-
* @param
|
|
45
|
+
* @param accessToken - JWT access token string.
|
|
46
46
|
* @returns User id (number) or `null` if the token is invalid, expired, or missing.
|
|
47
47
|
* @category Auth
|
|
48
48
|
*/
|
|
49
|
-
declare function getUserIdFromAccessToken(
|
|
49
|
+
declare function getUserIdFromAccessToken(accessToken?: string): number | null;
|
|
50
50
|
/**
|
|
51
51
|
* Verifies a plain password against the user's stored bcrypt hash.
|
|
52
52
|
* @param user - User object with `password` hash.
|
|
@@ -42,11 +42,11 @@ declare function getTokenizedResponse(accessToken?: string, refreshToken?: strin
|
|
|
42
42
|
declare function getUserIdFromRefreshToken(refreshToken?: string): number | null;
|
|
43
43
|
/**
|
|
44
44
|
* Decodes an access token and returns the user id from the JWT payload.
|
|
45
|
-
* @param
|
|
45
|
+
* @param accessToken - JWT access token string.
|
|
46
46
|
* @returns User id (number) or `null` if the token is invalid, expired, or missing.
|
|
47
47
|
* @category Auth
|
|
48
48
|
*/
|
|
49
|
-
declare function getUserIdFromAccessToken(
|
|
49
|
+
declare function getUserIdFromAccessToken(accessToken?: string): number | null;
|
|
50
50
|
/**
|
|
51
51
|
* Verifies a plain password against the user's stored bcrypt hash.
|
|
52
52
|
* @param user - User object with `password` hash.
|
|
@@ -100,10 +100,10 @@ function getUserIdFromRefreshToken(refreshToken) {
|
|
|
100
100
|
}
|
|
101
101
|
return null;
|
|
102
102
|
}
|
|
103
|
-
function getUserIdFromAccessToken(
|
|
104
|
-
if (
|
|
103
|
+
function getUserIdFromAccessToken(accessToken) {
|
|
104
|
+
if (accessToken)
|
|
105
105
|
try {
|
|
106
|
-
const decoded = verify(
|
|
106
|
+
const decoded = verify(accessToken, getEnv("SIGNING_KEY" /* SIGNING_KEY */));
|
|
107
107
|
if (typeof decoded !== "string" && typeof decoded.id === "number")
|
|
108
108
|
return decoded.id;
|
|
109
109
|
} catch (e) {
|
|
@@ -2,7 +2,7 @@ import { UserOutput, ErrorHandler } from '../types.mjs';
|
|
|
2
2
|
import 'next/server';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Options for initializing email auth routes (GET/POST/PUT/DELETE) via `
|
|
5
|
+
* Options for initializing email auth routes (GET/POST/PUT/DELETE) via `setupEmailAuth`.
|
|
6
6
|
*
|
|
7
7
|
* @property getUser - Fetches user by request data (e.g. `{ email }`); used for login and sign-up duplicate check. Must return a {@link UserOutput} or `undefined`.
|
|
8
8
|
* @property createUser - Creates a new user with the hashed password; returns the created user as {@link UserOutput}.
|
|
@@ -11,10 +11,11 @@ import 'next/server';
|
|
|
11
11
|
* @property onLogin - Optional callback after successful login. Receives `(userId, requestBody)`.
|
|
12
12
|
* @property onRefresh - Optional callback when GET refresh is used. Receives `(userId, requestBody)`.
|
|
13
13
|
* @property onLogout - Optional callback when DELETE logout is used. Receives `(userId, requestBody)`.
|
|
14
|
+
* @property allowedOrigins - Optional list of allowed CORS origins. If set, cross-origin requests from unlisted origins are rejected with 403.
|
|
14
15
|
*
|
|
15
16
|
* @example
|
|
16
17
|
* ```ts
|
|
17
|
-
* const options:
|
|
18
|
+
* const options: SetupEmailAuthOptions = {
|
|
18
19
|
* getUser: async ({ email }) => db.query.users.findFirst({ where: eq(users.email, email) }),
|
|
19
20
|
* createUser: async (data) => (await db.insert(users).values(data).returning())[0],
|
|
20
21
|
* onSignUp: async (userId, body) => { console.log("New user:", userId); },
|
|
@@ -23,7 +24,7 @@ import 'next/server';
|
|
|
23
24
|
*
|
|
24
25
|
* @category Auth
|
|
25
26
|
*/
|
|
26
|
-
type
|
|
27
|
+
type SetupEmailAuthOptions = {
|
|
27
28
|
getUser: (data: any) => Promise<UserOutput | undefined>;
|
|
28
29
|
createUser: (user: any) => Promise<UserOutput | undefined>;
|
|
29
30
|
onError?: ErrorHandler;
|
|
@@ -34,4 +35,4 @@ type InitRoutesOptions = {
|
|
|
34
35
|
allowedOrigins?: string[];
|
|
35
36
|
};
|
|
36
37
|
|
|
37
|
-
export type {
|
|
38
|
+
export type { SetupEmailAuthOptions };
|
|
@@ -2,7 +2,7 @@ import { UserOutput, ErrorHandler } from '../types.js';
|
|
|
2
2
|
import 'next/server';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Options for initializing email auth routes (GET/POST/PUT/DELETE) via `
|
|
5
|
+
* Options for initializing email auth routes (GET/POST/PUT/DELETE) via `setupEmailAuth`.
|
|
6
6
|
*
|
|
7
7
|
* @property getUser - Fetches user by request data (e.g. `{ email }`); used for login and sign-up duplicate check. Must return a {@link UserOutput} or `undefined`.
|
|
8
8
|
* @property createUser - Creates a new user with the hashed password; returns the created user as {@link UserOutput}.
|
|
@@ -11,10 +11,11 @@ import 'next/server';
|
|
|
11
11
|
* @property onLogin - Optional callback after successful login. Receives `(userId, requestBody)`.
|
|
12
12
|
* @property onRefresh - Optional callback when GET refresh is used. Receives `(userId, requestBody)`.
|
|
13
13
|
* @property onLogout - Optional callback when DELETE logout is used. Receives `(userId, requestBody)`.
|
|
14
|
+
* @property allowedOrigins - Optional list of allowed CORS origins. If set, cross-origin requests from unlisted origins are rejected with 403.
|
|
14
15
|
*
|
|
15
16
|
* @example
|
|
16
17
|
* ```ts
|
|
17
|
-
* const options:
|
|
18
|
+
* const options: SetupEmailAuthOptions = {
|
|
18
19
|
* getUser: async ({ email }) => db.query.users.findFirst({ where: eq(users.email, email) }),
|
|
19
20
|
* createUser: async (data) => (await db.insert(users).values(data).returning())[0],
|
|
20
21
|
* onSignUp: async (userId, body) => { console.log("New user:", userId); },
|
|
@@ -23,7 +24,7 @@ import 'next/server';
|
|
|
23
24
|
*
|
|
24
25
|
* @category Auth
|
|
25
26
|
*/
|
|
26
|
-
type
|
|
27
|
+
type SetupEmailAuthOptions = {
|
|
27
28
|
getUser: (data: any) => Promise<UserOutput | undefined>;
|
|
28
29
|
createUser: (user: any) => Promise<UserOutput | undefined>;
|
|
29
30
|
onError?: ErrorHandler;
|
|
@@ -34,4 +35,4 @@ type InitRoutesOptions = {
|
|
|
34
35
|
allowedOrigins?: string[];
|
|
35
36
|
};
|
|
36
37
|
|
|
37
|
-
export type {
|
|
38
|
+
export type { SetupEmailAuthOptions };
|