Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/meteor/app/utils/client/lib/SDKClient.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { RestClientInterface } from '@rocket.chat/api-client';
import type { SDK, ClientStream, StreamKeys, StreamNames, StreamerCallbackArgs, ServerMethods } from '@rocket.chat/ddp-client';
import { Emitter } from '@rocket.chat/emitter';
import { DDPCommon } from 'meteor/ddp-common';
import { Meteor } from 'meteor/meteor';

import { APIClient } from './RestApiClient';
import { parseDDP } from '../../../../client/lib/sdk/ddpProtocol';
import { ensureConnectedAndAuthenticated, getDdpSdk } from '../../../../client/lib/sdk/ddpSdk';
import { isSdkTransportEnabled } from '../../../../client/lib/sdk/sdkTransportEnabled';

Expand Down Expand Up @@ -267,7 +267,7 @@ const createStreamManager = () => {
// the SDK socket and createNewDdpSdkStream registers its own onCollection
// listener instead.
Meteor.connection._stream!.on('message', (rawMsg: string) => {
const msg = DDPCommon.parseDDP(rawMsg);
const msg = parseDDP(rawMsg);
if (!isChangedCollectionPayload(msg)) {
return;
}
Expand Down
4 changes: 4 additions & 0 deletions apps/meteor/client/lib/presence.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ jest.mock('meteor/meteor', () => ({
Meteor: {
subscribe: jest.fn(),
},
DDPCommon: {
parseDDP: jest.fn((msg: string) => JSON.parse(msg)),
stringifyDDP: jest.fn((msg: unknown) => JSON.stringify(msg)),
},
}));

const mockGet = jest.fn();
Expand Down
10 changes: 10 additions & 0 deletions apps/meteor/client/lib/sdk/ddpProtocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Single point of access to the DDP wire codec. Today it forwards to Meteor's
// `ddp-common` package; the eventual replacement will be a standalone EJSON
// helper. Consumers MUST import parseDDP / stringifyDDP from here so the codec
// stays swappable.

import { DDPCommon } from 'meteor/ddp-common';

export const { parseDDP, stringifyDDP } = DDPCommon;

export type DDPMessage = Parameters<typeof stringifyDDP>[0];
5 changes: 3 additions & 2 deletions apps/meteor/client/lib/sdk/meteorBackedSdk.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { DDPSDK } from '@rocket.chat/ddp-client';
import { Emitter } from '@rocket.chat/emitter';
import { Accounts } from 'meteor/accounts-base';
import { DDPCommon } from 'meteor/ddp-common';
import { Meteor } from 'meteor/meteor';

import { parseDDP } from './ddpProtocol';

/**
* Meteor-backed pass-through DDPSDK used when the SDK transport is OFF.
*
Expand Down Expand Up @@ -100,7 +101,7 @@ const createMeteorBackedClient = () => {
const handler = (rawMsg: string): void => {
let msg: unknown;
try {
msg = DDPCommon.parseDDP(rawMsg);
msg = parseDDP(rawMsg);
} catch {
return;
}
Expand Down
10 changes: 5 additions & 5 deletions apps/meteor/client/meteor/overrides/ddpOverREST.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DDPCommon } from 'meteor/ddp-common';
import { Meteor } from 'meteor/meteor';

import { sdk } from '../../../app/utils/client/lib/SDKClient';
import { parseDDP, stringifyDDP } from '../../lib/sdk/ddpProtocol';
import { getUserId } from '../../lib/user';

const bypassMethods: string[] = ['setUserStatus', 'logout'];
Expand Down Expand Up @@ -79,7 +79,7 @@ const withDDPOverREST = (_send: (this: Meteor.IMeteorConnection, message: Meteor
const endpoint = !getUserId() || wasResumeLogin ? 'method.callAnon' : 'method.call';

const restParams = {
message: DDPCommon.stringifyDDP({ ...message }),
message: stringifyDDP({ ...message }),
};

const method = encodeURIComponent(message.method.replace(/\//g, ':'));
Expand All @@ -92,7 +92,7 @@ const withDDPOverREST = (_send: (this: Meteor.IMeteorConnection, message: Meteor
// processed, but the Accounts.onLogin callbacks fire before that follow-up request — so any requests
// initiated inside onLogin callbacks queue behind the loginWithToken and only run after it completes.
if (!wasResumeLogin && message.method === 'login') {
const parsedMessage = DDPCommon.parseDDP(_message) as { result?: { token?: string } };
const parsedMessage = parseDDP(_message) as { result?: { token?: string } };
if (parsedMessage.result?.token) {
Meteor.loginWithToken(parsedMessage.result.token);
}
Expand All @@ -110,7 +110,7 @@ const withDDPOverREST = (_send: (this: Meteor.IMeteorConnection, message: Meteor
// open the 2FA modal.
if (typeof e.message === 'string') {
try {
const parsed = DDPCommon.parseDDP(e.message) as { msg?: string; id?: string };
const parsed = parseDDP(e.message) as { msg?: string; id?: string };
if (parsed?.msg === 'result' && parsed.id === message.id) {
processResult(e.message);
console.error(error);
Expand All @@ -126,7 +126,7 @@ const withDDPOverREST = (_send: (this: Meteor.IMeteorConnection, message: Meteor
// plain string — not a DDP frame. Re-encode as a proper DDP error
// result so Accounts' resume callback clears stale creds and the
// user isn't wedged on /home with no main UI.
const errorMessage = DDPCommon.stringifyDDP({
const errorMessage = stringifyDDP({
msg: 'result',
id: message.id,
error: {
Expand Down
6 changes: 2 additions & 4 deletions apps/meteor/client/meteor/overrides/ddpSdkCollectionBridge.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DDPCommon } from 'meteor/ddp-common';
import { Meteor } from 'meteor/meteor';

import { type DDPMessage, stringifyDDP } from '../../lib/sdk/ddpProtocol';
import { getDdpSdk } from '../../lib/sdk/ddpSdk';
import { isSdkTransportEnabled } from '../../lib/sdk/sdkTransportEnabled';

Expand Down Expand Up @@ -80,9 +80,7 @@ export const installDdpSdkCollectionBridge = (): void => {
// rejections are contained — Meteor keeps draining the queue even when
// individual frames hit dead invokers.
try {
const result = Meteor.connection._streamHandlers.onMessage(
DDPCommon.stringifyDDP(frame as Parameters<typeof DDPCommon.stringifyDDP>[0]),
) as unknown;
const result = Meteor.connection._streamHandlers.onMessage(stringifyDDP(frame as DDPMessage)) as unknown;
if (result && typeof (result as Promise<unknown>).then === 'function') {
(result as Promise<unknown>).catch((err) => {
console.warn('[ddpSdk] bridge frame drop (async)', frame.msg, err);
Expand Down
12 changes: 5 additions & 7 deletions apps/meteor/client/meteor/overrides/stubMeteorStream.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Accounts } from 'meteor/accounts-base';
import { DDPCommon } from 'meteor/ddp-common';
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';

import { type DDPMessage, parseDDP, stringifyDDP } from '../../lib/sdk/ddpProtocol';
import { adoptAccountFromMeteorLoginResult, getDdpSdk } from '../../lib/sdk/ddpSdk';
import { isSdkTransportEnabled } from '../../lib/sdk/sdkTransportEnabled';

Expand Down Expand Up @@ -85,7 +85,7 @@ function installStubMeteorStream(): void {
send(data) {
let frame: { msg?: string; id?: string; method?: string; name?: string; params?: unknown[] } | undefined;
try {
frame = DDPCommon.parseDDP(data) as typeof frame;
frame = parseDDP(data) as typeof frame;
} catch {
return;
}
Expand Down Expand Up @@ -114,9 +114,7 @@ function installStubMeteorStream(): void {
};

const bridgePongFor = (id?: string): void => {
conn._streamHandlers.onMessage(
DDPCommon.stringifyDDP({ msg: 'pong', ...(id != null && { id }) } as unknown as Parameters<typeof DDPCommon.stringifyDDP>[0]),
);
conn._streamHandlers.onMessage(stringifyDDP({ msg: 'pong', ...(id != null && { id }) } as unknown as DDPMessage));
};

type SdkDdp = {
Expand Down Expand Up @@ -178,10 +176,10 @@ function installStubMeteorStream(): void {
if (c._lastSessionId) return;
try {
conn._streamHandlers.onMessage(
DDPCommon.stringifyDDP({
stringifyDDP({
msg: 'connected',
session: 'sdk-bridged',
} as unknown as Parameters<typeof DDPCommon.stringifyDDP>[0]),
} as unknown as DDPMessage),
);
fire('reset');
} catch (err) {
Expand Down
5 changes: 5 additions & 0 deletions apps/meteor/tests/mocks/client/meteor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,8 @@ export const EJSON = {
clone: jest.fn((obj) => obj),
equals: jest.fn((a, b) => JSON.stringify(a) === JSON.stringify(b)),
};

export const DDPCommon = {
parseDDP: jest.fn((msg: string) => JSON.parse(msg)),
stringifyDDP: jest.fn((msg: unknown) => JSON.stringify(msg)),
};
Loading