@ckylinmc/mp-sdk 0.1.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/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@ckylinmc/mp-sdk",
3
+ "version": "0.1.0",
4
+ "description": "小程序桥 SDK(个人项目,非公开使用,见 README 声明)",
5
+ "license": "Unlicense",
6
+ "type": "module",
7
+ "main": "./dist/ckylmp.js",
8
+ "types": "./dist/ckylmp.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/ckylmp.d.ts",
12
+ "import": "./dist/ckylmp.js",
13
+ "default": "./dist/ckylmp.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "skills",
19
+ "UNLICENSE"
20
+ ],
21
+ "sideEffects": false,
22
+ "scripts": {
23
+ "build": "tsc -p tsconfig.json",
24
+ "prepack": "npm run build"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "keywords": [
30
+ "ckyl",
31
+ "ckylin",
32
+ "lynx",
33
+ "miniapp",
34
+ "bridge"
35
+ ],
36
+ "devDependencies": {
37
+ "typescript": "^5.5.0"
38
+ },
39
+ "engines": {
40
+ "node": ">=18"
41
+ }
42
+ }
@@ -0,0 +1,32 @@
1
+ # skills
2
+
3
+ 本目录存放「AI 可导入技能」,供开发 AI 助手(DSH / Claude / Cursor 等)在编写与排查
4
+ CKyLyn 小程序桥代码时使用。
5
+
6
+ ## 目录
7
+
8
+ | 技能 | 用途 |
9
+ |---|---|
10
+ | `ckylmp-sdk/` | CKyLyn 小程序桥 SDK(@ckylinmc/mp-sdk)使用速查:接入模式、权限契约、API 速查、错误码、降级矩阵 |
11
+
12
+ > 完整参考文档在仓库 `docs/` 下(`API.md` / `PERMISSIONS.md` / `ERRORS.md` /
13
+ > `EVENTS.md` / `WORKFLOW.md`),技能正文为自包含速查版。
14
+
15
+ ## 导入方法(DSH)
16
+
17
+ ```bash
18
+ # 从本仓库导入
19
+ cp -r skills/ckylmp-sdk ~/.dsh/skills/
20
+
21
+ # 或从 npm 安装后的包内导入(skills 随包分发,docs 不随包)
22
+ cp -r node_modules/@ckylinmc/mp-sdk/skills/* ~/.dsh/skills/
23
+ ```
24
+
25
+ 其他 AI 助手:把 `skills/<name>/` 整个目录复制到该工具的技能目录即可
26
+ (如 Claude Code 的 `~/.claude/skills/`)。
27
+
28
+ ## 格式约定
29
+
30
+ 每个技能是一个目录,内含 `SKILL.md`(YAML frontmatter:`name` + `description`,
31
+ 正文为使用说明;可附带 references/ 等资源文件)。与
32
+ [lynx-community/skills](https://github.com/lynx-community/skills) 的快照格式一致。
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: ckylmp-sdk
3
+ description: "Use when writing, reviewing, or debugging CKyLyn 宿主小程序(ReactLynx miniapp)的桥 SDK 代码:requestPerms/权限申请、getToken/getProfile、store、share、download、scanQR、getLocation、sendIntent、文件能力(writeFile/selectFolder/selectFiles/readFile/selectMedia/controlFolder)、WebRTC、streamHttp、推送事件订阅与错误码处理。涵盖@ckylinmc/mp-sdk 的接入模式(npm + background-only 包装层)、CkylMpError 错误码、双通道降级与宿主权限契约。"
4
+ ---
5
+
6
+ # ckylmp-sdk
7
+
8
+ CKyLyn 小程序桥 SDK(`@ckylinmc/mp-sdk`):单文件、零依赖、TypeScript 编写。
9
+ 本技能内容自包含(速查),完整参考在**仓库内** `docs/`(`API.md`/`PERMISSIONS.md`/
10
+ `ERRORS.md`/`EVENTS.md`/`WORKFLOW.md`,npm 包不含 docs)。
11
+
12
+ ## 双通道模型
13
+
14
+ 1. **事件桥**(`CkylMpBridge`,永久保留):交互/低频/推送型——权限弹窗、SAF 选择/保存
15
+ 对话框、下载、定位、扫码、deeplink/返回、`http.stream`、controlFolder 文本操作、
16
+ WebRTC 信令(SDP/ICE)。回执按 msgid 关联,SDK 默认 10s 超时。
17
+ 2. **原生模块**(`CkylMpFile`/`CkylMpWebRtc`/`CkylMpShare`):二进制/高频——文件字节、
18
+ WebRTC 实时收发、非文本分享,`byte[] ↔ ArrayBuffer` 直达,无 base64。
19
+
20
+ SDK 用 `hasNativeCapability(name)` 探测宿主;缺模块(旧宿主)按降级矩阵处理:
21
+ 写入/文本分享自动回退事件桥,**读取(readFileBytes)/文件分享明确失败 `NOT_IMPLEMENTED`**
22
+ (绝不降级到不等价能力)。
23
+
24
+ ## 接入模式(ReactLynx 双线程纪律)
25
+
26
+ ```ts
27
+ // src/lib/ckylmp.ts(项目内包装层,必须)
28
+ import "background-only";
29
+ export * from "@ckylinmc/mp-sdk";
30
+ ```
31
+
32
+ - 业务统一从 `./lib/ckylmp` 导入,不要直接在业务模块 import `@ckylinmc/mp-sdk`;
33
+ - 桥调用只在事件处理器 / `useEffect` / 显式后台函数(`'background only'` 指令);
34
+ - 渲染作用域(JSX 表达式、useState 初始化器)禁止引用桥标识符;纯类型用
35
+ `import type { ... } from "@ckylinmc/mp-sdk"`;
36
+ - 首次 `invoke`/`on` 惰性注册 `GlobalEventEmitter` 监听(**仅后台线程生效**),
37
+ 首帧后台触发一次 `requestPerms` 完成注册。
38
+
39
+ ## 权限契约(15 项可申请 + 1 隐式)
40
+
41
+ 后端 `mpindex.perms` 声明制:**未声明 = 零权限**(fail-closed);申请未声明 key →
42
+ `PERM_NOT_DECLARED`(`extra.undeclared` 列问题项,整批拒绝)。
43
+
44
+ `store` `token` `profile` `sendintent` `webrtc` `share` `download` `scanqr` `location`
45
+ `writefile` `selectfolder` `selectfile` `readfile` `selectmedia` `controlfolder`
46
+
47
+ - `token` 是唯一云同步项(userconnect;勾选即写云授权,含「仅一次」);
48
+ - 三态裁决:`ONCE`(仅进程内存,任务结束失效)/ `ALWAYS` / `DENIED`;
49
+ 全部已裁决 → `requestPerms` 立即返回不弹窗;
50
+ - `backevent` 隐式权限:perms 声明即生效(单次返回推送 `back_press`、宿主不退出),
51
+ 不可申请(申请报 `PERM_NOT_DECLARED`)、不询问、不列出;
52
+ - `controlfolder` scope 逐项授权:`requestFolderScope(绝对路径前缀)` → 说明弹窗 +
53
+ SAF 选目录(所选目录必须落在 scope 下,否则 `SCOPE_REJECTED`)→ 操作路径最长前缀
54
+ 命中 + 穿越拒绝(未命中 `SCOPE_NOT_GRANTED`)。
55
+
56
+ ## 核心 API 速查
57
+
58
+ | API | 权限 | 要点 |
59
+ |---|---|---|
60
+ | `requestPerms(perms)` | — | 批量申请;返回生效允许 key 列表;空数组 `BAD_REQUEST` |
61
+ | `getToken()` | `token` | 作用域子 token;未授权 `PERM_DENIED`;未登录 `AUTH_REQUIRED` |
62
+ | `getProfile()` | `profile` | `{userId,nickname,avatar?}`;未登录 `AUTH_REQUIRED` |
63
+ | `getLaunchOptions()` | — | 冷启动 deeplink `{query:[[k,v],...]}`(globalProps 注入,同步读) |
64
+ | `onDeeplinkCalled(h)` | — | 已启动带参 deeplink 推送;无参数不推送 |
65
+ | `onBackPress(h)`/`exitApp()` | backevent | 单次返回推送 `back_press`;返回到顶 `exitApp()` 自决退出 |
66
+ | `store.*` | `store` | 隔离 KV;`get` 缺键返回 `null` |
67
+ | `share({text?,file?})` | `share` | 纯文本走事件桥;`file({data\|uri,...})` 原生模块字节直达 ≤32MB |
68
+ | `download({url,...})` | `download` | 仅 http/https;进度每秒推送;`openAfterComplete` 失败带 `openFailed` |
69
+ | `scanQR()` | `scanqr` | 取消 `USER_CANCELLED`;SDK 超时 120s |
70
+ | `getLocation({timeoutMs?})` | `location` | 运行时权限被拒 `PERM_DENIED`;超时 `INTERNAL`;超时 = timeoutMs+5s |
71
+ | `sendIntent(spec)` | `sendintent` | 仅 action/data/categories/package/string extras |
72
+ | `writeFile({filename?,data,...})` | `writefile` | 宿主保存对话框;二进制输入字节直达 ≤32MB;旧宿主回退 base64 |
73
+ | `selectFolder`/`selectFiles`/`selectMedia` | 对应权限 | SAF/Photo Picker;取消 `USER_CANCELLED`;selectMedia 过滤未命中进 `skipped` |
74
+ | `readFile({uri,...})` | `readfile` | ≤1MB(文本/base64);超限 `FILE_TOO_LARGE`;非 UTF-8 文本 `BAD_REQUEST` |
75
+ | `readFileBytes({uri,maxBytes?})` | `readfile` | 字节直达;默认 8MB/上限 16MB;旧宿主 `NOT_IMPLEMENTED` |
76
+ | `controlFolder.*` | `controlfolder` | createDir/createFile/writeFile(±Bytes)/readFile(±Bytes)/list/rename/delete/copy/move |
77
+ | `streamHttp(req,handlers)` | — | 宿主 SSE 代理逐行推送;先订阅后 invoke;`cancel()` 幂等 |
78
+ | `on/off`, `hasNativeCapability`, `isBridgeAvailable` | — | 通用订阅/探测 |
79
+
80
+ WebRTC:`createPeerConnection(config)` → `createOffer/setLocalDescription` → 信令交换
81
+ (小程序自身网络通道)→ `setRemoteDescription/addIceCandidate` → `createDataChannel`/
82
+ `setMicrophone`(首开触发系统权限,拒绝 `PERM_DENIED`)。数据通道单条:二进制 ≤256KB
83
+ (`sendBytes`,自行分帧)、文本 ≤64KB;入站二进制 `msg.bytes`(ArrayBuffer)。
84
+
85
+ 限制速记:`list` 10000 条目/深度 32;写入 32MB/次;`readFile` ≤1MB;
86
+ `selectMedia` 多选上限 20、URI 为临时授权(尽快读取/复制)。
87
+
88
+ ## 错误码表(CkylMpError)
89
+
90
+ `BAD_REQUEST`(参数/Intent/目录操作)· `PERM_NOT_DECLARED`(未声明,extra.undeclared)·
91
+ `PERM_DENIED`(未授权/运行时权限被拒)· `AUTH_REQUIRED`(宿主未登录)·
92
+ `USER_CANCELLED`(用户取消)· `FILE_TOO_LARGE`(1MB/16MB 超限)·
93
+ `SCOPE_NOT_GRANTED`(未命中 scope/授权失效)· `SCOPE_REJECTED`(选目录不符,extra.picked)·
94
+ `NOT_IMPLEMENTED`(SDK 本地:无桥/缺原生模块)· `TIMEOUT`(SDK 兜底)· `INTERNAL`。
95
+
96
+ 超时语义:默认 10s;scanQR 120s;文件类 5 分钟;二进制读取 2 分钟;webrtc 30s;
97
+ setMicrophone 60s。
98
+
99
+ ## Rules
100
+
101
+ - 凡涉及权限能力,必须先 `requestPerms` 且后端 `perms` 已声明——未声明一律
102
+ `PERM_NOT_DECLARED`,不要假设可申请;
103
+ - `PERM_DENIED` 是确定性状态:提示用户,不循环重试弹窗;
104
+ - 二进制进出优先字节通道(`readFileBytes`/`sendBytes`/`writeFileBytes`),
105
+ base64 仅旧宿主回退路径;
106
+ - 书签式的能力细节(参数表/返回结构/每 API 行为/完整示例)以本仓库
107
+ `docs/API.md` 为准;推送事件载荷见 `docs/EVENTS.md`;打包与上传流程见
108
+ `docs/WORKFLOW.md`(`{APP_ID}.lynx.bundle.zip`,APP_ID 取 package.json name,
109
+ dist 内容平铺根级,不带 dist 层级)。