@cyberismo/backend 0.0.8 → 0.0.10

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 (152) hide show
  1. package/dist/app.js +22 -8
  2. package/dist/app.js.map +1 -1
  3. package/dist/common/validationSchemas.js +39 -0
  4. package/dist/common/validationSchemas.js.map +1 -0
  5. package/dist/domain/calculations/index.js +102 -0
  6. package/dist/domain/calculations/index.js.map +1 -0
  7. package/dist/domain/calculations/schema.js +24 -0
  8. package/dist/domain/calculations/schema.js.map +1 -0
  9. package/dist/domain/calculations/service.js +21 -0
  10. package/dist/domain/calculations/service.js.map +1 -0
  11. package/dist/domain/cardTypes/index.js +86 -0
  12. package/dist/domain/cardTypes/index.js.map +1 -0
  13. package/dist/domain/cardTypes/schema.js +19 -0
  14. package/dist/domain/cardTypes/schema.js.map +1 -0
  15. package/dist/domain/cardTypes/service.js +20 -0
  16. package/dist/domain/cardTypes/service.js.map +1 -0
  17. package/dist/{routes/cards.js → domain/cards/index.js} +52 -223
  18. package/dist/domain/cards/index.js.map +1 -0
  19. package/dist/domain/cards/lib.js +80 -0
  20. package/dist/domain/cards/lib.js.map +1 -0
  21. package/dist/domain/cards/service.js +178 -0
  22. package/dist/domain/cards/service.js.map +1 -0
  23. package/dist/domain/fieldTypes/index.js +87 -0
  24. package/dist/domain/fieldTypes/index.js.map +1 -0
  25. package/dist/domain/fieldTypes/schema.js +30 -0
  26. package/dist/domain/fieldTypes/schema.js.map +1 -0
  27. package/dist/domain/fieldTypes/service.js +24 -0
  28. package/dist/domain/fieldTypes/service.js.map +1 -0
  29. package/dist/domain/graphModels/index.js +50 -0
  30. package/dist/domain/graphModels/index.js.map +1 -0
  31. package/dist/domain/graphModels/schema.js +18 -0
  32. package/dist/domain/graphModels/schema.js.map +1 -0
  33. package/dist/domain/graphModels/service.js +16 -0
  34. package/dist/domain/graphModels/service.js.map +1 -0
  35. package/dist/domain/graphViews/index.js +50 -0
  36. package/dist/domain/graphViews/index.js.map +1 -0
  37. package/dist/domain/graphViews/schema.js +6 -0
  38. package/dist/domain/graphViews/schema.js.map +1 -0
  39. package/dist/domain/graphViews/service.js +16 -0
  40. package/dist/domain/graphViews/service.js.map +1 -0
  41. package/dist/domain/linkTypes/index.js +76 -0
  42. package/dist/domain/linkTypes/index.js.map +1 -0
  43. package/dist/domain/linkTypes/schema.js +18 -0
  44. package/dist/domain/linkTypes/schema.js.map +1 -0
  45. package/dist/domain/linkTypes/service.js +24 -0
  46. package/dist/domain/linkTypes/service.js.map +1 -0
  47. package/dist/domain/logicPrograms/index.js +25 -0
  48. package/dist/domain/logicPrograms/index.js.map +1 -0
  49. package/dist/domain/logicPrograms/service.js +9 -0
  50. package/dist/domain/logicPrograms/service.js.map +1 -0
  51. package/dist/domain/reports/index.js +50 -0
  52. package/dist/domain/reports/index.js.map +1 -0
  53. package/dist/domain/reports/schema.js +18 -0
  54. package/dist/domain/reports/schema.js.map +1 -0
  55. package/dist/domain/reports/service.js +16 -0
  56. package/dist/domain/reports/service.js.map +1 -0
  57. package/dist/domain/resources/index.js +128 -0
  58. package/dist/domain/resources/index.js.map +1 -0
  59. package/dist/domain/resources/schema.js +9 -0
  60. package/dist/domain/resources/schema.js.map +1 -0
  61. package/dist/domain/resources/service.js +258 -0
  62. package/dist/domain/resources/service.js.map +1 -0
  63. package/dist/domain/templates/index.js +81 -0
  64. package/dist/domain/templates/index.js.map +1 -0
  65. package/dist/domain/templates/schema.js +18 -0
  66. package/dist/domain/templates/schema.js.map +1 -0
  67. package/dist/domain/templates/service.js +23 -0
  68. package/dist/domain/templates/service.js.map +1 -0
  69. package/dist/domain/tree/index.js +44 -0
  70. package/dist/domain/tree/index.js.map +1 -0
  71. package/dist/domain/tree/service.js +17 -0
  72. package/dist/domain/tree/service.js.map +1 -0
  73. package/dist/domain/workflows/index.js +50 -0
  74. package/dist/domain/workflows/index.js.map +1 -0
  75. package/dist/domain/workflows/schema.js +18 -0
  76. package/dist/domain/workflows/schema.js.map +1 -0
  77. package/dist/domain/workflows/service.js +16 -0
  78. package/dist/domain/workflows/service.js.map +1 -0
  79. package/dist/export.js +3 -3
  80. package/dist/export.js.map +1 -1
  81. package/dist/middleware/zvalidator.js +8 -0
  82. package/dist/middleware/zvalidator.js.map +1 -0
  83. package/dist/public/THIRD-PARTY.txt +2452 -296
  84. package/dist/public/assets/index-jhDO7xT5.js +161493 -0
  85. package/dist/public/cropped-favicon-180x180.png +0 -0
  86. package/dist/public/cropped-favicon-192x192.png +0 -0
  87. package/dist/public/cropped-favicon-270x270.png +0 -0
  88. package/dist/public/cropped-favicon-32x32.png +0 -0
  89. package/dist/public/index.html +8 -1
  90. package/dist/types.js +14 -0
  91. package/dist/types.js.map +1 -0
  92. package/dist/utils.js +3 -1
  93. package/dist/utils.js.map +1 -1
  94. package/package.json +7 -3
  95. package/src/app.ts +22 -8
  96. package/src/common/validationSchemas.ts +46 -0
  97. package/src/domain/calculations/index.ts +121 -0
  98. package/src/domain/calculations/schema.ts +27 -0
  99. package/src/domain/calculations/service.ts +32 -0
  100. package/src/domain/cardTypes/index.ts +96 -0
  101. package/src/domain/cardTypes/schema.ts +19 -0
  102. package/src/domain/cardTypes/service.ts +28 -0
  103. package/src/{routes/cards.ts → domain/cards/index.ts} +82 -270
  104. package/src/domain/cards/lib.ts +103 -0
  105. package/src/domain/cards/service.ts +254 -0
  106. package/src/domain/fieldTypes/index.ts +97 -0
  107. package/src/domain/fieldTypes/schema.ts +30 -0
  108. package/src/domain/fieldTypes/service.ts +38 -0
  109. package/src/domain/graphModels/index.ts +54 -0
  110. package/src/domain/graphModels/schema.ts +18 -0
  111. package/src/domain/graphModels/service.ts +21 -0
  112. package/src/domain/graphViews/index.ts +53 -0
  113. package/src/domain/graphViews/schema.ts +6 -0
  114. package/src/domain/graphViews/service.ts +20 -0
  115. package/src/domain/linkTypes/index.ts +84 -0
  116. package/src/domain/linkTypes/schema.ts +19 -0
  117. package/src/domain/linkTypes/service.ts +34 -0
  118. package/src/domain/logicPrograms/index.ts +35 -0
  119. package/src/domain/logicPrograms/service.ts +25 -0
  120. package/src/domain/reports/index.ts +54 -0
  121. package/src/domain/reports/schema.ts +19 -0
  122. package/src/domain/reports/service.ts +21 -0
  123. package/src/domain/resources/index.ts +166 -0
  124. package/src/domain/resources/schema.ts +19 -0
  125. package/src/domain/resources/service.ts +436 -0
  126. package/src/domain/templates/index.ts +89 -0
  127. package/src/domain/templates/schema.ts +19 -0
  128. package/src/domain/templates/service.ts +29 -0
  129. package/src/domain/tree/index.ts +50 -0
  130. package/src/domain/tree/service.ts +22 -0
  131. package/src/domain/workflows/index.ts +54 -0
  132. package/src/domain/workflows/schema.ts +19 -0
  133. package/src/domain/workflows/service.ts +21 -0
  134. package/src/export.ts +9 -5
  135. package/src/middleware/commandManager.ts +1 -1
  136. package/src/middleware/zvalidator.ts +17 -0
  137. package/src/types.ts +20 -0
  138. package/src/utils.ts +4 -2
  139. package/dist/public/assets/index-D5kiRHuF.js +0 -111171
  140. package/dist/routes/cards.js.map +0 -1
  141. package/dist/routes/fieldTypes.js +0 -42
  142. package/dist/routes/fieldTypes.js.map +0 -1
  143. package/dist/routes/linkTypes.js +0 -42
  144. package/dist/routes/linkTypes.js.map +0 -1
  145. package/dist/routes/templates.js +0 -46
  146. package/dist/routes/templates.js.map +0 -1
  147. package/dist/routes/tree.js +0 -40
  148. package/dist/routes/tree.js.map +0 -1
  149. package/src/routes/fieldTypes.ts +0 -53
  150. package/src/routes/linkTypes.ts +0 -53
  151. package/src/routes/templates.ts +0 -52
  152. package/src/routes/tree.ts +0 -45
