openxiangda-cli 2.0.0-alpha.89 → 2.0.0-alpha.90

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 (77) hide show
  1. package/README.md +2 -2
  2. package/bin/run.js +1 -0
  3. package/dist/commands/skill.d.ts +26 -0
  4. package/dist/commands/skill.d.ts.map +1 -0
  5. package/dist/commands/skill.js +43 -0
  6. package/dist/commands/skill.js.map +1 -0
  7. package/dist/create-workspace.d.ts.map +1 -1
  8. package/dist/create-workspace.js +3 -3
  9. package/dist/create-workspace.js.map +1 -1
  10. package/dist/toolchain-capsule.d.ts.map +1 -1
  11. package/dist/toolchain-capsule.js +4 -8
  12. package/dist/toolchain-capsule.js.map +1 -1
  13. package/package.json +6 -7
  14. package/template/AGENTS.md +2 -1
  15. package/template/README.md +3 -3
  16. package/template/apps/server/package.json +1 -1
  17. package/template/apps/server/src/app.module.ts +1 -1
  18. package/template/apps/server/src/main.ts +1 -1
  19. package/template/apps/web/e2e/client-fixture.ts +5 -0
  20. package/template/apps/web/e2e/data-api-live-fixture.tsx +19 -14
  21. package/template/apps/web/e2e/field-protocol-fixture.tsx +87 -20
  22. package/template/apps/web/e2e/field-protocol.spec.ts +86 -0
  23. package/template/apps/web/e2e/resources.spec.ts +20 -181
  24. package/template/apps/web/field-protocol.e2e.html +3 -0
  25. package/template/apps/web/package.json +2 -5
  26. package/template/apps/web/src/main.tsx +12 -60
  27. package/template/apps/web/test/contracts.test.ts +52 -104
  28. package/template/openxiangda.config.ts +1 -1
  29. package/template/package.json +1 -3
  30. package/template/packages/contracts/src/generated.ts +1 -0
  31. package/template/scripts/verify-template-budget.mjs +2 -2
  32. package/template/apps/web/src/AuthoritativeSelector.tsx +0 -661
  33. package/template/apps/web/src/FilePreviewPage.tsx +0 -324
  34. package/template/apps/web/src/RoleSubjectSelect.tsx +0 -128
  35. package/template/apps/web/src/Shell.tsx +0 -445
  36. package/template/apps/web/src/appearance.tsx +0 -147
  37. package/template/apps/web/src/components/platform-fields/AddressField.tsx +0 -338
  38. package/template/apps/web/src/components/platform-fields/AttachmentFileList.tsx +0 -245
  39. package/template/apps/web/src/components/platform-fields/CascadeField.tsx +0 -49
  40. package/template/apps/web/src/components/platform-fields/DateTimeField.tsx +0 -148
  41. package/template/apps/web/src/components/platform-fields/JsonField.tsx +0 -77
  42. package/template/apps/web/src/components/platform-fields/LocationField.tsx +0 -164
  43. package/template/apps/web/src/components/platform-fields/PlatformDirectoryPicker.tsx +0 -673
  44. package/template/apps/web/src/components/platform-fields/ResourceReferenceField.tsx +0 -67
  45. package/template/apps/web/src/components/platform-fields/RichTextField.tsx +0 -196
  46. package/template/apps/web/src/components/platform-fields/SignatureField.tsx +0 -315
  47. package/template/apps/web/src/components/platform-fields/SubtableField.tsx +0 -553
  48. package/template/apps/web/src/components/platform-fields/address-value.ts +0 -80
  49. package/template/apps/web/src/components/platform-fields/cascade-value.ts +0 -66
  50. package/template/apps/web/src/components/platform-fields/directory-value.ts +0 -53
  51. package/template/apps/web/src/components/platform-fields/field-form-codec.ts +0 -98
  52. package/template/apps/web/src/components/platform-fields/location-value.ts +0 -87
  53. package/template/apps/web/src/components/platform-fields/resource-query.ts +0 -131
  54. package/template/apps/web/src/components/platform-fields/rich-text-value.ts +0 -59
  55. package/template/apps/web/src/components/platform-fields/subtable-value.ts +0 -187
  56. package/template/apps/web/src/components/resource/GeneratedResourceCrud.tsx +0 -1184
  57. package/template/apps/web/src/components/resource/ResourceBatchActions.tsx +0 -326
  58. package/template/apps/web/src/components/resource/StandardResourcePages.tsx +0 -392
  59. package/template/apps/web/src/components/resource/SurfaceFields.tsx +0 -915
  60. package/template/apps/web/src/components/resource/generated-resource-definition.ts +0 -18
  61. package/template/apps/web/src/components/resource/resource-import.ts +0 -205
  62. package/template/apps/web/src/data-provider.ts +0 -72
  63. package/template/apps/web/src/platform-client.ts +0 -708
  64. package/template/apps/web/src/runtime-meta.ts +0 -75
  65. package/template/apps/web/src/runtime.tsx +0 -227
  66. package/template/apps/web/src/styles.css +0 -1941
  67. package/template/apps/web/test/address-field.test.ts +0 -66
  68. package/template/apps/web/test/cascade-value.test.ts +0 -68
  69. package/template/apps/web/test/directory-value.test.ts +0 -55
  70. package/template/apps/web/test/field-bounds.test.ts +0 -17
  71. package/template/apps/web/test/field-form-codec.test.ts +0 -85
  72. package/template/apps/web/test/location-field.test.ts +0 -83
  73. package/template/apps/web/test/resource-import.test.ts +0 -143
  74. package/template/apps/web/test/resource-query.test.ts +0 -144
  75. package/template/apps/web/test/rich-json-field.test.ts +0 -53
  76. package/template/apps/web/test/signature-serial-field.test.ts +0 -40
  77. package/template/apps/web/test/subtable-value.test.ts +0 -144
