feat: Isomorphic SDKs#1512
Open
ChiragAgg5k wants to merge 79 commits into
Open
Conversation
Adds a ServerClient sibling class to the web SDK alongside the existing Client. Service classes are generic over `Client | ServerClient` when they have any client-tier methods, with TypeScript `this`-types gating admin methods (e.g. `Databases.createCollection` requires `Databases<ServerClient>`). Services with no client-tier methods (Health, Tokens, Sites, Users) are non-generic and require a ServerClient at construction. Tier detection is driven entirely off existing `x-appwrite.platforms` spec tags. The existing Client surface is unchanged — purely additive for current `appwrite` web users; sets up the path to consolidate `appwrite` + `node-appwrite` into a single isomorphic package. - Filter `Key` out of Client header iterations so Client cannot setKey - Add server-client.ts.twig (setKey/setJWT/setLocale + HTTP plumbing, no realtime, no session/devkey/impersonate) - Type-gate service methods via `this: Service<ServerClient>` (or `<Client>` for the few client-only methods like webAuth/location) - Re-export ServerClient from index.ts - Register the new template in Web.php getFiles() Verified on regenerated examples/web/: tsc --noEmit passes; negative tests confirm `new Health(browserClient)` and admin calls on a Client-bound service fail to type-check; djlint passes.
- Rename fromApiKey -> fromAPIKey for naming consistency - Make all setters private; expose only static factory methods - Guard window access with typeof window !== 'undefined' in realtime - Gate fromAPIKey behind server/console platform builds only - Normalize ClientRuntime to 'client' | 'server'; remove 'browser' - Add withJWT and withForwardedUserAgent builder methods - Fix clearTimeout misuse on interval handles
Moves the service-level auth tier detection and per-method this-gate construction from template.ts.twig set blocks into PHP helpers exposed as Twig filters (webServiceAuth, webMethodThisGate). This makes the template easier to read while keeping generated output identical.
- Rename ClientRuntime -> SDKPlatform and field runtime -> sdkPlatform - Remove ConsoleAuth type; merge cookie auth into ServerAuth (covers both console and SSR cookie-forwarding use cases) - Emit fromCookie on all platforms instead of console-only - Default mode: 'admin' in fromCookie on console builds so the wire request authenticates as admin without requiring callers to remember the X-Appwrite-Mode header - Add Prettify utility type and wrap factory params so IDE hover shows the full parameter shape instead of an opaque alias name - Simplify Web.php helpers (webServiceAuth, webMethodThisGate) by removing the platform argument now that ServerAuth covers all server-tier cases
- Wrap fromJWT in a platform guard mirroring fromAPIKey. JWT auth lives in ServerAuth, so emitting fromJWT on client builds produced a dead factory: the returned Client<'jwt'> could not satisfy any service generated from the client spec (which only carry ClientAuth). - Add selfSigned?: boolean to BaseClientParams and apply it inside applyBase so every factory gets a public migration path. Previously setSelfSigned was the only way to set the flag and was made private by the factory refactor, leaving callers without a public hook.
Replaces the hardcoded config block and ten manually-written auth setters with a single spec.global.headers loop, matching the pattern every other SDK template uses (Python, Dart, Kotlin, etc.). Setters become primitive: header write + config write + return this. The redundant sdkPlatform / x-sdk-platform writes are removed because applyBase already sets both before the setter runs, and the setters are private — only callable from inside factories. Dropping the duplication also lets the typed Client<'apiKey'> etc. flow through chained calls without `as unknown as Client<...>` casts. Each platform spec carries a different subset of securityDefinitions, so a Web.php Twig filter (webClientHeaders) augments the parsed list with auth headers the unified client needs but the loaded spec omits (e.g. Session/DevKey on console, Cookie on client). The filter has a TODO pointing at appwrite/appwrite#12211, which moves the union into each platform spec's securityDefinitions directly. Once that ships and specs regenerate, the filter and its registration can be deleted in a follow-up. Verified against console, client, and server builds plus an end-to-end smoke test calling Account.get() through fromCookie on Appwrite Cloud.
The server platform spec includes ForwardedUserAgent in securityDefinitions, so the new spec.global.headers loop generates a config field and setForwardedUserAgent setter for it on server builds. That collided with the manual versions left over in the template, producing TS2300/TS1117/TS2393 duplicate-identifier errors when running tsc --declaration in the web (server) CI job. Add ForwardedUserAgent to webClientHeaders so it is universally present across all platform builds (the unified web client always exposes withForwardedUserAgent for chained user-agent forwarding) and remove the manual config field and setter from the template. The loop now owns it on every build target. Verified npm run build:types passes for web (server), web (console), and web (client) on a clean examples/web tree.
…-server-client # Conflicts: # templates/web/src/client.ts.twig
abnegate
reviewed
May 11, 2026
abnegate
reviewed
May 12, 2026
- Inline fromClient into from; call from() directly in other factory methods - Remove callInternal wrapper; keep request logic in call() - Remove chunkedUploadInternal wrapper; keep upload logic in chunkedUpload() - Remove applySelfSigned wrapper; init calls setSelfSigned() directly - Omit explicit converter = null where parameter already defaults to null - Make Service.client a protected property so subclasses inherit it - Remove redundant private val client from Realtime and generated service constructors
# Conflicts: # templates/android/library/src/main/java/io/package/services/Realtime.kt.twig # tests/Android14Java11Test.php # tests/Android14Java8Test.php # tests/KotlinJava11Test.php # tests/KotlinJava8Test.php
abnegate
reviewed
May 14, 2026
# Conflicts: # templates/flutter/lib/src/realtime_io.dart.twig # templates/flutter/lib/src/realtime_mixin.dart.twig # tests/languages/flutter/tests.dart
3 tasks
…o URLs - Fix bare new Client() defaulting to server platform; default to 'client' so browser consumers keep credentials: 'include', X-Fallback-Cookies, and correct x-sdk-platform header. - Stop injecting client.config auth values (session, key, jwt, cookie, devkey) into location/webAuth URL query strings. - For server-only location methods (e.g. getDeploymentDownload), match Node SDK behavior by returning Promise<ArrayBuffer> via authenticated client.call() instead of returning a credential-bearing URL string. - Client/mixed location methods (avatars, storage previews) still return URL strings but without auth credentials in query params.
Re-add safe config headers (project, locale, mode, platform) to location/webAuth URL query strings so that <img src> and other header-less contexts remain self-contained. Credential-like headers (session, key, jwt, cookie, devkey, impersonation) are still excluded. Server-only location methods (e.g. getDeploymentDownload) continue to return Promise<ArrayBuffer> via authenticated client.call() and do not inject project into the URL, matching sdk-for-node behavior.
Resolved conflicts: - templates/web/src/client.ts.twig: Adopted concurrent chunked upload from master, kept ClientRuntime.CHUNK_SIZE references consistent. - templates/kotlin/src/main/kotlin/io/appwrite/Client.kt.twig: Kept auth factory methods and added MAX_CONCURRENT_UPLOADS from master.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the isomorphic SDK client/auth factory pattern across the generated SDKs. The branch now covers the Web SDK, Flutter, Apple, Android, server SDK variants, and React Native, while preserving the existing
Client()constructor and setter setup path for backwards compatibility.This consolidates the work from #1481, #1510, and #1511, extends the pattern to Android, and adds matching server-side factory coverage for the generated Node, Dart, Swift, and Kotlin SDKs.
Web SDK
The generated Web SDK now uses one typed generic
Clientacross browser, server, and console output. Static factories describe both runtime and auth capability, and generated services narrow their available methods from the client auth type.Available Web factories are
from,fromSession,fromDevKey, andfromImpersonationfor client auth. Server and console output also exposefromAPIKey,fromCookie, andfromJWT. Console cookie factories force admin mode.Flutter SDK
The generated Flutter client SDK now exposes a
ClientAuthinterface returned by factory-created clients. Services and Realtime acceptClientAuth, so construction stays the same while legacy setters are hidden from factory-created clients.Available Flutter factories are
from,fromSession,fromDevKey, andfromImpersonation. Factories validate endpoint schemes, mirror auth values into config, and store lowercase aliases for generated config lookups.Apple SDK
The generated Apple SDK now exposes a
ClientAuthprotocol returned by factory-created clients. Generated services and Realtime acceptClientAuth, and services read auth values throughgetConfig(key:)instead of exposing the raw config dictionary.Available Apple factories are
from,fromSession,fromDevKey, and throwingfromImpersonation. All factories accept optional endpoint, realtime endpoint, locale, self-signed, and compression values.fromImpersonationthrows anAppwriteErrorwhen callers pass zero or multiple impersonation targets.Android SDK
The generated Android SDK now exposes concrete
Clientfactories for Android/Kotlin/Java ergonomics. Generated services and Realtime continue to acceptClient, while factories apply the same project, auth header, config, endpoint validation, realtime endpoint, locale, and self-signed setup.Available Android factories are
from,fromSession,fromDevKey, andfromImpersonation.fromImpersonationvalidates that exactly one ofuserId,userEmail, oruserPhoneis provided, and factory auth values are mirrored intoclient.configwith the key aliases used by generated services.Server SDK Variants
Generated Node, Dart, Swift, and Kotlin server SDKs now expose the same factory family for server auth flows:
from,fromSession,fromAPIKey,fromCookie,fromJWT,fromDevKey, andfromImpersonation. React Native exposes the client-safe subset:from,fromSession,fromDevKey, andfromImpersonation.Backwards Compatibility
Existing constructor/setter setup remains supported in all affected SDKs:
Legacy setters are marked deprecated where the generated language surface supports that distinction, but remain available from direct
Client()instances.Implementation Notes
fromacross SDKs..clientinternals from the public generated service surface where supported by the SDK language.Validation
Previously run on the consolidated branch:
php example.php web server php example.php web client php example.php web console php example.php flutter client php example.php apple client php example.php android client composer lint-twig php -l src/SDK/Language/Web.php php -l src/SDK/Language/Flutter.php php -l src/SDK/Language/Apple.php git diff --check origin/master...HEAD sh ./gradlew :library:compileDebugKotlin # from examples/androidAndroid compilation succeeded after Gradle fell back from the Kotlin daemon. The daemon failed locally because the installed Java version reports as
25.0.2; the non-daemon compiler completed successfully with existing generated-code warnings.