@hkdigital/lib-sveltekit 0.0.81 → 0.0.83
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/dist/classes/svelte/audio/AudioLoader.svelte.d.ts +30 -0
 - package/dist/classes/svelte/audio/AudioLoader.svelte.js +58 -0
 - package/dist/classes/svelte/audio/AudioScene.svelte.d.ts +52 -0
 - package/dist/classes/svelte/audio/AudioScene.svelte.js +282 -0
 - package/dist/classes/svelte/audio/mocks.d.ts +7 -0
 - package/dist/classes/svelte/audio/mocks.js +35 -0
 - package/dist/classes/svelte/final-state-machine/FiniteStateMachine.svelte.d.ts +50 -0
 - package/dist/classes/svelte/final-state-machine/FiniteStateMachine.svelte.js +133 -0
 - package/dist/classes/svelte/final-state-machine/index.d.ts +1 -0
 - package/dist/classes/svelte/final-state-machine/index.js +1 -0
 - package/dist/classes/svelte/image/ImageLoader.svelte.d.ts +8 -0
 - package/dist/classes/svelte/image/ImageLoader.svelte.js +12 -0
 - package/dist/classes/svelte/image/ImageVariantsLoader.svelte.d.ts +39 -0
 - package/dist/classes/svelte/image/ImageVariantsLoader.svelte.js +151 -0
 - package/dist/classes/svelte/image/index.d.ts +2 -0
 - package/dist/classes/svelte/image/index.js +4 -0
 - package/dist/classes/svelte/image/mocks.d.ts +7 -0
 - package/dist/classes/svelte/image/mocks.js +38 -0
 - package/dist/classes/svelte/image/typedef.d.ts +16 -0
 - package/dist/classes/svelte/image/typedef.js +10 -0
 - package/dist/classes/svelte/loading-state-machine/LoadingStateMachine.svelte.d.ts +12 -0
 - package/dist/classes/svelte/loading-state-machine/LoadingStateMachine.svelte.js +107 -0
 - package/dist/classes/svelte/loading-state-machine/constants.d.ts +12 -0
 - package/dist/classes/svelte/loading-state-machine/constants.js +16 -0
 - package/dist/classes/svelte/loading-state-machine/index.d.ts +2 -0
 - package/dist/classes/svelte/loading-state-machine/index.js +3 -0
 - package/dist/classes/svelte/network-loader/NetworkLoader.svelte.d.ts +85 -0
 - package/dist/classes/svelte/network-loader/NetworkLoader.svelte.js +295 -0
 - package/dist/classes/svelte/network-loader/constants.d.ts +2 -0
 - package/dist/classes/svelte/network-loader/constants.js +3 -0
 - package/dist/classes/svelte/network-loader/index.d.ts +2 -0
 - package/dist/classes/svelte/network-loader/index.js +3 -0
 - package/dist/components/image/ResponsiveImage.svelte +103 -0
 - package/dist/components/image/ResponsiveImage.svelte.d.ts +15 -0
 - package/dist/components/image/index.d.ts +4 -1
 - package/dist/components/image/index.js +5 -1
 - package/dist/types/imagetools.d.ts +16 -13
 - package/dist/types/imagetools.js +8 -0
 - package/dist/util/expect/arrays.d.ts +4 -0
 - package/dist/util/expect/arrays.js +6 -1
 - package/dist/util/http/response.js +1 -0
 - package/dist/util/svelte/wait/index.d.ts +15 -0
 - package/dist/util/svelte/wait/index.js +38 -0
 - package/package.json +3 -1
 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /**
         
     | 
| 
      
 2 
     | 
    
         
            +
             * AudioLoader instance
         
     | 
| 
      
 3 
     | 
    
         
            +
             * - Loads audio data from network into an ArrayBuffer
         
     | 
| 
      
 4 
     | 
    
         
            +
             * - Loaded data can be transferred to an AudioBufferSourceNode
         
     | 
| 
      
 5 
     | 
    
         
            +
             */
         
     | 
| 
      
 6 
     | 
    
         
            +
            export default class AudioLoader extends NetworkLoader {
         
     | 
| 
      
 7 
     | 
    
         
            +
                /**
         
     | 
| 
      
 8 
     | 
    
         
            +
                 * Get an AudioBufferSourceNode instance
         
     | 
| 
      
 9 
     | 
    
         
            +
                 *
         
     | 
| 
      
 10 
     | 
    
         
            +
                 * @note AudioBufferSourceNodes can play only once, a new source node
         
     | 
| 
      
 11 
     | 
    
         
            +
                 *       must be created otherwise
         
     | 
| 
      
 12 
     | 
    
         
            +
                 *
         
     | 
| 
      
 13 
     | 
    
         
            +
                 * @param {AudioContext} audioContext
         
     | 
| 
      
 14 
     | 
    
         
            +
                 *
         
     | 
| 
      
 15 
     | 
    
         
            +
                 * @returns {Promise<AudioBufferSourceNode>}
         
     | 
| 
      
 16 
     | 
    
         
            +
                 */
         
     | 
| 
      
 17 
     | 
    
         
            +
                getAudioBufferSourceNode(audioContext: AudioContext): Promise<AudioBufferSourceNode>;
         
     | 
| 
      
 18 
     | 
    
         
            +
                /**
         
     | 
| 
      
 19 
     | 
    
         
            +
                 * Gets data as AudioBuffer
         
     | 
| 
      
 20 
     | 
    
         
            +
                 * - Stores created AudioBuffer instance internally
         
     | 
| 
      
 21 
     | 
    
         
            +
                 * - Transfers data from internal ArrayBuffer, which will be detached
         
     | 
| 
      
 22 
     | 
    
         
            +
                 *
         
     | 
| 
      
 23 
     | 
    
         
            +
                 * @param {AudioContext} audioContext
         
     | 
| 
      
 24 
     | 
    
         
            +
                 *
         
     | 
| 
      
 25 
     | 
    
         
            +
                 * @returns {Promise<AudioBuffer>}
         
     | 
| 
      
 26 
     | 
    
         
            +
                 */
         
     | 
| 
      
 27 
     | 
    
         
            +
                getAudioBuffer(audioContext: AudioContext): Promise<AudioBuffer>;
         
     | 
| 
      
 28 
     | 
    
         
            +
                #private;
         
     | 
| 
      
 29 
     | 
    
         
            +
            }
         
     | 
| 
      
 30 
     | 
    
         
            +
            import { NetworkLoader } from '../network-loader/index.js';
         
     | 
