ima2-gen 1.1.8 → 1.1.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 (230) hide show
  1. package/README.md +56 -27
  2. package/bin/commands/annotate.js +137 -0
  3. package/bin/commands/annotate.ts +118 -0
  4. package/bin/commands/cancel.js +37 -33
  5. package/bin/commands/cancel.ts +45 -0
  6. package/bin/commands/canvas-versions.js +91 -0
  7. package/bin/commands/canvas-versions.ts +80 -0
  8. package/bin/commands/cardnews.js +293 -0
  9. package/bin/commands/cardnews.ts +248 -0
  10. package/bin/commands/comfy.js +63 -0
  11. package/bin/commands/comfy.ts +54 -0
  12. package/bin/commands/config.js +270 -0
  13. package/bin/commands/config.ts +265 -0
  14. package/bin/commands/edit.js +97 -72
  15. package/bin/commands/edit.ts +116 -0
  16. package/bin/commands/gen.js +140 -118
  17. package/bin/commands/gen.ts +176 -0
  18. package/bin/commands/history.js +164 -0
  19. package/bin/commands/history.ts +145 -0
  20. package/bin/commands/ls.js +60 -42
  21. package/bin/commands/ls.ts +60 -0
  22. package/bin/commands/metadata.js +45 -0
  23. package/bin/commands/metadata.ts +36 -0
  24. package/bin/commands/multimode.js +159 -0
  25. package/bin/commands/multimode.ts +146 -0
  26. package/bin/commands/node.js +176 -0
  27. package/bin/commands/node.ts +157 -0
  28. package/bin/commands/observability.js +201 -0
  29. package/bin/commands/observability.ts +176 -0
  30. package/bin/commands/ping.js +26 -20
  31. package/bin/commands/ping.ts +29 -0
  32. package/bin/commands/prompt.js +506 -0
  33. package/bin/commands/prompt.ts +421 -0
  34. package/bin/commands/ps.js +78 -71
  35. package/bin/commands/ps.ts +78 -0
  36. package/bin/commands/session.js +308 -0
  37. package/bin/commands/session.ts +265 -0
  38. package/bin/commands/show.js +75 -40
  39. package/bin/commands/show.ts +69 -0
  40. package/bin/ima2.js +324 -310
  41. package/bin/ima2.ts +444 -0
  42. package/bin/lib/args.js +75 -66
  43. package/bin/lib/args.ts +73 -0
  44. package/bin/lib/browser-id.js +15 -0
  45. package/bin/lib/browser-id.ts +16 -0
  46. package/bin/lib/client.js +91 -83
  47. package/bin/lib/client.ts +109 -0
  48. package/bin/lib/error-hints.js +14 -17
  49. package/bin/lib/error-hints.ts +23 -0
  50. package/bin/lib/files.js +26 -28
  51. package/bin/lib/files.ts +39 -0
  52. package/bin/lib/output.js +44 -42
  53. package/bin/lib/output.ts +58 -0
  54. package/bin/lib/platform.js +60 -56
  55. package/bin/lib/platform.ts +97 -0
  56. package/bin/lib/sse.js +73 -0
  57. package/bin/lib/sse.ts +73 -0
  58. package/bin/lib/star-prompt.js +69 -76
  59. package/bin/lib/star-prompt.ts +97 -0
  60. package/bin/lib/storage-doctor.js +34 -35
  61. package/bin/lib/storage-doctor.ts +38 -0
  62. package/config.js +147 -243
  63. package/config.ts +331 -0
  64. package/docs/API.md +48 -8
  65. package/docs/CLI.md +190 -0
  66. package/docs/FAQ.ko.md +5 -5
  67. package/docs/FAQ.md +5 -5
  68. package/docs/README.ja.md +71 -25
  69. package/docs/README.ko.md +61 -24
  70. package/docs/README.zh-CN.md +73 -27
  71. package/lib/assetLifecycle.js +130 -130
  72. package/lib/assetLifecycle.ts +142 -0
  73. package/lib/canvasVersionStore.js +135 -153
  74. package/lib/canvasVersionStore.ts +181 -0
  75. package/lib/cardNewsGenerator.js +127 -142
  76. package/lib/cardNewsGenerator.ts +162 -0
  77. package/lib/cardNewsJobStore.js +78 -84
  78. package/lib/cardNewsJobStore.ts +107 -0
  79. package/lib/cardNewsManifestStore.js +88 -93
  80. package/lib/cardNewsManifestStore.ts +112 -0
  81. package/lib/cardNewsPlanner.js +157 -152
  82. package/lib/cardNewsPlanner.ts +180 -0
  83. package/lib/cardNewsPlannerClient.js +101 -98
  84. package/lib/cardNewsPlannerClient.ts +114 -0
  85. package/lib/cardNewsPlannerPrompt.js +56 -56
  86. package/lib/cardNewsPlannerPrompt.ts +60 -0
  87. package/lib/cardNewsPlannerSchema.js +231 -223
  88. package/lib/cardNewsPlannerSchema.ts +259 -0
  89. package/lib/cardNewsRoleTemplateStore.js +39 -41
  90. package/lib/cardNewsRoleTemplateStore.ts +47 -0
  91. package/lib/cardNewsTemplateStore.js +171 -175
  92. package/lib/cardNewsTemplateStore.ts +210 -0
  93. package/lib/codexDetect.js +44 -47
  94. package/lib/codexDetect.ts +69 -0
  95. package/lib/comfyBridge.js +164 -184
  96. package/lib/comfyBridge.ts +214 -0
  97. package/lib/db.js +41 -51
  98. package/lib/db.ts +166 -0
  99. package/lib/errorClassify.js +62 -78
  100. package/lib/errorClassify.ts +100 -0
  101. package/lib/generationErrors.js +140 -103
  102. package/lib/generationErrors.ts +125 -0
  103. package/lib/historyList.js +149 -147
  104. package/lib/historyList.ts +164 -0
  105. package/lib/imageMetadata.js +86 -89
  106. package/lib/imageMetadata.ts +111 -0
  107. package/lib/imageMetadataStore.js +46 -51
  108. package/lib/imageMetadataStore.ts +67 -0
  109. package/lib/imageModels.js +38 -45
  110. package/lib/imageModels.ts +52 -0
  111. package/lib/inflight.js +131 -150
  112. package/lib/inflight.ts +204 -0
  113. package/lib/localImportStore.js +87 -93
  114. package/lib/localImportStore.ts +111 -0
  115. package/lib/logger.js +105 -112
  116. package/lib/logger.ts +150 -0
  117. package/lib/nodeStore.js +65 -64
  118. package/lib/nodeStore.ts +81 -0
  119. package/lib/oauthLauncher.js +61 -59
  120. package/lib/oauthLauncher.ts +64 -0
  121. package/lib/oauthNormalize.js +15 -19
  122. package/lib/oauthNormalize.ts +30 -0
  123. package/lib/oauthProxy.js +834 -832
  124. package/lib/oauthProxy.ts +995 -0
  125. package/lib/openDirectory.js +41 -40
  126. package/lib/openDirectory.ts +45 -0
  127. package/lib/pngInfo.js +18 -20
  128. package/lib/pngInfo.ts +26 -0
  129. package/lib/promptImport/curatedSources.js +125 -129
  130. package/lib/promptImport/curatedSources.ts +139 -0
  131. package/lib/promptImport/discoveryRegistry.js +185 -203
  132. package/lib/promptImport/discoveryRegistry.ts +236 -0
  133. package/lib/promptImport/errors.js +10 -10
  134. package/lib/promptImport/errors.ts +18 -0
  135. package/lib/promptImport/githubDiscovery.js +209 -219
  136. package/lib/promptImport/githubDiscovery.ts +248 -0
  137. package/lib/promptImport/githubFolder.js +253 -259
  138. package/lib/promptImport/githubFolder.ts +308 -0
  139. package/lib/promptImport/githubSource.js +189 -200
  140. package/lib/promptImport/githubSource.ts +239 -0
  141. package/lib/promptImport/gptImageHints.js +49 -56
  142. package/lib/promptImport/gptImageHints.ts +68 -0
  143. package/lib/promptImport/parsePromptCandidates.js +108 -123
  144. package/lib/promptImport/parsePromptCandidates.ts +153 -0
  145. package/lib/promptImport/promptIndex.js +190 -208
  146. package/lib/promptImport/promptIndex.ts +248 -0
  147. package/lib/promptImport/rankPromptCandidates.js +46 -43
  148. package/lib/promptImport/rankPromptCandidates.ts +49 -0
  149. package/lib/providerOptions.js +31 -0
  150. package/lib/providerOptions.ts +41 -0
  151. package/lib/referenceImageCompress.js +51 -62
  152. package/lib/referenceImageCompress.ts +75 -0
  153. package/lib/refs.js +93 -81
  154. package/lib/refs.ts +117 -0
  155. package/lib/requestLogger.js +32 -38
  156. package/lib/requestLogger.ts +48 -0
  157. package/lib/responsesImageAdapter.js +351 -0
  158. package/lib/responsesImageAdapter.ts +352 -0
  159. package/lib/runtimePorts.js +71 -73
  160. package/lib/runtimePorts.ts +93 -0
  161. package/lib/sessionStore.js +179 -230
  162. package/lib/sessionStore.ts +272 -0
  163. package/lib/storageMigration.js +247 -245
  164. package/lib/storageMigration.ts +284 -0
  165. package/lib/styleSheet.js +86 -90
  166. package/lib/styleSheet.ts +128 -0
  167. package/lib/systemTrash.js +18 -0
  168. package/lib/systemTrash.ts +20 -0
  169. package/package.json +26 -10
  170. package/routes/annotations.js +76 -79
  171. package/routes/annotations.ts +95 -0
  172. package/routes/canvasVersions.js +50 -54
  173. package/routes/canvasVersions.ts +64 -0
  174. package/routes/cardNews.js +158 -171
  175. package/routes/cardNews.ts +183 -0
  176. package/routes/comfy.js +23 -31
  177. package/routes/comfy.ts +39 -0
  178. package/routes/edit.js +183 -214
  179. package/routes/edit.ts +230 -0
  180. package/routes/generate.js +269 -291
  181. package/routes/generate.ts +309 -0
  182. package/routes/health.js +102 -107
  183. package/routes/health.ts +114 -0
  184. package/routes/history.js +136 -144
  185. package/routes/history.ts +153 -0
  186. package/routes/imageImport.js +27 -27
  187. package/routes/imageImport.ts +33 -0
  188. package/routes/index.js +17 -17
  189. package/routes/index.ts +35 -0
  190. package/routes/metadata.js +60 -64
  191. package/routes/metadata.ts +71 -0
  192. package/routes/multimode.js +228 -263
  193. package/routes/multimode.ts +280 -0
  194. package/routes/nodes.js +378 -424
  195. package/routes/nodes.ts +455 -0
  196. package/routes/promptImport.js +284 -324
  197. package/routes/promptImport.ts +354 -0
  198. package/routes/prompts.js +333 -360
  199. package/routes/prompts.ts +379 -0
  200. package/routes/sessions.js +277 -285
  201. package/routes/sessions.ts +292 -0
  202. package/routes/storage.js +29 -31
  203. package/routes/storage.ts +39 -0
  204. package/server.js +189 -196
  205. package/server.ts +235 -0
  206. package/ui/dist/.vite/manifest.json +101 -0
  207. package/ui/dist/assets/CardNewsWorkspace-BJOCey7Z.js +2 -0
  208. package/ui/dist/assets/NodeCanvas-BZV40eAE.css +1 -0
  209. package/ui/dist/assets/NodeCanvas-C3dzYNsk.js +7 -0
  210. package/ui/dist/assets/PromptImportDialog-Dqu1VpUh.js +2 -0
  211. package/ui/dist/assets/PromptImportDiscoverySection-Dg8T9X0L.js +1 -0
  212. package/ui/dist/assets/PromptImportFolderSection-DBaqsFO4.js +1 -0
  213. package/ui/dist/assets/PromptLibraryPanel-p5QqR97M.js +2 -0
  214. package/ui/dist/assets/SettingsWorkspace-B5bSAZ6u.js +1 -0
  215. package/ui/dist/assets/index-C9cXwiWE.js +25 -0
  216. package/ui/dist/assets/index-CGMIkZXn.css +1 -0
  217. package/ui/dist/assets/index-Cvld7dUZ.js +1 -0
  218. package/ui/dist/index.html +2 -2
  219. package/assets/phase-a-bg-cleanup-test.png +0 -0
  220. package/assets/screenshot.png +0 -0
  221. package/assets/screenshots/classic-generate-light.png +0 -0
  222. package/assets/screenshots/node-graph-branching.png +0 -0
  223. package/assets/screenshots/settings-oauth-generation.png +0 -0
  224. package/assets/screenshots/settings-workspace.png +0 -0
  225. package/assets/screenshots/style-sheet-editor.png +0 -0
  226. package/integrations/comfyui/ima2_gen_bridge/__pycache__/__init__.cpython-313.pyc +0 -0
  227. package/integrations/comfyui/ima2_gen_bridge/__pycache__/nodes.cpython-313.pyc +0 -0
  228. package/ui/dist/assets/index-BDffwmLs.css +0 -1
  229. package/ui/dist/assets/index-D0fdHLkJ.js +0 -31
  230. package/ui/dist/assets/index-D0fdHLkJ.js.map +0 -1
