openxiangda 2.34.3 → 2.44.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.
Files changed (242) hide show
  1. package/dist/browser/FilePreviewPage.d.ts.map +1 -1
  2. package/dist/browser/FilePreviewPage.js +4 -2
  3. package/dist/browser/FilePreviewPage.js.map +1 -1
  4. package/dist/browser/ManagedCommand.d.ts +1 -0
  5. package/dist/browser/ManagedCommand.d.ts.map +1 -1
  6. package/dist/browser/ManagedCommand.js +1 -1
  7. package/dist/browser/ManagedCommand.js.map +1 -1
  8. package/dist/browser/Shell.d.ts.map +1 -1
  9. package/dist/browser/Shell.js +1 -1
  10. package/dist/browser/Shell.js.map +1 -1
  11. package/dist/browser/application.d.ts.map +1 -1
  12. package/dist/browser/application.js +5 -4
  13. package/dist/browser/application.js.map +1 -1
  14. package/dist/browser/components/administration/RoleMembershipManager.d.ts +7 -0
  15. package/dist/browser/components/administration/RoleMembershipManager.d.ts.map +1 -0
  16. package/dist/browser/components/administration/RoleMembershipManager.js +724 -0
  17. package/dist/browser/components/administration/RoleMembershipManager.js.map +1 -0
  18. package/dist/browser/components/administration/membership-batch-model.d.ts +17 -0
  19. package/dist/browser/components/administration/membership-batch-model.d.ts.map +1 -0
  20. package/dist/browser/components/administration/membership-batch-model.js +117 -0
  21. package/dist/browser/components/administration/membership-batch-model.js.map +1 -0
  22. package/dist/browser/components/platform-fields/AttachmentFileList.d.ts.map +1 -1
  23. package/dist/browser/components/platform-fields/AttachmentFileList.js +2 -1
  24. package/dist/browser/components/platform-fields/AttachmentFileList.js.map +1 -1
  25. package/dist/browser/components/platform-fields/MobileManagedFileField.d.ts +3 -1
  26. package/dist/browser/components/platform-fields/MobileManagedFileField.d.ts.map +1 -1
  27. package/dist/browser/components/platform-fields/MobileManagedFileField.js +9 -5
  28. package/dist/browser/components/platform-fields/MobileManagedFileField.js.map +1 -1
  29. package/dist/browser/components/resource/SurfaceFields.d.ts +3 -2
  30. package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -1
  31. package/dist/browser/components/resource/SurfaceFields.js +9 -9
  32. package/dist/browser/components/resource/SurfaceFields.js.map +1 -1
  33. package/dist/browser/components/resource/useResourceFormDrafts.d.ts.map +1 -1
  34. package/dist/browser/components/workflow/StandardWorkflowPages.d.ts +14 -3
  35. package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
  36. package/dist/browser/components/workflow/StandardWorkflowPages.js +283 -75
  37. package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
  38. package/dist/browser/components/workflow/WorkflowAssignmentRoutingEditor.d.ts +8 -0
  39. package/dist/browser/components/workflow/WorkflowAssignmentRoutingEditor.d.ts.map +1 -0
  40. package/dist/browser/components/workflow/WorkflowAssignmentRoutingEditor.js +174 -0
  41. package/dist/browser/components/workflow/WorkflowAssignmentRoutingEditor.js.map +1 -0
  42. package/dist/browser/components/workflow/WorkflowAssignmentRoutingManager.d.ts +3 -0
  43. package/dist/browser/components/workflow/WorkflowAssignmentRoutingManager.d.ts.map +1 -0
  44. package/dist/browser/components/workflow/WorkflowAssignmentRoutingManager.js +75 -0
  45. package/dist/browser/components/workflow/WorkflowAssignmentRoutingManager.js.map +1 -0
  46. package/dist/browser/components/workflow/WorkflowBusinessStepRecoveryPanel.d.ts +14 -0
  47. package/dist/browser/components/workflow/WorkflowBusinessStepRecoveryPanel.d.ts.map +1 -0
  48. package/dist/browser/components/workflow/WorkflowBusinessStepRecoveryPanel.js +117 -0
  49. package/dist/browser/components/workflow/WorkflowBusinessStepRecoveryPanel.js.map +1 -0
  50. package/dist/browser/components/workflow/WorkflowDelegationManager.d.ts +14 -0
  51. package/dist/browser/components/workflow/WorkflowDelegationManager.d.ts.map +1 -0
  52. package/dist/browser/components/workflow/WorkflowDelegationManager.js +204 -0
  53. package/dist/browser/components/workflow/WorkflowDelegationManager.js.map +1 -0
  54. package/dist/browser/components/workflow/WorkflowDiagram.d.ts +16 -0
  55. package/dist/browser/components/workflow/WorkflowDiagram.d.ts.map +1 -0
  56. package/dist/browser/components/workflow/WorkflowDiagram.js +110 -0
  57. package/dist/browser/components/workflow/WorkflowDiagram.js.map +1 -0
  58. package/dist/browser/components/workflow/WorkflowFlowCanvas.d.ts +23 -0
  59. package/dist/browser/components/workflow/WorkflowFlowCanvas.d.ts.map +1 -0
  60. package/dist/browser/components/workflow/WorkflowFlowCanvas.js +78 -0
  61. package/dist/browser/components/workflow/WorkflowFlowCanvas.js.map +1 -0
  62. package/dist/browser/components/workflow/WorkflowNodeCard.d.ts +15 -0
  63. package/dist/browser/components/workflow/WorkflowNodeCard.d.ts.map +1 -0
  64. package/dist/browser/components/workflow/WorkflowNodeCard.js +16 -0
  65. package/dist/browser/components/workflow/WorkflowNodeCard.js.map +1 -0
  66. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.d.ts +13 -0
  67. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.d.ts.map +1 -0
  68. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js +151 -0
  69. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js.map +1 -0
  70. package/dist/browser/components/workflow/WorkflowTaskCommandReceipt.d.ts +10 -0
  71. package/dist/browser/components/workflow/WorkflowTaskCommandReceipt.d.ts.map +1 -0
  72. package/dist/browser/components/workflow/WorkflowTaskCommandReceipt.js +59 -0
  73. package/dist/browser/components/workflow/WorkflowTaskCommandReceipt.js.map +1 -0
  74. package/dist/browser/components/workflow/WorkflowTaskDraftPanel.d.ts +17 -0
  75. package/dist/browser/components/workflow/WorkflowTaskDraftPanel.d.ts.map +1 -0
  76. package/dist/browser/components/workflow/WorkflowTaskDraftPanel.js +136 -0
  77. package/dist/browser/components/workflow/WorkflowTaskDraftPanel.js.map +1 -0
  78. package/dist/browser/components/workflow/WorkflowTaskFiles.d.ts +20 -0
  79. package/dist/browser/components/workflow/WorkflowTaskFiles.d.ts.map +1 -0
  80. package/dist/browser/components/workflow/WorkflowTaskFiles.js +124 -0
  81. package/dist/browser/components/workflow/WorkflowTaskFiles.js.map +1 -0
  82. package/dist/browser/components/workflow/WorkflowTaskForm.d.ts +49 -0
  83. package/dist/browser/components/workflow/WorkflowTaskForm.d.ts.map +1 -0
  84. package/dist/browser/components/workflow/WorkflowTaskForm.js +141 -0
  85. package/dist/browser/components/workflow/WorkflowTaskForm.js.map +1 -0
  86. package/dist/browser/components/workflow/workflow-flow-layout.d.ts +28 -0
  87. package/dist/browser/components/workflow/workflow-flow-layout.d.ts.map +1 -0
  88. package/dist/browser/components/workflow/workflow-flow-layout.js +54 -0
  89. package/dist/browser/components/workflow/workflow-flow-layout.js.map +1 -0
  90. package/dist/browser/components/workflow/workflow-routing-draft.d.ts +4 -0
  91. package/dist/browser/components/workflow/workflow-routing-draft.d.ts.map +1 -0
  92. package/dist/browser/components/workflow/workflow-routing-draft.js +9 -0
  93. package/dist/browser/components/workflow/workflow-routing-draft.js.map +1 -0
  94. package/dist/browser/durable-command.d.ts +9 -0
  95. package/dist/browser/durable-command.d.ts.map +1 -1
  96. package/dist/browser/durable-command.js +67 -13
  97. package/dist/browser/durable-command.js.map +1 -1
  98. package/dist/browser/navigation-guard.d.ts +3 -1
  99. package/dist/browser/navigation-guard.d.ts.map +1 -1
  100. package/dist/browser/navigation-guard.js +7 -3
  101. package/dist/browser/navigation-guard.js.map +1 -1
  102. package/dist/browser/platform-client.d.ts +76 -3
  103. package/dist/browser/platform-client.d.ts.map +1 -1
  104. package/dist/browser/platform-client.js +292 -47
  105. package/dist/browser/platform-client.js.map +1 -1
  106. package/dist/browser/record-detail.css +10 -0
  107. package/dist/browser/runtime-authorization-recovery.d.ts +7 -0
  108. package/dist/browser/runtime-authorization-recovery.d.ts.map +1 -0
  109. package/dist/browser/runtime-authorization-recovery.js +119 -0
  110. package/dist/browser/runtime-authorization-recovery.js.map +1 -0
  111. package/dist/browser/runtime.d.ts +2 -0
  112. package/dist/browser/runtime.d.ts.map +1 -1
  113. package/dist/browser/runtime.js +39 -13
  114. package/dist/browser/runtime.js.map +1 -1
  115. package/dist/browser/styles.css +155 -0
  116. package/dist/browser/workflow-task-command-recovery.d.ts +17 -0
  117. package/dist/browser/workflow-task-command-recovery.d.ts.map +1 -0
  118. package/dist/browser/workflow-task-command-recovery.js +50 -0
  119. package/dist/browser/workflow-task-command-recovery.js.map +1 -0
  120. package/dist/browser/workflow-task-file-upload.d.ts +18 -0
  121. package/dist/browser/workflow-task-file-upload.d.ts.map +1 -0
  122. package/dist/browser/workflow-task-file-upload.js +35 -0
  123. package/dist/browser/workflow-task-file-upload.js.map +1 -0
  124. package/dist/config.d.ts +1 -1
  125. package/dist/config.d.ts.map +1 -1
  126. package/dist/core.d.ts +9 -1
  127. package/dist/core.d.ts.map +1 -1
  128. package/dist/core.js +3 -0
  129. package/dist/core.js.map +1 -1
  130. package/dist/nest.d.ts +2 -2
  131. package/dist/nest.d.ts.map +1 -1
  132. package/dist/nest.js.map +1 -1
  133. package/dist/react.d.ts +10 -2
  134. package/dist/react.d.ts.map +1 -1
  135. package/dist/react.js +9 -1
  136. package/dist/react.js.map +1 -1
  137. package/documentation/administration.md +190 -0
  138. package/documentation/frontend.md +2 -0
  139. package/documentation/getting-started.md +7 -7
  140. package/documentation/managed-concurrency-frontend.md +9 -4
  141. package/documentation/managed-concurrency.md +10 -0
  142. package/documentation/manifest.json +7 -7
  143. package/documentation/workflow-events.md +237 -3
  144. package/package.json +26 -23
  145. package/releases/2.43.0.json +38 -0
  146. package/releases/2.44.0.json +36 -0
  147. package/skills/manifest.json +1 -1
  148. package/skills/openxiangda-v2/SKILL.md +4 -4
  149. package/skills/openxiangda-v2/references/administration.md +190 -0
  150. package/skills/openxiangda-v2/references/frontend.md +2 -0
  151. package/skills/openxiangda-v2/references/getting-started.md +7 -7
  152. package/skills/openxiangda-v2/references/managed-concurrency-frontend.md +9 -4
  153. package/skills/openxiangda-v2/references/managed-concurrency.md +10 -0
  154. package/skills/openxiangda-v2/references/workflow-events.md +237 -3
  155. package/releases/2.0.0.json +0 -50
  156. package/releases/2.0.1.json +0 -39
  157. package/releases/2.1.0.json +0 -44
  158. package/releases/2.1.1.json +0 -48
  159. package/releases/2.10.0.json +0 -42
  160. package/releases/2.11.0.json +0 -41
  161. package/releases/2.12.0.json +0 -38
  162. package/releases/2.13.0.json +0 -41
  163. package/releases/2.13.1.json +0 -33
  164. package/releases/2.13.2.json +0 -31
  165. package/releases/2.14.0.json +0 -41
  166. package/releases/2.15.0.json +0 -40
  167. package/releases/2.16.0.json +0 -41
  168. package/releases/2.17.0.json +0 -39
  169. package/releases/2.17.1.json +0 -34
  170. package/releases/2.18.0.json +0 -37
  171. package/releases/2.18.1.json +0 -31
  172. package/releases/2.18.10.json +0 -29
  173. package/releases/2.18.2.json +0 -30
  174. package/releases/2.18.3.json +0 -30
  175. package/releases/2.18.9.json +0 -37
  176. package/releases/2.19.0.json +0 -38
  177. package/releases/2.2.0.json +0 -48
  178. package/releases/2.2.1.json +0 -35
  179. package/releases/2.2.2.json +0 -34
  180. package/releases/2.20.0.json +0 -36
  181. package/releases/2.20.1.json +0 -30
  182. package/releases/2.20.4.json +0 -30
  183. package/releases/2.21.0.json +0 -35
  184. package/releases/2.21.1.json +0 -36
  185. package/releases/2.21.2.json +0 -34
  186. package/releases/2.21.3.json +0 -31
  187. package/releases/2.21.4.json +0 -31
  188. package/releases/2.22.0.json +0 -35
  189. package/releases/2.22.1.json +0 -32
  190. package/releases/2.22.2.json +0 -35
  191. package/releases/2.22.3.json +0 -32
  192. package/releases/2.22.4.json +0 -33
  193. package/releases/2.22.5.json +0 -31
  194. package/releases/2.22.6.json +0 -29
  195. package/releases/2.22.7.json +0 -29
  196. package/releases/2.23.0.json +0 -34
  197. package/releases/2.24.0.json +0 -33
  198. package/releases/2.24.1.json +0 -33
  199. package/releases/2.24.2.json +0 -31
  200. package/releases/2.24.3.json +0 -33
  201. package/releases/2.25.0.json +0 -31
  202. package/releases/2.25.1.json +0 -33
  203. package/releases/2.25.2.json +0 -32
  204. package/releases/2.25.3.json +0 -32
  205. package/releases/2.26.0.json +0 -41
  206. package/releases/2.27.0.json +0 -38
  207. package/releases/2.28.0.json +0 -37
  208. package/releases/2.28.1.json +0 -34
  209. package/releases/2.29.0.json +0 -37
  210. package/releases/2.29.1.json +0 -34
  211. package/releases/2.29.2.json +0 -32
  212. package/releases/2.3.0.json +0 -37
  213. package/releases/2.30.0.json +0 -34
  214. package/releases/2.31.0.json +0 -39
  215. package/releases/2.31.1.json +0 -38
  216. package/releases/2.31.2.json +0 -34
  217. package/releases/2.31.3.json +0 -32
  218. package/releases/2.31.4.json +0 -33
  219. package/releases/2.31.5.json +0 -33
  220. package/releases/2.31.6.json +0 -29
  221. package/releases/2.31.7.json +0 -29
  222. package/releases/2.31.8.json +0 -33
  223. package/releases/2.31.9.json +0 -33
  224. package/releases/2.32.0.json +0 -38
  225. package/releases/2.33.0.json +0 -33
  226. package/releases/2.34.0.json +0 -38
  227. package/releases/2.34.1.json +0 -34
  228. package/releases/2.34.2.json +0 -36
  229. package/releases/2.34.3.json +0 -35
  230. package/releases/2.4.0.json +0 -37
  231. package/releases/2.4.1.json +0 -35
  232. package/releases/2.5.0.json +0 -37
  233. package/releases/2.6.0.json +0 -37
  234. package/releases/2.7.0.json +0 -37
  235. package/releases/2.7.1.json +0 -31
  236. package/releases/2.8.0.json +0 -32
  237. package/releases/2.8.1.json +0 -30
  238. package/releases/2.9.0.json +0 -33
  239. package/releases/2.9.1.json +0 -31
  240. package/releases/2.9.2.json +0 -33
  241. package/releases/2.9.3.json +0 -31
  242. package/releases/2.9.4.json +0 -37
