ta_data_mas 0.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 (219) hide show
  1. package/README.md +42 -0
  2. package/apps/api/.prettierrc +4 -0
  3. package/apps/api/README.md +98 -0
  4. package/apps/api/drizzle/0000_right_drax.sql +87 -0
  5. package/apps/api/drizzle/meta/0000_snapshot.json +588 -0
  6. package/apps/api/drizzle/meta/_journal.json +13 -0
  7. package/apps/api/drizzle.config.ts +12 -0
  8. package/apps/api/eslint.config.mjs +35 -0
  9. package/apps/api/nest-cli.json +8 -0
  10. package/apps/api/package.json +99 -0
  11. package/apps/api/src/app.controller.spec.ts +25 -0
  12. package/apps/api/src/app.controller.ts +9 -0
  13. package/apps/api/src/app.module.ts +37 -0
  14. package/apps/api/src/app.service.ts +8 -0
  15. package/apps/api/src/auth/auth.controller.ts +113 -0
  16. package/apps/api/src/auth/auth.module.ts +15 -0
  17. package/apps/api/src/auth/auth.service.ts +309 -0
  18. package/apps/api/src/auth/decorators/current-user-decorator.ts +10 -0
  19. package/apps/api/src/auth/decorators/require-org-role-decorator.ts +7 -0
  20. package/apps/api/src/auth/dto/login.dto.ts +10 -0
  21. package/apps/api/src/auth/dto/register.dto.ts +14 -0
  22. package/apps/api/src/auth/guards/jwt-auth-guard.ts +40 -0
  23. package/apps/api/src/auth/guards/org-role.guards.ts +60 -0
  24. package/apps/api/src/db/db.module.ts +9 -0
  25. package/apps/api/src/db/drizzle.service.ts +16 -0
  26. package/apps/api/src/db/schema/index.ts +6 -0
  27. package/apps/api/src/db/schema/organizations.ts +30 -0
  28. package/apps/api/src/db/schema/projects.ts +26 -0
  29. package/apps/api/src/db/schema/query-history.ts +16 -0
  30. package/apps/api/src/db/schema/storage-buckets.ts +17 -0
  31. package/apps/api/src/db/schema/storage-objects.ts +18 -0
  32. package/apps/api/src/db/schema/users.ts +14 -0
  33. package/apps/api/src/main.ts +51 -0
  34. package/apps/api/src/members/dto/invite-member-dto.ts +6 -0
  35. package/apps/api/src/members/dto/update-role.dto.ts +8 -0
  36. package/apps/api/src/members/invite.service.ts +147 -0
  37. package/apps/api/src/members/members.controller.ts +56 -0
  38. package/apps/api/src/members/members.module.ts +13 -0
  39. package/apps/api/src/members/members.service.ts +85 -0
  40. package/apps/api/src/orgs/dto/create-org.dto.ts +8 -0
  41. package/apps/api/src/orgs/orgs.controller.ts +27 -0
  42. package/apps/api/src/orgs/orgs.module.ts +12 -0
  43. package/apps/api/src/orgs/orgs.service.ts +86 -0
  44. package/apps/api/src/project-api/project-api.controller.ts +95 -0
  45. package/apps/api/src/project-api/project-api.module.ts +12 -0
  46. package/apps/api/src/project-api/project-api.service.ts +196 -0
  47. package/apps/api/src/project-api/project-key.guard.ts +45 -0
  48. package/apps/api/src/project-api/query-parser.ts +129 -0
  49. package/apps/api/src/project-auth/dto/magic-link.dto.ts +7 -0
  50. package/apps/api/src/project-auth/dto/signin.dto.ts +10 -0
  51. package/apps/api/src/project-auth/dto/signup.dto.ts +11 -0
  52. package/apps/api/src/project-auth/project-auth-dashboard.controller.ts +35 -0
  53. package/apps/api/src/project-auth/project-auth.controller.ts +111 -0
  54. package/apps/api/src/project-auth/project-auth.module.ts +13 -0
  55. package/apps/api/src/project-auth/project-auth.service.ts +440 -0
  56. package/apps/api/src/projects/dto/create-project.dto.ts +9 -0
  57. package/apps/api/src/projects/projects.controller.ts +34 -0
  58. package/apps/api/src/projects/projects.module.ts +12 -0
  59. package/apps/api/src/projects/projects.service.ts +136 -0
  60. package/apps/api/src/realtime/realtime-socket.type.ts +14 -0
  61. package/apps/api/src/realtime/realtime.controller.ts +63 -0
  62. package/apps/api/src/realtime/realtime.gateway.ts +150 -0
  63. package/apps/api/src/realtime/realtime.module.ts +14 -0
  64. package/apps/api/src/realtime/realtime.service.ts +101 -0
  65. package/apps/api/src/realtime/trigger.service.ts +95 -0
  66. package/apps/api/src/sql-editor/dto/execute-query.dto.ts +7 -0
  67. package/apps/api/src/sql-editor/sql-editor.controller.ts +28 -0
  68. package/apps/api/src/sql-editor/sql-editor.module.ts +12 -0
  69. package/apps/api/src/sql-editor/sql-editor.service.ts +154 -0
  70. package/apps/api/src/storage/project-storage.controller.ts +140 -0
  71. package/apps/api/src/storage/storage.controller.ts +118 -0
  72. package/apps/api/src/storage/storage.module.ts +15 -0
  73. package/apps/api/src/storage/storage.service.ts +191 -0
  74. package/apps/api/src/storage/uploadthing.ts +23 -0
  75. package/apps/api/src/table-editor/dto/alter-table.dto.ts +15 -0
  76. package/apps/api/src/table-editor/dto/create-table.dto.ts +54 -0
  77. package/apps/api/src/table-editor/table-editor.controller.ts +117 -0
  78. package/apps/api/src/table-editor/table-editor.module.ts +12 -0
  79. package/apps/api/src/table-editor/table-editor.service.ts +366 -0
  80. package/apps/api/test/app.e2e-spec.ts +29 -0
  81. package/apps/api/test/jest-e2e.json +9 -0
  82. package/apps/api/tsconfig.build.json +4 -0
  83. package/apps/api/tsconfig.json +25 -0
  84. package/apps/web/.env.example +12 -0
  85. package/apps/web/AGENTS.md +9 -0
  86. package/apps/web/CLAUDE.md +1 -0
  87. package/apps/web/README.md +36 -0
  88. package/apps/web/components.json +25 -0
  89. package/apps/web/eslint.config.mjs +18 -0
  90. package/apps/web/next.config.ts +11 -0
  91. package/apps/web/package.json +48 -0
  92. package/apps/web/postcss.config.mjs +7 -0
  93. package/apps/web/public/file.svg +1 -0
  94. package/apps/web/public/globe.svg +1 -0
  95. package/apps/web/public/logo.svg +4 -0
  96. package/apps/web/public/next.svg +1 -0
  97. package/apps/web/public/vercel.svg +1 -0
  98. package/apps/web/public/window.svg +1 -0
  99. package/apps/web/src/app/(dashboard)/layout.tsx +33 -0
  100. package/apps/web/src/app/(dashboard)/organizations/(list)/layout.tsx +7 -0
  101. package/apps/web/src/app/(dashboard)/organizations/(list)/new/page.tsx +26 -0
  102. package/apps/web/src/app/(dashboard)/organizations/(list)/page.tsx +44 -0
  103. package/apps/web/src/app/(dashboard)/organizations/[slug]/[projectSlug]/api/page.tsx +13 -0
  104. package/apps/web/src/app/(dashboard)/organizations/[slug]/[projectSlug]/auth/layout.tsx +19 -0
  105. package/apps/web/src/app/(dashboard)/organizations/[slug]/[projectSlug]/auth/page.tsx +10 -0
  106. package/apps/web/src/app/(dashboard)/organizations/[slug]/[projectSlug]/auth/providers/page.tsx +19 -0
  107. package/apps/web/src/app/(dashboard)/organizations/[slug]/[projectSlug]/auth/url-configuration/page.tsx +24 -0
  108. package/apps/web/src/app/(dashboard)/organizations/[slug]/[projectSlug]/auth/users/page.tsx +13 -0
  109. package/apps/web/src/app/(dashboard)/organizations/[slug]/[projectSlug]/database/page.tsx +29 -0
  110. package/apps/web/src/app/(dashboard)/organizations/[slug]/[projectSlug]/realtime/page.tsx +28 -0
  111. package/apps/web/src/app/(dashboard)/organizations/[slug]/[projectSlug]/sql/page.tsx +21 -0
  112. package/apps/web/src/app/(dashboard)/organizations/[slug]/[projectSlug]/storage/page.tsx +28 -0
  113. package/apps/web/src/app/(dashboard)/organizations/[slug]/layout.tsx +20 -0
  114. package/apps/web/src/app/(dashboard)/organizations/[slug]/projects/page.tsx +62 -0
  115. package/apps/web/src/app/(dashboard)/organizations/[slug]/settings/members/page.tsx +28 -0
  116. package/apps/web/src/app/(dashboard)/organizations/[slug]/settings/page.tsx +10 -0
  117. package/apps/web/src/app/(dashboard)/settings/page.tsx +12 -0
  118. package/apps/web/src/app/dashboard/page.tsx +14 -0
  119. package/apps/web/src/app/favicon.ico +0 -0
  120. package/apps/web/src/app/globals.css +115 -0
  121. package/apps/web/src/app/layout.tsx +36 -0
  122. package/apps/web/src/app/login/page.tsx +199 -0
  123. package/apps/web/src/app/page.tsx +100 -0
  124. package/apps/web/src/app/register/page.tsx +218 -0
  125. package/apps/web/src/components/app-sidebar.tsx +301 -0
  126. package/apps/web/src/components/navbar.tsx +63 -0
  127. package/apps/web/src/components/topNav.tsx +68 -0
  128. package/apps/web/src/components/ui/avatar.tsx +112 -0
  129. package/apps/web/src/components/ui/badge.tsx +48 -0
  130. package/apps/web/src/components/ui/button.tsx +66 -0
  131. package/apps/web/src/components/ui/card.tsx +102 -0
  132. package/apps/web/src/components/ui/checkbox.tsx +32 -0
  133. package/apps/web/src/components/ui/dialog.tsx +168 -0
  134. package/apps/web/src/components/ui/dropdown-menu.tsx +269 -0
  135. package/apps/web/src/components/ui/field.tsx +238 -0
  136. package/apps/web/src/components/ui/input.tsx +19 -0
  137. package/apps/web/src/components/ui/label.tsx +24 -0
  138. package/apps/web/src/components/ui/resizable.tsx +50 -0
  139. package/apps/web/src/components/ui/scroll-area.tsx +55 -0
  140. package/apps/web/src/components/ui/select.tsx +192 -0
  141. package/apps/web/src/components/ui/separator.tsx +28 -0
  142. package/apps/web/src/components/ui/sheet.tsx +147 -0
  143. package/apps/web/src/components/ui/sidebar.tsx +703 -0
  144. package/apps/web/src/components/ui/skeleton.tsx +13 -0
  145. package/apps/web/src/components/ui/switch.tsx +33 -0
  146. package/apps/web/src/components/ui/table.tsx +116 -0
  147. package/apps/web/src/components/ui/tooltip.tsx +57 -0
  148. package/apps/web/src/features/api-docs/api-docs-client.tsx +227 -0
  149. package/apps/web/src/features/api-docs/api-docs-helpers.server.ts +86 -0
  150. package/apps/web/src/features/auth/action.ts +67 -0
  151. package/apps/web/src/features/auth/client.schema.ts +13 -0
  152. package/apps/web/src/features/auth/constants.ts +6 -0
  153. package/apps/web/src/features/auth/cookies.ts +86 -0
  154. package/apps/web/src/features/auth/server.schema.ts +11 -0
  155. package/apps/web/src/features/auth/sign-out.ts +17 -0
  156. package/apps/web/src/features/members/action.ts +66 -0
  157. package/apps/web/src/features/members/client.schema.ts +11 -0
  158. package/apps/web/src/features/members/constants.ts +8 -0
  159. package/apps/web/src/features/members/members-client.tsx +198 -0
  160. package/apps/web/src/features/members/members-helpers.server.ts +21 -0
  161. package/apps/web/src/features/members/server.schema.ts +19 -0
  162. package/apps/web/src/features/organization/action.ts +45 -0
  163. package/apps/web/src/features/organization/client.schema.ts +5 -0
  164. package/apps/web/src/features/organization/constants.tsx +3 -0
  165. package/apps/web/src/features/organization/create-org-form.tsx +66 -0
  166. package/apps/web/src/features/organization/organization-helpers.server.ts +35 -0
  167. package/apps/web/src/features/organization/server.schema.ts +10 -0
  168. package/apps/web/src/features/project-auth/project-auth-action.ts +78 -0
  169. package/apps/web/src/features/project-auth/project-auth-client.schema.ts +18 -0
  170. package/apps/web/src/features/project-auth/project-auth-constants.ts +8 -0
  171. package/apps/web/src/features/project-auth/project-auth-helpers.server.ts +39 -0
  172. package/apps/web/src/features/project-auth/project-auth-providers.tsx +222 -0
  173. package/apps/web/src/features/project-auth/project-auth-server.schema.ts +22 -0
  174. package/apps/web/src/features/project-auth/project-auth-shell.tsx +106 -0
  175. package/apps/web/src/features/project-auth/project-auth-url-config.tsx +151 -0
  176. package/apps/web/src/features/project-auth/project-auth-users.tsx +138 -0
  177. package/apps/web/src/features/projects/action.ts +46 -0
  178. package/apps/web/src/features/projects/client.schema.ts +9 -0
  179. package/apps/web/src/features/projects/constants.ts +6 -0
  180. package/apps/web/src/features/projects/create-project-modal.tsx +117 -0
  181. package/apps/web/src/features/projects/project-helpers.server.ts +38 -0
  182. package/apps/web/src/features/projects/server.schema.ts +10 -0
  183. package/apps/web/src/features/realtime/realtime-client.tsx +294 -0
  184. package/apps/web/src/features/realtime/realtime-helpers.server.ts +40 -0
  185. package/apps/web/src/features/sql-editor/sql-editor-client.tsx +324 -0
  186. package/apps/web/src/features/sql-editor/sql-editor-helpers.server.ts +22 -0
  187. package/apps/web/src/features/storage/storage-client.tsx +500 -0
  188. package/apps/web/src/features/storage/storage-helpers.server.ts +36 -0
  189. package/apps/web/src/features/table-editor/action.ts +97 -0
  190. package/apps/web/src/features/table-editor/add-column-dialog.tsx +184 -0
  191. package/apps/web/src/features/table-editor/client.schema.ts +36 -0
  192. package/apps/web/src/features/table-editor/create-table-drawer.tsx +542 -0
  193. package/apps/web/src/features/table-editor/server.schema.ts +41 -0
  194. package/apps/web/src/features/table-editor/table-editor-client.tsx +737 -0
  195. package/apps/web/src/features/table-editor/table-editor-helpers.server.ts +39 -0
  196. package/apps/web/src/hooks/use-mobile.ts +19 -0
  197. package/apps/web/src/lib/axios.ts +8 -0
  198. package/apps/web/src/lib/utils.ts +6 -0
  199. package/apps/web/src/proxy.ts +72 -0
  200. package/apps/web/src/server-utils/utils.ts +10 -0
  201. package/apps/web/tsconfig.json +34 -0
  202. package/package.json +22 -0
  203. package/packages/apiDatabase-js/package.json +39 -0
  204. package/packages/apiDatabase-js/src/auth/index.ts +121 -0
  205. package/packages/apiDatabase-js/src/client.ts +25 -0
  206. package/packages/apiDatabase-js/src/db/index.ts +15 -0
  207. package/packages/apiDatabase-js/src/db/query-builder.ts +194 -0
  208. package/packages/apiDatabase-js/src/index.ts +16 -0
  209. package/packages/apiDatabase-js/src/realtime/index.ts +84 -0
  210. package/packages/apiDatabase-js/src/storage/index.ts +130 -0
  211. package/packages/apiDatabase-js/tsconfig.json +13 -0
  212. package/packages/apiDatabase-js/tsdown.config.ts +20 -0
  213. package/packages/constants/package.json +6 -0
  214. package/packages/constants/src/index.ts +76 -0
  215. package/packages/tsconfig.json +13 -0
  216. package/packages/tsdown.config.ts +20 -0
  217. package/packages/types/package.json +6 -0
  218. package/packages/types/src/index.ts +254 -0
  219. package/pnpm-workspace.yaml +10 -0
