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

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 (150) hide show
  1. package/components.needle.json +1 -1
  2. package/dist/{gltf-progressive-CTlvpS3A.js → gltf-progressive-Bm_6aEi4.js} +1 -1
  3. package/dist/{gltf-progressive-CMwJPwEt.umd.cjs → gltf-progressive-BttGBXw6.umd.cjs} +1 -1
  4. package/dist/{gltf-progressive-DYL3SLVb.min.js → gltf-progressive-T5WKTux5.min.js} +1 -1
  5. package/dist/materialx-CJyQZtjt.min.js +90 -0
  6. package/dist/materialx-DMs1E08Z.js +4636 -0
  7. package/dist/materialx-DaKKOoVk.umd.cjs +90 -0
  8. package/dist/{needle-engine.bundle-DsTdfmeb.min.js → needle-engine.bundle-CBq_OMnI.min.js} +122 -124
  9. package/dist/{needle-engine.bundle-DB4kLWO_.js → needle-engine.bundle-DGyiwNWR.js} +3226 -3232
  10. package/dist/{needle-engine.bundle-C1BFRZDF.umd.cjs → needle-engine.bundle-JN3eiiYc.umd.cjs} +113 -115
  11. package/dist/needle-engine.d.ts +52 -33
  12. package/dist/needle-engine.js +288 -287
  13. package/dist/needle-engine.min.js +1 -1
  14. package/dist/needle-engine.umd.cjs +1 -1
  15. package/dist/{postprocessing-BN-f4viE.min.js → postprocessing-06AXuvdv.min.js} +1 -1
  16. package/dist/{postprocessing-De9ZpJrk.js → postprocessing-CI2x8Cln.js} +1 -1
  17. package/dist/{postprocessing-DYmYOVm4.umd.cjs → postprocessing-CPDcA21P.umd.cjs} +1 -1
  18. package/dist/{three-examples-BHqRVpO_.umd.cjs → three-examples-BMmNgNCN.umd.cjs} +12 -12
  19. package/dist/{three-examples-C0ZCCA_K.js → three-examples-CMYCd5nH.js} +192 -182
  20. package/dist/{three-examples-DmTY8tGr.min.js → three-examples-CQl1fFZp.min.js} +14 -14
  21. package/lib/engine/api.d.ts +2 -0
  22. package/lib/engine/api.js +2 -0
  23. package/lib/engine/api.js.map +1 -1
  24. package/lib/engine/debug/debug.js +1 -1
  25. package/lib/engine/debug/debug.js.map +1 -1
  26. package/lib/engine/debug/debug_spatial_console.js +1 -1
  27. package/lib/engine/debug/debug_spatial_console.js.map +1 -1
  28. package/lib/engine/engine_accessibility.d.ts +1 -1
  29. package/lib/engine/engine_accessibility.js +1 -1
  30. package/lib/engine/engine_accessibility.js.map +1 -1
  31. package/lib/engine/engine_context.d.ts +1 -1
  32. package/lib/engine/engine_context.js +2 -2
  33. package/lib/engine/engine_context.js.map +1 -1
  34. package/lib/engine/engine_create_objects.js +1 -1
  35. package/lib/engine/engine_create_objects.js.map +1 -1
  36. package/lib/engine/engine_gizmos.js +1 -1
  37. package/lib/engine/engine_gizmos.js.map +1 -1
  38. package/lib/engine/engine_license.js +2 -7
  39. package/lib/engine/engine_license.js.map +1 -1
  40. package/lib/engine/engine_test_utils.d.ts +39 -0
  41. package/lib/engine/engine_test_utils.js +84 -0
  42. package/lib/engine/engine_test_utils.js.map +1 -0
  43. package/lib/engine/engine_utils.js +2 -2
  44. package/lib/engine/engine_utils.js.map +1 -1
  45. package/lib/engine/export/gltf/index.js +1 -1
  46. package/lib/engine/export/gltf/index.js.map +1 -1
  47. package/lib/engine/webcomponents/logo-element.d.ts +3 -6
  48. package/lib/engine/webcomponents/logo-element.js +0 -18
  49. package/lib/engine/webcomponents/logo-element.js.map +1 -1
  50. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
  51. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
  52. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +7 -10
  53. package/lib/engine/webcomponents/needle menu/needle-menu.js +4 -14
  54. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  55. package/lib/engine/webcomponents/needle-engine.ar-overlay.js +1 -10
  56. package/lib/engine/webcomponents/needle-engine.ar-overlay.js.map +1 -1
  57. package/lib/engine/webcomponents/needle-engine.d.ts +0 -3
  58. package/lib/engine/webcomponents/needle-engine.js +0 -10
  59. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  60. package/lib/engine-components/Component.js +1 -0
  61. package/lib/engine-components/Component.js.map +1 -1
  62. package/lib/engine-components/ReflectionProbe.d.ts +2 -24
  63. package/lib/engine-components/ReflectionProbe.js +2 -28
  64. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  65. package/lib/engine-components/Skybox.js +2 -4
  66. package/lib/engine-components/Skybox.js.map +1 -1
  67. package/lib/engine-components/export/gltf/GltfExport.js +1 -1
  68. package/lib/engine-components/export/gltf/GltfExport.js.map +1 -1
  69. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +2 -2
  70. package/lib/engine-components/export/usdz/USDZExporter.js +1 -1
  71. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  72. package/lib/engine-components/export/usdz/extensions/behavior/PhysicsExtension.js +2 -2
  73. package/lib/engine-components/export/usdz/extensions/behavior/PhysicsExtension.js.map +1 -1
  74. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
  75. package/lib/include/three/EXT_mesh_gpu_instancing_exporter.js.map +1 -0
  76. package/package.json +14 -18
  77. package/plugins/common/buildinfo.js +10 -46
  78. package/plugins/common/files.js +1 -2
  79. package/plugins/common/license.js +69 -144
  80. package/plugins/common/logger.js +11 -172
  81. package/plugins/common/worker.js +4 -5
  82. package/plugins/types/userconfig.d.ts +2 -40
  83. package/plugins/vite/alias.js +5 -6
  84. package/plugins/vite/asap.js +5 -6
  85. package/plugins/vite/build-pipeline.js +41 -224
  86. package/plugins/vite/buildinfo.js +6 -66
  87. package/plugins/vite/copyfiles.js +12 -41
  88. package/plugins/vite/custom-element-data.js +16 -26
  89. package/plugins/vite/defines.js +5 -8
  90. package/plugins/vite/dependencies.js +10 -16
  91. package/plugins/vite/dependency-watcher.js +7 -35
  92. package/plugins/vite/drop-client.js +5 -7
  93. package/plugins/vite/drop.js +14 -16
  94. package/plugins/vite/editor-connection.js +16 -18
  95. package/plugins/vite/imports-logger.js +2 -12
  96. package/plugins/vite/index.js +3 -8
  97. package/plugins/vite/local-files.js +441 -2
  98. package/plugins/vite/logger.client.js +35 -45
  99. package/plugins/vite/logger.js +3 -6
  100. package/plugins/vite/meta.js +4 -18
  101. package/plugins/vite/needle-app.js +3 -4
  102. package/plugins/vite/peer.js +1 -2
  103. package/plugins/vite/pwa.js +17 -33
  104. package/plugins/vite/reload.js +2 -24
  105. package/src/engine/api.ts +3 -0
  106. package/src/engine/debug/debug.ts +1 -1
  107. package/src/engine/debug/debug_spatial_console.ts +1 -5
  108. package/src/engine/engine_accessibility.ts +1 -2
  109. package/src/engine/engine_context.ts +2 -2
  110. package/src/engine/engine_create_objects.ts +1 -1
  111. package/src/engine/engine_gizmos.ts +5 -9
  112. package/src/engine/engine_license.ts +2 -7
  113. package/src/engine/engine_test_utils.ts +109 -0
  114. package/src/engine/engine_utils.ts +2 -2
  115. package/src/engine/export/gltf/index.ts +1 -1
  116. package/src/engine/webcomponents/logo-element.ts +3 -20
  117. package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -6
  118. package/src/engine/webcomponents/needle menu/needle-menu.ts +11 -23
  119. package/src/engine/webcomponents/needle-engine.ar-overlay.ts +2 -13
  120. package/src/engine/webcomponents/needle-engine.ts +1 -13
  121. package/src/engine-components/Component.ts +2 -1
  122. package/src/engine-components/ReflectionProbe.ts +9 -33
  123. package/src/engine-components/Skybox.ts +2 -4
  124. package/src/engine-components/export/gltf/GltfExport.ts +1 -1
  125. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +2 -2
  126. package/src/engine-components/export/usdz/USDZExporter.ts +1 -1
  127. package/src/engine-components/export/usdz/extensions/behavior/PhysicsExtension.ts +2 -2
  128. package/src/include/draco/draco_decoder.js +34 -0
  129. package/src/include/draco/draco_decoder.wasm +0 -0
  130. package/src/include/draco/draco_wasm_wrapper.js +117 -0
  131. package/src/include/ktx2/basis_transcoder.js +19 -0
  132. package/src/include/ktx2/basis_transcoder.wasm +0 -0
  133. package/src/include/needle/arial-msdf.json +1472 -0
  134. package/src/include/needle/arial.png +0 -0
  135. package/src/include/needle/poweredbyneedle.webp +0 -0
  136. package/dist/materialx-4jJLLe9Q.js +0 -4174
  137. package/dist/materialx-Bt9FHwco.min.js +0 -158
  138. package/dist/materialx-NDD0y4JY.umd.cjs +0 -158
  139. package/lib/engine/export/gltf/EXT_mesh_gpu_instancing_exporter.js.map +0 -1
  140. package/plugins/common/needle-engine-skill.md +0 -175
  141. package/plugins/vite/ai.js +0 -71
  142. package/plugins/vite/local-files-analysis.js +0 -789
  143. package/plugins/vite/local-files-core.js +0 -992
  144. package/plugins/vite/local-files-internals.js +0 -28
  145. package/plugins/vite/local-files-types.d.ts +0 -111
  146. package/plugins/vite/local-files-utils.js +0 -359
  147. package/plugins/vite/logging.js +0 -129
  148. /package/lib/{engine/export/gltf → include/three}/EXT_mesh_gpu_instancing_exporter.d.ts +0 -0
  149. /package/lib/{engine/export/gltf → include/three}/EXT_mesh_gpu_instancing_exporter.js +0 -0
  150. /package/src/{engine/export/gltf → include/three}/EXT_mesh_gpu_instancing_exporter.js +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/engine",
