├── .nvmrc ├── packages ├── types │ ├── README.md │ ├── src │ │ ├── index.ts │ │ └── database.ts │ ├── .eslintrc.js │ ├── prettier.config.js │ ├── tsconfig.json │ ├── tsup.config.js │ └── package.json ├── prettier-config │ ├── prettier.config.base.js │ ├── prettier.config.tailwind.js │ └── package.json ├── eslint-config-custom │ ├── index.js │ └── package.json ├── eslint-config-custom-node │ ├── index.js │ └── package.json ├── eslint-config-custom-web │ ├── index.js │ └── package.json ├── eslint-config-custom-native │ ├── index.js │ └── package.json ├── tsconfig │ ├── package.json │ ├── README.md │ ├── react-library.json │ ├── preact.json │ ├── web.json │ ├── node.json │ ├── nextjs.json │ └── base.json └── jest-presets │ ├── package.json │ └── jest │ └── node │ └── jest-preset.js ├── supabase ├── README.md ├── .gitignore ├── package.json ├── migrations │ └── 20221113144425_initial.sql ├── config.toml ├── tests │ └── guestbook_entry │ │ └── rls.sql └── seed.sql ├── .npmrc ├── .husky ├── post-merge ├── post-checkout ├── post-rewrite ├── commit-msg └── pre-commit ├── pnpm-workspace.yaml ├── .sqllsrc.json ├── renovate.json ├── commitlint.config.js ├── .gitignore ├── .env.local ├── README.md ├── .github ├── workflows │ ├── abandoned-branches.yaml │ ├── deploy.yml │ └── ci.yml └── actions │ └── setup-monorepo │ └── action.yml ├── LICENSE ├── package.json └── turbo.json /.nvmrc: -------------------------------------------------------------------------------- 1 | 18 2 | -------------------------------------------------------------------------------- /packages/types/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /supabase/README.md: -------------------------------------------------------------------------------- 1 | # Supabase 2 | -------------------------------------------------------------------------------- /supabase/.gitignore: -------------------------------------------------------------------------------- 1 | # Supabase 2 | .branches 3 | .temp 4 | -------------------------------------------------------------------------------- /packages/types/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './database'; 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers=true 2 | strict-peer-dependencies=false -------------------------------------------------------------------------------- /.husky/post-merge: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm install 5 | -------------------------------------------------------------------------------- /.husky/post-checkout: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm install 5 | -------------------------------------------------------------------------------- /.husky/post-rewrite: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm install 5 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/*" 3 | - "supabase" 4 | - "packages/*" 5 | -------------------------------------------------------------------------------- /packages/prettier-config/prettier.config.base.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | singleQuote: true, 3 | }; 4 | -------------------------------------------------------------------------------- /packages/eslint-config-custom/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['turbo', 'universe'], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/eslint-config-custom-node/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['turbo', 'universe/node'], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/eslint-config-custom-web/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['turbo', 'universe/web'], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/types/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['@supasample/custom'], 4 | }; 5 | -------------------------------------------------------------------------------- /packages/eslint-config-custom-native/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['turbo', 'universe/native'], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/types/prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@supasample/prettier-config/prettier.config.base.js'); 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm commitlint --edit --config=commitlint.config.js 5 | -------------------------------------------------------------------------------- /packages/tsconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@supasample/tsconfig", 3 | "version": "0.0.0", 4 | "private": true 5 | } 6 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm -v 5 | pnpm install 6 | pnpm run turbo format:check lint typecheck 7 | -------------------------------------------------------------------------------- /packages/tsconfig/README.md: -------------------------------------------------------------------------------- 1 | # `tsconfig` 2 | 3 | These are base shared `tsconfig.json`s from which all other `tsconfig.json`'s inherit from. 4 | -------------------------------------------------------------------------------- /packages/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@supasample/tsconfig/base.json", 3 | "include": ["**/*.ts"], 4 | "exclude": ["node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /.sqllsrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "supabase", 3 | "adapter": "postgres", 4 | "host": "localhost", 5 | "port": 54322, 6 | "user": "postgres", 7 | "password": "postgres", 8 | "database": "postgres" 9 | } 10 | -------------------------------------------------------------------------------- /packages/prettier-config/prettier.config.tailwind.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require("./prettier.config.base.js"); 2 | 3 | module.exports = { 4 | ...baseConfig, 5 | plugins: [require("prettier-plugin-tailwindcss")], 6 | }; 7 | -------------------------------------------------------------------------------- /packages/tsconfig/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./web.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/tsconfig/preact.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Preact", 4 | "extends": "./web.json", 5 | "compilerOptions": { 6 | "jsx": "react", 7 | "jsxFactory": "h", 8 | "jsxFragmentFactory": "Fragment" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/tsconfig/web.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Web", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "lib": ["esnext", "dom", "dom.iterable"], 7 | "module": "ESNext", 8 | "target": "es6" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/types/tsup.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | const isProduction = process.env.NODE_ENV === 'production'; 4 | 5 | export default defineConfig({ 6 | clean: true, 7 | dts: true, 8 | entry: ['src/index.ts'], 9 | format: ['cjs', 'esm'], 10 | minify: isProduction, 11 | sourcemap: true, 12 | }); 13 | -------------------------------------------------------------------------------- /packages/jest-presets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@supasample/jest-presets", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "scripts": { 7 | "clean": "rm -rf .turbo && rm -rf lint-results && rm -rf .nyc_output && rm -rf node_modules" 8 | }, 9 | "dependencies": { 10 | "ts-jest": "29.2.4" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/prettier-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@supasample/prettier-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "clean": "rm -rf .turbo && rm -rf lint-results && rm -rf .nyc_output && rm -rf node_modules" 7 | }, 8 | "devDependencies": { 9 | "prettier": "2.8.0", 10 | "prettier-plugin-tailwindcss": "0.6.6" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/eslint-config-custom/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@supasample/eslint-config-custom", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "clean": "rm -rf .turbo && rm -rf lint-results && rm -rf .nyc_output && rm -rf node_modules" 7 | }, 8 | "dependencies": { 9 | "eslint-config-turbo": "0.0.4", 10 | "eslint-config-universe": "11.3.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/eslint-config-custom-web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@supasample/eslint-config-custom-web", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "clean": "rm -rf .turbo && rm -rf lint-results && rm -rf .nyc_output && rm -rf node_modules" 7 | }, 8 | "dependencies": { 9 | "eslint-config-turbo": "0.0.4", 10 | "eslint-config-universe": "11.3.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/eslint-config-custom-node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@supasample/eslint-config-custom-node", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "clean": "rm -rf .turbo && rm -rf lint-results && rm -rf .nyc_output && rm -rf node_modules" 7 | }, 8 | "dependencies": { 9 | "eslint-config-turbo": "0.0.4", 10 | "eslint-config-universe": "11.3.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/eslint-config-custom-native/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@supasample/eslint-config-custom-native", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "clean": "rm -rf .turbo && rm -rf lint-results && rm -rf .nyc_output && rm -rf node_modules" 7 | }, 8 | "dependencies": { 9 | "eslint-config-turbo": "0.0.4", 10 | "eslint-config-universe": "11.3.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/tsconfig/node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Node", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "lib": ["ESNext"], 7 | "module": "ESNext", 8 | "target": "ESNext", 9 | "strict": true, 10 | "esModuleInterop": false, 11 | "forceConsistentCasingInFileNames": true, 12 | "allowSyntheticDefaultImports": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:base"], 4 | "packageRules": [ 5 | { 6 | "matchDatasources": ["npm"], 7 | "stabilityDays": 3 8 | }, 9 | { 10 | "matchUpdateTypes": ["minor", "patch", "pin", "digest"], 11 | "automerge": true 12 | }, 13 | { 14 | "updateTypes": ["patch"], 15 | "enabled": false 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /supabase/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@supasample/supabase", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "supabase status || supabase start", 7 | "reset": "supabase db reset || supabase start", 8 | "test": "supabase db test", 9 | "lint": "supabase db lint", 10 | "lint:report": "supabase db lint", 11 | "deploy": "supabase link --project-ref $SUPABASE_PROJECT_REF && supabase db push" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | async function loadScopesFormWorkspace() { 2 | const { packages } = await require("@egoist/get-packages").getPackages( 3 | __dirname 4 | ); 5 | return [ 6 | "supabase", 7 | ...packages.map((p) => p.data.name.replace("@supasample/", "")), 8 | ]; 9 | } 10 | 11 | module.exports = { 12 | extends: ["@commitlint/config-conventional"], 13 | rules: { 14 | "scope-enum": async () => [ 15 | 2, 16 | "always", 17 | [...(await loadScopesFormWorkspace())], 18 | ], 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /packages/jest-presets/jest/node/jest-preset.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | roots: [''], 3 | transform: { 4 | '^.+\\.tsx?$': 'ts-jest', 5 | }, 6 | testMatch: ['**/?(*.)+(spec).ts*'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], 8 | modulePathIgnorePatterns: [ 9 | '/__tests__/__fixtures__', 10 | '/node_modules', 11 | '/dist', 12 | ], 13 | preset: 'ts-jest', 14 | testEnvironment: 'jsdom', 15 | verbose: true, 16 | testURL: 'http://localhost/', 17 | }; 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | .nyc_output 11 | 12 | # next.js 13 | .next/ 14 | out/ 15 | build 16 | 17 | # misc 18 | .DS_Store 19 | *.pem 20 | 21 | # debug 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | .pnpm-debug.log* 26 | 27 | # turbo 28 | .turbo 29 | 30 | # dist 31 | **/dist/ 32 | 33 | # storybook 34 | **/storybook-static/ 35 | 36 | # Lint results 37 | lint-results 38 | 39 | eslint_report.json 40 | .env 41 | 42 | 43 | .idea 44 | .idea/* 45 | -------------------------------------------------------------------------------- /packages/tsconfig/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Next.js", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "target": "es5", 7 | "lib": ["dom", "dom.iterable", "esnext"], 8 | "allowJs": true, 9 | "skipLibCheck": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noEmit": true, 13 | "incremental": true, 14 | "esModuleInterop": true, 15 | "module": "esnext", 16 | "resolveJsonModule": true, 17 | "isolatedModules": true, 18 | "jsx": "preserve" 19 | }, 20 | "include": ["src", "next-env.d.ts"], 21 | "exclude": ["node_modules"] 22 | } 23 | -------------------------------------------------------------------------------- /packages/tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Base", 4 | "compilerOptions": { 5 | "composite": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "inlineSources": false, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noUnusedLocals": false, 14 | "noUnusedParameters": false, 15 | "preserveWatchOutput": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "lib": ["esnext"], 19 | "module": "ESNext", 20 | "target": "es6" 21 | }, 22 | "exclude": ["node_modules"] 23 | } 24 | -------------------------------------------------------------------------------- /.env.local: -------------------------------------------------------------------------------- 1 | # - DATABASE ************************************************************************************************ 2 | SUPABASE_URL=http://localhost:54321 3 | SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0 4 | SUPABASE_SERVICE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU 5 | SUPABASE_JWT_SECRET=super-secret-jwt-token-with-at-least-32-characters-long 6 | DB_CONNECTION_STRING=postgresql://postgres:postgres@localhost:54322/postgres 7 | DB_UI_SUPABASE=postgresql://postgres:postgres@localhost:54322/postgres 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # supasample 2 | A sample monorepo with supabase and turborepo 3 | 4 | Unfortunately, the business model at my current company does not allow us to open source our code. To still be able to share my learninsg, I will update this repository with sample configurations and code. Further, it will contain examples for all my current and upcoming open source projects. 5 | 6 | ## Features and Roadmap 7 | - [x] Turborepo and Supabase [see blog post](https://philipp.steinroetter.com/posts/supabase-turborepo) 8 | - [ ] Shared components library with TailwindCSS and Storybook 9 | - [ ] NextJS app using supabase-cache-helpers 10 | - [ ] ... samples for upcoming os projects. [Follow](https://twitter.com/psteinroe) to receive updates! 11 | 12 | -------------------------------------------------------------------------------- /.github/workflows/abandoned-branches.yaml: -------------------------------------------------------------------------------- 1 | name: Delete abandoned branches 2 | 3 | on: 4 | # Run daily at midnight 5 | schedule: 6 | - cron: '0 0 * * *' 7 | 8 | # Allow workflow to be manually run from the GitHub UI 9 | workflow_dispatch: 10 | 11 | jobs: 12 | cleanup_old_branches: 13 | runs-on: ubuntu-latest 14 | name: Satisfy my repo CDO 15 | steps: 16 | - name: Delete those pesky dead branches 17 | uses: phpdocker-io/github-actions-delete-abandoned-branches@v1 18 | id: delete_stuff 19 | with: 20 | github_token: ${{ github.token }} 21 | last_commit_age_days: 60 22 | ignore_branches: dev,production,feat/mobile-app 23 | 24 | # Disable dry run and actually get stuff deleted 25 | dry_run: no 26 | 27 | - name: Get output 28 | run: "echo 'Deleted branches: ${{ steps.delete_stuff.outputs.deleted_branches }}'" 29 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | deploy: 15 | name: Deploy 16 | timeout-minutes: 15 17 | runs-on: ubuntu-latest 18 | env: 19 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} 20 | TURBO_TEAM: ${{ secrets.TURBO_TEAM }} 21 | SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} 22 | SUPABASE_PROJECT_REF: ${{ secrets.SUPABASE_PROJECT_REF }} 23 | SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_DB_PASSWORD }} 24 | 25 | steps: 26 | - name: 🏗 Setup repository 27 | uses: actions/checkout@v3 28 | 29 | - name: 🏗 Setup monorepo 30 | uses: ./.github/actions/setup-monorepo 31 | 32 | - name: 🚀 Deploy 33 | run: pnpm run deploy -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Philipp Steinrötter 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 | -------------------------------------------------------------------------------- /packages/types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@supasample/types", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./dist/index.js", 6 | "source": "./src/index.ts", 7 | "types": "./dist/index.d.ts", 8 | "files": [ 9 | "dist/**" 10 | ], 11 | "scripts": { 12 | "generate": "(cd ../../ && supabase gen types typescript --local > ./packages/types/src/database.ts) && prettier --write \"src/**/*.{ts,tsx,md}\"", 13 | "build": "tsup", 14 | "clean": "rm -rf .turbo && rm -rf lint-results && rm -rf .nyc_output && rm -rf node_modules && rm -rf dist", 15 | "dev": "tsup --watch", 16 | "lint": "eslint src/**", 17 | "lint:report": "eslint src/** --format json --output-file ./lint-results/types.json", 18 | "lint:fix": "eslint src/** --fix", 19 | "typecheck": "tsc --pretty --noEmit", 20 | "format:write": "prettier --write \"src/**/*.{ts,tsx,md}\"", 21 | "format:check": "prettier --check \"src/**/*.{ts,tsx,md}\"" 22 | }, 23 | "devDependencies": { 24 | "@supasample/supabase": "workspace:*", 25 | "@supasample/tsconfig": "workspace:*", 26 | "typescript": "4.9.3", 27 | "@supasample/prettier-config": "workspace:*", 28 | "@supasample/eslint-config-custom": "workspace:*", 29 | "tsup": "6.7.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.github/actions/setup-monorepo/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup Monorepo 2 | description: Prepare and install everything for the monorepo 3 | 4 | inputs: 5 | node-version: 6 | description: Version of Node to use 7 | default: 18.x 8 | 9 | pnpm-version: 10 | description: Version of pnpm to use 11 | default: 7.x 12 | 13 | supabase-version: 14 | description: Version of Supabase CLI to use 15 | default: latest 16 | 17 | runs: 18 | using: composite 19 | steps: 20 | - name: 🏗 Setup Node 21 | uses: actions/setup-node@v3 22 | with: 23 | node-version: ${{ inputs.node-version }} 24 | 25 | - name: 🏗 Setup pnpm 26 | uses: pnpm/action-setup@v2 27 | with: 28 | version: ${{ inputs.pnpm-version }} 29 | 30 | - name: 🔎 Get pnpm store directory 31 | id: pnpm-cache 32 | shell: bash 33 | run: | 34 | echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT 35 | 36 | - uses: actions/cache@v3 37 | name: ♻️ Setup pnpm cache 38 | with: 39 | path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} 40 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 41 | restore-keys: | 42 | ${{ runner.os }}-pnpm-store- 43 | 44 | - name: 🏗 Setup Supabase 45 | uses: supabase/setup-cli@v1 46 | with: 47 | version: ${{ inputs.supabase-version }} 48 | 49 | - name: 📦 Install dependencies 50 | run: pnpm install 51 | shell: bash 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "supasample", 3 | "version": "0.0.0", 4 | "private": true, 5 | "workspaces": [ 6 | "apps/*", 7 | "packages/*" 8 | ], 9 | "scripts": { 10 | "turbo": "turbo", 11 | "build": "turbo run build", 12 | "build:packages": "turbo run build --filter=./packages/*", 13 | "dev": "turbo run dev --parallel", 14 | "lint": "turbo run lint", 15 | "lint:report": "turbo run lint:report", 16 | "lint:fix": "turbo run lint:fix", 17 | "typecheck": "turbo run typecheck", 18 | "preview": "turbo run preview", 19 | "cleanup-preview": "turbo run cleanup-preview", 20 | "deploy": "turbo run deploy", 21 | "clean": "turbo run clean && rm -rf node_modules", 22 | "test": "turbo run test", 23 | "format:write": "turbo run format:write", 24 | "format:check": "turbo run format:check", 25 | "generate": "turbo run generate", 26 | "clear-branches": "git branch --merged | egrep -v \"(^\\*|production|dev|main)\" | xargs git branch -d", 27 | "reset-git": "git checkout main && git pull && pnpm run clear-branches", 28 | "merge-main": "git fetch origin main:main && git merge main", 29 | "prepare": "husky install" 30 | }, 31 | "devDependencies": { 32 | "@egoist/get-packages": "1.0.1", 33 | "prettier": "2.8.0", 34 | "@commitlint/cli": "17.8.0", 35 | "@commitlint/config-conventional": "17.8.0", 36 | "turbo": "1.13.2", 37 | "husky": "8.0.1", 38 | "eslint": "8.57.0" 39 | }, 40 | "engines": { 41 | "pnpm": "7", 42 | "node": "18" 43 | }, 44 | "dependencies": {}, 45 | "packageManager": "pnpm@7.33.0" 46 | } 47 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} 9 | cancel-in-progress: true 10 | 11 | jobs: 12 | ci: 13 | name: CI 14 | timeout-minutes: 15 15 | runs-on: ubuntu-latest 16 | env: 17 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} 18 | TURBO_TEAM: ${{ secrets.TURBO_TEAM }} 19 | 20 | steps: 21 | - name: 🏗 Setup repository 22 | uses: actions/checkout@v3 23 | 24 | - name: 🏗 Setup monorepo 25 | uses: ./.github/actions/setup-monorepo 26 | with: 27 | expo-token: ${{ secrets.EXPO_TOKEN }} 28 | 29 | - name: 🦺 Check Format, Lint, Typecheck and Test 30 | id: ci 31 | run: pnpm run turbo format:check lint:report typecheck test 32 | continue-on-error: true 33 | 34 | - name: 💍 Merge lint reports 35 | run: | 36 | shopt -s globstar 37 | jq -s '[.[]]|flatten' ./**/lint-results/*.json &> eslint_report.json 38 | 39 | - name: 👸 Annotate Code Linting Results 40 | uses: ataylorme/eslint-annotate-action@v2 41 | with: 42 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 43 | report-json: "eslint_report.json" 44 | 45 | - name: ☁️ Upload ESLint report 46 | uses: actions/upload-artifact@v3 47 | with: 48 | name: eslint_report.json 49 | path: eslint_report.json 50 | 51 | - name: ⚠️ Check for error 52 | if: steps.ci.outcome != 'success' 53 | run: exit 1 54 | 55 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turborepo.org/schema.json", 3 | "pipeline": { 4 | "@supasample/supabase#start": { 5 | "outputs": [], 6 | "cache": false 7 | }, 8 | "build": { 9 | "dependsOn": ["^build"], 10 | "outputs": ["dist/**", ".next/**"] 11 | }, 12 | "generate": { 13 | "dependsOn": ["^generate"], 14 | "outputs": [] 15 | }, 16 | "@supasample/types#generate": { 17 | "dependsOn": ["@supasample/supabase#start", "^generate"], 18 | "outputs": [] 19 | }, 20 | "test": { 21 | "dependsOn": ["^build"], 22 | "outputs": ["coverage/**"] 23 | }, 24 | "@supasample/supabase#test": { 25 | "dependsOn": ["@supasample/supabase#start", "^build"], 26 | "outputs": [] 27 | }, 28 | "clean": { 29 | "outputs": [], 30 | "cache": false 31 | }, 32 | "start": { 33 | "outputs": [] 34 | }, 35 | "lint": { 36 | "dependsOn": ["format:check"], 37 | "outputs": [] 38 | }, 39 | "@supasample/supabase#lint": { 40 | "dependsOn": ["@supasample/supabase#start", "format:check"], 41 | "outputs": [] 42 | }, 43 | "lint:report": { 44 | "dependsOn": ["format:check"], 45 | "outputs": ["lint-results/**"] 46 | }, 47 | "@supasample/supabase#lint:report": { 48 | "dependsOn": ["@supasample/supabase#start", "format:check"], 49 | "outputs": [] 50 | }, 51 | "lint:fix": { 52 | "dependsOn": ["format:write"], 53 | "outputs": [] 54 | }, 55 | "format:write": { 56 | "outputs": [] 57 | }, 58 | "format:check": { 59 | "outputs": [] 60 | }, 61 | "typecheck": { 62 | "dependsOn": ["^build"], 63 | "outputs": [] 64 | }, 65 | "preview": { 66 | "outputs": [] 67 | }, 68 | "cleanup-preview": { 69 | "outputs": [] 70 | }, 71 | "deploy": { 72 | "outputs": [] 73 | }, 74 | "dev": { 75 | "cache": false 76 | } 77 | }, 78 | "globalEnv": [ 79 | "NODE_ENV", 80 | "SUPABASE_URL", 81 | "SUPABASE_ANON_KEY" 82 | ] 83 | } 84 | -------------------------------------------------------------------------------- /supabase/migrations/20221113144425_initial.sql: -------------------------------------------------------------------------------- 1 | create or replace function uuid_from_filename(filename text) returns uuid as 2 | $$ 3 | select rtrim(storage.filename(filename), concat('.', storage.extension(filename)))::uuid; 4 | $$ language sql immutable security definer leakproof; 5 | 6 | 7 | create table if not exists guestbook_entry 8 | ( 9 | id uuid primary key not null default gen_random_uuid(), 10 | created_at timestamp with time zone not null default now(), 11 | updated_at timestamp with time zone not null default now(), 12 | user_id uuid not null references auth.users default auth.uid(), 13 | updated boolean, 14 | text text 15 | ); 16 | 17 | create or replace function set_updated_at() 18 | returns trigger as $$ 19 | begin 20 | new.updated_at = now(); 21 | new.updated = true; 22 | return new; 23 | end; 24 | $$ language 'plpgsql'; 25 | 26 | create trigger set_updated_at 27 | before update 28 | on guestbook_entry 29 | for each row 30 | execute procedure set_updated_at(); 31 | 32 | alter table guestbook_entry enable row level security; 33 | create policy "Everyone can read guestbook entries" on guestbook_entry for select to anon, authenticated using ( true ); 34 | create policy "Users can insert their guestbook entries" on guestbook_entry for insert to authenticated with check ( auth.uid() = user_id ); 35 | create policy "Users can update their guestbook entries" on guestbook_entry for update to authenticated using ( auth.uid() = user_id ); 36 | create policy "Users can delete their guestbook entries" on guestbook_entry for delete to authenticated using ( auth.uid() = user_id ); 37 | 38 | insert into storage.buckets (id, name, public) 39 | values ('profile_images', 'profile_images', true); 40 | 41 | create policy "Everyone can read profile images" on storage.objects for select to anon, authenticated using ( 42 | bucket_id = 'profile_images' 43 | ); 44 | 45 | create policy "Users can delete their profile image" 46 | on storage.objects for delete to authenticated 47 | using ( 48 | bucket_id = 'profile_images' and 49 | auth.uid() = owner and 50 | auth.uid() = uuid_from_filename(name) 51 | ); 52 | 53 | create policy "Users can update their profile image" 54 | on storage.objects for update to authenticated 55 | using ( 56 | bucket_id = 'profile_images' and 57 | auth.uid() = owner and 58 | auth.uid() = uuid_from_filename(name) 59 | ); 60 | 61 | create policy "Users can upload their profile image" 62 | on storage.objects for insert to authenticated 63 | with check ( 64 | bucket_id = 'profile_images' and 65 | auth.uid() = owner and 66 | auth.uid() = uuid_from_filename(name) 67 | ); 68 | -------------------------------------------------------------------------------- /supabase/config.toml: -------------------------------------------------------------------------------- 1 | # A string used to distinguish different Supabase projects on the same host. Defaults to the working 2 | # directory name when running `supabase init`. 3 | project_id = "supasample" 4 | 5 | [api] 6 | # Port to use for the API URL. 7 | port = 54321 8 | # Schemas to expose in your API. Tables, views and stored procedures in this schema will get API 9 | # endpoints. public and storage are always included. 10 | schemas = [] 11 | # Extra schemas to add to the search_path of every request. 12 | extra_search_path = ["extensions"] 13 | # The maximum number of rows returns from a view, table, or stored procedure. Limits payload size 14 | # for accidental or malicious requests. 15 | max_rows = 1000 16 | 17 | [db] 18 | # Port to use for the local database URL. 19 | port = 54322 20 | # The database major version to use. This has to be the same as your remote database's. Run `SHOW 21 | # server_version;` on the remote database to check. 22 | major_version = 14 23 | 24 | [studio] 25 | # Port to use for Supabase Studio. 26 | port = 54323 27 | 28 | # Email testing server. Emails sent with the local dev setup are not actually sent - rather, they 29 | # are monitored, and you can view the emails that would have been sent from the web interface. 30 | [inbucket] 31 | # Port to use for the email testing server web interface. 32 | port = 54324 33 | smtp_port = 54325 34 | pop3_port = 54326 35 | 36 | [storage] 37 | # The maximum file size allowed (e.g. "5MB", "500KB"). 38 | file_size_limit = "50MiB" 39 | 40 | [auth] 41 | # The base URL of your website. Used as an allow-list for redirects and for constructing URLs used 42 | # in emails. 43 | site_url = "http://localhost:3000" 44 | # A list of *exact* URLs that auth providers are permitted to redirect to post authentication. 45 | additional_redirect_urls = ["https://localhost:3000"] 46 | # How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 seconds (one 47 | # week). 48 | jwt_expiry = 3600 49 | # Allow/disallow new user signups to your project. 50 | enable_signup = true 51 | 52 | [auth.email] 53 | # Allow/disallow new user signups via email to your project. 54 | enable_signup = true 55 | # If enabled, a user will be required to confirm any email change on both the old, and new email 56 | # addresses. If disabled, only the new email is required to confirm. 57 | double_confirm_changes = true 58 | # If enabled, users need to confirm their email address before signing in. 59 | enable_confirmations = false 60 | 61 | # Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, 62 | # `discord`, `facebook`, `github`, `gitlab`, `google`, `twitch`, `twitter`, `slack`, `spotify`. 63 | [auth.external.apple] 64 | enabled = false 65 | client_id = "" 66 | secret = "" 67 | # Overrides the default auth redirectUrl. 68 | redirect_uri = "" 69 | # Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, 70 | # or any other third-party OIDC providers. 71 | url = "" 72 | -------------------------------------------------------------------------------- /supabase/tests/guestbook_entry/rls.sql: -------------------------------------------------------------------------------- 1 | begin; 2 | select plan(12); 3 | select tests.rls_enabled('guestbook_entry'); 4 | 5 | select tests.create_supabase_user('user_1'); 6 | select tests.create_supabase_user('user_2'); 7 | 8 | -- insert 9 | prepare insert_entry as insert into guestbook_entry (text) values ('Test'); 10 | select throws_ok ('insert_entry'); 11 | select tests.authenticate_as('user_1'); 12 | select lives_ok ('insert_entry', 'should be able to insert if authenticated'); 13 | select tests.authenticate_as('user_2'); 14 | select lives_ok ('insert_entry', 'should be able to insert if authenticated'); 15 | 16 | -- update 17 | select tests.clear_authentication(); 18 | prepare update_entry_1 as update guestbook_entry set text = 'updated' where user_id = tests.get_supabase_uid('user_1'); 19 | prepare update_entry_2 as update guestbook_entry set text = 'updated' where user_id = tests.get_supabase_uid('user_2'); 20 | execute update_entry_1; 21 | select is ( 22 | (select text from guestbook_entry where user_id = tests.get_supabase_uid('user_1')), 23 | 'Test', 24 | 'should not be able to update guestbook entry if not authenticated' 25 | ); 26 | select tests.authenticate_as('user_1'); 27 | execute update_entry_2; 28 | select is ( 29 | (select text from guestbook_entry where user_id = tests.get_supabase_uid('user_2')), 30 | 'Test', 31 | 'should not be able to update guestbook entry of another user' 32 | ); 33 | execute update_entry_1; 34 | select is ( 35 | (select text from guestbook_entry where user_id = tests.get_supabase_uid('user_1')), 36 | 'updated', 37 | 'should be able to update own guestbook entry' 38 | ); 39 | 40 | -- select 41 | select tests.clear_authentication(); 42 | select is ( 43 | (select count(id)::integer from guestbook_entry ), 44 | 2, 45 | 'should be able to read all guestbook entries as anon user' 46 | ); 47 | select tests.authenticate_as('user_1'); 48 | select is ( 49 | (select count(id)::integer from guestbook_entry ), 50 | 2, 51 | 'should be able to read all guestbook entries as authenticated user' 52 | ); 53 | 54 | -- delete 55 | select tests.clear_authentication(); 56 | prepare delete_entry_1 as delete from guestbook_entry where user_id = tests.get_supabase_uid('user_1'); 57 | prepare delete_entry_2 as delete from guestbook_entry where user_id = tests.get_supabase_uid('user_2'); 58 | execute delete_entry_1; 59 | select is ( 60 | (select count(id)::integer from guestbook_entry ), 61 | 2, 62 | 'should not be able to delete guestbook entry if not authenticated' 63 | ); 64 | select tests.authenticate_as('user_1'); 65 | execute delete_entry_2; 66 | select is ( 67 | (select count(id)::integer from guestbook_entry ), 68 | 2, 69 | 'should not be able to delete guestbook entry of another user' 70 | ); 71 | execute delete_entry_1; 72 | select is ( 73 | (select count(id)::integer from guestbook_entry where user_id = tests.get_supabase_uid('user_1')), 74 | 0, 75 | 'should be able to delete own guestbook entry' 76 | ); 77 | execute update_entry_1; 78 | 79 | select * from finish(); 80 | rollback; -------------------------------------------------------------------------------- /supabase/seed.sql: -------------------------------------------------------------------------------- 1 | -- Enable pgTAP if it's not already enabled 2 | create extension if not exists pgtap with schema extensions; 3 | 4 | -- We want to store all of this in the tests schema to keep it 5 | -- separate from any application data 6 | CREATE SCHEMA IF NOT EXISTS tests; 7 | 8 | -- anon and authenticated should have access to tests schema 9 | GRANT USAGE ON SCHEMA tests TO anon, authenticated; 10 | -- Don't allow public to execute any functions in the tests schema 11 | ALTER DEFAULT PRIVILEGES IN SCHEMA tests REVOKE EXECUTE ON FUNCTIONS FROM public; 12 | -- Grant execute to anon and authenticated for testing purposes 13 | ALTER DEFAULT PRIVILEGES IN SCHEMA tests GRANT EXECUTE ON FUNCTIONS TO anon, authenticated; 14 | 15 | /** 16 | * ### tests.create_supabase_user(identifier text, email text, phone text) 17 | * 18 | * Creates a new user in the `auth.users` table. 19 | * You can recall a user's info by using `tests.get_supabase_user(identifier text)`. 20 | * 21 | * Parameters: 22 | * - `identifier` - A unique identifier for the user. We recommend you keep it memorable like "test_owner" or "test_member" 23 | * - `email` - (Optional) The email address of the user 24 | * - `phone` - (Optional) The phone number of the user 25 | * 26 | * Returns: 27 | * - `user_id` - The UUID of the user in the `auth.users` table 28 | * 29 | * Example: 30 | * ```sql 31 | * SELECT tests.create_supabase_user('test_owner'); 32 | * SELECT tests.create_supabase_user('test_member', 'member@test.com', '555-555-5555'); 33 | * ``` 34 | */ 35 | CREATE OR REPLACE FUNCTION tests.create_supabase_user(identifier text, email text default null, phone text default null) 36 | RETURNS uuid 37 | SECURITY DEFINER 38 | SET search_path = auth, pg_temp 39 | AS $$ 40 | DECLARE 41 | user_id uuid; 42 | BEGIN 43 | 44 | -- create the user 45 | user_id := extensions.uuid_generate_v4(); 46 | INSERT INTO auth.users (id, email, phone, raw_user_meta_data) 47 | VALUES (user_id, coalesce(email, concat(user_id, '@test.com')), phone, json_build_object('test_identifier', identifier)) 48 | RETURNING id INTO user_id; 49 | 50 | RETURN user_id; 51 | END; 52 | $$ LANGUAGE plpgsql; 53 | 54 | /** 55 | * ### tests.get_supabase_user(identifier text) 56 | * 57 | * Returns the user info for a user created with `tests.create_supabase_user`. 58 | * 59 | * Parameters: 60 | * - `identifier` - The unique identifier for the user 61 | * 62 | * Returns: 63 | * - `user_id` - The UUID of the user in the `auth.users` table 64 | * 65 | * Example: 66 | * ```sql 67 | * SELECT posts where posts.user_id = tests.get_supabase_user('test_owner') -> 'id'; 68 | * ``` 69 | */ 70 | CREATE OR REPLACE FUNCTION tests.get_supabase_user(identifier text) 71 | RETURNS json 72 | SECURITY DEFINER 73 | SET search_path = auth, pg_temp 74 | AS $$ 75 | DECLARE 76 | supabase_user json; 77 | BEGIN 78 | SELECT json_build_object('id', id, 'email', email, 'phone', phone) into supabase_user FROM auth.users WHERE raw_user_meta_data ->> 'test_identifier' = identifier limit 1; 79 | if supabase_user is null OR supabase_user -> 'id' IS NULL then 80 | RAISE EXCEPTION 'User with identifier % not found', identifier; 81 | end if; 82 | RETURN supabase_user; 83 | END; 84 | $$ LANGUAGE plpgsql; 85 | 86 | /** 87 | * ### tests.get_supabase_uid(identifier text) 88 | * 89 | * Returns the user UUID for a user created with `tests.create_supabase_user`. 90 | * 91 | * Parameters: 92 | * - `identifier` - The unique identifier for the user 93 | * 94 | * Returns: 95 | * - `user_id` - The UUID of the user in the `auth.users` table 96 | * 97 | * Example: 98 | * ```sql 99 | * SELECT posts where posts.user_id = tests.get_supabase_uid('test_owner') -> 'id'; 100 | * ``` 101 | */ 102 | CREATE OR REPLACE FUNCTION tests.get_supabase_uid(identifier text) 103 | RETURNS uuid 104 | SECURITY DEFINER 105 | SET search_path = auth, pg_temp 106 | AS $$ 107 | DECLARE 108 | supabase_user uuid; 109 | BEGIN 110 | SELECT id into supabase_user FROM auth.users WHERE raw_user_meta_data ->> 'test_identifier' = identifier limit 1; 111 | if supabase_user is null then 112 | RAISE EXCEPTION 'User with identifier % not found', identifier; 113 | end if; 114 | RETURN supabase_user; 115 | END; 116 | $$ LANGUAGE plpgsql; 117 | 118 | /** 119 | * ### tests.authenticate_as(identifier text) 120 | * Authenticates as a user created with `tests.create_supabase_user`. 121 | * 122 | * Parameters: 123 | * - `identifier` - The unique identifier for the user 124 | * 125 | * Returns: 126 | * - `void` 127 | * 128 | * Example: 129 | * ```sql 130 | * SELECT tests.create_supabase_user('test_owner'); 131 | * SELECT tests.authenticate_as('test_owner'); 132 | * ``` 133 | */ 134 | CREATE OR REPLACE FUNCTION tests.authenticate_as (identifier text) 135 | RETURNS void 136 | AS $$ 137 | DECLARE 138 | user_data json; 139 | original_auth_data text; 140 | BEGIN 141 | -- store the request.jwt.claims in a variable in case we need it 142 | original_auth_data := current_setting('request.jwt.claims', true); 143 | user_data := tests.get_supabase_user(identifier); 144 | 145 | if user_data is null OR user_data ->> 'id' IS NULL then 146 | RAISE EXCEPTION 'User with identifier % not found', identifier; 147 | end if; 148 | 149 | 150 | perform set_config('role', 'authenticated', true); 151 | perform set_config('request.jwt.claims', json_build_object('sub', user_data ->> 'id', 'email', user_data ->> 'email', 'phone', user_data ->> 'phone')::text, true); 152 | 153 | EXCEPTION 154 | -- revert back to original auth data 155 | WHEN OTHERS THEN 156 | set local role authenticated; 157 | set local "request.jwt.claims" to original_auth_data; 158 | RAISE; 159 | END 160 | $$ LANGUAGE plpgsql; 161 | 162 | /** 163 | * ### tests.clear_authentication() 164 | * Clears out the authentication and sets role to anon 165 | * 166 | * Returns: 167 | * - `void` 168 | * 169 | * Example: 170 | * ```sql 171 | * SELECT tests.create_supabase_user('test_owner'); 172 | * SELECT tests.authenticate_as('test_owner'); 173 | * SELECT tests.clear_authentication(); 174 | * ``` 175 | */ 176 | CREATE OR REPLACE FUNCTION tests.clear_authentication() 177 | RETURNS void AS $$ 178 | BEGIN 179 | perform set_config('role', 'anon', true); 180 | perform set_config('request.jwt.claims', null, true); 181 | END 182 | $$ LANGUAGE plpgsql; 183 | 184 | /** 185 | * ### tests.rls_enabled(testing_schema text) 186 | * pgTAP function to check if RLS is enabled on all tables in a provided schema 187 | * 188 | * Parameters: 189 | * - schema_name text - The name of the schema to check 190 | * 191 | * Example: 192 | * ```sql 193 | * BEGIN; 194 | * select plan(1); 195 | * select tests.rls_enabled('public'); 196 | * SELECT * FROM finish(); 197 | * ROLLBACK; 198 | * ``` 199 | */ 200 | CREATE OR REPLACE FUNCTION tests.rls_enabled (testing_schema text) 201 | RETURNS text AS $$ 202 | select is( 203 | (select 204 | count(pc.relname)::integer 205 | from pg_class pc 206 | join pg_namespace pn on pn.oid = pc.relnamespace and pn.nspname = rls_enabled.testing_schema 207 | join pg_type pt on pt.oid = pc.reltype 208 | where relrowsecurity = FALSE) 209 | , 210 | 0, 211 | 'All tables in the' || testing_schema || ' schema should have row level security enabled'); 212 | $$ LANGUAGE sql; 213 | 214 | /** 215 | * ### tests.rls_enabled(testing_schema text, testing_table text) 216 | * pgTAP function to check if RLS is enabled on a specific table 217 | * 218 | * Parameters: 219 | * - schema_name text - The name of the schema to check 220 | * - testing_table text - The name of the table to check 221 | * 222 | * Example: 223 | * ```sql 224 | * BEGIN; 225 | * select plan(1); 226 | * select tests.rls_enabled('public', 'accounts'); 227 | * SELECT * FROM finish(); 228 | * ROLLBACK; 229 | * ``` 230 | */ 231 | CREATE OR REPLACE FUNCTION tests.rls_enabled (testing_schema text, testing_table text) 232 | RETURNS TEXT AS $$ 233 | select is( 234 | (select 235 | count(*)::integer 236 | from pg_class pc 237 | join pg_namespace pn on pn.oid = pc.relnamespace and pn.nspname = rls_enabled.testing_schema and pc.relname = rls_enabled.testing_table 238 | join pg_type pt on pt.oid = pc.reltype 239 | where relrowsecurity = TRUE), 240 | 1, 241 | testing_table || 'table in the' || testing_schema || ' schema should have row level security enabled' 242 | ); 243 | $$ LANGUAGE sql; 244 | 245 | 246 | -------------------------------------------------------------------------------- /packages/types/src/database.ts: -------------------------------------------------------------------------------- 1 | export type Json = 2 | | string 3 | | number 4 | | boolean 5 | | null 6 | | { [key: string]: Json } 7 | | Json[]; 8 | 9 | export interface Database { 10 | public: { 11 | Tables: { 12 | channel: { 13 | Row: { 14 | type: Database['public']['Enums']['channel_type']; 15 | config: Json | null; 16 | id: string; 17 | organisation_id: string; 18 | created_at: string; 19 | name: string | null; 20 | handle: string | null; 21 | updated_at: string; 22 | link: string | null; 23 | provider_id: string | null; 24 | settings: Json | null; 25 | external_id: string | null; 26 | provider_type: Database['public']['Enums']['provider_type']; 27 | opt_in: boolean | null; 28 | auto_responder: boolean | null; 29 | opt_in_template_id: string | null; 30 | opt_out_template_id: string | null; 31 | default_welcome_template_id: string | null; 32 | outside_business_hours_welcome_template_id: string | null; 33 | status: Database['public']['Enums']['channel_status']; 34 | active: boolean | null; 35 | inbox_id: string; 36 | fts: unknown | null; 37 | }; 38 | Insert: { 39 | type: Database['public']['Enums']['channel_type']; 40 | config?: Json | null; 41 | id?: string; 42 | organisation_id?: string; 43 | created_at?: string; 44 | name?: string | null; 45 | handle?: string | null; 46 | updated_at?: string; 47 | link?: string | null; 48 | provider_id?: string | null; 49 | settings?: Json | null; 50 | external_id?: string | null; 51 | provider_type: Database['public']['Enums']['provider_type']; 52 | opt_in?: boolean | null; 53 | auto_responder?: boolean | null; 54 | opt_in_template_id?: string | null; 55 | opt_out_template_id?: string | null; 56 | default_welcome_template_id?: string | null; 57 | outside_business_hours_welcome_template_id?: string | null; 58 | status: Database['public']['Enums']['channel_status']; 59 | active?: boolean | null; 60 | inbox_id: string; 61 | fts?: unknown | null; 62 | }; 63 | Update: { 64 | type?: Database['public']['Enums']['channel_type']; 65 | config?: Json | null; 66 | id?: string; 67 | organisation_id?: string; 68 | created_at?: string; 69 | name?: string | null; 70 | handle?: string | null; 71 | updated_at?: string; 72 | link?: string | null; 73 | provider_id?: string | null; 74 | settings?: Json | null; 75 | external_id?: string | null; 76 | provider_type?: Database['public']['Enums']['provider_type']; 77 | opt_in?: boolean | null; 78 | auto_responder?: boolean | null; 79 | opt_in_template_id?: string | null; 80 | opt_out_template_id?: string | null; 81 | default_welcome_template_id?: string | null; 82 | outside_business_hours_welcome_template_id?: string | null; 83 | status?: Database['public']['Enums']['channel_status']; 84 | active?: boolean | null; 85 | inbox_id?: string; 86 | fts?: unknown | null; 87 | }; 88 | }; 89 | comment: { 90 | Row: { 91 | conversation_id: string; 92 | message_id: string | null; 93 | text: string | null; 94 | id: string; 95 | organisation_id: string; 96 | created_at: string; 97 | author_id: string; 98 | updated_at: string; 99 | }; 100 | Insert: { 101 | conversation_id: string; 102 | message_id?: string | null; 103 | text?: string | null; 104 | id?: string; 105 | organisation_id?: string; 106 | created_at?: string; 107 | author_id?: string; 108 | updated_at?: string; 109 | }; 110 | Update: { 111 | conversation_id?: string; 112 | message_id?: string | null; 113 | text?: string | null; 114 | id?: string; 115 | organisation_id?: string; 116 | created_at?: string; 117 | author_id?: string; 118 | updated_at?: string; 119 | }; 120 | }; 121 | comment_mention: { 122 | Row: { 123 | employee_id: string; 124 | comment_id: string; 125 | organisation_id: string; 126 | conversation_id: string; 127 | }; 128 | Insert: { 129 | employee_id: string; 130 | comment_id: string; 131 | organisation_id?: string; 132 | conversation_id: string; 133 | }; 134 | Update: { 135 | employee_id?: string; 136 | comment_id?: string; 137 | organisation_id?: string; 138 | conversation_id?: string; 139 | }; 140 | }; 141 | contact: { 142 | Row: { 143 | full_name: string | null; 144 | description: string | null; 145 | email: string | null; 146 | id: string; 147 | organisation_id: string; 148 | created_at: string; 149 | sms: string | null; 150 | whatsapp: string | null; 151 | custom_fields: Json | null; 152 | instagram: string | null; 153 | facebook: string | null; 154 | updated_at: string; 155 | display_name: string | null; 156 | google_business_messaging: string | null; 157 | whatsapp_conversation_id: string | null; 158 | sms_conversation_id: string | null; 159 | fts: unknown | null; 160 | files: Json; 161 | }; 162 | Insert: { 163 | full_name?: string | null; 164 | description?: string | null; 165 | email?: string | null; 166 | id?: string; 167 | organisation_id?: string; 168 | created_at?: string; 169 | sms?: string | null; 170 | whatsapp?: string | null; 171 | custom_fields?: Json | null; 172 | instagram?: string | null; 173 | facebook?: string | null; 174 | updated_at?: string; 175 | display_name?: string | null; 176 | google_business_messaging?: string | null; 177 | whatsapp_conversation_id?: string | null; 178 | sms_conversation_id?: string | null; 179 | fts?: unknown | null; 180 | }; 181 | Update: { 182 | full_name?: string | null; 183 | description?: string | null; 184 | email?: string | null; 185 | id?: string; 186 | organisation_id?: string; 187 | created_at?: string; 188 | sms?: string | null; 189 | whatsapp?: string | null; 190 | custom_fields?: Json | null; 191 | instagram?: string | null; 192 | facebook?: string | null; 193 | updated_at?: string; 194 | display_name?: string | null; 195 | google_business_messaging?: string | null; 196 | whatsapp_conversation_id?: string | null; 197 | sms_conversation_id?: string | null; 198 | fts?: unknown | null; 199 | }; 200 | }; 201 | contact_custom_field: { 202 | Row: { 203 | contact_id: string; 204 | custom_field_id: string; 205 | value: string | null; 206 | organisation_id: string; 207 | created_at: string; 208 | updated_at: string; 209 | }; 210 | Insert: { 211 | contact_id: string; 212 | custom_field_id: string; 213 | value?: string | null; 214 | organisation_id?: string; 215 | created_at?: string; 216 | updated_at?: string; 217 | }; 218 | Update: { 219 | contact_id?: string; 220 | custom_field_id?: string; 221 | value?: string | null; 222 | organisation_id?: string; 223 | created_at?: string; 224 | updated_at?: string; 225 | }; 226 | }; 227 | contact_note: { 228 | Row: { 229 | contact_id: string; 230 | text: string | null; 231 | id: string; 232 | organisation_id: string; 233 | created_at: string; 234 | created_by_id: string | null; 235 | updated_at: string; 236 | }; 237 | Insert: { 238 | contact_id: string; 239 | text?: string | null; 240 | id?: string; 241 | organisation_id?: string; 242 | created_at?: string; 243 | created_by_id?: string | null; 244 | updated_at?: string; 245 | }; 246 | Update: { 247 | contact_id?: string; 248 | text?: string | null; 249 | id?: string; 250 | organisation_id?: string; 251 | created_at?: string; 252 | created_by_id?: string | null; 253 | updated_at?: string; 254 | }; 255 | }; 256 | contact_opt_in: { 257 | Row: { 258 | contact_id: string; 259 | channel_type: Database['public']['Enums']['channel_type']; 260 | opt_in_reason: Database['public']['Enums']['opt_in_reason'] | null; 261 | id: string; 262 | organisation_id: string; 263 | created_at: string; 264 | updated_at: string; 265 | }; 266 | Insert: { 267 | contact_id: string; 268 | channel_type: Database['public']['Enums']['channel_type']; 269 | opt_in_reason?: Database['public']['Enums']['opt_in_reason'] | null; 270 | id?: string; 271 | organisation_id?: string; 272 | created_at?: string; 273 | updated_at?: string; 274 | }; 275 | Update: { 276 | contact_id?: string; 277 | channel_type?: Database['public']['Enums']['channel_type']; 278 | opt_in_reason?: Database['public']['Enums']['opt_in_reason'] | null; 279 | id?: string; 280 | organisation_id?: string; 281 | created_at?: string; 282 | updated_at?: string; 283 | }; 284 | }; 285 | continent: { 286 | Row: { 287 | code: string; 288 | name: string | null; 289 | }; 290 | Insert: { 291 | code: string; 292 | name?: string | null; 293 | }; 294 | Update: { 295 | code?: string; 296 | name?: string | null; 297 | }; 298 | }; 299 | conversation: { 300 | Row: { 301 | subject: string | null; 302 | assignee_id: string | null; 303 | id: string; 304 | organisation_id: string; 305 | created_at: string; 306 | status: Database['public']['Enums']['conversation_status']; 307 | unread: boolean | null; 308 | channel_id: string; 309 | channel_type: Database['public']['Enums']['channel_type']; 310 | recipient_id: string | null; 311 | external_id: string | null; 312 | tags: Json | null; 313 | updated_at: string; 314 | is_spam: boolean; 315 | inbox_id: string; 316 | blurb: string | null; 317 | latest_message_id: string | null; 318 | latest_inbound_message_id: string | null; 319 | latest_message_created_at: string | null; 320 | latest_message_attachment_count: number | null; 321 | latest_inbound_message_created_at: string | null; 322 | fts: unknown | null; 323 | display_date: string; 324 | files: Json; 325 | recipient_list: string; 326 | session_time: number; 327 | }; 328 | Insert: { 329 | subject?: string | null; 330 | assignee_id?: string | null; 331 | id?: string; 332 | organisation_id?: string; 333 | created_at?: string; 334 | status?: Database['public']['Enums']['conversation_status']; 335 | unread?: boolean | null; 336 | channel_id: string; 337 | channel_type: Database['public']['Enums']['channel_type']; 338 | recipient_id?: string | null; 339 | external_id?: string | null; 340 | tags?: Json | null; 341 | updated_at?: string; 342 | is_spam?: boolean; 343 | inbox_id: string; 344 | blurb?: string | null; 345 | latest_message_id?: string | null; 346 | latest_inbound_message_id?: string | null; 347 | latest_message_created_at?: string | null; 348 | latest_message_attachment_count?: number | null; 349 | latest_inbound_message_created_at?: string | null; 350 | fts?: unknown | null; 351 | }; 352 | Update: { 353 | subject?: string | null; 354 | assignee_id?: string | null; 355 | id?: string; 356 | organisation_id?: string; 357 | created_at?: string; 358 | status?: Database['public']['Enums']['conversation_status']; 359 | unread?: boolean | null; 360 | channel_id?: string; 361 | channel_type?: Database['public']['Enums']['channel_type']; 362 | recipient_id?: string | null; 363 | external_id?: string | null; 364 | tags?: Json | null; 365 | updated_at?: string; 366 | is_spam?: boolean; 367 | inbox_id?: string; 368 | blurb?: string | null; 369 | latest_message_id?: string | null; 370 | latest_inbound_message_id?: string | null; 371 | latest_message_created_at?: string | null; 372 | latest_message_attachment_count?: number | null; 373 | latest_inbound_message_created_at?: string | null; 374 | fts?: unknown | null; 375 | }; 376 | }; 377 | conversation_follower: { 378 | Row: { 379 | employee_id: string; 380 | conversation_id: string; 381 | last_seen: string | null; 382 | organisation_id: string; 383 | }; 384 | Insert: { 385 | employee_id: string; 386 | conversation_id: string; 387 | last_seen?: string | null; 388 | organisation_id?: string; 389 | }; 390 | Update: { 391 | employee_id?: string; 392 | conversation_id?: string; 393 | last_seen?: string | null; 394 | organisation_id?: string; 395 | }; 396 | }; 397 | conversation_tag: { 398 | Row: { 399 | tag_id: string; 400 | conversation_id: string; 401 | organisation_id: string; 402 | created_at: string; 403 | }; 404 | Insert: { 405 | tag_id: string; 406 | conversation_id: string; 407 | organisation_id?: string; 408 | created_at?: string; 409 | }; 410 | Update: { 411 | tag_id?: string; 412 | conversation_id?: string; 413 | organisation_id?: string; 414 | created_at?: string; 415 | }; 416 | }; 417 | country: { 418 | Row: { 419 | code: string; 420 | name: string; 421 | full_name: string; 422 | iso3: string; 423 | number: string; 424 | continent_code: string; 425 | }; 426 | Insert: { 427 | code: string; 428 | name: string; 429 | full_name: string; 430 | iso3: string; 431 | number: string; 432 | continent_code: string; 433 | }; 434 | Update: { 435 | code?: string; 436 | name?: string; 437 | full_name?: string; 438 | iso3?: string; 439 | number?: string; 440 | continent_code?: string; 441 | }; 442 | }; 443 | custom_field: { 444 | Row: { 445 | name: string; 446 | description: string | null; 447 | id: string; 448 | organisation_id: string; 449 | type: Database['public']['Enums']['field_type']; 450 | updated_at: string; 451 | created_at: string; 452 | key: string; 453 | }; 454 | Insert: { 455 | name: string; 456 | description?: string | null; 457 | id?: string; 458 | organisation_id?: string; 459 | type: Database['public']['Enums']['field_type']; 460 | updated_at?: string; 461 | created_at?: string; 462 | key?: string; 463 | }; 464 | Update: { 465 | name?: string; 466 | description?: string | null; 467 | id?: string; 468 | organisation_id?: string; 469 | type?: Database['public']['Enums']['field_type']; 470 | updated_at?: string; 471 | created_at?: string; 472 | key?: string; 473 | }; 474 | }; 475 | customer: { 476 | Row: { 477 | id: string; 478 | stripe_customer_id: string; 479 | payment_missing: boolean | null; 480 | }; 481 | Insert: { 482 | id: string; 483 | stripe_customer_id: string; 484 | payment_missing?: boolean | null; 485 | }; 486 | Update: { 487 | id?: string; 488 | stripe_customer_id?: string; 489 | payment_missing?: boolean | null; 490 | }; 491 | }; 492 | employee: { 493 | Row: { 494 | user_id: string | null; 495 | username: string; 496 | id: string; 497 | created_at: string; 498 | is_admin: boolean | null; 499 | organisation_id: string; 500 | signature: string | null; 501 | updated_at: string; 502 | expo_tokens: string | null; 503 | full_name: string | null; 504 | email: string | null; 505 | display_name: string; 506 | fts: unknown | null; 507 | conversation_count: number; 508 | profile_image: Json; 509 | }; 510 | Insert: { 511 | user_id?: string | null; 512 | username: string; 513 | id?: string; 514 | created_at?: string; 515 | is_admin?: boolean | null; 516 | organisation_id?: string; 517 | signature?: string | null; 518 | updated_at?: string; 519 | expo_tokens?: string | null; 520 | full_name?: string | null; 521 | email?: string | null; 522 | display_name?: string; 523 | fts?: unknown | null; 524 | conversation_count?: number; 525 | }; 526 | Update: { 527 | user_id?: string | null; 528 | username?: string; 529 | id?: string; 530 | created_at?: string; 531 | is_admin?: boolean | null; 532 | organisation_id?: string; 533 | signature?: string | null; 534 | updated_at?: string; 535 | expo_tokens?: string | null; 536 | full_name?: string | null; 537 | email?: string | null; 538 | display_name?: string; 539 | fts?: unknown | null; 540 | conversation_count?: number; 541 | }; 542 | }; 543 | employee_notification: { 544 | Row: { 545 | notification_type: string; 546 | employee_id: string; 547 | conversation_id: string | null; 548 | id: string; 549 | organisation_id: string; 550 | created_at: string; 551 | updated_at: string; 552 | data: Json | null; 553 | seen: boolean; 554 | }; 555 | Insert: { 556 | notification_type: string; 557 | employee_id: string; 558 | conversation_id?: string | null; 559 | id?: string; 560 | organisation_id?: string; 561 | created_at?: string; 562 | updated_at?: string; 563 | data?: Json | null; 564 | }; 565 | Update: { 566 | notification_type?: string; 567 | employee_id?: string; 568 | conversation_id?: string | null; 569 | id?: string; 570 | organisation_id?: string; 571 | created_at?: string; 572 | updated_at?: string; 573 | data?: Json | null; 574 | }; 575 | }; 576 | event: { 577 | Row: { 578 | conversation_id: string; 579 | target_id: string | null; 580 | target_type: Database['public']['Enums']['event_entity_type'] | null; 581 | metadata: Json | null; 582 | id: string; 583 | organisation_id: string; 584 | created_at: string; 585 | type: Database['public']['Enums']['event_type']; 586 | source_type: Database['public']['Enums']['event_entity_type'] | null; 587 | source_id: string | null; 588 | source: Json; 589 | target: Json; 590 | }; 591 | Insert: { 592 | conversation_id: string; 593 | target_id?: string | null; 594 | target_type?: Database['public']['Enums']['event_entity_type'] | null; 595 | metadata?: Json | null; 596 | id?: string; 597 | organisation_id?: string; 598 | created_at?: string; 599 | type: Database['public']['Enums']['event_type']; 600 | source_type?: Database['public']['Enums']['event_entity_type'] | null; 601 | source_id?: string | null; 602 | }; 603 | Update: { 604 | conversation_id?: string; 605 | target_id?: string | null; 606 | target_type?: Database['public']['Enums']['event_entity_type'] | null; 607 | metadata?: Json | null; 608 | id?: string; 609 | organisation_id?: string; 610 | created_at?: string; 611 | type?: Database['public']['Enums']['event_type']; 612 | source_type?: Database['public']['Enums']['event_entity_type'] | null; 613 | source_id?: string | null; 614 | }; 615 | }; 616 | inbox: { 617 | Row: { 618 | name: string; 619 | id: string; 620 | organisation_id: string; 621 | updated_at: string; 622 | created_at: string; 623 | conversation_count: number; 624 | }; 625 | Insert: { 626 | name: string; 627 | id?: string; 628 | organisation_id?: string; 629 | updated_at?: string; 630 | created_at?: string; 631 | conversation_count?: number; 632 | }; 633 | Update: { 634 | name?: string; 635 | id?: string; 636 | organisation_id?: string; 637 | updated_at?: string; 638 | created_at?: string; 639 | conversation_count?: number; 640 | }; 641 | }; 642 | inbox_access: { 643 | Row: { 644 | inbox_id: string; 645 | employee_id: string | null; 646 | team_id: string | null; 647 | id: string; 648 | organisation_id: string; 649 | level: Database['public']['Enums']['inbox_level']; 650 | created_at: string; 651 | updated_at: string; 652 | }; 653 | Insert: { 654 | inbox_id: string; 655 | employee_id?: string | null; 656 | team_id?: string | null; 657 | id?: string; 658 | organisation_id?: string; 659 | level?: Database['public']['Enums']['inbox_level']; 660 | created_at?: string; 661 | updated_at?: string; 662 | }; 663 | Update: { 664 | inbox_id?: string; 665 | employee_id?: string | null; 666 | team_id?: string | null; 667 | id?: string; 668 | organisation_id?: string; 669 | level?: Database['public']['Enums']['inbox_level']; 670 | created_at?: string; 671 | updated_at?: string; 672 | }; 673 | }; 674 | industry: { 675 | Row: { 676 | key: string; 677 | comment: string | null; 678 | }; 679 | Insert: { 680 | key: string; 681 | comment?: string | null; 682 | }; 683 | Update: { 684 | key?: string; 685 | comment?: string | null; 686 | }; 687 | }; 688 | language: { 689 | Row: { 690 | code: string; 691 | name: string; 692 | }; 693 | Insert: { 694 | code: string; 695 | name: string; 696 | }; 697 | Update: { 698 | code?: string; 699 | name?: string; 700 | }; 701 | }; 702 | locale: { 703 | Row: { 704 | code: string; 705 | english_name: string; 706 | native_name: string; 707 | }; 708 | Insert: { 709 | code: string; 710 | english_name: string; 711 | native_name: string; 712 | }; 713 | Update: { 714 | code?: string; 715 | english_name?: string; 716 | native_name?: string; 717 | }; 718 | }; 719 | message: { 720 | Row: { 721 | conversation_id: string; 722 | subject: string | null; 723 | blurb: string | null; 724 | html: string | null; 725 | text: string | null; 726 | id: string; 727 | organisation_id: string; 728 | created_at: string; 729 | is_inbound: boolean; 730 | author_id: string | null; 731 | status: Database['public']['Enums']['recipient_status'] | null; 732 | attachment_count: number | null; 733 | reply_to_message_id: string | null; 734 | external_files: Json | null; 735 | external_id: string | null; 736 | template_id: string | null; 737 | is_draft: boolean; 738 | review_channel_id: string | null; 739 | author_type: Database['public']['Enums']['author_type'] | null; 740 | author: unknown; 741 | files: Json; 742 | }; 743 | Insert: { 744 | conversation_id: string; 745 | subject?: string | null; 746 | blurb?: string | null; 747 | html?: string | null; 748 | text?: string | null; 749 | id?: string; 750 | organisation_id?: string; 751 | created_at?: string; 752 | is_inbound?: boolean; 753 | author_id?: string | null; 754 | status?: Database['public']['Enums']['recipient_status'] | null; 755 | attachment_count?: number | null; 756 | reply_to_message_id?: string | null; 757 | external_files?: Json | null; 758 | external_id?: string | null; 759 | template_id?: string | null; 760 | is_draft?: boolean; 761 | review_channel_id?: string | null; 762 | author_type?: Database['public']['Enums']['author_type'] | null; 763 | }; 764 | Update: { 765 | conversation_id?: string; 766 | subject?: string | null; 767 | blurb?: string | null; 768 | html?: string | null; 769 | text?: string | null; 770 | id?: string; 771 | organisation_id?: string; 772 | created_at?: string; 773 | is_inbound?: boolean; 774 | author_id?: string | null; 775 | status?: Database['public']['Enums']['recipient_status'] | null; 776 | attachment_count?: number | null; 777 | reply_to_message_id?: string | null; 778 | external_files?: Json | null; 779 | external_id?: string | null; 780 | template_id?: string | null; 781 | is_draft?: boolean; 782 | review_channel_id?: string | null; 783 | author_type?: Database['public']['Enums']['author_type'] | null; 784 | }; 785 | }; 786 | notification_preference: { 787 | Row: { 788 | notification_type: string; 789 | opt_in: boolean | null; 790 | employee_id: string; 791 | organisation_id: string; 792 | created_at: string; 793 | updated_at: string; 794 | }; 795 | Insert: { 796 | notification_type: string; 797 | opt_in?: boolean | null; 798 | employee_id?: string; 799 | organisation_id?: string; 800 | created_at?: string; 801 | updated_at?: string; 802 | }; 803 | Update: { 804 | notification_type?: string; 805 | opt_in?: boolean | null; 806 | employee_id?: string; 807 | organisation_id?: string; 808 | created_at?: string; 809 | updated_at?: string; 810 | }; 811 | }; 812 | notification_type: { 813 | Row: { 814 | name: string; 815 | channel: Database['public']['Enums']['notification_channel']; 816 | title: string; 817 | body: string; 818 | created_at: string; 819 | updated_at: string; 820 | }; 821 | Insert: { 822 | name: string; 823 | channel: Database['public']['Enums']['notification_channel']; 824 | title: string; 825 | body: string; 826 | created_at?: string; 827 | updated_at?: string; 828 | }; 829 | Update: { 830 | name?: string; 831 | channel?: Database['public']['Enums']['notification_channel']; 832 | title?: string; 833 | body?: string; 834 | created_at?: string; 835 | updated_at?: string; 836 | }; 837 | }; 838 | opening_hours: { 839 | Row: { 840 | days_of_the_week: number[]; 841 | open_time: string; 842 | close_time: string; 843 | id: string; 844 | created_at: string; 845 | organisation_id: string; 846 | updated_at: string; 847 | }; 848 | Insert: { 849 | days_of_the_week: number[]; 850 | open_time: string; 851 | close_time: string; 852 | id?: string; 853 | created_at?: string; 854 | organisation_id?: string; 855 | updated_at?: string; 856 | }; 857 | Update: { 858 | days_of_the_week?: number[]; 859 | open_time?: string; 860 | close_time?: string; 861 | id?: string; 862 | created_at?: string; 863 | organisation_id?: string; 864 | updated_at?: string; 865 | }; 866 | }; 867 | organisation: { 868 | Row: { 869 | name: string; 870 | mobile: string | null; 871 | landline: string | null; 872 | email: string | null; 873 | street: string | null; 874 | postal_code: string | null; 875 | city: string | null; 876 | id: string; 877 | created_at: string; 878 | industry: string | null; 879 | region: string | null; 880 | iso_country: string | null; 881 | updated_at: string; 882 | vat: string | null; 883 | is_sp: boolean | null; 884 | sp_full_name: string | null; 885 | sp_region: string | null; 886 | sp_postal_code: string | null; 887 | sp_street: string | null; 888 | sp_city: string | null; 889 | data_privacy_url: string | null; 890 | description: string | null; 891 | website_url: string | null; 892 | display_name: string; 893 | timezone: string; 894 | locale: string; 895 | address_line: string | null; 896 | contact_widget_image: Json; 897 | favicon: Json; 898 | logo: Json; 899 | }; 900 | Insert: { 901 | name: string; 902 | mobile?: string | null; 903 | landline?: string | null; 904 | email?: string | null; 905 | street?: string | null; 906 | postal_code?: string | null; 907 | city?: string | null; 908 | id?: string; 909 | created_at?: string; 910 | industry?: string | null; 911 | region?: string | null; 912 | iso_country?: string | null; 913 | updated_at?: string; 914 | vat?: string | null; 915 | is_sp?: boolean | null; 916 | sp_full_name?: string | null; 917 | sp_region?: string | null; 918 | sp_postal_code?: string | null; 919 | sp_street?: string | null; 920 | sp_city?: string | null; 921 | data_privacy_url?: string | null; 922 | description?: string | null; 923 | website_url?: string | null; 924 | display_name: string; 925 | timezone: string; 926 | locale: string; 927 | address_line?: string | null; 928 | }; 929 | Update: { 930 | name?: string; 931 | mobile?: string | null; 932 | landline?: string | null; 933 | email?: string | null; 934 | street?: string | null; 935 | postal_code?: string | null; 936 | city?: string | null; 937 | id?: string; 938 | created_at?: string; 939 | industry?: string | null; 940 | region?: string | null; 941 | iso_country?: string | null; 942 | updated_at?: string; 943 | vat?: string | null; 944 | is_sp?: boolean | null; 945 | sp_full_name?: string | null; 946 | sp_region?: string | null; 947 | sp_postal_code?: string | null; 948 | sp_street?: string | null; 949 | sp_city?: string | null; 950 | data_privacy_url?: string | null; 951 | description?: string | null; 952 | website_url?: string | null; 953 | display_name?: string; 954 | timezone?: string; 955 | locale?: string; 956 | address_line?: string | null; 957 | }; 958 | }; 959 | pinned_assignee: { 960 | Row: { 961 | assignee_id: string; 962 | organisation_id: string; 963 | employee_id: string; 964 | }; 965 | Insert: { 966 | assignee_id: string; 967 | organisation_id?: string; 968 | employee_id?: string; 969 | }; 970 | Update: { 971 | assignee_id?: string; 972 | organisation_id?: string; 973 | employee_id?: string; 974 | }; 975 | }; 976 | pinned_inbox: { 977 | Row: { 978 | inbox_id: string; 979 | organisation_id: string; 980 | employee_id: string; 981 | }; 982 | Insert: { 983 | inbox_id: string; 984 | organisation_id?: string; 985 | employee_id?: string; 986 | }; 987 | Update: { 988 | inbox_id?: string; 989 | organisation_id?: string; 990 | employee_id?: string; 991 | }; 992 | }; 993 | price: { 994 | Row: { 995 | id: string; 996 | product_id: string | null; 997 | description: string | null; 998 | metadata: Json | null; 999 | active: boolean | null; 1000 | }; 1001 | Insert: { 1002 | id: string; 1003 | product_id?: string | null; 1004 | description?: string | null; 1005 | metadata?: Json | null; 1006 | active?: boolean | null; 1007 | }; 1008 | Update: { 1009 | id?: string; 1010 | product_id?: string | null; 1011 | description?: string | null; 1012 | metadata?: Json | null; 1013 | active?: boolean | null; 1014 | }; 1015 | }; 1016 | product: { 1017 | Row: { 1018 | id: string; 1019 | name: string | null; 1020 | description: string | null; 1021 | metadata: Json | null; 1022 | active: boolean | null; 1023 | }; 1024 | Insert: { 1025 | id: string; 1026 | name?: string | null; 1027 | description?: string | null; 1028 | metadata?: Json | null; 1029 | active?: boolean | null; 1030 | }; 1031 | Update: { 1032 | id?: string; 1033 | name?: string | null; 1034 | description?: string | null; 1035 | metadata?: Json | null; 1036 | active?: boolean | null; 1037 | }; 1038 | }; 1039 | provider: { 1040 | Row: { 1041 | external_id: string | null; 1042 | name: string | null; 1043 | status: Database['public']['Enums']['provider_status']; 1044 | rejection_reason: string | null; 1045 | config: Json | null; 1046 | type: Database['public']['Enums']['provider_type']; 1047 | authorised_channel_types: 1048 | | Database['public']['Enums']['channel_type'][] 1049 | | null; 1050 | authorised_review_channel_types: 1051 | | Database['public']['Enums']['review_channel_type'][] 1052 | | null; 1053 | id: string; 1054 | organisation_id: string; 1055 | created_at: string; 1056 | updated_at: string; 1057 | }; 1058 | Insert: { 1059 | external_id?: string | null; 1060 | name?: string | null; 1061 | status: Database['public']['Enums']['provider_status']; 1062 | rejection_reason?: string | null; 1063 | config?: Json | null; 1064 | type: Database['public']['Enums']['provider_type']; 1065 | authorised_channel_types?: 1066 | | Database['public']['Enums']['channel_type'][] 1067 | | null; 1068 | authorised_review_channel_types?: 1069 | | Database['public']['Enums']['review_channel_type'][] 1070 | | null; 1071 | id?: string; 1072 | organisation_id?: string; 1073 | created_at?: string; 1074 | updated_at?: string; 1075 | }; 1076 | Update: { 1077 | external_id?: string | null; 1078 | name?: string | null; 1079 | status?: Database['public']['Enums']['provider_status']; 1080 | rejection_reason?: string | null; 1081 | config?: Json | null; 1082 | type?: Database['public']['Enums']['provider_type']; 1083 | authorised_channel_types?: 1084 | | Database['public']['Enums']['channel_type'][] 1085 | | null; 1086 | authorised_review_channel_types?: 1087 | | Database['public']['Enums']['review_channel_type'][] 1088 | | null; 1089 | id?: string; 1090 | organisation_id?: string; 1091 | created_at?: string; 1092 | updated_at?: string; 1093 | }; 1094 | }; 1095 | provider_template_approval: { 1096 | Row: { 1097 | provider_id: string; 1098 | template_id: string; 1099 | status: Database['public']['Enums']['whatsapp_template_status']; 1100 | external_id: string | null; 1101 | organisation_id: string; 1102 | created_at: string; 1103 | updated_at: string; 1104 | }; 1105 | Insert: { 1106 | provider_id: string; 1107 | template_id: string; 1108 | status: Database['public']['Enums']['whatsapp_template_status']; 1109 | external_id?: string | null; 1110 | organisation_id?: string; 1111 | created_at?: string; 1112 | updated_at?: string; 1113 | }; 1114 | Update: { 1115 | provider_id?: string; 1116 | template_id?: string; 1117 | status?: Database['public']['Enums']['whatsapp_template_status']; 1118 | external_id?: string | null; 1119 | organisation_id?: string; 1120 | created_at?: string; 1121 | updated_at?: string; 1122 | }; 1123 | }; 1124 | recipient: { 1125 | Row: { 1126 | conversation_id: string; 1127 | message_id: string; 1128 | contact_id: string | null; 1129 | handle: string; 1130 | full_name: string | null; 1131 | id: string; 1132 | organisation_id: string; 1133 | created_at: string; 1134 | role: Database['public']['Enums']['recipient_role'] | null; 1135 | is_organisation: boolean | null; 1136 | status: Database['public']['Enums']['recipient_status'] | null; 1137 | context: Json | null; 1138 | }; 1139 | Insert: { 1140 | conversation_id: string; 1141 | message_id: string; 1142 | contact_id?: string | null; 1143 | handle: string; 1144 | full_name?: string | null; 1145 | id?: string; 1146 | organisation_id?: string; 1147 | created_at?: string; 1148 | role?: Database['public']['Enums']['recipient_role'] | null; 1149 | is_organisation?: boolean | null; 1150 | status?: Database['public']['Enums']['recipient_status'] | null; 1151 | context?: Json | null; 1152 | }; 1153 | Update: { 1154 | conversation_id?: string; 1155 | message_id?: string; 1156 | contact_id?: string | null; 1157 | handle?: string; 1158 | full_name?: string | null; 1159 | id?: string; 1160 | organisation_id?: string; 1161 | created_at?: string; 1162 | role?: Database['public']['Enums']['recipient_role'] | null; 1163 | is_organisation?: boolean | null; 1164 | status?: Database['public']['Enums']['recipient_status'] | null; 1165 | context?: Json | null; 1166 | }; 1167 | }; 1168 | review: { 1169 | Row: { 1170 | review_channel_id: string; 1171 | external_id: string | null; 1172 | comment: string | null; 1173 | id: string; 1174 | organisation_id: string; 1175 | created_at: string; 1176 | has_reply: boolean; 1177 | star_rating: number; 1178 | updated_at: string; 1179 | }; 1180 | Insert: { 1181 | review_channel_id: string; 1182 | external_id?: string | null; 1183 | comment?: string | null; 1184 | id?: string; 1185 | organisation_id?: string; 1186 | created_at?: string; 1187 | has_reply?: boolean; 1188 | star_rating: number; 1189 | updated_at?: string; 1190 | }; 1191 | Update: { 1192 | review_channel_id?: string; 1193 | external_id?: string | null; 1194 | comment?: string | null; 1195 | id?: string; 1196 | organisation_id?: string; 1197 | created_at?: string; 1198 | has_reply?: boolean; 1199 | star_rating?: number; 1200 | updated_at?: string; 1201 | }; 1202 | }; 1203 | review_channel: { 1204 | Row: { 1205 | type: Database['public']['Enums']['review_channel_type']; 1206 | id: string; 1207 | organisation_id: string; 1208 | created_at: string; 1209 | external_id: string | null; 1210 | config: Json | null; 1211 | active: boolean | null; 1212 | name: string | null; 1213 | updated_at: string; 1214 | provider_id: string | null; 1215 | welcome_text: string | null; 1216 | link: string | null; 1217 | new_review_link: string | null; 1218 | provider_type: Database['public']['Enums']['provider_type']; 1219 | handle: string; 1220 | review_app_link: string | null; 1221 | request_for_review_template_id: string | null; 1222 | organisation_logo: Json; 1223 | }; 1224 | Insert: { 1225 | type: Database['public']['Enums']['review_channel_type']; 1226 | id?: string; 1227 | organisation_id?: string; 1228 | created_at?: string; 1229 | external_id?: string | null; 1230 | config?: Json | null; 1231 | active?: boolean | null; 1232 | name?: string | null; 1233 | updated_at?: string; 1234 | provider_id?: string | null; 1235 | welcome_text?: string | null; 1236 | link?: string | null; 1237 | new_review_link?: string | null; 1238 | provider_type: Database['public']['Enums']['provider_type']; 1239 | handle: string; 1240 | review_app_link?: string | null; 1241 | request_for_review_template_id?: string | null; 1242 | }; 1243 | Update: { 1244 | type?: Database['public']['Enums']['review_channel_type']; 1245 | id?: string; 1246 | organisation_id?: string; 1247 | created_at?: string; 1248 | external_id?: string | null; 1249 | config?: Json | null; 1250 | active?: boolean | null; 1251 | name?: string | null; 1252 | updated_at?: string; 1253 | provider_id?: string | null; 1254 | welcome_text?: string | null; 1255 | link?: string | null; 1256 | new_review_link?: string | null; 1257 | provider_type?: Database['public']['Enums']['provider_type']; 1258 | handle?: string; 1259 | review_app_link?: string | null; 1260 | request_for_review_template_id?: string | null; 1261 | }; 1262 | }; 1263 | reviewer: { 1264 | Row: { 1265 | profile_photo_url: string | null; 1266 | display_name: string | null; 1267 | review_id: string; 1268 | id: string; 1269 | organisation_id: string; 1270 | created_at: string; 1271 | is_anonymous: boolean | null; 1272 | updated_at: string; 1273 | }; 1274 | Insert: { 1275 | profile_photo_url?: string | null; 1276 | display_name?: string | null; 1277 | review_id: string; 1278 | id?: string; 1279 | organisation_id?: string; 1280 | created_at?: string; 1281 | is_anonymous?: boolean | null; 1282 | updated_at?: string; 1283 | }; 1284 | Update: { 1285 | profile_photo_url?: string | null; 1286 | display_name?: string | null; 1287 | review_id?: string; 1288 | id?: string; 1289 | organisation_id?: string; 1290 | created_at?: string; 1291 | is_anonymous?: boolean | null; 1292 | updated_at?: string; 1293 | }; 1294 | }; 1295 | setting: { 1296 | Row: { 1297 | name: string; 1298 | value: string; 1299 | }; 1300 | Insert: { 1301 | name: string; 1302 | value: string; 1303 | }; 1304 | Update: { 1305 | name?: string; 1306 | value?: string; 1307 | }; 1308 | }; 1309 | subscription: { 1310 | Row: { 1311 | id: string; 1312 | organisation_id: string; 1313 | status: Database['public']['Enums']['subscription_status'] | null; 1314 | metadata: Json | null; 1315 | }; 1316 | Insert: { 1317 | id: string; 1318 | organisation_id: string; 1319 | status?: Database['public']['Enums']['subscription_status'] | null; 1320 | metadata?: Json | null; 1321 | }; 1322 | Update: { 1323 | id?: string; 1324 | organisation_id?: string; 1325 | status?: Database['public']['Enums']['subscription_status'] | null; 1326 | metadata?: Json | null; 1327 | }; 1328 | }; 1329 | subscription_item: { 1330 | Row: { 1331 | id: string; 1332 | subscription_id: string; 1333 | price_id: string; 1334 | metadata: Json | null; 1335 | quantity: number | null; 1336 | }; 1337 | Insert: { 1338 | id: string; 1339 | subscription_id: string; 1340 | price_id: string; 1341 | metadata?: Json | null; 1342 | quantity?: number | null; 1343 | }; 1344 | Update: { 1345 | id?: string; 1346 | subscription_id?: string; 1347 | price_id?: string; 1348 | metadata?: Json | null; 1349 | quantity?: number | null; 1350 | }; 1351 | }; 1352 | tag: { 1353 | Row: { 1354 | name: string; 1355 | color: string; 1356 | id: string; 1357 | organisation_id: string; 1358 | created_at: string; 1359 | updated_at: string; 1360 | }; 1361 | Insert: { 1362 | name: string; 1363 | color: string; 1364 | id?: string; 1365 | organisation_id?: string; 1366 | created_at?: string; 1367 | updated_at?: string; 1368 | }; 1369 | Update: { 1370 | name?: string; 1371 | color?: string; 1372 | id?: string; 1373 | organisation_id?: string; 1374 | created_at?: string; 1375 | updated_at?: string; 1376 | }; 1377 | }; 1378 | team: { 1379 | Row: { 1380 | name: string; 1381 | id: string; 1382 | is_default: boolean; 1383 | organisation_id: string; 1384 | updated_at: string; 1385 | created_at: string; 1386 | }; 1387 | Insert: { 1388 | name: string; 1389 | id?: string; 1390 | is_default?: boolean; 1391 | organisation_id?: string; 1392 | updated_at?: string; 1393 | created_at?: string; 1394 | }; 1395 | Update: { 1396 | name?: string; 1397 | id?: string; 1398 | is_default?: boolean; 1399 | organisation_id?: string; 1400 | updated_at?: string; 1401 | created_at?: string; 1402 | }; 1403 | }; 1404 | team_member: { 1405 | Row: { 1406 | team_id: string; 1407 | employee_id: string; 1408 | organisation_id: string; 1409 | updated_at: string; 1410 | created_at: string; 1411 | }; 1412 | Insert: { 1413 | team_id: string; 1414 | employee_id: string; 1415 | organisation_id?: string; 1416 | updated_at?: string; 1417 | created_at?: string; 1418 | }; 1419 | Update: { 1420 | team_id?: string; 1421 | employee_id?: string; 1422 | organisation_id?: string; 1423 | updated_at?: string; 1424 | created_at?: string; 1425 | }; 1426 | }; 1427 | template: { 1428 | Row: { 1429 | name: string; 1430 | hint: string | null; 1431 | subject: string | null; 1432 | html: string | null; 1433 | text: string | null; 1434 | metadata: Json | null; 1435 | id: string; 1436 | organisation_id: string; 1437 | created_at: string; 1438 | updated_at: string; 1439 | request_approvals: boolean | null; 1440 | not_user_selectable: boolean | null; 1441 | category: Database['public']['Enums']['template_category'] | null; 1442 | language: string; 1443 | key: string; 1444 | files: Json; 1445 | whatsapp_status: Database['public']['Enums']['whatsapp_template_status']; 1446 | }; 1447 | Insert: { 1448 | name: string; 1449 | hint?: string | null; 1450 | subject?: string | null; 1451 | html?: string | null; 1452 | text?: string | null; 1453 | metadata?: Json | null; 1454 | id?: string; 1455 | organisation_id?: string; 1456 | created_at?: string; 1457 | updated_at?: string; 1458 | request_approvals?: boolean | null; 1459 | not_user_selectable?: boolean | null; 1460 | category?: Database['public']['Enums']['template_category'] | null; 1461 | language: string; 1462 | key?: string; 1463 | }; 1464 | Update: { 1465 | name?: string; 1466 | hint?: string | null; 1467 | subject?: string | null; 1468 | html?: string | null; 1469 | text?: string | null; 1470 | metadata?: Json | null; 1471 | id?: string; 1472 | organisation_id?: string; 1473 | created_at?: string; 1474 | updated_at?: string; 1475 | request_approvals?: boolean | null; 1476 | not_user_selectable?: boolean | null; 1477 | category?: Database['public']['Enums']['template_category'] | null; 1478 | language?: string; 1479 | key?: string; 1480 | }; 1481 | }; 1482 | timezone: { 1483 | Row: { 1484 | name: string; 1485 | abbrev: string; 1486 | utc_offset_minutes: number; 1487 | }; 1488 | Insert: { 1489 | name: string; 1490 | abbrev: string; 1491 | }; 1492 | Update: { 1493 | name?: string; 1494 | abbrev?: string; 1495 | }; 1496 | }; 1497 | voice_call: { 1498 | Row: { 1499 | external_id: string; 1500 | channel_id: string; 1501 | from: string | null; 1502 | duration: number | null; 1503 | status: Database['public']['Enums']['call_status']; 1504 | id: string; 1505 | organisation_id: string; 1506 | created_at: string; 1507 | updated_at: string; 1508 | }; 1509 | Insert: { 1510 | external_id: string; 1511 | channel_id: string; 1512 | from?: string | null; 1513 | duration?: number | null; 1514 | status: Database['public']['Enums']['call_status']; 1515 | id?: string; 1516 | organisation_id?: string; 1517 | created_at?: string; 1518 | updated_at?: string; 1519 | }; 1520 | Update: { 1521 | external_id?: string; 1522 | channel_id?: string; 1523 | from?: string | null; 1524 | duration?: number | null; 1525 | status?: Database['public']['Enums']['call_status']; 1526 | id?: string; 1527 | organisation_id?: string; 1528 | created_at?: string; 1529 | updated_at?: string; 1530 | }; 1531 | }; 1532 | web_widget: { 1533 | Row: { 1534 | color: string | null; 1535 | welcome_message: string | null; 1536 | whatsapp_channel_id: string | null; 1537 | sms_channel_id: string | null; 1538 | facebook_channel_id: string | null; 1539 | instagram_channel_id: string | null; 1540 | email_channel_id: string | null; 1541 | id: string; 1542 | organisation_id: string; 1543 | created_at: string; 1544 | updated_at: string; 1545 | name: string; 1546 | background_color: string | null; 1547 | data_privacy_url: string; 1548 | email_channel_link: string; 1549 | facebook_channel_link: string; 1550 | instagram_channel_link: string; 1551 | organisation_name: string; 1552 | sms_channel_link: string; 1553 | whatsapp_channel_link: string; 1554 | }; 1555 | Insert: { 1556 | color?: string | null; 1557 | welcome_message?: string | null; 1558 | whatsapp_channel_id?: string | null; 1559 | sms_channel_id?: string | null; 1560 | facebook_channel_id?: string | null; 1561 | instagram_channel_id?: string | null; 1562 | email_channel_id?: string | null; 1563 | id?: string; 1564 | organisation_id?: string; 1565 | created_at?: string; 1566 | updated_at?: string; 1567 | name?: string; 1568 | background_color?: string | null; 1569 | }; 1570 | Update: { 1571 | color?: string | null; 1572 | welcome_message?: string | null; 1573 | whatsapp_channel_id?: string | null; 1574 | sms_channel_id?: string | null; 1575 | facebook_channel_id?: string | null; 1576 | instagram_channel_id?: string | null; 1577 | email_channel_id?: string | null; 1578 | id?: string; 1579 | organisation_id?: string; 1580 | created_at?: string; 1581 | updated_at?: string; 1582 | name?: string; 1583 | background_color?: string | null; 1584 | }; 1585 | }; 1586 | }; 1587 | Views: { 1588 | channel_link: { 1589 | Row: { 1590 | id: string | null; 1591 | link: string | null; 1592 | }; 1593 | Insert: { 1594 | id?: string | null; 1595 | link?: string | null; 1596 | }; 1597 | Update: { 1598 | id?: string | null; 1599 | link?: string | null; 1600 | }; 1601 | }; 1602 | pg_all_foreign_keys: { 1603 | Row: { 1604 | fk_schema_name: unknown | null; 1605 | fk_table_name: unknown | null; 1606 | fk_constraint_name: unknown | null; 1607 | fk_table_oid: unknown | null; 1608 | fk_columns: unknown[] | null; 1609 | pk_schema_name: unknown | null; 1610 | pk_table_name: unknown | null; 1611 | pk_constraint_name: unknown | null; 1612 | pk_table_oid: unknown | null; 1613 | pk_index_name: unknown | null; 1614 | pk_columns: unknown[] | null; 1615 | match_type: string | null; 1616 | on_delete: string | null; 1617 | on_update: string | null; 1618 | is_deferrable: boolean | null; 1619 | is_deferred: boolean | null; 1620 | }; 1621 | }; 1622 | public_organisation_profile: { 1623 | Row: { 1624 | id: string | null; 1625 | data_privacy_url: string | null; 1626 | display_name: string | null; 1627 | website_url: string | null; 1628 | description: string | null; 1629 | }; 1630 | Insert: { 1631 | id?: string | null; 1632 | data_privacy_url?: string | null; 1633 | display_name?: string | null; 1634 | website_url?: string | null; 1635 | description?: string | null; 1636 | }; 1637 | Update: { 1638 | id?: string | null; 1639 | data_privacy_url?: string | null; 1640 | display_name?: string | null; 1641 | website_url?: string | null; 1642 | description?: string | null; 1643 | }; 1644 | }; 1645 | public_review_channel: { 1646 | Row: { 1647 | id: string | null; 1648 | handle: string | null; 1649 | link: string | null; 1650 | new_review_link: string | null; 1651 | type: Database['public']['Enums']['review_channel_type'] | null; 1652 | organisation_id: string | null; 1653 | welcome_text: string | null; 1654 | organisation_name: string | null; 1655 | name: string | null; 1656 | }; 1657 | }; 1658 | tap_funky: { 1659 | Row: { 1660 | oid: unknown | null; 1661 | schema: unknown | null; 1662 | name: unknown | null; 1663 | owner: unknown | null; 1664 | args: string | null; 1665 | returns: string | null; 1666 | langoid: unknown | null; 1667 | is_strict: boolean | null; 1668 | kind: unknown | null; 1669 | is_definer: boolean | null; 1670 | returns_set: boolean | null; 1671 | volatility: string | null; 1672 | is_visible: boolean | null; 1673 | }; 1674 | }; 1675 | }; 1676 | Functions: { 1677 | _cleanup: { 1678 | Args: Record; 1679 | Returns: boolean; 1680 | }; 1681 | _contract_on: { 1682 | Args: { '': string }; 1683 | Returns: unknown; 1684 | }; 1685 | _currtest: { 1686 | Args: Record; 1687 | Returns: number; 1688 | }; 1689 | _db_privs: { 1690 | Args: Record; 1691 | Returns: unknown[]; 1692 | }; 1693 | _definer: { 1694 | Args: { '': unknown }; 1695 | Returns: boolean; 1696 | }; 1697 | _dexists: { 1698 | Args: { '': unknown }; 1699 | Returns: boolean; 1700 | }; 1701 | _expand_context: { 1702 | Args: { '': string }; 1703 | Returns: string; 1704 | }; 1705 | _expand_on: { 1706 | Args: { '': string }; 1707 | Returns: string; 1708 | }; 1709 | _expand_vol: { 1710 | Args: { '': string }; 1711 | Returns: string; 1712 | }; 1713 | _ext_exists: { 1714 | Args: { '': unknown }; 1715 | Returns: boolean; 1716 | }; 1717 | _extensions: 1718 | | { 1719 | Args: { '': unknown }; 1720 | Returns: unknown; 1721 | } 1722 | | { 1723 | Args: Record; 1724 | Returns: unknown; 1725 | }; 1726 | _funkargs: { 1727 | Args: { '': unknown }; 1728 | Returns: string; 1729 | }; 1730 | _get: { 1731 | Args: { '': string }; 1732 | Returns: number; 1733 | }; 1734 | _get_db_owner: { 1735 | Args: { '': unknown }; 1736 | Returns: unknown; 1737 | }; 1738 | _get_dtype: { 1739 | Args: { '': unknown }; 1740 | Returns: string; 1741 | }; 1742 | _get_language_owner: { 1743 | Args: { '': unknown }; 1744 | Returns: unknown; 1745 | }; 1746 | _get_latest: { 1747 | Args: { '': string }; 1748 | Returns: number[]; 1749 | }; 1750 | _get_note: 1751 | | { 1752 | Args: { '': string }; 1753 | Returns: string; 1754 | } 1755 | | { 1756 | Args: { '': number }; 1757 | Returns: string; 1758 | }; 1759 | _get_opclass_owner: { 1760 | Args: { '': unknown }; 1761 | Returns: unknown; 1762 | }; 1763 | _get_rel_owner: { 1764 | Args: { '': unknown }; 1765 | Returns: unknown; 1766 | }; 1767 | _get_schema_owner: { 1768 | Args: { '': unknown }; 1769 | Returns: unknown; 1770 | }; 1771 | _get_tablespace_owner: { 1772 | Args: { '': unknown }; 1773 | Returns: unknown; 1774 | }; 1775 | _get_type_owner: { 1776 | Args: { '': unknown }; 1777 | Returns: unknown; 1778 | }; 1779 | _got_func: { 1780 | Args: { '': unknown }; 1781 | Returns: boolean; 1782 | }; 1783 | _grolist: { 1784 | Args: { '': unknown }; 1785 | Returns: unknown[]; 1786 | }; 1787 | _has_group: { 1788 | Args: { '': unknown }; 1789 | Returns: boolean; 1790 | }; 1791 | _has_role: { 1792 | Args: { '': unknown }; 1793 | Returns: boolean; 1794 | }; 1795 | _has_user: { 1796 | Args: { '': unknown }; 1797 | Returns: boolean; 1798 | }; 1799 | _inherited: { 1800 | Args: { '': unknown }; 1801 | Returns: boolean; 1802 | }; 1803 | _is_schema: { 1804 | Args: { '': unknown }; 1805 | Returns: boolean; 1806 | }; 1807 | _is_super: { 1808 | Args: { '': unknown }; 1809 | Returns: boolean; 1810 | }; 1811 | _is_trusted: { 1812 | Args: { '': unknown }; 1813 | Returns: boolean; 1814 | }; 1815 | _is_verbose: { 1816 | Args: Record; 1817 | Returns: boolean; 1818 | }; 1819 | _lang: { 1820 | Args: { '': unknown }; 1821 | Returns: unknown; 1822 | }; 1823 | _opc_exists: { 1824 | Args: { '': unknown }; 1825 | Returns: boolean; 1826 | }; 1827 | _parts: { 1828 | Args: { '': unknown }; 1829 | Returns: unknown; 1830 | }; 1831 | _pg_sv_type_array: { 1832 | Args: { '': unknown }; 1833 | Returns: unknown[]; 1834 | }; 1835 | _prokind: { 1836 | Args: { p_oid: unknown }; 1837 | Returns: unknown; 1838 | }; 1839 | _query: { 1840 | Args: { '': string }; 1841 | Returns: string; 1842 | }; 1843 | _refine_vol: { 1844 | Args: { '': string }; 1845 | Returns: string; 1846 | }; 1847 | _relexists: { 1848 | Args: { '': unknown }; 1849 | Returns: boolean; 1850 | }; 1851 | _returns: { 1852 | Args: { '': unknown }; 1853 | Returns: string; 1854 | }; 1855 | _strict: { 1856 | Args: { '': unknown }; 1857 | Returns: boolean; 1858 | }; 1859 | _table_privs: { 1860 | Args: Record; 1861 | Returns: unknown[]; 1862 | }; 1863 | _temptypes: { 1864 | Args: { '': string }; 1865 | Returns: string; 1866 | }; 1867 | _todo: { 1868 | Args: Record; 1869 | Returns: string; 1870 | }; 1871 | _vol: { 1872 | Args: { '': unknown }; 1873 | Returns: string; 1874 | }; 1875 | accept_employee_invite: { 1876 | Args: { employee_id: string }; 1877 | Returns: unknown; 1878 | }; 1879 | accessable_channels: { 1880 | Args: { 1881 | v_search: string; 1882 | v_channel_type: Database['public']['Enums']['channel_type']; 1883 | }; 1884 | Returns: Record[]; 1885 | }; 1886 | accessable_inboxes: { 1887 | Args: { 1888 | v_level: Database['public']['Enums']['inbox_level']; 1889 | v_search: string; 1890 | }; 1891 | Returns: Record[]; 1892 | }; 1893 | accessable_pinned_inboxes: { 1894 | Args: { 1895 | v_level: Database['public']['Enums']['inbox_level']; 1896 | v_search: string; 1897 | }; 1898 | Returns: Record[]; 1899 | }; 1900 | auth_header: { 1901 | Args: { prefer_service_role: boolean }; 1902 | Returns: string; 1903 | }; 1904 | author: { 1905 | Args: { '': unknown }; 1906 | Returns: unknown; 1907 | }; 1908 | broadcast_message: { 1909 | Args: { 1910 | v_conversation_input: unknown; 1911 | v_message_input: unknown; 1912 | v_recipients_input: unknown; 1913 | v_channels: unknown; 1914 | }; 1915 | Returns: Json; 1916 | }; 1917 | build_notification_payload: { 1918 | Args: { v_notification_type: string; v_input: unknown }; 1919 | Returns: Json; 1920 | }; 1921 | build_submit_message_payload: { 1922 | Args: { v_message_id: string }; 1923 | Returns: Json; 1924 | }; 1925 | can: { 1926 | Args: { '': unknown }; 1927 | Returns: string; 1928 | }; 1929 | can_upsert_twilio_provider: { 1930 | Args: { v_organisation_id: string }; 1931 | Returns: string[]; 1932 | }; 1933 | cascade_entity_deletion: { 1934 | Args: { 1935 | v_type: Database['public']['Enums']['event_entity_type']; 1936 | v_id: string; 1937 | }; 1938 | Returns: undefined; 1939 | }; 1940 | casts_are: { 1941 | Args: { '': unknown }; 1942 | Returns: string; 1943 | }; 1944 | check_for_duplicates: { 1945 | Args: { v_array: unknown }; 1946 | Returns: boolean; 1947 | }; 1948 | col_is_null: 1949 | | { 1950 | Args: { 1951 | schema_name: unknown; 1952 | table_name: unknown; 1953 | column_name: unknown; 1954 | description: string; 1955 | }; 1956 | Returns: string; 1957 | } 1958 | | { 1959 | Args: { 1960 | table_name: unknown; 1961 | column_name: unknown; 1962 | description: string; 1963 | }; 1964 | Returns: string; 1965 | }; 1966 | col_not_null: 1967 | | { 1968 | Args: { 1969 | schema_name: unknown; 1970 | table_name: unknown; 1971 | column_name: unknown; 1972 | description: string; 1973 | }; 1974 | Returns: string; 1975 | } 1976 | | { 1977 | Args: { 1978 | table_name: unknown; 1979 | column_name: unknown; 1980 | description: string; 1981 | }; 1982 | Returns: string; 1983 | }; 1984 | collect_tap: 1985 | | { 1986 | Args: Record; 1987 | Returns: string; 1988 | } 1989 | | { 1990 | Args: { '': unknown }; 1991 | Returns: string; 1992 | }; 1993 | contact_widget_image: { 1994 | Args: { '': unknown }; 1995 | Returns: Json; 1996 | }; 1997 | conversation_chat: { 1998 | Args: { v_conversation_id: string }; 1999 | Returns: Record[]; 2000 | }; 2001 | conversation_follower_events: { 2002 | Args: { employee: string }; 2003 | Returns: Record[]; 2004 | }; 2005 | create_conversation: { 2006 | Args: { 2007 | v_conversation_input: unknown; 2008 | v_message_input: unknown; 2009 | v_recipients_input: unknown; 2010 | }; 2011 | Returns: Record[]; 2012 | }; 2013 | data_privacy_url: { 2014 | Args: { '': unknown }; 2015 | Returns: string; 2016 | }; 2017 | diag: 2018 | | { 2019 | Args: { msg: string }; 2020 | Returns: string; 2021 | } 2022 | | { 2023 | Args: { msg: unknown }; 2024 | Returns: string; 2025 | } 2026 | | { 2027 | Args: Record; 2028 | Returns: string; 2029 | } 2030 | | { 2031 | Args: Record; 2032 | Returns: string; 2033 | }; 2034 | diag_test_name: { 2035 | Args: { '': string }; 2036 | Returns: string; 2037 | }; 2038 | display_date: { 2039 | Args: { '': unknown }; 2040 | Returns: string; 2041 | }; 2042 | do_tap: 2043 | | { 2044 | Args: { '': unknown }; 2045 | Returns: string; 2046 | } 2047 | | { 2048 | Args: { '': string }; 2049 | Returns: string; 2050 | } 2051 | | { 2052 | Args: Record; 2053 | Returns: string; 2054 | }; 2055 | domains_are: { 2056 | Args: { '': unknown }; 2057 | Returns: string; 2058 | }; 2059 | email_channel_link: { 2060 | Args: { '': unknown }; 2061 | Returns: string; 2062 | }; 2063 | employee_id: { 2064 | Args: { fail: boolean }; 2065 | Returns: string; 2066 | }; 2067 | employees_with_access_to_inbox: { 2068 | Args: { inbox_id: string; search: string }; 2069 | Returns: Record[]; 2070 | }; 2071 | enums_are: { 2072 | Args: { '': unknown }; 2073 | Returns: string; 2074 | }; 2075 | extensions_are: { 2076 | Args: { '': unknown }; 2077 | Returns: string; 2078 | }; 2079 | facebook_channel_link: { 2080 | Args: { '': unknown }; 2081 | Returns: string; 2082 | }; 2083 | fail: 2084 | | { 2085 | Args: { '': string }; 2086 | Returns: string; 2087 | } 2088 | | { 2089 | Args: Record; 2090 | Returns: string; 2091 | }; 2092 | favicon: { 2093 | Args: { '': unknown }; 2094 | Returns: Json; 2095 | }; 2096 | files: 2097 | | { 2098 | Args: { '': unknown }; 2099 | Returns: Json; 2100 | } 2101 | | { 2102 | Args: { '': unknown }; 2103 | Returns: Json; 2104 | } 2105 | | { 2106 | Args: { '': unknown }; 2107 | Returns: Json; 2108 | } 2109 | | { 2110 | Args: { '': unknown }; 2111 | Returns: Json; 2112 | }; 2113 | findfuncs: { 2114 | Args: { '': string }; 2115 | Returns: string[]; 2116 | }; 2117 | finish: { 2118 | Args: { exception_on_failure: boolean }; 2119 | Returns: string; 2120 | }; 2121 | foreign_tables_are: { 2122 | Args: { '': unknown }; 2123 | Returns: string; 2124 | }; 2125 | functions_are: { 2126 | Args: { '': unknown }; 2127 | Returns: string; 2128 | }; 2129 | groups_are: { 2130 | Args: { '': unknown }; 2131 | Returns: string; 2132 | }; 2133 | handle_message_bounced: { 2134 | Args: { 2135 | v_external_conversation_id: string; 2136 | v_external_message_id: string; 2137 | v_recipient_handle: string; 2138 | }; 2139 | Returns: undefined; 2140 | }; 2141 | handle_message_deleted: { 2142 | Args: { 2143 | v_external_conversation_id: string; 2144 | v_external_message_id: string; 2145 | }; 2146 | Returns: undefined; 2147 | }; 2148 | handle_message_read: { 2149 | Args: { 2150 | v_external_conversation_id: string; 2151 | v_external_message_id: string; 2152 | v_recipient_handle: string; 2153 | }; 2154 | Returns: undefined; 2155 | }; 2156 | handle_message_sent: { 2157 | Args: { 2158 | v_external_conversation_id: string; 2159 | v_external_message_id: string; 2160 | }; 2161 | Returns: undefined; 2162 | }; 2163 | handle_messages_read_until: { 2164 | Args: { 2165 | v_external_conversation_id: string; 2166 | v_read_until: string; 2167 | v_recipient_handle: string; 2168 | }; 2169 | Returns: undefined; 2170 | }; 2171 | handle_new_message: 2172 | | { 2173 | Args: { 2174 | v_external_channel_id: string; 2175 | v_external_conversation_id: string; 2176 | v_message_input: unknown; 2177 | v_recipients_input: unknown; 2178 | v_metadata: Json; 2179 | v_is_spam: boolean; 2180 | }; 2181 | Returns: string; 2182 | } 2183 | | { 2184 | Args: { 2185 | v_channel_type: Database['public']['Enums']['channel_type']; 2186 | v_external_channel_id: string; 2187 | v_external_conversation_id: string; 2188 | v_insert_with_conversation_id: string; 2189 | v_message_input: unknown; 2190 | v_recipients_input: unknown; 2191 | v_metadata: Json; 2192 | v_is_spam: boolean; 2193 | }; 2194 | Returns: string; 2195 | }; 2196 | handle_sending_error: { 2197 | Args: { 2198 | v_external_conversation_id: string; 2199 | v_external_message_id: string; 2200 | v_metadata: Json; 2201 | }; 2202 | Returns: undefined; 2203 | }; 2204 | handle_stripe_customer_event: 2205 | | { 2206 | Args: { 2207 | v_organisation_input: unknown; 2208 | v_stripe_customer_id: string; 2209 | v_employee_input: unknown; 2210 | v_delete_organisation: boolean; 2211 | }; 2212 | Returns: string; 2213 | } 2214 | | { 2215 | Args: { 2216 | v_organisation_input: unknown; 2217 | v_stripe_customer_id: string; 2218 | v_employee_input: unknown; 2219 | v_delete_organisation: boolean; 2220 | v_desires_sms_channel: boolean; 2221 | }; 2222 | Returns: string; 2223 | }; 2224 | handle_stripe_subscription_event: { 2225 | Args: { 2226 | v_stripe_customer_id: string; 2227 | v_subscription_input: unknown; 2228 | v_subscription_items_input: unknown; 2229 | }; 2230 | Returns: undefined; 2231 | }; 2232 | has_access_to_conversation: { 2233 | Args: { v_conversation_id: string }; 2234 | Returns: boolean; 2235 | }; 2236 | has_access_to_inbox: { 2237 | Args: { v_inbox_id: string }; 2238 | Returns: boolean; 2239 | }; 2240 | has_check: { 2241 | Args: { '': unknown }; 2242 | Returns: string; 2243 | }; 2244 | has_composite: { 2245 | Args: { '': unknown }; 2246 | Returns: string; 2247 | }; 2248 | has_domain: { 2249 | Args: { '': unknown }; 2250 | Returns: string; 2251 | }; 2252 | has_enum: { 2253 | Args: { '': unknown }; 2254 | Returns: string; 2255 | }; 2256 | has_extension: { 2257 | Args: { '': unknown }; 2258 | Returns: string; 2259 | }; 2260 | has_fk: { 2261 | Args: { '': unknown }; 2262 | Returns: string; 2263 | }; 2264 | has_foreign_table: { 2265 | Args: { '': unknown }; 2266 | Returns: string; 2267 | }; 2268 | has_full_access_to_inbox: { 2269 | Args: { v_inbox_id: string }; 2270 | Returns: boolean; 2271 | }; 2272 | has_function: { 2273 | Args: { '': unknown }; 2274 | Returns: string; 2275 | }; 2276 | has_group: { 2277 | Args: { '': unknown }; 2278 | Returns: string; 2279 | }; 2280 | has_inherited_tables: { 2281 | Args: { '': unknown }; 2282 | Returns: string; 2283 | }; 2284 | has_language: { 2285 | Args: { '': unknown }; 2286 | Returns: string; 2287 | }; 2288 | has_materialized_view: { 2289 | Args: { '': unknown }; 2290 | Returns: string; 2291 | }; 2292 | has_missing_payment: { 2293 | Args: { v_organisation_id: string }; 2294 | Returns: boolean; 2295 | }; 2296 | has_opclass: { 2297 | Args: { '': unknown }; 2298 | Returns: string; 2299 | }; 2300 | has_pk: { 2301 | Args: { '': unknown }; 2302 | Returns: string; 2303 | }; 2304 | has_relation: { 2305 | Args: { '': unknown }; 2306 | Returns: string; 2307 | }; 2308 | has_role: { 2309 | Args: { '': unknown }; 2310 | Returns: string; 2311 | }; 2312 | has_schema: { 2313 | Args: { '': unknown }; 2314 | Returns: string; 2315 | }; 2316 | has_sequence: { 2317 | Args: { '': unknown }; 2318 | Returns: string; 2319 | }; 2320 | has_table: { 2321 | Args: { '': unknown }; 2322 | Returns: string; 2323 | }; 2324 | has_tablespace: { 2325 | Args: { '': unknown }; 2326 | Returns: string; 2327 | }; 2328 | has_type: { 2329 | Args: { '': unknown }; 2330 | Returns: string; 2331 | }; 2332 | has_unique: { 2333 | Args: { '': string }; 2334 | Returns: string; 2335 | }; 2336 | has_user: { 2337 | Args: { '': unknown }; 2338 | Returns: string; 2339 | }; 2340 | has_view: { 2341 | Args: { '': unknown }; 2342 | Returns: string; 2343 | }; 2344 | hasnt_composite: { 2345 | Args: { '': unknown }; 2346 | Returns: string; 2347 | }; 2348 | hasnt_domain: { 2349 | Args: { '': unknown }; 2350 | Returns: string; 2351 | }; 2352 | hasnt_enum: { 2353 | Args: { '': unknown }; 2354 | Returns: string; 2355 | }; 2356 | hasnt_extension: { 2357 | Args: { '': unknown }; 2358 | Returns: string; 2359 | }; 2360 | hasnt_fk: { 2361 | Args: { '': unknown }; 2362 | Returns: string; 2363 | }; 2364 | hasnt_foreign_table: { 2365 | Args: { '': unknown }; 2366 | Returns: string; 2367 | }; 2368 | hasnt_function: { 2369 | Args: { '': unknown }; 2370 | Returns: string; 2371 | }; 2372 | hasnt_group: { 2373 | Args: { '': unknown }; 2374 | Returns: string; 2375 | }; 2376 | hasnt_inherited_tables: { 2377 | Args: { '': unknown }; 2378 | Returns: string; 2379 | }; 2380 | hasnt_language: { 2381 | Args: { '': unknown }; 2382 | Returns: string; 2383 | }; 2384 | hasnt_materialized_view: { 2385 | Args: { '': unknown }; 2386 | Returns: string; 2387 | }; 2388 | hasnt_opclass: { 2389 | Args: { '': unknown }; 2390 | Returns: string; 2391 | }; 2392 | hasnt_pk: { 2393 | Args: { '': unknown }; 2394 | Returns: string; 2395 | }; 2396 | hasnt_relation: { 2397 | Args: { '': unknown }; 2398 | Returns: string; 2399 | }; 2400 | hasnt_role: { 2401 | Args: { '': unknown }; 2402 | Returns: string; 2403 | }; 2404 | hasnt_schema: { 2405 | Args: { '': unknown }; 2406 | Returns: string; 2407 | }; 2408 | hasnt_sequence: { 2409 | Args: { '': unknown }; 2410 | Returns: string; 2411 | }; 2412 | hasnt_table: { 2413 | Args: { '': unknown }; 2414 | Returns: string; 2415 | }; 2416 | hasnt_tablespace: { 2417 | Args: { '': unknown }; 2418 | Returns: string; 2419 | }; 2420 | hasnt_type: { 2421 | Args: { '': unknown }; 2422 | Returns: string; 2423 | }; 2424 | hasnt_user: { 2425 | Args: { '': unknown }; 2426 | Returns: string; 2427 | }; 2428 | hasnt_view: { 2429 | Args: { '': unknown }; 2430 | Returns: string; 2431 | }; 2432 | in_todo: { 2433 | Args: Record; 2434 | Returns: boolean; 2435 | }; 2436 | index_is_primary: { 2437 | Args: { '': unknown }; 2438 | Returns: string; 2439 | }; 2440 | index_is_unique: { 2441 | Args: { '': unknown }; 2442 | Returns: string; 2443 | }; 2444 | instagram_channel_link: { 2445 | Args: { '': unknown }; 2446 | Returns: string; 2447 | }; 2448 | is_admin_of_organisation: { 2449 | Args: { v_organisation_id: string }; 2450 | Returns: boolean; 2451 | }; 2452 | is_aggregate: { 2453 | Args: { '': unknown }; 2454 | Returns: string; 2455 | }; 2456 | is_clustered: { 2457 | Args: { '': unknown }; 2458 | Returns: string; 2459 | }; 2460 | is_definer: { 2461 | Args: { '': unknown }; 2462 | Returns: string; 2463 | }; 2464 | is_e164_format: { 2465 | Args: { v_input: string }; 2466 | Returns: boolean; 2467 | }; 2468 | is_employee_of_organisation: { 2469 | Args: { v_organisation_id: string }; 2470 | Returns: boolean; 2471 | }; 2472 | is_empty: { 2473 | Args: { '': string }; 2474 | Returns: string; 2475 | }; 2476 | is_member_of_team: { 2477 | Args: { v_team_id: string }; 2478 | Returns: boolean; 2479 | }; 2480 | is_normal_function: { 2481 | Args: { '': unknown }; 2482 | Returns: string; 2483 | }; 2484 | is_partitioned: { 2485 | Args: { '': unknown }; 2486 | Returns: string; 2487 | }; 2488 | is_procedure: { 2489 | Args: { '': unknown }; 2490 | Returns: string; 2491 | }; 2492 | is_strict: { 2493 | Args: { '': unknown }; 2494 | Returns: string; 2495 | }; 2496 | is_superuser: { 2497 | Args: { '': unknown }; 2498 | Returns: string; 2499 | }; 2500 | is_valid_email: { 2501 | Args: { v_input: string }; 2502 | Returns: boolean; 2503 | }; 2504 | is_window: { 2505 | Args: { '': unknown }; 2506 | Returns: string; 2507 | }; 2508 | isnt_aggregate: { 2509 | Args: { '': unknown }; 2510 | Returns: string; 2511 | }; 2512 | isnt_definer: { 2513 | Args: { '': unknown }; 2514 | Returns: string; 2515 | }; 2516 | isnt_empty: { 2517 | Args: { '': string }; 2518 | Returns: string; 2519 | }; 2520 | isnt_normal_function: { 2521 | Args: { '': unknown }; 2522 | Returns: string; 2523 | }; 2524 | isnt_partitioned: { 2525 | Args: { '': unknown }; 2526 | Returns: string; 2527 | }; 2528 | isnt_procedure: { 2529 | Args: { '': unknown }; 2530 | Returns: string; 2531 | }; 2532 | isnt_strict: { 2533 | Args: { '': unknown }; 2534 | Returns: string; 2535 | }; 2536 | isnt_superuser: { 2537 | Args: { '': unknown }; 2538 | Returns: string; 2539 | }; 2540 | isnt_window: { 2541 | Args: { '': unknown }; 2542 | Returns: string; 2543 | }; 2544 | language_is_trusted: { 2545 | Args: { '': unknown }; 2546 | Returns: string; 2547 | }; 2548 | languages_are: { 2549 | Args: { '': unknown }; 2550 | Returns: string; 2551 | }; 2552 | lives_ok: { 2553 | Args: { '': string }; 2554 | Returns: string; 2555 | }; 2556 | logo: { 2557 | Args: { '': unknown }; 2558 | Returns: Json; 2559 | }; 2560 | make_api_request: { 2561 | Args: { v_path: string; v_body: Json; prefer_service_role: boolean }; 2562 | Returns: undefined; 2563 | }; 2564 | materialized_views_are: { 2565 | Args: { '': unknown }; 2566 | Returns: string; 2567 | }; 2568 | merge_contacts: { 2569 | Args: { a: string; b: string }; 2570 | Returns: unknown; 2571 | }; 2572 | move_conversation: { 2573 | Args: { v_conversation_id: string; v_inbox_id: string }; 2574 | Returns: unknown; 2575 | }; 2576 | move_conversations: { 2577 | Args: { v_conversation_ids: unknown; v_inbox_id: string }; 2578 | Returns: unknown; 2579 | }; 2580 | no_plan: { 2581 | Args: Record; 2582 | Returns: boolean; 2583 | }; 2584 | num_failed: { 2585 | Args: Record; 2586 | Returns: number; 2587 | }; 2588 | ok: { 2589 | Args: { '': boolean }; 2590 | Returns: string; 2591 | }; 2592 | opclasses_are: { 2593 | Args: { '': unknown }; 2594 | Returns: string; 2595 | }; 2596 | operators_are: { 2597 | Args: { '': unknown }; 2598 | Returns: string; 2599 | }; 2600 | organisation_id: { 2601 | Args: Record; 2602 | Returns: string; 2603 | }; 2604 | organisation_logo: { 2605 | Args: { '': unknown }; 2606 | Returns: Json; 2607 | }; 2608 | organisation_name: { 2609 | Args: { '': unknown }; 2610 | Returns: string; 2611 | }; 2612 | os_name: { 2613 | Args: Record; 2614 | Returns: string; 2615 | }; 2616 | pass: 2617 | | { 2618 | Args: { '': string }; 2619 | Returns: string; 2620 | } 2621 | | { 2622 | Args: Record; 2623 | Returns: string; 2624 | }; 2625 | pg_version: { 2626 | Args: Record; 2627 | Returns: string; 2628 | }; 2629 | pg_version_num: { 2630 | Args: Record; 2631 | Returns: number; 2632 | }; 2633 | pgtap_version: { 2634 | Args: Record; 2635 | Returns: number; 2636 | }; 2637 | plan: { 2638 | Args: { '': number }; 2639 | Returns: string; 2640 | }; 2641 | profile_image: { 2642 | Args: { '': unknown }; 2643 | Returns: Json; 2644 | }; 2645 | recipient_list: { 2646 | Args: { '': unknown }; 2647 | Returns: string; 2648 | }; 2649 | reply_to_conversation: { 2650 | Args: { 2651 | v_conversation_id: string; 2652 | v_message_input: unknown; 2653 | v_recipients_input: unknown; 2654 | }; 2655 | Returns: Record[]; 2656 | }; 2657 | resolve_event_entity: { 2658 | Args: { 2659 | v_type: Database['public']['Enums']['event_entity_type']; 2660 | v_id: string; 2661 | }; 2662 | Returns: Json; 2663 | }; 2664 | roles_are: { 2665 | Args: { '': unknown }; 2666 | Returns: string; 2667 | }; 2668 | runtests: 2669 | | { 2670 | Args: { '': unknown }; 2671 | Returns: string; 2672 | } 2673 | | { 2674 | Args: { '': string }; 2675 | Returns: string; 2676 | } 2677 | | { 2678 | Args: Record; 2679 | Returns: string; 2680 | }; 2681 | schemas_are: { 2682 | Args: { '': unknown }; 2683 | Returns: string; 2684 | }; 2685 | seed_organisation: { 2686 | Args: { v_domain: string }; 2687 | Returns: boolean; 2688 | }; 2689 | seen: { 2690 | Args: { '': unknown }; 2691 | Returns: boolean; 2692 | }; 2693 | send_employee_invite: { 2694 | Args: { v_employee_id: string }; 2695 | Returns: undefined; 2696 | }; 2697 | send_morning_briefing: { 2698 | Args: Record; 2699 | Returns: undefined; 2700 | }; 2701 | send_notification: { 2702 | Args: { v_payload: Json }; 2703 | Returns: undefined; 2704 | }; 2705 | sequences_are: { 2706 | Args: { '': unknown }; 2707 | Returns: string; 2708 | }; 2709 | session_time: { 2710 | Args: { '': unknown }; 2711 | Returns: number; 2712 | }; 2713 | single_file_object_for_entity: { 2714 | Args: { v_bucket_id: string; v_entity_id: string }; 2715 | Returns: Json; 2716 | }; 2717 | skip: 2718 | | { 2719 | Args: { why: string; how_many: number }; 2720 | Returns: string; 2721 | } 2722 | | { 2723 | Args: { '': string }; 2724 | Returns: string; 2725 | } 2726 | | { 2727 | Args: { '': number }; 2728 | Returns: string; 2729 | }; 2730 | sms_channel_link: { 2731 | Args: { '': unknown }; 2732 | Returns: string; 2733 | }; 2734 | source: { 2735 | Args: { '': unknown }; 2736 | Returns: Json; 2737 | }; 2738 | strip_html: { 2739 | Args: { v_input: string }; 2740 | Returns: string; 2741 | }; 2742 | strip_special_chars: { 2743 | Args: { v_input: string }; 2744 | Returns: string; 2745 | }; 2746 | submit_message: { 2747 | Args: { v_message_id: string }; 2748 | Returns: undefined; 2749 | }; 2750 | tables_are: { 2751 | Args: { '': unknown }; 2752 | Returns: string; 2753 | }; 2754 | tablespaces_are: { 2755 | Args: { '': unknown }; 2756 | Returns: string; 2757 | }; 2758 | target: { 2759 | Args: { '': unknown }; 2760 | Returns: Json; 2761 | }; 2762 | throws_ok: { 2763 | Args: { '': string }; 2764 | Returns: string; 2765 | }; 2766 | todo: 2767 | | { 2768 | Args: { why: string; how_many: number }; 2769 | Returns: boolean; 2770 | } 2771 | | { 2772 | Args: { how_many: number; why: string }; 2773 | Returns: boolean; 2774 | } 2775 | | { 2776 | Args: { why: string }; 2777 | Returns: boolean; 2778 | } 2779 | | { 2780 | Args: { how_many: number }; 2781 | Returns: boolean; 2782 | }; 2783 | todo_end: { 2784 | Args: Record; 2785 | Returns: boolean; 2786 | }; 2787 | todo_start: 2788 | | { 2789 | Args: { '': string }; 2790 | Returns: boolean; 2791 | } 2792 | | { 2793 | Args: Record; 2794 | Returns: boolean; 2795 | }; 2796 | trigger_notifications: { 2797 | Args: { v_notification_type: string; v_input: unknown }; 2798 | Returns: undefined; 2799 | }; 2800 | types_are: { 2801 | Args: { '': unknown }; 2802 | Returns: string; 2803 | }; 2804 | upsert_contact: { 2805 | Args: { 2806 | v_contact_input: unknown; 2807 | v_custom_fields_input: unknown; 2808 | v_opt_ins_input: unknown; 2809 | }; 2810 | Returns: Record[]; 2811 | }; 2812 | user_objects: { 2813 | Args: { user_id: string }; 2814 | Returns: unknown; 2815 | }; 2816 | users_are: { 2817 | Args: { '': unknown }; 2818 | Returns: string; 2819 | }; 2820 | utc_offset_minutes: { 2821 | Args: { '': unknown }; 2822 | Returns: number; 2823 | }; 2824 | uuid_from_filename: { 2825 | Args: { filename: string }; 2826 | Returns: string; 2827 | }; 2828 | uuid_from_path_level_1: { 2829 | Args: { filename: string }; 2830 | Returns: string; 2831 | }; 2832 | uuid_from_path_level_2: { 2833 | Args: { filename: string }; 2834 | Returns: string; 2835 | }; 2836 | uuid_from_path_level_3: { 2837 | Args: { filename: string }; 2838 | Returns: string; 2839 | }; 2840 | views_are: { 2841 | Args: { '': unknown }; 2842 | Returns: string; 2843 | }; 2844 | whatsapp_channel_link: { 2845 | Args: { '': unknown }; 2846 | Returns: string; 2847 | }; 2848 | whatsapp_status: { 2849 | Args: { '': unknown }; 2850 | Returns: Database['public']['Enums']['whatsapp_template_status']; 2851 | }; 2852 | }; 2853 | Enums: { 2854 | author_type: 'employee' | 'bot' | 'external'; 2855 | call_status: 2856 | | 'queued' 2857 | | 'ringing' 2858 | | 'in-progress' 2859 | | 'completed' 2860 | | 'busy' 2861 | | 'failed' 2862 | | 'no-answer'; 2863 | channel_status: 2864 | | 'draft' 2865 | | 'in-review' 2866 | | 'rejected' 2867 | | 'active' 2868 | | 'inactive'; 2869 | channel_type: 2870 | | 'email' 2871 | | 'sms' 2872 | | 'whatsapp' 2873 | | 'instagram' 2874 | | 'facebook' 2875 | | 'google_business_messaging'; 2876 | conversation_status: 'open' | 'closed' | 'archived'; 2877 | event_entity_type: 2878 | | 'employee' 2879 | | 'channel' 2880 | | 'comment' 2881 | | 'message' 2882 | | 'tag' 2883 | | 'recipient'; 2884 | event_type: 2885 | | 'assign' 2886 | | 'unassign' 2887 | | 'close' 2888 | | 'reopen' 2889 | | 'comment' 2890 | | 'mention' 2891 | | 'inbound' 2892 | | 'outbound' 2893 | | 'tag' 2894 | | 'untag' 2895 | | 'sending_error' 2896 | | 'message_bounce_error' 2897 | | 'submit' 2898 | | 'subject_change' 2899 | | 'submission_error' 2900 | | 'read' 2901 | | 'archive'; 2902 | field_type: 'string' | 'datetime' | 'boolean' | 'number' | 'date'; 2903 | inbox_level: 'full' | 'inbox_only'; 2904 | notification_channel: 'email' | 'push'; 2905 | opt_in_reason: 2906 | | 'legitimate_interest' 2907 | | 'contract_fulfillment' 2908 | | 'consent_granted'; 2909 | pricing_plan_interval: 'day' | 'week' | 'month' | 'year'; 2910 | pricing_type: 'one_time' | 'recurring'; 2911 | provider_status: 2912 | | 'draft' 2913 | | 'in-review' 2914 | | 'rejected' 2915 | | 'active' 2916 | | 'inactive'; 2917 | provider_type: 2918 | | 'twilio-regulatory-bundle' 2919 | | 'meta-account' 2920 | | 'google-account' 2921 | | 'nylas' 2922 | | '360dialog-whatsapp-business-account'; 2923 | recipient_role: 'from' | 'to' | 'cc' | 'bcc'; 2924 | recipient_status: 2925 | | 'sent' 2926 | | 'sending_error' 2927 | | 'bounce_error' 2928 | | 'submission_error' 2929 | | 'submitted' 2930 | | 'sending' 2931 | | 'read' 2932 | | 'draft'; 2933 | review_channel_type: 'google-my-business'; 2934 | subscription_status: 2935 | | 'trialing' 2936 | | 'active' 2937 | | 'canceled' 2938 | | 'incomplete' 2939 | | 'incomplete_expired' 2940 | | 'past_due' 2941 | | 'unpaid'; 2942 | template_category: 2943 | | 'ACCOUNT_UPDATE' 2944 | | 'AUTO_REPLY' 2945 | | 'PAYMENT_UPDATE' 2946 | | 'PERSONAL_FINANCE_UPDATE' 2947 | | 'SHIPPING_UPDATE' 2948 | | 'RESERVATION_UPDATE' 2949 | | 'ISSUE_RESOLUTION' 2950 | | 'APPOINTMENT_UPDATE' 2951 | | 'TRANSPORTATION_UPDATE' 2952 | | 'TICKET_UPDATE' 2953 | | 'ALERT_UPDATE' 2954 | | 'TRANSACTIONAL'; 2955 | whatsapp_template_status: 2956 | | 'requested' 2957 | | 'in_review' 2958 | | 'approved' 2959 | | 'rejected'; 2960 | }; 2961 | }; 2962 | } 2963 | --------------------------------------------------------------------------------