| 
         @@ -0,0 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import {
         
     | 
| 
      
 2 
     | 
    
         
            +
              NetworkLoader,
         
     | 
| 
      
 3 
     | 
    
         
            +
              ERROR_NOT_LOADED,
         
     | 
| 
      
 4 
     | 
    
         
            +
              ERROR_TRANSFERRED
         
     | 
| 
      
 5 
     | 
    
         
            +
            } from '../network-loader/index.js';
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            /**
         
     | 
| 
      
 8 
     | 
    
         
            +
             * AudioLoader instance
         
     | 
| 
      
 9 
     | 
    
         
            +
             * - Loads audio data from network into an ArrayBuffer
         
     | 
| 
      
 10 
     | 
    
         
            +
             * - Loaded data can be transferred to an AudioBufferSourceNode
         
     | 
| 
      
 11 
     | 
    
         
            +
             */
         
     | 
| 
      
 12 
     | 
    
         
            +
            export default class AudioLoader extends NetworkLoader {
         
     | 
| 
      
 13 
     | 
    
         
            +
              /** @type {AudioBuffer|null} */
         
     | 
| 
      
 14 
     | 
    
         
            +
              #audioBuffer = null;
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              /**
         
     | 
| 
      
 17 
     | 
    
         
            +
               * Get an AudioBufferSourceNode instance
         
     | 
| 
      
 18 
     | 
    
         
            +
               *
         
     | 
| 
      
 19 
     | 
    
         
            +
               * @note AudioBufferSourceNodes can play only once, a new source node
         
     | 
| 
      
 20 
     | 
    
         
            +
               *       must be created otherwise
         
     | 
| 
      
 21 
     | 
    
         
            +
               *
         
     | 
| 
      
 22 
     | 
    
         
            +
               * @param {AudioContext} audioContext
         
     | 
| 
      
 23 
     | 
    
         
            +
               *
         
     | 
| 
      
 24 
     | 
    
         
            +
               * @returns {Promise<AudioBufferSourceNode>}
         
     | 
| 
      
 25 
     | 
    
         
            +
               */
         
     | 
| 
      
 26 
     | 
    
         
            +
              async getAudioBufferSourceNode(audioContext) {
         
     | 
| 
      
 27 
     | 
    
         
            +
                if (!this.#audioBuffer) {
         
     | 
| 
      
 28 
     | 
    
         
            +
                  this.#audioBuffer = await this.getAudioBuffer(audioContext);
         
     | 
| 
      
 29 
     | 
    
         
            +
                }
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                return new AudioBufferSourceNode(audioContext, {
         
     | 
| 
      
 32 
     | 
    
         
            +
                  buffer: this.#audioBuffer
         
     | 
| 
      
 33 
     | 
    
         
            +
                });
         
     | 
| 
      
 34 
     | 
    
         
            +
              }
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              /**
         
     | 
| 
      
 37 
     | 
    
         
            +
               * Gets data as AudioBuffer
         
     | 
| 
      
 38 
     | 
    
         
            +
               * - Stores created AudioBuffer instance internally
         
     | 
| 
      
 39 
     | 
    
         
            +
               * - Transfers data from internal ArrayBuffer, which will be detached
         
     | 
| 
      
 40 
     | 
    
         
            +
               *
         
     | 
| 
      
 41 
     | 
    
         
            +
               * @param {AudioContext} audioContext
         
     | 
| 
      
 42 
     | 
    
         
            +
               *
         
     | 
| 
      
 43 
     | 
    
         
            +
               * @returns {Promise<AudioBuffer>}
         
     | 
| 
      
 44 
     | 
    
         
            +
               */
         
     | 
| 
      
 45 
     | 
    
         
            +
              async getAudioBuffer(audioContext) {
         
     | 
| 
      
 46 
     | 
    
         
            +
                if (!this._buffer) {
         
     | 
| 
      
 47 
     | 
    
         
            +
                  throw new Error(ERROR_NOT_LOADED);
         
     | 
| 
      
 48 
     | 
    
         
            +
                }
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                if (this._buffer.detached) {
         
     | 
| 
      
 51 
     | 
    
         
            +
                  throw new Error(ERROR_TRANSFERRED);
         
     | 
| 
      
 52 
     | 
    
         
            +
                }
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                this.#audioBuffer = await audioContext.decodeAudioData(this._buffer);
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                return this.#audioBuffer;
         
     | 
| 
      
 57 
     | 
    
         
            +
              }
         
     | 
| 
      
 58 
     | 
    
         
            +
            } // end class
         
     | 
| 
         @@ -0,0 +1,52 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /**
         
     | 
| 
      
 2 
     | 
    
         
            +
             * @typedef {object} SourceConfig
         
     | 
| 
      
 3 
     | 
    
         
            +
             * // property ...
         
     | 
| 
      
 4 
     | 
    
         
            +
             */
         
     | 
| 
      
 5 
     | 
    
         
            +
            /**
         
     | 
| 
      
 6 
     | 
    
         
            +
             * @typedef {object} MemorySource
         
     | 
| 
      
 7 
     | 
    
         
            +
             * @property {string} label
         
     | 
| 
      
 8 
     | 
    
         
            +
             * @property {AudioLoader} audioLoader
         
     | 
| 
      
 9 
     | 
    
         
            +
             * @property {SourceConfig} [config]
         
     | 
| 
      
 10 
     | 
    
         
            +
             */
         
     | 
