From 0c38cdabd950bb121898cde6a50020bd8fd1bdd2 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Wed, 1 Apr 2026 09:48:17 +0530 Subject: [PATCH 01/54] feat: add bigint column type support and update dependencies --- package.json | 2 +- pnpm-lock.yaml | 41 ++----- src/lib/helpers/types.ts | 1 + .../table-[table]/columns/+page.svelte | 2 +- .../table-[table]/columns/bigint.svelte | 115 ++++++++++++++++++ .../table-[table]/columns/store.ts | 12 ++ .../rows/columns/types/string.svelte | 4 + .../table-[table]/spreadsheet.svelte | 1 + 8 files changed, 146 insertions(+), 32 deletions(-) create mode 100644 src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte diff --git a/package.json b/package.json index 588c69793..00d7fcb00 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@d223f36", + "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@863d3e9", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", "@appwrite.io/pink-legacy": "^1.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 12bb24e68..2c7e9ddf2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^1.1.24 version: 1.1.24(svelte@5.55.0)(zod@3.25.76) '@appwrite.io/console': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/console@83fd10c - version: https://pkg.vc/-/@appwrite/@appwrite.io/console@83fd10c + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/console@863d3e9 + version: https://pkg.vc/-/@appwrite/@appwrite.io/console@863d3e9 '@appwrite.io/pink-icons': specifier: 0.25.0 version: 0.25.0 @@ -75,8 +75,8 @@ importers: specifier: ^5.1.7 version: 5.1.7 nanotar: - specifier: ^0.1.1 - version: 0.1.1 + specifier: ^0.3.0 + version: 0.3.0 pretty-bytes: specifier: ^6.1.1 version: 6.1.1 @@ -281,9 +281,9 @@ packages: '@analytics/type-utils@0.6.4': resolution: {integrity: sha512-Ou1gQxFakOWLcPnbFVsrPb8g1wLLUZYYJXDPjHkG07+5mustGs5yqACx42UAu4A6NszNN6Z5gGxhyH45zPWRxw==} - '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@83fd10c': - resolution: {integrity: sha512-Mlq0dfJrcqUNFt+QUmrieHrJSScOUniigt1PL5Xum7QEDgT8Z/mMhG/xUcVfZqXtlF5gS4Sq7n72EB6P/3+kmQ==, tarball: https://pkg.vc/-/@appwrite/@appwrite.io/console@83fd10c} - version: 7.0.0 + '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@863d3e9': + resolution: {integrity: sha512-BJ9wrAI8frqAp9fN89RtJGn0r+RplWJ669s8AoW4JstYsnSe+ewhjBlLZWpFmIMfepz5agCE6G+4g7LXOfqdYg==, tarball: https://pkg.vc/-/@appwrite/@appwrite.io/console@863d3e9} + version: 8.0.0 '@appwrite.io/pink-icons-svelte@2.0.0-RC.1': resolution: {integrity: sha512-iLFlV55hj8mGuAbmxJGenxN5RaZMmVT4GJb9dv/MP1xBAtYibFq7JvBcxm18qV2KU8c31Rntf+Ub4GL7HwqTYg==} @@ -935,42 +935,36 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.6': resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.6': resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.6': resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.6': resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.6': resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [musl] '@parcel/watcher-win32-arm64@2.5.6': resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} @@ -1045,79 +1039,66 @@ packages: resolution: {integrity: sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.60.0': resolution: {integrity: sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.60.0': resolution: {integrity: sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.60.0': resolution: {integrity: sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.60.0': resolution: {integrity: sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.60.0': resolution: {integrity: sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==} cpu: [loong64] os: [linux] - libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.60.0': resolution: {integrity: sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.60.0': resolution: {integrity: sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==} cpu: [ppc64] os: [linux] - libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.60.0': resolution: {integrity: sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.60.0': resolution: {integrity: sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==} cpu: [riscv64] os: [linux] - libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.60.0': resolution: {integrity: sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.60.0': resolution: {integrity: sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.60.0': resolution: {integrity: sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-openbsd-x64@4.60.0': resolution: {integrity: sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==} @@ -2675,8 +2656,8 @@ packages: engines: {node: ^18 || >=20} hasBin: true - nanotar@0.1.1: - resolution: {integrity: sha512-AiJsGsSF3O0havL1BydvI4+wR76sKT+okKRwWIaK96cZUnXqH0uNBOsHlbwZq3+m2BR1VKqHDVudl3gO4mYjpQ==} + nanotar@0.3.0: + resolution: {integrity: sha512-Kv2JYYiCzt16Kt5QwAc9BFG89xfPNBx+oQL4GQXD9nLqPkZBiNaqaCWtwnbk/q7UVsTYevvM1b0UF8zmEI4pCg==} natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -3631,7 +3612,7 @@ snapshots: '@analytics/type-utils@0.6.4': {} - '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@83fd10c': + '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@863d3e9': dependencies: json-bigint: 1.0.0 @@ -6160,7 +6141,7 @@ snapshots: nanoid@5.1.7: {} - nanotar@0.1.1: {} + nanotar@0.3.0: {} natural-compare@1.4.0: {} diff --git a/src/lib/helpers/types.ts b/src/lib/helpers/types.ts index 07dcd7c85..544b1ca39 100644 --- a/src/lib/helpers/types.ts +++ b/src/lib/helpers/types.ts @@ -34,6 +34,7 @@ const columnTypes = [ 'text', 'mediumtext', 'longtext', + 'bigint', 'integer', 'double', 'boolean', diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte index 5b4075bc8..743e32016 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte @@ -198,7 +198,7 @@ ) { const stringColumn = column as Models.ColumnString; return { display: `Size: ${stringColumn.size}` }; - } else if (column.type === 'integer' || column.type === 'double') { + } else if (column.type === 'bigint' || column.type === 'integer' || column.type === 'double') { const numbersColumn = column as Models.ColumnInteger | Models.ColumnFloat; const { min, max } = numbersColumn; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte new file mode 100644 index 000000000..c6b26dc61 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte @@ -0,0 +1,115 @@ + + + + + + + + + + + + + diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/store.ts index dc8ee80f8..f64866143 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/store.ts @@ -4,6 +4,7 @@ import Boolean, { submitBoolean, updateBoolean } from './boolean.svelte'; import Email, { submitEmail, updateEmail } from './email.svelte'; import Enum, { submitEnum, updateEnum } from './enum.svelte'; import Float, { submitFloat, updateFloat } from './float.svelte'; +import BigInt, { submitBigInt, updateBigInt } from './bigint.svelte'; import Integer, { submitInteger, updateInteger } from './integer.svelte'; import Ip, { submitIp, updateIp } from './ip.svelte'; import String, { submitString, updateString } from './string.svelte'; @@ -41,6 +42,7 @@ export type Option = { | 'Mediumtext' | 'Longtext' | 'Varchar' + | 'BigInt' | 'Integer' | 'Float' | 'Boolean' @@ -62,6 +64,7 @@ export type Option = { | 'mediumtext' | 'longtext' | 'varchar' + | 'bigint' | 'integer' | 'double' | 'boolean' @@ -125,6 +128,15 @@ export const columnOptions: Option[] = [ update: updateVarchar, icon: IconText }, + { + name: 'BigInt', + sentenceName: 'bigint', + component: BigInt, + type: 'bigint', + create: submitBigInt, + update: updateBigInt, + icon: IconHashtag + }, { name: 'Integer', sentenceName: 'integer', diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte index fbfa549ae..ceaee2a96 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte @@ -24,6 +24,7 @@ | Models.ColumnText | Models.ColumnMediumtext | Models.ColumnLongtext + | Models.ColumnBigint | Models.ColumnInteger | Models.ColumnFloat | Models.ColumnBoolean @@ -51,6 +52,7 @@ if (!trimmed) return null; switch (column.type) { + case 'bigint': case 'integer': { const int = parseInt(trimmed, 10); return isNaN(int) ? null : int; @@ -122,6 +124,7 @@ const getPlaceholder = () => { if (!array) { switch (column.type) { + case 'bigint': case 'integer': return 'Enter integer'; case 'double': @@ -134,6 +137,7 @@ } } else { switch (column.type) { + case 'bigint': case 'integer': return 'Enter integers separated by commas'; case 'double': diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte index e5c5c76d3..7fee9b9fb 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte @@ -332,6 +332,7 @@ switch (type) { case 'string': return IconText; + case 'bigint': case 'double': case 'integer': return IconHashtag; From 272f2e9332305b7b7a66fd613264b527d35847eb Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Wed, 1 Apr 2026 11:08:06 +0530 Subject: [PATCH 02/54] feat: enhance bigint column support and improve input handling - Updated bigint column type handling in the database table columns. - Refactored input components to use InputText for bigint values with validation. - Improved parsing and error handling for bigint inputs in string representation. - Adjusted type definitions to include bigint in various contexts. --- .../table-[table]/columns/+page.svelte | 11 +- .../table-[table]/columns/bigint.svelte | 152 +++++++++++++----- .../rows/columns/types/string.svelte | 35 +++- 3 files changed, 149 insertions(+), 49 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte index 743e32016..feb0a4dff 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte @@ -198,8 +198,15 @@ ) { const stringColumn = column as Models.ColumnString; return { display: `Size: ${stringColumn.size}` }; - } else if (column.type === 'bigint' || column.type === 'integer' || column.type === 'double') { - const numbersColumn = column as Models.ColumnInteger | Models.ColumnFloat; + } else if ( + column.type === 'bigint' || + column.type === 'integer' || + column.type === 'double' + ) { + const numbersColumn = column as + | Models.ColumnBigint + | Models.ColumnInteger + | Models.ColumnFloat; const { min, max } = numbersColumn; const isMinBigInt = typeof min === 'bigint'; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte index c6b26dc61..885cd5633 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte @@ -1,4 +1,4 @@ - - - - diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte index ceaee2a96..80629f6d9 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte @@ -15,7 +15,16 @@ }: { id: string; label: string; - value: string | number | boolean | string[] | number[] | boolean[] | null; + value: + | string + | number + | bigint + | boolean + | string[] + | number[] + | bigint[] + | boolean[] + | null; array?: boolean; limited?: boolean; column: @@ -47,12 +56,26 @@ let stringValue = $state(''); - function parseValue(str: string | null): number | boolean | string | null { + function safeStringify(v: unknown): string { + // Note: `JSON.stringify` throws on `bigint` values unless a replacer is used. + return JSON.stringify(v, (_key, value) => + typeof value === 'bigint' ? value.toString() : value + ); + } + + function parseValue(str: string | null): number | bigint | boolean | string | null { const trimmed = str?.trim() ?? null; if (!trimmed) return null; switch (column.type) { - case 'bigint': + case 'bigint': { + try { + return BigInt(trimmed); + } catch { + return null; + } + } + case 'integer': { const int = parseInt(trimmed, 10); return isNaN(int) ? null : int; @@ -97,8 +120,8 @@ .split(',') .map((item) => parseValue(item)) .filter((item) => item !== null); - if (JSON.stringify(newArray) !== JSON.stringify(value)) { - value = newArray as string[] | number[] | boolean[]; + if (safeStringify(newArray) !== safeStringify(value)) { + value = newArray as string[] | number[] | bigint[] | boolean[]; } } else { let parsedValue = parseValue(stringValue); @@ -115,7 +138,7 @@ } } - if (JSON.stringify(parsedValue) !== JSON.stringify(value)) { + if (safeStringify(parsedValue) !== safeStringify(value)) { value = parsedValue; } } From 528c6575fa112fb3af57881e8168dc95568c3bb4 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Wed, 1 Apr 2026 11:34:21 +0530 Subject: [PATCH 03/54] feat: extend bigint support in database table components - Added bigint type to the Columns type definition. - Updated bigint input handling in the bigint.svelte component, replacing InputText with InputNumber for better user experience. - Enhanced data binding and validation for bigint values, including min, max, and default settings. - Adjusted column value handling in various components to accommodate bigint type. --- .../table-[table]/columns/bigint.svelte | 134 +++++------------- .../table-[table]/rows/columns/column.svelte | 4 +- .../rows/columns/types/string.svelte | 35 +---- .../table-[table]/store.ts | 1 + 4 files changed, 48 insertions(+), 126 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte index 885cd5633..2fef4ad44 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte @@ -42,7 +42,8 @@ - - - diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte index 9be533a7c..72960b7ce 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte @@ -16,7 +16,7 @@ export let label: string; export let array: boolean | undefined = undefined; export let optionalText: string | undefined = undefined; - export let value: string | number | boolean | null | string[]; + export let value: string | number | bigint | boolean | null | string[] | number[] | bigint[] | boolean[]; export let editing = false; export let limited = false; export let column: @@ -24,6 +24,7 @@ | Models.ColumnEmail | Models.ColumnEnum | Models.ColumnFloat + | Models.ColumnBigint | Models.ColumnInteger | Models.ColumnIp | Models.ColumnString @@ -43,6 +44,7 @@ text: String, mediumtext: String, longtext: String, + bigint: Integer, integer: Integer, double: Integer, boolean: Boolean, diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte index 80629f6d9..ceaee2a96 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte @@ -15,16 +15,7 @@ }: { id: string; label: string; - value: - | string - | number - | bigint - | boolean - | string[] - | number[] - | bigint[] - | boolean[] - | null; + value: string | number | boolean | string[] | number[] | boolean[] | null; array?: boolean; limited?: boolean; column: @@ -56,26 +47,12 @@ let stringValue = $state(''); - function safeStringify(v: unknown): string { - // Note: `JSON.stringify` throws on `bigint` values unless a replacer is used. - return JSON.stringify(v, (_key, value) => - typeof value === 'bigint' ? value.toString() : value - ); - } - - function parseValue(str: string | null): number | bigint | boolean | string | null { + function parseValue(str: string | null): number | boolean | string | null { const trimmed = str?.trim() ?? null; if (!trimmed) return null; switch (column.type) { - case 'bigint': { - try { - return BigInt(trimmed); - } catch { - return null; - } - } - + case 'bigint': case 'integer': { const int = parseInt(trimmed, 10); return isNaN(int) ? null : int; @@ -120,8 +97,8 @@ .split(',') .map((item) => parseValue(item)) .filter((item) => item !== null); - if (safeStringify(newArray) !== safeStringify(value)) { - value = newArray as string[] | number[] | bigint[] | boolean[]; + if (JSON.stringify(newArray) !== JSON.stringify(value)) { + value = newArray as string[] | number[] | boolean[]; } } else { let parsedValue = parseValue(stringValue); @@ -138,7 +115,7 @@ } } - if (safeStringify(parsedValue) !== safeStringify(value)) { + if (JSON.stringify(parsedValue) !== JSON.stringify(value)) { value = parsedValue; } } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts index 9d701180e..1307bab88 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts @@ -11,6 +11,7 @@ export type Columns = | Models.ColumnEmail | Models.ColumnEnum | Models.ColumnFloat + | Models.ColumnBigint | Models.ColumnInteger | Models.ColumnIp | Models.ColumnString From 501fdbbe27572ae22b50189d733c93ab9c97359e Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Wed, 1 Apr 2026 17:44:52 +0530 Subject: [PATCH 04/54] updated bun lock --- bun.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bun.lock b/bun.lock index dd34a80e7..7459e1433 100644 --- a/bun.lock +++ b/bun.lock @@ -6,7 +6,7 @@ "name": "@appwrite/console", "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@d223f36", + "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@863d3e9", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", "@appwrite.io/pink-legacy": "^1.0.3", @@ -113,15 +113,15 @@ "@analytics/type-utils": ["@analytics/type-utils@0.6.4", "", {}, "sha512-Ou1gQxFakOWLcPnbFVsrPb8g1wLLUZYYJXDPjHkG07+5mustGs5yqACx42UAu4A6NszNN6Z5gGxhyH45zPWRxw=="], - "@appwrite.io/console": ["@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@d223f36", { "dependencies": { "json-bigint": "1.0.0" } }], + "@appwrite.io/console": ["@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@863d3e9", { "dependencies": { "json-bigint": "1.0.0" } }, "sha512-BJ9wrAI8frqAp9fN89RtJGn0r+RplWJ669s8AoW4JstYsnSe+ewhjBlLZWpFmIMfepz5agCE6G+4g7LXOfqdYg=="], "@appwrite.io/pink-icons": ["@appwrite.io/pink-icons@0.25.0", "", {}, "sha512-0O3i2oEuh5mWvjO80i+X6rbzrWLJ1m5wmv2/M3a1p2PyBJsFxN8xQMTEmTn3Wl/D26SsM7SpzbdW6gmfgoVU9Q=="], - "@appwrite.io/pink-icons-svelte": ["@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", { "peerDependencies": { "svelte": "^4.0.0" } }], + "@appwrite.io/pink-icons-svelte": ["@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", { "peerDependencies": { "svelte": "^4.0.0" } }, "sha512-2HYl/CC2OlfZIR7LzbLXuSPBn0iNkjbnxpaeGCkZ7UNZ/hFeSeeWjDJqTBMdZ8+X95uuZqHx62XPTiE/svuSXQ=="], "@appwrite.io/pink-legacy": ["@appwrite.io/pink-legacy@1.0.3", "", { "dependencies": { "@appwrite.io/pink-icons": "1.0.0", "the-new-css-reset": "^1.11.2" } }, "sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ=="], - "@appwrite.io/pink-svelte": ["@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bfe7ce3", { "dependencies": { "@appwrite.io/pink-icons-svelte": "2.0.0-RC.1", "@floating-ui/dom": "^1.6.13", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.6", "@tanstack/svelte-virtual": "^3.13.10", "ansicolor": "^2.0.3", "d3": "^7.9.0", "fuse.js": "^7.1.0", "pretty-bytes": "^6.1.1", "shiki": "^1.18.0", "svelte-motion": "^0.12.2", "svelte-sonner": "^0.3.28" }, "peerDependencies": { "svelte": "^4.0.0" } }], + "@appwrite.io/pink-svelte": ["@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bfe7ce3", { "dependencies": { "@appwrite.io/pink-icons-svelte": "2.0.0-RC.1", "@floating-ui/dom": "^1.6.13", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.6", "@tanstack/svelte-virtual": "^3.13.10", "ansicolor": "^2.0.3", "d3": "^7.9.0", "fuse.js": "^7.1.0", "pretty-bytes": "^6.1.1", "shiki": "^1.18.0", "svelte-motion": "^0.12.2", "svelte-sonner": "^0.3.28" }, "peerDependencies": { "svelte": "^4.0.0" } }, "sha512-kOC6T1uhmggl02Wmu++WUBpVh1SqzwlRDpR4xw79Sl8Cy1RJju55IkeVl6doKcNYQyPl6kJItgxFwF1MhkB1DQ=="], "@asamuzakjp/css-color": ["@asamuzakjp/css-color@3.2.0", "", { "dependencies": { "@csstools/css-calc": "^2.1.3", "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", "lru-cache": "^10.4.3" } }, "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw=="], From a6eb30db476d957a7e4737a5eb40676d93e998ac Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Wed, 1 Apr 2026 17:58:58 +0530 Subject: [PATCH 05/54] linting --- .../table-[table]/rows/columns/column.svelte | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte index 72960b7ce..37947fefe 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte @@ -16,7 +16,16 @@ export let label: string; export let array: boolean | undefined = undefined; export let optionalText: string | undefined = undefined; - export let value: string | number | bigint | boolean | null | string[] | number[] | bigint[] | boolean[]; + export let value: + | string + | number + | bigint + | boolean + | null + | string[] + | number[] + | bigint[] + | boolean[]; export let editing = false; export let limited = false; export let column: From f484ce860236c699f6b4e1a8bbe51f6f2d6fded7 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Thu, 9 Apr 2026 14:50:15 +0530 Subject: [PATCH 06/54] feat: implement bigint support across various components and enhance payload handling --- src/lib/helpers/faker.ts | 4 ++ .../table-[table]/+layout.svelte | 6 +-- .../table-[table]/columns/bigint.svelte | 10 ++++- .../table-[table]/rows/create.svelte | 6 +-- .../table-[table]/rows/edit.svelte | 7 +++- .../table-[table]/rows/editRelated.svelte | 19 +++++++-- .../table-[table]/rows/store.ts | 41 +++++++++++++++++++ .../table-[table]/spreadsheet.svelte | 5 ++- 8 files changed, 84 insertions(+), 14 deletions(-) diff --git a/src/lib/helpers/faker.ts b/src/lib/helpers/faker.ts index cd937ac80..f05b11dc6 100644 --- a/src/lib/helpers/faker.ts +++ b/src/lib/helpers/faker.ts @@ -243,6 +243,10 @@ function generateSingleValue(field: Field): string | number | boolean | NestedNu return faker.number.int({ min, max }); } + case 'bigint': { + return faker.number.bigInt().toString(); + } + case 'double': { const floatAttr = field as Models.ColumnFloat; const min = isWithinSafeRange(floatAttr.min) ? floatAttr.min : 0; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte index cd99973a9..585ef8634 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte @@ -64,7 +64,7 @@ import { addNotification } from '$lib/stores/notifications'; import { hash } from '$lib/helpers/string'; import { preferences } from '$lib/stores/preferences'; - import { buildRowUrl, isRelationship } from './rows/store'; + import { buildRowUrl, isRelationship, buildPayload } from './rows/store'; import { chunks } from '$lib/helpers/array'; import { Submit, trackEvent } from '$lib/actions/analytics'; @@ -346,7 +346,7 @@ databaseId: page.params.database, tableId: page.params.table, rowId: row.$id, - data: row + data: buildPayload(columns, row as Record) }) ) ); @@ -358,7 +358,7 @@ await tablesSDK.createRows({ databaseId: page.params.database, tableId: page.params.table, - rows + rows: rows.map((row) => buildPayload(columns, row as Record)) }); } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte index 2fef4ad44..f59b94722 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte @@ -2,6 +2,12 @@ import { page } from '$app/state'; import { sdk } from '$lib/stores/sdk'; import type { Models } from '@appwrite.io/console'; + + function normalizeBigInt(value) { + if (value === undefined) return undefined; + if (value === null) return null; + return BigInt(value); + } export async function submitBigInt( databaseId: string, @@ -16,7 +22,7 @@ required: data.required, min: data.min, max: data.max, - xdefault: data.default, + xdefault: normalizeBigInt(data.default), array: data.array }); } @@ -32,7 +38,7 @@ tableId, key: originalKey, required: data.required, - xdefault: data.default, + xdefault: normalizeBigInt(data.default), min: data.min, max: data.max, newKey: data.key !== originalKey ? data.key : undefined diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/create.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/create.svelte index 62eb13dd6..40ed21595 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/create.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/create.svelte @@ -14,7 +14,7 @@ import { invalidate } from '$app/navigation'; import { Dependencies } from '$lib/constants'; import { tick } from 'svelte'; - import { isRelationship, isRelationshipToMany } from './store'; + import { isRelationship, isRelationshipToMany, buildPayload } from './store'; import { hash } from '$lib/helpers/string'; type CreateRow = { @@ -70,7 +70,7 @@ function prepareRowPayload(createRowObject: CreateRow): object { const { row, columns } = createRowObject; - const payload = structuredClone(row); + const payload = structuredClone(row) as Record; for (const column of columns) { if (isRelationship(column) && !isRelationshipToMany(column)) { @@ -87,7 +87,7 @@ } } - return payload; + return buildPayload(columns, payload); } async function create(): Promise { diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/edit.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/edit.svelte index 418b8a6c1..a440ba96f 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/edit.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/edit.svelte @@ -14,7 +14,8 @@ buildWildcardColumnsQuery, isRelationship, isRelationshipToMany, - isSpatialType + isSpatialType, + buildPayload } from './store'; import { Layout, Skeleton } from '@appwrite.io/pink-svelte'; import { deepClone } from '$lib/helpers/object'; @@ -142,11 +143,13 @@ if (!row || !work) return; try { + const payload = buildPayload(table.fields, $work as Record); + await sdk.forProject(page.params.region, page.params.project).tablesDB.updateRow({ databaseId: table.databaseId, tableId: table.$id, rowId: row.$id, - data: $work, + data: payload, permissions: $work.$permissions }); diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/editRelated.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/editRelated.svelte index 1b3c83eb9..f3819fa06 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/editRelated.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/editRelated.svelte @@ -10,7 +10,12 @@ import { invalidate } from '$app/navigation'; import { type Columns, PROHIBITED_ROW_KEYS } from '../store'; import ColumnItem from './columns/columnItem.svelte'; - import { buildWildcardColumnsQuery, isRelationship, isRelationshipToMany } from './store'; + import { + buildWildcardColumnsQuery, + isRelationship, + isRelationshipToMany, + buildPayload + } from './store'; import { Accordion, Layout, Skeleton } from '@appwrite.io/pink-svelte'; import { deepClone } from '$lib/helpers/object'; import { preferences } from '$lib/stores/preferences'; @@ -258,11 +263,15 @@ const work = workData.get(rowId); const workValue = get(work); + const payload = buildPayload( + relatedTable.fields, + workValue as Record + ); await sdk.forProject(page.params.region, page.params.project).tablesDB.updateRow({ databaseId, tableId: relatedTable.$id, rowId: rowId, - data: workValue, + data: payload, permissions: workValue.$permissions }); @@ -276,13 +285,17 @@ if (!work) return; const workValue = get(work); + const payload = buildPayload( + relatedTable.fields, + workValue as Record + ); return sdk .forProject(page.params.region, page.params.project) .tablesDB.updateRow({ databaseId, tableId: relatedTable.$id, rowId: row.$id, - data: workValue, + data: payload, permissions: workValue.$permissions }); }); diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts index 1a65e7873..94017945d 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts @@ -52,6 +52,47 @@ export function isSpatialType( return spatialTypes.includes(field.type.toLowerCase()); } +function castBigIntValue(value: unknown): unknown { + if (value === null || value === undefined || value === '') { + return value; + } + + if (typeof value === 'bigint') { + return value; + } + + try { + console.log({ value }); + return BigInt(value as string | number | boolean); + } catch { + return value; + } +} + +export function buildPayload( + fields: Field[] | undefined, + row: Record +): Record { + const payload = structuredClone(row); + + for (const field of fields ?? []) { + if (field.type !== 'bigint') { + continue; + } + + const value = payload[field.key]; + + if (field.array && Array.isArray(value)) { + payload[field.key] = value.map((item) => castBigIntValue(item)); + continue; + } + + payload[field.key] = castBigIntValue(value); + } + + return payload; +} + /** * Returns select queries for all main and related fields in an `Entity`. */ diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte index 7fee9b9fb..6b9992c16 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte @@ -17,6 +17,7 @@ buildWildcardColumnsQuery, isRelationship, isRelationshipToMany, + buildPayload, isSpatialType, isTextType } from './rows/store'; @@ -645,11 +646,13 @@ async function updateRowContents(row: Models.Row) { try { + const payload = buildPayload(table.fields, row as Record); + await sdk.forProject(page.params.region, page.params.project).tablesDB.updateRow({ databaseId, tableId: table.$id, rowId: row.$id, - data: row, + data: payload, permissions: row.$permissions }); From d5689d4693529f47eda3a39cd4721fd534e0fab8 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Thu, 9 Apr 2026 14:50:34 +0530 Subject: [PATCH 07/54] linting --- .../database-[database]/table-[table]/columns/bigint.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte index f59b94722..57d60dc5e 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte @@ -2,7 +2,7 @@ import { page } from '$app/state'; import { sdk } from '$lib/stores/sdk'; import type { Models } from '@appwrite.io/console'; - + function normalizeBigInt(value) { if (value === undefined) return undefined; if (value === null) return null; From 9374df048edf55a80e77825343b531f3600a1e76 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Thu, 9 Apr 2026 14:56:32 +0530 Subject: [PATCH 08/54] updated --- bun.lock | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bun.lock b/bun.lock index 143df2bed..eff43b53b 100644 --- a/bun.lock +++ b/bun.lock @@ -1,11 +1,12 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "@appwrite/console", "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@67539a6", + "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@ef672a3", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", "@appwrite.io/pink-legacy": "^1.0.3", @@ -24,7 +25,6 @@ "deep-equal": "^2.2.3", "echarts": "^5.6.0", "flatted": "^3.4.2", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@67539a6", "ignore": "^6.0.2", "nanoid": "^5.1.7", "nanotar": "^0.3.0", @@ -113,7 +113,7 @@ "@analytics/type-utils": ["@analytics/type-utils@0.6.4", "", {}, "sha512-Ou1gQxFakOWLcPnbFVsrPb8g1wLLUZYYJXDPjHkG07+5mustGs5yqACx42UAu4A6NszNN6Z5gGxhyH45zPWRxw=="], - "@appwrite.io/console": ["@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@67539a6", { "dependencies": { "json-bigint": "1.0.0" } }], + "@appwrite.io/console": ["@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@ef672a3", { "dependencies": { "json-bigint": "1.0.0" } }, "sha512-p56fUkb4Vj+MeTJAiVayKr6/qH6kYpsDbqNqb8YiVhu9x+aInxH8Vo44iDiYg/KYlTAgwFSOXLrq2ZEPaVrXIw=="], "@appwrite.io/pink-icons": ["@appwrite.io/pink-icons@0.25.0", "", {}, "sha512-0O3i2oEuh5mWvjO80i+X6rbzrWLJ1m5wmv2/M3a1p2PyBJsFxN8xQMTEmTn3Wl/D26SsM7SpzbdW6gmfgoVU9Q=="], @@ -121,7 +121,7 @@ "@appwrite.io/pink-legacy": ["@appwrite.io/pink-legacy@1.0.3", "", { "dependencies": { "@appwrite.io/pink-icons": "1.0.0", "the-new-css-reset": "^1.11.2" } }, "sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ=="], - "@appwrite.io/pink-svelte": ["@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@8dcaa17", { "dependencies": { "@appwrite.io/pink-icons-svelte": "2.0.0-RC.1", "@floating-ui/dom": "^1.6.13", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.6", "@tanstack/svelte-virtual": "^3.13.10", "ansicolor": "^2.0.3", "d3": "^7.9.0", "fuse.js": "^7.1.0", "pretty-bytes": "^6.1.1", "shiki": "^1.18.0", "svelte-motion": "^0.12.2", "svelte-sonner": "^0.3.28" }, "peerDependencies": { "svelte": "^4.0.0" } }], + "@appwrite.io/pink-svelte": ["@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@8dcaa17", { "dependencies": { "@appwrite.io/pink-icons-svelte": "2.0.0-RC.1", "@floating-ui/dom": "^1.6.13", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.6", "@tanstack/svelte-virtual": "^3.13.10", "ansicolor": "^2.0.3", "d3": "^7.9.0", "fuse.js": "^7.1.0", "pretty-bytes": "^6.1.1", "shiki": "^1.18.0", "svelte-motion": "^0.12.2", "svelte-sonner": "^0.3.28" }, "peerDependencies": { "svelte": "^4.0.0" } }, "sha512-rw3zXN7/cUciCnhj0FR8M0H5Db+LYYMaKtPxvOAIMxNTBmStzU8kTw6grqIvdtFu9vybIsjKtIwm9QLHpNDBjA=="], "@asamuzakjp/css-color": ["@asamuzakjp/css-color@3.2.0", "", { "dependencies": { "@csstools/css-calc": "^2.1.3", "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", "lru-cache": "^10.4.3" } }, "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw=="], diff --git a/package.json b/package.json index 74c0c7948..c33ff5ef6 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@67539a6", + "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@ef672a3", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", "@appwrite.io/pink-legacy": "^1.0.3", From 2d0defe5f9299fc9fef23797f359f77e035f1715 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Thu, 9 Apr 2026 17:14:18 +0530 Subject: [PATCH 09/54] updated the type --- .../table-[table]/+layout.svelte | 4 +-- .../table-[table]/rows/edit.svelte | 2 +- .../table-[table]/rows/editRelated.svelte | 10 ++----- .../table-[table]/rows/store.ts | 29 +++++++++---------- .../table-[table]/spreadsheet.svelte | 2 +- 5 files changed, 19 insertions(+), 28 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte index 9492c22cd..16a088f97 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte @@ -346,7 +346,7 @@ databaseId: page.params.database, tableId: page.params.table, rowId: row.$id, - data: buildPayload(columns, row as Record) + data: buildPayload(columns, row) }) ) ); @@ -358,7 +358,7 @@ await tablesSDK.createRows({ databaseId: page.params.database, tableId: page.params.table, - rows: rows.map((row) => buildPayload(columns, row as Record)) + rows: rows.map((row) => buildPayload(columns, row)) }); } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/edit.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/edit.svelte index a440ba96f..58a723129 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/edit.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/edit.svelte @@ -143,7 +143,7 @@ if (!row || !work) return; try { - const payload = buildPayload(table.fields, $work as Record); + const payload = buildPayload(table.fields, $work); await sdk.forProject(page.params.region, page.params.project).tablesDB.updateRow({ databaseId: table.databaseId, diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/editRelated.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/editRelated.svelte index af0afde35..67a0ce0b0 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/editRelated.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/editRelated.svelte @@ -258,10 +258,7 @@ const work = workData.get(rowId); const workValue = get(work); - const payload = buildPayload( - relatedTable.fields, - workValue as Record - ); + const payload = buildPayload(relatedTable.fields, workValue); await sdk.forProject(page.params.region, page.params.project).tablesDB.updateRow({ databaseId, tableId: relatedTable.$id, @@ -280,10 +277,7 @@ if (!work) return; const workValue = get(work); - const payload = buildPayload( - relatedTable.fields, - workValue as Record - ); + const payload = buildPayload(relatedTable.fields, workValue); return sdk .forProject(page.params.region, page.params.project) .tablesDB.updateRow({ diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts index 94017945d..b38649c3a 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts @@ -4,6 +4,12 @@ import type { Attributes, Columns } from '../store'; import { type Models, Query } from '@appwrite.io/console'; import type { Entity, Field } from '$database/(entity)'; +type RowPrimitive = string | number | bigint | boolean | null | undefined; +interface RowObject { + [key: string]: RowValue; +} +type RowValue = RowPrimitive | RowValue[] | RowObject; + export function isRelationshipToMany(field: Field) { if (!field) return false; if (!isRelationship(field)) return false; @@ -52,28 +58,19 @@ export function isSpatialType( return spatialTypes.includes(field.type.toLowerCase()); } -function castBigIntValue(value: unknown): unknown { +function castBigIntValue(value: RowValue): RowValue { if (value === null || value === undefined || value === '') { return value; } - if (typeof value === 'bigint') { - return value; - } - - try { - console.log({ value }); - return BigInt(value as string | number | boolean); - } catch { - return value; - } + return String(value); } -export function buildPayload( +export function buildPayload>( fields: Field[] | undefined, - row: Record -): Record { - const payload = structuredClone(row); + row: T +): T { + const payload = structuredClone(row) as Record; for (const field of fields ?? []) { if (field.type !== 'bigint') { @@ -90,7 +87,7 @@ export function buildPayload( payload[field.key] = castBigIntValue(value); } - return payload; + return payload as T; } /** diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte index 6b9992c16..36eae918f 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte @@ -646,7 +646,7 @@ async function updateRowContents(row: Models.Row) { try { - const payload = buildPayload(table.fields, row as Record); + const payload = buildPayload(table.fields, row); await sdk.forProject(page.params.region, page.params.project).tablesDB.updateRow({ databaseId, From ccef621c94012694bd0f2fe6055dc9c4f0235d76 Mon Sep 17 00:00:00 2001 From: harsh mahajan Date: Wed, 22 Apr 2026 12:44:20 +0530 Subject: [PATCH 10/54] feat:add SSR start command support for sites --- .../sites/create-site/configuration.svelte | 34 +++++++++++-- .../sites/create-site/deploy/+page.svelte | 11 +++- .../sites/create-site/finish/+page.svelte | 1 + .../sites/create-site/manual/+page.svelte | 9 +++- .../repository-[repository]/+page.svelte | 12 ++++- .../site-[site]/deployments/+page.svelte | 1 + .../createGitDeploymentModal.svelte | 1 + .../domains/add-domain/+page.svelte | 1 + .../settings/disconnectRepo.svelte | 1 + .../settings/updateBuildSettings.svelte | 50 ++++++++++++++++--- .../site-[site]/settings/updateLogging.svelte | 1 + .../site-[site]/settings/updateName.svelte | 1 + .../settings/updateRepository.svelte | 2 + .../settings/updateResourceLimits.svelte | 1 + .../settings/updateRuntimeSettings.svelte | 1 + .../site-[site]/settings/updateTimeout.svelte | 1 + src/routes/(public)/sites/deploy/+page.svelte | 2 + 17 files changed, 114 insertions(+), 16 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/sites/create-site/configuration.svelte b/src/routes/(console)/project-[region]-[project]/sites/create-site/configuration.svelte index 8b1a9ad3f..4b9d3a791 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/create-site/configuration.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/create-site/configuration.svelte @@ -6,30 +6,38 @@ import { getFrameworkIcon } from '$lib/stores/sites'; import { EnvironmentVariables } from '$lib/components/variables'; + type FrameworkAdapterWithStartCommand = Models.FrameworkAdapter & { + startCommand?: string; + }; + export let frameworks: Models.Framework[]; export let selectedFramework: Models.Framework; $: frameworkData = frameworks.find((framework) => framework.key === selectedFramework?.key); - $: adapterData = - frameworkData?.adapters.find((adapter) => adapter.key === 'ssr') ?? - frameworkData?.adapters.find((adapter) => adapter.key === 'static'); + $: adapterData = (frameworkData?.adapters.find((adapter) => adapter.key === 'ssr') ?? + frameworkData?.adapters.find( + (adapter) => adapter.key === 'static' + )) as FrameworkAdapterWithStartCommand; export let variables: Partial[] = []; export let isLoading = false; export let installCommand = ''; export let buildCommand = ''; + export let startCommand = ''; export let outputDirectory = ''; let frameworkId = selectedFramework.key; - $: if (!installCommand || !buildCommand || !outputDirectory) { + $: if (!installCommand || !buildCommand || !startCommand || !outputDirectory) { installCommand ||= adapterData?.installCommand; buildCommand ||= adapterData?.buildCommand; + startCommand ||= adapterData?.startCommand; outputDirectory ||= adapterData?.outputDirectory; } $: if (frameworkData) { installCommand = adapterData?.installCommand; buildCommand = adapterData?.buildCommand; + startCommand = adapterData?.startCommand; outputDirectory = adapterData?.outputDirectory; } @@ -84,6 +92,24 @@ Reset + {#if adapterData?.key === 'ssr'} + + + + + {/if} + f.key === 'other') ?? data.frameworks.frameworks?.[0]; - let adapter = framework?.adapters[0]; + let adapter = framework?.adapters[0] as FrameworkAdapterWithStartCommand; let installCommand = adapter?.installCommand; let buildCommand = adapter?.buildCommand; + let startCommand = adapter?.startCommand; let outputDirectory = adapter?.outputDirectory; let variables: Partial[] = []; let files: FileList; @@ -73,6 +78,7 @@ buildRuntime, installCommand: installCommand || undefined, buildCommand: buildCommand || undefined, + startCommand: startCommand || undefined, outputDirectory: outputDirectory || undefined }); @@ -243,6 +249,7 @@ f.key === 'other'); - let adapter = framework?.adapters[0]; + let adapter = framework?.adapters[0] as FrameworkAdapterWithStartCommand; let branch: string; let rootDir = './'; let installCommand = adapter?.installCommand; let buildCommand = adapter?.buildCommand; + let startCommand = adapter?.startCommand; let outputDirectory = adapter?.outputDirectory; let variables: Partial[] = []; let silentMode = false; @@ -81,9 +86,10 @@ if (!framework) { framework = data.frameworks.frameworks.find((f) => f.key === 'other'); } - adapter = framework?.adapters[0]; + adapter = framework?.adapters[0] as FrameworkAdapterWithStartCommand; installCommand = adapter?.installCommand; buildCommand = adapter?.buildCommand; + startCommand = adapter?.startCommand; outputDirectory = adapter?.outputDirectory; const detectedVariables = normalizeDetectedVariables(response?.variables); if (detectedVariables.length) { @@ -121,6 +127,7 @@ buildRuntime, installCommand, buildCommand, + startCommand, outputDirectory, installationId: data.installation.$id, providerRepositoryId: data.repository.id, @@ -218,6 +225,7 @@ a.key === adapter) ?? selectedFramework.adapters[0] + let frameworkAdapterData: FrameworkAdapterWithStartCommand = $derived( + (selectedFramework.adapters.find((a) => a.key === adapter) ?? + selectedFramework.adapters[0]) as FrameworkAdapterWithStartCommand ); $effect(() => { if (adapter) { - const data = selectedFramework.adapters.find((a) => a.key === adapter); + const data = selectedFramework.adapters.find( + (a) => a.key === adapter + ) as FrameworkAdapterWithStartCommand; if (data) { installCommand = data.installCommand; buildCommand = data.buildCommand; + startCommand = data.startCommand; outputDirectory = data.outputDirectory; fallback = data.fallbackFile; } @@ -78,11 +88,11 @@ } //Update values - const data = - selectedFramework.adapters.find((a) => a.key === adapter) ?? - selectedFramework.adapters[0]; + const data = (selectedFramework.adapters.find((a) => a.key === adapter) ?? + selectedFramework.adapters[0]) as FrameworkAdapterWithStartCommand; installCommand = data.installCommand; buildCommand = data.buildCommand; + startCommand = data.startCommand; outputDirectory = data.outputDirectory; adapter = data.key as Adapter; fallback = data.fallbackFile; @@ -90,6 +100,7 @@ adapter = site.adapter as Adapter; installCommand = site?.installCommand ?? frameworkAdapterData.installCommand; buildCommand = site?.buildCommand ?? frameworkAdapterData.buildCommand; + startCommand = site?.startCommand ?? frameworkAdapterData.startCommand; outputDirectory = site?.outputDirectory ?? frameworkAdapterData.outputDirectory; fallback = site?.fallbackFile ?? frameworkAdapterData.fallbackFile; } @@ -149,6 +160,7 @@ timeout: site.timeout || undefined, installCommand: installCommand || undefined, buildCommand: buildCommand || undefined, + startCommand: startCommand || undefined, outputDirectory: outputDirectory || undefined, buildRuntime: (site?.buildRuntime as BuildRuntime) || undefined, adapter: (adptr?.key as Adapter) || undefined, @@ -178,13 +190,17 @@ } } - function reset(type: 'installCommand' | 'buildCommand' | 'outputDirectory') { - const data = selectedFramework.adapters.find((a) => a.key === adapter); + function reset(type: 'installCommand' | 'buildCommand' | 'startCommand' | 'outputDirectory') { + const data = selectedFramework.adapters.find( + (a) => a.key === adapter + ) as FrameworkAdapterWithStartCommand; if (type === 'installCommand') { installCommand = data.installCommand; } else if (type === 'buildCommand') { buildCommand = data.buildCommand; + } else if (type === 'startCommand') { + startCommand = data.startCommand; } else if (type === 'outputDirectory') { outputDirectory = data.outputDirectory; } @@ -311,6 +327,24 @@ Reset + {#if adapter === Adapter.Ssr} + + + + + {/if} Date: Wed, 22 Apr 2026 13:12:05 +0530 Subject: [PATCH 11/54] addressed comments --- src/lib/stores/sites.ts | 6 ++++++ .../settings/updateProtocols.svelte | 13 ++++++++----- .../sites/create-site/configuration.svelte | 12 +++++------- .../sites/create-site/deploy/+page.svelte | 5 +++-- .../sites/create-site/manual/+page.svelte | 5 +---- .../repository-[repository]/+page.svelte | 5 +---- .../site-[site]/settings/updateBuildSettings.svelte | 12 +++++------- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/lib/stores/sites.ts b/src/lib/stores/sites.ts index 29d811332..ef39511ee 100644 --- a/src/lib/stores/sites.ts +++ b/src/lib/stores/sites.ts @@ -1,3 +1,9 @@ +import type { Models } from '@appwrite.io/console'; + +export type FrameworkAdapterWithStartCommand = Models.FrameworkAdapter & { + startCommand?: string; +}; + export function getFrameworkIcon(framework: string) { switch (true) { case framework.toLocaleLowerCase().includes('sveltekit'): diff --git a/src/routes/(console)/project-[region]-[project]/settings/updateProtocols.svelte b/src/routes/(console)/project-[region]-[project]/settings/updateProtocols.svelte index 8492bb66c..c5b0b4dde 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/updateProtocols.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/updateProtocols.svelte @@ -155,7 +155,9 @@ disabled={shouldDisableDisableAllButton}>Disable all - +
+ +
{#each $protocols.list as protocol, index} @@ -207,7 +209,12 @@ diff --git a/src/lib/helpers/files.ts b/src/lib/helpers/files.ts index de236f5f2..6aaf48769 100644 --- a/src/lib/helpers/files.ts +++ b/src/lib/helpers/files.ts @@ -80,6 +80,29 @@ export async function gzipUpload(files: FileList) { return uploadFile; } +export function isTarGzFile(file: File) { + return file.name.toLowerCase().endsWith('.tar.gz'); +} + +export function getInvalidDeploymentArchiveReason( + files: FileList | File[] | null | undefined, + maxSize?: number +) { + if (!files) return null; + + const normalizedFiles = Array.from(files); + + if (!normalizedFiles.length) return null; + if (maxSize && normalizedFiles.some((file) => file.size > maxSize)) { + return InvalidFileType.SIZE; + } + if (normalizedFiles.some((file) => !isTarGzFile(file))) { + return InvalidFileType.EXTENSION; + } + + return null; +} + export function removeFile(file: File, files: FileList) { const filteredFiles = Array.from(files).filter((f) => f.name !== file.name); const dataTransfer = new DataTransfer(); diff --git a/src/lib/stores/uploader.ts b/src/lib/stores/uploader.ts index 97f475f99..bf0125076 100644 --- a/src/lib/stores/uploader.ts +++ b/src/lib/stores/uploader.ts @@ -1,21 +1,34 @@ +import { page } from '$app/state'; +import { getApiEndpoint } from '$lib/stores/sdk'; import { Client, Functions, ID, type Models, Sites, Storage } from '@appwrite.io/console'; import { writable } from 'svelte/store'; -import { getApiEndpoint } from '$lib/stores/sdk'; -import { page } from '$app/state'; -type UploaderFile = { +export type UploadKind = 'storage' | 'site-deployment' | 'function-deployment'; +export type UploadGroupKey = 'storage' | 'deployments'; + +export type UploaderFile = { $id: string; + clientId: string; resourceId: string; name: string; progress: number; size: number; status: 'failed' | 'pending' | 'success'; + kind: UploadKind; error?: string; }; + +export type UploadGroupState = { + isOpen: boolean; + isVisible: boolean; +}; + +type UploadGroups = Record; + export type Uploader = { isOpen: boolean; - isCollapsed: boolean; files: UploaderFile[]; + groups: UploadGroups; }; const temporaryStorage = (region: string, projectId: string) => { @@ -41,22 +54,76 @@ const temporaryFunctions = (region: string, projectId: string) => { const MAX_CONCURRENT_UPLOADS = 5; +const createInitialGroups = (): UploadGroups => ({ + storage: { + isOpen: true, + isVisible: true + }, + deployments: { + isOpen: true, + isVisible: true + } +}); + +export function getUploadGroupKey(kind: UploadKind): UploadGroupKey { + return kind === 'storage' ? 'storage' : 'deployments'; +} + +function hasFilesForGroup(files: UploaderFile[], groupKey: UploadGroupKey) { + return files.some((file) => getUploadGroupKey(file.kind) === groupKey); +} + +function refreshUploaderState(state: Uploader) { + for (const groupKey of Object.keys(state.groups) as UploadGroupKey[]) { + if (!hasFilesForGroup(state.files, groupKey)) { + state.groups[groupKey] = { + ...createInitialGroups()[groupKey] + }; + } + } + + state.isOpen = (Object.keys(state.groups) as UploadGroupKey[]).some( + (groupKey) => hasFilesForGroup(state.files, groupKey) && state.groups[groupKey].isVisible + ); + + return state; +} + const createUploader = () => { const { subscribe, set, update } = writable({ isOpen: false, - isCollapsed: false, - files: [] + files: [], + groups: createInitialGroups() }); - const updateFile = (id: string, file: Partial) => { - return update((n) => { - const index = n.files.findIndex((f) => f.$id === id); - n.files[index] = { - ...n.files[index], + const updateFile = (clientId: string, file: Partial) => { + return update((state) => { + const index = state.files.findIndex((item) => item.clientId === clientId); + + if (index === -1) { + return state; + } + + state.files[index] = { + ...state.files[index], ...file }; - return n; + return state; + }); + }; + + const addFileToQueue = (file: UploaderFile) => { + update((state) => { + const groupKey = getUploadGroupKey(file.kind); + + state.files.unshift(file); + state.groups[groupKey] = { + isOpen: true, + isVisible: true + }; + + return refreshUploaderState(state); }); }; @@ -70,18 +137,17 @@ const createUploader = () => { ) => { const newFile: UploaderFile = { $id: id, + clientId: id, resourceId: bucketId, name: file.name, size: file.size, progress: 0, - status: 'pending' + status: 'pending', + kind: 'storage' }; - update((n) => { - n.isOpen = true; - n.isCollapsed = false; - n.files.unshift(newFile); - return n; - }); + + addFileToQueue(newFile); + try { const uploadedFile = await temporaryStorage(region, projectId).createFile({ bucketId, @@ -92,17 +158,17 @@ const createUploader = () => { newFile.$id = progress.$id; newFile.progress = progress.progress; newFile.status = progress.progress === 100 ? 'success' : 'pending'; - updateFile(progress.$id, newFile); + updateFile(newFile.clientId, newFile); } }); newFile.$id = uploadedFile.$id; newFile.progress = 100; newFile.status = 'success'; - updateFile(newFile.$id, newFile); + updateFile(newFile.clientId, newFile); } catch (e) { newFile.status = 'failed'; newFile.error = e?.message ?? 'Upload failed'; - updateFile(newFile.$id, newFile); + updateFile(newFile.clientId, newFile); throw e; } }; @@ -139,25 +205,47 @@ const createUploader = () => { return results; }; + const uploadDeployment = async ( + kind: Extract, + resourceId: string, + name: string, + size: number, + request: () => Promise + ) => { + const newDeployment: UploaderFile = { + $id: '', + clientId: ID.unique(), + resourceId, + name, + size, + progress: 0, + status: 'pending', + kind + }; + + addFileToQueue(newDeployment); + + try { + const uploadedFile = await request(); + newDeployment.$id = uploadedFile.$id; + newDeployment.progress = 100; + newDeployment.status = 'success'; + updateFile(newDeployment.clientId, newDeployment); + } catch (e) { + newDeployment.status = 'failed'; + newDeployment.error = e?.message ?? 'Upload failed'; + updateFile(newDeployment.clientId, newDeployment); + throw e; + } + }; + return { subscribe, - - close: () => - update((n) => { - n.isOpen = !n.isOpen; - return n; - }), - toggle: () => - update((n) => { - n.isCollapsed = !n.isCollapsed; - - return n; - }), reset: () => set({ isOpen: false, - isCollapsed: false, - files: [] + files: [], + groups: createInitialGroups() }), uploadFile, uploadFiles, @@ -166,53 +254,24 @@ const createUploader = () => { code, buildCommand, installCommand, - startCommand, outputDirectory }: { siteId: string; code: File; buildCommand?: string; installCommand?: string; - startCommand?: string; outputDirectory?: string; }) => { - const newDeployment: UploaderFile = { - $id: '', - resourceId: siteId, - name: code.name, - size: code.size, - progress: 0, - status: 'pending' - }; - update((n) => { - n.isOpen = true; - n.isCollapsed = false; - n.files.unshift(newDeployment); - return n; - }); - const deploymentPayload = { - siteId, - code, - activate: true, - buildCommand, - installCommand, - startCommand, - outputDirectory, - onProgress: (progress) => { - newDeployment.$id = progress.$id; - newDeployment.progress = progress.progress; - newDeployment.status = progress.progress === 100 ? 'success' : 'pending'; - updateFile(progress.$id, newDeployment); - } - }; - const uploadedFile = await temporarySites( - page.params.region, - page.params.project - ).createDeployment(deploymentPayload); - newDeployment.$id = uploadedFile.$id; - newDeployment.progress = 100; - newDeployment.status = 'success'; - updateFile(newDeployment.$id, newDeployment); + return uploadDeployment('site-deployment', siteId, code.name, code.size, async () => + temporarySites(page.params.region, page.params.project).createDeployment({ + siteId, + code, + activate: true, + buildCommand, + installCommand, + outputDirectory + }) + ); }, uploadFunctionDeployment: async ({ functionId, @@ -221,52 +280,42 @@ const createUploader = () => { functionId: string; code: File; }) => { - const newDeployment: UploaderFile = { - $id: '', - resourceId: functionId, - name: code.name, - size: code.size, - progress: 0, - status: 'pending' - }; - update((n) => { - n.isOpen = true; - n.isCollapsed = false; - n.files.unshift(newDeployment); - return n; - }); - const uploadedFile = await temporaryFunctions( - page.params.region, - page.params.project - ).createDeployment({ + return uploadDeployment( + 'function-deployment', functionId, - code, - activate: true, - onProgress: (progress) => { - newDeployment.$id = progress.$id; - newDeployment.progress = progress.progress; - newDeployment.status = progress.progress === 100 ? 'success' : 'pending'; - updateFile(progress.$id, newDeployment); - } + code.name, + code.size, + async () => + temporaryFunctions(page.params.region, page.params.project).createDeployment({ + functionId, + code, + activate: true + }) + ); + }, + toggleGroup: (groupKey: UploadGroupKey) => { + update((state) => { + state.groups[groupKey].isOpen = !state.groups[groupKey].isOpen; + return refreshUploaderState(state); + }); + }, + hideGroup: (groupKey: UploadGroupKey) => { + update((state) => { + state.groups[groupKey].isVisible = false; + return refreshUploaderState(state); }); - newDeployment.$id = uploadedFile.$id; - newDeployment.progress = 100; - newDeployment.status = 'success'; - updateFile(newDeployment.$id, newDeployment); }, removeFromQueue: (id: string) => { - update((n) => { - n.files = n.files.filter((f) => f.$id !== id); - n.isOpen = n.files.length !== 0; - return n; + update((state) => { + state.files = state.files.filter((file) => file.$id !== id && file.clientId !== id); + return refreshUploaderState(state); }); }, removeFile: async (file: Models.File) => { if (file.chunksTotal === file.chunksUploaded) { - return update((n) => { - n.files = n.files.filter((f) => f.$id !== file.$id); - - return n; + return update((state) => { + state.files = state.files.filter((item) => item.$id !== file.$id); + return refreshUploaderState(state); }); } } diff --git a/src/routes/(console)/project-[region]-[project]/functions/create-function/manual/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/create-function/manual/+page.svelte index d0e10cdf4..b7d3f5c5a 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/create-function/manual/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/create-function/manual/+page.svelte @@ -19,7 +19,11 @@ import Configuration from './configuration.svelte'; import { getIconFromRuntime } from '$lib/stores/runtimes'; import { regionalConsoleVariables } from '../../../store'; - import { InvalidFileType, removeFile } from '$lib/helpers/files'; + import { + getInvalidDeploymentArchiveReason, + InvalidFileType, + removeFile + } from '$lib/helpers/files'; import { isCloud } from '$lib/system'; import { humanFileSize } from '$lib/helpers/sizeConvertion'; import { currentPlan } from '$lib/stores/organization'; @@ -108,7 +112,9 @@ }); await promise; - const upload = $uploader.files.find((f) => f.resourceId === func.$id); + const upload = $uploader.files.find( + (f) => f.resourceId === func.$id && f.kind === 'function-deployment' + ); if (upload?.status === 'success') { const deploymentId = upload.$id; @@ -126,9 +132,11 @@ invalidate(Dependencies.FUNCTION); } catch (e) { - const upload = $uploader.files.find((f) => f.resourceId === func?.$id); + const upload = $uploader.files.find( + (f) => f.resourceId === func?.$id && f.kind === 'function-deployment' + ); if (upload) { - uploader.removeFromQueue(upload.$id); + uploader.removeFromQueue(upload.clientId); } addNotification({ type: 'error', @@ -158,6 +166,15 @@ } } + $: if (files?.length) { + const reason = getInvalidDeploymentArchiveReason(files, maxSize); + + if (reason) { + files = undefined; + handleInvalid(new CustomEvent('invalid', { detail: { reason } })); + } + } + $: filesList = files?.length ? Array.from(files).map((f) => { return { @@ -198,7 +215,7 @@ diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createManual.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createManual.svelte index 8250b1404..fcdd29db1 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createManual.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createManual.svelte @@ -4,7 +4,11 @@ import { Modal } from '$lib/components'; import { Dependencies } from '$lib/constants'; import { Button } from '$lib/elements/forms'; - import { InvalidFileType, removeFile } from '$lib/helpers/files'; + import { + getInvalidDeploymentArchiveReason, + InvalidFileType, + removeFile + } from '$lib/helpers/files'; import { addNotification } from '$lib/stores/notifications'; import { IconInfo } from '@appwrite.io/pink-icons-svelte'; import { Icon, Layout, Tooltip, Typography, Upload } from '@appwrite.io/pink-svelte'; @@ -60,6 +64,15 @@ } } + $: if (files?.length) { + const reason = getInvalidDeploymentArchiveReason(files, maxSize); + + if (reason) { + files = undefined; + handleInvalid(new CustomEvent('invalid', { detail: { reason } })); + } + } + $: filesList = files?.length ? Array.from(files).map((f) => { return { @@ -80,7 +93,7 @@ Upload a tar.gz file containing your function source code f.resourceId === site.$id); + const upload = $uploader.files.find( + (f) => f.resourceId === site.$id && f.kind === 'site-deployment' + ); if (upload?.status === 'success') { const deploymentId = upload.$id; @@ -129,9 +134,11 @@ await goto(`${resolvedPath}?site=${site.$id}&deployment=${deploymentId}`); } } catch (e) { - const upload = $uploader.files.find((f) => f.resourceId === site?.$id); + const upload = $uploader.files.find( + (f) => f.resourceId === site?.$id && f.kind === 'site-deployment' + ); if (upload) { - uploader.removeFromQueue(upload.$id); + uploader.removeFromQueue(upload.clientId); } addNotification({ type: 'error', @@ -145,17 +152,7 @@ let reason = e.detail?.reason ?? ''; if (!reason) { - const nativeEvent = e.detail as Event | undefined; - const input = (nativeEvent?.currentTarget ?? nativeEvent?.target) as - | HTMLInputElement - | undefined; - const pickedFiles = Array.from(input?.files ?? []); - - if (pickedFiles.some((file) => file.size > maxSize)) { - reason = InvalidFileType.SIZE; - } else if (pickedFiles.some((file) => !file.name.toLowerCase().endsWith('.tar.gz'))) { - reason = InvalidFileType.EXTENSION; - } + reason = getInvalidDeploymentArchiveReason(files, maxSize) ?? ''; } if (reason === InvalidFileType.EXTENSION) { @@ -176,6 +173,15 @@ } } + $: if (files?.length) { + const reason = getInvalidDeploymentArchiveReason(files, maxSize); + + if (reason) { + files = undefined; + handleInvalid(new CustomEvent('invalid', { detail: { reason } })); + } + } + $: filesList = files?.length ? Array.from(files).map((f) => { return { @@ -205,7 +211,7 @@ Upload a tar.gz containing your site source code { return { @@ -80,7 +93,7 @@ Upload a tar.gz file containing your site source code { isUploading = $uploader.files.some( (file) => - file.status !== 'success' && file.progress < 100 && file.status !== 'failed' + file.kind === 'storage' && + file.status !== 'success' && + file.progress < 100 && + file.status !== 'failed' ); }); }); From ee6d36f516d95e5e3f6a37d7bb88d5e341ee7907 Mon Sep 17 00:00:00 2001 From: harsh mahajan Date: Tue, 5 May 2026 00:23:39 +0530 Subject: [PATCH 24/54] Revert "fix: remove databases reads/writes usage tab and clear loaders" This reverts commit 1f2aab991617f13068f7842346c65d6c13b77c9b. --- .../database-[database]/header.svelte | 6 +++++ .../usage/[[period]]/+page.svelte | 23 ++++++++++++++-- .../usage/[[period]]/+page.ts | 16 ++++++++++- .../databases/header.svelte | 6 +++++ .../databases/usage/[[period]]/+page.svelte | 27 +++++++++++++++++-- .../databases/usage/[[period]]/+page.ts | 15 ++++++++++- 6 files changed, 87 insertions(+), 6 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/header.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/header.svelte index 7bd3d0756..1d3ded6c0 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/header.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/header.svelte @@ -34,6 +34,12 @@ event: 'backups', hasChildren: true }, + { + href: withPath(baseDatabasePath, '/usage'), + title: 'Usage', + event: 'usage', + hasChildren: true + }, { href: withPath(baseDatabasePath, '/settings'), event: 'settings', diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.svelte index 3ef899e53..84c6ff2b7 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.svelte @@ -1,5 +1,24 @@ - + + + diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.ts index 80b1ec6bf..9391c5451 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.ts @@ -1,3 +1,17 @@ +import { isValueOfStringEnum } from '$lib/helpers/types'; +import { sdk } from '$lib/stores/sdk'; +import { UsageRange } from '@appwrite.io/console'; import type { PageLoad } from './$types'; -export const load: PageLoad = async () => ({}); +export const load: PageLoad = async ({ params }) => { + const period = isValueOfStringEnum(UsageRange, params.period) + ? params.period + : UsageRange.ThirtyDays; + + return { + ...(await sdk.forProject(params.region, params.project).tablesDB.getUsage({ + databaseId: params.database, + range: period + })) + }; +}; diff --git a/src/routes/(console)/project-[region]-[project]/databases/header.svelte b/src/routes/(console)/project-[region]-[project]/databases/header.svelte index edaaeb32e..796c86d09 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/header.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/header.svelte @@ -14,6 +14,12 @@ title: 'Databases', event: 'databases', hasChildren: true + }, + { + href: `${path}/usage`, + title: 'Usage', + event: 'usage', + hasChildren: true } ]; diff --git a/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.svelte index 3ef899e53..b5b114d9a 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.svelte @@ -1,5 +1,28 @@ - + + + + + diff --git a/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.ts b/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.ts index 80b1ec6bf..359a5153e 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.ts @@ -1,3 +1,16 @@ +import { isValueOfStringEnum } from '$lib/helpers/types'; +import { sdk } from '$lib/stores/sdk'; +import { UsageRange } from '@appwrite.io/console'; import type { PageLoad } from './$types'; -export const load: PageLoad = async () => ({}); +export const load: PageLoad = async ({ params }) => { + const period = isValueOfStringEnum(UsageRange, params.period) + ? params.period + : UsageRange.ThirtyDays; + + return { + ...(await sdk + .forProject(params.region, params.project) + .tablesDB.listUsage({ range: period })) + }; +}; From e424e6e1bb3e128d20a5a27e872be79cc06b22f3 Mon Sep 17 00:00:00 2001 From: harsh mahajan Date: Tue, 5 May 2026 10:54:34 +0530 Subject: [PATCH 25/54] fix: restore deployment upload progress --- src/lib/helpers/files.ts | 8 ++------ src/lib/stores/uploader.ts | 22 +++++++++++++++++----- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/lib/helpers/files.ts b/src/lib/helpers/files.ts index 6aaf48769..1efd2319e 100644 --- a/src/lib/helpers/files.ts +++ b/src/lib/helpers/files.ts @@ -80,10 +80,6 @@ export async function gzipUpload(files: FileList) { return uploadFile; } -export function isTarGzFile(file: File) { - return file.name.toLowerCase().endsWith('.tar.gz'); -} - export function getInvalidDeploymentArchiveReason( files: FileList | File[] | null | undefined, maxSize?: number @@ -93,10 +89,10 @@ export function getInvalidDeploymentArchiveReason( const normalizedFiles = Array.from(files); if (!normalizedFiles.length) return null; - if (maxSize && normalizedFiles.some((file) => file.size > maxSize)) { + if (maxSize !== undefined && normalizedFiles.some((file) => file.size > maxSize)) { return InvalidFileType.SIZE; } - if (normalizedFiles.some((file) => !isTarGzFile(file))) { + if (normalizedFiles.some((file) => !file.name.toLowerCase().endsWith('.tar.gz'))) { return InvalidFileType.EXTENSION; } diff --git a/src/lib/stores/uploader.ts b/src/lib/stores/uploader.ts index bf0125076..9640326ff 100644 --- a/src/lib/stores/uploader.ts +++ b/src/lib/stores/uploader.ts @@ -31,6 +31,11 @@ export type Uploader = { groups: UploadGroups; }; +type UploadProgress = { + $id: string; + progress: number; +}; + const temporaryStorage = (region: string, projectId: string) => { const clientProject = new Client().setMode('admin'); const endpoint = getApiEndpoint(region); @@ -210,7 +215,7 @@ const createUploader = () => { resourceId: string, name: string, size: number, - request: () => Promise + request: (onProgress: (progress: UploadProgress) => void) => Promise ) => { const newDeployment: UploaderFile = { $id: '', @@ -226,7 +231,12 @@ const createUploader = () => { addFileToQueue(newDeployment); try { - const uploadedFile = await request(); + const uploadedFile = await request((progress) => { + newDeployment.$id = progress.$id; + newDeployment.progress = progress.progress; + newDeployment.status = progress.progress === 100 ? 'success' : 'pending'; + updateFile(newDeployment.clientId, newDeployment); + }); newDeployment.$id = uploadedFile.$id; newDeployment.progress = 100; newDeployment.status = 'success'; @@ -262,13 +272,14 @@ const createUploader = () => { installCommand?: string; outputDirectory?: string; }) => { - return uploadDeployment('site-deployment', siteId, code.name, code.size, async () => + return uploadDeployment('site-deployment', siteId, code.name, code.size, (onProgress) => temporarySites(page.params.region, page.params.project).createDeployment({ siteId, code, activate: true, buildCommand, installCommand, + onProgress, outputDirectory }) ); @@ -285,11 +296,12 @@ const createUploader = () => { functionId, code.name, code.size, - async () => + (onProgress) => temporaryFunctions(page.params.region, page.params.project).createDeployment({ functionId, code, - activate: true + activate: true, + onProgress }) ); }, From a10be206954a6129249f94d47dbcf9d818b3a540 Mon Sep 17 00:00:00 2001 From: harsh mahajan Date: Tue, 5 May 2026 12:16:39 +0530 Subject: [PATCH 26/54] fix: correct function usage period totals --- .../usage/[[period]]/+page.svelte | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/usage/[[period]]/+page.svelte index 705478db7..624d6bfe6 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/usage/[[period]]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/usage/[[period]]/+page.svelte @@ -1,20 +1,29 @@ @@ -26,11 +35,12 @@ legend: 'Executions', title: 'Total executions' }} + isCumulative {total} {count} /> {/if} - {#if mbSecondsCount} + {#if executionsTime.length} {/if} From 9193921bd51548e2df1a3c4c3bbe98b9a0fd90f0 Mon Sep 17 00:00:00 2001 From: harsh mahajan Date: Tue, 5 May 2026 12:23:59 +0530 Subject: [PATCH 27/54] fix: guard empty function usage chart --- .../functions/function-[function]/usage/[[period]]/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/usage/[[period]]/+page.svelte index 624d6bfe6..4a1316b98 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/usage/[[period]]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/usage/[[period]]/+page.svelte @@ -28,7 +28,7 @@ - {#if count} + {#if count.length} Date: Tue, 5 May 2026 12:24:15 +0530 Subject: [PATCH 28/54] refactor: improve periodic usage charts --- src/lib/layout/usageMultiple.svelte | 59 +++++++++++++------ .../usage/[[period]]/+page.svelte | 29 +++++++-- .../databases/usage/[[period]]/+page.svelte | 53 +++++++++++++++-- 3 files changed, 110 insertions(+), 31 deletions(-) diff --git a/src/lib/layout/usageMultiple.svelte b/src/lib/layout/usageMultiple.svelte index 85f5091ca..ff1789c49 100644 --- a/src/lib/layout/usageMultiple.svelte +++ b/src/lib/layout/usageMultiple.svelte @@ -1,19 +1,47 @@
@@ -41,19 +69,12 @@ {#if count} - {@const totalCount = clampMin(total.reduce((a, b) => a + b, 0))} - {formatNumberWithCommas(totalCount)} Total {title.toLocaleLowerCase()}
- ({ - name: legendData[index].name, - data: accumulateFromEndingTotal(c, total[index]) - }))} /> + {#if legendData} + import { base } from '$app/paths'; + import { page } from '$app/state'; + import { clampMin } from '$lib/helpers/numbers'; + import { formatNum } from '$lib/helpers/string'; import { Container, UsageMultiple } from '$lib/layout'; + import type { PageProps } from './$types'; - export let data; + let { data }: PageProps = $props(); - $: reads = data.databaseReads; - $: readsTotal = data.databaseReadsTotal; + const reads = $derived(data.databaseReads ?? []); + const readsTotal = $derived(clampMin(reads.reduce((sum, item) => sum + item.value, 0))); - $: writes = data.databaseWrites; - $: writesTotal = data.databaseWritesTotal; + const writes = $derived(data.databaseWrites ?? []); + const writesTotal = $derived(clampMin(writes.reduce((sum, item) => sum + item.value, 0))); + + const usagePath = $derived( + `${base}/project-${page.params.region}-${page.params.project}/databases/database-${page.params.database}/usage` + ); + import { goto } from '$app/navigation'; + import { base } from '$app/paths'; + import { page } from '$app/state'; import { Container, UsageMultiple } from '$lib/layout'; + import { InputSelect } from '$lib/elements/forms'; + import { clampMin } from '$lib/helpers/numbers'; + import { formatNum } from '$lib/helpers/string'; import { Layout } from '@appwrite.io/pink-svelte'; - import type { PageData } from './$types'; + import type { PageProps } from './$types'; - export let data: PageData; + let { data }: PageProps = $props(); - $: reads = data.databasesReads; - $: readsTotal = data.databasesReadsTotal; + const reads = $derived(data.databasesReads ?? []); + const readsTotal = $derived(clampMin(reads.reduce((sum, item) => sum + item.value, 0))); - $: writes = data.databasesWrites; - $: writesTotal = data.databasesWritesTotal; + const writes = $derived(data.databasesWrites ?? []); + const writesTotal = $derived(clampMin(writes.reduce((sum, item) => sum + item.value, 0))); + + const usagePath = $derived( + `${base}/project-${page.params.region}-${page.params.project}/databases/usage` + ); +
+ goto(`${usagePath}/${e.detail}`)} + id="period" + options={[ + { + label: '24 hours', + value: '24h' + }, + { + label: '30 days', + value: '30d' + }, + { + label: '90 days', + value: '90d' + } + ]} + value={page.params.period ?? '30d'} /> +
+ Date: Tue, 5 May 2026 16:00:08 +0530 Subject: [PATCH 29/54] fix: normalize created proxy rule status in console --- .../components/domains/nameserverTable.svelte | 12 ++-- src/lib/components/domains/recordTable.svelte | 16 ++--- src/lib/components/domains/status.ts | 70 +++++++++++++++++++ .../domains/add-domain/+page.svelte | 3 +- .../function-[function]/domains/table.svelte | 39 +++++------ .../settings/domains/add-domain/+page.svelte | 3 +- .../settings/domains/table.svelte | 39 +++++------ .../domains/add-domain/+page.svelte | 3 +- .../sites/site-[site]/domains/table.svelte | 39 +++++------ 9 files changed, 134 insertions(+), 90 deletions(-) create mode 100644 src/lib/components/domains/status.ts diff --git a/src/lib/components/domains/nameserverTable.svelte b/src/lib/components/domains/nameserverTable.svelte index 66c7c165d..59e652ed1 100644 --- a/src/lib/components/domains/nameserverTable.svelte +++ b/src/lib/components/domains/nameserverTable.svelte @@ -1,5 +1,6 @@ This project has been paused due to inactivity. - Your data is safe and will remain intact. Upgrade your plan to keep your projects - active, or restore the project to continue using it. + Your data is safe and will remain intact. + {#if $isSmallViewport} + Upgrade your plan to keep your projects + active, or restore the project to continue using it. + {:else} + Upgrade your plan to keep your projects active, or restore the project to continue + using it. + {/if} {#if error} @@ -103,7 +114,9 @@ Restore project {/if} - + {#if !$isSmallViewport} + + {/if}
From d6ab5a065d169bd2e9435c3632e7888beee437e0 Mon Sep 17 00:00:00 2001 From: harsh mahajan Date: Tue, 5 May 2026 18:56:36 +0530 Subject: [PATCH 31/54] Fix paused project modal upgrade href reactivity --- .../project-[region]-[project]/pausedProjectModal.svelte | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte b/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte index 6697f829b..56f2363b1 100644 --- a/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte @@ -75,9 +75,11 @@ ); } - const upgradeHref = resolve('/(console)/organization-[organization]/change-plan', { - organization: teamId - }); + const upgradeHref = $derived( + resolve('/(console)/organization-[organization]/change-plan', { + organization: teamId + }) + ); From 9efbe81d43b4bed0165cd9fd45771732c7b4f0b7 Mon Sep 17 00:00:00 2001 From: harsh mahajan Date: Tue, 5 May 2026 22:40:38 +0530 Subject: [PATCH 32/54] fix: restore project layout --- .../pausedProjectModal.svelte | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte b/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte index 56f2363b1..627d3d9ef 100644 --- a/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte @@ -104,22 +104,35 @@ - - - - - {#if !$isSmallViewport} - - {/if} + - + {:else} + + + + + + + + {/if} From 1636a7f57761e09609b718412c389653ce2d0540 Mon Sep 17 00:00:00 2001 From: harsh mahajan Date: Tue, 5 May 2026 23:12:55 +0530 Subject: [PATCH 33/54] fix: prevent false file size error when plan deploymentSize is zero --- .../functions/create-function/manual/+page.svelte | 6 +++--- .../function-[function]/(modals)/createManual.svelte | 4 ++-- .../sites/create-site/manual/+page.svelte | 4 ++-- .../deployments/createManualDeploymentModal.svelte | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/functions/create-function/manual/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/create-function/manual/+page.svelte index b7d3f5c5a..3e125c978 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/create-function/manual/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/create-function/manual/+page.svelte @@ -156,7 +156,7 @@ } else if (reason === InvalidFileType.SIZE) { addNotification({ type: 'error', - message: 'File size exceeds 10MB' + message: `File size exceeds ${readableMaxSize.value}${readableMaxSize.unit}` }); } else { addNotification({ @@ -188,9 +188,9 @@ : []; $: maxSize = - isCloud && $currentPlan + isCloud && $currentPlan?.deploymentSize ? $currentPlan.deploymentSize * 1000000 - : $regionalConsoleVariables._APP_COMPUTE_SIZE_LIMIT; // already in MB + : $regionalConsoleVariables._APP_COMPUTE_SIZE_LIMIT; $: readableMaxSize = humanFileSize(maxSize); diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createManual.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createManual.svelte index fcdd29db1..0ae9ada85 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createManual.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createManual.svelte @@ -27,7 +27,7 @@ $: maxSize = isCloud && $currentPlan?.deploymentSize ? $currentPlan.deploymentSize * 1000000 - : $consoleVariables._APP_COMPUTE_SIZE_LIMIT; // already in MB + : $consoleVariables._APP_COMPUTE_SIZE_LIMIT; $: readableMaxSize = humanFileSize(maxSize); @@ -58,7 +58,7 @@ if (reason === InvalidFileType.EXTENSION) { error = 'Only .tar.gz files allowed'; } else if (reason === InvalidFileType.SIZE) { - error = 'File size exceeds 10MB'; + error = `File size exceeds ${readableMaxSize.value}${readableMaxSize.unit}`; } else { error = 'Invalid file'; } diff --git a/src/routes/(console)/project-[region]-[project]/sites/create-site/manual/+page.svelte b/src/routes/(console)/project-[region]-[project]/sites/create-site/manual/+page.svelte index 3db11d7cf..5a313e8f5 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/create-site/manual/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/create-site/manual/+page.svelte @@ -50,9 +50,9 @@ let files: FileList; $: maxSize = - isCloud && $currentPlan + isCloud && $currentPlan?.deploymentSize ? $currentPlan.deploymentSize * 1000000 - : $regionalConsoleVariables._APP_COMPUTE_SIZE_LIMIT; // already in MB + : $regionalConsoleVariables._APP_COMPUTE_SIZE_LIMIT; $: readableMaxSize = humanFileSize(maxSize); diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/createManualDeploymentModal.svelte b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/createManualDeploymentModal.svelte index 8a3051c2a..6c99e2091 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/createManualDeploymentModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/createManualDeploymentModal.svelte @@ -26,9 +26,9 @@ let error: string = ''; $: maxSize = - isCloud && $currentPlan + isCloud && $currentPlan?.deploymentSize ? $currentPlan.deploymentSize * 1000000 - : $consoleVariables._APP_COMPUTE_SIZE_LIMIT; // already in MB + : $consoleVariables._APP_COMPUTE_SIZE_LIMIT; $: readableMaxSize = humanFileSize(maxSize); @@ -58,7 +58,7 @@ if (reason === InvalidFileType.EXTENSION) { error = 'Only .tar.gz files allowed'; } else if (reason === InvalidFileType.SIZE) { - error = 'File size exceeds 10MB'; + error = `File size exceeds ${readableMaxSize.value}${readableMaxSize.unit}`; } else { error = 'Invalid file'; } From f5a113a50190614af1332dc5c1aa54b032409a65 Mon Sep 17 00:00:00 2001 From: Prem Palanisamy Date: Wed, 6 May 2026 17:05:30 +0100 Subject: [PATCH 34/54] feat: add backup policy migration support --- bun.lock | 4 ++-- package.json | 2 +- src/lib/stores/migration.ts | 12 +++++++++++- .../(migration-wizard)/resource-form.svelte | 7 ++++++- .../settings/migrations/(import)/importReport.svelte | 6 ++++++ 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/bun.lock b/bun.lock index 616c2964a..05bdf932d 100644 --- a/bun.lock +++ b/bun.lock @@ -6,7 +6,7 @@ "name": "@appwrite/console", "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@93d2dfa", + "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@8f00f95", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", "@appwrite.io/pink-legacy": "^1.0.3", @@ -124,7 +124,7 @@ "@analytics/type-utils": ["@analytics/type-utils@0.6.4", "", {}, "sha512-Ou1gQxFakOWLcPnbFVsrPb8g1wLLUZYYJXDPjHkG07+5mustGs5yqACx42UAu4A6NszNN6Z5gGxhyH45zPWRxw=="], - "@appwrite.io/console": ["@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@93d2dfa", { "dependencies": { "json-bigint": "1.0.0" } }], + "@appwrite.io/console": ["@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@8f00f95", { "dependencies": { "json-bigint": "1.0.0" } }], "@appwrite.io/pink-icons": ["@appwrite.io/pink-icons@0.25.0", "", {}, "sha512-0O3i2oEuh5mWvjO80i+X6rbzrWLJ1m5wmv2/M3a1p2PyBJsFxN8xQMTEmTn3Wl/D26SsM7SpzbdW6gmfgoVU9Q=="], diff --git a/package.json b/package.json index 99b100b0a..0eb4abad8 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@93d2dfa", + "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@8f00f95", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", "@appwrite.io/pink-legacy": "^1.0.3", diff --git a/src/lib/stores/migration.ts b/src/lib/stores/migration.ts index 655c0abfc..756f63661 100644 --- a/src/lib/stores/migration.ts +++ b/src/lib/stores/migration.ts @@ -47,6 +47,9 @@ const initialFormData = { messaging: { root: false, messages: false + }, + backups: { + root: false } }; @@ -84,7 +87,8 @@ export const ResourcesFriendly = { provider: { singular: 'Provider', plural: 'Providers' }, topic: { singular: 'Topic', plural: 'Topics' }, subscriber: { singular: 'Subscriber', plural: 'Subscribers' }, - message: { singular: 'Message', plural: 'Messages' } + message: { singular: 'Message', plural: 'Messages' }, + 'backup-policy': { singular: 'Backup Policy', plural: 'Backup Policies' } }; export const providerResources: ProviderResourceMap = { @@ -148,6 +152,9 @@ export const migrationFormToResources =

( if (formData.messaging.messages) { addResource(MigrationResources.Message); } + if (formData.backups.root) { + addResource(MigrationResources.Backuppolicy); + } return resources as ProviderResourceMap[P]; }; @@ -224,6 +231,9 @@ export const resourcesToMigrationForm = (resources: MigrationResource[]): Migrat if (resources.includes(MigrationResources.Message)) { formData.messaging.messages = true; } + if (resources.includes(MigrationResources.Backuppolicy)) { + formData.backups.root = true; + } return formData; }; diff --git a/src/routes/(console)/(migration-wizard)/resource-form.svelte b/src/routes/(console)/(migration-wizard)/resource-form.svelte index ca5898e8f..e11a3d181 100644 --- a/src/routes/(console)/(migration-wizard)/resource-form.svelte +++ b/src/routes/(console)/(migration-wizard)/resource-form.svelte @@ -115,6 +115,10 @@ return resources.includes(MigrationResources.Provider); } + if (groupKey === 'backups') { + return resources.includes(MigrationResources.Backuppolicy); + } + const groupToResource: Record = { users: MigrationResources.User, databases: MigrationResources.Database @@ -135,7 +139,8 @@ functions: 'function', storage: 'bucket', sites: 'site', - messaging: 'provider' + messaging: 'provider', + backups: 'backuppolicy' }; return map[groupKey] || groupKey; }; diff --git a/src/routes/(console)/project-[region]-[project]/settings/migrations/(import)/importReport.svelte b/src/routes/(console)/project-[region]-[project]/settings/migrations/(import)/importReport.svelte index 4dbebc217..991426918 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/migrations/(import)/importReport.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/migrations/(import)/importReport.svelte @@ -33,6 +33,9 @@ messaging: { root: 'Messaging', messages: 'Include messages' + }, + backups: { + root: 'Backup policies' } }; @@ -56,6 +59,9 @@ messaging: { root: 'Import all messaging providers, topics and subscribers', messages: 'Import all messages' + }, + backups: { + root: 'Import all backup policies' } }; From 50b0386f4bf5d1ed26c7436073fca3cc69ac7aef Mon Sep 17 00:00:00 2001 From: Prem Palanisamy Date: Wed, 6 May 2026 18:50:39 +0100 Subject: [PATCH 35/54] fix: use API field name 'backup-policy' for report count --- src/routes/(console)/(migration-wizard)/resource-form.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/(console)/(migration-wizard)/resource-form.svelte b/src/routes/(console)/(migration-wizard)/resource-form.svelte index e11a3d181..7b863f7b7 100644 --- a/src/routes/(console)/(migration-wizard)/resource-form.svelte +++ b/src/routes/(console)/(migration-wizard)/resource-form.svelte @@ -140,7 +140,7 @@ storage: 'bucket', sites: 'site', messaging: 'provider', - backups: 'backuppolicy' + backups: 'backup-policy' }; return map[groupKey] || groupKey; }; From 5bfc3716e23a90f7d13ead8d91a5478801f4fa2d Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 7 May 2026 03:43:40 +0000 Subject: [PATCH 36/54] feat(billing): on-session live payment for create-organization and upgrade-plan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch the create-organization and change-plan submit flows to confirm PaymentIntents on-session via stripe.confirmPayment with redirect: 'if_required'. The frontend now treats PaymentAuthentication responses as the expected default path for paid plans (not just the 3DS edge case) and surfaces succeeded / processing / requires_action outcomes to callers via a new ConfirmPaymentOutcome return type. Other call sites (account/payments, billing, BAA, retry-invoice) remain on the previous redirect-based flow. Add a "Payment is processing" header alert that renders when the team status is 'upgrading' (Stripe still settling). The alert sits below readonly / budget / mark-for-deletion alerts (importance 5), so it only shows when nothing more critical is happening, and lets the user keep using the org while the charge clears. Update the Indian RBI card-holder warning copy to reflect that the first charge is now authenticated on-session and the $150 mandate applies to future renewals — this avoids the 24h "processing" limbo seen with off-session first charges under the RBI mandate. --- .../billing/alerts/paymentProcessing.svelte | 13 +++++ .../billing/selectPaymentMethod.svelte | 8 +-- src/lib/stores/billing.ts | 13 +++++ src/lib/stores/stripe.ts | 49 +++++++++++++++++-- src/routes/(console)/+layout.svelte | 2 + .../create-organization/+page.svelte | 38 ++++++++++---- .../change-plan/+page.svelte | 38 ++++++++++---- 7 files changed, 136 insertions(+), 25 deletions(-) create mode 100644 src/lib/components/billing/alerts/paymentProcessing.svelte diff --git a/src/lib/components/billing/alerts/paymentProcessing.svelte b/src/lib/components/billing/alerts/paymentProcessing.svelte new file mode 100644 index 000000000..0539ba2fa --- /dev/null +++ b/src/lib/components/billing/alerts/paymentProcessing.svelte @@ -0,0 +1,13 @@ + + +{#if $organization?.$id && $organization?.status === teamStatusUpgrading && !hideBillingHeaderRoutes.includes(page.url.pathname)} + + Your plan will activate within a few minutes. You can keep using {$organization.name} while we + confirm the charge with your bank. + +{/if} diff --git a/src/lib/components/billing/selectPaymentMethod.svelte b/src/lib/components/billing/selectPaymentMethod.svelte index 9682b9995..b6a09fc03 100644 --- a/src/lib/components/billing/selectPaymentMethod.svelte +++ b/src/lib/components/billing/selectPaymentMethod.svelte @@ -50,10 +50,10 @@ {#if selectedPaymentMethod?.country?.toLowerCase() === 'in'} Indian credit or debit card-holders - To comply with RBI regulations in India, Appwrite will ask for verification to charge - up to $150 USD on your payment method. We will never charge more than the cost of your - plan and the resources you use, or your budget cap limit. For higher usage limits, please - contact us. + To comply with RBI regulations in India, you will be asked to authenticate the first charge + during checkout, and Appwrite will set up a mandate to charge up to $150 USD on your payment + method for future renewals. We will never charge more than the cost of your plan and the + resources you use, or your budget cap limit. For higher usage limits, please contact us. {/if} { + const { clientSecret, paymentMethodId, orgId, route, redirectIfRequired } = config; try { const resolvedUrl = resolve('/(console)/organization-[organization]/billing', { @@ -203,8 +208,40 @@ export async function confirmPayment(config: { const paymentMethod = await sdk.forConsole.account.getPaymentMethod({ paymentMethodId }); + if (redirectIfRequired) { + const { paymentIntent, error } = await get(stripe).confirmPayment({ + clientSecret, + confirmParams: { + return_url: url, + payment_method: paymentMethod.providerMethodId + }, + redirect: 'if_required' + }); + + if (error) { + addNotification({ + title: 'Error', + message: + error.message ?? + 'There was an error processing your payment, try again later. If the problem persists, please contact support.', + type: 'error' + }); + return { status: 'error', message: error.message ?? 'Payment confirmation failed' }; + } + + const status = paymentIntent?.status; + if (status === 'succeeded' || status === 'processing' || status === 'requires_action') { + return { status }; + } + + return { + status: 'error', + message: `Unexpected payment status: ${status ?? 'unknown'}` + }; + } + const { error } = await get(stripe).confirmPayment({ - clientSecret: clientSecret, + clientSecret, confirmParams: { return_url: url, payment_method: paymentMethod.providerMethodId @@ -221,6 +258,12 @@ export async function confirmPayment(config: { 'There was an error processing your payment, try again later. If the problem persists, please contact support.', type: 'error' }); + if (redirectIfRequired) { + return { + status: 'error', + message: typeof e === 'string' ? e : (e?.message ?? 'Payment confirmation failed') + }; + } } } diff --git a/src/routes/(console)/+layout.svelte b/src/routes/(console)/+layout.svelte index ea0830ac0..8663437fb 100644 --- a/src/routes/(console)/+layout.svelte +++ b/src/routes/(console)/+layout.svelte @@ -18,6 +18,7 @@ checkForMarkedForDeletion, checkForMissingPaymentMethod, checkForNewDevUpgradePro, + checkForUpgradingStatus, checkForUsageLimit, checkPaymentAuthorizationRequired, paymentExpired, @@ -295,6 +296,7 @@ checkForEnterpriseTrial(org); await checkForUsageLimit(org); checkForMarkedForDeletion(org); + checkForUpgradingStatus(org); await checkForNewDevUpgradePro(org); if (org?.billingPlanDetails.requiresPaymentMethod) { diff --git a/src/routes/(console)/create-organization/+page.svelte b/src/routes/(console)/create-organization/+page.svelte index bf5a4a109..8966e2055 100644 --- a/src/routes/(console)/create-organization/+page.svelte +++ b/src/routes/(console)/create-organization/+page.svelte @@ -11,7 +11,8 @@ import { billingIdToPlan, getBasePlanFromGroup, - isPaymentAuthenticationRequired + isPaymentAuthenticationRequired, + teamStatusUpgrading } from '$lib/stores/billing'; import { addNotification } from '$lib/stores/notifications'; import { sdk } from '$lib/stores/sdk'; @@ -106,11 +107,21 @@ }); if (!isPaymentAuthenticationRequired(org)) { + await invalidate(Dependencies.ACCOUNT); await preloadAndNavigate(org.$id); - addNotification({ - type: 'success', - message: `${org.name ?? 'Organization'} has been created` - }); + + if (org.status === teamStatusUpgrading) { + addNotification({ + type: 'info', + message: + 'Payment is processing — your plan will activate within a few minutes.' + }); + } else { + addNotification({ + type: 'success', + message: `${org.name ?? 'Organization'} has been created` + }); + } } } catch (e) { addNotification({ @@ -144,8 +155,8 @@ }); if (isPaymentAuthenticationRequired(org)) { - let clientSecret = org.clientSecret; - let params = new URLSearchParams(); + const clientSecret = org.clientSecret; + const params = new URLSearchParams(); params.append('type', 'payment_confirmed'); params.append('id', org.organizationId); for (const [key, value] of page.url.searchParams.entries()) { @@ -156,12 +167,21 @@ params.append('invites', collaborators.join(',')); const resolvedUrl = resolve('/(console)/create-organization'); - await confirmPayment({ + const outcome = await confirmPayment({ clientSecret, paymentMethodId, - route: `${resolvedUrl}?${params}` + route: `${resolvedUrl}?${params}`, + redirectIfRequired: true }); + if (!outcome || outcome.status === 'error') { + return; + } + + if (outcome.status === 'requires_action') { + return; + } + await validate(org.organizationId, collaborators); } } diff --git a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte index b353f5738..7c9c6923a 100644 --- a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte +++ b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte @@ -12,7 +12,8 @@ import { billingIdToPlan, getBasePlanFromGroup, - isPaymentAuthenticationRequired + isPaymentAuthenticationRequired, + teamStatusUpgrading } from '$lib/stores/billing'; import { addNotification } from '$lib/stores/notifications'; import { currentPlan, organization } from '$lib/stores/organization'; @@ -220,10 +221,19 @@ await invalidate(Dependencies.ORGANIZATION); await goto(previousPage); - addNotification({ - type: 'success', - message: 'Your organization has been upgraded' - }); + + if (org.status === teamStatusUpgrading) { + addNotification({ + type: 'info', + message: + 'Payment is processing — your plan will activate within a few minutes.' + }); + } else { + addNotification({ + type: 'success', + message: 'Your organization has been upgraded' + }); + } trackEvent(Submit.OrganizationUpgrade, { plan: selectedPlan?.name @@ -259,8 +269,8 @@ }); if (isPaymentAuthenticationRequired(org)) { - let clientSecret = org.clientSecret; - let params = new URLSearchParams(); + const clientSecret = org.clientSecret; + const params = new URLSearchParams(); for (const [key, value] of page.url.searchParams.entries()) { if (key !== 'type' && key !== 'id') { params.append(key, value); @@ -275,11 +285,21 @@ organization: org.organizationId }); - await confirmPayment({ + const outcome = await confirmPayment({ clientSecret, paymentMethodId, - route: `${resolvedUrl}?${params.toString()}` + route: `${resolvedUrl}?${params.toString()}`, + redirectIfRequired: true }); + + if (!outcome || outcome.status === 'error') { + return; + } + + if (outcome.status === 'requires_action') { + return; + } + await validate(org.organizationId, collaborators); } From 9e9c737a1d72d11beb722715eac7c6447958c16e Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 7 May 2026 04:03:15 +0000 Subject: [PATCH 37/54] fix(billing): on-session live payment for BAA addon enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch the BAA addon enable flow (both the re-enable button on the settings card and the BAAEnableModal submit) to confirm the addon PaymentIntent on-session via stripe.confirmPayment with redirect: 'if_required'. After a succeeded or processing outcome, finalize the addon by calling organizations.confirmAddonPayment directly and invalidate ADDONS + ORGANIZATION dependencies inline — no more URL round-trip via ?type=confirm-addon&addonId=. A processing outcome surfaces an info notification ("BAA addon payment is processing — we'll activate it shortly.") since the addon stays pending while Stripe settles, and the existing "Payment pending" badge on the BAA card already covers the visual state. The onMount redirect-handler in BAA.svelte that consumes the ?type=confirm-addon query string is preserved as a fallback for the rare case where Stripe still elects to redirect (e.g. some 3DS challenges that can't be inlined) — the route is still passed to confirmPayment so Stripe has a return URL when needed. --- .../settings/BAA.svelte | 40 +++++++++++++++++- .../settings/BAAEnableModal.svelte | 41 ++++++++++++++++++- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/routes/(console)/organization-[organization]/settings/BAA.svelte b/src/routes/(console)/organization-[organization]/settings/BAA.svelte index 71a32f4d2..a4ba95ae3 100644 --- a/src/routes/(console)/organization-[organization]/settings/BAA.svelte +++ b/src/routes/(console)/organization-[organization]/settings/BAA.svelte @@ -160,12 +160,48 @@ const settingsUrl = resolve('/(console)/organization-[organization]/settings', { organization: $organization.$id }); - await confirmPayment({ + const outcome = await confirmPayment({ clientSecret: paymentAuth.clientSecret, paymentMethodId: $organization.paymentMethodId, orgId: $organization.$id, - route: `${settingsUrl}?type=confirm-addon&addonId=${paymentAuth.addonId}` + route: `${settingsUrl}?type=confirm-addon&addonId=${paymentAuth.addonId}`, + redirectIfRequired: true }); + + if (!outcome || outcome.status === 'error') { + trackError( + new Error(outcome?.status === 'error' ? outcome.message : 'Payment failed'), + Submit.BAAAddonEnable + ); + return; + } + + if (outcome.status === 'requires_action') { + return; + } + + await sdk.forConsole.organizations.confirmAddonPayment({ + organizationId: $organization.$id, + addonId: paymentAuth.addonId + }); + + await Promise.all([ + invalidate(Dependencies.ADDONS), + invalidate(Dependencies.ORGANIZATION) + ]); + + if (outcome.status === 'processing') { + addNotification({ + message: "BAA addon payment is processing — we'll activate it shortly.", + type: 'info' + }); + } else { + addNotification({ + message: 'BAA addon has been enabled', + type: 'success' + }); + } + trackEvent(Submit.BAAAddonEnable); return; } diff --git a/src/routes/(console)/organization-[organization]/settings/BAAEnableModal.svelte b/src/routes/(console)/organization-[organization]/settings/BAAEnableModal.svelte index 36881a73c..33d68f7a9 100644 --- a/src/routes/(console)/organization-[organization]/settings/BAAEnableModal.svelte +++ b/src/routes/(console)/organization-[organization]/settings/BAAEnableModal.svelte @@ -39,12 +39,49 @@ const settingsUrl = resolve('/(console)/organization-[organization]/settings', { organization: $organization.$id }); - await confirmPayment({ + const outcome = await confirmPayment({ clientSecret: paymentAuth.clientSecret, paymentMethodId: $organization.paymentMethodId, orgId: $organization.$id, - route: `${settingsUrl}?type=confirm-addon&addonId=${paymentAuth.addonId}` + route: `${settingsUrl}?type=confirm-addon&addonId=${paymentAuth.addonId}`, + redirectIfRequired: true }); + + if (!outcome || outcome.status === 'error') { + if (outcome?.status === 'error') { + error = outcome.message; + trackError(new Error(outcome.message), Submit.BAAAddonEnable); + } + return; + } + + if (outcome.status === 'requires_action') { + return; + } + + await sdk.forConsole.organizations.confirmAddonPayment({ + organizationId: $organization.$id, + addonId: paymentAuth.addonId + }); + + await Promise.all([ + invalidate(Dependencies.ADDONS), + invalidate(Dependencies.ORGANIZATION) + ]); + + if (outcome.status === 'processing') { + addNotification({ + message: "BAA addon payment is processing — we'll activate it shortly.", + type: 'info' + }); + } else { + addNotification({ + message: 'BAA addon has been enabled', + type: 'success' + }); + } + trackEvent(Submit.BAAAddonEnable); + show = false; return; } From 443153fd1a9a0d5062509e9f59c4b640ac250416 Mon Sep 17 00:00:00 2001 From: harsh mahajan Date: Thu, 7 May 2026 12:19:13 +0530 Subject: [PATCH 38/54] fix: restore free-form key/value input bindings --- .../executions/execute-function/+page.svelte | 12 +++++++----- .../messaging/create-[type]/(type)/push.svelte | 9 +++++---- .../messaging/message-[message]/pushMessage.svelte | 8 ++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/executions/execute-function/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/executions/execute-function/+page.svelte index 27e0ca094..bbefc34e7 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/executions/execute-function/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/executions/execute-function/+page.svelte @@ -211,7 +211,7 @@ {#if headers} - {#each headers as [name, value], index} + {#each headers as _, index (index)} + bind:value={headers[index][0]} + bind:search={headers[index][0]}> + bind:value={headers[index][1]}> @@ -248,7 +248,9 @@ -

- - - Critical: System is down or a critical component is non-functional, causing - a complete stoppage of work or significant business impact. - - - High: Major functionality is impaired, but a workaround is available, or a - critical component is significantly degraded. - - - Medium: Minor functionality is impaired without significant business impact. - - - Low: Issue has minor impact on business operations; workaround is not necessary. - - - Question: Requests for information, general guidance, or feature requests. - - -
- -{/snippet} -
@@ -279,17 +236,6 @@ options={projectOptions ?? []} bind:value={$supportData.project} placeholder="Select project" /> - -
- {@render severityPopover()} -
-
({ message: '', subject: '', category: 'technical', - severity: 'question', file: null }); From e608d82ddcf147f6f87a15bafc5b8ecd6bd144c3 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 8 May 2026 20:04:25 +0530 Subject: [PATCH 50/54] updated --- bun.lock | 4 ++-- package.json | 2 +- sdk-for-console | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) create mode 160000 sdk-for-console diff --git a/bun.lock b/bun.lock index df52aec61..a8194ed8e 100644 --- a/bun.lock +++ b/bun.lock @@ -6,7 +6,7 @@ "name": "@appwrite/console", "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@8f00f95", + "@appwrite.io/console": "^12.2.0", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", "@appwrite.io/pink-legacy": "^1.0.3", @@ -124,7 +124,7 @@ "@analytics/type-utils": ["@analytics/type-utils@0.6.4", "", {}, "sha512-Ou1gQxFakOWLcPnbFVsrPb8g1wLLUZYYJXDPjHkG07+5mustGs5yqACx42UAu4A6NszNN6Z5gGxhyH45zPWRxw=="], - "@appwrite.io/console": ["@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@8f00f95", { "dependencies": { "json-bigint": "1.0.0" } }], + "@appwrite.io/console": ["@appwrite.io/console@12.2.0", "", { "dependencies": { "json-bigint": "1.0.0" } }, "sha512-kv5CS/pWlSkLzG1mPctUr5fMdisZRrkOYStIvAaNPHv+bl/wFCZMMoRoiPGlBpw2NKwTddGFkkQvHq8GbxehNA=="], "@appwrite.io/pink-icons": ["@appwrite.io/pink-icons@0.25.0", "", {}, "sha512-0O3i2oEuh5mWvjO80i+X6rbzrWLJ1m5wmv2/M3a1p2PyBJsFxN8xQMTEmTn3Wl/D26SsM7SpzbdW6gmfgoVU9Q=="], diff --git a/package.json b/package.json index 0eb4abad8..71e540316 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@8f00f95", + "@appwrite.io/console": "^12.2.0", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", "@appwrite.io/pink-legacy": "^1.0.3", diff --git a/sdk-for-console b/sdk-for-console new file mode 160000 index 000000000..dcfff2a2a --- /dev/null +++ b/sdk-for-console @@ -0,0 +1 @@ +Subproject commit dcfff2a2aae16c35fac395da82b7bf6891e4d64d From 30c1ca97feecc0d0424a6bacb7377541252a68cf Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 8 May 2026 20:07:34 +0530 Subject: [PATCH 51/54] updated --- .../project-[region]-[project]/auth/settings/+page.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte b/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte index 3596e8d7e..ed70bb813 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte @@ -10,7 +10,7 @@ import { addNotification } from '$lib/stores/notifications'; import { oAuthProviders } from '$lib/stores/oauth-providers'; import { sdk } from '$lib/stores/sdk'; - import { MethodId, type Models } from '@appwrite.io/console'; + import { AuthMethod, type Models } from '@appwrite.io/console'; import { base } from '$app/paths'; import { Avatar, @@ -38,7 +38,7 @@ let isUpdatingAllAuthMethods = $state(false); let showUpdateAuthMethodsDialog = $state(false); let updateAuthMethodsEnabledMode = $state(null); - let apiAuthMethodUpdates = new SvelteSet(); + let apiAuthMethodUpdates = new SvelteSet(); const isAnyAuthMethodUpdating = $derived(apiAuthMethodUpdates.size > 0); const isAnyUpdateInProgress = $derived(isUpdatingAllAuthMethods || isAnyAuthMethodUpdating); From 91d3463e36be4175c638081e8232666ddaa4383c Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 8 May 2026 20:08:51 +0530 Subject: [PATCH 52/54] updated --- src/lib/stores/auth-methods.ts | 2 +- .../project-[region]-[project]/auth/settings/+page.svelte | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/stores/auth-methods.ts b/src/lib/stores/auth-methods.ts index 4e2c0cf78..4be9911c4 100644 --- a/src/lib/stores/auth-methods.ts +++ b/src/lib/stores/auth-methods.ts @@ -1,5 +1,5 @@ import { writable } from 'svelte/store'; -import { type Models, MethodId } from '@appwrite.io/console'; +import { type Models, AuthMethod as MethodId } from '@appwrite.io/console'; export type AuthMethod = { label: string; diff --git a/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte b/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte index ed70bb813..83b6c3e4e 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte @@ -10,7 +10,7 @@ import { addNotification } from '$lib/stores/notifications'; import { oAuthProviders } from '$lib/stores/oauth-providers'; import { sdk } from '$lib/stores/sdk'; - import { AuthMethod, type Models } from '@appwrite.io/console'; + import { AuthMethod as MethodId, type Models } from '@appwrite.io/console'; import { base } from '$app/paths'; import { Avatar, @@ -38,7 +38,7 @@ let isUpdatingAllAuthMethods = $state(false); let showUpdateAuthMethodsDialog = $state(false); let updateAuthMethodsEnabledMode = $state(null); - let apiAuthMethodUpdates = new SvelteSet(); + let apiAuthMethodUpdates = new SvelteSet(); const isAnyAuthMethodUpdating = $derived(apiAuthMethodUpdates.size > 0); const isAnyUpdateInProgress = $derived(isUpdatingAllAuthMethods || isAnyAuthMethodUpdating); From bd50bb8a89d0e6d2ca1fc79cb0073452c60c252c Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Mon, 11 May 2026 11:03:54 +0530 Subject: [PATCH 53/54] removed redundant --- sdk-for-console | 1 - 1 file changed, 1 deletion(-) delete mode 160000 sdk-for-console diff --git a/sdk-for-console b/sdk-for-console deleted file mode 160000 index dcfff2a2a..000000000 --- a/sdk-for-console +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dcfff2a2aae16c35fac395da82b7bf6891e4d64d From 8c8d2c2a7a500764fb9342938ac3e0347eaba4ec Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Mon, 11 May 2026 11:07:39 +0530 Subject: [PATCH 54/54] linting --- src/routes/(console)/supportWizard.svelte | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/routes/(console)/supportWizard.svelte b/src/routes/(console)/supportWizard.svelte index d3e4d7c0b..a56ab2183 100644 --- a/src/routes/(console)/supportWizard.svelte +++ b/src/routes/(console)/supportWizard.svelte @@ -1,23 +1,10 @@