Initial Commit
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
export {
|
||||
BUNDLE_PACKAGE_SLUG,
|
||||
BUNDLE_URI,
|
||||
CDN_URI,
|
||||
CHANNELS,
|
||||
ENTRY_ID,
|
||||
manifest,
|
||||
SAMPLE_RATE,
|
||||
} from "./manifest.js";
|
||||
@@ -0,0 +1,89 @@
|
||||
# `manifest` — single-entry `IrManifest` for the outdoor-swimming-pool IR
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Declares the lone `IrManifestEntry` shipped by `@suaveplan/audio-ir-room-plugin-pool`.
|
||||
The entry's `uri` is a `fallback://?u=<bundle>&u=<https>` URI built at module
|
||||
load by `buildFallbackUri` from `@suaveplan/storage-uri-plugin-fallback` —
|
||||
when the consuming resolver has both a `bundle://` plugin and an `https://`
|
||||
plugin wired, the shipped `fallback://` walk hits the in-package WAV first
|
||||
and only reaches for the CDN copy when the local file is absent.
|
||||
|
||||
The manifest also pins the **decoded** `channels` and `sampleRate` of the
|
||||
bundled WAV (`channels = 1`, `sampleRate = 48000`) so the loader's
|
||||
`validateAndFinalize` step can reject any subsequent re-encode that drifts
|
||||
from those values. Both numbers were obtained by feeding
|
||||
`files/outdoor-swimming-pool.wav` through `decodeWav` once at
|
||||
manifest-authoring time.
|
||||
|
||||
## Features
|
||||
|
||||
- Round-trips through `IrManifestSchema` at module load — any drift in the
|
||||
schema fails the build before `dist/` is emitted.
|
||||
- `BUNDLE_PACKAGE_SLUG`, `BUNDLE_URI`, `CDN_URI`, `ENTRY_ID`, `CHANNELS`,
|
||||
`SAMPLE_RATE` exported as named `const` literals so consumers can refer
|
||||
to them without re-deriving from `manifest.entries[0]`.
|
||||
- Frozen at runtime (`IrManifestSchema` applies `Object.freeze` to the
|
||||
parsed manifest + every entry).
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { manifest } from "@suaveplan/audio-ir-room-plugin-pool/manifest";
|
||||
|
||||
console.log(manifest.packageSlug); // "pool"
|
||||
console.log(manifest.entries[0].id); // "pool-outdoor-swimming-pool"
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
BUNDLE_URI,
|
||||
CDN_URI,
|
||||
ENTRY_ID,
|
||||
manifest,
|
||||
} from "@suaveplan/audio-ir-room-plugin-pool/manifest";
|
||||
import { parseFallbackUri } from "@suaveplan/storage-uri-plugin-fallback";
|
||||
|
||||
const entry = manifest.entries[0];
|
||||
const parsed = parseFallbackUri(entry.uri);
|
||||
console.log(parsed.candidates); // [BUNDLE_URI, CDN_URI]
|
||||
console.log(entry.id === ENTRY_ID); // true
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Description |
|
||||
| --- | --- | --- |
|
||||
| `manifest` | `IrManifest` | Frozen single-entry manifest. |
|
||||
| `BUNDLE_PACKAGE_SLUG` | `"audio-ir-room-plugin-pool"` | Slug expected by the bundle plugin. |
|
||||
| `BUNDLE_URI` | string literal | Bundle-local URI for the WAV. |
|
||||
| `CDN_URI` | string literal | HTTPS CDN URI for the WAV. |
|
||||
| `ENTRY_ID` | `"pool-outdoor-swimming-pool"` | Entry id within the registry. |
|
||||
| `CHANNELS` | `1` | Decoded channel count of the WAV. |
|
||||
| `SAMPLE_RATE` | `48000` | Decoded sample rate of the WAV (Hz). |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The manifest constants are NOT optional — the spec for this package
|
||||
requires them to equal the values measured by decoding
|
||||
`files/outdoor-swimming-pool.wav` at authoring time. If the bundled WAV is
|
||||
ever re-mastered, both `CHANNELS` and `SAMPLE_RATE` MUST be updated to
|
||||
match the new decode result, and the file-presence integration test
|
||||
SHOULD re-run as part of that change to assert the new constants.
|
||||
|
||||
`buildFallbackUri([BUNDLE_URI, CDN_URI])` runs at module load. The
|
||||
ordering of candidates IS the failover policy — bundle wins when present,
|
||||
CDN wins when bundle reports `BUNDLE_URI.NOT_FOUND`. Reversing the array
|
||||
would silently flip that policy without a separate spec change, so the
|
||||
constants are kept verbose and explicit rather than inlined.
|
||||
|
||||
The `license` field intentionally says "All Rights Reserved — Suaveplan
|
||||
internal media library" because the source media library has no public
|
||||
license attached. Consumers SHOULD NOT redistribute the bundled WAV
|
||||
outside the Suaveplan distribution.
|
||||
@@ -0,0 +1,63 @@
|
||||
import { IrManifestSchema } from "@suaveplan/audio-ir-core";
|
||||
import { parseFallbackUri } from "@suaveplan/storage-uri-plugin-fallback";
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import {
|
||||
BUNDLE_PACKAGE_SLUG,
|
||||
BUNDLE_URI,
|
||||
CDN_URI,
|
||||
CHANNELS,
|
||||
ENTRY_ID,
|
||||
manifest,
|
||||
SAMPLE_RATE,
|
||||
} from "./manifest.js";
|
||||
|
||||
describe("manifest", () => {
|
||||
it("manifest parses through IrManifestSchema", { timeout: 5000 }, () => {
|
||||
const reparsed = IrManifestSchema.parse(manifest);
|
||||
expect(reparsed).toEqual(manifest);
|
||||
expect(manifest.packageSlug).toBe("pool");
|
||||
expect(manifest.family).toBe("room");
|
||||
expect(manifest.entries.length).toBe(1);
|
||||
const entry = manifest.entries[0];
|
||||
expect(entry).toBeDefined();
|
||||
if (entry === undefined) throw new Error("unreachable");
|
||||
expect(entry.id).toBe(ENTRY_ID);
|
||||
expect(entry.id).toBe("pool-outdoor-swimming-pool");
|
||||
expect(entry.family).toBe("room");
|
||||
expect(entry.channels).toBe(CHANNELS);
|
||||
expect(entry.sampleRate).toBe(SAMPLE_RATE);
|
||||
expect(entry.gainDb).toBe(0);
|
||||
expect(entry.license.length).toBeGreaterThan(0);
|
||||
expect(entry.source.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("URI parses through parseFallbackUri with two ordered candidates", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const entry = manifest.entries[0];
|
||||
if (entry === undefined) throw new Error("unreachable");
|
||||
const parsed = parseFallbackUri(entry.uri);
|
||||
expect(parsed.candidates.length).toBe(2);
|
||||
const first = parsed.candidates[0];
|
||||
const second = parsed.candidates[1];
|
||||
expect(first).toBeDefined();
|
||||
expect(second).toBeDefined();
|
||||
if (first === undefined || second === undefined) {
|
||||
throw new Error("unreachable");
|
||||
}
|
||||
expect(first.startsWith("bundle://audio-ir-room-plugin-pool/")).toBe(
|
||||
true
|
||||
);
|
||||
expect(first).toBe(BUNDLE_URI);
|
||||
expect(second).toBe(CDN_URI);
|
||||
expect(second).toBe(
|
||||
"https://swch.b-cdn.net/_/audio/ir/room/roompool.wav"
|
||||
);
|
||||
});
|
||||
|
||||
it("exports the canonical constants", { timeout: 5000 }, () => {
|
||||
expect(BUNDLE_PACKAGE_SLUG).toBe("audio-ir-room-plugin-pool");
|
||||
expect(CHANNELS).toBe(1);
|
||||
expect(SAMPLE_RATE).toBe(48_000);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import type { IrManifest } from "@suaveplan/audio-ir-core";
|
||||
import { IrManifestSchema } from "@suaveplan/audio-ir-core";
|
||||
import { buildFallbackUri } from "@suaveplan/storage-uri-plugin-fallback";
|
||||
|
||||
/**
|
||||
* Slug embedded in the bundle URL. MUST match the `packageSlug` passed to
|
||||
* `bundleUriPlugin({ packageSlug })` inside `register` — the bundle plugin
|
||||
* uses this to validate that the URL authority matches the consuming
|
||||
* package.
|
||||
*/
|
||||
export const BUNDLE_PACKAGE_SLUG = "audio-ir-room-plugin-pool" as const;
|
||||
|
||||
/**
|
||||
* Bundle-local URI for the shipped WAV. Resolves against the package's
|
||||
* `files/` directory at runtime via `bundleUriPlugin`.
|
||||
*/
|
||||
export const BUNDLE_URI =
|
||||
"bundle://audio-ir-room-plugin-pool/outdoor-swimming-pool.wav" as const;
|
||||
|
||||
/**
|
||||
* CDN fallback URI. The shipped `fallback://` walk targets this when the
|
||||
* bundle adapter reports `BUNDLE_URI.NOT_FOUND`.
|
||||
*/
|
||||
export const CDN_URI =
|
||||
"https://swch.b-cdn.net/_/audio/ir/room/roompool.wav" as const;
|
||||
|
||||
/**
|
||||
* Entry id for the lone IR shipped by this package.
|
||||
*/
|
||||
export const ENTRY_ID = "pool-outdoor-swimming-pool" as const;
|
||||
|
||||
/**
|
||||
* Decoded channel count of `files/outdoor-swimming-pool.wav` — measured by
|
||||
* decoding the bundled file at manifest-authoring time with
|
||||
* `@suaveplan/audio-decode-wav`.
|
||||
*/
|
||||
export const CHANNELS = 1 as const;
|
||||
|
||||
/**
|
||||
* Decoded sample rate of `files/outdoor-swimming-pool.wav` (Hz) — measured by
|
||||
* decoding the bundled file at manifest-authoring time.
|
||||
*/
|
||||
export const SAMPLE_RATE = 48_000 as const;
|
||||
|
||||
/**
|
||||
* Single-entry `IrManifest` validated through `IrManifestSchema`.
|
||||
*
|
||||
* The lone entry's `uri` is a `fallback://?u=<bundle>&u=<https>` URI in
|
||||
* declared order — bundle first, CDN second. The shipped `fallback://` plugin
|
||||
* handles the ordered walk + transient classification.
|
||||
*/
|
||||
export const manifest: IrManifest = IrManifestSchema.parse({
|
||||
packageSlug: "pool",
|
||||
family: "room",
|
||||
entries: [
|
||||
{
|
||||
id: ENTRY_ID,
|
||||
family: "room",
|
||||
uri: buildFallbackUri([BUNDLE_URI, CDN_URI]),
|
||||
channels: CHANNELS,
|
||||
sampleRate: SAMPLE_RATE,
|
||||
gainDb: 0,
|
||||
license: "All Rights Reserved — Suaveplan internal media library",
|
||||
source: "Mountain Duck media library + https://swch.b-cdn.net CDN",
|
||||
},
|
||||
],
|
||||
});
|
||||
Reference in New Issue
Block a user