Unify web SDK Client auth factories#1481
Conversation
Greptile SummaryThis PR unifies the Web SDK into a single generic
Confidence Score: 4/5The core factory and type-alias machinery works correctly; outstanding open threads around jwt/ClientAuth classification, setter copy-vs-mutate semantics, and fromCookie platform guard should be resolved before merging. The new Omit-based auth-tier enforcement is functionally sound and the window/Node.js guards are a genuine improvement. However, unresolved threads from prior rounds — jwt placed in ServerAuth making it unusable in browser service constructors, setKey/setSession/setDevKey copy-returning semantics silently breaking the documented legacy imperative style, and fromCookie emitted unconditionally in server builds — represent real mismatches between the documented API and the generated output. templates/web/src/client.ts.twig deserves the most attention for the jwt/ServerAuth placement, setter copy-vs-mutate behaviour, and unguarded fromCookie. src/SDK/Language/Web.php contains the unused webMethodThisGate helper that should be removed. Important Files Changed
Reviews (30): Last reviewed commit: "Update web test auth headers fixture" | Re-trigger Greptile |
31090ee to
2e8c91b
Compare
8d88082 to
5d5bfba
Compare
5d5bfba to
6d4e4fa
Compare
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.
d8a6359 to
071a493
Compare
- 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
|
Superseded by #1511, which now consolidates the Web, Flutter, and Apple isomorphic SDK changes. |
Summary
Refactors the generated Web SDK so browser, server, and console usage share one typed
Clientclass with explicit static auth factories. The factories describe both runtime behavior and auth capability while preserving the existing constructor/setter style for compatibility.The recommended browser setup is now:
The old syntax is still supported:
Those legacy
set*methods are now marked@deprecatedand are only visible fromnew Client(). Factory-created clients do not expose legacy setters.Auth Factories
All factories take object params. Common fields include
endpoint,projectId,endpointRealtime,locale, andselfSigned. Spec-backed base params such asprojectId,locale,mode, andplatformare generated fromspec.global.headersvia Web language filters instead of hardcoded template branches.Available factories:
Client.fromBrowser(...)Client.fromSession(...)X-Appwrite-Session; useful when a session secret is explicitly available.Client.fromDevKey(...)Client.fromImpersonation(...)sessionand exactly one ofuserId,email, orphone.Client.fromAPIKey(...)Client.fromJWT(...)X-Appwrite-JWT. Not emitted for client-platform builds.Client.fromCookie(...)modetoadmin.Type Safety
The generated client is generic over auth capability:
Generated services use those capabilities directly:
Client<ClientAuth>.Client<ServerAuth>.new Service(client)syntax while omitting methods that are not valid for the provided client auth tier..clientinternals are hidden from the public service type.Examples:
Factory-created clients also hide internal helpers such as
withJWT,withForwardedUserAgent,CHUNK_SIZE, andflatten. JavaScript function properties such asapplyandargumentsremain inherent to the constructableClientvalue.Factory parameter types are wrapped with
Prettify<T>so IDE hover displays the expanded object shape instead of opaque aliases.Implementation Details
templates/web/src/client.ts.twigClient, staticfrom*factories, hidden public factory surfaces, deprecated legacy setters, and spec-driven base factory params.src/SDK/Language/Web.phpwebClientHeadersspec workaround.templates/web/src/services/template.ts.twignew Service(client)syntax while hiding invalid methods and service.clientfrom public types.templates/web/src/services/realtime.ts.twigtemplates/web/src/index.ts.twigexample.phpCompatibility Notes
new Client().setEndpoint(...).setProject(...).setKey(...)still works.Client.fromBrowser(...),Client.fromAPIKey(...), or other factory-created clients.with*helpers are not visible on either factory-created clients or legacynew Client()results.Client.Validation
Recent validation performed on this branch:
php example.php web serverphp example.php web clientphp example.php web consolenew Client()with*helpers hiddenCHUNK_SIZEandflattenhiddenFunctions.deleteandTablesDB.createBooleanColumn.clienthidden from public service typesfromAPIKeyandfromJWTmodeandplatformparamstscon final generatedexamples/web/src/client.tscomposer lint-twigphp -l src/SDK/Language/Web.phpgit diff --check