@@ -1,26 +1,21 @@
1
1
  /**
2
- Cyberismo
3
- Copyright © Cyberismo Ltd and contributors 2024
4
-
5
- This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
6
-
7
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
8
-
9
- You should have received a copy of the GNU Affero General Public
10
- License along with this program. If not, see <https://www.gnu.org/licenses/>.
2
+ Cyberismo
3
+ Copyright © Cyberismo Ltd and contributors 2025
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU Affero General Public License version 3 as published by
6
+ the Free Software Foundation.
7
+ This program is distributed in the hope that it will be useful, but WITHOUT
8
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
10
+ details. You should have received a copy of the GNU Affero General Public
11
+ License along with this program. If not, see <https://www.gnu.org/licenses/>.
11
12
  */
12
13
 
13
- import { Context, Hono } from 'hono';
14
- import Processor from '@asciidoctor/core';
15
- import {
16
- Card,
17
- CardLocation,
18
- MetadataContent,
19
- ProjectFetchCardDetails,
20
- } from '@cyberismo/data-handler/interfaces/project-interfaces';
21
- import { CommandManager, evaluateMacros } from '@cyberismo/data-handler';
22
- import { ContentfulStatusCode } from 'hono/utils/http-status';
23
- import { getCardQueryResult, isSSGContext, ssgParams } from '../export.js';
14
+ import { type Context, Hono } from 'hono';
15
+ import type { ContentfulStatusCode } from 'hono/utils/http-status';
16
+ import { ssgParams, isSSGContext } from '../../export.js';
17
+ import { getCardDetails } from './lib.js';
18
+ import * as cardService from './service.js';
24
19
 
