@wdywdy/electric-open-platform 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +585 -2
- package/dist/cjs/client.js +173 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/core/api.js +518 -0
- package/dist/cjs/core/api.js.map +1 -0
- package/dist/cjs/core/auth.js +293 -0
- package/dist/cjs/core/auth.js.map +1 -0
- package/dist/cjs/core/crypto.js +160 -0
- package/dist/cjs/core/crypto.js.map +1 -0
- package/dist/cjs/core/errors.js +114 -0
- package/dist/cjs/core/errors.js.map +1 -0
- package/dist/cjs/core/http.js +70 -0
- package/dist/cjs/core/http.js.map +1 -0
- package/dist/cjs/core/models.js +105 -0
- package/dist/cjs/core/models.js.map +1 -0
- package/dist/cjs/core/push.js +79 -0
- package/dist/cjs/core/push.js.map +1 -0
- package/dist/cjs/core/router.js +124 -0
- package/dist/cjs/core/router.js.map +1 -0
- package/dist/cjs/core/runtime.js +37 -0
- package/dist/cjs/core/runtime.js.map +1 -0
- package/dist/cjs/core/sign.js +75 -0
- package/dist/cjs/core/sign.js.map +1 -0
- package/dist/cjs/core/storage.js +152 -0
- package/dist/cjs/core/storage.js.map +1 -0
- package/dist/cjs/core/transport-fetch.js +57 -0
- package/dist/cjs/core/transport-fetch.js.map +1 -0
- package/dist/cjs/core/transport.js +41 -0
- package/dist/cjs/core/transport.js.map +1 -0
- package/dist/cjs/core/types.js +5 -0
- package/dist/cjs/core/types.js.map +1 -0
- package/dist/cjs/index.js +111 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/esm/client.d.ts +73 -0
- package/dist/esm/client.js +169 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/core/api.d.ts +377 -0
- package/dist/esm/core/api.js +506 -0
- package/dist/esm/core/api.js.map +1 -0
- package/dist/esm/core/auth.d.ts +69 -0
- package/dist/esm/core/auth.js +289 -0
- package/dist/esm/core/auth.js.map +1 -0
- package/dist/esm/core/crypto.d.ts +24 -0
- package/dist/esm/core/crypto.js +154 -0
- package/dist/esm/core/crypto.js.map +1 -0
- package/dist/esm/core/errors.d.ts +86 -0
- package/dist/esm/core/errors.js +108 -0
- package/dist/esm/core/errors.js.map +1 -0
- package/dist/esm/core/http.d.ts +24 -0
- package/dist/esm/core/http.js +56 -0
- package/dist/esm/core/http.js.map +1 -0
- package/dist/esm/core/models.d.ts +441 -0
- package/dist/esm/core/models.js +102 -0
- package/dist/esm/core/models.js.map +1 -0
- package/dist/esm/core/push.d.ts +54 -0
- package/dist/esm/core/push.js +74 -0
- package/dist/esm/core/push.js.map +1 -0
- package/dist/esm/core/router.d.ts +44 -0
- package/dist/esm/core/router.js +120 -0
- package/dist/esm/core/router.js.map +1 -0
- package/dist/esm/core/runtime.d.ts +23 -0
- package/dist/esm/core/runtime.js +33 -0
- package/dist/esm/core/runtime.js.map +1 -0
- package/dist/esm/core/sign.d.ts +54 -0
- package/dist/esm/core/sign.js +67 -0
- package/dist/esm/core/sign.js.map +1 -0
- package/dist/esm/core/storage.d.ts +73 -0
- package/dist/esm/core/storage.js +141 -0
- package/dist/esm/core/storage.js.map +1 -0
- package/dist/esm/core/transport-fetch.d.ts +2 -0
- package/dist/esm/core/transport-fetch.js +54 -0
- package/dist/esm/core/transport-fetch.js.map +1 -0
- package/dist/esm/core/transport.d.ts +23 -0
- package/dist/esm/core/transport.js +36 -0
- package/dist/esm/core/transport.js.map +1 -0
- package/dist/esm/core/types.d.ts +76 -0
- package/dist/esm/core/types.js +2 -0
- package/dist/esm/core/types.js.map +1 -0
- package/dist/esm/index.d.ts +37 -0
- package/dist/esm/index.js +47 -0
- package/dist/esm/index.js.map +1 -0
- package/package.json +63 -4
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TokenStore = exports.memoryBackend = void 0;
|
|
4
|
+
exports.createMemoryStore = createMemoryStore;
|
|
5
|
+
exports.createLocalStorageStore = createLocalStorageStore;
|
|
6
|
+
exports.setDefaultStore = setDefaultStore;
|
|
7
|
+
exports.getDefaultStore = getDefaultStore;
|
|
8
|
+
exports.clearDefaultStore = clearDefaultStore;
|
|
9
|
+
exports.resolveBackend = resolveBackend;
|
|
10
|
+
exports.resetStorageBackend = resetStorageBackend;
|
|
11
|
+
const memory = new Map();
|
|
12
|
+
/** 内存后端:进程内共享,适合测试与一次性脚本。 */
|
|
13
|
+
function createMemoryStore() {
|
|
14
|
+
return {
|
|
15
|
+
name: 'memory',
|
|
16
|
+
async get(key) {
|
|
17
|
+
return memory.has(key) ? memory.get(key) : null;
|
|
18
|
+
},
|
|
19
|
+
async set(key, value) {
|
|
20
|
+
memory.set(key, value);
|
|
21
|
+
},
|
|
22
|
+
async remove(key) {
|
|
23
|
+
memory.delete(key);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
exports.memoryBackend = createMemoryStore();
|
|
28
|
+
/** 探活 localStorage:隐私模式/服务端渲染下读写都会抛错,此时返回 null。 */
|
|
29
|
+
function createLocalStorageStore() {
|
|
30
|
+
try {
|
|
31
|
+
if (typeof globalThis.localStorage === 'undefined')
|
|
32
|
+
return null;
|
|
33
|
+
const probe = '__eop_probe__';
|
|
34
|
+
globalThis.localStorage.setItem(probe, '1');
|
|
35
|
+
globalThis.localStorage.removeItem(probe);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
name: 'localStorage',
|
|
42
|
+
async get(key) {
|
|
43
|
+
return globalThis.localStorage.getItem(key);
|
|
44
|
+
},
|
|
45
|
+
async set(key, value) {
|
|
46
|
+
globalThis.localStorage.setItem(key, value);
|
|
47
|
+
},
|
|
48
|
+
async remove(key) {
|
|
49
|
+
globalThis.localStorage.removeItem(key);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
let resolved = null;
|
|
54
|
+
let defaultStore;
|
|
55
|
+
/**
|
|
56
|
+
* 注入全局默认存储后端(如 iOS `UserDefaults` / Android `SharedPreferences`)。
|
|
57
|
+
*
|
|
58
|
+
* 与 `setTransport()` 对称:宿主应用在 bootstrap 阶段调用一次,之后所有
|
|
59
|
+
* `configure()` 都会用它,业务代码(组件、页面、共享模块)**不需要知道宿主是什么**。
|
|
60
|
+
* 传了 `config.store` 时以 `config.store` 为准。
|
|
61
|
+
*/
|
|
62
|
+
function setDefaultStore(store) {
|
|
63
|
+
defaultStore = store;
|
|
64
|
+
}
|
|
65
|
+
/** 当前注入的全局默认存储后端(未注入为 undefined)。 */
|
|
66
|
+
function getDefaultStore() {
|
|
67
|
+
return defaultStore;
|
|
68
|
+
}
|
|
69
|
+
/** 撤销全局默认存储后端(测试用)。 */
|
|
70
|
+
function clearDefaultStore() {
|
|
71
|
+
defaultStore = undefined;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 解析存储后端,优先级:
|
|
75
|
+
* `config.store`(最高)> `setDefaultStore()` 注入的全局后端 > `storage` 模式对应的内置后端。
|
|
76
|
+
*
|
|
77
|
+
* @param mode 配置里的 `storage`(默认 `auto`)
|
|
78
|
+
* @param custom 调用方在 `configure({ store })` 里传入的自定义 store
|
|
79
|
+
*/
|
|
80
|
+
function resolveBackend(mode = 'auto', custom) {
|
|
81
|
+
if (custom)
|
|
82
|
+
return custom;
|
|
83
|
+
if (defaultStore)
|
|
84
|
+
return defaultStore;
|
|
85
|
+
if (mode === 'memory')
|
|
86
|
+
return exports.memoryBackend;
|
|
87
|
+
if (mode === 'localStorage')
|
|
88
|
+
return createLocalStorageStore() ?? exports.memoryBackend;
|
|
89
|
+
// auto:localStorage → 内存(Node/SSR 没有 localStorage)
|
|
90
|
+
if (resolved)
|
|
91
|
+
return resolved;
|
|
92
|
+
resolved = createLocalStorageStore() ?? exports.memoryBackend;
|
|
93
|
+
return resolved;
|
|
94
|
+
}
|
|
95
|
+
/** Resets the cached backend — used by tests and after a `storage` config change. */
|
|
96
|
+
function resetStorageBackend() {
|
|
97
|
+
resolved = null;
|
|
98
|
+
}
|
|
99
|
+
class TokenStore {
|
|
100
|
+
constructor(backend, namespace) {
|
|
101
|
+
this.backend = backend;
|
|
102
|
+
this.namespace = namespace;
|
|
103
|
+
}
|
|
104
|
+
key(name) {
|
|
105
|
+
return `eop:${this.namespace}:${name}`;
|
|
106
|
+
}
|
|
107
|
+
async readTokens() {
|
|
108
|
+
let raw = null;
|
|
109
|
+
try {
|
|
110
|
+
raw = await this.backend.get(this.key('tokens'));
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// 自定义后端读失败不应让 App 启动即崩:当作没有 token,走重新登录。
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
if (!raw)
|
|
117
|
+
return null;
|
|
118
|
+
try {
|
|
119
|
+
return JSON.parse(raw);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// Corrupt payload: drop it rather than crashing the app on boot.
|
|
123
|
+
await this.safeRemove();
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async writeTokens(tokens) {
|
|
128
|
+
try {
|
|
129
|
+
await this.backend.set(this.key('tokens'), JSON.stringify(tokens));
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// 持久化失败不影响本次会话(内存里仍有 token),下次请求会自然重登。
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async clear() {
|
|
136
|
+
await this.safeRemove();
|
|
137
|
+
}
|
|
138
|
+
/** The backend actually in use, for diagnostics screens. */
|
|
139
|
+
get backendName() {
|
|
140
|
+
return this.backend.name;
|
|
141
|
+
}
|
|
142
|
+
async safeRemove() {
|
|
143
|
+
try {
|
|
144
|
+
await this.backend.remove(this.key('tokens'));
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
/* ignore */
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.TokenStore = TokenStore;
|
|
152
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/core/storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createFetchTransport = createFetchTransport;
|
|
4
|
+
/**
|
|
5
|
+
* 基于标准 `fetch` 的传输实现 —— 包内唯一的默认实现。
|
|
6
|
+
*
|
|
7
|
+
* 适用:Node ≥ 18、Electron 主进程、Deno/Bun、以及**同源或已配反向代理**的浏览器。
|
|
8
|
+
*
|
|
9
|
+
* ⚠️ 浏览器里直接请求 `open.snd02.com` 会被同源策略拦截:平台不返回 CORS 头。
|
|
10
|
+
* 浏览器场景请把 `baseUrl` 指向自己的代理/后端中转,或注入一个走原生网络的
|
|
11
|
+
* {@link Transport} 实现(见 README「在任何环境里使用」)。
|
|
12
|
+
*/
|
|
13
|
+
const errors_js_1 = require("./errors.js");
|
|
14
|
+
const transport_js_1 = require("./transport.js");
|
|
15
|
+
function createFetchTransport() {
|
|
16
|
+
return {
|
|
17
|
+
name: 'fetch',
|
|
18
|
+
async postForm(req) {
|
|
19
|
+
if (req.signal?.aborted) {
|
|
20
|
+
throw new errors_js_1.ElectricOpenPlatformError(errors_js_1.TransportCodes.ABORTED, '请求已取消');
|
|
21
|
+
}
|
|
22
|
+
const headers = {
|
|
23
|
+
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
24
|
+
Accept: 'application/json, text/plain, */*',
|
|
25
|
+
...req.headers,
|
|
26
|
+
};
|
|
27
|
+
const timeoutMs = req.timeoutMs ?? transport_js_1.DEFAULT_TIMEOUT_MS;
|
|
28
|
+
// AbortController 让超时行为不依赖运行时的具体实现
|
|
29
|
+
const controller = new AbortController();
|
|
30
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
31
|
+
const onAbort = () => controller.abort();
|
|
32
|
+
req.signal?.addEventListener('abort', onAbort);
|
|
33
|
+
try {
|
|
34
|
+
const res = await fetch(req.url, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers,
|
|
37
|
+
body: req.body,
|
|
38
|
+
signal: controller.signal,
|
|
39
|
+
});
|
|
40
|
+
const raw = await res.text();
|
|
41
|
+
(0, transport_js_1.assertHttpOk)(res.status, raw);
|
|
42
|
+
return { status: res.status, data: (0, transport_js_1.parseBody)(raw), raw };
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
if (err instanceof errors_js_1.ElectricOpenPlatformError)
|
|
46
|
+
throw err;
|
|
47
|
+
const aborted = err?.name === 'AbortError';
|
|
48
|
+
throw new errors_js_1.ElectricOpenPlatformError(aborted ? errors_js_1.TransportCodes.ABORTED : errors_js_1.TransportCodes.NETWORK, aborted ? '请求超时或已取消' : `网络请求失败:${err?.message ?? err}`, { cause: err });
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
req.signal?.removeEventListener('abort', onAbort);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=transport-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-fetch.js","sourceRoot":"","sources":["../../../src/core/transport-fetch.ts"],"names":[],"mappings":";;AAmBA,oDA6CC;AAhED;;;;;;;;GAQG;AACH,2CAAwE;AACxE,iDAOwB;AAExB,SAAgB,oBAAoB;IAClC,OAAO;QACL,IAAI,EAAE,OAAO;QACb,KAAK,CAAC,QAAQ,CAAC,GAAgB;YAC7B,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;gBACxB,MAAM,IAAI,qCAAyB,CAAC,0BAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACvE,CAAC;YAED,MAAM,OAAO,GAAG;gBACd,cAAc,EAAE,kDAAkD;gBAClE,MAAM,EAAE,mCAAmC;gBAC3C,GAAG,GAAG,CAAC,OAAO;aACf,CAAC;YACF,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,iCAAkB,CAAC;YAEtD,mCAAmC;YACnC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;YAC9D,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACzC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAE/C,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;oBAC/B,MAAM,EAAE,MAAM;oBACd,OAAO;oBACP,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,MAAM,EAAE,UAAU,CAAC,MAAM;iBAC1B,CAAC,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;gBAC7B,IAAA,2BAAY,EAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;gBAC9B,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAA,wBAAS,EAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC;YAC3D,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,qCAAyB;oBAAE,MAAM,GAAG,CAAC;gBACxD,MAAM,OAAO,GAAI,GAAa,EAAE,IAAI,KAAK,YAAY,CAAC;gBACtD,MAAM,IAAI,qCAAyB,CACjC,OAAO,CAAC,CAAC,CAAC,0BAAc,CAAC,OAAO,CAAC,CAAC,CAAC,0BAAc,CAAC,OAAO,EACzD,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAW,GAAa,EAAE,OAAO,IAAI,GAAG,EAAE,EACjE,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;YACJ,CAAC;oBAAS,CAAC;gBACT,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_TIMEOUT_MS = void 0;
|
|
4
|
+
exports.parseBody = parseBody;
|
|
5
|
+
exports.assertHttpOk = assertHttpOk;
|
|
6
|
+
/**
|
|
7
|
+
* Pluggable HTTP transport.
|
|
8
|
+
*
|
|
9
|
+
* 包内只提供一种实现({@link createFetchTransport},基于标准 `fetch`),
|
|
10
|
+
* 需要走原生网络栈、代理或自建网关时,实现 {@link Transport} 注入即可:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* await ElectricOpenPlatform.configure({ ...cfg, transport: myTransport });
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* 所有实现只负责「发出去、拿回来、把 HTTP 状态映射成异常」,
|
|
17
|
+
* 解析 JSON 与业务错误码由上层统一处理,保证不同传输实现的行为一致。
|
|
18
|
+
*/
|
|
19
|
+
const errors_js_1 = require("./errors.js");
|
|
20
|
+
exports.DEFAULT_TIMEOUT_MS = 20000;
|
|
21
|
+
function parseBody(raw) {
|
|
22
|
+
const trimmed = raw.trim();
|
|
23
|
+
if (trimmed === '')
|
|
24
|
+
return null;
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(trimmed);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return raw;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** 非 2xx 统一转成可识别的异常。 */
|
|
33
|
+
function assertHttpOk(status, raw) {
|
|
34
|
+
if (status < 200 || status >= 300) {
|
|
35
|
+
throw new errors_js_1.ElectricOpenPlatformError(errors_js_1.TransportCodes.HTTP, `服务器返回 HTTP ${status}`, {
|
|
36
|
+
httpStatus: status,
|
|
37
|
+
details: raw,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../src/core/transport.ts"],"names":[],"mappings":";;;AAuCA,8BAQC;AAGD,oCAOC;AAzDD;;;;;;;;;;;;GAYG;AACH,2CAAwE;AAwB3D,QAAA,kBAAkB,GAAG,KAAM,CAAC;AAEzC,SAAgB,SAAS,CAAC,GAAW;IACnC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC;AAED,wBAAwB;AACxB,SAAgB,YAAY,CAAC,MAAc,EAAE,GAAW;IACtD,IAAI,MAAM,GAAG,GAAG,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;QAClC,MAAM,IAAI,qCAAyB,CAAC,0BAAc,CAAC,IAAI,EAAE,cAAc,MAAM,EAAE,EAAE;YAC/E,UAAU,EAAE,MAAM;YAClB,OAAO,EAAE,GAAG;SACb,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/types.ts"],"names":[],"mappings":";;;AAmFa,QAAA,gBAAgB,GAAG,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.PushApi = exports.parseThirdPartyData = exports.ThirdPartyDeviceApi = exports.SceneApi = exports.StatsApi = exports.AlarmApi = exports.ControlApi = exports.ChannelApi = exports.BoxApi = exports.ProjectApi = exports.verifyPushKey = exports.RouterClient = exports.AuthManager = exports.clearDefaultStore = exports.getDefaultStore = exports.setDefaultStore = exports.memoryBackend = exports.createLocalStorageStore = exports.createMemoryStore = exports.resetStorageBackend = exports.resolveBackend = exports.TokenStore = exports.DEFAULT_BASE_URL = exports.isElectricOpenPlatformError = exports.describeCode = exports.TransportCodes = exports.PlatformCodes = exports.ElectricOpenPlatformError = exports.hasGlobalFetch = exports.detectRuntime = exports.hasExplicitTransport = exports.currentTransportName = exports.currentTransport = exports.resetTransport = exports.setTransport = exports.resolveTransport = exports.createFetchTransport = exports.parseBody = exports.postForm = exports.signRefreshSecret = exports.signAuthCodeSecret = exports.encodeForm = exports.buildSignedRequest = exports.signParams = exports.formatAlarmTime = exports.formatTimestamp = exports.md5 = exports.ElectricOpenPlatformClient = exports.ElectricOpenPlatform = void 0;
|
|
18
|
+
/**
|
|
19
|
+
* @packageDocumentation
|
|
20
|
+
* 智慧式用电数据开放平台(Mtsci Open Platform,open.snd02.com)的纯 TypeScript SDK。
|
|
21
|
+
*
|
|
22
|
+
* 零运行时依赖,Node ≥ 18 / 浏览器 / Electron / 任意前端框架通用;
|
|
23
|
+
* 需要走原生网络或自建网关时,注入一个 {@link Transport} 即可。
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { ElectricOpenPlatform } from '@wdywdy/electric-open-platform';
|
|
27
|
+
*
|
|
28
|
+
* await ElectricOpenPlatform.configure({
|
|
29
|
+
* appKey: 'O000093290',
|
|
30
|
+
* appSecret: process.env.EOP_APP_SECRET!, // keep out of source control
|
|
31
|
+
* redirectUri: 'http://yourserverurl/receive',
|
|
32
|
+
* projectCode: 'P00000104893',
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* await ElectricOpenPlatform.login('yfdq01', '…');
|
|
36
|
+
* const boxes = await ElectricOpenPlatform.box.listOnline();
|
|
37
|
+
* const [live] = await ElectricOpenPlatform.channel.realtime({ mac: boxes[0].mac });
|
|
38
|
+
* await ElectricOpenPlatform.control.switchCircuit({ mac: boxes[0].mac, action: 'close', addr: 1 });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
var client_js_1 = require("./client.js");
|
|
42
|
+
Object.defineProperty(exports, "ElectricOpenPlatform", { enumerable: true, get: function () { return client_js_1.ElectricOpenPlatform; } });
|
|
43
|
+
Object.defineProperty(exports, "ElectricOpenPlatformClient", { enumerable: true, get: function () { return client_js_1.ElectricOpenPlatformClient; } });
|
|
44
|
+
// Core building blocks — exported so host apps can sign their own calls or
|
|
45
|
+
// reuse the primitives in a backend.
|
|
46
|
+
var crypto_js_1 = require("./core/crypto.js");
|
|
47
|
+
Object.defineProperty(exports, "md5", { enumerable: true, get: function () { return crypto_js_1.md5; } });
|
|
48
|
+
Object.defineProperty(exports, "formatTimestamp", { enumerable: true, get: function () { return crypto_js_1.formatTimestamp; } });
|
|
49
|
+
Object.defineProperty(exports, "formatAlarmTime", { enumerable: true, get: function () { return crypto_js_1.formatAlarmTime; } });
|
|
50
|
+
var sign_js_1 = require("./core/sign.js");
|
|
51
|
+
Object.defineProperty(exports, "signParams", { enumerable: true, get: function () { return sign_js_1.signParams; } });
|
|
52
|
+
Object.defineProperty(exports, "buildSignedRequest", { enumerable: true, get: function () { return sign_js_1.buildSignedRequest; } });
|
|
53
|
+
Object.defineProperty(exports, "encodeForm", { enumerable: true, get: function () { return sign_js_1.encodeForm; } });
|
|
54
|
+
Object.defineProperty(exports, "signAuthCodeSecret", { enumerable: true, get: function () { return sign_js_1.signAuthCodeSecret; } });
|
|
55
|
+
Object.defineProperty(exports, "signRefreshSecret", { enumerable: true, get: function () { return sign_js_1.signRefreshSecret; } });
|
|
56
|
+
var http_js_1 = require("./core/http.js");
|
|
57
|
+
Object.defineProperty(exports, "postForm", { enumerable: true, get: function () { return http_js_1.postForm; } });
|
|
58
|
+
Object.defineProperty(exports, "parseBody", { enumerable: true, get: function () { return http_js_1.parseBody; } });
|
|
59
|
+
// 传输层:使用方可以显式指定实现(config.transport / setTransport),
|
|
60
|
+
// 未指定时一律用内置 fetch —— 不做宿主探测。
|
|
61
|
+
Object.defineProperty(exports, "createFetchTransport", { enumerable: true, get: function () { return http_js_1.createFetchTransport; } });
|
|
62
|
+
Object.defineProperty(exports, "resolveTransport", { enumerable: true, get: function () { return http_js_1.resolveTransport; } });
|
|
63
|
+
Object.defineProperty(exports, "setTransport", { enumerable: true, get: function () { return http_js_1.setTransport; } });
|
|
64
|
+
Object.defineProperty(exports, "resetTransport", { enumerable: true, get: function () { return http_js_1.resetTransport; } });
|
|
65
|
+
Object.defineProperty(exports, "currentTransport", { enumerable: true, get: function () { return http_js_1.currentTransport; } });
|
|
66
|
+
Object.defineProperty(exports, "currentTransportName", { enumerable: true, get: function () { return http_js_1.currentTransportName; } });
|
|
67
|
+
Object.defineProperty(exports, "hasExplicitTransport", { enumerable: true, get: function () { return http_js_1.hasExplicitTransport; } });
|
|
68
|
+
var runtime_js_1 = require("./core/runtime.js");
|
|
69
|
+
Object.defineProperty(exports, "detectRuntime", { enumerable: true, get: function () { return runtime_js_1.detectRuntime; } });
|
|
70
|
+
Object.defineProperty(exports, "hasGlobalFetch", { enumerable: true, get: function () { return runtime_js_1.hasGlobalFetch; } });
|
|
71
|
+
var errors_js_1 = require("./core/errors.js");
|
|
72
|
+
Object.defineProperty(exports, "ElectricOpenPlatformError", { enumerable: true, get: function () { return errors_js_1.ElectricOpenPlatformError; } });
|
|
73
|
+
Object.defineProperty(exports, "PlatformCodes", { enumerable: true, get: function () { return errors_js_1.PlatformCodes; } });
|
|
74
|
+
Object.defineProperty(exports, "TransportCodes", { enumerable: true, get: function () { return errors_js_1.TransportCodes; } });
|
|
75
|
+
Object.defineProperty(exports, "describeCode", { enumerable: true, get: function () { return errors_js_1.describeCode; } });
|
|
76
|
+
Object.defineProperty(exports, "isElectricOpenPlatformError", { enumerable: true, get: function () { return errors_js_1.isElectricOpenPlatformError; } });
|
|
77
|
+
var types_js_1 = require("./core/types.js");
|
|
78
|
+
Object.defineProperty(exports, "DEFAULT_BASE_URL", { enumerable: true, get: function () { return types_js_1.DEFAULT_BASE_URL; } });
|
|
79
|
+
var storage_js_1 = require("./core/storage.js");
|
|
80
|
+
Object.defineProperty(exports, "TokenStore", { enumerable: true, get: function () { return storage_js_1.TokenStore; } });
|
|
81
|
+
Object.defineProperty(exports, "resolveBackend", { enumerable: true, get: function () { return storage_js_1.resolveBackend; } });
|
|
82
|
+
Object.defineProperty(exports, "resetStorageBackend", { enumerable: true, get: function () { return storage_js_1.resetStorageBackend; } });
|
|
83
|
+
Object.defineProperty(exports, "createMemoryStore", { enumerable: true, get: function () { return storage_js_1.createMemoryStore; } });
|
|
84
|
+
Object.defineProperty(exports, "createLocalStorageStore", { enumerable: true, get: function () { return storage_js_1.createLocalStorageStore; } });
|
|
85
|
+
Object.defineProperty(exports, "memoryBackend", { enumerable: true, get: function () { return storage_js_1.memoryBackend; } });
|
|
86
|
+
// 宿主应用在 bootstrap 阶段注入全局默认存储(与 setTransport 对称),
|
|
87
|
+
// 这样共享页面/组件无需引用任何平台 SDK。
|
|
88
|
+
Object.defineProperty(exports, "setDefaultStore", { enumerable: true, get: function () { return storage_js_1.setDefaultStore; } });
|
|
89
|
+
Object.defineProperty(exports, "getDefaultStore", { enumerable: true, get: function () { return storage_js_1.getDefaultStore; } });
|
|
90
|
+
Object.defineProperty(exports, "clearDefaultStore", { enumerable: true, get: function () { return storage_js_1.clearDefaultStore; } });
|
|
91
|
+
var auth_js_1 = require("./core/auth.js");
|
|
92
|
+
Object.defineProperty(exports, "AuthManager", { enumerable: true, get: function () { return auth_js_1.AuthManager; } });
|
|
93
|
+
var router_js_1 = require("./core/router.js");
|
|
94
|
+
Object.defineProperty(exports, "RouterClient", { enumerable: true, get: function () { return router_js_1.RouterClient; } });
|
|
95
|
+
var push_js_1 = require("./core/push.js");
|
|
96
|
+
Object.defineProperty(exports, "verifyPushKey", { enumerable: true, get: function () { return push_js_1.verifyPushKey; } });
|
|
97
|
+
// Domain APIs (for typing custom wrappers) and every wire model / enum.
|
|
98
|
+
var api_js_1 = require("./core/api.js");
|
|
99
|
+
Object.defineProperty(exports, "ProjectApi", { enumerable: true, get: function () { return api_js_1.ProjectApi; } });
|
|
100
|
+
Object.defineProperty(exports, "BoxApi", { enumerable: true, get: function () { return api_js_1.BoxApi; } });
|
|
101
|
+
Object.defineProperty(exports, "ChannelApi", { enumerable: true, get: function () { return api_js_1.ChannelApi; } });
|
|
102
|
+
Object.defineProperty(exports, "ControlApi", { enumerable: true, get: function () { return api_js_1.ControlApi; } });
|
|
103
|
+
Object.defineProperty(exports, "AlarmApi", { enumerable: true, get: function () { return api_js_1.AlarmApi; } });
|
|
104
|
+
Object.defineProperty(exports, "StatsApi", { enumerable: true, get: function () { return api_js_1.StatsApi; } });
|
|
105
|
+
Object.defineProperty(exports, "SceneApi", { enumerable: true, get: function () { return api_js_1.SceneApi; } });
|
|
106
|
+
Object.defineProperty(exports, "ThirdPartyDeviceApi", { enumerable: true, get: function () { return api_js_1.ThirdPartyDeviceApi; } });
|
|
107
|
+
Object.defineProperty(exports, "parseThirdPartyData", { enumerable: true, get: function () { return api_js_1.parseThirdPartyData; } });
|
|
108
|
+
var push_js_2 = require("./core/push.js");
|
|
109
|
+
Object.defineProperty(exports, "PushApi", { enumerable: true, get: function () { return push_js_2.PushApi; } });
|
|
110
|
+
__exportStar(require("./core/models.js"), exports);
|
|
111
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,yCAA+E;AAAtE,iHAAA,oBAAoB,OAAA;AAAE,uHAAA,0BAA0B,OAAA;AAEzD,2EAA2E;AAC3E,qCAAqC;AACrC,8CAAyE;AAAhE,gGAAA,GAAG,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,4GAAA,eAAe,OAAA;AAC9C,0CAOwB;AANtB,qGAAA,UAAU,OAAA;AACV,6GAAA,kBAAkB,OAAA;AAClB,qGAAA,UAAU,OAAA;AACV,6GAAA,kBAAkB,OAAA;AAClB,4GAAA,iBAAiB,OAAA;AAGnB,0CAewB;AAdtB,mGAAA,QAAQ,OAAA;AACR,oGAAA,SAAS,OAAA;AACT,oDAAoD;AACpD,6BAA6B;AAC7B,+GAAA,oBAAoB,OAAA;AACpB,2GAAA,gBAAgB,OAAA;AAChB,uGAAA,YAAY,OAAA;AACZ,yGAAA,cAAc,OAAA;AACd,2GAAA,gBAAgB,OAAA;AAChB,+GAAA,oBAAoB,OAAA;AACpB,+GAAA,oBAAoB,OAAA;AAKtB,gDAAgF;AAAvE,2GAAA,aAAa,OAAA;AAAE,4GAAA,cAAc,OAAA;AACtC,8CAQ0B;AAPxB,sHAAA,yBAAyB,OAAA;AACzB,0GAAA,aAAa,OAAA;AACb,2GAAA,cAAc,OAAA;AACd,yGAAA,YAAY,OAAA;AACZ,wHAAA,2BAA2B,OAAA;AAI7B,4CASyB;AARvB,4GAAA,gBAAgB,OAAA;AASlB,gDAa2B;AAZzB,wGAAA,UAAU,OAAA;AACV,4GAAA,cAAc,OAAA;AACd,iHAAA,mBAAmB,OAAA;AACnB,+GAAA,iBAAiB,OAAA;AACjB,qHAAA,uBAAuB,OAAA;AACvB,2GAAA,aAAa,OAAA;AACb,iDAAiD;AACjD,yBAAyB;AACzB,6GAAA,eAAe,OAAA;AACf,6GAAA,eAAe,OAAA;AACf,+GAAA,iBAAiB,OAAA;AAGnB,0CAA6C;AAApC,sGAAA,WAAW,OAAA;AACpB,8CAAkE;AAAzD,yGAAA,YAAY,OAAA;AACrB,0CAA6D;AAApD,wGAAA,aAAa,OAAA;AAEtB,wEAAwE;AACxE,wCAUuB;AATrB,oGAAA,UAAU,OAAA;AACV,gGAAA,MAAM,OAAA;AACN,oGAAA,UAAU,OAAA;AACV,oGAAA,UAAU,OAAA;AACV,kGAAA,QAAQ,OAAA;AACR,kGAAA,QAAQ,OAAA;AACR,kGAAA,QAAQ,OAAA;AACR,6GAAA,mBAAmB,OAAA;AACnB,6GAAA,mBAAmB,OAAA;AAErB,0CAAyC;AAAhC,kGAAA,OAAO,OAAA;AAChB,mDAAiC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SDK facade.
|
|
3
|
+
*
|
|
4
|
+
* Everything is composed here so the public surface stays a single object:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { ElectricOpenPlatform } from '@wdywdy/electric-open-platform';
|
|
8
|
+
*
|
|
9
|
+
* await ElectricOpenPlatform.configure({ appKey, appSecret, redirectUri, projectCode });
|
|
10
|
+
* await ElectricOpenPlatform.login('yfdq01', '******');
|
|
11
|
+
* const boxes = await ElectricOpenPlatform.box.list();
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
import { AlarmApi, BoxApi, ChannelApi, ControlApi, ProjectApi, SceneApi, StatsApi, ThirdPartyDeviceApi } from './core/api.js';
|
|
15
|
+
import { PushApi } from './core/push.js';
|
|
16
|
+
import { ElectricConfig, LoginResult, TokenSet } from './core/types.js';
|
|
17
|
+
export declare class ElectricOpenPlatformClient {
|
|
18
|
+
private auth?;
|
|
19
|
+
private router?;
|
|
20
|
+
private config?;
|
|
21
|
+
private backend?;
|
|
22
|
+
/** Domain API groups — populated by {@link configure}. */
|
|
23
|
+
project: ProjectApi;
|
|
24
|
+
box: BoxApi;
|
|
25
|
+
channel: ChannelApi;
|
|
26
|
+
control: ControlApi;
|
|
27
|
+
alarm: AlarmApi;
|
|
28
|
+
stats: StatsApi;
|
|
29
|
+
scene: SceneApi;
|
|
30
|
+
push: PushApi;
|
|
31
|
+
/** 第三方设备(烟感/燃气/水表/温湿度…),即 equipmentType ≠ 1/2 */
|
|
32
|
+
thirdparty: ThirdPartyDeviceApi;
|
|
33
|
+
private credentials;
|
|
34
|
+
/**
|
|
35
|
+
* Configures the SDK. Safe to call again (e.g. after the user switches
|
|
36
|
+
* project) — previous timers are released and tokens for the old `appKey` are
|
|
37
|
+
* left untouched on disk.
|
|
38
|
+
*/
|
|
39
|
+
configure(config: ElectricConfig): Promise<void>;
|
|
40
|
+
/** True once `configure()` succeeded. */
|
|
41
|
+
get isConfigured(): boolean;
|
|
42
|
+
/** Where tokens are persisted — useful on a diagnostics screen. */
|
|
43
|
+
storageBackend(): Promise<string>;
|
|
44
|
+
/** Headless login with the platform account (POST /oauth/authverify2.as). */
|
|
45
|
+
login(username: string, password: string): Promise<LoginResult>;
|
|
46
|
+
/** Redirect-flow: the URL to open in a browser for the platform's login page. */
|
|
47
|
+
getAuthorizeUrl(options?: {
|
|
48
|
+
state?: string;
|
|
49
|
+
}): string;
|
|
50
|
+
/**
|
|
51
|
+
* Redirect-flow step 2: pass the full redirect URL (or the bare code) received
|
|
52
|
+
* by your `redirectUri` endpoint.
|
|
53
|
+
*/
|
|
54
|
+
handleRedirect(urlOrCode: string): Promise<TokenSet>;
|
|
55
|
+
/** Renews the token now instead of waiting for the timer. */
|
|
56
|
+
refreshToken(): Promise<TokenSet>;
|
|
57
|
+
get currentToken(): TokenSet | null;
|
|
58
|
+
logout(): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Escape hatch for platform methods that are not (yet) wrapped, e.g. new
|
|
61
|
+
* `GET_*` endpoints added after this release. Signs, retries and unwraps for
|
|
62
|
+
* you, so prefer it over hand-rolling `fetch`.
|
|
63
|
+
*/
|
|
64
|
+
invoke<T = unknown>(method: string, params?: Record<string, string | number | boolean | null | undefined>): Promise<T>;
|
|
65
|
+
/** Current configuration with the secret masked. */
|
|
66
|
+
describe(): Record<string, unknown>;
|
|
67
|
+
/** Releases timers; call from `ngOnDestroy` / `useEffect` cleanup. */
|
|
68
|
+
dispose(): void;
|
|
69
|
+
private requireAuth;
|
|
70
|
+
private requireRouter;
|
|
71
|
+
}
|
|
72
|
+
/** Default singleton instance. Also exported as the named `ElectricOpenPlatform`. */
|
|
73
|
+
export declare const ElectricOpenPlatform: ElectricOpenPlatformClient;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SDK facade.
|
|
3
|
+
*
|
|
4
|
+
* Everything is composed here so the public surface stays a single object:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { ElectricOpenPlatform } from '@wdywdy/electric-open-platform';
|
|
8
|
+
*
|
|
9
|
+
* await ElectricOpenPlatform.configure({ appKey, appSecret, redirectUri, projectCode });
|
|
10
|
+
* await ElectricOpenPlatform.login('yfdq01', '******');
|
|
11
|
+
* const boxes = await ElectricOpenPlatform.box.list();
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
import { AlarmApi, BoxApi, ChannelApi, ControlApi, ProjectApi, SceneApi, StatsApi, ThirdPartyDeviceApi, } from './core/api.js';
|
|
15
|
+
import { AuthManager } from './core/auth.js';
|
|
16
|
+
import { currentTransport, currentTransportName, hasExplicitTransport, resolveTransport, setTransport, } from './core/http.js';
|
|
17
|
+
import { PushApi } from './core/push.js';
|
|
18
|
+
import { detectRuntime } from './core/runtime.js';
|
|
19
|
+
import { RouterClient } from './core/router.js';
|
|
20
|
+
import { resolveBackend, TokenStore } from './core/storage.js';
|
|
21
|
+
export class ElectricOpenPlatformClient {
|
|
22
|
+
constructor() {
|
|
23
|
+
this.credentials = {};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Configures the SDK. Safe to call again (e.g. after the user switches
|
|
27
|
+
* project) — previous timers are released and tokens for the old `appKey` are
|
|
28
|
+
* left untouched on disk.
|
|
29
|
+
*/
|
|
30
|
+
async configure(config) {
|
|
31
|
+
assertConfig(config);
|
|
32
|
+
this.dispose();
|
|
33
|
+
this.config = config;
|
|
34
|
+
this.credentials = { username: config.username, password: config.password };
|
|
35
|
+
// 存储:config.store(自定义后端,最高)> config.storage 指定的内置后端
|
|
36
|
+
const backend = await resolveBackend(config.storage ?? 'auto', config.store);
|
|
37
|
+
this.backend = backend;
|
|
38
|
+
const store = new TokenStore(backend, config.appKey);
|
|
39
|
+
const auth = new AuthManager(store, config);
|
|
40
|
+
const router = new RouterClient(config, auth, () => this.credentials);
|
|
41
|
+
// 传输:config.transport(最高)> 调用方 setTransport 注入的实现 > 内置 fetch
|
|
42
|
+
setTransport(resolveTransport(config.transport, hasExplicitTransport() ? currentTransport() : undefined));
|
|
43
|
+
this.auth = auth;
|
|
44
|
+
this.router = router;
|
|
45
|
+
this.project = new ProjectApi(router);
|
|
46
|
+
this.box = new BoxApi(router);
|
|
47
|
+
this.channel = new ChannelApi(router);
|
|
48
|
+
this.control = new ControlApi(router);
|
|
49
|
+
this.alarm = new AlarmApi(router);
|
|
50
|
+
this.stats = new StatsApi(router);
|
|
51
|
+
this.scene = new SceneApi(router);
|
|
52
|
+
this.push = new PushApi(router);
|
|
53
|
+
this.thirdparty = new ThirdPartyDeviceApi(router);
|
|
54
|
+
await auth.restore();
|
|
55
|
+
}
|
|
56
|
+
/** True once `configure()` succeeded. */
|
|
57
|
+
get isConfigured() {
|
|
58
|
+
return !!this.router;
|
|
59
|
+
}
|
|
60
|
+
/** Where tokens are persisted — useful on a diagnostics screen. */
|
|
61
|
+
async storageBackend() {
|
|
62
|
+
return this.backend?.name ?? 'none';
|
|
63
|
+
}
|
|
64
|
+
// --------------------------------------------------------------------- auth
|
|
65
|
+
/** Headless login with the platform account (POST /oauth/authverify2.as). */
|
|
66
|
+
async login(username, password) {
|
|
67
|
+
const auth = this.requireAuth();
|
|
68
|
+
this.credentials = { username, password };
|
|
69
|
+
const code = await auth.fetchCode({ username, password });
|
|
70
|
+
const tokens = await auth.exchangeCode(code);
|
|
71
|
+
return { success: true, code, expiresIn: secondsUntil(tokens.expiresAt), expiresAt: tokens.expiresAt };
|
|
72
|
+
}
|
|
73
|
+
/** Redirect-flow: the URL to open in a browser for the platform's login page. */
|
|
74
|
+
getAuthorizeUrl(options = {}) {
|
|
75
|
+
return this.requireAuth().getAuthorizeUrl(options);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Redirect-flow step 2: pass the full redirect URL (or the bare code) received
|
|
79
|
+
* by your `redirectUri` endpoint.
|
|
80
|
+
*/
|
|
81
|
+
async handleRedirect(urlOrCode) {
|
|
82
|
+
const auth = this.requireAuth();
|
|
83
|
+
const code = AuthManager.extractCode(urlOrCode) ?? urlOrCode;
|
|
84
|
+
return auth.exchangeCode(code);
|
|
85
|
+
}
|
|
86
|
+
/** Renews the token now instead of waiting for the timer. */
|
|
87
|
+
async refreshToken() {
|
|
88
|
+
return this.requireAuth().refresh();
|
|
89
|
+
}
|
|
90
|
+
get currentToken() {
|
|
91
|
+
return this.auth?.current ?? null;
|
|
92
|
+
}
|
|
93
|
+
async logout() {
|
|
94
|
+
this.credentials = {};
|
|
95
|
+
this.config = this.config ? { ...this.config, username: undefined, password: undefined } : this.config;
|
|
96
|
+
await this.auth?.logout();
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Escape hatch for platform methods that are not (yet) wrapped, e.g. new
|
|
100
|
+
* `GET_*` endpoints added after this release. Signs, retries and unwraps for
|
|
101
|
+
* you, so prefer it over hand-rolling `fetch`.
|
|
102
|
+
*/
|
|
103
|
+
async invoke(method, params = {}) {
|
|
104
|
+
return this.requireRouter().call(method, { params });
|
|
105
|
+
}
|
|
106
|
+
/** Current configuration with the secret masked. */
|
|
107
|
+
describe() {
|
|
108
|
+
const c = this.config;
|
|
109
|
+
if (!c)
|
|
110
|
+
return { configured: false };
|
|
111
|
+
return {
|
|
112
|
+
configured: true,
|
|
113
|
+
appKey: c.appKey,
|
|
114
|
+
appSecret: c.appSecret ? `****${c.appSecret.slice(-4)}` : '',
|
|
115
|
+
redirectUri: c.redirectUri,
|
|
116
|
+
baseUrl: c.baseUrl ?? 'https://open.snd02.com',
|
|
117
|
+
projectCode: c.projectCode,
|
|
118
|
+
storage: c.storage ?? 'auto',
|
|
119
|
+
/** 实际生效的存储后端名(内置 memory/localStorage,或自定义 store 的 name) */
|
|
120
|
+
storageBackend: this.backend?.name ?? 'none',
|
|
121
|
+
/** 运行宿主:node / browser / unknown(仅诊断用,不参与能力选择) */
|
|
122
|
+
runtime: detectRuntime(),
|
|
123
|
+
/** 实际生效的网络传输实现 */
|
|
124
|
+
transport: currentTransportName(),
|
|
125
|
+
token: this.auth?.current
|
|
126
|
+
? { ...this.auth.current, accessToken: mask(this.auth.current.accessToken) }
|
|
127
|
+
: null,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** Releases timers; call from `ngOnDestroy` / `useEffect` cleanup. */
|
|
131
|
+
dispose() {
|
|
132
|
+
this.auth?.dispose();
|
|
133
|
+
this.auth = undefined;
|
|
134
|
+
this.router = undefined;
|
|
135
|
+
}
|
|
136
|
+
requireAuth() {
|
|
137
|
+
if (!this.auth)
|
|
138
|
+
throw new Error('SDK 尚未初始化,请先调用 configure({ appKey, appSecret, redirectUri })');
|
|
139
|
+
return this.auth;
|
|
140
|
+
}
|
|
141
|
+
requireRouter() {
|
|
142
|
+
if (!this.router)
|
|
143
|
+
throw new Error('SDK 尚未初始化,请先调用 configure()');
|
|
144
|
+
return this.router;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function assertConfig(config) {
|
|
148
|
+
const missing = [];
|
|
149
|
+
if (!config.appKey)
|
|
150
|
+
missing.push('appKey');
|
|
151
|
+
if (!config.appSecret)
|
|
152
|
+
missing.push('appSecret');
|
|
153
|
+
if (!config.redirectUri)
|
|
154
|
+
missing.push('redirectUri');
|
|
155
|
+
if (missing.length)
|
|
156
|
+
throw new Error(`缺少必填配置:${missing.join(', ')}`);
|
|
157
|
+
if (config.redirectUri && !/^https?:\/\//i.test(config.redirectUri)) {
|
|
158
|
+
throw new Error('redirectUri 必须是 http(s) 绝对地址(会参与签名,需与平台登记一致)');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function secondsUntil(epochMs) {
|
|
162
|
+
return Math.max(0, Math.round((epochMs - Date.now()) / 1000));
|
|
163
|
+
}
|
|
164
|
+
function mask(token) {
|
|
165
|
+
return token.length <= 8 ? '****' : `${token.slice(0, 6)}…${token.slice(-4)}`;
|
|
166
|
+
}
|
|
167
|
+
/** Default singleton instance. Also exported as the named `ElectricOpenPlatform`. */
|
|
168
|
+
export const ElectricOpenPlatform = new ElectricOpenPlatformClient();
|
|
169
|
+
//# sourceMappingURL=client.js.map
|