@@ -1,5 +1,6 @@
1
1
  import { parseBusinessProcessResolution, parseBusinessProcessCommitResult } from 'openxiangda-contracts/browser';
2
2
  import { recoverManagedRead } from './managed-read-recovery';
3
+ import { recoverRuntimeAuthorizationRead } from './runtime-authorization-recovery';
3
4
  import { normalizeWorkflowSurface, SCHEMA_VERSIONS, } from 'openxiangda-contracts/browser';
4
5
  import { useSyncExternalStore } from 'react';
5
6
  import { buildResourceWhere, } from './components/platform-fields/resource-query';
@@ -48,11 +49,17 @@ export function platformRequestDiagnostic(error) {
48
49
  }
49
50
  function responseRequestError(path, init, response, payload, fallback) {
50
51
  const context = requestContext(path, init, response, payload?.requestId);
51
- const code = String(payload?.errorCode || payload?.code || `HTTP_${response.status}`);
52
+ const dataCode = payload?.data && typeof payload.data === 'object' && 'errorCode' in payload.data
53
+ && typeof payload.data.errorCode === 'string' ? payload.data.errorCode : undefined;
54
+ const code = String(payload?.errorCode || dataCode || payload?.code || `HTTP_${response.status}`);
52
55
  const retryAfter = response.headers.get('retry-after');
53
- const retryAfterMs = retryAfter ? (/^\d+(?:\.\d+)?$/.test(retryAfter) ? Number(retryAfter) * 1000 : Date.parse(retryAfter) - Date.now()) : undefined;
56
+ const headerDelay = retryAfter ? (/^\d+(?:\.\d+)?$/.test(retryAfter) ? Number(retryAfter) * 1000 : Date.parse(retryAfter) - Date.now()) : undefined;
57
+ const dataDelay = payload?.data && typeof payload.data === 'object' && 'retryAfterMs' in payload.data
58
+ ? payload.data.retryAfterMs : undefined;
59
+ const delays = [headerDelay, payload?.retryAfterMs, dataDelay]
60
+ .filter((value) => typeof value === 'number' && Number.isFinite(value) && value >= 0);
54
61
  return new OpenXiangdaPlatformRequestError({ code, status: response.status,
55
- retryAfterMs: retryAfterMs !== undefined && Number.isFinite(retryAfterMs) && retryAfterMs >= 0 ? retryAfterMs : undefined,
62
+ retryAfterMs: delays.length ? Math.max(...delays) : undefined,
56
63
  message: response.status >= 400 && response.status < 500 && typeof payload?.message === 'string' && payload.message.trim()
57
64
  ? payload.message
58
65
  : `${code}: ${payload?.message || fallback}${context.requestId ? ` (requestId: ${context.requestId})` : ''}`,
@@ -253,7 +260,16 @@ export async function requestApplicationApi(path, init) {
253
260
  }
254
261
  let activeIdentity;
255
262
  let runtimeAuthorizationLoad;
263
+ let runtimeAuthorizationKey;
256
264
  let runtimeAuthorizationGeneration = 0;
265
+ function clearRuntimeAuthorization() {
266
+ const previous = runtimeAuthorizationLoad;
267
+ runtimeAuthorizationGeneration += 1;
268
+ activeIdentity = undefined;
269
+ runtimeAuthorizationLoad = undefined;
270
+ runtimeAuthorizationKey = undefined;
271
+ previous?.controller.abort(new DOMException('登录身份已变化', 'AbortError'));
272
+ }
257
273
  function applicationServiceBase() {
258
274
  return `/service/openxiangda-api/v2/applications/${applicationCode()}`;
259
275
  }
@@ -264,17 +280,20 @@ let applicationCsrfToken = '';
264
280
  // A workflow command is bound to the header used to issue its one-time surface.
265
281
  const workflowCommandCsrf = new Map();
266
282
  function bindWorkflowCsrf(surface, csrf) {
283
+ bindWorkflowCommandCsrf(surface.commandToken, surface.commandTokenExpiresAt, csrf);
284
+ return surface;
285
+ }
286
+ function bindWorkflowCommandCsrf(commandToken, expiration, csrf) {
267
287
  const now = Date.now();
268
288
  for (const [key, value] of workflowCommandCsrf)
269
289
  if (value.expiresAt <= now)
270
290
  workflowCommandCsrf.delete(key);
271
- const expiresAt = Date.parse(surface.commandTokenExpiresAt || '');
272
- if (surface.commandToken && Number.isFinite(expiresAt) && expiresAt > now) {
273
- if (!workflowCommandCsrf.has(surface.commandToken) && workflowCommandCsrf.size >= 512)
291
+ const expiresAt = Date.parse(expiration || '');
292
+ if (commandToken && Number.isFinite(expiresAt) && expiresAt > now) {
293
+ if (!workflowCommandCsrf.has(commandToken) && workflowCommandCsrf.size >= 512)
274
294
  workflowCommandCsrf.delete(workflowCommandCsrf.keys().next().value);
275
- workflowCommandCsrf.set(surface.commandToken, { csrf, expiresAt });
295
+ workflowCommandCsrf.set(commandToken, { csrf, expiresAt });
276
296
  }
277
- return surface;
278
297
  }
279
298
  async function commandBoundCsrf(commandToken) {
280
299
  const binding = commandToken ? workflowCommandCsrf.get(commandToken) : undefined;
@@ -301,9 +320,7 @@ function isPlatformLogoutSignal(value) {
301
320
  typeof signal.payload.at === 'number');
302
321
  }
303
322
  function invalidatePlatformSession() {
304
- runtimeAuthorizationGeneration += 1;
305
- activeIdentity = undefined;
306
- runtimeAuthorizationLoad = undefined;
323
+ clearRuntimeAuthorization();
307
324
  applicationCsrfToken = '';
308
325
  workflowCommandCsrf.clear();
309
326
  platformSessionListeners.forEach(listener => listener());
@@ -420,8 +437,7 @@ export async function passwordLoginApplication(input) {
420
437
  : {}),
421
438
  }),
422
439
  });
423
- activeIdentity = undefined;
424
- runtimeAuthorizationLoad = undefined;
440
+ clearRuntimeAuthorization();
425
441
  return receipt;
426
442
  }