@@ -2,110 +2,104 @@ import { mkdir, writeFile } from "fs/promises";
2
2
  import { basename, join, normalize } from "path";
3
3
  import { randomBytes } from "crypto";
4
4
  import { embedImageMetadataBestEffort } from "./imageMetadataStore.js";
5
-
6
5
  const PNG_SIGNATURE_HEX = "89504e470d0a1a0a";
7
6
  const JPEG_SIGNATURE_HEX = "ffd8ff";
8
7
  const WEBP_RIFF_HEAD = "52494646";
9
8
  const WEBP_VP_TAIL = "57454250";
10
-
11
9
  function detectFormat(buffer) {
12
- if (!Buffer.isBuffer(buffer) || buffer.length < 12) return null;
13
- const head8 = buffer.subarray(0, 8).toString("hex");
14
- if (head8 === PNG_SIGNATURE_HEX) return "png";
15
- if (head8.startsWith(JPEG_SIGNATURE_HEX)) return "jpeg";
16
- if (
17
- buffer.subarray(0, 4).toString("hex") === WEBP_RIFF_HEAD &&
18
- buffer.subarray(8, 12).toString("hex") === WEBP_VP_TAIL
19
- ) {
20
- return "webp";
21
- }
22
- return null;
10
+ if (!Buffer.isBuffer(buffer) || buffer.length < 12)
11
+ return null;
12
+ const head8 = buffer.subarray(0, 8).toString("hex");
13
+ if (head8 === PNG_SIGNATURE_HEX)
14
+ return "png";
15
+ if (head8.startsWith(JPEG_SIGNATURE_HEX))
16
+ return "jpeg";
17
+ if (buffer.subarray(0, 4).toString("hex") === WEBP_RIFF_HEAD &&
18
+ buffer.subarray(8, 12).toString("hex") === WEBP_VP_TAIL) {
19
+ return "webp";
20
+ }
21
+ return null;
23
22
  }
