@floegence/flowersec-core 0.21.1 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,24 +1,25 @@
1
1
  import { getClientTermination } from "../client-connect/termination.js";
2
2
  import { emitObserverDiagnostic, withObserverContext } from "../observability/observer.js";
3
+ import { SDK_DEFAULTS } from "../defaults.js";
3
4
  export { createArtifactResolver, createControlplaneArtifactSource } from "./artifactControlplane.js";
4
5
  function normalizeAutoReconnect(cfg) {
5
6
  if (!cfg?.enabled) {
6
7
  return {
7
8
  enabled: false,
8
9
  maxAttempts: 1,
9
- initialDelayMs: 500,
10
- maxDelayMs: 10_000,
11
- factor: 1.8,
12
- jitterRatio: 0.2,
10
+ initialDelayMs: SDK_DEFAULTS.reconnect.initialDelayMs,
11
+ maxDelayMs: SDK_DEFAULTS.reconnect.maxDelayMs,
12
+ factor: SDK_DEFAULTS.reconnect.factor,
13
+ jitterRatio: SDK_DEFAULTS.reconnect.jitterRatio,
13
14
  };
14
15
  }
15
16
  return {
16
17
  enabled: true,
17
- maxAttempts: Math.max(1, cfg.maxAttempts ?? 5),
18
- initialDelayMs: Math.max(0, cfg.initialDelayMs ?? 500),
19
- maxDelayMs: Math.max(0, cfg.maxDelayMs ?? 10_000),
20
- factor: Math.max(1, cfg.factor ?? 1.8),
21
- jitterRatio: Math.max(0, cfg.jitterRatio ?? 0.2),
18
+ maxAttempts: Math.max(1, cfg.maxAttempts ?? SDK_DEFAULTS.reconnect.maxAttempts),
19
+ initialDelayMs: Math.max(0, cfg.initialDelayMs ?? SDK_DEFAULTS.reconnect.initialDelayMs),
20
+ maxDelayMs: Math.max(0, cfg.maxDelayMs ?? SDK_DEFAULTS.reconnect.maxDelayMs),
21
+ factor: Math.max(1, cfg.factor ?? SDK_DEFAULTS.reconnect.factor),
22
+ jitterRatio: Math.max(0, cfg.jitterRatio ?? SDK_DEFAULTS.reconnect.jitterRatio),
22
23
  };
23
24
  }
