Skip to content

Drop topic wildcards from the Topic helper - #2056

Merged
ArnabChatterjee20k merged 17 commits into
mainfrom
feat/topic-no-wildcards
Oct 15, 2026
Merged

ArnabChatterjee20k merged 17 commits into
mainfrom
feat/topic-no-wildcards

Conversation

@ArnabChatterjee20k

@ArnabChatterjee20k ArnabChatterjee20k commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

What

Removes the wildcard builders from the Topic helper across every SDK that ships it, so a topic can only be a path of plain id levels — no single-level (+) or multi-level (#) MQTT wildcards.

Concretely, per SDK:

  • Drop the static and instance any() / all() builders (and their Topic.any() / Topic.all() entry points).
  • Drop the ResolvedTopic type, which existed only as the terminal value returned by all(). It is removed from the helper and from every Push.subscribe signature / TopicValue conversion that referenced it; subscribe now accepts a string or a Topic (and lists of them).
  • Validation keeps rejecting a level that contains /, + or #, but a + or # level is now simply "not allowed in a topic" instead of being steered toward a wildcard builder.

This follows from topics being plain ids: the broker only grants exact topic ids, so the wildcard surface had no server-side meaning.

Scope

Topic helper templates, their unit tests, the Push.subscribe signatures / docs that referenced ResolvedTopic, the SDK re-exports, and the per-language e2e programs plus the shared TOPIC_HELPER_RESPONSES expectations.

Verification

Regenerated every affected SDK and ran the available formatters/linters/tests locally:

  • Generation suite (104 tests), Twig lint, Rector — pass
  • gofmt + go build/go test (go, cli), cargo fmt + cargo test (rust)
  • dart format (dart), swift-format (swift, apple)
  • Pint + PHPStan + Rector on generated PHP, Black (python), RuboCop 1.90.0 (ruby), ktlint 1.8.0 (kotlin, android)
  • Prettier + ESLint + tsc for web / node / react-native; node npm test (910 tests) pass

dotnet format (dotnet, unity) was not run locally (no toolchain available); left for CI. Docker e2e is left for CI.

Usage (JS)

Build a topic as a path of plain id levels and pass it to push.subscribe (strings still work too):

import { Client, Push, Topic } from 'appwrite';

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

const push = new Push(client);

// Topic.path(levels) builds "user/123/notification"
const topic = Topic.path(['user', userId, 'notification']);

// append more levels with .path(); it returns a new Topic
const scoped = Topic.path(['org', orgId]).path(['logs']); // "org/42/logs"

const sub = await push.subscribe(topic, (message) => {
    console.log(message);
});

// a raw string and a Topic can be mixed in one call
await push.subscribe(['news', Topic.path(['chat', chatId])], (message) => {
    console.log(message);
});

// later
sub.unsubscribe();

There is no longer an any() / all() builder or a ResolvedTopic type. A level that contains /, + or # throws — + and # are "not allowed in a topic". To match the old .toString() form, String(topic) or `${topic}` still works.

Remove Topic::any()/all() and the ResolvedTopic type so a topic is only
a path of plain id levels. A level containing + or # is now rejected
outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
Remove the any()/all() wildcard builders and the ResolvedTopic type so a
topic is only a path of plain id levels. A level containing + or # is now
rejected outright rather than steered toward a wildcard builder.
The language programs no longer print the any()/all() cases, so remove the
matching lines from the shared topic helper expectations.
@hansi-codes

hansi-codes Bot commented Oct 15, 2026

Copy link
Copy Markdown

🟢 Tier S · Ready to merge

The removed builders and result type are consistently deleted from helper implementations, Push contracts, exports, and test programs, with no remaining ResolvedTopic references found.

This change removes the any() and all() topic builders and the terminal ResolvedTopic type across the generated SDKs. It updates Push subscription contracts and examples, and adjusts topic-helper unit and end-to-end expectations to match the plain-level API.

Verdict New comments Fixed Still open
✅ Approved 0 0 0
📂 Walkthrough · 6
File Change
src/SDK/Language/PHP.php; templates/php/src/ResolvedTopic.php.twig Removes generation of the PHP ResolvedTopic type.
templates/android/library/src/main/java/io/package/Topic.kt.twig; templates/kotlin/src/main/kotlin/io/appwrite/Topic.kt.twig; templates/dart/lib/topic.dart.twig; templates/dotnet/Package/Topic.cs.twig; templates/go/topic.go.twig; templates/php/src/Topic.php.twig; templates/python/package/topic.py.twig; templates/ruby/lib/container/topic.rb.twig; templates/rust/src/topic.rs.twig; templates/swift/Sources/Topic.swift.twig; templates/web/src/topic.ts.twig Removes wildcard builders and ResolvedTopic implementations from SDK topic helpers, retaining plain path construction and wildcard rejection.
templates/android/library/src/main/java/io/package/services/Push.kt.twig; templates/apple/Sources/Services/Push.swift.twig; templates/flutter/lib/src/mqtt.dart.twig; templates/flutter/lib/src/mqtt_browser.dart.twig; templates/flutter/lib/src/mqtt_io.dart.twig; templates/react-native/src/services/push.ts.twig; templates/unity/Assets/Runtime/Push.cs.twig; templates/web/src/services/push.ts.twig Updates Push subscription types, conversions, and documentation to accept strings and Topic values.
templates/node/src/index.ts.twig; templates/react-native/src/index.ts.twig; templates/web/src/index.ts.twig Removes ResolvedTopic from public SDK exports.
templates/android/library/src/test/java/io/package/TopicTest.kt.twig; templates/dart/test/topic_test.dart.twig; templates/go/topic_test.go.twig; templates/kotlin/src/test/kotlin/io/appwrite/TopicTest.kt.twig; templates/node/test/topic.test.js.twig; templates/php/tests/TopicTest.php.twig; templates/python/test/test_topic.py.twig; templates/rust/src/topic.rs.twig Updates topic-helper unit tests for plain path construction and invalid-level validation.
tests/e2e/Base.php; tests/e2e/languages/** Removes wildcard-builder examples from shared expected output and per-language end-to-end programs.

Reviewed 35f4d6a · Details · Comment @hansi-codes review to re-run, or mention @hansi-codes with a question.

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Tier S · Looks good to merge. Summary

@ArnabChatterjee20k
ArnabChatterjee20k merged commit 84b10b0 into main Oct 15, 2026
80 of 81 checks passed
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