Skip to content

Latest commit

 

History

History
597 lines (450 loc) · 19.2 KB

File metadata and controls

597 lines (450 loc) · 19.2 KB

Changelog

Version 5

v5.2.0

  • Supporting TypeScript 6:
    • Supported typescript versions: ^5.3.3 || ^6.0.2

v5.1.0

  • The onDisconnect hook is now equipped with reason property on its argument:
    • The default hook logs that reason;
    • This feature was suggested and implemented by @Miodec.

v5.0.1

  • Fixed withRooms().getClients() to return remote clients correctly in action handlers:
    • The method used to return an empty array due to wrong configuration;
    • The issue was found, reported and fixed by @simwai.

v5.0.0

  • Supported Node.js version: ^20.19.0 || ^22.12.0 || ^24.0.0:
    • Pure ESM distribution: all these versions support require(ESM) syntax;
  • Supported Zod version: ^4.1.0:
    • Imports may be changed from zod/v4 to just zod;
    • Dropped support of examples that are given as example property of .meta() argument;
    • Dropped support of examples given within an object-based value of examples property of .meta() argument;
  • Dropped support for depicting z.date() without transformations:
    • Use either z.iso.datetime().transform((str) => new Date(str)) for input schema,
    • Or z.date().transform((date) => date.toISOString()).pipe(z.iso.datetime()) for output schema.

Version 4

v4.1.2

  • Fixed the missing code property in the custom function schema validator.

v4.1.1

  • Updating documentation to reflect the new way to specify examples.

v4.1.0

  • Supporting zod@^4.0.5:
    • Imports may be changed from zod/v4 to just zod;

v4.0.1

  • Compatibility adjustment for Zod 3.25.75.

v4.0.0

  • Switched to Zod 4:
  • Changes to Documentation:
    • Generating Documentation is mostly delegated to Zod 4 z.toJSONSchema();
    • Zod Sockets implements some overrides and improvements to fit it into AsyncAPI 3.0.0 that extends JSON Schema;
    • Feat: supporting circular/recursive schemas: https://zod.dev/api#recursive-objects;
  • Changes to Integration:
    • The optionalPropStyle option removed from Integration class constructor:
    • Use .optional() to add question mark to the object property as well as undefined to its type;
    • Use .or(z.undefined()) to add undefined to the type of the object property;
    • See the reasoning;
    • Properties assigned with z.any() or z.unknown() schema are now typed as required:
    • Added types generation for z.never(), z.void() and z.unknown() schemas;
    • The fallback type for unsupported schemas and unclear transformations in response changed from any to unknown;
    • Supporting z.templateLiteral() and z.nonoptional() schemas;
  • Method Actions::example() removed — use the .meta({ examples }) method of its schema;
  • Property examples removed from the argument of createSimpleConfig() and Config::addNamespace():
    • use the .meta({ examples }) method of the corresponding schema;
  • The property originalError renamed to cause for InputValidationError and OutputValidationError.
- import { z } from "zod";
+ import { z } from "zod/v4";
  createSimpleConfig({
    emission: {
      event: {
-       schema: z.tuple([z.string()]),
+       schema: z.tuple([z.string().meta({ examples: ["test"] })]),
      },
    },
-   examples: {
-     event: {
-       payload: ["test"],
-     },
-   },
  });
  const action = actionsFactory
-   .build({ input: z.tuple([z.string()]) })
+   .build({ input: z.tuple([z.string().meta({ examples: ["test"] })]) })
-   .example("input", ["test"]);

Version 3

v3.0.0

  • Drop support for Node 18 (end of life);
  • The deprecated serializer property on the Integration constructor argument removed.

Version 2

v2.3.0

  • Supporting Node 24.

v2.2.0

  • Naming of circular types is now numeric:
    • Deprecated serializer property on the Integration constructor argument (no longer used).
