mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Feature/google cloud storage (#316)
* environment setup and reproduce * rmv my dashboard * Stop tracking my-dashboard * gitignore: ignore all .env files * working UI, not yet tested * Update credential validation Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * tested with fake-gcs-server * fix: migration * fix: migration, init for gcs and refactoring * fix: get object gcs --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Charles GTE <charlesgte31@gmail.com>
This commit is contained in:
co-authored by
coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Charles GTE
parent
79832f0d0b
commit
8f44071069
@@ -9,6 +9,8 @@
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
gcs-data/
|
||||
gcs-storage/
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
@@ -28,6 +30,8 @@ yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
.env
|
||||
**/.env
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
@@ -55,9 +55,56 @@ services:
|
||||
|
||||
# DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;
|
||||
|
||||
gcs:
|
||||
image: fsouza/fake-gcs-server:latest
|
||||
container_name: fake-gcs
|
||||
ports:
|
||||
- "4443:4443"
|
||||
command:
|
||||
- "-scheme"
|
||||
- "http"
|
||||
- "-port"
|
||||
- "4443"
|
||||
- "-public-host"
|
||||
- "localhost:4443"
|
||||
- "-external-url"
|
||||
- "http://localhost:4443"
|
||||
- "-backend"
|
||||
- "filesystem"
|
||||
- "-filesystem-root"
|
||||
- "/storage"
|
||||
volumes:
|
||||
- gcs-data:/data
|
||||
- gcs-storage:/storage
|
||||
networks:
|
||||
- portabase
|
||||
|
||||
gcs-init:
|
||||
image: curlimages/curl:latest
|
||||
depends_on:
|
||||
- gcs
|
||||
entrypoint: ["/bin/sh", "-c"]
|
||||
command: >
|
||||
'until curl -fsS http://gcs:4443/storage/v1/b >/dev/null; do sleep 1; done;
|
||||
curl -fsS http://gcs:4443/storage/v1/b/portabase >/dev/null
|
||||
|| curl -fsS -X POST "http://gcs:4443/storage/v1/b?project=local"
|
||||
-H "Content-Type: application/json"
|
||||
-d "{\"name\":\"portabase\"}"'
|
||||
networks:
|
||||
- portabase
|
||||
|
||||
# curl http://localhost:4443/storage/v1/b
|
||||
# projectId: "test-project",
|
||||
# bucketName: "portabase",
|
||||
# clientEmail: "fake@test.iam.gserviceaccount.com",
|
||||
# privateKey: "unused-when-emulated",
|
||||
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
azurite-data:
|
||||
gcs-data:
|
||||
gcs-storage:
|
||||
|
||||
networks:
|
||||
portabase:
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"@better-auth/core": "1.6.11",
|
||||
"@better-auth/passkey": "1.6.11",
|
||||
"@better-auth/sso": "1.6.11",
|
||||
"@google-cloud/storage": "^7.19.0",
|
||||
"@hookform/resolvers": "^5.4.0",
|
||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||
"@onboardjs/react": "1.0.0-rc.5",
|
||||
|
||||
Generated
+285
-12
@@ -26,6 +26,9 @@ importers:
|
||||
'@better-auth/sso':
|
||||
specifier: 1.6.11
|
||||
version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.21.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(@playwright/test@1.58.2)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.21.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(better-call@1.3.5(zod@4.3.6))
|
||||
'@google-cloud/storage':
|
||||
specifier: ^7.19.0
|
||||
version: 7.21.0
|
||||
'@hookform/resolvers':
|
||||
specifier: ^5.4.0
|
||||
version: 5.4.0(react-hook-form@7.77.0(react@19.2.7))
|
||||
@@ -1508,6 +1511,22 @@ packages:
|
||||
'@floating-ui/utils@0.2.11':
|
||||
resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==}
|
||||
|
||||
'@google-cloud/paginator@5.0.2':
|
||||
resolution: {integrity: sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
'@google-cloud/projectify@4.0.0':
|
||||
resolution: {integrity: sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
'@google-cloud/promisify@4.0.0':
|
||||
resolution: {integrity: sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@google-cloud/storage@7.21.0':
|
||||
resolution: {integrity: sha512-l+IFTkd+6Y5LoAuXyYCKNAKtw/Ci+rAMqgdTB1jv4iZiLhw0rtq+0qjIRbBizXkNzEFmXiXUW0H7sZQQvk1ffA==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@grpc/grpc-js@1.14.4':
|
||||
resolution: {integrity: sha512-k9Dj3DV/itK9D06Y8f190Qgop7/Ui+D0njFV3LHMPwPT75DpXLQohE9Wmz0QElrJnzsjB7KPWiKJbOl7IPDArQ==}
|
||||
engines: {node: '>=12.10.0'}
|
||||
@@ -3856,6 +3875,10 @@ packages:
|
||||
resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
'@tootallnate/once@2.0.1':
|
||||
resolution: {integrity: sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==}
|
||||
engines: {node: '>= 10'}
|
||||
|
||||
'@tootallnate/quickjs-emscripten@0.23.0':
|
||||
resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==}
|
||||
|
||||
@@ -3871,6 +3894,9 @@ packages:
|
||||
'@types/canvas-confetti@1.9.0':
|
||||
resolution: {integrity: sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg==}
|
||||
|
||||
'@types/caseless@0.12.5':
|
||||
resolution: {integrity: sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==}
|
||||
|
||||
'@types/cors@2.8.19':
|
||||
resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==}
|
||||
|
||||
@@ -3963,6 +3989,12 @@ packages:
|
||||
'@types/react@19.2.17':
|
||||
resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==}
|
||||
|
||||
'@types/request@2.48.13':
|
||||
resolution: {integrity: sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg==}
|
||||
|
||||
'@types/tough-cookie@4.0.5':
|
||||
resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
|
||||
|
||||
'@types/webpack@5.28.5':
|
||||
resolution: {integrity: sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw==}
|
||||
|
||||
@@ -4254,6 +4286,10 @@ packages:
|
||||
'@zenstackhq/tanstack-query@2.22.2':
|
||||
resolution: {integrity: sha512-VXYc9MyJRuEbwvkcIKwsgKjKSW44Gh19YPNGarR5//IfjZ2+uPf916vrOiOXb6Qzyc9aU3PriDYFrkZY5enK1g==}
|
||||
|
||||
abort-controller@3.0.0:
|
||||
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
||||
engines: {node: '>=6.5'}
|
||||
|
||||
accepts@1.3.8:
|
||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@@ -4393,6 +4429,10 @@ packages:
|
||||
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
arrify@2.0.1:
|
||||
resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
asn1@0.2.6:
|
||||
resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
|
||||
|
||||
@@ -4421,6 +4461,9 @@ packages:
|
||||
async@3.2.6:
|
||||
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
|
||||
|
||||
asynckit@0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
|
||||
atomic-sleep@1.0.0:
|
||||
resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
@@ -4806,6 +4849,10 @@ packages:
|
||||
resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==}
|
||||
engines: {node: '>=0.1.90'}
|
||||
|
||||
combined-stream@1.0.8:
|
||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
commander@13.1.0:
|
||||
resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -5094,6 +5141,10 @@ packages:
|
||||
resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
delayed-stream@1.0.0:
|
||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
|
||||
depd@2.0.0:
|
||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@@ -5267,6 +5318,9 @@ packages:
|
||||
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
duplexify@4.1.3:
|
||||
resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==}
|
||||
|
||||
eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
@@ -5579,6 +5633,10 @@ packages:
|
||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
event-target-shim@5.0.1:
|
||||
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
eventemitter3@4.0.7:
|
||||
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
|
||||
|
||||
@@ -5722,6 +5780,10 @@ packages:
|
||||
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
form-data@2.5.6:
|
||||
resolution: {integrity: sha512-Ogz/E85h9tlfJzpI6TuFpGcHZFhLrb9Gw8wq9v40CxSCPnv7ahKr6Xgtkn0KYCDQJ8DNn5VoMO8EXr9V5PadyA==}
|
||||
engines: {node: '>= 0.12'}
|
||||
|
||||
format@0.2.2:
|
||||
resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
|
||||
engines: {node: '>=0.4.x'}
|
||||
@@ -5796,6 +5858,10 @@ packages:
|
||||
functions-have-names@1.2.3:
|
||||
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
|
||||
|
||||
gaxios@6.7.1:
|
||||
resolution: {integrity: sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
gaxios@7.1.3:
|
||||
resolution: {integrity: sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -5804,6 +5870,10 @@ packages:
|
||||
resolution: {integrity: sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
gcp-metadata@6.1.1:
|
||||
resolution: {integrity: sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
gcp-metadata@8.1.2:
|
||||
resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -5915,6 +5985,14 @@ packages:
|
||||
resolution: {integrity: sha512-QpTAbNJ36TliZLx3TTtahR8HG0hN9RllL1e3FymOvQSIKK8JmgV58H924ub2wa2DsS3ANjjP1Aw1N+Ramc8hqQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
google-auth-library@9.15.1:
|
||||
resolution: {integrity: sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
google-logging-utils@0.0.2:
|
||||
resolution: {integrity: sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
google-logging-utils@1.1.3:
|
||||
resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -5934,6 +6012,10 @@ packages:
|
||||
graceful-fs@4.2.11:
|
||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||
|
||||
gtoken@7.1.0:
|
||||
resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
gtoken@8.0.0:
|
||||
resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -5997,6 +6079,9 @@ packages:
|
||||
resolution: {integrity: sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==}
|
||||
engines: {node: ^18.17.0 || >=20.5.0}
|
||||
|
||||
html-entities@2.6.0:
|
||||
resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==}
|
||||
|
||||
html-to-text@9.0.5:
|
||||
resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -6011,6 +6096,10 @@ packages:
|
||||
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
http-proxy-agent@5.0.0:
|
||||
resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -6215,6 +6304,10 @@ packages:
|
||||
is-ssh@1.4.1:
|
||||
resolution: {integrity: sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==}
|
||||
|
||||
is-stream@2.0.1:
|
||||
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-stream@3.0.0:
|
||||
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
@@ -6628,6 +6721,11 @@ packages:
|
||||
resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
mime@3.0.0:
|
||||
resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
hasBin: true
|
||||
|
||||
mimic-fn@2.1.0:
|
||||
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -7600,6 +7698,10 @@ packages:
|
||||
resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
retry-request@7.0.2:
|
||||
resolution: {integrity: sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
retry@0.13.1:
|
||||
resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
|
||||
engines: {node: '>= 4'}
|
||||
@@ -7881,9 +7983,15 @@ packages:
|
||||
stream-chain@2.2.5:
|
||||
resolution: {integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==}
|
||||
|
||||
stream-events@1.0.5:
|
||||
resolution: {integrity: sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==}
|
||||
|
||||
stream-json@1.9.1:
|
||||
resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==}
|
||||
|
||||
stream-shift@1.0.3:
|
||||
resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==}
|
||||
|
||||
strict-uri-encode@2.0.0:
|
||||
resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -7961,6 +8069,9 @@ packages:
|
||||
strnum@2.3.0:
|
||||
resolution: {integrity: sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==}
|
||||
|
||||
stubs@3.0.0:
|
||||
resolution: {integrity: sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==}
|
||||
|
||||
styled-jsx@5.1.6:
|
||||
resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
@@ -8037,6 +8148,10 @@ packages:
|
||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
teeny-request@9.0.0:
|
||||
resolution: {integrity: sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
terminal-link@2.1.1:
|
||||
resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -9513,6 +9628,35 @@ snapshots:
|
||||
|
||||
'@floating-ui/utils@0.2.11': {}
|
||||
|
||||
'@google-cloud/paginator@5.0.2':
|
||||
dependencies:
|
||||
arrify: 2.0.1
|
||||
extend: 3.0.2
|
||||
|
||||
'@google-cloud/projectify@4.0.0': {}
|
||||
|
||||
'@google-cloud/promisify@4.0.0': {}
|
||||
|
||||
'@google-cloud/storage@7.21.0':
|
||||
dependencies:
|
||||
'@google-cloud/paginator': 5.0.2
|
||||
'@google-cloud/projectify': 4.0.0
|
||||
'@google-cloud/promisify': 4.0.0
|
||||
abort-controller: 3.0.0
|
||||
async-retry: 1.3.3
|
||||
duplexify: 4.1.3
|
||||
fast-xml-parser: 5.8.0
|
||||
gaxios: 6.7.1
|
||||
google-auth-library: 9.15.1
|
||||
html-entities: 2.6.0
|
||||
mime: 3.0.0
|
||||
p-limit: 3.1.0
|
||||
retry-request: 7.0.2
|
||||
teeny-request: 9.0.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- supports-color
|
||||
|
||||
'@grpc/grpc-js@1.14.4':
|
||||
dependencies:
|
||||
'@grpc/proto-loader': 0.8.1
|
||||
@@ -11860,6 +12004,8 @@ snapshots:
|
||||
|
||||
'@tanstack/table-core@8.21.3': {}
|
||||
|
||||
'@tootallnate/once@2.0.1': {}
|
||||
|
||||
'@tootallnate/quickjs-emscripten@0.23.0': {}
|
||||
|
||||
'@ts-morph/common@0.17.0':
|
||||
@@ -11882,6 +12028,8 @@ snapshots:
|
||||
|
||||
'@types/canvas-confetti@1.9.0': {}
|
||||
|
||||
'@types/caseless@0.12.5': {}
|
||||
|
||||
'@types/cors@2.8.19':
|
||||
dependencies:
|
||||
'@types/node': 22.19.20
|
||||
@@ -11977,11 +12125,20 @@ snapshots:
|
||||
dependencies:
|
||||
csstype: 3.2.3
|
||||
|
||||
'@types/request@2.48.13':
|
||||
dependencies:
|
||||
'@types/caseless': 0.12.5
|
||||
'@types/node': 22.19.20
|
||||
'@types/tough-cookie': 4.0.5
|
||||
form-data: 2.5.6
|
||||
|
||||
'@types/tough-cookie@4.0.5': {}
|
||||
|
||||
'@types/webpack@5.28.5(esbuild@0.25.10)(postcss@8.5.10)':
|
||||
dependencies:
|
||||
'@types/node': 22.19.20
|
||||
tapable: 2.3.3
|
||||
webpack: 5.107.2(esbuild@0.25.10)(postcss@8.5.10)
|
||||
webpack: 5.107.2(esbuild@0.27.7)(postcss@8.5.10)
|
||||
transitivePeerDependencies:
|
||||
- '@minify-html/node'
|
||||
- '@swc/core'
|
||||
@@ -12406,6 +12563,10 @@ snapshots:
|
||||
- typescript
|
||||
- zod
|
||||
|
||||
abort-controller@3.0.0:
|
||||
dependencies:
|
||||
event-target-shim: 5.0.1
|
||||
|
||||
accepts@1.3.8:
|
||||
dependencies:
|
||||
mime-types: 2.1.35
|
||||
@@ -12567,6 +12728,8 @@ snapshots:
|
||||
get-intrinsic: 1.3.0
|
||||
is-array-buffer: 3.0.5
|
||||
|
||||
arrify@2.0.1: {}
|
||||
|
||||
asn1@0.2.6:
|
||||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
@@ -12593,6 +12756,8 @@ snapshots:
|
||||
|
||||
async@3.2.6: {}
|
||||
|
||||
asynckit@0.4.0: {}
|
||||
|
||||
atomic-sleep@1.0.0: {}
|
||||
|
||||
attr-accept@2.2.5: {}
|
||||
@@ -12995,6 +13160,10 @@ snapshots:
|
||||
|
||||
colors@1.4.0: {}
|
||||
|
||||
combined-stream@1.0.8:
|
||||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
|
||||
commander@13.1.0: {}
|
||||
|
||||
commander@2.20.3: {}
|
||||
@@ -13256,6 +13425,8 @@ snapshots:
|
||||
escodegen: 2.1.0
|
||||
esprima: 4.0.1
|
||||
|
||||
delayed-stream@1.0.0: {}
|
||||
|
||||
depd@2.0.0: {}
|
||||
|
||||
destr@2.0.5: {}
|
||||
@@ -13357,6 +13528,13 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
gopd: 1.2.0
|
||||
|
||||
duplexify@4.1.3:
|
||||
dependencies:
|
||||
end-of-stream: 1.4.5
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
stream-shift: 1.0.3
|
||||
|
||||
eastasianwidth@0.2.0: {}
|
||||
|
||||
ecdsa-sig-formatter@1.0.11:
|
||||
@@ -13726,7 +13904,7 @@ snapshots:
|
||||
'@next/eslint-plugin-next': 16.2.7
|
||||
eslint: 9.39.4(jiti@2.7.0)
|
||||
eslint-import-resolver-node: 0.3.10
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0))
|
||||
@@ -13749,7 +13927,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)):
|
||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)):
|
||||
dependencies:
|
||||
'@nolyfill/is-core-module': 1.0.39
|
||||
debug: 4.4.3
|
||||
@@ -13764,14 +13942,14 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.13.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)):
|
||||
eslint-module-utils@2.13.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)
|
||||
eslint: 9.39.4(jiti@2.7.0)
|
||||
eslint-import-resolver-node: 0.3.10
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -13786,7 +13964,7 @@ snapshots:
|
||||
doctrine: 2.1.0
|
||||
eslint: 9.39.4(jiti@2.7.0)
|
||||
eslint-import-resolver-node: 0.3.10
|
||||
eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))
|
||||
eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0))
|
||||
hasown: 2.0.4
|
||||
is-core-module: 2.16.2
|
||||
is-glob: 4.0.3
|
||||
@@ -13947,6 +14125,8 @@ snapshots:
|
||||
|
||||
etag@1.8.1: {}
|
||||
|
||||
event-target-shim@5.0.1: {}
|
||||
|
||||
eventemitter3@4.0.7: {}
|
||||
|
||||
eventemitter3@5.0.4: {}
|
||||
@@ -14129,6 +14309,15 @@ snapshots:
|
||||
cross-spawn: 7.0.6
|
||||
signal-exit: 4.1.0
|
||||
|
||||
form-data@2.5.6:
|
||||
dependencies:
|
||||
asynckit: 0.4.0
|
||||
combined-stream: 1.0.8
|
||||
es-set-tostringtag: 2.1.0
|
||||
hasown: 2.0.4
|
||||
mime-types: 2.1.35
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
format@0.2.2: {}
|
||||
|
||||
formdata-polyfill@4.0.10:
|
||||
@@ -14186,6 +14375,17 @@ snapshots:
|
||||
|
||||
functions-have-names@1.2.3: {}
|
||||
|
||||
gaxios@6.7.1:
|
||||
dependencies:
|
||||
extend: 3.0.2
|
||||
https-proxy-agent: 7.0.6
|
||||
is-stream: 2.0.1
|
||||
node-fetch: 2.7.0
|
||||
uuid: 9.0.1
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- supports-color
|
||||
|
||||
gaxios@7.1.3:
|
||||
dependencies:
|
||||
extend: 3.0.2
|
||||
@@ -14203,6 +14403,15 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
gcp-metadata@6.1.1:
|
||||
dependencies:
|
||||
gaxios: 6.7.1
|
||||
google-logging-utils: 0.0.2
|
||||
json-bigint: 1.0.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- supports-color
|
||||
|
||||
gcp-metadata@8.1.2:
|
||||
dependencies:
|
||||
gaxios: 7.1.5
|
||||
@@ -14330,7 +14539,7 @@ snapshots:
|
||||
dependencies:
|
||||
base64-js: 1.5.1
|
||||
ecdsa-sig-formatter: 1.0.11
|
||||
gaxios: 7.1.3
|
||||
gaxios: 7.1.5
|
||||
gcp-metadata: 8.1.3
|
||||
google-logging-utils: 1.1.3
|
||||
gtoken: 8.0.0
|
||||
@@ -14349,6 +14558,20 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
google-auth-library@9.15.1:
|
||||
dependencies:
|
||||
base64-js: 1.5.1
|
||||
ecdsa-sig-formatter: 1.0.11
|
||||
gaxios: 6.7.1
|
||||
gcp-metadata: 6.1.1
|
||||
gtoken: 7.1.0
|
||||
jws: 4.0.1
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- supports-color
|
||||
|
||||
google-logging-utils@0.0.2: {}
|
||||
|
||||
google-logging-utils@1.1.3: {}
|
||||
|
||||
googleapis-common@8.0.2:
|
||||
@@ -14373,9 +14596,17 @@ snapshots:
|
||||
|
||||
graceful-fs@4.2.11: {}
|
||||
|
||||
gtoken@7.1.0:
|
||||
dependencies:
|
||||
gaxios: 6.7.1
|
||||
jws: 4.0.1
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- supports-color
|
||||
|
||||
gtoken@8.0.0:
|
||||
dependencies:
|
||||
gaxios: 7.1.3
|
||||
gaxios: 7.1.5
|
||||
jws: 4.0.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -14434,6 +14665,8 @@ snapshots:
|
||||
dependencies:
|
||||
lru-cache: 10.4.3
|
||||
|
||||
html-entities@2.6.0: {}
|
||||
|
||||
html-to-text@9.0.5:
|
||||
dependencies:
|
||||
'@selderee/plugin-htmlparser2': 0.11.0
|
||||
@@ -14464,6 +14697,14 @@ snapshots:
|
||||
statuses: 2.0.2
|
||||
toidentifier: 1.0.1
|
||||
|
||||
http-proxy-agent@5.0.0:
|
||||
dependencies:
|
||||
'@tootallnate/once': 2.0.1
|
||||
agent-base: 6.0.2
|
||||
debug: 4.4.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
dependencies:
|
||||
agent-base: 7.1.4
|
||||
@@ -14655,6 +14896,8 @@ snapshots:
|
||||
dependencies:
|
||||
protocols: 2.0.2
|
||||
|
||||
is-stream@2.0.1: {}
|
||||
|
||||
is-stream@3.0.0: {}
|
||||
|
||||
is-string@1.1.1:
|
||||
@@ -15006,6 +15249,8 @@ snapshots:
|
||||
dependencies:
|
||||
mime-db: 1.54.0
|
||||
|
||||
mime@3.0.0: {}
|
||||
|
||||
mimic-fn@2.1.0: {}
|
||||
|
||||
mimic-fn@4.0.0: {}
|
||||
@@ -16097,6 +16342,15 @@ snapshots:
|
||||
onetime: 7.0.0
|
||||
signal-exit: 4.1.0
|
||||
|
||||
retry-request@7.0.2:
|
||||
dependencies:
|
||||
'@types/request': 2.48.13
|
||||
extend: 3.0.2
|
||||
teeny-request: 9.0.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- supports-color
|
||||
|
||||
retry@0.13.1: {}
|
||||
|
||||
reusify@1.1.0: {}
|
||||
@@ -16496,10 +16750,16 @@ snapshots:
|
||||
|
||||
stream-chain@2.2.5: {}
|
||||
|
||||
stream-events@1.0.5:
|
||||
dependencies:
|
||||
stubs: 3.0.0
|
||||
|
||||
stream-json@1.9.1:
|
||||
dependencies:
|
||||
stream-chain: 2.2.5
|
||||
|
||||
stream-shift@1.0.3: {}
|
||||
|
||||
strict-uri-encode@2.0.0: {}
|
||||
|
||||
string-width@4.2.3:
|
||||
@@ -16600,6 +16860,8 @@ snapshots:
|
||||
|
||||
strnum@2.3.0: {}
|
||||
|
||||
stubs@3.0.0: {}
|
||||
|
||||
styled-jsx@5.1.6(@babel/core@7.26.10)(react@19.0.0):
|
||||
dependencies:
|
||||
client-only: 0.0.1
|
||||
@@ -16706,18 +16968,29 @@ snapshots:
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
|
||||
teeny-request@9.0.0:
|
||||
dependencies:
|
||||
http-proxy-agent: 5.0.0
|
||||
https-proxy-agent: 5.0.0
|
||||
node-fetch: 2.7.0
|
||||
stream-events: 1.0.5
|
||||
uuid: 9.0.1
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- supports-color
|
||||
|
||||
terminal-link@2.1.1:
|
||||
dependencies:
|
||||
ansi-escapes: 4.3.2
|
||||
supports-hyperlinks: 2.3.0
|
||||
|
||||
terser-webpack-plugin@5.6.1(esbuild@0.25.10)(postcss@8.5.10)(webpack@5.107.2(esbuild@0.25.10)(postcss@8.5.10)):
|
||||
terser-webpack-plugin@5.6.1(esbuild@0.25.10)(postcss@8.5.10)(webpack@5.107.2(esbuild@0.27.7)(postcss@8.5.10)):
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
jest-worker: 27.5.1
|
||||
schema-utils: 4.3.3
|
||||
terser: 5.48.0
|
||||
webpack: 5.107.2(esbuild@0.25.10)(postcss@8.5.10)
|
||||
webpack: 5.107.2(esbuild@0.27.7)(postcss@8.5.10)
|
||||
optionalDependencies:
|
||||
esbuild: 0.25.10
|
||||
postcss: 8.5.10
|
||||
@@ -17114,7 +17387,7 @@ snapshots:
|
||||
|
||||
webpack-sources@3.5.0: {}
|
||||
|
||||
webpack@5.107.2(esbuild@0.25.10)(postcss@8.5.10):
|
||||
webpack@5.107.2(esbuild@0.27.7)(postcss@8.5.10):
|
||||
dependencies:
|
||||
'@types/estree': 1.0.9
|
||||
'@types/json-schema': 7.0.15
|
||||
@@ -17136,7 +17409,7 @@ snapshots:
|
||||
neo-async: 2.6.2
|
||||
schema-utils: 4.3.3
|
||||
tapable: 2.3.3
|
||||
terser-webpack-plugin: 5.6.1(esbuild@0.25.10)(postcss@8.5.10)(webpack@5.107.2(esbuild@0.25.10)(postcss@8.5.10))
|
||||
terser-webpack-plugin: 5.6.1(esbuild@0.25.10)(postcss@8.5.10)(webpack@5.107.2(esbuild@0.27.7)(postcss@8.5.10))
|
||||
watchpack: 2.5.1
|
||||
webpack-sources: 3.5.0
|
||||
transitivePeerDependencies:
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TYPE "public"."provider_storage_kind" ADD VALUE 'google-cloud-storage' BEFORE 'blob';
|
||||
File diff suppressed because it is too large
Load Diff
@@ -477,6 +477,13 @@
|
||||
"when": 1782573099089,
|
||||
"tag": "0067_clammy_stephen_strange",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 68,
|
||||
"version": "7",
|
||||
"when": 1782575192480,
|
||||
"tag": "0068_busy_zeigeist",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import {relations} from "drizzle-orm";
|
||||
import {createSelectSchema} from "drizzle-zod";
|
||||
import {z} from "zod";
|
||||
|
||||
export const providerStorageKindEnum = pgEnum('provider_storage_kind', ['local', 's3', 'google-drive', 'blob']);
|
||||
export const providerStorageKindEnum = pgEnum('provider_storage_kind', ['local', 's3', 'google-drive', 'google-cloud-storage', 'blob']);
|
||||
|
||||
export const storageChannel = pgTable('storage_channel', {
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
|
||||
@@ -44,6 +44,10 @@ import {
|
||||
import {
|
||||
StorageBlobForm
|
||||
} from "@/features/channel/components/storages/az-blob.form";
|
||||
import {
|
||||
StorageGoogleCloudStorageForm
|
||||
} from "@/features/channel/components/storages/google-cloud-storage/google-cloud-storage.form";
|
||||
|
||||
|
||||
export type ChannelKind = "notification" | "storage";
|
||||
|
||||
@@ -109,6 +113,8 @@ export const renderChannelForm = (provider: string | undefined, form: UseFormRet
|
||||
return <StorageS3Form form={form}/>
|
||||
case "google-drive":
|
||||
return <StorageGoogleDriveForm form={form}/>
|
||||
case "google-cloud-storage":
|
||||
return <StorageGoogleCloudStorageForm form={form}/>
|
||||
case "blob":
|
||||
return <StorageBlobForm form={form}/>
|
||||
case "local":
|
||||
|
||||
@@ -7,7 +7,7 @@ export const storageProviders: ProviderIconTypes[] = [
|
||||
{value: "s3", label: "S3", icon: S3Icon},
|
||||
{value: "google-drive", label: "Google Drive", icon: GoogleDriveIcon},
|
||||
{value: "blob", label: "Azure Blob Storage", icon: BlobIcon},
|
||||
{value: "gcs", label: "Google Cloud Storage", icon: GCSIcon, preview: true},
|
||||
{value: "google-cloud-storage", label: "Google Cloud Storage", icon: GCSIcon},
|
||||
]
|
||||
|
||||
export function S3Icon(props: SVGProps<SVGSVGElement>) {
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
import { UseFormReturn } from "react-hook-form";
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
|
||||
type StorageGoogleCloudStorageFormProps = {
|
||||
form: UseFormReturn<any, any, any>;
|
||||
};
|
||||
|
||||
export const StorageGoogleCloudStorageForm = ({
|
||||
form,
|
||||
}: StorageGoogleCloudStorageFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<Separator className="my-1" />
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.projectId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Project ID *</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} value={field.value ?? ""} placeholder="e.g. my-gcp-project" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.bucketName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Bucket name *</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} value={field.value ?? ""} placeholder="e.g. backups-prod" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.clientEmail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Client email *</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
placeholder="e.g. service-account@my-gcp-project.iam.gserviceaccount.com"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.apiEndpoint"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Endpoint URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
placeholder="e.g. http://localhost:4443"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.privateKey"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Private key *</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
rows={5}
|
||||
placeholder="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import {z} from "zod";
|
||||
|
||||
export const GoogleCloudStorageChannelConfigSchema = z.object({
|
||||
projectId: z.string().trim().min(1, "Project ID is required"),
|
||||
bucketName: z.string().trim().min(1, "Bucket name is required"),
|
||||
clientEmail: z.email("Client email must be a valid email").trim(),
|
||||
privateKey: z.string().trim().min(1, "Private key is required"),
|
||||
apiEndpoint: z.preprocess(
|
||||
(v) => (v === "" ? undefined : v),
|
||||
z.string().url("Endpoint URL must be a valid URL").optional(),
|
||||
),
|
||||
});
|
||||
@@ -0,0 +1,179 @@
|
||||
import {Storage} from "@google-cloud/storage";
|
||||
|
||||
import {Readable} from "node:stream";
|
||||
import {GoogleCloudStorageConfig} from "@/features/channel/components/storages/google-cloud-storage/types";
|
||||
import {
|
||||
StorageCopyInput,
|
||||
StorageDeleteInput,
|
||||
StorageGetInput,
|
||||
StorageMetaData,
|
||||
StorageResult,
|
||||
StorageUploadInput
|
||||
} from "@/features/storages/types";
|
||||
|
||||
async function getGoogleCloudStorageClient(config: GoogleCloudStorageConfig) {
|
||||
return new Storage({
|
||||
projectId: config.projectId,
|
||||
...(config.apiEndpoint ? {apiEndpoint: config.apiEndpoint} : {}),
|
||||
credentials: {
|
||||
client_email: config.clientEmail,
|
||||
private_key: config.privateKey.replace(/\\n/g, "\n"),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const BASE_DIR = "";
|
||||
|
||||
async function ensureBucket(config: GoogleCloudStorageConfig) {
|
||||
const client = await getGoogleCloudStorageClient(config);
|
||||
const [exists] = await client.bucket(config.bucketName).exists();
|
||||
if (!exists) throw new Error(`Bucket "${config.bucketName}" does not exist`);
|
||||
}
|
||||
|
||||
export async function uploadGoogleCloudStorage(
|
||||
config: GoogleCloudStorageConfig,
|
||||
input: { data: StorageUploadInput, metadata?: StorageMetaData }
|
||||
): Promise<StorageResult> {
|
||||
const client = await getGoogleCloudStorageClient(config);
|
||||
await ensureBucket(config);
|
||||
|
||||
const key = `${BASE_DIR}${input.data.path}`;
|
||||
const file = input.data.file;
|
||||
|
||||
let uploadStream: Readable;
|
||||
if (Buffer.isBuffer(file) || file instanceof Uint8Array) {
|
||||
uploadStream = Readable.from(file);
|
||||
} else if ((file as any).pipe) {
|
||||
uploadStream = file as Readable;
|
||||
} else {
|
||||
return {success: false, provider: "google-cloud-storage", error: "Unsupported file type for streaming upload"};
|
||||
}
|
||||
|
||||
try {
|
||||
const writeStream = client
|
||||
.bucket(config.bucketName)
|
||||
.file(key)
|
||||
.createWriteStream({contentType: input.data.contentType});
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
uploadStream
|
||||
.pipe(writeStream)
|
||||
.on("finish", resolve)
|
||||
.on("error", reject);
|
||||
});
|
||||
} catch (err: any) {
|
||||
return {success: false, provider: "google-cloud-storage", error: err.message};
|
||||
}
|
||||
|
||||
return {success: true, provider: "google-cloud-storage"};
|
||||
}
|
||||
|
||||
export async function getGoogleCloudStorage(
|
||||
config: GoogleCloudStorageConfig,
|
||||
input: { data: StorageGetInput, metadata: StorageMetaData }
|
||||
): Promise<StorageResult> {
|
||||
const client = await getGoogleCloudStorageClient(config);
|
||||
const key = `${BASE_DIR}${input.data.path}`;
|
||||
const file = client.bucket(config.bucketName).file(key);
|
||||
|
||||
const [exists] = await file.exists();
|
||||
if (!exists) return {success: false, provider: "google-cloud-storage", error: "File not found"};
|
||||
|
||||
const fileStream = file.createReadStream();
|
||||
|
||||
let signedUrl: string | undefined;
|
||||
if (input.data.signedUrl) {
|
||||
if (config.apiEndpoint) {
|
||||
signedUrl = `${config.apiEndpoint.replace(/\/$/, "")}/${config.bucketName}/${encodeURI(key)}`;
|
||||
} else {
|
||||
const [url] = await file.getSignedUrl({
|
||||
action: "read",
|
||||
expires: Date.now() + (input.data.expiresInSeconds ?? 60) * 1000,
|
||||
});
|
||||
signedUrl = url;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
provider: "google-cloud-storage",
|
||||
file: fileStream as unknown as Buffer | Readable,
|
||||
url: signedUrl,
|
||||
};
|
||||
}
|
||||
|
||||
export async function deleteGoogleCloudStorage(config: GoogleCloudStorageConfig, input: {
|
||||
data: StorageDeleteInput,
|
||||
metadata?: StorageMetaData
|
||||
}): Promise<StorageResult> {
|
||||
const client = await getGoogleCloudStorageClient(config);
|
||||
const key = `${BASE_DIR}${input.data.path}`;
|
||||
|
||||
try {
|
||||
await client.bucket(config.bucketName).file(key).delete();
|
||||
return {success: true, provider: "google-cloud-storage"};
|
||||
} catch (err: any) {
|
||||
return {success: false, provider: "google-cloud-storage", error: err.message};
|
||||
}
|
||||
}
|
||||
|
||||
export async function pingGoogleCloudStorage(config: GoogleCloudStorageConfig): Promise<StorageResult> {
|
||||
try {
|
||||
const client = await getGoogleCloudStorageClient(config);
|
||||
const bucket = client.bucket(config.bucketName);
|
||||
|
||||
const [exists] = await bucket.exists();
|
||||
if (!exists) return {
|
||||
success: false,
|
||||
provider: "google-cloud-storage",
|
||||
response: "Bucket does not exist"
|
||||
};
|
||||
|
||||
const key = `${BASE_DIR}ping.txt`;
|
||||
const file = bucket.file(key);
|
||||
await file.save(Buffer.from("ping"));
|
||||
await file.download();
|
||||
await file.delete();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
provider: "google-cloud-storage",
|
||||
response: "Google Cloud Storage OK"
|
||||
};
|
||||
} catch (err: any) {
|
||||
return {
|
||||
success: false,
|
||||
provider: "google-cloud-storage",
|
||||
response: err.message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function copyGoogleCloudStorage(
|
||||
config: GoogleCloudStorageConfig,
|
||||
input: {
|
||||
data: StorageCopyInput,
|
||||
},
|
||||
): Promise<StorageResult> {
|
||||
const client = await getGoogleCloudStorageClient(config);
|
||||
await ensureBucket(config);
|
||||
|
||||
const sourceKey = `${BASE_DIR}${input.data.from}`;
|
||||
const destinationKey = `${BASE_DIR}${input.data.to}`;
|
||||
|
||||
try {
|
||||
const bucket = client.bucket(config.bucketName);
|
||||
await bucket.file(sourceKey).copy(bucket.file(destinationKey));
|
||||
|
||||
return {
|
||||
success: true,
|
||||
provider: "google-cloud-storage",
|
||||
};
|
||||
} catch (err: any) {
|
||||
return {
|
||||
success: false,
|
||||
provider: "google-cloud-storage",
|
||||
error: err.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export type GoogleCloudStorageConfig = {
|
||||
projectId: string;
|
||||
bucketName: string;
|
||||
clientEmail: string;
|
||||
privateKey: string;
|
||||
apiEndpoint: string;
|
||||
};
|
||||
@@ -14,6 +14,13 @@ import {
|
||||
pingGoogleDrive,
|
||||
uploadGoogleDrive
|
||||
} from "@/features/channel/components/storages/google-drive";
|
||||
import {
|
||||
copyGoogleCloudStorage,
|
||||
deleteGoogleCloudStorage,
|
||||
getGoogleCloudStorage,
|
||||
pingGoogleCloudStorage,
|
||||
uploadGoogleCloudStorage
|
||||
} from "@/features/channel/components/storages/google-cloud-storage";
|
||||
|
||||
type ProviderHandler = {
|
||||
upload: (config: any, input: StorageInput & { action: 'upload' }) => Promise<StorageResult>;
|
||||
@@ -51,6 +58,13 @@ const handlers: Record<StorageProviderKind, ProviderHandler> = {
|
||||
delete: deleteBlob,
|
||||
ping: pingBlob,
|
||||
copy: copyBlob,
|
||||
},
|
||||
"google-cloud-storage": {
|
||||
upload: uploadGoogleCloudStorage,
|
||||
get: getGoogleCloudStorage,
|
||||
delete: deleteGoogleCloudStorage,
|
||||
ping: pingGoogleCloudStorage,
|
||||
copy: copyGoogleCloudStorage,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@ import {GoogleDriveChannelConfigSchema} from "@/features/channel/components/stor
|
||||
import {LocalChannelConfigSchema} from "@/features/channel/components/storages/local.schema";
|
||||
import {TeamsChannelConfigSchema} from "@/features/channel/components/notifications/teams.schema";
|
||||
import {BlobChannelConfigSchema} from "@/features/channel/components/storages/az-blob.schema";
|
||||
import {
|
||||
GoogleCloudStorageChannelConfigSchema
|
||||
} from "@/features/channel/components/storages/google-cloud-storage/google-cloud-storage.schema";
|
||||
|
||||
|
||||
|
||||
const BaseChannelFormSchema = z.object({
|
||||
@@ -79,6 +83,10 @@ export const StorageChannelFormSchema = z.discriminatedUnion("provider", [
|
||||
provider: z.literal("blob"),
|
||||
config: BlobChannelConfigSchema,
|
||||
}),
|
||||
BaseChannelFormSchema.extend({
|
||||
provider: z.literal("google-cloud-storage"),
|
||||
config: GoogleCloudStorageChannelConfigSchema,
|
||||
}),
|
||||
BaseChannelFormSchema.extend({
|
||||
provider: z.literal("local"),
|
||||
config: LocalChannelConfigSchema
|
||||
|
||||
@@ -4,6 +4,7 @@ export type StorageProviderKind =
|
||||
| 'local'
|
||||
| 's3'
|
||||
| 'google-drive'
|
||||
| 'google-cloud-storage'
|
||||
| 'blob'
|
||||
;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user