subaya 1.0.0 → 1.0.2

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.
Files changed (92) hide show
  1. package/README.md +54 -118
  2. package/dist/commands/axios/AxiosGeneratorCommand.d.ts.map +1 -1
  3. package/dist/commands/axios/AxiosGeneratorCommand.js +97 -17
  4. package/dist/commands/axios/AxiosGeneratorCommand.js.map +1 -1
  5. package/dist/commands/provider/ProviderGeneratorCommand.d.ts +2 -1
  6. package/dist/commands/provider/ProviderGeneratorCommand.d.ts.map +1 -1
  7. package/dist/commands/provider/ProviderGeneratorCommand.js.map +1 -1
  8. package/dist/commands/route/NextRouteGeneratorCommand.js +1 -1
  9. package/dist/commands/route/NextRouteGeneratorCommand.js.map +1 -1
  10. package/dist/commands/supabase/SupabaseCommand.d.ts +2 -1
  11. package/dist/commands/supabase/SupabaseCommand.d.ts.map +1 -1
  12. package/dist/commands/supabase/SupabaseCommand.js +97 -25
  13. package/dist/commands/supabase/SupabaseCommand.js.map +1 -1
  14. package/dist/core/EnsureSystem.d.ts +3 -0
  15. package/dist/core/EnsureSystem.d.ts.map +1 -1
  16. package/dist/core/EnsureSystem.js +16 -0
  17. package/dist/core/EnsureSystem.js.map +1 -1
  18. package/dist/core/FileSystemService.d.ts +1 -1
  19. package/dist/core/FileSystemService.d.ts.map +1 -1
  20. package/dist/core/FileSystemService.js +8 -0
  21. package/dist/core/FileSystemService.js.map +1 -1
  22. package/dist/template/axios/instance.d.ts +3 -1
  23. package/dist/template/axios/instance.d.ts.map +1 -1
  24. package/dist/template/axios/instance.js +204 -19
  25. package/dist/template/axios/instance.js.map +1 -1
  26. package/dist/template/axios/nextServerJwt.d.ts +4 -0
  27. package/dist/template/axios/nextServerJwt.d.ts.map +1 -0
  28. package/dist/template/axios/nextServerJwt.js +60 -0
  29. package/dist/template/axios/nextServerJwt.js.map +1 -0
  30. package/dist/template/axios/protectedProxy.d.ts +2 -0
  31. package/dist/template/axios/protectedProxy.d.ts.map +1 -0
  32. package/dist/template/axios/protectedProxy.js +40 -0
  33. package/dist/template/axios/protectedProxy.js.map +1 -0
  34. package/dist/template/axios/useLoginHook.d.ts +2 -0
  35. package/dist/template/axios/useLoginHook.d.ts.map +1 -0
  36. package/dist/template/axios/useLoginHook.js +16 -0
  37. package/dist/template/axios/useLoginHook.js.map +1 -0
  38. package/dist/template/axios/useLogoutHook.d.ts +2 -0
  39. package/dist/template/axios/useLogoutHook.d.ts.map +1 -0
  40. package/dist/template/axios/useLogoutHook.js +15 -0
  41. package/dist/template/axios/useLogoutHook.js.map +1 -0
  42. package/dist/template/axios/utilJwt.d.ts +2 -0
  43. package/dist/template/axios/utilJwt.d.ts.map +1 -0
  44. package/dist/template/axios/utilJwt.js +52 -0
  45. package/dist/template/axios/utilJwt.js.map +1 -0
  46. package/dist/template/supabase/actions/auth.d.ts +2 -0
  47. package/dist/template/supabase/actions/auth.d.ts.map +1 -0
  48. package/dist/template/supabase/actions/auth.js +61 -0
  49. package/dist/template/supabase/actions/auth.js.map +1 -0
  50. package/dist/template/supabase/actions/crud.d.ts +3 -0
  51. package/dist/template/supabase/actions/crud.d.ts.map +1 -0
  52. package/dist/template/supabase/actions/crud.js +72 -0
  53. package/dist/template/supabase/actions/crud.js.map +1 -0
  54. package/dist/template/supabase/actions/user.d.ts +2 -0
  55. package/dist/template/supabase/actions/user.d.ts.map +1 -0
  56. package/dist/template/supabase/actions/user.js +36 -0
  57. package/dist/template/supabase/actions/user.js.map +1 -0
  58. package/dist/template/supabase/admin/supabaseAdminLayout.d.ts +2 -0
  59. package/dist/template/supabase/admin/supabaseAdminLayout.d.ts.map +1 -0
  60. package/dist/template/supabase/admin/supabaseAdminLayout.js +7 -0
  61. package/dist/template/supabase/admin/supabaseAdminLayout.js.map +1 -0
  62. package/dist/template/supabase/admin/supabaseAdminLoginLayout.d.ts +2 -0
  63. package/dist/template/supabase/admin/supabaseAdminLoginLayout.d.ts.map +1 -0
  64. package/dist/template/supabase/admin/supabaseAdminLoginLayout.js +114 -0
  65. package/dist/template/supabase/admin/supabaseAdminLoginLayout.js.map +1 -0
  66. package/dist/template/supabase/proxy/adminProxy.d.ts +2 -0
  67. package/dist/template/supabase/proxy/adminProxy.d.ts.map +1 -0
  68. package/dist/template/supabase/proxy/adminProxy.js +45 -0
  69. package/dist/template/supabase/proxy/adminProxy.js.map +1 -0
  70. package/dist/template/supabase/proxy/authAdminProxy.d.ts +2 -0
  71. package/dist/template/supabase/proxy/authAdminProxy.d.ts.map +1 -0
  72. package/dist/template/supabase/proxy/authAdminProxy.js +61 -0
  73. package/dist/template/supabase/proxy/authAdminProxy.js.map +1 -0
  74. package/dist/template/supabase/proxy/authProxy.d.ts +2 -0
  75. package/dist/template/supabase/proxy/authProxy.d.ts.map +1 -0
  76. package/dist/template/supabase/proxy/authProxy.js +49 -0
  77. package/dist/template/supabase/proxy/authProxy.js.map +1 -0
  78. package/dist/template/supabase/route/googleCallback.d.ts +2 -0
  79. package/dist/template/supabase/route/googleCallback.d.ts.map +1 -0
  80. package/dist/template/supabase/route/googleCallback.js +25 -0
  81. package/dist/template/supabase/route/googleCallback.js.map +1 -0
  82. package/dist/template/supabase/schemas/user.d.ts +2 -0
  83. package/dist/template/supabase/schemas/user.d.ts.map +1 -0
  84. package/dist/template/supabase/schemas/user.js +14 -0
  85. package/dist/template/supabase/schemas/user.js.map +1 -0
  86. package/dist/template/supabase/utilBase.d.ts +1 -1
  87. package/dist/template/supabase/utilBase.d.ts.map +1 -1
  88. package/dist/template/supabase/utilBase.js +2 -2
  89. package/dist/types/BaseExtensionCommands.d.ts +2 -1
  90. package/dist/types/BaseExtensionCommands.d.ts.map +1 -1
  91. package/dist/types/BaseExtensionCommands.js.map +1 -1
  92. package/package.json +1 -1
