├── .npmrc ├── static ├── favicon.ico └── favicon.png ├── docs ├── screen-game.png ├── screen-intro.png └── screen-ssr.png ├── .env.example ├── .prettierrc ├── postcss.config.cjs ├── .gitignore ├── src ├── app.css ├── routes │ ├── __layout.svelte │ ├── index.svelte │ └── casino.svelte ├── app.d.ts ├── lib │ ├── Loading.svelte │ ├── alert.ts │ └── appwrite.ts ├── hooks.ts └── app.html ├── .eslintignore ├── .prettierignore ├── tsconfig.json ├── functions ├── placeBet │ ├── package.json │ ├── src │ │ └── index.js │ └── README.md └── createProfile │ ├── package.json │ ├── src │ └── index.js │ └── README.md ├── tailwind.config.cjs ├── .eslintrc.cjs ├── svelte.config.js ├── LICENSE ├── package.json ├── _appwrite.json └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesbii/near-casino/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesbii/near-casino/HEAD/static/favicon.png -------------------------------------------------------------------------------- /docs/screen-game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesbii/near-casino/HEAD/docs/screen-game.png -------------------------------------------------------------------------------- /docs/screen-intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesbii/near-casino/HEAD/docs/screen-intro.png -------------------------------------------------------------------------------- /docs/screen-ssr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesbii/near-casino/HEAD/docs/screen-ssr.png -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | VITE_APPWRITE_ENDPOINT=https://demo.appwrite.io/v1 2 | VITE_APPWRITE_PROJECT_ID=nearCasino -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100 6 | } 7 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | .vercel_build_output -------------------------------------------------------------------------------- /src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | body { 6 | font-family: 'Libre Baskerville', serif; 7 | } 8 | -------------------------------------------------------------------------------- /src/routes/__layout.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | // See https://kit.svelte.dev/docs/types#app 4 | // for information about these interfaces 5 | declare namespace App { 6 | // interface Locals {} 7 | // interface Platform {} 8 | // interface Session {} 9 | // interface Stuff {} 10 | } 11 | -------------------------------------------------------------------------------- /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 | } 14 | -------------------------------------------------------------------------------- /functions/placeBet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "appwrite-function", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "node-appwrite": "^5.0.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /functions/createProfile/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "appwrite-function", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "node-appwrite": "^5.0.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/Loading.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /src/hooks.ts: -------------------------------------------------------------------------------- 1 | import * as cookie from 'cookie'; 2 | 3 | export function getSession(event: any) { 4 | const cookieStr = event.request.headers.get("cookie"); 5 | const cookies = cookie.parse(cookieStr || ''); 6 | const authCookie = cookies[`a_session_${import.meta.env.VITE_APPWRITE_PROJECT_ID.toLowerCase()}_legacy`]; 7 | 8 | console.log(cookieStr); 9 | console.log(authCookie); 10 | 11 | return { 12 | authCookie 13 | } 14 | } -------------------------------------------------------------------------------- /tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ['./src/**/*.{html,js,svelte,ts}'], 3 | 4 | theme: { 5 | extend: { 6 | colors: { 7 | 'brand': { 8 | '50': '#faf9ec', 9 | '100': '#f3f1ce', 10 | '200': '#e9e29f', 11 | '300': '#dccc68', 12 | '400': '#cfb53b', 13 | '500': '#c1a231', 14 | '600': '#a68028', 15 | '700': '#855f23', 16 | '800': '#6f4e24', 17 | '900': '#604223', 18 | }, 19 | 20 | } 21 | }, 22 | }, 23 | plugins: [], 24 | } 25 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Near Casino 9 | 10 | 11 | 12 | 16 | 17 | %sveltekit.head% 18 | 19 | 20 |
%sveltekit.body%
21 | 22 | 23 | -------------------------------------------------------------------------------- /src/lib/alert.ts: -------------------------------------------------------------------------------- 1 | import { toast } from '@zerodevx/svelte-toast'; 2 | 3 | export class Alert { 4 | public static success(msg: string) { 5 | toast.push(msg, { 6 | theme: { 7 | '--toastBackground': '#16a34a', 8 | '--toastBarBackground': '#166534' 9 | } 10 | }) 11 | } 12 | 13 | public static warning(msg: string) { 14 | toast.push(msg, { 15 | theme: { 16 | '--toastBackground': '#ea580c', 17 | '--toastBarBackground': '#9a3412' 18 | } 19 | }) 20 | } 21 | 22 | public static error(msg: string) { 23 | toast.push(msg, { 24 | theme: { 25 | '--toastBackground': '#dc2626', 26 | '--toastBarBackground': '#991b1b' 27 | } 28 | }) 29 | } 30 | } -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-vercel'; 2 | import preprocess from 'svelte-preprocess'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://github.com/sveltejs/svelte-preprocess 7 | // for more information about preprocessors 8 | preprocess: [ 9 | preprocess({ 10 | postcss: true, 11 | }), 12 | ], 13 | 14 | kit: { 15 | adapter: adapter({ 16 | // if true, will deploy the app using edge functions 17 | // (https://vercel.com/docs/concepts/functions/edge-functions) 18 | // rather than serverless functions 19 | edge: false, 20 | 21 | // an array of dependencies that esbuild should treat 22 | // as external when bundling functions 23 | external: [], 24 | 25 | // if true, will split your app into multiple functions 26 | // instead of creating a single one for the entire app 27 | split: false 28 | }) 29 | } 30 | }; 31 | 32 | export default config; 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Otto Mayer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "near-casino", 3 | "version": "0.1", 4 | "scripts": { 5 | "dev": "svelte-kit dev", 6 | "build": "svelte-kit build", 7 | "package": "svelte-kit package", 8 | "preview": "svelte-kit preview", 9 | "prepare": "svelte-kit sync", 10 | "check": "svelte-check --tsconfig ./tsconfig.json", 11 | "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch", 12 | "lint": "prettier --check --plugin-search-dir=. . && eslint .", 13 | "format": "prettier --write --plugin-search-dir=. ." 14 | }, 15 | "devDependencies": { 16 | "@sveltejs/adapter-auto": "next", 17 | "@sveltejs/kit": "next", 18 | "@types/cookie": "^0.5.1", 19 | "@typescript-eslint/eslint-plugin": "^5.10.1", 20 | "@typescript-eslint/parser": "^5.10.1", 21 | "@zerodevx/svelte-toast": "^0.7.2", 22 | "autoprefixer": "^10.4.7", 23 | "eslint": "^8.12.0", 24 | "eslint-config-prettier": "^8.3.0", 25 | "eslint-plugin-svelte3": "^4.0.0", 26 | "postcss": "^8.4.14", 27 | "prettier": "^2.5.1", 28 | "prettier-plugin-svelte": "^2.5.0", 29 | "svelte": "^3.44.0", 30 | "svelte-check": "^2.2.6", 31 | "svelte-preprocess": "^4.10.6", 32 | "tailwindcss": "^3.0.24", 33 | "tslib": "^2.3.1", 34 | "typescript": "~4.6.2" 35 | }, 36 | "type": "module", 37 | "dependencies": { 38 | "@sveltejs/adapter-vercel": "^1.0.0-next.58", 39 | "appwrite": "^8.0.1", 40 | "cookie": "^0.5.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /functions/createProfile/src/index.js: -------------------------------------------------------------------------------- 1 | const sdk = require("node-appwrite"); 2 | 3 | /* 4 | 'req' variable has: 5 | 'headers' - object with request headers 6 | 'payload' - object with request body data 7 | 'env' - object with environment variables 8 | 9 | 'res' variable has: 10 | 'send(text, status)' - function to return text response. Status code defaults to 200 11 | 'json(obj, status)' - function to return JSON response. Status code defaults to 200 12 | 13 | If an error is thrown, a response with code 500 will be returned. 14 | */ 15 | 16 | module.exports = async function (req, res) { 17 | const client = new sdk.Client(); 18 | 19 | const db = new sdk.Database(client); 20 | 21 | if ( 22 | !req.env['APPWRITE_FUNCTION_ENDPOINT'] || 23 | !req.env['APPWRITE_FUNCTION_PROJECT_ID'] || 24 | !req.env['APPWRITE_FUNCTION_USER_ID'] || 25 | !req.env['APPWRITE_FUNCTION_API_KEY'] 26 | ) { 27 | throw new Error("Missing environment variables."); 28 | } 29 | 30 | const userId = req.env['APPWRITE_FUNCTION_USER_ID']; 31 | 32 | client 33 | .setEndpoint(req.env['APPWRITE_FUNCTION_ENDPOINT']) 34 | .setProject(req.env['APPWRITE_FUNCTION_PROJECT_ID']) 35 | .setKey(req.env['APPWRITE_FUNCTION_API_KEY']); 36 | 37 | let profile; 38 | 39 | try { 40 | profile = await db.getDocument('profiles', userId); 41 | 42 | } catch (err) { 43 | profile = await db.createDocument('profiles', userId, { 44 | balance: 500 45 | }); 46 | } 47 | 48 | res.json({ 49 | profile 50 | }); 51 | }; 52 | -------------------------------------------------------------------------------- /_appwrite.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectId": "nearCasino", 3 | "projectName": "Near Casino", 4 | "collections": [ 5 | { 6 | "$id": "profiles", 7 | "$read": [ 8 | "role:member" 9 | ], 10 | "$write": [], 11 | "name": "profiles", 12 | "enabled": true, 13 | "permission": "collection", 14 | "attributes": [ 15 | { 16 | "key": "balance", 17 | "type": "double", 18 | "status": "available", 19 | "required": true, 20 | "array": false, 21 | "min": -1.7976931348623157e+308, 22 | "max": 1.7976931348623157e+308, 23 | "default": null 24 | } 25 | ], 26 | "indexes": [] 27 | } 28 | ], 29 | "functions": [ 30 | { 31 | "$id": "createProfile", 32 | "name": "createProfile", 33 | "runtime": "node-16.0", 34 | "path": "functions/createProfile", 35 | "entrypoint": "src/index.js", 36 | "execute": [ 37 | "role:member" 38 | ], 39 | "events": [], 40 | "schedule": "", 41 | "timeout": 5 42 | }, 43 | { 44 | "$id": "placeBet", 45 | "name": "placeBet", 46 | "runtime": "node-16.0", 47 | "path": "functions/placeBet", 48 | "entrypoint": "src/index.js", 49 | "execute": [ 50 | "role:member" 51 | ], 52 | "events": [], 53 | "schedule": "", 54 | "timeout": 5 55 | } 56 | ] 57 | } -------------------------------------------------------------------------------- /functions/placeBet/src/index.js: -------------------------------------------------------------------------------- 1 | const sdk = require("node-appwrite"); 2 | 3 | /* 4 | 'req' variable has: 5 | 'headers' - object with request headers 6 | 'payload' - object with request body data 7 | 'env' - object with environment variables 8 | 9 | 'res' variable has: 10 | 'send(text, status)' - function to return text response. Status code defaults to 200 11 | 'json(obj, status)' - function to return JSON response. Status code defaults to 200 12 | 13 | If an error is thrown, a response with code 500 will be returned. 14 | */ 15 | 16 | module.exports = async function (req, res) { 17 | const { betPrice, betSide } = JSON.parse(req.payload || '{}'); 18 | 19 | if (!betPrice || !betSide) { 20 | throw new Error("Set a bet price and pick a coin side."); 21 | } 22 | 23 | const client = new sdk.Client(); 24 | 25 | const db = new sdk.Database(client); 26 | 27 | if ( 28 | !req.env['APPWRITE_FUNCTION_ENDPOINT'] || 29 | !req.env['APPWRITE_FUNCTION_PROJECT_ID'] || 30 | !req.env['APPWRITE_FUNCTION_USER_ID'] || 31 | !req.env['APPWRITE_FUNCTION_API_KEY'] 32 | ) { 33 | throw new Error("Missing environment variables."); 34 | } 35 | 36 | const userId = req.env['APPWRITE_FUNCTION_USER_ID']; 37 | 38 | client 39 | .setEndpoint(req.env['APPWRITE_FUNCTION_ENDPOINT']) 40 | .setProject(req.env['APPWRITE_FUNCTION_PROJECT_ID']) 41 | .setKey(req.env['APPWRITE_FUNCTION_API_KEY']); 42 | 43 | const profile = await db.getDocument('profiles', userId); 44 | 45 | if (betPrice > profile.balance) { 46 | throw new Error(`You can only bet up to ${profile.balance} Near Dollars.`); 47 | } 48 | 49 | const didWin = betSide === 'heads' ? Math.random() <= 0.5 : Math.random() >= 0.5; 50 | const change = didWin ? betPrice : -betPrice; 51 | 52 | await db.updateDocument('profiles', userId, { 53 | balance: profile.balance + change 54 | }); 55 | 56 | res.json({ 57 | didWin 58 | }); 59 | }; 60 | -------------------------------------------------------------------------------- /functions/createProfile/README.md: -------------------------------------------------------------------------------- 1 | # createProfile 2 | 3 | Welcome to the documentation of this function 👋 We strongly recommend keeping this file in sync with your function's logic to make sure anyone can easily understand your function in the future. If you don't need documentation, you can remove this file. 4 | 5 | ## 🤖 Documentation 6 | 7 | A function meant to be executed from a client-side right after creating Appwrite Account. This method created a profile document with a default balance set. 8 | 9 | _Example input:_ 10 | 11 | This function expects no input. 12 | 13 | _Example output:_ 14 | 15 | ```json 16 | { 17 | "$id": "SOME_USER_ID", 18 | "balance": 500 19 | } 20 | ``` 21 | 22 | ## 📝 Environment Variables 23 | 24 | List of environment variables used by this cloud function: 25 | 26 | - **APPWRITE_FUNCTION_ENDPOINT** - Endpoint of Appwrite project 27 | - **APPWRITE_FUNCTION_API_KEY** - Appwrite API Key 28 | 29 | ## 🚀 Deployment 30 | 31 | There are two ways of deploying the Appwrite function, both having the same results, but each using a different process. We highly recommend using CLI deployment to achieve the best experience. 32 | 33 | ### Using CLI 34 | 35 | Make sure you have [Appwrite CLI](https://appwrite.io/docs/command-line#installation) installed, and you have successfully logged into your Appwrite server. To make sure Appwrite CLI is ready, you can use the command `appwrite client --debug` and it should respond with green text `✓ Success`. 36 | 37 | Make sure you are in the same folder as your `appwrite.json` file and run `appwrite deploy function` to deploy your function. You will be prompted to select which functions you want to deploy. 38 | 39 | ### Manual using tar.gz 40 | 41 | Manual deployment has no requirements and uses Appwrite Console to deploy the tag. First, enter the folder of your function. Then, create a tarball of the whole folder and gzip it. After creating `.tar.gz` file, visit Appwrite Console, click on the `Deploy Tag` button and switch to the `Manual` tab. There, set the `entrypoint` to `src/index.js`, and upload the file we just generated. 42 | -------------------------------------------------------------------------------- /functions/placeBet/README.md: -------------------------------------------------------------------------------- 1 | # placeBet 2 | 3 | Welcome to the documentation of this function 👋 We strongly recommend keeping this file in sync with your function's logic to make sure anyone can easily understand your function in the future. If you don't need documentation, you can remove this file. 4 | 5 | ## 🤖 Documentation 6 | 7 | A method to bet on coin flip. 8 | 9 | _Example input:_ 10 | 11 | ```json 12 | { 13 | "betPrice": 12, 14 | "betSide": "heads" 15 | } 16 | ``` 17 | 18 | ```json 19 | { 20 | "betPrice": 55.2, 21 | "betSide": "tails" 22 | } 23 | ``` 24 | 25 | _Example output:_ 26 | 27 | ```json 28 | { 29 | "didWin": true 30 | } 31 | ``` 32 | 33 | ```json 34 | { 35 | "didWin": false 36 | } 37 | ``` 38 | 39 | ## 📝 Environment Variables 40 | 41 | List of environment variables used by this cloud function: 42 | 43 | - **APPWRITE_FUNCTION_ENDPOINT** - Endpoint of Appwrite project 44 | - **APPWRITE_FUNCTION_API_KEY** - Appwrite API Key 45 | 46 | ## 🚀 Deployment 47 | 48 | There are two ways of deploying the Appwrite function, both having the same results, but each using a different process. We highly recommend using CLI deployment to achieve the best experience. 49 | 50 | ### Using CLI 51 | 52 | Make sure you have [Appwrite CLI](https://appwrite.io/docs/command-line#installation) installed, and you have successfully logged into your Appwrite server. To make sure Appwrite CLI is ready, you can use the command `appwrite client --debug` and it should respond with green text `✓ Success`. 53 | 54 | Make sure you are in the same folder as your `appwrite.json` file and run `appwrite deploy function` to deploy your function. You will be prompted to select which functions you want to deploy. 55 | 56 | ### Manual using tar.gz 57 | 58 | Manual deployment has no requirements and uses Appwrite Console to deploy the tag. First, enter the folder of your function. Then, create a tarball of the whole folder and gzip it. After creating `.tar.gz` file, visit Appwrite Console, click on the `Deploy Tag` button and switch to the `Manual` tab. There, set the `entrypoint` to `src/index.js`, and upload the file we just generated. 59 | -------------------------------------------------------------------------------- /src/lib/appwrite.ts: -------------------------------------------------------------------------------- 1 | import { Appwrite, type RealtimeResponseEvent, type Models } from 'appwrite'; 2 | 3 | const appwrite = new Appwrite(); 4 | 5 | appwrite 6 | .setEndpoint(import.meta.env.VITE_APPWRITE_ENDPOINT) 7 | .setProject(import.meta.env.VITE_APPWRITE_PROJECT_ID); 8 | 9 | export type Profile = { 10 | balance: number; 11 | } & Models.Document; 12 | 13 | export class AppwriteService { 14 | // SSR related 15 | public static setSSR(cookieStr: string) { 16 | const authCookies: any = {}; 17 | authCookies[`a_session_${import.meta.env.VITE_APPWRITE_PROJECT_ID}`] = cookieStr; 18 | appwrite.headers['X-Fallback-Cookies'] = JSON.stringify(authCookies); 19 | } 20 | 21 | // Authentication-related 22 | public static async createAccount() { 23 | return await appwrite.account.createAnonymousSession(); 24 | } 25 | 26 | public static async getAccount() { 27 | return await appwrite.account.get(); 28 | } 29 | 30 | public static async signOut() { 31 | return await appwrite.account.deleteSession('current'); 32 | } 33 | 34 | // Profile-related 35 | public static async getProfile(userId: string): Promise { 36 | const response = await appwrite.functions.createExecution('createProfile', undefined, false); 37 | if (response.statusCode !== 200) { 38 | throw new Error(response.stderr); 39 | } 40 | 41 | return JSON.parse(response.response).profile; 42 | } 43 | 44 | 45 | public static async subscribeProfile(userId: string, callback: (payload: RealtimeResponseEvent) => void) { 46 | appwrite.subscribe(`collections.profiles.documents.${userId}`, callback); 47 | } 48 | 49 | // Game-related 50 | public static async bet(betPrice: number, betSide: 'tails' | 'heads'): Promise { 51 | const response = await appwrite.functions.createExecution('placeBet', JSON.stringify({ 52 | betPrice, 53 | betSide 54 | }), false); 55 | 56 | if (response.statusCode !== 200) { 57 | throw new Error(response.stderr); 58 | } 59 | 60 | return JSON.parse(response.response).didWin; 61 | } 62 | } -------------------------------------------------------------------------------- /src/routes/index.svelte: -------------------------------------------------------------------------------- 1 | 31 | 32 | 51 | 52 |
53 |
54 |

