Skip to content

Commit

Permalink
chore: Segregate rest and streaming directory (#915)
Browse files Browse the repository at this point in the history
* chore: Segregate rest and streaming directory

* chore: Segregate interfaces and adapters

* chore: Prettify tests directory

* chore: Move implementations to adapters

* chore: Use inline type import
  • Loading branch information
neet committed Jul 27, 2023
1 parent bc4a94a commit e42295f
Show file tree
Hide file tree
Showing 258 changed files with 711 additions and 717 deletions.
12 changes: 9 additions & 3 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
},
"env": {
"browser": true,
"node": true,
"jest": true
"node": true
},
"rules": {
"no-console": "error",
"import/no-cycle": "error",
"simple-import-sort/imports": "error",
"unicorn/prevent-abbreviations": "off",
"unicorn/no-array-reduce": "off"
Expand Down Expand Up @@ -46,7 +46,7 @@
],
"@typescript-eslint/consistent-type-imports": [
"error",
{ "prefer": "type-imports" }
{ "prefer": "type-imports", "fixStyle": "inline-type-imports" }
]
}
},
Expand All @@ -58,6 +58,12 @@
"unicorn/prefer-top-level-await": "off",
"unicorn/no-process-exit": "off"
}
},
{
"files": ["tests/**/*.ts", "**/*.spec.ts"],
"env": {
"jest": true
}
}
]
}
3 changes: 1 addition & 2 deletions examples/create-new-status.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { mastodon } from 'masto';
import { createRestClient } from 'masto';
import { createRestClient, type mastodon } from 'masto';

const masto = await createRestClient({
url: 'https://example.com',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"test:unit": "jest --coverage --config=jest.config.cjs --selectProjects unit",
"test:e2e": "jest --coverage --config=jest.config.cjs --selectProjects e2e",
"lint": "npm-run-all lint:*",
"lint:eslint": "eslint --ext ts --report-unused-disable-directives --cache src",
"lint:eslint": "eslint --ext ts --report-unused-disable-directives --cache '{src,examples,tests,test-utils}/**/*'",
"lint:spellcheck": "cspell '{src,examples}/**/*.{ts,tsx,js,json,md}'",
"build": "rollup -c rollup.config.cjs",
"prepublishOnly": "yarn run build",
Expand Down
2 changes: 1 addition & 1 deletion src/__mocks__/http-mock-impl.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Http } from '../http/http';
import { Http } from '../interfaces';

export const httpRequest = jest.fn();
export const httpGet = jest.fn();
Expand Down
2 changes: 1 addition & 1 deletion src/__mocks__/logger-mock-impl.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BaseLogger } from '../logger';
import { BaseLogger } from '../adapters/logger';

export const log = jest.fn();

Expand Down
60 changes: 60 additions & 0 deletions src/adapters/clients.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { type mastodon } from '../mastodon';
import {
HttpConfigImpl,
type MastoHttpConfigProps,
WebSocketConfigImpl,
type WebSocketConfigProps,
} from './config';
import { HttpNativeImpl } from './http';
import { createLogger, type LogType } from './logger';
import { createRequestBuilder } from './request-builder';
import { SerializerNativeImpl } from './serializers';
import { WebSocketClientNativeImpl, WebSocketConnector } from './ws';

type LogConfigProps = {
readonly logLevel?: LogType;
};

export const createRestClient = (
props: MastoHttpConfigProps & LogConfigProps,
): mastodon.rest.Client => {
const serializer = new SerializerNativeImpl();
const config = new HttpConfigImpl(props, serializer);
const logger = createLogger(props.logLevel);
const http = new HttpNativeImpl(serializer, config, logger);
const builder = createRequestBuilder(http, ['api']) as mastodon.rest.Client;
return builder;
};

export const createOAuthClient = (
props: MastoHttpConfigProps & LogConfigProps,
): mastodon.oauth.Client => {
const serializer = new SerializerNativeImpl();
const config = new HttpConfigImpl(props, serializer);
const logger = createLogger(props.logLevel);
const http = new HttpNativeImpl(serializer, config, logger);
const builder = createRequestBuilder(http, [
'oauth',
]) as mastodon.oauth.Client;
return builder;
};

