@needle-tools/engine 4.14.0 → 4.15.0-next.f391a30

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 (198) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/components.needle.json +1 -1
  3. package/dist/{gltf-progressive-BttGBXw6.umd.cjs → gltf-progressive-CMwJPwEt.umd.cjs} +1 -1
  4. package/dist/{gltf-progressive-Bm_6aEi4.js → gltf-progressive-CTlvpS3A.js} +1 -1
  5. package/dist/{gltf-progressive-T5WKTux5.min.js → gltf-progressive-DYL3SLVb.min.js} +1 -1
  6. package/dist/materialx-4jJLLe9Q.js +4174 -0
  7. package/dist/materialx-Bt9FHwco.min.js +158 -0
  8. package/dist/materialx-NDD0y4JY.umd.cjs +158 -0
  9. package/dist/{needle-engine.bundle-COL2Bar3.umd.cjs → needle-engine.bundle-C1BFRZDF.umd.cjs} +150 -140
  10. package/dist/{needle-engine.bundle-Z_gAD7Kg.js → needle-engine.bundle-DB4kLWO_.js} +6651 -6400
  11. package/dist/{needle-engine.bundle-NolzHLqO.min.js → needle-engine.bundle-DsTdfmeb.min.js} +151 -141
  12. package/dist/needle-engine.d.ts +345 -88
  13. package/dist/needle-engine.js +322 -322
  14. package/dist/needle-engine.min.js +1 -1
  15. package/dist/needle-engine.umd.cjs +1 -1
  16. package/dist/{postprocessing-06AXuvdv.min.js → postprocessing-BN-f4viE.min.js} +1 -1
  17. package/dist/{postprocessing-CPDcA21P.umd.cjs → postprocessing-DYmYOVm4.umd.cjs} +1 -1
  18. package/dist/{postprocessing-CI2x8Cln.js → postprocessing-De9ZpJrk.js} +1 -1
  19. package/dist/{three-examples-BMmNgNCN.umd.cjs → three-examples-BHqRVpO_.umd.cjs} +12 -12
  20. package/dist/{three-examples-CMYCd5nH.js → three-examples-C0ZCCA_K.js} +182 -192
  21. package/dist/{three-examples-CQl1fFZp.min.js → three-examples-DmTY8tGr.min.js} +14 -14
  22. package/lib/engine/api.d.ts +0 -2
  23. package/lib/engine/api.js +0 -2
  24. package/lib/engine/api.js.map +1 -1
  25. package/lib/engine/debug/debug.js +1 -1
  26. package/lib/engine/debug/debug.js.map +1 -1
  27. package/lib/engine/debug/debug_spatial_console.js +1 -1
  28. package/lib/engine/debug/debug_spatial_console.js.map +1 -1
  29. package/lib/engine/engine_accessibility.d.ts +77 -0
  30. package/lib/engine/engine_accessibility.js +162 -0
  31. package/lib/engine/engine_accessibility.js.map +1 -0
  32. package/lib/engine/engine_context.d.ts +2 -0
  33. package/lib/engine/engine_context.js +8 -1
  34. package/lib/engine/engine_context.js.map +1 -1
  35. package/lib/engine/engine_create_objects.js +1 -1
  36. package/lib/engine/engine_create_objects.js.map +1 -1
  37. package/lib/engine/engine_gizmos.js +1 -1
  38. package/lib/engine/engine_gizmos.js.map +1 -1
  39. package/lib/engine/engine_license.js +7 -2
  40. package/lib/engine/engine_license.js.map +1 -1
  41. package/lib/engine/engine_materialpropertyblock.d.ts +90 -4
  42. package/lib/engine/engine_materialpropertyblock.js +97 -7
  43. package/lib/engine/engine_materialpropertyblock.js.map +1 -1
  44. package/lib/engine/engine_math.d.ts +34 -1
  45. package/lib/engine/engine_math.js +34 -1
  46. package/lib/engine/engine_math.js.map +1 -1
  47. package/lib/engine/engine_networking.js +1 -1
  48. package/lib/engine/engine_networking.js.map +1 -1
  49. package/lib/engine/engine_types.d.ts +2 -0
  50. package/lib/engine/engine_types.js +2 -0
  51. package/lib/engine/engine_types.js.map +1 -1
  52. package/lib/engine/engine_utils.js +2 -2
  53. package/lib/engine/engine_utils.js.map +1 -1
  54. package/lib/engine/export/gltf/EXT_mesh_gpu_instancing_exporter.js.map +1 -0
  55. package/lib/engine/export/gltf/index.js +1 -1
  56. package/lib/engine/export/gltf/index.js.map +1 -1
  57. package/lib/engine/webcomponents/icons.js +3 -0
  58. package/lib/engine/webcomponents/icons.js.map +1 -1
  59. package/lib/engine/webcomponents/logo-element.d.ts +7 -3
  60. package/lib/engine/webcomponents/logo-element.js +21 -1
  61. package/lib/engine/webcomponents/logo-element.js.map +1 -1
  62. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
  63. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
  64. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +10 -7
  65. package/lib/engine/webcomponents/needle menu/needle-menu.js +14 -4
  66. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  67. package/lib/engine/webcomponents/needle-button.d.ts +37 -11
  68. package/lib/engine/webcomponents/needle-button.js +42 -11
  69. package/lib/engine/webcomponents/needle-button.js.map +1 -1
  70. package/lib/engine/webcomponents/needle-engine.ar-overlay.js +10 -1
  71. package/lib/engine/webcomponents/needle-engine.ar-overlay.js.map +1 -1
  72. package/lib/engine/webcomponents/needle-engine.d.ts +13 -2
  73. package/lib/engine/webcomponents/needle-engine.js +23 -3
  74. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  75. package/lib/engine-components/Component.d.ts +1 -2
  76. package/lib/engine-components/Component.js +1 -3
  77. package/lib/engine-components/Component.js.map +1 -1
  78. package/lib/engine-components/DragControls.d.ts +1 -0
  79. package/lib/engine-components/DragControls.js +21 -0
  80. package/lib/engine-components/DragControls.js.map +1 -1
  81. package/lib/engine-components/NeedleMenu.d.ts +2 -0
  82. package/lib/engine-components/NeedleMenu.js +2 -0
  83. package/lib/engine-components/NeedleMenu.js.map +1 -1
  84. package/lib/engine-components/Networking.d.ts +28 -3
  85. package/lib/engine-components/Networking.js +28 -3
  86. package/lib/engine-components/Networking.js.map +1 -1
  87. package/lib/engine-components/ReflectionProbe.d.ts +25 -2
  88. package/lib/engine-components/ReflectionProbe.js +46 -2
  89. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  90. package/lib/engine-components/Skybox.js +4 -2
  91. package/lib/engine-components/Skybox.js.map +1 -1
  92. package/lib/engine-components/export/gltf/GltfExport.js +1 -1
  93. package/lib/engine-components/export/gltf/GltfExport.js.map +1 -1
  94. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +2 -2
  95. package/lib/engine-components/export/usdz/USDZExporter.js +1 -1
  96. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  97. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.d.ts +15 -0
  98. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +77 -0
  99. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js.map +1 -1
  100. package/lib/engine-components/export/usdz/extensions/behavior/PhysicsExtension.js +2 -2
  101. package/lib/engine-components/export/usdz/extensions/behavior/PhysicsExtension.js.map +1 -1
  102. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
  103. package/lib/engine-components/ui/Button.d.ts +1 -0
  104. package/lib/engine-components/ui/Button.js +11 -0
  105. package/lib/engine-components/ui/Button.js.map +1 -1
  106. package/lib/engine-components/ui/Text.d.ts +1 -0
  107. package/lib/engine-components/ui/Text.js +11 -0
  108. package/lib/engine-components/ui/Text.js.map +1 -1
  109. package/package.json +18 -14
  110. package/plugins/common/buildinfo.js +46 -10
  111. package/plugins/common/files.js +2 -1
  112. package/plugins/common/license.js +144 -69
  113. package/plugins/common/logger.js +172 -11
  114. package/plugins/common/needle-engine-skill.md +175 -0
  115. package/plugins/common/worker.js +5 -4
  116. package/plugins/types/userconfig.d.ts +40 -2
  117. package/plugins/vite/ai.js +71 -0
  118. package/plugins/vite/alias.js +6 -5
  119. package/plugins/vite/asap.js +6 -5
  120. package/plugins/vite/build-pipeline.js +224 -41
  121. package/plugins/vite/buildinfo.js +66 -6
  122. package/plugins/vite/copyfiles.js +41 -12
  123. package/plugins/vite/custom-element-data.js +26 -16
  124. package/plugins/vite/defines.js +8 -5
  125. package/plugins/vite/dependencies.js +16 -10
  126. package/plugins/vite/dependency-watcher.js +35 -7
  127. package/plugins/vite/drop-client.js +7 -5
  128. package/plugins/vite/drop.js +16 -14
  129. package/plugins/vite/editor-connection.js +18 -16
  130. package/plugins/vite/imports-logger.js +12 -2
  131. package/plugins/vite/index.js +8 -3
  132. package/plugins/vite/local-files-analysis.js +789 -0
  133. package/plugins/vite/local-files-core.js +992 -0
  134. package/plugins/vite/local-files-internals.js +28 -0
  135. package/plugins/vite/local-files-types.d.ts +111 -0
  136. package/plugins/vite/local-files-utils.js +359 -0
  137. package/plugins/vite/local-files.js +2 -441
  138. package/plugins/vite/logger.client.js +45 -35
  139. package/plugins/vite/logger.js +6 -3
  140. package/plugins/vite/logging.js +129 -0
  141. package/plugins/vite/meta.js +18 -4
  142. package/plugins/vite/needle-app.js +4 -3
  143. package/plugins/vite/peer.js +2 -1
  144. package/plugins/vite/pwa.js +33 -17
  145. package/plugins/vite/reload.js +24 -2
  146. package/src/engine/api.ts +0 -3
  147. package/src/engine/debug/debug.ts +1 -1
  148. package/src/engine/debug/debug_spatial_console.ts +5 -1
  149. package/src/engine/engine_accessibility.ts +198 -0
  150. package/src/engine/engine_context.ts +10 -1
  151. package/src/engine/engine_create_objects.ts +1 -1
  152. package/src/engine/engine_gizmos.ts +9 -5
  153. package/src/engine/engine_license.ts +7 -2
  154. package/src/engine/engine_materialpropertyblock.ts +102 -11
  155. package/src/engine/engine_math.ts +34 -1
  156. package/src/engine/engine_networking.ts +1 -1
  157. package/src/engine/engine_types.ts +5 -0
  158. package/src/engine/engine_utils.ts +2 -2
  159. package/src/engine/export/gltf/index.ts +1 -1
  160. package/src/engine/webcomponents/icons.ts +3 -0
  161. package/src/engine/webcomponents/logo-element.ts +24 -4
  162. package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +6 -2
  163. package/src/engine/webcomponents/needle menu/needle-menu.ts +23 -11
  164. package/src/engine/webcomponents/needle-button.ts +44 -13
  165. package/src/engine/webcomponents/needle-engine.ar-overlay.ts +13 -2
  166. package/src/engine/webcomponents/needle-engine.ts +31 -8
  167. package/src/engine-components/Component.ts +2 -5
  168. package/src/engine-components/DragControls.ts +29 -4
  169. package/src/engine-components/NeedleMenu.ts +5 -3
  170. package/src/engine-components/Networking.ts +29 -4
  171. package/src/engine-components/ReflectionProbe.ts +52 -9
  172. package/src/engine-components/Skybox.ts +4 -2
  173. package/src/engine-components/export/gltf/GltfExport.ts +1 -1
  174. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +2 -2
  175. package/src/engine-components/export/usdz/USDZExporter.ts +1 -1
  176. package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +108 -32
  177. package/src/engine-components/export/usdz/extensions/behavior/PhysicsExtension.ts +2 -2
  178. package/src/engine-components/ui/Button.ts +12 -0
  179. package/src/engine-components/ui/Text.ts +13 -0
  180. package/dist/materialx-CJyQZtjt.min.js +0 -90
  181. package/dist/materialx-DMs1E08Z.js +0 -4636
  182. package/dist/materialx-DaKKOoVk.umd.cjs +0 -90
  183. package/lib/engine/engine_test_utils.d.ts +0 -39
  184. package/lib/engine/engine_test_utils.js +0 -84
  185. package/lib/engine/engine_test_utils.js.map +0 -1
  186. package/lib/include/three/EXT_mesh_gpu_instancing_exporter.js.map +0 -1
  187. package/src/engine/engine_test_utils.ts +0 -109
  188. package/src/include/draco/draco_decoder.js +0 -34
  189. package/src/include/draco/draco_decoder.wasm +0 -0
  190. package/src/include/draco/draco_wasm_wrapper.js +0 -117
  191. package/src/include/ktx2/basis_transcoder.js +0 -19
  192. package/src/include/ktx2/basis_transcoder.wasm +0 -0
  193. package/src/include/needle/arial-msdf.json +0 -1472
  194. package/src/include/needle/arial.png +0 -0
  195. package/src/include/needle/poweredbyneedle.webp +0 -0
  196. /package/lib/{include/three → engine/export/gltf}/EXT_mesh_gpu_instancing_exporter.d.ts +0 -0
  197. /package/lib/{include/three → engine/export/gltf}/EXT_mesh_gpu_instancing_exporter.js +0 -0
  198. /package/src/{include/three → engine/export/gltf}/EXT_mesh_gpu_instancing_exporter.js +0 -0