24
-
25
23
  function ensureInsideGeneratedDir(generatedDir, filename) {
26
- const full = normalize(join(generatedDir, filename));
27
- const root = normalize(generatedDir);
28
- if (!full.startsWith(root)) {
29
- const err = new Error("Imported path escapes generated directory");
30
- err.status = 400;
31
- err.code = "IMPORT_PATH_ESCAPE";
32
- throw err;
33
- }
34
- return full;
24
+ const full = normalize(join(generatedDir, filename));
25
+ const root = normalize(generatedDir);
26
+ if (!full.startsWith(root)) {
27
+ const err = new Error("Imported path escapes generated directory");
28
+ err.status = 400;
29
+ err.code = "IMPORT_PATH_ESCAPE";
30
+ throw err;
31
+ }
32
+ return full;
35
33
  }
36
-
37
34
  function makeImportedFilename(format) {
38
- const stamp = new Date().toISOString().slice(0, 19).replace(/[-:T]/g, "");
39
- const rand = randomBytes(3).toString("hex");
40
- return `imported-${stamp}-${rand}.${format}`;
35
+ const stamp = new Date().toISOString().slice(0, 19).replace(/[-:T]/g, "");
36
+ const rand = randomBytes(3).toString("hex");
37
+ return `imported-${stamp}-${rand}.${format}`;
41
38
  }
