@flighthq/audio 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export declare function inferAudioType(url: string): string | null;
2
+ //# sourceMappingURL=audioFormat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioFormat.d.ts","sourceRoot":"","sources":["../src/audioFormat.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoBzD"}
@@ -0,0 +1,22 @@
1
+ export function inferAudioType(url) {
2
+ const ext = url.split('?')[0].split('.').pop()?.toLowerCase();
3
+ switch (ext) {
4
+ case 'mp3':
5
+ return 'audio/mpeg';
6
+ case 'ogg':
7
+ return 'audio/ogg';
8
+ case 'wav':
9
+ return 'audio/wav';
10
+ case 'aac':
11
+ return 'audio/aac';
12
+ case 'flac':
13
+ return 'audio/flac';
14
+ case 'webm':
15
+ return 'audio/webm';
16
+ case 'm4a':
17
+ return 'audio/mp4';
18
+ default:
19
+ return null;
20
+ }
21
+ }
22
+ //# sourceMappingURL=audioFormat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioFormat.js","sourceRoot":"","sources":["../src/audioFormat.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,CAAC;IAC9D,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,KAAK;YACR,OAAO,YAAY,CAAC;QACtB,KAAK,KAAK;YACR,OAAO,WAAW,CAAC;QACrB,KAAK,KAAK;YACR,OAAO,WAAW,CAAC;QACrB,KAAK,KAAK;YACR,OAAO,WAAW,CAAC;QACrB,KAAK,MAAM;YACT,OAAO,YAAY,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,YAAY,CAAC;QACtB,KAAK,KAAK;YACR,OAAO,WAAW,CAAC;QACrB;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AudioResource } from '@flighthq/types';
2
+ export declare function createAudioResource(buffer?: AudioBuffer): AudioResource;
3
+ //# sourceMappingURL=audioResource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioResource.d.ts","sourceRoot":"","sources":["../src/audioResource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,aAAa,CAEvE"}
@@ -0,0 +1,4 @@
1
+ export function createAudioResource(buffer) {
2
+ return { buffer: buffer ?? null };
3
+ }
4
+ //# sourceMappingURL=audioResource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioResource.js","sourceRoot":"","sources":["../src/audioResource.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,mBAAmB,CAAC,MAAoB;IACtD,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,IAAI,EAAE,CAAC;AACpC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { AudioResource, AudioResourceUrl } from '@flighthq/types';
2
+ export declare function loadAudioResourceFromUrl(context: AudioContext, url: string, signal?: AbortSignal): Promise<AudioResource>;
3
+ export declare function loadAudioResourceFromUrls(context: AudioContext, sources: AudioResourceUrl[], signal?: AbortSignal): Promise<AudioResource>;
4
+ //# sourceMappingURL=audioResourceFrom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioResourceFrom.d.ts","sourceRoot":"","sources":["../src/audioResourceFrom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAKvE,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,YAAY,EACrB,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC,CAKxB;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC,CAKxB"}
@@ -0,0 +1,16 @@
1
+ import { inferAudioType } from './audioFormat';
2
+ import { createAudioResource } from './audioResource';
3
+ export async function loadAudioResourceFromUrl(context, url, signal) {
4
+ const response = await fetch(url, { signal });
5
+ const arrayBuffer = await response.arrayBuffer();
6
+ const audioBuffer = await context.decodeAudioData(arrayBuffer);
7
+ return createAudioResource(audioBuffer);
8
+ }
9
+ export async function loadAudioResourceFromUrls(context, sources, signal) {
10
+ const probe = new Audio();
11
+ const selected = sources.find(({ url, type }) => probe.canPlayType(type ?? inferAudioType(url) ?? '') !== '');
12
+ if (selected === undefined)
13
+ return createAudioResource();
14
+ return loadAudioResourceFromUrl(context, selected.url, signal);
15
+ }
16
+ //# sourceMappingURL=audioResourceFrom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioResourceFrom.js","sourceRoot":"","sources":["../src/audioResourceFrom.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAqB,EACrB,GAAW,EACX,MAAoB;IAEpB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;IACjD,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IAC/D,OAAO,mBAAmB,CAAC,WAAW,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,OAAqB,EACrB,OAA2B,EAC3B,MAAoB;IAEpB,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9G,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,mBAAmB,EAAE,CAAC;IACzD,OAAO,wBAAwB,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './audioFormat';
2
+ export * from './audioResource';
3
+ export * from './audioResourceFrom';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './audioFormat';
2
+ export * from './audioResource';
3
+ export * from './audioResourceFrom';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@flighthq/audio",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "src/**/*.test.ts",
16
+ "!dist/**/*.test.js",
17
+ "!dist/**/*.test.d.ts",
18
+ "!dist/**/*.test.js.map",
19
+ "!dist/**/*.test.d.ts.map"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc -b",
23
+ "clean": "tsc -b --clean",
24
+ "test": "vitest run --config vitest.config.ts",
25
+ "test:watch": "vitest --watch --config vitest.config.ts",
26
+ "prepack": "npm run clean && npm run clean:dist && npm run build",
27
+ "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
28
+ },
29
+ "dependencies": {
30
+ "@flighthq/types": "0.1.0"
31
+ },
32
+ "devDependencies": {
33
+ "typescript": "^5.3.0"
34
+ },
35
+ "description": "Audio resources, URL constructors, and the shared audio context",
36
+ "sideEffects": false
37
+ }
@@ -0,0 +1,43 @@
1
+ import { inferAudioType } from './audioFormat';
2
+
3
+ describe('inferAudioType', () => {
4
+ it('returns "audio/mpeg" for .mp3 files', () => {
5
+ expect(inferAudioType('track.mp3')).toBe('audio/mpeg');
6
+ });
7
+
8
+ it('returns "audio/ogg" for .ogg files', () => {
9
+ expect(inferAudioType('track.ogg')).toBe('audio/ogg');
10
+ });
11
+
12
+ it('returns "audio/wav" for .wav files', () => {
13
+ expect(inferAudioType('track.wav')).toBe('audio/wav');
14
+ });
15
+
16
+ it('returns "audio/aac" for .aac files', () => {
17
+ expect(inferAudioType('track.aac')).toBe('audio/aac');
18
+ });
19
+
20
+ it('returns "audio/flac" for .flac files', () => {
21
+ expect(inferAudioType('track.flac')).toBe('audio/flac');
22
+ });
23
+
24
+ it('returns "audio/webm" for .webm files', () => {
25
+ expect(inferAudioType('track.webm')).toBe('audio/webm');
26
+ });
27
+
28
+ it('returns "audio/mp4" for .m4a files', () => {
29
+ expect(inferAudioType('track.m4a')).toBe('audio/mp4');
30
+ });
31
+
32
+ it('returns null for unrecognized extensions', () => {
33
+ expect(inferAudioType('track.mid')).toBeNull();
34
+ });
35
+
36
+ it('strips query parameters before matching', () => {
37
+ expect(inferAudioType('track.mp3?cb=1')).toBe('audio/mpeg');
38
+ });
39
+
40
+ it('returns null for a URL with no extension', () => {
41
+ expect(inferAudioType('audio')).toBeNull();
42
+ });
43
+ });
@@ -0,0 +1,8 @@
1
+ import { createAudioResource } from './audioResource';
2
+
3
+ describe('createAudioResource', () => {
4
+ it('returns a resource with null buffer when called with no arguments', () => {
5
+ const resource = createAudioResource();
6
+ expect(resource.buffer).toBeNull();
7
+ });
8
+ });
@@ -0,0 +1,20 @@
1
+ import { loadAudioResourceFromUrl, loadAudioResourceFromUrls } from './audioResourceFrom';
2
+
3
+ const mockContext = {
4
+ decodeAudioData: vi.fn().mockResolvedValue({} as AudioBuffer),
5
+ } as unknown as AudioContext;
6
+
7
+ describe('loadAudioResourceFromUrl', () => {
8
+ it('returns a Promise', () => {
9
+ const result = loadAudioResourceFromUrl(mockContext, 'test.mp3');
10
+ result.catch(() => {});
11
+ expect(result).toBeInstanceOf(Promise);
12
+ });
13
+ });
14
+
15
+ describe('loadAudioResourceFromUrls', () => {
16
+ it('resolves immediately with a null-buffer resource when sources is empty', async () => {
17
+ const resource = await loadAudioResourceFromUrls(mockContext, []);
18
+ expect(resource.buffer).toBeNull();
19
+ });
20
+ });