Skip to content

Unify web SDK Client auth factories#1481

Closed
ChiragAgg5k wants to merge 34 commits intomasterfrom
feat/web-isomorphic-server-client
Closed

Unify web SDK Client auth factories#1481
ChiragAgg5k wants to merge 34 commits intomasterfrom
feat/web-isomorphic-server-client

Conversation

@ChiragAgg5k
Copy link
Copy Markdown
Member

@ChiragAgg5k ChiragAgg5k commented Apr 27, 2026

Summary

Refactors the generated Web SDK so browser, server, and console usage share one typed Client class 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:

import { Client, Account } from 'appwrite';

const client = Client.fromBrowser({
  endpoint: 'https://<REGION>.cloud.appwrite.io/v1',
  projectId: '<PROJECT_ID>',
});

const account = new Account(client);

The old syntax is still supported:

const client = new Client()
  .setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
  .setProject('<PROJECT_ID>')
  .setKey('<API_KEY>');

Those legacy set* methods are now marked @deprecated and are only visible from new Client(). Factory-created clients do not expose legacy setters.

Auth Factories

All factories take object params. Common fields include endpoint, projectId, endpointRealtime, locale, and selfSigned. Spec-backed base params such as projectId, locale, mode, and platform are generated from spec.global.headers via Web language filters instead of hardcoded template branches.

Available factories:

Factory Auth/runtime Notes
Client.fromBrowser(...) browser/client Normal browser apps; cookies may authenticate the current user automatically.
Client.fromSession(...) session/client Sends X-Appwrite-Session; useful when a session secret is explicitly available.
Client.fromDevKey(...) dev key/client Client-tier dev key usage.
Client.fromImpersonation(...) impersonation/client Requires session and exactly one of userId, email, or phone.
Client.fromAPIKey(...) API key/server Trusted server-side code only. Not emitted for client-platform builds.
Client.fromJWT(...) JWT/server Trusted server-side code using X-Appwrite-JWT. Not emitted for client-platform builds.
Client.fromCookie(...) cookie/server For SSR cookie forwarding and console runtime. Console builds default mode to admin.

Type Safety

The generated client is generic over auth capability:

type ClientAuth = 'browser' | 'session' | 'devKey' | 'impersonation';
type ServerAuth = 'apiKey' | 'jwt' | 'cookie';
type Auth = ClientAuth | ServerAuth;

Generated services use those capabilities directly:

  • Client/browser-only services require Client<ClientAuth>.
  • Server-only services require Client<ServerAuth>.
  • Mixed services preserve the existing new Service(client) syntax while omitting methods that are not valid for the provided client auth tier.
  • Service .client internals are hidden from the public service type.
  • Realtime accepts browser-capable clients in the Web SDK.

Examples:

const browserClient = Client.fromBrowser({ endpoint, projectId });
const serverClient = Client.fromAPIKey({ endpoint, projectId, apiKey });

new TablesDB(browserClient).createBooleanColumn; // Type error
new TablesDB(serverClient).createBooleanColumn;  // OK

new Functions(browserClient).delete; // Type error
new Functions(serverClient).delete;  // OK

Factory-created clients also hide internal helpers such as withJWT, withForwardedUserAgent, CHUNK_SIZE, and flatten. JavaScript function properties such as apply and arguments remain inherent to the constructable Client value.

Factory parameter types are wrapped with Prettify<T> so IDE hover displays the expanded object shape instead of opaque aliases.

Implementation Details

File Change
templates/web/src/client.ts.twig Generates one generic Client, static from* factories, hidden public factory surfaces, deprecated legacy setters, and spec-driven base factory params.
src/SDK/Language/Web.php Provides Web-specific filters for service auth typing, base client params, and setter return types. Removes the old webClientHeaders spec workaround.
templates/web/src/services/template.ts.twig Preserves new Service(client) syntax while hiding invalid methods and service .client from public types.
templates/web/src/services/realtime.ts.twig Narrows Realtime to browser-capable Web clients.
templates/web/src/index.ts.twig Re-exports the Web client auth capability types.
example.php Cleans generated examples before regeneration to avoid stale files from previous platform renders.

Compatibility Notes

  • new Client().setEndpoint(...).setProject(...).setKey(...) still works.
  • Legacy setters are deprecated to guide new code toward static factories.
  • Legacy setters are intentionally not visible on Client.fromBrowser(...), Client.fromAPIKey(...), or other factory-created clients.
  • Internal with* helpers are not visible on either factory-created clients or legacy new Client() results.
  • Old standalone server-client output has been removed in favor of the unified generic Web Client.

Validation

Recent validation performed on this branch:

  • php example.php web server
  • php example.php web client
  • php example.php web console
  • TypeScript smoke tests for server/client/console generated Web outputs covering:
    • legacy setters still supported on new Client()
    • legacy setters hidden from factory clients
    • internal with* helpers hidden
    • static internals such as CHUNK_SIZE and flatten hidden
    • browser clients reject server-only methods such as Functions.delete and TablesDB.createBooleanColumn
    • server clients accept those server-only methods
    • service .client hidden from public service types
    • client-platform output omits fromAPIKey and fromJWT
    • console-platform output accepts spec-driven mode and platform params
  • tsc on final generated examples/web/src/client.ts
  • composer lint-twig
  • php -l src/SDK/Language/Web.php
  • git diff --check

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 27, 2026