42
-
43
39
  function safeOriginalName(input) {
44
- if (typeof input !== "string" || !input) return null;
45
- const trimmed = input.slice(0, 200);
46
- return basename(trimmed);
40
+ if (typeof input !== "string" || !input)
41
+ return null;
42
+ const trimmed = input.slice(0, 200);
43
+ return basename(trimmed);
47
44
  }
48
-
49
45
  export async function createLocalImport(ctx, { buffer, originalFilename }) {
50
- if (!Buffer.isBuffer(buffer) || buffer.length === 0) {
51
- const err = new Error("Image body is required");
52
- err.status = 400;
53
- err.code = "EMPTY_IMPORT";
54
- throw err;
55
- }
56
- const format = detectFormat(buffer);
57
- if (!format) {
58
- const err = new Error("Only PNG, JPEG, or WebP is supported");
59
- err.status = 400;
60
- err.code = "IMPORT_BAD_FORMAT";
61
- throw err;
62
- }
63
- const filename = makeImportedFilename(format);
64
- const fullPath = ensureInsideGeneratedDir(ctx.config.storage.generatedDir, filename);
65
- await mkdir(ctx.config.storage.generatedDir, { recursive: true });
66
-
67
- const meta = {
68
- schema: "ima2.generation.v1",
69
- app: "ima2-gen",
70
- version: ctx.packageVersion,
71
- createdAt: Date.now(),
72
- kind: "imported",
73
- canvasVersion: false,
74
- originalFilename: safeOriginalName(originalFilename),
75
- format,
76
- };
77
- const embedded = await embedImageMetadataBestEffort(buffer, format, meta, {
78
- version: ctx.packageVersion,
79
- });
80
- await writeFile(fullPath, embedded.buffer);
81
- await writeFile(`${fullPath}.json`, JSON.stringify(meta)).catch(() => {});
82
-
83
- const url = `/generated/${encodeURIComponent(filename)}`;
84
- return {
85
- filename,
86
- url,
87
- image: url,
88
- thumb: url,
89
- createdAt: meta.createdAt,
90
- format,
91
- kind: "imported",
92
- canvasVersion: false,
93
- canvasSourceFilename: null,
94
- canvasEditableFilename: null,
95
- prompt: null,
96
- userPrompt: null,
97
- revisedPrompt: null,
98
- promptMode: null,
99
- quality: null,
100
- size: null,
101
- model: null,
102
- provider: null,
103
- usage: null,
104
- webSearchCalls: 0,
105
- sessionId: null,
106
- nodeId: null,
107
- parentNodeId: null,
108
- refsCount: 0,
109
- isFavorite: false,
110
- };
46
+ if (!Buffer.isBuffer(buffer) || buffer.length === 0) {
47
+ const err = new Error("Image body is required");
48
+ err.status = 400;
49
+ err.code = "EMPTY_IMPORT";
50
+ throw err;
51
+ }
52
+ const format = detectFormat(buffer);
53
+ if (!format) {
54
+ const err = new Error("Only PNG, JPEG, or WebP is supported");
55
+ err.status = 400;
56
+ err.code = "IMPORT_BAD_FORMAT";
57
+ throw err;
58
+ }
59
+ const filename = makeImportedFilename(format);
60
+ const fullPath = ensureInsideGeneratedDir(ctx.config.storage.generatedDir, filename);
61
+ await mkdir(ctx.config.storage.generatedDir, { recursive: true });
62
+ const meta = {
63
+ schema: "ima2.generation.v1",
64
+ app: "ima2-gen",
65
+ version: ctx.packageVersion,
66
+ createdAt: Date.now(),
67
+ kind: "imported",
68
+ canvasVersion: false,
69
+ originalFilename: safeOriginalName(originalFilename),
70
+ format,
71
+ };
72
+ const embedded = await embedImageMetadataBestEffort(buffer, format, meta, {
73
+ version: ctx.packageVersion,
74
+ });
75
+ await writeFile(fullPath, embedded.buffer);
76
+ await writeFile(`${fullPath}.json`, JSON.stringify(meta)).catch(() => { });
77
+ const url = `/generated/${encodeURIComponent(filename)}`;
78
+ return {
79
+ filename,
80
+ url,
81
+ image: url,
82
+ thumb: url,
83
+ createdAt: meta.createdAt,
84
+ format,
85
+ kind: "imported",
86
+ canvasVersion: false,
87
+ canvasSourceFilename: null,
88
+ canvasEditableFilename: null,
89
+ prompt: null,
90
+ userPrompt: null,
91
+ revisedPrompt: null,
92
+ promptMode: null,
93
+ quality: null,
94
+ size: null,
95
+ model: null,
96
+ provider: null,
97
+ usage: null,
98
+ webSearchCalls: 0,
99
+ sessionId: null,
100
+ nodeId: null,
101
+ parentNodeId: null,
102
+ refsCount: 0,
103
+ isFavorite: false,
104
+ };
111
105
  }
