Sign In

@msgmesh/sdk

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@msgmesh/sdk - npm Package Compare versions

Comparing version
0.1.2
to
0.1.3
+82
-0
dist/index.cjs

@@ -615,2 +615,84 @@ "use strict";

}
/**
* streamWs 透過 WebSocket 即時接收訊息,介面與 stream(SSE)一致、回傳停止函式。用全域 `WebSocket`
* (瀏覽器原生;Node ≥ 22 亦內建全域 WebSocket)——環境無全域 WebSocket 時立即拋錯(Node < 22 請改用
* subscribe() 長輪詢,或把 ws 套件掛到 globalThis.WebSocket)。連線鑑權走 query key(WebSocket 無法設 header)。
*
* 與 stream 的差異(WebSocket vs EventSource):
* - **WebSocket 無原生自動重連**(EventSource 有),故重連一律由 SDK 接管:每次斷線退避 1s 重連,
* 成功連上即重置失敗計數;**兩模式皆對「連續」失敗(未曾連上)設 MAX_AUTH_RETRIES 上限**——達上限
* 停止,避免對已撤銷憑證/持續不可用端點無限重連。getToken 模式另在重連前換新 token。
* - **撤權**:連線中撤權為 CLOSE 1008(PolicyViolation)+ reason `"authorization revoked"`(SSE 用具名
* msgmesh-close 事件),SDK 見此終態立即停止。**握手期**撤權/失效是 HTTP 401 → CloseEvent 1006(非 1008),
* 無法只靠 reason 判別,由上述連續失敗上限收口。其他暫時性關閉(`"authorization check unavailable"`
* /網路中斷)退避重連。`stop()` 主動關閉不觸發 onError、並清除待觸發的重連 timer。
*
* onMessage 收到每則事件的文字內容(訊息 value 字串);onError 收到 Event(連線錯誤)或 CloseEvent
* (關閉,可讀 e.code / e.reason)。
*/
streamWs(topic, onMessage, onError) {
const WS = globalThis.WebSocket;
if (typeof WS !== "function") {
throw new Error(
"msgmesh: streamWs \u9700\u8981\u5168\u57DF WebSocket(\u700F\u89BD\u5668\u6216 Node \u2265 22)\u3002Node < 22 \u8ACB\u6539\u7528 subscribe()(\u9577\u8F2A\u8A62),\u6216\u5C07 ws \u5957\u4EF6\u639B\u5230 globalThis.WebSocket\u3002"
);
}
let stopped = false;
let ws;
let failures = 0;
let reconnectTimer;
const wsBase = this.rt.replace(/^http/, "ws");
const wsUrl = (cred) => `${wsBase}/v1/topics/${encodeURIComponent(topic)}/ws?key=${encodeURIComponent(cred)}`;
const scheduleReconnect = () => {
if (stopped) return;
if (++failures >= MAX_AUTH_RETRIES) {
stopped = true;
console.warn(
"msgmesh: streamWs \u5DF2\u505C\u6B62 \u2014 \u9023\u7E8C\u591A\u6B21\u9023\u7DDA\u5931\u6557(\u6191\u8B49\u5DF2\u64A4\u92B7\u6216\u7AEF\u9EDE\u6301\u7E8C\u4E0D\u53EF\u7528)\u3002\u8ACB\u65BC\u6062\u5FA9\u5F8C\u91CD\u65B0\u547C\u53EB streamWs()\u3002"
);
return;
}
reconnectTimer = setTimeout(connect, 1e3);
};
const connect = async () => {
if (stopped) return;
let cred;
try {
cred = await this.credential();
} catch {
onError?.(new Event("error"));
if (this.getToken) this.invalidateToken();
scheduleReconnect();
return;
}
if (stopped) return;
try {
ws = new WS(wsUrl(cred));
} catch {
onError?.(new Event("error"));
scheduleReconnect();
return;
}
ws.onopen = () => {
failures = 0;
};
ws.onmessage = (e) => onMessage(typeof e.data === "string" ? e.data : String(e.data));
ws.onclose = (e) => {
if (stopped) return;
onError?.(e);
if (e.code === 1008 && e.reason === "authorization revoked") {
stopped = true;
return;
}
if (this.getToken) this.invalidateToken();
scheduleReconnect();
};
};
void connect();
return () => {
stopped = true;
if (reconnectTimer) clearTimeout(reconnectTimer);
ws?.close();
};
}
};

