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.
- package/dist/browser/AuthoritativeSelector.d.ts +3 -2
- package/dist/browser/AuthoritativeSelector.d.ts.map +1 -1
- package/dist/browser/AuthoritativeSelector.js +32 -11
- package/dist/browser/AuthoritativeSelector.js.map +1 -1
- package/dist/browser/FilePreviewPage.d.ts.map +1 -1
- package/dist/browser/FilePreviewPage.js +4 -0
- package/dist/browser/FilePreviewPage.js.map +1 -1
- package/dist/browser/components/administration/RoleMembershipManager.d.ts.map +1 -1
- package/dist/browser/components/administration/RoleMembershipManager.js +5 -5
- package/dist/browser/components/administration/RoleMembershipManager.js.map +1 -1
- package/dist/browser/components/administration/scope-applicability.d.ts +3 -0
- package/dist/browser/components/administration/scope-applicability.d.ts.map +1 -0
- package/dist/browser/components/administration/scope-applicability.js +7 -0
- package/dist/browser/components/administration/scope-applicability.js.map +1 -0
- package/dist/browser/components/platform-fields/ConstrainedUserField.d.ts +16 -0
- package/dist/browser/components/platform-fields/ConstrainedUserField.d.ts.map +1 -0
- package/dist/browser/components/platform-fields/ConstrainedUserField.js +140 -0
- package/dist/browser/components/platform-fields/ConstrainedUserField.js.map +1 -0
- package/dist/browser/components/platform-fields/JsonField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/JsonField.js +6 -1
- package/dist/browser/components/platform-fields/JsonField.js.map +1 -1
- package/dist/browser/components/platform-fields/ManagedMediaPlayer.d.ts +19 -0
- package/dist/browser/components/platform-fields/ManagedMediaPlayer.d.ts.map +1 -0
- package/dist/browser/components/platform-fields/ManagedMediaPlayer.js +42 -0
- package/dist/browser/components/platform-fields/ManagedMediaPlayer.js.map +1 -0
- package/dist/browser/components/platform-fields/MobileManagedFileField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/MobileManagedFileField.js +6 -1
- package/dist/browser/components/platform-fields/MobileManagedFileField.js.map +1 -1
- package/dist/browser/components/platform-fields/MobileSelection.d.ts +3 -1
- package/dist/browser/components/platform-fields/MobileSelection.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/MobileSelection.js +2 -2
- package/dist/browser/components/platform-fields/MobileSelection.js.map +1 -1
- package/dist/browser/components/platform-fields/MobileSubtableValidation.d.ts +2 -1
- package/dist/browser/components/platform-fields/MobileSubtableValidation.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/MobileSubtableValidation.js +3 -1
- package/dist/browser/components/platform-fields/MobileSubtableValidation.js.map +1 -1
- package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts +3 -2
- package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/ResourceReferenceField.js +2 -2
- package/dist/browser/components/platform-fields/ResourceReferenceField.js.map +1 -1
- package/dist/browser/components/platform-fields/RichTextField.d.ts +3 -2
- package/dist/browser/components/platform-fields/RichTextField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/RichTextField.js +96 -44
- package/dist/browser/components/platform-fields/RichTextField.js.map +1 -1
- package/dist/browser/components/platform-fields/SignatureField.d.ts +5 -4
- package/dist/browser/components/platform-fields/SignatureField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/SignatureField.js +69 -16
- package/dist/browser/components/platform-fields/SignatureField.js.map +1 -1
- package/dist/browser/components/platform-fields/SubtableField.d.ts +18 -2
- package/dist/browser/components/platform-fields/SubtableField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/SubtableField.js +146 -57
- package/dist/browser/components/platform-fields/SubtableField.js.map +1 -1
- package/dist/browser/components/platform-fields/managed-media-read.d.ts +19 -0
- package/dist/browser/components/platform-fields/managed-media-read.d.ts.map +1 -0
- package/dist/browser/components/platform-fields/managed-media-read.js +32 -0
- package/dist/browser/components/platform-fields/managed-media-read.js.map +1 -0
- package/dist/browser/components/platform-fields/subtable-pagination.d.ts +20 -0
- package/dist/browser/components/platform-fields/subtable-pagination.d.ts.map +1 -0
- package/dist/browser/components/platform-fields/subtable-pagination.js +39 -0
- package/dist/browser/components/platform-fields/subtable-pagination.js.map +1 -0
- package/dist/browser/components/platform-fields/subtable-value.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/subtable-value.js +2 -1
- package/dist/browser/components/platform-fields/subtable-value.js.map +1 -1
- package/dist/browser/components/platform-fields/surface-field-validation.d.ts +31 -0
- package/dist/browser/components/platform-fields/surface-field-validation.d.ts.map +1 -0
- package/dist/browser/components/platform-fields/surface-field-validation.js +36 -0
- package/dist/browser/components/platform-fields/surface-field-validation.js.map +1 -0
- package/dist/browser/components/platform-fields/user-candidate-context.d.ts +51 -0
- package/dist/browser/components/platform-fields/user-candidate-context.d.ts.map +1 -0
- package/dist/browser/components/platform-fields/user-candidate-context.js +62 -0
- package/dist/browser/components/platform-fields/user-candidate-context.js.map +1 -0
- package/dist/browser/components/resource/GeneratedResourceCrud.d.ts.map +1 -1
- package/dist/browser/components/resource/GeneratedResourceCrud.js +26 -2
- package/dist/browser/components/resource/GeneratedResourceCrud.js.map +1 -1
- package/dist/browser/components/resource/GeneratedResourceForm.js +1 -1
- package/dist/browser/components/resource/GeneratedResourceForm.js.map +1 -1
- package/dist/browser/components/resource/RecordDetailFrame.d.ts +3 -1
- package/dist/browser/components/resource/RecordDetailFrame.d.ts.map +1 -1
- package/dist/browser/components/resource/RecordDetailFrame.js +2 -2
- package/dist/browser/components/resource/RecordDetailFrame.js.map +1 -1
- package/dist/browser/components/resource/ResourceFormFrame.d.ts +2 -1
- package/dist/browser/components/resource/ResourceFormFrame.d.ts.map +1 -1
- package/dist/browser/components/resource/ResourceFormFrame.js +2 -2
- package/dist/browser/components/resource/ResourceFormFrame.js.map +1 -1
- package/dist/browser/components/resource/ResourceRecordComments.d.ts +13 -0
- package/dist/browser/components/resource/ResourceRecordComments.d.ts.map +1 -0
- package/dist/browser/components/resource/ResourceRecordComments.js +75 -0
- package/dist/browser/components/resource/ResourceRecordComments.js.map +1 -0
- package/dist/browser/components/resource/ResourceRecordDeletion.d.ts +7 -0
- package/dist/browser/components/resource/ResourceRecordDeletion.d.ts.map +1 -0
- package/dist/browser/components/resource/ResourceRecordDeletion.js +53 -0
- package/dist/browser/components/resource/ResourceRecordDeletion.js.map +1 -0
- package/dist/browser/components/resource/ResourceRecordPrintPreview.d.ts +16 -0
- package/dist/browser/components/resource/ResourceRecordPrintPreview.d.ts.map +1 -0
- package/dist/browser/components/resource/ResourceRecordPrintPreview.js +92 -0
- package/dist/browser/components/resource/ResourceRecordPrintPreview.js.map +1 -0
- package/dist/browser/components/resource/SurfaceFields.d.ts +9 -4
- package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -1
- package/dist/browser/components/resource/SurfaceFields.js +54 -72
- package/dist/browser/components/resource/SurfaceFields.js.map +1 -1
- package/dist/browser/components/resource/generated-resource-definition.d.ts +13 -0
- package/dist/browser/components/resource/generated-resource-definition.d.ts.map +1 -1
- package/dist/browser/components/resource/record-comment-session.d.ts +17 -0
- package/dist/browser/components/resource/record-comment-session.d.ts.map +1 -0
- package/dist/browser/components/resource/record-comment-session.js +64 -0
- package/dist/browser/components/resource/record-comment-session.js.map +1 -0
- package/dist/browser/components/resource/record-deletion-session.d.ts +19 -0
- package/dist/browser/components/resource/record-deletion-session.d.ts.map +1 -0
- package/dist/browser/components/resource/record-deletion-session.js +64 -0
- package/dist/browser/components/resource/record-deletion-session.js.map +1 -0
- package/dist/browser/components/resource/record-print-session.d.ts +12 -0
- package/dist/browser/components/resource/record-print-session.d.ts.map +1 -0
- package/dist/browser/components/resource/record-print-session.js +32 -0
- package/dist/browser/components/resource/record-print-session.js.map +1 -0
- package/dist/browser/components/resource/resource-field-selection.d.ts +1 -0
- package/dist/browser/components/resource/resource-field-selection.d.ts.map +1 -1
- package/dist/browser/components/resource/resource-form-operations.d.ts.map +1 -1
- package/dist/browser/components/resource/resource-form-operations.js +5 -1
- package/dist/browser/components/resource/resource-form-operations.js.map +1 -1
- package/dist/browser/components/resource/useResourceFormDrafts.d.ts.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts +13 -2
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.js +96 -47
- package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowDiagram.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowDiagram.js +14 -1
- package/dist/browser/components/workflow/WorkflowDiagram.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowFlowCanvas.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowFlowCanvas.js +27 -8
- package/dist/browser/components/workflow/WorkflowFlowCanvas.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowNodeCard.js +2 -2
- package/dist/browser/components/workflow/WorkflowNodeCard.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js +4 -4
- package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowRecordEditor.js +1 -1
- package/dist/browser/components/workflow/WorkflowRecordEditor.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowRecordHistoryPanel.d.ts +9 -0
- package/dist/browser/components/workflow/WorkflowRecordHistoryPanel.d.ts.map +1 -0
- package/dist/browser/components/workflow/WorkflowRecordHistoryPanel.js +50 -0
- package/dist/browser/components/workflow/WorkflowRecordHistoryPanel.js.map +1 -0
- package/dist/browser/components/workflow/WorkflowTaskFiles.d.ts +5 -3
- package/dist/browser/components/workflow/WorkflowTaskFiles.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowTaskFiles.js +67 -27
- package/dist/browser/components/workflow/WorkflowTaskFiles.js.map +1 -1
- package/dist/browser/components/workflow/WorkflowTaskForm.d.ts +6 -1
- package/dist/browser/components/workflow/WorkflowTaskForm.d.ts.map +1 -1
- package/dist/browser/components/workflow/WorkflowTaskForm.js +65 -16
- package/dist/browser/components/workflow/WorkflowTaskForm.js.map +1 -1
- package/dist/browser/components/workflow/standard-process-values.d.ts +10 -0
- package/dist/browser/components/workflow/standard-process-values.d.ts.map +1 -0
- package/dist/browser/components/workflow/standard-process-values.js +25 -0
- package/dist/browser/components/workflow/standard-process-values.js.map +1 -0
- package/dist/browser/components/workflow/workflow-graph-presentation.d.ts +19 -0
- package/dist/browser/components/workflow/workflow-graph-presentation.d.ts.map +1 -0
- package/dist/browser/components/workflow/workflow-graph-presentation.js +28 -0
- package/dist/browser/components/workflow/workflow-graph-presentation.js.map +1 -0
- package/dist/browser/components/workflow/workflow-submission-form.d.ts +18 -0
- package/dist/browser/components/workflow/workflow-submission-form.d.ts.map +1 -0
- package/dist/browser/components/workflow/workflow-submission-form.js +44 -0
- package/dist/browser/components/workflow/workflow-submission-form.js.map +1 -0
- package/dist/browser/components/workflow/workflow-task-field-codec.d.ts +4 -0
- package/dist/browser/components/workflow/workflow-task-field-codec.d.ts.map +1 -0
- package/dist/browser/components/workflow/workflow-task-field-codec.js +9 -0
- package/dist/browser/components/workflow/workflow-task-field-codec.js.map +1 -0
- package/dist/browser/components/workflow/workflow-task-required-errors.d.ts +10 -0
- package/dist/browser/components/workflow/workflow-task-required-errors.d.ts.map +1 -0
- package/dist/browser/components/workflow/workflow-task-required-errors.js +28 -0
- package/dist/browser/components/workflow/workflow-task-required-errors.js.map +1 -0
- package/dist/browser/components/workflow/workflow-task-subtable.d.ts +7 -0
- package/dist/browser/components/workflow/workflow-task-subtable.d.ts.map +1 -0
- package/dist/browser/components/workflow/workflow-task-subtable.js +58 -0
- package/dist/browser/components/workflow/workflow-task-subtable.js.map +1 -0
- package/dist/browser/durable-command.d.ts.map +1 -1
- package/dist/browser/durable-command.js +6 -1
- package/dist/browser/durable-command.js.map +1 -1
- package/dist/browser/mobile-fields.css +4 -0
- package/dist/browser/platform-client.d.ts +30 -1
- package/dist/browser/platform-client.d.ts.map +1 -1
- package/dist/browser/platform-client.js +161 -5
- package/dist/browser/platform-client.js.map +1 -1
- package/dist/browser/record-comments.css +14 -0
- package/dist/browser/record-deletion.css +11 -0
- package/dist/browser/record-detail.css +4 -2
- package/dist/browser/record-print.css +31 -0
- package/dist/browser/styles.css +41 -0
- package/dist/browser/workflow-operation-input.d.ts +15 -0
- package/dist/browser/workflow-operation-input.d.ts.map +1 -0
- package/dist/browser/workflow-operation-input.js +64 -0
- package/dist/browser/workflow-operation-input.js.map +1 -0
- package/dist/browser/workflow-task-file-upload.d.ts.map +1 -1
- package/dist/browser/workflow-task-file-upload.js +1 -0
- package/dist/browser/workflow-task-file-upload.js.map +1 -1
- package/dist/core.d.ts +2 -2
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/field-kit.d.ts +3 -0
- package/dist/field-kit.d.ts.map +1 -1
- package/dist/field-kit.js +3 -0
- package/dist/field-kit.js.map +1 -1
- package/dist/nest.d.ts +1 -1
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js.map +1 -1
- package/dist/react.d.ts +6 -2
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +5 -1
- package/dist/react.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/documentation/administration.md +7 -1
- package/documentation/backend.md +72 -1
- package/documentation/data-authz.md +42 -2
- package/documentation/declarations-cheatsheet.md +9 -0
- package/documentation/field-components.md +45 -1
- package/documentation/frontend.md +8 -0
- package/documentation/getting-started.md +7 -7
- package/documentation/managed-concurrency-frontend.md +1 -1
- package/documentation/manifest.json +11 -11
- package/documentation/testing.md +17 -0
- package/documentation/workflow-events.md +221 -6
- package/package.json +22 -25
- package/releases/2.51.0.json +32 -0
- package/releases/2.54.4.json +30 -0
- package/releases/2.54.6.json +30 -0
- package/releases/2.55.0.json +34 -0
- package/releases/2.55.1.json +32 -0
- package/skills/manifest.json +1 -1
- package/skills/openxiangda-v2/SKILL.md +4 -4
- package/skills/openxiangda-v2/references/administration.md +7 -1
- package/skills/openxiangda-v2/references/backend.md +72 -1
- package/skills/openxiangda-v2/references/data-authz.md +42 -2
- package/skills/openxiangda-v2/references/declarations-cheatsheet.md +9 -0
- package/skills/openxiangda-v2/references/field-components.md +45 -1
- package/skills/openxiangda-v2/references/frontend.md +8 -0
- package/skills/openxiangda-v2/references/getting-started.md +7 -7
- package/skills/openxiangda-v2/references/managed-concurrency-frontend.md +1 -1
- package/skills/openxiangda-v2/references/testing.md +17 -0
- package/skills/openxiangda-v2/references/workflow-events.md +221 -6
- package/dist/browser/components/platform-fields/MobileRichTextField.d.ts +0 -4
- package/dist/browser/components/platform-fields/MobileRichTextField.d.ts.map +0 -1
- package/dist/browser/components/platform-fields/MobileRichTextField.js +0 -38
- package/dist/browser/components/platform-fields/MobileRichTextField.js.map +0 -1
- package/releases/2.43.0.json +0 -38
- 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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
2108
|
+
idempotencyKey,
|
|
1953
2109
|
input,
|
|
1954
2110
|
}),
|
|
1955
2111
|
});
|