From f7efd00cd92c89786139ea526461428f75a2cb1a Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 9 Jun 2026 10:21:09 -0400 Subject: [PATCH] chore: remove node-sdk + browser-sdk (migrated to libxmtp) The @xmtp/node-sdk and @xmtp/browser-sdk packages now live in the libxmtp monorepo and are published from there. Remove them from xmtp-js and rewire the remaining consumers to the published npm versions. - Delete sdks/node-sdk, sdks/browser-sdk and their CI workflows (.github/workflows/{node,browser}-sdk.yml). - release.yml: drop the node-sdk/browser-sdk prerelease options + the auto-prerelease-bindings detect/publish jobs (that automation now lives in libxmtp); keep agent-sdk prerelease. - Rewire consumers to published npm: apps/xmtp.chat -> browser-sdk 7.0.0-dev.b5cdc06 (libxmtp dev build; the stable 7.0.0 predates the binding APIs xmtp.chat uses), sdks/agent-sdk + packages/xmtp-cli -> node-sdk ^6.0.0. - .yarnrc.yml: add @xmtp/browser-sdk to npmPreapprovedPackages so the freshly-published dev build clears the 7-day npmMinimalAgeGate. - renovate.json: track @xmtp/node-sdk + @xmtp/browser-sdk. - Drop the orphaned node-sdk changeset; remove stale SDK path filters from content-types.yml and xmtp-chat.yml. - Regenerate yarn.lock; agent-sdk, xmtp-cli and xmtp.chat all build. Follow-up: sync-documentation.yml still has node/browser-sdk branches that no longer fire (those release tags now come from libxmtp); left for the docs owner to delete or migrate to libxmtp. --- .changeset/curly-rivers-close.md | 5 - .github/workflows/browser-sdk.yml | 80 - .github/workflows/content-types.yml | 1 - .github/workflows/node-sdk.yml | 76 - .github/workflows/release.yml | 245 +- .github/workflows/xmtp-chat.yml | 1 - .yarnrc.yml | 1 + apps/xmtp.chat/package.json | 2 +- packages/xmtp-cli/package.json | 2 +- renovate.json | 11 +- sdks/agent-sdk/package.json | 2 +- sdks/browser-sdk/CHANGELOG.md | 1924 ----- sdks/browser-sdk/LICENSE | 21 - sdks/browser-sdk/README.md | 108 - sdks/browser-sdk/package.json | 101 - sdks/browser-sdk/rollup.config.js | 63 - sdks/browser-sdk/src/AsyncStream.ts | 189 - sdks/browser-sdk/src/Client.ts | 1089 --- sdks/browser-sdk/src/CodecRegistry.ts | 27 - sdks/browser-sdk/src/Conversation.ts | 555 -- sdks/browser-sdk/src/Conversations.ts | 633 -- sdks/browser-sdk/src/DebugInformation.ts | 31 - sdks/browser-sdk/src/DecodedMessage.ts | 265 - sdks/browser-sdk/src/Dm.ts | 63 - sdks/browser-sdk/src/Group.ts | 356 - sdks/browser-sdk/src/Opfs.ts | 63 - sdks/browser-sdk/src/Preferences.ts | 178 - sdks/browser-sdk/src/WorkerClient.ts | 260 - sdks/browser-sdk/src/WorkerConversation.ts | 343 - sdks/browser-sdk/src/WorkerConversations.ts | 191 - .../browser-sdk/src/WorkerDebugInformation.ts | 30 - sdks/browser-sdk/src/WorkerPreferences.ts | 78 - sdks/browser-sdk/src/constants.ts | 32 - sdks/browser-sdk/src/index.ts | 97 - sdks/browser-sdk/src/types/actions.ts | 79 - sdks/browser-sdk/src/types/actions/client.ts | 308 - .../src/types/actions/conversation.ts | 313 - .../src/types/actions/conversations.ts | 151 - .../src/types/actions/debugInformation.ts | 27 - sdks/browser-sdk/src/types/actions/dm.ts | 19 - sdks/browser-sdk/src/types/actions/group.ts | 186 - sdks/browser-sdk/src/types/actions/opfs.ts | 66 - .../src/types/actions/preferences.ts | 65 - sdks/browser-sdk/src/types/actions/streams.ts | 54 - sdks/browser-sdk/src/types/options.ts | 179 - sdks/browser-sdk/src/utils/WorkerBridge.ts | 148 - sdks/browser-sdk/src/utils/contentTypes.ts | 77 - sdks/browser-sdk/src/utils/conversions.ts | 46 - sdks/browser-sdk/src/utils/createBackend.ts | 45 - sdks/browser-sdk/src/utils/createClient.ts | 102 - sdks/browser-sdk/src/utils/date.ts | 3 - sdks/browser-sdk/src/utils/errors.ts | 68 - sdks/browser-sdk/src/utils/inboxId.ts | 36 - sdks/browser-sdk/src/utils/inboxState.ts | 19 - sdks/browser-sdk/src/utils/installations.ts | 86 - sdks/browser-sdk/src/utils/messages.ts | 92 - sdks/browser-sdk/src/utils/metadata.ts | 15 - sdks/browser-sdk/src/utils/signer.ts | 95 - sdks/browser-sdk/src/utils/streams.ts | 219 - sdks/browser-sdk/src/utils/uuid.ts | 8 - sdks/browser-sdk/src/workers/client.ts | 1159 --- sdks/browser-sdk/src/workers/opfs.ts | 127 - sdks/browser-sdk/test/AsyncStream.test.ts | 457 -- sdks/browser-sdk/test/Client.test.ts | 473 -- sdks/browser-sdk/test/Conversations.test.ts | 478 -- .../browser-sdk/test/DebugInformation.test.ts | 47 - sdks/browser-sdk/test/DeviceSync.test.ts | 220 - sdks/browser-sdk/test/Dm.test.ts | 457 -- sdks/browser-sdk/test/Group.test.ts | 1005 --- sdks/browser-sdk/test/Opfs.test.ts | 139 - sdks/browser-sdk/test/Preferences.test.ts | 256 - sdks/browser-sdk/test/contentTypes.test.ts | 1368 ---- sdks/browser-sdk/test/createBackend.test.ts | 56 - sdks/browser-sdk/test/helpers.ts | 161 - sdks/browser-sdk/test/inboxId.test.ts | 35 - sdks/browser-sdk/test/permissions.test.ts | 695 -- sdks/browser-sdk/test/signer.test.ts | 20 - sdks/browser-sdk/test/streams.test.ts | 773 -- sdks/browser-sdk/tsconfig.json | 21 - sdks/browser-sdk/typedoc.json | 8 - sdks/browser-sdk/vite.config.ts | 31 - sdks/node-sdk/.gitignore | 1 - sdks/node-sdk/CHANGELOG.md | 1852 ----- sdks/node-sdk/LICENSE | 21 - sdks/node-sdk/README.md | 70 - sdks/node-sdk/package.json | 81 - sdks/node-sdk/rollup.config.js | 49 - sdks/node-sdk/scripts/accounts.ts | 29 - sdks/node-sdk/scripts/groups.ts | 98 - sdks/node-sdk/src/AsyncStream.ts | 189 - sdks/node-sdk/src/Client.ts | 1250 --- sdks/node-sdk/src/CodecRegistry.ts | 27 - sdks/node-sdk/src/Conversation.ts | 483 -- sdks/node-sdk/src/Conversations.ts | 581 -- sdks/node-sdk/src/DebugInformation.ts | 30 - sdks/node-sdk/src/DecodedMessage.ts | 263 - sdks/node-sdk/src/Dm.ts | 49 - sdks/node-sdk/src/Group.ts | 255 - sdks/node-sdk/src/Preferences.ts | 135 - sdks/node-sdk/src/constants.ts | 32 - sdks/node-sdk/src/index.ts | 123 - sdks/node-sdk/src/types.ts | 209 - sdks/node-sdk/src/utils/createBackend.ts | 41 - sdks/node-sdk/src/utils/createClient.ts | 107 - sdks/node-sdk/src/utils/date.ts | 3 - sdks/node-sdk/src/utils/errors.ts | 48 - sdks/node-sdk/src/utils/inboxId.ts | 20 - sdks/node-sdk/src/utils/messages.ts | 92 - sdks/node-sdk/src/utils/signer.ts | 23 - sdks/node-sdk/src/utils/streams.ts | 209 - sdks/node-sdk/src/utils/uuid.ts | 6 - sdks/node-sdk/src/utils/validation.ts | 12 - sdks/node-sdk/test/AsyncStream.test.ts | 457 -- sdks/node-sdk/test/Client.test.ts | 657 -- sdks/node-sdk/test/Conversations.test.ts | 477 -- sdks/node-sdk/test/DebugInformation.test.ts | 45 - sdks/node-sdk/test/DeviceSync.test.ts | 219 - sdks/node-sdk/test/Dm.test.ts | 458 -- sdks/node-sdk/test/Group.test.ts | 994 --- sdks/node-sdk/test/Preferences.test.ts | 250 - sdks/node-sdk/test/contentTypes.test.ts | 1317 --- sdks/node-sdk/test/createBackend.test.ts | 52 - sdks/node-sdk/test/helpers.ts | 212 - sdks/node-sdk/test/inboxId.test.ts | 35 - sdks/node-sdk/test/libxmtpErrors.test.ts | 61 - sdks/node-sdk/test/permissions.test.ts | 712 -- sdks/node-sdk/test/streams.test.ts | 38 - sdks/node-sdk/test/validation.test.ts | 49 - sdks/node-sdk/tsconfig.json | 27 - sdks/node-sdk/vitest.config.ts | 20 - sdks/node-sdk/vitest.setup.ts | 11 - yarn.lock | 7068 +++++++---------- 132 files changed, 2973 insertions(+), 34189 deletions(-) delete mode 100644 .changeset/curly-rivers-close.md delete mode 100644 .github/workflows/browser-sdk.yml delete mode 100644 .github/workflows/node-sdk.yml delete mode 100644 sdks/browser-sdk/CHANGELOG.md delete mode 100644 sdks/browser-sdk/LICENSE delete mode 100644 sdks/browser-sdk/README.md delete mode 100644 sdks/browser-sdk/package.json delete mode 100644 sdks/browser-sdk/rollup.config.js delete mode 100644 sdks/browser-sdk/src/AsyncStream.ts delete mode 100644 sdks/browser-sdk/src/Client.ts delete mode 100644 sdks/browser-sdk/src/CodecRegistry.ts delete mode 100644 sdks/browser-sdk/src/Conversation.ts delete mode 100644 sdks/browser-sdk/src/Conversations.ts delete mode 100644 sdks/browser-sdk/src/DebugInformation.ts delete mode 100644 sdks/browser-sdk/src/DecodedMessage.ts delete mode 100644 sdks/browser-sdk/src/Dm.ts delete mode 100644 sdks/browser-sdk/src/Group.ts delete mode 100644 sdks/browser-sdk/src/Opfs.ts delete mode 100644 sdks/browser-sdk/src/Preferences.ts delete mode 100644 sdks/browser-sdk/src/WorkerClient.ts delete mode 100644 sdks/browser-sdk/src/WorkerConversation.ts delete mode 100644 sdks/browser-sdk/src/WorkerConversations.ts delete mode 100644 sdks/browser-sdk/src/WorkerDebugInformation.ts delete mode 100644 sdks/browser-sdk/src/WorkerPreferences.ts delete mode 100644 sdks/browser-sdk/src/constants.ts delete mode 100644 sdks/browser-sdk/src/index.ts delete mode 100644 sdks/browser-sdk/src/types/actions.ts delete mode 100644 sdks/browser-sdk/src/types/actions/client.ts delete mode 100644 sdks/browser-sdk/src/types/actions/conversation.ts delete mode 100644 sdks/browser-sdk/src/types/actions/conversations.ts delete mode 100644 sdks/browser-sdk/src/types/actions/debugInformation.ts delete mode 100644 sdks/browser-sdk/src/types/actions/dm.ts delete mode 100644 sdks/browser-sdk/src/types/actions/group.ts delete mode 100644 sdks/browser-sdk/src/types/actions/opfs.ts delete mode 100644 sdks/browser-sdk/src/types/actions/preferences.ts delete mode 100644 sdks/browser-sdk/src/types/actions/streams.ts delete mode 100644 sdks/browser-sdk/src/types/options.ts delete mode 100644 sdks/browser-sdk/src/utils/WorkerBridge.ts delete mode 100644 sdks/browser-sdk/src/utils/contentTypes.ts delete mode 100644 sdks/browser-sdk/src/utils/conversions.ts delete mode 100644 sdks/browser-sdk/src/utils/createBackend.ts delete mode 100644 sdks/browser-sdk/src/utils/createClient.ts delete mode 100644 sdks/browser-sdk/src/utils/date.ts delete mode 100644 sdks/browser-sdk/src/utils/errors.ts delete mode 100644 sdks/browser-sdk/src/utils/inboxId.ts delete mode 100644 sdks/browser-sdk/src/utils/inboxState.ts delete mode 100644 sdks/browser-sdk/src/utils/installations.ts delete mode 100644 sdks/browser-sdk/src/utils/messages.ts delete mode 100644 sdks/browser-sdk/src/utils/metadata.ts delete mode 100644 sdks/browser-sdk/src/utils/signer.ts delete mode 100644 sdks/browser-sdk/src/utils/streams.ts delete mode 100644 sdks/browser-sdk/src/utils/uuid.ts delete mode 100644 sdks/browser-sdk/src/workers/client.ts delete mode 100644 sdks/browser-sdk/src/workers/opfs.ts delete mode 100644 sdks/browser-sdk/test/AsyncStream.test.ts delete mode 100644 sdks/browser-sdk/test/Client.test.ts delete mode 100644 sdks/browser-sdk/test/Conversations.test.ts delete mode 100644 sdks/browser-sdk/test/DebugInformation.test.ts delete mode 100644 sdks/browser-sdk/test/DeviceSync.test.ts delete mode 100644 sdks/browser-sdk/test/Dm.test.ts delete mode 100644 sdks/browser-sdk/test/Group.test.ts delete mode 100644 sdks/browser-sdk/test/Opfs.test.ts delete mode 100644 sdks/browser-sdk/test/Preferences.test.ts delete mode 100644 sdks/browser-sdk/test/contentTypes.test.ts delete mode 100644 sdks/browser-sdk/test/createBackend.test.ts delete mode 100644 sdks/browser-sdk/test/helpers.ts delete mode 100644 sdks/browser-sdk/test/inboxId.test.ts delete mode 100644 sdks/browser-sdk/test/permissions.test.ts delete mode 100644 sdks/browser-sdk/test/signer.test.ts delete mode 100644 sdks/browser-sdk/test/streams.test.ts delete mode 100644 sdks/browser-sdk/tsconfig.json delete mode 100644 sdks/browser-sdk/typedoc.json delete mode 100644 sdks/browser-sdk/vite.config.ts delete mode 100644 sdks/node-sdk/.gitignore delete mode 100644 sdks/node-sdk/CHANGELOG.md delete mode 100644 sdks/node-sdk/LICENSE delete mode 100644 sdks/node-sdk/README.md delete mode 100644 sdks/node-sdk/package.json delete mode 100644 sdks/node-sdk/rollup.config.js delete mode 100644 sdks/node-sdk/scripts/accounts.ts delete mode 100644 sdks/node-sdk/scripts/groups.ts delete mode 100644 sdks/node-sdk/src/AsyncStream.ts delete mode 100644 sdks/node-sdk/src/Client.ts delete mode 100644 sdks/node-sdk/src/CodecRegistry.ts delete mode 100644 sdks/node-sdk/src/Conversation.ts delete mode 100644 sdks/node-sdk/src/Conversations.ts delete mode 100644 sdks/node-sdk/src/DebugInformation.ts delete mode 100644 sdks/node-sdk/src/DecodedMessage.ts delete mode 100644 sdks/node-sdk/src/Dm.ts delete mode 100644 sdks/node-sdk/src/Group.ts delete mode 100644 sdks/node-sdk/src/Preferences.ts delete mode 100644 sdks/node-sdk/src/constants.ts delete mode 100644 sdks/node-sdk/src/index.ts delete mode 100644 sdks/node-sdk/src/types.ts delete mode 100644 sdks/node-sdk/src/utils/createBackend.ts delete mode 100644 sdks/node-sdk/src/utils/createClient.ts delete mode 100644 sdks/node-sdk/src/utils/date.ts delete mode 100644 sdks/node-sdk/src/utils/errors.ts delete mode 100644 sdks/node-sdk/src/utils/inboxId.ts delete mode 100644 sdks/node-sdk/src/utils/messages.ts delete mode 100644 sdks/node-sdk/src/utils/signer.ts delete mode 100644 sdks/node-sdk/src/utils/streams.ts delete mode 100644 sdks/node-sdk/src/utils/uuid.ts delete mode 100644 sdks/node-sdk/src/utils/validation.ts delete mode 100644 sdks/node-sdk/test/AsyncStream.test.ts delete mode 100644 sdks/node-sdk/test/Client.test.ts delete mode 100644 sdks/node-sdk/test/Conversations.test.ts delete mode 100644 sdks/node-sdk/test/DebugInformation.test.ts delete mode 100644 sdks/node-sdk/test/DeviceSync.test.ts delete mode 100644 sdks/node-sdk/test/Dm.test.ts delete mode 100644 sdks/node-sdk/test/Group.test.ts delete mode 100644 sdks/node-sdk/test/Preferences.test.ts delete mode 100644 sdks/node-sdk/test/contentTypes.test.ts delete mode 100644 sdks/node-sdk/test/createBackend.test.ts delete mode 100644 sdks/node-sdk/test/helpers.ts delete mode 100644 sdks/node-sdk/test/inboxId.test.ts delete mode 100644 sdks/node-sdk/test/libxmtpErrors.test.ts delete mode 100644 sdks/node-sdk/test/permissions.test.ts delete mode 100644 sdks/node-sdk/test/streams.test.ts delete mode 100644 sdks/node-sdk/test/validation.test.ts delete mode 100644 sdks/node-sdk/tsconfig.json delete mode 100644 sdks/node-sdk/vitest.config.ts delete mode 100644 sdks/node-sdk/vitest.setup.ts diff --git a/.changeset/curly-rivers-close.md b/.changeset/curly-rivers-close.md deleted file mode 100644 index e588bbff8..000000000 --- a/.changeset/curly-rivers-close.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@xmtp/node-sdk": minor ---- - -Added `Client.close()` for clean shutdown. It cancels in-flight workers and detached streams, then releases the database connection. The method is idempotent — await it before deleting the database file or dropping the client reference to avoid log noise from background tasks running against a closed database. diff --git a/.github/workflows/browser-sdk.yml b/.github/workflows/browser-sdk.yml deleted file mode 100644 index 8683eaf1a..000000000 --- a/.github/workflows/browser-sdk.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: Browser SDK - -permissions: - contents: read - -on: - push: - branches: - - main - - pull_request: - paths: - - "sdks/browser-sdk/**" - - ".github/workflows/browser-sdk.yml" - - "dev/**" - - ".node-version" - - ".yarnrc.yml" - - "turbo.json" - -jobs: - typecheck: - name: Typecheck - runs-on: warp-ubuntu-latest-x64-8x - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 - with: - node-version-file: ".node-version" - cache: "yarn" - env: - SKIP_YARN_COREPACK_CHECK: "1" - - name: Enable corepack - run: corepack enable - - name: Install dependencies - run: yarn - - name: Typecheck - run: yarn turbo run typecheck --filter='./sdks/browser-sdk' - - test: - name: Test - runs-on: warp-ubuntu-latest-x64-8x - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 - with: - node-version-file: ".node-version" - cache: "yarn" - env: - SKIP_YARN_COREPACK_CHECK: "1" - - name: Enable corepack - run: corepack enable - - name: Install dependencies - run: yarn - - name: Install playwright browsers - working-directory: ./sdks/browser-sdk - run: yarn playwright install - - name: Start dev environment - run: ./dev/up - - name: Sleep for 5 seconds - run: sleep 5s - - name: Run tests - run: yarn turbo run test --filter='./sdks/browser-sdk' - - build: - name: Build - runs-on: warp-ubuntu-latest-x64-8x - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 - with: - node-version-file: ".node-version" - cache: "yarn" - env: - SKIP_YARN_COREPACK_CHECK: "1" - - name: Enable corepack - run: corepack enable - - name: Install dependencies - run: yarn - - name: Build - run: yarn turbo run build --filter='./sdks/browser-sdk' diff --git a/.github/workflows/content-types.yml b/.github/workflows/content-types.yml index 23cd49bae..265d4bbec 100644 --- a/.github/workflows/content-types.yml +++ b/.github/workflows/content-types.yml @@ -11,7 +11,6 @@ on: pull_request: paths: - "content-types/**" - - "sdks/node-sdk/src/**" - ".github/workflows/content-types.yml" - "dev/**" - ".node-version" diff --git a/.github/workflows/node-sdk.yml b/.github/workflows/node-sdk.yml deleted file mode 100644 index 193960f76..000000000 --- a/.github/workflows/node-sdk.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Node SDK -permissions: - contents: read - -on: - push: - branches: - - main - - pull_request: - paths: - - "sdks/node-sdk/**" - - ".github/workflows/node-sdk.yml" - - "dev/**" - - ".node-version" - - ".yarnrc.yml" - - "turbo.json" - -jobs: - typecheck: - name: Typecheck - runs-on: warp-ubuntu-latest-x64-8x - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 - with: - node-version-file: ".node-version" - cache: "yarn" - env: - SKIP_YARN_COREPACK_CHECK: "1" - - name: Enable corepack - run: corepack enable - - name: Install dependencies - run: yarn - - name: Typecheck - run: yarn turbo run typecheck --filter='./sdks/node-sdk' - - test: - name: Test - runs-on: warp-ubuntu-latest-x64-8x - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 - with: - node-version-file: ".node-version" - cache: "yarn" - env: - SKIP_YARN_COREPACK_CHECK: "1" - - name: Enable corepack - run: corepack enable - - name: Install dependencies - run: yarn - - name: Start dev environment - run: ./dev/up - - name: Sleep for 5 seconds - run: sleep 5s - - name: Run tests - run: yarn turbo run test --filter='./sdks/node-sdk' - - build: - name: Build - runs-on: warp-ubuntu-latest-x64-8x - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 - with: - node-version-file: ".node-version" - cache: "yarn" - env: - SKIP_YARN_COREPACK_CHECK: "1" - - name: Enable corepack - run: corepack enable - - name: Install dependencies - run: yarn - - name: Build - run: yarn turbo run build --filter='./sdks/node-sdk' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 95dfb7c62..ae5ff6168 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,12 +24,10 @@ on: description: "SDK you want to release" type: choice options: - - node-sdk - - browser-sdk - agent-sdk - default: node-sdk + default: agent-sdk prerelease_dependency_version: - description: "Dependency version (i.e. 1.7.0-dev.b057f23) for @xmtp/node-bindings (when releasing Node SDK) or @xmtp/node-sdk (when releasing Agent SDK), leave blank to use existing version" + description: "Dependency version (i.e. 6.1.0-dev.b057f23) for @xmtp/node-sdk (when releasing Agent SDK), leave blank to use existing version" type: string prerelease_tag: description: "Release tag" @@ -45,7 +43,7 @@ on: concurrency: ${{ github.workflow }}-${{ github.ref }} env: - SDK_DEPS: '{"node-sdk":"@xmtp/node-bindings","browser-sdk":"@xmtp/wasm-bindings","agent-sdk":"@xmtp/node-sdk"}' + SDK_DEPS: '{"agent-sdk":"@xmtp/node-sdk"}' jobs: release: @@ -153,240 +151,3 @@ jobs: - name: Publish working-directory: ./sdks/${{ inputs.prerelease_sdk }} run: npm publish --tag ${{ inputs.prerelease_tag }} - - auto-prerelease-bindings: - name: Auto Prerelease (Bindings) — detect - # NOTE: github.actor on push events is the user who merged the PR, not the - # commit author. We filter on head_commit.author.name so a human-merged - # Renovate PR still triggers publish. Confirmed against this repo's - # existing Dependabot squash-merges (which preserve bot authorship). - if: > - github.event_name == 'push' && - github.event.head_commit.author.name == 'renovate[bot]' && - contains(github.event.head_commit.message, 'xmtp bindings') - runs-on: ubuntu-latest - permissions: - contents: read - outputs: - changed: ${{ steps.detect.outputs.changed }} - sdks: ${{ steps.detect.outputs.sdks }} - node_bindings: ${{ steps.detect.outputs.node_bindings }} - wasm_bindings: ${{ steps.detect.outputs.wasm_bindings }} - steps: - - uses: actions/checkout@v5 - with: - fetch-depth: 2 - persist-credentials: false - - name: Detect bindings bump - id: detect - uses: actions/github-script@v8 - with: - script: | - const fs = require('fs'); - const cp = require('child_process'); - const VERSION_RE = /^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$/; - - const readDep = (rev, path, key) => { - try { - const json = rev === 'HEAD' - ? fs.readFileSync(path, 'utf8') - : cp.execFileSync('git', ['show', `${rev}:${path}`], { encoding: 'utf8' }); - return JSON.parse(json).dependencies?.[key] ?? ''; - } catch { - return ''; - } - }; - - const diff = (path, key) => { - const before = readDep('HEAD^', path, key); - const after = readDep('HEAD', path, key); - if (before === after || !after) return ''; - if (!VERSION_RE.test(after)) { - core.setFailed(`malformed version '${after}' for ${key} in ${path}`); - throw new Error('halt'); - } - return after; - }; - - const nodeBindings = diff('sdks/node-sdk/package.json', '@xmtp/node-bindings'); - if (nodeBindings) { - // primitives must also bump to the same version; missing or - // mismatched is an inconsistent partial bump. - const primitives = diff('content-types/content-type-primitives/package.json', '@xmtp/node-bindings'); - if (primitives !== nodeBindings) { - core.setFailed(`node-bindings version mismatch: node-sdk=${nodeBindings}, primitives=${primitives || ''}`); - throw new Error('halt'); - } - } - const wasmBindings = diff('sdks/browser-sdk/package.json', '@xmtp/wasm-bindings'); - - const sdks = [ - ...(nodeBindings ? ['node-sdk'] : []), - ...(wasmBindings ? ['browser-sdk'] : []), - ]; - core.setOutput('changed', sdks.length > 0 ? 'true' : 'false'); - core.setOutput('node_bindings', nodeBindings); - core.setOutput('wasm_bindings', wasmBindings); - core.setOutput('sdks', JSON.stringify(sdks)); - - name: Summary - run: | - { - echo "### Bindings detection" - echo "- changed: ${{ steps.detect.outputs.changed }}" - echo "- node_bindings: ${{ steps.detect.outputs.node_bindings }}" - echo "- wasm_bindings: ${{ steps.detect.outputs.wasm_bindings }}" - echo "- sdks: ${{ steps.detect.outputs.sdks }}" - } >> "$GITHUB_STEP_SUMMARY" - - auto-prerelease-publish: - name: Auto Prerelease (Bindings) — publish ${{ matrix.sdk }} - needs: auto-prerelease-bindings - if: needs.auto-prerelease-bindings.outputs.changed == 'true' - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - sdk: ${{ fromJSON(needs.auto-prerelease-bindings.outputs.sdks) }} - permissions: - contents: read - id-token: write - steps: - - uses: actions/checkout@v5 - with: - fetch-depth: 0 - persist-credentials: false - - uses: actions/setup-node@v5 - with: - node-version-file: ".node-version" - cache: "yarn" - env: - SKIP_YARN_COREPACK_CHECK: "1" - - name: Enable corepack - run: corepack enable - - name: Update npm to latest - run: npm install -g npm@latest - - name: Install dependencies - run: yarn - - name: Verify the integrity of provenance attestations and registry signatures for installed dependencies - run: npm audit signatures - - - name: Compute SDK version - id: version - uses: actions/github-script@v8 - env: - SDK: ${{ matrix.sdk }} - NODE_BINDINGS: ${{ needs.auto-prerelease-bindings.outputs.node_bindings }} - WASM_BINDINGS: ${{ needs.auto-prerelease-bindings.outputs.wasm_bindings }} - with: - script: | - const fs = require('fs'); - const cp = require('child_process'); - const VERSION_RE = /^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$/; - - const sdk = process.env.SDK; - const bindings = sdk === 'node-sdk' ? process.env.NODE_BINDINGS : process.env.WASM_BINDINGS; - if (!bindings) { - core.info(`No bindings version for ${sdk}; skipping.`); - core.setOutput('sdk_version', ''); - return; - } - const dash = bindings.indexOf('-'); - if (dash < 0) { - core.info(`Bindings ${bindings} is stable; skipping publish.`); - core.setOutput('sdk_version', ''); - return; - } - - const pkgPath = `sdks/${sdk}/package.json`; - let pkg; - try { - pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); - } catch (err) { - core.setFailed(`could not read ${pkgPath}: ${err.message}`); - return; - } - const releasedBase = (pkg.version || '').split('-')[0]; - if (!releasedBase) { - core.setFailed(`could not read .version from ${pkgPath}`); - return; - } - - // Prefer the next PLANNED version (from pending changesets) over the - // last released version, so nightlies preview the upcoming release - // instead of trailing it. `changeset status` reports the calculated - // newVersion without consuming changesets or mutating files. - // - // Caveats handled below: - // - `--output` is resolved relative to the repo root; absolute paths - // are ignored, so we use a repo-relative filename. - // - The command prints monorepo dependency-consistency warnings to - // stderr but still exits 0; a real failure (no changesets, etc.) is - // treated as "nothing planned" and falls back to the released base. - // - `releases[]` also contains phantom patch bumps for packages - // touched only by `updateInternalDependencies` cascade - // (changesets: []). Only a release with a non-empty `changesets` - // array reflects a genuine pending change, so we require that. - const sdkPkgName = pkg.name; - let plannedBase = ''; - const statusFile = 'cs-status.json'; - try { - cp.execFileSync('yarn', ['changeset', 'status', `--output=${statusFile}`], { stdio: 'ignore' }); - const status = JSON.parse(fs.readFileSync(statusFile, 'utf8')); - const release = (status.releases || []).find((r) => r.name === sdkPkgName); - if (release && Array.isArray(release.changesets) && release.changesets.length > 0 && release.newVersion) { - plannedBase = release.newVersion.split('-')[0]; - } - } catch (err) { - core.info(`changeset status unavailable (${err.message}); using released base.`); - } finally { - try { fs.unlinkSync(statusFile); } catch {} - } - - const sdkBase = plannedBase || releasedBase; - core.info(`${sdkPkgName} base: ${sdkBase} (planned=${plannedBase || ''}, released=${releasedBase})`); - - const sdkVersion = `${sdkBase}-${bindings.slice(dash + 1)}`; - if (!VERSION_RE.test(sdkVersion)) { - core.setFailed(`computed sdk_version '${sdkVersion}' is malformed`); - return; - } - core.setOutput('sdk_version', sdkVersion); - - - if: steps.version.outputs.sdk_version != '' - run: yarn lint - - if: steps.version.outputs.sdk_version != '' - run: yarn typecheck - - if: steps.version.outputs.sdk_version != '' - run: ./dev/up - - if: steps.version.outputs.sdk_version != '' - run: sleep 5s - - if: steps.version.outputs.sdk_version != '' - working-directory: ./sdks/${{ matrix.sdk }} - run: yarn test - - if: steps.version.outputs.sdk_version != '' - working-directory: ./sdks/${{ matrix.sdk }} - run: yarn version ${{ steps.version.outputs.sdk_version }} - - if: steps.version.outputs.sdk_version != '' - working-directory: ./sdks/${{ matrix.sdk }} - run: yarn build - - if: steps.version.outputs.sdk_version != '' - working-directory: ./sdks/${{ matrix.sdk }} - # Auth is inherited from the workflow environment (OIDC via - # id-token: write, matching the existing prerelease job's pattern). - # If npm auth needs an explicit token in the future, set - # NODE_AUTH_TOKEN here and add registry-url to setup-node above. - run: npm publish --tag nightly - - - name: Summary - if: always() - run: | - { - echo "### Nightly Publish (${{ matrix.sdk }})" - if [[ -z "${{ steps.version.outputs.sdk_version }}" ]]; then - echo "- **Skipped**: bindings version was stable, not a nightly" - else - echo "- **SDK**: @xmtp/${{ matrix.sdk }}" - echo "- **Version**: ${{ steps.version.outputs.sdk_version }}" - echo "- **Tag**: nightly" - fi - } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/xmtp-chat.yml b/.github/workflows/xmtp-chat.yml index 2333264d4..5406ad43d 100644 --- a/.github/workflows/xmtp-chat.yml +++ b/.github/workflows/xmtp-chat.yml @@ -8,7 +8,6 @@ on: pull_request: paths: - "apps/xmtp.chat/**" - - "sdks/browser-sdk/**" - ".github/workflows/xmtp-chat.yml" - "dev/**" - ".node-version" diff --git a/.yarnrc.yml b/.yarnrc.yml index 9a81b54c3..02d85c715 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -14,6 +14,7 @@ npmPreapprovedPackages: "@xmtp/node-bindings", "@xmtp/wasm-bindings", "@xmtp/node-sdk", + "@xmtp/browser-sdk", "@xmtp/agent-sdk", ] diff --git a/apps/xmtp.chat/package.json b/apps/xmtp.chat/package.json index 5e55d645a..7889721bf 100644 --- a/apps/xmtp.chat/package.json +++ b/apps/xmtp.chat/package.json @@ -24,7 +24,7 @@ "@sentry/react": "^10.36.0", "@tanstack/react-query": "^5.90.20", "@tanstack/react-virtual": "^3.13.18", - "@xmtp/browser-sdk": "workspace:^", + "@xmtp/browser-sdk": "7.0.0-dev.b5cdc06", "@xmtp/content-type-primitives": "workspace:^", "date-fns": "^4.1.0", "pinata": "^2.5.3", diff --git a/packages/xmtp-cli/package.json b/packages/xmtp-cli/package.json index a3690c7a4..0d62058cd 100644 --- a/packages/xmtp-cli/package.json +++ b/packages/xmtp-cli/package.json @@ -88,7 +88,7 @@ "@oclif/plugin-help": "^6.2.37", "@oclif/plugin-not-found": "^3.2.74", "@oclif/plugin-warn-if-update-available": "^3.1.55", - "@xmtp/node-sdk": "6.0.0", + "@xmtp/node-sdk": "^6.0.0", "viem": "^2.44.4" }, "devDependencies": { diff --git a/renovate.json b/renovate.json index f60057dba..23eed996d 100644 --- a/renovate.json +++ b/renovate.json @@ -17,11 +17,20 @@ "automerge": false, "rangeStrategy": "pin" }, + { + "matchPackageNames": ["@xmtp/node-sdk", "@xmtp/browser-sdk"], + "groupName": "xmtp sdks", + "groupSlug": "xmtp-sdks", + "commitMessageTopic": "xmtp sdks", + "rangeStrategy": "bump" + }, { "matchPackageNames": [ "*", "!@xmtp/node-bindings", - "!@xmtp/wasm-bindings" + "!@xmtp/wasm-bindings", + "!@xmtp/node-sdk", + "!@xmtp/browser-sdk" ], "enabled": false } diff --git a/sdks/agent-sdk/package.json b/sdks/agent-sdk/package.json index 1c32698db..146c10f7d 100644 --- a/sdks/agent-sdk/package.json +++ b/sdks/agent-sdk/package.json @@ -68,7 +68,7 @@ }, "dependencies": { "@xmtp/content-type-primitives": "3.0.1", - "@xmtp/node-sdk": "6.0.0", + "@xmtp/node-sdk": "^6.0.0", "ts-retry-promise": "^0.8.1", "viem": "^2.37.6" }, diff --git a/sdks/browser-sdk/CHANGELOG.md b/sdks/browser-sdk/CHANGELOG.md deleted file mode 100644 index 3a2c0f895..000000000 --- a/sdks/browser-sdk/CHANGELOG.md +++ /dev/null @@ -1,1924 +0,0 @@ -# @xmtp/browser-sdk - -## 7.0.0 - -This release includes a performance fix, a breaking change to history sync, and new methods for manual archive management. Update as soon as possible to take advantage of these enhancements and fixes. - -### Performance improvement - -Fixed a performance issue that could cause slowdowns in apps with many conversations or heavy use of disappearing messages. - -### History sync is now manual - -**THIS IS A BREAKING CHANGE.** - -Automatic sending of sync requests on new installations has been removed. XMTP SDKs no longer automatically send sync requests on new clients. - -This change gives you explicit control over when sync requests are sent, avoiding unexpected network activity during client initialization. - -You must now call `sendSyncRequest()` explicitly after creating a client on a new installation to trigger a history sync. - -To learn more, see [Control history sync](https://docs.xmtp.org/chat-apps/list-stream-sync/history-sync#control-history-sync) - -### Manual history sync archive management - -These methods give you fine-grained control over history sync archives. Use them when you need to push data to a new installation proactively, inspect what's available before syncing, or process a specific archive by pin. - -- `sendSyncArchive(pin, options?, serverUrl?)`: Send an archive to the sync group without waiting for a request from another installation - -- `listAvailableArchives(daysCutoff)`: List archives available for import from the sync group - -- `processSyncArchive(archivePin?)`: Process an available archive from the sync group - -- `syncAllDeviceSyncGroups()`: Sync all device sync groups from the network - -To learn more, see [Control history sync](https://docs.xmtp.org/chat-apps/list-stream-sync/history-sync#control-history-sync) - -### Upcoming deprecation of `preferences.sync()` - -In a future release, `preferences.sync()` will be deprecated. Use `syncAllDeviceSyncGroups()` instead to sync device sync groups from the network. - -To learn more, see [Sync device sync groups](https://docs.xmtp.org/chat-apps/list-stream-sync/history-sync#sync-device-sync-groups) - -### Archive-based backups - -Support archive-based backups to give your users an easy and durable way to back up their XMTP conversations, messages, and consent preferences from one app installation and import them into another. - -This feature includes three core methods: - -- `createArchive` — Create an encrypted archive -- `archiveMetadata` — Read metadata from an archive before importing -- `importArchive` — Import an archive into the current installation - -To learn more, see [Support archive-based backups.](https://docs.xmtp.org/chat-apps/list-stream-sync/archive-backups#1-create-the-archive) - -## 6.5.0 - -### Minor Changes - -- Added `processStreamedMessage` method to `Conversation` for decoding, decrypting, and persisting raw envelope bytes from a group message stream - -## 6.4.1 - -### Patch Changes - -- 49f297e: Marked the "codecs" options as non-enumerable - -## 6.4.0 - -### Minor Changes - -- Added `topic` property to `Conversations` for subscribing to incoming welcomes -- Added `topic` property to `Conversation` for subscribing to incoming messages - -## 6.3.0 - -Added `contentType` method to enriched replies. - -```ts -type EnrichedReply = { - referenceId: string; - content: T; - contentType: () => Promise; - inReplyTo: DecodedMessage | null; -}; -``` - -Use this new method to get the content type of a reply's content. - -```ts -import { encodeText, contentTypeText } from "@xmtp/browser-sdk"; - -const textMessageId = await group.sendText("hi"); -const replyMessageId = await group.sendReply({ - content: await encodeText("hello"), - reference: textMessageId, -}); -const reply: DecodedMessage = - await client.conversations.getMessageById(replyMessageId); - -// access reply's content type -expect(await reply.content.contentType()).toEqual(await contentTypeText()); -``` - -## 6.2.0 - -This release introduces new features and critical bug fixes. If you've been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of these enhancements and fixes. - -### Message type guards - -New utility functions have been added to help identify message content types. These type guards provide a convenient way to check message types and narrow TypeScript types when working with decoded messages. - -```ts -import { - isText, - isMarkdown, - isReaction, - isReply, - isTextReply, - isAttachment, - isRemoteAttachment, - isMultiRemoteAttachment, - isTransactionReference, - isReadReceipt, - isGroupUpdated, - isWalletSendCalls, - isActions, - isIntent, -} from "@xmtp/browser-sdk"; - -const messages = await group.messages(); - -for (const message of messages) { - if (isText(message)) { - // message.content is narrowed to string - console.log(message.content); - } - - if (isReaction(message)) { - // message.content is narrowed to Reaction - console.log(message.content.content); - } - - if (isTextReply(message)) { - // message.content is narrowed to EnrichedReply - console.log(message.content.content); - } -} -``` - -### Stream deleted messages - -The `streamMessageDeletions` method has been deprecated and will be removed in a future release. Use the new `streamDeletedMessages` method. This new method streams the entire decoded message of deleted messages rather than just the message ID. - -```ts -const deletedMessagesStream = - await client.conversations.streamDeletedMessages(); - -for await (const message of deletedMessagesStream) { - // message is a DecodedMessage -} -``` - -### Improved conversation streaming behavior - -The `stream` method for conversations now handles unknown conversation types more gracefully. Previously, encountering an unknown conversation type would throw an error. Now, unknown types are filtered out with a warning logged to the console, allowing the stream to continue without interruption. - -### Actions and intent content type serialization - -The actions and intent content types were not being serialized properly. This release ensures that these content types are backwards-compatible with all clients using these content types. - -## 6.1.2 - -### Patch Changes - -- d629632: Defaulted to an `undefined` gateway host when an empty string was provided - -## 6.1.1 - -### Patch Changes - -- 6c26498: Fixed browser SDK logging options - -## 6.1.0 - -This release introduces a new feature. If you've been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of this new feature. - -### Send sync requests - -When a device installation comes online, it automatically sends a request to other devices on the network to sync conversations and messages. In some cases, this process may be interrupted. To remedy this, it's now possible to re-request a sync. - -```ts -// send a sync request -await client.sendSyncRequest(); -``` - -## 6.0.1 - -Fixed reply content type exports - -## 6.0.0 - -This release introduces breaking changes and new features. If you've been building on a previous release, updating your app to use this release will require changes to your existing code. - -### BREAKING CHANGES - -#### Removed features - -- Removed `uploadDebugArchive` method from `Client.DebugInformation` -- Removed `debugEventsEnabled` client option -- Removed deprecated `Client.version` static property (use `Client.libxmtpVersion` instead) -- Removed `Conversation.sendOptimistic` method (use dedicated send methods with the `optimistic` parameter instead) -- Removed `codecFor`, `encodeContent`, `decodeContent`, and `prepareForSend` client methods (content encoding is now handled by dedicated send methods) -- Removed `Conversation.isCommitLogForked` property -- Removed `DecodedMessage.compression` property -- Removed `DecodedMessage.parameters` property -- Removed `MessageKind` and `MessageDeliveryStatus` type exports (use `GroupMessageKind` and `DeliveryStatus` enums instead) -- Removed most `Safe*` conversion types and functions from exports (these were mostly for internal usage and are no longer necessary): - - Types: `SafeContentTypeId`, `SafeEncodedContent`, `SafeMessage`, `SafeListMessagesOptions`, `SafeSendMessageOpts`, `SafeListConversationsOptions`, `SafePermissionPolicySet`, `SafeCreateGroupOptions`, `SafeCreateDmOptions`, `SafeInstallation`, `SafeInboxState`, `SafeConsent`, `SafeGroupMember`, `SafeHmacKey`, `SafeHmacKeys`, `SafeMessageDisappearingSettings`, `SafeKeyPackageStatus`, `SafeXMTPCursor`, `SafeConversationDebugInfo`, `SafeApiStats`, `SafeIdentityStats` - - Functions: `toContentTypeId`, `fromContentTypeId`, `toSafeContentTypeId`, `fromSafeContentTypeId`, `toEncodedContent`, `fromEncodedContent`, `toSafeEncodedContent`, `fromSafeEncodedContent`, `toSafeMessage`, `toSafeListMessagesOptions`, `fromSafeListMessagesOptions`, `toSafeSendMessageOpts`, `fromSafeSendMessageOpts`, `toSafeListConversationsOptions`, `fromSafeListConversationsOptions`, `toSafePermissionPolicySet`, `fromSafePermissionPolicySet`, `toSafeCreateGroupOptions`, `fromSafeCreateGroupOptions`, `toSafeCreateDmOptions`, `fromSafeCreateDmOptions`, `toSafeInstallation`, `toSafeInboxState`, `toSafeConsent`, `fromSafeConsent`, `toSafeGroupMember`, `fromSafeGroupMember`, `toSafeHmacKey`, `toSafeMessageDisappearingSettings`, `fromSafeMessageDisappearingSettings`, `toSafeKeyPackageStatus`, `toSafeConversationDebugInfo`, `toSafeApiStats`, `toSafeIdentityStats` - -#### Updated types - -Many types that were previously string literals or interfaces are now numeric enums. - -The following types are now numeric enums: - -- `ConsentEntityType` -- `ConsentState` -- `ContentType` -- `ConversationType` -- `DeliveryStatus` -- `GroupMembershipState` -- `GroupMessageKind` -- `GroupPermissionsOptions` -- `IdentifierKind` -- `LogLevel` -- `MetadataField` -- `PermissionLevel` -- `PermissionPolicy` -- `PermissionUpdateType` -- `SortDirection` - -Other type updates: - -- `DecodedMessage.kind` and `deliveryStatus` fields now use enum values instead of strings -- Conversation type value is now an enum in metadata -- `loggingLevel` client option is now uses `LogLevel` numeric enum - -```ts -// DecodedMessage.kind and deliveryStatus now use enums - -// OLD -if (message.kind === "application") { ... } -if (message.deliveryStatus === "published") { ... } - -// NEW -import { GroupMessageKind, DeliveryStatus } from "@xmtp/browser-sdk"; - -if (message.kind === GroupMessageKind.Application) { ... } -if (message.deliveryStatus === DeliveryStatus.Published) { ... } - -// `loggingLevel` client option is now uses `LogLevel` numeric enum -import { LogLevel } from "@xmtp/browser-sdk"; - -// OLD -const client = await Client.create(signer, { loggingLevel: "off" }); - -// NEW -const client = await Client.create(signer, { loggingLevel: LogLevel.Off }); - -// Conversation type value is now an enum in metadata - -// OLD -if (conversation.metadata.conversationType === "group") { ... } - -// NEW -import { ConversationType } from "@xmtp/browser-sdk"; - -if (conversation.metadata.conversationType === ConversationType.Group) { ... } -``` - -#### Refactored or renamed functions - -Method names have been updated to follow a consistent naming convention across the SDK. Methods that make network requests now use `fetch` prefix to distinguish them from local operations. Conversation creation methods now use `create` prefix for clarity. Several properties that could return variable internal state have been converted to functions. - -- Updated `Conversation.send` method signature -- Renamed `Client.getKeyPackageStatusesForInstallationIds` to `Client.fetchKeyPackageStatuses` -- Renamed `Client.getInboxIdByIdentifier` to `Client.fetchInboxIdByIdentifier` -- Renamed static `Client.inboxStateFromInboxIds` to static `Client.fetchInboxStates` -- Renamed `Conversation.getHmacKeys` to `Conversation.hmacKeys` -- `Conversation.consentState` is now a function -- Renamed `Conversations.getDmByIdentifier` to `Conversations.fetchDmByIdentifier` -- Renamed `Conversations.newGroupOptimistic` to `Conversations.createGroupOptimistic` -- Renamed `Conversations.newGroupWithIdentifiers` to `Conversations.createGroupWithIdentifiers` -- Renamed `Conversations.newDmWithIdentifier` to `Conversations.createDmWithIdentifier` -- Renamed `Conversations.newGroup` to `Conversations.createGroup` -- Renamed `Conversations.newDm` to `Conversations.createDm` -- `Group.permissions` is now a function -- `Group.isPendingRemoval` is now a function -- `Group.admins` property is now `Group.listAdmins` function -- `Group.superAdmins` property is now `Group.listSuperAdmins` function -- Removed `Preferences.getLatestInboxState` -- Refactored `Preferences.inboxState` -- Added `Preferences.fetchInboxState` -- Refactored `Preferences.inboxStateFromInboxIds` into `Preferences.getInboxStates` and `Preferences.fetchInboxStates` -- Renamed `Dm.getDuplicateDms` to `Dm.duplicateDms` - -```ts -// Conversation.send method signature changed - -// OLD -await conversation.send("hello"); -await conversation.send(reactionContent, ContentTypeReaction); - -// NEW - use dedicated send methods for built-in content types (see below for more details) -await conversation.sendText("hello"); -await conversation.sendReaction(reaction); - -// NEW - use send() for custom content types with EncodedContent -await conversation.send(encodedContent, { - shouldPush: true, - optimistic: false, -}); - -// Properties that are now functions - -// OLD -const consentState = conversation.consentState; -const permissions = group.permissions; -const isPendingRemoval = group.isPendingRemoval; -const admins = group.admins; -const superAdmins = group.superAdmins; - -// NEW -const consentState = conversation.consentState(); -const permissions = group.permissions(); -const isPendingRemoval = group.isPendingRemoval(); -const admins = group.listAdmins(); -const superAdmins = group.listSuperAdmins(); - -// Creating conversations - -// OLD -const group = await client.conversations.newGroup(inboxIds); -const dm = await client.conversations.newDm(inboxId); -const groupWithIdentifiers = - await client.conversations.newGroupWithIdentifiers(identifiers); - -// NEW -const group = await client.conversations.createGroup(inboxIds); -const dm = await client.conversations.createDm(inboxId); -const groupWithIdentifiers = - await client.conversations.createGroupWithIdentifiers(identifiers); - -// Preferences inbox state methods - -// OLD -const inboxState = await client.preferences.inboxState(); -const latestInboxState = await client.preferences.inboxState(true); -const latestInboxStateForInboxId = - await client.preferences.getLatestInboxState(inboxId); // this function removed -const inboxStates = await client.preferences.inboxStateFromInboxIds( - inboxIds, - false, -); -const latestInboxStates = await client.preferences.inboxStateFromInboxIds( - inboxIds, - true, -); - -// NEW -const inboxState = await client.preferences.inboxState(); -const latestInboxState = await client.preferences.fetchInboxState(); -const inboxStates = await client.preferences.getInboxStates(inboxIds); -const latestInboxStates = await client.preferences.fetchInboxStates(inboxIds); -``` - -### NEW FEATURES - -#### Built-in content types - -Previously, sending non-text messages required installing separate content type packages and registering codecs with the client. This release simplifies messaging by including all official content types directly in the SDK. You no longer need to manage codec registration, just use the dedicated send methods for each content type. - -Supported content types include: text, markdown, reactions, replies, read receipts, transaction references, wallet send calls, actions, intents, attachments, remote attachments, and multiple remote attachments. - -#### Enriched messages - -To make it easier to build rich messaging experiences, messages now include additional context. Each message includes the number of replies it has received and an array of reaction messages. This eliminates the need for separate queries to count replies or fetch reactions for a message thread. - -Reply messages also include the original message being replied to, allowing you to display the parent message context without an additional lookup. - -```ts -import { contentTypeReply, type Reply } from "@xmtp/browser-sdk"; -import { contentTypesAreEqual } from "@xmtp/content-type-primitives"; - -const messages = await group.messages(); - -for (const message of messages) { - // number of replies to a message - console.log(`message ${message.id} has ${message.numReplies} replies`); - - // message.reactions is an array of reaction messages - console.log( - `message ${message.id} has ${message.reactions.length} reactions`, - ); - - // reply messages include the original message - // note: contentTypeReply() is async in browser SDK - if (contentTypesAreEqual(message.contentType, await contentTypeReply())) { - const reply = message.content as Reply; - // the decoded content of the reply - console.log(reply.content); - // ID of message being replied to - console.log(reply.referenceId); - // the original message being replied to - console.log(reply.inReplyTo); - } -} -``` - -#### Send messages with different content types - -Each content type now has its own dedicated send method, making it easier to send different types of messages without manually encoding content or specifying content types. The second, optional parameter for each method is a boolean that indicates if it should be sent optimistically (stored locally before network confirmation). - -```ts -// send a text message -const textMessageId = await group.sendText("gm"); - -// send a markdown message -await group.sendMarkdown("# gm"); - -// send a reaction -await group.sendReaction({ - reference: textMessageId, - referenceInboxId: client.inboxId, - action: ReactionAction.Added, - content: "👍", - schema: ReactionSchema.Unicode, -}); - -// send a read receipt -await group.sendReadReceipt(); - -// send a reply (note: encodeText is async in browser SDK) -await group.sendReply({ - content: await encodeText("This is a text reply"), - reference: textMessageId, - referenceInboxId: client.inboxId, -}); - -// send an attachment -await group.sendAttachment({ - filename: "gm.txt", - mimeType: "text/plain", - content: new Uint8Array([103, 109]), -}); - -// send a remote attachment -const attachment: Attachment = { - filename: "gm.txt", - mimeType: "text/plain", - content: new Uint8Array([103, 109]), -}; -// must encrypt attachment first (note: encryptAttachment is async in browser SDK) -const encryptedAttachment = await encryptAttachment(attachment); -const remoteAttachment: RemoteAttachment = { - // upload URL - url: "https://example.com/gm.txt", - contentDigest: encryptedAttachment.contentDigest, - secret: encryptedAttachment.secret, - salt: encryptedAttachment.salt, - nonce: encryptedAttachment.nonce, - scheme: "https", - contentLength: encryptedAttachment.contentLength, - filename: encryptedAttachment.filename, -}; -await group.sendRemoteAttachment(remoteAttachment); - -// decrypt attachment (note: decryptAttachment is async in browser SDK) -const decryptedAttachment = await decryptAttachment( - // downloaded from remote attachment URL - encryptedBytes, - remoteAttachment, -); - -// send multiple remote attachments -await group.sendMultiRemoteAttachment({ - attachments: [remoteAttachment], -}); - -// send a transaction reference -await group.sendTransactionReference({ - // eth mainnet - networkId: "1", - reference: "1234567890", -}); - -// send a wallet send call -await group.sendWalletSendCalls({ - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x4567891230", - value: "1", - }, - ], -}); - -// send actions -await group.sendActions({ - id: "actions-1", - description: "Choose an option", - actions: [ - { - id: "opt-1", - label: "Option 1", - }, - { - id: "opt-2", - label: "Option 2", - }, - ], -}); - -// send intent -await group.sendIntent({ - id: "intent-1", - actionId: "opt-1", -}); -``` - -#### Send custom content - -For content types not included in the SDK, you can still define custom codecs and use the `send` method to send encoded content. This allows you to extend XMTP with app-specific message formats while maintaining compatibility with the SDK's message handling. - -```ts -export const ContentTypeTest: ContentTypeId = { - authorityId: "xmtp.org", - typeId: "test", - versionMajor: 1, - versionMinor: 0, -}; - -export class TestCodec implements ContentCodec { - contentType = ContentTypeTest; - encode(content: Record): EncodedContent { - return { - type: this.contentType, - parameters: {}, - content: new TextEncoder().encode(JSON.stringify(content)), - }; - } - decode(content: EncodedContent): Record { - const decoded = new TextDecoder().decode(content.content); - return JSON.parse(decoded); - } - fallback() { - return undefined; - } - shouldPush() { - return false; - } -} - -const testCodec = new TestCodec(); - -// send custom content with options -await group.send( - testCodec.encode({ - foo: "bar", - }), - { - // should this message be a push notification? - shouldPush: testCodec.shouldPush(), - // should this message be sent optimistically? - optimistic: false, - }, -); -``` - -#### Standalone utility functions - -The `Utils` class has been replaced with standalone functions that can be imported directly. - -```ts -// OLD -import { Utils } from "@xmtp/browser-sdk"; - -const utils = new Utils(); -const inboxId = await utils.generateInboxId(identifier); -const existingInboxId = await utils.getInboxIdForIdentifier(identifier, env); - -// NEW -import { generateInboxId, getInboxIdForIdentifier } from "@xmtp/browser-sdk"; - -const inboxId = await generateInboxId(identifier); -const existingInboxId = await getInboxIdForIdentifier(identifier, env); -``` - -#### Last read times - -Building read status indicators is now easier. When participants send read receipt messages, you can query a conversation to see when each member last read the conversation. This enables features like showing which messages are unread or displaying "seen by" indicators. - -```ts -// returns a map keyed by inbox ID -const lastReadTimes = await group.lastReadTimes(); - -// get the last read time of an inbox in nanoseconds -const inboxLastReadTimeNs = lastReadTimes.get(inboxId); -``` - -#### OPFS file management - -A new `Opfs` class provides direct access to manage files in the Origin Private File System, where the browser SDK stores its database. This is useful for debugging, exporting/importing databases, or cleaning up storage. - -```ts -import { Opfs } from "@xmtp/browser-sdk"; - -const opfs = await Opfs.create(); - -// list all files -const files = await opfs.listFiles(); - -// check file count -const count = await opfs.fileCount(); - -// export a database -const data = await opfs.exportDb("path/to/db"); - -// import a database -await opfs.importDb("path/to/db", data); - -// delete a specific file -await opfs.deleteFile("path/to/file"); - -// clear all files -await opfs.clearAll(); - -// close when done -opfs.close(); -``` - -#### Message expiration timestamp - -For conversations with disappearing messages enabled, messages now include an expiration timestamp. This allows you to display countdown timers or visual indicators showing when a message will be automatically removed. - -```ts -// message is disappearing -if (message.expiresAtNs !== undefined) { - // schedule an effect when message is about the expire -} -``` - -To learn more, see [Access message expiration timestamps](https://docs.xmtp.org/chat-apps/core-messaging/disappearing-messages#access-disappearing-message-expiration-timestamps) - -## 5.3.0 - -This release introduces new features. If you've been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of these enhancements. - -### Self-removal from group chats - -This feature enables a member to leave a group chat on their own. Previously, a member could be removed only by other members with appropriate permissions. This update addresses user privacy concerns and reduces the need for manual member removal by admins. - -To see if a user has requested removal, check the new `isPendingRemoval` property. - -```ts -// request removal from group -await group.requestRemoval(); - -console.log(group.isPendingRemoval); // true -``` - -To learn more, see [Leave a group](https://docs.xmtp.org/chat-apps/core-messaging/group-permissions#leave-a-group) and [XIP-75: Self-removal support for XMTP/MLS groups](https://community.xmtp.org/t/xip-75-self-removal-support-for-xmtp-mls-groups/1659). - -### New `appData` metadata for groups - -Groups now support an `appData` metadata field for storing custom application-specific data. This field enables developers to attach arbitrary data to groups, such as configuration settings. - -The `appData` field can store up to 8,192 bytes of string data. - -```ts -// access app data -const appData = group.appData; - -// update app data with custom JSON -await group.updateAppData( - JSON.stringify({ - muted: false, - pinned: true, - }), -); - -// retrieve and parse the updated data -const appData = JSON.parse(group.appData); -console.log(appData.pinned); // true -``` - -## 5.2.0 - -This release introduces new features, performance optimizations, and bug fixes. If you've been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of these enhancements and fixes. - -### Stream message deletions - -Call `streamMessageDeletions` to return a stream of message IDs that have been deleted. This new stream works in tandem with disappearing messages so that developers can be notified when messages have been removed. This is a local stream that doesn't require network sync and will not fail like other streams. - -To learn more, see [Support disappearing messages](https://docs.xmtp.org/chat-apps/core-messaging/disappearing-messages). - -### Paginate the conversation list - -For most pagination use cases, use the `createdBeforeNs` parameter for filtering and set `orderBy` to `createdAt`. This enables you to paginate against a stably sorted list. You can then perform a final sort of conversations in your app. - -To learn more, see [Paginate the conversation list](https://docs.xmtp.org/chat-apps/list-stream-sync/list#paginate-the-conversation-list). - -### Total ordered sort for message pagination - -Provides the ability to filter queries for the message list by insertion time rather than by time sent. Filtering by insertion time provides a totally ordered list, which is more reliable for pagination. - -To learn more, see [Paginate messages by insertion time](https://docs.xmtp.org/chat-apps/list-stream-sync/list-messages#paginate-by-insertion-time-recommended). - -### More details on sync - -The return value of `conversations.syncAllConversations` is now an object that includes both the number of conversations, and the number that needed to be synced. - -### Use `countMessages` to build an unread messages badge - -Call `countMessages` to return a count of messages without retrieving the full message list. This is more efficient when you only need the number, such as for unread message badges. - -To learn more, see [Count messages in a conversation](https://docs.xmtp.org/chat-apps/list-stream-sync/list-messages#count-messages-in-a-conversation). - -### New version properties on the client - -- `libxmtpVersion`: Returns the version of `libxmtp` used in the bindings -- `appVersion`: Returns the app version configured for the client - -The `libxmtpVersion` property can be useful for debugging or ensuring compatibility with the underlying XMTP APIs. - -**Note:** The static `Client.version` property is now deprecated, use `libxmtpVersion` instead. - -### `syncAll` performance improvements - -The `syncAll` method now performs the same function as before, but with significantly improved performance. It achieves this by syncing only group chat and DM conversations with a consent state of _allowed_ or _unknown_ that contain **unread messages**, rather than syncing all conversations. - -The method continues to sync new welcomes and preference updates. - -To learn more, see [Sync new welcomes, conversations with unread messages, and preferences](https://docs.xmtp.org/chat-apps/list-stream-sync/sync-and-syncall#sync-new-welcomes-conversations-with-unread-messages-and-preferences). - -### Streaming now includes catch-up messages - -Streaming messages now includes all messages sent after the last sync, including those missed while the client was offline. To only stream new messages, be sure to sync with the network before starting the stream. - -To learn more, see [Stream new group chat and DM messages](https://docs.xmtp.org/chat-apps/list-stream-sync/stream#stream-new-group-chat-and-dm-messages). - -### Welcome pointers - -OpenMLS supports sending welcomes to multiple installations in a single commit. This is currently used, but each welcome is sent individually to each installation. Some of the welcomes can be very large, and the data is duplicated for every installation. - -Welcome pointers introduce a new welcome message that provides a pointer to the location where the welcome data can be found. The large welcome pointer data can be sent to the server only once, and each installation can fetch that message. This is achieved using symmetric key encryption for the welcome data, with each installation receiving a message that includes these keys. - -This provides a performance and scalability improvement that makes both developer implementations and user experiences smoother and faster, without requiring changes to how developers write client code. - -To learn more, see [XIP-74: Welcome pointers](https://community.xmtp.org/t/xip-74-welcome-pointers/1211). - -### `revokeAllOtherInstallations` no longer crashes with a single installation - -Calling `revokeAllOtherInstallations()` on an inbox with only one active installation no longer crashes with an "Unknown signer" error. - -Because the method’s purpose is to keep only the current installation active, having just one installation already meets this condition. The operation now completes successfully without trying to revoke non-existent installations. - -To learn more, see [Revoke all other installations](https://docs.xmtp.org/chat-apps/core-messaging/manage-inboxes#revoke-all-other-installations). - -### Total ordered sort for message pagination - -Provides the ability to filter queries for the message list by insertion time rather than by time sent. Filtering by insertion time provides a totally ordered list, which is more reliable for pagination. - -To learn more, see [Paginate messages by insertion time](https://docs.xmtp.org/chat-apps/list-stream-sync/list-messages#paginate-by-insertion-time-recommended). - -### More details on sync - -The return value of `conversations.syncAllConversations` is now an object that includes both the number of conversations, and the number that needed to be synced. - -### Updates for disappearing messages - -The disappearing messages feature has been updated to exclude expired (already disappeared) messages from queries. - -To learn more, see [Support disappearing messages](https://docs.xmtp.org/chat-apps/core-messaging/disappearing-messages). - -## 5.1.0 - -### Minor Changes - -- 7ce84ce: Added `getDmByIdentifier` method to `Conversations` - -## 5.0.1 - -### Patch Changes - -- 61c19c9: - - Fixed an issue where duplicate welcome errors were fired erroneously - - Fixed a bug where building a client did a network request when not needed - -## 5.0.0 - -### BREAKING CHANGES - -- 90089b0: Refactored `Conversation.isActive` to async method for more accurate value - -## 4.3.0 - -### Minor Changes - -- b7a860e: Added `lastMessage()` method to `Conversation` - -## 4.2.1 - -### Patch Changes - -- 0abcb05: Fixed initial group membership validation - -## 4.2.0 - -- Improved performance of syncing new groups -- Added support for Lens chain Smart Contract Wallet verifier -- Fixed OpenMLS issue for persistence during message processing -- Fixed lifetime validation gaps - -## 4.1.0 - -This release introduces improved fork detection. If you've been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of this enhancement. - -### Improved fork detection - -The `isCommitLogForked` field provides definitive fork detection without false positives. To minimize the negative effects of spam, fork detection is active only for groups that a user has actively consented to. - -Important: The `maybeForked` field has been deprecated. You can now use `isCommitLogForked` instead to get definitive fork detection without false positives. - -To learn more, see [Forked group debugging tool](https://docs.xmtp.org/inboxes/debug-your-app#forked-group-debugging-tool). - -## 4.0.2 - -### Patch Changes - -- ed36644: Reverted performance improvement for large inboxes that caused message streaming issues - -## 4.0.1 - -### Patch Changes - -- ffec6e0: - - Improved performance for large inboxes - - Improved key package errors - - Added `appVersion` client option - - Added `debugEventsEnabled` client option - - Fixed DM stitching bug - - Added expiration to messages for disappearing messages - -## 4.0.0 - -This release introduces several enhancements to improve stream reliability. It contains breaking changes. - -### Stream reliability improvements - -When streams fail, an attempt to reconnect will be made automatically. By default, a stream will be retried 6 times with a 10 second delay between each retry. Maximum retries and retry delay can be configured with the `retryAttempts` and `retryDelay` options, respectively. To disable this feature, set the `retryOnFail` option to `false`. - -During the retry process, the `onRetry` and `onRestart` callbacks can be used to monitor progress. - -### BREAKING CHANGES - -#### All streaming methods now accept a single options argument - -The new argument defines streaming options: - -```ts -type StreamOptions = { - /** - * Called when the stream ends - */ - onEnd?: () => void; - /** - * Called when a stream error occurs - */ - onError?: (error: Error) => void; - /** - * Called when the stream fails - */ - onFail?: () => void; - /** - * Called when the stream is restarted - */ - onRestart?: () => void; - /** - * Called when the stream is retried - */ - onRetry?: (attempts: number, maxAttempts: number) => void; - /** - * Called when a value is emitted from the stream - */ - onValue?: (value: V) => void; - /** - * The number of times to retry the stream - * (default: 6) - */ - retryAttempts?: number; - /** - * The delay between retries (in milliseconds) - * (default: 10000) - */ - retryDelay?: number; - /** - * Whether to retry the stream if it fails - * (default: true) - */ - retryOnFail?: boolean; -}; -``` - -In addition to these options, some streaming methods have more options. See their respective types for more details. - -Update your calls to each streaming method as follows: - -```ts -// OLD -const conversationStream = await client.conversations.stream(callback, onFail); -const groupStream = await client.conversations.streamGroups(callback, onFail); -const dmStream = await client.conversations.streamDms(callback, onFail); -const allMessagesStream = await client.conversations.streamAllMessages( - callback, - conversationType, - consentStates, - onFail, -); -const allGroupMessagesStream = await client.conversations.streamAllGroupMessages( - callback, - consentStates, - onFail, -); -const allDmMessagesStream = await client.conversations.streamAllDmMessages( - callback, - consentStates, - onFail, -); - -const consentStream = await client.preferences.streamConsent(callback, onFail); -const preferencesStream = await client.preferences.streamPreferences(callback, onFail); - -const messagesStream = await conversation.stream(callback, onFail); - -// NEW -const conversationStream = await client.conversations.stream({ - onError, - onValue, - onFail -}); -const groupStream = await client.conversations.streamGroups({ - onError, - onValue, - onFail -}); -const dmStream = await client.conversations.streamDms({ - onError, - onValue, - onFail -}); -const allMessageStream = await client.conversations.streamAllMessages({ - consentStates, - conversationType - onError, - onValue, - onFail -}); -const allGroupMessagesStream = await client.conversations.streamAllGroupMessages({ - consentStates, - onError, - onValue, - onFail, -}); -const allDmMessagesStream = await client.conversations.streamAllDmMessages({ - consentStates, - onError, - onValue, - onFail, -}); - -const consentStream = await client.preferences.streamConsent({ - onError, - onValue, - onFail, -}); -const preferencesStream = await client.preferences.streamPreferences({ - onError, - onValue, - onFail, -}); - -const messagesStream = await conversation.stream({ - onError, - onValue, - onFail -}); -``` - -#### Streams no longer end on error - -When a stream error occurs, it's passed to the `onError` callback only. The stream will remain active. - -#### Stream types have changed - -When using the `for await..of` loop, the value will never be `undefined`. - -```ts -const stream = await client.conversations.streamAllMessages(); - -for await (const message of stream) { - // message will always be an instance of DecodedMessage -} -``` - -## 3.1.2 - -### Patch Changes - -- 78c6710: - - Resolved issue with too many key package API requests - - Fixed issue causing users with old installations to sometimes not be added to groups - - Fixed a performance bottleneck that affected listing conversations while syncing - -## 3.1.1 - -### Patch Changes - -- 41aeaae: - - Improved sync and stream performance - - Increased max installations to 10 - - Fixed a known fork issue - - Added key package rotation every 30 days - -## 3.1.0 - -This release introduces several enhancements, including quantum-resistant encryption, improved identity management, and refined read/write rate limits. - -If you've been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of these enhancements and fixes. - -### Support for quantum-resistant encryption - -XMTP now supports quantum-resistant encryption, providing enhanced security for message transmission and storage. This upgrade ensures your app is protected against future quantum computer attacks through post-quantum cryptography. - -To learn more, see [Quantum resistance](https://docs.xmtp.org/protocol/security#quantum-resistance). - -### Consistent identity ordering - -When an inbox has multiple associated identities, the `identities` array is now ordered by the `client_timestamp_ns` field, which sorts identities based on when they were added to the inbox, placing the earliest added identity first. - -To learn more, see [Select the identity to display](https://docs.xmtp.org/inboxes/manage-inboxes#select-the-identity-to-display). - -### Enhanced rate limits with separate read/write limits - -XMTP now provides separate rate limits for read and write operations, offering more granular control over API usage. Read operations are limited to 20,000 requests per 5-minute window, while write operations are limited to 3,000 messages per 5-minute window. - -To learn more, see [Observe rate limits](https://docs.xmtp.org/inboxes/rate-limits). - -### Improved history sync - -History sync has been enhanced with better consent management across installations and improved handling of denied conversations. These changes ensure a more consistent experience when users access XMTP from multiple installations. - -To learn more, see [Enable history sync](https://docs.xmtp.org/inboxes/history-sync). - -### Enhanced group chat updates - -Group membership changes now automatically trigger group update codec messages, ensuring all participants receive consistent information about group state changes. This improves the reliability of group chat synchronization across all devices. - -To learn more, see [Manage group chat membership](https://docs.xmtp.org/inboxes/group-permissions#manage-group-chat-membership). - -### Performance improvements and bug fixes - -This release includes various performance optimizations throughout the SDK, resulting in faster message processing, improved memory usage, and better overall responsiveness. The release also includes bug fixes that improve the reliability of group chats and address a performance degradation issue that could occur when creating new groups. - -To learn more about optimizing your XMTP implementation, see [Debug your app](https://docs.xmtp.org/inboxes/debug-your-app). - -## 3.0.5 - -### Patch Changes - -- 3f4d125: - - Refactored `AsyncStream` to be more spec-compliant - - Added `onDone` callback to `AsyncStream` - - Updated stream methods to use new `onDone` callback to end streams - -## 3.0.4 - -### Patch Changes - -- e0b7745: - - Fixed group syncing on larger groups - - Fixed HTTP stream panic when subscription request fails - -## 3.0.3 - -### Patch Changes - -- 8729f02: - - Increased max payload size to `25MB` - - Improved `syncAll` performance - -## 3.0.2 - -### Patch Changes - -- 63c144d: Fixed static installation revokation - -## 3.0.1 - -### Patch Changes - -- 10bf2d1: Fixed some issues that may cause group forks - -## 3.0.0 - -This update introduces enhancements for managing installations without a client. It also contains breaking changes related to signature management and consistency across SDKs. - -### BREAKING CHANGES - -#### Debug information has been moved to `client.debugInformation` - -To better align with our mobile SDKs, debug information helpers are now accessible at the `debugInformation` property of client instances. - -Update your calls to the following: - -- `client.apiStatistics()` => `client.debugInformation.apiStatistics()` -- `client.apiIdentityStatistics()` => `client.debugInformation.apiIdentityStatistics()` -- `client.apiAggregateStatistics()` => `client.debugInformation.apiAggregateStatistics()` -- `client.clearAllStatistics()` => `client.debugInformation.clearAllStatistics()` -- `client.uploadDebugArchive()` => `client.debugInformation.uploadDebugArchive()` - -#### Signatures are now managed through signature requests - -This change only affects developers who are using custom workflows with the `unsafe_*SignatureText` client methods. - -When using a custom signing workflow, the `unsafe_*SignatureText` client methods now return an object with the following type: - -```ts -type SignatureRequestResult = { - signatureText: string; - signatureRequestId: string; -}; -``` - -After signing the `signatureText`, you must create a special signer and pass it to the `unsafe_applySignatureRequest` client method along with the `signatureRequestId`. - -**Example** - -```ts -// change the recovery identifier -const { signatureText, signatureRequestId } = - await this.unsafe_changeRecoveryIdentifierSignatureText(newIdentifier); -// use a `Signer` to sign the signature text -const signature = await signer.signMessage(signatureText); -// `toSafeSigner` is a new export from `@xmtp/browser-sdk` -const safeSigner = await toSafeSigner(signer, signature); - -await client.unsafe_applySignatureRequest(safeSigner, signatureRequestId); -``` - -As part of this change, the `SignatureRequestType` export has been replaced with `SignatureRequestHandle`. - -### Other changes - -- Added `Client.revokeInstallations` static method for revoking installations without a client -- Added `Client.inboxStateFromInboxIds` static method for getting inbox state without a client - -## 2.2.1 - -### Patch Changes - -- e86b0c9: Fixed async iterator exit when calling `end()` on `AsyncStream` - -## 2.2.0 - -This update introduces several targeted enhancements and clarifications related to managing client builds, network statistics, installations, and group chats. - -If you’ve been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of these enhancements and fixes. - -### Reset network statistics for debugging - -A new helper, `clearAllStatistics()`, lets you reset all API/identity/stream network statistics counters. - -Use it to get a clean baseline between test runs or free memory on devices where cached gRPC stats grow over time. - -To learn more, see [Network statistics](https://docs.xmtp.org/inboxes/debug-your-app#network-statistics). - -### Support installation limits and more targeted revocations - -XMTP now enforces up to 5 app installations per inbox ID. - -When the installation limit is reached, you can revoke an installation to free up a slot. - -To learn more, see [Revoke installations](https://docs.xmtp.org/inboxes/manage-inboxes#revoke-installations). - -### Support slightly larger group chats - -The maximum group chat size has been raised from 220 to 250 members. - -To learn more, see [Create a new group chat](https://docs.xmtp.org/inboxes/create-conversations#create-a-new-group-chat). - -### Reduced risk of group chat forks - -Additional safeguards have been added to minimize the chance of unintended group chat forks. - -To learn about what group chat forks are and how they can occur, see [MLS Group State Forks: What, Why, How](https://cryspen.com/post/mls-fork-resolution/). - -## 2.1.1 - -### Patch Fixes - -Fixes streaming bug that would sometimes cause streams to miss messages - -Fixes stream conversations bug that would hang all conversations streams upon a backend node update adding a field to welcome messages - -updates @xmtp/wasm-bindings to 1.2.1 - -## 2.1.0 - -This release delivers enhancements to messaging performance and reliability, as well as a set of developer debugging tools, all focused on making it easier to build with XMTP. - -If you’ve been building on a previous release, this one should be a **drop-in replacement**—just update to the latest version to take advantage of everything below. - -### Consent-based listing, streaming, and syncing - -By default, `conversations.list`, `conversations.listGroups`, `conversations.listDms`, `conversations.syncAll`, `conversations.streamAllMessages`, `conversations.streamAllGroupMessages`, and `conversations.streamAllDmMessages` now filter for conversations with a consent state of `ConsentState.Allowed` or `ConsentState.Unknown`. - -We recommend listing `ConsentState.Allowed` conversations only. This ensures that spammy conversations with a consent state of `ConsentState.Unknown` don't degrade the user experience. - -To include all conversations regardless of consent state, you can pass `[ConsentState.Allowed, ConsentState.Unknown, ConsentState.Denied]`. - -### Optimistic group chat creation - -Provides faster and offline group chat creation and message preparation before adding members. - -### Group chat member limit - -**A 220-member limit is now enforced for group chats.** This helps prevent errors that oversized groups can cause and ensures consistent behavior across clients. - -### Preference sync - -Preference syncing enables you to sync the following preference-related information across multiple existing app installations: - -- Conversation consent preferences -- Conversation HMAC keys (for push notifications) - -### Developer tooling and debugging - -Delivers tools and features for debugging when building with XMTP, including group chat diagnostics, file logging, and network statistics. - -### Reliability and performance - -- Reliability improvements to message history -- Reliability improvements to [`streamAll`](https://docs.xmtp.org/inboxes/list-and-stream#stream-all-group-chat-and-dm-messages) -- Performance improvements to `peerInboxId` -- [Duplicate DMs](https://docs.xmtp.org/inboxes/push-notifs/understand-push-notifs#dm-stitching-considerations-for-push-notifications) removed from streams - -## 2.0.13 - -### Patch Changes - -- 441a029: `AsyncStream` updates - - Changed signature of `return` to allow no argument (e.g. `stream.return()`) - - Added `end` alias that calls `return` without an argument - - Added `AsyncStream` and `StreamCallback` to exports - -## 2.0.12 - -### Patch Changes - -- 616fdec: Added `null` option to `historySyncUrl` client option to allow disabling of history sync - -## 2.0.11 - -### Patch Changes - -- 5bc5a85: Update to the libxmtp stable release version - -## 2.0.10 - -### Patch Changes - -- 581d465: Added guard to prevent unexpected conversation types - -## 2.0.9 - -### Patch Changes - -- 4035fb5: Removed special sync groups from conversation list results - -## 2.0.8 - -### Patch Changes - -- fbce324: Fix welcome processing issue that could lead to incorrect group state - -## 2.0.7 - -### Patch Changes - -- 5a676b1: Propagated original error from workers - -## 2.0.6 - -### Patch Changes - -- b7a3001: Fixed message processing issue that could sometimes fork groups - -## 2.0.5 - -### Patch Changes - -- f0a43c4: Lowercase Ethereum addresses on static Client.canMessage calls - -## 2.0.4 - -### Patch Changes - -- Converted all `any` types to `unknown` -- Added generics for types with `unknown` where applicable -- Prevented `CodecNotFoundError` from throwing when instantiating `DecodedMessage` -- Added missing `signer` property to `Client` -- Updated code comments -- Updated dependencies [63e5276] - - @xmtp/content-type-group-updated@2.0.2 - - @xmtp/content-type-primitives@2.0.2 - - @xmtp/content-type-text@2.0.2 - -## 2.0.3 - -### Patch Changes - -- 6e54926: Exposed message decoding errors in streams - -## 2.0.2 - -### Patch Changes - -- f021255: Fixed missing key package status error - -## 2.0.1 - -### Patch Changes - -- 7e7fad4: Fixed error handling in `AsyncStream` - -## 2.0.0 - -This release focuses on new features, stability, and performance. - -## Upgrade from 1.1.4 to 2.0.0 - -Use the information in these release notes to upgrade from `@xmtp/browser-sdk` 1.1.4 to 2.0.0. - -## Breaking changes - -### Refactored `Client.create` - -The database encryption key parameter was removed from the static `Client.create` method. To use a database encryption key, add it to the client options. - -`1.x` code: - -```typescript -import { Client, type Signer } from "@xmtp/browser-sdk"; - -const clientOptions = { - /* client options */ -}; -const dbEncryptionKey = MY_ENCRYPTION_KEY; -const signer: Signer = { - /* signer properties */ -}; -const client = await Client.create(signer, dbEncryptionKey, clientOptions); -``` - -`2.0.0` code: - -```typescript -import { Client, type Signer } from "@xmtp/browser-sdk"; - -const clientOptions = { - dbEncryptionKey: MY_ENCRYPTION_KEY, -}; -const signer: Signer = { ... }; -const client = await Client.create(signer, clientOptions); -``` - -### Refactored `Client` constructor - -The `Client` constructor now only accepts a single parameter: client options. It's no longer possible to create a client with a signer using the constructor. Use `Client.create` to create a new client with a signer. - -`1.x` code: - -```typescript -import { Client, type Signer } from "@xmtp/browser-sdk"; - -const clientOptions = { - /* client options */ -}; -const dbEncryptionKey = MY_ENCRYPTION_KEY; -const signer: Signer = { - /* signer properties */ -}; -const client = new Client(signer, dbEncryptionKey, clientOptions); -``` - -`2.0.0` code: - -```typescript -import { Client, type Signer } from "@xmtp/browser-sdk"; - -const clientOptions = { - dbEncryptionKey: MY_ENCRYPTION_KEY, -}; -const signer: Signer = { ... }; -const client = await Client.create(signer, clientOptions); -``` - -### Client `accountIdentifier` method is now a property - -`1.x` code: - -```typescript -const identifier = await client.accountIdentifier(); -``` - -`2.0.0` code: - -```typescript -const identifier = client.accountIdentifier; -``` - -### Client options are now read-only - -Setting client options after initialization is no longer possible. - -### Removed `Opfs` export - -This export was not usable in its exported form and has been removed. OPFS utilities to manage local databases will be added in a future release. - -## New features - -### Added `Client.build` static method - -It's now possible to create a client without a signer using the new `Client.build` method. A signer is not required if an account is already registered on the XMTP network. Keep in mind, some client methods still require a signer. - -```typescript -import { Client, type Identifier } from "@xmtp/browser-sdk"; - -const identifier: Identifier = { - identifier: "0x1234567890abcdef1234567890abcdef12345678", - identifierKind: "Ethereum", -}; -const client = await Client.build(identifier, options); -``` - -### Added `changeRecoveryIdentifier` method to `Client` - -The recovery identifier can now be changed. This method requires a client with a signer. - -```typescript -import { Client, type Signer } from "@xmtp/browser-sdk"; - -const signer: Signer = { ... }; -const client = await Client.create(signer, options); - -const identifier: Identifier = { - identifier: "0x1234567890abcdef1234567890abcdef12345678", - identifierKind: "Ethereum", -}; -await client.changeRecoveryIdentifier() -``` - -### Added `getKeyPackageStatusesForInstallationIds` method to `Client` - -Key package status can now be retrieved for installation IDs. This new method returns a `Map` of installation IDs and their respective status. - -```typescript -import { Client, type Identifier } from "@xmtp/browser-sdk"; - -const identifier: Identifier = { - identifier: "0x1234567890abcdef1234567890abcdef12345678", - identifierKind: "Ethereum", -}; -const client = await Client.build(identifier, options); - -type SafeKeyPackageStatus = { - lifetime?: { - notBefore: bigint; - notAfter: bigint; - }; - validationError?: string; -}; - -const keyPackageStatuses: Map = - await client.getKeyPackageStatusesForInstallationIds([ - /* array of installation IDs here */ - ]); -``` - -## Added `getHmacKeys` method to `Conversation` - -It's now possible to get the HMAC keys of individual conversations. - -```typescript -type SafeHmacKey = { - key: Uint8Array; - epoch: bigint; -}; - -const conversation = client.conversations.getConversationById("..."); - -if (conversation) { - const hmacKeys: SafeHmacKey[] = await conversation.getHmacKeys(); -} -``` - -### Other changes - -- Refactored static `Client.canMessage` to remove the creation of a temporary client -- Updated `dbPath` client option to allow `null` value -- Added custom error types -- Added `dbEncryptionKey` option to client options - -## 1.1.4 - -### Patch Changes - -- 8bd3930: Fixed removing inboxes with invalid key packages from groups - -## 1.1.3 - -### Patch Changes - -- 295e046: - - Fixed incorrect key package associations - - Resolved DM stitching issues for conversations without messages - -## 1.1.2 - -### Patch Changes - -- 5845617: Refactored welcome message processing to prevent key package deletion on failure - -## 1.1.1 - -### Patch Changes - -- Updated dependencies [340fcf4] - - @xmtp/content-type-group-updated@2.0.1 - - @xmtp/content-type-primitives@2.0.1 - - @xmtp/content-type-text@2.0.1 - - @xmtp/proto@3.78.0 - - uuid@11.1.0 - -## 1.1.0 - -### Minor Changes - -- 999bb78: Added `inboxStateFromInboxIds` to `Preferences` - -## 1.0.0 - -This release focuses on delivering an SDK for a stable, performant, and hardened XMTP V3. - -> [!IMPORTANT] -> Please upgrade your app to **use @xmtp/browser-sdk ≥ 1.0.0 by May 1, 2025** to continue using XMTP. On May 1, XMTP V3 will enforce this minimum SDK version. Apps on outdated V3 SDKs will lose connectivity. - -## Upgrade from 0.0.x to 1.0.0 - -Use the information in these release notes to upgrade from @xmtp/browser-sdk 0.0.x to 1.0.0. - -> [!IMPORTANT] -> **Upgrading from a legacy XMTP V2 SDK?** Legacy XMTP V2 SDKs include JavaScript SDK vx.x.x. To learn how to upgrade to stable XMTP V3, be sure to also see important dates and considerations in [Upgrade from a legacy XMTP V2 SDK](https://docs.xmtp.org/upgrade-from-legacy-V2). - -## Breaking changes - -### Primary XMTP identifier is now an inbox ID, not an Ethereum address - -In preparation for upcoming support for [Passkeys](https://community.xmtp.org/t/xip-55-passkey-identity/874), XMTP must evolve from using Ethereum account addresses (0x...) as the primary identifier to an inbox-based identity model. - -This change allows for broader support of different authentication mechanisms, including the currently supported [Externally Owned Accounts (EOAs) and Smart Contract Wallets (SCWs)](https://docs.xmtp.org/inboxes/build-inbox#create-an-account-signer), as well as **future support** for Passkeys, Bitcoin, and Solana, for example. - -The move to an inbox-based identity model means the following shift in approach when developing with XMTP: - -- Instead of assuming an Ethereum address as the unique identifier, developers should default to using an inbox ID where possible. -- Where you previously used an Ethereum address, you must now use an inbox ID - - `addMembers(addresses)` → `addMembers(inboxIds)` - - `removeMember(addresses)` → `removeMembers(inboxIds)` - - `newGroup(addresses)` → `newGroup(inboxIds)` - - `newDm(address)` → `newDm(inboxId)` - -> [!WARNING] -> These function changes (address → inbox ID) won't trigger errors since both parameters are strings. Your code will pass a type-check but may fail at runtime. Pay special attention to these changes when upgrading. - -- The previous methods that allowed the use of an inbox ID have been removed in favor of the above methods - - ~`addMembersByInboxIds(inboxIds)`~ - - ~`removeMembersByInboxIds(inboxIds)`~ - - ~`newGroupByInboxIds(inboxIds)`~ - - ~`newDmByInboxId(inboxId)`~ - -- New methods have been added to allow the use of addresses with the `Identifier` type - - `addMembersByIdentifiers(Identifier[])` - - `removeMembersByIdentifiers(Identifier[])` - - `newGroupByIdentifiers(Identifier[])` - - `newDmByIdentifier(Identifier)` - -- We recommend moving away from using addresses in code completely. However, if you MUST use addresses, wrap them with the `Identifier` type. - - For example, the address `0x1234567890abcdef1234567890abcdef12345678` must now be wrapped like so: - - ```tsx - const identifier: Identifier = { - identifier: "0x1234567890abcdef1234567890abcdef12345678", - identifierKind: "Ethereum", - }; - ``` - -- Because XMTP is interoperable, you may interact with inboxes that are not on your app. In these scenarios, you will need to find the appropriate inbox ID or address. - - ```tsx - // get an inbox ID from an address - const inboxId = await getInboxIdForIdentifier({ - identifier: "0x1234567890abcdef1234567890abcdef12345678", - identifierKind: "Ethereum", - }); - - // find the addresses associated with an inbox ID - const inboxState = await client.inboxStateFromInboxIds([inboxId]); - - interface InboxState { - inboxId: string; - recoveryIdentifier: Identifier; - installations: Installation[]; - identifiers: Identifier[]; - } - - const addresses = inboxState.identifiers - .filter((i) => i.identifierKind === "Ethereum") - .map((i) => i.identifier); - ``` - -### Wallet and signer updates - -The term “wallet” has been removed from the codebase. This is to align with future support for Passkeys and other non-wallet-based authentication methods. - -This release includes breaking changes to the `Signer` type. - -- The `walletType` field is now `type`. The `type` field refers to the type of account that will sign messages, such as an `EOA` or `SCW`. -- The `getAddress` field has been replaced by `getIdentifier`, which is a function that returns an `Identifier` type. - -```tsx -// old -const address = await signer.getAddress(); - -// new -const identifier = await signer.getIdentifier(); -// identifier may not be an Ethereum address -const address = - identifier.identifierKind === "Ethereum" ? identifier.identifier : undefined; -``` - -### Consent and inbox state have been moved to `client.preferences` - -Everything related to consent, inbox state, and user preferences is now part of the `Preferences` class and accessible via `client.preferences`. - -- `client.inboxState` → `client.preferences.inboxState` -- `client.getLatestInboxState` → `client.preferences.getLatestInboxState` -- `client.inboxStateFromInboxIds` → `client.preferences.inboxStateFromInboxIds` -- `client.getConsentState` → `client.preferences.getConsentState` -- `client.setConsentStates` → `client.preferences.setConsentStates` -- `client.conversations.streamConsent` → `client.preferences.streamConsent` -- `client.conversations.streamPreferences` → `client.preferences.streamPreferences` - -## Other recent changes - -### Conversations are now instances of `Group` or `Dm` - -The new `Group` and `Dm` classes extend the `Conversation` class and provide specific functionality based on the conversation type. - -> [!NOTE] -> `client.conversations.list()` now returns an array of `Group` or `Dm` classes. When accessing specific functionality based on conversation type, you must check the type first so that the TypeScript compiler can narrow the type. - -```tsx -const conversations: (Group | Dm)[] = await client.conversations.list(); - -for (const conversation of conversations) { - // narrow the type to Group to access the group name - if (conversation instanceof Group) { - console.log(group.name); - } - - // narrow the type to Dm to access the peer inboxId - if (conversation instanceof Dm) { - console.log(conversation.peerInboxId); - } -} -``` - -## Recently added features - -### Disappearing messages - -This release provides support for disappearing (ephemeral) messages. These are messages that are intended to be visible to users for only a short period of time. After the message expiration time passes, the messages are removed from the UI and deleted from local storage so the messages are no longer accessible to conversation participants. - -To learn more, see [Support disappearing messages with XMTP](https://docs.xmtp.org/inboxes/disappearing-messages). - -### Future-proofing app interoperability - -This release introduces error handling that will help support app interoperability across SDK versions, even when breaking changes are required in the future. - -In the future, an SDK version may introduce a breaking change, such as a feature that works only for apps on the latest versions of the SDK. Instead of forcing immediate upgrades or causing apps on older versions to break, this update adds a safety net that gracefully handles breaking changes. - -At this time, no features rely on this mechanism, and no action is needed. However, this ensures your app remains resilient to future SDK updates that introduce breaking changes. - -## 1.0.0-rc1 - -- Updated `Signer` type -- Replaced address parameters with inbox IDs or identifiers -- Added new methods to use with identifiers -- Added `pausedForVersion` to `Conversation` -- Updated exports - -## 0.0.23 - -### Patch Changes - -- dd1a33a: Fixed stream errors - -## 0.0.22 - -### Patch Changes - -- 3cf6dd9: - - Exposed all client signature methods - - Added guard to `Client.addAccount` to prevent automatic reassignment of inboxes - - Renamed `syncAdmins` to `listAdmins` and `syncSuperAdmins` to `listSuperAdmins` - - Added consent and preference streaming - - Removed `allowedStates`, `conversationType`, and `includeSyncGroups` from `ListConversationsOptions` - - Added `contentTypes` option to `ListMessagesOptions` - - Changed OPFS VFS to SyncAccessHandle Pool - - Added more exports from the bindings - - Added `Group` and `Dm` classes - - Refactored some functions to use the new `Group` and `Dm` classes - -## 0.0.21 - -### Patch Changes - -- f53c967: Refactored `Signer`, made `getBlockNumber` optional for SCW signers - -## 0.0.20 - -### Patch Changes - -- 74ce850: Fix signer for SCW - -## 0.0.19 - -### Patch Changes - -- 03d2002: - - Added `allowedStates`, `consentStates`, `includeSyncGroups`, and `includeDuplicateDms` options to `Conversations.list` method - - Added `consentStates` option to `Conversations.syncAll` method - - Added `newGroupByInboxIds` method to `Conversations` - - Added `newDmByInboxId` method to `Conversations` - - Added `messageDisappearingSettings` option for creating groups and DMs - - Added `updateMessageDisappearingSettings` method to `Conversation` - - Added `removeMessageDisappearingSettings` method to `Conversation` - - Added `isMessageDisappearingEnabled` method to `Conversation` - - Fixed invalid key package issues - - Fixed rate limiting issues - -## 0.0.18 - -### Patch Changes - -- ec5cd41: - - Added streaming methods - - Removed group pinned frame URL metadata - - Fixed DB locking issues - -## 0.0.17 - -### Patch Changes - -- 25e0e15: - - Optimized `toSafeConversation` - - Replaced some `??` with `||` to ensure string values are not empty - -## 0.0.16 - -### Patch Changes - -- 626d420: Fixed DM group syncing across installations - -## 0.0.15 - -### Patch Changes - -- cf6fbc0: Added default history sync URL to client with option to override - -## 0.0.14 - -### Patch Changes - -- c91612d: Added support for HMAC keys - -## 0.0.13 - -### Patch Changes - -- b4f452c: Added installation ID bytes to inbox state - -## 0.0.12 - -### Patch Changes - -- d09ec27: - - Added support for revoking specific installations - - Refactored `list`, `listGroups`, and `listDms` to be synchronous when called from worker - -## 0.0.11 - -### Patch Changes - -- 3a1e53b: Enabled group permissions updates - - Added `updatePermission` method to `Conversation` - - Refactored `permissions` getter to async function - - Exported `MetadataField` type - -## 0.0.10 - -### Patch Changes - -- dad39c4: - - Added admins and super admins to conversation data sync - - Refactored `Conversation` admin and super admin accessors - - Changed `admins` and `superAdmins` to getters - - Added `syncAdmins` and `syncSuperAdmins` methods - - Refactored `Conversations.getConversationById`, `Conversations.listDms`, `Conversations.listGroups`, and `Conversations.getDmByInboxId` to return `Conversation` instances - - Refactored `Conversations.getMessageById` to return `DecodedMessage` instance - -## 0.0.9 - -### Patch Changes - -- a35afb8: Upgraded bindings, refactored some methods to be async - -## 0.0.8 - -### Patch Changes - -- 8120a39: Added support for custom permissions policy - -## 0.0.7 - -### Patch Changes - -- 1777a23: Dropped support for CommonJS -- Updated dependencies [1777a23] - - @xmtp/content-type-group-updated@2.0.0 - - @xmtp/content-type-primitives@2.0.0 - - @xmtp/content-type-text@2.0.0 - -## 0.0.6 - -### Patch Changes - -- 9324310: - - Added `installationIdBytes` to `Client` - - Added `Conversations.syncAll` method - - Added `signWithInstallationKey`, `verifySignedWithInstallationKey`, and `verifySignedWithPublicKey` methods to `Client` - -## 0.0.5 - -### Patch Changes - -- 63e5276: Updated exports -- Updated dependencies [63e5276] - - @xmtp/content-type-group-updated@1.0.1 - - @xmtp/content-type-primitives@1.0.3 - - @xmtp/content-type-text@1.0.1 - - @xmtp/proto@3.72.0 - -## 0.0.4 - -### Patch Changes - -- a1a16a0: - - Added `Signer` interface - - Refactored `Client.create` to accept a `Signer` instead of account address - - Refactored client creation to automatically register and identity - - Added `disableAutoRegister` to `ClientOptions` to allow disabling of client registration after creation - - Removed direct access to all signature functions - - Added `Client.register` method for registering a client - - Added `Client.addAccount` method for adding another account to an installation - - Added `Client.removeAccount` method for removing an account from an installation - - Added `Client.revokeInstallations` method for revoking all other installations - - Added static `Client.canMessage` for checking if an address is on the network without a client - -## 0.0.3 - -### Patch Changes - -- f3734c8: - - Upgraded to latest WASM bindings - - Required `encryptionKey` when creating a new client - - Added smart contract wallet signature support - - Added more logging options - - Updated WASM bindings re-exports - -## 0.0.2 - -### Patch Changes - -- 5479e31: Upgraded to latest WASM bindings - -## 0.0.1 - -Initial release diff --git a/sdks/browser-sdk/LICENSE b/sdks/browser-sdk/LICENSE deleted file mode 100644 index ae6695abd..000000000 --- a/sdks/browser-sdk/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 XMTP (xmtp.org) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/sdks/browser-sdk/README.md b/sdks/browser-sdk/README.md deleted file mode 100644 index f3c9225fb..000000000 --- a/sdks/browser-sdk/README.md +++ /dev/null @@ -1,108 +0,0 @@ -# XMTP client SDK for browsers - -This package provides the XMTP client SDK for browsers. - -To keep up with the latest SDK developments, see the [Issues tab](https://github.com/xmtp/xmtp-js/issues) in this repo. - -## Documentation - -To learn how to use the XMTP client SDK for browsers, see [Get started with the XMTP Browser SDK](https://docs.xmtp.org/sdks/browser). - -## SDK reference - -Coming soon - -## Limitations - -This SDK uses the [origin private file system](https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system) (OPFS) to persist a SQLite database and the [SyncAccessHandle Pool VFS](https://sqlite.org/wasm/doc/trunk/persistence.md#vfs-opfs-sahpool) to access it. This VFS does not support multiple simultaneous connections. - -This means that when using this SDK in your app, you must prevent multiple browser tabs or windows from accessing your app at the same time. - -### Bundlers - -This SDK and some of its dependencies use `import.meta.url`. Some bundlers must be configured to account for this during development. - -#### Vite - -Add the following to `vite.config.ts`: - -```typescript -import { defineConfig } from "vite"; - -export default defineConfig({ - optimizeDeps: { - exclude: ["@xmtp/wasm-bindings", "@xmtp/browser-sdk"], - include: ["@xmtp/proto"], - }, -}); -``` - -## Install - -**NPM** - -```bash -npm install @xmtp/browser-sdk -``` - -**PNPM** - -```bash -pnpm install @xmtp/browser-sdk -``` - -**Yarn** - -```bash -yarn add @xmtp/browser-sdk -``` - -## Signer utilities - -The SDK exports `createEOASigner` and `createSCWSigner` helper functions for creating XMTP-compatible signers. These require `viem` as a peer dependency, which is optional and only needs to be installed if you use these utilities. - -```bash -npm install viem -``` - -**Example** - -```ts -import { createEOASigner } from "@xmtp/browser-sdk"; - -// Create an EOA signer (generates a random key if none provided) -const eoaSigner = createEOASigner(); -``` - -## Developing - -Run `yarn dev` to build the SDK and watch for changes, which will trigger a rebuild. - -### Useful commands - -- `yarn build`: Builds the SDK -- `yarn clean`: Removes `node_modules`, `dist`, and `.turbo` folders -- `yarn dev`: Builds the SDK and watches for changes, which will trigger a rebuild -- `yarn test`: Runs all tests -- `yarn typecheck`: Runs `tsc` - -## Breaking revisions - -Because this SDK is in active development, you should expect breaking revisions that might require you to adopt the latest SDK release to enable your app to continue working as expected. - -Breaking revisions in a Browser SDK release are described on the [Releases page](https://github.com/xmtp/xmtp-js/releases). - -## Deprecation - -Older versions of the SDK will eventually be deprecated, which means: - -1. The network will not support and eventually actively reject connections from clients using deprecated versions. -2. Bugs will not be fixed in deprecated versions. - -The following table provides the deprecation schedule. - -| Announced | Effective | Minimum Version | Rationale | -| --------------------------- | ----------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| No more support for XMTP V2 | May 1, 2025 | >=1.1.4 | In a move toward better security with MLS and the ability to decentralize, we will be shutting down XMTP V2 and moving entirely to XMTP V3. To learn more about V2 deprecation, see [XIP-53: XMTP V2 deprecation plan](https://community.xmtp.org/t/xip-53-xmtp-v2-deprecation-plan/867). To learn how to upgrade, see [@xmtp/browser-sdk v1.1.4](https://github.com/xmtp/xmtp-js/releases/tag/%40xmtp%2Fbrowser-sdk%401.1.4). | - -Bug reports, feature requests, and PRs are welcome in accordance with these [contribution guidelines](https://github.com/xmtp/xmtp-js/blob/main/CONTRIBUTING.md). diff --git a/sdks/browser-sdk/package.json b/sdks/browser-sdk/package.json deleted file mode 100644 index 077122f89..000000000 --- a/sdks/browser-sdk/package.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "name": "@xmtp/browser-sdk", - "version": "7.0.0", - "description": "XMTP client SDK for browsers written in TypeScript", - "keywords": [ - "xmtp", - "messaging", - "web3", - "sdk", - "js", - "ts", - "javascript", - "typescript" - ], - "homepage": "https://github.com/xmtp/xmtp-js", - "bugs": { - "url": "https://github.com/xmtp/xmtp-js/issues" - }, - "repository": { - "type": "git", - "url": "git+ssh://git@github.com/xmtp/xmtp-js.git", - "directory": "sdks/browser-sdk" - }, - "license": "MIT", - "author": "XMTP Labs ", - "sideEffects": false, - "type": "module", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "./package.json": "./package.json" - }, - "main": "dist/index.js", - "types": "dist/index.d.ts", - "files": [ - "dist", - "src" - ], - "scripts": { - "build": "yarn clean:dist && yarn rollup -c", - "clean": "rm -rf .turbo && rm -rf node_modules && yarn clean:dist", - "clean:dist": "rm -rf dist", - "dev": "yarn clean:dist && yarn rollup -c --watch", - "test": "vitest run", - "test:debug": "vitest run --inspect-brk --no-file-parallelism", - "typecheck": "tsc" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 3 chrome versions", - "last 3 firefox versions", - "last 3 safari versions" - ] - }, - "dependencies": { - "@xmtp/content-type-primitives": "3.0.0", - "@xmtp/wasm-bindings": "1.11.0-nightly.20260603.89c3fc3" - }, - "devDependencies": { - "@rollup/plugin-terser": "^0.4.4", - "@rollup/plugin-typescript": "^12.3.0", - "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^6.9.1", - "@vitest/browser": "^4.0.18", - "@vitest/browser-playwright": "^4.0.18", - "@vitest/coverage-v8": "^4.0.18", - "@web/rollup-plugin-copy": "^0.5.1", - "playwright": "^1.58.0", - "rollup": "^4.59.0", - "rollup-plugin-dts": "^6.3.0", - "rollup-plugin-tsconfig-paths": "^1.5.2", - "typescript": "^5.9.3", - "viem": "^2.44.4", - "vite": "^7.3.1", - "vite-tsconfig-paths": "^6.0.4", - "vitest": "^4.0.18" - }, - "peerDependencies": { - "viem": ">=2" - }, - "peerDependenciesMeta": { - "viem": { - "optional": true - } - }, - "engines": { - "node": ">=22" - }, - "publishConfig": { - "access": "public", - "provenance": true, - "registry": "https://registry.npmjs.org/" - } -} diff --git a/sdks/browser-sdk/rollup.config.js b/sdks/browser-sdk/rollup.config.js deleted file mode 100644 index 21dbf9f77..000000000 --- a/sdks/browser-sdk/rollup.config.js +++ /dev/null @@ -1,63 +0,0 @@ -import terser from "@rollup/plugin-terser"; -import typescript from "@rollup/plugin-typescript"; -import { defineConfig } from "rollup"; -import { dts } from "rollup-plugin-dts"; -import tsConfigPaths from "rollup-plugin-tsconfig-paths"; - -const plugins = [ - tsConfigPaths(), - typescript({ - declaration: false, - declarationMap: false, - }), - terser(), -]; - -const external = [ - "@xmtp/content-type-text", - "@xmtp/wasm-bindings", - "@xmtp/content-type-primitives", - "@xmtp/content-type-group-updated", - "uuid", -]; - -export default defineConfig([ - { - input: "src/index.ts", - output: { - file: "dist/index.js", - format: "es", - sourcemap: true, - }, - plugins, - external, - }, - { - input: "src/workers/client.ts", - output: { - file: "dist/workers/client.js", - format: "es", - sourcemap: true, - }, - plugins, - external, - }, - { - input: "src/workers/opfs.ts", - output: { - file: "dist/workers/opfs.js", - format: "es", - sourcemap: true, - }, - plugins, - external, - }, - { - input: "src/index.ts", - output: { - file: "dist/index.d.ts", - format: "es", - }, - plugins: [tsConfigPaths(), dts()], - }, -]); diff --git a/sdks/browser-sdk/src/AsyncStream.ts b/sdks/browser-sdk/src/AsyncStream.ts deleted file mode 100644 index d4eead7c1..000000000 --- a/sdks/browser-sdk/src/AsyncStream.ts +++ /dev/null @@ -1,189 +0,0 @@ -type ResolveValue = { - value: T; - done: boolean; -}; - -type ResolveNext = (resolveValue: ResolveValue) => void; - -/** - * AsyncStream provides an async iterable interface for streaming data. - * - * This class implements a producer-consumer pattern where: - * - Producers can push values using the `push()` method - * - Consumers can iterate over values asynchronously using `for await` loops or `next()` - * - Values are queued internally when no consumers are waiting - * - Consumers are resolved immediately when values are available - * - The stream can be terminated using `done()`, `return()`, or `end()` - * - * @example - * ```typescript - * const stream = new AsyncStream(); - * - * stream.push("hello"); - * stream.push("world"); - * - * for await (const value of stream) { - * console.log(value); // "hello", "world" - * } - * ``` - */ -export class AsyncStream { - isDone = false; - #pendingResolves: ResolveNext[] = []; - #queue: T[]; - onDone: (() => void) | undefined; - onReturn: (() => void) | undefined; - - constructor() { - this.#queue = []; - this.isDone = false; - } - - flush() { - while (this.#pendingResolves.length > 0) { - const nextResolve = this.#pendingResolves.shift(); - if (nextResolve) { - nextResolve({ done: true, value: undefined }); - } - } - } - - done() { - this.flush(); - this.#queue = []; - this.#pendingResolves = []; - this.isDone = true; - this.onDone?.(); - } - - push = (value: T) => { - if (this.isDone) { - return; - } - - const nextResolve = this.#pendingResolves.shift(); - if (nextResolve) { - nextResolve({ - done: false, - value, - }); - } else { - this.#queue.push(value); - } - }; - - next = (): Promise> => { - if (this.isDone) { - return Promise.resolve({ done: true, value: undefined }); - } - - if (this.#queue.length > 0) { - return Promise.resolve({ - done: false, - value: this.#queue.shift(), - }); - } - - return new Promise((resolve) => { - this.#pendingResolves.push(resolve); - }); - }; - - return = (): Promise> => { - this.onReturn?.(); - this.done(); - - return Promise.resolve({ - done: true, - value: undefined, - }); - }; - - end = () => this.return(); - - [Symbol.asyncIterator]() { - return this; - } -} - -export interface AsyncStreamProxy extends AsyncIterable { - next(): Promise>; - return(): Promise>; - end(): Promise>; - isDone: boolean; -} - -const usableProperties = [ - "end", - "isDone", - "next", - "return", - Symbol.asyncIterator, -]; -const isUsableProperty = ( - prop: string | symbol, -): prop is keyof AsyncStreamProxy => { - return usableProperties.includes(prop); -}; - -/** - * Creates a read-only proxy for AsyncStream instances that restricts access to consumer-only methods. - * - * This proxy only exposes the following properties and methods: - * - `next()`: Get the next value from the stream - * - `end()`: Terminate the stream and stop iteration - * - `return()`: Same as end(), terminates the stream - * - `isDone`: Boolean indicating if the stream has been terminated - * - `Symbol.asyncIterator`: Enables `for await` loop iteration - * - * Producer methods like `push()`, `done()`, and `flush()` are hidden to prevent - * consumers from accidentally modifying the stream state. - * - * @param stream - The AsyncStream instance to create a proxy for - * @returns A read-only proxy that implements AsyncStreamProxy - * - * @example - * ```typescript - * const stream = new AsyncStream(); - * const proxy = createAsyncStreamProxy(stream); - * - * stream.push("hello"); - * stream.push("world"); - * - * for await (const value of proxy) { - * console.log(value); // "hello", "world" - * } - * ``` - */ -export function createAsyncStreamProxy(stream: AsyncStream) { - return new Proxy(stream, { - get(target, prop, receiver) { - if (isUsableProperty(prop)) { - return Reflect.get(target, prop, receiver); - } - }, - - set() { - return true; - }, - - has(_target, prop) { - return isUsableProperty(prop); - }, - - ownKeys() { - return usableProperties; - }, - - getOwnPropertyDescriptor(target, prop) { - if (isUsableProperty(prop)) { - return { - enumerable: true, - configurable: true, - value: Reflect.get(target, prop), - }; - } - return undefined; - }, - }) as AsyncStreamProxy; -} diff --git a/sdks/browser-sdk/src/Client.ts b/sdks/browser-sdk/src/Client.ts deleted file mode 100644 index 096c23d48..000000000 --- a/sdks/browser-sdk/src/Client.ts +++ /dev/null @@ -1,1089 +0,0 @@ -import { type ContentCodec } from "@xmtp/content-type-primitives"; -import { - Backend, - BackupElementSelectionOption, - IdentifierKind, - LogLevel, - type ArchiveMetadata, - type ArchiveOptions, - type AvailableArchiveInfo, - type GroupSyncSummary, - type Identifier, - type InboxState, -} from "@xmtp/wasm-bindings"; -import { CodecRegistry } from "@/CodecRegistry"; -import { HistorySyncUrls } from "@/constants"; -import { Conversations } from "@/Conversations"; -import { DebugInformation } from "@/DebugInformation"; -import { Preferences } from "@/Preferences"; -import type { ClientWorkerAction } from "@/types/actions"; -import type { - ClientOptions, - ExtractCodecContentTypes, - XmtpEnv, -} from "@/types/options"; -import { createBackend } from "@/utils/createBackend"; -import { createClient as createLowLevelClient } from "@/utils/createClient"; -import { - AccountAlreadyAssociatedError, - InboxReassignError, - SignerUnavailableError, -} from "@/utils/errors"; -import { getInboxIdForIdentifier } from "@/utils/inboxId"; -import { inboxStateFromInboxIds as utilsInboxStateFromInboxIds } from "@/utils/inboxState"; -import { revokeInstallations as utilsRevokeInstallations } from "@/utils/installations"; -import { toSafeSigner, type SafeSigner, type Signer } from "@/utils/signer"; -import { uuid } from "@/utils/uuid"; -import { WorkerBridge } from "@/utils/WorkerBridge"; - -/** - * Resolves a `Backend` instance from either a `Backend` or an `XmtpEnv` string. - * - * @param envOrBackend - A `Backend` instance, or an `XmtpEnv` string - * @param gatewayHost - Optional gateway host (only used when `envOrBackend` is an `XmtpEnv`) - * @returns A `Backend` instance - */ -const resolveBackend = async ( - envOrBackend?: XmtpEnv | Backend, - gatewayHost?: string, -): Promise => { - if (envOrBackend instanceof Backend) { - return envOrBackend; - } - return createBackend({ env: envOrBackend, gatewayHost }); -}; - -const createEphemeralIdentifier = (): Identifier => { - const bytes = new Uint8Array(20); - globalThis.crypto.getRandomValues(bytes); - - return { - identifier: `0x${Array.from(bytes, (byte) => - byte.toString(16).padStart(2, "0"), - ).join("")}`, - identifierKind: IdentifierKind.Ethereum, - }; -}; - -const toInboxUpdatesCountMap = ( - value: Map | Record, -) => { - if (value instanceof Map) { - return value; - } - - return new Map(Object.entries(value)); -}; - -/** - * Client for interacting with the XMTP network - */ -export class Client { - #appVersion?: string; - #codecRegistry: CodecRegistry; - #conversations: Conversations; - #debugInformation: DebugInformation; - #env?: XmtpEnv; - #identifier?: Identifier; - #inboxId?: string; - #installationId?: string; - #installationIdBytes?: Uint8Array; - #isReady = false; - #libxmtpVersion?: string; - #options?: ClientOptions; - #preferences: Preferences; - #signer?: Signer; - #worker: WorkerBridge; - - /** - * Creates a new XMTP client instance - * - * This class is not intended to be initialized directly. - * Use `Client.create` or `Client.build` instead. - * - * @param options - Optional configuration for the client - */ - constructor(options?: ClientOptions) { - /* - * The Browser SDK runs XMTP's WASM bindings inside a Web Worker. - * The SDK sends options to the worker via postMessage(), which uses the - * structured clone algorithm. Codecs contain functions that can't be - * cloned, so we mark the codecs property as non-enumerable to exclude - * it from serialization. - * - * @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#things_that_dont_work_with_structured_clone - */ - if (options) { - Object.defineProperty(options, "codecs", { - value: options.codecs, - enumerable: false, - }); - } - const worker = new Worker(new URL("./workers/client", import.meta.url), { - type: "module", - }); - const enableLogging = - options?.loggingLevel !== undefined && - options.loggingLevel !== LogLevel.Off; - this.#worker = new WorkerBridge(worker, enableLogging); - this.#codecRegistry = new CodecRegistry([...(options?.codecs ?? [])]); - this.#options = options; - this.#conversations = new Conversations( - this, - this.#worker, - this.#codecRegistry, - ); - this.#debugInformation = new DebugInformation(this.#worker); - this.#preferences = new Preferences(this.#worker); - } - - /** - * Initializes the client with the provided identifier - * - * This is not meant to be called directly. - * Use `Client.create` or `Client.build` instead. - * - * @param identifier - The identifier to initialize the client with - */ - async init(identifier: Identifier) { - const result = await this.#worker.action("client.init", { - identifier, - options: this.#options, - }); - this.#appVersion = result.appVersion; - this.#env = result.env as XmtpEnv; - this.#identifier = identifier; - this.#inboxId = result.inboxId; - this.#installationId = result.installationId; - this.#installationIdBytes = result.installationIdBytes; - this.#libxmtpVersion = result.libxmtpVersion; - this.#isReady = true; - } - - /** - * Shutdown the client - */ - close() { - this.#worker.close(); - this.#isReady = false; - } - - /** - * Creates a new client instance with a signer - * - * @param signer - The signer to use for authentication - * @param options - Optional configuration for the client - * @returns A new client instance - */ - static async create( - signer: Signer, - options?: Omit & { - codecs?: ContentCodecs; - }, - ) { - const client = new Client>(options); - client.#signer = signer; - - await client.init(await signer.getIdentifier()); - - if (!options?.disableAutoRegister) { - await client.register(); - } - - return client; - } - - /** - * Creates a new client instance with an identifier - * - * Clients created with this method must already be registered. - * Any methods called that require a signer will throw an error. - * - * @param identifier - The identifier to use - * @param options - Optional configuration for the client - * @returns A new client instance - */ - static async build( - identifier: Identifier, - options?: Omit & { - codecs?: ContentCodecs; - }, - ) { - const client = new Client>({ - ...options, - disableAutoRegister: true, - }); - await client.init(identifier); - return client; - } - - /** - * Gets the client options - */ - get options() { - return this.#options; - } - - /** - * Gets the signer associated with this client - */ - get signer() { - return this.#signer; - } - - /** - * Gets whether the client has been initialized - */ - get isReady() { - return this.#isReady; - } - - /** - * Gets the inbox ID associated with this client - */ - get inboxId() { - return this.#inboxId; - } - - /** - * Gets the account identifier for this client - */ - get accountIdentifier() { - return this.#identifier; - } - - /** - * Gets the installation ID for this client - */ - get installationId() { - return this.#installationId; - } - - /** - * Gets the installation ID bytes for this client - */ - get installationIdBytes() { - return this.#installationIdBytes; - } - - /** - * Gets the conversations manager for this client - */ - get conversations() { - return this.#conversations; - } - - /** - * Gets the debug information helpers for this client - */ - get debugInformation() { - return this.#debugInformation; - } - - /** - * Gets the preferences manager for this client - */ - get preferences() { - return this.#preferences; - } - - /** - * Gets the version of libxmtp used in the bindings - */ - get libxmtpVersion() { - return this.#libxmtpVersion; - } - - /** - * Gets the app version used by the client - */ - get appVersion() { - return this.#appVersion; - } - - /** - * Gets the XMTP environment used by this client - */ - get env() { - return this.#env; - } - - /** - * Creates signature text for creating a new inbox - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `register` method instead. - * - * @returns The signature text and signature request ID - */ - async unsafe_createInboxSignatureText() { - return this.#worker.action("client.createInboxSignatureText", { - signatureRequestId: uuid(), - }); - } - - /** - * Creates signature text for adding a new account to the client's inbox - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `unsafe_addAccount` method instead. - * - * @param newIdentifier - The identifier of the new account - * @param allowInboxReassign - Whether to allow inbox reassignment - * @throws {InboxReassignError} if `allowInboxReassign` is false - * @returns The signature text and signature request ID - */ - async unsafe_addAccountSignatureText( - newIdentifier: Identifier, - allowInboxReassign: boolean = false, - ) { - if (!allowInboxReassign) { - throw new InboxReassignError(); - } - - return this.#worker.action("client.addAccountSignatureText", { - newIdentifier, - signatureRequestId: uuid(), - }); - } - - /** - * Creates signature text for removing an account from the client's inbox - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `removeAccount` method instead. - * - * @param identifier - The identifier of the account to remove - * @returns The signature text and signature request ID - */ - async unsafe_removeAccountSignatureText(identifier: Identifier) { - return this.#worker.action("client.removeAccountSignatureText", { - identifier, - signatureRequestId: uuid(), - }); - } - - /** - * Creates signature text for revoking all other installations of the - * client's inbox - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `revokeAllOtherInstallations` method instead. - * - * @returns The signature text and signature request ID - */ - async unsafe_revokeAllOtherInstallationsSignatureText() { - return this.#worker.action( - "client.revokeAllOtherInstallationsSignatureText", - { - signatureRequestId: uuid(), - }, - ); - } - - /** - * Creates signature text for revoking specific installations of the - * client's inbox - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `revokeInstallations` method instead. - * - * @param installationIds - The installation IDs to revoke - * @returns The signature text and signature request ID - */ - async unsafe_revokeInstallationsSignatureText(installationIds: Uint8Array[]) { - return this.#worker.action("client.revokeInstallationsSignatureText", { - installationIds, - signatureRequestId: uuid(), - }); - } - - /** - * Creates signature text for changing the recovery identifier for this - * client's inbox - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `changeRecoveryIdentifier` method instead. - * - * @param identifier - The new recovery identifier - * @returns The signature text and signature request ID - */ - async unsafe_changeRecoveryIdentifierSignatureText(identifier: Identifier) { - return this.#worker.action("client.changeRecoveryIdentifierSignatureText", { - identifier, - signatureRequestId: uuid(), - }); - } - - /** - * Applies a signature request to the client - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `register`, `unsafe_addAccount`, - * `removeAccount`, `revokeAllOtherInstallations`, `revokeInstallations`, - * or `changeRecoveryIdentifier` method instead. - * - * @param signer - The signer to use - * @param signatureRequestId - The ID of the signature request to apply - */ - async unsafe_applySignatureRequest( - signer: SafeSigner, - signatureRequestId: string, - ) { - return this.#worker.action("client.applySignatureRequest", { - signer, - signatureRequestId, - }); - } - - /** - * Registers the client with the XMTP network - * - * Requires a signer, use `Client.create` to create a client with a signer. - * - * @throws {SignerUnavailableError} if no signer is available - */ - async register() { - if (!this.#signer) { - throw new SignerUnavailableError(); - } - - const { signatureText, signatureRequestId } = - await this.unsafe_createInboxSignatureText(); - - // if the signature text or request ID is not available, don't register - if (!signatureText || !signatureRequestId) { - return; - } - - const signature = await this.#signer.signMessage(signatureText); - const signer = await toSafeSigner(this.#signer, signature); - - return this.#worker.action("client.registerIdentity", { - signer, - signatureRequestId, - waitForRegistrationVisible: this.#options?.waitForRegistrationVisible, - }); - } - - /** - * Adds a new account to the client inbox - * - * WARNING: This function should be used with caution. Adding a wallet already - * associated with an inbox ID will cause the wallet to lose access to - * that inbox. - * - * The `allowInboxReassign` parameter must be true to reassign an inbox - * already associated with a different account. - * - * Requires a signer, use `Client.create` to create a client with a signer. - * - * @param newAccountSigner - The signer for the new account - * @param allowInboxReassign - Whether to allow inbox reassignment - * @throws {SignerUnavailableError} if no signer is available - * @throws {InboxReassignError} if `allowInboxReassign` is false - * @throws {AccountAlreadyAssociatedError} if the account is already associated with an inbox ID - */ - async unsafe_addAccount( - newAccountSigner: Signer, - allowInboxReassign: boolean = false, - ) { - if (!this.#signer) { - throw new SignerUnavailableError(); - } - - if (!allowInboxReassign) { - throw new InboxReassignError(); - } - - // check for existing inbox id - const existingInboxId = await this.fetchInboxIdByIdentifier( - await newAccountSigner.getIdentifier(), - ); - - if (existingInboxId) { - throw new AccountAlreadyAssociatedError(existingInboxId); - } - - const { signatureText, signatureRequestId } = - await this.unsafe_addAccountSignatureText( - await newAccountSigner.getIdentifier(), - true, - ); - const signature = await newAccountSigner.signMessage(signatureText); - const signer = await toSafeSigner(newAccountSigner, signature); - return this.#worker.action("client.addAccount", { - identifier: signer.identifier, - signer, - signatureRequestId, - }); - } - - /** - * Removes an account from the client's inbox - * - * Requires a signer, use `Client.create` to create a client with a signer. - * - * @param accountIdentifier - The identifier of the account to remove - * @throws {SignerUnavailableError} if no signer is available - */ - async removeAccount(identifier: Identifier) { - if (!this.#signer) { - throw new SignerUnavailableError(); - } - - const { signatureText, signatureRequestId } = - await this.unsafe_removeAccountSignatureText(identifier); - const signature = await this.#signer.signMessage(signatureText); - const signer = await toSafeSigner(this.#signer, signature); - - return this.#worker.action("client.removeAccount", { - identifier, - signer, - signatureRequestId, - }); - } - - /** - * Revokes all other installations of the client's inbox - * - * Requires a signer, use `Client.create` to create a client with a signer. - * - * @throws {SignerUnavailableError} if no signer is available - */ - async revokeAllOtherInstallations() { - if (!this.#signer) { - throw new SignerUnavailableError(); - } - - const { signatureText, signatureRequestId } = - await this.unsafe_revokeAllOtherInstallationsSignatureText(); - - // no other installations to revoke, nothing to do - if (!signatureText) { - return; - } - - const signature = await this.#signer.signMessage(signatureText); - const signer = await toSafeSigner(this.#signer, signature); - - return this.#worker.action("client.revokeAllOtherInstallations", { - signer, - signatureRequestId, - }); - } - - /** - * Revokes specific installations of the client's inbox - * - * Requires a signer, use `Client.create` to create a client with a signer. - * - * @param installationIds - The installation IDs to revoke - * @throws {SignerUnavailableError} if no signer is available - */ - async revokeInstallations(installationIds: Uint8Array[]) { - if (!this.#signer) { - throw new SignerUnavailableError(); - } - - const { signatureText, signatureRequestId } = - await this.unsafe_revokeInstallationsSignatureText(installationIds); - const signature = await this.#signer.signMessage(signatureText); - const signer = await toSafeSigner(this.#signer, signature); - - return this.#worker.action("client.revokeInstallations", { - installationIds, - signer, - signatureRequestId, - }); - } - - /** - * Revokes specific installations of the client's inbox without a client - * - * @param signer - The signer to use - * @param inboxId - The inbox ID to revoke installations for - * @param installationIds - The installation IDs to revoke - * @param backend - Optional `Backend` instance created with `createBackend()` - */ - static async revokeInstallations( - signer: Signer, - inboxId: string, - installationIds: Uint8Array[], - backend?: Backend, - ): Promise; - /** - * Revokes specific installations of the client's inbox without a client - * - * @param signer - The signer to use - * @param inboxId - The inbox ID to revoke installations for - * @param installationIds - The installation IDs to revoke - * @param env - The environment to use - * @param gatewayHost - Optional gateway host - * @deprecated Pass a `Backend` instance created with `createBackend()` instead - * of `XmtpEnv` and `gatewayHost`. - */ - static async revokeInstallations( - signer: Signer, - inboxId: string, - installationIds: Uint8Array[], - env?: XmtpEnv, - gatewayHost?: string, - ): Promise; - static async revokeInstallations( - signer: Signer, - inboxId: string, - installationIds: Uint8Array[], - envOrBackend?: XmtpEnv | Backend, - gatewayHost?: string, - ) { - const backend = await resolveBackend(envOrBackend, gatewayHost); - await utilsRevokeInstallations(backend, signer, inboxId, installationIds); - } - - /** - * Fetches the inbox states for the specified inbox IDs from the network - * without a client - * - * @param inboxIds - The inbox IDs to get the state for - * @param backend - Optional `Backend` instance created with `createBackend()` - * @returns The inbox states for the specified inbox IDs - */ - static async fetchInboxStates( - inboxIds: string[], - backend?: Backend, - ): Promise; - /** - * Fetches the inbox states for the specified inbox IDs from the network - * without a client - * - * @param inboxIds - The inbox IDs to get the state for - * @param env - The environment to use - * @param gatewayHost - Optional gateway host - * @returns The inbox states for the specified inbox IDs - * @deprecated Pass a `Backend` instance created with `createBackend()` instead - * of `XmtpEnv` and `gatewayHost`. - */ - static async fetchInboxStates( - inboxIds: string[], - env?: XmtpEnv, - gatewayHost?: string, - ): Promise; - static async fetchInboxStates( - inboxIds: string[], - envOrBackend?: XmtpEnv | Backend, - gatewayHost?: string, - ) { - const backend = await resolveBackend(envOrBackend, gatewayHost); - return utilsInboxStateFromInboxIds(backend, inboxIds); - } - - /** - * Changes the recovery identifier for the client's inbox - * - * Requires a signer, use `Client.create` to create a client with a signer. - * - * @param identifier - The new recovery identifier - * @throws {SignerUnavailableError} if no signer is available - */ - async changeRecoveryIdentifier(identifier: Identifier) { - if (!this.#signer) { - throw new SignerUnavailableError(); - } - - const { signatureText, signatureRequestId } = - await this.unsafe_changeRecoveryIdentifierSignatureText(identifier); - const signature = await this.#signer.signMessage(signatureText); - const signer = await toSafeSigner(this.#signer, signature); - - return this.#worker.action("client.changeRecoveryIdentifier", { - identifier, - signer, - signatureRequestId, - }); - } - - /** - * Checks if the client is registered with the XMTP network - * - * @returns Whether the client is registered - */ - async isRegistered() { - return this.#worker.action("client.isRegistered"); - } - - /** - * Checks if the client can message the specified identifiers - * - * @param identifiers - The identifiers to check - * @returns Whether the client can message the identifiers - */ - async canMessage(identifiers: Identifier[]) { - return this.#worker.action("client.canMessage", { identifiers }); - } - - /** - * Fetches the latest inbox updates count for the specified inbox IDs - * - * @param inboxIds - The inbox IDs to check - * @returns Map of inbox IDs to their updates count - */ - async fetchLatestInboxUpdatesCount(inboxIds: string[]) { - const result = await this.#worker.action( - "client.fetchLatestInboxUpdatesCount", - { - inboxIds, - }, - ); - - return toInboxUpdatesCountMap(result); - } - - /** - * Fetches the latest inbox updates count for the client's inbox - * - * @returns The latest inbox updates count - */ - async fetchOwnInboxUpdatesCount() { - return this.#worker.action("client.fetchOwnInboxUpdatesCount", {}); - } - - /** - * Checks if the specified identifiers can be messaged - * - * @param identifiers - The identifiers to check - * @param backend - Optional `Backend` instance created with `createBackend()` - * @returns Map of identifiers to whether they can be messaged - */ - static async canMessage( - identifiers: Identifier[], - backend?: Backend, - ): Promise>; - /** - * Checks if the specified identifiers can be messaged - * - * @param identifiers - The identifiers to check - * @param env - Optional XMTP environment - * @returns Map of identifiers to whether they can be messaged - * @deprecated Pass a `Backend` instance created with `createBackend()` instead - * of `XmtpEnv`. - */ - /* eslint-disable @typescript-eslint/unified-signatures */ - static async canMessage( - identifiers: Identifier[], - env?: XmtpEnv, - ): Promise>; - /* eslint-enable @typescript-eslint/unified-signatures */ - static async canMessage( - identifiers: Identifier[], - envOrBackend?: XmtpEnv | Backend, - ) { - const backend = await resolveBackend(envOrBackend); - const canMessageMap = new Map(); - for (const identifier of identifiers) { - const inboxId = await getInboxIdForIdentifier(backend, identifier); - canMessageMap.set( - identifier.identifier.toLowerCase(), - inboxId !== undefined, - ); - } - return canMessageMap; - } - - /** - * Fetches the latest inbox updates count for the specified inbox IDs - * without a client - * - * @param inboxIds - The inbox IDs to check - * @param backend - Optional `Backend` instance created with `createBackend()` - * @returns Map of inbox IDs to their updates count - */ - static async fetchLatestInboxUpdatesCount( - inboxIds: string[], - backendOrEnv?: Backend | XmtpEnv, - ): Promise>; - /** - * Fetches the latest inbox updates count for the specified inbox IDs - * without a client - * - * @param inboxIds - The inbox IDs to check - * @param env - Optional XMTP environment - * @param gatewayHost - Optional gateway host - * @returns Map of inbox IDs to their updates count - * @deprecated Pass a `Backend` instance created with `createBackend()` instead - * of `XmtpEnv` and `gatewayHost`. - */ - static async fetchLatestInboxUpdatesCount( - inboxIds: string[], - env?: XmtpEnv, - gatewayHost?: string, - ): Promise>; - static async fetchLatestInboxUpdatesCount( - inboxIds: string[], - envOrBackend?: XmtpEnv | Backend, - gatewayHost?: string, - ) { - const backend = await resolveBackend(envOrBackend, gatewayHost); - const { client } = await createLowLevelClient(createEphemeralIdentifier(), { - backend, - dbPath: null, - disableDeviceSync: true, - }); - // The wasm-bindings Client holds WASM-linear-memory allocations that are - // not reclaimed by the JS GC. Free the ephemeral client in finally so the - // allocation is released even if the fetch rejects. - try { - const result = (await client.fetchLatestInboxUpdatesCount( - true, - inboxIds, - )) as Record | Map; - - return toInboxUpdatesCountMap(result); - } finally { - client.free(); - } - } - - /** - * Fetches the inbox ID for a given identifier from the local database - * If not found, fetches from the network - * - * @param identifier - The identifier to look up - * @returns The inbox ID, if found - */ - async fetchInboxIdByIdentifier(identifier: Identifier) { - return this.#worker.action("client.getInboxIdByIdentifier", { identifier }); - } - - /** - * Signs a message with the installation key - * - * @param signatureText - The text to sign - * @returns The signature - */ - signWithInstallationKey(signatureText: string) { - return this.#worker.action("client.signWithInstallationKey", { - signatureText, - }); - } - - /** - * Verifies a signature was made with the installation key - * - * @param signatureText - The text that was signed - * @param signatureBytes - The signature bytes to verify - * @returns Whether the signature is valid - */ - verifySignedWithInstallationKey( - signatureText: string, - signatureBytes: Uint8Array, - ) { - return this.#worker.action("client.verifySignedWithInstallationKey", { - signatureText, - signatureBytes, - }); - } - - /** - * Verifies a signature was made with a public key - * - * @param signatureText - The text that was signed - * @param signatureBytes - The signature bytes to verify - * @param publicKey - The public key to verify against - * @returns Whether the signature is valid - */ - verifySignedWithPublicKey( - signatureText: string, - signatureBytes: Uint8Array, - publicKey: Uint8Array, - ) { - return this.#worker.action("client.verifySignedWithPublicKey", { - signatureText, - signatureBytes, - publicKey, - }); - } - - /** - * Fetches the key package statuses from the network for the specified - * installation IDs - * - * @param installationIds - The installation IDs to check - * @returns The key package statuses - */ - async fetchKeyPackageStatuses(installationIds: string[]) { - return this.#worker.action("client.fetchKeyPackageStatuses", { - installationIds, - }); - } - - /** - * Get the default archive options (consent and messages) - */ - #getDefaultArchiveOptions(): ArchiveOptions { - return { - elements: [ - BackupElementSelectionOption.Consent, - BackupElementSelectionOption.Messages, - ], - excludeDisappearingMessages: false, - }; - } - - /** - * Get the default server URL based on the environment - */ - #getDefaultServerUrl(): string { - const env = this.#env ?? "dev"; - return HistorySyncUrls[env]; - } - - /** - * Send a sync request to other devices on the network - * - * @param options - Archive options specifying what to sync (defaults to consent and messages) - * @param serverUrl - The server URL for the sync request (defaults to environment-specific URL) - * @returns Promise that resolves when the sync request is sent - */ - async sendSyncRequest(options?: ArchiveOptions, serverUrl?: string) { - const resolvedOptions = options ?? this.#getDefaultArchiveOptions(); - const resolvedServerUrl = serverUrl ?? this.#getDefaultServerUrl(); - - return this.#worker.action("client.sendSyncRequest", { - options: resolvedOptions, - serverUrl: resolvedServerUrl, - }); - } - - /** - * Send a sync archive to the sync group - * - * @param pin - The pin used for reference when importing - * @param options - Archive options specifying what to sync (defaults to consent and messages) - * @param serverUrl - The server URL for the sync archive (defaults to environment-specific URL) - * @returns Promise that resolves when the sync archive is sent - */ - async sendSyncArchive( - pin: string, - options?: ArchiveOptions, - serverUrl?: string, - ) { - const resolvedOptions = options ?? this.#getDefaultArchiveOptions(); - const resolvedServerUrl = serverUrl ?? this.#getDefaultServerUrl(); - - return this.#worker.action("client.sendSyncArchive", { - options: resolvedOptions, - serverUrl: resolvedServerUrl, - pin, - }); - } - - /** - * Process a sync archive that matches the pin given - * - * @param archivePin - Optional pin to match. If not provided, processes the last archive sent - * @returns Promise that resolves when the archive is processed - */ - async processSyncArchive(archivePin?: string | null) { - return this.#worker.action("client.processSyncArchive", { - archivePin, - }); - } - - /** - * List the archives available for import in the sync group - * - * You may need to manually sync the sync group before calling - * this function to see recently uploaded archives. - * - * @param daysCutoff - Number of days to look back for archives - * @returns Promise that resolves with array of available archive information - */ - async listAvailableArchives( - daysCutoff: number, - ): Promise { - return this.#worker.action("client.listAvailableArchives", { - daysCutoff, - }); - } - - /** - * Export archive data to bytes for later restoration - * - * @param key - Encryption key for the archive - * @param opts - Archive options specifying what to include (defaults to consent and messages) - * @returns Promise that resolves with the archive data as bytes - */ - async createArchive( - key: Uint8Array, - opts?: ArchiveOptions, - ): Promise { - const resolvedOpts = opts ?? this.#getDefaultArchiveOptions(); - - return this.#worker.action("client.createArchive", { - opts: resolvedOpts, - key, - }); - } - - /** - * Import an archive from bytes - * - * @param data - The archive data as bytes - * @param key - Encryption key for the archive - * @returns Promise that resolves when the archive is imported - */ - async importArchive(data: Uint8Array, key: Uint8Array) { - return this.#worker.action("client.importArchive", { - data, - key, - }); - } - - /** - * Load the metadata for an archive to see what it contains - * - * @param data - The archive data as bytes - * @param key - Encryption key for the archive - * @returns Promise that resolves with the archive metadata - */ - async archiveMetadata( - data: Uint8Array, - key: Uint8Array, - ): Promise { - return this.#worker.action("client.archiveMetadata", { - data, - key, - }); - } - - /** - * Manually sync all device sync groups - * - * @returns Promise that resolves with a summary of the sync operation - */ - async syncAllDeviceSyncGroups(): Promise { - return this.#worker.action("client.syncAllDeviceSyncGroups"); - } -} diff --git a/sdks/browser-sdk/src/CodecRegistry.ts b/sdks/browser-sdk/src/CodecRegistry.ts deleted file mode 100644 index 901f821d4..000000000 --- a/sdks/browser-sdk/src/CodecRegistry.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { - contentTypeToString, - type ContentCodec, - type ContentTypeId, -} from "@xmtp/content-type-primitives"; - -export class CodecRegistry { - #codecs: Map; - - constructor(codecs: ContentCodec[]) { - this.#codecs = new Map( - codecs.map((codec) => [contentTypeToString(codec.contentType), codec]), - ); - } - - /** - * Gets the codec for a given content type - * - * @param contentType - The content type to get the codec for - * @returns The codec, if found - */ - getCodec(contentType: ContentTypeId) { - return this.#codecs.get(contentTypeToString(contentType)) as - | ContentCodec - | undefined; - } -} diff --git a/sdks/browser-sdk/src/Conversation.ts b/sdks/browser-sdk/src/Conversation.ts deleted file mode 100644 index 144b5d625..000000000 --- a/sdks/browser-sdk/src/Conversation.ts +++ /dev/null @@ -1,555 +0,0 @@ -import { - type Actions, - type Attachment, - type ConsentState, - type EncodedContent, - type Intent, - type ListMessagesOptions, - type MultiRemoteAttachment, - type Reaction, - type RemoteAttachment, - type Reply, - type SendMessageOpts, - type TransactionReference, - type WalletSendCalls, - type DecodedMessage as XmtpDecodedMessage, -} from "@xmtp/wasm-bindings"; -import type { CodecRegistry } from "@/CodecRegistry"; -import { DecodedMessage } from "@/DecodedMessage"; -import type { ClientWorkerAction } from "@/types/actions"; -import type { SafeConversation } from "@/utils/conversions"; -import { nsToDate } from "@/utils/date"; -import { - createStream, - type StreamCallback, - type StreamOptions, -} from "@/utils/streams"; -import { uuid } from "@/utils/uuid"; -import type { WorkerBridge } from "@/utils/WorkerBridge"; - -/** - * Represents a conversation - * - * This class is not intended to be initialized directly. - */ -export class Conversation { - #addedByInboxId?: SafeConversation["addedByInboxId"]; - #codecRegistry: CodecRegistry; - #createdAtNs?: SafeConversation["createdAtNs"]; - #id: string; - #metadata?: SafeConversation["metadata"]; - #worker: WorkerBridge; - - /** - * Creates a new conversation instance - * - * @param worker - The worker bridge instance for client communication - * @param codecRegistry - The codec registry instance - * @param id - The unique identifier for this conversation - * @param data - Optional conversation data to initialize with - */ - constructor( - worker: WorkerBridge, - codecRegistry: CodecRegistry, - id: string, - data?: SafeConversation, - ) { - this.#worker = worker; - this.#codecRegistry = codecRegistry; - this.#id = id; - this.#syncData(data); - } - - #syncData(data?: SafeConversation) { - this.#addedByInboxId = data?.addedByInboxId; - this.#metadata = data?.metadata; - this.#createdAtNs = data?.createdAtNs; - } - - get id() { - return this.#id; - } - - get addedByInboxId() { - return this.#addedByInboxId; - } - - get createdAtNs() { - return this.#createdAtNs; - } - - get createdAt() { - return this.#createdAtNs ? nsToDate(this.#createdAtNs) : undefined; - } - - get metadata() { - return this.#metadata; - } - - get topic() { - return `/xmtp/mls/1/g-${this.id}/proto`; - } - - async lastMessage() { - const lastMessage = await this.#worker.action("conversation.lastMessage", { - id: this.#id, - }); - return lastMessage - ? new DecodedMessage(this.#codecRegistry, lastMessage) - : undefined; - } - - async isActive() { - return this.#worker.action("conversation.isActive", { - id: this.#id, - }); - } - - /** - * Gets the conversation members - * - * @returns Promise that resolves with the conversation members - */ - async members() { - return this.#worker.action("conversation.members", { - id: this.#id, - }); - } - - /** - * Synchronizes conversation data from the network - * - * @returns Promise that resolves with the updated conversation data - */ - async sync() { - const data = await this.#worker.action("conversation.sync", { - id: this.#id, - }); - this.#syncData(data); - return data; - } - - /** - * Publishes pending messages that were sent optimistically - * - * @returns Promise that resolves when publishing is complete - */ - async publishMessages() { - return this.#worker.action("conversation.publishMessages", { - id: this.#id, - }); - } - - /** - * Decodes, decrypts, and persists a raw envelope from a group message stream. - * - * @param envelopeBytes - Raw protobuf-encoded envelope bytes from the stream - * @returns The processed and stored messages - */ - async processStreamedMessage(envelopeBytes: Uint8Array) { - return this.#worker.action("conversation.processStreamedMessage", { - id: this.#id, - envelopeBytes, - }); - } - - /** - * Sends a message - * - * @param content - The encoded content to send - * @param options - Optional send options - * @param options.shouldPush - Indicates whether this message should be - * included in push notifications - * @param options.isOptimistic - Indicates whether this message should be - * sent optimistically and published later via `publishMessages` - * @returns Promise that resolves with the message ID after it has been sent - */ - async send(content: EncodedContent, options?: SendMessageOpts) { - return this.#worker.action("conversation.send", { - id: this.#id, - content, - options, - }); - } - - /** - * Sends a text message - * - * @param text - The text to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendText(text: string, isOptimistic?: boolean) { - return this.#worker.action("conversation.sendText", { - id: this.#id, - text, - isOptimistic, - }); - } - - /** - * Sends a markdown message - * - * @param markdown - The markdown to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendMarkdown(markdown: string, isOptimistic?: boolean) { - return this.#worker.action("conversation.sendMarkdown", { - id: this.#id, - markdown, - isOptimistic, - }); - } - - /** - * Sends a reaction message - * - * @param reaction - The reaction to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendReaction(reaction: Reaction, isOptimistic?: boolean) { - return this.#worker.action("conversation.sendReaction", { - id: this.#id, - reaction, - isOptimistic, - }); - } - - /** - * Sends a read receipt message - * - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendReadReceipt(isOptimistic?: boolean) { - return this.#worker.action("conversation.sendReadReceipt", { - id: this.#id, - isOptimistic, - }); - } - - /** - * Sends a reply message - * - * @param reply - The reply to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendReply(reply: Reply, isOptimistic?: boolean) { - return this.#worker.action("conversation.sendReply", { - id: this.#id, - reply, - isOptimistic, - }); - } - - /** - * Sends a transaction reference message - * - * @param transactionReference - The transaction reference to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendTransactionReference( - transactionReference: TransactionReference, - isOptimistic?: boolean, - ) { - return this.#worker.action("conversation.sendTransactionReference", { - id: this.#id, - transactionReference, - isOptimistic, - }); - } - - /** - * Sends a wallet send calls message - * - * @param walletSendCalls - The wallet send calls to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendWalletSendCalls( - walletSendCalls: WalletSendCalls, - isOptimistic?: boolean, - ) { - return this.#worker.action("conversation.sendWalletSendCalls", { - id: this.#id, - walletSendCalls, - isOptimistic, - }); - } - - /** - * Sends an actions message - * - * @param actions - The actions to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendActions(actions: Actions, isOptimistic?: boolean) { - return this.#worker.action("conversation.sendActions", { - id: this.#id, - actions, - isOptimistic, - }); - } - - /** - * Sends an intent message - * - * @param intent - The intent to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendIntent(intent: Intent, isOptimistic?: boolean) { - return this.#worker.action("conversation.sendIntent", { - id: this.#id, - intent, - isOptimistic, - }); - } - - /** - * Sends an attachment message - * - * @param attachment - The attachment to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendAttachment(attachment: Attachment, isOptimistic?: boolean) { - return this.#worker.action("conversation.sendAttachment", { - id: this.#id, - attachment, - isOptimistic, - }); - } - - /** - * Sends a multi remote attachment message - * - * @param multiRemoteAttachment - The multi remote attachment to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendMultiRemoteAttachment( - multiRemoteAttachment: MultiRemoteAttachment, - isOptimistic?: boolean, - ) { - return this.#worker.action("conversation.sendMultiRemoteAttachment", { - id: this.#id, - multiRemoteAttachment, - isOptimistic, - }); - } - - /** - * Sends a remote attachment message - * - * @param remoteAttachment - The remote attachment to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendRemoteAttachment( - remoteAttachment: RemoteAttachment, - isOptimistic?: boolean, - ) { - return this.#worker.action("conversation.sendRemoteAttachment", { - id: this.#id, - remoteAttachment, - isOptimistic, - }); - } - - /** - * Lists messages in this conversation - * - * @param options - Optional filtering and pagination options - * @returns Promise that resolves with an array of decoded messages - */ - async messages(options?: ListMessagesOptions) { - const messages = await this.#worker.action("conversation.messages", { - id: this.#id, - options, - }); - - return messages.map( - (message) => - new DecodedMessage(this.#codecRegistry, message), - ); - } - - /** - * Counts messages in this conversation - * - * @param options - Optional filtering options - * @returns Promise that resolves with the count of messages - */ - async countMessages( - options?: Omit, - ) { - const count = await this.#worker.action("conversation.countMessages", { - id: this.#id, - options, - }); - return count; - } - - /** - * Gets the consent state for this conversation - * - * @returns Promise that resolves with the current consent state - */ - async consentState(): Promise { - return this.#worker.action("conversation.consentState", { - id: this.#id, - }); - } - - /** - * Updates the consent state for this conversation - * - * @param state - The new consent state to set - * @returns Promise that resolves when the update is complete - */ - async updateConsentState(state: ConsentState) { - return this.#worker.action("conversation.updateConsentState", { - id: this.#id, - state, - }); - } - - /** - * Gets the message disappearing settings for this conversation - * - * @returns Promise that resolves with the current message disappearing settings - */ - async messageDisappearingSettings() { - return this.#worker.action("conversation.messageDisappearingSettings", { - id: this.#id, - }); - } - - /** - * Updates message disappearing settings for this conversation - * - * @param fromNs - The timestamp from which messages should start disappearing - * @param inNs - The duration after which messages should disappear - * @returns Promise that resolves when the update is complete - */ - async updateMessageDisappearingSettings(fromNs: bigint, inNs: bigint) { - return this.#worker.action( - "conversation.updateMessageDisappearingSettings", - { - id: this.#id, - fromNs, - inNs, - }, - ); - } - - /** - * Removes message disappearing settings from this conversation - * - * @returns Promise that resolves when the settings are removed - */ - async removeMessageDisappearingSettings() { - return this.#worker.action( - "conversation.removeMessageDisappearingSettings", - { - id: this.#id, - }, - ); - } - - /** - * Checks if message disappearing is enabled for this conversation - * - * @returns Promise that resolves with whether message disappearing is enabled - */ - async isMessageDisappearingEnabled() { - return this.#worker.action("conversation.isMessageDisappearingEnabled", { - id: this.#id, - }); - } - - /** - * Creates a stream for new messages in this conversation - * - * @param callback - Optional callback function for handling new stream values - * @returns Stream instance for new messages - */ - async stream( - options?: StreamOptions>, - ) { - const stream = async ( - callback: StreamCallback, - onFail: () => void, - ) => { - const streamId = uuid(); - if (!options?.disableSync) { - // sync the conversation - await this.sync(); - } - // start the stream - await this.#worker.action("conversation.stream", { - groupId: this.#id, - streamId, - }); - // handle stream messages - return this.#worker.handleStreamMessage< - XmtpDecodedMessage, - DecodedMessage - >(streamId, callback, { - ...options, - onFail, - }); - }; - const convertMessage = (value: XmtpDecodedMessage) => { - return new DecodedMessage(this.#codecRegistry, value); - }; - - return createStream(stream, convertMessage, options); - } - - async pausedForVersion() { - return this.#worker.action("conversation.pausedForVersion", { - id: this.#id, - }); - } - - /** - * Gets HMAC keys for this conversation - * - * @returns Promise that resolves with the HMAC keys - */ - async hmacKeys() { - return this.#worker.action("conversation.hmacKeys", { - id: this.#id, - }); - } - - /** - * Retrieves information for this conversation to help with debugging - * - * @returns The debug information for this conversation - */ - async debugInfo() { - return this.#worker.action("conversation.debugInfo", { - id: this.#id, - }); - } - - /** - * Retrieves the last read times for this conversation - * - * @returns A map keyed by inbox ID with the last read timestamp - * (nanoseconds since epoch) - */ - async lastReadTimes() { - return this.#worker.action("conversation.lastReadTimes", { - id: this.#id, - }); - } -} diff --git a/sdks/browser-sdk/src/Conversations.ts b/sdks/browser-sdk/src/Conversations.ts deleted file mode 100644 index 313db6949..000000000 --- a/sdks/browser-sdk/src/Conversations.ts +++ /dev/null @@ -1,633 +0,0 @@ -import { - ConversationType, - type ConsentState, - type CreateDmOptions, - type CreateGroupOptions, - type Identifier, - type ListConversationsOptions, - type DecodedMessage as XmtpDecodedMessage, -} from "@xmtp/wasm-bindings"; -import type { Client } from "@/Client"; -import type { CodecRegistry } from "@/CodecRegistry"; -import { DecodedMessage } from "@/DecodedMessage"; -import { Dm } from "@/Dm"; -import { Group } from "@/Group"; -import type { ClientWorkerAction } from "@/types/actions"; -import type { SafeConversation } from "@/utils/conversions"; -import { - createStream, - type StreamCallback, - type StreamOptions, -} from "@/utils/streams"; -import { uuid } from "@/utils/uuid"; -import type { WorkerBridge } from "@/utils/WorkerBridge"; - -/** - * Manages conversations - * - * This class is not intended to be initialized directly. - */ -export class Conversations { - #client: Client; - #codecRegistry: CodecRegistry; - #worker: WorkerBridge; - - /** - * Creates a new conversations instance - * - * @param worker - The worker bridge instance for client communication - * @param codecRegistry - The codec registry instance - */ - constructor( - client: Client, - worker: WorkerBridge, - codecRegistry: CodecRegistry, - ) { - this.#client = client; - this.#worker = worker; - this.#codecRegistry = codecRegistry; - } - - get topic() { - return this.#client.installationId - ? `/xmtp/mls/1/w-${this.#client.installationId}/proto` - : undefined; - } - - /** - * Synchronizes conversations for the current client from the network - * - * @returns Promise that resolves when sync is complete - */ - async sync() { - return this.#worker.action("conversations.sync"); - } - - /** - * Synchronizes all conversations and messages from the network with optional - * consent state filtering, then uploads conversation and message history to - * the history sync server - * - * @param consentStates - Optional array of consent states to filter by - * @returns Promise that resolves when sync is complete - */ - async syncAll(consentStates?: ConsentState[]) { - return this.#worker.action("conversations.syncAll", { - consentStates, - }); - } - - /** - * Retrieves a conversation by its ID - * - * @param id - The conversation ID to look up - * @returns Promise that resolves with the conversation, if found - */ - async getConversationById(id: string) { - const data = await this.#worker.action( - "conversations.getConversationById", - { - id, - }, - ); - if (data) { - switch (data.metadata.conversationType) { - case ConversationType.Group: - return new Group( - this.#worker, - this.#codecRegistry, - data.id, - data, - ); - case ConversationType.Dm: - return new Dm( - this.#worker, - this.#codecRegistry, - data.id, - data, - ); - default: - return undefined; - } - } - return undefined; - } - - /** - * Retrieves a message by its ID - * - * @param id - The message ID to look up - * @returns Promise that resolves with the decoded message, if found - */ - async getMessageById(id: string) { - const data = await this.#worker.action("conversations.getMessageById", { - id, - }); - return data - ? new DecodedMessage(this.#codecRegistry, data) - : undefined; - } - - /** - * Retrieves a DM by inbox ID - * - * @param inboxId - The inbox ID to look up - * @returns Promise that resolves with the DM, if found - */ - async getDmByInboxId(inboxId: string) { - const data = await this.#worker.action("conversations.getDmByInboxId", { - inboxId, - }); - return data - ? new Dm(this.#worker, this.#codecRegistry, data.id, data) - : undefined; - } - - /** - * Fetches a DM by identifier - * - * @param identifier - The identifier to look up - * @returns Promise that resolves with the DM, if found - */ - async fetchDmByIdentifier(identifier: Identifier) { - const inboxId = await this.#worker.action("client.getInboxIdByIdentifier", { - identifier, - }); - if (!inboxId) { - return undefined; - } - return this.getDmByInboxId(inboxId); - } - - /** - * Lists all conversations with optional filtering - * - * @param options - Optional filtering and pagination options - * @returns Promise that resolves with an array of conversations - */ - async list(options?: ListConversationsOptions) { - const conversations = await this.#worker.action("conversations.list", { - options, - }); - - return conversations - .map((conversation) => { - switch (conversation.metadata.conversationType) { - case ConversationType.Dm: - return new Dm( - this.#worker, - this.#codecRegistry, - conversation.id, - conversation, - ); - case ConversationType.Group: - return new Group( - this.#worker, - this.#codecRegistry, - conversation.id, - conversation, - ); - default: - return undefined; - } - }) - .filter((conversation) => conversation !== undefined); - } - - /** - * Lists all group conversations with optional filtering - * - * @param options - Optional filtering and pagination options - * @returns Promise that resolves with an array of groups - */ - async listGroups( - options?: Omit, - ) { - const conversations = await this.#worker.action( - "conversations.listGroups", - { - options, - }, - ); - - return conversations.map( - (conversation) => - new Group( - this.#worker, - this.#codecRegistry, - conversation.id, - conversation, - ), - ); - } - - /** - * Lists all DM conversations with optional filtering - * - * @param options - Optional filtering and pagination options - * @returns Promise that resolves with an array of DMs - */ - async listDms(options?: Omit) { - const conversations = await this.#worker.action("conversations.listDms", { - options, - }); - - return conversations.map( - (conversation) => - new Dm( - this.#worker, - this.#codecRegistry, - conversation.id, - conversation, - ), - ); - } - - /** - * Creates a new group conversation without publishing to the network - * - * @param options - Optional group creation options - * @returns Promise that resolves with the new group - */ - async createGroupOptimistic(options?: CreateGroupOptions) { - const conversation = await this.#worker.action( - "conversations.createGroupOptimistic", - { - options, - }, - ); - - return new Group( - this.#worker, - this.#codecRegistry, - conversation.id, - conversation, - ); - } - - /** - * Creates a new group conversation with the specified identifiers - * - * @param identifiers - Array of identifiers for group members - * @param options - Optional group creation options - * @returns Promise that resolves with the new group - */ - async createGroupWithIdentifiers( - identifiers: Identifier[], - options?: CreateGroupOptions, - ) { - const conversation = await this.#worker.action( - "conversations.createGroupWithIdentifiers", - { - identifiers, - options, - }, - ); - - return new Group( - this.#worker, - this.#codecRegistry, - conversation.id, - conversation, - ); - } - - /** - * Creates a new group conversation with the specified inbox IDs - * - * @param inboxIds - Array of inbox IDs for other group members (the creator is included automatically) - * @param options - Optional group creation options - * @returns Promise that resolves with the new group - */ - async createGroup(inboxIds: string[], options?: CreateGroupOptions) { - const conversation = await this.#worker.action( - "conversations.createGroup", - { - inboxIds, - options, - }, - ); - - return new Group( - this.#worker, - this.#codecRegistry, - conversation.id, - conversation, - ); - } - - /** - * Creates a new DM conversation with the specified identifier - * - * @param identifier - Identifier for the DM recipient - * @param options - Optional DM creation options - * @returns Promise that resolves with the new DM - */ - async createDmWithIdentifier( - identifier: Identifier, - options?: CreateDmOptions, - ) { - const conversation = await this.#worker.action( - "conversations.createDmWithIdentifier", - { - identifier, - options, - }, - ); - - return new Dm( - this.#worker, - this.#codecRegistry, - conversation.id, - conversation, - ); - } - - /** - * Creates a new DM conversation with the specified inbox ID - * - * @param inboxId - Inbox ID for the DM recipient - * @param options - Optional DM creation options - * @returns Promise that resolves with the new DM - */ - async createDm(inboxId: string, options?: CreateDmOptions) { - const conversation = await this.#worker.action("conversations.createDm", { - inboxId, - options, - }); - - return new Dm( - this.#worker, - this.#codecRegistry, - conversation.id, - conversation, - ); - } - - /** - * Gets the HMAC keys for all conversations - * - * @returns Promise that resolves with the HMAC keys for all conversations - */ - async hmacKeys() { - return this.#worker.action("conversations.hmacKeys"); - } - - /** - * Creates a stream for new conversations - * - * @param options - Optional stream options - * @param options.conversationType - Optional type to filter conversations - * @returns Stream instance for new conversations - */ - async stream< - T extends Group | Dm = - | Group - | Dm, - >( - options?: StreamOptions & { - conversationType?: ConversationType; - }, - ) { - const stream = async ( - callback: StreamCallback, - onFail: () => void, - ) => { - const streamId = uuid(); - if (!options?.disableSync) { - // sync the conversation - await this.sync(); - } - // start the stream - await this.#worker.action("conversations.stream", { - streamId, - conversationType: options?.conversationType, - }); - // handle stream messages - return this.#worker.handleStreamMessage( - streamId, - callback, - { - ...options, - onFail, - }, - ); - }; - const convertConversation = (value: SafeConversation) => { - switch (value.metadata.conversationType) { - case ConversationType.Group: - return new Group( - this.#worker, - this.#codecRegistry, - value.id, - value, - ) as T; - case ConversationType.Dm: - return new Dm( - this.#worker, - this.#codecRegistry, - value.id, - value, - ) as T; - default: - console.warn( - `Unknown conversation type: ${value.metadata.conversationType}`, - ); - return undefined; - } - }; - - return createStream(stream, convertConversation, options); - } - - /** - * Creates a stream for new group conversations - * - * @param options - Optional stream options - * @returns Stream instance for new group conversations - */ - async streamGroups( - options?: StreamOptions>, - ) { - return this.stream({ - ...options, - conversationType: ConversationType.Group, - }); - } - - /** - * Creates a stream for new DM conversations - * - * @param options - Optional stream options - * @returns Stream instance for new DM conversations - */ - async streamDms(options?: StreamOptions>) { - return this.stream({ - ...options, - conversationType: ConversationType.Dm, - }); - } - - /** - * Creates a stream for all new messages - * - * @param options - Optional stream options - * @param options.conversationType - Optional conversation type to filter messages - * @param options.consentStates - Optional consent states to filter messages - * @returns Stream instance for new messages - */ - async streamAllMessages( - options?: StreamOptions< - XmtpDecodedMessage, - DecodedMessage - > & { - conversationType?: ConversationType; - consentStates?: ConsentState[]; - }, - ) { - const stream = async ( - callback: StreamCallback, - onFail: () => void, - ) => { - const streamId = uuid(); - if (!options?.disableSync) { - // sync the conversation - await this.sync(); - } - // start the stream - await this.#worker.action("conversations.streamAllMessages", { - streamId, - conversationType: options?.conversationType, - consentStates: options?.consentStates, - }); - // handle stream messages - return this.#worker.handleStreamMessage< - XmtpDecodedMessage, - DecodedMessage - >(streamId, callback, { - ...options, - onFail, - }); - }; - const convertMessage = (value: XmtpDecodedMessage) => { - return new DecodedMessage(this.#codecRegistry, value); - }; - - return createStream(stream, convertMessage, options); - } - - /** - * Creates a stream for all new group messages - * - * @param options - Optional stream options - * @param options.consentStates - Optional consent states to filter messages - * @returns Stream instance for new group messages - */ - async streamAllGroupMessages( - options?: StreamOptions< - XmtpDecodedMessage, - DecodedMessage - > & { - consentStates?: ConsentState[]; - }, - ) { - return this.streamAllMessages({ - ...options, - conversationType: ConversationType.Group, - }); - } - - /** - * Creates a stream for all new DM messages - * - * @param options - Optional stream options - * @param options.consentStates - Optional consent states to filter messages - * @returns Stream instance for new DM messages - */ - async streamAllDmMessages( - options?: StreamOptions< - XmtpDecodedMessage, - DecodedMessage - > & { - consentStates?: ConsentState[]; - }, - ) { - return this.streamAllMessages({ - ...options, - conversationType: ConversationType.Dm, - }); - } - - /** - * Creates a stream for message deletions that streams the message IDs of - * deleted messages - * - * @param options - Optional stream options - * @returns Stream instance for message deletions - * @deprecated Use streamDeletedMessages instead - */ - async streamMessageDeletions( - options?: Omit< - StreamOptions, - | "disableSync" - | "onFail" - | "onRetry" - | "onRestart" - | "retryAttempts" - | "retryDelay" - | "retryOnFail" - >, - ) { - const stream = async (callback: StreamCallback) => { - const streamId = uuid(); - // start the stream - await this.#worker.action("conversations.streamDeletedMessages", { - streamId, - }); - // handle stream messages - return this.#worker.handleStreamMessage( - streamId, - callback, - options, - ); - }; - const convertMessage = (value: XmtpDecodedMessage) => value.id; - return createStream(stream, convertMessage, options); - } - - /** - * Creates a stream for deleted messages that streams the deleted messages - * - * @param options - Optional stream options - * @returns Stream instance for deleted messages - */ - async streamDeletedMessages( - options?: Omit< - StreamOptions>, - | "disableSync" - | "onFail" - | "onRetry" - | "onRestart" - | "retryAttempts" - | "retryDelay" - | "retryOnFail" - >, - ) { - const stream = async (callback: StreamCallback) => { - const streamId = uuid(); - // start the stream - await this.#worker.action("conversations.streamDeletedMessages", { - streamId, - }); - // handle stream messages - return this.#worker.handleStreamMessage< - XmtpDecodedMessage, - DecodedMessage - >(streamId, callback, options); - }; - const convertMessage = (value: XmtpDecodedMessage) => { - return new DecodedMessage(this.#codecRegistry, value); - }; - return createStream(stream, convertMessage, options); - } -} diff --git a/sdks/browser-sdk/src/DebugInformation.ts b/sdks/browser-sdk/src/DebugInformation.ts deleted file mode 100644 index a8b54801c..000000000 --- a/sdks/browser-sdk/src/DebugInformation.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { ClientWorkerAction } from "@/types/actions"; -import type { WorkerBridge } from "@/utils/WorkerBridge"; - -/** - * Debug information helpers for the client - * - * This class is not intended to be initialized directly. - */ -export class DebugInformation { - #worker: WorkerBridge; - - constructor(worker: WorkerBridge) { - this.#worker = worker; - } - - apiStatistics() { - return this.#worker.action("debugInformation.apiStatistics"); - } - - apiIdentityStatistics() { - return this.#worker.action("debugInformation.apiIdentityStatistics"); - } - - apiAggregateStatistics() { - return this.#worker.action("debugInformation.apiAggregateStatistics"); - } - - clearAllStatistics() { - return this.#worker.action("debugInformation.clearAllStatistics"); - } -} diff --git a/sdks/browser-sdk/src/DecodedMessage.ts b/sdks/browser-sdk/src/DecodedMessage.ts deleted file mode 100644 index 75fd87f6d..000000000 --- a/sdks/browser-sdk/src/DecodedMessage.ts +++ /dev/null @@ -1,265 +0,0 @@ -import { - contentTypeToString, - type EncodedContent, -} from "@xmtp/content-type-primitives"; -import { - type ContentTypeId, - type DecodedMessageContent, - type DeliveryStatus, - type GroupMessageKind, - type Reaction, - type DecodedMessage as XmtpDecodedMessage, -} from "@xmtp/wasm-bindings"; -import type { CodecRegistry } from "@/CodecRegistry"; -import { - contentTypeActions, - contentTypeAttachment, - contentTypeGroupUpdated, - contentTypeIntent, - contentTypeLeaveRequest, - contentTypeMarkdown, - contentTypeMultiRemoteAttachment, - contentTypeReaction, - contentTypeReadReceipt, - contentTypeRemoteAttachment, - contentTypeReply, - contentTypeText, - contentTypeTransactionReference, - contentTypeWalletSendCalls, -} from "@/utils/contentTypes"; -import { nsToDate } from "@/utils/date"; - -const getContentFromDecodedMessageContent = ( - content: DecodedMessageContent, -): T => { - switch (content.type) { - case "text": { - return content.content as T; - } - case "markdown": { - return content.content as T; - } - case "reply": { - return content.content as T; - } - case "reaction": { - return content.content as T; - } - case "attachment": { - return content.content as T; - } - case "remoteAttachment": { - return content.content as T; - } - case "multiRemoteAttachment": { - return content.content as T; - } - case "transactionReference": { - return content.content as T; - } - case "groupUpdated": { - return content.content as T; - } - case "readReceipt": { - return content.content as T; - } - case "leaveRequest": { - return content.content as T; - } - case "walletSendCalls": { - return content.content as T; - } - case "intent": { - return content.content as T; - } - case "actions": { - return content.content as T; - } - case "deletedMessage": { - return content.content as T; - } - case "custom": { - return content.content as T; - } - default: - content satisfies never; - return null as T; - } -}; - -const getContentTypeFromDecodedMessageContent = async ( - content: DecodedMessageContent, -): Promise => { - switch (content.type) { - case "text": { - return contentTypeText(); - } - case "markdown": { - return contentTypeMarkdown(); - } - case "reply": { - return contentTypeReply(); - } - case "reaction": { - return contentTypeReaction(); - } - case "attachment": { - return contentTypeAttachment(); - } - case "remoteAttachment": { - return contentTypeRemoteAttachment(); - } - case "multiRemoteAttachment": { - return contentTypeMultiRemoteAttachment(); - } - case "transactionReference": { - return contentTypeTransactionReference(); - } - case "groupUpdated": { - return contentTypeGroupUpdated(); - } - case "readReceipt": { - return contentTypeReadReceipt(); - } - case "leaveRequest": { - return contentTypeLeaveRequest(); - } - case "walletSendCalls": { - return contentTypeWalletSendCalls(); - } - case "intent": { - return contentTypeIntent(); - } - case "actions": { - return contentTypeActions(); - } - case "deletedMessage": { - return undefined; - } - case "custom": { - return content.content.type; - } - default: - content satisfies never; - return undefined; - } -}; - -/** - * Represents a decoded XMTP message - * - * @class - * @property {unknown} content - The decoded content of the message - * @property {ContentTypeId} contentType - The content type of the message content - * @property {string} conversationId - Unique identifier for the conversation - * @property {DeliveryStatus} deliveryStatus - Current delivery status of the message ("unpublished" | "published" | "failed") - * @property {bigint} expiresAtNs - Timestamp when the message will expire (in nanoseconds) - * @property {Date} expiresAt - Timestamp when the message will expire - * @property {string} fallback - Optional fallback text for the message - * @property {string} id - Unique identifier for the message - * @property {GroupMessageKind} kind - Type of message ("application" | "membership_change") - * @property {bigint} numReplies - Number of replies to the message - * @property {DecodedMessage[]} reactions - Reactions to the message - * @property {string} senderInboxId - Identifier for the sender's inbox - * @property {Date} sentAt - Timestamp when the message was sent - * @property {bigint} sentAtNs - Timestamp when the message was sent (in nanoseconds) - */ -export class DecodedMessage { - content: ContentTypes | undefined; - contentType: ContentTypeId; - conversationId: string; - deliveryStatus: DeliveryStatus; - expiresAtNs?: bigint; - expiresAt?: Date; - fallback?: string; - id: string; - kind: GroupMessageKind; - numReplies: bigint; - reactions: DecodedMessage[]; - senderInboxId: string; - sentAt: Date; - sentAtNs: bigint; - - constructor(codecRegistry: CodecRegistry, message: XmtpDecodedMessage) { - this.id = message.id; - this.expiresAtNs = message.expiresAtNs; - this.expiresAt = message.expiresAtNs - ? nsToDate(message.expiresAtNs) - : undefined; - this.sentAtNs = message.sentAtNs; - this.sentAt = nsToDate(message.sentAtNs); - this.conversationId = message.conversationId; - this.senderInboxId = message.senderInboxId; - this.contentType = message.contentType; - this.fallback = message.fallback ?? undefined; - - this.kind = message.kind; - this.deliveryStatus = message.deliveryStatus; - - this.numReplies = message.numReplies; - this.reactions = message.reactions.map( - (reaction) => new DecodedMessage(codecRegistry, reaction), - ); - - this.content = - getContentFromDecodedMessageContent(message.content) ?? - undefined; - - switch (message.content.type) { - case "reply": { - const reply = message.content.content; - let replyContent = getContentFromDecodedMessageContent( - reply.content, - ); - if (reply.content.type === "custom") { - const codec = codecRegistry.getCodec( - reply.content.content.type as ContentTypeId, - ); - if (codec) { - try { - replyContent = codec.decode(replyContent as EncodedContent); - } catch (error) { - if (error instanceof Error) { - console.warn(`Error decoding custom content: ${error.message}`); - } else { - console.warn(`Error decoding custom content`); - } - } - } - } - this.content = { - referenceId: reply.referenceId, - content: replyContent, - contentType: () => - getContentTypeFromDecodedMessageContent(reply.content), - inReplyTo: reply.inReplyTo - ? new DecodedMessage(codecRegistry, reply.inReplyTo) - : null, - } as ContentTypes; - break; - } - case "custom": { - const encodedContent = message.content.content; - const codec = codecRegistry.getCodec(this.contentType); - if (codec) { - try { - this.content = codec.decode(encodedContent); - } catch (error) { - if (error instanceof Error) { - console.warn(`Error decoding custom content: ${error.message}`); - } else { - console.warn(`Error decoding custom content`); - } - this.content = undefined; - } - } else { - console.warn( - `No codec found for content type "${contentTypeToString(this.contentType)}"`, - ); - this.content = undefined; - } - break; - } - } - } -} diff --git a/sdks/browser-sdk/src/Dm.ts b/sdks/browser-sdk/src/Dm.ts deleted file mode 100644 index e87f4c79c..000000000 --- a/sdks/browser-sdk/src/Dm.ts +++ /dev/null @@ -1,63 +0,0 @@ -import type { CodecRegistry } from "@/CodecRegistry"; -import { Conversation } from "@/Conversation"; -import type { ClientWorkerAction } from "@/types/actions"; -import type { SafeConversation } from "@/utils/conversions"; -import type { WorkerBridge } from "@/utils/WorkerBridge"; - -/** - * Represents a direct message conversation between two inboxes - * - * This class is not intended to be initialized directly. - */ -export class Dm extends Conversation { - #codecRegistry: CodecRegistry; - #worker: WorkerBridge; - #id: string; - - /** - * Creates a new direct message conversation instance - * - * @param worker - The worker bridge instance for client communication - * @param codecRegistry - The codec registry instance - * @param id - Identifier for the direct message conversation - * @param data - Optional conversation data to initialize with - */ - constructor( - worker: WorkerBridge, - codecRegistry: CodecRegistry, - id: string, - data?: SafeConversation, - ) { - super(worker, codecRegistry, id, data); - this.#worker = worker; - this.#codecRegistry = codecRegistry; - this.#id = id; - } - - /** - * Retrieves the inbox ID of the other participant in the DM - * - * @returns Promise that resolves with the peer's inbox ID - */ - async peerInboxId() { - return this.#worker.action("dm.peerInboxId", { - id: this.#id, - }); - } - - async duplicateDms() { - const conversations = await this.#worker.action("dm.duplicateDms", { - id: this.#id, - }); - - return conversations.map( - (conversation) => - new Dm( - this.#worker, - this.#codecRegistry, - conversation.id, - conversation, - ), - ); - } -} diff --git a/sdks/browser-sdk/src/Group.ts b/sdks/browser-sdk/src/Group.ts deleted file mode 100644 index c79d00d2a..000000000 --- a/sdks/browser-sdk/src/Group.ts +++ /dev/null @@ -1,356 +0,0 @@ -import type { - Identifier, - MetadataField, - PermissionPolicy, - PermissionUpdateType, -} from "@xmtp/wasm-bindings"; -import type { CodecRegistry } from "@/CodecRegistry"; -import { Conversation } from "@/Conversation"; -import type { ClientWorkerAction } from "@/types/actions"; -import type { SafeConversation } from "@/utils/conversions"; -import type { WorkerBridge } from "@/utils/WorkerBridge"; - -/** - * Represents a group conversation between multiple inboxes - * - * This class is not intended to be initialized directly. - */ -export class Group extends Conversation { - #admins: SafeConversation["admins"] = []; - #appData?: SafeConversation["appData"]; - #worker: WorkerBridge; - #description?: SafeConversation["description"]; - #id: string; - #imageUrl?: SafeConversation["imageUrl"]; - #name?: SafeConversation["name"]; - #superAdmins: SafeConversation["superAdmins"] = []; - - #syncData(data?: SafeConversation) { - this.#name = data?.name ?? ""; - this.#imageUrl = data?.imageUrl ?? ""; - this.#description = data?.description ?? ""; - this.#appData = data?.appData ?? ""; - this.#admins = data?.admins ?? []; - this.#superAdmins = data?.superAdmins ?? []; - } - - /** - * Creates a new group conversation instance - * - * @param worker - The worker bridge instance for client communication - * @param codecRegistry - The codec registry instance - * @param id - Identifier for the group conversation - * @param data - Optional conversation data to initialize with - */ - constructor( - worker: WorkerBridge, - codecRegistry: CodecRegistry, - id: string, - data?: SafeConversation, - ) { - super(worker, codecRegistry, id, data); - this.#worker = worker; - this.#id = id; - this.#syncData(data); - } - - /** - * Synchronizes the group's data with the network - * - * @returns Updated group data - */ - async sync() { - const data = await super.sync(); - this.#syncData(data); - return data; - } - - /** - * The name of the group - */ - get name() { - return this.#name; - } - - /** - * Updates the group's name - * - * @param name The new name for the group - */ - async updateName(name: string) { - await this.#worker.action("group.updateName", { - id: this.#id, - name, - }); - this.#name = name; - } - - /** - * The image URL of the group - */ - get imageUrl() { - return this.#imageUrl; - } - - /** - * Updates the group's image URL - * - * @param imageUrl The new image URL for the group - */ - async updateImageUrl(imageUrl: string) { - await this.#worker.action("group.updateImageUrl", { - id: this.#id, - imageUrl, - }); - this.#imageUrl = imageUrl; - } - - /** - * The description of the group - */ - get description() { - return this.#description; - } - - /** - * Updates the group's description - * - * @param description The new description for the group - */ - async updateDescription(description: string) { - await this.#worker.action("group.updateDescription", { - id: this.#id, - description, - }); - this.#description = description; - } - - /** - * The app data of the group - */ - get appData() { - return this.#appData; - } - - /** - * Updates the group's app data (max 8192 bytes) - * - * @param appData The new app data for the group - */ - async updateAppData(appData: string) { - await this.#worker.action("group.updateAppData", { - id: this.#id, - appData, - }); - this.#appData = appData; - } - - /** - * The list of admins of the group by inbox ID - */ - get admins() { - return this.#admins; - } - - /** - * The list of super admins of the group by inbox ID - */ - get superAdmins() { - return this.#superAdmins; - } - - /** - * Fetches and updates the list of group admins from the server - * - * @returns Array of admin inbox IDs - */ - async listAdmins() { - const admins = await this.#worker.action("group.listAdmins", { - id: this.#id, - }); - this.#admins = admins; - return admins; - } - - /** - * Fetches and updates the list of group super admins from the server - * - * @returns Array of super admin inbox IDs - */ - async listSuperAdmins() { - const superAdmins = await this.#worker.action("group.listSuperAdmins", { - id: this.#id, - }); - this.#superAdmins = superAdmins; - return superAdmins; - } - - /** - * Retrieves the group's permissions - * - * @returns The group's permissions - */ - async permissions() { - return this.#worker.action("group.permissions", { - id: this.#id, - }); - } - - /** - * Updates a specific permission policy for the group - * - * @param permissionType The type of permission to update - * @param policy The new permission policy - * @param metadataField Optional metadata field for the permission - */ - async updatePermission( - permissionType: PermissionUpdateType, - policy: PermissionPolicy, - metadataField?: MetadataField, - ) { - return this.#worker.action("group.updatePermission", { - id: this.#id, - permissionType, - policy, - metadataField, - }); - } - - /** - * Checks if an inbox is an admin of the group - * - * @param inboxId The inbox ID to check - * @returns Boolean indicating if the inbox is an admin - */ - async isAdmin(inboxId: string) { - const admins = await this.listAdmins(); - return admins.includes(inboxId); - } - - /** - * Checks if an inbox is a super admin of the group - * - * @param inboxId The inbox ID to check - * @returns Boolean indicating if the inbox is a super admin - */ - async isSuperAdmin(inboxId: string) { - const superAdmins = await this.listSuperAdmins(); - return superAdmins.includes(inboxId); - } - - /** - * Adds members to the group using identifiers - * - * @param identifiers Array of member identifiers to add - */ - async addMembersByIdentifiers(identifiers: Identifier[]) { - return this.#worker.action("group.addMembersByIdentifiers", { - id: this.#id, - identifiers, - }); - } - - /** - * Adds members to the group using inbox IDs - * - * @param inboxIds Array of inbox IDs to add - */ - async addMembers(inboxIds: string[]) { - return this.#worker.action("group.addMembers", { - id: this.#id, - inboxIds, - }); - } - - /** - * Removes members from the group using identifiers - * - * @param identifiers Array of member identifiers to remove - */ - async removeMembersByIdentifiers(identifiers: Identifier[]) { - return this.#worker.action("group.removeMembersByIdentifiers", { - id: this.#id, - identifiers, - }); - } - - /** - * Removes members from the group using inbox IDs - * - * @param inboxIds Array of inbox IDs to remove - */ - async removeMembers(inboxIds: string[]) { - return this.#worker.action("group.removeMembers", { - id: this.#id, - inboxIds, - }); - } - - /** - * Promotes a group member to admin status - * - * @param inboxId The inbox ID of the member to promote - */ - async addAdmin(inboxId: string) { - return this.#worker.action("group.addAdmin", { - id: this.#id, - inboxId, - }); - } - - /** - * Removes admin status from a group member - * - * @param inboxId The inbox ID of the admin to demote - */ - async removeAdmin(inboxId: string) { - return this.#worker.action("group.removeAdmin", { - id: this.#id, - inboxId, - }); - } - - /** - * Promotes a group member to super admin status - * - * @param inboxId The inbox ID of the member to promote - */ - async addSuperAdmin(inboxId: string) { - return this.#worker.action("group.addSuperAdmin", { - id: this.#id, - inboxId, - }); - } - - /** - * Removes super admin status from a group member - * - * @param inboxId The inbox ID of the super admin to demote - */ - async removeSuperAdmin(inboxId: string) { - return this.#worker.action("group.removeSuperAdmin", { - id: this.#id, - inboxId, - }); - } - - /** - * Request to leave the group - */ - async requestRemoval() { - return this.#worker.action("group.requestRemoval", { - id: this.#id, - }); - } - - /** - * Checks if the current user has requested to leave the group - * - * @returns Boolean - */ - async isPendingRemoval() { - return this.#worker.action("group.isPendingRemoval", { - id: this.#id, - }); - } -} diff --git a/sdks/browser-sdk/src/Opfs.ts b/sdks/browser-sdk/src/Opfs.ts deleted file mode 100644 index 3f3d219b4..000000000 --- a/sdks/browser-sdk/src/Opfs.ts +++ /dev/null @@ -1,63 +0,0 @@ -import type { OpfsAction } from "@/types/actions/opfs"; -import { WorkerBridge } from "@/utils/WorkerBridge"; - -export class Opfs { - #worker: WorkerBridge; - #enableLogging: boolean; - - constructor(enableLogging?: boolean) { - const worker = new Worker(new URL("./workers/opfs", import.meta.url), { - type: "module", - }); - this.#worker = new WorkerBridge(worker, enableLogging); - this.#enableLogging = enableLogging ?? false; - } - - async init() { - await this.#worker.action("opfs.init", { - enableLogging: this.#enableLogging, - }); - } - - close() { - this.#worker.close(); - } - - static async create(enableLogging?: boolean) { - const opfs = new Opfs(enableLogging); - await opfs.init(); - return opfs; - } - - async listFiles() { - return this.#worker.action("opfs.listFiles"); - } - - async fileCount() { - return this.#worker.action("opfs.fileCount"); - } - - async poolCapacity() { - return this.#worker.action("opfs.poolCapacity"); - } - - async fileExists(path: string) { - return this.#worker.action("opfs.fileExists", { path }); - } - - async deleteFile(path: string) { - return this.#worker.action("opfs.deleteFile", { path }); - } - - async exportDb(path: string) { - return this.#worker.action("opfs.exportDb", { path }); - } - - async importDb(path: string, data: Uint8Array) { - return this.#worker.action("opfs.importDb", { path, data }); - } - - async clearAll() { - return this.#worker.action("opfs.clearAll"); - } -} diff --git a/sdks/browser-sdk/src/Preferences.ts b/sdks/browser-sdk/src/Preferences.ts deleted file mode 100644 index 2ddd84efb..000000000 --- a/sdks/browser-sdk/src/Preferences.ts +++ /dev/null @@ -1,178 +0,0 @@ -import type { - Consent, - ConsentEntityType, - ConsentState, - UserPreferenceUpdate, -} from "@xmtp/wasm-bindings"; -import type { ClientWorkerAction } from "@/types/actions"; -import { - createStream, - type StreamCallback, - type StreamOptions, -} from "@/utils/streams"; -import { uuid } from "@/utils/uuid"; -import type { WorkerBridge } from "@/utils/WorkerBridge"; - -/** - * Manages user preferences and consent states - * - * This class is not intended to be initialized directly. - */ -export class Preferences { - #worker: WorkerBridge; - - /** - * Creates a new preferences instance - * - * @param client - The client instance managing preferences - */ - constructor(worker: WorkerBridge) { - this.#worker = worker; - } - - sync() { - return this.#worker.action("preferences.sync"); - } - - /** - * Retrieves the current inbox state of this client from the local database - * - * @returns Promise that resolves with the inbox state - */ - async inboxState() { - return this.#worker.action("preferences.inboxState", { - refreshFromNetwork: false, - }); - } - - /** - * Retrieves the latest inbox state of this client from the network - * - * @returns Promise that resolves with the inbox state - */ - async fetchInboxState() { - return this.#worker.action("preferences.inboxState", { - refreshFromNetwork: true, - }); - } - - /** - * Retrieves the current inbox states for specified inbox IDs from the local - * database - * - * @param inboxIds - Array of inbox IDs to get state for - * @returns Promise that resolves with the inbox states for the inbox IDs - */ - async getInboxStates(inboxIds: string[]) { - return this.#worker.action("preferences.getInboxStates", { - inboxIds, - refreshFromNetwork: false, - }); - } - - /** - * Retrieves the latest inbox states for specified inbox IDs from the network - * - * @param inboxIds - Array of inbox IDs to get state for - * @returns Promise that resolves with the inbox states for the inbox IDs - */ - async fetchInboxStates(inboxIds: string[]) { - return this.#worker.action("preferences.getInboxStates", { - inboxIds, - refreshFromNetwork: true, - }); - } - - /** - * Updates consent states for multiple records - * - * @param records - Array of consent records to update - * @returns Promise that resolves when consent states are updated - */ - async setConsentStates(records: Consent[]) { - return this.#worker.action("preferences.setConsentStates", { - records, - }); - } - - /** - * Retrieves consent state for a specific entity - * - * @param entityType - Type of entity to get consent for - * @param entity - Entity identifier - * @returns Promise that resolves with the consent state - */ - async getConsentState( - entityType: ConsentEntityType, - entity: string, - ): Promise { - return this.#worker.action("preferences.getConsentState", { - entityType, - entity, - }); - } - - /** - * Creates a stream of consent state updates - * - * @param options - Optional stream options - * @returns Stream instance for consent updates - */ - async streamConsent(options?: StreamOptions) { - const stream = async ( - callback: StreamCallback, - onFail: () => void, - ) => { - const streamId = uuid(); - // sync the conversation - if (!options?.disableSync) { - await this.sync(); - } - // start the stream - await this.#worker.action("preferences.streamConsent", { - streamId, - }); - // handle stream messages - return this.#worker.handleStreamMessage(streamId, callback, { - ...options, - onFail, - }); - }; - - return createStream(stream, undefined, options); - } - - /** - * Creates a stream of user preference updates - * - * @param options - Optional stream options - * @returns Stream instance for preference updates - */ - async streamPreferences(options?: StreamOptions) { - const stream = async ( - callback: StreamCallback, - onFail: () => void, - ) => { - const streamId = uuid(); - // sync the conversation - if (!options?.disableSync) { - await this.sync(); - } - // start the stream - await this.#worker.action("preferences.streamPreferences", { - streamId, - }); - // handle stream messages - return this.#worker.handleStreamMessage( - streamId, - callback, - { - ...options, - onFail, - }, - ); - }; - - return createStream(stream, undefined, options); - } -} diff --git a/sdks/browser-sdk/src/WorkerClient.ts b/sdks/browser-sdk/src/WorkerClient.ts deleted file mode 100644 index 5462ced62..000000000 --- a/sdks/browser-sdk/src/WorkerClient.ts +++ /dev/null @@ -1,260 +0,0 @@ -import { - verifySignedWithPublicKey, - type ArchiveMetadata, - type ArchiveOptions, - type AvailableArchiveInfo, - type Client, - type GroupSyncSummary, - type Identifier, - type KeyPackageStatus, - type SignatureRequestHandle, -} from "@xmtp/wasm-bindings"; -import type { - ClientOptions, - VisibilityConfirmationOptions, - XmtpEnv, -} from "@/types/options"; -import { createClient } from "@/utils/createClient"; -import type { SafeSigner } from "@/utils/signer"; -import { WorkerConversations } from "@/WorkerConversations"; -import { WorkerDebugInformation } from "@/WorkerDebugInformation"; -import { WorkerPreferences } from "@/WorkerPreferences"; - -export class WorkerClient { - #client: Client; - #conversations: WorkerConversations; - #debugInformation: WorkerDebugInformation; - #env: XmtpEnv; - #preferences: WorkerPreferences; - - constructor(client: Client, env: XmtpEnv) { - this.#client = client; - this.#env = env; - const conversations = client.conversations(); - this.#conversations = new WorkerConversations(this, conversations); - this.#debugInformation = new WorkerDebugInformation(client); - this.#preferences = new WorkerPreferences(client, conversations); - } - - static async create( - identifier: Identifier, - options?: Omit, - ) { - const { client, env } = await createClient(identifier, options); - return new WorkerClient(client, env); - } - - get libxmtpVersion() { - return this.#client.libxmtpVersion; - } - - get appVersion() { - return this.#client.appVersion; - } - - get env() { - return this.#env; - } - - get accountIdentifier() { - return this.#client.accountIdentifier; - } - - get inboxId() { - return this.#client.inboxId; - } - - get installationId() { - return this.#client.installationId; - } - - get installationIdBytes() { - return this.#client.installationIdBytes; - } - - get isRegistered() { - return this.#client.isRegistered; - } - - get conversations() { - return this.#conversations; - } - - get debugInformation() { - return this.#debugInformation; - } - - get preferences() { - return this.#preferences; - } - - async canMessage(identifiers: Identifier[]) { - return this.#client.canMessage(identifiers) as Promise< - Map - >; - } - - async fetchLatestInboxUpdatesCount(inboxIds: string[]) { - const result = (await this.#client.fetchLatestInboxUpdatesCount( - true, - inboxIds, - )) as Map | Record; - - return result instanceof Map ? Object.fromEntries(result) : result; - } - - async fetchOwnInboxUpdatesCount() { - return this.#client.fetchOwnInboxUpdatesCount(true); - } - - async addSignature( - signatureRequest: SignatureRequestHandle, - signer: SafeSigner, - ) { - switch (signer.type) { - case "SCW": - await signatureRequest.addScwSignature( - signer.identifier, - signer.signature, - signer.chainId, - signer.blockNumber, - ); - break; - case "EOA": - await signatureRequest.addEcdsaSignature(signer.signature); - break; - } - } - - async applySignatureRequest(signatureRequest: SignatureRequestHandle) { - return this.#client.applySignatureRequest(signatureRequest); - } - - async processSignatureRequest( - signer: SafeSigner, - signatureRequest: SignatureRequestHandle, - ) { - await this.addSignature(signatureRequest, signer); - await this.applySignatureRequest(signatureRequest); - } - - createInboxSignatureRequest() { - return this.#client.createInboxSignatureRequest(); - } - - async addAccountSignatureRequest(newAccountIdentifier: Identifier) { - return this.#client.addWalletSignatureRequest(newAccountIdentifier); - } - - async removeAccountSignatureRequest(identifier: Identifier) { - return this.#client.revokeWalletSignatureRequest(identifier); - } - - async revokeAllOtherInstallationsSignatureRequest() { - return this.#client.revokeAllOtherInstallationsSignatureRequest(); - } - - async revokeInstallationsSignatureRequest(installationIds: Uint8Array[]) { - return this.#client.revokeInstallationsSignatureRequest(installationIds); - } - - async changeRecoveryIdentifierSignatureRequest(identifier: Identifier) { - return this.#client.changeRecoveryIdentifierSignatureRequest(identifier); - } - - async registerIdentity( - signer: SafeSigner, - signatureRequest: SignatureRequestHandle, - visibilityConfirmationOptions?: VisibilityConfirmationOptions, - ) { - await this.addSignature(signatureRequest, signer); - await this.#client.registerIdentity( - signatureRequest, - visibilityConfirmationOptions, - ); - } - - async getInboxIdByIdentifier(identifier: Identifier) { - return this.#client.findInboxIdByIdentity(identifier); - } - - signWithInstallationKey(signatureText: string) { - return this.#client.signWithInstallationKey(signatureText); - } - - verifySignedWithInstallationKey( - signatureText: string, - signatureBytes: Uint8Array, - ) { - try { - this.#client.verifySignedWithInstallationKey( - signatureText, - signatureBytes, - ); - return true; - } catch { - return false; - } - } - - verifySignedWithPublicKey( - signatureText: string, - signatureBytes: Uint8Array, - publicKey: Uint8Array, - ) { - try { - verifySignedWithPublicKey(signatureText, signatureBytes, publicKey); - return true; - } catch { - return false; - } - } - - async fetchKeyPackageStatuses(installationIds: string[]) { - return this.#client.getKeyPackageStatusesForInstallationIds( - installationIds, - ) as Promise>; - } - - async sendSyncRequest(options: ArchiveOptions, serverUrl: string) { - return this.#client.device_sync().sendSyncRequest(options, serverUrl); - } - - async sendSyncArchive( - options: ArchiveOptions, - serverUrl: string, - pin: string, - ) { - return this.#client.device_sync().sendSyncArchive(options, serverUrl, pin); - } - - async processSyncArchive(archivePin?: string | null) { - return this.#client.device_sync().processSyncArchive(archivePin); - } - - listAvailableArchives(daysCutoff: number): AvailableArchiveInfo[] { - return this.#client.device_sync().listAvailableArchives(BigInt(daysCutoff)); - } - - async createArchive( - opts: ArchiveOptions, - key: Uint8Array, - ): Promise { - return this.#client.device_sync().createArchive(opts, key); - } - - async importArchive(data: Uint8Array, key: Uint8Array) { - return this.#client.device_sync().importArchive(data, key); - } - - async archiveMetadata( - data: Uint8Array, - key: Uint8Array, - ): Promise { - return this.#client.device_sync().archiveMetadata(data, key); - } - - async syncAllDeviceSyncGroups(): Promise { - return this.#client.device_sync().syncAllDeviceSyncGroups(); - } -} diff --git a/sdks/browser-sdk/src/WorkerConversation.ts b/sdks/browser-sdk/src/WorkerConversation.ts deleted file mode 100644 index 18a1f31c8..000000000 --- a/sdks/browser-sdk/src/WorkerConversation.ts +++ /dev/null @@ -1,343 +0,0 @@ -import { - GroupMembershipState, - SortDirection, - type Actions, - type Attachment, - type ConsentState, - type Conversation, - type ConversationDebugInfo, - type DecodedMessage, - type EncodedContent, - type GroupMember, - type HmacKey, - type Identifier, - type Intent, - type ListMessagesOptions, - type Message, - type MessageDisappearingSettings, - type MetadataField, - type MultiRemoteAttachment, - type PermissionPolicy, - type PermissionUpdateType, - type Reaction, - type RemoteAttachment, - type Reply, - type SendMessageOpts, - type TransactionReference, - type WalletSendCalls, -} from "@xmtp/wasm-bindings"; -import type { LastReadTimes } from "@/utils/conversions"; -import type { StreamCallback } from "@/utils/streams"; -import type { WorkerClient } from "@/WorkerClient"; - -export class WorkerConversation { - #client: WorkerClient; - #group: Conversation; - - constructor(client: WorkerClient, group: Conversation) { - this.#client = client; - this.#group = group; - } - - get id() { - return this.#group.id(); - } - - get name() { - return this.#group.groupName(); - } - - async updateName(name: string) { - return this.#group.updateGroupName(name); - } - - get imageUrl() { - return this.#group.groupImageUrlSquare(); - } - - async updateImageUrl(imageUrl: string) { - return this.#group.updateGroupImageUrlSquare(imageUrl); - } - - get description() { - return this.#group.groupDescription(); - } - - async updateDescription(description: string) { - return this.#group.updateGroupDescription(description); - } - - get appData() { - try { - return this.#group.appData(); - } catch { - // DM groups don't support appData - return ""; - } - } - - async updateAppData(appData: string) { - return this.#group.updateAppData(appData); - } - - get isActive() { - return this.#group.isActive(); - } - - get addedByInboxId() { - return this.#group.addedByInboxId(); - } - - get createdAtNs() { - return this.#group.createdAtNs(); - } - - async lastMessage() { - const messages = await this.messages({ - limit: 1n, - direction: SortDirection.Descending, - }); - if (messages.length > 0) { - return messages[0]; - } - return undefined; - } - - async metadata() { - return this.#group.groupMetadata(); - } - - async members() { - const members = (await this.#group.listMembers()) as GroupMember[]; - return members; - } - - listAdmins() { - return this.#group.adminList(); - } - - listSuperAdmins() { - return this.#group.superAdminList(); - } - - permissions() { - const permissions = this.#group.groupPermissions(); - return { - policyType: permissions.policyType, - policySet: permissions.policySet, - }; - } - - async updatePermission( - permissionType: PermissionUpdateType, - policy: PermissionPolicy, - metadataField?: MetadataField, - ) { - return this.#group.updatePermissionPolicy( - permissionType, - policy, - metadataField, - ); - } - - isAdmin(inboxId: string) { - return this.#group.isAdmin(inboxId); - } - - isSuperAdmin(inboxId: string) { - return this.#group.isSuperAdmin(inboxId); - } - - async sync() { - return this.#group.sync(); - } - - async addMembersByIdentifiers(identifiers: Identifier[]) { - return this.#group.addMembersByIdentity(identifiers); - } - - async addMembers(inboxIds: string[]) { - return this.#group.addMembers(inboxIds); - } - - async removeMembersByIdentifiers(identifiers: Identifier[]) { - return this.#group.removeMembersByIdentity(identifiers); - } - - async removeMembers(inboxIds: string[]) { - return this.#group.removeMembers(inboxIds); - } - - async addAdmin(inboxId: string) { - return this.#group.addAdmin(inboxId); - } - - async removeAdmin(inboxId: string) { - return this.#group.removeAdmin(inboxId); - } - - async addSuperAdmin(inboxId: string) { - return this.#group.addSuperAdmin(inboxId); - } - - async removeSuperAdmin(inboxId: string) { - return this.#group.removeSuperAdmin(inboxId); - } - - async publishMessages() { - return this.#group.publishMessages(); - } - - async processStreamedMessage(envelopeBytes: Uint8Array) { - return this.#group.processStreamedGroupMessage(envelopeBytes); - } - - async send(encodedContent: EncodedContent, opts?: SendMessageOpts) { - return this.#group.send(encodedContent, opts ?? { shouldPush: true }); - } - - async sendText(text: string, isOptimistic?: boolean) { - return this.#group.sendText(text, isOptimistic); - } - - async sendMarkdown(markdown: string, isOptimistic?: boolean) { - return this.#group.sendMarkdown(markdown, isOptimistic); - } - - async sendReaction(reaction: Reaction, isOptimistic?: boolean) { - return this.#group.sendReaction(reaction, isOptimistic); - } - - async sendReadReceipt(isOptimistic?: boolean) { - return this.#group.sendReadReceipt(isOptimistic); - } - - async sendReply(reply: Reply, isOptimistic?: boolean) { - return this.#group.sendReply(reply, isOptimistic); - } - - async sendTransactionReference( - transactionReference: TransactionReference, - isOptimistic?: boolean, - ) { - return this.#group.sendTransactionReference( - transactionReference, - isOptimistic, - ); - } - - async sendWalletSendCalls( - walletSendCalls: WalletSendCalls, - isOptimistic?: boolean, - ) { - return this.#group.sendWalletSendCalls(walletSendCalls, isOptimistic); - } - - async sendActions(actions: Actions, isOptimistic?: boolean) { - return this.#group.sendActions(actions, isOptimistic); - } - - async sendIntent(intent: Intent, isOptimistic?: boolean) { - return this.#group.sendIntent(intent, isOptimistic); - } - - async sendAttachment(attachment: Attachment, isOptimistic?: boolean) { - return this.#group.sendAttachment(attachment, isOptimistic); - } - - async sendMultiRemoteAttachment( - multiRemoteAttachment: MultiRemoteAttachment, - isOptimistic?: boolean, - ) { - return this.#group.sendMultiRemoteAttachment( - multiRemoteAttachment, - isOptimistic, - ); - } - - async sendRemoteAttachment( - remoteAttachment: RemoteAttachment, - isOptimistic?: boolean, - ) { - return this.#group.sendRemoteAttachment(remoteAttachment, isOptimistic); - } - - async messages(options?: ListMessagesOptions): Promise { - return this.#group.findEnrichedMessages(options); - } - - async countMessages(options?: ListMessagesOptions) { - return this.#group.countMessages(options); - } - - consentState() { - return this.#group.consentState(); - } - - updateConsentState(state: ConsentState) { - this.#group.updateConsentState(state); - } - - dmPeerInboxId() { - return this.#group.dmPeerInboxId(); - } - - messageDisappearingSettings() { - return this.#group.messageDisappearingSettings(); - } - - async updateMessageDisappearingSettings(fromNs: bigint, inNs: bigint) { - const settings: MessageDisappearingSettings = { fromNs, inNs }; - return this.#group.updateMessageDisappearingSettings(settings); - } - - async removeMessageDisappearingSettings() { - return this.#group.removeMessageDisappearingSettings(); - } - - isMessageDisappearingEnabled() { - return this.#group.isMessageDisappearingEnabled(); - } - - stream(callback: StreamCallback, onFail: () => void) { - const on_message = (message: Message) => { - callback(null, message); - }; - const on_error = (error: Error | null) => { - callback(error, undefined); - }; - const on_close = () => { - onFail(); - }; - return this.#group.stream({ on_message, on_error, on_close }); - } - - pausedForVersion() { - return this.#group.pausedForVersion(); - } - - hmacKeys() { - return this.#group.getHmacKeys() as Map; - } - - async debugInfo() { - return (await this.#group.getDebugInfo()) as ConversationDebugInfo; - } - - async duplicateDms() { - const dms = await this.#group.findDuplicateDms(); - return dms.map((dm) => new WorkerConversation(this.#client, dm)); - } - - async requestRemoval() { - return this.#group.leaveGroup(); - } - - isPendingRemoval() { - return this.#group.membershipState() === GroupMembershipState.PendingRemove; - } - - async lastReadTimes() { - return this.#group.getLastReadTimes() as Promise; - } -} diff --git a/sdks/browser-sdk/src/WorkerConversations.ts b/sdks/browser-sdk/src/WorkerConversations.ts deleted file mode 100644 index d50b7ccf0..000000000 --- a/sdks/browser-sdk/src/WorkerConversations.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { - ConversationType, - type ConsentState, - type Conversation, - type ConversationListItem, - type Conversations, - type CreateDmOptions, - type CreateGroupOptions, - type DecodedMessage, - type Identifier, - type ListConversationsOptions, - type Message, -} from "@xmtp/wasm-bindings"; -import { type HmacKeys } from "@/utils/conversions"; -import type { StreamCallback } from "@/utils/streams"; -import type { WorkerClient } from "@/WorkerClient"; -import { WorkerConversation } from "@/WorkerConversation"; - -export class WorkerConversations { - #client: WorkerClient; - - #conversations: Conversations; - - constructor(client: WorkerClient, conversations: Conversations) { - this.#client = client; - this.#conversations = conversations; - } - - async sync() { - return this.#conversations.sync(); - } - - async syncAll(consentStates?: ConsentState[]) { - return this.#conversations.syncAllConversations(consentStates); - } - - getConversationById(id: string) { - try { - const group = this.#conversations.findGroupById(id); - // findGroupById will throw if group is not found - return new WorkerConversation(this.#client, group); - } catch { - return undefined; - } - } - - async getMessageById(id: string): Promise { - try { - return await this.#conversations.findEnrichedMessageById(id); - } catch { - return undefined; - } - } - - getDmByInboxId(inboxId: string) { - try { - const group = this.#conversations.findDmByTargetInboxId(inboxId); - return new WorkerConversation(this.#client, group); - } catch { - return undefined; - } - } - - list(options?: ListConversationsOptions) { - const groups = this.#conversations.list(options) as ConversationListItem[]; - return groups.map( - (item) => new WorkerConversation(this.#client, item.conversation), - ); - } - - listGroups(options?: Omit) { - const groups = this.#conversations.list({ - ...(options ?? {}), - conversationType: ConversationType.Group, - }) as ConversationListItem[]; - return groups.map( - (item) => new WorkerConversation(this.#client, item.conversation), - ); - } - - listDms(options?: Omit) { - const groups = this.#conversations.list({ - ...(options ?? {}), - conversationType: ConversationType.Dm, - }) as ConversationListItem[]; - return groups.map( - (item) => new WorkerConversation(this.#client, item.conversation), - ); - } - - createGroupOptimistic(options?: CreateGroupOptions) { - const group = this.#conversations.createGroupOptimistic(options); - return new WorkerConversation(this.#client, group); - } - - async createGroupWithIdentifiers( - identifiers: Identifier[], - options?: CreateGroupOptions, - ) { - const group = await this.#conversations.createGroup(identifiers, options); - return new WorkerConversation(this.#client, group); - } - - async createGroup(inboxIds: string[], options?: CreateGroupOptions) { - const group = await this.#conversations.createGroupByInboxIds( - inboxIds, - options, - ); - return new WorkerConversation(this.#client, group); - } - - async createDmWithIdentifier( - identifier: Identifier, - options?: CreateDmOptions, - ) { - const group = await this.#conversations.createDm(identifier, options); - return new WorkerConversation(this.#client, group); - } - - async createDm(inboxId: string, options?: CreateDmOptions) { - const group = await this.#conversations.createDmByInboxId(inboxId, options); - return new WorkerConversation(this.#client, group); - } - - hmacKeys() { - return this.#conversations.getHmacKeys() as HmacKeys; - } - - stream( - callback: StreamCallback, - onFail: () => void, - conversationType?: ConversationType, - ) { - const on_conversation = (conversation: Conversation) => { - callback(null, conversation); - }; - const on_error = (error: Error | null) => { - callback(error, undefined); - }; - const on_close = () => { - onFail(); - }; - return this.#conversations.stream( - { on_conversation, on_error, on_close }, - conversationType, - ); - } - - streamGroups(callback: StreamCallback, onFail: () => void) { - return this.stream(callback, onFail, ConversationType.Group); - } - - streamDms(callback: StreamCallback, onFail: () => void) { - return this.stream(callback, onFail, ConversationType.Dm); - } - - streamAllMessages( - callback: StreamCallback, - onFail: () => void, - conversationType?: ConversationType, - consentStates?: ConsentState[], - ) { - const on_message = (message: Message) => { - callback(null, message); - }; - const on_error = (error: Error | null) => { - callback(error, undefined); - }; - const on_close = () => { - onFail(); - }; - return this.#conversations.streamAllMessages( - { on_message, on_error, on_close }, - conversationType, - consentStates, - ); - } - - streamDeletedMessages(callback: StreamCallback) { - const on_message_deleted = (message: DecodedMessage) => { - callback(null, message); - }; - const on_error = (error: Error | null) => { - callback(error, undefined); - }; - return this.#conversations.streamMessageDeletions({ - on_message_deleted, - on_error, - }); - } -} diff --git a/sdks/browser-sdk/src/WorkerDebugInformation.ts b/sdks/browser-sdk/src/WorkerDebugInformation.ts deleted file mode 100644 index 5a40d86fc..000000000 --- a/sdks/browser-sdk/src/WorkerDebugInformation.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { Client } from "@xmtp/wasm-bindings"; - -/** - * Debug information helpers for the client - * - * This class is not intended to be initialized directly. - */ -export class WorkerDebugInformation { - #client: Client; - - constructor(client: Client) { - this.#client = client; - } - - apiStatistics() { - return this.#client.apiStatistics(); - } - - apiIdentityStatistics() { - return this.#client.apiIdentityStatistics(); - } - - apiAggregateStatistics() { - return this.#client.apiAggregateStatistics(); - } - - clearAllStatistics() { - this.#client.clearAllStatistics(); - } -} diff --git a/sdks/browser-sdk/src/WorkerPreferences.ts b/sdks/browser-sdk/src/WorkerPreferences.ts deleted file mode 100644 index 034df26af..000000000 --- a/sdks/browser-sdk/src/WorkerPreferences.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { - type Client, - type Consent, - type ConsentEntityType, - type Conversations, - type UserPreferenceUpdate, -} from "@xmtp/wasm-bindings"; -import type { StreamCallback } from "@/utils/streams"; - -export class WorkerPreferences { - #client: Client; - #conversations: Conversations; - - constructor(client: Client, conversations: Conversations) { - this.#client = client; - this.#conversations = conversations; - } - - sync() { - return this.#client.syncPreferences(); - } - - async inboxState(refreshFromNetwork: boolean) { - return this.#client.inboxState(refreshFromNetwork); - } - - async getInboxStates(inboxIds: string[], refreshFromNetwork?: boolean) { - return this.#client.inboxStateFromInboxIds( - inboxIds, - refreshFromNetwork ?? false, - ); - } - - async setConsentStates(records: Consent[]) { - return this.#client.setConsentStates(records); - } - - async getConsentState(entityType: ConsentEntityType, entity: string) { - return this.#client.getConsentState(entityType, entity); - } - - streamConsent(callback: StreamCallback, onFail: () => void) { - const on_consent_update = (consent: Consent[]) => { - callback(null, consent); - }; - const on_error = (error: Error | null) => { - callback(error, undefined); - }; - const on_close = () => { - onFail(); - }; - return this.#conversations.streamConsent({ - on_consent_update, - on_error, - on_close, - }); - } - - streamPreferences( - callback: StreamCallback, - onFail: () => void, - ) { - const on_user_preference_update = (preferences: UserPreferenceUpdate[]) => { - callback(null, preferences); - }; - const on_error = (error: Error | null) => { - callback(error, undefined); - }; - const on_close = () => { - onFail(); - }; - return this.#conversations.streamPreferences({ - on_user_preference_update, - on_error, - on_close, - }); - } -} diff --git a/sdks/browser-sdk/src/constants.ts b/sdks/browser-sdk/src/constants.ts deleted file mode 100644 index 4b9a7aa90..000000000 --- a/sdks/browser-sdk/src/constants.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Pre-configured URLs for the XMTP network based on the environment - * - * @deprecated Use `createBackend()` instead. - * @constant - * @property {string} local - The local URL for the XMTP network - * @property {string} dev - The development URL for the XMTP network - * @property {string} production - The production URL for the XMTP network - */ -export const ApiUrls = { - local: "http://localhost:5557", - dev: "https://api.dev.xmtp.network:5558", - production: "https://api.production.xmtp.network:5558", -} as const; - -/** - * Pre-configured URLs for the XMTP history sync service based on the environment - * - * @constant - * @property {string} local - The local URL for the XMTP history sync service - * @property {string} dev - The development URL for the XMTP history sync service - * @property {string} production - The production URL for the XMTP history sync service - */ -export const HistorySyncUrls = { - local: "http://localhost:5558", - dev: "https://message-history.dev.ephemera.network", - production: "https://message-history.production.ephemera.network", - "testnet-staging": "https://message-history.dev.ephemera.network", - "testnet-dev": "https://message-history.dev.ephemera.network", - testnet: "https://message-history.dev.ephemera.network", - mainnet: "https://message-history.production.ephemera.network", -} as const; diff --git a/sdks/browser-sdk/src/index.ts b/sdks/browser-sdk/src/index.ts deleted file mode 100644 index 15fbcc418..000000000 --- a/sdks/browser-sdk/src/index.ts +++ /dev/null @@ -1,97 +0,0 @@ -export { Client } from "./Client"; -export { Opfs } from "./Opfs"; -export { Conversations } from "./Conversations"; -export { Conversation } from "./Conversation"; -export { Dm } from "./Dm"; -export { Group } from "./Group"; -export { DecodedMessage } from "./DecodedMessage"; -export { createBackend } from "./utils/createBackend"; -export { generateInboxId, getInboxIdForIdentifier } from "./utils/inboxId"; -export { metadataFieldName } from "./utils/metadata"; -export { ApiUrls, HistorySyncUrls } from "./constants"; -export type * from "./types/options"; -export * from "./utils/conversions"; -export * from "./utils/contentTypes"; -export type { AsyncStreamProxy } from "./AsyncStream"; -export type { - Action, - Actions, - ApiStats, - ArchiveMetadata, - ArchiveOptions, - Attachment, - AvailableArchiveInfo, - Backend, - BackendBuilder, - Consent, - ConversationDebugInfo, - ConversationListItem, - CreateDmOptions, - CreateGroupOptions, - Cursor, - EncryptedAttachment, - GroupMember, - GroupMetadata, - GroupPermissions, - GroupSyncSummary, - GroupUpdated, - HmacKey, - Identifier, - IdentityStats, - Inbox, - InboxState, - Installation, - Intent, - KeyPackageStatus, - LeaveRequest, - Lifetime, - ListConversationsOptions, - ListMessagesOptions, - LogOptions, - Message, - MessageDisappearingSettings, - MetadataFieldChange, - MultiRemoteAttachment, - PermissionPolicySet, - Reaction, - ReadReceipt, - RemoteAttachment, - Reply, - SendMessageOpts, - SignatureRequestHandle, - TransactionMetadata, - TransactionReference, - UserPreferenceUpdate, - WalletCall, - WalletSendCalls, - WorkerConfigOptions, - WorkerIntervalOverride, -} from "@xmtp/wasm-bindings"; -export { - ActionStyle, - BackupElementSelectionOption, - ConsentEntityType, - ConsentState, - ContentType, - ConversationType, - DeliveryStatus, - GroupMembershipState, - GroupMessageKind, - GroupPermissionsOptions, - IdentifierKind, - ListConversationsOrderBy, - LogLevel, - MessageSortBy, - MetadataField, - PermissionLevel, - PermissionPolicy, - PermissionUpdateType, - ReactionAction, - ReactionSchema, - SortDirection, - WorkerKind, -} from "@xmtp/wasm-bindings"; -export * from "./utils/signer"; -export * from "./utils/errors"; -export type * from "./utils/streams"; -export * from "./utils/messages"; diff --git a/sdks/browser-sdk/src/types/actions.ts b/sdks/browser-sdk/src/types/actions.ts deleted file mode 100644 index d514a4633..000000000 --- a/sdks/browser-sdk/src/types/actions.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { ClientAction } from "@/types/actions/client"; -import type { ConversationAction } from "@/types/actions/conversation"; -import type { ConversationsAction } from "@/types/actions/conversations"; -import type { DebugInformationAction } from "@/types/actions/debugInformation"; -import type { DmAction } from "@/types/actions/dm"; -import type { GroupAction } from "@/types/actions/group"; -import type { PreferencesAction } from "@/types/actions/preferences"; - -export type UnknownAction = { - action: string; - id: string; - result: unknown; - data: unknown; -}; - -export type EndStreamAction = { - action: "endStream"; - id: string; - result: undefined; - data: { - streamId: string; - }; -}; - -export type ClientWorkerAction = - | EndStreamAction - | ClientAction - | ConversationAction - | ConversationsAction - | DmAction - | GroupAction - | PreferencesAction - | DebugInformationAction; - -export type ActionName = T["action"]; - -export type ExtractAction< - T extends UnknownAction, - A extends ActionName, -> = Extract; - -export type ExtractActionWithoutData< - T extends UnknownAction, - A extends ActionName, -> = Omit, "data">; - -export type ExtractActionWithoutResult< - T extends UnknownAction, - A extends ActionName, -> = Omit, "result">; - -export type ExtractActionData< - T extends UnknownAction, - A extends ActionName, -> = ExtractAction["data"]; - -export type ExtractActionResult< - T extends UnknownAction, - A extends ActionName, -> = ExtractAction["result"]; - -export type ActionWithoutData = { - [A in T["action"]]: Omit, "data">; -}[T["action"]]; - -export type ActionWithoutResult = { - [A in T["action"]]: Omit, "result">; -}[T["action"]]; - -export type ActionErrorData = { - id: string; - action: ActionName; - error: Error; -}; - -export type ExtractActionGroup< - T extends UnknownAction, - U extends string, -> = Extract; diff --git a/sdks/browser-sdk/src/types/actions/client.ts b/sdks/browser-sdk/src/types/actions/client.ts deleted file mode 100644 index b8eac010a..000000000 --- a/sdks/browser-sdk/src/types/actions/client.ts +++ /dev/null @@ -1,308 +0,0 @@ -import type { - ArchiveMetadata, - ArchiveOptions, - AvailableArchiveInfo, - GroupSyncSummary, - Identifier, - KeyPackageStatus, -} from "@xmtp/wasm-bindings"; -import type { - ClientOptions, - VisibilityConfirmationOptions, -} from "@/types/options"; -import type { SafeSigner } from "@/utils/signer"; - -export type ClientAction = - | { - action: "client.init"; - id: string; - result: { - appVersion: string; - env: string; - inboxId: string; - installationId: string; - installationIdBytes: Uint8Array; - libxmtpVersion: string; - }; - data: { - identifier: Identifier; - options?: ClientOptions; - }; - } - | { - action: "client.applySignatureRequest"; - id: string; - result: undefined; - data: { - signer: SafeSigner; - signatureRequestId: string; - }; - } - | { - action: "client.createInboxSignatureText"; - id: string; - result: { - signatureText?: string; - signatureRequestId?: string; - }; - data: { - signatureRequestId: string; - }; - } - | { - action: "client.addAccountSignatureText"; - id: string; - result: { - signatureText: string; - signatureRequestId: string; - }; - data: { - newIdentifier: Identifier; - signatureRequestId: string; - }; - } - | { - action: "client.removeAccountSignatureText"; - id: string; - result: { - signatureText: string; - signatureRequestId: string; - }; - data: { - identifier: Identifier; - signatureRequestId: string; - }; - } - | { - action: "client.revokeAllOtherInstallationsSignatureText"; - id: string; - result: { - signatureText: string | undefined; - signatureRequestId: string; - }; - data: { - signatureRequestId: string; - }; - } - | { - action: "client.revokeInstallationsSignatureText"; - id: string; - result: { - signatureText: string; - signatureRequestId: string; - }; - data: { - installationIds: Uint8Array[]; - signatureRequestId: string; - }; - } - | { - action: "client.changeRecoveryIdentifierSignatureText"; - id: string; - result: { - signatureText: string; - signatureRequestId: string; - }; - data: { - identifier: Identifier; - signatureRequestId: string; - }; - } - | { - action: "client.registerIdentity"; - id: string; - result: undefined; - data: { - signer: SafeSigner; - signatureRequestId: string; - waitForRegistrationVisible?: VisibilityConfirmationOptions; - }; - } - | { - action: "client.addAccount"; - id: string; - result: undefined; - data: { - identifier: Identifier; - signer: SafeSigner; - signatureRequestId: string; - }; - } - | { - action: "client.removeAccount"; - id: string; - result: undefined; - data: { - identifier: Identifier; - signer: SafeSigner; - signatureRequestId: string; - }; - } - | { - action: "client.revokeAllOtherInstallations"; - id: string; - result: undefined; - data: { - signer: SafeSigner; - signatureRequestId: string; - }; - } - | { - action: "client.changeRecoveryIdentifier"; - id: string; - result: undefined; - data: { - identifier: Identifier; - signer: SafeSigner; - signatureRequestId: string; - }; - } - | { - action: "client.revokeInstallations"; - id: string; - result: undefined; - data: { - installationIds: Uint8Array[]; - signer: SafeSigner; - signatureRequestId: string; - }; - } - | { - action: "client.isRegistered"; - id: string; - result: boolean; - data: undefined; - } - | { - action: "client.canMessage"; - id: string; - result: Map; - data: { - identifiers: Identifier[]; - }; - } - | { - action: "client.fetchLatestInboxUpdatesCount"; - id: string; - result: Record; - data: { - inboxIds: string[]; - }; - } - | { - action: "client.fetchOwnInboxUpdatesCount"; - id: string; - result: number; - data: Record; - } - | { - action: "client.getInboxIdByIdentifier"; - id: string; - result: string | undefined; - data: { - identifier: Identifier; - }; - } - | { - action: "client.signWithInstallationKey"; - id: string; - result: Uint8Array; - data: { - signatureText: string; - }; - } - | { - action: "client.verifySignedWithInstallationKey"; - id: string; - result: boolean; - data: { - signatureText: string; - signatureBytes: Uint8Array; - }; - } - | { - action: "client.verifySignedWithPublicKey"; - id: string; - result: boolean; - data: { - signatureText: string; - signatureBytes: Uint8Array; - publicKey: Uint8Array; - }; - } - | { - action: "client.fetchKeyPackageStatuses"; - id: string; - result: Map; - data: { - installationIds: string[]; - }; - } - | { - action: "client.sendSyncRequest"; - id: string; - result: undefined; - data: { - options: ArchiveOptions; - serverUrl: string; - }; - } - | { - action: "client.sendSyncArchive"; - id: string; - result: undefined; - data: { - options: ArchiveOptions; - serverUrl: string; - pin: string; - }; - } - | { - action: "client.processSyncArchive"; - id: string; - result: undefined; - data: { - archivePin?: string | null; - }; - } - | { - action: "client.listAvailableArchives"; - id: string; - result: AvailableArchiveInfo[]; - data: { - daysCutoff: number; - }; - } - | { - action: "client.createArchive"; - id: string; - result: Uint8Array; - data: { - opts: ArchiveOptions; - key: Uint8Array; - }; - } - | { - action: "client.importArchive"; - id: string; - result: undefined; - data: { - data: Uint8Array; - key: Uint8Array; - }; - } - | { - action: "client.archiveMetadata"; - id: string; - result: ArchiveMetadata; - data: { - data: Uint8Array; - key: Uint8Array; - }; - } - | { - action: "client.syncAllDeviceSyncGroups"; - id: string; - result: GroupSyncSummary; - data: undefined; - }; diff --git a/sdks/browser-sdk/src/types/actions/conversation.ts b/sdks/browser-sdk/src/types/actions/conversation.ts deleted file mode 100644 index 7ce325323..000000000 --- a/sdks/browser-sdk/src/types/actions/conversation.ts +++ /dev/null @@ -1,313 +0,0 @@ -import type { - Actions, - Attachment, - ConsentState, - ConversationDebugInfo, - DecodedMessage, - EncodedContent, - GroupMember, - Intent, - ListMessagesOptions, - Message, - MessageDisappearingSettings, - MultiRemoteAttachment, - Reaction, - RemoteAttachment, - Reply, - SendMessageOpts, - TransactionReference, - WalletSendCalls, -} from "@xmtp/wasm-bindings"; -import type { - HmacKeys, - LastReadTimes, - SafeConversation, -} from "@/utils/conversions"; - -export type ConversationAction = - | { - action: "conversation.sync"; - id: string; - result: SafeConversation; - data: { - id: string; - }; - } - | { - action: "conversation.send"; - id: string; - result: string; - data: { - id: string; - content: EncodedContent; - options?: SendMessageOpts; - }; - } - | { - action: "conversation.publishMessages"; - id: string; - result: undefined; - data: { - id: string; - }; - } - | { - action: "conversation.processStreamedMessage"; - id: string; - result: Message[]; - data: { - id: string; - envelopeBytes: Uint8Array; - }; - } - | { - action: "conversation.messages"; - id: string; - result: DecodedMessage[]; - data: { - id: string; - options?: ListMessagesOptions; - }; - } - | { - action: "conversation.countMessages"; - id: string; - result: bigint; - data: { - id: string; - options?: Omit; - }; - } - | { - action: "conversation.members"; - id: string; - result: GroupMember[]; - data: { - id: string; - }; - } - | { - action: "conversation.messageDisappearingSettings"; - id: string; - result: MessageDisappearingSettings | undefined; - data: { - id: string; - }; - } - | { - action: "conversation.updateMessageDisappearingSettings"; - id: string; - result: undefined; - data: MessageDisappearingSettings & { - id: string; - }; - } - | { - action: "conversation.removeMessageDisappearingSettings"; - id: string; - result: undefined; - data: { - id: string; - }; - } - | { - action: "conversation.isMessageDisappearingEnabled"; - id: string; - result: boolean; - data: { - id: string; - }; - } - | { - action: "conversation.stream"; - id: string; - result: undefined; - data: { - groupId: string; - streamId: string; - }; - } - | { - action: "conversation.pausedForVersion"; - id: string; - result: string | undefined; - data: { - id: string; - }; - } - | { - action: "conversation.hmacKeys"; - id: string; - result: HmacKeys; - data: { - id: string; - }; - } - | { - action: "conversation.debugInfo"; - id: string; - result: ConversationDebugInfo; - data: { - id: string; - }; - } - | { - action: "conversation.consentState"; - id: string; - result: ConsentState; - data: { - id: string; - }; - } - | { - action: "conversation.updateConsentState"; - id: string; - result: undefined; - data: { - id: string; - state: ConsentState; - }; - } - | { - action: "conversation.lastMessage"; - id: string; - result: DecodedMessage | undefined; - data: { - id: string; - }; - } - | { - action: "conversation.isActive"; - id: string; - result: boolean; - data: { - id: string; - }; - } - | { - action: "conversation.lastReadTimes"; - id: string; - result: LastReadTimes; - data: { - id: string; - }; - } - | { - action: "conversation.sendText"; - id: string; - result: string; - data: { - id: string; - text: string; - isOptimistic?: boolean; - }; - } - | { - action: "conversation.sendMarkdown"; - id: string; - result: string; - data: { - id: string; - markdown: string; - isOptimistic?: boolean; - }; - } - | { - action: "conversation.sendReaction"; - id: string; - result: string; - data: { - id: string; - reaction: Reaction; - isOptimistic?: boolean; - }; - } - | { - action: "conversation.sendReadReceipt"; - id: string; - result: string; - data: { - id: string; - isOptimistic?: boolean; - }; - } - | { - action: "conversation.sendReply"; - id: string; - result: string; - data: { - id: string; - reply: Reply; - isOptimistic?: boolean; - }; - } - | { - action: "conversation.sendTransactionReference"; - id: string; - result: string; - data: { - id: string; - transactionReference: TransactionReference; - isOptimistic?: boolean; - }; - } - | { - action: "conversation.sendWalletSendCalls"; - id: string; - result: string; - data: { - id: string; - walletSendCalls: WalletSendCalls; - isOptimistic?: boolean; - }; - } - | { - action: "conversation.sendActions"; - id: string; - result: string; - data: { - id: string; - actions: Actions; - isOptimistic?: boolean; - }; - } - | { - action: "conversation.sendIntent"; - id: string; - result: string; - data: { - id: string; - intent: Intent; - isOptimistic?: boolean; - }; - } - | { - action: "conversation.sendAttachment"; - id: string; - result: string; - data: { - id: string; - attachment: Attachment; - isOptimistic?: boolean; - }; - } - | { - action: "conversation.sendMultiRemoteAttachment"; - id: string; - result: string; - data: { - id: string; - multiRemoteAttachment: MultiRemoteAttachment; - isOptimistic?: boolean; - }; - } - | { - action: "conversation.sendRemoteAttachment"; - id: string; - result: string; - data: { - id: string; - remoteAttachment: RemoteAttachment; - isOptimistic?: boolean; - }; - }; diff --git a/sdks/browser-sdk/src/types/actions/conversations.ts b/sdks/browser-sdk/src/types/actions/conversations.ts deleted file mode 100644 index ed1665211..000000000 --- a/sdks/browser-sdk/src/types/actions/conversations.ts +++ /dev/null @@ -1,151 +0,0 @@ -import type { - ConsentState, - ConversationType, - CreateDmOptions, - CreateGroupOptions, - DecodedMessage, - Identifier, - ListConversationsOptions, -} from "@xmtp/wasm-bindings"; -import type { HmacKeys, SafeConversation } from "@/utils/conversions"; - -export type ConversationsAction = - | { - action: "conversations.getConversationById"; - id: string; - result: SafeConversation | undefined; - data: { - id: string; - }; - } - | { - action: "conversations.getMessageById"; - id: string; - result: DecodedMessage | undefined; - data: { - id: string; - }; - } - | { - action: "conversations.getDmByInboxId"; - id: string; - result: SafeConversation | undefined; - data: { - inboxId: string; - }; - } - | { - action: "conversations.list"; - id: string; - result: SafeConversation[]; - data: { - options?: ListConversationsOptions; - }; - } - | { - action: "conversations.listGroups"; - id: string; - result: SafeConversation[]; - data: { - options?: Omit; - }; - } - | { - action: "conversations.listDms"; - id: string; - result: SafeConversation[]; - data: { - options?: Omit; - }; - } - | { - action: "conversations.createGroupOptimistic"; - id: string; - result: SafeConversation; - data: { - options?: CreateGroupOptions; - }; - } - | { - action: "conversations.createGroupWithIdentifiers"; - id: string; - result: SafeConversation; - data: { - identifiers: Identifier[]; - options?: CreateGroupOptions; - }; - } - | { - action: "conversations.createGroup"; - id: string; - result: SafeConversation; - data: { - inboxIds: string[]; - options?: CreateGroupOptions; - }; - } - | { - action: "conversations.createDmWithIdentifier"; - id: string; - result: SafeConversation; - data: { - identifier: Identifier; - options?: CreateDmOptions; - }; - } - | { - action: "conversations.createDm"; - id: string; - result: SafeConversation; - data: { - inboxId: string; - options?: CreateDmOptions; - }; - } - | { - action: "conversations.sync"; - id: string; - result: undefined; - data: undefined; - } - | { - action: "conversations.syncAll"; - id: string; - result: undefined; - data: { - consentStates?: ConsentState[]; - }; - } - | { - action: "conversations.hmacKeys"; - id: string; - result: HmacKeys; - data: undefined; - } - | { - action: "conversations.stream"; - id: string; - result: undefined; - data: { - streamId: string; - conversationType?: ConversationType; - }; - } - | { - action: "conversations.streamAllMessages"; - id: string; - result: undefined; - data: { - streamId: string; - conversationType?: ConversationType; - consentStates?: ConsentState[]; - }; - } - | { - action: "conversations.streamDeletedMessages"; - id: string; - result: undefined; - data: { - streamId: string; - }; - }; diff --git a/sdks/browser-sdk/src/types/actions/debugInformation.ts b/sdks/browser-sdk/src/types/actions/debugInformation.ts deleted file mode 100644 index fed688e0f..000000000 --- a/sdks/browser-sdk/src/types/actions/debugInformation.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { ApiStats, IdentityStats } from "@xmtp/wasm-bindings"; - -export type DebugInformationAction = - | { - action: "debugInformation.apiStatistics"; - id: string; - result: ApiStats; - data: undefined; - } - | { - action: "debugInformation.apiIdentityStatistics"; - id: string; - result: IdentityStats; - data: undefined; - } - | { - action: "debugInformation.apiAggregateStatistics"; - id: string; - result: string; - data: undefined; - } - | { - action: "debugInformation.clearAllStatistics"; - id: string; - result: undefined; - data: undefined; - }; diff --git a/sdks/browser-sdk/src/types/actions/dm.ts b/sdks/browser-sdk/src/types/actions/dm.ts deleted file mode 100644 index 00d642b7e..000000000 --- a/sdks/browser-sdk/src/types/actions/dm.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { SafeConversation } from "@/utils/conversions"; - -export type DmAction = - | { - action: "dm.peerInboxId"; - id: string; - result: string; - data: { - id: string; - }; - } - | { - action: "dm.duplicateDms"; - id: string; - result: SafeConversation[]; - data: { - id: string; - }; - }; diff --git a/sdks/browser-sdk/src/types/actions/group.ts b/sdks/browser-sdk/src/types/actions/group.ts deleted file mode 100644 index 2feb5ca1d..000000000 --- a/sdks/browser-sdk/src/types/actions/group.ts +++ /dev/null @@ -1,186 +0,0 @@ -import type { - Identifier, - MetadataField, - PermissionPolicy, - PermissionUpdateType, -} from "@xmtp/wasm-bindings"; -import type { SafeConversation } from "@/utils/conversions"; - -export type GroupAction = - | { - action: "group.listAdmins"; - id: string; - result: string[]; - data: { - id: string; - }; - } - | { - action: "group.listSuperAdmins"; - id: string; - result: string[]; - data: { - id: string; - }; - } - | { - action: "group.isAdmin"; - id: string; - result: boolean; - data: { - id: string; - inboxId: string; - }; - } - | { - action: "group.isSuperAdmin"; - id: string; - result: boolean; - data: { - id: string; - inboxId: string; - }; - } - | { - action: "group.addMembersByIdentifiers"; - id: string; - result: undefined; - data: { - id: string; - identifiers: Identifier[]; - }; - } - | { - action: "group.removeMembersByIdentifiers"; - id: string; - result: undefined; - data: { - id: string; - identifiers: Identifier[]; - }; - } - | { - action: "group.addMembers"; - id: string; - result: undefined; - data: { - id: string; - inboxIds: string[]; - }; - } - | { - action: "group.removeMembers"; - id: string; - result: undefined; - data: { - id: string; - inboxIds: string[]; - }; - } - | { - action: "group.addAdmin"; - id: string; - result: undefined; - data: { - id: string; - inboxId: string; - }; - } - | { - action: "group.removeAdmin"; - id: string; - result: undefined; - data: { - id: string; - inboxId: string; - }; - } - | { - action: "group.addSuperAdmin"; - id: string; - result: undefined; - data: { - id: string; - inboxId: string; - }; - } - | { - action: "group.removeSuperAdmin"; - id: string; - result: undefined; - data: { - id: string; - inboxId: string; - }; - } - | { - action: "group.updateName"; - id: string; - result: undefined; - data: { - id: string; - name: string; - }; - } - | { - action: "group.updateDescription"; - id: string; - result: undefined; - data: { - id: string; - description: string; - }; - } - | { - action: "group.updateImageUrl"; - id: string; - result: undefined; - data: { - id: string; - imageUrl: string; - }; - } - | { - action: "group.updateAppData"; - id: string; - result: undefined; - data: { - id: string; - appData: string; - }; - } - | { - action: "group.updatePermission"; - id: string; - result: undefined; - data: { - id: string; - permissionType: PermissionUpdateType; - policy: PermissionPolicy; - metadataField?: MetadataField; - }; - } - | { - action: "group.permissions"; - id: string; - result: SafeConversation["permissions"]; - data: { - id: string; - }; - } - | { - action: "group.requestRemoval"; - id: string; - result: undefined; - data: { - id: string; - }; - } - | { - action: "group.isPendingRemoval"; - id: string; - result: boolean; - data: { - id: string; - }; - }; diff --git a/sdks/browser-sdk/src/types/actions/opfs.ts b/sdks/browser-sdk/src/types/actions/opfs.ts deleted file mode 100644 index 6f94c3060..000000000 --- a/sdks/browser-sdk/src/types/actions/opfs.ts +++ /dev/null @@ -1,66 +0,0 @@ -export type OpfsAction = - | { - action: "opfs.init"; - id: string; - result: undefined; - data: { - enableLogging?: boolean; - }; - } - | { - action: "opfs.listFiles"; - id: string; - result: string[]; - data: undefined; - } - | { - action: "opfs.fileCount"; - id: string; - result: number; - data: undefined; - } - | { - action: "opfs.poolCapacity"; - id: string; - result: number; - data: undefined; - } - | { - action: "opfs.fileExists"; - id: string; - result: boolean; - data: { - path: string; - }; - } - | { - action: "opfs.deleteFile"; - id: string; - result: boolean; - data: { - path: string; - }; - } - | { - action: "opfs.exportDb"; - id: string; - result: Uint8Array; - data: { - path: string; - }; - } - | { - action: "opfs.importDb"; - id: string; - result: undefined; - data: { - path: string; - data: Uint8Array; - }; - } - | { - action: "opfs.clearAll"; - id: string; - result: undefined; - data: undefined; - }; diff --git a/sdks/browser-sdk/src/types/actions/preferences.ts b/sdks/browser-sdk/src/types/actions/preferences.ts deleted file mode 100644 index d0717d225..000000000 --- a/sdks/browser-sdk/src/types/actions/preferences.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { - Consent, - ConsentEntityType, - ConsentState, - GroupSyncSummary, - InboxState, -} from "@xmtp/wasm-bindings"; - -export type PreferencesAction = - | { - action: "preferences.inboxState"; - id: string; - result: InboxState; - data: { - refreshFromNetwork: boolean; - }; - } - | { - action: "preferences.getInboxStates"; - id: string; - result: InboxState[]; - data: { - inboxIds: string[]; - refreshFromNetwork: boolean; - }; - } - | { - action: "preferences.setConsentStates"; - id: string; - result: undefined; - data: { - records: Consent[]; - }; - } - | { - action: "preferences.getConsentState"; - id: string; - result: ConsentState; - data: { - entityType: ConsentEntityType; - entity: string; - }; - } - | { - action: "preferences.sync"; - id: string; - result: GroupSyncSummary; - data: undefined; - } - | { - action: "preferences.streamConsent"; - id: string; - result: undefined; - data: { - streamId: string; - }; - } - | { - action: "preferences.streamPreferences"; - id: string; - result: undefined; - data: { - streamId: string; - }; - }; diff --git a/sdks/browser-sdk/src/types/actions/streams.ts b/sdks/browser-sdk/src/types/actions/streams.ts deleted file mode 100644 index bd2a500f9..000000000 --- a/sdks/browser-sdk/src/types/actions/streams.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { - Consent, - DecodedMessage, - UserPreferenceUpdate, -} from "@xmtp/wasm-bindings"; -import type { SafeConversation } from "@/utils/conversions"; - -export type StreamAction = - | { - action: "stream.message"; - streamId: string; - result: DecodedMessage | undefined; - } - | { - action: "stream.conversation"; - streamId: string; - result: SafeConversation | undefined; - } - | { - action: "stream.consent"; - streamId: string; - result: Consent[] | undefined; - } - | { - action: "stream.preferences"; - streamId: string; - result: UserPreferenceUpdate[] | undefined; - } - | { - action: "stream.deletedMessage"; - streamId: string; - result: DecodedMessage | undefined; - } - | { - action: "stream.fail"; - streamId: string; - result: undefined; - }; - -export type StreamActionName = StreamAction["action"]; - -export type ExtractStreamAction = Extract< - StreamAction, - { action: A } ->; - -export type StreamActionResult = - ExtractStreamAction["result"]; - -export type StreamActionErrorData = { - action: StreamActionName; - error: Error; - streamId: string; -}; diff --git a/sdks/browser-sdk/src/types/options.ts b/sdks/browser-sdk/src/types/options.ts deleted file mode 100644 index ffc7c2014..000000000 --- a/sdks/browser-sdk/src/types/options.ts +++ /dev/null @@ -1,179 +0,0 @@ -import type { - ContentCodec, - ContentTypeId, -} from "@xmtp/content-type-primitives"; -import type { - Actions, - Attachment, - Backend, - DeletedMessage, - GroupUpdated, - Intent, - LeaveRequest, - LogLevel, - MultiRemoteAttachment, - Reaction, - ReadReceipt, - RemoteAttachment, - TransactionReference, - WalletSendCalls, - WasmVisibilityConfirmationOptions, - WorkerConfigOptions, -} from "@xmtp/wasm-bindings"; -import type { DecodedMessage } from "@/DecodedMessage"; - -export type VisibilityConfirmationOptions = WasmVisibilityConfirmationOptions; - -export type XmtpEnv = - | "local" - | "dev" - | "production" - | "testnet-staging" - | "testnet-dev" - | "testnet" - | "mainnet"; - -/** - * Network options - */ -export type NetworkOptions = { - /** - * Specify which XMTP environment to connect to. (default: `dev`) - */ - env?: XmtpEnv; - /** - * apiUrl can be used to override the `env` flag and connect to a - * specific endpoint - */ - apiUrl?: string; - /** - * gatewayHost can be used to override the gateway endpoint - */ - gatewayHost?: string; - /** - * Custom app version - */ - appVersion?: string; -}; - -/** - * Device sync options - */ -export type DeviceSyncOptions = { - /** - * historySyncUrl can be used to override the `env` flag and connect to a - * specific endpoint for syncing history - */ - historySyncUrl?: string | null; - /** - * Disable device sync - */ - disableDeviceSync?: boolean; -}; - -export type ContentOptions = { - /** - * Allow configuring codecs for additional content types - */ - codecs?: ContentCodec[]; -}; - -/** - * Storage options - */ -export type StorageOptions = { - /** - * Path to the local DB - * - * There are 3 value types that can be used to specify the database path: - * - * - `undefined` (or excluded from the client options) - * The database will be created in the current working directory and is based on - * the XMTP environment and client inbox ID. - * Example: `xmtp-dev-.db3` - * - * - `null` - * No database will be created and all data will be lost once the client disconnects. - * - * - `string` - * The given path will be used to create the database. - * Example: `./my-db.db3` - */ - dbPath?: string | null; - /** - * Encryption key for the local DB - */ - dbEncryptionKey?: Uint8Array; -}; - -export type OtherOptions = { - /** - * Enable structured JSON logging - */ - structuredLogging?: boolean; - /** - * Enable performance metrics - */ - performanceLogging?: boolean; - /** - * Logging level - */ - loggingLevel?: LogLevel; - /** - * Tuning for the background worker scheduler (intervals, jitter, per-worker - * overrides, and disabled workers). All fields are optional; omitting this - * object preserves the default worker behavior. - * - * Intervals are specified in nanoseconds. - */ - workerConfig?: WorkerConfigOptions; - /** - * Disable automatic registration when creating a client - */ - disableAutoRegister?: boolean; - /** - * Options for waiting until client registration is visible on the network. - * - * When set, `registerIdentity` will wait for the specified quorum of nodes - * to confirm the registration before resolving. - */ - waitForRegistrationVisible?: VisibilityConfirmationOptions; -}; - -export type ClientOptions = (NetworkOptions | { backend: Backend }) & - DeviceSyncOptions & - ContentOptions & - StorageOptions & - OtherOptions; - -export type EnrichedReply = { - referenceId: string; - content: T; - contentType: () => Promise; - inReplyTo: DecodedMessage | null; -}; - -export type BuiltInContentTypes = - | string // text, markdown - | LeaveRequest - | Reaction - | ReadReceipt - | Attachment - | RemoteAttachment - | TransactionReference - | WalletSendCalls - | Actions - | Intent - | MultiRemoteAttachment - | GroupUpdated - | DeletedMessage; - -export type ExtractCodecContentTypes = - C extends readonly [] - ? BuiltInContentTypes - : [...C][number] extends ContentCodec - ? - | T - | BuiltInContentTypes - | EnrichedReply - : BuiltInContentTypes; diff --git a/sdks/browser-sdk/src/utils/WorkerBridge.ts b/sdks/browser-sdk/src/utils/WorkerBridge.ts deleted file mode 100644 index 956f8645a..000000000 --- a/sdks/browser-sdk/src/utils/WorkerBridge.ts +++ /dev/null @@ -1,148 +0,0 @@ -import type { - ActionErrorData, - ActionName, - ActionWithoutData, - EndStreamAction, - ExtractActionData, - ExtractActionResult, - UnknownAction, -} from "@/types/actions"; -import type { - StreamAction, - StreamActionErrorData, -} from "@/types/actions/streams"; -import type { StreamOptions } from "@/utils/streams"; -import { uuid } from "@/utils/uuid"; - -const handleError = (event: ErrorEvent) => { - console.error(`[worker] error: ${event.message}`); -}; - -/** - * Class that sets up a bridge for worker communications - * - * This class is not meant to be used directly. - * - * @param worker - The worker to use for communications - * @param enableLogging - Whether to enable logging in the worker - * @returns A new WorkerBridge instance - */ -export class WorkerBridge { - #worker: Worker; - #enableLogging: boolean; - #promises = new Map< - string, - { - resolve: (value: unknown) => void; - reject: (reason?: unknown) => void; - } - >(); - - constructor(worker: Worker, enableLogging?: boolean) { - this.#worker = worker; - this.#worker.addEventListener("message", this.handleMessage); - this.#worker.addEventListener("error", handleError); - this.#enableLogging = enableLogging ?? false; - } - - /** - * Sends an action message to the worker - * - * @param action - The action to send to the worker - * @param data - The data to send to the worker - * @returns A promise that resolves when the action is completed - */ - action< - A extends ActionName, - D = ExtractActionData, - R = ExtractActionResult, - >(action: A, ...args: D extends undefined ? [] : [data: D]) { - const promiseId = uuid(); - this.#worker.postMessage({ - action, - id: promiseId, - data: args[0], - }); - const promise = new Promise((resolve, reject) => { - this.#promises.set(promiseId, { - resolve: resolve as (value: unknown) => void, - reject, - }); - }); - return promise as [R] extends [undefined] ? Promise : Promise; - } - - /** - * Handles a message from the worker - * - * @param event - The event to handle - */ - handleMessage = ( - event: MessageEvent | ActionErrorData>, - ) => { - const eventData = event.data; - if (this.#enableLogging) { - console.log("[worker] client received event data", eventData); - } - const promise = this.#promises.get(eventData.id); - if (promise) { - this.#promises.delete(eventData.id); - if ("error" in eventData) { - promise.reject(eventData.error); - } else { - promise.resolve(eventData.result); - } - } - }; - - /** - * Handles a stream message from the worker - * - * @param streamId - The ID of the stream to handle - * @param callback - The callback to handle the stream message - * @returns A function to remove the stream handler - */ - handleStreamMessage = ( - streamId: string, - callback: (error: Error | null, value: R | undefined) => void, - options?: StreamOptions, - ) => { - const streamHandler = ( - event: MessageEvent, - ) => { - const eventData = event.data; - // only handle messages for the passed stream ID - if (eventData.streamId === streamId) { - // if the stream failed, call the onFail callback - if (eventData.action === "stream.fail") { - options?.onFail?.(); - return; - } - if ("error" in eventData) { - callback(eventData.error, undefined); - } else { - callback(null, eventData.result as R); - } - } - }; - this.#worker.addEventListener("message", streamHandler); - - return async () => { - await this.action< - "endStream", - EndStreamAction["data"], - EndStreamAction["result"] - >("endStream", { streamId }); - this.#worker.removeEventListener("message", streamHandler); - }; - }; - - /** - * Removes all event listeners and terminates the worker - */ - close() { - this.#worker.removeEventListener("message", this.handleMessage); - this.#worker.removeEventListener("error", handleError); - this.#worker.terminate(); - } -} diff --git a/sdks/browser-sdk/src/utils/contentTypes.ts b/sdks/browser-sdk/src/utils/contentTypes.ts deleted file mode 100644 index 25bbb965b..000000000 --- a/sdks/browser-sdk/src/utils/contentTypes.ts +++ /dev/null @@ -1,77 +0,0 @@ -import init, { - contentTypeActions as wasmContentTypeActions, - contentTypeAttachment as wasmContentTypeAttachment, - contentTypeGroupUpdated as wasmContentTypeGroupUpdated, - contentTypeIntent as wasmContentTypeIntent, - contentTypeLeaveRequest as wasmContentTypeLeaveRequest, - contentTypeMarkdown as wasmContentTypeMarkdown, - contentTypeMultiRemoteAttachment as wasmContentTypeMultiRemoteAttachment, - contentTypeReaction as wasmContentTypeReaction, - contentTypeReadReceipt as wasmContentTypeReadReceipt, - contentTypeRemoteAttachment as wasmContentTypeRemoteAttachment, - contentTypeReply as wasmContentTypeReply, - contentTypeText as wasmContentTypeText, - contentTypeTransactionReference as wasmContentTypeTransactionReference, - contentTypeWalletSendCalls as wasmContentTypeWalletSendCalls, - decryptAttachment as wasmDecryptAttachment, - encodeActions as wasmEncodeActions, - encodeAttachment as wasmEncodeAttachment, - encodeIntent as wasmEncodeIntent, - encodeMarkdown as wasmEncodeMarkdown, - encodeMultiRemoteAttachment as wasmEncodeMultiRemoteAttachment, - encodeReaction as wasmEncodeReaction, - encodeReadReceipt as wasmEncodeReadReceipt, - encodeRemoteAttachment as wasmEncodeRemoteAttachment, - encodeText as wasmEncodeText, - encodeTransactionReference as wasmEncodeTransactionReference, - encodeWalletSendCalls as wasmEncodeWalletSendCalls, - encryptAttachment as wasmEncryptAttachment, -} from "@xmtp/wasm-bindings"; - -const wrap = - unknown>(fn: T) => - async (...args: Parameters): Promise> => { - await init(); - return fn(...args) as ReturnType; - }; - -// encoders -export const encodeActions = wrap(wasmEncodeActions); -export const encodeAttachment = wrap(wasmEncodeAttachment); -export const encodeIntent = wrap(wasmEncodeIntent); -export const encodeMarkdown = wrap(wasmEncodeMarkdown); -export const encodeMultiRemoteAttachment = wrap( - wasmEncodeMultiRemoteAttachment, -); -export const encodeReaction = wrap(wasmEncodeReaction); -export const encodeReadReceipt = wrap(wasmEncodeReadReceipt); -export const encodeRemoteAttachment = wrap(wasmEncodeRemoteAttachment); -export const encodeText = wrap(wasmEncodeText); -export const encodeTransactionReference = wrap(wasmEncodeTransactionReference); -export const encodeWalletSendCalls = wrap(wasmEncodeWalletSendCalls); - -// content types -export const contentTypeActions = wrap(wasmContentTypeActions); -export const contentTypeAttachment = wrap(wasmContentTypeAttachment); -export const contentTypeGroupUpdated = wrap(wasmContentTypeGroupUpdated); -export const contentTypeIntent = wrap(wasmContentTypeIntent); -export const contentTypeLeaveRequest = wrap(wasmContentTypeLeaveRequest); -export const contentTypeMarkdown = wrap(wasmContentTypeMarkdown); -export const contentTypeMultiRemoteAttachment = wrap( - wasmContentTypeMultiRemoteAttachment, -); -export const contentTypeReaction = wrap(wasmContentTypeReaction); -export const contentTypeReadReceipt = wrap(wasmContentTypeReadReceipt); -export const contentTypeRemoteAttachment = wrap( - wasmContentTypeRemoteAttachment, -); -export const contentTypeReply = wrap(wasmContentTypeReply); -export const contentTypeText = wrap(wasmContentTypeText); -export const contentTypeTransactionReference = wrap( - wasmContentTypeTransactionReference, -); -export const contentTypeWalletSendCalls = wrap(wasmContentTypeWalletSendCalls); - -// remote attachment encryption -export const encryptAttachment = wrap(wasmEncryptAttachment); -export const decryptAttachment = wrap(wasmDecryptAttachment); diff --git a/sdks/browser-sdk/src/utils/conversions.ts b/sdks/browser-sdk/src/utils/conversions.ts deleted file mode 100644 index 8033bb506..000000000 --- a/sdks/browser-sdk/src/utils/conversions.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { - GroupMetadata, - GroupPermissionsOptions, - HmacKey, - PermissionPolicySet, -} from "@xmtp/wasm-bindings"; -import type { WorkerConversation } from "@/WorkerConversation"; - -export type SafeConversation = { - id: string; - name: string; - imageUrl: string; - description: string; - appData: string; - permissions: { - policyType: GroupPermissionsOptions; - policySet: PermissionPolicySet; - }; - addedByInboxId: string; - metadata: GroupMetadata; - admins: string[]; - superAdmins: string[]; - createdAtNs: bigint; -}; - -export const toSafeConversation = async ( - conversation: WorkerConversation, -): Promise => { - return { - id: conversation.id, - name: conversation.name, - imageUrl: conversation.imageUrl, - description: conversation.description, - appData: conversation.appData, - permissions: conversation.permissions(), - addedByInboxId: conversation.addedByInboxId, - metadata: await conversation.metadata(), - admins: conversation.listAdmins(), - superAdmins: conversation.listSuperAdmins(), - createdAtNs: conversation.createdAtNs, - }; -}; - -export type HmacKeys = Map; - -export type LastReadTimes = Map; diff --git a/sdks/browser-sdk/src/utils/createBackend.ts b/sdks/browser-sdk/src/utils/createBackend.ts deleted file mode 100644 index 097f14ac2..000000000 --- a/sdks/browser-sdk/src/utils/createBackend.ts +++ /dev/null @@ -1,45 +0,0 @@ -import init, { - BackendBuilder, - XmtpEnv as BindingsEnv, - type Backend, -} from "@xmtp/wasm-bindings"; -import type { NetworkOptions, XmtpEnv } from "@/types/options"; - -const envMap: Record = { - local: BindingsEnv.Local, - dev: BindingsEnv.Dev, - production: BindingsEnv.Production, - "testnet-staging": BindingsEnv.TestnetStaging, - "testnet-dev": BindingsEnv.TestnetDev, - testnet: BindingsEnv.Testnet, - mainnet: BindingsEnv.Mainnet, -}; - -const reverseEnvMap: Record = { - [BindingsEnv.Local]: "local", - [BindingsEnv.Dev]: "dev", - [BindingsEnv.Production]: "production", - [BindingsEnv.TestnetStaging]: "testnet-staging", - [BindingsEnv.TestnetDev]: "testnet-dev", - [BindingsEnv.Testnet]: "testnet", - [BindingsEnv.Mainnet]: "mainnet", -}; - -export const envToString = (env: BindingsEnv): XmtpEnv => { - return reverseEnvMap[env]; -}; - -export const createBackend = async ( - options?: NetworkOptions, -): Promise => { - await init(); - const env = options?.env ?? "dev"; - let builder = new BackendBuilder(envMap[env]); - // WASM builder methods consume `self` and return a new instance, - // so we must reassign from the return value. - if (options?.apiUrl) builder = builder.setApiUrl(options.apiUrl); - if (options?.gatewayHost) - builder = builder.setGatewayHost(options.gatewayHost); - if (options?.appVersion) builder = builder.setAppVersion(options.appVersion); - return builder.build(); -}; diff --git a/sdks/browser-sdk/src/utils/createClient.ts b/sdks/browser-sdk/src/utils/createClient.ts deleted file mode 100644 index ecee8af37..000000000 --- a/sdks/browser-sdk/src/utils/createClient.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { - createClientWithBackend, - DeviceSyncMode, - generateInboxId, - getInboxIdForIdentifier, - type Backend, - type Identifier, -} from "@xmtp/wasm-bindings"; -import type { ClientOptions, NetworkOptions } from "@/types/options"; -import { createBackend, envToString } from "@/utils/createBackend"; - -type CreateClientOptions = ClientOptions extends infer T - ? T extends ClientOptions - ? Omit - : never - : never; - -const networkOptionKeys = [ - "env", - "apiUrl", - "gatewayHost", - "appVersion", -] as const; - -const hasBackend = (options: object): options is { backend: Backend } => { - return "backend" in options; -}; - -const resolveBackend = async ( - options?: CreateClientOptions, -): Promise => { - if (!options) { - return createBackend(); - } - - if (hasBackend(options)) { - // Validate that no NetworkOptions fields are also set - const conflicting = networkOptionKeys.filter( - (key) => - key in options && (options as Record)[key] != null, - ); - if (conflicting.length > 0) { - throw new Error( - `Cannot specify both 'backend' and network options (${conflicting.join(", ")}). ` + - `Use either a pre-built Backend or network options, not both.`, - ); - } - return options.backend; - } - - // No backend provided — build one from NetworkOptions - return createBackend(options as NetworkOptions); -}; - -export const createClient = async ( - identifier: Identifier, - options?: CreateClientOptions, -) => { - const backend = await resolveBackend(options); - - const inboxId = - (await getInboxIdForIdentifier(backend, identifier)) || - generateInboxId(identifier); - - const envString = envToString(backend.env); - - const dbPath = - options?.dbPath === undefined - ? `xmtp-${envString}-${inboxId}.db3` - : options.dbPath; - - const isLogging = - options && - (options.loggingLevel !== undefined || - options.structuredLogging || - options.performanceLogging); - - const deviceSyncMode = options?.disableDeviceSync - ? DeviceSyncMode.Disabled - : DeviceSyncMode.Enabled; - - const client = await createClientWithBackend( - backend, - inboxId, - identifier, - dbPath, - options?.dbEncryptionKey, - deviceSyncMode, - options?.workerConfig, - isLogging - ? { - structured: options.structuredLogging ?? false, - performance: options.performanceLogging ?? false, - level: options.loggingLevel, - } - : undefined, - undefined, // allowOffline - undefined, // nonce - ); - - return { client, env: envString }; -}; diff --git a/sdks/browser-sdk/src/utils/date.ts b/sdks/browser-sdk/src/utils/date.ts deleted file mode 100644 index b15e9987b..000000000 --- a/sdks/browser-sdk/src/utils/date.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function nsToDate(ns: bigint): Date { - return new Date(Number(ns / 1_000_000n)); -} diff --git a/sdks/browser-sdk/src/utils/errors.ts b/sdks/browser-sdk/src/utils/errors.ts deleted file mode 100644 index e3ea916c2..000000000 --- a/sdks/browser-sdk/src/utils/errors.ts +++ /dev/null @@ -1,68 +0,0 @@ -export class ClientNotInitializedError extends Error { - constructor() { - super( - "Client not initialized, use Client.create or Client.build to create a client", - ); - } -} - -export class SignerUnavailableError extends Error { - constructor() { - super( - "Signer unavailable, use Client.create to create a client with a signer", - ); - } -} - -export class InboxReassignError extends Error { - constructor() { - super( - "Unable to create add account signature text, `allowInboxReassign` must be true", - ); - } -} - -export class AccountAlreadyAssociatedError extends Error { - constructor(inboxId: string) { - super(`Account already associated with inbox ${inboxId}`); - } -} - -export class GroupNotFoundError extends Error { - constructor(groupId: string) { - super(`Group "${groupId}" not found`); - } -} - -export class StreamNotFoundError extends Error { - constructor(streamId: string) { - super(`Stream "${streamId}" not found`); - } -} - -export class StreamFailedError extends Error { - constructor(retryAttempts: number) { - const times = `time${retryAttempts !== 1 ? "s" : ""}`; - super(`Stream failed, retried ${retryAttempts} ${times}`); - } -} - -export class StreamInvalidRetryAttemptsError extends Error { - constructor() { - super("Stream retry attempts must be greater than 0"); - } -} - -export class OpfsNotInitializedError extends Error { - constructor() { - super("OPFS must be initialized before accessing its methods"); - } -} - -export class OpfsInitializationError extends Error { - constructor() { - super( - "Failed to initialize OPFS, ensure that there are no other active XMTP clients or Opfs instances", - ); - } -} diff --git a/sdks/browser-sdk/src/utils/inboxId.ts b/sdks/browser-sdk/src/utils/inboxId.ts deleted file mode 100644 index fef93de7b..000000000 --- a/sdks/browser-sdk/src/utils/inboxId.ts +++ /dev/null @@ -1,36 +0,0 @@ -import init, { - generateInboxId as wasmGenerateInboxId, - getInboxIdForIdentifier as wasmGetInboxIdForIdentifier, - type Backend, - type Identifier, -} from "@xmtp/wasm-bindings"; - -/** - * Generates an inbox ID for a given identifier - * - * @param identifier - The identifier to generate an inbox ID for - * @param nonce - Optional nonce to use for generating the inbox ID - * @returns Promise that resolves with the generated inbox ID - */ -export const generateInboxId = async ( - identifier: Identifier, - nonce?: bigint, -): Promise => { - await init(); - return wasmGenerateInboxId(identifier, nonce); -}; - -/** - * Gets the inbox ID for a specific identifier using a Backend - * - * @param backend - The Backend instance for API communication - * @param identifier - The identifier to get the inbox ID for - * @returns Promise that resolves with the inbox ID for the identifier - */ -export const getInboxIdForIdentifier = async ( - backend: Backend, - identifier: Identifier, -): Promise => { - await init(); - return wasmGetInboxIdForIdentifier(backend, identifier); -}; diff --git a/sdks/browser-sdk/src/utils/inboxState.ts b/sdks/browser-sdk/src/utils/inboxState.ts deleted file mode 100644 index 9c4a86ffc..000000000 --- a/sdks/browser-sdk/src/utils/inboxState.ts +++ /dev/null @@ -1,19 +0,0 @@ -import init, { - inboxStateFromInboxIds as wasmInboxStateFromInboxIds, - type Backend, -} from "@xmtp/wasm-bindings"; - -/** - * Gets the inbox state for the specified inbox IDs using a Backend - * - * @param backend - The Backend instance for API communication - * @param inboxIds - The inbox IDs to get the state for - * @returns The inbox state for the specified inbox IDs - */ -export const inboxStateFromInboxIds = async ( - backend: Backend, - inboxIds: string[], -) => { - await init(); - return wasmInboxStateFromInboxIds(backend, inboxIds); -}; diff --git a/sdks/browser-sdk/src/utils/installations.ts b/sdks/browser-sdk/src/utils/installations.ts deleted file mode 100644 index 18eafc106..000000000 --- a/sdks/browser-sdk/src/utils/installations.ts +++ /dev/null @@ -1,86 +0,0 @@ -import init, { - applySignatureRequest, - revokeInstallationsSignatureRequest, - type Backend, - type Identifier, - type SignatureRequestHandle, -} from "@xmtp/wasm-bindings"; -import type { Signer } from "@/utils/signer"; - -/** - * Creates signature text for revoking installations - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `revokeInstallations` function instead. - * - * @param backend - The Backend instance for API communication - * @param identifier - The identifier to revoke installations for - * @param inboxId - The inbox ID to revoke installations for - * @param installationIds - The installation IDs to revoke - * @returns The signature text and signature request ID - */ -export const revokeInstallationsSignatureText = async ( - backend: Backend, - identifier: Identifier, - inboxId: string, - installationIds: Uint8Array[], -): Promise<{ - signatureText: string; - signatureRequest: SignatureRequestHandle; -}> => { - await init(); - const signatureRequest = revokeInstallationsSignatureRequest( - backend, - identifier, - inboxId, - installationIds, - ); - const signatureText = await signatureRequest.signatureText(); - return { signatureText, signatureRequest }; -}; - -/** - * Revokes installations for a given inbox ID - * - * @param backend - The Backend instance for API communication - * @param signer - The signer to use - * @param inboxId - The inbox ID to revoke installations for - * @param installationIds - The installation IDs to revoke - * @returns Promise that resolves when the revoke installations operation is complete - */ -export const revokeInstallations = async ( - backend: Backend, - signer: Signer, - inboxId: string, - installationIds: Uint8Array[], -): Promise => { - await init(); - const identifier = await signer.getIdentifier(); - const { signatureText, signatureRequest } = - await revokeInstallationsSignatureText( - backend, - identifier, - inboxId, - installationIds, - ); - const signature = await signer.signMessage(signatureText); - - switch (signer.type) { - case "EOA": - await signatureRequest.addEcdsaSignature(signature); - break; - case "SCW": - await signatureRequest.addScwSignature( - identifier, - signature, - signer.getChainId(), - signer.getBlockNumber?.(), - ); - break; - } - - await applySignatureRequest(backend, signatureRequest); -}; diff --git a/sdks/browser-sdk/src/utils/messages.ts b/sdks/browser-sdk/src/utils/messages.ts deleted file mode 100644 index c0252e42a..000000000 --- a/sdks/browser-sdk/src/utils/messages.ts +++ /dev/null @@ -1,92 +0,0 @@ -import type { - Actions, - Attachment, - GroupUpdated, - Intent, - LeaveRequest, - MultiRemoteAttachment, - Reaction, - ReadReceipt, - RemoteAttachment, - TransactionReference, - WalletSendCalls, -} from "@xmtp/wasm-bindings"; -import type { DecodedMessage } from "@/DecodedMessage"; -import type { EnrichedReply } from "@/types/options"; - -export const isReaction = (m: DecodedMessage): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "reaction"; - -export const isReply = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && m.contentType.typeId === "reply"; - -export const isTextReply = ( - m: DecodedMessage, -): m is DecodedMessage> => - isReply(m) && typeof m.content?.content === "string"; - -export const isText = (m: DecodedMessage): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && m.contentType.typeId === "text"; - -export const isRemoteAttachment = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "remoteStaticAttachment"; - -export const isAttachment = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "attachment"; - -export const isMultiRemoteAttachment = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "multiRemoteStaticAttachment"; - -export const isTransactionReference = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "transactionReference"; - -export const isGroupUpdated = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "group_updated"; - -export const isReadReceipt = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "readReceipt"; - -export const isLeaveRequest = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "leave_request"; - -export const isWalletSendCalls = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "walletSendCalls"; - -export const isIntent = (m: DecodedMessage): m is DecodedMessage => - m.contentType.authorityId === "coinbase.com" && - m.contentType.typeId === "intent"; - -export const isActions = (m: DecodedMessage): m is DecodedMessage => - m.contentType.authorityId === "coinbase.com" && - m.contentType.typeId === "actions"; - -export const isMarkdown = (m: DecodedMessage): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "markdown"; diff --git a/sdks/browser-sdk/src/utils/metadata.ts b/sdks/browser-sdk/src/utils/metadata.ts deleted file mode 100644 index d20429ccd..000000000 --- a/sdks/browser-sdk/src/utils/metadata.ts +++ /dev/null @@ -1,15 +0,0 @@ -import init, { - metadataFieldName as wasmMetadataFieldName, - type MetadataField, -} from "@xmtp/wasm-bindings"; - -/** - * Gets the name of a metadata field - * - * @param field - The metadata field to get the name for - * @returns The name of the metadata field - */ -export const metadataFieldName = async (field: MetadataField) => { - await init(); - return wasmMetadataFieldName(field); -}; diff --git a/sdks/browser-sdk/src/utils/signer.ts b/sdks/browser-sdk/src/utils/signer.ts deleted file mode 100644 index 3a65c26e6..000000000 --- a/sdks/browser-sdk/src/utils/signer.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { IdentifierKind, type Identifier } from "@xmtp/wasm-bindings"; -import { toBytes } from "viem"; -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; - -type SignMessage = (message: string) => Promise | Uint8Array; -type GetIdentifier = () => Promise | Identifier; -type GetChainId = () => bigint; -type GetBlockNumber = () => bigint; - -export type Signer = - | { - type: "EOA"; - getIdentifier: GetIdentifier; - signMessage: SignMessage; - } - | { - type: "SCW"; - getIdentifier: GetIdentifier; - signMessage: SignMessage; - getBlockNumber?: GetBlockNumber; - getChainId: GetChainId; - }; - -export type EOASigner = Extract; -export type SCWSigner = Extract; - -export type SafeSigner = - | { - type: "EOA"; - identifier: Identifier; - signature: Uint8Array; - } - | { - type: "SCW"; - identifier: Identifier; - signature: Uint8Array; - chainId: bigint; - blockNumber?: bigint; - }; - -export const createEOASigner = (key = generatePrivateKey()): Signer => { - const account = privateKeyToAccount(key); - return { - type: "EOA", - getIdentifier: () => ({ - identifier: account.address.toLowerCase(), - identifierKind: IdentifierKind.Ethereum, - }), - signMessage: async (message: string) => { - const signature = await account.signMessage({ message }); - return toBytes(signature); - }, - }; -}; - -export const createSCWSigner = ( - address: `0x${string}`, - signMessage: (message: string) => Promise | string, - chainId: bigint, -): Signer => { - return { - type: "SCW", - getIdentifier: () => ({ - identifier: address.toLowerCase(), - identifierKind: IdentifierKind.Ethereum, - }), - signMessage: async (message: string) => { - const signature = await signMessage(message); - return toBytes(signature); - }, - getChainId: () => chainId, - }; -}; - -export const toSafeSigner = async ( - signer: Signer, - signature: Uint8Array, -): Promise => { - switch (signer.type) { - case "EOA": - return { - type: "EOA", - identifier: await signer.getIdentifier(), - signature, - }; - case "SCW": - return { - type: "SCW", - identifier: await signer.getIdentifier(), - signature, - chainId: signer.getChainId(), - blockNumber: signer.getBlockNumber?.(), - }; - } -}; diff --git a/sdks/browser-sdk/src/utils/streams.ts b/sdks/browser-sdk/src/utils/streams.ts deleted file mode 100644 index 911d0d907..000000000 --- a/sdks/browser-sdk/src/utils/streams.ts +++ /dev/null @@ -1,219 +0,0 @@ -import { AsyncStream, createAsyncStreamProxy } from "@/AsyncStream"; -import { StreamFailedError, StreamInvalidRetryAttemptsError } from "./errors"; - -const isPromise = (value: unknown): value is Promise => { - return ( - !!value && - (typeof value === "object" || typeof value === "function") && - "then" in value && - typeof value.then === "function" - ); -}; - -const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - -export const DEFAULT_RETRY_DELAY = 10000; // milliseconds -export const DEFAULT_RETRY_ATTEMPTS = 6; - -export type StreamOptions = { - /** - * Called when the stream ends - */ - onEnd?: () => void; - /** - * Called when a stream error occurs - */ - onError?: (error: Error) => void; - /** - * Called when the stream fails - */ - onFail?: () => void; - /** - * Called when the stream is restarted - */ - onRestart?: () => void; - /** - * Called when the stream is retried - */ - onRetry?: (attempts: number, maxAttempts: number) => void; - /** - * Called when a value is emitted from the stream - */ - onValue?: (value: V) => void; - /** - * The number of times to retry the stream - * (default: 6) - */ - retryAttempts?: number; - /** - * The delay between retries (in milliseconds) - * (default: 10000) - */ - retryDelay?: number; - /** - * Whether to retry the stream if it fails - * (default: true) - */ - retryOnFail?: boolean; - /** - * Whether to disable network sync before starting the stream - * (default: false) - */ - disableSync?: boolean; -}; - -export type StreamCallback = ( - error: Error | null, - value: T | undefined, -) => void; - -export type StreamFunction = ( - callback: StreamCallback, - onFail: () => void, -) => Promise<() => void>; - -export type StreamValueMutator = ( - value: T, -) => V | Promise; - -/** - * Creates a stream from a stream function - * - * If the stream fails, an attempt will be made to restart it. - * - * This function is not intended to be used directly. - * - * @param streamFunction - The stream function to create a stream from - * @param streamValueMutator - An optional function to mutate the value emitted from the stream - * @param options - The options for the stream - * @param args - Additional arguments to pass to the stream function - * @returns An async iterable stream proxy - * @throws {StreamInvalidRetryAttemptsError} if the retryAttempts option is less than 0 and retryOnFail is true - * @throws {StreamFailedError} if the stream fails and can't be restarted - */ -export const createStream = async ( - streamFunction: StreamFunction, - streamValueMutator?: StreamValueMutator, - options?: StreamOptions, -) => { - const { - onEnd, - onError, - onFail, - onRestart, - onRetry, - onValue, - retryAttempts = DEFAULT_RETRY_ATTEMPTS, - retryDelay = DEFAULT_RETRY_DELAY, - retryOnFail = true, - } = options ?? {}; - // retry attempts must be greater than 0 - if (retryOnFail && retryAttempts < 0) { - throw new StreamInvalidRetryAttemptsError(); - } - - const asyncStream = new AsyncStream(); - const streamCallback: StreamCallback = (error, value) => { - // if a stream error occurs, call the onError callback - if (error) { - onError?.(error); - return; - } - // ensure the value is not undefined - if (value !== undefined) { - try { - // if a streamValueMutator is provided, mutate the value - if (streamValueMutator) { - const mutatedValue = streamValueMutator(value); - if (isPromise(mutatedValue)) { - void mutatedValue - .then((mutatedValue) => { - if (mutatedValue !== undefined) { - asyncStream.push(mutatedValue); - onValue?.(mutatedValue); - } - }) - .catch((error: unknown) => { - onError?.(error as Error); - }); - } else { - if (mutatedValue !== undefined) { - asyncStream.push(mutatedValue); - onValue?.(mutatedValue); - } - } - } else { - asyncStream.push(value as unknown as V); - onValue?.(value as unknown as V); - } - } catch (error) { - onError?.(error as Error); - } - } - }; - const retry = async (retries: number = retryAttempts) => { - try { - // if the stream has been retried the maximum number of times without - // success, throw an error - if (retries === 0) { - void asyncStream.end(); - throw new StreamFailedError(retryAttempts); - } - - // wait for the retry delay before attempting to restart the stream - await wait(retryDelay); - // call the onRetry callback - onRetry?.(retryAttempts - retries + 1, retryAttempts); - - // attempt to restart the stream - const streamCloser = await streamFunction(streamCallback, () => { - // call the onFail callback - onFail?.(); - void retry(); - }); - - // when the async stream is done, end the stream - asyncStream.onDone = () => { - streamCloser(); - onEnd?.(); - }; - - // stream restarted, call the onRestart callback - onRestart?.(); - } catch (error) { - onError?.(error as Error); - // retry - void retry(retries - 1); - } - }; - const startRetry = () => { - // if the stream should be retried, start the process - if (retryOnFail) { - void retry(); - } else { - void asyncStream.end(); - // stream failed and should not be retried, throw an error - throw new StreamFailedError(0); - } - }; - - try { - // create the stream - const streamCloser = await streamFunction(streamCallback, () => { - // call the onFail callback - onFail?.(); - startRetry(); - }); - // when the async stream is done, end the stream - asyncStream.onDone = () => { - streamCloser(); - onEnd?.(); - }; - } catch (error) { - onError?.(error as Error); - startRetry(); - } - - // return a proxy for the async stream - return createAsyncStreamProxy(asyncStream); -}; diff --git a/sdks/browser-sdk/src/utils/uuid.ts b/sdks/browser-sdk/src/utils/uuid.ts deleted file mode 100644 index f0ef7e215..000000000 --- a/sdks/browser-sdk/src/utils/uuid.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Generates a unique identifier using crypto.getRandomValues() - */ -export const uuid = (): string => { - const bytes = new Uint8Array(16); - crypto.getRandomValues(bytes); - return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join(""); -}; diff --git a/sdks/browser-sdk/src/workers/client.ts b/sdks/browser-sdk/src/workers/client.ts deleted file mode 100644 index ec1730717..000000000 --- a/sdks/browser-sdk/src/workers/client.ts +++ /dev/null @@ -1,1159 +0,0 @@ -import init, { - LogLevel, - type Consent, - type Conversation, - type DecodedMessage, - type Message, - type SignatureRequestHandle, - type StreamCloser, - type UserPreferenceUpdate, -} from "@xmtp/wasm-bindings"; -import type { - ActionErrorData, - ActionName, - ActionWithoutResult, - ClientWorkerAction, - ExtractActionWithoutData, -} from "@/types/actions"; -import type { - ExtractStreamAction, - StreamActionErrorData, - StreamActionName, -} from "@/types/actions/streams"; -import { toSafeConversation } from "@/utils/conversions"; -import { - ClientNotInitializedError, - GroupNotFoundError, - StreamNotFoundError, -} from "@/utils/errors"; -import { WorkerClient } from "@/WorkerClient"; -import { WorkerConversation } from "@/WorkerConversation"; - -let maybeClient: WorkerClient | undefined; -let enableLogging = false; - -const streamClosers = new Map(); -const signatureRequests = new Map(); - -/** - * Type-safe postMessage - */ -const postMessage = >( - data: ExtractActionWithoutData, -) => { - self.postMessage(data); -}; - -/** - * Type-safe postMessage for errors - */ -const postMessageError = (data: ActionErrorData) => { - self.postMessage(data); -}; - -/** - * Type-safe postMessage for streams - */ -const postStreamMessage = ( - data: ExtractStreamAction, -) => { - self.postMessage(data); -}; - -/** - * Type-safe postMessage for stream errors - */ -const postStreamMessageError = (data: StreamActionErrorData) => { - self.postMessage(data); -}; - -self.onmessage = async ( - event: MessageEvent>, -) => { - const { action, id, data } = event.data; - - if (enableLogging) { - console.log("client worker received event data", event.data); - } - - // initialize WASM module - await init(); - - try { - // init is a special action that initializes the client - if (action === "client.init" && !maybeClient) { - maybeClient = await WorkerClient.create(data.identifier, data.options); - enableLogging = - data.options?.loggingLevel !== undefined && - data.options.loggingLevel !== LogLevel.Off; - postMessage({ - id, - action, - result: { - appVersion: maybeClient.appVersion, - env: maybeClient.env, - inboxId: maybeClient.inboxId, - installationId: maybeClient.installationId, - installationIdBytes: maybeClient.installationIdBytes, - libxmtpVersion: maybeClient.libxmtpVersion, - }, - }); - return; - } - - // a client is required for all other actions - if (!maybeClient) { - throw new ClientNotInitializedError(); - } - - // let typescript know that a client will be available for the rest - // of this code block - const client = maybeClient; - - // helper function that throws an error if the group is not found - const getGroup = (groupId: string) => { - const group = client.conversations.getConversationById(groupId); - if (!group) { - throw new GroupNotFoundError(groupId); - } - return group; - }; - - switch (action) { - /** - * Stream actions - */ - case "endStream": { - const streamCloser = streamClosers.get(data.streamId); - if (streamCloser) { - streamCloser.end(); - streamClosers.delete(data.streamId); - postMessage({ id, action, result: undefined }); - } else { - throw new StreamNotFoundError(data.streamId); - } - break; - } - /** - * Client actions - */ - case "client.applySignatureRequest": { - const signatureRequest = signatureRequests.get(data.signatureRequestId); - if (!signatureRequest) { - throw new Error("Signature request not found"); - } - await client.processSignatureRequest(data.signer, signatureRequest); - signatureRequests.delete(data.signatureRequestId); - postMessage({ id, action, result: undefined }); - break; - } - case "client.createInboxSignatureText": { - const result: { - signatureText?: string; - signatureRequestId?: string; - } = { - signatureText: undefined, - signatureRequestId: undefined, - }; - try { - const signatureRequest = client.createInboxSignatureRequest(); - if (signatureRequest) { - result.signatureText = await signatureRequest.signatureText(); - result.signatureRequestId = data.signatureRequestId; - signatureRequests.set(data.signatureRequestId, signatureRequest); - } - } finally { - postMessage({ id, action, result }); - } - break; - } - case "client.addAccountSignatureText": { - const signatureRequest = await client.addAccountSignatureRequest( - data.newIdentifier, - ); - const result = { - signatureText: await signatureRequest.signatureText(), - signatureRequestId: data.signatureRequestId, - }; - signatureRequests.set(data.signatureRequestId, signatureRequest); - postMessage({ id, action, result }); - break; - } - case "client.removeAccountSignatureText": { - const signatureRequest = await client.removeAccountSignatureRequest( - data.identifier, - ); - const result = { - signatureText: await signatureRequest.signatureText(), - signatureRequestId: data.signatureRequestId, - }; - signatureRequests.set(data.signatureRequestId, signatureRequest); - postMessage({ id, action, result }); - break; - } - case "client.revokeAllOtherInstallationsSignatureText": { - const signatureRequest = - await client.revokeAllOtherInstallationsSignatureRequest(); - const result = { - signatureText: await signatureRequest?.signatureText(), - signatureRequestId: data.signatureRequestId, - }; - if (signatureRequest) { - signatureRequests.set(data.signatureRequestId, signatureRequest); - } - postMessage({ id, action, result }); - break; - } - case "client.revokeInstallationsSignatureText": { - const signatureRequest = - await client.revokeInstallationsSignatureRequest( - data.installationIds, - ); - const result = { - signatureText: await signatureRequest.signatureText(), - signatureRequestId: data.signatureRequestId, - }; - signatureRequests.set(data.signatureRequestId, signatureRequest); - postMessage({ id, action, result }); - break; - } - case "client.changeRecoveryIdentifierSignatureText": { - const signatureRequest = - await client.changeRecoveryIdentifierSignatureRequest( - data.identifier, - ); - const result = { - signatureText: await signatureRequest.signatureText(), - signatureRequestId: data.signatureRequestId, - }; - signatureRequests.set(data.signatureRequestId, signatureRequest); - postMessage({ id, action, result }); - break; - } - case "client.registerIdentity": { - const signatureRequest = signatureRequests.get(data.signatureRequestId); - if (!signatureRequest) { - throw new Error("Signature request not found"); - } - await client.registerIdentity( - data.signer, - signatureRequest, - data.waitForRegistrationVisible, - ); - signatureRequests.delete(data.signatureRequestId); - postMessage({ id, action, result: undefined }); - break; - } - case "client.addAccount": { - const signatureRequest = signatureRequests.get(data.signatureRequestId); - if (!signatureRequest) { - throw new Error("Signature request not found"); - } - await client.processSignatureRequest(data.signer, signatureRequest); - signatureRequests.delete(data.signatureRequestId); - postMessage({ id, action, result: undefined }); - break; - } - case "client.removeAccount": { - const signatureRequest = signatureRequests.get(data.signatureRequestId); - if (!signatureRequest) { - throw new Error("Signature request not found"); - } - await client.processSignatureRequest(data.signer, signatureRequest); - signatureRequests.delete(data.signatureRequestId); - postMessage({ id, action, result: undefined }); - break; - } - case "client.revokeAllOtherInstallations": { - const signatureRequest = signatureRequests.get(data.signatureRequestId); - if (!signatureRequest) { - throw new Error("Signature request not found"); - } - await client.processSignatureRequest(data.signer, signatureRequest); - signatureRequests.delete(data.signatureRequestId); - postMessage({ id, action, result: undefined }); - break; - } - case "client.revokeInstallations": { - const signatureRequest = signatureRequests.get(data.signatureRequestId); - if (!signatureRequest) { - throw new Error("Signature request not found"); - } - await client.processSignatureRequest(data.signer, signatureRequest); - signatureRequests.delete(data.signatureRequestId); - postMessage({ id, action, result: undefined }); - break; - } - case "client.changeRecoveryIdentifier": { - const signatureRequest = signatureRequests.get(data.signatureRequestId); - if (!signatureRequest) { - throw new Error("Signature request not found"); - } - await client.processSignatureRequest(data.signer, signatureRequest); - signatureRequests.delete(data.signatureRequestId); - postMessage({ id, action, result: undefined }); - break; - } - case "client.isRegistered": { - const result = client.isRegistered; - postMessage({ id, action, result }); - break; - } - case "client.canMessage": { - const result = await client.canMessage(data.identifiers); - postMessage({ id, action, result }); - break; - } - case "client.fetchLatestInboxUpdatesCount": { - const result = await client.fetchLatestInboxUpdatesCount(data.inboxIds); - postMessage({ id, action, result }); - break; - } - case "client.fetchOwnInboxUpdatesCount": { - const result = await client.fetchOwnInboxUpdatesCount(); - postMessage({ id, action, result }); - break; - } - case "client.getInboxIdByIdentifier": { - const result = await client.getInboxIdByIdentifier(data.identifier); - postMessage({ id, action, result }); - break; - } - case "client.signWithInstallationKey": { - const result = client.signWithInstallationKey(data.signatureText); - postMessage({ id, action, result }); - break; - } - case "client.verifySignedWithInstallationKey": { - const result = client.verifySignedWithInstallationKey( - data.signatureText, - data.signatureBytes, - ); - postMessage({ id, action, result }); - break; - } - case "client.verifySignedWithPublicKey": { - const result = client.verifySignedWithPublicKey( - data.signatureText, - data.signatureBytes, - data.publicKey, - ); - postMessage({ id, action, result }); - break; - } - case "client.fetchKeyPackageStatuses": { - const result = await client.fetchKeyPackageStatuses( - data.installationIds, - ); - postMessage({ - id, - action, - result, - }); - break; - } - case "client.sendSyncRequest": { - await client.sendSyncRequest(data.options, data.serverUrl); - postMessage({ id, action, result: undefined }); - break; - } - case "client.sendSyncArchive": { - await client.sendSyncArchive(data.options, data.serverUrl, data.pin); - postMessage({ id, action, result: undefined }); - break; - } - case "client.processSyncArchive": { - await client.processSyncArchive(data.archivePin); - postMessage({ id, action, result: undefined }); - break; - } - case "client.listAvailableArchives": { - const result = client.listAvailableArchives(data.daysCutoff); - postMessage({ id, action, result }); - break; - } - case "client.createArchive": { - const result = await client.createArchive(data.opts, data.key); - postMessage({ id, action, result }); - break; - } - case "client.importArchive": { - await client.importArchive(data.data, data.key); - postMessage({ id, action, result: undefined }); - break; - } - case "client.archiveMetadata": { - const result = await client.archiveMetadata(data.data, data.key); - postMessage({ id, action, result }); - break; - } - case "client.syncAllDeviceSyncGroups": { - const result = await client.syncAllDeviceSyncGroups(); - postMessage({ id, action, result }); - break; - } - /** - * Debug information actions - */ - case "debugInformation.apiStatistics": { - const result = client.debugInformation.apiStatistics(); - postMessage({ id, action, result }); - break; - } - case "debugInformation.apiIdentityStatistics": { - const result = client.debugInformation.apiIdentityStatistics(); - postMessage({ id, action, result }); - break; - } - case "debugInformation.apiAggregateStatistics": { - const result = client.debugInformation.apiAggregateStatistics(); - postMessage({ id, action, result }); - break; - } - case "debugInformation.clearAllStatistics": { - client.debugInformation.clearAllStatistics(); - postMessage({ id, action, result: undefined }); - break; - } - /** - * Preferences actions - */ - case "preferences.inboxState": { - const result = await client.preferences.inboxState( - data.refreshFromNetwork, - ); - postMessage({ id, action, result }); - break; - } - case "preferences.getInboxStates": { - const result = await client.preferences.getInboxStates( - data.inboxIds, - data.refreshFromNetwork, - ); - postMessage({ id, action, result }); - break; - } - case "preferences.setConsentStates": { - await client.preferences.setConsentStates(data.records); - postMessage({ id, action, result: undefined }); - break; - } - case "preferences.getConsentState": { - const result = await client.preferences.getConsentState( - data.entityType, - data.entity, - ); - postMessage({ id, action, result }); - break; - } - case "preferences.sync": { - const result = await client.preferences.sync(); - postMessage({ id, action, result }); - break; - } - case "preferences.streamConsent": { - const streamCallback = ( - error: Error | null, - value: Consent[] | undefined, - ) => { - if (error) { - postStreamMessageError({ - action: "stream.consent", - streamId: data.streamId, - error, - }); - } else { - postStreamMessage({ - action: "stream.consent", - streamId: data.streamId, - result: value ?? [], - }); - } - }; - const streamCloser = client.preferences.streamConsent( - streamCallback, - () => { - streamClosers.delete(data.streamId); - postStreamMessage({ - action: "stream.fail", - streamId: data.streamId, - result: undefined, - }); - }, - ); - streamClosers.set(data.streamId, streamCloser); - postMessage({ - id, - action, - result: undefined, - }); - break; - } - case "preferences.streamPreferences": { - const streamCallback = ( - error: Error | null, - value: UserPreferenceUpdate[] | undefined, - ) => { - if (error) { - postStreamMessageError({ - action: "stream.preferences", - streamId: data.streamId, - error, - }); - } else { - postStreamMessage({ - action: "stream.preferences", - streamId: data.streamId, - result: value ?? undefined, - }); - } - }; - const streamCloser = client.preferences.streamPreferences( - streamCallback, - () => { - streamClosers.delete(data.streamId); - postStreamMessage({ - action: "stream.fail", - streamId: data.streamId, - result: undefined, - }); - }, - ); - streamClosers.set(data.streamId, streamCloser); - postMessage({ - id, - action, - result: undefined, - }); - break; - } - /** - * Conversations actions - */ - case "conversations.stream": { - const streamCallback = ( - error: Error | null, - value: Conversation | undefined, - ) => { - if (error) { - postStreamMessageError({ - action: "stream.conversation", - streamId: data.streamId, - error, - }); - } else { - if (value) { - toSafeConversation(new WorkerConversation(client, value)) - .then((result) => { - postStreamMessage({ - action: "stream.conversation", - streamId: data.streamId, - result, - }); - }) - .catch((error: unknown) => { - postStreamMessageError({ - action: "stream.conversation", - streamId: data.streamId, - error: error as Error, - }); - }); - } else { - postStreamMessage({ - action: "stream.conversation", - streamId: data.streamId, - result: undefined, - }); - } - } - }; - const streamCloser = client.conversations.stream( - streamCallback, - () => { - streamClosers.delete(data.streamId); - postStreamMessage({ - action: "stream.fail", - streamId: data.streamId, - result: undefined, - }); - }, - data.conversationType, - ); - streamClosers.set(data.streamId, streamCloser); - postMessage({ id, action, result: undefined }); - break; - } - case "conversations.streamAllMessages": { - const streamCallback = ( - error: Error | null, - value: Message | undefined, - ) => { - if (error) { - postStreamMessageError({ - action: "stream.message", - streamId: data.streamId, - error, - }); - } else if (value) { - void client.conversations - .getMessageById(value.id) - .then((enrichedMessage) => { - // guard against any edge cases where the message is not found - if (enrichedMessage) { - postStreamMessage({ - action: "stream.message", - streamId: data.streamId, - result: enrichedMessage, - }); - } - }); - } - }; - const streamCloser = client.conversations.streamAllMessages( - streamCallback, - () => { - streamClosers.delete(data.streamId); - postStreamMessage({ - action: "stream.fail", - streamId: data.streamId, - result: undefined, - }); - }, - data.conversationType, - data.consentStates, - ); - streamClosers.set(data.streamId, streamCloser); - postMessage({ id, action, result: undefined }); - break; - } - case "conversations.streamDeletedMessages": { - const streamCallback = ( - error: Error | null, - value: DecodedMessage | undefined, - ) => { - if (error) { - postStreamMessageError({ - action: "stream.deletedMessage", - streamId: data.streamId, - error, - }); - } else { - postStreamMessage({ - action: "stream.deletedMessage", - streamId: data.streamId, - result: value, - }); - } - }; - const streamCloser = - client.conversations.streamDeletedMessages(streamCallback); - streamClosers.set(data.streamId, streamCloser); - postMessage({ id, action, result: undefined }); - break; - } - case "conversations.list": { - const conversations = client.conversations.list(data.options); - const result = await Promise.all( - conversations.map((conversation) => toSafeConversation(conversation)), - ); - postMessage({ id, action, result }); - break; - } - case "conversations.listGroups": { - const conversations = client.conversations.listGroups(data.options); - const result = await Promise.all( - conversations.map((conversation) => toSafeConversation(conversation)), - ); - postMessage({ id, action, result }); - break; - } - case "conversations.listDms": { - const conversations = client.conversations.listDms(data.options); - const result = await Promise.all( - conversations.map((conversation) => toSafeConversation(conversation)), - ); - postMessage({ id, action, result }); - break; - } - case "conversations.createGroupOptimistic": { - const conversation = client.conversations.createGroupOptimistic( - data.options, - ); - const result = await toSafeConversation(conversation); - postMessage({ id, action, result }); - break; - } - case "conversations.createGroupWithIdentifiers": { - const conversation = - await client.conversations.createGroupWithIdentifiers( - data.identifiers, - data.options, - ); - const result = await toSafeConversation(conversation); - postMessage({ id, action, result }); - break; - } - case "conversations.createGroup": { - const conversation = await client.conversations.createGroup( - data.inboxIds, - data.options, - ); - const result = await toSafeConversation(conversation); - postMessage({ id, action, result }); - break; - } - case "conversations.createDmWithIdentifier": { - const conversation = await client.conversations.createDmWithIdentifier( - data.identifier, - data.options, - ); - const result = await toSafeConversation(conversation); - postMessage({ id, action, result }); - break; - } - case "conversations.createDm": { - const conversation = await client.conversations.createDm( - data.inboxId, - data.options, - ); - const result = await toSafeConversation(conversation); - postMessage({ id, action, result }); - break; - } - case "conversations.sync": { - await client.conversations.sync(); - postMessage({ id, action, result: undefined }); - break; - } - case "conversations.syncAll": { - await client.conversations.syncAll(data.consentStates); - postMessage({ id, action, result: undefined }); - break; - } - case "conversations.getConversationById": { - const conversation = client.conversations.getConversationById(data.id); - const result = conversation - ? await toSafeConversation(conversation) - : undefined; - postMessage({ id, action, result }); - break; - } - case "conversations.getMessageById": { - const result = await client.conversations.getMessageById(data.id); - postMessage({ id, action, result }); - break; - } - case "conversations.getDmByInboxId": { - const conversation = client.conversations.getDmByInboxId(data.inboxId); - const result = conversation - ? await toSafeConversation(conversation) - : undefined; - postMessage({ id, action, result }); - break; - } - case "conversations.hmacKeys": { - const hmacKeys = client.conversations.hmacKeys(); - postMessage({ id, action, result: hmacKeys }); - break; - } - /** - * Group actions - */ - case "conversation.sync": { - const group = getGroup(data.id); - await group.sync(); - const result = await toSafeConversation(group); - postMessage({ id, action, result }); - break; - } - case "conversation.lastMessage": { - const group = getGroup(data.id); - // lastMessage() now returns enriched DecodedMessage directly - const result = await group.lastMessage(); - postMessage({ id, action, result }); - break; - } - case "conversation.isActive": { - const group = getGroup(data.id); - const result = group.isActive; - postMessage({ id, action, result }); - break; - } - case "conversation.consentState": { - const group = getGroup(data.id); - const result = group.consentState(); - postMessage({ id, action, result }); - break; - } - case "conversation.updateConsentState": { - const group = getGroup(data.id); - group.updateConsentState(data.state); - postMessage({ id, action, result: undefined }); - break; - } - case "group.updateName": { - const group = getGroup(data.id); - await group.updateName(data.name); - postMessage({ id, action, result: undefined }); - break; - } - case "group.updateDescription": { - const group = getGroup(data.id); - await group.updateDescription(data.description); - postMessage({ id, action, result: undefined }); - break; - } - case "group.updateImageUrl": { - const group = getGroup(data.id); - await group.updateImageUrl(data.imageUrl); - postMessage({ id, action, result: undefined }); - break; - } - case "group.updateAppData": { - const group = getGroup(data.id); - await group.updateAppData(data.appData); - postMessage({ id, action, result: undefined }); - break; - } - case "conversation.send": { - const group = getGroup(data.id); - const result = await group.send(data.content, data.options); - postMessage({ id, action, result }); - break; - } - case "conversation.publishMessages": { - const group = getGroup(data.id); - await group.publishMessages(); - postMessage({ id, action, result: undefined }); - break; - } - case "conversation.processStreamedMessage": { - const group = getGroup(data.id); - const result = await group.processStreamedMessage(data.envelopeBytes); - postMessage({ id, action, result }); - break; - } - case "conversation.messages": { - const group = getGroup(data.id); - const messages = await group.messages(data.options); - // messages() now returns enriched DecodedMessage[] directly - postMessage({ id, action, result: messages }); - break; - } - case "conversation.countMessages": { - const group = getGroup(data.id); - const result = await group.countMessages(data.options); - postMessage({ id, action, result }); - break; - } - case "conversation.members": { - const group = getGroup(data.id); - const result = await group.members(); - postMessage({ id, action, result }); - break; - } - case "group.listAdmins": { - const group = getGroup(data.id); - const result = group.listAdmins(); - postMessage({ id, action, result }); - break; - } - case "group.listSuperAdmins": { - const group = getGroup(data.id); - const result = group.listSuperAdmins(); - postMessage({ id, action, result }); - break; - } - case "group.addAdmin": { - const group = getGroup(data.id); - await group.addAdmin(data.inboxId); - postMessage({ id, action, result: undefined }); - break; - } - case "group.removeAdmin": { - const group = getGroup(data.id); - await group.removeAdmin(data.inboxId); - postMessage({ id, action, result: undefined }); - break; - } - case "group.addSuperAdmin": { - const group = getGroup(data.id); - await group.addSuperAdmin(data.inboxId); - postMessage({ id, action, result: undefined }); - break; - } - case "group.removeSuperAdmin": { - const group = getGroup(data.id); - await group.removeSuperAdmin(data.inboxId); - postMessage({ id, action, result: undefined }); - break; - } - case "group.addMembersByIdentifiers": { - const group = getGroup(data.id); - await group.addMembersByIdentifiers(data.identifiers); - postMessage({ id, action, result: undefined }); - break; - } - case "group.removeMembersByIdentifiers": { - const group = getGroup(data.id); - await group.removeMembersByIdentifiers(data.identifiers); - postMessage({ id, action, result: undefined }); - break; - } - case "group.addMembers": { - const group = getGroup(data.id); - await group.addMembers(data.inboxIds); - postMessage({ id, action, result: undefined }); - break; - } - case "group.removeMembers": { - const group = getGroup(data.id); - await group.removeMembers(data.inboxIds); - postMessage({ id, action, result: undefined }); - break; - } - case "group.isAdmin": { - const group = getGroup(data.id); - const result = group.isAdmin(data.inboxId); - postMessage({ id, action, result }); - break; - } - case "group.isSuperAdmin": { - const group = getGroup(data.id); - const result = group.isSuperAdmin(data.inboxId); - postMessage({ id, action, result }); - break; - } - case "dm.peerInboxId": { - const group = getGroup(data.id); - const result = group.dmPeerInboxId(); - postMessage({ id, action, result }); - break; - } - case "group.updatePermission": { - const group = getGroup(data.id); - await group.updatePermission( - data.permissionType, - data.policy, - data.metadataField, - ); - postMessage({ id, action, result: undefined }); - break; - } - case "group.permissions": { - const group = getGroup(data.id); - const safeConversation = await toSafeConversation(group); - const result = safeConversation.permissions; - postMessage({ id, action, result }); - break; - } - case "group.requestRemoval": { - const group = getGroup(data.id); - await group.requestRemoval(); - postMessage({ id, action, result: undefined }); - break; - } - case "group.isPendingRemoval": { - const group = getGroup(data.id); - const result = group.isPendingRemoval(); - postMessage({ id, action, result }); - break; - } - case "conversation.messageDisappearingSettings": { - const group = getGroup(data.id); - const result = group.messageDisappearingSettings(); - postMessage({ id, action, result }); - break; - } - case "conversation.updateMessageDisappearingSettings": { - const group = getGroup(data.id); - await group.updateMessageDisappearingSettings(data.fromNs, data.inNs); - postMessage({ id, action, result: undefined }); - break; - } - case "conversation.removeMessageDisappearingSettings": { - const group = getGroup(data.id); - await group.removeMessageDisappearingSettings(); - postMessage({ id, action, result: undefined }); - break; - } - case "conversation.isMessageDisappearingEnabled": { - const group = getGroup(data.id); - const result = group.isMessageDisappearingEnabled(); - postMessage({ id, action, result }); - break; - } - case "conversation.stream": { - const group = getGroup(data.groupId); - const streamCallback = ( - error: Error | null, - value: Message | undefined, - ) => { - if (error) { - postStreamMessageError({ - action: "stream.message", - streamId: data.streamId, - error, - }); - } else if (value) { - void client.conversations - .getMessageById(value.id) - .then((enrichedMessage) => { - // guard against any edge cases where the message is not found - if (enrichedMessage) { - postStreamMessage({ - action: "stream.message", - streamId: data.streamId, - result: enrichedMessage, - }); - } - }); - } - }; - const streamCloser = group.stream(streamCallback, () => { - streamClosers.delete(data.streamId); - postStreamMessage({ - action: "stream.fail", - streamId: data.streamId, - result: undefined, - }); - }); - streamClosers.set(data.streamId, streamCloser); - postMessage({ id, action, result: undefined }); - break; - } - case "conversation.pausedForVersion": { - const group = getGroup(data.id); - const result = group.pausedForVersion(); - postMessage({ id, action, result }); - break; - } - case "conversation.hmacKeys": { - const group = getGroup(data.id); - const result = group.hmacKeys(); - postMessage({ id, action, result }); - break; - } - case "dm.duplicateDms": { - const group = getGroup(data.id); - const dms = await group.duplicateDms(); - const result = await Promise.all( - dms.map((dm) => toSafeConversation(dm)), - ); - postMessage({ id, action, result }); - break; - } - case "conversation.debugInfo": { - const group = getGroup(data.id); - const result = await group.debugInfo(); - postMessage({ id, action, result }); - break; - } - case "conversation.lastReadTimes": { - const group = getGroup(data.id); - const result = await group.lastReadTimes(); - postMessage({ id, action, result }); - break; - } - case "conversation.sendText": { - const group = getGroup(data.id); - const result = await group.sendText(data.text, data.isOptimistic); - postMessage({ id, action, result }); - break; - } - case "conversation.sendMarkdown": { - const group = getGroup(data.id); - const result = await group.sendMarkdown( - data.markdown, - data.isOptimistic, - ); - postMessage({ id, action, result }); - break; - } - case "conversation.sendReaction": { - const group = getGroup(data.id); - const result = await group.sendReaction( - data.reaction, - data.isOptimistic, - ); - postMessage({ id, action, result }); - break; - } - case "conversation.sendReadReceipt": { - const group = getGroup(data.id); - const result = await group.sendReadReceipt(data.isOptimistic); - postMessage({ id, action, result }); - break; - } - case "conversation.sendReply": { - const group = getGroup(data.id); - const result = await group.sendReply(data.reply, data.isOptimistic); - postMessage({ id, action, result }); - break; - } - case "conversation.sendTransactionReference": { - const group = getGroup(data.id); - const result = await group.sendTransactionReference( - data.transactionReference, - data.isOptimistic, - ); - postMessage({ id, action, result }); - break; - } - case "conversation.sendWalletSendCalls": { - const group = getGroup(data.id); - const result = await group.sendWalletSendCalls( - data.walletSendCalls, - data.isOptimistic, - ); - postMessage({ id, action, result }); - break; - } - case "conversation.sendActions": { - const group = getGroup(data.id); - const result = await group.sendActions(data.actions, data.isOptimistic); - postMessage({ id, action, result }); - break; - } - case "conversation.sendIntent": { - const group = getGroup(data.id); - const result = await group.sendIntent(data.intent, data.isOptimistic); - postMessage({ id, action, result }); - break; - } - case "conversation.sendAttachment": { - const group = getGroup(data.id); - const result = await group.sendAttachment( - data.attachment, - data.isOptimistic, - ); - postMessage({ id, action, result }); - break; - } - case "conversation.sendMultiRemoteAttachment": { - const group = getGroup(data.id); - const result = await group.sendMultiRemoteAttachment( - data.multiRemoteAttachment, - data.isOptimistic, - ); - postMessage({ id, action, result }); - break; - } - case "conversation.sendRemoteAttachment": { - const group = getGroup(data.id); - const result = await group.sendRemoteAttachment( - data.remoteAttachment, - data.isOptimistic, - ); - postMessage({ id, action, result }); - break; - } - } - } catch (e) { - postMessageError({ - id, - action, - error: e as Error, - }); - } -}; diff --git a/sdks/browser-sdk/src/workers/opfs.ts b/sdks/browser-sdk/src/workers/opfs.ts deleted file mode 100644 index 69656a801..000000000 --- a/sdks/browser-sdk/src/workers/opfs.ts +++ /dev/null @@ -1,127 +0,0 @@ -import init, { - opfsClearAll, - opfsDeleteFile, - opfsExportDb, - opfsFileCount, - opfsFileExists, - opfsImportDb, - opfsInit, - opfsListFiles, - opfsPoolCapacity, -} from "@xmtp/wasm-bindings"; -import type { - ActionErrorData, - ActionName, - ActionWithoutResult, - ExtractActionWithoutData, -} from "@/types/actions"; -import type { OpfsAction } from "@/types/actions/opfs"; -import { - OpfsInitializationError, - OpfsNotInitializedError, -} from "@/utils/errors"; - -let initialized = false; -let enableLogging = false; - -/** - * Type-safe postMessage - */ -const postMessage = >( - data: ExtractActionWithoutData, -) => { - self.postMessage(data); -}; - -/** - * Type-safe postMessage for errors - */ -const postMessageError = (data: ActionErrorData) => { - self.postMessage(data); -}; - -self.onmessage = async ( - event: MessageEvent>, -) => { - const { action, id, data } = event.data; - - // initialize WASM module - await init(); - - try { - // init is a special action that initializes the client - if (action === "opfs.init" && !initialized) { - try { - await opfsInit(); - } catch { - throw new OpfsInitializationError(); - } - initialized = true; - enableLogging = data.enableLogging ?? false; - postMessage({ id, action, result: undefined }); - } - - if (enableLogging) { - console.log("[worker] worker received event data", event.data); - } - - // nothing else to do - if (action === "opfs.init") { - return; - } - - // OPFS must be initialized for all other actions - if (!initialized) { - throw new OpfsNotInitializedError(); - } - - switch (action) { - case "opfs.listFiles": { - const files = await opfsListFiles(); - postMessage({ id, action, result: files }); - return; - } - case "opfs.fileCount": { - const fileCount = await opfsFileCount(); - postMessage({ id, action, result: fileCount }); - return; - } - case "opfs.poolCapacity": { - const poolCapacity = await opfsPoolCapacity(); - postMessage({ id, action, result: poolCapacity }); - return; - } - case "opfs.fileExists": { - const fileExists = await opfsFileExists(data.path); - postMessage({ id, action, result: fileExists }); - return; - } - case "opfs.deleteFile": { - const deleted = await opfsDeleteFile(data.path); - postMessage({ id, action, result: deleted }); - return; - } - case "opfs.exportDb": { - const db = await opfsExportDb(data.path); - postMessage({ id, action, result: db }); - return; - } - case "opfs.importDb": { - await opfsImportDb(data.path, data.data); - postMessage({ id, action, result: undefined }); - return; - } - case "opfs.clearAll": { - await opfsClearAll(); - postMessage({ id, action, result: undefined }); - return; - } - } - } catch (e) { - postMessageError({ - id, - action, - error: e as Error, - }); - } -}; diff --git a/sdks/browser-sdk/test/AsyncStream.test.ts b/sdks/browser-sdk/test/AsyncStream.test.ts deleted file mode 100644 index ed9cd0f0d..000000000 --- a/sdks/browser-sdk/test/AsyncStream.test.ts +++ /dev/null @@ -1,457 +0,0 @@ -import { describe, expect, it, vi } from "vitest"; -import { AsyncStream, createAsyncStreamProxy } from "@/AsyncStream"; - -const testError = new Error("test"); - -describe("AsyncStream", () => { - it("should return values from push() in sequence", async () => { - const stream = new AsyncStream(); - const onReturnSpy = vi.fn(); - const onDoneSpy = vi.fn(); - - stream.onReturn = onReturnSpy; - stream.onDone = onDoneSpy; - - stream.push(1); - stream.push(2); - stream.push(3); - stream.push(4); - stream.push(5); - - const values: (number | undefined)[] = []; - let iterationCount = 0; - - for await (const value of stream) { - values.push(value); - iterationCount++; - - if (iterationCount === 3) { - break; - } - } - - expect(values).toEqual([1, 2, 3]); - expect(onReturnSpy).toHaveBeenCalledOnce(); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - }); - - it("should handle values added during iteration", async () => { - const stream = new AsyncStream(); - const onReturnSpy = vi.fn(); - const onDoneSpy = vi.fn(); - - stream.onReturn = onReturnSpy; - stream.onDone = onDoneSpy; - - stream.push(1); - - const values: (number | undefined)[] = []; - let iterationCount = 0; - - for await (const value of stream) { - values.push(value); - iterationCount++; - - if (iterationCount === 1) { - stream.push(2); - stream.push(3); - } - - if (iterationCount === 3) { - break; - } - } - - expect(values).toEqual([1, 2, 3]); - expect(onReturnSpy).toHaveBeenCalledOnce(); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - }); - - it("should catch an error thrown in the for..await loop and cleanup properly", async () => { - const stream = new AsyncStream(); - const onReturnSpy = vi.fn(); - const onDoneSpy = vi.fn(); - - stream.onReturn = onReturnSpy; - stream.onDone = onDoneSpy; - stream.push(1); - stream.push(2); - - try { - for await (const value of stream) { - expect(value).toBe(1); - throw testError; - } - } catch (error) { - expect(error).toBe(testError); - } - - expect(onReturnSpy).toHaveBeenCalledOnce(); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - }); - - it("should end for await..of loop when stream is ended and call onDone", async () => { - const stream = new AsyncStream(); - const onDoneSpy = vi.fn(); - const onReturnSpy = vi.fn(); - - stream.onDone = onDoneSpy; - stream.onReturn = onReturnSpy; - - stream.push(1); - stream.push(2); - - setTimeout(() => { - void stream.end(); - }, 100); - - const values: (number | undefined)[] = []; - - for await (const value of stream) { - values.push(value); - } - - expect(values).toEqual([1, 2]); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(onReturnSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - - stream.push(3); - - for await (const _value of stream) { - // this block should never be reached - expect(false).toBe(true); - } - }); - - it("should handle multiple concurrent next() calls", async () => { - const stream = new AsyncStream(); - - const nextPromise1 = stream.next(); - const nextPromise2 = stream.next(); - const nextPromise3 = stream.next(); - - stream.push(1); - stream.push(2); - stream.push(3); - - const [result1, result2, result3] = await Promise.all([ - nextPromise1, - nextPromise2, - nextPromise3, - ]); - - expect(result1).toEqual({ done: false, value: 1 }); - expect(result2).toEqual({ done: false, value: 2 }); - expect(result3).toEqual({ done: false, value: 3 }); - expect(stream.isDone).toBe(false); - }); - - it("should handle return() with pending promises", async () => { - const stream = new AsyncStream(); - const onReturnSpy = vi.fn(); - - stream.onReturn = onReturnSpy; - - const nextPromise1 = stream.next(); - const nextPromise2 = stream.next(); - - const returnResult = await stream.return(); - - expect(returnResult).toEqual({ done: true, value: undefined }); - expect(onReturnSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - - const result1 = await nextPromise1; - const result2 = await nextPromise2; - - expect(result1).toEqual({ done: true, value: undefined }); - expect(result2).toEqual({ done: true, value: undefined }); - }); - - it("should not process callbacks after being done", async () => { - const stream = new AsyncStream(); - const onDoneSpy = vi.fn(); - const onReturnSpy = vi.fn(); - - stream.onDone = onDoneSpy; - stream.onReturn = onReturnSpy; - - // End the stream - await stream.end(); - - // These callbacks should be ignored - stream.push(1); - - for await (const _value of stream) { - // this block should never be reached - expect(false).toBe(true); - } - - expect(stream.isDone).toBe(true); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(onReturnSpy).toHaveBeenCalledOnce(); - - const result = await stream.next(); - expect(result).toEqual({ done: true, value: undefined }); - }); - - it("should handle queue properly when values arrive faster than consumption", async () => { - const stream = new AsyncStream(); - - for (let i = 1; i <= 5; i++) { - stream.push(i); - } - - const values: (number | undefined)[] = []; - - for (let i = 0; i < 3; i++) { - const result = await stream.next(); - expect(result.done).toBe(false); - values.push(result.value); - } - - expect(values).toEqual([1, 2, 3]); - expect(stream.isDone).toBe(false); - - await stream.end(); - - const finalResult = await stream.next(); - expect(finalResult).toEqual({ done: true, value: undefined }); - }); -}); - -describe("createAsyncStreamProxy", () => { - it("should only expose allowed methods and properties", () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - expect(typeof proxy.next).toBe("function"); - expect(typeof proxy.end).toBe("function"); - expect(typeof proxy.return).toBe("function"); - expect(typeof proxy[Symbol.asyncIterator]).toBe("function"); - - const ownProperties = Object.getOwnPropertyNames(proxy); - expect(ownProperties).toHaveLength(4); - expect(ownProperties).toContain("end"); - expect(ownProperties).toContain("return"); - expect(ownProperties).toContain("isDone"); - expect(ownProperties).toContain("next"); - }); - - it("should prevent setting properties", () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - // this will fail silently - proxy.isDone = true; - - expect(proxy.isDone).toBe(false); - }); - - it("should correctly forward next() calls to the underlying stream", async () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - stream.push(1); - stream.push(2); - - const result1 = await proxy.next(); - const result2 = await proxy.next(); - - expect(result1).toEqual({ done: false, value: 1 }); - expect(result2).toEqual({ done: false, value: 2 }); - }); - - it("should correctly forward end() calls to the underlying stream", async () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - const onDoneSpy = vi.fn(); - - stream.onDone = onDoneSpy; - - const result = await proxy.end(); - - expect(result).toEqual({ done: true, value: undefined }); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - expect(proxy.isDone).toBe(true); - }); - - it("should maintain async iterator functionality", async () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - stream.push(1); - stream.push(2); - stream.push(3); - - const values: number[] = []; - let iterationCount = 0; - - for await (const value of proxy) { - values.push(value); - iterationCount++; - - if (iterationCount === 3) { - break; - } - } - - expect(values).toEqual([1, 2, 3]); - expect(stream.isDone).toBe(true); - expect(proxy.isDone).toBe(true); - }); - - it("should end for await..of loop when proxy is ended and call onDone", async () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - const onDoneSpy = vi.fn(); - - stream.onDone = onDoneSpy; - - stream.push(1); - stream.push(2); - - setTimeout(() => { - void proxy.end(); - }, 100); - - const values: number[] = []; - - for await (const value of proxy) { - values.push(value); - } - - expect(values).toEqual([1, 2]); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - expect(proxy.isDone).toBe(true); - - stream.push(3); - - for await (const _value of proxy) { - // this block should never be reached - expect(false).toBe(true); - } - }); - - it("should correctly implement has() trap", () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - expect("isDone" in proxy).toBe(true); - expect("next" in proxy).toBe(true); - expect("end" in proxy).toBe(true); - expect("return" in proxy).toBe(true); - expect(Symbol.asyncIterator in proxy).toBe(true); - - expect("push" in proxy).toBe(false); - expect("error" in proxy).toBe(false); - expect("onDone" in proxy).toBe(false); - expect("onError" in proxy).toBe(false); - expect("onReturn" in proxy).toBe(false); - expect("nonExistentProperty" in proxy).toBe(false); - }); - - it("should correctly implement ownKeys() trap", () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - const keys = Object.getOwnPropertyNames(proxy); - const symbols = Object.getOwnPropertySymbols(proxy); - - expect(keys).toHaveLength(4); - expect(keys).toContain("next"); - expect(keys).toContain("end"); - expect(keys).toContain("return"); - expect(keys).toContain("isDone"); - expect(symbols).toHaveLength(1); - expect(symbols).toContain(Symbol.asyncIterator); - }); - - it("should correctly implement getOwnPropertyDescriptor() trap", () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - const nextDescriptor = Object.getOwnPropertyDescriptor(proxy, "next"); - expect(nextDescriptor).toBeDefined(); - expect(nextDescriptor?.enumerable).toBe(true); - expect(nextDescriptor?.configurable).toBe(true); - expect(typeof nextDescriptor?.value).toBe("function"); - - const endDescriptor = Object.getOwnPropertyDescriptor(proxy, "end"); - expect(endDescriptor).toBeDefined(); - expect(endDescriptor?.enumerable).toBe(true); - expect(endDescriptor?.configurable).toBe(true); - expect(typeof endDescriptor?.value).toBe("function"); - - const returnDescriptor = Object.getOwnPropertyDescriptor(proxy, "return"); - expect(returnDescriptor).toBeDefined(); - expect(returnDescriptor?.enumerable).toBe(true); - expect(returnDescriptor?.configurable).toBe(true); - expect(typeof returnDescriptor?.value).toBe("function"); - - const asyncIteratorDescriptor = Object.getOwnPropertyDescriptor( - proxy, - Symbol.asyncIterator, - ); - expect(asyncIteratorDescriptor).toBeDefined(); - expect(asyncIteratorDescriptor?.enumerable).toBe(true); - expect(asyncIteratorDescriptor?.configurable).toBe(true); - expect(typeof asyncIteratorDescriptor?.value).toBe("function"); - - // Non-exposed properties should return undefined - const callbackDescriptor = Object.getOwnPropertyDescriptor( - proxy, - "callback", - ); - expect(callbackDescriptor).toBeUndefined(); - - const isDoneDescriptor = Object.getOwnPropertyDescriptor(proxy, "isDone"); - expect(isDoneDescriptor).toBeDefined(); - expect(isDoneDescriptor?.enumerable).toBe(true); - expect(isDoneDescriptor?.configurable).toBe(true); - expect(typeof isDoneDescriptor?.value).toBe("boolean"); - }); - - it("should handle concurrent operations through proxy", async () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - const nextPromise1 = proxy.next(); - const nextPromise2 = proxy.next(); - const nextPromise3 = proxy.next(); - - stream.push(1); - stream.push(2); - stream.push(3); - - const [result1, result2, result3] = await Promise.all([ - nextPromise1, - nextPromise2, - nextPromise3, - ]); - - expect(result1).toEqual({ done: false, value: 1 }); - expect(result2).toEqual({ done: false, value: 2 }); - expect(result3).toEqual({ done: false, value: 3 }); - }); - - it("should work correctly when stream is already done", async () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - stream.push(1); - await proxy.end(); - - const result1 = await proxy.next(); - const result2 = await proxy.next(); - - expect(result1).toEqual({ done: true, value: undefined }); - expect(result2).toEqual({ done: true, value: undefined }); - }); -}); diff --git a/sdks/browser-sdk/test/Client.test.ts b/sdks/browser-sdk/test/Client.test.ts deleted file mode 100644 index afce09c29..000000000 --- a/sdks/browser-sdk/test/Client.test.ts +++ /dev/null @@ -1,473 +0,0 @@ -import { IdentifierKind } from "@xmtp/wasm-bindings"; -import { describe, expect, it } from "vitest"; -import { Client } from "@/Client"; -import { SignerUnavailableError } from "@/utils/errors"; -import { uuid } from "@/utils/uuid"; -import { - buildClient, - createClient, - createRegisteredClient, - createSigner, -} from "@test/helpers"; - -describe("Client", () => { - it("should create a client", async () => { - const { signer, address } = createSigner(); - const client = await createClient(signer); - expect(client.accountIdentifier).toEqual({ - identifier: address, - identifierKind: IdentifierKind.Ethereum, - }); - expect(await client.isRegistered()).toBe(false); - expect(client.inboxId).toBeDefined(); - expect(client.installationId).toBeDefined(); - }); - - it("should create a client without a signer", async () => { - const { identifier } = createSigner(); - const client = await buildClient(identifier); - expect(client).toBeDefined(); - expect(client.accountIdentifier).toEqual(identifier); - expect(await client.isRegistered()).toBe(false); - expect(client.inboxId).toBeDefined(); - expect(client.installationId).toBeDefined(); - - const { signer: signer2 } = createSigner(); - - await expect(() => client.register()).rejects.toThrow( - new SignerUnavailableError(), - ); - - await expect(async () => - client.removeAccount(await signer2.getIdentifier()), - ).rejects.toThrow(new SignerUnavailableError()); - - await expect(() => client.revokeInstallations([])).rejects.toThrow( - new SignerUnavailableError(), - ); - - await expect(() => client.revokeAllOtherInstallations()).rejects.toThrow( - new SignerUnavailableError(), - ); - - await expect(async () => - client.changeRecoveryIdentifier(await signer2.getIdentifier()), - ).rejects.toThrow(new SignerUnavailableError()); - }); - - it("should return a version", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - expect(client.appVersion).toBe(""); - expect(client.libxmtpVersion).toBeTypeOf("string"); - - const client2 = await createRegisteredClient(signer, { - appVersion: "1.0.0", - }); - expect(client2.appVersion).toBe("1.0.0"); - }); - - it("should register an identity", async () => { - const { signer } = createSigner(); - await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer); - expect(await client2.isRegistered()).toBe(true); - }); - - it("should be able to message registered identity", async () => { - const { signer, address } = createSigner(); - const client = await createRegisteredClient(signer); - const canMessage = await client.canMessage([await signer.getIdentifier()]); - expect(Object.fromEntries(canMessage)).toEqual({ - [address]: true, - }); - }); - - it("should be able to check if can message without client instance", async () => { - const { signer, address } = createSigner(); - await createRegisteredClient(signer); - const canMessage = await Client.canMessage( - [await signer.getIdentifier()], - "local", - ); - expect(Object.fromEntries(canMessage)).toEqual({ - [address]: true, - }); - }); - - it("should get an inbox ID from an address", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const inboxId = await client.fetchInboxIdByIdentifier( - await signer.getIdentifier(), - ); - expect(inboxId).toBe(client.inboxId); - }); - - it("should return the correct inbox state", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const inboxState = await client.preferences.inboxState(); - expect(inboxState.inboxId).toBe(client.inboxId); - expect(inboxState.installations.map((install) => install.id)).toEqual([ - client.installationId, - ]); - expect(inboxState.accountIdentifiers).toEqual([ - await signer.getIdentifier(), - ]); - expect(inboxState.recoveryIdentifier).toEqual(await signer.getIdentifier()); - - const { signer: signer2 } = createSigner(); - const client2 = await createClient(signer2); - const inboxStates = await client2.preferences.fetchInboxStates([ - client.inboxId!, - ]); - const inboxState2 = inboxStates[0]; - expect(inboxState2.inboxId).toBe(client.inboxId); - expect(inboxState.installations.length).toBe(1); - expect(inboxState.installations[0].id).toBe(client.installationId); - expect(inboxState.installations[0].bytes).toEqual( - client.installationIdBytes, - ); - expect(inboxState2.accountIdentifiers).toEqual([ - await signer.getIdentifier(), - ]); - expect(inboxState2.recoveryIdentifier).toEqual( - await signer.getIdentifier(), - ); - }); - - it("should add a wallet association to the client", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - - const { signer: signer2 } = createSigner(); - - await client.unsafe_addAccount(signer2, true); - const inboxState = await client.preferences.inboxState(); - expect(inboxState.accountIdentifiers.length).toEqual(2); - expect(inboxState.accountIdentifiers).toContainEqual( - await signer.getIdentifier(), - ); - expect(inboxState.accountIdentifiers).toContainEqual( - await signer2.getIdentifier(), - ); - }); - - it("should revoke a wallet association from the client", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - - const { signer: signer2 } = createSigner(); - - await client.unsafe_addAccount(signer2, true); - await client.removeAccount(await signer2.getIdentifier()); - - const inboxState = await client.preferences.inboxState(); - expect(inboxState.accountIdentifiers).toEqual([ - await signer.getIdentifier(), - ]); - }); - - it("should revoke all other installations", async () => { - const { signer } = createSigner(); - - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client3 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - const inboxState = await client3.preferences.fetchInboxState(); - expect(inboxState.installations.length).toBe(3); - - const installationIds = inboxState.installations.map((i) => i.id); - expect(installationIds).toContain(client.installationId); - expect(installationIds).toContain(client2.installationId); - expect(installationIds).toContain(client3.installationId); - - await client3.revokeAllOtherInstallations(); - - const inboxState2 = await client3.preferences.fetchInboxState(); - - expect(inboxState2.installations.length).toBe(1); - expect(inboxState2.installations[0].id).toBe(client3.installationId); - }); - - it("should revoke specific installations", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client3 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - const inboxState = await client3.preferences.fetchInboxState(); - expect(inboxState.installations.length).toBe(3); - - const installationIds = inboxState.installations.map((i) => i.id); - expect(installationIds).toContain(client.installationId); - expect(installationIds).toContain(client2.installationId); - expect(installationIds).toContain(client3.installationId); - - await client3.revokeInstallations([client.installationIdBytes!]); - - const inboxState2 = await client3.preferences.fetchInboxState(); - - expect(inboxState2.installations.length).toBe(2); - - const installationIds2 = inboxState2.installations.map((i) => i.id); - expect(installationIds2).toContain(client2.installationId); - expect(installationIds2).toContain(client3.installationId); - expect(installationIds2).not.toContain(client.installationId); - }); - - it("should throw when trying to create more than 10 installations", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client3 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client4 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client5 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client6 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client7 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client8 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client9 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client10 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - const inboxState = await client3.preferences.fetchInboxState(); - expect(inboxState.installations.length).toBe(10); - - const installationIds = inboxState.installations.map((i) => i.id); - expect(installationIds).toContain(client.installationId); - expect(installationIds).toContain(client2.installationId); - expect(installationIds).toContain(client3.installationId); - expect(installationIds).toContain(client4.installationId); - expect(installationIds).toContain(client5.installationId); - expect(installationIds).toContain(client6.installationId); - expect(installationIds).toContain(client7.installationId); - expect(installationIds).toContain(client8.installationId); - expect(installationIds).toContain(client9.installationId); - expect(installationIds).toContain(client10.installationId); - - await expect( - createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }), - ).rejects.toThrow(); - - await client3.revokeAllOtherInstallations(); - - const inboxState2 = await client3.preferences.fetchInboxState(); - - expect(inboxState2.installations.length).toBe(1); - expect(inboxState2.installations[0].id).toBe(client3.installationId); - - const client11 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - const inboxState3 = await client11.preferences.fetchInboxState(); - expect(inboxState3.installations.length).toBe(2); - const installationIds3 = inboxState3.installations.map((i) => i.id); - expect(installationIds3).toContain(client3.installationId); - expect(installationIds3).toContain(client11.installationId); - }); - - it("should change the recovery identifier", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - - const { signer: signer2 } = createSigner(); - await createRegisteredClient(signer2); - - await client.changeRecoveryIdentifier(await signer2.getIdentifier()); - - const inboxState = await client.preferences.inboxState(); - expect(inboxState.recoveryIdentifier).toEqual( - await signer2.getIdentifier(), - ); - }); - - it("should not fail when revoking all other installations with only one installation", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - - const inboxState = await client.preferences.fetchInboxState(); - expect(inboxState.installations.length).toBe(1); - expect(inboxState.installations[0].id).toBe(client.installationId); - - await expect(client.revokeAllOtherInstallations()).resolves.not.toThrow(); - }); - - it("should statically revoke specific installations", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client3 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - const inboxState = await client3.preferences.fetchInboxState(); - expect(inboxState.installations.length).toBe(3); - - const installationIds = inboxState.installations.map((i) => i.id); - expect(installationIds).toContain(client.installationId); - expect(installationIds).toContain(client2.installationId); - expect(installationIds).toContain(client3.installationId); - - await Client.revokeInstallations( - signer, - client3.inboxId!, - [client.installationIdBytes!], - "local", - ); - - const inboxState2 = await client3.preferences.fetchInboxState(); - - expect(inboxState2.installations.length).toBe(2); - - const installationIds2 = inboxState2.installations.map((i) => i.id); - expect(installationIds2).toContain(client2.installationId); - expect(installationIds2).toContain(client3.installationId); - expect(installationIds2).not.toContain(client.installationId); - }); - - it("should verify signatures", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const signatureText = "gm1"; - const signature = await client.signWithInstallationKey(signatureText); - const verified = await client.verifySignedWithInstallationKey( - signatureText, - signature, - ); - expect(verified).toBe(true); - const verified2 = await client.verifySignedWithPublicKey( - signatureText, - signature, - client.installationIdBytes!, - ); - expect(verified2).toBe(true); - }); - - it("should transfer an identifier to a new inbox", async () => { - // original signer - const { signer, identifier } = createSigner(); - // temporary signer - const { signer: signer2, identifier: identifier2 } = createSigner(); - const client = await createRegisteredClient(signer); - // add temporary account - await client.unsafe_addAccount(signer2, true); - // remove existing account - await client.removeAccount(identifier); - // change recovery identifier to temporary account - await client.changeRecoveryIdentifier(identifier2); - - const inboxState = await client.preferences.fetchInboxState(); - // check that the temporary account is the only account on the inbox - expect(inboxState.accountIdentifiers).toEqual([identifier2]); - expect(inboxState.recoveryIdentifier).toEqual(identifier2); - - // temporary signer - const { signer: signer3, identifier: identifier3 } = createSigner(); - // create client to transfer original account to - const transferClient = await createRegisteredClient(signer3); - // add original account to transfer client - await transferClient.unsafe_addAccount(signer, true); - // remove temporary transfer identifier - await transferClient.removeAccount(identifier3); - // change recovery identifier to original account - await transferClient.changeRecoveryIdentifier(identifier); - - const inboxState2 = await transferClient.preferences.fetchInboxState(); - // check that the original account is the only account on the inbox - expect(inboxState2.accountIdentifiers).toEqual([identifier]); - expect(inboxState2.recoveryIdentifier).toEqual(identifier); - - // check that the inbox IDs are different - expect(client.inboxId).not.toBe(transferClient.inboxId); - - // ensure that a client can be created with the original signer - const client2 = await createRegisteredClient(signer, { - // must use a different db path to avoid errors - dbPath: `./test-${uuid()}.db3`, - }); - expect(client2.inboxId).toBe(transferClient.inboxId); - }); - - it("should get key package statuses for installation ids", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - - const statuses = await client.fetchKeyPackageStatuses([ - client.installationId!, - ]); - expect(statuses.size).toBe(1); - - const status = statuses.get(client.installationId!); - expect(status).toBeDefined(); - expect(status?.lifetime).toBeDefined(); - expect(status?.validationError).toBeUndefined(); - }); - - it("should get inbox state from inbox ids without a client", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const inboxState = await Client.fetchInboxStates( - [client.inboxId!], - "local", - ); - expect(inboxState.length).toBe(1); - expect(inboxState[0].inboxId).toBe(client.inboxId); - expect(inboxState[0].accountIdentifiers).toEqual([ - await signer.getIdentifier(), - ]); - }); - - it("should get latest inbox updates count from inbox IDs without a client", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const inboxUpdatesCounts = await Client.fetchLatestInboxUpdatesCount( - [client.inboxId!], - "local", - ); - expect(inboxUpdatesCounts.get(client.inboxId!)).toBeTypeOf("number"); - }); - - it("should get own inbox updates count from a client", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const inboxUpdatesCounts = await client.fetchLatestInboxUpdatesCount([ - client.inboxId!, - ]); - const ownInboxUpdatesCount = await client.fetchOwnInboxUpdatesCount(); - expect(inboxUpdatesCounts.get(client.inboxId!)).toBe(ownInboxUpdatesCount); - expect(inboxUpdatesCounts.get(client.inboxId!)).toBeTypeOf("number"); - expect(ownInboxUpdatesCount).toBeTypeOf("number"); - }); -}); diff --git a/sdks/browser-sdk/test/Conversations.test.ts b/sdks/browser-sdk/test/Conversations.test.ts deleted file mode 100644 index c62b32d25..000000000 --- a/sdks/browser-sdk/test/Conversations.test.ts +++ /dev/null @@ -1,478 +0,0 @@ -import { - ConversationType, - ListConversationsOrderBy, -} from "@xmtp/wasm-bindings"; -import { describe, expect, it } from "vitest"; -import { uuid } from "@/utils/uuid"; -import { createRegisteredClient, createSigner, sleep } from "@test/helpers"; - -describe("Conversations", () => { - it("should have a topic", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - expect(client.conversations.topic).toBe( - `/xmtp/mls/1/w-${client.installationId}/proto`, - ); - }); - - it("should not have initial conversations", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - expect((await client.conversations.list()).length).toBe(0); - expect((await client.conversations.listDms()).length).toBe(0); - expect((await client.conversations.listGroups()).length).toBe(0); - }); - - it("should get a group or DM by ID", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const group = await client1.conversations.createGroup([client2.inboxId!]); - expect(group).toBeDefined(); - expect(group.id).toBeDefined(); - const foundGroup = await client1.conversations.getConversationById( - group.id, - ); - expect(foundGroup).toBeDefined(); - expect(foundGroup!.id).toBe(group.id); - - const dm = await client1.conversations.createDm(client2.inboxId!); - expect(dm).toBeDefined(); - expect(dm.id).toBeDefined(); - const foundDm = await client1.conversations.getConversationById(dm.id); - expect(foundDm).toBeDefined(); - expect(foundDm!.id).toBe(dm.id); - }); - - it("should get a DM by inbox ID", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId!); - const foundDm = await client1.conversations.getDmByInboxId( - client2.inboxId!, - ); - expect(foundDm).toBeDefined(); - expect(foundDm!.id).toBe(dm.id); - }); - - it("should get a DM by identifier", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2, identifier: identifier2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId!); - const foundDm = - await client1.conversations.fetchDmByIdentifier(identifier2); - expect(foundDm).toBeDefined(); - expect(foundDm!.id).toBe(dm.id); - }); - - it("should get a message by ID", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const messageId = await group.sendText("gm!"); - expect(messageId).toBeDefined(); - - const message = await client1.conversations.getMessageById(messageId); - expect(message).toBeDefined(); - expect(message!.id).toBe(messageId); - }); - - it("should list conversations with options", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const group1 = await client1.conversations.createGroup([client2.inboxId!]); - const group2 = await client1.conversations.createGroup([client3.inboxId!]); - const dm1 = await client1.conversations.createDm(client2.inboxId!); - const dm2 = await client1.conversations.createDm(client3.inboxId!); - - // conversations by type (group) - const groups = await client1.conversations.list({ - conversationType: ConversationType.Group, - }); - expect(groups.length).toBe(2); - expect(groups[0].id).toBe(group2.id); - expect(groups[1].id).toBe(group1.id); - - // conversations by type (dm) - const dms = await client1.conversations.list({ - conversationType: ConversationType.Dm, - }); - expect(dms.length).toBe(2); - expect(dms[0].id).toBe(dm2.id); - expect(dms[1].id).toBe(dm1.id); - - // conversations by created before timestamp - const convos = await client1.conversations.list({ - createdBeforeNs: dm2.createdAtNs, - }); - expect(convos.length).toBe(3); - expect(convos[0].id).toBe(dm1.id); - expect(convos[1].id).toBe(group2.id); - expect(convos[2].id).toBe(group1.id); - - // conversations by created after timestamp - const convos2 = await client1.conversations.list({ - createdAfterNs: group1.createdAtNs, - }); - expect(convos2.length).toBe(3); - expect(convos2[0].id).toBe(dm2.id); - expect(convos2[1].id).toBe(dm1.id); - expect(convos2[2].id).toBe(group2.id); - - // conversations by created after timestamp and before timestamp - const convos3 = await client1.conversations.list({ - createdBeforeNs: dm2.createdAtNs, - createdAfterNs: group1.createdAtNs, - }); - expect(convos3.length).toBe(2); - expect(convos3[0].id).toBe(dm1.id); - expect(convos3[1].id).toBe(group2.id); - - // conversations by limit - const convos4 = await client1.conversations.list({ - limit: 1n, - orderBy: ListConversationsOrderBy.CreatedAt, - }); - expect(convos4.length).toBe(1); - expect(convos4[0].id).toBe(dm2.id); - - // conversations by order by (created at) - const convos5 = await client1.conversations.list({ - limit: 1n, - orderBy: ListConversationsOrderBy.LastActivity, - }); - expect(convos5.length).toBe(1); - expect(convos5[0].id).toBe(dm2.id); - }); - - it("should stream new conversations", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const stream = await client3.conversations.stream(); - const conversation1 = await client1.conversations.createGroup([ - client3.inboxId!, - ]); - const conversation2 = await client2.conversations.createDm( - client3.inboxId!, - ); - - const expectedIds = [conversation1.id, conversation2.id]; - const receivedIds: string[] = []; - - setTimeout(() => { - void stream.end(); - }, 1000); - - for await (const convo of stream) { - expect(convo).toBeDefined(); - receivedIds.push(convo.id); - } - - expect(receivedIds.length).toBe(2); - expect(receivedIds.sort()).toEqual(expectedIds.sort()); - expect( - (await client3.conversations.getConversationById(conversation1.id))?.id, - ).toBe(conversation1.id); - expect( - (await client3.conversations.getConversationById(conversation2.id))?.id, - ).toBe(conversation2.id); - }); - - it("should only stream group conversations", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const { signer: signer4 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const client4 = await createRegisteredClient(signer4); - const stream = await client3.conversations.streamGroups(); - await client4.conversations.createDm(client3.inboxId!); - const group1 = await client1.conversations.createGroup([client3.inboxId!]); - const group2 = await client2.conversations.createGroup([client3.inboxId!]); - - const expectedIds = [group1.id, group2.id]; - const receivedIds: string[] = []; - - setTimeout(() => { - void stream.end(); - }, 2000); - - for await (const convo of stream) { - expect(convo).toBeDefined(); - receivedIds.push(convo.id); - } - expect(receivedIds.length).toBe(2); - expect(receivedIds.sort()).toEqual(expectedIds.sort()); - }); - - it("should only stream dm conversations", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const { signer: signer4 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const client4 = await createRegisteredClient(signer4); - const stream = await client3.conversations.streamDms(); - await client1.conversations.createGroup([client3.inboxId!]); - await client2.conversations.createGroup([client3.inboxId!]); - const group3 = await client4.conversations.createDm(client3.inboxId!); - - setTimeout(() => { - void stream.end(); - }, 2000); - - let count = 0; - for await (const convo of stream) { - count++; - expect(convo).toBeDefined(); - if (count === 1) { - expect(convo.id).toBe(group3.id); - } - } - expect(count).toBe(1); - }); - - it("should stream all messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - await client1.conversations.createGroup([client2.inboxId!]); - await client1.conversations.createDm(client3.inboxId!); - - await sleep(2000); - - const stream = await client1.conversations.streamAllMessages(); - - await client2.conversations.sync(); - const groups2 = await client2.conversations.listGroups(); - - await client3.conversations.sync(); - const groups3 = await client3.conversations.listDms(); - - await groups2[0].sendText("gm!"); - await groups3[0].sendText("gm2!"); - - setTimeout(() => { - void stream.end(); - }, 2000); - - let count = 0; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - if (count === 1) { - expect(message.senderInboxId).toBe(client2.inboxId); - } - if (count === 2) { - expect(message.senderInboxId).toBe(client3.inboxId); - } - } - expect(count).toBe(2); - }); - - it("should only stream group conversation messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const { signer: signer4 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const client4 = await createRegisteredClient(signer4); - await client1.conversations.createGroup([client2.inboxId!]); - await client1.conversations.createGroup([client3.inboxId!]); - await client1.conversations.createDm(client4.inboxId!); - - await sleep(2000); - - const stream = await client1.conversations.streamAllGroupMessages(); - - const groups2 = client2.conversations; - await groups2.sync(); - const groupsList2 = await groups2.list(); - - const groups3 = client3.conversations; - await groups3.sync(); - const groupsList3 = await groups3.list(); - - const groups4 = client4.conversations; - await groups4.sync(); - const groupsList4 = await groups4.list(); - - await groupsList4[0].sendText("gm3!"); - await groupsList2[0].sendText("gm!"); - await groupsList3[0].sendText("gm2!"); - - setTimeout(() => { - void stream.end(); - }, 2000); - - let count = 0; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - if (count === 1) { - expect(message.senderInboxId).toBe(client2.inboxId); - } - if (count === 2) { - expect(message.senderInboxId).toBe(client3.inboxId); - } - } - expect(count).toBe(2); - }); - - it("should only stream dm messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const { signer: signer4 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const client4 = await createRegisteredClient(signer4); - await client1.conversations.createGroup([client2.inboxId!]); - await client1.conversations.createGroup([client3.inboxId!]); - await client1.conversations.createDm(client4.inboxId!); - - await sleep(2000); - - const stream = await client1.conversations.streamAllDmMessages(); - - const groups2 = client2.conversations; - await groups2.sync(); - const groupsList2 = await groups2.list(); - - const groups3 = client3.conversations; - await groups3.sync(); - const groupsList3 = await groups3.list(); - - const groups4 = client4.conversations; - await groups4.sync(); - const groupsList4 = await groups4.list(); - - await groupsList2[0].sendText("gm!"); - await groupsList3[0].sendText("gm2!"); - await groupsList4[0].sendText("gm3!"); - - setTimeout(() => { - void stream.end(); - }, 2000); - - let count = 0; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - if (count === 1) { - expect(message.senderInboxId).toBe(client4.inboxId); - } - expect(count).toBe(1); - } - }); - - it("should get hmac keys", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const dm = await client1.conversations.createDm(client2.inboxId!); - const hmacKeys = await client1.conversations.hmacKeys(); - expect(hmacKeys).toBeDefined(); - const keys = [...hmacKeys.keys()]; - expect(keys.length).toBe(2); - expect(keys).toContain(group.id); - expect(keys).toContain(dm.id); - for (const values of hmacKeys.values()) { - expect(values.length).toBe(3); - for (const value of values) { - expect(value.key).toBeDefined(); - expect(value.key.length).toBe(42); - expect(value.epoch).toBeDefined(); - expect(typeof value.epoch).toBe("bigint"); - } - } - }); - - it("should sync groups across installations", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2, { - dbPath: `./test-${uuid()}.db3`, - }); - await createRegisteredClient(signer2); - - const group = await client.conversations.createGroup([client2.inboxId!]); - await client2.conversations.sync(); - const convos = await client2.conversations.listGroups(); - expect(convos.length).toBe(1); - expect(convos[0].id).toBe(group.id); - - const group2 = await client.conversations.createDm(client2.inboxId!); - await client2.conversations.sync(); - const convos2 = await client2.conversations.list(); - expect(convos2.length).toBe(2); - const convos2Ids = convos2.map((c) => c.id); - expect(convos2Ids).toContain(group.id); - expect(convos2Ids).toContain(group2.id); - }); - - it("should stitch DM groups together", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm1 = await client1.conversations.createDm(client2.inboxId!); - const dm2 = await client2.conversations.createDm(client1.inboxId!); - - await dm1.sendText("hi"); - // since this is the last message sent, the stitched group ID will be - // this group ID - await dm2.sendText("hi"); - - await client1.conversations.sync(); - await client2.conversations.sync(); - await dm1.sync(); - await dm2.sync(); - - const dm1_2 = await client1.conversations.getConversationById(dm1.id); - const dm2_2 = await client2.conversations.getConversationById(dm2.id); - expect(dm1_2?.id).toBe(dm2.id); - expect(dm2_2?.id).toBe(dm2.id); - - const dms1 = await client1.conversations.listDms(); - const dms2 = await client2.conversations.listDms(); - expect(dms1[0].id).toBe(dm2.id); - expect(dms2[0].id).toBe(dm2.id); - - const dupeDms1 = await dms1[0].duplicateDms(); - const dupeDms2 = await dms2[0].duplicateDms(); - expect(dupeDms1.length).toBe(1); - expect(dupeDms2.length).toBe(1); - expect(dupeDms1[0].id).toBe(dm1.id); - expect(dupeDms2[0].id).toBe(dm1.id); - }); -}); diff --git a/sdks/browser-sdk/test/DebugInformation.test.ts b/sdks/browser-sdk/test/DebugInformation.test.ts deleted file mode 100644 index 0f1ac3839..000000000 --- a/sdks/browser-sdk/test/DebugInformation.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { createRegisteredClient, createSigner } from "@test/helpers"; - -describe("DebugInformation", () => { - it("should return network API statistics", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - - const apiStats = await client.debugInformation.apiStatistics(); - expect(apiStats.fetchKeyPackage).toBe(0n); - expect(apiStats.queryGroupMessages).toBe(0n); - expect(apiStats.queryWelcomeMessages).toBe(0n); - expect(apiStats.sendGroupMessages).toBe(0n); - expect(apiStats.sendWelcomeMessages).toBe(0n); - expect(apiStats.subscribeMessages).toBe(0n); - expect(apiStats.subscribeWelcomes).toBe(0n); - expect(apiStats.uploadKeyPackage).toBe(1n); - - const apiIdentityStats = - await client.debugInformation.apiIdentityStatistics(); - expect(apiIdentityStats.getIdentityUpdatesV2).toBe(2n); - expect(apiIdentityStats.getInboxIds).toBe(1n); - expect(apiIdentityStats.publishIdentityUpdate).toBe(1n); - expect(apiIdentityStats.verifySmartContractWalletSignature).toBe(0n); - - await client.debugInformation.clearAllStatistics(); - - const apiStats2 = await client.debugInformation.apiStatistics(); - expect(apiStats2.uploadKeyPackage).toBe(0n); - expect(apiStats2.fetchKeyPackage).toBe(0n); - expect(apiStats2.sendWelcomeMessages).toBe(0n); - expect(apiStats2.queryGroupMessages).toBe(0n); - expect(apiStats2.queryWelcomeMessages).toBe(0n); - expect(apiStats2.subscribeMessages).toBe(0n); - - const apiIdentityStats2 = - await client.debugInformation.apiIdentityStatistics(); - expect(apiIdentityStats2.getIdentityUpdatesV2).toBe(0n); - expect(apiIdentityStats2.getInboxIds).toBe(0n); - expect(apiIdentityStats2.publishIdentityUpdate).toBe(0n); - expect(apiIdentityStats2.verifySmartContractWalletSignature).toBe(0n); - - const apiAggregateStats = - await client.debugInformation.apiAggregateStatistics(); - expect(apiAggregateStats).toBeDefined(); - }); -}); diff --git a/sdks/browser-sdk/test/DeviceSync.test.ts b/sdks/browser-sdk/test/DeviceSync.test.ts deleted file mode 100644 index 5f59f9e38..000000000 --- a/sdks/browser-sdk/test/DeviceSync.test.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { ConsentEntityType, ConsentState } from "@xmtp/wasm-bindings"; -import { describe, expect, it } from "vitest"; -import { HistorySyncUrls } from "@/constants"; -import { uuid } from "@/utils/uuid"; -import { createRegisteredClient, createSigner, sleep } from "@test/helpers"; - -describe("DeviceSync", () => { - it("should sync consent across installations", async () => { - const { signer: boSigner } = createSigner(); - const { signer: alixSigner } = createSigner(); - - const bo = await createRegisteredClient(boSigner); - const alix = await createRegisteredClient(alixSigner); - - // create DM conversation - const dm = await alix.conversations.createDm(bo.inboxId!); - const initialConsent = await dm.consentState(); - expect( - initialConsent === ConsentState.Unknown || - initialConsent === ConsentState.Allowed, - ).toBe(true); - - await bo.conversations.sync(); - - // create second installation for alix - const alix2 = await createRegisteredClient(alixSigner, { - dbPath: `./test-${uuid()}.db3`, - }); - - const state = await alix2.preferences.fetchInboxState(); - expect(state.installations.length).toBe(2); - - // sync the DM on alix so conversation is pushed - await dm.sync(); - await sleep(1000); - await alix.conversations.syncAll(); - await sleep(1000); - - // alix2 syncs so it has the DM - await alix2.conversations.sync(); - await sleep(1000); - - const dm2Initial = await alix2.conversations.getConversationById(dm.id); - expect(dm2Initial).not.toBeNull(); - - const consentOnAlix2Before = await dm2Initial!.consentState(); - expect( - consentOnAlix2Before === ConsentState.Unknown || - consentOnAlix2Before === ConsentState.Allowed, - ).toBe(true); - - // update consent to denied on alix - await dm.updateConsentState(ConsentState.Denied); - const consentState = await dm.consentState(); - expect(consentState).toBe(ConsentState.Denied); - - await alix.preferences.sync(); - await sleep(1000); - await alix2.preferences.sync(); - await sleep(1000); - - const dm2 = await alix2.conversations.getConversationById(dm.id); - expect(dm2).not.toBeNull(); - - const consentState2 = await dm2!.consentState(); - expect(consentState2).toBe(ConsentState.Denied); - - // update consent back to allowed on alix2 - await alix2.preferences.setConsentStates([ - { - entityType: ConsentEntityType.GroupId, - entity: dm2!.id, - state: ConsentState.Allowed, - }, - ]); - - const convoState = await alix2.preferences.getConsentState( - ConsentEntityType.GroupId, - dm2!.id, - ); - expect(convoState).toBe(ConsentState.Allowed); - - const updatedConsentState = await dm2!.consentState(); - expect(updatedConsentState).toBe(ConsentState.Allowed); - }); - - it("should sync device archive using sendSyncArchive, listAvailableArchives, and processSyncArchive", async () => { - const { signer: boSigner } = createSigner(); - const { signer: alixSigner } = createSigner(); - - const bo = await createRegisteredClient(boSigner); - const alix = await createRegisteredClient(alixSigner); - - const group = await alix.conversations.createGroup([bo.inboxId!]); - const msgFromAlix = await group.sendText("hello from alix"); - - await sleep(1000); - - // create second installation for alix - const alix2 = await createRegisteredClient(alixSigner, { - dbPath: `./test-${uuid()}.db3`, - }); - - await sleep(1000); - - await alix.syncAllDeviceSyncGroups(); - await alix.sendSyncArchive( - "123", - { - elements: [], - excludeDisappearingMessages: false, - }, - HistorySyncUrls.local, - ); - await sleep(1000); - - await bo.conversations.syncAll(); - const boGroup = await bo.conversations.getConversationById(group.id); - expect(boGroup).not.toBeNull(); - await boGroup!.sendText("hello from bo"); - - await alix.conversations.syncAll(); - await alix2.conversations.syncAll(); - - const group2Before = await alix2.conversations.getConversationById( - group.id, - ); - expect(group2Before).not.toBeNull(); - - const messagesBefore = await group2Before!.messages(); - expect(messagesBefore.length).toBe(2); - - await sleep(1000); - await alix.syncAllDeviceSyncGroups(); - await sleep(1000); - await alix2.syncAllDeviceSyncGroups(); - - // list available archives - may fail in some environments - try { - const archives = await alix2.listAvailableArchives(7); - expect(archives).toBeDefined(); - } catch { - // listAvailableArchives may not be fully supported in all test environments - } - - await alix2.processSyncArchive("123"); - await sleep(1000); - await alix2.conversations.syncAll(); - - const group2After = await alix2.conversations.getConversationById(group.id); - expect(group2After).not.toBeNull(); - - const messagesAfter = await group2After!.messages(); - // verify we received messages from the archive sync - // the exact count may vary depending on sync timing - expect(messagesAfter.length).toBeGreaterThanOrEqual(2); - // check if we found the original message from alix - const foundOriginalMessage = messagesAfter.some( - (m) => m.id === msgFromAlix, - ); - if (messagesAfter.length >= 3) { - expect(foundOriginalMessage).toBe(true); - } - }); - - it("should sync messages across installations using sendSyncRequest and syncAllDeviceSyncGroups", async () => { - const { signer: boSigner } = createSigner(); - const { signer: alixSigner } = createSigner(); - - const bo = await createRegisteredClient(boSigner); - const client1 = await createRegisteredClient(alixSigner); - - const group = await client1.conversations.createGroup([bo.inboxId!]); - - // send a message before second installation is created - const msgId = await group.sendText("hi"); - const messages = await group.messages(); - expect(messages.length).toBe(2); - - // create second installation - const client2 = await createRegisteredClient(alixSigner, { - dbPath: `./test-${uuid()}.db3`, - }); - - const state = await client2.preferences.fetchInboxState(); - expect(state.installations.length).toBe(2); - - await client2.sendSyncRequest( - { - elements: [], - excludeDisappearingMessages: false, - }, - HistorySyncUrls.local, - ); - - await client1.syncAllDeviceSyncGroups(); - await sleep(1000); - await client2.syncAllDeviceSyncGroups(); - await sleep(1000); - - // sync conversations to get the group on client2 - await client2.conversations.syncAll(); - await sleep(1000); - - const client1MessageCount = (await group.messages()).length; - const group2 = await client2.conversations.getConversationById(group.id); - expect(group2).not.toBeNull(); - - const messagesOnClient2 = await group2!.messages(); - const containsMessage = messagesOnClient2.some((m) => m.id === msgId); - const client2MessageCount = messagesOnClient2.length; - - // verify client2 has the group and some messages - expect(client2MessageCount).toBeGreaterThan(0); - - if (client1MessageCount === client2MessageCount) { - expect(containsMessage).toBe(true); - } - }); -}); diff --git a/sdks/browser-sdk/test/Dm.test.ts b/sdks/browser-sdk/test/Dm.test.ts deleted file mode 100644 index 98049cd53..000000000 --- a/sdks/browser-sdk/test/Dm.test.ts +++ /dev/null @@ -1,457 +0,0 @@ -import { - ConsentState, - ContentType, - ConversationType, - MetadataField, - type GroupUpdated, - type MessageDisappearingSettings, -} from "@xmtp/wasm-bindings"; -import { describe, expect, it } from "vitest"; -import type { DecodedMessage } from "@/DecodedMessage"; -import { metadataFieldName } from "@/utils/metadata"; -import { createRegisteredClient, createSigner, sleep } from "@test/helpers"; - -describe("Dm", () => { - it("should have a topic", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId!); - expect(dm.topic).toBe(`/xmtp/mls/1/g-${dm.id}/proto`); - }); - - it("should create a dm", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const dm = await client1.conversations.createDm(client2.inboxId!); - expect(dm).toBeDefined(); - expect(dm.id).toBeDefined(); - expect(dm.createdAtNs).toBeDefined(); - expect(dm.createdAt).toBeDefined(); - expect(await dm.isActive()).toBe(true); - expect(dm.addedByInboxId).toBe(client1.inboxId); - expect(await dm.peerInboxId()).toBe(client2.inboxId); - - expect((await dm.messages()).length).toBe(1); - - const members = await dm.members(); - expect(members.length).toBe(2); - const memberInboxIds = members.map((member) => member.inboxId); - expect(memberInboxIds).toContain(client1.inboxId); - expect(memberInboxIds).toContain(client2.inboxId); - - expect(dm.metadata?.conversationType).toBe(ConversationType.Dm); - expect(dm.metadata?.creatorInboxId).toBe(client1.inboxId); - - expect(await dm.consentState()).toBe(ConsentState.Allowed); - - const dms = await client1.conversations.listDms(); - expect(dms.length).toBe(1); - expect(dms[0].id).toBe(dm.id); - - expect((await client1.conversations.listDms()).length).toBe(1); - expect((await client1.conversations.listGroups()).length).toBe(0); - - // confirm DM in other client - await client2.conversations.sync(); - const dms2 = await client2.conversations.listDms(); - expect(dms2.length).toBe(1); - expect(dms2[0].id).toBe(dm.id); - expect(await dms2[0].peerInboxId()).toBe(client1.inboxId); - - expect((await client2.conversations.listDms()).length).toBe(1); - expect((await client2.conversations.listGroups()).length).toBe(0); - - const dupeDms = await dm.duplicateDms(); - expect(dupeDms.length).toEqual(0); - }); - - it("should create a DM with identifier", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2, identifier: identifier2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDmWithIdentifier(identifier2); - expect(await dm.peerInboxId()).toBe(client2.inboxId); - }); - - it("should send and list messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId!); - - expect(await dm.lastMessage()).toBeDefined(); - - const text = "gm"; - await dm.sendText(text); - - const messages = await dm.messages(); - expect(messages.length).toBe(2); - expect(messages[1].content).toBe(text); - - const lastMessage = await dm.lastMessage(); - expect(lastMessage).toBeDefined(); - expect(lastMessage?.id).toBe(messages[1].id); - expect(lastMessage?.content).toBe(text); - - await client2.conversations.sync(); - const dms = await client2.conversations.listDms(); - expect(dms.length).toBe(1); - - const dm2 = dms[0]; - expect(dm2).toBeDefined(); - await dm2.sync(); - expect(dm2.id).toBe(dm.id); - - const messages2 = await dm2.messages(); - expect(messages2.length).toBe(2); - expect(messages2[1].content).toBe(text); - - const lastMessage2 = await dm2.lastMessage(); - expect(lastMessage2).toBeDefined(); - expect(lastMessage2?.id).toBe(messages2[1].id); - expect(lastMessage2?.content).toBe(text); - }); - - it("should optimistically send and list messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId!); - - const text = "gm"; - await dm.sendText(text, true); - - const messages = await dm.messages(); - expect(messages.length).toBe(2); - expect(messages[1].content).toBe(text); - - await client2.conversations.sync(); - const dms = await client2.conversations.listDms(); - expect(dms.length).toBe(1); - - const dm2 = dms[0]; - expect(dm2).toBeDefined(); - - await dm2.sync(); - expect(dm2.id).toBe(dm.id); - - const messages2 = await dm2.messages(); - expect(messages2.length).toBe(1); - - await dm.publishMessages(); - await dm2.sync(); - - const messages4 = await dm2.messages(); - expect(messages4.length).toBe(2); - expect(messages4[1].content).toBe(text); - }); - - it("should stream messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId!); - - // wait a second to exclude GroupUpdated message - await sleep(1000); - - const streamedMessages: unknown[] = []; - const stream = await dm.stream({ - onValue: (message) => { - streamedMessages.push(message.content); - }, - }); - - await dm.sendText("gm"); - await dm.sendText("gm2"); - - setTimeout(() => { - void stream.end(); - }, 100); - - let count = 0; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - } - expect(count).toBe(2); - expect(streamedMessages).toEqual(["gm", "gm2"]); - }); - - it("should manage consent state", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId!); - expect(await dm.consentState()).toBe(ConsentState.Allowed); - - await client2.conversations.sync(); - const dm2 = (await client2.conversations.listDms())[0]; - expect(dm2).toBeDefined(); - expect(await dm2.consentState()).toBe(ConsentState.Unknown); - await dm2.sendText("gm!"); - expect(await dm2.consentState()).toBe(ConsentState.Allowed); - }); - - it("should handle disappearing messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const stream = await client1.conversations.streamDeletedMessages(); - - // create message disappearing settings so that messages are deleted after 1 second - const messageDisappearingSettings: MessageDisappearingSettings = { - fromNs: 1n, - inNs: 2_000_000_000n, - }; - - // create a group with message disappearing settings - const dm = await client1.conversations.createDm(client2.inboxId!, { - messageDisappearingSettings, - }); - - // verify that the message disappearing settings are set and enabled - expect(await dm.messageDisappearingSettings()).toEqual({ - fromNs: 1n, - inNs: 2_000_000_000n, - }); - expect(await dm.isMessageDisappearingEnabled()).toBe(true); - - // send messages to the group - const messageId1 = await dm.sendText("gm"); - const messageId2 = await dm.sendText("gm2"); - - // verify that the messages are sent - expect((await dm.messages()).length).toBe(3); - - // sync the messages to the other client - await client2.conversations.sync(); - const dm2 = (await client2.conversations.listDms())[0]; - expect(dm2).toBeDefined(); - await dm2.sync(); - - // verify that the message disappearing settings are set and enabled - expect(await dm2.messageDisappearingSettings()).toEqual({ - fromNs: 1n, - inNs: 2_000_000_000n, - }); - expect(await dm2.isMessageDisappearingEnabled()).toBe(true); - - // wait for the messages to be deleted - await sleep(2000); - - // verify that the messages are deleted - expect((await dm.messages()).length).toBe(1); - - // verify that the messages are deleted on the other client - expect((await dm2.messages()).length).toBe(1); - - setTimeout(() => { - void stream.end(); - }, 1000); - - let count = 0; - const messageIds: string[] = []; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - messageIds.push(message.id); - } - expect(count).toBe(2); - expect(messageIds).toContain(messageId1); - expect(messageIds).toContain(messageId2); - - // remove the message disappearing settings - await dm.removeMessageDisappearingSettings(); - - // verify that the message disappearing settings are removed - expect(await dm.messageDisappearingSettings()).toEqual({ - fromNs: 0n, - inNs: 0n, - }); - - expect(await dm.isMessageDisappearingEnabled()).toBe(false); - - // sync other group - await dm2.sync(); - - // verify that the message disappearing settings are set and disabled - expect(await dm2.messageDisappearingSettings()).toEqual({ - fromNs: 0n, - inNs: 0n, - }); - expect(await dm2.isMessageDisappearingEnabled()).toBe(false); - - // check for metadata field changes - const messages = await dm2.messages(); - const fieldChange1 = messages[1] as DecodedMessage; - expect(fieldChange1.content?.metadataFieldChanges).toBeDefined(); - expect(fieldChange1.content?.metadataFieldChanges.length).toBe(1); - expect(fieldChange1.content?.metadataFieldChanges[0].fieldName).toBe( - await metadataFieldName(MetadataField.MessageExpirationFromNs), - ); - expect(fieldChange1.content?.metadataFieldChanges[0].oldValue).toBe("1"); - expect(fieldChange1.content?.metadataFieldChanges[0].newValue).toBe("0"); - - const fieldChange2 = messages[2] as DecodedMessage; - expect(fieldChange2.content?.metadataFieldChanges).toBeDefined(); - expect(fieldChange2.content?.metadataFieldChanges.length).toBe(1); - expect(fieldChange2.content?.metadataFieldChanges[0].fieldName).toBe( - await metadataFieldName(MetadataField.MessageExpirationInNs), - ); - expect(fieldChange2.content?.metadataFieldChanges[0].oldValue).toBe( - "2000000000", - ); - expect(fieldChange2.content?.metadataFieldChanges[0].newValue).toBe("0"); - - // send messages to the group - await dm2.sendText("gm"); - await dm2.sendText("gm2"); - - // verify that the messages are sent - expect((await dm2.messages()).length).toBe(5); - - // sync original group - await dm.sync(); - - // verify that the messages are not deleted - expect((await dm.messages()).length).toBe(5); - }); - - it("should return paused for version", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const conversation = await client1.conversations.createDm(client2.inboxId!); - expect(await conversation.pausedForVersion()).toBeUndefined(); - }); - - it("should get hmac keys", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const dm = await client1.conversations.createDm(client2.inboxId!); - - const hmacKeys = await dm.hmacKeys(); - const groupIds = Array.from(hmacKeys.keys()); - for (const groupId of groupIds) { - expect(hmacKeys.get(groupId)?.length).toBe(3); - expect(hmacKeys.get(groupId)?.[0].key).toBeDefined(); - expect(hmacKeys.get(groupId)?.[0].epoch).toBeDefined(); - expect(hmacKeys.get(groupId)?.[1].key).toBeDefined(); - expect(hmacKeys.get(groupId)?.[1].epoch).toBeDefined(); - expect(hmacKeys.get(groupId)?.[2].key).toBeDefined(); - expect(hmacKeys.get(groupId)?.[2].epoch).toBeDefined(); - } - }); - - it("should get debug info", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId!); - const debugInfo = await dm.debugInfo(); - expect(debugInfo).toBeDefined(); - expect(debugInfo.epoch).toBeDefined(); - expect(debugInfo.maybeForked).toBe(false); - expect(debugInfo.forkDetails).toBe(""); - expect(debugInfo.isCommitLogForked).toBeUndefined(); - expect(debugInfo.localCommitLog).toBeDefined(); - expect(debugInfo.remoteCommitLog).toBeDefined(); - expect(debugInfo.cursor).toBeDefined(); - expect(debugInfo.cursor.length).toBeGreaterThan(0); - for (const cursor of debugInfo.cursor) { - expect(cursor.originatorId).toBeDefined(); - expect(cursor.sequenceId).toBeDefined(); - } - }); - - it("should filter messages by content type", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId!); - - await dm.sendText("gm"); - - const messages = await dm.messages(); - expect(messages.length).toBe(2); - - const filteredMessages = await dm.messages({ - contentTypes: [ContentType.Text], - }); - expect(filteredMessages.length).toBe(1); - }); - - it("should count messages with various filters", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - // Setup: create conversation and messages once - const dm = await client1.conversations.createDm(client2.inboxId!); - - await dm.sendText("text 1"); - await sleep(10); - const timestamp1 = BigInt(Date.now() * 1_000_000); - await sleep(10); - await dm.sendText("text 2"); - await sleep(10); - const timestamp2 = BigInt(Date.now() * 1_000_000); - await sleep(10); - await dm.sendText("text 3"); - - // GroupUpdated messages are not counted - expect(await dm.countMessages()).toBe(3n); - - // Time filters - expect( - await dm.countMessages({ - sentBeforeNs: timestamp1, - contentTypes: [ContentType.Text], - }), - ).toBe(1n); - expect( - await dm.countMessages({ - sentAfterNs: timestamp1, - }), - ).toBe(2n); - expect( - await dm.countMessages({ - sentAfterNs: timestamp2, - contentTypes: [ContentType.Text], - }), - ).toBe(1n); - expect( - await dm.countMessages({ - sentAfterNs: timestamp1, - sentBeforeNs: timestamp2, - }), - ).toBe(1n); - - // Content type filter - expect( - await dm.countMessages({ - contentTypes: [ContentType.Text], - }), - ).toBe(3n); - }); -}); diff --git a/sdks/browser-sdk/test/Group.test.ts b/sdks/browser-sdk/test/Group.test.ts deleted file mode 100644 index f5956275c..000000000 --- a/sdks/browser-sdk/test/Group.test.ts +++ /dev/null @@ -1,1005 +0,0 @@ -import { - ConsentState, - ContentType, - ConversationType, - DeliveryStatus, - encodeText, - GroupMessageKind, - MetadataField, - ReactionAction, - ReactionSchema, - SortDirection, - type GroupUpdated, - type MessageDisappearingSettings, -} from "@xmtp/wasm-bindings"; -import { describe, expect, it } from "vitest"; -import type { DecodedMessage } from "@/DecodedMessage"; -import { - contentTypeGroupUpdated, - contentTypeLeaveRequest, -} from "@/utils/contentTypes"; -import { metadataFieldName } from "@/utils/metadata"; -import { - createRegisteredClient, - createSigner, - sleep, - TestCodec, -} from "@test/helpers"; - -describe("Group", () => { - it("should have a topic", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - expect(group.topic).toBe(`/xmtp/mls/1/g-${group.id}/proto`); - }); - - it("should create a group", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const group = await client1.conversations.createGroup([client2.inboxId!]); - expect(group).toBeDefined(); - expect( - (await client1.conversations.getConversationById(group.id))?.id, - ).toBe(group.id); - expect(group.id).toBeDefined(); - expect(group.createdAt).toBeDefined(); - expect(group.createdAtNs).toBeDefined(); - expect(await group.isActive()).toBe(true); - expect(group.name).toBe(""); - expect(group.addedByInboxId).toBe(client1.inboxId); - expect((await group.messages()).length).toBe(1); - - const members = await group.members(); - expect(members.length).toBe(2); - const memberInboxIds = members.map((member) => member.inboxId); - expect(memberInboxIds).toContain(client1.inboxId); - expect(memberInboxIds).toContain(client2.inboxId); - expect(group.metadata).toEqual({ - conversationType: ConversationType.Group, - creatorInboxId: client1.inboxId, - }); - - expect((await client1.conversations.listDms()).length).toBe(0); - - const groups = await client1.conversations.listGroups(); - expect(groups.length).toBe(1); - expect(groups[0].id).toBe(group.id); - - // confirm group in other client - await client2.conversations.sync(); - const groups2 = await client2.conversations.listGroups(); - expect(groups2.length).toBe(1); - expect(groups2[0].id).toBe(group.id); - - expect((await client2.conversations.listDms()).length).toBe(0); - }); - - it("should create a group with an identifier", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2, identifier: identifier2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroupWithIdentifiers([ - identifier2, - ]); - expect(group).toBeDefined(); - expect( - (await client1.conversations.getConversationById(group.id))?.id, - ).toBe(group.id); - expect(group.id).toBeDefined(); - expect(group.createdAt).toBeDefined(); - expect(group.createdAtNs).toBeDefined(); - expect(await group.isActive()).toBe(true); - expect(group.name).toBe(""); - expect(group.addedByInboxId).toBe(client1.inboxId); - expect((await group.messages()).length).toBe(1); - - const members = await group.members(); - expect(members.length).toBe(2); - const memberInboxIds = members.map((member) => member.inboxId); - expect(memberInboxIds).toContain(client1.inboxId); - expect(memberInboxIds).toContain(client2.inboxId); - expect(group.metadata).toEqual({ - conversationType: ConversationType.Group, - creatorInboxId: client1.inboxId, - }); - - const groups = await client1.conversations.listGroups(); - expect(groups.length).toBe(1); - expect(groups[0].id).toBe(group.id); - expect((await client1.conversations.listDms()).length).toBe(0); - - // confirm group in other client - await client2.conversations.sync(); - const groups2 = await client2.conversations.listGroups(); - expect(groups2.length).toBe(1); - expect(groups2[0].id).toBe(group.id); - - expect((await client2.conversations.listDms()).length).toBe(0); - }); - - it("should optimistically create a group", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroupOptimistic({ - groupName: "foo", - groupDescription: "bar", - }); - - expect(group.id).toBeDefined(); - expect(group.name).toBe("foo"); - expect(group.description).toBe("bar"); - expect(group.imageUrl).toBe(""); - expect(group.addedByInboxId).toBe(client1.inboxId); - - const text = "gm"; - await group.sendText(text, true); - - const messages = await group.messages(); - expect(messages.length).toBe(1); - expect(messages[0].content).toBe(text); - expect(messages[0].deliveryStatus).toBe(DeliveryStatus.Unpublished); - - await group.publishMessages(); - - const messages2 = await group.messages(); - expect(messages2.length).toBe(1); - expect(messages2[0].content).toBe(text); - expect(messages2[0].deliveryStatus).toBe(DeliveryStatus.Published); - }); - - it("should optimistically create a group with members", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroupOptimistic({ - groupName: "foo", - groupDescription: "bar", - }); - - expect(group.id).toBeDefined(); - expect(group.name).toBe("foo"); - expect(group.description).toBe("bar"); - expect(group.imageUrl).toBe(""); - expect(group.addedByInboxId).toBe(client1.inboxId); - - const text = "gm"; - await group.sendText(text, true); - - const messages = await group.messages(); - expect(messages.length).toBe(1); - expect(messages[0].content).toBe(text); - expect(messages[0].deliveryStatus).toBe(DeliveryStatus.Unpublished); - - await group.addMembers([client2.inboxId!]); - - const members = await group.members(); - const memberInboxIds = members.map((member) => member.inboxId); - expect(memberInboxIds.length).toBe(2); - expect(memberInboxIds).toContain(client1.inboxId); - expect(memberInboxIds).toContain(client2.inboxId); - - const messages3 = await group.messages(); - expect(messages3.length).toBe(2); - expect(messages3[0].content).toBe(text); - expect(messages3[0].deliveryStatus).toBe(DeliveryStatus.Published); - expect(messages3[1].deliveryStatus).toBe(DeliveryStatus.Published); - }); - - it("should create a group with options", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([], { - groupName: "foo", - groupImageUrlSquare: "https://foo/bar.png", - groupDescription: "foo", - }); - expect(group.name).toBe("foo"); - expect(group.imageUrl).toBe("https://foo/bar.png"); - expect(group.description).toBe("foo"); - }); - - it("should update group name", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([]); - expect(group.name).toBe(""); - const newName = "foo"; - await group.updateName(newName); - expect(group.name).toBe(newName); - const messages = await group.messages(); - expect(messages.length).toBe(1); - const message = messages[0] as DecodedMessage; - expect(message.content!.metadataFieldChanges).toHaveLength(1); - expect(message.content!.metadataFieldChanges[0].fieldName).toBe( - await metadataFieldName(MetadataField.GroupName), - ); - expect(message.content!.metadataFieldChanges[0].oldValue).toBe(""); - expect(message.content!.metadataFieldChanges[0].newValue).toBe(newName); - }); - - it("should update group image URL", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([]); - expect(group.imageUrl).toBe(""); - const imageUrl = "https://foo/bar.jpg"; - await group.updateImageUrl(imageUrl); - expect(group.imageUrl).toBe(imageUrl); - const messages = await group.messages(); - expect(messages.length).toBe(1); - const message = messages[0] as DecodedMessage; - expect(message.content!.metadataFieldChanges).toHaveLength(1); - expect(message.content!.metadataFieldChanges[0].fieldName).toBe( - await metadataFieldName(MetadataField.GroupImageUrlSquare), - ); - expect(message.content!.metadataFieldChanges[0].oldValue).toBe(""); - expect(message.content!.metadataFieldChanges[0].newValue).toBe(imageUrl); - }); - - it("should update group description", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([]); - expect(group.description).toBe(""); - const newDescription = "foo"; - await group.updateDescription(newDescription); - expect(group.description).toBe(newDescription); - const messages = await group.messages(); - expect(messages.length).toBe(1); - const message = messages[0] as DecodedMessage; - expect(message.content!.metadataFieldChanges).toHaveLength(1); - expect(message.content!.metadataFieldChanges[0].fieldName).toBe( - await metadataFieldName(MetadataField.Description), - ); - expect(message.content!.metadataFieldChanges[0].oldValue).toBe(""); - expect(message.content!.metadataFieldChanges[0].newValue).toBe( - newDescription, - ); - }); - - it("should update group app data", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([]); - expect(group.appData).toBe(""); - const appData = "foo"; - await group.updateAppData(appData); - expect(group.appData).toBe(appData); - const messages = await group.messages(); - expect(messages.length).toBe(1); - const message = messages[0] as DecodedMessage; - expect(message.content!.metadataFieldChanges).toHaveLength(1); - expect(message.content!.metadataFieldChanges[0].fieldName).toBe( - await metadataFieldName(MetadataField.AppData), - ); - expect(message.content!.metadataFieldChanges[0].oldValue).toBe(""); - expect(message.content!.metadataFieldChanges[0].newValue).toBe(appData); - }); - - it("should add and remove members", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - const members = await group.members(); - - const memberInboxIds = members.map((member) => member.inboxId); - expect(memberInboxIds).toContain(client1.inboxId); - expect(memberInboxIds).toContain(client2.inboxId); - expect(memberInboxIds).not.toContain(client3.inboxId); - - await group.addMembers([client3.inboxId!]); - - const members2 = await group.members(); - expect(members2.length).toBe(3); - - const memberInboxIds2 = members2.map((member) => member.inboxId); - expect(memberInboxIds2).toContain(client1.inboxId); - expect(memberInboxIds2).toContain(client2.inboxId); - expect(memberInboxIds2).toContain(client3.inboxId); - - await group.removeMembers([client2.inboxId!]); - - const members3 = await group.members(); - expect(members3.length).toBe(2); - - const memberInboxIds3 = members3.map((member) => member.inboxId); - expect(memberInboxIds3).toContain(client1.inboxId); - expect(memberInboxIds3).not.toContain(client2.inboxId); - expect(memberInboxIds3).toContain(client3.inboxId); - - const messages = (await group.messages()) as DecodedMessage[]; - expect(messages.length).toBe(3); - expect(messages[0].content?.addedInboxes).toHaveLength(1); - expect(messages[0].content?.addedInboxes[0].inboxId).toBe(client2.inboxId); - expect(messages[1].content?.addedInboxes).toHaveLength(1); - expect(messages[1].content?.addedInboxes[0].inboxId).toBe(client3.inboxId); - expect(messages[2].content?.removedInboxes).toHaveLength(1); - expect(messages[2].content?.removedInboxes[0].inboxId).toBe( - client2.inboxId, - ); - }); - - it("should send and list messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - expect(await group.lastMessage()).toBeDefined(); - - const text = "gm"; - await group.sendText(text); - - const messages = await group.messages(); - expect(messages.length).toBe(2); - expect(messages[1].content).toBe(text); - - const lastMessage = await group.lastMessage(); - expect(lastMessage).toBeDefined(); - expect(lastMessage?.id).toBe(messages[1].id); - expect(lastMessage?.content).toBe(text); - - await client2.conversations.sync(); - const groups = await client2.conversations.listGroups(); - expect(groups.length).toBe(1); - - const group2 = groups[0]; - expect(group2).toBeDefined(); - await group2.sync(); - expect(group2.id).toBe(group.id); - - const messages2 = await group2.messages(); - expect(messages2.length).toBe(2); - expect(messages2[1].content).toBe(text); - - const lastMessage2 = await group2.lastMessage(); - expect(lastMessage2).toBeDefined(); - expect(lastMessage2?.id).toBe(messages2[1].id); - expect(lastMessage2?.content).toBe(text); - }); - - it("should optimistically send and list messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - const text = "gm"; - await group.sendText(text, true); - - const messages = await group.messages(); - expect(messages.length).toBe(2); - expect(messages[1].content).toBe(text); - - await client2.conversations.sync(); - const groups = await client2.conversations.listGroups(); - expect(groups.length).toBe(1); - - const group2 = groups[0]; - expect(group2).toBeDefined(); - - await group2.sync(); - expect(group2.id).toBe(group.id); - - const messages2 = await group2.messages(); - expect(messages2.length).toBe(1); - - await group.publishMessages(); - await group2.sync(); - - const messages4 = await group2.messages(); - expect(messages4.length).toBe(2); - expect(messages4[1].content).toBe(text); - }); - - it("should filter messages with options", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const testCodec = new TestCodec(); - const client1 = await createRegisteredClient(signer1, { - codecs: [testCodec], - }); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - // leave request message - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - await group2.requestRemoval(); - await group.sync(); - - const textMessageId = await group.sendText("gm"); - await group.sendMarkdown("# gm"); - await group.sendAttachment({ - filename: "test.txt", - mimeType: "text/plain", - content: new Uint8Array([1, 2, 3]), - }); - await group.sendReply({ - reference: textMessageId, - referenceInboxId: client1.inboxId, - content: encodeText("gm"), - }); - const replyMessage = await group.lastMessage(); - await group.sendReaction({ - reference: textMessageId, - action: ReactionAction.Added, - content: "👍", - schema: ReactionSchema.Unicode, - referenceInboxId: client1.inboxId!, - }); - await group.sendActions({ - id: "actions-1", - description: "test", - actions: [ - { - id: "opt-1", - label: "Option 1", - }, - ], - }); - await group.sendIntent({ - id: "intent-1", - actionId: "opt-1", - }); - await group.sendTransactionReference({ - networkId: "1", - reference: "1234567890", - }); - await group.sendWalletSendCalls({ - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - }, - ], - }); - await group.sendReadReceipt(); - await group.sendRemoteAttachment({ - url: "https://foo/bar.png", - contentDigest: "1234567890", - secret: new Uint8Array([1, 2, 3]), - salt: new Uint8Array([1, 2, 3]), - nonce: new Uint8Array([1, 2, 3]), - scheme: "https", - contentLength: 100, - }); - await group.sendMultiRemoteAttachment({ - attachments: [ - { - url: "https://foo/bar.png", - contentDigest: "1234567890", - secret: new Uint8Array([1, 2, 3]), - salt: new Uint8Array([1, 2, 3]), - nonce: new Uint8Array([1, 2, 3]), - scheme: "https", - contentLength: 100, - }, - ], - }); - - await group.send(testCodec.encode({ test: "test" })); - - const messages = await group.messages(); - // read receipts and reactions are automatically filtered - expect(messages.length).toBe(13); - - // default sort order - expect(messages[0].contentType).toEqual(await contentTypeGroupUpdated()); - - // descending sort order - const sortedMessages1 = await group.messages({ - direction: SortDirection.Descending, - }); - expect(sortedMessages1[0].contentType).toEqual(testCodec.contentType); - - const filteredMessages1 = await group.messages({ - contentTypes: [ContentType.Text, ContentType.Markdown, ContentType.Reply], - }); - expect(filteredMessages1.length).toBe(3); - - const filteredMessages2 = await group.messages({ - contentTypes: [ - ContentType.Actions, - ContentType.Intent, - ContentType.TransactionReference, - ContentType.WalletSendCalls, - ], - }); - expect(filteredMessages2.length).toBe(4); - - const filteredMessages3 = await group.messages({ - contentTypes: [ - ContentType.Attachment, - ContentType.RemoteAttachment, - ContentType.MultiRemoteAttachment, - ], - }); - expect(filteredMessages3.length).toBe(3); - - const filteredMessages4 = await group.messages({ - contentTypes: [ - ContentType.GroupUpdated, - ContentType.LeaveRequest, - ContentType.Custom, - ], - }); - expect(filteredMessages4.length).toBe(3); - - const filteredMessages5 = await group.messages({ - excludeSenderInboxIds: [client2.inboxId!], - }); - expect(filteredMessages5.length).toBe(12); - - const filteredMessages6 = await group.messages({ - excludeContentTypes: [ - ContentType.Text, - ContentType.Markdown, - ContentType.Reply, - ], - }); - expect(filteredMessages6.length).toBe(10); - - const filteredMessages7 = await group.messages({ - sentAfterNs: replyMessage?.sentAtNs, - }); - // does not include reaction and read receipt messages - expect(filteredMessages7.length).toBe(7); - - const filteredMessages8 = await group.messages({ - sentBeforeNs: replyMessage?.sentAtNs, - }); - expect(filteredMessages8.length).toBe(5); - - // initial group updated message adding a member - const filteredMessages9 = await group.messages({ - kind: GroupMessageKind.MembershipChange, - }); - expect(filteredMessages9.length).toBe(1); - - await group.sendText("gm", true); - const filteredMessages10 = await group.messages({ - deliveryStatus: DeliveryStatus.Published, - }); - expect(filteredMessages10.length).toBe(13); - const filteredMessages11 = await group.messages({ - deliveryStatus: DeliveryStatus.Unpublished, - }); - expect(filteredMessages11.length).toBe(1); - }); - - it("should stream messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - await client2.conversations.sync(); - const groups = await client2.conversations.listGroups(); - expect(groups.length).toBe(1); - expect(groups[0].id).toBe(group.id); - - const streamedMessages: unknown[] = []; - const stream = await groups[0].stream({ - onValue: (message) => { - streamedMessages.push(message.content); - }, - }); - - await group.sendText("gm"); - await group.sendText("gm2"); - - setTimeout(() => { - void stream.end(); - }, 100); - - let count = 0; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - if (count === 1) { - expect(message.content).toBe("gm"); - } - if (count === 2) { - expect(message.content).toBe("gm2"); - } - } - - expect(streamedMessages).toEqual(["gm", "gm2"]); - }); - - it("should add and remove admins", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - expect(await group.isSuperAdmin(client1.inboxId!)).toBe(true); - await group.listSuperAdmins(); - expect(group.superAdmins.length).toBe(1); - expect(group.superAdmins).toContain(client1.inboxId); - expect(await group.isAdmin(client1.inboxId!)).toBe(false); - expect(await group.isAdmin(client2.inboxId!)).toBe(false); - await group.listAdmins(); - expect(group.admins.length).toBe(0); - - await group.addAdmin(client2.inboxId!); - expect(await group.isAdmin(client2.inboxId!)).toBe(true); - await group.listAdmins(); - expect(group.admins.length).toBe(1); - expect(group.admins).toContain(client2.inboxId); - - await group.removeAdmin(client2.inboxId!); - expect(await group.isAdmin(client2.inboxId!)).toBe(false); - await group.listAdmins(); - expect(group.admins.length).toBe(0); - - const messages = (await group.messages()) as DecodedMessage[]; - expect(messages.length).toBe(3); - expect(messages[1].content?.addedAdminInboxes).toHaveLength(1); - expect(messages[1].content?.addedAdminInboxes[0].inboxId).toBe( - client2.inboxId, - ); - expect(messages[2].content?.removedAdminInboxes).toHaveLength(1); - expect(messages[2].content?.removedAdminInboxes[0].inboxId).toBe( - client2.inboxId, - ); - }); - - it("should add and remove super admins", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - expect(await group.isSuperAdmin(client1.inboxId!)).toBe(true); - expect(await group.isSuperAdmin(client2.inboxId!)).toBe(false); - await group.listSuperAdmins(); - expect(group.superAdmins.length).toBe(1); - expect(group.superAdmins).toContain(client1.inboxId); - - await group.addSuperAdmin(client2.inboxId!); - expect(await group.isSuperAdmin(client2.inboxId!)).toBe(true); - await group.listSuperAdmins(); - expect(group.superAdmins.length).toBe(2); - expect(group.superAdmins).toContain(client1.inboxId); - expect(group.superAdmins).toContain(client2.inboxId); - - await group.removeSuperAdmin(client2.inboxId!); - expect(await group.isSuperAdmin(client2.inboxId!)).toBe(false); - await group.listSuperAdmins(); - expect(group.superAdmins.length).toBe(1); - expect(group.superAdmins).toContain(client1.inboxId); - - const messages = (await group.messages()) as DecodedMessage[]; - expect(messages.length).toBe(3); - expect(messages[1].content?.addedSuperAdminInboxes).toHaveLength(1); - expect(messages[1].content?.addedSuperAdminInboxes[0].inboxId).toBe( - client2.inboxId, - ); - expect(messages[2].content?.removedSuperAdminInboxes).toHaveLength(1); - expect(messages[2].content?.removedSuperAdminInboxes[0].inboxId).toBe( - client2.inboxId, - ); - }); - - it("should manage consent state", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - expect(group).toBeDefined(); - expect(await group.consentState()).toBe(ConsentState.Allowed); - - await client2.conversations.sync(); - const group2 = await client2.conversations.getConversationById(group.id); - expect(group2).toBeDefined(); - expect(await group2!.consentState()).toBe(ConsentState.Unknown); - await group2!.sendText("gm!"); - expect(await group2!.consentState()).toBe(ConsentState.Allowed); - }); - - it("should handle disappearing messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const stream = await client1.conversations.streamDeletedMessages(); - - // create message disappearing settings so that messages are deleted after 1 second - const messageDisappearingSettings: MessageDisappearingSettings = { - fromNs: 1n, - inNs: 2_000_000_000n, - }; - - // create a group with message disappearing settings - const group = await client1.conversations.createGroup([client2.inboxId!], { - messageDisappearingSettings, - }); - - // verify that the message disappearing settings are set and enabled - expect(await group.messageDisappearingSettings()).toEqual({ - fromNs: 1n, - inNs: 2_000_000_000n, - }); - expect(await group.isMessageDisappearingEnabled()).toBe(true); - - // send messages to the group - const messageId1 = await group.sendText("gm"); - const messageId2 = await group.sendText("gm2"); - - // verify that the messages are sent - expect((await group.messages()).length).toBe(3); - - // sync the messages to the other client - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - await group2.sync(); - - // verify that the message disappearing settings are set and enabled - expect(await group2.messageDisappearingSettings()).toEqual({ - fromNs: 1n, - inNs: 2_000_000_000n, - }); - expect(await group2.isMessageDisappearingEnabled()).toBe(true); - - // wait for the messages to be deleted - await sleep(2000); - - // verify that the messages are deleted - expect((await group.messages()).length).toBe(1); - - // verify that the messages are deleted on the other client - expect((await group2.messages()).length).toBe(1); - - setTimeout(() => { - void stream.end(); - }, 1000); - - let count = 0; - const messageIds: string[] = []; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - messageIds.push(message.id); - } - expect(count).toBe(2); - expect(messageIds).toContain(messageId1); - expect(messageIds).toContain(messageId2); - - // remove the message disappearing settings - await group.removeMessageDisappearingSettings(); - - // verify that the message disappearing settings are removed - expect(await group.messageDisappearingSettings()).toEqual({ - fromNs: 0n, - inNs: 0n, - }); - - expect(await group.isMessageDisappearingEnabled()).toBe(false); - - // sync other group - await group2.sync(); - - // verify that the message disappearing settings are set and disabled - expect(await group2.messageDisappearingSettings()).toEqual({ - fromNs: 0n, - inNs: 0n, - }); - expect(await group2.isMessageDisappearingEnabled()).toBe(false); - - // check for metadata field changes - const messages = await group2.messages(); - const fieldChange1 = messages[1] as DecodedMessage; - expect(fieldChange1.content?.metadataFieldChanges).toBeDefined(); - expect(fieldChange1.content?.metadataFieldChanges.length).toBe(1); - expect(fieldChange1.content?.metadataFieldChanges[0].fieldName).toBe( - await metadataFieldName(MetadataField.MessageExpirationFromNs), - ); - expect(fieldChange1.content?.metadataFieldChanges[0].oldValue).toBe("1"); - expect(fieldChange1.content?.metadataFieldChanges[0].newValue).toBe("0"); - - const fieldChange2 = messages[2] as DecodedMessage; - expect(fieldChange2.content?.metadataFieldChanges).toBeDefined(); - expect(fieldChange2.content?.metadataFieldChanges.length).toBe(1); - expect(fieldChange2.content?.metadataFieldChanges[0].fieldName).toBe( - await metadataFieldName(MetadataField.MessageExpirationInNs), - ); - expect(fieldChange2.content?.metadataFieldChanges[0].oldValue).toBe( - "2000000000", - ); - expect(fieldChange2.content?.metadataFieldChanges[0].newValue).toBe("0"); - - // send messages to the group - await group2.sendText("gm"); - await group2.sendText("gm2"); - - // verify that the messages are sent - expect((await group2.messages()).length).toBe(5); - - // sync original group - await group.sync(); - - // verify that the messages are not deleted - expect((await group.messages()).length).toBe(5); - }); - - it("should return paused for version", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createDm(client2.inboxId!); - expect(await group.pausedForVersion()).toBeUndefined(); - }); - - it("should get hmac keys", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const group = await client1.conversations.createGroup([client2.inboxId!]); - - const hmacKeys = await group.hmacKeys(); - const groupIds = Array.from(hmacKeys.keys()); - for (const groupId of groupIds) { - expect(hmacKeys.get(groupId)?.length).toBe(3); - expect(hmacKeys.get(groupId)?.[0].key).toBeDefined(); - expect(hmacKeys.get(groupId)?.[0].epoch).toBeDefined(); - expect(hmacKeys.get(groupId)?.[1].key).toBeDefined(); - expect(hmacKeys.get(groupId)?.[1].epoch).toBeDefined(); - expect(hmacKeys.get(groupId)?.[2].key).toBeDefined(); - expect(hmacKeys.get(groupId)?.[2].epoch).toBeDefined(); - } - }); - - it("should get debug info", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const debugInfo = await group.debugInfo(); - expect(debugInfo).toBeDefined(); - expect(debugInfo.epoch).toBeDefined(); - expect(debugInfo.maybeForked).toBe(false); - expect(debugInfo.forkDetails).toBe(""); - expect(debugInfo.isCommitLogForked).toBeUndefined(); - expect(debugInfo.localCommitLog).toBeDefined(); - expect(debugInfo.remoteCommitLog).toBeDefined(); - expect(debugInfo.cursor).toBeDefined(); - expect(debugInfo.cursor.length).toBeGreaterThan(0); - for (const cursor of debugInfo.cursor) { - expect(cursor.originatorId).toBeDefined(); - expect(cursor.sequenceId).toBeDefined(); - } - }); - - it("should count messages with various filters", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const group = await client1.conversations.createGroup([client2.inboxId!]); - - await group.sendText("text 1"); - await sleep(10); - const timestamp1 = BigInt(Date.now() * 1_000_000); - await sleep(10); - await group.sendText("text 2"); - await sleep(10); - const timestamp2 = BigInt(Date.now() * 1_000_000); - await sleep(10); - await group.sendText("text 3"); - - expect(await group.countMessages()).toBe(4n); - - // Time filters - expect( - await group.countMessages({ - sentBeforeNs: timestamp1, - contentTypes: [ContentType.Text], - }), - ).toBe(1n); - expect( - await group.countMessages({ - sentAfterNs: timestamp1, - }), - ).toBe(2n); - expect( - await group.countMessages({ - sentAfterNs: timestamp2, - contentTypes: [ContentType.Text], - }), - ).toBe(1n); - expect( - await group.countMessages({ - sentAfterNs: timestamp1, - sentBeforeNs: timestamp2, - }), - ).toBe(1n); - - // Content type filter - expect( - await group.countMessages({ - contentTypes: [ContentType.Text], - }), - ).toBe(3n); - }); - - it("should have pending removal state after requesting removal from the group", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - await client1.conversations.createGroup([client2.inboxId!]); - - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - - expect(await group2.isPendingRemoval()).toBe(false); - await group2.requestRemoval(); - expect(await group2.isPendingRemoval()).toBe(true); - expect(await group2.isActive()).toBe(true); - - const messages = await group2.messages(); - const leaveRequestMessage = messages[1]; - expect(leaveRequestMessage.contentType).toEqual( - await contentTypeLeaveRequest(), - ); - }); - - it("should remove a member after processing their removal request", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - - await group2.requestRemoval(); - - // messages and welcomes must be synced - await client2.conversations.syncAll(); - await client1.conversations.syncAll(); - - // wait for worker to process the removal request - await sleep(4000); - - await group2.sync(); - - expect(await group2.isActive()).toBe(false); - expect(await group2.isPendingRemoval()).toBe(true); - - expect(await group.members()).toHaveLength(1); - expect(await group2.members()).toHaveLength(1); - }); -}); diff --git a/sdks/browser-sdk/test/Opfs.test.ts b/sdks/browser-sdk/test/Opfs.test.ts deleted file mode 100644 index 04235578d..000000000 --- a/sdks/browser-sdk/test/Opfs.test.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { Opfs } from "@/Opfs"; -import { uuid } from "@/utils/uuid"; -import { createRegisteredClient, createSigner } from "./helpers"; - -describe.skip("Opfs", () => { - describe.sequential("with no files", () => { - let opfs: Opfs; - - beforeEach(async () => { - opfs = await Opfs.create(); - }); - - afterEach(() => { - opfs.close(); - }); - - it("should list files", async () => { - const files = await opfs.listFiles(); - expect(files).toHaveLength(0); - }); - - it("should get file count", async () => { - const count = await opfs.fileCount(); - expect(count).toBe(0); - }); - - it("should get pool capacity", async () => { - const capacity = await opfs.poolCapacity(); - expect(capacity).toBe(6); - }); - - it("should check if file exists", async () => { - const exists = await opfs.fileExists("test.db3"); - expect(exists).toBe(false); - }); - - it("should return false when deleting a non-existent file", async () => { - const deleted = await opfs.deleteFile("test.db3"); - expect(deleted).toBe(false); - }); - - it("should throw an error when exporting a non-existent file", async () => { - await expect(opfs.exportDb("test.db3")).rejects.toThrow(); - }); - }); - - describe.sequential("with a client database", () => { - const dbPaths: string[] = []; - - it("should list files and get file count", async () => { - const { signer } = createSigner(); - const dbPath = `./test-${uuid()}.db3`; - dbPaths.push(dbPath); - const client = await createRegisteredClient(signer, { - dbPath, - }); - client.close(); - const opfs = await Opfs.create(); - const files = await opfs.listFiles(); - const fileCount = await opfs.fileCount(); - opfs.close(); - expect(files).toHaveLength(1); - expect(files[0]).toBe(dbPath); - expect(fileCount).toBe(1); - }); - - it("should check if file exists", async () => { - const { signer } = createSigner(); - const dbPath = `./test-${uuid()}.db3`; - dbPaths.push(dbPath); - const client = await createRegisteredClient(signer, { - dbPath, - }); - client.close(); - const opfs = await Opfs.create(); - const exists = await opfs.fileExists(dbPath); - opfs.close(); - expect(exists).toBe(true); - }); - - it("should delete an existing file", async () => { - const opfs = await Opfs.create(); - const dbPath = dbPaths.pop() as string; - expect(dbPaths).toHaveLength(1); - const deleted = await opfs.deleteFile(dbPath); - opfs.close(); - expect(deleted).toBe(true); - }); - - it("should export and import an existing database", async () => { - const opfs = await Opfs.create(); - const dbPath = dbPaths.pop() as string; - expect(dbPaths).toHaveLength(0); - const exportedData = await opfs.exportDb(dbPath); - expect(exportedData).toBeDefined(); - const newDbPath = `./test-${uuid()}.db3`; - dbPaths.push(newDbPath); - await opfs.importDb(newDbPath, exportedData); - const files = await opfs.listFiles(); - expect(files).toHaveLength(2); - expect(files).toContain(dbPath); - expect(files).toContain(newDbPath); - await opfs.deleteFile(dbPath); - const exportedData2 = await opfs.exportDb(newDbPath); - expect(exportedData2).toEqual(exportedData); - opfs.close(); - }); - - it("should throw an error when importing an invalid database", async () => { - const opfs = await Opfs.create(); - const dbPath = `./test-${uuid()}.db3`; - await expect( - opfs.importDb(dbPath, new Uint8Array([1, 2, 3])), - ).rejects.toThrow(); - opfs.close(); - }); - - it("should clear all files", async () => { - const { signer } = createSigner(); - const dbPath = `./test-${uuid()}.db3`; - const existingDbPath = dbPaths.pop() as string; - expect(dbPaths).toHaveLength(0); - const client = await createRegisteredClient(signer, { - dbPath, - }); - client.close(); - const opfs = await Opfs.create(); - const files = await opfs.listFiles(); - expect(files).toHaveLength(2); - expect(files).toContain(existingDbPath); - expect(files).toContain(dbPath); - await opfs.clearAll(); - const files2 = await opfs.listFiles(); - expect(files2).toHaveLength(0); - opfs.close(); - }); - }); -}); diff --git a/sdks/browser-sdk/test/Preferences.test.ts b/sdks/browser-sdk/test/Preferences.test.ts deleted file mode 100644 index 13186d5e7..000000000 --- a/sdks/browser-sdk/test/Preferences.test.ts +++ /dev/null @@ -1,256 +0,0 @@ -import { - ConsentEntityType, - ConsentState, - type UserPreferenceUpdate, -} from "@xmtp/wasm-bindings"; -import { describe, expect, it } from "vitest"; -import { uuid } from "@/utils/uuid"; -import { - createClient, - createRegisteredClient, - createSigner, - sleep, -} from "@test/helpers"; - -describe("Preferences", () => { - it("should return the correct inbox state", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const inboxState = await client.preferences.inboxState(); - expect(inboxState.inboxId).toBe(client.inboxId); - expect(inboxState.installations.map((install) => install.id)).toEqual([ - client.installationId, - ]); - expect(inboxState.accountIdentifiers).toEqual([ - await signer.getIdentifier(), - ]); - expect(inboxState.recoveryIdentifier).toStrictEqual( - await signer.getIdentifier(), - ); - - const { signer: signer2 } = createSigner(); - const client2 = await createClient(signer2); - const inboxStates = await client2.preferences.fetchInboxStates([ - client.inboxId!, - ]); - const inboxState2 = inboxStates[0]; - expect(inboxState2.inboxId).toBe(client.inboxId); - expect(inboxState.installations.length).toBe(1); - expect(inboxState.installations[0].id).toBe(client.installationId); - expect(inboxState2.accountIdentifiers).toEqual([ - await signer.getIdentifier(), - ]); - expect(inboxState2.recoveryIdentifier).toStrictEqual( - await signer.getIdentifier(), - ); - }); - - it("should get inbox states from inbox IDs", async () => { - const { signer } = createSigner(); - const { signer: signer2 } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer2); - const inboxStates = await client.preferences.getInboxStates([ - client.inboxId!, - ]); - expect(inboxStates.length).toBe(1); - expect(inboxStates[0].inboxId).toBe(client.inboxId); - expect(inboxStates[0].accountIdentifiers).toEqual([ - await signer.getIdentifier(), - ]); - - const inboxStates2 = await client2.preferences.fetchInboxStates([ - client2.inboxId!, - ]); - expect(inboxStates2.length).toBe(1); - expect(inboxStates2[0].inboxId).toBe(client2.inboxId); - expect(inboxStates2[0].accountIdentifiers).toEqual([ - await signer2.getIdentifier(), - ]); - }); - - it("should manage consent states", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - await client2.conversations.sync(); - const group2 = await client2.conversations.getConversationById(group.id); - - expect(group2).not.toBeNull(); - - expect( - await client2.preferences.getConsentState( - ConsentEntityType.GroupId, - group2!.id, - ), - ).toBe(ConsentState.Unknown); - - await client2.preferences.setConsentStates([ - { - entityType: ConsentEntityType.GroupId, - entity: group2!.id, - state: ConsentState.Allowed, - }, - ]); - - expect( - await client2.preferences.getConsentState( - ConsentEntityType.GroupId, - group2!.id, - ), - ).toBe(ConsentState.Allowed); - - expect(await group2!.consentState()).toBe(ConsentState.Allowed); - - await group2!.updateConsentState(ConsentState.Denied); - - expect( - await client2.preferences.getConsentState( - ConsentEntityType.GroupId, - group2!.id, - ), - ).toBe(ConsentState.Denied); - }); - - it("should stream consent updates", async () => { - const { signer } = createSigner(); - const { signer: signer2 } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer2); - const group = await client.conversations.createGroup([client2.inboxId!]); - const stream = await client.preferences.streamConsent(); - - await sleep(1000); - await group.updateConsentState(ConsentState.Denied); - - await sleep(1000); - await client.preferences.setConsentStates([ - { - entity: group.id, - entityType: ConsentEntityType.GroupId, - state: ConsentState.Allowed, - }, - ]); - - await sleep(1000); - await client.preferences.setConsentStates([ - { - entity: group.id, - entityType: ConsentEntityType.GroupId, - state: ConsentState.Denied, - }, - { - entity: client2.inboxId!, - entityType: ConsentEntityType.InboxId, - state: ConsentState.Allowed, - }, - ]); - - setTimeout(() => { - void stream.end(); - }, 2000); - - let count = 0; - for await (const updates of stream) { - count++; - if (count === 1) { - expect(updates.length).toBe(1); - expect(updates[0].state).toBe(ConsentState.Denied); - expect(updates[0].entity).toBe(group.id); - expect(updates[0].entityType).toBe(ConsentEntityType.GroupId); - } else if (count === 2) { - expect(updates.length).toBe(1); - expect(updates[0].state).toBe(ConsentState.Allowed); - expect(updates[0].entity).toBe(group.id); - expect(updates[0].entityType).toBe(ConsentEntityType.GroupId); - } else if (count === 3) { - expect(updates.length).toBe(2); - expect(updates[0].state).toBe(ConsentState.Denied); - expect(updates[0].entity).toBe(group.id); - expect(updates[0].entityType).toBe(ConsentEntityType.GroupId); - expect(updates[1].state).toBe(ConsentState.Allowed); - expect(updates[1].entity).toBe(client2.inboxId); - expect(updates[1].entityType).toBe(ConsentEntityType.InboxId); - } - } - expect(count).toBe(3); - }); - - it("should stream preferences", async () => { - const { signer } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer); - const clientB = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([clientB.inboxId!]); - const stream = await client1.preferences.streamPreferences(); - - await group.updateConsentState(ConsentState.Denied); - await client1.preferences.setConsentStates([ - { - entity: clientB.inboxId!, - entityType: ConsentEntityType.InboxId, - state: ConsentState.Denied, - }, - ]); - - const client2 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - const client3 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - await client3.conversations.syncAll(); - await sleep(1000); - await client1.conversations.syncAll(); - await sleep(1000); - await client2.conversations.syncAll(); - await sleep(1000); - - setTimeout(() => { - void stream.end(); - }, 100); - - const preferences: UserPreferenceUpdate[] = []; - for await (const update of stream) { - preferences.push(...update); - } - expect(preferences.length).toBe(4); - const consentUpdate1 = preferences[0] as Extract< - UserPreferenceUpdate, - { type: "ConsentUpdate" } - >; - expect(consentUpdate1.type).toBe("ConsentUpdate"); - expect(consentUpdate1.consent).toEqual({ - entity: group.id, - entityType: ConsentEntityType.GroupId, - state: ConsentState.Denied, - }); - const consentUpdate2 = preferences[1] as Extract< - UserPreferenceUpdate, - { type: "ConsentUpdate" } - >; - expect(consentUpdate2.type).toBe("ConsentUpdate"); - expect(consentUpdate2.consent).toEqual({ - entity: clientB.inboxId!, - entityType: ConsentEntityType.InboxId, - state: ConsentState.Denied, - }); - const hmacKeyUpdate1 = preferences[2] as Extract< - UserPreferenceUpdate, - { type: "HmacKeyUpdate" } - >; - expect(hmacKeyUpdate1.type).toBe("HmacKeyUpdate"); - expect(hmacKeyUpdate1.key).toBeInstanceOf(Uint8Array); - const hmacKeyUpdate2 = preferences[3] as Extract< - UserPreferenceUpdate, - { type: "HmacKeyUpdate" } - >; - expect(hmacKeyUpdate2.type).toBe("HmacKeyUpdate"); - expect(hmacKeyUpdate2.key).toBeInstanceOf(Uint8Array); - }); -}); diff --git a/sdks/browser-sdk/test/contentTypes.test.ts b/sdks/browser-sdk/test/contentTypes.test.ts deleted file mode 100644 index bdd1ae1b6..000000000 --- a/sdks/browser-sdk/test/contentTypes.test.ts +++ /dev/null @@ -1,1368 +0,0 @@ -import { - contentTypeToString, - type ContentCodec, - type EncodedContent, -} from "@xmtp/content-type-primitives"; -import { - ActionStyle, - ReactionAction, - ReactionSchema, - type Actions, - type Attachment, - type GroupUpdated, - type Intent, - type MultiRemoteAttachment, - type Reaction, - type ReadReceipt, - type RemoteAttachment, - type TransactionReference, - type WalletSendCalls, - type Reply as XmtpReply, -} from "@xmtp/wasm-bindings"; -import { - afterEach, - beforeEach, - describe, - expect, - expectTypeOf, - it, - vi, - type Mock, -} from "vitest"; -import type { DecodedMessage } from "@/DecodedMessage"; -import type { EnrichedReply } from "@/types/options"; -import { - contentTypeActions, - contentTypeAttachment, - contentTypeGroupUpdated, - contentTypeIntent, - contentTypeMarkdown, - contentTypeMultiRemoteAttachment, - contentTypeReaction, - contentTypeReadReceipt, - contentTypeRemoteAttachment, - contentTypeReply, - contentTypeText, - contentTypeTransactionReference, - contentTypeWalletSendCalls, - decryptAttachment, - encodeAttachment, - encodeText, - encryptAttachment, -} from "@/utils/contentTypes"; -import { - isActions, - isAttachment, - isGroupUpdated, - isIntent, - isMarkdown, - isMultiRemoteAttachment, - isReaction, - isReadReceipt, - isRemoteAttachment, - isReply, - isText, - isTextReply, - isTransactionReference, - isWalletSendCalls, -} from "@/utils/messages"; -import { - createRegisteredClient, - createSigner, - DecodeFailureCodec, - TestCodec, -} from "@test/helpers"; - -describe("Content types", () => { - it("should send and receive text content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const messageId = await group.sendText("gm"); - const messages = await group.messages(); - const textMessage = messages[1]; - expect(textMessage.content).toBe("gm"); - expect(textMessage.contentType).toEqual(await contentTypeText()); - expect(textMessage.fallback).toBeUndefined(); - expect(isText(textMessage)).toBe(true); - if (isText(textMessage)) { - expectTypeOf(textMessage).toEqualTypeOf>(); - } - const message = await client1.conversations.getMessageById(messageId); - expect(message).toBeDefined(); - expect(message?.content).toBe("gm"); - expect(message?.contentType).toEqual(await contentTypeText()); - }); - - it("should send and receive markdown content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const messageId = await group.sendMarkdown("# gm"); - const messages = await group.messages(); - const markdownMessage = messages[1]; - expect(markdownMessage.content).toBe("# gm"); - expect(markdownMessage.contentType).toEqual(await contentTypeMarkdown()); - expect(markdownMessage.fallback).toBeUndefined(); - expect(isMarkdown(markdownMessage)).toBe(true); - if (isMarkdown(markdownMessage)) { - expectTypeOf(markdownMessage).toEqualTypeOf>(); - } - const message = await client1.conversations.getMessageById(messageId); - expect(message).toBeDefined(); - expect(message?.content).toBe("# gm"); - expect(message?.contentType).toEqual(await contentTypeMarkdown()); - }); - - describe("Reaction", () => { - it("should send and receive reaction content with added action", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const textMessageId = await group.sendText("Hello!"); - const reaction: Reaction = { - reference: textMessageId, - referenceInboxId: client1.inboxId!, - action: ReactionAction.Added, - content: "👍", - schema: ReactionSchema.Unicode, - }; - const reactionId = await group.sendReaction(reaction); - expect(reactionId).toBeDefined(); - const messages = await group.messages(); - const textMessage = messages[1]; - expect(textMessage.reactions.length).toBe(1); - const decodedReaction = textMessage.reactions[0]; - expect(decodedReaction.id).toBe(reactionId); - expect(decodedReaction.contentType).toEqual(await contentTypeReaction()); - expect(decodedReaction.content).toEqual(reaction); - expect(decodedReaction.senderInboxId).toBe(client1.inboxId); - expect(decodedReaction.fallback).toBe( - `Reacted with "👍" to an earlier message`, - ); - expect(isReaction(decodedReaction)).toBe(true); - if (isReaction(decodedReaction)) { - expectTypeOf(decodedReaction).toEqualTypeOf>(); - } - const message = await client1.conversations.getMessageById(reactionId); - expect(message).toBeDefined(); - expect(message?.content).toEqual(reaction); - expect(message?.contentType).toEqual(await contentTypeReaction()); - }); - - it("should send and receive reaction content with removed action", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const textMessageId = await group.sendText("Hello!"); - const reaction: Reaction = { - reference: textMessageId, - referenceInboxId: client1.inboxId!, - action: ReactionAction.Removed, - content: "👍", - schema: ReactionSchema.Unicode, - }; - const reactionId = await group.sendReaction(reaction); - const messages = await group.messages(); - const textMessage = messages[1]; - expect(textMessage.reactions.length).toBe(1); - const decodedReaction = textMessage.reactions[0]; - expect(decodedReaction.id).toBe(reactionId); - expect(decodedReaction.contentType).toEqual(await contentTypeReaction()); - expect(decodedReaction.content).toEqual(reaction); - expect(decodedReaction.senderInboxId).toBe(client1.inboxId); - expect(decodedReaction.fallback).toBe( - `Removed "👍" from an earlier message`, - ); - }); - - it("should send and receive reaction content with custom schema", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const textMessageId = await group.sendText("Hello!"); - const reaction: Reaction = { - reference: textMessageId, - referenceInboxId: client1.inboxId!, - action: ReactionAction.Added, - content: "custom_reaction", - schema: ReactionSchema.Custom, - }; - const reactionId = await group.sendReaction(reaction); - const messages = await group.messages(); - const textMessage = messages[1]; - expect(textMessage.reactions.length).toBe(1); - const decodedReaction = textMessage.reactions[0]; - expect(decodedReaction.id).toBe(reactionId); - expect(decodedReaction.contentType).toEqual(await contentTypeReaction()); - expect(decodedReaction.content).toEqual(reaction); - expect(decodedReaction.senderInboxId).toBe(client1.inboxId); - expect(decodedReaction.fallback).toBe( - `Reacted with "custom_reaction" to an earlier message`, - ); - }); - - it("should send and receive reaction content with shortcode schema", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const textMessageId = await group.sendText("Hello!"); - const reaction: Reaction = { - reference: textMessageId, - referenceInboxId: client1.inboxId!, - action: ReactionAction.Added, - content: ":grin:", - schema: ReactionSchema.Shortcode, - }; - const reactionId = await group.sendReaction(reaction); - const messages = await group.messages(); - const textMessage = messages[1]; - expect(textMessage.reactions.length).toBe(1); - const decodedReaction = textMessage.reactions[0]; - expect(decodedReaction.id).toBe(reactionId); - expect(decodedReaction.contentType).toEqual(await contentTypeReaction()); - expect(decodedReaction.content).toEqual(reaction); - expect(decodedReaction.senderInboxId).toBe(client1.inboxId); - expect(decodedReaction.fallback).toBe( - `Reacted with ":grin:" to an earlier message`, - ); - }); - }); - - describe("Reply", () => { - it("should send and receive reply with text content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - const textMessageId = await group.sendText("Original message"); - const reply: XmtpReply = { - content: await encodeText("This is a text reply"), - reference: textMessageId, - referenceInboxId: client1.inboxId!, - }; - const replyId = await group.sendReply(reply); - - const messages = await group.messages(); - const replyMessage = messages[2]; - expect(replyMessage.contentType).toEqual(await contentTypeReply()); - const replyContent = replyMessage.content as EnrichedReply; - expect(replyContent.referenceId).toBe(textMessageId); - expect(replyContent.content).toBe("This is a text reply"); - expect(await replyContent.contentType()).toEqual(await contentTypeText()); - expect(replyContent.inReplyTo).toBeDefined(); - expect(replyContent.inReplyTo?.id).toBe(textMessageId); - expect(replyContent.inReplyTo?.content).toBe("Original message"); - expect(replyMessage.fallback).toBe( - `Replied with "This is a text reply" to an earlier message`, - ); - expect(isReply(replyMessage)).toBe(true); - expect(isTextReply(replyMessage)).toBe(true); - const message = await client1.conversations.getMessageById(replyId); - expect(message).toBeDefined(); - expect(message?.contentType).toEqual(await contentTypeReply()); - const replyContent2 = message?.content as EnrichedReply; - expect(replyContent2.referenceId).toBe(textMessageId); - expect(replyContent2.content).toBe("This is a text reply"); - expect(replyContent2.inReplyTo).toBeDefined(); - expect(replyContent2.inReplyTo?.id).toBe(textMessageId); - expect(replyContent2.inReplyTo?.content).toBe("Original message"); - }); - - it("should send and receive reply with non-text content (attachment)", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - const textMessageId = await group.sendText("Original message"); - const attachment: Attachment = { - filename: "reply.png", - mimeType: "image/png", - content: new Uint8Array([1, 2, 3, 4]), - }; - const reply: XmtpReply = { - reference: textMessageId, - referenceInboxId: client1.inboxId!, - content: await encodeAttachment(attachment), - }; - await group.sendReply(reply); - - const messages = await group.messages(); - const replyMessage = messages[2]; - expect(isReply(replyMessage)).toBe(true); - expect(replyMessage.contentType).toEqual(await contentTypeReply()); - const replyContent = replyMessage.content as EnrichedReply; - expect(replyContent.referenceId).toBe(textMessageId); - expect(replyContent.content).toEqual(attachment); - expect(await replyContent.contentType()).toEqual( - await contentTypeAttachment(), - ); - expect(replyContent.inReplyTo).toBeDefined(); - expect(replyContent.inReplyTo?.id).toBe(textMessageId); - expect(replyContent.inReplyTo?.content).toBe("Original message"); - expect(replyMessage.fallback).toBe(`Replied to an earlier message`); - expect(isReply(replyMessage)).toBe(true); - expect(isTextReply(replyMessage)).toBe(false); - }); - - it("should send and receive reply with custom content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const testCodec = new TestCodec(); - const client1 = await createRegisteredClient(signer1, { - codecs: [testCodec], - }); - const client2 = await createRegisteredClient(signer2, { - codecs: [testCodec], - }); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const textMessageId = await group.sendText("Original message"); - const reply: XmtpReply = { - content: testCodec.encode({ test: "test" }), - reference: textMessageId, - referenceInboxId: client1.inboxId!, - }; - await group.sendReply(reply); - const messages = await group.messages(); - const replyMessage = messages[2]; - expect(replyMessage.contentType).toEqual(await contentTypeReply()); - const replyContent = replyMessage.content as EnrichedReply<{ - test: string; - }>; - expect(replyContent.referenceId).toBe(textMessageId); - expect(replyContent.content).toEqual({ test: "test" }); - expect(await replyContent.contentType()).toEqual(testCodec.contentType); - expect(replyContent.inReplyTo).toBeDefined(); - expect(replyContent.inReplyTo?.id).toBe(textMessageId); - expect(replyContent.inReplyTo?.content).toBe("Original message"); - expect(replyMessage.fallback).toBe(`Replied to an earlier message`); - }); - }); - - describe("Attachment", () => { - it("should send and receive attachment content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const attachment: Attachment = { - filename: "test.txt", - mimeType: "text/plain", - content: new Uint8Array([1, 2, 3]), - }; - const attachmentId = await group.sendAttachment(attachment); - const messages = await group.messages(); - const attachmentMessage = messages[1]; - expect(attachmentMessage.content).toEqual(attachment); - expect(attachmentMessage.contentType).toEqual( - await contentTypeAttachment(), - ); - expect(attachmentMessage.fallback).toBe( - `Can't display ${attachment.filename}. This app doesn't support attachments.`, - ); - expect(isAttachment(attachmentMessage)).toBe(true); - if (isAttachment(attachmentMessage)) { - expectTypeOf(attachmentMessage).toEqualTypeOf< - DecodedMessage - >(); - } - const message = await client1.conversations.getMessageById(attachmentId); - expect(message).toBeDefined(); - expect(message?.content).toEqual(attachment); - expect(message?.contentType).toEqual(await contentTypeAttachment()); - }); - - it("should send and receive attachment content without filename", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const attachment: Attachment = { - mimeType: "text/plain", - content: new Uint8Array([1, 2, 3]), - }; - await group.sendAttachment(attachment); - const messages = await group.messages(); - const attachmentMessage = messages[1]; - expect(attachmentMessage.content).toEqual(attachment); - expect(attachmentMessage.contentType).toEqual( - await contentTypeAttachment(), - ); - expect(attachmentMessage.fallback).toBe( - "Can't display this content. This app doesn't support attachments.", - ); - }); - }); - - describe("RemoteAttachment", () => { - it("should encrypt and decrypt attachment content", async () => { - const attachment: Attachment = { - filename: "test.txt", - mimeType: "text/plain", - content: new Uint8Array([1, 2, 3]), - }; - const encryptedAttachment = await encryptAttachment(attachment); - const remoteAttachment: RemoteAttachment = { - url: "https://example.com/test.txt", - contentDigest: encryptedAttachment.contentDigest, - secret: encryptedAttachment.secret, - salt: encryptedAttachment.salt, - nonce: encryptedAttachment.nonce, - scheme: "https", - contentLength: encryptedAttachment.contentLength, - filename: encryptedAttachment.filename, - }; - const decryptedAttachment = await decryptAttachment( - encryptedAttachment.payload, - remoteAttachment, - ); - expect(decryptedAttachment).toEqual(attachment); - }); - - it("should send and receive remote attachment content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const remoteAttachment: RemoteAttachment = { - url: "https://example.com/test.txt", - contentDigest: "1234567890", - secret: new Uint8Array([1, 2, 3]), - salt: new Uint8Array([4, 5, 6]), - nonce: new Uint8Array([7, 8, 9]), - scheme: "https", - contentLength: 100, - filename: "test.txt", - }; - const remoteAttachmentId = - await group.sendRemoteAttachment(remoteAttachment); - const messages = await group.messages(); - const remoteAttachmentMessage = messages[1]; - expect(remoteAttachmentMessage.content).toEqual(remoteAttachment); - expect(remoteAttachmentMessage.contentType).toEqual( - await contentTypeRemoteAttachment(), - ); - expect(remoteAttachmentMessage.fallback).toBe( - `Can't display ${remoteAttachment.filename}. This app doesn't support remote attachments.`, - ); - expect(isRemoteAttachment(remoteAttachmentMessage)).toBe(true); - if (isRemoteAttachment(remoteAttachmentMessage)) { - expectTypeOf(remoteAttachmentMessage).toEqualTypeOf< - DecodedMessage - >(); - } - const message = - await client1.conversations.getMessageById(remoteAttachmentId); - expect(message).toBeDefined(); - expect(message?.content).toEqual(remoteAttachment); - expect(message?.contentType).toEqual(await contentTypeRemoteAttachment()); - }); - - it("should send and receive remote attachment content without filename", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const remoteAttachment: RemoteAttachment = { - url: "https://example.com/test.txt", - contentDigest: "1234567890", - secret: new Uint8Array([1, 2, 3]), - salt: new Uint8Array([4, 5, 6]), - nonce: new Uint8Array([7, 8, 9]), - scheme: "https", - contentLength: 100, - }; - await group.sendRemoteAttachment(remoteAttachment); - const messages = await group.messages(); - const remoteAttachmentMessage = messages[1]; - expect(remoteAttachmentMessage.contentType).toEqual( - await contentTypeRemoteAttachment(), - ); - expect(remoteAttachmentMessage.content).toEqual(remoteAttachment); - expect(remoteAttachmentMessage.fallback).toBe( - "Can't display this content. This app doesn't support remote attachments.", - ); - }); - }); - - it("should send and receive multi remote attachment content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const multiRemoteAttachment: MultiRemoteAttachment = { - attachments: [ - { - url: "https://example.com/test.txt", - contentDigest: "sha256:1234567890", - secret: new Uint8Array([1, 2, 3]), - salt: new Uint8Array([4, 5, 6]), - nonce: new Uint8Array([7, 8, 9]), - scheme: "https", - contentLength: 100, - filename: "test.txt", - }, - { - url: "https://example.com/test2.txt", - contentDigest: "sha256:1234567891", - secret: new Uint8Array([1, 2, 3]), - salt: new Uint8Array([4, 5, 6]), - nonce: new Uint8Array([7, 8, 9]), - scheme: "https", - contentLength: 100, - filename: "test2.txt", - }, - ], - }; - await group.sendMultiRemoteAttachment(multiRemoteAttachment); - const messages = await group.messages(); - const multiRemoteAttachmentMessage = messages[1]; - expect(multiRemoteAttachmentMessage.content).toEqual(multiRemoteAttachment); - expect(multiRemoteAttachmentMessage.contentType).toEqual( - await contentTypeMultiRemoteAttachment(), - ); - expect(multiRemoteAttachmentMessage.fallback).toBe( - "Can't display this content. This app doesn't support multiple remote attachments.", - ); - expect(isMultiRemoteAttachment(multiRemoteAttachmentMessage)).toBe(true); - if (isMultiRemoteAttachment(multiRemoteAttachmentMessage)) { - expectTypeOf(multiRemoteAttachmentMessage).toEqualTypeOf< - DecodedMessage - >(); - } - }); - - it("should send read receipts and get last read times", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - await group.sendText("gm"); - const readReceiptId = await group.sendReadReceipt(); - const readTimes = await group.lastReadTimes(); - expect([...readTimes.keys()]).toContain(client1.inboxId!); - expect(readTimes.get(client1.inboxId!)).toBeTypeOf("bigint"); - const message = await client1.conversations.getMessageById(readReceiptId); - expect(message).toBeDefined(); - expect(message?.contentType).toEqual(await contentTypeReadReceipt()); - expect(message?.content).toEqual({}); - expect(isReadReceipt(message!)).toBe(true); - if (isReadReceipt(message!)) { - expectTypeOf(message).toEqualTypeOf>(); - } - await client2.conversations.syncAll(); - const group2 = (await client2.conversations.listGroups())[0]; - await group2.sendReadReceipt(); - const readTimes2 = await group2.lastReadTimes(); - expect([...readTimes2.keys()]).toContain(client1.inboxId); - expect([...readTimes2.keys()]).toContain(client2.inboxId); - }); - - describe("TransactionReference", () => { - it("should send and receive transaction reference content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const transactionReference: TransactionReference = { - namespace: "test", - networkId: "1", - reference: "1234567890", - }; - const transactionReferenceId = - await group.sendTransactionReference(transactionReference); - const messages = await group.messages(); - const transactionReferenceMessage = messages[1]; - expect(transactionReferenceMessage.content).toEqual(transactionReference); - expect(transactionReferenceMessage.contentType).toEqual( - await contentTypeTransactionReference(), - ); - expect(transactionReferenceMessage.fallback).toBe( - `[Crypto transaction] Use a blockchain explorer to learn more using the transaction hash: 1234567890`, - ); - expect(isTransactionReference(transactionReferenceMessage)).toBe(true); - if (isTransactionReference(transactionReferenceMessage)) { - expectTypeOf(transactionReferenceMessage).toEqualTypeOf< - DecodedMessage - >(); - } - const message = await client1.conversations.getMessageById( - transactionReferenceId, - ); - expect(message).toBeDefined(); - expect(message?.content).toEqual(transactionReference); - expect(message?.contentType).toEqual( - await contentTypeTransactionReference(), - ); - }); - - it("should send and receive transaction reference content without namespace", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const transactionReference: TransactionReference = { - networkId: "1", - reference: "1234567890", - }; - await group.sendTransactionReference(transactionReference); - const messages = await group.messages(); - const transactionReferenceMessage = messages[1]; - expect(transactionReferenceMessage.content).toEqual(transactionReference); - expect(transactionReferenceMessage.contentType).toEqual( - await contentTypeTransactionReference(), - ); - expect(transactionReferenceMessage.fallback).toBe( - `[Crypto transaction] Use a blockchain explorer to learn more using the transaction hash: 1234567890`, - ); - }); - - it("should send and receive transaction reference content with empty reference", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const transactionReference: TransactionReference = { - networkId: "1", - reference: "", - }; - await group.sendTransactionReference(transactionReference); - const messages = await group.messages(); - const transactionReferenceMessage = messages[1]; - expect(transactionReferenceMessage.content).toEqual(transactionReference); - expect(transactionReferenceMessage.contentType).toEqual( - await contentTypeTransactionReference(), - ); - expect(transactionReferenceMessage.fallback).toBe("Crypto transaction"); - }); - - it("should send and receive transaction reference content with metadata", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const transactionReference: TransactionReference = { - namespace: "test", - networkId: "1", - reference: "1234567890", - metadata: { - transactionType: "transfer", - currency: "USDC", - amount: 100, - decimals: 18, - fromAddress: "0x1234567890", - toAddress: "0x1234567890", - }, - }; - await group.sendTransactionReference(transactionReference); - const messages = await group.messages(); - const transactionReferenceMessage = messages[1]; - expect(transactionReferenceMessage.content).toEqual(transactionReference); - expect(transactionReferenceMessage.contentType).toEqual( - await contentTypeTransactionReference(), - ); - expect(transactionReferenceMessage.fallback).toBe( - `[Crypto transaction] Use a blockchain explorer to learn more using the transaction hash: 1234567890`, - ); - }); - }); - - describe("WalletSendCalls", () => { - it("should send and receive wallet send calls content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const walletSendCalls: WalletSendCalls = { - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - }, - ], - }; - - const walletSendCallsId = - await group.sendWalletSendCalls(walletSendCalls); - const messages = await group.messages(); - const walletSendCallsMessage = messages[1]; - expect(walletSendCallsMessage.content).toEqual(walletSendCalls); - expect(walletSendCallsMessage.contentType).toEqual( - await contentTypeWalletSendCalls(), - ); - expect(walletSendCallsMessage.fallback).toBe( - `[Transaction request generated]: ${JSON.stringify(walletSendCalls)}`, - ); - expect(isWalletSendCalls(walletSendCallsMessage)).toBe(true); - if (isWalletSendCalls(walletSendCallsMessage)) { - expectTypeOf(walletSendCallsMessage).toEqualTypeOf< - DecodedMessage - >(); - } - const message = - await client1.conversations.getMessageById(walletSendCallsId); - expect(message).toBeDefined(); - expect(message?.content).toEqual(walletSendCalls); - expect(message?.contentType).toEqual(await contentTypeWalletSendCalls()); - }); - - it("should send and receive wallet send calls content with multiple calls", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const walletSendCalls: WalletSendCalls = { - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - }, - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - }, - ], - }; - - await group.sendWalletSendCalls(walletSendCalls); - const messages = await group.messages(); - const walletSendCallsMessage = messages[1]; - expect(walletSendCallsMessage.content).toEqual(walletSendCalls); - expect(walletSendCallsMessage.contentType).toEqual( - await contentTypeWalletSendCalls(), - ); - expect(walletSendCallsMessage.fallback).toBe( - `[Transaction request generated]: ${JSON.stringify(walletSendCalls)}`, - ); - }); - - it("should send and receive wallet send calls content with metadata and capabilities", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const walletSendCalls: WalletSendCalls = { - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - metadata: { - description: "test", - transactionType: "test", - note: "test", - }, - }, - ], - capabilities: { - test: "test", - }, - }; - - await group.sendWalletSendCalls(walletSendCalls); - const messages = await group.messages(); - const walletSendCallsMessage = messages[1]; - expect(walletSendCallsMessage.content).toEqual(walletSendCalls); - expect(walletSendCallsMessage.contentType).toEqual( - await contentTypeWalletSendCalls(), - ); - expect(walletSendCallsMessage.fallback).toBe( - `[Transaction request generated]: ${JSON.stringify(walletSendCalls)}`, - ); - }); - - it("should reject when sending wallet send calls content with metadata and missing `description` field", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const walletSendCalls: WalletSendCalls = { - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - metadata: { - transactionType: "test", - }, - }, - ], - }; - - await expect(group.sendWalletSendCalls(walletSendCalls)).rejects.toThrow( - "missing field `description`", - ); - }); - - it("should reject when sending wallet send calls content with metadata and missing `transactionType` field", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - const walletSendCalls: WalletSendCalls = { - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - metadata: { - description: "test", - }, - }, - ], - }; - - await expect(group.sendWalletSendCalls(walletSendCalls)).rejects.toThrow( - "missing field `transactionType`", - ); - }); - }); - - describe("Actions", () => { - it("should send and receive actions", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - const actions: Actions = { - id: "actions-1", - description: "Choose an option", - actions: [ - { - id: "opt-1", - label: "Option 1", - style: ActionStyle.Primary, - }, - { - id: "opt-2", - label: "Option 2", - style: ActionStyle.Secondary, - }, - ], - }; - - const actionsId = await group.sendActions(actions); - - const messages = await group.messages(); - const actionsMessage = messages[1]; - expect(actionsMessage.contentType).toEqual(await contentTypeActions()); - const actionsContent = actionsMessage.content as Actions; - expect(actionsContent).toEqual(actions); - expect(actionsMessage.fallback).toBe( - `Choose an option\n\n[1] Option 1\n[2] Option 2\n\nReply with the number to select`, - ); - expect(isActions(actionsMessage)).toBe(true); - if (isActions(actionsMessage)) { - expectTypeOf(actionsMessage).toEqualTypeOf>(); - } - const message = await client1.conversations.getMessageById(actionsId); - expect(message).toBeDefined(); - expect(message?.content).toEqual(actions); - expect(message?.contentType).toEqual(await contentTypeActions()); - }); - - it("should send and receive actions with all styles", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - const actions: Actions = { - id: "action-styles", - description: "All styles", - actions: [ - { - id: "primary", - label: "Primary", - style: ActionStyle.Primary, - }, - { - id: "secondary", - label: "Secondary", - style: ActionStyle.Secondary, - }, - { - id: "danger", - label: "Danger", - style: ActionStyle.Danger, - }, - ], - }; - - await group.sendActions(actions); - - const messages = await group.messages(); - const actionsMessage = messages[1]; - expect(actionsMessage.content).toEqual(actions); - expect(actionsMessage.contentType).toEqual(await contentTypeActions()); - expect(actionsMessage.fallback).toBe( - `All styles\n\n[1] Primary\n[2] Secondary\n[3] Danger\n\nReply with the number to select`, - ); - }); - - it("should send and receive actions with expiration", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - const expiresAtNs = 1700000000000000000n; - - const actions: Actions = { - id: "expiring-actions", - description: "Expiring action", - actions: [ - { - id: "opt-1", - label: "Option 1", - style: ActionStyle.Primary, - expiresAtNs: expiresAtNs, - }, - ], - expiresAtNs: expiresAtNs, - }; - - await group.sendActions(actions); - - const messages = await group.messages(); - const actionsMessage = messages[1]; - expect(actionsMessage.content).toEqual(actions); - expect(actionsMessage.contentType).toEqual(await contentTypeActions()); - expect(actionsMessage.fallback).toBe( - `Expiring action\n\n[1] Option 1\n\nReply with the number to select`, - ); - }); - - it("should send and receive actions with image URL", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - const actions: Actions = { - id: "action-with-image", - description: "Action with image", - actions: [ - { - id: "opt-1", - label: "Option 1", - style: ActionStyle.Primary, - imageUrl: "https://example.com/image.png", - }, - ], - }; - - await group.sendActions(actions); - - const messages = await group.messages(); - const actionsMessage = messages[1]; - expect(actionsMessage.content).toEqual(actions); - expect(actionsMessage.contentType).toEqual(await contentTypeActions()); - expect(actionsMessage.fallback).toBe( - `Action with image\n\n[1] Option 1\n\nReply with the number to select`, - ); - }); - }); - - describe("Intent", () => { - it("should send and receive intent", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - const intent: Intent = { - id: "intent-1", - actionId: "opt-1", - }; - - const intentId = await group.sendIntent(intent); - - const messages = await group.messages(); - const intentMessage = messages[1]; - expect(intentMessage.contentType).toEqual(await contentTypeIntent()); - expect(intentMessage.content).toEqual(intent); - expect(intentMessage.fallback).toBe(`User selected action: opt-1`); - expect(isIntent(intentMessage)).toBe(true); - if (isIntent(intentMessage)) { - expectTypeOf(intentMessage).toEqualTypeOf>(); - } - const message = await client1.conversations.getMessageById(intentId); - expect(message).toBeDefined(); - expect(message?.content).toEqual(intent); - expect(message?.contentType).toEqual(await contentTypeIntent()); - }); - - it("should send and receive intent with metadata", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - const intent: Intent = { - id: "intent-2", - actionId: "opt-2", - metadata: { - source: "test", - timestamp: "2024-01-01", - }, - }; - - await group.sendIntent(intent); - - const messages = await group.messages(); - const intentMessage = messages[1]; - expect(intentMessage.contentType).toEqual(await contentTypeIntent()); - expect(intentMessage.content).toEqual(intent); - expect(intentMessage.fallback).toBe(`User selected action: opt-2`); - }); - }); - - it("should send and receive group updated content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - await group.updateName("test"); - await group.updateDescription("test"); - await group.updateImageUrl("test"); - await group.updateAppData("test"); - await group.addAdmin(client2.inboxId!); - await group.removeAdmin(client2.inboxId!); - await group.addSuperAdmin(client2.inboxId!); - await group.removeSuperAdmin(client2.inboxId!); - await group.removeMembers([client2.inboxId!]); - - const messages = await group.messages(); - expect(messages.length).toBe(10); - - for (const message of messages) { - expect(message.contentType).toEqual(await contentTypeGroupUpdated()); - expect(isGroupUpdated(message)).toBe(true); - if (isGroupUpdated(message)) { - expectTypeOf(message).toEqualTypeOf>(); - } - const groupUpdated = await client1.conversations.getMessageById( - message.id, - ); - expect(groupUpdated?.content).toEqual(message.content); - expect(groupUpdated?.contentType).toEqual( - await contentTypeGroupUpdated(), - ); - } - - expect(messages[0].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [{ inboxId: client2.inboxId }], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - - expect(messages[1].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [ - { fieldName: "group_name", oldValue: "", newValue: "test" }, - ], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - expect(messages[2].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [ - { fieldName: "description", oldValue: "", newValue: "test" }, - ], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - expect(messages[3].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [ - { - fieldName: "group_image_url_square", - oldValue: "", - newValue: "test", - }, - ], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - expect(messages[4].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [ - { fieldName: "app_data", oldValue: "", newValue: "test" }, - ], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - expect(messages[5].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [], - addedAdminInboxes: [{ inboxId: client2.inboxId }], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - expect(messages[6].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [], - addedAdminInboxes: [], - removedAdminInboxes: [{ inboxId: client2.inboxId }], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - expect(messages[7].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [{ inboxId: client2.inboxId }], - removedSuperAdminInboxes: [], - }); - expect(messages[8].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [{ inboxId: client2.inboxId }], - }); - expect(messages[9].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [{ inboxId: client2.inboxId }], - leftInboxes: [], - metadataFieldChanges: [], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - }); - - describe("Custom content types", () => { - let consoleWarnSpy: Mock; - - beforeEach(() => { - consoleWarnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); - }); - - afterEach(() => { - consoleWarnSpy.mockRestore(); - }); - - it("should send and receive custom content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const testCodec = new TestCodec(); - const clientWithCodec = await createRegisteredClient(signer1, { - codecs: [testCodec], - }); - const client = await createRegisteredClient(signer2); - const group = await clientWithCodec.conversations.createGroup([ - client.inboxId!, - ]); - const customContentId = await group.send( - testCodec.encode({ test: "test" }), - ); - const messages = await group.messages(); - expect(messages[1].content).toEqual({ test: "test" }); - expect(messages[1].contentType).toEqual(testCodec.contentType); - const message = - await clientWithCodec.conversations.getMessageById(customContentId); - expect(message).toBeDefined(); - expect(message?.content).toEqual({ test: "test" }); - expect(message?.contentType).toEqual(testCodec.contentType); - }); - - it("should have undefined content when receiving custom content without codec", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const testCodec = new TestCodec(); - const clientWithCodec = await createRegisteredClient(signer1, { - codecs: [testCodec], - }); - const client = await createRegisteredClient(signer2); - const group = await clientWithCodec.conversations.createGroup([ - client.inboxId!, - ]); - await group.send(testCodec.encode({ test: "test" })); - await client.conversations.sync(); - const group2 = await client.conversations.getConversationById(group.id); - expect(group2).toBeDefined(); - await group2!.sync(); - const messages = await group2!.messages(); - expect(messages[1].content).toBeUndefined(); - expect(messages[1].contentType).toEqual(testCodec.contentType); - expect(consoleWarnSpy).toHaveBeenCalledWith( - `No codec found for content type "${contentTypeToString(testCodec.contentType)}"`, - ); - }); - - it("should send and receive custom content using an object literal codec", async () => { - const { signer: signer1 } = createSigner(); - const objectCodec: ContentCodec = { - contentType: { - authorityId: "xmtp.org", - typeId: "object-test", - versionMajor: 1, - versionMinor: 0, - }, - encode(content: Record): EncodedContent { - return { - type: this.contentType, - parameters: {}, - content: new TextEncoder().encode(JSON.stringify(content)), - }; - }, - decode(content: EncodedContent): Record { - const decoded = new TextDecoder().decode(content.content); - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return JSON.parse(decoded); - }, - fallback() { - return undefined; - }, - shouldPush() { - return false; - }, - }; - const groupCreator = await createRegisteredClient(signer1, { - codecs: [objectCodec], - }); - const group = await groupCreator.conversations.createGroup([]); - const customContentId = await group.send( - objectCodec.encode({ hello: "world" }), - ); - const messages = await group.messages(); - expect(messages[0].content).toEqual({ hello: "world" }); - expect(messages[0].contentType).toEqual(objectCodec.contentType); - const message = - await groupCreator.conversations.getMessageById(customContentId); - expect(message).toBeDefined(); - expect(message?.content).toEqual({ hello: "world" }); - expect(message?.contentType).toEqual(objectCodec.contentType); - }); - - it("should have undefined content when receiving custom content with decode failure", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const decodeFailureCodec = new DecodeFailureCodec(); - const clientWithCodec = await createRegisteredClient(signer1, { - codecs: [decodeFailureCodec], - }); - const client2WithCodec = await createRegisteredClient(signer2, { - codecs: [decodeFailureCodec], - }); - const group = await clientWithCodec.conversations.createGroup([ - client2WithCodec.inboxId!, - ]); - await group.send(decodeFailureCodec.encode("test")); - await client2WithCodec.conversations.sync(); - const group2 = await client2WithCodec.conversations.getConversationById( - group.id, - ); - expect(group2).toBeDefined(); - await group2!.sync(); - const messages = await group2!.messages(); - expect(messages[1].content).toBeUndefined(); - expect(messages[1].contentType).toEqual(decodeFailureCodec.contentType); - expect(consoleWarnSpy).toHaveBeenCalledWith( - "Error decoding custom content: Decode failure", - ); - }); - }); -}); diff --git a/sdks/browser-sdk/test/createBackend.test.ts b/sdks/browser-sdk/test/createBackend.test.ts deleted file mode 100644 index 73494e34c..000000000 --- a/sdks/browser-sdk/test/createBackend.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { createBackend } from "@/utils/createBackend"; - -// Browser-sdk tests run in a browser environment (vitest + playwright). -// Unlike node-sdk, the WASM BackendBuilder methods consume `self` and -// return a new instance, so we can't easily mock them by extending. -// Instead, we test the real implementation since WASM is available in -// the browser test environment. We avoid calling `build()` on envs that -// require a network connection by only testing the configuration API. - -describe("createBackend", () => { - it("should create a backend with default options", async () => { - const backend = await createBackend(); - expect(backend).toBeDefined(); - // WASM enums are numeric at runtime: Dev = 1 - expect(backend.env).toBe(1); - }); - - it("should create a backend with production env", async () => { - const backend = await createBackend({ env: "production" }); - // WASM enums are numeric: Production = 2 - expect(backend.env).toBe(2); - }); - - it("should create a backend with local env", async () => { - const backend = await createBackend({ env: "local" }); - // WASM enums are numeric: Local = 0 - expect(backend.env).toBe(0); - }); - - it("should create a backend with appVersion", async () => { - const backend = await createBackend({ - env: "dev", - appVersion: "test/1.0.0", - }); - expect(backend).toBeDefined(); - expect(backend.appVersion).toBe("test/1.0.0"); - }); - - it("should create a backend with apiUrl override", async () => { - const backend = await createBackend({ - apiUrl: "https://custom-api.example.com:5558", - }); - expect(backend).toBeDefined(); - expect(backend.v3Host).toBe("https://custom-api.example.com:5558"); - }); - - it("should create a backend with gateway host", async () => { - const backend = await createBackend({ - env: "dev", - gatewayHost: "https://my-gateway.example.com", - }); - expect(backend).toBeDefined(); - expect(backend.gatewayHost).toBe("https://my-gateway.example.com"); - }); -}); diff --git a/sdks/browser-sdk/test/helpers.ts b/sdks/browser-sdk/test/helpers.ts deleted file mode 100644 index 914c82bdf..000000000 --- a/sdks/browser-sdk/test/helpers.ts +++ /dev/null @@ -1,161 +0,0 @@ -import type { - ContentCodec, - EncodedContent, -} from "@xmtp/content-type-primitives"; -import { type ContentTypeId, type Identifier } from "@xmtp/wasm-bindings"; -import { Client } from "@/Client"; -import type { - ContentOptions, - DeviceSyncOptions, - NetworkOptions, - OtherOptions, - StorageOptions, -} from "@/types/options"; -import { createEOASigner, type Signer } from "@/utils/signer"; - -type TestClientOptions = NetworkOptions & - DeviceSyncOptions & - ContentOptions & - StorageOptions & - OtherOptions; - -export const sleep = (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - -export const waitFor = async ( - condition: () => boolean, - { timeout = 2000, interval = 10 } = {}, -) => { - const start = Date.now(); - while (!condition()) { - if (Date.now() - start > timeout) { - throw new Error(`waitFor timed out after ${timeout}ms`); - } - await sleep(interval); - } -}; - -export const createSigner = () => { - const signer = createEOASigner(); - const identifier = signer.getIdentifier() as Identifier; - return { - address: identifier.identifier, - identifier, - signer, - }; -}; - -export const buildClient = async ( - identifier: Identifier, - options?: TestClientOptions & { - codecs?: ContentCodecs; - }, -) => { - const opts = { - ...options, - env: options?.env ?? ("local" as const), - }; - return Client.build(identifier, { - ...opts, - dbPath: opts.dbPath ?? `./test-${identifier.identifier}.db3`, - }); -}; - -export const createClient = async ( - signer: Signer, - options?: TestClientOptions & { - codecs?: ContentCodecs; - }, -) => { - const opts = { - ...options, - env: options?.env ?? ("local" as const), - }; - const identifier = await signer.getIdentifier(); - return Client.create(signer, { - ...opts, - disableAutoRegister: true, - dbPath: opts.dbPath ?? `./test-${identifier.identifier}.db3`, - }); -}; - -export const createRegisteredClient = async < - ContentCodecs extends ContentCodec[] = [], ->( - signer: Signer, - options?: TestClientOptions & { - codecs?: ContentCodecs; - }, -) => { - const opts = { - ...options, - env: options?.env ?? ("local" as const), - }; - const identifier = await signer.getIdentifier(); - return Client.create(signer, { - ...opts, - dbPath: opts.dbPath ?? `./test-${identifier.identifier}.db3`, - }); -}; - -export const ContentTypeTest: ContentTypeId = { - authorityId: "xmtp.org", - typeId: "test", - versionMajor: 1, - versionMinor: 0, -}; - -export class TestCodec implements ContentCodec { - contentType = ContentTypeTest; - - encode(content: Record): EncodedContent { - return { - type: this.contentType, - parameters: {}, - content: new TextEncoder().encode(JSON.stringify(content)), - }; - } - - decode(content: EncodedContent): Record { - const decoded = new TextDecoder().decode(content.content); - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return JSON.parse(decoded); - } - - fallback() { - return undefined; - } - - shouldPush() { - return false; - } -} - -export class DecodeFailureCodec implements ContentCodec { - contentType = { - authorityId: "test", - typeId: "decode-failure", - versionMajor: 1, - versionMinor: 0, - }; - - encode(content: string): EncodedContent { - return { - type: this.contentType, - parameters: {}, - content: new TextEncoder().encode(content), - }; - } - - decode(_content: EncodedContent): string { - throw new Error("Decode failure"); - } - - fallback() { - return undefined; - } - - shouldPush() { - return false; - } -} diff --git a/sdks/browser-sdk/test/inboxId.test.ts b/sdks/browser-sdk/test/inboxId.test.ts deleted file mode 100644 index b8e44c0ba..000000000 --- a/sdks/browser-sdk/test/inboxId.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { createBackend } from "@/utils/createBackend"; -import { generateInboxId, getInboxIdForIdentifier } from "@/utils/inboxId"; -import { createRegisteredClient, createSigner } from "@test/helpers"; - -describe("generateInboxId", () => { - it("should generate an inbox id", async () => { - const { signer } = createSigner(); - const inboxId = await generateInboxId(await signer.getIdentifier()); - expect(inboxId).toBeDefined(); - - const inboxId2 = await generateInboxId(await signer.getIdentifier(), 1n); - expect(inboxId2).toBe(inboxId); - - const inboxId3 = await generateInboxId(await signer.getIdentifier(), 2n); - expect(inboxId3).not.toBe(inboxId); - }); -}); - -describe("getInboxIdForIdentifier", () => { - it("should return `undefined` inbox ID for unregistered address", async () => { - const { identifier } = createSigner(); - const backend = await createBackend({ env: "local" }); - const inboxId = await getInboxIdForIdentifier(backend, identifier); - expect(inboxId).toBeUndefined(); - }); - - it("should return inbox ID for registered address", async () => { - const { signer, identifier } = createSigner(); - const client = await createRegisteredClient(signer); - const backend = await createBackend({ env: "local" }); - const inboxId = await getInboxIdForIdentifier(backend, identifier); - expect(inboxId).toBe(client.inboxId); - }); -}); diff --git a/sdks/browser-sdk/test/permissions.test.ts b/sdks/browser-sdk/test/permissions.test.ts deleted file mode 100644 index c4789064d..000000000 --- a/sdks/browser-sdk/test/permissions.test.ts +++ /dev/null @@ -1,695 +0,0 @@ -import { - GroupPermissionsOptions, - MetadataField, - PermissionPolicy, - PermissionUpdateType, -} from "@xmtp/wasm-bindings"; -import { describe, expect, it } from "vitest"; -import { createRegisteredClient, createSigner } from "@test/helpers"; - -describe("Group permissions", () => { - it("should create a group with default permissions", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([]); - const permissions = await group.permissions(); - expect(permissions.policyType).toBe(GroupPermissionsOptions.Default); - expect(permissions.policySet).toEqual({ - addMemberPolicy: PermissionPolicy.Allow, - removeMemberPolicy: PermissionPolicy.Admin, - addAdminPolicy: PermissionPolicy.SuperAdmin, - removeAdminPolicy: PermissionPolicy.SuperAdmin, - updateGroupNamePolicy: PermissionPolicy.Allow, - updateGroupDescriptionPolicy: PermissionPolicy.Allow, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, - updateMessageDisappearingPolicy: PermissionPolicy.Admin, - updateAppDataPolicy: PermissionPolicy.Allow, - }); - }); - - it("should create a group with admin only permissions", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([], { - permissions: GroupPermissionsOptions.AdminOnly, - }); - const permissions = await group.permissions(); - expect(permissions.policyType).toBe(GroupPermissionsOptions.AdminOnly); - expect(permissions.policySet).toEqual({ - addMemberPolicy: PermissionPolicy.Admin, - removeMemberPolicy: PermissionPolicy.Admin, - addAdminPolicy: PermissionPolicy.SuperAdmin, - removeAdminPolicy: PermissionPolicy.SuperAdmin, - updateGroupNamePolicy: PermissionPolicy.Admin, - updateGroupDescriptionPolicy: PermissionPolicy.Admin, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Admin, - updateMessageDisappearingPolicy: PermissionPolicy.Admin, - updateAppDataPolicy: PermissionPolicy.Admin, - }); - }); - - it("should create a group with custom permissions", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!], { - permissions: GroupPermissionsOptions.CustomPolicy, - customPermissionPolicySet: { - addAdminPolicy: PermissionPolicy.Deny, - addMemberPolicy: PermissionPolicy.Allow, - removeAdminPolicy: PermissionPolicy.Deny, - removeMemberPolicy: PermissionPolicy.Deny, - updateGroupNamePolicy: PermissionPolicy.Deny, - updateGroupDescriptionPolicy: PermissionPolicy.Deny, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Deny, - updateMessageDisappearingPolicy: PermissionPolicy.Admin, - updateAppDataPolicy: PermissionPolicy.Deny, - }, - }); - const permissions = await group.permissions(); - expect(permissions.policyType).toBe(GroupPermissionsOptions.CustomPolicy); - expect(permissions.policySet).toEqual({ - addAdminPolicy: PermissionPolicy.Deny, - addMemberPolicy: PermissionPolicy.Allow, - removeAdminPolicy: PermissionPolicy.Deny, - removeMemberPolicy: PermissionPolicy.Deny, - updateGroupNamePolicy: PermissionPolicy.Deny, - updateGroupDescriptionPolicy: PermissionPolicy.Deny, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Deny, - updateMessageDisappearingPolicy: PermissionPolicy.Admin, - updateAppDataPolicy: PermissionPolicy.Deny, - }); - }); - - it("should update group permissions", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId!]); - - const permissions = await group.permissions(); - expect(permissions.policySet).toEqual({ - addMemberPolicy: PermissionPolicy.Allow, - removeMemberPolicy: PermissionPolicy.Admin, - addAdminPolicy: PermissionPolicy.SuperAdmin, - removeAdminPolicy: PermissionPolicy.SuperAdmin, - updateGroupNamePolicy: PermissionPolicy.Allow, - updateGroupDescriptionPolicy: PermissionPolicy.Allow, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, - updateMessageDisappearingPolicy: PermissionPolicy.Admin, - updateAppDataPolicy: PermissionPolicy.Allow, - }); - - await group.updatePermission( - PermissionUpdateType.AddMember, - PermissionPolicy.Admin, - ); - - await group.updatePermission( - PermissionUpdateType.RemoveMember, - PermissionPolicy.SuperAdmin, - ); - - await group.updatePermission( - PermissionUpdateType.AddAdmin, - PermissionPolicy.Admin, - ); - - await group.updatePermission( - PermissionUpdateType.RemoveAdmin, - PermissionPolicy.Admin, - ); - - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.GroupName, - ); - - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.Description, - ); - - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.GroupImageUrlSquare, - ); - - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.AppData, - ); - - const permissions2 = await group.permissions(); - expect(permissions2.policySet).toEqual({ - addMemberPolicy: PermissionPolicy.Admin, - removeMemberPolicy: PermissionPolicy.SuperAdmin, - addAdminPolicy: PermissionPolicy.Admin, - removeAdminPolicy: PermissionPolicy.Admin, - updateGroupNamePolicy: PermissionPolicy.Admin, - updateGroupDescriptionPolicy: PermissionPolicy.Admin, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Admin, - updateMessageDisappearingPolicy: PermissionPolicy.Admin, - updateAppDataPolicy: PermissionPolicy.Admin, - }); - }); - - it("should enforce add member policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const { signer: signer4 } = createSigner(); - const { signer: signer5 } = createSigner(); - const { signer: signer6 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const client4 = await createRegisteredClient(signer4); - const client5 = await createRegisteredClient(signer5); - const client6 = await createRegisteredClient(signer6); - // create group with default permissions (anyone can add members) - const group = await client1.conversations.createGroup([client2.inboxId!]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - // adding a member is allowed - await group2.addMembers([client3.inboxId!]); - expect((await group2.members()).length).toBe(3); - - // update group permissions to allow only admins to add members - await group.updatePermission( - PermissionUpdateType.AddMember, - PermissionPolicy.Admin, - ); - // client2 is no longer able to add members - await expect(() => group2.addMembers([client4.inboxId!])).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId!); - // client2 is now able to add members - await group2.addMembers([client4.inboxId!]); - expect((await group2.members()).length).toBe(4); - - // update group permissions to allow only super admins to add members - await group.updatePermission( - PermissionUpdateType.AddMember, - PermissionPolicy.SuperAdmin, - ); - // client2 is no longer able to add members - await expect(() => group2.addMembers([client5.inboxId!])).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId!); - // client2 is now able to add members - await group2.addMembers([client5.inboxId!]); - expect((await group2.members()).length).toBe(5); - - // update group permissions to deny adding members - await group.updatePermission( - PermissionUpdateType.AddMember, - PermissionPolicy.Deny, - ); - // client2 is no longer able to add members - await expect(() => group2.addMembers([client6.inboxId!])).rejects.toThrow(); - - // update group permissions to allow anyone to add members - await group.updatePermission( - PermissionUpdateType.AddMember, - PermissionPolicy.Allow, - ); - // client2 is able to add members again - await group2.addMembers([client6.inboxId!]); - expect((await group2.members()).length).toBe(6); - }); - - it("should enforce remove member policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const { signer: signer4 } = createSigner(); - const { signer: signer5 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const client4 = await createRegisteredClient(signer4); - const client5 = await createRegisteredClient(signer5); - // create group with default permissions (only admins can remove members) - const group = await client1.conversations.createGroup([ - client2.inboxId!, - client3.inboxId!, - client4.inboxId!, - client5.inboxId!, - ]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - // removing a member is not allowed - await expect(() => - group2.removeMembers([client3.inboxId!]), - ).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId!); - // client2 is now able to remove members - await group2.removeMembers([client5.inboxId!]); - expect((await group2.members()).length).toBe(4); - - // update group permissions to allow only super admins to remove members - await group.updatePermission( - PermissionUpdateType.RemoveMember, - PermissionPolicy.SuperAdmin, - ); - // client2 is no longer able to remove members - await expect(() => - group2.removeMembers([client4.inboxId!]), - ).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId!); - // client2 is now able to remove members - await group2.removeMembers([client4.inboxId!]); - expect((await group2.members()).length).toBe(3); - - // update group permissions to deny removing members - await group.updatePermission( - PermissionUpdateType.RemoveMember, - PermissionPolicy.Deny, - ); - // client2 is no longer able to remove members - await expect(() => - group2.removeMembers([client3.inboxId!]), - ).rejects.toThrow(); - - // update group permissions to allow anyone to remove members - await group.updatePermission( - PermissionUpdateType.RemoveMember, - PermissionPolicy.Allow, - ); - // client2 is able to remove members again - await group2.removeMembers([client3.inboxId!]); - expect((await group2.members()).length).toBe(2); - }); - - it("should enforce add admin policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - // create group with default permissions (only super admins can add admins) - const group = await client1.conversations.createGroup([ - client2.inboxId!, - client3.inboxId!, - ]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - - // verify default permissions - only super admins can add admins - const permissions = await group.permissions(); - expect(permissions.policySet.addAdminPolicy).toBe( - PermissionPolicy.SuperAdmin, - ); - - // client2 is not a super admin, so adding an admin should fail - await expect(() => group2.addAdmin(client3.inboxId!)).rejects.toThrow(); - - // add client2 as an admin (not super admin) - await group.addAdmin(client2.inboxId!); - // client2 is still not able to add admins (requires super admin) - await expect(() => group2.addAdmin(client3.inboxId!)).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId!); - // now client2 should be able to add admins - await group2.addAdmin(client3.inboxId!); - expect(await group2.isAdmin(client3.inboxId!)).toBe(true); - }); - - it("should enforce remove admin policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - // create group with default permissions (only super admins can remove admins) - const group = await client1.conversations.createGroup([ - client2.inboxId!, - client3.inboxId!, - ]); - - // add client3 as an admin so we have an admin to remove - await group.addAdmin(client3.inboxId!); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - - // verify default permissions - only super admins can remove admins - const permissions = await group.permissions(); - expect(permissions.policySet.removeAdminPolicy).toBe( - PermissionPolicy.SuperAdmin, - ); - - // client2 is not a super admin, so removing an admin should fail - await expect(() => group2.removeAdmin(client3.inboxId!)).rejects.toThrow(); - - // add client2 as an admin (not super admin) - await group.addAdmin(client2.inboxId!); - // client2 is still not able to remove admins (requires super admin) - await expect(() => group2.removeAdmin(client3.inboxId!)).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId!); - // now client2 should be able to remove admins - await group2.removeAdmin(client3.inboxId!); - expect(await group2.isAdmin(client3.inboxId!)).toBe(false); - }); - - it("should enforce update group name policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - // create group with default permissions (anyone can update group name) - const group = await client1.conversations.createGroup([client2.inboxId!]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - // updating group name is allowed - await group2.updateName("new name 1"); - expect(group2.name).toBe("new name 1"); - - // update group permissions to allow only admins to update group name - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.GroupName, - ); - // client2 is no longer able to update group name - await expect(() => group2.updateName("new name 2")).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId!); - // client2 is now able to update group name - await group2.updateName("new name 2"); - expect(group2.name).toBe("new name 2"); - - // update group permissions to allow only super admins to update group name - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.SuperAdmin, - MetadataField.GroupName, - ); - // client2 is no longer able to update group name - await expect(() => group2.updateName("new name 3")).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId!); - // client2 is now able to update group name - await group2.updateName("new name 3"); - expect(group2.name).toBe("new name 3"); - - // update group permissions to deny updating group name - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Deny, - MetadataField.GroupName, - ); - // client2 is no longer able to update group name - await expect(() => group2.updateName("new name 4")).rejects.toThrow(); - }); - - it("should enforce update group description policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - // create group with default permissions (anyone can update group description) - const group = await client1.conversations.createGroup([client2.inboxId!]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - // updating group description is allowed - await group2.updateDescription("new description 1"); - expect(group2.description).toBe("new description 1"); - - // update group permissions to allow only admins to update group description - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.Description, - ); - // client2 is no longer able to update group description - await expect(() => - group2.updateDescription("new description 2"), - ).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId!); - // client2 is now able to update group description - await group2.updateDescription("new description 2"); - expect(group2.description).toBe("new description 2"); - - // update group permissions to allow only super admins to update group description - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.SuperAdmin, - MetadataField.Description, - ); - // client2 is no longer able to update group description - await expect(() => - group2.updateDescription("new description 3"), - ).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId!); - // client2 is now able to update group description - await group2.updateDescription("new description 3"); - expect(group2.description).toBe("new description 3"); - - // update group permissions to deny updating group description - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Deny, - MetadataField.Description, - ); - // client2 is no longer able to update group description - await expect(() => - group2.updateDescription("new description 4"), - ).rejects.toThrow(); - }); - - it("should enforce update group image url policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - // create group with default permissions (anyone can update group image url) - const group = await client1.conversations.createGroup([client2.inboxId!]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - // updating group image url is allowed - await group2.updateImageUrl("https://example.com/image1.png"); - expect(group2.imageUrl).toBe("https://example.com/image1.png"); - - // update group permissions to allow only admins to update group image url - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.GroupImageUrlSquare, - ); - // client2 is no longer able to update group image url - await expect(() => - group2.updateImageUrl("https://example.com/image2.png"), - ).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId!); - // client2 is now able to update group image url - await group2.updateImageUrl("https://example.com/image2.png"); - expect(group2.imageUrl).toBe("https://example.com/image2.png"); - - // update group permissions to allow only super admins to update group image url - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.SuperAdmin, - MetadataField.GroupImageUrlSquare, - ); - // client2 is no longer able to update group image url - await expect(() => - group2.updateImageUrl("https://example.com/image3.png"), - ).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId!); - // client2 is now able to update group image url - await group2.updateImageUrl("https://example.com/image3.png"); - expect(group2.imageUrl).toBe("https://example.com/image3.png"); - - // update group permissions to deny updating group image url - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Deny, - MetadataField.GroupImageUrlSquare, - ); - // client2 is no longer able to update group image url - await expect(() => - group2.updateImageUrl("https://example.com/image4.png"), - ).rejects.toThrow(); - }); - - it("should enforce update message disappearing policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - // create group with default permissions (only admins can update message disappearing) - const group = await client1.conversations.createGroup([client2.inboxId!]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - // updating message disappearing settings is not allowed for regular members - await expect(() => - group2.updateMessageDisappearingSettings(1n, 1_000_000_000n), - ).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId!); - // client2 is now able to update message disappearing settings - await group2.updateMessageDisappearingSettings(1n, 1_000_000_000n); - expect(await group2.isMessageDisappearingEnabled()).toBe(true); - }); - - it("should enforce update message disappearing policy with allow policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - // create group with custom permissions (anyone can update message disappearing) - const group = await client1.conversations.createGroup([client2.inboxId!], { - permissions: GroupPermissionsOptions.CustomPolicy, - customPermissionPolicySet: { - addAdminPolicy: PermissionPolicy.SuperAdmin, - addMemberPolicy: PermissionPolicy.Allow, - removeAdminPolicy: PermissionPolicy.SuperAdmin, - removeMemberPolicy: PermissionPolicy.Admin, - updateGroupNamePolicy: PermissionPolicy.Allow, - updateGroupDescriptionPolicy: PermissionPolicy.Allow, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, - updateMessageDisappearingPolicy: PermissionPolicy.Allow, - updateAppDataPolicy: PermissionPolicy.Allow, - }, - }); - - // verify permissions - const permissions = await group.permissions(); - expect(permissions.policySet.updateMessageDisappearingPolicy).toBe( - PermissionPolicy.Allow, - ); - - // updating message disappearing settings works - await group.updateMessageDisappearingSettings(1n, 1_000_000_000n); - expect(await group.isMessageDisappearingEnabled()).toBe(true); - }); - - it("should deny update message disappearing with deny policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - // create group with custom permissions (nobody can update message disappearing) - const group = await client1.conversations.createGroup([client2.inboxId!], { - permissions: GroupPermissionsOptions.CustomPolicy, - customPermissionPolicySet: { - addAdminPolicy: PermissionPolicy.SuperAdmin, - addMemberPolicy: PermissionPolicy.Allow, - removeAdminPolicy: PermissionPolicy.SuperAdmin, - removeMemberPolicy: PermissionPolicy.Admin, - updateGroupNamePolicy: PermissionPolicy.Allow, - updateGroupDescriptionPolicy: PermissionPolicy.Allow, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, - updateMessageDisappearingPolicy: PermissionPolicy.Deny, - updateAppDataPolicy: PermissionPolicy.Allow, - }, - }); - - // even super admin (client1) cannot update message disappearing settings - await expect(() => - group.updateMessageDisappearingSettings(1n, 1_000_000_000n), - ).rejects.toThrow(); - }); - - it("should enforce update app data policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - // create group with default permissions (anyone can update app data) - const group = await client1.conversations.createGroup([client2.inboxId!]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = (await client2.conversations.listGroups())[0]; - // updating app data is allowed - await group2.updateAppData("app data 1"); - expect(group2.appData).toBe("app data 1"); - - // update group permissions to allow only admins to update app data - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.AppData, - ); - // client2 is no longer able to update app data - await expect(() => group2.updateAppData("app data 2")).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId!); - // client2 is now able to update app data - await group2.updateAppData("app data 2"); - expect(group2.appData).toBe("app data 2"); - - // update group permissions to allow only super admins to update app data - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.SuperAdmin, - MetadataField.AppData, - ); - // client2 is no longer able to update app data - await expect(() => group2.updateAppData("app data 3")).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId!); - // client2 is now able to update app data - await group2.updateAppData("app data 3"); - expect(group2.appData).toBe("app data 3"); - - // update group permissions to deny updating app data - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Deny, - MetadataField.AppData, - ); - // client2 is no longer able to update app data - await expect(() => group2.updateAppData("app data 4")).rejects.toThrow(); - }); -}); diff --git a/sdks/browser-sdk/test/signer.test.ts b/sdks/browser-sdk/test/signer.test.ts deleted file mode 100644 index 95b2d4337..000000000 --- a/sdks/browser-sdk/test/signer.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { createEOASigner } from "@/utils/signer"; -import { createClient, createRegisteredClient } from "@test/helpers"; - -describe("createEOASigner", () => { - it("should create a client with the signer", async () => { - const signer = createEOASigner(); - const client = await createClient(signer); - expect(client.accountIdentifier).toEqual(signer.getIdentifier()); - expect(await client.isRegistered()).toBe(false); - expect(client.inboxId).toBeDefined(); - expect(client.installationId).toBeDefined(); - }); - - it("should register a client with the signer", async () => { - const signer = createEOASigner(); - const client = await createRegisteredClient(signer); - expect(await client.isRegistered()).toBe(true); - }); -}); diff --git a/sdks/browser-sdk/test/streams.test.ts b/sdks/browser-sdk/test/streams.test.ts deleted file mode 100644 index 9377079a1..000000000 --- a/sdks/browser-sdk/test/streams.test.ts +++ /dev/null @@ -1,773 +0,0 @@ -import { describe, expect, it, vi } from "vitest"; -import { - StreamFailedError, - StreamInvalidRetryAttemptsError, -} from "@/utils/errors"; -import { - createStream, - DEFAULT_RETRY_ATTEMPTS, - DEFAULT_RETRY_DELAY, - type StreamCallback, - type StreamFunction, -} from "@/utils/streams"; -import { sleep, waitFor } from "@test/helpers"; - -describe("createStream", () => { - describe("basic functionality", () => { - it("should create a stream and emit values", async () => { - const values: number[] = []; - const onValueSpy = vi.fn<(value: number) => void>(); - - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callback(null, 1); - callback(null, 2); - callback(null, 3); - return Promise.resolve(() => {}); - }, - ); - - const stream = await createStream(mockStreamFunction, undefined, { - onValue: onValueSpy, - }); - - // Collect values - setTimeout(() => { - void stream.end(); - }, 50); - - for await (const value of stream) { - values.push(value); - } - - expect(values).toEqual([1, 2, 3]); - expect(onValueSpy).toHaveBeenCalledTimes(3); - expect(onValueSpy).toHaveBeenCalledWith(1); - expect(onValueSpy).toHaveBeenCalledWith(2); - expect(onValueSpy).toHaveBeenCalledWith(3); - }); - - it("should ignore undefined values", async () => { - const values: number[] = []; - const onValueSpy = vi.fn<(value: number) => void>(); - - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callback(null, 1); - callback(null, undefined); - callback(null, 2); - return Promise.resolve(() => {}); - }, - ); - - const stream = await createStream(mockStreamFunction, undefined, { - onValue: onValueSpy, - }); - - setTimeout(() => { - void stream.end(); - }, 50); - - for await (const value of stream) { - values.push(value); - } - - expect(values).toEqual([1, 2]); - expect(onValueSpy).toHaveBeenCalledTimes(2); - }); - - it("should call onEnd when stream ends", async () => { - const onEndSpy = vi.fn(); - - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callback(null, 1); - return Promise.resolve(() => {}); - }, - ); - - const stream = await createStream(mockStreamFunction, undefined, { - onEnd: onEndSpy, - }); - - await stream.end(); - - expect(onEndSpy).toHaveBeenCalledTimes(1); - }); - - it("should call streamCloser when stream ends", async () => { - const streamCloserSpy = vi.fn(); - - const mockStreamFunction: StreamFunction = vi.fn(async () => { - return Promise.resolve(streamCloserSpy); - }); - - const stream = await createStream(mockStreamFunction); - - await stream.end(); - - expect(streamCloserSpy).toHaveBeenCalledTimes(1); - }); - - it("should work with default options", async () => { - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callback(null, 42); - return Promise.resolve(() => {}); - }, - ); - - const stream = await createStream(mockStreamFunction); - - setTimeout(() => { - void stream.end(); - }, 50); - - const values: number[] = []; - for await (const value of stream) { - values.push(value); - } - - expect(values).toEqual([42]); - }); - }); - - describe("stream value mutators", () => { - it("should apply sync mutator to values", async () => { - const onValueSpy = vi.fn<(value: number) => void>(); - - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callback(null, 5); - return Promise.resolve(() => {}); - }, - ); - - const mutator = (value: number) => value * 2; - - const stream = await createStream(mockStreamFunction, mutator, { - onValue: onValueSpy, - }); - - setTimeout(() => { - void stream.end(); - }, 50); - - const values: number[] = []; - for await (const value of stream) { - values.push(value); - } - - expect(values).toEqual([10]); - expect(onValueSpy).toHaveBeenCalledWith(10); - }); - - it("should apply async mutator to values", async () => { - const onValueSpy = vi.fn<(value: number) => void>(); - - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callback(null, 5); - return Promise.resolve(() => {}); - }, - ); - - const asyncMutator = async (value: number) => { - await sleep(10); - return value * 3; - }; - - const stream = await createStream(mockStreamFunction, asyncMutator, { - onValue: onValueSpy, - }); - - setTimeout(() => { - void stream.end(); - }, 100); - - const values: number[] = []; - for await (const value of stream) { - values.push(value); - } - - expect(values).toEqual([15]); - expect(onValueSpy).toHaveBeenCalledWith(15); - }); - - it("should call onError when sync mutator throws", async () => { - const onErrorSpy = vi.fn<(error: Error) => void>(); - const mutatorError = new Error("Mutator error"); - - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callback(null, 5); - return Promise.resolve(() => {}); - }, - ); - - const throwingMutator = (): number => { - throw mutatorError; - }; - - const stream = await createStream(mockStreamFunction, throwingMutator, { - onError: onErrorSpy, - }); - - await sleep(50); - await stream.end(); - - expect(onErrorSpy).toHaveBeenCalledWith(mutatorError); - }); - - it("should call onError when async mutator rejects", async () => { - const onErrorSpy = vi.fn<(error: Error) => void>(); - const mutatorError = new Error("Async mutator error"); - - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callback(null, 5); - return Promise.resolve(() => {}); - }, - ); - - const rejectingMutator = async (): Promise => { - await sleep(10); - throw mutatorError; - }; - - const stream = await createStream(mockStreamFunction, rejectingMutator, { - onError: onErrorSpy, - }); - - await sleep(100); - await stream.end(); - - expect(onErrorSpy).toHaveBeenCalledWith(mutatorError); - }); - }); - - describe("error handling", () => { - it("should call onError when stream callback receives an error", async () => { - const onErrorSpy = vi.fn<(error: Error) => void>(); - const streamError = new Error("Stream error"); - - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callback(streamError, undefined); - return Promise.resolve(() => {}); - }, - ); - - const stream = await createStream(mockStreamFunction, undefined, { - onError: onErrorSpy, - }); - - await sleep(50); - await stream.end(); - - expect(onErrorSpy).toHaveBeenCalledWith(streamError); - }); - - it("should throw StreamInvalidRetryAttemptsError when retryAttempts < 0 and retryOnFail is true", async () => { - const mockStreamFunction: StreamFunction = vi.fn(async () => { - return Promise.resolve(() => {}); - }); - - await expect( - createStream(mockStreamFunction, undefined, { - retryAttempts: -1, - retryOnFail: true, - }), - ).rejects.toThrow(StreamInvalidRetryAttemptsError); - }); - - it("should not throw when retryAttempts < 0 and retryOnFail is false", async () => { - const mockStreamFunction: StreamFunction = vi.fn(async () => { - return Promise.resolve(() => {}); - }); - - const stream = await createStream(mockStreamFunction, undefined, { - retryAttempts: -1, - retryOnFail: false, - }); - - await stream.end(); - }); - }); - - describe("stream failure without retry", () => { - it("should call onFail when stream fails and retryOnFail is false", async () => { - const onFailSpy = vi.fn<() => void>(); - - const mockStreamFunction: StreamFunction = vi.fn( - async (_, onFail: () => void) => { - // Call onFail synchronously so the throw is caught - onFail(); - return Promise.resolve(() => {}); - }, - ); - - // When retryOnFail is false, StreamFailedError is thrown - await expect( - createStream(mockStreamFunction, undefined, { - onFail: onFailSpy, - retryOnFail: false, - }), - ).rejects.toThrow(StreamFailedError); - - expect(onFailSpy).toHaveBeenCalledTimes(1); - }); - - it("should throw StreamFailedError with 0 retries when retryOnFail is false", async () => { - const mockStreamFunction: StreamFunction = vi.fn( - async (_, onFail: () => void) => { - onFail(); - return Promise.resolve(() => {}); - }, - ); - - try { - await createStream(mockStreamFunction, undefined, { - retryOnFail: false, - }); - expect.fail("Should have thrown"); - } catch (error) { - expect(error).toBeInstanceOf(StreamFailedError); - expect((error as Error).message).toBe("Stream failed, retried 0 times"); - } - }); - - it("should throw StreamFailedError with singular 'time' when retryAttempts is 1", async () => { - const onErrorSpy = vi.fn<(error: Error) => void>(); - - const mockStreamFunction: StreamFunction = vi.fn(async () => { - throw new Error("Always fails"); - return Promise.resolve(() => {}); - }); - - const stream = await createStream(mockStreamFunction, undefined, { - onError: onErrorSpy, - retryOnFail: true, - retryDelay: 10, - retryAttempts: 1, - }); - - await sleep(100); - await stream.end(); - - // Find the StreamFailedError - const streamFailedError = onErrorSpy.mock.calls - .map((call) => call[0]) - .find((e) => e instanceof StreamFailedError); - - expect(streamFailedError).toBeDefined(); - expect(streamFailedError!.message).toBe("Stream failed, retried 1 time"); - }); - }); - - describe("stream failure with retry", () => { - it("should call onFail when stream fails", async () => { - const onFailSpy = vi.fn<() => void>(); - let callCount = 0; - - const mockStreamFunction: StreamFunction = vi.fn( - async (_, onFail: () => void) => { - callCount++; - if (callCount === 1) { - setTimeout(() => { - onFail(); - }, 0); - } - return Promise.resolve(() => {}); - }, - ); - - const stream = await createStream(mockStreamFunction, undefined, { - onFail: onFailSpy, - retryOnFail: true, - retryDelay: 10, - retryAttempts: 1, - }); - - await sleep(100); - await stream.end(); - - expect(onFailSpy).toHaveBeenCalled(); - }); - - it("should call onRetry when retrying", async () => { - const onRetrySpy = - vi.fn<(attempts: number, maxAttempts: number) => void>(); - let callCount = 0; - - const mockStreamFunction: StreamFunction = vi.fn(async () => { - callCount++; - if (callCount === 1) { - throw new Error("Initial failure"); - } - return Promise.resolve(() => {}); - }); - - const stream = await createStream(mockStreamFunction, undefined, { - onRetry: onRetrySpy, - retryOnFail: true, - retryDelay: 10, - retryAttempts: 3, - }); - - await sleep(100); - await stream.end(); - - // onRetry should be called with (currentAttempt, maxAttempts) - expect(onRetrySpy).toHaveBeenCalledWith(1, 3); - }); - - it("should call onRestart when stream restarts successfully", async () => { - const onRestartSpy = vi.fn<() => void>(); - let callCount = 0; - - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callCount++; - if (callCount === 1) { - throw new Error("Initial failure"); - } - callback(null, 42); - return Promise.resolve(() => {}); - }, - ); - - const stream = await createStream(mockStreamFunction, undefined, { - onRestart: onRestartSpy, - retryOnFail: true, - retryDelay: 10, - retryAttempts: 3, - }); - - await sleep(100); - await stream.end(); - - expect(onRestartSpy).toHaveBeenCalledTimes(1); - }); - - it("should fail after max retry attempts with StreamFailedError", async () => { - const onErrorSpy = vi.fn<(error: Error) => void>(); - - // This mock always throws, simulating a stream that always fails - const mockStreamFunction: StreamFunction = vi.fn(async () => { - throw new Error("Always fails"); - return Promise.resolve(() => {}); - }); - - const stream = await createStream(mockStreamFunction, undefined, { - onError: onErrorSpy, - retryOnFail: true, - retryDelay: 10, - retryAttempts: 2, - }); - - await sleep(200); - await stream.end(); - - // Should have received StreamFailedError at the end - const errors = onErrorSpy.mock.calls.map((call) => call[0]); - const streamFailedErrors = errors.filter( - (e) => e instanceof StreamFailedError, - ); - expect(streamFailedErrors.length).toBeGreaterThan(0); - expect(streamFailedErrors[0].message).toBe( - "Stream failed, retried 2 times", - ); - }); - - it("should use custom retryDelay", async () => { - const onRetrySpy = - vi.fn<(attempts: number, maxAttempts: number) => void>(); - const startTime = Date.now(); - - let callCount = 0; - const mockStreamFunction: StreamFunction = vi.fn(async () => { - callCount++; - if (callCount === 1) { - throw new Error("Initial failure"); - } - return Promise.resolve(() => {}); - }); - - const stream = await createStream(mockStreamFunction, undefined, { - onRetry: onRetrySpy, - retryOnFail: true, - retryDelay: 50, - retryAttempts: 1, - }); - - await sleep(200); - await stream.end(); - - const elapsed = Date.now() - startTime; - // Retry should happen after approximately 50ms - expect(elapsed).toBeGreaterThanOrEqual(40); - expect(onRetrySpy).toHaveBeenCalled(); - }); - - it("should use default retry values", () => { - expect(DEFAULT_RETRY_ATTEMPTS).toBe(6); - expect(DEFAULT_RETRY_DELAY).toBe(10000); - }); - }); - - describe("initial stream function failure", () => { - it("should retry when streamFunction throws initially", async () => { - const onErrorSpy = vi.fn<(error: Error) => void>(); - const onRetrySpy = - vi.fn<(attempts: number, maxAttempts: number) => void>(); - let callCount = 0; - - const mockStreamFunction: StreamFunction = vi.fn(async () => { - callCount++; - if (callCount === 1) { - throw new Error("Initial failure"); - } - return Promise.resolve(() => {}); - }); - - const stream = await createStream(mockStreamFunction, undefined, { - onError: onErrorSpy, - onRetry: onRetrySpy, - retryOnFail: true, - retryDelay: 10, - retryAttempts: 3, - }); - - await sleep(100); - await stream.end(); - - expect(onErrorSpy).toHaveBeenCalledWith(new Error("Initial failure")); - expect(onRetrySpy).toHaveBeenCalled(); - }); - - it("should throw StreamFailedError when initial failure and retryOnFail is false", async () => { - const onErrorSpy = vi.fn<(error: Error) => void>(); - - const mockStreamFunction: StreamFunction = vi.fn(async () => { - throw new Error("Initial failure"); - return Promise.resolve(() => {}); - }); - - try { - await createStream(mockStreamFunction, undefined, { - onError: onErrorSpy, - retryOnFail: false, - }); - expect.fail("Should have thrown"); - } catch (error) { - // The StreamFailedError is thrown - expect(error).toBeInstanceOf(StreamFailedError); - } - - // onError is called with the initial error - expect(onErrorSpy).toHaveBeenCalledWith(new Error("Initial failure")); - }); - }); - - describe("retry during retry", () => { - it("should call onFail during retry when stream fails again via onFail callback", async () => { - const onFailSpy = vi.fn<() => void>(); - let callCount = 0; - - const mockStreamFunction: StreamFunction = vi.fn( - async (_, onFail: () => void) => { - callCount++; - if (callCount === 1) { - // First call fails immediately via throw - throw new Error("Initial failure"); - } - if (callCount === 2) { - // Second call (retry) fails via onFail callback - setTimeout(() => { - onFail(); - }, 0); - } - return Promise.resolve(() => {}); - }, - ); - - const stream = await createStream(mockStreamFunction, undefined, { - onFail: onFailSpy, - retryOnFail: true, - retryDelay: 10, - retryAttempts: 3, - }); - - await sleep(200); - await stream.end(); - - // onFail should be called when the stream fails via the onFail callback - expect(onFailSpy).toHaveBeenCalled(); - }); - - it("should call onEnd and streamCloser after successful retry", async () => { - const onEndSpy = vi.fn<() => void>(); - const streamCloserSpy = vi.fn(); - let callCount = 0; - - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callCount++; - if (callCount === 1) { - throw new Error("Initial failure"); - } - // Successful on retry - callback(null, 42); - return Promise.resolve(streamCloserSpy); - }, - ); - - const stream = await createStream(mockStreamFunction, undefined, { - onEnd: onEndSpy, - retryOnFail: true, - retryDelay: 10, - retryAttempts: 3, - }); - - await sleep(100); - await stream.end(); - - expect(streamCloserSpy).toHaveBeenCalledTimes(1); - expect(onEndSpy).toHaveBeenCalledTimes(1); - }); - }); - - describe("retry function error handling", () => { - it("should call onRetry with correct attempt numbers when streamFunction throws", async () => { - const onErrorSpy = vi.fn<(error: Error) => void>(); - const onRetrySpy = - vi.fn<(attempts: number, maxAttempts: number) => void>(); - - // Mock that always throws - const mockStreamFunction: StreamFunction = vi.fn(async () => { - throw new Error("Always fails"); - return Promise.resolve(() => {}); - }); - - const stream = await createStream(mockStreamFunction, undefined, { - onError: onErrorSpy, - onRetry: onRetrySpy, - retryOnFail: true, - retryDelay: 10, - retryAttempts: 3, - }); - - // Wait for all retries to complete instead of using a fixed sleep - await waitFor(() => onRetrySpy.mock.calls.length >= 3); - await stream.end(); - - // onRetry should be called with (currentAttempt, maxAttempts) - expect(onRetrySpy).toHaveBeenCalledWith(1, 3); - expect(onRetrySpy).toHaveBeenCalledWith(2, 3); - expect(onRetrySpy).toHaveBeenCalledWith(3, 3); - - // Should have received StreamFailedError - const errors = onErrorSpy.mock.calls.map((call) => call[0]); - const streamFailedErrors = errors.filter( - (e) => e instanceof StreamFailedError, - ); - expect(streamFailedErrors.length).toBeGreaterThan(0); - }); - - it("should call onError for each failed retry attempt", async () => { - const onErrorSpy = vi.fn<(error: Error) => void>(); - - const mockStreamFunction: StreamFunction = vi.fn(async () => { - throw new Error("Always fails"); - return Promise.resolve(() => {}); - }); - - const stream = await createStream(mockStreamFunction, undefined, { - onError: onErrorSpy, - retryOnFail: true, - retryDelay: 10, - retryAttempts: 2, - }); - - // Wait for retries to exhaust and StreamFailedError to be reported - await waitFor(() => onErrorSpy.mock.calls.length > 1); - await stream.end(); - - // onError should be called multiple times - // Initial error + errors during retries + StreamFailedError - expect(onErrorSpy.mock.calls.length).toBeGreaterThan(1); - }); - }); - - describe("edge cases", () => { - it("should handle retryAttempts of 0", async () => { - const onErrorSpy = vi.fn<(error: Error) => void>(); - - const mockStreamFunction: StreamFunction = vi.fn(async () => { - throw new Error("Initial failure"); - return Promise.resolve(() => {}); - }); - - const stream = await createStream(mockStreamFunction, undefined, { - onError: onErrorSpy, - retryOnFail: true, - retryDelay: 10, - retryAttempts: 0, - }); - - await sleep(100); - await stream.end(); - - // With 0 retry attempts, it should fail immediately - const errors = onErrorSpy.mock.calls.map((call) => call[0]); - const streamFailedErrors = errors.filter( - (e) => e instanceof StreamFailedError, - ); - expect(streamFailedErrors.length).toBeGreaterThan(0); - }); - - it("should handle no options provided", async () => { - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callback(null, 1); - return Promise.resolve(() => {}); - }, - ); - - // Call without options - const stream = await createStream(mockStreamFunction); - - setTimeout(() => { - void stream.end(); - }, 50); - - const values: number[] = []; - for await (const value of stream) { - values.push(value); - } - - expect(values).toEqual([1]); - }); - - it("should handle no mutator with onValue callback", async () => { - const onValueSpy = vi.fn<(value: string) => void>(); - - const mockStreamFunction: StreamFunction = vi.fn( - async (callback: StreamCallback) => { - callback(null, "test"); - return Promise.resolve(() => {}); - }, - ); - - const stream = await createStream(mockStreamFunction, undefined, { - onValue: onValueSpy, - }); - - await sleep(50); - await stream.end(); - - expect(onValueSpy).toHaveBeenCalledWith("test"); - }); - }); -}); diff --git a/sdks/browser-sdk/tsconfig.json b/sdks/browser-sdk/tsconfig.json deleted file mode 100644 index 14ab24977..000000000 --- a/sdks/browser-sdk/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "module": "ESNext", - "moduleResolution": "bundler", - "noEmit": true, - "paths": { - "@/*": ["./src/*"], - "@test/*": ["./test/*"] - }, - "preserveConstEnums": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "target": "ESNext", - "types": ["vitest/globals"] - }, - "include": ["src", "test", "vite.config.ts", "rollup.config.js"] -} diff --git a/sdks/browser-sdk/typedoc.json b/sdks/browser-sdk/typedoc.json deleted file mode 100644 index accbb58d3..000000000 --- a/sdks/browser-sdk/typedoc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["src/index.ts"], - "out": "docs", - "excludeExternals": true, - "excludePrivate": true, - "excludeProtected": true -} diff --git a/sdks/browser-sdk/vite.config.ts b/sdks/browser-sdk/vite.config.ts deleted file mode 100644 index fe4943780..000000000 --- a/sdks/browser-sdk/vite.config.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { playwright } from "@vitest/browser-playwright"; -import { defineConfig, mergeConfig } from "vite"; -import tsconfigPaths from "vite-tsconfig-paths"; -import { defineConfig as defineVitestConfig } from "vitest/config"; - -// https://vitejs.dev/config/ -const viteConfig = defineConfig({ - plugins: [tsconfigPaths()], -}); - -const vitestConfig = defineVitestConfig({ - optimizeDeps: { - exclude: ["@xmtp/wasm-bindings"], - }, - test: { - browser: { - provider: playwright(), - enabled: true, - headless: true, - screenshotFailures: false, - instances: [ - { - browser: "chromium", - }, - ], - }, - testTimeout: 120000, - }, -}); - -export default mergeConfig(viteConfig, vitestConfig); diff --git a/sdks/node-sdk/.gitignore b/sdks/node-sdk/.gitignore deleted file mode 100644 index 73d74c7bb..000000000 --- a/sdks/node-sdk/.gitignore +++ /dev/null @@ -1 +0,0 @@ -scripts/accounts.json diff --git a/sdks/node-sdk/CHANGELOG.md b/sdks/node-sdk/CHANGELOG.md deleted file mode 100644 index e3359a8de..000000000 --- a/sdks/node-sdk/CHANGELOG.md +++ /dev/null @@ -1,1852 +0,0 @@ -# @xmtp/node-sdk - -## 6.0.0 - -This release includes a performance fix, a breaking change to history sync, and new methods for manual archive management. Update as soon as possible to take advantage of these enhancements and fixes. - -### Performance improvement - -Fixed a performance issue that could cause slowdowns in apps with many conversations or heavy use of disappearing messages. - -### History sync is now manual - -**THIS IS A BREAKING CHANGE.** - -Automatic sending of sync requests on new installations has been removed. XMTP SDKs no longer automatically send sync requests on new clients. - -This change gives you explicit control over when sync requests are sent, avoiding unexpected network activity during client initialization. - -You must now call `sendSyncRequest()` explicitly after creating a client on a new installation to trigger a history sync. - -To learn more, see [Control history sync](https://docs.xmtp.org/chat-apps/list-stream-sync/history-sync#control-history-sync) - -### Manual history sync archive management - -These methods give you fine-grained control over history sync archives. Use them when you need to push data to a new installation proactively, inspect what's available before syncing, or process a specific archive by pin. - -- `sendSyncArchive(pin, options?, serverUrl?)`: Send an archive to the sync group without waiting for a request from another installation - -- `listAvailableArchives(daysCutoff)`: List archives available for import from the sync group - -- `processSyncArchive(archivePin?)`: Process an available archive from the sync group - -- `syncAllDeviceSyncGroups()`: Sync all device sync groups from the network - -To learn more, see [Control history sync](https://docs.xmtp.org/chat-apps/list-stream-sync/history-sync#control-history-sync) - -### Upcoming deprecation of `preferences.sync()` - -In a future release, `preferences.sync()` will be deprecated. Use `syncAllDeviceSyncGroups()` instead to sync device sync groups from the network. - -To learn more, see [Sync device sync groups](https://docs.xmtp.org/chat-apps/list-stream-sync/history-sync#sync-device-sync-groups) - -### Archive-based backups - -Support archive-based backups to give your users an easy and durable way to back up their XMTP conversations, messages, and consent preferences from one app installation and import them into another. - -This feature includes three core methods: - -- `createArchive` — Create an encrypted archive -- `archiveMetadata` — Read metadata from an archive before importing -- `importArchive` — Import an archive into the current installation - -To learn more, see [Support archive-based backups.](https://docs.xmtp.org/chat-apps/list-stream-sync/archive-backups#1-create-the-archive) - -## 5.5.0 - -### Minor Changes - -- Added `processStreamedMessage` method to `Conversation` for decoding, decrypting, and persisting raw envelope bytes from a group message stream - -## 5.4.0 - -### Minor Changes - -- Added `topic` property to `Conversations` for subscribing to incoming welcomes -- Added `topic` property to `Conversation` for subscribing to incoming messages - -## 5.3.0 - -Added `contentType` field to enriched replies. - -```ts -type EnrichedReply = { - referenceId: string; - content: T; - contentType: ContentTypeId | undefined; - inReplyTo: DecodedMessage | null; -}; -``` - -Use this new field to get the content type of a reply's content. - -```ts -import { encodeText, contentTypeText } from "@xmtp/node-sdk"; - -const textMessageId = await group.sendText("hi"); -const replyMessageId = await group.sendReply({ - content: encodeText("hello"), - reference: textMessageId, -}); -const reply: DecodedMessage = - client.conversations.getMessageById(replyMessageId); - -// access reply's content type -expect(reply.content.contentType).toEqual(contentTypeText()); -``` - -## 5.2.0 - -This release introduces new features and critical bug fixes. If you've been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of these enhancements and fixes. - -### Message type guards - -New utility functions have been added to help identify message content types. These type guards provide a convenient way to check message types and narrow TypeScript types when working with decoded messages. - -```ts -import { - isText, - isMarkdown, - isReaction, - isReply, - isTextReply, - isAttachment, - isRemoteAttachment, - isMultiRemoteAttachment, - isTransactionReference, - isReadReceipt, - isGroupUpdated, - isWalletSendCalls, - isActions, - isIntent, -} from "@xmtp/node-sdk"; - -const messages = await group.messages(); - -for (const message of messages) { - if (isText(message)) { - // message.content is narrowed to string - console.log(message.content); - } - - if (isReaction(message)) { - // message.content is narrowed to Reaction - console.log(message.content.content); - } - - if (isTextReply(message)) { - // message.content is narrowed to EnrichedReply - console.log(message.content.content); - } -} -``` - -### Stream deleted messages - -The `streamMessageDeletions` method has been deprecated and will be removed in a future release. Use the new `streamDeletedMessages` method. This new method streams the entire decoded message of deleted messages rather than just the message ID. - -```ts -const deletedMessagesStream = - await client.conversations.streamDeletedMessages(); - -for await (const message of deletedMessagesStream) { - // message is a DecodedMessage -} -``` - -### Improved streaming method types - -The return types of `streamAllMessages`, `streamAllGroupMessages`, `streamAllDmMessages`, and `stream` (for conversations) have been simplified. These methods now return only converted values (`DecodedMessage` or `Group`/`Dm`) instead of a union type that could include raw or undefined values. - -Previously, when a streamed value couldn't be converted, the raw value or `undefined` was returned. Now, unconvertible values are filtered out with a warning logged to the console. This makes the stream output more predictable and type-safe. - -### Actions and intent content type serialization - -The actions and intent content types were not being serialized properly. This release ensures that these content types are backwards-compatible with all clients using these content types. - -## 5.1.1 - -### Patch Changes - -- d629632: Defaulted to an `undefined` gateway host when an empty string was provided - -## 5.1.0 - -This release introduces a new feature. If you've been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of this new feature. - -### Send sync requests - -When a device installation comes online, it automatically sends a request to other devices on the network to sync conversations and messages. In some cases, this process may be interrupted. To remedy this, it's now possible to re-request a sync. - -```ts -// send a sync request -await client.sendSyncRequest(); -``` - -## 5.0.1 - -Fixed reply content type exports - -## 5.0.0 - -This release introduces breaking changes and new features. If you've been building on a previous release, updating your app to use this release will require changes to your existing code. - -### BREAKING CHANGES - -#### Removed features - -- Removed `uploadDebugArchive` method from `Client.DebugInformation` -- Removed `debugEventsEnabled` client option -- Removed deprecated `Client.version` static property (use `Client.libxmtpVersion` instead) -- Removed `Conversation.sendOptimistic` method (use dedicated send methods with the `optimistic` parameter instead) -- Removed `codecFor`, `encodeContent`, `decodeContent`, and `prepareForSend` client methods (content encoding is now handled by dedicated send methods) -- Removed `Conversation.isCommitLogForked` property -- Removed `DecodedMessage.compression` property -- Removed `DecodedMessage.parameters` property -- Removed `MessageKind` and `MessageDeliveryStatus` type exports (use `GroupMessageKind` and `DeliveryStatus` enums instead) - -#### Updated types - -- `DecodedMessage.sentAtNs` is now `bigint` -- `DecodedMessage.kind` and `DecodedMessage.deliveryStatus` fields now use enum values instead of strings -- `DecodedMessage.contentType` is no longer optional -- Message disappearing settings are now `bigint` -- `LogLevel` enum variant casing changed (e.g., `LogLevel.off` → `LogLevel.Off`) -- Conversation type value is now an enum in metadata - -```ts -// DecodedMessage.sentAtNs is now bigint - -// OLD -const sentAtNs: number = message.sentAtNs; - -// NEW -const sentAtNs: bigint = message.sentAtNs; - -// DecodedMessage.kind and deliveryStatus now use enums - -// OLD -if (message.kind === "application") { ... } -if (message.deliveryStatus === "published") { ... } - -// NEW -import { GroupMessageKind, DeliveryStatus } from "@xmtp/node-sdk"; - -if (message.kind === GroupMessageKind.Application) { ... } -if (message.deliveryStatus === DeliveryStatus.Published) { ... } - -// Message disappearing settings are now bigint - -// OLD -await conversation.updateMessageDisappearingSettings(0, 86400000000000); - -// NEW -await conversation.updateMessageDisappearingSettings(0n, 86400000000000n); - -// LogLevel enum variants casing changed -import { LogLevel } from "@xmtp/node-sdk"; - -// OLD -const client = await Client.create(signer, { loggingLevel: LogLevel.off }); - -// NEW -const client = await Client.create(signer, { loggingLevel: LogLevel.Off }); - -// Conversation type value is now an enum in metadata - -// OLD -const metadata = await conversation.metadata(); -if (metadata.conversationType() === "group") { ... } - -// NEW -import { ConversationType } from "@xmtp/node-sdk"; - -const metadata = await conversation.metadata(); -if (metadata.conversationType() === ConversationType.Group) { ... } -``` - -#### Refactored or renamed functions - -Method names have been updated to follow a consistent naming convention across the SDK. Methods that make network requests now use `fetch` prefix to distinguish them from local operations. Conversation creation methods now use `create` prefix for clarity. Several properties that could return variable internal state have been converted to functions. - -- Updated `Conversation.send` method signature -- Renamed `Client.getKeyPackageStatusesForInstallationIds` to `Client.fetchKeyPackageStatuses` -- Renamed `Client.getInboxIdByIdentifier` to `Client.fetchInboxIdByIdentifier` -- Renamed static `Client.inboxStateFromInboxIds` to static `Client.fetchInboxStates` -- Renamed `Conversation.getHmacKeys` to `Conversation.hmacKeys` -- `Conversation.consentState` is now a function -- Renamed `Conversations.getDmByIdentifier` to `Conversations.fetchDmByIdentifier` -- Renamed `Conversations.newGroupOptimistic` to `Conversations.createGroupOptimistic` -- Renamed `Conversations.newGroupWithIdentifiers` to `Conversations.createGroupWithIdentifiers` -- Renamed `Conversations.newDmWithIdentifier` to `Conversations.createDmWithIdentifier` -- Renamed `Conversations.newGroup` to `Conversations.createGroup` -- Renamed `Conversations.newDm` to `Conversations.createDm` -- `Group.permissions` is now a function -- `Group.isPendingRemoval` is now a function -- `Group.admins` property is now `Group.listAdmins` function -- `Group.superAdmins` property is now `Group.listSuperAdmins` function -- Removed `Preferences.getLatestInboxState` -- Refactored `Preferences.inboxState` -- Added `Preferences.fetchInboxState` -- Refactored `Preferences.inboxStateFromInboxIds` into `Preferences.getInboxStates` and `Preferences.fetchInboxStates` -- Renamed `Dm.getDuplicateDms` to `Dm.duplicateDms` - -```ts -// Conversation.send method signature changed - -// OLD -await conversation.send("hello"); -await conversation.send(reactionContent, ContentTypeReaction); - -// NEW - use dedicated send methods for built-in content types (see below for more details) -await conversation.sendText("hello"); -await conversation.sendReaction(reaction); - -// NEW - use send() for custom content types with EncodedContent -await conversation.send(encodedContent, { - shouldPush: true, - optimistic: false, -}); - -// Properties that are now functions - -// OLD -const consentState = conversation.consentState; -const permissions = group.permissions; -const isPendingRemoval = group.isPendingRemoval; -const admins = group.admins; -const superAdmins = group.superAdmins; - -// NEW -const consentState = conversation.consentState(); -const permissions = group.permissions(); -const isPendingRemoval = group.isPendingRemoval(); -const admins = group.listAdmins(); -const superAdmins = group.listSuperAdmins(); - -// Creating conversations - -// OLD -const group = await client.conversations.newGroup(inboxIds); -const dm = await client.conversations.newDm(inboxId); -const groupWithIdentifiers = - await client.conversations.newGroupWithIdentifiers(identifiers); - -// NEW -const group = await client.conversations.createGroup(inboxIds); -const dm = await client.conversations.createDm(inboxId); -const groupWithIdentifiers = - await client.conversations.createGroupWithIdentifiers(identifiers); - -// Preferences inbox state methods - -// OLD -const inboxState = await client.preferences.inboxState(); -const latestInboxState = await client.preferences.inboxState(true); -const latestInboxStateForInboxId = - await client.preferences.getLatestInboxState(inboxId); // this function removed -const inboxStates = await client.preferences.inboxStateFromInboxIds( - inboxIds, - false, -); -const latestInboxStates = await client.preferences.inboxStateFromInboxIds( - inboxIds, - true, -); - -// NEW -const inboxState = await client.preferences.inboxState(); -const latestInboxState = await client.preferences.fetchInboxState(); -const inboxStates = await client.preferences.getInboxStates(inboxIds); -const latestInboxStates = await client.preferences.fetchInboxStates(inboxIds); -``` - -### NEW FEATURES - -#### Built-in content types - -Previously, sending non-text messages required installing separate content type packages and registering codecs with the client. This release simplifies messaging by including all official content types directly in the SDK. You no longer need to manage codec registration, just use the dedicated send methods for each content type. - -Supported content types include: text, markdown, reactions, replies, read receipts, transaction references, wallet send calls, actions, intents, attachments, remote attachments, and multiple remote attachments. - -#### Enriched messages - -To make it easier to build rich messaging experiences, messages now include additional context. Each message includes the number of replies it has received and an array of reaction messages. This eliminates the need for separate queries to count replies or fetch reactions for a message thread. - -Reply messages also include the original message being replied to, allowing you to display the parent message context without an additional lookup. - -```ts -import { contentTypeReply, type Reply } from "@xmtp/node-sdk"; -import { contentTypesAreEqual } from "@xmtp/content-type-primitives"; - -const messages = await group.messages(); - -for (const message of messages) { - // number of replies to a message - console.log(`message ${message.id} has ${message.numReplies} replies`); - - // message.reactions is an array of reaction messages - console.log( - `message ${message.id} has ${message.reactions.length} reactions`, - ); - - // reply messages include the original message - if (contentTypesAreEqual(message.contentType, contentTypeReply)) { - const reply = message.content as Reply; - // the decoded content of the reply - console.log(reply.content); - // ID of message being replied to - console.log(reply.referenceId); - // the original message being replied to - console.log(reply.inReplyTo); - } -} -``` - -#### Send messages with different content types - -Each content type now has its own dedicated send method, making it easier to send different types of messages without manually encoding content or specifying content types. The second, optional parameter for each method is a boolean that indicates if it should be sent optimistically (stored locally before network confirmation). - -```ts -// send a text message -const textMessageId = await group.sendText("gm"); - -// send a markdown message -await group.sendMarkdown("# gm"); - -// send a reaction -await group.sendReaction({ - reference: textMessageId, - referenceInboxId: client.inboxId, - action: ReactionAction.Added, - content: "👍", - schema: ReactionSchema.Unicode, -}); - -// send a read receipt -await group.sendReadReceipt(); - -// send a reply -await group.sendReply({ - content: encodeText("This is a text reply"), - reference: textMessageId, - referenceInboxId: client.inboxId, -}); - -// send an attachment -await group.sendAttachment({ - filename: "gm.txt", - mimeType: "text/plain", - content: new Uint8Array([103, 109]), -}); - -// send a remote attachment -const attachment: Attachment = { - filename: "gm.txt", - mimeType: "text/plain", - content: new Uint8Array([103, 109]), -}; -// must encrypt attachment first -const encryptedAttachment = encryptAttachment(attachment); -const remoteAttachment: RemoteAttachment = { - // upload URL - url: "https://example.com/gm.txt", - contentDigest: encryptedAttachment.contentDigest, - secret: encryptedAttachment.secret, - salt: encryptedAttachment.salt, - nonce: encryptedAttachment.nonce, - scheme: "https", - contentLength: encryptedAttachment.contentLength, - filename: encryptedAttachment.filename, -}; -await group.sendRemoteAttachment(remoteAttachment); - -// decrypt attachment -const decryptedAttachment = decryptAttachment( - // downloaded from remote attachment URL - encryptedBytes, - remoteAttachment, -); - -// send multiple remote attachments -await group.sendMultiRemoteAttachment({ - attachments: [remoteAttachment], -}); - -// send a transaction reference -await group.sendTransactionReference({ - // eth mainnet - networkId: "1", - reference: "1234567890", -}); - -// send a wallet send call -await group.sendWalletSendCalls({ - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x4567891230", - value: "1", - }, - ], -}); - -// send actions -await group.sendActions({ - id: "actions-1", - description: "Choose an option", - actions: [ - { - id: "opt-1", - label: "Option 1", - }, - { - id: "opt-2", - label: "Option 2", - }, - ], -}); - -// send intent -await group.sendIntent({ - id: "intent-1", - actionId: "opt-1", -}); -``` - -#### Send custom content - -For content types not included in the SDK, you can still define custom codecs and use the `send` method to send encoded content. This allows you to extend XMTP with app-specific message formats while maintaining compatibility with the SDK's message handling. - -```ts -const ContentTypeTest: ContentTypeId = { - authorityId: "xmtp.org", - typeId: "test", - versionMajor: 1, - versionMinor: 0, -}; - -class TestCodec implements ContentCodec { - contentType = ContentTypeTest; - encode(content: Record): EncodedContent { - return { - type: this.contentType, - parameters: {}, - content: new TextEncoder().encode(JSON.stringify(content)), - }; - } - decode(content: EncodedContent): Record { - const decoded = new TextDecoder().decode(content.content); - return JSON.parse(decoded); - } - fallback() { - return undefined; - } - shouldPush() { - return false; - } -} - -const testCodec = new TestCodec(); - -// send custom content with options -await group.send( - testCodec.encode({ - foo: "bar", - }), - { - // should this message be a push notification? - shouldPush: testCodec.shouldPush(), - // should this message be sent optimistically? - optimistic: false, - }, -); -``` - -#### Last read times - -Building read status indicators is now easier. When participants send read receipt messages, you can query a conversation to see when each member last read the conversation. This enables features like showing which messages are unread or displaying "seen by" indicators. - -```ts -// returns an object keyed by inbox ID -const lastReadTimes = await group.lastReadTimes(); - -// get the last read time of an inbox in nanoseconds -const inboxLastReadTimeNs = lastReadTimes[inboxId]; -``` - -#### Message expiration timestamp - -For conversations with disappearing messages enabled, messages now include an expiration timestamp. This allows you to display countdown timers or visual indicators showing when a message will be automatically removed. - -```ts -// message is disappearing -if (message.expiresAtNs !== undefined) { - // schedule an effect when message is about the expire -} -``` - -To learn more, see [Access message expiration timestamps](https://docs.xmtp.org/chat-apps/core-messaging/disappearing-messages#access-disappearing-message-expiration-timestamps) - -## 4.6.0 - -This release introduces new features. If you've been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of these enhancements. - -### Self-removal from group chats - -This feature enables a member to leave a group chat on their own. Previously, a member could be removed only by other members with appropriate permissions. This update addresses user privacy concerns and reduces the need for manual member removal by admins. - -To see if a user has requested removal, check the new `isPendingRemoval` property. - -```ts -// request removal from group -await group.requestRemoval(); - -console.log(group.isPendingRemoval); // true -``` - -To learn more, see [Leave a group](https://docs.xmtp.org/chat-apps/core-messaging/group-permissions#leave-a-group) and [XIP-75: Self-removal support for XMTP/MLS groups](https://community.xmtp.org/t/xip-75-self-removal-support-for-xmtp-mls-groups/1659). - -### New `appData` metadata for groups - -Groups now support an `appData` metadata field for storing custom application-specific data. This field enables developers to attach arbitrary data to groups, such as configuration settings. - -The `appData` field can store up to 8,192 bytes of string data. - -```ts -// access app data -const appData = group.appData; - -// update app data with custom JSON -await group.updateAppData( - JSON.stringify({ - muted: false, - pinned: true, - }), -); - -// retrieve and parse the updated data -const appData = JSON.parse(group.appData); -console.log(appData.pinned); // true -``` - -## 4.5.1 - -### Patch Changes - -- fe6a04f: Added `GroupSyncSummary` export - -## 4.5.0 - -This release introduces new features, performance optimizations, and bug fixes. If you've been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of these enhancements and fixes. - -### Stream message deletions - -Call `streamMessageDeletions` to return a stream of message IDs that have been deleted. This new stream works in tandem with disappearing messages so that developers can be notified when messages have been removed. This is a local stream that doesn't require network sync and will not fail like other streams. - -To learn more, see [Support disappearing messages](https://docs.xmtp.org/chat-apps/core-messaging/disappearing-messages). - -### Paginate the conversation list - -For most pagination use cases, use the `createdBeforeNs` parameter for filtering and set `orderBy` to `createdAt`. This enables you to paginate against a stably sorted list. You can then perform a final sort of conversations in your app. - -To learn more, see [Paginate the conversation list](https://docs.xmtp.org/chat-apps/list-stream-sync/list#paginate-the-conversation-list). - -### Use `countMessages` to build an unread messages badge - -Call `countMessages` to return a count of messages without retrieving the full message list. This is more efficient when you only need the number, such as for unread message badges. - -To learn more, see [Count messages in a conversation](https://docs.xmtp.org/chat-apps/list-stream-sync/list-messages#count-messages-in-a-conversation). - -### New version properties on the client - -- `libxmtpVersion`: Returns the version of `libxmtp` used in the bindings -- `appVersion`: Returns the app version configured for the client - -The `libxmtpVersion` property can be useful for debugging or ensuring compatibility with the underlying XMTP APIs. - -**Note:** The static `Client.version` property is now deprecated, use `libxmtpVersion` instead. - -### `syncAll` performance improvements - -The `syncAll` method now performs the same function as before, but with significantly improved performance. It achieves this by syncing only group chat and DM conversations with a consent state of _allowed_ or _unknown_ that contain **unread messages**, rather than syncing all conversations. - -The method continues to sync new welcomes and preference updates. - -To learn more, see [Sync new welcomes, conversations with unread messages, and preferences](https://docs.xmtp.org/chat-apps/list-stream-sync/sync-and-syncall#sync-new-welcomes-conversations-with-unread-messages-and-preferences). - -### Streaming now includes catch-up messages - -Streaming messages now includes all messages sent after the last sync, including those missed while the client was offline. To only stream new messages, be sure to sync with the network before starting the stream. - -To learn more, see [Stream new group chat and DM messages](https://docs.xmtp.org/chat-apps/list-stream-sync/stream#stream-new-group-chat-and-dm-messages). - -### Welcome pointers - -OpenMLS supports sending welcomes to multiple installations in a single commit. This is currently used, but each welcome is sent individually to each installation. Some of the welcomes can be very large, and the data is duplicated for every installation. - -Welcome pointers introduce a new welcome message that provides a pointer to the location where the welcome data can be found. The large welcome pointer data can be sent to the server only once, and each installation can fetch that message. This is achieved using symmetric key encryption for the welcome data, with each installation receiving a message that includes these keys. - -This provides a performance and scalability improvement that makes both developer implementations and user experiences smoother and faster, without requiring changes to how developers write client code. - -To learn more, see [XIP-74: Welcome pointers](https://community.xmtp.org/t/xip-74-welcome-pointers/1211). - -### `revokeAllOtherInstallations` no longer crashes with a single installation - -Calling `revokeAllOtherInstallations()` on an inbox with only one active installation no longer crashes with an "Unknown signer" error. - -Because the method’s purpose is to keep only the current installation active, having just one installation already meets this condition. The operation now completes successfully without trying to revoke non-existent installations. - -To learn more, see [Revoke all other installations](https://docs.xmtp.org/chat-apps/core-messaging/manage-inboxes#revoke-all-other-installations). - -### Total ordered sort for message pagination - -Provides the ability to filter queries for the message list by insertion time rather than by time sent. Filtering by insertion time provides a totally ordered list, which is more reliable for pagination. - -To learn more, see [Paginate messages by insertion time](https://docs.xmtp.org/chat-apps/list-stream-sync/list-messages#paginate-by-insertion-time-recommended). - -### More details on sync - -The return value of `conversations.syncAll` is now an object that includes both the number of conversations, and the number that needed to be synced. - -### Updates for disappearing messages - -The disappearing messages feature has been updated to exclude expired (already disappeared) messages from queries. - -To learn more, see [Support disappearing messages](https://docs.xmtp.org/chat-apps/core-messaging/disappearing-messages). - -## 4.4.0 - -### Minor Changes - -- 7ce84ce: Added `getDmByIdentifier` method to `Conversations` - -## 4.3.1 - -Fixed accidental publishing of `4.3.0` - -## 4.2.6 - -### Patch Changes - -- 396767b: Increased default stream retry delay - -## 4.2.5 - -### Patch Changes - -- 8bf9ecb: Add "validHex" validation function - -## 4.2.4 - -### Patch Changes - -- 9003bb9: Enable hex strings as database encryption keys - -## 4.2.3 - -### Patch Changes - -- 61c19c9: - - Fixed an issue where duplicate welcome errors were fired erroneously - - Fixed a bug where building a client did a network request when not needed - -## 4.2.2 - -### Patch Changes - -- b7a860e: Refactored `lastMessage()` method of `Conversation` to always query the database - -## 4.2.1 - -### Patch Changes - -- 0abcb05: Fixed initial group membership validation - -## 4.2.0 - -- Improved performance of syncing new groups -- Added support for Lens chain Smart Contract Wallet verifier -- Fixed OpenMLS issue for persistence during message processing -- Fixed lifetime validation gaps - -## 4.1.2 - -### Patch Changes - -- bb4163f: - Added `onError` callback when stream reconnection fails - - Updated `uuid` dependency to v13 - -## 4.1.1 - -### Patch Changes - -- 5b0160e: Updated `dbPath` client option to allow callback function - -## 4.1.0 - -This release introduces improved fork detection. If you've been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of this enhancement. - -### Improved fork detection - -The `isCommitLogForked` field provides definitive fork detection without false positives. To minimize the negative effects of spam, fork detection is active only for groups that a user has actively consented to. - -Important: The `maybeForked` field has been deprecated. You can now use `isCommitLogForked` instead to get definitive fork detection without false positives. - -To learn more, see [Forked group debugging tool](https://docs.xmtp.org/inboxes/debug-your-app#forked-group-debugging-tool). - -## 4.0.3 - -### Patch Changes - -- ed36644: Reverted performance improvement for large inboxes that caused message streaming issues - -## 4.0.2 - -### Patch Changes - -- ffec6e0: - - Improved performance for large inboxes - - Improved key package errors - - Added `appVersion` client option - - Added `debugEventsEnabled` client option - - Fixed DM stitching bug - - Added expiration to messages for disappearing messages - -## 4.0.1 - -### Patch Changes - -- 3170da0: Improved syncAll performance when syncing large numbers of conversations - -## 4.0.0 - -This release introduces several enhancements to improve stream reliability. It contains breaking changes. - -### Stream reliability improvements - -When streams fail, an attempt to reconnect will be made automatically. By default, a stream will be retried 6 times with a 10 second delay between each retry. Maximum retries and retry delay can be configured with the `retryAttempts` and `retryDelay` options, respectively. To disable this feature, set the `retryOnFail` option to `false`. - -During the retry process, the `onRetry` and `onRestart` callbacks can be used to monitor progress. - -### BREAKING CHANGES - -#### All streaming methods are now async and accept a single options argument - -The new argument defines streaming options: - -```ts -type StreamOptions = { - /** - * Called when the stream ends - */ - onEnd?: () => void; - /** - * Called when a stream error occurs - */ - onError?: (error: Error) => void; - /** - * Called when the stream fails - */ - onFail?: () => void; - /** - * Called when the stream is restarted - */ - onRestart?: () => void; - /** - * Called when the stream is retried - */ - onRetry?: (attempts: number, maxAttempts: number) => void; - /** - * Called when a value is emitted from the stream - */ - onValue?: (value: V) => void; - /** - * The number of times to retry the stream - * (default: 6) - */ - retryAttempts?: number; - /** - * The delay between retries (in milliseconds) - * (default: 10000) - */ - retryDelay?: number; - /** - * Whether to retry the stream if it fails - * (default: true) - */ - retryOnFail?: boolean; -}; -``` - -In addition to these options, some streaming methods have more options. See their respective types for more details. - -Update your calls to each streaming method as follows: - -```ts -// OLD -const conversationStream = client.conversations.stream(callback, onFail); -const groupStream = client.conversations.streamGroups(callback, onFail); -const dmStream = client.conversations.streamDms(callback, onFail); -const allMessagesStream = await client.conversations.streamAllMessages( - callback, - conversationType, - consentStates, - onFail, -); -const allGroupMessagesStream = await client.conversations.streamAllGroupMessages( - callback, - consentStates, - onFail, -); -const allDmMessagesStream = await client.conversations.streamAllDmMessages( - callback, - consentStates, - onFail, -); - -const consentStream = client.preferences.streamConsent(callback, onFail); -const preferencesStream = client.preferences.streamPreferences(callback, onFail); - -const messagesStream = conversation.stream(callback, onFail); - -// NEW -const conversationStream = await client.conversations.stream({ - onError, - onValue, - onFail -}); -const groupStream = await client.conversations.streamGroups({ - onError, - onValue, - onFail -}); -const dmStream = await client.conversations.streamDms({ - onError, - onValue, - onFail -}); -const allMessageStream = await client.conversations.streamAllMessages({ - consentStates, - conversationType - onError, - onValue, - onFail -}); -const allGroupMessagesStream = await client.conversations.streamAllGroupMessages({ - consentStates, - onError, - onValue, - onFail, -}); -const allDmMessagesStream = await client.conversations.streamAllDmMessages({ - consentStates, - onError, - onValue, - onFail, -}); - -const consentStream = await client.preferences.streamConsent({ - onError, - onValue, - onFail, -}); -const preferencesStream = await client.preferences.streamPreferences({ - onError, - onValue, - onFail, -}); - -const messagesStream = await conversation.stream({ - onError, - onValue, - onFail -}); -``` - -#### Streams no longer end on error - -When a stream error occurs, it's passed to the `onError` callback only. The stream will remain active. - -#### Stream types have changed - -When using the `for await..of` loop, the value will never be `undefined`. - -```ts -const stream = await client.conversations.streamAllMessages(); - -for await (const message of stream) { - // message will always be an instance of DecodedMessage -} -``` - -## 3.2.2 - -### Patch Changes - -- 78c6710: - - Resolved issue with too many key package API requests - - Fixed issue causing users with old installations to sometimes not be added to groups - - Fixed a performance bottleneck that affected listing conversations while syncing - -## 3.2.1 - -### Patch Changes - -- 41aeaae: - - Improved sync and stream performance - - Increased max installations to 10 - - Fixed a known fork issue - - Added key package rotation every 30 days - -## 3.2.0 - -This release introduces several enhancements, including quantum-resistant encryption, improved identity management, and refined read/write rate limits. - -If you've been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of these enhancements and fixes. - -### Support for quantum-resistant encryption - -XMTP now supports quantum-resistant encryption, providing enhanced security for message transmission and storage. This upgrade ensures your app is protected against future quantum computer attacks through post-quantum cryptography. - -To learn more, see [Quantum resistance](https://docs.xmtp.org/protocol/security#quantum-resistance). - -### Consistent identity ordering - -When an inbox has multiple associated identities, the `identities` array is now ordered by the `client_timestamp_ns` field, which sorts identities based on when they were added to the inbox, placing the earliest added identity first. - -To learn more, see [Select the identity to display](https://docs.xmtp.org/inboxes/manage-inboxes#select-the-identity-to-display). - -### Enhanced rate limits with separate read/write limits - -XMTP now provides separate rate limits for read and write operations, offering more granular control over API usage. Read operations are limited to 20,000 requests per 5-minute window, while write operations are limited to 3,000 messages per 5-minute window. - -To learn more, see [Observe rate limits](https://docs.xmtp.org/inboxes/rate-limits). - -### Improved history sync - -History sync has been enhanced with better consent management across installations and improved handling of denied conversations. These changes ensure a more consistent experience when users access XMTP from multiple installations. - -To learn more, see [Enable history sync](https://docs.xmtp.org/inboxes/history-sync). - -### Enhanced group chat updates - -Group membership changes now automatically trigger group update codec messages, ensuring all participants receive consistent information about group state changes. This improves the reliability of group chat synchronization across all devices. - -To learn more, see [Manage group chat membership](https://docs.xmtp.org/inboxes/group-permissions#manage-group-chat-membership). - -### Performance improvements and bug fixes - -This release includes various performance optimizations throughout the SDK, resulting in faster message processing, improved memory usage, and better overall responsiveness. The release also includes bug fixes that improve the reliability of group chats and address a performance degradation issue that could occur when creating new groups. - -To learn more about optimizing your XMTP implementation, see [Debug your app](https://docs.xmtp.org/inboxes/debug-your-app). - -## 3.1.3 - -### Patch Changes - -- 3f4d125: - - Refactored `AsyncStream` to be more spec-compliant - - Added `onDone` callback to `AsyncStream` - - Updated stream methods to use new `onDone` callback to end streams - -## 3.1.2 - -### Patch Changes - -- 6b2e3d4: Improved gRPC connection detection - -## 3.1.1 - -### Patch Changes - -- e8fbfac: Fixed group syncing on larger groups - -## 3.1.0 - -### Minor Changes - -- b72f006: Added `onFail` callback option to stream methods - -## 3.0.1 - -### Patch Changes - -- 10bf2d1: Fix forks - -## 3.0.0 - -This update introduces enhancements for managing installations without a client. It also contains breaking changes related to signature management and consistency across SDKs. - -### BREAKING CHANGES - -#### Debug information has been moved to `client.debugInformation` - -To better align with our mobile SDKs, debug information helpers are now accessible at the `debugInformation` property of client instances. - -Update your calls to the following: - -- `client.apiStatistics()` => `client.debugInformation.apiStatistics()` -- `client.apiIdentityStatistics()` => `client.debugInformation.apiIdentityStatistics()` -- `client.apiAggregateStatistics()` => `client.debugInformation.apiAggregateStatistics()` -- `client.clearAllStatistics()` => `client.debugInformation.clearAllStatistics()` -- `client.uploadDebugArchive()` => `client.debugInformation.uploadDebugArchive()` - -#### Signatures are now managed through signature requests - -This change only affects developers who are using custom workflows with the `unsafe_*SignatureText` client methods. When using a custom signing workflow, use the new `unsafe_*SignatureRequest` methods. - -**Example** - -```ts -// change the recovery identifier -const signatureRequest = - await this.unsafe_changeRecoveryIdentifierSignatureRequest(newIdentifier); - -await this.unsafe_addSignature(signatureRequest); -await this.unsafe_applySignatureRequest(signatureRequest); -``` - -As part of this change, the `SignatureRequestType` export has been replaced with `SignatureRequestHandle`. - -### Other changes - -- Added `Client.revokeInstallations` static method for revoking installations without a client -- Added `Client.inboxStateFromInboxIds` static method for getting inbox state without a client - -## 2.2.1 - -### Patch Changes - -- e86b0c9: Fixed async iterator exit when calling `end()` on `AsyncStream` - -## 2.2.0 - -This update introduces several targeted enhancements and clarifications related to managing client builds, network statistics, installations, and group chats. - -If you’ve been building on a previous release, this one should be a **drop-in replacement**. Update as soon as possible to take advantage of these enhancements and fixes. - -### Reset network statistics for debugging - -A new helper, `clearAllStatistics()`, lets you reset all API/identity/stream network statistics counters. - -Use it to get a clean baseline between test runs or free memory on devices where cached gRPC stats grow over time. - -To learn more, see [Network statistics](https://docs.xmtp.org/inboxes/debug-your-app#network-statistics). - -### Support installation limits and more targeted revocations - -XMTP now enforces up to 5 app installations per inbox ID. - -When the installation limit is reached, you can revoke an installation to free up a slot. - -To learn more, see [Revoke installations](https://docs.xmtp.org/inboxes/manage-inboxes#revoke-installations). - -### Support slightly larger group chats - -The maximum group chat size has been raised from 220 to 250 members. - -To learn more, see [Create a new group chat](https://docs.xmtp.org/inboxes/create-conversations#create-a-new-group-chat). - -### Reduced risk of group chat forks - -Additional safeguards have been added to minimize the chance of unintended group chat forks. - -To learn about what group chat forks are and how they can occur, see [MLS Group State Forks: What, Why, How](https://cryspen.com/post/mls-fork-resolution/). - -## 2.1.0 - -This release delivers enhancements to messaging performance and reliability, as well as a set of developer debugging tools, all focused on making it easier to build with XMTP. - -If you’ve been building on a previous release, this one should be a **drop-in replacement**—just update to the latest version to take advantage of everything below. - -### Consent-based listing, streaming, and syncing - -By default, `conversations.list`, `conversations.listGroups`, `conversations.listDms`, `conversations.syncAll`, `conversations.streamAllMessages`, `conversations.streamAllGroupMessages`, and `conversations.streamAllDmMessages` now filter for conversations with a consent state of `ConsentState.Allowed` or `ConsentState.Unknown`. - -We recommend listing `ConsentState.Allowed` conversations only. This ensures that spammy conversations with a consent state of `ConsentState.Unknown` don't degrade the user experience. - -To include all conversations regardless of consent state, you can pass `[ConsentState.Allowed, ConsentState.Unknown, ConsentState.Denied]`. - -### Optimistic group chat creation - -Provides faster and offline group chat creation and message preparation before adding members. - -### Group chat member limit - -**A 220-member limit is now enforced for group chats.** This helps prevent errors that oversized groups can cause and ensures consistent behavior across clients. - -### Preference sync - -Preference syncing enables you to sync the following preference-related information across multiple existing app installations: - -- Conversation consent preferences -- Conversation HMAC keys (for push notifications) - -### Developer tooling and debugging - -Delivers tools and features for debugging when building with XMTP, including group chat diagnostics, file logging, and network statistics. - -### Reliability and performance - -- Reliability improvements to message history -- Reliability improvements to [`streamAll`](https://docs.xmtp.org/inboxes/list-and-stream#stream-all-group-chat-and-dm-messages) -- Performance improvements to `peerInboxId` -- [Duplicate DMs](https://docs.xmtp.org/inboxes/push-notifs/understand-push-notifs#dm-stitching-considerations-for-push-notifications) removed from streams - -## 2.0.9 - -### Patch Changes - -- 441a029: `AsyncStream` updates - - Changed signature of `return` to allow no argument (e.g. `stream.return()`) - - Added `end` alias that calls `return` without an argument - - Added `AsyncStream` to exports - -## 2.0.8 - -### Patch Changes - -- 609b509: Do not stop stream on benign message processing errors - -## 2.0.7 - -### Patch Changes - -- 616fdec: Added `null` option to `historySyncUrl` client option to allow disabling of history sync - -## 2.0.6 - -### Patch Changes - -- 5bc5a85: Update to the libxmtp stable release version - -## 2.0.5 - -### Patch Changes - -- 581d465: Added guard to prevent unexpected conversation types - -## 2.0.4 - -### Patch Changes - -- fbce324: Fix welcome processing issue that could lead to incorrect group state - -## 2.0.3 - -### Patch Changes - -- b7a3001: Fixed message processing issue that could sometimes fork groups - -## 2.0.2 - -### Patch Changes - -- f0a43c4: Lowercase Ethereum addresses on static Client.canMessage calls - -## 2.0.1 - -### Patch Changes - -- Removed filter for messages when content is `undefined` -- Converted all `any` types to `unknown` -- Added generics for types with `unknown` where applicable -- Prevented `CodecNotFoundError` from throwing when instantiating `DecodedMessage` -- Added code comments -- Updated dependencies - - @xmtp/content-type-group-updated@2.0.2 - - @xmtp/content-type-primitives@2.0.2 - - @xmtp/content-type-text@2.0.2 - -## 2.0.0 - -This release focuses on new features, stability, and performance. - -### Upgrade from 1.2.1 to 2.0.0 - -Use the information in these release notes to upgrade from `@xmtp/node-sdk` version `1.2.1` to `2.0.0`. - -### Breaking changes - -#### Refactored `Client.create` - -The database encryption key parameter was removed from the static `Client.create` method. To use a database encryption key, add it to the client options. - -`1.x` code: - -```typescript -import { Client, type ClientOptions, type Signer } from "@xmtp/node-sdk"; - -const clientOptions: ClientOptions = { ... }; -const dbEncryptionKey = MY_ENCRYPTION_KEY; -const signer: Signer = { ... }; -const client = await Client.create(signer, dbEncryptionKey, clientOptions); -``` - -`2.0.0` code: - -```typescript -import { Client, type ClientOptions, type Signer } from "@xmtp/node-sdk"; - -const clientOptions: ClientOptions = { - dbEncryptionKey: MY_ENCRYPTION_KEY, -}; -const signer: Signer = { ... }; -const client = await Client.create(signer, clientOptions); -``` - -#### Refactored `Client` constructor - -The `Client` constructor now only accepts a single parameter: client options. It's no longer possible to create a client with a signer using the constructor. Use `Client.create` to create a new client with a signer. - -`1.x` code: - -```typescript -import { Client, type Signer } from "@xmtp/node-sdk"; - -const signer: Signer = { ... }; -const client = new Client(XMTPClient, signer, codecs); -``` - -`2.0.0` code: - -```typescript -import { Client, type ClientOptions, type Signer } from "@xmtp/node-sdk"; - -const clientOptions: ClientOptions = { - dbEncryptionKey: MY_ENCRYPTION_KEY, -}; -const signer: Signer = { ... }; -const client = await Client.create(signer, clientOptions); -``` - -#### Client `identifier` property is now `accountIdentifier` - -`1.x` code: - -```typescript -const identifier = await client.identifier; -``` - -`2.0.0` code: - -```typescript -const identifier = client.accountIdentifier; -``` - -#### Removed `requestHistorySync` method from client - -Device sync is being refactored and this method will not be compatible with a future version. Removing it now with these breaking changes so we don't need to bump the major version in the near future. - -### New features - -#### Added `Client.build` static method - -It's now possible to create a client without a signer using the new `Client.build` method. A signer is not required if an account is already registered on the XMTP network. Keep in mind, some client methods still require a signer. - -```typescript -import { Client, IdentifierKind, type ClientOptions, type Identifier } from "@xmtp/node-sdk"; - -const clientOptions: ClientOptions = { ... }; -const identifier: Identifier = { - identifier: "0x1234567890abcdef1234567890abcdef12345678", - identifierKind: IdentifierKind.Ethereum, -}; -const client = await Client.build(identifier, clientOptions); -``` - -### Other changes - -- Updated `dbPath` client option to allow `null` value -- Added more custom error types -- Added `dbEncryptionKey` option to client options -- Added `options` property to client -- Added `signer` property to client - -## 1.2.1 - -### Patch Changes - -- 6e54926: Exposed message decoding errors in streams - -## 1.2.0 - -### Minor Changes - -- d35fbc1: - - Added `getHmacKeys` to `Conversation` - - Added custom errors - -## 1.1.1 - -### Patch Changes - -- 7e7fad4: Fixed error handling in `AsyncStream` - -## 1.1.0 - -### Minor Changes - -- 88e6ff6: - - Added `unsafe_changeRecoveryIdentifierSignatureText` method to client - - Added `changeRecoveryIdentifier` method to client - - Added `getKeyPackageStatusesForInstallationIds` method to client - -## 1.0.5 - -### Patch Changes - -- 8bd3930: Fixed removing inboxes with invalid key packages from groups - -## 1.0.4 - -### Patch Changes - -- 295e046: - - Fixed incorrect key package associations - - Resolved DM stitching issues for conversations without messages - -## 1.0.3 - -### Patch Changes - -- 5845617: Refactored welcome message processing to prevent key package deletion on failure - -## 1.0.2 - -### Patch Changes - -- Updated dependencies [340fcf4] - - @xmtp/content-type-group-updated@2.0.1 - - @xmtp/content-type-primitives@2.0.1 - - @xmtp/content-type-text@2.0.1 - - @xmtp/proto@3.78.0 - -## 1.0.1 - -### Patch Changes - -- 607ae92: Fixed `IdentifierKind` enum export in build - -## 1.0.0 - -### Major Changes - -- Updated `Signer` type -- Replaced address parameters with inbox IDs or identifiers -- Added new methods to use with identifiers -- Added `pausedForVersion` to `Conversation` -- Added new `Preferences` class accessible from `client.preferences` -- Renamed `newGroupByIdentifiers` to `newGroupWithIdentifiers` -- Renamed `newDmByIdentifier` to `newDmWithIdentifier` -- Updated exports -- Improved DM group stitching - -## 1.0.0-rc2 - -- Renamed `newGroupByIdentifiers` to `newGroupWithIdentifiers` -- Renamed `newDmByIdentifier` to `newDmWithIdentifier` - -## 1.0.0-rc1 - -- Updated `Signer` type -- Replaced address parameters with inbox IDs or identifiers -- Added new methods to use with identifiers -- Added `pausedForVersion` to `Conversation` -- Updated exports - -## 0.0.47 - -### Patch Changes - -- dd1a33a: - - Fixed stream errors - - Fixed build for later node versions - -## 0.0.46 - -### Patch Changes - -- 3cf6dd9: - - Exposed all client signature methods - - Refactored client signature methods to return `undefined` instead of `null` - - Added guard to `Client.addAccount` to prevent automatic reassignment of inboxes - - Removed `allowedStates`, `conversationType`, and `includeSyncGroups` from `ListConversationsOptions` - - Added `contentTypes` option to `ListMessagesOptions` - - Added more exports from the bindings - - Added `Group` and `Dm` classes - - Refactored some functions to use the new `Group` and `Dm` classes - -## 0.0.45 - -### Patch Changes - -- 5221111: - - Added new methods to create groups by inbox ID - - Added consent states option to `syncAllConversations` - - Updated list conversations options to include `consentStates` and `includeDuplicateDms` - - Removed automatic message filtering from DM groups - - Added disappearing messages methods to conversations - - Added optional `listMessage` property to `Conversation` - - Added consent streaming - - Added preferences streaming - - Added `Client.version` static getter - -## 0.0.44 - -### Patch Changes - -- c63d8af: Make `getBlockNumber` optional for SCW signers - -## 0.0.43 - -### Patch Changes - -- 68b0200: Refactored `Signer` type - -## 0.0.42 - -### Patch Changes - -- ec5cd41: - - Removed group pinned frame URL metadata - - Fixed DB locking issues - -## 0.0.41 - -### Patch Changes - -- 931c4a4: Updated `createDm` to return an existing DM group, if it exists - -## 0.0.40 - -### Patch Changes - -- 25e0e15: Replaced some `??` with `||` to ensure string values are not empty - -## 0.0.39 - -### Patch Changes - -- 626d420: Fixed DM group syncing across installations - -## 0.0.38 - -### Patch Changes - -- cf6fbc0: Added default history sync URL to client with option to override - -## 0.0.37 - -### Patch Changes - -- d09ec27: - - Added support for revoking specific installations - - Refactored `list`, `listGroups`, and `listDms` to be synchronous - -## 0.0.36 - -### Patch Changes - -- d84932a: Added support for HMAC keys - -## 0.0.35 - -### Patch Changes - -- 3a1e53b: Enabled group permissions updates - - Added `updatePermission` method to `Conversation` - - Exported `MetadataField` type - -## 0.0.34 - -### Patch Changes - -- a35afb8: Upgraded bindings, refactored some methods to be async - -## 0.0.33 - -### Patch Changes - -- 8120a39: Added support for custom permissions policy - -## 0.0.32 - -### Patch Changes - -- 1777a23: Dropped support for CommonJS -- Updated dependencies [1777a23] - - @xmtp/content-type-group-updated@2.0.0 - - @xmtp/content-type-primitives@2.0.0 - - @xmtp/content-type-text@2.0.0 - -## 0.0.31 - -### Patch Changes - -- 9c625ad: Do not create local DB when calling the `Client.canMessage` static method - -## 0.0.30 - -### Patch Changes - -- 7338e0e: - - Removed authorization instance methods from client - - Added static authorization methods to client - - Upgraded to latest node bindings - -## 0.0.29 - -### Patch Changes - -- f1b93bb: Upgraded to latest node bindings - -## 0.0.28 - -### Patch Changes - -- a1f27b8: - - Added `isAddressAuthorized` to `Client` - - Added `isInstallationAuthorized` to `Client` - -## 0.0.27 - -### Patch Changes - -- 9324310: - - Added `installationIdBytes` to `Client` - - Refactored `Client.verifySignedWithInstallationKey` to return a `boolean` - - Changed `Client.verifySignedWithPublicKey` to a static method - -## 0.0.26 - -### Patch Changes - -- 7661f78: - - Added `syncAll` method to `Conversations` - - Added `signWithInstallationKey`, `verifySignedWithInstallationKey`, and `verifySignedWithPublicKey` to `Client` - -## 0.0.25 - -### Patch Changes - -- 63e5276: Updated exports -- Updated dependencies [63e5276] - - @xmtp/content-type-group-updated@1.0.1 - - @xmtp/content-type-primitives@1.0.3 - - @xmtp/content-type-text@1.0.1 - - @xmtp/proto@3.72.0 - -## 0.0.24 - -### Patch Changes - -- a1a16a0: - - Added `Signer` interface - - Refactored `Client.create` to accept a `Signer` instead of account address - - Refactored client creation to automatically register and identity - - Added `disableAutoRegister` to `ClientOptions` to allow disabling of client registration after creation - - Removed direct access to all signature functions - - Added `Client.register` method for registering a client - - Added `Client.addAccount` method for adding another account to an installation - - Added `Client.removeAccount` method for removing an account from an installation - - Added `Client.revokeInstallations` method for revoking all other installations - - Added static `Client.canMessage` for checking if an address is on the network without a client - - Added environment to DB path - -## 0.0.23 - -### Patch Changes - -- 31ca82d: - - Updated return type of `Client.canMessage` from Record to Map - - Added requirement of encryption key when creating a client - - Updated logging options - - Added smart contract wallet support - - Updated exports - -## 0.0.22 - -### Patch Changes - -- 5a41542: - - Upgraded node bindings - - Refactored code with updated type exports - - Fixed streaming issues when a stream error occurs - -## 0.0.21 - -### Patch Changes - -- 764d6c0: Refactor streams for better error handling - -## 0.0.20 - -### Patch Changes - -- 981bcf4: - - Added 1:1 messages - - Added stream errors to the stream's async iterator values - - Added consent state methods to client and conversation - - Added signature methods for adding/revoke wallets and revoking installations - - Added `getLatestInboxState` to client - - Added inbox ID helpers - -## 0.0.19 - -### Patch Changes - -- 87457d6: - - Allowed for `undefined` content type and content in messages - - Filtered out messages without content when calling `Conversation.messages` - - Added generic typing for message content to `DecodedMessage` class and `Conversations.findMessageById` - - Replaced temporary group updated codec with official content type - -## 0.0.18 - -### Patch Changes - -- cdc9212: Update `@xmtp/node-bindings` to 0.0.14 - -## 0.0.17 - -### Patch Changes - -- 5f02a9b: - - Upgraded node bindings - - Added `inboxStateFromInboxIds` method to client - - Added logging option when creating a client - -## 0.0.16 - -### Patch Changes - -- b8f97ba: Upgrade to latest node bindings - -### BREAKING CHANGE - -This is a breaking change as some of the APIs have changed. - -- `Client.signatureText` is now an async function -- `Client.addScwSignature` has been removed -- `Client.addEcdsaSignature` has been renamed to `Client.addSignature` -- `Conversation.members` is now an async function - -## 0.0.15 - -### Patch Changes - -- b8d9b36: - - Upgraded to latest MLS node bindings - - Added `inboxState` to Client - -## 0.0.14 - -### Patch Changes - -- 93f0fb9: Upgraded to latest MLS node bindings - -## 0.0.13 - -### Patch Changes - -- 4c0340b: - - Upgraded `@xmtp/proto` - - Upgraded MLS bindings - - Added optimistic sending - - Added `pinnedFrameUrl` metadata to conversations - - Added `policySet` to conversation permissions - -## 0.0.12 - -### Patch Changes - -- 4ec046b: - - Added conversation descriptions - - Fixed DB locking issues - - Fixed invalid policy error - - Removed Admin status from group creators (Super Admin only) - - Made content type optional when sending messages - -## 0.0.11 - -### Patch Changes - -- c506faf: - - Upgraded to latest MLS node bindings - - Added `requestHistorySync` and `getInboxIdByAddress` to `Client` - - Renamed `get` to `getConversationById` in `Conversations` - - Added `getMessageById` to `Conversations` - -## 0.0.10 - -### Patch Changes - -- b5db898: Upgrade node bindings for bug fixes - -## 0.0.9 - -### Patch Changes - -- a419052: - - Upgrade to latest node bindings - - Rename addErc1271Signature to addScwSignature - - Add more options when creating a group with client.conversations.newConversation - - Add getter and setter for group image URL - - Add getter for group permissions - - Add more tests - - Add GroupPermissions to exports - -## 0.0.8 - -### Patch Changes - -- b87672a: - - Add production environment - - Allow for all environments when creating a client - - Remove dependency on `@xmtp/xmtp-js` for content types and their primitives - -## 0.0.7 - -### Patch Changes - -- 8a9b624: - - Add streaming callbacks - - Add `get` method to `Conversations` for easy access to conversations that are created, listed, or streamed during a client session - -## 0.0.6 - -### Patch Changes - -- 6dd6a0e: Add `streamAllMessages` to Conversations - -## 0.0.5 - -### Patch Changes - -- ff6c304: Use correct inbox ID for all environments - -## 0.0.4 - -### Patch Changes - -- 632e6a3: Add conversation reference to messages - -## 0.0.3 - -### Patch Changes - -- 3006d8b: Upgrade MLS node bindings, add admin features - -## 0.0.2 - -### Patch Changes - -- ff5fcd7: Fix package.json issues - -## 0.0.1 - -Initial release diff --git a/sdks/node-sdk/LICENSE b/sdks/node-sdk/LICENSE deleted file mode 100644 index ae6695abd..000000000 --- a/sdks/node-sdk/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 XMTP (xmtp.org) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/sdks/node-sdk/README.md b/sdks/node-sdk/README.md deleted file mode 100644 index 62c1c3f3e..000000000 --- a/sdks/node-sdk/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# XMTP client SDK for Node - -This package provides the XMTP client SDK for Node. - -To keep up with the latest SDK developments, see the [Issues tab](https://github.com/xmtp/xmtp-js/issues) in this repo. - -## Documentation - -To learn how to use the XMTP client SDK for Node, see [Get started with the XMTP Node SDK](https://docs.xmtp.org/sdks/node). - -## Requirements - -- Node.js 20+ -- `glibc` 3.28+ (i.e. Ubuntu 24.04 or later) - -## Install - -**NPM** - -```bash -npm install @xmtp/node-sdk -``` - -**PNPM** - -```bash -pnpm install @xmtp/node-sdk -``` - -**Yarn** - -```bash -yarn add @xmtp/node-sdk -``` - -## Developing - -Run `yarn dev` to build the SDK and watch for changes, which will trigger a rebuild. - -## Testing - -For testing setup instructions, see our [testing guidelines](https://github.com/xmtp/xmtp-js/blob/main/CONTRIBUTING.md#testing) in the main repository. - -### Useful commands - -- `yarn build`: Builds the SDK -- `yarn clean`: Removes `node_modules`, `dist`, and `.turbo` folders -- `yarn test`: Runs all tests -- `yarn typecheck`: Runs `tsc` - -## Breaking revisions - -Because this SDK is in active development, you should expect breaking revisions that might require you to adopt the latest SDK release to enable your app to continue working as expected. - -Breaking revisions in a Node SDK release are described on the [Releases page](https://github.com/xmtp/xmtp-js/releases). - -## Deprecation - -Older versions of the SDK will eventually be deprecated, which means: - -1. The network will not support and eventually actively reject connections from clients using deprecated versions. -2. Bugs will not be fixed in deprecated versions. - -The following table provides the deprecation schedule. - -| Announced | Effective | Minimum Version | Rationale | -| --------------------------- | ----------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| No more support for XMTP V2 | May 1, 2025 | >=1.0.5 | In a move toward better security with MLS and the ability to decentralize, we will be shutting down XMTP V2 and moving entirely to XMTP V3. To learn more about V2 deprecation, see [XIP-53: XMTP V2 deprecation plan](https://community.xmtp.org/t/xip-53-xmtp-v2-deprecation-plan/867). To learn how to upgrade, see [@xmtp/node-sdk v1.0.5](https://github.com/xmtp/xmtp-js/releases/tag/%40xmtp%2Fnode-sdk%401.0.5). | - -Bug reports, feature requests, and PRs are welcome in accordance with these [contribution guidelines](https://github.com/xmtp/xmtp-js/blob/main/CONTRIBUTING.md). diff --git a/sdks/node-sdk/package.json b/sdks/node-sdk/package.json deleted file mode 100644 index 82fe49b73..000000000 --- a/sdks/node-sdk/package.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "@xmtp/node-sdk", - "version": "6.0.0", - "description": "XMTP Node client SDK for interacting with XMTP networks", - "keywords": [ - "xmtp", - "messaging", - "web3", - "js", - "javascript", - "node", - "nodejs" - ], - "homepage": "https://github.com/xmtp/xmtp-js", - "bugs": { - "url": "https://github.com/xmtp/xmtp-js/issues" - }, - "repository": { - "type": "git", - "url": "git+https://git@github.com/xmtp/xmtp-js.git", - "directory": "packages/node-sdk" - }, - "license": "MIT", - "author": "XMTP Labs ", - "type": "module", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "./package.json": "./package.json" - }, - "main": "dist/index.js", - "types": "dist/index.d.ts", - "files": [ - "dist" - ], - "scripts": { - "build": "yarn clean:dist && rollup -c", - "clean": "rimraf .turbo && yarn clean:dbs && yarn clean:dist && yarn clean:deps", - "clean:dbs": "rimraf **/*.db3* ||:", - "clean:deps": "rimraf node_modules", - "clean:dist": "rimraf dist", - "dev": "yarn build --watch", - "generate:accounts": "tsx scripts/accounts.ts", - "generate:groups": "tsx scripts/groups.ts", - "test": "vitest run", - "test:cov": "vitest run --coverage", - "typecheck": "tsc" - }, - "dependencies": { - "@xmtp/content-type-primitives": "3.0.0", - "@xmtp/node-bindings": "1.11.0-nightly.20260603.89c3fc3" - }, - "devDependencies": { - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-typescript": "^12.3.0", - "@types/node": "^24.10.9", - "@vitest/coverage-v8": "^4.0.18", - "fast-glob": "^3.3.3", - "rimraf": "^6.1.2", - "rollup": "^4.59.0", - "rollup-plugin-dts": "^6.3.0", - "rollup-plugin-tsconfig-paths": "^1.5.2", - "tsx": "^4.21.0", - "typescript": "^5.9.3", - "uint8array-extras": "^1.5.0", - "viem": "^2.44.4", - "vite": "^7.3.1", - "vite-tsconfig-paths": "^6.0.4", - "vitest": "^4.0.18" - }, - "engines": { - "node": ">=22" - }, - "publishConfig": { - "access": "public", - "provenance": true, - "registry": "https://registry.npmjs.org/" - } -} diff --git a/sdks/node-sdk/rollup.config.js b/sdks/node-sdk/rollup.config.js deleted file mode 100644 index bc285f73c..000000000 --- a/sdks/node-sdk/rollup.config.js +++ /dev/null @@ -1,49 +0,0 @@ -import json from "@rollup/plugin-json"; -import typescript from "@rollup/plugin-typescript"; -import { defineConfig } from "rollup"; -import { dts } from "rollup-plugin-dts"; -import tsConfigPaths from "rollup-plugin-tsconfig-paths"; - -const external = [ - "node:path", - "node:process", - "node:util/types", - "@xmtp/content-type-group-updated", - "@xmtp/content-type-primitives", - "@xmtp/content-type-text", - "@xmtp/node-bindings", - "@xmtp/node-bindings/version.json", -]; - -const plugins = [ - tsConfigPaths(), - typescript({ - declaration: false, - declarationMap: false, - }), - json({ - preferConst: true, - }), -]; - -export default defineConfig([ - { - input: "src/index.ts", - output: { - file: "dist/index.js", - format: "es", - sourcemap: true, - importAttributesKey: "with", - }, - plugins, - external, - }, - { - input: "src/index.ts", - output: { - file: "dist/index.d.ts", - format: "es", - }, - plugins: [tsConfigPaths(), dts()], - }, -]); diff --git a/sdks/node-sdk/scripts/accounts.ts b/sdks/node-sdk/scripts/accounts.ts deleted file mode 100644 index 46a1d7827..000000000 --- a/sdks/node-sdk/scripts/accounts.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { writeFile } from "node:fs/promises"; -import path from "node:path"; -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; - -type Account = [key: string, address: string]; -type AccountsMap = Record; - -const createRandomAccount = (): Account => { - const privateKey = generatePrivateKey(); - const account = privateKeyToAccount(privateKey); - return [privateKey, account.address]; -}; - -const writeAccountsJson = async (accounts: AccountsMap) => { - console.log("Writing accounts to file..."); - const accountsJsonPath = path.join(import.meta.dirname, "accounts.json"); - await writeFile(accountsJsonPath, JSON.stringify(accounts, null, 2)); - console.log(`Accounts data written to '${accountsJsonPath}'`); -}; - -const main = async () => { - console.log("Creating 1000 accounts..."); - const accounts = Object.fromEntries( - Array.from({ length: 1000 }, () => createRandomAccount()), - ); - await writeAccountsJson(accounts); -}; - -await main(); diff --git a/sdks/node-sdk/scripts/groups.ts b/sdks/node-sdk/scripts/groups.ts deleted file mode 100644 index 05bcad1d1..000000000 --- a/sdks/node-sdk/scripts/groups.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { readFile } from "node:fs/promises"; -import path from "node:path"; -import { IdentifierKind } from "@xmtp/node-bindings"; -import { Client } from "@/Client"; -import type { NetworkOptions, StorageOptions } from "@/types"; -import { createSigner, createUser, type User } from "@test/helpers"; - -export const createRegisteredClient = async ( - user: User, - dbPath?: string | null, -) => { - const options: NetworkOptions & StorageOptions = { - env: "local", - dbPath, - }; - return Client.create(createSigner().signer, options); -}; - -const accountsJsonPath = path.join(import.meta.dirname, "accounts.json"); -const parsedAccounts = JSON.parse( - await readFile(accountsJsonPath, "utf-8"), -) as Record; - -type Account = { key: string; address: string }; -const accounts: Account[] = Object.entries(parsedAccounts).map( - ([key, address]) => ({ key, address }), -); - -const primaryAccount = accounts.shift() as Account; - -const primaryAccountClient = await createRegisteredClient( - createUser(primaryAccount.key as `0x${string}`), - "./test.db3", -); - -console.log("Registering accounts..."); - -for (const a of accounts) { - await createRegisteredClient(createUser(a.key as `0x${string}`), null); -} - -const groups = []; - -console.log("Creating groups..."); - -// create a bunch of groups -while (accounts.length > 200) { - const groupsAccounts = accounts.splice(0, 4); - const group = - await primaryAccountClient.conversations.createGroupWithIdentifiers( - groupsAccounts.map((a) => ({ - identifierKind: IdentifierKind.Ethereum, - identifier: a.address, - })), - ); - groups.push(group); -} - -console.log(`Created ${groups.length} groups`); - -console.log(`Sending "gm" message into each group...`); - -for (const group of groups) { - await group.sendText("gm"); -} - -console.log("Creating DM groups..."); - -const dmGroups = []; - -while (accounts.length > 0) { - const dmGroup = - await primaryAccountClient.conversations.createDmWithIdentifier({ - identifierKind: IdentifierKind.Ethereum, - identifier: (accounts.pop() as Account).address, - }); - dmGroups.push(dmGroup); -} - -console.log(`Created ${dmGroups.length} DM groups`); - -console.log("Sending 'gm' message into each DM group..."); - -for (const dmGroup of dmGroups) { - await dmGroup.sendText("gm"); -} - -console.log("Syncing all conversations..."); - -await primaryAccountClient.conversations.syncAll(); - -console.log("Querying DM groups..."); - -const groupConvos = primaryAccountClient.conversations.listGroups(); -const dmConvos = primaryAccountClient.conversations.listDms(); - -console.log(`Found ${dmConvos.length} DM conversations`); -console.log(`Found ${groupConvos.length} group conversations`); diff --git a/sdks/node-sdk/src/AsyncStream.ts b/sdks/node-sdk/src/AsyncStream.ts deleted file mode 100644 index d4eead7c1..000000000 --- a/sdks/node-sdk/src/AsyncStream.ts +++ /dev/null @@ -1,189 +0,0 @@ -type ResolveValue = { - value: T; - done: boolean; -}; - -type ResolveNext = (resolveValue: ResolveValue) => void; - -/** - * AsyncStream provides an async iterable interface for streaming data. - * - * This class implements a producer-consumer pattern where: - * - Producers can push values using the `push()` method - * - Consumers can iterate over values asynchronously using `for await` loops or `next()` - * - Values are queued internally when no consumers are waiting - * - Consumers are resolved immediately when values are available - * - The stream can be terminated using `done()`, `return()`, or `end()` - * - * @example - * ```typescript - * const stream = new AsyncStream(); - * - * stream.push("hello"); - * stream.push("world"); - * - * for await (const value of stream) { - * console.log(value); // "hello", "world" - * } - * ``` - */ -export class AsyncStream { - isDone = false; - #pendingResolves: ResolveNext[] = []; - #queue: T[]; - onDone: (() => void) | undefined; - onReturn: (() => void) | undefined; - - constructor() { - this.#queue = []; - this.isDone = false; - } - - flush() { - while (this.#pendingResolves.length > 0) { - const nextResolve = this.#pendingResolves.shift(); - if (nextResolve) { - nextResolve({ done: true, value: undefined }); - } - } - } - - done() { - this.flush(); - this.#queue = []; - this.#pendingResolves = []; - this.isDone = true; - this.onDone?.(); - } - - push = (value: T) => { - if (this.isDone) { - return; - } - - const nextResolve = this.#pendingResolves.shift(); - if (nextResolve) { - nextResolve({ - done: false, - value, - }); - } else { - this.#queue.push(value); - } - }; - - next = (): Promise> => { - if (this.isDone) { - return Promise.resolve({ done: true, value: undefined }); - } - - if (this.#queue.length > 0) { - return Promise.resolve({ - done: false, - value: this.#queue.shift(), - }); - } - - return new Promise((resolve) => { - this.#pendingResolves.push(resolve); - }); - }; - - return = (): Promise> => { - this.onReturn?.(); - this.done(); - - return Promise.resolve({ - done: true, - value: undefined, - }); - }; - - end = () => this.return(); - - [Symbol.asyncIterator]() { - return this; - } -} - -export interface AsyncStreamProxy extends AsyncIterable { - next(): Promise>; - return(): Promise>; - end(): Promise>; - isDone: boolean; -} - -const usableProperties = [ - "end", - "isDone", - "next", - "return", - Symbol.asyncIterator, -]; -const isUsableProperty = ( - prop: string | symbol, -): prop is keyof AsyncStreamProxy => { - return usableProperties.includes(prop); -}; - -/** - * Creates a read-only proxy for AsyncStream instances that restricts access to consumer-only methods. - * - * This proxy only exposes the following properties and methods: - * - `next()`: Get the next value from the stream - * - `end()`: Terminate the stream and stop iteration - * - `return()`: Same as end(), terminates the stream - * - `isDone`: Boolean indicating if the stream has been terminated - * - `Symbol.asyncIterator`: Enables `for await` loop iteration - * - * Producer methods like `push()`, `done()`, and `flush()` are hidden to prevent - * consumers from accidentally modifying the stream state. - * - * @param stream - The AsyncStream instance to create a proxy for - * @returns A read-only proxy that implements AsyncStreamProxy - * - * @example - * ```typescript - * const stream = new AsyncStream(); - * const proxy = createAsyncStreamProxy(stream); - * - * stream.push("hello"); - * stream.push("world"); - * - * for await (const value of proxy) { - * console.log(value); // "hello", "world" - * } - * ``` - */ -export function createAsyncStreamProxy(stream: AsyncStream) { - return new Proxy(stream, { - get(target, prop, receiver) { - if (isUsableProperty(prop)) { - return Reflect.get(target, prop, receiver); - } - }, - - set() { - return true; - }, - - has(_target, prop) { - return isUsableProperty(prop); - }, - - ownKeys() { - return usableProperties; - }, - - getOwnPropertyDescriptor(target, prop) { - if (isUsableProperty(prop)) { - return { - enumerable: true, - configurable: true, - value: Reflect.get(target, prop), - }; - } - return undefined; - }, - }) as AsyncStreamProxy; -} diff --git a/sdks/node-sdk/src/Client.ts b/sdks/node-sdk/src/Client.ts deleted file mode 100644 index c137d4029..000000000 --- a/sdks/node-sdk/src/Client.ts +++ /dev/null @@ -1,1250 +0,0 @@ -import { randomBytes } from "node:crypto"; -import { type ContentCodec } from "@xmtp/content-type-primitives"; -import { - applySignatureRequest, - Backend, - BackupElementSelectionOption, - fetchInboxStatesByInboxIds, - IdentifierKind, - isAddressAuthorized as isAddressAuthorizedBinding, - isInstallationAuthorized as isInstallationAuthorizedBinding, - revokeInstallationsSignatureRequest, - verifySignedWithPublicKey as verifySignedWithPublicKeyBinding, - type ArchiveMetadata, - type ArchiveOptions, - type AvailableArchiveInfo, - type GroupSyncSummary, - type Identifier, - type InboxState, - type Client as NodeClient, - type SignatureRequestHandle, -} from "@xmtp/node-bindings"; -import { CodecRegistry } from "@/CodecRegistry"; -import { HistorySyncUrls } from "@/constants"; -import { Conversations } from "@/Conversations"; -import { DebugInformation } from "@/DebugInformation"; -import { Preferences } from "@/Preferences"; -import type { ClientOptions, ExtractCodecContentTypes, XmtpEnv } from "@/types"; -import { createBackend } from "@/utils/createBackend"; -import { createClient } from "@/utils/createClient"; -import { - AccountAlreadyAssociatedError, - ClientNotInitializedError, - InboxReassignError, - SignerUnavailableError, -} from "@/utils/errors"; -import { getInboxIdForIdentifier } from "@/utils/inboxId"; -import { type Signer } from "@/utils/signer"; - -/** - * Resolves a `Backend` instance from either a `Backend` or an `XmtpEnv` string. - * - * @param envOrBackend - A `Backend` instance, or an `XmtpEnv` string - * @param gatewayHost - Optional gateway host (only used when `envOrBackend` is an `XmtpEnv`) - * @returns A `Backend` instance - */ -const resolveBackend = async ( - envOrBackend?: XmtpEnv | Backend, - gatewayHost?: string, -): Promise => { - if (envOrBackend instanceof Backend) { - return envOrBackend; - } - return createBackend({ env: envOrBackend, gatewayHost }); -}; - -const createEphemeralIdentifier = (): Identifier => ({ - identifier: `0x${randomBytes(20).toString("hex")}`, - identifierKind: IdentifierKind.Ethereum, -}); - -const toInboxUpdatesCountMap = ( - value: Map | Record, -) => { - if (value instanceof Map) { - return value; - } - - return new Map(Object.entries(value)); -}; - -/** - * Client for interacting with the XMTP network - */ -export class Client { - #client?: NodeClient; - #codecRegistry: CodecRegistry; - #conversations?: Conversations; - #debugInformation?: DebugInformation; - #env?: XmtpEnv; - #preferences?: Preferences; - #signer?: Signer; - #identifier?: Identifier; - #options?: ClientOptions; - - /** - * Creates a new XMTP client instance - * - * This class is not intended to be initialized directly. - * Use `Client.create` or `Client.build` instead. - * - * @param options - Optional configuration for the client - */ - constructor(options?: ClientOptions) { - this.#options = options; - this.#codecRegistry = new CodecRegistry([...(options?.codecs ?? [])]); - } - - /** - * Initializes the client with the provided identifier - * - * This is not meant to be called directly. - * Use `Client.create` or `Client.build` instead. - * - * @param identifier - The identifier to initialize the client with - */ - async init(identifier: Identifier) { - if (this.#client) { - return; - } - - this.#identifier = identifier; - const { client, env } = await createClient(identifier, this.#options); - this.#client = client; - this.#env = env; - const conversations = this.#client.conversations(); - this.#conversations = new Conversations( - this, - this.#codecRegistry, - conversations, - ); - this.#debugInformation = new DebugInformation(this.#client); - this.#preferences = new Preferences(this.#client, conversations); - } - - /** - * Creates a new client instance with a signer - * - * @param signer - The signer to use for authentication - * @param options - Optional configuration for the client - * @returns A new client instance - */ - static async create( - signer: Signer, - options?: Omit & { - codecs?: ContentCodecs; - }, - ) { - const identifier = await signer.getIdentifier(); - const client = new Client>(options); - client.#signer = signer; - await client.init(identifier); - - if (!options?.disableAutoRegister) { - await client.register(); - } - - return client; - } - - /** - * Creates a new client instance with an identifier - * - * Clients created with this method must already be registered. - * Any methods called that require a signer will throw an error. - * - * @param identifier - The identifier to use - * @param options - Optional configuration for the client - * @returns A new client instance - */ - static async build( - identifier: Identifier, - options?: Omit & { - codecs?: ContentCodecs; - }, - ) { - const client = new Client>({ - ...options, - disableAutoRegister: true, - }); - await client.init(identifier); - return client; - } - - /** - * Gets the version of libxmtp used in the bindings - */ - get libxmtpVersion() { - return this.#client?.libxmtpVersion(); - } - - /** - * Gets the app version used by the client - */ - get appVersion() { - return this.#client?.appVersion(); - } - - /** - * Gets the XMTP environment the client is connected to - * - * @throws {ClientNotInitializedError} if the client is not initialized - */ - get env(): XmtpEnv { - if (!this.#env) { - throw new ClientNotInitializedError(); - } - return this.#env; - } - - /** - * Gets the client options - */ - get options() { - return this.#options; - } - - /** - * Gets the signer associated with this client - */ - get signer() { - return this.#signer; - } - - /** - * Gets the account identifier for this client - */ - get accountIdentifier() { - return this.#identifier; - } - - /** - * Gets the inbox ID associated with this client - */ - get inboxId() { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - return this.#client.inboxId(); - } - - /** - * Gets the installation ID for this client - */ - get installationId() { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - return this.#client.installationId(); - } - - /** - * Gets the installation ID bytes for this client - */ - get installationIdBytes() { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - return this.#client.installationIdBytes(); - } - - /** - * Gets whether the client is registered with the XMTP network - * - * @throws {ClientNotInitializedError} if the client is not initialized - */ - get isRegistered() { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - return this.#client.isRegistered(); - } - - /** - * Gets the conversations manager for this client - * - * @throws {ClientNotInitializedError} if the client is not initialized - */ - get conversations() { - if (!this.#conversations) { - throw new ClientNotInitializedError(); - } - return this.#conversations; - } - - /** - * Gets the debug information helpersfor this client - * - * @throws {ClientNotInitializedError} if the client is not initialized - */ - get debugInformation() { - if (!this.#debugInformation) { - throw new ClientNotInitializedError(); - } - return this.#debugInformation; - } - - /** - * Gets the preferences manager for this client - * - * @throws {ClientNotInitializedError} if the client is not initialized - */ - get preferences() { - if (!this.#preferences) { - throw new ClientNotInitializedError(); - } - return this.#preferences; - } - - /** - * Cleanly shuts down the client: cancels in-flight workers and detached - * streams, then releases the database connection. - * - * This is idempotent — calling it more than once resolves without error. - * Await this before deleting the database file or dropping the client - * reference to avoid log noise from background tasks running against a - * closed database. - * - * @throws {ClientNotInitializedError} if the client is not initialized - * @returns Promise that resolves when the client has shut down - */ - async close() { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - return this.#client.close(); - } - - /** - * Adds a signature to a signature request using the client's signer (or the - * provided signer) - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `register`, `unsafe_addAccount`, - * `removeAccount`, `revokeAllOtherInstallations`, or `revokeInstallations` - * methods instead. - * - * @param signatureRequest - The signature request to add the signature to - * @throws {ClientNotInitializedError} if the client is not initialized - * @throws {SignerUnavailableError} if no signer is available - */ - async unsafe_addSignature( - signatureRequest: SignatureRequestHandle, - signer?: Signer, - ) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - if (!this.#signer) { - throw new SignerUnavailableError(); - } - - const finalSigner = signer ?? this.#signer; - const signature = await finalSigner.signMessage( - await signatureRequest.signatureText(), - ); - const identifier = await finalSigner.getIdentifier(); - - switch (finalSigner.type) { - case "SCW": - await signatureRequest.addScwSignature( - identifier, - signature, - finalSigner.getChainId(), - finalSigner.getBlockNumber?.(), - ); - break; - case "EOA": - await signatureRequest.addEcdsaSignature(signature); - break; - } - } - - /** - * Returns a signature request handler for creating a new inbox - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `register` method instead. - * - * @returns The signature text - * @throws {ClientNotInitializedError} if the client is not initialized - */ - async unsafe_createInboxSignatureRequest() { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.createInboxSignatureRequest(); - } - - /** - * Returns a signature request handler for adding a new account to the - * client's inbox - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `unsafe_addAccount` method instead. - * - * The `allowInboxReassign` parameter must be true or this function will - * throw an error. - * - * @param newAccountIdentifier - The identifier of the new account - * @param allowInboxReassign - Whether to allow inbox reassignment - * @returns The signature text - * @throws {ClientNotInitializedError} if the client is not initialized - */ - async unsafe_addAccountSignatureRequest( - newAccountIdentifier: Identifier, - allowInboxReassign: boolean = false, - ) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - if (!allowInboxReassign) { - throw new InboxReassignError(); - } - - return this.#client.addIdentifierSignatureRequest(newAccountIdentifier); - } - - /** - * Returns a signature request handler for removing an account from the - * client's inbox - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `removeAccount` method instead. - * - * @param identifier - The identifier of the account to remove - * @returns The signature text - * @throws {ClientNotInitializedError} if the client is not initialized - */ - async unsafe_removeAccountSignatureRequest(identifier: Identifier) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.revokeIdentifierSignatureRequest(identifier); - } - - /** - * Returns a signature request handler for revoking all other installations - * of the client's inbox - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `revokeAllOtherInstallations` method instead. - * - * @returns The signature text - * @throws {ClientNotInitializedError} if the client is not initialized - */ - async unsafe_revokeAllOtherInstallationsSignatureRequest() { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.revokeAllOtherInstallationsSignatureRequest(); - } - - /** - * Returns a signature request handler for revoking specific installations - * of the client's inbox - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `revokeInstallations` method instead. - * - * @param installationIds - The installation IDs to revoke - * @returns The signature text - * @throws {ClientNotInitializedError} if the client is not initialized - */ - async unsafe_revokeInstallationsSignatureRequest( - installationIds: Uint8Array[], - ) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.revokeInstallationsSignatureRequest(installationIds); - } - - /** - * Returns a signature request handler for changing the recovery identifier - * for this client's inbox - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `changeRecoveryIdentifier` method instead. - * - * @param identifier - The new recovery identifier - * @returns The signature text - * @throws {ClientNotInitializedError} if the client is not initialized - */ - async unsafe_changeRecoveryIdentifierSignatureRequest( - identifier: Identifier, - ) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.changeRecoveryIdentifierSignatureRequest(identifier); - } - - /** - * Applies a signature request to the client - * - * WARNING: This function should be used with caution. It is only provided - * for use in special cases where the provided workflows do not meet the - * requirements of an application. - * - * It is highly recommended to use the `register`, `unsafe_addAccount`, - * `removeAccount`, `revokeAllOtherInstallations`, or `revokeInstallations` - * methods instead. - * - * @throws {ClientNotInitializedError} if the client is not initialized - */ - async unsafe_applySignatureRequest(signatureRequest: SignatureRequestHandle) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.applySignatureRequest(signatureRequest); - } - - /** - * Registers the client with the XMTP network - * - * Requires a signer, use `Client.create` to create a client with a signer. - * - * @throws {ClientNotInitializedError} if the client is not initialized - * @throws {SignerUnavailableError} if no signer is available - */ - async register() { - const signatureRequest = await this.unsafe_createInboxSignatureRequest(); - if (!signatureRequest) { - return; - } - - await this.unsafe_addSignature(signatureRequest); - await this.#client?.registerIdentity( - signatureRequest, - this.#options?.waitForRegistrationVisible, - ); - } - - /** - * Adds a new account to the client inbox - * - * WARNING: This function should be used with caution. Adding a wallet already - * associated with an inbox ID will cause the wallet to lose access to - * that inbox. - * - * The `allowInboxReassign` parameter must be true to reassign an inbox - * already associated with a different account. - * - * Requires a signer, use `Client.create` to create a client with a signer. - * - * @param newAccountSigner - The signer for the new account - * @param allowInboxReassign - Whether to allow inbox reassignment - * @throws {AccountAlreadyAssociatedError} if the account is already associated with an inbox ID - * @throws {ClientNotInitializedError} if the client is not initialized - * @throws {SignerUnavailableError} if no signer is available - */ - async unsafe_addAccount( - newAccountSigner: Signer, - allowInboxReassign: boolean = false, - ) { - // check for existing inbox id - const identifier = await newAccountSigner.getIdentifier(); - const existingInboxId = await this.fetchInboxIdByIdentifier(identifier); - - if (existingInboxId && !allowInboxReassign) { - throw new AccountAlreadyAssociatedError(existingInboxId); - } - - const signatureRequest = await this.unsafe_addAccountSignatureRequest( - identifier, - allowInboxReassign, - ); - - await this.unsafe_addSignature(signatureRequest, newAccountSigner); - await this.unsafe_applySignatureRequest(signatureRequest); - } - - /** - * Removes an account from the client's inbox - * - * Requires a signer, use `Client.create` to create a client with a signer. - * - * @param identifier - The identifier of the account to remove - * @throws {ClientNotInitializedError} if the client is not initialized - * @throws {SignerUnavailableError} if no signer is available - */ - async removeAccount(identifier: Identifier) { - const signatureRequest = - await this.unsafe_removeAccountSignatureRequest(identifier); - - await this.unsafe_addSignature(signatureRequest); - await this.unsafe_applySignatureRequest(signatureRequest); - } - - /** - * Revokes all other installations of the client's inbox - * - * Requires a signer, use `Client.create` to create a client with a signer. - * - * @throws {ClientNotInitializedError} if the client is not initialized - * @throws {SignerUnavailableError} if no signer is available - */ - async revokeAllOtherInstallations() { - const signatureRequest = - await this.unsafe_revokeAllOtherInstallationsSignatureRequest(); - - // no other installations to revoke - if (!signatureRequest) { - return; - } - - await this.unsafe_addSignature(signatureRequest); - await this.unsafe_applySignatureRequest(signatureRequest); - } - - /** - * Revokes specific installations of the client's inbox - * - * Requires a signer, use `Client.create` to create a client with a signer. - * - * @param installationIds - The installation IDs to revoke - * @throws {ClientNotInitializedError} if the client is not initialized - * @throws {SignerUnavailableError} if no signer is available - */ - async revokeInstallations(installationIds: Uint8Array[]) { - const signatureRequest = - await this.unsafe_revokeInstallationsSignatureRequest(installationIds); - - await this.unsafe_addSignature(signatureRequest); - await this.unsafe_applySignatureRequest(signatureRequest); - } - - /** - * Revokes specific installations of the client's inbox without a client - * - * @param signer - The signer to use - * @param inboxId - The inbox ID to revoke installations for - * @param installationIds - The installation IDs to revoke - * @param backend - Optional `Backend` instance created with `createBackend()` - */ - static async revokeInstallations( - signer: Signer, - inboxId: string, - installationIds: Uint8Array[], - backend?: Backend, - ): Promise; - /** - * Revokes specific installations of the client's inbox without a client - * - * @param signer - The signer to use - * @param inboxId - The inbox ID to revoke installations for - * @param installationIds - The installation IDs to revoke - * @param env - The environment to use - * @param gatewayHost - Optional gateway host - * @deprecated Pass a `Backend` instance created with `createBackend()` instead - * of `XmtpEnv` and `gatewayHost`. - */ - static async revokeInstallations( - signer: Signer, - inboxId: string, - installationIds: Uint8Array[], - env?: XmtpEnv, - gatewayHost?: string, - ): Promise; - static async revokeInstallations( - signer: Signer, - inboxId: string, - installationIds: Uint8Array[], - envOrBackend?: XmtpEnv | Backend, - gatewayHost?: string, - ) { - const backend = await resolveBackend(envOrBackend, gatewayHost); - const identifier = await signer.getIdentifier(); - const signatureRequest = await revokeInstallationsSignatureRequest( - backend, - identifier, - inboxId, - installationIds, - ); - const signatureText = await signatureRequest.signatureText(); - const signature = await signer.signMessage(signatureText); - - switch (signer.type) { - case "SCW": - await signatureRequest.addScwSignature( - identifier, - signature, - signer.getChainId(), - signer.getBlockNumber?.(), - ); - break; - case "EOA": - await signatureRequest.addEcdsaSignature(signature); - break; - } - - await applySignatureRequest(backend, signatureRequest); - } - - /** - * Changes the recovery identifier for the client's inbox - * - * Requires a signer, use `Client.create` to create a client with a signer. - * - * @param identifier - The new recovery identifier - * @throws {ClientNotInitializedError} if the client is not initialized - * @throws {SignerUnavailableError} if no signer is available - */ - async changeRecoveryIdentifier(identifier: Identifier) { - const signatureRequest = - await this.unsafe_changeRecoveryIdentifierSignatureRequest(identifier); - - await this.unsafe_addSignature(signatureRequest); - await this.unsafe_applySignatureRequest(signatureRequest); - } - - /** - * Checks if the client can message the specified identifiers - * - * @param identifiers - The identifiers to check - * @returns Whether the client can message the identifiers - * @throws {ClientNotInitializedError} if the client is not initialized - */ - async canMessage(identifiers: Identifier[]) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - const canMessage = await this.#client.canMessage(identifiers); - return new Map(Object.entries(canMessage)); - } - - /** - * Fetches the latest inbox updates count for the specified inbox IDs - * - * @param inboxIds - The inbox IDs to check - * @returns Map of inbox IDs to their updates count - * @throws {ClientNotInitializedError} if the client is not initialized - */ - async fetchLatestInboxUpdatesCount(inboxIds: string[]) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - const result = await this.#client.fetchInboxUpdatesCount(inboxIds, true); - - return toInboxUpdatesCountMap(result); - } - - /** - * Fetches the latest inbox updates count for the client's inbox - * - * @returns The latest inbox updates count - * @throws {ClientNotInitializedError} if the client is not initialized - */ - async fetchOwnInboxUpdatesCount() { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.fetchOwnInboxUpdatesCount(true); - } - - /** - * Fetches the key package statuses from the network for the specified - * installation IDs - * - * @param installationIds - The installation IDs to check - * @returns The key package statuses - * @throws {ClientNotInitializedError} if the client is not initialized - */ - async fetchKeyPackageStatuses(installationIds: string[]) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.fetchKeyPackageStatusesByInstallationIds( - installationIds, - ); - } - - /** - * Fetches the inbox ID for a given identifier from the local database - * If not found, fetches from the network - * - * @param identifier - The identifier to look up - * @returns The inbox ID, if found - * @throws {ClientNotInitializedError} if the client is not initialized - */ - async fetchInboxIdByIdentifier(identifier: Identifier) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.getInboxIdByIdentity(identifier); - } - - /** - * Signs a message with the installation key - * - * @param signatureText - The text to sign - * @returns The signature - * @throws {ClientNotInitializedError} if the client is not initialized - */ - signWithInstallationKey(signatureText: string) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.signWithInstallationKey(signatureText); - } - - /** - * Verifies a signature was made with the installation key - * - * @param signatureText - The text that was signed - * @param signatureBytes - The signature bytes to verify - * @returns Whether the signature is valid - * @throws {ClientNotInitializedError} if the client is not initialized - */ - verifySignedWithInstallationKey( - signatureText: string, - signatureBytes: Uint8Array, - ) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - try { - this.#client.verifySignedWithInstallationKey( - signatureText, - signatureBytes, - ); - return true; - } catch { - return false; - } - } - - /** - * Fetches the inbox states for the specified inbox IDs from the network - * without a client - * - * @param inboxIds - The inbox IDs to get the state for - * @param backend - Optional `Backend` instance created with `createBackend()` - * @returns The inbox states for the specified inbox IDs - */ - static async fetchInboxStates( - inboxIds: string[], - backend?: Backend, - ): Promise; - /** - * Fetches the inbox states for the specified inbox IDs from the network - * without a client - * - * @param inboxIds - The inbox IDs to get the state for - * @param env - The environment to use - * @param gatewayHost - Optional gateway host - * @returns The inbox states for the specified inbox IDs - * @deprecated Pass a `Backend` instance created with `createBackend()` instead - * of `XmtpEnv` and `gatewayHost`. - */ - static async fetchInboxStates( - inboxIds: string[], - env?: XmtpEnv, - gatewayHost?: string, - ): Promise; - static async fetchInboxStates( - inboxIds: string[], - envOrBackend?: XmtpEnv | Backend, - gatewayHost?: string, - ) { - const backend = await resolveBackend(envOrBackend, gatewayHost); - return fetchInboxStatesByInboxIds(backend, inboxIds); - } - - /** - * Fetches the latest inbox updates count for the specified inbox IDs - * without a client - * - * @param inboxIds - The inbox IDs to check - * @param backend - Optional `Backend` instance created with `createBackend()` - * @returns Map of inbox IDs to their updates count - */ - static async fetchLatestInboxUpdatesCount( - inboxIds: string[], - backendOrEnv?: Backend | XmtpEnv, - ): Promise>; - /** - * Fetches the latest inbox updates count for the specified inbox IDs - * without a client - * - * @param inboxIds - The inbox IDs to check - * @param env - The environment to use - * @param gatewayHost - Optional gateway host - * @returns Map of inbox IDs to their updates count - * @deprecated Pass a `Backend` instance created with `createBackend()` instead - * of `XmtpEnv` and `gatewayHost`. - */ - static async fetchLatestInboxUpdatesCount( - inboxIds: string[], - env?: XmtpEnv, - gatewayHost?: string, - ): Promise>; - static async fetchLatestInboxUpdatesCount( - inboxIds: string[], - envOrBackend?: XmtpEnv | Backend, - gatewayHost?: string, - ) { - const backend = await resolveBackend(envOrBackend, gatewayHost); - // The node-bindings Client is a napi-rs class with no explicit close/free - // method. Release is non-deterministic: once this reference goes out of - // scope, JS GC will eventually invoke the Rust Drop impl and reclaim the - // underlying resources. If this becomes a bottleneck, switch to an - // explicit disposal API if/when the bindings expose one. - const { client } = await createClient(createEphemeralIdentifier(), { - backend, - dbPath: null, - disableDeviceSync: true, - }); - const result = await client.fetchInboxUpdatesCount(inboxIds, true); - - return toInboxUpdatesCountMap(result); - } - - /** - * Checks if the specified identifiers can be messaged - * - * @param identifiers - The identifiers to check - * @param backend - Optional `Backend` instance created with `createBackend()` - * @returns Map of identifiers to whether they can be messaged - */ - static async canMessage( - identifiers: Identifier[], - backend?: Backend, - ): Promise>; - /** - * Checks if the specified identifiers can be messaged - * - * @param identifiers - The identifiers to check - * @param env - Optional XMTP environment - * @returns Map of identifiers to whether they can be messaged - * @deprecated Pass a `Backend` instance created with `createBackend()` instead - * of `XmtpEnv`. - */ - /* eslint-disable @typescript-eslint/unified-signatures */ - static async canMessage( - identifiers: Identifier[], - env?: XmtpEnv, - ): Promise>; - /* eslint-enable @typescript-eslint/unified-signatures */ - static async canMessage( - identifiers: Identifier[], - envOrBackend?: XmtpEnv | Backend, - ) { - const backend = await resolveBackend(envOrBackend); - const canMessageMap = new Map(); - for (const identifier of identifiers) { - const inboxId = await getInboxIdForIdentifier(backend, identifier); - canMessageMap.set(identifier.identifier.toLowerCase(), inboxId !== null); - } - return canMessageMap; - } - - /** - * Verifies a signature was made with a public key - * - * @param signatureText - The text that was signed - * @param signatureBytes - The signature bytes to verify - * @param publicKey - The public key to verify against - * @returns Whether the signature is valid - */ - static verifySignedWithPublicKey( - signatureText: string, - signatureBytes: Uint8Array, - publicKey: Uint8Array, - ) { - try { - verifySignedWithPublicKeyBinding( - signatureText, - signatureBytes, - publicKey, - ); - return true; - } catch { - return false; - } - } - - /** - * Checks if an address is authorized for an inbox - * - * @param inboxId - The inbox ID to check - * @param address - The address to check - * @param backend - Optional `Backend` instance created with `createBackend()` - * @returns Whether the address is authorized - */ - static async isAddressAuthorized( - inboxId: string, - address: string, - backend?: Backend, - ): Promise; - /** - * Checks if an address is authorized for an inbox - * - * @param inboxId - The inbox ID to check - * @param address - The address to check - * @param env - The environment to use - * @param gatewayHost - Optional gateway host - * @returns Whether the address is authorized - * @deprecated Pass a `Backend` instance created with `createBackend()` instead - * of `XmtpEnv` and `gatewayHost`. - */ - static async isAddressAuthorized( - inboxId: string, - address: string, - env?: XmtpEnv, - gatewayHost?: string, - ): Promise; - static async isAddressAuthorized( - inboxId: string, - address: string, - envOrBackend?: XmtpEnv | Backend, - gatewayHost?: string, - ): Promise { - const backend = await resolveBackend(envOrBackend, gatewayHost); - return await isAddressAuthorizedBinding(backend, inboxId, address); - } - - /** - * Checks if an installation is authorized for an inbox - * - * @param inboxId - The inbox ID to check - * @param installation - The installation to check - * @param backend - Optional `Backend` instance created with `createBackend()` - * @returns Whether the installation is authorized - */ - static async isInstallationAuthorized( - inboxId: string, - installation: Uint8Array, - backend?: Backend, - ): Promise; - /** - * Checks if an installation is authorized for an inbox - * - * @param inboxId - The inbox ID to check - * @param installation - The installation to check - * @param env - The environment to use - * @param gatewayHost - Optional gateway host - * @returns Whether the installation is authorized - * @deprecated Pass a `Backend` instance created with `createBackend()` instead - * of `XmtpEnv` and `gatewayHost`. - */ - static async isInstallationAuthorized( - inboxId: string, - installation: Uint8Array, - env?: XmtpEnv, - gatewayHost?: string, - ): Promise; - static async isInstallationAuthorized( - inboxId: string, - installation: Uint8Array, - envOrBackend?: XmtpEnv | Backend, - gatewayHost?: string, - ): Promise { - const backend = await resolveBackend(envOrBackend, gatewayHost); - return await isInstallationAuthorizedBinding( - backend, - inboxId, - installation, - ); - } - - /** - * Get the default archive options (consent and messages) - */ - #getDefaultArchiveOptions(): ArchiveOptions { - return { - elements: [ - BackupElementSelectionOption.Consent, - BackupElementSelectionOption.Messages, - ], - excludeDisappearingMessages: false, - }; - } - - /** - * Get the default server URL based on the environment - */ - #getDefaultServerUrl(): string { - const env = this.env; - return HistorySyncUrls[env]; - } - - /** - * Send a sync request to other devices on the network - * - * @param options - Archive options specifying what to sync (defaults to consent and messages) - * @param serverUrl - The server URL for the sync request (defaults to environment-specific URL) - * @returns Promise that resolves when the sync request is sent - */ - async sendSyncRequest(options?: ArchiveOptions, serverUrl?: string) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - const resolvedOptions = options ?? this.#getDefaultArchiveOptions(); - const resolvedServerUrl = serverUrl ?? this.#getDefaultServerUrl(); - - return this.#client - .deviceSync() - .sendSyncRequest(resolvedOptions, resolvedServerUrl); - } - - /** - * Send a sync archive to the sync group - * - * @param pin - The pin used for reference when importing - * @param options - Archive options specifying what to sync (defaults to consent and messages) - * @param serverUrl - The server URL for the sync archive (defaults to environment-specific URL) - * @returns Promise that resolves when the sync archive is sent - */ - async sendSyncArchive( - pin: string, - options?: ArchiveOptions, - serverUrl?: string, - ) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - const resolvedOptions = options ?? this.#getDefaultArchiveOptions(); - const resolvedServerUrl = serverUrl ?? this.#getDefaultServerUrl(); - - return this.#client - .deviceSync() - .sendSyncArchive(resolvedOptions, resolvedServerUrl, pin); - } - - /** - * Process a sync archive that matches the pin given - * - * @param archivePin - Optional pin to match. If not provided, processes the last archive sent - * @returns Promise that resolves when the archive is processed - */ - async processSyncArchive(archivePin?: string | null) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.deviceSync().processSyncArchive(archivePin); - } - - /** - * List the archives available for import in the sync group - * - * You may need to manually sync the sync group before calling - * this function to see recently uploaded archives. - * - * @param daysCutoff - Number of days to look back for archives - * @returns Array of available archive information - */ - listAvailableArchives(daysCutoff: number): AvailableArchiveInfo[] { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.deviceSync().listAvailableArchives(daysCutoff); - } - - /** - * Archive application elements to file for later restoration - * - * @param path - The file path to save the archive - * @param key - Encryption key for the archive - * @param opts - Archive options specifying what to include (defaults to consent and messages) - * @returns Promise that resolves when the archive is created - */ - async createArchive(path: string, key: Uint8Array, opts?: ArchiveOptions) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - const resolvedOpts = opts ?? this.#getDefaultArchiveOptions(); - - return this.#client.deviceSync().createArchive(path, resolvedOpts, key); - } - - /** - * Import a previous archive from a file - * - * @param path - The file path to the archive - * @param key - Encryption key for the archive - * @returns Promise that resolves when the archive is imported - */ - async importArchive(path: string, key: Uint8Array) { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.deviceSync().importArchive(path, key); - } - - /** - * Load the metadata for an archive to see what it contains - * - * Reads only the metadata without loading the entire file, so this function is quick. - * - * @param path - The file path to the archive - * @param key - Encryption key for the archive - * @returns Promise that resolves with the archive metadata - */ - async archiveMetadata( - path: string, - key: Uint8Array, - ): Promise { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.deviceSync().archiveMetadata(path, key); - } - - /** - * Manually sync all device sync groups - * - * @returns Promise that resolves with a summary of the sync operation - */ - async syncAllDeviceSyncGroups(): Promise { - if (!this.#client) { - throw new ClientNotInitializedError(); - } - - return this.#client.deviceSync().syncAllDeviceSyncGroups(); - } -} diff --git a/sdks/node-sdk/src/CodecRegistry.ts b/sdks/node-sdk/src/CodecRegistry.ts deleted file mode 100644 index 901f821d4..000000000 --- a/sdks/node-sdk/src/CodecRegistry.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { - contentTypeToString, - type ContentCodec, - type ContentTypeId, -} from "@xmtp/content-type-primitives"; - -export class CodecRegistry { - #codecs: Map; - - constructor(codecs: ContentCodec[]) { - this.#codecs = new Map( - codecs.map((codec) => [contentTypeToString(codec.contentType), codec]), - ); - } - - /** - * Gets the codec for a given content type - * - * @param contentType - The content type to get the codec for - * @returns The codec, if found - */ - getCodec(contentType: ContentTypeId) { - return this.#codecs.get(contentTypeToString(contentType)) as - | ContentCodec - | undefined; - } -} diff --git a/sdks/node-sdk/src/Conversation.ts b/sdks/node-sdk/src/Conversation.ts deleted file mode 100644 index 6cd28999a..000000000 --- a/sdks/node-sdk/src/Conversation.ts +++ /dev/null @@ -1,483 +0,0 @@ -import { - SortDirection, - type Actions, - type Attachment, - type ConsentState, - type EncodedContent, - type Intent, - type ListMessagesOptions, - type Message, - type MultiRemoteAttachment, - type Reaction, - type RemoteAttachment, - type Reply, - type SendMessageOpts, - type TransactionReference, - type WalletSendCalls, - type Conversation as XmtpConversation, -} from "@xmtp/node-bindings"; -import type { Client } from "@/Client"; -import type { CodecRegistry } from "@/CodecRegistry"; -import { DecodedMessage } from "@/DecodedMessage"; -import { nsToDate } from "@/utils/date"; -import { MissingContentTypeError } from "@/utils/errors"; -import { - createStream, - type StreamCallback, - type StreamOptions, -} from "@/utils/streams"; - -/** - * Represents a conversation - * - * This class is not intended to be initialized directly. - */ -export class Conversation { - #client: Client; - #codecRegistry: CodecRegistry; - #conversation: XmtpConversation; - - /** - * Creates a new conversation instance - * - * @param client - The client instance managing the conversation - * @param codecRegistry - The codec registry instance - * @param conversation - The underlying conversation instance - */ - constructor( - client: Client, - codecRegistry: CodecRegistry, - conversation: XmtpConversation, - ) { - this.#client = client; - this.#codecRegistry = codecRegistry; - this.#conversation = conversation; - } - - /** - * Gets the unique identifier for this conversation - */ - get id() { - return this.#conversation.id(); - } - - /** - * Gets whether this conversation is currently active - */ - get isActive() { - return this.#conversation.isActive(); - } - - /** - * Gets the inbox ID that added this client's inbox to the conversation - */ - get addedByInboxId() { - return this.#conversation.addedByInboxId(); - } - - /** - * Gets the timestamp when the conversation was created in nanoseconds - */ - get createdAtNs() { - return this.#conversation.createdAtNs(); - } - - /** - * Gets the date when the conversation was created - */ - get createdAt() { - return nsToDate(this.createdAtNs); - } - - get topic() { - return `/xmtp/mls/1/g-${this.id}/proto`; - } - - pausedForVersion() { - return this.#conversation.pausedForVersion() ?? undefined; - } - - /** - * Gets HMAC keys for this conversation - * - * @returns The HMAC keys for this conversation - */ - hmacKeys() { - return this.#conversation.hmacKeys(); - } - - /** - * Gets the metadata for this conversation - * - * @returns Promise that resolves with the conversation metadata - */ - async metadata() { - const metadata = await this.#conversation.groupMetadata(); - return { - creatorInboxId: metadata.creatorInboxId(), - conversationType: metadata.conversationType(), - }; - } - - /** - * Gets the members of this conversation - * - * @returns Promise that resolves with the conversation members - */ - async members() { - return this.#conversation.listMembers(); - } - - /** - * Synchronizes conversation data from the network - * - * @returns Promise that resolves when synchronization is complete - */ - async sync() { - return this.#conversation.sync(); - } - - /** - * Creates a stream for new messages in this conversation - * - * @param options - Optional stream options - * @returns Stream instance for new messages - */ - async stream(options?: StreamOptions>) { - const stream = async ( - callback: StreamCallback, - onFail: () => void, - ) => { - if (!options?.disableSync) { - await this.sync(); - } - return this.#conversation.stream(callback, onFail); - }; - const convertMessage = (value: Message) => { - const enrichedMessage = this.#client.conversations.getMessageById( - value.id, - ); - if (enrichedMessage === undefined) { - console.warn(`Streamed message with ID "${value.id}" not found`); - } - return enrichedMessage; - }; - - return createStream(stream, convertMessage, options); - } - - /** - * Decodes, decrypts, and persists a raw envelope from a group message stream. - * - * @param envelopeBytes - Raw protobuf-encoded envelope bytes from the stream - * @returns The processed and stored messages - */ - async processStreamedMessage(envelopeBytes: Uint8Array) { - return this.#conversation.processStreamedGroupMessage(envelopeBytes); - } - - /** - * Publishes pending messages that were sent optimistically - * - * @returns Promise that resolves when publishing is complete - */ - async publishMessages() { - return this.#conversation.publishMessages(); - } - - /** - * Sends a message with configurable delivery behavior - * - * @param encodedContent - The encoded content to send - * @param sendOptions - Options for sending the message - * @param sendOptions.shouldPush - Indicates whether this message should be - * included in push notifications - * @param sendOptions.isOptimistic - Indicates whether this message should be - * sent optimistically and published later via `publishMessages` - * @returns Promise that resolves with the message ID after it has been sent - */ - async send(encodedContent: EncodedContent, sendOptions?: SendMessageOpts) { - if (!encodedContent.type) { - throw new MissingContentTypeError(); - } - return this.#conversation.send( - encodedContent, - sendOptions ?? { shouldPush: false }, - ); - } - - /** - * Sends a text message - * - * @param text - The text to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendText(text: string, isOptimistic?: boolean) { - return this.#conversation.sendText(text, isOptimistic); - } - - /** - * Sends a markdown message - * - * @param markdown - The markdown to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendMarkdown(markdown: string, isOptimistic?: boolean) { - return this.#conversation.sendMarkdown(markdown, isOptimistic); - } - - /** - * Sends a reaction message - * - * @param reaction - The reaction to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendReaction(reaction: Reaction, isOptimistic?: boolean) { - return this.#conversation.sendReaction(reaction, isOptimistic); - } - - /** - * Sends a read receipt message - * - * @param readReceipt - The read receipt to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendReadReceipt(isOptimistic?: boolean) { - return this.#conversation.sendReadReceipt(isOptimistic); - } - - /** - * Sends a reply message - * - * @param reply - The reply to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendReply(reply: Reply, isOptimistic?: boolean) { - return this.#conversation.sendReply(reply, isOptimistic); - } - - /** - * Sends a transaction reference message - * - * @param transactionReference - The transaction reference to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendTransactionReference( - transactionReference: TransactionReference, - isOptimistic?: boolean, - ) { - return this.#conversation.sendTransactionReference( - transactionReference, - isOptimistic, - ); - } - - /** - * Sends a wallet send calls message - * - * @param walletSendCalls - The wallet send calls to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendWalletSendCalls( - walletSendCalls: WalletSendCalls, - isOptimistic?: boolean, - ) { - return this.#conversation.sendWalletSendCalls( - walletSendCalls, - isOptimistic, - ); - } - - /** - * Sends a actions message - * - * @param actions - The actions to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendActions(actions: Actions, isOptimistic?: boolean) { - return this.#conversation.sendActions(actions, isOptimistic); - } - - /** - * Sends a intent message - * - * @param intent - The intent to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendIntent(intent: Intent, isOptimistic?: boolean) { - return this.#conversation.sendIntent(intent, isOptimistic); - } - - /** - * Sends an attachment message - * - * @param attachment - The attachment to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendAttachment(attachment: Attachment, isOptimistic?: boolean) { - return this.#conversation.sendAttachment(attachment, isOptimistic); - } - - /** - * Sends a multi remote attachment message - * - * @param multiRemoteAttachment - The multi remote attachment to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendMultiRemoteAttachment( - multiRemoteAttachment: MultiRemoteAttachment, - isOptimistic?: boolean, - ) { - return this.#conversation.sendMultiRemoteAttachment( - multiRemoteAttachment, - isOptimistic, - ); - } - - /** - * Sends a remote attachment message - * - * @param remoteAttachment - The remote attachment to send - * @param isOptimistic - Whether to send the message optimistically - * @returns Promise that resolves with the message ID after it has been sent - */ - async sendRemoteAttachment( - remoteAttachment: RemoteAttachment, - isOptimistic?: boolean, - ) { - return this.#conversation.sendRemoteAttachment( - remoteAttachment, - isOptimistic, - ); - } - - /** - * Lists messages in this conversation - * - * @param options - Optional filtering and pagination options - * @returns Promise that resolves with an array of decoded messages - */ - async messages(options?: ListMessagesOptions) { - const messages = await this.#conversation.listEnrichedMessages(options); - return messages.map( - (message) => - new DecodedMessage(this.#codecRegistry, message), - ); - } - - /** - * Counts messages in this conversation - * - * @param options - Optional filtering options - * @returns Promise that resolves with the count of messages - */ - async countMessages( - options?: Omit, - ) { - const count = await this.#conversation.countMessages(options); - return count; - } - - /** - * Gets the last message in this conversation - * - * @returns Promise that resolves with the last message or undefined if none exists - */ - async lastMessage() { - const messages = await this.messages({ - limit: 1, - direction: SortDirection.Descending, - }); - if (messages.length > 0) { - return messages[0]; - } - return undefined; - } - - /** - * Gets the consent state for this conversation - */ - consentState() { - return this.#conversation.consentState(); - } - - /** - * Updates the consent state for this conversation - * - * @param consentState - The new consent state to set - */ - updateConsentState(consentState: ConsentState) { - this.#conversation.updateConsentState(consentState); - } - - /** - * Gets the message disappearing settings for this conversation - * - * @returns The current message disappearing settings or undefined if not set - */ - messageDisappearingSettings() { - return this.#conversation.messageDisappearingSettings() ?? undefined; - } - - /** - * Updates message disappearing settings for this conversation - * - * @param fromNs - The timestamp from which messages should start disappearing - * @param inNs - The duration after which messages should disappear - * @returns Promise that resolves when the update is complete - */ - async updateMessageDisappearingSettings(fromNs: bigint, inNs: bigint) { - return this.#conversation.updateMessageDisappearingSettings({ - fromNs, - inNs, - }); - } - - /** - * Removes message disappearing settings from this conversation - * - * @returns Promise that resolves when the settings are removed - */ - async removeMessageDisappearingSettings() { - return this.#conversation.removeMessageDisappearingSettings(); - } - - /** - * Checks if message disappearing is enabled for this conversation - * - * @returns Whether message disappearing is enabled - */ - isMessageDisappearingEnabled() { - return this.#conversation.isMessageDisappearingEnabled(); - } - - /** - * Retrieves information for this conversation to help with debugging - * - * @returns The debug information for this conversation - */ - async debugInfo() { - return this.#conversation.debugInfo(); - } - - /** - * Retrieves the last read times for this conversation - * - * @returns A map keyed by inbox ID with the last read timestamp - * (nanoseconds since epoch) - */ - async lastReadTimes() { - return this.#conversation.lastReadTimes(); - } -} diff --git a/sdks/node-sdk/src/Conversations.ts b/sdks/node-sdk/src/Conversations.ts deleted file mode 100644 index 58f133745..000000000 --- a/sdks/node-sdk/src/Conversations.ts +++ /dev/null @@ -1,581 +0,0 @@ -import { - ConversationType, - type ConsentState, - type Conversation, - type CreateDmOptions, - type CreateGroupOptions, - type Identifier, - type ListConversationsOptions, - type Message, - type Conversations as XmtpConversations, - type DecodedMessage as XmtpDecodedMessage, -} from "@xmtp/node-bindings"; -import type { Client } from "@/Client"; -import type { CodecRegistry } from "@/CodecRegistry"; -import { DecodedMessage } from "@/DecodedMessage"; -import { Dm } from "@/Dm"; -import { Group } from "@/Group"; -import { - createStream, - type StreamCallback, - type StreamOptions, -} from "@/utils/streams"; - -/** - * Manages conversations - * - * This class is not intended to be initialized directly. - */ -export class Conversations { - #client: Client; - #codecRegistry: CodecRegistry; - #conversations: XmtpConversations; - - /** - * Creates a new conversations instance - * - * @param client - The client instance managing the conversations - * @param codecRegistry - The codec registry instance - * @param conversations - The underlying conversations instance - */ - constructor( - client: Client, - codecRegistry: CodecRegistry, - conversations: XmtpConversations, - ) { - this.#client = client; - this.#codecRegistry = codecRegistry; - this.#conversations = conversations; - } - - get topic() { - return `/xmtp/mls/1/w-${this.#client.installationId}/proto`; - } - - /** - * Retrieves a conversation by its ID - * - * @param id - The conversation ID to look up - * @returns The conversation if found, undefined otherwise - * @see https://docs.xmtp.org/chat-apps/core-messaging/create-conversations#conversation-helper-methods - */ - async getConversationById(id: string) { - try { - // getConversationById will throw if group is not found - const group = this.#conversations.getConversationById(id); - const metadata = await group.groupMetadata(); - switch (metadata.conversationType()) { - case ConversationType.Group: - return new Group( - this.#client, - this.#codecRegistry, - group, - ); - case ConversationType.Dm: - return new Dm(this.#client, this.#codecRegistry, group); - default: - return undefined; - } - } catch { - return undefined; - } - } - - /** - * Retrieves a DM by inbox ID - * - * @param inboxId - The inbox ID to look up - * @returns The DM if found, undefined otherwise - * @see https://docs.xmtp.org/chat-apps/core-messaging/create-conversations#conversation-helper-methods - */ - getDmByInboxId(inboxId: string) { - try { - // getDmByInboxId will throw if group is not found - const group = this.#conversations.getDmByInboxId(inboxId); - return new Dm(this.#client, this.#codecRegistry, group); - } catch { - return undefined; - } - } - - /** - * Retrieves a DM by identifier - * - * @param identifier - The identifier to look up - * @returns Promise that resolves with the DM, if found - * @see https://docs.xmtp.org/chat-apps/core-messaging/create-conversations#conversation-helper-methods - */ - async fetchDmByIdentifier(identifier: Identifier) { - const inboxId = await this.#client.fetchInboxIdByIdentifier(identifier); - if (!inboxId) { - return undefined; - } - return this.getDmByInboxId(inboxId); - } - - /** - * Retrieves a message by its ID - * - * @param id - The message ID to look up - * @returns The decoded message if found, undefined otherwise - * @see https://docs.xmtp.org/chat-apps/core-messaging/create-conversations#conversation-helper-methods - */ - getMessageById(id: string) { - try { - // getEnrichedMessageById will throw if message is not found - const message = this.#conversations.getEnrichedMessageById(id); - return new DecodedMessage(this.#codecRegistry, message); - } catch { - return undefined; - } - } - - /** - * Creates a new group conversation without publishing to the network - * - * @param options - Optional group creation options - * @returns The new group - * @see https://docs.xmtp.org/chat-apps/core-messaging/create-conversations#optimistically-create-a-new-group-chat - */ - createGroupOptimistic(options?: CreateGroupOptions) { - const group = this.#conversations.createGroupOptimistic(options); - return new Group(this.#client, this.#codecRegistry, group); - } - - /** - * Creates a new group conversation with the specified identifiers - * - * @param identifiers - Array of identifiers for group members - * @param options - Optional group creation options - * @returns The new group - * @see https://docs.xmtp.org/chat-apps/core-messaging/create-conversations#create-a-new-group-chat - */ - async createGroupWithIdentifiers( - identifiers: Identifier[], - options?: CreateGroupOptions, - ) { - const group = await this.#conversations.createGroupByIdentity( - identifiers, - options, - ); - const conversation = new Group( - this.#client, - this.#codecRegistry, - group, - ); - return conversation; - } - - /** - * Creates a new group conversation with the specified inbox IDs - * - * @param inboxIds - Array of inbox IDs for group members - * @param options - Optional group creation options - * @returns The new group - * @see https://docs.xmtp.org/chat-apps/core-messaging/create-conversations#create-a-new-group-chat - */ - async createGroup(inboxIds: string[], options?: CreateGroupOptions) { - const group = await this.#conversations.createGroup(inboxIds, options); - const conversation = new Group( - this.#client, - this.#codecRegistry, - group, - ); - return conversation; - } - - /** - * Creates a new DM conversation with the specified identifier - * - * @param identifier - Identifier for the DM recipient - * @param options - Optional DM creation options - * @returns The new DM - * @see https://docs.xmtp.org/agents/build-agents/create-conversations#by-ethereum-address-1 - */ - async createDmWithIdentifier( - identifier: Identifier, - options?: CreateDmOptions, - ) { - const group = await this.#conversations.createDmByIdentity( - identifier, - options, - ); - const conversation = new Dm( - this.#client, - this.#codecRegistry, - group, - ); - return conversation; - } - - /** - * Creates a new DM conversation with the specified inbox ID - * - * @param inboxId - Inbox ID for the DM recipient - * @param options - Optional DM creation options - * @returns The new DM - * @see https://docs.xmtp.org/agents/build-agents/create-conversations#by-inbox-id-1 - */ - async createDm(inboxId: string, options?: CreateDmOptions) { - const group = await this.#conversations.createDm(inboxId, options); - const conversation = new Dm( - this.#client, - this.#codecRegistry, - group, - ); - return conversation; - } - - /** - * Lists all conversations with optional filtering - * - * @param options - Optional filtering and pagination options - * @returns Array of conversations - * @see https://docs.xmtp.org/chat-apps/list-stream-sync/list - */ - async list(options?: ListConversationsOptions) { - const groups = this.#conversations.list(options); - const conversations = await Promise.all( - groups.map(async (item) => { - const metadata = await item.conversation.groupMetadata(); - const conversationType = metadata.conversationType(); - switch (conversationType) { - case ConversationType.Dm: - return new Dm( - this.#client, - this.#codecRegistry, - item.conversation, - ); - case ConversationType.Group: - return new Group( - this.#client, - this.#codecRegistry, - item.conversation, - ); - default: - return undefined; - } - }), - ); - return conversations.filter((conversation) => conversation !== undefined); - } - - /** - * Lists all groups with optional filtering - * - * @param options - Optional filtering and pagination options - * @returns Array of groups - * @see https://docs.xmtp.org/chat-apps/list-stream-sync/list#list-existing-conversations - */ - listGroups(options?: Omit) { - const groups = this.#conversations.list({ - ...(options ?? {}), - conversationType: ConversationType.Group, - }); - return groups.map((item) => { - const conversation = new Group( - this.#client, - this.#codecRegistry, - item.conversation, - ); - return conversation; - }); - } - - /** - * Lists all DMs with optional filtering - * - * @param options - Optional filtering and pagination options - * @returns Array of DMs - * @see https://docs.xmtp.org/chat-apps/list-stream-sync/list#list-existing-conversations - */ - listDms(options?: Omit) { - const groups = this.#conversations.list({ - ...(options ?? {}), - conversationType: ConversationType.Dm, - }); - return groups.map((item) => { - const conversation = new Dm( - this.#client, - this.#codecRegistry, - item.conversation, - ); - return conversation; - }); - } - - /** - * Synchronizes conversations for the current client from the network - * - * @returns Promise that resolves when sync is complete - * @see https://docs.xmtp.org/chat-apps/list-stream-sync/sync-and-syncall - */ - async sync() { - return this.#conversations.sync(); - } - - /** - * Synchronizes all conversations and messages from the network with optional - * consent state filtering - * - * @param consentStates - Optional array of consent states to filter by - * @returns Promise that resolves when sync is complete - * @see https://docs.xmtp.org/chat-apps/list-stream-sync/sync-and-syncall#sync-all-new-welcomes-conversations-messages-and-preferences - */ - async syncAll(consentStates?: ConsentState[]) { - return this.#conversations.syncAll(consentStates); - } - - /** - * Creates a stream for new conversations - * - * @param options - Optional stream options - * @param options.conversationType - Optional conversation type to filter by - * @returns Stream instance for new conversations - * @see https://docs.xmtp.org/chat-apps/list-stream-sync/stream#stream-new-group-chat-and-dm-conversations - */ - async stream( - options?: StreamOptions< - Conversation, - Group | Dm | undefined - > & { - conversationType?: ConversationType; - }, - ) { - const stream = async ( - callback: StreamCallback, - onFail: () => void, - ) => { - if (!options?.disableSync) { - await this.sync(); - } - return this.#conversations.stream( - callback, - onFail, - options?.conversationType, - ); - }; - const convertConversation = async (value: Conversation) => { - const metadata = await value.groupMetadata(); - const conversationType = metadata.conversationType(); - switch (conversationType) { - case ConversationType.Dm: - return new Dm(this.#client, this.#codecRegistry, value); - case ConversationType.Group: - return new Group( - this.#client, - this.#codecRegistry, - value, - ); - default: - console.warn(`Unknown conversation type: ${conversationType}`); - return undefined; - } - }; - - return createStream(stream, convertConversation, options); - } - - /** - * Creates a stream for new group conversations - * - * @param options - Optional stream options - * @returns Stream instance for new group conversations - * @see https://docs.xmtp.org/chat-apps/list-stream-sync/stream#stream-new-group-chat-and-dm-conversations - */ - async streamGroups( - options?: StreamOptions>, - ) { - const stream = async ( - callback: StreamCallback, - onFail: () => void, - ) => { - if (!options?.disableSync) { - await this.sync(); - } - return this.#conversations.stream( - callback, - onFail, - ConversationType.Group, - ); - }; - const convertConversation = (value: Conversation) => { - return new Group(this.#client, this.#codecRegistry, value); - }; - - return createStream(stream, convertConversation, options); - } - - /** - * Creates a stream for new DM conversations - * - * @param options - Optional stream options - * @returns Stream instance for new DM conversations - * @see https://docs.xmtp.org/chat-apps/list-stream-sync/stream#stream-new-group-chat-and-dm-conversations - */ - async streamDms(options?: StreamOptions>) { - const stream = async ( - callback: StreamCallback, - onFail: () => void, - ) => { - if (!options?.disableSync) { - await this.sync(); - } - return this.#conversations.stream(callback, onFail, ConversationType.Dm); - }; - const convertConversation = (value: Conversation) => { - return new Dm(this.#client, this.#codecRegistry, value); - }; - - return createStream(stream, convertConversation, options); - } - - /** - * Creates a stream for all new messages - * - * @param options - Optional stream options - * @param options.conversationType - Optional conversation type to filter by - * @param options.consentStates - Optional array of consent states to filter by - * @returns Stream instance for new messages - * @see https://docs.xmtp.org/chat-apps/list-stream-sync/stream#stream-new-group-chat-and-dm-messages - */ - async streamAllMessages( - options?: StreamOptions> & { - conversationType?: ConversationType; - consentStates?: ConsentState[]; - }, - ) { - const streamAllMessages = async ( - callback: StreamCallback, - onFail: () => void, - ) => { - if (!options?.disableSync) { - await this.syncAll(options?.consentStates); - } - return this.#conversations.streamAllMessages( - callback, - onFail, - options?.conversationType, - options?.consentStates, - ); - }; - const convertMessage = (value: Message) => { - const enrichedMessage = this.getMessageById(value.id); - if (enrichedMessage === undefined) { - console.warn(`Streamed message with ID "${value.id}" not found`); - } - return enrichedMessage; - }; - return createStream(streamAllMessages, convertMessage, options); - } - - /** - * Creates a stream for all new group messages - * - * @param options - Optional stream options - * @param options.consentStates - Optional array of consent states to filter by - * @returns Stream instance for new group messages - * @see https://docs.xmtp.org/chat-apps/list-stream-sync/stream#stream-new-group-chat-and-dm-messages - */ - async streamAllGroupMessages( - options?: StreamOptions> & { - consentStates?: ConsentState[]; - }, - ) { - return this.streamAllMessages({ - ...(options ?? {}), - conversationType: ConversationType.Group, - consentStates: options?.consentStates, - }); - } - - /** - * Creates a stream for all new DM messages - * - * @param options - Optional stream options - * @param options.consentStates - Optional array of consent states to filter by - * @returns Stream instance for new DM messages - * @see https://docs.xmtp.org/chat-apps/list-stream-sync/stream#stream-new-group-chat-and-dm-messages - */ - async streamAllDmMessages( - options?: StreamOptions> & { - consentStates?: ConsentState[]; - }, - ) { - return this.streamAllMessages({ - ...(options ?? {}), - conversationType: ConversationType.Dm, - consentStates: options?.consentStates, - }); - } - - /** - * Creates a stream for message deletions that streams the message IDs of - * deleted messages - * - * This is a local stream, does not require network sync, and will not fail - * like other streams. - * - * @param options - Optional stream options - * @returns Stream instance for message deletions - * @deprecated Use streamDeletedMessages instead - */ - async streamMessageDeletions( - options?: Omit< - StreamOptions, - | "disableSync" - | "onFail" - | "onRetry" - | "onRestart" - | "retryAttempts" - | "retryDelay" - | "retryOnFail" - >, - ) { - const stream = async (callback: StreamCallback) => { - return this.#conversations.streamMessageDeletions(callback); - }; - const convertMessage = (value: XmtpDecodedMessage) => value.id; - return createStream(stream, convertMessage, options); - } - - /** - * Creates a stream for message deletions that streams the deleted messages - * - * This is a local stream, does not require network sync, and will not fail - * like other streams. - * - * @param options - Optional stream options - * @returns Stream instance for message deletions - */ - async streamDeletedMessages( - options?: Omit< - StreamOptions>, - | "disableSync" - | "onFail" - | "onRetry" - | "onRestart" - | "retryAttempts" - | "retryDelay" - | "retryOnFail" - >, - ) { - const stream = async (callback: StreamCallback) => { - return this.#conversations.streamMessageDeletions(callback); - }; - const convertMessage = (value: XmtpDecodedMessage) => { - return new DecodedMessage(this.#codecRegistry, value); - }; - return createStream(stream, convertMessage, options); - } - - /** - * Gets the HMAC keys for all conversations - * - * @returns The HMAC keys for all conversations - * @see https://docs.xmtp.org/chat-apps/push-notifs/push-notifs#get-hmac-keys-for-a-conversation - */ - hmacKeys() { - return this.#conversations.hmacKeys(); - } -} diff --git a/sdks/node-sdk/src/DebugInformation.ts b/sdks/node-sdk/src/DebugInformation.ts deleted file mode 100644 index 851fe48c6..000000000 --- a/sdks/node-sdk/src/DebugInformation.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { Client } from "@xmtp/node-bindings"; - -/** - * Debug information helpers for the client - * - * This class is not intended to be initialized directly. - */ -export class DebugInformation { - #client: Client; - - constructor(client: Client) { - this.#client = client; - } - - apiStatistics() { - return this.#client.apiStatistics(); - } - - apiIdentityStatistics() { - return this.#client.apiIdentityStatistics(); - } - - apiAggregateStatistics() { - return this.#client.apiAggregateStatistics(); - } - - clearAllStatistics() { - this.#client.clearAllStatistics(); - } -} diff --git a/sdks/node-sdk/src/DecodedMessage.ts b/sdks/node-sdk/src/DecodedMessage.ts deleted file mode 100644 index cf9d225df..000000000 --- a/sdks/node-sdk/src/DecodedMessage.ts +++ /dev/null @@ -1,263 +0,0 @@ -import { contentTypeToString } from "@xmtp/content-type-primitives"; -import { - contentTypeActions, - contentTypeAttachment, - contentTypeGroupUpdated, - contentTypeIntent, - contentTypeLeaveRequest, - contentTypeMarkdown, - contentTypeMultiRemoteAttachment, - contentTypeReaction, - contentTypeReadReceipt, - contentTypeRemoteAttachment, - contentTypeReply, - contentTypeText, - contentTypeTransactionReference, - contentTypeWalletSendCalls, - DecodedMessageContentType, - type ContentTypeId, - type DecodedMessageContent, - type DeliveryStatus, - type EncodedContent, - type EnrichedReply, - type GroupMessageKind, - type Reaction, - type DecodedMessage as XmtpDecodedMessage, -} from "@xmtp/node-bindings"; -import type { CodecRegistry } from "@/CodecRegistry"; -import { nsToDate } from "@/utils/date"; - -const getContentFromDecodedMessageContent = ( - content: DecodedMessageContent, -): T => { - switch (content.type) { - case DecodedMessageContentType.Text: { - return content.text as T; - } - case DecodedMessageContentType.Markdown: { - return content.markdown as T; - } - case DecodedMessageContentType.Reply: { - return content.reply as T; - } - case DecodedMessageContentType.Reaction: { - return content.reaction as T; - } - case DecodedMessageContentType.Attachment: { - return content.attachment as T; - } - case DecodedMessageContentType.RemoteAttachment: { - return content.remoteAttachment as T; - } - case DecodedMessageContentType.MultiRemoteAttachment: { - return content.multiRemoteAttachment as T; - } - case DecodedMessageContentType.TransactionReference: { - return content.transactionReference as T; - } - case DecodedMessageContentType.GroupUpdated: { - return content.groupUpdated as T; - } - case DecodedMessageContentType.ReadReceipt: { - return content.readReceipt as T; - } - case DecodedMessageContentType.LeaveRequest: { - return content.leaveRequest as T; - } - case DecodedMessageContentType.WalletSendCalls: { - return content.walletSendCalls as T; - } - case DecodedMessageContentType.Actions: { - return content.actions as T; - } - case DecodedMessageContentType.Intent: { - return content.intent as T; - } - case DecodedMessageContentType.DeletedMessage: { - return content.deletedMessage as T; - } - case DecodedMessageContentType.Custom: { - return content.custom as T; - } - default: - content.type satisfies never; - return null as T; - } -}; - -const getContentTypeFromDecodedMessageContent = ( - content: DecodedMessageContent, -): ContentTypeId | undefined => { - switch (content.type) { - case DecodedMessageContentType.Text: { - return contentTypeText(); - } - case DecodedMessageContentType.Markdown: { - return contentTypeMarkdown(); - } - case DecodedMessageContentType.Reply: { - return contentTypeReply(); - } - case DecodedMessageContentType.Reaction: { - return contentTypeReaction(); - } - case DecodedMessageContentType.Attachment: { - return contentTypeAttachment(); - } - case DecodedMessageContentType.RemoteAttachment: { - return contentTypeRemoteAttachment(); - } - case DecodedMessageContentType.MultiRemoteAttachment: { - return contentTypeMultiRemoteAttachment(); - } - case DecodedMessageContentType.TransactionReference: { - return contentTypeTransactionReference(); - } - case DecodedMessageContentType.GroupUpdated: { - return contentTypeGroupUpdated(); - } - case DecodedMessageContentType.ReadReceipt: { - return contentTypeReadReceipt(); - } - case DecodedMessageContentType.LeaveRequest: { - return contentTypeLeaveRequest(); - } - case DecodedMessageContentType.WalletSendCalls: { - return contentTypeWalletSendCalls(); - } - case DecodedMessageContentType.Actions: { - return contentTypeActions(); - } - case DecodedMessageContentType.Intent: { - return contentTypeIntent(); - } - case DecodedMessageContentType.DeletedMessage: { - return undefined; - } - case DecodedMessageContentType.Custom: { - return content.custom?.type; - } - default: - content.type satisfies never; - return undefined; - } -}; - -/** - * Represents a decoded XMTP message - * - * @class - * @property {unknown} content - The decoded content of the message - * @property {ContentTypeId} contentType - The content type of the message content - * @property {string} conversationId - Unique identifier for the conversation - * @property {MessageDeliveryStatus} deliveryStatus - Current delivery status of the message ("unpublished" | "published" | "failed") - * @property {bigint} expiresAtNs - Timestamp when the message will expire (in nanoseconds) - * @property {Date} expiresAt - Timestamp when the message will expire - * @property {string} [fallback] - Optional fallback text for the message - * @property {string} id - Unique identifier for the message - * @property {MessageKind} kind - Type of message ("application" | "membership_change") - * @property {number} numReplies - Number of replies to the message - * @property {DecodedMessage[]} reactions - Reactions to the message - * @property {string} senderInboxId - Identifier for the sender's inbox - * @property {Date} sentAt - Timestamp when the message was sent - * @property {bigint} sentAtNs - Timestamp when the message was sent (in nanoseconds) - */ -export class DecodedMessage { - content: ContentTypes | undefined; - contentType: ContentTypeId; - conversationId: string; - deliveryStatus: DeliveryStatus; - expiresAtNs?: bigint; - expiresAt?: Date; - fallback?: string; - id: string; - kind: GroupMessageKind; - numReplies: number; - reactions: DecodedMessage[]; - senderInboxId: string; - sentAt: Date; - sentAtNs: bigint; - - constructor(codecRegistry: CodecRegistry, message: XmtpDecodedMessage) { - this.id = message.id; - this.expiresAtNs = message.expiresAtNs ?? undefined; - this.expiresAt = message.expiresAtNs - ? nsToDate(message.expiresAtNs) - : undefined; - this.sentAtNs = message.sentAtNs; - this.sentAt = nsToDate(message.sentAtNs); - this.conversationId = message.conversationId; - this.senderInboxId = message.senderInboxId; - this.contentType = message.contentType; - this.fallback = message.fallback ?? undefined; - this.kind = message.kind; - this.deliveryStatus = message.deliveryStatus; - - this.numReplies = message.numReplies; - this.reactions = message.reactions.map( - (reaction) => new DecodedMessage(codecRegistry, reaction), - ); - - this.content = - getContentFromDecodedMessageContent(message.content) ?? - undefined; - - switch (message.content.type) { - case DecodedMessageContentType.Reply: { - const reply = message.content.reply as EnrichedReply; - let replyContent = getContentFromDecodedMessageContent( - reply.content, - ); - if (reply.content.type === DecodedMessageContentType.Custom) { - const codec = codecRegistry.getCodec( - reply.content.custom?.type as ContentTypeId, - ); - if (codec) { - try { - replyContent = codec.decode(replyContent as EncodedContent); - } catch (error) { - if (error instanceof Error) { - console.warn(`Error decoding custom content: ${error.message}`); - } else { - console.warn(`Error decoding custom content`); - } - } - } - } - this.content = { - referenceId: reply.referenceId, - content: replyContent, - contentType: getContentTypeFromDecodedMessageContent(reply.content), - inReplyTo: reply.inReplyTo - ? new DecodedMessage(codecRegistry, reply.inReplyTo) - : null, - } as ContentTypes; - break; - } - case DecodedMessageContentType.Custom: { - const customContent = message.content.custom; - if (customContent !== null) { - const codec = codecRegistry.getCodec(this.contentType); - if (codec) { - try { - this.content = codec.decode(customContent); - } catch (error) { - if (error instanceof Error) { - console.warn(`Error decoding custom content: ${error.message}`); - } else { - console.warn(`Error decoding custom content`); - } - this.content = undefined; - } - } else { - console.warn( - `No codec found for content type "${contentTypeToString(this.contentType)}"`, - ); - this.content = undefined; - } - } - break; - } - } - } -} diff --git a/sdks/node-sdk/src/Dm.ts b/sdks/node-sdk/src/Dm.ts deleted file mode 100644 index 55bd0f9b3..000000000 --- a/sdks/node-sdk/src/Dm.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { Conversation as XmtpConversation } from "@xmtp/node-bindings"; -import type { Client } from "@/Client"; -import type { CodecRegistry } from "@/CodecRegistry"; -import { Conversation } from "@/Conversation"; - -/** - * Represents a direct message conversation between two inboxes - * - * This class is not intended to be initialized directly. - */ -export class Dm extends Conversation { - #client: Client; - #codecRegistry: CodecRegistry; - #conversation: XmtpConversation; - - /** - * Creates a new direct message conversation instance - * - * @param client - The client instance managing this direct message conversation - * @param codecRegistry - The codec registry instance - * @param conversation - The underlying conversation instance - */ - constructor( - client: Client, - codecRegistry: CodecRegistry, - conversation: XmtpConversation, - ) { - super(client, codecRegistry, conversation); - this.#client = client; - this.#codecRegistry = codecRegistry; - this.#conversation = conversation; - } - - /** - * Retrieves the inbox ID of the other participant in the DM - * - * @returns Promise that resolves with the peer's inbox ID - */ - get peerInboxId() { - return this.#conversation.dmPeerInboxId(); - } - - async duplicateDms() { - const duplicateDms = await this.#conversation.duplicateDms(); - return duplicateDms.map( - (dm) => new Dm(this.#client, this.#codecRegistry, dm), - ); - } -} diff --git a/sdks/node-sdk/src/Group.ts b/sdks/node-sdk/src/Group.ts deleted file mode 100644 index 71c618ff5..000000000 --- a/sdks/node-sdk/src/Group.ts +++ /dev/null @@ -1,255 +0,0 @@ -import { - GroupMembershipState, - type Identifier, - type MetadataField, - type PermissionPolicy, - type PermissionUpdateType, - type Conversation as XmtpConversation, -} from "@xmtp/node-bindings"; -import type { Client } from "@/Client"; -import type { CodecRegistry } from "@/CodecRegistry"; -import { Conversation } from "@/Conversation"; - -/** - * Represents a group conversation between multiple inboxes - * - * This class is not intended to be initialized directly. - */ -export class Group extends Conversation { - #conversation: XmtpConversation; - - /** - * Creates a new group conversation instance - * - * @param client - The client instance managing this group conversation - * @param codecRegistry - The codec registry instance - * @param conversation - The underlying conversation object - */ - constructor( - client: Client, - codecRegistry: CodecRegistry, - conversation: XmtpConversation, - ) { - super(client, codecRegistry, conversation); - this.#conversation = conversation; - } - - /** - * The name of the group - */ - get name() { - return this.#conversation.groupName(); - } - - /** - * Updates the group's name - * - * @param name The new name for the group - */ - async updateName(name: string) { - return this.#conversation.updateGroupName(name); - } - - /** - * The image URL of the group - */ - get imageUrl() { - return this.#conversation.groupImageUrlSquare(); - } - - /** - * Updates the group's image URL - * - * @param imageUrl The new image URL for the group - */ - async updateImageUrl(imageUrl: string) { - return this.#conversation.updateGroupImageUrlSquare(imageUrl); - } - - /** - * The description of the group - */ - get description() { - return this.#conversation.groupDescription(); - } - - /** - * Updates the group's description - * - * @param description The new description for the group - */ - async updateDescription(description: string) { - return this.#conversation.updateGroupDescription(description); - } - - /** - * The app data of the group - */ - get appData() { - return this.#conversation.appData(); - } - - /** - * Updates the group's app data (max 8192 bytes) - * - * @param appData The new app data for the group - */ - async updateAppData(appData: string) { - return this.#conversation.updateAppData(appData); - } - - /** - * The permissions of the group - */ - permissions() { - const permissions = this.#conversation.groupPermissions(); - return { - policyType: permissions.policyType(), - policySet: permissions.policySet(), - }; - } - - /** - * Updates a specific permission policy for the group - * - * @param permissionType The type of permission to update - * @param policy The new permission policy - * @param metadataField Optional metadata field for the permission - */ - async updatePermission( - permissionType: PermissionUpdateType, - policy: PermissionPolicy, - metadataField?: MetadataField, - ) { - return this.#conversation.updatePermissionPolicy( - permissionType, - policy, - metadataField, - ); - } - - /** - * The list of admins of the group - */ - listAdmins() { - return this.#conversation.listAdmins(); - } - - /** - * The list of super admins of the group - */ - listSuperAdmins() { - return this.#conversation.listSuperAdmins(); - } - - /** - * Checks if an inbox is an admin of the group - * - * @param inboxId The inbox ID to check - * @returns Boolean indicating if the inbox is an admin - */ - isAdmin(inboxId: string) { - return this.#conversation.isAdmin(inboxId); - } - - /** - * Checks if an inbox is a super admin of the group - * - * @param inboxId The inbox ID to check - * @returns Boolean indicating if the inbox is a super admin - */ - isSuperAdmin(inboxId: string) { - return this.#conversation.isSuperAdmin(inboxId); - } - - /** - * Adds members to the group using identifiers - * - * @param identifiers Array of member identifiers to add - */ - async addMembersByIdentifiers(identifiers: Identifier[]) { - return this.#conversation.addMembersByIdentity(identifiers); - } - - /** - * Adds members to the group using inbox IDs - * - * @param inboxIds Array of inbox IDs to add - */ - async addMembers(inboxIds: string[]) { - return this.#conversation.addMembers(inboxIds); - } - - /** - * Removes members from the group using identifiers - * - * @param identifiers Array of member identifiers to remove - */ - async removeMembersByIdentifiers(identifiers: Identifier[]) { - return this.#conversation.removeMembersByIdentity(identifiers); - } - - /** - * Removes members from the group using inbox IDs - * - * @param inboxIds Array of inbox IDs to remove - */ - async removeMembers(inboxIds: string[]) { - return this.#conversation.removeMembers(inboxIds); - } - - /** - * Promotes a group member to admin status - * - * @param inboxId The inbox ID of the member to promote - */ - async addAdmin(inboxId: string) { - return this.#conversation.addAdmin(inboxId); - } - - /** - * Removes admin status from a group member - * - * @param inboxId The inbox ID of the admin to demote - */ - async removeAdmin(inboxId: string) { - return this.#conversation.removeAdmin(inboxId); - } - - /** - * Promotes a group member to super admin status - * - * @param inboxId The inbox ID of the member to promote - */ - async addSuperAdmin(inboxId: string) { - return this.#conversation.addSuperAdmin(inboxId); - } - - /** - * Removes super admin status from a group member - * - * @param inboxId The inbox ID of the super admin to demote - */ - async removeSuperAdmin(inboxId: string) { - return this.#conversation.removeSuperAdmin(inboxId); - } - - /** - * Request to leave the group - */ - async requestRemoval() { - return this.#conversation.leaveGroup(); - } - - /** - * Checks if the current user has requested to leave the group - * - * @returns Boolean - */ - isPendingRemoval() { - return ( - this.#conversation.membershipState() === - GroupMembershipState.PendingRemove - ); - } -} diff --git a/sdks/node-sdk/src/Preferences.ts b/sdks/node-sdk/src/Preferences.ts deleted file mode 100644 index 8f6d78df5..000000000 --- a/sdks/node-sdk/src/Preferences.ts +++ /dev/null @@ -1,135 +0,0 @@ -import type { - Client, - Consent, - ConsentEntityType, - Conversations, - UserPreferenceUpdate, -} from "@xmtp/node-bindings"; -import { - createStream, - type StreamCallback, - type StreamOptions, -} from "@/utils/streams"; - -/** - * Manages user preferences and consent states - * - * This class is not intended to be initialized directly. - */ -export class Preferences { - #client: Client; - #conversations: Conversations; - - /** - * Creates a new preferences instance - * - * @param client - The client instance managing preferences - * @param conversations - The underlying conversations instance - */ - constructor(client: Client, conversations: Conversations) { - this.#client = client; - this.#conversations = conversations; - } - - sync() { - return this.#conversations.syncPreferences(); - } - - /** - * Retrieves the current inbox state of this client from the local database - * - * @returns Promise that resolves with the inbox state - */ - async inboxState() { - return this.#client.inboxState(false); - } - - /** - * Retrieves the latest inbox state of this clientfrom the network - * - * @returns Promise that resolves with the inbox state - */ - async fetchInboxState() { - return this.#client.inboxState(true); - } - - /** - * Retrieves the current inbox states for specified inbox IDs from the local - * database - * - * @param inboxIds - Array of inbox IDs to get state for - * @returns Promise that resolves with the inbox states for the inbox IDs - */ - async getInboxStates(inboxIds: string[]) { - return this.#client.fetchInboxStatesByInboxIds(inboxIds, false); - } - - /** - * Retrieves the latest inbox states for specified inbox IDs from the network - * - * @param inboxIds - Array of inbox IDs to get state for - * @returns Promise that resolves with the inbox states for the inbox IDs - */ - async fetchInboxStates(inboxIds: string[]) { - return this.#client.fetchInboxStatesByInboxIds(inboxIds, true); - } - - /** - * Updates consent states for multiple records - * - * @param consentStates - Array of consent records to update - * @returns Promise that resolves when consent states are updated - */ - async setConsentStates(consentStates: Consent[]) { - return this.#client.setConsentStates(consentStates); - } - - /** - * Retrieves consent state for a specific entity - * - * @param entityType - Type of entity to get consent for - * @param entity - Entity identifier - * @returns Promise that resolves with the consent state - */ - async getConsentState(entityType: ConsentEntityType, entity: string) { - return this.#client.getConsentState(entityType, entity); - } - - /** - * Creates a stream of consent state updates - * - * @param options - Optional stream options - * @returns Stream instance for consent updates - */ - streamConsent(options?: StreamOptions) { - const streamConsent = async ( - callback: StreamCallback, - onFail: () => void, - ) => { - if (!options?.disableSync) { - await this.sync(); - } - return this.#conversations.streamConsent(callback, onFail); - }; - return createStream(streamConsent, undefined, options); - } - - /** - * Creates a stream of user preference updates - * - * @param options - Optional stream options - * @returns Stream instance for preference updates - */ - streamPreferences(options?: StreamOptions) { - const streamPreferences = async ( - callback: StreamCallback, - onFail: () => void, - ) => { - if (!options?.disableSync) { - await this.sync(); - } - return this.#conversations.streamPreferences(callback, onFail); - }; - return createStream(streamPreferences, undefined, options); - } -} diff --git a/sdks/node-sdk/src/constants.ts b/sdks/node-sdk/src/constants.ts deleted file mode 100644 index dc8fa1a4e..000000000 --- a/sdks/node-sdk/src/constants.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Pre-configured URLs for the XMTP network based on the environment - * - * @deprecated Use `createBackend()` instead. - * @constant - * @property {string} local - The local URL for the XMTP network - * @property {string} dev - The development URL for the XMTP network - * @property {string} production - The production URL for the XMTP network - */ -export const ApiUrls = { - local: "http://localhost:5556", - dev: "https://grpc.dev.xmtp.network:443", - production: "https://grpc.production.xmtp.network:443", -} as const; - -/** - * Pre-configured URLs for the XMTP history sync service based on the environment - * - * @constant - * @property {string} local - The local URL for the XMTP history sync service - * @property {string} dev - The development URL for the XMTP history sync service - * @property {string} production - The production URL for the XMTP history sync service - */ -export const HistorySyncUrls = { - local: "http://localhost:5558", - dev: "https://message-history.dev.ephemera.network", - production: "https://message-history.production.ephemera.network", - "testnet-staging": "https://message-history.dev.ephemera.network", - "testnet-dev": "https://message-history.dev.ephemera.network", - testnet: "https://message-history.dev.ephemera.network", - mainnet: "https://message-history.production.ephemera.network", -} as const; diff --git a/sdks/node-sdk/src/index.ts b/sdks/node-sdk/src/index.ts deleted file mode 100644 index 3718d482f..000000000 --- a/sdks/node-sdk/src/index.ts +++ /dev/null @@ -1,123 +0,0 @@ -export * from "./constants"; -export type * from "./types"; -export * from "./utils/createBackend"; -export * from "./utils/errors"; -export * from "./utils/inboxId"; -export type * from "./utils/signer"; -export type * from "./utils/streams"; -export * from "./utils/validation"; -export * from "./utils/messages"; -export type { AsyncStreamProxy } from "./AsyncStream"; -export { Client } from "./Client"; -export { Conversation } from "./Conversation"; -export { Conversations } from "./Conversations"; -export { DecodedMessage } from "./DecodedMessage"; -export { Dm } from "./Dm"; -export { Group } from "./Group"; -export type { - Action, - Actions, - ApiStats, - ArchiveMetadata, - ArchiveOptions, - Attachment, - AvailableArchiveInfo, - Backend, - BackendBuilder, - Consent, - ConversationDebugInfo, - ConversationListItem, - CreateDmOptions, - CreateGroupOptions, - Cursor, - EncryptedAttachment, - GroupMember, - GroupMetadata, - GroupPermissions, - GroupSyncSummary, - GroupUpdated, - HmacKey, - Identifier, - IdentityStats, - Inbox, - InboxState, - Installation, - Intent, - KeyPackageStatus, - LeaveRequest, - Lifetime, - ListConversationsOptions, - ListMessagesOptions, - LogOptions, - Message, - MessageDisappearingSettings, - MetadataFieldChange, - MultiRemoteAttachment, - PermissionPolicySet, - Reaction, - ReadReceipt, - RemoteAttachment, - Reply, - SendMessageOpts, - SignatureRequestHandle, - TransactionMetadata, - TransactionReference, - UserPreferenceUpdate, - VisibilityConfirmationOptions, - WalletCall, - WalletSendCalls, - WorkerConfigOptions, - WorkerIntervalOverride, -} from "@xmtp/node-bindings"; -export { - ActionStyle, - BackupElementSelectionOption, - ConsentEntityType, - ConsentState, - ContentType, - contentTypeActions, - contentTypeAttachment, - contentTypeGroupUpdated, - contentTypeIntent, - contentTypeLeaveRequest, - contentTypeMarkdown, - contentTypeMultiRemoteAttachment, - contentTypeReaction, - contentTypeReadReceipt, - contentTypeRemoteAttachment, - contentTypeReply, - contentTypeText, - contentTypeTransactionReference, - contentTypeWalletSendCalls, - ConversationType, - decryptAttachment, - DeliveryStatus, - encodeActions, - encodeAttachment, - encodeIntent, - encodeMarkdown, - encodeMultiRemoteAttachment, - encodeReaction, - encodeReadReceipt, - encodeRemoteAttachment, - encodeText, - encodeTransactionReference, - encodeWalletSendCalls, - encryptAttachment, - flushTelemetry, - GroupMembershipState, - GroupMessageKind, - GroupPermissionsOptions, - IdentifierKind, - ListConversationsOrderBy, - LogLevel, - MessageSortBy, - MetadataField, - PermissionLevel, - PermissionPolicy, - PermissionUpdateType, - ReactionAction, - ReactionSchema, - SortDirection, - WorkerKind, -} from "@xmtp/node-bindings"; diff --git a/sdks/node-sdk/src/types.ts b/sdks/node-sdk/src/types.ts deleted file mode 100644 index 1f2e8c4ae..000000000 --- a/sdks/node-sdk/src/types.ts +++ /dev/null @@ -1,209 +0,0 @@ -import type { ContentCodec } from "@xmtp/content-type-primitives"; -import { - type Actions, - type Attachment, - type Backend, - type ContentTypeId, - type DeletedMessage, - type GroupUpdated, - type Intent, - type LeaveRequest, - type LogLevel, - type MultiRemoteAttachment, - type Reaction, - type ReadReceipt, - type RemoteAttachment, - type TransactionReference, - type VisibilityConfirmationOptions, - type WalletSendCalls, - type WorkerConfigOptions, -} from "@xmtp/node-bindings"; -import type { DecodedMessage } from "@/DecodedMessage"; -import type { HexString } from "./utils/validation"; - -/** - * XMTP environment - */ -export type XmtpEnv = - | "local" - | "dev" - | "production" - | "testnet-staging" - | "testnet-dev" - | "testnet" - | "mainnet"; - -/** - * Network options - */ -export type NetworkOptions = { - /** - * Specify which XMTP environment to connect to. (default: `dev`) - * - * @see https://docs.xmtp.org/chat-apps/core-messaging/create-a-client#xmtp-network-environments - */ - env?: XmtpEnv; - /** - * apiUrl can be used to override the `env` flag and connect to a - * specific endpoint - */ - apiUrl?: string; - /** - * The host of the XMTP Gateway for your application - * - * Only valid for `dev` and `production` environments - * - * @see https://docs.xmtp.org/fund-agents-apps/run-gateway - */ - gatewayHost?: string; - /** - * Custom app version - */ - appVersion?: string; -}; - -/** - * Device sync options - */ -export type DeviceSyncOptions = { - /** - * historySyncUrl can be used to override the `env` flag and connect to a - * specific endpoint for syncing history - * - * @see https://docs.xmtp.org/chat-apps/list-stream-sync/history-sync - */ - historySyncUrl?: string | null; - /** - * Disable device sync - */ - disableDeviceSync?: boolean; -}; - -/** - * Storage options - */ -export type StorageOptions = { - /** - * Path to the local DB - * - * There are 4 value types that can be used to specify the database path: - * - * - `undefined` (or excluded from the client options) - * The database will be created in the current working directory and is based on - * the XMTP environment and client inbox ID. - * Example: `xmtp-dev-.db3` - * - * - `null` - * No database will be created and all data will be lost once the client disconnects. - * - * - `string` - * The given path will be used to create the database. - * Example: `./my-db.db3` - * - * - `function` - * A callback function that receives the inbox ID and returns a string path. - * Example: `(inboxId) => string` - */ - dbPath?: string | null | ((inboxId: string) => string); - /** - * Encryption key for the local DB (32 bytes, hex) - * - * @see https://docs.xmtp.org/chat-apps/core-messaging/create-a-client#view-an-encrypted-database - */ - dbEncryptionKey?: Uint8Array | HexString; -}; - -export type ContentOptions = { - /** - * Allow configuring codecs for additional content types - */ - codecs?: ContentCodec[]; -}; - -export type OtherOptions = { - /** - * Enable structured JSON logging - */ - structuredLogging?: boolean; - /** - * Logging level - */ - loggingLevel?: LogLevel; - /** - * OTLP endpoint (e.g. `"http://collector:4317"`) for exporting telemetry - * spans. When set (and the binding is built with the `otel` feature), spans - * are exported via OTLP to this endpoint, where a downstream OpenTelemetry - * Collector can derive metrics from them. - * - * Call {@link flushTelemetry} on graceful shutdown to flush buffered spans. - */ - otelEndpoint?: string; - /** - * Resource attributes attached to all exported telemetry spans - * (e.g. `{ "service.instance.id": "herald-7", "deployment.environment": "prod" }`). - * Use these to attribute telemetry to its source. - */ - resourceAttributes?: Record; - /** - * Tuning for the background worker scheduler (intervals, jitter, per-worker - * overrides, and disabled workers). All fields are optional; omitting this - * object preserves the default worker behavior. - * - * Intervals are specified in nanoseconds. - */ - workerConfig?: WorkerConfigOptions; - /** - * Disable automatic registration when creating a client - */ - disableAutoRegister?: boolean; - /** - * The nonce to use when generating an inbox ID - * (default: undefined = 1) - */ - nonce?: bigint; - /** - * Options for waiting until client registration is visible on the network. - * - * When set, `registerIdentity` will wait for the specified quorum of nodes - * to confirm the registration before resolving. - */ - waitForRegistrationVisible?: VisibilityConfirmationOptions; -}; - -export type ClientOptions = (NetworkOptions | { backend: Backend }) & - DeviceSyncOptions & - StorageOptions & - ContentOptions & - OtherOptions; - -export type EnrichedReply = { - referenceId: string; - content: T; - contentType: ContentTypeId | undefined; - inReplyTo: DecodedMessage | null; -}; - -export type BuiltInContentTypes = - | string // text, markdown - | LeaveRequest - | Reaction - | ReadReceipt - | Attachment - | RemoteAttachment - | TransactionReference - | WalletSendCalls - | Actions - | Intent - | MultiRemoteAttachment - | GroupUpdated - | DeletedMessage; - -export type ExtractCodecContentTypes = - C extends readonly [] - ? BuiltInContentTypes - : [...C][number] extends ContentCodec - ? - | T - | BuiltInContentTypes - | EnrichedReply - : BuiltInContentTypes; diff --git a/sdks/node-sdk/src/utils/createBackend.ts b/sdks/node-sdk/src/utils/createBackend.ts deleted file mode 100644 index 3df75e43a..000000000 --- a/sdks/node-sdk/src/utils/createBackend.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { - BackendBuilder, - XmtpEnv as BindingsEnv, - type Backend, -} from "@xmtp/node-bindings"; -import type { NetworkOptions, XmtpEnv } from "@/types"; - -const envMap: Record = { - local: BindingsEnv.Local, - dev: BindingsEnv.Dev, - production: BindingsEnv.Production, - "testnet-staging": BindingsEnv.TestnetStaging, - "testnet-dev": BindingsEnv.TestnetDev, - testnet: BindingsEnv.Testnet, - mainnet: BindingsEnv.Mainnet, -}; - -const reverseEnvMap: Record = { - [BindingsEnv.Local]: "local", - [BindingsEnv.Dev]: "dev", - [BindingsEnv.Production]: "production", - [BindingsEnv.TestnetStaging]: "testnet-staging", - [BindingsEnv.TestnetDev]: "testnet-dev", - [BindingsEnv.Testnet]: "testnet", - [BindingsEnv.Mainnet]: "mainnet", -}; - -export const envToString = (env: BindingsEnv): XmtpEnv => { - return reverseEnvMap[env]; -}; - -export const createBackend = async ( - options?: NetworkOptions, -): Promise => { - const env = options?.env ?? "dev"; - const builder = new BackendBuilder(envMap[env]); - if (options?.apiUrl) builder.setApiUrl(options.apiUrl); - if (options?.gatewayHost) builder.setGatewayHost(options.gatewayHost); - if (options?.appVersion) builder.setAppVersion(options.appVersion); - return builder.build(); -}; diff --git a/sdks/node-sdk/src/utils/createClient.ts b/sdks/node-sdk/src/utils/createClient.ts deleted file mode 100644 index 97c8aa55e..000000000 --- a/sdks/node-sdk/src/utils/createClient.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { join } from "node:path"; -import process from "node:process"; -import { - createClientWithBackend, - LogLevel, - SyncWorkerMode, - type Backend, - type Identifier, - type LogOptions, -} from "@xmtp/node-bindings"; -import type { ClientOptions } from "@/types"; -import { createBackend, envToString } from "@/utils/createBackend"; -import { generateInboxId, getInboxIdForIdentifier } from "@/utils/inboxId"; -import { isHexString } from "./validation"; - -const networkOptionKeys = [ - "env", - "apiUrl", - "gatewayHost", - "appVersion", -] as const; - -const hasBackend = ( - options: ClientOptions, -): options is { backend: Backend } & ClientOptions => { - return "backend" in options; -}; - -const resolveBackend = async (options?: ClientOptions): Promise => { - if (!options) { - return createBackend(); - } - - if (hasBackend(options)) { - // Validate that no NetworkOptions fields are also set - const conflicting = networkOptionKeys.filter( - (key) => - key in options && (options as Record)[key] != null, - ); - if (conflicting.length > 0) { - throw new Error( - `Cannot specify both 'backend' and network options (${conflicting.join(", ")}). ` + - `Use either a pre-built Backend or network options, not both.`, - ); - } - return options.backend; - } - - // No backend provided — build one from NetworkOptions - return createBackend(options); -}; - -export const createClient = async ( - identifier: Identifier, - options?: ClientOptions, -) => { - const backend = await resolveBackend(options); - - const inboxId = - (await getInboxIdForIdentifier(backend, identifier)) || - generateInboxId(identifier, options?.nonce); - - const env = envToString(backend.env); - - let dbPath: string | null; - if (options?.dbPath === undefined) { - // Default: auto-generated path - dbPath = join(process.cwd(), `xmtp-${env}-${inboxId}.db3`); - } else if (typeof options.dbPath === "function") { - // Callback function: call with inbox ID - dbPath = options.dbPath(inboxId); - } else { - // String or null: use as-is - dbPath = options.dbPath; - } - - const logOptions: LogOptions = { - structured: options?.structuredLogging ?? false, - level: options?.loggingLevel ?? LogLevel.Off, - otelEndpoint: options?.otelEndpoint, - resourceAttributes: options?.resourceAttributes, - }; - const deviceSyncWorkerMode = options?.disableDeviceSync - ? SyncWorkerMode.Disabled - : SyncWorkerMode.Enabled; - - const dbEncryptionKey = isHexString(options?.dbEncryptionKey) - ? Buffer.from(options.dbEncryptionKey.replace(/^0x/, ""), "hex") - : options?.dbEncryptionKey; - - const client = await createClientWithBackend( - backend, - { - dbPath: dbPath ?? undefined, - encryptionKey: dbEncryptionKey, - }, - inboxId, - identifier, - deviceSyncWorkerMode, - options?.workerConfig, - logOptions, - undefined, // allowOffline - options?.nonce, - ); - - return { client, env }; -}; diff --git a/sdks/node-sdk/src/utils/date.ts b/sdks/node-sdk/src/utils/date.ts deleted file mode 100644 index b15e9987b..000000000 --- a/sdks/node-sdk/src/utils/date.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function nsToDate(ns: bigint): Date { - return new Date(Number(ns / 1_000_000n)); -} diff --git a/sdks/node-sdk/src/utils/errors.ts b/sdks/node-sdk/src/utils/errors.ts deleted file mode 100644 index 83a51b916..000000000 --- a/sdks/node-sdk/src/utils/errors.ts +++ /dev/null @@ -1,48 +0,0 @@ -export class InboxReassignError extends Error { - constructor() { - super( - "Unable to create add account signature text, `allowInboxReassign` must be true", - ); - } -} - -export class AccountAlreadyAssociatedError extends Error { - constructor(inboxId: string) { - super(`Account already associated with inbox ${inboxId}`); - } -} - -export class MissingContentTypeError extends Error { - constructor() { - super("Content type is required when sending encoded content"); - } -} - -export class SignerUnavailableError extends Error { - constructor() { - super( - "Signer unavailable, use Client.create to create a client with a signer", - ); - } -} - -export class ClientNotInitializedError extends Error { - constructor() { - super( - "Client not initialized, use Client.create or Client.build to create a client", - ); - } -} - -export class StreamFailedError extends Error { - constructor(retryAttempts: number) { - const times = `time${retryAttempts !== 1 ? "s" : ""}`; - super(`Stream failed, retried ${retryAttempts} ${times}`); - } -} - -export class StreamInvalidRetryAttemptsError extends Error { - constructor() { - super("Stream retry attempts must be greater than 0"); - } -} diff --git a/sdks/node-sdk/src/utils/inboxId.ts b/sdks/node-sdk/src/utils/inboxId.ts deleted file mode 100644 index d033d4562..000000000 --- a/sdks/node-sdk/src/utils/inboxId.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { - generateInboxId as generateInboxIdBinding, - getInboxIdByIdentity, - type Backend, - type Identifier, -} from "@xmtp/node-bindings"; - -export const generateInboxId = ( - identifier: Identifier, - nonce?: bigint, -): string => { - return generateInboxIdBinding(identifier, nonce); -}; - -export const getInboxIdForIdentifier = async ( - backend: Backend, - identifier: Identifier, -) => { - return getInboxIdByIdentity(backend, identifier); -}; diff --git a/sdks/node-sdk/src/utils/messages.ts b/sdks/node-sdk/src/utils/messages.ts deleted file mode 100644 index faedbf09c..000000000 --- a/sdks/node-sdk/src/utils/messages.ts +++ /dev/null @@ -1,92 +0,0 @@ -import type { - Actions, - Attachment, - GroupUpdated, - Intent, - LeaveRequest, - MultiRemoteAttachment, - Reaction, - ReadReceipt, - RemoteAttachment, - TransactionReference, - WalletSendCalls, -} from "@xmtp/node-bindings"; -import type { DecodedMessage } from "@/DecodedMessage"; -import type { EnrichedReply } from "@/types"; - -export const isReaction = (m: DecodedMessage): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "reaction"; - -export const isReply = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && m.contentType.typeId === "reply"; - -export const isTextReply = ( - m: DecodedMessage, -): m is DecodedMessage> => - isReply(m) && typeof m.content?.content === "string"; - -export const isText = (m: DecodedMessage): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && m.contentType.typeId === "text"; - -export const isRemoteAttachment = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "remoteStaticAttachment"; - -export const isAttachment = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "attachment"; - -export const isMultiRemoteAttachment = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "multiRemoteStaticAttachment"; - -export const isTransactionReference = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "transactionReference"; - -export const isGroupUpdated = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "group_updated"; - -export const isReadReceipt = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "readReceipt"; - -export const isLeaveRequest = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "leave_request"; - -export const isWalletSendCalls = ( - m: DecodedMessage, -): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "walletSendCalls"; - -export const isIntent = (m: DecodedMessage): m is DecodedMessage => - m.contentType.authorityId === "coinbase.com" && - m.contentType.typeId === "intent"; - -export const isActions = (m: DecodedMessage): m is DecodedMessage => - m.contentType.authorityId === "coinbase.com" && - m.contentType.typeId === "actions"; - -export const isMarkdown = (m: DecodedMessage): m is DecodedMessage => - m.contentType.authorityId === "xmtp.org" && - m.contentType.typeId === "markdown"; diff --git a/sdks/node-sdk/src/utils/signer.ts b/sdks/node-sdk/src/utils/signer.ts deleted file mode 100644 index aaf209c66..000000000 --- a/sdks/node-sdk/src/utils/signer.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Identifier } from "@xmtp/node-bindings"; - -type SignMessage = (message: string) => Promise | Uint8Array; -type GetIdentifier = () => Promise | Identifier; -type GetChainId = () => bigint; -type GetBlockNumber = () => bigint; - -export type Signer = - | { - type: "EOA"; - signMessage: SignMessage; - getIdentifier: GetIdentifier; - } - | { - type: "SCW"; - signMessage: SignMessage; - getIdentifier: GetIdentifier; - getBlockNumber?: GetBlockNumber; - getChainId: GetChainId; - }; - -export type EOASigner = Extract; -export type SCWSigner = Extract; diff --git a/sdks/node-sdk/src/utils/streams.ts b/sdks/node-sdk/src/utils/streams.ts deleted file mode 100644 index 09b4a0e97..000000000 --- a/sdks/node-sdk/src/utils/streams.ts +++ /dev/null @@ -1,209 +0,0 @@ -import { isPromise } from "node:util/types"; -import type { StreamCloser } from "@xmtp/node-bindings"; -import { AsyncStream, createAsyncStreamProxy } from "@/AsyncStream"; -import { StreamFailedError, StreamInvalidRetryAttemptsError } from "./errors"; - -const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - -export const DEFAULT_RETRY_DELAY = 60_000; // milliseconds -export const DEFAULT_RETRY_ATTEMPTS = 10; - -export type StreamOptions = { - /** - * Called when the stream ends - */ - onEnd?: () => void; - /** - * Called when a stream error occurs - */ - onError?: (error: Error) => void; - /** - * Called when the stream fails - */ - onFail?: () => void; - /** - * Called when the stream is restarted - */ - onRestart?: () => void; - /** - * Called when the stream is retried - */ - onRetry?: (attempts: number, maxAttempts: number) => void; - /** - * Called when a value is emitted from the stream - */ - onValue?: (value: V) => void; - /** - * The number of times to retry the stream - * (default: 10) - */ - retryAttempts?: number; - /** - * The delay between retries (in milliseconds) - * (default: 60000) - */ - retryDelay?: number; - /** - * Whether to retry the stream if it fails - * (default: true) - */ - retryOnFail?: boolean; - /** - * Whether to disable network sync before starting the stream - * (default: false) - */ - disableSync?: boolean; -}; - -export type StreamCallback = ( - error: Error | null, - value: T | undefined, -) => void; - -export type StreamFunction = ( - callback: StreamCallback, - onFail: () => void, -) => Promise; - -export type StreamValueMutator = ( - value: T, -) => V | Promise; - -/** - * Creates a stream from a stream function - * - * If the stream fails, an attempt will be made to restart it. - * - * This function is not intended to be used directly. - * - * @param streamFunction - The stream function to create a stream from - * @param streamValueMutator - An optional function to mutate the value emitted from the stream - * @param options - The options for the stream - * @param args - Additional arguments to pass to the stream function - * @returns An async iterable stream proxy - * @throws {StreamInvalidRetryAttemptsError} if the retryAttempts option is less than 0 and retryOnFail is true - * @throws {StreamFailedError} if the stream fails and can't be restarted - */ -export const createStream = async ( - streamFunction: StreamFunction, - streamValueMutator?: StreamValueMutator, - options?: StreamOptions, -) => { - const { - onError, - onFail, - onRestart, - onRetry, - onValue, - retryAttempts = DEFAULT_RETRY_ATTEMPTS, - retryDelay = DEFAULT_RETRY_DELAY, - retryOnFail = true, - } = options ?? {}; - // retry attempts must be greater than 0 - if (retryOnFail && retryAttempts < 0) { - throw new StreamInvalidRetryAttemptsError(); - } - - const asyncStream = new AsyncStream(); - const streamCallback: StreamCallback = (error, value) => { - // if a stream error occurs, call the onError callback - if (error) { - onError?.(error); - return; - } - // ensure the value is not undefined - if (value !== undefined) { - try { - // if a streamValueMutator is provided, mutate the value - if (streamValueMutator) { - const mutatedValue = streamValueMutator(value); - if (isPromise(mutatedValue)) { - void mutatedValue - .then((mutatedValue) => { - if (mutatedValue !== undefined) { - asyncStream.push(mutatedValue); - onValue?.(mutatedValue); - } - }) - .catch((error: unknown) => { - onError?.(error as Error); - }); - } else { - if (mutatedValue !== undefined) { - asyncStream.push(mutatedValue); - onValue?.(mutatedValue); - } - } - } else { - asyncStream.push(value as unknown as V); - onValue?.(value as unknown as V); - } - } catch (error) { - onError?.(error as Error); - } - } - }; - const retry = async (retries: number = retryAttempts) => { - // if the stream has been retried the maximum number of times without - // success, call onError - if (retries === 0) { - void asyncStream.end(); - onError?.(new StreamFailedError(retryAttempts)); - return; - } - - // wait for the retry delay before attempting to restart the stream - await wait(retryDelay); - // call the onRetry callback - onRetry?.(retryAttempts - retries + 1, retryAttempts); - try { - // attempt to restart the stream - const streamCloser = await streamFunction(streamCallback, () => { - // call the onFail callback - onFail?.(); - void retry(); - }); - await streamCloser.waitForReady(); - // when the async stream is done, end the stream - asyncStream.onDone = () => { - streamCloser.end(); - }; - // stream restarted, call the onRestart callback - onRestart?.(); - } catch (error) { - onError?.(error as Error); - // retry - void retry(retries - 1); - } - }; - const startRetry = () => { - // if the stream should be retried, start the process - if (retryOnFail) { - void retry(); - } else { - void asyncStream.end(); - // stream failed and should not be retried, throw an error - onError?.(new StreamFailedError(0)); - } - }; - - try { - // create the stream - const streamCloser = await streamFunction(streamCallback, () => { - // call the onFail callback - onFail?.(); - startRetry(); - }); - await streamCloser.waitForReady(); - // when the async stream is done, end the stream - asyncStream.onDone = () => { - streamCloser.end(); - }; - } catch (error) { - onError?.(error as Error); - startRetry(); - } - - // return a proxy for the async stream - return createAsyncStreamProxy(asyncStream); -}; diff --git a/sdks/node-sdk/src/utils/uuid.ts b/sdks/node-sdk/src/utils/uuid.ts deleted file mode 100644 index a6e3037dc..000000000 --- a/sdks/node-sdk/src/utils/uuid.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { randomBytes } from "node:crypto"; - -/** - * Generates a unique identifier using crypto.randomBytes() - */ -export const uuid = (): string => randomBytes(16).toString("hex"); diff --git a/sdks/node-sdk/src/utils/validation.ts b/sdks/node-sdk/src/utils/validation.ts deleted file mode 100644 index ed8ec8862..000000000 --- a/sdks/node-sdk/src/utils/validation.ts +++ /dev/null @@ -1,12 +0,0 @@ -export type HexString = `0x${string}`; - -export function isHexString(value: unknown): value is HexString { - return typeof value === "string" && /^0x(?:[0-9a-fA-F]{2})+$/.test(value); -} - -export function validHex(value: unknown): HexString { - if (!isHexString(value)) { - throw new TypeError(`Value is not a hexadecimal string.`); - } - return value; -} diff --git a/sdks/node-sdk/test/AsyncStream.test.ts b/sdks/node-sdk/test/AsyncStream.test.ts deleted file mode 100644 index ed9cd0f0d..000000000 --- a/sdks/node-sdk/test/AsyncStream.test.ts +++ /dev/null @@ -1,457 +0,0 @@ -import { describe, expect, it, vi } from "vitest"; -import { AsyncStream, createAsyncStreamProxy } from "@/AsyncStream"; - -const testError = new Error("test"); - -describe("AsyncStream", () => { - it("should return values from push() in sequence", async () => { - const stream = new AsyncStream(); - const onReturnSpy = vi.fn(); - const onDoneSpy = vi.fn(); - - stream.onReturn = onReturnSpy; - stream.onDone = onDoneSpy; - - stream.push(1); - stream.push(2); - stream.push(3); - stream.push(4); - stream.push(5); - - const values: (number | undefined)[] = []; - let iterationCount = 0; - - for await (const value of stream) { - values.push(value); - iterationCount++; - - if (iterationCount === 3) { - break; - } - } - - expect(values).toEqual([1, 2, 3]); - expect(onReturnSpy).toHaveBeenCalledOnce(); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - }); - - it("should handle values added during iteration", async () => { - const stream = new AsyncStream(); - const onReturnSpy = vi.fn(); - const onDoneSpy = vi.fn(); - - stream.onReturn = onReturnSpy; - stream.onDone = onDoneSpy; - - stream.push(1); - - const values: (number | undefined)[] = []; - let iterationCount = 0; - - for await (const value of stream) { - values.push(value); - iterationCount++; - - if (iterationCount === 1) { - stream.push(2); - stream.push(3); - } - - if (iterationCount === 3) { - break; - } - } - - expect(values).toEqual([1, 2, 3]); - expect(onReturnSpy).toHaveBeenCalledOnce(); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - }); - - it("should catch an error thrown in the for..await loop and cleanup properly", async () => { - const stream = new AsyncStream(); - const onReturnSpy = vi.fn(); - const onDoneSpy = vi.fn(); - - stream.onReturn = onReturnSpy; - stream.onDone = onDoneSpy; - stream.push(1); - stream.push(2); - - try { - for await (const value of stream) { - expect(value).toBe(1); - throw testError; - } - } catch (error) { - expect(error).toBe(testError); - } - - expect(onReturnSpy).toHaveBeenCalledOnce(); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - }); - - it("should end for await..of loop when stream is ended and call onDone", async () => { - const stream = new AsyncStream(); - const onDoneSpy = vi.fn(); - const onReturnSpy = vi.fn(); - - stream.onDone = onDoneSpy; - stream.onReturn = onReturnSpy; - - stream.push(1); - stream.push(2); - - setTimeout(() => { - void stream.end(); - }, 100); - - const values: (number | undefined)[] = []; - - for await (const value of stream) { - values.push(value); - } - - expect(values).toEqual([1, 2]); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(onReturnSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - - stream.push(3); - - for await (const _value of stream) { - // this block should never be reached - expect(false).toBe(true); - } - }); - - it("should handle multiple concurrent next() calls", async () => { - const stream = new AsyncStream(); - - const nextPromise1 = stream.next(); - const nextPromise2 = stream.next(); - const nextPromise3 = stream.next(); - - stream.push(1); - stream.push(2); - stream.push(3); - - const [result1, result2, result3] = await Promise.all([ - nextPromise1, - nextPromise2, - nextPromise3, - ]); - - expect(result1).toEqual({ done: false, value: 1 }); - expect(result2).toEqual({ done: false, value: 2 }); - expect(result3).toEqual({ done: false, value: 3 }); - expect(stream.isDone).toBe(false); - }); - - it("should handle return() with pending promises", async () => { - const stream = new AsyncStream(); - const onReturnSpy = vi.fn(); - - stream.onReturn = onReturnSpy; - - const nextPromise1 = stream.next(); - const nextPromise2 = stream.next(); - - const returnResult = await stream.return(); - - expect(returnResult).toEqual({ done: true, value: undefined }); - expect(onReturnSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - - const result1 = await nextPromise1; - const result2 = await nextPromise2; - - expect(result1).toEqual({ done: true, value: undefined }); - expect(result2).toEqual({ done: true, value: undefined }); - }); - - it("should not process callbacks after being done", async () => { - const stream = new AsyncStream(); - const onDoneSpy = vi.fn(); - const onReturnSpy = vi.fn(); - - stream.onDone = onDoneSpy; - stream.onReturn = onReturnSpy; - - // End the stream - await stream.end(); - - // These callbacks should be ignored - stream.push(1); - - for await (const _value of stream) { - // this block should never be reached - expect(false).toBe(true); - } - - expect(stream.isDone).toBe(true); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(onReturnSpy).toHaveBeenCalledOnce(); - - const result = await stream.next(); - expect(result).toEqual({ done: true, value: undefined }); - }); - - it("should handle queue properly when values arrive faster than consumption", async () => { - const stream = new AsyncStream(); - - for (let i = 1; i <= 5; i++) { - stream.push(i); - } - - const values: (number | undefined)[] = []; - - for (let i = 0; i < 3; i++) { - const result = await stream.next(); - expect(result.done).toBe(false); - values.push(result.value); - } - - expect(values).toEqual([1, 2, 3]); - expect(stream.isDone).toBe(false); - - await stream.end(); - - const finalResult = await stream.next(); - expect(finalResult).toEqual({ done: true, value: undefined }); - }); -}); - -describe("createAsyncStreamProxy", () => { - it("should only expose allowed methods and properties", () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - expect(typeof proxy.next).toBe("function"); - expect(typeof proxy.end).toBe("function"); - expect(typeof proxy.return).toBe("function"); - expect(typeof proxy[Symbol.asyncIterator]).toBe("function"); - - const ownProperties = Object.getOwnPropertyNames(proxy); - expect(ownProperties).toHaveLength(4); - expect(ownProperties).toContain("end"); - expect(ownProperties).toContain("return"); - expect(ownProperties).toContain("isDone"); - expect(ownProperties).toContain("next"); - }); - - it("should prevent setting properties", () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - // this will fail silently - proxy.isDone = true; - - expect(proxy.isDone).toBe(false); - }); - - it("should correctly forward next() calls to the underlying stream", async () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - stream.push(1); - stream.push(2); - - const result1 = await proxy.next(); - const result2 = await proxy.next(); - - expect(result1).toEqual({ done: false, value: 1 }); - expect(result2).toEqual({ done: false, value: 2 }); - }); - - it("should correctly forward end() calls to the underlying stream", async () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - const onDoneSpy = vi.fn(); - - stream.onDone = onDoneSpy; - - const result = await proxy.end(); - - expect(result).toEqual({ done: true, value: undefined }); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - expect(proxy.isDone).toBe(true); - }); - - it("should maintain async iterator functionality", async () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - stream.push(1); - stream.push(2); - stream.push(3); - - const values: number[] = []; - let iterationCount = 0; - - for await (const value of proxy) { - values.push(value); - iterationCount++; - - if (iterationCount === 3) { - break; - } - } - - expect(values).toEqual([1, 2, 3]); - expect(stream.isDone).toBe(true); - expect(proxy.isDone).toBe(true); - }); - - it("should end for await..of loop when proxy is ended and call onDone", async () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - const onDoneSpy = vi.fn(); - - stream.onDone = onDoneSpy; - - stream.push(1); - stream.push(2); - - setTimeout(() => { - void proxy.end(); - }, 100); - - const values: number[] = []; - - for await (const value of proxy) { - values.push(value); - } - - expect(values).toEqual([1, 2]); - expect(onDoneSpy).toHaveBeenCalledOnce(); - expect(stream.isDone).toBe(true); - expect(proxy.isDone).toBe(true); - - stream.push(3); - - for await (const _value of proxy) { - // this block should never be reached - expect(false).toBe(true); - } - }); - - it("should correctly implement has() trap", () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - expect("isDone" in proxy).toBe(true); - expect("next" in proxy).toBe(true); - expect("end" in proxy).toBe(true); - expect("return" in proxy).toBe(true); - expect(Symbol.asyncIterator in proxy).toBe(true); - - expect("push" in proxy).toBe(false); - expect("error" in proxy).toBe(false); - expect("onDone" in proxy).toBe(false); - expect("onError" in proxy).toBe(false); - expect("onReturn" in proxy).toBe(false); - expect("nonExistentProperty" in proxy).toBe(false); - }); - - it("should correctly implement ownKeys() trap", () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - const keys = Object.getOwnPropertyNames(proxy); - const symbols = Object.getOwnPropertySymbols(proxy); - - expect(keys).toHaveLength(4); - expect(keys).toContain("next"); - expect(keys).toContain("end"); - expect(keys).toContain("return"); - expect(keys).toContain("isDone"); - expect(symbols).toHaveLength(1); - expect(symbols).toContain(Symbol.asyncIterator); - }); - - it("should correctly implement getOwnPropertyDescriptor() trap", () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - const nextDescriptor = Object.getOwnPropertyDescriptor(proxy, "next"); - expect(nextDescriptor).toBeDefined(); - expect(nextDescriptor?.enumerable).toBe(true); - expect(nextDescriptor?.configurable).toBe(true); - expect(typeof nextDescriptor?.value).toBe("function"); - - const endDescriptor = Object.getOwnPropertyDescriptor(proxy, "end"); - expect(endDescriptor).toBeDefined(); - expect(endDescriptor?.enumerable).toBe(true); - expect(endDescriptor?.configurable).toBe(true); - expect(typeof endDescriptor?.value).toBe("function"); - - const returnDescriptor = Object.getOwnPropertyDescriptor(proxy, "return"); - expect(returnDescriptor).toBeDefined(); - expect(returnDescriptor?.enumerable).toBe(true); - expect(returnDescriptor?.configurable).toBe(true); - expect(typeof returnDescriptor?.value).toBe("function"); - - const asyncIteratorDescriptor = Object.getOwnPropertyDescriptor( - proxy, - Symbol.asyncIterator, - ); - expect(asyncIteratorDescriptor).toBeDefined(); - expect(asyncIteratorDescriptor?.enumerable).toBe(true); - expect(asyncIteratorDescriptor?.configurable).toBe(true); - expect(typeof asyncIteratorDescriptor?.value).toBe("function"); - - // Non-exposed properties should return undefined - const callbackDescriptor = Object.getOwnPropertyDescriptor( - proxy, - "callback", - ); - expect(callbackDescriptor).toBeUndefined(); - - const isDoneDescriptor = Object.getOwnPropertyDescriptor(proxy, "isDone"); - expect(isDoneDescriptor).toBeDefined(); - expect(isDoneDescriptor?.enumerable).toBe(true); - expect(isDoneDescriptor?.configurable).toBe(true); - expect(typeof isDoneDescriptor?.value).toBe("boolean"); - }); - - it("should handle concurrent operations through proxy", async () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - const nextPromise1 = proxy.next(); - const nextPromise2 = proxy.next(); - const nextPromise3 = proxy.next(); - - stream.push(1); - stream.push(2); - stream.push(3); - - const [result1, result2, result3] = await Promise.all([ - nextPromise1, - nextPromise2, - nextPromise3, - ]); - - expect(result1).toEqual({ done: false, value: 1 }); - expect(result2).toEqual({ done: false, value: 2 }); - expect(result3).toEqual({ done: false, value: 3 }); - }); - - it("should work correctly when stream is already done", async () => { - const stream = new AsyncStream(); - const proxy = createAsyncStreamProxy(stream); - - stream.push(1); - await proxy.end(); - - const result1 = await proxy.next(); - const result2 = await proxy.next(); - - expect(result1).toEqual({ done: true, value: undefined }); - expect(result2).toEqual({ done: true, value: undefined }); - }); -}); diff --git a/sdks/node-sdk/test/Client.test.ts b/sdks/node-sdk/test/Client.test.ts deleted file mode 100644 index 87d4b3cd0..000000000 --- a/sdks/node-sdk/test/Client.test.ts +++ /dev/null @@ -1,657 +0,0 @@ -import fs from "node:fs"; -import path from "node:path"; -import { - flushTelemetry, - IdentifierKind, - LogLevel, - WorkerKind, -} from "@xmtp/node-bindings"; -import { uint8ArrayToHex } from "uint8array-extras"; -import { describe, expect, it } from "vitest"; -import { Client } from "@/Client"; -import { createBackend } from "@/index"; -import { - ClientNotInitializedError, - SignerUnavailableError, -} from "@/utils/errors"; -import { uuid } from "@/utils/uuid"; -import { - buildClient, - createClient, - createIdentifier, - createRegisteredClient, - createSigner, - createUser, -} from "@test/helpers"; - -describe("Client", () => { - it("should create a client", async () => { - const { signer, address } = createSigner(); - const client = await createClient(signer); - expect(client.accountIdentifier?.identifierKind).toBe( - IdentifierKind.Ethereum, - ); - expect(client.accountIdentifier?.identifier).toBe(address); - expect(client.isRegistered).toBe(false); - expect(client.inboxId).toBeDefined(); - expect(client.installationId).toBeDefined(); - expect(client.options).toBeDefined(); - expect(client.signer).toBe(signer); - - const client2 = await createClient(signer, { - nonce: 1n, - }); - expect(client2.inboxId).toBe(client.inboxId); - - const client3 = await createClient(signer, { - nonce: 2n, - }); - expect(client3.inboxId).not.toEqual(client.inboxId); - }); - - it("should create a client with worker config and logging options", async () => { - const { signer } = createSigner(); - const workerConfig = { - defaultIntervalNs: 60_000_000_000n, - jitterNs: 1_000_000_000n, - workerIntervalsNs: [ - { kind: WorkerKind.DeviceSync, intervalNs: 30_000_000_000n }, - ], - disabledWorkers: [WorkerKind.KeyPackageCleaner], - }; - const client = await createClient(signer, { - loggingLevel: LogLevel.Off, - structuredLogging: true, - otelEndpoint: "http://collector:4317", - resourceAttributes: { "service.instance.id": "test-instance" }, - workerConfig, - }); - expect(client.inboxId).toBeDefined(); - expect(client.options?.workerConfig).toEqual(workerConfig); - expect(client.options?.otelEndpoint).toBe("http://collector:4317"); - expect(client.options?.resourceAttributes).toEqual({ - "service.instance.id": "test-instance", - }); - - // flushTelemetry is a process-global no-op when telemetry is not enabled - expect(() => { - flushTelemetry(); - }).not.toThrow(); - }); - - it("should create a client without a signer", async () => { - const identifier = createIdentifier(createUser()); - const client = await buildClient(identifier); - expect(client).toBeDefined(); - expect(client.accountIdentifier).toEqual(identifier); - expect(client.isRegistered).toBe(false); - expect(client.inboxId).toBeDefined(); - expect(client.installationId).toBeDefined(); - expect(client.signer).toBeUndefined(); - - const { signer: signer2 } = createSigner(); - - await expect(() => client.register()).rejects.toThrow( - new SignerUnavailableError(), - ); - - await expect(async () => - client.removeAccount(identifier), - ).rejects.toThrow(); - - await expect(() => client.revokeInstallations([])).rejects.toThrow(); - - await expect(() => client.revokeAllOtherInstallations()).rejects.toThrow(); - - await expect(async () => - client.changeRecoveryIdentifier(await signer2.getIdentifier()), - ).rejects.toThrow(); - }); - - it("should support a callback function for dbPath client option", async () => { - const { signer } = createSigner(); - - const client = await Client.create(signer, { - dbPath: (inboxId: string) => `./user-${inboxId}.db3`, - }); - expect(client).toBeDefined(); - - const database = path.join(process.cwd(), `./user-${client.inboxId}.db3`); - expect(fs.existsSync(database)).toBe(true); - }); - - it("should create a client with Uint8Array encryption key", async () => { - const { signer } = createSigner(); - const encryptionKey = new Uint8Array(32).fill(1); - - const client = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - dbEncryptionKey: encryptionKey, - }); - - expect(client).toBeDefined(); - }); - - it("should create a client with hex string encryption key with 0x prefix", async () => { - const { signer } = createSigner(); - const encryptionKey = - "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; - - const client = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - dbEncryptionKey: encryptionKey, - }); - - expect(client).toBeDefined(); - }); - - it("should return a version", async () => { - const { signer } = createSigner(); - const client = await createClient(signer); - expect(client.appVersion).toBeDefined(); - expect(client.libxmtpVersion).toBeDefined(); - }); - - it("should register an identity", async () => { - const { signer } = createSigner(); - await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer); - expect(client2.isRegistered).toBe(true); - }); - - it("should be able to message a registered identity", async () => { - const { signer, address } = createSigner(); - const client = await createRegisteredClient(signer); - const canMessage = await client.canMessage([await signer.getIdentifier()]); - expect(Object.fromEntries(canMessage)).toEqual({ - [address]: true, - }); - }); - - it("should be able to check if an identifier can be messaged without a client instance", async () => { - const { signer, address } = createSigner(); - await createRegisteredClient(signer); - const canMessage = await Client.canMessage( - [await signer.getIdentifier()], - await createBackend({ env: "local" }), - ); - expect(Object.fromEntries(canMessage)).toEqual({ - [address]: true, - }); - }); - - it("should get an inbox ID from an address", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const inboxId = await client.fetchInboxIdByIdentifier( - await signer.getIdentifier(), - ); - expect(inboxId).toBe(client.inboxId); - }); - - it("should add a wallet association to the client", async () => { - const { signer } = createSigner(); - const { signer: signer2 } = createSigner(); - const client = await createRegisteredClient(signer); - - await client.unsafe_addAccount(signer2, true); - - const inboxState = await client.preferences.inboxState(); - expect(inboxState.identifiers.length).toEqual(2); - expect(inboxState.identifiers).toContainEqual(await signer.getIdentifier()); - expect(inboxState.identifiers).toContainEqual( - await signer2.getIdentifier(), - ); - }); - - it("should remove a wallet association from the client", async () => { - const { signer } = createSigner(); - const { signer: signer2 } = createSigner(); - const client = await createRegisteredClient(signer); - - await client.unsafe_addAccount(signer2, true); - await client.removeAccount(await signer2.getIdentifier()); - - const inboxState = await client.preferences.inboxState(); - expect(inboxState.identifiers).toEqual([await signer.getIdentifier()]); - }); - - it("should revoke specific installations", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client3 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - const inboxState = await client3.preferences.fetchInboxState(); - expect(inboxState.installations.length).toBe(3); - - const installationIds = inboxState.installations.map((i) => i.id); - expect(installationIds).toContain(client.installationId); - expect(installationIds).toContain(client2.installationId); - expect(installationIds).toContain(client3.installationId); - - await client3.revokeInstallations([client.installationIdBytes]); - - const inboxState2 = await client3.preferences.fetchInboxState(); - - expect(inboxState2.installations.length).toBe(2); - - const installationIds2 = inboxState2.installations.map((i) => i.id); - expect(installationIds2).toContain(client2.installationId); - expect(installationIds2).toContain(client3.installationId); - expect(installationIds2).not.toContain(client.installationId); - }); - - it("should revoke all other installations", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client3 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - const inboxState = await client3.preferences.fetchInboxState(); - expect(inboxState.installations.length).toBe(3); - - const installationIds = inboxState.installations.map((i) => i.id); - expect(installationIds).toContain(client.installationId); - expect(installationIds).toContain(client2.installationId); - expect(installationIds).toContain(client3.installationId); - - await client3.revokeAllOtherInstallations(); - - const inboxState2 = await client3.preferences.fetchInboxState(); - - expect(inboxState2.installations.length).toBe(1); - expect(inboxState2.installations[0].id).toBe(client3.installationId); - }); - - it("should not fail when revoking all other installations with only one installation", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - - const inboxState = await client.preferences.fetchInboxState(); - expect(inboxState.installations.length).toBe(1); - expect(inboxState.installations[0].id).toBe(client.installationId); - - await expect(client.revokeAllOtherInstallations()).resolves.not.toThrow(); - }); - - it("should statically revoke specific installations", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client3 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - const inboxState = await client3.preferences.fetchInboxState(); - expect(inboxState.installations.length).toBe(3); - - const installationIds = inboxState.installations.map((i) => i.id); - expect(installationIds).toContain(client.installationId); - expect(installationIds).toContain(client2.installationId); - expect(installationIds).toContain(client3.installationId); - - await Client.revokeInstallations( - signer, - client3.inboxId, - [client.installationIdBytes], - "local", - ); - - const inboxState2 = await client3.preferences.fetchInboxState(); - - expect(inboxState2.installations.length).toBe(2); - - const installationIds2 = inboxState2.installations.map((i) => i.id); - expect(installationIds2).toContain(client2.installationId); - expect(installationIds2).toContain(client3.installationId); - expect(installationIds2).not.toContain(client.installationId); - }); - - it("should throw when trying to create more than 10 installations", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client3 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client4 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client5 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client6 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client7 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client8 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client9 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client10 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - const inboxState = await client3.preferences.fetchInboxState(); - expect(inboxState.installations.length).toBe(10); - - const installationIds = inboxState.installations.map((i) => i.id); - expect(installationIds).toContain(client.installationId); - expect(installationIds).toContain(client2.installationId); - expect(installationIds).toContain(client3.installationId); - expect(installationIds).toContain(client4.installationId); - expect(installationIds).toContain(client5.installationId); - expect(installationIds).toContain(client6.installationId); - expect(installationIds).toContain(client7.installationId); - expect(installationIds).toContain(client8.installationId); - expect(installationIds).toContain(client9.installationId); - expect(installationIds).toContain(client10.installationId); - - await expect( - createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }), - ).rejects.toThrow(); - }); - - it("should verify signatures", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const signatureText = "gm1"; - const signature = client.signWithInstallationKey(signatureText); - const verified = client.verifySignedWithInstallationKey( - signatureText, - signature, - ); - expect(verified).toBe(true); - const verified2 = Client.verifySignedWithPublicKey( - signatureText, - signature, - client.installationIdBytes, - ); - expect(verified2).toBe(true); - - const signatureText2 = new Uint8Array(32).fill(1); - const signature2 = client.signWithInstallationKey( - uint8ArrayToHex(signatureText2), - ); - const verified3 = Client.verifySignedWithPublicKey( - uint8ArrayToHex(signatureText2), - signature2, - client.installationIdBytes, - ); - expect(verified3).toBe(true); - const verified4 = Client.verifySignedWithPublicKey( - uint8ArrayToHex(signatureText2), - signature, - client.installationIdBytes, - ); - expect(verified4).toBe(false); - }); - - it("should check if an address is authorized", async () => { - const { signer, address } = createSigner(); - const client = await createRegisteredClient(signer); - const authorized = await Client.isAddressAuthorized( - client.inboxId, - address, - "local", - ); - expect(authorized).toBe(true); - - const authorized2 = await Client.isAddressAuthorized( - client.inboxId, - "0x1234567890123456789012345678901234567890", - "local", - ); - expect(authorized2).toBe(false); - }); - - it("should check if an installation is authorized", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const authorized = await Client.isInstallationAuthorized( - client.inboxId, - client.installationIdBytes, - "local", - ); - expect(authorized).toBe(true); - - const authorized2 = await Client.isInstallationAuthorized( - client.inboxId, - new Uint8Array(32), - "local", - ); - expect(authorized2).toBe(false); - }); - - it("should change the recovery identifier", async () => { - const { signer } = createSigner(); - const { signer: signer2 } = createSigner(); - const client = await createRegisteredClient(signer); - - const inboxState = await client.preferences.inboxState(); - expect(inboxState.recoveryIdentifier).toEqual(await signer.getIdentifier()); - - await client.changeRecoveryIdentifier(await signer2.getIdentifier()); - - const inboxState2 = await client.preferences.inboxState(); - expect(inboxState2.recoveryIdentifier).toEqual( - await signer2.getIdentifier(), - ); - }); - - it("should read key package lifetime for specific installations", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - const client3 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - const inboxState = await client3.preferences.fetchInboxState(); - expect(inboxState.installations.length).toBe(3); - - const keyPackageStatuses = await client3.fetchKeyPackageStatuses([ - client.installationId, - client2.installationId, - client3.installationId, - ]); - expect( - (keyPackageStatuses[client.installationId].lifetime?.notAfter ?? 0n) - - (keyPackageStatuses[client.installationId].lifetime?.notBefore ?? 0n), - ).toEqual(BigInt(3600 * 24 * 28 * 3 + 3600)); - }); - - it("should throw errors when client is not initialized", async () => { - const client = new Client({ env: "local" }); - - await expect(async () => - client.unsafe_createInboxSignatureRequest(), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => - client.unsafe_addAccountSignatureRequest(createIdentifier(createUser())), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => - client.unsafe_removeAccountSignatureRequest( - createIdentifier(createUser()), - ), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => - client.unsafe_revokeAllOtherInstallationsSignatureRequest(), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => - client.unsafe_revokeInstallationsSignatureRequest([new Uint8Array()]), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => - client.unsafe_changeRecoveryIdentifierSignatureRequest( - createIdentifier(createUser()), - ), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => - client.unsafe_addAccount(createSigner().signer), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => - client.changeRecoveryIdentifier(createIdentifier(createUser())), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => - client.removeAccount(createIdentifier(createUser())), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => - client.revokeAllOtherInstallations(), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => - client.revokeInstallations([new Uint8Array()]), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => client.register()).rejects.toThrow( - new ClientNotInitializedError(), - ); - await expect(async () => - client.canMessage([createIdentifier(createUser())]), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => - client.fetchKeyPackageStatuses([]), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => - client.fetchInboxIdByIdentifier(createIdentifier(createUser())), - ).rejects.toThrow(new ClientNotInitializedError()); - await expect(async () => client.close()).rejects.toThrow( - new ClientNotInitializedError(), - ); - expect(() => client.signWithInstallationKey("gm1")).toThrow( - new ClientNotInitializedError(), - ); - expect(() => - client.verifySignedWithInstallationKey("gm1", new Uint8Array()), - ).toThrow(new ClientNotInitializedError()); - expect(() => client.conversations).toThrow(new ClientNotInitializedError()); - expect(() => client.preferences).toThrow(new ClientNotInitializedError()); - expect(() => client.inboxId).toThrow(new ClientNotInitializedError()); - expect(() => client.installationId).toThrow( - new ClientNotInitializedError(), - ); - expect(() => client.installationIdBytes).toThrow( - new ClientNotInitializedError(), - ); - expect(() => client.isRegistered).toThrow(new ClientNotInitializedError()); - }); - - it("should close the client idempotently", async () => { - const { signer } = createSigner(); - const client = await createClient(signer); - await client.close(); - // a second call must resolve without throwing - await expect(client.close()).resolves.not.toThrow(); - }); - - it("should get inbox states from inbox IDs without a client", async () => { - const { signer } = createSigner(); - const { signer: signer2 } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer2); - const inboxStates = await Client.fetchInboxStates( - [client.inboxId], - "local", - ); - expect(inboxStates.length).toBe(1); - expect(inboxStates[0].inboxId).toBe(client.inboxId); - expect(inboxStates[0].identifiers).toEqual([await signer.getIdentifier()]); - - const inboxStates2 = await Client.fetchInboxStates( - [client2.inboxId], - "local", - ); - expect(inboxStates2.length).toBe(1); - expect(inboxStates2[0].inboxId).toBe(client2.inboxId); - expect(inboxStates2[0].identifiers).toEqual([ - await signer2.getIdentifier(), - ]); - }); - - it("should get latest inbox updates count from inbox IDs without a client", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const inboxUpdatesCounts = await Client.fetchLatestInboxUpdatesCount( - [client.inboxId], - "local", - ); - expect(inboxUpdatesCounts.get(client.inboxId)).toBeTypeOf("number"); - }); - - it("should get own inbox updates count from a client", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const inboxUpdatesCounts = await client.fetchLatestInboxUpdatesCount([ - client.inboxId, - ]); - const ownInboxUpdatesCount = await client.fetchOwnInboxUpdatesCount(); - expect(inboxUpdatesCounts.get(client.inboxId)).toBe(ownInboxUpdatesCount); - - expect(inboxUpdatesCounts.get(client.inboxId)).toBeTypeOf("number"); - expect(ownInboxUpdatesCount).toBeTypeOf("number"); - }); - - it("should transfer an identifier to a new inbox", async () => { - // original signer - const { signer, identifier } = createSigner(); - // temporary signer - const { signer: signer2, identifier: identifier2 } = createSigner(); - const client = await createRegisteredClient(signer); - // add temporary account - await client.unsafe_addAccount(signer2, true); - // remove existing account - await client.removeAccount(identifier); - // change recovery identifier to temporary account - await client.changeRecoveryIdentifier(identifier2); - - const inboxState = await client.preferences.fetchInboxState(); - // check that the temporary account is the only account on the inbox - expect(inboxState.identifiers).toEqual([identifier2]); - expect(inboxState.recoveryIdentifier).toEqual(identifier2); - - // temporary signer - const { signer: signer3, identifier: identifier3 } = createSigner(); - // create client to transfer original account to - const transferClient = await createRegisteredClient(signer3); - // add original account to transfer client - await transferClient.unsafe_addAccount(signer, true); - // remove temporary transfer identifier - await transferClient.removeAccount(identifier3); - // change recovery identifier to original account - await transferClient.changeRecoveryIdentifier(identifier); - - const inboxState2 = await transferClient.preferences.fetchInboxState(); - // check that the original account is the only account on the inbox - expect(inboxState2.identifiers).toEqual([identifier]); - expect(inboxState2.recoveryIdentifier).toEqual(identifier); - - // check that the inbox IDs are different - expect(client.inboxId).not.toBe(transferClient.inboxId); - - // ensure that a client can be created with the original signer - const client2 = await createRegisteredClient(signer, { - // must use a different db path to avoid errors - dbPath: `./test-${uuid()}.db3`, - }); - expect(client2.inboxId).toBe(transferClient.inboxId); - }); -}); diff --git a/sdks/node-sdk/test/Conversations.test.ts b/sdks/node-sdk/test/Conversations.test.ts deleted file mode 100644 index 3d19135a4..000000000 --- a/sdks/node-sdk/test/Conversations.test.ts +++ /dev/null @@ -1,477 +0,0 @@ -import { - ConversationType, - ListConversationsOrderBy, -} from "@xmtp/node-bindings"; -import { describe, expect, it } from "vitest"; -import { uuid } from "@/utils/uuid"; -import { createRegisteredClient, createSigner, sleep } from "@test/helpers"; - -describe("Conversations", () => { - it("should have a topic", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - expect(client.conversations.topic).toBe( - `/xmtp/mls/1/w-${client.installationId}/proto`, - ); - }); - - it("should not have initial conversations", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - expect((await client.conversations.list()).length).toBe(0); - expect(client.conversations.listDms().length).toBe(0); - expect(client.conversations.listGroups().length).toBe(0); - }); - - it("should get a group or DM by ID", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const group = await client1.conversations.createGroup([client2.inboxId]); - expect(group).toBeDefined(); - expect(group.id).toBeDefined(); - const foundGroup = await client1.conversations.getConversationById( - group.id, - ); - expect(foundGroup).toBeDefined(); - expect(foundGroup!.id).toBe(group.id); - - const dm = await client1.conversations.createDm(client2.inboxId); - expect(dm).toBeDefined(); - expect(dm.id).toBeDefined(); - const foundDm = await client1.conversations.getConversationById(dm.id); - expect(foundDm).toBeDefined(); - expect(foundDm!.id).toBe(dm.id); - }); - - it("should get a DM by inbox ID", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId); - const foundDm = client1.conversations.getDmByInboxId(client2.inboxId); - expect(foundDm).toBeDefined(); - expect(foundDm!.id).toBe(dm.id); - }); - - it("should get a DM by identifier", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2, identifier: identifier2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId); - const foundDm = - await client1.conversations.fetchDmByIdentifier(identifier2); - expect(foundDm).toBeDefined(); - expect(foundDm!.id).toBe(dm.id); - }); - - it("should get a message by ID", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const messageId = await group.sendText("gm!"); - expect(messageId).toBeDefined(); - - const message = client1.conversations.getMessageById(messageId); - expect(message).toBeDefined(); - expect(message!.id).toBe(messageId); - }); - - it("should list conversations with options", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const group1 = await client1.conversations.createGroup([client2.inboxId]); - const group2 = await client1.conversations.createGroup([client3.inboxId]); - const dm1 = await client1.conversations.createDm(client2.inboxId); - const dm2 = await client1.conversations.createDm(client3.inboxId); - - // conversations by type (group) - const groups = await client1.conversations.list({ - conversationType: ConversationType.Group, - }); - expect(groups.length).toBe(2); - expect(groups[0].id).toBe(group2.id); - expect(groups[1].id).toBe(group1.id); - - // conversations by type (dm) - const dms = await client1.conversations.list({ - conversationType: ConversationType.Dm, - }); - expect(dms.length).toBe(2); - expect(dms[0].id).toBe(dm2.id); - expect(dms[1].id).toBe(dm1.id); - - // conversations by created before timestamp - const convos = await client1.conversations.list({ - createdBeforeNs: dm2.createdAtNs, - }); - expect(convos.length).toBe(3); - expect(convos[0].id).toBe(dm1.id); - expect(convos[1].id).toBe(group2.id); - expect(convos[2].id).toBe(group1.id); - - // conversations by created after timestamp - const convos2 = await client1.conversations.list({ - createdAfterNs: group1.createdAtNs, - }); - expect(convos2.length).toBe(3); - expect(convos2[0].id).toBe(dm2.id); - expect(convos2[1].id).toBe(dm1.id); - expect(convos2[2].id).toBe(group2.id); - - // conversations by created after timestamp and before timestamp - const convos3 = await client1.conversations.list({ - createdBeforeNs: dm2.createdAtNs, - createdAfterNs: group1.createdAtNs, - }); - expect(convos3.length).toBe(2); - expect(convos3[0].id).toBe(dm1.id); - expect(convos3[1].id).toBe(group2.id); - - // conversations by limit - const convos4 = await client1.conversations.list({ - limit: 1, - orderBy: ListConversationsOrderBy.CreatedAt, - }); - expect(convos4.length).toBe(1); - expect(convos4[0].id).toBe(dm2.id); - - // conversations by order by (created at) - const convos5 = await client1.conversations.list({ - limit: 1, - orderBy: ListConversationsOrderBy.LastActivity, - }); - expect(convos5.length).toBe(1); - expect(convos5[0].id).toBe(dm2.id); - }); - - it("should stream new conversations", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const stream = await client3.conversations.stream(); - const conversation1 = await client1.conversations.createGroup([ - client3.inboxId, - ]); - const conversation2 = await client2.conversations.createDm(client3.inboxId); - - const expectedIds = [conversation1.id, conversation2.id]; - const receivedIds: string[] = []; - - setTimeout(() => { - void stream.end(); - }, 2000); - - for await (const convo of stream) { - expect(convo).toBeDefined(); - receivedIds.push(convo.id); - } - - expect(receivedIds.length).toBe(2); - expect(receivedIds.sort()).toEqual(expectedIds.sort()); - expect( - (await client3.conversations.getConversationById(conversation1.id))?.id, - ).toBe(conversation1.id); - expect( - (await client3.conversations.getConversationById(conversation2.id))?.id, - ).toBe(conversation2.id); - }); - - it("should only stream group conversations", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const { signer: signer4 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const client4 = await createRegisteredClient(signer4); - const stream = await client3.conversations.streamGroups(); - await client4.conversations.createDm(client3.inboxId); - const group1 = await client1.conversations.createGroup([client3.inboxId]); - const group2 = await client2.conversations.createGroup([client3.inboxId]); - - const expectedIds = [group1.id, group2.id]; - const receivedIds: string[] = []; - - setTimeout(() => { - void stream.end(); - }, 2000); - - for await (const convo of stream) { - expect(convo).toBeDefined(); - receivedIds.push(convo.id); - } - expect(receivedIds.length).toBe(2); - expect(receivedIds.sort()).toEqual(expectedIds.sort()); - }); - - it("should only stream dm conversations", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const { signer: signer4 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const client4 = await createRegisteredClient(signer4); - const stream = await client3.conversations.streamDms(); - await client1.conversations.createGroup([client3.inboxId]); - await client2.conversations.createGroup([client3.inboxId]); - const group3 = await client4.conversations.createDm(client3.inboxId); - - setTimeout(() => { - void stream.end(); - }, 2000); - - let count = 0; - for await (const convo of stream) { - count++; - expect(convo).toBeDefined(); - if (count === 1) { - expect(convo.id).toBe(group3.id); - } - } - expect(count).toBe(1); - }); - - it("should stream all messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - await client1.conversations.createGroup([client2.inboxId]); - await client1.conversations.createDm(client3.inboxId); - - await sleep(2000); - - const stream = await client1.conversations.streamAllMessages(); - - await client2.conversations.sync(); - const groups2 = client2.conversations.listGroups(); - - await client3.conversations.sync(); - const groups3 = client3.conversations.listDms(); - - await groups2[0].sendText("gm!"); - await groups3[0].sendText("gm2!"); - - setTimeout(() => { - void stream.end(); - }, 2000); - - let count = 0; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - if (count === 1) { - expect(message.senderInboxId).toBe(client2.inboxId); - } - if (count === 2) { - expect(message.senderInboxId).toBe(client3.inboxId); - } - } - expect(count).toBe(2); - }); - - it("should only stream group conversation messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const { signer: signer4 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const client4 = await createRegisteredClient(signer4); - await client1.conversations.createGroup([client2.inboxId]); - await client1.conversations.createGroup([client3.inboxId]); - await client1.conversations.createDm(client4.inboxId); - - await sleep(2000); - - const stream = await client1.conversations.streamAllGroupMessages(); - - const groups2 = client2.conversations; - await groups2.sync(); - const groupsList2 = await groups2.list(); - - const groups3 = client3.conversations; - await groups3.sync(); - const groupsList3 = await groups3.list(); - - const groups4 = client4.conversations; - await groups4.sync(); - const groupsList4 = await groups4.list(); - - await groupsList4[0].sendText("gm3!"); - await groupsList2[0].sendText("gm!"); - await groupsList3[0].sendText("gm2!"); - - setTimeout(() => { - void stream.end(); - }, 2000); - - let count = 0; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - if (count === 1) { - expect(message.senderInboxId).toBe(client2.inboxId); - } - if (count === 2) { - expect(message.senderInboxId).toBe(client3.inboxId); - } - } - expect(count).toBe(2); - }); - - it("should only stream dm messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const { signer: signer4 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const client4 = await createRegisteredClient(signer4); - await client1.conversations.createGroup([client2.inboxId]); - await client1.conversations.createGroup([client3.inboxId]); - await client1.conversations.createDm(client4.inboxId); - - await sleep(2000); - - const stream = await client1.conversations.streamAllDmMessages(); - - const groups2 = client2.conversations; - await groups2.sync(); - const groupsList2 = await groups2.list(); - - const groups3 = client3.conversations; - await groups3.sync(); - const groupsList3 = await groups3.list(); - - const groups4 = client4.conversations; - await groups4.sync(); - const groupsList4 = await groups4.list(); - - await groupsList2[0].sendText("gm!"); - await groupsList3[0].sendText("gm2!"); - await groupsList4[0].sendText("gm3!"); - - setTimeout(() => { - void stream.end(); - }, 2000); - - let count = 0; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - if (count === 1) { - expect(message.senderInboxId).toBe(client4.inboxId); - } - expect(count).toBe(1); - } - }); - - it("should get hmac keys", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const dm = await client1.conversations.createDm(client2.inboxId); - const hmacKeys = client1.conversations.hmacKeys(); - expect(hmacKeys).toBeDefined(); - const keys = Object.keys(hmacKeys); - expect(keys.length).toBe(2); - expect(keys).toContain(group.id); - expect(keys).toContain(dm.id); - for (const values of Object.values(hmacKeys) as { - key: Uint8Array; - epoch: bigint; - }[][]) { - expect(values.length).toBe(3); - for (const value of values) { - expect(value.key).toBeDefined(); - expect(value.key.length).toBe(42); - expect(value.epoch).toBeDefined(); - expect(typeof value.epoch).toBe("bigint"); - } - } - }); - - it("should sync groups across installations", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2, { - dbPath: `./test-${uuid()}.db3`, - }); - await createRegisteredClient(signer2); - - const group = await client.conversations.createGroup([client2.inboxId]); - await client2.conversations.sync(); - const convos = client2.conversations.listGroups(); - expect(convos.length).toBe(1); - expect(convos[0].id).toBe(group.id); - - const group2 = await client.conversations.createDm(client2.inboxId); - await client2.conversations.sync(); - const convos2 = await client2.conversations.list(); - expect(convos2.length).toBe(2); - const convos2Ids = convos2.map((c) => c.id); - expect(convos2Ids).toContain(group.id); - expect(convos2Ids).toContain(group2.id); - }); - - it("should stitch DM groups together", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm1 = await client1.conversations.createDm(client2.inboxId); - const dm2 = await client2.conversations.createDm(client1.inboxId); - - await dm1.sendText("hi"); - // since this is the last message sent, the stitched group ID will be - // this group ID - await dm2.sendText("hi"); - - await client1.conversations.sync(); - await client2.conversations.sync(); - await dm1.sync(); - await dm2.sync(); - - const dm1_2 = await client1.conversations.getConversationById(dm1.id); - const dm2_2 = await client2.conversations.getConversationById(dm2.id); - expect(dm1_2?.id).toBe(dm2.id); - expect(dm2_2?.id).toBe(dm2.id); - - const dms1 = client1.conversations.listDms(); - const dms2 = client2.conversations.listDms(); - expect(dms1[0].id).toBe(dm2.id); - expect(dms2[0].id).toBe(dm2.id); - - const dupeDms1 = await dms1[0].duplicateDms(); - const dupeDms2 = await dms2[0].duplicateDms(); - expect(dupeDms1.length).toBe(1); - expect(dupeDms2.length).toBe(1); - expect(dupeDms1[0].id).toBe(dm1.id); - expect(dupeDms2[0].id).toBe(dm1.id); - }); -}); diff --git a/sdks/node-sdk/test/DebugInformation.test.ts b/sdks/node-sdk/test/DebugInformation.test.ts deleted file mode 100644 index 2738a8a53..000000000 --- a/sdks/node-sdk/test/DebugInformation.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { createRegisteredClient, createSigner } from "@test/helpers"; - -describe("DebugInformation", () => { - it("should return network API statistics", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - - const apiStats = client.debugInformation.apiStatistics(); - expect(apiStats.fetchKeyPackage).toBe(0n); - expect(apiStats.queryGroupMessages).toBe(0n); - expect(apiStats.queryWelcomeMessages).toBe(0n); - expect(apiStats.sendGroupMessages).toBe(0n); - expect(apiStats.sendWelcomeMessages).toBe(0n); - expect(apiStats.subscribeMessages).toBe(0n); - expect(apiStats.subscribeWelcomes).toBe(0n); - expect(apiStats.uploadKeyPackage).toBe(1n); - - const apiIdentityStats = client.debugInformation.apiIdentityStatistics(); - expect(apiIdentityStats.getIdentityUpdatesV2).toBe(2n); - expect(apiIdentityStats.getInboxIds).toBe(1n); - expect(apiIdentityStats.publishIdentityUpdate).toBe(1n); - expect(apiIdentityStats.verifySmartContractWalletSignature).toBe(0n); - - client.debugInformation.clearAllStatistics(); - - const apiStats2 = client.debugInformation.apiStatistics(); - expect(apiStats2.uploadKeyPackage).toBe(0n); - expect(apiStats2.fetchKeyPackage).toBe(0n); - expect(apiStats2.sendGroupMessages).toBe(0n); - expect(apiStats2.sendWelcomeMessages).toBe(0n); - expect(apiStats2.queryGroupMessages).toBe(0n); - expect(apiStats2.queryWelcomeMessages).toBe(0n); - expect(apiStats2.subscribeMessages).toBe(0n); - - const apiIdentityStats2 = client.debugInformation.apiIdentityStatistics(); - expect(apiIdentityStats2.getIdentityUpdatesV2).toBe(0n); - expect(apiIdentityStats2.getInboxIds).toBe(0n); - expect(apiIdentityStats2.publishIdentityUpdate).toBe(0n); - expect(apiIdentityStats2.verifySmartContractWalletSignature).toBe(0n); - - const apiAggregateStats = client.debugInformation.apiAggregateStatistics(); - expect(apiAggregateStats).toBeDefined(); - }); -}); diff --git a/sdks/node-sdk/test/DeviceSync.test.ts b/sdks/node-sdk/test/DeviceSync.test.ts deleted file mode 100644 index 586d20dad..000000000 --- a/sdks/node-sdk/test/DeviceSync.test.ts +++ /dev/null @@ -1,219 +0,0 @@ -import { ConsentEntityType, ConsentState } from "@xmtp/node-bindings"; -import { describe, expect, it } from "vitest"; -import { HistorySyncUrls } from "@/constants"; -import { uuid } from "@/utils/uuid"; -import { createRegisteredClient, createSigner, sleep } from "@test/helpers"; - -describe("DeviceSync", () => { - it("should sync consent across installations", async () => { - const { signer: boSigner } = createSigner(); - const { signer: alixSigner } = createSigner(); - - const bo = await createRegisteredClient(boSigner); - - const alix = await createRegisteredClient(alixSigner); - - // create DM conversation - const dm = await alix.conversations.createDm(bo.inboxId); - const initialConsent = dm.consentState(); - expect( - initialConsent === ConsentState.Unknown || - initialConsent === ConsentState.Allowed, - ).toBe(true); - - await bo.conversations.sync(); - - // create second installation for alix - const alix2 = await createRegisteredClient(alixSigner, { - dbPath: `./test-${uuid()}.db3`, - }); - - const state = await alix2.preferences.fetchInboxState(); - expect(state.installations.length).toBe(2); - - // sync the DM on alix so conversation is pushed - await dm.sync(); - await sleep(1000); - await alix.conversations.syncAll(); - await sleep(1000); - - // alix2 syncs so it has the DM - await alix2.conversations.sync(); - await sleep(1000); - - const dm2Initial = await alix2.conversations.getConversationById(dm.id); - expect(dm2Initial).not.toBeNull(); - - const consentOnAlix2Before = dm2Initial!.consentState(); - expect( - consentOnAlix2Before === ConsentState.Unknown || - consentOnAlix2Before === ConsentState.Allowed, - ).toBe(true); - - // update consent to denied on alix - dm.updateConsentState(ConsentState.Denied); - const consentState = dm.consentState(); - expect(consentState).toBe(ConsentState.Denied); - - await alix.preferences.sync(); - await sleep(1000); - await alix2.preferences.sync(); - await sleep(1000); - - const dm2 = await alix2.conversations.getConversationById(dm.id); - expect(dm2).not.toBeNull(); - - const consentState2 = dm2!.consentState(); - expect(consentState2).toBe(ConsentState.Denied); - - // update consent back to allowed on alix2 - await alix2.preferences.setConsentStates([ - { - entityType: ConsentEntityType.GroupId, - entity: dm2!.id, - state: ConsentState.Allowed, - }, - ]); - - const convoState = await alix2.preferences.getConsentState( - ConsentEntityType.GroupId, - dm2!.id, - ); - expect(convoState).toBe(ConsentState.Allowed); - - const updatedConsentState = dm2!.consentState(); - expect(updatedConsentState).toBe(ConsentState.Allowed); - }); - - it("should sync device archive using sendSyncArchive, listAvailableArchives, and processSyncArchive", async () => { - const { signer: boSigner } = createSigner(); - const { signer: alixSigner } = createSigner(); - - const bo = await createRegisteredClient(boSigner); - - const alix = await createRegisteredClient(alixSigner); - - const group = await alix.conversations.createGroup([bo.inboxId]); - const msgFromAlix = await group.sendText("hello from alix"); - - await sleep(1000); - - // create second installation for alix - const alix2 = await createRegisteredClient(alixSigner, { - dbPath: `./test-${uuid()}.db3`, - }); - - await sleep(1000); - - await alix.syncAllDeviceSyncGroups(); - await alix.sendSyncArchive( - "123", - { - elements: [], - excludeDisappearingMessages: false, - }, - HistorySyncUrls.local, - ); - await sleep(1000); - - await bo.conversations.syncAll(); - const boGroup = await bo.conversations.getConversationById(group.id); - expect(boGroup).not.toBeNull(); - await boGroup!.sendText("hello from bo"); - - await alix.conversations.syncAll(); - await alix2.conversations.syncAll(); - - const group2Before = await alix2.conversations.getConversationById( - group.id, - ); - expect(group2Before).not.toBeNull(); - - const messagesBefore = await group2Before!.messages(); - expect(messagesBefore.length).toBe(2); - - await sleep(1000); - await alix.syncAllDeviceSyncGroups(); - await sleep(1000); - await alix2.syncAllDeviceSyncGroups(); - - // list available archives - const archives = alix2.listAvailableArchives(7); - expect(archives).toBeDefined(); - - await alix2.processSyncArchive("123"); - await sleep(1000); - await alix2.conversations.syncAll(); - - const group2After = await alix2.conversations.getConversationById(group.id); - expect(group2After).not.toBeNull(); - - const messagesAfter = await group2After!.messages(); - // verify we received messages from the archive sync - // the exact count may vary depending on sync timing - expect(messagesAfter.length).toBeGreaterThanOrEqual(2); - // check if we found the original message from alix - const foundOriginalMessage = messagesAfter.some( - (m) => m.id === msgFromAlix, - ); - if (messagesAfter.length >= 3) { - expect(foundOriginalMessage).toBe(true); - } - }); - - it("should sync messages across installations using sendSyncRequest and syncAllDeviceSyncGroups", async () => { - const { signer: boSigner } = createSigner(); - const { signer: alixSigner } = createSigner(); - - const bo = await createRegisteredClient(boSigner); - - const client1 = await createRegisteredClient(alixSigner); - - const group = await client1.conversations.createGroup([bo.inboxId]); - - // send a message before second installation is created - const msgId = await group.sendText("hi"); - const messages = await group.messages(); - expect(messages.length).toBe(2); - - // create second installation - const client2 = await createRegisteredClient(alixSigner, { - dbPath: `./test-${uuid()}.db3`, - }); - - const state = await client2.preferences.fetchInboxState(); - expect(state.installations.length).toBe(2); - - await client2.sendSyncRequest( - { - elements: [], - excludeDisappearingMessages: false, - }, - HistorySyncUrls.local, - ); - - await client1.syncAllDeviceSyncGroups(); - await sleep(1000); - await client2.syncAllDeviceSyncGroups(); - await sleep(1000); - - // sync conversations to get the group on client2 - await client2.conversations.syncAll(); - await sleep(1000); - - const client1MessageCount = (await group.messages()).length; - const group2 = await client2.conversations.getConversationById(group.id); - expect(group2).not.toBeNull(); - - const messagesOnClient2 = await group2!.messages(); - const containsMessage = messagesOnClient2.some((m) => m.id === msgId); - const client2MessageCount = messagesOnClient2.length; - - // verify client2 has the group and some messages - expect(client2MessageCount).toBeGreaterThan(0); - - if (client1MessageCount === client2MessageCount) { - expect(containsMessage).toBe(true); - } - }); -}); diff --git a/sdks/node-sdk/test/Dm.test.ts b/sdks/node-sdk/test/Dm.test.ts deleted file mode 100644 index 404211ed9..000000000 --- a/sdks/node-sdk/test/Dm.test.ts +++ /dev/null @@ -1,458 +0,0 @@ -import { - ConsentState, - ContentType, - ConversationType, - MetadataField, - metadataFieldName, - type GroupUpdated, - type MessageDisappearingSettings, -} from "@xmtp/node-bindings"; -import { describe, expect, it } from "vitest"; -import type { DecodedMessage } from "@/DecodedMessage"; -import { createRegisteredClient, createSigner, sleep } from "@test/helpers"; - -describe("Dm", () => { - it("should have a topic", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId); - expect(dm.topic).toBe(`/xmtp/mls/1/g-${dm.id}/proto`); - }); - - it("should create a dm", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const dm = await client1.conversations.createDm(client2.inboxId); - expect(dm).toBeDefined(); - expect(dm.id).toBeDefined(); - expect(dm.createdAtNs).toBeDefined(); - expect(dm.createdAt).toBeDefined(); - expect(dm.isActive).toBe(true); - expect(dm.addedByInboxId).toBe(client1.inboxId); - expect(dm.peerInboxId).toBe(client2.inboxId); - - expect((await dm.messages()).length).toBe(1); - - const members = await dm.members(); - expect(members.length).toBe(2); - const memberInboxIds = members.map((member) => member.inboxId); - expect(memberInboxIds).toContain(client1.inboxId); - expect(memberInboxIds).toContain(client2.inboxId); - - const metadata = await dm.metadata(); - expect(metadata.conversationType).toBe(ConversationType.Dm); - expect(metadata.creatorInboxId).toBe(client1.inboxId); - - expect(dm.consentState()).toBe(ConsentState.Allowed); - - const dms = client1.conversations.listDms(); - expect(dms.length).toBe(1); - expect(dms[0].id).toBe(dm.id); - - expect(client1.conversations.listDms().length).toBe(1); - expect(client1.conversations.listGroups().length).toBe(0); - - // confirm DM in other client - await client2.conversations.sync(); - const dms2 = client2.conversations.listDms(); - expect(dms2.length).toBe(1); - expect(dms2[0].id).toBe(dm.id); - expect(dms2[0].peerInboxId).toBe(client1.inboxId); - - expect(client2.conversations.listDms().length).toBe(1); - expect(client2.conversations.listGroups().length).toBe(0); - - const dupeDms = await dm.duplicateDms(); - expect(dupeDms.length).toEqual(0); - }); - - it("should create a DM with identifier", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2, identifier: identifier2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDmWithIdentifier(identifier2); - expect(dm.peerInboxId).toBe(client2.inboxId); - }); - - it("should send and list messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId); - - expect(await dm.lastMessage()).toBeDefined(); - - const text = "gm"; - await dm.sendText(text); - - const messages = await dm.messages(); - expect(messages.length).toBe(2); - expect(messages[1].content).toBe(text); - - const lastMessage = await dm.lastMessage(); - expect(lastMessage).toBeDefined(); - expect(lastMessage?.id).toBe(messages[1].id); - expect(lastMessage?.content).toBe(text); - - await client2.conversations.sync(); - const dms = client2.conversations.listDms(); - expect(dms.length).toBe(1); - - const dm2 = dms[0]; - expect(dm2).toBeDefined(); - await dm2.sync(); - expect(dm2.id).toBe(dm.id); - - const messages2 = await dm2.messages(); - expect(messages2.length).toBe(2); - expect(messages2[1].content).toBe(text); - - const lastMessage2 = await dm2.lastMessage(); - expect(lastMessage2).toBeDefined(); - expect(lastMessage2?.id).toBe(messages2[1].id); - expect(lastMessage2?.content).toBe(text); - }); - - it("should optimistically send and list messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId); - - const text = "gm"; - await dm.sendText(text, true); - - const messages = await dm.messages(); - expect(messages.length).toBe(2); - expect(messages[1].content).toBe(text); - - await client2.conversations.sync(); - const dms = client2.conversations.listDms(); - expect(dms.length).toBe(1); - - const dm2 = dms[0]; - expect(dm2).toBeDefined(); - - await dm2.sync(); - expect(dm2.id).toBe(dm.id); - - const messages2 = await dm2.messages(); - expect(messages2.length).toBe(1); - - await dm.publishMessages(); - await dm2.sync(); - - const messages4 = await dm2.messages(); - expect(messages4.length).toBe(2); - expect(messages4[1].content).toBe(text); - }); - - it("should stream messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId); - - // wait a second to exclude GroupUpdated message - await sleep(1000); - - const streamedMessages: unknown[] = []; - const stream = await dm.stream({ - onValue: (message) => { - streamedMessages.push(message.content); - }, - }); - - await dm.sendText("gm"); - await dm.sendText("gm2"); - - setTimeout(() => { - void stream.end(); - }, 100); - - let count = 0; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - } - expect(count).toBe(2); - expect(streamedMessages).toEqual(["gm", "gm2"]); - }); - - it("should manage consent state", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId); - expect(dm.consentState()).toBe(ConsentState.Allowed); - - await client2.conversations.sync(); - const dm2 = client2.conversations.listDms()[0]; - expect(dm2).toBeDefined(); - expect(dm2.consentState()).toBe(ConsentState.Unknown); - await dm2.sendText("gm!"); - expect(dm2.consentState()).toBe(ConsentState.Allowed); - }); - - it("should handle disappearing messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const stream = await client1.conversations.streamDeletedMessages(); - - // create message disappearing settings so that messages are deleted after 1 second - const messageDisappearingSettings: MessageDisappearingSettings = { - fromNs: 1n, - inNs: 2_000_000_000n, - }; - - // create a group with message disappearing settings - const dm = await client1.conversations.createDm(client2.inboxId, { - messageDisappearingSettings, - }); - - // verify that the message disappearing settings are set and enabled - expect(dm.messageDisappearingSettings()).toEqual({ - fromNs: 1n, - inNs: 2_000_000_000n, - }); - expect(dm.isMessageDisappearingEnabled()).toBe(true); - - // send messages to the group - const messageId1 = await dm.sendText("gm"); - const messageId2 = await dm.sendText("gm2"); - - // verify that the messages are sent - expect((await dm.messages()).length).toBe(3); - - // sync the messages to the other client - await client2.conversations.sync(); - const dm2 = client2.conversations.listDms()[0]; - expect(dm2).toBeDefined(); - await dm2.sync(); - - // verify that the message disappearing settings are set and enabled - expect(dm2.messageDisappearingSettings()).toEqual({ - fromNs: 1n, - inNs: 2_000_000_000n, - }); - expect(dm2.isMessageDisappearingEnabled()).toBe(true); - - // wait for the messages to be deleted - await sleep(2000); - - // verify that the messages are deleted - expect((await dm.messages()).length).toBe(1); - - // verify that the messages are deleted on the other client - expect((await dm2.messages()).length).toBe(1); - - setTimeout(() => { - void stream.end(); - }, 1000); - - let count = 0; - const messageIds: string[] = []; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - messageIds.push(message.id); - } - expect(count).toBe(2); - expect(messageIds).toContain(messageId1); - expect(messageIds).toContain(messageId2); - - // remove the message disappearing settings - await dm.removeMessageDisappearingSettings(); - - // verify that the message disappearing settings are removed - expect(dm.messageDisappearingSettings()).toEqual({ - fromNs: 0n, - inNs: 0n, - }); - - expect(dm.isMessageDisappearingEnabled()).toBe(false); - - // sync other group - await dm2.sync(); - - // verify that the message disappearing settings are set and disabled - expect(dm2.messageDisappearingSettings()).toEqual({ - fromNs: 0n, - inNs: 0n, - }); - expect(dm2.isMessageDisappearingEnabled()).toBe(false); - - // check for metadata field changes - const messages = await dm2.messages(); - const fieldChange1 = messages[1] as DecodedMessage; - expect(fieldChange1.content?.metadataFieldChanges).toBeDefined(); - expect(fieldChange1.content?.metadataFieldChanges.length).toBe(1); - expect(fieldChange1.content?.metadataFieldChanges[0].fieldName).toBe( - metadataFieldName(MetadataField.MessageExpirationFromNs), - ); - expect(fieldChange1.content?.metadataFieldChanges[0].oldValue).toBe("1"); - expect(fieldChange1.content?.metadataFieldChanges[0].newValue).toBe("0"); - - const fieldChange2 = messages[2] as DecodedMessage; - expect(fieldChange2.content?.metadataFieldChanges).toBeDefined(); - expect(fieldChange2.content?.metadataFieldChanges.length).toBe(1); - expect(fieldChange2.content?.metadataFieldChanges[0].fieldName).toBe( - metadataFieldName(MetadataField.MessageExpirationInNs), - ); - expect(fieldChange2.content?.metadataFieldChanges[0].oldValue).toBe( - "2000000000", - ); - expect(fieldChange2.content?.metadataFieldChanges[0].newValue).toBe("0"); - - // send messages to the group - await dm2.sendText("gm"); - await dm2.sendText("gm2"); - - // verify that the messages are sent - expect((await dm2.messages()).length).toBe(5); - - // sync original group - await dm.sync(); - - // verify that the messages are not deleted - expect((await dm.messages()).length).toBe(5); - }); - - it("should return paused for version", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const conversation = await client1.conversations.createDm(client2.inboxId); - expect(conversation.pausedForVersion()).toBeUndefined(); - }); - - it("should get hmac keys", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const dm = await client1.conversations.createDm(client2.inboxId); - - const hmacKeys = dm.hmacKeys(); - const groupIds = Object.keys(hmacKeys); - for (const groupId of groupIds) { - expect(hmacKeys[groupId].length).toBe(3); - expect(hmacKeys[groupId][0].key).toBeDefined(); - expect(hmacKeys[groupId][0].epoch).toBeDefined(); - expect(hmacKeys[groupId][1].key).toBeDefined(); - expect(hmacKeys[groupId][1].epoch).toBeDefined(); - expect(hmacKeys[groupId][2].key).toBeDefined(); - expect(hmacKeys[groupId][2].epoch).toBeDefined(); - } - }); - - it("should get debug info", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId); - const debugInfo = await dm.debugInfo(); - expect(debugInfo).toBeDefined(); - expect(debugInfo.epoch).toBeDefined(); - expect(debugInfo.maybeForked).toBe(false); - expect(debugInfo.forkDetails).toBe(""); - expect(debugInfo.isCommitLogForked).toBeUndefined(); - expect(debugInfo.localCommitLog).toBeDefined(); - expect(debugInfo.remoteCommitLog).toBeDefined(); - expect(debugInfo.cursor).toBeDefined(); - expect(debugInfo.cursor.length).toBeGreaterThan(0); - for (const cursor of debugInfo.cursor) { - expect(cursor.originatorId).toBeDefined(); - expect(cursor.sequenceId).toBeDefined(); - } - }); - - it("should filter messages by content type", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const dm = await client1.conversations.createDm(client2.inboxId); - - await dm.sendText("gm"); - - const messages = await dm.messages(); - expect(messages.length).toBe(2); - - const filteredMessages = await dm.messages({ - contentTypes: [ContentType.Text], - }); - expect(filteredMessages.length).toBe(1); - }); - - it("should count messages with various filters", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - // Setup: create conversation and messages once - const dm = await client1.conversations.createDm(client2.inboxId); - - await dm.sendText("text 1"); - await sleep(10); - const timestamp1 = BigInt(Date.now() * 1_000_000); - await sleep(10); - await dm.sendText("text 2"); - await sleep(10); - const timestamp2 = BigInt(Date.now() * 1_000_000); - await sleep(10); - await dm.sendText("text 3"); - - // GroupUpdated messages are not counted - expect(await dm.countMessages()).toBe(3); - - // Time filters - expect( - await dm.countMessages({ - sentBeforeNs: timestamp1, - contentTypes: [ContentType.Text], - }), - ).toBe(1); - expect( - await dm.countMessages({ - sentAfterNs: timestamp1, - }), - ).toBe(2); - expect( - await dm.countMessages({ - sentAfterNs: timestamp2, - contentTypes: [ContentType.Text], - }), - ).toBe(1); - expect( - await dm.countMessages({ - sentAfterNs: timestamp1, - sentBeforeNs: timestamp2, - }), - ).toBe(1); - - // Content type filter - expect( - await dm.countMessages({ - contentTypes: [ContentType.Text], - }), - ).toBe(3); - }); -}); diff --git a/sdks/node-sdk/test/Group.test.ts b/sdks/node-sdk/test/Group.test.ts deleted file mode 100644 index 9dcc09315..000000000 --- a/sdks/node-sdk/test/Group.test.ts +++ /dev/null @@ -1,994 +0,0 @@ -import { - ConsentState, - ContentType, - contentTypeGroupUpdated, - contentTypeLeaveRequest, - ConversationType, - DeliveryStatus, - encodeText, - GroupMessageKind, - MetadataField, - metadataFieldName, - ReactionAction, - ReactionSchema, - SortDirection, - type GroupUpdated, - type MessageDisappearingSettings, -} from "@xmtp/node-bindings"; -import { describe, expect, it } from "vitest"; -import type { DecodedMessage } from "@/DecodedMessage"; -import { - createRegisteredClient, - createSigner, - sleep, - TestCodec, -} from "@test/helpers"; - -describe("Group", () => { - it("should have a topic", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - expect(group.topic).toBe(`/xmtp/mls/1/g-${group.id}/proto`); - }); - - it("should create a group", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const group = await client1.conversations.createGroup([client2.inboxId]); - expect(group).toBeDefined(); - expect( - (await client1.conversations.getConversationById(group.id))?.id, - ).toBe(group.id); - expect(group.id).toBeDefined(); - expect(group.createdAt).toBeDefined(); - expect(group.createdAtNs).toBeDefined(); - expect(group.isActive).toBe(true); - expect(group.name).toBe(""); - expect(group.addedByInboxId).toBe(client1.inboxId); - expect((await group.messages()).length).toBe(1); - - const members = await group.members(); - expect(members.length).toBe(2); - const memberInboxIds = members.map((member) => member.inboxId); - expect(memberInboxIds).toContain(client1.inboxId); - expect(memberInboxIds).toContain(client2.inboxId); - expect(await group.metadata()).toEqual({ - conversationType: ConversationType.Group, - creatorInboxId: client1.inboxId, - }); - - expect(client1.conversations.listDms().length).toBe(0); - - const groups = client1.conversations.listGroups(); - expect(groups.length).toBe(1); - expect(groups[0].id).toBe(group.id); - - // confirm group in other client - await client2.conversations.sync(); - const groups2 = client2.conversations.listGroups(); - expect(groups2.length).toBe(1); - expect(groups2[0].id).toBe(group.id); - - expect(client2.conversations.listDms().length).toBe(0); - }); - - it("should create a group with an identifier", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2, identifier: identifier2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroupWithIdentifiers([ - identifier2, - ]); - expect(group).toBeDefined(); - expect( - (await client1.conversations.getConversationById(group.id))?.id, - ).toBe(group.id); - expect(group.id).toBeDefined(); - expect(group.createdAt).toBeDefined(); - expect(group.createdAtNs).toBeDefined(); - expect(group.isActive).toBe(true); - expect(group.name).toBe(""); - expect(group.addedByInboxId).toBe(client1.inboxId); - expect((await group.messages()).length).toBe(1); - - const members = await group.members(); - expect(members.length).toBe(2); - const memberInboxIds = members.map((member) => member.inboxId); - expect(memberInboxIds).toContain(client1.inboxId); - expect(memberInboxIds).toContain(client2.inboxId); - expect(await group.metadata()).toEqual({ - conversationType: ConversationType.Group, - creatorInboxId: client1.inboxId, - }); - - const groups = client1.conversations.listGroups(); - expect(groups.length).toBe(1); - expect(groups[0].id).toBe(group.id); - expect(client1.conversations.listDms().length).toBe(0); - - // confirm group in other client - await client2.conversations.sync(); - const groups2 = client2.conversations.listGroups(); - expect(groups2.length).toBe(1); - expect(groups2[0].id).toBe(group.id); - - expect(client2.conversations.listDms().length).toBe(0); - }); - - it("should optimistically create a group", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = client1.conversations.createGroupOptimistic({ - groupName: "foo", - groupDescription: "bar", - }); - - expect(group.id).toBeDefined(); - expect(group.name).toBe("foo"); - expect(group.description).toBe("bar"); - expect(group.imageUrl).toBe(""); - expect(group.addedByInboxId).toBe(client1.inboxId); - - const text = "gm"; - await group.sendText(text, true); - - const messages = await group.messages(); - expect(messages.length).toBe(1); - expect(messages[0].content).toBe(text); - expect(messages[0].deliveryStatus).toBe(DeliveryStatus.Unpublished); - - await group.publishMessages(); - - const messages2 = await group.messages(); - expect(messages2.length).toBe(1); - expect(messages2[0].content).toBe(text); - expect(messages2[0].deliveryStatus).toBe(DeliveryStatus.Published); - }); - - it("should optimistically create a group with members", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = client1.conversations.createGroupOptimistic({ - groupName: "foo", - groupDescription: "bar", - }); - - expect(group.id).toBeDefined(); - expect(group.name).toBe("foo"); - expect(group.description).toBe("bar"); - expect(group.imageUrl).toBe(""); - expect(group.addedByInboxId).toBe(client1.inboxId); - - const text = "gm"; - await group.sendText(text, true); - - const messages = await group.messages(); - expect(messages.length).toBe(1); - expect(messages[0].content).toBe(text); - expect(messages[0].deliveryStatus).toBe(DeliveryStatus.Unpublished); - - await group.addMembers([client2.inboxId]); - - const members = await group.members(); - const memberInboxIds = members.map((member) => member.inboxId); - expect(memberInboxIds.length).toBe(2); - expect(memberInboxIds).toContain(client1.inboxId); - expect(memberInboxIds).toContain(client2.inboxId); - - const messages3 = await group.messages(); - expect(messages3.length).toBe(2); - expect(messages3[0].content).toBe(text); - expect(messages3[0].deliveryStatus).toBe(DeliveryStatus.Published); - expect(messages3[1].deliveryStatus).toBe(DeliveryStatus.Published); - }); - - it("should create a group with options", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([], { - groupName: "foo", - groupImageUrlSquare: "https://foo/bar.png", - groupDescription: "foo", - }); - expect(group.name).toBe("foo"); - expect(group.imageUrl).toBe("https://foo/bar.png"); - expect(group.description).toBe("foo"); - }); - - it("should update group name", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([]); - expect(group.name).toBe(""); - const newName = "foo"; - await group.updateName(newName); - expect(group.name).toBe(newName); - const messages = await group.messages(); - expect(messages.length).toBe(1); - const message = messages[0] as DecodedMessage; - expect(message.content!.metadataFieldChanges).toHaveLength(1); - expect(message.content!.metadataFieldChanges[0].fieldName).toBe( - metadataFieldName(MetadataField.GroupName), - ); - expect(message.content!.metadataFieldChanges[0].oldValue).toBe(""); - expect(message.content!.metadataFieldChanges[0].newValue).toBe(newName); - }); - - it("should update group image URL", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([]); - expect(group.imageUrl).toBe(""); - const imageUrl = "https://foo/bar.jpg"; - await group.updateImageUrl(imageUrl); - expect(group.imageUrl).toBe(imageUrl); - const messages = await group.messages(); - expect(messages.length).toBe(1); - const message = messages[0] as DecodedMessage; - expect(message.content!.metadataFieldChanges).toHaveLength(1); - expect(message.content!.metadataFieldChanges[0].fieldName).toBe( - metadataFieldName(MetadataField.GroupImageUrlSquare), - ); - expect(message.content!.metadataFieldChanges[0].oldValue).toBe(""); - expect(message.content!.metadataFieldChanges[0].newValue).toBe(imageUrl); - }); - - it("should update group description", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([]); - expect(group.description).toBe(""); - const newDescription = "foo"; - await group.updateDescription(newDescription); - expect(group.description).toBe(newDescription); - const messages = await group.messages(); - expect(messages.length).toBe(1); - const message = messages[0] as DecodedMessage; - expect(message.content!.metadataFieldChanges).toHaveLength(1); - expect(message.content!.metadataFieldChanges[0].fieldName).toBe( - metadataFieldName(MetadataField.Description), - ); - expect(message.content!.metadataFieldChanges[0].oldValue).toBe(""); - expect(message.content!.metadataFieldChanges[0].newValue).toBe( - newDescription, - ); - }); - - it("should update group app data", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([]); - expect(group.appData).toBe(""); - const appData = "foo"; - await group.updateAppData(appData); - expect(group.appData).toBe(appData); - const messages = await group.messages(); - expect(messages.length).toBe(1); - const message = messages[0] as DecodedMessage; - expect(message.content!.metadataFieldChanges).toHaveLength(1); - expect(message.content!.metadataFieldChanges[0].fieldName).toBe( - metadataFieldName(MetadataField.AppData), - ); - expect(message.content!.metadataFieldChanges[0].oldValue).toBe(""); - expect(message.content!.metadataFieldChanges[0].newValue).toBe(appData); - }); - - it("should send and list messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - expect(await group.lastMessage()).toBeDefined(); - - const text = "gm"; - await group.sendText(text); - - const messages = await group.messages(); - expect(messages.length).toBe(2); - expect(messages[1].content).toBe(text); - - const lastMessage = await group.lastMessage(); - expect(lastMessage).toBeDefined(); - expect(lastMessage?.id).toBe(messages[1].id); - expect(lastMessage?.content).toBe(text); - - await client2.conversations.sync(); - const groups = client2.conversations.listGroups(); - expect(groups.length).toBe(1); - - const group2 = groups[0]; - expect(group2).toBeDefined(); - await group2.sync(); - expect(group2.id).toBe(group.id); - - const messages2 = await group2.messages(); - expect(messages2.length).toBe(2); - expect(messages2[1].content).toBe(text); - - const lastMessage2 = await group2.lastMessage(); - expect(lastMessage2).toBeDefined(); - expect(lastMessage2?.id).toBe(messages2[1].id); - expect(lastMessage2?.content).toBe(text); - }); - - it("should optimistically send and list messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - const text = "gm"; - await group.sendText(text, true); - - const messages = await group.messages(); - expect(messages.length).toBe(2); - expect(messages[1].content).toBe(text); - - await client2.conversations.sync(); - const groups = client2.conversations.listGroups(); - expect(groups.length).toBe(1); - - const group2 = groups[0]; - expect(group2).toBeDefined(); - - await group2.sync(); - expect(group2.id).toBe(group.id); - - const messages2 = await group2.messages(); - expect(messages2.length).toBe(1); - - await group.publishMessages(); - await group2.sync(); - - const messages4 = await group2.messages(); - expect(messages4.length).toBe(2); - expect(messages4[1].content).toBe(text); - }); - - it("should filter messages with options", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const testCodec = new TestCodec(); - const client1 = await createRegisteredClient(signer1, { - codecs: [testCodec], - }); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - // leave request message - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - await group2.requestRemoval(); - await group.sync(); - - const textMessageId = await group.sendText("gm"); - await group.sendMarkdown("# gm"); - await group.sendAttachment({ - filename: "test.txt", - mimeType: "text/plain", - content: new Uint8Array([1, 2, 3]), - }); - await group.sendReply({ - reference: textMessageId, - referenceInboxId: client1.inboxId, - content: encodeText("gm"), - }); - const replyMessage = await group.lastMessage(); - await group.sendReaction({ - reference: textMessageId, - action: ReactionAction.Added, - content: "👍", - schema: ReactionSchema.Unicode, - referenceInboxId: client1.inboxId, - }); - await group.sendActions({ - id: "actions-1", - description: "test", - actions: [ - { - id: "opt-1", - label: "Option 1", - }, - ], - }); - await group.sendIntent({ - id: "intent-1", - actionId: "opt-1", - }); - await group.sendTransactionReference({ - networkId: "1", - reference: "1234567890", - }); - await group.sendWalletSendCalls({ - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - }, - ], - }); - await group.sendReadReceipt(); - await group.sendRemoteAttachment({ - url: "https://foo/bar.png", - contentDigest: "1234567890", - secret: new Uint8Array([1, 2, 3]), - salt: new Uint8Array([1, 2, 3]), - nonce: new Uint8Array([1, 2, 3]), - scheme: "https", - contentLength: 100, - }); - await group.sendMultiRemoteAttachment({ - attachments: [ - { - url: "https://foo/bar.png", - contentDigest: "1234567890", - secret: new Uint8Array([1, 2, 3]), - salt: new Uint8Array([1, 2, 3]), - nonce: new Uint8Array([1, 2, 3]), - scheme: "https", - contentLength: 100, - }, - ], - }); - - await group.send(testCodec.encode({ test: "test" })); - - const messages = await group.messages(); - // read receipts and reactions are automatically filtered - expect(messages.length).toBe(13); - - // default sort order - expect(messages[0].contentType).toEqual(contentTypeGroupUpdated()); - - // descending sort order - const sortedMessages1 = await group.messages({ - direction: SortDirection.Descending, - }); - expect(sortedMessages1[0].contentType).toEqual(testCodec.contentType); - - const filteredMessages1 = await group.messages({ - contentTypes: [ContentType.Text, ContentType.Markdown, ContentType.Reply], - }); - expect(filteredMessages1.length).toBe(3); - - const filteredMessages2 = await group.messages({ - contentTypes: [ - ContentType.Actions, - ContentType.Intent, - ContentType.TransactionReference, - ContentType.WalletSendCalls, - ], - }); - expect(filteredMessages2.length).toBe(4); - - const filteredMessages3 = await group.messages({ - contentTypes: [ - ContentType.Attachment, - ContentType.RemoteAttachment, - ContentType.MultiRemoteAttachment, - ], - }); - expect(filteredMessages3.length).toBe(3); - - const filteredMessages4 = await group.messages({ - contentTypes: [ - ContentType.GroupUpdated, - ContentType.LeaveRequest, - ContentType.Custom, - ], - }); - expect(filteredMessages4.length).toBe(3); - - const filteredMessages5 = await group.messages({ - excludeSenderInboxIds: [client2.inboxId], - }); - expect(filteredMessages5.length).toBe(12); - - const filteredMessages6 = await group.messages({ - excludeContentTypes: [ - ContentType.Text, - ContentType.Markdown, - ContentType.Reply, - ], - }); - expect(filteredMessages6.length).toBe(10); - - const filteredMessages7 = await group.messages({ - sentAfterNs: replyMessage?.sentAtNs, - }); - // does not include reaction and read receipt messages - expect(filteredMessages7.length).toBe(7); - - const filteredMessages8 = await group.messages({ - sentBeforeNs: replyMessage?.sentAtNs, - }); - expect(filteredMessages8.length).toBe(5); - - // initial group updated message adding a member - const filteredMessages9 = await group.messages({ - kind: GroupMessageKind.MembershipChange, - }); - expect(filteredMessages9.length).toBe(1); - - await group.sendText("gm", true); - const filteredMessages10 = await group.messages({ - deliveryStatus: DeliveryStatus.Published, - }); - expect(filteredMessages10.length).toBe(13); - const filteredMessages11 = await group.messages({ - deliveryStatus: DeliveryStatus.Unpublished, - }); - expect(filteredMessages11.length).toBe(1); - }); - - it("should stream messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - await client2.conversations.sync(); - const groups = client2.conversations.listGroups(); - expect(groups.length).toBe(1); - expect(groups[0].id).toBe(group.id); - - const streamedMessages: unknown[] = []; - const stream = await groups[0].stream({ - onValue: (message) => { - streamedMessages.push(message.content); - }, - }); - - await group.sendText("gm"); - await group.sendText("gm2"); - - setTimeout(() => { - void stream.end(); - }, 100); - - let count = 0; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - if (count === 1) { - expect(message.content).toBe("gm"); - } - if (count === 2) { - expect(message.content).toBe("gm2"); - } - } - - expect(streamedMessages).toEqual(["gm", "gm2"]); - }); - - it("should add and remove members", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const group = await client1.conversations.createGroup([client2.inboxId]); - - const members = await group.members(); - - const memberInboxIds = members.map((member) => member.inboxId); - expect(memberInboxIds).toContain(client1.inboxId); - expect(memberInboxIds).toContain(client2.inboxId); - expect(memberInboxIds).not.toContain(client3.inboxId); - - await group.addMembers([client3.inboxId]); - - const members2 = await group.members(); - expect(members2.length).toBe(3); - - const memberInboxIds2 = members2.map((member) => member.inboxId); - expect(memberInboxIds2).toContain(client1.inboxId); - expect(memberInboxIds2).toContain(client2.inboxId); - expect(memberInboxIds2).toContain(client3.inboxId); - - await group.removeMembers([client2.inboxId]); - - const members3 = await group.members(); - expect(members3.length).toBe(2); - - const memberInboxIds3 = members3.map((member) => member.inboxId); - expect(memberInboxIds3).toContain(client1.inboxId); - expect(memberInboxIds3).not.toContain(client2.inboxId); - expect(memberInboxIds3).toContain(client3.inboxId); - - const messages = (await group.messages()) as DecodedMessage[]; - expect(messages.length).toBe(3); - expect(messages[0].content?.addedInboxes).toHaveLength(1); - expect(messages[0].content?.addedInboxes[0].inboxId).toBe(client2.inboxId); - expect(messages[1].content?.addedInboxes).toHaveLength(1); - expect(messages[1].content?.addedInboxes[0].inboxId).toBe(client3.inboxId); - expect(messages[2].content?.removedInboxes).toHaveLength(1); - expect(messages[2].content?.removedInboxes[0].inboxId).toBe( - client2.inboxId, - ); - }); - - it("should add and remove admins", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - expect(group.isSuperAdmin(client1.inboxId)).toBe(true); - expect(group.listSuperAdmins().length).toBe(1); - expect(group.listSuperAdmins()).toContain(client1.inboxId); - expect(group.isAdmin(client1.inboxId)).toBe(false); - expect(group.isAdmin(client2.inboxId)).toBe(false); - expect(group.listAdmins().length).toBe(0); - - await group.addAdmin(client2.inboxId); - expect(group.isAdmin(client2.inboxId)).toBe(true); - expect(group.listAdmins().length).toBe(1); - expect(group.listAdmins()).toContain(client2.inboxId); - - await group.removeAdmin(client2.inboxId); - expect(group.isAdmin(client2.inboxId)).toBe(false); - expect(group.listAdmins().length).toBe(0); - - const messages = (await group.messages()) as DecodedMessage[]; - expect(messages.length).toBe(3); - expect(messages[1].content?.addedAdminInboxes).toHaveLength(1); - expect(messages[1].content?.addedAdminInboxes[0].inboxId).toBe( - client2.inboxId, - ); - expect(messages[2].content?.removedAdminInboxes).toHaveLength(1); - expect(messages[2].content?.removedAdminInboxes[0].inboxId).toBe( - client2.inboxId, - ); - }); - - it("should add and remove super admins", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - expect(group.isSuperAdmin(client1.inboxId)).toBe(true); - expect(group.isSuperAdmin(client2.inboxId)).toBe(false); - expect(group.listSuperAdmins().length).toBe(1); - expect(group.listSuperAdmins()).toContain(client1.inboxId); - - await group.addSuperAdmin(client2.inboxId); - expect(group.isSuperAdmin(client2.inboxId)).toBe(true); - expect(group.listSuperAdmins().length).toBe(2); - expect(group.listSuperAdmins()).toContain(client1.inboxId); - expect(group.listSuperAdmins()).toContain(client2.inboxId); - - await group.removeSuperAdmin(client2.inboxId); - expect(group.isSuperAdmin(client2.inboxId)).toBe(false); - expect(group.listSuperAdmins().length).toBe(1); - expect(group.listSuperAdmins()).toContain(client1.inboxId); - - const messages = (await group.messages()) as DecodedMessage[]; - expect(messages.length).toBe(3); - expect(messages[1].content?.addedSuperAdminInboxes).toHaveLength(1); - expect(messages[1].content?.addedSuperAdminInboxes[0].inboxId).toBe( - client2.inboxId, - ); - expect(messages[2].content?.removedSuperAdminInboxes).toHaveLength(1); - expect(messages[2].content?.removedSuperAdminInboxes[0].inboxId).toBe( - client2.inboxId, - ); - }); - - it("should manage consent state", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - expect(group).toBeDefined(); - expect(group.consentState()).toBe(ConsentState.Allowed); - - await client2.conversations.sync(); - const group2 = await client2.conversations.getConversationById(group.id); - expect(group2).toBeDefined(); - expect(group2!.consentState()).toBe(ConsentState.Unknown); - await group2!.sendText("gm!"); - expect(group2!.consentState()).toBe(ConsentState.Allowed); - }); - - it("should handle disappearing messages", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const stream = await client1.conversations.streamDeletedMessages(); - - // create message disappearing settings so that messages are deleted after 1 second - const messageDisappearingSettings: MessageDisappearingSettings = { - fromNs: 1n, - inNs: 2_000_000_000n, - }; - - // create a group with message disappearing settings - const group = await client1.conversations.createGroup([client2.inboxId], { - messageDisappearingSettings, - }); - - // verify that the message disappearing settings are set and enabled - expect(group.messageDisappearingSettings()).toEqual({ - fromNs: 1n, - inNs: 2_000_000_000n, - }); - expect(group.isMessageDisappearingEnabled()).toBe(true); - - // send messages to the group - const messageId1 = await group.sendText("gm"); - const messageId2 = await group.sendText("gm2"); - - // verify that the messages are sent - expect((await group.messages()).length).toBe(3); - - // sync the messages to the other client - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - await group2.sync(); - - // verify that the message disappearing settings are set and enabled - expect(group2.messageDisappearingSettings()).toEqual({ - fromNs: 1n, - inNs: 2_000_000_000n, - }); - expect(group2.isMessageDisappearingEnabled()).toBe(true); - - // wait for the messages to be deleted - await sleep(2000); - - // verify that the messages are deleted - expect((await group.messages()).length).toBe(1); - - // verify that the messages are deleted on the other client - expect((await group2.messages()).length).toBe(1); - - setTimeout(() => { - void stream.end(); - }, 1000); - - let count = 0; - const messageIds: string[] = []; - for await (const message of stream) { - count++; - expect(message).toBeDefined(); - messageIds.push(message.id); - } - expect(count).toBe(2); - expect(messageIds).toContain(messageId1); - expect(messageIds).toContain(messageId2); - - // remove the message disappearing settings - await group.removeMessageDisappearingSettings(); - - // verify that the message disappearing settings are removed - expect(group.messageDisappearingSettings()).toEqual({ - fromNs: 0n, - inNs: 0n, - }); - - expect(group.isMessageDisappearingEnabled()).toBe(false); - - // sync other group - await group2.sync(); - - // verify that the message disappearing settings are set and disabled - expect(group2.messageDisappearingSettings()).toEqual({ - fromNs: 0n, - inNs: 0n, - }); - expect(group2.isMessageDisappearingEnabled()).toBe(false); - - // check for metadata field changes - const messages = await group2.messages(); - const fieldChange1 = messages[1] as DecodedMessage; - expect(fieldChange1.content?.metadataFieldChanges).toBeDefined(); - expect(fieldChange1.content?.metadataFieldChanges.length).toBe(1); - expect(fieldChange1.content?.metadataFieldChanges[0].fieldName).toBe( - metadataFieldName(MetadataField.MessageExpirationFromNs), - ); - expect(fieldChange1.content?.metadataFieldChanges[0].oldValue).toBe("1"); - expect(fieldChange1.content?.metadataFieldChanges[0].newValue).toBe("0"); - - const fieldChange2 = messages[2] as DecodedMessage; - expect(fieldChange2.content?.metadataFieldChanges).toBeDefined(); - expect(fieldChange2.content?.metadataFieldChanges.length).toBe(1); - expect(fieldChange2.content?.metadataFieldChanges[0].fieldName).toBe( - metadataFieldName(MetadataField.MessageExpirationInNs), - ); - expect(fieldChange2.content?.metadataFieldChanges[0].oldValue).toBe( - "2000000000", - ); - expect(fieldChange2.content?.metadataFieldChanges[0].newValue).toBe("0"); - - // send messages to the group - await group2.sendText("gm"); - await group2.sendText("gm2"); - - // verify that the messages are sent - expect((await group2.messages()).length).toBe(5); - - // sync original group - await group.sync(); - - // verify that the messages are not deleted - expect((await group.messages()).length).toBe(5); - }); - - it("should return paused for version", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createDm(client2.inboxId); - expect(group.pausedForVersion()).toBeUndefined(); - }); - - it("should get hmac keys", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const group = await client1.conversations.createGroup([client2.inboxId]); - - const hmacKeys = group.hmacKeys(); - const groupIds = Object.keys(hmacKeys); - for (const groupId of groupIds) { - expect(hmacKeys[groupId].length).toBe(3); - expect(hmacKeys[groupId][0].key).toBeDefined(); - expect(hmacKeys[groupId][0].epoch).toBeDefined(); - expect(hmacKeys[groupId][1].key).toBeDefined(); - expect(hmacKeys[groupId][1].epoch).toBeDefined(); - expect(hmacKeys[groupId][2].key).toBeDefined(); - expect(hmacKeys[groupId][2].epoch).toBeDefined(); - } - }); - - it("should get debug info", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const debugInfo = await group.debugInfo(); - expect(debugInfo).toBeDefined(); - expect(debugInfo.epoch).toBeDefined(); - expect(debugInfo.maybeForked).toBe(false); - expect(debugInfo.forkDetails).toBe(""); - expect(debugInfo.isCommitLogForked).toBeUndefined(); - expect(debugInfo.localCommitLog).toBeDefined(); - expect(debugInfo.remoteCommitLog).toBeDefined(); - expect(debugInfo.cursor).toBeDefined(); - expect(debugInfo.cursor.length).toBeGreaterThan(0); - for (const cursor of debugInfo.cursor) { - expect(cursor.originatorId).toBeDefined(); - expect(cursor.sequenceId).toBeDefined(); - } - }); - - it("should count messages with various filters", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - const group = await client1.conversations.createGroup([client2.inboxId]); - - await group.sendText("text 1"); - await sleep(10); - const timestamp1 = BigInt(Date.now() * 1_000_000); - await sleep(10); - await group.sendText("text 2"); - await sleep(10); - const timestamp2 = BigInt(Date.now() * 1_000_000); - await sleep(10); - await group.sendText("text 3"); - - expect(await group.countMessages()).toBe(4); - - // Time filters - expect( - await group.countMessages({ - sentBeforeNs: timestamp1, - contentTypes: [ContentType.Text], - }), - ).toBe(1); - expect( - await group.countMessages({ - sentAfterNs: timestamp1, - }), - ).toBe(2); - expect( - await group.countMessages({ - sentAfterNs: timestamp2, - contentTypes: [ContentType.Text], - }), - ).toBe(1); - expect( - await group.countMessages({ - sentAfterNs: timestamp1, - sentBeforeNs: timestamp2, - }), - ).toBe(1); - - // Content type filter - expect( - await group.countMessages({ - contentTypes: [ContentType.Text], - }), - ).toBe(3); - }); - - it("should have pending removal state after requesting removal from the group", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - await client1.conversations.createGroup([client2.inboxId]); - - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - - expect(group2.isPendingRemoval()).toBe(false); - await group2.requestRemoval(); - expect(group2.isPendingRemoval()).toBe(true); - expect(group2.isActive).toBe(true); - - const messages = await group2.messages(); - const leaveRequestMessage = messages[1]; - expect(leaveRequestMessage.contentType).toEqual(contentTypeLeaveRequest()); - }); - - it("should remove a member after processing their removal request", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - - await group2.requestRemoval(); - - // messages and welcomes must be synced - await client2.conversations.syncAll(); - await client1.conversations.syncAll(); - - // wait for worker to process the removal request - await sleep(4000); - - await group2.sync(); - - expect(group2.isActive).toBe(false); - expect(group2.isPendingRemoval()).toBe(true); - - expect(await group.members()).toHaveLength(1); - expect(await group2.members()).toHaveLength(1); - }); -}); diff --git a/sdks/node-sdk/test/Preferences.test.ts b/sdks/node-sdk/test/Preferences.test.ts deleted file mode 100644 index 6b6b6c262..000000000 --- a/sdks/node-sdk/test/Preferences.test.ts +++ /dev/null @@ -1,250 +0,0 @@ -import { - ConsentEntityType, - ConsentState, - type UserPreferenceUpdate, -} from "@xmtp/node-bindings"; -import { describe, expect, it } from "vitest"; -import { uuid } from "@/utils/uuid"; -import { - createClient, - createRegisteredClient, - createSigner, - sleep, -} from "@test/helpers"; - -describe("Preferences", () => { - it("should return the correct inbox state", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - const inboxState = await client.preferences.inboxState(); - expect(inboxState.inboxId).toBe(client.inboxId); - expect(inboxState.installations.map((install) => install.id)).toEqual([ - client.installationId, - ]); - expect(inboxState.identifiers).toEqual([await signer.getIdentifier()]); - expect(inboxState.recoveryIdentifier).toStrictEqual( - await signer.getIdentifier(), - ); - - const { signer: signer2 } = createSigner(); - const client2 = await createClient(signer2); - const inboxStates = await client2.preferences.fetchInboxStates([ - client.inboxId, - ]); - const inboxState2 = inboxStates[0]; - expect(inboxState2.inboxId).toBe(client.inboxId); - expect(inboxState.installations.length).toBe(1); - expect(inboxState.installations[0].id).toBe(client.installationId); - expect(inboxState2.identifiers).toEqual([await signer.getIdentifier()]); - expect(inboxState2.recoveryIdentifier).toStrictEqual( - await signer.getIdentifier(), - ); - }); - - it("should get inbox states from inbox IDs", async () => { - const { signer } = createSigner(); - const { signer: signer2 } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer2); - const inboxStates = await client.preferences.getInboxStates([ - client.inboxId, - ]); - expect(inboxStates.length).toBe(1); - expect(inboxStates[0].inboxId).toBe(client.inboxId); - expect(inboxStates[0].identifiers).toEqual([await signer.getIdentifier()]); - - const inboxStates2 = await client2.preferences.fetchInboxStates([ - client2.inboxId, - ]); - expect(inboxStates2.length).toBe(1); - expect(inboxStates2[0].inboxId).toBe(client2.inboxId); - expect(inboxStates2[0].identifiers).toEqual([ - await signer2.getIdentifier(), - ]); - }); - - it("should manage consent states", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - await client2.conversations.sync(); - const group2 = await client2.conversations.getConversationById(group.id); - - expect(group2).not.toBeNull(); - - expect( - await client2.preferences.getConsentState( - ConsentEntityType.GroupId, - group2!.id, - ), - ).toBe(ConsentState.Unknown); - - await client2.preferences.setConsentStates([ - { - entityType: ConsentEntityType.GroupId, - entity: group2!.id, - state: ConsentState.Allowed, - }, - ]); - - expect( - await client2.preferences.getConsentState( - ConsentEntityType.GroupId, - group2!.id, - ), - ).toBe(ConsentState.Allowed); - - expect(group2!.consentState()).toBe(ConsentState.Allowed); - - group2!.updateConsentState(ConsentState.Denied); - - expect( - await client2.preferences.getConsentState( - ConsentEntityType.GroupId, - group2!.id, - ), - ).toBe(ConsentState.Denied); - }); - - it("should stream consent updates", async () => { - const { signer } = createSigner(); - const { signer: signer2 } = createSigner(); - const client = await createRegisteredClient(signer); - const client2 = await createRegisteredClient(signer2); - const group = await client.conversations.createGroup([client2.inboxId]); - const stream = await client.preferences.streamConsent(); - - await sleep(1000); - group.updateConsentState(ConsentState.Denied); - - await sleep(1000); - await client.preferences.setConsentStates([ - { - entity: group.id, - entityType: ConsentEntityType.GroupId, - state: ConsentState.Allowed, - }, - ]); - - await sleep(1000); - await client.preferences.setConsentStates([ - { - entity: group.id, - entityType: ConsentEntityType.GroupId, - state: ConsentState.Denied, - }, - { - entity: client2.inboxId, - entityType: ConsentEntityType.InboxId, - state: ConsentState.Allowed, - }, - ]); - - setTimeout(() => { - void stream.end(); - }, 2000); - - let count = 0; - for await (const updates of stream) { - count++; - if (count === 1) { - expect(updates.length).toBe(1); - expect(updates[0].state).toBe(ConsentState.Denied); - expect(updates[0].entity).toBe(group.id); - expect(updates[0].entityType).toBe(ConsentEntityType.GroupId); - } else if (count === 2) { - expect(updates.length).toBe(1); - expect(updates[0].state).toBe(ConsentState.Allowed); - expect(updates[0].entity).toBe(group.id); - expect(updates[0].entityType).toBe(ConsentEntityType.GroupId); - } else if (count === 3) { - expect(updates.length).toBe(2); - expect(updates[0].state).toBe(ConsentState.Denied); - expect(updates[0].entity).toBe(group.id); - expect(updates[0].entityType).toBe(ConsentEntityType.GroupId); - expect(updates[1].state).toBe(ConsentState.Allowed); - expect(updates[1].entity).toBe(client2.inboxId); - expect(updates[1].entityType).toBe(ConsentEntityType.InboxId); - } - } - expect(count).toBe(3); - }); - - it("should stream preferences", async () => { - const { signer } = createSigner(); - const client1 = await createRegisteredClient(signer); - const { signer: signer2 } = createSigner(); - const clientB = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([clientB.inboxId]); - const stream = await client1.preferences.streamPreferences(); - - group.updateConsentState(ConsentState.Denied); - await client1.preferences.setConsentStates([ - { - entity: clientB.inboxId, - entityType: ConsentEntityType.InboxId, - state: ConsentState.Denied, - }, - ]); - - const client2 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - const client3 = await createRegisteredClient(signer, { - dbPath: `./test-${uuid()}.db3`, - }); - - await client3.conversations.syncAll(); - await sleep(1000); - await client1.conversations.syncAll(); - await sleep(1000); - await client2.conversations.syncAll(); - await sleep(1000); - - setTimeout(() => { - void stream.end(); - }, 100); - - const preferences: UserPreferenceUpdate[] = []; - for await (const update of stream) { - preferences.push(...update); - } - expect(preferences.length).toBe(4); - const consentUpdate1 = preferences[0] as Extract< - UserPreferenceUpdate, - { type: "ConsentUpdate" } - >; - expect(consentUpdate1.type).toBe("ConsentUpdate"); - expect(consentUpdate1.consent).toEqual({ - entity: group.id, - entityType: ConsentEntityType.GroupId, - state: ConsentState.Denied, - }); - const consentUpdate2 = preferences[1] as Extract< - UserPreferenceUpdate, - { type: "ConsentUpdate" } - >; - expect(consentUpdate2.type).toBe("ConsentUpdate"); - expect(consentUpdate2.consent).toEqual({ - entity: clientB.inboxId, - entityType: ConsentEntityType.InboxId, - state: ConsentState.Denied, - }); - const hmacKeyUpdate1 = preferences[2] as Extract< - UserPreferenceUpdate, - { type: "HmacKeyUpdate" } - >; - expect(hmacKeyUpdate1.type).toBe("HmacKeyUpdate"); - expect(hmacKeyUpdate1.key).toBeInstanceOf(Uint8Array); - const hmacKeyUpdate2 = preferences[3] as Extract< - UserPreferenceUpdate, - { type: "HmacKeyUpdate" } - >; - expect(hmacKeyUpdate2.type).toBe("HmacKeyUpdate"); - expect(hmacKeyUpdate2.key).toBeInstanceOf(Uint8Array); - }); -}); diff --git a/sdks/node-sdk/test/contentTypes.test.ts b/sdks/node-sdk/test/contentTypes.test.ts deleted file mode 100644 index dac8e14db..000000000 --- a/sdks/node-sdk/test/contentTypes.test.ts +++ /dev/null @@ -1,1317 +0,0 @@ -import { contentTypeToString } from "@xmtp/content-type-primitives"; -import { - ActionStyle, - contentTypeActions, - contentTypeAttachment, - contentTypeGroupUpdated, - contentTypeIntent, - contentTypeMarkdown, - contentTypeMultiRemoteAttachment, - contentTypeReaction, - contentTypeReadReceipt, - contentTypeRemoteAttachment, - contentTypeReply, - contentTypeText, - contentTypeTransactionReference, - contentTypeWalletSendCalls, - decryptAttachment, - encodeAttachment, - encodeText, - encryptAttachment, - MetadataField, - metadataFieldName, - ReactionAction, - ReactionSchema, - type Actions, - type Attachment, - type GroupUpdated, - type Intent, - type MultiRemoteAttachment, - type Reaction, - type RemoteAttachment, - type TransactionReference, - type WalletSendCalls, - type Reply as XmtpReply, -} from "@xmtp/node-bindings"; -import { describe, expect, expectTypeOf, it, type Mock } from "vitest"; -import type { DecodedMessage } from "@/DecodedMessage"; -import type { EnrichedReply } from "@/types"; -import { - isActions, - isAttachment, - isGroupUpdated, - isIntent, - isMarkdown, - isMultiRemoteAttachment, - isReaction, - isReadReceipt, - isRemoteAttachment, - isReply, - isText, - isTextReply, - isTransactionReference, - isWalletSendCalls, -} from "@/utils/messages"; -import { - createRegisteredClient, - createSigner, - DecodeFailureCodec, - TestCodec, -} from "@test/helpers"; - -describe("Content types", () => { - it("should send and receive text content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const messageId = await group.sendText("gm"); - const messages = await group.messages(); - const textMessage = messages[1]; - expect(textMessage.content).toBe("gm"); - expect(textMessage.contentType).toEqual(contentTypeText()); - expect(textMessage.fallback).toBeUndefined(); - expect(isText(textMessage)).toBe(true); - if (isText(textMessage)) { - expectTypeOf(textMessage).toEqualTypeOf>(); - } - const message = client1.conversations.getMessageById(messageId); - expect(message).toBeDefined(); - expect(message?.content).toBe("gm"); - expect(message?.contentType).toEqual(contentTypeText()); - }); - - it("should send and receive markdown content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const messageId = await group.sendMarkdown("# gm"); - const messages = await group.messages(); - const markdownMessage = messages[1]; - expect(markdownMessage.content).toBe("# gm"); - expect(markdownMessage.contentType).toEqual(contentTypeMarkdown()); - expect(markdownMessage.fallback).toBeUndefined(); - expect(isMarkdown(markdownMessage)).toBe(true); - if (isMarkdown(markdownMessage)) { - expectTypeOf(markdownMessage).toEqualTypeOf>(); - } - const message = client1.conversations.getMessageById(messageId); - expect(message).toBeDefined(); - expect(message?.content).toBe("# gm"); - expect(message?.contentType).toEqual(contentTypeMarkdown()); - }); - - describe("Reaction", () => { - it("should send and receive reaction content with added action", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const textMessageId = await group.sendText("Hello!"); - const reaction: Reaction = { - reference: textMessageId, - referenceInboxId: client1.inboxId, - action: ReactionAction.Added, - content: "👍", - schema: ReactionSchema.Unicode, - }; - const reactionId = await group.sendReaction(reaction); - expect(reactionId).toBeDefined(); - const messages = await group.messages(); - const textMessage = messages[1]; - expect(textMessage.reactions.length).toBe(1); - const decodedReaction = textMessage.reactions[0]; - expect(decodedReaction.id).toBe(reactionId); - expect(decodedReaction.contentType).toEqual(contentTypeReaction()); - expect(decodedReaction.content).toEqual(reaction); - expect(decodedReaction.senderInboxId).toBe(client1.inboxId); - expect(decodedReaction.fallback).toBe( - `Reacted with "👍" to an earlier message`, - ); - expect(isReaction(decodedReaction)).toBe(true); - if (isReaction(decodedReaction)) { - expectTypeOf(decodedReaction).toEqualTypeOf>(); - } - const message = client1.conversations.getMessageById(reactionId); - expect(message).toBeDefined(); - expect(message?.content).toEqual(reaction); - expect(message?.contentType).toEqual(contentTypeReaction()); - }); - - it("should send and receive reaction content with removed action", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const textMessageId = await group.sendText("Hello!"); - const reaction: Reaction = { - reference: textMessageId, - referenceInboxId: client1.inboxId, - action: ReactionAction.Removed, - content: "👍", - schema: ReactionSchema.Unicode, - }; - const reactionId = await group.sendReaction(reaction); - const messages = await group.messages(); - const textMessage = messages[1]; - expect(textMessage.reactions.length).toBe(1); - const decodedReaction = textMessage.reactions[0]; - expect(decodedReaction.id).toBe(reactionId); - expect(decodedReaction.contentType).toEqual(contentTypeReaction()); - expect(decodedReaction.content).toEqual(reaction); - expect(decodedReaction.senderInboxId).toBe(client1.inboxId); - expect(decodedReaction.fallback).toBe( - `Removed "👍" from an earlier message`, - ); - }); - - it("should send and receive reaction content with custom schema", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const textMessageId = await group.sendText("Hello!"); - const reaction: Reaction = { - reference: textMessageId, - referenceInboxId: client1.inboxId, - action: ReactionAction.Added, - content: "custom_reaction", - schema: ReactionSchema.Custom, - }; - const reactionId = await group.sendReaction(reaction); - const messages = await group.messages(); - const textMessage = messages[1]; - expect(textMessage.reactions.length).toBe(1); - const decodedReaction = textMessage.reactions[0]; - expect(decodedReaction.id).toBe(reactionId); - expect(decodedReaction.contentType).toEqual(contentTypeReaction()); - expect(decodedReaction.content).toEqual(reaction); - expect(decodedReaction.senderInboxId).toBe(client1.inboxId); - expect(decodedReaction.fallback).toBe( - `Reacted with "custom_reaction" to an earlier message`, - ); - }); - - it("should send and receive reaction content with shortcode schema", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const textMessageId = await group.sendText("Hello!"); - const reaction: Reaction = { - reference: textMessageId, - referenceInboxId: client1.inboxId, - action: ReactionAction.Added, - content: ":grin:", - schema: ReactionSchema.Shortcode, - }; - const reactionId = await group.sendReaction(reaction); - const messages = await group.messages(); - const textMessage = messages[1]; - expect(textMessage.reactions.length).toBe(1); - const decodedReaction = textMessage.reactions[0]; - expect(decodedReaction.id).toBe(reactionId); - expect(decodedReaction.contentType).toEqual(contentTypeReaction()); - expect(decodedReaction.content).toEqual(reaction); - expect(decodedReaction.senderInboxId).toBe(client1.inboxId); - expect(decodedReaction.fallback).toBe( - `Reacted with ":grin:" to an earlier message`, - ); - }); - }); - - describe("Reply", () => { - it("should send and receive reply with text content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - const textMessageId = await group.sendText("Original message"); - const reply: XmtpReply = { - content: encodeText("This is a text reply"), - reference: textMessageId, - referenceInboxId: client1.inboxId, - }; - const replyId = await group.sendReply(reply); - - const messages = await group.messages(); - const replyMessage = messages[2]; - expect(replyMessage.contentType).toEqual(contentTypeReply()); - const replyContent = replyMessage.content as EnrichedReply; - expect(replyContent.referenceId).toBe(textMessageId); - expect(replyContent.content).toBe("This is a text reply"); - expect(replyContent.contentType).toEqual(contentTypeText()); - expect(replyContent.inReplyTo).toBeDefined(); - expect(replyContent.inReplyTo?.id).toBe(textMessageId); - expect(replyContent.inReplyTo?.content).toBe("Original message"); - expect(replyMessage.fallback).toBe( - `Replied with "This is a text reply" to an earlier message`, - ); - expect(isReply(replyMessage)).toBe(true); - expect(isTextReply(replyMessage)).toBe(true); - if (isTextReply(replyMessage)) { - expectTypeOf(replyMessage).toEqualTypeOf< - DecodedMessage> - >(); - } - const message = client1.conversations.getMessageById(replyId); - expect(message).toBeDefined(); - expect(message?.contentType).toEqual(contentTypeReply()); - const replyContent2 = message?.content as EnrichedReply; - expect(replyContent2.referenceId).toBe(textMessageId); - expect(replyContent2.content).toBe("This is a text reply"); - expect(replyContent2.inReplyTo).toBeDefined(); - expect(replyContent2.inReplyTo?.id).toBe(textMessageId); - expect(replyContent2.inReplyTo?.content).toBe("Original message"); - }); - - it("should send and receive reply with non-text content (attachment)", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - const textMessageId = await group.sendText("Original message"); - const attachment: Attachment = { - filename: "reply.png", - mimeType: "image/png", - content: new Uint8Array([1, 2, 3, 4]), - }; - const reply: XmtpReply = { - reference: textMessageId, - referenceInboxId: client1.inboxId, - content: encodeAttachment(attachment), - }; - await group.sendReply(reply); - - const messages = await group.messages(); - const replyMessage = messages[2]; - expect(isReply(replyMessage)).toBe(true); - if (isReply(replyMessage)) { - expectTypeOf(replyMessage).toEqualTypeOf< - DecodedMessage - >(); - } - expect(replyMessage.contentType).toEqual(contentTypeReply()); - const replyContent = replyMessage.content as EnrichedReply; - expect(replyContent.referenceId).toBe(textMessageId); - expect(replyContent.content).toEqual(attachment); - expect(replyContent.contentType).toEqual(contentTypeAttachment()); - expect(replyContent.inReplyTo).toBeDefined(); - expect(replyContent.inReplyTo?.id).toBe(textMessageId); - expect(replyContent.inReplyTo?.content).toBe("Original message"); - expect(replyMessage.fallback).toBe(`Replied to an earlier message`); - expect(isReply(replyMessage)).toBe(true); - expect(isTextReply(replyMessage)).toBe(false); - }); - - it("should send and receive reply with custom content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const testCodec = new TestCodec(); - const client1 = await createRegisteredClient(signer1, { - codecs: [testCodec], - }); - const client2 = await createRegisteredClient(signer2, { - codecs: [testCodec], - }); - const group = await client1.conversations.createGroup([client2.inboxId]); - const textMessageId = await group.sendText("Original message"); - const reply: XmtpReply = { - content: testCodec.encode({ test: "test" }), - reference: textMessageId, - referenceInboxId: client1.inboxId, - }; - await group.sendReply(reply); - const messages = await group.messages(); - const replyMessage = messages[2]; - expect(replyMessage.contentType).toEqual(contentTypeReply()); - const replyContent = replyMessage.content as EnrichedReply<{ - test: string; - }>; - expect(replyContent.referenceId).toBe(textMessageId); - expect(replyContent.content).toEqual({ test: "test" }); - expect(replyContent.contentType).toEqual(testCodec.contentType); - expect(replyContent.inReplyTo).toBeDefined(); - expect(replyContent.inReplyTo?.id).toBe(textMessageId); - expect(replyContent.inReplyTo?.content).toBe("Original message"); - expect(replyMessage.fallback).toBe(`Replied to an earlier message`); - }); - }); - - describe("Attachment", () => { - it("should send and receive attachment content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const attachment: Attachment = { - filename: "test.txt", - mimeType: "text/plain", - content: new Uint8Array([1, 2, 3]), - }; - const attachmentId = await group.sendAttachment(attachment); - const messages = await group.messages(); - const attachmentMessage = messages[1]; - expect(attachmentMessage.content).toEqual(attachment); - expect(attachmentMessage.contentType).toEqual(contentTypeAttachment()); - expect(attachmentMessage.fallback).toBe( - `Can't display ${attachment.filename}. This app doesn't support attachments.`, - ); - expect(isAttachment(attachmentMessage)).toBe(true); - if (isAttachment(attachmentMessage)) { - expectTypeOf(attachmentMessage).toEqualTypeOf< - DecodedMessage - >(); - } - const message = client1.conversations.getMessageById(attachmentId); - expect(message).toBeDefined(); - expect(message?.content).toEqual(attachment); - expect(message?.contentType).toEqual(contentTypeAttachment()); - }); - - it("should send and receive attachment content without filename", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const attachment: Attachment = { - mimeType: "text/plain", - content: new Uint8Array([1, 2, 3]), - }; - await group.sendAttachment(attachment); - const messages = await group.messages(); - const attachmentMessage = messages[1]; - expect(attachmentMessage.content).toEqual(attachment); - expect(attachmentMessage.contentType).toEqual(contentTypeAttachment()); - expect(attachmentMessage.fallback).toBe( - "Can't display this content. This app doesn't support attachments.", - ); - }); - }); - - describe("RemoteAttachment", () => { - it("should encrypt and decrypt attachment content", () => { - const attachment: Attachment = { - filename: "test.txt", - mimeType: "text/plain", - content: new Uint8Array([1, 2, 3]), - }; - const encryptedAttachment = encryptAttachment(attachment); - const remoteAttachment: RemoteAttachment = { - url: "https://example.com/test.txt", - contentDigest: encryptedAttachment.contentDigest, - secret: encryptedAttachment.secret, - salt: encryptedAttachment.salt, - nonce: encryptedAttachment.nonce, - scheme: "https", - contentLength: encryptedAttachment.contentLength, - filename: encryptedAttachment.filename, - }; - const decryptedAttachment = decryptAttachment( - encryptedAttachment.payload, - remoteAttachment, - ); - expect(decryptedAttachment).toEqual(attachment); - }); - - it("should send and receive remote attachment content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const remoteAttachment: RemoteAttachment = { - url: "https://example.com/test.txt", - contentDigest: "1234567890", - secret: new Uint8Array([1, 2, 3]), - salt: new Uint8Array([4, 5, 6]), - nonce: new Uint8Array([7, 8, 9]), - scheme: "https", - contentLength: 100, - filename: "test.txt", - }; - const remoteAttachmentId = - await group.sendRemoteAttachment(remoteAttachment); - const messages = await group.messages(); - const remoteAttachmentMessage = messages[1]; - expect(remoteAttachmentMessage.content).toEqual(remoteAttachment); - expect(remoteAttachmentMessage.contentType).toEqual( - contentTypeRemoteAttachment(), - ); - expect(remoteAttachmentMessage.fallback).toBe( - `Can't display ${remoteAttachment.filename}. This app doesn't support remote attachments.`, - ); - expect(isRemoteAttachment(remoteAttachmentMessage)).toBe(true); - if (isRemoteAttachment(remoteAttachmentMessage)) { - expectTypeOf(remoteAttachmentMessage).toEqualTypeOf< - DecodedMessage - >(); - } - const message = client1.conversations.getMessageById(remoteAttachmentId); - expect(message).toBeDefined(); - expect(message?.content).toEqual(remoteAttachment); - expect(message?.contentType).toEqual(contentTypeRemoteAttachment()); - }); - - it("should send and receive remote attachment content without filename", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const remoteAttachment: RemoteAttachment = { - url: "https://example.com/test.txt", - contentDigest: "1234567890", - secret: new Uint8Array([1, 2, 3]), - salt: new Uint8Array([4, 5, 6]), - nonce: new Uint8Array([7, 8, 9]), - scheme: "https", - contentLength: 100, - }; - await group.sendRemoteAttachment(remoteAttachment); - const messages = await group.messages(); - const remoteAttachmentMessage = messages[1]; - expect(remoteAttachmentMessage.contentType).toEqual( - contentTypeRemoteAttachment(), - ); - expect(remoteAttachmentMessage.content).toEqual(remoteAttachment); - expect(remoteAttachmentMessage.fallback).toBe( - "Can't display this content. This app doesn't support remote attachments.", - ); - }); - }); - - it("should send and receive multi remote attachment content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const multiRemoteAttachment: MultiRemoteAttachment = { - attachments: [ - { - url: "https://example.com/test.txt", - contentDigest: "sha256:1234567890", - secret: new Uint8Array([1, 2, 3]), - salt: new Uint8Array([4, 5, 6]), - nonce: new Uint8Array([7, 8, 9]), - scheme: "https", - contentLength: 100, - filename: "test.txt", - }, - { - url: "https://example.com/test2.txt", - contentDigest: "sha256:1234567891", - secret: new Uint8Array([1, 2, 3]), - salt: new Uint8Array([4, 5, 6]), - nonce: new Uint8Array([7, 8, 9]), - scheme: "https", - contentLength: 100, - filename: "test2.txt", - }, - ], - }; - await group.sendMultiRemoteAttachment(multiRemoteAttachment); - const messages = await group.messages(); - const multiRemoteAttachmentMessage = messages[1]; - expect(multiRemoteAttachmentMessage.content).toEqual(multiRemoteAttachment); - expect(multiRemoteAttachmentMessage.contentType).toEqual( - contentTypeMultiRemoteAttachment(), - ); - expect(multiRemoteAttachmentMessage.fallback).toBe( - "Can't display this content. This app doesn't support multiple remote attachments.", - ); - expect(isMultiRemoteAttachment(multiRemoteAttachmentMessage)).toBe(true); - if (isMultiRemoteAttachment(multiRemoteAttachmentMessage)) { - expectTypeOf(multiRemoteAttachmentMessage).toEqualTypeOf< - DecodedMessage - >(); - } - }); - - it("should send read receipts and get last read times", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - await group.sendText("gm"); - const readReceiptId = await group.sendReadReceipt(); - const readTimes = await group.lastReadTimes(); - expect(Object.keys(readTimes)).toContain(client1.inboxId); - const message = client1.conversations.getMessageById(readReceiptId); - expect(message).toBeDefined(); - expect(message?.contentType).toEqual(contentTypeReadReceipt()); - expect(message?.content).toEqual({}); - expect(isReadReceipt(message!)).toBe(true); - await client2.conversations.syncAll(); - const group2 = client2.conversations.listGroups()[0]; - await group2.sendReadReceipt(); - const readTimes2 = await group2.lastReadTimes(); - expect(Object.keys(readTimes2)).toContain(client1.inboxId); - expect(Object.keys(readTimes2)).toContain(client2.inboxId); - }); - - describe("TransactionReference", () => { - it("should send and receive transaction reference content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const transactionReference: TransactionReference = { - namespace: "test", - networkId: "1", - reference: "1234567890", - }; - const transactionReferenceId = - await group.sendTransactionReference(transactionReference); - const messages = await group.messages(); - const transactionReferenceMessage = messages[1]; - expect(transactionReferenceMessage.content).toEqual({ - namespace: "test", - networkId: "1", - reference: "1234567890", - }); - expect(transactionReferenceMessage.contentType).toEqual( - contentTypeTransactionReference(), - ); - expect(transactionReferenceMessage.fallback).toBe( - `[Crypto transaction] Use a blockchain explorer to learn more using the transaction hash: 1234567890`, - ); - expect(isTransactionReference(transactionReferenceMessage)).toBe(true); - if (isTransactionReference(transactionReferenceMessage)) { - expectTypeOf(transactionReferenceMessage).toEqualTypeOf< - DecodedMessage - >(); - } - const message = client1.conversations.getMessageById( - transactionReferenceId, - ); - expect(message).toBeDefined(); - expect(message?.content).toEqual(transactionReference); - expect(message?.contentType).toEqual(contentTypeTransactionReference()); - }); - - it("should send and receive transaction reference content without namespace", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const transactionReference: TransactionReference = { - networkId: "1", - reference: "1234567890", - }; - await group.sendTransactionReference(transactionReference); - const messages = await group.messages(); - const transactionReferenceMessage = messages[1]; - expect(transactionReferenceMessage.content).toEqual(transactionReference); - expect(transactionReferenceMessage.contentType).toEqual( - contentTypeTransactionReference(), - ); - expect(transactionReferenceMessage.fallback).toBe( - `[Crypto transaction] Use a blockchain explorer to learn more using the transaction hash: 1234567890`, - ); - }); - - it("should send and receive transaction reference content with empty reference", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const transactionReference: TransactionReference = { - networkId: "1", - reference: "", - }; - await group.sendTransactionReference(transactionReference); - const messages = await group.messages(); - const transactionReferenceMessage = messages[1]; - expect(transactionReferenceMessage.content).toEqual(transactionReference); - expect(transactionReferenceMessage.contentType).toEqual( - contentTypeTransactionReference(), - ); - expect(transactionReferenceMessage.fallback).toBe("Crypto transaction"); - }); - - it("should send and receive transaction reference content with metadata", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const transactionReference: TransactionReference = { - namespace: "test", - networkId: "1", - reference: "1234567890", - metadata: { - transactionType: "transfer", - currency: "USDC", - amount: 100, - decimals: 18, - fromAddress: "0x1234567890", - toAddress: "0x1234567890", - }, - }; - await group.sendTransactionReference(transactionReference); - const messages = await group.messages(); - const transactionReferenceMessage = messages[1]; - expect(transactionReferenceMessage.content).toEqual(transactionReference); - expect(transactionReferenceMessage.contentType).toEqual( - contentTypeTransactionReference(), - ); - expect(transactionReferenceMessage.fallback).toBe( - `[Crypto transaction] Use a blockchain explorer to learn more using the transaction hash: 1234567890`, - ); - }); - }); - - describe("WalletSendCalls", () => { - it("should send and receive wallet send calls content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const walletSendCalls: WalletSendCalls = { - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - }, - ], - }; - - const walletSendCallsId = - await group.sendWalletSendCalls(walletSendCalls); - const messages = await group.messages(); - const walletSendCallsMessage = messages[1]; - expect(walletSendCallsMessage.content).toEqual(walletSendCalls); - expect(walletSendCallsMessage.contentType).toEqual( - contentTypeWalletSendCalls(), - ); - expect(walletSendCallsMessage.fallback).toBe( - `[Transaction request generated]: ${JSON.stringify(walletSendCalls)}`, - ); - expect(isWalletSendCalls(walletSendCallsMessage)).toBe(true); - if (isWalletSendCalls(walletSendCallsMessage)) { - expectTypeOf(walletSendCallsMessage).toEqualTypeOf< - DecodedMessage - >(); - } - const message = client1.conversations.getMessageById(walletSendCallsId); - expect(message).toBeDefined(); - expect(message?.content).toEqual(walletSendCalls); - expect(message?.contentType).toEqual(contentTypeWalletSendCalls()); - }); - - it("should send and receive wallet send calls content with multiple calls", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const walletSendCalls: WalletSendCalls = { - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - }, - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - }, - ], - }; - - await group.sendWalletSendCalls(walletSendCalls); - const messages = await group.messages(); - const walletSendCallsMessage = messages[1]; - expect(walletSendCallsMessage.content).toEqual(walletSendCalls); - expect(walletSendCallsMessage.contentType).toEqual( - contentTypeWalletSendCalls(), - ); - expect(walletSendCallsMessage.fallback).toBe( - `[Transaction request generated]: ${JSON.stringify(walletSendCalls)}`, - ); - }); - - it("should send and receive wallet send calls content with metadata and capabilities", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const walletSendCalls: WalletSendCalls = { - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - metadata: { - description: "test", - transactionType: "test", - note: "test", - }, - }, - ], - capabilities: { - test: "test", - }, - }; - - await group.sendWalletSendCalls(walletSendCalls); - const messages = await group.messages(); - const walletSendCallsMessage = messages[1]; - expect(walletSendCallsMessage.content).toEqual(walletSendCalls); - expect(walletSendCallsMessage.contentType).toEqual( - contentTypeWalletSendCalls(), - ); - expect(walletSendCallsMessage.fallback).toBe( - `[Transaction request generated]: ${JSON.stringify(walletSendCalls)}`, - ); - }); - - it("should reject when sending wallet send calls content with metadata and missing `description` field", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const walletSendCalls: WalletSendCalls = { - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - metadata: { - transactionType: "test", - }, - }, - ], - }; - - await expect(group.sendWalletSendCalls(walletSendCalls)).rejects.toThrow( - "missing field `description`", - ); - }); - - it("should reject when sending wallet send calls content with metadata and missing `transactionType` field", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - const walletSendCalls: WalletSendCalls = { - version: "1.0", - chainId: "1", - from: "0x1234567890", - calls: [ - { - to: "0x1234567890", - data: "0x1234567890", - value: "0x1234567890", - metadata: { - description: "test", - }, - }, - ], - }; - - await expect(group.sendWalletSendCalls(walletSendCalls)).rejects.toThrow( - "missing field `transactionType`", - ); - }); - }); - - describe("Actions", () => { - it("should send and receive actions", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - const actions: Actions = { - id: "actions-1", - description: "Choose an option", - actions: [ - { - id: "opt-1", - label: "Option 1", - style: ActionStyle.Primary, - }, - { - id: "opt-2", - label: "Option 2", - style: ActionStyle.Secondary, - }, - ], - }; - - const actionsId = await group.sendActions(actions); - - const messages = await group.messages(); - const actionsMessage = messages[1]; - expect(actionsMessage.contentType).toEqual(contentTypeActions()); - const actionsContent = actionsMessage.content as Actions; - expect(actionsContent).toEqual(actions); - expect(actionsMessage.fallback).toBe( - `Choose an option\n\n[1] Option 1\n[2] Option 2\n\nReply with the number to select`, - ); - expect(isActions(actionsMessage)).toBe(true); - if (isActions(actionsMessage)) { - expectTypeOf(actionsMessage).toEqualTypeOf>(); - } - const message = client1.conversations.getMessageById(actionsId); - expect(message).toBeDefined(); - expect(message?.content).toEqual(actions); - expect(message?.contentType).toEqual(contentTypeActions()); - }); - - it("should send and receive actions with all styles", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - const actions: Actions = { - id: "action-styles", - description: "All styles", - actions: [ - { - id: "primary", - label: "Primary", - style: ActionStyle.Primary, - }, - { - id: "secondary", - label: "Secondary", - style: ActionStyle.Secondary, - }, - { - id: "danger", - label: "Danger", - style: ActionStyle.Danger, - }, - ], - }; - - await group.sendActions(actions); - - const messages = await group.messages(); - const actionsMessage = messages[1]; - expect(actionsMessage.content).toEqual(actions); - expect(actionsMessage.contentType).toEqual(contentTypeActions()); - expect(actionsMessage.fallback).toBe( - `All styles\n\n[1] Primary\n[2] Secondary\n[3] Danger\n\nReply with the number to select`, - ); - }); - - it("should send and receive actions with expiration", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - const expiresAtNs = 1700000000000000000n; - - const actions: Actions = { - id: "expiring-actions", - description: "Expiring action", - actions: [ - { - id: "opt-1", - label: "Option 1", - style: ActionStyle.Primary, - expiresAtNs: expiresAtNs, - }, - ], - expiresAtNs: expiresAtNs, - }; - - await group.sendActions(actions); - - const messages = await group.messages(); - const actionsMessage = messages[1]; - expect(actionsMessage.content).toEqual(actions); - expect(actionsMessage.contentType).toEqual(contentTypeActions()); - expect(actionsMessage.fallback).toBe( - `Expiring action\n\n[1] Option 1\n\nReply with the number to select`, - ); - }); - - it("should send and receive actions with image URL", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - const actions: Actions = { - id: "action-with-image", - description: "Action with image", - actions: [ - { - id: "opt-1", - label: "Option 1", - style: ActionStyle.Primary, - imageUrl: "https://example.com/image.png", - }, - ], - }; - - await group.sendActions(actions); - - const messages = await group.messages(); - const actionsMessage = messages[1]; - expect(actionsMessage.content).toEqual(actions); - expect(actionsMessage.contentType).toEqual(contentTypeActions()); - expect(actionsMessage.fallback).toBe( - `Action with image\n\n[1] Option 1\n\nReply with the number to select`, - ); - }); - }); - - describe("Intent", () => { - it("should send and receive intent", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - const intent: Intent = { - id: "intent-1", - actionId: "opt-1", - }; - - const intentId = await group.sendIntent(intent); - - const messages = await group.messages(); - const intentMessage = messages[1]; - expect(intentMessage.contentType).toEqual(contentTypeIntent()); - expect(intentMessage.content).toEqual(intent); - expect(intentMessage.fallback).toBe(`User selected action: opt-1`); - expect(isIntent(intentMessage)).toBe(true); - if (isIntent(intentMessage)) { - expectTypeOf(intentMessage).toEqualTypeOf>(); - } - const message = client1.conversations.getMessageById(intentId); - expect(message).toBeDefined(); - expect(message?.content).toEqual(intent); - expect(message?.contentType).toEqual(contentTypeIntent()); - }); - - it("should send and receive intent with metadata", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - const intent: Intent = { - id: "intent-2", - actionId: "opt-2", - metadata: { - source: "test", - timestamp: "2024-01-01", - }, - }; - - await group.sendIntent(intent); - - const messages = await group.messages(); - const intentMessage = messages[1]; - expect(intentMessage.contentType).toEqual(contentTypeIntent()); - expect(intentMessage.content).toEqual(intent); - expect(intentMessage.fallback).toBe(`User selected action: opt-2`); - }); - }); - - it("should send and receive group updated content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - await group.updateName("test"); - await group.updateDescription("test"); - await group.updateImageUrl("test"); - await group.updateAppData("test"); - await group.addAdmin(client2.inboxId); - await group.removeAdmin(client2.inboxId); - await group.addSuperAdmin(client2.inboxId); - await group.removeSuperAdmin(client2.inboxId); - await group.removeMembers([client2.inboxId]); - - const messages = await group.messages(); - expect(messages.length).toBe(10); - - for (const message of messages) { - expect(message.contentType).toEqual(contentTypeGroupUpdated()); - expect(isGroupUpdated(message)).toBe(true); - if (isGroupUpdated(message)) { - expectTypeOf(message).toEqualTypeOf>(); - } - const groupUpdated = client1.conversations.getMessageById(message.id); - expect(groupUpdated?.content).toEqual(message.content); - expect(groupUpdated?.contentType).toEqual(contentTypeGroupUpdated()); - } - - expect(messages[0].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [{ inboxId: client2.inboxId }], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - - expect(messages[1].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [ - { - fieldName: metadataFieldName(MetadataField.GroupName), - oldValue: "", - newValue: "test", - }, - ], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - expect(messages[2].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [ - { - fieldName: metadataFieldName(MetadataField.Description), - oldValue: "", - newValue: "test", - }, - ], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - expect(messages[3].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [ - { - fieldName: metadataFieldName(MetadataField.GroupImageUrlSquare), - oldValue: "", - newValue: "test", - }, - ], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - expect(messages[4].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [ - { - fieldName: metadataFieldName(MetadataField.AppData), - oldValue: "", - newValue: "test", - }, - ], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - expect(messages[5].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [], - addedAdminInboxes: [{ inboxId: client2.inboxId }], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - expect(messages[6].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [], - addedAdminInboxes: [], - removedAdminInboxes: [{ inboxId: client2.inboxId }], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - expect(messages[7].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [{ inboxId: client2.inboxId }], - removedSuperAdminInboxes: [], - }); - expect(messages[8].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [], - leftInboxes: [], - metadataFieldChanges: [], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [{ inboxId: client2.inboxId }], - }); - expect(messages[9].content).toEqual({ - initiatedByInboxId: client1.inboxId, - addedInboxes: [], - removedInboxes: [{ inboxId: client2.inboxId }], - leftInboxes: [], - metadataFieldChanges: [], - addedAdminInboxes: [], - removedAdminInboxes: [], - addedSuperAdminInboxes: [], - removedSuperAdminInboxes: [], - }); - }); - - describe("Custom content types", () => { - let consoleWarnSpy: Mock; - - beforeEach(() => { - consoleWarnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); - }); - - afterEach(() => { - consoleWarnSpy.mockRestore(); - }); - - it("should send and receive custom content", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const testCodec = new TestCodec(); - const clientWithCodec = await createRegisteredClient(signer1, { - codecs: [testCodec], - }); - const client = await createRegisteredClient(signer2); - const group = await clientWithCodec.conversations.createGroup([ - client.inboxId, - ]); - const customContentId = await group.send( - testCodec.encode({ test: "test" }), - ); - const messages = await group.messages(); - expect(messages[1].content).toEqual({ test: "test" }); - expect(messages[1].contentType).toEqual(testCodec.contentType); - const message = - clientWithCodec.conversations.getMessageById(customContentId); - expect(message).toBeDefined(); - expect(message?.content).toEqual({ test: "test" }); - expect(message?.contentType).toEqual(testCodec.contentType); - }); - - it("should have undefined content when receiving custom content without codec", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const testCodec = new TestCodec(); - const clientWithCodec = await createRegisteredClient(signer1, { - codecs: [testCodec], - }); - const client = await createRegisteredClient(signer2); - const group = await clientWithCodec.conversations.createGroup([ - client.inboxId, - ]); - await group.send(testCodec.encode({ test: "test" })); - await client.conversations.sync(); - const group2 = await client.conversations.getConversationById(group.id); - expect(group2).toBeDefined(); - await group2!.sync(); - const messages = await group2!.messages(); - expect(messages[1].content).toBeUndefined(); - expect(messages[1].contentType).toEqual(testCodec.contentType); - expect(consoleWarnSpy).toHaveBeenCalledWith( - `No codec found for content type "${contentTypeToString(testCodec.contentType)}"`, - ); - }); - - it("should have undefined content when receiving custom content with decode failure", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const decodeFailureCodec = new DecodeFailureCodec(); - const clientWithCodec = await createRegisteredClient(signer1, { - codecs: [decodeFailureCodec], - }); - const client2WithCodec = await createRegisteredClient(signer2, { - codecs: [decodeFailureCodec], - }); - const group = await clientWithCodec.conversations.createGroup([ - client2WithCodec.inboxId, - ]); - await group.send(decodeFailureCodec.encode("test")); - await client2WithCodec.conversations.sync(); - const group2 = await client2WithCodec.conversations.getConversationById( - group.id, - ); - expect(group2).toBeDefined(); - await group2!.sync(); - const messages = await group2!.messages(); - expect(messages[1].content).toBeUndefined(); - expect(messages[1].contentType).toEqual(decodeFailureCodec.contentType); - expect(consoleWarnSpy).toHaveBeenCalledWith( - "Error decoding custom content: Decode failure", - ); - }); - }); -}); diff --git a/sdks/node-sdk/test/createBackend.test.ts b/sdks/node-sdk/test/createBackend.test.ts deleted file mode 100644 index 76417f99c..000000000 --- a/sdks/node-sdk/test/createBackend.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { createBackend } from "@/utils/createBackend"; - -describe("createBackend", () => { - it("should create a backend with default options", async () => { - const backend = await createBackend(); - expect(backend).toBeDefined(); - expect(backend.env).toBe("Dev"); - }); - - it("should create a backend with a specific env", async () => { - const backend = await createBackend({ env: "production" }); - expect(backend).toBeDefined(); - expect(backend.env).toBe("Production"); - }); - - it("should create a backend with local env", async () => { - const backend = await createBackend({ env: "local" }); - expect(backend).toBeDefined(); - expect(backend.env).toBe("Local"); - }); - - it("should create a backend with gateway host", async () => { - const backend = await createBackend({ - env: "production", - gatewayHost: "https://my-gateway.example.com", - }); - expect(backend).toBeDefined(); - expect(backend.env).toBe("Production"); - }); - - it("should create a backend with appVersion", async () => { - const backend = await createBackend({ - env: "dev", - appVersion: "test/1.0.0", - }); - expect(backend).toBeDefined(); - }); - - it("should create a backend with apiUrl override", async () => { - const backend = await createBackend({ - apiUrl: "https://custom-api.example.com:5558", - }); - expect(backend).toBeDefined(); - }); - - it("should create a backend with no optional fields", async () => { - const backend = await createBackend({ env: "dev" }); - expect(backend).toBeDefined(); - expect(backend.env).toBe("Dev"); - }); -}); diff --git a/sdks/node-sdk/test/helpers.ts b/sdks/node-sdk/test/helpers.ts deleted file mode 100644 index ee32a90c0..000000000 --- a/sdks/node-sdk/test/helpers.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { - type ContentCodec, - type ContentTypeId, - type EncodedContent, -} from "@xmtp/content-type-primitives"; -import { - generateInboxId, - IdentifierKind, - type Identifier, -} from "@xmtp/node-bindings"; -import { createWalletClient, http, toBytes } from "viem"; -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; -import { sepolia } from "viem/chains"; -import { Client } from "@/Client"; -import { HistorySyncUrls } from "@/constants"; -import type { - ContentOptions, - DeviceSyncOptions, - NetworkOptions, - OtherOptions, - StorageOptions, -} from "@/types"; -import type { Signer } from "@/utils/signer"; - -type TestClientOptions = NetworkOptions & - DeviceSyncOptions & - StorageOptions & - ContentOptions & - OtherOptions; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -export const sleep = (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - -export const createUser = (key?: `0x${string}`) => { - const accountKey = key ?? generatePrivateKey(); - const account = privateKeyToAccount(accountKey); - return { - key: accountKey, - account, - wallet: createWalletClient({ - account, - chain: sepolia, - transport: http(), - }), - }; -}; - -export const createIdentifier = (user: User): Identifier => ({ - identifier: user.account.address.toLowerCase(), - identifierKind: IdentifierKind.Ethereum, -}); - -export const createSigner = () => { - const user = createUser(); - const identifier = createIdentifier(user); - const signer: Signer = { - type: "EOA", - getIdentifier: () => identifier, - signMessage: async (message: string) => { - const signature = await user.wallet.signMessage({ - message, - }); - return toBytes(signature); - }, - }; - return { - address: user.account.address.toLowerCase(), - identifier, - signer, - user, - }; -}; - -export type User = ReturnType; - -export const buildClient = async ( - identifier: Identifier, - options?: TestClientOptions & { - codecs?: ContentCodecs; - }, -) => { - const opts = { - ...options, - env: options?.env ?? "local", - }; - return Client.build(identifier, { - ...opts, - dbPath: opts.dbPath ?? `./test-${identifier.identifier}.db3`, - }); -}; - -export const createClient = async ( - signer: Signer, - options?: TestClientOptions & { - codecs?: ContentCodecs; - }, -) => { - const opts = { - ...options, - env: options?.env ?? "local", - }; - const inboxId = generateInboxId(await signer.getIdentifier()); - - let dbPath: string; - if (typeof opts.dbPath === "function") { - dbPath = opts.dbPath(inboxId); - } else { - dbPath = join(__dirname, opts.dbPath ?? `./test-${inboxId}.db3`); - } - - const client = await Client.create(signer, { - ...opts, - disableAutoRegister: true, - dbPath: dbPath, - historySyncUrl: HistorySyncUrls.local, - }); - return client; -}; - -export const createRegisteredClient = async < - ContentCodecs extends ContentCodec[] = [], ->( - signer: Signer, - options?: TestClientOptions & { - codecs?: ContentCodecs; - }, -) => { - const opts = { - ...options, - env: options?.env ?? "local", - }; - const inboxId = generateInboxId(await signer.getIdentifier()); - - let dbPath: string; - if (typeof opts.dbPath === "function") { - dbPath = opts.dbPath(inboxId); - } else { - dbPath = opts.dbPath ?? `./test-${inboxId}.db3`; - } - - return Client.create(signer, { - ...opts, - dbPath, - historySyncUrl: HistorySyncUrls.local, - }); -}; - -export const ContentTypeTest: ContentTypeId = { - authorityId: "xmtp.org", - typeId: "test", - versionMajor: 1, - versionMinor: 0, -}; - -export class TestCodec implements ContentCodec { - contentType = ContentTypeTest; - - encode(content: Record): EncodedContent { - return { - type: this.contentType, - parameters: {}, - content: new TextEncoder().encode(JSON.stringify(content)), - }; - } - - decode(content: EncodedContent): Record { - const decoded = new TextDecoder().decode(content.content); - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return JSON.parse(decoded); - } - - fallback() { - return undefined; - } - - shouldPush() { - return false; - } -} - -export class DecodeFailureCodec implements ContentCodec { - contentType = { - authorityId: "test", - typeId: "decode-failure", - versionMajor: 1, - versionMinor: 0, - }; - - encode(content: string): EncodedContent { - return { - type: this.contentType, - parameters: {}, - content: new TextEncoder().encode(content), - }; - } - - decode(_content: EncodedContent): string { - throw new Error("Decode failure"); - } - - fallback() { - return undefined; - } - - shouldPush() { - return false; - } -} diff --git a/sdks/node-sdk/test/inboxId.test.ts b/sdks/node-sdk/test/inboxId.test.ts deleted file mode 100644 index 583b5ebc7..000000000 --- a/sdks/node-sdk/test/inboxId.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { createBackend } from "@/utils/createBackend"; -import { generateInboxId, getInboxIdForIdentifier } from "@/utils/inboxId"; -import { createRegisteredClient, createSigner } from "@test/helpers"; - -describe("generateInboxId", () => { - it("should generate an inbox id", async () => { - const { signer } = createSigner(); - const inboxId = generateInboxId(await signer.getIdentifier()); - expect(inboxId).toBeDefined(); - - const inboxId2 = generateInboxId(await signer.getIdentifier(), 1n); - expect(inboxId2).toBe(inboxId); - - const inboxId3 = generateInboxId(await signer.getIdentifier(), 2n); - expect(inboxId3).not.toBe(inboxId); - }); -}); - -describe("getInboxIdForIdentifier", () => { - it("should return `undefined` inbox ID for unregistered address", async () => { - const { identifier } = createSigner(); - const backend = await createBackend({ env: "local" }); - const inboxId = await getInboxIdForIdentifier(backend, identifier); - expect(inboxId == null).toBe(true); - }); - - it("should return inbox ID for registered address", async () => { - const { signer, identifier } = createSigner(); - const client = await createRegisteredClient(signer); - const backend = await createBackend({ env: "local" }); - const inboxId = await getInboxIdForIdentifier(backend, identifier); - expect(inboxId).toBe(client.inboxId); - }); -}); diff --git a/sdks/node-sdk/test/libxmtpErrors.test.ts b/sdks/node-sdk/test/libxmtpErrors.test.ts deleted file mode 100644 index 106c676bb..000000000 --- a/sdks/node-sdk/test/libxmtpErrors.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { GroupPermissionsOptions } from "@xmtp/node-bindings"; -import { describe, expect, it } from "vitest"; -import { Group } from "@/Group"; -import { createRegisteredClient, createSigner } from "@test/helpers"; - -describe("LibXMTP errors", () => { - it("should throw when a non-admin tries to add members", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - - // client1 creates an admin-only group and adds client2 as a regular member - const group = await client1.conversations.createGroup([client2.inboxId], { - permissions: GroupPermissionsOptions.AdminOnly, - }); - - // Sync client2 so they have the group - await client2.conversations.sync(); - const group2 = await client2.conversations.getConversationById(group.id); - - // client2 (non-admin) tries to add client3 - this should fail - if (!(group2 instanceof Group)) { - throw new Error("Expected a Group conversation"); - } - - try { - await group2.addMembers([client3.inboxId]); - expect.fail("Expected an error to be thrown"); - } catch (error) { - assert(error instanceof Error); - expect( - error.message.startsWith("[GroupError::Sync] synced 1 messages"), - ).toBe(true); - } - }); - - it("should throw when adding a non-existent inbox ID", async () => { - const { signer } = createSigner(); - const client = await createRegisteredClient(signer); - - const group = await client.conversations.createGroup([]); - - const fakeInboxId = - "0000000000000000000000000000000000000000000000000000000000000000"; - - try { - await group.addMembers([fakeInboxId]); - expect.fail("Expected an error to be thrown"); - } catch (error) { - assert(error instanceof Error); - console.log(error.message); - expect(error.message).toBe( - "[GroupError::MissingSequenceId] SequenceId not found in local db", - ); - } - }); -}); diff --git a/sdks/node-sdk/test/permissions.test.ts b/sdks/node-sdk/test/permissions.test.ts deleted file mode 100644 index ccaa0ee20..000000000 --- a/sdks/node-sdk/test/permissions.test.ts +++ /dev/null @@ -1,712 +0,0 @@ -import { - GroupPermissionsOptions, - MetadataField, - PermissionPolicy, - PermissionUpdateType, -} from "@xmtp/node-bindings"; -import { describe, expect, it } from "vitest"; -import { createRegisteredClient, createSigner } from "@test/helpers"; - -describe("Group permissions", () => { - it("should create a group with default permissions", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([]); - expect(group.permissions().policyType).toBe( - GroupPermissionsOptions.Default, - ); - expect(group.permissions().policySet).toEqual({ - addMemberPolicy: PermissionPolicy.Allow, - removeMemberPolicy: PermissionPolicy.Admin, - addAdminPolicy: PermissionPolicy.SuperAdmin, - removeAdminPolicy: PermissionPolicy.SuperAdmin, - updateGroupNamePolicy: PermissionPolicy.Allow, - updateGroupDescriptionPolicy: PermissionPolicy.Allow, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, - updateMessageDisappearingPolicy: PermissionPolicy.Admin, - updateAppDataPolicy: PermissionPolicy.Allow, - }); - }); - - it("should create a group with admin only permissions", async () => { - const { signer: signer1 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const group = await client1.conversations.createGroup([], { - permissions: GroupPermissionsOptions.AdminOnly, - }); - expect(group.permissions().policyType).toBe( - GroupPermissionsOptions.AdminOnly, - ); - expect(group.permissions().policySet).toEqual({ - addMemberPolicy: PermissionPolicy.Admin, - removeMemberPolicy: PermissionPolicy.Admin, - addAdminPolicy: PermissionPolicy.SuperAdmin, - removeAdminPolicy: PermissionPolicy.SuperAdmin, - updateGroupNamePolicy: PermissionPolicy.Admin, - updateGroupDescriptionPolicy: PermissionPolicy.Admin, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Admin, - updateMessageDisappearingPolicy: PermissionPolicy.Admin, - updateAppDataPolicy: PermissionPolicy.Admin, - }); - }); - - it("should create a group with custom permissions", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId], { - permissions: GroupPermissionsOptions.CustomPolicy, - customPermissionPolicySet: { - addAdminPolicy: PermissionPolicy.Deny, - addMemberPolicy: PermissionPolicy.Allow, - removeAdminPolicy: PermissionPolicy.Deny, - removeMemberPolicy: PermissionPolicy.Deny, - updateGroupNamePolicy: PermissionPolicy.Deny, - updateGroupDescriptionPolicy: PermissionPolicy.Deny, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Deny, - updateMessageDisappearingPolicy: PermissionPolicy.Admin, - updateAppDataPolicy: PermissionPolicy.Deny, - }, - }); - expect(group.permissions().policyType).toBe( - GroupPermissionsOptions.CustomPolicy, - ); - expect(group.permissions().policySet).toEqual({ - addAdminPolicy: PermissionPolicy.Deny, - addMemberPolicy: PermissionPolicy.Allow, - removeAdminPolicy: PermissionPolicy.Deny, - removeMemberPolicy: PermissionPolicy.Deny, - updateGroupNamePolicy: PermissionPolicy.Deny, - updateGroupDescriptionPolicy: PermissionPolicy.Deny, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Deny, - updateMessageDisappearingPolicy: PermissionPolicy.Admin, - updateAppDataPolicy: PermissionPolicy.Deny, - }); - }); - - it("should update group permissions", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const group = await client1.conversations.createGroup([client2.inboxId]); - - expect(group.permissions().policySet).toEqual({ - addMemberPolicy: PermissionPolicy.Allow, - removeMemberPolicy: PermissionPolicy.Admin, - addAdminPolicy: PermissionPolicy.SuperAdmin, - removeAdminPolicy: PermissionPolicy.SuperAdmin, - updateGroupNamePolicy: PermissionPolicy.Allow, - updateGroupDescriptionPolicy: PermissionPolicy.Allow, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, - updateMessageDisappearingPolicy: PermissionPolicy.Admin, - updateAppDataPolicy: PermissionPolicy.Allow, - }); - - await group.updatePermission( - PermissionUpdateType.AddMember, - PermissionPolicy.Admin, - ); - - await group.updatePermission( - PermissionUpdateType.RemoveMember, - PermissionPolicy.SuperAdmin, - ); - - await group.updatePermission( - PermissionUpdateType.AddAdmin, - PermissionPolicy.Admin, - ); - - await group.updatePermission( - PermissionUpdateType.RemoveAdmin, - PermissionPolicy.Admin, - ); - - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.GroupName, - ); - - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.Description, - ); - - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.GroupImageUrlSquare, - ); - - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.AppData, - ); - - expect(group.permissions().policySet).toEqual({ - addMemberPolicy: PermissionPolicy.Admin, - removeMemberPolicy: PermissionPolicy.SuperAdmin, - addAdminPolicy: PermissionPolicy.Admin, - removeAdminPolicy: PermissionPolicy.Admin, - updateGroupNamePolicy: PermissionPolicy.Admin, - updateGroupDescriptionPolicy: PermissionPolicy.Admin, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Admin, - updateMessageDisappearingPolicy: PermissionPolicy.Admin, - updateAppDataPolicy: PermissionPolicy.Admin, - }); - }); - - it("should enforce add member policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const { signer: signer4 } = createSigner(); - const { signer: signer5 } = createSigner(); - const { signer: signer6 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const client4 = await createRegisteredClient(signer4); - const client5 = await createRegisteredClient(signer5); - const client6 = await createRegisteredClient(signer6); - // create group with default permissions (anyone can add members) - const group = await client1.conversations.createGroup([client2.inboxId]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - // adding a member is allowed - await group2.addMembers([client3.inboxId]); - expect(await group2.members()).toHaveLength(3); - - // update group permissions to allow only admins to add members - await group.updatePermission( - PermissionUpdateType.AddMember, - PermissionPolicy.Admin, - ); - // client2 is no longer able to add members - await expect(() => group2.addMembers([client4.inboxId])).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId); - // client2 is now able to add members - await group2.addMembers([client4.inboxId]); - expect(await group2.members()).toHaveLength(4); - - // update group permissions to allow only super admins to add members - await group.updatePermission( - PermissionUpdateType.AddMember, - PermissionPolicy.SuperAdmin, - ); - // client2 is no longer able to add members - await expect(() => group2.addMembers([client5.inboxId])).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId); - // client2 is now able to add members - await group2.addMembers([client5.inboxId]); - expect(await group2.members()).toHaveLength(5); - - // update group permissions to deny adding members - await group.updatePermission( - PermissionUpdateType.AddMember, - PermissionPolicy.Deny, - ); - // client2 is no longer able to add members - await expect(() => group2.addMembers([client6.inboxId])).rejects.toThrow(); - - // update group permissions to allow anyone to add members - await group.updatePermission( - PermissionUpdateType.AddMember, - PermissionPolicy.Allow, - ); - // client2 is able to add members again - await group2.addMembers([client6.inboxId]); - expect(await group2.members()).toHaveLength(6); - }); - - it("should enforce remove member policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const { signer: signer4 } = createSigner(); - const { signer: signer5 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - const client4 = await createRegisteredClient(signer4); - const client5 = await createRegisteredClient(signer5); - // create group with default permissions (only admins can remove members) - const group = await client1.conversations.createGroup([ - client2.inboxId, - client3.inboxId, - client4.inboxId, - client5.inboxId, - ]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - // removing a member is not allowed - await expect(() => - group2.removeMembers([client3.inboxId]), - ).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId); - // client2 is now able to remove members - await group2.removeMembers([client5.inboxId]); - expect(await group2.members()).toHaveLength(4); - - // update group permissions to allow only super admins to remove members - await group.updatePermission( - PermissionUpdateType.RemoveMember, - PermissionPolicy.SuperAdmin, - ); - // client2 is no longer able to remove members - await expect(() => - group2.removeMembers([client4.inboxId]), - ).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId); - // client2 is now able to remove members - await group2.removeMembers([client4.inboxId]); - expect(await group2.members()).toHaveLength(3); - - // update group permissions to deny removing members - await group.updatePermission( - PermissionUpdateType.RemoveMember, - PermissionPolicy.Deny, - ); - // client2 is no longer able to remove members - await expect(() => - group2.removeMembers([client3.inboxId]), - ).rejects.toThrow(); - - // update group permissions to allow anyone to remove members - await group.updatePermission( - PermissionUpdateType.RemoveMember, - PermissionPolicy.Allow, - ); - // client2 is able to remove members again - await group2.removeMembers([client3.inboxId]); - expect(await group2.members()).toHaveLength(2); - }); - - it("should enforce add admin policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - // create group with default permissions (only super admins can add admins) - const group = await client1.conversations.createGroup([ - client2.inboxId, - client3.inboxId, - ]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - - // client2 is not a super admin, so adding an admin should fail - await expect(() => group2.addAdmin(client3.inboxId)).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId); - // client2 is still not able to add admins (requires super admin) - await expect(() => group2.addAdmin(client3.inboxId)).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId); - // now client2 should be able to add admins - await group2.addAdmin(client3.inboxId); - }); - - it("should enforce remove admin policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const { signer: signer3 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - const client3 = await createRegisteredClient(signer3); - // create group with default permissions (only super admins can remove admins) - const group = await client1.conversations.createGroup([ - client2.inboxId, - client3.inboxId, - ]); - - // add client3 as an admin so we have an admin to remove - await group.addAdmin(client3.inboxId); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - - // client2 is not a super admin, so removing an admin should fail - await expect(() => group2.removeAdmin(client3.inboxId)).rejects.toThrow(); - - // add client2 as an admin (not super admin) - await group.addAdmin(client2.inboxId); - // client2 is still not able to remove admins (requires super admin) - await expect(() => group2.removeAdmin(client3.inboxId)).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId); - // now client2 should be able to remove admins - await group2.removeAdmin(client3.inboxId); - }); - - it("should enforce update group name policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - // create group with default permissions (anyone can update group name) - const group = await client1.conversations.createGroup([client2.inboxId]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - // updating group name is allowed - await group2.updateName("new name 1"); - expect(group2.name).toBe("new name 1"); - - // update group permissions to allow only admins to update group name - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.GroupName, - ); - // client2 is no longer able to update group name - await expect(() => group2.updateName("new name 2")).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId); - // client2 is now able to update group name - await group2.updateName("new name 2"); - expect(group2.name).toBe("new name 2"); - - // update group permissions to allow only super admins to update group name - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.SuperAdmin, - MetadataField.GroupName, - ); - // client2 is no longer able to update group name - await expect(() => group2.updateName("new name 3")).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId); - // client2 is now able to update group name - await group2.updateName("new name 3"); - expect(group2.name).toBe("new name 3"); - - // update group permissions to deny updating group name - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Deny, - MetadataField.GroupName, - ); - // client2 is no longer able to update group name - await expect(() => group2.updateName("new name 4")).rejects.toThrow(); - - // update group permissions to allow anyone to update group name - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Allow, - MetadataField.GroupName, - ); - - // client2 is able to update group name again - await group2.updateName("new name 4"); - expect(group2.name).toBe("new name 4"); - }); - - it("should enforce update group description policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - // create group with default permissions (anyone can update group description) - const group = await client1.conversations.createGroup([client2.inboxId]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - // updating group description is allowed - await group2.updateDescription("new description 1"); - expect(group2.description).toBe("new description 1"); - - // update group permissions to allow only admins to update group description - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.Description, - ); - // client2 is no longer able to update group description - await expect(() => - group2.updateDescription("new description 2"), - ).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId); - // client2 is now able to update group description - await group2.updateDescription("new description 2"); - expect(group2.description).toBe("new description 2"); - - // update group permissions to allow only super admins to update group description - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.SuperAdmin, - MetadataField.Description, - ); - // client2 is no longer able to update group description - await expect(() => - group2.updateDescription("new description 3"), - ).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId); - // client2 is now able to update group description - await group2.updateDescription("new description 3"); - expect(group2.description).toBe("new description 3"); - - // update group permissions to deny updating group description - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Deny, - MetadataField.Description, - ); - // client2 is no longer able to update group description - await expect(() => - group2.updateDescription("new description 4"), - ).rejects.toThrow(); - - // update group permissions to allow anyone to update group description - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Allow, - MetadataField.Description, - ); - // client2 is able to update group description again - await group2.updateDescription("new description 4"); - expect(group2.description).toBe("new description 4"); - }); - - it("should enforce update group image url policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - // create group with default permissions (anyone can update group image url) - const group = await client1.conversations.createGroup([client2.inboxId]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - // updating group image url is allowed - await group2.updateImageUrl("https://example.com/image1.png"); - expect(group2.imageUrl).toBe("https://example.com/image1.png"); - - // update group permissions to allow only admins to update group image url - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.GroupImageUrlSquare, - ); - // client2 is no longer able to update group image url - await expect(() => - group2.updateImageUrl("https://example.com/image2.png"), - ).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId); - // client2 is now able to update group image url - await group2.updateImageUrl("https://example.com/image2.png"); - expect(group2.imageUrl).toBe("https://example.com/image2.png"); - - // update group permissions to allow only super admins to update group image url - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.SuperAdmin, - MetadataField.GroupImageUrlSquare, - ); - // client2 is no longer able to update group image url - await expect(() => - group2.updateImageUrl("https://example.com/image3.png"), - ).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId); - // client2 is now able to update group image url - await group2.updateImageUrl("https://example.com/image3.png"); - expect(group2.imageUrl).toBe("https://example.com/image3.png"); - - // update group permissions to deny updating group image url - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Deny, - MetadataField.GroupImageUrlSquare, - ); - // client2 is no longer able to update group image url - await expect(() => - group2.updateImageUrl("https://example.com/image4.png"), - ).rejects.toThrow(); - - // update group permissions to allow anyone to update group image url - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Allow, - MetadataField.GroupImageUrlSquare, - ); - // client2 is able to update group image url again - await group2.updateImageUrl("https://example.com/image4.png"); - expect(group2.imageUrl).toBe("https://example.com/image4.png"); - }); - - it("should enforce update message disappearing policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - // create group with default permissions (only admins can update message disappearing) - const group = await client1.conversations.createGroup([client2.inboxId]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - // updating message disappearing settings is not allowed for regular members - await expect(() => - group2.updateMessageDisappearingSettings(1n, 1_000_000_000n), - ).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId); - // client2 is now able to update message disappearing settings - await group2.updateMessageDisappearingSettings(1n, 1_000_000_000n); - expect(group2.isMessageDisappearingEnabled()).toBe(true); - }); - - it("should enforce update message disappearing policy with allow policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - // create group with custom permissions (anyone can update message disappearing) - const group = await client1.conversations.createGroup([client2.inboxId], { - permissions: GroupPermissionsOptions.CustomPolicy, - customPermissionPolicySet: { - addAdminPolicy: PermissionPolicy.SuperAdmin, - addMemberPolicy: PermissionPolicy.Allow, - removeAdminPolicy: PermissionPolicy.SuperAdmin, - removeMemberPolicy: PermissionPolicy.Admin, - updateGroupNamePolicy: PermissionPolicy.Allow, - updateGroupDescriptionPolicy: PermissionPolicy.Allow, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, - updateMessageDisappearingPolicy: PermissionPolicy.Allow, - updateAppDataPolicy: PermissionPolicy.Allow, - }, - }); - - // verify permissions - expect(group.permissions().policySet.updateMessageDisappearingPolicy).toBe( - PermissionPolicy.Allow, - ); - - // updating message disappearing settings works - await group.updateMessageDisappearingSettings(1n, 1_000_000_000n); - expect(group.isMessageDisappearingEnabled()).toBe(true); - }); - - it("should deny update message disappearing with deny policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - - // create group with custom permissions (nobody can update message disappearing) - const group = await client1.conversations.createGroup([client2.inboxId], { - permissions: GroupPermissionsOptions.CustomPolicy, - customPermissionPolicySet: { - addAdminPolicy: PermissionPolicy.SuperAdmin, - addMemberPolicy: PermissionPolicy.Allow, - removeAdminPolicy: PermissionPolicy.SuperAdmin, - removeMemberPolicy: PermissionPolicy.Admin, - updateGroupNamePolicy: PermissionPolicy.Allow, - updateGroupDescriptionPolicy: PermissionPolicy.Allow, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, - updateMessageDisappearingPolicy: PermissionPolicy.Deny, - updateAppDataPolicy: PermissionPolicy.Allow, - }, - }); - - // even super admin (client1) cannot update message disappearing settings - await expect(() => - group.updateMessageDisappearingSettings(1n, 1_000_000_000n), - ).rejects.toThrow(); - }); - - it("should enforce update app data policy", async () => { - const { signer: signer1 } = createSigner(); - const { signer: signer2 } = createSigner(); - const client1 = await createRegisteredClient(signer1); - const client2 = await createRegisteredClient(signer2); - // create group with default permissions (anyone can update app data) - const group = await client1.conversations.createGroup([client2.inboxId]); - - // client2 is a regular member of the group - await client2.conversations.sync(); - const group2 = client2.conversations.listGroups()[0]; - // updating app data is allowed - await group2.updateAppData("app data 1"); - expect(group2.appData).toBe("app data 1"); - - // update group permissions to allow only admins to update app data - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, - MetadataField.AppData, - ); - // client2 is no longer able to update app data - await expect(() => group2.updateAppData("app data 2")).rejects.toThrow(); - - // add client2 as an admin - await group.addAdmin(client2.inboxId); - // client2 is now able to update app data - await group2.updateAppData("app data 2"); - expect(group2.appData).toBe("app data 2"); - - // update group permissions to allow only super admins to update app data - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.SuperAdmin, - MetadataField.AppData, - ); - // client2 is no longer able to update app data - await expect(() => group2.updateAppData("app data 3")).rejects.toThrow(); - - // add client2 as a super admin - await group.addSuperAdmin(client2.inboxId); - // client2 is now able to update app data - await group2.updateAppData("app data 3"); - expect(group2.appData).toBe("app data 3"); - - // update group permissions to deny updating app data - await group.updatePermission( - PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Deny, - MetadataField.AppData, - ); - // client2 is no longer able to update app data - await expect(() => group2.updateAppData("app data 4")).rejects.toThrow(); - }); -}); diff --git a/sdks/node-sdk/test/streams.test.ts b/sdks/node-sdk/test/streams.test.ts deleted file mode 100644 index 456a0ae6d..000000000 --- a/sdks/node-sdk/test/streams.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { describe, expect, it, vi } from "vitest"; -import { StreamFailedError } from "@/utils/errors"; -import { createStream } from "@/utils/streams"; - -describe("createStream", () => { - it("should forward StreamFailedError to onError", async () => { - const onErrorSpy = vi.fn(); - const onFailSpy = vi.fn(); - - const mockStreamFunction = vi.fn(async (_, onFail: () => void) => { - // Simulate immediate stream failure - setTimeout(() => { - onFail(); - }, 0); - return Promise.resolve({ - end: vi.fn(), - endAndWait: vi.fn().mockResolvedValue(undefined), - isClosed: vi.fn().mockReturnValue(false), - waitForReady: vi.fn().mockResolvedValue(undefined), - }); - }); - - const stream = await createStream(mockStreamFunction, undefined, { - onError: onErrorSpy, - onFail: onFailSpy, - retryOnFail: false, - }); - - setTimeout(() => { - void stream.end(); - }, 100); - - // Wait for the failure to be processed - await new Promise((resolve) => setTimeout(resolve, 100)); - - expect(onErrorSpy).toHaveBeenCalledWith(expect.any(StreamFailedError)); - }); -}); diff --git a/sdks/node-sdk/test/validation.test.ts b/sdks/node-sdk/test/validation.test.ts deleted file mode 100644 index ae89d9b36..000000000 --- a/sdks/node-sdk/test/validation.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { describe, expect, expectTypeOf, it } from "vitest"; -import { isHexString, validHex, type HexString } from "@/utils/validation"; - -describe("validHex", () => { - it("validates that a string is of type HexString", () => { - // Type is widened to "string" on purpose for this test - const userInput: string = `0xfb8b505f66005ca19546d7f405f1c531`; - - const result = validHex(userInput); - - expectTypeOf(result).toEqualTypeOf(); - expectTypeOf(result).not.toEqualTypeOf(); - }); - - it("throws when input is not a valid hex string", () => { - expect(() => validHex("not-hex")).toThrow(); - }); -}); - -describe("isHexString", () => { - it("returns true for valid hex strings", () => { - const valid = [ - "0xab", - "0xabcd", - "0xABCD", - "0x0123456789abcdefABCDEF", - ] as const; - - for (const value of valid) { - expect(isHexString(value)).toBe(true); - } - }); - - it("returns false for invalid hex strings", () => { - const invalid = ["0x", "123", "0xg", "0X123", "0x123"] as const; - - for (const value of invalid) { - expect(isHexString(value)).toBe(false); - } - }); - - it("returns false for non-string values", () => { - const invalid = [123, null, undefined, {}, []] as const; - - for (const value of invalid) { - expect(isHexString(value)).toBe(false); - } - }); -}); diff --git a/sdks/node-sdk/tsconfig.json b/sdks/node-sdk/tsconfig.json deleted file mode 100644 index 14fa2b8c6..000000000 --- a/sdks/node-sdk/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "compilerOptions": { - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "module": "ESNext", - "moduleResolution": "bundler", - "noEmit": true, - "paths": { - "@/*": ["./src/*"], - "@test/*": ["./test/*"] - }, - "preserveConstEnums": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "target": "ESNext", - "types": ["vitest/globals"] - }, - "include": [ - "rollup.config.js", - "scripts/**/*", - "src/**/*", - "test/**/*", - "vitest.config.ts", - "vitest.setup.ts" - ] -} diff --git a/sdks/node-sdk/vitest.config.ts b/sdks/node-sdk/vitest.config.ts deleted file mode 100644 index d6b1e8b9b..000000000 --- a/sdks/node-sdk/vitest.config.ts +++ /dev/null @@ -1,20 +0,0 @@ -/// -import { defineConfig, mergeConfig } from "vite"; -import tsconfigPaths from "vite-tsconfig-paths"; -import { defineConfig as defineVitestConfig } from "vitest/config"; - -// https://vitejs.dev/config/ -const viteConfig = defineConfig({ - plugins: [tsconfigPaths()], -}); - -const vitestConfig = defineVitestConfig({ - test: { - globals: true, - testTimeout: 120000, - hookTimeout: 60000, - globalSetup: ["./vitest.setup.ts"], - }, -}); - -export default mergeConfig(viteConfig, vitestConfig); diff --git a/sdks/node-sdk/vitest.setup.ts b/sdks/node-sdk/vitest.setup.ts deleted file mode 100644 index c15b3a24c..000000000 --- a/sdks/node-sdk/vitest.setup.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { unlink } from "node:fs/promises"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { glob } from "fast-glob"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -export const teardown = async () => { - const files = await glob("**/*.db3*", { cwd: __dirname }); - await Promise.all(files.map((file) => unlink(join(__dirname, file)))); -}; diff --git a/yarn.lock b/yarn.lock index 28446424b..2433ac213 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,13 +5,6 @@ __metadata: version: 8 cacheKey: 10 -"@adobe/css-tools@npm:^4.4.0": - version: 4.4.4 - resolution: "@adobe/css-tools@npm:4.4.4" - checksum: 10/0abd4715737877e5aa5d730d6ec2cffae2131102ddc8310ac5ba3f457ffb2ef453324dbb5b927e3cbc3f81bdd29ce485754014c6e64f4577a49540c76e26ac6b - languageName: node - linkType: hard - "@adraffy/ens-normalize@npm:^1.10.1, @adraffy/ens-normalize@npm:^1.11.0": version: 1.11.1 resolution: "@adraffy/ens-normalize@npm:1.11.1" @@ -101,858 +94,567 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-cloudfront@npm:^3.971.0": - version: 3.980.0 - resolution: "@aws-sdk/client-cloudfront@npm:3.980.0" +"@aws-sdk/client-cloudfront@npm:^3.1009.0": + version: 3.1058.0 + resolution: "@aws-sdk/client-cloudfront@npm:3.1058.0" dependencies: "@aws-crypto/sha256-browser": "npm:5.2.0" "@aws-crypto/sha256-js": "npm:5.2.0" - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/credential-provider-node": "npm:^3.972.4" - "@aws-sdk/middleware-host-header": "npm:^3.972.3" - "@aws-sdk/middleware-logger": "npm:^3.972.3" - "@aws-sdk/middleware-recursion-detection": "npm:^3.972.3" - "@aws-sdk/middleware-user-agent": "npm:^3.972.5" - "@aws-sdk/region-config-resolver": "npm:^3.972.3" - "@aws-sdk/types": "npm:^3.973.1" - "@aws-sdk/util-endpoints": "npm:3.980.0" - "@aws-sdk/util-user-agent-browser": "npm:^3.972.3" - "@aws-sdk/util-user-agent-node": "npm:^3.972.3" - "@smithy/config-resolver": "npm:^4.4.6" - "@smithy/core": "npm:^3.22.0" - "@smithy/fetch-http-handler": "npm:^5.3.9" - "@smithy/hash-node": "npm:^4.2.8" - "@smithy/invalid-dependency": "npm:^4.2.8" - "@smithy/middleware-content-length": "npm:^4.2.8" - "@smithy/middleware-endpoint": "npm:^4.4.12" - "@smithy/middleware-retry": "npm:^4.4.29" - "@smithy/middleware-serde": "npm:^4.2.9" - "@smithy/middleware-stack": "npm:^4.2.8" - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/node-http-handler": "npm:^4.4.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/smithy-client": "npm:^4.11.1" - "@smithy/types": "npm:^4.12.0" - "@smithy/url-parser": "npm:^4.2.8" - "@smithy/util-base64": "npm:^4.3.0" - "@smithy/util-body-length-browser": "npm:^4.2.0" - "@smithy/util-body-length-node": "npm:^4.2.1" - "@smithy/util-defaults-mode-browser": "npm:^4.3.28" - "@smithy/util-defaults-mode-node": "npm:^4.2.31" - "@smithy/util-endpoints": "npm:^3.2.8" - "@smithy/util-middleware": "npm:^4.2.8" - "@smithy/util-retry": "npm:^4.2.8" - "@smithy/util-stream": "npm:^4.5.10" - "@smithy/util-utf8": "npm:^4.2.0" - "@smithy/util-waiter": "npm:^4.2.8" + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/credential-provider-node": "npm:^3.972.48" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/fetch-http-handler": "npm:^5.4.5" + "@smithy/node-http-handler": "npm:^4.7.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/5064a92fda35d15e6a687f52de7e51c2cbf9b3599629ec5519d61e03098efdef32d8ae79578fc89eeadf27df3c950ed0fba613e3b2ee4a4bcf61c97922fc2b20 + checksum: 10/87ec489628a2640df35f0d2a49449ec05945300aa27d6a78d3c26def94d422cca9e83d46c493246b44d48dd36c6009766d095d24a3b37a39bd2ebe814e413f8a languageName: node linkType: hard -"@aws-sdk/client-s3@npm:^3.975.0": - version: 3.980.0 - resolution: "@aws-sdk/client-s3@npm:3.980.0" +"@aws-sdk/client-s3@npm:^3.1053.0": + version: 3.1058.0 + resolution: "@aws-sdk/client-s3@npm:3.1058.0" dependencies: "@aws-crypto/sha1-browser": "npm:5.2.0" "@aws-crypto/sha256-browser": "npm:5.2.0" "@aws-crypto/sha256-js": "npm:5.2.0" - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/credential-provider-node": "npm:^3.972.4" - "@aws-sdk/middleware-bucket-endpoint": "npm:^3.972.3" - "@aws-sdk/middleware-expect-continue": "npm:^3.972.3" - "@aws-sdk/middleware-flexible-checksums": "npm:^3.972.3" - "@aws-sdk/middleware-host-header": "npm:^3.972.3" - "@aws-sdk/middleware-location-constraint": "npm:^3.972.3" - "@aws-sdk/middleware-logger": "npm:^3.972.3" - "@aws-sdk/middleware-recursion-detection": "npm:^3.972.3" - "@aws-sdk/middleware-sdk-s3": "npm:^3.972.5" - "@aws-sdk/middleware-ssec": "npm:^3.972.3" - "@aws-sdk/middleware-user-agent": "npm:^3.972.5" - "@aws-sdk/region-config-resolver": "npm:^3.972.3" - "@aws-sdk/signature-v4-multi-region": "npm:3.980.0" - "@aws-sdk/types": "npm:^3.973.1" - "@aws-sdk/util-endpoints": "npm:3.980.0" - "@aws-sdk/util-user-agent-browser": "npm:^3.972.3" - "@aws-sdk/util-user-agent-node": "npm:^3.972.3" - "@smithy/config-resolver": "npm:^4.4.6" - "@smithy/core": "npm:^3.22.0" - "@smithy/eventstream-serde-browser": "npm:^4.2.8" - "@smithy/eventstream-serde-config-resolver": "npm:^4.3.8" - "@smithy/eventstream-serde-node": "npm:^4.2.8" - "@smithy/fetch-http-handler": "npm:^5.3.9" - "@smithy/hash-blob-browser": "npm:^4.2.9" - "@smithy/hash-node": "npm:^4.2.8" - "@smithy/hash-stream-node": "npm:^4.2.8" - "@smithy/invalid-dependency": "npm:^4.2.8" - "@smithy/md5-js": "npm:^4.2.8" - "@smithy/middleware-content-length": "npm:^4.2.8" - "@smithy/middleware-endpoint": "npm:^4.4.12" - "@smithy/middleware-retry": "npm:^4.4.29" - "@smithy/middleware-serde": "npm:^4.2.9" - "@smithy/middleware-stack": "npm:^4.2.8" - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/node-http-handler": "npm:^4.4.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/smithy-client": "npm:^4.11.1" - "@smithy/types": "npm:^4.12.0" - "@smithy/url-parser": "npm:^4.2.8" - "@smithy/util-base64": "npm:^4.3.0" - "@smithy/util-body-length-browser": "npm:^4.2.0" - "@smithy/util-body-length-node": "npm:^4.2.1" - "@smithy/util-defaults-mode-browser": "npm:^4.3.28" - "@smithy/util-defaults-mode-node": "npm:^4.2.31" - "@smithy/util-endpoints": "npm:^3.2.8" - "@smithy/util-middleware": "npm:^4.2.8" - "@smithy/util-retry": "npm:^4.2.8" - "@smithy/util-stream": "npm:^4.5.10" - "@smithy/util-utf8": "npm:^4.2.0" - "@smithy/util-waiter": "npm:^4.2.8" + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/credential-provider-node": "npm:^3.972.48" + "@aws-sdk/middleware-bucket-endpoint": "npm:^3.972.17" + "@aws-sdk/middleware-expect-continue": "npm:^3.972.14" + "@aws-sdk/middleware-flexible-checksums": "npm:^3.974.23" + "@aws-sdk/middleware-location-constraint": "npm:^3.972.11" + "@aws-sdk/middleware-sdk-s3": "npm:^3.972.44" + "@aws-sdk/middleware-ssec": "npm:^3.972.11" + "@aws-sdk/signature-v4-multi-region": "npm:^3.996.30" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/fetch-http-handler": "npm:^5.4.5" + "@smithy/node-http-handler": "npm:^4.7.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/52867aeab4dee02556a10e84a2c74d67888daa039f3ca8417b28846a4886283f7465037cdfd9795bc5cbc4d71d18fd413a17a96227dcffc462aec31152f3193c + checksum: 10/9d385edb30dc51e587ce742d1f0f62a6ee804f863389ff9c51e51b890d93c8ec65b4a68bfffd21e410b3668a7d4a3a3a557e990f2f878b03fc80f60615e5a2ff languageName: node linkType: hard -"@aws-sdk/client-sso@npm:3.980.0": - version: 3.980.0 - resolution: "@aws-sdk/client-sso@npm:3.980.0" +"@aws-sdk/core@npm:^3.974.15": + version: 3.974.15 + resolution: "@aws-sdk/core@npm:3.974.15" dependencies: - "@aws-crypto/sha256-browser": "npm:5.2.0" - "@aws-crypto/sha256-js": "npm:5.2.0" - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/middleware-host-header": "npm:^3.972.3" - "@aws-sdk/middleware-logger": "npm:^3.972.3" - "@aws-sdk/middleware-recursion-detection": "npm:^3.972.3" - "@aws-sdk/middleware-user-agent": "npm:^3.972.5" - "@aws-sdk/region-config-resolver": "npm:^3.972.3" - "@aws-sdk/types": "npm:^3.973.1" - "@aws-sdk/util-endpoints": "npm:3.980.0" - "@aws-sdk/util-user-agent-browser": "npm:^3.972.3" - "@aws-sdk/util-user-agent-node": "npm:^3.972.3" - "@smithy/config-resolver": "npm:^4.4.6" - "@smithy/core": "npm:^3.22.0" - "@smithy/fetch-http-handler": "npm:^5.3.9" - "@smithy/hash-node": "npm:^4.2.8" - "@smithy/invalid-dependency": "npm:^4.2.8" - "@smithy/middleware-content-length": "npm:^4.2.8" - "@smithy/middleware-endpoint": "npm:^4.4.12" - "@smithy/middleware-retry": "npm:^4.4.29" - "@smithy/middleware-serde": "npm:^4.2.9" - "@smithy/middleware-stack": "npm:^4.2.8" - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/node-http-handler": "npm:^4.4.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/smithy-client": "npm:^4.11.1" - "@smithy/types": "npm:^4.12.0" - "@smithy/url-parser": "npm:^4.2.8" - "@smithy/util-base64": "npm:^4.3.0" - "@smithy/util-body-length-browser": "npm:^4.2.0" - "@smithy/util-body-length-node": "npm:^4.2.1" - "@smithy/util-defaults-mode-browser": "npm:^4.3.28" - "@smithy/util-defaults-mode-node": "npm:^4.2.31" - "@smithy/util-endpoints": "npm:^3.2.8" - "@smithy/util-middleware": "npm:^4.2.8" - "@smithy/util-retry": "npm:^4.2.8" - "@smithy/util-utf8": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/c2715478f72b9d022de424c767e7c57a56e043d03e6fd9930baa11f228da8cda7173561706385e3617d5723cb71e4e8999eb3ddc62430940cc89df48f1c62ce7 - languageName: node - linkType: hard - -"@aws-sdk/core@npm:^3.973.5": - version: 3.973.5 - resolution: "@aws-sdk/core@npm:3.973.5" - dependencies: - "@aws-sdk/types": "npm:^3.973.1" - "@aws-sdk/xml-builder": "npm:^3.972.2" - "@smithy/core": "npm:^3.22.0" - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/signature-v4": "npm:^5.3.8" - "@smithy/smithy-client": "npm:^4.11.1" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-base64": "npm:^4.3.0" - "@smithy/util-middleware": "npm:^4.2.8" - "@smithy/util-utf8": "npm:^4.2.0" + "@aws-sdk/types": "npm:^3.973.9" + "@aws-sdk/xml-builder": "npm:^3.972.26" + "@aws/lambda-invoke-store": "npm:^0.2.2" + "@smithy/core": "npm:^3.24.5" + "@smithy/signature-v4": "npm:^5.4.5" + "@smithy/types": "npm:^4.14.2" + bowser: "npm:^2.11.0" tslib: "npm:^2.6.2" - checksum: 10/f5021f131d9755d72f3e4d871bc75c1eeaf40b944a1f2e483a0166bf1b9b5b9622fce41f3568d3a6ec58da03c811cc7008399edb86bd5d32f10a963a20870101 + checksum: 10/d63c1a68a85ed790c64055e52713392ca816a9c19580ba375f513d4650e98e4411e3160143604eec93692b22bc79337a409e7b733b17ad965d29cbcc9c033a9a languageName: node linkType: hard -"@aws-sdk/crc64-nvme@npm:3.972.0": - version: 3.972.0 - resolution: "@aws-sdk/crc64-nvme@npm:3.972.0" +"@aws-sdk/crc64-nvme@npm:^3.972.9": + version: 3.972.9 + resolution: "@aws-sdk/crc64-nvme@npm:3.972.9" dependencies: - "@smithy/types": "npm:^4.12.0" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/47d41dfbff4ed7664d1cc4565f4b190cdf6d87c7b550897a709894ba041c6d4c28171cf7089365af8441bf40234167df916f56bd4ea7c7cd6ba31cab56ed28b1 + checksum: 10/b09ed0ef7cce6984708ad180a553deb0b3f429b5d97e1618222e29d058fafa576b0b1171e3409597abdaafff225b22403053973f36d264e4b6257bf4ad85dfa9 languageName: node linkType: hard -"@aws-sdk/credential-provider-env@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/credential-provider-env@npm:3.972.3" +"@aws-sdk/credential-provider-env@npm:^3.972.41": + version: 3.972.41 + resolution: "@aws-sdk/credential-provider-env@npm:3.972.41" dependencies: - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/a67ccab5c46d7b336ebe91ca8bb93c1741115c067b9243ed6f2164c921001fe5a798e84786381d9d03bc4ff07b4aeb1b0094404a9bac0674a0e975419709f7e4 + checksum: 10/26980410b83f27d7d3cb9155e10f4d09001133f1c3162c501c35681adf250ac985166cd63b1077630872e7a55d018411e08bf9673da827222c9def421990c25f languageName: node linkType: hard -"@aws-sdk/credential-provider-http@npm:^3.972.5": - version: 3.972.5 - resolution: "@aws-sdk/credential-provider-http@npm:3.972.5" +"@aws-sdk/credential-provider-http@npm:^3.972.43": + version: 3.972.43 + resolution: "@aws-sdk/credential-provider-http@npm:3.972.43" dependencies: - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/fetch-http-handler": "npm:^5.3.9" - "@smithy/node-http-handler": "npm:^4.4.8" - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/smithy-client": "npm:^4.11.1" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-stream": "npm:^4.5.10" + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/fetch-http-handler": "npm:^5.4.5" + "@smithy/node-http-handler": "npm:^4.7.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/55fd400d28ac906049a87090923ee6cecfbd8c182dd32ee699f3109c3e1c165aa9819c042d9e73f07802675aee620de41c348cc4794588ff7d231c4ff54dddcf - languageName: node - linkType: hard - -"@aws-sdk/credential-provider-ini@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/credential-provider-ini@npm:3.972.3" - dependencies: - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/credential-provider-env": "npm:^3.972.3" - "@aws-sdk/credential-provider-http": "npm:^3.972.5" - "@aws-sdk/credential-provider-login": "npm:^3.972.3" - "@aws-sdk/credential-provider-process": "npm:^3.972.3" - "@aws-sdk/credential-provider-sso": "npm:^3.972.3" - "@aws-sdk/credential-provider-web-identity": "npm:^3.972.3" - "@aws-sdk/nested-clients": "npm:3.980.0" - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/credential-provider-imds": "npm:^4.2.8" - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/shared-ini-file-loader": "npm:^4.4.3" - "@smithy/types": "npm:^4.12.0" + checksum: 10/f6f0afbcc09b0da4ec6dc4e33b2cfeeda0968043f4a7204a5fde8c4fe66def99e90bc1c563b1eb3528d7ec2a6904d2279de4671b0c8a07eb73b61ce323467238 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-ini@npm:^3.972.46": + version: 3.972.46 + resolution: "@aws-sdk/credential-provider-ini@npm:3.972.46" + dependencies: + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/credential-provider-env": "npm:^3.972.41" + "@aws-sdk/credential-provider-http": "npm:^3.972.43" + "@aws-sdk/credential-provider-login": "npm:^3.972.45" + "@aws-sdk/credential-provider-process": "npm:^3.972.41" + "@aws-sdk/credential-provider-sso": "npm:^3.972.45" + "@aws-sdk/credential-provider-web-identity": "npm:^3.972.45" + "@aws-sdk/nested-clients": "npm:^3.997.13" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/credential-provider-imds": "npm:^4.3.6" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/22ecb40caf4ef4217c403d32bc809837cc0a78431af6004ca25a7d82597835aa00af0e387b826a130570059f1eab1229ce9e0f0c555e39b1218ca229d98dc538 + checksum: 10/2b853d24e52c7203835c5c0d6ebc776cd0dcfca87e8072b30e270750231f85ed49a7cd46d034113b7e1a1fff4a9067919e88955330b4517796aa85a301a356c2 languageName: node linkType: hard -"@aws-sdk/credential-provider-login@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/credential-provider-login@npm:3.972.3" +"@aws-sdk/credential-provider-login@npm:^3.972.45": + version: 3.972.45 + resolution: "@aws-sdk/credential-provider-login@npm:3.972.45" dependencies: - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/nested-clients": "npm:3.980.0" - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/shared-ini-file-loader": "npm:^4.4.3" - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/nested-clients": "npm:^3.997.13" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/4ac4bd7d38f691311d9bac46e2986943a67ae4fc3d8d15f4539b2ef6d22608e564d0fe007b46815d780ec2de8c37c86b322387789fd05593484e338163691bc7 + checksum: 10/70dc627d1dc1c7cb3a7308b3ee244585024a6d1c2b9562b5e9105de496d732c2c774146f029dcf0902715e7f6c1738daf7e3d15b080c932362b5fe874267358b languageName: node linkType: hard -"@aws-sdk/credential-provider-node@npm:^3.972.4": - version: 3.972.4 - resolution: "@aws-sdk/credential-provider-node@npm:3.972.4" +"@aws-sdk/credential-provider-node@npm:^3.972.48": + version: 3.972.48 + resolution: "@aws-sdk/credential-provider-node@npm:3.972.48" dependencies: - "@aws-sdk/credential-provider-env": "npm:^3.972.3" - "@aws-sdk/credential-provider-http": "npm:^3.972.5" - "@aws-sdk/credential-provider-ini": "npm:^3.972.3" - "@aws-sdk/credential-provider-process": "npm:^3.972.3" - "@aws-sdk/credential-provider-sso": "npm:^3.972.3" - "@aws-sdk/credential-provider-web-identity": "npm:^3.972.3" - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/credential-provider-imds": "npm:^4.2.8" - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/shared-ini-file-loader": "npm:^4.4.3" - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/credential-provider-env": "npm:^3.972.41" + "@aws-sdk/credential-provider-http": "npm:^3.972.43" + "@aws-sdk/credential-provider-ini": "npm:^3.972.46" + "@aws-sdk/credential-provider-process": "npm:^3.972.41" + "@aws-sdk/credential-provider-sso": "npm:^3.972.45" + "@aws-sdk/credential-provider-web-identity": "npm:^3.972.45" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/credential-provider-imds": "npm:^4.3.6" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/0ee3ad056d78f67f9c8afe78ab46f82ceca7e432079ec1a1c3db29d23ec0c67959c72ece571d3a143d1eab78158825aac720d5c3f47715984ab0dff27c619400 + checksum: 10/6db71f0e71c5931a80a061fa16d992f67b60e7b2c2eae849f6286e4e29b1d09a69850763b2d0e6449aa57a75b32ae1bf537f305619b81706e87544b4710793a6 languageName: node linkType: hard -"@aws-sdk/credential-provider-process@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/credential-provider-process@npm:3.972.3" +"@aws-sdk/credential-provider-process@npm:^3.972.41": + version: 3.972.41 + resolution: "@aws-sdk/credential-provider-process@npm:3.972.41" dependencies: - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/shared-ini-file-loader": "npm:^4.4.3" - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/37421140a546a9a45e890d8d32e8214a5b1b0ed80844031d9deb5c3e2ab2cb5b52242ee9f72795310d194fc54ffc51f6f15f9d36ae07b1ccd32873f99b9fba41 + checksum: 10/0a9090d15f782c0f6842950bda126e69adb584166a763c0d23cfe3fef0b59c94bfa228a17930106ca1a08f2c515d2a0ad34937b4f34101a6f4b264061eba7680 languageName: node linkType: hard -"@aws-sdk/credential-provider-sso@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/credential-provider-sso@npm:3.972.3" +"@aws-sdk/credential-provider-sso@npm:^3.972.45": + version: 3.972.45 + resolution: "@aws-sdk/credential-provider-sso@npm:3.972.45" dependencies: - "@aws-sdk/client-sso": "npm:3.980.0" - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/token-providers": "npm:3.980.0" - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/shared-ini-file-loader": "npm:^4.4.3" - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/nested-clients": "npm:^3.997.13" + "@aws-sdk/token-providers": "npm:3.1056.0" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/f025a35c068548be28b5e1343e52102b09b9fd9e01d0bc433700d68cd06007b92ea56c836c79ec74612ad7fce1112a65293a81e85961aa09023a7b39049cf271 + checksum: 10/7986b32e124bcd53a0d461b555afdd3fbb6de70a6338ba87b8316b882eea80296a13bb36db1d12af1cfe133edc21b8c932401eacff710d67d7536537f675f5de languageName: node linkType: hard -"@aws-sdk/credential-provider-web-identity@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/credential-provider-web-identity@npm:3.972.3" +"@aws-sdk/credential-provider-web-identity@npm:^3.972.45": + version: 3.972.45 + resolution: "@aws-sdk/credential-provider-web-identity@npm:3.972.45" dependencies: - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/nested-clients": "npm:3.980.0" - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/shared-ini-file-loader": "npm:^4.4.3" - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/nested-clients": "npm:^3.997.13" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/0022c2e17f2bab8d39d0b3875a6ac65631e984256ea95fb5e0b67cab19a38e0fdc02ce3089051b8307d3ad7ddfef0211e94b76ee39e40fe90ca7e587c740dbe2 + checksum: 10/0ccbba9383b8e818cd5dfe5715d903f8f3e5e94c0603536edd06775b768476a67e1c8cbc7c52e0e71de2ead41f0932732ef2fd98541e17087ecc538363ce86af languageName: node linkType: hard -"@aws-sdk/middleware-bucket-endpoint@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.972.3" +"@aws-sdk/middleware-bucket-endpoint@npm:^3.972.17": + version: 3.972.17 + resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.972.17" dependencies: - "@aws-sdk/types": "npm:^3.973.1" - "@aws-sdk/util-arn-parser": "npm:^3.972.2" - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-config-provider": "npm:^4.2.0" + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/5e0906a76ab6f200901759537fb69034546d228405b12b02b64e04f85aefacda0e0818f07d8595617b9956f135fc56545827624f9652858e27da231240cbb9b3 + checksum: 10/99452b9859f99e1490b24c699d60a6245b09536a9574f4a7c93fe8eef29d1c8bed9e1d74bb67606d9310236efcd1f96ed2589e90c3f3767fc228c3e076e9cb6a languageName: node linkType: hard -"@aws-sdk/middleware-expect-continue@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/middleware-expect-continue@npm:3.972.3" +"@aws-sdk/middleware-expect-continue@npm:^3.972.14": + version: 3.972.14 + resolution: "@aws-sdk/middleware-expect-continue@npm:3.972.14" dependencies: - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/96c2d64294e9482873345543a2d1c11a67941bde5dfdb32c1c05b578a394083583e53c6a1c2c3ccee41e4937391ae38878b7c03fd2b5ba08e06567926e34a248 + checksum: 10/0886c120d015d6699a3565760690bdbaced2a2ae130af2cb77887eb19e6171e1ba4dc714ab986c23e23a85d25b138025eebdaa702ca2a2291cae76f214c7a776 languageName: node linkType: hard -"@aws-sdk/middleware-flexible-checksums@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.972.3" +"@aws-sdk/middleware-flexible-checksums@npm:^3.974.23": + version: 3.974.23 + resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.974.23" dependencies: "@aws-crypto/crc32": "npm:5.2.0" "@aws-crypto/crc32c": "npm:5.2.0" "@aws-crypto/util": "npm:5.2.0" - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/crc64-nvme": "npm:3.972.0" - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/is-array-buffer": "npm:^4.2.0" - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-middleware": "npm:^4.2.8" - "@smithy/util-stream": "npm:^4.5.10" - "@smithy/util-utf8": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/0ba04273b21ffaee56d444dc2c6c65e0f75c2f823ad1ff78973fac959a1c57ad2429f0c6d19e1366830e8981fda471c79d8d07b1cf8389690f7d2f7b45dce340 - languageName: node - linkType: hard - -"@aws-sdk/middleware-host-header@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/middleware-host-header@npm:3.972.3" - dependencies: - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/14b6e32f32f1c8b0e66a396b092785d3d597b27df696ed2daf8310d2a463416bcc89480043b6a5083698403fc85904caf5ebbcb0fbd12f89f05dbf10878d2cc7 - languageName: node - linkType: hard - -"@aws-sdk/middleware-location-constraint@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/middleware-location-constraint@npm:3.972.3" - dependencies: - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/9c9677e07af9db00af5f748aae79321ec9fb3888b508704e1de0a1fbcf19e1f254037274324d17fc1c11f24ad60c075024560784f0e9958b4868da3e24e9460b - languageName: node - linkType: hard - -"@aws-sdk/middleware-logger@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/middleware-logger@npm:3.972.3" - dependencies: - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/crc64-nvme": "npm:^3.972.9" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/abda3a05b73a2056fbe0d2aa139ee5ad590733d7ef96a18c2ca92b314795ba3fe83216668bd731b8a40f7951b1147eb1ed3566c1b33ee9b8ae9994089596e3b8 + checksum: 10/60d60b1676bee440c931911bd3bd2b56fe4833c121f9f9ab1a837aa131dd6aa09da68693e9c67d605bdff96968db173e197e3c08e95c6821627aeec5d8e15554 languageName: node linkType: hard -"@aws-sdk/middleware-recursion-detection@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/middleware-recursion-detection@npm:3.972.3" +"@aws-sdk/middleware-location-constraint@npm:^3.972.11": + version: 3.972.11 + resolution: "@aws-sdk/middleware-location-constraint@npm:3.972.11" dependencies: - "@aws-sdk/types": "npm:^3.973.1" - "@aws/lambda-invoke-store": "npm:^0.2.2" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/8308e8eb1344669bca86613f160768dd39640ca3ed37730b579a6f71be14f6deed7acdb4f3d195a7f8c5a130afb82411dc18c8a361f7dc1f769c9dc240aaa16f - languageName: node - linkType: hard - -"@aws-sdk/middleware-sdk-s3@npm:^3.972.5": - version: 3.972.5 - resolution: "@aws-sdk/middleware-sdk-s3@npm:3.972.5" - dependencies: - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/types": "npm:^3.973.1" - "@aws-sdk/util-arn-parser": "npm:^3.972.2" - "@smithy/core": "npm:^3.22.0" - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/signature-v4": "npm:^5.3.8" - "@smithy/smithy-client": "npm:^4.11.1" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-config-provider": "npm:^4.2.0" - "@smithy/util-middleware": "npm:^4.2.8" - "@smithy/util-stream": "npm:^4.5.10" - "@smithy/util-utf8": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/94aef879d027d2bd99facbf485ad6bd0219905f62825c4abda59c69813d9f68b0221dfd347015bcb7cdb848a764cdec1b84630ec86b59c0cad1125bd082e874b + checksum: 10/a318f0c0d5486ff74a769f3cabfca6aaa8668afea760016e70a59df3b47c1e788d748cfc3a6ea1cead03fc941a4e64d42c3ddf2f51dd33054d97d6af80b07789 languageName: node linkType: hard -"@aws-sdk/middleware-ssec@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/middleware-ssec@npm:3.972.3" +"@aws-sdk/middleware-sdk-s3@npm:^3.972.44": + version: 3.972.44 + resolution: "@aws-sdk/middleware-sdk-s3@npm:3.972.44" dependencies: - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/signature-v4-multi-region": "npm:^3.996.30" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/6510039afd2f1dce5b9b4870123fb269b6315246a58111d7b08849fff1dd4312f10f39ca69dc5838406c3b7063923fc182dd746cb6543934b41f6f4a29f61980 + checksum: 10/e20b47de556712489ff10b768ccc0f60ac7ba2d8b61eb324b771cb37f605df1fd3b73446aa6c9a14aca09d433b9bbf3c057227e55db0f0311ccd4cf9d5e629fc languageName: node linkType: hard -"@aws-sdk/middleware-user-agent@npm:^3.972.5": - version: 3.972.5 - resolution: "@aws-sdk/middleware-user-agent@npm:3.972.5" +"@aws-sdk/middleware-ssec@npm:^3.972.11": + version: 3.972.11 + resolution: "@aws-sdk/middleware-ssec@npm:3.972.11" dependencies: - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/types": "npm:^3.973.1" - "@aws-sdk/util-endpoints": "npm:3.980.0" - "@smithy/core": "npm:^3.22.0" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/2e77b0b5c15eef3ce192c403c86f31ff20418d2657fda4d66f0bd7997116cf5638610e9b277fc2be9fb86ae63f3f804706e7cd96bec839602d350adf800c5f4c + checksum: 10/c438cd09bf7cc42205741dd69abcd0517a0c7a84923167ee71efe136002eaade4e67a20ee3caaa471f5aca55c63f4d85353b1c998755714e1996a13fed4a6f7d languageName: node linkType: hard -"@aws-sdk/nested-clients@npm:3.980.0": - version: 3.980.0 - resolution: "@aws-sdk/nested-clients@npm:3.980.0" +"@aws-sdk/nested-clients@npm:^3.997.13": + version: 3.997.13 + resolution: "@aws-sdk/nested-clients@npm:3.997.13" dependencies: "@aws-crypto/sha256-browser": "npm:5.2.0" "@aws-crypto/sha256-js": "npm:5.2.0" - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/middleware-host-header": "npm:^3.972.3" - "@aws-sdk/middleware-logger": "npm:^3.972.3" - "@aws-sdk/middleware-recursion-detection": "npm:^3.972.3" - "@aws-sdk/middleware-user-agent": "npm:^3.972.5" - "@aws-sdk/region-config-resolver": "npm:^3.972.3" - "@aws-sdk/types": "npm:^3.973.1" - "@aws-sdk/util-endpoints": "npm:3.980.0" - "@aws-sdk/util-user-agent-browser": "npm:^3.972.3" - "@aws-sdk/util-user-agent-node": "npm:^3.972.3" - "@smithy/config-resolver": "npm:^4.4.6" - "@smithy/core": "npm:^3.22.0" - "@smithy/fetch-http-handler": "npm:^5.3.9" - "@smithy/hash-node": "npm:^4.2.8" - "@smithy/invalid-dependency": "npm:^4.2.8" - "@smithy/middleware-content-length": "npm:^4.2.8" - "@smithy/middleware-endpoint": "npm:^4.4.12" - "@smithy/middleware-retry": "npm:^4.4.29" - "@smithy/middleware-serde": "npm:^4.2.9" - "@smithy/middleware-stack": "npm:^4.2.8" - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/node-http-handler": "npm:^4.4.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/smithy-client": "npm:^4.11.1" - "@smithy/types": "npm:^4.12.0" - "@smithy/url-parser": "npm:^4.2.8" - "@smithy/util-base64": "npm:^4.3.0" - "@smithy/util-body-length-browser": "npm:^4.2.0" - "@smithy/util-body-length-node": "npm:^4.2.1" - "@smithy/util-defaults-mode-browser": "npm:^4.3.28" - "@smithy/util-defaults-mode-node": "npm:^4.2.31" - "@smithy/util-endpoints": "npm:^3.2.8" - "@smithy/util-middleware": "npm:^4.2.8" - "@smithy/util-retry": "npm:^4.2.8" - "@smithy/util-utf8": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/601bcf7ec78ca3ffa476d069a17182364fcc6cc4812bf0550af2d4fa58be2b87eb0da1a0c6ba25d3c361aa2a7a05bed6c1e3a25fa8aba8c87037fff97a237b2e - languageName: node - linkType: hard - -"@aws-sdk/region-config-resolver@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/region-config-resolver@npm:3.972.3" - dependencies: - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/config-resolver": "npm:^4.4.6" - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/8512a573492a990b028d9f0058d6034d54fb186af20d1da9529ac3d5f8d435c43fa16ef7d3dc0b3ffa679bb90529b55b0d00619160a3549839a136cc698fefb8 - languageName: node - linkType: hard - -"@aws-sdk/signature-v4-multi-region@npm:3.980.0": - version: 3.980.0 - resolution: "@aws-sdk/signature-v4-multi-region@npm:3.980.0" - dependencies: - "@aws-sdk/middleware-sdk-s3": "npm:^3.972.5" - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/signature-v4": "npm:^5.3.8" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/456e1617c1f51289616e858181ee84f1d2424abd21dd27ff3a9b1c1834fa07cf88e34674321a20b1a15533988adeced6cb07888a7b61a3988e98044c2189b7f5 - languageName: node - linkType: hard - -"@aws-sdk/token-providers@npm:3.980.0": - version: 3.980.0 - resolution: "@aws-sdk/token-providers@npm:3.980.0" - dependencies: - "@aws-sdk/core": "npm:^3.973.5" - "@aws-sdk/nested-clients": "npm:3.980.0" - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/shared-ini-file-loader": "npm:^4.4.3" - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/signature-v4-multi-region": "npm:^3.996.30" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/fetch-http-handler": "npm:^5.4.5" + "@smithy/node-http-handler": "npm:^4.7.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/b9d903cc9d84b95a9260001e617eb2bab3c037a7778bd22728e85a02ad48d207771b7d803135653919ed9d89ca4c0a9dc535cec8d728cde5a7e8dc5569482cbb + checksum: 10/801e5367d2175cbcd03cf6de4369eac67b99e38f2b01ed17a7502508cd78f89072201ca925d9c1c84bce1081d3caeaa82385ad4c9091af3d29dbd140394b7a6e languageName: node linkType: hard -"@aws-sdk/types@npm:^3.222.0, @aws-sdk/types@npm:^3.973.1": - version: 3.973.1 - resolution: "@aws-sdk/types@npm:3.973.1" +"@aws-sdk/signature-v4-multi-region@npm:^3.996.30": + version: 3.996.30 + resolution: "@aws-sdk/signature-v4-multi-region@npm:3.996.30" dependencies: - "@smithy/types": "npm:^4.12.0" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/signature-v4": "npm:^5.4.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/9cdcb457d6110a88a547fe26922d43450bf7685b26034e935c72c1717de90a22541f298ce4e76fde564d3af11908928b1584b856085dcb175f9bb08853d1a575 + checksum: 10/b7d7ed5c1d0a6344ef6e17468af80274a711d256a0aef0834d9b9f226084ae62de75442a96cf25ab705afe6a0c1ae89de6e0145e65846bdfb794523865d0f90e languageName: node linkType: hard -"@aws-sdk/util-arn-parser@npm:^3.972.2": - version: 3.972.2 - resolution: "@aws-sdk/util-arn-parser@npm:3.972.2" +"@aws-sdk/token-providers@npm:3.1056.0": + version: 3.1056.0 + resolution: "@aws-sdk/token-providers@npm:3.1056.0" dependencies: + "@aws-sdk/core": "npm:^3.974.15" + "@aws-sdk/nested-clients": "npm:^3.997.13" + "@aws-sdk/types": "npm:^3.973.9" + "@smithy/core": "npm:^3.24.5" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/6c09725259187615199b44c21cc9aaf6e61c4d1f326535fd36cf1e95d9842bd58084542c72a9facbca47c5846c5bd8fed7b179e86a036ee142d4a171a6098092 + checksum: 10/a3428f2002dbd7e0d8bd75e1482c78c1bbe150853f11405d55675bd74a2efc91fb855eb1731b542c36e298eb71a194a9f37086db44fdaf7c7ab12c8059673aeb languageName: node linkType: hard -"@aws-sdk/util-endpoints@npm:3.980.0": - version: 3.980.0 - resolution: "@aws-sdk/util-endpoints@npm:3.980.0" +"@aws-sdk/types@npm:^3.222.0, @aws-sdk/types@npm:^3.973.9": + version: 3.973.9 + resolution: "@aws-sdk/types@npm:3.973.9" dependencies: - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/types": "npm:^4.12.0" - "@smithy/url-parser": "npm:^4.2.8" - "@smithy/util-endpoints": "npm:^3.2.8" + "@smithy/types": "npm:^4.14.2" tslib: "npm:^2.6.2" - checksum: 10/a61ec475660cc736960663f756970e07246a7684b762830e8b17ec0873dc5a4f9135fa6104219a2c790d22f30d36369ee19ade124b396d6f09a1139a878e656e + checksum: 10/000bcdc931a23898dbae9ced4c5ca32a766ba787227a98b3d6f935c81571d68e3863d24910e6cacc8937751d381ad5f804d2b29997e5d27e8072877e5bf4c59b languageName: node linkType: hard "@aws-sdk/util-locate-window@npm:^3.0.0": - version: 3.965.4 - resolution: "@aws-sdk/util-locate-window@npm:3.965.4" - dependencies: - tslib: "npm:^2.6.2" - checksum: 10/5b41a026b8600549805a368143f2c4fb79deb60fb8a82064c76a0286bda5ef629c2ea0e5eb6b4d038f90bf2a5cf46cb098232e84c9dc342c15c7206543fbb8b1 - languageName: node - linkType: hard - -"@aws-sdk/util-user-agent-browser@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/util-user-agent-browser@npm:3.972.3" - dependencies: - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/types": "npm:^4.12.0" - bowser: "npm:^2.11.0" - tslib: "npm:^2.6.2" - checksum: 10/fb51d6ae56ba2a69a1239fc1f83a739c468c78ff678cf336b923273237e861b8ff4bfb296b7a250f5980dc2ef6741492a802432243313daf9a03a5332199f7aa - languageName: node - linkType: hard - -"@aws-sdk/util-user-agent-node@npm:^3.972.3": - version: 3.972.3 - resolution: "@aws-sdk/util-user-agent-node@npm:3.972.3" + version: 3.965.5 + resolution: "@aws-sdk/util-locate-window@npm:3.965.5" dependencies: - "@aws-sdk/middleware-user-agent": "npm:^3.972.5" - "@aws-sdk/types": "npm:^3.973.1" - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/types": "npm:^4.12.0" tslib: "npm:^2.6.2" - peerDependencies: - aws-crt: ">=1.0.0" - peerDependenciesMeta: - aws-crt: - optional: true - checksum: 10/abeabdf825d9fbcc2e88c0ce6c47f15b29a8a0932e3106cd2637d0843897abca3b7f2eef757b31c82eb0ced0d733b84c9695ff260b950794bab9aac9807871b3 + checksum: 10/66391a7f6d0c383d6bc3ea67e35b0b0164798d9acbe47271fbc676cf74e7a56690f48425a91cce70e764c53ca46619f4abc076b569d8f991c19dd7c1ac4b0a79 languageName: node linkType: hard -"@aws-sdk/xml-builder@npm:^3.972.2": - version: 3.972.2 - resolution: "@aws-sdk/xml-builder@npm:3.972.2" +"@aws-sdk/xml-builder@npm:^3.972.26": + version: 3.972.26 + resolution: "@aws-sdk/xml-builder@npm:3.972.26" dependencies: - "@smithy/types": "npm:^4.12.0" - fast-xml-parser: "npm:5.2.5" + "@smithy/types": "npm:^4.14.2" + fast-xml-parser: "npm:5.7.3" tslib: "npm:^2.6.2" - checksum: 10/d2f16b53520589fcc1d7720a290286790da94690f49c472afa7017b1250f98abcdb1d32d39b29d7a6c63542eb6808cb006702d5bd470365e86aef18d6dc76ea4 + checksum: 10/b7865682d189cf98c73b40b263f634ba6424931edc303f001d9921f9c939a9837edb64301006cd853819aa50df88ccd7fce6d27ec8e4cafa4a066f37eb7e512e languageName: node linkType: hard "@aws/lambda-invoke-store@npm:^0.2.2": - version: 0.2.3 - resolution: "@aws/lambda-invoke-store@npm:0.2.3" - checksum: 10/d0efa8ca73b2d8dc0bf634525eefa1b72cda85f5d47366264849343a6f2860cfa5c52b7f766a16b78da8406bbd3ee975da3abb1dbe38183f8af95413eafeb256 + version: 0.2.4 + resolution: "@aws/lambda-invoke-store@npm:0.2.4" + checksum: 10/47e73cf73141be73854c69722502e928a435b3d908ffa693a9545c1099dd7b2dd3f67c43c523d786a75911100e77ed52dce1f88d09363a67526448c5b7c804d5 languageName: node linkType: hard -"@babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.27.1, @babel/code-frame@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/code-frame@npm:7.28.6" +"@babel/code-frame@npm:^7.29.0, @babel/code-frame@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/code-frame@npm:7.29.7" dependencies: - "@babel/helper-validator-identifier": "npm:^7.28.5" + "@babel/helper-validator-identifier": "npm:^7.29.7" js-tokens: "npm:^4.0.0" picocolors: "npm:^1.1.1" - checksum: 10/93e7ed9e039e3cb661bdb97c26feebafacc6ec13d745881dae5c7e2708f579475daebe7a3b5d23b183bb940b30744f52f4a5bcb65b4df03b79d82fcb38495784 + checksum: 10/84da552e51a55795a50b3589116edb2f9e368a647d266380683775f18effd9acd4521b0246bebd0b049a7f32af1f87b1e8475d3bcb665f876bd04ade8da99697 languageName: node linkType: hard -"@babel/compat-data@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/compat-data@npm:7.28.6" - checksum: 10/dc17dfb55711a15f006e34c4610c49b7335fc11b23e192f9e5f625e8ea0f48805e61a57b6b4f5550879332782c93af0b5d6952825fffbb8d4e604b14d698249f +"@babel/compat-data@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/compat-data@npm:7.29.7" + checksum: 10/ad2272714087f68970977f6e2b53597a8503fc9c3028c4a91686474bd77a707dd00903cdde4b73788972016d1bad4dc3fa4e5ff38e1ed8f1c3bde1095352973a languageName: node linkType: hard -"@babel/core@npm:^7.28.5": - version: 7.28.6 - resolution: "@babel/core@npm:7.28.6" +"@babel/core@npm:^7.29.0": + version: 7.29.7 + resolution: "@babel/core@npm:7.29.7" dependencies: - "@babel/code-frame": "npm:^7.28.6" - "@babel/generator": "npm:^7.28.6" - "@babel/helper-compilation-targets": "npm:^7.28.6" - "@babel/helper-module-transforms": "npm:^7.28.6" - "@babel/helpers": "npm:^7.28.6" - "@babel/parser": "npm:^7.28.6" - "@babel/template": "npm:^7.28.6" - "@babel/traverse": "npm:^7.28.6" - "@babel/types": "npm:^7.28.6" + "@babel/code-frame": "npm:^7.29.7" + "@babel/generator": "npm:^7.29.7" + "@babel/helper-compilation-targets": "npm:^7.29.7" + "@babel/helper-module-transforms": "npm:^7.29.7" + "@babel/helpers": "npm:^7.29.7" + "@babel/parser": "npm:^7.29.7" + "@babel/template": "npm:^7.29.7" + "@babel/traverse": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" "@jridgewell/remapping": "npm:^2.3.5" convert-source-map: "npm:^2.0.0" debug: "npm:^4.1.0" gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.3" semver: "npm:^6.3.1" - checksum: 10/1a150a69c547daf13c457be1fdaf1a0935d02b94605e777e049537ec2f279b4bb442ffbe1c2d8ff62c688878b1d5530a5784daf72ece950d1917fb78717f51d2 + checksum: 10/38e71cf81db790b0bb2a3a0c8140c2b1c87576b61dc6be676de4fab8c3be871af590a739e8c489fe8e8f9a8e5899fa11e35e59e9e09d40b259c6a675f2f98928 languageName: node linkType: hard -"@babel/generator@npm:^7.26.2, @babel/generator@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/generator@npm:7.28.6" +"@babel/generator@npm:^7.26.2, @babel/generator@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/generator@npm:7.29.7" dependencies: - "@babel/parser": "npm:^7.28.6" - "@babel/types": "npm:^7.28.6" + "@babel/parser": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" "@jridgewell/gen-mapping": "npm:^0.3.12" "@jridgewell/trace-mapping": "npm:^0.3.28" jsesc: "npm:^3.0.2" - checksum: 10/ef2af927e8e0985d02ec4321a242da761a934e927539147c59fdd544034dc7f0e9846f6bf86209aca7a28aee2243ed0fad668adccd48f96d7d6866215173f9af + checksum: 10/60fb0432ebeab791b2d68e5fc49da6f8e8b68bcc4751211ccf08ac0101e9dcaddefd0cbbbd488afb1c1517515c7c3e76f63d9b05d06deaeb008afd499488db9c languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/helper-compilation-targets@npm:7.28.6" +"@babel/helper-compilation-targets@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-compilation-targets@npm:7.29.7" dependencies: - "@babel/compat-data": "npm:^7.28.6" - "@babel/helper-validator-option": "npm:^7.27.1" + "@babel/compat-data": "npm:^7.29.7" + "@babel/helper-validator-option": "npm:^7.29.7" browserslist: "npm:^4.24.0" lru-cache: "npm:^5.1.1" semver: "npm:^6.3.1" - checksum: 10/f512a5aeee4dfc6ea8807f521d085fdca8d66a7d068a6dd5e5b37da10a6081d648c0bbf66791a081e4e8e6556758da44831b331540965dfbf4f5275f3d0a8788 + checksum: 10/af9ed4299ad5cfbe48432a964f37cbbfc200bbeb0f8ba9cbc86448503fa929382d5161d32096274752230c9feb919c9ef595559498833da656fc6a8e24a62383 languageName: node linkType: hard -"@babel/helper-globals@npm:^7.28.0": - version: 7.28.0 - resolution: "@babel/helper-globals@npm:7.28.0" - checksum: 10/91445f7edfde9b65dcac47f4f858f68dc1661bf73332060ab67ad7cc7b313421099a2bfc4bda30c3db3842cfa1e86fffbb0d7b2c5205a177d91b22c8d7d9cb47 +"@babel/helper-globals@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-globals@npm:7.29.7" + checksum: 10/e53203e87ae24a45f59639edea0c429bc3c63c6d74f1862fe60a35032d89478e7511d2f34855da0fcb65782668d72e59e93d1de5bc00121ba9bc1aa38f1f0ad3 languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/helper-module-imports@npm:7.28.6" +"@babel/helper-module-imports@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-module-imports@npm:7.29.7" dependencies: - "@babel/traverse": "npm:^7.28.6" - "@babel/types": "npm:^7.28.6" - checksum: 10/64b1380d74425566a3c288074d7ce4dea56d775d2d3325a3d4a6df1dca702916c1d268133b6f385de9ba5b822b3c6e2af5d3b11ac88e5453d5698d77264f0ec0 + "@babel/traverse": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + checksum: 10/28ec6f7efd99588d6eebfb25c9f1ccc34cb0cdb0839c4c0f08b3ec0105ccaefbe7e8b4f651f3f55a4f5c4fcb1d979bd32a9b8ee23e3e62163ea22aaa7ee0dfa1 languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/helper-module-transforms@npm:7.28.6" +"@babel/helper-module-transforms@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-module-transforms@npm:7.29.7" dependencies: - "@babel/helper-module-imports": "npm:^7.28.6" - "@babel/helper-validator-identifier": "npm:^7.28.5" - "@babel/traverse": "npm:^7.28.6" + "@babel/helper-module-imports": "npm:^7.29.7" + "@babel/helper-validator-identifier": "npm:^7.29.7" + "@babel/traverse": "npm:^7.29.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10/2e421c7db743249819ee51e83054952709dc2e197c7d5d415b4bdddc718580195704bfcdf38544b3f674efc2eccd4d29a65d38678fc827ed3934a7690984cd8b + checksum: 10/33251b1fb44d726194a974a0078b1269511d130a2609357ff829b479e9e4dca96ecd5384c534a477095f665ffb01503d3e680699c2002e5b62e6ca1a272f1892 languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.27.1": - version: 7.28.6 - resolution: "@babel/helper-plugin-utils@npm:7.28.6" - checksum: 10/21c853bbc13dbdddf03309c9a0477270124ad48989e1ad6524b83e83a77524b333f92edd2caae645c5a7ecf264ec6d04a9ebe15aeb54c7f33c037b71ec521e4a +"@babel/helper-plugin-utils@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-plugin-utils@npm:7.29.7" + checksum: 10/6d16929fe5c792bbc8e4d67e18d7c1be69d2f18992deaa3d94dc26541fec662e83cbeeaf7553c6867d068eb7aed4e0d5e3e137c1dd4d5bcfa286f8d772f1f457 languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-string-parser@npm:7.27.1" - checksum: 10/0ae29cc2005084abdae2966afdb86ed14d41c9c37db02c3693d5022fba9f5d59b011d039380b8e537c34daf117c549f52b452398f576e908fb9db3c7abbb3a00 +"@babel/helper-string-parser@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-string-parser@npm:7.29.7" + checksum: 10/4d8ef0ef7105f3d9fe4361137c8f42e5b4c7a52b5380b962762f2a528a1ba89064e2c6236090716ce34b63707b886ae0ebf36b2c2fcc2851f27e652febfc3648 languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.28.5": - version: 7.28.5 - resolution: "@babel/helper-validator-identifier@npm:7.28.5" - checksum: 10/8e5d9b0133702cfacc7f368bf792f0f8ac0483794877c6dca5fcb73810ee138e27527701826fb58a40a004f3a5ec0a2f3c3dd5e326d262530b119918f3132ba7 +"@babel/helper-validator-identifier@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-validator-identifier@npm:7.29.7" + checksum: 10/2efa42701eb05babf26dff3332109c9e5e1a3400a71fb9e68ee27af28235036a2a72c2494c04bdab3f909075f42a58b2e8271074372bc7f8e79ec02bd364d7a7 languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-validator-option@npm:7.27.1" - checksum: 10/db73e6a308092531c629ee5de7f0d04390835b21a263be2644276cb27da2384b64676cab9f22cd8d8dbd854c92b1d7d56fc8517cf0070c35d1c14a8c828b0903 +"@babel/helper-validator-option@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-validator-option@npm:7.29.7" + checksum: 10/aeb6aa966f59300d3cc2fea7c68e1dfd7ad011fc10e535c8e2b2de3094b27c859428dc7220f16420350f8b1cde99da120b673be04bcb0c2f37b56258c96bed58 languageName: node linkType: hard -"@babel/helpers@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/helpers@npm:7.28.6" +"@babel/helpers@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helpers@npm:7.29.7" dependencies: - "@babel/template": "npm:^7.28.6" - "@babel/types": "npm:^7.28.6" - checksum: 10/213485cdfffc4deb81fc1bf2cefed61bc825049322590ef69690e223faa300a2a4d1e7d806c723bb1f1f538226b9b1b6c356ca94eb47fa7c6d9e9f251ee425e6 + "@babel/template": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + checksum: 10/b4d1ef12c19e896585c009ba29677839097ff04f8b11a2430d335c3fb6bd667b4f9e96a3b185a083fdde6b1137eabbbf2600c32425cb69cefc81d81d5cfe425d languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.26.2, @babel/parser@npm:^7.28.5, @babel/parser@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/parser@npm:7.28.6" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.26.2, @babel/parser@npm:^7.29.3, @babel/parser@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/parser@npm:7.29.7" dependencies: - "@babel/types": "npm:^7.28.6" + "@babel/types": "npm:^7.29.7" bin: parser: ./bin/babel-parser.js - checksum: 10/483a6fb5f9876ec9cbbb98816f2c94f39ae4d1158d35f87e1c4bf19a1f56027c96a1a3962ff0c8c46e8322a6d9e1c80d26b7f9668410df13d5b5769d9447b010 + checksum: 10/da40c5928c95997b01aabe84fc3440881b8f20b866714fefa142961d37e82ffc03fbb9afed706f15f8a688278f95286ca0cea0d87ad6c77600f8c6c45d9824ee languageName: node linkType: hard "@babel/plugin-transform-react-jsx-self@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/plugin-transform-react-jsx-self@npm:7.27.1" + version: 7.29.7 + resolution: "@babel/plugin-transform-react-jsx-self@npm:7.29.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/helper-plugin-utils": "npm:^7.29.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/72cbae66a58c6c36f7e12e8ed79f292192d858dd4bb00e9e89d8b695e4c5cb6ef48eec84bffff421a5db93fd10412c581f1cccdb00264065df76f121995bdb68 + checksum: 10/779cde890f36a0160585a357f0850951d9e18d72e960099e32544420252e983b54bfe4a7c81c39b1668ad588231771c97e6b9e59056b21e5cda0953f26db1286 languageName: node linkType: hard "@babel/plugin-transform-react-jsx-source@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/plugin-transform-react-jsx-source@npm:7.27.1" + version: 7.29.7 + resolution: "@babel/plugin-transform-react-jsx-source@npm:7.29.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/helper-plugin-utils": "npm:^7.29.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/e2843362adb53692be5ee9fa07a386d2d8883daad2063a3575b3c373fc14cdf4ea7978c67a183cb631b4c9c8d77b2f48c24c088f8e65cc3600cb8e97d72a7161 + checksum: 10/286641d64bfd1d91eb8fcc3a6a5c48cc7b8e04268c79f3ee9902addc723652a4aa1d967278208d3b0ef03db381853d68eb25ae609e5a305421ff3d3fd5f3cb77 languageName: node linkType: hard -"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7": - version: 7.28.6 - resolution: "@babel/runtime@npm:7.28.6" - checksum: 10/fbcd439cb74d4a681958eb064c509829e3f46d8a4bfaaf441baa81bb6733d1e680bccc676c813883d7741bcaada1d0d04b15aa320ef280b5734e2192b50decf9 +"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7": + version: 7.29.7 + resolution: "@babel/runtime@npm:7.29.7" + checksum: 10/9883b4951787779fd382b121f22f92966d85f19434841f65fb00b2dfec232107e139683f47c6f252891826ad8ee18317b46c3a0e4819116a9885f47b46d7126a languageName: node linkType: hard -"@babel/template@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/template@npm:7.28.6" +"@babel/template@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/template@npm:7.29.7" dependencies: - "@babel/code-frame": "npm:^7.28.6" - "@babel/parser": "npm:^7.28.6" - "@babel/types": "npm:^7.28.6" - checksum: 10/0ad6e32bf1e7e31bf6b52c20d15391f541ddd645cbd488a77fe537a15b280ee91acd3a777062c52e03eedbc2e1f41548791f6a3697c02476ec5daf49faa38533 + "@babel/code-frame": "npm:^7.29.7" + "@babel/parser": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + checksum: 10/da92f7a5b61e05d2fb3934a44f18cec6006ee3c595116c17a3b44cb9756ecd43205c7360dbfa326fa8f4d00aaeb9e777342a881070d11c2305e9c694bc3ca6ff languageName: node linkType: hard -"@babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/traverse@npm:7.28.6" +"@babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/traverse@npm:7.29.7" dependencies: - "@babel/code-frame": "npm:^7.28.6" - "@babel/generator": "npm:^7.28.6" - "@babel/helper-globals": "npm:^7.28.0" - "@babel/parser": "npm:^7.28.6" - "@babel/template": "npm:^7.28.6" - "@babel/types": "npm:^7.28.6" + "@babel/code-frame": "npm:^7.29.7" + "@babel/generator": "npm:^7.29.7" + "@babel/helper-globals": "npm:^7.29.7" + "@babel/parser": "npm:^7.29.7" + "@babel/template": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" debug: "npm:^4.3.1" - checksum: 10/dd71efe9412433169b805d5c346a6473e539ce30f605752a0d40a0733feba37259bd72bb4ad2ab591e2eaff1ee56633de160c1e98efdc8f373cf33a4a8660275 + checksum: 10/ce24086a7dd8c408cbdb159437d3c8e02464a6d32b320d884fa742e2c5a3344b9342a923c7a371fc1789b4d82a59972a7008b5d8bbc1bc0c5ae42a39b28dc7f6 languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.26.0, @babel/types@npm:^7.28.2, @babel/types@npm:^7.28.5, @babel/types@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/types@npm:7.28.6" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.26.0, @babel/types@npm:^7.28.2, @babel/types@npm:^7.29.0, @babel/types@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/types@npm:7.29.7" dependencies: - "@babel/helper-string-parser": "npm:^7.27.1" - "@babel/helper-validator-identifier": "npm:^7.28.5" - checksum: 10/f9c6e52b451065aae5654686ecfc7de2d27dd0fbbc204ee2bd912a71daa359521a32f378981b1cf333ace6c8f86928814452cb9f388a7da59ad468038deb6b5f + "@babel/helper-string-parser": "npm:^7.29.7" + "@babel/helper-validator-identifier": "npm:^7.29.7" + checksum: 10/bd4f5635db1057bd0abeebf93eb3ae38399e152271cea8dce8288350f0afa13ed3e2db2e16e22bd3303068890eec18965a83420539afbe0dde31432b4cf9636d languageName: node linkType: hard @@ -980,11 +682,18 @@ __metadata: languageName: node linkType: hard -"@changesets/apply-release-plan@npm:^7.0.14": - version: 7.0.14 - resolution: "@changesets/apply-release-plan@npm:7.0.14" +"@blazediff/core@npm:1.9.1": + version: 1.9.1 + resolution: "@blazediff/core@npm:1.9.1" + checksum: 10/6bb615f104da313934bcabc09627f3c803461bf85182453d5c13a6a354be4d32b35504b84f1043c21e95d0f6c0acb45083caeb72e72c1d6a76ca5e1f61f25510 + languageName: node + linkType: hard + +"@changesets/apply-release-plan@npm:^7.1.1": + version: 7.1.1 + resolution: "@changesets/apply-release-plan@npm:7.1.1" dependencies: - "@changesets/config": "npm:^3.1.2" + "@changesets/config": "npm:^3.1.4" "@changesets/get-version-range-type": "npm:^0.4.0" "@changesets/git": "npm:^3.0.4" "@changesets/should-skip-package": "npm:^0.1.2" @@ -997,21 +706,21 @@ __metadata: prettier: "npm:^2.7.1" resolve-from: "npm:^5.0.0" semver: "npm:^7.5.3" - checksum: 10/7735783734bddd6d628e3a18c6de253685504c18f580636979fe558dda88501c8e4bda28c34a2f9da96f80fae0d1228271857d86fff6045226ce04b18d8b98b6 + checksum: 10/6810c645c08f5f54a7d40025e41b79fe0d52cf83830b1ce1562d34ba6cbc26d9ce2c7482580623ebf3ea5fa1b01f32e9f61f6b7e1b4296d8ac45d8ba7a6bcae0 languageName: node linkType: hard -"@changesets/assemble-release-plan@npm:^6.0.9": - version: 6.0.9 - resolution: "@changesets/assemble-release-plan@npm:6.0.9" +"@changesets/assemble-release-plan@npm:^6.0.10": + version: 6.0.10 + resolution: "@changesets/assemble-release-plan@npm:6.0.10" dependencies: "@changesets/errors": "npm:^0.2.0" - "@changesets/get-dependents-graph": "npm:^2.1.3" + "@changesets/get-dependents-graph": "npm:^2.1.4" "@changesets/should-skip-package": "npm:^0.1.2" "@changesets/types": "npm:^6.1.0" "@manypkg/get-packages": "npm:^1.1.3" semver: "npm:^7.5.3" - checksum: 10/f84656eabb700ed77f97751b282e1701636ed45a44b443abd9af0291870495cc046fee301478010f39a1dc455799065ae007b9d7d2bb5ae8b793b65bbb8e052a + checksum: 10/75abf5d008d7aed4f29cdb8c46a7d3bcb16531a317be7d2cdbd51b6b6a80cffb350ac5dafe658954402440de1836cd0096f1b69c0768c2bec8939f4ff26cc34e languageName: node linkType: hard @@ -1025,31 +734,29 @@ __metadata: linkType: hard "@changesets/cli@npm:^2.29.8": - version: 2.29.8 - resolution: "@changesets/cli@npm:2.29.8" + version: 2.31.0 + resolution: "@changesets/cli@npm:2.31.0" dependencies: - "@changesets/apply-release-plan": "npm:^7.0.14" - "@changesets/assemble-release-plan": "npm:^6.0.9" + "@changesets/apply-release-plan": "npm:^7.1.1" + "@changesets/assemble-release-plan": "npm:^6.0.10" "@changesets/changelog-git": "npm:^0.2.1" - "@changesets/config": "npm:^3.1.2" + "@changesets/config": "npm:^3.1.4" "@changesets/errors": "npm:^0.2.0" - "@changesets/get-dependents-graph": "npm:^2.1.3" - "@changesets/get-release-plan": "npm:^4.0.14" + "@changesets/get-dependents-graph": "npm:^2.1.4" + "@changesets/get-release-plan": "npm:^4.0.16" "@changesets/git": "npm:^3.0.4" "@changesets/logger": "npm:^0.1.1" "@changesets/pre": "npm:^2.0.2" - "@changesets/read": "npm:^0.6.6" + "@changesets/read": "npm:^0.6.7" "@changesets/should-skip-package": "npm:^0.1.2" "@changesets/types": "npm:^6.1.0" "@changesets/write": "npm:^0.4.0" "@inquirer/external-editor": "npm:^1.0.2" "@manypkg/get-packages": "npm:^1.1.3" ansi-colors: "npm:^4.1.3" - ci-info: "npm:^3.7.0" enquirer: "npm:^2.4.1" fs-extra: "npm:^7.0.1" mri: "npm:^1.2.0" - p-limit: "npm:^2.2.0" package-manager-detector: "npm:^0.2.0" picocolors: "npm:^1.1.0" resolve-from: "npm:^5.0.0" @@ -1058,22 +765,23 @@ __metadata: term-size: "npm:^2.1.0" bin: changeset: bin.js - checksum: 10/1169d97d7d0b86fdeb778aadc1ffa3e46c840345c97b4cdbe90e5fc0168d0d0870001d66f6676537716a2d22c147a84e8a120f1298156419dc6a662681861af5 + checksum: 10/7e64feb46375b56fe97e4eb41d0a38594275b5f0a5d9a8dc7fc2ded09194abbdc1386e9fcd6316da634b76aab07bf364005a331d3092a3cbbebf9ea84b61e488 languageName: node linkType: hard -"@changesets/config@npm:^3.1.2": - version: 3.1.2 - resolution: "@changesets/config@npm:3.1.2" +"@changesets/config@npm:^3.1.4": + version: 3.1.4 + resolution: "@changesets/config@npm:3.1.4" dependencies: "@changesets/errors": "npm:^0.2.0" - "@changesets/get-dependents-graph": "npm:^2.1.3" + "@changesets/get-dependents-graph": "npm:^2.1.4" "@changesets/logger": "npm:^0.1.1" + "@changesets/should-skip-package": "npm:^0.1.2" "@changesets/types": "npm:^6.1.0" "@manypkg/get-packages": "npm:^1.1.3" fs-extra: "npm:^7.0.1" micromatch: "npm:^4.0.8" - checksum: 10/c35626240c0af83433808216be48cc39dd0b27d20a7d3bbb95c0da0044a08207986678dae97f081cc524abf8351e0303890794a28e8c67f17036bd88013b2576 + checksum: 10/d563b0613c3fa387d517bd137c64755bd8246f74dc070c6a9cd5d2d05b2cd7b95cc042f8064fc01f4c18b04d5becc28e1c35f72e386e7c89ec5f0de781d30bf6 languageName: node linkType: hard @@ -1086,29 +794,29 @@ __metadata: languageName: node linkType: hard -"@changesets/get-dependents-graph@npm:^2.1.3": - version: 2.1.3 - resolution: "@changesets/get-dependents-graph@npm:2.1.3" +"@changesets/get-dependents-graph@npm:^2.1.4": + version: 2.1.4 + resolution: "@changesets/get-dependents-graph@npm:2.1.4" dependencies: "@changesets/types": "npm:^6.1.0" "@manypkg/get-packages": "npm:^1.1.3" picocolors: "npm:^1.1.0" semver: "npm:^7.5.3" - checksum: 10/33f2bb5dc88443b68fd796fd3b019a553fb3e21cb957a8a117db2a6770ad81f7c156ebdc3b12cfa75169de918f11271a71f61034aec48a53bf1a936d6d783e3d + checksum: 10/4b4895a69a47315e286b365d68af00216e29cba0b1033374cc4b7db0ec75625dd829e9e54aecf2ca7131ba7cc50f1ff1f51beb79a901b6da845c310f85d94464 languageName: node linkType: hard -"@changesets/get-release-plan@npm:^4.0.14": - version: 4.0.14 - resolution: "@changesets/get-release-plan@npm:4.0.14" +"@changesets/get-release-plan@npm:^4.0.16": + version: 4.0.16 + resolution: "@changesets/get-release-plan@npm:4.0.16" dependencies: - "@changesets/assemble-release-plan": "npm:^6.0.9" - "@changesets/config": "npm:^3.1.2" + "@changesets/assemble-release-plan": "npm:^6.0.10" + "@changesets/config": "npm:^3.1.4" "@changesets/pre": "npm:^2.0.2" - "@changesets/read": "npm:^0.6.6" + "@changesets/read": "npm:^0.6.7" "@changesets/types": "npm:^6.1.0" "@manypkg/get-packages": "npm:^1.1.3" - checksum: 10/0b54f4e34dc27aa9df928488bf84f3d6a2b516701985d06b49306d45b87b48e642aef3de751f9517de4c1b88011b5826975aa85f8ba596da1f9681a5d1699093 + checksum: 10/bb19b1ed535071d0d706731c91f19f6e87f18f78e583fa1e4fb7ab944c166ce1be5aa5f70b31cc5178aee6155b214522e49e0fd44a74eab416f8524411e07be6 languageName: node linkType: hard @@ -1141,13 +849,13 @@ __metadata: languageName: node linkType: hard -"@changesets/parse@npm:^0.4.2": - version: 0.4.2 - resolution: "@changesets/parse@npm:0.4.2" +"@changesets/parse@npm:^0.4.3": + version: 0.4.3 + resolution: "@changesets/parse@npm:0.4.3" dependencies: "@changesets/types": "npm:^6.1.0" js-yaml: "npm:^4.1.1" - checksum: 10/d45d7f5d7a0aeede197935f16bb459479c8d0b16ebe89ceaf4bd58b307ef1be696bcc5d5fc33d5b64a80dec946b49f6107af32d57d91967e6b3f9013a0d53740 + checksum: 10/f5742266a4ecb90a8283868f2bec740ce7be94745dee7df0b2f47882775d700bdfa3b660c2ec8d06b64153cf9b02cb3d46064f391c62933c9c60a9570763f928 languageName: node linkType: hard @@ -1163,18 +871,18 @@ __metadata: languageName: node linkType: hard -"@changesets/read@npm:^0.6.6": - version: 0.6.6 - resolution: "@changesets/read@npm:0.6.6" +"@changesets/read@npm:^0.6.7": + version: 0.6.7 + resolution: "@changesets/read@npm:0.6.7" dependencies: "@changesets/git": "npm:^3.0.4" "@changesets/logger": "npm:^0.1.1" - "@changesets/parse": "npm:^0.4.2" + "@changesets/parse": "npm:^0.4.3" "@changesets/types": "npm:^6.1.0" fs-extra: "npm:^7.0.1" p-filter: "npm:^2.1.0" picocolors: "npm:^1.1.0" - checksum: 10/3ac0cf24159b0e0fea4339d0a01c57459a6b7796f868dca7db65727c3dd33ead38b78f224b677cf7b50bb7b96fa3d0b155843e800a524b435a772c9ed21fa914 + checksum: 10/6bf3fd4b0c743d2ef53cb39c4e52731622949a695f031412ff6ea9f30860620a1d9deb1cfd1af0c92d2e2d275b6d949c0cc1e83c192f2094e0071d690c48a42e languageName: node linkType: hard @@ -1215,22 +923,22 @@ __metadata: linkType: hard "@coinbase/cdp-sdk@npm:^1.0.0": - version: 1.43.1 - resolution: "@coinbase/cdp-sdk@npm:1.43.1" + version: 1.51.0 + resolution: "@coinbase/cdp-sdk@npm:1.51.0" dependencies: "@solana-program/system": "npm:^0.10.0" "@solana-program/token": "npm:^0.9.0" - "@solana/kit": "npm:^5.1.0" - "@solana/web3.js": "npm:^1.98.1" + "@solana/kit": "npm:^5.5.1" abitype: "npm:1.0.6" - axios: "npm:^1.12.2" + axios: "npm:1.16.0" axios-retry: "npm:^4.5.0" - jose: "npm:^6.0.8" + bs58: "npm:^6.0.0" + jose: "npm:^6.2.0" md5: "npm:^2.3.0" uncrypto: "npm:^0.1.3" - viem: "npm:^2.21.26" - zod: "npm:^3.24.4" - checksum: 10/7e7d047e4fc946546ef8e7889b8573f21c59a44ceb8dd9499d93a1a3d41d581c60d8a3c30c466eed8d029b4f3de829fbf25c8f6d20a621ade7b8c8deccd39cd1 + viem: "npm:^2.47.0" + zod: "npm:^3.25.76" + checksum: 10/49805c3c61aff4c94011dabdca2ba182fa22f0e49ab10d109d7aaa34b23ca85f9f12c183b3ed71b1b1ce5342af56067eadd1ee0b069b5ea456082e0fc3324805 languageName: node linkType: hard @@ -1250,193 +958,403 @@ __metadata: languageName: node linkType: hard -"@ecies/ciphers@npm:^0.2.4": - version: 0.2.5 - resolution: "@ecies/ciphers@npm:0.2.5" +"@ecies/ciphers@npm:^0.2.5": + version: 0.2.6 + resolution: "@ecies/ciphers@npm:0.2.6" peerDependencies: "@noble/ciphers": ^1.0.0 - checksum: 10/af90636ee51812c9ead6e2c4be006f334bd6e12c5840de9c673b974b1ff3f79776747059257da3cb1731fcbc2d435a67b86dfb18fa90e07a6962c8816e6ab596 + checksum: 10/48e98971161497b7b4a49f70e20e2b807096d477262cd86bff7b6aa7e065f7ca10e6199529f41207ab65f4486ad6689c158798cd3a0ba20b875df3c68bec6281 + languageName: node + linkType: hard + +"@emnapi/core@npm:1.10.0": + version: 1.10.0 + resolution: "@emnapi/core@npm:1.10.0" + dependencies: + "@emnapi/wasi-threads": "npm:1.2.1" + tslib: "npm:^2.4.0" + checksum: 10/d32f386084e64deaf2609aabb8295d1ad5af6144d0f46d2060b76cc53f1f3b486df54bec9b0f33c37d85a3822e1193ebcd4e3deb4a5f0e4cd650aa2ffc631715 + languageName: node + linkType: hard + +"@emnapi/runtime@npm:1.10.0": + version: 1.10.0 + resolution: "@emnapi/runtime@npm:1.10.0" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10/d21083d07fa0c2da171c142e78ef986b66b07d45b06accc0bcaf49fcc61bb4dbc10e1c1760813070165b9f49b054376a931045347f21c0f42ff1eb2d2040faac + languageName: node + linkType: hard + +"@emnapi/wasi-threads@npm:1.2.1": + version: 1.2.1 + resolution: "@emnapi/wasi-threads@npm:1.2.1" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10/57cd4292be81c05d26aa886d68a9e4c449ff666e8503fed6463dfc6b64a4e4213f03c152d53296b7cda32840271e38cd33347332070658f01befeb9bf4e59f36 + languageName: node + linkType: hard + +"@esbuild/aix-ppc64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/aix-ppc64@npm:0.27.7" + conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/aix-ppc64@npm:0.27.2" +"@esbuild/aix-ppc64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/aix-ppc64@npm:0.28.0" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/android-arm64@npm:0.27.2" +"@esbuild/android-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/android-arm64@npm:0.27.7" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/android-arm@npm:0.27.2" +"@esbuild/android-arm64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/android-arm64@npm:0.28.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/android-arm@npm:0.27.7" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/android-arm@npm:0.28.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/android-x64@npm:0.27.2" +"@esbuild/android-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/android-x64@npm:0.27.7" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/darwin-arm64@npm:0.27.2" +"@esbuild/android-x64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/android-x64@npm:0.28.0" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/darwin-arm64@npm:0.27.7" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/darwin-arm64@npm:0.28.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/darwin-x64@npm:0.27.2" +"@esbuild/darwin-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/darwin-x64@npm:0.27.7" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/freebsd-arm64@npm:0.27.2" +"@esbuild/darwin-x64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/darwin-x64@npm:0.28.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/freebsd-arm64@npm:0.27.7" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/freebsd-arm64@npm:0.28.0" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/freebsd-x64@npm:0.27.2" +"@esbuild/freebsd-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/freebsd-x64@npm:0.27.7" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-arm64@npm:0.27.2" +"@esbuild/freebsd-x64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/freebsd-x64@npm:0.28.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-arm64@npm:0.27.7" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/linux-arm64@npm:0.28.0" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-arm@npm:0.27.2" +"@esbuild/linux-arm@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-arm@npm:0.27.7" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-ia32@npm:0.27.2" +"@esbuild/linux-arm@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/linux-arm@npm:0.28.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-ia32@npm:0.27.7" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/linux-ia32@npm:0.28.0" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-loong64@npm:0.27.2" +"@esbuild/linux-loong64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-loong64@npm:0.27.7" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-mips64el@npm:0.27.2" +"@esbuild/linux-loong64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/linux-loong64@npm:0.28.0" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-mips64el@npm:0.27.7" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/linux-mips64el@npm:0.28.0" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-ppc64@npm:0.27.2" +"@esbuild/linux-ppc64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-ppc64@npm:0.27.7" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-riscv64@npm:0.27.2" +"@esbuild/linux-ppc64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/linux-ppc64@npm:0.28.0" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-riscv64@npm:0.27.7" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/linux-riscv64@npm:0.28.0" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-s390x@npm:0.27.2" +"@esbuild/linux-s390x@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-s390x@npm:0.27.7" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-x64@npm:0.27.2" +"@esbuild/linux-s390x@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/linux-s390x@npm:0.28.0" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-x64@npm:0.27.7" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/linux-x64@npm:0.28.0" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/netbsd-arm64@npm:0.27.2" +"@esbuild/netbsd-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/netbsd-arm64@npm:0.27.7" conditions: os=netbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/netbsd-x64@npm:0.27.2" +"@esbuild/netbsd-arm64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/netbsd-arm64@npm:0.28.0" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/netbsd-x64@npm:0.27.7" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/netbsd-x64@npm:0.28.0" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/openbsd-arm64@npm:0.27.2" +"@esbuild/openbsd-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/openbsd-arm64@npm:0.27.7" conditions: os=openbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/openbsd-x64@npm:0.27.2" +"@esbuild/openbsd-arm64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/openbsd-arm64@npm:0.28.0" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/openbsd-x64@npm:0.27.7" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/openbsd-x64@npm:0.28.0" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openharmony-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/openharmony-arm64@npm:0.27.2" +"@esbuild/openharmony-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/openharmony-arm64@npm:0.27.7" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/sunos-x64@npm:0.27.2" +"@esbuild/openharmony-arm64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/openharmony-arm64@npm:0.28.0" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/sunos-x64@npm:0.27.7" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/sunos-x64@npm:0.28.0" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/win32-arm64@npm:0.27.2" +"@esbuild/win32-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/win32-arm64@npm:0.27.7" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/win32-ia32@npm:0.27.2" +"@esbuild/win32-arm64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/win32-arm64@npm:0.28.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/win32-ia32@npm:0.27.7" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/win32-ia32@npm:0.28.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/win32-x64@npm:0.27.2" +"@esbuild/win32-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/win32-x64@npm:0.27.7" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.28.0": + version: 0.28.0 + resolution: "@esbuild/win32-x64@npm:0.28.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -1460,27 +1378,27 @@ __metadata: linkType: hard "@eslint/compat@npm:^2.0.1": - version: 2.0.1 - resolution: "@eslint/compat@npm:2.0.1" + version: 2.1.0 + resolution: "@eslint/compat@npm:2.1.0" dependencies: - "@eslint/core": "npm:^1.0.1" + "@eslint/core": "npm:^1.2.1" peerDependencies: - eslint: ^8.40 || 9 + eslint: ^8.40 || 9 || 10 peerDependenciesMeta: eslint: optional: true - checksum: 10/3ae4af6faba4a1191fc42f51675e1e8a78f9133e980133e2a6b86acd7d9d79bb8692afbeef283c4359a611874cd6bd4583464ae656f9a64d7dcecbbdb7afaa08 + checksum: 10/e868afc209242b168e287ede744f52c4158cec3fb61dd269d88df919ee812f1d08ec09075bb74d2e130a4f8fc1768bbb2fd151d3da43e88987c3df1633255190 languageName: node linkType: hard -"@eslint/config-array@npm:^0.21.1": - version: 0.21.1 - resolution: "@eslint/config-array@npm:0.21.1" +"@eslint/config-array@npm:^0.21.2": + version: 0.21.2 + resolution: "@eslint/config-array@npm:0.21.2" dependencies: "@eslint/object-schema": "npm:^2.1.7" debug: "npm:^4.3.1" - minimatch: "npm:^3.1.2" - checksum: 10/6eaa0435972f735ce52d581f355a0b616e50a9b8a73304a7015398096e252798b9b3b968a67b524eefb0fdeacc57c4d960f0ec6432abe1c1e24be815b88c5d18 + minimatch: "npm:^3.1.5" + checksum: 10/148477ba995cf57fc725601916d5a7914aa249112d8bec2c3ac9122e2b2f540e6ef013ff4f6785346a4b565f09b20db127fa6f7322f5ffbdb3f1f8d2078a531c languageName: node linkType: hard @@ -1502,36 +1420,36 @@ __metadata: languageName: node linkType: hard -"@eslint/core@npm:^1.0.1": - version: 1.0.1 - resolution: "@eslint/core@npm:1.0.1" +"@eslint/core@npm:^1.2.1": + version: 1.2.1 + resolution: "@eslint/core@npm:1.2.1" dependencies: "@types/json-schema": "npm:^7.0.15" - checksum: 10/442b54d50adee1681672596abc538cba1a57d108d28e39aeed64e4beaee23aa6f9f029c7bc0b39e26d8c4754de16305fbfce7f6539e7df266163c0c49fbaa4af + checksum: 10/e1f9f5534f495b74a4c13c372e8f2feaf0c67f5dd666111c849c97c221d4ba730c98333a2ca94dd28cd7c24e3b1016bd868ca03c42e070732c047053f854cb13 languageName: node linkType: hard -"@eslint/eslintrc@npm:^3.3.1": - version: 3.3.3 - resolution: "@eslint/eslintrc@npm:3.3.3" +"@eslint/eslintrc@npm:^3.3.5": + version: 3.3.5 + resolution: "@eslint/eslintrc@npm:3.3.5" dependencies: - ajv: "npm:^6.12.4" + ajv: "npm:^6.14.0" debug: "npm:^4.3.2" espree: "npm:^10.0.1" globals: "npm:^14.0.0" ignore: "npm:^5.2.0" import-fresh: "npm:^3.2.1" js-yaml: "npm:^4.1.1" - minimatch: "npm:^3.1.2" + minimatch: "npm:^3.1.5" strip-json-comments: "npm:^3.1.1" - checksum: 10/b586a364ff15ce1b68993aefc051ca330b1fece15fb5baf4a708d00113f9a14895cffd84a5f24c5a97bd4b4321130ab2314f90aa462a250f6b859c2da2cba1f3 + checksum: 10/edabb65693d82a88cac3b2cf932a0f825e986b5e0a21ef08782d07e3a61ad87d39db67cfd5aeb146fd5053e5e24e389dbe5649ab22936a71d633c7b32a7e6d86 languageName: node linkType: hard -"@eslint/js@npm:9.39.2, @eslint/js@npm:^9.39.2": - version: 9.39.2 - resolution: "@eslint/js@npm:9.39.2" - checksum: 10/6b7f676746f3111b5d1b23715319212ab9297868a0fa9980d483c3da8965d5841673aada2d5653e85a3f7156edee0893a7ae7035211b4efdcb2848154bb947f2 +"@eslint/js@npm:9.39.4, @eslint/js@npm:^9.39.2": + version: 9.39.4 + resolution: "@eslint/js@npm:9.39.4" + checksum: 10/0a7ab4c4108cf2cadf66849ebd20f5957cc53052b88d8807d0b54e489dbf6ffcaf741e144e7f9b187c395499ce2e6ddc565dbfa4f60c6df455cf2b30bcbdc5a3 languageName: node linkType: hard @@ -1601,55 +1519,55 @@ __metadata: languageName: node linkType: hard -"@floating-ui/core@npm:^1.7.3": - version: 1.7.3 - resolution: "@floating-ui/core@npm:1.7.3" +"@floating-ui/core@npm:^1.7.5": + version: 1.7.5 + resolution: "@floating-ui/core@npm:1.7.5" dependencies: - "@floating-ui/utils": "npm:^0.2.10" - checksum: 10/a8952ff2673ddf28f12feeb86d90c54949e45bcb1af5758b7672850ac0dadb36d4bd61aa45dad1b6a35ba40d4756d3573afac6610b90502639d7266b91e0864e + "@floating-ui/utils": "npm:^0.2.11" + checksum: 10/fecdc9b3ce93f02bf78a6114b93730a4cb9fa8234c62f9a949016186297a039c9f9cd3c5c81ff74b93ebddf0b32048c4af7a528afe7904b75423ed2e7491b888 languageName: node linkType: hard -"@floating-ui/dom@npm:^1.7.4": - version: 1.7.4 - resolution: "@floating-ui/dom@npm:1.7.4" +"@floating-ui/dom@npm:^1.7.6": + version: 1.7.6 + resolution: "@floating-ui/dom@npm:1.7.6" dependencies: - "@floating-ui/core": "npm:^1.7.3" - "@floating-ui/utils": "npm:^0.2.10" - checksum: 10/d3d6a23e7b9804ba56338c7c666590258683af14b6026270d32afc1202f72b5b82cca359004bdc7830bf2463a045da6c7bd4e7d5351218cf270ff94206197971 + "@floating-ui/core": "npm:^1.7.5" + "@floating-ui/utils": "npm:^0.2.11" + checksum: 10/84dff2ffdf85c8b92d7edafc543c55869abbeaeb3007fa983159467e050153b507a0f5fe8e84f88c3f28c35a82de9df9c20a6eef5560cbba3afae19141444ff2 languageName: node linkType: hard -"@floating-ui/react-dom@npm:^2.1.6": - version: 2.1.6 - resolution: "@floating-ui/react-dom@npm:2.1.6" +"@floating-ui/react-dom@npm:^2.1.8": + version: 2.1.8 + resolution: "@floating-ui/react-dom@npm:2.1.8" dependencies: - "@floating-ui/dom": "npm:^1.7.4" + "@floating-ui/dom": "npm:^1.7.6" peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 10/fbfd3319b42edb9c156e4e872f500d2edb112bc9cfd1b45892bff16ccf21c2484ddc9c416f7631c2aaaadec1b2f98b205db8a3f89eb78ca870905fcfe3917c35 + checksum: 10/39c3e3e5538a111a3eadf1b9ca486d7dc17c7eb24b83a0ea9b4c189fa7dbe5abe01357388d8cf6a4badb2d3fec2b1090e10529537bde91acbcfe19b0a8d10f90 languageName: node linkType: hard "@floating-ui/react@npm:^0.27.16": - version: 0.27.16 - resolution: "@floating-ui/react@npm:0.27.16" + version: 0.27.19 + resolution: "@floating-ui/react@npm:0.27.19" dependencies: - "@floating-ui/react-dom": "npm:^2.1.6" - "@floating-ui/utils": "npm:^0.2.10" + "@floating-ui/react-dom": "npm:^2.1.8" + "@floating-ui/utils": "npm:^0.2.11" tabbable: "npm:^6.0.0" peerDependencies: react: ">=17.0.0" react-dom: ">=17.0.0" - checksum: 10/b9baedee124035323a8f74794ec782678faf52af1c88731ce7d2641b7e7c97748fda1e711a3c4db007a0153d93158d867f4726ee632d713d3de76ec4bdfd84e1 + checksum: 10/4ebdc582544d0abf8f8011a6182af2ce4464e3a6a9a0fd4ff5facef161e73c6defa80240a7dc62f7cd2cbd5ecfb00b17c5dd5b10aa6e787cbc1ed963f323245c languageName: node linkType: hard -"@floating-ui/utils@npm:^0.2.10": - version: 0.2.10 - resolution: "@floating-ui/utils@npm:0.2.10" - checksum: 10/b635ea865a8be2484b608b7157f5abf9ed439f351011a74b7e988439e2898199a9a8b790f52291e05bdcf119088160dc782d98cff45cc98c5a271bc6f51327ae +"@floating-ui/utils@npm:^0.2.11": + version: 0.2.11 + resolution: "@floating-ui/utils@npm:0.2.11" + checksum: 10/72150138ba1c274d757a1da85233202fa9fdfd2272ec1fb0883eb0ffdf138863af81573049ed2c20b98adb4b7ae2236065541ce14037fe328955089831a678d5 languageName: node linkType: hard @@ -1665,20 +1583,30 @@ __metadata: languageName: node linkType: hard -"@humanfs/core@npm:^0.19.1": - version: 0.19.1 - resolution: "@humanfs/core@npm:0.19.1" - checksum: 10/270d936be483ab5921702623bc74ce394bf12abbf57d9145a69e8a0d1c87eb1c768bd2d93af16c5705041e257e6d9cc7529311f63a1349f3678abc776fc28523 +"@humanfs/core@npm:^0.19.2": + version: 0.19.2 + resolution: "@humanfs/core@npm:0.19.2" + dependencies: + "@humanfs/types": "npm:^0.15.0" + checksum: 10/c6c0273721ec8df3d36a57c390a11a168d0a2f513d78bceb25165bded4fcb73609b1a317edc6c8f331cefd4b47285dde0b1e6679e08ef7f062232ec14fe05312 languageName: node linkType: hard "@humanfs/node@npm:^0.16.6": - version: 0.16.7 - resolution: "@humanfs/node@npm:0.16.7" + version: 0.16.8 + resolution: "@humanfs/node@npm:0.16.8" dependencies: - "@humanfs/core": "npm:^0.19.1" + "@humanfs/core": "npm:^0.19.2" + "@humanfs/types": "npm:^0.15.0" "@humanwhocodes/retry": "npm:^0.4.0" - checksum: 10/b3633d3dce898592cac515ba5e6693c78e6be92863541d3eaf2c009b10f52b2fa62ff6e6e06f240f2447ddbe7b5f1890bc34e9308470675c876eee207553a08d + checksum: 10/ed01b3c066d9cec7526d139b9e71ca00ee4a30b3b5f5f5c198eb069c3509a3e167e180ba7e1e5a83b9571e906c4908bd20402b47586887452311af7354995e95 + languageName: node + linkType: hard + +"@humanfs/types@npm:^0.15.0": + version: 0.15.0 + resolution: "@humanfs/types@npm:0.15.0" + checksum: 10/dea3cc7fd8f8d4d088ed8d0a9921cf12bd8e1cdf40a6133106b03a6e2aebcc9a6f1771b3643b7ec71baae90d08245db34069dfcc861da8d678662741e6c3c986 languageName: node linkType: hard @@ -1697,8 +1625,8 @@ __metadata: linkType: hard "@ianvs/prettier-plugin-sort-imports@npm:^4.7.0": - version: 4.7.0 - resolution: "@ianvs/prettier-plugin-sort-imports@npm:4.7.0" + version: 4.7.1 + resolution: "@ianvs/prettier-plugin-sort-imports@npm:4.7.1" dependencies: "@babel/generator": "npm:^7.26.2" "@babel/parser": "npm:^7.26.2" @@ -1706,7 +1634,7 @@ __metadata: "@babel/types": "npm:^7.26.0" semver: "npm:^7.5.2" peerDependencies: - "@prettier/plugin-oxc": ^0.0.4 + "@prettier/plugin-oxc": ^0.0.4 || ^0.1.0 "@vue/compiler-sfc": 2.7.x || 3.x content-tag: ^4.0.0 prettier: 2 || 3 || ^4.0.0-0 @@ -1720,7 +1648,7 @@ __metadata: optional: true prettier-plugin-ember-template-tag: optional: true - checksum: 10/0bdb53a5f82624825819a5b5130c61e3fa43ae7fb404b6d515001794a0b7036a397b747f98829ddc9e079343c4435569d8799271e9629445fda815b93ace6f9f + checksum: 10/6bee1d83205af81ade7f4881dd6fe0e3015fbeda0360234b21675739f1752496fe8cb7c5e4b52b17dd772ea05a6ae64bae1330c7e8c8f2ea46fe214f1b1b14a1 languageName: node linkType: hard @@ -2042,36 +1970,6 @@ __metadata: languageName: node linkType: hard -"@isaacs/balanced-match@npm:^4.0.1": - version: 4.0.1 - resolution: "@isaacs/balanced-match@npm:4.0.1" - checksum: 10/102fbc6d2c0d5edf8f6dbf2b3feb21695a21bc850f11bc47c4f06aa83bd8884fde3fe9d6d797d619901d96865fdcb4569ac2a54c937992c48885c5e3d9967fe8 - languageName: node - linkType: hard - -"@isaacs/brace-expansion@npm:^5.0.0": - version: 5.0.0 - resolution: "@isaacs/brace-expansion@npm:5.0.0" - dependencies: - "@isaacs/balanced-match": "npm:^4.0.1" - checksum: 10/cf3b7f206aff12128214a1df764ac8cdbc517c110db85249b945282407e3dfc5c6e66286383a7c9391a059fc8e6e6a8ca82262fc9d2590bd615376141fbebd2d - languageName: node - linkType: hard - -"@isaacs/cliui@npm:^8.0.2": - version: 8.0.2 - resolution: "@isaacs/cliui@npm:8.0.2" - dependencies: - string-width: "npm:^5.1.2" - string-width-cjs: "npm:string-width@^4.2.0" - strip-ansi: "npm:^7.0.1" - strip-ansi-cjs: "npm:strip-ansi@^6.0.1" - wrap-ansi: "npm:^8.1.0" - wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" - checksum: 10/e9ed5fd27c3aec1095e3a16e0c0cf148d1fee55a38665c35f7b3f86a9b5d00d042ddaabc98e8a1cb7463b9378c15f22a94eb35e99469c201453eb8375191f243 - languageName: node - linkType: hard - "@isaacs/fs-minipass@npm:^4.0.0": version: 4.0.1 resolution: "@isaacs/fs-minipass@npm:4.0.1" @@ -2136,9 +2034,9 @@ __metadata: linkType: hard "@lit-labs/ssr-dom-shim@npm:^1.5.0": - version: 1.5.1 - resolution: "@lit-labs/ssr-dom-shim@npm:1.5.1" - checksum: 10/8b90e101cbaef3aa9d3a16cd90010c2c7c13cc0b3effa8ce166e2c7a57e52e759fb7bb4f800ce5b5dfb1d7cbd8430a0b430bcc8bcb8b54d1417dbf2eb046dd6a + version: 1.6.0 + resolution: "@lit-labs/ssr-dom-shim@npm:1.6.0" + checksum: 10/144432432e1749c4878a59baf41b2afaadef565675d64b2a8e088c6f54e36f26f67ef43aa93e49d3e6dd38a5e27c41059e981c33accdb4e8c6d47c1048696b80 languageName: node linkType: hard @@ -2152,8 +2050,8 @@ __metadata: linkType: hard "@mantine/core@npm:^8.3.13": - version: 8.3.13 - resolution: "@mantine/core@npm:8.3.13" + version: 8.3.18 + resolution: "@mantine/core@npm:8.3.18" dependencies: "@floating-ui/react": "npm:^0.27.16" clsx: "npm:^2.1.1" @@ -2162,67 +2060,67 @@ __metadata: react-textarea-autosize: "npm:8.5.9" type-fest: "npm:^4.41.0" peerDependencies: - "@mantine/hooks": 8.3.13 + "@mantine/hooks": 8.3.18 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - checksum: 10/80cf25ededceef514e35d22f8a3e612209749f8d80ab9a6e4d582c95b7b22032684f501d6e4445e363f434a114d230b03aadcd564da8b3978e581631b18b56b4 + checksum: 10/1ac226df8b4a26fe5e4a92710abcbcc5e8d80a25bd2f2e7f99f1764d0ef603961bf237642ed0795049bd877ff1a3a612d41f613cea442a852adce5ccb4483c1b languageName: node linkType: hard "@mantine/form@npm:^8.3.13": - version: 8.3.13 - resolution: "@mantine/form@npm:8.3.13" + version: 8.3.18 + resolution: "@mantine/form@npm:8.3.18" dependencies: fast-deep-equal: "npm:^3.1.3" klona: "npm:^2.0.6" peerDependencies: react: ^18.x || ^19.x - checksum: 10/bb9c75f44e813dccbc0987c1ba0b603b57853844a52cc44530fae1990799e1f08a482e87e7dfc9145d8ff2ac2685d19c9439e311ea33614472bc3d07a34ba736 + checksum: 10/fad4997445b9f4d742b6af3f163f4b5319ff3e3aa37173fd0c8ba0a8ed9d3dbb356a868dfd7daf509a0e4a5ced4a061481fa2beffb6d77504c88a2741876c43a languageName: node linkType: hard "@mantine/hooks@npm:^8.3.13": - version: 8.3.13 - resolution: "@mantine/hooks@npm:8.3.13" + version: 8.3.18 + resolution: "@mantine/hooks@npm:8.3.18" peerDependencies: react: ^18.x || ^19.x - checksum: 10/e37e482810e76865e86efdb827ce68975334b1f2a448d4fce6735c0d6a4801cca8f19cc19242356bba5062c29b10969918b7000eda192e204791053f522695ed + checksum: 10/a7ed06619095afc183046eea8a46c3780eb538a460f201c99da48b36ebacb6653daafcf3905ec473179335303994c602d477acacbf4cdfd65e8653062eb9a6cd languageName: node linkType: hard "@mantine/modals@npm:^8.3.13": - version: 8.3.13 - resolution: "@mantine/modals@npm:8.3.13" + version: 8.3.18 + resolution: "@mantine/modals@npm:8.3.18" peerDependencies: - "@mantine/core": 8.3.13 - "@mantine/hooks": 8.3.13 + "@mantine/core": 8.3.18 + "@mantine/hooks": 8.3.18 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - checksum: 10/e3de8af7589a39aa8b4e580a00fc51953e97beaaa37551f787eee7bb8eeb2b182c51610afc039233f6419909df4042079dc2e313cb2388a6248abcde45f8c048 + checksum: 10/9dd487692c892d0a4cedd80651e5179b028f8727e4c1b57d75dff417f1da34aac23e0b68c3d2fd07dfbfabbe0df8e276db2d7515adaf3564df35c532388eae22 languageName: node linkType: hard "@mantine/notifications@npm:^8.3.13": - version: 8.3.13 - resolution: "@mantine/notifications@npm:8.3.13" + version: 8.3.18 + resolution: "@mantine/notifications@npm:8.3.18" dependencies: - "@mantine/store": "npm:8.3.13" + "@mantine/store": "npm:8.3.18" react-transition-group: "npm:4.4.5" peerDependencies: - "@mantine/core": 8.3.13 - "@mantine/hooks": 8.3.13 + "@mantine/core": 8.3.18 + "@mantine/hooks": 8.3.18 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - checksum: 10/444ab820b1a94cf1359936bd1afa17f5a0d847143e7855e736eaafd75472b323e95b9c902be73f764d25707f8e58509653ec0bd4c3d0e1a8e07ce8a2b11df81d + checksum: 10/b42934e656158add3e3f680f8ab8322ec9a445e408bd08dda0b31d9194d2d2737dee7eb4c8a3e820035322238a7ca7f0587047fb1227d6389e05f5229e9f9ae6 languageName: node linkType: hard -"@mantine/store@npm:8.3.13": - version: 8.3.13 - resolution: "@mantine/store@npm:8.3.13" +"@mantine/store@npm:8.3.18": + version: 8.3.18 + resolution: "@mantine/store@npm:8.3.18" peerDependencies: react: ^18.x || ^19.x - checksum: 10/a5018acb7b38d90b17c6043b271175d73c0721de4daed262bb067ae795b36992d0bb39cdfba5bfa71e65c380caffe2f23d8bcc9ac419a9534b3cc6040a43ab4c + checksum: 10/473fd7ec7fc5be2fa86d73d006c7b25d7ea885937bdb924b736efcf82d15f4b27e8c64dc42aa078c0bd40a24ea259fb1bc2e8ca05dcb58da17ad8e38927fb427 languageName: node linkType: hard @@ -2444,8 +2342,8 @@ __metadata: linkType: hard "@metamask/utils@npm:^11.0.1": - version: 11.9.0 - resolution: "@metamask/utils@npm:11.9.0" + version: 11.11.0 + resolution: "@metamask/utils@npm:11.11.0" dependencies: "@ethereumjs/tx": "npm:^4.2.0" "@metamask/superstruct": "npm:^3.1.0" @@ -2458,7 +2356,7 @@ __metadata: pony-cause: "npm:^2.1.10" semver: "npm:^7.5.4" uuid: "npm:^9.0.1" - checksum: 10/f8f5e99ba6c6de0395ed4e0acc82ee9c0dca26991ea6a8f10b3896e72745790966a8eded8c42be905d9f01fa99c1fd29a7f68541e2ef9854fc14984a0b514ad3 + checksum: 10/c4381b9e451a9616bde84ac659bc0d1848ef06b6e605f877bfa065b78c8ed5015706683ea88a3387de5eaeb3a50d1af9af0994f04f9e06258d992598fe2be3bf languageName: node linkType: hard @@ -2509,6 +2407,18 @@ __metadata: languageName: node linkType: hard +"@napi-rs/wasm-runtime@npm:^1.1.4": + version: 1.1.4 + resolution: "@napi-rs/wasm-runtime@npm:1.1.4" + dependencies: + "@tybys/wasm-util": "npm:^0.10.1" + peerDependencies: + "@emnapi/core": ^1.7.1 + "@emnapi/runtime": ^1.7.1 + checksum: 10/1db3dc7eeb981306b09360487bd8ce4dfa5588d273bd8ea9f07dccca1b4ade57b675414180fc9bb66966c6c50b17208b0263194993e2f7f92cc7af28bda4d1af + languageName: node + linkType: hard + "@noble/ciphers@npm:1.2.1": version: 1.2.1 resolution: "@noble/ciphers@npm:1.2.1" @@ -2559,7 +2469,7 @@ __metadata: languageName: node linkType: hard -"@noble/curves@npm:^1.4.2, @noble/curves@npm:^1.6.0, @noble/curves@npm:^1.9.7, @noble/curves@npm:~1.9.0": +"@noble/curves@npm:^1.6.0, @noble/curves@npm:^1.9.7, @noble/curves@npm:~1.9.0": version: 1.9.7 resolution: "@noble/curves@npm:1.9.7" dependencies: @@ -2605,7 +2515,7 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:^1.8.0, @noble/hashes@npm:~1.8.0": +"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:^1.8.0, @noble/hashes@npm:~1.8.0": version: 1.8.0 resolution: "@noble/hashes@npm:1.8.0" checksum: 10/474b7f56bc6fb2d5b3a42132561e221b0ea4f91e590f4655312ca13667840896b34195e2b53b7f097ec080a1fdd3b58d902c2a8d0fbdf51d2e238b53808a177e @@ -2619,6 +2529,13 @@ __metadata: languageName: node linkType: hard +"@nodable/entities@npm:^2.1.0": + version: 2.1.1 + resolution: "@nodable/entities@npm:2.1.1" + checksum: 10/0786f9133cc7bc64cb56477dad7e805cca0e179fd53773b430ed9de342328e621d641ba379ea480ec2d5f246e893c399aeeed579c436841e61c372139a3d9aa5 + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -2646,28 +2563,6 @@ __metadata: languageName: node linkType: hard -"@npmcli/agent@npm:^4.0.0": - version: 4.0.0 - resolution: "@npmcli/agent@npm:4.0.0" - dependencies: - agent-base: "npm:^7.1.0" - http-proxy-agent: "npm:^7.0.0" - https-proxy-agent: "npm:^7.0.1" - lru-cache: "npm:^11.2.1" - socks-proxy-agent: "npm:^8.0.3" - checksum: 10/1a81573becc60515031accc696e6405e9b894e65c12b98ef4aeee03b5617c41948633159dbf6caf5dde5b47367eeb749bdc7b7dfb21960930a9060a935c6f636 - languageName: node - linkType: hard - -"@npmcli/fs@npm:^5.0.0": - version: 5.0.0 - resolution: "@npmcli/fs@npm:5.0.0" - dependencies: - semver: "npm:^7.3.5" - checksum: 10/4935c7719d17830d0f9fa46c50be17b2a3c945cec61760f6d0909bce47677c42e1810ca673305890f9e84f008ec4d8e841182f371e42100a8159d15f22249208 - languageName: node - linkType: hard - "@oclif/color@npm:^1.0.13": version: 1.0.13 resolution: "@oclif/color@npm:1.0.13" @@ -2717,9 +2612,9 @@ __metadata: languageName: node linkType: hard -"@oclif/core@npm:^4, @oclif/core@npm:^4.8.0": - version: 4.8.0 - resolution: "@oclif/core@npm:4.8.0" +"@oclif/core@npm:^4, @oclif/core@npm:^4.11.4, @oclif/core@npm:^4.8.0": + version: 4.11.4 + resolution: "@oclif/core@npm:4.11.4" dependencies: ansi-escapes: "npm:^4.3.2" ansis: "npm:^3.17.0" @@ -2731,77 +2626,84 @@ __metadata: indent-string: "npm:^4.0.0" is-wsl: "npm:^2.2.0" lilconfig: "npm:^3.1.3" - minimatch: "npm:^9.0.5" - semver: "npm:^7.7.3" + minimatch: "npm:^10.2.5" + semver: "npm:^7.8.1" string-width: "npm:^4.2.3" supports-color: "npm:^8" - tinyglobby: "npm:^0.2.14" + tinyglobby: "npm:^0.2.16" widest-line: "npm:^3.1.0" wordwrap: "npm:^1.0.0" wrap-ansi: "npm:^7.0.0" - checksum: 10/e4816207b6a5d93db7df0247052efa69555513622a1c3dc5e91f5e8c995bc9ecb7addfb1a4753c6be27c627701f58f98f6087e6907def00ba602c5f8a8df3be4 + checksum: 10/e213c43818fe8c78067bb131bed4d0e1bc8b441f35a33f61292bb513741e17ba1849bb995de7b3b07fa1c5b80bbcf7eadc805963fc236dbbd762154d9fc506e4 languageName: node linkType: hard "@oclif/plugin-autocomplete@npm:^3.2.40": - version: 3.2.40 - resolution: "@oclif/plugin-autocomplete@npm:3.2.40" + version: 3.2.50 + resolution: "@oclif/plugin-autocomplete@npm:3.2.50" dependencies: "@oclif/core": "npm:^4" ansis: "npm:^3.16.0" debug: "npm:^4.4.1" ejs: "npm:^3.1.10" - checksum: 10/be482db085f89d0c976140e48db5fcd8758f6150fb3c517e949c174b8d6922f0959e4043243dd85fbdb690e7e8faee9ae17d1ede1839acaf668867b3b5143fc1 + checksum: 10/2adbd9ff16d87a2dc66d7633ebd1c3fcfc1c7bf6443dc31bb47b4e92c8aad4df8df6339c26eeeff1cc46171bc0d5528ae17c2e9300d5ff7038cf0985e410d226 languageName: node linkType: hard -"@oclif/plugin-help@npm:^6.2.36, @oclif/plugin-help@npm:^6.2.37": - version: 6.2.37 - resolution: "@oclif/plugin-help@npm:6.2.37" +"@oclif/plugin-help@npm:^6.2.37, @oclif/plugin-help@npm:^6.2.49": + version: 6.2.50 + resolution: "@oclif/plugin-help@npm:6.2.50" dependencies: "@oclif/core": "npm:^4" - checksum: 10/f8b398dfd698d860dc7f17f82faf130bd840be0f48a21542113b5bf3109cec378de833dc432999e4f158d02062d84dbe7846e7e34fba476d0cb3cea2b49e5a74 + checksum: 10/ad094a49aa3524c5e9afdc8cd1f87cbbbbf931cd067befd5bb93d4d35fdb3101d408be6727cdba39720cbc8584e173fbf3667bc4d666e1dc57a9623550b951f9 languageName: node linkType: hard "@oclif/plugin-legacy@npm:^2.0.27": - version: 2.0.27 - resolution: "@oclif/plugin-legacy@npm:2.0.27" + version: 2.0.33 + resolution: "@oclif/plugin-legacy@npm:2.0.33" dependencies: "@oclif/color": "npm:^1.0.13" "@oclif/core": "npm:^3.27.0" ansi-escapes: "npm:^4.3.2" debug: "npm:^4.4.3" - semver: "npm:^7.7.3" + semver: "npm:^7.8.1" peerDependencies: "@heroku-cli/command": "*" - checksum: 10/0dfb2493a295e0d3201e6a43de51d7c1ec6410d9d7e4432dd9322da2ba8677b6a5c92686cfc06718890012105ab3396463480e41106b20f4e32f543e8fca7a41 + checksum: 10/a59623d806d84047827a18c5aa769cd399bef856efe8ad1e65ee52d4f0b7578110eb9c7f330bca94d948973e7bae6b2acbbebca604a7d44e5bd5dd6c031b0fa2 languageName: node linkType: hard -"@oclif/plugin-not-found@npm:^3.2.73, @oclif/plugin-not-found@npm:^3.2.74": - version: 3.2.74 - resolution: "@oclif/plugin-not-found@npm:3.2.74" +"@oclif/plugin-not-found@npm:^3.2.74, @oclif/plugin-not-found@npm:^3.2.85": + version: 3.2.87 + resolution: "@oclif/plugin-not-found@npm:3.2.87" dependencies: "@inquirer/prompts": "npm:^7.10.1" - "@oclif/core": "npm:^4.8.0" + "@oclif/core": "npm:^4.11.4" ansis: "npm:^3.17.0" fast-levenshtein: "npm:^3.0.0" - checksum: 10/2ac698130bc0bb185e608cc05a0621cfecb57cdd7929945de81bc76517d601049ea96feb14cd2b42c2b0361a18223637496245eab1c23952c7c98c6ad47e21e8 + checksum: 10/67d30839461bb18423dd79254842f313f28b9b65f59658532ec98768ab21bc839b2e010e88a464d782db6e8e0343b5b20ae94915dbeffc409e7142d1fcb201ea languageName: node linkType: hard -"@oclif/plugin-warn-if-update-available@npm:^3.1.55": - version: 3.1.55 - resolution: "@oclif/plugin-warn-if-update-available@npm:3.1.55" +"@oclif/plugin-warn-if-update-available@npm:^3.1.55, @oclif/plugin-warn-if-update-available@npm:^3.1.65": + version: 3.1.65 + resolution: "@oclif/plugin-warn-if-update-available@npm:3.1.65" dependencies: "@oclif/core": "npm:^4" ansis: "npm:^3.17.0" debug: "npm:^4.4.3" http-call: "npm:^5.2.2" - lodash: "npm:^4.17.23" + lodash: "npm:^4.18.1" registry-auth-token: "npm:^5.1.1" - checksum: 10/627998df65b4492c33c5008c824049bbf52e9ba576abbb344d2e79efc0cf3bab589bc1694c950d25a319fdb6c13a62530901bc2b144788543d449ad604460f1d + checksum: 10/f1a70f51e3b8aa951736bceffc42c20cad8d4b69404eb766c78eb0077ad3b5855b99cfa08e89f23bfb1b978e25143ec29da95e2d4d656720001e6a97ea16be08 + languageName: node + linkType: hard + +"@oxc-project/types@npm:=0.133.0": + version: 0.133.0 + resolution: "@oxc-project/types@npm:0.133.0" + checksum: 10/de44f653a9e0c0267309122f1f184120c6869af4382218a6bf4a320c5150743eb00b5e8641b04917666281995ed0fe6381561922a48a28082a75bb122acf3ac6 languageName: node linkType: hard @@ -2812,17 +2714,10 @@ __metadata: languageName: node linkType: hard -"@pkgjs/parseargs@npm:^0.11.0": - version: 0.11.0 - resolution: "@pkgjs/parseargs@npm:0.11.0" - checksum: 10/115e8ceeec6bc69dff2048b35c0ab4f8bbee12d8bb6c1f4af758604586d802b6e669dcb02dda61d078de42c2b4ddce41b3d9e726d7daa6b4b850f4adbf7333ff - languageName: node - linkType: hard - -"@pkgr/core@npm:^0.2.9": - version: 0.2.9 - resolution: "@pkgr/core@npm:0.2.9" - checksum: 10/bb2fb86977d63f836f8f5b09015d74e6af6488f7a411dcd2bfdca79d76b5a681a9112f41c45bdf88a9069f049718efc6f3900d7f1de66a2ec966068308ae517f +"@pkgr/core@npm:^0.3.6": + version: 0.3.6 + resolution: "@pkgr/core@npm:0.3.6" + checksum: 10/29082aa13d36f13fc41cdc64cb1feb36b630de0d6ebde84e2ff68e3d7a7f1dce4462cca91f76176c46e50bbca6b1e7f1fd9cf907af12d5d70da83bc981ca4ccf languageName: node linkType: hard @@ -2860,9 +2755,16 @@ __metadata: languageName: node linkType: hard +"@prisma/client-runtime-utils@npm:^7.3.0": + version: 7.8.0 + resolution: "@prisma/client-runtime-utils@npm:7.8.0" + checksum: 10/759a02392f562a4118991dcd5a68393a6e26e1881b28bf01082e05751b84d27790a3cbd550bc317da617af97746432d411a6138268b45676696b18a264a5f2a7 + languageName: node + linkType: hard + "@prisma/client@npm:^6.19.2": - version: 6.19.2 - resolution: "@prisma/client@npm:6.19.2" + version: 6.19.3 + resolution: "@prisma/client@npm:6.19.3" peerDependencies: prisma: "*" typescript: ">=5.1.0" @@ -2871,40 +2773,40 @@ __metadata: optional: true typescript: optional: true - checksum: 10/409276476999c9200d07ee2185f054c39d7f3b2bcd245d95f4f2d35d46808d39a1458ed4b896774f6bdf7eb7cc518c7c0590ebf94869a93c4b57a94a6339c27c + checksum: 10/358fbbe859f1b9dca97376cad19206b3fbb2bda0d9b087952aa35ff181dbbe8b40a23f2567c46994da6d85424cee03db9457a6fc994bda25a81b211530472ce6 languageName: node linkType: hard -"@prisma/config@npm:6.19.2": - version: 6.19.2 - resolution: "@prisma/config@npm:6.19.2" +"@prisma/config@npm:6.19.3": + version: 6.19.3 + resolution: "@prisma/config@npm:6.19.3" dependencies: c12: "npm:3.1.0" deepmerge-ts: "npm:7.1.5" - effect: "npm:3.18.4" + effect: "npm:3.21.0" empathic: "npm:2.0.0" - checksum: 10/0615abdbd4c4ffe464622ac517293c1c7cddea61ab652539052838b0d24fb5e5c0f16921e2a26bf6adf13d9c9e54bea5b7b6f56ddd383e44b8d6f9e162fb4d74 + checksum: 10/85e0bfd07eef63f70360eeaea764e72b476af3510517ae77dd5fcea351c87929d19c66bcc6f8803193b2b054dec669f190c075c9093fdca3313c6a6a3bbccfa2 languageName: node linkType: hard -"@prisma/debug@npm:6.19.2": - version: 6.19.2 - resolution: "@prisma/debug@npm:6.19.2" - checksum: 10/345e15df1b1883d0800fc6f61ba31422ac2e251dfd786f37b945ab28fbaecd3a96a2abbc61a672bb8cb285eed2c3f16489669dbdac0f84b11448db657571cd10 +"@prisma/debug@npm:6.19.3": + version: 6.19.3 + resolution: "@prisma/debug@npm:6.19.3" + checksum: 10/22807b71f85c484d0a374db7c3f055a4d290852b7229afd10c3b6c3f930e3c58b8b17c49f141445f416dbbb957b4db4bdf631ae0544c959776e041a3199efb99 languageName: node linkType: hard -"@prisma/debug@npm:7.3.0": - version: 7.3.0 - resolution: "@prisma/debug@npm:7.3.0" - checksum: 10/071dbd3b7cec5bdae4b83f75b9a70673bf49b22524c0f8389684ce2e6af17a4349ac6d1fa7793de5c41a9e129904d0cf864d0dcd31fb650c8cac3c3e0aea3235 +"@prisma/debug@npm:7.8.0": + version: 7.8.0 + resolution: "@prisma/debug@npm:7.8.0" + checksum: 10/486189513be5965e0b61415b58699727abbc134ab411de3d705c2b8445371bad1473fd7b225e362784dd6084b4f690d3e42e622e4df40c4c47658c696160a25a languageName: node linkType: hard -"@prisma/dmmf@npm:7.3.0, @prisma/dmmf@npm:^7.0.1": - version: 7.3.0 - resolution: "@prisma/dmmf@npm:7.3.0" - checksum: 10/8ff8318e080a421c517092780352e3bbd2857197f01b0db498a9fb3968f4470f1d07a68d939094c5173fcdb4ffa30222139d1bf7c42296a171058d9c2bed4d5e +"@prisma/dmmf@npm:7.8.0, @prisma/dmmf@npm:^7.3.0": + version: 7.8.0 + resolution: "@prisma/dmmf@npm:7.8.0" + checksum: 10/2d5d1819849a799cbe1388c222e0111ef701ac43550c686d4bd4d699452ccb508425ca0ff8c505670ef362d6bf5706f40a536377cf719283a10d41f252b19b9f languageName: node linkType: hard @@ -2915,53 +2817,53 @@ __metadata: languageName: node linkType: hard -"@prisma/engines@npm:6.19.2": - version: 6.19.2 - resolution: "@prisma/engines@npm:6.19.2" +"@prisma/engines@npm:6.19.3": + version: 6.19.3 + resolution: "@prisma/engines@npm:6.19.3" dependencies: - "@prisma/debug": "npm:6.19.2" + "@prisma/debug": "npm:6.19.3" "@prisma/engines-version": "npm:7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7" - "@prisma/fetch-engine": "npm:6.19.2" - "@prisma/get-platform": "npm:6.19.2" - checksum: 10/84d0c010b42286f19dec6ba8ed9726bfceb696185f352d67f61378afe431b59e27a3cc83a914ea5b61cd35c8ccb12819f408b5ab494341cc6d495bfb838db084 + "@prisma/fetch-engine": "npm:6.19.3" + "@prisma/get-platform": "npm:6.19.3" + checksum: 10/4e9440b7b769b3da6a8b6ddc4f4f6dcc161923ec3c535719118a4e5ba74c43c38d7d607a74e4281454a68234e4fb48f23c0050f991d3c7901fccc3efd44b5baa languageName: node linkType: hard -"@prisma/fetch-engine@npm:6.19.2": - version: 6.19.2 - resolution: "@prisma/fetch-engine@npm:6.19.2" +"@prisma/fetch-engine@npm:6.19.3": + version: 6.19.3 + resolution: "@prisma/fetch-engine@npm:6.19.3" dependencies: - "@prisma/debug": "npm:6.19.2" + "@prisma/debug": "npm:6.19.3" "@prisma/engines-version": "npm:7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7" - "@prisma/get-platform": "npm:6.19.2" - checksum: 10/fe81ff8af81492a8d7d1f6989b6f3b0c7607474612d9a8849b0a004ad26dd9d05719857f1826d62bea9de89f671e89ed4fdd4af8502a32fbccefcc887e009cce + "@prisma/get-platform": "npm:6.19.3" + checksum: 10/597ed1762da68a52a8b70fd47144ab3cf0d35475a5b93f4d1eec367893d3a607b4b355741ae44a9426b77b0aef0a1c439707e550398653a81e20db17fc634eb3 languageName: node linkType: hard -"@prisma/generator-helper@npm:^7.0.1": - version: 7.3.0 - resolution: "@prisma/generator-helper@npm:7.3.0" +"@prisma/generator-helper@npm:^7.3.0": + version: 7.8.0 + resolution: "@prisma/generator-helper@npm:7.8.0" dependencies: - "@prisma/debug": "npm:7.3.0" - "@prisma/dmmf": "npm:7.3.0" - "@prisma/generator": "npm:7.3.0" - checksum: 10/2411944ad305c957efb6a837108bf2083d83e00c9de4738974eb1b5f718af32ebf1873cd30702370e30ab0f52b402ee18c3b3eec6a923c412cf7dea27af9b7b6 + "@prisma/debug": "npm:7.8.0" + "@prisma/dmmf": "npm:7.8.0" + "@prisma/generator": "npm:7.8.0" + checksum: 10/5271b4204f58f62f0cdc4944b5928a0fc6a0a88b34fa3241c0ee3ab8f15cb642304825292443c8626b01f8f947f0515e95765febda21abd0e26f12ba2be303c5 languageName: node linkType: hard -"@prisma/generator@npm:7.3.0": - version: 7.3.0 - resolution: "@prisma/generator@npm:7.3.0" - checksum: 10/1d7ce5b6b29a1f5788d642f3dbce8d2b5ac0fbe1595e19384234abcafdff1d80d4e186cfdb6beb957f16fcaccdfad77f05e8d202a57224d756dac771c95f8818 +"@prisma/generator@npm:7.8.0": + version: 7.8.0 + resolution: "@prisma/generator@npm:7.8.0" + checksum: 10/1d20eee8e496458a6de246c4355f825fb8c3499b2cef698a2543eee2853034dd55f745b8c68a13e3dc319a4a9458438ac6b8c22d120fcf5775ecbf46242e0e98 languageName: node linkType: hard -"@prisma/get-platform@npm:6.19.2": - version: 6.19.2 - resolution: "@prisma/get-platform@npm:6.19.2" +"@prisma/get-platform@npm:6.19.3": + version: 6.19.3 + resolution: "@prisma/get-platform@npm:6.19.3" dependencies: - "@prisma/debug": "npm:6.19.2" - checksum: 10/6aa7d53d05ec31c80e5fb996637a6b3eec63b4934a44c77f1a0b8721b174e67816b17f65448dcf087d964101d22039dbc8fed6c76a891044444ce18e2bfe7ea1 + "@prisma/debug": "npm:6.19.3" + checksum: 10/53d8f05771f4f8e974f8b6a9a9e58eba0387589c0f2fb2b3f4958499cdccce737f2bda9b0a8a234cf11a20d6e328db5285fbbc93815149b3953ce843dba6da86 languageName: node linkType: hard @@ -2979,27 +2881,26 @@ __metadata: languageName: node linkType: hard -"@protobufjs/codegen@npm:^2.0.4": - version: 2.0.4 - resolution: "@protobufjs/codegen@npm:2.0.4" - checksum: 10/c6ee5fa172a8464f5253174d3c2353ea520c2573ad7b6476983d9b1346f4d8f2b44aa29feb17a949b83c1816bc35286a5ea265ed9d8fdd2865acfa09668c0447 +"@protobufjs/codegen@npm:^2.0.5": + version: 2.0.5 + resolution: "@protobufjs/codegen@npm:2.0.5" + checksum: 10/290335fa114f26202abc0695f279d53e2fd516b01cfd8298923591e0bda011295ff40e3582a1cda0a0f27cbc5039a0292082d5ad08872bb5d6243a614ac15c88 languageName: node linkType: hard -"@protobufjs/eventemitter@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/eventemitter@npm:1.1.0" - checksum: 10/03af3e99f17ad421283d054c88a06a30a615922a817741b43ca1b13e7c6b37820a37f6eba9980fb5150c54dba6e26cb6f7b64a6f7d8afa83596fafb3afa218c3 +"@protobufjs/eventemitter@npm:^1.1.1": + version: 1.1.1 + resolution: "@protobufjs/eventemitter@npm:1.1.1" + checksum: 10/a54dc1aff4475ffad4fdf3235c71a553f5e40e3b4cf6a2e217151895a61cb4eb0be20d63791db22441ca25e594671f1021977133f9939540750231ff7d8e9dd6 languageName: node linkType: hard -"@protobufjs/fetch@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/fetch@npm:1.1.0" +"@protobufjs/fetch@npm:^1.1.1": + version: 1.1.1 + resolution: "@protobufjs/fetch@npm:1.1.1" dependencies: "@protobufjs/aspromise": "npm:^1.1.1" - "@protobufjs/inquire": "npm:^1.1.0" - checksum: 10/67ae40572ad536e4ef94269199f252c024b66e3059850906bdaee161ca1d75c73d04d35cd56f147a8a5a079f5808e342b99e61942c1dae15604ff0600b09a958 + checksum: 10/427cf2da8c69b494b0df3b2fb1f43c97f0f71ca2c8ef8232dac7e44f2527ad0cc9cecb243eda14a918e86018bfa6d54d92252240d2b37ed205b13adb5506fa1d languageName: node linkType: hard @@ -3010,10 +2911,10 @@ __metadata: languageName: node linkType: hard -"@protobufjs/inquire@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/inquire@npm:1.1.0" - checksum: 10/c09efa34a5465cb120775e1a482136f2340a58b4abce7e93d72b8b5a9324a0e879275016ef9fcd73d72a4731639c54f2bb755bb82f916e4a78892d1d840bb3d2 +"@protobufjs/inquire@npm:^1.1.2": + version: 1.1.2 + resolution: "@protobufjs/inquire@npm:1.1.2" + checksum: 10/259756489c75a751552df60d18f82503d2534855646397b96b91cf15807fa852e99bd9eb73dabb64da37aec7913844032ecb031a4326d82aae622f5e4c2f8a17 languageName: node linkType: hard @@ -3031,10 +2932,10 @@ __metadata: languageName: node linkType: hard -"@protobufjs/utf8@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/utf8@npm:1.1.0" - checksum: 10/131e289c57534c1d73a0e55782d6751dd821db1583cb2f7f7e017c9d6747addaebe79f28120b2e0185395d990aad347fb14ffa73ef4096fa38508d61a0e64602 +"@protobufjs/utf8@npm:^1.1.1": + version: 1.1.1 + resolution: "@protobufjs/utf8@npm:1.1.1" + checksum: 10/ed0c3f9ff1afd602a0aed54c4c03a0b8f641686a5587d8949e088dcac653fb2019d15691ed92eef23dfdf9f4293249532d0508ecd15cef810acf026917719a19 languageName: node linkType: hard @@ -3163,10 +3064,126 @@ __metadata: languageName: node linkType: hard -"@rolldown/pluginutils@npm:1.0.0-beta.53": - version: 1.0.0-beta.53 - resolution: "@rolldown/pluginutils@npm:1.0.0-beta.53" - checksum: 10/09dab7cbff3143838310a003ea5e453b219b27d00f34a88efe4c0c4d2540f16d95b770db2be111a424d51947dc3a3598798124e3f3622a99337f7a7c3f6913b2 +"@rolldown/binding-android-arm64@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-android-arm64@npm:1.0.3" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@rolldown/binding-darwin-arm64@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-darwin-arm64@npm:1.0.3" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rolldown/binding-darwin-x64@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-darwin-x64@npm:1.0.3" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rolldown/binding-freebsd-x64@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-freebsd-x64@npm:1.0.3" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.3" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@rolldown/binding-linux-arm64-gnu@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.3" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rolldown/binding-linux-arm64-musl@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.3" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rolldown/binding-linux-ppc64-gnu@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.3" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rolldown/binding-linux-s390x-gnu@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.3" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rolldown/binding-linux-x64-gnu@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.3" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rolldown/binding-linux-x64-musl@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.3" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rolldown/binding-openharmony-arm64@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.3" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@rolldown/binding-wasm32-wasi@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.3" + dependencies: + "@emnapi/core": "npm:1.10.0" + "@emnapi/runtime": "npm:1.10.0" + "@napi-rs/wasm-runtime": "npm:^1.1.4" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@rolldown/binding-win32-arm64-msvc@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.3" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rolldown/binding-win32-x64-msvc@npm:1.0.3": + version: 1.0.3 + resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.3" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rolldown/pluginutils@npm:1.0.0-rc.3": + version: 1.0.0-rc.3 + resolution: "@rolldown/pluginutils@npm:1.0.0-rc.3" + checksum: 10/b181a693b70e0e5de736458d46b31f72862cd7f36f955656f61ccbf4de11d9206bc3b55404317a65e5714559490444e9fdd83b4097706496e96b082fb584d049 + languageName: node + linkType: hard + +"@rolldown/pluginutils@npm:^1.0.0": + version: 1.0.1 + resolution: "@rolldown/pluginutils@npm:1.0.1" + checksum: 10/4e95cf9ce23d75e5aa03ea0249cd86f7d1e21f83fbf6f8520e4edd8a251ba1b82c4ba9bc13cd24b6c4661daec6225b06e6d35c64c604e731b230b2a49af47d05 languageName: node linkType: hard @@ -3220,8 +3237,8 @@ __metadata: linkType: hard "@rollup/pluginutils@npm:^5.1.0": - version: 5.3.0 - resolution: "@rollup/pluginutils@npm:5.3.0" + version: 5.4.0 + resolution: "@rollup/pluginutils@npm:5.4.0" dependencies: "@types/estree": "npm:^1.0.0" estree-walker: "npm:^2.0.2" @@ -3231,356 +3248,181 @@ __metadata: peerDependenciesMeta: rollup: optional: true - checksum: 10/6c7dbab90e0ca5918a36875f745a0f30b47d5e0f45b42ed381ad8f7fed76b23e935766b66e3ae75375a42a80369569913abc8fd2529f4338471a1b2b4dfebaff + checksum: 10/eb1687d52c3847a27c5f6e790ee31a6a356c23e3c16222b4d7cf31d48dfaad2edc13e49355da9f2c59c90c1220cb089b36780cb95dc6d0ee54587f61cc5cf080 languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.56.0" +"@rollup/rollup-android-arm-eabi@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.61.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.59.0" - conditions: os=android & cpu=arm - languageName: node - linkType: hard - -"@rollup/rollup-android-arm64@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-android-arm64@npm:4.56.0" +"@rollup/rollup-android-arm64@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-android-arm64@npm:4.61.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-android-arm64@npm:4.59.0" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - -"@rollup/rollup-darwin-arm64@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-darwin-arm64@npm:4.56.0" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@rollup/rollup-darwin-arm64@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-darwin-arm64@npm:4.59.0" +"@rollup/rollup-darwin-arm64@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.61.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-darwin-x64@npm:4.56.0" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@rollup/rollup-darwin-x64@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-darwin-x64@npm:4.59.0" +"@rollup/rollup-darwin-x64@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.61.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.56.0" - conditions: os=freebsd & cpu=arm64 - languageName: node - linkType: hard - -"@rollup/rollup-freebsd-arm64@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.59.0" +"@rollup/rollup-freebsd-arm64@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.61.0" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-freebsd-x64@npm:4.56.0" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"@rollup/rollup-freebsd-x64@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-freebsd-x64@npm:4.59.0" +"@rollup/rollup-freebsd-x64@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.61.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.56.0" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.61.0" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.59.0" - conditions: os=linux & cpu=arm & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-arm-musleabihf@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.56.0" - conditions: os=linux & cpu=arm & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-linux-arm-musleabihf@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.59.0" +"@rollup/rollup-linux-arm-musleabihf@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.61.0" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.56.0" +"@rollup/rollup-linux-arm64-gnu@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.61.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.59.0" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-arm64-musl@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.56.0" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-linux-arm64-musl@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.59.0" +"@rollup/rollup-linux-arm64-musl@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.61.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-loong64-gnu@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.56.0" +"@rollup/rollup-linux-loong64-gnu@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.61.0" conditions: os=linux & cpu=loong64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-loong64-gnu@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.59.0" - conditions: os=linux & cpu=loong64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-loong64-musl@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-loong64-musl@npm:4.56.0" - conditions: os=linux & cpu=loong64 & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-linux-loong64-musl@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-loong64-musl@npm:4.59.0" +"@rollup/rollup-linux-loong64-musl@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-loong64-musl@npm:4.61.0" conditions: os=linux & cpu=loong64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-ppc64-gnu@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.56.0" +"@rollup/rollup-linux-ppc64-gnu@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.61.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-ppc64-gnu@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.59.0" - conditions: os=linux & cpu=ppc64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-ppc64-musl@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.56.0" - conditions: os=linux & cpu=ppc64 & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-linux-ppc64-musl@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.59.0" +"@rollup/rollup-linux-ppc64-musl@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.61.0" conditions: os=linux & cpu=ppc64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.56.0" +"@rollup/rollup-linux-riscv64-gnu@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.61.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.59.0" - conditions: os=linux & cpu=riscv64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-riscv64-musl@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.56.0" - conditions: os=linux & cpu=riscv64 & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-linux-riscv64-musl@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.59.0" +"@rollup/rollup-linux-riscv64-musl@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.61.0" conditions: os=linux & cpu=riscv64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.56.0" +"@rollup/rollup-linux-s390x-gnu@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.61.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.59.0" - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-x64-gnu@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.56.0" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-x64-gnu@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.59.0" +"@rollup/rollup-linux-x64-gnu@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.61.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.56.0" +"@rollup/rollup-linux-x64-musl@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.61.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.59.0" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-openbsd-x64@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-openbsd-x64@npm:4.56.0" - conditions: os=openbsd & cpu=x64 - languageName: node - linkType: hard - -"@rollup/rollup-openbsd-x64@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-openbsd-x64@npm:4.59.0" +"@rollup/rollup-openbsd-x64@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-openbsd-x64@npm:4.61.0" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-openharmony-arm64@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-openharmony-arm64@npm:4.56.0" +"@rollup/rollup-openharmony-arm64@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-openharmony-arm64@npm:4.61.0" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-openharmony-arm64@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-openharmony-arm64@npm:4.59.0" - conditions: os=openharmony & cpu=arm64 - languageName: node - linkType: hard - -"@rollup/rollup-win32-arm64-msvc@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.56.0" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@rollup/rollup-win32-arm64-msvc@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.59.0" +"@rollup/rollup-win32-arm64-msvc@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.61.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.56.0" +"@rollup/rollup-win32-ia32-msvc@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.61.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.59.0" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@rollup/rollup-win32-x64-gnu@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-win32-x64-gnu@npm:4.56.0" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@rollup/rollup-win32-x64-gnu@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-win32-x64-gnu@npm:4.59.0" +"@rollup/rollup-win32-x64-gnu@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-win32-x64-gnu@npm:4.61.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.56.0": - version: 4.56.0 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.56.0" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@rollup/rollup-win32-x64-msvc@npm:4.59.0": - version: 4.59.0 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.59.0" +"@rollup/rollup-win32-x64-msvc@npm:4.61.0": + version: 4.61.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.61.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -3696,73 +3538,73 @@ __metadata: languageName: node linkType: hard -"@sentry-internal/browser-utils@npm:10.36.0": - version: 10.36.0 - resolution: "@sentry-internal/browser-utils@npm:10.36.0" +"@sentry-internal/browser-utils@npm:10.56.0": + version: 10.56.0 + resolution: "@sentry-internal/browser-utils@npm:10.56.0" dependencies: - "@sentry/core": "npm:10.36.0" - checksum: 10/b96a9e58cae781cad14e591f5a8d348679e41f3355957e66d6f60851dda336b47f8af533e9fe15154005b970f8980eeabaf51c6164b660fd5a649070b0356eb7 + "@sentry/core": "npm:10.56.0" + checksum: 10/7cfadd1a4862089cc076aaaefa251669a3deb34ce497efd8d91efd6b937223a97bc26be110e4667a1b02d6f2f5a681d7fe40cfe814f3d9416b294e3b5383e48c languageName: node linkType: hard -"@sentry-internal/feedback@npm:10.36.0": - version: 10.36.0 - resolution: "@sentry-internal/feedback@npm:10.36.0" +"@sentry-internal/feedback@npm:10.56.0": + version: 10.56.0 + resolution: "@sentry-internal/feedback@npm:10.56.0" dependencies: - "@sentry/core": "npm:10.36.0" - checksum: 10/7055329d833c91f77ce2988ecb78d15a5b3c3148cb916b00a3b4f70d473f4bb11f84854f56bd0733d40e73b58bff3106240c4455e7c4c65a096443a5073a66d1 + "@sentry/core": "npm:10.56.0" + checksum: 10/d2baa354fe79d0949f539d934b29d2d90fd95089fcfc47d0e8538ea305b0380fefe1d56dc1a2903af5d555671f92fd5b930a95a98dd4423d51df0d0c5970a387 languageName: node linkType: hard -"@sentry-internal/replay-canvas@npm:10.36.0": - version: 10.36.0 - resolution: "@sentry-internal/replay-canvas@npm:10.36.0" +"@sentry-internal/replay-canvas@npm:10.56.0": + version: 10.56.0 + resolution: "@sentry-internal/replay-canvas@npm:10.56.0" dependencies: - "@sentry-internal/replay": "npm:10.36.0" - "@sentry/core": "npm:10.36.0" - checksum: 10/4ded8ef7fb5ca0dd7414d22281bfe1b948a69946b2d8af35ce2f598749e3960da3f48fbee18eae356017d9fde5465cf3467fe2994eadb37b2ff11102e52dcb0e + "@sentry-internal/replay": "npm:10.56.0" + "@sentry/core": "npm:10.56.0" + checksum: 10/095473987400689136e7d7765c167158d0a0af878b274b88d67822a8a71feca496aa726cb18d1513f2780677b38619dcbb26f89e2188ed421b0e417873ebcb64 languageName: node linkType: hard -"@sentry-internal/replay@npm:10.36.0": - version: 10.36.0 - resolution: "@sentry-internal/replay@npm:10.36.0" +"@sentry-internal/replay@npm:10.56.0": + version: 10.56.0 + resolution: "@sentry-internal/replay@npm:10.56.0" dependencies: - "@sentry-internal/browser-utils": "npm:10.36.0" - "@sentry/core": "npm:10.36.0" - checksum: 10/7a22486becef94b618cab8dadcb33fb15c0e0b190c6d4c9236293f7948cec83b1b57c0ff87d620685ead878e09777668ae2beaa799adf165a55643f6c38e9bfc + "@sentry-internal/browser-utils": "npm:10.56.0" + "@sentry/core": "npm:10.56.0" + checksum: 10/d42053eb62cbdd2cace99d462f6a304a7f84726212ce6fb0908c8e93145ce0698f530c420c42076f49f8607834e507d71a68e407c29c31a4bdb2a23c14dc569a languageName: node linkType: hard -"@sentry/browser@npm:10.36.0": - version: 10.36.0 - resolution: "@sentry/browser@npm:10.36.0" +"@sentry/browser@npm:10.56.0": + version: 10.56.0 + resolution: "@sentry/browser@npm:10.56.0" dependencies: - "@sentry-internal/browser-utils": "npm:10.36.0" - "@sentry-internal/feedback": "npm:10.36.0" - "@sentry-internal/replay": "npm:10.36.0" - "@sentry-internal/replay-canvas": "npm:10.36.0" - "@sentry/core": "npm:10.36.0" - checksum: 10/ec5cff5a83f6064348daf9a0ff5fc4cf4bf15d510bbc266b78a2aaabe47c6148843fbf5f193f136f6c9a26e176ca5b203bdd3be1e343fa65d92c9ce8a060372d + "@sentry-internal/browser-utils": "npm:10.56.0" + "@sentry-internal/feedback": "npm:10.56.0" + "@sentry-internal/replay": "npm:10.56.0" + "@sentry-internal/replay-canvas": "npm:10.56.0" + "@sentry/core": "npm:10.56.0" + checksum: 10/c032ae937e9510720ef3f552e626c31e27de8f3ee2cfa3eef4000d67c03f95035cc42d7f2503de65a019e4d5fd77092764efff601210e70372ae9811535f8702 languageName: node linkType: hard -"@sentry/core@npm:10.36.0": - version: 10.36.0 - resolution: "@sentry/core@npm:10.36.0" - checksum: 10/eb952172eda4bab238931c473248a22feeb4e0fcfe39408d043ea4409dc29d5f62204577f3fab89635ebb446af41d0ee5f13e2edfb8f1d7b0789f80674e9c534 +"@sentry/core@npm:10.56.0": + version: 10.56.0 + resolution: "@sentry/core@npm:10.56.0" + checksum: 10/ccdfc87928805c6c3468112c302001e8a316a1015a73582d05bb129d7520d9d36447bb982d416e917631a5b90fce998a6325c15efe39a12eb5ff008635cd2f7b languageName: node linkType: hard "@sentry/react@npm:^10.36.0": - version: 10.36.0 - resolution: "@sentry/react@npm:10.36.0" + version: 10.56.0 + resolution: "@sentry/react@npm:10.56.0" dependencies: - "@sentry/browser": "npm:10.36.0" - "@sentry/core": "npm:10.36.0" + "@sentry/browser": "npm:10.56.0" + "@sentry/core": "npm:10.56.0" peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x - checksum: 10/730990d2a87e1f38c1bc2478e45f1a3f2bf72800162dbcfa32ff705bb646619dd2f9d9c7fd925764213dd41ee88f60b983167a507b6c20e9f412a7fe4b66700c + checksum: 10/e69a9ac55c2a1ee6fd0d9cfdc07af2825164e58a78da11fd2a483e7f34add27e434e6bae3a3d0e932038dd461525ff756735f57cefdd1b4a6b11e0b074d51e36 languageName: node linkType: hard @@ -3780,190 +3622,36 @@ __metadata: languageName: node linkType: hard -"@smithy/abort-controller@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/abort-controller@npm:4.2.8" - dependencies: - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/17d5beb1c86227ced459e6abbb03d6a3f205bd6f535a4bca2a10e9b4838292c533be78dbf39cdbf1f8f4af0c2fc3fec2f3081b3d4a1bf4e12a2a2aa52e298173 - languageName: node - linkType: hard - -"@smithy/chunked-blob-reader-native@npm:^4.2.1": - version: 4.2.1 - resolution: "@smithy/chunked-blob-reader-native@npm:4.2.1" - dependencies: - "@smithy/util-base64": "npm:^4.3.0" - tslib: "npm:^2.6.2" - checksum: 10/491cd1fbf74c53cc8c63abef1d9c0e93d1c0773db2c4458d4d3bd08217ea58872e413191b56259fd8081653ee07628e3ffcf7ff594d124378401fc3637794474 - languageName: node - linkType: hard - -"@smithy/chunked-blob-reader@npm:^5.2.0": - version: 5.2.0 - resolution: "@smithy/chunked-blob-reader@npm:5.2.0" - dependencies: - tslib: "npm:^2.6.2" - checksum: 10/c2f3b93343daba9a71e2f00fb93ae527a03c0adb6c6c6e194834bf4a67111e87f0694e2d9dd9b70bca87e9eb9da1d905d4450147e54e4cd27c6703dd98d58e0c - languageName: node - linkType: hard - -"@smithy/config-resolver@npm:^4.4.6": - version: 4.4.6 - resolution: "@smithy/config-resolver@npm:4.4.6" - dependencies: - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-config-provider": "npm:^4.2.0" - "@smithy/util-endpoints": "npm:^3.2.8" - "@smithy/util-middleware": "npm:^4.2.8" - tslib: "npm:^2.6.2" - checksum: 10/6440612a9e9a29b74f3420244f3e416d2c2ff0ed4956af323cd39eb4b8efe22a01e791e8cf465c5b0230a778a825290d6b935e3c6d4ca5a92336b48a2b2b4dbd - languageName: node - linkType: hard - -"@smithy/core@npm:^3.22.0": - version: 3.22.0 - resolution: "@smithy/core@npm:3.22.0" - dependencies: - "@smithy/middleware-serde": "npm:^4.2.9" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-base64": "npm:^4.3.0" - "@smithy/util-body-length-browser": "npm:^4.2.0" - "@smithy/util-middleware": "npm:^4.2.8" - "@smithy/util-stream": "npm:^4.5.10" - "@smithy/util-utf8": "npm:^4.2.0" - "@smithy/uuid": "npm:^1.1.0" - tslib: "npm:^2.6.2" - checksum: 10/2a10318b5503f02777a29c77578977ff427808edb98bb481d5d0ac770b99b662137abc89564f50ef92e4ef0a64366a3da4e9b8cd86ede13e76a694db1b4e6584 - languageName: node - linkType: hard - -"@smithy/credential-provider-imds@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/credential-provider-imds@npm:4.2.8" - dependencies: - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/types": "npm:^4.12.0" - "@smithy/url-parser": "npm:^4.2.8" - tslib: "npm:^2.6.2" - checksum: 10/f0d7abbe28a8244cacf65a453f132e38902e8e912b284b8371165b94ce6ae183acedc430d84ab466ef2d6930867f44d6aeaa4bb877e53a06a8f2dbd42c145d69 - languageName: node - linkType: hard - -"@smithy/eventstream-codec@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/eventstream-codec@npm:4.2.8" +"@smithy/core@npm:^3.24.5, @smithy/core@npm:^3.24.6": + version: 3.24.6 + resolution: "@smithy/core@npm:3.24.6" dependencies: "@aws-crypto/crc32": "npm:5.2.0" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-hex-encoding": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/45e027b320056dc82ce23928a09d29baa5d080c89008874f409c557228923ce216940990bbe53204d8628a0ca4d1e774cbb5aaceb4b5ba6237b89c108ce39a32 - languageName: node - linkType: hard - -"@smithy/eventstream-serde-browser@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/eventstream-serde-browser@npm:4.2.8" - dependencies: - "@smithy/eventstream-serde-universal": "npm:^4.2.8" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/10aef5211bb360b67861f672084a1270caa8b5c1ab5ccbb388d507080387d65b714239e997e8851ec8a38082144ebca316af0db963b1aae15f5160c5c36a1315 - languageName: node - linkType: hard - -"@smithy/eventstream-serde-config-resolver@npm:^4.3.8": - version: 4.3.8 - resolution: "@smithy/eventstream-serde-config-resolver@npm:4.3.8" - dependencies: - "@smithy/types": "npm:^4.12.0" + "@smithy/types": "npm:^4.14.3" tslib: "npm:^2.6.2" - checksum: 10/fbd4b1278c047a7b8bde7181a17c46ee17c93c8d907d54f8122312bed16a6ef835914962746ec4cb11154a09c9eec166e7ffd3bdc65af0a38a62ab7083902418 + checksum: 10/c37a2bc247d19612e6b5cc6ce9dea2436d94b2133869d35711fb4a964e604cb2eec295ea563997a2be237a85430c24eed4c71159cf29d7191fb36ff6787dadb1 languageName: node linkType: hard -"@smithy/eventstream-serde-node@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/eventstream-serde-node@npm:4.2.8" +"@smithy/credential-provider-imds@npm:^4.3.6": + version: 4.3.7 + resolution: "@smithy/credential-provider-imds@npm:4.3.7" dependencies: - "@smithy/eventstream-serde-universal": "npm:^4.2.8" - "@smithy/types": "npm:^4.12.0" + "@smithy/core": "npm:^3.24.6" + "@smithy/types": "npm:^4.14.3" tslib: "npm:^2.6.2" - checksum: 10/603840ac95222293b7b5db6201249b08c2dd9ee343a66fde5a5025b1f3bab130be6b4f6ddd7b657a440b422a2f16868a2f30553eb1a27aafabcf8a0aab1729c9 + checksum: 10/a6a2df442fe5a74fce35d930042798985b8932f71359c57bb0ed18cc16f7e8b85c802845dc2105cc828de86832e219106741ca4824d0169c922c7911e3d72730 languageName: node linkType: hard -"@smithy/eventstream-serde-universal@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/eventstream-serde-universal@npm:4.2.8" +"@smithy/fetch-http-handler@npm:^5.4.5": + version: 5.4.6 + resolution: "@smithy/fetch-http-handler@npm:5.4.6" dependencies: - "@smithy/eventstream-codec": "npm:^4.2.8" - "@smithy/types": "npm:^4.12.0" + "@smithy/core": "npm:^3.24.6" + "@smithy/types": "npm:^4.14.3" tslib: "npm:^2.6.2" - checksum: 10/814366a4184ed28e51edeeee43c46b3a8e7153d1136e0802e86c6ff9143c73bf6137617b67c7763d374ed921d673f54fd950bf0fdc09aebaf07977eeb0c60e63 - languageName: node - linkType: hard - -"@smithy/fetch-http-handler@npm:^5.3.9": - version: 5.3.9 - resolution: "@smithy/fetch-http-handler@npm:5.3.9" - dependencies: - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/querystring-builder": "npm:^4.2.8" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-base64": "npm:^4.3.0" - tslib: "npm:^2.6.2" - checksum: 10/7e350c6a4f49e9c913367791f2fb48bc160ae60ad2a6f314baf384623aed2ee5b50996b4ffcc8ddf8abb0ba9489bb524dedb1769756431c45e3ab7bfc41b7994 - languageName: node - linkType: hard - -"@smithy/hash-blob-browser@npm:^4.2.9": - version: 4.2.9 - resolution: "@smithy/hash-blob-browser@npm:4.2.9" - dependencies: - "@smithy/chunked-blob-reader": "npm:^5.2.0" - "@smithy/chunked-blob-reader-native": "npm:^4.2.1" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/de9641b7b66085e35a2896304216419fb7f073609f12686d7df775b0df8c83066e778a757e664be37c07ed4c2f87cce7754878213a2e4cd6f80cc208e61aa42f - languageName: node - linkType: hard - -"@smithy/hash-node@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/hash-node@npm:4.2.8" - dependencies: - "@smithy/types": "npm:^4.12.0" - "@smithy/util-buffer-from": "npm:^4.2.0" - "@smithy/util-utf8": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/db765b8f338e4109aab1d7032175c74673bfedff10cae2241e91034efa42cf01a657f5c0494ef79fc9d7aa2da9ab01981c64583d0a736baf5e6b3038a69a0c1f - languageName: node - linkType: hard - -"@smithy/hash-stream-node@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/hash-stream-node@npm:4.2.8" - dependencies: - "@smithy/types": "npm:^4.12.0" - "@smithy/util-utf8": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/154583e9f39508aad8250d121bb6810a480db6428319b12a10465b83cc87246c74cbef65ec71953c7a80d626fb55e38506b294d93a082fabf9217be7c7d35cda - languageName: node - linkType: hard - -"@smithy/invalid-dependency@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/invalid-dependency@npm:4.2.8" - dependencies: - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/e1c1d0a654e096f74dfec32e48492075f4d96f7f3694a1c5b530c575e402eb605f381748f321ae7b491b97142d3bfbd55f269b1b3257dcc0d3aa38508e227e2b + checksum: 10/b4f631e68519384ee891a4f29584d63e08c86d9e325d8af551aa2febfc091475630033cb5b4b8c25a9db289a646344c5660877b1841f29acd8ac51084f13ccca languageName: node linkType: hard @@ -3976,253 +3664,34 @@ __metadata: languageName: node linkType: hard -"@smithy/is-array-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "@smithy/is-array-buffer@npm:4.2.0" - dependencies: - tslib: "npm:^2.6.2" - checksum: 10/fdc097ce6a8b241565e2d56460ec289730bcd734dcde17c23d1eaaa0996337f897217166276a3fd82491fe9fd17447aadf62e8d9056b3d2b9daf192b4b668af9 - languageName: node - linkType: hard - -"@smithy/md5-js@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/md5-js@npm:4.2.8" - dependencies: - "@smithy/types": "npm:^4.12.0" - "@smithy/util-utf8": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/bc5478f5918c9c9bb7f6f3b62c2a374b20c3f7e0a01df25edf1f8b0832778a0625d69df50bf01c9434e9d8002561c28bc20a2d151cfc7a89d157a79bd900e199 - languageName: node - linkType: hard - -"@smithy/middleware-content-length@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/middleware-content-length@npm:4.2.8" - dependencies: - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/9077c99f263843d347c847057ba3f7c270a8f71d96018f123fd78f1a0439f076e5ae989e7ce83e158f94b45afc7e8665f67d33e4c2cb66d7bbb88495ae9f1785 - languageName: node - linkType: hard - -"@smithy/middleware-endpoint@npm:^4.4.12": - version: 4.4.12 - resolution: "@smithy/middleware-endpoint@npm:4.4.12" - dependencies: - "@smithy/core": "npm:^3.22.0" - "@smithy/middleware-serde": "npm:^4.2.9" - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/shared-ini-file-loader": "npm:^4.4.3" - "@smithy/types": "npm:^4.12.0" - "@smithy/url-parser": "npm:^4.2.8" - "@smithy/util-middleware": "npm:^4.2.8" - tslib: "npm:^2.6.2" - checksum: 10/cd45ae6da1cb327fe2ff79ca1a5635c43ca6c47cdc42dc3c1103bcfc9b61417d444a8a927bf9a3f440ce7b8390520ccb606d72cd77f361433e4f24c65f94c533 - languageName: node - linkType: hard - -"@smithy/middleware-retry@npm:^4.4.29": - version: 4.4.29 - resolution: "@smithy/middleware-retry@npm:4.4.29" - dependencies: - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/service-error-classification": "npm:^4.2.8" - "@smithy/smithy-client": "npm:^4.11.1" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-middleware": "npm:^4.2.8" - "@smithy/util-retry": "npm:^4.2.8" - "@smithy/uuid": "npm:^1.1.0" - tslib: "npm:^2.6.2" - checksum: 10/a95d40ea5d5c44c9815726b803d742975caa49aafbc9c321af5f1dafc1c3810b38cb2a83791be36ecfae50bb6ddbd9deac1b99fa4b81acbd7a3a2217dbfa9387 - languageName: node - linkType: hard - -"@smithy/middleware-serde@npm:^4.2.9": - version: 4.2.9 - resolution: "@smithy/middleware-serde@npm:4.2.9" +"@smithy/node-http-handler@npm:^4.7.5": + version: 4.7.6 + resolution: "@smithy/node-http-handler@npm:4.7.6" dependencies: - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/types": "npm:^4.12.0" + "@smithy/core": "npm:^3.24.6" + "@smithy/types": "npm:^4.14.3" tslib: "npm:^2.6.2" - checksum: 10/490e9ab6ce6664812e30975d3f24d769c8ba59f153c97a5095516f8fd22ed6d948cd4838cfdb253b020b3ec8914b4ec3cb31f1d6ca84ece7639381d5dec6c463 + checksum: 10/19e0bf31185297d915cd20b8a0e9d8aa360e74f6be2353ca619bc9cf570fa4d4c71efb3f416e6255c9a20db910b75ae55577a176b738b416f5ec586999fe5407 languageName: node linkType: hard -"@smithy/middleware-stack@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/middleware-stack@npm:4.2.8" +"@smithy/signature-v4@npm:^5.4.5": + version: 5.4.6 + resolution: "@smithy/signature-v4@npm:5.4.6" dependencies: - "@smithy/types": "npm:^4.12.0" + "@smithy/core": "npm:^3.24.6" + "@smithy/types": "npm:^4.14.3" tslib: "npm:^2.6.2" - checksum: 10/c4b8dc4e466e31e4adc36a52af5e7f5bdc9adf3cc31e825947a2f73f5e1beb5ef87b72624427e6f3a18951407878d7f0ef33990c210aa7df5143c028f0ef8740 + checksum: 10/bb4ac3ec29e57c86d4ca2e0dd14c1c4b6e0f37d8d4da271107a4ce070f989ce96a0ccf0f2d65f0990149b74fdea86140737e3beb3c93da58f45852cb1ce85e82 languageName: node linkType: hard -"@smithy/node-config-provider@npm:^4.3.8": - version: 4.3.8 - resolution: "@smithy/node-config-provider@npm:4.3.8" - dependencies: - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/shared-ini-file-loader": "npm:^4.4.3" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/e954b98ad121e76174453bf67bf9824b661de61865d3e92e845d6e0656b3d8c41ebc90a176428d3732a14dd8cfe5795644864d17470a5af37599c2c4b3c221fd - languageName: node - linkType: hard - -"@smithy/node-http-handler@npm:^4.4.8": - version: 4.4.8 - resolution: "@smithy/node-http-handler@npm:4.4.8" - dependencies: - "@smithy/abort-controller": "npm:^4.2.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/querystring-builder": "npm:^4.2.8" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/f5df30b2dc307c36a866104c415af2b776ad28821948f4391ae18bd62f66a99886530b0ff9c02f7389bcbda1dcc325f5818d6edf9cf1bea361a81f40892cadac - languageName: node - linkType: hard - -"@smithy/property-provider@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/property-provider@npm:4.2.8" - dependencies: - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/d50f51bf029f72ec3679c7945cbb77f71d53fa5f53a20adcbc0ab25f53587add46d1ed1dd90becb1bdf0c97c9caf7f8a45d868eefe3951a4e68bc3ce5ed1eb29 - languageName: node - linkType: hard - -"@smithy/protocol-http@npm:^5.3.8": - version: 5.3.8 - resolution: "@smithy/protocol-http@npm:5.3.8" - dependencies: - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/6465375d9feff2c2718e5b30d358f3d63f007574b2338c6b08dde11d11a98371697b9ec047455fa71be6ede9770e7e53ee5d9715ed7033dbfb825ec4d029066e - languageName: node - linkType: hard - -"@smithy/querystring-builder@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/querystring-builder@npm:4.2.8" - dependencies: - "@smithy/types": "npm:^4.12.0" - "@smithy/util-uri-escape": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/13bd560936d31f51006174f962260526c21df1cdb821f83cc3f7e6424c1a37f2b6b76a92bef1241174eebbdd5ef06f050752460ad638f7814f23f499e0a847fa - languageName: node - linkType: hard - -"@smithy/querystring-parser@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/querystring-parser@npm:4.2.8" - dependencies: - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/26e5a3fc8d1623980f9a03662b6b2349a4a4e6f0ecb9af4df9f11a2cc83a58d4ef3571d104e5ff1a10973a4e297b3aa8327f261d647ffc6f5ee871008a740580 - languageName: node - linkType: hard - -"@smithy/service-error-classification@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/service-error-classification@npm:4.2.8" - dependencies: - "@smithy/types": "npm:^4.12.0" - checksum: 10/ffcbaa6fa3536642dc03f3c7feb762a3b4acfa5d45ff74e401634f472549fce2608a5b1ebd339de5fc0ba2e0f6296b5fa8e49258cb1b675aa298aed631728542 - languageName: node - linkType: hard - -"@smithy/shared-ini-file-loader@npm:^4.4.3": - version: 4.4.3 - resolution: "@smithy/shared-ini-file-loader@npm:4.4.3" +"@smithy/types@npm:^4.14.2, @smithy/types@npm:^4.14.3": + version: 4.14.3 + resolution: "@smithy/types@npm:4.14.3" dependencies: - "@smithy/types": "npm:^4.12.0" tslib: "npm:^2.6.2" - checksum: 10/70cf7db0e24768d5e6a019de29d194ca4516e9177cbd9cd97ce7800889ee2bd3d8cfd71958d11cd026f79223cb34c64176234443d464cf6146562e0385f7daea - languageName: node - linkType: hard - -"@smithy/signature-v4@npm:^5.3.8": - version: 5.3.8 - resolution: "@smithy/signature-v4@npm:5.3.8" - dependencies: - "@smithy/is-array-buffer": "npm:^4.2.0" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-hex-encoding": "npm:^4.2.0" - "@smithy/util-middleware": "npm:^4.2.8" - "@smithy/util-uri-escape": "npm:^4.2.0" - "@smithy/util-utf8": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/88bd0b507bf1a567519208d5b5fb923142bf63bd9b7bfd8b0d4485a8225a80c4274956770127ef471ace96dbb00f1e0bee0bafeb365c5f5346e5419e6ed882fc - languageName: node - linkType: hard - -"@smithy/smithy-client@npm:^4.11.1": - version: 4.11.1 - resolution: "@smithy/smithy-client@npm:4.11.1" - dependencies: - "@smithy/core": "npm:^3.22.0" - "@smithy/middleware-endpoint": "npm:^4.4.12" - "@smithy/middleware-stack": "npm:^4.2.8" - "@smithy/protocol-http": "npm:^5.3.8" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-stream": "npm:^4.5.10" - tslib: "npm:^2.6.2" - checksum: 10/b72ed4deea2fea948e89b026d319d85380a23bce7a7f6690769a2615ba5d989656a43f6a5aa85dbbb35b1e7d6c3ffab0546fb97daa506b3d87f6b9d929da1f6e - languageName: node - linkType: hard - -"@smithy/types@npm:^4.12.0": - version: 4.12.0 - resolution: "@smithy/types@npm:4.12.0" - dependencies: - tslib: "npm:^2.6.2" - checksum: 10/7fe734b4cae1ae3a5c3f8a0aefae072530026917436a5db699d2e27e3518cde4ba4ffe001ef7c45e4a87a02bdae8eabb67b82e6db80153eaf41776901718aa62 - languageName: node - linkType: hard - -"@smithy/url-parser@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/url-parser@npm:4.2.8" - dependencies: - "@smithy/querystring-parser": "npm:^4.2.8" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/8e99b893502f219e5bd9c17f6f974a433f3e56c6dc899cb753281c7701c19126f202766dcee69c4e5ecb1b941daa68bc5d6ea603dd5121bce0de5135268664d4 - languageName: node - linkType: hard - -"@smithy/util-base64@npm:^4.3.0": - version: 4.3.0 - resolution: "@smithy/util-base64@npm:4.3.0" - dependencies: - "@smithy/util-buffer-from": "npm:^4.2.0" - "@smithy/util-utf8": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/87065ca13e3745858e0bb0ab6374433b258c378ee2a5ef865b74f6a4208c56db7db2b9ee5f888e021de0107fae49e9957662c4c6847fe10529e2f6cc882426b4 - languageName: node - linkType: hard - -"@smithy/util-body-length-browser@npm:^4.2.0": - version: 4.2.0 - resolution: "@smithy/util-body-length-browser@npm:4.2.0" - dependencies: - tslib: "npm:^2.6.2" - checksum: 10/deeb689b52652651c11530a324e07725805533899215ad1f93c5e9a14931443e22b313491a3c2a6d7f61d6dd1e84f9154d0d32de62bf61e0bd8e6ab7bf5f81ed - languageName: node - linkType: hard - -"@smithy/util-body-length-node@npm:^4.2.1": - version: 4.2.1 - resolution: "@smithy/util-body-length-node@npm:4.2.1" - dependencies: - tslib: "npm:^2.6.2" - checksum: 10/efb1333d35120124ec0c751b7b7d5657eb9ad6d0bf6171ff61fde2504639883d36e9562613c70eca623b726193b22601c8ff60e40a8156102d4c5b12fae222f8 + checksum: 10/fd2131c6f9263b139f9ca1cf7c492454809b60fff516cc7c59bc4713c9931c57dcd353746ff5b8f7db4e8458628f3026e3e4af5ccd5bf91250365b23f15f4c78 languageName: node linkType: hard @@ -4236,118 +3705,6 @@ __metadata: languageName: node linkType: hard -"@smithy/util-buffer-from@npm:^4.2.0": - version: 4.2.0 - resolution: "@smithy/util-buffer-from@npm:4.2.0" - dependencies: - "@smithy/is-array-buffer": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/6a81e658554d7123fe089426a840b5e691aee4aa4f0d72b79af19dcf57ccb212dca518acb447714792d48c2dc99bda5e0e823dab05e450ee2393146706d476f9 - languageName: node - linkType: hard - -"@smithy/util-config-provider@npm:^4.2.0": - version: 4.2.0 - resolution: "@smithy/util-config-provider@npm:4.2.0" - dependencies: - tslib: "npm:^2.6.2" - checksum: 10/d65f36401c7a085660cf201a1b317d271e390258b619179fff88248c2db64fc35e6c62fe055f1e55be8935b06eb600379824dabf634fb26d528f54fe60c9d77b - languageName: node - linkType: hard - -"@smithy/util-defaults-mode-browser@npm:^4.3.28": - version: 4.3.28 - resolution: "@smithy/util-defaults-mode-browser@npm:4.3.28" - dependencies: - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/smithy-client": "npm:^4.11.1" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/175aa34d207a66a2fb500a1ef68b8a89455e11410fbb2687eba099efb3ededb505144811ac6ed7df1fe29bce3758bf2c748b1b85f5ee8b6f7d4efef61553ff53 - languageName: node - linkType: hard - -"@smithy/util-defaults-mode-node@npm:^4.2.31": - version: 4.2.31 - resolution: "@smithy/util-defaults-mode-node@npm:4.2.31" - dependencies: - "@smithy/config-resolver": "npm:^4.4.6" - "@smithy/credential-provider-imds": "npm:^4.2.8" - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/property-provider": "npm:^4.2.8" - "@smithy/smithy-client": "npm:^4.11.1" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/fd5a7d8789b898ca9c17805eb44a62e5b81c35dc4b0823e3d68f70ba0a5a605c36a2c4c528259724293735953b64f53f4184de7e34ac642d2a990b05eb979e20 - languageName: node - linkType: hard - -"@smithy/util-endpoints@npm:^3.2.8": - version: 3.2.8 - resolution: "@smithy/util-endpoints@npm:3.2.8" - dependencies: - "@smithy/node-config-provider": "npm:^4.3.8" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/65ea9b1d5abaa944290d6cc4106f74909dafb832616187c17b6c6705f4cb3aa9ea33068595cf161418020a01724716e3c3e1534e78983e92a656f3b85cac02bf - languageName: node - linkType: hard - -"@smithy/util-hex-encoding@npm:^4.2.0": - version: 4.2.0 - resolution: "@smithy/util-hex-encoding@npm:4.2.0" - dependencies: - tslib: "npm:^2.6.2" - checksum: 10/478773d73690e39167b67481116c4fd47cecfc97c3a935d88db9271fb0718627bec1cbc143efbf0cd49d1ac417bde7e76aa74139ea07e365b51e66797f63a45d - languageName: node - linkType: hard - -"@smithy/util-middleware@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/util-middleware@npm:4.2.8" - dependencies: - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/a675f1968ad4a674cc70833be14e8f0e99b09626db9c5764e1d92c76e663d83ba64af4aac5d03112726436cad045cc817d19a71addc5aca6d363b1964ff51d31 - languageName: node - linkType: hard - -"@smithy/util-retry@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/util-retry@npm:4.2.8" - dependencies: - "@smithy/service-error-classification": "npm:^4.2.8" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/c725368bafc63cc54a2fad528d5667998986699ca87c87c30e12354f45008b0664f7d1b2afb0e310190227a1e99aa4c44dcb27e8663431ca3b37659c44ec339b - languageName: node - linkType: hard - -"@smithy/util-stream@npm:^4.5.10": - version: 4.5.10 - resolution: "@smithy/util-stream@npm:4.5.10" - dependencies: - "@smithy/fetch-http-handler": "npm:^5.3.9" - "@smithy/node-http-handler": "npm:^4.4.8" - "@smithy/types": "npm:^4.12.0" - "@smithy/util-base64": "npm:^4.3.0" - "@smithy/util-buffer-from": "npm:^4.2.0" - "@smithy/util-hex-encoding": "npm:^4.2.0" - "@smithy/util-utf8": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/7d8fc4f86fc43edba5124836a7701cacacd65aa0f3a917faba4febcc091055c2be176b3de9bdacbcff5b7e8a97ecd35c66e38fd92743de385fd9774bdbdcc42f - languageName: node - linkType: hard - -"@smithy/util-uri-escape@npm:^4.2.0": - version: 4.2.0 - resolution: "@smithy/util-uri-escape@npm:4.2.0" - dependencies: - tslib: "npm:^2.6.2" - checksum: 10/a838a3afe557d7087d4500735c79d5da72e0cd5a08f95d1a1c450ba29d9cd85c950228eedbd9b2494156f4eb8658afb0a9a5bd2df3fc4f297faed886c396242b - languageName: node - linkType: hard - "@smithy/util-utf8@npm:^2.0.0": version: 2.3.0 resolution: "@smithy/util-utf8@npm:2.3.0" @@ -4358,36 +3715,6 @@ __metadata: languageName: node linkType: hard -"@smithy/util-utf8@npm:^4.2.0": - version: 4.2.0 - resolution: "@smithy/util-utf8@npm:4.2.0" - dependencies: - "@smithy/util-buffer-from": "npm:^4.2.0" - tslib: "npm:^2.6.2" - checksum: 10/d49f58fc6681255eecc3dee39c657b80ef8a4c5617e361bdaf6aaa22f02e378622376153cafc9f0655fb80162e88fc98bbf459f8dd5ba6d7c4b9a59e6eaa05f8 - languageName: node - linkType: hard - -"@smithy/util-waiter@npm:^4.2.8": - version: 4.2.8 - resolution: "@smithy/util-waiter@npm:4.2.8" - dependencies: - "@smithy/abort-controller": "npm:^4.2.8" - "@smithy/types": "npm:^4.12.0" - tslib: "npm:^2.6.2" - checksum: 10/d492ed07fc9b1147660d99b142c4db150d730f2155ba3027363894c97c3d6a539cb69ae6952cf25cb5f79b870e4ce13a30d8fcd7346b3a358d223ae1b080188a - languageName: node - linkType: hard - -"@smithy/uuid@npm:^1.1.0": - version: 1.1.0 - resolution: "@smithy/uuid@npm:1.1.0" - dependencies: - tslib: "npm:^2.6.2" - checksum: 10/fe77b1cebbbf2d541ee2f07eec6d4573af16e08dd3228758f59dcbe85a504112cefe81b971818cf39e2e3fa0ed1fcc61d392cddc50fca13d9dc9bd835e366db0 - languageName: node - linkType: hard - "@socket.io/component-emitter@npm:~3.1.0": version: 3.1.2 resolution: "@socket.io/component-emitter@npm:3.1.2" @@ -4413,141 +3740,109 @@ __metadata: languageName: node linkType: hard -"@solana/accounts@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/accounts@npm:5.4.0" +"@solana/accounts@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/accounts@npm:5.5.1" dependencies: - "@solana/addresses": "npm:5.4.0" - "@solana/codecs-core": "npm:5.4.0" - "@solana/codecs-strings": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" - "@solana/rpc-spec": "npm:5.4.0" - "@solana/rpc-types": "npm:5.4.0" + "@solana/addresses": "npm:5.5.1" + "@solana/codecs-core": "npm:5.5.1" + "@solana/codecs-strings": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" + "@solana/rpc-spec": "npm:5.5.1" + "@solana/rpc-types": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/413bf1ca0c29f0c8b1c8dd81cc5abf208dfa29eecaf63d5564189673fc35ddfa44173feb7b2de0c6111a4c47e46b02b3fd323ad661437b7def4859d73a3bd8bb + checksum: 10/4a40bb46770c310922b0e6752c6e1bda5d7ac73a5bd2071390352190d07d17771a255fb3e6060cbf32b92518514a9a90864a95da6c1a85ecc501604600c9b015 languageName: node linkType: hard -"@solana/addresses@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/addresses@npm:5.4.0" +"@solana/addresses@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/addresses@npm:5.5.1" dependencies: - "@solana/assertions": "npm:5.4.0" - "@solana/codecs-core": "npm:5.4.0" - "@solana/codecs-strings": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" - "@solana/nominal-types": "npm:5.4.0" + "@solana/assertions": "npm:5.5.1" + "@solana/codecs-core": "npm:5.5.1" + "@solana/codecs-strings": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" + "@solana/nominal-types": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/dec3743fc75fbfec13807228ac3328ba4c0dca7fbb3f16604ebaea3336543a1a00f1087ef4b1535894cb1283c5f610e538f27248fbd3b338a599c59bdff4a60a + checksum: 10/a92212c1522b1148d6ea9a0c6ec39cce5321c4c2582b62a60c8b6d0ae786d2dd80bbced7ad9e0f635d52ed0d4e88c6ecef8da2e1ed0937a6010133bf2668e1ad languageName: node linkType: hard -"@solana/assertions@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/assertions@npm:5.4.0" +"@solana/assertions@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/assertions@npm:5.5.1" dependencies: - "@solana/errors": "npm:5.4.0" + "@solana/errors": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/69496f3ed82cb111c273a2c66c05795d8529ebf7c7a28b1bb62ce040b95d612a20420e685025d789e06b41d9d1448d3edcc7c94b555ee6b1868e93d86e19f57b - languageName: node - linkType: hard - -"@solana/buffer-layout@npm:^4.0.1": - version: 4.0.1 - resolution: "@solana/buffer-layout@npm:4.0.1" - dependencies: - buffer: "npm:~6.0.3" - checksum: 10/c64b996b832b2b7966a09e97f501fdd1409fece8975f7fb47698d7b8addb97504360cfb2f3d1368949c643d23ed9a4c9f79e19bbd721ebe5bf229353252f649e + checksum: 10/1c5c2f11abb5d54134fcbf37b837dc3f175107a3d5a8512128cca38f48f03dae23741a071da226e527617853e0ee2e1c1d45a55125eac1a1bfd17934e686ae94 languageName: node linkType: hard -"@solana/codecs-core@npm:2.3.0": - version: 2.3.0 - resolution: "@solana/codecs-core@npm:2.3.0" - dependencies: - "@solana/errors": "npm:2.3.0" - peerDependencies: - typescript: ">=5.3.3" - checksum: 10/d9bba1eaa3ee38fef04e1cbfa43defeea16729a1cf1628a71cb72340558a3f2296279899680e1dda4b1756ab2b280b5f1502330c21c35e167e554f3d0c9d193d - languageName: node - linkType: hard - -"@solana/codecs-core@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/codecs-core@npm:5.4.0" +"@solana/codecs-core@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/codecs-core@npm:5.5.1" dependencies: - "@solana/errors": "npm:5.4.0" + "@solana/errors": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/a69d2baa510ffe26d9217920a001e171dfad6982b0b59c1e52c7497c3179051d7c3e157c93117b97b0b200404596542cf60a6650ea51d5b4cd02c04dca6e1a98 + checksum: 10/cb54ca60d6db18bfc294d64df4bfbf19019508415b6b20c8777f296d06d13014d86fcd65d2e6084091e0b15d15117796942ecd0ffb4ad6b04ad7da94326a0aac languageName: node linkType: hard -"@solana/codecs-data-structures@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/codecs-data-structures@npm:5.4.0" +"@solana/codecs-data-structures@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/codecs-data-structures@npm:5.5.1" dependencies: - "@solana/codecs-core": "npm:5.4.0" - "@solana/codecs-numbers": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" + "@solana/codecs-core": "npm:5.5.1" + "@solana/codecs-numbers": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/22382912c23cd6fe69c1ccd524beeb58c2d68387c318320fdb88a6d7bc76dcc78fe3800288614f4fb3f9505515222963c2348467f84c08604c61ace8c03ba9a7 + checksum: 10/016adffef52ced1ea24442364d4864e35d0efae52b8dd9dd0df5b7d0cee4ff82953039bc263d0f39371b546d7fe91b160141d4e2d179c52787664dfffd3119f8 languageName: node linkType: hard -"@solana/codecs-numbers@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/codecs-numbers@npm:5.4.0" +"@solana/codecs-numbers@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/codecs-numbers@npm:5.5.1" dependencies: - "@solana/codecs-core": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" + "@solana/codecs-core": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/8f3da1e7f16ce8d0a418924d1715359783723987e248e0f900725907f4844289de856aa2d7c19008e589da9d3a7f3e423206e763be1f0fea9afc8b79d8384485 - languageName: node - linkType: hard - -"@solana/codecs-numbers@npm:^2.1.0": - version: 2.3.0 - resolution: "@solana/codecs-numbers@npm:2.3.0" - dependencies: - "@solana/codecs-core": "npm:2.3.0" - "@solana/errors": "npm:2.3.0" - peerDependencies: - typescript: ">=5.3.3" - checksum: 10/e661338b5eb04268a104ff2189b5d001bd2f99e1a3726deaa7157d5acbc3b24740bc25ca03b2028c52ad21fd71d5d5aa64957411c895a9dc1c132aa3bc97b336 + checksum: 10/0ed130b310c42d87c5ebde93537d84fd11d8ad78d138c4c67babe6e1ce616c0d34cbf747903e069e7d28646ceff382e988fdeda36a5039a3e4db0eaf0452809e languageName: node linkType: hard -"@solana/codecs-strings@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/codecs-strings@npm:5.4.0" +"@solana/codecs-strings@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/codecs-strings@npm:5.5.1" dependencies: - "@solana/codecs-core": "npm:5.4.0" - "@solana/codecs-numbers": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" + "@solana/codecs-core": "npm:5.5.1" + "@solana/codecs-numbers": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 typescript: ^5.0.0 @@ -4556,45 +3851,31 @@ __metadata: optional: true typescript: optional: true - checksum: 10/60fc9af52ee17e125eb49f6f24109788a80ded8458ae1adda5c8ec709f3c1d61176f917bfade98349bc6476edb9ef4eb68ef95b1aeb11a0149ca4a59b3a5e84d + checksum: 10/aa2f864f3c973af79d581bcda834a693aad34134faf2431529505e15f1002e817bb1091a67b038aae71d643aa3e90ed4b35f93704c7b5502d41940cab9bd8646 languageName: node linkType: hard -"@solana/codecs@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/codecs@npm:5.4.0" +"@solana/codecs@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/codecs@npm:5.5.1" dependencies: - "@solana/codecs-core": "npm:5.4.0" - "@solana/codecs-data-structures": "npm:5.4.0" - "@solana/codecs-numbers": "npm:5.4.0" - "@solana/codecs-strings": "npm:5.4.0" - "@solana/options": "npm:5.4.0" + "@solana/codecs-core": "npm:5.5.1" + "@solana/codecs-data-structures": "npm:5.5.1" + "@solana/codecs-numbers": "npm:5.5.1" + "@solana/codecs-strings": "npm:5.5.1" + "@solana/options": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/2a30b64c8ed7a249531508285eae1b274e20725ddcffa8356ed357e0c25f72abdad9f83f707b48034b8910dab76ea4287924200b0c439e3fac7b08730bf25646 + checksum: 10/988186858de995a8265c084a28e66275787e25f353c828c2ffba983026476300c4a3d1563a26cef324369f11ba5b1739ece418d1784d185979a7ab6b455b1603 languageName: node linkType: hard -"@solana/errors@npm:2.3.0": - version: 2.3.0 - resolution: "@solana/errors@npm:2.3.0" - dependencies: - chalk: "npm:^5.4.1" - commander: "npm:^14.0.0" - peerDependencies: - typescript: ">=5.3.3" - bin: - errors: bin/cli.mjs - checksum: 10/0e8a329790b7d38b4bfe1fa6ec2ac60be20562a610d992031395fe9886da28b578a9d0aebb318f5357ae0d4cbc8f3d323c12b9520da2cf6adc9038f96afc3fe1 - languageName: node - linkType: hard - -"@solana/errors@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/errors@npm:5.4.0" +"@solana/errors@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/errors@npm:5.5.1" dependencies: chalk: "npm:5.6.2" commander: "npm:14.0.2" @@ -4605,591 +3886,559 @@ __metadata: optional: true bin: errors: bin/cli.mjs - checksum: 10/1fec5f8c3d796c5417f5f958ddaa1aa9db549a9b3363ea4efa15a89f596a62b60667434f5f545606237b651b3d298faea11e8a645349f1ce5d77395727f3a321 + checksum: 10/3301fa66aa6a4423d0ecd305f54e1e8d8cd62351610927a2225ccedacd1d381d8546ab8c1adedebc5bb4807df18d4ee83d8f36afff90b25f059e01c15cb39712 languageName: node linkType: hard -"@solana/fast-stable-stringify@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/fast-stable-stringify@npm:5.4.0" +"@solana/fast-stable-stringify@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/fast-stable-stringify@npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/f7dc4c98a9b417d927eb81cd1523c68c05bcb0a012541402931cb9d17e7a54d81dfb7000229e5f10ae4d34a3f9fa8d86dddc82fa1f3806c7b444145fb8b17463 + checksum: 10/6b5cdbd8982858d2fa56c34adef3beb0776c473b1b540af3ed3fbb7981851707b70e6e980be4b4a033659de5ed2e64bd6ebcdbcaaea7dec31071b969a11fc559 languageName: node linkType: hard -"@solana/functional@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/functional@npm:5.4.0" +"@solana/functional@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/functional@npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/b8f33ed9be5c7def3d27966af6bbcf2e8f72b96a51bca33a98d3bf5be47a0cde994131beb27a948ed867e5e00a7fcb38db88ab24d6e4d36a043c3007bd826125 + checksum: 10/f83328f64684ef775507e4c58e10d8fa762fe96adfaa4e264044e7e9e4321f15da995344e6441078898250d2e29f8d189266bacc129b93acc76d9ef9f37b820e languageName: node linkType: hard -"@solana/instruction-plans@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/instruction-plans@npm:5.4.0" +"@solana/instruction-plans@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/instruction-plans@npm:5.5.1" dependencies: - "@solana/errors": "npm:5.4.0" - "@solana/instructions": "npm:5.4.0" - "@solana/keys": "npm:5.4.0" - "@solana/promises": "npm:5.4.0" - "@solana/transaction-messages": "npm:5.4.0" - "@solana/transactions": "npm:5.4.0" + "@solana/errors": "npm:5.5.1" + "@solana/instructions": "npm:5.5.1" + "@solana/keys": "npm:5.5.1" + "@solana/promises": "npm:5.5.1" + "@solana/transaction-messages": "npm:5.5.1" + "@solana/transactions": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/028a73ce10f492d0e9b1bbf727f3990fddbaefbabb07d1ed273d1efc8b65c28716f8cb50bf603cbb43ac9eecd9f136e10823a38428bd210c5ee2d340809b4df2 + checksum: 10/73d64f3b82a1e8cc903bade66b2ddac37d37a7c43aa07ab9a8d88762d1d293c1e951aa39e9531ea6b72298b56ae95171da023da634d52fd56310490e2664dc0e languageName: node linkType: hard -"@solana/instructions@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/instructions@npm:5.4.0" +"@solana/instructions@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/instructions@npm:5.5.1" dependencies: - "@solana/codecs-core": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" + "@solana/codecs-core": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/4c65f981c51ab1bcdf59a80be1cf403f84aa9ddc4e13a53039ef938a5c030621abe6a5650c69ae9842ee424e376ee16c429523967c8c66ea09c481e8de199666 + checksum: 10/1de7990d121e9bf3487332ddb5ac120a2cd858fe39ef7aeff0b0930f1bfe98e153a515bd0e40c6febd99dca37a6bb4e9bd9ef0ec28e252e74992d859132cb8ea languageName: node linkType: hard -"@solana/keys@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/keys@npm:5.4.0" +"@solana/keys@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/keys@npm:5.5.1" dependencies: - "@solana/assertions": "npm:5.4.0" - "@solana/codecs-core": "npm:5.4.0" - "@solana/codecs-strings": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" - "@solana/nominal-types": "npm:5.4.0" + "@solana/assertions": "npm:5.5.1" + "@solana/codecs-core": "npm:5.5.1" + "@solana/codecs-strings": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" + "@solana/nominal-types": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/c12663ea26263f45441a76b32546c5730d91151f97d003231355c80436b6bcc2472642c26a47fed0867a3172fbc871b874b9249383ba56d18fb431a7b7f156b8 - languageName: node - linkType: hard - -"@solana/kit@npm:^5.1.0": - version: 5.4.0 - resolution: "@solana/kit@npm:5.4.0" - dependencies: - "@solana/accounts": "npm:5.4.0" - "@solana/addresses": "npm:5.4.0" - "@solana/codecs": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" - "@solana/functional": "npm:5.4.0" - "@solana/instruction-plans": "npm:5.4.0" - "@solana/instructions": "npm:5.4.0" - "@solana/keys": "npm:5.4.0" - "@solana/offchain-messages": "npm:5.4.0" - "@solana/plugin-core": "npm:5.4.0" - "@solana/programs": "npm:5.4.0" - "@solana/rpc": "npm:5.4.0" - "@solana/rpc-api": "npm:5.4.0" - "@solana/rpc-parsed-types": "npm:5.4.0" - "@solana/rpc-spec-types": "npm:5.4.0" - "@solana/rpc-subscriptions": "npm:5.4.0" - "@solana/rpc-types": "npm:5.4.0" - "@solana/signers": "npm:5.4.0" - "@solana/sysvars": "npm:5.4.0" - "@solana/transaction-confirmation": "npm:5.4.0" - "@solana/transaction-messages": "npm:5.4.0" - "@solana/transactions": "npm:5.4.0" + checksum: 10/0ad24ee3710c69707e91d461e7aaf557bbfd362a005765a60ad37f0d13529fedb46fe9f2f70e9e569138aa63586e2f88787285f634f27d3ea0dee3c7b33227cf + languageName: node + linkType: hard + +"@solana/kit@npm:^5.5.1": + version: 5.5.1 + resolution: "@solana/kit@npm:5.5.1" + dependencies: + "@solana/accounts": "npm:5.5.1" + "@solana/addresses": "npm:5.5.1" + "@solana/codecs": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" + "@solana/functional": "npm:5.5.1" + "@solana/instruction-plans": "npm:5.5.1" + "@solana/instructions": "npm:5.5.1" + "@solana/keys": "npm:5.5.1" + "@solana/offchain-messages": "npm:5.5.1" + "@solana/plugin-core": "npm:5.5.1" + "@solana/programs": "npm:5.5.1" + "@solana/rpc": "npm:5.5.1" + "@solana/rpc-api": "npm:5.5.1" + "@solana/rpc-parsed-types": "npm:5.5.1" + "@solana/rpc-spec-types": "npm:5.5.1" + "@solana/rpc-subscriptions": "npm:5.5.1" + "@solana/rpc-types": "npm:5.5.1" + "@solana/signers": "npm:5.5.1" + "@solana/sysvars": "npm:5.5.1" + "@solana/transaction-confirmation": "npm:5.5.1" + "@solana/transaction-messages": "npm:5.5.1" + "@solana/transactions": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/7e60da5273d816741c331049cf6c231216a1d96e2e95d3014c1a45592062b52c4e741eaa74ccd91681ae96e3518a18b2a4c6ce8e31e1055ed8dd9bbcefa172c1 + checksum: 10/56a8202f632baa0dc9d8e324d252fcbfb37c46de5154e3c443c219b4603befcad505bbb51d92069385c37a4e77b1403b9f9016e72f779790052acc855fc0954b languageName: node linkType: hard -"@solana/nominal-types@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/nominal-types@npm:5.4.0" +"@solana/nominal-types@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/nominal-types@npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/d6ee40109f78f985a2858278b4841e206d6a090b5b6db731d88c5cb0ac4892da3a12be9a380d171431e53711d3af5a8a740408b76884c7e264864c86ab58cb32 + checksum: 10/49ff6ca222d4a7e70e907756fd5c7a455a3d1ff9ed2450adf4e9df7472fbde656ea3c0b5b10259cbca6c629f373e31311aa916e21c13674bb83e2abfb3dd42e7 languageName: node linkType: hard -"@solana/offchain-messages@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/offchain-messages@npm:5.4.0" +"@solana/offchain-messages@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/offchain-messages@npm:5.5.1" dependencies: - "@solana/addresses": "npm:5.4.0" - "@solana/codecs-core": "npm:5.4.0" - "@solana/codecs-data-structures": "npm:5.4.0" - "@solana/codecs-numbers": "npm:5.4.0" - "@solana/codecs-strings": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" - "@solana/keys": "npm:5.4.0" - "@solana/nominal-types": "npm:5.4.0" + "@solana/addresses": "npm:5.5.1" + "@solana/codecs-core": "npm:5.5.1" + "@solana/codecs-data-structures": "npm:5.5.1" + "@solana/codecs-numbers": "npm:5.5.1" + "@solana/codecs-strings": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" + "@solana/keys": "npm:5.5.1" + "@solana/nominal-types": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/af9fd7ba032e7fba448b20ef3dbb0baae0f73dc5a72bd937998e262fbc72740eaa5f82bf2d82ba280d2d396c7120816f7bdc4dd011fd40e137fae89faf70d8a8 + checksum: 10/ee25dbbee33417bfd431c5c303ebe12e0c188c62916c4f3d55b0a6f95297479a946325c9e076464713f64bcfc80d61afe52fdd230e327eaa659b62ae0305805d languageName: node linkType: hard -"@solana/options@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/options@npm:5.4.0" +"@solana/options@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/options@npm:5.5.1" dependencies: - "@solana/codecs-core": "npm:5.4.0" - "@solana/codecs-data-structures": "npm:5.4.0" - "@solana/codecs-numbers": "npm:5.4.0" - "@solana/codecs-strings": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" + "@solana/codecs-core": "npm:5.5.1" + "@solana/codecs-data-structures": "npm:5.5.1" + "@solana/codecs-numbers": "npm:5.5.1" + "@solana/codecs-strings": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/5d235af74e282a8756ea40725a155f58655e26b32237d3aa70656077efefd0796b8150a0b6c727bb86c9072701a97be0754a26e07b56ebb9616e2fe0e64c3651 + checksum: 10/60a6e9a16e3272665e180add1f120f20a305aca75dce9f795a4d6fbffe042e18a5599594e4ec3676a33c4a6cb860170f4d2e21de0e48177f6ca0b05c9a605e4d languageName: node linkType: hard -"@solana/plugin-core@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/plugin-core@npm:5.4.0" +"@solana/plugin-core@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/plugin-core@npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/123e4367a6243f779217eb8d7f6de8e10ee7f6f853433a8f5acf91593aa310446967c24a9b533225670676404b8d2ca3a2c517679c6423675745452649680f5d + checksum: 10/813c31b9c0d48c7c19c5d66e5c2ac0bfb7d85bb02d6562cf14d3acc731bf3e22f5755a4bc021c60a16c8f8d12098a6da24bd61feae1110469feeac5ff645c9e0 languageName: node linkType: hard -"@solana/programs@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/programs@npm:5.4.0" +"@solana/programs@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/programs@npm:5.5.1" dependencies: - "@solana/addresses": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" + "@solana/addresses": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/01892a1daa55a123ba26406919755b271b1ee7b92d88c68971564d581cd6338be65e7fddb1da775f92f6be2fe2402eaf6fac6a6a421a5122f7507fed746e149b + checksum: 10/061407227a46f2e1966121cb1f95dd3f7f95094cb91d5917b045443b6c68c204a1d062796ce61ea2159ed32dfb77115bcdc19d8edf9d785c7e0cd05d8821dcfc languageName: node linkType: hard -"@solana/promises@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/promises@npm:5.4.0" +"@solana/promises@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/promises@npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/4126047d16cd2b63d52b0e26f91ccd39c7974ecc2e42d40e4cf547756e6eb4c66a4f4d014aa055440ffbfa56eb169ace8dd7d56c037c2fdfaee34561f2685129 + checksum: 10/f35057fa40885596688e4762260e8835ac22945e8978d99ee7ef448d412494922ec4f032c4befd3d8a46c0ea6ee1e515bae01c971ca3efd0fd1f840dac01a66b languageName: node linkType: hard -"@solana/rpc-api@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/rpc-api@npm:5.4.0" - dependencies: - "@solana/addresses": "npm:5.4.0" - "@solana/codecs-core": "npm:5.4.0" - "@solana/codecs-strings": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" - "@solana/keys": "npm:5.4.0" - "@solana/rpc-parsed-types": "npm:5.4.0" - "@solana/rpc-spec": "npm:5.4.0" - "@solana/rpc-transformers": "npm:5.4.0" - "@solana/rpc-types": "npm:5.4.0" - "@solana/transaction-messages": "npm:5.4.0" - "@solana/transactions": "npm:5.4.0" +"@solana/rpc-api@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/rpc-api@npm:5.5.1" + dependencies: + "@solana/addresses": "npm:5.5.1" + "@solana/codecs-core": "npm:5.5.1" + "@solana/codecs-strings": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" + "@solana/keys": "npm:5.5.1" + "@solana/rpc-parsed-types": "npm:5.5.1" + "@solana/rpc-spec": "npm:5.5.1" + "@solana/rpc-transformers": "npm:5.5.1" + "@solana/rpc-types": "npm:5.5.1" + "@solana/transaction-messages": "npm:5.5.1" + "@solana/transactions": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/e28bd233c211c2aeb68b79ed01ca9daa1e037fbce611d7d9aa9ed256e6c568a46b5c4d92548c742babd701df3c34dd3785d06b06dfa534634344689b86e02a0f + checksum: 10/c2197acc9ad02206c09816663aa580aa4b1cf47fefb0f4a137f90228ff88258c923edf6e1806dc0f4138fa435e0650fa19278fe52e9fdd097d4b54c13ca6e3d5 languageName: node linkType: hard -"@solana/rpc-parsed-types@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/rpc-parsed-types@npm:5.4.0" +"@solana/rpc-parsed-types@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/rpc-parsed-types@npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/574a662dcbf7b08e707e59aabba4aa6756167fc53d19d4ceee8b170867d2f94350e67b81738cdbf25e8684e4eee0757d3fd3403761eb3c3f8acccc02c0dc1056 + checksum: 10/ea23e549a23c5c36b94f06c784ac6b02ae5a853c8cb3410c4286816855c33d14cecc2c4cc820aeaa0bddfa210bcc42fb5c61f7945b82a84f22074e4faa334469 languageName: node linkType: hard -"@solana/rpc-spec-types@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/rpc-spec-types@npm:5.4.0" +"@solana/rpc-spec-types@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/rpc-spec-types@npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/461dc18577442b4b88f14508356d499f616bee68b469d1cdcad11b8a2e20c651271ce512f01f0037fb4b0cd42abd27aedee6ef8dee152663cd8c0233fc51d074 + checksum: 10/2185ce7cfc7fe6de75e8e12a6f7e1958590151d6508a795135aa35e3e291c3665ea78154877db10c8094788983b1c42120e5b4c2134ae95afe89a23847d2c2c1 languageName: node linkType: hard -"@solana/rpc-spec@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/rpc-spec@npm:5.4.0" +"@solana/rpc-spec@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/rpc-spec@npm:5.5.1" dependencies: - "@solana/errors": "npm:5.4.0" - "@solana/rpc-spec-types": "npm:5.4.0" + "@solana/errors": "npm:5.5.1" + "@solana/rpc-spec-types": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/8f5bbd8146deed140d5e01e01afb6cafca2657240aae731f6053af708dc0bef82b80cfe3254b4a859f1b37386d3ca904a6ede5ad074b5a383d75b7d8c320cf12 + checksum: 10/55a5090b249cc11a3a8919e88a111d02202c490a0de5982c04f76aa0f0c57156f0102994afd9a1946ebb1656a07a657c18616a98ad993149d9a51b1fdcdfa21b languageName: node linkType: hard -"@solana/rpc-subscriptions-api@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/rpc-subscriptions-api@npm:5.4.0" +"@solana/rpc-subscriptions-api@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/rpc-subscriptions-api@npm:5.5.1" dependencies: - "@solana/addresses": "npm:5.4.0" - "@solana/keys": "npm:5.4.0" - "@solana/rpc-subscriptions-spec": "npm:5.4.0" - "@solana/rpc-transformers": "npm:5.4.0" - "@solana/rpc-types": "npm:5.4.0" - "@solana/transaction-messages": "npm:5.4.0" - "@solana/transactions": "npm:5.4.0" + "@solana/addresses": "npm:5.5.1" + "@solana/keys": "npm:5.5.1" + "@solana/rpc-subscriptions-spec": "npm:5.5.1" + "@solana/rpc-transformers": "npm:5.5.1" + "@solana/rpc-types": "npm:5.5.1" + "@solana/transaction-messages": "npm:5.5.1" + "@solana/transactions": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/8e430e7acde81860c251a8030904edbc1db47e39c120cf74c762093985b6b35caf8947d9412992551701a20219d9010ccb82161ce6648f35242273211f2e841d + checksum: 10/d7abfa7065d681afe3b798156ef6ee0f3cfc4cf72eb46a52c1f85a28da642eacce8c42046e4d88db05e7437dc3b8fa3915fe0bdef852d28874a0f0e233ecebdd languageName: node linkType: hard -"@solana/rpc-subscriptions-channel-websocket@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/rpc-subscriptions-channel-websocket@npm:5.4.0" +"@solana/rpc-subscriptions-channel-websocket@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/rpc-subscriptions-channel-websocket@npm:5.5.1" dependencies: - "@solana/errors": "npm:5.4.0" - "@solana/functional": "npm:5.4.0" - "@solana/rpc-subscriptions-spec": "npm:5.4.0" - "@solana/subscribable": "npm:5.4.0" + "@solana/errors": "npm:5.5.1" + "@solana/functional": "npm:5.5.1" + "@solana/rpc-subscriptions-spec": "npm:5.5.1" + "@solana/subscribable": "npm:5.5.1" ws: "npm:^8.19.0" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/780d018f37eaebd24ebb33d1c92de84195b3c75700998081d40cff1fd65d4621264b438b2ef965a422f98cb72379cbe0d9e34f327649564a0164aa91c387d0de + checksum: 10/f9cd4c7786ec07c21f917a227aa46aa804722d9a0ecaab13e8b539627f84f374fb3b3f98304065219ad78ba7be67b8a05136761701ce9cd48f90aa4607a8560e languageName: node linkType: hard -"@solana/rpc-subscriptions-spec@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/rpc-subscriptions-spec@npm:5.4.0" +"@solana/rpc-subscriptions-spec@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/rpc-subscriptions-spec@npm:5.5.1" dependencies: - "@solana/errors": "npm:5.4.0" - "@solana/promises": "npm:5.4.0" - "@solana/rpc-spec-types": "npm:5.4.0" - "@solana/subscribable": "npm:5.4.0" + "@solana/errors": "npm:5.5.1" + "@solana/promises": "npm:5.5.1" + "@solana/rpc-spec-types": "npm:5.5.1" + "@solana/subscribable": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/ad5426e69f1199278863603658061d39e9db09ba42638a635c7d77a3f5d06a342c02102b2c05fff8fa1dab099162710a903e61259dd8ef37ee19a412c97db0d3 + checksum: 10/c0defd70a9d228f9277a19d87cd60f6a430d83298f5422155d5c198d41dd6d033005f79b7b8f1037f09c9ddd87c559f314e5f4f6fd1fac3406966ff30cbe6c60 languageName: node linkType: hard -"@solana/rpc-subscriptions@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/rpc-subscriptions@npm:5.4.0" - dependencies: - "@solana/errors": "npm:5.4.0" - "@solana/fast-stable-stringify": "npm:5.4.0" - "@solana/functional": "npm:5.4.0" - "@solana/promises": "npm:5.4.0" - "@solana/rpc-spec-types": "npm:5.4.0" - "@solana/rpc-subscriptions-api": "npm:5.4.0" - "@solana/rpc-subscriptions-channel-websocket": "npm:5.4.0" - "@solana/rpc-subscriptions-spec": "npm:5.4.0" - "@solana/rpc-transformers": "npm:5.4.0" - "@solana/rpc-types": "npm:5.4.0" - "@solana/subscribable": "npm:5.4.0" - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10/fb4798eb4172167c050c1cad52990f05243e2856e8e1291b8e1506c803d7d56ed4062135a061e35432d36ca2942ebe786998161dbc101e86d9ca5226da329406 - languageName: node - linkType: hard - -"@solana/rpc-transformers@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/rpc-transformers@npm:5.4.0" +"@solana/rpc-subscriptions@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/rpc-subscriptions@npm:5.5.1" dependencies: - "@solana/errors": "npm:5.4.0" - "@solana/functional": "npm:5.4.0" - "@solana/nominal-types": "npm:5.4.0" - "@solana/rpc-spec-types": "npm:5.4.0" - "@solana/rpc-types": "npm:5.4.0" + "@solana/errors": "npm:5.5.1" + "@solana/fast-stable-stringify": "npm:5.5.1" + "@solana/functional": "npm:5.5.1" + "@solana/promises": "npm:5.5.1" + "@solana/rpc-spec-types": "npm:5.5.1" + "@solana/rpc-subscriptions-api": "npm:5.5.1" + "@solana/rpc-subscriptions-channel-websocket": "npm:5.5.1" + "@solana/rpc-subscriptions-spec": "npm:5.5.1" + "@solana/rpc-transformers": "npm:5.5.1" + "@solana/rpc-types": "npm:5.5.1" + "@solana/subscribable": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/8a81ebed02a9f8989e673c5ee24219b279f3e7b0e56cc25b499b3137c6794740dad8b3db8622ea990fd1e51823cb1954335a012a893b75a32baebbf680f11217 + checksum: 10/be9e516fa95859ac89eecb9314a36e404d5de43e9ae5846793097b1e8725f73c8ed20bae36ff89e743d50b00023b3e8397d188a93246ffd4dd319970a9575e58 languageName: node linkType: hard -"@solana/rpc-transport-http@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/rpc-transport-http@npm:5.4.0" +"@solana/rpc-transformers@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/rpc-transformers@npm:5.5.1" dependencies: - "@solana/errors": "npm:5.4.0" - "@solana/rpc-spec": "npm:5.4.0" - "@solana/rpc-spec-types": "npm:5.4.0" - undici-types: "npm:^7.18.2" + "@solana/errors": "npm:5.5.1" + "@solana/functional": "npm:5.5.1" + "@solana/nominal-types": "npm:5.5.1" + "@solana/rpc-spec-types": "npm:5.5.1" + "@solana/rpc-types": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/466d3c5762afce147add76b4d54b4188ad2cec9c9ae651d6395ab545a3fb591ea4cbb8a8d5ed21c680ec4d5c944ab7e7bfc9cbadffbe0b0f0db39c812200702c + checksum: 10/ad89b40b5a0ef1e903d89598b995b81d49783c007ea12bb78b770e6136d6366c11c45dded4ad295c8bffab95031296995c02eef8950f051524eb5770a70d8f9a languageName: node linkType: hard -"@solana/rpc-types@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/rpc-types@npm:5.4.0" +"@solana/rpc-transport-http@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/rpc-transport-http@npm:5.5.1" dependencies: - "@solana/addresses": "npm:5.4.0" - "@solana/codecs-core": "npm:5.4.0" - "@solana/codecs-numbers": "npm:5.4.0" - "@solana/codecs-strings": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" - "@solana/nominal-types": "npm:5.4.0" + "@solana/errors": "npm:5.5.1" + "@solana/rpc-spec": "npm:5.5.1" + "@solana/rpc-spec-types": "npm:5.5.1" + undici-types: "npm:^7.19.2" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/9760b3ab51f3d9fee67eaaf18d85b854df82eb4a95255f61e9ff4c52fe42c3c973c5375bc42e3800426d3eb216ec7624e1ec0cbcd15ecce1c6c17d920e11da96 + checksum: 10/22bdd410e81ed9140d5cdfa56a794bfc53b2bafb59af59e0107fbff06c5fb805fde9bf26142b7960112c1e6ae8a09a444b43326dedba0980d0c6a8b1a6ac729b languageName: node linkType: hard -"@solana/rpc@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/rpc@npm:5.4.0" - dependencies: - "@solana/errors": "npm:5.4.0" - "@solana/fast-stable-stringify": "npm:5.4.0" - "@solana/functional": "npm:5.4.0" - "@solana/rpc-api": "npm:5.4.0" - "@solana/rpc-spec": "npm:5.4.0" - "@solana/rpc-spec-types": "npm:5.4.0" - "@solana/rpc-transformers": "npm:5.4.0" - "@solana/rpc-transport-http": "npm:5.4.0" - "@solana/rpc-types": "npm:5.4.0" +"@solana/rpc-types@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/rpc-types@npm:5.5.1" + dependencies: + "@solana/addresses": "npm:5.5.1" + "@solana/codecs-core": "npm:5.5.1" + "@solana/codecs-numbers": "npm:5.5.1" + "@solana/codecs-strings": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" + "@solana/nominal-types": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/2c56ce06bb5ab3ebf4775744ecb87ec78e3fdbcefbf74814ecbdae58404bfce85c7e50e1dec211d7f3f0ccb280125e4f3281e732a330e5c2b6c62aed662c0a67 + checksum: 10/44b9503362a177fefdf6f4afac5be11599e5937c7ee87d0cf2254a6fc6624a4a6132af49fb37b42507b863cbb5428b0a2969eb732532f2075aa67a10ab372793 languageName: node linkType: hard -"@solana/signers@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/signers@npm:5.4.0" - dependencies: - "@solana/addresses": "npm:5.4.0" - "@solana/codecs-core": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" - "@solana/instructions": "npm:5.4.0" - "@solana/keys": "npm:5.4.0" - "@solana/nominal-types": "npm:5.4.0" - "@solana/offchain-messages": "npm:5.4.0" - "@solana/transaction-messages": "npm:5.4.0" - "@solana/transactions": "npm:5.4.0" +"@solana/rpc@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/rpc@npm:5.5.1" + dependencies: + "@solana/errors": "npm:5.5.1" + "@solana/fast-stable-stringify": "npm:5.5.1" + "@solana/functional": "npm:5.5.1" + "@solana/rpc-api": "npm:5.5.1" + "@solana/rpc-spec": "npm:5.5.1" + "@solana/rpc-spec-types": "npm:5.5.1" + "@solana/rpc-transformers": "npm:5.5.1" + "@solana/rpc-transport-http": "npm:5.5.1" + "@solana/rpc-types": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/660d6a6dd4b71538a772f06410ee28dcd9b005febc289c7f09dfe935c24807915cc289a6ccdd0abee1403e80b4edae9c5597e74aa198ed8f0a74a87f4443ecee + checksum: 10/a7958d98f3358031a7fb19695d1f09d3bc0414ffce7568f241b20a065f6741b93dd05724510f88cc078b99cea03bd4817ca3401e46fe11c1df7a99e1e69720aa languageName: node linkType: hard -"@solana/subscribable@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/subscribable@npm:5.4.0" +"@solana/signers@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/signers@npm:5.5.1" dependencies: - "@solana/errors": "npm:5.4.0" + "@solana/addresses": "npm:5.5.1" + "@solana/codecs-core": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" + "@solana/instructions": "npm:5.5.1" + "@solana/keys": "npm:5.5.1" + "@solana/nominal-types": "npm:5.5.1" + "@solana/offchain-messages": "npm:5.5.1" + "@solana/transaction-messages": "npm:5.5.1" + "@solana/transactions": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/7008596fd17cd4a862ec33c6e7a5ef925befaa5acd025f73155e30b7d587fee0a2f11de03bc57910447ac3c3f47a3b52a0d84a5c3d6b94e6682432b0d06b0a2b + checksum: 10/a7f1bbd60f86908718e0a4f8cc3264e879553afd5583893ce6907b036617aaed56fa036b2923b8f4fd82d9edec49b7365c4f4d0b9cf939af385e5e04b04b6b73 languageName: node linkType: hard -"@solana/sysvars@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/sysvars@npm:5.4.0" +"@solana/subscribable@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/subscribable@npm:5.5.1" dependencies: - "@solana/accounts": "npm:5.4.0" - "@solana/codecs": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" - "@solana/rpc-types": "npm:5.4.0" + "@solana/errors": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/833324703ab258c457bcad27ac8d698f551ebb3ec42ca04398829bf661588bb197ceb6d9e02d6d405c9bd08639e8f4bcc48961e9115016db55ba740de413452c + checksum: 10/412eb11cb9dba1218fefdfbaeb3464efdbe58628fa57f6b0b4747adcdae8140da5623dc687d1a9fe206d402eee4ffc6152f0d987f3eed8a39f3be56aa54bed32 languageName: node linkType: hard -"@solana/transaction-confirmation@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/transaction-confirmation@npm:5.4.0" - dependencies: - "@solana/addresses": "npm:5.4.0" - "@solana/codecs-strings": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" - "@solana/keys": "npm:5.4.0" - "@solana/promises": "npm:5.4.0" - "@solana/rpc": "npm:5.4.0" - "@solana/rpc-subscriptions": "npm:5.4.0" - "@solana/rpc-types": "npm:5.4.0" - "@solana/transaction-messages": "npm:5.4.0" - "@solana/transactions": "npm:5.4.0" +"@solana/sysvars@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/sysvars@npm:5.5.1" + dependencies: + "@solana/accounts": "npm:5.5.1" + "@solana/codecs": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" + "@solana/rpc-types": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/142161fbd3f116924e2fbcacec76317ae15c650bcb85ae5908d0b5cead23c9a43e878ff23fffabf72b5a26bbc5b31789661c86dac60b167cd9aa72b057a51d64 + checksum: 10/eca4894e5d0ee0e1a2b2fdf8fa79c5abbd043f2072f8ae06c3856a5c9b572a28aec9885222e91fad79da48a927b2324cfe23f2caee69f26fe900b824954040aa languageName: node linkType: hard -"@solana/transaction-messages@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/transaction-messages@npm:5.4.0" - dependencies: - "@solana/addresses": "npm:5.4.0" - "@solana/codecs-core": "npm:5.4.0" - "@solana/codecs-data-structures": "npm:5.4.0" - "@solana/codecs-numbers": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" - "@solana/functional": "npm:5.4.0" - "@solana/instructions": "npm:5.4.0" - "@solana/nominal-types": "npm:5.4.0" - "@solana/rpc-types": "npm:5.4.0" +"@solana/transaction-confirmation@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/transaction-confirmation@npm:5.5.1" + dependencies: + "@solana/addresses": "npm:5.5.1" + "@solana/codecs-strings": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" + "@solana/keys": "npm:5.5.1" + "@solana/promises": "npm:5.5.1" + "@solana/rpc": "npm:5.5.1" + "@solana/rpc-subscriptions": "npm:5.5.1" + "@solana/rpc-types": "npm:5.5.1" + "@solana/transaction-messages": "npm:5.5.1" + "@solana/transactions": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/6331d89f4a15a029be921907ee900b381434b2ca731c107836b089998dd836c0800bc7f0ad9de268ed683b5f2c7e509a6c9c6377bdba2b60f70cef7941a1a8af + checksum: 10/859aad5b9090d31ef09e2156b9cffb6d7f41af50d8648c4357500e658b2e13a265de60e8a5f5940979a3ca44df2513d5a5544d81b2b15fb61fe04df97dcec587 languageName: node linkType: hard -"@solana/transactions@npm:5.4.0": - version: 5.4.0 - resolution: "@solana/transactions@npm:5.4.0" - dependencies: - "@solana/addresses": "npm:5.4.0" - "@solana/codecs-core": "npm:5.4.0" - "@solana/codecs-data-structures": "npm:5.4.0" - "@solana/codecs-numbers": "npm:5.4.0" - "@solana/codecs-strings": "npm:5.4.0" - "@solana/errors": "npm:5.4.0" - "@solana/functional": "npm:5.4.0" - "@solana/instructions": "npm:5.4.0" - "@solana/keys": "npm:5.4.0" - "@solana/nominal-types": "npm:5.4.0" - "@solana/rpc-types": "npm:5.4.0" - "@solana/transaction-messages": "npm:5.4.0" +"@solana/transaction-messages@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/transaction-messages@npm:5.5.1" + dependencies: + "@solana/addresses": "npm:5.5.1" + "@solana/codecs-core": "npm:5.5.1" + "@solana/codecs-data-structures": "npm:5.5.1" + "@solana/codecs-numbers": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" + "@solana/functional": "npm:5.5.1" + "@solana/instructions": "npm:5.5.1" + "@solana/nominal-types": "npm:5.5.1" + "@solana/rpc-types": "npm:5.5.1" peerDependencies: typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/68cc414a0fa13fb56429c27b884f9f1a26c3e6860b5c73444491c78f729b51d31b5c6a13d2ab587e963e491b76a81749a972649acf01c74bbf088c5597b990f8 + checksum: 10/07c1a7d2386a63d908adc1d231d62867ae8685dc8c43561f3d9f7a022e3080d5e14c107baf437cb2e2126dbbc0e260711cf5426097f2e7769a3bed4ae92e897e languageName: node linkType: hard -"@solana/web3.js@npm:^1.98.1": - version: 1.98.4 - resolution: "@solana/web3.js@npm:1.98.4" +"@solana/transactions@npm:5.5.1": + version: 5.5.1 + resolution: "@solana/transactions@npm:5.5.1" dependencies: - "@babel/runtime": "npm:^7.25.0" - "@noble/curves": "npm:^1.4.2" - "@noble/hashes": "npm:^1.4.0" - "@solana/buffer-layout": "npm:^4.0.1" - "@solana/codecs-numbers": "npm:^2.1.0" - agentkeepalive: "npm:^4.5.0" - bn.js: "npm:^5.2.1" - borsh: "npm:^0.7.0" - bs58: "npm:^4.0.1" - buffer: "npm:6.0.3" - fast-stable-stringify: "npm:^1.0.0" - jayson: "npm:^4.1.1" - node-fetch: "npm:^2.7.0" - rpc-websockets: "npm:^9.0.2" - superstruct: "npm:^2.0.2" - checksum: 10/cd7cc9c989b704d8af73d622823147f936329b76440f0b4fb12372f5b5904f5033bb8a16e03924360c627c828703156cd8d544281fad818569068ed10debd17c + "@solana/addresses": "npm:5.5.1" + "@solana/codecs-core": "npm:5.5.1" + "@solana/codecs-data-structures": "npm:5.5.1" + "@solana/codecs-numbers": "npm:5.5.1" + "@solana/codecs-strings": "npm:5.5.1" + "@solana/errors": "npm:5.5.1" + "@solana/functional": "npm:5.5.1" + "@solana/instructions": "npm:5.5.1" + "@solana/keys": "npm:5.5.1" + "@solana/nominal-types": "npm:5.5.1" + "@solana/rpc-types": "npm:5.5.1" + "@solana/transaction-messages": "npm:5.5.1" + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/37dfbcd0f234b97a37823f2096694322428a0dbbe96d72c8940d2758928d56859d0a744e53b1a905b9aa8665850636d7155c344e09bbfd4e4f395fcb5b55cc29 languageName: node linkType: hard -"@standard-schema/spec@npm:^1.0.0": +"@standard-schema/spec@npm:^1.0.0, @standard-schema/spec@npm:^1.1.0": version: 1.1.0 resolution: "@standard-schema/spec@npm:1.1.0" checksum: 10/a209615c9e8b2ea535d7db0a5f6aa0f962fd4ab73ee86a46c100fb78116964af1f55a27c1794d4801e534a196794223daa25ff5135021e03c7828aa3d95e1763 languageName: node linkType: hard -"@swc/helpers@npm:^0.5.11": - version: 0.5.18 - resolution: "@swc/helpers@npm:0.5.18" - dependencies: - tslib: "npm:^2.8.0" - checksum: 10/03c7efa3e62d965fddd0baea98ee7a4c3ba7fa58187f07f26ec8d86740572f5ffd6f7517578a1d3201f64c85399be1538eba4dd30cef79d073060ecb101d753c - languageName: node - linkType: hard - "@szmarczak/http-timer@npm:^5.0.1": version: 5.0.1 resolution: "@szmarczak/http-timer@npm:5.0.1" @@ -5199,70 +4448,40 @@ __metadata: languageName: node linkType: hard -"@tanstack/query-core@npm:5.90.20": - version: 5.90.20 - resolution: "@tanstack/query-core@npm:5.90.20" - checksum: 10/25e38f4382442bc15e0f6cce8d787e9df8d8822c61d3f3e9427e89e01b1e2506f848292e086dae29aeb55f8ce71b097c34221f3c5eda37fb4a688b5ceca5d1b3 +"@tanstack/query-core@npm:5.100.14": + version: 5.100.14 + resolution: "@tanstack/query-core@npm:5.100.14" + checksum: 10/76018531e06a94bb7d7b7f766ae223b43cdb11528689fd54fd29e19e247ed4233ab66caf360e9fd5ebd5116e7239292bc5ba109bb657e381fe6e7888250aa3fe languageName: node linkType: hard "@tanstack/react-query@npm:^5.90.20": - version: 5.90.20 - resolution: "@tanstack/react-query@npm:5.90.20" + version: 5.100.14 + resolution: "@tanstack/react-query@npm:5.100.14" dependencies: - "@tanstack/query-core": "npm:5.90.20" + "@tanstack/query-core": "npm:5.100.14" peerDependencies: react: ^18 || ^19 - checksum: 10/ac98af011078717f4ee754f687b434a9396d05dc17a6b0dd80048c56a1081da921adf81aa48ccb92eaca80f06db6d28497ce4adfaebd5e01b16effd1e5f4ff85 + checksum: 10/985bb0fe1b90510c2fdc1d771fa6da65a883762cc5b97501d5c5ae9cf76bccbe7c7781e446c6ec601e7f8e01fd25ce83e4feb5cc72a87f76952f0092f010e6c1 languageName: node linkType: hard "@tanstack/react-virtual@npm:^3.13.18": - version: 3.13.18 - resolution: "@tanstack/react-virtual@npm:3.13.18" + version: 3.14.2 + resolution: "@tanstack/react-virtual@npm:3.14.2" dependencies: - "@tanstack/virtual-core": "npm:3.13.18" + "@tanstack/virtual-core": "npm:3.17.0" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10/73dcfd5681db1c07834c9d286a7d2194ebded84f09466b37072c630bad1ec9d546c0b58981e8a4cf855b0bd6a5c53c64834c6428022fe12096ff3a905da2a4a4 - languageName: node - linkType: hard - -"@tanstack/virtual-core@npm:3.13.18": - version: 3.13.18 - resolution: "@tanstack/virtual-core@npm:3.13.18" - checksum: 10/b891eac7bfa1bc20a353f65e12d6863c1ff8f91ad763f5ebbd624887c286f4b3ec5664b0c1426270463765802e514792d6864b95076e4087735b28d7db0461f0 - languageName: node - linkType: hard - -"@testing-library/dom@npm:^10.4.1": - version: 10.4.1 - resolution: "@testing-library/dom@npm:10.4.1" - dependencies: - "@babel/code-frame": "npm:^7.10.4" - "@babel/runtime": "npm:^7.12.5" - "@types/aria-query": "npm:^5.0.1" - aria-query: "npm:5.3.0" - dom-accessibility-api: "npm:^0.5.9" - lz-string: "npm:^1.5.0" - picocolors: "npm:1.1.1" - pretty-format: "npm:^27.0.2" - checksum: 10/7f93e09ea015f151f8b8f42cbab0b2b858999b5445f15239a72a612ef7716e672b14c40c421218194cf191cbecbde0afa6f3dc2cc83dda93ff6a4fb0237df6e6 + checksum: 10/01816d6cb1d8e20b3b253764856c686126c753f4341aaee959457b517f5de75d51fb156ee2a8df74ac6a7bb1f068e18da260f7b33e1c2be797ca209cc5f7762b languageName: node linkType: hard -"@testing-library/jest-dom@npm:^6.9.1": - version: 6.9.1 - resolution: "@testing-library/jest-dom@npm:6.9.1" - dependencies: - "@adobe/css-tools": "npm:^4.4.0" - aria-query: "npm:^5.0.0" - css.escape: "npm:^1.5.1" - dom-accessibility-api: "npm:^0.6.3" - picocolors: "npm:^1.1.1" - redent: "npm:^3.0.0" - checksum: 10/409b4f519e4c68f4d31e3b0317338cc19098b9029513fca61aa2af8270086ae3956a1eaedd19bbce2d2c9e2cf9ff27a616c06556be7a26e101c0d529a0062233 +"@tanstack/virtual-core@npm:3.17.0": + version: 3.17.0 + resolution: "@tanstack/virtual-core@npm:3.17.0" + checksum: 10/0f6bdd491ef49fe50fca17857ceee2f0c482cf5d5b3df4a4fa0164ed5194ea486a44b12acc10eae3863cfda7c9e8bb563059e5061211ef22c4970f67f4dec020 languageName: node linkType: hard @@ -5286,10 +4505,54 @@ __metadata: languageName: node linkType: hard -"@types/aria-query@npm:^5.0.1": - version: 5.0.4 - resolution: "@types/aria-query@npm:5.0.4" - checksum: 10/c0084c389dc030daeaf0115a92ce43a3f4d42fc8fef2d0e22112d87a42798d4a15aac413019d4a63f868327d52ad6740ab99609462b442fe6b9286b172d2e82e +"@turbo/darwin-64@npm:2.9.16": + version: 2.9.16 + resolution: "@turbo/darwin-64@npm:2.9.16" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@turbo/darwin-arm64@npm:2.9.16": + version: 2.9.16 + resolution: "@turbo/darwin-arm64@npm:2.9.16" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@turbo/linux-64@npm:2.9.16": + version: 2.9.16 + resolution: "@turbo/linux-64@npm:2.9.16" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@turbo/linux-arm64@npm:2.9.16": + version: 2.9.16 + resolution: "@turbo/linux-arm64@npm:2.9.16" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@turbo/windows-64@npm:2.9.16": + version: 2.9.16 + resolution: "@turbo/windows-64@npm:2.9.16" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@turbo/windows-arm64@npm:2.9.16": + version: 2.9.16 + resolution: "@turbo/windows-arm64@npm:2.9.16" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@tybys/wasm-util@npm:^0.10.1": + version: 0.10.2 + resolution: "@tybys/wasm-util@npm:0.10.2" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10/d12f1dafe12d7a573c406b35ffef0038042b9cc9fbcc74d657267eb635499b956276afc05eebdbd81bea582e1c4c921421a1dd7243a93daaa8c8216b19395c23 languageName: node linkType: hard @@ -5363,7 +4626,7 @@ __metadata: languageName: node linkType: hard -"@types/connect@npm:*, @types/connect@npm:^3.4.33": +"@types/connect@npm:*": version: 3.4.38 resolution: "@types/connect@npm:3.4.38" dependencies: @@ -5382,11 +4645,11 @@ __metadata: linkType: hard "@types/debug@npm:^4.0.0, @types/debug@npm:^4.1.7": - version: 4.1.12 - resolution: "@types/debug@npm:4.1.12" + version: 4.1.13 + resolution: "@types/debug@npm:4.1.13" dependencies: "@types/ms": "npm:*" - checksum: 10/47876a852de8240bfdaf7481357af2b88cb660d30c72e73789abf00c499d6bc7cd5e52f41c915d1b9cd8ec9fef5b05688d7b7aef17f7f272c2d04679508d1053 + checksum: 10/5091d4ebda85236e6f4a6ecea552860e521e11d1d388d3f6255b40726f5a4a7cf1baa0d09f60853838e4cac6c12a13b14114d5f422ccecaee4d1d07dab349900 languageName: node linkType: hard @@ -5406,10 +4669,10 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:1.0.8, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": - version: 1.0.8 - resolution: "@types/estree@npm:1.0.8" - checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099 +"@types/estree@npm:*, @types/estree@npm:1.0.9, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": + version: 1.0.9 + resolution: "@types/estree@npm:1.0.9" + checksum: 10/16aabfa703b5bdac83f719b07ce92a11b2d3c9b8628eacc92889d8af46cab2d78fc45c7b5378de383d0500585cea5c2f79125eeddfe5fbc6bd6a27eb0c8ccee5 languageName: node linkType: hard @@ -5467,9 +4730,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.17.20": - version: 4.17.23 - resolution: "@types/lodash@npm:4.17.23" - checksum: 10/05935534a44aadef67c2158b2fb4a042a226970088106a40ddc67e4f063783149fe5cf02279d7dd4a1e72c98d9189b9430face659645dbf77270f8c4c3e387f5 + version: 4.17.24 + resolution: "@types/lodash@npm:4.17.24" + checksum: 10/0f2082565f60f9787eefc046edc38458054512be5a8b3584ef0bad5fd9e85d0ab55ec5a1fbfae1ed6ba015cf1f9e837d5fb4da1f99fc60b8f74b2a46146fb00f languageName: node linkType: hard @@ -5499,15 +4762,15 @@ __metadata: linkType: hard "@types/node@npm:*, @types/node@npm:>=13.7.0": - version: 25.0.10 - resolution: "@types/node@npm:25.0.10" + version: 25.9.1 + resolution: "@types/node@npm:25.9.1" dependencies: - undici-types: "npm:~7.16.0" - checksum: 10/e5fc1fe0e585957f91ff3ad8ee01b051ce0c9da9658c5ba68d11d557522450783ab61ac2778355e8f566b83bc3bd18e78576569162e9729ed52af36999f81c9a + undici-types: "npm:>=7.24.0 <7.24.7" + checksum: 10/8a1ccf60f0c0ca856d3324a690ee35776f26dfc1d51c3763aecdf246a3246a7971a0156bf6eb3239aa22dfa940eb361d048212f5c3204264d31ef4c41d17416a languageName: node linkType: hard -"@types/node@npm:^12.12.54, @types/node@npm:^12.7.1": +"@types/node@npm:^12.7.1": version: 12.20.55 resolution: "@types/node@npm:12.20.55" checksum: 10/1f916a06fff02faadb09a16ed6e31820ce170798b202ef0b14fc244bfbd721938c54a3a99836e185e4414ca461fe96c5bb5c67c3d248f153555b7e6347f061dd @@ -5515,27 +4778,27 @@ __metadata: linkType: hard "@types/node@npm:^22.5.5": - version: 22.19.7 - resolution: "@types/node@npm:22.19.7" + version: 22.19.19 + resolution: "@types/node@npm:22.19.19" dependencies: undici-types: "npm:~6.21.0" - checksum: 10/0a5c9cc3bdd2a2d8105735b136e280a2dec90136679adfe82faa7e4de375dcc6b4cebaa6b2de35cc6b37e5e135cdc9486373d574782a4ca22f5eeab299111aa6 + checksum: 10/d404eb0bc391805537a172fcc607f7f9c142e20edc01a4203ec33e33a3c4e98fbe3a7ddb63725c399dd05947fac938722a6e05afe1c3d92017ac05c9a6b3ed8f languageName: node linkType: hard "@types/node@npm:^24.10.9": - version: 24.10.9 - resolution: "@types/node@npm:24.10.9" + version: 24.12.4 + resolution: "@types/node@npm:24.12.4" dependencies: undici-types: "npm:~7.16.0" - checksum: 10/c831395567689bdd59d0f3826332ff15c3f3f8e6acf160d7f75ce45e5476427c10ac484031c5c8d3480ae8d1729d95f3354ef4cc359364107e22da5a22e3797c + checksum: 10/4e5ce6faaf0e6f291114d6ac14fe546d491812b306107620802d5bef00ca36fb290637e79ec4fc24f33214f78f58c9b63254bd0ce94788bebfec03f26d45f2ea languageName: node linkType: hard "@types/qs@npm:*": - version: 6.14.0 - resolution: "@types/qs@npm:6.14.0" - checksum: 10/1909205514d22b3cbc7c2314e2bd8056d5f05dfb21cf4377f0730ee5e338ea19957c41735d5e4806c746176563f50005bbab602d8358432e25d900bdf4970826 + version: 6.15.1 + resolution: "@types/qs@npm:6.15.1" + checksum: 10/fd04a36c683dbb1ec5819c01773905259955bfd84d7294af178ad609990a9b8d75d458629ca3bf97b151fe2934eb12ade7fdeb98f2e3ad40d138f0a7d195ac7c languageName: node linkType: hard @@ -5556,11 +4819,11 @@ __metadata: linkType: hard "@types/react@npm:^19.2.9": - version: 19.2.9 - resolution: "@types/react@npm:19.2.9" + version: 19.2.16 + resolution: "@types/react@npm:19.2.16" dependencies: csstype: "npm:^3.2.2" - checksum: 10/580a4acf91cb596edfcf280e3d94380bd5bc675fdce257787432cc77ab67440374fd17a1abde869f3bd47ec1705bf2d66e442a9e9e371603f628e34f9d5790a6 + checksum: 10/b88e77eec8c99757b74539d3495ecd5426e423191fe8c3cdb311f48760046598d9e7c9f876fa6232ee850202205e3165613791ff679e4007d2a92f1512e3b60a languageName: node linkType: hard @@ -5604,13 +4867,6 @@ __metadata: languageName: node linkType: hard -"@types/uuid@npm:^8.3.4": - version: 8.3.4 - resolution: "@types/uuid@npm:8.3.4" - checksum: 10/6f11f3ff70f30210edaa8071422d405e9c1d4e53abbe50fdce365150d3c698fe7bbff65c1e71ae080cbfb8fded860dbb5e174da96fdbbdfcaa3fb3daa474d20f - languageName: node - linkType: hard - "@types/wrap-ansi@npm:^3.0.0": version: 3.0.0 resolution: "@types/wrap-ansi@npm:3.0.0" @@ -5618,318 +4874,302 @@ __metadata: languageName: node linkType: hard -"@types/ws@npm:^7.4.4": - version: 7.4.7 - resolution: "@types/ws@npm:7.4.7" - dependencies: - "@types/node": "npm:*" - checksum: 10/5236b6c54817bdf17674337db5776bb34a876b77a90d885d0f70084c9d453cc2f21703207cc1147d33a9e49a4306773830fbade4729b01ffe33ef0c82cd4c701 - languageName: node - linkType: hard - -"@types/ws@npm:^8.2.2": - version: 8.18.1 - resolution: "@types/ws@npm:8.18.1" - dependencies: - "@types/node": "npm:*" - checksum: 10/1ce05e3174dcacf28dae0e9b854ef1c9a12da44c7ed73617ab6897c5cbe4fccbb155a20be5508ae9a7dde2f83bd80f5cf3baa386b934fc4b40889ec963e94f3a - languageName: node - linkType: hard - -"@typescript-eslint/eslint-plugin@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/eslint-plugin@npm:8.53.1" +"@typescript-eslint/eslint-plugin@npm:8.60.1": + version: 8.60.1 + resolution: "@typescript-eslint/eslint-plugin@npm:8.60.1" dependencies: "@eslint-community/regexpp": "npm:^4.12.2" - "@typescript-eslint/scope-manager": "npm:8.53.1" - "@typescript-eslint/type-utils": "npm:8.53.1" - "@typescript-eslint/utils": "npm:8.53.1" - "@typescript-eslint/visitor-keys": "npm:8.53.1" + "@typescript-eslint/scope-manager": "npm:8.60.1" + "@typescript-eslint/type-utils": "npm:8.60.1" + "@typescript-eslint/utils": "npm:8.60.1" + "@typescript-eslint/visitor-keys": "npm:8.60.1" ignore: "npm:^7.0.5" natural-compare: "npm:^1.4.0" - ts-api-utils: "npm:^2.4.0" + ts-api-utils: "npm:^2.5.0" peerDependencies: - "@typescript-eslint/parser": ^8.53.1 - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10/264a2f3a0d21bedb0fbc54e93749dd9569f6a2936161a892c25ef4d02082025cd5c8714359629fe3c03dd739f8a0815d8af1cf9ca7d090481ee2447b9fe6801b + "@typescript-eslint/parser": ^8.60.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10/f3633bb2700bc32299578baeaf6650418656229be256147ba9d1ab09b34ef2b7fed83804ef4d2439e9189dbdcb89399d67bc8fea55262be6caa32114be048538 languageName: node linkType: hard -"@typescript-eslint/parser@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/parser@npm:8.53.1" +"@typescript-eslint/parser@npm:8.60.1": + version: 8.60.1 + resolution: "@typescript-eslint/parser@npm:8.60.1" dependencies: - "@typescript-eslint/scope-manager": "npm:8.53.1" - "@typescript-eslint/types": "npm:8.53.1" - "@typescript-eslint/typescript-estree": "npm:8.53.1" - "@typescript-eslint/visitor-keys": "npm:8.53.1" + "@typescript-eslint/scope-manager": "npm:8.60.1" + "@typescript-eslint/types": "npm:8.60.1" + "@typescript-eslint/typescript-estree": "npm:8.60.1" + "@typescript-eslint/visitor-keys": "npm:8.60.1" debug: "npm:^4.4.3" peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10/7873eb0ca1e524664b93e78c72d110142b333879e71f66992beec993e5d700fc5a562628af53d318cc8555810730cf42f4dfdbb2588c7c8625c5fa53a96f4630 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10/f9c484c4a3897015328f328a1c6ee778d113dd134201f635c0421cb72efe6e63f3a68524aff0df6e19e76ff93daf5cabd946e67f12f10dddcf19bda534aa68dc languageName: node linkType: hard -"@typescript-eslint/project-service@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/project-service@npm:8.53.1" +"@typescript-eslint/project-service@npm:8.60.1": + version: 8.60.1 + resolution: "@typescript-eslint/project-service@npm:8.60.1" dependencies: - "@typescript-eslint/tsconfig-utils": "npm:^8.53.1" - "@typescript-eslint/types": "npm:^8.53.1" + "@typescript-eslint/tsconfig-utils": "npm:^8.60.1" + "@typescript-eslint/types": "npm:^8.60.1" debug: "npm:^4.4.3" peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10/e450cda2cb30426d55ebbbb5ecad40ba91e68f913ec7df3008ce4c1be524f7cde8411f4ea3c0a3e12fb43655def0e2473315897e410520e496f3fbb3c450ea08 + typescript: ">=4.8.4 <6.1.0" + checksum: 10/fec693dd79c3a1e6a24091127a37af4eb9d9cee8192cf2a434adae48543eadff834bc0623b5b563c8b592b250bc080570f9e7b42807252ea898442c525beeee9 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/scope-manager@npm:8.53.1" +"@typescript-eslint/scope-manager@npm:8.60.1": + version: 8.60.1 + resolution: "@typescript-eslint/scope-manager@npm:8.60.1" dependencies: - "@typescript-eslint/types": "npm:8.53.1" - "@typescript-eslint/visitor-keys": "npm:8.53.1" - checksum: 10/eaf320706143cab1cd1ac27a766be36f038f748be9e891dbedeeb29a39d3e3e7af0789f6f0a94f5c77842533253e10bd63af22c1b974ffc8a25c0ab3a120ba9e + "@typescript-eslint/types": "npm:8.60.1" + "@typescript-eslint/visitor-keys": "npm:8.60.1" + checksum: 10/7228c110410ff8cfc01e96d8f17c986f8b4dd447fe3a3291baaab8fe946026ccdf0291865f788f18cf538ab49bfc067fe797708b6b8590104a65f7e69f921cc5 languageName: node linkType: hard -"@typescript-eslint/tsconfig-utils@npm:8.53.1, @typescript-eslint/tsconfig-utils@npm:^8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/tsconfig-utils@npm:8.53.1" +"@typescript-eslint/tsconfig-utils@npm:8.60.1, @typescript-eslint/tsconfig-utils@npm:^8.60.1": + version: 8.60.1 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.60.1" peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10/0e2743e3f16d60d6784edab67964725686c3efb9fddf9f90e88a9f8b3e5cf40af23be80d55142397704d765a02771626b23b43151c4e3089a394a7c487d035f9 + typescript: ">=4.8.4 <6.1.0" + checksum: 10/afc78b19b856a71dc4e493f931ae44e1a91dc6441a14cb92e4063db880892f3874768f9d347d4b2f45362f2090e4455407c70f42027d77ddc85d6cba95cdb76c languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/type-utils@npm:8.53.1" +"@typescript-eslint/type-utils@npm:8.60.1": + version: 8.60.1 + resolution: "@typescript-eslint/type-utils@npm:8.60.1" dependencies: - "@typescript-eslint/types": "npm:8.53.1" - "@typescript-eslint/typescript-estree": "npm:8.53.1" - "@typescript-eslint/utils": "npm:8.53.1" + "@typescript-eslint/types": "npm:8.60.1" + "@typescript-eslint/typescript-estree": "npm:8.60.1" + "@typescript-eslint/utils": "npm:8.60.1" debug: "npm:^4.4.3" - ts-api-utils: "npm:^2.4.0" + ts-api-utils: "npm:^2.5.0" peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10/d03b8f092d53896ac1d64d3e0555f34d8d52c78eb6d14ca7c4b3a7f62baa37aa99fbeb69ab77d6ea0df3b8e1011e1356a8f281fd00bbb2aa965e433b78b8e9f3 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10/6f426263be597063831bf308e52328e8d387af5db955a09cb85fde1c72f5b1b36a365133b9c9a74330e5e948e59bf9a9b82605f4c9c4e3bf9b6cb7f4c37e4b18 languageName: node linkType: hard -"@typescript-eslint/types@npm:8.53.1, @typescript-eslint/types@npm:^8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/types@npm:8.53.1" - checksum: 10/9a01aa343329af529c645204070dd20be54556c6fd92bfda3a42b6213c0408f5f2f57084064d88d5de1337a7731e57290f0ec11a0fb181bbb3c3b293ef0dcf4a +"@typescript-eslint/types@npm:8.60.1, @typescript-eslint/types@npm:^8.60.1": + version: 8.60.1 + resolution: "@typescript-eslint/types@npm:8.60.1" + checksum: 10/c603417e621b5b1263c2f60fad9e202d560fd07fce7f40e9a356c0530e5eaf0ff1a9af865237bf93aa18a5a4e2f034ee0cce0fe6c070f08df33e35a099bdea47 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/typescript-estree@npm:8.53.1" +"@typescript-eslint/typescript-estree@npm:8.60.1": + version: 8.60.1 + resolution: "@typescript-eslint/typescript-estree@npm:8.60.1" dependencies: - "@typescript-eslint/project-service": "npm:8.53.1" - "@typescript-eslint/tsconfig-utils": "npm:8.53.1" - "@typescript-eslint/types": "npm:8.53.1" - "@typescript-eslint/visitor-keys": "npm:8.53.1" + "@typescript-eslint/project-service": "npm:8.60.1" + "@typescript-eslint/tsconfig-utils": "npm:8.60.1" + "@typescript-eslint/types": "npm:8.60.1" + "@typescript-eslint/visitor-keys": "npm:8.60.1" debug: "npm:^4.4.3" - minimatch: "npm:^9.0.5" + minimatch: "npm:^10.2.2" semver: "npm:^7.7.3" tinyglobby: "npm:^0.2.15" - ts-api-utils: "npm:^2.4.0" + ts-api-utils: "npm:^2.5.0" peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10/fb1e0016292b82a873df1d4d95f9ecc441b443bdd83236eb7c118a88e500b9466e29bba4a6a5c3526d37c3cb189b427ea9f45d49f988fbc6dc4f238d58cfadb9 + typescript: ">=4.8.4 <6.1.0" + checksum: 10/9c3a56266aadf589bc6e770cd04cb3f55b1ee1507dcacda61866408c656ae4462aa7e11baf39eb939bc4d1e3b843cf58e60f3ebdeb3e75f042ff0f6fb39c311b languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/utils@npm:8.53.1" +"@typescript-eslint/utils@npm:8.60.1": + version: 8.60.1 + resolution: "@typescript-eslint/utils@npm:8.60.1" dependencies: "@eslint-community/eslint-utils": "npm:^4.9.1" - "@typescript-eslint/scope-manager": "npm:8.53.1" - "@typescript-eslint/types": "npm:8.53.1" - "@typescript-eslint/typescript-estree": "npm:8.53.1" + "@typescript-eslint/scope-manager": "npm:8.60.1" + "@typescript-eslint/types": "npm:8.60.1" + "@typescript-eslint/typescript-estree": "npm:8.60.1" peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10/ff874fc9938b3b9493e0e543d400cd51ed34391a6bf9838a688bb124d1999639207efb9b626908fc927ae6f149ef4aa62e02df794e5b5b0b34e6ac5de48cdaa6 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10/a75f8714995b6280b4c15ca957bbc6634862453461111e4a2a07b8bc72b51a504484a9b957fc5b7a646c4bf09f1e414a0c52cd3b6798c42fb8c4de83b1b5a364 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/visitor-keys@npm:8.53.1" +"@typescript-eslint/visitor-keys@npm:8.60.1": + version: 8.60.1 + resolution: "@typescript-eslint/visitor-keys@npm:8.60.1" dependencies: - "@typescript-eslint/types": "npm:8.53.1" - eslint-visitor-keys: "npm:^4.2.1" - checksum: 10/9498ecd42de7ce5746faee88f67edebd92781d35b31c1da355207b42b564a5974c1a5314d01cd7aea865c5e948b15b3aa043d724b2e51b4f8bc26e0b3711a8b2 + "@typescript-eslint/types": "npm:8.60.1" + eslint-visitor-keys: "npm:^5.0.0" + checksum: 10/6d120b4a790477ae0291e69f6457686c71b929cc40519148f6b6c7fbc09604b15821ae8cf1005aa23acec5105b4016db256a68d68f30eda8d6c24d4fdb0ede86 languageName: node linkType: hard "@ungap/structured-clone@npm:^1.0.0": - version: 1.3.0 - resolution: "@ungap/structured-clone@npm:1.3.0" - checksum: 10/80d6910946f2b1552a2406650051c91bbd1f24a6bf854354203d84fe2714b3e8ce4618f49cc3410494173a1c1e8e9777372fe68dce74bd45faf0a7a1a6ccf448 + version: 1.3.1 + resolution: "@ungap/structured-clone@npm:1.3.1" + checksum: 10/64df206f50aef71c176f9059c1b29e1694821419c6728c446ecf39c80a811eeef156668bf51421b676494a12fd0129ccf09a44f0c641f13c27f50d5f0db6de4e languageName: node linkType: hard "@vitejs/plugin-react@npm:^5.1.2": - version: 5.1.2 - resolution: "@vitejs/plugin-react@npm:5.1.2" + version: 5.2.0 + resolution: "@vitejs/plugin-react@npm:5.2.0" dependencies: - "@babel/core": "npm:^7.28.5" + "@babel/core": "npm:^7.29.0" "@babel/plugin-transform-react-jsx-self": "npm:^7.27.1" "@babel/plugin-transform-react-jsx-source": "npm:^7.27.1" - "@rolldown/pluginutils": "npm:1.0.0-beta.53" + "@rolldown/pluginutils": "npm:1.0.0-rc.3" "@types/babel__core": "npm:^7.20.5" react-refresh: "npm:^0.18.0" peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - checksum: 10/2b15994a7f787456bf66d00cc231617148bd10a439a115767ab14d47d435f182758bce38f7c07d5275e79930dc7f689e3ebab44ac57a833fe13b6a233aa37738 + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10/f4c98e084d053227fae80358fc33641e4a143daa9528c8f821ac7ce7eabe27329616c3a9efbe5b1a87ea131a5ad21e26a0ab355685727ec7bb65d244266250ee languageName: node linkType: hard "@vitest/browser-playwright@npm:^4.0.18": - version: 4.0.18 - resolution: "@vitest/browser-playwright@npm:4.0.18" + version: 4.1.8 + resolution: "@vitest/browser-playwright@npm:4.1.8" dependencies: - "@vitest/browser": "npm:4.0.18" - "@vitest/mocker": "npm:4.0.18" - tinyrainbow: "npm:^3.0.3" + "@vitest/browser": "npm:4.1.8" + "@vitest/mocker": "npm:4.1.8" + tinyrainbow: "npm:^3.1.0" peerDependencies: playwright: "*" - vitest: 4.0.18 + vitest: 4.1.8 peerDependenciesMeta: playwright: optional: false - checksum: 10/ce6dc911e841abcb447bb68a363cc564cab1cf45978748e11d20ca560c0df2bd88fa70a4ae706f11f4191b948bc22adb93ffd375e61e7b4a94d4a2648421cbb0 + checksum: 10/d68c0746d0a3b5235874f6195313ee338162913500415d7270541ea6e794812c4ee0eeb3add0ed8ad266884519865d453e35617282e7e3c5d7b811692fd58ebd languageName: node linkType: hard -"@vitest/browser@npm:4.0.18, @vitest/browser@npm:^4.0.18": - version: 4.0.18 - resolution: "@vitest/browser@npm:4.0.18" +"@vitest/browser@npm:4.1.8, @vitest/browser@npm:^4.0.18": + version: 4.1.8 + resolution: "@vitest/browser@npm:4.1.8" dependencies: - "@vitest/mocker": "npm:4.0.18" - "@vitest/utils": "npm:4.0.18" + "@blazediff/core": "npm:1.9.1" + "@vitest/mocker": "npm:4.1.8" + "@vitest/utils": "npm:4.1.8" magic-string: "npm:^0.30.21" - pixelmatch: "npm:7.1.0" pngjs: "npm:^7.0.0" sirv: "npm:^3.0.2" - tinyrainbow: "npm:^3.0.3" - ws: "npm:^8.18.3" + tinyrainbow: "npm:^3.1.0" + ws: "npm:^8.19.0" peerDependencies: - vitest: 4.0.18 - checksum: 10/4f462b8b2961d422d3002d63117515ad4539753eb64ef73fed6024dc66e3b63931302848d3f50be6c371b684756d2a48db7b4058209529615cb4fe5908ffb9f1 + vitest: 4.1.8 + checksum: 10/be106ec58ba095d8cc9ceeaa359844cfc746eff9006ec624db4a888429b86d09920e008bcd3fb4448038b2e9bb665e58f8dff2a391cf47d5a2c62bc91ae10f0e languageName: node linkType: hard "@vitest/coverage-v8@npm:^4.0.18": - version: 4.0.18 - resolution: "@vitest/coverage-v8@npm:4.0.18" + version: 4.1.8 + resolution: "@vitest/coverage-v8@npm:4.1.8" dependencies: "@bcoe/v8-coverage": "npm:^1.0.2" - "@vitest/utils": "npm:4.0.18" - ast-v8-to-istanbul: "npm:^0.3.10" + "@vitest/utils": "npm:4.1.8" + ast-v8-to-istanbul: "npm:^1.0.0" istanbul-lib-coverage: "npm:^3.2.2" istanbul-lib-report: "npm:^3.0.1" istanbul-reports: "npm:^3.2.0" - magicast: "npm:^0.5.1" + magicast: "npm:^0.5.2" obug: "npm:^2.1.1" - std-env: "npm:^3.10.0" - tinyrainbow: "npm:^3.0.3" + std-env: "npm:^4.0.0-rc.1" + tinyrainbow: "npm:^3.1.0" peerDependencies: - "@vitest/browser": 4.0.18 - vitest: 4.0.18 + "@vitest/browser": 4.1.8 + vitest: 4.1.8 peerDependenciesMeta: "@vitest/browser": optional: true - checksum: 10/33bd54aa8ea1c4b0acae77722b34460408325793d4d74159f7d73aedf2d1c4aa940c8666baf31c4b19b3760d68bbc268dd8c9265ebc2088cece428d26568afb4 + checksum: 10/08d9ea65ca4cc007a1f1cdc85ea36d51bfa91a9b2f0e9ad27436b777629b4138e33dba2f68c8e68b01343310bf9d5624ad1d6d24553a5b289b66da51561259eb languageName: node linkType: hard -"@vitest/expect@npm:4.0.18": - version: 4.0.18 - resolution: "@vitest/expect@npm:4.0.18" +"@vitest/expect@npm:4.1.8": + version: 4.1.8 + resolution: "@vitest/expect@npm:4.1.8" dependencies: - "@standard-schema/spec": "npm:^1.0.0" + "@standard-schema/spec": "npm:^1.1.0" "@types/chai": "npm:^5.2.2" - "@vitest/spy": "npm:4.0.18" - "@vitest/utils": "npm:4.0.18" - chai: "npm:^6.2.1" - tinyrainbow: "npm:^3.0.3" - checksum: 10/2115bff1bbcad460ce72032022e4dbcf8572c4b0fe07ca60f5644a8d96dd0dfa112986b5a1a5c5705f4548119b3b829c45d1de0838879211e0d6bb276b4ece73 + "@vitest/spy": "npm:4.1.8" + "@vitest/utils": "npm:4.1.8" + chai: "npm:^6.2.2" + tinyrainbow: "npm:^3.1.0" + checksum: 10/cb7d78e250ec77b7e180ac3e5f543501488c69b237d7ed97ffe9196c5e946b0e4a37be05a2ec38af7ce7750c1a98286480acdd247286a29c239b08a13b085d4b languageName: node linkType: hard -"@vitest/mocker@npm:4.0.18": - version: 4.0.18 - resolution: "@vitest/mocker@npm:4.0.18" +"@vitest/mocker@npm:4.1.8": + version: 4.1.8 + resolution: "@vitest/mocker@npm:4.1.8" dependencies: - "@vitest/spy": "npm:4.0.18" + "@vitest/spy": "npm:4.1.8" estree-walker: "npm:^3.0.3" magic-string: "npm:^0.30.21" peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: msw: optional: true vite: optional: true - checksum: 10/46f584a4c1180dfb513137bc8db6e2e3b53e141adfe964307297e98321652d86a3f2a52d80cda1f810205bd5fdcab789bb8b52a532e68f175ef1e20be398218d + checksum: 10/fc977703b07d950aa170bafdef988bc7ba88f0a80159d1563ce95696763729ec1f6d015012aad36cf4e1b522d327b205292c56d76692d2a9f72285d694ed3cba languageName: node linkType: hard -"@vitest/pretty-format@npm:4.0.18": - version: 4.0.18 - resolution: "@vitest/pretty-format@npm:4.0.18" +"@vitest/pretty-format@npm:4.1.8": + version: 4.1.8 + resolution: "@vitest/pretty-format@npm:4.1.8" dependencies: - tinyrainbow: "npm:^3.0.3" - checksum: 10/4cafc7c9853097345bd94e8761bf47c2c04e00d366ac56d79928182787ff83c512c96f1dc2ce9b6aeed4d3a8c23ce12254da203783108d3c096bc398eed2a62d + tinyrainbow: "npm:^3.1.0" + checksum: 10/56a4b685cdf9f2e9708025f17dab8c0fa990ab06e5b38606a1ddde52a09830a099843da6a1b127ee48217ab023bad7bd23c49eb4969d77dff07df363fad0bb0e languageName: node linkType: hard -"@vitest/runner@npm:4.0.18": - version: 4.0.18 - resolution: "@vitest/runner@npm:4.0.18" +"@vitest/runner@npm:4.1.8": + version: 4.1.8 + resolution: "@vitest/runner@npm:4.1.8" dependencies: - "@vitest/utils": "npm:4.0.18" + "@vitest/utils": "npm:4.1.8" pathe: "npm:^2.0.3" - checksum: 10/d7deebf086d7e084f449733ecea6c9c81737a18aafece318cbe7500e45debea00fa9dbf9315fd38aa88550dd5240a791b885ac71665f89b154d71a6c63da5836 + checksum: 10/278d1482123877343731b3bb822d0280af928252ee263aab73ca189c39de3bb767ce715581870b2e1eb408f7cba01106a6989406cb2ada1332f181912558a3c1 languageName: node linkType: hard -"@vitest/snapshot@npm:4.0.18": - version: 4.0.18 - resolution: "@vitest/snapshot@npm:4.0.18" +"@vitest/snapshot@npm:4.1.8": + version: 4.1.8 + resolution: "@vitest/snapshot@npm:4.1.8" dependencies: - "@vitest/pretty-format": "npm:4.0.18" + "@vitest/pretty-format": "npm:4.1.8" + "@vitest/utils": "npm:4.1.8" magic-string: "npm:^0.30.21" pathe: "npm:^2.0.3" - checksum: 10/50aa5fb7fca45c499c145cc2f20e53b8afb0990b53ff4a4e6447dd6f147437edc5316f22e2d82119e154c3cf7c59d44898e7b2faf7ba614ac1051cbe4d662a77 + checksum: 10/162ca0eccb72db02081b04307d21ac8d14c8fcd4a840872459274f589b1665f108bd4119dff19d5a2150a0e26b90531791ebec7ee74f0c2c5285b491cebbcfcb languageName: node linkType: hard -"@vitest/spy@npm:4.0.18": - version: 4.0.18 - resolution: "@vitest/spy@npm:4.0.18" - checksum: 10/f7b1618ae13790105771dd2a8c973c63c018366fcc69b50f15ce5d12f9ac552efd3c1e6e5ae4ebdb6023d0b8d8f31fef2a0b1b77334284928db45c80c63de456 +"@vitest/spy@npm:4.1.8": + version: 4.1.8 + resolution: "@vitest/spy@npm:4.1.8" + checksum: 10/53e948d8f5e229e969e704dc8a54fd42ad715b2b18f401592f4bba97dcf33bd4cf01d11af577d4efe42dc2d90c9e6574ec991531fd8f1bdfee916a1dd0828547 languageName: node linkType: hard -"@vitest/utils@npm:4.0.18": - version: 4.0.18 - resolution: "@vitest/utils@npm:4.0.18" +"@vitest/utils@npm:4.1.8": + version: 4.1.8 + resolution: "@vitest/utils@npm:4.1.8" dependencies: - "@vitest/pretty-format": "npm:4.0.18" - tinyrainbow: "npm:^3.0.3" - checksum: 10/e8b2ad7bc35b2bc5590f9dc1d1a67644755da416b47ab7099a6f26792903fa0aacb81e6ba99f0f03858d9d3a1d76eeba65150a1a0849690a40817424e749c367 + "@vitest/pretty-format": "npm:4.1.8" + convert-source-map: "npm:^2.0.0" + tinyrainbow: "npm:^3.1.0" + checksum: 10/13250b9e7825d425cc9a3d22aeb2e8d117c93e96a192138e93d76bfe7d5a391ab3888c5aa9e0394b0314bdff41e441ad7a32b0c0caa00cd202223b88087dcc78 languageName: node linkType: hard @@ -6369,15 +5609,6 @@ __metadata: languageName: node linkType: hard -"@web/rollup-plugin-copy@npm:^0.5.1": - version: 0.5.1 - resolution: "@web/rollup-plugin-copy@npm:0.5.1" - dependencies: - glob: "npm:^10.0.0" - checksum: 10/fa11f8b8a778476102bd94c3878271ae4e7b4fc7e1c5dcad1d840e42e5471253e25e77ae66061f8e5bf686850dfe9ae197825a6468712f4d25d594f76392576b - languageName: node - linkType: hard - "@xmtp/agent-sdk@workspace:sdks/agent-sdk": version: 0.0.0-use.local resolution: "@xmtp/agent-sdk@workspace:sdks/agent-sdk" @@ -6387,7 +5618,7 @@ __metadata: "@types/node": "npm:^24.10.9" "@vitest/coverage-v8": "npm:^4.0.18" "@xmtp/content-type-primitives": "npm:3.0.1" - "@xmtp/node-sdk": "npm:6.0.0" + "@xmtp/node-sdk": "npm:^6.0.0" rollup: "npm:^4.59.0" rollup-plugin-dts: "npm:^6.3.0" rollup-plugin-tsconfig-paths: "npm:^1.5.2" @@ -6401,36 +5632,20 @@ __metadata: languageName: unknown linkType: soft -"@xmtp/browser-sdk@workspace:^, @xmtp/browser-sdk@workspace:sdks/browser-sdk": - version: 0.0.0-use.local - resolution: "@xmtp/browser-sdk@workspace:sdks/browser-sdk" +"@xmtp/browser-sdk@npm:7.0.0-dev.b5cdc06": + version: 7.0.0-dev.b5cdc06 + resolution: "@xmtp/browser-sdk@npm:7.0.0-dev.b5cdc06" dependencies: - "@rollup/plugin-terser": "npm:^0.4.4" - "@rollup/plugin-typescript": "npm:^12.3.0" - "@testing-library/dom": "npm:^10.4.1" - "@testing-library/jest-dom": "npm:^6.9.1" - "@vitest/browser": "npm:^4.0.18" - "@vitest/browser-playwright": "npm:^4.0.18" - "@vitest/coverage-v8": "npm:^4.0.18" - "@web/rollup-plugin-copy": "npm:^0.5.1" "@xmtp/content-type-primitives": "npm:3.0.0" - "@xmtp/wasm-bindings": "npm:1.11.0-nightly.20260603.89c3fc3" - playwright: "npm:^1.58.0" - rollup: "npm:^4.59.0" - rollup-plugin-dts: "npm:^6.3.0" - rollup-plugin-tsconfig-paths: "npm:^1.5.2" - typescript: "npm:^5.9.3" - viem: "npm:^2.44.4" - vite: "npm:^7.3.1" - vite-tsconfig-paths: "npm:^6.0.4" - vitest: "npm:^4.0.18" + "@xmtp/wasm-bindings": "npm:1.11.0-dev.b5cdc06" peerDependencies: viem: ">=2" peerDependenciesMeta: viem: optional: true - languageName: unknown - linkType: soft + checksum: 10/a667014eeac4a4ac64be2cd72dee5db73275dc45c45eed454a0723712187450c67c75ba22ade07dda097c707d9d36cbe1e3a802c5f242836526ef243f2f43a1a + languageName: node + linkType: hard "@xmtp/cli@workspace:packages/xmtp-cli": version: 0.0.0-use.local @@ -6443,7 +5658,7 @@ __metadata: "@oclif/plugin-not-found": "npm:^3.2.74" "@oclif/plugin-warn-if-update-available": "npm:^3.1.55" "@types/node": "npm:^24.10.9" - "@xmtp/node-sdk": "npm:6.0.0" + "@xmtp/node-sdk": "npm:^6.0.0" execa: "npm:^9.6.1" oclif: "npm:^4.22.70" tsx: "npm:^4.21.0" @@ -6657,6 +5872,13 @@ __metadata: languageName: unknown linkType: soft +"@xmtp/node-bindings@npm:1.10.0": + version: 1.10.0 + resolution: "@xmtp/node-bindings@npm:1.10.0" + checksum: 10/63ab1b66c0f837f030d12a7c6ead06ee68cdf48cca091aaea35614d6d61fd6b86d11562dc553444de4641f0b970098a74b0f01c9501dd64160c9f975b6dec601 + languageName: node + linkType: hard + "@xmtp/node-bindings@npm:1.11.0-nightly.20260603.89c3fc3": version: 1.11.0-nightly.20260603.89c3fc3 resolution: "@xmtp/node-bindings@npm:1.11.0-nightly.20260603.89c3fc3" @@ -6690,30 +5912,15 @@ __metadata: languageName: node linkType: hard -"@xmtp/node-sdk@npm:6.0.0, @xmtp/node-sdk@workspace:sdks/node-sdk": - version: 0.0.0-use.local - resolution: "@xmtp/node-sdk@workspace:sdks/node-sdk" +"@xmtp/node-sdk@npm:^6.0.0": + version: 6.0.0 + resolution: "@xmtp/node-sdk@npm:6.0.0" dependencies: - "@rollup/plugin-json": "npm:^6.1.0" - "@rollup/plugin-typescript": "npm:^12.3.0" - "@types/node": "npm:^24.10.9" - "@vitest/coverage-v8": "npm:^4.0.18" "@xmtp/content-type-primitives": "npm:3.0.0" - "@xmtp/node-bindings": "npm:1.11.0-nightly.20260603.89c3fc3" - fast-glob: "npm:^3.3.3" - rimraf: "npm:^6.1.2" - rollup: "npm:^4.59.0" - rollup-plugin-dts: "npm:^6.3.0" - rollup-plugin-tsconfig-paths: "npm:^1.5.2" - tsx: "npm:^4.21.0" - typescript: "npm:^5.9.3" - uint8array-extras: "npm:^1.5.0" - viem: "npm:^2.44.4" - vite: "npm:^7.3.1" - vite-tsconfig-paths: "npm:^6.0.4" - vitest: "npm:^4.0.18" - languageName: unknown - linkType: soft + "@xmtp/node-bindings": "npm:1.10.0" + checksum: 10/937e082c75ff6937d256fcc7be828e358b5aeb6a0569ae07b9f160d653f4149567c5f8addaf00061252e6021e67d8c5cdf5d726aed0cfb330d5b2a1ae15b5a32 + languageName: node + linkType: hard "@xmtp/proto@npm:3.78.0": version: 3.78.0 @@ -6740,10 +5947,10 @@ __metadata: languageName: node linkType: hard -"@xmtp/wasm-bindings@npm:1.11.0-nightly.20260603.89c3fc3": - version: 1.11.0-nightly.20260603.89c3fc3 - resolution: "@xmtp/wasm-bindings@npm:1.11.0-nightly.20260603.89c3fc3" - checksum: 10/a328ae3e123910f1bdd7edab97f41f97609156a7a4ce418fbe9652866057856245c78347516aa69073eb5a731d8463fabeb2744975a052829256a1ea17b7b795 +"@xmtp/wasm-bindings@npm:1.11.0-dev.b5cdc06": + version: 1.11.0-dev.b5cdc06 + resolution: "@xmtp/wasm-bindings@npm:1.11.0-dev.b5cdc06" + checksum: 10/c9e418cbfb65fd688826310faeda2b4ac0f0454865430967526c10564cb2f53976b9cb33c684bc9a8287d445f57923a393a40f59094a7044013f1459203cdf94 languageName: node linkType: hard @@ -6765,7 +5972,7 @@ __metadata: "@vitejs/plugin-react": "npm:^5.1.2" "@vitest/browser": "npm:^4.0.18" "@vitest/browser-playwright": "npm:^4.0.18" - "@xmtp/browser-sdk": "workspace:^" + "@xmtp/browser-sdk": "npm:7.0.0-dev.b5cdc06" "@xmtp/content-type-primitives": "workspace:^" date-fns: "npm:^4.1.0" pinata: "npm:^2.5.3" @@ -6829,7 +6036,7 @@ __metadata: languageName: node linkType: hard -"abitype@npm:1.2.3, abitype@npm:^1.0.6, abitype@npm:^1.0.9, abitype@npm:^1.2.3": +"abitype@npm:1.2.3": version: 1.2.3 resolution: "abitype@npm:1.2.3" peerDependencies: @@ -6844,6 +6051,21 @@ __metadata: languageName: node linkType: hard +"abitype@npm:^1.0.6, abitype@npm:^1.0.9, abitype@npm:^1.2.3": + version: 1.2.4 + resolution: "abitype@npm:1.2.4" + peerDependencies: + typescript: ">=5.0.4" + zod: ^3.22.0 || ^4.0.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + checksum: 10/500b317a53b34cb6ffe3e4f090e135972b43cd2fbdfebe64fc497dfd8515d9117919e5f88f0aaede332d29a21c1826be64a3ffa620b0b91c16e8b560b6635714 + languageName: node + linkType: hard + "abort-controller@npm:^3.0.0": version: 3.0.0 resolution: "abort-controller@npm:3.0.0" @@ -6873,39 +6095,23 @@ __metadata: linkType: hard "acorn@npm:^8.15.0": - version: 8.15.0 - resolution: "acorn@npm:8.15.0" + version: 8.16.0 + resolution: "acorn@npm:8.16.0" bin: acorn: bin/acorn - checksum: 10/77f2de5051a631cf1729c090e5759148459cdb76b5f5c70f890503d629cf5052357b0ce783c0f976dd8a93c5150f59f6d18df1def3f502396a20f81282482fa4 - languageName: node - linkType: hard - -"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": - version: 7.1.4 - resolution: "agent-base@npm:7.1.4" - checksum: 10/79bef167247789f955aaba113bae74bf64aa1e1acca4b1d6bb444bdf91d82c3e07e9451ef6a6e2e35e8f71a6f97ce33e3d855a5328eb9fad1bc3cc4cfd031ed8 - languageName: node - linkType: hard - -"agentkeepalive@npm:^4.5.0": - version: 4.6.0 - resolution: "agentkeepalive@npm:4.6.0" - dependencies: - humanize-ms: "npm:^1.2.1" - checksum: 10/80c546bd88dd183376d6a29e5598f117f380b1d567feb1de184241d6ece721e2bdd38f179a1674276de01780ccae229a38c60a77317e2f5ad2f1818856445bd7 + checksum: 10/690c673bb4d61b38ef82795fab58526471ad7f7e67c0e40c4ff1e10ecd80ce5312554ef633c9995bfc4e6d170cef165711f9ca9e49040b62c0c66fbf2dd3df2b languageName: node linkType: hard -"ajv@npm:^6.12.4": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" +"ajv@npm:^6.14.0": + version: 6.15.0 + resolution: "ajv@npm:6.15.0" dependencies: fast-deep-equal: "npm:^3.1.1" fast-json-stable-stringify: "npm:^2.0.0" json-schema-traverse: "npm:^0.4.1" uri-js: "npm:^4.2.2" - checksum: 10/48d6ad21138d12eb4d16d878d630079a2bda25a04e745c07846a4ad768319533031e28872a9b3c5790fa1ec41aabdf2abed30a56e5a03ebc2cf92184b8ee306c + checksum: 10/0916dda09c152fb5857bc1cc7ce61718e9cec5b7faeff44a74f5e324eed8a556e1a84856724ea322a067b436ecad9f74ac8295fd395449788cca52f0c25bd5fb languageName: node linkType: hard @@ -6932,13 +6138,6 @@ __metadata: languageName: node linkType: hard -"ansi-regex@npm:^6.0.1": - version: 6.2.2 - resolution: "ansi-regex@npm:6.2.2" - checksum: 10/9b17ce2c6daecc75bcd5966b9ad672c23b184dc3ed9bf3c98a0702f0d2f736c15c10d461913568f2cf527a5e64291c7473358885dd493305c84a1cfed66ba94f - languageName: node - linkType: hard - "ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0, ansi-styles@npm:^4.2.1, ansi-styles@npm:^4.3.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" @@ -6948,20 +6147,6 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^5.0.0": - version: 5.2.0 - resolution: "ansi-styles@npm:5.2.0" - checksum: 10/d7f4e97ce0623aea6bc0d90dcd28881ee04cba06c570b97fd3391bd7a268eedfd9d5e2dd4fdcbdd82b8105df5faf6f24aaedc08eaf3da898e702db5948f63469 - languageName: node - linkType: hard - -"ansi-styles@npm:^6.1.0": - version: 6.2.3 - resolution: "ansi-styles@npm:6.2.3" - checksum: 10/c49dad7639f3e48859bd51824c93b9eb0db628afc243c51c3dd2410c4a15ede1a83881c6c7341aa2b159c4f90c11befb38f2ba848c07c66c9f9de4bcd7cb9f30 - languageName: node - linkType: hard - "ansicolors@npm:~0.3.2": version: 0.3.2 resolution: "ansicolors@npm:0.3.2" @@ -7002,22 +6187,6 @@ __metadata: languageName: node linkType: hard -"aria-query@npm:5.3.0": - version: 5.3.0 - resolution: "aria-query@npm:5.3.0" - dependencies: - dequal: "npm:^2.0.3" - checksum: 10/c3e1ed127cc6886fea4732e97dd6d3c3938e64180803acfb9df8955517c4943760746ffaf4020ce8f7ffaa7556a3b5f85c3769a1f5ca74a1288e02d042f9ae4e - languageName: node - linkType: hard - -"aria-query@npm:^5.0.0": - version: 5.3.2 - resolution: "aria-query@npm:5.3.2" - checksum: 10/b2fe9bc98bd401bc322ccb99717c1ae2aaf53ea0d468d6e7aebdc02fac736e4a99b46971ee05b783b08ade23c675b2d8b60e4a1222a95f6e27bc4d2a0bfdcc03 - languageName: node - linkType: hard - "array-union@npm:^2.1.0": version: 2.1.0 resolution: "array-union@npm:2.1.0" @@ -7032,14 +6201,14 @@ __metadata: languageName: node linkType: hard -"ast-v8-to-istanbul@npm:^0.3.10": - version: 0.3.10 - resolution: "ast-v8-to-istanbul@npm:0.3.10" +"ast-v8-to-istanbul@npm:^1.0.0": + version: 1.0.3 + resolution: "ast-v8-to-istanbul@npm:1.0.3" dependencies: "@jridgewell/trace-mapping": "npm:^0.3.31" estree-walker: "npm:^3.0.3" - js-tokens: "npm:^9.0.1" - checksum: 10/240a5e2c24776b355f2442fa93564a528b8df4b8d94e9bc3234f25020ffac745886865a3a92e5e9dc67ee9720739ec078f04790a3607a7ad98d8349cf75ddf04 + js-tokens: "npm:^10.0.0" + checksum: 10/7b9079a87d311f4a4dd13c6a3bd2cc76c70b094ab7a8359eaf8314bf8a5841b38db0ea26f12ae5ee08abf0654fc46778db6562c1e8ff6145739ba659ee139744 languageName: node linkType: hard @@ -7123,14 +6292,14 @@ __metadata: languageName: node linkType: hard -"axios@npm:^1.12.2": - version: 1.13.5 - resolution: "axios@npm:1.13.5" +"axios@npm:1.16.0": + version: 1.16.0 + resolution: "axios@npm:1.16.0" dependencies: - follow-redirects: "npm:^1.15.11" + follow-redirects: "npm:^1.16.0" form-data: "npm:^4.0.5" - proxy-from-env: "npm:^1.1.0" - checksum: 10/db726d09902565ef9a0632893530028310e2ec2b95b727114eca1b101450b00014133dfc3871cffc87983fb922bca7e4874d7e2826d1550a377a157cdf3f05b6 + proxy-from-env: "npm:^2.1.0" + checksum: 10/cf8b521ff732c21550b38c8739aef556ea5e14b268468bb89e4307416ab262b462e582474e810963a3d61c2392ab47ad35c11d05eff027de7c97113bc7411623 languageName: node linkType: hard @@ -7148,12 +6317,10 @@ __metadata: languageName: node linkType: hard -"base-x@npm:^3.0.2": - version: 3.0.11 - resolution: "base-x@npm:3.0.11" - dependencies: - safe-buffer: "npm:^5.0.1" - checksum: 10/c2e3c443fd07cb9b9d3e179a9e9c581daa31881005841fe8d6a834e534505890fedf03465ccf14512da60e3f7be00fe66167806b159ba076d2c03952ae7460c4 +"balanced-match@npm:^4.0.2": + version: 4.0.4 + resolution: "balanced-match@npm:4.0.4" + checksum: 10/fb07bb66a0959c2843fc055838047e2a95ccebb837c519614afb067ebfdf2fa967ca8d712c35ced07f2cd26fc6f07964230b094891315ad74f11eba3d53178a0 languageName: node linkType: hard @@ -7171,12 +6338,12 @@ __metadata: languageName: node linkType: hard -"baseline-browser-mapping@npm:^2.9.0": - version: 2.9.17 - resolution: "baseline-browser-mapping@npm:2.9.17" +"baseline-browser-mapping@npm:^2.10.12": + version: 2.10.33 + resolution: "baseline-browser-mapping@npm:2.10.33" bin: - baseline-browser-mapping: dist/cli.js - checksum: 10/e48a1249dacae1efad6cf3aefaa69ded2d716f702f67565424e7ea3318097b1bcd3b84309f750a2a50edcdd0efdf8c87a58bc68c313873bc8ca8e6ca470fb6c5 + baseline-browser-mapping: dist/cli.cjs + checksum: 10/e5ea31ff7988d631af72cc579825d109f1b8ab70af2490b875daaef5eba9257c60e108a768f7bd949394ca6a9e33469ea48e7367aea680671f8073733514f101 languageName: node linkType: hard @@ -7196,10 +6363,10 @@ __metadata: languageName: node linkType: hard -"bn.js@npm:^5.2.0, bn.js@npm:^5.2.1": - version: 5.2.2 - resolution: "bn.js@npm:5.2.2" - checksum: 10/51ebb2df83b33e5d8581165206e260d5e9c873752954616e5bf3758952b84d7399a9c6d00852815a0aeefb1150a7f34451b62d4287342d457fa432eee869e83e +"bn.js@npm:^5.2.1": + version: 5.2.3 + resolution: "bn.js@npm:5.2.3" + checksum: 10/dfb3927e0d531e6ec4f191597ce6f7f7665310c356fef5f968ada676b8058027f959af42eaa37b5f5c63617e819d3741813025ab15dd71a90f2e74698df0b58e languageName: node linkType: hard @@ -7220,40 +6387,38 @@ __metadata: languageName: node linkType: hard -"borsh@npm:^0.7.0": - version: 0.7.0 - resolution: "borsh@npm:0.7.0" - dependencies: - bn.js: "npm:^5.2.0" - bs58: "npm:^4.0.0" - text-encoding-utf-8: "npm:^1.0.2" - checksum: 10/e51a9395dad0c1db38d7b764052369c536a830de4c744107992765b7b560f141f79a8214a684d186b27c61308b75796613a60aef3b70d1a6ab638140ed5087ca - languageName: node - linkType: hard - "bowser@npm:^2.11.0, bowser@npm:^2.9.0": - version: 2.13.1 - resolution: "bowser@npm:2.13.1" - checksum: 10/b93c4f92b0ee2225c7bcfd8cd8a657e4abe4dadfae51588e7567b39846d7e47d98dfb4b178a23989eb753a36dc6451a18c5adce7a38bc41f5df7b2de19e4a759 + version: 2.14.1 + resolution: "bowser@npm:2.14.1" + checksum: 10/a002f0795ef360314c75552b94daa42f74473f38b34255cfa959779e875806ef8e41b24ec63a533717798c8ef70bb991aef3037a2bb5dd32e8f507b39a509163 languageName: node linkType: hard "brace-expansion@npm:^1.1.7": - version: 1.1.12 - resolution: "brace-expansion@npm:1.1.12" + version: 1.1.15 + resolution: "brace-expansion@npm:1.1.15" dependencies: balanced-match: "npm:^1.0.0" concat-map: "npm:0.0.1" - checksum: 10/12cb6d6310629e3048cadb003e1aca4d8c9bb5c67c3c321bafdd7e7a50155de081f78ea3e0ed92ecc75a9015e784f301efc8132383132f4f7904ad1ac529c562 + checksum: 10/f2a950034e670523cc186da61aabe3beab74b1b8a7c74a756bf6b172dad1917312f255d9ec46906c9f0cab530868095d8c143918576930dd0e1323c3803850f1 languageName: node linkType: hard -"brace-expansion@npm:^2.0.1": - version: 2.0.2 - resolution: "brace-expansion@npm:2.0.2" +"brace-expansion@npm:^2.0.1, brace-expansion@npm:^2.0.2": + version: 2.1.1 + resolution: "brace-expansion@npm:2.1.1" dependencies: balanced-match: "npm:^1.0.0" - checksum: 10/01dff195e3646bc4b0d27b63d9bab84d2ebc06121ff5013ad6e5356daa5a9d6b60fa26cf73c74797f2dc3fbec112af13578d51f75228c1112b26c790a87b0488 + checksum: 10/4681c533dc4e6c77b3ad795b38683d297fd03c739a17bfb2a338529fa7dcf4540683a79dcd662905f4c5b0db7cfda18daafcd18dd1bbf7c3b076fe0c9c3487eb + languageName: node + linkType: hard + +"brace-expansion@npm:^5.0.5": + version: 5.0.6 + resolution: "brace-expansion@npm:5.0.6" + dependencies: + balanced-match: "npm:^4.0.2" + checksum: 10/a7acf120fefa79e9d7c9c92898114f57c07596a3920197f3c5917e6a628b04220a5f7f9618c30bdd973a6576a32113b99f9c3f1c8245ccc399dd2a9a718d81d8 languageName: node linkType: hard @@ -7267,21 +6432,21 @@ __metadata: linkType: hard "browserslist@npm:^4.24.0": - version: 4.28.1 - resolution: "browserslist@npm:4.28.1" - dependencies: - baseline-browser-mapping: "npm:^2.9.0" - caniuse-lite: "npm:^1.0.30001759" - electron-to-chromium: "npm:^1.5.263" - node-releases: "npm:^2.0.27" - update-browserslist-db: "npm:^1.2.0" + version: 4.28.2 + resolution: "browserslist@npm:4.28.2" + dependencies: + baseline-browser-mapping: "npm:^2.10.12" + caniuse-lite: "npm:^1.0.30001782" + electron-to-chromium: "npm:^1.5.328" + node-releases: "npm:^2.0.36" + update-browserslist-db: "npm:^1.2.3" bin: browserslist: cli.js - checksum: 10/64f2a97de4bce8473c0e5ae0af8d76d1ead07a5b05fc6bc87b848678bb9c3a91ae787b27aa98cdd33fc00779607e6c156000bed58fefb9cf8e4c5a183b994cdb + checksum: 10/cff88386e5b5ba5614c9063bd32ef94865bba22b6a381844c7d09ea1eea62a2247e7106e516abdbfda6b75b9986044c991dfe45f92f10add5ad63dccc07589ec languageName: node linkType: hard -"bs58@npm:6.0.0": +"bs58@npm:6.0.0, bs58@npm:^6.0.0": version: 6.0.0 resolution: "bs58@npm:6.0.0" dependencies: @@ -7290,15 +6455,6 @@ __metadata: languageName: node linkType: hard -"bs58@npm:^4.0.0, bs58@npm:^4.0.1": - version: 4.0.1 - resolution: "bs58@npm:4.0.1" - dependencies: - base-x: "npm:^3.0.2" - checksum: 10/b3c5365bb9e0c561e1a82f1a2d809a1a692059fae016be233a6127ad2f50a6b986467c3a50669ce4c18929dcccb297c5909314dd347a25a68c21b68eb3e95ac2 - languageName: node - linkType: hard - "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" @@ -7306,7 +6462,7 @@ __metadata: languageName: node linkType: hard -"buffer@npm:6.0.3, buffer@npm:^6.0.3, buffer@npm:~6.0.3": +"buffer@npm:6.0.3, buffer@npm:^6.0.3": version: 6.0.3 resolution: "buffer@npm:6.0.3" dependencies: @@ -7316,7 +6472,7 @@ __metadata: languageName: node linkType: hard -"bufferutil@npm:^4.0.1, bufferutil@npm:^4.0.8": +"bufferutil@npm:^4.0.8": version: 4.1.0 resolution: "bufferutil@npm:4.1.0" dependencies: @@ -7358,25 +6514,6 @@ __metadata: languageName: node linkType: hard -"cacache@npm:^20.0.1": - version: 20.0.3 - resolution: "cacache@npm:20.0.3" - dependencies: - "@npmcli/fs": "npm:^5.0.0" - fs-minipass: "npm:^3.0.0" - glob: "npm:^13.0.0" - lru-cache: "npm:^11.1.0" - minipass: "npm:^7.0.3" - minipass-collect: "npm:^2.0.1" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - p-map: "npm:^7.0.2" - ssri: "npm:^13.0.0" - unique-filename: "npm:^5.0.0" - checksum: 10/388a0169970df9d051da30437f93f81b7e91efb570ad0ff2b8fde33279fbe726c1bc8e8e2b9c05053ffb4f563854c73db395e8712e3b62347a1bc4f7fb8899ff - languageName: node - linkType: hard - "cacheable-lookup@npm:^7.0.0": version: 7.0.0 resolution: "cacheable-lookup@npm:7.0.0" @@ -7399,7 +6536,7 @@ __metadata: languageName: node linkType: hard -"call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": +"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": version: 1.0.2 resolution: "call-bind-apply-helpers@npm:1.0.2" dependencies: @@ -7409,15 +6546,15 @@ __metadata: languageName: node linkType: hard -"call-bind@npm:^1.0.8": - version: 1.0.8 - resolution: "call-bind@npm:1.0.8" +"call-bind@npm:^1.0.9": + version: 1.0.9 + resolution: "call-bind@npm:1.0.9" dependencies: - call-bind-apply-helpers: "npm:^1.0.0" - es-define-property: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.4" + call-bind-apply-helpers: "npm:^1.0.2" + es-define-property: "npm:^1.0.1" + get-intrinsic: "npm:^1.3.0" set-function-length: "npm:^1.2.2" - checksum: 10/659b03c79bbfccf0cde3a79e7d52570724d7290209823e1ca5088f94b52192dc1836b82a324d0144612f816abb2f1734447438e38d9dafe0b3f82c2a1b9e3bce + checksum: 10/25b1a98d6158f0adf9fface594ca82be4e3ed481d8ff7f36ad1fccb0c8377e38c6a04ff3248693723222d378677e93077c739defc8a6741c82b7e00bcee1245d languageName: node linkType: hard @@ -7462,10 +6599,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001759": - version: 1.0.30001765 - resolution: "caniuse-lite@npm:1.0.30001765" - checksum: 10/d7e90e3c02bbab9aa69c28c8c609284d51275396b8e5646ad9fd89b7bc7adcfcd1f5414be25399adde985eadf8d0041fda6d86c1e58384b69b5a9f03a916eb18 +"caniuse-lite@npm:^1.0.30001782": + version: 1.0.30001793 + resolution: "caniuse-lite@npm:1.0.30001793" + checksum: 10/5a1ac39f2f174e86d8320f394a5dfbeab98041722b13d02a21fe47afc2723bc754ea3716a1f276f8462bcbbc3016e82e6f155ebde0881e537af463b5eac1816b languageName: node linkType: hard @@ -7516,14 +6653,14 @@ __metadata: languageName: node linkType: hard -"chai@npm:^6.2.1": +"chai@npm:^6.2.2": version: 6.2.2 resolution: "chai@npm:6.2.2" checksum: 10/13cda42cc40aa46da04a41cf7e5c61df6b6ae0b4e8a8c8b40e04d6947e4d7951377ea8c14f9fa7fe5aaa9e8bd9ba414f11288dc958d4cee6f5221b9436f2778f languageName: node linkType: hard -"chalk@npm:5.6.2, chalk@npm:^5.4.1": +"chalk@npm:5.6.2": version: 5.6.2 resolution: "chalk@npm:5.6.2" checksum: 10/1b2f48f6fba1370670d5610f9cd54c391d6ede28f4b7062dd38244ea5768777af72e5be6b74fb6c6d54cb84c4a2dff3f3afa9b7cb5948f7f022cfd3d087989e0 @@ -7627,13 +6764,6 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^3.7.0": - version: 3.9.0 - resolution: "ci-info@npm:3.9.0" - checksum: 10/75bc67902b4d1c7b435497adeb91598f6d52a3389398e44294f6601b20cfef32cf2176f7be0eb961d9e085bb333a8a5cae121cb22f81cf238ae7f58eb80e9397 - languageName: node - linkType: hard - "citty@npm:^0.1.6": version: 0.1.6 resolution: "citty@npm:0.1.6" @@ -7643,10 +6773,10 @@ __metadata: languageName: node linkType: hard -"citty@npm:^0.2.0": - version: 0.2.0 - resolution: "citty@npm:0.2.0" - checksum: 10/023f84b0610e9b7717f930b8d419a42fa079cc6178f6dedfd8b2d13d7cc4898d0b09c1a9e13480200d660201d924e65131d59bc432497a7c185fc6d389ca4b05 +"citty@npm:^0.2.2": + version: 0.2.2 + resolution: "citty@npm:0.2.2" + checksum: 10/5e17b66ddb65274170e1ab83baec49ef70a07074b4323e29595063d06dfb7710527f3f403b2647acef06eb66871c8ba81d361d24c7166540f78815572da15221 languageName: node linkType: hard @@ -7766,14 +6896,14 @@ __metadata: languageName: node linkType: hard -"commander@npm:14.0.2, commander@npm:^14.0.0": +"commander@npm:14.0.2": version: 14.0.2 resolution: "commander@npm:14.0.2" checksum: 10/2d202db5e5f9bb770112a3c1579b893d17ac6f6d932183077308bdd96d0f87f0bbe6a68b5b9ed2cf3b2514be6bb7de637480703c0e2db9741ee1b383237deb26 languageName: node linkType: hard -"commander@npm:^2.20.0, commander@npm:^2.20.3": +"commander@npm:^2.20.0": version: 2.20.3 resolution: "commander@npm:2.20.3" checksum: 10/90c5b6898610cd075984c58c4f88418a4fb44af08c1b1415e9854c03171bec31b336b7f3e4cefe33de994b3f12b03c5e2d638da4316df83593b9e82554e7e95b @@ -7787,10 +6917,10 @@ __metadata: languageName: node linkType: hard -"confbox@npm:^0.2.2": - version: 0.2.2 - resolution: "confbox@npm:0.2.2" - checksum: 10/988c7216f9b5aee5d8a8f32153a9164e1b58d92d8335c5daa323fd3fdee91f742ffc25f6c28b059474b6319204085eca985ab14c5a246988dc7ef1fe29414108 +"confbox@npm:^0.2.2, confbox@npm:^0.2.4": + version: 0.2.4 + resolution: "confbox@npm:0.2.4" + checksum: 10/10243036f2eca8f02c85f1c8c99f492d2b690e41b5fb9c6bf91afbaca8972eb760bf9fafb7b669433c1ea0c98f12e910d4d1e73b017cd06b72150d080a2c78b6 languageName: node linkType: hard @@ -7823,9 +6953,9 @@ __metadata: linkType: hard "content-disposition@npm:^1.0.0": - version: 1.0.1 - resolution: "content-disposition@npm:1.0.1" - checksum: 10/0718d861dfec56f532fd9acd714f173782ce5257b243344fecab5196621746cf8623bf1c833441612f1ac84559c546b59277cf0e91c3a646b0712a806decb1c8 + version: 1.1.0 + resolution: "content-disposition@npm:1.1.0" + checksum: 10/c4f65e3c001a4a8eb87d0d24c0f112abb139836fb13b8ea67276715e7dce09570ef666ba7848ee8b660d467e6588d030c8ed7e8d0128db6ca78a0800dcd8c7a8 languageName: node linkType: hard @@ -7836,6 +6966,13 @@ __metadata: languageName: node linkType: hard +"content-type@npm:^2.0.0": + version: 2.0.0 + resolution: "content-type@npm:2.0.0" + checksum: 10/0bbb276b790ba7e86c479c7d69fae1861b2e908ff3ce2cb01975b516f93eede2216d242902ed6c5b15cd554014611ce9dfdcf51cd35b16569e45a979e50d0cef + languageName: node + linkType: hard + "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -7843,10 +6980,10 @@ __metadata: languageName: node linkType: hard -"cookie-es@npm:^1.2.2": - version: 1.2.2 - resolution: "cookie-es@npm:1.2.2" - checksum: 10/0fd742c11caa185928e450543f84df62d4b2c1fc7b5041196b57b7db04e1c6ac6585fb40e4f579a2819efefd2d6a9cbb4d17f71240d05f4dcd8f74ae81341a20 +"cookie-es@npm:^1.2.3": + version: 1.2.3 + resolution: "cookie-es@npm:1.2.3" + checksum: 10/899f72d6354de72522ccf01c990c4f6caf8dd3180bd3cb426ea4be495af5acab6e74631e319b969285001ddecf9ea8a0657f71bf4dcd433238f2acc638f36d6f languageName: node linkType: hard @@ -7942,13 +7079,6 @@ __metadata: languageName: node linkType: hard -"css.escape@npm:^1.5.1": - version: 1.5.1 - resolution: "css.escape@npm:1.5.1" - checksum: 10/f6d38088d870a961794a2580b2b2af1027731bb43261cfdce14f19238a88664b351cc8978abc20f06cc6bbde725699dec8deb6fe9816b139fc3f2af28719e774 - languageName: node - linkType: hard - "cssesc@npm:^3.0.0": version: 3.0.0 resolution: "cssesc@npm:3.0.0" @@ -7975,9 +7105,9 @@ __metadata: linkType: hard "date-fns@npm:^4.1.0": - version: 4.1.0 - resolution: "date-fns@npm:4.1.0" - checksum: 10/d5f6e9de5bbc52310f786099e18609289ed5e30af60a71e0646784c8185ddd1d0eebcf7c96b7faaaefc4a8366f3a3a4244d099b6d0866ee2bec80d1361e64342 + version: 4.4.0 + resolution: "date-fns@npm:4.4.0" + checksum: 10/ae702acea42fb8452abe74f6d133c2360de9a14f00985645684b0df9c12280276649e95b52298a4fd7dabcc3b38799eb111107da99320d1cd94ba1d8a3d1c174 languageName: node linkType: hard @@ -7988,27 +7118,27 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.0, debug@npm:^4.4.1, debug@npm:^4.4.3, debug@npm:~4.4.1": - version: 4.4.3 - resolution: "debug@npm:4.4.3" +"debug@npm:4.3.4": + version: 4.3.4 + resolution: "debug@npm:4.3.4" dependencies: - ms: "npm:^2.1.3" + ms: "npm:2.1.2" peerDependenciesMeta: supports-color: optional: true - checksum: 10/9ada3434ea2993800bd9a1e320bd4aa7af69659fb51cca685d390949434bc0a8873c21ed7c9b852af6f2455a55c6d050aa3937d52b3c69f796dab666f762acad + checksum: 10/0073c3bcbd9cb7d71dd5f6b55be8701af42df3e56e911186dfa46fac3a5b9eb7ce7f377dd1d3be6db8977221f8eb333d945216f645cf56f6b688cd484837d255 languageName: node linkType: hard -"debug@npm:4.3.4": - version: 4.3.4 - resolution: "debug@npm:4.3.4" +"debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.0, debug@npm:^4.4.1, debug@npm:^4.4.3, debug@npm:~4.4.1": + version: 4.4.3 + resolution: "debug@npm:4.4.3" dependencies: - ms: "npm:2.1.2" + ms: "npm:^2.1.3" peerDependenciesMeta: supports-color: optional: true - checksum: 10/0073c3bcbd9cb7d71dd5f6b55be8701af42df3e56e911186dfa46fac3a5b9eb7ce7f377dd1d3be6db8977221f8eb333d945216f645cf56f6b688cd484837d255 + checksum: 10/9ada3434ea2993800bd9a1e320bd4aa7af69659fb51cca685d390949434bc0a8873c21ed7c9b852af6f2455a55c6d050aa3937d52b3c69f796dab666f762acad languageName: node linkType: hard @@ -8076,17 +7206,10 @@ __metadata: languageName: node linkType: hard -"defu@npm:^6.1.4": - version: 6.1.4 - resolution: "defu@npm:6.1.4" - checksum: 10/aeffdb47300f45b4fdef1c5bd3880ac18ea7a1fd5b8a8faf8df29350ff03bf16dd34f9800205cab513d476e4c0a3783aa0cff0a433aff0ac84a67ddc4c8a2d64 - languageName: node - linkType: hard - -"delay@npm:^5.0.0": - version: 5.0.0 - resolution: "delay@npm:5.0.0" - checksum: 10/62f151151ecfde0d9afbb8a6be37a6d103c4cb24f35a20ef3fe56f920b0d0d0bb02bc9c0a3084d0179ef669ca332b91155f2ee4d9854622cd2cdba5fc95285f9 +"defu@npm:^6.1.4, defu@npm:^6.1.6": + version: 6.1.7 + resolution: "defu@npm:6.1.7" + checksum: 10/09480a5fbe6318f622f30017f9386df6ae92ed895fb1ccc61e1ff0d5016b28a321c751749fdd52c996ddd4eafc2c95b77dc0c8cc109881a231c23c7fd630deb9 languageName: node linkType: hard @@ -8104,7 +7227,7 @@ __metadata: languageName: node linkType: hard -"dequal@npm:^2.0.0, dequal@npm:^2.0.3": +"dequal@npm:^2.0.0": version: 2.0.3 resolution: "dequal@npm:2.0.3" checksum: 10/6ff05a7561f33603df87c45e389c9ac0a95e3c056be3da1a0c4702149e3a7f6fe5ffbb294478687ba51a9e95f3a60e8b6b9005993acd79c292c7d15f71964b6b @@ -8148,6 +7271,13 @@ __metadata: languageName: node linkType: hard +"detect-libc@npm:^2.0.3": + version: 2.1.2 + resolution: "detect-libc@npm:2.1.2" + checksum: 10/b736c8d97d5d46164c0d1bed53eb4e6a3b1d8530d460211e2d52f1c552875e706c58a5376854e4e54f8b828c9cada58c855288c968522eb93ac7696d65970766 + languageName: node + linkType: hard + "detect-newline@npm:^4.0.0, detect-newline@npm:^4.0.1": version: 4.0.1 resolution: "detect-newline@npm:4.0.1" @@ -8187,20 +7317,6 @@ __metadata: languageName: node linkType: hard -"dom-accessibility-api@npm:^0.5.9": - version: 0.5.16 - resolution: "dom-accessibility-api@npm:0.5.16" - checksum: 10/377b4a7f9eae0a5d72e1068c369c99e0e4ca17fdfd5219f3abd32a73a590749a267475a59d7b03a891f9b673c27429133a818c44b2e47e32fec024b34274e2ca - languageName: node - linkType: hard - -"dom-accessibility-api@npm:^0.6.3": - version: 0.6.3 - resolution: "dom-accessibility-api@npm:0.6.3" - checksum: 10/83d3371f8226487fbad36e160d44f1d9017fb26d46faba6a06fcad15f34633fc827b8c3e99d49f71d5f3253d866e2131826866fd0a3c86626f8eccfc361881ff - languageName: node - linkType: hard - "dom-helpers@npm:^5.0.1": version: 5.2.1 resolution: "dom-helpers@npm:5.2.1" @@ -8251,22 +7367,15 @@ __metadata: languageName: node linkType: hard -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 - resolution: "eastasianwidth@npm:0.2.0" - checksum: 10/9b1d3e1baefeaf7d70799db8774149cef33b97183a6addceeba0cf6b85ba23ee2686f302f14482006df32df75d32b17c509c143a3689627929e4a8efaf483952 - languageName: node - linkType: hard - "eciesjs@npm:^0.4.11": - version: 0.4.16 - resolution: "eciesjs@npm:0.4.16" + version: 0.4.18 + resolution: "eciesjs@npm:0.4.18" dependencies: - "@ecies/ciphers": "npm:^0.2.4" + "@ecies/ciphers": "npm:^0.2.5" "@noble/ciphers": "npm:^1.3.0" "@noble/curves": "npm:^1.9.7" "@noble/hashes": "npm:^1.8.0" - checksum: 10/0b179dc8ad470b976edb1c7f59770c934a36854d22ccab979fea32ae559f017d843c468f8a551523877251e7340df1babef0777acebcf6518341337d8ed7bb94 + checksum: 10/c2e58ce1ce67c7959da064372081bea38b9769a1db61bf91e084001a3906ce7cc1ce77536737446eb83365ec567e50c879209b5647a00d45c9727dd3a79b0543 languageName: node linkType: hard @@ -8277,13 +7386,13 @@ __metadata: languageName: node linkType: hard -"effect@npm:3.18.4": - version: 3.18.4 - resolution: "effect@npm:3.18.4" +"effect@npm:3.21.0": + version: 3.21.0 + resolution: "effect@npm:3.21.0" dependencies: "@standard-schema/spec": "npm:^1.0.0" fast-check: "npm:^3.23.1" - checksum: 10/aa1d55bbb9f52e2e0899a169545aa41a8d7487f710a625aa411aec3421152084b39cf8ceb5780884df481d0790d67079775588d0b3451a7827e288801c76dadb + checksum: 10/c920efb24ae1f5225069fa47334817372f1b4f37b47f878a7aaf17d0cf870338e21144b3fc6dd6d35044f404bb8313071420bc9139831670995f1f8ebfc70a61 languageName: node linkType: hard @@ -8298,10 +7407,10 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.5.263": - version: 1.5.277 - resolution: "electron-to-chromium@npm:1.5.277" - checksum: 10/5c63c3a2b414d268a7b4292b2215d8bd2484bc6af0b9803c51dde02c2cf8575c653fb6f5f74f45abf4ac00cffd678eeeda4ac5e6bc6d7116ff0d52b42ab60066 +"electron-to-chromium@npm:^1.5.328": + version: 1.5.365 + resolution: "electron-to-chromium@npm:1.5.365" + checksum: 10/f184e2d75cb0ce70a26cadcbed92cc828be81a5f08890727cc6b28ea7704fab49ec5f78dd234477a4679536b1ecec335208c6a7dba7c10d9687d88b788ac10fb languageName: node linkType: hard @@ -8312,13 +7421,6 @@ __metadata: languageName: node linkType: hard -"emoji-regex@npm:^9.2.2": - version: 9.2.2 - resolution: "emoji-regex@npm:9.2.2" - checksum: 10/915acf859cea7131dac1b2b5c9c8e35c4849e325a1d114c30adb8cd615970f6dca0e27f64f3a4949d7d6ed86ecd79a1c5c63f02e697513cddd7b5835c90948b8 - languageName: node - linkType: hard - "empathic@npm:2.0.0": version: 2.0.0 resolution: "empathic@npm:2.0.0" @@ -8340,15 +7442,6 @@ __metadata: languageName: node linkType: hard -"encoding@npm:^0.1.13": - version: 0.1.13 - resolution: "encoding@npm:0.1.13" - dependencies: - iconv-lite: "npm:^0.6.2" - checksum: 10/bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f - languageName: node - linkType: hard - "end-of-stream@npm:^1.1.0, end-of-stream@npm:^1.4.0, end-of-stream@npm:^1.4.1": version: 1.4.5 resolution: "end-of-stream@npm:1.4.5" @@ -8359,15 +7452,15 @@ __metadata: linkType: hard "engine.io-client@npm:~6.6.1": - version: 6.6.4 - resolution: "engine.io-client@npm:6.6.4" + version: 6.6.5 + resolution: "engine.io-client@npm:6.6.5" dependencies: "@socket.io/component-emitter": "npm:~3.1.0" debug: "npm:~4.4.1" engine.io-parser: "npm:~5.2.1" - ws: "npm:~8.18.3" + ws: "npm:~8.20.1" xmlhttprequest-ssl: "npm:~2.1.1" - checksum: 10/1e45a6f5453d7112173ab593c791f1d17f7fba73774309adc9049428ab8318f71b5dd9b362aa5a05a11d1de338d46ef7b9777602357aa14894abdc100a50802d + checksum: 10/604f4db1477e6d04c833d70abfb2213879b4c67c36bc151658a9b945acd1485b0e22b8d8b22ee04ae8d7c2fd6ddb4e98317d3be74771812edf2020c1b04d6a49 languageName: node linkType: hard @@ -8395,13 +7488,6 @@ __metadata: languageName: node linkType: hard -"err-code@npm:^2.0.2": - version: 2.0.3 - resolution: "err-code@npm:2.0.3" - checksum: 10/1d20d825cdcce8d811bfbe86340f4755c02655a7feb2f13f8c880566d9d72a3f6c92c192a6867632e490d6da67b678271f46e01044996a6443e870331100dfdd - languageName: node - linkType: hard - "error-ex@npm:^1.3.1": version: 1.3.4 resolution: "error-ex@npm:1.3.4" @@ -8425,19 +7511,19 @@ __metadata: languageName: node linkType: hard -"es-module-lexer@npm:^1.7.0": - version: 1.7.0 - resolution: "es-module-lexer@npm:1.7.0" - checksum: 10/b6f3e576a3fed4d82b0d0ad4bbf6b3a5ad694d2e7ce8c4a069560da3db6399381eaba703616a182b16dde50ce998af64e07dcf49f2ae48153b9e07be3f107087 +"es-module-lexer@npm:^2.0.0": + version: 2.1.0 + resolution: "es-module-lexer@npm:2.1.0" + checksum: 10/554c4374e78a812a1fa3673871ce7d42236438c414ea80c2ec35521cd9bb26d1d9155287529057d07431fd91df50d6a26d9bee5afd755fb7f6f7c81905a03956 languageName: node linkType: hard "es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": - version: 1.1.1 - resolution: "es-object-atoms@npm:1.1.1" + version: 1.1.2 + resolution: "es-object-atoms@npm:1.1.2" dependencies: es-errors: "npm:^1.3.0" - checksum: 10/54fe77de288451dae51c37bfbfe3ec86732dc3778f98f3eb3bdb4bf48063b2c0b8f9c93542656986149d08aa5be3204286e2276053d19582b76753f1a2728867 + checksum: 10/70041de72ab8996df74c17775cdedb8a0c36eb09a4111921d974f7d018af963023bb035a328b5772c2851daa40fb49f52313be0418763a975cb42cb6fe723255 languageName: node linkType: hard @@ -8465,52 +7551,125 @@ __metadata: languageName: node linkType: hard -"es6-promise@npm:^4.0.3": - version: 4.2.8 - resolution: "es6-promise@npm:4.2.8" - checksum: 10/b250c55523c496c43c9216c2646e58ec182b819e036fe5eb8d83fa16f044ecc6b8dcefc88ace2097be3d3c4d02b6aa8eeae1a66deeaf13e7bee905ebabb350a3 - languageName: node - linkType: hard - -"es6-promisify@npm:^5.0.0": - version: 5.0.0 - resolution: "es6-promisify@npm:5.0.0" - dependencies: - es6-promise: "npm:^4.0.3" - checksum: 10/fbed9d791598831413be84a5374eca8c24800ec71a16c1c528c43a98e2dadfb99331483d83ae6094ddb9b87e6f799a15d1553cebf756047e0865c753bc346b92 - languageName: node - linkType: hard - -"esbuild@npm:^0.27.0, esbuild@npm:~0.27.0": - version: 0.27.2 - resolution: "esbuild@npm:0.27.2" - dependencies: - "@esbuild/aix-ppc64": "npm:0.27.2" - "@esbuild/android-arm": "npm:0.27.2" - "@esbuild/android-arm64": "npm:0.27.2" - "@esbuild/android-x64": "npm:0.27.2" - "@esbuild/darwin-arm64": "npm:0.27.2" - "@esbuild/darwin-x64": "npm:0.27.2" - "@esbuild/freebsd-arm64": "npm:0.27.2" - "@esbuild/freebsd-x64": "npm:0.27.2" - "@esbuild/linux-arm": "npm:0.27.2" - "@esbuild/linux-arm64": "npm:0.27.2" - "@esbuild/linux-ia32": "npm:0.27.2" - "@esbuild/linux-loong64": "npm:0.27.2" - "@esbuild/linux-mips64el": "npm:0.27.2" - "@esbuild/linux-ppc64": "npm:0.27.2" - "@esbuild/linux-riscv64": "npm:0.27.2" - "@esbuild/linux-s390x": "npm:0.27.2" - "@esbuild/linux-x64": "npm:0.27.2" - "@esbuild/netbsd-arm64": "npm:0.27.2" - "@esbuild/netbsd-x64": "npm:0.27.2" - "@esbuild/openbsd-arm64": "npm:0.27.2" - "@esbuild/openbsd-x64": "npm:0.27.2" - "@esbuild/openharmony-arm64": "npm:0.27.2" - "@esbuild/sunos-x64": "npm:0.27.2" - "@esbuild/win32-arm64": "npm:0.27.2" - "@esbuild/win32-ia32": "npm:0.27.2" - "@esbuild/win32-x64": "npm:0.27.2" +"esbuild@npm:^0.27.0": + version: 0.27.7 + resolution: "esbuild@npm:0.27.7" + dependencies: + "@esbuild/aix-ppc64": "npm:0.27.7" + "@esbuild/android-arm": "npm:0.27.7" + "@esbuild/android-arm64": "npm:0.27.7" + "@esbuild/android-x64": "npm:0.27.7" + "@esbuild/darwin-arm64": "npm:0.27.7" + "@esbuild/darwin-x64": "npm:0.27.7" + "@esbuild/freebsd-arm64": "npm:0.27.7" + "@esbuild/freebsd-x64": "npm:0.27.7" + "@esbuild/linux-arm": "npm:0.27.7" + "@esbuild/linux-arm64": "npm:0.27.7" + "@esbuild/linux-ia32": "npm:0.27.7" + "@esbuild/linux-loong64": "npm:0.27.7" + "@esbuild/linux-mips64el": "npm:0.27.7" + "@esbuild/linux-ppc64": "npm:0.27.7" + "@esbuild/linux-riscv64": "npm:0.27.7" + "@esbuild/linux-s390x": "npm:0.27.7" + "@esbuild/linux-x64": "npm:0.27.7" + "@esbuild/netbsd-arm64": "npm:0.27.7" + "@esbuild/netbsd-x64": "npm:0.27.7" + "@esbuild/openbsd-arm64": "npm:0.27.7" + "@esbuild/openbsd-x64": "npm:0.27.7" + "@esbuild/openharmony-arm64": "npm:0.27.7" + "@esbuild/sunos-x64": "npm:0.27.7" + "@esbuild/win32-arm64": "npm:0.27.7" + "@esbuild/win32-ia32": "npm:0.27.7" + "@esbuild/win32-x64": "npm:0.27.7" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10/262b16c4a33cb70e9f054759a7ce420541649315eef7b064172c795021ccce322e56c3f5fd52e8842873f1c23745f3ab62311a24860950bd5406ba77b36b8529 + languageName: node + linkType: hard + +"esbuild@npm:~0.28.0": + version: 0.28.0 + resolution: "esbuild@npm:0.28.0" + dependencies: + "@esbuild/aix-ppc64": "npm:0.28.0" + "@esbuild/android-arm": "npm:0.28.0" + "@esbuild/android-arm64": "npm:0.28.0" + "@esbuild/android-x64": "npm:0.28.0" + "@esbuild/darwin-arm64": "npm:0.28.0" + "@esbuild/darwin-x64": "npm:0.28.0" + "@esbuild/freebsd-arm64": "npm:0.28.0" + "@esbuild/freebsd-x64": "npm:0.28.0" + "@esbuild/linux-arm": "npm:0.28.0" + "@esbuild/linux-arm64": "npm:0.28.0" + "@esbuild/linux-ia32": "npm:0.28.0" + "@esbuild/linux-loong64": "npm:0.28.0" + "@esbuild/linux-mips64el": "npm:0.28.0" + "@esbuild/linux-ppc64": "npm:0.28.0" + "@esbuild/linux-riscv64": "npm:0.28.0" + "@esbuild/linux-s390x": "npm:0.28.0" + "@esbuild/linux-x64": "npm:0.28.0" + "@esbuild/netbsd-arm64": "npm:0.28.0" + "@esbuild/netbsd-x64": "npm:0.28.0" + "@esbuild/openbsd-arm64": "npm:0.28.0" + "@esbuild/openbsd-x64": "npm:0.28.0" + "@esbuild/openharmony-arm64": "npm:0.28.0" + "@esbuild/sunos-x64": "npm:0.28.0" + "@esbuild/win32-arm64": "npm:0.28.0" + "@esbuild/win32-ia32": "npm:0.28.0" + "@esbuild/win32-x64": "npm:0.28.0" dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -8566,7 +7725,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10/7f1229328b0efc63c4184a61a7eb303df1e99818cc1d9e309fb92600703008e69821e8e984e9e9f54a627da14e0960d561db3a93029482ef96dc82dd267a60c2 + checksum: 10/49eafc8906cc4a760a1704556bd3b301f808fcdcf2725190383f151741226bf2a2898a03da75a06a896d6217dadc4f3f3168983557ee31bae602e2e37779a83a languageName: node linkType: hard @@ -8610,11 +7769,11 @@ __metadata: linkType: hard "eslint-plugin-prettier@npm:^5.5.5": - version: 5.5.5 - resolution: "eslint-plugin-prettier@npm:5.5.5" + version: 5.5.6 + resolution: "eslint-plugin-prettier@npm:5.5.6" dependencies: prettier-linter-helpers: "npm:^1.0.1" - synckit: "npm:^0.11.12" + synckit: "npm:^0.11.13" peerDependencies: "@types/eslint": ">=8.0.0" eslint: ">=8.0.0" @@ -8625,7 +7784,7 @@ __metadata: optional: true eslint-config-prettier: optional: true - checksum: 10/36c22c2fa2fd7c61ed292af1280e1d8f94dfe1671eacc5a503a249ca4b27fd226dbf6a1820457d611915926946f42729488d2dc7a5c320601e6cf1fad0d28f66 + checksum: 10/18a0189e084dd5f1e4e3944a8ff89f20d69c14f100965033a94edd8de16fb7abdcbf226fbc40f27b7ac6cfdb779065272dd8a9e6ca34ed86a59d895e630bd48b languageName: node linkType: hard @@ -8653,23 +7812,30 @@ __metadata: languageName: node linkType: hard +"eslint-visitor-keys@npm:^5.0.0": + version: 5.0.1 + resolution: "eslint-visitor-keys@npm:5.0.1" + checksum: 10/f9cc1a57b75e0ef949545cac33d01e8367e302de4c1483266ed4d8646ee5c306376660196bbb38b004e767b7043d1e661cb4336b49eff634a1bbe75c1db709ec + languageName: node + linkType: hard + "eslint@npm:^9.39.2": - version: 9.39.2 - resolution: "eslint@npm:9.39.2" + version: 9.39.4 + resolution: "eslint@npm:9.39.4" dependencies: "@eslint-community/eslint-utils": "npm:^4.8.0" "@eslint-community/regexpp": "npm:^4.12.1" - "@eslint/config-array": "npm:^0.21.1" + "@eslint/config-array": "npm:^0.21.2" "@eslint/config-helpers": "npm:^0.4.2" "@eslint/core": "npm:^0.17.0" - "@eslint/eslintrc": "npm:^3.3.1" - "@eslint/js": "npm:9.39.2" + "@eslint/eslintrc": "npm:^3.3.5" + "@eslint/js": "npm:9.39.4" "@eslint/plugin-kit": "npm:^0.4.1" "@humanfs/node": "npm:^0.16.6" "@humanwhocodes/module-importer": "npm:^1.0.1" "@humanwhocodes/retry": "npm:^0.4.2" "@types/estree": "npm:^1.0.6" - ajv: "npm:^6.12.4" + ajv: "npm:^6.14.0" chalk: "npm:^4.0.0" cross-spawn: "npm:^7.0.6" debug: "npm:^4.3.2" @@ -8688,7 +7854,7 @@ __metadata: is-glob: "npm:^4.0.0" json-stable-stringify-without-jsonify: "npm:^1.0.1" lodash.merge: "npm:^4.6.2" - minimatch: "npm:^3.1.2" + minimatch: "npm:^3.1.5" natural-compare: "npm:^1.4.0" optionator: "npm:^0.9.3" peerDependencies: @@ -8698,7 +7864,7 @@ __metadata: optional: true bin: eslint: bin/eslint.js - checksum: 10/53ff0e9c8264e7e8d40d50fdc0c0df0b701cfc5289beedfb686c214e3e7b199702f894bbd1bb48653727bb1ecbd1147cf5f555a4ae71e1daf35020cdc9072d9f + checksum: 10/de95093d710e62e8c7e753220d985587c40f4a05247ed4393ffb6e6cb43a60e825a47fc5b4263151bb2fc5871a206a31d563ccbabdceee1711072ae12db90adf languageName: node linkType: hard @@ -8897,7 +8063,7 @@ __metadata: languageName: node linkType: hard -"expect-type@npm:^1.2.2": +"expect-type@npm:^1.3.0": version: 1.3.0 resolution: "expect-type@npm:1.3.0" checksum: 10/a5fada3d0c621649261f886e7d93e6bf80ce26d8a86e5d517e38301b8baec8450ab2cb94ba6e7a0a6bf2fc9ee55f54e1b06938ef1efa52ddcfeffbfa01acbbcc @@ -8912,13 +8078,13 @@ __metadata: linkType: hard "express-rate-limit@npm:^8.2.2": - version: 8.3.2 - resolution: "express-rate-limit@npm:8.3.2" + version: 8.5.2 + resolution: "express-rate-limit@npm:8.5.2" dependencies: - ip-address: "npm:10.1.0" + ip-address: "npm:^10.2.0" peerDependencies: express: ">= 4.11" - checksum: 10/71afac0fff29bf03117a89902953e7feafc67402332910cfb601b27da079b98f04ba551a1ef4f0ad5cf2538d9599c2649450af6d3f7505bcc7d24f7eaf765a4e + checksum: 10/de2aa4582d3b1b1d242fdb8dba7b3b1c64e3a58dfa7a40d370681c175a61321fb550c6b190d755f47cefdf28f35eaad6c99ea196f99caec8caaffc2462fea1ae languageName: node linkType: hard @@ -8958,7 +8124,7 @@ __metadata: languageName: node linkType: hard -"exsolve@npm:^1.0.7": +"exsolve@npm:^1.0.7, exsolve@npm:^1.0.8": version: 1.0.8 resolution: "exsolve@npm:1.0.8" checksum: 10/e7e8eac048af9f6856628a46df15529ab37428bdb5f7bc5b7824614383223de1aff60ebe85f44d9c8d4ee218d98c71df1a3e2d336f7d022a4dccd97a0651ec5b @@ -8989,13 +8155,6 @@ __metadata: languageName: node linkType: hard -"eyes@npm:^0.1.8": - version: 0.1.8 - resolution: "eyes@npm:0.1.8" - checksum: 10/58480c1f4c8e80ae9d4147afa0e0cc3403e5a3d1fa9e0c17dd8418f87273762c40ab035919ed407f6ed0992086495b93ff7163eb2a1027f58ae70e3c847d6c08 - languageName: node - linkType: hard - "fast-check@npm:^3.23.1": version: 3.23.2 resolution: "fast-check@npm:3.23.2" @@ -9019,7 +8178,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.3": +"fast-glob@npm:^3.2.9": version: 3.3.3 resolution: "fast-glob@npm:3.3.3" dependencies: @@ -9069,21 +8228,27 @@ __metadata: languageName: node linkType: hard -"fast-stable-stringify@npm:^1.0.0": - version: 1.0.0 - resolution: "fast-stable-stringify@npm:1.0.0" - checksum: 10/e4743ae52f621b42aa04ab4a44fec9e644dd30f476d37f9cf13e7dd95de3e427ecd1b20e6be7adaf0dea7252ed11ff72819066f939b1d491cec1e7e898524989 +"fast-xml-builder@npm:^1.1.7": + version: 1.2.0 + resolution: "fast-xml-builder@npm:1.2.0" + dependencies: + path-expression-matcher: "npm:^1.5.0" + xml-naming: "npm:^0.1.0" + checksum: 10/5948add7796879d03b6c779cbb17f2f203a41cdf23dfaaa4789c65078a36376cd0709a6586701e980e3d244ebd5fdb35db1235ccb5e4fb9e9abfd8c51e7b8813 languageName: node linkType: hard -"fast-xml-parser@npm:5.2.5": - version: 5.2.5 - resolution: "fast-xml-parser@npm:5.2.5" +"fast-xml-parser@npm:5.7.3": + version: 5.7.3 + resolution: "fast-xml-parser@npm:5.7.3" dependencies: - strnum: "npm:^2.1.0" + "@nodable/entities": "npm:^2.1.0" + fast-xml-builder: "npm:^1.1.7" + path-expression-matcher: "npm:^1.5.0" + strnum: "npm:^2.2.3" bin: fxparser: src/cli/cli.js - checksum: 10/305017cff6968a34cbac597317be1516e85c44f650f30d982c84f8c30043e81fd38d39a8810d570136c921399dd43b9ac4775bdfbbbcfee96456f3c086b48bdd + checksum: 10/00a58655d0d58c1f914c7fd8e3a94e88799c3d473e29a6d2231dc02103df069e8c6043137cbec8df1cda6525a39914d1b84455a79530f63be266876a2211251c languageName: node linkType: hard @@ -9134,11 +8299,11 @@ __metadata: linkType: hard "filelist@npm:^1.0.4": - version: 1.0.4 - resolution: "filelist@npm:1.0.4" + version: 1.0.6 + resolution: "filelist@npm:1.0.6" dependencies: minimatch: "npm:^5.0.1" - checksum: 10/4b436fa944b1508b95cffdfc8176ae6947b92825483639ef1b9a89b27d82f3f8aa22b21eed471993f92709b431670d4e015b39c087d435a61e1bb04564cf51de + checksum: 10/84a0be69efe6724c105f18c34e8a772370d9c45e53a1ba8ced7eecf4addd2c5a357347d94bfd8bfa9cbc36b09392cad70d82206305263e26bba184eea4ca8042 languageName: node linkType: hard @@ -9223,19 +8388,19 @@ __metadata: linkType: hard "flatted@npm:^3.2.9": - version: 3.4.1 - resolution: "flatted@npm:3.4.1" - checksum: 10/39a308e2ef82d2d8c80ebc74b67d4ff3f668be168137b649440b6735eb9c115d1e0c13ab0d9958b3d2ea9c85087ab7e14c14aa6f625a22b2916d89bbd91bc4a0 + version: 3.4.2 + resolution: "flatted@npm:3.4.2" + checksum: 10/a9e78fe5c2c1fcd98209a015ccee3a6caa953e01729778e83c1fe92e68601a63e1e69cd4e573010ca99eaf585a581b80ccf1018b99283e6cbc2117bcba1e030f languageName: node linkType: hard -"follow-redirects@npm:^1.15.11": - version: 1.15.11 - resolution: "follow-redirects@npm:1.15.11" +"follow-redirects@npm:^1.16.0": + version: 1.16.0 + resolution: "follow-redirects@npm:1.16.0" peerDependenciesMeta: debug: optional: true - checksum: 10/07372fd74b98c78cf4d417d68d41fdaa0be4dcacafffb9e67b1e3cf090bc4771515e65020651528faab238f10f9b9c0d9707d6c1574a6c0387c5de1042cde9ba + checksum: 10/3fbe3d80b3b544c22705d837aa5d4a0d07a740d913534a2620b0a004c610af4148e3b58723536dd099aaa1c9d3a155964bde9665d6e5cb331460809a1fc572fd languageName: node linkType: hard @@ -9248,16 +8413,6 @@ __metadata: languageName: node linkType: hard -"foreground-child@npm:^3.1.0": - version: 3.3.1 - resolution: "foreground-child@npm:3.3.1" - dependencies: - cross-spawn: "npm:^7.0.6" - signal-exit: "npm:^4.0.1" - checksum: 10/427b33f997a98073c0424e5c07169264a62cda806d8d2ded159b5b903fdfc8f0a1457e06b5fc35506497acb3f1e353f025edee796300209ac6231e80edece835 - languageName: node - linkType: hard - "form-data-encoder@npm:^2.1.2": version: 2.1.4 resolution: "form-data-encoder@npm:2.1.4" @@ -9314,15 +8469,6 @@ __metadata: languageName: node linkType: hard -"fs-minipass@npm:^3.0.0": - version: 3.0.3 - resolution: "fs-minipass@npm:3.0.3" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/af143246cf6884fe26fa281621d45cfe111d34b30535a475bfa38dafe343dadb466c047a924ffc7d6b7b18265df4110224ce3803806dbb07173bf2087b648d7f - languageName: node - linkType: hard - "fsevents@npm:2.3.2": version: 2.3.2 resolution: "fsevents@npm:2.3.2" @@ -9458,15 +8604,6 @@ __metadata: languageName: node linkType: hard -"get-tsconfig@npm:^4.7.5": - version: 4.13.0 - resolution: "get-tsconfig@npm:4.13.0" - dependencies: - resolve-pkg-maps: "npm:^1.0.0" - checksum: 10/3603c6da30e312636e4c20461e779114c9126601d1eca70ee4e36e3e3c00e3c21892d2d920027333afa2cc9e20998a436b14abe03a53cde40742581cb0e9ceb2 - languageName: node - linkType: hard - "giget@npm:^2.0.0": version: 2.0.0 resolution: "giget@npm:2.0.0" @@ -9522,30 +8659,14 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.0.0": - version: 10.5.0 - resolution: "glob@npm:10.5.0" - dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^3.1.2" - minimatch: "npm:^9.0.4" - minipass: "npm:^7.1.2" - package-json-from-dist: "npm:^1.0.0" - path-scurry: "npm:^1.11.1" - bin: - glob: dist/esm/bin.mjs - checksum: 10/ab3bccfefcc0afaedbd1f480cd0c4a2c0e322eb3f0aa7ceaa31b3f00b825069f17cf0f1fc8b6f256795074b903f37c0ade37ddda6a176aa57f1c2bbfe7240653 - languageName: node - linkType: hard - -"glob@npm:^13.0.0": - version: 13.0.0 - resolution: "glob@npm:13.0.0" +"glob@npm:^13.0.3": + version: 13.0.6 + resolution: "glob@npm:13.0.6" dependencies: - minimatch: "npm:^10.1.1" - minipass: "npm:^7.1.2" - path-scurry: "npm:^2.0.0" - checksum: 10/de390721d29ee1c9ea41e40ec2aa0de2cabafa68022e237dc4297665a5e4d650776f2573191984ea1640aba1bf0ea34eddef2d8cbfbfc2ad24b5fb0af41d8846 + minimatch: "npm:^10.2.2" + minipass: "npm:^7.1.3" + path-scurry: "npm:^2.0.2" + checksum: 10/201ad69e5f0aa74e1d8c00a481581f8b8c804b6a4fbfabeeb8541f5d756932800331daeba99b58fb9e4cd67e12ba5a7eba5b82fb476691588418060b84353214 languageName: node linkType: hard @@ -9557,9 +8678,9 @@ __metadata: linkType: hard "globals@npm:^17.1.0": - version: 17.1.0 - resolution: "globals@npm:17.1.0" - checksum: 10/6e77442a3b80b41b11fb4f986326f0487b9872dee6852cc9373e01696787889f4648d2264a125504315a645be0dde61625200e422b5b8002c106ffbabaaf8fdc + version: 17.6.0 + resolution: "globals@npm:17.6.0" + checksum: 10/2bf0febf31c942edee6f4eca7e939a9c885f8ecfb767048b1c4dd2a32008d0ab136e6076665d76b44b29c2571bbbc1681371caab05fd8ee0067c7618e841b89d languageName: node linkType: hard @@ -9624,20 +8745,20 @@ __metadata: languageName: node linkType: hard -"h3@npm:^1.15.5": - version: 1.15.8 - resolution: "h3@npm:1.15.8" +"h3@npm:^1.15.10": + version: 1.15.11 + resolution: "h3@npm:1.15.11" dependencies: - cookie-es: "npm:^1.2.2" + cookie-es: "npm:^1.2.3" crossws: "npm:^0.3.5" - defu: "npm:^6.1.4" + defu: "npm:^6.1.6" destr: "npm:^2.0.5" iron-webcrypto: "npm:^1.2.1" node-mock-http: "npm:^1.0.4" radix3: "npm:^1.1.2" ufo: "npm:^1.6.3" uncrypto: "npm:^0.1.3" - checksum: 10/016599d5de0a317da7b154f080bed99a106000856aa60d9ab39d968458dcf77c406c682d8fe610c31e6a2a29fba210a15145fd0337d8ba338027792d09e0df48 + checksum: 10/8a13eef49f076eedf1aa6b32ab9190c647cbae517ed2945c951905ef018e2949dd0baa73d0954dc17eaf432d1657e3a09a10ebe5ac5532365083d3560d17d8b5 languageName: node linkType: hard @@ -9673,12 +8794,12 @@ __metadata: languageName: node linkType: hard -"hasown@npm:^2.0.2": - version: 2.0.2 - resolution: "hasown@npm:2.0.2" +"hasown@npm:^2.0.2, hasown@npm:^2.0.3": + version: 2.0.4 + resolution: "hasown@npm:2.0.4" dependencies: function-bind: "npm:^1.1.2" - checksum: 10/7898a9c1788b2862cf0f9c345a6bec77ba4a0c0983c7f19d610c382343d4f98fa260686b225dfb1f88393a66679d2ec58ee310c1d6868c081eda7918f32cc70a + checksum: 10/13823863ae48161068b4c51606a3128451c66f14545a5169d667fe9fca168dcd38c27570c7a299e32ef844b8da3d55def7fe88602f8970d4311fb543ee88001a languageName: node linkType: hard @@ -9725,16 +8846,16 @@ __metadata: linkType: hard "helmet@npm:^8.1.0": - version: 8.1.0 - resolution: "helmet@npm:8.1.0" - checksum: 10/262e678d340bb102158f4e6ba1469a7cda1643329a50863f8fe704d5b60d9ebe6ea1e7793ed51224ae464f197dedf2fe8035df278c042e32ebc95b237fa41ad0 + version: 8.2.0 + resolution: "helmet@npm:8.2.0" + checksum: 10/bc34f2e04369625ab7c441273a1f44ee80548ee6da5fcec8b073f351daa930b02809f9fb186c7f3f80a12a3e0944f05c24eebaa642e1b5e805325ce13042d164 languageName: node linkType: hard "hono@npm:^4.10.3": - version: 4.12.9 - resolution: "hono@npm:4.12.9" - checksum: 10/2466bab60ef6ca568f1636f27e0b735ce1a7c6f3a03bb2aa5bcab5b67e3a6ed6cb59edaddb5f836fbeb627804fb4c0ac21e59e73345e9e640b3fbd765163b9ed + version: 4.12.23 + resolution: "hono@npm:4.12.23" + checksum: 10/721a7f0728fafe229ea84d5f0f3a2575b44dce5eb2047e49f4e7929257bb59511c80adefbe09637480ca3b65ad553510d7cd75c7dc696a916f141aefcbcb2667 languageName: node linkType: hard @@ -9795,16 +8916,6 @@ __metadata: languageName: node linkType: hard -"http-proxy-agent@npm:^7.0.0": - version: 7.0.2 - resolution: "http-proxy-agent@npm:7.0.2" - dependencies: - agent-base: "npm:^7.1.0" - debug: "npm:^4.3.4" - checksum: 10/d062acfa0cb82beeb558f1043c6ba770ea892b5fb7b28654dbc70ea2aeea55226dd34c02a294f6c1ca179a5aa483c4ea641846821b182edbd9cc5d89b54c6848 - languageName: node - linkType: hard - "http2-wrapper@npm:^2.1.10": version: 2.2.1 resolution: "http2-wrapper@npm:2.2.1" @@ -9815,16 +8926,6 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.1": - version: 7.0.6 - resolution: "https-proxy-agent@npm:7.0.6" - dependencies: - agent-base: "npm:^7.1.2" - debug: "npm:4" - checksum: 10/784b628cbd55b25542a9d85033bdfd03d4eda630fb8b3c9477959367f3be95dc476ed2ecbb9836c359c7c698027fc7b45723a302324433590f45d6c1706e8c13 - languageName: node - linkType: hard - "human-id@npm:^4.1.1": version: 4.1.3 resolution: "human-id@npm:4.1.3" @@ -9841,15 +8942,6 @@ __metadata: languageName: node linkType: hard -"humanize-ms@npm:^1.2.1": - version: 1.2.1 - resolution: "humanize-ms@npm:1.2.1" - dependencies: - ms: "npm:^2.0.0" - checksum: 10/9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16 - languageName: node - linkType: hard - "hyperlinker@npm:^1.0.0": version: 1.0.0 resolution: "hyperlinker@npm:1.0.0" @@ -9857,15 +8949,6 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:^0.6.2": - version: 0.6.3 - resolution: "iconv-lite@npm:0.6.3" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10/24e3292dd3dadaa81d065c6f8c41b274a47098150d444b96e5f53b4638a9a71482921ea6a91a1f59bb71d9796de25e04afd05919fa64c360347ba65d3766f10f - languageName: node - linkType: hard - "iconv-lite@npm:^0.7.0, iconv-lite@npm:~0.7.0": version: 0.7.2 resolution: "iconv-lite@npm:0.7.2" @@ -9883,9 +8966,9 @@ __metadata: linkType: hard "idb-keyval@npm:^6.2.1": - version: 6.2.2 - resolution: "idb-keyval@npm:6.2.2" - checksum: 10/8c22342d94deba01066460fe6593f29c78027d0935a6ed7a1da68b28a7a68b89d0830dada4b30d51b779ed1dc1e362007a8939cda651b9ad0807176bd841e8cb + version: 6.2.5 + resolution: "idb-keyval@npm:6.2.5" + checksum: 10/ac645882b3258ff07347d085baab91b871bac7be4f46ff8e20a7c036c2df35d3f695a30050009f27237b99045203568f2a842a35295a48f9b815959ee51a347e languageName: node linkType: hard @@ -9955,10 +9038,10 @@ __metadata: languageName: node linkType: hard -"ip-address@npm:10.1.0, ip-address@npm:^10.0.1": - version: 10.1.0 - resolution: "ip-address@npm:10.1.0" - checksum: 10/a6979629d1ad9c1fb424bc25182203fad739b40225aebc55ec6243bbff5035faf7b9ed6efab3a097de6e713acbbfde944baacfa73e11852bb43989c45a68d79e +"ip-address@npm:^10.2.0": + version: 10.2.0 + resolution: "ip-address@npm:10.2.0" + checksum: 10/12fec399e1af5753ac322e47a6d81a50d3a528b3abb17c09525b2a2edcaedcca628c40520706f7037bc4d8e951b0296c47e7b86d0a8e6e2335c8f0ba4afcfac1 languageName: node linkType: hard @@ -10032,11 +9115,11 @@ __metadata: linkType: hard "is-core-module@npm:^2.16.1": - version: 2.16.1 - resolution: "is-core-module@npm:2.16.1" + version: 2.16.2 + resolution: "is-core-module@npm:2.16.2" dependencies: - hasown: "npm:^2.0.2" - checksum: 10/452b2c2fb7f889cbbf7e54609ef92cf6c24637c568acc7e63d166812a0fb365ae8a504c333a29add8bdb1686704068caa7f4e4b639b650dde4f00a038b8941fb + hasown: "npm:^2.0.3" + checksum: 10/6ee7535d82bbe457685799c5f145daf4b7c6be3afbd8e90788429d557f663d6dee72a8e4b9a45d0d756c243fcb5028095999243df090e5f04c02b153786bc8c6 languageName: node linkType: hard @@ -10222,19 +9305,10 @@ __metadata: languageName: node linkType: hard -"isexe@npm:^3.1.1": - version: 3.1.1 - resolution: "isexe@npm:3.1.1" - checksum: 10/7fe1931ee4e88eb5aa524cd3ceb8c882537bc3a81b02e438b240e47012eef49c86904d0f0e593ea7c3a9996d18d0f1f3be8d3eaa92333977b0c3a9d353d5563e - languageName: node - linkType: hard - -"isomorphic-ws@npm:^4.0.1": - version: 4.0.1 - resolution: "isomorphic-ws@npm:4.0.1" - peerDependencies: - ws: "*" - checksum: 10/d7190eadefdc28bdb93d67b5f0c603385aaf87724fa2974abb382ac1ec9756ed2cfb27065cbe76122879c2d452e2982bc4314317f3d6c737ddda6c047328771a +"isexe@npm:^4.0.0": + version: 4.0.0 + resolution: "isexe@npm:4.0.0" + checksum: 10/2ead327ef596042ef9c9ec5f236b316acfaedb87f4bb61b3c3d574fb2e9c8a04b67305e04733bde52c24d9622fdebd3270aadb632adfbf9cadef88fe30f479e5 languageName: node linkType: hard @@ -10284,19 +9358,6 @@ __metadata: languageName: node linkType: hard -"jackspeak@npm:^3.1.2": - version: 3.4.3 - resolution: "jackspeak@npm:3.4.3" - dependencies: - "@isaacs/cliui": "npm:^8.0.2" - "@pkgjs/parseargs": "npm:^0.11.0" - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 10/96f8786eaab98e4bf5b2a5d6d9588ea46c4d06bbc4f2eb861fdd7b6b182b16f71d8a70e79820f335d52653b16d4843b29dd9cdcf38ae80406756db9199497cf3 - languageName: node - linkType: hard - "jake@npm:^10.8.5": version: 10.9.4 resolution: "jake@npm:10.9.4" @@ -10310,41 +9371,26 @@ __metadata: languageName: node linkType: hard -"jayson@npm:^4.1.1": - version: 4.3.0 - resolution: "jayson@npm:4.3.0" - dependencies: - "@types/connect": "npm:^3.4.33" - "@types/node": "npm:^12.12.54" - "@types/ws": "npm:^7.4.4" - commander: "npm:^2.20.3" - delay: "npm:^5.0.0" - es6-promisify: "npm:^5.0.0" - eyes: "npm:^0.1.8" - isomorphic-ws: "npm:^4.0.1" - json-stringify-safe: "npm:^5.0.1" - stream-json: "npm:^1.9.1" - uuid: "npm:^8.3.2" - ws: "npm:^7.5.10" +"jiti@npm:^2.4.2": + version: 2.7.0 + resolution: "jiti@npm:2.7.0" bin: - jayson: bin/jayson.js - checksum: 10/cc58516462997da377d56584f2f8f870659ca2d76bf217d3153c105d7f51136cc3b3c7f23eb1ea425d8883ce20eb3ecbdd2eca52c2909afd5217f3bbc77552ea + jiti: lib/jiti-cli.mjs + checksum: 10/6d75a8dbd61dbee031aa0937fabb748ff8ddf370b971958cc704f5cf26b4c5bdc9dcd0563059b2627a2bd41d946fa0bc64f912fdc8981ca7945a9d63c74ad0f9 languageName: node linkType: hard -"jiti@npm:^2.4.2": - version: 2.6.1 - resolution: "jiti@npm:2.6.1" - bin: - jiti: lib/jiti-cli.mjs - checksum: 10/8cd72c5fd03a0502564c3f46c49761090f6dadead21fa191b73535724f095ad86c2fa89ee6fe4bc3515337e8d406cc8fb2d37b73fa0c99a34584bac35cd4a4de +"jose@npm:^6.2.0": + version: 6.2.3 + resolution: "jose@npm:6.2.3" + checksum: 10/876974613c5ee988d43b65a34c96ce440dbf7706a2f07f465b8874af16ee532102e224459a7068d2c6ef044affe49690667d23ca12770c279804baec95a09608 languageName: node linkType: hard -"jose@npm:^6.0.8": - version: 6.1.3 - resolution: "jose@npm:6.1.3" - checksum: 10/9626c51e8c3792b505e954f3094698c182208617b62dfb27269230f31e57560b083985ed8128b8a9753aa92daf18d3a2341cc826d149503f14569abe87d42389 +"js-tokens@npm:^10.0.0": + version: 10.0.0 + resolution: "js-tokens@npm:10.0.0" + checksum: 10/88f536ec89f076fc230d29df255b3c55531237669d746d1868fca716b1e3f5f2e4abf8e5b8701903216e3f00d2dc3918d078b35da87772d433ab6a513c3bf76d languageName: node linkType: hard @@ -10355,13 +9401,6 @@ __metadata: languageName: node linkType: hard -"js-tokens@npm:^9.0.1": - version: 9.0.1 - resolution: "js-tokens@npm:9.0.1" - checksum: 10/3288ba73bb2023adf59501979fb4890feb6669cc167b13771b226814fde96a1583de3989249880e3f4d674040d1815685db9a9880db9153307480d39dc760365 - languageName: node - linkType: hard - "js-yaml@npm:^3.14.1, js-yaml@npm:^3.6.1": version: 3.14.2 resolution: "js-yaml@npm:3.14.2" @@ -10375,13 +9414,13 @@ __metadata: linkType: hard "js-yaml@npm:^4.1.1": - version: 4.1.1 - resolution: "js-yaml@npm:4.1.1" + version: 4.2.0 + resolution: "js-yaml@npm:4.2.0" dependencies: argparse: "npm:^2.0.1" bin: js-yaml: bin/js-yaml.js - checksum: 10/a52d0519f0f4ef5b4adc1cde466cb54c50d56e2b4a983b9d5c9c0f2f99462047007a6274d7e95617a21d3c91fde3ee6115536ed70991cd645ba8521058b78f77 + checksum: 10/51de2067a2b44b07ba5206132e56005f8b568ff279bb4d2f645068958c56fa4827d40a6841c983234671fa0a134bf094d0b0717873c2a3d319185297af145a6d languageName: node linkType: hard @@ -10439,13 +9478,6 @@ __metadata: languageName: node linkType: hard -"json-stringify-safe@npm:^5.0.1": - version: 5.0.1 - resolution: "json-stringify-safe@npm:5.0.1" - checksum: 10/59169a081e4eeb6f9559ae1f938f656191c000e0512aa6df9f3c8b2437a4ab1823819c6b9fd1818a4e39593ccfd72e9a051fdd3e2d1e340ed913679e888ded8c - languageName: node - linkType: hard - "json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" @@ -10455,60 +9487,180 @@ __metadata: languageName: node linkType: hard -"jsonfile@npm:^4.0.0": - version: 4.0.0 - resolution: "jsonfile@npm:4.0.0" - dependencies: - graceful-fs: "npm:^4.1.6" - dependenciesMeta: - graceful-fs: - optional: true - checksum: 10/17796f0ab1be8479827d3683433f97ebe0a1c6932c3360fa40348eac36904d69269aab26f8b16da311882d94b42e9208e8b28e490bf926364f3ac9bff134c226 +"jsonfile@npm:^4.0.0": + version: 4.0.0 + resolution: "jsonfile@npm:4.0.0" + dependencies: + graceful-fs: "npm:^4.1.6" + dependenciesMeta: + graceful-fs: + optional: true + checksum: 10/17796f0ab1be8479827d3683433f97ebe0a1c6932c3360fa40348eac36904d69269aab26f8b16da311882d94b42e9208e8b28e490bf926364f3ac9bff134c226 + languageName: node + linkType: hard + +"keccak@npm:^3.0.3": + version: 3.0.4 + resolution: "keccak@npm:3.0.4" + dependencies: + node-addon-api: "npm:^2.0.0" + node-gyp: "npm:latest" + node-gyp-build: "npm:^4.2.0" + readable-stream: "npm:^3.6.0" + checksum: 10/45478bb0a57e44d0108646499b8360914b0fbc8b0e088f1076659cb34faaa9eb829c40f6dd9dadb3460bb86cc33153c41fed37fe5ce09465a60e71e78c23fa55 + languageName: node + linkType: hard + +"keyv@npm:^4.5.3, keyv@npm:^4.5.4": + version: 4.5.4 + resolution: "keyv@npm:4.5.4" + dependencies: + json-buffer: "npm:3.0.1" + checksum: 10/167eb6ef64cc84b6fa0780ee50c9de456b422a1e18802209234f7c2cf7eae648c7741f32e50d7e24ccb22b24c13154070b01563d642755b156c357431a191e75 + languageName: node + linkType: hard + +"keyvaluestorage-interface@npm:^1.0.0": + version: 1.0.0 + resolution: "keyvaluestorage-interface@npm:1.0.0" + checksum: 10/e652448bc915f9c21b9916678ed58f5314c831f0a284d190a340c0370296c71918e0cdc1156a17b12d1993941b302f0881e23fb9c395079e2065a7d2f33d0199 + languageName: node + linkType: hard + +"klona@npm:^2.0.6": + version: 2.0.6 + resolution: "klona@npm:2.0.6" + checksum: 10/ed7e2c9af58cb646e758e60b75dec24bf72466066290f78c515a2bae23a06fa280f11ff3210c43b94a18744954aa5358f9d46583d5e4c36da073ecc3606355c4 + languageName: node + linkType: hard + +"levn@npm:^0.4.1": + version: 0.4.1 + resolution: "levn@npm:0.4.1" + dependencies: + prelude-ls: "npm:^1.2.1" + type-check: "npm:~0.4.0" + checksum: 10/2e4720ff79f21ae08d42374b0a5c2f664c5be8b6c8f565bb4e1315c96ed3a8acaa9de788ffed82d7f2378cf36958573de07ef92336cb5255ed74d08b8318c9ee + languageName: node + linkType: hard + +"lightningcss-android-arm64@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-android-arm64@npm:1.32.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-darwin-arm64@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-darwin-arm64@npm:1.32.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-darwin-x64@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-darwin-x64@npm:1.32.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"lightningcss-freebsd-x64@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-freebsd-x64@npm:1.32.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"lightningcss-linux-arm-gnueabihf@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-arm-gnueabihf@npm:1.32.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"lightningcss-linux-arm64-gnu@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-arm64-gnu@npm:1.32.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"lightningcss-linux-arm64-musl@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-arm64-musl@npm:1.32.0" + conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"keccak@npm:^3.0.3": - version: 3.0.4 - resolution: "keccak@npm:3.0.4" - dependencies: - node-addon-api: "npm:^2.0.0" - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.2.0" - readable-stream: "npm:^3.6.0" - checksum: 10/45478bb0a57e44d0108646499b8360914b0fbc8b0e088f1076659cb34faaa9eb829c40f6dd9dadb3460bb86cc33153c41fed37fe5ce09465a60e71e78c23fa55 +"lightningcss-linux-x64-gnu@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-x64-gnu@npm:1.32.0" + conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"keyv@npm:^4.5.3, keyv@npm:^4.5.4": - version: 4.5.4 - resolution: "keyv@npm:4.5.4" - dependencies: - json-buffer: "npm:3.0.1" - checksum: 10/167eb6ef64cc84b6fa0780ee50c9de456b422a1e18802209234f7c2cf7eae648c7741f32e50d7e24ccb22b24c13154070b01563d642755b156c357431a191e75 +"lightningcss-linux-x64-musl@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-x64-musl@npm:1.32.0" + conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"keyvaluestorage-interface@npm:^1.0.0": - version: 1.0.0 - resolution: "keyvaluestorage-interface@npm:1.0.0" - checksum: 10/e652448bc915f9c21b9916678ed58f5314c831f0a284d190a340c0370296c71918e0cdc1156a17b12d1993941b302f0881e23fb9c395079e2065a7d2f33d0199 +"lightningcss-win32-arm64-msvc@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-win32-arm64-msvc@npm:1.32.0" + conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"klona@npm:^2.0.6": - version: 2.0.6 - resolution: "klona@npm:2.0.6" - checksum: 10/ed7e2c9af58cb646e758e60b75dec24bf72466066290f78c515a2bae23a06fa280f11ff3210c43b94a18744954aa5358f9d46583d5e4c36da073ecc3606355c4 +"lightningcss-win32-x64-msvc@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-win32-x64-msvc@npm:1.32.0" + conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"levn@npm:^0.4.1": - version: 0.4.1 - resolution: "levn@npm:0.4.1" +"lightningcss@npm:^1.32.0": + version: 1.32.0 + resolution: "lightningcss@npm:1.32.0" dependencies: - prelude-ls: "npm:^1.2.1" - type-check: "npm:~0.4.0" - checksum: 10/2e4720ff79f21ae08d42374b0a5c2f664c5be8b6c8f565bb4e1315c96ed3a8acaa9de788ffed82d7f2378cf36958573de07ef92336cb5255ed74d08b8318c9ee + detect-libc: "npm:^2.0.3" + lightningcss-android-arm64: "npm:1.32.0" + lightningcss-darwin-arm64: "npm:1.32.0" + lightningcss-darwin-x64: "npm:1.32.0" + lightningcss-freebsd-x64: "npm:1.32.0" + lightningcss-linux-arm-gnueabihf: "npm:1.32.0" + lightningcss-linux-arm64-gnu: "npm:1.32.0" + lightningcss-linux-arm64-musl: "npm:1.32.0" + lightningcss-linux-x64-gnu: "npm:1.32.0" + lightningcss-linux-x64-musl: "npm:1.32.0" + lightningcss-win32-arm64-msvc: "npm:1.32.0" + lightningcss-win32-x64-msvc: "npm:1.32.0" + dependenciesMeta: + lightningcss-android-arm64: + optional: true + lightningcss-darwin-arm64: + optional: true + lightningcss-darwin-x64: + optional: true + lightningcss-freebsd-x64: + optional: true + lightningcss-linux-arm-gnueabihf: + optional: true + lightningcss-linux-arm64-gnu: + optional: true + lightningcss-linux-arm64-musl: + optional: true + lightningcss-linux-x64-gnu: + optional: true + lightningcss-linux-x64-musl: + optional: true + lightningcss-win32-arm64-msvc: + optional: true + lightningcss-win32-x64-msvc: + optional: true + checksum: 10/098e61007f0d0ec8b5c50884e33b543b551d1ff21bc7b062434b6638fd0b8596858f823b60dfc2a4aa756f3cb120ad79f2b7f4a55b1bda2c0269ab8cf476f114 languageName: node linkType: hard @@ -10531,11 +9683,11 @@ __metadata: linkType: hard "lit-html@npm:^3.3.0": - version: 3.3.2 - resolution: "lit-html@npm:3.3.2" + version: 3.3.3 + resolution: "lit-html@npm:3.3.3" dependencies: "@types/trusted-types": "npm:^2.0.2" - checksum: 10/5e938739641e312673e722eb41d5ca48dfcf69277e665c72dadd6514f53fc3dc4d5172cf8ca6af67736df1bce267f6189b3ef6fcb4125386b2490cd10c266b8f + checksum: 10/d8fc4ccd983ad5c32e5efa98687e6be90dbfb29863ecda124d18452545854fdd97c8b06679182d8fbb2324e5db9ba1e210724e1d3e279545357b031e94ec9139 languageName: node linkType: hard @@ -10591,14 +9743,14 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.21, lodash@npm:^4.17.23": - version: 4.17.23 - resolution: "lodash@npm:4.17.23" - checksum: 10/82504c88250f58da7a5a4289f57a4f759c44946c005dd232821c7688b5fcfbf4a6268f6a6cdde4b792c91edd2f3b5398c1d2a0998274432cff76def48735e233 +"lodash@npm:^4.17.21, lodash@npm:^4.17.23, lodash@npm:^4.18.1": + version: 4.18.1 + resolution: "lodash@npm:4.18.1" + checksum: 10/306fea53dfd39dad1f03d45ba654a2405aebd35797b673077f401edb7df2543623dc44b9effbb98f69b32152295fff725a4cec99c684098947430600c6af0c3f languageName: node linkType: hard -"long@npm:^5.0.0, long@npm:^5.2.0": +"long@npm:^5.2.0, long@npm:^5.3.2": version: 5.3.2 resolution: "long@npm:5.3.2" checksum: 10/b6b55ddae56fcce2864d37119d6b02fe28f6dd6d9e44fd22705f86a9254b9321bd69e9ffe35263b4846d54aba197c64882adcb8c543f2383c1e41284b321ea64 @@ -10639,17 +9791,17 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": +"lru-cache@npm:^10.0.1": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" checksum: 10/e6e90267360476720fa8e83cc168aa2bf0311f3f2eea20a6ba78b90a885ae72071d9db132f40fda4129c803e7dcec3a6b6a6fbb44ca90b081630b810b5d6a41a languageName: node linkType: hard -"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.0, lru-cache@npm:^11.2.1": - version: 11.2.4 - resolution: "lru-cache@npm:11.2.4" - checksum: 10/3b2da74c0b6653767f8164c38c4c4f4d7f0cc10c62bfa512663d94a830191ae6a5af742a8d88a8b30d5f9974652d3adae53931f32069139ad24fa2a18a199aca +"lru-cache@npm:^11.0.0, lru-cache@npm:^11.2.7": + version: 11.5.1 + resolution: "lru-cache@npm:11.5.1" + checksum: 10/02c4f73967d91fb101f4accf8ebac9e0541e08e16d987bdb9e9737f13e5f2c4bc33c593b98ec30e4486bf899bc97edb36fbd133684b36087336559e41edafdea languageName: node linkType: hard @@ -10662,15 +9814,6 @@ __metadata: languageName: node linkType: hard -"lz-string@npm:^1.5.0": - version: 1.5.0 - resolution: "lz-string@npm:1.5.0" - bin: - lz-string: bin/bin.js - checksum: 10/e86f0280e99a8d8cd4eef24d8601ddae15ce54e43ac9990dfcb79e1e081c255ad24424a30d78d2ad8e51a8ce82a66a930047fed4b4aa38c6f0b392ff9300edfc - languageName: node - linkType: hard - "magic-string@npm:^0.30.21": version: 0.30.21 resolution: "magic-string@npm:0.30.21" @@ -10680,14 +9823,14 @@ __metadata: languageName: node linkType: hard -"magicast@npm:^0.5.1": - version: 0.5.1 - resolution: "magicast@npm:0.5.1" +"magicast@npm:^0.5.2": + version: 0.5.3 + resolution: "magicast@npm:0.5.3" dependencies: - "@babel/parser": "npm:^7.28.5" - "@babel/types": "npm:^7.28.5" + "@babel/parser": "npm:^7.29.3" + "@babel/types": "npm:^7.29.0" source-map-js: "npm:^1.2.1" - checksum: 10/ee6149994760f0b539a07f1d36631fed366ae19b9fc82e338c1cdd2a2e0b33a773635327514a6aa73faca9dc0ca37df5e5376b7b0687fb56353f431f299714c4 + checksum: 10/436ad518726b691cf9ac1a14ab14705784f28075892a092b06e8b17ac7303fe57e8a2789989c68b560653a909a8df49d1582bb73f9bdad4bcbab892201251049 languageName: node linkType: hard @@ -10700,25 +9843,6 @@ __metadata: languageName: node linkType: hard -"make-fetch-happen@npm:^15.0.0": - version: 15.0.3 - resolution: "make-fetch-happen@npm:15.0.3" - dependencies: - "@npmcli/agent": "npm:^4.0.0" - cacache: "npm:^20.0.1" - http-cache-semantics: "npm:^4.1.1" - minipass: "npm:^7.0.2" - minipass-fetch: "npm:^5.0.0" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - negotiator: "npm:^1.0.0" - proc-log: "npm:^6.0.0" - promise-retry: "npm:^2.0.1" - ssri: "npm:^13.0.0" - checksum: 10/78da4fc1df83cb596e2bae25aa0653b8a9c6cbdd6674a104894e03be3acfcd08c70b78f06ef6407fbd6b173f6a60672480d78641e693d05eb71c09c13ee35278 - languageName: node - linkType: hard - "markdown-table@npm:^3.0.0": version: 3.0.4 resolution: "markdown-table@npm:3.0.4" @@ -10757,8 +9881,8 @@ __metadata: linkType: hard "mdast-util-from-markdown@npm:^2.0.0": - version: 2.0.2 - resolution: "mdast-util-from-markdown@npm:2.0.2" + version: 2.0.3 + resolution: "mdast-util-from-markdown@npm:2.0.3" dependencies: "@types/mdast": "npm:^4.0.0" "@types/unist": "npm:^3.0.0" @@ -10772,7 +9896,7 @@ __metadata: micromark-util-symbol: "npm:^2.0.0" micromark-util-types: "npm:^2.0.0" unist-util-stringify-position: "npm:^4.0.0" - checksum: 10/69b207913fbcc0469f8c59d922af4d5509b79e809d77c9bd4781543a907fe2ecc8e6433ce0707066a27b117b13f38af3aae4f2d085e18ebd2d3ad5f1a5647902 + checksum: 10/96f2bfb3b240c3d20a57db5d215faed795abf495c65ca2a4d61c0cf796011bc980619aa032d7984b05b67c15edc0eccd12a004a848952d3a598d108cf14901ab languageName: node linkType: hard @@ -11377,117 +10501,50 @@ __metadata: languageName: node linkType: hard -"min-indent@npm:^1.0.0": - version: 1.0.1 - resolution: "min-indent@npm:1.0.1" - checksum: 10/bfc6dd03c5eaf623a4963ebd94d087f6f4bbbfd8c41329a7f09706b0cb66969c4ddd336abeb587bc44bc6f08e13bf90f0b374f9d71f9f01e04adc2cd6f083ef1 - languageName: node - linkType: hard - -"minimatch@npm:^10.1.1": - version: 10.1.1 - resolution: "minimatch@npm:10.1.1" +"minimatch@npm:^10.2.2, minimatch@npm:^10.2.5": + version: 10.2.5 + resolution: "minimatch@npm:10.2.5" dependencies: - "@isaacs/brace-expansion": "npm:^5.0.0" - checksum: 10/110f38921ea527022e90f7a5f43721838ac740d0a0c26881c03b57c261354fb9a0430e40b2c56dfcea2ef3c773768f27210d1106f1f2be19cde3eea93f26f45e + brace-expansion: "npm:^5.0.5" + checksum: 10/19e87a931aff60ee7b9d80f39f817b8bfc54f61f8356ee3549fbf636dbccacacfec8d803eac73293955c4527cd085247dfc064bce4a5e349f8f3b85e2bf5da0f languageName: node linkType: hard -"minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" +"minimatch@npm:^3.1.5": + version: 3.1.5 + resolution: "minimatch@npm:3.1.5" dependencies: brace-expansion: "npm:^1.1.7" - checksum: 10/e0b25b04cd4ec6732830344e5739b13f8690f8a012d73445a4a19fbc623f5dd481ef7a5827fde25954cd6026fede7574cc54dc4643c99d6c6b653d6203f94634 + checksum: 10/b11a7ee5773cd34c1a0c8436cdbe910901018fb4b6cb47aa508a18d567f6efd2148507959e35fba798389b161b8604a2d704ccef751ea36bd4582f9852b7d63f languageName: node linkType: hard "minimatch@npm:^5.0.1": - version: 5.1.6 - resolution: "minimatch@npm:5.1.6" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10/126b36485b821daf96d33b5c821dac600cc1ab36c87e7a532594f9b1652b1fa89a1eebcaad4dff17c764dce1a7ac1531327f190fed5f97d8f6e5f889c116c429 - languageName: node - linkType: hard - -"minimatch@npm:^9.0.4, minimatch@npm:^9.0.5": - version: 9.0.5 - resolution: "minimatch@npm:9.0.5" + version: 5.1.9 + resolution: "minimatch@npm:5.1.9" dependencies: brace-expansion: "npm:^2.0.1" - checksum: 10/dd6a8927b063aca6d910b119e1f2df6d2ce7d36eab91de83167dd136bb85e1ebff97b0d3de1cb08bd1f7e018ca170b4962479fefab5b2a69e2ae12cb2edc8348 - languageName: node - linkType: hard - -"minipass-collect@npm:^2.0.1": - version: 2.0.1 - resolution: "minipass-collect@npm:2.0.1" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/b251bceea62090f67a6cced7a446a36f4cd61ee2d5cea9aee7fff79ba8030e416327a1c5aa2908dc22629d06214b46d88fdab8c51ac76bacbf5703851b5ad342 - languageName: node - linkType: hard - -"minipass-fetch@npm:^5.0.0": - version: 5.0.0 - resolution: "minipass-fetch@npm:5.0.0" - dependencies: - encoding: "npm:^0.1.13" - minipass: "npm:^7.0.3" - minipass-sized: "npm:^1.0.3" - minizlib: "npm:^3.0.1" - dependenciesMeta: - encoding: - optional: true - checksum: 10/4fb7dca630a64e6970a8211dade505bfe260d0b8d60beb348dcdfb95fe35ef91d977b29963929c9017ae0805686aa3f413107dc6bc5deac9b9e26b0b41c3b86c + checksum: 10/23b4feb64dcb77ba93b70a72be551eb2e2677ac02178cf1ed3d38836cc4cd84802d90b77f60ef87f2bac64d270d2d8eba242e428f0554ea4e36bfdb7e9d25d0c languageName: node linkType: hard -"minipass-flush@npm:^1.0.5": - version: 1.0.5 - resolution: "minipass-flush@npm:1.0.5" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf - languageName: node - linkType: hard - -"minipass-pipeline@npm:^1.2.4": - version: 1.2.4 - resolution: "minipass-pipeline@npm:1.2.4" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b - languageName: node - linkType: hard - -"minipass-sized@npm:^1.0.3": - version: 1.0.3 - resolution: "minipass-sized@npm:1.0.3" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/40982d8d836a52b0f37049a0a7e5d0f089637298e6d9b45df9c115d4f0520682a78258905e5c8b180fb41b593b0a82cc1361d2c74b45f7ada66334f84d1ecfdd - languageName: node - linkType: hard - -"minipass@npm:^3.0.0": - version: 3.3.6 - resolution: "minipass@npm:3.3.6" +"minimatch@npm:^9.0.4": + version: 9.0.9 + resolution: "minimatch@npm:9.0.9" dependencies: - yallist: "npm:^4.0.0" - checksum: 10/a5c6ef069f70d9a524d3428af39f2b117ff8cd84172e19b754e7264a33df460873e6eb3d6e55758531580970de50ae950c496256bb4ad3691a2974cddff189f0 + brace-expansion: "npm:^2.0.2" + checksum: 10/b91fad937deaffb68a45a2cb731ff3cff1c3baf9b6469c879477ed16f15c8f4ce39d63a3f75c2455107c2fdff0f3ab597d97dc09e2e93b883aafcf926ef0c8f9 languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": - version: 7.1.2 - resolution: "minipass@npm:7.1.2" - checksum: 10/c25f0ee8196d8e6036661104bacd743785b2599a21de5c516b32b3fa2b83113ac89a2358465bc04956baab37ffb956ae43be679b2262bf7be15fce467ccd7950 +"minipass@npm:^7.0.4, minipass@npm:^7.1.2, minipass@npm:^7.1.3": + version: 7.1.3 + resolution: "minipass@npm:7.1.3" + checksum: 10/175e4d5e20980c3cd316ae82d2c031c42f6c746467d8b1905b51060a0ba4461441a0c25bb67c025fd9617f9a3873e152c7b543c6b5ac83a1846be8ade80dffd6 languageName: node linkType: hard -"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": +"minizlib@npm:^3.1.0": version: 3.1.0 resolution: "minizlib@npm:3.1.0" dependencies: @@ -11529,7 +10586,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:^2.0.0, ms@npm:^2.1.3": +"ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: 10/aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d @@ -11557,12 +10614,12 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.11": - version: 3.3.11 - resolution: "nanoid@npm:3.3.11" +"nanoid@npm:^3.3.12": + version: 3.3.12 + resolution: "nanoid@npm:3.3.12" bin: nanoid: bin/nanoid.cjs - checksum: 10/73b5afe5975a307aaa3c95dfe3334c52cdf9ae71518176895229b8d65ab0d1c0417dd081426134eb7571c055720428ea5d57c645138161e7d10df80815527c48 + checksum: 10/6eec280694e2088d18fb802b1e3bfc4578e27b665b7ecfbe36c7356612fea2f814277056e671e2a1529dff551588a652efdc0bfa39f8a3185bc2247be311872e languageName: node linkType: hard @@ -11639,22 +10696,22 @@ __metadata: linkType: hard "node-gyp@npm:latest": - version: 12.1.0 - resolution: "node-gyp@npm:12.1.0" + version: 12.3.0 + resolution: "node-gyp@npm:12.3.0" dependencies: env-paths: "npm:^2.2.0" exponential-backoff: "npm:^3.1.1" graceful-fs: "npm:^4.2.6" - make-fetch-happen: "npm:^15.0.0" nopt: "npm:^9.0.0" proc-log: "npm:^6.0.0" semver: "npm:^7.3.5" - tar: "npm:^7.5.2" + tar: "npm:^7.5.4" tinyglobby: "npm:^0.2.12" + undici: "npm:^6.25.0" which: "npm:^6.0.0" bin: node-gyp: bin/node-gyp.js - checksum: 10/d93079236cef1dd7fa4df683708d8708ad255c55865f6656664c8959e4d3963d908ac48e8f9f341705432e979dbbf502a40d68d65a17fe35956a5a05ba6c1cb4 + checksum: 10/cd97bf17f0f3e6288c42cc23a6db8528a98e7530abdb72ab558272906d603362e4558069f99f8a5250bc78f65ff305b1438caca4f1b31c81904a8798c242603e languageName: node linkType: hard @@ -11665,10 +10722,10 @@ __metadata: languageName: node linkType: hard -"node-releases@npm:^2.0.27": - version: 2.0.27 - resolution: "node-releases@npm:2.0.27" - checksum: 10/f6c78ddb392ae500719644afcbe68a9ea533242c02312eb6a34e8478506eb7482a3fb709c70235b01c32fe65625b68dfa9665113f816d87f163bc3819b62b106 +"node-releases@npm:^2.0.36": + version: 2.0.47 + resolution: "node-releases@npm:2.0.47" + checksum: 10/6ba88359ea4a653bcb428c7ac47a3b9093d0fe873d0fbda8b6714df6d1829630769d1c737d5938458af6a101b4bb7c70bcf7e38f36db469a17a348261d26f822 languageName: node linkType: hard @@ -11719,15 +10776,15 @@ __metadata: linkType: hard "nypm@npm:^0.6.0": - version: 0.6.4 - resolution: "nypm@npm:0.6.4" + version: 0.6.6 + resolution: "nypm@npm:0.6.6" dependencies: - citty: "npm:^0.2.0" + citty: "npm:^0.2.2" pathe: "npm:^2.0.3" - tinyexec: "npm:^1.0.2" + tinyexec: "npm:^1.1.1" bin: nypm: dist/cli.mjs - checksum: 10/a11e34ebb8ed5e4952341b0376307bb65a619ea5a252d7da825a641bcf88f3880f46d1633725f08b6d263d212bc9ae18b24249964d7ca41c3031f7cf8f1c5b6c + checksum: 10/615f8f661e74440a42f93b2f05082b4de2c91aacaa497aafa939b212a125ce8ce82d0c50e0cd0a8f8e8a5931764e3a63f76c4c8a68d5f1586274394a8fc8c5a6 languageName: node linkType: hard @@ -11749,7 +10806,7 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.13.3": +"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4": version: 1.13.4 resolution: "object-inspect@npm:1.13.4" checksum: 10/aa13b1190ad3e366f6c83ad8a16ed37a19ed57d267385aa4bfdccda833d7b90465c057ff6c55d035a6b2e52c1a2295582b294217a0a3a1ae7abdd6877ef781fb @@ -11771,18 +10828,18 @@ __metadata: linkType: hard "oclif@npm:^4.22.70": - version: 4.22.70 - resolution: "oclif@npm:4.22.70" + version: 4.23.10 + resolution: "oclif@npm:4.23.10" dependencies: - "@aws-sdk/client-cloudfront": "npm:^3.971.0" - "@aws-sdk/client-s3": "npm:^3.975.0" + "@aws-sdk/client-cloudfront": "npm:^3.1009.0" + "@aws-sdk/client-s3": "npm:^3.1053.0" "@inquirer/confirm": "npm:^3.1.22" "@inquirer/input": "npm:^2.2.4" "@inquirer/select": "npm:^2.5.0" - "@oclif/core": "npm:^4.8.0" - "@oclif/plugin-help": "npm:^6.2.36" - "@oclif/plugin-not-found": "npm:^3.2.73" - "@oclif/plugin-warn-if-update-available": "npm:^3.1.55" + "@oclif/core": "npm:^4.11.4" + "@oclif/plugin-help": "npm:^6.2.49" + "@oclif/plugin-not-found": "npm:^3.2.85" + "@oclif/plugin-warn-if-update-available": "npm:^3.1.65" ansis: "npm:^3.16.0" async-retry: "npm:^1.3.3" change-case: "npm:^4" @@ -11792,15 +10849,15 @@ __metadata: fs-extra: "npm:^8.1" github-slugger: "npm:^2" got: "npm:^13" - lodash: "npm:^4.17.23" + lodash: "npm:^4.18.1" normalize-package-data: "npm:^6" - semver: "npm:^7.7.3" + semver: "npm:^7.7.4" sort-package-json: "npm:^2.15.1" tiny-jsonc: "npm:^1.0.2" validate-npm-package-name: "npm:^5.0.1" bin: oclif: bin/run.js - checksum: 10/6f3eabebd6cf3a7eea72d2c56ff8cd41ab675919e20f83ac3f79385c6987ec44a2c2cd6c3c2706e6d322b03e61b204f5cd644dc339b32ea9ea26e2d6ce722953 + checksum: 10/6cf42204c7f95222f79c731baed56bda682d7c29d79376a65ff10c0cbd777403dd9a1e30570e24396176e13475d09a8589afa2b9442d62e55b0493b223e6a5cc languageName: node linkType: hard @@ -11884,9 +10941,9 @@ __metadata: languageName: node linkType: hard -"ox@npm:0.11.3": - version: 0.11.3 - resolution: "ox@npm:0.11.3" +"ox@npm:0.14.27": + version: 0.14.27 + resolution: "ox@npm:0.14.27" dependencies: "@adraffy/ens-normalize": "npm:^1.11.0" "@noble/ciphers": "npm:^1.3.0" @@ -11901,7 +10958,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10/6eaf0e0ea812b3673228b323c90a7ab04513a2a495e483419333bda6eae802ad7afd17ab869e417036d85683eda2e2f2a811c2e2d26fd09fc6aa9729b4e063a6 + checksum: 10/eb022ccc101d35218457d9160ab9898463bc98959f5983086002380772ed5e4bbe1cd1aaf0c28c146950a20f1f02b7c2fd6d77fd945fcfebbe71afe20797cdbf languageName: node linkType: hard @@ -12043,13 +11100,6 @@ __metadata: languageName: node linkType: hard -"p-map@npm:^7.0.2": - version: 7.0.4 - resolution: "p-map@npm:7.0.4" - checksum: 10/ef48c3b2e488f31c693c9fcc0df0ef76518cf6426a495cf9486ebbb0fd7f31aef7f90e96f72e0070c0ff6e3177c9318f644b512e2c29e3feee8d7153fcb6782e - languageName: node - linkType: hard - "p-try@npm:^2.0.0": version: 2.2.0 resolution: "p-try@npm:2.2.0" @@ -12057,7 +11107,7 @@ __metadata: languageName: node linkType: hard -"package-json-from-dist@npm:^1.0.0, package-json-from-dist@npm:^1.0.1": +"package-json-from-dist@npm:^1.0.1": version: 1.0.1 resolution: "package-json-from-dist@npm:1.0.1" checksum: 10/58ee9538f2f762988433da00e26acc788036914d57c71c246bf0be1b60cdbd77dd60b6a3e1a30465f0b248aeb80079e0b34cb6050b1dfa18c06953bb1cbc7602 @@ -12175,6 +11225,13 @@ __metadata: languageName: node linkType: hard +"path-expression-matcher@npm:^1.5.0": + version: 1.5.0 + resolution: "path-expression-matcher@npm:1.5.0" + checksum: 10/28303bb9ee6831e6df14c10cd3f3f7b2d7c8d7f788d8bdb7440136fd696064c82a3e264999a0764d28e39f698275fc03a5493bec93c57ef4a22566280367dd64 + languageName: node + linkType: hard + "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -12196,30 +11253,20 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^1.11.1": - version: 1.11.1 - resolution: "path-scurry@npm:1.11.1" - dependencies: - lru-cache: "npm:^10.2.0" - minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - checksum: 10/5e8845c159261adda6f09814d7725683257fcc85a18f329880ab4d7cc1d12830967eae5d5894e453f341710d5484b8fdbbd4d75181b4d6e1eb2f4dc7aeadc434 - languageName: node - linkType: hard - -"path-scurry@npm:^2.0.0": - version: 2.0.1 - resolution: "path-scurry@npm:2.0.1" +"path-scurry@npm:^2.0.2": + version: 2.0.2 + resolution: "path-scurry@npm:2.0.2" dependencies: lru-cache: "npm:^11.0.0" minipass: "npm:^7.1.2" - checksum: 10/1e9c74e9ccf94d7c16056a5cb2dba9fa23eec1bc221ab15c44765486b9b9975b4cd9a4d55da15b96eadf67d5202e9a2f1cec9023fbb35fe7d9ccd0ff1891f88b + checksum: 10/2b4257422bcb870a4c2d205b3acdbb213a72f5e2250f61c80f79c9d014d010f82bdf8584441612c8e1fa4eb098678f5704a66fa8377d72646bad4be38e57a2c3 languageName: node linkType: hard "path-to-regexp@npm:^8.0.0": - version: 8.3.0 - resolution: "path-to-regexp@npm:8.3.0" - checksum: 10/568f148fc64f5fd1ecebf44d531383b28df924214eabf5f2570dce9587a228e36c37882805ff02d71c6209b080ea3ee6a4d2b712b5df09741b67f1f3cf91e55a + version: 8.4.2 + resolution: "path-to-regexp@npm:8.4.2" + checksum: 10/70fd2cbce0b962cbcf4d312af07818bfce2bae11c09cf3bd86be99c0e30168238a1a7b02b18b452e73f075897df04597d30d63e56da7be41eecfc37998693389 languageName: node linkType: hard @@ -12244,7 +11291,7 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:1.1.1, picocolors@npm:^1.1.0, picocolors@npm:^1.1.1": +"picocolors@npm:^1.1.0, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: 10/e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 @@ -12252,16 +11299,16 @@ __metadata: linkType: hard "picomatch@npm:^2.0.4, picomatch@npm:^2.3.1": - version: 2.3.1 - resolution: "picomatch@npm:2.3.1" - checksum: 10/60c2595003b05e4535394d1da94850f5372c9427ca4413b71210f437f7b2ca091dbd611c45e8b37d10036fa8eade25c1b8951654f9d3973bfa66a2ff4d3b08bc + version: 2.3.2 + resolution: "picomatch@npm:2.3.2" + checksum: 10/b788ef8148a2415b9dec12f0bb350ae6a5830f8f1950e472abc2f5225494debf7d1b75eb031df0ceaea9e8ec3e7bad599e8dbf3c60d61b42be429ba41bff4426 languageName: node linkType: hard -"picomatch@npm:^4.0.2, picomatch@npm:^4.0.3": - version: 4.0.3 - resolution: "picomatch@npm:4.0.3" - checksum: 10/57b99055f40b16798f2802916d9c17e9744e620a0db136554af01d19598b96e45e2f00014c91d1b8b13874b80caa8c295b3d589a3f72373ec4aaf54baa5962d5 +"picomatch@npm:^4.0.2, picomatch@npm:^4.0.3, picomatch@npm:^4.0.4": + version: 4.0.4 + resolution: "picomatch@npm:4.0.4" + checksum: 10/f6ef80a3590827ce20378ae110ac78209cc4f74d39236370f1780f957b7ee41c12acde0e4651b90f39983506fd2f5e449994716f516db2e9752924aff8de93ce languageName: node linkType: hard @@ -12287,8 +11334,8 @@ __metadata: linkType: hard "pinata@npm:^2.5.3": - version: 2.5.3 - resolution: "pinata@npm:2.5.3" + version: 2.5.6 + resolution: "pinata@npm:2.5.6" peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" @@ -12297,7 +11344,7 @@ __metadata: optional: true react-dom: optional: true - checksum: 10/9f401de49f4fc06b65232cf0cf13ebfa45bc17f050b00df39119e15966d216c821b073cdcd6eea90cb3b1cbdb38c243972bf0c57037afb4e2d9dba3f44ae2709 + checksum: 10/e84fb93223d01d04a9fb4a72411e32ac529b9bc3872945826e5f0b343bfc1cd1bc13f313e80fa252b928a3f8284d9f20102b93f55b0d9824a62c895b4c9aae0e languageName: node linkType: hard @@ -12339,25 +11386,14 @@ __metadata: languageName: node linkType: hard -"pixelmatch@npm:7.1.0": - version: 7.1.0 - resolution: "pixelmatch@npm:7.1.0" - dependencies: - pngjs: "npm:^7.0.0" - bin: - pixelmatch: bin/pixelmatch - checksum: 10/57a122196318ea8ce74e8759b1b7b94b9f9627b495cd79e50a49d470dc23b6c679e89c38660d0f7e8f959eac3b279c55b728e52d02c276dc51505f06eaba1141 - languageName: node - linkType: hard - "pkg-types@npm:^2.2.0": - version: 2.3.0 - resolution: "pkg-types@npm:2.3.0" + version: 2.3.1 + resolution: "pkg-types@npm:2.3.1" dependencies: - confbox: "npm:^0.2.2" - exsolve: "npm:^1.0.7" + confbox: "npm:^0.2.4" + exsolve: "npm:^1.0.8" pathe: "npm:^2.0.3" - checksum: 10/4b36e4eb12693a1beb145573c564ec6fb74b1008d3b457eaa1f0072331edf05cb7c479c47fe0c4bfdec76c2caff5b68215ff270e5fe49634c07984a7a0197118 + checksum: 10/59d892b5e18b319a66e745214b66bc68a77c6eccc4bf955582775aa393f79a6a29495184233d71e10a986e9346e44d72f5957d2d0e7104cb0d6ef43b4e92a969 languageName: node linkType: hard @@ -12368,27 +11404,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.58.0": - version: 1.58.0 - resolution: "playwright-core@npm:1.58.0" +"playwright-core@npm:1.60.0": + version: 1.60.0 + resolution: "playwright-core@npm:1.60.0" bin: playwright-core: cli.js - checksum: 10/718549cdcd22e55f42887e7b832276c9a50e112b278d22a2242bb00c401021623fedf9554c7090f132e389b5bbe11a987ce71e3c877e767eed4dd9bfe573019c + checksum: 10/66c0f83d627e673261c848dd6fe1f2856d5b5b6859268acb61a45c00f5bf926e596a351a9c481a3a4e82a45022c7c6b5d99ebc3906fc6876ac582ed6f7e16190 languageName: node linkType: hard "playwright@npm:^1.58.0": - version: 1.58.0 - resolution: "playwright@npm:1.58.0" + version: 1.60.0 + resolution: "playwright@npm:1.60.0" dependencies: fsevents: "npm:2.3.2" - playwright-core: "npm:1.58.0" + playwright-core: "npm:1.60.0" dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 10/5ef5d0977906046400cee9a359f18c87eafb3e3193a33a22351cc84740c0dffb3cff7b9f2320d1e200817dbf24e63b747a0546b6c671a9fd95937e2402682ad9 + checksum: 10/8569770637ee35d08cca3b53a5b56c21e9236bd1ac4718456d5988fb8acd51c5b3cc2cf90748363a36199529e870a9b6c68d6fc9e19571261cd867005d6331c1 languageName: node linkType: hard @@ -12531,14 +11567,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.5.6": - version: 8.5.6 - resolution: "postcss@npm:8.5.6" +"postcss@npm:^8.5.15, postcss@npm:^8.5.6": + version: 8.5.15 + resolution: "postcss@npm:8.5.15" dependencies: - nanoid: "npm:^3.3.11" + nanoid: "npm:^3.3.12" picocolors: "npm:^1.1.1" source-map-js: "npm:^1.2.1" - checksum: 10/9e4fbe97574091e9736d0e82a591e29aa100a0bf60276a926308f8c57249698935f35c5d2f4e80de778d0cbb8dcffab4f383d85fd50c5649aca421c3df729b86 + checksum: 10/d02ad19eb1e0fa53a1229ee6d53807eb88f903f2b9a8cac66993367f3ac7dd3b97238c783a54ccbf4145f82f6ca9a5cbd58f089846285d759c8a3259fbea8318 languageName: node linkType: hard @@ -12550,9 +11586,9 @@ __metadata: linkType: hard "preact@npm:^10.16.0": - version: 10.28.2 - resolution: "preact@npm:10.28.2" - checksum: 10/08b7273fd7a0858897df27a38985a38ed0ecb0c9a32ba8685197bad1be4c7cb7b430d40211ee92ba3fd346454256629c03da660db164aedc2082963bda10482a + version: 10.29.2 + resolution: "preact@npm:10.29.2" + checksum: 10/933ab114157448fbb60ab92a4e3d1394c6cc8a29ce77cc454b061797fa1e689929ca5b8cda55cf74a042c929351302f8d8db0456e0ab01fd0ebb1d204ba29192 languageName: node linkType: hard @@ -12573,16 +11609,16 @@ __metadata: linkType: hard "prettier-plugin-packagejson@npm:^3.0.0": - version: 3.0.0 - resolution: "prettier-plugin-packagejson@npm:3.0.0" + version: 3.0.2 + resolution: "prettier-plugin-packagejson@npm:3.0.2" dependencies: - sort-package-json: "npm:3.6.0" + sort-package-json: "npm:^3.6.0" peerDependencies: prettier: ^3 peerDependenciesMeta: prettier: optional: true - checksum: 10/00378f77c50d411d9e78d8de91f9f7ced37253730f0a66371fe9d549de53927c8828f2921c068cf22a763f843224a15e924a985a482fa3d83ab60e23526e0ee6 + checksum: 10/45693ad53ab4b5d3f2d61f50194f110dfa31972c82b1c3f81988a03c373e2b8431ea9d773086aeb854115587b39a0525979adcafaad8b931aa753c5adb745409 languageName: node linkType: hard @@ -12596,22 +11632,11 @@ __metadata: linkType: hard "prettier@npm:^3.8.1": - version: 3.8.1 - resolution: "prettier@npm:3.8.1" + version: 3.8.3 + resolution: "prettier@npm:3.8.3" bin: prettier: bin/prettier.cjs - checksum: 10/3da1cf8c1ef9bea828aa618553696c312e951f810bee368f6887109b203f18ee869fe88f66e65f9cf60b7cb1f2eae859892c860a300c062ff8ec69c381fc8dbd - languageName: node - linkType: hard - -"pretty-format@npm:^27.0.2": - version: 27.5.1 - resolution: "pretty-format@npm:27.5.1" - dependencies: - ansi-regex: "npm:^5.0.1" - ansi-styles: "npm:^5.0.0" - react-is: "npm:^17.0.1" - checksum: 10/248990cbef9e96fb36a3e1ae6b903c551ca4ddd733f8d0912b9cc5141d3d0b3f9f8dfb4d799fb1c6723382c9c2083ffbfa4ad43ff9a0e7535d32d41fd5f01da6 + checksum: 10/4b3b12cbb29e4c96bed936e5d070167552500c18d37676fb3e0caae6199c42860662608e4dc116230698f6e2bb0267ef2548158224c92d40f188d309d72fdd6f languageName: node linkType: hard @@ -12625,11 +11650,11 @@ __metadata: linkType: hard "prisma@npm:^6.19.2": - version: 6.19.2 - resolution: "prisma@npm:6.19.2" + version: 6.19.3 + resolution: "prisma@npm:6.19.3" dependencies: - "@prisma/config": "npm:6.19.2" - "@prisma/engines": "npm:6.19.2" + "@prisma/config": "npm:6.19.3" + "@prisma/engines": "npm:6.19.3" peerDependencies: typescript: ">=5.1.0" peerDependenciesMeta: @@ -12637,7 +11662,7 @@ __metadata: optional: true bin: prisma: build/index.js - checksum: 10/4ed40df535e5ab9dfbf40bff66d3feb44c3a3cc3d3f040bebdaaf5e147157edfec9fe742236775787384d86740889ba74255d7f66fcff30ab9bbbba8f5091b8e + checksum: 10/29f1890306c7365c5f7c079defabc7df96ea392f799606d3a0c943d4c37dd3cd2575e2fd41bf6af8a33be6f3b3bf493c2c19b0b34f79d880eaf2031dda8669c9 languageName: node linkType: hard @@ -12669,16 +11694,6 @@ __metadata: languageName: node linkType: hard -"promise-retry@npm:^2.0.1": - version: 2.0.1 - resolution: "promise-retry@npm:2.0.1" - dependencies: - err-code: "npm:^2.0.2" - retry: "npm:^0.12.0" - checksum: 10/96e1a82453c6c96eef53a37a1d6134c9f2482f94068f98a59145d0986ca4e497bf110a410adf73857e588165eab3899f0ebcf7b3890c1b3ce802abc0d65967d4 - languageName: node - linkType: hard - "prop-types@npm:^15.6.2": version: 15.8.1 resolution: "prop-types@npm:15.8.1" @@ -12691,9 +11706,9 @@ __metadata: linkType: hard "property-information@npm:^7.0.0": - version: 7.1.0 - resolution: "property-information@npm:7.1.0" - checksum: 10/896d38a52ad7170de73f832d277c69e76a9605d941ebb3f0d6e56271414a7fdf95ff6d2819e68036b8a0c7d2d4d88bf1d4a5765c032cb19c2343567ee3a14b15 + version: 7.2.0 + resolution: "property-information@npm:7.2.0" + checksum: 10/3e2919470164287dc69bc8da2c6365f674a6bd84dd670eb339af24576b0210d87edd3b7c461bf04d699d8444e94bfe9b6656c5fed3504cc277f8d72b12c8f5c1 languageName: node linkType: hard @@ -12705,22 +11720,22 @@ __metadata: linkType: hard "protobufjs@npm:^7.0.0": - version: 7.5.4 - resolution: "protobufjs@npm:7.5.4" + version: 7.6.2 + resolution: "protobufjs@npm:7.6.2" dependencies: "@protobufjs/aspromise": "npm:^1.1.2" "@protobufjs/base64": "npm:^1.1.2" - "@protobufjs/codegen": "npm:^2.0.4" - "@protobufjs/eventemitter": "npm:^1.1.0" - "@protobufjs/fetch": "npm:^1.1.0" + "@protobufjs/codegen": "npm:^2.0.5" + "@protobufjs/eventemitter": "npm:^1.1.1" + "@protobufjs/fetch": "npm:^1.1.1" "@protobufjs/float": "npm:^1.0.2" - "@protobufjs/inquire": "npm:^1.1.0" + "@protobufjs/inquire": "npm:^1.1.2" "@protobufjs/path": "npm:^1.1.2" "@protobufjs/pool": "npm:^1.1.0" - "@protobufjs/utf8": "npm:^1.1.0" + "@protobufjs/utf8": "npm:^1.1.1" "@types/node": "npm:>=13.7.0" - long: "npm:^5.0.0" - checksum: 10/88d677bb6f11a2ecec63fdd053dfe6d31120844d04e865efa9c8fbe0674cd077d6624ecfdf014018a20dcb114ae2a59c1b21966dd8073e920650c71370966439 + long: "npm:^5.3.2" + checksum: 10/964e39237febf2369cba371175a49602ccc7582f059504ab35e27adb01c690ad669bc2c134577f08f5fb55d1dc8320483f6a65a97f236dc6e749046d89283b5f languageName: node linkType: hard @@ -12741,20 +11756,20 @@ __metadata: languageName: node linkType: hard -"proxy-from-env@npm:^1.1.0": - version: 1.1.0 - resolution: "proxy-from-env@npm:1.1.0" - checksum: 10/f0bb4a87cfd18f77bc2fba23ae49c3b378fb35143af16cc478171c623eebe181678f09439707ad80081d340d1593cd54a33a0113f3ccb3f4bc9451488780ee23 +"proxy-from-env@npm:^2.1.0": + version: 2.1.0 + resolution: "proxy-from-env@npm:2.1.0" + checksum: 10/fbbaf4dab2a6231dc9e394903a5f66f20475e36b734335790b46feb9da07c37d6b32e2c02e3e2ea4d4b23774c53d8562e5b7cc73282cb43f4a597b7eacaee2ee languageName: node linkType: hard "pump@npm:^3.0.0": - version: 3.0.3 - resolution: "pump@npm:3.0.3" + version: 3.0.4 + resolution: "pump@npm:3.0.4" dependencies: end-of-stream: "npm:^1.1.0" once: "npm:^1.3.1" - checksum: 10/52843fc933b838c0330f588388115a1b28ef2a5ffa7774709b142e35431e8ab0c2edec90de3fa34ebb72d59fef854f151eea7dfc211b6dcf586b384556bd2f39 + checksum: 10/d043c3e710c56ffd280711e98a94e863ab334f79ea43cee0fb70e1349b2355ffd2ff287c7522e4c960a247699d5b7825f00fa090b85d6179c973be13f78a6c49 languageName: node linkType: hard @@ -12787,11 +11802,11 @@ __metadata: linkType: hard "qs@npm:^6.14.0, qs@npm:^6.14.1": - version: 6.14.2 - resolution: "qs@npm:6.14.2" + version: 6.15.2 + resolution: "qs@npm:6.15.2" dependencies: side-channel: "npm:^1.1.0" - checksum: 10/682933a85bb4b7bd0d66e13c0a40d9e612b5e4bcc2cb9238f711a9368cd22d91654097a74fff93551e58146db282c56ac094957dfdc60ce64ea72c3c9d7779ac + checksum: 10/7a934b2dba40654cf9878dab7c1e7ad56c6186265509727fbece67dadc38fd5d67715b61b6ef938e5a0475faeee701d18ec0a7ce420ad64367caad7f1bdb66e2 languageName: node linkType: hard @@ -12881,13 +11896,13 @@ __metadata: linkType: hard "react-dom@npm:^19.2.3": - version: 19.2.3 - resolution: "react-dom@npm:19.2.3" + version: 19.2.7 + resolution: "react-dom@npm:19.2.7" dependencies: scheduler: "npm:^0.27.0" peerDependencies: - react: ^19.2.3 - checksum: 10/5780f6d4c8e8ece09f82c5500ba2d55e01c30b5273f9281734d7d3b65013cd1fa52ec4e4436e5248c0a9e5bc340836044051168bbad8d7eac4d33ee6c2a867a1 + react: ^19.2.7 + checksum: 10/9564f4b83843ca5518ed5f807c93cb1663706559cde52f3ef814b41e60b63b16e684d849926458f0ba436745d7eabf822cba1c528be370e7b2f35a4c91e35941 languageName: node linkType: hard @@ -12898,13 +11913,6 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^17.0.1": - version: 17.0.2 - resolution: "react-is@npm:17.0.2" - checksum: 10/73b36281e58eeb27c9cc6031301b6ae19ecdc9f18ae2d518bdb39b0ac564e65c5779405d623f1df9abf378a13858b79442480244bd579968afc1faf9a2ce5e05 - languageName: node - linkType: hard - "react-markdown@npm:^10.1.0": version: 10.1.0 resolution: "react-markdown@npm:10.1.0" @@ -12928,12 +11936,12 @@ __metadata: linkType: hard "react-number-format@npm:^5.4.4": - version: 5.4.4 - resolution: "react-number-format@npm:5.4.4" + version: 5.4.5 + resolution: "react-number-format@npm:5.4.5" peerDependencies: react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10/e40a568a59ddccce3bdf23d0990cbd996e5c1d82f268ca5d23e6f926739fdac7370be0e836db543cc77c30e853fe5c849b58be29d867db4786deb2d2bd57cf33 + checksum: 10/48c5f7c13e6cabf70259ba3f98237b58ca37a998b2a24f35a1df8b285d63345b544c96a5a35d933daf26a9a31dc6353dd22133d0d0dc8f0bb33c5cdfab69b35c languageName: node linkType: hard @@ -12980,8 +11988,8 @@ __metadata: linkType: hard "react-router@npm:^7.12.0": - version: 7.12.0 - resolution: "react-router@npm:7.12.0" + version: 7.16.0 + resolution: "react-router@npm:7.16.0" dependencies: cookie: "npm:^1.0.1" set-cookie-parser: "npm:^2.6.0" @@ -12991,7 +11999,7 @@ __metadata: peerDependenciesMeta: react-dom: optional: true - checksum: 10/578324f792721200bd57a220c7931af692613943051c9bb0c6303613849ec9a2c2365a3a6afe1b3976c13edc8f71616bb9cfdb13c0ac501f239ad11a6884e3f8 + checksum: 10/2c77d27170eab1dfa6f0593e846f9d352424cc789a505aaee9bee9c9da1ed9d6a044d0a476e3eaf240e73b09169b4ffb85b5910d026a34abd055aed5b2f5a5cb languageName: node linkType: hard @@ -13040,9 +12048,9 @@ __metadata: linkType: hard "react@npm:^19.2.3": - version: 19.2.3 - resolution: "react@npm:19.2.3" - checksum: 10/d16b7f35c0d35a56f63d9d1693819762e4abc479c57dd6310298920bed3820fcec7e17a99d44983416d8f5049143ea45b8005d3ab8324bae8973224400502b08 + version: 19.2.7 + resolution: "react@npm:19.2.7" + checksum: 10/2939997e87d7f0ee0d9d2bb556866b616b999dfb7916283647034eda867a045a39c4f7a736c8ea6beffffcd78397fc30f63a7a3aaf8425b683c3060670859560 languageName: node linkType: hard @@ -13118,16 +12126,6 @@ __metadata: languageName: node linkType: hard -"redent@npm:^3.0.0": - version: 3.0.0 - resolution: "redent@npm:3.0.0" - dependencies: - indent-string: "npm:^4.0.0" - strip-indent: "npm:^3.0.0" - checksum: 10/fa1ef20404a2d399235e83cc80bd55a956642e37dd197b4b612ba7327bf87fa32745aeb4a1634b2bab25467164ab4ed9c15be2c307923dd08b0fe7c52431ae6b - languageName: node - linkType: hard - "redeyed@npm:~2.1.0": version: 2.1.1 resolution: "redeyed@npm:2.1.1" @@ -13242,36 +12240,31 @@ __metadata: languageName: node linkType: hard -"resolve-pkg-maps@npm:^1.0.0": - version: 1.0.0 - resolution: "resolve-pkg-maps@npm:1.0.0" - checksum: 10/0763150adf303040c304009231314d1e84c6e5ebfa2d82b7d94e96a6e82bacd1dcc0b58ae257315f3c8adb89a91d8d0f12928241cba2df1680fbe6f60bf99b0e - languageName: node - linkType: hard - "resolve@npm:^1.22.1": - version: 1.22.11 - resolution: "resolve@npm:1.22.11" + version: 1.22.12 + resolution: "resolve@npm:1.22.12" dependencies: + es-errors: "npm:^1.3.0" is-core-module: "npm:^2.16.1" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 10/e1b2e738884a08de03f97ee71494335eba8c2b0feb1de9ae065e82c48997f349f77a2b10e8817e147cf610bfabc4b1cb7891ee8eaf5bf80d4ad514a34c4fab0a + checksum: 10/1d2a081e4b7198e2a70abd7bbbf8aea5380c2d074b6c870035aab50ebfb7312b6492b3588e752faef83a75147862a3d3e09b222bc9afd536804181fd3a515ef9 languageName: node linkType: hard "resolve@patch:resolve@npm%3A^1.22.1#optional!builtin": - version: 1.22.11 - resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d" + version: 1.22.12 + resolution: "resolve@patch:resolve@npm%3A1.22.12#optional!builtin::version=1.22.12&hash=c3c19d" dependencies: + es-errors: "npm:^1.3.0" is-core-module: "npm:^2.16.1" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 10/fd342cad25e52cd6f4f3d1716e189717f2522bfd6641109fe7aa372f32b5714a296ed7c238ddbe7ebb0c1ddfe0b7f71c9984171024c97cf1b2073e3e40ff71a8 + checksum: 10/f80ad2c2b6820331cbe079198a184ffce322cfeca140065118066276bc08b03d5fa2c1ce652aeb584ec74050d1f656f46f034cc0dd9300452c5ab7866907f8c0 languageName: node linkType: hard @@ -13291,13 +12284,6 @@ __metadata: languageName: node linkType: hard -"retry@npm:^0.12.0": - version: 0.12.0 - resolution: "retry@npm:0.12.0" - checksum: 10/1f914879f97e7ee931ad05fe3afa629bd55270fc6cf1c1e589b6a99fab96d15daad0fa1a52a00c729ec0078045fe3e399bd4fd0c93bcc906957bdc17f89cb8e6 - languageName: node - linkType: hard - "reusify@npm:^1.0.4": version: 1.1.0 resolution: "reusify@npm:1.1.0" @@ -13306,164 +12292,135 @@ __metadata: linkType: hard "rimraf@npm:^6.1.2": - version: 6.1.2 - resolution: "rimraf@npm:6.1.2" + version: 6.1.3 + resolution: "rimraf@npm:6.1.3" dependencies: - glob: "npm:^13.0.0" + glob: "npm:^13.0.3" package-json-from-dist: "npm:^1.0.1" bin: rimraf: dist/esm/bin.mjs - checksum: 10/add8e566fe903f59d7b55c6c2382320c48302778640d1951baf247b3b451af496c2dee7195c204a8c646fd6327feadd1f5b61ce68c1362d4898075a726d83cc6 - languageName: node - linkType: hard - -"rollup-plugin-dts@npm:^6.3.0": - version: 6.3.0 - resolution: "rollup-plugin-dts@npm:6.3.0" - dependencies: - "@babel/code-frame": "npm:^7.27.1" - magic-string: "npm:^0.30.21" - peerDependencies: - rollup: ^3.29.4 || ^4 - typescript: ^4.5 || ^5.0 - dependenciesMeta: - "@babel/code-frame": - optional: true - checksum: 10/1b2b25126eee0c4e7f59d82ee5850b0c5779a1a0bb77d677798e20a3d29dba76d1a19a73300ed5b20aab02f6888ecc4209a95b07f6cc9c1b80af14bdcbeda5b9 - languageName: node - linkType: hard - -"rollup-plugin-tsconfig-paths@npm:^1.5.2": - version: 1.5.2 - resolution: "rollup-plugin-tsconfig-paths@npm:1.5.2" - dependencies: - typescript-paths: "npm:^1.5.1" - peerDependencies: - rollup: ^2 || ^3 || ^4 - checksum: 10/11e9cb8b096edc0dd17deba660213ec3047ea06790ff034984a3a6687acb0bd910a10ca825184f01a838a5c934021e8858e043c8668d0bf1fde389bf50240b78 + checksum: 10/dd98ec2ad7cd2cccae1c7110754d472eac8edb2bab8a8b057dce04edfe1433dab246a889b3fd85a66c78ca81caa1429caa0e736c7647f6832b04fd5d4dfb8ab8 languageName: node linkType: hard -"rollup@npm:^4.43.0": - version: 4.56.0 - resolution: "rollup@npm:4.56.0" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.56.0" - "@rollup/rollup-android-arm64": "npm:4.56.0" - "@rollup/rollup-darwin-arm64": "npm:4.56.0" - "@rollup/rollup-darwin-x64": "npm:4.56.0" - "@rollup/rollup-freebsd-arm64": "npm:4.56.0" - "@rollup/rollup-freebsd-x64": "npm:4.56.0" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.56.0" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.56.0" - "@rollup/rollup-linux-arm64-gnu": "npm:4.56.0" - "@rollup/rollup-linux-arm64-musl": "npm:4.56.0" - "@rollup/rollup-linux-loong64-gnu": "npm:4.56.0" - "@rollup/rollup-linux-loong64-musl": "npm:4.56.0" - "@rollup/rollup-linux-ppc64-gnu": "npm:4.56.0" - "@rollup/rollup-linux-ppc64-musl": "npm:4.56.0" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.56.0" - "@rollup/rollup-linux-riscv64-musl": "npm:4.56.0" - "@rollup/rollup-linux-s390x-gnu": "npm:4.56.0" - "@rollup/rollup-linux-x64-gnu": "npm:4.56.0" - "@rollup/rollup-linux-x64-musl": "npm:4.56.0" - "@rollup/rollup-openbsd-x64": "npm:4.56.0" - "@rollup/rollup-openharmony-arm64": "npm:4.56.0" - "@rollup/rollup-win32-arm64-msvc": "npm:4.56.0" - "@rollup/rollup-win32-ia32-msvc": "npm:4.56.0" - "@rollup/rollup-win32-x64-gnu": "npm:4.56.0" - "@rollup/rollup-win32-x64-msvc": "npm:4.56.0" - "@types/estree": "npm:1.0.8" - fsevents: "npm:~2.3.2" +"rolldown@npm:1.0.3": + version: 1.0.3 + resolution: "rolldown@npm:1.0.3" + dependencies: + "@oxc-project/types": "npm:=0.133.0" + "@rolldown/binding-android-arm64": "npm:1.0.3" + "@rolldown/binding-darwin-arm64": "npm:1.0.3" + "@rolldown/binding-darwin-x64": "npm:1.0.3" + "@rolldown/binding-freebsd-x64": "npm:1.0.3" + "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.3" + "@rolldown/binding-linux-arm64-gnu": "npm:1.0.3" + "@rolldown/binding-linux-arm64-musl": "npm:1.0.3" + "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.3" + "@rolldown/binding-linux-s390x-gnu": "npm:1.0.3" + "@rolldown/binding-linux-x64-gnu": "npm:1.0.3" + "@rolldown/binding-linux-x64-musl": "npm:1.0.3" + "@rolldown/binding-openharmony-arm64": "npm:1.0.3" + "@rolldown/binding-wasm32-wasi": "npm:1.0.3" + "@rolldown/binding-win32-arm64-msvc": "npm:1.0.3" + "@rolldown/binding-win32-x64-msvc": "npm:1.0.3" + "@rolldown/pluginutils": "npm:^1.0.0" dependenciesMeta: - "@rollup/rollup-android-arm-eabi": - optional: true - "@rollup/rollup-android-arm64": - optional: true - "@rollup/rollup-darwin-arm64": - optional: true - "@rollup/rollup-darwin-x64": - optional: true - "@rollup/rollup-freebsd-arm64": - optional: true - "@rollup/rollup-freebsd-x64": - optional: true - "@rollup/rollup-linux-arm-gnueabihf": - optional: true - "@rollup/rollup-linux-arm-musleabihf": - optional: true - "@rollup/rollup-linux-arm64-gnu": - optional: true - "@rollup/rollup-linux-arm64-musl": - optional: true - "@rollup/rollup-linux-loong64-gnu": + "@rolldown/binding-android-arm64": optional: true - "@rollup/rollup-linux-loong64-musl": + "@rolldown/binding-darwin-arm64": optional: true - "@rollup/rollup-linux-ppc64-gnu": + "@rolldown/binding-darwin-x64": optional: true - "@rollup/rollup-linux-ppc64-musl": + "@rolldown/binding-freebsd-x64": optional: true - "@rollup/rollup-linux-riscv64-gnu": + "@rolldown/binding-linux-arm-gnueabihf": optional: true - "@rollup/rollup-linux-riscv64-musl": + "@rolldown/binding-linux-arm64-gnu": optional: true - "@rollup/rollup-linux-s390x-gnu": + "@rolldown/binding-linux-arm64-musl": optional: true - "@rollup/rollup-linux-x64-gnu": + "@rolldown/binding-linux-ppc64-gnu": optional: true - "@rollup/rollup-linux-x64-musl": + "@rolldown/binding-linux-s390x-gnu": optional: true - "@rollup/rollup-openbsd-x64": + "@rolldown/binding-linux-x64-gnu": optional: true - "@rollup/rollup-openharmony-arm64": + "@rolldown/binding-linux-x64-musl": optional: true - "@rollup/rollup-win32-arm64-msvc": + "@rolldown/binding-openharmony-arm64": optional: true - "@rollup/rollup-win32-ia32-msvc": + "@rolldown/binding-wasm32-wasi": optional: true - "@rollup/rollup-win32-x64-gnu": + "@rolldown/binding-win32-arm64-msvc": optional: true - "@rollup/rollup-win32-x64-msvc": + "@rolldown/binding-win32-x64-msvc": optional: true - fsevents: + bin: + rolldown: ./bin/cli.mjs + checksum: 10/4dbe2c055104c47c15c051b713068cf4660acd473841904d3f7118f730922b2e498176610a45826cbc1ffe36842a29a076385d3bfcd5acb0f7ef8ad06b8feefb + languageName: node + linkType: hard + +"rollup-plugin-dts@npm:^6.3.0": + version: 6.4.1 + resolution: "rollup-plugin-dts@npm:6.4.1" + dependencies: + "@babel/code-frame": "npm:^7.29.0" + "@jridgewell/remapping": "npm:^2.3.5" + "@jridgewell/sourcemap-codec": "npm:^1.5.5" + convert-source-map: "npm:^2.0.0" + magic-string: "npm:^0.30.21" + peerDependencies: + rollup: ^3.29.4 || ^4 + typescript: ^4.5 || ^5.0 || ^6.0 + dependenciesMeta: + "@babel/code-frame": optional: true - bin: - rollup: dist/bin/rollup - checksum: 10/dc5a590fb7bea4dda9a43ba893e5982986c38a41a9fd09e70821cdad201f692d4aba9f9b9c160a50994ced66dbbfac2e3d26d60f5ca73a5414b8e8104f974a32 - languageName: node - linkType: hard - -"rollup@npm:^4.59.0": - version: 4.59.0 - resolution: "rollup@npm:4.59.0" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.59.0" - "@rollup/rollup-android-arm64": "npm:4.59.0" - "@rollup/rollup-darwin-arm64": "npm:4.59.0" - "@rollup/rollup-darwin-x64": "npm:4.59.0" - "@rollup/rollup-freebsd-arm64": "npm:4.59.0" - "@rollup/rollup-freebsd-x64": "npm:4.59.0" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.59.0" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.59.0" - "@rollup/rollup-linux-arm64-gnu": "npm:4.59.0" - "@rollup/rollup-linux-arm64-musl": "npm:4.59.0" - "@rollup/rollup-linux-loong64-gnu": "npm:4.59.0" - "@rollup/rollup-linux-loong64-musl": "npm:4.59.0" - "@rollup/rollup-linux-ppc64-gnu": "npm:4.59.0" - "@rollup/rollup-linux-ppc64-musl": "npm:4.59.0" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.59.0" - "@rollup/rollup-linux-riscv64-musl": "npm:4.59.0" - "@rollup/rollup-linux-s390x-gnu": "npm:4.59.0" - "@rollup/rollup-linux-x64-gnu": "npm:4.59.0" - "@rollup/rollup-linux-x64-musl": "npm:4.59.0" - "@rollup/rollup-openbsd-x64": "npm:4.59.0" - "@rollup/rollup-openharmony-arm64": "npm:4.59.0" - "@rollup/rollup-win32-arm64-msvc": "npm:4.59.0" - "@rollup/rollup-win32-ia32-msvc": "npm:4.59.0" - "@rollup/rollup-win32-x64-gnu": "npm:4.59.0" - "@rollup/rollup-win32-x64-msvc": "npm:4.59.0" - "@types/estree": "npm:1.0.8" + checksum: 10/a18685fde4c59339cacb47e084ff589b39fc680d186b496b83197370295002f748066e3c9c62ced2eca1af0bca77d3096bb24905c40c0478a6d845d63531293d + languageName: node + linkType: hard + +"rollup-plugin-tsconfig-paths@npm:^1.5.2": + version: 1.5.2 + resolution: "rollup-plugin-tsconfig-paths@npm:1.5.2" + dependencies: + typescript-paths: "npm:^1.5.1" + peerDependencies: + rollup: ^2 || ^3 || ^4 + checksum: 10/11e9cb8b096edc0dd17deba660213ec3047ea06790ff034984a3a6687acb0bd910a10ca825184f01a838a5c934021e8858e043c8668d0bf1fde389bf50240b78 + languageName: node + linkType: hard + +"rollup@npm:^4.43.0, rollup@npm:^4.59.0": + version: 4.61.0 + resolution: "rollup@npm:4.61.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.61.0" + "@rollup/rollup-android-arm64": "npm:4.61.0" + "@rollup/rollup-darwin-arm64": "npm:4.61.0" + "@rollup/rollup-darwin-x64": "npm:4.61.0" + "@rollup/rollup-freebsd-arm64": "npm:4.61.0" + "@rollup/rollup-freebsd-x64": "npm:4.61.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.61.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.61.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.61.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.61.0" + "@rollup/rollup-linux-loong64-gnu": "npm:4.61.0" + "@rollup/rollup-linux-loong64-musl": "npm:4.61.0" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.61.0" + "@rollup/rollup-linux-ppc64-musl": "npm:4.61.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.61.0" + "@rollup/rollup-linux-riscv64-musl": "npm:4.61.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.61.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.61.0" + "@rollup/rollup-linux-x64-musl": "npm:4.61.0" + "@rollup/rollup-openbsd-x64": "npm:4.61.0" + "@rollup/rollup-openharmony-arm64": "npm:4.61.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.61.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.61.0" + "@rollup/rollup-win32-x64-gnu": "npm:4.61.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.61.0" + "@types/estree": "npm:1.0.9" fsevents: "npm:~2.3.2" dependenciesMeta: "@rollup/rollup-android-arm-eabi": @@ -13520,7 +12477,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10/728237932aad7022c0640cd126b9fe5285f2578099f22a0542229a17785320a6553b74582fa5977877541c1faf27de65ed2750bc89dbb55b525405244a46d9f1 + checksum: 10/66809d13e2ee2108a33a86488a61ed3d8424ad94002d7c38ffbd078b58e3215b6469453760c56a8b550c592c3dd7235761a95866c31c166730530c368ff59340 languageName: node linkType: hard @@ -13537,28 +12494,6 @@ __metadata: languageName: node linkType: hard -"rpc-websockets@npm:^9.0.2": - version: 9.3.3 - resolution: "rpc-websockets@npm:9.3.3" - dependencies: - "@swc/helpers": "npm:^0.5.11" - "@types/uuid": "npm:^8.3.4" - "@types/ws": "npm:^8.2.2" - buffer: "npm:^6.0.3" - bufferutil: "npm:^4.0.1" - eventemitter3: "npm:^5.0.1" - utf-8-validate: "npm:^5.0.2" - uuid: "npm:^8.3.2" - ws: "npm:^8.5.0" - dependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 10/0d4e72bc7799e1d8329bc696f517ade34f52ef9244ceffe96a32d1567f04ae4746eae57bb6af7735e78c6040dce393b20add6b1c0cc8726f4677ee0f61e1d46c - languageName: node - linkType: hard - "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -13632,12 +12567,12 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.5, semver@npm:^7.3.8, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.7.3": - version: 7.7.3 - resolution: "semver@npm:7.7.3" +"semver@npm:^7.3.5, semver@npm:^7.3.8, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.7.3, semver@npm:^7.7.4, semver@npm:^7.8.1": + version: 7.8.1 + resolution: "semver@npm:7.8.1" bin: semver: bin/semver.js - checksum: 10/8dbc3168e057a38fc322af909c7f5617483c50caddba135439ff09a754b20bdd6482a5123ff543dad4affa488ecf46ec5fb56d61312ad20bb140199b88dfaea9 + checksum: 10/3244f6c4cb3f8126fea0426d353829ed4967e41e1f4696337c6fdcad87426466fe2badaf49d7dc85849acfc496ea0599432a4aecc33802d2d774e723acfa30e6 languageName: node linkType: hard @@ -13757,12 +12692,12 @@ __metadata: linkType: hard "side-channel-list@npm:^1.0.0": - version: 1.0.0 - resolution: "side-channel-list@npm:1.0.0" + version: 1.0.1 + resolution: "side-channel-list@npm:1.0.1" dependencies: es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - checksum: 10/603b928997abd21c5a5f02ae6b9cc36b72e3176ad6827fab0417ead74580cc4fb4d5c7d0a8a2ff4ead34d0f9e35701ed7a41853dac8a6d1a664fcce1a044f86f + object-inspect: "npm:^1.13.4" + checksum: 10/3499671cd52adaee739eac1e14d07530b8e3530192741aeb05e7fe4ad1b51d1368ceea2cd3c21b0f62b05410a5c70a7c4d997ba4b143303ef73d0c65dfd1c252 languageName: node linkType: hard @@ -13856,17 +12791,10 @@ __metadata: languageName: node linkType: hard -"smart-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "smart-buffer@npm:4.2.0" - checksum: 10/927484aa0b1640fd9473cee3e0a0bcad6fce93fd7bbc18bac9ad0c33686f5d2e2c422fba24b5899c184524af01e11dd2bd051c2bf2b07e47aff8ca72cbfc60d2 - languageName: node - linkType: hard - "smob@npm:^1.0.0": - version: 1.5.0 - resolution: "smob@npm:1.5.0" - checksum: 10/a1ea453bcea89989062626ea30a1fcb42c62e96255619c8641ffa1d7ab42baf415975c67c718127036901b9e487d8bf4c46219e50cec54295412c1227700b8fe + version: 1.6.2 + resolution: "smob@npm:1.6.2" + checksum: 10/500799e7887cd8557de610666d206f1e2d073b34ef2732d9565c940afa9e9555f0e42268044e10eb7f061054fa3ed7c2a6f6387b13c1ceb3370f50f299acd34f languageName: node linkType: hard @@ -13893,33 +12821,12 @@ __metadata: linkType: hard "socket.io-parser@npm:~4.2.4": - version: 4.2.5 - resolution: "socket.io-parser@npm:4.2.5" + version: 4.2.6 + resolution: "socket.io-parser@npm:4.2.6" dependencies: "@socket.io/component-emitter": "npm:~3.1.0" debug: "npm:~4.4.1" - checksum: 10/612b3ba068327cbdca043d07f8d96da587a18e0b3e00f002b6476c22410c891abafc44a3f009abd014f2de42b348032f465a7b19771151728f6361ed116423d2 - languageName: node - linkType: hard - -"socks-proxy-agent@npm:^8.0.3": - version: 8.0.5 - resolution: "socks-proxy-agent@npm:8.0.5" - dependencies: - agent-base: "npm:^7.1.2" - debug: "npm:^4.3.4" - socks: "npm:^2.8.3" - checksum: 10/ee99e1dacab0985b52cbe5a75640be6e604135e9489ebdc3048635d186012fbaecc20fbbe04b177dee434c319ba20f09b3e7dfefb7d932466c0d707744eac05c - languageName: node - linkType: hard - -"socks@npm:^2.8.3": - version: 2.8.7 - resolution: "socks@npm:2.8.7" - dependencies: - ip-address: "npm:^10.0.1" - smart-buffer: "npm:^4.2.0" - checksum: 10/d19366c95908c19db154f329bbe94c2317d315dc933a7c2b5101e73f32a555c84fb199b62174e1490082a593a4933d8d5a9b297bde7d1419c14a11a965f51356 + checksum: 10/cf8f3e9feee42b2405065bccef732894a0b07b7cb734c4954eb8876d7a0038e7df6e6d06fab3a25f816f5d996917391833d5f06136e8c8c6fbecf5da962c1c9e languageName: node linkType: hard @@ -13946,23 +12853,6 @@ __metadata: languageName: node linkType: hard -"sort-package-json@npm:3.6.0": - version: 3.6.0 - resolution: "sort-package-json@npm:3.6.0" - dependencies: - detect-indent: "npm:^7.0.2" - detect-newline: "npm:^4.0.1" - git-hooks-list: "npm:^4.1.1" - is-plain-obj: "npm:^4.1.0" - semver: "npm:^7.7.3" - sort-object-keys: "npm:^2.0.1" - tinyglobby: "npm:^0.2.15" - bin: - sort-package-json: cli.js - checksum: 10/1489edd177dc325c1e5fbfa55e9583dfea8caa950363b43f797d99986f00b722644275f4dfd5491265519365d6394a5fec9fe5d360ed83b74317fdc9fc071ba1 - languageName: node - linkType: hard - "sort-package-json@npm:^2.15.1": version: 2.15.1 resolution: "sort-package-json@npm:2.15.1" @@ -13981,6 +12871,23 @@ __metadata: languageName: node linkType: hard +"sort-package-json@npm:^3.6.0": + version: 3.6.1 + resolution: "sort-package-json@npm:3.6.1" + dependencies: + detect-indent: "npm:^7.0.2" + detect-newline: "npm:^4.0.1" + git-hooks-list: "npm:^4.1.1" + is-plain-obj: "npm:^4.1.0" + semver: "npm:^7.7.3" + sort-object-keys: "npm:^2.0.1" + tinyglobby: "npm:^0.2.15" + bin: + sort-package-json: cli.js + checksum: 10/e4bcf8432b570143e94b6b302fc941fd0b564e8f9f423bc55ae469c81e6f84c35e456f024d8d186a2ec6ca120407444e6ceb5a5f0feb7c877c159ef716f651ed + languageName: node + linkType: hard + "source-map-js@npm:^1.2.1": version: 1.2.1 resolution: "source-map-js@npm:1.2.1" @@ -14050,9 +12957,9 @@ __metadata: linkType: hard "spdx-license-ids@npm:^3.0.0": - version: 3.0.22 - resolution: "spdx-license-ids@npm:3.0.22" - checksum: 10/a2f214aaf74c21a0172232367ce785157cef45d78617ee4d12aa1246350af566968e28b511e2096b707611566ac3959b85d8bf2d53a65bc6b66580735d3e1965 + version: 3.0.23 + resolution: "spdx-license-ids@npm:3.0.23" + checksum: 10/fead6be44478e4dd73a0721ae569f4a04f358846d8d82e8d92efae64aca928592e380cf17e8b84c25c948f3a7d8a0b4fc781a1830f3911ca87d52733265176b5 languageName: node linkType: hard @@ -14077,15 +12984,6 @@ __metadata: languageName: node linkType: hard -"ssri@npm:^13.0.0": - version: 13.0.0 - resolution: "ssri@npm:13.0.0" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/fd59bfedf0659c1b83f6e15459162da021f08ec0f5834dd9163296f8b77ee82f9656aa1d415c3d3848484293e0e6aefdd482e863e52ddb53d520bb73da1eeec1 - languageName: node - linkType: hard - "stackback@npm:0.0.2": version: 0.0.2 resolution: "stackback@npm:0.0.2" @@ -14100,26 +12998,10 @@ __metadata: languageName: node linkType: hard -"std-env@npm:^3.10.0": - version: 3.10.0 - resolution: "std-env@npm:3.10.0" - checksum: 10/19c9cda4f370b1ffae2b8b08c72167d8c3e5cfa972aaf5c6873f85d0ed2faa729407f5abb194dc33380708c00315002febb6f1e1b484736bfcf9361ad366013a - languageName: node - linkType: hard - -"stream-chain@npm:^2.2.5": - version: 2.2.5 - resolution: "stream-chain@npm:2.2.5" - checksum: 10/f9c65fe21251106083ca753d8b36f5a35dc426f5cb12851d9a872b6eb69e30ea2c94d87887bfda8c820503e842183812922532fb2adab18d5878d31a4516b956 - languageName: node - linkType: hard - -"stream-json@npm:^1.9.1": - version: 1.9.1 - resolution: "stream-json@npm:1.9.1" - dependencies: - stream-chain: "npm:^2.2.5" - checksum: 10/8c97d3078127aaf70197b0e4b5ca668307f1768a4eb1ac4c2030056e1f862d7a11b83094b87d2b04c3c14f76a8a8657eb87b1760d57781c172e3a513c7e2b5fd +"std-env@npm:^4.0.0-rc.1": + version: 4.1.0 + resolution: "std-env@npm:4.1.0" + checksum: 10/008146cdb834010383138d356e0dd3e3b0ac127a8229f711b8c518bb22940813cc0dcd654fc76b17f0b18179f56089f8b8e52bd6a7ffa0041a966581e7a44dbe languageName: node linkType: hard @@ -14137,7 +13019,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -14148,17 +13030,6 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^5.0.1, string-width@npm:^5.1.2": - version: 5.1.2 - resolution: "string-width@npm:5.1.2" - dependencies: - eastasianwidth: "npm:^0.2.0" - emoji-regex: "npm:^9.2.2" - strip-ansi: "npm:^7.0.1" - checksum: 10/7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 - languageName: node - linkType: hard - "string_decoder@npm:^1.1.1, string_decoder@npm:^1.3.0": version: 1.3.0 resolution: "string_decoder@npm:1.3.0" @@ -14187,7 +13058,7 @@ __metadata: languageName: node linkType: hard -"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": +"strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" dependencies: @@ -14196,15 +13067,6 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^7.0.1": - version: 7.1.2 - resolution: "strip-ansi@npm:7.1.2" - dependencies: - ansi-regex: "npm:^6.0.1" - checksum: 10/db0e3f9654e519c8a33c50fc9304d07df5649388e7da06d3aabf66d29e5ad65d5e6315d8519d409c15b32fa82c1df7e11ed6f8cd50b0e4404463f0c9d77c8d0b - languageName: node - linkType: hard - "strip-bom@npm:^3.0.0": version: 3.0.0 resolution: "strip-bom@npm:3.0.0" @@ -14219,15 +13081,6 @@ __metadata: languageName: node linkType: hard -"strip-indent@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-indent@npm:3.0.0" - dependencies: - min-indent: "npm:^1.0.0" - checksum: 10/18f045d57d9d0d90cd16f72b2313d6364fd2cb4bf85b9f593523ad431c8720011a4d5f08b6591c9d580f446e78855c5334a30fb91aa1560f5d9f95ed1b4a0530 - languageName: node - linkType: hard - "strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -14235,10 +13088,10 @@ __metadata: languageName: node linkType: hard -"strnum@npm:^2.1.0": - version: 2.1.2 - resolution: "strnum@npm:2.1.2" - checksum: 10/7d894dff385e3a5c5b29c012cf0a7ea7962a92c6a299383c3d6db945ad2b6f3e770511356a9774dbd54444c56af1dc7c435dad6466c47293c48173274dd6c631 +"strnum@npm:^2.2.3": + version: 2.3.0 + resolution: "strnum@npm:2.3.0" + checksum: 10/ce79c86bb2b96f053eb28e14924c13604e22977dcdece9aa914c25e16cc5c4bbe048976fe0b2a4decf08a1e13600b820749cea25463fc0e5fee3078339e0a457 languageName: node linkType: hard @@ -14276,13 +13129,6 @@ __metadata: languageName: node linkType: hard -"superstruct@npm:^2.0.2": - version: 2.0.2 - resolution: "superstruct@npm:2.0.2" - checksum: 10/10e1944a9da4baee187fbaa6c5d97d7af266b55786dfe50bce67f0f1e7d93f1a5a42dd51e245a2e16404f8336d07c21c67f1c1fbc4ad0a252d3d2601d6c926da - languageName: node - linkType: hard - "supports-color@npm:^7.0.0, supports-color@npm:^7.1.0": version: 7.2.0 resolution: "supports-color@npm:7.2.0" @@ -14318,12 +13164,12 @@ __metadata: languageName: node linkType: hard -"synckit@npm:^0.11.12": - version: 0.11.12 - resolution: "synckit@npm:0.11.12" +"synckit@npm:^0.11.13": + version: 0.11.13 + resolution: "synckit@npm:0.11.13" dependencies: - "@pkgr/core": "npm:^0.2.9" - checksum: 10/2f51978bfed81aaf0b093f596709a72c49b17909020f42b43c5549f9c0fe18b1fe29f82e41ef771172d729b32e9ce82900a85d2b87fa14d59f886d4df8d7a329 + "@pkgr/core": "npm:^0.3.6" + checksum: 10/188544a829dbd38abd144281960835c1f8027aaa495b7c40d39ebf0c1c63a4a41c0edc42818b7ada9b5c0c15fba2f625b472220d128798fe98f9181fed84e6a2 languageName: node linkType: hard @@ -14334,16 +13180,16 @@ __metadata: languageName: node linkType: hard -"tar@npm:^7.5.2": - version: 7.5.10 - resolution: "tar@npm:7.5.10" +"tar@npm:^7.5.4": + version: 7.5.16 + resolution: "tar@npm:7.5.16" dependencies: "@isaacs/fs-minipass": "npm:^4.0.0" chownr: "npm:^3.0.0" minipass: "npm:^7.1.2" minizlib: "npm:^3.1.0" yallist: "npm:^5.0.0" - checksum: 10/98ba6421a250b233c36a54f7441647bdfee1ed0b916cd57850259a3602154d996f5b8422f67ef5c8ce77f582ed938054775c2873fc7c901e0c7530ed50febc40 + checksum: 10/fafa22efceb9f056bf29ddc47d9bd90bb82fe3ce57b8d1242fc45771251741964cebba69d4e14a24fd1643f3c7f68478e945a19def534703cf370c2d9dca2e09 languageName: node linkType: hard @@ -14355,8 +13201,8 @@ __metadata: linkType: hard "terser@npm:^5.17.4": - version: 5.46.0 - resolution: "terser@npm:5.46.0" + version: 5.48.0 + resolution: "terser@npm:5.48.0" dependencies: "@jridgewell/source-map": "npm:^0.3.3" acorn: "npm:^8.15.0" @@ -14364,14 +13210,7 @@ __metadata: source-map-support: "npm:~0.5.20" bin: terser: bin/terser - checksum: 10/331e4f5a165d91d16ac6a95b510d4f5ef24679e4bc9e1b4e4182e89b7245f614d24ce0def583e2ca3ca45f82ba810991e0c5b66dd4353a6e0b7082786af6bd35 - languageName: node - linkType: hard - -"text-encoding-utf-8@npm:^1.0.2": - version: 1.0.2 - resolution: "text-encoding-utf-8@npm:1.0.2" - checksum: 10/845bb4bd058d6ec7bb9e1f00be7dab394cd7facd270e2bc266912e975ffe29bc3953cce369da70b92bec964ddc48961c3a5146402d094e11a7a4654e4a365204 + checksum: 10/dfbb121823b703bed2f36b7464e2ee5c7a9147fcebdb0c40e372318796b9a13e34b0610fd8af983e4d849a5b060262e08e2601d16032849086afa831fbf7f690 languageName: node linkType: hard @@ -14398,27 +13237,27 @@ __metadata: languageName: node linkType: hard -"tinyexec@npm:^1.0.2": - version: 1.0.2 - resolution: "tinyexec@npm:1.0.2" - checksum: 10/cb709ed4240e873d3816e67f851d445f5676e0ae3a52931a60ff571d93d388da09108c8057b62351766133ee05ff3159dd56c3a0fbd39a5933c6639ce8771405 +"tinyexec@npm:^1.0.2, tinyexec@npm:^1.1.1": + version: 1.2.4 + resolution: "tinyexec@npm:1.2.4" + checksum: 10/f20b3e6f56f24c3ebe0129d0b6e657e561d225df2cf93c1a10362996232dd6ad4b8af8c9e81d258a64d09020e723772baf6fe0be26512dba7c61bb366d67b1f9 languageName: node linkType: hard -"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.14, tinyglobby@npm:^0.2.15, tinyglobby@npm:^0.2.9": - version: 0.2.15 - resolution: "tinyglobby@npm:0.2.15" +"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.14, tinyglobby@npm:^0.2.15, tinyglobby@npm:^0.2.16, tinyglobby@npm:^0.2.17, tinyglobby@npm:^0.2.9": + version: 0.2.17 + resolution: "tinyglobby@npm:0.2.17" dependencies: fdir: "npm:^6.5.0" - picomatch: "npm:^4.0.3" - checksum: 10/d72bd826a8b0fa5fa3929e7fe5ba48fceb2ae495df3a231b6c5408cd7d8c00b58ab5a9c2a76ba56a62ee9b5e083626f1f33599734bed1ffc4b792406408f0ca2 + picomatch: "npm:^4.0.4" + checksum: 10/f85e8a217d675c3f78d5f0ad25ea4557e7e023ed13ddc2b014da10bd0312eea53a34cd52356af07ccdff777f1243012547656282a4ca70936f68bf5065fbaa71 languageName: node linkType: hard -"tinyrainbow@npm:^3.0.3": - version: 3.0.3 - resolution: "tinyrainbow@npm:3.0.3" - checksum: 10/169cc63c15e1378674180f3207c82c05bfa58fc79992e48792e8d97b4b759012f48e95297900ede24a81f0087cf329a0d85bb81109739eacf03c650127b3f6c1 +"tinyrainbow@npm:^3.1.0": + version: 3.1.0 + resolution: "tinyrainbow@npm:3.1.0" + checksum: 10/4c2c01dde1e5bb9a74973daaae141d4d733d246280b2f9a7f6a9e7dd8e940d48b2580a6086125278777897bc44635d6ccec5f9f563c2179dd2129f4542d0ec05 languageName: node linkType: hard @@ -14477,12 +13316,12 @@ __metadata: languageName: node linkType: hard -"ts-api-utils@npm:^2.4.0": - version: 2.4.0 - resolution: "ts-api-utils@npm:2.4.0" +"ts-api-utils@npm:^2.5.0": + version: 2.5.0 + resolution: "ts-api-utils@npm:2.5.0" peerDependencies: typescript: ">=4.8.4" - checksum: 10/d6b2b3b6caad8d2f4ddc0c3785d22bb1a6041773335a1c71d73a5d67d11d993763fe8e4faefc4a4d03bb42b26c6126bbcf2e34826baed1def5369d0ebad358fa + checksum: 10/d5f1936f5618c6ab6942a97b78802217540ced00e7501862ae1f578d9a3aa189fc06050e64cb8951d21f7088e5fd35f53d2bf0d0370a883861c7b05e993ebc44 languageName: node linkType: hard @@ -14514,7 +13353,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2, tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.6.0, tslib@npm:^2.6.2, tslib@npm:^2.8.0, tslib@npm:^2.8.1": +"tslib@npm:^2, tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.6.0, tslib@npm:^2.6.2, tslib@npm:^2.8.1": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7 @@ -14522,18 +13361,17 @@ __metadata: linkType: hard "tsx@npm:^4.21.0": - version: 4.21.0 - resolution: "tsx@npm:4.21.0" + version: 4.22.4 + resolution: "tsx@npm:4.22.4" dependencies: - esbuild: "npm:~0.27.0" + esbuild: "npm:~0.28.0" fsevents: "npm:~2.3.3" - get-tsconfig: "npm:^4.7.5" dependenciesMeta: fsevents: optional: true bin: tsx: dist/cli.mjs - checksum: 10/7afedeff855ba98c47dc28b33d7e8e253c4dc1f791938db402d79c174bdf806b897c1a5f91e5b1259c112520c816f826b4c5d98f0bad7e95b02dec66fedb64d2 + checksum: 10/9d6e7e9d1158eb84327d822720a2053bcfd972f8988e4789041bac5a767fc394ef302b1ff7e1d3dfbee391a0b03bd3dbb02cd302387729baf1dc7b9dce93b3ba languageName: node linkType: hard @@ -14546,74 +13384,32 @@ __metadata: languageName: node linkType: hard -"turbo-darwin-64@npm:2.7.5": - version: 2.7.5 - resolution: "turbo-darwin-64@npm:2.7.5" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"turbo-darwin-arm64@npm:2.7.5": - version: 2.7.5 - resolution: "turbo-darwin-arm64@npm:2.7.5" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"turbo-linux-64@npm:2.7.5": - version: 2.7.5 - resolution: "turbo-linux-64@npm:2.7.5" - conditions: os=linux & cpu=x64 - languageName: node - linkType: hard - -"turbo-linux-arm64@npm:2.7.5": - version: 2.7.5 - resolution: "turbo-linux-arm64@npm:2.7.5" - conditions: os=linux & cpu=arm64 - languageName: node - linkType: hard - -"turbo-windows-64@npm:2.7.5": - version: 2.7.5 - resolution: "turbo-windows-64@npm:2.7.5" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"turbo-windows-arm64@npm:2.7.5": - version: 2.7.5 - resolution: "turbo-windows-arm64@npm:2.7.5" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - "turbo@npm:^2.7.5": - version: 2.7.5 - resolution: "turbo@npm:2.7.5" - dependencies: - turbo-darwin-64: "npm:2.7.5" - turbo-darwin-arm64: "npm:2.7.5" - turbo-linux-64: "npm:2.7.5" - turbo-linux-arm64: "npm:2.7.5" - turbo-windows-64: "npm:2.7.5" - turbo-windows-arm64: "npm:2.7.5" + version: 2.9.16 + resolution: "turbo@npm:2.9.16" + dependencies: + "@turbo/darwin-64": "npm:2.9.16" + "@turbo/darwin-arm64": "npm:2.9.16" + "@turbo/linux-64": "npm:2.9.16" + "@turbo/linux-arm64": "npm:2.9.16" + "@turbo/windows-64": "npm:2.9.16" + "@turbo/windows-arm64": "npm:2.9.16" dependenciesMeta: - turbo-darwin-64: + "@turbo/darwin-64": optional: true - turbo-darwin-arm64: + "@turbo/darwin-arm64": optional: true - turbo-linux-64: + "@turbo/linux-64": optional: true - turbo-linux-arm64: + "@turbo/linux-arm64": optional: true - turbo-windows-64: + "@turbo/windows-64": optional: true - turbo-windows-arm64: + "@turbo/windows-arm64": optional: true bin: turbo: bin/turbo - checksum: 10/fe9c2c8c55242ae102bf30494f8830749fc91c0fade85a2ad376eb3df0d5aa3452f222dbf080f852f2f8a2197fec3b607e0cec63fae096f48b5fff2228caaff6 + checksum: 10/a151be0f24bd66802d36b0303eb5ed21bbe05077265831ea457554fb7b859b7cfdd35938e3b3812c5aa86721935032c9f1d03c247b17786a2ea7aecb65b82e1d languageName: node linkType: hard @@ -14641,13 +13437,13 @@ __metadata: linkType: hard "type-is@npm:^2.0.1": - version: 2.0.1 - resolution: "type-is@npm:2.0.1" + version: 2.1.0 + resolution: "type-is@npm:2.1.0" dependencies: - content-type: "npm:^1.0.5" + content-type: "npm:^2.0.0" media-typer: "npm:^1.1.0" mime-types: "npm:^3.0.0" - checksum: 10/bacdb23c872dacb7bd40fbd9095e6b2fca2895eedbb689160c05534d7d4810a7f4b3fd1ae87e96133c505958f6d602967a68db5ff577b85dd6be76eaa75d58af + checksum: 10/f011885fefb6c6882f36fab89cc596596b96eab1d208a3774628537cad7ce1f91232a6d758115e1a6ed03f0f8c21e9654bb6d280a5c6827ff72a35f6df0fa182 languageName: node linkType: hard @@ -14663,26 +13459,26 @@ __metadata: linkType: hard "typescript-eslint@npm:^8.53.1": - version: 8.53.1 - resolution: "typescript-eslint@npm:8.53.1" + version: 8.60.1 + resolution: "typescript-eslint@npm:8.60.1" dependencies: - "@typescript-eslint/eslint-plugin": "npm:8.53.1" - "@typescript-eslint/parser": "npm:8.53.1" - "@typescript-eslint/typescript-estree": "npm:8.53.1" - "@typescript-eslint/utils": "npm:8.53.1" + "@typescript-eslint/eslint-plugin": "npm:8.60.1" + "@typescript-eslint/parser": "npm:8.60.1" + "@typescript-eslint/typescript-estree": "npm:8.60.1" + "@typescript-eslint/utils": "npm:8.60.1" peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10/7065be8cb4ec2ab4bd53d7342b4c1ea51d96a735cd86496040e34d7b8f1adfc846055b39f0ba80c2c224e0ee49b9273de167f915ffb5cc75e392011c15d7be50 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10/e12091ab2540b817c76b0ec6aad92e341f810310bec2b24bc95780aee106049c05363998f6ea52ed066130c8afc41dca1627f56e4c1df1dd519f4d4ca0ce4910 languageName: node linkType: hard "typescript-paths@npm:^1.5.1": - version: 1.5.1 - resolution: "typescript-paths@npm:1.5.1" + version: 1.5.2 + resolution: "typescript-paths@npm:1.5.2" peerDependencies: - typescript: ^4.7.2 || ^5 - checksum: 10/755aecb40a1015152c31f1b3b8e587330aca05e8dfb7e4e48df28add152c9cc257a16df98c58f31724d9b210199f56feb2710db3e7da948ab6f607d32fb6a572 + typescript: ^4.7.2 || ^5 || ^6 + checksum: 10/4a05bd0d12a3ed129017082b920e0677a36f2f8130f5b784c2292670e5fe18f4b527b794b741207187bea2148055ccfb7205e2c2949d7b84a608f773090a7b29 languageName: node linkType: hard @@ -14707,9 +13503,9 @@ __metadata: linkType: hard "ufo@npm:^1.6.1, ufo@npm:^1.6.3": - version: 1.6.3 - resolution: "ufo@npm:1.6.3" - checksum: 10/79803984f3e414567273a666183d6a50d1bec0d852100a98f55c1e393cb705e3b88033e04029dd651714e6eec99e1b00f54fdc13f32404968251a16f8898cfe5 + version: 1.6.4 + resolution: "ufo@npm:1.6.4" + checksum: 10/dbf85425e00dd106abb852c0ea4cef6e58b395b9a43858049a8be0b0825e5cc4b53cf58a41da695c3c2a9ab4f8605923b64812be1358c39a56b3920504759d3a languageName: node linkType: hard @@ -14745,10 +13541,17 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:^7.18.2": - version: 7.19.0 - resolution: "undici-types@npm:7.19.0" - checksum: 10/9bdac5c59b8d8374e90d0b4d4ba768253134d699670e026eb4d43387a655b10e9bfae3027e79ee58cc1fa0b7db81eb5e1b151a35801c02f9e7fe40491f440661 +"undici-types@npm:>=7.24.0 <7.24.7": + version: 7.24.6 + resolution: "undici-types@npm:7.24.6" + checksum: 10/defc9538b952e3c15b8526596c591f7c1f0c7605ad27a2b7feddbea7ef2e3003f3eda2cdb051a3cb1a2185e3893100fd9cb925c799db99d48131ea63b5233d10 + languageName: node + linkType: hard + +"undici-types@npm:^7.19.2": + version: 7.27.0 + resolution: "undici-types@npm:7.27.0" + checksum: 10/a986d66d90db440f2a3e00ff1205f08b56689f64cb62a2cf406499a24a7f89dcfa72ede40150eedbfc6bdbc3676467b7a61b011ff5c89b053622e33656c708b9 languageName: node linkType: hard @@ -14775,6 +13578,13 @@ __metadata: languageName: node linkType: hard +"undici@npm:^6.25.0": + version: 6.26.0 + resolution: "undici@npm:6.26.0" + checksum: 10/a1715ee4304f58fecd61e0a8c3bd7064435cfbc98b3ec1414dba5e89de97d436b7e88dd094b06ff8440428bf36b56163fc88972118890826039865edf58bdfcf + languageName: node + linkType: hard + "unicorn-magic@npm:^0.1.0": version: 0.1.0 resolution: "unicorn-magic@npm:0.1.0" @@ -14804,24 +13614,6 @@ __metadata: languageName: node linkType: hard -"unique-filename@npm:^5.0.0": - version: 5.0.0 - resolution: "unique-filename@npm:5.0.0" - dependencies: - unique-slug: "npm:^6.0.0" - checksum: 10/a5f67085caef74bdd2a6869a200ed5d68d171f5cc38435a836b5fd12cce4e4eb55e6a190298035c325053a5687ed7a3c96f0a91e82215fd14729769d9ac57d9b - languageName: node - linkType: hard - -"unique-slug@npm:^6.0.0": - version: 6.0.0 - resolution: "unique-slug@npm:6.0.0" - dependencies: - imurmurhash: "npm:^0.1.4" - checksum: 10/b78ed9d5b01ff465f80975f17387750ed3639909ac487fa82c4ae4326759f6de87c2131c0c39eca4c68cf06c537a8d104fba1dfc8a30308f99bc505345e1eba3 - languageName: node - linkType: hard - "unist-util-is@npm:^6.0.0": version: 6.0.1 resolution: "unist-util-is@npm:6.0.1" @@ -14885,14 +13677,14 @@ __metadata: linkType: hard "unstorage@npm:^1.9.0": - version: 1.17.4 - resolution: "unstorage@npm:1.17.4" + version: 1.17.5 + resolution: "unstorage@npm:1.17.5" dependencies: anymatch: "npm:^3.1.3" chokidar: "npm:^5.0.0" destr: "npm:^2.0.5" - h3: "npm:^1.15.5" - lru-cache: "npm:^11.2.0" + h3: "npm:^1.15.10" + lru-cache: "npm:^11.2.7" node-fetch-native: "npm:^1.6.7" ofetch: "npm:^1.5.1" ufo: "npm:^1.6.3" @@ -14955,11 +13747,11 @@ __metadata: optional: true uploadthing: optional: true - checksum: 10/db66f4f7a49db7e769df70beb02b8368c4a4dd34a37af0dfe65e6370fc3a1d5691768b34ea6c2133daae3d79db0070c93f7c03289784dcfef755ebbad6c79643 + checksum: 10/e0059c08e87a86d2a43dc2a49853fd6bc324f655f3dba59fec2b1eb59bb784495772013a5925017a2970d63b9921d31d9211d42a361f810d3c20bded57c13d46 languageName: node linkType: hard -"update-browserslist-db@npm:^1.2.0": +"update-browserslist-db@npm:^1.2.3": version: 1.2.3 resolution: "update-browserslist-db@npm:1.2.3" dependencies: @@ -15219,9 +14011,9 @@ __metadata: languageName: node linkType: hard -"viem@npm:>=2.29.0, viem@npm:^2.1.1, viem@npm:^2.21.26, viem@npm:^2.27.2, viem@npm:^2.31.7, viem@npm:^2.37.6, viem@npm:^2.44.4": - version: 2.44.4 - resolution: "viem@npm:2.44.4" +"viem@npm:>=2.29.0, viem@npm:^2.1.1, viem@npm:^2.27.2, viem@npm:^2.31.7, viem@npm:^2.37.6, viem@npm:^2.44.4, viem@npm:^2.47.0": + version: 2.52.0 + resolution: "viem@npm:2.52.0" dependencies: "@noble/curves": "npm:1.9.1" "@noble/hashes": "npm:1.8.0" @@ -15229,37 +14021,90 @@ __metadata: "@scure/bip39": "npm:1.6.0" abitype: "npm:1.2.3" isows: "npm:1.0.7" - ox: "npm:0.11.3" - ws: "npm:8.18.3" + ox: "npm:0.14.27" + ws: "npm:8.20.1" peerDependencies: typescript: ">=5.0.4" peerDependenciesMeta: typescript: optional: true - checksum: 10/1af511dcd8b995a5a9914723ade0b6a65b0cf0a8bc7059bd6114cb2d5c3aae662cf62739d06cc1f210bfa14fcdab1ec78986836cdc6fc4b770e0cce676b4914f + checksum: 10/9adc38ea2f93a57172eeae4d73c44e5bce7013cf9518beffd69dedd8ff1bb013cdcd953527b0c19e24539d4f85b1b89381f78444056ad7ff3b61493385ed5f6b languageName: node linkType: hard "vite-tsconfig-paths@npm:^6.0.4": - version: 6.0.4 - resolution: "vite-tsconfig-paths@npm:6.0.4" + version: 6.1.1 + resolution: "vite-tsconfig-paths@npm:6.1.1" dependencies: debug: "npm:^4.1.1" globrex: "npm:^0.1.2" tsconfck: "npm:^3.0.3" - vite: "npm:*" peerDependencies: vite: "*" + checksum: 10/f752bce4f3c5707f0df7af8a20294b1f325e26f50578b82c8262d851028616ebb1a3e73ab0789c55cf3c8da8d985e843193c0bec2cb31662c567ccdf137f1fd0 + languageName: node + linkType: hard + +"vite@npm:^6.0.0 || ^7.0.0 || ^8.0.0": + version: 8.0.16 + resolution: "vite@npm:8.0.16" + dependencies: + fsevents: "npm:~2.3.3" + lightningcss: "npm:^1.32.0" + picomatch: "npm:^4.0.4" + postcss: "npm:^8.5.15" + rolldown: "npm:1.0.3" + tinyglobby: "npm:^0.2.17" + peerDependencies: + "@types/node": ^20.19.0 || >=22.12.0 + "@vitejs/devtools": ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: ">=1.21.0" + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: ">=0.54.8" + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + dependenciesMeta: + fsevents: + optional: true peerDependenciesMeta: - vite: + "@types/node": + optional: true + "@vitejs/devtools": + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: optional: true - checksum: 10/85f871cd5e321f2865972559b01c518664e6e34f9039b630dd77c2f379f8fdc386e15f7237aa5c108d813030c6e9bc8edfbf61687df7684803111a2495edadac + bin: + vite: bin/vite.js + checksum: 10/a5d91d26f6110672a292a06ca161af9a58279fe9d27106c8c0afb725a942b0b47091c440c3b1e7ebc8e0fe901f64ac6a2ffee3cdae2f899339686dbecd0c0266 languageName: node linkType: hard -"vite@npm:*, vite@npm:^6.0.0 || ^7.0.0, vite@npm:^7.3.1": - version: 7.3.1 - resolution: "vite@npm:7.3.1" +"vite@npm:^7.3.1": + version: 7.3.5 + resolution: "vite@npm:7.3.5" dependencies: esbuild: "npm:^0.27.0" fdir: "npm:^6.5.0" @@ -15308,44 +14153,47 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10/62e48ffa4283b688f0049005405a004447ad38ffc99a0efea4c3aa9b7eed739f7402b43f00668c0ee5a895b684dc953d62f0722d8a92c5b2f6c95f051bceb208 + checksum: 10/2e1337510d6b81948b035f8b096c9be22daf1101fc52ad3d06cad9e090057ba1c1396e5e12cbaac2485f9c6cdcc854f978fe862280bdfe1a9a4149c60734c125 languageName: node linkType: hard "vitest@npm:^4.0.18": - version: 4.0.18 - resolution: "vitest@npm:4.0.18" - dependencies: - "@vitest/expect": "npm:4.0.18" - "@vitest/mocker": "npm:4.0.18" - "@vitest/pretty-format": "npm:4.0.18" - "@vitest/runner": "npm:4.0.18" - "@vitest/snapshot": "npm:4.0.18" - "@vitest/spy": "npm:4.0.18" - "@vitest/utils": "npm:4.0.18" - es-module-lexer: "npm:^1.7.0" - expect-type: "npm:^1.2.2" + version: 4.1.8 + resolution: "vitest@npm:4.1.8" + dependencies: + "@vitest/expect": "npm:4.1.8" + "@vitest/mocker": "npm:4.1.8" + "@vitest/pretty-format": "npm:4.1.8" + "@vitest/runner": "npm:4.1.8" + "@vitest/snapshot": "npm:4.1.8" + "@vitest/spy": "npm:4.1.8" + "@vitest/utils": "npm:4.1.8" + es-module-lexer: "npm:^2.0.0" + expect-type: "npm:^1.3.0" magic-string: "npm:^0.30.21" obug: "npm:^2.1.1" pathe: "npm:^2.0.3" picomatch: "npm:^4.0.3" - std-env: "npm:^3.10.0" + std-env: "npm:^4.0.0-rc.1" tinybench: "npm:^2.9.0" tinyexec: "npm:^1.0.2" tinyglobby: "npm:^0.2.15" - tinyrainbow: "npm:^3.0.3" - vite: "npm:^6.0.0 || ^7.0.0" + tinyrainbow: "npm:^3.1.0" + vite: "npm:^6.0.0 || ^7.0.0 || ^8.0.0" why-is-node-running: "npm:^2.3.0" peerDependencies: "@edge-runtime/vm": "*" "@opentelemetry/api": ^1.9.0 "@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0 - "@vitest/browser-playwright": 4.0.18 - "@vitest/browser-preview": 4.0.18 - "@vitest/browser-webdriverio": 4.0.18 - "@vitest/ui": 4.0.18 + "@vitest/browser-playwright": 4.1.8 + "@vitest/browser-preview": 4.1.8 + "@vitest/browser-webdriverio": 4.1.8 + "@vitest/coverage-istanbul": 4.1.8 + "@vitest/coverage-v8": 4.1.8 + "@vitest/ui": 4.1.8 happy-dom: "*" jsdom: "*" + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: "@edge-runtime/vm": optional: true @@ -15359,15 +14207,21 @@ __metadata: optional: true "@vitest/browser-webdriverio": optional: true + "@vitest/coverage-istanbul": + optional: true + "@vitest/coverage-v8": + optional: true "@vitest/ui": optional: true happy-dom: optional: true jsdom: optional: true + vite: + optional: false bin: vitest: vitest.mjs - checksum: 10/6c6464ebcf3af83546862896fd1b5f10cb6607261bffce39df60033a288b8c1687ae1dd20002b6e4997a7a05303376d1eb58ce20afe63be052529a4378a8c165 + checksum: 10/b9f1308436717da9558b36e149cac6bab8e3730aa7e90b49f9d7a84ba853e353d8afba7d406dc0abec731fb2a9ea9e92b89aba06b94b1a2802203048b43468af languageName: node linkType: hard @@ -15391,13 +14245,13 @@ __metadata: linkType: hard "web3bio-profile-kit@npm:^0.1.38": - version: 0.1.38 - resolution: "web3bio-profile-kit@npm:0.1.38" + version: 0.1.43 + resolution: "web3bio-profile-kit@npm:0.1.43" peerDependencies: "@tanstack/react-query": ^4.0.0 || ^5.0.0 react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 10/136f7c7738225a8fffaa2c85447495df416abba63bc14e078cfc93baf3f37f49248b413c73cdc4c69f464af9cb5195b9b83857803b78517ebe162906e6607506 + checksum: 10/e8ef7dc4a974dae5eaa5f72aa9311b8959cf5a6045745587054f87280e9b80b56f41fff6c37ae6adc0aca25c7a6f088b3eeb666d3d1e67a6e21f0fc9bb8b81c7 languageName: node linkType: hard @@ -15440,17 +14294,17 @@ __metadata: linkType: hard "which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.2": - version: 1.1.20 - resolution: "which-typed-array@npm:1.1.20" + version: 1.1.21 + resolution: "which-typed-array@npm:1.1.21" dependencies: available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" + call-bind: "npm:^1.0.9" call-bound: "npm:^1.0.4" for-each: "npm:^0.3.5" get-proto: "npm:^1.0.1" gopd: "npm:^1.2.0" has-tostringtag: "npm:^1.0.2" - checksum: 10/e56da3fc995d330ff012f682476f7883c16b12d36c6717c87c7ca23eb5a5ef957fa89115dacb389b11a9b4e99d5dbe2d12689b4d5d08c050b5aed0eae385b840 + checksum: 10/7b763b3dfcf086daf4ded9a4d1eae9a3ac589c3c0803598a811272bdc63720653af8c4c3184fb5fa4fb492ce03312a1f9343119800eb5bb00f274598e78061d5 languageName: node linkType: hard @@ -15466,13 +14320,13 @@ __metadata: linkType: hard "which@npm:^6.0.0": - version: 6.0.0 - resolution: "which@npm:6.0.0" + version: 6.0.1 + resolution: "which@npm:6.0.1" dependencies: - isexe: "npm:^3.1.1" + isexe: "npm:^4.0.0" bin: node-which: bin/which.js - checksum: 10/df19b2cd8aac94b333fa29b42e8e371a21e634a742a3b156716f7752a5afe1d73fb5d8bce9b89326f453d96879e8fe626eb421e0117eb1a3ce9fd8c97f6b7db9 + checksum: 10/dbea77c7d3058bf6c78bf9659d2dce4d2b57d39a15b826b2af6ac2e5a219b99dc8a831b79fdbc453c0598adb4f3f84cf9c2491fd52beb9f5d2dececcad117f68 languageName: node linkType: hard @@ -15511,17 +14365,6 @@ __metadata: languageName: node linkType: hard -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": - version: 7.0.0 - resolution: "wrap-ansi@npm:7.0.0" - dependencies: - ansi-styles: "npm:^4.0.0" - string-width: "npm:^4.1.0" - strip-ansi: "npm:^6.0.0" - checksum: 10/cebdaeca3a6880da410f75209e68cd05428580de5ad24535f22696d7d9cab134d1f8498599f344c3cf0fb37c1715807a183778d8c648d6cc0cb5ff2bb4236540 - languageName: node - linkType: hard - "wrap-ansi@npm:^6.2.0": version: 6.2.0 resolution: "wrap-ansi@npm:6.2.0" @@ -15533,14 +14376,14 @@ __metadata: languageName: node linkType: hard -"wrap-ansi@npm:^8.1.0": - version: 8.1.0 - resolution: "wrap-ansi@npm:8.1.0" +"wrap-ansi@npm:^7.0.0": + version: 7.0.0 + resolution: "wrap-ansi@npm:7.0.0" dependencies: - ansi-styles: "npm:^6.1.0" - string-width: "npm:^5.0.1" - strip-ansi: "npm:^7.0.1" - checksum: 10/7b1e4b35e9bb2312d2ee9ee7dc95b8cb5f8b4b5a89f7dde5543fe66c1e3715663094defa50d75454ac900bd210f702d575f15f3f17fa9ec0291806d2578d1ddf + ansi-styles: "npm:^4.0.0" + string-width: "npm:^4.1.0" + strip-ansi: "npm:^6.0.0" + checksum: 10/cebdaeca3a6880da410f75209e68cd05428580de5ad24535f22696d7d9cab134d1f8498599f344c3cf0fb37c1715807a183778d8c648d6cc0cb5ff2bb4236540 languageName: node linkType: hard @@ -15566,9 +14409,9 @@ __metadata: languageName: node linkType: hard -"ws@npm:8.18.3, ws@npm:~8.18.3": - version: 8.18.3 - resolution: "ws@npm:8.18.3" +"ws@npm:8.20.1, ws@npm:~8.20.1": + version: 8.20.1 + resolution: "ws@npm:8.20.1" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -15577,13 +14420,13 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 10/725964438d752f0ab0de582cd48d6eeada58d1511c3f613485b5598a83680bedac6187c765b0fe082e2d8cc4341fc57707c813ae780feee82d0c5efe6a4c61b6 + checksum: 10/8c4d2b06dc65381b6bfab1f2e584275dabd30a99a5ce058b4dc76f3d03fad1921cef3a21d8f53127d30a808cfd1864aa2fe6890a5d43359f682457315baec873 languageName: node linkType: hard -"ws@npm:^7.5.1, ws@npm:^7.5.10": - version: 7.5.10 - resolution: "ws@npm:7.5.10" +"ws@npm:^7.5.1": + version: 7.5.11 + resolution: "ws@npm:7.5.11" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -15592,13 +14435,13 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 10/9c796b84ba80ffc2c2adcdfc9c8e9a219ba99caa435c9a8d45f9ac593bba325563b3f83edc5eb067cc6d21b9a6bf2c930adf76dd40af5f58a5ca6859e81858f0 + checksum: 10/486141e4a01bb75883f9ba39317309c2427e24db1cb75e340fad6e5886b65c03d994a34209f0e4ba06dd6cb9ec95dd1b6a09c52c05eed9a34d6376f4fbbf617c languageName: node linkType: hard -"ws@npm:^8.18.3, ws@npm:^8.19.0, ws@npm:^8.5.0": - version: 8.19.0 - resolution: "ws@npm:8.19.0" +"ws@npm:^8.19.0": + version: 8.21.0 + resolution: "ws@npm:8.21.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -15607,7 +14450,14 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 10/26e4901e93abaf73af9f26a93707c95b4845e91a7a347ec8c569e6e9be7f9df066f6c2b817b2d685544e208207898a750b78461e6e8d810c11a370771450c31b + checksum: 10/088411956432c8f876158409d5a285cb9ad1382f593391f51d3a599bd0a5b277f876609ebd00fc3596321c4a4c9064d6fffe1ebad960e8ea7fd9ae25324f35c2 + languageName: node + linkType: hard + +"xml-naming@npm:^0.1.0": + version: 0.1.0 + resolution: "xml-naming@npm:0.1.0" + checksum: 10/45abd94ba64a508bda3f4d0b70e49811a3c3542596252c213caf47c858bbe9bba365ebba8eeff68e2a876e22a1bf6855d90cd2019b2f28012cebb167a4df2293 languageName: node linkType: hard @@ -15690,13 +14540,6 @@ __metadata: languageName: node linkType: hard -"yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 10/4cb02b42b8a93b5cf50caf5d8e9beb409400a8a4d85e83bb0685c1457e9ac0b7a00819e9f5991ac25ffabb56a78e2f017c1acc010b3a1babfe6de690ba531abd - languageName: node - linkType: hard - "yallist@npm:^5.0.0": version: 5.0.0 resolution: "yallist@npm:5.0.0" @@ -15762,21 +14605,22 @@ __metadata: linkType: hard "zod-prisma-types@npm:^3.3.10": - version: 3.3.10 - resolution: "zod-prisma-types@npm:3.3.10" + version: 3.3.11 + resolution: "zod-prisma-types@npm:3.3.11" dependencies: - "@prisma/dmmf": "npm:^7.0.1" - "@prisma/generator-helper": "npm:^7.0.1" + "@prisma/client-runtime-utils": "npm:^7.3.0" + "@prisma/dmmf": "npm:^7.3.0" + "@prisma/generator-helper": "npm:^7.3.0" code-block-writer: "npm:^13.0.3" - lodash: "npm:^4.17.21" - zod: "npm:^4.1.11" + lodash: "npm:^4.17.23" + zod: "npm:^4.3.6" peerDependencies: "@prisma/client": ^4.x.x || ^5.x.x || ^6.x.x || ^7.x.x prisma: ^4.x.x || ^5.x.x || ^6.x.x || ^7.x.x zod: ^3.25.0 || ^4.0.0 bin: zod-prisma-types: dist/bin.js - checksum: 10/6d433c07900dfc1a4223a86a92b7a0a31b29f7d6959d83996d276c8a9c8fbc87fa33d44d85bd811c100b5d16d41ab8ac6c4a949aa67c8abeabff88292920f33a + checksum: 10/437a7104a5fcf1f65bc0783d3d21d1f39309849192195b3b68b1df427484b2177f4fdc20cf1a0619e0044fa1be7f7d433a7133dd563e3777e90bf0431c75f1f7 languageName: node linkType: hard @@ -15787,17 +14631,17 @@ __metadata: languageName: node linkType: hard -"zod@npm:^3.24.4": +"zod@npm:^3.25.76": version: 3.25.76 resolution: "zod@npm:3.25.76" checksum: 10/f0c963ec40cd96858451d1690404d603d36507c1fc9682f2dae59ab38b578687d542708a7fdbf645f77926f78c9ed558f57c3d3aa226c285f798df0c4da16995 languageName: node linkType: hard -"zod@npm:^4.1.11, zod@npm:^4.1.5, zod@npm:^4.3.6": - version: 4.3.6 - resolution: "zod@npm:4.3.6" - checksum: 10/25fc0f62e01b557b4644bf0b393bbaf47542ab30877c37837ea8caf314a8713d220c7d7fe51f68ffa72f0e1018ddfa34d96f1973d23033f5a2a5a9b6b9d9da01 +"zod@npm:^4.1.5, zod@npm:^4.3.6": + version: 4.4.3 + resolution: "zod@npm:4.4.3" + checksum: 10/804b9a42aa8f35f2b3c5a8dff906291cb749115f83ee2afe3576d70b5b5c53c965365c7f4967690647a9c54af9838ff232a85ff9577a0a36c44b68bc6cdefe36 languageName: node linkType: hard @@ -15844,8 +14688,8 @@ __metadata: linkType: hard "zustand@npm:^5.0.1, zustand@npm:^5.0.10": - version: 5.0.10 - resolution: "zustand@npm:5.0.10" + version: 5.0.14 + resolution: "zustand@npm:5.0.14" peerDependencies: "@types/react": ">=18.0.0" immer: ">=9.0.6" @@ -15860,7 +14704,7 @@ __metadata: optional: true use-sync-external-store: optional: true - checksum: 10/1a48812ef1f5dc8ead8eb05c9861d1627d4ec79302f3b329cb3029d07e0325c44beb1829d2d2bbc511cf42e4f26be496723813f1117effa1ee10c2e83834c9ff + checksum: 10/136ab316fa4fa479ce7cc0cf485665dcee9e1bd926d4e51e138cd40d6602900fd2a4b6bb172b39b03bd7b6df073a0656679e5a237c28dd026d8fd4e5228e1b7c languageName: node linkType: hard