Merge branch 'main' of https://github.com/Dhravya/supermemory into new-ui
|
|
@ -6,7 +6,7 @@ const config = {
|
|||
"next/core-web-vitals",
|
||||
"plugin:@typescript-eslint/recommended-type-checked",
|
||||
"plugin:@typescript-eslint/stylistic-type-checked",
|
||||
"plugin:eslint-plugin-next-on-pages/recommended"
|
||||
"plugin:eslint-plugin-next-on-pages/recommended",
|
||||
],
|
||||
rules: {
|
||||
// These opinionated rules are enabled in stylistic-type-checked above.
|
||||
|
|
|
|||
8
.github/actions/buildextension/action.yml
vendored
|
|
@ -1,7 +1,7 @@
|
|||
name: 'Build Chrome extension'
|
||||
description: 'Builds the chrome extension into a ZIP'
|
||||
name: "Build Chrome extension"
|
||||
description: "Builds the chrome extension into a ZIP"
|
||||
runs:
|
||||
using: 'composite'
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
|
|
@ -26,4 +26,4 @@ runs:
|
|||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: extension-${{ github.sha }}
|
||||
path: apps/extension/dist/extension-${{ github.sha }}.zip
|
||||
path: apps/extension/dist/extension-${{ github.sha }}.zip
|
||||
|
|
|
|||
12
.github/workflows/build.yml
vendored
|
|
@ -4,15 +4,15 @@ on:
|
|||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'apps/web/**'
|
||||
- 'apps/extension/**'
|
||||
- 'apps/cf-ai-backend/**'
|
||||
- "apps/web/**"
|
||||
- "apps/extension/**"
|
||||
- "apps/cf-ai-backend/**"
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'apps/web/**'
|
||||
- 'apps/extension/**'
|
||||
- 'apps/cf-ai-backend/**'
|
||||
- "apps/web/**"
|
||||
- "apps/extension/**"
|
||||
- "apps/cf-ai-backend/**"
|
||||
|
||||
jobs:
|
||||
build-extension:
|
||||
|
|
|
|||
2
.github/workflows/release.yml
vendored
|
|
@ -2,7 +2,7 @@ name: Upload to Web Store
|
|||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
- "*"
|
||||
jobs:
|
||||
build-extension:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
1
.gitignore
vendored
|
|
@ -5,6 +5,7 @@
|
|||
.next
|
||||
.wrangler
|
||||
drizzle/
|
||||
dist/
|
||||
|
||||
node_modules
|
||||
|
||||
|
|
|
|||
0
.husky/_/husky.sh
Normal file
3
.husky/_/pre-commit
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
. "$(dirname "$0")/husky.sh"
|
||||
bun run lint-staged
|
||||
1
.prettierignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
**/.gitignore
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"name": "cf-ai-backend",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"deploy": "wrangler deploy",
|
||||
"dev": "wrangler dev",
|
||||
"start": "wrangler dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20240222.0",
|
||||
"typescript": "^5.0.4",
|
||||
"wrangler": "^3.0.0"
|
||||
}
|
||||
"name": "cf-ai-backend",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"deploy": "wrangler deploy",
|
||||
"dev": "wrangler dev",
|
||||
"start": "wrangler dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20240222.0",
|
||||
"typescript": "^5.0.4",
|
||||
"wrangler": "^3.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
789
apps/cf-ai-backend/pnpm-lock.yaml
generated
Normal file
|
|
@ -0,0 +1,789 @@
|
|||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
devDependencies:
|
||||
'@cloudflare/workers-types':
|
||||
specifier: ^4.20240222.0
|
||||
version: 4.20240222.0
|
||||
typescript:
|
||||
specifier: ^5.0.4
|
||||
version: 5.3.3
|
||||
wrangler:
|
||||
specifier: ^3.0.0
|
||||
version: 3.29.0(@cloudflare/workers-types@4.20240222.0)
|
||||
|
||||
packages:
|
||||
/@cloudflare/kv-asset-handler@0.3.1:
|
||||
resolution: { integrity: sha512-lKN2XCfKCmpKb86a1tl4GIwsJYDy9TGuwjhDELLmpKygQhw8X2xR4dusgpC5Tg7q1pB96Eb0rBo81kxSILQMwA== }
|
||||
dependencies:
|
||||
mime: 3.0.0
|
||||
dev: true
|
||||
|
||||
/@cloudflare/workerd-darwin-64@1.20240208.0:
|
||||
resolution: { integrity: sha512-64qjsCUz6VtjXnUex5D6dWoJDuUBRw1ps2TEVH9wGJ4ubiLVUxKhj3bzkVy0RoJ8FhaCKzJWWRyTo4yc192UTA== }
|
||||
engines: { node: '>=16' }
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cloudflare/workerd-darwin-arm64@1.20240208.0:
|
||||
resolution: { integrity: sha512-eVQrAV200LhwLY6JZLx3l2lDrjsTC86lqnvH+RSeM43bAcdneC6lVfykHnTaOTgYFvYQbqRkn9ICWxXj1V9L5g== }
|
||||
engines: { node: '>=16' }
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cloudflare/workerd-linux-64@1.20240208.0:
|
||||
resolution: { integrity: sha512-ivZ2UuCvi44j8JZ++XlQzSYajt5ptvAdwlh3WPpCcygtHXEh6SVo8QXEUOXhPbv861C0HZMYxLCaLqlpQDWB8g== }
|
||||
engines: { node: '>=16' }
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cloudflare/workerd-linux-arm64@1.20240208.0:
|
||||
resolution: { integrity: sha512-aLfvl9kXQKbM7aLvfL0HbOt5VEgv15mEZGyFKyDldJ8+nOXH6nYPma1ccwF8BHmu8otHc420eyPr2xPKhLSJnw== }
|
||||
engines: { node: '>=16' }
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cloudflare/workerd-windows-64@1.20240208.0:
|
||||
resolution: { integrity: sha512-Y6KMukWnorsSmPx6d82IuJ4SU8sX1+2y+w1uFJ76sucSgXqUAN1fmjG+EyzRVbcbsxRGBCD9c1Pn8T1amMLEYA== }
|
||||
engines: { node: '>=16' }
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@cloudflare/workers-types@4.20240222.0:
|
||||
resolution: { integrity: sha512-luO0BdK3rLlCv3B240+cTrfqm+XSbHtpk+88aJtGwzyVK9QF/Xz8lBgE/oZZLN8nCTmOvxAZnszyxUuZ8GP8Cg== }
|
||||
dev: true
|
||||
|
||||
/@cspotcode/source-map-support@0.8.1:
|
||||
resolution: { integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== }
|
||||
engines: { node: '>=12' }
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.9
|
||||
dev: true
|
||||
|
||||
/@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19):
|
||||
resolution: { integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw== }
|
||||
peerDependencies:
|
||||
esbuild: '*'
|
||||
dependencies:
|
||||
esbuild: 0.17.19
|
||||
dev: true
|
||||
|
||||
/@esbuild-plugins/node-modules-polyfill@0.2.2(esbuild@0.17.19):
|
||||
resolution: { integrity: sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA== }
|
||||
peerDependencies:
|
||||
esbuild: '*'
|
||||
dependencies:
|
||||
esbuild: 0.17.19
|
||||
escape-string-regexp: 4.0.0
|
||||
rollup-plugin-node-polyfills: 0.2.1
|
||||
dev: true
|
||||
|
||||
/@esbuild/android-arm64@0.17.19:
|
||||
resolution: { integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/android-arm@0.17.19:
|
||||
resolution: { integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/android-x64@0.17.19:
|
||||
resolution: { integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/darwin-arm64@0.17.19:
|
||||
resolution: { integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/darwin-x64@0.17.19:
|
||||
resolution: { integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/freebsd-arm64@0.17.19:
|
||||
resolution: { integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/freebsd-x64@0.17.19:
|
||||
resolution: { integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-arm64@0.17.19:
|
||||
resolution: { integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-arm@0.17.19:
|
||||
resolution: { integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-ia32@0.17.19:
|
||||
resolution: { integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-loong64@0.17.19:
|
||||
resolution: { integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-mips64el@0.17.19:
|
||||
resolution: { integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-ppc64@0.17.19:
|
||||
resolution: { integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-riscv64@0.17.19:
|
||||
resolution: { integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-s390x@0.17.19:
|
||||
resolution: { integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-x64@0.17.19:
|
||||
resolution: { integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/netbsd-x64@0.17.19:
|
||||
resolution: { integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/openbsd-x64@0.17.19:
|
||||
resolution: { integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/sunos-x64@0.17.19:
|
||||
resolution: { integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-arm64@0.17.19:
|
||||
resolution: { integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-ia32@0.17.19:
|
||||
resolution: { integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-x64@0.17.19:
|
||||
resolution: { integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA== }
|
||||
engines: { node: '>=12' }
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@fastify/busboy@2.1.0:
|
||||
resolution: { integrity: sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA== }
|
||||
engines: { node: '>=14' }
|
||||
dev: true
|
||||
|
||||
/@jridgewell/resolve-uri@3.1.2:
|
||||
resolution: { integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== }
|
||||
engines: { node: '>=6.0.0' }
|
||||
dev: true
|
||||
|
||||
/@jridgewell/sourcemap-codec@1.4.15:
|
||||
resolution: { integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== }
|
||||
dev: true
|
||||
|
||||
/@jridgewell/trace-mapping@0.3.9:
|
||||
resolution: { integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== }
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
dev: true
|
||||
|
||||
/@types/node-forge@1.3.11:
|
||||
resolution: { integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ== }
|
||||
dependencies:
|
||||
'@types/node': 20.11.20
|
||||
dev: true
|
||||
|
||||
/@types/node@20.11.20:
|
||||
resolution: { integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg== }
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
dev: true
|
||||
|
||||
/acorn-walk@8.3.2:
|
||||
resolution: { integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== }
|
||||
engines: { node: '>=0.4.0' }
|
||||
dev: true
|
||||
|
||||
/acorn@8.11.3:
|
||||
resolution: { integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== }
|
||||
engines: { node: '>=0.4.0' }
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/anymatch@3.1.3:
|
||||
resolution: { integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== }
|
||||
engines: { node: '>= 8' }
|
||||
dependencies:
|
||||
normalize-path: 3.0.0
|
||||
picomatch: 2.3.1
|
||||
dev: true
|
||||
|
||||
/as-table@1.0.55:
|
||||
resolution: { integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ== }
|
||||
dependencies:
|
||||
printable-characters: 1.0.42
|
||||
dev: true
|
||||
|
||||
/binary-extensions@2.2.0:
|
||||
resolution: { integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== }
|
||||
engines: { node: '>=8' }
|
||||
dev: true
|
||||
|
||||
/blake3-wasm@2.1.5:
|
||||
resolution: { integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g== }
|
||||
dev: true
|
||||
|
||||
/braces@3.0.2:
|
||||
resolution: { integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== }
|
||||
engines: { node: '>=8' }
|
||||
dependencies:
|
||||
fill-range: 7.0.1
|
||||
dev: true
|
||||
|
||||
/capnp-ts@0.7.0:
|
||||
resolution: { integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g== }
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
tslib: 2.6.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/chokidar@3.6.0:
|
||||
resolution: { integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== }
|
||||
engines: { node: '>= 8.10.0' }
|
||||
dependencies:
|
||||
anymatch: 3.1.3
|
||||
braces: 3.0.2
|
||||
glob-parent: 5.1.2
|
||||
is-binary-path: 2.1.0
|
||||
is-glob: 4.0.3
|
||||
normalize-path: 3.0.0
|
||||
readdirp: 3.6.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
dev: true
|
||||
|
||||
/cookie@0.5.0:
|
||||
resolution: { integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== }
|
||||
engines: { node: '>= 0.6' }
|
||||
dev: true
|
||||
|
||||
/data-uri-to-buffer@2.0.2:
|
||||
resolution: { integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA== }
|
||||
dev: true
|
||||
|
||||
/debug@4.3.4:
|
||||
resolution: { integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== }
|
||||
engines: { node: '>=6.0' }
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
dev: true
|
||||
|
||||
/esbuild@0.17.19:
|
||||
resolution: { integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw== }
|
||||
engines: { node: '>=12' }
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
'@esbuild/android-arm': 0.17.19
|
||||
'@esbuild/android-arm64': 0.17.19
|
||||
'@esbuild/android-x64': 0.17.19
|
||||
'@esbuild/darwin-arm64': 0.17.19
|
||||
'@esbuild/darwin-x64': 0.17.19
|
||||
'@esbuild/freebsd-arm64': 0.17.19
|
||||
'@esbuild/freebsd-x64': 0.17.19
|
||||
'@esbuild/linux-arm': 0.17.19
|
||||
'@esbuild/linux-arm64': 0.17.19
|
||||
'@esbuild/linux-ia32': 0.17.19
|
||||
'@esbuild/linux-loong64': 0.17.19
|
||||
'@esbuild/linux-mips64el': 0.17.19
|
||||
'@esbuild/linux-ppc64': 0.17.19
|
||||
'@esbuild/linux-riscv64': 0.17.19
|
||||
'@esbuild/linux-s390x': 0.17.19
|
||||
'@esbuild/linux-x64': 0.17.19
|
||||
'@esbuild/netbsd-x64': 0.17.19
|
||||
'@esbuild/openbsd-x64': 0.17.19
|
||||
'@esbuild/sunos-x64': 0.17.19
|
||||
'@esbuild/win32-arm64': 0.17.19
|
||||
'@esbuild/win32-ia32': 0.17.19
|
||||
'@esbuild/win32-x64': 0.17.19
|
||||
dev: true
|
||||
|
||||
/escape-string-regexp@4.0.0:
|
||||
resolution: { integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== }
|
||||
engines: { node: '>=10' }
|
||||
dev: true
|
||||
|
||||
/estree-walker@0.6.1:
|
||||
resolution: { integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== }
|
||||
dev: true
|
||||
|
||||
/exit-hook@2.2.1:
|
||||
resolution: { integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw== }
|
||||
engines: { node: '>=6' }
|
||||
dev: true
|
||||
|
||||
/fill-range@7.0.1:
|
||||
resolution: { integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== }
|
||||
engines: { node: '>=8' }
|
||||
dependencies:
|
||||
to-regex-range: 5.0.1
|
||||
dev: true
|
||||
|
||||
/fsevents@2.3.3:
|
||||
resolution: { integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== }
|
||||
engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 }
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/function-bind@1.1.2:
|
||||
resolution: { integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== }
|
||||
dev: true
|
||||
|
||||
/get-source@2.0.12:
|
||||
resolution: { integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w== }
|
||||
dependencies:
|
||||
data-uri-to-buffer: 2.0.2
|
||||
source-map: 0.6.1
|
||||
dev: true
|
||||
|
||||
/glob-parent@5.1.2:
|
||||
resolution: { integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== }
|
||||
engines: { node: '>= 6' }
|
||||
dependencies:
|
||||
is-glob: 4.0.3
|
||||
dev: true
|
||||
|
||||
/glob-to-regexp@0.4.1:
|
||||
resolution: { integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== }
|
||||
dev: true
|
||||
|
||||
/hasown@2.0.1:
|
||||
resolution: { integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA== }
|
||||
engines: { node: '>= 0.4' }
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
dev: true
|
||||
|
||||
/is-binary-path@2.1.0:
|
||||
resolution: { integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== }
|
||||
engines: { node: '>=8' }
|
||||
dependencies:
|
||||
binary-extensions: 2.2.0
|
||||
dev: true
|
||||
|
||||
/is-core-module@2.13.1:
|
||||
resolution: { integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== }
|
||||
dependencies:
|
||||
hasown: 2.0.1
|
||||
dev: true
|
||||
|
||||
/is-extglob@2.1.1:
|
||||
resolution: { integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== }
|
||||
engines: { node: '>=0.10.0' }
|
||||
dev: true
|
||||
|
||||
/is-glob@4.0.3:
|
||||
resolution: { integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== }
|
||||
engines: { node: '>=0.10.0' }
|
||||
dependencies:
|
||||
is-extglob: 2.1.1
|
||||
dev: true
|
||||
|
||||
/is-number@7.0.0:
|
||||
resolution: { integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== }
|
||||
engines: { node: '>=0.12.0' }
|
||||
dev: true
|
||||
|
||||
/magic-string@0.25.9:
|
||||
resolution: { integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== }
|
||||
dependencies:
|
||||
sourcemap-codec: 1.4.8
|
||||
dev: true
|
||||
|
||||
/mime@3.0.0:
|
||||
resolution: { integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== }
|
||||
engines: { node: '>=10.0.0' }
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/miniflare@3.20240208.0:
|
||||
resolution: { integrity: sha512-NnP3MQFh2pV7iETNmJzSlMBF/KhRA+XT4A7JLCfxunadQSPbTMMgbsZo9EfLloMwHMUhZGNVot3Pvh+VnT2joQ== }
|
||||
engines: { node: '>=16.13' }
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
acorn: 8.11.3
|
||||
acorn-walk: 8.3.2
|
||||
capnp-ts: 0.7.0
|
||||
exit-hook: 2.2.1
|
||||
glob-to-regexp: 0.4.1
|
||||
stoppable: 1.1.0
|
||||
undici: 5.28.3
|
||||
workerd: 1.20240208.0
|
||||
ws: 8.16.0
|
||||
youch: 3.3.3
|
||||
zod: 3.22.4
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/ms@2.1.2:
|
||||
resolution: { integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== }
|
||||
dev: true
|
||||
|
||||
/mustache@4.2.0:
|
||||
resolution: { integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== }
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/nanoid@3.3.7:
|
||||
resolution: { integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== }
|
||||
engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 }
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/node-forge@1.3.1:
|
||||
resolution: { integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== }
|
||||
engines: { node: '>= 6.13.0' }
|
||||
dev: true
|
||||
|
||||
/normalize-path@3.0.0:
|
||||
resolution: { integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== }
|
||||
engines: { node: '>=0.10.0' }
|
||||
dev: true
|
||||
|
||||
/path-parse@1.0.7:
|
||||
resolution: { integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== }
|
||||
dev: true
|
||||
|
||||
/path-to-regexp@6.2.1:
|
||||
resolution: { integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw== }
|
||||
dev: true
|
||||
|
||||
/picomatch@2.3.1:
|
||||
resolution: { integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== }
|
||||
engines: { node: '>=8.6' }
|
||||
dev: true
|
||||
|
||||
/printable-characters@1.0.42:
|
||||
resolution: { integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ== }
|
||||
dev: true
|
||||
|
||||
/readdirp@3.6.0:
|
||||
resolution: { integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== }
|
||||
engines: { node: '>=8.10.0' }
|
||||
dependencies:
|
||||
picomatch: 2.3.1
|
||||
dev: true
|
||||
|
||||
/resolve.exports@2.0.2:
|
||||
resolution: { integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== }
|
||||
engines: { node: '>=10' }
|
||||
dev: true
|
||||
|
||||
/resolve@1.22.8:
|
||||
resolution: { integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== }
|
||||
hasBin: true
|
||||
dependencies:
|
||||
is-core-module: 2.13.1
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
dev: true
|
||||
|
||||
/rollup-plugin-inject@3.0.2:
|
||||
resolution: { integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w== }
|
||||
deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.
|
||||
dependencies:
|
||||
estree-walker: 0.6.1
|
||||
magic-string: 0.25.9
|
||||
rollup-pluginutils: 2.8.2
|
||||
dev: true
|
||||
|
||||
/rollup-plugin-node-polyfills@0.2.1:
|
||||
resolution: { integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA== }
|
||||
dependencies:
|
||||
rollup-plugin-inject: 3.0.2
|
||||
dev: true
|
||||
|
||||
/rollup-pluginutils@2.8.2:
|
||||
resolution: { integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== }
|
||||
dependencies:
|
||||
estree-walker: 0.6.1
|
||||
dev: true
|
||||
|
||||
/selfsigned@2.4.1:
|
||||
resolution: { integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q== }
|
||||
engines: { node: '>=10' }
|
||||
dependencies:
|
||||
'@types/node-forge': 1.3.11
|
||||
node-forge: 1.3.1
|
||||
dev: true
|
||||
|
||||
/source-map@0.6.1:
|
||||
resolution: { integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== }
|
||||
engines: { node: '>=0.10.0' }
|
||||
dev: true
|
||||
|
||||
/sourcemap-codec@1.4.8:
|
||||
resolution: { integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== }
|
||||
deprecated: Please use @jridgewell/sourcemap-codec instead
|
||||
dev: true
|
||||
|
||||
/stacktracey@2.1.8:
|
||||
resolution: { integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw== }
|
||||
dependencies:
|
||||
as-table: 1.0.55
|
||||
get-source: 2.0.12
|
||||
dev: true
|
||||
|
||||
/stoppable@1.1.0:
|
||||
resolution: { integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw== }
|
||||
engines: { node: '>=4', npm: '>=6' }
|
||||
dev: true
|
||||
|
||||
/supports-preserve-symlinks-flag@1.0.0:
|
||||
resolution: { integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== }
|
||||
engines: { node: '>= 0.4' }
|
||||
dev: true
|
||||
|
||||
/to-regex-range@5.0.1:
|
||||
resolution: { integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== }
|
||||
engines: { node: '>=8.0' }
|
||||
dependencies:
|
||||
is-number: 7.0.0
|
||||
dev: true
|
||||
|
||||
/tslib@2.6.2:
|
||||
resolution: { integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== }
|
||||
dev: true
|
||||
|
||||
/typescript@5.3.3:
|
||||
resolution: { integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== }
|
||||
engines: { node: '>=14.17' }
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/undici-types@5.26.5:
|
||||
resolution: { integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== }
|
||||
dev: true
|
||||
|
||||
/undici@5.28.3:
|
||||
resolution: { integrity: sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA== }
|
||||
engines: { node: '>=14.0' }
|
||||
dependencies:
|
||||
'@fastify/busboy': 2.1.0
|
||||
dev: true
|
||||
|
||||
/workerd@1.20240208.0:
|
||||
resolution: { integrity: sha512-edFdwHU95Ww2SmjBvBJhbc7hhVXMEo6Y7qqSWCl6W9lGScTlCMCXd4AU3f/EGJ3P++FC+CWqu+XuAywebbKF2Q== }
|
||||
engines: { node: '>=16' }
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
'@cloudflare/workerd-darwin-64': 1.20240208.0
|
||||
'@cloudflare/workerd-darwin-arm64': 1.20240208.0
|
||||
'@cloudflare/workerd-linux-64': 1.20240208.0
|
||||
'@cloudflare/workerd-linux-arm64': 1.20240208.0
|
||||
'@cloudflare/workerd-windows-64': 1.20240208.0
|
||||
dev: true
|
||||
|
||||
/wrangler@3.29.0(@cloudflare/workers-types@4.20240222.0):
|
||||
resolution: { integrity: sha512-VXUUltM0/fxCF20Z3tH39zpnykDJNPH2lMWI5wA0VmRpuKG0Gffjj5lU2vJaI/PfUCo3q4JErxWcgLezBGnFyA== }
|
||||
engines: { node: '>=16.17.0' }
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@cloudflare/workers-types': ^4.20230914.0
|
||||
peerDependenciesMeta:
|
||||
'@cloudflare/workers-types':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@cloudflare/kv-asset-handler': 0.3.1
|
||||
'@cloudflare/workers-types': 4.20240222.0
|
||||
'@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19)
|
||||
'@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19)
|
||||
blake3-wasm: 2.1.5
|
||||
chokidar: 3.6.0
|
||||
esbuild: 0.17.19
|
||||
miniflare: 3.20240208.0
|
||||
nanoid: 3.3.7
|
||||
path-to-regexp: 6.2.1
|
||||
resolve: 1.22.8
|
||||
resolve.exports: 2.0.2
|
||||
selfsigned: 2.4.1
|
||||
source-map: 0.6.1
|
||||
xxhash-wasm: 1.0.2
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/ws@8.16.0:
|
||||
resolution: { integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== }
|
||||
engines: { node: '>=10.0.0' }
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
dev: true
|
||||
|
||||
/xxhash-wasm@1.0.2:
|
||||
resolution: { integrity: sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A== }
|
||||
dev: true
|
||||
|
||||
/youch@3.3.3:
|
||||
resolution: { integrity: sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA== }
|
||||
dependencies:
|
||||
cookie: 0.5.0
|
||||
mustache: 4.2.0
|
||||
stacktracey: 2.1.8
|
||||
dev: true
|
||||
|
||||
/zod@3.22.4:
|
||||
resolution: { integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg== }
|
||||
dev: true
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { AiTextGenerationOutput } from "@cloudflare/ai/dist/ai/tasks/text-generation";
|
||||
import { AiTextGenerationOutput } from '@cloudflare/ai/dist/ai/tasks/text-generation';
|
||||
|
||||
interface OpenAIEmbeddingsParams {
|
||||
apiKey: string;
|
||||
|
|
@ -15,7 +15,7 @@ export class OpenAIEmbeddings {
|
|||
}
|
||||
|
||||
async embedDocuments(texts: string[]): Promise<number[][]> {
|
||||
const responses = await Promise.all(texts.map(text => this.embedQuery(text)));
|
||||
const responses = await Promise.all(texts.map((text) => this.embedQuery(text)));
|
||||
return responses;
|
||||
}
|
||||
|
||||
|
|
@ -24,18 +24,18 @@ export class OpenAIEmbeddings {
|
|||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${this.apiKey}`
|
||||
Authorization: `Bearer ${this.apiKey}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
input: text,
|
||||
model: this.modelName
|
||||
})
|
||||
model: this.modelName,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json() as {
|
||||
const data = (await response.json()) as {
|
||||
data: {
|
||||
embedding: number[]
|
||||
}[]
|
||||
embedding: number[];
|
||||
}[];
|
||||
};
|
||||
|
||||
return data.data[0].embedding;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
import type {
|
||||
VectorizeIndex,
|
||||
Fetcher,
|
||||
Request,
|
||||
} from "@cloudflare/workers-types";
|
||||
import type { VectorizeIndex, Fetcher, Request } from '@cloudflare/workers-types';
|
||||
|
||||
import {
|
||||
CloudflareVectorizeStore,
|
||||
} from "@langchain/cloudflare";
|
||||
import { OpenAIEmbeddings } from "./OpenAIEmbedder";
|
||||
import { GoogleGenerativeAI } from "@google/generative-ai";
|
||||
import routeMap from "./routes";
|
||||
import { CloudflareVectorizeStore } from '@langchain/cloudflare';
|
||||
import { OpenAIEmbeddings } from './OpenAIEmbedder';
|
||||
import { GoogleGenerativeAI } from '@google/generative-ai';
|
||||
import routeMap from './routes';
|
||||
|
||||
function isAuthorized(request: Request, env: Env): boolean {
|
||||
return request.headers.get('X-Custom-Auth-Key') === env.SECURITY_KEY;
|
||||
|
|
@ -32,7 +26,7 @@ export default {
|
|||
|
||||
const genAI = new GoogleGenerativeAI(env.GOOGLE_AI_API_KEY);
|
||||
|
||||
const model = genAI.getGenerativeModel({ model: "gemini-pro" });
|
||||
const model = genAI.getGenerativeModel({ model: 'gemini-pro' });
|
||||
|
||||
const url = new URL(request.url);
|
||||
const path = url.pathname;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
import { CloudflareVectorizeStore } from '@langchain/cloudflare';
|
||||
import * as apiAdd from './routes/add';
|
||||
import * as apiQuery from "./routes/query"
|
||||
import * as apiAsk from "./routes/ask"
|
||||
import * as apiChat from "./routes/chat"
|
||||
import * as apiQuery from './routes/query';
|
||||
import * as apiAsk from './routes/ask';
|
||||
import * as apiChat from './routes/chat';
|
||||
import { OpenAIEmbeddings } from './OpenAIEmbedder';
|
||||
import { GenerativeModel } from '@google/generative-ai';
|
||||
import { Request } from '@cloudflare/workers-types';
|
||||
|
||||
|
||||
type RouteHandler = (request: Request, store: CloudflareVectorizeStore, embeddings: OpenAIEmbeddings, model: GenerativeModel, env: Env, ctx?: ExecutionContext) => Promise<Response>;
|
||||
type RouteHandler = (
|
||||
request: Request,
|
||||
store: CloudflareVectorizeStore,
|
||||
embeddings: OpenAIEmbeddings,
|
||||
model: GenerativeModel,
|
||||
env: Env,
|
||||
ctx?: ExecutionContext,
|
||||
) => Promise<Response>;
|
||||
|
||||
const routeMap = new Map<string, Record<string, RouteHandler>>();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,36 +1,38 @@
|
|||
import { Request } from "@cloudflare/workers-types";
|
||||
import { type CloudflareVectorizeStore } from "@langchain/cloudflare";
|
||||
import { Request } from '@cloudflare/workers-types';
|
||||
import { type CloudflareVectorizeStore } from '@langchain/cloudflare';
|
||||
|
||||
export async function POST(request: Request, store: CloudflareVectorizeStore) {
|
||||
const body = await request.json() as {
|
||||
pageContent: string,
|
||||
title?: string,
|
||||
description?: string,
|
||||
space?: string,
|
||||
url: string,
|
||||
user: string
|
||||
const body = (await request.json()) as {
|
||||
pageContent: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
space?: string;
|
||||
url: string;
|
||||
user: string;
|
||||
};
|
||||
|
||||
if (!body.pageContent || !body.url) {
|
||||
return new Response(JSON.stringify({ message: "Invalid Page Content" }), { status: 400 });
|
||||
return new Response(JSON.stringify({ message: 'Invalid Page Content' }), { status: 400 });
|
||||
}
|
||||
const newPageContent = `Title: ${body.title}\nDescription: ${body.description}\nURL: ${body.url}\nContent: ${body.pageContent}`
|
||||
const newPageContent = `Title: ${body.title}\nDescription: ${body.description}\nURL: ${body.url}\nContent: ${body.pageContent}`;
|
||||
|
||||
|
||||
await store.addDocuments([
|
||||
{
|
||||
pageContent: newPageContent,
|
||||
metadata: {
|
||||
title: body.title ?? "",
|
||||
description: body.description ?? "",
|
||||
space: body.space ?? "",
|
||||
url: body.url,
|
||||
user: body.user,
|
||||
await store.addDocuments(
|
||||
[
|
||||
{
|
||||
pageContent: newPageContent,
|
||||
metadata: {
|
||||
title: body.title ?? '',
|
||||
description: body.description ?? '',
|
||||
space: body.space ?? '',
|
||||
url: body.url,
|
||||
user: body.user,
|
||||
},
|
||||
},
|
||||
],
|
||||
{
|
||||
ids: [`${body.url}-${body.user}`],
|
||||
},
|
||||
], {
|
||||
ids: [`${body.url}`]
|
||||
})
|
||||
);
|
||||
|
||||
return new Response(JSON.stringify({ message: "Document Added" }), { status: 200 });
|
||||
return new Response(JSON.stringify({ message: 'Document Added' }), { status: 200 });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { GenerativeModel } from "@google/generative-ai";
|
||||
import { OpenAIEmbeddings } from "../OpenAIEmbedder";
|
||||
import { CloudflareVectorizeStore } from "@langchain/cloudflare";
|
||||
import { Request } from "@cloudflare/workers-types";
|
||||
import { GenerativeModel } from '@google/generative-ai';
|
||||
import { OpenAIEmbeddings } from '../OpenAIEmbedder';
|
||||
import { CloudflareVectorizeStore } from '@langchain/cloudflare';
|
||||
import { Request } from '@cloudflare/workers-types';
|
||||
|
||||
export async function POST(request: Request, _: CloudflareVectorizeStore, embeddings: OpenAIEmbeddings, model: GenerativeModel, env?: Env) {
|
||||
const body = await request.json() as {
|
||||
query: string
|
||||
const body = (await request.json()) as {
|
||||
query: string;
|
||||
};
|
||||
|
||||
if (!body.query) {
|
||||
return new Response(JSON.stringify({ message: "Invalid Page Content" }), { status: 400 });
|
||||
return new Response(JSON.stringify({ message: 'Invalid Page Content' }), { status: 400 });
|
||||
}
|
||||
|
||||
const prompt = `You are an agent that answers a question based on the query. don't say 'based on the context'.\n\n Context:\n${body.query} \nAnswer this question based on the context. Question: ${body.query}\nAnswer:`
|
||||
const prompt = `You are an agent that answers a question based on the query. don't say 'based on the context'.\n\n Context:\n${body.query} \nAnswer this question based on the context. Question: ${body.query}\nAnswer:`;
|
||||
const output = await model.generateContentStream(prompt);
|
||||
|
||||
const response = new Response(
|
||||
|
|
@ -22,14 +22,14 @@ export async function POST(request: Request, _: CloudflareVectorizeStore, embedd
|
|||
for await (const chunk of output.stream) {
|
||||
const chunkText = await chunk.text();
|
||||
console.log(chunkText);
|
||||
const encodedChunk = converter.encode("data: " + JSON.stringify({ "response": chunkText }) + "\n\n");
|
||||
const encodedChunk = converter.encode('data: ' + JSON.stringify({ response: chunkText }) + '\n\n');
|
||||
controller.enqueue(encodedChunk);
|
||||
}
|
||||
const doneChunk = converter.encode("data: [DONE]");
|
||||
const doneChunk = converter.encode('data: [DONE]');
|
||||
controller.enqueue(doneChunk);
|
||||
controller.close();
|
||||
}
|
||||
})
|
||||
},
|
||||
}),
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,28 @@
|
|||
import { Content, GenerativeModel } from "@google/generative-ai";
|
||||
import { OpenAIEmbeddings } from "../OpenAIEmbedder";
|
||||
import { CloudflareVectorizeStore } from "@langchain/cloudflare";
|
||||
import { Request } from "@cloudflare/workers-types";
|
||||
import { Content, GenerativeModel } from '@google/generative-ai';
|
||||
import { OpenAIEmbeddings } from '../OpenAIEmbedder';
|
||||
import { CloudflareVectorizeStore } from '@langchain/cloudflare';
|
||||
import { Request } from '@cloudflare/workers-types';
|
||||
|
||||
export async function POST(request: Request, _: CloudflareVectorizeStore, embeddings: OpenAIEmbeddings, model: GenerativeModel, env?: Env) {
|
||||
const queryparams = new URL(request.url).searchParams;
|
||||
const query = queryparams.get("q");
|
||||
const topK = parseInt(queryparams.get("topK") ?? "5");
|
||||
const user = queryparams.get("user")
|
||||
const spaces = queryparams.get("spaces")
|
||||
const spacesArray = spaces ? spaces.split(",") : undefined
|
||||
const query = queryparams.get('q');
|
||||
const topK = parseInt(queryparams.get('topK') ?? '5');
|
||||
const user = queryparams.get('user');
|
||||
const spaces = queryparams.get('spaces');
|
||||
const spacesArray = spaces ? spaces.split(',') : undefined;
|
||||
|
||||
const sourcesOnly = (queryparams.get("sourcesOnly") ?? "false")
|
||||
const sourcesOnly = queryparams.get('sourcesOnly') ?? 'false';
|
||||
|
||||
if (!user) {
|
||||
return new Response(JSON.stringify({ message: "Invalid User" }), { status: 400 });
|
||||
return new Response(JSON.stringify({ message: 'Invalid User' }), { status: 400 });
|
||||
}
|
||||
|
||||
if (!query) {
|
||||
return new Response(JSON.stringify({ message: "Invalid Query" }), { status: 400 });
|
||||
return new Response(JSON.stringify({ message: 'Invalid Query' }), { status: 400 });
|
||||
}
|
||||
const filter: VectorizeVectorMetadataFilter = {
|
||||
user
|
||||
}
|
||||
user,
|
||||
};
|
||||
|
||||
const responses: VectorizeMatches = { matches: [], count: 0 };
|
||||
|
||||
|
|
@ -34,12 +34,12 @@ export async function POST(request: Request, _: CloudflareVectorizeStore, embedd
|
|||
|
||||
const resp = await env!.VECTORIZE_INDEX.query(queryAsVector, {
|
||||
topK,
|
||||
filter
|
||||
filter,
|
||||
});
|
||||
|
||||
if (resp.count > 0) {
|
||||
responses.matches.push(...resp.matches)
|
||||
responses.count += resp.count
|
||||
responses.matches.push(...resp.matches);
|
||||
responses.count += resp.count;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -47,13 +47,13 @@ export async function POST(request: Request, _: CloudflareVectorizeStore, embedd
|
|||
const resp = await env!.VECTORIZE_INDEX.query(queryAsVector, {
|
||||
topK,
|
||||
filter: {
|
||||
user
|
||||
}
|
||||
user,
|
||||
},
|
||||
});
|
||||
|
||||
if (resp.count > 0) {
|
||||
responses.matches.push(...resp.matches)
|
||||
responses.count += resp.count
|
||||
responses.matches.push(...resp.matches);
|
||||
responses.count += resp.count;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,27 +61,36 @@ export async function POST(request: Request, _: CloudflareVectorizeStore, embedd
|
|||
// return new Response(JSON.stringify({ message: "No Results Found" }), { status: 404 });
|
||||
// }
|
||||
|
||||
const highScoreIds = responses.matches.filter(({ score }) => score > 0.35).map(({ id }) => id)
|
||||
const highScoreIds = responses.matches.filter(({ score }) => score > 0.35).map(({ id }) => id);
|
||||
|
||||
if (sourcesOnly === "true") {
|
||||
if (sourcesOnly === 'true') {
|
||||
return new Response(JSON.stringify({ ids: highScoreIds }), { status: 200 });
|
||||
}
|
||||
|
||||
const vec = await env!.VECTORIZE_INDEX.getByIds(highScoreIds)
|
||||
const vec = await env!.VECTORIZE_INDEX.getByIds(highScoreIds);
|
||||
|
||||
const preparedContext = vec.map(({ metadata }) => `Website title: ${metadata!.title}\nDescription: ${metadata!.description}\nURL: ${metadata!.url}\nContent: ${metadata!.text}`).join("\n\n");
|
||||
const preparedContext = vec
|
||||
.map(
|
||||
({ metadata }) =>
|
||||
`Website title: ${metadata!.title}\nDescription: ${metadata!.description}\nURL: ${metadata!.url}\nContent: ${metadata!.text}`,
|
||||
)
|
||||
.join('\n\n');
|
||||
|
||||
const body = await request.json() as {
|
||||
chatHistory?: Content[]
|
||||
const body = (await request.json()) as {
|
||||
chatHistory?: Content[];
|
||||
};
|
||||
|
||||
const defaultHistory = [
|
||||
{
|
||||
role: "user",
|
||||
parts: [{ text: `You are an agent that summarizes a page based on the query. don't say 'based on the context'. I expect you to be like a 'Second Brain'. you will be provided with the context (old saved posts) and questions. Answer accordingly. Answer in markdown format` }],
|
||||
role: 'user',
|
||||
parts: [
|
||||
{
|
||||
text: `You are an agent that summarizes a page based on the query. don't say 'based on the context'. I expect you to be like a 'Second Brain'. you will be provided with the context (old saved posts) and questions. Answer accordingly. Answer in markdown format`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
role: "model",
|
||||
role: 'model',
|
||||
parts: [{ text: "Ok, I am a personal assistant, and will act as a second brain to help with user's queries." }],
|
||||
},
|
||||
] as Content[];
|
||||
|
|
@ -100,14 +109,14 @@ export async function POST(request: Request, _: CloudflareVectorizeStore, embedd
|
|||
const converter = new TextEncoder();
|
||||
for await (const chunk of output.stream) {
|
||||
const chunkText = await chunk.text();
|
||||
const encodedChunk = converter.encode("data: " + JSON.stringify({ "response": chunkText }) + "\n\n");
|
||||
const encodedChunk = converter.encode('data: ' + JSON.stringify({ response: chunkText }) + '\n\n');
|
||||
controller.enqueue(encodedChunk);
|
||||
}
|
||||
const doneChunk = converter.encode("data: [DONE]");
|
||||
const doneChunk = converter.encode('data: [DONE]');
|
||||
controller.enqueue(doneChunk);
|
||||
controller.close();
|
||||
}
|
||||
})
|
||||
},
|
||||
}),
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,59 +1,65 @@
|
|||
import { GenerativeModel } from "@google/generative-ai";
|
||||
import { OpenAIEmbeddings } from "../OpenAIEmbedder";
|
||||
import { CloudflareVectorizeStore } from "@langchain/cloudflare";
|
||||
import { Request } from "@cloudflare/workers-types";
|
||||
import { GenerativeModel } from '@google/generative-ai';
|
||||
import { OpenAIEmbeddings } from '../OpenAIEmbedder';
|
||||
import { CloudflareVectorizeStore } from '@langchain/cloudflare';
|
||||
import { Request } from '@cloudflare/workers-types';
|
||||
|
||||
export async function GET(request: Request, _: CloudflareVectorizeStore, embeddings: OpenAIEmbeddings, model: GenerativeModel, env?: Env) {
|
||||
const queryparams = new URL(request.url).searchParams;
|
||||
const query = queryparams.get("q");
|
||||
const topK = parseInt(queryparams.get("topK") ?? "5");
|
||||
const user = queryparams.get("user")
|
||||
const space = queryparams.get("space")
|
||||
const query = queryparams.get('q');
|
||||
const topK = parseInt(queryparams.get('topK') ?? '5');
|
||||
const user = queryparams.get('user');
|
||||
const space = queryparams.get('space');
|
||||
|
||||
const sourcesOnly = (queryparams.get("sourcesOnly") ?? "false")
|
||||
const sourcesOnly = queryparams.get('sourcesOnly') ?? 'false';
|
||||
|
||||
if (!user) {
|
||||
return new Response(JSON.stringify({ message: "Invalid User" }), { status: 400 });
|
||||
return new Response(JSON.stringify({ message: 'Invalid User' }), { status: 400 });
|
||||
}
|
||||
|
||||
if (!query) {
|
||||
return new Response(JSON.stringify({ message: "Invalid Query" }), { status: 400 });
|
||||
return new Response(JSON.stringify({ message: 'Invalid Query' }), { status: 400 });
|
||||
}
|
||||
|
||||
const filter: VectorizeVectorMetadataFilter = {
|
||||
user
|
||||
}
|
||||
user,
|
||||
};
|
||||
|
||||
if (space) {
|
||||
filter.space
|
||||
filter.space;
|
||||
}
|
||||
|
||||
const queryAsVector = await embeddings.embedQuery(query);
|
||||
|
||||
const resp = await env!.VECTORIZE_INDEX.query(queryAsVector, {
|
||||
topK,
|
||||
filter
|
||||
filter,
|
||||
});
|
||||
|
||||
if (resp.count === 0) {
|
||||
return new Response(JSON.stringify({ message: "No Results Found" }), { status: 404 });
|
||||
return new Response(JSON.stringify({ message: 'No Results Found' }), { status: 404 });
|
||||
}
|
||||
|
||||
const highScoreIds = resp.matches.filter(({ score }) => score > 0.3).map(({ id }) => id)
|
||||
const highScoreIds = resp.matches.filter(({ score }) => score > 0.3).map(({ id }) => id);
|
||||
|
||||
if (sourcesOnly === "true") {
|
||||
if (sourcesOnly === 'true') {
|
||||
return new Response(JSON.stringify({ ids: highScoreIds }), { status: 200 });
|
||||
}
|
||||
|
||||
const vec = await env!.VECTORIZE_INDEX.getByIds(highScoreIds)
|
||||
const vec = await env!.VECTORIZE_INDEX.getByIds(highScoreIds);
|
||||
|
||||
if (vec.length === 0 || !vec[0].metadata) {
|
||||
return new Response(JSON.stringify({ message: "No Results Found" }), { status: 400 });
|
||||
return new Response(JSON.stringify({ message: 'No Results Found' }), { status: 400 });
|
||||
}
|
||||
|
||||
const preparedContext = vec.slice(0, 3).map(({ metadata }) => `Website title: ${metadata!.title}\nDescription: ${metadata!.description}\nURL: ${metadata!.url}\nContent: ${metadata!.text}`).join("\n\n");
|
||||
const preparedContext = vec
|
||||
.slice(0, 3)
|
||||
.map(
|
||||
({ metadata }) =>
|
||||
`Website title: ${metadata!.title}\nDescription: ${metadata!.description}\nURL: ${metadata!.url}\nContent: ${metadata!.text}`,
|
||||
)
|
||||
.join('\n\n');
|
||||
|
||||
const prompt = `You are an agent that summarizes a page based on the query. Be direct and concise, don't say 'based on the context'.\n\n Context:\n${preparedContext} \nAnswer this question based on the context. Question: ${query}\nAnswer:`
|
||||
const prompt = `You are an agent that summarizes a page based on the query. Be direct and concise, don't say 'based on the context'.\n\n Context:\n${preparedContext} \nAnswer this question based on the context. Question: ${query}\nAnswer:`;
|
||||
const output = await model.generateContentStream(prompt);
|
||||
|
||||
const response = new Response(
|
||||
|
|
@ -62,14 +68,14 @@ export async function GET(request: Request, _: CloudflareVectorizeStore, embeddi
|
|||
const converter = new TextEncoder();
|
||||
for await (const chunk of output.stream) {
|
||||
const chunkText = await chunk.text();
|
||||
const encodedChunk = converter.encode("data: " + JSON.stringify({ "response": chunkText }) + "\n\n");
|
||||
const encodedChunk = converter.encode('data: ' + JSON.stringify({ response: chunkText }) + '\n\n');
|
||||
controller.enqueue(encodedChunk);
|
||||
}
|
||||
const doneChunk = converter.encode("data: [DONE]");
|
||||
const doneChunk = converter.encode('data: [DONE]');
|
||||
controller.enqueue(doneChunk);
|
||||
controller.close();
|
||||
}
|
||||
})
|
||||
},
|
||||
}),
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@ module.exports = {
|
|||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:react-hooks/recommended",
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react-refresh'],
|
||||
ignorePatterns: ["dist", ".eslintrc.cjs"],
|
||||
parser: "@typescript-eslint/parser",
|
||||
plugins: ["react-refresh"],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
"react-refresh/only-export-components": [
|
||||
"warn",
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,15 +17,14 @@ If you are developing a production application, we recommend updating the config
|
|||
export default {
|
||||
// other rules...
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
project: ['./tsconfig.json', './tsconfig.node.json'],
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
project: ["./tsconfig.json", "./tsconfig.node.json"],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
|
||||
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
|
||||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
|
||||
|
||||
|
|
@ -14,4 +14,4 @@
|
|||
"components": "src/components",
|
||||
"utils": "src/lib/utils"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +1,35 @@
|
|||
{
|
||||
"manifest_version": 3,
|
||||
"name": "SuperMemory",
|
||||
"version": "1.0.0",
|
||||
"action": {
|
||||
"default_popup": "index.html"
|
||||
},
|
||||
"icons": {
|
||||
"16": "icons/icon16.png",
|
||||
"32": "icons/icon32.png",
|
||||
"48": "icons/icon48.png",
|
||||
"128": "icons/icon128.png"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"js": [
|
||||
"src/content.tsx"
|
||||
],
|
||||
"matches": [
|
||||
"http://localhost:3000/*",
|
||||
"https://opulent-funicular-94rx4v9w775f96q-3000.app.github.dev/*",
|
||||
"https://anycontext.dhr.wtf/*",
|
||||
"<all_urls>"
|
||||
]
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"storage",
|
||||
"manifest_version": 3,
|
||||
"name": "SuperMemory",
|
||||
"version": "1.0.0",
|
||||
"action": {
|
||||
"default_popup": "index.html"
|
||||
},
|
||||
"icons": {
|
||||
"16": "icons/icon16.png",
|
||||
"32": "icons/icon32.png",
|
||||
"48": "icons/icon48.png",
|
||||
"128": "icons/icon128.png"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"js": ["src/content.tsx"],
|
||||
"matches": [
|
||||
"http://localhost:3000/*",
|
||||
"https://opulent-funicular-94rx4v9w775f96q-3000.app.github.dev/*",
|
||||
"https://anycontext.dhr.wtf/*"
|
||||
],
|
||||
"background": {
|
||||
"service_worker": "src/background.ts"
|
||||
"https://anycontext.dhr.wtf/*",
|
||||
"<all_urls>"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"storage",
|
||||
"http://localhost:3000/*",
|
||||
"https://opulent-funicular-94rx4v9w775f96q-3000.app.github.dev/*",
|
||||
"https://anycontext.dhr.wtf/*"
|
||||
],
|
||||
"background": {
|
||||
"service_worker": "src/background.ts"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,4 +28,4 @@
|
|||
"typescript": "^5.2.2",
|
||||
"vite": "^5.1.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ export default {
|
|||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { z } from 'zod';
|
||||
import { userObj } from './types/zods';
|
||||
import { getEnv } from './util';
|
||||
import { useEffect, useState } from "react";
|
||||
import { z } from "zod";
|
||||
import { userObj } from "./types/zods";
|
||||
import { getEnv } from "./util";
|
||||
|
||||
const backendUrl = getEnv() === "development" ? "http://localhost:3000" : "https://supermemory.dhr.wtf";
|
||||
const backendUrl =
|
||||
getEnv() === "development"
|
||||
? "http://localhost:3000"
|
||||
: "https://supermemory.dhr.wtf";
|
||||
|
||||
function App() {
|
||||
const [userData, setUserData] = useState<z.infer<typeof userObj> | null>(
|
||||
|
|
@ -11,9 +14,9 @@ function App() {
|
|||
);
|
||||
|
||||
const doStuff = () => {
|
||||
chrome.runtime.sendMessage({ type: 'getJwt' }, (response) => {
|
||||
chrome.runtime.sendMessage({ type: "getJwt" }, (response) => {
|
||||
const jwt = response.jwt;
|
||||
const loginButton = document.getElementById('login');
|
||||
const loginButton = document.getElementById("login");
|
||||
|
||||
if (loginButton) {
|
||||
if (jwt) {
|
||||
|
|
@ -31,7 +34,7 @@ function App() {
|
|||
console.error(d.error);
|
||||
}
|
||||
});
|
||||
loginButton.style.display = 'none';
|
||||
loginButton.style.display = "none";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,215 +1,64 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import './dist.css';
|
||||
import { Input } from './components/ui/input';
|
||||
import { Button } from './components/ui/button';
|
||||
import { useState } from "react";
|
||||
|
||||
import "./ext.css";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from './components/ui/tooltip';
|
||||
} from "./components/ui/tooltip";
|
||||
|
||||
function sendUrlToAPI() {
|
||||
// get the current URL
|
||||
const url = window.location.href;
|
||||
|
||||
const blacklist = ['localhost:3000', 'anycontext.dhr.wtf'];
|
||||
const blacklist = ["localhost:3000", "anycontext.dhr.wtf"];
|
||||
// check if the URL is blacklisted
|
||||
if (blacklist.some((blacklisted) => url.includes(blacklisted))) {
|
||||
console.log('URL is blacklisted');
|
||||
console.log("URL is blacklisted");
|
||||
return;
|
||||
} else {
|
||||
// const content = Entire page content, but cleaned up for the LLM. No ads, no scripts, no styles, just the text. if article, just the importnat info abou tit.
|
||||
const content = document.documentElement.innerText;
|
||||
chrome.runtime.sendMessage({ type: 'urlChange', content, url });
|
||||
chrome.runtime.sendMessage({ type: "urlChange", content, url });
|
||||
}
|
||||
}
|
||||
|
||||
function SideBar({ jwt }: { jwt: string }) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [input, setInput] = useState('');
|
||||
function SideBar() {
|
||||
const [savedWebsites, setSavedWebsites] = useState<string[]>([]);
|
||||
|
||||
const [isSendingData, setIsSendingData] = useState(false);
|
||||
|
||||
const [toBeParsed, setToBeParsed] = useState('');
|
||||
const [aiResponse, setAIResponse] = useState<string>('');
|
||||
const [lastQuestion, setLastQuestion] = useState<string>('');
|
||||
|
||||
const handleStreamData = (newChunk: string) => {
|
||||
// Append the new chunk to the existing data to be parsed
|
||||
setToBeParsed((prev) => prev + newChunk);
|
||||
};
|
||||
|
||||
const queryApi = async () => {
|
||||
const content = document.documentElement.innerText;
|
||||
|
||||
setAIResponse('');
|
||||
|
||||
const query = `Answer this question based on this query: ${input}\n\n${content}`;
|
||||
|
||||
chrome.runtime.sendMessage({ type: 'queryApi', input: query, jwt });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
chrome.runtime.onMessage.addListener((message) => {
|
||||
if (message.action === 'streamData') {
|
||||
console.log(message.data);
|
||||
handleStreamData(message.data);
|
||||
} else if (message.action === 'streamEnd') {
|
||||
setLastQuestion(input);
|
||||
setInput('');
|
||||
setToBeParsed('');
|
||||
}
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Define a function to try parsing the accumulated data
|
||||
const tryParseAccumulatedData = () => {
|
||||
// Attempt to parse the "toBeParsed" state as JSON
|
||||
try {
|
||||
// Split the accumulated data by the known delimiter "\n\n"
|
||||
const parts = toBeParsed.split('\n\n');
|
||||
let remainingData = '';
|
||||
|
||||
// Process each part to extract JSON objects
|
||||
parts.forEach((part, index) => {
|
||||
if (part.startsWith('data: [DONE]data: ')) {
|
||||
part = part.replace('data: [DONE]data: ', 'data: ');
|
||||
}
|
||||
try {
|
||||
const parsedPart = JSON.parse(part.replace('data: ', '')); // Try to parse the part as JSON
|
||||
|
||||
// If the part is the last one and couldn't be parsed, keep it to accumulate more data
|
||||
if (index === parts.length - 1 && !parsedPart) {
|
||||
remainingData = part;
|
||||
} else if (parsedPart && parsedPart.response) {
|
||||
// If the part is parsable and has the "response" field, update the AI response state
|
||||
setAIResponse((prev) => prev + parsedPart.response);
|
||||
}
|
||||
} catch (error) {
|
||||
// If parsing fails and it's not the last part, it's a malformed JSON
|
||||
if (index !== parts.length - 1) {
|
||||
console.error('Malformed JSON part: ', part);
|
||||
} else {
|
||||
// If it's the last part, it may be incomplete, so keep it
|
||||
remainingData = part;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Update the toBeParsed state to only contain the unparsed remainder
|
||||
if (remainingData !== toBeParsed) {
|
||||
setToBeParsed(remainingData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error parsing accumulated data: ', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Call the parsing function if there's data to be parsed
|
||||
if (toBeParsed) {
|
||||
tryParseAccumulatedData();
|
||||
}
|
||||
}, [toBeParsed]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<TooltipProvider>
|
||||
{isOpen && (
|
||||
<div
|
||||
onClick={() => setIsOpen(false)}
|
||||
className="anycontext-overlay"
|
||||
></div>
|
||||
)}
|
||||
<div className="anycontext-flex anycontext-flex-col anycontext-gap-2 anycontext-fixed anycontext-bottom-12 anycontext-right-0 anycontext-z-[99999] anycontext-font-sans">
|
||||
{/* <Tooltip delayDuration={300}>
|
||||
<TooltipContent side="left">
|
||||
<p>Open Sidebar</p>
|
||||
</TooltipContent>
|
||||
</Tooltip> */}
|
||||
|
||||
{isOpen ? (
|
||||
<motion.div
|
||||
initial={{ x: '100%' }}
|
||||
animate={{ x: 0 }}
|
||||
exit={{ x: '100%' }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="anycontext-sidebar anycontext-relative"
|
||||
>
|
||||
<div className="anycontext-sidebar-content anycontext-text-black anycontext-px-4 anycontext-relative">
|
||||
<h1 className="anycontext-header anycontext-font-sans">
|
||||
Ask a question to this page
|
||||
</h1>
|
||||
|
||||
{/* Three buttons as options to choose from */}
|
||||
{!input && (
|
||||
<div className="anycontext-flex anycontext-flex-col anycontext-gap-4 anycontext-mt-8 anycontext-px-4">
|
||||
<Button
|
||||
onClick={async () => {
|
||||
setInput('Summarise the content of this web page');
|
||||
await queryApi();
|
||||
}}
|
||||
className="anycontext-w-full"
|
||||
>
|
||||
Summarize content
|
||||
</Button>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
setInput(
|
||||
'Whats the most important points of this page? Answer in points.',
|
||||
);
|
||||
await queryApi();
|
||||
}}
|
||||
className="anycontext-w-full"
|
||||
>
|
||||
What's the most important?
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
sendUrlToAPI();
|
||||
setIsSendingData(true);
|
||||
setTimeout(() => {
|
||||
setIsSendingData(false);
|
||||
setSavedWebsites([
|
||||
...savedWebsites,
|
||||
window.location.href,
|
||||
]);
|
||||
}, 1000);
|
||||
}}
|
||||
className="anycontext-w-full anycontext-bg-gradient-to-tr anycontext-from-purple-400 anycontext-to-purple-600"
|
||||
>
|
||||
Save to memory
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{lastQuestion && (
|
||||
<div className="anycontext-mb-4">
|
||||
<h2 className="anycontext-text-lg anycontext-font-semibold">
|
||||
{lastQuestion}
|
||||
</h2>
|
||||
</div>
|
||||
)}
|
||||
<div className="anycontext-px-4 anycontext-max-h-[75vh] anycontext-overflow-y-auto anycontext-mt-8">
|
||||
{aiResponse.replace('</s>', '')}
|
||||
</div>
|
||||
|
||||
<form
|
||||
onSubmit={async (e) => {
|
||||
e.preventDefault();
|
||||
await queryApi();
|
||||
setInput('');
|
||||
<Tooltip delayDuration={300}>
|
||||
<TooltipTrigger
|
||||
className="anycontext-bg-transparent
|
||||
anycontext-border-none anycontext-m-0 anycontext-p-0
|
||||
"
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
sendUrlToAPI();
|
||||
setIsSendingData(true);
|
||||
setTimeout(() => {
|
||||
setIsSendingData(false);
|
||||
setSavedWebsites([...savedWebsites, window.location.href]);
|
||||
}, 1000);
|
||||
}}
|
||||
className="anycontext-flex anycontext-absolute anycontext-bottom-0 anycontext-w-full anycontext-gap-4 anycontext-justify-between anycontext-px-4"
|
||||
disabled={savedWebsites.includes(window.location.href)}
|
||||
className="anycontext-open-button disabled:anycontext-opacity-30 anycontext-bg-transparent
|
||||
anycontext-border-none anycontext-m-0 anycontext-p-0"
|
||||
>
|
||||
<Input
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
placeholder="Ask anything about this website"
|
||||
className="anycontext-mb-4 anycontext-text-black anycontext-outline"
|
||||
/>
|
||||
<Button onClick={async () => queryApi()}>
|
||||
{savedWebsites.includes(window.location.href) ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
|
|
@ -220,102 +69,33 @@ function SideBar({ jwt }: { jwt: string }) {
|
|||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="lucide lucide-send-horizontal"
|
||||
className="lucide lucide-file-check-2"
|
||||
>
|
||||
<path d="m3 3 3 9-3 9 19-9Z" />
|
||||
<path d="M6 12h16" />
|
||||
<path d="M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4" />
|
||||
<path d="M14 2v4a2 2 0 0 0 2 2h4" />
|
||||
<path d="m3 15 2 2 4-4" />
|
||||
</svg>
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
</motion.div>
|
||||
) : (
|
||||
<div className="anycontext-flex anycontext-flex-col anycontext-gap-2 anycontext-fixed anycontext-bottom-12 anycontext-right-0 anycontext-z-[99999]">
|
||||
<Tooltip delayDuration={300}>
|
||||
<TooltipTrigger>
|
||||
<button
|
||||
onClick={() => setIsOpen(true)}
|
||||
className="anycontext-open-button"
|
||||
>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="lucide lucide-panel-right-open"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
className={`anycontext-w-5 anycontext-h-5 ${isSendingData ? "anycontext-animate-spin" : ""}`}
|
||||
>
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" />
|
||||
<path d="M15 3v18" />
|
||||
<path d="m10 15-3-3 3-3" />
|
||||
<path d="M15.98 1.804a1 1 0 0 0-1.96 0l-.24 1.192a1 1 0 0 1-.784.785l-1.192.238a1 1 0 0 0 0 1.962l1.192.238a1 1 0 0 1 .785.785l.238 1.192a1 1 0 0 0 1.962 0l.238-1.192a1 1 0 0 1 .785-.785l1.192-.238a1 1 0 0 0 0-1.962l-1.192-.238a1 1 0 0 1-.785-.785l-.238-1.192ZM6.949 5.684a1 1 0 0 0-1.898 0l-.683 2.051a1 1 0 0 1-.633.633l-2.051.683a1 1 0 0 0 0 1.898l2.051.684a1 1 0 0 1 .633.632l.683 2.051a1 1 0 0 0 1.898 0l.683-2.051a1 1 0 0 1 .633-.633l2.051-.683a1 1 0 0 0 0-1.898l-2.051-.683a1 1 0 0 1-.633-.633L6.95 5.684ZM13.949 13.684a1 1 0 0 0-1.898 0l-.184.551a1 1 0 0 1-.632.633l-.551.183a1 1 0 0 0 0 1.898l.551.183a1 1 0 0 1 .633.633l.183.551a1 1 0 0 0 1.898 0l.184-.551a1 1 0 0 1 .632-.633l.551-.183a1 1 0 0 0 0-1.898l-.551-.184a1 1 0 0 1-.633-.632l-.183-.551Z" />
|
||||
</svg>
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="left">
|
||||
<p>Open Sidebar</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip delayDuration={300}>
|
||||
<TooltipTrigger>
|
||||
<button
|
||||
onClick={() => {
|
||||
sendUrlToAPI();
|
||||
setIsSendingData(true);
|
||||
setTimeout(() => {
|
||||
setIsSendingData(false);
|
||||
setSavedWebsites([
|
||||
...savedWebsites,
|
||||
window.location.href,
|
||||
]);
|
||||
}, 1000);
|
||||
}}
|
||||
disabled={savedWebsites.includes(window.location.href)}
|
||||
className="anycontext-open-button disabled:anycontext-opacity-30"
|
||||
>
|
||||
{savedWebsites.includes(window.location.href) ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="lucide lucide-file-check-2"
|
||||
>
|
||||
<path d="M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4" />
|
||||
<path d="M14 2v4a2 2 0 0 0 2 2h4" />
|
||||
<path d="m3 15 2 2 4-4" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
className={`anycontext-w-5 anycontext-h-5 ${isSendingData ? 'anycontext-animate-spin' : ''}`}
|
||||
>
|
||||
<path d="M15.98 1.804a1 1 0 0 0-1.96 0l-.24 1.192a1 1 0 0 1-.784.785l-1.192.238a1 1 0 0 0 0 1.962l1.192.238a1 1 0 0 1 .785.785l.238 1.192a1 1 0 0 0 1.962 0l.238-1.192a1 1 0 0 1 .785-.785l1.192-.238a1 1 0 0 0 0-1.962l-1.192-.238a1 1 0 0 1-.785-.785l-.238-1.192ZM6.949 5.684a1 1 0 0 0-1.898 0l-.683 2.051a1 1 0 0 1-.633.633l-2.051.683a1 1 0 0 0 0 1.898l2.051.684a1 1 0 0 1 .633.632l.683 2.051a1 1 0 0 0 1.898 0l.683-2.051a1 1 0 0 1 .633-.633l2.051-.683a1 1 0 0 0 0-1.898l-2.051-.683a1 1 0 0 1-.633-.633L6.95 5.684ZM13.949 13.684a1 1 0 0 0-1.898 0l-.184.551a1 1 0 0 1-.632.633l-.551.183a1 1 0 0 0 0 1.898l.551.183a1 1 0 0 1 .633.633l.183.551a1 1 0 0 0 1.898 0l.184-.551a1 1 0 0 1 .632-.633l.551-.183a1 1 0 0 0 0-1.898l-.551-.184a1 1 0 0 1-.633-.632l-.183-.551Z" />
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="left">
|
||||
<p>
|
||||
{savedWebsites.includes(window.location.href)
|
||||
? 'Added to memory'
|
||||
: 'Add to memory'}
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="anycontext-p-0" side="left">
|
||||
<p className="anycontext-p-0 anycontext-m-0">
|
||||
{savedWebsites.includes(window.location.href)
|
||||
? "Added to memory"
|
||||
: "Add to memory"}
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import { getEnv } from "./util";
|
||||
|
||||
const backendUrl = getEnv() === "development" ? "http://localhost:3000" : "https://supermemory.dhr.wtf";
|
||||
const backendUrl =
|
||||
getEnv() === "development"
|
||||
? "http://localhost:3000"
|
||||
: "https://supermemory.dhr.wtf";
|
||||
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
if (request.type === "getJwt") {
|
||||
|
|
@ -9,9 +12,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (request.type === "urlChange") {
|
||||
} else if (request.type === "urlChange") {
|
||||
const content = request.content;
|
||||
const url = request.url;
|
||||
|
||||
|
|
@ -24,15 +25,13 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||
fetch(`${backendUrl}/api/store`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Authorization": `Bearer ${jwt}`,
|
||||
Authorization: `Bearer ${jwt}`,
|
||||
},
|
||||
body: JSON.stringify({ pageContent: content, url }),
|
||||
}).then(ers => console.log(ers.status))
|
||||
}).then((ers) => console.log(ers.status));
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
else if (request.type === "queryApi") {
|
||||
} else if (request.type === "queryApi") {
|
||||
const input = request.input;
|
||||
const jwt = request.jwt;
|
||||
|
||||
|
|
@ -40,12 +39,12 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||
await fetch(`${backendUrl}/api/ask`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Authorization": `Bearer ${jwt}`,
|
||||
Authorization: `Bearer ${jwt}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query: input,
|
||||
}),
|
||||
}).then(async response => {
|
||||
}).then(async (response) => {
|
||||
if (!response.body) {
|
||||
throw new Error("No response body");
|
||||
}
|
||||
|
|
@ -59,8 +58,13 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||
if (done) break;
|
||||
// For simplicity, we're sending chunks as they come.
|
||||
// This might need to be adapted based on your data and needs.
|
||||
const chunkAsString = new TextDecoder('utf-8').decode(value).replace("data: ", "")
|
||||
chrome.tabs.sendMessage(sender.tab.id, { action: "streamData", data: chunkAsString });
|
||||
const chunkAsString = new TextDecoder("utf-8")
|
||||
.decode(value)
|
||||
.replace("data: ", "");
|
||||
chrome.tabs.sendMessage(sender.tab.id, {
|
||||
action: "streamData",
|
||||
data: chunkAsString,
|
||||
});
|
||||
}
|
||||
// Notify the content script that the stream is complete.
|
||||
chrome.tabs.sendMessage(sender.tab.id, { action: "streamEnd" });
|
||||
|
|
|
|||
|
|
@ -1,22 +1,24 @@
|
|||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import * as React from "react";
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
|
||||
import { cn } from "../../lib/utils"
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
const buttonVariants = cva(
|
||||
"anycontext-inline-flex anycontext-items-center anycontext-justify-center anycontext-whitespace-nowrap anycontext-rounded-md anycontext-text-sm anycontext-font-medium anycontext-ring-offset-white anycontext-transition-colors focus-visible:anycontext-outline-none focus-visible:anycontext-ring-2 focus-visible:anycontext-ring-stone-950 focus-visible:anycontext-ring-offset-2 disabled:anycontext-pointer-events-none disabled:anycontext-opacity-50 dark:anycontext-ring-offset-stone-950 dark:focus-visible:anycontext-ring-stone-300",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "anycontext-bg-stone-900 anycontext-text-stone-50 hover:anycontext-bg-stone-900/90 dark:anycontext-bg-stone-50 dark:anycontext-text-stone-900 dark:hover:anycontext-bg-stone-50/90",
|
||||
default:
|
||||
"anycontext-bg-stone-900 anycontext-text-stone-50 hover:anycontext-bg-stone-900/90 dark:anycontext-bg-stone-50 dark:anycontext-text-stone-900 dark:hover:anycontext-bg-stone-50/90",
|
||||
destructive:
|
||||
"anycontext-bg-red-500 anycontext-text-stone-50 hover:anycontext-bg-red-500/90 dark:anycontext-bg-red-900 dark:anycontext-text-stone-50 dark:hover:anycontext-bg-red-900/90",
|
||||
outline:
|
||||
"anycontext-border anycontext-border-stone-200 anycontext-bg-white hover:anycontext-bg-stone-100 hover:anycontext-text-stone-900 dark:anycontext-border-stone-800 dark:anycontext-bg-stone-950 dark:hover:anycontext-bg-stone-800 dark:hover:anycontext-text-stone-50",
|
||||
secondary:
|
||||
"anycontext-bg-stone-100 anycontext-text-stone-900 hover:anycontext-bg-stone-100/80 dark:anycontext-bg-stone-800 dark:anycontext-text-stone-50 dark:hover:anycontext-bg-stone-800/80",
|
||||
ghost: "hover:anycontext-bg-stone-100 hover:anycontext-text-stone-900 dark:hover:anycontext-bg-stone-800 dark:hover:anycontext-text-stone-50",
|
||||
ghost:
|
||||
"hover:anycontext-bg-stone-100 hover:anycontext-text-stone-900 dark:hover:anycontext-bg-stone-800 dark:hover:anycontext-text-stone-50",
|
||||
link: "anycontext-text-stone-900 anycontext-underline-offset-4 hover:anycontext-underline dark:anycontext-text-stone-50",
|
||||
},
|
||||
size: {
|
||||
|
|
@ -30,27 +32,27 @@ const buttonVariants = cva(
|
|||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
const Comp = asChild ? Slot : "button";
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Button.displayName = "Button"
|
||||
);
|
||||
},
|
||||
);
|
||||
Button.displayName = "Button";
|
||||
|
||||
export { Button, buttonVariants }
|
||||
export { Button };
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react"
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "../../lib/utils"
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
export interface InputProps
|
||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
|
|
@ -12,14 +12,14 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|||
type={type}
|
||||
className={cn(
|
||||
"anycontext-flex anycontext-h-10 anycontext-w-full anycontext-rounded-md anycontext-border anycontext-border-stone-200 anycontext-bg-white anycontext-px-3 anycontext-py-2 anycontext-text-sm anycontext-ring-offset-white file:anycontext-border-0 file:anycontext-bg-transparent file:anycontext-text-sm file:anycontext-font-medium placeholder:anycontext-text-stone-500 focus-visible:anycontext-outline-none focus-visible:anycontext-ring-2 focus-visible:anycontext-ring-stone-950 focus-visible:anycontext-ring-offset-2 disabled:anycontext-cursor-not-allowed disabled:anycontext-opacity-50 dark:anycontext-border-stone-800 dark:anycontext-bg-stone-950 dark:anycontext-ring-offset-stone-950 dark:placeholder:anycontext-text-stone-400 dark:focus-visible:anycontext-ring-stone-300",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Input.displayName = "Input"
|
||||
);
|
||||
},
|
||||
);
|
||||
Input.displayName = "Input";
|
||||
|
||||
export { Input }
|
||||
export { Input };
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import * as React from "react"
|
||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
||||
import * as React from "react";
|
||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||
|
||||
import { cn } from "../../lib/utils"
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
const TooltipProvider = TooltipPrimitive.Provider
|
||||
const TooltipProvider = TooltipPrimitive.Provider;
|
||||
|
||||
const Tooltip = TooltipPrimitive.Root
|
||||
const Tooltip = TooltipPrimitive.Root;
|
||||
|
||||
const TooltipTrigger = TooltipPrimitive.Trigger
|
||||
const TooltipTrigger = TooltipPrimitive.Trigger;
|
||||
|
||||
const TooltipContent = React.forwardRef<
|
||||
React.ElementRef<typeof TooltipPrimitive.Content>,
|
||||
|
|
@ -18,11 +18,11 @@ const TooltipContent = React.forwardRef<
|
|||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"anycontext-z-50 anycontext-overflow-hidden anycontext-rounded-md anycontext-border anycontext-border-stone-200 anycontext-bg-white anycontext-px-3 anycontext-py-1.5 anycontext-text-sm anycontext-text-stone-950 anycontext-shadow-md anycontext-animate-in anycontext-fade-in-0 anycontext-zoom-in-95 data-[state=closed]:anycontext-animate-out data-[state=closed]:anycontext-fade-out-0 data-[state=closed]:anycontext-zoom-out-95 data-[side=bottom]:anycontext-slide-in-from-top-2 data-[side=left]:anycontext-slide-in-from-right-2 data-[side=right]:anycontext-slide-in-from-left-2 data-[side=top]:anycontext-slide-in-from-bottom-2 dark:anycontext-border-stone-800 dark:anycontext-bg-stone-950 dark:anycontext-text-stone-50",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName
|
||||
));
|
||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
||||
|
||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
window.addEventListener('message', (event) => {
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.source !== window) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -7,13 +7,13 @@ window.addEventListener('message', (event) => {
|
|||
if (jwt) {
|
||||
if (
|
||||
!(
|
||||
window.location.hostname === 'localhost' ||
|
||||
window.location.hostname === 'anycontext.dhr.wtf' ||
|
||||
window.location.hostname === 'supermemory.dhr.wtf'
|
||||
window.location.hostname === "localhost" ||
|
||||
window.location.hostname === "anycontext.dhr.wtf" ||
|
||||
window.location.hostname === "supermemory.dhr.wtf"
|
||||
)
|
||||
) {
|
||||
console.log(
|
||||
'JWT is only allowed to be used on localhost or anycontext.dhr.wtf',
|
||||
"JWT is only allowed to be used on localhost or anycontext.dhr.wtf",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -22,24 +22,24 @@ window.addEventListener('message', (event) => {
|
|||
}
|
||||
});
|
||||
|
||||
const appContainer = document.createElement('div');
|
||||
appContainer.id = 'anycontext-app-container';
|
||||
const appContainer = document.createElement("div");
|
||||
appContainer.id = "anycontext-app-container";
|
||||
|
||||
// First in the body, above the content
|
||||
document.body.insertBefore(appContainer, document.body.firstChild);
|
||||
|
||||
appContainer.style.zIndex = '9999';
|
||||
appContainer.style.zIndex = "9999";
|
||||
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import SideBar from './SideBar';
|
||||
import ReactDOM from "react-dom/client";
|
||||
import SideBar from "./SideBar";
|
||||
|
||||
// get JWT from local storage
|
||||
const jwt = chrome.storage.local.get('jwt').then((data) => {
|
||||
const jwt = chrome.storage.local.get("jwt").then((data) => {
|
||||
return data.jwt;
|
||||
}) as Promise<string>;
|
||||
|
||||
jwt.then((jwt) => {
|
||||
jwt.then(() => {
|
||||
ReactDOM.createRoot(
|
||||
document.getElementById('anycontext-app-container')!,
|
||||
).render(<SideBar jwt={jwt} />);
|
||||
document.getElementById("anycontext-app-container")!,
|
||||
).render(<SideBar />);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,951 +0,0 @@
|
|||
*,
|
||||
::before,
|
||||
::after {
|
||||
box-sizing: border-box;
|
||||
/* 1 */
|
||||
|
||||
border-width: 0;
|
||||
/* 2 */
|
||||
|
||||
border-style: solid;
|
||||
/* 2 */
|
||||
|
||||
border-color: #e5e7eb;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
::before,
|
||||
::after {
|
||||
--tw-content: '';
|
||||
}
|
||||
|
||||
/*
|
||||
1. Use a consistent sensible line-height in all browsers.
|
||||
2. Prevent adjustments of font size after orientation changes in iOS.
|
||||
3. Use a more readable tab size.
|
||||
4. Use the user's configured `sans` font-family by default.
|
||||
5. Use the user's configured `sans` font-feature-settings by default.
|
||||
6. Use the user's configured `sans` font-variation-settings by default.
|
||||
7. Disable tap highlights on iOS
|
||||
*/
|
||||
|
||||
/* Make elements with the HTML hidden attribute stay hidden by default */
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
--tw-border-spacing-x: 0;
|
||||
|
||||
--tw-border-spacing-y: 0;
|
||||
|
||||
--tw-translate-x: 0;
|
||||
|
||||
--tw-translate-y: 0;
|
||||
|
||||
--tw-rotate: 0;
|
||||
|
||||
--tw-skew-x: 0;
|
||||
|
||||
--tw-skew-y: 0;
|
||||
|
||||
--tw-scale-x: 1;
|
||||
|
||||
--tw-scale-y: 1;
|
||||
|
||||
--tw-pan-x: ;
|
||||
|
||||
--tw-pan-y: ;
|
||||
|
||||
--tw-pinch-zoom: ;
|
||||
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
|
||||
--tw-gradient-from-position: ;
|
||||
|
||||
--tw-gradient-via-position: ;
|
||||
|
||||
--tw-gradient-to-position: ;
|
||||
|
||||
--tw-ordinal: ;
|
||||
|
||||
--tw-slashed-zero: ;
|
||||
|
||||
--tw-numeric-figure: ;
|
||||
|
||||
--tw-numeric-spacing: ;
|
||||
|
||||
--tw-numeric-fraction: ;
|
||||
|
||||
--tw-ring-inset: ;
|
||||
|
||||
--tw-ring-offset-width: 0px;
|
||||
|
||||
--tw-ring-offset-color: #fff;
|
||||
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
|
||||
--tw-shadow: 0 0 #0000;
|
||||
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
|
||||
--tw-blur: ;
|
||||
|
||||
--tw-brightness: ;
|
||||
|
||||
--tw-contrast: ;
|
||||
|
||||
--tw-grayscale: ;
|
||||
|
||||
--tw-hue-rotate: ;
|
||||
|
||||
--tw-invert: ;
|
||||
|
||||
--tw-saturate: ;
|
||||
|
||||
--tw-sepia: ;
|
||||
|
||||
--tw-drop-shadow: ;
|
||||
|
||||
--tw-backdrop-blur: ;
|
||||
|
||||
--tw-backdrop-brightness: ;
|
||||
|
||||
--tw-backdrop-contrast: ;
|
||||
|
||||
--tw-backdrop-grayscale: ;
|
||||
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
|
||||
--tw-backdrop-invert: ;
|
||||
|
||||
--tw-backdrop-opacity: ;
|
||||
|
||||
--tw-backdrop-saturate: ;
|
||||
|
||||
--tw-backdrop-sepia: ;
|
||||
}
|
||||
|
||||
::backdrop {
|
||||
--tw-border-spacing-x: 0;
|
||||
|
||||
--tw-border-spacing-y: 0;
|
||||
|
||||
--tw-translate-x: 0;
|
||||
|
||||
--tw-translate-y: 0;
|
||||
|
||||
--tw-rotate: 0;
|
||||
|
||||
--tw-skew-x: 0;
|
||||
|
||||
--tw-skew-y: 0;
|
||||
|
||||
--tw-scale-x: 1;
|
||||
|
||||
--tw-scale-y: 1;
|
||||
|
||||
--tw-pan-x: ;
|
||||
|
||||
--tw-pan-y: ;
|
||||
|
||||
--tw-pinch-zoom: ;
|
||||
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
|
||||
--tw-gradient-from-position: ;
|
||||
|
||||
--tw-gradient-via-position: ;
|
||||
|
||||
--tw-gradient-to-position: ;
|
||||
|
||||
--tw-ordinal: ;
|
||||
|
||||
--tw-slashed-zero: ;
|
||||
|
||||
--tw-numeric-figure: ;
|
||||
|
||||
--tw-numeric-spacing: ;
|
||||
|
||||
--tw-numeric-fraction: ;
|
||||
|
||||
--tw-ring-inset: ;
|
||||
|
||||
--tw-ring-offset-width: 0px;
|
||||
|
||||
--tw-ring-offset-color: #fff;
|
||||
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
|
||||
--tw-shadow: 0 0 #0000;
|
||||
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
|
||||
--tw-blur: ;
|
||||
|
||||
--tw-brightness: ;
|
||||
|
||||
--tw-contrast: ;
|
||||
|
||||
--tw-grayscale: ;
|
||||
|
||||
--tw-hue-rotate: ;
|
||||
|
||||
--tw-invert: ;
|
||||
|
||||
--tw-saturate: ;
|
||||
|
||||
--tw-sepia: ;
|
||||
|
||||
--tw-drop-shadow: ;
|
||||
|
||||
--tw-backdrop-blur: ;
|
||||
|
||||
--tw-backdrop-brightness: ;
|
||||
|
||||
--tw-backdrop-contrast: ;
|
||||
|
||||
--tw-backdrop-grayscale: ;
|
||||
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
|
||||
--tw-backdrop-invert: ;
|
||||
|
||||
--tw-backdrop-opacity: ;
|
||||
|
||||
--tw-backdrop-saturate: ;
|
||||
|
||||
--tw-backdrop-sepia: ;
|
||||
}
|
||||
|
||||
.anycontext-fixed {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.anycontext-absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.anycontext-relative {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.anycontext-bottom-0 {
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
.anycontext-bottom-12 {
|
||||
bottom: 3rem;
|
||||
}
|
||||
|
||||
.anycontext-right-0 {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.anycontext-z-50 {
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.anycontext-z-\[99999\] {
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
.anycontext-mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.anycontext-mt-8 {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.anycontext-flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.anycontext-inline-flex {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.anycontext-h-10 {
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.anycontext-h-11 {
|
||||
height: 2.75rem;
|
||||
}
|
||||
|
||||
.anycontext-h-5 {
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.anycontext-h-9 {
|
||||
height: 2.25rem;
|
||||
}
|
||||
|
||||
.anycontext-max-h-\[75vh\] {
|
||||
max-height: 75vh;
|
||||
}
|
||||
|
||||
.anycontext-w-10 {
|
||||
width: 2.5rem;
|
||||
}
|
||||
|
||||
.anycontext-w-5 {
|
||||
width: 1.25rem;
|
||||
}
|
||||
|
||||
.anycontext-w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@keyframes anycontext-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.anycontext-animate-spin {
|
||||
animation: anycontext-spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.anycontext-flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.anycontext-items-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.anycontext-justify-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.anycontext-justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.anycontext-gap-2 {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.anycontext-gap-4 {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.anycontext-overflow-hidden {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.anycontext-overflow-y-auto {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.anycontext-whitespace-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.anycontext-rounded-md {
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
|
||||
.anycontext-border {
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.anycontext-border-stone-200 {
|
||||
--tw-border-opacity: 1;
|
||||
|
||||
border-color: rgb(231 229 228 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.anycontext-bg-red-500 {
|
||||
--tw-bg-opacity: 1;
|
||||
|
||||
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.anycontext-bg-stone-100 {
|
||||
--tw-bg-opacity: 1;
|
||||
|
||||
background-color: rgb(245 245 244 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.anycontext-bg-stone-900 {
|
||||
--tw-bg-opacity: 1;
|
||||
|
||||
background-color: rgb(28 25 23 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.anycontext-bg-white {
|
||||
--tw-bg-opacity: 1;
|
||||
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.anycontext-bg-gradient-to-tr {
|
||||
background-image: linear-gradient(to top right, var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.anycontext-from-purple-400 {
|
||||
--tw-gradient-from: #c084fc var(--tw-gradient-from-position);
|
||||
|
||||
--tw-gradient-to: rgb(192 132 252 / 0) var(--tw-gradient-to-position);
|
||||
|
||||
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
||||
}
|
||||
|
||||
.anycontext-to-purple-600 {
|
||||
--tw-gradient-to: #9333ea var(--tw-gradient-to-position);
|
||||
}
|
||||
|
||||
.anycontext-px-3 {
|
||||
padding-left: 0.75rem;
|
||||
|
||||
padding-right: 0.75rem;
|
||||
}
|
||||
|
||||
.anycontext-px-4 {
|
||||
padding-left: 1rem;
|
||||
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.anycontext-px-8 {
|
||||
padding-left: 2rem;
|
||||
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
.anycontext-py-1 {
|
||||
padding-top: 0.25rem;
|
||||
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.anycontext-py-1\.5 {
|
||||
padding-top: 0.375rem;
|
||||
|
||||
padding-bottom: 0.375rem;
|
||||
}
|
||||
|
||||
.anycontext-py-2 {
|
||||
padding-top: 0.5rem;
|
||||
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.anycontext-font-sans {
|
||||
font-family: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji',
|
||||
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
}
|
||||
|
||||
.anycontext-text-sm {
|
||||
font-size: 0.875rem;
|
||||
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.anycontext-text-lg {
|
||||
font-size: 1.125rem;
|
||||
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.anycontext-font-medium {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.anycontext-font-semibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.anycontext-text-black {
|
||||
--tw-text-opacity: 1;
|
||||
|
||||
color: rgb(0 0 0 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.anycontext-text-stone-50 {
|
||||
--tw-text-opacity: 1;
|
||||
|
||||
color: rgb(250 250 249 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.anycontext-text-stone-900 {
|
||||
--tw-text-opacity: 1;
|
||||
|
||||
color: rgb(28 25 23 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.anycontext-text-stone-950 {
|
||||
--tw-text-opacity: 1;
|
||||
|
||||
color: rgb(12 10 9 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.anycontext-underline-offset-4 {
|
||||
text-underline-offset: 4px;
|
||||
}
|
||||
|
||||
.anycontext-shadow-md {
|
||||
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
|
||||
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color),
|
||||
0 2px 4px -2px var(--tw-shadow-color);
|
||||
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.anycontext-outline {
|
||||
outline-style: solid;
|
||||
}
|
||||
|
||||
.anycontext-ring-offset-white {
|
||||
--tw-ring-offset-color: #fff;
|
||||
}
|
||||
|
||||
.anycontext-transition-colors {
|
||||
transition-property: color, background-color, border-color,
|
||||
text-decoration-color, fill, stroke;
|
||||
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
@keyframes enter {
|
||||
from {
|
||||
opacity: var(--tw-enter-opacity, 1);
|
||||
|
||||
transform: translate3d(
|
||||
var(--tw-enter-translate-x, 0),
|
||||
var(--tw-enter-translate-y, 0),
|
||||
0
|
||||
)
|
||||
scale3d(
|
||||
var(--tw-enter-scale, 1),
|
||||
var(--tw-enter-scale, 1),
|
||||
var(--tw-enter-scale, 1)
|
||||
)
|
||||
rotate(var(--tw-enter-rotate, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes exit {
|
||||
to {
|
||||
opacity: var(--tw-exit-opacity, 1);
|
||||
|
||||
transform: translate3d(
|
||||
var(--tw-exit-translate-x, 0),
|
||||
var(--tw-exit-translate-y, 0),
|
||||
0
|
||||
)
|
||||
scale3d(
|
||||
var(--tw-exit-scale, 1),
|
||||
var(--tw-exit-scale, 1),
|
||||
var(--tw-exit-scale, 1)
|
||||
)
|
||||
rotate(var(--tw-exit-rotate, 0));
|
||||
}
|
||||
}
|
||||
|
||||
.anycontext-animate-in {
|
||||
animation-name: enter;
|
||||
|
||||
animation-duration: 150ms;
|
||||
|
||||
--tw-enter-opacity: initial;
|
||||
|
||||
--tw-enter-scale: initial;
|
||||
|
||||
--tw-enter-rotate: initial;
|
||||
|
||||
--tw-enter-translate-x: initial;
|
||||
|
||||
--tw-enter-translate-y: initial;
|
||||
}
|
||||
|
||||
.anycontext-fade-in-0 {
|
||||
--tw-enter-opacity: 0;
|
||||
}
|
||||
|
||||
.anycontext-zoom-in-95 {
|
||||
--tw-enter-scale: 0.95;
|
||||
}
|
||||
|
||||
/* ext.css - Assuming this is your CSS file */
|
||||
|
||||
.anycontext-overlay {
|
||||
position: fixed;
|
||||
|
||||
top: 0;
|
||||
|
||||
left: 0;
|
||||
|
||||
min-height: 100vh;
|
||||
|
||||
width: 100%;
|
||||
|
||||
height: 100%;
|
||||
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
|
||||
z-index: 99998;
|
||||
}
|
||||
|
||||
.anycontext-sidebar {
|
||||
position: fixed;
|
||||
|
||||
top: 0;
|
||||
|
||||
right: 0;
|
||||
|
||||
min-height: 100vh;
|
||||
|
||||
width: 100%;
|
||||
|
||||
max-width: 31%;
|
||||
/* Responsive width */
|
||||
|
||||
z-index: 99999;
|
||||
|
||||
padding: 8px 16px;
|
||||
/* px-4 py-2 */
|
||||
}
|
||||
|
||||
.anycontext-sidebar-content {
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
|
||||
flex-direction: column;
|
||||
|
||||
height: 95vh;
|
||||
|
||||
background-color: white;
|
||||
|
||||
border-radius: 8px;
|
||||
/* rounded-lg */
|
||||
|
||||
padding: 8px;
|
||||
/* px-2 */
|
||||
|
||||
box-shadow:
|
||||
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
/* shadow-md */
|
||||
}
|
||||
|
||||
.anycontext-close-button {
|
||||
position: absolute;
|
||||
|
||||
right: 0;
|
||||
|
||||
padding: 8px;
|
||||
/* p-2 */
|
||||
|
||||
border-radius: 4px;
|
||||
/* rounded-md */
|
||||
|
||||
margin: 8px;
|
||||
/* m-2 */
|
||||
}
|
||||
|
||||
.anycontext-close-button:hover {
|
||||
background-color: rgba(114, 87, 255, 0.5);
|
||||
/* hover:bg-[#7257ff]/50 */
|
||||
|
||||
color: white;
|
||||
/* hover:text-white */
|
||||
}
|
||||
|
||||
.anycontext-open-button {
|
||||
color: white;
|
||||
|
||||
background-color: #7257ff;
|
||||
|
||||
background-opacity: 75%;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
padding: 8px;
|
||||
/* px-4 py-2 */
|
||||
|
||||
border-radius: 4px 0 0 4px;
|
||||
/* rounded-l-md */
|
||||
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.anycontext-header {
|
||||
margin: 16px;
|
||||
/* m-4 */
|
||||
|
||||
font-weight: 600;
|
||||
/* font-semibold */
|
||||
|
||||
font-size: 1.25rem;
|
||||
/* text-xl */
|
||||
|
||||
color: black;
|
||||
}
|
||||
|
||||
.anycontext-icon {
|
||||
height: 24px;
|
||||
/* h-6 */
|
||||
|
||||
width: 24px;
|
||||
/* w-6 */
|
||||
}
|
||||
|
||||
.file\:anycontext-border-0::file-selector-button {
|
||||
border-width: 0px;
|
||||
}
|
||||
|
||||
.file\:anycontext-bg-transparent::file-selector-button {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.file\:anycontext-text-sm::file-selector-button {
|
||||
font-size: 0.875rem;
|
||||
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.file\:anycontext-font-medium::file-selector-button {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.placeholder\:anycontext-text-stone-500::-moz-placeholder {
|
||||
--tw-text-opacity: 1;
|
||||
|
||||
color: rgb(120 113 108 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.placeholder\:anycontext-text-stone-500::placeholder {
|
||||
--tw-text-opacity: 1;
|
||||
|
||||
color: rgb(120 113 108 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hover\:anycontext-bg-red-500\/90:hover {
|
||||
background-color: rgb(239 68 68 / 0.9);
|
||||
}
|
||||
|
||||
.hover\:anycontext-bg-stone-100:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
|
||||
background-color: rgb(245 245 244 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:anycontext-bg-stone-100\/80:hover {
|
||||
background-color: rgb(245 245 244 / 0.8);
|
||||
}
|
||||
|
||||
.hover\:anycontext-bg-stone-900\/90:hover {
|
||||
background-color: rgb(28 25 23 / 0.9);
|
||||
}
|
||||
|
||||
.hover\:anycontext-text-stone-900:hover {
|
||||
--tw-text-opacity: 1;
|
||||
|
||||
color: rgb(28 25 23 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hover\:anycontext-underline:hover {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
.focus-visible\:anycontext-outline-none:focus-visible {
|
||||
outline: 2px solid transparent;
|
||||
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.focus-visible\:anycontext-ring-2:focus-visible {
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0
|
||||
var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
|
||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0
|
||||
calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
|
||||
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow),
|
||||
var(--tw-shadow, 0 0 #0000);
|
||||
}
|
||||
|
||||
.focus-visible\:anycontext-ring-stone-950:focus-visible {
|
||||
--tw-ring-opacity: 1;
|
||||
|
||||
--tw-ring-color: rgb(12 10 9 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
.focus-visible\:anycontext-ring-offset-2:focus-visible {
|
||||
--tw-ring-offset-width: 2px;
|
||||
}
|
||||
|
||||
.disabled\:anycontext-pointer-events-none:disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.disabled\:anycontext-cursor-not-allowed:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.disabled\:anycontext-opacity-30:disabled {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.disabled\:anycontext-opacity-50:disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.data-\[state\=closed\]\:anycontext-animate-out[data-state='closed'] {
|
||||
animation-name: exit;
|
||||
|
||||
animation-duration: 150ms;
|
||||
|
||||
--tw-exit-opacity: initial;
|
||||
|
||||
--tw-exit-scale: initial;
|
||||
|
||||
--tw-exit-rotate: initial;
|
||||
|
||||
--tw-exit-translate-x: initial;
|
||||
|
||||
--tw-exit-translate-y: initial;
|
||||
}
|
||||
|
||||
.data-\[state\=closed\]\:anycontext-fade-out-0[data-state='closed'] {
|
||||
--tw-exit-opacity: 0;
|
||||
}
|
||||
|
||||
.data-\[state\=closed\]\:anycontext-zoom-out-95[data-state='closed'] {
|
||||
--tw-exit-scale: 0.95;
|
||||
}
|
||||
|
||||
.data-\[side\=bottom\]\:anycontext-slide-in-from-top-2[data-side='bottom'] {
|
||||
--tw-enter-translate-y: -0.5rem;
|
||||
}
|
||||
|
||||
.data-\[side\=left\]\:anycontext-slide-in-from-right-2[data-side='left'] {
|
||||
--tw-enter-translate-x: 0.5rem;
|
||||
}
|
||||
|
||||
.data-\[side\=right\]\:anycontext-slide-in-from-left-2[data-side='right'] {
|
||||
--tw-enter-translate-x: -0.5rem;
|
||||
}
|
||||
|
||||
.data-\[side\=top\]\:anycontext-slide-in-from-bottom-2[data-side='top'] {
|
||||
--tw-enter-translate-y: 0.5rem;
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:anycontext-border-stone-800) {
|
||||
--tw-border-opacity: 1;
|
||||
|
||||
border-color: rgb(41 37 36 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:anycontext-bg-red-900) {
|
||||
--tw-bg-opacity: 1;
|
||||
|
||||
background-color: rgb(127 29 29 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:anycontext-bg-stone-50) {
|
||||
--tw-bg-opacity: 1;
|
||||
|
||||
background-color: rgb(250 250 249 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:anycontext-bg-stone-800) {
|
||||
--tw-bg-opacity: 1;
|
||||
|
||||
background-color: rgb(41 37 36 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:anycontext-bg-stone-950) {
|
||||
--tw-bg-opacity: 1;
|
||||
|
||||
background-color: rgb(12 10 9 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:anycontext-text-stone-50) {
|
||||
--tw-text-opacity: 1;
|
||||
|
||||
color: rgb(250 250 249 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:anycontext-text-stone-900) {
|
||||
--tw-text-opacity: 1;
|
||||
|
||||
color: rgb(28 25 23 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:anycontext-ring-offset-stone-950) {
|
||||
--tw-ring-offset-color: #0c0a09;
|
||||
}
|
||||
|
||||
:is(
|
||||
.anycontext-dark .dark\:placeholder\:anycontext-text-stone-400
|
||||
)::-moz-placeholder {
|
||||
--tw-text-opacity: 1;
|
||||
|
||||
color: rgb(168 162 158 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
:is(
|
||||
.anycontext-dark .dark\:placeholder\:anycontext-text-stone-400
|
||||
)::placeholder {
|
||||
--tw-text-opacity: 1;
|
||||
|
||||
color: rgb(168 162 158 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:hover\:anycontext-bg-red-900\/90:hover) {
|
||||
background-color: rgb(127 29 29 / 0.9);
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:hover\:anycontext-bg-stone-50\/90:hover) {
|
||||
background-color: rgb(250 250 249 / 0.9);
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:hover\:anycontext-bg-stone-800:hover) {
|
||||
--tw-bg-opacity: 1;
|
||||
|
||||
background-color: rgb(41 37 36 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:hover\:anycontext-bg-stone-800\/80:hover) {
|
||||
background-color: rgb(41 37 36 / 0.8);
|
||||
}
|
||||
|
||||
:is(.anycontext-dark .dark\:hover\:anycontext-text-stone-50:hover) {
|
||||
--tw-text-opacity: 1;
|
||||
|
||||
color: rgb(250 250 249 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
:is(
|
||||
.anycontext-dark
|
||||
.dark\:focus-visible\:anycontext-ring-stone-300:focus-visible
|
||||
) {
|
||||
--tw-ring-opacity: 1;
|
||||
|
||||
--tw-ring-color: rgb(214 211 209 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* ext.css - Assuming this is your CSS file */
|
||||
.anycontext-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
|
@ -53,7 +52,7 @@
|
|||
|
||||
.anycontext-open-button {
|
||||
color: white;
|
||||
background-color: #7257ff;
|
||||
background-color: #7257ff50; /* bg-indigo-600 */
|
||||
background-opacity: 75%;
|
||||
cursor: pointer;
|
||||
padding: 8px; /* px-4 py-2 */
|
||||
|
|
@ -68,7 +67,6 @@
|
|||
font-weight: 600; /* font-semibold */
|
||||
font-size: 1.25rem; /* text-xl */
|
||||
color: black;
|
||||
|
||||
}
|
||||
|
||||
.anycontext-icon {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { type ClassValue, clsx } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App.tsx";
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { z } from "zod"
|
||||
import { z } from "zod";
|
||||
|
||||
export const userObj = z.object({
|
||||
message: z.string(),
|
||||
|
|
@ -6,14 +6,14 @@ export const userObj = z.object({
|
|||
session: z.object({
|
||||
sessionToken: z.string(),
|
||||
userId: z.string(),
|
||||
expires: z.string()
|
||||
expires: z.string(),
|
||||
}),
|
||||
user: z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
email: z.string().nullable().optional(),
|
||||
emailVerified: z.string().nullable(),
|
||||
image: z.string().nullable().optional()
|
||||
})
|
||||
})
|
||||
})
|
||||
image: z.string().nullable().optional(),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
export const getEnv = () => {
|
||||
// chrome.management.getSelf((self) => {
|
||||
// if (self.installType === 'development') {
|
||||
// return "development"
|
||||
// }
|
||||
// else {
|
||||
// return "production"
|
||||
// }
|
||||
// })
|
||||
// chrome.management.getSelf((self) => {
|
||||
// if (self.installType === 'development') {
|
||||
// return "development"
|
||||
// }
|
||||
// else {
|
||||
// return "production"
|
||||
// }
|
||||
// })
|
||||
|
||||
// return null
|
||||
return 'development'
|
||||
}
|
||||
// return null
|
||||
return "production";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import tailwindcssAnimate from 'tailwindcss-animate';
|
||||
import tailwindcssAnimate from "tailwindcss-animate";
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
darkMode: ["class"],
|
||||
content: [
|
||||
'./pages/**/*.{ts,tsx}',
|
||||
'./components/**/*.{ts,tsx}',
|
||||
'./app/**/*.{ts,tsx}',
|
||||
'./src/**/*.{ts,tsx}',
|
||||
'index.html'
|
||||
"./pages/**/*.{ts,tsx}",
|
||||
"./components/**/*.{ts,tsx}",
|
||||
"./app/**/*.{ts,tsx}",
|
||||
"./src/**/*.{ts,tsx}",
|
||||
"index.html",
|
||||
],
|
||||
prefix: "anycontext-",
|
||||
theme: {
|
||||
|
|
@ -36,4 +36,7 @@ export default {
|
|||
},
|
||||
},
|
||||
plugins: [tailwindcssAnimate],
|
||||
}
|
||||
corePlugins: {
|
||||
preflight: false,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,29 +1,27 @@
|
|||
import { Plugin, defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { crx } from '@crxjs/vite-plugin'
|
||||
import manifest from './manifest.json'
|
||||
import path from 'path'
|
||||
import { Plugin, defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import { crx } from "@crxjs/vite-plugin";
|
||||
import manifest from "./manifest.json";
|
||||
import path from "path";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const viteManifestHackIssue846: Plugin & { renderCrxManifest: (manifest: unknown, bundle: any) => void } = {
|
||||
const viteManifestHackIssue846: Plugin & {
|
||||
renderCrxManifest: (manifest: unknown, bundle: any) => void;
|
||||
} = {
|
||||
// Workaround from https://github.com/crxjs/chrome-extension-tools/issues/846#issuecomment-1861880919.
|
||||
name: 'manifestHackIssue846',
|
||||
name: "manifestHackIssue846",
|
||||
renderCrxManifest(_manifest, bundle) {
|
||||
bundle['manifest.json'] = bundle['.vite/manifest.json']
|
||||
bundle['manifest.json'].fileName = 'manifest.json'
|
||||
delete bundle['.vite/manifest.json']
|
||||
bundle["manifest.json"] = bundle[".vite/manifest.json"];
|
||||
bundle["manifest.json"].fileName = "manifest.json";
|
||||
delete bundle[".vite/manifest.json"];
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
crx({ manifest }),
|
||||
viteManifestHackIssue846
|
||||
],
|
||||
plugins: [react(), crx({ manifest }), viteManifestHackIssue846],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
})
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,7 +3,5 @@
|
|||
"next/core-web-vitals",
|
||||
"plugin:eslint-plugin-next-on-pages/recommended"
|
||||
],
|
||||
"plugins": [
|
||||
"eslint-plugin-next-on-pages"
|
||||
]
|
||||
}
|
||||
"plugins": ["eslint-plugin-next-on-pages"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@ Open [http://localhost:3000](http://localhost:3000) with your browser to see the
|
|||
## Cloudflare integration
|
||||
|
||||
Besides the `dev` script mentioned above `c3` has added a few extra scripts that allow you to integrate the application with the [Cloudflare Pages](https://pages.cloudflare.com/) environment, these are:
|
||||
- `pages:build` to build the application for Pages using the [`@cloudflare/next-on-pages`](https://github.com/cloudflare/next-on-pages) CLI
|
||||
- `preview` to locally preview your Pages application using the [Wrangler](https://developers.cloudflare.com/workers/wrangler/) CLI
|
||||
- `deploy` to deploy your Pages application using the [Wrangler](https://developers.cloudflare.com/workers/wrangler/) CLI
|
||||
|
||||
> __Note:__ while the `dev` script is optimal for local development you should preview your Pages application as well (periodically or before deployments) in order to make sure that it can properly work in the Pages environment (for more details see the [`@cloudflare/next-on-pages` recommended workflow](https://github.com/cloudflare/next-on-pages/blob/05b6256/internal-packages/next-dev/README.md#recommended-workflow))
|
||||
- `pages:build` to build the application for Pages using the [`@cloudflare/next-on-pages`](https://github.com/cloudflare/next-on-pages) CLI
|
||||
- `preview` to locally preview your Pages application using the [Wrangler](https://developers.cloudflare.com/workers/wrangler/) CLI
|
||||
- `deploy` to deploy your Pages application using the [Wrangler](https://developers.cloudflare.com/workers/wrangler/) CLI
|
||||
|
||||
> **Note:** while the `dev` script is optimal for local development you should preview your Pages application as well (periodically or before deployments) in order to make sure that it can properly work in the Pages environment (for more details see the [`@cloudflare/next-on-pages` recommended workflow](https://github.com/cloudflare/next-on-pages/blob/05b6256/internal-packages/next-dev/README.md#recommended-workflow))
|
||||
|
||||
### Bindings
|
||||
|
||||
|
|
@ -35,13 +36,14 @@ You can use bindings during development, when previewing locally your applicatio
|
|||
|
||||
- To use bindings in the preview mode you need to add them to the `pages:preview` script accordingly to the `wrangler pages dev` command. For more details see its [documentation](https://developers.cloudflare.com/workers/wrangler/commands/#dev-1) or the [Pages Bindings documentation](https://developers.cloudflare.com/pages/functions/bindings/).
|
||||
|
||||
- To use bindings in the deployed application you will need to configure them in the Cloudflare [dashboard](https://dash.cloudflare.com/). For more details see the [Pages Bindings documentation](https://developers.cloudflare.com/pages/functions/bindings/).
|
||||
- To use bindings in the deployed application you will need to configure them in the Cloudflare [dashboard](https://dash.cloudflare.com/). For more details see the [Pages Bindings documentation](https://developers.cloudflare.com/pages/functions/bindings/).
|
||||
|
||||
#### KV Example
|
||||
|
||||
`c3` has added for you an example showing how you can use a KV binding.
|
||||
|
||||
In order to enable the example:
|
||||
|
||||
- Search for javascript/typescript lines containing the following comment:
|
||||
```ts
|
||||
// KV Example:
|
||||
|
|
@ -65,4 +67,4 @@ In order to enable the example:
|
|||
|
||||
After doing this you can run the `dev` or `preview` script and visit the `/api/hello` route to see the example in action.
|
||||
|
||||
Finally, if you also want to see the example work in the deployed application make sure to add a `MY_KV_NAMESPACE` binding to your Pages application in its [dashboard kv bindings settings section](https://dash.cloudflare.com/?to=/:account/pages/view/:pages-project/settings/functions#kv_namespace_bindings_section). After having configured it make sure to re-deploy your application.
|
||||
Finally, if you also want to see the example work in the deployed application make sure to add a `MY_KV_NAMESPACE` binding to your Pages application in its [dashboard kv bindings settings section](https://dash.cloudflare.com/?to=/:account/pages/view/:pages-project/settings/functions#kv_namespace_bindings_section). After having configured it make sure to re-deploy your application.
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "default",
|
||||
"rsc": true,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.ts",
|
||||
"css": "src/app/globals.css",
|
||||
"baseColor": "gray",
|
||||
"cssVariables": false
|
||||
},
|
||||
"aliases": {
|
||||
"utils": "@/lib/utils",
|
||||
"components": "@/components"
|
||||
}
|
||||
}
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "default",
|
||||
"rsc": true,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.ts",
|
||||
"css": "src/app/globals.css",
|
||||
"baseColor": "gray",
|
||||
"cssVariables": false
|
||||
},
|
||||
"aliases": {
|
||||
"utils": "@/lib/utils",
|
||||
"components": "@/components"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@ export default {
|
|||
wranglerConfigPath: "./wrangler.toml",
|
||||
dbName: "dev-d1-anycontext",
|
||||
},
|
||||
out: 'drizzle'
|
||||
out: "drizzle",
|
||||
} satisfies Config;
|
||||
|
|
|
|||
18
apps/web/env.d.ts
vendored
|
|
@ -1,12 +1,12 @@
|
|||
declare global {
|
||||
namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
[key: string]: string | undefined;
|
||||
DATABASE: D1Database;
|
||||
VECTORIZE_INDEX: VectorizeIndex;
|
||||
AI: any
|
||||
}
|
||||
namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
[key: string]: string | undefined;
|
||||
DATABASE: D1Database;
|
||||
VECTORIZE_INDEX: VectorizeIndex;
|
||||
AI: any;
|
||||
}
|
||||
}
|
||||
|
||||
export { };
|
||||
}
|
||||
|
||||
export {};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { setupDevPlatform } from '@cloudflare/next-on-pages/next-dev';
|
||||
import { setupDevPlatform } from "@cloudflare/next-on-pages/next-dev";
|
||||
|
||||
// Here we use the @cloudflare/next-on-pages next-dev module to allow us to use bindings during local development
|
||||
// (when running the application with `next dev`), for more information see:
|
||||
// https://github.com/cloudflare/next-on-pages/blob/5712c57ea7/internal-packages/next-dev/README.md
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
await setupDevPlatform();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,4 +51,4 @@
|
|||
"vercel": "^33.6.2",
|
||||
"wrangler": "^3.41.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
apps/web/public/icons/black_without_bg.png
Normal file
|
After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
BIN
apps/web/public/icons/logo_bw_without_bg.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
apps/web/public/icons/logo_without_bg.png
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
apps/web/public/icons/white_without_bg.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
apps/web/public/icons/wordmark.png
Normal file
|
After Width: | Height: | Size: 141 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>
|
||||
|
Before Width: | Height: | Size: 629 B |
|
|
@ -1,21 +1,21 @@
|
|||
'use client';
|
||||
"use client";
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect } from "react";
|
||||
|
||||
function MessagePoster({ jwt }: { jwt: string }) {
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') return;
|
||||
window.postMessage({ jwt }, '*');
|
||||
if (typeof window === "undefined") return;
|
||||
window.postMessage({ jwt }, "*");
|
||||
}, [jwt]);
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={() => {
|
||||
if (typeof window === 'undefined') return;
|
||||
window.postMessage({ jwt }, '*');
|
||||
if (typeof window === "undefined") return;
|
||||
window.postMessage({ jwt }, "*");
|
||||
}}
|
||||
>
|
||||
Send message
|
||||
Extension Auth
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,42 +7,62 @@ import { env } from "@/env";
|
|||
export const runtime = "edge";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const token = req.cookies.get("next-auth.session-token")?.value ?? req.cookies.get("__Secure-authjs.session-token")?.value ?? req.cookies.get("authjs.session-token")?.value ?? req.headers.get("Authorization")?.replace("Bearer ", "");
|
||||
const token =
|
||||
req.cookies.get("next-auth.session-token")?.value ??
|
||||
req.cookies.get("__Secure-authjs.session-token")?.value ??
|
||||
req.cookies.get("authjs.session-token")?.value ??
|
||||
req.headers.get("Authorization")?.replace("Bearer ", "");
|
||||
|
||||
const sessionData = await db.select().from(sessions).where(eq(sessions.sessionToken, token!))
|
||||
const sessionData = await db
|
||||
.select()
|
||||
.from(sessions)
|
||||
.where(eq(sessions.sessionToken, token!));
|
||||
|
||||
if (!sessionData || sessionData.length === 0) {
|
||||
return new Response(JSON.stringify({ message: "Invalid Key, session not found." }), { status: 404 });
|
||||
}
|
||||
if (!sessionData || sessionData.length === 0) {
|
||||
return new Response(
|
||||
JSON.stringify({ message: "Invalid Key, session not found." }),
|
||||
{ status: 404 },
|
||||
);
|
||||
}
|
||||
|
||||
const user = await db.select().from(users).where(eq(users.id, sessionData[0].userId)).limit(1)
|
||||
const user = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, sessionData[0].userId))
|
||||
.limit(1);
|
||||
|
||||
if (!user || user.length === 0) {
|
||||
return NextResponse.json({ message: "Invalid Key, session not found." }, { status: 404 });
|
||||
}
|
||||
if (!user || user.length === 0) {
|
||||
return NextResponse.json(
|
||||
{ message: "Invalid Key, session not found." },
|
||||
{ status: 404 },
|
||||
);
|
||||
}
|
||||
|
||||
const body = await req.json() as {
|
||||
query: string;
|
||||
}
|
||||
const body = (await req.json()) as {
|
||||
query: string;
|
||||
};
|
||||
|
||||
const resp = await fetch(`https://cf-ai-backend.dhravya.workers.dev/ask`, {
|
||||
headers: {
|
||||
"X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
|
||||
},
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
query: body.query,
|
||||
}),
|
||||
})
|
||||
const resp = await fetch(`https://cf-ai-backend.dhravya.workers.dev/ask`, {
|
||||
headers: {
|
||||
"X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
|
||||
},
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
query: body.query,
|
||||
}),
|
||||
});
|
||||
|
||||
if (resp.status !== 200 || !resp.ok) {
|
||||
const errorData = await resp.json();
|
||||
return new Response(JSON.stringify({ message: "Error in CF function", error: errorData }), { status: resp.status });
|
||||
}
|
||||
if (resp.status !== 200 || !resp.ok) {
|
||||
const errorData = await resp.json();
|
||||
return new Response(
|
||||
JSON.stringify({ message: "Error in CF function", error: errorData }),
|
||||
{ status: resp.status },
|
||||
);
|
||||
}
|
||||
|
||||
// Stream the response back to the client
|
||||
const { readable, writable } = new TransformStream();
|
||||
resp && resp.body!.pipeTo(writable);
|
||||
// Stream the response back to the client
|
||||
const { readable, writable } = new TransformStream();
|
||||
resp && resp.body!.pipeTo(writable);
|
||||
|
||||
return new Response(readable, { status: 200 });
|
||||
}
|
||||
return new Response(readable, { status: 200 });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,60 +8,85 @@ import { ChatHistory } from "../../../../types/memory";
|
|||
export const runtime = "edge";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const token = req.cookies.get("next-auth.session-token")?.value ?? req.cookies.get("__Secure-authjs.session-token")?.value ?? req.cookies.get("authjs.session-token")?.value ?? req.headers.get("Authorization")?.replace("Bearer ", "");
|
||||
const token =
|
||||
req.cookies.get("next-auth.session-token")?.value ??
|
||||
req.cookies.get("__Secure-authjs.session-token")?.value ??
|
||||
req.cookies.get("authjs.session-token")?.value ??
|
||||
req.headers.get("Authorization")?.replace("Bearer ", "");
|
||||
|
||||
const sessionData = await db.select().from(sessions).where(eq(sessions.sessionToken, token!))
|
||||
const sessionData = await db
|
||||
.select()
|
||||
.from(sessions)
|
||||
.where(eq(sessions.sessionToken, token!));
|
||||
|
||||
if (!sessionData || sessionData.length === 0) {
|
||||
return new Response(JSON.stringify({ message: "Invalid Key, session not found." }), { status: 404 });
|
||||
}
|
||||
if (!sessionData || sessionData.length === 0) {
|
||||
return new Response(
|
||||
JSON.stringify({ message: "Invalid Key, session not found." }),
|
||||
{ status: 404 },
|
||||
);
|
||||
}
|
||||
|
||||
const user = await db.select().from(users).where(eq(users.id, sessionData[0].userId)).limit(1)
|
||||
const user = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, sessionData[0].userId))
|
||||
.limit(1);
|
||||
|
||||
if (!user || user.length === 0) {
|
||||
return NextResponse.json({ message: "Invalid Key, session not found." }, { status: 404 });
|
||||
}
|
||||
if (!user || user.length === 0) {
|
||||
return NextResponse.json(
|
||||
{ message: "Invalid Key, session not found." },
|
||||
{ status: 404 },
|
||||
);
|
||||
}
|
||||
|
||||
const session = { session: sessionData[0], user: user[0] }
|
||||
const session = { session: sessionData[0], user: user[0] };
|
||||
|
||||
const query = new URL(req.url).searchParams.get("q");
|
||||
const spaces = new URL(req.url).searchParams.get("spaces");
|
||||
const query = new URL(req.url).searchParams.get("q");
|
||||
const spaces = new URL(req.url).searchParams.get("spaces");
|
||||
|
||||
const sourcesOnly = new URL(req.url).searchParams.get("sourcesOnly") ?? "false";
|
||||
const sourcesOnly =
|
||||
new URL(req.url).searchParams.get("sourcesOnly") ?? "false";
|
||||
|
||||
const chatHistory = await req.json() as {
|
||||
chatHistory: ChatHistory[]
|
||||
};
|
||||
const chatHistory = (await req.json()) as {
|
||||
chatHistory: ChatHistory[];
|
||||
};
|
||||
|
||||
console.log("CHathistory", chatHistory)
|
||||
console.log("CHathistory", chatHistory);
|
||||
|
||||
if (!query) {
|
||||
return new Response(JSON.stringify({ message: "Invalid query" }), { status: 400 });
|
||||
}
|
||||
if (!query) {
|
||||
return new Response(JSON.stringify({ message: "Invalid query" }), {
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const resp = await fetch(
|
||||
`https://cf-ai-backend.dhravya.workers.dev/chat?q=${query}&user=${session.user.email ?? session.user.name}&sourcesOnly=${sourcesOnly}&spaces=${spaces}`,
|
||||
{
|
||||
headers: {
|
||||
"X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
|
||||
},
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
chatHistory: chatHistory.chatHistory ?? [],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
const resp = await fetch(`https://cf-ai-backend.dhravya.workers.dev/chat?q=${query}&user=${session.user.email ?? session.user.name}&sourcesOnly=${sourcesOnly}&spaces=${spaces}`, {
|
||||
headers: {
|
||||
"X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
|
||||
},
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
chatHistory: chatHistory.chatHistory ?? []
|
||||
})
|
||||
})
|
||||
console.log(resp.status);
|
||||
console.log(resp.statusText);
|
||||
|
||||
console.log(resp.status)
|
||||
console.log(resp.statusText)
|
||||
if (resp.status !== 200 || !resp.ok) {
|
||||
const errorData = await resp.json();
|
||||
console.log(errorData);
|
||||
return new Response(
|
||||
JSON.stringify({ message: "Error in CF function", error: errorData }),
|
||||
{ status: resp.status },
|
||||
);
|
||||
}
|
||||
|
||||
if (resp.status !== 200 || !resp.ok) {
|
||||
const errorData = await resp.json();
|
||||
console.log(errorData)
|
||||
return new Response(JSON.stringify({ message: "Error in CF function", error: errorData }), { status: resp.status });
|
||||
}
|
||||
// Stream the response back to the client
|
||||
const { readable, writable } = new TransformStream();
|
||||
resp && resp.body!.pipeTo(writable);
|
||||
|
||||
// Stream the response back to the client
|
||||
const { readable, writable } = new TransformStream();
|
||||
resp && resp.body!.pipeTo(writable);
|
||||
|
||||
return new Response(readable, { status: 200 });
|
||||
}
|
||||
return new Response(readable, { status: 200 });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,19 +7,42 @@ import { env } from "@/env";
|
|||
export const runtime = "edge";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const token = req.cookies.get("next-auth.session-token")?.value ?? req.cookies.get("__Secure-authjs.session-token")?.value ?? req.cookies.get("authjs.session-token")?.value ?? req.headers.get("Authorization")?.replace("Bearer ", "");
|
||||
const token =
|
||||
req.cookies.get("next-auth.session-token")?.value ??
|
||||
req.cookies.get("__Secure-authjs.session-token")?.value ??
|
||||
req.cookies.get("authjs.session-token")?.value ??
|
||||
req.headers.get("Authorization")?.replace("Bearer ", "");
|
||||
|
||||
const session = await db.select().from(sessions).where(eq(sessions.sessionToken, token!))
|
||||
const session = await db
|
||||
.select()
|
||||
.from(sessions)
|
||||
.where(eq(sessions.sessionToken, token!));
|
||||
|
||||
if (!session || session.length === 0) {
|
||||
return new Response(JSON.stringify({ message: "Invalid Key, session not found." }), { status: 404 });
|
||||
}
|
||||
if (!session || session.length === 0) {
|
||||
return new Response(
|
||||
JSON.stringify({ message: "Invalid Key, session not found." }),
|
||||
{ status: 404 },
|
||||
);
|
||||
}
|
||||
|
||||
const user = await db.select().from(users).where(eq(users.id, session[0].userId)).limit(1)
|
||||
const user = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, session[0].userId))
|
||||
.limit(1);
|
||||
|
||||
if (!user || user.length === 0) {
|
||||
return NextResponse.json({ message: "Invalid Key, session not found." }, { status: 404 });
|
||||
}
|
||||
if (!user || user.length === 0) {
|
||||
return NextResponse.json(
|
||||
{ message: "Invalid Key, session not found." },
|
||||
{ status: 404 },
|
||||
);
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ message: "OK", data: { session: session[0], user: user[0] } }), { status: 200 });
|
||||
}
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
message: "OK",
|
||||
data: { session: session[0], user: user[0] },
|
||||
}),
|
||||
{ status: 200 },
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,46 +7,72 @@ import { env } from "@/env";
|
|||
export const runtime = "edge";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const token = req.cookies.get("next-auth.session-token")?.value ?? req.cookies.get("__Secure-authjs.session-token")?.value ?? req.cookies.get("authjs.session-token")?.value ?? req.headers.get("Authorization")?.replace("Bearer ", "");
|
||||
const token =
|
||||
req.cookies.get("next-auth.session-token")?.value ??
|
||||
req.cookies.get("__Secure-authjs.session-token")?.value ??
|
||||
req.cookies.get("authjs.session-token")?.value ??
|
||||
req.headers.get("Authorization")?.replace("Bearer ", "");
|
||||
|
||||
const sessionData = await db.select().from(sessions).where(eq(sessions.sessionToken, token!))
|
||||
const sessionData = await db
|
||||
.select()
|
||||
.from(sessions)
|
||||
.where(eq(sessions.sessionToken, token!));
|
||||
|
||||
if (!sessionData || sessionData.length === 0) {
|
||||
return new Response(JSON.stringify({ message: "Invalid Key, session not found." }), { status: 404 });
|
||||
}
|
||||
if (!sessionData || sessionData.length === 0) {
|
||||
return new Response(
|
||||
JSON.stringify({ message: "Invalid Key, session not found." }),
|
||||
{ status: 404 },
|
||||
);
|
||||
}
|
||||
|
||||
const user = await db.select().from(users).where(eq(users.id, sessionData[0].userId)).limit(1)
|
||||
const user = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, sessionData[0].userId))
|
||||
.limit(1);
|
||||
|
||||
if (!user || user.length === 0) {
|
||||
return NextResponse.json({ message: "Invalid Key, session not found." }, { status: 404 });
|
||||
}
|
||||
if (!user || user.length === 0) {
|
||||
return NextResponse.json(
|
||||
{ message: "Invalid Key, session not found." },
|
||||
{ status: 404 },
|
||||
);
|
||||
}
|
||||
|
||||
const session = { session: sessionData[0], user: user[0] }
|
||||
const session = { session: sessionData[0], user: user[0] };
|
||||
|
||||
const query = new URL(req.url).searchParams.get("q");
|
||||
const sourcesOnly = new URL(req.url).searchParams.get("sourcesOnly") ?? "false";
|
||||
const query = new URL(req.url).searchParams.get("q");
|
||||
const sourcesOnly =
|
||||
new URL(req.url).searchParams.get("sourcesOnly") ?? "false";
|
||||
|
||||
if (!query) {
|
||||
return new Response(JSON.stringify({ message: "Invalid query" }), { status: 400 });
|
||||
}
|
||||
if (!query) {
|
||||
return new Response(JSON.stringify({ message: "Invalid query" }), {
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const resp = await fetch(`https://cf-ai-backend.dhravya.workers.dev/query?q=${query}&user=${session.user.email ?? session.user.name}&sourcesOnly=${sourcesOnly}`, {
|
||||
headers: {
|
||||
"X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
|
||||
}
|
||||
})
|
||||
const resp = await fetch(
|
||||
`https://cf-ai-backend.dhravya.workers.dev/query?q=${query}&user=${session.user.email ?? session.user.name}&sourcesOnly=${sourcesOnly}`,
|
||||
{
|
||||
headers: {
|
||||
"X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
console.log(resp.status)
|
||||
console.log(resp.status);
|
||||
|
||||
if (resp.status !== 200 || !resp.ok) {
|
||||
const errorData = await resp.json();
|
||||
console.log(errorData)
|
||||
return new Response(JSON.stringify({ message: "Error in CF function", error: errorData }), { status: resp.status });
|
||||
}
|
||||
if (resp.status !== 200 || !resp.ok) {
|
||||
const errorData = await resp.json();
|
||||
console.log(errorData);
|
||||
return new Response(
|
||||
JSON.stringify({ message: "Error in CF function", error: errorData }),
|
||||
{ status: resp.status },
|
||||
);
|
||||
}
|
||||
|
||||
// Stream the response back to the client
|
||||
const { readable, writable } = new TransformStream();
|
||||
resp && resp.body!.pipeTo(writable);
|
||||
// Stream the response back to the client
|
||||
const { readable, writable } = new TransformStream();
|
||||
resp && resp.body!.pipeTo(writable);
|
||||
|
||||
return new Response(readable, { status: 200 });
|
||||
}
|
||||
return new Response(readable, { status: 200 });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
import { db } from "@/server/db";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { contentToSpace, sessions, storedContent, users, space } from "@/server/db/schema";
|
||||
import {
|
||||
contentToSpace,
|
||||
sessions,
|
||||
storedContent,
|
||||
users,
|
||||
space,
|
||||
} from "@/server/db/schema";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { env } from "@/env";
|
||||
import { getMetaData } from "@/server/helpers";
|
||||
|
|
@ -8,94 +14,123 @@ import { getMetaData } from "@/server/helpers";
|
|||
export const runtime = "edge";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const token = req.cookies.get("next-auth.session-token")?.value ?? req.cookies.get("__Secure-authjs.session-token")?.value ?? req.cookies.get("authjs.session-token")?.value ?? req.headers.get("Authorization")?.replace("Bearer ", "");
|
||||
const token =
|
||||
req.cookies.get("next-auth.session-token")?.value ??
|
||||
req.cookies.get("__Secure-authjs.session-token")?.value ??
|
||||
req.cookies.get("authjs.session-token")?.value ??
|
||||
req.headers.get("Authorization")?.replace("Bearer ", "");
|
||||
|
||||
if (!token) {
|
||||
return new Response(JSON.stringify({ message: "Invalid Key, session not found." }), { status: 404 });
|
||||
}
|
||||
if (!token) {
|
||||
return new Response(
|
||||
JSON.stringify({ message: "Invalid Key, session not found." }),
|
||||
{ status: 404 },
|
||||
);
|
||||
}
|
||||
|
||||
const sessionData = await db.select().from(sessions).where(eq(sessions.sessionToken, token!))
|
||||
const sessionData = await db
|
||||
.select()
|
||||
.from(sessions)
|
||||
.where(eq(sessions.sessionToken, token!));
|
||||
|
||||
if (!sessionData || sessionData.length === 0) {
|
||||
return new Response(JSON.stringify({ message: "Invalid Key, session not found." }), { status: 404 });
|
||||
}
|
||||
if (!sessionData || sessionData.length === 0) {
|
||||
return new Response(
|
||||
JSON.stringify({ message: "Invalid Key, session not found." }),
|
||||
{ status: 404 },
|
||||
);
|
||||
}
|
||||
|
||||
const user = await db.select().from(users).where(eq(users.id, sessionData[0].userId)).limit(1)
|
||||
const user = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, sessionData[0].userId))
|
||||
.limit(1);
|
||||
|
||||
if (!user || user.length === 0) {
|
||||
return NextResponse.json({ message: "Invalid Key, session not found." }, { status: 404 });
|
||||
}
|
||||
if (!user || user.length === 0) {
|
||||
return NextResponse.json(
|
||||
{ message: "Invalid Key, session not found." },
|
||||
{ status: 404 },
|
||||
);
|
||||
}
|
||||
|
||||
const session = { session: sessionData[0], user: user[0] }
|
||||
const session = { session: sessionData[0], user: user[0] };
|
||||
|
||||
const data = await req.json() as {
|
||||
pageContent: string,
|
||||
url: string,
|
||||
space?: string
|
||||
};
|
||||
const data = (await req.json()) as {
|
||||
pageContent: string;
|
||||
url: string;
|
||||
space?: string;
|
||||
};
|
||||
|
||||
const metadata = await getMetaData(data.url);
|
||||
const metadata = await getMetaData(data.url);
|
||||
|
||||
let id: number | undefined = undefined;
|
||||
|
||||
let id: number | undefined = undefined;
|
||||
let storeToSpace = data.space;
|
||||
|
||||
let storeToSpace = data.space
|
||||
if (!storeToSpace) {
|
||||
storeToSpace = "all";
|
||||
}
|
||||
|
||||
if (!storeToSpace) {
|
||||
storeToSpace = 'all'
|
||||
}
|
||||
const storedContentId = await db.insert(storedContent).values({
|
||||
content: data.pageContent,
|
||||
title: metadata.title,
|
||||
description: metadata.description,
|
||||
url: data.url,
|
||||
baseUrl: metadata.baseUrl,
|
||||
image: metadata.image,
|
||||
savedAt: new Date(),
|
||||
user: session.user.id,
|
||||
});
|
||||
|
||||
const storedContentId = await db.insert(storedContent).values({
|
||||
content: data.pageContent,
|
||||
title: metadata.title,
|
||||
description: metadata.description,
|
||||
url: data.url,
|
||||
baseUrl: metadata.baseUrl,
|
||||
image: metadata.image,
|
||||
savedAt: new Date(),
|
||||
user: session.user.id
|
||||
})
|
||||
id = storedContentId.meta.last_row_id;
|
||||
|
||||
id = storedContentId.meta.last_row_id;
|
||||
if (!id) {
|
||||
return NextResponse.json(
|
||||
{ message: "Error", error: "Error in CF function" },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ message: "Error", error: "Error in CF function" }, { status: 500 });
|
||||
}
|
||||
let spaceID = 0;
|
||||
|
||||
let spaceID = 0;
|
||||
const spaceData = await db
|
||||
.select()
|
||||
.from(space)
|
||||
.where(and(eq(space.name, storeToSpace), eq(space.user, session.user.id)))
|
||||
.limit(1);
|
||||
spaceID = spaceData[0]?.id;
|
||||
|
||||
const spaceData = await db.select().from(space).where(and(eq(space.name, storeToSpace), eq(space.user, session.user.id))).limit(1)
|
||||
spaceID = spaceData[0]?.id
|
||||
if (!spaceData || spaceData.length === 0) {
|
||||
const spaceId = await db.insert(space).values({
|
||||
name: storeToSpace,
|
||||
user: session.user.id,
|
||||
});
|
||||
spaceID = spaceId.meta.last_row_id;
|
||||
}
|
||||
|
||||
if (!spaceData || spaceData.length === 0) {
|
||||
const spaceId = await db.insert(space).values({
|
||||
name: storeToSpace,
|
||||
user: session.user.id
|
||||
})
|
||||
spaceID = spaceId.meta.last_row_id;
|
||||
}
|
||||
await db.insert(contentToSpace).values({
|
||||
contentId: id as number,
|
||||
spaceId: spaceID,
|
||||
});
|
||||
|
||||
await db.insert(contentToSpace).values({
|
||||
contentId: id as number,
|
||||
spaceId: spaceID
|
||||
})
|
||||
const res = (await Promise.race([
|
||||
fetch("https://cf-ai-backend.dhravya.workers.dev/add", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
|
||||
},
|
||||
body: JSON.stringify({ ...data, user: session.user.email }),
|
||||
}),
|
||||
new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error("Request timed out")), 40000),
|
||||
),
|
||||
])) as Response;
|
||||
|
||||
const res = await Promise.race([
|
||||
fetch("https://cf-ai-backend.dhravya.workers.dev/add", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
|
||||
},
|
||||
body: JSON.stringify({ ...data, user: session.user.email }),
|
||||
}),
|
||||
new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error('Request timed out')), 40000)
|
||||
)
|
||||
]) as Response
|
||||
if (res.status !== 200) {
|
||||
return NextResponse.json(
|
||||
{ message: "Error", error: "Error in CF function" },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
if (res.status !== 200) {
|
||||
return NextResponse.json({ message: "Error", error: "Error in CF function" }, { status: 500 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: "OK", data: "Success" }, { status: 200 });
|
||||
}
|
||||
return NextResponse.json({ message: "OK", data: "Success" }, { status: 200 });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
'use client';
|
||||
import Main from '@/components/Main';
|
||||
import Sidebar from '@/components/Sidebar/index';
|
||||
import { SessionProvider } from 'next-auth/react';
|
||||
import { useState } from 'react';
|
||||
"use client";
|
||||
import Main from "@/components/Main";
|
||||
import Sidebar from "@/components/Sidebar/index";
|
||||
import { SessionProvider } from "next-auth/react";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function Content() {
|
||||
export default function Content({ jwt }: { jwt: string }) {
|
||||
const [selectedItem, setSelectedItem] = useState<string | null>(null);
|
||||
|
||||
return (
|
||||
<SessionProvider>
|
||||
<div className="flex w-screen">
|
||||
<Sidebar selectChange={setSelectedItem} />
|
||||
<Sidebar jwt={jwt} selectChange={setSelectedItem} />
|
||||
<Main sidebarOpen={selectedItem !== null} />
|
||||
</div>
|
||||
</SessionProvider>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
}
|
||||
|
||||
body {
|
||||
@apply bg-rgray-2 text-rgray-11 max-h-screen overflow-y-hidden;
|
||||
@apply text-rgray-11 max-h-screen overflow-y-hidden bg-white;
|
||||
/* color: rgb(var(--foreground-rgb));
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
|
|
@ -66,7 +66,7 @@ body {
|
|||
}
|
||||
|
||||
.chat-answer h1 {
|
||||
@apply text-rgray-11 text-xl font-medium my-5;
|
||||
@apply text-rgray-11 my-5 text-xl font-medium;
|
||||
}
|
||||
|
||||
.chat-answer img {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import type { Metadata } from "next";
|
||||
import { Roboto } from "next/font/google";
|
||||
import { Roboto, Inter } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const roboto = Roboto({ weight: ["300", "400", "500"], subsets: ["latin"] });
|
||||
const inter = Inter({ weight: ["300", "400", "500"], subsets: ["latin"] });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
|
|
@ -16,7 +17,7 @@ export default function RootLayout({
|
|||
}>) {
|
||||
return (
|
||||
<html lang="en" className="dark">
|
||||
<body className={roboto.className}>
|
||||
<body className={inter.className}>
|
||||
<div vaul-drawer-wrapper="" className="min-w-screen overflow-x-hidden">
|
||||
{children}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -59,26 +59,26 @@ export default async function Home() {
|
|||
const collectedSpaces =
|
||||
contents.length > 0 ? await transformContent(contents) : [];
|
||||
|
||||
collectedSpaces.push({
|
||||
id: 2,
|
||||
title: "Test",
|
||||
content: [
|
||||
{
|
||||
id: 1,
|
||||
content: "Test",
|
||||
title: "Vscode",
|
||||
description: "Test",
|
||||
url: "https://vscode-remake.vercel.app/",
|
||||
savedAt: new Date(),
|
||||
baseUrl: "https://vscode-remake.vercel.app/",
|
||||
image: "https://vscode-remake.vercel.app/favicon.svg",
|
||||
},
|
||||
],
|
||||
});
|
||||
// collectedSpaces.push({
|
||||
// id: 2,
|
||||
// title: "Test",
|
||||
// content: [
|
||||
// {
|
||||
// id: 1,
|
||||
// content: "Test",
|
||||
// title: "Vscode",
|
||||
// description: "Test",
|
||||
// url: "https://vscode-remake.vercel.app/",
|
||||
// savedAt: new Date(),
|
||||
// baseUrl: "https://vscode-remake.vercel.app/",
|
||||
// image: "https://vscode-remake.vercel.app/favicon.svg",
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
return (
|
||||
<MemoryProvider spaces={collectedSpaces}>
|
||||
<Content />
|
||||
<Content jwt={token} />
|
||||
{/* <MessagePoster jwt={token} /> */}
|
||||
</MemoryProvider>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import Markdown from 'react-markdown';
|
||||
import { policy } from './privacy';
|
||||
import React from "react";
|
||||
import Markdown from "react-markdown";
|
||||
import { policy } from "./privacy";
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -46,4 +46,4 @@ If you have any questions about this Privacy Policy, the practices of this site,
|
|||
|
||||
- Email: dhravyashah@gmail.com
|
||||
|
||||
This document was last updated on March 2, 2024.`
|
||||
This document was last updated on March 2, 2024.`;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { ChatHistory } from "../../types/memory";
|
|||
import { ChatAnswer, ChatMessage, ChatQuestion } from "./ChatMessage";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { useMemory } from "@/contexts/MemoryContext";
|
||||
import WordMark from "./WordMark";
|
||||
|
||||
function supportsDVH() {
|
||||
try {
|
||||
|
|
@ -293,8 +294,8 @@ export default function Main({ sidebarOpen }: { sidebarOpen: boolean }) {
|
|||
hide ? "" : "main-hidden",
|
||||
)}
|
||||
>
|
||||
<h1 className="text-rgray-11 mt-auto w-full text-center text-3xl md:mt-0">
|
||||
Ask your Second brain
|
||||
<h1 className="text-rgray-11 mt-auto w-full text-center text-3xl font-bold tracking-tight md:mt-0">
|
||||
Ask your second brain
|
||||
</h1>
|
||||
|
||||
<Textarea2
|
||||
|
|
@ -308,14 +309,13 @@ export default function Main({ sidebarOpen }: { sidebarOpen: boolean }) {
|
|||
duration: 0.2,
|
||||
}}
|
||||
textAreaProps={{
|
||||
placeholder: "Ask your SuperMemory...",
|
||||
placeholder: "Ask your second brain...",
|
||||
className:
|
||||
"h-auto overflow-auto md:h-full md:resize-none text-lg py-0 px-2 pt-2 md:py-0 md:p-5 resize-y text-rgray-11 w-full min-h-[1em]",
|
||||
value,
|
||||
autoFocus: true,
|
||||
onChange: (e) => setValue(e.target.value),
|
||||
onKeyDown: (e) => {
|
||||
console.log(e.key, e.ctrlKey, e.metaKey);
|
||||
if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
|
||||
onSend();
|
||||
}
|
||||
|
|
|
|||
139
apps/web/src/components/QueryAI.tsx
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
"use client";
|
||||
|
||||
import { Label } from "./ui/label";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Input } from "./ui/input";
|
||||
import { Button } from "./ui/button";
|
||||
import SearchResults from "./SearchResults";
|
||||
|
||||
function QueryAI() {
|
||||
const [searchResults, setSearchResults] = useState<string[]>([]);
|
||||
const [isAiLoading, setIsAiLoading] = useState(false);
|
||||
|
||||
const [aiResponse, setAIResponse] = useState("");
|
||||
const [input, setInput] = useState("");
|
||||
const [toBeParsed, setToBeParsed] = useState("");
|
||||
|
||||
const handleStreamData = (newChunk: string) => {
|
||||
// Append the new chunk to the existing data to be parsed
|
||||
setToBeParsed((prev) => prev + newChunk);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// Define a function to try parsing the accumulated data
|
||||
const tryParseAccumulatedData = () => {
|
||||
// Attempt to parse the "toBeParsed" state as JSON
|
||||
try {
|
||||
// Split the accumulated data by the known delimiter "\n\n"
|
||||
const parts = toBeParsed.split("\n\n");
|
||||
let remainingData = "";
|
||||
|
||||
// Process each part to extract JSON objects
|
||||
parts.forEach((part, index) => {
|
||||
try {
|
||||
const parsedPart = JSON.parse(part.replace("data: ", "")); // Try to parse the part as JSON
|
||||
|
||||
// If the part is the last one and couldn't be parsed, keep it to accumulate more data
|
||||
if (index === parts.length - 1 && !parsedPart) {
|
||||
remainingData = part;
|
||||
} else if (parsedPart && parsedPart.response) {
|
||||
// If the part is parsable and has the "response" field, update the AI response state
|
||||
setAIResponse((prev) => prev + parsedPart.response);
|
||||
}
|
||||
} catch (error) {
|
||||
// If parsing fails and it's not the last part, it's a malformed JSON
|
||||
if (index !== parts.length - 1) {
|
||||
console.error("Malformed JSON part: ", part);
|
||||
} else {
|
||||
// If it's the last part, it may be incomplete, so keep it
|
||||
remainingData = part;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Update the toBeParsed state to only contain the unparsed remainder
|
||||
if (remainingData !== toBeParsed) {
|
||||
setToBeParsed(remainingData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error parsing accumulated data: ", error);
|
||||
}
|
||||
};
|
||||
|
||||
// Call the parsing function if there's data to be parsed
|
||||
if (toBeParsed) {
|
||||
tryParseAccumulatedData();
|
||||
}
|
||||
}, [toBeParsed]);
|
||||
|
||||
const getSearchResults = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
setIsAiLoading(true);
|
||||
|
||||
const sourcesResponse = await fetch(
|
||||
`/api/query?sourcesOnly=true&q=${input}`,
|
||||
);
|
||||
|
||||
const sourcesInJson = (await sourcesResponse.json()) as {
|
||||
ids: string[];
|
||||
};
|
||||
|
||||
setSearchResults(sourcesInJson.ids);
|
||||
|
||||
const response = await fetch(`/api/query?q=${input}`);
|
||||
|
||||
if (response.status !== 200) {
|
||||
setIsAiLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.body) {
|
||||
let reader = response.body.getReader();
|
||||
let decoder = new TextDecoder("utf-8");
|
||||
let result = "";
|
||||
|
||||
// @ts-ignore
|
||||
reader.read().then(function processText({ done, value }) {
|
||||
if (done) {
|
||||
// setSearchResults(JSON.parse(result.replace('data: ', '')));
|
||||
// setIsAiLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
handleStreamData(decoder.decode(value));
|
||||
|
||||
return reader.read().then(processText);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-2xl">
|
||||
<form onSubmit={async (e) => await getSearchResults(e)} className="mt-8">
|
||||
<Label htmlFor="searchInput">Ask your SuperMemory</Label>
|
||||
<div className="flex flex-col space-y-2 md:w-full md:flex-row md:items-center md:space-x-2 md:space-y-0">
|
||||
<Input
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
placeholder="Search using AI... ✨"
|
||||
id="searchInput"
|
||||
/>
|
||||
<Button
|
||||
disabled={isAiLoading}
|
||||
className="max-w-min md:w-full"
|
||||
type="submit"
|
||||
variant="default"
|
||||
>
|
||||
Ask AI
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{searchResults && (
|
||||
<SearchResults aiResponse={aiResponse} sources={searchResults} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default QueryAI;
|
||||
40
apps/web/src/components/SearchResults.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { Card, CardContent } from "./ui/card";
|
||||
import Markdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
|
||||
function SearchResults({
|
||||
aiResponse,
|
||||
sources,
|
||||
}: {
|
||||
aiResponse: string;
|
||||
sources: string[];
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: `linear-gradient(to right, #E5D9F2, #CDC1FF)`,
|
||||
}}
|
||||
className="mx-auto mt-4 w-full max-w-2xl space-y-6 rounded-xl border px-4 py-6"
|
||||
>
|
||||
<div className="text-start">
|
||||
<div className="text-xl text-black">
|
||||
<Markdown remarkPlugins={[remarkGfm]}>
|
||||
{aiResponse.replace("</s>", "")}
|
||||
</Markdown>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-6">
|
||||
{sources.map((value, index) => (
|
||||
<Card key={index}>
|
||||
<CardContent className="space-y-2">{value}</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SearchResults;
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
'use client';
|
||||
import { cleanUrl } from '@/lib/utils';
|
||||
import { StoredContent } from '@/server/db/schema';
|
||||
"use client";
|
||||
import { cleanUrl } from "@/lib/utils";
|
||||
import { StoredContent } from "@/server/db/schema";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
} from '../ui/dropdown-menu';
|
||||
import { Label } from '../ui/label';
|
||||
} from "../ui/dropdown-menu";
|
||||
import { Label } from "../ui/label";
|
||||
import {
|
||||
ArrowUpRight,
|
||||
MoreHorizontal,
|
||||
|
|
@ -19,8 +19,8 @@ import {
|
|||
ChevronRight,
|
||||
Plus,
|
||||
Minus,
|
||||
} from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Drawer,
|
||||
DrawerContent,
|
||||
|
|
@ -29,106 +29,106 @@ import {
|
|||
DrawerDescription,
|
||||
DrawerFooter,
|
||||
DrawerClose,
|
||||
} from '../ui/drawer';
|
||||
import { Input } from '../ui/input';
|
||||
import { Textarea } from '../ui/textarea';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
|
||||
} from "../ui/drawer";
|
||||
import { Input } from "../ui/input";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
||||
import {
|
||||
AnimatePresence,
|
||||
motion,
|
||||
Reorder,
|
||||
useMotionValue,
|
||||
} from 'framer-motion';
|
||||
} from "framer-motion";
|
||||
|
||||
const pages: StoredContent[] = [
|
||||
{
|
||||
id: 1,
|
||||
content: '',
|
||||
title: 'Visual Studio Code',
|
||||
url: 'https://code.visualstudio.com',
|
||||
description: '',
|
||||
image: 'https://code.visualstudio.com/favicon.ico',
|
||||
baseUrl: 'https://code.visualstudio.com',
|
||||
content: "",
|
||||
title: "Visual Studio Code",
|
||||
url: "https://code.visualstudio.com",
|
||||
description: "",
|
||||
image: "https://code.visualstudio.com/favicon.ico",
|
||||
baseUrl: "https://code.visualstudio.com",
|
||||
savedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
content: '',
|
||||
content: "",
|
||||
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
|
||||
url: 'https://github.com/yxshv/vscode',
|
||||
description: '',
|
||||
image: 'https://github.com/favicon.ico',
|
||||
baseUrl: 'https://github.com',
|
||||
url: "https://github.com/yxshv/vscode",
|
||||
description: "",
|
||||
image: "https://github.com/favicon.ico",
|
||||
baseUrl: "https://github.com",
|
||||
savedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
content: '',
|
||||
content: "",
|
||||
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
|
||||
url: 'https://github.com/yxshv/vscode',
|
||||
description: '',
|
||||
image: 'https://github.com/favicon.ico',
|
||||
baseUrl: 'https://github.com',
|
||||
url: "https://github.com/yxshv/vscode",
|
||||
description: "",
|
||||
image: "https://github.com/favicon.ico",
|
||||
baseUrl: "https://github.com",
|
||||
savedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
content: '',
|
||||
content: "",
|
||||
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
|
||||
url: 'https://github.com/yxshv/vscode',
|
||||
description: '',
|
||||
image: 'https://github.com/favicon.ico',
|
||||
baseUrl: 'https://github.com',
|
||||
url: "https://github.com/yxshv/vscode",
|
||||
description: "",
|
||||
image: "https://github.com/favicon.ico",
|
||||
baseUrl: "https://github.com",
|
||||
savedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
content: '',
|
||||
content: "",
|
||||
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
|
||||
url: 'https://github.com/yxshv/vscode',
|
||||
description: '',
|
||||
image: 'https://github.com/favicon.ico',
|
||||
baseUrl: 'https://github.com',
|
||||
url: "https://github.com/yxshv/vscode",
|
||||
description: "",
|
||||
image: "https://github.com/favicon.ico",
|
||||
baseUrl: "https://github.com",
|
||||
savedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
content: '',
|
||||
content: "",
|
||||
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
|
||||
url: 'https://github.com/yxshv/vscode',
|
||||
description: '',
|
||||
image: 'https://github.com/favicon.ico',
|
||||
baseUrl: 'https://github.com',
|
||||
url: "https://github.com/yxshv/vscode",
|
||||
description: "",
|
||||
image: "https://github.com/favicon.ico",
|
||||
baseUrl: "https://github.com",
|
||||
savedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
content: '',
|
||||
content: "",
|
||||
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
|
||||
url: 'https://github.com/yxshv/vscode',
|
||||
description: '',
|
||||
image: 'https://github.com/favicon.ico',
|
||||
baseUrl: 'https://github.com',
|
||||
url: "https://github.com/yxshv/vscode",
|
||||
description: "",
|
||||
image: "https://github.com/favicon.ico",
|
||||
baseUrl: "https://github.com",
|
||||
savedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
content: '',
|
||||
content: "",
|
||||
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
|
||||
url: 'https://github.com/yxshv/vscode',
|
||||
description: '',
|
||||
image: 'https://github.com/favicon.ico',
|
||||
baseUrl: 'https://github.com',
|
||||
url: "https://github.com/yxshv/vscode",
|
||||
description: "",
|
||||
image: "https://github.com/favicon.ico",
|
||||
baseUrl: "https://github.com",
|
||||
savedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
content: '',
|
||||
content: "",
|
||||
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
|
||||
url: 'https://github.com/yxshv/vscode',
|
||||
description: '',
|
||||
image: 'https://github.com/favicon.ico',
|
||||
baseUrl: 'https://github.com',
|
||||
url: "https://github.com/yxshv/vscode",
|
||||
description: "",
|
||||
image: "https://github.com/favicon.ico",
|
||||
baseUrl: "https://github.com",
|
||||
savedAt: new Date(),
|
||||
},
|
||||
];
|
||||
|
|
@ -153,13 +153,13 @@ export const CategoryItem: React.FC<{ item: StoredContent }> = ({ item }) => {
|
|||
/>
|
||||
<ChevronDown
|
||||
data-down-icon
|
||||
className={`absolute left-1/2 top-1/2 z-[2] h-4 w-4 min-w-4 -translate-x-1/2 -translate-y-1/2 scale-75 opacity-0 transition-[transform,opacity] duration-150 ${isExpanded ? 'rotate-180' : 'rotate-0'}`}
|
||||
className={`absolute left-1/2 top-1/2 z-[2] h-4 w-4 min-w-4 -translate-x-1/2 -translate-y-1/2 scale-75 opacity-0 transition-[transform,opacity] duration-150 ${isExpanded ? "rotate-180" : "rotate-0"}`}
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<span className="w-full truncate text-nowrap text-left">
|
||||
{item.title ?? 'Untitled website'}
|
||||
{item.title ?? "Untitled website"}
|
||||
</span>
|
||||
</button>
|
||||
<Drawer
|
||||
|
|
@ -178,7 +178,7 @@ export const CategoryItem: React.FC<{ item: StoredContent }> = ({ item }) => {
|
|||
href={item.url}
|
||||
className="text-rgray-11/90 bg-rgray-3 text-md absolute right-0 top-0 flex w-min translate-y-1/2 items-center justify-center gap-1 rounded-full px-5 py-1"
|
||||
>
|
||||
<img src={item.image ?? '/brain.png'} className="h-4 w-4" />
|
||||
<img src={item.image ?? "/brain.png"} className="h-4 w-4" />
|
||||
{cleanUrl(item.url)}
|
||||
</a>
|
||||
</DrawerHeader>
|
||||
|
|
@ -188,16 +188,16 @@ export const CategoryItem: React.FC<{ item: StoredContent }> = ({ item }) => {
|
|||
<Input
|
||||
className=""
|
||||
required
|
||||
value={item.title ?? ''}
|
||||
placeholder={item.title ?? 'Enter the title for the page'}
|
||||
value={item.title ?? ""}
|
||||
placeholder={item.title ?? "Enter the title for the page"}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Label>Additional Context</Label>
|
||||
<Textarea
|
||||
className=""
|
||||
value={item.content ?? ''}
|
||||
placeholder={'Enter additional context for this page'}
|
||||
value={item.content ?? ""}
|
||||
placeholder={"Enter additional context for this page"}
|
||||
/>
|
||||
</div>
|
||||
<DrawerFooter className="flex flex-row-reverse items-center justify-end px-0 pt-5">
|
||||
|
|
@ -224,7 +224,7 @@ export const CategoryItem: React.FC<{ item: StoredContent }> = ({ item }) => {
|
|||
onReorder={setItems}
|
||||
as="div"
|
||||
initial={{ height: 0 }}
|
||||
animate={{ height: 'auto' }}
|
||||
animate={{ height: "auto" }}
|
||||
exit={{
|
||||
height: 0,
|
||||
transition: {},
|
||||
|
|
@ -272,8 +272,8 @@ export const CategoryPage: React.FC<{
|
|||
>
|
||||
<div className="relative h-4 min-w-4">
|
||||
<img
|
||||
src={item.image ?? '/brain.png'}
|
||||
alt={item.title ?? 'Untitiled website'}
|
||||
src={item.image ?? "/brain.png"}
|
||||
alt={item.title ?? "Untitiled website"}
|
||||
className="z-1 h-4 w-4 transition-[transform,opacity] delay-150 duration-150"
|
||||
/>
|
||||
<ArrowUpRight
|
||||
|
|
@ -284,7 +284,7 @@ export const CategoryPage: React.FC<{
|
|||
</div>
|
||||
|
||||
<span className="w-full truncate text-nowrap">
|
||||
{item.title ?? 'Untitled website'}
|
||||
{item.title ?? "Untitled website"}
|
||||
</span>
|
||||
</a>
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
'use client';
|
||||
"use client";
|
||||
|
||||
import * as React from 'react';
|
||||
import { Check, ChevronsUpDown } from 'lucide-react';
|
||||
import * as React from "react";
|
||||
import { Check, ChevronsUpDown } from "lucide-react";
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
|
|
@ -12,28 +12,30 @@ import {
|
|||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@/components/ui/command';
|
||||
} from "@/components/ui/command";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover';
|
||||
import { SpaceIcon } from '@/assets/Memories';
|
||||
import { AnimatePresence, LayoutGroup, motion } from 'framer-motion';
|
||||
import { useMemory } from '@/contexts/MemoryContext';
|
||||
} from "@/components/ui/popover";
|
||||
import { SpaceIcon } from "@/assets/Memories";
|
||||
import { AnimatePresence, LayoutGroup, motion } from "framer-motion";
|
||||
import { useMemory } from "@/contexts/MemoryContext";
|
||||
|
||||
export interface Props extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
side?: 'top' | 'bottom';
|
||||
align?: 'end' | 'start' | 'center';
|
||||
side?: "top" | "bottom";
|
||||
align?: "end" | "start" | "center";
|
||||
onClose?: () => void;
|
||||
selectedSpaces: number[];
|
||||
setSelectedSpaces: (spaces: number[] | ((prev: number[]) => number[])) => void;
|
||||
setSelectedSpaces: (
|
||||
spaces: number[] | ((prev: number[]) => number[]),
|
||||
) => void;
|
||||
}
|
||||
|
||||
export function FilterCombobox({
|
||||
className,
|
||||
side = 'bottom',
|
||||
align = 'center',
|
||||
side = "bottom",
|
||||
align = "center",
|
||||
onClose,
|
||||
selectedSpaces,
|
||||
setSelectedSpaces,
|
||||
|
|
@ -65,7 +67,7 @@ export function FilterCombobox({
|
|||
<button
|
||||
data-state-on={open}
|
||||
className={cn(
|
||||
'text-rgray-11/70 on:bg-rgray-3 focus-visible:ring-rgray-8 hover:bg-rgray-3 relative flex items-center justify-center gap-1 rounded-md px-3 py-1.5 ring-2 ring-transparent focus-visible:outline-none',
|
||||
"text-rgray-11/70 on:bg-rgray-3 focus-visible:ring-rgray-8 hover:bg-rgray-3 relative flex items-center justify-center gap-1 rounded-md px-3 py-1.5 ring-2 ring-transparent focus-visible:outline-none",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -129,7 +131,7 @@ export function FilterCombobox({
|
|||
<Check
|
||||
data-state-on={selectedSpaces.includes(space.id)}
|
||||
className={cn(
|
||||
'on:opacity-100 ml-auto h-4 w-4 opacity-0',
|
||||
"on:opacity-100 ml-auto h-4 w-4 opacity-0",
|
||||
)}
|
||||
/>
|
||||
</motion.div>
|
||||
|
|
|
|||
|
|
@ -1,29 +1,35 @@
|
|||
'use client';
|
||||
import { MemoryIcon } from '../../assets/Memories';
|
||||
import { Trash2, User2 } from 'lucide-react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { MemoriesBar } from './MemoriesBar';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { Bin } from '@/assets/Bin';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@radix-ui/react-avatar';
|
||||
import { useSession } from 'next-auth/react';
|
||||
"use client";
|
||||
import { MemoryIcon } from "../../assets/Memories";
|
||||
import { Trash2, User2 } from "lucide-react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { MemoriesBar } from "./MemoriesBar";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { Bin } from "@/assets/Bin";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@radix-ui/react-avatar";
|
||||
import { useSession } from "next-auth/react";
|
||||
import MessagePoster from "@/app/MessagePoster";
|
||||
import Image from "next/image";
|
||||
import WordMark from "../WordMark";
|
||||
|
||||
export type MenuItem = {
|
||||
icon: React.ReactNode | React.ReactNode[];
|
||||
label: string;
|
||||
content?: React.ReactNode;
|
||||
labelDisplay?: React.ReactNode;
|
||||
};
|
||||
|
||||
export default function Sidebar({
|
||||
selectChange,
|
||||
jwt,
|
||||
}: {
|
||||
selectChange?: (selectedItem: string | null) => void;
|
||||
jwt: string;
|
||||
}) {
|
||||
const { data: session } = useSession();
|
||||
const menuItemsTop: Array<MenuItem> = [
|
||||
{
|
||||
icon: <MemoryIcon className="h-10 w-10" />,
|
||||
label: 'Memories',
|
||||
label: "Memories",
|
||||
content: <MemoriesBar />,
|
||||
},
|
||||
];
|
||||
|
|
@ -31,7 +37,7 @@ export default function Sidebar({
|
|||
const menuItemsBottom: Array<MenuItem> = [
|
||||
{
|
||||
icon: <Trash2 strokeWidth={1.3} className="h-6 w-6" />,
|
||||
label: 'Trash',
|
||||
label: "Trash",
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
|
|
@ -47,12 +53,12 @@ export default function Sidebar({
|
|||
<User2 strokeWidth={1.3} className="h-6 w-6" />
|
||||
)}
|
||||
<AvatarFallback>
|
||||
{session?.user?.name?.split(' ').map((n) => n[0])}{' '}
|
||||
{session?.user?.name?.split(" ").map((n) => n[0])}{" "}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
),
|
||||
label: 'Profile',
|
||||
label: "Profile",
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -70,22 +76,30 @@ export default function Sidebar({
|
|||
return (
|
||||
<>
|
||||
<div className="relative hidden h-screen max-h-screen w-max flex-col items-center text-sm font-light md:flex">
|
||||
<div className="bg-rgray-2 border-r-rgray-6 relative z-[50] flex h-full w-full flex-col items-center justify-center border-r px-2 py-5 ">
|
||||
<div className="bg-rgray-3 border-r-rgray-6 relative z-[50] flex h-full w-full flex-col items-center justify-center border-r px-2 py-5 ">
|
||||
<Image
|
||||
className="mb-4 rounded-md"
|
||||
src="/icons/logo_bw_without_bg.png"
|
||||
alt="Smort logo"
|
||||
width={50}
|
||||
height={50}
|
||||
/>
|
||||
|
||||
<div className="bg-rgray-6 mb-8 h-[1px] w-full" />
|
||||
|
||||
<MenuItem
|
||||
item={{
|
||||
label: 'Memories',
|
||||
label: "Memories",
|
||||
icon: <MemoryIcon className="h-10 w-10" />,
|
||||
content: <MemoriesBar />,
|
||||
}}
|
||||
selectedItem={selectedItem}
|
||||
setSelectedItem={setSelectedItem}
|
||||
/>
|
||||
|
||||
<div className="mt-auto" />
|
||||
|
||||
<MenuItem
|
||||
item={{
|
||||
label: 'Trash',
|
||||
label: "Trash",
|
||||
icon: <Bin id="trash" className="z-[300] h-7 w-7" />,
|
||||
}}
|
||||
selectedItem={selectedItem}
|
||||
|
|
@ -94,7 +108,7 @@ export default function Sidebar({
|
|||
/>
|
||||
<MenuItem
|
||||
item={{
|
||||
label: 'Profile',
|
||||
label: "Profile",
|
||||
icon: (
|
||||
<div className="mb-2">
|
||||
<Avatar>
|
||||
|
|
@ -108,7 +122,7 @@ export default function Sidebar({
|
|||
<User2 strokeWidth={1.3} className="h-6 w-6" />
|
||||
)}
|
||||
<AvatarFallback>
|
||||
{session?.user?.name?.split(' ').map((n) => n[0])}{' '}
|
||||
{session?.user?.name?.split(" ").map((n) => n[0])}{" "}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
|
|
@ -117,6 +131,7 @@ export default function Sidebar({
|
|||
selectedItem={selectedItem}
|
||||
setSelectedItem={setSelectedItem}
|
||||
/>
|
||||
<MessagePoster jwt={jwt} />
|
||||
</div>
|
||||
<AnimatePresence>
|
||||
{selectedItem && <SubSidebar>{Subbar}</SubSidebar>}
|
||||
|
|
@ -127,7 +142,7 @@ export default function Sidebar({
|
|||
}
|
||||
|
||||
const MenuItem = ({
|
||||
item: { icon, label },
|
||||
item: { icon, label, labelDisplay },
|
||||
selectedItem,
|
||||
setSelectedItem,
|
||||
...props
|
||||
|
|
@ -143,18 +158,18 @@ const MenuItem = ({
|
|||
{...props}
|
||||
>
|
||||
{icon}
|
||||
<span className="">{label}</span>
|
||||
<span className="">{labelDisplay ?? label}</span>
|
||||
</button>
|
||||
);
|
||||
|
||||
export function SubSidebar({ children }: { children?: React.ReactNode }) {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: '-100%' }}
|
||||
initial={{ opacity: 0, x: "-100%" }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{
|
||||
opacity: 0,
|
||||
x: '-100%',
|
||||
x: "-100%",
|
||||
transition: { delay: 0.2 },
|
||||
}}
|
||||
transition={{
|
||||
|
|
|
|||
12
apps/web/src/components/WordMark.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { cn } from "@/lib/utils";
|
||||
import React from "react";
|
||||
|
||||
function WordMark({ className }: { className?: string }) {
|
||||
return (
|
||||
<span className={cn(`text-xl font-bold tracking-tight ${className}`)}>
|
||||
smort.
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export default WordMark;
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
"use client"
|
||||
"use client";
|
||||
|
||||
import * as React from "react"
|
||||
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
||||
import * as React from "react";
|
||||
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const Avatar = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Root>,
|
||||
|
|
@ -13,12 +13,12 @@ const Avatar = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Avatar.displayName = AvatarPrimitive.Root.displayName
|
||||
));
|
||||
Avatar.displayName = AvatarPrimitive.Root.displayName;
|
||||
|
||||
const AvatarImage = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Image>,
|
||||
|
|
@ -29,8 +29,8 @@ const AvatarImage = React.forwardRef<
|
|||
className={cn("aspect-square h-full w-full", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarImage.displayName = AvatarPrimitive.Image.displayName
|
||||
));
|
||||
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
|
||||
|
||||
const AvatarFallback = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
||||
|
|
@ -40,11 +40,11 @@ const AvatarFallback = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full items-center justify-center rounded-full bg-gray-100 dark:bg-gray-800",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
|
||||
));
|
||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
|
||||
|
||||
export { Avatar, AvatarImage, AvatarFallback }
|
||||
export { Avatar, AvatarImage, AvatarFallback };
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from "react"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import * as React from "react";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-full border border-gray-200 px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-gray-950 focus:ring-offset-2 dark:border-gray-800 dark:focus:ring-gray-300",
|
||||
|
|
@ -20,8 +20,8 @@ const badgeVariants = cva(
|
|||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
export interface BadgeProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
|
|
@ -30,7 +30,7 @@ export interface BadgeProps
|
|||
function Badge({ className, variant, ...props }: BadgeProps) {
|
||||
return (
|
||||
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export { Badge, badgeVariants }
|
||||
export { Badge, badgeVariants };
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import * as React from "react";
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-gray-950 dark:focus-visible:ring-gray-300",
|
||||
|
|
@ -30,27 +30,27 @@ const buttonVariants = cva(
|
|||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
const Comp = asChild ? Slot : "button";
|
||||
return (
|
||||
<button
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Button.displayName = "Button"
|
||||
);
|
||||
},
|
||||
);
|
||||
Button.displayName = "Button";
|
||||
|
||||
export { Button, buttonVariants }
|
||||
export { Button, buttonVariants };
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react"
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const Card = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
|
|
@ -10,12 +10,12 @@ const Card = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"rounded-lg border border-gray-200 bg-white text-gray-950 shadow-sm dark:border-gray-800 dark:bg-gray-950 dark:text-gray-50",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Card.displayName = "Card"
|
||||
));
|
||||
Card.displayName = "Card";
|
||||
|
||||
const CardHeader = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
|
|
@ -26,8 +26,8 @@ const CardHeader = React.forwardRef<
|
|||
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CardHeader.displayName = "CardHeader"
|
||||
));
|
||||
CardHeader.displayName = "CardHeader";
|
||||
|
||||
const CardTitle = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
|
|
@ -37,12 +37,12 @@ const CardTitle = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"text-2xl font-semibold leading-none tracking-tight",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CardTitle.displayName = "CardTitle"
|
||||
));
|
||||
CardTitle.displayName = "CardTitle";
|
||||
|
||||
const CardDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
|
|
@ -53,16 +53,16 @@ const CardDescription = React.forwardRef<
|
|||
className={cn("text-sm text-gray-500 dark:text-gray-400", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CardDescription.displayName = "CardDescription"
|
||||
));
|
||||
CardDescription.displayName = "CardDescription";
|
||||
|
||||
const CardContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
||||
))
|
||||
CardContent.displayName = "CardContent"
|
||||
));
|
||||
CardContent.displayName = "CardContent";
|
||||
|
||||
const CardFooter = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
|
|
@ -73,7 +73,14 @@ const CardFooter = React.forwardRef<
|
|||
className={cn("flex items-center p-6 pt-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CardFooter.displayName = "CardFooter"
|
||||
));
|
||||
CardFooter.displayName = "CardFooter";
|
||||
|
||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|
||||
export {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
"use client"
|
||||
"use client";
|
||||
|
||||
import * as React from "react"
|
||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import * as React from "react";
|
||||
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const labelVariants = cva(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
)
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||
);
|
||||
|
||||
const Label = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
|
|
@ -20,7 +20,7 @@ const Label = React.forwardRef<
|
|||
className={cn(labelVariants(), className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Label.displayName = LabelPrimitive.Root.displayName
|
||||
));
|
||||
Label.displayName = LabelPrimitive.Root.displayName;
|
||||
|
||||
export { Label }
|
||||
export { Label };
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use client';
|
||||
import React, { useCallback } from 'react';
|
||||
import { CollectedSpaces } from '../../types/memory';
|
||||
"use client";
|
||||
import React, { useCallback } from "react";
|
||||
import { CollectedSpaces } from "../../types/memory";
|
||||
|
||||
// temperory (will change)
|
||||
export const MemoryContext = React.createContext<{
|
||||
|
|
@ -41,7 +41,7 @@ export const MemoryProvider: React.FC<
|
|||
export const useMemory = () => {
|
||||
const context = React.useContext(MemoryContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useMemory must be used within a MemoryProvider');
|
||||
throw new Error("useMemory must be used within a MemoryProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { createEnv } from "@t3-oss/env-nextjs";
|
||||
import { z } from "zod";
|
||||
|
||||
|
||||
export const env = createEnv({
|
||||
/**
|
||||
* Specify your server-side environment variables schema here. This way you can ensure the app
|
||||
|
|
@ -12,15 +11,13 @@ export const env = createEnv({
|
|||
.enum(["development", "test", "production"])
|
||||
.default("development"),
|
||||
NEXTAUTH_SECRET:
|
||||
process.env.NODE_ENV === "production"
|
||||
? z.string()
|
||||
: z.string(),
|
||||
process.env.NODE_ENV === "production" ? z.string() : z.string(),
|
||||
NEXTAUTH_URL: z.preprocess(
|
||||
// This makes Vercel deployments not fail if you don't set NEXTAUTH_URL
|
||||
// Since NextAuth.js automatically uses the VERCEL_URL if present.
|
||||
(str) => process.env.VERCEL_URL ?? str,
|
||||
// VERCEL_URL doesn't include `https` so it cant be validated as a URL
|
||||
process.env.VERCEL ? z.string() : z.string().url()
|
||||
process.env.VERCEL ? z.string() : z.string().url(),
|
||||
),
|
||||
GOOGLE_CLIENT_ID: z.string(),
|
||||
GOOGLE_CLIENT_SECRET: z.string(),
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import {
|
||||
createSearchParamsCache,
|
||||
parseAsInteger,
|
||||
parseAsString
|
||||
} from 'nuqs/server'
|
||||
// Note: import from 'nuqs/server' to avoid the "use client" directive
|
||||
|
||||
export const searchParamsCache = createSearchParamsCache({
|
||||
// List your search param keys and associated parsers here:
|
||||
q: parseAsString.withDefault(''),
|
||||
maxResults: parseAsInteger.withDefault(10)
|
||||
})
|
||||
createSearchParamsCache,
|
||||
parseAsInteger,
|
||||
parseAsString,
|
||||
} from "nuqs/server";
|
||||
// Note: import from 'nuqs/server' to avoid the "use client" directive
|
||||
|
||||
export const searchParamsCache = createSearchParamsCache({
|
||||
// List your search param keys and associated parsers here:
|
||||
q: parseAsString.withDefault(""),
|
||||
maxResults: parseAsInteger.withDefault(10),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { env } from "@/env";
|
||||
import NextAuth from "next-auth";
|
||||
import Google from "next-auth/providers/google";
|
||||
import { DrizzleAdapter } from "@auth/drizzle-adapter"
|
||||
import { DrizzleAdapter } from "@auth/drizzle-adapter";
|
||||
import { db } from "./db";
|
||||
|
||||
export const {
|
||||
|
|
@ -15,9 +15,9 @@ export const {
|
|||
...session,
|
||||
user: {
|
||||
...session.user,
|
||||
id: user.id
|
||||
id: user.id,
|
||||
},
|
||||
})
|
||||
}),
|
||||
},
|
||||
adapter: DrizzleAdapter(db),
|
||||
providers: [
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import { drizzle } from 'drizzle-orm/d1';
|
||||
import { drizzle } from "drizzle-orm/d1";
|
||||
|
||||
import * as schema from "./schema";
|
||||
|
||||
export const db = drizzle(
|
||||
process.env.DATABASE,
|
||||
{ schema, logger: true }
|
||||
);
|
||||
export const db = drizzle(process.env.DATABASE, { schema, logger: true });
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
sqliteTableCreator,
|
||||
text,
|
||||
integer,
|
||||
unique
|
||||
unique,
|
||||
} from "drizzle-orm/sqlite-core";
|
||||
|
||||
export const createTable = sqliteTableCreator((name) => `${name}`);
|
||||
|
|
@ -78,7 +78,6 @@ export const verificationTokens = createTable(
|
|||
}),
|
||||
);
|
||||
|
||||
|
||||
export const storedContent = createTable(
|
||||
"storedContent",
|
||||
{
|
||||
|
|
@ -103,8 +102,12 @@ export const storedContent = createTable(
|
|||
export const contentToSpace = createTable(
|
||||
"contentToSpace",
|
||||
{
|
||||
contentId: integer("contentId").notNull().references(() => storedContent.id),
|
||||
spaceId: integer("spaceId").notNull().references(() => space.id),
|
||||
contentId: integer("contentId")
|
||||
.notNull()
|
||||
.references(() => storedContent.id),
|
||||
spaceId: integer("spaceId")
|
||||
.notNull()
|
||||
.references(() => space.id),
|
||||
},
|
||||
(cts) => ({
|
||||
compoundKey: primaryKey({ columns: [cts.contentId, cts.spaceId] }),
|
||||
|
|
@ -115,7 +118,7 @@ export const space = createTable(
|
|||
"space",
|
||||
{
|
||||
id: integer("id").notNull().primaryKey({ autoIncrement: true }),
|
||||
name: text('name').notNull().default('all'),
|
||||
name: text("name").notNull().default("all"),
|
||||
user: text("user", { length: 255 }).references(() => users.id),
|
||||
},
|
||||
(space) => ({
|
||||
|
|
@ -124,4 +127,4 @@ export const space = createTable(
|
|||
}),
|
||||
);
|
||||
|
||||
export type StoredContent = Omit<typeof storedContent.$inferSelect, 'user'>
|
||||
export type StoredContent = Omit<typeof storedContent.$inferSelect, "user">;
|
||||
|
|
|
|||
|
|
@ -1,34 +1,34 @@
|
|||
export async function getMetaData(url: string) {
|
||||
const response = await fetch(url);
|
||||
const html = await response.text();
|
||||
|
||||
// Extract the base URL
|
||||
const baseUrl = new URL(url).origin;
|
||||
|
||||
// Extract title
|
||||
const titleMatch = html.match(/<title>(.*?)<\/title>/);
|
||||
const title = titleMatch ? titleMatch[1] : 'Title not found';
|
||||
|
||||
// Extract meta description
|
||||
const descriptionMatch = html.match(
|
||||
/<meta name="description" content="(.*?)"\s*\/?>/,
|
||||
);
|
||||
const description = descriptionMatch
|
||||
? descriptionMatch[1]
|
||||
: 'Description not found';
|
||||
|
||||
// Extract Open Graph image
|
||||
const imageMatch = html.match(
|
||||
/<meta property="og:image" content="(.*?)"\s*\/?>/,
|
||||
);
|
||||
const image = imageMatch ? imageMatch[1] : 'Image not found';
|
||||
|
||||
// Prepare the metadata object
|
||||
const metadata = {
|
||||
title,
|
||||
description,
|
||||
image,
|
||||
baseUrl,
|
||||
};
|
||||
return metadata;
|
||||
}
|
||||
const response = await fetch(url);
|
||||
const html = await response.text();
|
||||
|
||||
// Extract the base URL
|
||||
const baseUrl = new URL(url).origin;
|
||||
|
||||
// Extract title
|
||||
const titleMatch = html.match(/<title>(.*?)<\/title>/);
|
||||
const title = titleMatch ? titleMatch[1] : "Title not found";
|
||||
|
||||
// Extract meta description
|
||||
const descriptionMatch = html.match(
|
||||
/<meta name="description" content="(.*?)"\s*\/?>/,
|
||||
);
|
||||
const description = descriptionMatch
|
||||
? descriptionMatch[1]
|
||||
: "Description not found";
|
||||
|
||||
// Extract Open Graph image
|
||||
const imageMatch = html.match(
|
||||
/<meta property="og:image" content="(.*?)"\s*\/?>/,
|
||||
);
|
||||
const image = imageMatch ? imageMatch[1] : "Image not found";
|
||||
|
||||
// Prepare the metadata object
|
||||
const metadata = {
|
||||
title,
|
||||
description,
|
||||
image,
|
||||
baseUrl,
|
||||
};
|
||||
return metadata;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
"lint": "dotenv -- turbo run lint",
|
||||
"start": "dotenv -- turbo run start"
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*": "prettier --write --ignore-unknown"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/better-sqlite3": "^7.6.6",
|
||||
"@types/eslint": "^8.44.7",
|
||||
|
|
@ -56,6 +59,8 @@
|
|||
"framer-motion": "^11.0.6",
|
||||
"html-metadata": "^1.7.1",
|
||||
"html-metadata-parser": "^2.0.4",
|
||||
"husky": "^9.0.11",
|
||||
"lint-staged": "^15.2.2",
|
||||
"lucide-react": "^0.343.0",
|
||||
"next-auth": "beta",
|
||||
"nuqs": "^1.17.1",
|
||||
|
|
@ -64,4 +69,4 @@
|
|||
"tailwind-scrollbar": "^3.1.0",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,44 +1,38 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"target": "es2022",
|
||||
"allowJs": true,
|
||||
"resolveJsonModule": true,
|
||||
"moduleDetection": "force",
|
||||
"isolatedModules": true,
|
||||
"strict": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"checkJs": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"ES2022"
|
||||
],
|
||||
"noEmit": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"jsx": "preserve",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"incremental": true,
|
||||
"baseUrl": "."
|
||||
},
|
||||
"include": [
|
||||
"../.eslintrc.cjs",
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.cjs",
|
||||
"**/*.js",
|
||||
".next/types/**/*.ts",
|
||||
"../tailwind.config.ts",
|
||||
"../prettier.config.js"
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"target": "es2022",
|
||||
"allowJs": true,
|
||||
"resolveJsonModule": true,
|
||||
"moduleDetection": "force",
|
||||
"isolatedModules": true,
|
||||
"strict": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"checkJs": true,
|
||||
"lib": ["dom", "dom.iterable", "ES2022"],
|
||||
"noEmit": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"jsx": "preserve",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
"incremental": true,
|
||||
"baseUrl": "."
|
||||
},
|
||||
"include": [
|
||||
"../.eslintrc.cjs",
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.cjs",
|
||||
"**/*.js",
|
||||
".next/types/**/*.ts",
|
||||
"../tailwind.config.ts",
|
||||
"../prettier.config.js"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"name": "tsconfig"
|
||||
}
|
||||
"name": "tsconfig"
|
||||
}
|
||||
|
|
|
|||
28
turbo.json
|
|
@ -2,39 +2,23 @@
|
|||
"$schema": "https://turbo.build/schema.json",
|
||||
"pipeline": {
|
||||
"build": {
|
||||
"outputs": [
|
||||
".next/**",
|
||||
"!.next/cache/**"
|
||||
]
|
||||
"outputs": [".next/**", "!.next/cache/**"]
|
||||
},
|
||||
"deploy": {
|
||||
"dependsOn": [
|
||||
"build",
|
||||
"test",
|
||||
"lint"
|
||||
]
|
||||
"dependsOn": ["build", "test", "lint"]
|
||||
},
|
||||
"db:push": {},
|
||||
"db:studio": {},
|
||||
"test": {
|
||||
"dependsOn": [
|
||||
"build"
|
||||
],
|
||||
"inputs": [
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.ts",
|
||||
"test/**/*.ts",
|
||||
"test/**/*.tsx"
|
||||
]
|
||||
"dependsOn": ["build"],
|
||||
"inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts", "test/**/*.tsx"]
|
||||
},
|
||||
"lint": {},
|
||||
"type-check": {},
|
||||
"dev": {
|
||||
"env": [
|
||||
"NODE_ENV=development"
|
||||
],
|
||||
"env": ["NODE_ENV=development"],
|
||||
"cache": false,
|
||||
"persistent": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||