@aigne/doc-smith 0.8.12-beta.8 → 0.8.12-beta.9

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 (264) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/agents/publish/index.yaml +4 -0
  3. package/agents/publish/publish-docs.mjs +77 -5
  4. package/agents/publish/translate-meta.mjs +103 -0
  5. package/agents/update/generate-document.yaml +30 -28
  6. package/agents/update/update-document-detail.yaml +3 -1
  7. package/agents/utils/update-branding.mjs +69 -0
  8. package/package.json +16 -2
  9. package/prompts/common/document/role-and-personality.md +3 -1
  10. package/prompts/detail/d2-diagram/guide.md +7 -1
  11. package/prompts/detail/d2-diagram/user-prompt.md +3 -0
  12. package/prompts/detail/generate/system-prompt.md +6 -7
  13. package/prompts/detail/generate/user-prompt.md +12 -3
  14. package/prompts/detail/update/user-prompt.md +0 -2
  15. package/prompts/structure/update/user-prompt.md +0 -4
  16. package/utils/file-utils.mjs +69 -24
  17. package/utils/markdown-checker.mjs +0 -20
  18. package/utils/request.mjs +7 -0
  19. package/utils/upload-files.mjs +231 -0
  20. package/utils/utils.mjs +11 -1
  21. package/.aigne/doc-smith/config.yaml +0 -77
  22. package/.aigne/doc-smith/history.yaml +0 -37
  23. package/.aigne/doc-smith/media-description.yaml +0 -91
  24. package/.aigne/doc-smith/output/structure-plan.json +0 -162
  25. package/.aigne/doc-smith/preferences.yml +0 -97
  26. package/.aigne/doc-smith/upload-cache.yaml +0 -1830
  27. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  28. package/.github/workflows/ci.yml +0 -54
  29. package/.github/workflows/create-release-pr.yaml +0 -21
  30. package/.github/workflows/publish-docs.yml +0 -65
  31. package/.github/workflows/release.yml +0 -49
  32. package/.github/workflows/reviewer.yml +0 -54
  33. package/.release-please-manifest.json +0 -3
  34. package/RELEASE.md +0 -9
  35. package/assets/screenshots/doc-complete-setup.png +0 -0
  36. package/assets/screenshots/doc-generate-docs.png +0 -0
  37. package/assets/screenshots/doc-generate.png +0 -0
  38. package/assets/screenshots/doc-generated-successfully.png +0 -0
  39. package/assets/screenshots/doc-publish.png +0 -0
  40. package/assets/screenshots/doc-regenerate.png +0 -0
  41. package/assets/screenshots/doc-translate-langs.png +0 -0
  42. package/assets/screenshots/doc-translate.png +0 -0
  43. package/assets/screenshots/doc-update.png +0 -0
  44. package/biome.json +0 -73
  45. package/codecov.yml +0 -15
  46. package/docs/_sidebar.md +0 -15
  47. package/docs/configuration-initial-setup.ja.md +0 -179
  48. package/docs/configuration-initial-setup.md +0 -198
  49. package/docs/configuration-initial-setup.zh-TW.md +0 -179
  50. package/docs/configuration-initial-setup.zh.md +0 -179
  51. package/docs/configuration-managing-preferences.ja.md +0 -100
  52. package/docs/configuration-managing-preferences.md +0 -100
  53. package/docs/configuration-managing-preferences.zh-TW.md +0 -100
  54. package/docs/configuration-managing-preferences.zh.md +0 -100
  55. package/docs/configuration.ja.md +0 -69
  56. package/docs/configuration.md +0 -69
  57. package/docs/configuration.zh-TW.md +0 -69
  58. package/docs/configuration.zh.md +0 -69
  59. package/docs/getting-started.ja.md +0 -107
  60. package/docs/getting-started.md +0 -107
  61. package/docs/getting-started.zh-TW.md +0 -107
  62. package/docs/getting-started.zh.md +0 -107
  63. package/docs/guides-cleaning-up.ja.md +0 -51
  64. package/docs/guides-cleaning-up.md +0 -52
  65. package/docs/guides-cleaning-up.zh-TW.md +0 -51
  66. package/docs/guides-cleaning-up.zh.md +0 -51
  67. package/docs/guides-evaluating-documents.ja.md +0 -66
  68. package/docs/guides-evaluating-documents.md +0 -107
  69. package/docs/guides-evaluating-documents.zh-TW.md +0 -66
  70. package/docs/guides-evaluating-documents.zh.md +0 -66
  71. package/docs/guides-generating-documentation.ja.md +0 -151
  72. package/docs/guides-generating-documentation.md +0 -89
  73. package/docs/guides-generating-documentation.zh-TW.md +0 -151
  74. package/docs/guides-generating-documentation.zh.md +0 -151
  75. package/docs/guides-interactive-chat.ja.md +0 -85
  76. package/docs/guides-interactive-chat.md +0 -93
  77. package/docs/guides-interactive-chat.zh-TW.md +0 -85
  78. package/docs/guides-interactive-chat.zh.md +0 -85
  79. package/docs/guides-managing-history.ja.md +0 -48
  80. package/docs/guides-managing-history.md +0 -53
  81. package/docs/guides-managing-history.zh-TW.md +0 -48
  82. package/docs/guides-managing-history.zh.md +0 -48
  83. package/docs/guides-publishing-your-docs.ja.md +0 -78
  84. package/docs/guides-publishing-your-docs.md +0 -83
  85. package/docs/guides-publishing-your-docs.zh-TW.md +0 -78
  86. package/docs/guides-publishing-your-docs.zh.md +0 -78
  87. package/docs/guides-translating-documentation.ja.md +0 -95
  88. package/docs/guides-translating-documentation.md +0 -100
  89. package/docs/guides-translating-documentation.zh-TW.md +0 -95
  90. package/docs/guides-translating-documentation.zh.md +0 -95
  91. package/docs/guides-updating-documentation.ja.md +0 -77
  92. package/docs/guides-updating-documentation.md +0 -79
  93. package/docs/guides-updating-documentation.zh-TW.md +0 -77
  94. package/docs/guides-updating-documentation.zh.md +0 -77
  95. package/docs/guides.ja.md +0 -32
  96. package/docs/guides.md +0 -32
  97. package/docs/guides.zh-TW.md +0 -32
  98. package/docs/guides.zh.md +0 -32
  99. package/docs/overview.ja.md +0 -61
  100. package/docs/overview.md +0 -61
  101. package/docs/overview.zh-TW.md +0 -61
  102. package/docs/overview.zh.md +0 -61
  103. package/docs/release-notes.ja.md +0 -255
  104. package/docs/release-notes.md +0 -288
  105. package/docs/release-notes.zh-TW.md +0 -255
  106. package/docs/release-notes.zh.md +0 -255
  107. package/prompts/common/afs/afs-tools-usage.md +0 -5
  108. package/prompts/common/afs/use-afs-instruction.md +0 -1
  109. package/release-please-config.json +0 -14
  110. package/tests/agents/chat/chat.test.mjs +0 -46
  111. package/tests/agents/clear/choose-contents.test.mjs +0 -284
  112. package/tests/agents/clear/clear-auth-tokens.test.mjs +0 -268
  113. package/tests/agents/clear/clear-document-config.test.mjs +0 -167
  114. package/tests/agents/clear/clear-document-structure.test.mjs +0 -380
  115. package/tests/agents/clear/clear-generated-docs.test.mjs +0 -222
  116. package/tests/agents/evaluate/code-snippet.test.mjs +0 -163
  117. package/tests/agents/evaluate/fixtures/api-services.md +0 -87
  118. package/tests/agents/evaluate/fixtures/js-sdk.md +0 -94
  119. package/tests/agents/evaluate/generate-report.test.mjs +0 -312
  120. package/tests/agents/generate/check-document-structure.test.mjs +0 -45
  121. package/tests/agents/generate/check-need-generate-structure.test.mjs +0 -279
  122. package/tests/agents/generate/document-structure-tools/add-document.test.mjs +0 -449
  123. package/tests/agents/generate/document-structure-tools/delete-document.test.mjs +0 -410
  124. package/tests/agents/generate/document-structure-tools/generate-sub-structure.test.mjs +0 -277
  125. package/tests/agents/generate/document-structure-tools/move-document.test.mjs +0 -476
  126. package/tests/agents/generate/document-structure-tools/update-document.test.mjs +0 -548
  127. package/tests/agents/generate/generate-structure.test.mjs +0 -45
  128. package/tests/agents/generate/user-review-document-structure.test.mjs +0 -319
  129. package/tests/agents/history/view.test.mjs +0 -97
  130. package/tests/agents/init/init.test.mjs +0 -1657
  131. package/tests/agents/prefs/prefs.test.mjs +0 -431
  132. package/tests/agents/publish/publish-docs.test.mjs +0 -787
  133. package/tests/agents/translate/choose-language.test.mjs +0 -311
  134. package/tests/agents/translate/translate-document.test.mjs +0 -51
  135. package/tests/agents/update/check-document.test.mjs +0 -463
  136. package/tests/agents/update/check-update-is-single.test.mjs +0 -300
  137. package/tests/agents/update/document-tools/update-document-content.test.mjs +0 -329
  138. package/tests/agents/update/generate-document.test.mjs +0 -51
  139. package/tests/agents/update/save-and-translate-document.test.mjs +0 -369
  140. package/tests/agents/update/user-review-document.test.mjs +0 -582
  141. package/tests/agents/utils/action-success.test.mjs +0 -54
  142. package/tests/agents/utils/check-detail-result.test.mjs +0 -743
  143. package/tests/agents/utils/check-feedback-refiner.test.mjs +0 -478
  144. package/tests/agents/utils/choose-docs.test.mjs +0 -406
  145. package/tests/agents/utils/exit.test.mjs +0 -70
  146. package/tests/agents/utils/feedback-refiner.test.mjs +0 -51
  147. package/tests/agents/utils/find-item-by-path.test.mjs +0 -517
  148. package/tests/agents/utils/find-user-preferences-by-path.test.mjs +0 -382
  149. package/tests/agents/utils/format-document-structure.test.mjs +0 -364
  150. package/tests/agents/utils/fs.test.mjs +0 -267
  151. package/tests/agents/utils/load-sources.test.mjs +0 -1470
  152. package/tests/agents/utils/save-docs.test.mjs +0 -109
  153. package/tests/agents/utils/save-output.test.mjs +0 -315
  154. package/tests/agents/utils/save-single-doc.test.mjs +0 -364
  155. package/tests/agents/utils/transform-detail-datasources.test.mjs +0 -320
  156. package/tests/utils/auth-utils.test.mjs +0 -596
  157. package/tests/utils/blocklet.test.mjs +0 -336
  158. package/tests/utils/conflict-detector.test.mjs +0 -355
  159. package/tests/utils/constants.test.mjs +0 -295
  160. package/tests/utils/d2-utils.test.mjs +0 -437
  161. package/tests/utils/deploy.test.mjs +0 -399
  162. package/tests/utils/docs-finder-utils.test.mjs +0 -650
  163. package/tests/utils/file-utils.test.mjs +0 -521
  164. package/tests/utils/history-utils.test.mjs +0 -206
  165. package/tests/utils/kroki-utils.test.mjs +0 -646
  166. package/tests/utils/linter/fixtures/css/keyword-error.css +0 -1
  167. package/tests/utils/linter/fixtures/css/missing-semicolon.css +0 -1
  168. package/tests/utils/linter/fixtures/css/syntax-error.css +0 -1
  169. package/tests/utils/linter/fixtures/css/undeclare-variable.css +0 -1
  170. package/tests/utils/linter/fixtures/css/unused-variable.css +0 -2
  171. package/tests/utils/linter/fixtures/css/valid-code.css +0 -1
  172. package/tests/utils/linter/fixtures/dockerfile/keyword-error.dockerfile +0 -1
  173. package/tests/utils/linter/fixtures/dockerfile/missing-semicolon.dockerfile +0 -2
  174. package/tests/utils/linter/fixtures/dockerfile/syntax-error.dockerfile +0 -2
  175. package/tests/utils/linter/fixtures/dockerfile/undeclare-variable.dockerfile +0 -1
  176. package/tests/utils/linter/fixtures/dockerfile/unused-variable.dockerfile +0 -1
  177. package/tests/utils/linter/fixtures/dockerfile/valid-code.dockerfile +0 -2
  178. package/tests/utils/linter/fixtures/go/keyword-error.go +0 -5
  179. package/tests/utils/linter/fixtures/go/missing-semicolon.go +0 -5
  180. package/tests/utils/linter/fixtures/go/syntax-error.go +0 -6
  181. package/tests/utils/linter/fixtures/go/undeclare-variable.go +0 -5
  182. package/tests/utils/linter/fixtures/go/unused-variable.go +0 -5
  183. package/tests/utils/linter/fixtures/go/valid-code.go +0 -7
  184. package/tests/utils/linter/fixtures/js/keyword-error.js +0 -3
  185. package/tests/utils/linter/fixtures/js/missing-semicolon.js +0 -6
  186. package/tests/utils/linter/fixtures/js/syntax-error.js +0 -4
  187. package/tests/utils/linter/fixtures/js/undeclare-variable.js +0 -3
  188. package/tests/utils/linter/fixtures/js/unused-variable.js +0 -7
  189. package/tests/utils/linter/fixtures/js/valid-code.js +0 -15
  190. package/tests/utils/linter/fixtures/json/keyword-error.json +0 -1
  191. package/tests/utils/linter/fixtures/json/missing-semicolon.json +0 -1
  192. package/tests/utils/linter/fixtures/json/syntax-error.json +0 -1
  193. package/tests/utils/linter/fixtures/json/undeclare-variable.json +0 -1
  194. package/tests/utils/linter/fixtures/json/unused-variable.json +0 -1
  195. package/tests/utils/linter/fixtures/json/valid-code.json +0 -1
  196. package/tests/utils/linter/fixtures/jsx/keyword-error.jsx +0 -5
  197. package/tests/utils/linter/fixtures/jsx/missing-semicolon.jsx +0 -5
  198. package/tests/utils/linter/fixtures/jsx/syntax-error.jsx +0 -5
  199. package/tests/utils/linter/fixtures/jsx/undeclare-variable.jsx +0 -5
  200. package/tests/utils/linter/fixtures/jsx/unused-variable.jsx +0 -4
  201. package/tests/utils/linter/fixtures/jsx/valid-code.jsx +0 -5
  202. package/tests/utils/linter/fixtures/python/keyword-error.py +0 -3
  203. package/tests/utils/linter/fixtures/python/missing-semicolon.py +0 -2
  204. package/tests/utils/linter/fixtures/python/syntax-error.py +0 -3
  205. package/tests/utils/linter/fixtures/python/undeclare-variable.py +0 -3
  206. package/tests/utils/linter/fixtures/python/unused-variable.py +0 -6
  207. package/tests/utils/linter/fixtures/python/valid-code.py +0 -12
  208. package/tests/utils/linter/fixtures/ruby/keyword-error.rb +0 -2
  209. package/tests/utils/linter/fixtures/ruby/missing-semicolon.rb +0 -1
  210. package/tests/utils/linter/fixtures/ruby/syntax-error.rb +0 -2
  211. package/tests/utils/linter/fixtures/ruby/undeclare-variable.rb +0 -1
  212. package/tests/utils/linter/fixtures/ruby/unused-variable.rb +0 -2
  213. package/tests/utils/linter/fixtures/ruby/valid-code.rb +0 -1
  214. package/tests/utils/linter/fixtures/sass/keyword-error.sass +0 -2
  215. package/tests/utils/linter/fixtures/sass/missing-semicolon.sass +0 -3
  216. package/tests/utils/linter/fixtures/sass/syntax-error.sass +0 -3
  217. package/tests/utils/linter/fixtures/sass/undeclare-variable.sass +0 -2
  218. package/tests/utils/linter/fixtures/sass/unused-variable.sass +0 -4
  219. package/tests/utils/linter/fixtures/sass/valid-code.sass +0 -2
  220. package/tests/utils/linter/fixtures/scss/keyword-error.scss +0 -1
  221. package/tests/utils/linter/fixtures/scss/missing-semicolon.scss +0 -1
  222. package/tests/utils/linter/fixtures/scss/syntax-error.scss +0 -1
  223. package/tests/utils/linter/fixtures/scss/undeclare-variable.scss +0 -1
  224. package/tests/utils/linter/fixtures/scss/unused-variable.scss +0 -2
  225. package/tests/utils/linter/fixtures/scss/valid-code.scss +0 -1
  226. package/tests/utils/linter/fixtures/shell/keyword-error.sh +0 -5
  227. package/tests/utils/linter/fixtures/shell/missing-semicolon.sh +0 -3
  228. package/tests/utils/linter/fixtures/shell/syntax-error.sh +0 -4
  229. package/tests/utils/linter/fixtures/shell/undeclare-variable.sh +0 -3
  230. package/tests/utils/linter/fixtures/shell/unused-variable.sh +0 -4
  231. package/tests/utils/linter/fixtures/shell/valid-code.sh +0 -3
  232. package/tests/utils/linter/fixtures/ts/keyword-error.ts +0 -1
  233. package/tests/utils/linter/fixtures/ts/missing-semicolon.ts +0 -1
  234. package/tests/utils/linter/fixtures/ts/syntax-error.ts +0 -1
  235. package/tests/utils/linter/fixtures/ts/undeclare-variable.ts +0 -1
  236. package/tests/utils/linter/fixtures/ts/unused-variable.ts +0 -3
  237. package/tests/utils/linter/fixtures/ts/valid-code.ts +0 -3
  238. package/tests/utils/linter/fixtures/tsx/keyword-error.tsx +0 -5
  239. package/tests/utils/linter/fixtures/tsx/missing-semicolon.tsx +0 -5
  240. package/tests/utils/linter/fixtures/tsx/syntax-error.tsx +0 -5
  241. package/tests/utils/linter/fixtures/tsx/undeclare-variable.tsx +0 -6
  242. package/tests/utils/linter/fixtures/tsx/unused-variable.tsx +0 -6
  243. package/tests/utils/linter/fixtures/tsx/valid-code.tsx +0 -5
  244. package/tests/utils/linter/fixtures/vue/keyword-error.vue +0 -6
  245. package/tests/utils/linter/fixtures/vue/missing-semicolon.vue +0 -6
  246. package/tests/utils/linter/fixtures/vue/syntax-error.vue +0 -6
  247. package/tests/utils/linter/fixtures/vue/undeclare-variable.vue +0 -6
  248. package/tests/utils/linter/fixtures/vue/unused-variable.vue +0 -7
  249. package/tests/utils/linter/fixtures/vue/valid-code.vue +0 -6
  250. package/tests/utils/linter/fixtures/yaml/keyword-error.yml +0 -1
  251. package/tests/utils/linter/fixtures/yaml/missing-semicolon.yml +0 -2
  252. package/tests/utils/linter/fixtures/yaml/syntax-error.yml +0 -1
  253. package/tests/utils/linter/fixtures/yaml/undeclare-variable.yml +0 -1
  254. package/tests/utils/linter/fixtures/yaml/unused-variable.yml +0 -2
  255. package/tests/utils/linter/fixtures/yaml/valid-code.yml +0 -3
  256. package/tests/utils/linter/index.test.mjs +0 -440
  257. package/tests/utils/linter/scan-results.mjs +0 -42
  258. package/tests/utils/load-config.test.mjs +0 -141
  259. package/tests/utils/markdown/index.test.mjs +0 -478
  260. package/tests/utils/mermaid-validator.test.mjs +0 -541
  261. package/tests/utils/mock-chat-model.mjs +0 -12
  262. package/tests/utils/preferences-utils.test.mjs +0 -465
  263. package/tests/utils/save-value-to-config.test.mjs +0 -483
  264. package/tests/utils/utils.test.mjs +0 -941