24
25
  function backoffDelayMs(attemptIndex, cfg) {
@@ -13,9 +13,14 @@ export type RpcServerTransport = Readonly<{
13
13
  write(bytes: Uint8Array): Promise<void>;
14
14
  close(error: unknown): void;
15
15
  }>;
16
+ export declare class RpcRouter {
17
+ private readonly handlers;
18
+ register(typeId: number, handler: RpcHandler): void;
19
+ handler(typeId: number): RpcHandler | undefined;
20
+ }
16
21
  export declare class RpcServer {
17
22
  private readonly transport;
18
- private readonly handlers;
23
+ private readonly router;
19
24
  private closed;
20
25
  private readonly options;
21
26
  private readonly requests;
@@ -27,8 +32,9 @@ export declare class RpcServer {
27
32
  private readonly terminalSignal;
28
33
  private signalTerminal;
29
34
  private transportClosed;
30
- constructor(transport: RpcServerTransport, options?: RpcServerOptions);
35
+ constructor(transport: RpcServerTransport, options?: RpcServerOptions, router?: RpcRouter);
31
36
  register(typeId: number, h: RpcHandler): void;
37
+ notify(typeId: number, payload: unknown): Promise<void>;
32
38
  serve(signal?: AbortSignal): Promise<void>;
33
39
  close(error?: unknown): void;
34
40
  private fail;
@@ -37,4 +43,5 @@ export declare class RpcServer {
37
43
  private nextWork;
38
44
  private wakeOne;
39
45
  private writeResponse;
46
+ private writeEnvelope;
40
47
  }
@@ -1,15 +1,24 @@
1
1
  import { DEFAULT_MAX_JSON_FRAME_BYTES, readJsonFrame, writeJsonFrame } from "../framing/jsonframe.js";
2
2
  import { assertRpcEnvelope } from "./validate.js";
3
+ import { SDK_DEFAULTS } from "../defaults.js";
3
4
  const DEFAULT_RPC_SERVER_OPTIONS = Object.freeze({
4
- maxConcurrentRequests: 32,
5
- maxQueuedRequests: 128,
6
- maxQueuedNotifications: 128,
5
+ maxConcurrentRequests: SDK_DEFAULTS.rpc.maxConcurrentRequests,
6
+ maxQueuedRequests: SDK_DEFAULTS.rpc.maxQueuedRequests,
7
+ maxQueuedNotifications: SDK_DEFAULTS.rpc.maxQueuedNotifications,
7
8
  });
9
+ export class RpcRouter {
10
+ handlers = new Map();
11
+ register(typeId, handler) {
12
+ this.handlers.set(typeId >>> 0, handler);
13
+ }
14
+ handler(typeId) {
15
+ return this.handlers.get(typeId >>> 0);
16
+ }
17
+ }
8
18
  // RpcServer dispatches request envelopes to registered handlers.
9
19
  export class RpcServer {
10
20
  transport;
11
- // Registered handlers keyed by type ID.
12
- handlers = new Map();
21
+ router;
13
22
  // Closed flag to stop the serve loop.
14
23
  closed = false;
15
24
  options;
@@ -22,8 +31,9 @@ export class RpcServer {
22
31
  terminalSignal;
23
32
  signalTerminal;
24
33
  transportClosed = false;
25
- constructor(transport, options = {}) {
34
+ constructor(transport, options = {}, router = new RpcRouter()) {
26
35
  this.transport = transport;
36
+ this.router = router;
27
37
  this.terminalSignal = new Promise((resolve) => { this.signalTerminal = resolve; });
28
38
  this.options = {
29
39
  maxConcurrentRequests: positiveInteger(options.maxConcurrentRequests ?? DEFAULT_RPC_SERVER_OPTIONS.maxConcurrentRequests, "maxConcurrentRequests"),
@@ -33,7 +43,17 @@ export class RpcServer {
33
43
  }
34
44
  // register binds a handler to a type ID.
35
45
  register(typeId, h) {
36
- this.handlers.set(typeId >>> 0, h);
46
+ this.router.register(typeId, h);
47
+ }
48
+ async notify(typeId, payload) {
49
+ if (this.closed)
50
+ throw new Error("rpc server closed");
51
+ await this.writeEnvelope({
52
+ type_id: typeId >>> 0,
53
+ request_id: 0,
54
+ response_to: 0,
55
+ payload,
56
+ });
37
57
  }
38
58
  // serve handles request/response frames until closed or aborted.
39
59
  async serve(signal) {
@@ -106,7 +126,7 @@ export class RpcServer {
106
126
  if (work == null)
107
127
  return;
108
128
  const v = work.envelope;
109
- const h = this.handlers.get(v.type_id >>> 0);
129
+ const h = this.router.handler(v.type_id);
110
130
  let out;
111
131
  if (h == null)
112
132
  out = { payload: null, error: { code: 404, message: "handler not found" } };
@@ -129,7 +149,7 @@ export class RpcServer {
129
149
  if (work == null)
130
150
  return;
131
151
  const v = work.envelope;
132
- const h = this.handlers.get(v.type_id >>> 0);
152
+ const h = this.router.handler(v.type_id);
133
153
  if (h == null)
134
154
  continue;
135
155
  try {
@@ -158,7 +178,10 @@ export class RpcServer {
158
178
  payload: out.payload,
159
179
  ...(out.error != null ? { error: out.error } : {}),
160
180
  };
161
- const write = this.writeChain.then(() => writeJsonFrame(this.transport.write, resp));
181
+ await this.writeEnvelope(resp);
182
+ }
183
+ async writeEnvelope(envelope) {
184
+ const write = this.writeChain.then(() => writeJsonFrame(this.transport.write, envelope));
162
185
  this.writeChain = write.catch(() => { });
163
186
  await write;
164
187
  }
@@ -3,14 +3,15 @@ import { decodeHeader, encodeHeader, HEADER_LEN } from "./header.js";
3
3
  import { FLAG_ACK, FLAG_RST, FLAG_SYN, TYPE_DATA, TYPE_GO_AWAY, TYPE_PING, TYPE_WINDOW_UPDATE, YAMUX_VERSION } from "./constants.js";
4
4
  import { YamuxStream } from "./stream.js";
5
5
  import { YamuxResourceExhaustedError } from "./errors.js";
6
+ import { SDK_DEFAULTS } from "../defaults.js";
6
7
  export const DEFAULT_YAMUX_LIMITS = Object.freeze({
7
- maxActiveStreams: 64,
8
- maxInboundStreams: 32,
9
- maxFrameBytes: 256 * 1024,
10
- preferredOutboundFrameBytes: 64 * 1024,
11
- maxStreamReceiveBytes: 256 * 1024,
12
- maxSessionReceiveBytes: 16 * (1 << 20),
13
- maxStreamWriteQueueBytes: 4 * (1 << 20),
8
+ maxActiveStreams: SDK_DEFAULTS.yamux.maxActiveStreams,
9
+ maxInboundStreams: SDK_DEFAULTS.yamux.maxInboundStreams,
10
+ maxFrameBytes: SDK_DEFAULTS.yamux.maxFrameBytes,
11
+ preferredOutboundFrameBytes: SDK_DEFAULTS.yamux.preferredOutboundFrameBytes,
12
+ maxStreamReceiveBytes: SDK_DEFAULTS.yamux.maxStreamReceiveBytes,
13
+ maxSessionReceiveBytes: SDK_DEFAULTS.yamux.maxSessionReceiveBytes,
14
+ maxStreamWriteQueueBytes: SDK_DEFAULTS.e2ee.maxOutboundBufferedBytes,
14
15
  });
15
16
  // YamuxSession multiplexes multiple streams over a single byte stream.
16
17
  export class YamuxSession {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floegence/flowersec-core",
3
- "version": "0.21.1",
3
+ "version": "0.22.1",
4
4
  "description": "Flowersec core TypeScript library (browser-friendly E2EE + multiplexing over WebSocket).",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -40,6 +40,10 @@
40
40
  "types": "./dist/controlplane/index.d.ts",
41
41
  "default": "./dist/controlplane/index.js"
42
42
  },
43
+ "./endpoint": {
44
+ "types": "./dist/endpoint/index.d.ts",
45
+ "default": "./dist/endpoint/index.js"
46
+ },
43
47
  "./framing": {
44
48
  "types": "./dist/framing/index.d.ts",
45
49
  "default": "./dist/framing/index.js"
@@ -116,8 +120,8 @@
116
120
  "scripts": {
117
121
  "build": "tsc -p tsconfig.build.json",
118
122
  "bench": "vitest bench --run",
119
- "test": "vitest run",
120
- "test:coverage": "vitest run --coverage",
123
+ "test": "npm run build && vitest run",
124
+ "test:coverage": "npm run build && vitest run --coverage",
121
125
  "lint": "eslint .",
122
126
  "verify:package": "node ./scripts/verify-package-exports.mjs",
123
127
  "prepack": "npm run build",