@@ -0,0 +1,111 @@
1
+ import { mkdir, writeFile } from "fs/promises";
2
+ import { basename, join, normalize } from "path";
3
+ import { randomBytes } from "crypto";
4
+ import { embedImageMetadataBestEffort } from "./imageMetadataStore.js";
5
+
6
+ const PNG_SIGNATURE_HEX = "89504e470d0a1a0a";
7
+ const JPEG_SIGNATURE_HEX = "ffd8ff";
8
+ const WEBP_RIFF_HEAD = "52494646";
9
+ const WEBP_VP_TAIL = "57454250";
10
+
11
+ function detectFormat(buffer) {
12
+ if (!Buffer.isBuffer(buffer) || buffer.length < 12) return null;
13
+ const head8 = buffer.subarray(0, 8).toString("hex");
14
+ if (head8 === PNG_SIGNATURE_HEX) return "png";
15
+ if (head8.startsWith(JPEG_SIGNATURE_HEX)) return "jpeg";
16
+ if (
17
+ buffer.subarray(0, 4).toString("hex") === WEBP_RIFF_HEAD &&
18
+ buffer.subarray(8, 12).toString("hex") === WEBP_VP_TAIL
19
+ ) {
20
+ return "webp";
21
+ }
22
+ return null;
23
+ }
24
+
25
+ function ensureInsideGeneratedDir(generatedDir, filename) {
26
+ const full = normalize(join(generatedDir, filename));
27
+ const root = normalize(generatedDir);
28
+ if (!full.startsWith(root)) {
29
+ const err: any = new Error("Imported path escapes generated directory");
30
+ err.status = 400;
31
+ err.code = "IMPORT_PATH_ESCAPE";
32
+ throw err;
33
+ }
34
+ return full;
35
+ }
36
+
37
+ function makeImportedFilename(format) {
38
+ const stamp = new Date().toISOString().slice(0, 19).replace(/[-:T]/g, "");
39
+ const rand = randomBytes(3).toString("hex");
40
+ return `imported-${stamp}-${rand}.${format}`;
41
+ }
42
+
43
+ function safeOriginalName(input) {
44
+ if (typeof input !== "string" || !input) return null;
45
+ const trimmed = input.slice(0, 200);
46
+ return basename(trimmed);
47
+ }
48
+
49
+ export async function createLocalImport(ctx, { buffer, originalFilename }) {
50
+ if (!Buffer.isBuffer(buffer) || buffer.length === 0) {
51
+ const err: any = new Error("Image body is required");
52
+ err.status = 400;
53
+ err.code = "EMPTY_IMPORT";
54
+ throw err;
55
+ }
56
+ const format = detectFormat(buffer);
57
+ if (!format) {
58
+ const err: any = new Error("Only PNG, JPEG, or WebP is supported");
59
+ err.status = 400;
60
+ err.code = "IMPORT_BAD_FORMAT";
61
+ throw err;
62
+ }
63
+ const filename = makeImportedFilename(format);
64
+ const fullPath = ensureInsideGeneratedDir(ctx.config.storage.generatedDir, filename);
65
+ await mkdir(ctx.config.storage.generatedDir, { recursive: true });
66
+
67
+ const meta = {
68
+ schema: "ima2.generation.v1",
69
+ app: "ima2-gen",
70
+ version: ctx.packageVersion,
71
+ createdAt: Date.now(),
72
+ kind: "imported",
73
+ canvasVersion: false,
74
+ originalFilename: safeOriginalName(originalFilename),
75
+ format,
76
+ };
77
+ const embedded = await embedImageMetadataBestEffort(buffer, format, meta, {
78
+ version: ctx.packageVersion,
79
+ });
80
+ await writeFile(fullPath, embedded.buffer);
81
+ await writeFile(`${fullPath}.json`, JSON.stringify(meta)).catch(() => {});
82
+
83
+ const url = `/generated/${encodeURIComponent(filename)}`;
84
+ return {
85
+ filename,
86
+ url,
87
+ image: url,
88
+ thumb: url,
89
+ createdAt: meta.createdAt,
90
+ format,
91
+ kind: "imported",
92
+ canvasVersion: false,
93
+ canvasSourceFilename: null,
94
+ canvasEditableFilename: null,
95
+ prompt: null,
96
+ userPrompt: null,
97
+ revisedPrompt: null,
98
+ promptMode: null,
99
+ quality: null,
100
+ size: null,
101
+ model: null,
102
+ provider: null,
103
+ usage: null,
104
+ webSearchCalls: 0,
105
+ sessionId: null,
106
+ nodeId: null,
107
+ parentNodeId: null,
108
+ refsCount: 0,
109
+ isFavorite: false,
110
+ };
111
+ }
package/lib/logger.js CHANGED
@@ -1,150 +1,143 @@
1
1
  const REDACTED = "[redacted]";