@@ -0,0 +1,60 @@
1
+ export const nextServerAuthLoginRoute = () => `import { instance } from "@/configs/axios/instance"
2
+ import { AUTH_ENDPOINTS, setTokens } from "@/utils/jwt"
3
+ import { NextResponse } from "next/server"
4
+
5
+ export async function POST(request: Request) {
6
+ try {
7
+ const body = await request.json()
8
+
9
+ const response = await instance.post(AUTH_ENDPOINTS.LOGIN, body)
10
+
11
+ const { accessToken, refreshToken, ...userData } = response.data
12
+
13
+ await setTokens(accessToken, refreshToken)
14
+
15
+ return NextResponse.json({ success: true, user: userData })
16
+
17
+ } catch (error: any) {
18
+ const status = error.response?.status || 500
19
+ const errorData = error.response?.data || { message: 'Login failed' }
20
+
21
+ return NextResponse.json(errorData, { status })
22
+ }
23
+ }
24
+ `;
25
+ export const nextServerAuthRefreshRoute = () => `import { instance } from "@/configs/axios/instance"
26
+ import { AUTH_ENDPOINTS, getTokens, setTokens, clearTokens } from "@/utils/jwt"
27
+ import { NextResponse } from "next/server"
28
+
29
+ export async function POST() {
30
+ const { refreshToken } = await getTokens()
31
+
32
+ if (!refreshToken) {
33
+ return NextResponse.json({ message: 'No refresh token' }, { status: 401 })
34
+ }
35
+
36
+ try {
37
+ const response = await instance.post(AUTH_ENDPOINTS.REFRESH, {
38
+ refresh: refreshToken
39
+ })
40
+
41
+ const { accessToken, refreshToken: newRefreshToken } = response.data
42
+
43
+ await setTokens(accessToken, newRefreshToken)
44
+
45
+ return NextResponse.json({ success: true })
46
+ } catch {
47
+ await clearTokens()
48
+ return NextResponse.json({ message: 'Refresh failed' }, { status: 401 })
49
+ }
50
+ }
51
+ `;
52
+ export const nextServerAuthLogoutRoute = () => `import { NextResponse } from 'next/server'
53
+ import { clearTokens } from '@/utils/jwt'
54
+
55
+ export async function POST() {
56
+ await clearTokens()
57
+ return NextResponse.json({ success: true })
58
+ }
59
+ `;
60
+ //# sourceMappingURL=nextServerJwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nextServerJwt.js","sourceRoot":"","sources":["../../../src/template/axios/nextServerJwt.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;CAuB7C,CAAA;AAED,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;CA0B/C,CAAA;AAED,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,EAAE,CAAC;;;;;;;CAO9C,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare const protectedProxy: () => string;
2
+ //# sourceMappingURL=protectedProxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protectedProxy.d.ts","sourceRoot":"","sources":["../../../src/template/axios/protectedProxy.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,cAsC1B,CAAA"}
@@ -0,0 +1,40 @@
1
+ export const protectedProxy = () => `import { NextResponse } from 'next/server';
2
+ import type { NextRequest } from 'next/server';
3
+ import { TOKEN_KEYS } from '@/utils/jwt';
4
+ import { PROTECTED_ROUTES, ROUTES } from '@/generated/path/routes';
5
+
6
+ export function proxy(request: NextRequest) {
7
+ const { pathname } = request.nextUrl;
8
+
9
+ const isProtectedRoute = PROTECTED_ROUTES.some((route) =>
10
+ pathname.startsWith(route)
11
+ );
12
+
13
+ if (isProtectedRoute) {
14
+ const hasAccessToken = request.cookies.has(TOKEN_KEYS.ACCESS);
15
+ const hasRefreshToken = request.cookies.has(TOKEN_KEYS.REFRESH);
16
+
17
+ if (!hasAccessToken && !hasRefreshToken) {
18
+ const loginUrl = new URL(ROUTES.LOGIN, request.url);
19
+ loginUrl.searchParams.set('redirect', pathname);
20
+ return NextResponse.redirect(loginUrl);
21
+ }
22
+ }
23
+
24
+ if (pathname === ROUTES.LOGIN) {
25
+ const hasRefreshToken = request.cookies.has(TOKEN_KEYS.REFRESH);
26
+ if (hasRefreshToken) {
27
+ return NextResponse.redirect(new URL(ROUTES.HOME, request.url));
28
+ }
29
+ }
30
+
31
+ return NextResponse.next();
32
+ }
33
+
34
+ export const config = {
35
+ matcher: [
36
+ '/((?!api|_next/static|_next/image|favicon.ico).*)',
37
+ ],
38
+ };
39
+ `;
40
+ //# sourceMappingURL=protectedProxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protectedProxy.js","sourceRoot":"","sources":["../../../src/template/axios/protectedProxy.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCnC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare const useLoginHook: () => string;
2
+ //# sourceMappingURL=useLoginHook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLoginHook.d.ts","sourceRoot":"","sources":["../../../src/template/axios/useLoginHook.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,cAexB,CAAA"}
@@ -0,0 +1,16 @@
1
+ export const useLoginHook = () => `import { CommonErrorType, UserLoginRequestType, UserLoginType } from "@/generated/api/@types/data-contracts"
2
+ import { useMutation } from "@tanstack/react-query"
3
+ import axios, { AxiosError } from "axios"
4
+
5
+ export const useLoginMutation = () => {
6
+ // TODO: Change to the actual login type from the API
7
+ return useMutation<UserLoginType, AxiosError<CommonErrorType>, UserLoginRequestType>({
8
+ mutationKey: ["AUTH_JWT_LOGIN_CREATE"],
9
+ mutationFn: async (data) => {
10
+ const res = await axios.post("/api/auth/login", data)
11
+ return res.data
12
+ },
13
+ })
14
+ }
15
+ `;
16
+ //# sourceMappingURL=useLoginHook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLoginHook.js","sourceRoot":"","sources":["../../../src/template/axios/useLoginHook.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GACvB,GAAG,EAAE,CAAC;;;;;;;;;;;;;;CAcP,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare const useLogoutHook: () => string;
2
+ //# sourceMappingURL=useLogoutHook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLogoutHook.d.ts","sourceRoot":"","sources":["../../../src/template/axios/useLogoutHook.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,cAazB,CAAA"}
@@ -0,0 +1,15 @@
1
+ export const useLogoutHook = () => `import { CommonErrorType } from "@/generated/api/@types/data-contracts"
2
+ import { useMutation } from "@tanstack/react-query"
3
+ import axios, { AxiosError } from "axios"
4
+
5
+ export const useLogoutMutation = () => {
6
+ return useMutation<void, AxiosError<CommonErrorType>, void>({
7
+ mutationKey: ["AUTH_JWT_LOGOUT_CREATE"],
8
+ mutationFn: async () => {
9
+ const res = await axios.post("/api/auth/logout")
10
+ return res.data
11
+ },
12
+ })
13
+ }
14
+ `;
15
+ //# sourceMappingURL=useLogoutHook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLogoutHook.js","sourceRoot":"","sources":["../../../src/template/axios/useLogoutHook.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC;;;;;;;;;;;;;CAalC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare const utilJwt: () => string;
2
+ //# sourceMappingURL=utilJwt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utilJwt.d.ts","sourceRoot":"","sources":["../../../src/template/axios/utilJwt.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,cAkDnB,CAAA"}
@@ -0,0 +1,52 @@
1
+ export const utilJwt = () => `import { cookies } from "next/headers"
2
+
3
+ export const AUTH_ENDPOINTS = {
4
+ LOGIN: "/v1/user/login/", // TODO: Change to the actual login endpoint
5
+ REFRESH: "/v1/user/refresh/",
6
+ }
7
+
8
+ export const TOKEN_KEYS = {
9
+ ACCESS: "accessToken",
10
+ REFRESH: "refreshToken",
11
+ } as const
12
+
13
+ const cookieOptions = {
14
+ httpOnly: true,
15
+ secure: process.env.NODE_ENV === "production",
16
+ sameSite: process.env.NODE_ENV === "production" ? "lax" : "none",
17
+ path: "/",
18
+ } as const
19
+
20
+ export async function setTokens(accessToken: string, refreshToken?: string) {
21
+ const cookieStore = await cookies()
22
+
23
+ cookieStore.set(TOKEN_KEYS.ACCESS, accessToken, {
24
+ ...cookieOptions,
25
+ maxAge: 60 * 15, // 15min
26
+ })
27
+
28
+ if (refreshToken) {
29
+ cookieStore.set(TOKEN_KEYS.REFRESH, refreshToken, {
30
+ ...cookieOptions,
31
+ maxAge: 60 * 60 * 24 * 7, // 7days
32
+ })
33
+ }
34
+ }
35
+
36
+ export async function clearTokens() {
37
+ const cookieStore = await cookies()
38
+
39
+ cookieStore.delete(TOKEN_KEYS.ACCESS)
40
+ cookieStore.delete(TOKEN_KEYS.REFRESH)
41
+ }
42
+
43
+ export async function getTokens() {
44
+ const cookieStore = await cookies()
45
+
46
+ return {
47
+ accessToken: cookieStore.get(TOKEN_KEYS.ACCESS)?.value,
48
+ refreshToken: cookieStore.get(TOKEN_KEYS.REFRESH)?.value,
49
+ }
50
+ }
51
+ `;
52
+ //# sourceMappingURL=utilJwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utilJwt.js","sourceRoot":"","sources":["../../../src/template/axios/utilJwt.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkD5B,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare const supabaseAuthActions: (isNeedAuth: boolean) => string;
2
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../../src/template/supabase/actions/auth.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,GAAI,YAAY,OAAO,WA6DtD,CAAA"}
@@ -0,0 +1,61 @@
1
+ export const supabaseAuthActions = (isNeedAuth) => `"use server"
2
+
3
+ ${!isNeedAuth ? `import { ROUTES } from "@/generated/path/routes"` : 'import { ENV } from "@/configs/env"'}
4
+ import { createClient } from "@/lib/supabase/server"
5
+ import { redirect } from "next/navigation"
6
+
7
+ export async function login(formData: FormData) {
8
+ const supabase = await createClient()
9
+ const email = formData.get("email") as string
10
+ const password = formData.get("password") as string
11
+
12
+ const { error } = await supabase.auth.signInWithPassword({
13
+ email,
14
+ password,
15
+ })
16
+
17
+ if (error) {
18
+ redirect(${isNeedAuth ? '"/login?message=login_failed"' : '"/"'})
19
+ }
20
+
21
+ redirect(${isNeedAuth ? '"/"' : "ROUTES.ADMIN"})
22
+ }
23
+
24
+ ${isNeedAuth
25
+ ? `export async function signup(formData: FormData) {
26
+ const supabase = await createClient()
27
+ const email = formData.get("email") as string
28
+ const password = formData.get("password") as string
29
+
30
+ const { error } = await supabase.auth.signUp({
31
+ email,
32
+ password,
33
+ })
34
+
35
+ if (error) {
36
+ redirect("/login?message=signup_failed")
37
+ }
38
+
39
+ redirect("/login?message=signup_success")
40
+ }
41
+
42
+ export async function signInWithGoogle() {
43
+ const supabase = await createClient()
44
+ const { data, error } = await supabase.auth.signInWithOAuth({
45
+ provider: "google",
46
+ options: {
47
+ redirectTo: \`\${ENV.DOMAIN}/api/auth/google/callback\`,
48
+ },
49
+ })
50
+
51
+ if (error) {
52
+ redirect("/login?message=signin_with_failed&provider=google")
53
+ }
54
+
55
+ if (data.url) {
56
+ redirect(data.url)
57
+ }
58
+ }`
59
+ : ""}
60
+ `;
61
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../src/template/supabase/actions/auth.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,UAAmB,EAAE,EAAE,CAAC;;EAE1D,CAAC,UAAU,CAAC,CAAC,CAAC,kDAAkD,CAAC,CAAC,CAAC,qCAAqC;;;;;;;;;;;;;;;eAe3F,UAAU,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,KAAK;;;aAGtD,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc;;;EAI9C,UAAU;IACR,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCJ;IACE,CAAC,CAAC,EACN;CACC,CAAA"}
@@ -0,0 +1,3 @@
1
+ export declare const supabaseCrudService: (tableName: string) => string;
2
+ export declare const supabaseCrudActions: (tableName: string) => string;
3
+ //# sourceMappingURL=crud.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../../../src/template/supabase/actions/crud.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,mBAAmB,GAAI,WAAW,MAAM,WAsCpD,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,WAAW,MAAM,WA8BpD,CAAA"}
@@ -0,0 +1,72 @@
1
+ import { capitalCase } from "change-case";
2
+ export const supabaseCrudService = (tableName) => `import "server-only"
3
+
4
+ import { createClient } from "@/lib/supabase/server"
5
+
6
+ const TABLE_NAME = "${tableName}"
7
+
8
+ export async function insert${capitalCase(tableName)}(title: string) {
9
+ const supabase = await createClient()
10
+ const { data, error } = await supabase
11
+ .from(TABLE_NAME)
12
+ .insert([{ title, is_completed: false }])
13
+ .select()
14
+ .single()
15
+
16
+ if (error) throw new Error(error.message)
17
+ return data
18
+ }
19
+
20
+ export async function modify${capitalCase(tableName)}(id: string, isCompleted: boolean) {
21
+ const supabase = await createClient()
22
+ const { data, error } = await supabase
23
+ .from(TABLE_NAME)
24
+ .update({ is_completed: isCompleted })
25
+ .eq("id", id)
26
+ .select()
27
+ .single()
28
+
29
+ if (error) throw new Error(error.message)
30
+ return data
31
+ }
32
+
33
+ export async function remove${capitalCase(tableName)}(id: string) {
34
+ const supabase = await createClient()
35
+ const { error } = await supabase.from(TABLE_NAME).delete().eq("id", id)
36
+
37
+ if (error) throw new Error(error.message)
38
+ return true
39
+ }
40
+ `;
41
+ export const supabaseCrudActions = (tableName) => `"use server"
42
+
43
+ import { insert${capitalCase(tableName)}, modify${capitalCase(tableName)}, remove${capitalCase(tableName)} } from "@/services/${tableName}.service"
44
+
45
+ export async function add${capitalCase(tableName)}Action(title: string) {
46
+ try {
47
+ const data = await insert${capitalCase(tableName)}(title)
48
+ return { success: true, data }
49
+ } catch (error: any) {
50
+ return { success: false, error: error.message }
51
+ }
52
+ }
53
+
54
+ export async function update${capitalCase(tableName)}Action(id: string, isCompleted: boolean) {
55
+ try {
56
+ const data = await modify${capitalCase(tableName)}(id, isCompleted)
57
+ return { success: true, data }
58
+ } catch (error: any) {
59
+ return { success: false, error: error.message }
60
+ }
61
+ }
62
+
63
+ export async function delete${capitalCase(tableName)}Action(id: string) {
64
+ try {
65
+ await remove${capitalCase(tableName)}(id)
66
+ return { success: true }
67
+ } catch (error: any) {
68
+ return { success: false, error: error.message }
69
+ }
70
+ }
71
+ `;
72
+ //# sourceMappingURL=crud.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crud.js","sourceRoot":"","sources":["../../../../src/template/supabase/actions/crud.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC;;;;sBAIpC,SAAS;;8BAED,WAAW,CAAC,SAAS,CAAC;;;;;;;;;;;;8BAYtB,WAAW,CAAC,SAAS,CAAC;;;;;;;;;;;;;8BAatB,WAAW,CAAC,SAAS,CAAC;;;;;;;CAOnD,CAAA;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC;;iBAEzC,WAAW,CAAC,SAAS,CAAC,WAAW,WAAW,CAAC,SAAS,CAAC,WAAW,WAAW,CAAC,SAAS,CAAC,uBAAuB,SAAS;;2BAE9G,WAAW,CAAC,SAAS,CAAC;;+BAElB,WAAW,CAAC,SAAS,CAAC;;;;;;;8BAOvB,WAAW,CAAC,SAAS,CAAC;;+BAErB,WAAW,CAAC,SAAS,CAAC;;;;;;;8BAOvB,WAAW,CAAC,SAAS,CAAC;;kBAElC,WAAW,CAAC,SAAS,CAAC;;;;;;CAMvC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare const supabaseUserActions: () => string;
2
+ //# sourceMappingURL=user.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../../src/template/supabase/actions/user.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,cAkC/B,CAAA"}
@@ -0,0 +1,36 @@
1
+ export const supabaseUserActions = () => `"use server"
2
+
3
+ import { createClient } from "@/lib/supabase/server"
4
+ import { SafeUserDefaultSchema, SafeUserDTO } from "@/schemas/user"
5
+ import { experimental_taintObjectReference as taintObjectReference } from "react"
6
+
7
+ export async function getUserAction(): Promise<SafeUserDTO> {
8
+ const supabase = await createClient()
9
+ const { data, error } = await supabase.auth.getUser()
10
+
11
+ if (error || !data.user) {
12
+ throw new Error("Not authenticated user")
13
+ }
14
+
15
+ taintObjectReference(
16
+ "Warning: Supabase original User object is not allowed to be directly returned to the client. Must pass through DTO.",
17
+ data.user,
18
+ )
19
+
20
+ if (data.user.user_metadata) {
21
+ taintObjectReference("Warning: user_metadata original object exposure risk", data.user.user_metadata)
22
+ }
23
+
24
+ const safeData = SafeUserDefaultSchema.parse({
25
+ id: data.user.id,
26
+ email: data.user.email,
27
+ phone: data.user.phone,
28
+ name: data.user.user_metadata?.full_name,
29
+ providers: data.user.app_metadata?.providers ?? ["email"],
30
+ avatarUrl: data.user.user_metadata?.avatar_url,
31
+ })
32
+
33
+ return safeData
34
+ }
35
+ `;
36
+ //# sourceMappingURL=user.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.js","sourceRoot":"","sources":["../../../../src/template/supabase/actions/user.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCxC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare const supabaseAdminLayout = "\"use client\"\n\nexport default function AdminPage() {\n return <div>AdminPage</div>\n}\n";
2
+ //# sourceMappingURL=supabaseAdminLayout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabaseAdminLayout.d.ts","sourceRoot":"","sources":["../../../../src/template/supabase/admin/supabaseAdminLayout.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,gGAK/B,CAAA"}
@@ -0,0 +1,7 @@
1
+ export const supabaseAdminLayout = `"use client"
2
+
3
+ export default function AdminPage() {
4
+ return <div>AdminPage</div>
5
+ }
6
+ `;
7
+ //# sourceMappingURL=supabaseAdminLayout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabaseAdminLayout.js","sourceRoot":"","sources":["../../../../src/template/supabase/admin/supabaseAdminLayout.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;CAKlC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare const supabaseAdminLoginLayout = "\"use client\"\n\nimport { login } from \"@/actions/auth.action\"\nimport { useState, useTransition } from \"react\"\n\nexport default function AdminLoginPage() {\n const [email, setEmail] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [isPending, startTransition] = useTransition()\n const [error, setError] = useState<string | null>(null)\n\n const handleLogin = async (e: React.SubmitEvent<HTMLFormElement>) => {\n e.preventDefault()\n setError(null)\n\n const formData = new FormData()\n formData.set(\"email\", email)\n formData.set(\"password\", password)\n\n startTransition(async () => {\n await login(formData)\n })\n }\n\n return (\n <div className=\"flex justify-center items-center min-h-screen bg-linear-to-br from-black to-zinc-900\">\n <div className=\"rounded-2xl shadow-xl bg-zinc-900 p-8 w-full max-w-md border border-gray-700\">\n <h1 className=\"text-3xl font-bold mb-1 text-center text-white\">Login</h1>\n <p className=\"mb-6 text-zinc-500 text-center\">Login as admin</p>\n <form onSubmit={handleLogin} className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"admin-email\" className=\"text-sm font-medium text-zinc-700\">\n Email\n </label>\n <input\n id=\"admin-email\"\n type=\"email\"\n value={email}\n autoComplete=\"off\"\n autoFocus\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"Enter Email\"\n required\n disabled={isPending}\n className=\"border border-gray-700 rounded-lg px-4 py-2 transition focus:outline-none focus:ring-1 ring-gray-500 bg-zinc-900 placeholder-white text-white autofill:bg-zinc-900 autofill:text-white\"\n style={{\n WebkitBoxShadow: \"0 0 0 1000px #18181b inset\",\n boxShadow: \"0 0 0 1000px #18181b inset\",\n WebkitTextFillColor: \"#fff\",\n }}\n />\n </div>\n <div className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"admin-password\" className=\"text-sm font-medium text-zinc-700\">\n Password\n </label>\n <input\n id=\"admin-password\"\n type=\"password\"\n value={password}\n autoComplete=\"off\"\n onChange={(e) => setPassword(e.target.value)}\n placeholder=\"Enter Password\"\n required\n disabled={isPending}\n className=\"border border-gray-700 rounded-lg px-4 py-2 transition focus:outline-none focus:ring-1 ring-gray-500 bg-zinc-900 placeholder-white text-white\"\n style={{\n WebkitBoxShadow: \"0 0 0 1000px #18181b inset\",\n boxShadow: \"0 0 0 1000px #18181b inset\",\n WebkitTextFillColor: \"#fff\",\n }}\n />\n </div>\n {error && (\n <div className=\"text-red-500 text-sm mt-1 rounded bg-red-50 p-2 border border-red-100 text-center animate-pulse\">\n {error}\n </div>\n )}\n <button\n type=\"submit\"\n disabled={isPending}\n className=\"mt-2 rounded-lg bg-blue-600 hover:bg-blue-700 transition text-white font-semibold py-2 shadow text-lg disabled:opacity-60 disabled:cursor-not-allowed\"\n >\n {isPending ? (\n <span className=\"flex justify-center items-center gap-2\">\n <svg className=\"animate-spin h-5 w-5 text-white\" viewBox=\"0 0 24 24\">\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n fill=\"none\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8v4l3-3-3-3v4a8 8 0 000 16v-4l-3 3 3 3v-4a8 8 0 01-8-8z\"\n />\n </svg>\n Logging in...\n </span>\n ) : (\n \"Submit\"\n )}\n </button>\n </form>\n </div>\n </div>\n )\n}\n";
2
+ //# sourceMappingURL=supabaseAdminLoginLayout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabaseAdminLoginLayout.d.ts","sourceRoot":"","sources":["../../../../src/template/supabase/admin/supabaseAdminLoginLayout.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,wBAAwB,85IAgHpC,CAAA"}
@@ -0,0 +1,114 @@
1
+ export const supabaseAdminLoginLayout = `"use client"
2
+
3
+ import { login } from "@/actions/auth.action"
4
+ import { useState, useTransition } from "react"
5
+
6
+ export default function AdminLoginPage() {
7
+ const [email, setEmail] = useState("")
8
+ const [password, setPassword] = useState("")
9
+ const [isPending, startTransition] = useTransition()
10
+ const [error, setError] = useState<string | null>(null)
11
+
12
+ const handleLogin = async (e: React.SubmitEvent<HTMLFormElement>) => {
13
+ e.preventDefault()
14
+ setError(null)
15
+
16
+ const formData = new FormData()
17
+ formData.set("email", email)
18
+ formData.set("password", password)
19
+
20
+ startTransition(async () => {
21
+ await login(formData)
22
+ })
23
+ }
24
+
25
+ return (
26
+ <div className="flex justify-center items-center min-h-screen bg-linear-to-br from-black to-zinc-900">
27
+ <div className="rounded-2xl shadow-xl bg-zinc-900 p-8 w-full max-w-md border border-gray-700">
28
+ <h1 className="text-3xl font-bold mb-1 text-center text-white">Login</h1>
29
+ <p className="mb-6 text-zinc-500 text-center">Login as admin</p>
30
+ <form onSubmit={handleLogin} className="flex flex-col gap-4">
31
+ <div className="flex flex-col gap-1.5">
32
+ <label htmlFor="admin-email" className="text-sm font-medium text-zinc-700">
33
+ Email
34
+ </label>
35
+ <input
36
+ id="admin-email"
37
+ type="email"
38
+ value={email}
39
+ autoComplete="off"
40
+ autoFocus
41
+ onChange={(e) => setEmail(e.target.value)}
42
+ placeholder="Enter Email"
43
+ required
44
+ disabled={isPending}
45
+ className="border border-gray-700 rounded-lg px-4 py-2 transition focus:outline-none focus:ring-1 ring-gray-500 bg-zinc-900 placeholder-white text-white autofill:bg-zinc-900 autofill:text-white"
46
+ style={{
47
+ WebkitBoxShadow: "0 0 0 1000px #18181b inset",
48
+ boxShadow: "0 0 0 1000px #18181b inset",
49
+ WebkitTextFillColor: "#fff",
50
+ }}
51
+ />
52
+ </div>
53
+ <div className="flex flex-col gap-1.5">
54
+ <label htmlFor="admin-password" className="text-sm font-medium text-zinc-700">
55
+ Password
56
+ </label>
57
+ <input
58
+ id="admin-password"
59
+ type="password"
60
+ value={password}
61
+ autoComplete="off"
62
+ onChange={(e) => setPassword(e.target.value)}
63
+ placeholder="Enter Password"
64
+ required
65
+ disabled={isPending}
66
+ className="border border-gray-700 rounded-lg px-4 py-2 transition focus:outline-none focus:ring-1 ring-gray-500 bg-zinc-900 placeholder-white text-white"
67
+ style={{
68
+ WebkitBoxShadow: "0 0 0 1000px #18181b inset",
69
+ boxShadow: "0 0 0 1000px #18181b inset",
70
+ WebkitTextFillColor: "#fff",
71
+ }}
72
+ />
73
+ </div>
74
+ {error && (
75
+ <div className="text-red-500 text-sm mt-1 rounded bg-red-50 p-2 border border-red-100 text-center animate-pulse">
76
+ {error}
77
+ </div>
78
+ )}
79
+ <button
80
+ type="submit"
81
+ disabled={isPending}
82
+ className="mt-2 rounded-lg bg-blue-600 hover:bg-blue-700 transition text-white font-semibold py-2 shadow text-lg disabled:opacity-60 disabled:cursor-not-allowed"
83
+ >
84
+ {isPending ? (
85
+ <span className="flex justify-center items-center gap-2">
86
+ <svg className="animate-spin h-5 w-5 text-white" viewBox="0 0 24 24">
87
+ <circle
88
+ className="opacity-25"
89
+ cx="12"
90
+ cy="12"
91
+ r="10"
92
+ stroke="currentColor"
93
+ strokeWidth="4"
94
+ fill="none"
95
+ />
96
+ <path
97
+ className="opacity-75"
98
+ fill="currentColor"
99
+ d="M4 12a8 8 0 018-8v4l3-3-3-3v4a8 8 0 000 16v-4l-3 3 3 3v-4a8 8 0 01-8-8z"
100
+ />
101
+ </svg>
102
+ Logging in...
103
+ </span>
104
+ ) : (
105
+ "Submit"
106
+ )}
107
+ </button>
108
+ </form>
109
+ </div>
110
+ </div>
111
+ )
112
+ }
113
+ `;
114
+ //# sourceMappingURL=supabaseAdminLoginLayout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabaseAdminLoginLayout.js","sourceRoot":"","sources":["../../../../src/template/supabase/admin/supabaseAdminLoginLayout.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgHvC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare const adminProxy = "import { ENV } from \"@/configs/env\"\nimport { createServerClient } from \"@supabase/ssr\"\nimport { NextResponse, type NextRequest } from \"next/server\"\n\nexport async function proxy(request: NextRequest) {\n let supabaseResponse = NextResponse.next({ request })\n const { pathname } = request.nextUrl\n\n const isAdminRoute = pathname.startsWith(\"/admin\")\n\n if (isAdminRoute) {\n if (pathname.startsWith(\"/admin/login\")) {\n return supabaseResponse\n }\n\n const supabase = createServerClient(ENV.SUPABASE_URL!, ENV.SUPABASE_ANON_KEY!, {\n cookies: {\n getAll() {\n return request.cookies.getAll()\n },\n setAll(cookiesToSet) {\n cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))\n supabaseResponse = NextResponse.next({ request })\n cookiesToSet.forEach(({ name, value, options }) => supabaseResponse.cookies.set(name, value, options))\n },\n },\n })\n\n const {\n data: { user },\n } = await supabase.auth.getUser()\n\n if (!user || user.id !== ENV.SUPABASE_ADMIN_UID) {\n return NextResponse.redirect(new URL(\"/\", request.url))\n }\n }\n\n return supabaseResponse\n}\n\nexport const config = {\n matcher: [\"/((?!_next/static|_next/image|favicon.ico|.*\\\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)\"],\n}\n";
2
+ //# sourceMappingURL=adminProxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adminProxy.d.ts","sourceRoot":"","sources":["../../../../src/template/supabase/proxy/adminProxy.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,u1CA2CtB,CAAA"}