@@ -617,0 +699,0 @@ // Annotate the CommonJS export names for ESM import in node:

@@ -86,2 +86,3 @@ interface MsgMeshOptions {

tenant_id: string;
actor: string;
action: string;

@@ -424,4 +425,22 @@ result: string;

stream(topic: string, onMessage: (data: string) => void, onError?: (e: Event | MessageEvent) => void): () => void;
/**
* streamWs 透過 WebSocket 即時接收訊息,介面與 stream(SSE)一致、回傳停止函式。用全域 `WebSocket`
* (瀏覽器原生;Node ≥ 22 亦內建全域 WebSocket)——環境無全域 WebSocket 時立即拋錯(Node < 22 請改用
* subscribe() 長輪詢,或把 ws 套件掛到 globalThis.WebSocket)。連線鑑權走 query key(WebSocket 無法設 header)。
*
* 與 stream 的差異(WebSocket vs EventSource):
* - **WebSocket 無原生自動重連**(EventSource 有),故重連一律由 SDK 接管:每次斷線退避 1s 重連,
* 成功連上即重置失敗計數;**兩模式皆對「連續」失敗(未曾連上)設 MAX_AUTH_RETRIES 上限**——達上限
* 停止,避免對已撤銷憑證/持續不可用端點無限重連。getToken 模式另在重連前換新 token。
* - **撤權**:連線中撤權為 CLOSE 1008(PolicyViolation)+ reason `"authorization revoked"`(SSE 用具名
* msgmesh-close 事件),SDK 見此終態立即停止。**握手期**撤權/失效是 HTTP 401 → CloseEvent 1006(非 1008),
* 無法只靠 reason 判別,由上述連續失敗上限收口。其他暫時性關閉(`"authorization check unavailable"`
* /網路中斷)退避重連。`stop()` 主動關閉不觸發 onError、並清除待觸發的重連 timer。
*
* onMessage 收到每則事件的文字內容(訊息 value 字串);onError 收到 Event(連線錯誤)或 CloseEvent
* (關閉,可讀 e.code / e.reason)。
*/
streamWs(topic: string, onMessage: (data: string) => void, onError?: (e: Event | CloseEvent) => void): () => void;
}
export { type APIKey, type AdjustResult, type AuditEntry, AuthError, type Billing, type Deposit, type DepositAddress, type DepositStatus, type FinanceChainAmount, type FinanceOverview, type FinanceTenant, type LedgerEntry, type Message, MsgMesh, MsgMeshError, type MsgMeshOptions, NotFoundError, type Overview, type Page, type PlanLimits, type Presence, type PublishResult, RateLimitError, type ReplayResult, type SchemaVersion, type Settings, type Tenant, type TokenResponse, type Topic, type TopicFunction, type UsageDebit, type UsageResponse, type UsageRow, ValidationError, type Webhook, errorFromResponse, errorFromStatus };

