@obm/apaas-embed-sdk 0.1.0 → 0.1.2

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 CHANGED
@@ -1,19 +1,19 @@
1
1
  # MediPaaS Embed SDK
2
2
 
3
- 在第三方网页中通过 iframe 打开 MediPaaS 应用页面。SDK 负责嵌入与实例管理;第三方后端负责获取 embed token。
4
-
5
- ## 安装
6
-
7
- 发布到 npm 后,可在第三方项目中安装:
8
-
9
- ```bash
10
- npm install @obm/apaas-embed-sdk
11
- ```
12
-
13
- 当前为 `0.1.0` 初期 MVP 版本,API 仍可能调整。支持 ESM、CommonJS 与 TypeScript 类型声明。iframe 嵌入需要浏览器 DOM 环境。
3
+ 在第三方网页中通过 iframe 打开 MediPaaS 应用页面。SDK 负责嵌入与实例管理;第三方后端负责获取 embed token。
4
+
5
+ ## 安装
6
+
7
+ 发布到 npm 后,可在第三方项目中安装:
8
+
9
+ ```bash
10
+ npm install @obm/apaas-embed-sdk
11
+ ```
12
+
13
+ 当前为 `0.1.0` 初期 MVP 版本,API 仍可能调整。支持 ESM、CommonJS 与 TypeScript 类型声明。iframe 嵌入需要浏览器 DOM 环境。
14
14
 
15
15
  ```ts
16
- import { ApassEmbedSDK, type EmbedParamValue } from '@obm/apaas-embed-sdk'
16
+ import { ApassEmbedSDK, type EmbedParamValue } from '@obm/apaas-embed-sdk'
17
17
 
18
18
  // getToken 是第三方系统自己的接口。后端调用
19
19
  // POST /api/auth/token/embed?clientId=xxx,返回 token 和 runtimeAppId。
@@ -26,6 +26,9 @@ const instance = await sdk.embed({
26
26
  appId: String(runtimeAppId), apiName: 'order_detail', token,
27
27
  containerId: 'medipaas-container', params,
28
28
  onError: error => console.error(error),
29
+ onEvent: ({ name, payload }) => {
30
+ if (name === 'order.saved') refreshOrder((payload as { orderId: string }).orderId)
31
+ },
29
32
  })
30
33
  // 需要关闭时:instance.close()
31
34
  ```
@@ -80,8 +83,10 @@ Content-Type: application/json
80
83
  | `fullscreen` | 默认 false,仅控制默认弹窗尺寸 |
81
84
  | `iframeAttrs` | iframe 属性字典,如 title、allow、sandbox;禁止 src/srcdoc(大小写均禁止) |
82
85
  | `onReady` | iframe load 回调,不表示首次数据查询完成 |
86
+ | `onBridgeReady` | 消息桥握手完成回调;此后可调用实例 `send()` |
83
87
  | `onClose` | 实例 close() 回调;closeAll()、遮罩点击不会触发 |
84
88
  | `onError` | 参数、容器或 iframe 错误回调;参数错误同时拒绝 embed Promise |
89
+ | `onEvent` | 嵌入页业务事件回调,参数为 `{ name, payload }` |
85
90
 
86
91
  `params` 的值允许字符串、有限数字、布尔值、null、undefined。字符串通过 URLSearchParams 编码,调用方传原始值,不预先编码。数字与布尔转为字符串;0、false、空字符串保留;null/undefined 属性忽略。对象、数组、函数、NaN、Infinity 均拒绝;params 本身不能为 null。
87
92
 
@@ -89,9 +94,28 @@ Content-Type: application/json
89
94
 
90
95
  页面通过 `{{ urlParams.value.orderId }}` 读取。所有 SDK 参数在页面中均为字符串,布尔判断使用 `{{ urlParams.value.editable === 'true' }}`,ID 建议传字符串以保留前导零和大整数精度。URL 显式值优先于页面参数默认值,显式空字符串不会被默认值覆盖。目标页面需将参数绑定到数据源查询条件或初始化动作。
91
96
 
92
- 参数属于当前 iframe 地址,刷新可恢复,各实例互不共享;页间导航需显式传参。切换记录请重新 embed,暂不支持 updateParams 或业务 postMessage 通信。URL 中的业务参数不能赋予权限,服务端仍验证 token 与记录权限;不要通过 URL 传敏感内容或大量数据。
97
+ 参数属于当前 iframe 地址,刷新可恢复,各实例互不共享;页间导航需显式传参。切换记录可重新 embed,或在握手完成后调用 `instance.send('params.update', { orderId: '000124' })` 更新目标页面已声明的 URL 参数;返回 `false` 表示通道尚未就绪。`instance.send('page.refresh')` 可重新加载当前页面。URL 中的业务参数不能赋予权限,服务端仍验证 token 与记录权限;不要通过 URL 传敏感内容或大量数据。
98
+
99
+ ## 双向消息
100
+
101
+ 页面在按钮点击或数据请求成功时调用 JS 方法,通过原生 postMessage 发送业务事件;第三方通过 `embed({ onEvent })` 接收 `{ name, payload }`:
102
+
103
+ ```js
104
+ window.parent.postMessage({
105
+ name: 'order.saved',
106
+ payload: { orderId: '000123' },
107
+ }, 'https://your-host-domain.com') // 第三方宿主的 origin(协议、域名、端口)
108
+ ```
109
+
110
+ 业务消息无需 namespace、version、channelId、type,也无需等待握手。SDK 只接收当前 iframe、配置 baseUrl 同源的消息,以及非空字符串 name;回调传入 `{ name, payload }`。旧的 `type: 'event'` 消息仍可接收,握手控制消息不会触发 onEvent。接收端保留 source 和 origin 校验;不要在事件载荷中传 token 或敏感业务数据。
111
+
112
+ 设计器已移除“通知第三方宿主”专用动作及执行逻辑。已有页面的 notifyHost 动作需手动改为调用 JS 方法,并保存、发布对应应用;本次不批量修改已保存的业务页面。
113
+
114
+ 宿主向页面发送 `page.refresh`、`params.update` 的握手与指令仍使用内部 `medipaas.embed` v1 协议,业务脚本无需处理这些字段。
115
+
116
+ `onReady` 仍只表示 iframe `load`,不表示业务数据完成或消息桥就绪。`onBridgeReady` 表示可以调用实例 `send()`;提前调用会返回 `false`。`onEvent` 接收不依赖这两个回调。页面内保存成功通知应通过数据请求成功事件调用 JS 方法。消息仅送达当前打开的 iframe,不提供离线投递。
93
117
 
94
- 实例返回 iframe、token、expiresAt(当前固定 0)和 close()。SDK 还提供 closeAll() 与 getInstanceCount()。现有默认弹窗关闭行为尚未完整清理遮罩,建议第三方使用指定容器。
118
+ 实例返回 iframe、token、expiresAt(当前固定 0)、send() 和 close()。SDK 还提供 closeAll() 与 getInstanceCount()。
95
119
 
96
120
  ## 构建与示例
97
121
 
@@ -101,23 +125,29 @@ Content-Type: application/json
101
125
  - [文档索引](docs/README.md)
102
126
  - [原生 HTML 示例](examples/basic-html/index.html):构建后以 HTTP 静态服务打开,填入前端地址、runtimeAppId、apiName、token 和参数。
103
127
 
104
- 测试:`pnpm --filter @obm/apaas-embed-sdk exec vitest run`。
128
+ 测试:`pnpm --filter @obm/apaas-embed-sdk exec vitest run`。
105
129
 