| 
      
 11 
     | 
    
         
            +
            export default class AudioScene {
         
     | 
| 
      
 12 
     | 
    
         
            +
                state: string;
         
     | 
| 
      
 13 
     | 
    
         
            +
                loaded: boolean;
         
     | 
| 
      
 14 
     | 
    
         
            +
                destroy(): void;
         
     | 
| 
      
 15 
     | 
    
         
            +
                /**
         
     | 
| 
      
 16 
     | 
    
         
            +
                 * Add in-memory audio source
         
     | 
| 
      
 17 
     | 
    
         
            +
                 * - Uses an AudioLoader instance to load audio data from network
         
     | 
| 
      
 18 
     | 
    
         
            +
                 *
         
     | 
| 
      
 19 
     | 
    
         
            +
                 * @param {object} _
         
     | 
| 
      
 20 
     | 
    
         
            +
                 * @param {string} _.label
         
     | 
| 
      
 21 
     | 
    
         
            +
                 * @param {string} _.url
         
     | 
| 
      
 22 
     | 
    
         
            +
                 * @param {SourceConfig} [_.config]
         
     | 
| 
      
 23 
     | 
    
         
            +
                 */
         
     | 
| 
      
 24 
     | 
    
         
            +
                defineMemorySource({ label, url, config }: {
         
     | 
| 
      
 25 
     | 
    
         
            +
                    label: string;
         
     | 
| 
      
 26 
     | 
    
         
            +
                    url: string;
         
     | 
| 
      
 27 
     | 
    
         
            +
                    config?: SourceConfig;
         
     | 
| 
      
 28 
     | 
    
         
            +
                }): void;
         
     | 
| 
      
 29 
     | 
    
         
            +
                /**
         
     | 
| 
      
 30 
     | 
    
         
            +
                 * Start loading all audio sources
         
     | 
| 
      
 31 
     | 
    
         
            +
                 *
         
     | 
| 
      
 32 
     | 
    
         
            +
                 * @param {AudioContext} audioContext
         
     | 
| 
      
 33 
     | 
    
         
            +
                 */
         
     | 
| 
      
 34 
     | 
    
         
            +
                load(audioContext: AudioContext): void;
         
     | 
| 
      
 35 
     | 
    
         
            +
                /**
         
     | 
| 
      
 36 
     | 
    
         
            +
                 * Get a source that can be used to plat the audio once
         
     | 
| 
      
 37 
     | 
    
         
            +
                 *
         
     | 
| 
      
 38 
     | 
    
         
            +
                 * @param {string} label
         
     | 
| 
      
 39 
     | 
    
         
            +
                 */
         
     | 
| 
      
 40 
     | 
    
         
            +
                getSourceNode(label: string): Promise<AudioBufferSourceNode>;
         
     | 
| 
      
 41 
     | 
    
         
            +
                #private;
         
     | 
| 
      
 42 
     | 
    
         
            +
            }
         
     | 
| 
      
 43 
     | 
    
         
            +
            /**
         
     | 
| 
      
 44 
     | 
    
         
            +
             * // property ...
         
     | 
| 
      
 45 
     | 
    
         
            +
             */
         
     | 
| 
      
 46 
     | 
    
         
            +
            export type SourceConfig = object;
         
     | 
| 
      
 47 
     | 
    
         
            +
            export type MemorySource = {
         
     | 
| 
      
 48 
     | 
    
         
            +
                label: string;
         
     | 
| 
      
 49 
     | 
    
         
            +
                audioLoader: AudioLoader;
         
     | 
| 
      
 50 
     | 
    
         
            +
                config?: SourceConfig;
         
     | 
| 
      
 51 
     | 
    
         
            +
            };
         
     | 
| 
      
 52 
     | 
    
         
            +
            import AudioLoader from './AudioLoader.svelte.js';
         
     | 
| 
         @@ -0,0 +1,282 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import * as expect from '@hkdigital/lib-sveltekit/util/expect/index.js';
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            import {
         
     | 
| 
      
 4 
     | 
    
         
            +
              LoadingStateMachine,
         
     | 
| 
      
 5 
     | 
    
         
            +
              STATE_INITIAL,
         
     | 
| 
      
 6 
     | 
    
         
            +
              STATE_LOADING,
         
     | 
| 
      
 7 
     | 
    
         
            +
              STATE_UNLOADING,
         
     | 
| 
      
 8 
     | 
    
         
            +
              STATE_LOADED,
         
     | 
| 
      
 9 
     | 
    
         
            +
              STATE_CANCELLED,
         
     | 
| 
      
 10 
     | 
    
         
            +
              STATE_ERROR,
         
     | 
| 
      
 11 
     | 
    
         
            +
              LOAD,
         
     | 
| 
      
 12 
     | 
    
         
            +
              // CANCEL,
         
     | 
| 
      
 13 
     | 
    
         
            +
              ERROR,
         
     | 
| 
      
 14 
     | 
    
         
            +
              LOADED,
         
     | 
| 
      
 15 
     | 
    
         
            +
              UNLOAD,
         
     | 
| 
      
 16 
     | 
    
         
            +
              INITIAL
         
     | 
| 
      
 17 
     | 
    
         
            +
            } from '../loading-state-machine/index.js';
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            import AudioLoader from './AudioLoader.svelte.js';
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            /**
         
     | 
| 
      
 22 
     | 
    
         
            +
             * @typedef {object} SourceConfig
         
     | 
| 
      
 23 
     | 
    
         
            +
             * // property ...
         
     | 
| 
      
 24 
     | 
    
         
            +
             */
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            /**
         
     | 
| 
      
 27 
     | 
    
         
            +
             * @typedef {object} MemorySource
         
     | 
| 
      
 28 
     | 
    
         
            +
             * @property {string} label
         
     | 
| 
      
 29 
     | 
    
         
            +
             * @property {AudioLoader} audioLoader
         
     | 
| 
      
 30 
     | 
    
         
            +
             * @property {SourceConfig} [config]
         
     | 
| 
      
 31 
     | 
    
         
            +
             */
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            export default class AudioScene {
         
     | 
| 
      
 34 
     | 
    
         
            +
              #state = new LoadingStateMachine();
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              // @note this exported state is set by $effect's
         
     | 
| 
      
 37 
     | 
    
         
            +
              state = $state(STATE_INITIAL);
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              // @note this exported state is set by $effect's
         
     | 
| 
      
 40 
     | 
    
         
            +
              loaded = $derived.by(() => {
         
     | 
| 
      
 41 
     | 
    
         
            +
                return this.state === STATE_LOADED;
         
     | 
| 
      
 42 
     | 
    
         
            +
              });
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              /** @type {AudioContext|null} */
         
     | 
| 
      
 45 
     | 
    
         
            +
              #audioContext = null;
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              /** @type {MemorySource[]} */
         
     | 
| 
      
 48 
     | 
    
         
            +
              #memorySources = $state([]);
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              #progress = $derived.by(() => {
         
     | 
| 
      
 51 
     | 
    
         
            +
                // console.log('update progress');
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                let totalSize = 0;
         
     | 
| 
      
 54 
     | 
    
         
            +
                let totalBytesLoaded = 0;
         
     | 
| 
      
 55 
     | 
    
         
            +
                let sourcesLoaded = 0;
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                const sources = this.#memorySources;
         
     | 
| 
      
 58 
     | 
    
         
            +
                const numberOfSources = sources.length;
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                for (let j = 0; j < numberOfSources; j++) {
         
     | 
| 
      
 61 
     | 
    
         
            +
                  const source = sources[j];
         
     | 
| 
      
 62 
     | 
    
         
            +
                  const { audioLoader } = source;
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  const { bytesLoaded, size, loaded } = audioLoader.progress;
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                  totalSize += size;
         
     | 
| 
      
 67 
     | 
    
         
            +
                  totalBytesLoaded += bytesLoaded;
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  if (loaded) {
         
     | 
| 
      
 70 
     | 
    
         
            +
                    sourcesLoaded++;
         
     | 
| 
      
 71 
     | 
    
         
            +
                  }
         
     | 
| 
      
 72 
     | 
    
         
            +
                } // end for
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                return {
         
     | 
| 
      
 75 
     | 
    
         
            +
                  totalBytesLoaded,
         
     | 
| 
      
 76 
     | 
    
         
            +
                  totalSize,
         
     | 
| 
      
 77 
     | 
    
         
            +
                  sourcesLoaded,
         
     | 
| 
      
 78 
     | 
    
         
            +
                  numberOfSources
         
     | 
| 
      
 79 
     | 
    
         
            +
                };
         
     | 
| 
      
 80 
     | 
    
         
            +
              });
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
              /**
         
     | 
| 
      
 83 
     | 
    
         
            +
               * Construct AudioScene
         
     | 
| 
      
 84 
     | 
    
         
            +
               *
         
     | 
| 
      
 85 
     | 
    
         
            +
               * @param {object} _
         
     | 
| 
      
 86 
     | 
    
         
            +
               * @param {AudioContext} _.audioContext
         
     | 
| 
      
 87 
     | 
    
         
            +
               */
         
     | 
