Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 53 additions & 3 deletions .github/workflows/publish-npm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
pull_request:
push:
branches: [main]
tags: ["v*", "window-multicast-bridge-v*"]
tags: ["v*", "window-multicast-bridge-v*", "mabr-route-proxy-v*"]
workflow_dispatch:

# Node is pinned to an exact release, never the bare range '24' (the reasoning
Expand Down Expand Up @@ -82,6 +82,13 @@ jobs:
npm test
npm run test:dist

- name: Build and test the ROUTE mABR proxy
working-directory: packages/mabr-route-proxy
run: |
npm install --include=dev --no-audit --no-fund
npm run build
npm test

- name: Pack release artifacts
run: |
mkdir npm-packages
Expand All @@ -92,15 +99,17 @@ jobs:
# npm-packages/ against its tag, and the bridge's version is not that tag.
mkdir npm-packages-bridge
npm pack ./packages/window-multicast-bridge --pack-destination npm-packages-bridge
ls -l npm-packages npm-packages-bridge
mkdir npm-packages-mabr
npm pack ./packages/mabr-route-proxy --pack-destination npm-packages-mabr
ls -l npm-packages npm-packages-bridge npm-packages-mabr

# Asserted on the packed tarballs, never on the repo tree: what ships is
# the tarball, and `files` / .npmignore decide which of the two you are
# actually looking at.
- name: Verify tarball contents
run: |
set -euo pipefail
for tgz in npm-packages/*.tgz npm-packages-bridge/*.tgz; do
for tgz in npm-packages/*.tgz npm-packages-bridge/*.tgz npm-packages-mabr/*.tgz; do
echo "=== $tgz ==="
# Capture the member list once rather than piping `tar` into a
# matcher: `grep -q` exits at the first match, which SIGPIPEs tar,
Expand Down Expand Up @@ -249,6 +258,13 @@ jobs:
if-no-files-found: error
retention-days: 7

- uses: actions/upload-artifact@v4
with:
name: npm-packages-mabr
path: npm-packages-mabr/*.tgz
if-no-files-found: error
retention-days: 7

# Repo-surface privacy gate. This repository is PUBLIC; the tarball gate in
# `build` is structurally incapable of seeing this surface, because both
# packages declare `files: ["dist"]`, so docs/, src/*.test.ts and .github/
Expand Down Expand Up @@ -459,3 +475,37 @@ jobs:

- name: Publish @blockcast/window-multicast-bridge
run: npm publish ./npm-packages-bridge/blockcast-window-multicast-bridge-*.tgz --access public --provenance --loglevel silly

# The ROUTE adapter has its own version stream. Keep its tag and artifact
# separate from the existing v* gateway package release assertion.
publish-mabr:
needs: build
if: startsWith(github.ref, 'refs/tags/mabr-route-proxy-v')
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Update npm
run: |
npm install --global npm@11
npm --version
- uses: actions/download-artifact@v4
with:
name: npm-packages-mabr
path: npm-packages-mabr
- name: Assert the tag matches the packed version
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME#mabr-route-proxy-v}"
tgz="$(echo npm-packages-mabr/blockcast-mabr-route-proxy-*.tgz)"
version="$(tar -xOzf "$tgz" package/package.json | node -pe 'JSON.parse(require("fs").readFileSync(0)).version')"
[ "$version" = "$tag" ] || {
echo "::error::$tgz is $version, tag is $tag"
exit 1
}
- name: Publish @blockcast/mabr-route-proxy
run: npm publish npm-packages-mabr/blockcast-mabr-route-proxy-*.tgz --access public --provenance --loglevel silly
6 changes: 6 additions & 0 deletions packages/mabr-route-proxy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
"scripts": { "build": "tsc -b", "typecheck": "tsc --noEmit", "test": "node --experimental-strip-types --test 'src/**/*.test.ts'", "test:e2e": "npm run build && node tests/route-wasm-shaka-e2e.mjs", "clean": "rm -rf dist tsconfig.tsbuildinfo" },
"keywords": ["mabr", "route", "cmaf", "dash", "hls", "shaka"],
"license": "MIT",
"publishConfig": { "access": "public" },
"repository": {
"type": "git",
"url": "https://github.com/Blockcast/beacon.git",
"directory": "packages/mabr-route-proxy"
},
"dependencies": {},
"devDependencies": { "typescript": "^5.7.0" }
}
8 changes: 7 additions & 1 deletion packages/mabr-route-proxy/src/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,10 +424,12 @@ test('rejects a sourceless AMT endpoint instead of emitting a DRIAD join', async
test('discovers AMT service bytes through a delivery-service hostname', async () => {
const originalFetch = globalThis.fetch;
const urls: string[] = [];
const fetchOptions: RequestInit[] = [];
let config: Record<string, unknown> | undefined;
globalThis.fetch = (async (input: RequestInfo | URL) => {
globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => {
const url = String(input);
urls.push(url);
fetchOptions.push(init ?? {});
if (url === 'https://cdn.onprem-live-multicast.public-st.cdn.blockcast.net/slt/') {
return new Response('<ul><li><a href="7" /></li></ul>');
}
Expand All @@ -454,6 +456,10 @@ test('discovers AMT service bytes through a delivery-service hostname', async ()
'https://cdn.onprem-live-multicast.public-st.cdn.blockcast.net/slt/',
'https://cdn.onprem-live-multicast.public-st.cdn.blockcast.net/slt/7',
]);
assert.deepEqual(fetchOptions, [
{ credentials: 'omit', mode: 'cors' },
{ credentials: 'omit', mode: 'cors' },
]);
assert.deepEqual(config, {
origin: 'amt', group: '232.0.1.3', port: 1024,
consume: 'bytes', relay: 'amt-relay.example.test', relayPort: 2268,
Expand Down
5 changes: 4 additions & 1 deletion packages/mabr-route-proxy/src/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,10 @@ async function discoverSlsEndpoint(options: RouteMabrOptions): Promise<RouteEndp
const base = new URL(raw, globalThis.location?.href ?? 'http://localhost/');
const basePath = base.pathname.replace(/\/+$/, '');
const get = async (url: string): Promise<string> => {
const response = await globalThis.fetch(url);
// The DS is public HTTP discovery, not a TO control-plane endpoint. Keep
// browser credentials out of every LLS request even when the page has
// cookies for another authority.
const response = await globalThis.fetch(url, { credentials: 'omit', mode: 'cors' });
if (!response.ok) throw new Error(`HTTP LLS fetch ${url} failed with ${response.status}`);
return response.text();
};
Expand Down
Loading