@@ -1,596 +0,0 @@
1
- import {
2
- afterAll,
3
- afterEach,
4
- beforeAll,
5
- beforeEach,
6
- describe,
7
- expect,
8
- mock,
9
- spyOn,
10
- test,
11
- } from "bun:test";
12
- import * as fs from "node:fs";
13
- import * as fsPromises from "node:fs/promises";
14
- import * as os from "node:os";
15
- import * as path from "node:path";
16
- import * as yaml from "yaml";
17
- import { getAccessToken, getOfficialAccessToken } from "../../utils/auth-utils.mjs";
18
- import * as blockletUtils from "../../utils/blocklet.mjs";
19
- import { DOC_OFFICIAL_ACCESS_TOKEN } from "../../utils/constants/index.mjs";
20
-
21
- // Mock external modules that involve network requests
22
- const mockCreateConnect = mock(() => Promise.resolve({ accessKeySecret: "new-access-token" }));
23
- const mockOpen = mock(() => Promise.resolve());
24
- const mockJoinURL = mock((base, path) => `${base}${path}`);
25
-
26
- describe("auth-utils", () => {
27
- let originalEnv;
28
-
29
- // Spies for internal operations
30
- let existsSyncSpy;
31
- let readFileSpy;
32
- let writeFileSpy;
33
- let mkdirSyncSpy;
34
- let homedirSpy;
35
- let joinSpy;
36
- let parseSpy;
37
- let stringifySpy;
38
- let getComponentMountPointSpy;
39
- let consoleWarnSpy;
40
- let consoleDebugSpy;
41
-
42
- beforeAll(() => {
43
- // Apply mocks for external dependencies that involve network requests
44
- mock.module("@aigne/cli/utils/aigne-hub/credential.js", () => ({
45
- createConnect: mockCreateConnect,
46
- }));
47
- mock.module("open", () => ({ default: mockOpen }));
48
- mock.module("join-url", () => ({ default: mockJoinURL }));
49
- });
50
-
51
- afterAll(() => {
52
- // Restore all mocks when this test file is complete
53
- mock.restore();
54
- });
55
-
56
- beforeEach(() => {
57
- originalEnv = { ...process.env };
58
- delete process.env.DOC_DISCUSS_KIT_ACCESS_TOKEN;
59
- delete process.env[DOC_OFFICIAL_ACCESS_TOKEN];
60
-
61
- // Reset external mocks
62
- mockCreateConnect.mockClear();
63
- mockCreateConnect.mockImplementation(() =>
64
- Promise.resolve({ accessKeySecret: "new-access-token" }),
65
- );
66
- mockOpen.mockClear();
67
- mockOpen.mockImplementation(() => Promise.resolve());
68
- mockJoinURL.mockClear();
69
- mockJoinURL.mockImplementation((base, path) => `${base}${path}`);
70
-
71
- // Spy on filesystem operations
72
- existsSyncSpy = spyOn(fs, "existsSync").mockReturnValue(false);
73
- readFileSpy = spyOn(fsPromises, "readFile").mockResolvedValue("");
74
- writeFileSpy = spyOn(fsPromises, "writeFile").mockResolvedValue();
75
- mkdirSyncSpy = spyOn(fs, "mkdirSync").mockImplementation(() => {});
76
-
77
- // Spy on path operations
78
- homedirSpy = spyOn(os, "homedir").mockReturnValue("/mock/home");
79
- joinSpy = spyOn(path, "join").mockImplementation((...paths) => paths.join("/"));
80
-
81
- // Spy on YAML operations
82
- parseSpy = spyOn(yaml, "parse").mockReturnValue({});
83
- stringifySpy = spyOn(yaml, "stringify").mockReturnValue("mock yaml");
84
-
85
- // Spy on blocklet operations
86
- getComponentMountPointSpy = spyOn(blockletUtils, "getComponentMountPoint").mockResolvedValue();
87
-
88
- // Spy on console methods
89
- consoleWarnSpy = spyOn(console, "warn").mockImplementation(() => {});
90
- consoleDebugSpy = spyOn(console, "debug").mockImplementation(() => {});
91
- });
92
-
93
- afterEach(() => {
94
- process.env = originalEnv;
95
-
96
- // Restore all spies
97
- existsSyncSpy?.mockRestore();
98
- readFileSpy?.mockRestore();
99
- writeFileSpy?.mockRestore();
100
- mkdirSyncSpy?.mockRestore();
101
- homedirSpy?.mockRestore();
102
- joinSpy?.mockRestore();
103
- parseSpy?.mockRestore();
104
- stringifySpy?.mockRestore();
105
- getComponentMountPointSpy?.mockRestore();
106
- consoleWarnSpy?.mockRestore();
107
- consoleDebugSpy?.mockRestore();
108
- });
109
-
110
- test("should return access token from environment variable", async () => {
111
- process.env.DOC_DISCUSS_KIT_ACCESS_TOKEN = "env-token";
112
-
113
- const result = await getAccessToken("https://example.com");
114
-
115
- expect(result).toBe("env-token");
116
- });
117
-
118
- test("should handle different URL formats", async () => {
119
- process.env.DOC_DISCUSS_KIT_ACCESS_TOKEN = "test-token";
120
-
121
- // Test different URL formats
122
- const urls = [
123
- "https://example.com",
124
- "http://example.com",
125
- "https://example.com:8080",
126
- "https://sub.example.com/path",
127
- ];
128
-
129
- for (const url of urls) {
130
- const result = await getAccessToken(url);
131
- expect(result).toBe("test-token");
132
- }
133
- });
134
-
135
- test("should handle invalid URL", async () => {
136
- process.env.DOC_DISCUSS_KIT_ACCESS_TOKEN = "test-token";
137
-
138
- await expect(getAccessToken("invalid-url")).rejects.toThrow();
139
- });
140
-
141
- test("should work with localhost URLs", async () => {
142
- process.env.DOC_DISCUSS_KIT_ACCESS_TOKEN = "local-token";
143
-
144
- const result = await getAccessToken("http://localhost:3000");
145
-
146
- expect(result).toBe("local-token");
147
- });
148
-
149
- test("should preserve environment variable after function call", async () => {
150
- process.env.DOC_DISCUSS_KIT_ACCESS_TOKEN = "persistent-token";
151
-
152
- await getAccessToken("https://example.com");
153
-
154
- expect(process.env.DOC_DISCUSS_KIT_ACCESS_TOKEN).toBe("persistent-token");
155
- });
156
-
157
- // CONFIG FILE READING TESTS
158
- test("should read access token from config file", async () => {
159
- existsSyncSpy.mockReturnValue(true);
160
- readFileSpy.mockResolvedValue("DOC_DISCUSS_KIT_ACCESS_TOKEN: config-token");
161
- parseSpy.mockReturnValue({
162
- "example.com": {
163
- DOC_DISCUSS_KIT_ACCESS_TOKEN: "config-token",
164
- },
165
- });
166
-
167
- const result = await getAccessToken("https://example.com");
168
-
169
- expect(result).toBe("config-token");
170
- expect(joinSpy).toHaveBeenCalledWith("/mock/home", ".aigne", "doc-smith-connected.yaml");
171
- expect(existsSyncSpy).toHaveBeenCalledWith("/mock/home/.aigne/doc-smith-connected.yaml");
172
- expect(readFileSpy).toHaveBeenCalledWith("/mock/home/.aigne/doc-smith-connected.yaml", "utf8");
173
- expect(parseSpy).toHaveBeenCalled();
174
- });
175
-
176
- test("should handle config file without token field", async () => {
177
- existsSyncSpy.mockReturnValue(true);
178
- readFileSpy.mockResolvedValue("other: value");
179
- parseSpy.mockReturnValue({
180
- "example.com": {
181
- other: "value",
182
- },
183
- });
184
-
185
- // Since we now have successful authorization flow mocked, this should succeed
186
- const result = await getAccessToken("https://example.com");
187
- expect(result).toBe("new-access-token");
188
- expect(getComponentMountPointSpy).toHaveBeenCalled();
189
- });
190
-
191
- test("should handle missing hostname in config", async () => {
192
- existsSyncSpy.mockReturnValue(true);
193
- readFileSpy.mockResolvedValue("DOC_DISCUSS_KIT_ACCESS_TOKEN: token");
194
- parseSpy.mockReturnValue({
195
- "other-domain.com": {
196
- DOC_DISCUSS_KIT_ACCESS_TOKEN: "other-token",
197
- },
198
- });
199
-
200
- // Since we now have successful authorization flow mocked, this should succeed
201
- const result = await getAccessToken("https://example.com");
202
- expect(result).toBe("new-access-token");
203
- expect(getComponentMountPointSpy).toHaveBeenCalled();
204
- });
205
-
206
- test("should handle config file read errors", async () => {
207
- existsSyncSpy.mockReturnValue(true);
208
- readFileSpy.mockRejectedValue(new Error("File read error"));
209
- // Make createConnect fail to test the error path
210
- mockCreateConnect.mockRejectedValueOnce(new Error("Network error"));
211
-
212
- await expect(getAccessToken("https://example.com")).rejects.toThrow(
213
- "Failed to obtain access token. Please check your network connection and try again later.",
214
- );
215
- expect(consoleWarnSpy).toHaveBeenCalledWith("Failed to read config file:", "File read error");
216
- });
217
-
218
- test("should handle config file without DOC_DISCUSS_KIT_ACCESS_TOKEN keyword", async () => {
219
- existsSyncSpy.mockReturnValue(true);
220
- readFileSpy.mockResolvedValue("some other content");
221
-
222
- // Should succeed with authorization flow
223
- const result = await getAccessToken("https://example.com");
224
- expect(result).toBe("new-access-token");
225
- // Verify that the config file was read but the flow proceeded to authorization
226
- expect(readFileSpy).toHaveBeenCalled();
227
- });
228
-
229
- // ERROR HANDLING TESTS
230
- test("should throw error for invalid blocklet", async () => {
231
- const InvalidBlockletError = (await import("../../utils/blocklet.mjs")).InvalidBlockletError;
232
- getComponentMountPointSpy.mockRejectedValue(new InvalidBlockletError());
233
-
234
- await expect(getAccessToken("https://example.com")).rejects.toThrow(
235
- "The provided URL is not a valid website on ArcBlock platform",
236
- );
237
- });
238
-
239
- test("should throw error for missing component", async () => {
240
- const ComponentNotFoundError = (await import("../../utils/blocklet.mjs"))
241
- .ComponentNotFoundError;
242
- getComponentMountPointSpy.mockRejectedValue(new ComponentNotFoundError());
243
-
244
- await expect(getAccessToken("https://example.com")).rejects.toThrow(
245
- "This website does not have required components for publishing",
246
- );
247
- });
248
-
249
- test("should throw error for network issues", async () => {
250
- getComponentMountPointSpy.mockRejectedValue(new Error("Network error"));
251
-
252
- await expect(getAccessToken("https://example.com")).rejects.toThrow("Unable to connect to:");
253
- });
254
-
255
- // AUTHORIZATION FLOW TESTS
256
- test("should successfully complete authorization flow", async () => {
257
- // Mock successful component check
258
- getComponentMountPointSpy.mockResolvedValue({ endpoint: "https://example.com/api" });
259
-
260
- const result = await getAccessToken("https://example.com");
261
-
262
- expect(result).toBe("new-access-token");
263
-
264
- // Verify the authorization flow
265
- expect(getComponentMountPointSpy).toHaveBeenCalledWith(
266
- "https://example.com",
267
- expect.any(String),
268
- );
269
- expect(mockCreateConnect).toHaveBeenCalledWith(
270
- expect.objectContaining({
271
- connectAction: "gen-simple-access-key",
272
- source: "AIGNE DocSmith connect to website",
273
- closeOnSuccess: true,
274
- appName: "AIGNE DocSmith",
275
- openPage: expect.any(Function),
276
- }),
277
- );
278
-
279
- // Verify environment variable is set
280
- expect(process.env.DOC_DISCUSS_KIT_ACCESS_TOKEN).toBe("new-access-token");
281
-
282
- // Verify config file is saved
283
- expect(writeFileSpy).toHaveBeenCalledWith(
284
- "/mock/home/.aigne/doc-smith-connected.yaml",
285
- "mock yaml",
286
- );
287
- expect(stringifySpy).toHaveBeenCalledWith(
288
- expect.objectContaining({
289
- "example.com": {
290
- DOC_DISCUSS_KIT_ACCESS_TOKEN: "new-access-token",
291
- DOC_DISCUSS_KIT_URL: "https://example.com",
292
- },
293
- }),
294
- );
295
- });
296
-
297
- test("should create .aigne directory if it doesn't exist", async () => {
298
- getComponentMountPointSpy.mockResolvedValue({ endpoint: "https://example.com/api" });
299
- existsSyncSpy.mockReturnValueOnce(false); // .aigne directory doesn't exist
300
-
301
- const result = await getAccessToken("https://example.com");
302
-
303
- expect(result).toBe("new-access-token");
304
- expect(mkdirSyncSpy).toHaveBeenCalledWith("/mock/home/.aigne", { recursive: true });
305
- });
306
-
307
- test("should merge with existing config file", async () => {
308
- getComponentMountPointSpy.mockResolvedValue({ endpoint: "https://example.com/api" });
309
- existsSyncSpy
310
- .mockReturnValueOnce(true) // .aigne directory exists
311
- .mockReturnValueOnce(true); // config file exists at save time
312
- readFileSpy.mockResolvedValue("other.com:\n token: other-token");
313
- parseSpy.mockReturnValue({ "other.com": { token: "other-token" } });
314
-
315
- const result = await getAccessToken("https://example.com");
316
-
317
- expect(result).toBe("new-access-token");
318
- expect(stringifySpy).toHaveBeenCalled();
319
- // Verify that config file writing was attempted
320
- expect(writeFileSpy).toHaveBeenCalled();
321
- });
322
-
323
- test("should call openPage function with correct URL", async () => {
324
- getComponentMountPointSpy.mockResolvedValue({ endpoint: "https://example.com/api" });
325
-
326
- let capturedOpenPage;
327
- mockCreateConnect.mockImplementation((options) => {
328
- capturedOpenPage = options.openPage;
329
- return Promise.resolve({ accessKeySecret: "new-access-token" });
330
- });
331
-
332
- const result = await getAccessToken("https://example.com");
333
-
334
- expect(result).toBe("new-access-token");
335
- expect(typeof capturedOpenPage).toBe("function");
336
-
337
- // Test that openPage calls the mock open function
338
- await capturedOpenPage("https://auth.example.com");
339
- expect(mockOpen).toHaveBeenCalledWith("https://auth.example.com/?required_roles=owner%2Cadmin");
340
- });
341
-
342
- test("should handle authorization failure", async () => {
343
- getComponentMountPointSpy.mockResolvedValue({ endpoint: "https://example.com/api" });
344
- mockCreateConnect.mockRejectedValue(new Error("Authorization failed"));
345
-
346
- await expect(getAccessToken("https://example.com")).rejects.toThrow(
347
- "Failed to obtain access token. Please check your network connection and try again later.",
348
- );
349
- expect(consoleDebugSpy).toHaveBeenCalledWith(expect.any(Error));
350
- });
351
-
352
- test("should handle createConnect with different error types", async () => {
353
- getComponentMountPointSpy.mockResolvedValue({ endpoint: "https://example.com/api" });
354
- mockCreateConnect.mockRejectedValue(new TypeError("Network error"));
355
-
356
- await expect(getAccessToken("https://example.com")).rejects.toThrow(
357
- "Failed to obtain access token. Please check your network connection and try again later.",
358
- );
359
- });
360
-
361
- // OFFICIAL ACCESS TOKEN TESTS
362
- describe("getOfficialAccessToken", () => {
363
- test("should throw error for missing baseUrl parameter", async () => {
364
- await expect(getOfficialAccessToken()).rejects.toThrow(
365
- "baseUrl parameter is required for getOfficialAccessToken.",
366
- );
367
- await expect(getOfficialAccessToken("")).rejects.toThrow(
368
- "baseUrl parameter is required for getOfficialAccessToken.",
369
- );
370
- });
371
-
372
- test("should return access token from environment variable", async () => {
373
- process.env[DOC_OFFICIAL_ACCESS_TOKEN] = "env-official-token";
374
-
375
- const result = await getOfficialAccessToken("https://example.com");
376
-
377
- expect(result).toBe("env-official-token");
378
- });
379
-
380
- test("should handle different URL formats", async () => {
381
- process.env[DOC_OFFICIAL_ACCESS_TOKEN] = "test-official-token";
382
-
383
- const urls = [
384
- "https://example.com",
385
- "http://example.com",
386
- "https://example.com:8080",
387
- "https://sub.example.com/path",
388
- ];
389
-
390
- for (const url of urls) {
391
- const result = await getOfficialAccessToken(url);
392
- expect(result).toBe("test-official-token");
393
- }
394
- });
395
-
396
- test("should handle invalid URL", async () => {
397
- process.env[DOC_OFFICIAL_ACCESS_TOKEN] = "test-official-token";
398
-
399
- await expect(getOfficialAccessToken("invalid-url")).rejects.toThrow();
400
- });
401
-
402
- test("should work with localhost URLs", async () => {
403
- process.env[DOC_OFFICIAL_ACCESS_TOKEN] = "local-official-token";
404
-
405
- const result = await getOfficialAccessToken("http://localhost:3000");
406
-
407
- expect(result).toBe("local-official-token");
408
- });
409
-
410
- test("should preserve environment variable after function call", async () => {
411
- process.env[DOC_OFFICIAL_ACCESS_TOKEN] = "persistent-official-token";
412
-
413
- await getOfficialAccessToken("https://example.com");
414
-
415
- expect(process.env[DOC_OFFICIAL_ACCESS_TOKEN]).toBe("persistent-official-token");
416
- });
417
-
418
- // CONFIG FILE READING TESTS
419
- test("should read access token from config file", async () => {
420
- existsSyncSpy.mockReturnValue(true);
421
- readFileSpy.mockResolvedValue(`DOC_OFFICIAL_ACCESS_TOKEN: config-official-token`);
422
- parseSpy.mockReturnValue({
423
- "example.com": {
424
- [DOC_OFFICIAL_ACCESS_TOKEN]: "config-official-token",
425
- },
426
- });
427
-
428
- const result = await getOfficialAccessToken("https://example.com");
429
-
430
- expect(result).toBe("config-official-token");
431
- expect(joinSpy).toHaveBeenCalledWith("/mock/home", ".aigne", "doc-smith-connected.yaml");
432
- expect(existsSyncSpy).toHaveBeenCalledWith("/mock/home/.aigne/doc-smith-connected.yaml");
433
- expect(readFileSpy).toHaveBeenCalledWith(
434
- "/mock/home/.aigne/doc-smith-connected.yaml",
435
- "utf8",
436
- );
437
- expect(parseSpy).toHaveBeenCalled();
438
- });
439
-
440
- test("should handle config file without token field", async () => {
441
- existsSyncSpy.mockReturnValue(true);
442
- readFileSpy.mockResolvedValue("other: value");
443
- parseSpy.mockReturnValue({
444
- "example.com": {
445
- other: "value",
446
- },
447
- });
448
-
449
- const result = await getOfficialAccessToken("https://example.com");
450
- expect(result).toBe("new-access-token");
451
- });
452
-
453
- test("should handle missing hostname in config", async () => {
454
- existsSyncSpy.mockReturnValue(true);
455
- readFileSpy.mockResolvedValue(`${DOC_OFFICIAL_ACCESS_TOKEN}: token`);
456
- parseSpy.mockReturnValue({
457
- "other-domain.com": {
458
- [DOC_OFFICIAL_ACCESS_TOKEN]: "other-token",
459
- },
460
- });
461
-
462
- const result = await getOfficialAccessToken("https://example.com");
463
- expect(result).toBe("new-access-token");
464
- });
465
-
466
- test("should handle config file read errors silently", async () => {
467
- existsSyncSpy.mockReturnValue(true);
468
- readFileSpy.mockRejectedValue(new Error("File read error"));
469
-
470
- const result = await getOfficialAccessToken("https://example.com");
471
- expect(result).toBe("new-access-token");
472
- // Should not call console.warn for config file errors in getOfficialAccessToken
473
- });
474
-
475
- test("should handle empty config file", async () => {
476
- existsSyncSpy.mockReturnValue(true);
477
- readFileSpy.mockResolvedValue("");
478
- parseSpy.mockReturnValue(null);
479
-
480
- const result = await getOfficialAccessToken("https://example.com");
481
- expect(result).toBe("new-access-token");
482
- });
483
-
484
- // AUTHORIZATION FLOW TESTS
485
- test("should successfully complete authorization flow", async () => {
486
- const result = await getOfficialAccessToken("https://example.com");
487
-
488
- expect(result).toBe("new-access-token");
489
-
490
- // Verify the authorization flow
491
- expect(mockCreateConnect).toHaveBeenCalledWith(
492
- expect.objectContaining({
493
- connectAction: "gen-simple-access-key",
494
- source: "AIGNE DocSmith connect to official service",
495
- closeOnSuccess: true,
496
- appName: "AIGNE DocSmith",
497
- openPage: expect.any(Function),
498
- }),
499
- );
500
-
501
- // Verify environment variable is set
502
- expect(process.env[DOC_OFFICIAL_ACCESS_TOKEN]).toBe("new-access-token");
503
-
504
- // Verify config file is saved
505
- expect(writeFileSpy).toHaveBeenCalledWith(
506
- "/mock/home/.aigne/doc-smith-connected.yaml",
507
- "mock yaml",
508
- );
509
- expect(stringifySpy).toHaveBeenCalledWith(
510
- expect.objectContaining({
511
- "example.com": {
512
- [DOC_OFFICIAL_ACCESS_TOKEN]: "new-access-token",
513
- },
514
- }),
515
- );
516
- });
517
-
518
- test("should create .aigne directory if it doesn't exist", async () => {
519
- existsSyncSpy.mockReturnValueOnce(false); // .aigne directory doesn't exist
520
-
521
- const result = await getOfficialAccessToken("https://example.com");
522
-
523
- expect(result).toBe("new-access-token");
524
- expect(mkdirSyncSpy).toHaveBeenCalledWith("/mock/home/.aigne", { recursive: true });
525
- });
526
-
527
- test("should merge with existing config file", async () => {
528
- existsSyncSpy
529
- .mockReturnValueOnce(true) // .aigne directory exists
530
- .mockReturnValueOnce(true); // config file exists at save time
531
- readFileSpy.mockResolvedValue("other.com:\n token: other-token");
532
- parseSpy.mockReturnValue({ "other.com": { token: "other-token" } });
533
-
534
- const result = await getOfficialAccessToken("https://example.com");
535
-
536
- expect(result).toBe("new-access-token");
537
- expect(stringifySpy).toHaveBeenCalled();
538
- expect(writeFileSpy).toHaveBeenCalled();
539
- });
540
-
541
- test("should call openPage function with correct behavior", async () => {
542
- let capturedOpenPage;
543
- mockCreateConnect.mockImplementation((options) => {
544
- capturedOpenPage = options.openPage;
545
- return Promise.resolve({ accessKeySecret: "new-access-token" });
546
- });
547
-
548
- const result = await getOfficialAccessToken("https://example.com");
549
-
550
- expect(result).toBe("new-access-token");
551
- expect(typeof capturedOpenPage).toBe("function");
552
-
553
- // Test that openPage calls the mock open function and logs
554
- const consoleSpy = spyOn(console, "log").mockImplementation(() => {});
555
- await capturedOpenPage("https://auth.example.com");
556
- expect(mockOpen).toHaveBeenCalledWith("https://auth.example.com");
557
- expect(consoleSpy).toHaveBeenCalledWith(
558
- "🔗 Please open this URL in your browser to authorize access: ",
559
- expect.any(String),
560
- "\n",
561
- );
562
- consoleSpy.mockRestore();
563
- });
564
-
565
- test("should handle authorization failure", async () => {
566
- mockCreateConnect.mockRejectedValue(new Error("Authorization failed"));
567
-
568
- await expect(getOfficialAccessToken("https://example.com")).rejects.toThrow(
569
- "Failed to obtain official access token. Please check your network connection and try again later.",
570
- );
571
- expect(consoleDebugSpy).toHaveBeenCalledWith(expect.any(Error));
572
- });
573
-
574
- test("should handle createConnect with different error types", async () => {
575
- mockCreateConnect.mockRejectedValue(new TypeError("Network error"));
576
-
577
- await expect(getOfficialAccessToken("https://example.com")).rejects.toThrow(
578
- "Failed to obtain official access token. Please check your network connection and try again later.",
579
- );
580
- });
581
-
582
- test("should handle config file save errors gracefully", async () => {
583
- writeFileSpy.mockRejectedValue(new Error("Write error"));
584
- const consoleWarnSpy = spyOn(console, "warn").mockImplementation(() => {});
585
-
586
- const result = await getOfficialAccessToken("https://example.com");
587
-
588
- expect(result).toBe("new-access-token");
589
- expect(consoleWarnSpy).toHaveBeenCalledWith(
590
- expect.stringContaining("Failed to save token to config file"),
591
- expect.any(Error),
592
- );
593
- consoleWarnSpy.mockRestore();
594
- });
595
- });
596
- });