Skip to content

feat: SDK update for version 18.0.0 - #114

Merged
lohanidamodar merged 15 commits into
mainfrom
dev
Sep 27, 2026
Merged

lohanidamodar merged 15 commits into
mainfrom
dev

Conversation

@lohanidamodar

@lohanidamodar lohanidamodar commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

This PR contains updates to the SDK for version 18.0.0.

What's Changed

  • Breaking: SDK now targets Appwrite 2.3 (X-Appwrite-Response-Format: 2.3.0)
  • Breaking: removed Organizations.getEstimation
  • Breaking: QuerySuggestionResource.AppwritePushLedger renamed to PushLedger
  • Added: Manager.updateOrganizationStatus to block and unblock an organization
  • Added: Push service over MQTT with Topic, plus Client.setPushEndpoint and Client.setPushClientId
  • Added: Growth service with createConversation, createInstallation, ConversationType enum and GrowthConversation model
  • Added: Account.createRecoveryOTP and Account.updateRecoveryOTP for code-based password recovery
  • Added: prompt parameter on Project.updateOAuth2* for Auth0, Discord, GitHub, Kakao, Microsoft, Okta, Salesforce, Zoho
  • Added: matching prompt fields and enums on the OAuth2* provider models
  • Added: replyToName and replyToEmail on Messaging.createEmail and Messaging.updateEmail
  • Added: organizationUrl on the Installation model
  • Added: ProjectEmailTemplateId.OtpRecovery and Deno 1.21, 1.24, 1.35 in Runtime and BuildRuntime
  • Updated: Databases.getAttribute return type now includes bigint, spatial, varchar and text attributes
  • Updated: added mqtt and buffer dependencies and browser Node polyfills for Push
  • Fixed: chunked uploads without a file in the payload now send a regular request

