feat(generators): byte-identical snapshot machinery + realtime snapshot
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
[
|
||||
{
|
||||
"path": "AGENTS.md",
|
||||
"sha256": "2a9e6bab1f14016d687c20ed4ec5087004cab2c5045aaf4bd0be84e0fe57da4d"
|
||||
},
|
||||
{
|
||||
"path": "eslint.config.js",
|
||||
"sha256": "64a85c158e386417d855793d256b9c59be38635ce2febcb5a6a15b17f4143745"
|
||||
},
|
||||
{
|
||||
"path": "package.json",
|
||||
"sha256": "ce70964118f988701e169f2df5fb5c558833dcf44204b0fa1d3c4641e67d45a3"
|
||||
},
|
||||
{
|
||||
"path": "src/authorize.test.ts",
|
||||
"sha256": "0030cc5ddb12a38a8de1c50b9973cdba09ac4055400e25983dc034dbe71193cb"
|
||||
},
|
||||
{
|
||||
"path": "src/authorize.ts",
|
||||
"sha256": "404c4b72f48000cb9fd8fc4ced7d782e9427e498ee5e492687b8076fdde3b642"
|
||||
},
|
||||
{
|
||||
"path": "src/channel-room.ts",
|
||||
"sha256": "a10260850326718e46c3cb848de8b30df886006020125aaf6516ea0224997329"
|
||||
},
|
||||
{
|
||||
"path": "src/channel-template.test.ts",
|
||||
"sha256": "35a7e15128d89885dcfd91a515a6de33324d0997540a4a1cd79719047e6bb711"
|
||||
},
|
||||
{
|
||||
"path": "src/channel-template.ts",
|
||||
"sha256": "f25a0a975a1d25629c8b07bad8dc8a5c113abdd4825ce72b11f59ca1df6f1f97"
|
||||
},
|
||||
{
|
||||
"path": "src/in-memory-realtime-broadcaster.test.ts",
|
||||
"sha256": "e61df5d86315d91f756be5d9af22642f96631ee1710e3e8e0d5d28699840483d"
|
||||
},
|
||||
{
|
||||
"path": "src/in-memory-realtime-broadcaster.ts",
|
||||
"sha256": "0e1f14a1227d3479fbfed899b930c0b5e4fef9197cd81eb4d49ccfad063d16fc"
|
||||
},
|
||||
{
|
||||
"path": "src/index.ts",
|
||||
"sha256": "a6600ba0d37658e40e9a29aef107d5375626dcb96abed2acfa424b1fbd81360d"
|
||||
},
|
||||
{
|
||||
"path": "src/realtime-authenticator.interface.ts",
|
||||
"sha256": "d5134e00f5381e3d6184575b515e29a2b0be86e35eab645c93d48aadde813467"
|
||||
},
|
||||
{
|
||||
"path": "src/realtime-broadcaster.interface.ts",
|
||||
"sha256": "83f79438dd18dfd34da886d2c0c9a01b5b8b6a5c0343476e42d4564eccf5535e"
|
||||
},
|
||||
{
|
||||
"path": "src/realtime-channel.test.ts",
|
||||
"sha256": "b48da304a506d34fff3fb313f9697c27922d3e16b3bb7e0f9f26503ab7b4d8a0"
|
||||
},
|
||||
{
|
||||
"path": "src/realtime-channel.ts",
|
||||
"sha256": "8a9764e2cbd6aa3019e82042b1ad7b33aeae64c80d35fdd29a1bd142c348ba59"
|
||||
},
|
||||
{
|
||||
"path": "src/realtime-handler-registry.test.ts",
|
||||
"sha256": "4a1a22639d772452848ec376e2cfbe5aa5eaa663168a058421c3d29e318f064e"
|
||||
},
|
||||
{
|
||||
"path": "src/realtime-handler-registry.ts",
|
||||
"sha256": "6726a36377d83d828f481febd38901611180071e28a8f3fa06aa735904bf7ee0"
|
||||
},
|
||||
{
|
||||
"path": "src/realtime-handler.interface.ts",
|
||||
"sha256": "c28f56e374281d93b39f50e6c74713afd25b6e51fa3891ad170d48e1c7de8343"
|
||||
},
|
||||
{
|
||||
"path": "src/realtime-ping.ts",
|
||||
"sha256": "2c68dc003865ba30ad0f9e2c1207030bc893151195df68e9c5d7358bdc68e08f"
|
||||
},
|
||||
{
|
||||
"path": "src/realtime-server.interface.ts",
|
||||
"sha256": "3928bcdc5e7e39048db554664ddaa3a8b444020ebc1d984f2eb6882ed3e7d5ef"
|
||||
},
|
||||
{
|
||||
"path": "src/socket-io-realtime-broadcaster.test.ts",
|
||||
"sha256": "1b1918f321e83196153a760da6193edd6a7d1cadc59e0947f97a598c3c2dd0e1"
|
||||
},
|
||||
{
|
||||
"path": "src/socket-io-realtime-broadcaster.ts",
|
||||
"sha256": "ae9d177b4d7bb47c2152b2b9ad2f5681d9ddcfb6fd09f2de565b55cd5837c7d7"
|
||||
},
|
||||
{
|
||||
"path": "src/socket-io-realtime-server.test.ts",
|
||||
"sha256": "ea13510ba1cfc8591c98336a00c598e1f756c2ca373bfaa705faf502752322e7"
|
||||
},
|
||||
{
|
||||
"path": "src/socket-io-realtime-server.ts",
|
||||
"sha256": "93b23af378de5bb2fe2be588a9e6d517f97ed68ab49c00ce4ff91ceb0d2553de"
|
||||
},
|
||||
{
|
||||
"path": "src/symbols.ts",
|
||||
"sha256": "3f899581aa6861a2e9e29127f4666cc701793cd478f4d25c5d537af0fd6db69d"
|
||||
},
|
||||
{
|
||||
"path": "tsconfig.json",
|
||||
"sha256": "739ba5cffa02bc348254cfe14829f8188ae1f67eb15d33a8e7a995331d39a58d"
|
||||
},
|
||||
{
|
||||
"path": "turbo.json",
|
||||
"sha256": "3b9d3e6a95048be20ff1eb2169abc76336390e7e5efc95250bab8a05ef27b4ce"
|
||||
},
|
||||
{
|
||||
"path": "vitest.config.ts",
|
||||
"sha256": "cc7a9e6aba7cbe81af665c3e1bf50f535f77a2b950db8ccc62775c7b5d380df7"
|
||||
}
|
||||
]
|
||||
19
turbo/generators/lib/snapshot.test.ts
Normal file
19
turbo/generators/lib/snapshot.test.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { mkdtempSync, mkdirSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { computeSnapshot } from "./snapshot";
|
||||
|
||||
describe("computeSnapshot", () => {
|
||||
it("returns sorted file paths + sha256 hashes", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "snapshot-"));
|
||||
mkdirSync(join(tmp, "src"));
|
||||
writeFileSync(join(tmp, "package.json"), `{ "name": "x" }\n`);
|
||||
writeFileSync(join(tmp, "src", "index.ts"), `export {};\n`);
|
||||
const snap = computeSnapshot(tmp);
|
||||
expect(snap).toEqual([
|
||||
{ path: "package.json", sha256: expect.any(String) },
|
||||
{ path: "src/index.ts", sha256: expect.any(String) },
|
||||
]);
|
||||
});
|
||||
});
|
||||
33
turbo/generators/lib/snapshot.ts
Normal file
33
turbo/generators/lib/snapshot.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { readdirSync, readFileSync, statSync } from "node:fs";
|
||||
import { createHash } from "node:crypto";
|
||||
import { join, relative } from "node:path";
|
||||
|
||||
export type SnapshotEntry = { path: string; sha256: string };
|
||||
|
||||
/**
|
||||
* Recursively collect all files under root, sorted by relative path, with
|
||||
* sha256 of post-normalized contents (LF line endings, single trailing
|
||||
* newline). Used by the byte-identical reconstruction test.
|
||||
*/
|
||||
export function computeSnapshot(root: string): SnapshotEntry[] {
|
||||
const out: SnapshotEntry[] = [];
|
||||
walk(root, root, out);
|
||||
out.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
||||
return out;
|
||||
}
|
||||
|
||||
function walk(root: string, dir: string, out: SnapshotEntry[]): void {
|
||||
for (const name of readdirSync(dir)) {
|
||||
const full = join(dir, name);
|
||||
const stat = statSync(full);
|
||||
if (stat.isDirectory()) {
|
||||
if (name === "node_modules" || name === ".turbo") continue;
|
||||
walk(root, full, out);
|
||||
} else if (stat.isFile()) {
|
||||
const raw = readFileSync(full, "utf8");
|
||||
const normalized = raw.replace(/\r\n/g, "\n").replace(/\n*$/, "\n");
|
||||
const sha = createHash("sha256").update(normalized).digest("hex");
|
||||
out.push({ path: relative(root, full).replace(/\\/g, "/"), sha256: sha });
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user