openxiangda-cli 2.0.0-alpha.86 → 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 (78) 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 +5 -5
  16. package/template/apps/server/package.json +1 -1
  17. package/template/apps/server/src/app.module.ts +14 -1
  18. package/template/apps/server/src/main.ts +1 -1
  19. package/template/apps/server/test/smoke.test.ts +3 -1
  20. package/template/apps/web/e2e/client-fixture.ts +5 -0
  21. package/template/apps/web/e2e/data-api-live-fixture.tsx +19 -14
  22. package/template/apps/web/e2e/field-protocol-fixture.tsx +87 -20
  23. package/template/apps/web/e2e/field-protocol.spec.ts +86 -0
  24. package/template/apps/web/e2e/resources.spec.ts +20 -181
  25. package/template/apps/web/field-protocol.e2e.html +3 -0
  26. package/template/apps/web/package.json +2 -5
  27. package/template/apps/web/src/main.tsx +12 -60
  28. package/template/apps/web/test/contracts.test.ts +52 -104
  29. package/template/openxiangda.config.ts +2 -2
  30. package/template/package.json +1 -3
  31. package/template/packages/contracts/src/generated.ts +27 -0
  32. package/template/scripts/verify-template-budget.mjs +2 -2
  33. package/template/apps/web/src/AuthoritativeSelector.tsx +0 -661
  34. package/template/apps/web/src/FilePreviewPage.tsx +0 -324
  35. package/template/apps/web/src/RoleSubjectSelect.tsx +0 -128
  36. package/template/apps/web/src/Shell.tsx +0 -445
  37. package/template/apps/web/src/appearance.tsx +0 -147
  38. package/template/apps/web/src/components/platform-fields/AddressField.tsx +0 -338
  39. package/template/apps/web/src/components/platform-fields/AttachmentFileList.tsx +0 -245
  40. package/template/apps/web/src/components/platform-fields/CascadeField.tsx +0 -49
  41. package/template/apps/web/src/components/platform-fields/DateTimeField.tsx +0 -148
  42. package/template/apps/web/src/components/platform-fields/JsonField.tsx +0 -77
  43. package/template/apps/web/src/components/platform-fields/LocationField.tsx +0 -164
  44. package/template/apps/web/src/components/platform-fields/PlatformDirectoryPicker.tsx +0 -673
  45. package/template/apps/web/src/components/platform-fields/ResourceReferenceField.tsx +0 -67
  46. package/template/apps/web/src/components/platform-fields/RichTextField.tsx +0 -196
  47. package/template/apps/web/src/components/platform-fields/SignatureField.tsx +0 -315
  48. package/template/apps/web/src/components/platform-fields/SubtableField.tsx +0 -553
  49. package/template/apps/web/src/components/platform-fields/address-value.ts +0 -80
  50. package/template/apps/web/src/components/platform-fields/cascade-value.ts +0 -66
  51. package/template/apps/web/src/components/platform-fields/directory-value.ts +0 -53
  52. package/template/apps/web/src/components/platform-fields/field-form-codec.ts +0 -98
  53. package/template/apps/web/src/components/platform-fields/location-value.ts +0 -87
  54. package/template/apps/web/src/components/platform-fields/resource-query.ts +0 -131
  55. package/template/apps/web/src/components/platform-fields/rich-text-value.ts +0 -59
  56. package/template/apps/web/src/components/platform-fields/subtable-value.ts +0 -187
  57. package/template/apps/web/src/components/resource/GeneratedResourceCrud.tsx +0 -1184
  58. package/template/apps/web/src/components/resource/ResourceBatchActions.tsx +0 -326
  59. package/template/apps/web/src/components/resource/StandardResourcePages.tsx +0 -392
  60. package/template/apps/web/src/components/resource/SurfaceFields.tsx +0 -915
  61. package/template/apps/web/src/components/resource/generated-resource-definition.ts +0 -18
  62. package/template/apps/web/src/components/resource/resource-import.ts +0 -205
  63. package/template/apps/web/src/data-provider.ts +0 -72
  64. package/template/apps/web/src/platform-client.ts +0 -708
  65. package/template/apps/web/src/runtime-meta.ts +0 -75
  66. package/template/apps/web/src/runtime.tsx +0 -227
  67. package/template/apps/web/src/styles.css +0 -1941
  68. package/template/apps/web/test/address-field.test.ts +0 -66
  69. package/template/apps/web/test/cascade-value.test.ts +0 -68
  70. package/template/apps/web/test/directory-value.test.ts +0 -55
  71. package/template/apps/web/test/field-bounds.test.ts +0 -17
  72. package/template/apps/web/test/field-form-codec.test.ts +0 -85
  73. package/template/apps/web/test/location-field.test.ts +0 -83
  74. package/template/apps/web/test/resource-import.test.ts +0 -143
  75. package/template/apps/web/test/resource-query.test.ts +0 -144
  76. package/template/apps/web/test/rich-json-field.test.ts +0 -53
  77. package/template/apps/web/test/signature-serial-field.test.ts +0 -40
  78. 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
- }