- type Type2048581c137c5b2130eb860e3ae37da196dfc25b = {
+ type Type1 = {
      title: string;
-     features: Type2048581c137c5b2130eb860e3ae37da196dfc25b;
+     features: Type1;
  }[];

v2.1.1

  • Documentation update on compatibility with Express Zod API v21;
  • Tested compatibility with Express v5;
  • Removed redundant event argument for Action::execute().

v2.1.0

  • Featuring onError hook for handling errors of various natures:
    • The hook is intended to be generic, so some of its arguments are optional;
    • Exposing error classes: InputValidationError and OutputValidationError (for Action acknowledgments);
    • The following example shows how to emit an outgoing error event when the incoming event data is invalid:
import { createSimpleConfig, InputValidationError } from "zod-sockets";

const config = createSimpleConfig({
  emission: {
    error: {
      schema: z.tuple([
        z.string().describe("name"),
        z.string().describe("message"),
      ]),
    },
  },
  hooks: {
    onError: async ({ error, event, payload, client, logger }) => {
      logger.error(event ? `${event} handling error` : "Error", error);
      if (error instanceof InputValidationError && client) {
        try {
          await client.emit("error", error.name, error.message);
        } catch {} // no errors inside this hook
      }
    },
  },
});

v2.0.1

  • Technical update due to improved builder configuration:
    • Fixed missing node: protocol in the imports of core modules in the distributed javascript files.

v2.0.0

  • Breaking changes:
    • Minimum supported versions:
      • For Node.js: 18.18.0, 20.9.0, 22.0.0;
      • For zod: 3.23.0.

Version 1

v1.2.0

  • Ability to describe security schemas on the server and namespace level:
    • These security schemas go directly to the generated documentation.
// Single namespace
import { createSimpleConfig } from "zod-sockets";

const config = createSimpleConfig({
  security: [
    {
      type: "httpApiKey",
      description: "Server security schema",
      in: "header",
      name: "X-Api-Key",
    },
  ],
});
// Multiple namespaces
import { Config } from "zod-sockets";

const config = new Config({
  security: [
    {
      type: "httpApiKey",
      description: "Server security schema",
      in: "header",
      name: "X-Api-Key",
    },
  ],
}).addNamespace({
  security: [
    {
      type: "userPassword",
      description: "Namespace security schema",
    },
  ],
});

v1.1.0

  • Supporting Node 22.

v1.0.0

  • First production-ready release having stable public API.

Version 0

v0.20.0

  • Moved logger from configuration to attachRouting():
    • This simplifies reusing logger instance when running along with express-zod-api.
// before:
import { createSimpleConfig, Config } from "zod-sockets";
createSimpleConfig({ logger });
// or
new Config({ logger });

// after:
import { attachSockets } from "zod-sockets";
attachSockets({ config });

v0.19.0

  • Added client.getRequest() method (proxy for Socket::request).

v0.18.0

  • Fixed possibly invalid values of type property when depicting z.literal(), z.enum() and z.nativeEnum();
  • Added depicting of z.tuple().rest() when used in a nested level of the schemas;
  • Upgraded all dependencies;
  • Consistent typing of the Namespace properties;
  • Client distribution methods join() and leave() made async (always return Promise<void>).

v0.17.0

v0.16.0

  • Added .emit() method to the clients returned by getClients() method of all or withRoom();
  • Improved types for getData() in the for the clients returned by getClients() method;
  • Better example of a subscription service using rooms.
// sending to someone knowing their id:
(await all.getClients())
  .find(({ id }) => id === "someId")
  ?.emit("event", ...payload);

v0.15.1

  • Changed runtime dependency: replaced chalk with ansis.

v0.15.0

  • Major improvement to the generated documentation: depicting payloads as actual tuples they are.

v0.14.2

  • Detaching from OpenAPI:
    • Reducing dependencies;
    • AsyncAPI 3.0.0 stricter compliance;
    • Extending from JSON Schema Draft-07 with several proprietary features of AsyncAPI standard.
  • Several adjustments made in this regard:
    • discriminator field changed to string;
    • using const field for z.literal().

v0.14.1

  • Fixed broken publishing workflow (broken release).
  • The following versions and deprecated: 0.14.0, 0.13.1, 0.13.0, 0.12.0, 0.11.3, 0.11.2.

v0.14.0

  • Featuring examples in the generated documentation:
    • Describe Action examples using its .example() method;
    • Describe Emission examples using examples property in namespace config.
import { createSimpleConfig, ActionsFactory } from "zod-sockets";

// Examples for outgoing events (emission)
const config = createSimpleConfig({
  emission: {
    event1: { schema },
    event2: { schema, ack },
  },
  examples: {
    event1: { schema: ["example payload"] }, // single example
    event2: [
      // multiple examples
      { schema: ["example payload"], ack: ["example acknowledgement"] },
      { schema: ["example payload"], ack: ["example acknowledgement"] },
    ],
  },
});

// Examples for incoming event (action)
const factory = new ActionsFactory(config);
const action = factory
  .build({
    input: payloadSchema,
    output: ackSchema,
  })
  .example("input", ["example payload"])
  .example("output", ["example acknowledgement"]);

v0.13.1

  • Minor adjustments to the documentation.

v0.13.0

  • Config creation changes aim to improve the clarity and make it easier to begin using this library for the first time;
  • Easier config for a simple applications:
    • Replacing createConfig() with createSimpleConfig() - for a single namespace (root namespace only).
  • Making namespaces opt-in feature:
    • Use the exposed new Config() and its .addNamespace() method of each namespace;
    • Fallbacks removed from Config::constructor — it creates no namespaces by default, but addNamespace creates root namespace when path prop is omitted;
  • See the migration advice below.
// if using the root namespace only:
import { createSimpleConfig } from "zod-sockets";
const simpleConfig = createSimpleConfig({
  /* logger, timeout, emission, hooks, metadata */
});

// if using namespaces other than "/":
import { Config } from "zod-sockets";
const config = new Config({ logger, timeout })
  .addNamespace({
    path: "ns1",
    /* emission, hooks, metadata */
  })
  .addNamespace({
    path: "ns2",
    /* emission, hooks, metadata */
  });

v0.12.0

  • Switching to AsyncAPI version 3.0.0 for generating documentation:
    • Channel identifiers are human-readable again thanks to the dedicated address property;
    • Server URL is deconstructed into protocol, host and pathname;
    • The featured operations are detached from channels;
    • Custom protocols are no longer supported, therefore changing socket.io to ws, channel bindings remain;
    • For the Socket.IO acknowledgements using the featured reply schema instead of the message bindings;
    • In this regard, new composition implies a dedicated operation per message;
    • Several other adjustments according to Release notes.

v0.11.3

  • Fixed the server protocol in the generated documentation (taking from the supplied server URL);
  • Meanwhile, the server url in the generated documentation has no protocol prefix now;
  • Reverted channel identifiers to actual namespaces in the generated documentation (according to AsyncAPI spec).

v0.11.2

  • Increasing AsyncAPI version to 2.6.0 in the generated documentation;
  • Human-readable identifiers for channels, operations and messages in the generated documentation.

v0.11.1

  • Fix: marked tuple items as required.

v0.11.0

  • Featuring Documentation class:
    • Ability to generate the documentation of your Socket.IO-based application according to AsyncAPI standard;
    • Using a custom protocol socket.io that extends WebSockets bindings for describing acknowledgements and handshake;
    • Compliance with AsyncAPI version 2.5.0 so far (will be increased later);
    • Following features are not supported yet:
      • Examples,
      • z.lazy() and handling of circular references,
      • References and component-based composition of the document,
      • Informative errors.
    • Since AsyncAPI does not yet support prefixItems feature for describing tuples, those are depicted as objects having numeric properties. I found it acceptable at the moment because Arrays are Objects;
    • See the example of the generated documentation here.
import { Documentation } from "zod-sockets";

const yamlString = new Documentation({
  config,
  actions,
  version: "1.2.3",
  title: "Example APP",
  servers: { example: { url: "https://example.com/socket.io" } },
}).getSpecAsYaml();

v0.10.0

  • Important changes to configuration:
    • The createConfig() method now returns an instance of Config class providing addNamespace() method;
    • The addNamespace() method becomes a primary approach for the namespace-first configuration;
    • By default, createConfig() creates an empty root namespace (having / path);
    • Namespaces consist of optional emission, hooks and metadata;
    • Therefore, the declaration of namespaces is moved from being under emission to the top level;
    • Hooks are moved from the argument of attachSockets() into the one of addNamespace().
  • Metadata is now a schema-based property of namespace:
    • No need to declare its interface;
    • Instead, metadata property of namespace should be assigned with an object-based schema;
    • The default schema for metadata is z.object({}).strip() — an empty object;
    • Methods getData() and setData() of the client context no longer require a type argument;
    • The setData() method performs validation and can throw ZodError;
    • Transformations are not allowed in the schema of metadata.
import { createConfig } from "zod-sockets";

const before = createConfig({
  emission: {
    // The namespace "/public"
    public: {},
    // The namespace "/private"
    private: {},
  },
});

const after = createConfig() // this makes root namespace "/"
  .addNamespace({ path: "public" })
  .addNamespace({ path: "private" });

v0.9.1

  • Ensuring that the namespace in the generated client is named the same as it's declared on backend;
  • Using chalk v5 in runtime.

v0.9.0

  • New peer dependency required: typescript.
  • Featuring Integration class:
    • It provides an ability to export the event definitions into a Typescript file for using on the frontend side;
    • For better naming of the functional arguments consider using .describe() method of the schemas;
    • There is also a special handling for the cases when event has both .rest() on the payload and an acknowledgement;
    • See the example of the generated code.
import { Integration } from "zod-sockets";

new Integration({ config, actions }).print(); // typescript code

v0.8.1

  • Minor adjustments and cleanup.

v0.8.0

  • Introducing namespaces feature.
    • See the Namespaces documentation.
    • The default namespace is a root namespace /.
    • The namespaces can be declared within emission property of the createConfig() argument.
    • The ActionsFactory::build() method now accepts optional property ns.
    • The hooks property of the attachSockets() method now accepts handlers for each namespace (optional).
  • Breaking changes:
    • ActionMap type removed;
    • Instead, the ActionsFactory::build() method now requires the event property of its argument;
    • Meanwhile, actions supplied to attachSockets() method now has to be an array of the produced actions.
    • The following properties of the attachSockets() argument must now be wrapped into hooks:
      • onConnection(), onDisconnect(), onAnyIncoming(), onAnyOutgoing(), onStartup().

v0.7.0

  • onAny() property of attachSockets() argument renamed to onAnyIncoming(), having event and payload arguments;
  • Introducing onAnyOutgoing(), having the same interface;
  • Startup logo added;
  • Some more refactoring.

v0.6.2

  • Upgrading dependencies and improving the documentation.

v0.6.1

  • Adding join() and leave() methods to RemoteClient (the ones returned by getClients()).

v0.6.0

  • Restoring the all argument of the Action handler (removed in v0.4.0), but now it works as expected, by providing:
    • getRooms() — all available rooms,
    • getClients() — all familiar clients,
    • broadcast() — sends an event to everyone.
  • Describing the basic features in the documentation (Readme).

v0.5.0

  • Introducing onStartup option for attachSockets() method:
    • Ability to interact with rooms regardless of incoming events.
  • join() and leave() methods are moved from withRooms() to client.
  • attachSockets() became async.

v0.4.0

  • Reverted some changed made in v0.3.0: removed all argument from the Action handler:
    • The nested broadcast method moved to client argument,
    • The nested getRooms() renamed to getAllRooms(),
    • The nested getClients() renamed to getAllClients().

v0.3.2

  • Ability to interact with the client's metadata: getData<T>() and setData<T>() methods.

v0.3.1

  • Using io.of("/") for both all.getRooms() and all.getClients().

v0.3.0

  • New argument for the Action handler: all having methods:
    • broadcast() (moved);
    • getRooms() — returns all the available rooms;
    • getClients() — returns all the familiar clients.
  • The argument emit() of the Action handler moved into client one.
  • The argument withRooms() of the Action handler now also provides the getClients() method (clients in the rooms).

v0.2.3

  • Adding getRooms() and withRooms() providing join(), leave() and broadcast() methods to the Action handler.

v0.2.2

  • Adjusting documentation.

v0.2.1

  • Concept description and a workflow diagram.

v0.2.0

  • Moved logger from attachSockets() to createConfig() argument.

v0.1.0

  • Fixed module exports.
  • Unit and integration tests.
  • createSocketsConfig() renamed to createConfig().

v0.0.3

  • Ensure emitting the declared events only.
  • Generic implementation for emit() and broadcast().

v0.0.2

  • Added broadcasting feature.
  • Delegated emission error handling to user.

v0.0.1

  • First draft of the idea originally implemented as a feature for express-zod-api.
  • Capable to handle incoming events handling payloads validated by zod schemas and acknowledge them.
  • Can emit events having validated payloads and receive acknowledgements.