25
20
  const router = new Hono();
26
21
 
@@ -41,111 +36,16 @@ const router = new Hono();
41
36
  router.get('/', async (c) => {
42
37
  const commands = c.get('commands');
43
38
 
44
- const projectResponse = await commands.showCmd.showProject();
45
-
46
- const workflowsResponse = await commands.showCmd.showWorkflowsWithDetails();
47
- if (!workflowsResponse) {
48
- return c.text(`No workflows found from path ${c.get('projectPath')}`, 500);
49
- }
50
-
51
- const cardTypesResponse = await commands.showCmd.showCardTypesWithDetails();
52
- if (!cardTypesResponse) {
53
- return c.text(`No card types found from path ${c.get('projectPath')}`, 500);
54
- }
55
-
56
- const cardsResponse = await commands.showCmd.showProjectCards();
57
-
58
- if (!cardsResponse) {
59
- return c.text(`No cards found from path ${c.get('projectPath')}`, 500);
60
- }
61
-
62
- const response = {
63
- name: (projectResponse! as any).name,
64
- cards: cardsResponse,
65
- workflows: workflowsResponse,
66
- cardTypes: cardTypesResponse,
67
- };
68
- return c.json(response);
69
- });
70
-
71
- async function getCardDetails(
72
- commands: CommandManager,
73
- key: string,
74
- staticMode?: boolean,
75
- ): Promise<any> {
76
- const fetchCardDetails: ProjectFetchCardDetails = {
77
- attachments: true,
78
- children: false,
79
- content: true,
80
- contentType: 'adoc',
81
- metadata: false,
82
- parent: false,
83
- location: CardLocation.projectOnly,
84
- };
85
-
86
- let cardDetailsResponse: Card | undefined;
87
39
  try {
88
- cardDetailsResponse = await commands.showCmd.showCardDetails(
89
- fetchCardDetails,
90
- key,
91
- );
92
- } catch {
93
- return { status: 400, message: `Card ${key} not found from project` };
94
- }
95
-
96
- if (!cardDetailsResponse) {
97
- return { status: 400, message: `Card ${key} not found from project` };
98
- }
99
-
100
- let asciidocContent = '';
101
- try {
102
- asciidocContent = await evaluateMacros(
103
- cardDetailsResponse.content || '',
104
- {
105
- mode: staticMode ? 'static' : 'inject',
106
- project: commands.project,
107
- cardKey: key,
108
- },
109
- commands.calculateCmd,
110
- );
40
+ const response = await cardService.getProjectInfo(commands);
41
+ return c.json(response);
111
42
  } catch (error) {
112
- asciidocContent = `Macro error: ${error instanceof Error ? error.message : 'Unknown error'}\n\n${asciidocContent}`;
113
- }
114
-
115
- const htmlContent = Processor()
116
- .convert(asciidocContent, {
117
- safe: 'safe',
118
- attributes: {
119
- imagesdir: `/api/cards/${key}/a`,
120
- icons: 'font',
121
- },
122
- })
123
- .toString();
124
-
125
- // always parse for now if not in export mode
126
- if (!staticMode) {
127
- await commands.calculateCmd.generate();
128
- }
129
-
130
- const card = staticMode
131
- ? await getCardQueryResult(commands.project.basePath, key)
132
- : await commands.calculateCmd.runQuery('card', {
133
- cardKey: key,
134
- });
135
- if (card.length !== 1) {
136
- throw new Error('Query failed. Check card-query syntax');
43
+ return c.text(
44
+ `${error instanceof Error ? error.message : 'Unknown error'} from path ${c.get('projectPath')}`,
45
+ 500,
46
+ );
137
47
  }
138
-
139
- return {
140
- status: 200,
141
- data: {
142
- ...card[0],
143
- rawContent: cardDetailsResponse.content || '',
144
- parsedContent: htmlContent,
145
- attachments: cardDetailsResponse.attachments,
146
- },
147
- };
148
- }
48
+ });
149
49
 