@@ -1,8 +1,10 @@
1
+ // @ts-check
1
2
  import { spawn } from "child_process";
2
3
  import { NEEDLE_CLOUD_CLI_NAME } from "./cloud.js";
3
4
  import { existsSync } from "fs";
4
5
  import http from "http";
5
6
  import https from "https";
7
+ import { needleLog } from "../vite/logging.js";
6
8
 
7
9
  const port = 8424;
8
10
  const localServerUrl = `http://localhost:${port}`;
@@ -10,10 +12,80 @@ const licenseServerUrl = `http://localhost:${port}/api/license`;
10
12
  const projectIdentifierUrl = `http://localhost:${port}/api/public_key`;
11
13
  const needleCloudApiEndpoint = "https://cloud.needle.tools/api";
12
14
 
15
+ /** @param {string} message @param {string} [level] */
16
+ function logLicense(message, level = "log") {
17
+ needleLog("needle-license", message, level);
18
+ }
19
+
20
+ /** @param {string} message @param {string} [level] */
21
+ function logIdentifier(message, level = "log") {
22
+ needleLog("needle-identifier", message, level);
23
+ }
24
+
25
+ /**
26
+ * Ensure response streams are fully released to avoid lingering sockets.
27
+ * @param {Response | null | undefined} response
28
+ */
29
+ async function releaseResponse(response) {
30
+ if (!response?.body) return;
31
+ try {
32
+ await response.arrayBuffer();
33
+ }
34
+ catch {
35
+ try {
36
+ await response.body.cancel();
37
+ }
38
+ catch {
39
+ // ignore
40
+ }
41
+ }
42
+ }
43
+
44
+ /**
45
+ * @param {string} path
46
+ * @param {{ method:"GET"|"POST", accessToken:string, body?: Record<string, any>, timeoutMs:number }} options
47
+ * @returns {Promise<NeedleCloudHttpResponse>}
48
+ */
49
+ async function requestNeedleCloud(path, options) {
50
+ const url = new URL(`${needleCloudApiEndpoint}${path}`);
51
+ const requestBody = options.body ? JSON.stringify(options.body) : undefined;
52
+ return new Promise((resolve, reject) => {
53
+ const req = https.request(url, {
54
+ method: options.method,
55
+ agent: false,
56
+ timeout: options.timeoutMs,
57
+ headers: {
58
+ Authorization: `Bearer ${options.accessToken}`,
59
+ "x-needle": "cli",
60
+ "Connection": "close",
61
+ ...(requestBody ? { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(requestBody) } : {}),
62
+ }
63
+ }, (res) => {
64
+ let text = "";
65
+ res.setEncoding("utf8");
66
+ res.on("data", (/** @type {Buffer|string} */ chunk) => text += chunk);
67
+ res.on("end", () => {
68
+ resolve({
69
+ ok: (res.statusCode || 500) >= 200 && (res.statusCode || 500) < 300,
70
+ status: res.statusCode || 500,
71
+ statusText: res.statusMessage || "",
72
+ text,
73
+ });
74
+ });
75
+ });
76
+ req.on("timeout", () => req.destroy(new Error("Request timed out")));
77
+ req.on("error", reject);
78
+ if (requestBody) req.write(requestBody);
79
+ req.end();
80
+ });
81
+ }
82
+
13
83
  /**
14
84
  * @typedef {{loglevel?:"verbose"}} DefaultOptions
15
85
  */
