@vector-metis/browser-sdk 0.1.2 → 0.2.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 ADDED
@@ -0,0 +1,32 @@
1
+ # @vector-metis/browser-sdk
2
+
3
+ 智办应用浏览器 SDK,为平台注入的 `window.Metis` 能力提供 TypeScript 类型和统一调用代理。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install @vector-metis/browser-sdk
9
+ ```
10
+
11
+ ```ts
12
+ import { init } from "@vector-metis/browser-sdk";
13
+
14
+ const Metis = await init();
15
+ const dependencies = await Metis.listDependencies();
16
+ ```
17
+
18
+ `init()` 会自动加载当前平台的 `/api/runtime/v1/browser-sdk.js`,并在脚本完成且能力校验通过后返回 SDK。重复调用会复用已经加载的 `window.Metis`。本地开发或严格 CSP 场景可以覆盖脚本地址、nonce 和超时时间:
19
+
20
+ ```ts
21
+ const Metis = await init({
22
+ scriptUrl: "/api/runtime/v1/browser-sdk.js",
23
+ nonce: document.querySelector("meta[name=csp-nonce]")?.content,
24
+ timeoutMs: 10000,
25
+ });
26
+ ```
27
+
28
+ 请在浏览器应用启动阶段调用 `init()`;服务端渲染、Node.js 和构建阶段不提供浏览器环境。
29
+
30
+ 浏览器 SDK 不暴露应用令牌、模型 API key、对象存储凭据或 Service 端口。完整说明见[开发文档](https://github.com/vector-metis/metis-sdk-typescript#readme)。
31
+
32
+ Apache-2.0,见仓库中的 `LICENSE`。
package/dist/index.d.ts CHANGED
@@ -34,10 +34,16 @@ declare global {
34
34
  Metis?: InjectedBrowserSDK;
35
35
  }
36
36
  }
37
- /** 返回平台已经注入的浏览器能力;脚本缺失时明确失败。 */
38
- export declare function injected(): InjectedBrowserSDK;
39
- /** 对平台注入能力做延迟解析的类型化代理。 */
40
- export declare const Metis: InjectedBrowserSDK;
37
+ export type BrowserSDKInitOptions = {
38
+ /** Same-origin by default; override for local development or a platform proxy. */
39
+ scriptUrl?: string;
40
+ /** Optional CSP nonce for the dynamically-created script element. */
41
+ nonce?: string;
42
+ /** Milliseconds to wait for the platform script before rejecting. */
43
+ timeoutMs?: number;
44
+ };
45
+ /** Load the platform-injected browser capabilities and return a ready SDK. */
46
+ export declare function init(options?: BrowserSDKInitOptions): Promise<InjectedBrowserSDK>;
41
47
  export type MetisBrowserContext = BrowserContext;
42
48
  export type MetisBrowserSDK = InjectedBrowserSDK;
43
49
  export type MetisWebDependency = WebDependency;
package/dist/index.js CHANGED
@@ -1,17 +1,77 @@
1
- /** 返回平台已经注入的浏览器能力;脚本缺失时明确失败。 */
2
- export function injected() {
3
- const sdk = globalThis.window?.Metis;
4
- if (!sdk) {
5
- throw new Error("Metis browser SDK is not injected; load /api/runtime/v1/browser-sdk.js first");
1
+ let initialization;
2
+ function validateSDK(value) {
3
+ if (!value || typeof value !== "object") {
4
+ throw new Error("Metis browser SDK loaded without a valid window.Metis object");
5
+ }
6
+ const sdk = value;
7
+ const methods = [
8
+ "appURL",
9
+ "getContext",
10
+ "listDependencies",
11
+ "dependency",
12
+ "dependencyURL",
13
+ "openAppPage",
14
+ ];
15
+ if (methods.some((method) => typeof sdk[method] !== "function")) {
16
+ throw new Error("Metis browser SDK loaded without the required platform methods");
6
17
  }
7
18
  return sdk;
8
19
  }
9
- /** 对平台注入能力做延迟解析的类型化代理。 */
10
- export const Metis = Object.freeze({
11
- appURL: (path) => injected().appURL(path),
12
- getContext: () => injected().getContext(),
13
- listDependencies: () => injected().listDependencies(),
14
- dependency: (selector) => injected().dependency(selector),
15
- dependencyURL: (selector, path) => injected().dependencyURL(selector, path),
16
- openAppPage: (options) => injected().openAppPage(options),
17
- });
20
+ /** Load the platform-injected browser capabilities and return a ready SDK. */
21
+ export function init(options = {}) {
22
+ if (initialization) {
23
+ return initialization;
24
+ }
25
+ const browserWindow = globalThis.window;
26
+ const document = globalThis.document;
27
+ if (!browserWindow) {
28
+ return Promise.reject(new Error("Metis browser SDK requires a browser environment"));
29
+ }
30
+ if (browserWindow.Metis) {
31
+ return Promise.resolve(validateSDK(browserWindow.Metis));
32
+ }
33
+ if (!document) {
34
+ return Promise.reject(new Error("Metis browser SDK requires a browser document"));
35
+ }
36
+ const timeoutMs = options.timeoutMs ?? 10000;
37
+ const script = document.createElement("script");
38
+ let timer;
39
+ let resolveInitialization;
40
+ let rejectInitialization;
41
+ initialization = new Promise((resolve, reject) => {
42
+ resolveInitialization = resolve;
43
+ rejectInitialization = reject;
44
+ });
45
+ const pending = initialization;
46
+ const fail = (error) => {
47
+ if (timer)
48
+ clearTimeout(timer);
49
+ initialization = undefined;
50
+ rejectInitialization(error);
51
+ };
52
+ script.src = options.scriptUrl ?? "/api/runtime/v1/browser-sdk.js";
53
+ script.async = true;
54
+ if (options.nonce)
55
+ script.nonce = options.nonce;
56
+ script.onload = () => {
57
+ try {
58
+ if (timer)
59
+ clearTimeout(timer);
60
+ const sdk = validateSDK(browserWindow.Metis);
61
+ initialization = undefined;
62
+ resolveInitialization(sdk);
63
+ }
64
+ catch (error) {
65
+ fail(error instanceof Error ? error : new Error(String(error)));
66
+ }
67
+ };
68
+ script.onerror = () => fail(new Error(`Failed to load Metis browser SDK: ${script.src}`));
69
+ timer = setTimeout(() => fail(new Error(`Metis browser SDK load timed out after ${timeoutMs}ms`)), timeoutMs);
70
+ try {
71
+ document.head.appendChild(script);
72
+ }
73
+ catch (error) {
74
+ fail(error instanceof Error ? error : new Error(String(error)));
75
+ }
76
+ return pending;
77
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vector-metis/browser-sdk",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Metis browser SDK for injected application capabilities",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,7 +16,8 @@
16
16
  }
17
17
  },
18
18
  "files": [
19
- "dist"
19
+ "dist",
20
+ "README.md"
20
21
  ],
21
22
  "engines": {
22
23
  "node": ">=20"