| 
      
 88 
     | 
    
         
            +
              constructor() {
         
     | 
| 
      
 89 
     | 
    
         
            +
                const state = this.#state;
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                $effect(() => {
         
     | 
| 
      
 92 
     | 
    
         
            +
                  if (state.current === STATE_LOADING) {
         
     | 
| 
      
 93 
     | 
    
         
            +
                    // console.log(
         
     | 
| 
      
 94 
     | 
    
         
            +
                    //   'progress',
         
     | 
| 
      
 95 
     | 
    
         
            +
                    //   JSON.stringify($state.snapshot(this.#progress))
         
     | 
| 
      
 96 
     | 
    
         
            +
                    // );
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                    const { sourcesLoaded, numberOfSources } = this.#progress;
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                    if (sourcesLoaded === numberOfSources) {
         
     | 
| 
      
 101 
     | 
    
         
            +
                      console.log(`All [${numberOfSources}] sources loaded`);
         
     | 
| 
      
 102 
     | 
    
         
            +
                      this.#state.send(LOADED);
         
     | 
| 
      
 103 
     | 
    
         
            +
                    }
         
     | 
| 
      
 104 
     | 
    
         
            +
                  }
         
     | 
| 
      
 105 
     | 
    
         
            +
                });
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                $effect(() => {
         
     | 
| 
      
 108 
     | 
    
         
            +
                  switch (state.current) {
         
     | 
| 
      
 109 
     | 
    
         
            +
                    case STATE_LOADING:
         
     | 
| 
      
 110 
     | 
    
         
            +
                      {
         
     | 
| 
      
 111 
     | 
    
         
            +
                        console.log('AudioScene:loading');
         
     | 
| 
      
 112 
     | 
    
         
            +
                        this.#startLoading();
         
     | 
| 
      
 113 
     | 
    
         
            +
                      }
         
     | 
| 
      
 114 
     | 
    
         
            +
                      break;
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                    case STATE_UNLOADING:
         
     | 
| 
      
 117 
     | 
    
         
            +
                      {
         
     | 
| 
      
 118 
     | 
    
         
            +
                        // console.log('AudioScene:unloading');
         
     | 
| 
      
 119 
     | 
    
         
            +
                        // this.#startUnLoading();
         
     | 
| 
      
 120 
     | 
    
         
            +
                      }
         
     | 
| 
      
 121 
     | 
    
         
            +
                      break;
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                    case STATE_LOADED:
         
     | 
| 
      
 124 
     | 
    
         
            +
                      {
         
     | 
| 
      
 125 
     | 
    
         
            +
                        console.log('AudioScene:loaded');
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                        // tODO
         
     | 
| 
      
 128 
     | 
    
         
            +
                        // this.#abortLoading = null;
         
     | 
| 
      
 129 
     | 
    
         
            +
                      }
         
     | 
| 
      
 130 
     | 
    
         
            +
                      break;
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                    case STATE_CANCELLED:
         
     | 
| 
      
 133 
     | 
    
         
            +
                      {
         
     | 
| 
      
 134 
     | 
    
         
            +
                        // console.log('AudioScene:cancelled');
         
     | 
| 
      
 135 
     | 
    
         
            +
                        // TODO
         
     | 
| 
      
 136 
     | 
    
         
            +
                      }
         
     | 
| 
      
 137 
     | 
    
         
            +
                      break;
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                    case STATE_ERROR:
         
     | 
| 
      
 140 
     | 
    
         
            +
                      {
         
     | 
| 
      
 141 
     | 
    
         
            +
                        console.log('AudioScene:error', state.error);
         
     | 
| 
      
 142 
     | 
    
         
            +
                      }
         
     | 
| 
      
 143 
     | 
    
         
            +
                      break;
         
     | 
| 
      
 144 
     | 
    
         
            +
                  } // end switch
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                  this.state = state.current;
         
     | 
| 
      
 147 
     | 
    
         
            +
                });
         
     | 
| 
      
 148 
     | 
    
         
            +
              }
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
              destroy() {
         
     | 
| 
      
 151 
     | 
    
         
            +
                // TODO: disconnect all audio sources?
         
     | 
| 
      
 152 
     | 
    
         
            +
                // TODO: Unload AUdioLoaders?
         
     | 
| 
      
 153 
     | 
    
         
            +
              }
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
              /**
         
     | 
| 
      
 156 
     | 
    
         
            +
               * Add in-memory audio source
         
     | 
| 
      
 157 
     | 
    
         
            +
               * - Uses an AudioLoader instance to load audio data from network
         
     | 
| 
      
 158 
     | 
    
         
            +
               *
         
     | 
| 
      
 159 
     | 
    
         
            +
               * @param {object} _
         
     | 
| 
      
 160 
     | 
    
         
            +
               * @param {string} _.label
         
     | 
| 
      
 161 
     | 
    
         
            +
               * @param {string} _.url
         
     | 
| 
      
 162 
     | 
    
         
            +
               * @param {SourceConfig} [_.config]
         
     | 
| 
      
 163 
     | 
    
         
            +
               */
         
     | 