export function createStreamingClient(
props: WebSocketConfigProps & LogConfigProps,
): mastodon.streaming.Client {
const serializer = new SerializerNativeImpl();
const config = new WebSocketConfigImpl(props, serializer);
const logger = createLogger(props.logLevel);
const connector = new WebSocketConnector(
[config.resolvePath('/api/v1/streaming').toString(), config.getProtocols()],
logger,
config,
);
const connections = connector.getConnections();

return new WebSocketClientNativeImpl(
connections,
serializer,
connector.close.bind(connector),
);
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,31 @@
import { SerializerNativeImpl } from '../serializers';
import { MastoHttpConfig } from './http-config';
import { MastoLogConfig } from './log-config';
import { HttpConfigImpl } from './http-config';

describe('Config', () => {
it('creates header', () => {
const config = new MastoHttpConfig(
const config = new HttpConfigImpl(
{
url: 'https://mastodon.social',
accessToken: 'token',
},
new SerializerNativeImpl(),
new MastoLogConfig(),
);
const headers = config.createHeader({ extra: 'header' });
const headers = config.mergeHeadersWithDefaults({ extra: 'header' });

expect(headers.get('Authorization')).toBe('Bearer token');
expect(headers.get('extra')).toBe('header');
});

it('overrides content-type header', () => {
const config = new MastoHttpConfig(
const config = new HttpConfigImpl(
{
url: 'https://mastodon.social',
accessToken: 'token',
},
new SerializerNativeImpl(),
new MastoLogConfig(),
);

const headers = config.createHeader({
const headers = config.mergeHeadersWithDefaults({
'Content-Type': 'multipart/form-data',
});

Expand All @@ -37,27 +34,25 @@ describe('Config', () => {
});

it('resolves HTTP path', () => {
const config = new MastoHttpConfig(
const config = new HttpConfigImpl(
{
url: 'https://mastodon.social',
accessToken: 'token',
},
new SerializerNativeImpl(),
new MastoLogConfig(),
);

const url = config.resolvePath('/api/v1/yay').toString();
expect(url).toEqual('https://mastodon.social/api/v1/yay');
});

it('resolves HTTP path with query', () => {
const config = new MastoHttpConfig(
const config = new HttpConfigImpl(
{
url: 'https://mastodon.social',
accessToken: 'token',
},
new SerializerNativeImpl(),
new MastoLogConfig(),
);

const url = config
Expand All @@ -69,27 +64,25 @@ describe('Config', () => {
});

it('preserves query parameters in the URL when no query parameters specified', () => {
const config = new MastoHttpConfig(
const config = new HttpConfigImpl(
{
url: 'https://mastodon.social',
accessToken: 'token',
},
new SerializerNativeImpl(),
new MastoLogConfig(),
);

const url = config.resolvePath('/path/to/somewhere?foo=bar').toString();
expect(url).toEqual('https://mastodon.social/path/to/somewhere?foo=bar');
});

it('revokes query parameters in the URL when query parameters specified', () => {
const config = new MastoHttpConfig(
const config = new HttpConfigImpl(
{
url: 'https://mastodon.social',
accessToken: 'token',
},
new SerializerNativeImpl(),
new MastoLogConfig(),
);

const url = config
Expand Down
26 changes: 16 additions & 10 deletions src/config/http-config.ts → src/adapters/config/http-config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import type { AbortSignal, HeadersInit, RequestInit } from '@mastojs/ponyfills';
import { Headers } from '@mastojs/ponyfills';
import {
type AbortSignal,
Headers,
type HeadersInit,
type RequestInit,
} from '@mastojs/ponyfills';

import type { Serializer } from '../serializers';
import { mergeAbortSignals, mergeHeadersInit, Timeout } from '../utils';
import type { MastoLogConfig } from './log-config';
import { type HttpConfig, type Serializer } from '../../interfaces';
import { Timeout } from '../../utils';
import { mergeAbortSignals } from './merge-abort-signals';
import { mergeHeadersInit } from './merge-headers-init';

const DEFAULT_TIMEOUT_MS = 1000 * 300;

Expand All @@ -14,14 +19,13 @@ export interface MastoHttpConfigProps {
readonly defaultRequestInit?: Omit<RequestInit, 'body' | 'method'>;
}

export class MastoHttpConfig {
export class HttpConfigImpl implements HttpConfig {
constructor(
private readonly props: MastoHttpConfigProps,
private readonly serializer: Serializer,
readonly log: MastoLogConfig,
) {}

createHeader(override: HeadersInit = {}): Headers {
mergeHeadersWithDefaults(override: HeadersInit = {}): Headers {
const headersInit = mergeHeadersInit([
this.props.defaultRequestInit?.headers ?? {},
override,
Expand All @@ -42,7 +46,7 @@ export class MastoHttpConfig {
url.search =
typeof params === 'string'
? params
: this.serializer.serializeQueryString(params);
: this.serializer.serialize('querystring', params);
}

return url;
Expand All @@ -52,7 +56,9 @@ export class MastoHttpConfig {
return new Timeout(this.props.timeout ?? DEFAULT_TIMEOUT_MS);
}

createAbortSignal(signal?: AbortSignal | null): [AbortSignal, Timeout] {
mergeAbortSignalWithDefaults(
signal?: AbortSignal | null,
): [AbortSignal, Timeout] {
const timeout = this.createTimeout();
const signals: AbortSignal[] = [timeout.signal];

Expand Down
1 change: 0 additions & 1 deletion src/config/index.ts → src/adapters/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from './http-config';
export * from './log-config';
export * from './web-socket-config';
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { AbortSignal } from '@mastojs/ponyfills';
import { AbortController } from '@mastojs/ponyfills';
import { AbortController, type AbortSignal } from '@mastojs/ponyfills';

export const mergeAbortSignals = (
signals: readonly AbortSignal[],
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { HeadersInit } from '@mastojs/ponyfills';
import { Headers } from '@mastojs/ponyfills';
import { Headers, type HeadersInit } from '@mastojs/ponyfills';

/* eslint-disable unicorn/no-array-for-each */
export const mergeHeadersInit = ([
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,28 @@
import { SerializerNativeImpl } from '../serializers';
import { MastoLogConfig } from './log-config';
import { MastoWebSocketConfig } from './web-socket-config';
import { WebSocketConfigImpl } from './web-socket-config';

describe('WebSocketConfig', () => {
describe('WebSocketConfigImpl', () => {
it('resolves WS path with path', () => {
const config = new MastoWebSocketConfig(
const config = new WebSocketConfigImpl(
{
url: 'wss://mastodon.social',
accessToken: 'token',
},
new SerializerNativeImpl(),
new MastoLogConfig(),
);

const url = config.resolvePath('/path/to/somewhere').toString();
expect(url).toEqual('wss://mastodon.social/path/to/somewhere');
});

it('resolves WS path with path with token when Sec-Websocket-Protocols is not supported', () => {
const config = new MastoWebSocketConfig(
const config = new WebSocketConfigImpl(
{
url: 'wss://mastodon.social',
accessToken: 'token',
useInsecureAccessToken: true,
},
new SerializerNativeImpl(),
new MastoLogConfig(),
);

const url = config.resolvePath('/path/to/somewhere').toString();
Expand All @@ -35,27 +32,25 @@ describe('WebSocketConfig', () => {
});

it('creates websocket protocol with token when supported', () => {
const config = new MastoWebSocketConfig(
const config = new WebSocketConfigImpl(
{
url: 'wss://mastodon.social',
accessToken: 'token',
},
new SerializerNativeImpl(),
new MastoLogConfig(),
);

expect(config.getProtocols()).toEqual(['token']);
});

it('creates websocket protocol without token when not supported', () => {
const config = new MastoWebSocketConfig(
const config = new WebSocketConfigImpl(
{
url: 'wss://mastodon.social',
accessToken: 'token',
useInsecureAccessToken: true,
},
new SerializerNativeImpl(),
new MastoLogConfig(),
);

expect(config.getProtocols()).toEqual([]);
Expand Down
Loading

0 comments on commit e42295f

Please sign in to comment.