Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
f1a797c
chore(p-np): add test harness + bump to 4.4.0 (v4.4.0-client)
alexey-max-fedorov May 24, 2026
e33a54b
feat(p-np): extract PatchRule + RULES + applyRules + hashRules
alexey-max-fedorov May 24, 2026
8d260b8
feat(p-np): extract buildPrefix + buildSuffix into wrappers.ts
alexey-max-fedorov May 24, 2026
3dc65d2
refactor(p-np): restore verbatim suffix, loosen timer regex tests
alexey-max-fedorov May 24, 2026
a5fc8cf
feat(p-np): add Manifest type + buildManifest + hashManifest
alexey-max-fedorov May 24, 2026
a05648b
feat(p-np): emit manifest.json alongside game.min.js (v4.4.0-client)
alexey-max-fedorov May 24, 2026
3ae7676
chore(p-np): bump VERSION constant to 4.4.0
alexey-max-fedorov May 24, 2026
a016b5e
test(p-np): integration test for rules + wrappers + manifest pipeline
alexey-max-fedorov May 24, 2026
c78f804
ci(p-np): add dist/manifest.json to commit list
alexey-max-fedorov May 24, 2026
8a2b222
docs(p-np): document client-side patching architecture (v4.4.0)
alexey-max-fedorov May 24, 2026
1ba9ee9
chore(p-np): refresh dist artifacts
alexey-max-fedorov May 24, 2026
924135f
refactor(patcher): drop guiLink param from buildSuffix; use global
alexey-max-fedorov May 24, 2026
d22d1c7
feat(patcher): add defaultMenuUrl to manifest schema + hash
alexey-max-fedorov May 24, 2026
a38c508
feat(patcher): orchestrator emits defaultMenuUrl; bump to 4.4.1
alexey-max-fedorov May 24, 2026
31b984f
Potential fix for pull request finding
alexey-max-fedorov May 25, 2026
dc04fbd
Potential fix for pull request finding
alexey-max-fedorov May 25, 2026
9baf26d
Merge remote-tracking branch 'origin/master' into v4.4.0-client
alexey-max-fedorov May 25, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/patch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config user.name "github-actions[bot]"

git add dist/game.min.js dist/metadata.json
git add dist/manifest.json dist/game.min.js dist/metadata.json
git add dist/public-game.min.js 2>/dev/null || true

