fix: use robust instance-level monkey patch for Appwrite clients to survive Turbopack/Next.js module duplication and npm installs

This commit is contained in:
Carlos (Almeira) 2026-07-09 23:57:43 -05:00
parent cd6a91ba9a
commit 7113ba706b
2 changed files with 46 additions and 38 deletions

View File

@ -1,29 +1,30 @@
import { Client, Account, Databases } from 'node-appwrite'; import { Client, Account, Databases } from 'node-appwrite';
import { cookies } from 'next/headers'; import { cookies } from 'next/headers';
// Patch console.warn to suppress Appwrite version mismatch warning // Robust instance-level patch for Appwrite Next.js Server Components
if (typeof console !== 'undefined' && !(console as any)._appwritePatchedServer) { function patchClientInstance(client: any) {
const originalWarn = console.warn; if (client._isPatched) return client;
console.warn = (...args) => { const originalCall = client.call.bind(client);
if (args[0] && typeof args[0] === 'string' && args[0].includes('The current SDK is built for Appwrite')) { client.call = async function (...args: any[]) {
return; // Suppress Appwrite version mismatch warnings during this call
} const oldWarn = console.warn;
originalWarn(...args); console.warn = (...warnArgs: any[]) => {
if (warnArgs[0] && typeof warnArgs[0] === 'string' && warnArgs[0].includes('built for Appwrite')) return;
oldWarn(...warnArgs);
}; };
try {
// Monkey-patch Client.prototype.call to always return plain objects const res = await originalCall(...args);
const originalCall = Client.prototype.call; // Ensure all objects are fully plain JSON (strips getters/prototypes that break Server -> Client transitions)
if (originalCall) {
Client.prototype.call = async function (this: any, ...args: any[]) {
const res = await originalCall.apply(this, args);
if (res && typeof res === 'object') { if (res && typeof res === 'object') {
return JSON.parse(JSON.stringify(res)); return JSON.parse(JSON.stringify(res));
} }
return res; return res;
}; } finally {
console.warn = oldWarn;
} }
};
(console as any)._appwritePatchedServer = true; client._isPatched = true;
return client;
} }
const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1'; const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1';
@ -50,6 +51,8 @@ export async function createSessionClient() {
client.setSession(sessionCookie.value); client.setSession(sessionCookie.value);
} }
patchClientInstance(client);
return { return {
get account() { get account() {
return new Account(client); return new Account(client);
@ -66,6 +69,8 @@ export async function createAdminClient() {
.setProject(PROJECT_ID) .setProject(PROJECT_ID)
.setKey(process.env.APPWRITE_API_KEY || ''); .setKey(process.env.APPWRITE_API_KEY || '');
patchClientInstance(client);
return { return {
get account() { get account() {
return new Account(client); return new Account(client);

View File

@ -1,28 +1,29 @@
import { Client, Databases, Storage, Query, Account } from 'appwrite'; import { Client, Databases, Storage, Query, Account } from 'appwrite';
// Patch console.warn to suppress Appwrite version mismatch warning // Robust instance-level patch for Appwrite Client
if (typeof console !== 'undefined' && !(console as any)._appwritePatchedClient) { function patchClientInstance(clientInstance: any) {
const originalWarn = console.warn; if (clientInstance._isPatched) return clientInstance;
console.warn = (...args) => { const originalCall = clientInstance.call.bind(clientInstance);
if (args[0] && typeof args[0] === 'string' && args[0].includes('The current SDK is built for Appwrite')) { clientInstance.call = async function (...args: any[]) {
return; // Suppress Appwrite version mismatch warnings during this call
} const oldWarn = console.warn;
originalWarn(...args); console.warn = (...warnArgs: any[]) => {
if (warnArgs[0] && typeof warnArgs[0] === 'string' && warnArgs[0].includes('built for Appwrite')) return;
oldWarn(...warnArgs);
}; };
try {
// Monkey-patch Client.prototype.call to always return plain objects const res = await originalCall(...args);
const originalCall = Client.prototype.call; // Ensure all objects are fully plain JSON (strips getters/prototypes that break Server -> Client transitions)
if (originalCall) {
Client.prototype.call = async function (this: any, ...args: any[]) {
const res = await originalCall.apply(this, args);
if (res && typeof res === 'object') { if (res && typeof res === 'object') {
return JSON.parse(JSON.stringify(res)); return JSON.parse(JSON.stringify(res));
} }
return res; return res;
}; } finally {
console.warn = oldWarn;
} }
};
(console as any)._appwritePatchedClient = true; clientInstance._isPatched = true;
return clientInstance;
} }
const client = new Client(); const client = new Client();
@ -35,6 +36,8 @@ client
.setEndpoint(endpoint) .setEndpoint(endpoint)
.setProject(projectId); .setProject(projectId);
patchClientInstance(client);
export const databases = new Databases(client); export const databases = new Databases(client);
export const storage = new Storage(client); export const storage = new Storage(client);
export const account = new Account(client); export const account = new Account(client);