connectbase-client 3.6.0 → 3.7.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.
- package/dist/cli.js +260 -118
- package/dist/connect-base.umd.js +3 -3
- package/dist/index.d.mts +46 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +85 -0
- package/dist/index.mjs +85 -0
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -7010,6 +7010,36 @@ declare class EndpointAPI {
|
|
|
7010
7010
|
* )
|
|
7011
7011
|
* ```
|
|
7012
7012
|
*/
|
|
7013
|
+
/**
|
|
7014
|
+
* Open a native browser `WebSocket` to a user model server (e.g. ComfyUI's
|
|
7015
|
+
* `/ws` event channel) through the ConnectBase proxy.
|
|
7016
|
+
*
|
|
7017
|
+
* Background: native browser `WebSocket` cannot send custom headers, so
|
|
7018
|
+
* `X-Public-Key` cannot be supplied on the Upgrade request. This helper
|
|
7019
|
+
* solves that by:
|
|
7020
|
+
* 1. POSTing to `/v1/proxy/<label>/ws-ticket` (with `X-Public-Key`)
|
|
7021
|
+
* to obtain a single-use 30s token,
|
|
7022
|
+
* 2. Opening `wss://<base>/v1/proxy/<label><path>?ticket=<token>&...`,
|
|
7023
|
+
* 3. Returning the established `WebSocket` to the caller.
|
|
7024
|
+
*
|
|
7025
|
+
* Both the client→upstream and upstream→client byte streams flow
|
|
7026
|
+
* transparently — the proxy server adds no framing of its own.
|
|
7027
|
+
*
|
|
7028
|
+
* @example ComfyUI native event channel
|
|
7029
|
+
* ```ts
|
|
7030
|
+
* const ws = await cb.endpoint.connectWebSocket("comfyui-main", {
|
|
7031
|
+
* path: "/ws",
|
|
7032
|
+
* query: { clientId: crypto.randomUUID() },
|
|
7033
|
+
* })
|
|
7034
|
+
* ws.onmessage = (e) => {
|
|
7035
|
+
* const msg = JSON.parse(typeof e.data === "string" ? e.data : "")
|
|
7036
|
+
* if (msg.type === "progress") {
|
|
7037
|
+
* // progress.value / progress.max — exact node-level progress
|
|
7038
|
+
* }
|
|
7039
|
+
* }
|
|
7040
|
+
* ```
|
|
7041
|
+
*/
|
|
7042
|
+
connectWebSocket(label: string, opts?: ConnectWebSocketOptions): Promise<WebSocket>;
|
|
7013
7043
|
pollUntil<T>(label: string, init: EndpointCallInit, predicate: (body: any, res: Response) => T | undefined | Promise<T | undefined>, opts?: PollUntilOptions): Promise<T>;
|
|
7014
7044
|
}
|
|
7015
7045
|
/**
|
|
@@ -7032,6 +7062,22 @@ interface EndpointCallInit {
|
|
|
7032
7062
|
/** 취소 신호. */
|
|
7033
7063
|
signal?: AbortSignal;
|
|
7034
7064
|
}
|
|
7065
|
+
/**
|
|
7066
|
+
* EndpointAPI.connectWebSocket 옵션.
|
|
7067
|
+
*/
|
|
7068
|
+
interface ConnectWebSocketOptions {
|
|
7069
|
+
/**
|
|
7070
|
+
* 사용자 모델 서버의 WebSocket 엔드포인트 경로. `/` 로 시작 (기본 `/`).
|
|
7071
|
+
* 예: `/ws`, `/socket`.
|
|
7072
|
+
*/
|
|
7073
|
+
path?: string;
|
|
7074
|
+
/** 추가 query 파라미터 (ticket 은 자동 주입). */
|
|
7075
|
+
query?: Record<string, string>;
|
|
7076
|
+
/** WebSocket subprotocols (Sec-WebSocket-Protocol 헤더). */
|
|
7077
|
+
protocols?: string | string[];
|
|
7078
|
+
/** Abort 시 ws.close(1000) 호출. */
|
|
7079
|
+
signal?: AbortSignal;
|
|
7080
|
+
}
|
|
7035
7081
|
/**
|
|
7036
7082
|
* EndpointAPI.pollUntil 옵션.
|
|
7037
7083
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -7010,6 +7010,36 @@ declare class EndpointAPI {
|
|
|
7010
7010
|
* )
|
|
7011
7011
|
* ```
|
|
7012
7012
|
*/
|
|
7013
|
+
/**
|
|
7014
|
+
* Open a native browser `WebSocket` to a user model server (e.g. ComfyUI's
|
|
7015
|
+
* `/ws` event channel) through the ConnectBase proxy.
|
|
7016
|
+
*
|
|
7017
|
+
* Background: native browser `WebSocket` cannot send custom headers, so
|
|
7018
|
+
* `X-Public-Key` cannot be supplied on the Upgrade request. This helper
|
|
7019
|
+
* solves that by:
|
|
7020
|
+
* 1. POSTing to `/v1/proxy/<label>/ws-ticket` (with `X-Public-Key`)
|
|
7021
|
+
* to obtain a single-use 30s token,
|
|
7022
|
+
* 2. Opening `wss://<base>/v1/proxy/<label><path>?ticket=<token>&...`,
|
|
7023
|
+
* 3. Returning the established `WebSocket` to the caller.
|
|
7024
|
+
*
|
|
7025
|
+
* Both the client→upstream and upstream→client byte streams flow
|
|
7026
|
+
* transparently — the proxy server adds no framing of its own.
|
|
7027
|
+
*
|
|
7028
|
+
* @example ComfyUI native event channel
|
|
7029
|
+
* ```ts
|
|
7030
|
+
* const ws = await cb.endpoint.connectWebSocket("comfyui-main", {
|
|
7031
|
+
* path: "/ws",
|
|
7032
|
+
* query: { clientId: crypto.randomUUID() },
|
|
7033
|
+
* })
|
|
7034
|
+
* ws.onmessage = (e) => {
|
|
7035
|
+
* const msg = JSON.parse(typeof e.data === "string" ? e.data : "")
|
|
7036
|
+
* if (msg.type === "progress") {
|
|
7037
|
+
* // progress.value / progress.max — exact node-level progress
|
|
7038
|
+
* }
|
|
7039
|
+
* }
|
|
7040
|
+
* ```
|
|
7041
|
+
*/
|
|
7042
|
+
connectWebSocket(label: string, opts?: ConnectWebSocketOptions): Promise<WebSocket>;
|
|
7013
7043
|
pollUntil<T>(label: string, init: EndpointCallInit, predicate: (body: any, res: Response) => T | undefined | Promise<T | undefined>, opts?: PollUntilOptions): Promise<T>;
|
|
7014
7044
|
}
|
|
7015
7045
|
/**
|
|
@@ -7032,6 +7062,22 @@ interface EndpointCallInit {
|
|
|
7032
7062
|
/** 취소 신호. */
|
|
7033
7063
|
signal?: AbortSignal;
|
|
7034
7064
|
}
|
|
7065
|
+
/**
|
|
7066
|
+
* EndpointAPI.connectWebSocket 옵션.
|
|
7067
|
+
*/
|
|
7068
|
+
interface ConnectWebSocketOptions {
|
|
7069
|
+
/**
|
|
7070
|
+
* 사용자 모델 서버의 WebSocket 엔드포인트 경로. `/` 로 시작 (기본 `/`).
|
|
7071
|
+
* 예: `/ws`, `/socket`.
|
|
7072
|
+
*/
|
|
7073
|
+
path?: string;
|
|
7074
|
+
/** 추가 query 파라미터 (ticket 은 자동 주입). */
|
|
7075
|
+
query?: Record<string, string>;
|
|
7076
|
+
/** WebSocket subprotocols (Sec-WebSocket-Protocol 헤더). */
|
|
7077
|
+
protocols?: string | string[];
|
|
7078
|
+
/** Abort 시 ws.close(1000) 호출. */
|
|
7079
|
+
signal?: AbortSignal;
|
|
7080
|
+
}
|
|
7035
7081
|
/**
|
|
7036
7082
|
* EndpointAPI.pollUntil 옵션.
|
|
7037
7083
|
*/
|
package/dist/index.js
CHANGED
|
@@ -7849,6 +7849,91 @@ var EndpointAPI = class {
|
|
|
7849
7849
|
* )
|
|
7850
7850
|
* ```
|
|
7851
7851
|
*/
|
|
7852
|
+
/**
|
|
7853
|
+
* Open a native browser `WebSocket` to a user model server (e.g. ComfyUI's
|
|
7854
|
+
* `/ws` event channel) through the ConnectBase proxy.
|
|
7855
|
+
*
|
|
7856
|
+
* Background: native browser `WebSocket` cannot send custom headers, so
|
|
7857
|
+
* `X-Public-Key` cannot be supplied on the Upgrade request. This helper
|
|
7858
|
+
* solves that by:
|
|
7859
|
+
* 1. POSTing to `/v1/proxy/<label>/ws-ticket` (with `X-Public-Key`)
|
|
7860
|
+
* to obtain a single-use 30s token,
|
|
7861
|
+
* 2. Opening `wss://<base>/v1/proxy/<label><path>?ticket=<token>&...`,
|
|
7862
|
+
* 3. Returning the established `WebSocket` to the caller.
|
|
7863
|
+
*
|
|
7864
|
+
* Both the client→upstream and upstream→client byte streams flow
|
|
7865
|
+
* transparently — the proxy server adds no framing of its own.
|
|
7866
|
+
*
|
|
7867
|
+
* @example ComfyUI native event channel
|
|
7868
|
+
* ```ts
|
|
7869
|
+
* const ws = await cb.endpoint.connectWebSocket("comfyui-main", {
|
|
7870
|
+
* path: "/ws",
|
|
7871
|
+
* query: { clientId: crypto.randomUUID() },
|
|
7872
|
+
* })
|
|
7873
|
+
* ws.onmessage = (e) => {
|
|
7874
|
+
* const msg = JSON.parse(typeof e.data === "string" ? e.data : "")
|
|
7875
|
+
* if (msg.type === "progress") {
|
|
7876
|
+
* // progress.value / progress.max — exact node-level progress
|
|
7877
|
+
* }
|
|
7878
|
+
* }
|
|
7879
|
+
* ```
|
|
7880
|
+
*/
|
|
7881
|
+
async connectWebSocket(label, opts = {}) {
|
|
7882
|
+
if (!label) {
|
|
7883
|
+
throw new Error("EndpointAPI.connectWebSocket: label required");
|
|
7884
|
+
}
|
|
7885
|
+
const path = opts.path ?? "/";
|
|
7886
|
+
if (!path.startsWith("/")) {
|
|
7887
|
+
throw new Error(
|
|
7888
|
+
`EndpointAPI.connectWebSocket: path must start with '/', got ${JSON.stringify(path)}`
|
|
7889
|
+
);
|
|
7890
|
+
}
|
|
7891
|
+
const baseUrl = this.http.getBaseUrl().replace(/\/+$/, "");
|
|
7892
|
+
const ticketUrl = `${baseUrl}/v1/proxy/${encodeURIComponent(label)}/ws-ticket`;
|
|
7893
|
+
const ticketHeaders = new Headers();
|
|
7894
|
+
const pk = this.http.getPublicKey();
|
|
7895
|
+
if (!pk) {
|
|
7896
|
+
throw new Error(
|
|
7897
|
+
"EndpointAPI.connectWebSocket: publicKey not configured. Pass `publicKey` to ConnectBase constructor."
|
|
7898
|
+
);
|
|
7899
|
+
}
|
|
7900
|
+
ticketHeaders.set("X-Public-Key", pk);
|
|
7901
|
+
const ticketRes = await fetch(ticketUrl, {
|
|
7902
|
+
method: "POST",
|
|
7903
|
+
headers: ticketHeaders,
|
|
7904
|
+
signal: opts.signal
|
|
7905
|
+
});
|
|
7906
|
+
if (!ticketRes.ok) {
|
|
7907
|
+
const text = await ticketRes.text().catch(() => "");
|
|
7908
|
+
throw new Error(
|
|
7909
|
+
`EndpointAPI.connectWebSocket: ticket issuance failed (${ticketRes.status}) ${text.slice(0, 200)}`
|
|
7910
|
+
);
|
|
7911
|
+
}
|
|
7912
|
+
const { ticket } = await ticketRes.json();
|
|
7913
|
+
if (!ticket) {
|
|
7914
|
+
throw new Error("EndpointAPI.connectWebSocket: server returned empty ticket");
|
|
7915
|
+
}
|
|
7916
|
+
const wsUrl = new URL(`${baseUrl}/v1/proxy/${encodeURIComponent(label)}${path}`);
|
|
7917
|
+
wsUrl.protocol = wsUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
7918
|
+
if (opts.query) {
|
|
7919
|
+
for (const [k, v] of Object.entries(opts.query)) {
|
|
7920
|
+
wsUrl.searchParams.set(k, v);
|
|
7921
|
+
}
|
|
7922
|
+
}
|
|
7923
|
+
wsUrl.searchParams.set("ticket", ticket);
|
|
7924
|
+
const ws = opts.protocols ? new WebSocket(wsUrl.toString(), opts.protocols) : new WebSocket(wsUrl.toString());
|
|
7925
|
+
if (opts.signal) {
|
|
7926
|
+
const onAbort = () => {
|
|
7927
|
+
try {
|
|
7928
|
+
ws.close(1e3, "client aborted");
|
|
7929
|
+
} catch {
|
|
7930
|
+
}
|
|
7931
|
+
};
|
|
7932
|
+
if (opts.signal.aborted) onAbort();
|
|
7933
|
+
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
7934
|
+
}
|
|
7935
|
+
return ws;
|
|
7936
|
+
}
|
|
7852
7937
|
async pollUntil(label, init, predicate, opts = {}) {
|
|
7853
7938
|
const intervalMs = opts.intervalMs ?? 1500;
|
|
7854
7939
|
const timeoutMs = opts.timeoutMs ?? 5 * 6e4;
|
package/dist/index.mjs
CHANGED
|
@@ -7808,6 +7808,91 @@ var EndpointAPI = class {
|
|
|
7808
7808
|
* )
|
|
7809
7809
|
* ```
|
|
7810
7810
|
*/
|
|
7811
|
+
/**
|
|
7812
|
+
* Open a native browser `WebSocket` to a user model server (e.g. ComfyUI's
|
|
7813
|
+
* `/ws` event channel) through the ConnectBase proxy.
|
|
7814
|
+
*
|
|
7815
|
+
* Background: native browser `WebSocket` cannot send custom headers, so
|
|
7816
|
+
* `X-Public-Key` cannot be supplied on the Upgrade request. This helper
|
|
7817
|
+
* solves that by:
|
|
7818
|
+
* 1. POSTing to `/v1/proxy/<label>/ws-ticket` (with `X-Public-Key`)
|
|
7819
|
+
* to obtain a single-use 30s token,
|
|
7820
|
+
* 2. Opening `wss://<base>/v1/proxy/<label><path>?ticket=<token>&...`,
|
|
7821
|
+
* 3. Returning the established `WebSocket` to the caller.
|
|
7822
|
+
*
|
|
7823
|
+
* Both the client→upstream and upstream→client byte streams flow
|
|
7824
|
+
* transparently — the proxy server adds no framing of its own.
|
|
7825
|
+
*
|
|
7826
|
+
* @example ComfyUI native event channel
|
|
7827
|
+
* ```ts
|
|
7828
|
+
* const ws = await cb.endpoint.connectWebSocket("comfyui-main", {
|
|
7829
|
+
* path: "/ws",
|
|
7830
|
+
* query: { clientId: crypto.randomUUID() },
|
|
7831
|
+
* })
|
|
7832
|
+
* ws.onmessage = (e) => {
|
|
7833
|
+
* const msg = JSON.parse(typeof e.data === "string" ? e.data : "")
|
|
7834
|
+
* if (msg.type === "progress") {
|
|
7835
|
+
* // progress.value / progress.max — exact node-level progress
|
|
7836
|
+
* }
|
|
7837
|
+
* }
|
|
7838
|
+
* ```
|
|
7839
|
+
*/
|
|
7840
|
+
async connectWebSocket(label, opts = {}) {
|
|
7841
|
+
if (!label) {
|
|
7842
|
+
throw new Error("EndpointAPI.connectWebSocket: label required");
|
|
7843
|
+
}
|
|
7844
|
+
const path = opts.path ?? "/";
|
|
7845
|
+
if (!path.startsWith("/")) {
|
|
7846
|
+
throw new Error(
|
|
7847
|
+
`EndpointAPI.connectWebSocket: path must start with '/', got ${JSON.stringify(path)}`
|
|
7848
|
+
);
|
|
7849
|
+
}
|
|
7850
|
+
const baseUrl = this.http.getBaseUrl().replace(/\/+$/, "");
|
|
7851
|
+
const ticketUrl = `${baseUrl}/v1/proxy/${encodeURIComponent(label)}/ws-ticket`;
|
|
7852
|
+
const ticketHeaders = new Headers();
|
|
7853
|
+
const pk = this.http.getPublicKey();
|
|
7854
|
+
if (!pk) {
|
|
7855
|
+
throw new Error(
|
|
7856
|
+
"EndpointAPI.connectWebSocket: publicKey not configured. Pass `publicKey` to ConnectBase constructor."
|
|
7857
|
+
);
|
|
7858
|
+
}
|
|
7859
|
+
ticketHeaders.set("X-Public-Key", pk);
|
|
7860
|
+
const ticketRes = await fetch(ticketUrl, {
|
|
7861
|
+
method: "POST",
|
|
7862
|
+
headers: ticketHeaders,
|
|
7863
|
+
signal: opts.signal
|
|
7864
|
+
});
|
|
7865
|
+
if (!ticketRes.ok) {
|
|
7866
|
+
const text = await ticketRes.text().catch(() => "");
|
|
7867
|
+
throw new Error(
|
|
7868
|
+
`EndpointAPI.connectWebSocket: ticket issuance failed (${ticketRes.status}) ${text.slice(0, 200)}`
|
|
7869
|
+
);
|
|
7870
|
+
}
|
|
7871
|
+
const { ticket } = await ticketRes.json();
|
|
7872
|
+
if (!ticket) {
|
|
7873
|
+
throw new Error("EndpointAPI.connectWebSocket: server returned empty ticket");
|
|
7874
|
+
}
|
|
7875
|
+
const wsUrl = new URL(`${baseUrl}/v1/proxy/${encodeURIComponent(label)}${path}`);
|
|
7876
|
+
wsUrl.protocol = wsUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
7877
|
+
if (opts.query) {
|
|
7878
|
+
for (const [k, v] of Object.entries(opts.query)) {
|
|
7879
|
+
wsUrl.searchParams.set(k, v);
|
|
7880
|
+
}
|
|
7881
|
+
}
|
|
7882
|
+
wsUrl.searchParams.set("ticket", ticket);
|
|
7883
|
+
const ws = opts.protocols ? new WebSocket(wsUrl.toString(), opts.protocols) : new WebSocket(wsUrl.toString());
|
|
7884
|
+
if (opts.signal) {
|
|
7885
|
+
const onAbort = () => {
|
|
7886
|
+
try {
|
|
7887
|
+
ws.close(1e3, "client aborted");
|
|
7888
|
+
} catch {
|
|
7889
|
+
}
|
|
7890
|
+
};
|
|
7891
|
+
if (opts.signal.aborted) onAbort();
|
|
7892
|
+
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
7893
|
+
}
|
|
7894
|
+
return ws;
|
|
7895
|
+
}
|
|
7811
7896
|
async pollUntil(label, init, predicate, opts = {}) {
|
|
7812
7897
|
const intervalMs = opts.intervalMs ?? 1500;
|
|
7813
7898
|
const timeoutMs = opts.timeoutMs ?? 5 * 6e4;
|