427
443
  async function startApplicationLoginRedirect(input) {
@@ -445,8 +461,7 @@ export async function completeApplicationDingTalkJsapi(input) {
445
461
  headers: { 'x-openxiangda-csrf-token': applicationCsrfToken },
446
462
  body: JSON.stringify({ code: input.code }),
447
463
  });
448
- activeIdentity = undefined;
449
- runtimeAuthorizationLoad = undefined;
464
+ clearRuntimeAuthorization();
450
465
  return receipt;
451
466
  }
452
467
  function validateRuntimeAuthorization(context) {
@@ -486,19 +501,35 @@ function validateRuntimeAuthorization(context) {
486
501
  };
487
502
  return { state: context.state, identity: activeIdentity };
488
503
  }
489
- async function requestRuntimeAuthorization(generation) {
504
+ async function requestRuntimeAuthorization(generation, signal) {
490
505
  const mount = runtimeMount();
491
- if (mount) {
492
- const context = await requestRead(`${nativeBase()}/authz/current?environmentKey=${encodeURIComponent(mount.environmentKey)}`);
493
- if (generation !== runtimeAuthorizationGeneration) {
506
+ const scope = runtimeAuthorizationScope();
507
+ const assertCurrent = () => {
508
+ if (signal.aborted)
509
+ throw signal.reason;
510
+ if (generation !== runtimeAuthorizationGeneration || runtimeAuthorizationScope() !== scope) {
494
511
  throw new Error('OPENXIANGDA_RUNTIME_AUTHORIZATION_SUPERSEDED');
495
512
  }
513
+ };
514
+ const assertObservedCurrent = () => {
515
+ assertCurrent();
516
+ if (runtimeAuthorizationLoad?.controller.signal !== signal || runtimeAuthorizationLoad.subscribers === 0) {
517
+ throw new DOMException('读取已取消', 'AbortError');
518
+ }
519
+ };
520
+ const read = async (path) => recoverRuntimeAuthorizationRead(async (signal) => {
521
+ assertCurrent();
522
+ const value = await request(path, { signal });
523
+ assertCurrent();
524
+ return value;
525
+ }, signal);
526
+ if (mount) {
527
+ const context = await read(`${nativeBase()}/authz/current?environmentKey=${encodeURIComponent(mount.environmentKey)}`);
528
+ assertObservedCurrent();
496
529
  return validateRuntimeAuthorization(context);
497
530
  }
498
- const current = await requestRead(`${applicationServiceBase()}/dev-sessions/current`);
499
- if (generation !== runtimeAuthorizationGeneration) {
500
- throw new Error('OPENXIANGDA_RUNTIME_AUTHORIZATION_SUPERSEDED');
501
- }
531
+ const current = await read(`${applicationServiceBase()}/dev-sessions/current`);
532
+ assertObservedCurrent();
502
533
  activeIdentity = {
503
534
  ...current.principal,
504
535
  identityScope: `connected-dev:${applicationCode()}:${current.environment.key}:${current.principal.userId}`,
@@ -508,28 +539,93 @@ async function requestRuntimeAuthorization(generation) {
508
539
  };
509
540
  return { state: 'active', identity: activeIdentity };
510
541
  }
511
- export async function loadRuntimeAuthorization(options = {}) {
512
- if (options.refresh) {
513
- runtimeAuthorizationGeneration += 1;
514
- activeIdentity = undefined;
515
- runtimeAuthorizationLoad = undefined;
516
- }
517
- if (runtimeAuthorizationLoad)
518
- return await runtimeAuthorizationLoad;
519
- const generation = runtimeAuthorizationGeneration;
520
- const pending = (async () => {
521
- return await requestRuntimeAuthorization(generation);
522
- })();
523
- runtimeAuthorizationLoad = pending;
542
+ function runtimeAuthorizationScope() {
543
+ const mount = runtimeMount();
544
+ return JSON.stringify([applicationCode(), mount?.environmentKey || null, mount?.runtimeBase || null]);
545
+ }
546
+ export function isRuntimeAuthorizationIdentityRejection(error) {
547
+ return error instanceof OpenXiangdaPlatformRequestError && [401, 403, 409].includes(error.status) ||
548
+ error instanceof Error && /^OPENXIANGDA_RUNTIME_AUTHORIZATION_(?:INVALID|INACTIVE_INVALID|ACTIVE_INVALID|SUPERSEDED)$/.test(error.message);
549
+ }
550
+ function clearRuntimeEntryWait() {
524
551
  try {
525
- return await pending;
526
- }
527
- catch (error) {
528
- if (runtimeAuthorizationLoad === pending) {
529
- runtimeAuthorizationLoad = undefined;
530
- }
531
- throw error;
552
+ if (typeof window !== 'undefined')
553
+ window.sessionStorage?.removeItem(`oxa-entry-wait:${window.location.pathname}`);
554
+ }
555
+ catch { /* Storage restrictions must not prevent a verified runtime from starting. */ }
556
+ }
557
+ function observeRuntimeAuthorization(owner, signal) {
558
+ owner.subscribers++;
559
+ return new Promise((resolve, reject) => {
560
+ let finished = false;
561
+ const finish = () => {
562
+ if (finished)
563
+ return false;
564
+ finished = true;
565
+ signal?.removeEventListener('abort', abort);
566
+ owner.subscribers--;
567
+ return true;
568
+ };
569
+ const abort = () => {
570
+ if (!finish())
571
+ return;
572
+ const reason = signal?.reason || new DOMException('读取已取消', 'AbortError');
573
+ if (!owner.settled && owner.subscribers === 0) {
574
+ // StrictMode can resubscribe in this commit. A real departure still
575
+ // retires the owner in the next microtask, without extending its budget.
576
+ queueMicrotask(() => {
577
+ if (owner.settled || owner.subscribers > 0)
578
+ return;
579
+ if (runtimeAuthorizationLoad === owner) {
580
+ runtimeAuthorizationLoad = undefined;
581
+ runtimeAuthorizationGeneration++;
582
+ }
583
+ owner.controller.abort(reason);
584
+ });
585
+ }
586
+ reject(reason);
587
+ };
588
+ if (signal?.aborted)
589
+ abort();
590
+ else
591
+ signal?.addEventListener('abort', abort, { once: true });
592
+ owner.promise.then(value => { if (finish())
593
+ resolve(value); }, reason => { if (finish())
594
+ reject(reason); });
595
+ });
596
+ }
597
+ export async function loadRuntimeAuthorization(options = {}) {
598
+ if (options.signal?.aborted)
599
+ throw options.signal.reason || new DOMException('读取已取消', 'AbortError');
600
+ const key = runtimeAuthorizationScope();
601
+ if (runtimeAuthorizationKey && runtimeAuthorizationKey !== key)
602
+ clearRuntimeAuthorization();
603
+ let owner = runtimeAuthorizationLoad;
604
+ if (!owner || (options.refresh && owner.settled)) {
605
+ const generation = ++runtimeAuthorizationGeneration;
606
+ owner = { controller: new AbortController(), key, subscribers: 0, settled: false,
607
+ promise: undefined };
608
+ runtimeAuthorizationLoad = owner;
609
+ runtimeAuthorizationKey = key;
610
+ const currentOwner = owner;
611
+ currentOwner.promise = requestRuntimeAuthorization(generation, currentOwner.controller.signal).then(value => {
612
+ currentOwner.settled = true;
613
+ if (runtimeAuthorizationLoad === currentOwner && !currentOwner.controller.signal.aborted)
614
+ clearRuntimeEntryWait();
615
+ return value;
616
+ }, error => {
617
+ currentOwner.settled = true;
618
+ if (runtimeAuthorizationLoad === currentOwner) {
619
+ runtimeAuthorizationLoad = undefined;
620
+ if (isRuntimeAuthorizationIdentityRejection(error)) {
621
+ activeIdentity = undefined;
622
+ workflowCommandCsrf.clear();
623
+ }
624
+ }
625
+ throw error;
626
+ });
532
627
  }
628
+ return await observeRuntimeAuthorization(owner, options.signal);
533
629
  }
534
630
  export async function logoutCurrentUser() {
535
631
  const device = typeof window !== 'undefined' &&
@@ -544,9 +640,7 @@ export async function logoutCurrentUser() {
544
640
  headers: { 'x-openxiangda-csrf-token': applicationCsrfToken },
545
641
  body: JSON.stringify({ environmentKey: runtimeEnvironmentKey(), device }),
546
642
  });
547
- runtimeAuthorizationGeneration += 1;
548
- activeIdentity = undefined;
549
- runtimeAuthorizationLoad = undefined;
643
+ clearRuntimeAuthorization();
550
644
  applicationCsrfToken = '';
551
645
  workflowCommandCsrf.clear();
552
646
  publishPlatformLogout();
@@ -599,7 +693,8 @@ export function createManagedConcurrencyClient() {
599
693
  const scope = JSON.stringify([appCode, identity.environment.id, identity.userId]);
600
694
  const assertScope = () => {
601
695
  if (applicationCode() !== appCode || currentEnvironmentKey() !== environmentKey ||
602
- activeIdentity?.userId !== identity.userId || activeIdentity?.environment.id !== identity.environment.id)
696
+ activeIdentity?.userId !== identity.userId || activeIdentity?.environment.id !== identity.environment.id ||
697
+ activeIdentity?.identityScope !== identity.identityScope)
603
698
  throw new OpenXiangdaPlatformRequestError({ code: 'CONCURRENCY_IDENTITY_CHANGED', status: 401, message: '用户或应用环境已变化,请重新打开原操作' });
604
699
  };
605
700
  const frozenCall = async (path, body, signal) => {
@@ -1256,9 +1351,30 @@ function roleManagementQuery(input = {}) {
1256
1351
  export async function loadRoleManagementCatalog() {
1257
1352
  return await request(`${roleManagementBase()}/catalog?${roleManagementQuery()}`);
1258
1353
  }
1354
+ export async function listRoleManagementScopeValues(dimensionCode, input = {}) {
1355
+ return request(`${roleManagementBase()}/scope-values?${roleManagementQuery({ ...input, dimensionCode })}`);
1356
+ }
1259
1357
  export async function listRoleMemberships(input = {}) {
1260
1358
  return await request(`${roleManagementBase()}/memberships?${roleManagementQuery(input)}`);
1261
1359
  }
1360
+ /** Each item is independent; retain its operationId when recovering an unknown result. */
1361
+ export async function previewRoleMembershipBatch(input) {
1362
+ return request(`${roleManagementBase()}/memberships/batch/preview`, {
1363
+ method: 'POST', body: JSON.stringify({ ...input,
1364
+ schemaVersion: 'openxiangda.native-role-membership-batch-request/v2', environmentKey: currentEnvironmentKey() }),
1365
+ });
1366
+ }
1367
+ export async function executeRoleMembershipBatch(input) {
1368
+ return request(`${roleManagementBase()}/memberships/batch/execute`, {
1369
+ method: 'POST', body: JSON.stringify({ ...input,
1370
+ schemaVersion: 'openxiangda.native-role-membership-batch-request/v2', environmentKey: currentEnvironmentKey() }),
1371
+ });
1372
+ }
1373
+ /** Potential versioned nodes, authorized by the existing workflow management reader. */
1374
+ export async function loadWorkflowRoleReferences(roleCode, input = {}) {
1375
+ const query = roleManagementQuery({ ...input, roleCode });
1376
+ return request(`${applicationServiceBase()}/workflow/management/role-references?${query}`);
1377
+ }
1262
1378
  export async function searchRoleManagementUsers(input) {
1263
1379
  const query = roleManagementQuery({
1264
1380
  purpose: 'authorization-management',
@@ -1441,6 +1557,8 @@ export async function downloadDataFile(resource, fileId, fileName) {
1441
1557
  }
1442
1558
  }
1443
1559
  function workflowFileBase(binding, fileId) {
1560
+ if (binding.taskId)
1561
+ return `${workflowBase()}/tasks/${encodeURIComponent(binding.taskId)}/form-files/${encodeURIComponent(fileId)}?fieldCode=${encodeURIComponent(binding.fieldCode)}`;
1444
1562
  const query = new URLSearchParams({
1445
1563
  resourceCode: binding.resourceCode,
1446
1564
  recordId: binding.recordId,
@@ -1493,6 +1611,42 @@ export async function downloadWorkflowDataFile(binding, fileId, fileName) {
1493
1611
  function workflowBase() {
1494
1612
  return `${applicationServiceBase()}/workflow`;
1495
1613
  }
1614
+ function delegationManagementQuery(input = {}) {
1615
+ if ('environmentKey' in input && input.environmentKey !== currentEnvironmentKey())
1616
+ throw new Error('WORKFLOW_DELEGATION_ENVIRONMENT_MISMATCH');
1617
+ const params = new URLSearchParams({ environmentKey: currentEnvironmentKey() });
1618
+ for (const [key, value] of Object.entries(input))
1619
+ if (value !== undefined && value !== '')
1620
+ params.set(key, String(value));
1621
+ return params;
1622
+ }
1623
+ export async function loadWorkflowDelegationCatalog() {
1624
+ return requestRead(`${workflowBase()}/delegation-management/catalog?${delegationManagementQuery()}`);
1625
+ }
1626
+ export async function listWorkflowDelegations(input = {}) {
1627
+ return requestRead(`${workflowBase()}/delegation-management?${delegationManagementQuery(input)}`);
1628
+ }
1629
+ export async function loadWorkflowDelegation(id) {
1630
+ return requestRead(`${workflowBase()}/delegation-management/${encodeURIComponent(id)}?${delegationManagementQuery()}`);
1631
+ }
1632
+ export async function listWorkflowDelegationCandidates(input) {
1633
+ return requestRead(`${workflowBase()}/delegation-management/candidates?${delegationManagementQuery(input)}`);
1634
+ }
1635
+ export async function loadWorkflowDelegationMutationReceipt(operationId) {
1636
+ return requestRead(`${workflowBase()}/delegation-management/receipts/${encodeURIComponent(operationId)}?${delegationManagementQuery()}`);
1637
+ }
1638
+ async function delegationManagementMutation(input, mode) {
1639
+ if (input.environmentKey !== currentEnvironmentKey())
1640
+ throw new Error('WORKFLOW_DELEGATION_ENVIRONMENT_MISMATCH');
1641
+ const csrfToken = await workflowCsrfToken();
1642
+ return request(`${workflowBase()}/delegation-management/${mode}`, { method: 'POST', headers: { 'x-openxiangda-csrf-token': csrfToken }, body: JSON.stringify(input) });
1643
+ }
1644
+ export async function previewWorkflowDelegationMutation(input) {
1645
+ return delegationManagementMutation(input, 'preview');
1646
+ }
1647
+ export async function executeWorkflowDelegationMutation(input) {
1648
+ return delegationManagementMutation(input, 'execute');
1649
+ }
1496
1650
  export async function loadWorkflowLaunchSurface(workflowCode) {
1497
1651
  const query = new URLSearchParams({
1498
1652
  environmentKey: currentEnvironmentKey(),
@@ -1603,6 +1757,34 @@ export async function loadWorkflowTaskSurface(taskId) {
1603
1757
  const surface = await requestRead(`${workflowBase()}/tasks/${encodeURIComponent(taskId)}/surface`, { headers: { 'x-openxiangda-csrf-token': csrfToken } });
1604
1758
  return bindWorkflowCsrf(normalizeWorkflowSurface(surface), csrfToken);
1605
1759
  }
1760
+ /** Private values remain scoped to the current user and fixed actionable task. */
1761
+ export async function loadWorkflowTaskDrafts(taskId) {
1762
+ return requestRead(`${workflowBase()}/tasks/${encodeURIComponent(taskId)}/form-drafts`);
1763
+ }
1764
+ export async function saveWorkflowTaskDraft(taskId, input) {
1765
+ return request(`${workflowBase()}/tasks/${encodeURIComponent(taskId)}/form-drafts`, {
1766
+ method: 'POST', headers: { 'x-openxiangda-csrf-token': await workflowCsrfToken() }, body: JSON.stringify(input),
1767
+ });
1768
+ }
1769
+ export async function removeWorkflowTaskDraft(taskId, input) {
1770
+ return request(`${workflowBase()}/tasks/${encodeURIComponent(taskId)}/form-drafts/delete`, {
1771
+ method: 'POST', headers: { 'x-openxiangda-csrf-token': await workflowCsrfToken() }, body: JSON.stringify(input),
1772
+ });
1773
+ }
1774
+ /** Fix the upload ID before this call. Retrying uses the same intent and task. */
1775
+ export async function initiateWorkflowTaskFileUpload(taskId, input) {
1776
+ return request(`${workflowBase()}/tasks/${encodeURIComponent(taskId)}/form-files`, {
1777
+ method: 'POST', headers: { 'x-openxiangda-csrf-token': await workflowCsrfToken() }, body: JSON.stringify(input),
1778
+ });
1779
+ }
1780
+ export async function loadWorkflowTaskFileUploadPlan(taskId, fileId) {
1781
+ return requestRead(`${workflowBase()}/tasks/${encodeURIComponent(taskId)}/form-files/${encodeURIComponent(fileId)}`);
1782
+ }
1783
+ export async function completeWorkflowTaskFileUpload(taskId, fileId) {
1784
+ return request(`${workflowBase()}/tasks/${encodeURIComponent(taskId)}/form-files/${encodeURIComponent(fileId)}/complete`, {
1785
+ method: 'POST', headers: { 'x-openxiangda-csrf-token': await workflowCsrfToken() }, body: '{}',
1786
+ });
1787
+ }
1606
1788
  export async function loadWorkflowInstanceSurface(instanceId) {
1607
1789
  const csrfToken = await workflowCsrfToken();
1608
1790
  const surface = await requestRead(`${workflowBase()}/instances/${encodeURIComponent(instanceId)}/surface`, { headers: { 'x-openxiangda-csrf-token': csrfToken } });
@@ -1611,6 +1793,65 @@ export async function loadWorkflowInstanceSurface(instanceId) {
1611
1793
  export async function loadWorkflowTimeline(instanceId) {
1612
1794
  return await requestRead(`${workflowBase()}/instances/${encodeURIComponent(instanceId)}/timeline`);
1613
1795
  }
1796
+ /** Requires the same workflow management authority as the platform console. */
1797
+ export async function loadWorkflowDefinitionGraph(workflowCode, version) {
1798
+ const result = await requestRead(`${workflowBase()}/management/definitions/${encodeURIComponent(workflowCode)}/versions/${version}`);
1799
+ if (!result.graph || result.graph.definitionDigest !== result.definitionDigest)
1800
+ throw new Error('WORKFLOW_V2_GRAPH_DIGEST_MISMATCH');
1801
+ return result;
1802
+ }
1803
+ export async function loadWorkflowInstanceGraph(instanceId) {
1804
+ const result = await requestRead(`${workflowBase()}/management/instances/${encodeURIComponent(instanceId)}/graph`);
1805
+ if (!result.graph || result.graph.definitionDigest !== result.definitionDigest)
1806
+ throw new Error('WORKFLOW_V2_GRAPH_DIGEST_MISMATCH');
1807
+ return result;
1808
+ }
1809
+ export async function loadApplicationAdministrationContext() {
1810
+ return requestRead(`${applicationServiceBase()}/admin/context?${new URLSearchParams({ environmentKey: currentEnvironmentKey() })}`);
1811
+ }
1812
+ /** Same administrator authority as the console; does not grant ordinary users repair access. */
1813
+ export async function loadWorkflowBusinessStepRecovery(instanceId) {
1814
+ return requestRead(`${applicationServiceBase()}/admin/workflow-instances/${encodeURIComponent(instanceId)}/options?${new URLSearchParams({ environmentKey: currentEnvironmentKey() })}`);
1815
+ }
1816
+ export async function previewWorkflowBusinessStepRecovery(instanceId) {
1817
+ const csrf = await workflowCsrfToken();
1818
+ const preview = await request(`${applicationServiceBase()}/admin/workflow-instances/${encodeURIComponent(instanceId)}/preview`, {
1819
+ method: 'POST', headers: { 'x-openxiangda-csrf-token': csrf },
1820
+ body: JSON.stringify({ environmentKey: currentEnvironmentKey(), action: 'admin_retry_step' }),
1821
+ });
1822
+ bindWorkflowCommandCsrf(preview.commandToken, preview.expiresAt, csrf);
1823
+ return preview;
1824
+ }
1825
+ /** Keep this exact token/input/key until the outcome is known. Never executes the external handler. */
1826
+ export async function executeWorkflowBusinessStepRecovery(instanceId, input) {
1827
+ return request(`${applicationServiceBase()}/admin/workflow-instances/${encodeURIComponent(instanceId)}/commands/admin_retry_step`, {
1828
+ method: 'POST', headers: { 'x-openxiangda-csrf-token': await commandBoundCsrf(input.commandToken) }, body: JSON.stringify(input),
1829
+ });
1830
+ }
1831
+ export async function loadWorkflowNodeConfigurations(workflowCode) {
1832
+ return requestRead(`${applicationServiceBase()}/admin/workflows/${encodeURIComponent(workflowCode)}/node-configurations?${new URLSearchParams({ environmentKey: currentEnvironmentKey() })}`);
1833
+ }
1834
+ /** Retain the same operationId and exact input while the write result is unknown. */
1835
+ export async function saveWorkflowNodeConfiguration(workflowCode, nodeId, input) {
1836
+ return request(`${applicationServiceBase()}/admin/workflows/${encodeURIComponent(workflowCode)}/node-configurations/${encodeURIComponent(nodeId)}`, { method: 'POST', body: JSON.stringify({ ...input, environmentKey: currentEnvironmentKey() }) });
1837
+ }
1838
+ export async function loadWorkflowAssignmentRoutingCatalog(input = {}) {
1839
+ const query = new URLSearchParams({ environmentKey: currentEnvironmentKey(), keyword: input.keyword || '', limit: String(input.limit ?? 20), offset: String(input.offset ?? 0) });
1840
+ return request(`${applicationServiceBase()}/admin/workflow-assignment-routing?${query}`);
1841
+ }
1842
+ export async function loadWorkflowAssignmentRoutingConfiguration(policyCode) {
1843
+ return request(`${applicationServiceBase()}/admin/workflow-assignment-routing/${encodeURIComponent(policyCode)}?environmentKey=${encodeURIComponent(currentEnvironmentKey())}`);
1844
+ }
1845
+ export async function loadWorkflowAssignmentRoutingHistory(policyCode, input = {}) {
1846
+ const query = new URLSearchParams({ environmentKey: currentEnvironmentKey(), limit: String(input.limit ?? 20), offset: String(input.offset ?? 0) });
1847
+ return request(`${applicationServiceBase()}/admin/workflow-assignment-routing/${encodeURIComponent(policyCode)}/history?${query}`);
1848
+ }
1849
+ /** Keep the exact mutation and operationId to recover an unknown write result. */
1850
+ export async function saveWorkflowAssignmentRoutingConfiguration(policyCode, input) {
1851
+ return request(`${applicationServiceBase()}/admin/workflow-assignment-routing/${encodeURIComponent(policyCode)}`, {
1852
+ method: 'POST', body: JSON.stringify({ ...input, environmentKey: currentEnvironmentKey() }),
1853
+ });
1854
+ }
1614
1855
  function normalizeWorkflowDetailSurface(detail, csrfToken) {
1615
1856
  return {
1616
1857
  ...detail,
@@ -1685,6 +1926,10 @@ export async function executeWorkflowInstanceCommand(instanceId, command, input)
1685
1926
  body: JSON.stringify(input),
1686
1927
  });
1687
1928
  }
1929
+ /** A read does not consume a token or imply that an unobserved command failed. */
1930
+ export async function loadWorkflowTaskCommandReceipt(taskId, idempotencyKey, tokenDigest) {
1931
+ return await request(`${workflowBase()}/tasks/${encodeURIComponent(taskId)}/commands/original?idempotencyKey=${encodeURIComponent(idempotencyKey)}${tokenDigest ? `&tokenDigest=${encodeURIComponent(tokenDigest)}` : ''}`);
1932
+ }
1688
1933
  /** Execute a server-issued Workflow operation without task/instance branching. */
1689
1934
  export async function executeWorkflowOperation(surface, operation, input = {}, options = {}) {
1690
1935
  if (operation.kind !== 'workflow_command' ||