| 
      
 164 
     | 
    
         
            +
              defineMemorySource({ label, url, config }) {
         
     | 
| 
      
 165 
     | 
    
         
            +
                expect.notEmptyString(label);
         
     | 
| 
      
 166 
     | 
    
         
            +
                expect.notEmptyString(url);
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                const audioLoader = new AudioLoader({ url });
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                this.#memorySources.push({ label, audioLoader, config });
         
     | 
| 
      
 171 
     | 
    
         
            +
              }
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
              /**
         
     | 
| 
      
 174 
     | 
    
         
            +
               * Start loading all audio sources
         
     | 
| 
      
 175 
     | 
    
         
            +
               *
         
     | 
| 
      
 176 
     | 
    
         
            +
               * @param {AudioContext} audioContext
         
     | 
| 
      
 177 
     | 
    
         
            +
               */
         
     | 
| 
      
 178 
     | 
    
         
            +
              load(audioContext) {
         
     | 
| 
      
 179 
     | 
    
         
            +
                this.#audioContext = audioContext;
         
     | 
| 
      
 180 
     | 
    
         
            +
                // console.log(123);
         
     | 
| 
      
 181 
     | 
    
         
            +
                this.#state.send(LOAD);
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                // FIXME: in unit test when moved to startloading it hangs!
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                for (const { audioLoader } of this.#memorySources) {
         
     | 
| 
      
 186 
     | 
    
         
            +
                  audioLoader.load();
         
     | 
| 
      
 187 
     | 
    
         
            +
                }
         
     | 
| 
      
 188 
     | 
    
         
            +
              }
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
              async #startLoading() {
         
     | 
| 
      
 191 
     | 
    
         
            +
                console.log('#startLoading');
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
                // FIXME: in unit test when moved to startloading it hangs!
         
     | 
| 
      
 194 
     | 
    
         
            +
                // for (const { audioLoader } of this.#memorySources) {
         
     | 
| 
      
 195 
     | 
    
         
            +
                //   audioLoader.load();
         
     | 
| 
      
 196 
     | 
    
         
            +
                // }
         
     | 
| 
      
 197 
     | 
    
         
            +
              }
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
              /**
         
     | 
| 
      
 200 
     | 
    
         
            +
               * Get a source that can be used to plat the audio once
         
     | 
| 
      
 201 
     | 
    
         
            +
               *
         
     | 
| 
      
 202 
     | 
    
         
            +
               * @param {string} label
         
     | 
| 
      
 203 
     | 
    
         
            +
               */
         
     | 
| 
      
 204 
     | 
    
         
            +
              async getSourceNode(label) {
         
     | 
| 
      
 205 
     | 
    
         
            +
                // @note Gain setup
         
     | 
| 
      
 206 
     | 
    
         
            +
                // https://stackoverflow.com/questions/46203191/should-i-disconnect-nodes-that-cant-be-used-anymore
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
                const { audioLoader /*, config */ } = this.#getMemorySource(label);
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
                if (!audioLoader.loaded) {
         
     | 
| 
      
 211 
     | 
    
         
            +
                  throw new Error(`Source [${label}] has not been loaded yet`);
         
     | 
| 
      
 212 
     | 
    
         
            +
                }
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
                const sourceNode = await audioLoader.getAudioBufferSourceNode(
         
     | 
| 
      
 215 
     | 
    
         
            +
                  // @ts-ignore
         
     | 
| 
      
 216 
     | 
    
         
            +
                  this.#audioContext
         
     | 
| 
      
 217 
     | 
    
         
            +
                );
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
                // @ts-ignore
         
     | 
| 
      
 220 
     | 
    
         
            +
                sourceNode.connect(this.#audioContext.destination);
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
                // Clean up
         
     | 
| 
      
 223 
     | 
    
         
            +
                sourceNode.onended = () => {
         
     | 
| 
      
 224 
     | 
    
         
            +
                  // console.log(`Source [${label}] ended `);
         
     | 
| 
      
 225 
     | 
    
         
            +
                  sourceNode.disconnect();
         
     | 
| 
      
 226 
     | 
    
         
            +
                };
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
                return sourceNode;
         
     | 
| 
      
 229 
     | 
    
         
            +
              }
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
              /**
         
     | 
| 
      
 232 
     | 
    
         
            +
               * Get memory source
         
     | 
| 
      
 233 
     | 
    
         
            +
               *
         
     | 
| 
      
 234 
     | 
    
         
            +
               * @param {string} label
         
     | 
| 
      
 235 
     | 
    
         
            +
               *
         
     | 
| 
      
 236 
     | 
    
         
            +
               * @returns {MemorySource}
         
     | 
| 
      
 237 
     | 
    
         
            +
               */
         
     | 
| 
      
 238 
     | 
    
         
            +
              #getMemorySource(label) {
         
     | 
| 
      
 239 
     | 
    
         
            +
                for (const source of this.#memorySources) {
         
     | 
| 
      
 240 
     | 
    
         
            +
                  if (label === source.label) {
         
     | 
| 
      
 241 
     | 
    
         
            +
                    return source;
         
     | 
| 
      
 242 
     | 
    
         
            +
                  }
         
     | 
| 
      
 243 
     | 
    
         
            +
                }
         
     | 
| 
      
 244 
     | 
    
         
            +
             
     | 
| 
      
 245 
     | 
    
         
            +
                throw new Error(`Source [${label}] has not been defined`);
         
     | 
| 
      
 246 
     | 
    
         
            +
              }
         
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
              // connect
         
     | 
| 
      
 249 
     | 
    
         
            +
              // play
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
              // source.connect(audioContext.destination);
         
     | 
| 
      
 252 
     | 
    
         
            +
              // source.loop = true;
         
     | 
| 
      
 253 
     | 
    
         
            +
              // source.start();
         
     | 
| 
      
 254 
     | 
    
         
            +
             
     | 
| 
      
 255 
     | 
    
         
            +
              // /**
         
     | 
| 
      
 256 
     | 
    
         
            +
              //  * Get the source identified by the specified label
         
     | 
| 
      
 257 
     | 
    
         
            +
              //  *
         
     | 
| 
      
 258 
     | 
    
         
            +
              //  * @param {string} label
         
     | 
| 
      
 259 
     | 
    
         
            +
              //  */
         
     | 
| 
      
 260 
     | 
    
         
            +
              // async getBufferSourceNode(label) {
         
     | 
| 
      
 261 
     | 
    
         
            +
              //   // expect.notEmptyString( label );
         
     | 
| 
      
 262 
     | 
    
         
            +
             
     | 
| 
      
 263 
     | 
    
         
            +
              //   for (const source of this.#memorySources) {
         
     | 
| 
      
 264 
     | 
    
         
            +
              //     if (label === source.label) {
         
     | 
