@cyberismo/backend 0.0.21 → 0.0.22

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 (126) hide show
  1. package/dist/app.d.ts +5 -2
  2. package/dist/app.js +22 -9
  3. package/dist/app.js.map +1 -1
  4. package/dist/auth/index.d.ts +16 -0
  5. package/dist/auth/index.js +15 -0
  6. package/dist/auth/index.js.map +1 -0
  7. package/dist/auth/keycloak.d.ts +27 -0
  8. package/dist/auth/keycloak.js +81 -0
  9. package/dist/auth/keycloak.js.map +1 -0
  10. package/dist/auth/mock.d.ts +23 -0
  11. package/dist/auth/mock.js +28 -0
  12. package/dist/auth/mock.js.map +1 -0
  13. package/dist/auth/types.d.ts +16 -0
  14. package/dist/auth/types.js +14 -0
  15. package/dist/auth/types.js.map +1 -0
  16. package/dist/domain/auth/index.d.ts +14 -0
  17. package/dist/domain/auth/index.js +30 -0
  18. package/dist/domain/auth/index.js.map +1 -0
  19. package/dist/domain/calculations/index.js +3 -1
  20. package/dist/domain/calculations/index.js.map +1 -1
  21. package/dist/domain/calculations/service.js +13 -11
  22. package/dist/domain/calculations/service.js.map +1 -1
  23. package/dist/domain/cardTypes/index.js +5 -3
  24. package/dist/domain/cardTypes/index.js.map +1 -1
  25. package/dist/domain/cardTypes/service.js +24 -72
  26. package/dist/domain/cardTypes/service.js.map +1 -1
  27. package/dist/domain/cards/index.js +19 -15
  28. package/dist/domain/cards/index.js.map +1 -1
  29. package/dist/domain/cards/lib.js +95 -93
  30. package/dist/domain/cards/lib.js.map +1 -1
  31. package/dist/domain/cards/service.d.ts +2 -1
  32. package/dist/domain/cards/service.js +60 -87
  33. package/dist/domain/cards/service.js.map +1 -1
  34. package/dist/domain/fieldTypes/index.js +4 -2
  35. package/dist/domain/fieldTypes/index.js.map +1 -1
  36. package/dist/domain/graphModels/index.js +3 -1
  37. package/dist/domain/graphModels/index.js.map +1 -1
  38. package/dist/domain/graphViews/index.js +3 -1
  39. package/dist/domain/graphViews/index.js.map +1 -1
  40. package/dist/domain/labels/index.js +4 -2
  41. package/dist/domain/labels/index.js.map +1 -1
  42. package/dist/domain/labels/service.d.ts +1 -1
  43. package/dist/domain/labels/service.js +2 -2
  44. package/dist/domain/labels/service.js.map +1 -1
  45. package/dist/domain/linkTypes/index.js +4 -2
  46. package/dist/domain/linkTypes/index.js.map +1 -1
  47. package/dist/domain/logicPrograms/index.js +3 -1
  48. package/dist/domain/logicPrograms/index.js.map +1 -1
  49. package/dist/domain/mcp/index.d.ts +15 -0
  50. package/dist/domain/mcp/index.js +127 -0
  51. package/dist/domain/mcp/index.js.map +1 -0
  52. package/dist/domain/project/index.js +7 -5
  53. package/dist/domain/project/index.js.map +1 -1
  54. package/dist/domain/project/service.js +18 -14
  55. package/dist/domain/project/service.js.map +1 -1
  56. package/dist/domain/reports/index.js +3 -1
  57. package/dist/domain/reports/index.js.map +1 -1
  58. package/dist/domain/resources/index.js +6 -4
  59. package/dist/domain/resources/index.js.map +1 -1
  60. package/dist/domain/resources/service.js +66 -64
  61. package/dist/domain/resources/service.js.map +1 -1
  62. package/dist/domain/templates/index.js +5 -3
  63. package/dist/domain/templates/index.js.map +1 -1
  64. package/dist/domain/tree/index.js +3 -1
  65. package/dist/domain/tree/index.js.map +1 -1
  66. package/dist/domain/workflows/index.js +3 -1
  67. package/dist/domain/workflows/index.js.map +1 -1
  68. package/dist/export.d.ts +6 -5
  69. package/dist/export.js +15 -11
  70. package/dist/export.js.map +1 -1
  71. package/dist/index.d.ts +8 -2
  72. package/dist/index.js +5 -3
  73. package/dist/index.js.map +1 -1
  74. package/dist/main.js +29 -2
  75. package/dist/main.js.map +1 -1
  76. package/dist/middleware/auth.d.ts +40 -0
  77. package/dist/middleware/auth.js +68 -0
  78. package/dist/middleware/auth.js.map +1 -0
  79. package/dist/middleware/commandManager.d.ts +2 -2
  80. package/dist/middleware/commandManager.js +9 -11
  81. package/dist/middleware/commandManager.js.map +1 -1
  82. package/dist/public/THIRD-PARTY.txt +37 -11
  83. package/dist/public/assets/index-B_lh6qtv.css +1 -0
  84. package/dist/public/assets/{index-Ca10XaMv.js → index-CEol8Bfi.js} +43823 -43030
  85. package/dist/public/config.json +1 -0
  86. package/dist/public/index.html +2 -2
  87. package/dist/types.d.ts +25 -0
  88. package/dist/types.js +13 -1
  89. package/dist/types.js.map +1 -1
  90. package/package.json +8 -5
  91. package/src/app.ts +34 -14
  92. package/src/auth/index.ts +17 -0
  93. package/src/auth/keycloak.ts +109 -0
  94. package/src/auth/mock.ts +38 -0
  95. package/src/auth/types.ts +18 -0
  96. package/src/domain/auth/index.ts +35 -0
  97. package/src/domain/calculations/index.ts +13 -6
  98. package/src/domain/calculations/service.ts +16 -14
  99. package/src/domain/cardTypes/index.ts +24 -16
  100. package/src/domain/cardTypes/service.ts +41 -95
  101. package/src/domain/cards/index.ts +62 -44
  102. package/src/domain/cards/lib.ts +105 -100
  103. package/src/domain/cards/service.ts +73 -89
  104. package/src/domain/fieldTypes/index.ts +23 -16
  105. package/src/domain/graphModels/index.ts +13 -6
  106. package/src/domain/graphViews/index.ts +13 -6
  107. package/src/domain/labels/index.ts +5 -2
  108. package/src/domain/labels/service.ts +2 -2
  109. package/src/domain/linkTypes/index.ts +14 -7
  110. package/src/domain/logicPrograms/index.ts +3 -0
  111. package/src/domain/mcp/index.ts +159 -0
  112. package/src/domain/project/index.ts +17 -8
  113. package/src/domain/project/service.ts +20 -16
  114. package/src/domain/reports/index.ts +13 -6
  115. package/src/domain/resources/index.ts +6 -1
  116. package/src/domain/resources/service.ts +102 -97
  117. package/src/domain/templates/index.ts +31 -19
  118. package/src/domain/tree/index.ts +3 -1
  119. package/src/domain/workflows/index.ts +13 -6
  120. package/src/export.ts +16 -13
  121. package/src/index.ts +10 -3
  122. package/src/main.ts +44 -2
  123. package/src/middleware/auth.ts +90 -0
  124. package/src/middleware/commandManager.ts +11 -14
  125. package/src/types.ts +27 -0
  126. package/dist/public/assets/index-CRSBseQM.css +0 -1