@@ -86,2 +86,3 @@ interface MsgMeshOptions {

tenant_id: string;
actor: string;
action: string;

@@ -424,4 +425,22 @@ result: string;

stream(topic: string, onMessage: (data: string) => void, onError?: (e: Event | MessageEvent) => void): () => void;
/**
* streamWs 透過 WebSocket 即時接收訊息,介面與 stream(SSE)一致、回傳停止函式。用全域 `WebSocket`
* (瀏覽器原生;Node ≥ 22 亦內建全域 WebSocket)——環境無全域 WebSocket 時立即拋錯(Node < 22 請改用
* subscribe() 長輪詢,或把 ws 套件掛到 globalThis.WebSocket)。連線鑑權走 query key(WebSocket 無法設 header)。
*
* 與 stream 的差異(WebSocket vs EventSource):
* - **WebSocket 無原生自動重連**(EventSource 有),故重連一律由 SDK 接管:每次斷線退避 1s 重連,
* 成功連上即重置失敗計數;**兩模式皆對「連續」失敗(未曾連上)設 MAX_AUTH_RETRIES 上限**——達上限
* 停止,避免對已撤銷憑證/持續不可用端點無限重連。getToken 模式另在重連前換新 token。
* - **撤權**:連線中撤權為 CLOSE 1008(PolicyViolation)+ reason `"authorization revoked"`(SSE 用具名
* msgmesh-close 事件),SDK 見此終態立即停止。**握手期**撤權/失效是 HTTP 401 → CloseEvent 1006(非 1008),
* 無法只靠 reason 判別,由上述連續失敗上限收口。其他暫時性關閉(`"authorization check unavailable"`
* /網路中斷)退避重連。`stop()` 主動關閉不觸發 onError、並清除待觸發的重連 timer。
*
* onMessage 收到每則事件的文字內容(訊息 value 字串);onError 收到 Event(連線錯誤)或 CloseEvent
* (關閉,可讀 e.code / e.reason)。
*/
streamWs(topic: string, onMessage: (data: string) => void, onError?: (e: Event | CloseEvent) => void): () => void;
}
export { type APIKey, type AdjustResult, type AuditEntry, AuthError, type Billing, type Deposit, type DepositAddress, type DepositStatus, type FinanceChainAmount, type FinanceOverview, type FinanceTenant, type LedgerEntry, type Message, MsgMesh, MsgMeshError, type MsgMeshOptions, NotFoundError, type Overview, type Page, type PlanLimits, type Presence, type PublishResult, RateLimitError, type ReplayResult, type SchemaVersion, type Settings, type Tenant, type TokenResponse, type Topic, type TopicFunction, type UsageDebit, type UsageResponse, type UsageRow, ValidationError, type Webhook, errorFromResponse, errorFromStatus };

@@ -582,2 +582,84 @@ // src/errors.ts

}
/**
* streamWs 透過 WebSocket 即時接收訊息,介面與 stream(SSE)一致、回傳停止函式。用全域 `WebSocket`
* (瀏覽器原生;Node ≥ 22 亦內建全域 WebSocket)——環境無全域 WebSocket 時立即拋錯(Node < 22 請改用
* subscribe() 長輪詢,或把 ws 套件掛到 globalThis.WebSocket)。連線鑑權走 query key(WebSocket 無法設 header)。
*
* 與 stream 的差異(WebSocket vs EventSource):
* - **WebSocket 無原生自動重連**(EventSource 有),故重連一律由 SDK 接管:每次斷線退避 1s 重連,
* 成功連上即重置失敗計數;**兩模式皆對「連續」失敗(未曾連上)設 MAX_AUTH_RETRIES 上限**——達上限
* 停止,避免對已撤銷憑證/持續不可用端點無限重連。getToken 模式另在重連前換新 token。
* - **撤權**:連線中撤權為 CLOSE 1008(PolicyViolation)+ reason `"authorization revoked"`(SSE 用具名
* msgmesh-close 事件),SDK 見此終態立即停止。**握手期**撤權/失效是 HTTP 401 → CloseEvent 1006(非 1008),
* 無法只靠 reason 判別,由上述連續失敗上限收口。其他暫時性關閉(`"authorization check unavailable"`
* /網路中斷)退避重連。`stop()` 主動關閉不觸發 onError、並清除待觸發的重連 timer。
*
* onMessage 收到每則事件的文字內容(訊息 value 字串);onError 收到 Event(連線錯誤)或 CloseEvent
* (關閉,可讀 e.code / e.reason)。
*/
streamWs(topic, onMessage, onError) {
const WS = globalThis.WebSocket;
if (typeof WS !== "function") {
throw new Error(
"msgmesh: streamWs \u9700\u8981\u5168\u57DF WebSocket(\u700F\u89BD\u5668\u6216 Node \u2265 22)\u3002Node < 22 \u8ACB\u6539\u7528 subscribe()(\u9577\u8F2A\u8A62),\u6216\u5C07 ws \u5957\u4EF6\u639B\u5230 globalThis.WebSocket\u3002"
);
}
let stopped = false;
let ws;
let failures = 0;
let reconnectTimer;
const wsBase = this.rt.replace(/^http/, "ws");
const wsUrl = (cred) => `${wsBase}/v1/topics/${encodeURIComponent(topic)}/ws?key=${encodeURIComponent(cred)}`;
const scheduleReconnect = () => {
if (stopped) return;
if (++failures >= MAX_AUTH_RETRIES) {
stopped = true;
console.warn(
"msgmesh: streamWs \u5DF2\u505C\u6B62 \u2014 \u9023\u7E8C\u591A\u6B21\u9023\u7DDA\u5931\u6557(\u6191\u8B49\u5DF2\u64A4\u92B7\u6216\u7AEF\u9EDE\u6301\u7E8C\u4E0D\u53EF\u7528)\u3002\u8ACB\u65BC\u6062\u5FA9\u5F8C\u91CD\u65B0\u547C\u53EB streamWs()\u3002"
);
return;
}
reconnectTimer = setTimeout(connect, 1e3);
};
const connect = async () => {
if (stopped) return;
let cred;
try {
cred = await this.credential();
} catch {
onError?.(new Event("error"));
if (this.getToken) this.invalidateToken();
scheduleReconnect();
return;
}
if (stopped) return;
try {
ws = new WS(wsUrl(cred));
} catch {
onError?.(new Event("error"));
scheduleReconnect();
return;
}
ws.onopen = () => {
failures = 0;
};
ws.onmessage = (e) => onMessage(typeof e.data === "string" ? e.data : String(e.data));
ws.onclose = (e) => {
if (stopped) return;
onError?.(e);
if (e.code === 1008 && e.reason === "authorization revoked") {
stopped = true;
return;
}
if (this.getToken) this.invalidateToken();
scheduleReconnect();
};
};
void connect();
return () => {
stopped = true;
if (reconnectTimer) clearTimeout(reconnectTimer);
ws?.close();
};
}
};

