Skip to content

v1.7.0-rc

Latest

Choose a tag to compare

@Uanela Uanela released this 22 Jul 07:17
46c8e67

Highlights

  • WebSocket GatewaysArkosGateway, built on Socket.io, with the same conventions as the rest of the framework: reuses your existing authentication, plugs into ArkosPolicy for per-event authorization, reuses your Zod/class-validator setup, and shares the global error handler.
  • Deduplication and freshness checks built into the event pipeline, with a pluggable store (in-memory by default, bring your own for Redis/multi-instance).
  • Client packages@arkosjs/websockets-client (framework-agnostic) and @arkosjs/react-websockets (hooks + provider) for consuming Gateways from the frontend.
  • Dynamic-mode permission overrides — permissions can now be granted or denied to individual users on top of their role, via a new UserPermission model.
  • Static file serving, upload pipeline improvements, and orderBy passthrough to Prisma.

WebSocket Gateways

// src/gateway.ts
import { ArkosGateway } from "arkos/websockets";
 
const gateway = ArkosGateway({ name: "/", authentication: true });
 
gateway.on({ event: "send_message" }, (socket, data) => {
  socket.to(data.room).emit("receive_message", data);
});
 
export default gateway;
// src/server.ts
import { Server } from "socket.io";
import http from "http";
import app from "@/src/app";
import gateway from "@/src/gateway";
 
const server = http.createServer(app);
const io = new Server(server);
 
gateway.register(io);
 
app.listen(server);

gateway.register(io) can only be called once per io instance — compose additional namespaces with .use() (either connection middleware, or a nested ArkosGateway that inherits the parent's authentication and rateLimit, though not its .pipe()s).

Authentication and authorization

  • authentication: true reuses whatever auth mode (static/dynamic) is already configured in arkos.config.ts — there's no separate WebSocket auth setup. On success, socket.currentUser is populated and the socket auto-joins an internal per-user room; on failure the connection is rejected before any handler runs.
  • If a Gateway sets authentication: true without any authentication mode configured for the app, Arkos throws at startup rather than silently accepting unauthenticated sockets.
  • Per-event authorization plugs into ArkosPolicy:
  gateway.on(
    { event: "delete_message", authorization: chatPolicy.DeleteMessage },
    handler
  );

Registering an event with authorization on a Gateway that has authentication: false throws immediately, at registration time — not on the first request.

Validation, dedup, and freshness

  • validation on an event reuses your existing Zod/class-validator resolver — no separate WebSocket validation system.
  • Deduplication is on by default for every event ({ enabled: true, ttl: 3600 } seconds), keyed on data._meta.mid. A duplicate mid skips your handler and acks { success: true, duplicate: true } rather than erroring, since the first delivery already succeeded. Disable per event (dedup: false) or per Gateway.
  • maxAge rejects messages older than a given window, based on _meta.timestamp. A cheap future-timestamp guard (1-second tolerance) runs on every message with a timestamp, regardless of whether maxAge is set.
  • Both resolve event → Gateway → parent Gateway, with the most specific config winning.
  • _meta is injected automatically on every outgoing emit (socket.emit, emitWithAck, socket.to().emit(), socket.broadcast.emit()) and is what the client SDKs rely on for this — if you're emitting from a raw socket.io-client connection instead of the SDK, you're responsible for sending _meta yourself.

Targeting

socket.to() and socket.broadcast return an enhanced broadcast operator with .except({ user }) (exclude every active connection of one or more users) and .users() (unique user IDs in the target room). socket.user(userId) targets every active connection of a specific user and adds .activeRooms(). socket.retry(times, baseDelay?, multiplier?) wraps emitWithAck with exponential backoff.

Stores

Rate limiting and deduplication share one ArkosGatewayStore interface (increment, clear, has, set, setIfNotExists). The default is in-memory and single-instance only. Implement the interface against Redis for distributed deployments, or chain stores with MultiTierArkosGatewayStore for a fast local tier in front of a shared one.

Client packages

These are pre-1.0 and still maturing.

Package Status
@arkosjs/websockets-client (Vanilla JS) Stable core API
@arkosjs/react-websockets Reference implementation, tested
Vue / Svelte / Solid / Angular bindings Under development — starting-point implementations exist but haven't been validated in a real app; tracked at #260, #258, #259, #261

The vanilla client wraps a socket.io-client Manager, injects _meta automatically on emit, and exposes .emit(event, data, { ack, timeout, retries }) returning { success, data, error }. The React binding adds <ArkosSocketProvider>, useGateway(namespace) (with reactive .status/.user), and chat.useEmit(event) (with .loading/.error/.reset()).


Dynamic-mode permission overrides

AuthPermission moves from one row per role to a shared row referenced by many roles (roles: AuthRole[], unique on [resource, action]), and a new UserPermission model lets you grant or deny a specific permission to an individual user (effect: Allow | Deny), independent of their role. See the migration guide if you're upgrading an existing Dynamic-mode project — it involves a staged Prisma migration, not just a config change.

Static files, uploads, query

  • Built-in static file serving via express.static, with corrected default path resolution and CORS removed from the default middleware stack (add it explicitly if you relied on it).
  • Nested array upload paths, upload config inheritance/drilling, a customizable body-attachment function, and [] → [0] field naming in generated OpenAPI schemas.
  • req.query.orderBy can now be forwarded directly to Prisma's orderBy input.

Also in this release

  • Scalar is now available as an alternative to Swagger for /api/docs.
  • CLI generator templates renamed (middlewares-templateinterceptors-template), naming only.

Upgrading

pnpm install arkos@latest

Resources

What's Changed

  • feat(websockets): move emit methods directly to Arkos socket to eliminate circular dependencies by @Uanela in #263
  • Feat/websockets client by @Uanela in #285
  • Promote canary-1.7canarymain (v1.7.0) by @Uanela in #286
  • Revert "Promote canary-1.7canarymain (v1.7.0)" by @Uanela in #287
  • Canary 1.7 by @Uanela in #288
  • Promote canarymain (v1.7.0 GA) by @Uanela in #289

Full Changelog: v1.6.7-beta...v1.7.0-rc