@@ -66,7 +68,25 @@ Installation
2. Click "Speed Insights" tab
3. Follow "Enable Speed Insights" instructions (`@vercel/speed-insights` already included)
-### 7. Optional configuration
+### 7. Add experimental AI text generation
+
+_⚠️ READ BEFORE PROCEEDING_
+
+> _Usage of this feature will result in fees from OpenAI. When enabling AI text generation, follow all recommended mitigations in order to avoid unexpected charges and attacks. Make sure your OpenAI secret key environment variable is not prefixed with NEXT_PUBLIC._
+
+1. Setup OpenAI
+ - If you don't already have one, create an [OpenAI](https://openai.com) account
+ - Generate an API key and store in environment variable `OPENAI_SECRET_KEY`
+ - Setup usage limits to avoid unexpected charges (_recommended_)
+2. Add rate limiting (_recommended_)
+ - As an additional precaution, create a [Vercel KV](https://vercel.com/docs/storage/vercel-kv/quickstart#create-a-kv-database) store and link it to your project in order to enable rate limiting
+3. Configure auto-generated fields (optional)
+ - Set which text fields should auto-generate when uploading a photo by storing a comma-separated list, e.g., `AI_TEXT_AUTO_GENERATED_FIELDS = title, semantic`
+ - Accepted values: title, caption, tags, description, all, or none (default is "all")
+
+### 8. Optional configuration
+
+Application behavior can be changed by configuring the following environment variables:
- `NEXT_PUBLIC_PRO_MODE = 1` enables higher quality image storage for jpgs (results in increased storage usage)
- `NEXT_PUBLIC_STATICALLY_OPTIMIZE = 1` enables PPR and static optimization, i.e., building pages ahead of time (results in increased storage usage)—⚠️ _Experimental_
diff --git a/__tests__/ai.test.ts b/__tests__/ai.test.ts
new file mode 100644
index 00000000..b70c93a0
--- /dev/null
+++ b/__tests__/ai.test.ts
@@ -0,0 +1,42 @@
+/* eslint-disable quotes */
+import { parseTitleAndCaption } from "@/photo/ai";
+
+describe('AI text parses', () => {
+ it('titles and captions', () => {
+ // Complex case
+ expect(parseTitleAndCaption(
+ `'Title: "Ephemeral Beauty" Caption: "Roses bask in fleeting sunlight."'`
+ )).toStrictEqual({
+ title: 'Ephemeral Beauty',
+ caption: 'Roses bask in fleeting sunlight',
+ });
+ // Without surrounding single quotes
+ expect(parseTitleAndCaption(
+ `Title: "Ephemeral Beauty" Caption: "Roses bask in fleeting sunlight."`
+ )).toStrictEqual({
+ title: 'Ephemeral Beauty',
+ caption: 'Roses bask in fleeting sunlight',
+ });
+ // Without trailing period
+ expect(parseTitleAndCaption(
+ `Title: "Ephemeral Beauty" Caption: "Roses bask in fleeting sunlight"`
+ )).toStrictEqual({
+ title: 'Ephemeral Beauty',
+ caption: 'Roses bask in fleeting sunlight',
+ });
+ // Without and quotes
+ expect(parseTitleAndCaption(
+ `Title: Ephemeral Beauty Caption: Roses bask in fleeting sunlight`
+ )).toStrictEqual({
+ title: 'Ephemeral Beauty',
+ caption: 'Roses bask in fleeting sunlight',
+ });
+ // With single space
+ expect(parseTitleAndCaption(
+ `Title: Ephemeral Beauty Caption: Roses bask in fleeting sunlight`
+ )).toStrictEqual({
+ title: 'Ephemeral Beauty',
+ caption: 'Roses bask in fleeting sunlight',
+ });
+ });
+});
diff --git a/package.json b/package.json
index ce562cab..9f6cff03 100644
--- a/package.json
+++ b/package.json
@@ -23,10 +23,13 @@
"@types/react-dom": "18.2.21",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
+ "@upstash/ratelimit": "^1.0.1",
"@vercel/analytics": "^1.2.2",
"@vercel/blob": "^0.22.1",
+ "@vercel/kv": "^1.0.1",
"@vercel/postgres": "0.7.2",
"@vercel/speed-insights": "^1.0.10",
+ "ai": "^3.0.13",
"autoprefixer": "10.4.18",
"camelcase-keys": "^9.1.3",
"clsx": "^2.1.0",
@@ -39,9 +42,10 @@
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"nanoid": "^5.0.6",
- "next": "14.2.0-canary.31",
+ "next": "14.2.0-canary.39",
"next-auth": "5.0.0-beta.15",
"next-themes": "^0.3.0",
+ "openai": "^4.29.2",
"postcss": "8.4.35",
"react": "18.2.0",
"react-dom": "18.2.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8d0186e0..704ae7e3 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -47,18 +47,27 @@ dependencies:
'@typescript-eslint/parser':
specifier: ^7.2.0
version: 7.2.0(eslint@8.57.0)(typescript@5.4.2)
+ '@upstash/ratelimit':
+ specifier: ^1.0.1
+ version: 1.0.1
'@vercel/analytics':
specifier: ^1.2.2
- version: 1.2.2(next@14.2.0-canary.31)(react@18.2.0)
+ version: 1.2.2(next@14.2.0-canary.39)(react@18.2.0)
'@vercel/blob':
specifier: ^0.22.1
version: 0.22.1
+ '@vercel/kv':
+ specifier: ^1.0.1
+ version: 1.0.1
'@vercel/postgres':
specifier: 0.7.2
version: 0.7.2
'@vercel/speed-insights':
specifier: ^1.0.10
- version: 1.0.10(next@14.2.0-canary.31)(react@18.2.0)
+ version: 1.0.10(next@14.2.0-canary.39)(react@18.2.0)(svelte@4.2.12)(vue@3.4.21)
+ ai:
+ specifier: ^3.0.13
+ version: 3.0.13(react@18.2.0)(solid-js@1.8.15)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
autoprefixer:
specifier: 10.4.18
version: 10.4.18(postcss@8.4.35)
@@ -96,14 +105,17 @@ dependencies:
specifier: ^5.0.6
version: 5.0.6
next:
- specifier: 14.2.0-canary.31
- version: 14.2.0-canary.31(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0)
+ specifier: 14.2.0-canary.39
+ version: 14.2.0-canary.39(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0)
next-auth:
specifier: 5.0.0-beta.15
- version: 5.0.0-beta.15(next@14.2.0-canary.31)(react@18.2.0)
+ version: 5.0.0-beta.15(next@14.2.0-canary.39)(react@18.2.0)
next-themes:
specifier: ^0.3.0
version: 0.3.0(react-dom@18.2.0)(react@18.2.0)
+ openai:
+ specifier: ^4.29.2
+ version: 4.29.2
postcss:
specifier: 8.4.35
version: 8.4.35
@@ -1551,8 +1563,8 @@ packages:
- utf-8-validate
dev: false
- /@next/env@14.2.0-canary.31:
- resolution: {integrity: sha512-xdUjSv8c5e1QPiB010TcyW1zPL3bK7FySHQDu6NjzZuUkYwm8W9c9NGIdJLB2UQv0rfpaFBKfWNlGbakicrE+g==}
+ /@next/env@14.2.0-canary.39:
+ resolution: {integrity: sha512-ROeqwq9mybhzfdzNDbz9/0e3fFB6gtC25NZNC/rhZzvgkTvUuYXUbJOJSvvtsoUjQolTCFOhZqKmopX+QgwYwQ==}
dev: false
/@next/eslint-plugin-next@14.1.3:
@@ -1561,8 +1573,8 @@ packages:
glob: 10.3.10
dev: false
- /@next/swc-darwin-arm64@14.2.0-canary.31:
- resolution: {integrity: sha512-9NRPNOWxY/ecv1hxZej9nVvggIemdCqkwlgmkVv+M2TkAJzff5bwY4IzTuyPxQmioxHs43gPyKh/wpVsH4cuog==}
+ /@next/swc-darwin-arm64@14.2.0-canary.39:
+ resolution: {integrity: sha512-ImAEFQBac/jYFCQYAEOxLZlzZfoa0GnbmXlGruzyNXl7RG3gJ3OBXx6G/puySAdytp54tArmr+0h+xoEXbop2Q==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
@@ -1570,8 +1582,8 @@ packages:
dev: false
optional: true
- /@next/swc-darwin-x64@14.2.0-canary.31:
- resolution: {integrity: sha512-8xbOircQJzJx39GZ4iNd/6PIyOI/qZ8TpjJ9qzA1FpVZUDAMXZIDnQIHIsnxvn0HkP85PByw3tcKZLLKcw5k4g==}
+ /@next/swc-darwin-x64@14.2.0-canary.39:
+ resolution: {integrity: sha512-2q0F3L261vYPOrn7KXLX5SzfMe8yPRs0plnExpV2MwQjikt5OhlUdGwRRyEFT0DS0S0cyaKw00nENxBuDi7VyA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
@@ -1579,8 +1591,8 @@ packages:
dev: false
optional: true
- /@next/swc-linux-arm64-gnu@14.2.0-canary.31:
- resolution: {integrity: sha512-zpA19+op2KxnIutpoZbvQiplmoJHsUUPIhynC+PpZtSqA1IWBZoem+T4IhnmHr+F0DQZRqO9lmZZkHdEpRAzbQ==}
+ /@next/swc-linux-arm64-gnu@14.2.0-canary.39:
+ resolution: {integrity: sha512-efraDAfAjQosfUdW8ZMjnrH3/mveQQxs055BdGfh+L0+hlTf05ECUH07tg3AKqihhnk+sgJUqigR5ZSsUYrqsw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
@@ -1588,8 +1600,8 @@ packages:
dev: false
optional: true
- /@next/swc-linux-arm64-musl@14.2.0-canary.31:
- resolution: {integrity: sha512-cZ1GuBi6YOHdEw8/lhuxZsObJVpry7irgf1PCsOLigpIqCAyMhbAcQ32FkTA3N5MKWpOkrmS9xQ2B6K1ZaQzCg==}
+ /@next/swc-linux-arm64-musl@14.2.0-canary.39:
+ resolution: {integrity: sha512-Eb6+d3XkhwaEd69OoTOa4/scqQJtCUiZrmWjR0sVbW3QJ0wWu2o5gz8mInYsLeLwxN+HDy1aDuQSl3hp2PwBbQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
@@ -1597,8 +1609,8 @@ packages:
dev: false
optional: true
- /@next/swc-linux-x64-gnu@14.2.0-canary.31:
- resolution: {integrity: sha512-YxWC/fipzs/3cTeGcsSSU3GXEAJ16TI3yo4jgwofWko2jSF2/kpCOZSnRYbqX3eNyBCD4K9/g/9v6rAx2zHiew==}
+ /@next/swc-linux-x64-gnu@14.2.0-canary.39:
+ resolution: {integrity: sha512-HKkx1WCMsycDFOp76avVMCIGm/E0jw3yugfyIc/g1vRIh6fTOZ9iyLd1Uannu4MorTxGWS4g1ZRr1C5/9Ve8kg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
@@ -1606,8 +1618,8 @@ packages:
dev: false
optional: true
- /@next/swc-linux-x64-musl@14.2.0-canary.31:
- resolution: {integrity: sha512-CoZVZyx08myeDXmoSEuk+eXrwMYenevXP03Rz/+6+BT6zOrq+1s1rFKUZVd6/3AnD9Q7vNCuTGtaL5jaF5koGw==}
+ /@next/swc-linux-x64-musl@14.2.0-canary.39:
+ resolution: {integrity: sha512-9W/UTFugvG0fYhNK5IqahiwldH3JSXmF2iCzQMbGMpyhjvOn1UirEZPwkMXz6tdSGXVHwxvvsuhZhZgBIt8csw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
@@ -1615,8 +1627,8 @@ packages:
dev: false
optional: true
- /@next/swc-win32-arm64-msvc@14.2.0-canary.31:
- resolution: {integrity: sha512-m1nuZmu8DOJKJvVrrz7KxMH1K3IU1UC7av1jD55cFf3ZM5ur06Mx2PvtbKSnSLCjK7Ga8LHMYXBXQWAbkD6Bcg==}
+ /@next/swc-win32-arm64-msvc@14.2.0-canary.39:
+ resolution: {integrity: sha512-rtG2wYP3Sa67F2AqaX2qISefZbc/KN0fj5gPx3ReFIuK8/p6tR/L063xvyNmBZs22DZuc07EaFCQ9Px7EB0C2Q==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
@@ -1624,8 +1636,8 @@ packages:
dev: false
optional: true
- /@next/swc-win32-ia32-msvc@14.2.0-canary.31:
- resolution: {integrity: sha512-OFmjN8wK6eSViHUqsh7VLzI8H8d3G6esjn3zOHoSirg821MJLyWVGAXMBjykDz4kTP6VmGdCkohBP6nf/uy94Q==}
+ /@next/swc-win32-ia32-msvc@14.2.0-canary.39:
+ resolution: {integrity: sha512-Qh3vNCQQqghFuX4XhKuBhlleaRNIVFTspFMMKdQKFoATVVZh5n/PEeGEIgwjZjsjwfLPI82fkIvxhZkPujcAgg==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
@@ -1633,8 +1645,8 @@ packages:
dev: false
optional: true
- /@next/swc-win32-x64-msvc@14.2.0-canary.31:
- resolution: {integrity: sha512-Dv+FC2zYh8aEKsFUpq6815grRS0dcRw9uJ9hxULAZ9EuFcw0iu5zKbEPWZ+klxDrAWA8bw7WYMZfkvEH7bSLOA==}
+ /@next/swc-win32-x64-msvc@14.2.0-canary.39:
+ resolution: {integrity: sha512-CPFzgcPYamtJpHtrHr55LsZ9g95l9vnm85OckaDQCK+359z4sgWk5Jp2ortPN/ZorDk+KjiixrE8x1Ix07Mk9g==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@@ -2785,6 +2797,14 @@ packages:
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
dev: false
+ /@types/diff-match-patch@1.0.36:
+ resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==}
+ dev: false
+
+ /@types/estree@1.0.5:
+ resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
+ dev: false
+
/@types/graceful-fs@4.1.9:
resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
dependencies:
@@ -2830,6 +2850,19 @@ packages:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: false
+ /@types/node-fetch@2.6.11:
+ resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==}
+ dependencies:
+ '@types/node': 20.11.26
+ form-data: 4.0.0
+ dev: false
+
+ /@types/node@18.19.24:
+ resolution: {integrity: sha512-eghAz3gnbQbvnHqB+mgB2ZR3aH6RhdEmHGS48BnV75KceQPHqabkxKI0BbUSsqhqy2Ddhc2xD/VAR9ySZd57Lw==}
+ dependencies:
+ undici-types: 5.26.5
+ dev: false
+
/@types/node@20.11.26:
resolution: {integrity: sha512-YwOMmyhNnAWijOBQweOJnQPl068Oqd4K3OFbTc6AHJwzweUwwWG3GIFY74OKks2PJUDkQPeddOQES9mLn1CTEQ==}
dependencies:
@@ -3088,7 +3121,32 @@ packages:
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
dev: false
- /@vercel/analytics@1.2.2(next@14.2.0-canary.31)(react@18.2.0):
+ /@upstash/core-analytics@0.0.7:
+ resolution: {integrity: sha512-lC2j5efqb1haX/fpTGaPUx1rue1WUkOZBVHDzCB7eMIVsRdFFp4xiHtyH/G9omiR1zj39fU5SCTWFiKJH3KOpw==}
+ engines: {node: '>=16.0.0'}
+ dependencies:
+ '@upstash/redis': 1.28.4
+ dev: false
+
+ /@upstash/ratelimit@1.0.1:
+ resolution: {integrity: sha512-G9LZ7idhlkuYknbUngCB3qzd7QnkK1xDkFG5jRtEJZuOUS5UKJ0UTKbhalCtp39eX2wu2Ubv8W7HCeaJQOWM0A==}
+ dependencies:
+ '@upstash/core-analytics': 0.0.7
+ dev: false
+
+ /@upstash/redis@1.25.1:
+ resolution: {integrity: sha512-ACj0GhJ4qrQyBshwFgPod6XufVEfKX2wcaihsEvSdLYnY+m+pa13kGt1RXm/yTHKf4TQi/Dy2A8z/y6WUEOmlg==}
+ dependencies:
+ crypto-js: 4.2.0
+ dev: false
+
+ /@upstash/redis@1.28.4:
+ resolution: {integrity: sha512-UalkSAny/dz1m8giEhD3Y5ru1o+CPHI32wFyS3MyzDzj2TRvEN+lTw+mPwi20ojk0H2gs8TBW3qsrvwuLLy+pA==}
+ dependencies:
+ crypto-js: 4.2.0
+ dev: false
+
+ /@vercel/analytics@1.2.2(next@14.2.0-canary.39)(react@18.2.0):
resolution: {integrity: sha512-X0rctVWkQV1e5Y300ehVNqpOfSOufo7ieA5PIdna8yX/U7Vjz0GFsGf4qvAhxV02uQ2CVt7GYcrFfddXXK2Y4A==}
peerDependencies:
next: '>= 13'
@@ -3099,7 +3157,7 @@ packages:
react:
optional: true
dependencies:
- next: 14.2.0-canary.31(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0)
+ next: 14.2.0-canary.39(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0)
react: 18.2.0
server-only: 0.0.1
dev: false
@@ -3114,6 +3172,13 @@ packages:
undici: 5.28.3
dev: false
+ /@vercel/kv@1.0.1:
+ resolution: {integrity: sha512-uTKddsqVYS2GRAM/QMNNXCTuw9N742mLoGRXoNDcyECaxEXvIHG0dEY+ZnYISV4Vz534VwJO+64fd9XeSggSKw==}
+ engines: {node: '>=14.6'}
+ dependencies:
+ '@upstash/redis': 1.25.1
+ dev: false
+
/@vercel/postgres@0.7.2:
resolution: {integrity: sha512-IqR/ZAvoPGcPaXl9eWWB5KaA+w/81RzZa/18P4izQRHpNBkTGt9HwGfYi9+wut5UgxNq4QSX9A7HIQR6QDvX2Q==}
engines: {node: '>=14.6'}
@@ -3124,7 +3189,7 @@ packages:
ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)
dev: false
- /@vercel/speed-insights@1.0.10(next@14.2.0-canary.31)(react@18.2.0):
+ /@vercel/speed-insights@1.0.10(next@14.2.0-canary.39)(react@18.2.0)(svelte@4.2.12)(vue@3.4.21):
resolution: {integrity: sha512-4uzdKB0RW6Ff2FkzshzjZ+RlJfLPxgm/00i0XXgxfMPhwnnsk92YgtqsxT9OcPLdJUyVU1DqFlSWWjIQMPkh0g==}
requiresBuild: true
peerDependencies:
@@ -3148,8 +3213,83 @@ packages:
vue-router:
optional: true
dependencies:
- next: 14.2.0-canary.31(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0)
+ next: 14.2.0-canary.39(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0)
react: 18.2.0
+ svelte: 4.2.12
+ vue: 3.4.21(typescript@5.4.2)
+ dev: false
+
+ /@vue/compiler-core@3.4.21:
+ resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==}
+ dependencies:
+ '@babel/parser': 7.23.9
+ '@vue/shared': 3.4.21
+ entities: 4.5.0
+ estree-walker: 2.0.2
+ source-map-js: 1.0.2
+ dev: false
+
+ /@vue/compiler-dom@3.4.21:
+ resolution: {integrity: sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==}
+ dependencies:
+ '@vue/compiler-core': 3.4.21
+ '@vue/shared': 3.4.21
+ dev: false
+
+ /@vue/compiler-sfc@3.4.21:
+ resolution: {integrity: sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==}
+ dependencies:
+ '@babel/parser': 7.23.9
+ '@vue/compiler-core': 3.4.21
+ '@vue/compiler-dom': 3.4.21
+ '@vue/compiler-ssr': 3.4.21
+ '@vue/shared': 3.4.21
+ estree-walker: 2.0.2
+ magic-string: 0.30.8
+ postcss: 8.4.35
+ source-map-js: 1.0.2
+ dev: false
+
+ /@vue/compiler-ssr@3.4.21:
+ resolution: {integrity: sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==}
+ dependencies:
+ '@vue/compiler-dom': 3.4.21
+ '@vue/shared': 3.4.21
+ dev: false
+
+ /@vue/reactivity@3.4.21:
+ resolution: {integrity: sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==}
+ dependencies:
+ '@vue/shared': 3.4.21
+ dev: false
+
+ /@vue/runtime-core@3.4.21:
+ resolution: {integrity: sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==}
+ dependencies:
+ '@vue/reactivity': 3.4.21
+ '@vue/shared': 3.4.21
+ dev: false
+
+ /@vue/runtime-dom@3.4.21:
+ resolution: {integrity: sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==}
+ dependencies:
+ '@vue/runtime-core': 3.4.21
+ '@vue/shared': 3.4.21
+ csstype: 3.1.3
+ dev: false
+
+ /@vue/server-renderer@3.4.21(vue@3.4.21):
+ resolution: {integrity: sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==}
+ peerDependencies:
+ vue: 3.4.21
+ dependencies:
+ '@vue/compiler-ssr': 3.4.21
+ '@vue/shared': 3.4.21
+ vue: 3.4.21(typescript@5.4.2)
+ dev: false
+
+ /@vue/shared@3.4.21:
+ resolution: {integrity: sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==}
dev: false
/abab@2.0.6:
@@ -3157,6 +3297,13 @@ packages:
deprecated: Use your platform's native atob() and btoa() methods instead
dev: false
+ /abort-controller@3.0.0:
+ resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
+ engines: {node: '>=6.5'}
+ dependencies:
+ event-target-shim: 5.0.1
+ dev: false
+
/acorn-globals@7.0.1:
resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==}
dependencies:
@@ -3192,6 +3339,50 @@ packages:
- supports-color
dev: false
+ /agentkeepalive@4.5.0:
+ resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==}
+ engines: {node: '>= 8.0.0'}
+ dependencies:
+ humanize-ms: 1.2.1
+ dev: false
+
+ /ai@3.0.13(react@18.2.0)(solid-js@1.8.15)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4):
+ resolution: {integrity: sha512-fDrYnVTdMJuS/qYUq0T/CX3WDuTfcZFie9LkgnoQ2layfUG2Wzh/mpfkfYXFEq/mqnpep3xUtECOB1weyyvwUg==}
+ engines: {node: '>=14.6'}
+ peerDependencies:
+ react: ^18.2.0
+ solid-js: ^1.7.7
+ svelte: ^3.0.0 || ^4.0.0
+ vue: ^3.3.4
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ react:
+ optional: true
+ solid-js:
+ optional: true
+ svelte:
+ optional: true
+ vue:
+ optional: true
+ zod:
+ optional: true
+ dependencies:
+ eventsource-parser: 1.0.0
+ jsondiffpatch: 0.6.0
+ nanoid: 3.3.6
+ react: 18.2.0
+ solid-js: 1.8.15
+ solid-swr-store: 0.10.7(solid-js@1.8.15)(swr-store@0.10.6)
+ sswr: 2.0.0(svelte@4.2.12)
+ svelte: 4.2.12
+ swr: 2.2.0(react@18.2.0)
+ swr-store: 0.10.6
+ swrv: 1.0.4(vue@3.4.21)
+ vue: 3.4.21(typescript@5.4.2)
+ zod: 3.22.4
+ zod-to-json-schema: 3.22.4(zod@3.22.4)
+ dev: false
+
/ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
dependencies:
@@ -3429,6 +3620,12 @@ packages:
dequal: 2.0.3
dev: false
+ /axobject-query@4.0.0:
+ resolution: {integrity: sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==}
+ dependencies:
+ dequal: 2.0.3
+ dev: false
+
/babel-jest@29.7.0(@babel/core@7.23.9):
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -3505,6 +3702,10 @@ packages:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: false
+ /base-64@0.1.0:
+ resolution: {integrity: sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==}
+ dev: false
+
/binary-extensions@2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
@@ -3660,11 +3861,20 @@ packages:
supports-color: 7.2.0
dev: false
+ /chalk@5.3.0:
+ resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
+ engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+ dev: false
+
/char-regex@1.0.2:
resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
engines: {node: '>=10'}
dev: false
+ /charenc@0.0.2:
+ resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
+ dev: false
+
/chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
@@ -3727,6 +3937,16 @@ packages:
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
dev: false
+ /code-red@1.0.4:
+ resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==}
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.4.15
+ '@types/estree': 1.0.5
+ acorn: 8.11.3
+ estree-walker: 3.0.3
+ periscopic: 3.1.0
+ dev: false
+
/collect-v8-coverage@1.0.2:
resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==}
dev: false
@@ -3810,6 +4030,22 @@ packages:
which: 2.0.2
dev: false
+ /crypt@0.0.2:
+ resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
+ dev: false
+
+ /crypto-js@4.2.0:
+ resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
+ dev: false
+
+ /css-tree@2.3.1:
+ resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+ dependencies:
+ mdn-data: 2.0.30
+ source-map-js: 1.0.2
+ dev: false
+
/css.escape@1.5.1:
resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
dev: false
@@ -3971,11 +4207,22 @@ packages:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
dev: false
+ /diff-match-patch@1.0.5:
+ resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==}
+ dev: false
+
/diff-sequences@29.6.3:
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dev: false
+ /digest-fetch@1.3.0:
+ resolution: {integrity: sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==}
+ dependencies:
+ base-64: 0.1.0
+ md5: 2.3.0
+ dev: false
+
/dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
@@ -4513,11 +4760,31 @@ packages:
engines: {node: '>=4.0'}
dev: false
+ /estree-walker@2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+ dev: false
+
+ /estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+ dependencies:
+ '@types/estree': 1.0.5
+ dev: false
+
/esutils@2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
dev: false
+ /event-target-shim@5.0.1:
+ resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /eventsource-parser@1.0.0:
+ resolution: {integrity: sha512-9jgfSCa3dmEme2ES3mPByGXfgZ87VbP97tng1G2nWwWx6bV2nYxm2AWCrbQjXToSe+yYlqaZNtxffR9IeQr95g==}
+ engines: {node: '>=14.18'}
+ dev: false
+
/execa@5.1.1:
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
engines: {node: '>=10'}
@@ -4652,6 +4919,10 @@ packages:
signal-exit: 4.1.0
dev: false
+ /form-data-encoder@1.7.2:
+ resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
+ dev: false
+
/form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
@@ -4661,6 +4932,14 @@ packages:
mime-types: 2.1.35
dev: false
+ /formdata-node@4.4.1:
+ resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
+ engines: {node: '>= 12.20'}
+ dependencies:
+ node-domexception: 1.0.0
+ web-streams-polyfill: 4.0.0-beta.3
+ dev: false
+
/fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
dev: false
@@ -4935,6 +5214,12 @@ packages:
engines: {node: '>=10.17.0'}
dev: false
+ /humanize-ms@1.2.1:
+ resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
+ dependencies:
+ ms: 2.1.3
+ dev: false
+
/iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'}
@@ -5048,6 +5333,10 @@ packages:
has-tostringtag: 1.0.2
dev: false
+ /is-buffer@1.1.6:
+ resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
+ dev: false
+
/is-buffer@2.0.5:
resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==}
engines: {node: '>=4'}
@@ -5141,6 +5430,12 @@ packages:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
dev: false
+ /is-reference@3.0.2:
+ resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==}
+ dependencies:
+ '@types/estree': 1.0.5
+ dev: false
+
/is-regex@1.1.4:
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
engines: {node: '>= 0.4'}
@@ -5825,6 +6120,16 @@ packages:
hasBin: true
dev: false
+ /jsondiffpatch@0.6.0:
+ resolution: {integrity: sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ dependencies:
+ '@types/diff-match-patch': 1.0.36
+ chalk: 5.3.0
+ diff-match-patch: 1.0.5
+ dev: false
+
/jsx-ast-utils@3.3.5:
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
engines: {node: '>=4.0'}
@@ -5884,6 +6189,10 @@ packages:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: false
+ /locate-character@3.0.0:
+ resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
+ dev: false
+
/locate-path@5.0.0:
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
engines: {node: '>=8'}
@@ -5936,6 +6245,13 @@ packages:
hasBin: true
dev: false
+ /magic-string@0.30.8:
+ resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.4.15
+ dev: false
+
/make-dir@4.0.0:
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
engines: {node: '>=10'}
@@ -5954,6 +6270,18 @@ packages:
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: false
+ /md5@2.3.0:
+ resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
+ dependencies:
+ charenc: 0.0.2
+ crypt: 0.0.2
+ is-buffer: 1.1.6
+ dev: false
+
+ /mdn-data@2.0.30:
+ resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
+ dev: false
+
/merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
dev: false
@@ -6041,6 +6369,12 @@ packages:
thenify-all: 1.6.0
dev: false
+ /nanoid@3.3.6:
+ resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+ dev: false
+
/nanoid@3.3.7:
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -6057,7 +6391,7 @@ packages:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: false
- /next-auth@5.0.0-beta.15(next@14.2.0-canary.31)(react@18.2.0):
+ /next-auth@5.0.0-beta.15(next@14.2.0-canary.39)(react@18.2.0):
resolution: {integrity: sha512-UQggNq8CDu3/w8CYkihKLLnRPNXel98K0j7mtjj9a6XTNYo4Hni8xg/2h1YhElW6vXE8mgtvmH11rU8NKw86jQ==}
peerDependencies:
'@simplewebauthn/browser': ^9.0.1
@@ -6074,7 +6408,7 @@ packages:
optional: true
dependencies:
'@auth/core': 0.28.0
- next: 14.2.0-canary.31(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0)
+ next: 14.2.0-canary.39(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0)
react: 18.2.0
dev: false
@@ -6088,8 +6422,8 @@ packages:
react-dom: 18.2.0(react@18.2.0)
dev: false
- /next@14.2.0-canary.31(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0):
- resolution: {integrity: sha512-aKls3+4raMbu8ex6YDuQFa8U4ajKojXpn8GvdlFtgNUyBHJ7IrVuaFJw6rU9s9OibfgpFnAbsmvKzYQmAAjmlg==}
+ /next@14.2.0-canary.39(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-sTAsUnf7ihBdvN0XwiPKe6kfqxUeEZJaHVOR5RIt2LJ2OnI1mVAp875hjKNxDeOxg2TjpxQCWiEEeKE8IV/tvw==}
engines: {node: '>=18.17.0'}
hasBin: true
peerDependencies:
@@ -6103,7 +6437,7 @@ packages:
sass:
optional: true
dependencies:
- '@next/env': 14.2.0-canary.31
+ '@next/env': 14.2.0-canary.39
'@swc/helpers': 0.5.5
busboy: 1.6.0
caniuse-lite: 1.0.30001591
@@ -6113,20 +6447,37 @@ packages:
react-dom: 18.2.0(react@18.2.0)
styled-jsx: 5.1.1(@babel/core@7.23.9)(react@18.2.0)
optionalDependencies:
- '@next/swc-darwin-arm64': 14.2.0-canary.31
- '@next/swc-darwin-x64': 14.2.0-canary.31
- '@next/swc-linux-arm64-gnu': 14.2.0-canary.31
- '@next/swc-linux-arm64-musl': 14.2.0-canary.31
- '@next/swc-linux-x64-gnu': 14.2.0-canary.31
- '@next/swc-linux-x64-musl': 14.2.0-canary.31
- '@next/swc-win32-arm64-msvc': 14.2.0-canary.31
- '@next/swc-win32-ia32-msvc': 14.2.0-canary.31
- '@next/swc-win32-x64-msvc': 14.2.0-canary.31
+ '@next/swc-darwin-arm64': 14.2.0-canary.39
+ '@next/swc-darwin-x64': 14.2.0-canary.39
+ '@next/swc-linux-arm64-gnu': 14.2.0-canary.39
+ '@next/swc-linux-arm64-musl': 14.2.0-canary.39
+ '@next/swc-linux-x64-gnu': 14.2.0-canary.39
+ '@next/swc-linux-x64-musl': 14.2.0-canary.39
+ '@next/swc-win32-arm64-msvc': 14.2.0-canary.39
+ '@next/swc-win32-ia32-msvc': 14.2.0-canary.39
+ '@next/swc-win32-x64-msvc': 14.2.0-canary.39
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
dev: false
+ /node-domexception@1.0.0:
+ resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
+ engines: {node: '>=10.5.0'}
+ dev: false
+
+ /node-fetch@2.7.0:
+ resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
+ engines: {node: 4.x || >=6.0.0}
+ peerDependencies:
+ encoding: ^0.1.0
+ peerDependenciesMeta:
+ encoding:
+ optional: true
+ dependencies:
+ whatwg-url: 5.0.0
+ dev: false
+
/node-gyp-build@4.8.0:
resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==}
hasBin: true
@@ -6259,6 +6610,23 @@ packages:
mimic-fn: 2.1.0
dev: false
+ /openai@4.29.2:
+ resolution: {integrity: sha512-cPkT6zjEcE4qU5OW/SoDDuXEsdOLrXlAORhzmaguj5xZSPlgKvLhi27sFWhLKj07Y6WKNWxcwIbzm512FzTBNQ==}
+ hasBin: true
+ dependencies:
+ '@types/node': 18.19.24
+ '@types/node-fetch': 2.6.11
+ abort-controller: 3.0.0
+ agentkeepalive: 4.5.0
+ digest-fetch: 1.3.0
+ form-data-encoder: 1.7.2
+ formdata-node: 4.4.1
+ node-fetch: 2.7.0
+ web-streams-polyfill: 3.3.3
+ transitivePeerDependencies:
+ - encoding
+ dev: false
+
/opener@1.5.2:
resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==}
hasBin: true
@@ -6364,6 +6732,14 @@ packages:
engines: {node: '>=8'}
dev: false
+ /periscopic@3.1.0:
+ resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==}
+ dependencies:
+ '@types/estree': 1.0.5
+ estree-walker: 3.0.3
+ is-reference: 3.0.2
+ dev: false
+
/pg-int8@1.0.1:
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
engines: {node: '>=4.0.0'}
@@ -6858,6 +7234,20 @@ packages:
lru-cache: 6.0.0
dev: false
+ /seroval-plugins@1.0.5(seroval@1.0.5):
+ resolution: {integrity: sha512-8+pDC1vOedPXjKG7oz8o+iiHrtF2WswaMQJ7CKFpccvSYfrzmvKY9zOJWCg+881722wIHfwkdnRmiiDm9ym+zQ==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ seroval: ^1.0
+ dependencies:
+ seroval: 1.0.5
+ dev: false
+
+ /seroval@1.0.5:
+ resolution: {integrity: sha512-TM+Z11tHHvQVQKeNlOUonOWnsNM+2IBwZ4vwoi4j3zKzIpc5IDw8WPwCfcc8F17wy6cBcJGbZbFOR0UCuTZHQA==}
+ engines: {node: '>=10'}
+ dev: false
+
/server-only@0.0.1:
resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==}
dev: false
@@ -6932,6 +7322,25 @@ packages:
engines: {node: '>=8'}
dev: false
+ /solid-js@1.8.15:
+ resolution: {integrity: sha512-d0QP/efr3UVcwGgWVPveQQ0IHOH6iU7yUhc2piy8arNG8wxKmvUy1kFxyF8owpmfCWGB87usDKMaVnsNYZm+Vw==}
+ dependencies:
+ csstype: 3.1.3
+ seroval: 1.0.5
+ seroval-plugins: 1.0.5(seroval@1.0.5)
+ dev: false
+
+ /solid-swr-store@0.10.7(solid-js@1.8.15)(swr-store@0.10.6):
+ resolution: {integrity: sha512-A6d68aJmRP471aWqKKPE2tpgOiR5fH4qXQNfKIec+Vap+MGQm3tvXlT8n0I8UgJSlNAsSAUuw2VTviH2h3Vv5g==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ solid-js: ^1.2
+ swr-store: ^0.10
+ dependencies:
+ solid-js: 1.8.15
+ swr-store: 0.10.6
+ dev: false
+
/sonner@1.4.3(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-SArYlHbkjqRuLiR0iGY2ZSr09oOrxw081ZZkQPfXrs8aZQLIBOLOdzTYxGJB5yIZ7qL56UEPmrX1YqbODwG0Lw==}
peerDependencies:
@@ -6963,6 +7372,15 @@ packages:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
dev: false
+ /sswr@2.0.0(svelte@4.2.12):
+ resolution: {integrity: sha512-mV0kkeBHcjcb0M5NqKtKVg/uTIYNlIIniyDfSGrSfxpEdM9C365jK0z55pl9K0xAkNTJi2OAOVFQpgMPUk+V0w==}
+ peerDependencies:
+ svelte: ^4.0.0
+ dependencies:
+ svelte: 4.2.12
+ swrev: 4.0.0
+ dev: false
+
/stack-utils@2.0.6:
resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
engines: {node: '>=10'}
@@ -7150,6 +7568,54 @@ packages:
engines: {node: '>= 0.4'}
dev: false
+ /svelte@4.2.12:
+ resolution: {integrity: sha512-d8+wsh5TfPwqVzbm4/HCXC783/KPHV60NvwitJnyTA5lWn1elhXMNWhXGCJ7PwPa8qFUnyJNIyuIRt2mT0WMug==}
+ engines: {node: '>=16'}
+ dependencies:
+ '@ampproject/remapping': 2.2.1
+ '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/trace-mapping': 0.3.22
+ '@types/estree': 1.0.5
+ acorn: 8.11.3
+ aria-query: 5.3.0
+ axobject-query: 4.0.0
+ code-red: 1.0.4
+ css-tree: 2.3.1
+ estree-walker: 3.0.3
+ is-reference: 3.0.2
+ locate-character: 3.0.0
+ magic-string: 0.30.8
+ periscopic: 3.1.0
+ dev: false
+
+ /swr-store@0.10.6:
+ resolution: {integrity: sha512-xPjB1hARSiRaNNlUQvWSVrG5SirCjk2TmaUyzzvk69SZQan9hCJqw/5rG9iL7xElHU784GxRPISClq4488/XVw==}
+ engines: {node: '>=10'}
+ dependencies:
+ dequal: 2.0.3
+ dev: false
+
+ /swr@2.2.0(react@18.2.0):
+ resolution: {integrity: sha512-AjqHOv2lAhkuUdIiBu9xbuettzAzWXmCEcLONNKJRba87WAefz8Ca9d6ds/SzrPc235n1IxWYdhJ2zF3MNUaoQ==}
+ peerDependencies:
+ react: ^16.11.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ use-sync-external-store: 1.2.0(react@18.2.0)
+ dev: false
+
+ /swrev@4.0.0:
+ resolution: {integrity: sha512-LqVcOHSB4cPGgitD1riJ1Hh4vdmITOp+BkmfmXRh4hSF/t7EnS4iD+SOTmq7w5pPm/SiPeto4ADbKS6dHUDWFA==}
+ dev: false
+
+ /swrv@1.0.4(vue@3.4.21):
+ resolution: {integrity: sha512-zjEkcP8Ywmj+xOJW3lIT65ciY/4AL4e/Or7Gj0MzU3zBJNMdJiT8geVZhINavnlHRMMCcJLHhraLTAiDOTmQ9g==}
+ peerDependencies:
+ vue: '>=3.2.26 < 4'
+ dependencies:
+ vue: 3.4.21(typescript@5.4.2)
+ dev: false
+
/symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
dev: false
@@ -7247,6 +7713,10 @@ packages:
url-parse: 1.5.10
dev: false
+ /tr46@0.0.3:
+ resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+ dev: false
+
/tr46@3.0.0:
resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==}
engines: {node: '>=12'}
@@ -7461,6 +7931,14 @@ packages:
tslib: 2.6.2
dev: false
+ /use-sync-external-store@1.2.0(react@18.2.0):
+ resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
/utf-8-validate@6.0.3:
resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==}
engines: {node: '>=6.14.2'}
@@ -7487,6 +7965,22 @@ packages:
convert-source-map: 2.0.0
dev: false
+ /vue@3.4.21(typescript@5.4.2):
+ resolution: {integrity: sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@vue/compiler-dom': 3.4.21
+ '@vue/compiler-sfc': 3.4.21
+ '@vue/runtime-dom': 3.4.21
+ '@vue/server-renderer': 3.4.21(vue@3.4.21)
+ '@vue/shared': 3.4.21
+ typescript: 5.4.2
+ dev: false
+
/w3c-xmlserializer@4.0.0:
resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==}
engines: {node: '>=14'}
@@ -7500,6 +7994,20 @@ packages:
makeerror: 1.0.12
dev: false
+ /web-streams-polyfill@3.3.3:
+ resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
+ engines: {node: '>= 8'}
+ dev: false
+
+ /web-streams-polyfill@4.0.0-beta.3:
+ resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
+ engines: {node: '>= 14'}
+ dev: false
+
+ /webidl-conversions@3.0.1:
+ resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+ dev: false
+
/webidl-conversions@7.0.0:
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
engines: {node: '>=12'}
@@ -7548,6 +8056,13 @@ packages:
webidl-conversions: 7.0.0
dev: false
+ /whatwg-url@5.0.0:
+ resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+ dependencies:
+ tr46: 0.0.3
+ webidl-conversions: 3.0.1
+ dev: false
+
/which-boxed-primitive@1.0.2:
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
dependencies:
@@ -7730,3 +8245,15 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: false
+
+ /zod-to-json-schema@3.22.4(zod@3.22.4):
+ resolution: {integrity: sha512-2Ed5dJ+n/O3cU383xSY28cuVi0BCQhF8nYqWU5paEpl7fVdqdAmiLdqLyfblbNdfOFwFfi/mqU4O1pwc60iBhQ==}
+ peerDependencies:
+ zod: ^3.22.4
+ dependencies:
+ zod: 3.22.4
+ dev: false
+
+ /zod@3.22.4:
+ resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
+ dev: false
diff --git a/src/app/admin/photos/[photoId]/edit/page.tsx b/src/app/admin/photos/[photoId]/edit/page.tsx
index 2a5c2d6c..c9a5c68c 100644
--- a/src/app/admin/photos/[photoId]/edit/page.tsx
+++ b/src/app/admin/photos/[photoId]/edit/page.tsx
@@ -2,6 +2,7 @@ import { redirect } from 'next/navigation';
import { getPhotoNoStore, getUniqueTagsCached } from '@/photo/cache';
import { PATH_ADMIN } from '@/site/paths';
import PhotoEditPageClient from '@/photo/PhotoEditPageClient';
+import { AI_TEXT_GENERATION_ENABLED } from '@/site/config';
export default async function PhotoEditPage({
params: { photoId },
@@ -14,7 +15,13 @@ export default async function PhotoEditPage({
const uniqueTags = await getUniqueTagsCached();
+ const hasAiTextGeneration = AI_TEXT_GENERATION_ENABLED;
+
return (
-