150
50
  /**
151
51
  * @swagger
@@ -170,16 +70,8 @@ router.get(
170
70
  '/:key',
171
71
  ssgParams(async (c: Context) => {
172
72
  const commands = c.get('commands');
173
- const fetchedCards = await commands.showCmd.showCards(
174
- CardLocation.projectOnly,
175
- );
176
- const projectCards = fetchedCards.find(
177
- (cardContainer) => cardContainer.type === 'project',
178
- );
179
- if (!projectCards) {
180
- throw new Error('Data handler did not return project cards');
181
- }
182
- return projectCards.cards.map((key) => ({ key }));
73
+ const cards = await cardService.getAllCards(commands);
74
+ return cards.map((key) => ({ key }));
183
75
  }),
184
76
  async (c) => {
185
77
  const key = c.req.param('key');
@@ -243,70 +135,23 @@ router.patch('/:key', async (c) => {
243
135
  }
244
136
 
245
137
  const body = await c.req.json();
246
- let successes = 0;
247
- const errors = [];
248
138
 
249
- if (body.state) {
250
- try {
251
- await commands.transitionCmd.cardTransition(key, body.state);
252
- successes++;
253
- } catch (error) {
254
- if (error instanceof Error) errors.push(error.message);
255
- }
256
- }
257
-
258
- if (body.content != null) {
259
- try {
260
- await commands.editCmd.editCardContent(key, body.content);
261
- successes++;
262
- } catch (error) {
263
- if (error instanceof Error) errors.push(error.message);
264
- }
265
- }
266
-
267
- if (body.metadata) {
268
- for (const [metadataKey, metadataValue] of Object.entries(body.metadata)) {
269
- const value = metadataValue as MetadataContent;
270
-
271
- try {
272
- await commands.editCmd.editCardMetadata(key, metadataKey, value);
273
- successes++;
274
- } catch (error) {
275
- if (error instanceof Error) errors.push(error.message);
276
- }
277
- }
278
- }
279
-
280
- if (body.parent) {
281
- try {
282
- await commands.moveCmd.moveCard(key, body.parent);
283
- successes++;
284
- } catch (error) {
285
- if (error instanceof Error) errors.push(error.message);
286
- }
287
- }
288
- if (body.index != null) {
289
- try {
290
- await commands.moveCmd.rankByIndex(key, body.index);
291
- successes++;
292
- } catch (error) {
293
- if (error instanceof Error) errors.push(error.message);
139
+ try {
140
+ const result = await cardService.updateCard(commands, key, body);
141
+ if (result.status === 200) {
142
+ return c.json(result.data);
143
+ } else {
144
+ return c.json(
145
+ {
146
+ error: result.message || 'Unknown error',
147
+ },
148
+ result.status as ContentfulStatusCode,
149
+ );
294
150
  }
295
- }
296
-
297
- if (errors.length > 0) {
298
- return c.text(errors.join('\n'), 400);
299
- }
300
-
301
- const result = await getCardDetails(commands, key);
302
- if (result.status === 200) {
303
- return c.json(result.data);
304
- } else {
305
- return c.json(
306
- {
307
- error: result.message || 'Unknown error',
308
- },
309
- result.status as ContentfulStatusCode,
151
+ } catch (error) {
152
+ return c.text(
153
+ error instanceof Error ? error.message : 'Unknown error',
154
+ 400,
310
155
  );
311
156
  }
312
157
  });
@@ -339,7 +184,7 @@ router.delete('/:key', async (c) => {
339
184
  }
340
185
 
341
186
  try {
342
- await commands.removeCmd.remove('card', key);
187
+ await cardService.deleteCard(commands, key);
343
188
  return new Response(null, { status: 204 });
344
189
  } catch (error) {
345
190
  return c.json(
@@ -386,13 +231,11 @@ router.post('/:key', async (c) => {
386
231
  }
387
232
 
388
233
  try {
389
- const result = await c
390
- .get('commands')
391
- .createCmd.createCard(body.template, key === 'root' ? undefined : key);
392
-
393
- if (result.length === 0) {
394
- return c.json({ error: 'No cards created' }, 400);
395
- }
234
+ const result = await cardService.createCard(
235
+ c.get('commands'),
236
+ body.template,
237
+ key,
238
+ );
396
239
  return c.json(result);
397
240
  } catch (error) {
398
241
  if (error instanceof Error) {
@@ -443,23 +286,12 @@ router.post('/:key/attachments', async (c) => {
443
286
  return c.json({ error: 'No files uploaded' }, 400);
444
287
  }
445
288
 
446
- const succeeded = [];
447
- for (const file of files) {
448
- if (file instanceof File) {
449
- const buffer = await file.arrayBuffer();
450
- await commands.createCmd.createAttachment(
451
- key,
452
- file.name,
453
- Buffer.from(buffer),
454
- );
455
- succeeded.push(file.name);
456
- }
457
- }
458
-
459
- return c.json({
460
- message: 'Attachments uploaded successfully',
461
- files: succeeded,
462
- });
289
+ const result = await cardService.uploadAttachments(
290
+ commands,
291
+ key,
292
+ files as File[],
293
+ );
294
+ return c.json(result);
463
295
  } catch (error) {
464
296
  return c.json(
465
297
  {
@@ -502,8 +334,8 @@ router.delete('/:key/attachments/:filename', async (c) => {
502
334
  const { key, filename } = c.req.param();
503
335
 
504
336
  try {
505
- await commands.removeCmd.remove('attachment', key, filename);
506
- return c.json({ message: 'Attachment removed successfully' });
337
+ const result = await cardService.removeAttachment(commands, key, filename);
338
+ return c.json(result);
507
339
  } catch (error) {
508
340
  return c.json(
509
341
  {
@@ -546,8 +378,8 @@ router.post('/:key/attachments/:filename/open', async (c) => {
546
378
  const { key, filename } = c.req.param();
547
379
 
548
380
  try {
549
- await commands.showCmd.openAttachment(key, filename);
550
- return c.json({ message: 'Attachment opened successfully' });
381
+ const result = await cardService.openAttachment(commands, key, filename);
382
+ return c.json(result);
551
383
  } catch (error) {
552
384
  return c.json(
553
385
  {
@@ -596,33 +428,8 @@ router.post('/:key/parse', async (c) => {
596
428
  }
597
429
 
598
430
  try {
599
- let asciidocContent = '';
600
- try {
601
- asciidocContent = await evaluateMacros(
602
- content,
603
- {
604
- mode: 'inject',
605
- project: commands.project,
606
- cardKey: key,
607
- },
608
- commands.calculateCmd,
609
- );
610
- } catch (error) {
611
- asciidocContent = `Macro error: ${error instanceof Error ? error.message : 'Unknown error'}\n\n${content}`;
612
- }
613
-
614
- const processor = Processor();
615
- const parsedContent = processor
616
- .convert(asciidocContent, {
617
- safe: 'safe',
618
- attributes: {
619
- imagesdir: `/api/cards/${key}/a`,
620
- icons: 'font',
621
- },
622
- })
623
- .toString();
624
-
625
- return c.json({ parsedContent });
431
+ const result = await cardService.parseContent(commands, key, content);
432
+ return c.json(result);
626
433
  } catch (error) {
627
434
  return c.json(
628
435
  {
@@ -675,8 +482,14 @@ router.post('/:key/links', async (c) => {
675
482
  }
676
483
 
677
484
  try {
678
- await commands.createCmd.createLink(key, toCard, linkType, description);
679
- return c.json({ message: 'Link created successfully' });
485
+ const result = await cardService.createLink(
486
+ commands,
487
+ key,
488
+ toCard,
489
+ linkType,
490
+ description,
491
+ );
492
+ return c.json(result);
680
493
  } catch (error) {
681
494
  return c.json(
682
495
  {
@@ -728,8 +541,14 @@ router.delete('/:key/links', async (c) => {
728
541
  }
729
542
 
730
543
  try {
731
- await commands.removeCmd.remove('link', key, toCard, linkType, description);
732
- return c.json({ message: 'Link removed successfully' });
544
+ const result = await cardService.removeLink(
545
+ commands,
546
+ key,
547
+ toCard,
548
+ linkType,
549
+ description,
550
+ );
551
+ return c.json(result);
733
552
  } catch (error) {
734
553
  return c.json(
735
554
  {
@@ -768,11 +587,7 @@ router.get(
768
587
  '/:key/a/:attachment',
769
588
  ssgParams(async (c: Context) => {
770
589
  const commands = c.get('commands');
771
- const attachments = await commands.showCmd.showAttachments();
772
- return attachments.map((attachment) => ({
773
- key: attachment.card,
774
- attachment: attachment.fileName,
775
- }));
590
+ return await cardService.getAllAttachments(commands);
776
591
  }),
777
592
  async (c) => {
778
593
  const commands = c.get('commands');
@@ -784,18 +599,12 @@ router.get(
784
599
  }
785
600
 
786
601
  try {
787
- const attachmentResponse = await commands.showCmd.showAttachment(
602
+ const attachmentResponse = await cardService.getAttachment(
603
+ commands,
788
604
  key,
789
605
  filename,
790
606
  );
791
-
792
- if (!attachmentResponse) {
793
- return c.text(
794
- `No attachment found from card ${key} and filename ${filename}`,
795
- 404,
796
- );
797
- }
798
-
607
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
799
608
  const payload = attachmentResponse as any;
800
609
 
801
610
  return new Response(payload.fileBuffer, {
@@ -805,10 +614,13 @@ router.get(
805
614
  'Cache-Control': 'no-store',
806
615
  },
807
616
  });
808
- } catch {
617
+ } catch (error) {
809
618
  return c.json(
810
619
  {
811
- error: `No attachment found from card ${key} and filename ${filename}`,
620
+ error:
621
+ error instanceof Error
622
+ ? error.message
623
+ : `No attachment found from card ${key} and filename ${filename}`,
812
624
  },
813
625
  404,
814
626
  );
@@ -0,0 +1,103 @@
1
+ /**
2
+ Cyberismo
3
+ Copyright © Cyberismo Ltd and contributors 2025
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU Affero General Public License version 3 as published by
6
+ the Free Software Foundation.
7
+ This program is distributed in the hope that it will be useful, but WITHOUT
8
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
10
+ details. You should have received a copy of the GNU Affero General Public
11
+ License along with this program. If not, see <https://www.gnu.org/licenses/>.
12
+ */
13
+
14
+ import Processor from '@asciidoctor/core';
15
+ import {
16
+ type Card,
17
+ CardLocation,
18
+ type ProjectFetchCardDetails,
19
+ } from '@cyberismo/data-handler/interfaces/project-interfaces';
20
+ import { type CommandManager, evaluateMacros } from '@cyberismo/data-handler';
21
+ import { getCardQueryResult } from '../../export.js';
22
+
23
+ interface result {
24
+ status: number;
25
+ message?: string;
26
+ data?: object;
27
+ }
28
+
29
+ export async function getCardDetails(
30
+ commands: CommandManager,
31
+ key: string,
32
+ staticMode?: boolean,
33
+ ): Promise<result> {
34
+ const fetchCardDetails: ProjectFetchCardDetails = {
35
+ attachments: true,
36
+ children: false,
37
+ content: true,
38
+ contentType: 'adoc',
39
+ metadata: false,
40
+ parent: false,
41
+ location: CardLocation.all,
42
+ };
43
+
44
+ let cardDetailsResponse: Card | undefined;
45
+ try {
46
+ cardDetailsResponse = await commands.showCmd.showCardDetails(
47
+ fetchCardDetails,
48
+ key,
49
+ );
50
+ } catch {
51
+ return { status: 400, message: `Card ${key} not found from project` };
52
+ }
53
+
54
+ if (!cardDetailsResponse) {
55
+ return { status: 400, message: `Card ${key} not found from project` };
56
+ }
57
+
58
+ // always parse for now if not in export mode
59
+ if (!staticMode) {
60
+ await commands.calculateCmd.generate();
61
+ }
62
+
63
+ let asciidocContent = '';
64
+ try {
65
+ asciidocContent = await evaluateMacros(cardDetailsResponse.content || '', {
66
+ context: staticMode ? 'exportedSite' : 'localApp',
67
+ mode: staticMode ? 'staticSite' : 'inject',
68
+ project: commands.project,
69
+ cardKey: key,
70
+ });
71
+ } catch (error) {
72
+ asciidocContent = `Macro error: ${error instanceof Error ? error.message : 'Unknown error'}\n\n${asciidocContent}`;
73
+ }
74
+
75
+ const htmlContent = Processor()
76
+ .convert(asciidocContent, {
77
+ safe: 'safe',
78
+ attributes: {
79
+ imagesdir: `/api/cards/${key}/a`,
80
+ icons: 'font',
81
+ },
82
+ })
83
+ .toString();
84
+
85
+ const card = staticMode
86
+ ? await getCardQueryResult(commands.project.basePath, key)
87
+ : await commands.calculateCmd.runQuery('card', 'localApp', {
88
+ cardKey: key,
89
+ });
90
+ if (card.length !== 1) {
91
+ throw new Error('Query failed. Check card-query syntax');
92
+ }
93
+
94
+ return {
95
+ status: 200,
96
+ data: {
97
+ ...card[0],
98
+ rawContent: cardDetailsResponse.content || '',
99
+ parsedContent: htmlContent,
100
+ attachments: cardDetailsResponse.attachments,
101
+ },
102
+ };
103
+ }