Greptile Summary

This PR unifies the Web SDK into a single generic ClientRuntime<TAuth> class with static auth factories (fromBrowser, fromSession, fromAPIKey, fromCookie, fromJWT, fromDevKey, fromImpersonation) and exposes it as a cast Client constructor. Service templates are updated to use Omit-based type aliases that enforce auth-tier constraints at compile time.

  • ClientRuntime replaces the original Client class; the public Client surface is a ClientConstructor type cast that hides legacy setters and internal helpers from factory-created instances.
  • template.ts.twig computes per-service auth flags via the new webServiceAuth PHP filter and generates Omit-based type aliases to restrict server-only or client-only methods on mixed-tier services.
  • realtime.ts.twig is narrowed to accept Client<ClientAuth> for the Web SDK, and window/setInterval usages are guarded for Node.js compatibility.

Confidence Score: 4/5

The 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

Filename Overview
templates/web/src/client.ts.twig Major refactor introducing generic ClientRuntime, static auth factories, and type aliases. Several previously noted issues around runtime/platform mutation, JWT classification, and missing guards remain open.
templates/web/src/services/template.ts.twig Refactored to Omit-based type aliases for auth-tier enforcement; thisGate placeholder is always empty (dead code path), but functional correctness is preserved by the Omit approach.
src/SDK/Language/Web.php Adds webServiceAuth, webClientBaseParams, webClientSetterReturnType helpers and Twig filters; webMethodThisGate is registered but unused.
templates/web/src/services/realtime.ts.twig Narrows Realtime constructor to Client for Web SDK and guards window/setInterval usage for Node.js compatibility.
templates/web/src/index.ts.twig Re-exports new SDKPlatform, ClientAuth, ServerAuth types alongside existing exports; minor newline fix.
.github/workflows/sdk-build-validation.yml Adds web/server to the CI matrix; web/client platform generation path remains untested in CI (noted in prior review).
tests/resources/spec.json Adds Cookie, DevKey, and three Impersonate* global headers to support new factory methods in the test spec.

Reviews (30): Last reviewed commit: "Update web test auth headers fixture" | Re-trigger Greptile

Comment thread templates/web/src/server-client.ts.twig Outdated
Comment thread templates/web/src/services/template.ts.twig Outdated
Comment thread templates/web/src/server-client.ts.twig Outdated
@ChiragAgg5k ChiragAgg5k force-pushed the feat/web-isomorphic-server-client branch from 31090ee to 2e8c91b Compare April 29, 2026 09:43
Comment thread templates/web/src/services/template.ts.twig Outdated
@ChiragAgg5k ChiragAgg5k force-pushed the feat/web-isomorphic-server-client branch 5 times, most recently from 8d88082 to 5d5bfba Compare April 29, 2026 10:44
Comment thread templates/web/src/server-client.ts.twig Outdated
@ChiragAgg5k ChiragAgg5k force-pushed the feat/web-isomorphic-server-client branch from 5d5bfba to 6d4e4fa Compare April 29, 2026 10:54
Comment thread templates/web/src/services/template.ts.twig Outdated
Comment thread templates/web/src/services/template.ts.twig Outdated
@ChiragAgg5k ChiragAgg5k changed the title Add ServerClient to web SDK with type-gated admin methods Unify web SDK Client auth factories Apr 30, 2026
Comment thread templates/web/src/client.ts.twig Outdated
Comment thread templates/web/src/client.ts.twig Outdated
Comment thread templates/web/src/client.ts.twig Outdated
Comment thread templates/web/src/client.ts.twig Outdated
Comment thread templates/web/src/services/template.ts.twig Outdated
Comment thread templates/web/src/services/template.ts.twig Outdated
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.
@ChiragAgg5k ChiragAgg5k force-pushed the feat/web-isomorphic-server-client branch from d8a6359 to 071a493 Compare April 30, 2026 11:49
Comment thread templates/web/src/client.ts.twig Outdated
Comment thread templates/web/src/client.ts.twig Outdated
Comment thread templates/web/src/client.ts.twig
Comment thread templates/web/src/client.ts.twig Outdated
- 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
Comment thread templates/web/src/client.ts.twig Outdated
Comment thread templates/web/src/client.ts.twig Outdated
Comment thread templates/web/src/client.ts.twig Outdated
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.
Comment thread templates/web/src/client.ts.twig Outdated
Comment thread templates/web/src/client.ts.twig Outdated
- 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
Comment thread templates/web/src/client.ts.twig Outdated
- 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.
ChiragAgg5k added 11 commits May 4, 2026 17:01
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
@ChiragAgg5k
Copy link
Copy Markdown
Member Author

Superseded by #1511, which now consolidates the Web, Flutter, and Apple isomorphic SDK changes.

@ChiragAgg5k ChiragAgg5k closed this May 7, 2026
This was referenced May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant