@open-dy/vibecoding-sdk-taro 0.1.11 → 0.1.13

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.
Files changed (47) hide show
  1. package/dist/adapters/interest-card/eslint/taro.mjs +1 -0
  2. package/dist/adapters/interest-card/runtime/microapp.d.ts +1 -1
  3. package/dist/adapters/interest-card/runtime/microapp.js +1 -1
  4. package/dist/adapters/interest-card/runtime/microapp.js.map +1 -1
  5. package/dist/eslint/card-profile.mjs +96 -0
  6. package/dist/eslint/eslint-plugin-post-card.mjs +82 -0
  7. package/dist/eslint/taro.mjs +10 -0
  8. package/dist/reference/llms.txt +3 -1
  9. package/dist/reference/sdk-api/runtime/CreateMicroappClientOptions.md +3 -1
  10. package/dist/reference/sdk-api/runtime/PreparedImageForUpload.md +52 -0
  11. package/dist/reference/sdk-api/runtime/createMicroappClient.md +4 -3
  12. package/dist/reference/sdk-api/runtime/index.md +3 -1
  13. package/dist/reference/sdk-api/runtime/prepareImageForUpload.md +69 -0
  14. package/dist/reference/sdk-api.json +144 -6
  15. package/dist/reference/sdk-api.md +2 -0
  16. package/dist/runtime/client.d.ts +3 -1
  17. package/dist/runtime/client.js +20 -5
  18. package/dist/runtime/client.js.map +1 -1
  19. package/dist/runtime/default-client.d.ts +2 -2
  20. package/dist/runtime/default-client.js +2 -2
  21. package/dist/runtime/douyin-container-request.d.ts +3 -2
  22. package/dist/runtime/douyin-container-request.js +24 -15
  23. package/dist/runtime/douyin-container-request.js.map +1 -1
  24. package/dist/runtime/globals.d.ts +2 -2
  25. package/dist/runtime/image-upload-preparation.d.ts +39 -0
  26. package/dist/runtime/image-upload-preparation.js +190 -0
  27. package/dist/runtime/image-upload-preparation.js.map +1 -0
  28. package/dist/runtime/index.d.ts +1 -0
  29. package/dist/runtime/index.js +1 -0
  30. package/dist/runtime/index.js.map +1 -1
  31. package/dist/runtime/prepared-upload-task.d.ts +3 -0
  32. package/dist/runtime/prepared-upload-task.js +91 -0
  33. package/dist/runtime/prepared-upload-task.js.map +1 -0
  34. package/package.json +1 -1
  35. package/release-provenance.json +4 -4
  36. package/src/adapters/interest-card/eslint/taro.mjs +1 -0
  37. package/src/adapters/interest-card/runtime/microapp.ts +2 -0
  38. package/src/eslint/card-profile.mjs +2 -0
  39. package/src/eslint/eslint-plugin-post-card.mjs +82 -0
  40. package/src/eslint/taro.mjs +10 -0
  41. package/src/runtime/client.ts +25 -5
  42. package/src/runtime/default-client.ts +2 -2
  43. package/src/runtime/douyin-container-request.ts +26 -20
  44. package/src/runtime/globals.d.ts +2 -2
  45. package/src/runtime/image-upload-preparation.ts +225 -0
  46. package/src/runtime/index.ts +1 -0
  47. package/src/runtime/prepared-upload-task.ts +86 -0
@@ -1,3 +1,4 @@
1
+ export { CARD_TYPE_RULES_VERSION } from '../../../eslint/taro.mjs'
1
2
  import { createMicroappTaroEslintConfig } from '../../../eslint/taro.mjs'
2
3
 
3
4
  /**
@@ -4,4 +4,4 @@
4
4
  * 此适配层只提供稳定的兴趣卡导入路径;请求、登录和传输能力仍由通用
5
5
  * microapp Runtime 实现,避免在业务域内复制基础逻辑。
6
6
  */
7
- export { clearDouyinLoginAuth, createMicroappClient, type CreateMicroappClientOptions, } from '../../../runtime/index.js';
7
+ export { clearDouyinLoginAuth, createMicroappClient, prepareImageForUpload, type CreateMicroappClientOptions, type PreparedImageForUpload, } from '../../../runtime/index.js';
@@ -4,5 +4,5 @@
4
4
  * 此适配层只提供稳定的兴趣卡导入路径;请求、登录和传输能力仍由通用
5
5
  * microapp Runtime 实现,避免在业务域内复制基础逻辑。
6
6
  */
7
- export { clearDouyinLoginAuth, createMicroappClient, } from '../../../runtime/index.js';
7
+ export { clearDouyinLoginAuth, createMicroappClient, prepareImageForUpload, } from '../../../runtime/index.js';
8
8
  //# sourceMappingURL=microapp.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"microapp.js","sourceRoot":"","sources":["../../../../src/adapters/interest-card/runtime/microapp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,oBAAoB,EACpB,oBAAoB,GAErB,MAAM,2BAA2B,CAAA"}