106
- 在前端工作区运行 `pnpm --filter medipaas-frontend test:embed-params`,会先构建最新 SDK,再验证设计器生成代码与页面参数查询链路,避免读取旧 dist。
107
-
108
- ## 发布检查
109
-
110
- 在 SDK 目录执行 `pnpm run verify`,依次检查 lint、单元测试、构建、打包、临时项目安装、ESM/CJS 导入及类型声明。临时测试文件会自动清理。
111
-
112
- `npm publish` 会通过 `prepublishOnly` 自动执行完整验证,检查失败时停止发布。发布前需确认使用 `obm` 账号发布到 `@obm` scope,且目标版本尚未发布。
113
-
114
- ```bash
115
- pnpm run publish:check
116
- pnpm run publish:release
117
- ```
118
-
119
- 第一条仅预演;第二条实际发布公开包,使用默认的 `latest` 标签。npm 版本发布后不能覆盖,后续发布需更新 `package.json` 版本号。
120
-
121
- ## 许可与反馈
122
-
123
- 本 SDK 使用 [MIT License](LICENSE)。仓库及问题反馈地址见 `package.json` 的 `repository`、`homepage` 与 `bugs` 字段;访问项目 GitLab 可能需要账号权限。
130
+ 在前端工作区运行 `pnpm --filter medipaas-frontend test:embed-params`,会先构建最新 SDK,再验证设计器生成代码与页面参数查询链路,避免读取旧 dist。
131
+
132
+ ## 发布检查
133
+
134
+ 在 SDK 目录执行 `pnpm run verify`,依次检查 lint、单元测试、构建、打包、临时项目安装、ESM/CJS 导入及类型声明。临时测试文件会自动清理。
135
+
136
+ `npm publish` 会通过 `prepublishOnly` 自动执行完整验证,检查失败时停止发布。发布前需确认使用 `obm` 账号发布到 `@obm` scope,且目标版本尚未发布。
137
+
138
+ ```bash
139
+ pnpm run publish:check
140
+ pnpm run publish:release
141
+ ```
142
+
143
+ 第一条仅预演;第二条实际发布公开包,使用默认的 `latest` 标签。npm 版本发布后不能覆盖,后续发布需更新 `package.json` 版本号。
144
+
145
+ ## 许可与反馈
146
+
147
+ 本 SDK 使用 [MIT License](LICENSE)。仓库及问题反馈地址见 `package.json` 的 `repository`、`homepage` 与 `bugs` 字段;访问项目 GitLab 可能需要账号权限。
148
+
149
+ 公开会话中的 `runtimeAppId` 字段保留,值为稳定的逻辑应用 ID(响应如提供 `appId`,含义相同)。
150
+ 始终将此值传给 SDK 的 `appId`。后续发布或回滚无需更换 appId、URL 或 token;
151
+ APaaS 页面会在发现配置已更新时内部重新加载,不要求宿主监听发版事件。
152
+ 触发版本冲突的写入或流程不会自动重试,页面更新后由用户重新操作。
153
+ 物理版本预览凭证仍访问指定版本;本变更不迁移旧 token 或旧物理公开 URL。
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var d=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var j=(r,e,t)=>e in r?d(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var P=(r,e)=>{for(var t in e)d(r,t,{get:e[t],enumerable:!0})},U=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of A(e))!R.call(r,o)&&o!==t&&d(r,o,{get:()=>e[o],enumerable:!(n=O(e,o))||n.enumerable});return r};var $=r=>U(d({},"__esModule",{value:!0}),r);var m=(r,e,t)=>j(r,typeof e!="symbol"?e+"":e,t);var D={};P(D,{ApassEmbedSDK:()=>f});module.exports=$(D);var k=new Set(["token","__proto__","constructor","prototype"]);function b(r){if(r===null||typeof r!="object")return!1;let e=Object.getPrototypeOf(r);return e===null?!0:Object.getPrototypeOf(e)===null&&Object.prototype.hasOwnProperty.call(e,"constructor")&&typeof e.constructor=="function"&&Function.prototype.toString.call(e.constructor)===Function.prototype.toString.call(Object)}function w(r={}){if(!b(r))throw new Error("iframeAttrs must be a plain object");let e=Object.entries(r);for(let[t]of e){let n=t.trim().toLowerCase();if(n==="src"||n==="srcdoc")throw new Error(`iframeAttrs.${t} cannot override the SDK page address`);if(!t||/[\s"'>/=\u0000-\u001f]/.test(t))throw new Error(`Invalid iframe attribute name: ${t}`)}return Object.fromEntries(e)}function g(r,e){if(!r||r==="."||r==="..")throw new Error(`${e} must be a non-empty path segment other than . or ..`);return encodeURIComponent(r)}function E(r,e){if(!e.token)throw new Error("Token is required");let t=String(e.apiName||e.pageCode||e.pageId||"").trim();if(!t)throw new Error("Either apiName, pageCode (deprecated), or pageId (deprecated) is required");let n=new URL(`/apps/${g(e.appId,"appId")}/user/${g(t,"apiName")}`,r);n.searchParams.set("token",e.token);let o=e.params;if(o!==void 0){if(!b(o))throw new Error("params must be a plain object");for(let[s,i]of Object.entries(o)){if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)||k.has(s))throw new Error(`Invalid or reserved parameter name: ${s}`);if(i!=null){if(!["string","number","boolean"].includes(typeof i)||typeof i=="number"&&!Number.isFinite(i))throw new Error(`Parameter ${s} must be a string, finite number, or boolean`);n.searchParams.set(s,String(i))}}}return n.toString()}var f=class{constructor(e){m(this,"config");m(this,"instances",new Map);m(this,"instanceCounter",0);this.validateConfig(e),this.config={timeout:3e4,...e}}async embed(e){let{apiName:t,pageCode:n,pageId:o,token:s,containerId:i,onReady:y,onClose:C,onError:l,iframeAttrs:I={},fullscreen:v=!1}=e;try{let a=E(this.config.baseUrl,e),c=w(I);n&&!t&&console.warn("[MediPaaS SDK] pageCode is deprecated. Please use apiName instead."),o&&!t&&!n&&console.warn("[MediPaaS SDK] pageId is deprecated. Please use apiName instead.");let p=this.createIframe(a,c),x=this.prepareContainer(i,v),u=`apass-${++this.instanceCounter}`,h={iframe:p,token:s,expiresAt:0,close:()=>{this.closeInstance(u),C?.()}};return x.appendChild(p),p.onload=()=>{y?.()},p.onerror=()=>{let S=new Error("Failed to load A-pass iframe");l?.(S)},this.instances.set(u,h),h}catch(a){let c=a instanceof Error?a:new Error(String(a));throw l?.(c),c}}closeInstance(e){let t=this.instances.get(e);t&&(t.iframe.remove(),this.instances.delete(e))}prepareContainer(e,t){if(e){let s=document.getElementById(e);if(!s)throw new Error(`Container with id "${e}" not found`);return s}let n=document.createElement("div");n.style.cssText=`
1
+ "use strict";var g=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var K=(r,e,t)=>e in r?g(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var L=(r,e)=>{for(var t in e)g(r,t,{get:e[t],enumerable:!0})},N=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of $(e))!k.call(r,s)&&s!==t&&g(r,s,{get:()=>e[s],enumerable:!(n=D(e,s))||n.enumerable});return r};var T=r=>N(g({},"__esModule",{value:!0}),r);var f=(r,e,t)=>K(r,typeof e!="symbol"?e+"":e,t);var z={};L(z,{ApassEmbedSDK:()=>h});module.exports=T(z);var _=new Set(["token","__proto__","constructor","prototype"]);function x(r){if(r===null||typeof r!="object")return!1;let e=Object.getPrototypeOf(r);return e===null?!0:Object.getPrototypeOf(e)===null&&Object.prototype.hasOwnProperty.call(e,"constructor")&&typeof e.constructor=="function"&&Function.prototype.toString.call(e.constructor)===Function.prototype.toString.call(Object)}function O(r={}){if(!x(r))throw new Error("iframeAttrs must be a plain object");let e=Object.entries(r);for(let[t]of e){let n=t.trim().toLowerCase();if(n==="src"||n==="srcdoc")throw new Error(`iframeAttrs.${t} cannot override the SDK page address`);if(!t||/[\s"'>/=\u0000-\u001f]/.test(t))throw new Error(`Invalid iframe attribute name: ${t}`)}return Object.fromEntries(e)}function I(r,e){if(!r||r==="."||r==="..")throw new Error(`${e} must be a non-empty path segment other than . or ..`);return encodeURIComponent(r)}function S(r,e){if(!e.token)throw new Error("Token is required");let t=String(e.apiName||e.pageCode||e.pageId||"").trim();if(!t)throw new Error("Either apiName, pageCode (deprecated), or pageId (deprecated) is required");let n=new URL(`/apps/${I(e.appId,"appId")}/user/${I(t,"apiName")}`,r);n.searchParams.set("token",e.token);let s=e.params;if(s!==void 0){if(!x(s))throw new Error("params must be a plain object");for(let[i,c]of Object.entries(s)){if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)||_.has(i))throw new Error(`Invalid or reserved parameter name: ${i}`);if(c!=null){if(!["string","number","boolean"].includes(typeof c)||typeof c=="number"&&!Number.isFinite(c))throw new Error(`Parameter ${i} must be a string, finite number, or boolean`);n.searchParams.set(i,String(c))}}}return n.toString()}var h=class{constructor(e){f(this,"config");f(this,"instances",new Map);f(this,"cleanups",new Map);f(this,"instanceCounter",0);this.validateConfig(e),this.config={timeout:3e4,...e}}async embed(e){let{apiName:t,pageCode:n,pageId:s,token:i,containerId:c,onReady:A,onBridgeReady:R,onClose:U,onError:E,onEvent:j,iframeAttrs:P={},fullscreen:M=!1}=e;try{let d=S(this.config.baseUrl,e),l=O(P);n&&!t&&console.warn("[MediPaaS SDK] pageCode is deprecated. Please use apiName instead."),s&&!t&&!n&&console.warn("[MediPaaS SDK] pageId is deprecated. Please use apiName instead.");let p=this.createIframe(d,l),v=this.prepareContainer(c,M),m=`apass-${++this.instanceCounter}`,b=crypto.randomUUID(),w=new URL(d).origin,u=!1,C=o=>{if(o.source!==p.contentWindow||o.origin!==w)return;let a=o.data;if(!(!a||typeof a!="object"||Array.isArray(a))){if(a.type==="ready"){a.namespace==="medipaas.embed"&&a.version===1&&a.channelId===b&&!u&&(u=!0,R?.());return}(a.type===void 0||a.type==="event")&&typeof a.name=="string"&&a.name.trim()&&j?.({name:a.name,payload:a.payload})}};window.addEventListener("message",C);let y={iframe:p,token:i,expiresAt:0,close:()=>{this.closeInstance(m),U?.()},send:(o,a)=>{if(!u||!this.instances.has(m)||o!=="page.refresh"&&o!=="params.update")return!1;try{return p.contentWindow?.postMessage({namespace:"medipaas.embed",version:1,channelId:b,type:"event",name:o,payload:a},w),!0}catch{return!1}}};if(!c){let o=v.parentElement;o.dataset.apassOverlay=m,o.addEventListener("click",a=>{a.target===o&&y.close()})}return p.onload=()=>{u=!1,p.contentWindow?.postMessage({namespace:"medipaas.embed",version:1,channelId:b,type:"hello"},w),A?.()},p.onerror=()=>{let o=new Error("Failed to load A-pass iframe");E?.(o)},v.appendChild(p),this.instances.set(m,y),this.cleanups.set(m,()=>window.removeEventListener("message",C)),y}catch(d){let l=d instanceof Error?d:new Error(String(d));throw E?.(l),l}}closeInstance(e){let t=this.instances.get(e);if(t){this.cleanups.get(e)?.(),this.cleanups.delete(e);let n=t.iframe.parentElement?.parentElement;t.iframe.remove(),n?.dataset.apassOverlay===e&&n.remove(),this.instances.delete(e)}}prepareContainer(e,t){if(e){let i=document.getElementById(e);if(!i)throw new Error(`Container with id "${e}" not found`);return i}let n=document.createElement("div");n.style.cssText=`
2
2
  position: fixed;
3
3
  top: 0;
4
4
  left: 0;
@@ -9,10 +9,10 @@
9
9
  display: flex;
10
10
  align-items: center;
11
11
  justify-content: center;
12
- `;let o=document.createElement("div");return t?o.style.cssText=`
12
+ `;let s=document.createElement("div");return t?s.style.cssText=`
13
13
  width: 100%;
14
14
  height: 100%;
15
- `:o.style.cssText=`
15
+ `:s.style.cssText=`
16
16
  width: 90%;
17
17
  height: 90%;
18
18
  max-width: 1200px;
@@ -20,9 +20,9 @@
20
20
  border-radius: 8px;
21
21
  overflow: hidden;
22
22
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
23
- `,n.appendChild(o),document.body.appendChild(n),n.addEventListener("click",s=>{s.target===n&&n.remove()}),o}createIframe(e,t){let n=document.createElement("iframe");return n.src=e,n.style.cssText=`
23
+ `,n.appendChild(s),document.body.appendChild(n),s}createIframe(e,t){let n=document.createElement("iframe");return n.src=e,n.style.cssText=`
24
24
  width: 100%;
25
25
  height: 100%;
26
26
  border: none;
27
- `,Object.entries(t).forEach(([o,s])=>{n.setAttribute(o,s)}),n}validateConfig(e){if(!e.baseUrl)throw new Error("SDKConfig.baseUrl is required");try{new URL(e.baseUrl)}catch{throw new Error(`SDKConfig.baseUrl must be a valid URL: ${e.baseUrl}`)}}closeAll(){this.instances.forEach((e,t)=>{this.closeInstance(t)})}getInstanceCount(){return this.instances.size}};0&&(module.exports={ApassEmbedSDK});
27
+ `,Object.entries(t).forEach(([s,i])=>{n.setAttribute(s,i)}),n}validateConfig(e){if(!e.baseUrl)throw new Error("SDKConfig.baseUrl is required");try{new URL(e.baseUrl)}catch{throw new Error(`SDKConfig.baseUrl must be a valid URL: ${e.baseUrl}`)}}closeAll(){this.instances.forEach((e,t)=>{this.closeInstance(t)})}getInstanceCount(){return this.instances.size}};0&&(module.exports={ApassEmbedSDK});
28
28
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core/embedUrl.ts","../src/core/sdk.ts"],"sourcesContent":["export { ApassEmbedSDK } from './core/sdk';\r\nexport type {\r\n SDKConfig,\r\n EmbedOptions,\r\n EmbedParamValue,\r\n ApassInstanceRef,\r\n} from './types';\r\n","import type { EmbedOptions } from '../types';\r\n\r\nconst reservedNames = new Set(['token', '__proto__', 'constructor', 'prototype']);\r\n\r\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\r\n if (value === null || typeof value !== 'object') return false;\r\n const prototype = Object.getPrototypeOf(value);\r\n if (prototype === null) return true;\r\n // Object.prototype differs between same-origin windows. Compare its native\r\n // constructor instead of requiring this window's exact prototype identity.\r\n return Object.getPrototypeOf(prototype) === null &&\r\n Object.prototype.hasOwnProperty.call(prototype, 'constructor') &&\r\n typeof prototype.constructor === 'function' &&\r\n Function.prototype.toString.call(prototype.constructor) === Function.prototype.toString.call(Object);\r\n}\r\n\r\n/** Snapshot once so parameter/attribute getters cannot later replace the address. */\r\nexport function prepareIframeAttributes(attrs: Record<string, string> = {}): Record<string, string> {\r\n if (!isPlainObject(attrs)) throw new Error('iframeAttrs must be a plain object');\r\n const entries = Object.entries(attrs);\r\n for (const [name] of entries) {\r\n const normalized = name.trim().toLowerCase();\r\n if (normalized === 'src' || normalized === 'srcdoc') {\r\n throw new Error(`iframeAttrs.${name} cannot override the SDK page address`);\r\n }\r\n // eslint-disable-next-line no-control-regex -- Intentionally reject ASCII control characters in attribute names.\r\n if (!name || /[\\s\"'>/=\\u0000-\\u001f]/.test(name)) {\r\n throw new Error(`Invalid iframe attribute name: ${name}`);\r\n }\r\n }\r\n return Object.fromEntries(entries);\r\n}\r\n\r\nfunction encodeSegment(value: string, name: string): string {\r\n if (!value || value === '.' || value === '..') {\r\n throw new Error(`${name} must be a non-empty path segment other than . or ..`);\r\n }\r\n return encodeURIComponent(value);\r\n}\r\n\r\n/** Build and validate the complete iframe address before any DOM is created. */\r\nexport function buildEmbedUrl(baseUrl: string, options: EmbedOptions): string {\r\n if (!options.token) throw new Error('Token is required');\r\n const apiName = String(options.apiName || options.pageCode || options.pageId || '').trim();\r\n if (!apiName) {\r\n throw new Error('Either apiName, pageCode (deprecated), or pageId (deprecated) is required');\r\n }\r\n const url = new URL(`/apps/${encodeSegment(options.appId, 'appId')}/user/${encodeSegment(apiName, 'apiName')}`, baseUrl);\r\n url.searchParams.set('token', options.token);\r\n const params = options.params;\r\n if (params !== undefined) {\r\n if (!isPlainObject(params)) {\r\n throw new Error('params must be a plain object');\r\n }\r\n for (const [name, value] of Object.entries(params)) {\r\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) || reservedNames.has(name)) {\r\n throw new Error(`Invalid or reserved parameter name: ${name}`);\r\n }\r\n if (value === null || value === undefined) continue;\r\n if (!['string', 'number', 'boolean'].includes(typeof value) ||\r\n (typeof value === 'number' && !Number.isFinite(value))) {\r\n throw new Error(`Parameter ${name} must be a string, finite number, or boolean`);\r\n }\r\n url.searchParams.set(name, String(value));\r\n }\r\n }\r\n return url.toString();\r\n}\r\n","import type {\r\n SDKConfig,\r\n EmbedOptions,\r\n ApassInstanceRef,\r\n} from '../types';\r\nimport { buildEmbedUrl, prepareIframeAttributes } from './embedUrl';\r\n\r\n/**\r\n * Main SDK class for embedding A-pass applications\r\n *\r\n * @example\r\n * ```ts\r\n * const sdk = new ApassEmbedSDK({\r\n * baseUrl: 'https://apass.example.com',\r\n * });\r\n *\r\n * // CRM 项目先调自己的后端获取 token\r\n * const tokenResponse = await fetch('/api/embed-token', {\r\n * method: 'POST',\r\n * body: JSON.stringify({\r\n * recordId: 416,\r\n * enterpriseId: 456,\r\n * }),\r\n * });\r\n * const { token } = await tokenResponse.json();\r\n *\r\n * // 然后把 token 传给 SDK\r\n * await sdk.embed({\r\n * appId: '180',\r\n * apiName: 'patient_list',\r\n * token: token,\r\n * containerId: 'my-container',\r\n * });\r\n * ```\r\n */\r\nexport class ApassEmbedSDK {\r\n private config: SDKConfig;\r\n private instances: Map<string, ApassInstanceRef> = new Map();\r\n private instanceCounter = 0;\r\n\r\n constructor(config: SDKConfig) {\r\n this.validateConfig(config);\r\n this.config = {\r\n timeout: 30000,\r\n ...config,\r\n };\r\n }\r\n\r\n /**\r\n * Embed an A-pass application in an iframe\r\n */\r\n async embed(options: EmbedOptions): Promise<ApassInstanceRef> {\r\n const {\r\n apiName,\r\n pageCode,\r\n pageId,\r\n token,\r\n containerId,\r\n onReady,\r\n onClose,\r\n onError,\r\n iframeAttrs = {},\r\n fullscreen = false,\r\n } = options;\r\n\r\n try {\r\n const url = buildEmbedUrl(this.config.baseUrl, options);\r\n const attrs = prepareIframeAttributes(iframeAttrs);\r\n // Warn if using deprecated parameters\r\n if (pageCode && !apiName) {\r\n console.warn('[MediPaaS SDK] pageCode is deprecated. Please use apiName instead.');\r\n }\r\n if (pageId && !apiName && !pageCode) {\r\n console.warn('[MediPaaS SDK] pageId is deprecated. Please use apiName instead.');\r\n }\r\n\r\n // Prepare the detached iframe first: DOM attribute validation must finish\r\n // before a default overlay is attached to the host page.\r\n const iframe = this.createIframe(url, attrs);\r\n const container = this.prepareContainer(containerId, fullscreen);\r\n\r\n // Step 5: Setup lifecycle handlers\r\n const instanceId = `apass-${++this.instanceCounter}`;\r\n\r\n const instance: ApassInstanceRef = {\r\n iframe,\r\n token,\r\n expiresAt: 0, // Token expiration not tracked in this mode\r\n close: () => {\r\n this.closeInstance(instanceId);\r\n onClose?.();\r\n },\r\n };\r\n\r\n // Step 6: Append iframe to container\r\n container.appendChild(iframe);\r\n\r\n // Step 7: Setup ready handler\r\n iframe.onload = () => {\r\n onReady?.();\r\n };\r\n\r\n // Step 8: Setup error handler\r\n iframe.onerror = () => {\r\n const error = new Error('Failed to load A-pass iframe');\r\n onError?.(error);\r\n };\r\n\r\n // Store instance reference\r\n this.instances.set(instanceId, instance);\r\n\r\n return instance;\r\n } catch (error) {\r\n const err =\r\n error instanceof Error ? error : new Error(String(error));\r\n onError?.(err);\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Close and cleanup an instance\r\n */\r\n private closeInstance(instanceId: string): void {\r\n const instance = this.instances.get(instanceId);\r\n if (instance) {\r\n // Remove iframe from DOM\r\n instance.iframe.remove();\r\n // Remove from tracking\r\n this.instances.delete(instanceId);\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Prepare container for iframe\r\n */\r\n private prepareContainer(\r\n containerId: string | undefined,\r\n fullscreen: boolean,\r\n ): HTMLElement {\r\n if (containerId) {\r\n const container = document.getElementById(containerId);\r\n if (!container) {\r\n throw new Error(`Container with id \"${containerId}\" not found`);\r\n }\r\n return container;\r\n }\r\n\r\n // Create default container\r\n const container = document.createElement('div');\r\n container.style.cssText = `\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n width: 100%;\r\n height: 100%;\r\n z-index: 10000;\r\n background: rgba(0, 0, 0, 0.5);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n `;\r\n\r\n const wrapper = document.createElement('div');\r\n if (fullscreen) {\r\n wrapper.style.cssText = `\r\n width: 100%;\r\n height: 100%;\r\n `;\r\n } else {\r\n wrapper.style.cssText = `\r\n width: 90%;\r\n height: 90%;\r\n max-width: 1200px;\r\n max-height: 800px;\r\n border-radius: 8px;\r\n overflow: hidden;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n `;\r\n }\r\n\r\n container.appendChild(wrapper);\r\n document.body.appendChild(container);\r\n\r\n // Auto-close on background click\r\n container.addEventListener('click', (e) => {\r\n if (e.target === container) {\r\n container.remove();\r\n }\r\n });\r\n\r\n return wrapper;\r\n }\r\n\r\n /**\r\n * Create iframe element\r\n */\r\n private createIframe(\r\n url: string,\r\n attrs: Record<string, string>,\r\n ): HTMLIFrameElement {\r\n const iframe = document.createElement('iframe');\r\n\r\n // Build A-pass URL with token parameter\r\n iframe.src = url;\r\n iframe.style.cssText = `\r\n width: 100%;\r\n height: 100%;\r\n border: none;\r\n `;\r\n\r\n // Apply custom attributes\r\n Object.entries(attrs).forEach(([key, value]) => {\r\n iframe.setAttribute(key, value);\r\n });\r\n\r\n return iframe;\r\n }\r\n\r\n /**\r\n * Validate SDK configuration\r\n */\r\n private validateConfig(config: SDKConfig): void {\r\n if (!config.baseUrl) {\r\n throw new Error('SDKConfig.baseUrl is required');\r\n }\r\n\r\n try {\r\n new URL(config.baseUrl);\r\n } catch {\r\n throw new Error(\r\n `SDKConfig.baseUrl must be a valid URL: ${config.baseUrl}`,\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Close all instances\r\n */\r\n closeAll(): void {\r\n this.instances.forEach((_, instanceId) => {\r\n this.closeInstance(instanceId);\r\n });\r\n }\r\n\r\n /**\r\n * Get active instances count\r\n */\r\n getInstanceCount(): number {\r\n return this.instances.size;\r\n }\r\n}\r\n"],"mappings":"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","names":["src_exports","__export","ApassEmbedSDK","__toCommonJS","reservedNames","isPlainObject","value","prototype","prepareIframeAttributes","attrs","entries","name","normalized","encodeSegment","buildEmbedUrl","baseUrl","options","apiName","url","params","ApassEmbedSDK","config","__publicField","options","apiName","pageCode","pageId","token","containerId","onReady","onClose","onError","iframeAttrs","fullscreen","url","buildEmbedUrl","attrs","prepareIframeAttributes","iframe","container","instanceId","instance","error","err","wrapper","e","key","value","_"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core/embedUrl.ts","../src/core/sdk.ts"],"sourcesContent":["export { ApassEmbedSDK } from './core/sdk';\r\nexport type {\r\n SDKConfig,\r\n EmbedOptions,\r\n EmbedParamValue,\n EmbedBusinessEvent,\n ApassInstanceRef,\r\n} from './types';\r\n","import type { EmbedOptions } from '../types';\r\n\r\nconst reservedNames = new Set(['token', '__proto__', 'constructor', 'prototype']);\r\n\r\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\r\n if (value === null || typeof value !== 'object') return false;\r\n const prototype = Object.getPrototypeOf(value);\r\n if (prototype === null) return true;\r\n // Object.prototype differs between same-origin windows. Compare its native\r\n // constructor instead of requiring this window's exact prototype identity.\r\n return Object.getPrototypeOf(prototype) === null &&\r\n Object.prototype.hasOwnProperty.call(prototype, 'constructor') &&\r\n typeof prototype.constructor === 'function' &&\r\n Function.prototype.toString.call(prototype.constructor) === Function.prototype.toString.call(Object);\r\n}\r\n\r\n/** Snapshot once so parameter/attribute getters cannot later replace the address. */\r\nexport function prepareIframeAttributes(attrs: Record<string, string> = {}): Record<string, string> {\r\n if (!isPlainObject(attrs)) throw new Error('iframeAttrs must be a plain object');\r\n const entries = Object.entries(attrs);\r\n for (const [name] of entries) {\r\n const normalized = name.trim().toLowerCase();\r\n if (normalized === 'src' || normalized === 'srcdoc') {\r\n throw new Error(`iframeAttrs.${name} cannot override the SDK page address`);\r\n }\r\n // eslint-disable-next-line no-control-regex -- Intentionally reject ASCII control characters in attribute names.\r\n if (!name || /[\\s\"'>/=\\u0000-\\u001f]/.test(name)) {\r\n throw new Error(`Invalid iframe attribute name: ${name}`);\r\n }\r\n }\r\n return Object.fromEntries(entries);\r\n}\r\n\r\nfunction encodeSegment(value: string, name: string): string {\r\n if (!value || value === '.' || value === '..') {\r\n throw new Error(`${name} must be a non-empty path segment other than . or ..`);\r\n }\r\n return encodeURIComponent(value);\r\n}\r\n\r\n/** Build and validate the complete iframe address before any DOM is created. */\r\nexport function buildEmbedUrl(baseUrl: string, options: EmbedOptions): string {\r\n if (!options.token) throw new Error('Token is required');\r\n const apiName = String(options.apiName || options.pageCode || options.pageId || '').trim();\r\n if (!apiName) {\r\n throw new Error('Either apiName, pageCode (deprecated), or pageId (deprecated) is required');\r\n }\r\n const url = new URL(`/apps/${encodeSegment(options.appId, 'appId')}/user/${encodeSegment(apiName, 'apiName')}`, baseUrl);\r\n url.searchParams.set('token', options.token);\r\n const params = options.params;\r\n if (params !== undefined) {\r\n if (!isPlainObject(params)) {\r\n throw new Error('params must be a plain object');\r\n }\r\n for (const [name, value] of Object.entries(params)) {\r\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) || reservedNames.has(name)) {\r\n throw new Error(`Invalid or reserved parameter name: ${name}`);\r\n }\r\n if (value === null || value === undefined) continue;\r\n if (!['string', 'number', 'boolean'].includes(typeof value) ||\r\n (typeof value === 'number' && !Number.isFinite(value))) {\r\n throw new Error(`Parameter ${name} must be a string, finite number, or boolean`);\r\n }\r\n url.searchParams.set(name, String(value));\r\n }\r\n }\r\n return url.toString();\r\n}\r\n","import type {\r\n SDKConfig,\r\n EmbedOptions,\r\n ApassInstanceRef,\r\n} from '../types';\r\nimport { buildEmbedUrl, prepareIframeAttributes } from './embedUrl';\r\n\r\n/**\r\n * Main SDK class for embedding A-pass applications\r\n *\r\n * @example\r\n * ```ts\r\n * const sdk = new ApassEmbedSDK({\r\n * baseUrl: 'https://apass.example.com',\r\n * });\r\n *\r\n * // CRM 项目先调自己的后端获取 token\r\n * const tokenResponse = await fetch('/api/embed-token', {\r\n * method: 'POST',\r\n * body: JSON.stringify({\r\n * recordId: 416,\r\n * enterpriseId: 456,\r\n * }),\r\n * });\r\n * const { token } = await tokenResponse.json();\r\n *\r\n * // 然后把 token 传给 SDK\r\n * await sdk.embed({\r\n * appId: '180',\r\n * apiName: 'patient_list',\r\n * token: token,\r\n * containerId: 'my-container',\r\n * });\r\n * ```\r\n */\r\nexport class ApassEmbedSDK {\r\n private config: SDKConfig;\r\n private instances: Map<string, ApassInstanceRef> = new Map();\n private cleanups: Map<string, () => void> = new Map();\n private instanceCounter = 0;\r\n\r\n constructor(config: SDKConfig) {\r\n this.validateConfig(config);\r\n this.config = {\r\n timeout: 30000,\r\n ...config,\r\n };\r\n }\r\n\r\n /**\r\n * Embed an A-pass application in an iframe\r\n */\r\n async embed(options: EmbedOptions): Promise<ApassInstanceRef> {\r\n const {\r\n apiName,\r\n pageCode,\r\n pageId,\r\n token,\r\n containerId,\r\n onReady,\n onBridgeReady,\n onClose,\r\n onError,\n onEvent,\n iframeAttrs = {},\r\n fullscreen = false,\r\n } = options;\r\n\r\n try {\r\n const url = buildEmbedUrl(this.config.baseUrl, options);\r\n const attrs = prepareIframeAttributes(iframeAttrs);\r\n // Warn if using deprecated parameters\r\n if (pageCode && !apiName) {\r\n console.warn('[MediPaaS SDK] pageCode is deprecated. Please use apiName instead.');\r\n }\r\n if (pageId && !apiName && !pageCode) {\r\n console.warn('[MediPaaS SDK] pageId is deprecated. Please use apiName instead.');\r\n }\r\n\r\n // Prepare the detached iframe first: DOM attribute validation must finish\r\n // before a default overlay is attached to the host page.\r\n const iframe = this.createIframe(url, attrs);\r\n const container = this.prepareContainer(containerId, fullscreen);\r\n\r\n // Step 5: Setup lifecycle handlers\r\n const instanceId = `apass-${++this.instanceCounter}`;\n const channelId = crypto.randomUUID();\n const targetOrigin = new URL(url).origin;\n let ready = false;\n const receiveMessage = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow || event.origin !== targetOrigin) return;\n const message = event.data;\n if (!message || typeof message !== 'object' || Array.isArray(message)) return;\n if (message.type === 'ready') {\n if (message.namespace === 'medipaas.embed' && message.version === 1\n && message.channelId === channelId && !ready) {\n ready = true;\n onBridgeReady?.();\n }\n return;\n }\n // Business scripts can post { name, payload } directly, without a handshake.\n if ((message.type === undefined || message.type === 'event')\n && typeof message.name === 'string' && message.name.trim()) {\n onEvent?.({ name: message.name, payload: message.payload });\n }\n };\n window.addEventListener('message', receiveMessage);\n\n const instance: ApassInstanceRef = {\n iframe,\r\n token,\r\n expiresAt: 0, // Token expiration not tracked in this mode\r\n close: () => {\n this.closeInstance(instanceId);\n onClose?.();\n },\n send: (name, payload) => {\n if (!ready || !this.instances.has(instanceId)) return false;\n if (name !== 'page.refresh' && name !== 'params.update') return false;\n try {\n iframe.contentWindow?.postMessage({ namespace: 'medipaas.embed', version: 1,\n channelId, type: 'event', name, payload }, targetOrigin);\n return true;\n } catch {\n return false;\n }\n },\n };\n\n if (!containerId) {\n const overlay = container.parentElement!;\n overlay.dataset.apassOverlay = instanceId;\n overlay.addEventListener('click', (event) => {\n if (event.target === overlay) instance.close();\n });\n }\n\r\n // Step 6: Setup ready handler before attaching the iframe\n iframe.onload = () => {\n ready = false;\n iframe.contentWindow?.postMessage({ namespace: 'medipaas.embed', version: 1,\n channelId, type: 'hello' }, targetOrigin);\n onReady?.();\n };\r\n\r\n // Step 8: Setup error handler\r\n iframe.onerror = () => {\n const error = new Error('Failed to load A-pass iframe');\r\n onError?.(error);\r\n };\n\n container.appendChild(iframe);\n\r\n // Store instance reference\r\n this.instances.set(instanceId, instance);\n this.cleanups.set(instanceId, () => window.removeEventListener('message', receiveMessage));\n\r\n return instance;\r\n } catch (error) {\r\n const err =\r\n error instanceof Error ? error : new Error(String(error));\r\n onError?.(err);\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Close and cleanup an instance\r\n */\r\n private closeInstance(instanceId: string): void {\n const instance = this.instances.get(instanceId);\r\n if (instance) {\n this.cleanups.get(instanceId)?.();\n this.cleanups.delete(instanceId);\n // Remove iframe from DOM\n const overlay = instance.iframe.parentElement?.parentElement;\n instance.iframe.remove();\n if (overlay?.dataset.apassOverlay === instanceId) overlay.remove();\n // Remove from tracking\r\n this.instances.delete(instanceId);\r\n }\r\n }\n\r\n\r\n /**\r\n * Prepare container for iframe\r\n */\r\n private prepareContainer(\r\n containerId: string | undefined,\r\n fullscreen: boolean,\r\n ): HTMLElement {\r\n if (containerId) {\r\n const container = document.getElementById(containerId);\r\n if (!container) {\r\n throw new Error(`Container with id \"${containerId}\" not found`);\r\n }\r\n return container;\r\n }\r\n\r\n // Create default container\r\n const container = document.createElement('div');\r\n container.style.cssText = `\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n width: 100%;\r\n height: 100%;\r\n z-index: 10000;\r\n background: rgba(0, 0, 0, 0.5);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n `;\r\n\r\n const wrapper = document.createElement('div');\r\n if (fullscreen) {\r\n wrapper.style.cssText = `\r\n width: 100%;\r\n height: 100%;\r\n `;\r\n } else {\r\n wrapper.style.cssText = `\r\n width: 90%;\r\n height: 90%;\r\n max-width: 1200px;\r\n max-height: 800px;\r\n border-radius: 8px;\r\n overflow: hidden;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n `;\r\n }\r\n\r\n container.appendChild(wrapper);\r\n document.body.appendChild(container);\r\n\r\n return wrapper;\n }\r\n\r\n /**\r\n * Create iframe element\r\n */\r\n private createIframe(\r\n url: string,\r\n attrs: Record<string, string>,\r\n ): HTMLIFrameElement {\r\n const iframe = document.createElement('iframe');\r\n\r\n // Build A-pass URL with token parameter\r\n iframe.src = url;\r\n iframe.style.cssText = `\r\n width: 100%;\r\n height: 100%;\r\n border: none;\r\n `;\r\n\r\n // Apply custom attributes\r\n Object.entries(attrs).forEach(([key, value]) => {\r\n iframe.setAttribute(key, value);\r\n });\r\n\r\n return iframe;\r\n }\r\n\r\n /**\r\n * Validate SDK configuration\r\n */\r\n private validateConfig(config: SDKConfig): void {\r\n if (!config.baseUrl) {\r\n throw new Error('SDKConfig.baseUrl is required');\r\n }\r\n\r\n try {\r\n new URL(config.baseUrl);\r\n } catch {\r\n throw new Error(\r\n `SDKConfig.baseUrl must be a valid URL: ${config.baseUrl}`,\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Close all instances\r\n */\r\n closeAll(): void {\r\n this.instances.forEach((_, instanceId) => {\r\n this.closeInstance(instanceId);\r\n });\r\n }\r\n\r\n /**\r\n * Get active instances count\r\n */\r\n getInstanceCount(): number {\r\n return this.instances.size;\r\n }\r\n}\r\n"],"mappings":"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","names":["src_exports","__export","ApassEmbedSDK","__toCommonJS","reservedNames","isPlainObject","value","prototype","prepareIframeAttributes","attrs","entries","name","normalized","encodeSegment","buildEmbedUrl","baseUrl","options","apiName","url","params","ApassEmbedSDK","config","__publicField","options","apiName","pageCode","pageId","token","containerId","onReady","onBridgeReady","onClose","onError","onEvent","iframeAttrs","fullscreen","url","buildEmbedUrl","attrs","prepareIframeAttributes","iframe","container","instanceId","channelId","targetOrigin","ready","receiveMessage","event","message","instance","name","payload","overlay","error","err","wrapper","key","value","_"]}
package/dist/index.d.cts CHANGED
@@ -11,6 +11,10 @@ interface SDKConfig {
11
11
  * Options for embedding an A-pass application
12
12
  */
13
13
  type EmbedParamValue = string | number | boolean | null | undefined;
14
+ interface EmbedBusinessEvent {
15
+ name: string;
16
+ payload: unknown;
17
+ }
14
18
  interface EmbedOptions {
15
19
  /** Application ID in A-pass */
16
20
  appId: string;
@@ -28,10 +32,14 @@ interface EmbedOptions {
28
32
  containerId?: string;
29
33
  /** Optional callback when iframe is loaded */
30
34
  onReady?: () => void;
35
+ /** Called after the embedded page acknowledges the message channel. */
36
+ onBridgeReady?: () => void;
31
37
  /** Optional callback when iframe is closed/destroyed */
32
38
  onClose?: () => void;
33
39
  /** Optional callback on error */
34
40
  onError?: (error: Error) => void;
41
+ /** Receives iframe postMessage({ name, payload }); no handshake required. */
42
+ onEvent?: (event: EmbedBusinessEvent) => void;
35
43
  /** Optional custom iframe attributes. src and srcdoc are prohibited. */
36
44
  iframeAttrs?: Record<string, string>;
37
45
  /** Whether to fullscreen the iframe (default: false) */
@@ -45,6 +53,8 @@ interface ApassInstanceRef {
45
53
  iframe: HTMLIFrameElement;
46
54
  /** Close/destroy the instance */
47
55
  close: () => void;
56
+ /** Send a supported event to the running page. Returns false until the bridge is ready. */
57
+ send: (name: 'page.refresh' | 'params.update', payload?: unknown) => boolean;
48
58
  /** Token expiration time */
49
59
  expiresAt: number;
50
60
  /** Token value */
@@ -82,6 +92,7 @@ interface ApassInstanceRef {
82
92
  declare class ApassEmbedSDK {
83
93
  private config;
84
94
  private instances;
95
+ private cleanups;
85
96
  private instanceCounter;
86
97
  constructor(config: SDKConfig);
87
98
  /**
@@ -114,4 +125,4 @@ declare class ApassEmbedSDK {
114
125
  getInstanceCount(): number;
115
126
  }
116
127
 
117
- export { ApassEmbedSDK, type ApassInstanceRef, type EmbedOptions, type EmbedParamValue, type SDKConfig };
128
+ export { ApassEmbedSDK, type ApassInstanceRef, type EmbedBusinessEvent, type EmbedOptions, type EmbedParamValue, type SDKConfig };
package/dist/index.d.ts CHANGED
@@ -11,6 +11,10 @@ interface SDKConfig {
11
11
  * Options for embedding an A-pass application
12
12
  */
13
13
  type EmbedParamValue = string | number | boolean | null | undefined;
14
+ interface EmbedBusinessEvent {
15
+ name: string;
16
+ payload: unknown;
17
+ }
14
18
  interface EmbedOptions {
15
19
  /** Application ID in A-pass */
16
20
  appId: string;
@@ -28,10 +32,14 @@ interface EmbedOptions {
28
32
  containerId?: string;
29
33
  /** Optional callback when iframe is loaded */
30
34
  onReady?: () => void;
35
+ /** Called after the embedded page acknowledges the message channel. */
36
+ onBridgeReady?: () => void;
31
37
  /** Optional callback when iframe is closed/destroyed */
32
38
  onClose?: () => void;
33
39
  /** Optional callback on error */
34
40
  onError?: (error: Error) => void;
41
+ /** Receives iframe postMessage({ name, payload }); no handshake required. */
42
+ onEvent?: (event: EmbedBusinessEvent) => void;
35
43
  /** Optional custom iframe attributes. src and srcdoc are prohibited. */
36
44
  iframeAttrs?: Record<string, string>;
37
45
  /** Whether to fullscreen the iframe (default: false) */
@@ -45,6 +53,8 @@ interface ApassInstanceRef {
45
53
  iframe: HTMLIFrameElement;
46
54
  /** Close/destroy the instance */
47
55
  close: () => void;
56
+ /** Send a supported event to the running page. Returns false until the bridge is ready. */
57
+ send: (name: 'page.refresh' | 'params.update', payload?: unknown) => boolean;
48
58
  /** Token expiration time */
49
59
  expiresAt: number;
50
60
  /** Token value */
@@ -82,6 +92,7 @@ interface ApassInstanceRef {
82
92
  declare class ApassEmbedSDK {
83
93
  private config;
84
94
  private instances;
95
+ private cleanups;
85
96
  private instanceCounter;
86
97
  constructor(config: SDKConfig);
87
98
  /**
@@ -114,4 +125,4 @@ declare class ApassEmbedSDK {
114
125
  getInstanceCount(): number;
115
126
  }
116
127
 
117
- export { ApassEmbedSDK, type ApassInstanceRef, type EmbedOptions, type EmbedParamValue, type SDKConfig };
128
+ export { ApassEmbedSDK, type ApassInstanceRef, type EmbedBusinessEvent, type EmbedOptions, type EmbedParamValue, type SDKConfig };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- var S=Object.defineProperty;var O=(n,e,t)=>e in n?S(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var d=(n,e,t)=>O(n,typeof e!="symbol"?e+"":e,t);var A=new Set(["token","__proto__","constructor","prototype"]);function g(n){if(n===null||typeof n!="object")return!1;let e=Object.getPrototypeOf(n);return e===null?!0:Object.getPrototypeOf(e)===null&&Object.prototype.hasOwnProperty.call(e,"constructor")&&typeof e.constructor=="function"&&Function.prototype.toString.call(e.constructor)===Function.prototype.toString.call(Object)}function b(n={}){if(!g(n))throw new Error("iframeAttrs must be a plain object");let e=Object.entries(n);for(let[t]of e){let r=t.trim().toLowerCase();if(r==="src"||r==="srcdoc")throw new Error(`iframeAttrs.${t} cannot override the SDK page address`);if(!t||/[\s"'>/=\u0000-\u001f]/.test(t))throw new Error(`Invalid iframe attribute name: ${t}`)}return Object.fromEntries(e)}function h(n,e){if(!n||n==="."||n==="..")throw new Error(`${e} must be a non-empty path segment other than . or ..`);return encodeURIComponent(n)}function w(n,e){if(!e.token)throw new Error("Token is required");let t=String(e.apiName||e.pageCode||e.pageId||"").trim();if(!t)throw new Error("Either apiName, pageCode (deprecated), or pageId (deprecated) is required");let r=new URL(`/apps/${h(e.appId,"appId")}/user/${h(t,"apiName")}`,n);r.searchParams.set("token",e.token);let s=e.params;if(s!==void 0){if(!g(s))throw new Error("params must be a plain object");for(let[o,i]of Object.entries(s)){if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)||A.has(o))throw new Error(`Invalid or reserved parameter name: ${o}`);if(i!=null){if(!["string","number","boolean"].includes(typeof i)||typeof i=="number"&&!Number.isFinite(i))throw new Error(`Parameter ${o} must be a string, finite number, or boolean`);r.searchParams.set(o,String(i))}}}return r.toString()}var m=class{constructor(e){d(this,"config");d(this,"instances",new Map);d(this,"instanceCounter",0);this.validateConfig(e),this.config={timeout:3e4,...e}}async embed(e){let{apiName:t,pageCode:r,pageId:s,token:o,containerId:i,onReady:E,onClose:y,onError:f,iframeAttrs:C={},fullscreen:I=!1}=e;try{let a=w(this.config.baseUrl,e),c=b(C);r&&!t&&console.warn("[MediPaaS SDK] pageCode is deprecated. Please use apiName instead."),s&&!t&&!r&&console.warn("[MediPaaS SDK] pageId is deprecated. Please use apiName instead.");let p=this.createIframe(a,c),v=this.prepareContainer(i,I),l=`apass-${++this.instanceCounter}`,u={iframe:p,token:o,expiresAt:0,close:()=>{this.closeInstance(l),y?.()}};return v.appendChild(p),p.onload=()=>{E?.()},p.onerror=()=>{let x=new Error("Failed to load A-pass iframe");f?.(x)},this.instances.set(l,u),u}catch(a){let c=a instanceof Error?a:new Error(String(a));throw f?.(c),c}}closeInstance(e){let t=this.instances.get(e);t&&(t.iframe.remove(),this.instances.delete(e))}prepareContainer(e,t){if(e){let o=document.getElementById(e);if(!o)throw new Error(`Container with id "${e}" not found`);return o}let r=document.createElement("div");r.style.cssText=`
1
+ var M=Object.defineProperty;var D=(n,e,t)=>e in n?M(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var f=(n,e,t)=>D(n,typeof e!="symbol"?e+"":e,t);var $=new Set(["token","__proto__","constructor","prototype"]);function I(n){if(n===null||typeof n!="object")return!1;let e=Object.getPrototypeOf(n);return e===null?!0:Object.getPrototypeOf(e)===null&&Object.prototype.hasOwnProperty.call(e,"constructor")&&typeof e.constructor=="function"&&Function.prototype.toString.call(e.constructor)===Function.prototype.toString.call(Object)}function x(n={}){if(!I(n))throw new Error("iframeAttrs must be a plain object");let e=Object.entries(n);for(let[t]of e){let r=t.trim().toLowerCase();if(r==="src"||r==="srcdoc")throw new Error(`iframeAttrs.${t} cannot override the SDK page address`);if(!t||/[\s"'>/=\u0000-\u001f]/.test(t))throw new Error(`Invalid iframe attribute name: ${t}`)}return Object.fromEntries(e)}function C(n,e){if(!n||n==="."||n==="..")throw new Error(`${e} must be a non-empty path segment other than . or ..`);return encodeURIComponent(n)}function O(n,e){if(!e.token)throw new Error("Token is required");let t=String(e.apiName||e.pageCode||e.pageId||"").trim();if(!t)throw new Error("Either apiName, pageCode (deprecated), or pageId (deprecated) is required");let r=new URL(`/apps/${C(e.appId,"appId")}/user/${C(t,"apiName")}`,n);r.searchParams.set("token",e.token);let o=e.params;if(o!==void 0){if(!I(o))throw new Error("params must be a plain object");for(let[i,c]of Object.entries(o)){if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)||$.has(i))throw new Error(`Invalid or reserved parameter name: ${i}`);if(c!=null){if(!["string","number","boolean"].includes(typeof c)||typeof c=="number"&&!Number.isFinite(c))throw new Error(`Parameter ${i} must be a string, finite number, or boolean`);r.searchParams.set(i,String(c))}}}return r.toString()}var w=class{constructor(e){f(this,"config");f(this,"instances",new Map);f(this,"cleanups",new Map);f(this,"instanceCounter",0);this.validateConfig(e),this.config={timeout:3e4,...e}}async embed(e){let{apiName:t,pageCode:r,pageId:o,token:i,containerId:c,onReady:S,onBridgeReady:A,onClose:R,onError:y,onEvent:U,iframeAttrs:j={},fullscreen:P=!1}=e;try{let d=O(this.config.baseUrl,e),l=x(j);r&&!t&&console.warn("[MediPaaS SDK] pageCode is deprecated. Please use apiName instead."),o&&!t&&!r&&console.warn("[MediPaaS SDK] pageId is deprecated. Please use apiName instead.");let p=this.createIframe(d,l),E=this.prepareContainer(c,P),m=`apass-${++this.instanceCounter}`,g=crypto.randomUUID(),h=new URL(d).origin,u=!1,v=a=>{if(a.source!==p.contentWindow||a.origin!==h)return;let s=a.data;if(!(!s||typeof s!="object"||Array.isArray(s))){if(s.type==="ready"){s.namespace==="medipaas.embed"&&s.version===1&&s.channelId===g&&!u&&(u=!0,A?.());return}(s.type===void 0||s.type==="event")&&typeof s.name=="string"&&s.name.trim()&&U?.({name:s.name,payload:s.payload})}};window.addEventListener("message",v);let b={iframe:p,token:i,expiresAt:0,close:()=>{this.closeInstance(m),R?.()},send:(a,s)=>{if(!u||!this.instances.has(m)||a!=="page.refresh"&&a!=="params.update")return!1;try{return p.contentWindow?.postMessage({namespace:"medipaas.embed",version:1,channelId:g,type:"event",name:a,payload:s},h),!0}catch{return!1}}};if(!c){let a=E.parentElement;a.dataset.apassOverlay=m,a.addEventListener("click",s=>{s.target===a&&b.close()})}return p.onload=()=>{u=!1,p.contentWindow?.postMessage({namespace:"medipaas.embed",version:1,channelId:g,type:"hello"},h),S?.()},p.onerror=()=>{let a=new Error("Failed to load A-pass iframe");y?.(a)},E.appendChild(p),this.instances.set(m,b),this.cleanups.set(m,()=>window.removeEventListener("message",v)),b}catch(d){let l=d instanceof Error?d:new Error(String(d));throw y?.(l),l}}closeInstance(e){let t=this.instances.get(e);if(t){this.cleanups.get(e)?.(),this.cleanups.delete(e);let r=t.iframe.parentElement?.parentElement;t.iframe.remove(),r?.dataset.apassOverlay===e&&r.remove(),this.instances.delete(e)}}prepareContainer(e,t){if(e){let i=document.getElementById(e);if(!i)throw new Error(`Container with id "${e}" not found`);return i}let r=document.createElement("div");r.style.cssText=`
2
2
  position: fixed;
3
3
  top: 0;
4
4
  left: 0;
@@ -9,10 +9,10 @@ var S=Object.defineProperty;var O=(n,e,t)=>e in n?S(n,e,{enumerable:!0,configura
9
9
  display: flex;
10
10
  align-items: center;
11
11
  justify-content: center;
12
- `;let s=document.createElement("div");return t?s.style.cssText=`
12
+ `;let o=document.createElement("div");return t?o.style.cssText=`
13
13
  width: 100%;
14
14
  height: 100%;
15
- `:s.style.cssText=`
15
+ `:o.style.cssText=`
16
16
  width: 90%;
17
17
  height: 90%;
18
18
  max-width: 1200px;
@@ -20,9 +20,9 @@ var S=Object.defineProperty;var O=(n,e,t)=>e in n?S(n,e,{enumerable:!0,configura
20
20
  border-radius: 8px;
21
21
  overflow: hidden;
22
22
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
23
- `,r.appendChild(s),document.body.appendChild(r),r.addEventListener("click",o=>{o.target===r&&r.remove()}),s}createIframe(e,t){let r=document.createElement("iframe");return r.src=e,r.style.cssText=`
23
+ `,r.appendChild(o),document.body.appendChild(r),o}createIframe(e,t){let r=document.createElement("iframe");return r.src=e,r.style.cssText=`
24
24
  width: 100%;
25
25
  height: 100%;
26
26
  border: none;
27
- `,Object.entries(t).forEach(([s,o])=>{r.setAttribute(s,o)}),r}validateConfig(e){if(!e.baseUrl)throw new Error("SDKConfig.baseUrl is required");try{new URL(e.baseUrl)}catch{throw new Error(`SDKConfig.baseUrl must be a valid URL: ${e.baseUrl}`)}}closeAll(){this.instances.forEach((e,t)=>{this.closeInstance(t)})}getInstanceCount(){return this.instances.size}};export{m as ApassEmbedSDK};
27
+ `,Object.entries(t).forEach(([o,i])=>{r.setAttribute(o,i)}),r}validateConfig(e){if(!e.baseUrl)throw new Error("SDKConfig.baseUrl is required");try{new URL(e.baseUrl)}catch{throw new Error(`SDKConfig.baseUrl must be a valid URL: ${e.baseUrl}`)}}closeAll(){this.instances.forEach((e,t)=>{this.closeInstance(t)})}getInstanceCount(){return this.instances.size}};export{w as ApassEmbedSDK};
28
28
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/embedUrl.ts","../src/core/sdk.ts"],"sourcesContent":["import type { EmbedOptions } from '../types';\r\n\r\nconst reservedNames = new Set(['token', '__proto__', 'constructor', 'prototype']);\r\n\r\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\r\n if (value === null || typeof value !== 'object') return false;\r\n const prototype = Object.getPrototypeOf(value);\r\n if (prototype === null) return true;\r\n // Object.prototype differs between same-origin windows. Compare its native\r\n // constructor instead of requiring this window's exact prototype identity.\r\n return Object.getPrototypeOf(prototype) === null &&\r\n Object.prototype.hasOwnProperty.call(prototype, 'constructor') &&\r\n typeof prototype.constructor === 'function' &&\r\n Function.prototype.toString.call(prototype.constructor) === Function.prototype.toString.call(Object);\r\n}\r\n\r\n/** Snapshot once so parameter/attribute getters cannot later replace the address. */\r\nexport function prepareIframeAttributes(attrs: Record<string, string> = {}): Record<string, string> {\r\n if (!isPlainObject(attrs)) throw new Error('iframeAttrs must be a plain object');\r\n const entries = Object.entries(attrs);\r\n for (const [name] of entries) {\r\n const normalized = name.trim().toLowerCase();\r\n if (normalized === 'src' || normalized === 'srcdoc') {\r\n throw new Error(`iframeAttrs.${name} cannot override the SDK page address`);\r\n }\r\n // eslint-disable-next-line no-control-regex -- Intentionally reject ASCII control characters in attribute names.\r\n if (!name || /[\\s\"'>/=\\u0000-\\u001f]/.test(name)) {\r\n throw new Error(`Invalid iframe attribute name: ${name}`);\r\n }\r\n }\r\n return Object.fromEntries(entries);\r\n}\r\n\r\nfunction encodeSegment(value: string, name: string): string {\r\n if (!value || value === '.' || value === '..') {\r\n throw new Error(`${name} must be a non-empty path segment other than . or ..`);\r\n }\r\n return encodeURIComponent(value);\r\n}\r\n\r\n/** Build and validate the complete iframe address before any DOM is created. */\r\nexport function buildEmbedUrl(baseUrl: string, options: EmbedOptions): string {\r\n if (!options.token) throw new Error('Token is required');\r\n const apiName = String(options.apiName || options.pageCode || options.pageId || '').trim();\r\n if (!apiName) {\r\n throw new Error('Either apiName, pageCode (deprecated), or pageId (deprecated) is required');\r\n }\r\n const url = new URL(`/apps/${encodeSegment(options.appId, 'appId')}/user/${encodeSegment(apiName, 'apiName')}`, baseUrl);\r\n url.searchParams.set('token', options.token);\r\n const params = options.params;\r\n if (params !== undefined) {\r\n if (!isPlainObject(params)) {\r\n throw new Error('params must be a plain object');\r\n }\r\n for (const [name, value] of Object.entries(params)) {\r\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) || reservedNames.has(name)) {\r\n throw new Error(`Invalid or reserved parameter name: ${name}`);\r\n }\r\n if (value === null || value === undefined) continue;\r\n if (!['string', 'number', 'boolean'].includes(typeof value) ||\r\n (typeof value === 'number' && !Number.isFinite(value))) {\r\n throw new Error(`Parameter ${name} must be a string, finite number, or boolean`);\r\n }\r\n url.searchParams.set(name, String(value));\r\n }\r\n }\r\n return url.toString();\r\n}\r\n","import type {\r\n SDKConfig,\r\n EmbedOptions,\r\n ApassInstanceRef,\r\n} from '../types';\r\nimport { buildEmbedUrl, prepareIframeAttributes } from './embedUrl';\r\n\r\n/**\r\n * Main SDK class for embedding A-pass applications\r\n *\r\n * @example\r\n * ```ts\r\n * const sdk = new ApassEmbedSDK({\r\n * baseUrl: 'https://apass.example.com',\r\n * });\r\n *\r\n * // CRM 项目先调自己的后端获取 token\r\n * const tokenResponse = await fetch('/api/embed-token', {\r\n * method: 'POST',\r\n * body: JSON.stringify({\r\n * recordId: 416,\r\n * enterpriseId: 456,\r\n * }),\r\n * });\r\n * const { token } = await tokenResponse.json();\r\n *\r\n * // 然后把 token 传给 SDK\r\n * await sdk.embed({\r\n * appId: '180',\r\n * apiName: 'patient_list',\r\n * token: token,\r\n * containerId: 'my-container',\r\n * });\r\n * ```\r\n */\r\nexport class ApassEmbedSDK {\r\n private config: SDKConfig;\r\n private instances: Map<string, ApassInstanceRef> = new Map();\r\n private instanceCounter = 0;\r\n\r\n constructor(config: SDKConfig) {\r\n this.validateConfig(config);\r\n this.config = {\r\n timeout: 30000,\r\n ...config,\r\n };\r\n }\r\n\r\n /**\r\n * Embed an A-pass application in an iframe\r\n */\r\n async embed(options: EmbedOptions): Promise<ApassInstanceRef> {\r\n const {\r\n apiName,\r\n pageCode,\r\n pageId,\r\n token,\r\n containerId,\r\n onReady,\r\n onClose,\r\n onError,\r\n iframeAttrs = {},\r\n fullscreen = false,\r\n } = options;\r\n\r\n try {\r\n const url = buildEmbedUrl(this.config.baseUrl, options);\r\n const attrs = prepareIframeAttributes(iframeAttrs);\r\n // Warn if using deprecated parameters\r\n if (pageCode && !apiName) {\r\n console.warn('[MediPaaS SDK] pageCode is deprecated. Please use apiName instead.');\r\n }\r\n if (pageId && !apiName && !pageCode) {\r\n console.warn('[MediPaaS SDK] pageId is deprecated. Please use apiName instead.');\r\n }\r\n\r\n // Prepare the detached iframe first: DOM attribute validation must finish\r\n // before a default overlay is attached to the host page.\r\n const iframe = this.createIframe(url, attrs);\r\n const container = this.prepareContainer(containerId, fullscreen);\r\n\r\n // Step 5: Setup lifecycle handlers\r\n const instanceId = `apass-${++this.instanceCounter}`;\r\n\r\n const instance: ApassInstanceRef = {\r\n iframe,\r\n token,\r\n expiresAt: 0, // Token expiration not tracked in this mode\r\n close: () => {\r\n this.closeInstance(instanceId);\r\n onClose?.();\r\n },\r\n };\r\n\r\n // Step 6: Append iframe to container\r\n container.appendChild(iframe);\r\n\r\n // Step 7: Setup ready handler\r\n iframe.onload = () => {\r\n onReady?.();\r\n };\r\n\r\n // Step 8: Setup error handler\r\n iframe.onerror = () => {\r\n const error = new Error('Failed to load A-pass iframe');\r\n onError?.(error);\r\n };\r\n\r\n // Store instance reference\r\n this.instances.set(instanceId, instance);\r\n\r\n return instance;\r\n } catch (error) {\r\n const err =\r\n error instanceof Error ? error : new Error(String(error));\r\n onError?.(err);\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Close and cleanup an instance\r\n */\r\n private closeInstance(instanceId: string): void {\r\n const instance = this.instances.get(instanceId);\r\n if (instance) {\r\n // Remove iframe from DOM\r\n instance.iframe.remove();\r\n // Remove from tracking\r\n this.instances.delete(instanceId);\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Prepare container for iframe\r\n */\r\n private prepareContainer(\r\n containerId: string | undefined,\r\n fullscreen: boolean,\r\n ): HTMLElement {\r\n if (containerId) {\r\n const container = document.getElementById(containerId);\r\n if (!container) {\r\n throw new Error(`Container with id \"${containerId}\" not found`);\r\n }\r\n return container;\r\n }\r\n\r\n // Create default container\r\n const container = document.createElement('div');\r\n container.style.cssText = `\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n width: 100%;\r\n height: 100%;\r\n z-index: 10000;\r\n background: rgba(0, 0, 0, 0.5);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n `;\r\n\r\n const wrapper = document.createElement('div');\r\n if (fullscreen) {\r\n wrapper.style.cssText = `\r\n width: 100%;\r\n height: 100%;\r\n `;\r\n } else {\r\n wrapper.style.cssText = `\r\n width: 90%;\r\n height: 90%;\r\n max-width: 1200px;\r\n max-height: 800px;\r\n border-radius: 8px;\r\n overflow: hidden;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n `;\r\n }\r\n\r\n container.appendChild(wrapper);\r\n document.body.appendChild(container);\r\n\r\n // Auto-close on background click\r\n container.addEventListener('click', (e) => {\r\n if (e.target === container) {\r\n container.remove();\r\n }\r\n });\r\n\r\n return wrapper;\r\n }\r\n\r\n /**\r\n * Create iframe element\r\n */\r\n private createIframe(\r\n url: string,\r\n attrs: Record<string, string>,\r\n ): HTMLIFrameElement {\r\n const iframe = document.createElement('iframe');\r\n\r\n // Build A-pass URL with token parameter\r\n iframe.src = url;\r\n iframe.style.cssText = `\r\n width: 100%;\r\n height: 100%;\r\n border: none;\r\n `;\r\n\r\n // Apply custom attributes\r\n Object.entries(attrs).forEach(([key, value]) => {\r\n iframe.setAttribute(key, value);\r\n });\r\n\r\n return iframe;\r\n }\r\n\r\n /**\r\n * Validate SDK configuration\r\n */\r\n private validateConfig(config: SDKConfig): void {\r\n if (!config.baseUrl) {\r\n throw new Error('SDKConfig.baseUrl is required');\r\n }\r\n\r\n try {\r\n new URL(config.baseUrl);\r\n } catch {\r\n throw new Error(\r\n `SDKConfig.baseUrl must be a valid URL: ${config.baseUrl}`,\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Close all instances\r\n */\r\n closeAll(): void {\r\n this.instances.forEach((_, instanceId) => {\r\n this.closeInstance(instanceId);\r\n });\r\n }\r\n\r\n /**\r\n * Get active instances count\r\n */\r\n getInstanceCount(): number {\r\n return this.instances.size;\r\n }\r\n}\r\n"],"mappings":"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","names":["reservedNames","isPlainObject","value","prototype","prepareIframeAttributes","attrs","entries","name","normalized","encodeSegment","buildEmbedUrl","baseUrl","options","apiName","url","params","ApassEmbedSDK","config","__publicField","options","apiName","pageCode","pageId","token","containerId","onReady","onClose","onError","iframeAttrs","fullscreen","url","buildEmbedUrl","attrs","prepareIframeAttributes","iframe","container","instanceId","instance","error","err","wrapper","e","key","value","_"]}
1
+ {"version":3,"sources":["../src/core/embedUrl.ts","../src/core/sdk.ts"],"sourcesContent":["import type { EmbedOptions } from '../types';\r\n\r\nconst reservedNames = new Set(['token', '__proto__', 'constructor', 'prototype']);\r\n\r\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\r\n if (value === null || typeof value !== 'object') return false;\r\n const prototype = Object.getPrototypeOf(value);\r\n if (prototype === null) return true;\r\n // Object.prototype differs between same-origin windows. Compare its native\r\n // constructor instead of requiring this window's exact prototype identity.\r\n return Object.getPrototypeOf(prototype) === null &&\r\n Object.prototype.hasOwnProperty.call(prototype, 'constructor') &&\r\n typeof prototype.constructor === 'function' &&\r\n Function.prototype.toString.call(prototype.constructor) === Function.prototype.toString.call(Object);\r\n}\r\n\r\n/** Snapshot once so parameter/attribute getters cannot later replace the address. */\r\nexport function prepareIframeAttributes(attrs: Record<string, string> = {}): Record<string, string> {\r\n if (!isPlainObject(attrs)) throw new Error('iframeAttrs must be a plain object');\r\n const entries = Object.entries(attrs);\r\n for (const [name] of entries) {\r\n const normalized = name.trim().toLowerCase();\r\n if (normalized === 'src' || normalized === 'srcdoc') {\r\n throw new Error(`iframeAttrs.${name} cannot override the SDK page address`);\r\n }\r\n // eslint-disable-next-line no-control-regex -- Intentionally reject ASCII control characters in attribute names.\r\n if (!name || /[\\s\"'>/=\\u0000-\\u001f]/.test(name)) {\r\n throw new Error(`Invalid iframe attribute name: ${name}`);\r\n }\r\n }\r\n return Object.fromEntries(entries);\r\n}\r\n\r\nfunction encodeSegment(value: string, name: string): string {\r\n if (!value || value === '.' || value === '..') {\r\n throw new Error(`${name} must be a non-empty path segment other than . or ..`);\r\n }\r\n return encodeURIComponent(value);\r\n}\r\n\r\n/** Build and validate the complete iframe address before any DOM is created. */\r\nexport function buildEmbedUrl(baseUrl: string, options: EmbedOptions): string {\r\n if (!options.token) throw new Error('Token is required');\r\n const apiName = String(options.apiName || options.pageCode || options.pageId || '').trim();\r\n if (!apiName) {\r\n throw new Error('Either apiName, pageCode (deprecated), or pageId (deprecated) is required');\r\n }\r\n const url = new URL(`/apps/${encodeSegment(options.appId, 'appId')}/user/${encodeSegment(apiName, 'apiName')}`, baseUrl);\r\n url.searchParams.set('token', options.token);\r\n const params = options.params;\r\n if (params !== undefined) {\r\n if (!isPlainObject(params)) {\r\n throw new Error('params must be a plain object');\r\n }\r\n for (const [name, value] of Object.entries(params)) {\r\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) || reservedNames.has(name)) {\r\n throw new Error(`Invalid or reserved parameter name: ${name}`);\r\n }\r\n if (value === null || value === undefined) continue;\r\n if (!['string', 'number', 'boolean'].includes(typeof value) ||\r\n (typeof value === 'number' && !Number.isFinite(value))) {\r\n throw new Error(`Parameter ${name} must be a string, finite number, or boolean`);\r\n }\r\n url.searchParams.set(name, String(value));\r\n }\r\n }\r\n return url.toString();\r\n}\r\n","import type {\r\n SDKConfig,\r\n EmbedOptions,\r\n ApassInstanceRef,\r\n} from '../types';\r\nimport { buildEmbedUrl, prepareIframeAttributes } from './embedUrl';\r\n\r\n/**\r\n * Main SDK class for embedding A-pass applications\r\n *\r\n * @example\r\n * ```ts\r\n * const sdk = new ApassEmbedSDK({\r\n * baseUrl: 'https://apass.example.com',\r\n * });\r\n *\r\n * // CRM 项目先调自己的后端获取 token\r\n * const tokenResponse = await fetch('/api/embed-token', {\r\n * method: 'POST',\r\n * body: JSON.stringify({\r\n * recordId: 416,\r\n * enterpriseId: 456,\r\n * }),\r\n * });\r\n * const { token } = await tokenResponse.json();\r\n *\r\n * // 然后把 token 传给 SDK\r\n * await sdk.embed({\r\n * appId: '180',\r\n * apiName: 'patient_list',\r\n * token: token,\r\n * containerId: 'my-container',\r\n * });\r\n * ```\r\n */\r\nexport class ApassEmbedSDK {\r\n private config: SDKConfig;\r\n private instances: Map<string, ApassInstanceRef> = new Map();\n private cleanups: Map<string, () => void> = new Map();\n private instanceCounter = 0;\r\n\r\n constructor(config: SDKConfig) {\r\n this.validateConfig(config);\r\n this.config = {\r\n timeout: 30000,\r\n ...config,\r\n };\r\n }\r\n\r\n /**\r\n * Embed an A-pass application in an iframe\r\n */\r\n async embed(options: EmbedOptions): Promise<ApassInstanceRef> {\r\n const {\r\n apiName,\r\n pageCode,\r\n pageId,\r\n token,\r\n containerId,\r\n onReady,\n onBridgeReady,\n onClose,\r\n onError,\n onEvent,\n iframeAttrs = {},\r\n fullscreen = false,\r\n } = options;\r\n\r\n try {\r\n const url = buildEmbedUrl(this.config.baseUrl, options);\r\n const attrs = prepareIframeAttributes(iframeAttrs);\r\n // Warn if using deprecated parameters\r\n if (pageCode && !apiName) {\r\n console.warn('[MediPaaS SDK] pageCode is deprecated. Please use apiName instead.');\r\n }\r\n if (pageId && !apiName && !pageCode) {\r\n console.warn('[MediPaaS SDK] pageId is deprecated. Please use apiName instead.');\r\n }\r\n\r\n // Prepare the detached iframe first: DOM attribute validation must finish\r\n // before a default overlay is attached to the host page.\r\n const iframe = this.createIframe(url, attrs);\r\n const container = this.prepareContainer(containerId, fullscreen);\r\n\r\n // Step 5: Setup lifecycle handlers\r\n const instanceId = `apass-${++this.instanceCounter}`;\n const channelId = crypto.randomUUID();\n const targetOrigin = new URL(url).origin;\n let ready = false;\n const receiveMessage = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow || event.origin !== targetOrigin) return;\n const message = event.data;\n if (!message || typeof message !== 'object' || Array.isArray(message)) return;\n if (message.type === 'ready') {\n if (message.namespace === 'medipaas.embed' && message.version === 1\n && message.channelId === channelId && !ready) {\n ready = true;\n onBridgeReady?.();\n }\n return;\n }\n // Business scripts can post { name, payload } directly, without a handshake.\n if ((message.type === undefined || message.type === 'event')\n && typeof message.name === 'string' && message.name.trim()) {\n onEvent?.({ name: message.name, payload: message.payload });\n }\n };\n window.addEventListener('message', receiveMessage);\n\n const instance: ApassInstanceRef = {\n iframe,\r\n token,\r\n expiresAt: 0, // Token expiration not tracked in this mode\r\n close: () => {\n this.closeInstance(instanceId);\n onClose?.();\n },\n send: (name, payload) => {\n if (!ready || !this.instances.has(instanceId)) return false;\n if (name !== 'page.refresh' && name !== 'params.update') return false;\n try {\n iframe.contentWindow?.postMessage({ namespace: 'medipaas.embed', version: 1,\n channelId, type: 'event', name, payload }, targetOrigin);\n return true;\n } catch {\n return false;\n }\n },\n };\n\n if (!containerId) {\n const overlay = container.parentElement!;\n overlay.dataset.apassOverlay = instanceId;\n overlay.addEventListener('click', (event) => {\n if (event.target === overlay) instance.close();\n });\n }\n\r\n // Step 6: Setup ready handler before attaching the iframe\n iframe.onload = () => {\n ready = false;\n iframe.contentWindow?.postMessage({ namespace: 'medipaas.embed', version: 1,\n channelId, type: 'hello' }, targetOrigin);\n onReady?.();\n };\r\n\r\n // Step 8: Setup error handler\r\n iframe.onerror = () => {\n const error = new Error('Failed to load A-pass iframe');\r\n onError?.(error);\r\n };\n\n container.appendChild(iframe);\n\r\n // Store instance reference\r\n this.instances.set(instanceId, instance);\n this.cleanups.set(instanceId, () => window.removeEventListener('message', receiveMessage));\n\r\n return instance;\r\n } catch (error) {\r\n const err =\r\n error instanceof Error ? error : new Error(String(error));\r\n onError?.(err);\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Close and cleanup an instance\r\n */\r\n private closeInstance(instanceId: string): void {\n const instance = this.instances.get(instanceId);\r\n if (instance) {\n this.cleanups.get(instanceId)?.();\n this.cleanups.delete(instanceId);\n // Remove iframe from DOM\n const overlay = instance.iframe.parentElement?.parentElement;\n instance.iframe.remove();\n if (overlay?.dataset.apassOverlay === instanceId) overlay.remove();\n // Remove from tracking\r\n this.instances.delete(instanceId);\r\n }\r\n }\n\r\n\r\n /**\r\n * Prepare container for iframe\r\n */\r\n private prepareContainer(\r\n containerId: string | undefined,\r\n fullscreen: boolean,\r\n ): HTMLElement {\r\n if (containerId) {\r\n const container = document.getElementById(containerId);\r\n if (!container) {\r\n throw new Error(`Container with id \"${containerId}\" not found`);\r\n }\r\n return container;\r\n }\r\n\r\n // Create default container\r\n const container = document.createElement('div');\r\n container.style.cssText = `\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n width: 100%;\r\n height: 100%;\r\n z-index: 10000;\r\n background: rgba(0, 0, 0, 0.5);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n `;\r\n\r\n const wrapper = document.createElement('div');\r\n if (fullscreen) {\r\n wrapper.style.cssText = `\r\n width: 100%;\r\n height: 100%;\r\n `;\r\n } else {\r\n wrapper.style.cssText = `\r\n width: 90%;\r\n height: 90%;\r\n max-width: 1200px;\r\n max-height: 800px;\r\n border-radius: 8px;\r\n overflow: hidden;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n `;\r\n }\r\n\r\n container.appendChild(wrapper);\r\n document.body.appendChild(container);\r\n\r\n return wrapper;\n }\r\n\r\n /**\r\n * Create iframe element\r\n */\r\n private createIframe(\r\n url: string,\r\n attrs: Record<string, string>,\r\n ): HTMLIFrameElement {\r\n const iframe = document.createElement('iframe');\r\n\r\n // Build A-pass URL with token parameter\r\n iframe.src = url;\r\n iframe.style.cssText = `\r\n width: 100%;\r\n height: 100%;\r\n border: none;\r\n `;\r\n\r\n // Apply custom attributes\r\n Object.entries(attrs).forEach(([key, value]) => {\r\n iframe.setAttribute(key, value);\r\n });\r\n\r\n return iframe;\r\n }\r\n\r\n /**\r\n * Validate SDK configuration\r\n */\r\n private validateConfig(config: SDKConfig): void {\r\n if (!config.baseUrl) {\r\n throw new Error('SDKConfig.baseUrl is required');\r\n }\r\n\r\n try {\r\n new URL(config.baseUrl);\r\n } catch {\r\n throw new Error(\r\n `SDKConfig.baseUrl must be a valid URL: ${config.baseUrl}`,\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Close all instances\r\n */\r\n closeAll(): void {\r\n this.instances.forEach((_, instanceId) => {\r\n this.closeInstance(instanceId);\r\n });\r\n }\r\n\r\n /**\r\n * Get active instances count\r\n */\r\n getInstanceCount(): number {\r\n return this.instances.size;\r\n }\r\n}\r\n"],"mappings":"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","names":["reservedNames","isPlainObject","value","prototype","prepareIframeAttributes","attrs","entries","name","normalized","encodeSegment","buildEmbedUrl","baseUrl","options","apiName","url","params","ApassEmbedSDK","config","__publicField","options","apiName","pageCode","pageId","token","containerId","onReady","onBridgeReady","onClose","onError","onEvent","iframeAttrs","fullscreen","url","buildEmbedUrl","attrs","prepareIframeAttributes","iframe","container","instanceId","channelId","targetOrigin","ready","receiveMessage","event","message","instance","name","payload","overlay","error","err","wrapper","key","value","_"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obm/apaas-embed-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "SDK for embedding A-pass pages into third-party applications using embed tokens",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",