2
2
  const MAX_VALUE_LEN = 240;
3
3
  const LOG_LEVELS = {
4
- debug: 10,
5
- info: 20,
6
- warn: 30,
7
- error: 40,
8
- silent: 50,
4
+ debug: 10,
5
+ info: 20,
6
+ warn: 30,
7
+ error: 40,
8
+ silent: 50,
9
9
  };
10
-
11
10
  const SECRET_KEYS = new Set([
12
- "authorization",
13
- "cookie",
14
- "headers",
15
- "apiKey",
16
- "token",
17
- "password",
18
- "secret",
19
- "body",
20
- "prompt",
21
- "effectivePrompt",
22
- "userPrompt",
23
- "revisedPrompt",
24
- "textPrompt",
25
- "styleSheet",
26
- "style_sheet",
27
- "image",
28
- "imageB64",
29
- "image_url",
30
- "references",
31
- "rawResponse",
11
+ "authorization",
12
+ "cookie",
13
+ "headers",
14
+ "apiKey",
15
+ "token",
16
+ "password",
17
+ "secret",
18
+ "body",
19
+ "prompt",
20
+ "effectivePrompt",
21
+ "userPrompt",
22
+ "revisedPrompt",
23
+ "textPrompt",
24
+ "styleSheet",
25
+ "style_sheet",
26
+ "image",
27
+ "imageB64",
28
+ "image_url",
29
+ "references",
30
+ "rawResponse",
32
31
  ]);