Near Casino

55 | 56 |

57 | Welcome to Near Casino! This is as fake casino as possible. No worries, it's all virtual and 58 | no real money is involved. 59 |

60 | 61 |

62 | Near Casino was created as a project to showcase how well Appwrite 66 | works with Svelte Kit and it's 67 | server-side rendering. 68 |

69 | 70 |

71 | Keep in mind, SSR uses cookies! Your backend (Appwrite) and frontend (Svelte app) must be on 72 | the same domain to work properly. That could be either domain of your app, or localhost. 73 |

74 | 75 |

Let's Create Account!

76 | 77 |

78 | Why would we make it complex? Let's make anonymous session. It's just like a casual account, 79 | but it is lost as soon as your browser throws it out. 80 |

81 | 82 |

83 | All it takes to create anonymous session is one *click* below. 84 |

85 | 86 | 95 |
96 |
97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🎰 Near Casino 2 | [![Current Version](https://img.shields.io/badge/version-0.1-green.svg)](https://github.com/OttoMayer313/near-casino) 3 | 4 | ![Cover](docs/screen-game.png) 5 | 6 | ![Cover](docs/screen-intro.png) 7 | 8 | ## 👋 Introduction 9 | 10 | Near Casino is a fake online casino that supports one game - coin flip. The website is mainly useful for developers serving as demo application using Appwrite and Sveite Kit. 11 | 12 | Project focuses on multiple aspects: 13 | 14 | - Appwrite Backend 15 | - Secure use of Appwrite 16 | - Svelte and Svelte Kit 17 | - SSR using Svelte (and Vercel) 18 | 19 | Proof of server-side rendering kicking in properly with Appwrite and Svelte Kit (hosted on Vercel): 20 | 21 | ![Cover](docs/screen-ssr.png) 22 | 23 | ## 🤖 Tech Stack 24 | 25 | Near Casino uses multiple frontend and backend technologies with focus of simplifying the development. Main focus of tech stack in this project is to make development fast and fun, instead of making it scalable and micro-optimized. 26 | 27 | - **[Appwrite](https://appwrite.io/)**, a secure backend as a service that provides 90% of necessary backend functionality out of the box 28 | - [TailwindCSS](https://tailwindcss.com/), a CSS library to rapidly design components using HTML classes 29 | - [Svelte](https://svelte.dev/), a JS library to build reactive frontend. Alongside this, application uses [TypeScript](https://www.typescriptlang.org/) 30 | - [Svelte Kit](https://kit.svelte.dev/), a Svelte framework to give proejct proper structure, routing and other cool features 31 | - [Vercel](https://vercel.com/), a static site hosting with amazing deployment flow using Git 32 | 33 | ## 💻 Development Setup 34 | 35 | **Frontend:** 36 | 37 | 1. Install dependencies: `npm install` 38 | 2. Spin-up HTTP server: `npm run dev` 39 | 3. Visit [localhost:3000](http://localhost:3000/) 40 | 41 | **Backend:** 42 | 43 | > 🚨 There is a bug in Vercel adapter! Please rename file from `_appwrite.json` to `appwrite.json` after cloning this repository. 🚨 44 | 45 | > You only need to spin-up backend if you man on backend changes. For frontend changes, you can skip this step as project is connected to production backend instance. 46 | 47 | 1. Install [Appwrite](https://appwrite.io/docs/installation) locally, or on development server 48 | 2. Sign up into your Appwrite instance and create project with both name and ID set to `nearCasino` 49 | 3. Install [Appwrite CLI](https://appwrite.io/docs/command-line) locally, and login: `appwrite login` 50 | 4. Deploy collections: `appwrite deploy collection` 51 | 5. Deploy functions: `appwrite deploy functions`, and configute environment variables in Appwite Web Console 52 | 53 | To prepare your changes from your Appwrite instance database to production one: 54 | 55 | 1. Pull database changes: `appwrite init collection` 56 | 57 | To create a new function: 58 | 59 | 1. Create function: `appwrite init function` 60 | 61 | Feel free to do manual changes to [appwrite.json](appwrite.json) if you are familiar with this file. 62 | 63 | ## 🚀 Deployment 64 | 65 | **Frontend:** 66 | 67 | 1. Install dependencies: `npm install` 68 | 2. Build project: `npm run build` 69 | 3. Deploy folder `build` on a static hosting 70 | 71 | > Frontend build does not use any special environment variables. 72 | 73 | **Backend:** 74 | 75 | 1. Deploy database changes, if necessary: `appwrite deploy collection` 76 | 2. Deploy function changes, if necessary: `appwrite deploy function` 77 | 78 | --- 79 | 80 | Assets used in the project made by [Alex Martynov](https://www.figma.com/community/file/1096465749704772913). 81 | 82 | --- 83 | 84 | ## 📚 Svelte Kit Resources (Generated) 85 | 86 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte). 87 | 88 | ## Creating a project 89 | 90 | If you're seeing this, you've probably already done this step. Congrats!!! 91 | 92 | ```bash 93 | # create a new project in the current directory 94 | npm init svelte 95 | 96 | # create a new project in my-app 97 | npm init svelte my-app 98 | ``` 99 | 100 | ## Developing 101 | 102 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 103 | 104 | ```bash 105 | npm run dev 106 | 107 | # or start the server and open the app in a new browser tab 108 | npm run dev -- --open 109 | ``` 110 | 111 | ## Building 112 | 113 | To create a production version of your app: 114 | 115 | ```bash 116 | npm run build 117 | ``` 118 | 119 | You can preview the production build with `npm run preview`. 120 | 121 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. 122 | -------------------------------------------------------------------------------- /src/routes/casino.svelte: -------------------------------------------------------------------------------- 1 | 42 | 43 | 118 | 119 |
120 |
121 |

Near Casino

122 | 123 |

124 | There we go, account created! Don't believe? This is your ID: {account?.$id} 127 |

128 | 129 |

130 | If the account ID is not server-side rendered, it means we dont have same-domain 131 | authentication cookie. Please make sure to run frontend app on same domain as Appwrite 132 | backend. 133 |

134 | 135 | 144 | 145 |

Balance

146 | 147 |

Your current blalance is:

148 |

149 | {profile?.balance} Near Dollars 150 |

151 | 152 |

Coin Flip

153 | 154 |

155 | Head or tails? Place your bet and see if luck is on your side. 156 |

157 | 158 |
159 | 165 | 171 | 177 |
178 | 179 |
180 | 189 | 190 | 199 |
200 |
201 |
202 | --------------------------------------------------------------------------------