@akanjs/devkit 1.0.20 → 2.1.0-rc.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.
Files changed (195) hide show
  1. package/README.ko.md +65 -0
  2. package/README.md +62 -6
  3. package/aiEditor.ts +304 -0
  4. package/akanApp/akanApp.host.ts +393 -0
  5. package/akanApp/index.ts +1 -0
  6. package/akanConfig/akanConfig.test.ts +236 -0
  7. package/akanConfig/akanConfig.ts +384 -0
  8. package/akanConfig/index.ts +2 -0
  9. package/akanConfig/types.ts +23 -0
  10. package/applicationBuildReporter.ts +69 -0
  11. package/applicationBuildRunner.ts +302 -0
  12. package/applicationReleasePackager.ts +206 -0
  13. package/artifact/implicitRootLayout.ts +155 -0
  14. package/artifact/index.ts +1 -0
  15. package/artifact/routeSeedIndex.test.ts +98 -0
  16. package/artifact/routeSeedIndex.ts +130 -0
  17. package/auth.ts +41 -0
  18. package/builder.ts +164 -0
  19. package/capacitor.base.config.ts +88 -0
  20. package/capacitorApp.ts +440 -0
  21. package/commandDecorators/argMeta.ts +102 -0
  22. package/commandDecorators/command.ts +351 -0
  23. package/commandDecorators/commandBuilder.ts +224 -0
  24. package/commandDecorators/commandDecorators.test.ts +212 -0
  25. package/commandDecorators/commandMeta.ts +7 -0
  26. package/commandDecorators/dependencyBuilder.ts +100 -0
  27. package/{esm/src/commandDecorators/helpFormatter.js → commandDecorators/helpFormatter.ts} +100 -47
  28. package/{esm/src/commandDecorators/index.js → commandDecorators/index.ts} +4 -2
  29. package/commandDecorators/targetMeta.ts +31 -0
  30. package/commandDecorators/types.ts +10 -0
  31. package/constants.ts +25 -0
  32. package/createTunnel.ts +36 -0
  33. package/dependencyScanner.ts +357 -0
  34. package/devkitUtils.test.ts +259 -0
  35. package/executors.test.ts +315 -0
  36. package/executors.ts +1390 -0
  37. package/{esm/src/extractDeps.js → extractDeps.ts} +26 -20
  38. package/{esm/src/fileEditor.js → fileEditor.ts} +51 -32
  39. package/fileSys.ts +39 -0
  40. package/frontendBuild/allRoutesBuilder.ts +103 -0
  41. package/frontendBuild/buildRouteClient.test.ts +190 -0
  42. package/frontendBuild/clientBuildTypes.ts +114 -0
  43. package/frontendBuild/clientEntriesBundler.ts +303 -0
  44. package/frontendBuild/clientEntryDiscovery.ts +199 -0
  45. package/frontendBuild/csrArtifactBuilder.ts +237 -0
  46. package/frontendBuild/cssCompiler.ts +286 -0
  47. package/frontendBuild/cssImportResolver.ts +116 -0
  48. package/frontendBuild/fontOptimizer.ts +427 -0
  49. package/frontendBuild/frontendBuild.test.ts +204 -0
  50. package/frontendBuild/hmrChangeClassifier.ts +28 -0
  51. package/frontendBuild/hmrWatcher.ts +102 -0
  52. package/frontendBuild/index.ts +18 -0
  53. package/frontendBuild/pagesBundleBuilder.ts +137 -0
  54. package/frontendBuild/pagesEntrySourceGenerator.ts +37 -0
  55. package/frontendBuild/precompressArtifacts.ts +59 -0
  56. package/frontendBuild/routeClientBuilder.ts +290 -0
  57. package/frontendBuild/routesManifestArtifactSerializer.ts +62 -0
  58. package/frontendBuild/ssrBaseArtifactBuilder.ts +139 -0
  59. package/frontendBuild/vendorSpecifiers.ts +16 -0
  60. package/frontendBuild/watchRootResolver.ts +28 -0
  61. package/getCredentials.ts +19 -0
  62. package/getDirname.ts +3 -0
  63. package/getModelFileData.ts +59 -0
  64. package/getRelatedCnsts.ts +313 -0
  65. package/guideline.ts +19 -0
  66. package/incrementalBuilder/incrementalBuilder.host.test.ts +51 -0
  67. package/incrementalBuilder/incrementalBuilder.host.ts +152 -0
  68. package/incrementalBuilder/incrementalBuilder.proc.ts +331 -0
  69. package/incrementalBuilder/index.ts +1 -0
  70. package/{esm/src/index.js → index.ts} +28 -15
  71. package/lint/no-deep-internal-import.grit +25 -0
  72. package/lint/no-import-client-functions.grit +32 -0
  73. package/lint/no-import-external-library.grit +21 -0
  74. package/lint/no-js-private-class-method.grit +42 -0
  75. package/lint/no-use-client-in-server.grit +7 -0
  76. package/lint/non-scalar-props-restricted.grit +13 -0
  77. package/linter.ts +271 -0
  78. package/mobile/index.ts +1 -0
  79. package/mobile/mobileTarget.test.ts +53 -0
  80. package/mobile/mobileTarget.ts +88 -0
  81. package/package.json +48 -31
  82. package/prompter.ts +72 -0
  83. package/scanInfo.ts +606 -0
  84. package/selectModel.ts +11 -0
  85. package/{esm/src/spinner.js → spinner.ts} +22 -28
  86. package/{esm/src/capacitorApp.js → src/capacitorApp.ts} +82 -81
  87. package/sshTunnel.ts +152 -0
  88. package/{esm/src/streamAi.js → streamAi.ts} +18 -12
  89. package/transforms/barrelAnalyzer.ts +278 -0
  90. package/transforms/barrelImportsPlugin.ts +504 -0
  91. package/transforms/externalizeFrameworkPlugin.ts +185 -0
  92. package/transforms/index.ts +5 -0
  93. package/transforms/rscUseClientTransform.ts +59 -0
  94. package/transforms/transforms.test.ts +208 -0
  95. package/transforms/useClientBundlePlugin.ts +47 -0
  96. package/tsconfig.json +37 -0
  97. package/typeChecker.ts +264 -0
  98. package/types.ts +44 -0
  99. package/ui/MultiScrollList.tsx +242 -0
  100. package/ui/ScrollList.tsx +107 -0
  101. package/ui/index.ts +2 -0
  102. package/{esm/src/uploadRelease.js → uploadRelease.ts} +50 -34
  103. package/{esm/src/useStdoutDimensions.js → useStdoutDimensions.ts} +5 -5
  104. package/cjs/index.js +0 -21
  105. package/cjs/src/aiEditor.js +0 -311
  106. package/cjs/src/auth.js +0 -72
  107. package/cjs/src/builder.js +0 -114
  108. package/cjs/src/capacitorApp.js +0 -313
  109. package/cjs/src/commandDecorators/argMeta.js +0 -88
  110. package/cjs/src/commandDecorators/command.js +0 -324
  111. package/cjs/src/commandDecorators/commandMeta.js +0 -30
  112. package/cjs/src/commandDecorators/helpFormatter.js +0 -211
  113. package/cjs/src/commandDecorators/index.js +0 -31
  114. package/cjs/src/commandDecorators/targetMeta.js +0 -57
  115. package/cjs/src/commandDecorators/types.js +0 -15
  116. package/cjs/src/constants.js +0 -46
  117. package/cjs/src/createTunnel.js +0 -49
  118. package/cjs/src/dependencyScanner.js +0 -220
  119. package/cjs/src/executors.js +0 -964
  120. package/cjs/src/extractDeps.js +0 -103
  121. package/cjs/src/fileEditor.js +0 -120
  122. package/cjs/src/getCredentials.js +0 -44
  123. package/cjs/src/getDirname.js +0 -38
  124. package/cjs/src/getModelFileData.js +0 -66
  125. package/cjs/src/getRelatedCnsts.js +0 -260
  126. package/cjs/src/guideline.js +0 -15
  127. package/cjs/src/index.js +0 -65
  128. package/cjs/src/linter.js +0 -238
  129. package/cjs/src/prompter.js +0 -85
  130. package/cjs/src/scanInfo.js +0 -491
  131. package/cjs/src/selectModel.js +0 -46
  132. package/cjs/src/spinner.js +0 -93
  133. package/cjs/src/streamAi.js +0 -62
  134. package/cjs/src/typeChecker.js +0 -207
  135. package/cjs/src/types.js +0 -15
  136. package/cjs/src/uploadRelease.js +0 -112
  137. package/cjs/src/useStdoutDimensions.js +0 -43
  138. package/esm/index.js +0 -1
  139. package/esm/src/aiEditor.js +0 -282
  140. package/esm/src/auth.js +0 -42
  141. package/esm/src/builder.js +0 -81
  142. package/esm/src/commandDecorators/argMeta.js +0 -54
  143. package/esm/src/commandDecorators/command.js +0 -290
  144. package/esm/src/commandDecorators/commandMeta.js +0 -7
  145. package/esm/src/commandDecorators/targetMeta.js +0 -33
  146. package/esm/src/commandDecorators/types.js +0 -0
  147. package/esm/src/constants.js +0 -17
  148. package/esm/src/createTunnel.js +0 -26
  149. package/esm/src/dependencyScanner.js +0 -187
  150. package/esm/src/executors.js +0 -928
  151. package/esm/src/getCredentials.js +0 -11
  152. package/esm/src/getDirname.js +0 -5
  153. package/esm/src/getModelFileData.js +0 -33
  154. package/esm/src/getRelatedCnsts.js +0 -221
  155. package/esm/src/guideline.js +0 -0
  156. package/esm/src/linter.js +0 -205
  157. package/esm/src/prompter.js +0 -51
  158. package/esm/src/scanInfo.js +0 -455
  159. package/esm/src/selectModel.js +0 -13
  160. package/esm/src/typeChecker.js +0 -174
  161. package/esm/src/types.js +0 -0
  162. package/index.d.ts +0 -1
  163. package/src/aiEditor.d.ts +0 -50
  164. package/src/auth.d.ts +0 -9
  165. package/src/builder.d.ts +0 -18
  166. package/src/capacitorApp.d.ts +0 -39
  167. package/src/commandDecorators/argMeta.d.ts +0 -67
  168. package/src/commandDecorators/command.d.ts +0 -2
  169. package/src/commandDecorators/commandMeta.d.ts +0 -2
  170. package/src/commandDecorators/helpFormatter.d.ts +0 -3
  171. package/src/commandDecorators/index.d.ts +0 -6
  172. package/src/commandDecorators/targetMeta.d.ts +0 -19
  173. package/src/commandDecorators/types.d.ts +0 -1
  174. package/src/constants.d.ts +0 -26
  175. package/src/createTunnel.d.ts +0 -8
  176. package/src/dependencyScanner.d.ts +0 -23
  177. package/src/executors.d.ts +0 -296
  178. package/src/extractDeps.d.ts +0 -7
  179. package/src/fileEditor.d.ts +0 -16
  180. package/src/getCredentials.d.ts +0 -12
  181. package/src/getDirname.d.ts +0 -1
  182. package/src/getModelFileData.d.ts +0 -16
  183. package/src/getRelatedCnsts.d.ts +0 -53
  184. package/src/guideline.d.ts +0 -19
  185. package/src/index.d.ts +0 -23
  186. package/src/linter.d.ts +0 -109
  187. package/src/prompter.d.ts +0 -14
  188. package/src/scanInfo.d.ts +0 -82
  189. package/src/selectModel.d.ts +0 -1
  190. package/src/spinner.d.ts +0 -20
  191. package/src/streamAi.d.ts +0 -6
  192. package/src/typeChecker.d.ts +0 -52
  193. package/src/types.d.ts +0 -31
  194. package/src/uploadRelease.d.ts +0 -10
  195. package/src/useStdoutDimensions.d.ts +0 -1