| 
      
 265 
     | 
    
         
            +
              //       if (!source.bufferSourceNode) {
         
     | 
| 
      
 266 
     | 
    
         
            +
              //         source.bufferSourceNode =
         
     | 
| 
      
 267 
     | 
    
         
            +
              //           await source.AudioLoader.transferToBufferSource(this.#audioContext);
         
     | 
| 
      
 268 
     | 
    
         
            +
              //       }
         
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
      
 270 
     | 
    
         
            +
              //       return source.bufferSourceNode;
         
     | 
| 
      
 271 
     | 
    
         
            +
              //     }
         
     | 
| 
      
 272 
     | 
    
         
            +
              //   }
         
     | 
| 
      
 273 
     | 
    
         
            +
              // }
         
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
              // async connectSourceToDestination(label) {
         
     | 
| 
      
 276 
     | 
    
         
            +
              //   const source = await this.getBufferSourceNode(label);
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
      
 278 
     | 
    
         
            +
              //   if (source) {
         
     | 
| 
      
 279 
     | 
    
         
            +
              //     source.connect(this.#audioContext.destination);
         
     | 
| 
      
 280 
     | 
    
         
            +
              //   }
         
     | 
| 
      
 281 
     | 
    
         
            +
              // }
         
     | 
| 
      
 282 
     | 
    
         
            +
            }
         
     | 
| 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import { CONTENT_TYPE, CONTENT_LENGTH } from '@hkdigital/lib-sveltekit/constants/http/index.js';
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            import { AUDIO_WAV } from '@hkdigital/lib-sveltekit/constants/mime/audio.js';
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            // import MockWav from './tiny-silence.wav?raw';
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            const BASE64_WAV =
         
     | 
| 
      
 8 
     | 
    
         
            +
            	'UklGRnwAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YVgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            /**
         
     | 
| 
      
 11 
     | 
    
         
            +
             * Create a response value that can be used by a mocked
         
     | 
| 
      
 12 
     | 
    
         
            +
             * fetch function
         
     | 
| 
      
 13 
     | 
    
         
            +
             *
         
     | 
| 
      
 14 
     | 
    
         
            +
             * @returns {Response}
         
     | 
| 
      
 15 
     | 
    
         
            +
             */
         
     | 
| 
      
 16 
     | 
    
         
            +
            export function createWavResponse(/* data , options */) {
         
     | 
| 
      
 17 
     | 
    
         
            +
            	// @note encode as Uint8Array to get the proper byte size of data
         
     | 
| 
      
 18 
     | 
    
         
            +
            	// const bytes = new TextEncoder().encode(MockWav);
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            	const binaryString = atob(BASE64_WAV);
         
     | 
| 
      
 21 
     | 
    
         
            +
            	const bytes = new Uint8Array(binaryString.length);
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            	for (let i = 0; i < binaryString.length; i++) {
         
     | 
| 
      
 24 
     | 
    
         
            +
            		bytes[i] = binaryString.charCodeAt(i);
         
     | 
| 
      
 25 
     | 
    
         
            +
            	}
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            	const response = new Response(bytes, {
         
     | 
| 
      
 28 
     | 
    
         
            +
            		headers: new Headers({
         
     | 
| 
      
 29 
     | 
    
         
            +
            			[CONTENT_TYPE]: AUDIO_WAV,
         
     | 
| 
      
 30 
     | 
    
         
            +
            			[CONTENT_LENGTH]: String(bytes.length)
         
     | 
| 
      
 31 
     | 
    
         
            +
            		})
         
     | 
| 
      
 32 
     | 
    
         
            +
            	});
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            	return response;
         
     | 
| 
      
 35 
     | 
    
         
            +
            }
         
     | 
| 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /**
         
     | 
| 
      
 2 
     | 
    
         
            +
             * Initial code borrowed from:
         
     | 
| 
      
 3 
     | 
    
         
            +
             *
         
     | 
| 
      
 4 
     | 
    
         
            +
             * @see {@link https://runed.dev/docs/utilities/finite-state-machine}
         
     | 
| 
      
 5 
     | 
    
         
            +
             */
         
     | 
| 
      
 6 
     | 
    
         
            +
            /**
         
     | 
| 
      
 7 
     | 
    
         
            +
             * Check if the value is valid meta data
         
     | 
| 
      
 8 
     | 
    
         
            +
             *
         
     | 
| 
      
 9 
     | 
    
         
            +
             * @param {any} meta
         
     | 
| 
      
 10 
     | 
    
         
            +
             */
         
     | 
| 
      
 11 
     | 
    
         
            +
            export function isLifecycleFnMeta(meta: any): boolean;
         
     | 
| 
      
 12 
     | 
    
         
            +
            /**
         
     | 
| 
      
 13 
     | 
    
         
            +
             * Defines a Finite State Machine
         
     | 
| 
      
 14 
     | 
    
         
            +
             */
         
     | 
| 
      
 15 
     | 
    
         
            +
            export default class FiniteStateMachine {
         
     | 
| 
      
 16 
     | 
    
         
            +
                /**
         
     | 
| 
      
 17 
     | 
    
         
            +
                 * Constructor
         
     | 
| 
      
 18 
     | 
    
         
            +
                 *
         
     | 
| 
      
 19 
     | 
    
         
            +
                 * @param {string} initial
         
     | 
| 
      
 20 
     | 
    
         
            +
                 * @param {{ [key: string]: { [key: string]: (string|((...args: any[])=>void)) } }} states
         
     | 
| 
      
 21 
     | 
    
         
            +
                 */
         
     | 
| 
      
 22 
     | 
    
         
            +
                constructor(initial: string, states: {
         
     | 
| 
      
 23 
     | 
    
         
            +
                    [key: string]: {
         
     | 
| 
      
 24 
     | 
    
         
            +
                        [key: string]: (string | ((...args: any[]) => void));
         
     | 
| 
      
 25 
     | 
    
         
            +
                    };
         
     | 
| 
      
 26 
     | 
    
         
            +
                });
         
     | 
| 
      
 27 
     | 
    
         
            +
                states: {
         
     | 
| 
      
 28 
     | 
    
         
            +
                    [key: string]: {
         
     | 
| 
      
 29 
     | 
    
         
            +
                        [key: string]: string | ((...args: any[]) => void);
         
     | 
| 
      
 30 
     | 
    
         
            +
                    };
         
     | 
| 
      
 31 
     | 
    
         
            +
                };
         
     | 
| 
      
 32 
     | 
    
         
            +
                /**
         
     | 
| 
      
 33 
     | 
    
         
            +
                 * Triggers a new event and returns the new state.
         
     | 
| 
      
 34 
     | 
    
         
            +
                 *
         
     | 
| 
      
 35 
     | 
    
         
            +
                 * @param {string} event
         
     | 
| 
      
 36 
     | 
    
         
            +
                 * @param {any[]} args
         
     | 
| 
      
 37 
     | 
    
         
            +
                 */
         
     | 
| 
      
 38 
     | 
    
         
            +
                send(event: string, ...args: any[]): any;
         
     | 
| 
      
 39 
     | 
    
         
            +
                /**
         
     | 
| 
      
 40 
     | 
    
         
            +
                 * Debounces the triggering of an event.
         
     | 
| 
      
 41 
     | 
    
         
            +
                 *
         
     | 
| 
      
 42 
     | 
    
         
            +
                 * @param {number} wait
         
     | 
| 
      
 43 
     | 
    
         
            +
                 * @param {string} event
         
     | 
| 
      
 44 
     | 
    
         
            +
                 * @param {any[]} args
         
     | 
| 
      
 45 
     | 
    
         
            +
                 */
         
     | 
| 
      
 46 
     | 
    
         
            +
                debounce(wait: number, event: string, ...args: any[]): Promise<any>;
         
     | 
| 
      
 47 
     | 
    
         
            +
                /** The current state. */
         
     | 
| 
      
 48 
     | 
    
         
            +
                get current(): any;
         
     | 
| 
      
 49 
     | 
    
         
            +
                #private;
         
     | 
| 
      
 50 
     | 
    
         
            +
            }
         
     | 