@@ -54,126 +54,72 @@ export async function updateFieldVisibility(
54
54
  ): Promise<void> {
55
55
  const { fieldName, group: targetGroup, index: targetIndex } = body;
56
56
 
57
- // Get current card type data
58
- const cardType = await commands.showCmd.showResource(
59
- cardTypeName,
60
- 'cardTypes',
61
- );
62
- if (!cardType) {
63
- throw new Error(`Card type '${cardTypeName}' not found`);
64
- }
57
+ await commands.atomic(async () => {
58
+ // Read is now inside the write lock
59
+ const cardType = await commands.showCmd.showResource(
60
+ cardTypeName,
61
+ 'cardTypes',
62
+ );
63
+ if (!cardType) {
64
+ throw new Error(`Card type '${cardTypeName}' not found`);
65
+ }
65
66
 
66
- const customFields = cardType.customFields || [];
67
- const alwaysVisibleFields = cardType.alwaysVisibleFields || [];
68
- const optionallyVisibleFields = cardType.optionallyVisibleFields || [];
67
+ const customFields = cardType.customFields || [];
68
+ const alwaysVisibleFields = cardType.alwaysVisibleFields || [];
69
+ const optionallyVisibleFields = cardType.optionallyVisibleFields || [];
69
70
 
70
- // Validate that the field exists in customFields
71
- const fieldExists = customFields.some(
72
- (f: { name: string }) => f.name === fieldName,
73
- );
74
- if (!fieldExists) {
75
- throw new Error(
76
- `Field '${fieldName}' does not exist in card type '${cardTypeName}'. `,
71
+ // Validate that the field exists in customFields
72
+ const fieldExists = customFields.some(
73
+ (f: { name: string }) => f.name === fieldName,
77
74
  );
78
- }
75
+ if (!fieldExists) {
76
+ throw new Error(
77
+ `Field '${fieldName}' does not exist in card type '${cardTypeName}'. `,
78
+ );
79
+ }
79
80
 
80
- const currentGroup = getCurrentGroup(
81
- alwaysVisibleFields,
82
- optionallyVisibleFields,
83
- fieldName,
84
- );
81
+ const currentGroup = getCurrentGroup(
82
+ alwaysVisibleFields,
83
+ optionallyVisibleFields,
84
+ fieldName,
85
+ );
85
86
 
86
- // If same group, just handle reordering
87
- if (currentGroup === targetGroup) {
88
- if (targetGroup === 'hidden') {
89
- // Nothing to reorder in hidden group
87
+ // If same group, just handle reordering
88
+ if (currentGroup === targetGroup) {
89
+ if (targetGroup !== 'hidden' && targetIndex !== undefined) {
90
+ await commands.updateCmd.applyResourceOperation(
91
+ cardTypeName,
92
+ { key: groupToKey[targetGroup] },
93
+ { name: 'rank', target: fieldName, newIndex: targetIndex },
94
+ );
95
+ }
90
96
  return;
91
97
  }
92
98
 
93
- if (targetIndex !== undefined) {
94
- await commands.updateCmd.applyResourceOperation(
95
- cardTypeName,
96
- {
97
- key: groupToKey[targetGroup],
98
- },
99
- {
100
- name: 'rank',
101
- target: fieldName,
102
- newIndex: targetIndex,
103
- },
104
- );
105
- }
106
- return;
107
- }
108
-
109
- // Different group - need to remove from old and add to new
110
- let removedFromOld = false;
111
-
112
- try {
113
99
  // Remove from current group (if not hidden)
114
100
  if (currentGroup !== 'hidden') {
115
101
  await commands.updateCmd.applyResourceOperation(
116
102
  cardTypeName,
117
- {
118
- key: groupToKey[currentGroup],
119
- },
120
- {
121
- name: 'remove',
122
- target: fieldName,
123
- },
103
+ { key: groupToKey[currentGroup] },
104
+ { name: 'remove', target: fieldName },
124
105
  );
125
- removedFromOld = true;
126
106
  }
127
107
 
128
108
  // Add to new group (if not hidden)
129
109
  if (targetGroup !== 'hidden') {
130
110
  await commands.updateCmd.applyResourceOperation(
131
111
  cardTypeName,
132
- {
133
- key: groupToKey[targetGroup],
134
- },
135
- {
136
- name: 'add',
137
- target: fieldName,
138
- },
112
+ { key: groupToKey[targetGroup] },
113
+ { name: 'add', target: fieldName },
139
114
  );
140
115
 
141
- // Reorder if index specified
142
116
  if (targetIndex !== undefined) {
143
117
  await commands.updateCmd.applyResourceOperation(
144
118
  cardTypeName,
145
- {
146
- key: groupToKey[targetGroup],
147
- },
148
- {
149
- name: 'rank',
150
- target: fieldName,
151
- newIndex: targetIndex,
152
- },
153
- );
154
- }
155
- }
156
- } catch (error) {
157
- // Attempt rollback if we removed from old group but failed to add to new
158
- if (removedFromOld && currentGroup !== 'hidden') {
159
- try {
160
- await commands.updateCmd.applyResourceOperation(
161
- cardTypeName,
162
- {
163
- key: groupToKey[currentGroup],
164
- },
165
- {
166
- name: 'add',
167
- target: fieldName,
168
- },
169
- );
170
- } catch {
171
- // Rollback failed - log but throw original error
172
- console.error(
173
- `Rollback failed for field '${fieldName}' in card type '${cardTypeName}'`,
119
+ { key: groupToKey[targetGroup] },
120
+ { name: 'rank', target: fieldName, newIndex: targetIndex },
174
121
  );
175
122
  }
176
123
  }
177
- throw error;
178
- }
124
+ }, `Update field visibility for ${cardTypeName}`);
179
125
  }
@@ -17,6 +17,8 @@ import { getCardDetails } from './lib.js';
17
17
  import * as cardService from './service.js';
18
18
  import { isSSGContext, ssgParams } from 'hono/ssg';
19
19
  import type { AppContext } from '../../types.js';
20
+ import { UserRole } from '../../types.js';
21
+ import { requireRole } from '../../middleware/auth.js';
20
22
 
21
23
  const router = new Hono();
22
24
 
@@ -34,7 +36,7 @@ const router = new Hono();
34
36
  * 500:
35
37
  * description: project_path not set.
36
38
  */
37
- router.get('/', async (c) => {
39
+ router.get('/', requireRole(UserRole.Reader), async (c) => {
38
40
  const commands = c.get('commands');
39
41
 
40
42
  try {
@@ -75,6 +77,7 @@ router.get('/', async (c) => {
75
77
  */
76
78
  router.get(
77
79
  '/:key',
80
+ requireRole(UserRole.Reader),
78
81
  ssgParams(async (c: AppContext) => {
79
82
  const commands = c.get('commands');
80
83
  const opts = c.get('tree');
@@ -144,7 +147,7 @@ router.get(
144
147
  * 500:
145
148
  * description: project_path not set.
146
149
  */
147
- router.patch('/:key', async (c) => {
150
+ router.patch('/:key', requireRole(UserRole.Editor), async (c) => {
148
151
  const commands = c.get('commands');
149
152
  const key = c.req.param('key');
150
153
  if (!key) {
@@ -201,7 +204,7 @@ router.patch('/:key', async (c) => {
201
204
  * 500:
202
205
  * description: project_path not set.
203
206
  */
204
- router.delete('/:key', async (c) => {
207
+ router.delete('/:key', requireRole(UserRole.Editor), async (c) => {
205
208
  const commands = c.get('commands');
206
209
  const key = c.req.param('key');
207
210
  if (!key) {
@@ -244,7 +247,7 @@ router.delete('/:key', async (c) => {
244
247
  * 500:
245
248
  * description: project_path not set
246
249
  */
247
- router.post('/:key', async (c) => {
250
+ router.post('/:key', requireRole(UserRole.Editor), async (c) => {
248
251
  const key = c.req.param('key');
249
252
  if (!key) {
250
253
  return c.text('No search key', 400);
@@ -300,7 +303,7 @@ router.post('/:key', async (c) => {
300
303
  * 500:
301
304
  * description: Server error
302
305
  */
303
- router.post('/:key/attachments', async (c) => {
306
+ router.post('/:key/attachments', requireRole(UserRole.Editor), async (c) => {
304
307
  const commands = c.get('commands');
305
308
  const key = c.req.param('key');
306
309
 
@@ -354,25 +357,33 @@ router.post('/:key/attachments', async (c) => {
354
357
  * 500:
355
358
  * description: Server error
356
359
  */
357
- router.delete('/:key/attachments/:filename', async (c) => {
358
- const commands = c.get('commands');
359
- const { key, filename } = c.req.param();
360
+ router.delete(
361
+ '/:key/attachments/:filename',
362
+ requireRole(UserRole.Editor),
363
+ async (c) => {
364
+ const commands = c.get('commands');
365
+ const { key, filename } = c.req.param();
360
366
 
361
- try {
362
- const result = await cardService.removeAttachment(commands, key, filename);
363
- return c.json(result);
364
- } catch (error) {
365
- return c.json(
366
- {
367
- error:
368
- error instanceof Error
369
- ? error.message
370
- : 'Failed to remove attachment',
371
- },
372
- 500,
373
- );
374
- }
375
- });
367
+ try {
368
+ const result = await cardService.removeAttachment(
369
+ commands,
370
+ key,
371
+ filename,
372
+ );
373
+ return c.json(result);
374
+ } catch (error) {
375
+ return c.json(
376
+ {
377
+ error:
378
+ error instanceof Error
379
+ ? error.message
380
+ : 'Failed to remove attachment',
381
+ },
382
+ 500,
383
+ );
384
+ }
385
+ },
386
+ );
376
387
 
377
388
  /**
378
389
  * @swagger
@@ -398,23 +409,29 @@ router.delete('/:key/attachments/:filename', async (c) => {
398
409
  * 500:
399
410
  * description: Server error
400
411
  */
401
- router.post('/:key/attachments/:filename/open', async (c) => {
402
- const commands = c.get('commands');
403
- const { key, filename } = c.req.param();
412
+ router.post(
413
+ '/:key/attachments/:filename/open',
414
+ requireRole(UserRole.Reader),
415
+ async (c) => {
416
+ const commands = c.get('commands');
417
+ const { key, filename } = c.req.param();
404
418
 
405
- try {
406
- const result = await cardService.openAttachment(commands, key, filename);
407
- return c.json(result);
408
- } catch (error) {
409
- return c.json(
410
- {
411
- error:
412
- error instanceof Error ? error.message : 'Failed to open attachment',
413
- },
414
- 500,
415
- );
416
- }
417
- });
419
+ try {
420
+ const result = await cardService.openAttachment(commands, key, filename);
421
+ return c.json(result);
422
+ } catch (error) {
423
+ return c.json(
424
+ {
425
+ error:
426
+ error instanceof Error
427
+ ? error.message
428
+ : 'Failed to open attachment',
429
+ },
430
+ 500,
431
+ );
432
+ }
433
+ },
434
+ );
418
435
 
419
436
  /**
420
437
  * @swagger
@@ -443,7 +460,7 @@ router.post('/:key/attachments/:filename/open', async (c) => {
443
460
  * 500:
444
461
  * description: Server error
445
462
  */
446
- router.post('/:key/parse', async (c) => {
463
+ router.post('/:key/parse', requireRole(UserRole.Reader), async (c) => {
447
464
  const commands = c.get('commands');
448
465
  const key = c.req.param('key');
449
466
  const { content } = await c.req.json();
@@ -497,7 +514,7 @@ router.post('/:key/parse', async (c) => {
497
514
  * 500:
498
515
  * description: Server error
499
516
  */
500
- router.post('/:key/links', async (c) => {
517
+ router.post('/:key/links', requireRole(UserRole.Editor), async (c) => {
501
518
  const commands = c.get('commands');
502
519
  const key = c.req.param('key');
503
520
  const { toCard, linkType, description } = await c.req.json();
@@ -556,7 +573,7 @@ router.post('/:key/links', async (c) => {
556
573
  * 500:
557
574
  * description: Server error
558
575
  */
559
- router.delete('/:key/links', async (c) => {
576
+ router.delete('/:key/links', requireRole(UserRole.Editor), async (c) => {
560
577
  const commands = c.get('commands');
561
578
  const key = c.req.param('key');
562
579
  const { toCard, linkType, description } = await c.req.json();
@@ -610,11 +627,12 @@ router.delete('/:key/links', async (c) => {
610
627
  */
611
628
  router.get(
612
629
  '/:key/a/:attachment',
630
+ requireRole(UserRole.Reader),
613
631
  ssgParams(async (c: Context) => {
614
632
  const commands = c.get('commands');
615
633
  return await cardService.findRelevantAttachments(commands, c.get('tree'));
616
634
  }),
617
- (c) => {
635
+ async (c) => {
618
636
  const commands = c.get('commands');
619
637
  const { key, attachment } = c.req.param();
620
638
  const filename = decodeURI(attachment);
@@ -624,7 +642,7 @@ router.get(
624
642
  }
625
643
 
626
644
  try {
627
- const attachmentResponse = cardService.getAttachment(
645
+ const attachmentResponse = await cardService.getAttachment(
628
646
  commands,
629
647
  key,
630
648
  filename,
@@ -30,122 +30,127 @@ export async function getCardDetails(
30
30
  staticMode: boolean,
31
31
  raw: boolean,
32
32
  ): Promise<result> {
33
- let cardDetailsResponse: Card;
34
- try {
35
- cardDetailsResponse = commands.showCmd.showCardDetails(key);
36
- } catch {
37
- return { status: 400, message: `Card ${key} not found from project` };
38
- }
33
+ return commands.consistent(async () => {
34
+ let cardDetailsResponse: Card;
35
+ try {
36
+ cardDetailsResponse = await commands.showCmd.showCardDetails(key);
37
+ } catch {
38
+ return { status: 400, message: `Card ${key} not found from project` };
39
+ }
39
40
 
40
- if (!cardDetailsResponse) {
41
- return { status: 400, message: `Card ${key} not found from project` };
42
- }
41
+ if (!cardDetailsResponse) {
42
+ return { status: 400, message: `Card ${key} not found from project` };
43
+ }
43
44
 
44
- // always parse for now if not in export mode
45
- if (!staticMode && !raw) {
46
- await commands.calculateCmd.generate();
47
- }
45
+ // always parse for now if not in export mode
46
+ if (!staticMode && !raw) {
47
+ await commands.calculateCmd.generate();
48
+ }
48
49
 
49
- let asciidocContent = '';
50
- try {
51
- asciidocContent = await evaluateMacros(cardDetailsResponse.content || '', {
52
- context: staticMode ? 'exportedSite' : 'localApp',
53
- mode: staticMode ? 'staticSite' : 'inject',
54
- project: commands.project,
55
- cardKey: key,
56
- });
57
- } catch (error) {
58
- asciidocContent = `Macro error: ${error instanceof Error ? error.message : 'Unknown error'}\n\n${asciidocContent}`;
59
- }
50
+ let asciidocContent = '';
51
+ try {
52
+ asciidocContent = await evaluateMacros(
53
+ cardDetailsResponse.content || '',
54
+ {
55
+ context: staticMode ? 'exportedSite' : 'localApp',
56
+ mode: staticMode ? 'staticSite' : 'inject',
57
+ project: commands.project,
58
+ cardKey: key,
59
+ },
60
+ );
61
+ } catch (error) {
62
+ asciidocContent = `Macro error: ${error instanceof Error ? error.message : 'Unknown error'}\n\n${asciidocContent}`;
63
+ }
60
64
 
61
- const htmlContent = Processor()
62
- .convert(asciidocContent, {
63
- safe: 'safe',
64
- attributes: {
65
- imagesdir: `/api/cards/${key}/a`,
66
- icons: 'font',
67
- },
68
- })
69
- .toString();
65
+ const htmlContent = Processor()
66
+ .convert(asciidocContent, {
67
+ safe: 'safe',
68
+ attributes: {
69
+ imagesdir: `/api/cards/${key}/a`,
70
+ icons: 'font',
71
+ },
72
+ })
73
+ .toString();
70
74
 
71
- if (raw) {
72
- if (!cardDetailsResponse.metadata) {
73
- throw new Error('Card has no metadata');
75
+ if (raw) {
76
+ if (!cardDetailsResponse.metadata) {
77
+ throw new Error('Card has no metadata');
78
+ }
79
+ const cardType = await commands.showCmd.showResource(
80
+ cardDetailsResponse.metadata.cardType,
81
+ 'cardTypes',
82
+ );
83
+
84
+ const fields = [];
85
+ let i = 0;
86
+ for (const customField of cardType.customFields) {
87
+ const fieldType = await commands.showCmd.showResource(
88
+ customField.name,
89
+ 'fieldTypes',
90
+ );
91
+ fields.push({
92
+ key: customField.name,
93
+ visibility: 'always',
94
+ index: i++,
95
+ fieldDisplayName: fieldType.displayName,
96
+ fieldDescription: fieldType.description,
97
+ dataType: fieldType.dataType,
98
+ isCalculated: customField.isCalculated,
99
+ value: cardDetailsResponse.metadata[customField.name],
100
+ enumValues: fieldType.enumValues ?? [],
101
+ });
102
+ }
103
+ return {
104
+ status: 200,
105
+ data: {
106
+ key: cardDetailsResponse.key,
107
+ rank: cardDetailsResponse.metadata?.rank,
108
+ title: cardDetailsResponse.metadata?.title || '',
109
+ cardType: cardDetailsResponse.metadata?.cardType || '',
110
+ cardTypeDisplayName: cardDetailsResponse.metadata.cardType,
111
+ workflowState: '',
112
+ lastUpdated: cardDetailsResponse.metadata.lastUpdated,
113
+ fields,
114
+ labels: cardDetailsResponse.metadata?.labels || [],
115
+ links: [],
116
+ notifications: [],
117
+ policyChecks: {
118
+ successes: [],
119
+ failures: [],
120
+ },
121
+ deniedOperations: {
122
+ transition: [],
123
+ move: [],
124
+ delete: [],
125
+ editField: [],
126
+ editContent: [],
127
+ },
128
+ rawContent: cardDetailsResponse.content || '',
129
+ parsedContent: htmlContent,
130
+ attachments: cardDetailsResponse.attachments,
131
+ },
132
+ };
74
133
  }
75
- const cardType = await commands.showCmd.showResource(
76
- cardDetailsResponse.metadata.cardType,
77
- 'cardTypes',
78
- );
79
134
 
80
- const fields = [];
81
- let i = 0;
82
- for (const customField of cardType.customFields) {
83
- const fieldType = await commands.showCmd.showResource(
84
- customField.name,
85
- 'fieldTypes',
86
- );
87
- fields.push({
88
- key: customField.name,
89
- visibility: 'always',
90
- index: i++,
91
- fieldDisplayName: fieldType.displayName,
92
- fieldDescription: fieldType.description,
93
- dataType: fieldType.dataType,
94
- isCalculated: customField.isCalculated,
95
- value: cardDetailsResponse.metadata[customField.name],
96
- enumValues: fieldType.enumValues ?? [],
97
- });
135
+ const card = staticMode
136
+ ? await getCardQueryResult(commands, key)
137
+ : await commands.calculateCmd.runQuery('card', 'localApp', {
138
+ cardKey: key,
139
+ });
140
+ if (card.length !== 1) {
141
+ throw new Error('Query failed. Check card-query syntax');
98
142
  }
143
+
99
144
  return {
100
145
  status: 200,
101
146
  data: {
102
- key: cardDetailsResponse.key,
103
- rank: cardDetailsResponse.metadata?.rank,
104
- title: cardDetailsResponse.metadata?.title || '',
105
- cardType: cardDetailsResponse.metadata?.cardType || '',
106
- cardTypeDisplayName: cardDetailsResponse.metadata.cardType,
107
- workflowState: '',
108
- lastUpdated: cardDetailsResponse.metadata.lastUpdated,
109
- fields,
110
- labels: cardDetailsResponse.metadata?.labels || [],
111
- links: [],
112
- notifications: [],
113
- policyChecks: {
114
- successes: [],
115
- failures: [],
116
- },
117
- deniedOperations: {
118
- transition: [],
119
- move: [],
120
- delete: [],
121
- editField: [],
122
- editContent: [],
123
- },
147
+ ...card[0],
124
148
  rawContent: cardDetailsResponse.content || '',
125
149
  parsedContent: htmlContent,
126
150
  attachments: cardDetailsResponse.attachments,
127
151
  },
128
152
  };
129
- }
130
-
131
- const card = staticMode
132
- ? await getCardQueryResult(commands.project.basePath, key)
133
- : await commands.calculateCmd.runQuery('card', 'localApp', {
134
- cardKey: key,
135
- });
136
- if (card.length !== 1) {
137
- throw new Error('Query failed. Check card-query syntax');
138
- }
139
-
140
- return {
141
- status: 200,
142
- data: {
143
- ...card[0],
144
- rawContent: cardDetailsResponse.content || '',
145
- parsedContent: htmlContent,
146
- attachments: cardDetailsResponse.attachments,
147
- },
148
- };
153
+ });
149
154
  }
150
155
  /**
151
156
  * Returns all cards from a tree query, flattened.