@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
@@ -1,28 +0,0 @@
1
- export {
2
- getActiveHandlers,
3
- getFeatureBasePath,
4
- handleWebXRProfiles,
5
- makeLocal,
6
- makeLocalHtml,
7
- } from './local-files-core.js';
8
-
9
- export {
10
- analyzeProjectGlbs,
11
- buildAutoPolicy,
12
- collectAssetGlbs,
13
- collectIndexHtmlSkyboxUrls,
14
- collectNeedleComponentExtensionBlobs,
15
- detectAutoPolicy,
16
- getWebXRProfilesForMode,
17
- hasAutoFeatureSelection,
18
- readGlbJsonChunk,
19
- resolveSkyboxSelectionUrls,
20
- resolveSkyboxValueToUrl,
21
- shouldHandleUrlInAutoMode,
22
- } from './local-files-analysis.js';
23
-
24
- export {
25
- fixDracoRangeQueryProbe,
26
- fixRelativeNewURL,
27
- getRelativeToBasePath,
28
- } from './local-files-utils.js';
@@ -1,111 +0,0 @@
1
- /**
2
- * Shared type declarations for the local-files plugin family.
3
- * Referenced from local-files-utils.js, local-files-analysis.js, local-files-core.js, etc.
4
- */
5
-
6
- export interface UrlHandler {
7
- name: string;
8
- /** RegExp with the /g flag — match group 1 must capture the URL. */
9
- pattern: RegExp;
10
- type: "binary" | "css" | "decoder-dir" | "webxr-profiles";
11
- feature: string;
12
- decoderFiles?: string[];
13
- localDirName?: string;
14
- }
15
-
16
- export interface LocalizationStats {
17
- fileCount: number;
18
- totalBytes: number;
19
- mimeCounts: Map<string, number>;
20
- }
21
-
22
- export interface LocalizationOptions {
23
- features?: string | string[];
24
- excludeFeatures?: string[];
25
- /** URL substrings or RegExps to skip. */
26
- exclude?: (string | RegExp)[];
27
- /** @deprecated use `exclude` */
28
- excludeUrls?: string[];
29
- /** e.g. "facebook-instant", "discord" */
30
- platform?: string;
31
- /** Only process files inside these npm packages. */
32
- packages?: string[];
33
- /** Skybox selection: URL, magic keyword, array of those, or "all". */
34
- skybox?: string | string[];
35
- /** WebXR controller profile mode: "minimal" | "quest" | "pico" | "all" */
36
- webxr?: string;
37
- templateExpansions?: Array<{
38
- cdnPrefix: string;
39
- variables: Record<string, string[]>;
40
- localPrefix?: string;
41
- }>;
42
- /** Used when makeFilesLocal is an object — set to false to disable. */
43
- enabled?: boolean;
44
- }
45
-
46
- export interface AutoPolicy {
47
- features: Set<string>;
48
- hasWebXR: boolean;
49
- hasVideoPlayer: boolean;
50
- allowedSkyboxUrls: Set<string> | null;
51
- selectedWebXRProfiles: string[];
52
- }
53
-
54
- export interface VitePluginContext {
55
- emitFile(asset: {
56
- type: "asset" | "chunk";
57
- fileName?: string;
58
- name?: string;
59
- source?: string | Uint8Array;
60
- }): string;
61
- getFileName(referenceId: string): string;
62
- }
63
-
64
- export interface LocalizationContext {
65
- pluginContext: VitePluginContext | null;
66
- cache: {
67
- addToCache(key: string, value: Buffer | string): void;
68
- getFromCache(key: string): Buffer | string | null;
69
- readonly map: Map<string, Buffer | string>;
70
- };
71
- command: "build" | "serve";
72
- viteConfig: { build?: { assetsDir?: string } } | null;
73
- options: LocalizationOptions;
74
- autoPolicy: AutoPolicy | null;
75
- failedDownloads: Map<string, string>;
76
- localizationStats: LocalizationStats;
77
- }
78
-
79
- export interface SceneAnalysisReport {
80
- hasWebXRComponent: boolean;
81
- hasVideoPlayerComponent: boolean;
82
- extensions: Set<string>;
83
- componentTypes: Set<string>;
84
- componentCounts: Map<string, number>;
85
- glbFileCount: number;
86
- gltfFileCount: number;
87
- totalSceneFileCount: number;
88
- totalNodeCount: number;
89
- totalVertexCount: number;
90
- totalTextureCount: number;
91
- totalMeshCount: number;
92
- totalPrimitiveCount: number;
93
- dracoPrimitiveCount: number;
94
- meshoptBufferViewCount: number;
95
- }
96
-
97
- export interface SceneFile {
98
- path: string;
99
- type: "glb" | "gltf";
100
- }
101
-
102
- export interface NeedleComponentEntry {
103
- name?: string;
104
- type?: string;
105
- guid?: string;
106
- }
107
-
108
- export interface NeedleComponentExtension {
109
- components?: NeedleComponentEntry[];
110
- builtin_components?: NeedleComponentEntry[];
111
- }
@@ -1,359 +0,0 @@
1
- // @ts-check
2
- import https from 'https';
3
- import http from 'http';
4
- import { createHash } from 'crypto';
5
- import { needleLog, setTransientLogLineCleaner } from './logging.js';
6
-
7
- /** @typedef {import('./local-files-types.js').LocalizationContext} LocalizationContext */
8
-
9
- const debug = false;
10
- const DOWNLOAD_TIMEOUT_MS = 30_000;
11
- const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
12
- let spinnerIndex = 0;
13
- let spinnerActive = false;
14
-
15
- setTransientLogLineCleaner(() => clearSpinnerLine());
16
-
17
- function clearSpinnerLine() {
18
- if (!process.stdout.isTTY || !spinnerActive) return;
19
- process.stdout.write("\r\x1b[2K");
20
- spinnerActive = false;
21
- }
22
-
23
- /** @param {string} url */
24
- function updateMakeLocalProgress(url) {
25
- if (!process.stdout.isTTY) {
26
- needleLog("needle:local-files", "Make local: " + url, "log", { dimBody: true, showHeader: false });
27
- return;
28
- }
29
- const frame = SPINNER_FRAMES[spinnerIndex++ % SPINNER_FRAMES.length];
30
- const maxLength = Math.max(24, (process.stdout.columns || 120) - 4);
31
- const message = `Make local: ${url}`;
32
- const text = message.length > maxLength ? `${message.slice(0, Math.max(0, maxLength - 1))}…` : message;
33
- process.stdout.write(`\r\x1b[2K${frame} ${text}\x1b[0K`);
34
- spinnerActive = true;
35
- }
36
-
37
- export function finishMakeLocalProgress() {
38
- clearSpinnerLine();
39
- }
40
-
41
- /**
42
- * @param {string} src
43
- * @param {string} search
44
- * @param {string} replacement
45
- * @returns {string}
46
- */
47
- export function replaceAll(src, search, replacement) {
48
- return src.split(search).join(replacement);
49
- }
50
-
51
- export class Cache {
52
- /** @type {Map<string, Buffer|string>} */
53
- __cache = new Map();
54
- /**
55
- * @param {string} key
56
- * @param {Buffer|string} value
57
- */
58
- addToCache(key, value) {
59
- if (debug && this.__cache.has(key)) {
60
- console.warn("Key " + key + " already exists in cache, overwriting.");
61
- }
62
- this.__cache.set(key, value);
63
- }
64
- /**
65
- * @param {string} key
66
- * @returns {Buffer|string|null}
67
- */
68
- getFromCache(key) {
69
- return this.__cache.get(key) ?? null;
70
- }
71
- get map() {
72
- return this.__cache;
73
- }
74
- }
75
-
76
- /**
77
- * @param {string} path
78
- * @param {string} basePath
79
- * @returns {string}
80
- */
81
- export function getRelativeToBasePath(path, basePath) {
82
- const normalizedPath = normalizeWebPath(path);
83
- const normalizedBasePath = normalizeWebPath(basePath);
84
-
85
- if (!normalizedBasePath) return normalizedPath;
86
-
87
- if (normalizedPath.startsWith(normalizedBasePath)) {
88
- return "./" + normalizedPath.substring(normalizedBasePath.length);
89
- }
90
-
91
- const baseSegments = normalizedBasePath.replace(/\/+$/g, "").split("/").filter(Boolean);
92
- const backtrack = baseSegments.map(() => "..").join("/");
93
- return (backtrack ? backtrack + "/" : "") + normalizedPath;
94
- }
95
-
96
- /**
97
- * @param {string} path
98
- * @returns {string}
99
- */
100
- export function normalizeWebPath(path) {
101
- if (!path) return "";
102
- return path.replace(/\\/g, "/");
103
- }
104
-
105
- /**
106
- * @param {string} path
107
- * @returns {string}
108
- */
109
- export function ensureTrailingSlash(path) {
110
- if (!path) return "";
111
- return path.endsWith("/") ? path : path + "/";
112
- }
113
-
114
- /**
115
- * @param {string} src
116
- * @returns {string}
117
- */
118
- export function fixRelativeNewURL(src) {
119
- src = src.replace(
120
- /(?<==\s*)(["'])((?:(?:\.{1,2}\/)|\/)?ext\/[^"']*\/)\1/g,
121
- (/** @type {string} */ match, /** @type {string} */ quote, /** @type {string} */ path) => {
122
- const runtimePath = path.startsWith("/ext/") ? path.substring(1) : path;
123
- return `new URL(${quote}${runtimePath}${quote}, self.location?.href || ${quote}${quote}).href`;
124
- }
125
- );
126
-
127
- src = src.replace(
128
- /new\s+URL\s*\(\s*(["'`])((?:(?:\.{1,2}\/)|\/)?ext\/[^"'`]+)\1\s*\)/g,
129
- (/** @type {string} */ match, /** @type {string} */ quote, /** @type {string} */ path) => {
130
- const runtimePath = path.startsWith("/ext/") ? path.substring(1) : path;
131
- return `new URL(${quote}${runtimePath}${quote}, self.location?.href)`;
132
- }
133
- );
134
-
135
- return src;
136
- }
137
-
138
- /**
139
- * @param {string} src
140
- * @returns {string}
141
- */
142
- export function fixDracoRangeQueryProbe(src) {
143
- return src;
144
- }
145
-
146
- /**
147
- * @param {string} path
148
- * @param {string|Buffer} content
149
- * @returns {string}
150
- */
151
- export function getValidFilename(path, content) {
152
- if (path.startsWith("http:") || path.startsWith("https:")) {
153
- const url = new URL(path);
154
- const pathParts = url.pathname.split('/');
155
- const filename = pathParts.pop() || 'file';
156
- const nameParts = filename.split('.');
157
- const nameWithoutExt = nameParts.slice(0, -1).join('.');
158
- path = nameWithoutExt + "-" + createContentMd5(url.host + pathParts.join('/')) + "." + (nameParts.pop() || 'unknown');
159
- }
160
-
161
- let name = path.replace(/[^a-z0-9_\-\.\+]/gi, '-');
162
-
163
- const maxLength = 200;
164
- if (path.length > maxLength) {
165
- const hash = createContentMd5(content);
166
- let ext = "";
167
- const extIndex = name.lastIndexOf('.');
168
- if (extIndex !== -1) {
169
- ext = name.substring(extIndex + 1);
170
- name = name.substring(0, extIndex);
171
- }
172
- name = name.substring(0, maxLength) + "-" + hash + (ext ? "." + ext : '');
173
- }
174
- return name;
175
- }
176
-
177
- /**
178
- * @param {string} str
179
- * @returns {string}
180
- */
181
- function createContentMd5(str) {
182
- return createHash('md5')
183
- .update(str)
184
- .digest('hex');
185
- }
186
-
187
- /**
188
- * @param {string} url
189
- * @returns {Promise<string>}
190
- */
191
- export function downloadText(url) {
192
- return new Promise((res, rej) => {
193
- const timer = setTimeout(() => {
194
- rej(new Error("Download timed out after " + DOWNLOAD_TIMEOUT_MS + "ms: " + url));
195
- }, DOWNLOAD_TIMEOUT_MS);
196
-
197
- const req = (url.startsWith("http://") ? http.get(url, (response) => {
198
- if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
199
- clearTimeout(timer);
200
- return downloadText(response.headers.location).then(res).catch(rej);
201
- }
202
-
203
- if (response.statusCode !== 200) {
204
- clearTimeout(timer);
205
- clearSpinnerLine();
206
- rej(new Error("Failed to download (" + response.statusCode + "): " + url));
207
- return;
208
- }
209
-
210
- updateMakeLocalProgress(url);
211
-
212
- let data = '';
213
- response.on('data', (/** @type {Buffer|string} */ chunk) => {
214
- data += chunk;
215
- });
216
- response.on('end', () => {
217
- clearTimeout(timer);
218
- res(data);
219
- });
220
- response.on('error', (err) => {
221
- clearTimeout(timer);
222
- rej(err);
223
- });
224
- }) : https.get(url, (response) => {
225
- if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
226
- clearTimeout(timer);
227
- return downloadText(response.headers.location).then(res).catch(rej);
228
- }
229
-
230
- if (response.statusCode !== 200) {
231
- clearTimeout(timer);
232
- clearSpinnerLine();
233
- rej(new Error("Failed to download (" + response.statusCode + "): " + url));
234
- return;
235
- }
236
-
237
- updateMakeLocalProgress(url);
238
-
239
- let data = '';
240
- response.on('data', (/** @type {Buffer|string} */ chunk) => {
241
- data += chunk;
242
- });
243
- response.on('end', () => {
244
- clearTimeout(timer);
245
- res(data);
246
- });
247
- response.on('error', (err) => {
248
- clearTimeout(timer);
249
- rej(err);
250
- });
251
- }));
252
- req.on('error', (err) => {
253
- clearTimeout(timer);
254
- clearSpinnerLine();
255
- rej(err);
256
- });
257
- });
258
- }
259
-
260
- /**
261
- * @param {string} url
262
- * @returns {Promise<Buffer>}
263
- */
264
- export function downloadBinary(url) {
265
- return new Promise((res, rej) => {
266
- const timer = setTimeout(() => {
267
- rej(new Error("Download timed out after " + DOWNLOAD_TIMEOUT_MS + "ms: " + url));
268
- }, DOWNLOAD_TIMEOUT_MS);
269
-
270
- const req = (url.startsWith("http://") ? http.get(url, (response) => {
271
- if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
272
- clearTimeout(timer);
273
- return downloadBinary(response.headers.location).then(res).catch(rej);
274
- }
275
-
276
- if (response.statusCode !== 200) {
277
- clearTimeout(timer);
278
- clearSpinnerLine();
279
- rej(new Error("Failed to download (" + response.statusCode + "): " + url));
280
- return;
281
- }
282
-
283
- updateMakeLocalProgress(url);
284
-
285
- const chunks = /** @type {Buffer[]} */ ([]);
286
- response.on('data', (/** @type {Buffer|string} */ chunk) => {
287
- chunks.push(chunk);
288
- });
289
- response.on('end', () => {
290
- clearTimeout(timer);
291
- res(Buffer.concat(chunks));
292
- });
293
- response.on('error', (err) => {
294
- clearTimeout(timer);
295
- rej(err);
296
- });
297
- }) : https.get(url, (response) => {
298
- if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
299
- clearTimeout(timer);
300
- return downloadBinary(response.headers.location).then(res).catch(rej);
301
- }
302
-
303
- if (response.statusCode !== 200) {
304
- clearTimeout(timer);
305
- clearSpinnerLine();
306
- rej(new Error("Failed to download (" + response.statusCode + "): " + url));
307
- return;
308
- }
309
-
310
- updateMakeLocalProgress(url);
311
-
312
- const chunks = /** @type {Buffer[]} */ ([]);
313
- response.on('data', (/** @type {Buffer|string} */ chunk) => {
314
- chunks.push(chunk);
315
- });
316
- response.on('end', () => {
317
- clearTimeout(timer);
318
- res(Buffer.concat(chunks));
319
- });
320
- response.on('error', (err) => {
321
- clearTimeout(timer);
322
- rej(err);
323
- });
324
- }));
325
- req.on('error', (err) => {
326
- clearTimeout(timer);
327
- clearSpinnerLine();
328
- rej(err);
329
- });
330
- });
331
- }
332
-
333
- /**
334
- * @param {LocalizationContext} context
335
- * @param {string} url
336
- * @param {unknown} err
337
- */
338
- export function recordFailedDownload(context, url, err) {
339
- if (!url || !context?.failedDownloads) return;
340
- const message = err?.message ? String(err.message) : "";
341
- if (!context.failedDownloads.has(url)) {
342
- context.failedDownloads.set(url, message);
343
- }
344
- }
345
-
346
- /**
347
- * @param {string} url
348
- * @returns {string}
349
- */
350
- export function getShortUrlName(url) {
351
- try {
352
- const parsed = new URL(url);
353
- const parts = parsed.pathname.split("/").filter(Boolean);
354
- return parts[parts.length - 1] || parsed.host;
355
- }
356
- catch {
357
- return url;
358
- }
359
- }
@@ -1,129 +0,0 @@
1
- import picocolors from 'picocolors';
2
-
3
- const { createColors, isColorSupported } = picocolors;
4
-
5
- const colors = createColors(isColorSupported);
6
- /** @type {null | (() => void)} */
7
- let transientLogLineCleaner = null;
8
-
9
- function getConsoleMethod(level) {
10
- if (level === 'error') return console.error;
11
- if (level === 'warn') return console.warn;
12
- return console.log;
13
- }
14
-
15
- function colorBodyByLevel(level, text) {
16
- if (!isColorSupported) return text;
17
- if (level === 'error') return colors.red(text);
18
- if (level === 'warn') return colors.yellow(text);
19
- return text;
20
- }
21
-
22
- function normalizeMessage(message) {
23
- if (Array.isArray(message)) return message.join("\n");
24
- if (message === undefined || message === null) return "";
25
- return String(message);
26
- }
27
-
28
- function formatHeader(pluginName) {
29
- if (!isColorSupported) return `[${pluginName}]`;
30
-
31
- const name = String(pluginName ?? "");
32
- let prefix = "";
33
- let suffix = name;
34
- if (name.startsWith("needle-")) {
35
- prefix = "needle-";
36
- suffix = name.substring("needle-".length);
37
- }
38
- else if (name.startsWith("needle:")) {
39
- prefix = "needle:";
40
- suffix = name.substring("needle:".length);
41
- }
42
-
43
- const open = colors.green("[");
44
- const close = colors.green("]");
45
- if (!prefix.length) {
46
- return `${open}${colors.bold(colors.green(name))}${close}`;
47
- }
48
- const prefixStyled = colors.green(prefix);
49
- const suffixStyled = colors.bold(colors.green(suffix));
50
- return `${open}${prefixStyled}${suffixStyled}${close}`;
51
- }
52
-
53
- /**
54
- * @param {string} pluginName
55
- * @param {string | string[]} message
56
- * @param {'log' | 'warn' | 'error'} [level='log']
57
- * @param {{ dimBody?: boolean, leadingNewline?: boolean, showHeader?: boolean }} [options]
58
- */
59
- export function needleLog(pluginName, message, level = 'log', options = undefined) {
60
- if (typeof transientLogLineCleaner === "function") {
61
- transientLogLineCleaner();
62
- }
63
- const log = getConsoleMethod(level);
64
- const headerText = formatHeader(pluginName);
65
- const bodyText = normalizeMessage(message);
66
- const dimBody = options?.dimBody ?? (level === 'log');
67
- const leadingNewline = options?.leadingNewline === true;
68
- const showHeader = options?.showHeader !== false;
69
-
70
- if (isColorSupported) {
71
- const header = `\x1b[0m${headerText}`;
72
- const leveledBody = colorBodyByLevel(level, bodyText);
73
- const body = bodyText.length > 0
74
- ? (dimBody ? leveledBody.split('\n').map(l => colors.dim(l)).join('\n') : leveledBody)
75
- : "";
76
- const payloadCore = showHeader
77
- ? (body.length > 0 ? `${header}\n${body}\n` : `${header}\n`)
78
- : (body.length > 0 ? `${body}\n` : "");
79
- const payload = leadingNewline ? `\n${payloadCore}` : payloadCore;
80
- log(payload);
81
- return;
82
- }
83
-
84
- if (bodyText.length > 0) {
85
- const out = showHeader ? `${headerText} ${bodyText}` : bodyText;
86
- log(leadingNewline ? `\n${out}` : out);
87
- }
88
- else {
89
- const out = showHeader ? headerText : "";
90
- if (out.length > 0) {
91
- log(leadingNewline ? `\n${out}` : out);
92
- }
93
- }
94
- }
95
-
96
- /**
97
- * @param {string} pluginName
98
- * @param {string[]} lines
99
- * @param {'log' | 'warn' | 'error'} [level='log']
100
- */
101
- export function needleLogLines(pluginName, lines, level = 'log') {
102
- needleLog(pluginName, lines.join("\n"), level);
103
- }
104
-
105
- export function needleSupportsColor() {
106
- return isColorSupported;
107
- }
108
-
109
- export function needleBlue(text) {
110
- const value = String(text ?? "");
111
- return isColorSupported ? colors.blue(value) : value;
112
- }
113
-
114
- export function needleDim(text) {
115
- const value = String(text ?? "");
116
- return isColorSupported ? colors.dim(value) : value;
117
- }
118
-
119
- export function needleGreenBold(text) {
120
- const value = String(text ?? "");
121
- return isColorSupported ? colors.bold(colors.green(value)) : value;
122
- }
123
-
124
- /**
125
- * @param {(() => void) | null} cleaner
126
- */
127
- export function setTransientLogLineCleaner(cleaner) {
128
- transientLogLineCleaner = typeof cleaner === "function" ? cleaner : null;
129
- }