@@ -0,0 +1,242 @@
1
+ "use client";
2
+ import { Box, Text, useInput } from "ink";
3
+ import { useEffect, useState } from "react";
4
+ import { useStdoutDimensions } from "../useStdoutDimensions";
5
+
6
+ interface MultiScrollListProps {
7
+ logList: {
8
+ title: string;
9
+ logs: {
10
+ type: string;
11
+ content: string;
12
+ }[];
13
+ color: string;
14
+ }[];
15
+
16
+ maxLength?: number;
17
+ }
18
+
19
+ /**
20
+ * @param logList 로그 목록
21
+ * @param maxLength 최대 로그 길이 (기본 100)
22
+ */
23
+ const HEADER_HEIGHT = 1;
24
+ const FOOTER_HEIGHT = 1;
25
+ const OUTER_BORDER_HEIGHT = 2;
26
+ const BORDER_HEIGHT = 2;
27
+ const ANSI_ESCAPE_RE = new RegExp(`${String.fromCharCode(27)}(?:[@-Z\\\\-_]|\\[[\\s\\S]*?[@-~])`, "g");
28
+
29
+ export const MultiScrollList = ({ logList, maxLength = 100 }: MultiScrollListProps) => {
30
+ // 창 너비, 높이
31
+ const [width, height] = useStdoutDimensions();
32
+ // 탭별 로그 렌더링
33
+
34
+ const [focusLog, setFocusLog] = useState<{ type: string; content: string }[]>([]);
35
+ // 탭별 로그 길이 저장 (스크롤시 로그 길이 변화로 위치 조정)
36
+ const [lengthMap, setLengthMap] = useState<Map<number, number>>(new Map());
37
+ // 스크롤 위치
38
+ const [scrollPos, setScrollPos] = useState(0);
39
+ // 현재 포커싱탭 인덱스
40
+ const [tabIndex, setTabIndex] = useState<number>(0);
41
+ // 스크롤 실행 여부
42
+ const [isRunning, setIsRunning] = useState(false);
43
+ // 박스 높이 (보더 사이즈 2, 헤더 사이즈 1, 푸터 사이즈 5 기본 1)
44
+ const [boxHeight, setBoxHeight] = useState(
45
+ height - HEADER_HEIGHT - OUTER_BORDER_HEIGHT - FOOTER_HEIGHT - BORDER_HEIGHT,
46
+ );
47
+ const boxWidth = width - 27;
48
+
49
+ // maxLength에 따라 로그 배열을 제한하는 유틸리티 함수
50
+ const getLimitedLogs = (logs: { type: string; content: string }[]) => {
51
+ const sortedLogs = logs.reduce<{ type: string; content: string }[]>((acc, log) => {
52
+ // log.content.length가 boxWidth보다 큰 경우 잘라서 줄 수 만큼 추가
53
+ // ANSI 코드 보관
54
+
55
+ const content = log.content.replace(ANSI_ESCAPE_RE, "");
56
+ if (content.length > boxWidth) {
57
+ const lines = Math.ceil(content.length / boxWidth);
58
+ for (let i = 0; i < lines; i++) {
59
+ acc.push({ type: log.type, content: content.slice(i * boxWidth, (i + 1) * boxWidth) });
60
+ }
61
+ } else {
62
+ acc.push(log);
63
+ }
64
+ return acc;
65
+ }, []);
66
+ return sortedLogs.length > maxLength ? sortedLogs.slice(sortedLogs.length - maxLength) : sortedLogs;
67
+ };
68
+
69
+ // 입력 이벤트 처리
70
+ useInput((input, key) => {
71
+ // 탭 키 이벤트 처리(포커싱 탭 변경)
72
+ if (key.tab) {
73
+ setTabIndex((prev: number) => (prev + 1) % logList.length);
74
+ setScrollPos(0);
75
+ setIsRunning(false);
76
+ }
77
+ // 스크롤 중지 이벤트 처리 (포커싱까지 완전히 종료)
78
+ if (key.escape) {
79
+ setScrollPos(0);
80
+ setIsRunning(false);
81
+ }
82
+ // 스크롤 중지 이벤트 처리 (포커싱 유지)
83
+ if (input === " ") {
84
+ setScrollPos(0);
85
+ setIsRunning(false);
86
+ }
87
+ // 스크롤 다운 이벤트 처리
88
+ if (key.downArrow && scrollPos > 0) {
89
+ if (key.shift) {
90
+ const newScrollPos = scrollPos - 10;
91
+ // 스크롤 최소 위치에 도달 경우에 대한 예외 처리
92
+ if (newScrollPos < 0) {
93
+ setScrollPos(0);
94
+ } else {
95
+ setScrollPos(newScrollPos);
96
+ }
97
+ } else {
98
+ const newScrollPos = scrollPos - 1;
99
+ setScrollPos(newScrollPos);
100
+ }
101
+ }
102
+ // 스크롤 업 이벤트 처리
103
+ if (key.upArrow && scrollPos < logList[tabIndex].logs.length - boxHeight) {
104
+ const limitedLogs = getLimitedLogs(logList[tabIndex].logs);
105
+ if (scrollPos < limitedLogs.length - boxHeight) {
106
+ // 스크롤 업 이벤트 처리 (스크롤 속도 증가)
107
+ if (key.shift) {
108
+ const newScrollPos = scrollPos + 10;
109
+ // 스크롤 최대 위치에 도달 경우에 대한 예외 처리
110
+ if (newScrollPos > limitedLogs.length - boxHeight) {
111
+ setScrollPos(limitedLogs.length - boxHeight);
112
+ } else {
113
+ setScrollPos(newScrollPos);
114
+ }
115
+ } else {
116
+ setScrollPos(scrollPos + 1);
117
+ }
118
+ if (!isRunning) setIsRunning(true);
119
+ }
120
+ }
121
+ });
122
+
123
+ useEffect(() => {
124
+ // 공통 로직을 함수로 추출
125
+ const getLogsToRender = (logs: { type: string; content: string }[], index: number) => {
126
+ // maxLength에 따라 로그 제한
127
+ const limitedLogs = getLimitedLogs(logs);
128
+ // 로그 중 boxWidth보다 긴 것이 있는 경우 잘라서 출력
129
+
130
+ // 활성 탭이고 스크롤 중인 특별한 경우
131
+ if (scrollPos > 0 && tabIndex === index) {
132
+ return limitedLogs.slice(limitedLogs.length - boxHeight - scrollPos, limitedLogs.length - scrollPos);
133
+ }
134
+ // 로그가 표시 영역보다 큰 경우 (공통 로직)
135
+ else if (limitedLogs.length > boxHeight) {
136
+ return limitedLogs.slice(limitedLogs.length - boxHeight, limitedLogs.length);
137
+ }
138
+ // 로그가 표시 영역에 모두 들어가는 경우 (공통 로직)
139
+ else {
140
+ return limitedLogs;
141
+ }
142
+ };
143
+
144
+ // isRunning일 때 로직
145
+ if (isRunning) {
146
+ // 선택된 탭의 로그 길이 변화 확인 및 스크롤 포지션 업데이트
147
+ if (lengthMap.has(tabIndex)) {
148
+ const tabLength = lengthMap.get(tabIndex);
149
+ const limitedLogsLength = Math.min(logList[tabIndex].logs.length, maxLength);
150
+ if (tabLength && tabLength < limitedLogsLength) {
151
+ setScrollPos(scrollPos + 1);
152
+ lengthMap.set(tabIndex, limitedLogsLength);
153
+ }
154
+ }
155
+
156
+ // 스크롤 위치에 따른 로그 렌더링 업데이트
157
+
158
+ setFocusLog(getLogsToRender(logList[tabIndex].logs, tabIndex));
159
+ }
160
+ // isRunning이 아닐 때 로직
161
+ else {
162
+ // lengthMap 업데이트 및 초기 렌더링
163
+ setFocusLog(getLogsToRender(logList[tabIndex].logs, tabIndex));
164
+ }
165
+ }, [logList, isRunning, scrollPos, tabIndex, boxHeight, maxLength]);
166
+
167
+ useEffect(() => {
168
+ setBoxHeight(height - HEADER_HEIGHT - OUTER_BORDER_HEIGHT - FOOTER_HEIGHT - BORDER_HEIGHT);
169
+ }, [height]);
170
+
171
+ // 초기 로그 사이즈 설정
172
+ useEffect(() => {
173
+ setLengthMap(new Map(logList.map((log, index) => [index, Math.min(log.logs.length, maxLength)])));
174
+ }, [logList, maxLength]);
175
+
176
+ return (
177
+ <Box width={width} height={height} borderStyle="round" borderColor="blackBright" flexDirection="column">
178
+ <Box width={"100%"} height={boxHeight + BORDER_HEIGHT + HEADER_HEIGHT} flexDirection="row">
179
+ <Box width={30} height="100%" flexDirection="column">
180
+ <Box>
181
+ <Text>
182
+ List {tabIndex + 1}/{logList.length}
183
+ </Text>
184
+ </Box>
185
+ <Box borderStyle="round" borderColor="blackBright" width={"100%"} height="100%" flexDirection="column">
186
+ {logList.map((log, index) => {
187
+ return (
188
+ <Text key={index} color={index === tabIndex ? "green" : "white"}>
189
+ <Text>●</Text>&nbsp;
190
+ {log.title.length > 25 ? `${log.title.slice(0, 25)}...` : log.title}
191
+ </Text>
192
+ );
193
+ })}
194
+ </Box>
195
+ </Box>
196
+ <Box width={"100%"} height="100%" flexDirection="column">
197
+ <Box height={1}>
198
+ <Text color={logList[tabIndex].color}>
199
+ {logList[tabIndex].title} {logList[tabIndex].logs.length}
200
+ </Text>
201
+ </Box>
202
+ <Box
203
+ borderStyle={isRunning ? "double" : "round"}
204
+ flexDirection="column"
205
+ borderColor={logList[tabIndex].color}
206
+ width="100%"
207
+ height="100%"
208
+ >
209
+ {scrollPos > 0 ? (
210
+ <>
211
+ {focusLog.slice(0, focusLog.length - 1).map((log, index) => {
212
+ return (
213
+ <Text underline={false} color={log.type === "error" ? "red" : "white"} key={index}>
214
+ {log.content}
215
+ </Text>
216
+ );
217
+ })}
218
+ <Text underline={false} backgroundColor="green">
219
+ Scrolling... +{scrollPos}
220
+ </Text>
221
+ </>
222
+ ) : (
223
+ focusLog.map((log, index) => {
224
+ return (
225
+ <Text underline={false} color={log.type === "error" ? "red" : "white"} key={index}>
226
+ {log.content}
227
+ </Text>
228
+ );
229
+ })
230
+ )}
231
+ </Box>
232
+ </Box>
233
+ </Box>
234
+ {/* <Text>{renderMultiLogs[tabIndex][0]}</Text> */}
235
+ <Box width={"100%"} height={FOOTER_HEIGHT}>
236
+ <Text dimColor={true}>
237
+ Tab : switch tab | Up / Down(shift : x10) : scroll | Space : back last position | Esc : stop scrolling
238
+ </Text>
239
+ </Box>
240
+ </Box>
241
+ );
242
+ };
@@ -0,0 +1,107 @@
1
+ "use client";
2
+ import { Box, type BoxProps, Newline, Text, useInput } from "ink";
3
+ import { type ReactNode, useEffect, useState } from "react";
4
+ import { useStdoutDimensions } from "../useStdoutDimensions";
5
+
6
+ interface ScrollListProps extends BoxProps {
7
+ list: ReactNode[];
8
+ }
9
+
10
+ export const ScrollList = ({ list, ...props }: ScrollListProps) => {
11
+ const [renderLogs, setRenderLogs] = useState<ReactNode[]>(list);
12
+ const [width, height] = useStdoutDimensions();
13
+ const [scrollPos, setScrollPos] = useState(0);
14
+ const [isRunning, setIsRunning] = useState(false);
15
+ const [boxHeight, setBoxHeight] = useState(height - 3);
16
+
17
+ useInput((input, key) => {
18
+ if (key.escape) {
19
+ setIsRunning(false);
20
+ setScrollPos(0);
21
+ }
22
+ if (input === " " && isRunning) {
23
+ setIsRunning(false);
24
+ setScrollPos(0);
25
+ }
26
+ if (key.downArrow && scrollPos > 0) {
27
+ if (key.shift) {
28
+ setScrollPos(scrollPos - 10);
29
+ } else {
30
+ setScrollPos(scrollPos - 1);
31
+ }
32
+ }
33
+ if (key.upArrow && scrollPos < list.length - boxHeight) {
34
+ if (key.shift) {
35
+ setScrollPos(scrollPos + 10);
36
+ } else {
37
+ setScrollPos(scrollPos + 1);
38
+ }
39
+ }
40
+ });
41
+
42
+ useEffect(() => {
43
+ //1 로그가 박스 높이보다 크면 스크롤 위치 조정
44
+ //2. scrollPos값에 따라 포커싱 위치 변경하고 pos 활성시 포커싱 위치 고정
45
+ if (isRunning) {
46
+ setScrollPos(scrollPos + 1);
47
+ return;
48
+ }
49
+ if (list.length > boxHeight) {
50
+ setRenderLogs(list.slice(list.length - boxHeight, list.length));
51
+ } else {
52
+ setRenderLogs(list);
53
+ }
54
+ }, [list, isRunning]);
55
+
56
+ useEffect(() => {
57
+ setBoxHeight(Math.floor(height * 0.9));
58
+ }, [height]);
59
+
60
+ useEffect(() => {
61
+ if (scrollPos > 0) {
62
+ setRenderLogs(list.slice(list.length - boxHeight - scrollPos, list.length - scrollPos));
63
+ setIsRunning(true);
64
+ } else {
65
+ setRenderLogs(list.slice(list.length - boxHeight, list.length));
66
+ setIsRunning(false);
67
+ }
68
+ }, [scrollPos]);
69
+
70
+ return (
71
+ <Box {...props} width={width} height={"100%"} flexDirection="column">
72
+ <Box borderStyle="round" width={width} height={height - 3}>
73
+ <Newline />
74
+ <Text>
75
+ {isRunning ? (
76
+ <>
77
+ {renderLogs.slice(0, renderLogs.length - 1).map((log, index) => (
78
+ <>
79
+ <Text key={index}>{log}</Text>
80
+ <Newline />
81
+ </>
82
+ ))}
83
+ <Text backgroundColor="green">scrolling... + {scrollPos}</Text>
84
+ </>
85
+ ) : (
86
+ <>
87
+ {renderLogs.map((log, index) => (
88
+ <>
89
+ <Text key={index}>{log}</Text>
90
+ <Newline />
91
+ </>
92
+ ))}
93
+ </>
94
+ )}
95
+ </Text>
96
+ </Box>
97
+ <Box>
98
+ <Text dimColor={true}>
99
+ You can use the following shortcuts:
100
+ <Newline />* <Text backgroundColor="green">up</Text> and <Text backgroundColor="green">down</Text> to scroll.{" "}
101
+ <Text backgroundColor="green">shift</Text> to scroll faster.
102
+ <Newline />* <Text backgroundColor="green">escape</Text> to stop scrolling.
103
+ </Text>
104
+ </Box>
105
+ </Box>
106
+ );
107
+ };
package/ui/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./MultiScrollList";
2
+ export * from "./ScrollList";
@@ -1,71 +1,90 @@
1
- import { Logger } from "@akanjs/common";
2
- import axios from "axios";
3
- import FormData from "form-data";
4
- import fs from "fs";
1
+ import { HttpClient, Logger } from "akanjs/common";
2
+
5
3
  import { Spinner } from "./spinner";
