Skip to content

Commit

Permalink
Add zod for runtime validation
Browse files Browse the repository at this point in the history
- Upgrade typescript version to support `satiesfies` operator
  • Loading branch information
w1am committed Nov 20, 2023
1 parent b5eb55e commit 2e75059
Show file tree
Hide file tree
Showing 59 changed files with 2,571 additions and 1,424 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module.exports = {
"jsdoc/check-indentation": ["warn"],
"jsdoc/check-syntax": ["warn"],
"jsdoc/check-tag-names": ["warn", { definedTags: ["jest-environment"] }],
"jsdoc/newline-after-description": ["warn", "never"],
"jsdoc/tag-lines": ["warn", "never"],
"jsdoc/no-types": ["error", { contexts: ["any"] }],
"jsdoc/require-description": ["warn"],
"jsdoc/require-description-complete-sentence": ["warn"],
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build_and_lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
branches:
- master
schedule:
- cron: "0 3 * * 0" # Every sunday at 3am UTC.
- cron: '0 3 * * 0' # Every sunday at 3am UTC.

jobs:
build:
Expand All @@ -33,7 +33,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: "14.x"
node-version: '14.x'
- name: Install
run: yarn
- name: Build
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/test_LTS.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
name: "LTS"
name: 'LTS'

on:
pull_request:
push:
branches:
- master
schedule:
- cron: "0 3 * * 0" # Every sunday at 3am UTC.
- cron: '0 3 * * 0' # Every sunday at 3am UTC.

jobs:
test:
name: Test
uses: ./.github/workflows/tests.yml
with:
version: "21.10.1-focal"
cloud_version: '21.10.1-focal'
esdb_version: '21.10.1-focal'
secrets:
eventstore_cloud_id: ${{ secrets.EVENTSTORE_CLOUD_ID }}
tailscale_auth: ${{ secrets.TAILSCALE_AUTH }}
13 changes: 9 additions & 4 deletions .github/workflows/test_dispatch.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
name: "Dispatch"
name: 'Dispatch'

on:
workflow_dispatch:
inputs:
version:
description: "Version tag"
cloud_version:
description: 'EventStoreDB server tag'
required: true
type: string
esdb_version:
description: 'EventStoreDB cloud version tag'
required: true
type: string

Expand All @@ -13,7 +17,8 @@ jobs:
name: Test
uses: ./.github/workflows/tests.yml
with:
version: ${{ inputs.version }}
esdb_version: ${{ inputs.esdb_version }}
cloud_version: ${{ inputs.cloud_version }}
secrets:
eventstore_cloud_id: ${{ secrets.EVENTSTORE_CLOUD_ID }}
tailscale_auth: ${{ secrets.TAILSCALE_AUTH }}
3 changes: 2 additions & 1 deletion .github/workflows/test_next.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ jobs:
name: Test
uses: ./.github/workflows/tests.yml
with:
version: "ci"
cloud_version: "ci"
esdb_version: "ci"
secrets:
eventstore_cloud_id: ${{ secrets.EVENTSTORE_CLOUD_ID }}
tailscale_auth: ${{ secrets.TAILSCALE_AUTH }}
7 changes: 4 additions & 3 deletions .github/workflows/test_previous_LTS.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
name: "previous LTS"
name: 'previous LTS'

on:
pull_request:
push:
branches:
- master
schedule:
- cron: "0 3 * * 0" # Every sunday at 3am UTC.
- cron: '0 3 * * 0' # Every sunday at 3am UTC.

jobs:
test:
name: Test
uses: ./.github/workflows/tests.yml
with:
version: "20.10.5-focal"
cloud_version: '20.10.5-focal'
esdb_version: '20.10.5-focal'
secrets:
eventstore_cloud_id: ${{ secrets.EVENTSTORE_CLOUD_ID }}
tailscale_auth: ${{ secrets.TAILSCALE_AUTH }}
13 changes: 8 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ name: tests workflow
on:
workflow_call:
inputs:
version:
cloud_version:
required: true
type: string
esdb_version:
required: true
type: string
secrets:
Expand All @@ -14,7 +17,7 @@ on:

jobs:
tests:
name: "${{ matrix.group.name }}"
name: '${{ matrix.group.name }}'
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -51,17 +54,17 @@ jobs:
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/eoan.list | sudo tee /etc/apt/sources.list.d/tailscale.list
sudo apt-get update
sudo apt-get install tailscale
sudo tailscale up --authkey ${{ secrets.tailscale_auth }} --hostname "node-client-ci-${{ inputs.version }}-$(date +'%Y-%m-%d-%H-%M-%S')" --advertise-tags=tag:ci --accept-routes
sudo tailscale up --authkey ${{ secrets.tailscale_auth }} --hostname "node-client-ci-${{ inputs.cloud_version }}-$(date +'%Y-%m-%d-%H-%M-%S')" --advertise-tags=tag:ci --accept-routes
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: "14.x"
node-version: '14.x'
- name: Install
run: yarn
- name: Run Tests
run: yarn test ${{ matrix.group.path }} --ci --run-in-band --forceExit
env:
EVENTSTORE_IMAGE: github:${{ inputs.version }}
EVENTSTORE_IMAGE: github:${{ inputs.esdb_version }}
EVENTSTORE_CLOUD_ID: ${{ secrets.eventstore_cloud_id }}
- name: Disconnect from tailscale
if: ${{ always() && matrix.group.tailscale && env.SECRETS_AVAILABLE == 'true' }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,6 @@ dist
.DS_Store
.npmrc
package-lock.json
.vscode

src/__test__/utils/instances
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@
"@types/node": "^16.11.4",
"debug": "^4.3.2",
"google-protobuf": "^3.19.0",
"uuid": "^8.3.2"
"uuid": "^8.3.2",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/jest": "^27.0.2",
Expand All @@ -98,6 +99,6 @@
"prettier": "^2.4.1",
"shx": "^0.3.3",
"ts-jest": "^27.0.7",
"typescript": "^4.4.4"
"typescript": "^4.4.2"
}
}
6 changes: 6 additions & 0 deletions src/Client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,32 @@ interface ClientOptions {
/**
* The amount of time (in milliseconds) to wait after which a keepalive ping is sent on the transport.
* Use -1 to disable.
*
* @default 10_000
*/
keepAliveInterval?: number;
/**
* The amount of time (in milliseconds) the sender of the keepalive ping waits for an acknowledgement.
* If it does not receive an acknowledgment within this time, it will close the connection.
*
* @default 10_000
*/
keepAliveTimeout?: number;
/**
* Whether or not to immediately throw an exception when an append fails.
*
* @default true
*/
throwOnAppendFailure?: boolean;
/**
* An optional length of time (in milliseconds) to use for gRPC deadlines.
*
* @default 10_000
*/
defaultDeadline?: number;
/**
* The name of the connection to use in logs.
*
* @default uuid
*/
connectionName?: string;
Expand Down Expand Up @@ -143,6 +148,7 @@ export class Client {
// eslint-disable-next-line jsdoc/require-param
/**
* Returns a connection from a connection string.
*
* @param connectionString The connection string for your database.
*/
static connectionString(
Expand Down
32 changes: 22 additions & 10 deletions src/persistentSubscription/createPersistentSubscriptionToAll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import { Client } from "../Client";
import { END, EVENT_TYPE, START, STREAM_NAME } from "../constants";

import { settingsToGRPC } from "./utils/settingsToGRPC";
import type { PersistentSubscriptionToAllSettings } from "./utils/persistentSubscriptionSettings";
import type {
PersistentSubscriptionToAllSettings,
persistentSubscriptionToStreamSettingsFromDefaults,
} from "./utils/persistentSubscriptionSettings";
import schemas from "../schemas";
import { validateField } from "../utils/validation";

export interface CreatePersistentSubscriptionToAllOptions extends BaseOptions {
/**
Expand All @@ -23,10 +28,12 @@ export interface CreatePersistentSubscriptionToAllOptions extends BaseOptions {
declare module "../Client" {
interface Client {
/**
* Creates a persistent subscription to all. Persistent subscriptions are special kind of subscription where the
* server remembers where the read offset is. This allows for many different modes of operations compared to a
* regular subscription where the client holds the read offset. The group name must be unique.
* Available from server version 21.10 onwards.
* Creates a persistent subscription to all. Persistent subscriptions are
* special kind of subscription where the server remembers where the read
* offset is. This allows for many different modes of operations compared to
* a regular subscription where the client holds the read offset. The group
* name must be unique. Available from server version 21.10 onwards.
*
* @param groupName A group name.
* @param settings PersistentSubscription settings.
* @see {@link persistentSubscriptionToStreamSettingsFromDefaults}
Expand All @@ -44,12 +51,17 @@ Client.prototype.createPersistentSubscriptionToAll = async function (
this: Client,
groupName: string,
settings: PersistentSubscriptionToAllSettings,
{
filter,

...baseOptions
}: CreatePersistentSubscriptionToAllOptions = {}
createPersistentSubscriptionToAllOptions: CreatePersistentSubscriptionToAllOptions = {}
): Promise<void> {
const { filter, ...baseOptions } = createPersistentSubscriptionToAllOptions;

validateField(schemas.groupName, groupName);
validateField(schemas.persistentSubscriptionToAllSettings, settings);
validateField(
schemas.createPersistentSubscriptionToAllOptions.optional(),
baseOptions
);

if (!(await this.supports(PersistentSubscriptionsService.create, "all"))) {
throw new UnsupportedError("createPersistentSubscriptionToAll", "21.10");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,20 @@ import { Client } from "../Client";
import { END, START } from "../constants";

import { settingsToGRPC } from "./utils/settingsToGRPC";
import type { PersistentSubscriptionToStreamSettings } from "./utils/persistentSubscriptionSettings";
import type {
PersistentSubscriptionToStreamSettings,
persistentSubscriptionToStreamSettingsFromDefaults,
} from "./utils/persistentSubscriptionSettings";
import schemas from "../schemas";
import { validateField } from "../utils/validation";

declare module "../Client" {
interface Client {
/**
* Creates a persistent subscription on a stream. Persistent subscriptions are special kind of subscription where the
* server remembers where the read offset is at. This allows for many different modes of operations compared to a
* regular subscription where the client holds the read offset. The pair stream name and group must be unique.
*
* @param streamName A stream name.
* @param groupName A group name.
* @param settings PersistentSubscription settings.
Expand All @@ -37,6 +43,11 @@ Client.prototype.createPersistentSubscriptionToStream = async function (
settings: PersistentSubscriptionToStreamSettings,
baseOptions: BaseOptions = {}
): Promise<void> {
validateField(schemas.streamName, streamName);
validateField(schemas.groupName, groupName);
validateField(schemas.persistentSubscriptionToStreamSettings, settings);
validateField(schemas.baseOptions.optional(), baseOptions);

const req = new CreateReq();
const options = new CreateReq.Options();
const identifier = createStreamIdentifier(streamName);
Expand Down
13 changes: 12 additions & 1 deletion src/persistentSubscription/deletePersistentSubscriptionToAll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ import {
import { convertToCommandError, debug, UnsupportedError } from "../utils";
import type { BaseOptions } from "../types";
import { Client } from "../Client";
import schemas from "../schemas";
import { validateField } from "../utils/validation";

export interface DeletePersistentSubscriptionToAllOptions extends BaseOptions {}

declare module "../Client" {
interface Client {
/**
* Deletes a persistent subscription.
*
* @param streamName A stream name.
* @param groupName A group name.
* @param options Deletion options.
Expand All @@ -29,8 +32,16 @@ declare module "../Client" {
Client.prototype.deletePersistentSubscriptionToAll = async function (
this: Client,
groupName: string,
{ ...baseOptions }: DeletePersistentSubscriptionToAllOptions = {}
deletePersistentSubscriptionToAllOptions: DeletePersistentSubscriptionToAllOptions = {}
): Promise<void> {
const { ...baseOptions } = deletePersistentSubscriptionToAllOptions;

validateField(schemas.groupName, groupName);
validateField(
schemas.deletePersistentSubscriptionToAllOptions.optional(),
deletePersistentSubscriptionToAllOptions
);

if (!(await this.supports(PersistentSubscriptionsService.delete, "all"))) {
throw new UnsupportedError("deletePersistentSubscriptionToAll", "21.10");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { PersistentSubscriptionsClient } from "../../generated/persistent_grpc_p
import { convertToCommandError, createStreamIdentifier, debug } from "../utils";
import type { BaseOptions } from "../types";
import { Client } from "../Client";
import schemas from "../schemas";
import { validateField } from "../utils/validation";

export interface DeletePersistentSubscriptionToStreamOptions
extends BaseOptions {}
Expand All @@ -12,6 +14,7 @@ declare module "../Client" {
interface Client {
/**
* Deletes a persistent subscription.
*
* @param streamName A stream name.
* @param groupName A group name.
* @param options Deletion options.
Expand All @@ -30,6 +33,10 @@ Client.prototype.deletePersistentSubscriptionToStream = async function (
groupName: string,
baseOptions: DeletePersistentSubscriptionToStreamOptions = {}
): Promise<void> {
validateField(schemas.streamName, streamName);
validateField(schemas.groupName, groupName);
validateField(schemas.baseOptions.optional(), baseOptions);

const req = new DeleteReq();
const options = new DeleteReq.Options();
const identifier = createStreamIdentifier(streamName);
Expand Down
Loading

0 comments on commit 2e75059

Please sign in to comment.