3
- "version": "4.15.0-next.f391a30",
3
+ "version": "4.15.0",
4
4
  "description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.",
5
5
  "main": "dist/needle-engine.min.js",
6
6
  "exports": {
@@ -57,12 +57,9 @@
57
57
  "test:circular-imports": "node plugins/test/check-circular-imports.mjs",
58
58
  "test:tsc": "tsc --strict false && tsc --strict true",
59
59
  "test:attw": "npx --yes @arethetypeswrong/cli --pack dist",
60
- "test:type-coverage:plugins": "node test/type-coverage.mjs plugins",
61
- "test:type-coverage:engine": "node test/type-coverage.mjs engine",
62
- "test:type-coverage:components": "node test/type-coverage.mjs components",
63
60
  "generate:custom-elements": "npx web-component-analyzer src --format vscode --outFile custom-elements.json && node plugins/publish/clean-wca-json.mjs",
64
- "lint": "eslint src",
65
- "lint:fix": "eslint src --fix",
61
+ "lint": "eslint --ext .ts src",
62
+ "lint:fix": "eslint --ext .ts src --fix",
66
63
  "stats": "howfat ."
67
64
  },
68
65
  "files": [
@@ -103,7 +100,7 @@
103
100
  "dependencies": {
104
101
  "@dimforge/rapier3d-compat": "0.19.x",
105
102
  "@needle-tools/gltf-progressive": "3.4.0-beta.1",
106
- "@needle-tools/materialx": "1.4.3",
103
+ "@needle-tools/materialx": "1.4.2",
107
104
  "@needle-tools/three-animation-pointer": "1.0.7",
108
105
  "@webxr-input-profiles/motion-controllers": "^1.0.0",
109
106
  "flatbuffers": "2.0.4",
@@ -123,22 +120,22 @@
123
120
  },
124
121
  "devDependencies": {
125
122
  "@babel/runtime": "^7.16.0",
126
- "@eslint/js": "^9.0.0",
127
123
  "@luncheon/esbuild-plugin-gzip": "^0.1.0",
128
- "@needle-tools/helper": "2.0.0-next.faf57e6",
129
- "@needle-tools/needle-component-compiler": "3.0.0-alpha.1.999f08a",
124
+ "@needle-tools/helper": "^1.8.0",
125
+ "@needle-tools/needle-component-compiler": "^1.9.3",
130
126
  "@stylistic/eslint-plugin-ts": "^1.5.4",
131
127
  "@types/node": "^20.14.8",
132
128
  "@types/three": "0.169.0",
133
- "@typescript-eslint/eslint-plugin": "^8.0.0",
134
- "@typescript-eslint/parser": "^8.0.0",
129
+ "@typescript-eslint/eslint-plugin": "^6.2.0",
130
+ "@typescript-eslint/parser": "^6.2.0",
135
131
  "esbuild": "^0.15.10",
136
132
  "esbuild-node-externals": "^1.5.0",
137
- "eslint": "^9.0.0",
133
+ "eslint": "^8.56.0",
134
+ "eslint-plugin-deprecation": "^3.0.0",
138
135
  "eslint-plugin-import": "^2.29.1",
139
- "eslint-plugin-no-secrets": "^2.2.2",
140
- "eslint-plugin-no-unsanitized": "^4.1.5",
141
- "eslint-plugin-promise": "^7.0.0",
136
+ "eslint-plugin-no-secrets": "^0.8.9",
137
+ "eslint-plugin-no-unsanitized": "4.1.4",
138
+ "eslint-plugin-promise": "^6.1.1",
142
139
  "eslint-plugin-simple-import-sort": "^10.0.0",
143
140
  "eslint-plugin-xss": "^0.1.12",
144
141
  "filehound": "^1.17.6",
@@ -150,7 +147,6 @@
150
147
  "madge": "^5.0.1",
151
148
  "npm-watch": "^0.11.0",
152
149
  "typescript": "^4.5.5",
153
- "typescript-eslint": "^8.0.0",
154
150
  "vite": "7",
155
151
  "vite-plugin-dts": "^3.9.1"
156
152
  },
@@ -181,4 +177,4 @@
181
177
  "module": "lib/needle-engine.js",
182
178
  "typings": "lib/needle-engine.d.ts",
183
179
  "types": "lib/needle-engine.d.ts"
184
- }
180
+ }
@@ -1,23 +1,14 @@
1
1
  import fs, { existsSync, statSync } from 'fs';