6
- const spinning = (message) => {
4
+
5
+ const spinning = (message: string) => {
7
6
  const spinner = new Spinner(message, { prefix: message, enableSpin: true }).start();
8
7
  return spinner;
9
8
  };
10
- const uploadRelease = async (appName, {
11
- workspaceRoot,
12
- environment,
13
- buildNum,
14
- platformVersion,
15
- os,
16
- local
17
- }) => {
9
+ export const uploadRelease = async (
10
+ appName: string,
11
+ {
12
+ workspaceRoot,
13
+ environment,
14
+ buildNum,
15
+ platformVersion,
16
+ os,
17
+ local,
18
+ }: {
19
+ workspaceRoot: string;
20
+ environment: string;
21
+ buildNum: number;
22
+ platformVersion?: string;
23
+ os?: "android" | "ios";
24
+ local?: boolean;
25
+ },
26
+ ) => {
18
27
  const logger = new Logger("uploadRelease");
19
- const basePath = local ? "http://localhost:8080/backend" : "https://cloud.akanjs.com/backend";
28
+ const basePath = local ? "http://localhost:8282/backend" : "https://cloud.akanjs.com/backend";
29
+ const httpClient = new HttpClient(basePath);
20
30
  const buildPath = `${workspaceRoot}/releases/builds/${appName}-release.tar.gz`;
21
31
  const appBuildPath = `${workspaceRoot}/releases/builds/${appName}-appBuild.zip`;
22
32
  const sourcePath = `${workspaceRoot}/releases/sources/${appName}-source.tar.gz`;
33
+
23
34
  const readingFilesSpinner = spinning("Reading files...");
24
35
  try {
25
- const build = fs.readFileSync(buildPath);
26
- const source = fs.readFileSync(sourcePath);
27
- const appBuild = fs.readFileSync(appBuildPath);
28
- const buildStat = fs.statSync(buildPath);
29
- const sourceStat = fs.statSync(sourcePath);
30
- const appBuildStat = fs.statSync(appBuildPath);
36
+ const buildFile = Bun.file(buildPath);
37
+ const sourceFile = Bun.file(sourcePath);
38
+ const appBuildFile = Bun.file(appBuildPath);
39
+ const buildStat = { mtime: new Date(buildFile.lastModified), size: buildFile.size };
40
+ const sourceStat = { mtime: new Date(sourceFile.lastModified), size: sourceFile.size };
41
+ const appBuildStat = { mtime: new Date(appBuildFile.lastModified), size: appBuildFile.size };
31
42
  readingFilesSpinner.succeed("Reading files... done");
43
+
32
44
  const preparingFormSpinner = spinning("Preparing form data...");
33
45
  const formData = new FormData();
34
- formData.append("files", build, `${appName}-release.tar.gz`);
35
- formData.append("files", source, `${appName}-source.tar.gz`);
36
- formData.append("files", appBuild, `${appName}-appBuild.zip`);
46
+ formData.append("files", buildFile, `${appName}-release.tar.gz`);
47
+ formData.append("files", sourceFile, `${appName}-source.tar.gz`);
48
+ formData.append("files", appBuildFile, `${appName}-appBuild.zip`);
37
49
  formData.append(
38
50
  "metas",
39
51
  JSON.stringify([
40
52
  { lastModifiedAt: buildStat.mtime, size: buildStat.size },
41
53
  { lastModifiedAt: sourceStat.mtime, size: sourceStat.size },
42
- { lastModifiedAt: appBuildStat.mtime, size: appBuildStat.size }
43
- ])
54
+ { lastModifiedAt: appBuildStat.mtime, size: appBuildStat.size },
55
+ ]),
44
56
  );
45
57
  formData.append("type", "release");
46
58
  preparingFormSpinner.succeed("Preparing form data... done");
59
+
47
60
  try {
48
61
  const uploadingFilesSpinner = spinning("Uploading files to server...");
49
- const [buildFile, sourceFile, appBuildFile] = (await axios.post(`${basePath}/file/addFilesRestApi`, formData)).data;
62
+ const [buildFile, sourceFile, appBuildFile] = await httpClient.post<
63
+ [{ id: string }, { id: string }, { id: string }]
64
+ >("/file/addFilesRestApi", formData);
50
65
  uploadingFilesSpinner.succeed("Uploading files to server... done");
66
+
51
67
  const fetchingAppSpinner = spinning(`Fetching dev app information for ${appName}...`);
52
68
  const major = platformVersion ? parseInt(platformVersion.split(".")[0]) : 1;
53
69
  const minor = platformVersion ? parseInt(platformVersion.split(".")[1]) : 0;
54
70
  const patch = platformVersion ? parseInt(platformVersion.split(".")[2]) : 0;
55
- const devApp = (await axios.get(`${basePath}/devApp/devAppInName/${appName}`)).data;
71
+
72
+ const devApp = await httpClient.get<{ id: string }>(`/devApp/devAppInName/${appName}`);
56
73
  fetchingAppSpinner.succeed(`Fetching dev app information for ${appName}... done`);
74
+
57
75
  const pushingReleaseSpinner = spinning(`Pushing release to ${environment} environment...`);
58
- const release = (await axios.post(
59
- `${basePath}/release/pushRelease/${devApp.id}/${environment}/${major}/${minor}/${patch}/${sourceFile.id}/${buildFile.id}/${appBuildFile.id}${os ? `/${os}` : ""}`
60
- )).data;
76
+ const release = await httpClient.post<{ id: string }>(
77
+ `/release/pushRelease/${devApp.id}/${environment}/${major}/${minor}/${patch}/${sourceFile.id}/${buildFile.id}/${appBuildFile.id}${os ? `/${os}` : ""}`,
78
+ );
61
79
  pushingReleaseSpinner.succeed(`Pushing release to ${environment} environment... done`);
62
80
  new Spinner(`Successfully pushed release to ${appName}-${environment} server. `, {
63
81
  prefix: `Successfully pushed release to ${appName}-${environment} server. `,
64
- enableSpin: false
82
+ enableSpin: false,
65
83
  }).succeed(`Successfully pushed release to ${appName}-${environment} server. `);
66
84
  return release;
67
85
  } catch (e) {
68
86
  const errorMessage = e instanceof Error ? e.message : "Unknown error";
87
+ logger.error(`Upload release failed: ${errorMessage}`);
69
88
  return null;
70
89
  }
71
90
  } catch (e) {
@@ -74,6 +93,3 @@ const uploadRelease = async (appName, {
74
93
  return null;
75
94
  }
76
95
  };
77
- export {
78
- uploadRelease
79
- };
@@ -1,9 +1,11 @@
1
1
  "use client";
2
2
  import { useStdout } from "ink";
3
3
  import { useEffect, useState } from "react";
4
- const useStdoutDimensions = () => {
4
+
5
+ export const useStdoutDimensions = (): [number, number] => {
5
6
  const { stdout } = useStdout();
6
- const [dimensions, setDimensions] = useState([stdout.columns, stdout.rows]);
7
+ const [dimensions, setDimensions] = useState<[number, number]>([stdout.columns, stdout.rows]);
8
+
7
9
  useEffect(() => {
8
10
  const handler = () => {
9
11
  setDimensions([stdout.columns, stdout.rows]);
@@ -13,8 +15,6 @@ const useStdoutDimensions = () => {
13
15
  stdout.off("resize", handler);
14
16
  };
15
17
  }, [stdout]);
18
+
16
19
  return dimensions;
17
20
  };
18
- export {
19
- useStdoutDimensions
20
- };
package/cjs/index.js DELETED
@@ -1,21 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __copyProps = (to, from, except, desc) => {
6
- if (from && typeof from === "object" || typeof from === "function") {
7
- for (let key of __getOwnPropNames(from))
8
- if (!__hasOwnProp.call(to, key) && key !== except)
9
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
10
- }
11
- return to;
12
- };
13
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
14
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
- var devkit_exports = {};
16
- module.exports = __toCommonJS(devkit_exports);
17
- __reExport(devkit_exports, require("./src"), module.exports);
18
- // Annotate the CommonJS export names for ESM import in node:
19
- 0 && (module.exports = {
20
- ...require("./src")
21
- });