openxiangda 1.0.222 → 1.0.224
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 +8 -6
- package/lib/cli.js +22 -15
- package/lib/source-dependencies.js +6 -13
- package/openxiangda-skills/SKILL.md +1 -1
- package/openxiangda-skills/references/automation-v3.md +1 -1
- package/openxiangda-skills/references/connector-resources.md +1 -1
- package/openxiangda-skills/references/pages/page-sdk.md +27 -1
- package/openxiangda-skills/references/resource-manifest-cheatsheet.md +1 -1
- package/openxiangda-skills/references/workflow-v3.md +1 -1
- package/openxiangda-skills/skills/openxiangda-core/SKILL.md +2 -2
- package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +2 -2
- package/package.json +1 -1
- package/packages/sdk/dist/runtime/index.cjs +75 -5
- package/packages/sdk/dist/runtime/index.cjs.map +1 -1
- package/packages/sdk/dist/runtime/index.d.mts +1 -1
- package/packages/sdk/dist/runtime/index.d.ts +1 -1
- package/packages/sdk/dist/runtime/index.mjs +75 -5
- package/packages/sdk/dist/runtime/index.mjs.map +1 -1
- package/packages/sdk/dist/runtime/react.cjs +75 -5
- package/packages/sdk/dist/runtime/react.cjs.map +1 -1
- package/packages/sdk/dist/runtime/react.d.mts +189 -1
- package/packages/sdk/dist/runtime/react.d.ts +189 -1
- package/packages/sdk/dist/runtime/react.mjs +75 -5
- package/packages/sdk/dist/runtime/react.mjs.map +1 -1
- package/packages/sdk/source/admin-list/AdminList.tsx +30 -7
- package/packages/sdk/source/admin-list/dataSources.ts +28 -1
- package/packages/sdk/source/admin-list/types.ts +12 -1
- package/templates/openxiangda-react-spa/AGENTS.md +1 -1
- package/templates/sy-lowcode-app-workspace/AGENTS.md +1 -1
package/README.md
CHANGED
|
@@ -96,11 +96,13 @@ Use `environment policy update <kind|id>` when only one environment's side-effec
|
|
|
96
96
|
|
|
97
97
|
`resource plan` and `resource publish --dry-run` run behind a strict GET/HEAD-only HTTP guard. If a read receives HTTP 401, the command fails with `READ_ONLY_AUTH_REQUIRED` and never calls the token refresh POST from inside the plan. Run `openxiangda auth refresh --profile <name>` (or log in again) before retrying; a plan must not mutate auth state or platform resources.
|
|
98
98
|
|
|
99
|
-
For Function/Automation plans, `formFieldContracts`
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
For Function/Automation plans, `formFieldContracts` resolves statically
|
|
100
|
+
referenced Forms through the target application's registry and checks
|
|
101
|
+
filter/order fields against frozen online Form schemas. A missing application
|
|
102
|
+
mapping or field makes publish fail before lease/write; repeating every source
|
|
103
|
+
reference in every Function manifest is not required. Dynamic field names are
|
|
104
|
+
checked again by the platform before SQL and return `FORM_FIELD_NOT_FOUND`
|
|
105
|
+
instead of a database-column error.
|
|
104
106
|
|
|
105
107
|
React SPA workspaces publish their frontend with `openxiangda runtime deploy`. Every finalized Runtime release is built from a clean, committed Git `HEAD`; the CLI freezes `sourceRevision`, the current active release, and its source revision before any build/upload. Deploy fails with `RUNTIME_SOURCE_BASE_DIVERGED` when its `HEAD` does not descend from the online Runtime source, including with `--no-activate`, so an old isolated worktree cannot stage and later activate a silent rollback. `.openxiangda/`, `openspec/`, `dist/`, and other pure generated/governance/state paths do not make the source dirty, but `--no-build` cannot bypass the lineage gate. An intentional rollback requires `--allow-runtime-rollback --reason "<at least 8 characters>"`, which is persisted for audit and never bypasses dirty/non-Git checks.
|
|
106
108
|
|
|
@@ -506,7 +508,7 @@ const PublicAccessError = ({ error }: { error: { message?: string } }) => (
|
|
|
506
508
|
|
|
507
509
|
多表只读查询和固定口径统计优先声明 `src/resources/data-views/*.json` 数据视图,而不是在页面里手写多次单表查询再拼数据。默认 `storageMode: "materialized"` 会创建 PostgreSQL materialized view,适合读多写少和可接受刷新延迟的列表/报表;`storageMode: "live"` 每次查询实时编译逻辑视图,适合强实时但数据量可控的复杂查询。`viewType: "aggregate"` 是统计聚合视图,适合按客户、状态、月份等维度聚合 count/sum/avg/min/max。发布时 CLI 会把 `formCode` 解析为当前 profile 的 `formUuid`;页面通过 `sdk.dataView.query(code, params)` 查询行级视图,通过 `sdk.dataView.stats(code, params)` 查询聚合视图,也可以用 `sdk.dataSource.run()` 路由 `dataView.query` / `dataView.stats`。materialized 模式应为常用筛选、排序、统计维度和时间桶声明 `indexes`,并确认用户能接受的刷新延迟;live 模式忽略 `indexes`,不需要刷新。
|
|
508
510
|
|
|
509
|
-
后端业务逻辑优先声明为 App Function:源码放在 `src/functions/<functionCode>/index.ts`,资源 manifest 放在 `src/resources/functions/<functionCode>.json`。函数运行在 trusted_node 中,通过 `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`、`ctx.process.startFromExistingInstance/resolveCapabilities/resubmitTask/withdraw/transferTask`、`ctx.dataView`、`ctx.connector`、`ctx.notification`、`ctx.organization`、`ctx.platform.roles`、`ctx.platform.api` 等受控 API 访问平台能力;自动化、流程和运行时接口都可以调用同一个 function。`ctx.
|
|
511
|
+
后端业务逻辑优先声明为 App Function:源码放在 `src/functions/<functionCode>/index.ts`,资源 manifest 放在 `src/resources/functions/<functionCode>.json`。函数运行在 trusted_node 中,通过 `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`、`ctx.files.readAsBase64`、`ctx.process.startFromExistingInstance/resolveCapabilities/resubmitTask/withdraw/transferTask`、`ctx.dataView`、`ctx.connector`、`ctx.notification`、`ctx.organization`、`ctx.platform.roles`、`ctx.platform.api` 等受控 API 访问平台能力;自动化、流程和运行时接口都可以调用同一个 function。`ctx.files.readAsBase64` 只读取当前 `formData` 已授权的图片附件,或由当前应用的 `formCode/formUuid + formInstId + fieldId` 定位的图片;它不会下载任意 URL,单文件上限为 10 MiB,Base64 不应写入日志、函数返回值或业务表。已发布可信代码可以访问当前租户、当前应用内的资源,Function `resources` 是可选的环境映射、审计和影响分析信息,不再是逐函数权限白名单;跨应用、跨租户和外部敏感能力仍受平台边界限制。`ctx.process` 复用正式工作流服务,以真实运行时 operator 执行,流程实例、任务授权、操作日志、事件和 replay 语义与 PageSdk 后端接口一致。角色查询和角色成员维护优先使用 `ctx.platform.roles.list/findByCode/addUsers/removeUser`,底层 `ctx.platform.api` 返回 HTTP 包装和平台 envelope,需要业务代码自行解包。运行时页面调用会在 `ctx.operator`、`ctx.currentUser`、`ctx.permissions` 中注入可信的角色上下文;敏感业务动作必须读取这些服务端上下文,不要信任页面 input 里传入的角色字段。`ctx.form.createOne/updateOne/updateById` 是后端受控写入,不是页面用户对目标表单的直接提交入口;内部多表写入应走 App Function,不要为了函数写入给普通用户开放原始 submit 权限。内部业务表单需要关闭原始写入接口时,在表单 settings 中设置 `runtimeWrite.mode="function_only"`。
|
|
510
512
|
|
|
511
513
|
App Function 访问第三方凭据时使用 `app_function_secrets_v1`:manifest 顶层只声明 `secretRefs: [{ "name": "dingtalk_org_app_key", "required": true }]`,同时使用 `definitionJson.version="function_v2"`、`runtimeContractVersion="trusted_node_v2"`;源码通过 `await ctx.secrets.get(name)` 解析,并通过 `ctx.utils.http` 访问受控公网 HTTPS(该桥接不会携带平台 Runtime token)。值只能经 `openxiangda secret create|rotate --value-stdin --change <id> --profile <name>` 或隐藏 TTY 输入,禁止进入 Git、manifest、源码、构建产物、plan、日志或异常。带 `secretRefs` 的 Function 必须走 `backend_release_v2`;需要整应用原子发布时先执行 `resource publish function --only <code> --stage-only`,再把返回的真实 `stagedResource` 交给 `release app-finalize --staged-resources-json ...` 完成 `atomic_staged_children_v2`。默认直接激活的 Backend Release 只返回 `activeResource`,不会伪装成 staged;旧平台 capability 不完整时 CLI 会失败关闭,绝不忽略绑定。
|
|
512
514
|
|
package/lib/cli.js
CHANGED
|
@@ -22178,16 +22178,28 @@ function formSettingValuesFromSnapshot(frozen) {
|
|
|
22178
22178
|
};
|
|
22179
22179
|
}
|
|
22180
22180
|
|
|
22181
|
+
function formSettingManifestSettings(item) {
|
|
22182
|
+
const resourceCode = String(item.code || item.formCode || '').trim();
|
|
22183
|
+
if (
|
|
22184
|
+
item.settings === undefined &&
|
|
22185
|
+
item.runtimeWrite === undefined &&
|
|
22186
|
+
!resourceCode
|
|
22187
|
+
) {
|
|
22188
|
+
return undefined;
|
|
22189
|
+
}
|
|
22190
|
+
return {
|
|
22191
|
+
...(item.settings || {}),
|
|
22192
|
+
...(item.runtimeWrite !== undefined
|
|
22193
|
+
? { runtimeWrite: item.runtimeWrite }
|
|
22194
|
+
: {}),
|
|
22195
|
+
...(resourceCode ? { openxiangdaResourceCode: resourceCode } : {}),
|
|
22196
|
+
};
|
|
22197
|
+
}
|
|
22198
|
+
|
|
22181
22199
|
function buildFormSettingBundleBody(item) {
|
|
22182
22200
|
const body = {};
|
|
22183
|
-
|
|
22184
|
-
|
|
22185
|
-
...(item.settings || {}),
|
|
22186
|
-
...(item.runtimeWrite !== undefined
|
|
22187
|
-
? { runtimeWrite: item.runtimeWrite }
|
|
22188
|
-
: {}),
|
|
22189
|
-
};
|
|
22190
|
-
}
|
|
22201
|
+
const settings = formSettingManifestSettings(item);
|
|
22202
|
+
if (settings !== undefined) body.settings = settings;
|
|
22191
22203
|
for (const key of [
|
|
22192
22204
|
'name',
|
|
22193
22205
|
'schema',
|
|
@@ -25936,13 +25948,8 @@ function formSettingEquals(desired, existing = {}) {
|
|
|
25936
25948
|
return false;
|
|
25937
25949
|
}
|
|
25938
25950
|
}
|
|
25939
|
-
|
|
25940
|
-
|
|
25941
|
-
...(desired.settings || {}),
|
|
25942
|
-
...(desired.runtimeWrite !== undefined
|
|
25943
|
-
? { runtimeWrite: desired.runtimeWrite }
|
|
25944
|
-
: {}),
|
|
25945
|
-
};
|
|
25951
|
+
const expectedSettings = formSettingManifestSettings(desired);
|
|
25952
|
+
if (expectedSettings !== undefined) {
|
|
25946
25953
|
const currentSettings = unwrapFormSettingPlanValue(
|
|
25947
25954
|
existing.settings,
|
|
25948
25955
|
'settings'
|
|
@@ -849,29 +849,22 @@ function validateManifestSourceBindings(options = {}) {
|
|
|
849
849
|
|
|
850
850
|
for (const target of index.targets) {
|
|
851
851
|
const label = `${target.targetKey.replace(/s$/, '')} ${target.code}`;
|
|
852
|
-
const
|
|
852
|
+
const undeclared = [];
|
|
853
853
|
for (const reference of target.resourceReferenceDetails) {
|
|
854
854
|
const declared = target.declaredResources[reference.bucket] || [];
|
|
855
855
|
if (declared.includes(reference.code)) continue;
|
|
856
856
|
if (reference.bucket === 'forms' && /^FORM[_-]/i.test(reference.code)) continue;
|
|
857
|
-
|
|
858
|
-
`${label}: ${reference.file}:${reference.line} ${reference.api} 引用 ${reference.bucket}.${reference.code},` +
|
|
859
|
-
`但 manifest 未声明。请将 "${reference.code}" 加入 resources.${reference.bucket}`;
|
|
860
|
-
if (target.entryFiles.includes(reference.file)) {
|
|
861
|
-
errors.push(message);
|
|
862
|
-
} else {
|
|
863
|
-
transitiveMissing.push(reference);
|
|
864
|
-
}
|
|
857
|
+
undeclared.push(reference);
|
|
865
858
|
}
|
|
866
|
-
if (
|
|
859
|
+
if (undeclared.length > 0) {
|
|
867
860
|
const codes = Array.from(
|
|
868
|
-
new Set(
|
|
861
|
+
new Set(undeclared.map(reference => `${reference.bucket}.${reference.code}`))
|
|
869
862
|
).sort();
|
|
870
863
|
const visible = codes.slice(0, 12);
|
|
871
864
|
warnings.push(
|
|
872
|
-
`${label}:
|
|
865
|
+
`${label}: 源码引用了未在逐资源清单声明的应用内资源: ${visible.join(', ')}` +
|
|
873
866
|
`${codes.length > visible.length ? ` 等 ${codes.length} 项` : ''}。` +
|
|
874
|
-
'
|
|
867
|
+
'平台运行时将按当前租户和应用自动解析;resources 仅用于显式映射、审计和影响分析'
|
|
875
868
|
);
|
|
876
869
|
}
|
|
877
870
|
for (const warning of target.warnings) {
|
|
@@ -135,7 +135,7 @@ When the same change already has staged FormRelease children before a fresh base
|
|
|
135
135
|
|
|
136
136
|
When a Function or Automation is selected because its TypeScript source changed, publishing is source-only by default. Backend Release v2 accepts source-backed create, source-free declarative Automation manifest create, source-only update, and manifest replacement update in one immutable child and one database transaction, so a stale member produces zero resource writes and noops do not advance versions/timestamps. A new Automation with a complete `definitionJson.version="v3"` and no `sourceFile` automatically uses manifest create without `--replace-manifest`; an incomplete definition still fails closed. `--stage-only` is fail-closed: every selected mutation must enter that child, and a missing/incompatible Backend Release API never falls back to direct writes. Online bindings, input/output contracts, metadata, trigger/view configuration, and enabled/published state remain unchanged unless exact `--replace-manifest --reason "..."` authority was provided for an existing resource.
|
|
137
137
|
|
|
138
|
-
Treat resource
|
|
138
|
+
Treat resource declarations as environment mapping and release-observability metadata, not as per-Function authorization. Trusted code can access Forms/DataViews inside its current tenant and application without repeating every resource in every manifest; cross-app and cross-tenant access remains forbidden. Source analysis reports undeclared application resources as warnings. Explicit duplicate Automation outer/runtime declarations must still match, and explicit environment-specific code-to-ID mappings remain part of the sealed/read-back release contract.
|
|
139
139
|
|
|
140
140
|
An App Function may declare metadata-only top-level `secretRefs: [{ name, required }]` only with `function_v2` + `trusted_node_v2`; source resolves values with `await ctx.secrets.get(name)` and uses `ctx.utils.http` for controlled public HTTPS. Create/rotate values through hidden TTY or `openxiangda secret ... --value-stdin --change <change> --profile <name>`. Never put values in arguments, files, manifests, state, plans, logs, errors, or chat. Secret bindings require `backend_release_v2` and whole-app `atomic_staged_children_v2`; a missing capability is fail-closed and never uses the legacy source PATCH. For whole-app activation use exact-scope `resource publish <type> --only <code> --stage-only`, then pass the returned verified `stagedResource` to `release app-finalize`; an active Backend Release is never labeled staged.
|
|
141
141
|
|
|
@@ -291,7 +291,7 @@ Author source in `src/js-code-nodes/<scriptCode>/index.ts`. AI-authored source m
|
|
|
291
291
|
|
|
292
292
|
The backend runs the snapshot in the trusted Node runtime, applies the node timeout (`30000` ms by default), stores execution logs, and writes the returned value to the node output and `variables.node_<nodeId>`. Scripts may use `export default async function (ctx) {}`, `module.exports = async (ctx) => {}`, `require`, `process`, `Buffer`, arbitrary HTTP, and `platform.api` for `/openxiangda-api/v1`.
|
|
293
293
|
|
|
294
|
-
Runtime context includes `ctx.triggerEvent`, `ctx.formData`, `ctx.workflowData`, `ctx.operator`, `ctx.app`, `ctx.variables`, and `ctx.node`. Prefer the higher-level resource helpers when available: `ctx.resources.resolveForm/resolveDataView/resolveConnector`, `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.dataView.query/stats`, `ctx.connector.call/invoke`, `ctx.notification.*`, `ctx.platform.roles.*`, and `ctx.platform.api.*`. Use `ctx.platform.roles.findByCode/addUsers/removeUser` for app role member synchronization; raw `ctx.platform.api.*` returns an HTTP response and platform envelope. App Function and trusted-node
|
|
294
|
+
Runtime context includes `ctx.triggerEvent`, `ctx.formData`, `ctx.workflowData`, `ctx.operator`, `ctx.app`, `ctx.variables`, and `ctx.node`. Prefer the higher-level resource helpers when available: `ctx.resources.resolveForm/resolveDataView/resolveConnector`, `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.files.readAsBase64`, `ctx.dataView.query/stats`, `ctx.connector.call/invoke`, `ctx.notification.*`, `ctx.platform.roles.*`, and `ctx.platform.api.*`. `ctx.files.readAsBase64` reads only server-authorized image attachments from current form data or an explicit form record/field reference, never an arbitrary URL; the file limit is 10 MiB and its Base64 result must not be logged or persisted. Use `ctx.platform.roles.findByCode/addUsers/removeUser` for app role member synchronization; raw `ctx.platform.api.*` returns an HTTP response and platform envelope. Published App Function and trusted-node code may write forms in its current tenant/application; per-resource declarations are mapping and audit metadata, not an application-internal allowlist. This does not grant page users direct submit access, so keep internal forms closed to raw user submission unless the business requires it. Legacy data/process bridge methods remain available as `ctx.methods.queryOneData`, `queryManyData`, `getDataByFormInstanceId`, `updateOneData`, `updateDataByFormInstanceId`, `updateManyData`, `createOneData`, `terminateProcess`, and `getAllParentDepartments`.
|
|
295
295
|
|
|
296
296
|
Code automation also exposes `ctx.logger.debug/info/warn/error(message, data?)`. AI-authored code should log input parsing, query conditions, external calls, writes, branch decisions, and caught errors. Logs are stored as full raw execution data by default. Use CLI diagnosis commands:
|
|
297
297
|
|
|
@@ -32,7 +32,7 @@ Notification manifests live under `src/resources/notifications/` and contain `te
|
|
|
32
32
|
|
|
33
33
|
Data view manifests live under `src/resources/data-views/` and define read-only joined or aggregate query resources. Use `storageMode: "materialized"` for refreshed lists/reports where lag is acceptable, and `storageMode: "live"` for bounded real-time query shapes. Use row views with `sdk.dataView.query` and aggregate views with `sdk.dataView.stats`. Before generating one, confirm freshness tolerance, query bounds, and indexes for materialized filters/sort fields/dimensions/date buckets. Do not use them for single-form CRUD, simple linkedForm selects, writes, write-back, or ad-hoc BI. See `data-views.md` before generating one.
|
|
34
34
|
|
|
35
|
-
App Function manifests live under `src/resources/functions/`, with source in `src/functions/<functionCode>/index.ts`. Use them for reusable server-side logic that pages, automations, and workflows can share through `sdk.function.invoke` or `function_call` nodes. App Functions expose controlled runtime helpers such as `ctx.resources`, `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.process.startFromExistingInstance/resolveCapabilities/resubmitTask/withdraw/transferTask`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, `ctx.organization`, `ctx.platform.roles`, and `ctx.platform.api`; they do not expose raw SQL or Redis in the current MVP.
|
|
35
|
+
App Function manifests live under `src/resources/functions/`, with source in `src/functions/<functionCode>/index.ts`. Use them for reusable server-side logic that pages, automations, and workflows can share through `sdk.function.invoke` or `function_call` nodes. App Functions expose controlled runtime helpers such as `ctx.resources`, `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.process.startFromExistingInstance/resolveCapabilities/resubmitTask/withdraw/transferTask`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, `ctx.organization`, `ctx.platform.roles`, and `ctx.platform.api`; they do not expose raw SQL or Redis in the current MVP. Published trusted code may use all application-owned Forms/DataViews in the current tenant/app. Function `resources` remains optional code-to-ID mapping and audit metadata, while cross-app/cross-tenant access stays forbidden. Use `ctx.platform.roles.list/findByCode/addUsers/removeUser` for app role lookup and membership changes; raw `ctx.platform.api` returns an HTTP response plus platform envelope. Runtime page invocations also expose trusted role context on `ctx.operator.roleCodes`, `ctx.operator.currentRoleCode`, `ctx.operator.hasFullAccess`, `ctx.currentUser`, and `ctx.permissions`; use that context for business authorization, and never trust page-submitted role codes for sensitive actions. Page-call grants should use `definitionJson.runtimeInvoke.audience` (`authenticated`, `page_permission_group`, `app_roles`, or `scope_policy`); `roleCodes` is only for current app-role grants and does not support `"*"` or `"all-app-roles"`. App Function form writes are trusted backend operations, not direct page-user submit access to the target form. For internal function-only forms, publish form settings with `runtimeWrite.mode="function_only"` so raw write endpoints are closed. App Function organization writes require `app:organization:manage` on the real operator/audit actor. Use JS_CODE V2 only for node-local workflow/automation scripts.
|
|
36
36
|
|
|
37
37
|
Auth manifests live under `src/resources/auth/`. Use them to enable app-level login methods and bind phone-code/CAS/custom providers to App Functions. Auth provider functions are called only by the platform auth flow. They validate external credentials and return identity assertions such as `phone`, `email`, `externalId`, or `unionId`; they must not issue tokens, set cookies, or mutate platform user/binding tables.
|
|
38
38
|
|
|
@@ -16,6 +16,7 @@ Guidelines:
|
|
|
16
16
|
- Use `sdk.function.invoke(code, { input })` for reusable backend business logic declared under `src/resources/functions/` and `src/functions/`. Do not implement multi-form orchestration, connector fan-out, notification orchestration, or permission-sensitive backend rules directly in a page component.
|
|
17
17
|
- Use `sdk.connector.invoke`, `sdk.connector.call("connector.api")`, or `sdk.connector.download` for external services. The SDK calls the platform runtime connector endpoint; it must not call third-party domains directly.
|
|
18
18
|
- Use `sdk.notification.sendByType` and `batchSendByType` for reusable business messages. Custom notification types must be declared in `src/resources/notifications/` and published with `openxiangda resource publish`.
|
|
19
|
+
- Use `sdk.export.create` and `sdk.export.get` for asynchronous XLSX exports. Simple pages may send a declarative workbook definition. Complex or reusable exports should send only a published App Function `definitionCode`, the current query snapshot, export scope, and stable selected row IDs. The server executes `structured_export_provider_v1` with fresh user permissions; never upload executable rendering code from the browser. See `docs/structured-export-v1.md`.
|
|
19
20
|
- Use `AttachmentPreviewList`, `ImagePreviewGrid`, or `useFilePreview` from `openxiangda/runtime/react` for in-page attachment previews in a custom React SPA page. They use the current PageSdk context and enforce the platform capability and ticket contracts. Use `sdk.createFileAccessTicket(bucketName, objectName, fileName, "preview", { appType })` only when the page needs a shareable or new-window preview link. `appType` defaults to the current page context. Open `response.result.previewPageUrl`; do not use `previewUrl` or `/service/file/preview-by-ticket/:ticket` as the page entry.
|
|
20
21
|
- Use `sdk.organization.departments.*` and `sdk.organization.accounts.*` only for intentional organization pages. Read-only list/detail pages need `app:organization:read` or `app:organization:manage`; writes and password operations need `app:organization:manage`. Do not call legacy `/user` or `/department` endpoints from pages.
|
|
21
22
|
- Use `sdk.workCenter.listItems({ boxType })` and `sdk.workCenter.getStats()` for current-user work center lists and counts. `boxType` is one of `todo`, `done`, `cc`, or `initiated`. This is the end-user task/handled/cc/initiated surface; do not build todo pages by reading workflow operation logs, automation logs, or raw process-task tables.
|
|
@@ -187,7 +188,32 @@ App Function source should prefer `export default async function(ctx, input) {}`
|
|
|
187
188
|
The second argument is the `input` passed by `sdk.function.invoke`, and the
|
|
188
189
|
same value is also available as `ctx.input` for compatibility.
|
|
189
190
|
|
|
190
|
-
Use App Functions when the logic must run server-side and be reusable by pages, automations, or workflows. Runtime invocation requires app automation management permission by default. To let ordinary app users call a function from a page, declare `definitionJson.runtimeInvoke.audience` with `authenticated`, `page_permission_group`, `app_roles`, or `scope_policy`; use `roleCodes` only for current app-role grants. Do not use `"*"` or `"all-app-roles"` as role codes. Inside the function, authorize sensitive actions with trusted runtime context such as `ctx.operator.roleCodes`, `ctx.operator.currentRoleCode`, `ctx.operator.hasFullAccess`, `ctx.currentUser`, or `ctx.permissions`; do not trust role codes sent in the page input.
|
|
191
|
+
Use App Functions when the logic must run server-side and be reusable by pages, automations, or workflows. Runtime invocation requires app automation management permission by default. To let ordinary app users call a function from a page, declare `definitionJson.runtimeInvoke.audience` with `authenticated`, `page_permission_group`, `app_roles`, or `scope_policy`; use `roleCodes` only for current app-role grants. Do not use `"*"` or `"all-app-roles"` as role codes. Inside the function, authorize sensitive actions with trusted runtime context such as `ctx.operator.roleCodes`, `ctx.operator.currentRoleCode`, `ctx.operator.hasFullAccess`, `ctx.currentUser`, or `ctx.permissions`; do not trust role codes sent in the page input. Published trusted code may write any form in its current tenant/application; per-function `resources.forms` is optional mapping and audit metadata, not an authorization allowlist. Do not open direct submit permission on internal forms just for that page action.
|
|
192
|
+
|
|
193
|
+
Server-defined export:
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
const response = await sdk.export.create({
|
|
197
|
+
exportKey: "orders",
|
|
198
|
+
definitionCode: "order_export_provider",
|
|
199
|
+
definitionInput: { variant: "finance" },
|
|
200
|
+
query: {
|
|
201
|
+
filters,
|
|
202
|
+
sorts: [{ field: "createTime", direction: "descend" }],
|
|
203
|
+
},
|
|
204
|
+
scope: selectedIds.length ? "selected" : "all",
|
|
205
|
+
rowIds: selectedIds,
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
const task = response.result
|
|
209
|
+
const latest = task ? await sdk.export.get(task.id) : null
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
`definitionCode` must identify a published, permission-scoped App Function
|
|
213
|
+
implementing `structured_export_provider_v1`. Its `describe` phase owns the
|
|
214
|
+
workbook and column definition; its paged `query` phase owns trusted data
|
|
215
|
+
selection and custom computed fields. The platform owns the queue, permission
|
|
216
|
+
revalidation, XLSX generation, formula hardening, storage, and download ticket.
|
|
191
217
|
|
|
192
218
|
Organization management:
|
|
193
219
|
|
|
@@ -678,7 +678,7 @@ const result = await sdk.function.invoke("reservation_reminder_summary", {
|
|
|
678
678
|
}
|
|
679
679
|
```
|
|
680
680
|
|
|
681
|
-
适用边界:可复用后端业务逻辑、跨页面/自动化/流程共享的查询编排、连接器调用、通知编排、受控平台 API 调用。App Function 支持 `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`、`ctx.dataView`、`ctx.connector`、`ctx.notification`、`ctx.platform.roles`、`ctx.platform.api` 等受控 helper,当前 MVP 不暴露原始 SQL/Redis。应用角色查询和成员维护优先使用 `ctx.platform.roles.list/findByCode/addUsers/removeUser`;底层 `ctx.platform.api` 返回 HTTP 包装与平台 envelope
|
|
681
|
+
适用边界:可复用后端业务逻辑、跨页面/自动化/流程共享的查询编排、连接器调用、通知编排、受控平台 API 调用。App Function 支持 `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`、`ctx.dataView`、`ctx.connector`、`ctx.notification`、`ctx.platform.roles`、`ctx.platform.api` 等受控 helper,当前 MVP 不暴露原始 SQL/Redis。应用角色查询和成员维护优先使用 `ctx.platform.roles.list/findByCode/addUsers/removeUser`;底层 `ctx.platform.api` 返回 HTTP 包装与平台 envelope,需要自行解包。已发布可信代码可以访问当前租户、当前应用内的资源;function manifest 的 `resources` 是可选映射、审计和影响分析信息,不再是逐函数权限白名单。页面用户仍不能直接提交内部表单,跨应用和跨租户访问仍被拒绝。运行时接口默认需要应用自动化管理权限;普通用户页面要调用时,用 `definitionJson.runtimeInvoke.audience` 声明 `authenticated`、`page_permission_group`、`app_roles` 或 `scope_policy`,不要把 `"*"`、`"all-app-roles"` 写进 `roleCodes`。若表单只能由函数/流程写入,在 `src/resources/settings/forms/<formCode>.json` 设置 `runtimeWrite.mode="function_only"` 关闭原始写入接口。
|
|
682
682
|
|
|
683
683
|
## 5. Workflow — `src/resources/workflows/<code>/workflow.json`(manifest)+ `src/workflows/<code>/workflow.ts`(代码优先)
|
|
684
684
|
|
|
@@ -389,7 +389,7 @@ For reusable backend logic that should be shared by pages, automations, and work
|
|
|
389
389
|
|
|
390
390
|
Use JS_CODE V2 when the script is local to one workflow node.
|
|
391
391
|
|
|
392
|
-
Scripts can export `export default async function (ctx) {}` or `module.exports = async (ctx) => {}`. The runtime exposes `ctx.triggerEvent`, `ctx.formData`, `ctx.workflowData`, `ctx.operator`, `ctx.app`, `ctx.variables`, `ctx.resources`, `ctx.form`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, `ctx.organization`, `ctx.platform.roles.*`, `ctx.platform.api.*`, `ctx.utils`, `require`, `process`, and `Buffer`. App Functions additionally expose `ctx.process.startFromExistingInstance/resolveCapabilities/resubmitTask/withdraw/transferTask`;
|
|
392
|
+
Scripts can export `export default async function (ctx) {}` or `module.exports = async (ctx) => {}`. The runtime exposes `ctx.triggerEvent`, `ctx.formData`, `ctx.workflowData`, `ctx.operator`, `ctx.app`, `ctx.variables`, `ctx.resources`, `ctx.form`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, `ctx.organization`, `ctx.platform.roles.*`, `ctx.platform.api.*`, `ctx.utils`, `require`, `process`, and `Buffer`. App Functions additionally expose `ctx.process.startFromExistingInstance/resolveCapabilities/resubmitTask/withdraw/transferTask`; trusted code is scoped to its current tenant/application and reuses the real operator's official workflow permission, operation-log, event, idempotency, and replay paths. Per-resource declarations are optional mapping/audit metadata, not an application-internal authorization list. Prefer `ctx.resources.resolveForm/resolveDataView/resolveConnector`, `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.dataView.query/stats`, `ctx.connector.call/invoke`, and `ctx.platform.roles.findByCode/addUsers/removeUser` for platform-side work. Use `ctx.organization.departments.*` and `ctx.organization.accounts.*` only for intentional organization-management flows; the real operator/audit actor must hold `app:organization:manage`. App Function and trusted-node form writes are backend operations, not direct page-user submit access; keep internal forms closed to raw user submission unless the business requires it. Raw `ctx.platform.api.*` calls return HTTP response plus platform envelope. Legacy data/process bridge methods remain available as `ctx.methods.queryOneData/queryManyData/getDataByFormInstanceId/updateOneData/updateDataByFormInstanceId/updateManyData/createOneData/terminateProcess/getAllParentDepartments`.
|
|
393
393
|
|
|
394
394
|
Example `src/js-code-nodes/sync_customer/index.ts`:
|
|
395
395
|
|
|
@@ -63,11 +63,11 @@ openxiangda resource publish function --only function_a,function_b --profile <na
|
|
|
63
63
|
|
|
64
64
|
Selectors apply before manifest parsing, source dependency analysis, and JS_CODE typecheck/build. A scoped Function/Automation plan must touch only the selected targets plus their transitive/shared/ambient dependencies; an unscoped plan intentionally retains full-workspace behavior. Resource commands use the canonical scoped builder packaged with the installed CLI for standard workspaces, so old checked-in builders still receive the optimization; refresh/bootstrap the workspace script only for equivalent manual `pnpm build-js-code` behavior. Nonstandard custom builders remain an explicit compatibility fallback.
|
|
65
65
|
|
|
66
|
-
Function/Automation source analysis also extracts statically declared Form filter and order fields. `resource plan` compares them with each
|
|
66
|
+
Function/Automation source analysis also extracts statically declared Form filter and order fields. `resource plan` resolves them through the target application's resource registry, compares them with each Form's frozen online schema, and reports `formFieldContracts`; publish fails before lease/write when the application mapping or field is missing. A source reference does not need to be repeated in every Function/Automation manifest. Fix the application mapping/source or stage the Form schema in the same reviewed release instead of waiting for a production SQL-column error. Dynamic field names remain runtime-validated by the platform and return `FORM_FIELD_NOT_FOUND` as a configuration error.
|
|
67
67
|
|
|
68
68
|
Source-triggered Function/Automation targets use Backend Release v2 when the platform exposes that capability. One child may mix source-backed create, source-free declarative Automation manifest create, source-only update, and manifest replacement update through explicit per-resource `operation/mode`; the CLI freezes the current Backend Release parent plus Git/change baseline, then runs `prepare -> verify -> activate` or stops verified for `--stage-only`. A new Automation with a complete `definitionJson.version="v3"` and no `sourceFile` automatically uses manifest create without `--replace-manifest`; an incomplete definition still fails closed. Activation CAS-checks the entire set and applies all updates in one transaction. `--stage-only` and Secret-bound Function publishing fail closed when Backend Release v2 is unavailable; compatibility fallback is limited to non-staged, non-Secret publishing after an explicit Backend head 404. Existing online bindings, contracts, metadata, trigger/view configuration, and enabled/published state remain unchanged; noops do not advance versions/timestamps. A deliberate whole-definition replacement of an existing resource requires exact `--only/--code` and `--replace-manifest --reason "<why>"`; SDD bypass does not imply replacement authority.
|
|
69
69
|
|
|
70
|
-
Resource
|
|
70
|
+
Resource declarations are mapping, audit, and impact-analysis metadata rather than per-Function authorization. Trusted application code may use any Form/DataView in its current tenant and app; the platform still rejects cross-app/cross-tenant access. Statically discovered source references that are absent from a Function/Automation manifest are warnings, not publish blockers. When an outer Automation `resources` declaration and runtime `definitionJson.resources` are both explicitly present they must still match, and explicit resource bindings remain sealed/read back so environment-specific code-to-ID mappings cannot silently drift.
|
|
71
71
|
|
|
72
72
|
Repository identity remains strict across immutable releases. If a clone-derived primary repository ID differs from the frozen change source base, the CLI may canonicalize Backend, Workflow, and Root App Release payloads to the frozen ID only when that ID is already present in `releaseSourceRevision.repoAliases`; no alias intersection fails with `RELEASE_SOURCE_REPOSITORY_MISMATCH` before prepare.
|
|
73
73
|
|
|
@@ -103,7 +103,7 @@ Use `workflow pull` to inspect the live definition. Use `workflow list --json` a
|
|
|
103
103
|
|
|
104
104
|
JS_CODE is the backend execution escape hatch for workflow and automation. Use it when the logic must run on the server after a backend trigger, such as a fixed cron schedule, a form date-field schedule, a form submit/update/delete/field-change event, or a workflow approval/process event. It is appropriate for cross-form data queries, create/update/batch update operations, process termination, platform API calls, external HTTP calls, and complex orchestration that the frontend cannot handle reliably.
|
|
105
105
|
|
|
106
|
-
App Function is the reusable backend execution model. Use it when the logic should be called by custom pages, multiple automations, workflows, or the runtime API. Source lives in `src/functions/<functionCode>/index.ts`; manifest lives in `src/resources/functions/<functionCode>.json`. Call it from pages with `sdk.function.invoke(code, { input })`, from graph definitions with `function_call`, or from the runtime endpoint `/:appType/v1/functions/:code/invoke.json`. Direct runtime invocation defaults to app automation management permission; ordinary page callers must declare `definitionJson.runtimeInvoke.audience` (`authenticated`, `page_permission_group`, `app_roles`, or `scope_policy`). Prefer `export default async function(ctx, input) {}` for App Function source; the second argument is the invoke input and the same value is available as `ctx.input`. Current MVP exposes controlled helpers only and does not expose raw SQL or Redis. App Functions can call `ctx.process.startFromExistingInstance`, `resolveCapabilities`, `resubmitTask`, `withdraw`, and `transferTask`;
|
|
106
|
+
App Function is the reusable backend execution model. Use it when the logic should be called by custom pages, multiple automations, workflows, or the runtime API. Source lives in `src/functions/<functionCode>/index.ts`; manifest lives in `src/resources/functions/<functionCode>.json`. Call it from pages with `sdk.function.invoke(code, { input })`, from graph definitions with `function_call`, or from the runtime endpoint `/:appType/v1/functions/:code/invoke.json`. Direct runtime invocation defaults to app automation management permission; ordinary page callers must declare `definitionJson.runtimeInvoke.audience` (`authenticated`, `page_permission_group`, `app_roles`, or `scope_policy`). Prefer `export default async function(ctx, input) {}` for App Function source; the second argument is the invoke input and the same value is available as `ctx.input`. Current MVP exposes controlled helpers only and does not expose raw SQL or Redis. App Functions and trusted-node Automation scripts can call `ctx.files.readAsBase64` with an attachment from the current `ctx.formData`, or with a server-verified form record/field reference. This helper reads platform storage without a browser session, rejects arbitrary URLs and non-images, caps files at 10 MiB, and must be used without logging or persisting the Base64. App Functions can call `ctx.process.startFromExistingInstance`, `resolveCapabilities`, `resubmitTask`, `withdraw`, and `transferTask`; published trusted code may access resources in its current tenant/application, while workflow/task authorization, audit, event, replay, cross-app, and cross-tenant boundaries remain enforced. `resources` is optional mapping/audit metadata rather than an application-internal authorization list. Keep internal forms closed to direct user submit unless the business explicitly needs raw form submission; use `runtimeWrite.mode="function_only"` for function-only forms.
|
|
107
107
|
|
|
108
108
|
For third-party credentials, use top-level metadata-only `secretRefs` plus `definitionJson.version="function_v2"` and `runtimeContractVersion="trusted_node_v2"`; read a declared value with `await ctx.secrets.get(name)` and call public business APIs through `ctx.utils.http`. Never use `process.env` for platform secrets. Values are managed with `openxiangda secret create|rotate --value-stdin --change <change> --profile <name>` and never appear in Git, build output, snapshots, plan diffs, logs, exceptions, or traces. Local tests may use `function test --secret-from-env logical=ENV` only; the value is passed to an isolated child over stdin and is never written to workspace/cache/state. For a Root App transaction, use exact-scope `resource publish function --only <code> --stage-only` and include its verified `stagedResource` in `release app-finalize`.
|
|
109
109
|
|
|
@@ -143,7 +143,7 @@ Inside the TypeScript script, prefer `export default async function (ctx) {}` or
|
|
|
143
143
|
- Data/process methods: `ctx.methods.queryOneData`, `queryManyData`, `getDataByFormInstanceId`, `updateOneData`, `updateDataByFormInstanceId`, `updateManyData`, `createOneData`, `terminateProcess`, and `getAllParentDepartments`.
|
|
144
144
|
- Notification bridge: `ctx.notification.sendByType`, `batchSendByType`, `findConfig`, and `previewTemplate`. Declare templates in `src/resources/notifications/` before using custom `notificationType`.
|
|
145
145
|
- Platform API bridge: `ctx.platform.api.get/post/put/patch/delete/request` for `/openxiangda-api/v1`; role helpers: `ctx.platform.roles.list/findByCode/addUsers/removeUser`.
|
|
146
|
-
- Resource helpers: `ctx.resources.resolveForm/resolveDataView/resolveConnector`, `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.process.startFromExistingInstance/resolveCapabilities/resubmitTask/withdraw/transferTask` for App Functions, `ctx.dataView.query/stats`, and `ctx.connector.call/invoke`.
|
|
146
|
+
- Resource helpers: `ctx.resources.resolveForm/resolveDataView/resolveConnector`, `ctx.form.queryOne/queryMany/getById/createOne/updateOne/updateById`, `ctx.files.readAsBase64`, `ctx.process.startFromExistingInstance/resolveCapabilities/resubmitTask/withdraw/transferTask` for App Functions, `ctx.dataView.query/stats`, and `ctx.connector.call/invoke`.
|
|
147
147
|
- Node runtime helpers: `require`, `process`, `Buffer`, `ctx.utils`, `ctx.utils.http`, and `ctx.console`.
|
|
148
148
|
|
|
149
149
|
Example `function_call` node:
|
package/package.json
CHANGED
|
@@ -35926,6 +35926,35 @@ var createPageSdk = (context) => {
|
|
|
35926
35926
|
});
|
|
35927
35927
|
}
|
|
35928
35928
|
};
|
|
35929
|
+
const structuredExport = {
|
|
35930
|
+
create: (params) => request({
|
|
35931
|
+
path: buildOpenXiangdaAppPath(
|
|
35932
|
+
context,
|
|
35933
|
+
params.appType,
|
|
35934
|
+
"/exports"
|
|
35935
|
+
),
|
|
35936
|
+
method: "post",
|
|
35937
|
+
body: {
|
|
35938
|
+
...params,
|
|
35939
|
+
appType: void 0,
|
|
35940
|
+
protocol: "structured_export_v1"
|
|
35941
|
+
}
|
|
35942
|
+
}),
|
|
35943
|
+
get: (taskId, params = {}) => {
|
|
35944
|
+
const normalizedTaskId = String(taskId || "").trim();
|
|
35945
|
+
if (!normalizedTaskId) {
|
|
35946
|
+
throw new Error("\u5BFC\u51FA\u4EFB\u52A1 ID \u4E0D\u80FD\u4E3A\u7A7A");
|
|
35947
|
+
}
|
|
35948
|
+
return request({
|
|
35949
|
+
path: buildOpenXiangdaAppPath(
|
|
35950
|
+
context,
|
|
35951
|
+
params.appType,
|
|
35952
|
+
`/exports/${encodePathSegment(normalizedTaskId)}`
|
|
35953
|
+
),
|
|
35954
|
+
method: "get"
|
|
35955
|
+
});
|
|
35956
|
+
}
|
|
35957
|
+
};
|
|
35929
35958
|
const notification2 = {
|
|
35930
35959
|
sendByType: (params) => request({
|
|
35931
35960
|
path: buildOpenXiangdaAppPath(
|
|
@@ -36100,6 +36129,7 @@ var createPageSdk = (context) => {
|
|
|
36100
36129
|
request,
|
|
36101
36130
|
download,
|
|
36102
36131
|
createFileAccessTicket,
|
|
36132
|
+
export: structuredExport,
|
|
36103
36133
|
transport: {
|
|
36104
36134
|
request,
|
|
36105
36135
|
download
|
|
@@ -44846,14 +44876,27 @@ function AdminList(props) {
|
|
|
44846
44876
|
if (!dataSource.createExportTask) return;
|
|
44847
44877
|
setExporting(true);
|
|
44848
44878
|
try {
|
|
44879
|
+
const exportColumns = (preference.columns || []).filter((column) => column.visible !== false).map((column) => columns.find((item) => item.key === column.key)).filter(
|
|
44880
|
+
(definition) => Boolean(
|
|
44881
|
+
definition && definition.exportable !== false && definition.export !== false
|
|
44882
|
+
)
|
|
44883
|
+
).map((definition) => {
|
|
44884
|
+
const configured = definition.export || {};
|
|
44885
|
+
const title = typeof definition.title === "string" || typeof definition.title === "number" ? String(definition.title) : definition.key;
|
|
44886
|
+
const dataPath = Array.isArray(definition.dataIndex) ? definition.dataIndex.join(".") : definition.dataIndex || definition.key;
|
|
44887
|
+
return {
|
|
44888
|
+
key: definition.key,
|
|
44889
|
+
title,
|
|
44890
|
+
valuePath: dataPath,
|
|
44891
|
+
...configured
|
|
44892
|
+
};
|
|
44893
|
+
});
|
|
44849
44894
|
const input = {
|
|
44850
44895
|
scope,
|
|
44851
44896
|
query: { ...query },
|
|
44852
44897
|
rowIds: scope === "selected" ? selectedKeys : void 0,
|
|
44853
|
-
fieldKeys:
|
|
44854
|
-
|
|
44855
|
-
return definition && definition.exportable !== false;
|
|
44856
|
-
}),
|
|
44898
|
+
fieldKeys: exportColumns.map((column) => column.key),
|
|
44899
|
+
columns: exportColumns,
|
|
44857
44900
|
fileName
|
|
44858
44901
|
};
|
|
44859
44902
|
const created = await dataSource.createExportTask(input);
|
|
@@ -45751,13 +45794,33 @@ var createExportClient = (options, source) => {
|
|
|
45751
45794
|
)}/admin-list/exports`;
|
|
45752
45795
|
return {
|
|
45753
45796
|
createExportTask: async (input) => {
|
|
45797
|
+
const normalizedInput = {
|
|
45798
|
+
...input,
|
|
45799
|
+
rowIds: input.rowIds?.map(
|
|
45800
|
+
(rowId) => typeof rowId === "number" ? rowId : String(rowId)
|
|
45801
|
+
)
|
|
45802
|
+
};
|
|
45803
|
+
if (options.sdk.export?.create) {
|
|
45804
|
+
const response2 = await options.sdk.export.create({
|
|
45805
|
+
appType,
|
|
45806
|
+
exportKey: options.listKey,
|
|
45807
|
+
source,
|
|
45808
|
+
...normalizedInput,
|
|
45809
|
+
definitionCode: options.exportDefinitionCode,
|
|
45810
|
+
definitionInput: options.exportDefinitionInput
|
|
45811
|
+
});
|
|
45812
|
+
if (!response2.result) {
|
|
45813
|
+
throw new Error("\u521B\u5EFA\u5BFC\u51FA\u4EFB\u52A1\u5931\u8D25\uFF1A\u670D\u52A1\u7AEF\u672A\u8FD4\u56DE\u4EFB\u52A1");
|
|
45814
|
+
}
|
|
45815
|
+
return response2.result;
|
|
45816
|
+
}
|
|
45754
45817
|
const response = await options.sdk.request({
|
|
45755
45818
|
path: basePath,
|
|
45756
45819
|
method: "post",
|
|
45757
45820
|
body: {
|
|
45758
45821
|
listKey: options.listKey,
|
|
45759
45822
|
source,
|
|
45760
|
-
...
|
|
45823
|
+
...normalizedInput
|
|
45761
45824
|
}
|
|
45762
45825
|
});
|
|
45763
45826
|
if (!response.result) {
|
|
@@ -45766,6 +45829,13 @@ var createExportClient = (options, source) => {
|
|
|
45766
45829
|
return response.result;
|
|
45767
45830
|
},
|
|
45768
45831
|
getExportTask: async (taskId) => {
|
|
45832
|
+
if (options.sdk.export?.get) {
|
|
45833
|
+
const response2 = await options.sdk.export.get(taskId, { appType });
|
|
45834
|
+
if (!response2.result) {
|
|
45835
|
+
throw new Error("\u67E5\u8BE2\u5BFC\u51FA\u4EFB\u52A1\u5931\u8D25\uFF1A\u4EFB\u52A1\u4E0D\u5B58\u5728");
|
|
45836
|
+
}
|
|
45837
|
+
return response2.result;
|
|
45838
|
+
}
|
|
45769
45839
|
const response = await options.sdk.request({
|
|
45770
45840
|
path: `${basePath}/${encodeURIComponent(taskId)}`,
|
|
45771
45841
|
method: "get"
|