16
86
 
87
+ /** @typedef {{ ok: boolean, status: number, statusText: string, text: string }} NeedleCloudHttpResponse */
88
+
17
89
  /**
18
90
  * Replace license string - used for webpack
19
91
  * @param {string} code
@@ -48,37 +120,31 @@ export async function resolveLicense(args = null) {
48
120
  // If a process.env.NEEDLE_CLOUD_TOKEN is set we want to use this (e.g. via nextjs)
49
121
  if (!accessToken) {
50
122
  if (process.env.NEEDLE_CLOUD_TOKEN) {
51
- console.log("[needle-license] INFO: Using Needle Cloud access token from NEEDLE_CLOUD_TOKEN environment variable");
123
+ logLicense("INFO: Using Needle Cloud access token from NEEDLE_CLOUD_TOKEN environment variable");
52
124
  accessToken = process.env.NEEDLE_CLOUD_TOKEN;
53
125
  }
54
126
  else if (process.env.CI) {
55
- console.warn("[needle-license] WARN: Missing NEEDLE_CLOUD_TOKEN for CI environment");
127
+ logLicense("WARN: Missing NEEDLE_CLOUD_TOKEN for CI environment", "warn");
56
128
  }
57
129
  }
58
130
 
59
131
  if (accessToken) {
60
- const timeout = AbortSignal.timeout(10_000);
61
- const url = new URL(`${needleCloudApiEndpoint}/v1/account/get/licenses`);
62
- const res = await fetch(url, {
132
+ const res = await requestNeedleCloud("/v1/account/get/licenses", {
63
133
  method: "GET",
64
- signal: timeout,
65
- headers: {
66
- Authorization: `Bearer ${accessToken}`,
67
- "x-needle": "cli"
68
- }
69
- }).catch(err => {
134
+ accessToken,
135
+ timeoutMs: 10_000,
136
+ }).catch((/** @type {{ message?: string }} */ err) => {
70
137
  return { ok: false, error: err.message };
71
138
  });
