Repository navigation
Vendor the H5P core from h5p-php-library and retire h5p-standalone - #46
Merged
Merged
Conversation
…lone The runtime took the core from h5p-standalone, which copies it about once a year and records no upstream revision, and its loader walked every library.json from the frame. Now `pnpm core:sync` vendors h5p-php-library at a commit (cb64a1f, 2026-08-11, core API 1.28) into packages/runtime/vendor/h5p-core/, taking what and in what order from upstream's own H5PCore::$scripts and $styles; the build joins and minifies the scripts into frame.bundle.js (48.5 kB gzipped, against 54.6 for the two bundles it replaces) and rebuilds the stylesheets as before. The boot script builds H5PIntegration itself, field for field as h5p-standalone did, with the core's English strings from getLocalization() at the same commit, and loads what the worker's new `boot` route names: every library's scripts and styles in h5p-standalone's order, ported to the letter (its walk, its edges, toposort 2.0.2 and its tie-breaks). The order is checked against h5p-standalone's own code on 500 random graphs, and on 68 packages (the demo's, nine fixtures, the sweep's 55) captured from the frame before and after: the same files in the same order. One fix fell out: a package with folders named without versions, played with the pack, whose parts are named with them, ended h5p-standalone's boot on a 404, since it named every folder by its first dependency's probe; the walk tries each library both ways. BREAKING CHANGE: the runtime has no main.bundle.js and its `runtime` export no `mainJs`; its boot script needs a worker that answers the `boot` route. The worker still writes the old document for a runtime up to 0.2 handed over with `mainJs`. The player's peer range moves at release. Closes #37 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The core under packages/runtime/vendor/h5p-core/ is h5p-php-library's code at a pinned commit, unchanged. CodeQL's two findings in it (js/insecure-randomness, the anonymous learner id H5P.createUUID makes with Math.random) are upstream's, and before #37 the same code came from node_modules/, which was not scanned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ssing library On a host without Range, a lookup the worker's walk could not finish because the download stopped moving fell through to "the package does not carry H5P.Foo", a 422 naming a library the package may well carry, after waiting the stall bound twice. It answers 503 with Retry-After now, as an entry's request does. And the walk goes on with the reader `awaitEntry` hands back, as `serveEntry` does: once the archive is whole that is a new reader, and every later lookup on the old partial one opened another. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #37.
The runtime no longer uses h5p-standalone. It vendors the H5P core from h5p-php-library at a pinned commit, and its boot script loads the core itself, in the order the worker gives.
What changed
The core, vendored (
packages/runtime/)pnpm core:sync [<ref>](scripts/sync-core.mjs) fetches h5p-php-library at a commit intovendor/h5p-core/, which is committed. It is pinned at cb64a1f (2026-08-11, core API 1.28), the commitcontent-check.tsis already ported from.H5PCore::$scriptsandH5PCore::$stylesinh5p.classes.phpat that commit. It also takes the fonts and image the stylesheets reach, their licence files, and the player's English strings fromgetLocalization(), ending where the hub's sharing-wizard strings begin.l10n-rules.mjsreads them fromstrings.jsonand no language file changes.frame.bundle.jsis the ten scripts joined in upstream's order and minified with top-level names kept. They are global scripts, as a site loads them, and H5P'sjQuery.noConflict(true)needs jQuery's global (h5p-standalone built that file as an ES module to get the same effect).frame.bundle.jsandmain.bundle.jstogether before.h5p.cssis built as before, from the eight sheets.NOTICE.txtandMANIFEST.jsonnow name the commit, so the corresponding source is exact.h5p-standalonedependency is gone, andmain.bundle.jswith it.The boot (
src/frame-boot.ts)H5PIntegrationitself, field for field as h5p-standalone did, then mounts the.h5p-contentdiv, adds the core's and the libraries' stylesheets and scripts (markeddata-h5p, waited for), and holdsH5P.initback with the core's ownpreventInit.urlis now the package's root rather than a random id. No library in the pack reads it, andgetContentPathwas already answered fromcontentUrl.What to load: the worker's
bootroute (packages/player/src/sw/library-load.ts,mount.ts)…/h5p/boot/<load>answers aLibraryLoad:libraryDirectoriesfor a library in a folder its version does not name, which the core'sH5P.getLibraryPathreads;upgradeslist.loadDependencieslevels, itssortDependenciesedges, andtoposort2.0.2 with its tie-breaks, including the phantom node a library without dependencies gets. Two deliberate differences:Across versions
mainJscame from an element paired with runtime ≤ 0.2. For it, the worker still writes the old document: the loader script, and the upgrade list in the config.runtimeproperty, plays against this worker.bootURL), fails with a message to update the player andh5p-sw.jstogether.Testing
tests/unit/library-load.test.tsruns h5p-standalone's ownloadDependencies,sortDependenciesandtoposortbeside the port on 500 random dependency graphs.mainand on this branch: the six demo packages, nine fixtures and the sweep's 55. All 68 load the same files in the same order. 62 are byte-identical. In the other six, only folder names changed:H5P.Question-1.5/…where h5p-standalone requested1.4/…and the server answered from 1.5.boardgame.h5p(in the fixtures folder, not built by the repo). Its folders are named without versions. With the pack, the refreshed parts sit in versioned folders beside them, and h5p-standalone named every folder by its first dependency's probe, so it ended on "Unexpected end of JSON input". The new fixtureunversioned-pack.h5pand a test inpack.test.tspin the fix.mainand on this branch. The reports are identical apart from timings, so every content type sends the same statements in both modes.test:engine: 182/182, plus the app's 24 (3 Chromium-only skipped).test:engine: 182/182, plus the app's 24.main.bundle.jsamong a written site's files).pnpm typecheckpasses;pnpm build:demobuilds.test/h5p-test.h5ppasses, and so do the demo quiz and video.stalling-host.test.ts's 35-second outage test failed 4 times in a row with the tail arriving at 26–32 s. That was while Spotlight was indexing a worktree, with load average 20. It then passed 5 times and in the full run once the machine was quiet.mainpassed it twice at the same time, so I can't fully rule out this branch. What fits load is the server giving up after twice the stall bound when the Jobs worker's liveness notices are delayed. Keep an eye on it in CI.Not covered
assets-basewith this player: the element no longer namesmain.bundle.js, so that pairing does not work and is not meant to.h5p-sw.jscopy: the old worker cannot write a document for a runtime withoutmainJs. That is the existing "updateh5p-sw.jswith the element" case.Release
Runtime and player go together:
runtimeexport losesmainJsand itsdist/losesmain.bundle.js.bootroute.^0.2).🤖 Generated with Claude Code