33
-
34
32
  const ALLOWED_PROMPT_METRICS = new Set(["promptChars", "promptMode"]);
35
-
36
33
  let activeLevel = "info";
37
34
  let activeSink = console;
38
-
39
35
  function shouldRedactKey(key) {
40
- if (ALLOWED_PROMPT_METRICS.has(key)) return false;
41
- if (SECRET_KEYS.has(key)) return true;
42
- const lower = key.toLowerCase();
43
- return (
44
- lower.includes("token") ||
45
- lower.includes("authorization") ||
46
- lower.includes("cookie") ||
47
- lower.includes("apikey") ||
48
- lower.includes("api_key") ||
49
- lower.includes("secret") ||
50
- lower.includes("b64") ||
51
- lower.includes("base64") ||
52
- lower.includes("dataurl")
53
- );
36
+ if (ALLOWED_PROMPT_METRICS.has(key))
37
+ return false;
38
+ if (SECRET_KEYS.has(key))
39
+ return true;
40
+ const lower = key.toLowerCase();
41
+ return (lower.includes("token") ||
42
+ lower.includes("authorization") ||
43
+ lower.includes("cookie") ||
44
+ lower.includes("apikey") ||
45
+ lower.includes("api_key") ||
46
+ lower.includes("secret") ||
47
+ lower.includes("b64") ||
48
+ lower.includes("base64") ||
49
+ lower.includes("dataurl"));
54
50
  }
55
-
56
51
  function sanitizeValue(value) {
57
- if (value == null) return value;
58
- if (value instanceof Error) return sanitizeError(value);
59
- if (Array.isArray(value)) return `[array:${value.length}]`;
60
- if (Buffer.isBuffer(value)) return `[buffer:${value.length}]`;
61
- if (typeof value === "object") return "[object]";
62
- if (typeof value === "string") {
63
- const oneLine = value
64
- .replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [redacted]")
65
- .replace(/data:image\/[a-z0-9.+-]+;base64,[A-Za-z0-9+/=]+/gi, "data:image/[redacted]")
66
- .replace(/\s+/g, " ")
67
- .trim();
68
- return oneLine.length > MAX_VALUE_LEN ? `${oneLine.slice(0, MAX_VALUE_LEN)}...` : oneLine;
69
- }
70
- return value;
52
+ if (value == null)
53
+ return value;
54
+ if (value instanceof Error)
55
+ return sanitizeError(value);
56
+ if (Array.isArray(value))
57
+ return `[array:${value.length}]`;
58
+ if (Buffer.isBuffer(value))
59
+ return `[buffer:${value.length}]`;
60
+ if (typeof value === "object")
61
+ return "[object]";
62
+ if (typeof value === "string") {
63
+ const oneLine = value
64
+ .replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [redacted]")
65
+ .replace(/data:image\/[a-z0-9.+-]+;base64,[A-Za-z0-9+/=]+/gi, "data:image/[redacted]")
66
+ .replace(/\s+/g, " ")
67
+ .trim();
68
+ return oneLine.length > MAX_VALUE_LEN ? `${oneLine.slice(0, MAX_VALUE_LEN)}...` : oneLine;
69
+ }
70
+ return value;
71
71
  }
72
-
73
72
  export function sanitizeError(err) {
74
- if (!err) return { message: "Unknown error" };
75
- return {
76
- name: err.name || "Error",
77
- code: err.code || undefined,
78
- status: err.status || undefined,
79
- message: sanitizeValue(err.message || "Unknown error"),
80
- };
73
+ if (!err)
74
+ return { message: "Unknown error" };
75
+ return {
76
+ name: err.name || "Error",
77
+ code: err.code || undefined,
78
+ status: err.status || undefined,
79
+ message: sanitizeValue(err.message || "Unknown error"),
80
+ };
81
81
  }