72
139
  if ("error" in res) {
73
- console.error(`[needle-license] Could not fetch license from Needle Cloud API (${res.error})`);
140
+ logLicense(`Could not fetch license from Needle Cloud API (${res.error})`, "error");
74
141
  return null;
75
142
  }
76
143
  if (res.ok) {
77
- const text = await res.text();
78
- return tryParseLicense(text);
144
+ return tryParseLicense(res.text);
79
145
  }
80
146
  else {
81
- console.error(`[needle-license] Could not fetch license from Needle Cloud API (${res.status})`);
147
+ logLicense(`Could not fetch license from Needle Cloud API (${res.status})`, "error");
82
148
  if (process.env.CI) {
83
149
  return null;
84
150
  }
@@ -86,26 +152,26 @@ export async function resolveLicense(args = null) {
86
152
  }
87
153
  else if (process.env.CI) {
88
154
  const isGithubCI = process.env.GITHUB_ACTIONS;
89
- let message = "[needle-license] WARN: Missing NEEDLE_CLOUD_TOKEN for CI environment run.";
155
+ let message = "WARN: Missing NEEDLE_CLOUD_TOKEN for CI environment run.";
90
156
  if (isGithubCI) {
91
157
  const repositoryUrl = process.env.GITHUB_REPOSITORY;
92
158
  const url = `${repositoryUrl}/settings/secrets/actions`;
93
159
  message += `\nPlease add the token to your GitHub repository secrets: ${url}`;
94
160
  }
95
- console.warn(message);
161
+ logLicense(message, "warn");
96
162
  return null;
97
163
  }
98
164
 
99
165
 
100
166
  if (!canRunCLI(args)) {
101
- console.error("[needle-license] License server CLI is not available. Please use an access token for authorization.");
167
+ logLicense("License server CLI is not available. Please use an access token for authorization.", "error");
102
168
  return null;
103
169
  }
104
170
 
105
171
  // Fallback to use CLI
106
172
  // Wait for the server to start
107
173
  if (!await waitForLicenseServer(args || undefined)) {
108
- console.error("[needle-license] ERR: Failed to start license server...");
174
+ logLicense("ERR: Failed to start license server...", "error");
109
175
  return null;
110
176
  }
111
177
 
@@ -116,12 +182,15 @@ export async function resolveLicense(args = null) {
116
182
  url.searchParams.append("token", accessToken);
117
183
  }
118
184
 
119
- console.log(`[needle-license] INFO: Fetching license...`);
185
+ const includeFetchLineInSuccessLog = true;
120
186
  const timeout = AbortSignal.timeout(10_000);
121
187
  const licenseResponse = await fetch(url.toString(), {
122
188
  method: "GET",
123
- signal: timeout
124
- }).catch(err => {
189
+ signal: timeout,
190
+ headers: {
191
+ "Connection": "close"
192
+ }
193
+ }).catch((/** @type {{ message?: string, cause?: { code?: string } }} */ err) => {
125
194
  if (args?.loglevel === "verbose") console.error("Error fetching license", err.message);
126
195
 
127
196
  if (err.cause?.code === "ECONNREFUSED") {
@@ -133,7 +202,7 @@ export async function resolveLicense(args = null) {
133
202
  });
134
203
 
135
204
  if (!licenseResponse) {
136
- console.warn("[needle-license] WARN: Failed to fetch license");
205
+ logLicense("WARN: Failed to fetch license", "warn");
137
206
  return null;
138
207
  }
139
208
  else if ("error" in licenseResponse) {
@@ -142,41 +211,49 @@ export async function resolveLicense(args = null) {
142
211
  }
143
212
  else if (!licenseResponse.ok) {
144
213
  if (licenseResponse.status === 500)
145
- console.error(`[needle-license] ERROR: Failed to fetch license (${licenseResponse.status})`);
214
+ logLicense(`ERROR: Failed to fetch license (${licenseResponse.status})`, "error");
146
215
  else
147
- console.log(`[needle-license] No license found (${licenseResponse.status})`);
216
+ logLicense(`No license found (${licenseResponse.status})`);
217
+ await releaseResponse(licenseResponse);
148
218
  return null;
149
219
  }
150
220
 
151
221
  const text = await licenseResponse.text();
152
- return tryParseLicense(text);
222
+ return tryParseLicense(text, { includeFetchLine: includeFetchLineInSuccessLog });
153
223
  }
154
224
 
155
225
 
156
226
  /**
157
227
  * @param {string} str License string
228
+ * @param {{includeFetchLine?: boolean}} [options]
158
229
  */
159
- function tryParseLicense(str) {
230
+ function tryParseLicense(str, options = undefined) {
160
231
  try {
161
232
  /** @type {{needle_engine_license:string}} */
162
233
  const licenseJson = JSON.parse(str);
163
234
  if (licenseJson.needle_engine_license) {
164
- console.log(`[needle-license] INFO: Successfully received \"${licenseJson.needle_engine_license?.toUpperCase()}\" license`)
235
+ const success = `INFO: Successfully received \"${licenseJson.needle_engine_license?.toUpperCase()}\" license`;
236
+ if (options?.includeFetchLine) {
237
+ logLicense(`INFO: Fetching license...\n${success}`);
238
+ }
239
+ else {
240
+ logLicense(success);
241
+ }
165
242
  return licenseJson.needle_engine_license;
166
243
  }
167
244
  if ("error" in licenseJson) {
168
- console.error(`[needle-license] ERROR in license check: \"${licenseJson.error}\"`);
245
+ logLicense(`ERROR in license check: \"${licenseJson.error}\"`, "error");
169
246
  }
170
247
  else if (licenseJson.needle_engine_license == null) {
171
248
  return null;
172
249
  }
173
250
  else {
174
- console.warn("[needle-license] WARN: Received invalid license.", licenseJson);
251
+ logLicense("WARN: Received invalid license. " + JSON.stringify(licenseJson), "warn");
175
252
  }
176
253
  return null;
177
254
  }
178
- catch (err) {
179
- console.error("[needle-license] ERROR: Failed to parse license response");
255
+ catch (/** @type {unknown} */ err) {
256
+ logLicense("ERROR: Failed to parse license response", "error");
180
257
  return null;
181
258
  }
182
259
  }
@@ -188,58 +265,50 @@ function tryParseLicense(str) {
188
265
  */
189
266
  export async function getPublicIdentifier(project_id, opts = undefined) {
190
267
 
191
- let accessToken = undefined;
268
+ let accessToken = /** @type {string | undefined} */ (undefined);
192
269
  if (!accessToken) {
193
270
 
194
- if (opts?.loglevel === "verbose" && process.env.CI) console.debug("[needle-identifier] INFO: Running in CI environment");
271
+ if (opts?.loglevel === "verbose" && process.env.CI) logIdentifier("INFO: Running in CI environment");
195
272
 
196
273
  if (process.env.NEEDLE_CLOUD_TOKEN) {
197
- console.log("[needle-identifier] INFO: Using Needle Cloud access token from environment variable");
274
+ logIdentifier("INFO: Using Needle Cloud access token from environment variable");
198
275
  accessToken = process.env.NEEDLE_CLOUD_TOKEN;
199
276
  }
200
277
 
201
278
  if (accessToken) {
202
- const url = new URL(`${needleCloudApiEndpoint}/v1/account/public_key`);
203
279
  const body = {
204
280
  project_id: project_id || process.env.GITHUB_REPOSITORY || undefined,
205
281
  machine_id: process.env.GITHUB_REPOSITORY_ID || "unknown",
206
282
  }
207
- const timeout = AbortSignal.timeout(10_000);
208
- const res = await fetch(url, {
283
+ const res = await requestNeedleCloud("/v1/account/public_key", {
209
284
  method: "POST",
210
- signal: timeout,
211
- headers: {
212
- Authorization: `Bearer ${accessToken}`,
213
- "Content-Type": "application/json",
214
- "x-needle": "cli"
215
- },
216
- body: JSON.stringify(body),
217
- }).catch(err => {
285
+ accessToken,
286
+ timeoutMs: 10_000,
287
+ body,
288
+ }).catch((/** @type {{ message?: string }} */ err) => {
218
289
  if (opts?.loglevel === "verbose") {
219
290
  console.error(err);
220
291
  }
221
292
  return { ok: false, error: err.message };
222
293
  });
223
294
  if ("error" in res) {
224
- console.error(`[needle-identifier] Could not fetch project identifier from Needle Cloud API (${res.error})`);
295
+ logIdentifier(`Could not fetch project identifier from Needle Cloud API (${res.error})`, "error");
225
296
  return null;
226
297
  }
227
298
  if (res.ok) {
228
- const text = await res.text();
229
299
  try {
230
300
  /** @type {{public_key:string}} */
231
- const json = JSON.parse(text);
232
- console.log(`[needle-identifier] INFO: Successfully received public project identifier`);
301
+ const json = JSON.parse(res.text);
302
+ logIdentifier(`INFO: Successfully received public project identifier`);
233
303
  return json.public_key;
234
304
  }
235
- catch (err) {
236
- console.error("[needle-identifier] ERROR: Failed to parse project identifier response");
305
+ catch (/** @type {unknown} */ err) {
306
+ logIdentifier("ERROR: Failed to parse project identifier response", "error");
237
307
  return null;
238
308
  }
239
309
  }
240
310
  else {
241
- const message = await res.text();
242
- console.error(`[needle-identifier] Could not fetch project identifier from Needle Cloud API (${res.status}, ${res.statusText}, ${message})`);
311
+ logIdentifier(`Could not fetch project identifier from Needle Cloud API (${res.status}, ${res.statusText}, ${res.text})`, "error");
243
312
  return null;
244
313
  }
245
314
  }
@@ -247,7 +316,7 @@ export async function getPublicIdentifier(project_id, opts = undefined) {
247
316
 
248
317
 
249
318
  if (!canRunCLI(opts)) {
250
- console.error("[needle-license] License server CLI is not available. Please use an access token for authorization.");
319
+ logLicense("License server CLI is not available. Please use an access token for authorization.", "error");
251
320
  return null;
252
321
  }
253
322
 
@@ -255,18 +324,21 @@ export async function getPublicIdentifier(project_id, opts = undefined) {
255
324
 
256
325
  // Wait for the server to start
257
326
  if (!await waitForLicenseServer(opts)) {
258
- console.error("[needle-identifier] ERR: Failed to start license server...");
327
+ logIdentifier("ERR: Failed to start license server...", "error");
259
328
  return null;
260
329
  }
261
330
 
262
- console.log(`[needle-identifier] INFO: Fetching project identifier...`);
331
+ logIdentifier(`INFO: Fetching project identifier...`);
263
332
  const url = new URL(projectIdentifierUrl);
264
333
  if (project_id) url.searchParams.append("project_id", project_id);
265
334
  const timeout = AbortSignal.timeout(5_000);
266
335
  const res = await fetch(projectIdentifierUrl, {
267
336
  method: "GET",
268
- signal: timeout
269
- }).catch(err => {
337
+ signal: timeout,
338
+ headers: {
339
+ "Connection": "close"
340
+ }
341
+ }).catch((/** @type {{ message?: string, cause?: { code?: string } }} */ err) => {
270
342
 
271
343
  if (opts?.loglevel === "verbose") {
272
344
  console.error(err);
@@ -281,7 +353,7 @@ export async function getPublicIdentifier(project_id, opts = undefined) {
281
353
  })
282
354
 
283
355
  if (!res) {
284
- console.warn("[needle-identifier] WARN: Failed to fetch project identifier");
356
+ logIdentifier("WARN: Failed to fetch project identifier", "warn");
285
357
  return null;
286
358
  }
287
359
  else if ("error" in res) {
@@ -289,7 +361,8 @@ export async function getPublicIdentifier(project_id, opts = undefined) {
289
361
  return null;
290
362
  }
291
363
  else if (!res.ok) {
292
- console.error("[needle-identifier] ERROR: Failed to fetch project identifier");
364
+ logIdentifier("ERROR: Failed to fetch project identifier", "error");
365
+ await releaseResponse(res);
293
366
  return null;
294
367
  }
295
368
  const text = await res.text();
@@ -299,7 +372,7 @@ export async function getPublicIdentifier(project_id, opts = undefined) {
299
372
  const json = JSON.parse(text);
300
373
  return json.public_key;
301
374
  }
302
- catch (err) {
375
+ catch (/** @type {unknown} */ err) {
303
376
  // TODO: report error to backend
304
377
  if (opts?.loglevel === "verbose") console.error(err);
305
378
  return null;
@@ -307,6 +380,7 @@ export async function getPublicIdentifier(project_id, opts = undefined) {
307
380
  };
308
381
 
309
382
 
383
+ /** @type {boolean | undefined} */
310
384
  let licenseServerStarted = undefined;
311
385
 
312
386
  /**
@@ -333,7 +407,7 @@ async function waitForLicenseServer(opts) {
333
407
  const response = await fetch_WaitForServer(localServerUrl, {
334
408
  method: "GET",
335
409
  signal: timeout
336
- }).catch(err => {
410
+ }).catch((/** @type {{ message?: string, stack?: string }} */ err) => {
337
411
  if (opts?.loglevel === "verbose") {
338
412
  console.error("ERROR connecting to local license server url at " + localServerUrl, err.message);
339
413
  }
@@ -383,12 +457,12 @@ async function waitForLicenseServer(opts) {
383
457
  */
384
458
  function canRunCLI(opts) {
385
459
  if (process.env.CI) {
386
- if (opts?.loglevel === "verbose") console.log("[needle-license] INFO: Running in CI environment");
460
+ if (opts?.loglevel === "verbose") logLicense("INFO: Running in CI environment");
387
461
  return false; // We cannot run the CLI in CI environments
388
462
  }
389
463
  // Note: the .stackblitz directory doesnt always exist it seems
390
464
  if (existsSync("/home/.stackblitz")) {
391
- if (opts?.loglevel === "verbose") console.log("[needle-license] INFO: Running in Stackblitz environment");
465
+ if (opts?.loglevel === "verbose") logLicense("INFO: Running in Stackblitz environment");
392
466
  return false;
393
467
  }
394
468
  // Default to true:
@@ -399,9 +473,10 @@ function canRunCLI(opts) {
399
473
  * @param {string} processName
400
474
  * @param {string[]} args
401
475
  * @param {DefaultOptions | undefined} opts
476
+ * @returns {Promise<boolean>}
402
477
  */
403
478
  async function runCommand(processName, args, opts) {
404
- if (opts?.loglevel === "verbose") console.log(`[needle-license] INFO: Running command: ${processName} ${args.join(" ")}`);
479
+ if (opts?.loglevel === "verbose") logLicense(`INFO: Running command: ${processName} ${args.join(" ")}`);
405
480
  const process = spawn(processName, [...args], {
406
481
  shell: true,
407
482
  timeout: 30_000,
@@ -411,11 +486,11 @@ async function runCommand(processName, args, opts) {
411
486
  return new Promise((resolve, _reject) => {
412
487
  process.on('close', (code) => {
413
488
  if (opts?.loglevel === "verbose")
414
- console.log(`[needle-license] INFO: \"${processName}\" process exited with code ${code}`);
489
+ logLicense(`INFO: \"${processName}\" process exited with code ${code}`);
415
490
  if (code === 0 || code === null || code === undefined) {
416
491
  resolve(true);
417
492
  } else {
418
- console.warn(`[needle-license] WARN: \"${processName}\" process exited with code ${code}\nProcess Arguments: ${args.join(" ")}`);
493
+ logLicense(`WARN: \"${processName}\" process exited with code ${code}\nProcess Arguments: ${args.join(" ")}`, "warn");
419
494
  resolve(false);
420
495
  }
421
496
  });
@@ -440,7 +515,7 @@ function fetch_WaitForServer(url, options) {
440
515
  if (!options) { options = {}; }
441
516
  module.get(url, options, (res) => {
442
517
  let data = '';
443
- res.on('data', (chunk) => {
518
+ res.on('data', (/** @type {Buffer|string} */ chunk) => {
444
519
  data += chunk;
445
520
  });
446
521
  res.on('end', () => {