├── .env ├── .github └── workflows │ ├── build.yml │ └── update.yml ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── postcss.config.js ├── prisma ├── migrations │ ├── 20230905040838_init │ │ └── migration.sql │ ├── 20241222160427_add_space_owner │ │ └── migration.sql │ └── migration_lock.toml └── schema.prisma ├── schema.zmodel ├── src ├── app.css ├── app.d.ts ├── app.html ├── components │ └── List.svelte ├── hooks.server.ts ├── lib │ ├── auth.ts │ ├── components │ │ ├── Avatar.svelte │ │ ├── BreadCrumb.svelte │ │ ├── CreateListDialog.svelte │ │ ├── ManageMembers.svelte │ │ ├── NavBar.svelte │ │ ├── SpaceMembers.svelte │ │ ├── Spaces.svelte │ │ ├── TimeInfo.svelte │ │ ├── Todo.svelte │ │ └── TodoList.svelte │ ├── constant.ts │ ├── hooks │ │ ├── __model_meta.ts │ │ ├── index.ts │ │ ├── list.ts │ │ ├── space-user.ts │ │ ├── space.ts │ │ ├── todo.ts │ │ └── user.ts │ └── prisma.ts └── routes │ ├── (app) │ ├── +layout.server.ts │ ├── +layout.svelte │ ├── +page.server.ts │ ├── +page.svelte │ ├── create-space │ │ ├── +page.server.ts │ │ └── +page.svelte │ └── space │ │ └── [slug] │ │ ├── +layout.server.ts │ │ ├── +page.server.ts │ │ ├── +page.svelte │ │ └── [listId] │ │ ├── +page.server.ts │ │ └── +page.svelte │ ├── (auth) │ ├── signin │ │ ├── +page.server.ts │ │ └── +page.svelte │ └── signup │ │ ├── +page.server.ts │ │ └── +page.svelte │ ├── +layout.svelte │ └── api │ └── auth │ ├── signin │ └── +server.ts │ └── signout │ └── +server.ts ├── static ├── auth-bg.jpg ├── avatar.jpg └── logo.png ├── svelte.config.js ├── tailwind.config.js ├── tsconfig.json └── vite.config.js /.env: -------------------------------------------------------------------------------- 1 | DATABASE_URL=postgres://postgres:abc123@localhost:5432/todo-sveltekit 2 | DATABASE_DIRECT_URL=postgres://postgres:abc123@localhost:5432/todo-sveltekit 3 | JWT_SECRET=secret -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | env: 4 | DO_NOT_TRACK: '1' 5 | 6 | on: 7 | push: 8 | branches: ['main'] 9 | pull_request: 10 | branches: ['main'] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | - name: Use Node.js 20.x 19 | uses: actions/setup-node@v3 20 | with: 21 | node-version: 20.x 22 | cache: 'npm' 23 | - run: npm ci 24 | - run: npm run build 25 | -------------------------------------------------------------------------------- /.github/workflows/update.yml: -------------------------------------------------------------------------------- 1 | name: Update ZenStack 2 | 3 | env: 4 | DO_NOT_TRACK: '1' 5 | 6 | on: 7 | workflow_dispatch: 8 | repository_dispatch: 9 | types: [zenstack-release] 10 | 11 | jobs: 12 | update: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Update to latest ZenStack 18 | run: | 19 | git config --global user.name ymc9 20 | git config --global user.email yiming@whimslab.io 21 | npm ci 22 | npm run up 23 | 24 | - name: Build 25 | run: | 26 | npm run build 27 | 28 | - name: Commit and push 29 | run: | 30 | git add . 31 | git commit -m "chore: update to latest ZenStack" || true 32 | git push || true 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | *.db 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

ZenStack SaaS Demo