ChiragAgg5k and others added 14 commits July 28, 2026 17:05
main received 15.7.0 as a squash merge (#108), so the same change exists
under a different commit on each branch. main's tree is identical to dev's
15.7.0 commit, so dev's generated 15.8.0 tree is kept as-is.
main carries only the squashed 16.0.0 release commit, whose tree the generator has since superseded — the doc text in `account.ts`, the formatting of `rollup.config.mjs` and the two `dist/*/package.json` files all differ from what `sdks` now emits. Keeping the generated tree verbatim means the next generation produces no spurious diff.
@lohanidamodar lohanidamodar changed the title feat: Console SDK update for version 18.0.0 feat: SDK update for version 18.0.0 Sep 27, 2026
@greptile-apps

greptile-apps Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 0/5

[High risk] SDK version bump with new services and breaking API changes.

The PR is not safe to merge until the Push credential, identity, replay, and lifecycle defects and the Growth and positional-call regressions are addressed.

Fix All in Claude CodeFindings

  1. P1 Conversation attributes are corrupted ▶
  2. P1 Push connections displace each other ▶
  3. P1 Offline replay is not retained ▶
  4. P1 Push keeps the previous identity ▶
  5. P1 Concurrent subscriptions bypass connection ▶
  6. P1 Positional email arguments shift ▶
  7. P1 Security Push credentials use cleartext ▶
  8. P2 Overlapping filters duplicate callbacks ▶
Fix with agent prompt
### Issue 1
src/services/growth.ts:192-193
When `createConversation` receives an `attributes` object, the multipart encoder turns it into the string `"[object Object]"`. This happens with or without an attachment, so the API receives corrupted attributes instead of the values the caller supplied.

### Issue 2
src/services/push.ts:508-513
If the same user opens two tabs, both Push connections use the user ID as their MQTT client ID. The second connection takes over the first one's broker session, and automatic reconnection makes the tabs repeatedly disconnect each other instead of maintaining both subscriptions.

### Issue 3
src/services/push.ts:515-527
With MQTT 5, `clean: false` alone does not keep a broker session after disconnection: the session-expiry interval defaults to zero. Because these connection options do not set one, QoS-1 messages missed during a reload or outage cannot be replayed as `retry` promises.

### Issue 4
src/services/push.ts:489-501
If an application changes the client's JWT, session, or project after login or logout, Push reuses the MQTT connection created with the previous values. It can keep delivering subscriptions under the old identity, while new subscriptions do not connect under the newly configured identity or project until Push is closed.

### Issue 5
src/services/push.ts:452-457
If a second `subscribe()` starts before the first connection receives CONNACK, `this.mqtt` is already set and the second call skips the in-flight connection promise. It can subscribe on a client that has not connected; if the first connection fails, its cleanup also clears the second call's subscription state.

### Issue 6
src/services/messaging.ts:503-506
An existing positional `updateEmail` call that passes `scheduledAt` still type-checks, but this mapping now sends that string as `replyToEmail` and omits the scheduled time. The added arguments also break existing positional calls that pass `draft` to `createEmail` or `enabled` to the changed OAuth methods.

### Issue 7
src/client.ts:500-507
If a caller sets a `ws://` Push endpoint, or derives one from a supported `http://` API endpoint, Push sends the full JWT or session secret in MQTT CONNECT authentication data over that unencrypted connection. This exposes the credential in transit.

**How this was verified:** The allowed cleartext endpoint reaches `mqtt.connect` with the raw credential in CONNECT `authenticationData`.

### Issue 8
src/services/push.ts:639-641
When one `subscribe()` call supplies overlapping filters such as `users/123/#` and `users/123/alerts`, each filter registers the same callback. A message matching both invokes it twice, which can duplicate notification handling or other side effects.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Updates the Console SDK to Appwrite 2.3, adding Push, Growth, recovery OTPs, provider prompts, and other service and model changes. The new Push transport and conversation upload path need corrections before release.

  • Expands public services, enums, models, and examples.
  • Changes multipart fallback and browser bundling for the new services.

Reviews (1) · Last reviewed commit: "chore: merge main into dev for the 18.0...."

Comment thread src/services/growth.ts
Comment on lines +192 to +193
if (typeof attributes !== 'undefined') {
payload['attributes'] = attributes;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Conversation attributes are corrupted When createConversation receives an attributes object, the multipart encoder turns it into the string "[object Object]". This happens with or without an attachment, so the API receives corrupted attributes instead of the values the caller supplied.

Knowledge Base Used: Client configuration and HTTP transport

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/services/growth.ts
Line: 192-193

Comment:
**Conversation attributes are corrupted** When `createConversation` receives an `attributes` object, the multipart encoder turns it into the string `"[object Object]"`. This happens with or without an attachment, so the API receives corrupted attributes instead of the values the caller supplied.

**Knowledge Base Used:** [Client configuration and HTTP transport](https://app.greptile.com/appwrite/-/custom-context/knowledge-base/appwrite/sdk-for-console/-/docs/sdk-client-and-transport.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

Comment thread src/services/push.ts
Comment on lines +508 to +513
const clientId =
this.client.config.pushClientId ||
(authMethod === 'appwrite-jwt'
? userIdFromJwt(credential)
: userIdFromSession(credential)) ||
this.fallbackClientId;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Push connections displace each other If the same user opens two tabs, both Push connections use the user ID as their MQTT client ID. The second connection takes over the first one's broker session, and automatic reconnection makes the tabs repeatedly disconnect each other instead of maintaining both subscriptions.

Knowledge Base Used: Networking, realtime, and security

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/services/push.ts
Line: 508-513

Comment:
**Push connections displace each other** If the same user opens two tabs, both Push connections use the user ID as their MQTT client ID. The second connection takes over the first one's broker session, and automatic reconnection makes the tabs repeatedly disconnect each other instead of maintaining both subscriptions.

**Knowledge Base Used:** [Networking, realtime, and security](https://app.greptile.com/appwrite/-/custom-context/knowledge-base/appwrite/sdk-for-console/-/docs/networking-realtime-and-security.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

Comment thread src/services/push.ts
Comment on lines +515 to +527
const options: IClientOptions = {
clientId,
protocolVersion: 5,
clean: false, // always keep the session so the broker can replay QoS-1 topics
keepalive: KEEP_ALIVE_SECONDS,
reconnectPeriod: RECONNECT_PERIOD_MS,
manualConnect: true,
// Enhanced auth carried in CONNECT properties.
properties: {
authenticationMethod: authMethod,
authenticationData: Buffer.from(credential),
userProperties: { projectId: project },
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Offline replay is not retained With MQTT 5, clean: false alone does not keep a broker session after disconnection: the session-expiry interval defaults to zero. Because these connection options do not set one, QoS-1 messages missed during a reload or outage cannot be replayed as retry promises.

Knowledge Base Used: Integrations and communications

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/services/push.ts
Line: 515-527

Comment:
**Offline replay is not retained** With MQTT 5, `clean: false` alone does not keep a broker session after disconnection: the session-expiry interval defaults to zero. Because these connection options do not set one, QoS-1 messages missed during a reload or outage cannot be replayed as `retry` promises.

**Knowledge Base Used:** [Integrations and communications](https://app.greptile.com/appwrite/-/custom-context/knowledge-base/appwrite/sdk-for-console/-/docs/integrations-and-communications.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

Comment thread src/services/push.ts
Comment on lines +489 to +501
if (this.client.config.jwt) {
authMethod = 'appwrite-jwt';
credential = this.client.config.jwt;
} else if (this.client.config.session) {
authMethod = 'appwrite-session';
credential = this.client.config.session;
} else {
throw new Error(
'No credential set on the client; call Client.setJWT() or Client.setSession() first.',
);
}

const project = this.client.config.project ?? '';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Push keeps the previous identity If an application changes the client's JWT, session, or project after login or logout, Push reuses the MQTT connection created with the previous values. It can keep delivering subscriptions under the old identity, while new subscriptions do not connect under the newly configured identity or project until Push is closed.

Knowledge Base Used: Client configuration and HTTP transport

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/services/push.ts
Line: 489-501

Comment:
**Push keeps the previous identity** If an application changes the client's JWT, session, or project after login or logout, Push reuses the MQTT connection created with the previous values. It can keep delivering subscriptions under the old identity, while new subscriptions do not connect under the newly configured identity or project until Push is closed.

**Knowledge Base Used:** [Client configuration and HTTP transport](https://app.greptile.com/appwrite/-/custom-context/knowledge-base/appwrite/sdk-for-console/-/docs/sdk-client-and-transport.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

Comment thread src/services/push.ts
Comment on lines +452 to +457
private connect(): Promise<MqttClient> {
if (this.mqtt) {
return Promise.resolve(this.mqtt);
}
if (!this.connecting) {
this.connecting = this.open();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Concurrent subscriptions bypass connection If a second subscribe() starts before the first connection receives CONNACK, this.mqtt is already set and the second call skips the in-flight connection promise. It can subscribe on a client that has not connected; if the first connection fails, its cleanup also clears the second call's subscription state.

Knowledge Base Used: Networking, realtime, and security

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/services/push.ts
Line: 452-457

Comment:
**Concurrent subscriptions bypass connection** If a second `subscribe()` starts before the first connection receives CONNACK, `this.mqtt` is already set and the second call skips the in-flight connection promise. It can subscribe on a client that has not connected; if the first connection fails, its cleanup also clears the second call's subscription state.

**Knowledge Base Used:** [Networking, realtime, and security](https://app.greptile.com/appwrite/-/custom-context/knowledge-base/appwrite/sdk-for-console/-/docs/networking-realtime-and-security.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

Comment thread src/services/messaging.ts
Comment on lines +503 to +506
replyToEmail: rest[9] as string,
replyToName: rest[10] as string,
scheduledAt: rest[11] as string,
attachments: rest[12] as string[],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Positional email arguments shift An existing positional updateEmail call that passes scheduledAt still type-checks, but this mapping now sends that string as replyToEmail and omits the scheduled time. The added arguments also break existing positional calls that pass draft to createEmail or enabled to the changed OAuth methods.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/services/messaging.ts
Line: 503-506

Comment:
**Positional email arguments shift** An existing positional `updateEmail` call that passes `scheduledAt` still type-checks, but this mapping now sends that string as `replyToEmail` and omits the scheduled time. The added arguments also break existing positional calls that pass `draft` to `createEmail` or `enabled` to the changed OAuth methods.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

Comment thread src/client.ts
Comment on lines +500 to +507
if (
!endpointPush.startsWith('ws://') &&
!endpointPush.startsWith('wss://')
) {
throw new AppwriteException(
'Invalid push endpoint URL: ' + endpointPush,
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Push credentials use cleartext If a caller sets a ws:// Push endpoint, or derives one from a supported http:// API endpoint, Push sends the full JWT or session secret in MQTT CONNECT authentication data over that unencrypted connection. This exposes the credential in transit.

How this was verified: The allowed cleartext endpoint reaches mqtt.connect with the raw credential in CONNECT authenticationData.

Knowledge Base Used: Client configuration and HTTP transport

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/client.ts
Line: 500-507

Comment:
**Push credentials use cleartext** If a caller sets a `ws://` Push endpoint, or derives one from a supported `http://` API endpoint, Push sends the full JWT or session secret in MQTT CONNECT authentication data over that unencrypted connection. This exposes the credential in transit.

**How this was verified:** The allowed cleartext endpoint reaches `mqtt.connect` with the raw credential in CONNECT `authenticationData`.

**Knowledge Base Used:** [Client configuration and HTTP transport](https://app.greptile.com/appwrite/-/custom-context/knowledge-base/appwrite/sdk-for-console/-/docs/sdk-client-and-transport.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

Comment thread src/services/push.ts
Comment on lines +639 to +641
for (const sub of this.subscriptions.values()) {
if (matches(sub.topic, message.topic)) {
await sub.callback(message);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Overlapping filters duplicate callbacks When one subscribe() call supplies overlapping filters such as users/123/# and users/123/alerts, each filter registers the same callback. A message matching both invokes it twice, which can duplicate notification handling or other side effects.

Knowledge Base Used: Networking, realtime, and security

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/services/push.ts
Line: 639-641

Comment:
**Overlapping filters duplicate callbacks** When one `subscribe()` call supplies overlapping filters such as `users/123/#` and `users/123/alerts`, each filter registers the same callback. A message matching both invokes it twice, which can duplicate notification handling or other side effects.

**Knowledge Base Used:** [Networking, realtime, and security](https://app.greptile.com/appwrite/-/custom-context/knowledge-base/appwrite/sdk-for-console/-/docs/networking-realtime-and-security.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

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.

2 participants