1
+ {"version":3,"file":"microapp.js","sourceRoot":"","sources":["../../../../src/adapters/interest-card/runtime/microapp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,GAGtB,MAAM,2BAA2B,CAAA"}
@@ -0,0 +1,96 @@
1
+ import { existsSync, readFileSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { pathToFileURL } from 'node:url'
4
+
5
+ /**
6
+ * @desc 校验卡片形态;缺少字段保留历史兴趣卡语义,不写回配置。
7
+ * @params {object} config 已解析的工程配置。
8
+ * @params {string} [source] 错误信息中的配置来源。
9
+ * @return {'interest'|'post'} 卡片形态。
10
+ * @example parseCardType({ cardType: 'post' })
11
+ */
12
+ export function parseCardType(config, source = 'card-routing.json') {
13
+ if (!config || typeof config !== 'object' || Array.isArray(config)) {
14
+ throw new Error(`${source} must contain an object`)
15
+ }
16
+ if (!Object.hasOwn(config, 'cardType')) return 'interest'
17
+ if (config.cardType !== 'interest' && config.cardType !== 'post') {
18
+ throw new Error(`${source}: cardType must be interest or post; got ${JSON.stringify(config.cardType)}`)
19
+ }
20
+ return config.cardType
21
+ }
22
+
23
+ /**
24
+ * @desc 从明确的宿主工程目录读取形态,供 CLI 与两端 SDK 共用。
25
+ * @params {{projectRoot: string}} options 宿主工程绝对路径;OpenCard 配置也传宿主目录。
26
+ * @return {{cardType: 'interest'|'post', configPath: string}} 形态及配置来源。
27
+ * @example readCardProfile({ projectRoot: '/workspace/project/card-app' })
28
+ */
29
+ export function readCardProfile({ projectRoot }) {
30
+ if (typeof projectRoot !== 'string' || !path.isAbsolute(projectRoot)) {
31
+ throw new Error('readCardProfile requires an absolute projectRoot')
32
+ }
33
+ const configPath = path.join(projectRoot, 'config/card-routing.json')
34
+ let raw
35
+ try {
36
+ raw = readFileSync(configPath, 'utf8')
37
+ } catch (error) {
38
+ if (error.code === 'ENOENT') return { cardType: 'interest', configPath }
39
+ throw error
40
+ }
41
+ let config
42
+ try {
43
+ config = JSON.parse(raw)
44
+ } catch (error) {
45
+ throw new Error(`${configPath} must contain valid JSON: ${error.message}`)
46
+ }
47
+ return { cardType: parseCardType(config, configPath), configPath }
48
+ }
49
+
50
+ function findEslintHost(filename, target) {
51
+ let directory = path.dirname(filename)
52
+ while (true) {
53
+ // Stop at the owning package/config instead of inheriting another project's
54
+ // routing. An OpenCard package belongs to its immediate host directory.
55
+ if (existsSync(path.join(directory, 'package.json')) ||
56
+ existsSync(path.join(directory, 'eslint.config.mjs')) ||
57
+ existsSync(path.join(directory, 'project.card.json'))) {
58
+ return target === 'opencard' ? path.dirname(directory) : directory
59
+ }
60
+ if (existsSync(path.join(directory, '.git'))) return undefined
61
+ const parent = path.dirname(directory)
62
+ if (parent === directory) return undefined
63
+ directory = parent
64
+ }
65
+ }
66
+
67
+ /**
68
+ * @desc 创建作品卡文件匹配器;CLI 传入形态,直接 ESLint 从待检查文件定位工程。
69
+ * @params {{cardType?: 'interest'|'post', target: 'taro'|'opencard'}} options SDK 配置及目标端。
70
+ * @params {object} [environment] CLI 子进程环境。
71
+ * @return {(filename: string) => boolean} 是否启用作品卡配置。
72
+ * @example createPostCardMatcher({ target: 'taro' })('/workspace/app/src/index.ts')
73
+ */
74
+ export function createPostCardMatcher(options, environment = process.env) {
75
+ const configured = options.cardType ?? environment.VIBECODING_CARD_TYPE
76
+ // An explicitly supplied null must not silently fall back to legacy rules.
77
+ const explicit = options.cardType !== undefined
78
+ if (explicit || configured !== undefined) {
79
+ const cardType = parseCardType({ cardType: explicit ? options.cardType : configured }, 'ESLint cardType')
80
+ return () => cardType === 'post'
81
+ }
82
+ return filename => {
83
+ const projectRoot = findEslintHost(filename, options.target)
84
+ return projectRoot ? readCardProfile({ projectRoot }).cardType === 'post' : false
85
+ }
86
+ }
87
+
88
+ // The legacy shell entry uses the same parser as the SDK-owned ESLint configs.
89
+ if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
90
+ try {
91
+ console.log(readCardProfile({ projectRoot: path.resolve(process.argv[2]) }).cardType)
92
+ } catch (error) {
93
+ console.error(error.message)
94
+ process.exitCode = 1
95
+ }
96
+ }
@@ -0,0 +1,82 @@
1
+ const TARO_SOURCES = new Set(['@tarojs/taro'])
2
+ const TAB_APIS = new Set([
3
+ 'switchTab', 'setTabBarItem', 'setTabBarStyle', 'showTabBar', 'hideTabBar',
4
+ 'setTabBarBadge', 'removeTabBarBadge', 'showTabBarRedDot', 'hideTabBarRedDot',
5
+ 'getTabBar', 'onTabItemTap', 'useTabItemTap',
6
+ ])
7
+
8
+ function key(node) {
9
+ return node?.type === 'Identifier' ? node.name
10
+ : node?.type === 'Literal' && typeof node.value === 'string' ? node.value : null
11
+ }
12
+
13
+ function platformObject(node, context, seen = new Set()) {
14
+ if (!node || seen.has(node)) return false
15
+ seen.add(node)
16
+ if (['TSAsExpression', 'TSNonNullExpression', 'ChainExpression'].includes(node.type)) {
17
+ return platformObject(node.expression, context, seen)
18
+ }
19
+ if (node.type === 'CallExpression') {
20
+ return node.callee.type === 'Identifier' && node.callee.name === 'require'
21
+ && TARO_SOURCES.has(node.arguments[0]?.value)
22
+ }
23
+ if (node.type === 'MemberExpression') {
24
+ return ['globalThis', 'window'].includes(node.object?.name)
25
+ && ['tt', 'Taro'].includes(key(node.property))
26
+ }
27
+ if (node.type !== 'Identifier') return false
28
+ let scope = context.sourceCode.getScope(node)
29
+ let variable
30
+ while (scope && !variable) { variable = scope.set.get(node.name); scope = scope.upper }
31
+ if (!variable?.defs.length) return ['tt', 'Taro'].includes(node.name)
32
+ return variable.defs.some(def => {
33
+ if (def.type === 'ImportBinding') {
34
+ return TARO_SOURCES.has(def.parent?.source?.value)
35
+ && ['ImportDefaultSpecifier', 'ImportNamespaceSpecifier'].includes(def.node.type)
36
+ }
37
+ return def.type === 'Variable' && platformObject(def.node.init, context, seen)
38
+ })
39
+ }
40
+
41
+ export default {
42
+ rules: {
43
+ 'no-platform-tabbar': {
44
+ meta: { type: 'problem', schema: [], messages: {
45
+ config: '作品卡不支持平台 tabBar(含 custom 模式)。请用普通组件绘制导航并实现页面或状态切换。',
46
+ api: '作品卡不支持 {{name}}。请使用普通页面路由或组件状态切换,不调用平台 TabBar。',
47
+ } },
48
+ create(context) {
49
+ const filename = context.filename.replaceAll('\\', '/')
50
+ const isAppConfig = /\/app\.config\.[cm]?[jt]s$/.test(filename)
51
+ const report = (node, name) => {
52
+ if (TAB_APIS.has(name)) context.report({ node, messageId: 'api', data: { name } })
53
+ }
54
+ return {
55
+ Property(node) {
56
+ if (isAppConfig && key(node.key) === 'tabBar') context.report({ node, messageId: 'config' })
57
+ if (node.parent.type === 'ObjectPattern' && platformObject(node.parent.parent?.init, context)) {
58
+ report(node, key(node.key))
59
+ }
60
+ },
61
+ ImportSpecifier(node) {
62
+ if (node.importKind !== 'type' && node.parent.importKind !== 'type'
63
+ && TARO_SOURCES.has(node.parent.source.value)) report(node, key(node.imported))
64
+ },
65
+ ExportSpecifier(node) {
66
+ if (TARO_SOURCES.has(node.parent.source?.value)) report(node, key(node.local))
67
+ },
68
+ MemberExpression(node) {
69
+ const name = key(node.property)
70
+ if (platformObject(node.object, context) || (name === 'getTabBar' && node.object.type === 'ThisExpression')) {
71
+ report(node, name)
72
+ }
73
+ },
74
+ JSXAttribute(node) {
75
+ const value = node.value?.type === 'JSXExpressionContainer' ? node.value.expression?.value : node.value?.value
76
+ if (node.name.name === 'openType' && value === 'switchTab') report(node, 'switchTab')
77
+ },
78
+ }
79
+ },
80
+ },
81
+ },
82
+ }
@@ -1,3 +1,6 @@
1
+ import postCard from './eslint-plugin-post-card.mjs';
2
+ import { createPostCardMatcher } from './card-profile.mjs';
3
+ export const CARD_TYPE_RULES_VERSION = 1;
1
4
  import eslint from '@eslint/js';
2
5
  import { fixupPluginRules } from '@eslint/compat';
3
6
  import tseslint from 'typescript-eslint';
@@ -381,6 +384,7 @@ const indexPageRestrictedSyntaxRules = [
381
384
  ];
382
385
 
383
386
  export function createMicroappTaroEslintConfig(options = {}) {
387
+ const matchesPostCard = createPostCardMatcher({ cardType: options.cardType, target: 'taro' });
384
388
  const lucideColorCheckPlugin = createLucideColorCheckPlugin(options.lucideImportSources)
385
389
  const pageRestrictedSyntaxRules = createPageRestrictedSyntaxRules(
386
390
  options.preferredUiImportBase,
@@ -581,6 +585,12 @@ export function createMicroappTaroEslintConfig(options = {}) {
581
585
  },
582
586
  );
583
587
 
588
+ defaults.push({
589
+ files: [['src/**/*.{js,jsx,ts,tsx}', matchesPostCard]],
590
+ settings: { cardType: 'post', cardTypeRulesVersion: CARD_TYPE_RULES_VERSION },
591
+ plugins: { postCard },
592
+ rules: { 'postCard/no-platform-tabbar': 'error' },
593
+ });
584
594
  const overrides = options.overrides
585
595
  if (!overrides) return defaults
586
596
  if (typeof overrides === 'function') return overrides(defaults) ?? defaults
@@ -14,7 +14,9 @@ Companion libraries are separate project dependencies, imported from their own p
14
14
  ## APIs
15
15
 
16
16
  - [createMicroappClient](./sdk-api/runtime/createMicroappClient.md): 创建普通小程序的网络入口;SDK 自动绑定项目 Taro 运行时。 Import: `@open-dy/vibecoding-sdk-taro/runtime`.
17
- - [CreateMicroappClientOptions](./sdk-api/runtime/CreateMicroappClientOptions.md): 配置普通小程序 Network 的平台渠道。 Import: `@open-dy/vibecoding-sdk-taro/runtime`.
17
+ - [CreateMicroappClientOptions](./sdk-api/runtime/CreateMicroappClientOptions.md): 配置普通小程序 Network 的平台渠道和真机预览上传环境。 Import: `@open-dy/vibecoding-sdk-taro/runtime`.
18
+ - [prepareImageForUpload](./sdk-api/runtime/prepareImageForUpload.md): 显式预处理本地 JPEG,返回上传路径和诊断信息。 Import: `@open-dy/vibecoding-sdk-taro/runtime`.
19
+ - [PreparedImageForUpload](./sdk-api/runtime/PreparedImageForUpload.md): 图片上传应使用的本地路径,以及可取得的压缩诊断信息。 Import: `@open-dy/vibecoding-sdk-taro/runtime`.
18
20
  - [MiniappOpenCard](./sdk-api/components/miniapp-open-card/MiniappOpenCard.md): 承载同一 OpenCard;SDK 选择环境版本并为空初始化参数提供对象,错误类型直接报错。 Import: `@open-dy/vibecoding-sdk-taro/components/miniapp-open-card`.
19
21
  - [MiniappOpenCardProps](./sdk-api/components/miniapp-open-card/MiniappOpenCardProps.md): 普通 Taro 宿主的内嵌卡属性;沿用 StandardProps,但不接受 children 或 envVersion。 Import: `@open-dy/vibecoding-sdk-taro/components/miniapp-open-card`.
20
22
  - [MiniappOpenCardErrorDetail](./sdk-api/components/miniapp-open-card/MiniappOpenCardErrorDetail.md): 内嵌卡加载错误的事件 detail;可选错误字段由平台提供。 Import: `@open-dy/vibecoding-sdk-taro/components/miniapp-open-card`.
@@ -7,7 +7,7 @@
7
7
 
8
8
  #### 说明
9
9
 
10
- 配置普通小程序 Network 的平台渠道。
10
+ 配置普通小程序 Network 的平台渠道和真机预览上传环境。
11
11
 
12
12
  示例:
13
13
 
@@ -34,6 +34,7 @@ const options = { platformChannel: 'ext' as const }
34
34
  ```ts
35
35
  export interface CreateMicroappClientOptions {
36
36
  platformChannel?: '' | 'ext';
37
+ previewUploadEnvType?: 'development';
37
38
  }
38
39
  ```
39
40
 
@@ -50,3 +51,4 @@ CreateMicroappClientOptions
50
51
  | 字段 | 类型 | 说明 |
51
52
  | --- | --- | --- |
52
53
  | platformChannel? | `"" \| "ext" \| undefined` | 平台渠道:空字符串为内场,ext 为外场;默认空字符串。 |
54
+ | previewUploadEnvType? | `"development" \| undefined` | 设置为 development 时,真机扫码预览的托管上传使用抖音云开发环境。 |
@@ -0,0 +1,52 @@
1
+ # PreparedImageForUpload
2
+
3
+ <!-- Generated by packages/sdk-tooling/src/reference/skill-reference.ts. Do not edit. -->
4
+
5
+ 导入路径:`@open-dy/vibecoding-sdk-taro/runtime`
6
+ 源码:实际安装的 `@open-dy/vibecoding-sdk-taro` 包内 `src/runtime/image-upload-preparation.ts`(仅补缺或排错时读取)。
7
+
8
+ #### 说明
9
+
10
+ 图片上传应使用的本地路径,以及可取得的压缩诊断信息。
11
+
12
+ 示例:
13
+
14
+ ```ts
15
+ const { filePath, reason } = await prepareImageForUpload(tempFilePath)
16
+ ```
17
+
18
+ #### AI 使用约束
19
+
20
+ | 规则 | 内容 |
21
+ | --- | --- |
22
+ | 意图 | 读取静默压缩选出的路径和诊断信息。 |
23
+ | 适用时机 | 既有调用方需要读取显式预处理的结果时。 |
24
+ | 避免 | 不要把压缩诊断用作上传错误或用户提示。 |
25
+
26
+ #### 声明
27
+
28
+ ```ts
29
+ export interface PreparedImageForUpload {
30
+ filePath: string;
31
+ originalBytes?: number;
32
+ bytes?: number;
33
+ reason: 'compressed' | 'below-target' | 'unsupported' | 'not-jpeg' | 'input-budget' | 'busy' | 'invalid-image' | 'no-benefit' | 'timeout' | 'failed';
34
+ }
35
+ ```
36
+
37
+ ### PreparedImageForUpload 的类型契约
38
+
39
+ #### 类型
40
+
41
+ ```ts
42
+ PreparedImageForUpload
43
+ ```
44
+
45
+ #### 字段
46
+
47
+ | 字段 | 类型 | 说明 |
48
+ | --- | --- | --- |
49
+ | filePath | `string` | 最终上传使用的本地文件路径。 |
50
+ | originalBytes? | `number \| undefined` | 原文件实际大小,单位字节。未取得时为 undefined。 |
51
+ | bytes? | `number \| undefined` | 最终文件实际大小,单位字节。未取得时为 undefined。 |
52
+ | reason | `"timeout" \| "compressed" \| "below-target" \| "unsupported" \| "not-jpeg" \| "input-budget" \| "busy" \| "invalid-image" \| "no-benefit" \| "failed"` | 压缩采用或使用原文件的原因。 |
@@ -13,11 +13,11 @@
13
13
 
14
14
  | 名称 | 说明 |
15
15
  | --- | --- |
16
- | `options` | 平台渠道配置;默认使用内场渠道。 |
16
+ | `options` | 平台渠道和真机预览上传环境配置。默认使用内场渠道。 |
17
17
 
18
18
  返回:仅提供普通小程序的 request、uploadFile、downloadFile 和 streamSse。
19
19
 
20
- 备注:业务优先从模板的 @/network 导入 Network;HTTP(S) 绝对地址直接交给 Taro。宿主需要封闭域功能时通过 MiniappOpenCard 承载,请求与数据处理仅在卡内完成。streamSse 返回的是流句柄,Promise resolve 不代表生成完成。正常关闭仅调用一次 onComplete;流错误仅调用一次 onError(Error),随后释放任务;close() 主动取消仅调用一次可选的 onCancel,不调用 onComplete/onError。业务须在对应终态回调中清理 loading,不能把 onComplete 当通用 finally;终态后的消息与重复事件会被忽略。创建任务前的失败仍通过 Promise rejection 交付。
20
+ 备注:业务优先从模板的 @/network 导入 Network。uploadFile 在支持原生图片处理的抖音小程序中自动尝试压缩符合条件的本地 JPEG,各上传路由均适用。业务直接传入原始 filePath。HTTP(S) 绝对地址仍由 Taro 传输。宿主需要封闭域功能时通过 MiniappOpenCard 承载,请求与数据处理仅在卡内完成。streamSse 返回的是流句柄,Promise resolve 不代表生成完成。正常关闭仅调用一次 onComplete;流错误仅调用一次 onError(Error),随后释放任务;close() 主动取消仅调用一次可选的 onCancel,不调用 onComplete/onError。业务须在对应终态回调中清理 loading,不能把 onComplete 当通用 finally;终态后的消息与重复事件会被忽略。创建任务前的失败仍通过 Promise rejection 交付。
21
21
 
22
22
  示例:
23
23
 
@@ -61,13 +61,14 @@ function createMicroappClient(options?: CreateMicroappClientOptions);
61
61
 
62
62
  | 参数 | 类型 | 说明 |
63
63
  | --- | --- | --- |
64
- | options? | `CreateMicroappClientOptions` | 平台渠道配置;默认使用内场渠道。 |
64
+ | options? | `CreateMicroappClientOptions` | 平台渠道和真机预览上传环境配置。默认使用内场渠道。 |
65
65
 
66
66
  ##### options 字段
67
67
 
68
68
  | 字段 | 类型 | 说明 |
69
69
  | --- | --- | --- |
70
70
  | platformChannel? | `"" \| "ext" \| undefined` | 平台渠道:空字符串为内场,ext 为外场;默认空字符串。 |
71
+ | previewUploadEnvType? | `"development" \| undefined` | 设置为 development 时,真机扫码预览的托管上传使用抖音云开发环境。 |
71
72
 
72
73
  #### 返回值
73
74
 
@@ -7,4 +7,6 @@
7
7
  | API | 说明 | 文档 |
8
8
  | --- | --- | --- |
9
9
  | `createMicroappClient` | 创建普通小程序的网络入口;SDK 自动绑定项目 Taro 运行时。 | [查看](./createMicroappClient.md) |
10
- | `CreateMicroappClientOptions` | 配置普通小程序 Network 的平台渠道。 | [查看](./CreateMicroappClientOptions.md) |
10
+ | `CreateMicroappClientOptions` | 配置普通小程序 Network 的平台渠道和真机预览上传环境。 | [查看](./CreateMicroappClientOptions.md) |
11
+ | `prepareImageForUpload` | 显式预处理本地 JPEG,返回上传路径和诊断信息。 | [查看](./prepareImageForUpload.md) |
12
+ | `PreparedImageForUpload` | 图片上传应使用的本地路径,以及可取得的压缩诊断信息。 | [查看](./PreparedImageForUpload.md) |
@@ -0,0 +1,69 @@
1
+ # prepareImageForUpload
2
+
3
+ <!-- Generated by packages/sdk-tooling/src/reference/skill-reference.ts. Do not edit. -->
4
+
5
+ 导入路径:`@open-dy/vibecoding-sdk-taro/runtime`
6
+ 源码:实际安装的 `@open-dy/vibecoding-sdk-taro` 包内 `src/runtime/image-upload-preparation.ts`(仅补缺或排错时读取)。
7
+
8
+ #### 说明
9
+
10
+ 显式预处理本地 JPEG,返回上传路径和诊断信息。
11
+
12
+ 返回:上传路径及诊断信息,降级时返回原路径。
13
+
14
+ 备注:Network.uploadFile 会自动预处理符合条件的 JPEG。此方法兼容已有显式调用。压缩结果由宿主临时保存,能力缺失或超时时沿用原路径或已验证的候选。
15
+
16
+ 示例:
17
+
18
+ ```ts
19
+ const prepared = await prepareImageForUpload(tempFilePath)
20
+ console.log(prepared.bytes, prepared.reason)
21
+ ```
22
+
23
+ #### AI 使用约束
24
+
25
+ | 规则 | 内容 |
26
+ | --- | --- |
27
+ | 意图 | 兼容已有的本地 JPEG 显式预处理。 |
28
+ | 适用时机 | 维护已使用显式预处理或需要其诊断信息的调用方时。 |
29
+ | 避免 | 不要为使用新版 Network.uploadFile 的新业务再接一层手动预处理。 |
30
+
31
+ 示例:
32
+
33
+ ```ts
34
+ const prepared = await prepareImageForUpload(tempFilePath)
35
+ ```
36
+
37
+ #### 声明
38
+
39
+ ```ts
40
+ function prepareImageForUpload(filePath: string): Promise<PreparedImageForUpload>;
41
+ ```
42
+
43
+ ### prepareImageForUpload 的类型契约
44
+
45
+ #### 工厂签名
46
+
47
+ ```ts
48
+ (filePath: string): Promise<PreparedImageForUpload>
49
+ ```
50
+
51
+ #### 参数
52
+
53
+ | 参数 | 类型 | 说明 |
54
+ | --- | --- | --- |
55
+ | filePath | `string` | 选图或拍摄获得的本地文件路径。 |
56
+
57
+ #### 返回值
58
+
59
+ - 类型:`Promise<PreparedImageForUpload>`
60
+ - Promise resolve 类型:`PreparedImageForUpload`
61
+
62
+ ##### 字段
63
+
64
+ | 字段 | 类型 | 说明 |
65
+ | --- | --- | --- |
66
+ | filePath | `string` | 最终上传使用的本地文件路径。 |
67
+ | originalBytes? | `number \| undefined` | 原文件实际大小,单位字节。未取得时为 undefined。 |
68
+ | bytes? | `number \| undefined` | 最终文件实际大小,单位字节。未取得时为 undefined。 |
69
+ | reason | `"timeout" \| "compressed" \| "below-target" \| "unsupported" \| "not-jpeg" \| "input-budget" \| "busy" \| "invalid-image" \| "no-benefit" \| "failed"` | 压缩采用或使用原文件的原因。 |
@@ -99,12 +99,12 @@
99
99
  "parameters": [
100
100
  {
101
101
  "name": "options",
102
- "description": "平台渠道配置;默认使用内场渠道。"
102
+ "description": "平台渠道和真机预览上传环境配置。默认使用内场渠道。"
103
103
  }
104
104
  ],
105
105
  "returns": "仅提供普通小程序的 request、uploadFile、downloadFile 和 streamSse。",
106
106
  "remarks": [
107
- "业务优先从模板的 @/network 导入 Network;HTTP(S) 绝对地址直接交给 Taro。宿主需要封闭域功能时通过 MiniappOpenCard 承载,请求与数据处理仅在卡内完成。streamSse 返回的是流句柄,Promise resolve 不代表生成完成。正常关闭仅调用一次 onComplete;流错误仅调用一次 onError(Error),随后释放任务;close() 主动取消仅调用一次可选的 onCancel,不调用 onComplete/onError。业务须在对应终态回调中清理 loading,不能把 onComplete 当通用 finally;终态后的消息与重复事件会被忽略。创建任务前的失败仍通过 Promise rejection 交付。"
107
+ "业务优先从模板的 @/network 导入 Network。uploadFile 在支持原生图片处理的抖音小程序中自动尝试压缩符合条件的本地 JPEG,各上传路由均适用。业务直接传入原始 filePath。HTTP(S) 绝对地址仍由 Taro 传输。宿主需要封闭域功能时通过 MiniappOpenCard 承载,请求与数据处理仅在卡内完成。streamSse 返回的是流句柄,Promise resolve 不代表生成完成。正常关闭仅调用一次 onComplete;流错误仅调用一次 onError(Error),随后释放任务;close() 主动取消仅调用一次可选的 onCancel,不调用 onComplete/onError。业务须在对应终态回调中清理 loading,不能把 onComplete 当通用 finally;终态后的消息与重复事件会被忽略。创建任务前的失败仍通过 Promise rejection 交付。"
108
108
  ],
109
109
  "examples": [
110
110
  {
@@ -128,13 +128,19 @@
128
128
  "name": "options",
129
129
  "optional": true,
130
130
  "type": "CreateMicroappClientOptions",
131
- "description": "平台渠道配置;默认使用内场渠道。",
131
+ "description": "平台渠道和真机预览上传环境配置。默认使用内场渠道。",
132
132
  "fields": [
133
133
  {
134
134
  "name": "platformChannel",
135
135
  "optional": true,
136
136
  "type": "\"\" | \"ext\" | undefined",
137
137
  "description": "平台渠道:空字符串为内场,ext 为外场;默认空字符串。"
138
+ },
139
+ {
140
+ "name": "previewUploadEnvType",
141
+ "optional": true,
142
+ "type": "\"development\" | undefined",
143
+ "description": "设置为 development 时,真机扫码预览的托管上传使用抖音云开发环境。"
138
144
  }
139
145
  ]
140
146
  }
@@ -734,9 +740,9 @@
734
740
  "importPath": "@open-dy/vibecoding-sdk-taro/runtime",
735
741
  "source": "src/runtime/client.ts",
736
742
  "docPath": "sdk-api/runtime/CreateMicroappClientOptions.md",
737
- "summary": "配置普通小程序 Network 的平台渠道。",
743
+ "summary": "配置普通小程序 Network 的平台渠道和真机预览上传环境。",
738
744
  "documentation": {
739
- "summary": "配置普通小程序 Network 的平台渠道。",
745
+ "summary": "配置普通小程序 Network 的平台渠道和真机预览上传环境。",
740
746
  "examples": [
741
747
  {
742
748
  "language": "ts",
@@ -750,7 +756,7 @@
750
756
  "avoid": "不要在业务页面直接拼接渠道请求头。",
751
757
  "example": "{ platformChannel: 'ext' }"
752
758
  },
753
- "signature": "export interface CreateMicroappClientOptions {\n platformChannel?: '' | 'ext';\n}",
759
+ "signature": "export interface CreateMicroappClientOptions {\n platformChannel?: '' | 'ext';\n previewUploadEnvType?: 'development';\n}",
754
760
  "contract": {
755
761
  "kind": "type",
756
762
  "type": "CreateMicroappClientOptions",
@@ -760,6 +766,138 @@
760
766
  "optional": true,
761
767
  "type": "\"\" | \"ext\" | undefined",
762
768
  "description": "平台渠道:空字符串为内场,ext 为外场;默认空字符串。"
769
+ },
770
+ {
771
+ "name": "previewUploadEnvType",
772
+ "optional": true,
773
+ "type": "\"development\" | undefined",
774
+ "description": "设置为 development 时,真机扫码预览的托管上传使用抖音云开发环境。"
775
+ }
776
+ ]
777
+ }
778
+ },
779
+ {
780
+ "id": "runtime.prepareImageForUpload",
781
+ "name": "prepareImageForUpload",
782
+ "importPath": "@open-dy/vibecoding-sdk-taro/runtime",
783
+ "source": "src/runtime/image-upload-preparation.ts",
784
+ "docPath": "sdk-api/runtime/prepareImageForUpload.md",
785
+ "summary": "显式预处理本地 JPEG,返回上传路径和诊断信息。",
786
+ "documentation": {
787
+ "summary": "显式预处理本地 JPEG,返回上传路径和诊断信息。",
788
+ "returns": "上传路径及诊断信息,降级时返回原路径。",
789
+ "remarks": [
790
+ "Network.uploadFile 会自动预处理符合条件的 JPEG。此方法兼容已有显式调用。压缩结果由宿主临时保存,能力缺失或超时时沿用原路径或已验证的候选。"
791
+ ],
792
+ "examples": [
793
+ {
794
+ "language": "ts",
795
+ "code": "const prepared = await prepareImageForUpload(tempFilePath)\nconsole.log(prepared.bytes, prepared.reason)"
796
+ }
797
+ ]
798
+ },
799
+ "ai": {
800
+ "intent": "兼容已有的本地 JPEG 显式预处理。",
801
+ "when": "维护已使用显式预处理或需要其诊断信息的调用方时。",
802
+ "avoid": "不要为使用新版 Network.uploadFile 的新业务再接一层手动预处理。",
803
+ "example": "const prepared = await prepareImageForUpload(tempFilePath)"
804
+ },
805
+ "signature": "function prepareImageForUpload(filePath: string): Promise<PreparedImageForUpload>;",
806
+ "contract": {
807
+ "kind": "callable",
808
+ "signature": "(filePath: string): Promise<PreparedImageForUpload>",
809
+ "parameters": [
810
+ {
811
+ "name": "filePath",
812
+ "optional": false,
813
+ "type": "string",
814
+ "description": "选图或拍摄获得的本地文件路径。"
815
+ }
816
+ ],
817
+ "returns": {
818
+ "type": "Promise<PreparedImageForUpload>",
819
+ "promise": true,
820
+ "resolvesTo": "PreparedImageForUpload",
821
+ "fields": [
822
+ {
823
+ "name": "filePath",
824
+ "optional": false,
825
+ "type": "string",
826
+ "description": "最终上传使用的本地文件路径。"
827
+ },
828
+ {
829
+ "name": "originalBytes",
830
+ "optional": true,
831
+ "type": "number | undefined",
832
+ "description": "原文件实际大小,单位字节。未取得时为 undefined。"
833
+ },
834
+ {
835
+ "name": "bytes",
836
+ "optional": true,
837
+ "type": "number | undefined",
838
+ "description": "最终文件实际大小,单位字节。未取得时为 undefined。"
839
+ },
840
+ {
841
+ "name": "reason",
842
+ "optional": false,
843
+ "type": "\"timeout\" | \"compressed\" | \"below-target\" | \"unsupported\" | \"not-jpeg\" | \"input-budget\" | \"busy\" | \"invalid-image\" | \"no-benefit\" | \"failed\"",
844
+ "description": "压缩采用或使用原文件的原因。"
845
+ }
846
+ ]
847
+ },
848
+ "methods": []
849
+ }
850
+ },
851
+ {
852
+ "id": "runtime.PreparedImageForUpload",
853
+ "name": "PreparedImageForUpload",
854
+ "importPath": "@open-dy/vibecoding-sdk-taro/runtime",
855
+ "source": "src/runtime/image-upload-preparation.ts",
856
+ "docPath": "sdk-api/runtime/PreparedImageForUpload.md",
857
+ "summary": "图片上传应使用的本地路径,以及可取得的压缩诊断信息。",
858
+ "documentation": {
859
+ "summary": "图片上传应使用的本地路径,以及可取得的压缩诊断信息。",
860
+ "examples": [
861
+ {
862
+ "language": "ts",
863
+ "code": "const { filePath, reason } = await prepareImageForUpload(tempFilePath)"
864
+ }
865
+ ]
866
+ },
867
+ "ai": {
868
+ "intent": "读取静默压缩选出的路径和诊断信息。",
869
+ "when": "既有调用方需要读取显式预处理的结果时。",
870
+ "avoid": "不要把压缩诊断用作上传错误或用户提示。",
871
+ "example": "const { filePath, reason } = await prepareImageForUpload(tempFilePath)"
872
+ },
873
+ "signature": "export interface PreparedImageForUpload {\n filePath: string;\n originalBytes?: number;\n bytes?: number;\n reason: 'compressed' | 'below-target' | 'unsupported' | 'not-jpeg' | 'input-budget' | 'busy' | 'invalid-image' | 'no-benefit' | 'timeout' | 'failed';\n}",
874
+ "contract": {
875
+ "kind": "type",
876
+ "type": "PreparedImageForUpload",
877
+ "fields": [
878
+ {
879
+ "name": "filePath",
880
+ "optional": false,
881
+ "type": "string",
882
+ "description": "最终上传使用的本地文件路径。"
883
+ },
884
+ {
885
+ "name": "originalBytes",
886
+ "optional": true,
887
+ "type": "number | undefined",
888
+ "description": "原文件实际大小,单位字节。未取得时为 undefined。"
889
+ },
890
+ {
891
+ "name": "bytes",
892
+ "optional": true,
893
+ "type": "number | undefined",
894
+ "description": "最终文件实际大小,单位字节。未取得时为 undefined。"
895
+ },
896
+ {
897
+ "name": "reason",
898
+ "optional": false,
899
+ "type": "\"timeout\" | \"compressed\" | \"below-target\" | \"unsupported\" | \"not-jpeg\" | \"input-budget\" | \"busy\" | \"invalid-image\" | \"no-benefit\" | \"failed\"",
900
+ "description": "压缩采用或使用原文件的原因。"
763
901
  }
764
902
  ]
765
903
  }
@@ -44,6 +44,8 @@
44
44
  - [runtime](sdk-api/runtime/index.md)
45
45
  - `createMicroappClient`
46
46
  - `CreateMicroappClientOptions`
47
+ - `prepareImageForUpload`
48
+ - `PreparedImageForUpload`
47
49
  - [components/miniapp-open-card](sdk-api/components/miniapp-open-card/index.md)
48
50
  - `MiniappOpenCard`
49
51
  - `MiniappOpenCardProps`
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @desc 配置普通小程序 Network 的平台渠道。
2
+ * @desc 配置普通小程序 Network 的平台渠道和真机预览上传环境。
3
3
  * @example
4
4
  * ```ts
5
5
  * const options = { platformChannel: 'ext' as const }
@@ -12,6 +12,8 @@
12
12
  export interface CreateMicroappClientOptions {
13
13
  /** @desc 平台渠道:空字符串为内场,ext 为外场;默认空字符串。 */
14
14
  platformChannel?: '' | 'ext';
15
+ /** @desc 设置为 development 时,真机扫码预览的托管上传使用抖音云开发环境。 */
16
+ previewUploadEnvType?: 'development';
15
17
  }
16
18
  /**
17
19
  * 网络请求模块