@@ -584,0 +666,0 @@ export {

+4
-2
{
"name": "@msgmesh/sdk",
"version": "0.1.2",
"version": "0.1.3",
"description": "MsgMesh TypeScript SDK — 多租戶事件總線的收發 / 即時(SSE·WS)/ 治理 client(Node 與瀏覽器通用)。",

@@ -33,3 +33,5 @@ "license": "MIT",

},
"files": ["dist"],
"files": [
"dist"
],
"publishConfig": {

@@ -36,0 +38,0 @@ "access": "public"

@@ -36,5 +36,10 @@ # @msgmesh/sdk

});
mq.stream("room.42", (data) => console.log(data)); // SSE;token 過期自動換新後重連
mq.stream("room.42", (data) => console.log(data)); // SSE;token 過期自動換新後重連
mq.streamWs("room.42", (data) => console.log(data)); // WebSocket;同介面,SDK 自管重連
```
即時接收兩種選擇,介面一致、皆回傳停止函式:
- **`stream`(SSE)**:靠瀏覽器原生 `EventSource`(有原生自動重連),走 `/…/sse`。**僅瀏覽器**。
- **`streamWs`(WebSocket)**:全域 `WebSocket`(瀏覽器原生;Node ≥ 22 內建),走 `/…/ws`。**WebSocket 無原生重連,故由 SDK 接管**:每次斷線退避 1s 重連,成功連上即重置失敗計數;**連續**失敗達上限(未曾連上)即停止(避免對已撤銷的憑證或持續不可用的端點無限重連),getToken 模式另在重連前換新 token。撤權若在連線中發生為 CLOSE 1008 `authorization revoked`(立即停);若在握手期(HTTP 401→CloseEvent 1006)則由上限收口。適合 SSE 被中間層擋掉、或已有 WS 基礎設施的場景。Node < 22 無全域 WebSocket 會拋錯,改用 `subscribe`(長輪詢)。
後端(~5 行)代呼 `/v1/tokens`(可帶 `capabilities` 降權為金鑰能力子集,只准更窄)後把結果回傳即可。

@@ -78,3 +83,3 @@

- Topics:`createTopic` / `listTopics` / `deleteTopic`
- 收發:`publish` / `poll` / `subscribe`(輪詢)/ `stream`(SSE,瀏覽器)/ `getPresence`
- 收發:`publish` / `poll` / `subscribe`(輪詢)/ `stream`(SSE,瀏覽器)/ `streamWs`(WebSocket,瀏覽器 + Node ≥ 22)/ `getPresence`
- Keys:`listKeys`(回傳含 `capabilities`/`name`)/ `createKey`(可帶 `scope`+`capabilities`)/ `deleteKey`

@@ -81,0 +86,0 @@ - Webhooks:`listWebhooks` / `createWebhook` / `deleteWebhook` / `reactivateWebhook`