@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.
- package/components.needle.json +1 -1
- package/dist/{gltf-progressive-CTlvpS3A.js → gltf-progressive-Bm_6aEi4.js} +1 -1
- package/dist/{gltf-progressive-CMwJPwEt.umd.cjs → gltf-progressive-BttGBXw6.umd.cjs} +1 -1
- package/dist/{gltf-progressive-DYL3SLVb.min.js → gltf-progressive-T5WKTux5.min.js} +1 -1
- package/dist/materialx-CJyQZtjt.min.js +90 -0
- package/dist/materialx-DMs1E08Z.js +4636 -0
- package/dist/materialx-DaKKOoVk.umd.cjs +90 -0
- package/dist/{needle-engine.bundle-DsTdfmeb.min.js → needle-engine.bundle-CBq_OMnI.min.js} +122 -124
- package/dist/{needle-engine.bundle-DB4kLWO_.js → needle-engine.bundle-DGyiwNWR.js} +3226 -3232
- package/dist/{needle-engine.bundle-C1BFRZDF.umd.cjs → needle-engine.bundle-JN3eiiYc.umd.cjs} +113 -115
- package/dist/needle-engine.d.ts +52 -33
- package/dist/needle-engine.js +288 -287
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{postprocessing-BN-f4viE.min.js → postprocessing-06AXuvdv.min.js} +1 -1
- package/dist/{postprocessing-De9ZpJrk.js → postprocessing-CI2x8Cln.js} +1 -1
- package/dist/{postprocessing-DYmYOVm4.umd.cjs → postprocessing-CPDcA21P.umd.cjs} +1 -1
- package/dist/{three-examples-BHqRVpO_.umd.cjs → three-examples-BMmNgNCN.umd.cjs} +12 -12
- package/dist/{three-examples-C0ZCCA_K.js → three-examples-CMYCd5nH.js} +192 -182
- package/dist/{three-examples-DmTY8tGr.min.js → three-examples-CQl1fFZp.min.js} +14 -14
- package/lib/engine/api.d.ts +2 -0
- package/lib/engine/api.js +2 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/debug/debug.js +1 -1
- package/lib/engine/debug/debug.js.map +1 -1
- package/lib/engine/debug/debug_spatial_console.js +1 -1
- package/lib/engine/debug/debug_spatial_console.js.map +1 -1
- package/lib/engine/engine_accessibility.d.ts +1 -1
- package/lib/engine/engine_accessibility.js +1 -1
- package/lib/engine/engine_accessibility.js.map +1 -1
- package/lib/engine/engine_context.d.ts +1 -1
- package/lib/engine/engine_context.js +2 -2
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_create_objects.js +1 -1
- package/lib/engine/engine_create_objects.js.map +1 -1
- package/lib/engine/engine_gizmos.js +1 -1
- package/lib/engine/engine_gizmos.js.map +1 -1
- package/lib/engine/engine_license.js +2 -7
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_test_utils.d.ts +39 -0
- package/lib/engine/engine_test_utils.js +84 -0
- package/lib/engine/engine_test_utils.js.map +1 -0
- package/lib/engine/engine_utils.js +2 -2
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/export/gltf/index.js +1 -1
- package/lib/engine/export/gltf/index.js.map +1 -1
- package/lib/engine/webcomponents/logo-element.d.ts +3 -6
- package/lib/engine/webcomponents/logo-element.js +0 -18
- package/lib/engine/webcomponents/logo-element.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +7 -10
- package/lib/engine/webcomponents/needle menu/needle-menu.js +4 -14
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.ar-overlay.js +1 -10
- package/lib/engine/webcomponents/needle-engine.ar-overlay.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +0 -3
- package/lib/engine/webcomponents/needle-engine.js +0 -10
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine-components/Component.js +1 -0
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/ReflectionProbe.d.ts +2 -24
- package/lib/engine-components/ReflectionProbe.js +2 -28
- package/lib/engine-components/ReflectionProbe.js.map +1 -1
- package/lib/engine-components/Skybox.js +2 -4
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/export/gltf/GltfExport.js +1 -1
- package/lib/engine-components/export/gltf/GltfExport.js.map +1 -1
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +2 -2
- package/lib/engine-components/export/usdz/USDZExporter.js +1 -1
- package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
- package/lib/engine-components/export/usdz/extensions/behavior/PhysicsExtension.js +2 -2
- package/lib/engine-components/export/usdz/extensions/behavior/PhysicsExtension.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
- package/lib/include/three/EXT_mesh_gpu_instancing_exporter.js.map +1 -0
- package/package.json +14 -18
- package/plugins/common/buildinfo.js +10 -46
- package/plugins/common/files.js +1 -2
- package/plugins/common/license.js +69 -144
- package/plugins/common/logger.js +11 -172
- package/plugins/common/worker.js +4 -5
- package/plugins/types/userconfig.d.ts +2 -40
- package/plugins/vite/alias.js +5 -6
- package/plugins/vite/asap.js +5 -6
- package/plugins/vite/build-pipeline.js +41 -224
- package/plugins/vite/buildinfo.js +6 -66
- package/plugins/vite/copyfiles.js +12 -41
- package/plugins/vite/custom-element-data.js +16 -26
- package/plugins/vite/defines.js +5 -8
- package/plugins/vite/dependencies.js +10 -16
- package/plugins/vite/dependency-watcher.js +7 -35
- package/plugins/vite/drop-client.js +5 -7
- package/plugins/vite/drop.js +14 -16
- package/plugins/vite/editor-connection.js +16 -18
- package/plugins/vite/imports-logger.js +2 -12
- package/plugins/vite/index.js +3 -8
- package/plugins/vite/local-files.js +441 -2
- package/plugins/vite/logger.client.js +35 -45
- package/plugins/vite/logger.js +3 -6
- package/plugins/vite/meta.js +4 -18
- package/plugins/vite/needle-app.js +3 -4
- package/plugins/vite/peer.js +1 -2
- package/plugins/vite/pwa.js +17 -33
- package/plugins/vite/reload.js +2 -24
- package/src/engine/api.ts +3 -0
- package/src/engine/debug/debug.ts +1 -1
- package/src/engine/debug/debug_spatial_console.ts +1 -5
- package/src/engine/engine_accessibility.ts +1 -2
- package/src/engine/engine_context.ts +2 -2
- package/src/engine/engine_create_objects.ts +1 -1
- package/src/engine/engine_gizmos.ts +5 -9
- package/src/engine/engine_license.ts +2 -7
- package/src/engine/engine_test_utils.ts +109 -0
- package/src/engine/engine_utils.ts +2 -2
- package/src/engine/export/gltf/index.ts +1 -1
- package/src/engine/webcomponents/logo-element.ts +3 -20
- package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -6
- package/src/engine/webcomponents/needle menu/needle-menu.ts +11 -23
- package/src/engine/webcomponents/needle-engine.ar-overlay.ts +2 -13
- package/src/engine/webcomponents/needle-engine.ts +1 -13
- package/src/engine-components/Component.ts +2 -1
- package/src/engine-components/ReflectionProbe.ts +9 -33
- package/src/engine-components/Skybox.ts +2 -4
- package/src/engine-components/export/gltf/GltfExport.ts +1 -1
- package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +2 -2
- package/src/engine-components/export/usdz/USDZExporter.ts +1 -1
- package/src/engine-components/export/usdz/extensions/behavior/PhysicsExtension.ts +2 -2
- package/src/include/draco/draco_decoder.js +34 -0
- package/src/include/draco/draco_decoder.wasm +0 -0
- package/src/include/draco/draco_wasm_wrapper.js +117 -0
- package/src/include/ktx2/basis_transcoder.js +19 -0
- package/src/include/ktx2/basis_transcoder.wasm +0 -0
- package/src/include/needle/arial-msdf.json +1472 -0
- package/src/include/needle/arial.png +0 -0
- package/src/include/needle/poweredbyneedle.webp +0 -0
- package/dist/materialx-4jJLLe9Q.js +0 -4174
- package/dist/materialx-Bt9FHwco.min.js +0 -158
- package/dist/materialx-NDD0y4JY.umd.cjs +0 -158
- package/lib/engine/export/gltf/EXT_mesh_gpu_instancing_exporter.js.map +0 -1
- package/plugins/common/needle-engine-skill.md +0 -175
- package/plugins/vite/ai.js +0 -71
- package/plugins/vite/local-files-analysis.js +0 -789
- package/plugins/vite/local-files-core.js +0 -992
- package/plugins/vite/local-files-internals.js +0 -28
- package/plugins/vite/local-files-types.d.ts +0 -111
- package/plugins/vite/local-files-utils.js +0 -359
- package/plugins/vite/logging.js +0 -129
- /package/lib/{engine/export/gltf → include/three}/EXT_mesh_gpu_instancing_exporter.d.ts +0 -0
- /package/lib/{engine/export/gltf → include/three}/EXT_mesh_gpu_instancing_exporter.js +0 -0
- /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
|
|
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.
|
|
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": "
|
|
129
|
-
"@needle-tools/needle-component-compiler": "
|
|
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": "^
|
|
134
|
-
"@typescript-eslint/parser": "^
|
|
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": "^
|
|
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": "^
|
|
140
|
-
"eslint-plugin-no-unsanitized": "
|
|
141
|
-
"eslint-plugin-promise": "^
|
|
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
|
|
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
|
-
|
|
20
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
37
|
-
return
|
|
27
|
+
console.warn(`WARN: Could not write build info file to \"${buildInfoPath}\"`);
|
|
28
|
+
return;
|
|
38
29
|
}
|
|
39
|
-
|
|
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
|
-
|
|
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}`;
|
package/plugins/common/files.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
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
|
-
|
|
77
|
+
const text = await res.text();
|
|
78
|
+
return tryParseLicense(text);
|
|
145
79
|
}
|
|
146
80
|
else {
|
|
147
|
-
|
|
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
|
-
|
|
95
|
+
console.warn(message);
|
|
162
96
|
return null;
|
|
163
97
|
}
|
|
164
98
|
|
|
165
99
|
|
|
166
100
|
if (!canRunCLI(args)) {
|
|
167
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
145
|
+
console.error(`[needle-license] ERROR: Failed to fetch license (${licenseResponse.status})`);
|
|
215
146
|
else
|
|
216
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
174
|
+
console.warn("[needle-license] WARN: Received invalid license.", licenseJson);
|
|
252
175
|
}
|
|
253
176
|
return null;
|
|
254
177
|
}
|
|
255
|
-
catch (
|
|
256
|
-
|
|
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 =
|
|
191
|
+
let accessToken = undefined;
|
|
269
192
|
if (!accessToken) {
|
|
270
193
|
|
|
271
|
-
if (opts?.loglevel === "verbose" && process.env.CI)
|
|
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
|
-
|
|
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
|
|
207
|
+
const timeout = AbortSignal.timeout(10_000);
|
|
208
|
+
const res = await fetch(url, {
|
|
284
209
|
method: "POST",
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
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(
|
|
302
|
-
|
|
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 (
|
|
306
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
258
|
+
console.error("[needle-identifier] ERR: Failed to start license server...");
|
|
328
259
|
return null;
|
|
329
260
|
}
|
|
330
261
|
|
|
331
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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(
|
|
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")
|
|
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")
|
|
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")
|
|
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
|
-
|
|
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
|
-
|
|
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', (
|
|
443
|
+
res.on('data', (chunk) => {
|
|
519
444
|
data += chunk;
|
|
520
445
|
});
|
|
521
446
|
res.on('end', () => {
|