4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | # ZenStack Todo Sample With SvelteKit 13 | 14 | This project is a collaborative Todo app built with [SvelteKit](https://kit.svelte.dev/) and [ZenStack](https://zenstack.dev). 15 | 16 | In this fictitious app, users can be invited to workspaces where they can collaborate on todos. Public todo lists are visible to all members in the workspace. 17 | 18 | ## Live deployment 19 | https://sample-todo-sveltekit.vercel.app/ 20 | 21 | ## Features 22 | 23 | - User signup/signin 24 | - Creating workspaces and inviting members 25 | - Data segregation and permission control 26 | 27 | ## Running the sample 28 | 29 | 1. Setup a new database 30 | 31 | It use PostgreSQL by default, if you want to use MySQL, simply change the db datasource provider to `mysql` in `schema.zmodel` file. 32 | 33 | You can launch a PostgreSQL instance locally, or create one from a hoster like [Supabase](https://supabase.com). Create a new database for this app, and set the connection string in .env file. 34 | 35 | 1. Install dependencies 36 | 37 | ```bash 38 | npm install 39 | ``` 40 | 41 | 1. Generate server and client-side code from model 42 | 43 | ```bash 44 | npm run generate 45 | ``` 46 | 47 | 1. Synchronize database schema 48 | 49 | ```bash 50 | npm run db:push 51 | ``` 52 | 53 | 1. Start dev server 54 | 55 | ```bash 56 | npm run dev 57 | ``` 58 | 59 | 60 | 61 | ## Feedback and Issues 62 | If you encounter any issue or have any feedback, please create a new issue in our main repository so we could respond to it promptly: 63 | 64 | [https://github.com/zenstackhq/zenstack](https://github.com/zenstackhq/zenstack) 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rest-sveltekit", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "generate": "zenstack generate", 7 | "dev": "vite dev", 8 | "build": "npm run generate && vite build", 9 | "vercel-build": "npm run build && npm run db:deploy", 10 | "preview": "vite preview", 11 | "db:push": "prisma db push", 12 | "db:migrate": "prisma migrate dev", 13 | "db:deploy": "prisma migrate deploy", 14 | "db:reset": "prisma migrate reset", 15 | "db:browse": "prisma studio", 16 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 17 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 18 | "package-clean": "npm rm zenstack @zenstackhq/runtime @zenstackhq/server @zenstackhq/tanstack-query", 19 | "up": "npm run package-clean && npm install -D zenstack@latest && npm install @zenstackhq/runtime@latest @zenstackhq/server@latest @zenstackhq/tanstack-query@latest", 20 | "up-preview": "npm run package-clean && npm install --registry https://preview.registry.zenstack.dev -D zenstack@latest && npm install --registry https://preview.registry.zenstack.dev @zenstackhq/runtime@latest @zenstackhq/server@latest @zenstackhq/tanstack-query@latest" 21 | }, 22 | "devDependencies": { 23 | "@sveltejs/adapter-auto": "^2.1.0", 24 | "@sveltejs/kit": "^1.22.4", 25 | "@sveltejs/package": "^2.2.0", 26 | "@tailwindcss/line-clamp": "^0.4.4", 27 | "@types/bcryptjs": "^2.4.2", 28 | "@types/jsonwebtoken": "^9.0.1", 29 | "@typescript-eslint/eslint-plugin": "^5.45.0", 30 | "@typescript-eslint/parser": "^5.45.0", 31 | "autoprefixer": "^10.4.14", 32 | "eslint": "^8.28.0", 33 | "eslint-config-prettier": "^8.5.0", 34 | "postcss": "^8.4.23", 35 | "prettier": "^2.8.0", 36 | "prettier-plugin-svelte": "^2.8.1", 37 | "prisma": "^6.5.0", 38 | "svelte": "^4.1.2", 39 | "svelte-check": "^3.4.6", 40 | "tailwindcss": "^3.3.2", 41 | "ts-node": "10.9.1", 42 | "tslib": "^2.4.1", 43 | "typescript": "^5.8.2", 44 | "vite": "^4.4.4", 45 | "zenstack": "^2.15.0" 46 | }, 47 | "type": "module", 48 | "dependencies": { 49 | "@prisma/client": "^6.5.0", 50 | "@steeze-ui/heroicons": "^2.2.3", 51 | "@steeze-ui/svelte-icon": "^1.5.0", 52 | "@tanstack/svelte-query": "^4.32.6", 53 | "@zenstackhq/runtime": "^2.15.0", 54 | "@zenstackhq/server": "^2.15.0", 55 | "@zenstackhq/tanstack-query": "^2.15.0", 56 | "bcryptjs": "^2.4.3", 57 | "daisyui": "^2.51.5", 58 | "jsonwebtoken": "^9.0.0", 59 | "moment": "^2.29.4", 60 | "nanoid": "^4.0.2", 61 | "superjson": "^1.12.3", 62 | "zod": "3.21.1", 63 | "zod-validation-error": "^1.3.0" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /prisma/migrations/20230905040838_init/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateEnum 2 | CREATE TYPE "SpaceUserRole" AS ENUM ('USER', 'ADMIN'); 3 | 4 | -- CreateTable 5 | CREATE TABLE "Space" ( 6 | "id" TEXT NOT NULL, 7 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 8 | "updatedAt" TIMESTAMP(3) NOT NULL, 9 | "name" TEXT NOT NULL, 10 | "slug" TEXT NOT NULL, 11 | 12 | CONSTRAINT "Space_pkey" PRIMARY KEY ("id") 13 | ); 14 | 15 | -- CreateTable 16 | CREATE TABLE "SpaceUser" ( 17 | "id" TEXT NOT NULL, 18 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 19 | "updatedAt" TIMESTAMP(3) NOT NULL, 20 | "spaceId" TEXT NOT NULL, 21 | "userId" TEXT NOT NULL, 22 | "role" "SpaceUserRole" NOT NULL, 23 | 24 | CONSTRAINT "SpaceUser_pkey" PRIMARY KEY ("id") 25 | ); 26 | 27 | -- CreateTable 28 | CREATE TABLE "User" ( 29 | "id" TEXT NOT NULL, 30 | "email" TEXT NOT NULL, 31 | "password" TEXT NOT NULL, 32 | "name" TEXT, 33 | 34 | CONSTRAINT "User_pkey" PRIMARY KEY ("id") 35 | ); 36 | 37 | -- CreateTable 38 | CREATE TABLE "List" ( 39 | "id" TEXT NOT NULL, 40 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 41 | "updatedAt" TIMESTAMP(3) NOT NULL, 42 | "spaceId" TEXT NOT NULL, 43 | "ownerId" TEXT NOT NULL, 44 | "title" TEXT NOT NULL, 45 | "private" BOOLEAN NOT NULL DEFAULT false, 46 | 47 | CONSTRAINT "List_pkey" PRIMARY KEY ("id") 48 | ); 49 | 50 | -- CreateTable 51 | CREATE TABLE "Todo" ( 52 | "id" TEXT NOT NULL, 53 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 54 | "updatedAt" TIMESTAMP(3) NOT NULL, 55 | "ownerId" TEXT NOT NULL, 56 | "listId" TEXT NOT NULL, 57 | "title" TEXT NOT NULL, 58 | "completedAt" TIMESTAMP(3), 59 | 60 | CONSTRAINT "Todo_pkey" PRIMARY KEY ("id") 61 | ); 62 | 63 | -- CreateIndex 64 | CREATE UNIQUE INDEX "Space_slug_key" ON "Space"("slug"); 65 | 66 | -- CreateIndex 67 | CREATE UNIQUE INDEX "SpaceUser_userId_spaceId_key" ON "SpaceUser"("userId", "spaceId"); 68 | 69 | -- CreateIndex 70 | CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); 71 | 72 | -- AddForeignKey 73 | ALTER TABLE "SpaceUser" ADD CONSTRAINT "SpaceUser_spaceId_fkey" FOREIGN KEY ("spaceId") REFERENCES "Space"("id") ON DELETE CASCADE ON UPDATE CASCADE; 74 | 75 | -- AddForeignKey 76 | ALTER TABLE "SpaceUser" ADD CONSTRAINT "SpaceUser_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; 77 | 78 | -- AddForeignKey 79 | ALTER TABLE "List" ADD CONSTRAINT "List_spaceId_fkey" FOREIGN KEY ("spaceId") REFERENCES "Space"("id") ON DELETE CASCADE ON UPDATE CASCADE; 80 | 81 | -- AddForeignKey 82 | ALTER TABLE "List" ADD CONSTRAINT "List_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; 83 | 84 | -- AddForeignKey 85 | ALTER TABLE "Todo" ADD CONSTRAINT "Todo_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; 86 | 87 | -- AddForeignKey 88 | ALTER TABLE "Todo" ADD CONSTRAINT "Todo_listId_fkey" FOREIGN KEY ("listId") REFERENCES "List"("id") ON DELETE CASCADE ON UPDATE CASCADE; 89 | -------------------------------------------------------------------------------- /prisma/migrations/20241222160427_add_space_owner/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - Added the required column `ownerId` to the `Space` table without a default value. This is not possible if the table is not empty. 5 | 6 | */ 7 | -- AlterTable 8 | ALTER TABLE "Space" ADD COLUMN "ownerId" TEXT NOT NULL; 9 | 10 | -- AddForeignKey 11 | ALTER TABLE "Space" ADD CONSTRAINT "Space_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; 12 | -------------------------------------------------------------------------------- /prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (e.g., Git) 3 | provider = "postgresql" -------------------------------------------------------------------------------- /prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////// 2 | // DO NOT MODIFY THIS FILE // 3 | // This file is automatically generated by ZenStack CLI and should not be manually updated. // 4 | ////////////////////////////////////////////////////////////////////////////////////////////// 5 | 6 | datasource db { 7 | provider = "postgresql" 8 | url = env("DATABASE_URL") 9 | directUrl = env("DATABASE_DIRECT_URL") 10 | } 11 | 12 | generator client { 13 | provider = "prisma-client-js" 14 | } 15 | 16 | enum SpaceUserRole { 17 | USER 18 | ADMIN 19 | } 20 | 21 | model Space { 22 | id String @id() @default(uuid()) 23 | createdAt DateTime @default(now()) 24 | updatedAt DateTime @updatedAt() 25 | owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) 26 | ownerId String 27 | name String 28 | slug String @unique() 29 | members SpaceUser[] 30 | lists List[] 31 | } 32 | 33 | model SpaceUser { 34 | id String @id() @default(uuid()) 35 | createdAt DateTime @default(now()) 36 | updatedAt DateTime @updatedAt() 37 | space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade) 38 | spaceId String 39 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 40 | userId String 41 | role SpaceUserRole 42 | 43 | @@unique([userId, spaceId]) 44 | } 45 | 46 | model User { 47 | id String @id() @default(cuid()) 48 | email String @unique() 49 | password String 50 | name String? 51 | ownedSpaces Space[] 52 | memberships SpaceUser[] 53 | todos Todo[] 54 | lists List[] 55 | } 56 | 57 | model List { 58 | id String @id() @default(uuid()) 59 | createdAt DateTime @default(now()) 60 | updatedAt DateTime @updatedAt() 61 | space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade) 62 | spaceId String 63 | owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) 64 | ownerId String 65 | title String 66 | private Boolean @default(false) 67 | todos Todo[] 68 | } 69 | 70 | model Todo { 71 | id String @id() @default(uuid()) 72 | createdAt DateTime @default(now()) 73 | updatedAt DateTime @updatedAt() 74 | owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) 75 | ownerId String 76 | list List @relation(fields: [listId], references: [id], onDelete: Cascade) 77 | listId String 78 | title String 79 | completedAt DateTime? 80 | } 81 | -------------------------------------------------------------------------------- /schema.zmodel: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | } 4 | 5 | datasource db { 6 | provider = 'postgresql' 7 | url = env('DATABASE_URL') 8 | directUrl = env('DATABASE_DIRECT_URL') 9 | } 10 | 11 | /* 12 | * Enum for user's role in a space 13 | */ 14 | enum SpaceUserRole { 15 | USER 16 | ADMIN 17 | } 18 | 19 | plugin hooks { 20 | provider = '@zenstackhq/tanstack-query' 21 | output = 'src/lib/hooks' 22 | target = 'svelte' 23 | } 24 | 25 | /* 26 | * Model for a space in which users can collaborate on Lists and Todos 27 | */ 28 | model Space { 29 | id String @id @default(uuid()) 30 | createdAt DateTime @default(now()) 31 | updatedAt DateTime @updatedAt 32 | owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) 33 | ownerId String @default(auth().id) 34 | name String @length(4, 50) 35 | slug String @unique @regex('^[0-9a-zA-Z\-_]{4,16}$') 36 | members SpaceUser[] 37 | lists List[] 38 | 39 | // require login 40 | @@deny('all', auth() == null) 41 | 42 | // everyone can create a space 43 | @@allow('create', true) 44 | 45 | // any user in the space can read the space 46 | @@allow('read', members?[user == auth()]) 47 | 48 | // space admin can update and delete 49 | @@allow('update,delete', members?[user == auth() && role == ADMIN]) 50 | } 51 | 52 | /* 53 | * Model representing membership of a user in a space 54 | */ 55 | model SpaceUser { 56 | id String @id @default(uuid()) 57 | createdAt DateTime @default(now()) 58 | updatedAt DateTime @updatedAt 59 | space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade) 60 | spaceId String 61 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 62 | userId String 63 | role SpaceUserRole 64 | @@unique([userId, spaceId]) 65 | 66 | // require login 67 | @@deny('all', auth() == null) 68 | 69 | // space owner can add any one 70 | @@allow('create', space.owner == auth()) 71 | 72 | // space admin can add anyone but not himself 73 | @@allow('create', auth() != user && space.members?[user == auth() && role == ADMIN]) 74 | 75 | // space admin can update/delete 76 | @@allow('update,delete', space.members?[user == auth() && role == ADMIN]) 77 | 78 | // user can read entries for spaces which he's a member of 79 | @@allow('read', space.members?[user == auth()]) 80 | } 81 | 82 | /* 83 | * User model 84 | */ 85 | model User { 86 | id String @id @default(cuid()) 87 | email String @unique @email 88 | password String @password @omit @length(6, 32) 89 | name String? 90 | ownedSpaces Space[] 91 | memberships SpaceUser[] 92 | todos Todo[] 93 | lists List[] 94 | @@allow('create,read', true) 95 | @@allow('all', auth() == this) 96 | } 97 | 98 | /* 99 | * Model for a Todo list 100 | */ 101 | model List { 102 | id String @id @default(uuid()) 103 | createdAt DateTime @default(now()) 104 | updatedAt DateTime @updatedAt 105 | space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade) 106 | spaceId String 107 | owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) 108 | ownerId String @default(auth().id) 109 | title String @length(1, 100) 110 | private Boolean @default(false) 111 | todos Todo[] 112 | 113 | // require login 114 | @@deny('all', auth() == null) 115 | 116 | // can be read by owner or space members (only if not private) 117 | @@allow('read', owner == auth() || (space.members?[user == auth()] && !private)) 118 | 119 | // when create, owner must be set to current user, and user must be in the space 120 | @@allow('create', owner == auth() && space.members?[user == auth()]) 121 | 122 | // when create, owner must be set to current user, and user must be in the space 123 | // update is not allowed to change owner 124 | @@allow('update', owner == auth() && space.members?[user == auth()] && future().owner == owner) 125 | 126 | // can be deleted by owner 127 | @@allow('delete', owner == auth()) 128 | } 129 | 130 | /* 131 | * Model for a single Todo 132 | */ 133 | model Todo { 134 | id String @id @default(uuid()) 135 | createdAt DateTime @default(now()) 136 | updatedAt DateTime @updatedAt 137 | owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) 138 | ownerId String @default(auth().id) 139 | list List @relation(fields: [listId], references: [id], onDelete: Cascade) 140 | listId String 141 | title String @length(1, 100) 142 | completedAt DateTime? 143 | 144 | // require login 145 | @@deny('all', auth() == null) 146 | 147 | // owner has full access, also space members have full access (if the parent List is not private) 148 | @@allow('all', list.owner == auth()) 149 | @@allow('all', list.space.members?[user == auth()] && !list.private) 150 | 151 | // update cannot change owner 152 | @@deny('update', future().owner != owner) 153 | } 154 | -------------------------------------------------------------------------------- /src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | 4 | import type { PrismaClient, User } from '@prisma/client'; 5 | 6 | declare global { 7 | namespace App { 8 | interface Locals { 9 | user?: User; 10 | db: PrismaClient; 11 | } 12 | } 13 | } 14 | 15 | export {}; 16 | -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /src/components/List.svelte: -------------------------------------------------------------------------------- 1 | 25 | 26 |
27 | {#if $posts.data} 28 | {#each $posts.data.pages as page} 29 | {#each page as post (post.id)} 30 |
  • {post.title} by {post.author.email}
  • 31 | {/each} 32 | {/each} 33 | {/if} 34 | {#if $posts.hasNextPage} 35 | 36 | {/if} 37 |
    38 | -------------------------------------------------------------------------------- /src/hooks.server.ts: -------------------------------------------------------------------------------- 1 | import { env } from '$env/dynamic/private'; 2 | import { JWT_TOKEN_COOKIE_NAME } from '$lib/constant'; 3 | import prisma, { getEnhancedPrisma } from '$lib/prisma'; 4 | import type { Handle } from '@sveltejs/kit'; 5 | import { sequence } from '@sveltejs/kit/hooks'; 6 | import zenstack from '@zenstackhq/server/sveltekit'; 7 | import jwt from 'jsonwebtoken'; 8 | 9 | const auth = (async ({ event, resolve }) => { 10 | const token = event.cookies.get(JWT_TOKEN_COOKIE_NAME); 11 | if (token) { 12 | try { 13 | const decoded = jwt.verify(token, env.JWT_SECRET); 14 | const user = await prisma.user.findUnique({ 15 | where: { id: decoded.sub as string }, 16 | }); 17 | if (user) { 18 | event.locals.user = user; 19 | } else { 20 | console.warn('User not found:', decoded.sub); 21 | event.cookies.delete(JWT_TOKEN_COOKIE_NAME, { path: '/' }); 22 | } 23 | } catch { 24 | event.cookies.delete(JWT_TOKEN_COOKIE_NAME, { path: '/' }); 25 | } 26 | } 27 | 28 | event.locals.db = getEnhancedPrisma( 29 | event.locals.user ? event.locals.user.id : undefined 30 | ); 31 | 32 | return resolve(event); 33 | }) satisfies Handle; 34 | 35 | const crud = zenstack.SvelteKitHandler({ 36 | prefix: '/api/model', 37 | getPrisma: (event) => event.locals.db, 38 | }); 39 | 40 | export const handle = sequence(auth, crud); 41 | -------------------------------------------------------------------------------- /src/lib/auth.ts: -------------------------------------------------------------------------------- 1 | import { env } from '$env/dynamic/private'; 2 | import type { User } from '@prisma/client'; 3 | import jwt from 'jsonwebtoken'; 4 | 5 | export function createToken(user: User) { 6 | return jwt.sign( 7 | { 8 | sub: user.id, 9 | email: user.email, 10 | }, 11 | env.JWT_SECRET, 12 | { expiresIn: '7d' } 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/components/Avatar.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
    9 | avatar 15 |
    16 | -------------------------------------------------------------------------------- /src/lib/components/BreadCrumb.svelte: -------------------------------------------------------------------------------- 1 | 24 | 25 | 38 | -------------------------------------------------------------------------------- /src/lib/components/CreateListDialog.svelte: -------------------------------------------------------------------------------- 1 | 41 | 42 |
    43 | 49 | 95 |
    96 | -------------------------------------------------------------------------------- /src/lib/components/ManageMembers.svelte: -------------------------------------------------------------------------------- 1 | 67 | 68 |
    69 |
    74 | 81 | 82 | 86 | 87 | 90 |
    91 | 92 | 117 |
    118 | -------------------------------------------------------------------------------- /src/lib/components/NavBar.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 47 | -------------------------------------------------------------------------------- /src/lib/components/SpaceMembers.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |
    13 | 16 | 17 |
    18 | 23 |
    24 | 25 | 26 | 27 | 44 |
    45 | -------------------------------------------------------------------------------- /src/lib/components/Spaces.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 21 | -------------------------------------------------------------------------------- /src/lib/components/TimeInfo.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |

    12 | {value.completedAt 13 | ? `Completed ${moment(value.completedAt).fromNow()}` 14 | : value.createdAt === value.updatedAt 15 | ? `Created ${moment(value.createdAt).fromNow()}` 16 | : `Updated ${moment(value.updatedAt).fromNow()}`} 17 |

    18 | -------------------------------------------------------------------------------- /src/lib/components/Todo.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    17 |
    18 |

    25 | {value.title} 26 |

    27 |
    28 |
    34 | 35 | completeForm.submit()} 41 | /> 42 |
    43 |
    49 | 50 | 56 |
    57 |
    58 |
    59 |
    60 | 61 | 62 |
    63 |
    64 | -------------------------------------------------------------------------------- /src/lib/components/TodoList.svelte: -------------------------------------------------------------------------------- 1 | 30 | 31 |
    32 | 33 |
    34 | Cover 41 |
    42 |
    43 |
    44 | 45 |

    46 | {value.title || 'Missing Title'} 47 |

    48 |
    49 |
    50 |
    51 | 52 |
    53 |
    54 | 55 | {#if value.private} 56 |
    57 | 58 |
    59 | {/if} 60 |
    61 | 62 | 68 |
    69 |
    70 |
    71 |
    72 |
    73 | -------------------------------------------------------------------------------- /src/lib/constant.ts: -------------------------------------------------------------------------------- 1 | export const JWT_TOKEN_COOKIE_NAME = 'ZenStack-Todo-Token'; 2 | -------------------------------------------------------------------------------- /src/lib/hooks/__model_meta.ts: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file was generated by ZenStack CLI. 3 | ******************************************************************************/ 4 | 5 | /* eslint-disable */ 6 | // @ts-nocheck 7 | 8 | const metadata = { 9 | models: { 10 | space: { 11 | name: 'Space', fields: { 12 | id: { 13 | name: "id", 14 | type: "String", 15 | isId: true, 16 | attributes: [{ "name": "@default", "args": [] }], 17 | }, createdAt: { 18 | name: "createdAt", 19 | type: "DateTime", 20 | attributes: [{ "name": "@default", "args": [] }], 21 | }, updatedAt: { 22 | name: "updatedAt", 23 | type: "DateTime", 24 | attributes: [{ "name": "@updatedAt", "args": [] }], 25 | }, owner: { 26 | name: "owner", 27 | type: "User", 28 | isDataModel: true, 29 | backLink: 'ownedSpaces', 30 | isRelationOwner: true, 31 | onDeleteAction: 'Cascade', 32 | foreignKeyMapping: { "id": "ownerId" }, 33 | }, ownerId: { 34 | name: "ownerId", 35 | type: "String", 36 | attributes: [{ "name": "@default", "args": [] }], 37 | defaultValueProvider: $default$Space$ownerId, 38 | isForeignKey: true, 39 | relationField: 'owner', 40 | }, name: { 41 | name: "name", 42 | type: "String", 43 | }, slug: { 44 | name: "slug", 45 | type: "String", 46 | }, members: { 47 | name: "members", 48 | type: "SpaceUser", 49 | isDataModel: true, 50 | isArray: true, 51 | backLink: 'space', 52 | }, lists: { 53 | name: "lists", 54 | type: "List", 55 | isDataModel: true, 56 | isArray: true, 57 | backLink: 'space', 58 | }, 59 | }, uniqueConstraints: { 60 | id: { 61 | name: "id", 62 | fields: ["id"] 63 | }, slug: { 64 | name: "slug", 65 | fields: ["slug"] 66 | }, 67 | }, 68 | }, 69 | spaceUser: { 70 | name: 'SpaceUser', fields: { 71 | id: { 72 | name: "id", 73 | type: "String", 74 | isId: true, 75 | attributes: [{ "name": "@default", "args": [] }], 76 | }, createdAt: { 77 | name: "createdAt", 78 | type: "DateTime", 79 | attributes: [{ "name": "@default", "args": [] }], 80 | }, updatedAt: { 81 | name: "updatedAt", 82 | type: "DateTime", 83 | attributes: [{ "name": "@updatedAt", "args": [] }], 84 | }, space: { 85 | name: "space", 86 | type: "Space", 87 | isDataModel: true, 88 | backLink: 'members', 89 | isRelationOwner: true, 90 | onDeleteAction: 'Cascade', 91 | foreignKeyMapping: { "id": "spaceId" }, 92 | }, spaceId: { 93 | name: "spaceId", 94 | type: "String", 95 | isForeignKey: true, 96 | relationField: 'space', 97 | }, user: { 98 | name: "user", 99 | type: "User", 100 | isDataModel: true, 101 | backLink: 'memberships', 102 | isRelationOwner: true, 103 | onDeleteAction: 'Cascade', 104 | foreignKeyMapping: { "id": "userId" }, 105 | }, userId: { 106 | name: "userId", 107 | type: "String", 108 | isForeignKey: true, 109 | relationField: 'user', 110 | }, role: { 111 | name: "role", 112 | type: "SpaceUserRole", 113 | }, 114 | }, uniqueConstraints: { 115 | id: { 116 | name: "id", 117 | fields: ["id"] 118 | }, userId_spaceId: { 119 | name: "userId_spaceId", 120 | fields: ["userId", "spaceId"] 121 | }, 122 | }, 123 | }, 124 | user: { 125 | name: 'User', fields: { 126 | id: { 127 | name: "id", 128 | type: "String", 129 | isId: true, 130 | attributes: [{ "name": "@default", "args": [] }], 131 | }, email: { 132 | name: "email", 133 | type: "String", 134 | }, password: { 135 | name: "password", 136 | type: "String", 137 | }, name: { 138 | name: "name", 139 | type: "String", 140 | isOptional: true, 141 | }, ownedSpaces: { 142 | name: "ownedSpaces", 143 | type: "Space", 144 | isDataModel: true, 145 | isArray: true, 146 | backLink: 'owner', 147 | }, memberships: { 148 | name: "memberships", 149 | type: "SpaceUser", 150 | isDataModel: true, 151 | isArray: true, 152 | backLink: 'user', 153 | }, todos: { 154 | name: "todos", 155 | type: "Todo", 156 | isDataModel: true, 157 | isArray: true, 158 | backLink: 'owner', 159 | }, lists: { 160 | name: "lists", 161 | type: "List", 162 | isDataModel: true, 163 | isArray: true, 164 | backLink: 'owner', 165 | }, 166 | }, uniqueConstraints: { 167 | id: { 168 | name: "id", 169 | fields: ["id"] 170 | }, email: { 171 | name: "email", 172 | fields: ["email"] 173 | }, 174 | }, 175 | }, 176 | list: { 177 | name: 'List', fields: { 178 | id: { 179 | name: "id", 180 | type: "String", 181 | isId: true, 182 | attributes: [{ "name": "@default", "args": [] }], 183 | }, createdAt: { 184 | name: "createdAt", 185 | type: "DateTime", 186 | attributes: [{ "name": "@default", "args": [] }], 187 | }, updatedAt: { 188 | name: "updatedAt", 189 | type: "DateTime", 190 | attributes: [{ "name": "@updatedAt", "args": [] }], 191 | }, space: { 192 | name: "space", 193 | type: "Space", 194 | isDataModel: true, 195 | backLink: 'lists', 196 | isRelationOwner: true, 197 | onDeleteAction: 'Cascade', 198 | foreignKeyMapping: { "id": "spaceId" }, 199 | }, spaceId: { 200 | name: "spaceId", 201 | type: "String", 202 | isForeignKey: true, 203 | relationField: 'space', 204 | }, owner: { 205 | name: "owner", 206 | type: "User", 207 | isDataModel: true, 208 | backLink: 'lists', 209 | isRelationOwner: true, 210 | onDeleteAction: 'Cascade', 211 | foreignKeyMapping: { "id": "ownerId" }, 212 | }, ownerId: { 213 | name: "ownerId", 214 | type: "String", 215 | attributes: [{ "name": "@default", "args": [] }], 216 | defaultValueProvider: $default$List$ownerId, 217 | isForeignKey: true, 218 | relationField: 'owner', 219 | }, title: { 220 | name: "title", 221 | type: "String", 222 | }, private: { 223 | name: "private", 224 | type: "Boolean", 225 | attributes: [{ "name": "@default", "args": [{ "value": false }] }], 226 | }, todos: { 227 | name: "todos", 228 | type: "Todo", 229 | isDataModel: true, 230 | isArray: true, 231 | backLink: 'list', 232 | }, 233 | }, uniqueConstraints: { 234 | id: { 235 | name: "id", 236 | fields: ["id"] 237 | }, 238 | }, 239 | }, 240 | todo: { 241 | name: 'Todo', fields: { 242 | id: { 243 | name: "id", 244 | type: "String", 245 | isId: true, 246 | attributes: [{ "name": "@default", "args": [] }], 247 | }, createdAt: { 248 | name: "createdAt", 249 | type: "DateTime", 250 | attributes: [{ "name": "@default", "args": [] }], 251 | }, updatedAt: { 252 | name: "updatedAt", 253 | type: "DateTime", 254 | attributes: [{ "name": "@updatedAt", "args": [] }], 255 | }, owner: { 256 | name: "owner", 257 | type: "User", 258 | isDataModel: true, 259 | backLink: 'todos', 260 | isRelationOwner: true, 261 | onDeleteAction: 'Cascade', 262 | foreignKeyMapping: { "id": "ownerId" }, 263 | }, ownerId: { 264 | name: "ownerId", 265 | type: "String", 266 | attributes: [{ "name": "@default", "args": [] }], 267 | defaultValueProvider: $default$Todo$ownerId, 268 | isForeignKey: true, 269 | relationField: 'owner', 270 | }, list: { 271 | name: "list", 272 | type: "List", 273 | isDataModel: true, 274 | backLink: 'todos', 275 | isRelationOwner: true, 276 | onDeleteAction: 'Cascade', 277 | foreignKeyMapping: { "id": "listId" }, 278 | }, listId: { 279 | name: "listId", 280 | type: "String", 281 | isForeignKey: true, 282 | relationField: 'list', 283 | }, title: { 284 | name: "title", 285 | type: "String", 286 | }, completedAt: { 287 | name: "completedAt", 288 | type: "DateTime", 289 | isOptional: true, 290 | }, 291 | }, uniqueConstraints: { 292 | id: { 293 | name: "id", 294 | fields: ["id"] 295 | }, 296 | }, 297 | }, 298 | 299 | }, 300 | deleteCascade: { 301 | space: ['SpaceUser', 'List'], 302 | user: ['Space', 'SpaceUser', 'List', 'Todo'], 303 | list: ['Todo'], 304 | 305 | }, 306 | authModel: 'User' 307 | 308 | }; 309 | 310 | function $default$Space$ownerId(user: any): unknown { 311 | return user?.id; 312 | } 313 | 314 | function $default$List$ownerId(user: any): unknown { 315 | return user?.id; 316 | } 317 | 318 | function $default$Todo$ownerId(user: any): unknown { 319 | return user?.id; 320 | } 321 | export default metadata; 322 | -------------------------------------------------------------------------------- /src/lib/hooks/index.ts: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file was generated by ZenStack CLI. 3 | ******************************************************************************/ 4 | 5 | /* eslint-disable */ 6 | // @ts-nocheck 7 | 8 | export * from './space'; 9 | export * from './space-user'; 10 | export * from './user'; 11 | export * from './list'; 12 | export * from './todo'; 13 | export { getQueryKey } from '@zenstackhq/tanstack-query/runtime-v5'; 14 | export { SvelteQueryContextKey, setHooksContext } from '@zenstackhq/tanstack-query/runtime-v5/svelte'; 15 | export { default as metadata } from './__model_meta'; 16 | -------------------------------------------------------------------------------- /src/lib/hooks/list.ts: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file was generated by ZenStack CLI. 3 | ******************************************************************************/ 4 | 5 | /* eslint-disable */ 6 | // @ts-nocheck 7 | 8 | import type { Prisma, List } from "@zenstackhq/runtime/models"; 9 | import { derived } from 'svelte/store'; 10 | import type { MutationOptions, CreateQueryOptions, CreateInfiniteQueryOptions } from '@tanstack/svelte-query'; 11 | import type { InfiniteData, StoreOrVal } from '@tanstack/svelte-query'; 12 | import { getHooksContext } from '@zenstackhq/tanstack-query/runtime-v5/svelte'; 13 | import { useModelQuery, useInfiniteModelQuery, useModelMutation } from '@zenstackhq/tanstack-query/runtime-v5/svelte'; 14 | import type { PickEnumerable, CheckSelect, QueryError, ExtraQueryOptions, ExtraMutationOptions } from '@zenstackhq/tanstack-query/runtime-v5'; 15 | import type { PolicyCrudKind } from '@zenstackhq/runtime' 16 | import metadata from './__model_meta'; 17 | type DefaultError = QueryError; 18 | 19 | export function useCreateList(options?: Omit<(MutationOptions<(List | undefined), DefaultError, Prisma.ListCreateArgs> & ExtraMutationOptions), 'mutationFn'>) { 20 | const { endpoint, fetch } = getHooksContext(); 21 | const _mutation = 22 | useModelMutation('List', 'POST', `${endpoint}/list/create`, metadata, options, fetch, true) 23 | ; 24 | const mutation = derived(_mutation, value => ({ 25 | ...value, 26 | mutateAsync: async ( 27 | args: Prisma.SelectSubset, 28 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 29 | ) => { 30 | return (await value.mutateAsync( 31 | args, 32 | options as any 33 | )) as (CheckSelect> | undefined); 34 | }, 35 | })); 36 | return mutation; 37 | } 38 | 39 | export function useCreateManyList(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 40 | const { endpoint, fetch } = getHooksContext(); 41 | const _mutation = 42 | useModelMutation('List', 'POST', `${endpoint}/list/createMany`, metadata, options, fetch, false) 43 | ; 44 | const mutation = derived(_mutation, value => ({ 45 | ...value, 46 | mutateAsync: async ( 47 | args: Prisma.SelectSubset, 48 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 49 | ) => { 50 | return (await value.mutateAsync( 51 | args, 52 | options as any 53 | )) as Prisma.BatchPayload; 54 | }, 55 | })); 56 | return mutation; 57 | } 58 | 59 | export function useFindManyList & { $optimistic?: boolean }>, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 60 | const { endpoint, fetch } = getHooksContext(); 61 | return useModelQuery('List', `${endpoint}/list/findMany`, args, options, fetch); 62 | } 63 | 64 | export function useInfiniteFindManyList>, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: StoreOrVal>, 'queryKey' | 'initialPageParam'>>) { 65 | options = options ?? { getNextPageParam: () => null }; 66 | const { endpoint, fetch } = getHooksContext(); 67 | return useInfiniteModelQuery('List', `${endpoint}/list/findMany`, args, options, fetch); 68 | } 69 | 70 | export function useFindUniqueList & { $optimistic?: boolean }, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 71 | const { endpoint, fetch } = getHooksContext(); 72 | return useModelQuery('List', `${endpoint}/list/findUnique`, args, options, fetch); 73 | } 74 | 75 | export function useFindFirstList & { $optimistic?: boolean }, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 76 | const { endpoint, fetch } = getHooksContext(); 77 | return useModelQuery('List', `${endpoint}/list/findFirst`, args, options, fetch); 78 | } 79 | 80 | export function useUpdateList(options?: Omit<(MutationOptions<(List | undefined), DefaultError, Prisma.ListUpdateArgs> & ExtraMutationOptions), 'mutationFn'>) { 81 | const { endpoint, fetch } = getHooksContext(); 82 | const _mutation = 83 | useModelMutation('List', 'PUT', `${endpoint}/list/update`, metadata, options, fetch, true) 84 | ; 85 | const mutation = derived(_mutation, value => ({ 86 | ...value, 87 | mutateAsync: async ( 88 | args: Prisma.SelectSubset, 89 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 90 | ) => { 91 | return (await value.mutateAsync( 92 | args, 93 | options as any 94 | )) as (CheckSelect> | undefined); 95 | }, 96 | })); 97 | return mutation; 98 | } 99 | 100 | export function useUpdateManyList(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 101 | const { endpoint, fetch } = getHooksContext(); 102 | const _mutation = 103 | useModelMutation('List', 'PUT', `${endpoint}/list/updateMany`, metadata, options, fetch, false) 104 | ; 105 | const mutation = derived(_mutation, value => ({ 106 | ...value, 107 | mutateAsync: async ( 108 | args: Prisma.SelectSubset, 109 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 110 | ) => { 111 | return (await value.mutateAsync( 112 | args, 113 | options as any 114 | )) as Prisma.BatchPayload; 115 | }, 116 | })); 117 | return mutation; 118 | } 119 | 120 | export function useUpsertList(options?: Omit<(MutationOptions<(List | undefined), DefaultError, Prisma.ListUpsertArgs> & ExtraMutationOptions), 'mutationFn'>) { 121 | const { endpoint, fetch } = getHooksContext(); 122 | const _mutation = 123 | useModelMutation('List', 'POST', `${endpoint}/list/upsert`, metadata, options, fetch, true) 124 | ; 125 | const mutation = derived(_mutation, value => ({ 126 | ...value, 127 | mutateAsync: async ( 128 | args: Prisma.SelectSubset, 129 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 130 | ) => { 131 | return (await value.mutateAsync( 132 | args, 133 | options as any 134 | )) as (CheckSelect> | undefined); 135 | }, 136 | })); 137 | return mutation; 138 | } 139 | 140 | export function useDeleteList(options?: Omit<(MutationOptions<(List | undefined), DefaultError, Prisma.ListDeleteArgs> & ExtraMutationOptions), 'mutationFn'>) { 141 | const { endpoint, fetch } = getHooksContext(); 142 | const _mutation = 143 | useModelMutation('List', 'DELETE', `${endpoint}/list/delete`, metadata, options, fetch, true) 144 | ; 145 | const mutation = derived(_mutation, value => ({ 146 | ...value, 147 | mutateAsync: async ( 148 | args: Prisma.SelectSubset, 149 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 150 | ) => { 151 | return (await value.mutateAsync( 152 | args, 153 | options as any 154 | )) as (CheckSelect> | undefined); 155 | }, 156 | })); 157 | return mutation; 158 | } 159 | 160 | export function useDeleteManyList(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 161 | const { endpoint, fetch } = getHooksContext(); 162 | const _mutation = 163 | useModelMutation('List', 'DELETE', `${endpoint}/list/deleteMany`, metadata, options, fetch, false) 164 | ; 165 | const mutation = derived(_mutation, value => ({ 166 | ...value, 167 | mutateAsync: async ( 168 | args: Prisma.SelectSubset, 169 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 170 | ) => { 171 | return (await value.mutateAsync( 172 | args, 173 | options as any 174 | )) as Prisma.BatchPayload; 175 | }, 176 | })); 177 | return mutation; 178 | } 179 | 180 | export function useAggregateList, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 181 | const { endpoint, fetch } = getHooksContext(); 182 | return useModelQuery('List', `${endpoint}/list/aggregate`, args, options, fetch); 183 | } 184 | 185 | export function useGroupByList>, Prisma.Extends<'take', Prisma.Keys>>, OrderByArg extends Prisma.True extends HasSelectOrTake ? { orderBy: Prisma.ListGroupByArgs['orderBy'] } : { orderBy?: Prisma.ListGroupByArgs['orderBy'] }, OrderFields extends Prisma.ExcludeUnderscoreKeys>>, ByFields extends Prisma.MaybeTupleToUnion, ByValid extends Prisma.Has, HavingFields extends Prisma.GetHavingFields, HavingValid extends Prisma.Has, ByEmpty extends TArgs['by'] extends never[] ? Prisma.True : Prisma.False, InputErrors extends ByEmpty extends Prisma.True 186 | ? `Error: "by" must not be empty.` 187 | : HavingValid extends Prisma.False 188 | ? { 189 | [P in HavingFields]: P extends ByFields 190 | ? never 191 | : P extends string 192 | ? `Error: Field "${P}" used in "having" needs to be provided in "by".` 193 | : [ 194 | Error, 195 | 'Field ', 196 | P, 197 | ` in "having" needs to be provided in "by"`, 198 | ] 199 | }[HavingFields] 200 | : 'take' extends Prisma.Keys 201 | ? 'orderBy' extends Prisma.Keys 202 | ? ByValid extends Prisma.True 203 | ? {} 204 | : { 205 | [P in OrderFields]: P extends ByFields 206 | ? never 207 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 208 | }[OrderFields] 209 | : 'Error: If you provide "take", you also need to provide "orderBy"' 210 | : 'skip' extends Prisma.Keys 211 | ? 'orderBy' extends Prisma.Keys 212 | ? ByValid extends Prisma.True 213 | ? {} 214 | : { 215 | [P in OrderFields]: P extends ByFields 216 | ? never 217 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 218 | }[OrderFields] 219 | : 'Error: If you provide "skip", you also need to provide "orderBy"' 220 | : ByValid extends Prisma.True 221 | ? {} 222 | : { 223 | [P in OrderFields]: P extends ByFields 224 | ? never 225 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 226 | }[OrderFields], TQueryFnData = {} extends InputErrors ? 227 | Array & 228 | { 229 | [P in ((keyof TArgs) & (keyof Prisma.ListGroupByOutputType))]: P extends '_count' 230 | ? TArgs[P] extends boolean 231 | ? number 232 | : Prisma.GetScalarType 233 | : Prisma.GetScalarType 234 | } 235 | > : InputErrors, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset & InputErrors>, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 236 | const { endpoint, fetch } = getHooksContext(); 237 | return useModelQuery('List', `${endpoint}/list/groupBy`, args, options, fetch); 238 | } 239 | 240 | export function useCountList : number, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 241 | const { endpoint, fetch } = getHooksContext(); 242 | return useModelQuery('List', `${endpoint}/list/count`, args, options, fetch); 243 | } 244 | 245 | export function useCheckList(args: { operation: PolicyCrudKind; where?: { id?: string; spaceId?: string; ownerId?: string; title?: string; private?: boolean }; }, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 246 | const { endpoint, fetch } = getHooksContext(); 247 | return useModelQuery('List', `${endpoint}/list/check`, args, options, fetch); 248 | } 249 | -------------------------------------------------------------------------------- /src/lib/hooks/space-user.ts: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file was generated by ZenStack CLI. 3 | ******************************************************************************/ 4 | 5 | /* eslint-disable */ 6 | // @ts-nocheck 7 | 8 | import type { Prisma, SpaceUser } from "@zenstackhq/runtime/models"; 9 | import { derived } from 'svelte/store'; 10 | import type { MutationOptions, CreateQueryOptions, CreateInfiniteQueryOptions } from '@tanstack/svelte-query'; 11 | import type { InfiniteData, StoreOrVal } from '@tanstack/svelte-query'; 12 | import { getHooksContext } from '@zenstackhq/tanstack-query/runtime-v5/svelte'; 13 | import { useModelQuery, useInfiniteModelQuery, useModelMutation } from '@zenstackhq/tanstack-query/runtime-v5/svelte'; 14 | import type { PickEnumerable, CheckSelect, QueryError, ExtraQueryOptions, ExtraMutationOptions } from '@zenstackhq/tanstack-query/runtime-v5'; 15 | import type { PolicyCrudKind } from '@zenstackhq/runtime' 16 | import metadata from './__model_meta'; 17 | type DefaultError = QueryError; 18 | 19 | export function useCreateSpaceUser(options?: Omit<(MutationOptions<(SpaceUser | undefined), DefaultError, Prisma.SpaceUserCreateArgs> & ExtraMutationOptions), 'mutationFn'>) { 20 | const { endpoint, fetch } = getHooksContext(); 21 | const _mutation = 22 | useModelMutation('SpaceUser', 'POST', `${endpoint}/spaceUser/create`, metadata, options, fetch, true) 23 | ; 24 | const mutation = derived(_mutation, value => ({ 25 | ...value, 26 | mutateAsync: async ( 27 | args: Prisma.SelectSubset, 28 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 29 | ) => { 30 | return (await value.mutateAsync( 31 | args, 32 | options as any 33 | )) as (CheckSelect> | undefined); 34 | }, 35 | })); 36 | return mutation; 37 | } 38 | 39 | export function useCreateManySpaceUser(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 40 | const { endpoint, fetch } = getHooksContext(); 41 | const _mutation = 42 | useModelMutation('SpaceUser', 'POST', `${endpoint}/spaceUser/createMany`, metadata, options, fetch, false) 43 | ; 44 | const mutation = derived(_mutation, value => ({ 45 | ...value, 46 | mutateAsync: async ( 47 | args: Prisma.SelectSubset, 48 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 49 | ) => { 50 | return (await value.mutateAsync( 51 | args, 52 | options as any 53 | )) as Prisma.BatchPayload; 54 | }, 55 | })); 56 | return mutation; 57 | } 58 | 59 | export function useFindManySpaceUser & { $optimistic?: boolean }>, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 60 | const { endpoint, fetch } = getHooksContext(); 61 | return useModelQuery('SpaceUser', `${endpoint}/spaceUser/findMany`, args, options, fetch); 62 | } 63 | 64 | export function useInfiniteFindManySpaceUser>, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: StoreOrVal>, 'queryKey' | 'initialPageParam'>>) { 65 | options = options ?? { getNextPageParam: () => null }; 66 | const { endpoint, fetch } = getHooksContext(); 67 | return useInfiniteModelQuery('SpaceUser', `${endpoint}/spaceUser/findMany`, args, options, fetch); 68 | } 69 | 70 | export function useFindUniqueSpaceUser & { $optimistic?: boolean }, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 71 | const { endpoint, fetch } = getHooksContext(); 72 | return useModelQuery('SpaceUser', `${endpoint}/spaceUser/findUnique`, args, options, fetch); 73 | } 74 | 75 | export function useFindFirstSpaceUser & { $optimistic?: boolean }, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 76 | const { endpoint, fetch } = getHooksContext(); 77 | return useModelQuery('SpaceUser', `${endpoint}/spaceUser/findFirst`, args, options, fetch); 78 | } 79 | 80 | export function useUpdateSpaceUser(options?: Omit<(MutationOptions<(SpaceUser | undefined), DefaultError, Prisma.SpaceUserUpdateArgs> & ExtraMutationOptions), 'mutationFn'>) { 81 | const { endpoint, fetch } = getHooksContext(); 82 | const _mutation = 83 | useModelMutation('SpaceUser', 'PUT', `${endpoint}/spaceUser/update`, metadata, options, fetch, true) 84 | ; 85 | const mutation = derived(_mutation, value => ({ 86 | ...value, 87 | mutateAsync: async ( 88 | args: Prisma.SelectSubset, 89 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 90 | ) => { 91 | return (await value.mutateAsync( 92 | args, 93 | options as any 94 | )) as (CheckSelect> | undefined); 95 | }, 96 | })); 97 | return mutation; 98 | } 99 | 100 | export function useUpdateManySpaceUser(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 101 | const { endpoint, fetch } = getHooksContext(); 102 | const _mutation = 103 | useModelMutation('SpaceUser', 'PUT', `${endpoint}/spaceUser/updateMany`, metadata, options, fetch, false) 104 | ; 105 | const mutation = derived(_mutation, value => ({ 106 | ...value, 107 | mutateAsync: async ( 108 | args: Prisma.SelectSubset, 109 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 110 | ) => { 111 | return (await value.mutateAsync( 112 | args, 113 | options as any 114 | )) as Prisma.BatchPayload; 115 | }, 116 | })); 117 | return mutation; 118 | } 119 | 120 | export function useUpsertSpaceUser(options?: Omit<(MutationOptions<(SpaceUser | undefined), DefaultError, Prisma.SpaceUserUpsertArgs> & ExtraMutationOptions), 'mutationFn'>) { 121 | const { endpoint, fetch } = getHooksContext(); 122 | const _mutation = 123 | useModelMutation('SpaceUser', 'POST', `${endpoint}/spaceUser/upsert`, metadata, options, fetch, true) 124 | ; 125 | const mutation = derived(_mutation, value => ({ 126 | ...value, 127 | mutateAsync: async ( 128 | args: Prisma.SelectSubset, 129 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 130 | ) => { 131 | return (await value.mutateAsync( 132 | args, 133 | options as any 134 | )) as (CheckSelect> | undefined); 135 | }, 136 | })); 137 | return mutation; 138 | } 139 | 140 | export function useDeleteSpaceUser(options?: Omit<(MutationOptions<(SpaceUser | undefined), DefaultError, Prisma.SpaceUserDeleteArgs> & ExtraMutationOptions), 'mutationFn'>) { 141 | const { endpoint, fetch } = getHooksContext(); 142 | const _mutation = 143 | useModelMutation('SpaceUser', 'DELETE', `${endpoint}/spaceUser/delete`, metadata, options, fetch, true) 144 | ; 145 | const mutation = derived(_mutation, value => ({ 146 | ...value, 147 | mutateAsync: async ( 148 | args: Prisma.SelectSubset, 149 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 150 | ) => { 151 | return (await value.mutateAsync( 152 | args, 153 | options as any 154 | )) as (CheckSelect> | undefined); 155 | }, 156 | })); 157 | return mutation; 158 | } 159 | 160 | export function useDeleteManySpaceUser(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 161 | const { endpoint, fetch } = getHooksContext(); 162 | const _mutation = 163 | useModelMutation('SpaceUser', 'DELETE', `${endpoint}/spaceUser/deleteMany`, metadata, options, fetch, false) 164 | ; 165 | const mutation = derived(_mutation, value => ({ 166 | ...value, 167 | mutateAsync: async ( 168 | args: Prisma.SelectSubset, 169 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 170 | ) => { 171 | return (await value.mutateAsync( 172 | args, 173 | options as any 174 | )) as Prisma.BatchPayload; 175 | }, 176 | })); 177 | return mutation; 178 | } 179 | 180 | export function useAggregateSpaceUser, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 181 | const { endpoint, fetch } = getHooksContext(); 182 | return useModelQuery('SpaceUser', `${endpoint}/spaceUser/aggregate`, args, options, fetch); 183 | } 184 | 185 | export function useGroupBySpaceUser>, Prisma.Extends<'take', Prisma.Keys>>, OrderByArg extends Prisma.True extends HasSelectOrTake ? { orderBy: Prisma.SpaceUserGroupByArgs['orderBy'] } : { orderBy?: Prisma.SpaceUserGroupByArgs['orderBy'] }, OrderFields extends Prisma.ExcludeUnderscoreKeys>>, ByFields extends Prisma.MaybeTupleToUnion, ByValid extends Prisma.Has, HavingFields extends Prisma.GetHavingFields, HavingValid extends Prisma.Has, ByEmpty extends TArgs['by'] extends never[] ? Prisma.True : Prisma.False, InputErrors extends ByEmpty extends Prisma.True 186 | ? `Error: "by" must not be empty.` 187 | : HavingValid extends Prisma.False 188 | ? { 189 | [P in HavingFields]: P extends ByFields 190 | ? never 191 | : P extends string 192 | ? `Error: Field "${P}" used in "having" needs to be provided in "by".` 193 | : [ 194 | Error, 195 | 'Field ', 196 | P, 197 | ` in "having" needs to be provided in "by"`, 198 | ] 199 | }[HavingFields] 200 | : 'take' extends Prisma.Keys 201 | ? 'orderBy' extends Prisma.Keys 202 | ? ByValid extends Prisma.True 203 | ? {} 204 | : { 205 | [P in OrderFields]: P extends ByFields 206 | ? never 207 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 208 | }[OrderFields] 209 | : 'Error: If you provide "take", you also need to provide "orderBy"' 210 | : 'skip' extends Prisma.Keys 211 | ? 'orderBy' extends Prisma.Keys 212 | ? ByValid extends Prisma.True 213 | ? {} 214 | : { 215 | [P in OrderFields]: P extends ByFields 216 | ? never 217 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 218 | }[OrderFields] 219 | : 'Error: If you provide "skip", you also need to provide "orderBy"' 220 | : ByValid extends Prisma.True 221 | ? {} 222 | : { 223 | [P in OrderFields]: P extends ByFields 224 | ? never 225 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 226 | }[OrderFields], TQueryFnData = {} extends InputErrors ? 227 | Array & 228 | { 229 | [P in ((keyof TArgs) & (keyof Prisma.SpaceUserGroupByOutputType))]: P extends '_count' 230 | ? TArgs[P] extends boolean 231 | ? number 232 | : Prisma.GetScalarType 233 | : Prisma.GetScalarType 234 | } 235 | > : InputErrors, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset & InputErrors>, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 236 | const { endpoint, fetch } = getHooksContext(); 237 | return useModelQuery('SpaceUser', `${endpoint}/spaceUser/groupBy`, args, options, fetch); 238 | } 239 | 240 | export function useCountSpaceUser : number, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 241 | const { endpoint, fetch } = getHooksContext(); 242 | return useModelQuery('SpaceUser', `${endpoint}/spaceUser/count`, args, options, fetch); 243 | } 244 | import type { SpaceUserRole } from '@zenstackhq/runtime/models'; 245 | 246 | export function useCheckSpaceUser(args: { operation: PolicyCrudKind; where?: { id?: string; spaceId?: string; userId?: string; role?: SpaceUserRole }; }, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 247 | const { endpoint, fetch } = getHooksContext(); 248 | return useModelQuery('SpaceUser', `${endpoint}/spaceUser/check`, args, options, fetch); 249 | } 250 | -------------------------------------------------------------------------------- /src/lib/hooks/space.ts: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file was generated by ZenStack CLI. 3 | ******************************************************************************/ 4 | 5 | /* eslint-disable */ 6 | // @ts-nocheck 7 | 8 | import type { Prisma, Space } from "@zenstackhq/runtime/models"; 9 | import { derived } from 'svelte/store'; 10 | import type { MutationOptions, CreateQueryOptions, CreateInfiniteQueryOptions } from '@tanstack/svelte-query'; 11 | import type { InfiniteData, StoreOrVal } from '@tanstack/svelte-query'; 12 | import { getHooksContext } from '@zenstackhq/tanstack-query/runtime-v5/svelte'; 13 | import { useModelQuery, useInfiniteModelQuery, useModelMutation } from '@zenstackhq/tanstack-query/runtime-v5/svelte'; 14 | import type { PickEnumerable, CheckSelect, QueryError, ExtraQueryOptions, ExtraMutationOptions } from '@zenstackhq/tanstack-query/runtime-v5'; 15 | import type { PolicyCrudKind } from '@zenstackhq/runtime' 16 | import metadata from './__model_meta'; 17 | type DefaultError = QueryError; 18 | 19 | export function useCreateSpace(options?: Omit<(MutationOptions<(Space | undefined), DefaultError, Prisma.SpaceCreateArgs> & ExtraMutationOptions), 'mutationFn'>) { 20 | const { endpoint, fetch } = getHooksContext(); 21 | const _mutation = 22 | useModelMutation('Space', 'POST', `${endpoint}/space/create`, metadata, options, fetch, true) 23 | ; 24 | const mutation = derived(_mutation, value => ({ 25 | ...value, 26 | mutateAsync: async ( 27 | args: Prisma.SelectSubset, 28 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 29 | ) => { 30 | return (await value.mutateAsync( 31 | args, 32 | options as any 33 | )) as (CheckSelect> | undefined); 34 | }, 35 | })); 36 | return mutation; 37 | } 38 | 39 | export function useCreateManySpace(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 40 | const { endpoint, fetch } = getHooksContext(); 41 | const _mutation = 42 | useModelMutation('Space', 'POST', `${endpoint}/space/createMany`, metadata, options, fetch, false) 43 | ; 44 | const mutation = derived(_mutation, value => ({ 45 | ...value, 46 | mutateAsync: async ( 47 | args: Prisma.SelectSubset, 48 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 49 | ) => { 50 | return (await value.mutateAsync( 51 | args, 52 | options as any 53 | )) as Prisma.BatchPayload; 54 | }, 55 | })); 56 | return mutation; 57 | } 58 | 59 | export function useFindManySpace & { $optimistic?: boolean }>, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 60 | const { endpoint, fetch } = getHooksContext(); 61 | return useModelQuery('Space', `${endpoint}/space/findMany`, args, options, fetch); 62 | } 63 | 64 | export function useInfiniteFindManySpace>, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: StoreOrVal>, 'queryKey' | 'initialPageParam'>>) { 65 | options = options ?? { getNextPageParam: () => null }; 66 | const { endpoint, fetch } = getHooksContext(); 67 | return useInfiniteModelQuery('Space', `${endpoint}/space/findMany`, args, options, fetch); 68 | } 69 | 70 | export function useFindUniqueSpace & { $optimistic?: boolean }, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 71 | const { endpoint, fetch } = getHooksContext(); 72 | return useModelQuery('Space', `${endpoint}/space/findUnique`, args, options, fetch); 73 | } 74 | 75 | export function useFindFirstSpace & { $optimistic?: boolean }, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 76 | const { endpoint, fetch } = getHooksContext(); 77 | return useModelQuery('Space', `${endpoint}/space/findFirst`, args, options, fetch); 78 | } 79 | 80 | export function useUpdateSpace(options?: Omit<(MutationOptions<(Space | undefined), DefaultError, Prisma.SpaceUpdateArgs> & ExtraMutationOptions), 'mutationFn'>) { 81 | const { endpoint, fetch } = getHooksContext(); 82 | const _mutation = 83 | useModelMutation('Space', 'PUT', `${endpoint}/space/update`, metadata, options, fetch, true) 84 | ; 85 | const mutation = derived(_mutation, value => ({ 86 | ...value, 87 | mutateAsync: async ( 88 | args: Prisma.SelectSubset, 89 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 90 | ) => { 91 | return (await value.mutateAsync( 92 | args, 93 | options as any 94 | )) as (CheckSelect> | undefined); 95 | }, 96 | })); 97 | return mutation; 98 | } 99 | 100 | export function useUpdateManySpace(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 101 | const { endpoint, fetch } = getHooksContext(); 102 | const _mutation = 103 | useModelMutation('Space', 'PUT', `${endpoint}/space/updateMany`, metadata, options, fetch, false) 104 | ; 105 | const mutation = derived(_mutation, value => ({ 106 | ...value, 107 | mutateAsync: async ( 108 | args: Prisma.SelectSubset, 109 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 110 | ) => { 111 | return (await value.mutateAsync( 112 | args, 113 | options as any 114 | )) as Prisma.BatchPayload; 115 | }, 116 | })); 117 | return mutation; 118 | } 119 | 120 | export function useUpsertSpace(options?: Omit<(MutationOptions<(Space | undefined), DefaultError, Prisma.SpaceUpsertArgs> & ExtraMutationOptions), 'mutationFn'>) { 121 | const { endpoint, fetch } = getHooksContext(); 122 | const _mutation = 123 | useModelMutation('Space', 'POST', `${endpoint}/space/upsert`, metadata, options, fetch, true) 124 | ; 125 | const mutation = derived(_mutation, value => ({ 126 | ...value, 127 | mutateAsync: async ( 128 | args: Prisma.SelectSubset, 129 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 130 | ) => { 131 | return (await value.mutateAsync( 132 | args, 133 | options as any 134 | )) as (CheckSelect> | undefined); 135 | }, 136 | })); 137 | return mutation; 138 | } 139 | 140 | export function useDeleteSpace(options?: Omit<(MutationOptions<(Space | undefined), DefaultError, Prisma.SpaceDeleteArgs> & ExtraMutationOptions), 'mutationFn'>) { 141 | const { endpoint, fetch } = getHooksContext(); 142 | const _mutation = 143 | useModelMutation('Space', 'DELETE', `${endpoint}/space/delete`, metadata, options, fetch, true) 144 | ; 145 | const mutation = derived(_mutation, value => ({ 146 | ...value, 147 | mutateAsync: async ( 148 | args: Prisma.SelectSubset, 149 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 150 | ) => { 151 | return (await value.mutateAsync( 152 | args, 153 | options as any 154 | )) as (CheckSelect> | undefined); 155 | }, 156 | })); 157 | return mutation; 158 | } 159 | 160 | export function useDeleteManySpace(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 161 | const { endpoint, fetch } = getHooksContext(); 162 | const _mutation = 163 | useModelMutation('Space', 'DELETE', `${endpoint}/space/deleteMany`, metadata, options, fetch, false) 164 | ; 165 | const mutation = derived(_mutation, value => ({ 166 | ...value, 167 | mutateAsync: async ( 168 | args: Prisma.SelectSubset, 169 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 170 | ) => { 171 | return (await value.mutateAsync( 172 | args, 173 | options as any 174 | )) as Prisma.BatchPayload; 175 | }, 176 | })); 177 | return mutation; 178 | } 179 | 180 | export function useAggregateSpace, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 181 | const { endpoint, fetch } = getHooksContext(); 182 | return useModelQuery('Space', `${endpoint}/space/aggregate`, args, options, fetch); 183 | } 184 | 185 | export function useGroupBySpace>, Prisma.Extends<'take', Prisma.Keys>>, OrderByArg extends Prisma.True extends HasSelectOrTake ? { orderBy: Prisma.SpaceGroupByArgs['orderBy'] } : { orderBy?: Prisma.SpaceGroupByArgs['orderBy'] }, OrderFields extends Prisma.ExcludeUnderscoreKeys>>, ByFields extends Prisma.MaybeTupleToUnion, ByValid extends Prisma.Has, HavingFields extends Prisma.GetHavingFields, HavingValid extends Prisma.Has, ByEmpty extends TArgs['by'] extends never[] ? Prisma.True : Prisma.False, InputErrors extends ByEmpty extends Prisma.True 186 | ? `Error: "by" must not be empty.` 187 | : HavingValid extends Prisma.False 188 | ? { 189 | [P in HavingFields]: P extends ByFields 190 | ? never 191 | : P extends string 192 | ? `Error: Field "${P}" used in "having" needs to be provided in "by".` 193 | : [ 194 | Error, 195 | 'Field ', 196 | P, 197 | ` in "having" needs to be provided in "by"`, 198 | ] 199 | }[HavingFields] 200 | : 'take' extends Prisma.Keys 201 | ? 'orderBy' extends Prisma.Keys 202 | ? ByValid extends Prisma.True 203 | ? {} 204 | : { 205 | [P in OrderFields]: P extends ByFields 206 | ? never 207 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 208 | }[OrderFields] 209 | : 'Error: If you provide "take", you also need to provide "orderBy"' 210 | : 'skip' extends Prisma.Keys 211 | ? 'orderBy' extends Prisma.Keys 212 | ? ByValid extends Prisma.True 213 | ? {} 214 | : { 215 | [P in OrderFields]: P extends ByFields 216 | ? never 217 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 218 | }[OrderFields] 219 | : 'Error: If you provide "skip", you also need to provide "orderBy"' 220 | : ByValid extends Prisma.True 221 | ? {} 222 | : { 223 | [P in OrderFields]: P extends ByFields 224 | ? never 225 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 226 | }[OrderFields], TQueryFnData = {} extends InputErrors ? 227 | Array & 228 | { 229 | [P in ((keyof TArgs) & (keyof Prisma.SpaceGroupByOutputType))]: P extends '_count' 230 | ? TArgs[P] extends boolean 231 | ? number 232 | : Prisma.GetScalarType 233 | : Prisma.GetScalarType 234 | } 235 | > : InputErrors, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset & InputErrors>, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 236 | const { endpoint, fetch } = getHooksContext(); 237 | return useModelQuery('Space', `${endpoint}/space/groupBy`, args, options, fetch); 238 | } 239 | 240 | export function useCountSpace : number, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 241 | const { endpoint, fetch } = getHooksContext(); 242 | return useModelQuery('Space', `${endpoint}/space/count`, args, options, fetch); 243 | } 244 | 245 | export function useCheckSpace(args: { operation: PolicyCrudKind; where?: { id?: string; ownerId?: string; name?: string; slug?: string }; }, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 246 | const { endpoint, fetch } = getHooksContext(); 247 | return useModelQuery('Space', `${endpoint}/space/check`, args, options, fetch); 248 | } 249 | -------------------------------------------------------------------------------- /src/lib/hooks/todo.ts: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file was generated by ZenStack CLI. 3 | ******************************************************************************/ 4 | 5 | /* eslint-disable */ 6 | // @ts-nocheck 7 | 8 | import type { Prisma, Todo } from "@zenstackhq/runtime/models"; 9 | import { derived } from 'svelte/store'; 10 | import type { MutationOptions, CreateQueryOptions, CreateInfiniteQueryOptions } from '@tanstack/svelte-query'; 11 | import type { InfiniteData, StoreOrVal } from '@tanstack/svelte-query'; 12 | import { getHooksContext } from '@zenstackhq/tanstack-query/runtime-v5/svelte'; 13 | import { useModelQuery, useInfiniteModelQuery, useModelMutation } from '@zenstackhq/tanstack-query/runtime-v5/svelte'; 14 | import type { PickEnumerable, CheckSelect, QueryError, ExtraQueryOptions, ExtraMutationOptions } from '@zenstackhq/tanstack-query/runtime-v5'; 15 | import type { PolicyCrudKind } from '@zenstackhq/runtime' 16 | import metadata from './__model_meta'; 17 | type DefaultError = QueryError; 18 | 19 | export function useCreateTodo(options?: Omit<(MutationOptions<(Todo | undefined), DefaultError, Prisma.TodoCreateArgs> & ExtraMutationOptions), 'mutationFn'>) { 20 | const { endpoint, fetch } = getHooksContext(); 21 | const _mutation = 22 | useModelMutation('Todo', 'POST', `${endpoint}/todo/create`, metadata, options, fetch, true) 23 | ; 24 | const mutation = derived(_mutation, value => ({ 25 | ...value, 26 | mutateAsync: async ( 27 | args: Prisma.SelectSubset, 28 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 29 | ) => { 30 | return (await value.mutateAsync( 31 | args, 32 | options as any 33 | )) as (CheckSelect> | undefined); 34 | }, 35 | })); 36 | return mutation; 37 | } 38 | 39 | export function useCreateManyTodo(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 40 | const { endpoint, fetch } = getHooksContext(); 41 | const _mutation = 42 | useModelMutation('Todo', 'POST', `${endpoint}/todo/createMany`, metadata, options, fetch, false) 43 | ; 44 | const mutation = derived(_mutation, value => ({ 45 | ...value, 46 | mutateAsync: async ( 47 | args: Prisma.SelectSubset, 48 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 49 | ) => { 50 | return (await value.mutateAsync( 51 | args, 52 | options as any 53 | )) as Prisma.BatchPayload; 54 | }, 55 | })); 56 | return mutation; 57 | } 58 | 59 | export function useFindManyTodo & { $optimistic?: boolean }>, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 60 | const { endpoint, fetch } = getHooksContext(); 61 | return useModelQuery('Todo', `${endpoint}/todo/findMany`, args, options, fetch); 62 | } 63 | 64 | export function useInfiniteFindManyTodo>, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: StoreOrVal>, 'queryKey' | 'initialPageParam'>>) { 65 | options = options ?? { getNextPageParam: () => null }; 66 | const { endpoint, fetch } = getHooksContext(); 67 | return useInfiniteModelQuery('Todo', `${endpoint}/todo/findMany`, args, options, fetch); 68 | } 69 | 70 | export function useFindUniqueTodo & { $optimistic?: boolean }, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 71 | const { endpoint, fetch } = getHooksContext(); 72 | return useModelQuery('Todo', `${endpoint}/todo/findUnique`, args, options, fetch); 73 | } 74 | 75 | export function useFindFirstTodo & { $optimistic?: boolean }, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 76 | const { endpoint, fetch } = getHooksContext(); 77 | return useModelQuery('Todo', `${endpoint}/todo/findFirst`, args, options, fetch); 78 | } 79 | 80 | export function useUpdateTodo(options?: Omit<(MutationOptions<(Todo | undefined), DefaultError, Prisma.TodoUpdateArgs> & ExtraMutationOptions), 'mutationFn'>) { 81 | const { endpoint, fetch } = getHooksContext(); 82 | const _mutation = 83 | useModelMutation('Todo', 'PUT', `${endpoint}/todo/update`, metadata, options, fetch, true) 84 | ; 85 | const mutation = derived(_mutation, value => ({ 86 | ...value, 87 | mutateAsync: async ( 88 | args: Prisma.SelectSubset, 89 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 90 | ) => { 91 | return (await value.mutateAsync( 92 | args, 93 | options as any 94 | )) as (CheckSelect> | undefined); 95 | }, 96 | })); 97 | return mutation; 98 | } 99 | 100 | export function useUpdateManyTodo(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 101 | const { endpoint, fetch } = getHooksContext(); 102 | const _mutation = 103 | useModelMutation('Todo', 'PUT', `${endpoint}/todo/updateMany`, metadata, options, fetch, false) 104 | ; 105 | const mutation = derived(_mutation, value => ({ 106 | ...value, 107 | mutateAsync: async ( 108 | args: Prisma.SelectSubset, 109 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 110 | ) => { 111 | return (await value.mutateAsync( 112 | args, 113 | options as any 114 | )) as Prisma.BatchPayload; 115 | }, 116 | })); 117 | return mutation; 118 | } 119 | 120 | export function useUpsertTodo(options?: Omit<(MutationOptions<(Todo | undefined), DefaultError, Prisma.TodoUpsertArgs> & ExtraMutationOptions), 'mutationFn'>) { 121 | const { endpoint, fetch } = getHooksContext(); 122 | const _mutation = 123 | useModelMutation('Todo', 'POST', `${endpoint}/todo/upsert`, metadata, options, fetch, true) 124 | ; 125 | const mutation = derived(_mutation, value => ({ 126 | ...value, 127 | mutateAsync: async ( 128 | args: Prisma.SelectSubset, 129 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 130 | ) => { 131 | return (await value.mutateAsync( 132 | args, 133 | options as any 134 | )) as (CheckSelect> | undefined); 135 | }, 136 | })); 137 | return mutation; 138 | } 139 | 140 | export function useDeleteTodo(options?: Omit<(MutationOptions<(Todo | undefined), DefaultError, Prisma.TodoDeleteArgs> & ExtraMutationOptions), 'mutationFn'>) { 141 | const { endpoint, fetch } = getHooksContext(); 142 | const _mutation = 143 | useModelMutation('Todo', 'DELETE', `${endpoint}/todo/delete`, metadata, options, fetch, true) 144 | ; 145 | const mutation = derived(_mutation, value => ({ 146 | ...value, 147 | mutateAsync: async ( 148 | args: Prisma.SelectSubset, 149 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 150 | ) => { 151 | return (await value.mutateAsync( 152 | args, 153 | options as any 154 | )) as (CheckSelect> | undefined); 155 | }, 156 | })); 157 | return mutation; 158 | } 159 | 160 | export function useDeleteManyTodo(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 161 | const { endpoint, fetch } = getHooksContext(); 162 | const _mutation = 163 | useModelMutation('Todo', 'DELETE', `${endpoint}/todo/deleteMany`, metadata, options, fetch, false) 164 | ; 165 | const mutation = derived(_mutation, value => ({ 166 | ...value, 167 | mutateAsync: async ( 168 | args: Prisma.SelectSubset, 169 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 170 | ) => { 171 | return (await value.mutateAsync( 172 | args, 173 | options as any 174 | )) as Prisma.BatchPayload; 175 | }, 176 | })); 177 | return mutation; 178 | } 179 | 180 | export function useAggregateTodo, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 181 | const { endpoint, fetch } = getHooksContext(); 182 | return useModelQuery('Todo', `${endpoint}/todo/aggregate`, args, options, fetch); 183 | } 184 | 185 | export function useGroupByTodo>, Prisma.Extends<'take', Prisma.Keys>>, OrderByArg extends Prisma.True extends HasSelectOrTake ? { orderBy: Prisma.TodoGroupByArgs['orderBy'] } : { orderBy?: Prisma.TodoGroupByArgs['orderBy'] }, OrderFields extends Prisma.ExcludeUnderscoreKeys>>, ByFields extends Prisma.MaybeTupleToUnion, ByValid extends Prisma.Has, HavingFields extends Prisma.GetHavingFields, HavingValid extends Prisma.Has, ByEmpty extends TArgs['by'] extends never[] ? Prisma.True : Prisma.False, InputErrors extends ByEmpty extends Prisma.True 186 | ? `Error: "by" must not be empty.` 187 | : HavingValid extends Prisma.False 188 | ? { 189 | [P in HavingFields]: P extends ByFields 190 | ? never 191 | : P extends string 192 | ? `Error: Field "${P}" used in "having" needs to be provided in "by".` 193 | : [ 194 | Error, 195 | 'Field ', 196 | P, 197 | ` in "having" needs to be provided in "by"`, 198 | ] 199 | }[HavingFields] 200 | : 'take' extends Prisma.Keys 201 | ? 'orderBy' extends Prisma.Keys 202 | ? ByValid extends Prisma.True 203 | ? {} 204 | : { 205 | [P in OrderFields]: P extends ByFields 206 | ? never 207 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 208 | }[OrderFields] 209 | : 'Error: If you provide "take", you also need to provide "orderBy"' 210 | : 'skip' extends Prisma.Keys 211 | ? 'orderBy' extends Prisma.Keys 212 | ? ByValid extends Prisma.True 213 | ? {} 214 | : { 215 | [P in OrderFields]: P extends ByFields 216 | ? never 217 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 218 | }[OrderFields] 219 | : 'Error: If you provide "skip", you also need to provide "orderBy"' 220 | : ByValid extends Prisma.True 221 | ? {} 222 | : { 223 | [P in OrderFields]: P extends ByFields 224 | ? never 225 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 226 | }[OrderFields], TQueryFnData = {} extends InputErrors ? 227 | Array & 228 | { 229 | [P in ((keyof TArgs) & (keyof Prisma.TodoGroupByOutputType))]: P extends '_count' 230 | ? TArgs[P] extends boolean 231 | ? number 232 | : Prisma.GetScalarType 233 | : Prisma.GetScalarType 234 | } 235 | > : InputErrors, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset & InputErrors>, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 236 | const { endpoint, fetch } = getHooksContext(); 237 | return useModelQuery('Todo', `${endpoint}/todo/groupBy`, args, options, fetch); 238 | } 239 | 240 | export function useCountTodo : number, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 241 | const { endpoint, fetch } = getHooksContext(); 242 | return useModelQuery('Todo', `${endpoint}/todo/count`, args, options, fetch); 243 | } 244 | 245 | export function useCheckTodo(args: { operation: PolicyCrudKind; where?: { id?: string; ownerId?: string; listId?: string; title?: string }; }, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 246 | const { endpoint, fetch } = getHooksContext(); 247 | return useModelQuery('Todo', `${endpoint}/todo/check`, args, options, fetch); 248 | } 249 | -------------------------------------------------------------------------------- /src/lib/hooks/user.ts: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file was generated by ZenStack CLI. 3 | ******************************************************************************/ 4 | 5 | /* eslint-disable */ 6 | // @ts-nocheck 7 | 8 | import type { Prisma, User } from "@zenstackhq/runtime/models"; 9 | import { derived } from 'svelte/store'; 10 | import type { MutationOptions, CreateQueryOptions, CreateInfiniteQueryOptions } from '@tanstack/svelte-query'; 11 | import type { InfiniteData, StoreOrVal } from '@tanstack/svelte-query'; 12 | import { getHooksContext } from '@zenstackhq/tanstack-query/runtime-v5/svelte'; 13 | import { useModelQuery, useInfiniteModelQuery, useModelMutation } from '@zenstackhq/tanstack-query/runtime-v5/svelte'; 14 | import type { PickEnumerable, CheckSelect, QueryError, ExtraQueryOptions, ExtraMutationOptions } from '@zenstackhq/tanstack-query/runtime-v5'; 15 | import type { PolicyCrudKind } from '@zenstackhq/runtime' 16 | import metadata from './__model_meta'; 17 | type DefaultError = QueryError; 18 | 19 | export function useCreateUser(options?: Omit<(MutationOptions<(User | undefined), DefaultError, Prisma.UserCreateArgs> & ExtraMutationOptions), 'mutationFn'>) { 20 | const { endpoint, fetch } = getHooksContext(); 21 | const _mutation = 22 | useModelMutation('User', 'POST', `${endpoint}/user/create`, metadata, options, fetch, true) 23 | ; 24 | const mutation = derived(_mutation, value => ({ 25 | ...value, 26 | mutateAsync: async ( 27 | args: Prisma.SelectSubset, 28 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 29 | ) => { 30 | return (await value.mutateAsync( 31 | args, 32 | options as any 33 | )) as (CheckSelect> | undefined); 34 | }, 35 | })); 36 | return mutation; 37 | } 38 | 39 | export function useCreateManyUser(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 40 | const { endpoint, fetch } = getHooksContext(); 41 | const _mutation = 42 | useModelMutation('User', 'POST', `${endpoint}/user/createMany`, metadata, options, fetch, false) 43 | ; 44 | const mutation = derived(_mutation, value => ({ 45 | ...value, 46 | mutateAsync: async ( 47 | args: Prisma.SelectSubset, 48 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 49 | ) => { 50 | return (await value.mutateAsync( 51 | args, 52 | options as any 53 | )) as Prisma.BatchPayload; 54 | }, 55 | })); 56 | return mutation; 57 | } 58 | 59 | export function useFindManyUser & { $optimistic?: boolean }>, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 60 | const { endpoint, fetch } = getHooksContext(); 61 | return useModelQuery('User', `${endpoint}/user/findMany`, args, options, fetch); 62 | } 63 | 64 | export function useInfiniteFindManyUser>, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: StoreOrVal>, 'queryKey' | 'initialPageParam'>>) { 65 | options = options ?? { getNextPageParam: () => null }; 66 | const { endpoint, fetch } = getHooksContext(); 67 | return useInfiniteModelQuery('User', `${endpoint}/user/findMany`, args, options, fetch); 68 | } 69 | 70 | export function useFindUniqueUser & { $optimistic?: boolean }, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 71 | const { endpoint, fetch } = getHooksContext(); 72 | return useModelQuery('User', `${endpoint}/user/findUnique`, args, options, fetch); 73 | } 74 | 75 | export function useFindFirstUser & { $optimistic?: boolean }, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 76 | const { endpoint, fetch } = getHooksContext(); 77 | return useModelQuery('User', `${endpoint}/user/findFirst`, args, options, fetch); 78 | } 79 | 80 | export function useUpdateUser(options?: Omit<(MutationOptions<(User | undefined), DefaultError, Prisma.UserUpdateArgs> & ExtraMutationOptions), 'mutationFn'>) { 81 | const { endpoint, fetch } = getHooksContext(); 82 | const _mutation = 83 | useModelMutation('User', 'PUT', `${endpoint}/user/update`, metadata, options, fetch, true) 84 | ; 85 | const mutation = derived(_mutation, value => ({ 86 | ...value, 87 | mutateAsync: async ( 88 | args: Prisma.SelectSubset, 89 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 90 | ) => { 91 | return (await value.mutateAsync( 92 | args, 93 | options as any 94 | )) as (CheckSelect> | undefined); 95 | }, 96 | })); 97 | return mutation; 98 | } 99 | 100 | export function useUpdateManyUser(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 101 | const { endpoint, fetch } = getHooksContext(); 102 | const _mutation = 103 | useModelMutation('User', 'PUT', `${endpoint}/user/updateMany`, metadata, options, fetch, false) 104 | ; 105 | const mutation = derived(_mutation, value => ({ 106 | ...value, 107 | mutateAsync: async ( 108 | args: Prisma.SelectSubset, 109 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 110 | ) => { 111 | return (await value.mutateAsync( 112 | args, 113 | options as any 114 | )) as Prisma.BatchPayload; 115 | }, 116 | })); 117 | return mutation; 118 | } 119 | 120 | export function useUpsertUser(options?: Omit<(MutationOptions<(User | undefined), DefaultError, Prisma.UserUpsertArgs> & ExtraMutationOptions), 'mutationFn'>) { 121 | const { endpoint, fetch } = getHooksContext(); 122 | const _mutation = 123 | useModelMutation('User', 'POST', `${endpoint}/user/upsert`, metadata, options, fetch, true) 124 | ; 125 | const mutation = derived(_mutation, value => ({ 126 | ...value, 127 | mutateAsync: async ( 128 | args: Prisma.SelectSubset, 129 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 130 | ) => { 131 | return (await value.mutateAsync( 132 | args, 133 | options as any 134 | )) as (CheckSelect> | undefined); 135 | }, 136 | })); 137 | return mutation; 138 | } 139 | 140 | export function useDeleteUser(options?: Omit<(MutationOptions<(User | undefined), DefaultError, Prisma.UserDeleteArgs> & ExtraMutationOptions), 'mutationFn'>) { 141 | const { endpoint, fetch } = getHooksContext(); 142 | const _mutation = 143 | useModelMutation('User', 'DELETE', `${endpoint}/user/delete`, metadata, options, fetch, true) 144 | ; 145 | const mutation = derived(_mutation, value => ({ 146 | ...value, 147 | mutateAsync: async ( 148 | args: Prisma.SelectSubset, 149 | options?: Omit<(MutationOptions<(CheckSelect> | undefined), DefaultError, Prisma.SelectSubset> & ExtraMutationOptions), 'mutationFn'> 150 | ) => { 151 | return (await value.mutateAsync( 152 | args, 153 | options as any 154 | )) as (CheckSelect> | undefined); 155 | }, 156 | })); 157 | return mutation; 158 | } 159 | 160 | export function useDeleteManyUser(options?: Omit<(MutationOptions & ExtraMutationOptions), 'mutationFn'>) { 161 | const { endpoint, fetch } = getHooksContext(); 162 | const _mutation = 163 | useModelMutation('User', 'DELETE', `${endpoint}/user/deleteMany`, metadata, options, fetch, false) 164 | ; 165 | const mutation = derived(_mutation, value => ({ 166 | ...value, 167 | mutateAsync: async ( 168 | args: Prisma.SelectSubset, 169 | options?: Omit<(MutationOptions> & ExtraMutationOptions), 'mutationFn'> 170 | ) => { 171 | return (await value.mutateAsync( 172 | args, 173 | options as any 174 | )) as Prisma.BatchPayload; 175 | }, 176 | })); 177 | return mutation; 178 | } 179 | 180 | export function useAggregateUser, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 181 | const { endpoint, fetch } = getHooksContext(); 182 | return useModelQuery('User', `${endpoint}/user/aggregate`, args, options, fetch); 183 | } 184 | 185 | export function useGroupByUser>, Prisma.Extends<'take', Prisma.Keys>>, OrderByArg extends Prisma.True extends HasSelectOrTake ? { orderBy: Prisma.UserGroupByArgs['orderBy'] } : { orderBy?: Prisma.UserGroupByArgs['orderBy'] }, OrderFields extends Prisma.ExcludeUnderscoreKeys>>, ByFields extends Prisma.MaybeTupleToUnion, ByValid extends Prisma.Has, HavingFields extends Prisma.GetHavingFields, HavingValid extends Prisma.Has, ByEmpty extends TArgs['by'] extends never[] ? Prisma.True : Prisma.False, InputErrors extends ByEmpty extends Prisma.True 186 | ? `Error: "by" must not be empty.` 187 | : HavingValid extends Prisma.False 188 | ? { 189 | [P in HavingFields]: P extends ByFields 190 | ? never 191 | : P extends string 192 | ? `Error: Field "${P}" used in "having" needs to be provided in "by".` 193 | : [ 194 | Error, 195 | 'Field ', 196 | P, 197 | ` in "having" needs to be provided in "by"`, 198 | ] 199 | }[HavingFields] 200 | : 'take' extends Prisma.Keys 201 | ? 'orderBy' extends Prisma.Keys 202 | ? ByValid extends Prisma.True 203 | ? {} 204 | : { 205 | [P in OrderFields]: P extends ByFields 206 | ? never 207 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 208 | }[OrderFields] 209 | : 'Error: If you provide "take", you also need to provide "orderBy"' 210 | : 'skip' extends Prisma.Keys 211 | ? 'orderBy' extends Prisma.Keys 212 | ? ByValid extends Prisma.True 213 | ? {} 214 | : { 215 | [P in OrderFields]: P extends ByFields 216 | ? never 217 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 218 | }[OrderFields] 219 | : 'Error: If you provide "skip", you also need to provide "orderBy"' 220 | : ByValid extends Prisma.True 221 | ? {} 222 | : { 223 | [P in OrderFields]: P extends ByFields 224 | ? never 225 | : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` 226 | }[OrderFields], TQueryFnData = {} extends InputErrors ? 227 | Array & 228 | { 229 | [P in ((keyof TArgs) & (keyof Prisma.UserGroupByOutputType))]: P extends '_count' 230 | ? TArgs[P] extends boolean 231 | ? number 232 | : Prisma.GetScalarType 233 | : Prisma.GetScalarType 234 | } 235 | > : InputErrors, TData = TQueryFnData, TError = DefaultError>(args: Prisma.SelectSubset & InputErrors>, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 236 | const { endpoint, fetch } = getHooksContext(); 237 | return useModelQuery('User', `${endpoint}/user/groupBy`, args, options, fetch); 238 | } 239 | 240 | export function useCountUser : number, TData = TQueryFnData, TError = DefaultError>(args?: Prisma.SelectSubset, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 241 | const { endpoint, fetch } = getHooksContext(); 242 | return useModelQuery('User', `${endpoint}/user/count`, args, options, fetch); 243 | } 244 | 245 | export function useCheckUser(args: { operation: PolicyCrudKind; where?: { id?: string; email?: string; password?: string; name?: string }; }, options?: (StoreOrVal, 'queryKey'>> & ExtraQueryOptions)) { 246 | const { endpoint, fetch } = getHooksContext(); 247 | return useModelQuery('User', `${endpoint}/user/check`, args, options, fetch); 248 | } 249 | -------------------------------------------------------------------------------- /src/lib/prisma.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from '@prisma/client'; 2 | import { enhance } from '@zenstackhq/runtime'; 3 | 4 | const prisma = new PrismaClient(); 5 | 6 | export function getEnhancedPrisma(userId?: string) { 7 | return enhance(prisma, { user: userId ? { id: userId } : undefined }); 8 | } 9 | 10 | export default prisma; 11 | -------------------------------------------------------------------------------- /src/routes/(app)/+layout.server.ts: -------------------------------------------------------------------------------- 1 | import { redirect } from '@sveltejs/kit'; 2 | import type { LayoutServerLoad } from './$types'; 3 | 4 | export const load = (async ({ locals }) => { 5 | if (!locals.user) { 6 | throw redirect(303, '/signin'); 7 | } 8 | return { 9 | user: locals.user, 10 | }; 11 | }) satisfies LayoutServerLoad; 12 | -------------------------------------------------------------------------------- /src/routes/(app)/+layout.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 |
    14 | 15 | 16 |
    17 | -------------------------------------------------------------------------------- /src/routes/(app)/+page.server.ts: -------------------------------------------------------------------------------- 1 | import type { PageServerLoad } from './$types'; 2 | 3 | export const load = (async ({ locals }) => { 4 | const spaces = await locals.db.space.findMany({ 5 | orderBy: { createdAt: 'desc' }, 6 | }); 7 | return { user: locals.user!, spaces }; 8 | }) satisfies PageServerLoad; 9 | -------------------------------------------------------------------------------- /src/routes/(app)/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
    9 |

    10 | Welcome {data.user.name || data.user.email}! 11 |

    12 | 13 |
    14 |

    15 | Choose a space to start, or{' '} 16 | 17 | create a new one. 18 | 19 |

    20 | 21 | 22 |
    23 |
    24 | -------------------------------------------------------------------------------- /src/routes/(app)/create-space/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { SpaceUserRole, type Space } from '@prisma/client'; 2 | import { error, fail, redirect, type Actions } from '@sveltejs/kit'; 3 | import { isPrismaClientKnownRequestError } from '@zenstackhq/runtime'; 4 | 5 | export const actions = { 6 | default: async ({ request, locals }) => { 7 | if (!locals.user) { 8 | throw error(401, 'Unauthorized'); 9 | } 10 | 11 | const data = await request.formData(); 12 | const name = data.get('name'); 13 | const slug = data.get('slug'); 14 | 15 | if (typeof name !== 'string' || typeof slug !== 'string') { 16 | return fail(400, { name, slug, missing: true }); 17 | } 18 | 19 | let space: Space; 20 | try { 21 | space = await locals.db.space.create({ 22 | data: { 23 | name, 24 | slug, 25 | owner: { connect: { id: locals.user.id } }, 26 | members: { 27 | create: { 28 | user: { connect: { id: locals.user.id } }, 29 | role: SpaceUserRole.ADMIN, 30 | }, 31 | }, 32 | }, 33 | }); 34 | } catch (err) { 35 | if (isPrismaClientKnownRequestError(err) && err.code === 'P2002') { 36 | return fail(400, { name, slug, dup: true }); 37 | } else { 38 | throw err; 39 | } 40 | } 41 | 42 | throw redirect(303, `/space/${space.slug}`); 43 | }, 44 | } satisfies Actions; 45 | -------------------------------------------------------------------------------- /src/routes/(app)/create-space/+page.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |
    13 |
    14 |

    Create a space

    15 | {#if form?.dup} 16 |

    Slug already in use!

    17 | {/if} 18 |
    19 |
    20 | 21 | 22 | 31 |
    32 |
    33 | 34 | 42 |
    43 |
    44 | 45 |
    46 | 20 || 50 | !slug.match(/^[0-9a-zA-Z]{4,16}$/)} 51 | value="Create" 52 | class="btn btn-primary px-8" 53 | /> 54 | 57 |
    58 |
    59 |
    60 | -------------------------------------------------------------------------------- /src/routes/(app)/space/[slug]/+layout.server.ts: -------------------------------------------------------------------------------- 1 | import { error } from '@sveltejs/kit'; 2 | import type { LayoutServerLoad } from './$types'; 3 | 4 | export const load = (async ({ locals, params }) => { 5 | const space = await locals.db.space.findUnique({ 6 | where: { slug: params.slug }, 7 | }); 8 | if (!space) { 9 | throw error(404, 'Space not found'); 10 | } 11 | return { space }; 12 | }) satisfies LayoutServerLoad; 13 | -------------------------------------------------------------------------------- /src/routes/(app)/space/[slug]/+page.server.ts: -------------------------------------------------------------------------------- 1 | import type { PageServerLoad } from './$types'; 2 | 3 | export const load = (async ({ locals, params }) => { 4 | const lists = await locals.db.list.findMany({ 5 | where: { 6 | space: { slug: params.slug }, 7 | }, 8 | include: { 9 | owner: true, 10 | }, 11 | orderBy: { 12 | updatedAt: 'desc', 13 | }, 14 | }); 15 | 16 | const members = locals.db.spaceUser.findMany({ 17 | where: { 18 | space: { slug: params.slug }, 19 | }, 20 | include: { 21 | user: true, 22 | }, 23 | orderBy: { 24 | role: 'desc', 25 | }, 26 | }); 27 | 28 | return { 29 | lists, 30 | members, 31 | }; 32 | }) satisfies PageServerLoad; 33 | -------------------------------------------------------------------------------- /src/routes/(app)/space/[slug]/+page.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
    12 |
    13 | 14 |
    15 |
    16 |
    19 | 25 | 26 |
    27 | 28 |
      29 | {#each data.lists as list (list.id)} 30 |
    • 31 | 32 |
    • 33 | {/each} 34 |
    35 |
    36 | 37 |
    38 | -------------------------------------------------------------------------------- /src/routes/(app)/space/[slug]/[listId]/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { error } from '@sveltejs/kit'; 2 | import type { Actions, PageServerLoad } from './$types'; 3 | 4 | export const load = (async ({ locals, params }) => { 5 | const list = await locals.db.list.findUnique({ 6 | where: { id: params?.listId as string }, 7 | }); 8 | if (!list) { 9 | throw error(404, 'List not found'); 10 | } 11 | 12 | const todos = await locals.db.todo.findMany({ 13 | where: { listId: params?.listId as string }, 14 | include: { 15 | owner: true, 16 | }, 17 | orderBy: { 18 | updatedAt: 'desc', 19 | }, 20 | }); 21 | return { list, todos }; 22 | }) satisfies PageServerLoad; 23 | 24 | export const actions = { 25 | create: async ({ request, locals, params }) => { 26 | const data = await request.formData(); 27 | const title = data.get('title') as string; 28 | await locals.db.todo.create({ 29 | data: { 30 | title, 31 | list: { connect: { id: params.listId } }, 32 | }, 33 | }); 34 | }, 35 | 36 | complete: async ({ request, locals }) => { 37 | const data = await request.formData(); 38 | const todoId = data.get('todoId') as string; 39 | const completed = data.get('completed') as string; 40 | await locals.db.todo.update({ 41 | where: { id: todoId }, 42 | data: { completedAt: completed === 'on' ? new Date() : null }, 43 | }); 44 | }, 45 | 46 | delete: async ({ request, locals }) => { 47 | const data = await request.formData(); 48 | const todoId = data.get('todoId') as string; 49 | await locals.db.todo.delete({ where: { id: todoId } }); 50 | }, 51 | } satisfies Actions; 52 | -------------------------------------------------------------------------------- /src/routes/(app)/space/[slug]/[listId]/+page.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |
    13 | 14 |
    15 |
    16 |

    17 | {data.list?.title} 18 |

    19 |
    20 | 21 | 29 | 32 |
    33 |
      34 | {#each data.todos as todo (todo.id)} 35 | 36 | {/each} 37 |
    38 |
    39 | -------------------------------------------------------------------------------- /src/routes/(auth)/signin/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { createToken } from '$lib/auth'; 2 | import { JWT_TOKEN_COOKIE_NAME } from '$lib/constant'; 3 | import prisma from '$lib/prisma'; 4 | import { fail, redirect, type Actions } from '@sveltejs/kit'; 5 | import bcrypt from 'bcryptjs'; 6 | 7 | export const actions = { 8 | default: async ({ request, cookies }) => { 9 | const data = await request.formData(); 10 | 11 | const email = data.get('email'); 12 | const password = data.get('password'); 13 | 14 | if (typeof email !== 'string' || typeof password !== 'string') { 15 | return fail(400, { email, password, missing: true }); 16 | } 17 | 18 | const user = await prisma.user.findFirst({ 19 | where: { email }, 20 | }); 21 | if (!user || !bcrypt.compareSync(password, user.password)) { 22 | return fail(401, { email, password, invalid: true }); 23 | } 24 | 25 | const token = createToken(user); 26 | cookies.set(JWT_TOKEN_COOKIE_NAME, token, { 27 | httpOnly: true, 28 | expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), 29 | path: '/', 30 | }); 31 | throw redirect(303, `/`); 32 | }, 33 | } satisfies Actions; 34 | -------------------------------------------------------------------------------- /src/routes/(auth)/signin/+page.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
    8 |
    11 | 12 |
    13 | logo 14 |

    Welcome to Todo

    15 |
    16 |
    17 |
    20 |
    21 |

    22 | Sign in to your account 23 |

    24 |
    25 | {#if form?.missing} 26 |

    Missing field required!

    27 | {/if} 28 | {#if form?.invalid} 29 |

    30 | Invalid email and password combination! 31 |

    32 | {/if} 33 |
    34 | 40 | 49 |
    50 |
    51 | 57 | 66 |
    67 |
    68 |
    69 |
    70 | 77 |
    78 |
    79 | 85 |
    86 |
    87 |
    88 | 91 |
    92 | Not registered? {' '} 93 | 94 | Create Account 95 | 96 |
    97 |
    98 |
    99 |
    100 |
    101 |
    102 | -------------------------------------------------------------------------------- /src/routes/(auth)/signup/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { createToken } from '$lib/auth'; 2 | import { JWT_TOKEN_COOKIE_NAME } from '$lib/constant'; 3 | import { getEnhancedPrisma } from '$lib/prisma'; 4 | import { SpaceUserRole } from '@prisma/client'; 5 | import { fail, redirect, type Actions } from '@sveltejs/kit'; 6 | import { isPrismaClientKnownRequestError } from '@zenstackhq/runtime'; 7 | import { nanoid } from 'nanoid'; 8 | 9 | export const actions = { 10 | default: async ({ request, cookies, locals }) => { 11 | const data = await request.formData(); 12 | 13 | const email = data.get('email'); 14 | const password = data.get('password'); 15 | 16 | if (typeof email !== 'string' || typeof password !== 'string') { 17 | return fail(400, { email, password, missing: true }); 18 | } 19 | 20 | let db = locals.db; 21 | 22 | try { 23 | // create the user together with a default space 24 | const user = await db.user.create({ 25 | data: { 26 | email, 27 | password, 28 | }, 29 | }); 30 | 31 | // use db under the context of the new user 32 | db = getEnhancedPrisma(user.id); 33 | 34 | const space = await db.space.create({ 35 | data: { 36 | name: `My Space`, 37 | slug: nanoid(8), 38 | owner: { connect: { id: user.id } }, 39 | members: { 40 | create: { 41 | user: { connect: { id: user.id } }, 42 | role: SpaceUserRole.ADMIN, 43 | }, 44 | }, 45 | }, 46 | }); 47 | console.log('Space created for user:', space); 48 | 49 | const token = createToken(user); 50 | cookies.set(JWT_TOKEN_COOKIE_NAME, token, { 51 | httpOnly: true, 52 | expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), 53 | path: '/', 54 | }); 55 | } catch (err) { 56 | if (isPrismaClientKnownRequestError(err) && err.code === 'P2002') { 57 | return fail(400, { email, password, dup: true }); 58 | } else { 59 | throw err; 60 | } 61 | } 62 | 63 | throw redirect(303, `/`); 64 | }, 65 | } satisfies Actions; 66 | -------------------------------------------------------------------------------- /src/routes/(auth)/signup/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
    9 |
    12 | 13 |
    14 | logo 15 |

    Welcome to Todo

    16 |
    17 |
    18 |
    21 |
    22 |

    23 | Create a Free Account 24 |

    25 |
    26 | {#if form?.dup} 27 |

    28 | Email already registered! 29 |

    30 | {/if} 31 |
    32 | 38 | 47 |
    48 |
    49 | 55 | 64 |
    65 |
    66 |
    67 | 75 |
    76 |
    77 | 90 |
    91 |
    92 | 95 |
    96 | Already have an account?{' '} 97 | 98 | Login here 99 | 100 |
    101 |
    102 |
    103 |
    104 |
    105 |
    106 | -------------------------------------------------------------------------------- /src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 17 | 18 |
    19 | 20 | 21 | 22 |
    23 | -------------------------------------------------------------------------------- /src/routes/api/auth/signin/+server.ts: -------------------------------------------------------------------------------- 1 | import { createToken } from '$lib/auth'; 2 | import { JWT_TOKEN_COOKIE_NAME } from '$lib/constant'; 3 | import prisma from '$lib/prisma'; 4 | import { error, json, type RequestHandler } from '@sveltejs/kit'; 5 | import bcrypt from 'bcryptjs'; 6 | 7 | export const POST = (async ({ request, cookies }) => { 8 | const { email, password } = await request.json(); 9 | 10 | if (typeof email !== 'string' || typeof password !== 'string') { 11 | throw error(400, 'Invalid credentials'); 12 | } 13 | 14 | const user = await prisma.user.findFirst({ 15 | where: { email }, 16 | }); 17 | if (!user || !bcrypt.compareSync(password, user.password)) { 18 | throw error(401, 'Invalid credentials'); 19 | } 20 | 21 | const token = createToken(user); 22 | cookies.set(JWT_TOKEN_COOKIE_NAME, token, { 23 | httpOnly: true, 24 | expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), 25 | path: '/', 26 | }); 27 | return json({ success: true, data: user }); 28 | }) satisfies RequestHandler; 29 | -------------------------------------------------------------------------------- /src/routes/api/auth/signout/+server.ts: -------------------------------------------------------------------------------- 1 | import { JWT_TOKEN_COOKIE_NAME } from '$lib/constant'; 2 | import { redirect, type RequestHandler } from '@sveltejs/kit'; 3 | 4 | export const POST = (({ cookies }) => { 5 | cookies.delete(JWT_TOKEN_COOKIE_NAME, { path: '/' }); 6 | throw redirect(303, '/signin'); 7 | }) satisfies RequestHandler; 8 | -------------------------------------------------------------------------------- /static/auth-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenstackhq/sample-todo-sveltekit/31b907fbc6ca8e23bb113478ece3ff192da92ec1/static/auth-bg.jpg -------------------------------------------------------------------------------- /static/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenstackhq/sample-todo-sveltekit/31b907fbc6ca8e23bb113478ece3ff192da92ec1/static/avatar.jpg -------------------------------------------------------------------------------- /static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenstackhq/sample-todo-sveltekit/31b907fbc6ca8e23bb113478ece3ff192da92ec1/static/logo.png -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | // import preprocess from 'svelte-preprocess'; 3 | import { vitePreprocess } from '@sveltejs/kit/vite'; 4 | 5 | /** @type {import('@sveltejs/kit').Config} */ 6 | const config = { 7 | // Consult https://github.com/sveltejs/svelte-preprocess 8 | // for more information about preprocessors 9 | preprocess: vitePreprocess(), 10 | 11 | kit: { 12 | adapter: adapter(), 13 | }, 14 | }; 15 | 16 | export default config; 17 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ['./src/**/*.{html,js,svelte,ts}'], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [require('daisyui'), require('@tailwindcss/line-clamp')], 8 | daisyui: { 9 | themes: false, 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | }, 13 | "ts-node": { 14 | "esm": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | 3 | /** @type {import('vite').UserConfig} */ 4 | const config = { 5 | plugins: [sveltekit()], 6 | resolve: { 7 | alias: { 8 | '.prisma/client/index-browser': 9 | './node_modules/.prisma/client/index-browser.js', 10 | }, 11 | }, 12 | ssr: { 13 | // this is needed to make sure "vite" processes "@tanstack/svelte-query" imported inside 14 | // "@zenstackhq/tanstack-query" 15 | noExternal: ['@zenstackhq/tanstack-query'], 16 | }, 17 | }; 18 | 19 | export default config; 20 | --------------------------------------------------------------------------------