openxiangda 2.44.0 → 2.55.1

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 (247) hide show
  1. package/dist/browser/AuthoritativeSelector.d.ts +3 -2
  2. package/dist/browser/AuthoritativeSelector.d.ts.map +1 -1
  3. package/dist/browser/AuthoritativeSelector.js +32 -11
  4. package/dist/browser/AuthoritativeSelector.js.map +1 -1
  5. package/dist/browser/FilePreviewPage.d.ts.map +1 -1
  6. package/dist/browser/FilePreviewPage.js +4 -0
  7. package/dist/browser/FilePreviewPage.js.map +1 -1
  8. package/dist/browser/components/administration/RoleMembershipManager.d.ts.map +1 -1
  9. package/dist/browser/components/administration/RoleMembershipManager.js +5 -5
  10. package/dist/browser/components/administration/RoleMembershipManager.js.map +1 -1
  11. package/dist/browser/components/administration/scope-applicability.d.ts +3 -0
  12. package/dist/browser/components/administration/scope-applicability.d.ts.map +1 -0
  13. package/dist/browser/components/administration/scope-applicability.js +7 -0
  14. package/dist/browser/components/administration/scope-applicability.js.map +1 -0
  15. package/dist/browser/components/platform-fields/ConstrainedUserField.d.ts +16 -0
  16. package/dist/browser/components/platform-fields/ConstrainedUserField.d.ts.map +1 -0
  17. package/dist/browser/components/platform-fields/ConstrainedUserField.js +140 -0
  18. package/dist/browser/components/platform-fields/ConstrainedUserField.js.map +1 -0
  19. package/dist/browser/components/platform-fields/JsonField.d.ts.map +1 -1
  20. package/dist/browser/components/platform-fields/JsonField.js +6 -1
  21. package/dist/browser/components/platform-fields/JsonField.js.map +1 -1
  22. package/dist/browser/components/platform-fields/ManagedMediaPlayer.d.ts +19 -0
  23. package/dist/browser/components/platform-fields/ManagedMediaPlayer.d.ts.map +1 -0
  24. package/dist/browser/components/platform-fields/ManagedMediaPlayer.js +42 -0
  25. package/dist/browser/components/platform-fields/ManagedMediaPlayer.js.map +1 -0
  26. package/dist/browser/components/platform-fields/MobileManagedFileField.d.ts.map +1 -1
  27. package/dist/browser/components/platform-fields/MobileManagedFileField.js +6 -1
  28. package/dist/browser/components/platform-fields/MobileManagedFileField.js.map +1 -1
  29. package/dist/browser/components/platform-fields/MobileSelection.d.ts +3 -1
  30. package/dist/browser/components/platform-fields/MobileSelection.d.ts.map +1 -1
  31. package/dist/browser/components/platform-fields/MobileSelection.js +2 -2
  32. package/dist/browser/components/platform-fields/MobileSelection.js.map +1 -1
  33. package/dist/browser/components/platform-fields/MobileSubtableValidation.d.ts +2 -1
  34. package/dist/browser/components/platform-fields/MobileSubtableValidation.d.ts.map +1 -1
  35. package/dist/browser/components/platform-fields/MobileSubtableValidation.js +3 -1
  36. package/dist/browser/components/platform-fields/MobileSubtableValidation.js.map +1 -1
  37. package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts +3 -2
  38. package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts.map +1 -1
  39. package/dist/browser/components/platform-fields/ResourceReferenceField.js +2 -2
  40. package/dist/browser/components/platform-fields/ResourceReferenceField.js.map +1 -1
  41. package/dist/browser/components/platform-fields/RichTextField.d.ts +3 -2
  42. package/dist/browser/components/platform-fields/RichTextField.d.ts.map +1 -1
  43. package/dist/browser/components/platform-fields/RichTextField.js +96 -44
  44. package/dist/browser/components/platform-fields/RichTextField.js.map +1 -1
  45. package/dist/browser/components/platform-fields/SignatureField.d.ts +5 -4
  46. package/dist/browser/components/platform-fields/SignatureField.d.ts.map +1 -1
  47. package/dist/browser/components/platform-fields/SignatureField.js +69 -16
  48. package/dist/browser/components/platform-fields/SignatureField.js.map +1 -1
  49. package/dist/browser/components/platform-fields/SubtableField.d.ts +18 -2
  50. package/dist/browser/components/platform-fields/SubtableField.d.ts.map +1 -1
  51. package/dist/browser/components/platform-fields/SubtableField.js +146 -57
  52. package/dist/browser/components/platform-fields/SubtableField.js.map +1 -1
  53. package/dist/browser/components/platform-fields/managed-media-read.d.ts +19 -0
  54. package/dist/browser/components/platform-fields/managed-media-read.d.ts.map +1 -0
  55. package/dist/browser/components/platform-fields/managed-media-read.js +32 -0
  56. package/dist/browser/components/platform-fields/managed-media-read.js.map +1 -0
  57. package/dist/browser/components/platform-fields/subtable-pagination.d.ts +20 -0
  58. package/dist/browser/components/platform-fields/subtable-pagination.d.ts.map +1 -0
  59. package/dist/browser/components/platform-fields/subtable-pagination.js +39 -0
  60. package/dist/browser/components/platform-fields/subtable-pagination.js.map +1 -0
  61. package/dist/browser/components/platform-fields/subtable-value.d.ts.map +1 -1
  62. package/dist/browser/components/platform-fields/subtable-value.js +2 -1
  63. package/dist/browser/components/platform-fields/subtable-value.js.map +1 -1
  64. package/dist/browser/components/platform-fields/surface-field-validation.d.ts +31 -0
  65. package/dist/browser/components/platform-fields/surface-field-validation.d.ts.map +1 -0
  66. package/dist/browser/components/platform-fields/surface-field-validation.js +36 -0
  67. package/dist/browser/components/platform-fields/surface-field-validation.js.map +1 -0
  68. package/dist/browser/components/platform-fields/user-candidate-context.d.ts +51 -0
  69. package/dist/browser/components/platform-fields/user-candidate-context.d.ts.map +1 -0
  70. package/dist/browser/components/platform-fields/user-candidate-context.js +62 -0
  71. package/dist/browser/components/platform-fields/user-candidate-context.js.map +1 -0
  72. package/dist/browser/components/resource/GeneratedResourceCrud.d.ts.map +1 -1
  73. package/dist/browser/components/resource/GeneratedResourceCrud.js +26 -2
  74. package/dist/browser/components/resource/GeneratedResourceCrud.js.map +1 -1
  75. package/dist/browser/components/resource/GeneratedResourceForm.js +1 -1
  76. package/dist/browser/components/resource/GeneratedResourceForm.js.map +1 -1
  77. package/dist/browser/components/resource/RecordDetailFrame.d.ts +3 -1
  78. package/dist/browser/components/resource/RecordDetailFrame.d.ts.map +1 -1
  79. package/dist/browser/components/resource/RecordDetailFrame.js +2 -2
  80. package/dist/browser/components/resource/RecordDetailFrame.js.map +1 -1
  81. package/dist/browser/components/resource/ResourceFormFrame.d.ts +2 -1
  82. package/dist/browser/components/resource/ResourceFormFrame.d.ts.map +1 -1
  83. package/dist/browser/components/resource/ResourceFormFrame.js +2 -2
  84. package/dist/browser/components/resource/ResourceFormFrame.js.map +1 -1
  85. package/dist/browser/components/resource/ResourceRecordComments.d.ts +13 -0
  86. package/dist/browser/components/resource/ResourceRecordComments.d.ts.map +1 -0
  87. package/dist/browser/components/resource/ResourceRecordComments.js +75 -0
  88. package/dist/browser/components/resource/ResourceRecordComments.js.map +1 -0
  89. package/dist/browser/components/resource/ResourceRecordDeletion.d.ts +7 -0
  90. package/dist/browser/components/resource/ResourceRecordDeletion.d.ts.map +1 -0
  91. package/dist/browser/components/resource/ResourceRecordDeletion.js +53 -0
  92. package/dist/browser/components/resource/ResourceRecordDeletion.js.map +1 -0
  93. package/dist/browser/components/resource/ResourceRecordPrintPreview.d.ts +16 -0
  94. package/dist/browser/components/resource/ResourceRecordPrintPreview.d.ts.map +1 -0
  95. package/dist/browser/components/resource/ResourceRecordPrintPreview.js +92 -0
  96. package/dist/browser/components/resource/ResourceRecordPrintPreview.js.map +1 -0
  97. package/dist/browser/components/resource/SurfaceFields.d.ts +9 -4
  98. package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -1
  99. package/dist/browser/components/resource/SurfaceFields.js +54 -72
  100. package/dist/browser/components/resource/SurfaceFields.js.map +1 -1
  101. package/dist/browser/components/resource/generated-resource-definition.d.ts +13 -0
  102. package/dist/browser/components/resource/generated-resource-definition.d.ts.map +1 -1
  103. package/dist/browser/components/resource/record-comment-session.d.ts +17 -0
  104. package/dist/browser/components/resource/record-comment-session.d.ts.map +1 -0
  105. package/dist/browser/components/resource/record-comment-session.js +64 -0
  106. package/dist/browser/components/resource/record-comment-session.js.map +1 -0
  107. package/dist/browser/components/resource/record-deletion-session.d.ts +19 -0
  108. package/dist/browser/components/resource/record-deletion-session.d.ts.map +1 -0
  109. package/dist/browser/components/resource/record-deletion-session.js +64 -0
  110. package/dist/browser/components/resource/record-deletion-session.js.map +1 -0
  111. package/dist/browser/components/resource/record-print-session.d.ts +12 -0
  112. package/dist/browser/components/resource/record-print-session.d.ts.map +1 -0
  113. package/dist/browser/components/resource/record-print-session.js +32 -0
  114. package/dist/browser/components/resource/record-print-session.js.map +1 -0
  115. package/dist/browser/components/resource/resource-field-selection.d.ts +1 -0
  116. package/dist/browser/components/resource/resource-field-selection.d.ts.map +1 -1
  117. package/dist/browser/components/resource/resource-form-operations.d.ts.map +1 -1
  118. package/dist/browser/components/resource/resource-form-operations.js +5 -1
  119. package/dist/browser/components/resource/resource-form-operations.js.map +1 -1
  120. package/dist/browser/components/resource/useResourceFormDrafts.d.ts.map +1 -1
  121. package/dist/browser/components/workflow/StandardWorkflowPages.d.ts +13 -2
  122. package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
  123. package/dist/browser/components/workflow/StandardWorkflowPages.js +96 -47
  124. package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
  125. package/dist/browser/components/workflow/WorkflowDiagram.d.ts.map +1 -1
  126. package/dist/browser/components/workflow/WorkflowDiagram.js +14 -1
  127. package/dist/browser/components/workflow/WorkflowDiagram.js.map +1 -1
  128. package/dist/browser/components/workflow/WorkflowFlowCanvas.d.ts.map +1 -1
  129. package/dist/browser/components/workflow/WorkflowFlowCanvas.js +27 -8
  130. package/dist/browser/components/workflow/WorkflowFlowCanvas.js.map +1 -1
  131. package/dist/browser/components/workflow/WorkflowNodeCard.js +2 -2
  132. package/dist/browser/components/workflow/WorkflowNodeCard.js.map +1 -1
  133. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.d.ts.map +1 -1
  134. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js +4 -4
  135. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js.map +1 -1
  136. package/dist/browser/components/workflow/WorkflowRecordEditor.js +1 -1
  137. package/dist/browser/components/workflow/WorkflowRecordEditor.js.map +1 -1
  138. package/dist/browser/components/workflow/WorkflowRecordHistoryPanel.d.ts +9 -0
  139. package/dist/browser/components/workflow/WorkflowRecordHistoryPanel.d.ts.map +1 -0
  140. package/dist/browser/components/workflow/WorkflowRecordHistoryPanel.js +50 -0
  141. package/dist/browser/components/workflow/WorkflowRecordHistoryPanel.js.map +1 -0
  142. package/dist/browser/components/workflow/WorkflowTaskFiles.d.ts +5 -3
  143. package/dist/browser/components/workflow/WorkflowTaskFiles.d.ts.map +1 -1
  144. package/dist/browser/components/workflow/WorkflowTaskFiles.js +67 -27
  145. package/dist/browser/components/workflow/WorkflowTaskFiles.js.map +1 -1
  146. package/dist/browser/components/workflow/WorkflowTaskForm.d.ts +6 -1
  147. package/dist/browser/components/workflow/WorkflowTaskForm.d.ts.map +1 -1
  148. package/dist/browser/components/workflow/WorkflowTaskForm.js +65 -16
  149. package/dist/browser/components/workflow/WorkflowTaskForm.js.map +1 -1
  150. package/dist/browser/components/workflow/standard-process-values.d.ts +10 -0
  151. package/dist/browser/components/workflow/standard-process-values.d.ts.map +1 -0
  152. package/dist/browser/components/workflow/standard-process-values.js +25 -0
  153. package/dist/browser/components/workflow/standard-process-values.js.map +1 -0
  154. package/dist/browser/components/workflow/workflow-graph-presentation.d.ts +19 -0
  155. package/dist/browser/components/workflow/workflow-graph-presentation.d.ts.map +1 -0
  156. package/dist/browser/components/workflow/workflow-graph-presentation.js +28 -0
  157. package/dist/browser/components/workflow/workflow-graph-presentation.js.map +1 -0
  158. package/dist/browser/components/workflow/workflow-submission-form.d.ts +18 -0
  159. package/dist/browser/components/workflow/workflow-submission-form.d.ts.map +1 -0
  160. package/dist/browser/components/workflow/workflow-submission-form.js +44 -0
  161. package/dist/browser/components/workflow/workflow-submission-form.js.map +1 -0
  162. package/dist/browser/components/workflow/workflow-task-field-codec.d.ts +4 -0
  163. package/dist/browser/components/workflow/workflow-task-field-codec.d.ts.map +1 -0
  164. package/dist/browser/components/workflow/workflow-task-field-codec.js +9 -0
  165. package/dist/browser/components/workflow/workflow-task-field-codec.js.map +1 -0
  166. package/dist/browser/components/workflow/workflow-task-required-errors.d.ts +10 -0
  167. package/dist/browser/components/workflow/workflow-task-required-errors.d.ts.map +1 -0
  168. package/dist/browser/components/workflow/workflow-task-required-errors.js +28 -0
  169. package/dist/browser/components/workflow/workflow-task-required-errors.js.map +1 -0
  170. package/dist/browser/components/workflow/workflow-task-subtable.d.ts +7 -0
  171. package/dist/browser/components/workflow/workflow-task-subtable.d.ts.map +1 -0
  172. package/dist/browser/components/workflow/workflow-task-subtable.js +58 -0
  173. package/dist/browser/components/workflow/workflow-task-subtable.js.map +1 -0
  174. package/dist/browser/durable-command.d.ts.map +1 -1
  175. package/dist/browser/durable-command.js +6 -1
  176. package/dist/browser/durable-command.js.map +1 -1
  177. package/dist/browser/mobile-fields.css +4 -0
  178. package/dist/browser/platform-client.d.ts +30 -1
  179. package/dist/browser/platform-client.d.ts.map +1 -1
  180. package/dist/browser/platform-client.js +161 -5
  181. package/dist/browser/platform-client.js.map +1 -1
  182. package/dist/browser/record-comments.css +14 -0
  183. package/dist/browser/record-deletion.css +11 -0
  184. package/dist/browser/record-detail.css +4 -2
  185. package/dist/browser/record-print.css +31 -0
  186. package/dist/browser/styles.css +41 -0
  187. package/dist/browser/workflow-operation-input.d.ts +15 -0
  188. package/dist/browser/workflow-operation-input.d.ts.map +1 -0
  189. package/dist/browser/workflow-operation-input.js +64 -0
  190. package/dist/browser/workflow-operation-input.js.map +1 -0
  191. package/dist/browser/workflow-task-file-upload.d.ts.map +1 -1
  192. package/dist/browser/workflow-task-file-upload.js +1 -0
  193. package/dist/browser/workflow-task-file-upload.js.map +1 -1
  194. package/dist/core.d.ts +2 -2
  195. package/dist/core.d.ts.map +1 -1
  196. package/dist/core.js +1 -1
  197. package/dist/core.js.map +1 -1
  198. package/dist/field-kit.d.ts +3 -0
  199. package/dist/field-kit.d.ts.map +1 -1
  200. package/dist/field-kit.js +3 -0
  201. package/dist/field-kit.js.map +1 -1
  202. package/dist/nest.d.ts +1 -1
  203. package/dist/nest.d.ts.map +1 -1
  204. package/dist/nest.js.map +1 -1
  205. package/dist/react.d.ts +6 -2
  206. package/dist/react.d.ts.map +1 -1
  207. package/dist/react.js +5 -1
  208. package/dist/react.js.map +1 -1
  209. package/dist/testing.d.ts +1 -1
  210. package/dist/testing.d.ts.map +1 -1
  211. package/dist/testing.js +1 -1
  212. package/dist/testing.js.map +1 -1
  213. package/documentation/administration.md +7 -1
  214. package/documentation/backend.md +72 -1
  215. package/documentation/data-authz.md +42 -2
  216. package/documentation/declarations-cheatsheet.md +9 -0
  217. package/documentation/field-components.md +45 -1
  218. package/documentation/frontend.md +8 -0
  219. package/documentation/getting-started.md +7 -7
  220. package/documentation/managed-concurrency-frontend.md +1 -1
  221. package/documentation/manifest.json +11 -11
  222. package/documentation/testing.md +17 -0
  223. package/documentation/workflow-events.md +221 -6
  224. package/package.json +22 -25
  225. package/releases/2.51.0.json +32 -0
  226. package/releases/2.54.4.json +30 -0
  227. package/releases/2.54.6.json +30 -0
  228. package/releases/2.55.0.json +34 -0
  229. package/releases/2.55.1.json +32 -0
  230. package/skills/manifest.json +1 -1
  231. package/skills/openxiangda-v2/SKILL.md +4 -4
  232. package/skills/openxiangda-v2/references/administration.md +7 -1
  233. package/skills/openxiangda-v2/references/backend.md +72 -1
  234. package/skills/openxiangda-v2/references/data-authz.md +42 -2
  235. package/skills/openxiangda-v2/references/declarations-cheatsheet.md +9 -0
  236. package/skills/openxiangda-v2/references/field-components.md +45 -1
  237. package/skills/openxiangda-v2/references/frontend.md +8 -0
  238. package/skills/openxiangda-v2/references/getting-started.md +7 -7
  239. package/skills/openxiangda-v2/references/managed-concurrency-frontend.md +1 -1
  240. package/skills/openxiangda-v2/references/testing.md +17 -0
  241. package/skills/openxiangda-v2/references/workflow-events.md +221 -6
  242. package/dist/browser/components/platform-fields/MobileRichTextField.d.ts +0 -4
  243. package/dist/browser/components/platform-fields/MobileRichTextField.d.ts.map +0 -1
  244. package/dist/browser/components/platform-fields/MobileRichTextField.js +0 -38
  245. package/dist/browser/components/platform-fields/MobileRichTextField.js.map +0 -1
  246. package/releases/2.43.0.json +0 -38
  247. package/releases/2.44.0.json +0 -36