@@ -0,0 +1,39 @@
1
+ import { redirect } from "next/navigation";
2
+ import apiClient from "@/lib/axios";
3
+ import { retrieveTokenFromCookie } from "@/server-utils/utils";
4
+ import { COOKIE_KEYS } from "@apiDatabase/constants";
5
+ import type { Project } from "@apiDatabase/types";
6
+
7
+ export async function retrieveTablesFromApi(
8
+ orgSlug: string,
9
+ projectSlug: string,
10
+ ): Promise<string[]> {
11
+ const token = await retrieveTokenFromCookie();
12
+
13
+ try {
14
+ const { data } = await apiClient.get<string[]>(
15
+ `/orgs/${orgSlug}/projects/${projectSlug}/tables`,
16
+ { headers: { Cookie: `${COOKIE_KEYS.ACCESS_TOKEN}=${token}` } },
17
+ );
18
+ return data;
19
+ } catch {
20
+ redirect(`/organizations/${orgSlug}/projects`);
21
+ }
22
+ }
23
+
24
+ export async function retrieveProjectDbSchema(
25
+ orgSlug: string,
26
+ projectSlug: string,
27
+ ): Promise<string> {
28
+ const token = await retrieveTokenFromCookie();
29
+
30
+ try {
31
+ const { data } = await apiClient.get<{ projects: Project }>(
32
+ `/orgs/${orgSlug}/projects/${projectSlug}`,
33
+ { headers: { Cookie: `${COOKIE_KEYS.ACCESS_TOKEN}=${token}` } },
34
+ );
35
+ return data.projects.dbSchema;
36
+ } catch {
37
+ redirect(`/organizations/${orgSlug}/projects`);
38
+ }
39
+ }
@@ -0,0 +1,19 @@
1
+ import * as React from "react"
2
+
3
+ const MOBILE_BREAKPOINT = 768
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
7
+
8
+ React.useEffect(() => {
9
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
10
+ const onChange = () => {
11
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
12
+ }
13
+ mql.addEventListener("change", onChange)
14
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
15
+ return () => mql.removeEventListener("change", onChange)
16
+ }, [])
17
+
18
+ return !!isMobile
19
+ }
@@ -0,0 +1,8 @@
1
+ import axios from "axios";
2
+
3
+ const apiClient = axios.create({
4
+ baseURL: process.env.NEXT_PUBLIC_API_URL ?? process.env.API_URL,
5
+ withCredentials: true,
6
+ });
7
+
8
+ export default apiClient;
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -0,0 +1,72 @@
1
+ import { NextResponse } from "next/server";
2
+ import type { NextRequest } from "next/server";
3
+ import { COOKIE_KEYS } from "@apiDatabase/constants";
4
+ import * as jose from "jose";
5
+ import { applyAuthCookiesToResponse } from "@/features/auth/cookies";
6
+
7
+ const AUTH_ROUTES = ["/login", "/register"];
8
+
9
+ async function refreshSession(
10
+ refreshToken: string,
11
+ response: NextResponse,
12
+ ): Promise<boolean> {
13
+ const apiUrl = process.env.API_URL;
14
+ if (!apiUrl) return false;
15
+
16
+ const refreshRes = await fetch(`${apiUrl}/auth/refresh`, {
17
+ method: "POST",
18
+ headers: { Cookie: `${COOKIE_KEYS.REFRESH_TOKEN}=${refreshToken}` },
19
+ });
20
+
21
+ if (!refreshRes.ok) return false;
22
+
23
+ applyAuthCookiesToResponse(response, refreshRes.headers.getSetCookie());
24
+ return true;
25
+ }
26
+
27
+ export async function proxy(request: NextRequest) {
28
+ const { pathname } = request.nextUrl;
29
+ const accessToken = request.cookies.get(COOKIE_KEYS.ACCESS_TOKEN)?.value;
30
+ const refreshToken = request.cookies.get(COOKIE_KEYS.REFRESH_TOKEN)?.value;
31
+
32
+ const isAuthRoute = AUTH_ROUTES.some((r) => pathname.startsWith(r));
33
+ const isProtected =
34
+ pathname.startsWith("/organizations") || pathname.startsWith("/dashboard");
35
+
36
+ let isValid = false;
37
+ if (accessToken && process.env.JWT_ACCESS_SECRET) {
38
+ try {
39
+ const secret = new TextEncoder().encode(process.env.JWT_ACCESS_SECRET);
40
+ await jose.jwtVerify(accessToken, secret);
41
+ isValid = true;
42
+ } catch {
43
+ // token is expired or invalid: invalid remains false
44
+ }
45
+ }
46
+
47
+ if (isAuthRoute && isValid) {
48
+ return NextResponse.redirect(new URL("/dashboard", request.url));
49
+ }
50
+
51
+ if (isAuthRoute && refreshToken) {
52
+ const response = NextResponse.redirect(new URL("/dashboard", request.url));
53
+ if (await refreshSession(refreshToken, response)) {
54
+ return response;
55
+ }
56
+ }
57
+ if (isProtected && !isValid) {
58
+ if (refreshToken) {
59
+ const response = NextResponse.next();
60
+ if (await refreshSession(refreshToken, response)) {
61
+ return response;
62
+ }
63
+ }
64
+ return NextResponse.redirect(new URL("/login", request.url));
65
+ }
66
+
67
+ return NextResponse.next();
68
+ }
69
+
70
+ export const config = {
71
+ matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
72
+ };
@@ -0,0 +1,10 @@
1
+ import { cookies } from "next/headers";
2
+ import { redirect } from "next/navigation";
3
+ import { COOKIE_KEYS } from "@apiDatabase/constants";
4
+
5
+ export async function retrieveTokenFromCookie(): Promise<string> {
6
+ const cookieStore = await cookies();
7
+ const token = cookieStore.get(COOKIE_KEYS.ACCESS_TOKEN)?.value;
8
+ if (!token) redirect("/login");
9
+ return token;
10
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./src/*"]
23
+ }
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ "**/*.ts",
28
+ "**/*.tsx",
29
+ ".next/types/**/*.ts",
30
+ ".next/dev/types/**/*.ts",
31
+ "**/*.mts"
32
+ ],
33
+ "exclude": ["node_modules"]
34
+ }
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "ta_data_mas",
3
+ "private": false,
4
+ "version": "0.0.2",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "API's",
8
+ "Postgres SQL",
9
+ "data"
10
+ ],
11
+ "scripts": {
12
+ "dev:api": "pnpm --filter api run start:dev",
13
+ "dev:web": "pnpm --filter web run dev",
14
+ "dev": "concurrently \"pnpm run dev:api\" \"pnpm run dev:web\"",
15
+ "build": "pnpm -r --if-present run build",
16
+ "test": "pnpm --filter api test"
17
+ },
18
+ "packageManager": "pnpm@11.17.0",
19
+ "devDependencies": {
20
+ "concurrently": "^10.0.5"
21
+ }
22
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "ta_data_mas-js",
3
+ "version": "1.0.0",
4
+ "description": "The official Javascript SDK for Api_Database",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsdown",
17
+ "dev": "tsdown --watch"
18
+ },
19
+ "keywords": [
20
+ "backend",
21
+ "database",
22
+ "realtime",
23
+ "auth",
24
+ "storage"
25
+ ],
26
+ "author": "argyrios",
27
+ "license": "ISC",
28
+ "type": "module",
29
+ "dependencies": {
30
+ "@apiDatabase/constants": "workspace:*",
31
+ "socket.io-client": "^4.8.3",
32
+ "uploadthing": "^7.7.4"
33
+ },
34
+ "devDependencies": {
35
+ "@apiDatabase/types": "workspace:*",
36
+ "tsdown": "^0.22.14",
37
+ "typescript": "^6.0.3"
38
+ }
39
+ }
@@ -0,0 +1,121 @@
1
+ interface AuthUser {
2
+ id: string;
3
+ email: string;
4
+ }
5
+
6
+ export interface AuthResult {
7
+ data: { user: AuthUser; accessToken: string } | null;
8
+ error: string | null;
9
+ }
10
+
11
+ export class ApiDatabaseAuth {
12
+ private currentToken: string | null = null;
13
+
14
+ constructor(private projectUrl: string) {}
15
+
16
+ async signUp(credentials: {
17
+ email: string;
18
+ password: string;
19
+ }): Promise<AuthResult> {
20
+ try {
21
+ const res = await fetch(`${this.projectUrl}/auth/signup`, {
22
+ method: "POST",
23
+ headers: { "Content-Type": "application/json" },
24
+ body: JSON.stringify(credentials),
25
+ });
26
+
27
+ if (!res.ok) {
28
+ const err = (await res.json().catch(() => ({}))) as {
29
+ message?: string;
30
+ };
31
+ return { data: null, error: err.message ?? "Sign up failed" };
32
+ }
33
+
34
+ const data = (await res.json()) as {
35
+ user: AuthUser;
36
+ accessToken: string;
37
+ };
38
+ this.currentToken = data.accessToken;
39
+ return { data, error: null };
40
+ } catch (err: unknown) {
41
+ const message = err instanceof Error ? err.message : "Network error";
42
+ return { data: null, error: message };
43
+ }
44
+ }
45
+
46
+ async signIn(credentials: {
47
+ email: string;
48
+ password: string;
49
+ }): Promise<AuthResult> {
50
+ try {
51
+ const res = await fetch(`${this.projectUrl}/auth/signin`, {
52
+ method: "POST",
53
+ headers: { "Content-Type": "application/json" },
54
+ body: JSON.stringify(credentials),
55
+ });
56
+
57
+ if (!res.ok) {
58
+ const err = (await res.json().catch(() => ({}))) as {
59
+ message?: string;
60
+ };
61
+ return { data: null, error: err.message ?? "Sign in failed" };
62
+ }
63
+
64
+ const data = (await res.json()) as {
65
+ user: AuthUser;
66
+ accessToken: string;
67
+ };
68
+ this.currentToken = data.accessToken;
69
+ return { data, error: null };
70
+ } catch (err: unknown) {
71
+ const message = err instanceof Error ? err.message : "Network error";
72
+ return { data: null, error: message };
73
+ }
74
+ }
75
+
76
+ async sendMagicLink(email: string): Promise<{ error: string | null }> {
77
+ try {
78
+ const res = await fetch(`${this.projectUrl}/auth/magic-link`, {
79
+ method: "POST",
80
+ headers: { "Content-Type": "application/json" },
81
+ body: JSON.stringify({ email }),
82
+ });
83
+
84
+ if (!res.ok) return { error: "Failed to send magic link" };
85
+ return { error: null };
86
+ } catch (err: unknown) {
87
+ const message = err instanceof Error ? err.message : "Network error";
88
+ return { error: message };
89
+ }
90
+ }
91
+
92
+ signInWithGoogle(): void {
93
+ window.location.href = `${this.projectUrl}/auth/google`;
94
+ }
95
+
96
+ signInWithGithub(): void {
97
+ window.location.href = `${this.projectUrl}/auth/github`;
98
+ }
99
+
100
+ signOut(): void {
101
+ this.currentToken = null;
102
+ }
103
+
104
+ getUser(): AuthUser | null {
105
+ if (!this.currentToken) return null;
106
+
107
+ try {
108
+ const payload = JSON.parse(atob(this.currentToken.split(".")[1])) as {
109
+ sub: string;
110
+ email: string;
111
+ };
112
+ return { id: payload.sub, email: payload.email };
113
+ } catch {
114
+ return null;
115
+ }
116
+ }
117
+
118
+ getAccessToken(): string | null {
119
+ return this.currentToken;
120
+ }
121
+ }
@@ -0,0 +1,25 @@
1
+ import { ApiDatabaseDb } from "./db";
2
+ import { apiDatabaseRealtime } from "./realtime";
3
+ import { ApiDatabaseStorage } from "./storage";
4
+ import { ApiDatabaseAuth } from "./auth";
5
+
6
+ export class ApiDatabaseClient {
7
+ readonly db: ApiDatabaseDb;
8
+ readonly realtime: apiDatabaseRealtime;
9
+ readonly storage: ApiDatabaseStorage;
10
+ readonly auth: ApiDatabaseAuth;
11
+
12
+ constructor(
13
+ private projectUrl: string,
14
+ private apiKey: string,
15
+ ) {
16
+ this.db = new ApiDatabaseDb(projectUrl, apiKey);
17
+ this.realtime = new apiDatabaseRealtime(projectUrl, apiKey);
18
+ this.storage = new ApiDatabaseStorage(projectUrl, apiKey);
19
+ this.auth = new ApiDatabaseAuth(projectUrl);
20
+ }
21
+
22
+ from<T = Record<string, unknown>>(table: string) {
23
+ return this.db.from<T>(table);
24
+ }
25
+ }
@@ -0,0 +1,15 @@
1
+ import { QueryBuilder } from "./query-builder";
2
+
3
+ export class ApiDatabaseDb {
4
+ constructor(
5
+ private projectUrl: string,
6
+ private apiKey: string,
7
+ ) {}
8
+
9
+ from<T = Record<string, unknown>>(table: string): QueryBuilder<T> {
10
+ return new QueryBuilder<T>(this.projectUrl, table, this.apiKey);
11
+ }
12
+ }
13
+
14
+ export { QueryBuilder } from "./query-builder";
15
+ export type { QueryResult } from "./query-builder";
@@ -0,0 +1,194 @@
1
+ export type HttpMethod = "GET" | "POST" | "PATCH" | "DELETE";
2
+
3
+ interface FilterClause {
4
+ column: string;
5
+ operator: string;
6
+ value: string;
7
+ }
8
+
9
+ export interface QueryResult<T> {
10
+ data: T | null;
11
+ error: string | null;
12
+ }
13
+
14
+ export class QueryBuilder<T = Record<string, unknown>> {
15
+ private _method: HttpMethod = "GET";
16
+ private _body: Record<string, unknown> | null = null;
17
+ private _filters: FilterClause[] = [];
18
+ private _selectColumns: string[] = [];
19
+ private _orderCol: string | null = null;
20
+ private _orderDir: "asc" | "desc" = "asc";
21
+ private _limitVal: number | null = null;
22
+ private _offsetVal: number | null = null;
23
+
24
+ constructor(
25
+ private projectUrl: string,
26
+ private table: string,
27
+ private apiKey: string,
28
+ ) {}
29
+
30
+ select(columns = "*"): this {
31
+ this._selectColumns =
32
+ columns === "*" ? [] : columns.split(",").map((c) => c.trim());
33
+ return this;
34
+ }
35
+
36
+ eq(column: string, value: unknown): this {
37
+ this._filters.push({ column, operator: "eq", value: String(value) });
38
+ return this;
39
+ }
40
+
41
+ neq(column: string, value: unknown): this {
42
+ this._filters.push({ column, operator: "neq", value: String(value) });
43
+ return this;
44
+ }
45
+
46
+ gt(column: string, value: unknown): this {
47
+ this._filters.push({ column, operator: "gt", value: String(value) });
48
+ return this;
49
+ }
50
+
51
+ gte(column: string, value: unknown): this {
52
+ this._filters.push({ column, operator: "gte", value: String(value) });
53
+ return this;
54
+ }
55
+
56
+ lt(column: string, value: unknown): this {
57
+ this._filters.push({ column, operator: "lt", value: String(value) });
58
+ return this;
59
+ }
60
+
61
+ lte(column: string, value: unknown): this {
62
+ this._filters.push({ column, operator: "lte", value: String(value) });
63
+ return this;
64
+ }
65
+
66
+ like(column: string, pattern: string): this {
67
+ this._filters.push({ column, operator: "like", value: pattern });
68
+ return this;
69
+ }
70
+
71
+ ilike(column: string, pattern: string): this {
72
+ this._filters.push({ column, operator: "ilike", value: pattern });
73
+ return this;
74
+ }
75
+
76
+ is(column: string, value: "null" | "not null"): this {
77
+ this._filters.push({
78
+ column,
79
+ operator: "is",
80
+ value: value === "null" ? "null" : "not null",
81
+ });
82
+ return this;
83
+ }
84
+
85
+ order(column: string, direction: "asc" | "desc" = "asc"): this {
86
+ this._orderCol = column;
87
+ this._orderDir = direction;
88
+ return this;
89
+ }
90
+
91
+ limit(n: number): this {
92
+ this._limitVal = n;
93
+ return this;
94
+ }
95
+
96
+ offset(n: number): this {
97
+ this._offsetVal = n;
98
+ return this;
99
+ }
100
+
101
+ insert(data: Record<string, unknown>): this {
102
+ this._method = "POST";
103
+ this._body = data;
104
+ return this;
105
+ }
106
+
107
+ update(data: Record<string, unknown>): this {
108
+ this._method = "PATCH";
109
+ this._body = data;
110
+ return this;
111
+ }
112
+
113
+ delete(): this {
114
+ this._method = "DELETE";
115
+ return this;
116
+ }
117
+
118
+ private getRowIdForMutation(): string {
119
+ const idFilter = this._filters.find(
120
+ (f) => f.column === "id" && f.operator === "eq",
121
+ );
122
+ if (!idFilter) {
123
+ throw new Error(
124
+ 'update() and delete() require .eq("id", rowId) before executing',
125
+ );
126
+ }
127
+ return idFilter.value;
128
+ }
129
+
130
+ private buildUrl(): string {
131
+ const base = `${this.projectUrl}/rest/${this.table}`;
132
+
133
+ if (this._method === "PATCH" || this._method === "DELETE") {
134
+ return `${base}/${this.getRowIdForMutation()}`;
135
+ }
136
+
137
+ const params = new URLSearchParams();
138
+
139
+ if (this._selectColumns.length > 0) {
140
+ params.set("select", this._selectColumns.join(","));
141
+ }
142
+
143
+ for (const { column, operator, value } of this._filters) {
144
+ params.set(column, `${operator}.${value}`);
145
+ }
146
+
147
+ if (this._orderCol) {
148
+ params.set("order", `${this._orderCol}.${this._orderDir}`);
149
+ }
150
+
151
+ if (this._limitVal !== null) params.set("limit", String(this._limitVal));
152
+ if (this._offsetVal !== null) params.set("offset", String(this._offsetVal));
153
+
154
+ const query = params.toString();
155
+ return query ? `${base}?${query}` : base;
156
+ }
157
+
158
+ async execute(): Promise<QueryResult<T | T[]>> {
159
+ try {
160
+ const res = await fetch(this.buildUrl(), {
161
+ method: this._method,
162
+ headers: {
163
+ Authorization: `Bearer ${this.apiKey}`,
164
+ "Content-Type": "application/json",
165
+ },
166
+ body: this._body ? JSON.stringify(this._body) : undefined,
167
+ });
168
+
169
+ if (!res.ok) {
170
+ const err = (await res.json().catch(() => ({}))) as {
171
+ message?: string;
172
+ };
173
+ return { data: null, error: err.message ?? `HTTP ${res.status}` };
174
+ }
175
+
176
+ if (res.status === 204) return { data: null, error: null };
177
+
178
+ const data = (await res.json()) as T | T[];
179
+ return { data, error: null };
180
+ } catch (err: unknown) {
181
+ const message = err instanceof Error ? err.message : "Network error";
182
+ return { data: null, error: message };
183
+ }
184
+ }
185
+
186
+ then<TResult1 = QueryResult<T | T[]>, TResult2 = never>(
187
+ onfulfilled?:
188
+ | ((value: QueryResult<T | T[]>) => TResult1 | PromiseLike<TResult1>)
189
+ | null,
190
+ onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,
191
+ ): Promise<TResult1 | TResult2> {
192
+ return this.execute().then(onfulfilled, onrejected);
193
+ }
194
+ }
@@ -0,0 +1,16 @@
1
+ import { ApiDatabaseClient } from "./client";
2
+
3
+ export function createClient(
4
+ projectUrl: string,
5
+ apiKey: string,
6
+ ): ApiDatabaseClient {
7
+ return new ApiDatabaseClient(projectUrl, apiKey);
8
+ }
9
+
10
+ export { ApiDatabaseClient } from "./client";
11
+ export { QueryBuilder, ApiDatabaseDb } from "./db";
12
+ export type { QueryResult } from "./db";
13
+ export { apiDatabaseRealtime } from "./realtime";
14
+ export type { RealtimeCallback } from "./realtime";
15
+ export { ApiDatabaseStorage } from "./storage";
16
+ export { ApiDatabaseAuth } from "./auth";