| 
         @@ -0,0 +1,133 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /**
         
     | 
| 
      
 2 
     | 
    
         
            +
             * Initial code borrowed from:
         
     | 
| 
      
 3 
     | 
    
         
            +
             *
         
     | 
| 
      
 4 
     | 
    
         
            +
             * @see {@link https://runed.dev/docs/utilities/finite-state-machine}
         
     | 
| 
      
 5 
     | 
    
         
            +
             */
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            /**
         
     | 
| 
      
 8 
     | 
    
         
            +
             * Check if the value is valid meta data
         
     | 
| 
      
 9 
     | 
    
         
            +
             *
         
     | 
| 
      
 10 
     | 
    
         
            +
             * @param {any} meta
         
     | 
| 
      
 11 
     | 
    
         
            +
             */
         
     | 
| 
      
 12 
     | 
    
         
            +
            export function isLifecycleFnMeta(meta) {
         
     | 
| 
      
 13 
     | 
    
         
            +
              return (
         
     | 
| 
      
 14 
     | 
    
         
            +
                !!meta &&
         
     | 
| 
      
 15 
     | 
    
         
            +
                typeof meta === 'object' &&
         
     | 
| 
      
 16 
     | 
    
         
            +
                'to' in meta &&
         
     | 
| 
      
 17 
     | 
    
         
            +
                'from' in meta &&
         
     | 
| 
      
 18 
     | 
    
         
            +
                'event' in meta &&
         
     | 
| 
      
 19 
     | 
    
         
            +
                'args' in meta
         
     | 
| 
      
 20 
     | 
    
         
            +
              );
         
     | 
| 
      
 21 
     | 
    
         
            +
            }
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            /**
         
     | 
| 
      
 24 
     | 
    
         
            +
             * Defines a Finite State Machine
         
     | 
| 
      
 25 
     | 
    
         
            +
             */
         
     | 
| 
      
 26 
     | 
    
         
            +
            export default class FiniteStateMachine {
         
     | 
| 
      
 27 
     | 
    
         
            +
              #current = $state();
         
     | 
| 
      
 28 
     | 
    
         
            +
              states;
         
     | 
| 
      
 29 
     | 
    
         
            +
              #timeout = {};
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              /**
         
     | 
| 
      
 32 
     | 
    
         
            +
               * Constructor
         
     | 
| 
      
 33 
     | 
    
         
            +
               *
         
     | 
| 
      
 34 
     | 
    
         
            +
               * @param {string} initial
         
     | 
| 
      
 35 
     | 
    
         
            +
               * @param {{ [key: string]: { [key: string]: (string|((...args: any[])=>void)) } }} states
         
     | 
| 
      
 36 
     | 
    
         
            +
               */
         
     | 
| 
      
 37 
     | 
    
         
            +
              constructor(initial, states) {
         
     | 
| 
      
 38 
     | 
    
         
            +
                this.#current = initial;
         
     | 
| 
      
 39 
     | 
    
         
            +
                this.states = states;
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                // synthetically trigger _enter for the initial state.
         
     | 
| 
      
 42 
     | 
    
         
            +
                this.#dispatch('_enter', {
         
     | 
| 
      
 43 
     | 
    
         
            +
                  from: null,
         
     | 
| 
      
 44 
     | 
    
         
            +
                  to: initial,
         
     | 
| 
      
 45 
     | 
    
         
            +
                  event: null,
         
     | 
| 
      
 46 
     | 
    
         
            +
                  args: []
         
     | 
| 
      
 47 
     | 
    
         
            +
                });
         
     | 
| 
      
 48 
     | 
    
         
            +
              }
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              /**
         
     | 
| 
      
 51 
     | 
    
         
            +
               * Transition to new state
         
     | 
| 
      
 52 
     | 
    
         
            +
               *
         
     | 
| 
      
 53 
     | 
    
         
            +
               * @param {string} newState
         
     | 
| 
      
 54 
     | 
    
         
            +
               * @param {string} event
         
     | 
| 
      
 55 
     | 
    
         
            +
               * @param {any[]} [args]
         
     | 
| 
      
 56 
     | 
    
         
            +
               */
         
     | 
| 
      
 57 
     | 
    
         
            +
              #transition(newState, event, args) {
         
     | 
| 
      
 58 
     | 
    
         
            +
                const metadata = { from: this.#current, to: newState, event, args };
         
     | 
| 
      
 59 
     | 
    
         
            +
                this.#dispatch('_exit', metadata);
         
     | 
| 
      
 60 
     | 
    
         
            +
                this.#current = newState;
         
     | 
| 
      
 61 
     | 
    
         
            +
                this.#dispatch('_enter', metadata);
         
     | 
| 
      
 62 
     | 
    
         
            +
              }
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
              /**
         
     | 
| 
      
 65 
     | 
    
         
            +
               * Dispatch an event
         
     | 
| 
      
 66 
     | 
    
         
            +
               *
         
     | 
| 
      
 67 
     | 
    
         
            +
               * @param {string} event
         
     | 
| 
      
 68 
     | 
    
         
            +
               * @param {any[]} args
         
     | 
| 
      
 69 
     | 
    
         
            +
               */
         
     | 