2
2
  import crypto from 'crypto';
3
- import { relative } from 'path';
4
- import { needleLog } from '../vite/logging.js';
5
3
 
6
4
 
7
5
  /** Create a file containing information about the build inside the build directory
8
6
  * @param {String} buildDirectory
9
- * @param {{log?:boolean}} [options]
10
7
  */
11
- export function createBuildInfoFile(buildDirectory, options = undefined) {
12
- const shouldLog = options?.log !== false;
13
- const rel = (pathValue) => {
14
- const value = relative(process.cwd(), pathValue).replaceAll("\\", "/");
15
- return value?.length ? value : ".";
16
- };
17
-
8
+ export function createBuildInfoFile(buildDirectory) {
18
9
  if (!buildDirectory) {
19
- if (shouldLog) needleLog("needle-buildinfo", "Can not create build info file because \"buildDirectory\" is not defined", "warn", { dimBody: false });
20
- return { ok: false, error: "buildDirectory is not defined" };
10
+ console.warn("WARN: Can not create build info file because \"buildDirectory\" is not defined");
11
+ return;
21
12
  }
22
13
  // start creating the buildinfo
23
14
  const buildInfo = {
@@ -25,46 +16,18 @@ export function createBuildInfoFile(buildDirectory, options = undefined) {
25
16
  totalsize: 0,
26
17
  files: []
27
18
  };
28
- if (shouldLog) needleLog("needle-buildinfo", `Begin collecting files in \"${rel(buildDirectory)}\"`);
19
+ console.log(`[needle-buildinfo] - Begin collecting files in \"${buildDirectory}\"`);
29
20
  recursivelyCollectFiles(buildDirectory, "", buildInfo);
30
21
  const buildInfoPath = `${buildDirectory}/needle.buildinfo.json`;
31
22
  const totalSizeInMB = buildInfo.totalsize / 1024 / 1024;
32
- if (shouldLog) needleLog("needle-buildinfo", `Collected ${buildInfo.files.length} files (${totalSizeInMB.toFixed(2)} MB). Writing build info to \"${rel(buildInfoPath)}\"`);
23
+ console.log(`[needle-buildinfo] - Collected ${buildInfo.files.length} files (${totalSizeInMB.toFixed(2)} MB). Writing build info to \"${buildInfoPath}\"`);
33
24
  const str = JSON.stringify(buildInfo);
34
25
  fs.writeFileSync(buildInfoPath, str);
35
26
  if(!existsSync(buildDirectory)) {
36
- if (shouldLog) needleLog("needle-buildinfo", `Could not write build info file to \"${rel(buildInfoPath)}\"`, "warn", { dimBody: false });
37
- return { ok: false, error: `Could not write build info file to \"${rel(buildInfoPath)}\"` };
27
+ console.warn(`WARN: Could not write build info file to \"${buildInfoPath}\"`);
28
+ return;
38
29
  }
39
- if (shouldLog) needleLog("needle-buildinfo", `Build info file successfully written to \"${rel(buildInfoPath)}\"`);
40
- return {
41
- ok: true,
42
- buildDirectory: rel(buildDirectory),
43
- buildInfoPath: rel(buildInfoPath),
44
- fileCount: buildInfo.files.length,
45
- totalSizeBytes: buildInfo.totalsize,
46
- totalSizeInMB,
47
- };
48
- }
49
-
50
- export function collectBuildDirectoryStats(buildDirectory) {
51
- if (!buildDirectory || !existsSync(buildDirectory)) {
52
- return {
53
- fileCount: 0,
54
- totalSizeBytes: 0,
55
- totalSizeInMB: 0,
56
- };
57
- }
58
- const info = {
59
- totalsize: 0,
60
- files: [],
61
- };
62
- recursivelyCollectFiles(buildDirectory, "", info);
63
- return {
64
- fileCount: info.files.length,
65
- totalSizeBytes: info.totalsize,
66
- totalSizeInMB: info.totalsize / 1024 / 1024,
67
- };
30
+ console.log(`[needle-buildinfo] - Build info file successfully written to \"${buildInfoPath}\"`);
68
31
  }
69
32
 
70
33
  /** Recursively collect all files in a directory
@@ -77,11 +40,12 @@ function recursivelyCollectFiles(directory, path, info) {
77
40
  if (entry.isDirectory()) {
78
41
  // make sure we never collect files inside node_modules
79
42
  if (entry.name === "node_modules") {
80
- needleLog("needle-buildinfo", "Skipping node_modules directory at " + path, "warn", { dimBody: false });
43
+ console.warn("WARN: Skipping node_modules directory at " + path);
81
44
  continue;
82
45
  }
83
46
  const newPath = path?.length <= 0 ? entry.name : `${path}/${entry.name}`;
84
47
  const newDirectory = `${directory}/${entry.name}`;
48
+ console.log(`[needle-buildinfo] - Collect files in \"/${newPath}\"`);
85
49
  recursivelyCollectFiles(newDirectory, newPath, info);
86
50
  } else {
87
51
  const relpath = path?.length <= 0 ? entry.name : `${path}/${entry.name}`;
@@ -5,7 +5,7 @@ import { join } from "path";
5
5
  * @param {string} src
6
6
  * @param {string} dest
7
7
  * @param {boolean} override
8
- * @param {{count:number, bytes?:number} | undefined} ctx
8
+ * @param {{count:number} | undefined} ctx
9
9
  */
10
10
  export function copyFilesSync(src, dest, override = true, ctx = undefined) {
11
11
  if (dest === null) {
@@ -27,7 +27,6 @@ export function copyFilesSync(src, dest, override = true, ctx = undefined) {
27
27
  if (exists) {
28
28
  if (ctx) {
29
29
  ctx.count += 1;
30
- ctx.bytes = (ctx.bytes || 0) + (stats?.size || 0);
31
30
  }
32
31
  copyFileSync(src, dest);
33
32
  }
@@ -1,10 +1,8 @@
1
- // @ts-check
2
1
  import { spawn } from "child_process";
3
2
  import { NEEDLE_CLOUD_CLI_NAME } from "./cloud.js";
4
3
  import { existsSync } from "fs";
5
4
  import http from "http";
6
5
  import https from "https";
7
- import { needleLog } from "../vite/logging.js";
8
6
 
9
7
  const port = 8424;
10
8
  const localServerUrl = `http://localhost:${port}`;
@@ -12,80 +10,10 @@ const licenseServerUrl = `http://localhost:${port}/api/license`;
12
10
  const projectIdentifierUrl = `http://localhost:${port}/api/public_key`;
13
11
  const needleCloudApiEndpoint = "https://cloud.needle.tools/api";
14
12
 
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
-
83
13
  /**
84
14
  * @typedef {{loglevel?:"verbose"}} DefaultOptions
85
15
  */
86
16
 
87
- /** @typedef {{ ok: boolean, status: number, statusText: string, text: string }} NeedleCloudHttpResponse */
88
-
89
17
  /**
90
18
  * Replace license string - used for webpack
91
19
  * @param {string} code
@@ -120,31 +48,37 @@ export async function resolveLicense(args = null) {
120
48
  // If a process.env.NEEDLE_CLOUD_TOKEN is set we want to use this (e.g. via nextjs)
121
49
  if (!accessToken) {
122
50
  if (process.env.NEEDLE_CLOUD_TOKEN) {
123
- logLicense("INFO: Using Needle Cloud access token from NEEDLE_CLOUD_TOKEN environment variable");
51
+ console.log("[needle-license] INFO: Using Needle Cloud access token from NEEDLE_CLOUD_TOKEN environment variable");
124
52
  accessToken = process.env.NEEDLE_CLOUD_TOKEN;
125
53
  }
126
54
  else if (process.env.CI) {
127
- logLicense("WARN: Missing NEEDLE_CLOUD_TOKEN for CI environment", "warn");
55
+ console.warn("[needle-license] WARN: Missing NEEDLE_CLOUD_TOKEN for CI environment");
128
56
  }
129
57
  }
130
58
 
131
59
  if (accessToken) {
132
- const res = await requestNeedleCloud("/v1/account/get/licenses", {
60
+ const timeout = AbortSignal.timeout(10_000);
61
+ const url = new URL(`${needleCloudApiEndpoint}/v1/account/get/licenses`);
62
+ const res = await fetch(url, {
133
63
  method: "GET",
134
- accessToken,
135
- timeoutMs: 10_000,
136
- }).catch((/** @type {{ message?: string }} */ err) => {
64
+ signal: timeout,
65
+ headers: {
66
+ Authorization: `Bearer ${accessToken}`,
67
+ "x-needle": "cli"
68
+ }
69
+ }).catch(err => {
137
70
  return { ok: false, error: err.message };
138
71
  });
139
72
  if ("error" in res) {
140
- logLicense(`Could not fetch license from Needle Cloud API (${res.error})`, "error");
73
+ console.error(`[needle-license] Could not fetch license from Needle Cloud API (${res.error})`);
141
74
  return null;
142
75
  }
143
76
  if (res.ok) {
144
- return tryParseLicense(res.text);
77
+ const text = await res.text();
78
+ return tryParseLicense(text);
145
79
  }
146
80
  else {
147
- logLicense(`Could not fetch license from Needle Cloud API (${res.status})`, "error");
81
+ console.error(`[needle-license] Could not fetch license from Needle Cloud API (${res.status})`);
148
82
  if (process.env.CI) {
149
83
  return null;
150
84
  }
@@ -152,26 +86,26 @@ export async function resolveLicense(args = null) {
152
86
  }
153
87
  else if (process.env.CI) {
154
88
  const isGithubCI = process.env.GITHUB_ACTIONS;
155
- let message = "WARN: Missing NEEDLE_CLOUD_TOKEN for CI environment run.";
89
+ let message = "[needle-license] WARN: Missing NEEDLE_CLOUD_TOKEN for CI environment run.";
156
90
  if (isGithubCI) {
157
91
  const repositoryUrl = process.env.GITHUB_REPOSITORY;
158
92
  const url = `${repositoryUrl}/settings/secrets/actions`;
159
93
  message += `\nPlease add the token to your GitHub repository secrets: ${url}`;
160
94
  }
161
- logLicense(message, "warn");
95
+ console.warn(message);
162
96
  return null;
163
97
  }
164
98
 
165
99
 
166
100
  if (!canRunCLI(args)) {
167
- logLicense("License server CLI is not available. Please use an access token for authorization.", "error");
101
+ console.error("[needle-license] License server CLI is not available. Please use an access token for authorization.");
168
102
  return null;
169
103
  }
170
104
 
171
105
  // Fallback to use CLI
172
106
  // Wait for the server to start
173
107
  if (!await waitForLicenseServer(args || undefined)) {
174
- logLicense("ERR: Failed to start license server...", "error");
108
+ console.error("[needle-license] ERR: Failed to start license server...");
175
109
  return null;
176
110
  }
177
111
 
@@ -182,15 +116,12 @@ export async function resolveLicense(args = null) {
182
116
  url.searchParams.append("token", accessToken);
183
117
  }
184
118
 
185
- const includeFetchLineInSuccessLog = true;
119
+ console.log(`[needle-license] INFO: Fetching license...`);
186
120
  const timeout = AbortSignal.timeout(10_000);
187
121
  const licenseResponse = await fetch(url.toString(), {
188
122
  method: "GET",
189
- signal: timeout,
190
- headers: {
191
- "Connection": "close"
192
- }
193
- }).catch((/** @type {{ message?: string, cause?: { code?: string } }} */ err) => {
123
+ signal: timeout
124
+ }).catch(err => {
194
125
  if (args?.loglevel === "verbose") console.error("Error fetching license", err.message);
195
126
 
196
127
  if (err.cause?.code === "ECONNREFUSED") {
@@ -202,7 +133,7 @@ export async function resolveLicense(args = null) {
202
133
  });
203
134
 
204
135
  if (!licenseResponse) {
205
- logLicense("WARN: Failed to fetch license", "warn");
136
+ console.warn("[needle-license] WARN: Failed to fetch license");
206
137
  return null;
207
138
  }
208
139
  else if ("error" in licenseResponse) {
@@ -211,49 +142,41 @@ export async function resolveLicense(args = null) {
211
142
  }
212
143
  else if (!licenseResponse.ok) {
213
144
  if (licenseResponse.status === 500)
214
- logLicense(`ERROR: Failed to fetch license (${licenseResponse.status})`, "error");
145
+ console.error(`[needle-license] ERROR: Failed to fetch license (${licenseResponse.status})`);
215
146
  else
216
- logLicense(`No license found (${licenseResponse.status})`);
217
- await releaseResponse(licenseResponse);
147
+ console.log(`[needle-license] No license found (${licenseResponse.status})`);
218
148
  return null;
219
149
  }
220
150
 
221
151
  const text = await licenseResponse.text();
222
- return tryParseLicense(text, { includeFetchLine: includeFetchLineInSuccessLog });
152
+ return tryParseLicense(text);
223
153
  }
224
154
 
225
155
 
226
156
  /**
227
157
  * @param {string} str License string
228
- * @param {{includeFetchLine?: boolean}} [options]
229
158
  */
230
- function tryParseLicense(str, options = undefined) {
159
+ function tryParseLicense(str) {
231
160
  try {
232
161
  /** @type {{needle_engine_license:string}} */
233
162
  const licenseJson = JSON.parse(str);
234
163
  if (licenseJson.needle_engine_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
- }
164
+ console.log(`[needle-license] INFO: Successfully received \"${licenseJson.needle_engine_license?.toUpperCase()}\" license`)
242
165
  return licenseJson.needle_engine_license;
243
166
  }
244
167
  if ("error" in licenseJson) {
245
- logLicense(`ERROR in license check: \"${licenseJson.error}\"`, "error");
168
+ console.error(`[needle-license] ERROR in license check: \"${licenseJson.error}\"`);
246
169
  }
247
170
  else if (licenseJson.needle_engine_license == null) {
248
171
  return null;
249
172
  }
250
173
  else {
251
- logLicense("WARN: Received invalid license. " + JSON.stringify(licenseJson), "warn");
174
+ console.warn("[needle-license] WARN: Received invalid license.", licenseJson);
252
175
  }
253
176
  return null;
254
177
  }
255
- catch (/** @type {unknown} */ err) {
256
- logLicense("ERROR: Failed to parse license response", "error");
178
+ catch (err) {
179
+ console.error("[needle-license] ERROR: Failed to parse license response");
257
180
  return null;
258
181
  }
259
182
  }
@@ -265,50 +188,58 @@ function tryParseLicense(str, options = undefined) {
265
188
  */
266
189
  export async function getPublicIdentifier(project_id, opts = undefined) {
267
190
 
268
- let accessToken = /** @type {string | undefined} */ (undefined);
191
+ let accessToken = undefined;
269
192
  if (!accessToken) {
270
193
 
271
- if (opts?.loglevel === "verbose" && process.env.CI) logIdentifier("INFO: Running in CI environment");
194
+ if (opts?.loglevel === "verbose" && process.env.CI) console.debug("[needle-identifier] INFO: Running in CI environment");
272
195
 
273
196
  if (process.env.NEEDLE_CLOUD_TOKEN) {
274
- logIdentifier("INFO: Using Needle Cloud access token from environment variable");
197
+ console.log("[needle-identifier] INFO: Using Needle Cloud access token from environment variable");
275
198
  accessToken = process.env.NEEDLE_CLOUD_TOKEN;
276
199
  }
277
200
 
278
201
  if (accessToken) {
202
+ const url = new URL(`${needleCloudApiEndpoint}/v1/account/public_key`);
279
203
  const body = {
280
204
  project_id: project_id || process.env.GITHUB_REPOSITORY || undefined,
281
205
  machine_id: process.env.GITHUB_REPOSITORY_ID || "unknown",
282
206
  }
283
- const res = await requestNeedleCloud("/v1/account/public_key", {
207
+ const timeout = AbortSignal.timeout(10_000);
208
+ const res = await fetch(url, {
284
209
  method: "POST",
285
- accessToken,
286
- timeoutMs: 10_000,
287
- body,
288
- }).catch((/** @type {{ message?: string }} */ err) => {
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 => {
289
218
  if (opts?.loglevel === "verbose") {
290
219
  console.error(err);
291
220
  }
292
221
  return { ok: false, error: err.message };
293
222
  });
294
223
  if ("error" in res) {
295
- logIdentifier(`Could not fetch project identifier from Needle Cloud API (${res.error})`, "error");
224
+ console.error(`[needle-identifier] Could not fetch project identifier from Needle Cloud API (${res.error})`);
296
225
  return null;
297
226
  }
298
227
  if (res.ok) {
228
+ const text = await res.text();
299
229
  try {
300
230
  /** @type {{public_key:string}} */
301
- const json = JSON.parse(res.text);
302
- logIdentifier(`INFO: Successfully received public project identifier`);
231
+ const json = JSON.parse(text);
232
+ console.log(`[needle-identifier] INFO: Successfully received public project identifier`);
303
233
  return json.public_key;
304
234
  }
305
- catch (/** @type {unknown} */ err) {
306
- logIdentifier("ERROR: Failed to parse project identifier response", "error");
235
+ catch (err) {
236
+ console.error("[needle-identifier] ERROR: Failed to parse project identifier response");
307
237
  return null;
308
238
  }
309
239
  }
310
240
  else {
311
- logIdentifier(`Could not fetch project identifier from Needle Cloud API (${res.status}, ${res.statusText}, ${res.text})`, "error");
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})`);
312
243
  return null;
313
244
  }
314
245
  }
@@ -316,7 +247,7 @@ export async function getPublicIdentifier(project_id, opts = undefined) {
316
247
 
317
248
 
318
249
  if (!canRunCLI(opts)) {
319
- logLicense("License server CLI is not available. Please use an access token for authorization.", "error");
250
+ console.error("[needle-license] License server CLI is not available. Please use an access token for authorization.");
320
251
  return null;
321
252
  }
322
253
 
@@ -324,21 +255,18 @@ export async function getPublicIdentifier(project_id, opts = undefined) {
324
255
 
325
256
  // Wait for the server to start
326
257
  if (!await waitForLicenseServer(opts)) {
327
- logIdentifier("ERR: Failed to start license server...", "error");
258
+ console.error("[needle-identifier] ERR: Failed to start license server...");
328
259
  return null;
329
260
  }
330
261
 
331
- logIdentifier(`INFO: Fetching project identifier...`);
262
+ console.log(`[needle-identifier] INFO: Fetching project identifier...`);
332
263
  const url = new URL(projectIdentifierUrl);
333
264
  if (project_id) url.searchParams.append("project_id", project_id);
334
265
  const timeout = AbortSignal.timeout(5_000);
335
266
  const res = await fetch(projectIdentifierUrl, {
336
267
  method: "GET",
337
- signal: timeout,
338
- headers: {
339
- "Connection": "close"
340
- }
341
- }).catch((/** @type {{ message?: string, cause?: { code?: string } }} */ err) => {
268
+ signal: timeout
269
+ }).catch(err => {
342
270
 
343
271
  if (opts?.loglevel === "verbose") {
344
272
  console.error(err);
@@ -353,7 +281,7 @@ export async function getPublicIdentifier(project_id, opts = undefined) {
353
281
  })
354
282
 
355
283
  if (!res) {
356
- logIdentifier("WARN: Failed to fetch project identifier", "warn");
284
+ console.warn("[needle-identifier] WARN: Failed to fetch project identifier");
357
285
  return null;
358
286
  }
359
287
  else if ("error" in res) {
@@ -361,8 +289,7 @@ export async function getPublicIdentifier(project_id, opts = undefined) {
361
289
  return null;
362
290
  }
363
291
  else if (!res.ok) {
364
- logIdentifier("ERROR: Failed to fetch project identifier", "error");
365
- await releaseResponse(res);
292
+ console.error("[needle-identifier] ERROR: Failed to fetch project identifier");
366
293
  return null;
367
294
  }
368
295
  const text = await res.text();
@@ -372,7 +299,7 @@ export async function getPublicIdentifier(project_id, opts = undefined) {
372
299
  const json = JSON.parse(text);
373
300
  return json.public_key;
374
301
  }
375
- catch (/** @type {unknown} */ err) {
302
+ catch (err) {
376
303
  // TODO: report error to backend
377
304
  if (opts?.loglevel === "verbose") console.error(err);
378
305
  return null;
@@ -380,7 +307,6 @@ export async function getPublicIdentifier(project_id, opts = undefined) {
380
307
  };
381
308
 
382
309
 
383
- /** @type {boolean | undefined} */
384
310
  let licenseServerStarted = undefined;
385
311
 
386
312
  /**
@@ -407,7 +333,7 @@ async function waitForLicenseServer(opts) {
407
333
  const response = await fetch_WaitForServer(localServerUrl, {
408
334
  method: "GET",
409
335
  signal: timeout
410
- }).catch((/** @type {{ message?: string, stack?: string }} */ err) => {
336
+ }).catch(err => {
411
337
  if (opts?.loglevel === "verbose") {
412
338
  console.error("ERROR connecting to local license server url at " + localServerUrl, err.message);
413
339
  }
@@ -457,12 +383,12 @@ async function waitForLicenseServer(opts) {
457
383
  */
458
384
  function canRunCLI(opts) {
459
385
  if (process.env.CI) {
460
- if (opts?.loglevel === "verbose") logLicense("INFO: Running in CI environment");
386
+ if (opts?.loglevel === "verbose") console.log("[needle-license] INFO: Running in CI environment");
461
387
  return false; // We cannot run the CLI in CI environments
462
388
  }
463
389
  // Note: the .stackblitz directory doesnt always exist it seems
464
390
  if (existsSync("/home/.stackblitz")) {
465
- if (opts?.loglevel === "verbose") logLicense("INFO: Running in Stackblitz environment");
391
+ if (opts?.loglevel === "verbose") console.log("[needle-license] INFO: Running in Stackblitz environment");
466
392
  return false;
467
393
  }
468
394
  // Default to true:
@@ -473,10 +399,9 @@ function canRunCLI(opts) {
473
399
  * @param {string} processName
474
400
  * @param {string[]} args
475
401
  * @param {DefaultOptions | undefined} opts
476
- * @returns {Promise<boolean>}
477
402
  */
478
403
  async function runCommand(processName, args, opts) {
479
- if (opts?.loglevel === "verbose") logLicense(`INFO: Running command: ${processName} ${args.join(" ")}`);
404
+ if (opts?.loglevel === "verbose") console.log(`[needle-license] INFO: Running command: ${processName} ${args.join(" ")}`);
480
405
  const process = spawn(processName, [...args], {
481
406
  shell: true,
482
407
  timeout: 30_000,
@@ -486,11 +411,11 @@ async function runCommand(processName, args, opts) {
486
411
  return new Promise((resolve, _reject) => {
487
412
  process.on('close', (code) => {
488
413
  if (opts?.loglevel === "verbose")
489
- logLicense(`INFO: \"${processName}\" process exited with code ${code}`);
414
+ console.log(`[needle-license] INFO: \"${processName}\" process exited with code ${code}`);
490
415
  if (code === 0 || code === null || code === undefined) {
491
416
  resolve(true);
492
417
  } else {
493
- logLicense(`WARN: \"${processName}\" process exited with code ${code}\nProcess Arguments: ${args.join(" ")}`, "warn");
418
+ console.warn(`[needle-license] WARN: \"${processName}\" process exited with code ${code}\nProcess Arguments: ${args.join(" ")}`);
494
419
  resolve(false);
495
420
  }
496
421
  });
@@ -515,7 +440,7 @@ function fetch_WaitForServer(url, options) {
515
440
  if (!options) { options = {}; }
516
441
  module.get(url, options, (res) => {
517
442
  let data = '';
518
- res.on('data', (/** @type {Buffer|string} */ chunk) => {
443
+ res.on('data', (chunk) => {
519
444
  data += chunk;
520
445
  });
521
446
  res.on('end', () => {