82
-
83
82
  export function sanitizeFields(fields = {}) {
84
- const out = {};
85
- for (const [key, value] of Object.entries(fields)) {
86
- out[key] = shouldRedactKey(key) ? REDACTED : sanitizeValue(value);
87
- }
88
- return out;
83
+ const out = {};
84
+ for (const [key, value] of Object.entries(fields)) {
85
+ out[key] = shouldRedactKey(key) ? REDACTED : sanitizeValue(value);
86
+ }
87
+ return out;
89
88
  }
90
-
91
89
  function formatValue(value) {
92
- if (value === undefined) return undefined;
93
- if (value === null) return "null";
94
- if (typeof value === "boolean" || typeof value === "number") return String(value);
95
- return JSON.stringify(String(value));
90
+ if (value === undefined)
91
+ return undefined;
92
+ if (value === null)
93
+ return "null";
94
+ if (typeof value === "boolean" || typeof value === "number")
95
+ return String(value);
96
+ return JSON.stringify(String(value));
96
97
  }
97
-
98
98
  export function formatLog(scope, event, fields = {}) {
99
- const safeFields = sanitizeFields(fields);
100
- const parts = Object.entries(safeFields)
101
- .map(([key, value]) => {
102
- const formatted = formatValue(value);
103
- return formatted === undefined ? null : `${key}=${formatted}`;
99
+ const safeFields = sanitizeFields(fields);
100
+ const parts = Object.entries(safeFields)
101
+ .map(([key, value]) => {
102
+ const formatted = formatValue(value);
103
+ return formatted === undefined ? null : `${key}=${formatted}`;
104
104
  })
105
- .filter(Boolean);
106
- return `[${scope}.${event}]${parts.length ? ` ${parts.join(" ")}` : ""}`;
105
+ .filter(Boolean);
106
+ return `[${scope}.${event}]${parts.length ? ` ${parts.join(" ")}` : ""}`;
107
107
  }
108
-
109
108
  export function normalizeLogLevel(level) {
110
- return typeof level === "string" && Object.hasOwn(LOG_LEVELS, level) ? level : "info";
109
+ return typeof level === "string" && Object.hasOwn(LOG_LEVELS, level) ? level : "info";
111
110
  }
112
-
113
111
  export function configureLogger(options = {}) {
114
- activeLevel = normalizeLogLevel(options.level);
115
- activeSink = options.sink || console;
112
+ activeLevel = normalizeLogLevel(options.level);
113
+ activeSink = options.sink || console;
116
114
  }
117
-
118
115
  export function shouldLog(level) {
119
- const normalized = normalizeLogLevel(level);
120
- return LOG_LEVELS[normalized] >= LOG_LEVELS[activeLevel] && activeLevel !== "silent";
116
+ const normalized = normalizeLogLevel(level);
117
+ return LOG_LEVELS[normalized] >= LOG_LEVELS[activeLevel] && activeLevel !== "silent";
121
118
  }
122
-
123
119
  function writeLog(level, line) {
124
- if (!shouldLog(level)) return;
125
- const writer = activeSink[level] || activeSink.log || console.log;
126
- writer.call(activeSink, line);
120
+ if (!shouldLog(level))
121
+ return;
122
+ const writer = activeSink[level] || activeSink.log || console.log;
123
+ writer.call(activeSink, line);
127
124
  }
128
-
129
125
  export function logDebug(scope, event, fields = {}) {
130
- writeLog("debug", formatLog(scope, event, fields));
126
+ writeLog("debug", formatLog(scope, event, fields));
131
127
  }
132
-
133
128
  export function logEvent(scope, event, fields = {}) {
134
- writeLog("info", formatLog(scope, event, fields));
129
+ writeLog("info", formatLog(scope, event, fields));
135
130
  }
136
-
137
131
  export function logWarn(scope, event, fields = {}) {
138
- writeLog("warn", formatLog(scope, event, fields));
132
+ writeLog("warn", formatLog(scope, event, fields));
139
133
  }
140
-
141
134
  export function logError(scope, event, err, fields = {}) {
142
- const safe = sanitizeError(err);
143
- writeLog("error", formatLog(scope, event, {
144
- ...fields,
145
- errorName: safe.name,
146
- errorCode: safe.code,
147
- errorStatus: safe.status,
148
- errorMessage: safe.message,
149
- }));
135
+ const safe = sanitizeError(err);
136
+ writeLog("error", formatLog(scope, event, {
137
+ ...fields,
138
+ errorName: safe.name,
139
+ errorCode: safe.code,
140
+ errorStatus: safe.status,
141
+ errorMessage: safe.message,
142
+ }));
150
143
  }