@@ -1,53 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import { readFileSync } from 'node:fs';
3
- import test from 'node:test';
4
- import { parseJsonEditorValue } from '../src/components/platform-fields/JsonField';
5
- import { richTextPlainText } from '../src/components/platform-fields/rich-text-value';
6
-
7
- test('JSON editor submits structured values and rejects invalid text', () => {
8
- assert.deepEqual(parseJsonEditorValue('{"enabled":true,"items":[1,2]}'), {
9
- enabled: true,
10
- items: [1, 2],
11
- });
12
- assert.equal(parseJsonEditorValue(' '), undefined);
13
- assert.throws(() => parseJsonEditorValue('{broken'), SyntaxError);
14
- });
15
-
16
- test('rich text plain fallback does not expose markup in compact contexts', () => {
17
- assert.equal(
18
- richTextPlainText('<h2>Heading</h2><p>Body <strong>text</strong></p>'),
19
- 'Heading Body text'
20
- );
21
- });
22
-
23
- test('rich text editor mirrors the platform allowlist and JSON has readonly formatting', () => {
24
- const richValue = readFileSync(
25
- new URL('../src/components/platform-fields/rich-text-value.ts', import.meta.url),
26
- 'utf8'
27
- );
28
- const richField = readFileSync(
29
- new URL('../src/components/platform-fields/RichTextField.tsx', import.meta.url),
30
- 'utf8'
31
- );
32
- const jsonField = readFileSync(
33
- new URL('../src/components/platform-fields/JsonField.tsx', import.meta.url),
34
- 'utf8'
35
- );
36
- const attachmentList = readFileSync(
37
- new URL('../src/components/platform-fields/AttachmentFileList.tsx', import.meta.url),
38
- 'utf8'
39
- );
40
- assert.match(richValue, /MANAGED_IMAGE/);
41
- assert.match(richValue, /disposition=inline/);
42
- assert.match(richValue, /noopener noreferrer/);
43
- assert.match(richField, /contentEditable/);
44
- assert.match(richField, /dangerouslySetInnerHTML/);
45
- assert.match(richField, /FileImageOutlined/);
46
- assert.match(richField, /dataRichTextImageSource/);
47
- assert.match(richField, /10 \* 1024 \* 1024/);
48
- assert.match(richField, /INLINE_IMAGE_MAX_COUNT = 20/);
49
- assert.match(attachmentList, /file\.thumbnailUrl/);
50
- assert.match(attachmentList, /oxa-file-thumbnail/);
51
- assert.match(jsonField, /JSON\.stringify\(value, null, 2\)/);
52
- assert.match(jsonField, /JSON 格式无效/);
53
- });
@@ -1,40 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import { readFileSync } from 'node:fs';
3
- import test from 'node:test';
4
-
5
- test('signature canvas emits managed PNG, SHA-256 and business metadata', () => {
6
- const field = readFileSync(
7
- new URL('../src/components/platform-fields/SignatureField.tsx', import.meta.url),
8
- 'utf8'
9
- );
10
- assert.match(field, /toBlob\(resolve, 'image\/png'\)/);
11
- assert.match(field, /digest\('SHA-256'/);
12
- assert.match(field, /signedAt: new Date\(\)\.toISOString\(\)/);
13
- assert.match(field, /points: points\.current\.slice\(\)/);
14
- assert.match(field, /file: managedFile\(uploaded\)/);
15
- assert.doesNotMatch(field, /dataURL|base64/);
16
- });
17
-
18
- test('signature has separate desktop/mobile dialogs and serial stays server-owned', () => {
19
- const signature = readFileSync(
20
- new URL('../src/components/platform-fields/SignatureField.tsx', import.meta.url),
21
- 'utf8'
22
- );
23
- const surface = readFileSync(
24
- new URL('../src/components/resource/SurfaceFields.tsx', import.meta.url),
25
- 'utf8'
26
- );
27
- const crud = readFileSync(
28
- new URL('../src/components/resource/GeneratedResourceCrud.tsx', import.meta.url),
29
- 'utf8'
30
- );
31
- assert.match(signature, /<Drawer/);
32
- assert.match(signature, /<Modal/);
33
- assert.match(surface, /保存后由系统自动生成/);
34
- assert.match(
35
- crud,
36
- /field\.widget !== 'readonly' && fieldWriteAuthorized\(field, mode/
37
- );
38
- assert.match(crud, /canWrite: \(fieldCode, childField, childOperation\) =>\s+fieldWriteAuthorized\(/);
39
- assert.match(crud, /signatureSigner\(identity\.subjectProfile\)/);
40
- });
@@ -1,144 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import test from 'node:test';
3
- import type { DataResourceSurface } from 'openxiangda-contracts/browser';
4
- import {
5
- buildSubtableOperations,
6
- type SubtableDraftRow,
7
- } from '../src/components/platform-fields/subtable-value';
8
-
9
- const childSurface: DataResourceSurface = {
10
- fields: {
11
- parent_id: field('uuid'),
12
- display_order: field('number.integer'),
13
- description: field('text.short'),
14
- private_note: {
15
- ...field('text.long'),
16
- createCapabilities: [],
17
- updateCapabilities: [],
18
- },
19
- },
20
- };
21
-
22
- test('plans parent references, updates, deletes and deterministic reorder', () => {
23
- const rows: SubtableDraftRow[] = [
24
- {
25
- key: 'new',
26
- state: 'created',
27
- data: { description: 'New', private_note: 'forbidden' },
28
- },
29
- {
30
- key: 'existing',
31
- state: 'persisted',
32
- id: 'child-1',
33
- revision: 3,
34
- originalOrder: 0,
35
- originalData: { description: 'Old' },
36
- data: { description: 'Changed' },
37
- },
38
- {
39
- key: 'deleted',
40
- state: 'deleted',
41
- id: 'child-2',
42
- revision: 2,
43
- data: {},
44
- },
45
- ];
46
- const operations = buildSubtableOperations({
47
- rows,
48
- childResourceCode: 'children',
49
- childSurface,
50
- foreignKey: 'parent_id',
51
- orderField: 'display_order',
52
- parent: { operation: 'create', operationIndex: 0 },
53
- canWrite: (_code, field, operation) =>
54
- (operation === 'create'
55
- ? field.createCapabilities
56
- : field.updateCapabilities
57
- ).length > 0,
58
- canDelete: true,
59
- });
60
- assert.deepEqual(operations, [
61
- {
62
- operation: 'delete',
63
- resourceCode: 'children',
64
- id: 'child-2',
65
- expectedRevision: 2,
66
- },
67
- {
68
- operation: 'create',
69
- resourceCode: 'children',
70
- data: {
71
- description: 'New',
72
- parent_id: { operationIndex: 0, field: 'id' },
73
- display_order: 0,
74
- },
75
- },
76
- {
77
- operation: 'update',
78
- resourceCode: 'children',
79
- id: 'child-1',
80
- expectedRevision: 3,
81
- data: { description: 'Changed', display_order: 1 },
82
- },
83
- ]);
84
- });
85
-
86
- test('omits unchanged persisted rows and enforces the transaction-derived row bound', () => {
87
- const unchanged: SubtableDraftRow = {
88
- key: 'existing',
89
- state: 'persisted',
90
- id: 'child-1',
91
- revision: 1,
92
- originalOrder: 0,
93
- originalData: { description: 'Same' },
94
- data: { description: 'Same' },
95
- };
96
- assert.deepEqual(
97
- buildSubtableOperations({
98
- rows: [unchanged],
99
- childResourceCode: 'children',
100
- childSurface,
101
- foreignKey: 'parent_id',
102
- orderField: 'display_order',
103
- parent: { operation: 'update', id: 'parent-1' },
104
- canWrite: () => true,
105
- canDelete: true,
106
- }),
107
- []
108
- );
109
- assert.throws(
110
- () =>
111
- buildSubtableOperations({
112
- rows: Array.from({ length: 50 }, (_, index) => ({
113
- key: String(index),
114
- state: 'created' as const,
115
- data: { description: String(index) },
116
- })),
117
- childResourceCode: 'children',
118
- childSurface,
119
- foreignKey: 'parent_id',
120
- orderField: 'display_order',
121
- maxRows: 49,
122
- parent: { operation: 'update', id: 'parent-1' },
123
- canWrite: () => true,
124
- canDelete: true,
125
- }),
126
- /OPENXIANGDA_SUBTABLE_MAX_ROWS_EXCEEDED/
127
- );
128
- });
129
-
130
- function field(type: string) {
131
- return {
132
- label: type,
133
- type,
134
- widget:
135
- type === 'uuid'
136
- ? 'readonly'
137
- : type === 'number.integer'
138
- ? 'number'
139
- : 'text',
140
- readCapabilities: ['read'],
141
- createCapabilities: ['create'],
142
- updateCapabilities: ['update'],
143
- } as any;
144
- }