if git diff --cached --quiet; then
Expand Down
12 changes: 8 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ The Play Origin extension (in `ProdigyPXP/ProdigyOrigin`, formerly "Prodigy Orig

### Architecture

- **src/patch.ts** — Core patcher. Fetches game files, applies regex-based patches, writes output.
- **src/patch.ts** — Orchestrator. Fetches game files, runs rules via `src/patches.ts` for VERIFICATION, builds the prefix/suffix via `src/wrappers.ts`, assembles `dist/manifest.json` (primary artifact) + `dist/game.min.js` (verification copy) + `dist/metadata.json`.
- **src/patches.ts** — `PatchRule` type, `RULES` array, `applyRules`, `hashRules`.
- **src/wrappers.ts** — `buildPrefix(version)`, `buildSuffix(version, displayImages)`; `buildSuffix` reads `window.__ORIGIN_MENU_URL__`, which is provided via `manifest.defaultMenuUrl`.
- **src/manifest.ts** — `Manifest` type, `buildManifest`, `hashManifest`.
- **src/constants.ts** — URLs, version, GUI link.
- **src/displayImages.ts** — Console splash images.
- **build.mjs** — esbuild build script.
Expand Down Expand Up @@ -45,6 +48,7 @@ node dist/patch.js # Run patcher locally
## Output

The patcher writes to the output directory:
- `game.min.js` — Patched game with injected hack entry points
- `metadata.json` — Build metadata (version, hash, degraded status)
- `public-game.min.js` — Patched public game file (if available)
- `manifest.json` — **Primary artifact.** Consumed by the Play Origin extension.
- `game.min.js` — Verification copy of the patched bundle (not loaded by the extension at runtime).
- `metadata.json` — Per-run metadata: version, hash, perRuleCounts, degraded status.
- `public-game.min.js` — Patched public game file (if available).
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@ P-NP is the static patch pipeline that powers **Play Origin** (the browser-exten

The repository no longer runs an HTTP server. Instead, a GitHub Action fetches current Prodigy assets, applies the patcher logic, and pushes the patched files to a dedicated `patched` branch so they can be served from `raw.githubusercontent.com`.

## Architecture (v4.4.0+)

The patcher's primary artifact is `dist/manifest.json` — a small JSON file containing:

- `schemaVersion` — manifest schema version for compatibility checks.
- `patcherVersion` — version of this patcher that produced the manifest.
- `rules` — ordered list of regex find/replace rules applied to `game.min.js`.
- `prefix` — pre-rendered JS string prepended to the patched game.
- `suffix` — pre-rendered JS string appended after the patched game.
- `defaultMenuUrl` — default menu/loader URL used by consumers when patching.
- `hash` — content hash of `{rules, prefix, suffix, defaultMenuUrl}` for cache invalidation.

The Play Origin extension fetches this manifest, fetches the original `game.min.js`
from `code.prodigygame.com`, applies the rules locally in its background service
worker, wraps with prefix/suffix, and caches the result in `chrome.storage.local`.

`dist/game.min.js` is still produced as a verification copy so this repo's history
stays auditable, but the extension no longer fetches it.

## How It Works

1. `.github/workflows/patch.yml` runs every 2 hours (cron) and on manual dispatch.
Expand Down
19 changes: 13 additions & 6 deletions dist/game.min.js

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions dist/manifest.json

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions dist/metadata.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
{
"generatedAt": "2026-05-25T19:39:06.899Z",
"patcherVersion": "4.3.0",
"generatedAt": "2026-05-25T20:58:13.440Z",
"patcherVersion": "4.4.1",
"gameVersion": "2026.26.0",
"publicGameHash": null,
"loadGamePath": "/js/load-game-f2baaaba58.min.js",
"patchDegraded": false,
"manifestHash": "aa3a3ec39939dbb0",
"perRuleCounts": {
"singleton-exposure": 1,
"safe-bind": 9,
"expose-constants": 1,
"answer-question-bypass": 1,
"external-factory-bypass": 1,
"open-question-bypass": 1
},
"source": {
"gameUrl": "https://code.prodigygame.com/code/2026.26.0/game.min.js?v=2026.26.0",
"publicGameUrl": null,
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{
"name": "p-np-patcher",
"version": "4.3.0",
"version": "4.4.1",
"description": "Fetches and patches Prodigy game files for static hosting",
"main": "./dist/patch.js",
"type": "module",
"scripts": {
"build": "node build.mjs",
"patch": "node dist/patch.js"
"patch": "node dist/patch.js",
"test": "node --experimental-strip-types --test \"tests/**/*.test.ts\"",
"typecheck": "tsc --noEmit"
},
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const VERSION = "4.3.0";
export const VERSION = "4.4.1";
export const GUI_LINK = "https://raw.githubusercontent.com/ProdigyPXP/ProdigyOrigin/master/originGUI/dist/bundle.js";
export const PRODIGY_LOAD_URL = "https://math.prodigygame.com/load";
export const PRODIGY_CODE_ORIGIN = "https://code.prodigygame.com";
38 changes: 38 additions & 0 deletions src/manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { createHash } from "node:crypto";
import type { PatchRule } from "./patches.ts";

export type Manifest = {
schemaVersion: 1;
patcherVersion: string;
hash: string;
rules: ReadonlyArray<PatchRule>;
prefix: string;
suffix: string;
defaultMenuUrl: string;
};

export const hashManifest = (
rules: ReadonlyArray<PatchRule>,
prefix: string,
suffix: string,
defaultMenuUrl: string
): string => {
const canonical = JSON.stringify({ rules, prefix, suffix, defaultMenuUrl });
return createHash("sha256").update(canonical).digest("hex").slice(0, 16);
};

export const buildManifest = (input: {
patcherVersion: string;
rules: ReadonlyArray<PatchRule>;
prefix: string;
suffix: string;
defaultMenuUrl: string;
}): Manifest => ({
schemaVersion: 1,
patcherVersion: input.patcherVersion,
hash: hashManifest(input.rules, input.prefix, input.suffix, input.defaultMenuUrl),
rules: input.rules,
prefix: input.prefix,
suffix: input.suffix,
defaultMenuUrl: input.defaultMenuUrl
});
Loading
Loading