@floegence/flowersec-core 0.25.0 → 0.27.0
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.
- package/README.md +2 -2
- package/dist/browser/connect.d.ts +2 -1
- package/dist/browser/index.d.ts +3 -3
- package/dist/browser/index.js +2 -2
- package/dist/client-connect/connectCore.d.ts +1 -1
- package/dist/client-connect/transportSecurity.d.ts +1 -3
- package/dist/client-connect/transportSecurity.js +0 -4
- package/dist/connect/artifact.d.ts +0 -1
- package/dist/connect/artifact.js +0 -4
- package/dist/connect/{internalNormalize.d.ts → resolveArtifact.d.ts} +8 -8
- package/dist/connect/resolveArtifact.js +87 -0
- package/dist/controlplane/request.d.ts +1 -0
- package/dist/controlplane/request.js +77 -2
- package/dist/defaults.d.ts +1 -0
- package/dist/defaults.js +1 -0
- package/dist/e2ee/record.js +8 -4
- package/dist/e2ee/secureChannel.d.ts +1 -0
- package/dist/e2ee/secureChannel.js +18 -4
- package/dist/facade.d.ts +1 -4
- package/dist/facade.js +5 -11
- package/dist/node/connect.d.ts +0 -2
- package/dist/node/index.d.ts +1 -1
- package/dist/node/index.js +1 -1
- package/dist/proxy/bootstrap.d.ts +5 -24
- package/dist/proxy/bootstrap.js +1 -11
- package/dist/proxy/constants.d.ts +1 -0
- package/dist/proxy/constants.js +1 -0
- package/dist/proxy/integration.js +0 -6
- package/dist/proxy/preset.d.ts +0 -1
- package/dist/proxy/preset.js +0 -9
- package/dist/proxy/runtimeScope.js +2 -7
- package/dist/proxy/server.d.ts +0 -1
- package/dist/proxy/server.js +257 -145
- package/dist/tunnel-client/connect.d.ts +1 -1
- package/dist/tunnel-client/connect.js +1 -11
- package/package.json +4 -6
- package/dist/browser/controlplane.d.ts +0 -15
- package/dist/browser/controlplane.js +0 -65
- package/dist/connect/internalNormalize.js +0 -173
- package/dist/proxy/profiles.d.ts +0 -18
- package/dist/proxy/profiles.js +0 -71
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@floegence/flowersec-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Flowersec core TypeScript library (browser-friendly E2EE + multiplexing over WebSocket).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -103,10 +103,6 @@
|
|
|
103
103
|
"./gen/flowersec/tunnel/*": {
|
|
104
104
|
"types": "./dist/gen/flowersec/tunnel/*.d.ts",
|
|
105
105
|
"default": "./dist/gen/flowersec/tunnel/*.js"
|
|
106
|
-
},
|
|
107
|
-
"./internal": {
|
|
108
|
-
"types": "./dist/index.d.ts",
|
|
109
|
-
"default": "./dist/index.js"
|
|
110
106
|
}
|
|
111
107
|
},
|
|
112
108
|
"engines": {
|
|
@@ -122,7 +118,9 @@
|
|
|
122
118
|
"bench": "vitest bench --run",
|
|
123
119
|
"test": "npm run build && vitest run",
|
|
124
120
|
"test:browser": "npm run build && playwright test",
|
|
125
|
-
"
|
|
121
|
+
"test:browser:chromium": "npm run build && playwright test --project=chromium",
|
|
122
|
+
"test:browser:webkit": "npm run build && playwright test --project=webkit-smoke",
|
|
123
|
+
"ensure:browser": "node ./scripts/ensure-playwright-browsers.mjs",
|
|
126
124
|
"test:coverage": "npm run build && vitest run --coverage",
|
|
127
125
|
"lint": "eslint .",
|
|
128
126
|
"verify:package": "node ./scripts/verify-package-exports.mjs",
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { type ChannelInitGrant } from "../facade.js";
|
|
2
|
-
import type { ControlplaneBaseConfig as SharedControlplaneBaseConfig, RequestConnectArtifactInput, RequestEntryConnectArtifactInput } from "../controlplane/request.js";
|
|
3
|
-
export { ControlplaneRequestError, requestConnectArtifact, requestEntryConnectArtifact, } from "../controlplane/request.js";
|
|
4
|
-
type BaseControlplaneRequestConfig = SharedControlplaneBaseConfig & Readonly<{
|
|
5
|
-
endpointId: string;
|
|
6
|
-
payload?: Record<string, unknown>;
|
|
7
|
-
}>;
|
|
8
|
-
export type ControlplaneConfig = BaseControlplaneRequestConfig;
|
|
9
|
-
export type EntryControlplaneConfig = BaseControlplaneRequestConfig & Readonly<{
|
|
10
|
-
entryTicket: string;
|
|
11
|
-
}>;
|
|
12
|
-
export type ConnectArtifactRequestConfig = RequestConnectArtifactInput;
|
|
13
|
-
export type EntryConnectArtifactRequestConfig = RequestEntryConnectArtifactInput;
|
|
14
|
-
export declare function requestChannelGrant(config: ControlplaneConfig): Promise<ChannelInitGrant>;
|
|
15
|
-
export declare function requestEntryChannelGrant(config: EntryControlplaneConfig): Promise<ChannelInitGrant>;
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { assertChannelInitGrant } from "../facade.js";
|
|
2
|
-
import { requestControlplaneJSON, } from "../controlplane/request.js";
|
|
3
|
-
export { ControlplaneRequestError, requestConnectArtifact, requestEntryConnectArtifact, } from "../controlplane/request.js";
|
|
4
|
-
function buildURL(baseUrl, path) {
|
|
5
|
-
const base = String(baseUrl ?? "").trim();
|
|
6
|
-
if (base === "")
|
|
7
|
-
return path;
|
|
8
|
-
return `${base.replace(/\/+$/, "")}${path}`;
|
|
9
|
-
}
|
|
10
|
-
function buildPayload(endpointId, payload) {
|
|
11
|
-
const id = String(endpointId ?? "").trim();
|
|
12
|
-
if (id === "")
|
|
13
|
-
throw new Error("endpointId is required");
|
|
14
|
-
const out = { ...(payload ?? {}) };
|
|
15
|
-
const raw = out.endpoint_id;
|
|
16
|
-
if (raw !== undefined && String(raw ?? "").trim() !== id) {
|
|
17
|
-
throw new Error("payload.endpoint_id must match endpointId");
|
|
18
|
-
}
|
|
19
|
-
out.endpoint_id = id;
|
|
20
|
-
return out;
|
|
21
|
-
}
|
|
22
|
-
async function requestGrant(url, init) {
|
|
23
|
-
return await requestControlplaneJSON(url, init);
|
|
24
|
-
}
|
|
25
|
-
export async function requestChannelGrant(config) {
|
|
26
|
-
const headers = new Headers(config.headers);
|
|
27
|
-
if (!headers.has("Content-Type")) {
|
|
28
|
-
headers.set("Content-Type", "application/json");
|
|
29
|
-
}
|
|
30
|
-
const data = (await requestGrant(buildURL(config.baseUrl, "/v1/channel/init"), {
|
|
31
|
-
...(config.fetch === undefined ? {} : { fetch: config.fetch }),
|
|
32
|
-
method: "POST",
|
|
33
|
-
credentials: config.credentials ?? "omit",
|
|
34
|
-
headers,
|
|
35
|
-
body: JSON.stringify(buildPayload(config.endpointId, config.payload)),
|
|
36
|
-
...(config.signal === undefined ? {} : { signal: config.signal }),
|
|
37
|
-
}));
|
|
38
|
-
if (!data?.grant_client) {
|
|
39
|
-
throw new Error("Invalid controlplane response: missing `grant_client`");
|
|
40
|
-
}
|
|
41
|
-
return assertChannelInitGrant(data.grant_client);
|
|
42
|
-
}
|
|
43
|
-
export async function requestEntryChannelGrant(config) {
|
|
44
|
-
const entryTicket = String(config.entryTicket ?? "").trim();
|
|
45
|
-
if (entryTicket === "")
|
|
46
|
-
throw new Error("entryTicket is required");
|
|
47
|
-
const endpointId = String(config.endpointId ?? "").trim();
|
|
48
|
-
const headers = new Headers(config.headers);
|
|
49
|
-
headers.set("Authorization", `Bearer ${entryTicket}`);
|
|
50
|
-
if (!headers.has("Content-Type")) {
|
|
51
|
-
headers.set("Content-Type", "application/json");
|
|
52
|
-
}
|
|
53
|
-
const data = (await requestGrant(buildURL(config.baseUrl, `/v1/channel/init/entry?endpoint_id=${encodeURIComponent(endpointId)}`), {
|
|
54
|
-
...(config.fetch === undefined ? {} : { fetch: config.fetch }),
|
|
55
|
-
method: "POST",
|
|
56
|
-
credentials: config.credentials ?? "omit",
|
|
57
|
-
headers,
|
|
58
|
-
body: JSON.stringify(buildPayload(endpointId, config.payload)),
|
|
59
|
-
...(config.signal === undefined ? {} : { signal: config.signal }),
|
|
60
|
-
}));
|
|
61
|
-
if (!data?.grant_client) {
|
|
62
|
-
throw new Error("Invalid controlplane response: missing `grant_client`");
|
|
63
|
-
}
|
|
64
|
-
return assertChannelInitGrant(data.grant_client);
|
|
65
|
-
}
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import { Role as ControlRole } from "../gen/flowersec/controlplane/v1.gen.js";
|
|
2
|
-
import { emitObserverDiagnostic, normalizeObserver, withObserverContext } from "../observability/observer.js";
|
|
3
|
-
import { FlowersecError } from "../utils/errors.js";
|
|
4
|
-
import { assertConnectArtifact, hasArtifactOnlyFields, } from "./artifact.js";
|
|
5
|
-
function maybeParseJSON(input) {
|
|
6
|
-
if (typeof input !== "string")
|
|
7
|
-
return input;
|
|
8
|
-
const s = input.trim();
|
|
9
|
-
if (s === "")
|
|
10
|
-
return input;
|
|
11
|
-
if (s[0] !== "{" && s[0] !== "[")
|
|
12
|
-
return input;
|
|
13
|
-
try {
|
|
14
|
-
return JSON.parse(s);
|
|
15
|
-
}
|
|
16
|
-
catch (e) {
|
|
17
|
-
throw new FlowersecError({
|
|
18
|
-
path: "auto",
|
|
19
|
-
stage: "validate",
|
|
20
|
-
code: "invalid_input",
|
|
21
|
-
message: "invalid JSON string",
|
|
22
|
-
cause: e,
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
async function validateArtifactScopes(artifact, opts, observer) {
|
|
27
|
-
const scoped = artifact.scoped ?? [];
|
|
28
|
-
if (scoped.length === 0)
|
|
29
|
-
return;
|
|
30
|
-
const path = artifact.transport;
|
|
31
|
-
for (const entry of scoped) {
|
|
32
|
-
const resolver = opts.scopeResolvers?.[entry.scope];
|
|
33
|
-
if (resolver == null) {
|
|
34
|
-
if (entry.critical) {
|
|
35
|
-
throw new FlowersecError({
|
|
36
|
-
path,
|
|
37
|
-
stage: "validate",
|
|
38
|
-
code: "resolve_failed",
|
|
39
|
-
message: `missing scope resolver for ${entry.scope}@${entry.scope_version}`,
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
emitObserverDiagnostic(observer, {
|
|
43
|
-
path,
|
|
44
|
-
stage: "scope",
|
|
45
|
-
code_domain: "event",
|
|
46
|
-
code: "scope_ignored_missing_resolver",
|
|
47
|
-
result: "skip",
|
|
48
|
-
});
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
try {
|
|
52
|
-
await resolver(entry);
|
|
53
|
-
}
|
|
54
|
-
catch (e) {
|
|
55
|
-
if (!entry.critical && opts.relaxedOptionalScopeValidation === true) {
|
|
56
|
-
emitObserverDiagnostic(observer, {
|
|
57
|
-
path,
|
|
58
|
-
stage: "scope",
|
|
59
|
-
code_domain: "event",
|
|
60
|
-
code: "scope_ignored_relaxed_validation",
|
|
61
|
-
result: "skip",
|
|
62
|
-
});
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
throw new FlowersecError({
|
|
66
|
-
path,
|
|
67
|
-
stage: "validate",
|
|
68
|
-
code: "resolve_failed",
|
|
69
|
-
message: `scope validation failed for ${entry.scope}@${entry.scope_version}`,
|
|
70
|
-
cause: e,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
export async function normalizeConnectInput(input, opts = {}) {
|
|
76
|
-
const v = maybeParseJSON(input);
|
|
77
|
-
if (v == null || typeof v !== "object") {
|
|
78
|
-
throw new FlowersecError({
|
|
79
|
-
path: "auto",
|
|
80
|
-
stage: "validate",
|
|
81
|
-
code: "invalid_input",
|
|
82
|
-
message: "invalid input: expected an object or a JSON string",
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
const o = v;
|
|
86
|
-
const hasWsUrl = Object.prototype.hasOwnProperty.call(o, "ws_url");
|
|
87
|
-
const hasTunnelUrl = Object.prototype.hasOwnProperty.call(o, "tunnel_url");
|
|
88
|
-
const hasGrantClient = Object.prototype.hasOwnProperty.call(o, "grant_client");
|
|
89
|
-
const hasGrantServer = Object.prototype.hasOwnProperty.call(o, "grant_server");
|
|
90
|
-
const isArtifactCandidate = hasArtifactOnlyFields(o);
|
|
91
|
-
if ((hasWsUrl && (hasTunnelUrl || hasGrantClient || hasGrantServer)) || (hasTunnelUrl && (hasGrantClient || hasGrantServer))) {
|
|
92
|
-
throw new FlowersecError({
|
|
93
|
-
path: "auto",
|
|
94
|
-
stage: "validate",
|
|
95
|
-
code: "invalid_input",
|
|
96
|
-
message: "hybrid connect input is not allowed",
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
if (isArtifactCandidate && (hasWsUrl || hasTunnelUrl || hasGrantClient || hasGrantServer)) {
|
|
100
|
-
throw new FlowersecError({
|
|
101
|
-
path: "auto",
|
|
102
|
-
stage: "validate",
|
|
103
|
-
code: "invalid_input",
|
|
104
|
-
message: "artifact fields cannot be mixed with legacy connect inputs",
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
if (hasGrantServer) {
|
|
108
|
-
throw new FlowersecError({
|
|
109
|
-
path: "tunnel",
|
|
110
|
-
stage: "validate",
|
|
111
|
-
code: "role_mismatch",
|
|
112
|
-
message: "expected role=client",
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
if (hasGrantClient)
|
|
116
|
-
return { kind: "tunnel", input: v };
|
|
117
|
-
if (hasWsUrl)
|
|
118
|
-
return { kind: "direct", input: v };
|
|
119
|
-
if (hasTunnelUrl) {
|
|
120
|
-
if (typeof o.role === "number" && Number.isSafeInteger(o.role) && o.role === ControlRole.Role_server) {
|
|
121
|
-
throw new FlowersecError({
|
|
122
|
-
path: "tunnel",
|
|
123
|
-
stage: "validate",
|
|
124
|
-
code: "role_mismatch",
|
|
125
|
-
message: "expected role=client",
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
return { kind: "tunnel", input: v };
|
|
129
|
-
}
|
|
130
|
-
if (isArtifactCandidate) {
|
|
131
|
-
let artifact;
|
|
132
|
-
try {
|
|
133
|
-
artifact = assertConnectArtifact(v);
|
|
134
|
-
}
|
|
135
|
-
catch (e) {
|
|
136
|
-
throw new FlowersecError({
|
|
137
|
-
path: "auto",
|
|
138
|
-
stage: "validate",
|
|
139
|
-
code: "invalid_input",
|
|
140
|
-
message: "invalid ConnectArtifact",
|
|
141
|
-
cause: e,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
const observer = opts.observer == null
|
|
145
|
-
? undefined
|
|
146
|
-
: normalizeObserver(withObserverContext(opts.observer, {
|
|
147
|
-
path: artifact.transport,
|
|
148
|
-
...(artifact.correlation?.trace_id === undefined ? {} : { traceId: artifact.correlation.trace_id }),
|
|
149
|
-
...(artifact.correlation?.session_id === undefined ? {} : { sessionId: artifact.correlation.session_id }),
|
|
150
|
-
}), { path: artifact.transport });
|
|
151
|
-
await validateArtifactScopes(artifact, opts, observer);
|
|
152
|
-
if (artifact.transport === "direct") {
|
|
153
|
-
return {
|
|
154
|
-
kind: "direct",
|
|
155
|
-
input: artifact.direct_info,
|
|
156
|
-
...(artifact.correlation === undefined ? {} : { correlation: artifact.correlation }),
|
|
157
|
-
...(observer === undefined ? {} : { observer }),
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
return {
|
|
161
|
-
kind: "tunnel",
|
|
162
|
-
input: artifact.tunnel_grant,
|
|
163
|
-
...(artifact.correlation === undefined ? {} : { correlation: artifact.correlation }),
|
|
164
|
-
...(observer === undefined ? {} : { observer }),
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
throw new FlowersecError({
|
|
168
|
-
path: "auto",
|
|
169
|
-
stage: "validate",
|
|
170
|
-
code: "invalid_input",
|
|
171
|
-
message: "invalid input: expected DirectConnectInfo, ChannelInitGrant, wrapper, or ConnectArtifact",
|
|
172
|
-
});
|
|
173
|
-
}
|
package/dist/proxy/profiles.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { type ProxyPresetManifest } from "./preset.js";
|
|
2
|
-
export type ProxyProfile = Readonly<{
|
|
3
|
-
maxJsonFrameBytes: number;
|
|
4
|
-
maxChunkBytes: number;
|
|
5
|
-
maxBodyBytes: number;
|
|
6
|
-
maxWsFrameBytes: number;
|
|
7
|
-
timeoutMs: number;
|
|
8
|
-
}>;
|
|
9
|
-
export type ProxyProfileName = "default";
|
|
10
|
-
export declare const PROXY_PROFILE_DEFAULT: Readonly<{
|
|
11
|
-
maxJsonFrameBytes: number;
|
|
12
|
-
maxChunkBytes: number;
|
|
13
|
-
maxBodyBytes: number;
|
|
14
|
-
maxWsFrameBytes: number;
|
|
15
|
-
timeoutMs: number;
|
|
16
|
-
}>;
|
|
17
|
-
export declare function resolveProxyProfile(profile?: ProxyProfileName | Partial<ProxyProfile>): ProxyProfile;
|
|
18
|
-
export declare function profileToPresetManifest(profile?: ProxyProfileName | Partial<ProxyProfile>): ProxyPresetManifest;
|
package/dist/proxy/profiles.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { DEFAULT_PROXY_PRESET_MANIFEST, resolveProxyPreset, } from "./preset.js";
|
|
2
|
-
function toLegacyProfile(manifest) {
|
|
3
|
-
const resolved = resolveProxyPreset(manifest);
|
|
4
|
-
return Object.freeze({
|
|
5
|
-
maxJsonFrameBytes: resolved.limits.max_json_frame_bytes,
|
|
6
|
-
maxChunkBytes: resolved.limits.max_chunk_bytes,
|
|
7
|
-
maxBodyBytes: resolved.limits.max_body_bytes,
|
|
8
|
-
maxWsFrameBytes: resolved.limits.max_ws_frame_bytes,
|
|
9
|
-
timeoutMs: resolved.limits.timeout_ms ?? 0,
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
const DEFAULT_PROFILE = toLegacyProfile(DEFAULT_PROXY_PRESET_MANIFEST);
|
|
13
|
-
export const PROXY_PROFILE_DEFAULT = DEFAULT_PROFILE;
|
|
14
|
-
function normalizeSafeInt(name, value) {
|
|
15
|
-
if (!Number.isFinite(value))
|
|
16
|
-
throw new Error(`${name} must be a finite number`);
|
|
17
|
-
const n = Math.floor(value);
|
|
18
|
-
if (!Number.isSafeInteger(n))
|
|
19
|
-
throw new Error(`${name} must be a safe integer`);
|
|
20
|
-
if (n < 0)
|
|
21
|
-
throw new Error(`${name} must be >= 0`);
|
|
22
|
-
return n;
|
|
23
|
-
}
|
|
24
|
-
function resolveNamedProfile(name) {
|
|
25
|
-
switch (name) {
|
|
26
|
-
case "default":
|
|
27
|
-
return DEFAULT_PROFILE;
|
|
28
|
-
default:
|
|
29
|
-
throw new Error(`unknown proxy profile: ${name}`);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
export function resolveProxyProfile(profile) {
|
|
33
|
-
if (profile == null)
|
|
34
|
-
return DEFAULT_PROFILE;
|
|
35
|
-
if (typeof profile === "string") {
|
|
36
|
-
return resolveNamedProfile(profile);
|
|
37
|
-
}
|
|
38
|
-
const base = DEFAULT_PROFILE;
|
|
39
|
-
return Object.freeze({
|
|
40
|
-
maxJsonFrameBytes: normalizeSafeInt("maxJsonFrameBytes", profile.maxJsonFrameBytes ?? base.maxJsonFrameBytes),
|
|
41
|
-
maxChunkBytes: normalizeSafeInt("maxChunkBytes", profile.maxChunkBytes ?? base.maxChunkBytes),
|
|
42
|
-
maxBodyBytes: normalizeSafeInt("maxBodyBytes", profile.maxBodyBytes ?? base.maxBodyBytes),
|
|
43
|
-
maxWsFrameBytes: normalizeSafeInt("maxWsFrameBytes", profile.maxWsFrameBytes ?? base.maxWsFrameBytes),
|
|
44
|
-
timeoutMs: normalizeSafeInt("timeoutMs", profile.timeoutMs ?? base.timeoutMs),
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
export function profileToPresetManifest(profile) {
|
|
48
|
-
if (profile == null)
|
|
49
|
-
return DEFAULT_PROXY_PRESET_MANIFEST;
|
|
50
|
-
if (typeof profile === "string") {
|
|
51
|
-
switch (profile) {
|
|
52
|
-
case "default":
|
|
53
|
-
return DEFAULT_PROXY_PRESET_MANIFEST;
|
|
54
|
-
default:
|
|
55
|
-
throw new Error(`unknown proxy profile: ${profile}`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
const resolved = resolveProxyProfile(profile);
|
|
59
|
-
return Object.freeze({
|
|
60
|
-
v: 1,
|
|
61
|
-
preset_id: "legacy-profile",
|
|
62
|
-
deprecated: true,
|
|
63
|
-
limits: {
|
|
64
|
-
...(resolved.maxJsonFrameBytes > 0 ? { max_json_frame_bytes: resolved.maxJsonFrameBytes } : {}),
|
|
65
|
-
...(resolved.maxChunkBytes > 0 ? { max_chunk_bytes: resolved.maxChunkBytes } : {}),
|
|
66
|
-
...(resolved.maxBodyBytes > 0 ? { max_body_bytes: resolved.maxBodyBytes } : {}),
|
|
67
|
-
...(resolved.maxWsFrameBytes > 0 ? { max_ws_frame_bytes: resolved.maxWsFrameBytes } : {}),
|
|
68
|
-
...(resolved.timeoutMs > 0 ? { timeout_ms: resolved.timeoutMs } : {}),
|
|
69
|
-
},
|
|
70
|
-
});
|
|
71
|
-
}
|