bambu-printer-mcp 1.1.6 → 1.1.8
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/CONTRIBUTORS.md +26 -0
- package/README.md +98 -25
- package/dist/blender-mcp-bridge.d.ts +10 -0
- package/dist/blender-mcp-bridge.js +389 -0
- package/dist/index.js +116 -80
- package/dist/printers/bambu.js +31 -13
- package/dist/slicer/profile-flatten.d.ts +15 -4
- package/dist/slicer/profile-flatten.js +181 -74
- package/dist/stl/stl-manipulator.d.ts +3 -17
- package/dist/stl/stl-manipulator.js +142 -85
- package/package.json +8 -4
- package/patches/bambu-node+3.22.21.patch +18 -2
- package/scripts/install-patches.mjs +64 -0
- package/src/blender-mcp-bridge.ts +344 -0
- package/src/index.ts +133 -103
- package/src/printers/bambu.ts +29 -13
- package/src/slicer/profile-flatten.ts +202 -80
- package/src/stl/stl-manipulator.ts +161 -98
|
@@ -117,13 +117,18 @@ export class STLManipulator extends EventEmitter {
|
|
|
117
117
|
return crypto.randomUUID();
|
|
118
118
|
}
|
|
119
119
|
getAvailableProfileRoots() {
|
|
120
|
-
|
|
120
|
+
const selectedRoot = process.env.BAMBU_PROFILES_ROOT;
|
|
121
|
+
return [
|
|
122
|
+
...(selectedRoot ? [path.join(selectedRoot, 'BBL')] : []),
|
|
123
|
+
...configuredBambuProfileDirs(),
|
|
124
|
+
...BAMBU_PROFILE_ROOTS,
|
|
125
|
+
].filter((root) => fs.existsSync(root));
|
|
121
126
|
}
|
|
122
|
-
findProfileFile(category, profileName) {
|
|
127
|
+
findProfileFile(category, profileName, roots = this.getAvailableProfileRoots()) {
|
|
123
128
|
if (!profileName) {
|
|
124
129
|
return undefined;
|
|
125
130
|
}
|
|
126
|
-
for (const root of
|
|
131
|
+
for (const root of roots) {
|
|
127
132
|
const candidate = path.join(root, category, `${profileName}.json`);
|
|
128
133
|
if (fs.existsSync(candidate)) {
|
|
129
134
|
return candidate;
|
|
@@ -131,9 +136,9 @@ export class STLManipulator extends EventEmitter {
|
|
|
131
136
|
}
|
|
132
137
|
return undefined;
|
|
133
138
|
}
|
|
134
|
-
buildFilamentIdIndex() {
|
|
139
|
+
buildFilamentIdIndex(roots = this.getAvailableProfileRoots()) {
|
|
135
140
|
const index = new Map();
|
|
136
|
-
for (const root of
|
|
141
|
+
for (const root of roots) {
|
|
137
142
|
const filamentDir = path.join(root, 'filament');
|
|
138
143
|
if (!fs.existsSync(filamentDir)) {
|
|
139
144
|
continue;
|
|
@@ -195,17 +200,27 @@ export class STLManipulator extends EventEmitter {
|
|
|
195
200
|
return sanitized;
|
|
196
201
|
}
|
|
197
202
|
writeTempJson(outputBase, suffix, value) {
|
|
198
|
-
const
|
|
199
|
-
|
|
203
|
+
const serialized = JSON.stringify(value, null, 2);
|
|
204
|
+
const hash = crypto.createHash('sha256').update(serialized).digest('hex').slice(0, 16);
|
|
205
|
+
const outPath = path.join(this.tempDir, `${outputBase}_${suffix}_${hash}.json`);
|
|
206
|
+
fs.writeFileSync(outPath, serialized);
|
|
200
207
|
return outPath;
|
|
201
208
|
}
|
|
202
|
-
resolveBambuLikeSettingsBundle(outputBase, slicerType, slicerProfile, printerPreset, bambuOptions) {
|
|
203
|
-
const
|
|
209
|
+
resolveBambuLikeSettingsBundle(outputBase, slicerType, slicerProfile, printerPreset, bambuOptions, activeProfilesRoot) {
|
|
210
|
+
const roots = activeProfilesRoot
|
|
211
|
+
? [path.join(activeProfilesRoot, 'BBL'), ...this.getAvailableProfileRoots()]
|
|
212
|
+
: this.getAvailableProfileRoots();
|
|
213
|
+
const findProfile = (kind, name) => this.findProfileFile(kind, name, roots);
|
|
214
|
+
const machinePath = findProfile('machine', printerPreset);
|
|
215
|
+
if (slicerType === 'bambustudio' && printerPreset && !machinePath) {
|
|
216
|
+
throw new Error(`Printer profile "${printerPreset}" was not found. Set BAMBU_PROFILES_ROOT to the matching BambuStudio profile tree; refusing to use printer defaults.`);
|
|
217
|
+
}
|
|
204
218
|
const machineConfig = machinePath ? this.readJsonFile(machinePath) : null;
|
|
205
219
|
const hasSlicerProfile = !!slicerProfile && fs.existsSync(slicerProfile);
|
|
206
220
|
const filamentPaths = [];
|
|
207
221
|
let processPath;
|
|
208
222
|
let parsedProfile = null;
|
|
223
|
+
let processSource;
|
|
209
224
|
if (hasSlicerProfile) {
|
|
210
225
|
try {
|
|
211
226
|
parsedProfile = this.readJsonFile(slicerProfile);
|
|
@@ -215,6 +230,7 @@ export class STLManipulator extends EventEmitter {
|
|
|
215
230
|
}
|
|
216
231
|
}
|
|
217
232
|
if (parsedProfile && typeof parsedProfile === 'object') {
|
|
233
|
+
processSource = { filePath: slicerProfile, profile: parsedProfile };
|
|
218
234
|
const inheritedProcessName = (typeof parsedProfile.inherits === 'string' && parsedProfile.inherits) ||
|
|
219
235
|
(typeof parsedProfile.print_settings_id === 'string' &&
|
|
220
236
|
parsedProfile.print_settings_id !== parsedProfile.name
|
|
@@ -226,7 +242,7 @@ export class STLManipulator extends EventEmitter {
|
|
|
226
242
|
(typeof machineConfig?.default_print_profile === 'string'
|
|
227
243
|
? machineConfig.default_print_profile
|
|
228
244
|
: undefined);
|
|
229
|
-
const inheritedProcessPath =
|
|
245
|
+
const inheritedProcessPath = findProfile('process', inheritedProcessName);
|
|
230
246
|
const inheritedProcess = inheritedProcessPath && fs.existsSync(inheritedProcessPath)
|
|
231
247
|
? this.readJsonFile(inheritedProcessPath)
|
|
232
248
|
: {};
|
|
@@ -238,22 +254,28 @@ export class STLManipulator extends EventEmitter {
|
|
|
238
254
|
processPath = this.writeTempJson(outputBase, slicerType === 'orcaslicer' ? 'process_orca' : 'process', slicerType === 'orcaslicer'
|
|
239
255
|
? this.sanitizeProcessForOrca(mergedProcess, printerPreset)
|
|
240
256
|
: mergedProcess);
|
|
241
|
-
const defaultFilamentProfiles = Array.isArray(parsedProfile.default_filament_profile)
|
|
257
|
+
const defaultFilamentProfiles = !bambuOptions?.loadFilaments && Array.isArray(parsedProfile.default_filament_profile)
|
|
242
258
|
? parsedProfile.default_filament_profile
|
|
243
259
|
: [];
|
|
244
260
|
for (const profileName of defaultFilamentProfiles) {
|
|
245
|
-
const filamentPath =
|
|
261
|
+
const filamentPath = findProfile('filament', String(profileName));
|
|
246
262
|
if (filamentPath) {
|
|
247
263
|
filamentPaths.push(filamentPath);
|
|
248
264
|
}
|
|
265
|
+
else {
|
|
266
|
+
throw new Error(`Filament profile "${String(profileName)}" was not found; refusing to omit its slot.`);
|
|
267
|
+
}
|
|
249
268
|
}
|
|
250
|
-
if (filamentPaths.length === 0 && Array.isArray(parsedProfile.filament_ids)) {
|
|
251
|
-
const filamentIdIndex = this.buildFilamentIdIndex();
|
|
269
|
+
if (!bambuOptions?.loadFilaments && filamentPaths.length === 0 && Array.isArray(parsedProfile.filament_ids)) {
|
|
270
|
+
const filamentIdIndex = this.buildFilamentIdIndex(roots);
|
|
252
271
|
for (const filamentId of parsedProfile.filament_ids) {
|
|
253
272
|
const filamentPath = filamentIdIndex.get(String(filamentId));
|
|
254
273
|
if (filamentPath) {
|
|
255
274
|
filamentPaths.push(filamentPath);
|
|
256
275
|
}
|
|
276
|
+
else {
|
|
277
|
+
throw new Error(`Filament ID "${String(filamentId)}" could not be resolved; refusing to omit its slot.`);
|
|
278
|
+
}
|
|
257
279
|
}
|
|
258
280
|
}
|
|
259
281
|
}
|
|
@@ -264,7 +286,7 @@ export class STLManipulator extends EventEmitter {
|
|
|
264
286
|
const defaultProcessName = typeof machineConfig?.default_print_profile === 'string'
|
|
265
287
|
? machineConfig.default_print_profile
|
|
266
288
|
: undefined;
|
|
267
|
-
const defaultProcessPath =
|
|
289
|
+
const defaultProcessPath = findProfile('process', defaultProcessName);
|
|
268
290
|
if (defaultProcessPath) {
|
|
269
291
|
processPath =
|
|
270
292
|
slicerType === 'orcaslicer'
|
|
@@ -276,10 +298,13 @@ export class STLManipulator extends EventEmitter {
|
|
|
276
298
|
filamentPaths.length === 0 &&
|
|
277
299
|
Array.isArray(machineConfig?.default_filament_profile)) {
|
|
278
300
|
for (const profileName of machineConfig.default_filament_profile) {
|
|
279
|
-
const filamentPath =
|
|
301
|
+
const filamentPath = findProfile('filament', String(profileName));
|
|
280
302
|
if (filamentPath) {
|
|
281
303
|
filamentPaths.push(filamentPath);
|
|
282
304
|
}
|
|
305
|
+
else {
|
|
306
|
+
throw new Error(`Filament profile "${String(profileName)}" was not found; refusing to omit its slot.`);
|
|
307
|
+
}
|
|
283
308
|
}
|
|
284
309
|
}
|
|
285
310
|
if (bambuOptions?.loadFilaments) {
|
|
@@ -294,68 +319,111 @@ export class STLManipulator extends EventEmitter {
|
|
|
294
319
|
const settingsParts = [machinePath, processPath].filter((entry) => Boolean(entry));
|
|
295
320
|
return {
|
|
296
321
|
settingsArg: settingsParts.length > 0 ? settingsParts.join(';') : undefined,
|
|
297
|
-
filamentPaths
|
|
322
|
+
filamentPaths,
|
|
323
|
+
processSource,
|
|
298
324
|
};
|
|
299
325
|
}
|
|
300
|
-
/**
|
|
301
|
-
* Optionally rewrite a Bambu-like settings bundle so the paths point at
|
|
302
|
-
* fully-flattened temp configs instead of the BBL-shipped leaf JSONs.
|
|
303
|
-
*
|
|
304
|
-
* BambuStudio's CLI does not resolve the `inherits` chain when loading
|
|
305
|
-
* profiles via --load-settings / --load-filaments, which causes a
|
|
306
|
-
* cluster of upstream bugs (see https://github.com/bambulab/BambuStudio/issues/9636
|
|
307
|
-
* and #9968). Our flattener (src/slicer/profile-flatten.ts) reproduces
|
|
308
|
-
* what the GUI does at slice time so the CLI accepts the configs.
|
|
309
|
-
*
|
|
310
|
-
* Opt-in via `BAMBU_CLI_FLATTEN=true`. When the env var is unset or
|
|
311
|
-
* not "true"/"1", returns the bundle unchanged so behavior is
|
|
312
|
-
* backward-compatible. When enabled, only BBL-shipped leaves get
|
|
313
|
-
* flattened; user-provided custom configs pass through untouched.
|
|
314
|
-
*/
|
|
326
|
+
/** Resolve BBL dependencies before invoking the CLI; failures stop the slice. */
|
|
315
327
|
async maybeFlattenBundle(bundle, bambuOptions, activeSlicerPath) {
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
328
|
+
const parts = bundle.settingsArg?.split(';').filter(Boolean) ?? [];
|
|
329
|
+
const readProfile = (filePath) => {
|
|
330
|
+
try {
|
|
331
|
+
const data = this.readJsonFile(filePath);
|
|
332
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
333
|
+
throw new Error('expected a JSON profile object');
|
|
334
|
+
}
|
|
335
|
+
return data;
|
|
336
|
+
}
|
|
337
|
+
catch (err) {
|
|
338
|
+
throw new Error(`Cannot read slicer profile "${filePath}": ${err?.message ?? err}`);
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
const settings = parts.map(readProfile);
|
|
342
|
+
// Read every slot: filtering unreadable names would change positional mapping.
|
|
343
|
+
const filaments = bundle.filamentPaths.map(readProfile);
|
|
344
|
+
const profilesRoot = detectProfilesRoot(activeSlicerPath || process.env.SLICER_PATH);
|
|
345
|
+
const profileRoots = [path.join(profilesRoot, 'BBL'), ...this.getAvailableProfileRoots()];
|
|
346
|
+
const hasReferences = (profile) => (typeof profile.inherits === 'string' && profile.inherits.length > 0) ||
|
|
347
|
+
(profile.include !== undefined && profile.include !== null);
|
|
348
|
+
const isBundledFile = (filePath) => profileRoots.some(root => {
|
|
349
|
+
const relative = path.relative(root, filePath);
|
|
350
|
+
return relative !== '' && !relative.startsWith('..') && !path.isAbsolute(relative);
|
|
351
|
+
});
|
|
352
|
+
const isBundled = (filePath, profile) => String(profile.from).toLowerCase() === 'system' || isBundledFile(filePath);
|
|
353
|
+
const needsResolution = (filePath, profile) => hasReferences(profile) || isBundled(filePath, profile);
|
|
354
|
+
if (![...settings, ...filaments].some((profile, i) => needsResolution([...parts, ...bundle.filamentPaths][i], profile)))
|
|
324
355
|
return bundle;
|
|
356
|
+
if (parts.length !== 2) {
|
|
357
|
+
throw new Error('Resolving BBL profiles requires both a machine and process profile; refusing to slice with unresolved settings.');
|
|
358
|
+
}
|
|
325
359
|
const [machinePath, processPath] = parts;
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
360
|
+
const [machine, processProfile] = settings;
|
|
361
|
+
const leafName = (filePath, profile) => {
|
|
362
|
+
// A user preset inherits its system identity, while keeping its own values.
|
|
363
|
+
const name = !isBundled(filePath, profile) && typeof profile.inherits === 'string' && profile.inherits
|
|
364
|
+
? profile.inherits
|
|
365
|
+
: profile.name;
|
|
366
|
+
if (typeof name !== 'string' || !name) {
|
|
367
|
+
if (needsResolution(filePath, profile))
|
|
368
|
+
throw new Error(`Cannot determine the profile name for "${filePath}".`);
|
|
369
|
+
return path.basename(filePath, '.json');
|
|
370
|
+
}
|
|
371
|
+
return name;
|
|
372
|
+
};
|
|
373
|
+
const flat = await flattenForCli({
|
|
374
|
+
machineLeaf: leafName(machinePath, machine),
|
|
375
|
+
// A generated path loses bundled provenance; inherited metadata can also
|
|
376
|
+
// make a custom preset look like a system profile. Use the original source
|
|
377
|
+
// only for identity and retain the prepared values in sourceProfiles below.
|
|
378
|
+
processLeaf: bundle.processSource
|
|
379
|
+
? leafName(bundle.processSource.filePath, bundle.processSource.profile)
|
|
380
|
+
: leafName(processPath, processProfile),
|
|
381
|
+
filamentLeaves: filaments.map((profile, i) => leafName(bundle.filamentPaths[i], profile)),
|
|
382
|
+
profilesRoot,
|
|
383
|
+
tempDir: this.tempDir,
|
|
384
|
+
bedType: this.resolveBambuStudioBedType(bambuOptions?.bedType),
|
|
385
|
+
sourceProfiles: {
|
|
386
|
+
machine: isBundledFile(machinePath) ? undefined : machine,
|
|
387
|
+
process: isBundledFile(processPath) ? undefined : processProfile,
|
|
388
|
+
filaments: filaments.map((profile, i) => isBundledFile(bundle.filamentPaths[i]) ? undefined : profile),
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
// Standalone custom files have no BBL dependencies; preserve their identity
|
|
392
|
+
// and content. Other profiles retain user values through sourceProfiles.
|
|
393
|
+
return {
|
|
394
|
+
settingsArg: [
|
|
395
|
+
needsResolution(machinePath, machine) ? flat.machinePath : machinePath,
|
|
396
|
+
needsResolution(processPath, processProfile) ? flat.processPath : processPath,
|
|
397
|
+
].join(';'),
|
|
398
|
+
filamentPaths: filaments.map((profile, i) => needsResolution(bundle.filamentPaths[i], profile) ? flat.filamentPaths[i] : bundle.filamentPaths[i]),
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
/** --load-filaments is positional; a single override must cover every project slot. */
|
|
402
|
+
async expandProjectFilaments(inputPath, bundle) {
|
|
403
|
+
if (!inputPath.toLowerCase().endsWith('.3mf') || bundle.filamentPaths.length === 0)
|
|
336
404
|
return bundle;
|
|
337
|
-
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
machineLeaf,
|
|
343
|
-
processLeaf,
|
|
344
|
-
filamentLeaves,
|
|
345
|
-
profilesRoot,
|
|
346
|
-
tempDir: this.tempDir,
|
|
347
|
-
bedType,
|
|
348
|
-
});
|
|
349
|
-
console.log(`[cli-flatten] applied for ${machineLeaf} (cliOverlay=${flat.meta.cliOverlayApplied})`);
|
|
350
|
-
return {
|
|
351
|
-
settingsArg: `${flat.machinePath};${flat.processPath}`,
|
|
352
|
-
filamentPaths: flat.filamentPaths,
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
catch (err) {
|
|
356
|
-
console.error(`[cli-flatten] failed, falling back to unflattened bundle: ${err?.message ?? err}`);
|
|
405
|
+
const JSZip = (await import('jszip')).default;
|
|
406
|
+
const zip = await JSZip.loadAsync(await fs.promises.readFile(inputPath));
|
|
407
|
+
const file = zip.file('Metadata/project_settings.config');
|
|
408
|
+
// Geometry-only 3MFs have no embedded filament slots.
|
|
409
|
+
if (!file)
|
|
357
410
|
return bundle;
|
|
358
|
-
|
|
411
|
+
const config = JSON.parse(await file.async('string'));
|
|
412
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
413
|
+
throw new Error('Cannot determine project filament slots: invalid project_settings.config.');
|
|
414
|
+
}
|
|
415
|
+
const data = config;
|
|
416
|
+
const count = Math.max(0, ...['filament_settings_id', 'filament_type', 'filament_colour', 'filament_diameter']
|
|
417
|
+
.map(key => Array.isArray(data[key]) ? data[key].length : 0));
|
|
418
|
+
if (count === 0)
|
|
419
|
+
throw new Error('Cannot determine project filament slots from project_settings.config.');
|
|
420
|
+
if (bundle.filamentPaths.length === 1) {
|
|
421
|
+
return { ...bundle, filamentPaths: Array(count).fill(bundle.filamentPaths[0]) };
|
|
422
|
+
}
|
|
423
|
+
if (bundle.filamentPaths.length !== count) {
|
|
424
|
+
throw new Error(`Project declares ${count} filament slots, but ${bundle.filamentPaths.length} profiles were supplied. Provide one profile for all slots or one per slot.`);
|
|
425
|
+
}
|
|
426
|
+
return bundle;
|
|
359
427
|
}
|
|
360
428
|
resolveBambuStudioBedType(bedType) {
|
|
361
429
|
if (!bedType)
|
|
@@ -366,16 +434,6 @@ export class STLManipulator extends EventEmitter {
|
|
|
366
434
|
}
|
|
367
435
|
return BAMBU_CLI_BED_TYPES[normalized] || bedType;
|
|
368
436
|
}
|
|
369
|
-
/** Read a profile JSON's top-level `name` field, or null if unreadable. */
|
|
370
|
-
readLeafName(filePath) {
|
|
371
|
-
try {
|
|
372
|
-
const data = this.readJsonFile(filePath);
|
|
373
|
-
return typeof data?.name === 'string' && data.name.length > 0 ? data.name : null;
|
|
374
|
-
}
|
|
375
|
-
catch {
|
|
376
|
-
return null;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
437
|
/**
|
|
380
438
|
* Load STL file and return geometry and bounding box
|
|
381
439
|
*/
|
|
@@ -1145,11 +1203,10 @@ export class STLManipulator extends EventEmitter {
|
|
|
1145
1203
|
const outputBase = path.basename(stlFilePath, is3mf ? '.3mf' : '.stl');
|
|
1146
1204
|
const bambuOutputPath = path.join(this.tempDir, outputBase + '_sliced.3mf');
|
|
1147
1205
|
const outputDir = path.dirname(bambuOutputPath);
|
|
1148
|
-
const rawBundle = this.resolveBambuLikeSettingsBundle(outputBase, slicerType, slicerProfile, printerPreset, bambuOptions);
|
|
1149
|
-
//
|
|
1150
|
-
// CLI accepts what we hand it. See maybeFlattenBundle docstring.
|
|
1206
|
+
const rawBundle = this.resolveBambuLikeSettingsBundle(outputBase, slicerType, slicerProfile, printerPreset, bambuOptions, slicerType === 'bambustudio' ? detectProfilesRoot(slicerPath) : undefined);
|
|
1207
|
+
// Resolve every BBL dependency before launching the slicer.
|
|
1151
1208
|
const settingsBundle = slicerType === 'bambustudio'
|
|
1152
|
-
? await this.maybeFlattenBundle(rawBundle, bambuOptions, slicerPath)
|
|
1209
|
+
? await this.maybeFlattenBundle(await this.expandProjectFilaments(stlFilePath, rawBundle), bambuOptions, slicerPath)
|
|
1153
1210
|
: rawBundle;
|
|
1154
1211
|
args = [
|
|
1155
1212
|
'--slice', String(bambuOptions?.slicePlate ?? 0),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bambu-printer-mcp",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "MCP server for Bambu Lab 3D printers with STL manipulation, slicing, and print management",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
"start:http": "MCP_TRANSPORT=streamable-http node dist/index.js",
|
|
15
15
|
"build": "tsc",
|
|
16
16
|
"test": "npm run build && node --test tests/*.test.mjs tests/**/*.test.mjs",
|
|
17
|
-
"
|
|
17
|
+
"package:mcpb": "npm run build && node scripts/package-mcpb.mjs",
|
|
18
|
+
"version": "node scripts/sync-manifest-version.mjs",
|
|
19
|
+
"postinstall": "node scripts/install-patches.mjs"
|
|
18
20
|
},
|
|
19
21
|
"bin": {
|
|
20
22
|
"bambu-printer-mcp": "dist/index.js"
|
|
@@ -23,7 +25,9 @@
|
|
|
23
25
|
"dist",
|
|
24
26
|
"src",
|
|
25
27
|
"patches",
|
|
28
|
+
"scripts/install-patches.mjs",
|
|
26
29
|
"README.md",
|
|
30
|
+
"CONTRIBUTORS.md",
|
|
27
31
|
"LICENSE"
|
|
28
32
|
],
|
|
29
33
|
"keywords": [
|
|
@@ -40,12 +44,12 @@
|
|
|
40
44
|
"dependencies": {
|
|
41
45
|
"@modelcontextprotocol/sdk": "^1.27.0",
|
|
42
46
|
"bambu-js": "^2.2.2",
|
|
43
|
-
"bambu-node": "
|
|
47
|
+
"bambu-node": "3.22.21",
|
|
44
48
|
"basic-ftp": "^5.0.5",
|
|
45
49
|
"dotenv": "^16.3.1",
|
|
46
50
|
"jszip": "^3.10.1",
|
|
47
51
|
"mqtt": "^5.15.1",
|
|
48
|
-
"patch-package": "
|
|
52
|
+
"patch-package": "8.0.1",
|
|
49
53
|
"three": "^0.173.0",
|
|
50
54
|
"xml2js": "^0.6.2"
|
|
51
55
|
},
|
|
@@ -1,5 +1,21 @@
|
|
|
1
|
+
diff --git a/node_modules/bambu-node/dist/index.d.ts b/node_modules/bambu-node/dist/index.d.ts
|
|
2
|
+
index c0e8d81..573d072 100644
|
|
3
|
+
--- a/node_modules/bambu-node/dist/index.d.ts
|
|
4
|
+
+++ b/node_modules/bambu-node/dist/index.d.ts
|
|
5
|
+
@@ -1079,6 +1079,11 @@ declare enum PrinterModel {
|
|
6
|
+
X1E = "X1E",
|
|
7
|
+
P1P = "P1P",
|
|
8
|
+
P1S = "P1S",
|
|
9
|
+
+ P2S = "P2S",
|
|
10
|
+
+ H2S = "H2S",
|
|
11
|
+
+ H2D = "H2D",
|
|
12
|
+
+ H2C = "H2C",
|
|
13
|
+
+ H2DPRO = "H2DPRO",
|
|
14
|
+
A1 = "A1",
|
|
15
|
+
A1M = "A1M"
|
|
16
|
+
}
|
|
1
17
|
diff --git a/node_modules/bambu-node/dist/index.js b/node_modules/bambu-node/dist/index.js
|
|
2
|
-
index 916e924..
|
|
18
|
+
index 916e924..6eb81e9 100644
|
|
3
19
|
--- a/node_modules/bambu-node/dist/index.js
|
|
4
20
|
+++ b/node_modules/bambu-node/dist/index.js
|
|
5
21
|
@@ -1,4 +1,4 @@
|
|
@@ -13,4 +29,4 @@ index 916e924..6cc3f33 100644
|
|
|
13
29
|
{if activate_air_filtration[current_extruder] && support_air_filtration}
|
|
14
30
|
M106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]}
|
|
15
31
|
-{endif}`],filament_id:"GFL01",filament_flow_ratio:["0.98"],filament_vendor:["Polymaker"]}};var W;(function(e){e[e.PRINTING=0]="PRINTING",e[e.BED_LEVELING=1]="BED_LEVELING",e[e.HEATBED_PREHEATING=2]="HEATBED_PREHEATING",e[e.XY_MECH_MODE_SWEEP=3]="XY_MECH_MODE_SWEEP",e[e.CHANGE_MATERIAL=4]="CHANGE_MATERIAL",e[e.M400_PAUSE=5]="M400_PAUSE",e[e.FILAMENT_RUNOUT_PAUSE=6]="FILAMENT_RUNOUT_PAUSE",e[e.HOTEND_HEATING=7]="HOTEND_HEATING",e[e.EXTRUDE_COMPENSATION_SCAN=8]="EXTRUDE_COMPENSATION_SCAN",e[e.BED_SCAN=9]="BED_SCAN",e[e.FIRST_LAYER_SCAN=10]="FIRST_LAYER_SCAN",e[e.BE_SURFACE_TYPT_IDENTIFICATION=11]="BE_SURFACE_TYPT_IDENTIFICATION",e[e.SCANNER_EXTRINSIC_PARA_CALI=12]="SCANNER_EXTRINSIC_PARA_CALI",e[e.TOOLHEAD_HOMING=13]="TOOLHEAD_HOMING",e[e.NOZZLE_TIP_CLEANING=14]="NOZZLE_TIP_CLEANING",e[e.EXTRUDER_TEMP_PROTECT_CALI=15]="EXTRUDER_TEMP_PROTECT_CALI",e[e.USER_PAUSE=16]="USER_PAUSE",e[e.TOOLHEAD_SHELL_OFF_PAUSE=17]="TOOLHEAD_SHELL_OFF_PAUSE",e[e.SCANNER_LASER_PARA_CALI=18]="SCANNER_LASER_PARA_CALI",e[e.EXTRUDER_ABSOLUTE_FLOW_CALI=19]="EXTRUDER_ABSOLUTE_FLOW_CALI",e[e.HOTEND_TEMPERATURE_ERROR_PAUSE=20]="HOTEND_TEMPERATURE_ERROR_PAUSE",e[e.HEATED_BED_TEMPERATURE_ERROR_PAUSE=21]="HEATED_BED_TEMPERATURE_ERROR_PAUSE",e[e.FILAMENT_UNLOADING=22]="FILAMENT_UNLOADING",e[e.SKIP_STEP_PAUSE=23]="SKIP_STEP_PAUSE",e[e.FILAMENT_LOADING=24]="FILAMENT_LOADING",e[e.MOTOR_NOISE_CALIBRATION=25]="MOTOR_NOISE_CALIBRATION",e[e.AMS_LOST_PAUSE=26]="AMS_LOST_PAUSE",e[e.HEAT_BREAK_FAN_PAUSE=27]="HEAT_BREAK_FAN_PAUSE",e[e.CHAMBER_TEMPERATURE_CONTROL_ERROR_PAUSE=28]="CHAMBER_TEMPERATURE_CONTROL_ERROR_PAUSE",e[e.CHAMBER_COOLING=29]="CHAMBER_COOLING",e[e.USER_INSERT_GCODE_PAUSE=30]="USER_INSERT_GCODE_PAUSE",e[e.MOTOR_NOISE_SHOWOFF=31]="MOTOR_NOISE_SHOWOFF",e[e.NOZZLE_FILAMENT_COVERED_DETECTED_PAUSE=32]="NOZZLE_FILAMENT_COVERED_DETECTED_PAUSE",e[e.CUTTER_ERROR_PAUSE=33]="CUTTER_ERROR_PAUSE",e[e.FIRST_LAYER_ERROR_PAUSE=34]="FIRST_LAYER_ERROR_PAUSE",e[e.NOZZLE_CLOG_PAUSE=35]="NOZZLE_CLOG_PAUSE"})(W||(W={}));var X;(function(e){e.SILENT="1",e.NORMAL="2",e.SPORT="3",e.LUDICROUS="4"})(X||(X={}));var V;(function(e){e[e.IDLE=0]="IDLE",e[e.READING=1]="READING",e[e.GCODE_TRANS=2]="GCODE_TRANS",e[e.GCODE_RUNNING=3]="GCODE_RUNNING",e[e.ASSISTANT=4]="ASSISTANT",e[e.SWITCH_FILAMENT=5]="SWITCH_FILAMENT",e[e.HAS_FILAMENT=6]="HAS_FILAMENT"})(V||(V={}));var $;(function(e){e.DOWNLOADING="DOWNLOADING",e.UPGRADE_REQUEST="UPGRADE_REQUEST",e.PRE_FLASH_START="PRE_FLASH_START",e.PRE_FLASH_SUCCESS="PRE_FLASH_SUCCESS"})($||($={}));var Z;(function(e){e.UPGRADE_SUCCESS="UPGRADE_SUCCESS",e.DOWNLOAD_FAIL="DOWNLOAD_FAIL",e.FLASH_FAIL="FLASH_FAIL",e.PRE_FLASH_FAIL="PRE_FLASH_FAIL",e.UPGRADE_FAIL="UPGRADE_FAIL"})(Z||(Z={}));var Y;(function(e){e[e.UpgradeNoError=0]="UpgradeNoError",e[e.UpgradeDownloadFailed=1]="UpgradeDownloadFailed",e[e.UpgradeVerifyFailed=2]="UpgradeVerifyFailed",e[e.UpgradeFlashFailed=3]="UpgradeFlashFailed",e[e.UpgradePrinting=4]="UpgradePrinting"})(Y||(Y={}));var K;(function(e){e[e.UNAVAILABLE=0]="UNAVAILABLE",e[e.IDLE=1]="IDLE",e[e.UPGRADING=2]="UPGRADING",e[e.UPGRADE_FINISHED=3]="UPGRADE_FINISHED"})(K||(K={}));var Q;(function(e){e.PLA="PLA",e.ABS="ABS",e.TPU="TPU",e.PC="PC",e.ASA="ASA",e.PA_CF="PA-CF",e.PA6_CF="PA6-CF",e.PET_CF="PET-CF",e.PETG="PETG",e.PETG_CF="PETG-CF",e.PLA_AERO="PLA-AERO",e.PLA_CF="PLA-CF",e.PPA_CF="PPA-CF",e.PPA_GF="PPA-GF",e.PA="PA",e.HIPS="HIPS",e.PPS="PPS",e.PPS_CF="PPS-CF",e.PVA="PVA",e.PLA_S="PLA-S",e.PA_S="PLA-S"})(Q||(Q={}));function Je(e){return k[e]??null}r(Je,"getFilamentConfig");function h(e){return e.command==="push_status"&&Object.keys(e).length>=40}r(h,"isPushAllCommand");function ee(e){return e.command==="gcode_line"&&!!e?.param?.startsWith("M106")}r(ee,"isUpdateFanCommand");function te(e){return e.command==="push_status"&&e.hasOwnProperty("lights_report")}r(te,"isUpdateLightCommand");function _e(e){return e.command==="push_status"&&(e.hasOwnProperty("spd_lvl")||e.hasOwnProperty("spd_mag"))}r(_e,"isUpdateSpeedCommand");function re(e){return e.command===e.command}r(re,"isUpdateStateCommand");function ae(e){return e.command==="gcode_line"&&!!(e?.param?.startsWith("M104")||e?.param?.startsWith("M140"))}r(ae,"isUpdateTempCommand");function g(e){return!!e?.mc_print&&!!e?.mc_print?.command&&["push_info"].includes(e.mc_print.command)}r(g,"isMCPrintMessage");function ht(e){return e.command==="push_info"}r(ht,"isPushInfoCommand");function gt(e){let[,_,t,l]=e.param.match(/^\[(.+?)](?:\[(.+?)])?\s*(.+)$/)??[];return{sequenceId:Number(e.sequence_id),category:_,subcategory:t,content:l,rawParam:e.param}}r(gt,"getCleanPushInfoCommand");function x(e){return e.command==="get_version"}r(x,"isGetVersionCommand");function z(e){return!!e?.info&&!!e?.info?.command&&["get_version"].includes(e.info.command)}r(z,"isInfoMessage");var E=class E extends f{constructor({fileName:t}){super({param:t});n(this,"category","print");n(this,"command","gcode_file");n(this,"ownsResponse",q)}};r(E,"GCodeFileCommand");var ie=E;var S=class S extends d{constructor({gcodes:t}){super(t);n(this,"command","gcode_line");n(this,"ownsResponse",j)}};r(S,"GCodeLineCommand");var ne=S;var G=class G extends f{constructor(){super();n(this,"category","info");n(this,"command","get_version");n(this,"ownsResponse",x)}};r(G,"GetVersionCommand");var b=G;var M=class M extends f{constructor(){super();n(this,"category","pushing");n(this,"command","pushall");n(this,"ownsResponse",h)}};r(M,"PushAllCommand");var c=M;var le;(function(e){e[e.PART_COOLING_FAN=1]="PART_COOLING_FAN",e[e.AUXILIARY_FAN=2]="AUXILIARY_FAN",e[e.CHAMBER_FAN=3]="CHAMBER_FAN"})(le||(le={}));var L=class L extends d{constructor({fan:t,speed:l}){super([`M106 P${t.toString()} S${255*l/100}`]);n(this,"command","gcode_line");n(this,"ownsResponse",ee)}};r(L,"UpdateFanCommand");var me=L;var F=class F extends f{constructor({light:t,mode:l,loopOptions:a={led_on_time:0,led_off_time:0,loop_times:0,interval_time:0}}){super({led_node:t,led_mode:l,...a});n(this,"category","system");n(this,"command","ledctrl");n(this,"ownsResponse",te)}};r(F,"UpdateLightCommand");var oe=F;var N=class N extends f{constructor({speed:t}){super({param:t.toString()});n(this,"category","print");n(this,"command","print_speed");n(this,"ownsResponse",_e)}};r(N,"UpdateSpeedCommand");var pe=N;var C=class C extends f{constructor({state:t}){super();n(this,"category","print");n(this,"command");n(this,"ownsResponse",re);this.command=t}};r(C,"UpdateStateCommand");var se=C;var fe;(function(e){e.BED="M140",e.EXTRUDER="M104"})(fe||(fe={}));var T=class T extends d{constructor({part:t,temperature:l}){super([`${t} S${l}`]);n(this,"command","gcode_line");n(this,"ownsResponse",ae)}};r(T,"UpdateTempCommand");var ue=T;var p;(function(e){e.X1C="X1C",e.X1="X1",e.X1E="X1E",e.P1P="P1P",e.P1S="P1S",e.A1="A1",e.A1M="A1M"})(p||(p={}));import{createId as xe}from"@paralleldrive/cuid2";var ze=new RegExp(/\.[^/.]+$/),R=class R{constructor(_,t,l,a=new Date){n(this,"_jobData");let o=[p.P1P,p.P1S].includes(l);this._jobData={id:xe(),printerId:t,printerModel:l,name:_.subtask_name.replace(ze,""),fileName:_.subtask_name,gcodeName:_.gcode_file,jobOrigin:_.print_type,totalLayerNumber:_.total_layer_num,totalPrintTime:_.mc_remaining_time,status:_.gcode_state,stage:_.stg_cur,percentDone:_.mc_percent,layerNumber:_.layer_num,remainingTime:_.mc_remaining_time,skippedObjects:_.s_obj,statusHistory:[{status:_.gcode_state,changedAt:a}],speedLevelHistory:[{speedLevel:_.spd_lvl,speedMagnitude:_.spd_mag,changedAt:a}],printingStageHistory:[{stage:_.stg_cur,changedAt:a}],temperatureHistory:[{bedTemp:_.bed_temper,bedTargetTemp:_.bed_target_temper,interiorTemp:o?_.frame_temper:_.chamber_temper,nozzleTemp:_.nozzle_temper,nozzleTargetTemp:_.nozzle_target_temper,changedAt:a}],tempLastUpdatedAt:new Date,errorCodes:_.hms.map(m=>({attr:m.attr,code:m.code,thrownAt:a,layerNumber:_.layer_num})),createdAt:a}}update(_){if(!this._jobData)return;let t=this._jobData,l=new Date,a=[p.P1P,p.P1S].includes(this._jobData.printerModel);_.gcode_state&&t.statusHistory.at(-1)?.status!==_.gcode_state&&t.statusHistory.push({status:_.gcode_state,changedAt:l}),_.spd_lvl&&_.spd_mag&&t.speedLevelHistory.at(-1)?.speedLevel!==_.spd_lvl&&t.speedLevelHistory.push({speedLevel:_.spd_lvl,speedMagnitude:_.spd_mag,changedAt:l}),_.stg_cur&&t.printingStageHistory.at(-1)?.stage!==_.stg_cur&&t.printingStageHistory.push({stage:_.stg_cur,changedAt:l});let o=!!(_.bed_temper||_.bed_target_temper||(a?_.frame_temper:_.chamber_temper)||_.nozzle_temper||_.nozzle_target_temper),m=t.tempLastUpdatedAt.getTime()+5e3<l.getTime();if(o&&m){let s=a?_.frame_temper:_.chamber_temper,u=t.temperatureHistory.at(-1);t.temperatureHistory.push({bedTemp:_.bed_temper??u.bedTemp,bedTargetTemp:_.bed_target_temper??u.bedTargetTemp,interiorTemp:s??u.interiorTemp,nozzleTemp:_.nozzle_temper??u.nozzleTemp,nozzleTargetTemp:_.nozzle_target_temper??u.nozzleTargetTemp,changedAt:l}),t.tempLastUpdatedAt=l}let i={status:_.gcode_state??t.status,stage:_.stg_cur??t.stage,percentDone:_.mc_percent??t.percentDone,layerNumber:_.layer_num??t.layerNumber,remainingTime:_.mc_remaining_time??t.remainingTime,skippedObjects:_.s_obj??t.skippedObjects,errorCodes:_.hms?.map((s,u)=>({attr:s.attr??t.errorCodes[u].attr,code:s.code??t.errorCodes[u].code,thrownAt:l??t.errorCodes[u].thrownAt,layerNumber:_.layer_num??t.errorCodes[u].layerNumber}))??t.errorCodes};this._jobData={...this._jobData,...i}}get data(){return this._jobData}};r(R,"Job");var w=R;import*as ce from"mqtt";import*as ye from"eventemitter3";import{createId as be}from"@paralleldrive/cuid2";function I(e){return new Promise(_=>setTimeout(_,e))}r(I,"sleep");function O(e,_){let t={},l=r((a,o,m)=>{for(let i in o){let s=o[i],u=a[i];if(!(i in a&&JSON.stringify(a[i])===JSON.stringify(o[i]))){if(typeof s=="object"&&s!==null&&u!==null&&!Array.isArray(s)){m[i]=m[i]||{},l(a[i],o[i],m[i]);continue}m[i]=o[i]}}},"checkDifferences");return l(e,_,t),t}r(O,"subtractObject");var D=class D extends ye.EventEmitter{constructor(t){super();n(this,"clientOptions");n(this,"id");n(this,"mqttClient");n(this,"config");n(this,"_printerData");n(this,"_printerStatus");n(this,"jobHistory");n(this,"currentJob");this.clientOptions=t,this.id=be(),this.mqttClient=void 0,this._printerData={modules:[],model:void 0},this._printerStatus="OFFLINE",this.jobHistory=[],this.currentJob=null,this.config={host:t.host,port:t.port??8883,accessToken:t.accessToken,serialNumber:t.serialNumber,throwOnOfflineCommands:t.throwOnOfflineCommands??!1,reconnectInterval:t.reconnectInterval??1e3,connectTimeout:t.connectTimeout??2e3,keepAlive:t.keepAlive??20},this.jobHistory=t.jobHistory??[],this.currentJob=t.currentJob??null}emit(t,...l){return super.emit(t,...l)}off(t,l){return super.off(t,l),this}once(t,l){return super.once(t,l),this}on(t,l){return super.on(t,l),this}async connectMQTT(){return new Promise((t,l)=>{if(this.mqttClient)throw new Error("Can't establish a new connection while running another one!");this.mqttClient=ce.connect(`mqtts://${this.config.host}:${this.config.port}`,{username:"bblp",password:this.config.accessToken,reconnectPeriod:this.clientOptions.reconnectInterval,connectTimeout:this.clientOptions.connectTimeout,keepalive:this.clientOptions.keepAlive,resubscribe:!0,rejectUnauthorized:!1}),this.mqttClient.on("connect",async(...a)=>{await this.onConnect(...a),this.emit("client:connect"),t()}),this.mqttClient.on("disconnect",()=>{this.emit("client:disconnect",!1),this.emit("printer:statusUpdate",this._printerStatus,"OFFLINE"),this._printerStatus="OFFLINE",this.currentJob&&this.emit("job:pause",this.currentJob,!0)}),this.mqttClient.on("offline",()=>{this.emit("client:disconnect",!0),this.emit("printer:statusUpdate",this._printerStatus,"OFFLINE"),this._printerStatus="OFFLINE",this.currentJob&&this.emit("job:pause",this.currentJob,!0)}),this.mqttClient.on("message",(a,o)=>this.emit("rawMessage",a,o)),this.mqttClient.on("error",a=>{this.emit("client:error",a),l(a)})})}async connect(){return await Promise.all([this.connectMQTT()])}async disconnect(t=!1,l){return new Promise(a=>this.mqttClient?.end(t,l,a))}subscribe(t){if(this._printerStatus!=="OFFLINE"&&this.config.throwOnOfflineCommands)throw new Error(`Unable to subscribe to topic "${t}" while disconnected from printer!`);return new Promise((l,a)=>{if(!this.mqttClient)return a("Client not connected.");this.mqttClient.subscribe(t,m=>{if(m)return a(`Error subscribing to topic '${t}': ${m.message}`)});let o=r(async(m,i)=>{m===t&&await this.onMessage(i.toString(),t)},"listener");this.mqttClient.on("message",o),l()})}async executeCommand(t){if(this._printerStatus!=="OFFLINE"&&this.config.throwOnOfflineCommands)throw new Error("Unable to send commands while disconnected from printer!");return new Promise((l,a)=>{t.invoke(this).catch(m=>a(m));let o=setTimeout(()=>{a(new Error("Command execution timed out after 5 seconds."))},5e3);this.on("rawMessage",(m,i)=>{let s=JSON.parse(i.toString()),u=Object.keys(s)[0];if(!(z(s)||g(s)||y(s)))return;let P=s[u];P?.command&&t.ownsResponse(P)&&(clearTimeout(o),l(P))})})}async onConnect(t){await this.subscribe(`device/${this.config.serialNumber}/report`),await I(1e3),await this.executeCommand(new b),(this._printerData.model===p.P1P||this._printerData.model===p.P1S||this._printerData.model===p.A1||this._printerData.model===p.A1M)&&(await this.executeCommand(new c),setInterval(async()=>{await this.executeCommand(new c)},5*60*1e3))}async onMessage(t,l){let a=JSON.parse(t),o=Object.keys(a)[0];if(z(a)||g(a)||y(a)){if(y(a)&&(this.emit("message",l,o,a.print),(h(a.print)||J(a.print))&&(this._printerData={...this._printerData,...a.print},this.emit("printer:dataUpdate",this._printerData,a.print),a.print.gcode_state&&a.print.gcode_state!==this._printerStatus))){let m=this._printerStatus,i=a.print.gcode_state;if(this.emit("printer:statusUpdate",m,i),(i==="PREPARE"||i==="SLICING")&&(i="IDLE"),(m==="PREPARE"||m==="SLICING")&&(m="RUNNING"),(m==="IDLE"||m==="FINISH"||m==="FAILED")&&i==="RUNNING")this.currentJob!==null&&this.jobHistory.push(this.currentJob),this.currentJob=new w(this._printerData,this.id,this._printerData.model),this.emit("job:start",this.currentJob);else if(m==="RUNNING"&&(i==="FINISH"||i==="FAILED"||i==="IDLE"))i==="FINISH"?this.currentJob!==null&&this.emit("job:finish",this.currentJob,"SUCCESS"):i==="FAILED"?this.currentJob!==null&&this.emit("job:finish",this.currentJob,"FAILED"):i==="IDLE"&&this.currentJob!==null&&this.emit("job:finish",this.currentJob,"UNEXPECTED"),this.currentJob!==null&&this.jobHistory.push(this.currentJob),this.currentJob=null;else if(m==="RUNNING"&&i==="PAUSE")this.currentJob&&this.emit("job:pause",this.currentJob,!1);else if(m==="PAUSE"&&i==="RUNNING")this.currentJob&&this.emit("job:unpause",this.currentJob);else if(m==="OFFLINE"&&i==="PAUSE")this.emit("job:offlineRecovery",this.currentJob);else if(!(m==="OFFLINE"&&i==="RUNNING")){if(!((m==="IDLE"||m==="OFFLINE")&&(i==="FINISH"||i==="FAILED"||i==="IDLE"))){if(!((m==="FINISH"||i==="FAILED")&&i==="IDLE")){if(m!==i)throw new Error("Edge case detected while updating printer status!")}}}if(this._printerStatus=a.print.gcode_state,this.currentJob){let s=this.currentJob?.data;this.currentJob.update(a.print),this.emit("job:update",this.currentJob,O(s,this.currentJob.data))}}if(g(a)&&this.emit("message",l,o,a.print),z(a)&&(this.emit("message",l,o,a.info),x(a.info))){let m=[...new Set([...this._printerData.modules,...a.info.module])];this._printerData.modules=m,this.emit("printer:dataUpdate",this._printerData,{modules:m});let i=this._printerData.modules.find(s=>s.name==="ota");if(!i)throw new Error("OTA module version data not found, unable to determine printer model!");if(i.sn.startsWith("00M"))this._printerData.model=p.X1C;else if(i.sn.startsWith("00W"))this._printerData.model=p.X1;else if(i.sn.startsWith("03W"))this._printerData.model=p.X1E;else if(i.sn.startsWith("01S"))this._printerData.model=p.P1P;else if(i.sn.startsWith("01P"))this._printerData.model=p.P1S;else if(i.sn.startsWith("030"))this._printerData.model=p.A1;else if(i.sn.startsWith("039"))this._printerData.model=p.A1M;else throw new Error("Printer model not supported!");this.emit("printer:dataUpdate",this._printerData,{model:this._printerData.model})}}}publish(t){return new Promise((l,a)=>{if(!this.mqttClient)return a("Client not connected.");let o=typeof t=="string"?t:JSON.stringify(t),m=`device/${this.config.serialNumber}/request`;this.mqttClient.publish(m,o,i=>{if(i)return a(`Error publishing to topic '${m}': ${i.message}`);l()})})}get data(){return this._printerData}get status(){return this._printerStatus}};r(D,"BambuClient");var de=D;export{f as AbstractCommand,V as AmsRFIDStatus,de as BambuClient,le as Fan,Q as FilamentType,d as GCodeCommand,ie as GCodeFileCommand,ne as GCodeLineCommand,b as GetVersionCommand,w as Job,W as PrintStage,p as PrinterModel,c as PushAllCommand,X as SpeedLevel,me as UpdateFanCommand,oe as UpdateLightCommand,pe as UpdateSpeedCommand,se as UpdateStateCommand,ue as UpdateTempCommand,K as UpgradeDisplayState,Y as UpgradeErrorCode,Z as UpgradeStatusFinishState,$ as UpgradeStatusProgressState,gt as getCleanPushInfoCommand,Je as getFilamentConfig,j as isGCodeLineCommand,q as isGcodeFileCommand,x as isGetVersionCommand,z as isInfoMessage,g as isMCPrintMessage,y as isPrintMessage,Oe as isProjectFileCommand,h as isPushAllCommand,ht as isPushInfoCommand,J as isPushStatusCommand,ee as isUpdateFanCommand,te as isUpdateLightCommand,_e as isUpdateSpeedCommand,re as isUpdateStateCommand,ae as isUpdateTempCommand};
|
|
16
|
-
+{endif}`],filament_id:"GFL01",filament_flow_ratio:["0.98"],filament_vendor:["Polymaker"]}};var W;(function(e){e[e.PRINTING=0]="PRINTING",e[e.BED_LEVELING=1]="BED_LEVELING",e[e.HEATBED_PREHEATING=2]="HEATBED_PREHEATING",e[e.XY_MECH_MODE_SWEEP=3]="XY_MECH_MODE_SWEEP",e[e.CHANGE_MATERIAL=4]="CHANGE_MATERIAL",e[e.M400_PAUSE=5]="M400_PAUSE",e[e.FILAMENT_RUNOUT_PAUSE=6]="FILAMENT_RUNOUT_PAUSE",e[e.HOTEND_HEATING=7]="HOTEND_HEATING",e[e.EXTRUDE_COMPENSATION_SCAN=8]="EXTRUDE_COMPENSATION_SCAN",e[e.BED_SCAN=9]="BED_SCAN",e[e.FIRST_LAYER_SCAN=10]="FIRST_LAYER_SCAN",e[e.BE_SURFACE_TYPT_IDENTIFICATION=11]="BE_SURFACE_TYPT_IDENTIFICATION",e[e.SCANNER_EXTRINSIC_PARA_CALI=12]="SCANNER_EXTRINSIC_PARA_CALI",e[e.TOOLHEAD_HOMING=13]="TOOLHEAD_HOMING",e[e.NOZZLE_TIP_CLEANING=14]="NOZZLE_TIP_CLEANING",e[e.EXTRUDER_TEMP_PROTECT_CALI=15]="EXTRUDER_TEMP_PROTECT_CALI",e[e.USER_PAUSE=16]="USER_PAUSE",e[e.TOOLHEAD_SHELL_OFF_PAUSE=17]="TOOLHEAD_SHELL_OFF_PAUSE",e[e.SCANNER_LASER_PARA_CALI=18]="SCANNER_LASER_PARA_CALI",e[e.EXTRUDER_ABSOLUTE_FLOW_CALI=19]="EXTRUDER_ABSOLUTE_FLOW_CALI",e[e.HOTEND_TEMPERATURE_ERROR_PAUSE=20]="HOTEND_TEMPERATURE_ERROR_PAUSE",e[e.HEATED_BED_TEMPERATURE_ERROR_PAUSE=21]="HEATED_BED_TEMPERATURE_ERROR_PAUSE",e[e.FILAMENT_UNLOADING=22]="FILAMENT_UNLOADING",e[e.SKIP_STEP_PAUSE=23]="SKIP_STEP_PAUSE",e[e.FILAMENT_LOADING=24]="FILAMENT_LOADING",e[e.MOTOR_NOISE_CALIBRATION=25]="MOTOR_NOISE_CALIBRATION",e[e.AMS_LOST_PAUSE=26]="AMS_LOST_PAUSE",e[e.HEAT_BREAK_FAN_PAUSE=27]="HEAT_BREAK_FAN_PAUSE",e[e.CHAMBER_TEMPERATURE_CONTROL_ERROR_PAUSE=28]="CHAMBER_TEMPERATURE_CONTROL_ERROR_PAUSE",e[e.CHAMBER_COOLING=29]="CHAMBER_COOLING",e[e.USER_INSERT_GCODE_PAUSE=30]="USER_INSERT_GCODE_PAUSE",e[e.MOTOR_NOISE_SHOWOFF=31]="MOTOR_NOISE_SHOWOFF",e[e.NOZZLE_FILAMENT_COVERED_DETECTED_PAUSE=32]="NOZZLE_FILAMENT_COVERED_DETECTED_PAUSE",e[e.CUTTER_ERROR_PAUSE=33]="CUTTER_ERROR_PAUSE",e[e.FIRST_LAYER_ERROR_PAUSE=34]="FIRST_LAYER_ERROR_PAUSE",e[e.NOZZLE_CLOG_PAUSE=35]="NOZZLE_CLOG_PAUSE"})(W||(W={}));var X;(function(e){e.SILENT="1",e.NORMAL="2",e.SPORT="3",e.LUDICROUS="4"})(X||(X={}));var V;(function(e){e[e.IDLE=0]="IDLE",e[e.READING=1]="READING",e[e.GCODE_TRANS=2]="GCODE_TRANS",e[e.GCODE_RUNNING=3]="GCODE_RUNNING",e[e.ASSISTANT=4]="ASSISTANT",e[e.SWITCH_FILAMENT=5]="SWITCH_FILAMENT",e[e.HAS_FILAMENT=6]="HAS_FILAMENT"})(V||(V={}));var $;(function(e){e.DOWNLOADING="DOWNLOADING",e.UPGRADE_REQUEST="UPGRADE_REQUEST",e.PRE_FLASH_START="PRE_FLASH_START",e.PRE_FLASH_SUCCESS="PRE_FLASH_SUCCESS"})($||($={}));var Z;(function(e){e.UPGRADE_SUCCESS="UPGRADE_SUCCESS",e.DOWNLOAD_FAIL="DOWNLOAD_FAIL",e.FLASH_FAIL="FLASH_FAIL",e.PRE_FLASH_FAIL="PRE_FLASH_FAIL",e.UPGRADE_FAIL="UPGRADE_FAIL"})(Z||(Z={}));var Y;(function(e){e[e.UpgradeNoError=0]="UpgradeNoError",e[e.UpgradeDownloadFailed=1]="UpgradeDownloadFailed",e[e.UpgradeVerifyFailed=2]="UpgradeVerifyFailed",e[e.UpgradeFlashFailed=3]="UpgradeFlashFailed",e[e.UpgradePrinting=4]="UpgradePrinting"})(Y||(Y={}));var K;(function(e){e[e.UNAVAILABLE=0]="UNAVAILABLE",e[e.IDLE=1]="IDLE",e[e.UPGRADING=2]="UPGRADING",e[e.UPGRADE_FINISHED=3]="UPGRADE_FINISHED"})(K||(K={}));var Q;(function(e){e.PLA="PLA",e.ABS="ABS",e.TPU="TPU",e.PC="PC",e.ASA="ASA",e.PA_CF="PA-CF",e.PA6_CF="PA6-CF",e.PET_CF="PET-CF",e.PETG="PETG",e.PETG_CF="PETG-CF",e.PLA_AERO="PLA-AERO",e.PLA_CF="PLA-CF",e.PPA_CF="PPA-CF",e.PPA_GF="PPA-GF",e.PA="PA",e.HIPS="HIPS",e.PPS="PPS",e.PPS_CF="PPS-CF",e.PVA="PVA",e.PLA_S="PLA-S",e.PA_S="PLA-S"})(Q||(Q={}));function Je(e){return k[e]??null}r(Je,"getFilamentConfig");function h(e){return e.command==="push_status"&&Object.keys(e).length>=40}r(h,"isPushAllCommand");function ee(e){return e.command==="gcode_line"&&!!e?.param?.startsWith("M106")}r(ee,"isUpdateFanCommand");function te(e){return e.command==="push_status"&&e.hasOwnProperty("lights_report")}r(te,"isUpdateLightCommand");function _e(e){return e.command==="push_status"&&(e.hasOwnProperty("spd_lvl")||e.hasOwnProperty("spd_mag"))}r(_e,"isUpdateSpeedCommand");function re(e){return e.command===e.command}r(re,"isUpdateStateCommand");function ae(e){return e.command==="gcode_line"&&!!(e?.param?.startsWith("M104")||e?.param?.startsWith("M140"))}r(ae,"isUpdateTempCommand");function g(e){return!!e?.mc_print&&!!e?.mc_print?.command&&["push_info"].includes(e.mc_print.command)}r(g,"isMCPrintMessage");function ht(e){return e.command==="push_info"}r(ht,"isPushInfoCommand");function gt(e){let[,_,t,l]=e.param.match(/^\[(.+?)](?:\[(.+?)])?\s*(.+)$/)??[];return{sequenceId:Number(e.sequence_id),category:_,subcategory:t,content:l,rawParam:e.param}}r(gt,"getCleanPushInfoCommand");function x(e){return e.command==="get_version"}r(x,"isGetVersionCommand");function z(e){return!!e?.info&&!!e?.info?.command&&["get_version"].includes(e.info.command)}r(z,"isInfoMessage");var E=class E extends f{constructor({fileName:t}){super({param:t});n(this,"category","print");n(this,"command","gcode_file");n(this,"ownsResponse",q)}};r(E,"GCodeFileCommand");var ie=E;var S=class S extends d{constructor({gcodes:t}){super(t);n(this,"command","gcode_line");n(this,"ownsResponse",j)}};r(S,"GCodeLineCommand");var ne=S;var G=class G extends f{constructor(){super();n(this,"category","info");n(this,"command","get_version");n(this,"ownsResponse",x)}};r(G,"GetVersionCommand");var b=G;var M=class M extends f{constructor(){super();n(this,"category","pushing");n(this,"command","pushall");n(this,"ownsResponse",h)}};r(M,"PushAllCommand");var c=M;var le;(function(e){e[e.PART_COOLING_FAN=1]="PART_COOLING_FAN",e[e.AUXILIARY_FAN=2]="AUXILIARY_FAN",e[e.CHAMBER_FAN=3]="CHAMBER_FAN"})(le||(le={}));var L=class L extends d{constructor({fan:t,speed:l}){super([`M106 P${t.toString()} S${255*l/100}`]);n(this,"command","gcode_line");n(this,"ownsResponse",ee)}};r(L,"UpdateFanCommand");var me=L;var F=class F extends f{constructor({light:t,mode:l,loopOptions:a={led_on_time:0,led_off_time:0,loop_times:0,interval_time:0}}){super({led_node:t,led_mode:l,...a});n(this,"category","system");n(this,"command","ledctrl");n(this,"ownsResponse",te)}};r(F,"UpdateLightCommand");var oe=F;var N=class N extends f{constructor({speed:t}){super({param:t.toString()});n(this,"category","print");n(this,"command","print_speed");n(this,"ownsResponse",_e)}};r(N,"UpdateSpeedCommand");var pe=N;var C=class C extends f{constructor({state:t}){super();n(this,"category","print");n(this,"command");n(this,"ownsResponse",re);this.command=t}};r(C,"UpdateStateCommand");var se=C;var fe;(function(e){e.BED="M140",e.EXTRUDER="M104"})(fe||(fe={}));var T=class T extends d{constructor({part:t,temperature:l}){super([`${t} S${l}`]);n(this,"command","gcode_line");n(this,"ownsResponse",ae)}};r(T,"UpdateTempCommand");var ue=T;var p;(function(e){e.X1C="X1C",e.X1="X1",e.X1E="X1E",e.P1P="P1P",e.P1S="P1S",e.P2S="P2S",e.A1="A1",e.A1M="A1M"})(p||(p={}));import{createId as xe}from"@paralleldrive/cuid2";var ze=new RegExp(/\.[^/.]+$/),R=class R{constructor(_,t,l,a=new Date){n(this,"_jobData");let o=[p.P1P,p.P1S].includes(l);this._jobData={id:xe(),printerId:t,printerModel:l,name:_.subtask_name.replace(ze,""),fileName:_.subtask_name,gcodeName:_.gcode_file,jobOrigin:_.print_type,totalLayerNumber:_.total_layer_num,totalPrintTime:_.mc_remaining_time,status:_.gcode_state,stage:_.stg_cur,percentDone:_.mc_percent,layerNumber:_.layer_num,remainingTime:_.mc_remaining_time,skippedObjects:_.s_obj,statusHistory:[{status:_.gcode_state,changedAt:a}],speedLevelHistory:[{speedLevel:_.spd_lvl,speedMagnitude:_.spd_mag,changedAt:a}],printingStageHistory:[{stage:_.stg_cur,changedAt:a}],temperatureHistory:[{bedTemp:_.bed_temper,bedTargetTemp:_.bed_target_temper,interiorTemp:o?_.frame_temper:_.chamber_temper,nozzleTemp:_.nozzle_temper,nozzleTargetTemp:_.nozzle_target_temper,changedAt:a}],tempLastUpdatedAt:new Date,errorCodes:_.hms.map(m=>({attr:m.attr,code:m.code,thrownAt:a,layerNumber:_.layer_num})),createdAt:a}}update(_){if(!this._jobData)return;let t=this._jobData,l=new Date,a=[p.P1P,p.P1S].includes(this._jobData.printerModel);_.gcode_state&&t.statusHistory.at(-1)?.status!==_.gcode_state&&t.statusHistory.push({status:_.gcode_state,changedAt:l}),_.spd_lvl&&_.spd_mag&&t.speedLevelHistory.at(-1)?.speedLevel!==_.spd_lvl&&t.speedLevelHistory.push({speedLevel:_.spd_lvl,speedMagnitude:_.spd_mag,changedAt:l}),_.stg_cur&&t.printingStageHistory.at(-1)?.stage!==_.stg_cur&&t.printingStageHistory.push({stage:_.stg_cur,changedAt:l});let o=!!(_.bed_temper||_.bed_target_temper||(a?_.frame_temper:_.chamber_temper)||_.nozzle_temper||_.nozzle_target_temper),m=t.tempLastUpdatedAt.getTime()+5e3<l.getTime();if(o&&m){let s=a?_.frame_temper:_.chamber_temper,u=t.temperatureHistory.at(-1);t.temperatureHistory.push({bedTemp:_.bed_temper??u.bedTemp,bedTargetTemp:_.bed_target_temper??u.bedTargetTemp,interiorTemp:s??u.interiorTemp,nozzleTemp:_.nozzle_temper??u.nozzleTemp,nozzleTargetTemp:_.nozzle_target_temper??u.nozzleTargetTemp,changedAt:l}),t.tempLastUpdatedAt=l}let i={status:_.gcode_state??t.status,stage:_.stg_cur??t.stage,percentDone:_.mc_percent??t.percentDone,layerNumber:_.layer_num??t.layerNumber,remainingTime:_.mc_remaining_time??t.remainingTime,skippedObjects:_.s_obj??t.skippedObjects,errorCodes:_.hms?.map((s,u)=>({attr:s.attr??t.errorCodes[u].attr,code:s.code??t.errorCodes[u].code,thrownAt:l??t.errorCodes[u].thrownAt,layerNumber:_.layer_num??t.errorCodes[u].layerNumber}))??t.errorCodes};this._jobData={...this._jobData,...i}}get data(){return this._jobData}};r(R,"Job");var w=R;import*as ce from"mqtt";import*as ye from"eventemitter3";import{createId as be}from"@paralleldrive/cuid2";function I(e){return new Promise(_=>setTimeout(_,e))}r(I,"sleep");function O(e,_){let t={},l=r((a,o,m)=>{for(let i in o){let s=o[i],u=a[i];if(!(i in a&&JSON.stringify(a[i])===JSON.stringify(o[i]))){if(typeof s=="object"&&s!==null&&u!==null&&!Array.isArray(s)){m[i]=m[i]||{},l(a[i],o[i],m[i]);continue}m[i]=o[i]}}},"checkDifferences");return l(e,_,t),t}r(O,"subtractObject");var D=class D extends ye.EventEmitter{constructor(t){super();n(this,"clientOptions");n(this,"id");n(this,"mqttClient");n(this,"config");n(this,"_printerData");n(this,"_printerStatus");n(this,"jobHistory");n(this,"currentJob");this.clientOptions=t,this.id=be(),this.mqttClient=void 0,this._printerData={modules:[],model:void 0},this._printerStatus="OFFLINE",this.jobHistory=[],this.currentJob=null,this.config={host:t.host,port:t.port??8883,accessToken:t.accessToken,serialNumber:t.serialNumber,throwOnOfflineCommands:t.throwOnOfflineCommands??!1,reconnectInterval:t.reconnectInterval??1e3,connectTimeout:t.connectTimeout??2e3,keepAlive:t.keepAlive??20},this.jobHistory=t.jobHistory??[],this.currentJob=t.currentJob??null}emit(t,...l){return super.emit(t,...l)}off(t,l){return super.off(t,l),this}once(t,l){return super.once(t,l),this}on(t,l){return super.on(t,l),this}async connectMQTT(){return new Promise((t,l)=>{if(this.mqttClient)throw new Error("Can't establish a new connection while running another one!");this.mqttClient=ce.connect(`mqtts://${this.config.host}:${this.config.port}`,{username:"bblp",password:this.config.accessToken,reconnectPeriod:this.clientOptions.reconnectInterval,connectTimeout:this.clientOptions.connectTimeout,keepalive:this.clientOptions.keepAlive,resubscribe:!0,rejectUnauthorized:!1}),this.mqttClient.on("connect",async(...a)=>{await this.onConnect(...a),this.emit("client:connect"),t()}),this.mqttClient.on("disconnect",()=>{this.emit("client:disconnect",!1),this.emit("printer:statusUpdate",this._printerStatus,"OFFLINE"),this._printerStatus="OFFLINE",this.currentJob&&this.emit("job:pause",this.currentJob,!0)}),this.mqttClient.on("offline",()=>{this.emit("client:disconnect",!0),this.emit("printer:statusUpdate",this._printerStatus,"OFFLINE"),this._printerStatus="OFFLINE",this.currentJob&&this.emit("job:pause",this.currentJob,!0)}),this.mqttClient.on("message",(a,o)=>this.emit("rawMessage",a,o)),this.mqttClient.on("error",a=>{this.emit("client:error",a),l(a)})})}async connect(){return await Promise.all([this.connectMQTT()])}async disconnect(t=!1,l){return new Promise(a=>this.mqttClient?.end(t,l,a))}subscribe(t){if(this._printerStatus!=="OFFLINE"&&this.config.throwOnOfflineCommands)throw new Error(`Unable to subscribe to topic "${t}" while disconnected from printer!`);return new Promise((l,a)=>{if(!this.mqttClient)return a("Client not connected.");this.mqttClient.subscribe(t,m=>{if(m)return a(`Error subscribing to topic '${t}': ${m.message}`)});let o=r(async(m,i)=>{m===t&&await this.onMessage(i.toString(),t)},"listener");this.mqttClient.on("message",o),l()})}async executeCommand(t){if(this._printerStatus!=="OFFLINE"&&this.config.throwOnOfflineCommands)throw new Error("Unable to send commands while disconnected from printer!");return new Promise((l,a)=>{t.invoke(this).catch(m=>a(m));let o=setTimeout(()=>{a(new Error("Command execution timed out after 5 seconds."))},5e3);this.on("rawMessage",(m,i)=>{let s=JSON.parse(i.toString()),u=Object.keys(s)[0];if(!(z(s)||g(s)||y(s)))return;let P=s[u];P?.command&&t.ownsResponse(P)&&(clearTimeout(o),l(P))})})}async onConnect(t){await this.subscribe(`device/${this.config.serialNumber}/report`),await I(1e3),await this.executeCommand(new b),(this._printerData.model===p.P1P||this._printerData.model===p.P1S||this._printerData.model===p.P2S||this._printerData.model===p.A1||this._printerData.model===p.A1M)&&(await this.executeCommand(new c),setInterval(async()=>{await this.executeCommand(new c)},5*60*1e3))}async onMessage(t,l){let a=JSON.parse(t),o=Object.keys(a)[0];if(z(a)||g(a)||y(a)){if(y(a)&&(this.emit("message",l,o,a.print),(h(a.print)||J(a.print))&&(this._printerData={...this._printerData,...a.print},this.emit("printer:dataUpdate",this._printerData,a.print),a.print.gcode_state&&a.print.gcode_state!==this._printerStatus))){let m=this._printerStatus,i=a.print.gcode_state;if(this.emit("printer:statusUpdate",m,i),(i==="PREPARE"||i==="SLICING")&&(i="IDLE"),(m==="PREPARE"||m==="SLICING")&&(m="RUNNING"),(m==="IDLE"||m==="FINISH"||m==="FAILED")&&i==="RUNNING")this.currentJob!==null&&this.jobHistory.push(this.currentJob),this.currentJob=new w(this._printerData,this.id,this._printerData.model),this.emit("job:start",this.currentJob);else if(m==="RUNNING"&&(i==="FINISH"||i==="FAILED"||i==="IDLE"))i==="FINISH"?this.currentJob!==null&&this.emit("job:finish",this.currentJob,"SUCCESS"):i==="FAILED"?this.currentJob!==null&&this.emit("job:finish",this.currentJob,"FAILED"):i==="IDLE"&&this.currentJob!==null&&this.emit("job:finish",this.currentJob,"UNEXPECTED"),this.currentJob!==null&&this.jobHistory.push(this.currentJob),this.currentJob=null;else if(m==="RUNNING"&&i==="PAUSE")this.currentJob&&this.emit("job:pause",this.currentJob,!1);else if(m==="PAUSE"&&i==="RUNNING")this.currentJob&&this.emit("job:unpause",this.currentJob);else if(m==="OFFLINE"&&i==="PAUSE")this.emit("job:offlineRecovery",this.currentJob);else if(!(m==="OFFLINE"&&i==="RUNNING")){if(!((m==="IDLE"||m==="OFFLINE")&&(i==="FINISH"||i==="FAILED"||i==="IDLE"))){if(!((m==="FINISH"||i==="FAILED")&&i==="IDLE")){if(m!==i)throw new Error("Edge case detected while updating printer status!")}}}if(this._printerStatus=a.print.gcode_state,this.currentJob){let s=this.currentJob?.data;this.currentJob.update(a.print),this.emit("job:update",this.currentJob,O(s,this.currentJob.data))}}if(g(a)&&this.emit("message",l,o,a.print),z(a)&&(this.emit("message",l,o,a.info),x(a.info))){let m=[...new Set([...this._printerData.modules,...a.info.module])];this._printerData.modules=m,this.emit("printer:dataUpdate",this._printerData,{modules:m});let i=this._printerData.modules.find(s=>s.name==="ota");if(!i)throw new Error("OTA module version data not found, unable to determine printer model!");if(i.sn.startsWith("00M"))this._printerData.model=p.X1C;else if(i.sn.startsWith("00W"))this._printerData.model=p.X1;else if(i.sn.startsWith("03W"))this._printerData.model=p.X1E;else if(i.sn.startsWith("01S"))this._printerData.model=p.P1P;else if(i.sn.startsWith("01P"))this._printerData.model=p.P1S;else if(i.sn.startsWith("22E"))this._printerData.model=p.P2S;else if(i.sn.startsWith("030"))this._printerData.model=p.A1;else if(i.sn.startsWith("039"))this._printerData.model=p.A1M;else throw new Error("Printer model not supported!");this.emit("printer:dataUpdate",this._printerData,{model:this._printerData.model})}}}publish(t){return new Promise((l,a)=>{if(!this.mqttClient)return a("Client not connected.");let o=typeof t=="string"?t:JSON.stringify(t),m=`device/${this.config.serialNumber}/request`;this.mqttClient.publish(m,o,i=>{if(i)return a(`Error publishing to topic '${m}': ${i.message}`);l()})})}get data(){return this._printerData}get status(){return this._printerStatus}};r(D,"BambuClient");var de=D;export{f as AbstractCommand,V as AmsRFIDStatus,de as BambuClient,le as Fan,Q as FilamentType,d as GCodeCommand,ie as GCodeFileCommand,ne as GCodeLineCommand,b as GetVersionCommand,w as Job,W as PrintStage,p as PrinterModel,c as PushAllCommand,X as SpeedLevel,me as UpdateFanCommand,oe as UpdateLightCommand,pe as UpdateSpeedCommand,se as UpdateStateCommand,ue as UpdateTempCommand,K as UpgradeDisplayState,Y as UpgradeErrorCode,Z as UpgradeStatusFinishState,$ as UpgradeStatusProgressState,gt as getCleanPushInfoCommand,Je as getFilamentConfig,j as isGCodeLineCommand,q as isGcodeFileCommand,x as isGetVersionCommand,z as isInfoMessage,g as isMCPrintMessage,y as isPrintMessage,Oe as isProjectFileCommand,h as isPushAllCommand,ht as isPushInfoCommand,J as isPushStatusCommand,ee as isUpdateFanCommand,te as isUpdateLightCommand,_e as isUpdateSpeedCommand,re as isUpdateStateCommand,ae as isUpdateTempCommand};
|
|
32
|
+
+{endif}`],filament_id:"GFL01",filament_flow_ratio:["0.98"],filament_vendor:["Polymaker"]}};var W;(function(e){e[e.PRINTING=0]="PRINTING",e[e.BED_LEVELING=1]="BED_LEVELING",e[e.HEATBED_PREHEATING=2]="HEATBED_PREHEATING",e[e.XY_MECH_MODE_SWEEP=3]="XY_MECH_MODE_SWEEP",e[e.CHANGE_MATERIAL=4]="CHANGE_MATERIAL",e[e.M400_PAUSE=5]="M400_PAUSE",e[e.FILAMENT_RUNOUT_PAUSE=6]="FILAMENT_RUNOUT_PAUSE",e[e.HOTEND_HEATING=7]="HOTEND_HEATING",e[e.EXTRUDE_COMPENSATION_SCAN=8]="EXTRUDE_COMPENSATION_SCAN",e[e.BED_SCAN=9]="BED_SCAN",e[e.FIRST_LAYER_SCAN=10]="FIRST_LAYER_SCAN",e[e.BE_SURFACE_TYPT_IDENTIFICATION=11]="BE_SURFACE_TYPT_IDENTIFICATION",e[e.SCANNER_EXTRINSIC_PARA_CALI=12]="SCANNER_EXTRINSIC_PARA_CALI",e[e.TOOLHEAD_HOMING=13]="TOOLHEAD_HOMING",e[e.NOZZLE_TIP_CLEANING=14]="NOZZLE_TIP_CLEANING",e[e.EXTRUDER_TEMP_PROTECT_CALI=15]="EXTRUDER_TEMP_PROTECT_CALI",e[e.USER_PAUSE=16]="USER_PAUSE",e[e.TOOLHEAD_SHELL_OFF_PAUSE=17]="TOOLHEAD_SHELL_OFF_PAUSE",e[e.SCANNER_LASER_PARA_CALI=18]="SCANNER_LASER_PARA_CALI",e[e.EXTRUDER_ABSOLUTE_FLOW_CALI=19]="EXTRUDER_ABSOLUTE_FLOW_CALI",e[e.HOTEND_TEMPERATURE_ERROR_PAUSE=20]="HOTEND_TEMPERATURE_ERROR_PAUSE",e[e.HEATED_BED_TEMPERATURE_ERROR_PAUSE=21]="HEATED_BED_TEMPERATURE_ERROR_PAUSE",e[e.FILAMENT_UNLOADING=22]="FILAMENT_UNLOADING",e[e.SKIP_STEP_PAUSE=23]="SKIP_STEP_PAUSE",e[e.FILAMENT_LOADING=24]="FILAMENT_LOADING",e[e.MOTOR_NOISE_CALIBRATION=25]="MOTOR_NOISE_CALIBRATION",e[e.AMS_LOST_PAUSE=26]="AMS_LOST_PAUSE",e[e.HEAT_BREAK_FAN_PAUSE=27]="HEAT_BREAK_FAN_PAUSE",e[e.CHAMBER_TEMPERATURE_CONTROL_ERROR_PAUSE=28]="CHAMBER_TEMPERATURE_CONTROL_ERROR_PAUSE",e[e.CHAMBER_COOLING=29]="CHAMBER_COOLING",e[e.USER_INSERT_GCODE_PAUSE=30]="USER_INSERT_GCODE_PAUSE",e[e.MOTOR_NOISE_SHOWOFF=31]="MOTOR_NOISE_SHOWOFF",e[e.NOZZLE_FILAMENT_COVERED_DETECTED_PAUSE=32]="NOZZLE_FILAMENT_COVERED_DETECTED_PAUSE",e[e.CUTTER_ERROR_PAUSE=33]="CUTTER_ERROR_PAUSE",e[e.FIRST_LAYER_ERROR_PAUSE=34]="FIRST_LAYER_ERROR_PAUSE",e[e.NOZZLE_CLOG_PAUSE=35]="NOZZLE_CLOG_PAUSE"})(W||(W={}));var X;(function(e){e.SILENT="1",e.NORMAL="2",e.SPORT="3",e.LUDICROUS="4"})(X||(X={}));var V;(function(e){e[e.IDLE=0]="IDLE",e[e.READING=1]="READING",e[e.GCODE_TRANS=2]="GCODE_TRANS",e[e.GCODE_RUNNING=3]="GCODE_RUNNING",e[e.ASSISTANT=4]="ASSISTANT",e[e.SWITCH_FILAMENT=5]="SWITCH_FILAMENT",e[e.HAS_FILAMENT=6]="HAS_FILAMENT"})(V||(V={}));var $;(function(e){e.DOWNLOADING="DOWNLOADING",e.UPGRADE_REQUEST="UPGRADE_REQUEST",e.PRE_FLASH_START="PRE_FLASH_START",e.PRE_FLASH_SUCCESS="PRE_FLASH_SUCCESS"})($||($={}));var Z;(function(e){e.UPGRADE_SUCCESS="UPGRADE_SUCCESS",e.DOWNLOAD_FAIL="DOWNLOAD_FAIL",e.FLASH_FAIL="FLASH_FAIL",e.PRE_FLASH_FAIL="PRE_FLASH_FAIL",e.UPGRADE_FAIL="UPGRADE_FAIL"})(Z||(Z={}));var Y;(function(e){e[e.UpgradeNoError=0]="UpgradeNoError",e[e.UpgradeDownloadFailed=1]="UpgradeDownloadFailed",e[e.UpgradeVerifyFailed=2]="UpgradeVerifyFailed",e[e.UpgradeFlashFailed=3]="UpgradeFlashFailed",e[e.UpgradePrinting=4]="UpgradePrinting"})(Y||(Y={}));var K;(function(e){e[e.UNAVAILABLE=0]="UNAVAILABLE",e[e.IDLE=1]="IDLE",e[e.UPGRADING=2]="UPGRADING",e[e.UPGRADE_FINISHED=3]="UPGRADE_FINISHED"})(K||(K={}));var Q;(function(e){e.PLA="PLA",e.ABS="ABS",e.TPU="TPU",e.PC="PC",e.ASA="ASA",e.PA_CF="PA-CF",e.PA6_CF="PA6-CF",e.PET_CF="PET-CF",e.PETG="PETG",e.PETG_CF="PETG-CF",e.PLA_AERO="PLA-AERO",e.PLA_CF="PLA-CF",e.PPA_CF="PPA-CF",e.PPA_GF="PPA-GF",e.PA="PA",e.HIPS="HIPS",e.PPS="PPS",e.PPS_CF="PPS-CF",e.PVA="PVA",e.PLA_S="PLA-S",e.PA_S="PLA-S"})(Q||(Q={}));function Je(e){return k[e]??null}r(Je,"getFilamentConfig");function h(e){return e.command==="push_status"&&Object.keys(e).length>=40}r(h,"isPushAllCommand");function ee(e){return e.command==="gcode_line"&&!!e?.param?.startsWith("M106")}r(ee,"isUpdateFanCommand");function te(e){return e.command==="push_status"&&e.hasOwnProperty("lights_report")}r(te,"isUpdateLightCommand");function _e(e){return e.command==="push_status"&&(e.hasOwnProperty("spd_lvl")||e.hasOwnProperty("spd_mag"))}r(_e,"isUpdateSpeedCommand");function re(e){return e.command===e.command}r(re,"isUpdateStateCommand");function ae(e){return e.command==="gcode_line"&&!!(e?.param?.startsWith("M104")||e?.param?.startsWith("M140"))}r(ae,"isUpdateTempCommand");function g(e){return!!e?.mc_print&&!!e?.mc_print?.command&&["push_info"].includes(e.mc_print.command)}r(g,"isMCPrintMessage");function ht(e){return e.command==="push_info"}r(ht,"isPushInfoCommand");function gt(e){let[,_,t,l]=e.param.match(/^\[(.+?)](?:\[(.+?)])?\s*(.+)$/)??[];return{sequenceId:Number(e.sequence_id),category:_,subcategory:t,content:l,rawParam:e.param}}r(gt,"getCleanPushInfoCommand");function x(e){return e.command==="get_version"}r(x,"isGetVersionCommand");function z(e){return!!e?.info&&!!e?.info?.command&&["get_version"].includes(e.info.command)}r(z,"isInfoMessage");var E=class E extends f{constructor({fileName:t}){super({param:t});n(this,"category","print");n(this,"command","gcode_file");n(this,"ownsResponse",q)}};r(E,"GCodeFileCommand");var ie=E;var S=class S extends d{constructor({gcodes:t}){super(t);n(this,"command","gcode_line");n(this,"ownsResponse",j)}};r(S,"GCodeLineCommand");var ne=S;var G=class G extends f{constructor(){super();n(this,"category","info");n(this,"command","get_version");n(this,"ownsResponse",x)}};r(G,"GetVersionCommand");var b=G;var M=class M extends f{constructor(){super();n(this,"category","pushing");n(this,"command","pushall");n(this,"ownsResponse",h)}};r(M,"PushAllCommand");var c=M;var le;(function(e){e[e.PART_COOLING_FAN=1]="PART_COOLING_FAN",e[e.AUXILIARY_FAN=2]="AUXILIARY_FAN",e[e.CHAMBER_FAN=3]="CHAMBER_FAN"})(le||(le={}));var L=class L extends d{constructor({fan:t,speed:l}){super([`M106 P${t.toString()} S${255*l/100}`]);n(this,"command","gcode_line");n(this,"ownsResponse",ee)}};r(L,"UpdateFanCommand");var me=L;var F=class F extends f{constructor({light:t,mode:l,loopOptions:a={led_on_time:0,led_off_time:0,loop_times:0,interval_time:0}}){super({led_node:t,led_mode:l,...a});n(this,"category","system");n(this,"command","ledctrl");n(this,"ownsResponse",te)}};r(F,"UpdateLightCommand");var oe=F;var N=class N extends f{constructor({speed:t}){super({param:t.toString()});n(this,"category","print");n(this,"command","print_speed");n(this,"ownsResponse",_e)}};r(N,"UpdateSpeedCommand");var pe=N;var C=class C extends f{constructor({state:t}){super();n(this,"category","print");n(this,"command");n(this,"ownsResponse",re);this.command=t}};r(C,"UpdateStateCommand");var se=C;var fe;(function(e){e.BED="M140",e.EXTRUDER="M104"})(fe||(fe={}));var T=class T extends d{constructor({part:t,temperature:l}){super([`${t} S${l}`]);n(this,"command","gcode_line");n(this,"ownsResponse",ae)}};r(T,"UpdateTempCommand");var ue=T;var p;(function(e){e.X1C="X1C",e.X1="X1",e.X1E="X1E",e.P1P="P1P",e.P1S="P1S",e.P2S="P2S",e.H2S="H2S",e.H2D="H2D",e.H2C="H2C",e.H2DPRO="H2DPRO",e.A1="A1",e.A1M="A1M"})(p||(p={}));import{createId as xe}from"@paralleldrive/cuid2";var ze=new RegExp(/\.[^/.]+$/),R=class R{constructor(_,t,l,a=new Date){n(this,"_jobData");let o=[p.P1P,p.P1S].includes(l);this._jobData={id:xe(),printerId:t,printerModel:l,name:_.subtask_name.replace(ze,""),fileName:_.subtask_name,gcodeName:_.gcode_file,jobOrigin:_.print_type,totalLayerNumber:_.total_layer_num,totalPrintTime:_.mc_remaining_time,status:_.gcode_state,stage:_.stg_cur,percentDone:_.mc_percent,layerNumber:_.layer_num,remainingTime:_.mc_remaining_time,skippedObjects:_.s_obj,statusHistory:[{status:_.gcode_state,changedAt:a}],speedLevelHistory:[{speedLevel:_.spd_lvl,speedMagnitude:_.spd_mag,changedAt:a}],printingStageHistory:[{stage:_.stg_cur,changedAt:a}],temperatureHistory:[{bedTemp:_.bed_temper,bedTargetTemp:_.bed_target_temper,interiorTemp:o?_.frame_temper:_.chamber_temper,nozzleTemp:_.nozzle_temper,nozzleTargetTemp:_.nozzle_target_temper,changedAt:a}],tempLastUpdatedAt:new Date,errorCodes:_.hms.map(m=>({attr:m.attr,code:m.code,thrownAt:a,layerNumber:_.layer_num})),createdAt:a}}update(_){if(!this._jobData)return;let t=this._jobData,l=new Date,a=[p.P1P,p.P1S].includes(this._jobData.printerModel);_.gcode_state&&t.statusHistory.at(-1)?.status!==_.gcode_state&&t.statusHistory.push({status:_.gcode_state,changedAt:l}),_.spd_lvl&&_.spd_mag&&t.speedLevelHistory.at(-1)?.speedLevel!==_.spd_lvl&&t.speedLevelHistory.push({speedLevel:_.spd_lvl,speedMagnitude:_.spd_mag,changedAt:l}),_.stg_cur&&t.printingStageHistory.at(-1)?.stage!==_.stg_cur&&t.printingStageHistory.push({stage:_.stg_cur,changedAt:l});let o=!!(_.bed_temper||_.bed_target_temper||(a?_.frame_temper:_.chamber_temper)||_.nozzle_temper||_.nozzle_target_temper),m=t.tempLastUpdatedAt.getTime()+5e3<l.getTime();if(o&&m){let s=a?_.frame_temper:_.chamber_temper,u=t.temperatureHistory.at(-1);t.temperatureHistory.push({bedTemp:_.bed_temper??u.bedTemp,bedTargetTemp:_.bed_target_temper??u.bedTargetTemp,interiorTemp:s??u.interiorTemp,nozzleTemp:_.nozzle_temper??u.nozzleTemp,nozzleTargetTemp:_.nozzle_target_temper??u.nozzleTargetTemp,changedAt:l}),t.tempLastUpdatedAt=l}let i={status:_.gcode_state??t.status,stage:_.stg_cur??t.stage,percentDone:_.mc_percent??t.percentDone,layerNumber:_.layer_num??t.layerNumber,remainingTime:_.mc_remaining_time??t.remainingTime,skippedObjects:_.s_obj??t.skippedObjects,errorCodes:_.hms?.map((s,u)=>({attr:s.attr??t.errorCodes[u].attr,code:s.code??t.errorCodes[u].code,thrownAt:l??t.errorCodes[u].thrownAt,layerNumber:_.layer_num??t.errorCodes[u].layerNumber}))??t.errorCodes};this._jobData={...this._jobData,...i}}get data(){return this._jobData}};r(R,"Job");var w=R;import*as ce from"mqtt";import*as ye from"eventemitter3";import{createId as be}from"@paralleldrive/cuid2";function I(e){return new Promise(_=>setTimeout(_,e))}r(I,"sleep");function O(e,_){let t={},l=r((a,o,m)=>{for(let i in o){let s=o[i],u=a[i];if(!(i in a&&JSON.stringify(a[i])===JSON.stringify(o[i]))){if(typeof s=="object"&&s!==null&&u!==null&&!Array.isArray(s)){m[i]=m[i]||{},l(a[i],o[i],m[i]);continue}m[i]=o[i]}}},"checkDifferences");return l(e,_,t),t}r(O,"subtractObject");var D=class D extends ye.EventEmitter{constructor(t){super();n(this,"clientOptions");n(this,"id");n(this,"mqttClient");n(this,"config");n(this,"_printerData");n(this,"_printerStatus");n(this,"jobHistory");n(this,"currentJob");this.clientOptions=t,this.id=be(),this.mqttClient=void 0,this._printerData={modules:[],model:void 0},this._printerStatus="OFFLINE",this.jobHistory=[],this.currentJob=null,this.config={host:t.host,port:t.port??8883,accessToken:t.accessToken,serialNumber:t.serialNumber,throwOnOfflineCommands:t.throwOnOfflineCommands??!1,reconnectInterval:t.reconnectInterval??1e3,connectTimeout:t.connectTimeout??2e3,keepAlive:t.keepAlive??20},this.jobHistory=t.jobHistory??[],this.currentJob=t.currentJob??null}emit(t,...l){return super.emit(t,...l)}off(t,l){return super.off(t,l),this}once(t,l){return super.once(t,l),this}on(t,l){return super.on(t,l),this}async connectMQTT(){return new Promise((t,l)=>{if(this.mqttClient)throw new Error("Can't establish a new connection while running another one!");this.mqttClient=ce.connect(`mqtts://${this.config.host}:${this.config.port}`,{username:"bblp",password:this.config.accessToken,reconnectPeriod:this.clientOptions.reconnectInterval,connectTimeout:this.clientOptions.connectTimeout,keepalive:this.clientOptions.keepAlive,resubscribe:!0,rejectUnauthorized:!1}),this.mqttClient.on("connect",async(...a)=>{await this.onConnect(...a),this.emit("client:connect"),t()}),this.mqttClient.on("disconnect",()=>{this.emit("client:disconnect",!1),this.emit("printer:statusUpdate",this._printerStatus,"OFFLINE"),this._printerStatus="OFFLINE",this.currentJob&&this.emit("job:pause",this.currentJob,!0)}),this.mqttClient.on("offline",()=>{this.emit("client:disconnect",!0),this.emit("printer:statusUpdate",this._printerStatus,"OFFLINE"),this._printerStatus="OFFLINE",this.currentJob&&this.emit("job:pause",this.currentJob,!0)}),this.mqttClient.on("message",(a,o)=>this.emit("rawMessage",a,o)),this.mqttClient.on("error",a=>{this.emit("client:error",a),l(a)})})}async connect(){return await Promise.all([this.connectMQTT()])}async disconnect(t=!1,l){return new Promise(a=>this.mqttClient?.end(t,l,a))}subscribe(t){if(this._printerStatus!=="OFFLINE"&&this.config.throwOnOfflineCommands)throw new Error(`Unable to subscribe to topic "${t}" while disconnected from printer!`);return new Promise((l,a)=>{if(!this.mqttClient)return a("Client not connected.");this.mqttClient.subscribe(t,m=>{if(m)return a(`Error subscribing to topic '${t}': ${m.message}`)});let o=r(async(m,i)=>{m===t&&await this.onMessage(i.toString(),t)},"listener");this.mqttClient.on("message",o),l()})}async executeCommand(t){if(this._printerStatus!=="OFFLINE"&&this.config.throwOnOfflineCommands)throw new Error("Unable to send commands while disconnected from printer!");return new Promise((l,a)=>{t.invoke(this).catch(m=>a(m));let o=setTimeout(()=>{a(new Error("Command execution timed out after 5 seconds."))},5e3);this.on("rawMessage",(m,i)=>{let s=JSON.parse(i.toString()),u=Object.keys(s)[0];if(!(z(s)||g(s)||y(s)))return;let P=s[u];P?.command&&t.ownsResponse(P)&&(clearTimeout(o),l(P))})})}async onConnect(t){await this.subscribe(`device/${this.config.serialNumber}/report`),await I(1e3),await this.executeCommand(new b),(this._printerData.model===p.P1P||this._printerData.model===p.P1S||this._printerData.model===p.P2S||this._printerData.model===p.A1||this._printerData.model===p.A1M)&&(await this.executeCommand(new c),setInterval(async()=>{await this.executeCommand(new c)},5*60*1e3))}async onMessage(t,l){let a=JSON.parse(t),o=Object.keys(a)[0];if(z(a)||g(a)||y(a)){if(y(a)&&(this.emit("message",l,o,a.print),(h(a.print)||J(a.print))&&(this._printerData={...this._printerData,...a.print},this.emit("printer:dataUpdate",this._printerData,a.print),a.print.gcode_state&&a.print.gcode_state!==this._printerStatus))){let m=this._printerStatus,i=a.print.gcode_state;if(this.emit("printer:statusUpdate",m,i),(i==="PREPARE"||i==="SLICING")&&(i="IDLE"),(m==="PREPARE"||m==="SLICING")&&(m="RUNNING"),(m==="IDLE"||m==="FINISH"||m==="FAILED")&&i==="RUNNING")this.currentJob!==null&&this.jobHistory.push(this.currentJob),this.currentJob=new w(this._printerData,this.id,this._printerData.model),this.emit("job:start",this.currentJob);else if(m==="RUNNING"&&(i==="FINISH"||i==="FAILED"||i==="IDLE"))i==="FINISH"?this.currentJob!==null&&this.emit("job:finish",this.currentJob,"SUCCESS"):i==="FAILED"?this.currentJob!==null&&this.emit("job:finish",this.currentJob,"FAILED"):i==="IDLE"&&this.currentJob!==null&&this.emit("job:finish",this.currentJob,"UNEXPECTED"),this.currentJob!==null&&this.jobHistory.push(this.currentJob),this.currentJob=null;else if(m==="RUNNING"&&i==="PAUSE")this.currentJob&&this.emit("job:pause",this.currentJob,!1);else if(m==="PAUSE"&&i==="RUNNING")this.currentJob&&this.emit("job:unpause",this.currentJob);else if(m==="OFFLINE"&&i==="PAUSE")this.emit("job:offlineRecovery",this.currentJob);else if(!(m==="OFFLINE"&&i==="RUNNING")){if(!((m==="IDLE"||m==="OFFLINE")&&(i==="FINISH"||i==="FAILED"||i==="IDLE"))){if(!((m==="FINISH"||i==="FAILED")&&i==="IDLE")){if(m!==i)void 0}}}if(this._printerStatus=a.print.gcode_state,this.currentJob){let s=this.currentJob?.data;this.currentJob.update(a.print),this.emit("job:update",this.currentJob,O(s,this.currentJob.data))}}if(g(a)&&this.emit("message",l,o,a.print),z(a)&&(this.emit("message",l,o,a.info),x(a.info))){let m=[...new Set([...this._printerData.modules,...a.info.module])];this._printerData.modules=m,this.emit("printer:dataUpdate",this._printerData,{modules:m});let i=this._printerData.modules.find(s=>s.name==="ota");if(!i)return;if(i.sn.startsWith("00M"))this._printerData.model=p.X1C;else if(i.sn.startsWith("00W"))this._printerData.model=p.X1;else if(i.sn.startsWith("03W"))this._printerData.model=p.X1E;else if(i.sn.startsWith("01S"))this._printerData.model=p.P1P;else if(i.sn.startsWith("01P"))this._printerData.model=p.P1S;else if(i.sn.startsWith("22E"))this._printerData.model=p.P2S;else if(i.sn.startsWith("030"))this._printerData.model=p.A1;else if(i.sn.startsWith("039"))this._printerData.model=p.A1M;else if(i.sn.startsWith("093"))this._printerData.model=p.H2S;else if(i.sn.startsWith("094"))this._printerData.model=p.H2D;else if(i.sn.startsWith("239"))this._printerData.model=p.H2C;else if(i.sn.startsWith("31B"))this._printerData.model=p.H2DPRO;this.emit("printer:dataUpdate",this._printerData,{model:this._printerData.model})}}}publish(t){return new Promise((l,a)=>{if(!this.mqttClient)return a("Client not connected.");let o=typeof t=="string"?t:JSON.stringify(t),m=`device/${this.config.serialNumber}/request`;this.mqttClient.publish(m,o,i=>{if(i)return a(`Error publishing to topic '${m}': ${i.message}`);l()})})}get data(){return this._printerData}get status(){return this._printerStatus}};r(D,"BambuClient");var de=D;export{f as AbstractCommand,V as AmsRFIDStatus,de as BambuClient,le as Fan,Q as FilamentType,d as GCodeCommand,ie as GCodeFileCommand,ne as GCodeLineCommand,b as GetVersionCommand,w as Job,W as PrintStage,p as PrinterModel,c as PushAllCommand,X as SpeedLevel,me as UpdateFanCommand,oe as UpdateLightCommand,pe as UpdateSpeedCommand,se as UpdateStateCommand,ue as UpdateTempCommand,K as UpgradeDisplayState,Y as UpgradeErrorCode,Z as UpgradeStatusFinishState,$ as UpgradeStatusProgressState,gt as getCleanPushInfoCommand,Je as getFilamentConfig,j as isGCodeLineCommand,q as isGcodeFileCommand,x as isGetVersionCommand,z as isInfoMessage,g as isMCPrintMessage,y as isPrintMessage,Oe as isProjectFileCommand,h as isPushAllCommand,ht as isPushInfoCommand,J as isPushStatusCommand,ee as isUpdateFanCommand,te as isUpdateLightCommand,_e as isUpdateSpeedCommand,re as isUpdateStateCommand,ae as isUpdateTempCommand};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
+
const version = "3.22.21";
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
// npm can hoist this dependency beside our installed package. Resolve from
|
|
13
|
+
// this script, never from the caller's cwd or a guessed node_modules path.
|
|
14
|
+
const dependencyRoot = fs.realpathSync(path.dirname(require.resolve("bambu-node/package.json")));
|
|
15
|
+
const dependency = JSON.parse(fs.readFileSync(path.join(dependencyRoot, "package.json"), "utf8"));
|
|
16
|
+
if (dependency.name !== "bambu-node" || dependency.version !== version) {
|
|
17
|
+
throw new Error(`Expected bambu-node@${version}; found ${dependency.name}@${dependency.version}.`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { parsePatchFile } = require("patch-package/dist/patch/parse.js");
|
|
21
|
+
const { executeEffects } = require("patch-package/dist/patch/apply.js");
|
|
22
|
+
const { reversePatch } = require("patch-package/dist/patch/reverse.js");
|
|
23
|
+
const patchFile = path.join(packageRoot, "patches", `bambu-node+${version}.patch`);
|
|
24
|
+
const targets = new Map([
|
|
25
|
+
["node_modules/bambu-node/dist/index.js", "dist/index.js"],
|
|
26
|
+
["node_modules/bambu-node/dist/index.d.ts", "dist/index.d.ts"],
|
|
27
|
+
]);
|
|
28
|
+
const effects = parsePatchFile(fs.readFileSync(patchFile, "utf8")).map((effect) => {
|
|
29
|
+
const relative = targets.get(effect.path);
|
|
30
|
+
if (effect.type !== "patch" || !relative) {
|
|
31
|
+
throw new Error("The bundled patch contains an unexpected operation or target.");
|
|
32
|
+
}
|
|
33
|
+
targets.delete(effect.path);
|
|
34
|
+
const destination = path.join(dependencyRoot, relative);
|
|
35
|
+
if (fs.realpathSync(destination) !== destination || !fs.statSync(destination).isFile()) {
|
|
36
|
+
throw new Error(`Refusing to patch a symlink or non-file target: ${relative}`);
|
|
37
|
+
}
|
|
38
|
+
return { ...effect, path: relative };
|
|
39
|
+
});
|
|
40
|
+
if (targets.size !== 0) throw new Error("The bundled patch is missing required targets.");
|
|
41
|
+
|
|
42
|
+
const options = { cwd: dependencyRoot, bestEffort: false };
|
|
43
|
+
let alreadyApplied = false;
|
|
44
|
+
try {
|
|
45
|
+
executeEffects(reversePatch(effects), { ...options, dryRun: true });
|
|
46
|
+
alreadyApplied = true;
|
|
47
|
+
} catch {
|
|
48
|
+
// A reverse dry run only succeeds if every required change is present.
|
|
49
|
+
}
|
|
50
|
+
if (!alreadyApplied) {
|
|
51
|
+
try {
|
|
52
|
+
// Validate every file before allowing any write. Never accept a partial
|
|
53
|
+
// patch: the status parser and protocol changes are runtime requirements.
|
|
54
|
+
executeEffects(effects, { ...options, dryRun: true });
|
|
55
|
+
executeEffects(effects, { ...options, dryRun: false });
|
|
56
|
+
} catch {
|
|
57
|
+
throw new Error(`Unable to apply the required bambu-node@${version} patch. Reinstall dependencies from the release package.`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
console.log(`bambu-node@${version} compatibility patch ${alreadyApplied ? "already applied" : "applied"}.`);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error(`bambu-printer-mcp postinstall failed: ${error.message}`);
|
|
63
|
+
process.exitCode = 1;
|
|
64
|
+
}
|