| 
      
 70 
     | 
    
         
            +
              #dispatch(event, ...args) {
         
     | 
| 
      
 71 
     | 
    
         
            +
                const action =
         
     | 
| 
      
 72 
     | 
    
         
            +
                  this.states[this.#current]?.[event] ?? this.states['*']?.[event];
         
     | 
| 
      
 73 
     | 
    
         
            +
                if (action instanceof Function) {
         
     | 
| 
      
 74 
     | 
    
         
            +
                  if (event === '_enter' || event === '_exit') {
         
     | 
| 
      
 75 
     | 
    
         
            +
                    if (isLifecycleFnMeta(args[0])) {
         
     | 
| 
      
 76 
     | 
    
         
            +
                      action(args[0]);
         
     | 
| 
      
 77 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 78 
     | 
    
         
            +
                      console.warn(
         
     | 
| 
      
 79 
     | 
    
         
            +
                        'Invalid metadata passed to lifecycle function of the FSM.'
         
     | 
| 
      
 80 
     | 
    
         
            +
                      );
         
     | 
| 
      
 81 
     | 
    
         
            +
                    }
         
     | 
| 
      
 82 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 83 
     | 
    
         
            +
                    return action(...args);
         
     | 
| 
      
 84 
     | 
    
         
            +
                  }
         
     | 
| 
      
 85 
     | 
    
         
            +
                } else if (typeof action === 'string') {
         
     | 
| 
      
 86 
     | 
    
         
            +
                  return action;
         
     | 
| 
      
 87 
     | 
    
         
            +
                } else if (event !== '_enter' && event !== '_exit') {
         
     | 
| 
      
 88 
     | 
    
         
            +
                  console.warn(
         
     | 
| 
      
 89 
     | 
    
         
            +
                    'No action defined for event',
         
     | 
| 
      
 90 
     | 
    
         
            +
                    event,
         
     | 
| 
      
 91 
     | 
    
         
            +
                    'in state',
         
     | 
| 
      
 92 
     | 
    
         
            +
                    this.#current
         
     | 
| 
      
 93 
     | 
    
         
            +
                  );
         
     | 
| 
      
 94 
     | 
    
         
            +
                }
         
     | 
| 
      
 95 
     | 
    
         
            +
              }
         
     | 
| 
      
 96 
     | 
    
         
            +
              /**
         
     | 
| 
      
 97 
     | 
    
         
            +
               * Triggers a new event and returns the new state.
         
     | 
| 
      
 98 
     | 
    
         
            +
               *
         
     | 
| 
      
 99 
     | 
    
         
            +
               * @param {string} event
         
     | 
| 
      
 100 
     | 
    
         
            +
               * @param {any[]} args
         
     | 
| 
      
 101 
     | 
    
         
            +
               */
         
     | 
| 
      
 102 
     | 
    
         
            +
              send(event, ...args) {
         
     | 
| 
      
 103 
     | 
    
         
            +
                const newState = this.#dispatch(event, ...args);
         
     | 
| 
      
 104 
     | 
    
         
            +
                if (newState && newState !== this.#current) {
         
     | 
| 
      
 105 
     | 
    
         
            +
                  this.#transition(newState, event, args);
         
     | 
| 
      
 106 
     | 
    
         
            +
                }
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                return this.#current;
         
     | 
| 
      
 109 
     | 
    
         
            +
              }
         
     | 
| 
      
 110 
     | 
    
         
            +
              /**
         
     | 
| 
      
 111 
     | 
    
         
            +
               * Debounces the triggering of an event.
         
     | 
| 
      
 112 
     | 
    
         
            +
               *
         
     | 
| 
      
 113 
     | 
    
         
            +
               * @param {number} wait
         
     | 
| 
      
 114 
     | 
    
         
            +
               * @param {string} event
         
     | 
| 
      
 115 
     | 
    
         
            +
               * @param {any[]} args
         
     | 
| 
      
 116 
     | 
    
         
            +
               */
         
     | 
| 
      
 117 
     | 
    
         
            +
              async debounce(wait = 500, event, ...args) {
         
     | 
| 
      
 118 
     | 
    
         
            +
                if (this.#timeout[event]) {
         
     | 
| 
      
 119 
     | 
    
         
            +
                  clearTimeout(this.#timeout[event]);
         
     | 
| 
      
 120 
     | 
    
         
            +
                }
         
     | 
| 
      
 121 
     | 
    
         
            +
                return new Promise((resolve) => {
         
     | 
| 
      
 122 
     | 
    
         
            +
                  this.#timeout[event] = setTimeout(() => {
         
     | 
| 
      
 123 
     | 
    
         
            +
                    delete this.#timeout[event];
         
     | 
| 
      
 124 
     | 
    
         
            +
                    resolve(this.send(event, ...args));
         
     | 
| 
      
 125 
     | 
    
         
            +
                  }, wait);
         
     | 
| 
      
 126 
     | 
    
         
            +
                });
         
     | 
| 
      
 127 
     | 
    
         
            +
              }
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
              /** The current state. */
         
     | 
| 
      
 130 
     | 
    
         
            +
              get current() {
         
     | 
| 
      
 131 
     | 
    
         
            +
                return this.#current;
         
     | 
| 
      
 132 
     | 
    
         
            +
              }
         
     | 
| 
      
 133 
     | 
    
         
            +
            }
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            export { default as FiniteStateMachine } from "./FiniteStateMachine.svelte";
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            export { default as FiniteStateMachine } from './FiniteStateMachine.svelte';
         
     | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import {
         
     | 
| 
      
 2 
     | 
    
         
            +
              NetworkLoader,
         
     | 
| 
      
 3 
     | 
    
         
            +
              ERROR_NOT_LOADED,
         
     | 
| 
      
 4 
     | 
    
         
            +
              ERROR_TRANSFERRED
         
     | 
| 
      
 5 
     | 
    
         
            +
            } from '../network-loader/index.js';
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            /**
         
     | 
| 
      
 8 
     | 
    
         
            +
             * ImageLoader instance
         
     | 
| 
      
 9 
     | 
    
         
            +
             * - Loads image data from network
         
     | 
| 
      
 10 
     | 
    
         
            +
             * - The loading process can be monitored
         
     | 
| 
      
 11 
     | 
    
         
            +
             */
         
     | 
| 
      
 12 
     | 
    
         
            +
            export default class ImageLoader extends NetworkLoader {} // end class
         
     |