@jswork/howler-audio-manager 0.0.0-stage → 1.0.1

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.
@@ -0,0 +1,485 @@
1
+ function _class_call_check(instance, Constructor) {
2
+ if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
3
+ }
4
+ function _defineProperties(target, props) {
5
+ for(var i = 0; i < props.length; i++){
6
+ var descriptor = props[i];
7
+ descriptor.enumerable = descriptor.enumerable || false;
8
+ descriptor.configurable = true;
9
+ if ("value" in descriptor) descriptor.writable = true;
10
+ Object.defineProperty(target, descriptor.key, descriptor);
11
+ }
12
+ }
13
+ function _create_class(Constructor, protoProps, staticProps) {
14
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
15
+ if (staticProps) _defineProperties(Constructor, staticProps);
16
+ return Constructor;
17
+ }
18
+ function _type_of(obj) {
19
+ "@swc/helpers - typeof";
20
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
21
+ }
22
+ /*!
23
+ * name: @jswork/howler-audio-manager
24
+ * description: Howler.js audio manager, enum-driven sounds for H5.
25
+ * homepage: https://js.work
26
+ * version: 1.0.1
27
+ * date: 2026-10-20 18:54:06
28
+ * license: MIT
29
+ */ (function(g, f) {
30
+ if ((typeof exports === "undefined" ? "undefined" : _type_of(exports)) == "object" && (typeof module === "undefined" ? "undefined" : _type_of(module)) < "u") {
31
+ module.exports = f();
32
+ } else if ("function" == typeof define && define.amd) {
33
+ define("urlLiteral", f);
34
+ } else {
35
+ g["urlLiteral"] = f();
36
+ }
37
+ })((typeof globalThis === "undefined" ? "undefined" : _type_of(globalThis)) < "u" ? globalThis : (typeof self === "undefined" ? "undefined" : _type_of(self)) < "u" ? self : this, function() {
38
+ var exports1 = {};
39
+ var __exports = exports1;
40
+ var module1 = {
41
+ exports: exports1
42
+ };
43
+ "use strict";
44
+ var __defProp = Object.defineProperty;
45
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
46
+ var __getOwnPropNames = Object.getOwnPropertyNames;
47
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
48
+ var __export = function __export(target, all) {
49
+ for(var name in all)__defProp(target, name, {
50
+ get: all[name],
51
+ enumerable: true
52
+ });
53
+ };
54
+ var __copyProps = function __copyProps(to, from, except, desc) {
55
+ if (from && (typeof from === "undefined" ? "undefined" : _type_of(from)) === "object" || typeof from === "function") {
56
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
57
+ try {
58
+ var _loop = function() {
59
+ var key = _step.value;
60
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
61
+ get: function get() {
62
+ return from[key];
63
+ },
64
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
65
+ });
66
+ };
67
+ for(var _iterator = __getOwnPropNames(from)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true)_loop();
68
+ } catch (err) {
69
+ _didIteratorError = true;
70
+ _iteratorError = err;
71
+ } finally{
72
+ try {
73
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
74
+ _iterator.return();
75
+ }
76
+ } finally{
77
+ if (_didIteratorError) {
78
+ throw _iteratorError;
79
+ }
80
+ }
81
+ }
82
+ }
83
+ return to;
84
+ };
85
+ var __toCommonJS = function __toCommonJS(mod) {
86
+ return __copyProps(__defProp({}, "__esModule", {
87
+ value: true
88
+ }), mod);
89
+ };
90
+ // src/index.ts
91
+ var index_exports = {};
92
+ __export(index_exports, {
93
+ AudioManager: function AudioManager1() {
94
+ return AudioManager;
95
+ },
96
+ default: function _default() {
97
+ return AudioManager;
98
+ }
99
+ });
100
+ module1.exports = __toCommonJS(index_exports);
101
+ // src/manager.ts
102
+ var import_howler = require("howler");
103
+ var AudioManager = /*#__PURE__*/ function() {
104
+ "use strict";
105
+ function AudioManager(options, inject) {
106
+ _class_call_check(this, AudioManager);
107
+ var _ref, _ref1;
108
+ this.effectCache = /* @__PURE__ */ new Map();
109
+ this.urlAudioCache = /* @__PURE__ */ new Map();
110
+ this.preloadPromises = /* @__PURE__ */ new Map();
111
+ this.activeUrlHowl = null;
112
+ this.globalVolume = 1;
113
+ this.listeners = /* @__PURE__ */ new Map();
114
+ this.HowlConstructor = (_ref = inject === null || inject === void 0 ? void 0 : inject.HowlClass) !== null && _ref !== void 0 ? _ref : import_howler.Howl;
115
+ this.HowlerInstance = (_ref1 = inject === null || inject === void 0 ? void 0 : inject.HowlerObj) !== null && _ref1 !== void 0 ? _ref1 : import_howler.Howler;
116
+ if (typeof (options === null || options === void 0 ? void 0 : options.defaultVolume) === "number") {
117
+ this.setGlobalVolume(options.defaultVolume);
118
+ }
119
+ }
120
+ _create_class(AudioManager, [
121
+ {
122
+ key: "hasEffect",
123
+ value: function hasEffect(key) {
124
+ return this.effectCache.has(key);
125
+ }
126
+ },
127
+ {
128
+ key: "loadEffect",
129
+ value: function loadEffect(key, url) {
130
+ var _this = this;
131
+ if (this.effectCache.has(key)) {
132
+ this.effectCache.get(key).unload();
133
+ }
134
+ var howl = new this.HowlConstructor({
135
+ src: [
136
+ url
137
+ ],
138
+ preload: true
139
+ });
140
+ howl.on("load", function() {
141
+ _this.emit("load", {
142
+ type: "effect",
143
+ key: key,
144
+ url: url
145
+ });
146
+ });
147
+ howl.on("loaderror", function(_id, error) {
148
+ _this.emit("error", {
149
+ type: "effect",
150
+ key: key,
151
+ url: url,
152
+ error: error
153
+ });
154
+ });
155
+ this.effectCache.set(key, howl);
156
+ }
157
+ },
158
+ {
159
+ key: "loadEffects",
160
+ value: function loadEffects(map) {
161
+ var _this = this;
162
+ Object.keys(map).forEach(function(key) {
163
+ var typedKey = isNaN(Number(key)) ? key : Number(key);
164
+ _this.loadEffect(typedKey, map[key]);
165
+ });
166
+ }
167
+ },
168
+ {
169
+ key: "playEffect",
170
+ value: function playEffect(key, options) {
171
+ var _this = this;
172
+ var howl = this.effectCache.get(key);
173
+ if (!howl) {
174
+ console.warn("[AudioManager] Effect not found for key: ".concat(String(key), "."));
175
+ return void 0;
176
+ }
177
+ if (howl.playing()) {
178
+ howl.stop();
179
+ }
180
+ if (typeof (options === null || options === void 0 ? void 0 : options.volume) === "number") {
181
+ howl.volume(options.volume);
182
+ }
183
+ howl.off("play");
184
+ howl.off("end");
185
+ howl.off("stop");
186
+ howl.off("playerror");
187
+ howl.once("play", function(soundId) {
188
+ var _options_onStart;
189
+ options === null || options === void 0 ? void 0 : (_options_onStart = options.onStart) === null || _options_onStart === void 0 ? void 0 : _options_onStart.call(options, soundId);
190
+ _this.emit("play", {
191
+ type: "effect",
192
+ key: key,
193
+ soundId: soundId
194
+ });
195
+ });
196
+ howl.once("end", function(soundId) {
197
+ var _options_onEnd;
198
+ if (typeof (options === null || options === void 0 ? void 0 : options.volume) === "number") {
199
+ howl.volume(1);
200
+ }
201
+ options === null || options === void 0 ? void 0 : (_options_onEnd = options.onEnd) === null || _options_onEnd === void 0 ? void 0 : _options_onEnd.call(options, soundId);
202
+ _this.emit("end", {
203
+ type: "effect",
204
+ key: key,
205
+ soundId: soundId
206
+ });
207
+ });
208
+ howl.once("stop", function(soundId) {
209
+ var _options_onStop;
210
+ if (typeof (options === null || options === void 0 ? void 0 : options.volume) === "number") {
211
+ howl.volume(1);
212
+ }
213
+ options === null || options === void 0 ? void 0 : (_options_onStop = options.onStop) === null || _options_onStop === void 0 ? void 0 : _options_onStop.call(options, soundId);
214
+ _this.emit("stop", {
215
+ type: "effect",
216
+ key: key,
217
+ soundId: soundId
218
+ });
219
+ });
220
+ howl.once("playerror", function(soundId, error) {
221
+ var _options_onError;
222
+ options === null || options === void 0 ? void 0 : (_options_onError = options.onError) === null || _options_onError === void 0 ? void 0 : _options_onError.call(options, soundId, error);
223
+ _this.emit("error", {
224
+ type: "effect",
225
+ key: key,
226
+ soundId: soundId,
227
+ error: error
228
+ });
229
+ });
230
+ return howl.play();
231
+ }
232
+ },
233
+ {
234
+ key: "stopEffect",
235
+ value: function stopEffect(key) {
236
+ var howl = this.effectCache.get(key);
237
+ if (howl) {
238
+ howl.stop();
239
+ }
240
+ }
241
+ },
242
+ {
243
+ key: "removeEffect",
244
+ value: function removeEffect(key) {
245
+ var howl = this.effectCache.get(key);
246
+ if (howl) {
247
+ howl.unload();
248
+ this.effectCache.delete(key);
249
+ }
250
+ }
251
+ },
252
+ {
253
+ key: "preloadUrl",
254
+ value: function preloadUrl(url) {
255
+ var _this = this;
256
+ var existing = this.urlAudioCache.get(url);
257
+ if (existing && existing.state() === "loaded") {
258
+ return Promise.resolve();
259
+ }
260
+ var pending = this.preloadPromises.get(url);
261
+ if (pending) {
262
+ return pending;
263
+ }
264
+ var howl = existing && existing.state() !== "unloaded" ? existing : this.createUrlHowl(url);
265
+ var promise = new Promise(function(resolve, reject) {
266
+ howl.once("load", function() {
267
+ resolve();
268
+ });
269
+ howl.once("loaderror", function(_id, error) {
270
+ _this.urlAudioCache.delete(url);
271
+ reject(error);
272
+ });
273
+ });
274
+ this.preloadPromises.set(url, promise);
275
+ var settle = function settle() {
276
+ if (_this.preloadPromises.get(url) === promise) {
277
+ _this.preloadPromises.delete(url);
278
+ }
279
+ };
280
+ promise.then(settle, settle);
281
+ return promise;
282
+ }
283
+ },
284
+ {
285
+ key: "preloadUrls",
286
+ value: function preloadUrls(urls) {
287
+ var _this = this;
288
+ return Promise.all(urls.map(function(url) {
289
+ return _this.preloadUrl(url);
290
+ }));
291
+ }
292
+ },
293
+ {
294
+ key: "createUrlHowl",
295
+ value: function createUrlHowl(url) {
296
+ var _this = this;
297
+ var howl = new this.HowlConstructor({
298
+ src: [
299
+ url
300
+ ],
301
+ preload: true
302
+ });
303
+ howl.on("load", function() {
304
+ _this.emit("load", {
305
+ type: "url",
306
+ url: url
307
+ });
308
+ });
309
+ howl.on("loaderror", function(_id, error) {
310
+ _this.urlAudioCache.delete(url);
311
+ _this.emit("error", {
312
+ type: "url",
313
+ url: url,
314
+ error: error
315
+ });
316
+ });
317
+ this.urlAudioCache.set(url, howl);
318
+ return howl;
319
+ }
320
+ },
321
+ {
322
+ key: "playUrl",
323
+ value: function playUrl(url, options) {
324
+ var _this = this;
325
+ var howl = this.urlAudioCache.get(url) || this.createUrlHowl(url);
326
+ var isSingleton = (options === null || options === void 0 ? void 0 : options.singleton) !== false;
327
+ if (isSingleton && this.activeUrlHowl && this.activeUrlHowl !== howl && this.activeUrlHowl.playing()) {
328
+ this.activeUrlHowl.stop();
329
+ }
330
+ if (howl.playing()) {
331
+ howl.stop();
332
+ }
333
+ if ((options === null || options === void 0 ? void 0 : options.loop) !== void 0) {
334
+ howl.loop(options.loop);
335
+ }
336
+ if (typeof (options === null || options === void 0 ? void 0 : options.volume) === "number") {
337
+ howl.volume(options.volume);
338
+ }
339
+ if (isSingleton) {
340
+ this.activeUrlHowl = howl;
341
+ }
342
+ howl.off("play");
343
+ howl.off("end");
344
+ howl.off("stop");
345
+ howl.off("playerror");
346
+ howl.once("play", function(soundId) {
347
+ var _options_onStart;
348
+ options === null || options === void 0 ? void 0 : (_options_onStart = options.onStart) === null || _options_onStart === void 0 ? void 0 : _options_onStart.call(options, soundId);
349
+ _this.emit("play", {
350
+ type: "url",
351
+ url: url,
352
+ soundId: soundId
353
+ });
354
+ });
355
+ howl.once("end", function(soundId) {
356
+ var _options_onEnd;
357
+ if (typeof (options === null || options === void 0 ? void 0 : options.volume) === "number") {
358
+ howl.volume(1);
359
+ }
360
+ options === null || options === void 0 ? void 0 : (_options_onEnd = options.onEnd) === null || _options_onEnd === void 0 ? void 0 : _options_onEnd.call(options, soundId);
361
+ _this.emit("end", {
362
+ type: "url",
363
+ url: url,
364
+ soundId: soundId
365
+ });
366
+ if (_this.activeUrlHowl === howl && !howl.loop()) {
367
+ _this.activeUrlHowl = null;
368
+ }
369
+ });
370
+ howl.once("stop", function(soundId) {
371
+ var _options_onStop;
372
+ if (typeof (options === null || options === void 0 ? void 0 : options.volume) === "number") {
373
+ howl.volume(1);
374
+ }
375
+ options === null || options === void 0 ? void 0 : (_options_onStop = options.onStop) === null || _options_onStop === void 0 ? void 0 : _options_onStop.call(options, soundId);
376
+ _this.emit("stop", {
377
+ type: "url",
378
+ url: url,
379
+ soundId: soundId
380
+ });
381
+ if (_this.activeUrlHowl === howl) {
382
+ _this.activeUrlHowl = null;
383
+ }
384
+ });
385
+ howl.once("playerror", function(soundId, error) {
386
+ var _options_onError;
387
+ options === null || options === void 0 ? void 0 : (_options_onError = options.onError) === null || _options_onError === void 0 ? void 0 : _options_onError.call(options, soundId, error);
388
+ _this.emit("error", {
389
+ type: "url",
390
+ url: url,
391
+ soundId: soundId,
392
+ error: error
393
+ });
394
+ if (_this.activeUrlHowl === howl) {
395
+ _this.activeUrlHowl = null;
396
+ }
397
+ });
398
+ return howl.play();
399
+ }
400
+ },
401
+ {
402
+ key: "stopUrl",
403
+ value: function stopUrl(url) {
404
+ var howl = this.urlAudioCache.get(url);
405
+ if (howl) {
406
+ howl.stop();
407
+ }
408
+ }
409
+ },
410
+ {
411
+ key: "on",
412
+ value: function on(event, handler) {
413
+ var _this_listeners_get;
414
+ var set = (_this_listeners_get = this.listeners.get(event)) !== null && _this_listeners_get !== void 0 ? _this_listeners_get : /* @__PURE__ */ new Set();
415
+ this.listeners.set(event, set);
416
+ set.add(handler);
417
+ return {
418
+ destroy: function destroy() {
419
+ set.delete(handler);
420
+ }
421
+ };
422
+ }
423
+ },
424
+ {
425
+ key: "emit",
426
+ value: function emit(event, payload) {
427
+ var set = this.listeners.get(event);
428
+ if (set) {
429
+ set.forEach(function(handler) {
430
+ try {
431
+ handler(payload);
432
+ } catch (err) {
433
+ console.error("[AudioManager] Error in event listener for ".concat(event, ":"), err);
434
+ }
435
+ });
436
+ }
437
+ }
438
+ },
439
+ {
440
+ key: "setGlobalVolume",
441
+ value: function setGlobalVolume(volume) {
442
+ this.globalVolume = volume;
443
+ this.HowlerInstance.volume(volume);
444
+ }
445
+ },
446
+ {
447
+ key: "mute",
448
+ value: function mute(muted) {
449
+ this.HowlerInstance.mute(muted);
450
+ }
451
+ },
452
+ {
453
+ key: "stopAll",
454
+ value: function stopAll() {
455
+ this.HowlerInstance.stop();
456
+ this.activeUrlHowl = null;
457
+ }
458
+ },
459
+ {
460
+ key: "destroy",
461
+ value: function destroy() {
462
+ this.effectCache.forEach(function(howl) {
463
+ return howl.unload();
464
+ });
465
+ this.urlAudioCache.forEach(function(howl) {
466
+ return howl.unload();
467
+ });
468
+ this.effectCache.clear();
469
+ this.urlAudioCache.clear();
470
+ this.preloadPromises.clear();
471
+ this.listeners.clear();
472
+ this.activeUrlHowl = null;
473
+ }
474
+ }
475
+ ]);
476
+ return AudioManager;
477
+ }();
478
+ // Annotate the CommonJS export names for ESM import in node:
479
+ 0 && (module1.exports = {
480
+ AudioManager: AudioManager
481
+ });
482
+ if (__exports != exports1) module1.exports = exports1;
483
+ return module1.exports;
484
+ });
485
+ //# sourceMappingURL=index.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/afei/github/howler-audio-manager/dist/index.umd.js","../src/index.ts","../src/manager.ts"],"names":["g","f","exports","module","define","amd","globalThis","self","__exports","__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toCommonJS","mod","value","index_exports","AudioManager","default","import_howler","require","options","inject","effectCache","Map","urlAudioCache","preloadPromises","activeUrlHowl","globalVolume","listeners","HowlConstructor","HowlClass","Howl","HowlerInstance","HowlerObj","Howler","defaultVolume","setGlobalVolume","hasEffect","has","loadEffect","url","unload","howl","src","preload","on","emit","type","_id","error","set","loadEffects","map","keys","forEach","typedKey","isNaN","Number","playEffect","console","warn","String","playing","stop","volume","off","once","soundId","onStart","onEnd","onStop","onError","play","stopEffect","removeEffect","delete","preloadUrl","existing","state","Promise","resolve","pending","createUrlHowl","promise","reject","settle","then","preloadUrls","urls","playUrl","isSingleton","singleton","loop","stopUrl","event","handler","Set","add","destroy","payload","err","mute","muted","stopAll","clear"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;CAOC,GACA,CAAA,SAASA,CAAC,EAACC,CAAC;IAAE,IAAG,CAAA,OAAOC,wCAAP,SAAOA,QAAM,KAAG,YAAU,CAAA,OAAOC,uCAAP,SAAOA,OAAK,IAAE,KAAI;QAACA,OAAOD,OAAO,GAACD;IAAG,OAAM,IAAG,cAAY,OAAOG,UAAUA,OAAOC,GAAG,EAAC;QAACD,OAAO,cAAaH;IAAE,OAAM;QAACD,CAAC,CAAC,aAAa,GAACC;IAAG;AAAC,CAAA,EAAE,CAAA,OAAOK,2CAAP,SAAOA,WAAS,IAAI,MAAMA,aAAa,CAAA,OAAOC,qCAAP,SAAOA,KAAG,IAAI,MAAMA,OAAO,IAAI,EAAC;IAAW,IAAIL,WAAQ,CAAC;IAAE,IAAIM,YAAUN;IAAQ,IAAIC,UAAO;QAACD,SAAAA;IAAO;IAChU;IACA,IAAIO,YAAYC,OAAOC,cAAc;IACrC,IAAIC,mBAAmBF,OAAOG,wBAAwB;IACtD,IAAIC,oBAAoBJ,OAAOK,mBAAmB;IAClD,IAAIC,eAAeN,OAAOO,SAAS,CAACC,cAAc;IAClD,IAAIC,WAAW,kBAACC,QAAQC;QACtB,IAAK,IAAIC,QAAQD,IACfZ,UAAUW,QAAQE,MAAM;YAAEC,KAAKF,GAAG,CAACC,KAAK;YAAEE,YAAY;QAAK;IAC/D;IACA,IAAIC,cAAc,qBAACC,IAAIC,MAAMC,QAAQC;QACnC,IAAIF,QAAQ,CAAA,OAAOA,qCAAP,SAAOA,KAAG,MAAM,YAAY,OAAOA,SAAS,YAAY;gBAC7D,kCAAA,2BAAA;;;oBAAA,IAAIG,MAAJ;oBACH,IAAI,CAACd,aAAae,IAAI,CAACL,IAAII,QAAQA,QAAQF,QACzCnB,UAAUiB,IAAII,KAAK;wBAAEP,KAAK,SAALA;mCAAWI,IAAI,CAACG,IAAI;;wBAAEN,YAAY,CAAEK,CAAAA,OAAOjB,iBAAiBe,MAAMG,IAAG,KAAMD,KAAKL,UAAU;oBAAC;;gBAFpH,QAAK,YAAWV,kBAAkBa,0BAA7B,SAAA,6BAAA,QAAA,yBAAA;;gBAAA;gBAAA;;;yBAAA,6BAAA;wBAAA;;;wBAAA;8BAAA;;;;QAGP;QACA,OAAOD;IACT;IACA,IAAIM,eAAe,sBAACC;eAAQR,YAAYhB,UAAU,CAAC,GAAG,cAAc;YAAEyB,OAAO;QAAK,IAAID;;IAEtF,eAAe;IC5Bf,IAAAE,gBAAA,CAAA;IAAAhB,SAAAgB,eAAA;QAAAC,cAAA,SAAAA;mBAAAA;;QAAAC,SAAA,SAAAA;mBAAAD;;IAAA;IAAAjC,QAAAD,OAAA,GAAA8B,aAAAG;IDoCA,iBAAiB;IEpCjB,IAAAG,gBAA6BC,QAAA;IAWtB,IAAMH,6BAAN;;iBAAMA,aAYTI,OAAA,EACAC,MAAA;oCAbSL;;YACX,IAAA,CAAQM,WAAA,GAAc,aAAA,GAAA,IAAIC;YAC1B,IAAA,CAAQC,aAAA,GAAgB,aAAA,GAAA,IAAID;YAC5B,IAAA,CAAQE,eAAA,GAAkB,aAAA,GAAA,IAAIF;YAC9B,IAAA,CAAQG,aAAA,GAA6B;YACrC,IAAA,CAAQC,YAAA,GAAe;YACvB,IAAA,CAAQC,SAAA,GAAY,aAAA,GAAA,IAAIL;YAStB,IAAA,CAAKM,eAAA,WAAkBR,mBAAAA,6BAAAA,OAAQS,SAAA,uCAAaZ,cAAAa,IAAA;YAC5C,IAAA,CAAKC,cAAA,YAAiBX,mBAAAA,6BAAAA,OAAQY,SAAA,yCAAaf,cAAAgB,MAAA;YAC3C,IAAI,QAAOd,oBAAAA,8BAAAA,QAASe,aAAA,MAAkB,UAAU;gBAC9C,IAAA,CAAKC,eAAA,CAAgBhB,QAAQe,aAAa;YAC5C;;;;gBAGFE,KAAAA;uBAAAA,SAAAA,UAAU3B,GAAA;oBACR,OAAO,IAAA,CAAKY,WAAA,CAAYgB,GAAA,CAAI5B;gBAC9B;;;gBAEA6B,KAAAA;uBAAAA,SAAAA,WAAW7B,GAAA,EAAQ8B,GAAA;;oBACjB,IAAI,IAAA,CAAKlB,WAAA,CAAYgB,GAAA,CAAI5B,MAAM;wBAC7B,IAAA,CAAKY,WAAA,CAAYnB,GAAA,CAAIO,KAAM+B,MAAA;oBAC7B;oBACA,IAAMC,OAAO,IAAI,IAAA,CAAKb,eAAA,CAAgB;wBACpCc,KAAK;4BAACH;yBAAG;wBACTI,SAAS;oBACX;oBACAF,KAAKG,EAAA,CAAG,QAAQ;wBACd,MAAKC,IAAA,CAAK,QAAQ;4BAAEC,MAAM;4BAAUrC,KAAAA;4BAAK8B,KAAAA;wBAAI;oBAC/C;oBACAE,KAAKG,EAAA,CAAG,aAAa,SAACG,KAAaC;wBACjC,MAAKH,IAAA,CAAK,SAAS;4BAAEC,MAAM;4BAAUrC,KAAAA;4BAAK8B,KAAAA;4BAAKS,OAAAA;wBAAM;oBACvD;oBACA,IAAA,CAAK3B,WAAA,CAAY4B,GAAA,CAAIxC,KAAKgC;gBAC5B;;;gBAEAS,KAAAA;uBAAAA,SAAAA,YAAYC,GAAA;;oBACV9D,OAAO+D,IAAA,CAAKD,KAAKE,OAAA,CAAQ,SAAC5C;wBACxB,IAAM6C,WAAYC,MAAMC,OAAO/C,QAAQA,MAAM+C,OAAO/C;wBACpD,MAAK6B,UAAA,CAAWgB,UAAUH,GAAA,CAAI1C,IAAW;oBAC3C;gBACF;;;gBAEAgD,KAAAA;uBAAAA,SAAAA,WAAWhD,GAAA,EAAQU,OAAA;;oBACjB,IAAMsB,OAAO,IAAA,CAAKpB,WAAA,CAAYnB,GAAA,CAAIO;oBAClC,IAAI,CAACgC,MAAM;wBACTiB,QAAQC,IAAA,CAAK,4CAAuD,OAAXC,OAAOnD,MAAI;wBACpE,OAAO,KAAA;oBACT;oBAEA,IAAIgC,KAAKoB,OAAA,IAAW;wBAClBpB,KAAKqB,IAAA;oBACP;oBAEA,IAAI,QAAO3C,oBAAAA,8BAAAA,QAAS4C,MAAA,MAAW,UAAU;wBACvCtB,KAAKsB,MAAA,CAAO5C,QAAQ4C,MAAM;oBAC5B;oBAGAtB,KAAKuB,GAAA,CAAI;oBACTvB,KAAKuB,GAAA,CAAI;oBACTvB,KAAKuB,GAAA,CAAI;oBACTvB,KAAKuB,GAAA,CAAI;oBAETvB,KAAKwB,IAAA,CAAK,QAAQ,SAACC;4BACjB/C;wBAAAA,oBAAAA,+BAAAA,mBAAAA,QAASgD,OAAA,cAAThD,uCAAAA,sBAAAA,SAAmB+C;wBACnB,MAAKrB,IAAA,CAAK,QAAQ;4BAAEC,MAAM;4BAAUrC,KAAAA;4BAAKyD,SAAAA;wBAAQ;oBACnD;oBAEAzB,KAAKwB,IAAA,CAAK,OAAO,SAACC;4BAIhB/C;wBAHA,IAAI,QAAOA,oBAAAA,8BAAAA,QAAS4C,MAAA,MAAW,UAAU;4BACvCtB,KAAKsB,MAAA,CAAO;wBACd;wBACA5C,oBAAAA,+BAAAA,iBAAAA,QAASiD,KAAA,cAATjD,qCAAAA,oBAAAA,SAAiB+C;wBACjB,MAAKrB,IAAA,CAAK,OAAO;4BAAEC,MAAM;4BAAUrC,KAAAA;4BAAKyD,SAAAA;wBAAQ;oBAClD;oBAEAzB,KAAKwB,IAAA,CAAK,QAAQ,SAACC;4BAIjB/C;wBAHA,IAAI,QAAOA,oBAAAA,8BAAAA,QAAS4C,MAAA,MAAW,UAAU;4BACvCtB,KAAKsB,MAAA,CAAO;wBACd;wBACA5C,oBAAAA,+BAAAA,kBAAAA,QAASkD,MAAA,cAATlD,sCAAAA,qBAAAA,SAAkB+C;wBAClB,MAAKrB,IAAA,CAAK,QAAQ;4BAAEC,MAAM;4BAAUrC,KAAAA;4BAAKyD,SAAAA;wBAAQ;oBACnD;oBAEAzB,KAAKwB,IAAA,CAAK,aAAa,SAACC,SAAiBlB;4BACvC7B;wBAAAA,oBAAAA,+BAAAA,mBAAAA,QAASmD,OAAA,cAATnD,uCAAAA,sBAAAA,SAAmB+C,SAASlB;wBAC5B,MAAKH,IAAA,CAAK,SAAS;4BAAEC,MAAM;4BAAUrC,KAAAA;4BAAKyD,SAAAA;4BAASlB,OAAAA;wBAAM;oBAC3D;oBAEA,OAAOP,KAAK8B,IAAA;gBACd;;;gBAEAC,KAAAA;uBAAAA,SAAAA,WAAW/D,GAAA;oBACT,IAAMgC,OAAO,IAAA,CAAKpB,WAAA,CAAYnB,GAAA,CAAIO;oBAClC,IAAIgC,MAAM;wBACRA,KAAKqB,IAAA;oBACP;gBACF;;;gBAEAW,KAAAA;uBAAAA,SAAAA,aAAahE,GAAA;oBACX,IAAMgC,OAAO,IAAA,CAAKpB,WAAA,CAAYnB,GAAA,CAAIO;oBAClC,IAAIgC,MAAM;wBACRA,KAAKD,MAAA;wBACL,IAAA,CAAKnB,WAAA,CAAYqD,MAAA,CAAOjE;oBAC1B;gBACF;;;gBAEAkE,KAAAA;uBAAAA,SAAAA,WAAWpC,GAAA;;oBACT,IAAMqC,WAAW,IAAA,CAAKrD,aAAA,CAAcrB,GAAA,CAAIqC;oBACxC,IAAIqC,YAAYA,SAASC,KAAA,OAAY,UAAU;wBAC7C,OAAOC,QAAQC,OAAA;oBACjB;oBAEA,IAAMC,UAAU,IAAA,CAAKxD,eAAA,CAAgBtB,GAAA,CAAIqC;oBACzC,IAAIyC,SAAS;wBACX,OAAOA;oBACT;oBAIA,IAAMvC,OAAOmC,YAAYA,SAASC,KAAA,OAAY,aAAaD,WAAW,IAAA,CAAKK,aAAA,CAAc1C;oBAEzF,IAAM2C,UAAU,IAAIJ,QAAc,SAACC,SAASI;wBAC1C1C,KAAKwB,IAAA,CAAK,QAAQ;4BAChBc;wBACF;wBAEAtC,KAAKwB,IAAA,CAAK,aAAa,SAAClB,KAAaC;4BACnC,MAAKzB,aAAA,CAAcmD,MAAA,CAAOnC;4BAC1B4C,OAAOnC;wBACT;oBACF;oBAEA,IAAA,CAAKxB,eAAA,CAAgByB,GAAA,CAAIV,KAAK2C;oBAC9B,IAAME,SAAS;wBACb,IAAI,MAAK5D,eAAA,CAAgBtB,GAAA,CAAIqC,SAAS2C,SAAS;4BAC7C,MAAK1D,eAAA,CAAgBkD,MAAA,CAAOnC;wBAC9B;oBACF;oBACA2C,QAAQG,IAAA,CAAKD,QAAQA;oBAErB,OAAOF;gBACT;;;gBAEAI,KAAAA;uBAAAA,SAAAA,YAAYC,IAAA;;oBACV,OAAOT,QAAQ9E,GAAA,CAAIuF,KAAKpC,GAAA,CAAI,SAACZ;+BAAQ,MAAKoC,UAAA,CAAWpC;;gBACvD;;;gBAEQ0C,KAAAA;uBAAAA,SAAAA,cAAc1C,GAAA;;oBACpB,IAAME,OAAO,IAAI,IAAA,CAAKb,eAAA,CAAgB;wBACpCc,KAAK;4BAACH;yBAAG;wBACTI,SAAS;oBACX;oBACAF,KAAKG,EAAA,CAAG,QAAQ;wBACd,MAAKC,IAAA,CAAK,QAAQ;4BAAEC,MAAM;4BAAOP,KAAAA;wBAAI;oBACvC;oBACAE,KAAKG,EAAA,CAAG,aAAa,SAACG,KAAaC;wBACjC,MAAKzB,aAAA,CAAcmD,MAAA,CAAOnC;wBAC1B,MAAKM,IAAA,CAAK,SAAS;4BAAEC,MAAM;4BAAOP,KAAAA;4BAAKS,OAAAA;wBAAM;oBAC/C;oBACA,IAAA,CAAKzB,aAAA,CAAc0B,GAAA,CAAIV,KAAKE;oBAC5B,OAAOA;gBACT;;;gBAEA+C,KAAAA;uBAAAA,SAAAA,QAAQjD,GAAA,EAAapB,OAAA;;oBACnB,IAAMsB,OAAO,IAAA,CAAKlB,aAAA,CAAcrB,GAAA,CAAIqC,QAAQ,IAAA,CAAK0C,aAAA,CAAc1C;oBAG/D,IAAMkD,cAActE,CAAAA,oBAAAA,8BAAAA,QAASuE,SAAA,MAAc;oBAC3C,IACED,eACA,IAAA,CAAKhE,aAAA,IACL,IAAA,CAAKA,aAAA,KAAkBgB,QACvB,IAAA,CAAKhB,aAAA,CAAcoC,OAAA,IACnB;wBACA,IAAA,CAAKpC,aAAA,CAAcqC,IAAA;oBACrB;oBAGA,IAAIrB,KAAKoB,OAAA,IAAW;wBAClBpB,KAAKqB,IAAA;oBACP;oBAEA,IAAI3C,CAAAA,oBAAAA,8BAAAA,QAASwE,IAAA,MAAS,KAAA,GAAW;wBAC/BlD,KAAKkD,IAAA,CAAKxE,QAAQwE,IAAI;oBACxB;oBAEA,IAAI,QAAOxE,oBAAAA,8BAAAA,QAAS4C,MAAA,MAAW,UAAU;wBACvCtB,KAAKsB,MAAA,CAAO5C,QAAQ4C,MAAM;oBAC5B;oBAEA,IAAI0B,aAAa;wBACf,IAAA,CAAKhE,aAAA,GAAgBgB;oBACvB;oBAGAA,KAAKuB,GAAA,CAAI;oBACTvB,KAAKuB,GAAA,CAAI;oBACTvB,KAAKuB,GAAA,CAAI;oBACTvB,KAAKuB,GAAA,CAAI;oBAETvB,KAAKwB,IAAA,CAAK,QAAQ,SAACC;4BACjB/C;wBAAAA,oBAAAA,+BAAAA,mBAAAA,QAASgD,OAAA,cAAThD,uCAAAA,sBAAAA,SAAmB+C;wBACnB,MAAKrB,IAAA,CAAK,QAAQ;4BAAEC,MAAM;4BAAOP,KAAAA;4BAAK2B,SAAAA;wBAAQ;oBAChD;oBAEAzB,KAAKwB,IAAA,CAAK,OAAO,SAACC;4BAIhB/C;wBAHA,IAAI,QAAOA,oBAAAA,8BAAAA,QAAS4C,MAAA,MAAW,UAAU;4BACvCtB,KAAKsB,MAAA,CAAO;wBACd;wBACA5C,oBAAAA,+BAAAA,iBAAAA,QAASiD,KAAA,cAATjD,qCAAAA,oBAAAA,SAAiB+C;wBACjB,MAAKrB,IAAA,CAAK,OAAO;4BAAEC,MAAM;4BAAOP,KAAAA;4BAAK2B,SAAAA;wBAAQ;wBAC7C,IAAI,MAAKzC,aAAA,KAAkBgB,QAAQ,CAACA,KAAKkD,IAAA,IAAQ;4BAC/C,MAAKlE,aAAA,GAAgB;wBACvB;oBACF;oBAEAgB,KAAKwB,IAAA,CAAK,QAAQ,SAACC;4BAIjB/C;wBAHA,IAAI,QAAOA,oBAAAA,8BAAAA,QAAS4C,MAAA,MAAW,UAAU;4BACvCtB,KAAKsB,MAAA,CAAO;wBACd;wBACA5C,oBAAAA,+BAAAA,kBAAAA,QAASkD,MAAA,cAATlD,sCAAAA,qBAAAA,SAAkB+C;wBAClB,MAAKrB,IAAA,CAAK,QAAQ;4BAAEC,MAAM;4BAAOP,KAAAA;4BAAK2B,SAAAA;wBAAQ;wBAC9C,IAAI,MAAKzC,aAAA,KAAkBgB,MAAM;4BAC/B,MAAKhB,aAAA,GAAgB;wBACvB;oBACF;oBAEAgB,KAAKwB,IAAA,CAAK,aAAa,SAACC,SAAiBlB;4BACvC7B;wBAAAA,oBAAAA,+BAAAA,mBAAAA,QAASmD,OAAA,cAATnD,uCAAAA,sBAAAA,SAAmB+C,SAASlB;wBAC5B,MAAKH,IAAA,CAAK,SAAS;4BAAEC,MAAM;4BAAOP,KAAAA;4BAAK2B,SAAAA;4BAASlB,OAAAA;wBAAM;wBACtD,IAAI,MAAKvB,aAAA,KAAkBgB,MAAM;4BAC/B,MAAKhB,aAAA,GAAgB;wBACvB;oBACF;oBAEA,OAAOgB,KAAK8B,IAAA;gBACd;;;gBAEAqB,KAAAA;uBAAAA,SAAAA,QAAQrD,GAAA;oBACN,IAAME,OAAO,IAAA,CAAKlB,aAAA,CAAcrB,GAAA,CAAIqC;oBACpC,IAAIE,MAAM;wBACRA,KAAKqB,IAAA;oBACP;gBACF;;;gBAEAlB,KAAAA;uBAAAA,SAAAA,GAAGiD,KAAA,EAAuBC,OAAA;wBACZ;oBAAZ,IAAM7C,OAAM,sBAAA,IAAA,CAAKtB,SAAA,CAAUzB,GAAA,CAAI2F,oBAAnB,iCAAA,sBAA6B,aAAA,GAAA,IAAIE;oBAC7C,IAAA,CAAKpE,SAAA,CAAUsB,GAAA,CAAI4C,OAAO5C;oBAC1BA,IAAI+C,GAAA,CAAIF;oBACR,OAAO;wBACLG,SAAS,SAATA;4BACEhD,IAAIyB,MAAA,CAAOoB;wBACb;oBACF;gBACF;;;gBAEUjD,KAAAA;uBAAAA,SAAAA,KAAKgD,KAAA,EAAuBK,OAAA;oBACpC,IAAMjD,MAAM,IAAA,CAAKtB,SAAA,CAAUzB,GAAA,CAAI2F;oBAC/B,IAAI5C,KAAK;wBACPA,IAAII,OAAA,CAAQ,SAACyC;4BACX,IAAI;gCACFA,QAAQI;4BACV,EAAA,OAASC,KAAK;gCACZzC,QAAQV,KAAA,CAAM,8CAAmD,OAAL6C,OAAK,MAAKM;4BACxE;wBACF;oBACF;gBACF;;;gBAEAhE,KAAAA;uBAAAA,SAAAA,gBAAgB4B,MAAA;oBACd,IAAA,CAAKrC,YAAA,GAAeqC;oBACpB,IAAA,CAAKhC,cAAA,CAAegC,MAAA,CAAOA;gBAC7B;;;gBAEAqC,KAAAA;uBAAAA,SAAAA,KAAKC,KAAA;oBACH,IAAA,CAAKtE,cAAA,CAAeqE,IAAA,CAAKC;gBAC3B;;;gBAEAC,KAAAA;uBAAAA,SAAAA;oBACE,IAAA,CAAKvE,cAAA,CAAe+B,IAAA;oBACpB,IAAA,CAAKrC,aAAA,GAAgB;gBACvB;;;gBAEAwE,KAAAA;uBAAAA,SAAAA;oBACE,IAAA,CAAK5E,WAAA,CAAYgC,OAAA,CAAQ,SAACZ;+BAASA,KAAKD,MAAA;;oBACxC,IAAA,CAAKjB,aAAA,CAAc8B,OAAA,CAAQ,SAACZ;+BAASA,KAAKD,MAAA;;oBAC1C,IAAA,CAAKnB,WAAA,CAAYkF,KAAA;oBACjB,IAAA,CAAKhF,aAAA,CAAcgF,KAAA;oBACnB,IAAA,CAAK/E,eAAA,CAAgB+E,KAAA;oBACrB,IAAA,CAAK5E,SAAA,CAAU4E,KAAA;oBACf,IAAA,CAAK9E,aAAA,GAAgB;gBACvB;;;;;IF/BF,6DAA6D;IAC7D,KAAM3C,CAAAA,QAAOD,OAAO,GAAG;QACrBkC,cAAAA;IACF,CAAA;IAEA,IAAG5B,aAAaN,UAAQC,QAAOD,OAAO,GAAGA;IAAQ,OAAOC,QAAOD,OAAO;AAAA","sourcesContent":["/*!\n * name: @jswork/howler-audio-manager\n * description: Howler.js audio manager, enum-driven sounds for H5.\n * homepage: https://js.work\n * version: 1.0.1\n * date: 2026-10-20 18:54:06\n * license: MIT\n */\n(function(g,f){if(typeof exports==\"object\"&&typeof module<\"u\"){module.exports=f()}else if(\"function\"==typeof define && define.amd){define(\"urlLiteral\",f)}else {g[\"urlLiteral\"]=f()}}(typeof globalThis < \"u\" ? globalThis : typeof self < \"u\" ? self : this,function(){var exports={};var __exports=exports;var module={exports};\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/index.ts\nvar index_exports = {};\n__export(index_exports, {\n AudioManager: () => AudioManager,\n default: () => AudioManager\n});\nmodule.exports = __toCommonJS(index_exports);\n\n// src/manager.ts\nvar import_howler = require(\"howler\");\nvar AudioManager = class {\n constructor(options, inject) {\n this.effectCache = /* @__PURE__ */ new Map();\n this.urlAudioCache = /* @__PURE__ */ new Map();\n this.preloadPromises = /* @__PURE__ */ new Map();\n this.activeUrlHowl = null;\n this.globalVolume = 1;\n this.listeners = /* @__PURE__ */ new Map();\n this.HowlConstructor = inject?.HowlClass ?? import_howler.Howl;\n this.HowlerInstance = inject?.HowlerObj ?? import_howler.Howler;\n if (typeof options?.defaultVolume === \"number\") {\n this.setGlobalVolume(options.defaultVolume);\n }\n }\n hasEffect(key) {\n return this.effectCache.has(key);\n }\n loadEffect(key, url) {\n if (this.effectCache.has(key)) {\n this.effectCache.get(key).unload();\n }\n const howl = new this.HowlConstructor({\n src: [url],\n preload: true\n });\n howl.on(\"load\", () => {\n this.emit(\"load\", { type: \"effect\", key, url });\n });\n howl.on(\"loaderror\", (_id, error) => {\n this.emit(\"error\", { type: \"effect\", key, url, error });\n });\n this.effectCache.set(key, howl);\n }\n loadEffects(map) {\n Object.keys(map).forEach((key) => {\n const typedKey = isNaN(Number(key)) ? key : Number(key);\n this.loadEffect(typedKey, map[key]);\n });\n }\n playEffect(key, options) {\n const howl = this.effectCache.get(key);\n if (!howl) {\n console.warn(`[AudioManager] Effect not found for key: ${String(key)}.`);\n return void 0;\n }\n if (howl.playing()) {\n howl.stop();\n }\n if (typeof options?.volume === \"number\") {\n howl.volume(options.volume);\n }\n howl.off(\"play\");\n howl.off(\"end\");\n howl.off(\"stop\");\n howl.off(\"playerror\");\n howl.once(\"play\", (soundId) => {\n options?.onStart?.(soundId);\n this.emit(\"play\", { type: \"effect\", key, soundId });\n });\n howl.once(\"end\", (soundId) => {\n if (typeof options?.volume === \"number\") {\n howl.volume(1);\n }\n options?.onEnd?.(soundId);\n this.emit(\"end\", { type: \"effect\", key, soundId });\n });\n howl.once(\"stop\", (soundId) => {\n if (typeof options?.volume === \"number\") {\n howl.volume(1);\n }\n options?.onStop?.(soundId);\n this.emit(\"stop\", { type: \"effect\", key, soundId });\n });\n howl.once(\"playerror\", (soundId, error) => {\n options?.onError?.(soundId, error);\n this.emit(\"error\", { type: \"effect\", key, soundId, error });\n });\n return howl.play();\n }\n stopEffect(key) {\n const howl = this.effectCache.get(key);\n if (howl) {\n howl.stop();\n }\n }\n removeEffect(key) {\n const howl = this.effectCache.get(key);\n if (howl) {\n howl.unload();\n this.effectCache.delete(key);\n }\n }\n preloadUrl(url) {\n const existing = this.urlAudioCache.get(url);\n if (existing && existing.state() === \"loaded\") {\n return Promise.resolve();\n }\n const pending = this.preloadPromises.get(url);\n if (pending) {\n return pending;\n }\n const howl = existing && existing.state() !== \"unloaded\" ? existing : this.createUrlHowl(url);\n const promise = new Promise((resolve, reject) => {\n howl.once(\"load\", () => {\n resolve();\n });\n howl.once(\"loaderror\", (_id, error) => {\n this.urlAudioCache.delete(url);\n reject(error);\n });\n });\n this.preloadPromises.set(url, promise);\n const settle = () => {\n if (this.preloadPromises.get(url) === promise) {\n this.preloadPromises.delete(url);\n }\n };\n promise.then(settle, settle);\n return promise;\n }\n preloadUrls(urls) {\n return Promise.all(urls.map((url) => this.preloadUrl(url)));\n }\n createUrlHowl(url) {\n const howl = new this.HowlConstructor({\n src: [url],\n preload: true\n });\n howl.on(\"load\", () => {\n this.emit(\"load\", { type: \"url\", url });\n });\n howl.on(\"loaderror\", (_id, error) => {\n this.urlAudioCache.delete(url);\n this.emit(\"error\", { type: \"url\", url, error });\n });\n this.urlAudioCache.set(url, howl);\n return howl;\n }\n playUrl(url, options) {\n const howl = this.urlAudioCache.get(url) || this.createUrlHowl(url);\n const isSingleton = options?.singleton !== false;\n if (isSingleton && this.activeUrlHowl && this.activeUrlHowl !== howl && this.activeUrlHowl.playing()) {\n this.activeUrlHowl.stop();\n }\n if (howl.playing()) {\n howl.stop();\n }\n if (options?.loop !== void 0) {\n howl.loop(options.loop);\n }\n if (typeof options?.volume === \"number\") {\n howl.volume(options.volume);\n }\n if (isSingleton) {\n this.activeUrlHowl = howl;\n }\n howl.off(\"play\");\n howl.off(\"end\");\n howl.off(\"stop\");\n howl.off(\"playerror\");\n howl.once(\"play\", (soundId) => {\n options?.onStart?.(soundId);\n this.emit(\"play\", { type: \"url\", url, soundId });\n });\n howl.once(\"end\", (soundId) => {\n if (typeof options?.volume === \"number\") {\n howl.volume(1);\n }\n options?.onEnd?.(soundId);\n this.emit(\"end\", { type: \"url\", url, soundId });\n if (this.activeUrlHowl === howl && !howl.loop()) {\n this.activeUrlHowl = null;\n }\n });\n howl.once(\"stop\", (soundId) => {\n if (typeof options?.volume === \"number\") {\n howl.volume(1);\n }\n options?.onStop?.(soundId);\n this.emit(\"stop\", { type: \"url\", url, soundId });\n if (this.activeUrlHowl === howl) {\n this.activeUrlHowl = null;\n }\n });\n howl.once(\"playerror\", (soundId, error) => {\n options?.onError?.(soundId, error);\n this.emit(\"error\", { type: \"url\", url, soundId, error });\n if (this.activeUrlHowl === howl) {\n this.activeUrlHowl = null;\n }\n });\n return howl.play();\n }\n stopUrl(url) {\n const howl = this.urlAudioCache.get(url);\n if (howl) {\n howl.stop();\n }\n }\n on(event, handler) {\n const set = this.listeners.get(event) ?? /* @__PURE__ */ new Set();\n this.listeners.set(event, set);\n set.add(handler);\n return {\n destroy: () => {\n set.delete(handler);\n }\n };\n }\n emit(event, payload) {\n const set = this.listeners.get(event);\n if (set) {\n set.forEach((handler) => {\n try {\n handler(payload);\n } catch (err) {\n console.error(`[AudioManager] Error in event listener for ${event}:`, err);\n }\n });\n }\n }\n setGlobalVolume(volume) {\n this.globalVolume = volume;\n this.HowlerInstance.volume(volume);\n }\n mute(muted) {\n this.HowlerInstance.mute(muted);\n }\n stopAll() {\n this.HowlerInstance.stop();\n this.activeUrlHowl = null;\n }\n destroy() {\n this.effectCache.forEach((howl) => howl.unload());\n this.urlAudioCache.forEach((howl) => howl.unload());\n this.effectCache.clear();\n this.urlAudioCache.clear();\n this.preloadPromises.clear();\n this.listeners.clear();\n this.activeUrlHowl = null;\n }\n};\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n AudioManager\n});\n\nif(__exports != exports)module.exports = exports;return module.exports}));\n","export * from './types';\nexport { AudioManager } from './manager';\nexport { AudioManager as default } from './manager';\n","import { Howl, Howler } from 'howler';\nimport type {\n AudioManagerOptions,\n PlayOptions,\n PlayUrlOptions,\n AudioEventType,\n AudioEventPayload,\n EventSubscription,\n SoundResourceMap\n} from './types';\n\nexport class AudioManager<K extends string | number = string> {\n private effectCache = new Map<K, Howl>();\n private urlAudioCache = new Map<string, Howl>();\n private preloadPromises = new Map<string, Promise<void>>();\n private activeUrlHowl: Howl | null = null;\n private globalVolume = 1.0;\n private listeners = new Map<AudioEventType, Set<(payload: AudioEventPayload<K>) => void>>();\n\n private HowlConstructor: typeof Howl;\n private HowlerInstance: typeof Howler;\n\n constructor(\n options?: AudioManagerOptions,\n inject?: { HowlClass?: typeof Howl; HowlerObj?: typeof Howler }\n ) {\n this.HowlConstructor = inject?.HowlClass ?? Howl;\n this.HowlerInstance = inject?.HowlerObj ?? Howler;\n if (typeof options?.defaultVolume === 'number') {\n this.setGlobalVolume(options.defaultVolume);\n }\n }\n\n hasEffect(key: K): boolean {\n return this.effectCache.has(key);\n }\n\n loadEffect(key: K, url: string): void {\n if (this.effectCache.has(key)) {\n this.effectCache.get(key)!.unload();\n }\n const howl = new this.HowlConstructor({\n src: [url],\n preload: true\n });\n howl.on('load', () => {\n this.emit('load', { type: 'effect', key, url });\n });\n howl.on('loaderror', (_id: number, error: unknown) => {\n this.emit('error', { type: 'effect', key, url, error });\n });\n this.effectCache.set(key, howl);\n }\n\n loadEffects(map: SoundResourceMap<K>): void {\n Object.keys(map).forEach((key) => {\n const typedKey = (isNaN(Number(key)) ? key : Number(key)) as K;\n this.loadEffect(typedKey, map[key as any]);\n });\n }\n\n playEffect(key: K, options?: PlayOptions): number | undefined {\n const howl = this.effectCache.get(key);\n if (!howl) {\n console.warn(`[AudioManager] Effect not found for key: ${String(key)}.`);\n return undefined;\n }\n\n if (howl.playing()) {\n howl.stop();\n }\n\n if (typeof options?.volume === 'number') {\n howl.volume(options.volume);\n }\n\n // Clear handlers from previous plays to avoid stale/duplicate callbacks.\n howl.off('play');\n howl.off('end');\n howl.off('stop');\n howl.off('playerror');\n\n howl.once('play', (soundId: number) => {\n options?.onStart?.(soundId);\n this.emit('play', { type: 'effect', key, soundId });\n });\n\n howl.once('end', (soundId: number) => {\n if (typeof options?.volume === 'number') {\n howl.volume(1);\n }\n options?.onEnd?.(soundId);\n this.emit('end', { type: 'effect', key, soundId });\n });\n\n howl.once('stop', (soundId: number) => {\n if (typeof options?.volume === 'number') {\n howl.volume(1);\n }\n options?.onStop?.(soundId);\n this.emit('stop', { type: 'effect', key, soundId });\n });\n\n howl.once('playerror', (soundId: number, error: unknown) => {\n options?.onError?.(soundId, error);\n this.emit('error', { type: 'effect', key, soundId, error });\n });\n\n return howl.play();\n }\n\n stopEffect(key: K): void {\n const howl = this.effectCache.get(key);\n if (howl) {\n howl.stop();\n }\n }\n\n removeEffect(key: K): void {\n const howl = this.effectCache.get(key);\n if (howl) {\n howl.unload();\n this.effectCache.delete(key);\n }\n }\n\n preloadUrl(url: string): Promise<void> {\n const existing = this.urlAudioCache.get(url);\n if (existing && existing.state() === 'loaded') {\n return Promise.resolve();\n }\n\n const pending = this.preloadPromises.get(url);\n if (pending) {\n return pending;\n }\n\n // A howl in a terminal failed state (unloaded after error) must be replaced\n // so a fresh instance can retry the load.\n const howl = existing && existing.state() !== 'unloaded' ? existing : this.createUrlHowl(url);\n\n const promise = new Promise<void>((resolve, reject) => {\n howl.once('load', () => {\n resolve();\n });\n\n howl.once('loaderror', (_id: number, error: unknown) => {\n this.urlAudioCache.delete(url);\n reject(error);\n });\n });\n\n this.preloadPromises.set(url, promise);\n const settle = () => {\n if (this.preloadPromises.get(url) === promise) {\n this.preloadPromises.delete(url);\n }\n };\n promise.then(settle, settle);\n\n return promise;\n }\n\n preloadUrls(urls: string[]): Promise<void[]> {\n return Promise.all(urls.map((url) => this.preloadUrl(url)));\n }\n\n private createUrlHowl(url: string): Howl {\n const howl = new this.HowlConstructor({\n src: [url],\n preload: true\n });\n howl.on('load', () => {\n this.emit('load', { type: 'url', url });\n });\n howl.on('loaderror', (_id: number, error: unknown) => {\n this.urlAudioCache.delete(url);\n this.emit('error', { type: 'url', url, error });\n });\n this.urlAudioCache.set(url, howl);\n return howl;\n }\n\n playUrl(url: string, options?: PlayUrlOptions): number {\n const howl = this.urlAudioCache.get(url) || this.createUrlHowl(url);\n\n // Singleton mutex: stop currently active URL audio if singleton !== false\n const isSingleton = options?.singleton !== false;\n if (\n isSingleton &&\n this.activeUrlHowl &&\n this.activeUrlHowl !== howl &&\n this.activeUrlHowl.playing()\n ) {\n this.activeUrlHowl.stop();\n }\n\n // Overlap prevention on the same audio instance\n if (howl.playing()) {\n howl.stop();\n }\n\n if (options?.loop !== undefined) {\n howl.loop(options.loop);\n }\n\n if (typeof options?.volume === 'number') {\n howl.volume(options.volume);\n }\n\n if (isSingleton) {\n this.activeUrlHowl = howl;\n }\n\n // Clear handlers from previous plays to avoid stale/duplicate callbacks.\n howl.off('play');\n howl.off('end');\n howl.off('stop');\n howl.off('playerror');\n\n howl.once('play', (soundId: number) => {\n options?.onStart?.(soundId);\n this.emit('play', { type: 'url', url, soundId });\n });\n\n howl.once('end', (soundId: number) => {\n if (typeof options?.volume === 'number') {\n howl.volume(1);\n }\n options?.onEnd?.(soundId);\n this.emit('end', { type: 'url', url, soundId });\n if (this.activeUrlHowl === howl && !howl.loop()) {\n this.activeUrlHowl = null;\n }\n });\n\n howl.once('stop', (soundId: number) => {\n if (typeof options?.volume === 'number') {\n howl.volume(1);\n }\n options?.onStop?.(soundId);\n this.emit('stop', { type: 'url', url, soundId });\n if (this.activeUrlHowl === howl) {\n this.activeUrlHowl = null;\n }\n });\n\n howl.once('playerror', (soundId: number, error: unknown) => {\n options?.onError?.(soundId, error);\n this.emit('error', { type: 'url', url, soundId, error });\n if (this.activeUrlHowl === howl) {\n this.activeUrlHowl = null;\n }\n });\n\n return howl.play();\n }\n\n stopUrl(url: string): void {\n const howl = this.urlAudioCache.get(url);\n if (howl) {\n howl.stop();\n }\n }\n\n on(event: AudioEventType, handler: (payload: AudioEventPayload<K>) => void): EventSubscription {\n const set = this.listeners.get(event) ?? new Set<(payload: AudioEventPayload<K>) => void>();\n this.listeners.set(event, set);\n set.add(handler);\n return {\n destroy: () => {\n set.delete(handler);\n }\n };\n }\n\n protected emit(event: AudioEventType, payload: AudioEventPayload<K>): void {\n const set = this.listeners.get(event);\n if (set) {\n set.forEach((handler) => {\n try {\n handler(payload);\n } catch (err) {\n console.error(`[AudioManager] Error in event listener for ${event}:`, err);\n }\n });\n }\n }\n\n setGlobalVolume(volume: number): void {\n this.globalVolume = volume;\n this.HowlerInstance.volume(volume);\n }\n\n mute(muted: boolean): void {\n this.HowlerInstance.mute(muted);\n }\n\n stopAll(): void {\n this.HowlerInstance.stop();\n this.activeUrlHowl = null;\n }\n\n destroy(): void {\n this.effectCache.forEach((howl) => howl.unload());\n this.urlAudioCache.forEach((howl) => howl.unload());\n this.effectCache.clear();\n this.urlAudioCache.clear();\n this.preloadPromises.clear();\n this.listeners.clear();\n this.activeUrlHowl = null;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,53 @@
1
1
  {
2
2
  "name": "@jswork/howler-audio-manager",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.1",
4
+ "description": "Howler.js audio manager, enum-driven sounds for H5.",
5
+ "npmClient": "pnpm",
6
+ "main": "dist/index.cjs.js",
7
+ "module": "dist/index.esm.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "src",
11
+ "dist"
12
+ ],
13
+ "prettier": "@jswork/style-guide/prettier",
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "test": "bun test",
17
+ "release": "release-it"
18
+ },
19
+ "license": "MIT",
20
+ "peerDependencies": {
21
+ "howler": "^2.2.4"
22
+ },
23
+ "peerDependenciesMeta": {
24
+ "howler": {
25
+ "optional": false
26
+ }
27
+ },
28
+ "devDependencies": {
29
+ "@jswork/style-guide": "^1.0.3",
30
+ "@jswork/tsup-banner": "^1.0.4",
31
+ "@swc/core": "^1.5.5",
32
+ "@types/howler": "^2.2.12",
33
+ "@types/jest": "^29.5.12",
34
+ "@types/node": "^20.12.11",
35
+ "esbuild-plugin-replace": "^1.4.0",
36
+ "esbuild-plugin-umd-wrapper": "^3.0.0",
37
+ "howler": "^2.2.4",
38
+ "prettier": "^3.3.3",
39
+ "tsup": "^8.2.4",
40
+ "typescript": "^4.9.5"
41
+ },
42
+ "publishConfig": {
43
+ "access": "public",
44
+ "registry": "https://registry.npmjs.org"
45
+ },
46
+ "homepage": "https://js.work",
47
+ "keywords": [
48
+ "howler",
49
+ "audio-manager",
50
+ "h5-audio",
51
+ "sound-effects"
52
+ ]
53
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './types';
2
+ export { AudioManager } from './manager';
3
+ export { AudioManager as default } from './manager';