skillrepo 4.9.1 → 4.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/test/lib/http.test.mjs +60 -0
package/package.json
CHANGED
|
@@ -551,6 +551,66 @@ describe("getLibrary", () => {
|
|
|
551
551
|
}
|
|
552
552
|
});
|
|
553
553
|
|
|
554
|
+
// ── Wire identity (#2358 — skillset epic no-file contract) ──────────
|
|
555
|
+
//
|
|
556
|
+
// The skillset epic's D2 contract: a repo with no skillset declaration
|
|
557
|
+
// must produce request/receipt payloads byte-identical to the
|
|
558
|
+
// pre-skillset CLI, forever. These tests capture today's wire shape so
|
|
559
|
+
// any future change to it — a new query param, a pin/skillset header —
|
|
560
|
+
// fails here first and has to be made deliberately.
|
|
561
|
+
|
|
562
|
+
it("wire identity: a plain sync sends the exact pre-skillset request shape (#2358)", async () => {
|
|
563
|
+
let captured;
|
|
564
|
+
const srv = await startServer((req, res) => {
|
|
565
|
+
captured = { url: req.url, method: req.method, headers: { ...req.headers } };
|
|
566
|
+
jsonRes(res, 200, { skills: [], removals: [], syncedAt: "x" });
|
|
567
|
+
});
|
|
568
|
+
try {
|
|
569
|
+
await getLibrary(srv.url, VALID_KEY);
|
|
570
|
+
|
|
571
|
+
// Exact path — no query string at all on a plain sync.
|
|
572
|
+
assert.equal(captured.url, "/api/v1/library");
|
|
573
|
+
assert.equal(captured.method, "GET");
|
|
574
|
+
// Auth rides the Authorization header, and no pin/skillset-shaped
|
|
575
|
+
// vocabulary appears in any header name or value.
|
|
576
|
+
assert.match(captured.headers.authorization, /^Bearer /);
|
|
577
|
+
const headerBlob = JSON.stringify(captured.headers);
|
|
578
|
+
assert.doesNotMatch(headerBlob, /skillset|approved|pin/i);
|
|
579
|
+
} finally {
|
|
580
|
+
await srv.close();
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
it("wire identity: a pin-suffixed ETag round-trips verbatim as an opaque string (#2358)", async () => {
|
|
585
|
+
// Servers emit `"{ts}-{count}-{removals}-p{ts}-{n}"` for accounts
|
|
586
|
+
// with pin history. The CLI must treat every ETag as opaque: store
|
|
587
|
+
// it exactly, send it back exactly. A client that parsed the legacy
|
|
588
|
+
// three-segment shape would corrupt the conditional-GET cycle for
|
|
589
|
+
// pinned accounts.
|
|
590
|
+
const SUFFIXED = '"1754680000000-12-3-p1754690000000-2"';
|
|
591
|
+
let conditional;
|
|
592
|
+
const srv = await startServer((req, res) => {
|
|
593
|
+
if (req.headers["if-none-match"]) {
|
|
594
|
+
conditional = req.headers["if-none-match"];
|
|
595
|
+
res.statusCode = 304;
|
|
596
|
+
res.end();
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
jsonRes(res, 200, { skills: [], removals: [], syncedAt: "x" }, { ETag: SUFFIXED });
|
|
600
|
+
});
|
|
601
|
+
try {
|
|
602
|
+
const first = await getLibrary(srv.url, VALID_KEY);
|
|
603
|
+
assert.equal(first.etag, SUFFIXED);
|
|
604
|
+
|
|
605
|
+
const second = await getLibrary(srv.url, VALID_KEY, { ifNoneMatch: first.etag });
|
|
606
|
+
assert.equal(conditional, SUFFIXED);
|
|
607
|
+
assert.equal(second.notModified, true);
|
|
608
|
+
assert.equal(second.etag, SUFFIXED);
|
|
609
|
+
} finally {
|
|
610
|
+
await srv.close();
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
|
|
554
614
|
it("throws authError on 401", async () => {
|
|
555
615
|
const srv = await startServer((req, res) => jsonRes(res, 401, { error: "nope" }));
|
|
556
616
|
try {
|