@@ -152,7 +152,12 @@ async function request(path, init) {
152
152
  ? payload
153
153
  : null;
154
154
  if (!response.ok || (envelope && envelope.code !== 200)) {
155
- throw responseRequestError(path, init, response, envelope, '平台请求失败');
155
+ // Application backends may return Nest HttpException JSON without an envelope code.
156
+ // Only failed HTTP responses use that object as an error payload; successful JSON
157
+ // retains the existing envelope/plain-response contract.
158
+ const failurePayload = payload && typeof payload === 'object' && !Array.isArray(payload)
159
+ ? payload : null;
160
+ throw responseRequestError(path, init, response, failurePayload, '平台请求失败');
156
161
  }
157
162
  return envelope ? envelope.data : payload;
158
163
  }
@@ -283,7 +288,7 @@ function bindWorkflowCsrf(surface, csrf) {
283
288
  bindWorkflowCommandCsrf(surface.commandToken, surface.commandTokenExpiresAt, csrf);
284
289
  return surface;
285
290
  }
286
- function bindWorkflowCommandCsrf(commandToken, expiration, csrf) {
291
+ function bindWorkflowCommandCsrf(commandToken, expiration, csrf, retainForReceipt = false) {
287
292
  const now = Date.now();
288
293
  for (const [key, value] of workflowCommandCsrf)
289
294
  if (value.expiresAt <= now)
@@ -292,7 +297,9 @@ function bindWorkflowCommandCsrf(commandToken, expiration, csrf) {
292
297
  if (commandToken && Number.isFinite(expiresAt) && expiresAt > now) {
293
298
  if (!workflowCommandCsrf.has(commandToken) && workflowCommandCsrf.size >= 512)
294
299
  workflowCommandCsrf.delete(workflowCommandCsrf.keys().next().value);
295
- workflowCommandCsrf.set(commandToken, { csrf, expiresAt });
300
+ // Record deletion receipts can outlive their preview. Keep the original header
301
+ // in the same bounded, identity-cleared command cache until it is evicted.
302
+ workflowCommandCsrf.set(commandToken, { csrf, expiresAt: retainForReceipt ? Infinity : expiresAt });
296
303
  }
297
304
  }
298
305
  async function commandBoundCsrf(commandToken) {
@@ -934,6 +941,7 @@ export async function searchResource(resourceCode, fieldCode, options) {
934
941
  schemaVersion: SCHEMA_VERSIONS.dataFieldSourceQuery,
935
942
  operation: options.operation,
936
943
  ...(options.launch ? { launch: options.launch } : {}),
944
+ ...(options.action ? { action: options.action } : {}),
937
945
  ...(options.keyword.trim() ? { keyword: options.keyword.trim() } : {}),
938
946
  ...(options.cursor ? { cursor: options.cursor } : {}),
939
947
  ...(options.bindings && Object.keys(options.bindings).length
@@ -948,6 +956,12 @@ export async function searchResource(resourceCode, fieldCode, options) {
948
956
  }),
949
957
  });
950
958
  }
959
+ export async function queryFieldUserCandidates(resourceCode, fieldCode, input) {
960
+ return requestRead(`${nativeBase()}/data-resources/${encodeURIComponent(resourceCode)}/fields/${encodeURIComponent(fieldCode)}/user-candidates/query`, { method: 'POST', body: JSON.stringify({ ...input, environmentKey: currentEnvironmentKey() }) });
961
+ }
962
+ export async function queryWorkflowTaskUserCandidates(taskId, fieldCode, input) {
963
+ return requestRead(`${workflowBase()}/tasks/${encodeURIComponent(taskId)}/fields/${encodeURIComponent(fieldCode)}/user-candidates/query`, { method: 'POST', body: JSON.stringify(input) });
964
+ }
951
965
  function nativeResourceListQuery(code, surface, query) {
952
966
  const sorts = query.sorts ?? (query.sort ? [query.sort] : surface.list?.defaultSort ? [surface.list.defaultSort] : []);
953
967
  const where = buildResourceWhere(code, surface, query);
@@ -1063,6 +1077,103 @@ export async function batchAggregateNativeResources(operations) {
1063
1077
  };
1064
1078
  });
1065
1079
  }
1080
+ export async function loadNativeRecordPrint(code, recordId, options = {}) {
1081
+ const query = new URLSearchParams({ environmentKey: currentEnvironmentKey(),
1082
+ ...(options.viewCode === undefined ? {} : { viewCode: options.viewCode }) });
1083
+ const snapshot = await requestRead(`${dataBase(code)}/records/${encodeURIComponent(recordId)}/print?${query}`);
1084
+ if (snapshot.schemaVersion !== 'openxiangda.data-record-print/v1' || snapshot.resourceCode !== code ||
1085
+ snapshot.recordId !== recordId || snapshot.viewCode !== options.viewCode ||
1086
+ !Array.isArray(snapshot.fields) || snapshot.fields.length < 1 || snapshot.fields.length > 100 ||
1087
+ new Set(snapshot.fields.map(field => field.code)).size !== snapshot.fields.length ||
1088
+ !snapshot.data || typeof snapshot.data !== 'object' || Array.isArray(snapshot.data))
1089
+ throw new Error('OPENXIANGDA_NATIVE_RECORD_PRINT_RESPONSE_INVALID');
1090
+ return snapshot;
1091
+ }
1092
+ /** Comment reads retain current Perspective; writes/recovery use Native current-user authority. */
1093
+ export async function loadNativeRecordComments(code, recordId, options = {}) {
1094
+ const limit = options.limit ?? 20;
1095
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 50 ||
1096
+ (options.cursor !== undefined && (!/^[A-Za-z0-9_-]{1,256}$/.test(options.cursor))))
1097
+ throw new Error('OPENXIANGDA_NATIVE_RECORD_COMMENTS_PAGE_INVALID');
1098
+ const query = new URLSearchParams({ environmentKey: currentEnvironmentKey(), limit: String(limit),
1099
+ ...(options.cursor === undefined ? {} : { cursor: options.cursor }) });
1100
+ const page = await requestRead(`${dataBase(code)}/records/${encodeURIComponent(recordId)}/comments?${query}`);
1101
+ if (page.schemaVersion !== 'openxiangda.data-record-comments/v1' || page.resourceCode !== code ||
1102
+ page.recordId !== recordId || page.limit !== limit || !Array.isArray(page.items) || page.items.length > limit ||
1103
+ !page.items.every(validRecordComment) || (page.nextCursor !== null &&
1104
+ (typeof page.nextCursor !== 'string' || !/^[A-Za-z0-9_-]{1,256}$/.test(page.nextCursor))))
1105
+ throw new Error('OPENXIANGDA_NATIVE_RECORD_COMMENTS_RESPONSE_INVALID');
1106
+ return page;
1107
+ }
1108
+ function validRecordComment(value) {
1109
+ if (!value || typeof value !== 'object' || Array.isArray(value))
1110
+ return false;
1111
+ const comment = value;
1112
+ return typeof comment.id === 'string' && typeof comment.body === 'string' && comment.body.length <= 4000 &&
1113
+ typeof comment.authorUserId === 'string' && typeof comment.isOwn === 'boolean' &&
1114
+ typeof comment.createdAt === 'string' && Number.isFinite(Date.parse(comment.createdAt)) &&
1115
+ typeof comment.appVersionId === 'string' && Number.isSafeInteger(comment.environmentHeadRevision) && comment.environmentHeadRevision > 0;
1116
+ }
1117
+ function checkedRecordCommentReceipt(receipt, code, recordId, key) {
1118
+ if (receipt.schemaVersion !== 'openxiangda.data-record-comment-receipt/v1' || receipt.resourceCode !== code ||
1119
+ receipt.recordId !== recordId || receipt.idempotencyKey !== key || !validRecordComment(receipt.comment) ||
1120
+ receipt.comment.isOwn !== true || typeof receipt.replayed !== 'boolean')
1121
+ throw new Error('OPENXIANGDA_NATIVE_RECORD_COMMENTS_RESPONSE_INVALID');
1122
+ return receipt;
1123
+ }
1124
+ /** Fix the mutation before sending; never generate a replacement key for an unknown result. */
1125
+ export async function createNativeRecordComment(code, recordId, input) {
1126
+ const receipt = await request(`${dataBase(code)}/records/${encodeURIComponent(recordId)}/comments`, { method: 'POST', body: JSON.stringify({ ...input, environmentKey: currentEnvironmentKey() }) });
1127
+ return checkedRecordCommentReceipt(receipt, code, recordId, input.idempotencyKey);
1128
+ }
1129
+ /** Author-only original-key recovery is re-authorized, even after a new application Head. */
1130
+ export async function loadNativeRecordCommentReceipt(code, recordId, idempotencyKey) {
1131
+ const query = new URLSearchParams({ environmentKey: currentEnvironmentKey(), idempotencyKey });
1132
+ const receipt = await requestRead(`${dataBase(code)}/records/${encodeURIComponent(recordId)}/comments/receipt?${query}`);
1133
+ return checkedRecordCommentReceipt(receipt, code, recordId, idempotencyKey);
1134
+ }
1135
+ function checkedRecordDeletionPreview(value, code, recordId) {
1136
+ const count = (n, min = 0, max = 100) => Number.isSafeInteger(n) && n >= min && n <= max;
1137
+ if (value.schemaVersion !== 'openxiangda.data-record-deletion-preview/v1' || value.resourceCode !== code || value.recordId !== recordId ||
1138
+ typeof value.resourceName !== 'string' || typeof value.appVersionId !== 'string' || !count(value.environmentHeadRevision, 1, Number.MAX_SAFE_INTEGER) ||
1139
+ !count(value.recordRevision, 1, Number.MAX_SAFE_INTEGER) || !count(value.affectedRecords, 1) || !count(value.workflowCount) ||
1140
+ !count(value.pendingLaunchCount) || !count(value.cancelledTaskCount, 0, Number.MAX_SAFE_INTEGER) || typeof value.canCommit !== 'boolean' ||
1141
+ (value.canCommit ? value.workflowCount > 1 || value.pendingLaunchCount !== 0 || value.blocker !== undefined ||
1142
+ !['native-transaction', 'workflow-command'].includes(value.receiptOwner || '') ||
1143
+ (value.receiptOwner === 'workflow-command') !== (value.workflowCount === 1) ||
1144
+ typeof value.previewToken !== 'string' || !/^[A-Za-z0-9_-]{100,16384}$/.test(value.previewToken) ||
1145
+ typeof value.expiresAt !== 'string' || !Number.isFinite(Date.parse(value.expiresAt))
1146
+ : !['pending_launch', 'multiple_workflows', 'owned_workflow'].includes(value.blocker || '') || value.previewToken !== undefined || value.receiptOwner !== undefined))
1147
+ throw new Error('OPENXIANGDA_NATIVE_RECORD_DELETION_RESPONSE_INVALID');
1148
+ return value;
1149
+ }
1150
+ function checkedRecordDeletionReceipt(value, code, recordId, key) {
1151
+ if (value.schemaVersion !== 'openxiangda.data-record-deletion-receipt/v1' || value.resourceCode !== code || value.recordId !== recordId ||
1152
+ value.idempotencyKey !== key || !['native-transaction', 'workflow-command'].includes(value.receiptOwner) ||
1153
+ typeof value.receiptId !== 'string' || !value.receiptId || value.receiptId.length > 255 ||
1154
+ typeof value.deleted !== 'boolean' || typeof value.replayed !== 'boolean' ||
1155
+ (!value.deleted && (typeof value.errorCode !== 'string' || !value.errorCode)))
1156
+ throw new Error('OPENXIANGDA_NATIVE_RECORD_DELETION_RESPONSE_INVALID');
1157
+ return value;
1158
+ }
1159
+ /** Maintenance uses the current user role union, independent of read Perspective. */
1160
+ export async function previewNativeRecordDeletion(code, recordId) {
1161
+ const csrf = await workflowCsrfToken();
1162
+ const result = await request(`${dataBase(code)}/records/${encodeURIComponent(recordId)}/deletion/preview`, { method: 'POST', headers: { 'x-openxiangda-csrf-token': csrf }, body: JSON.stringify({ environmentKey: currentEnvironmentKey() }) });
1163
+ const preview = checkedRecordDeletionPreview(result, code, recordId);
1164
+ if (preview.canCommit)
1165
+ bindWorkflowCommandCsrf(preview.previewToken, preview.expiresAt, csrf, true);
1166
+ return preview;
1167
+ }
1168
+ export async function deleteNativeRecordWithPreview(code, recordId, input) {
1169
+ const result = await request(`${dataBase(code)}/records/${encodeURIComponent(recordId)}/deletion/execute`, { method: 'POST', headers: { 'x-openxiangda-csrf-token': await commandBoundCsrf(input.previewToken) }, body: JSON.stringify({ ...input, environmentKey: currentEnvironmentKey() }) });
1170
+ return checkedRecordDeletionReceipt(result, code, recordId, input.idempotencyKey);
1171
+ }
1172
+ /** Read the original owner receipt; never replace the pending request with a new key. */
1173
+ export async function recoverNativeRecordDeletion(code, recordId, input) {
1174
+ const result = await request(`${dataBase(code)}/records/${encodeURIComponent(recordId)}/deletion/receipt`, { method: 'POST', headers: { 'x-openxiangda-csrf-token': await commandBoundCsrf(input.previewToken) }, body: JSON.stringify({ ...input, environmentKey: currentEnvironmentKey() }) });
1175
+ return checkedRecordDeletionReceipt(result, code, recordId, input.idempotencyKey);
1176
+ }
1066
1177
  export function createNativeResourceClient(code, surface) {
1067
1178
  const base = dataBase(code);
1068
1179
  const declaredFields = new Set(Object.keys(surface.fields));
@@ -1072,6 +1183,9 @@ export function createNativeResourceClient(code, surface) {
1072
1183
  return field;
1073
1184
  };
1074
1185
  return {
1186
+ previewDeletion: (recordId) => previewNativeRecordDeletion(code, recordId),
1187
+ deleteWithPreview: (recordId, input) => deleteNativeRecordWithPreview(code, recordId, input),
1188
+ deletionReceipt: (recordId, input) => recoverNativeRecordDeletion(code, recordId, input),
1075
1189
  async list(query) {
1076
1190
  const body = nativeResourceListQuery(code, surface, query);
1077
1191
  const page = await requestRead(`${base}/query`, {
@@ -1237,6 +1351,9 @@ export async function loadApplicationOperationSurfaces(options = {}) {
1237
1351
  * The caller never supplies a runtime path, capability, or subject resource.
1238
1352
  */
1239
1353
  export async function executeApplicationOperation(operationSurface, input, options = {}) {
1354
+ return executeApplicationOperationWithCsrf(operationSurface, input, options, workflowCsrfToken);
1355
+ }
1356
+ async function executeApplicationOperationWithCsrf(operationSurface, input, options, csrf) {
1240
1357
  if (!operationSurface?.code ||
1241
1358
  !operationSurface.appVersionId ||
1242
1359
  operationSurface.fileIntent ||
@@ -1249,7 +1366,7 @@ export async function executeApplicationOperation(operationSurface, input, optio
1249
1366
  (!idempotencyKey || idempotencyKey.length > 128)) {
1250
1367
  throw new Error('OPENXIANGDA_APPLICATION_OPERATION_IDEMPOTENCY_REQUIRED');
1251
1368
  }
1252
- const csrfToken = await workflowCsrfToken();
1369
+ const csrfToken = await csrf();
1253
1370
  return await request(`${nativeBase()}/operation-surfaces/${encodeURIComponent(operationSurface.code)}/execute`, {
1254
1371
  method: 'POST',
1255
1372
  headers: { 'x-openxiangda-csrf-token': csrfToken },
@@ -1790,6 +1907,18 @@ export async function loadWorkflowInstanceSurface(instanceId) {
1790
1907
  const surface = await requestRead(`${workflowBase()}/instances/${encodeURIComponent(instanceId)}/surface`, { headers: { 'x-openxiangda-csrf-token': csrfToken } });
1791
1908
  return bindWorkflowCsrf(normalizeWorkflowSurface(surface), csrfToken);
1792
1909
  }
1910
+ /** Current record read/RLS plus explicit history policy, without handling authority. */
1911
+ export async function loadWorkflowRecordHistory(resourceCode, recordId, options = {}) {
1912
+ const limit = options.limit ?? 20;
1913
+ const offset = options.offset ?? 0;
1914
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100 ||
1915
+ !Number.isSafeInteger(offset) || offset < 0 || offset > 500)
1916
+ throw new Error('WORKFLOW_V2_RECORD_HISTORY_PAGE_INVALID');
1917
+ const query = new URLSearchParams({ environmentKey: currentEnvironmentKey(), limit: String(limit), offset: String(offset) });
1918
+ if (options.instanceId)
1919
+ query.set('instanceId', options.instanceId);
1920
+ return await requestRead(`${workflowBase()}/records/${encodeURIComponent(resourceCode)}/${encodeURIComponent(recordId)}/history?${query}`);
1921
+ }
1793
1922
  export async function loadWorkflowTimeline(instanceId) {
1794
1923
  return await requestRead(`${workflowBase()}/instances/${encodeURIComponent(instanceId)}/timeline`);
1795
1924
  }
@@ -1940,6 +2069,33 @@ export async function executeWorkflowOperation(surface, operation, input = {}, o
1940
2069
  if (!surface.commandToken) {
1941
2070
  throw new Error('OPENXIANGDA_WORKFLOW_COMMAND_TOKEN_REQUIRED');
1942
2071
  }
2072
+ const idempotencyKey = options.idempotencyKey || randomWorkflowIdempotencyKey(operation.key);
2073
+ if (operation.execute.operationCode) {
2074
+ const catalog = await loadApplicationOperationSurfaces();
2075
+ const action = catalog.operations.find(item => item.code === operation.execute.operationCode);
2076
+ if (!action)
2077
+ throw new Error('OPENXIANGDA_WORKFLOW_BUSINESS_OPERATION_UNAVAILABLE');
2078
+ const instance = surface.instance;
2079
+ const dataRef = instance.dataRef;
2080
+ const resourceCode = surface.navigationTarget?.resourceCode || dataRef?.resourceCode;
2081
+ const recordId = surface.navigationTarget?.recordId || dataRef?.id;
2082
+ const detail = surface.presentation.businessDetail;
2083
+ const expectedRevision = surface.taskForm?.expectedRevision || detail?.sourceRevision;
2084
+ if (!recordId || !resourceCode || resourceCode !== action.subject.resourceCode ||
2085
+ !Number.isSafeInteger(expectedRevision) || Number(expectedRevision) < 1 ||
2086
+ !['approve', 'reject', 'withdraw'].includes(operation.key))
2087
+ throw new Error('OPENXIANGDA_WORKFLOW_BUSINESS_SUBJECT_UNAVAILABLE');
2088
+ const target = operation.key === 'withdraw'
2089
+ ? { kind: 'instance', id: String(instance.id), command: 'withdraw' }
2090
+ : { kind: 'task', id: String(surface.task?.id || ''), command: operation.key };
2091
+ if (!target.id || target.id === 'undefined')
2092
+ throw new Error('OPENXIANGDA_WORKFLOW_BUSINESS_TARGET_UNAVAILABLE');
2093
+ const receipt = await executeApplicationOperationWithCsrf(action, {
2094
+ workflowCode: instance.workflowCode, target, recordId, expectedRevision,
2095
+ commandToken: surface.commandToken, idempotencyKey, input,
2096
+ }, { idempotencyKey }, () => commandBoundCsrf(surface.commandToken));
2097
+ return receipt.result;
2098
+ }
1943
2099
  const csrfToken = await commandBoundCsrf(surface.commandToken);
1944
2100
  const href = operation.execute.href.startsWith('/service/')
1945
2101
  ? operation.execute.href
@@ -1949,7 +2105,7 @@ export async function executeWorkflowOperation(surface, operation, input = {}, o
1949
2105
  headers: { 'x-openxiangda-csrf-token': csrfToken },
1950
2106
  body: JSON.stringify({
1951
2107
  commandToken: surface.commandToken,
1952
- idempotencyKey: options.idempotencyKey || randomWorkflowIdempotencyKey(operation.key),
2108
+ idempotencyKey,
1953
2109
  input,
1954
2110
  }),
1955
2111
  });