nervur 0.21.4 → 0.22.0
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/README.md +215 -158
- package/dist/browser.js +4 -3
- package/dist/cli.js +16 -0
- package/dist/{being → core/being}/being.js +10 -0
- package/dist/{being → core/being}/faculty.js +5 -2
- package/dist/{being → core/being}/index.d.ts +1 -1
- package/dist/{being → core/being}/index.js +1 -1
- package/dist/{being → core/being}/kind.d.ts +2 -0
- package/dist/{being → core/being}/kind.js +6 -0
- package/dist/{being → core/being}/types.js +1 -1
- package/dist/{browser → core/browser}/index.d.ts +6 -5
- package/dist/{browser → core/browser}/index.js +10 -10
- package/dist/{browser → core/browser}/worker.d.ts +2 -3
- package/dist/{browser → core/browser}/worker.js +8 -11
- package/dist/{cli → core/cli}/command.d.ts +4 -4
- package/dist/{cli → core/cli}/command.js +116 -66
- package/dist/{cli → core/cli}/edge.js +4 -2
- package/dist/core/cli/harbor.d.ts +25 -0
- package/dist/{cli → core/cli}/harbor.js +45 -33
- package/dist/{contract → core/contract}/index.d.ts +6 -5
- package/dist/{contract → core/contract}/index.js +8 -9
- package/dist/core/contract/link.d.ts +4 -0
- package/dist/core/contract/link.js +45 -0
- package/dist/{crypto → core/crypto}/ed25519.js +22 -14
- package/dist/core/crypto/subtle.d.ts +3 -0
- package/dist/core/crypto/subtle.js +11 -0
- package/dist/core/crypto/x25519.js +24 -0
- package/dist/core/edge/index.d.ts +164 -0
- package/dist/core/edge/index.js +739 -0
- package/dist/core/edge/kit.d.ts +2 -0
- package/dist/core/edge/kit.js +2 -0
- package/dist/core/git/http.d.ts +6 -0
- package/dist/core/git/http.js +102 -0
- package/dist/core/git/index.d.ts +5 -0
- package/dist/core/git/index.js +10 -0
- package/dist/core/git/object.d.ts +40 -0
- package/dist/core/git/object.js +103 -0
- package/dist/core/git/pack.d.ts +9 -0
- package/dist/core/git/pack.js +171 -0
- package/dist/core/git/store.d.ts +23 -0
- package/dist/core/git/store.js +120 -0
- package/dist/core/git/zlib.d.ts +6 -0
- package/dist/core/git/zlib.js +210 -0
- package/dist/core/harbor/carrying.d.ts +51 -0
- package/dist/core/harbor/carrying.js +69 -0
- package/dist/core/harbor/catalogue.d.ts +33 -0
- package/dist/core/harbor/catalogue.js +365 -0
- package/dist/core/harbor/dna.d.ts +13 -0
- package/dist/core/harbor/dna.js +120 -0
- package/dist/{harbor → core/harbor}/dock.d.ts +22 -13
- package/dist/core/harbor/dock.js +381 -0
- package/dist/core/harbor/harbor.d.ts +16 -0
- package/dist/core/harbor/harbor.js +438 -0
- package/dist/core/harbor/index.d.ts +11 -0
- package/dist/{harbor → core/harbor}/index.js +5 -5
- package/dist/core/harbor/memory.d.ts +10 -0
- package/dist/core/harbor/memory.js +25 -0
- package/dist/{harbor → core/harbor}/package.d.ts +0 -1
- package/dist/{harbor → core/harbor}/package.js +9 -9
- package/dist/core/harbor/probe.d.ts +22 -0
- package/dist/core/harbor/probe.js +15 -0
- package/dist/core/harbor/registry.d.ts +15 -0
- package/dist/{harbor → core/harbor}/registry.js +26 -10
- package/dist/core/harbor/root-line.d.ts +7 -0
- package/dist/core/harbor/root-line.js +9 -0
- package/dist/{harbor → core/harbor}/terrain.d.ts +9 -6
- package/dist/{harbor → core/harbor}/terrain.js +5 -4
- package/dist/core/http/index.d.ts +2 -0
- package/dist/{http → core/http}/index.js +3 -5
- package/dist/{line → core/line}/answer.d.ts +2 -2
- package/dist/{line → core/line}/frame.d.ts +0 -5
- package/dist/{line → core/line}/frame.js +0 -4
- package/dist/core/line/ground.js +7 -0
- package/dist/core/line/index.d.ts +4 -0
- package/dist/core/line/index.js +8 -0
- package/dist/core/line/web.d.ts +12 -0
- package/dist/{line → core/line}/web.js +13 -77
- package/dist/{node → core/node}/index.d.ts +2 -15
- package/dist/core/node/index.js +124 -0
- package/dist/{pointer → core/pointer}/bodies.d.ts +7 -5
- package/dist/core/pointer/bodies.js +118 -0
- package/dist/core/pointer/index.d.ts +2 -0
- package/dist/{pointer → core/pointer}/index.js +1 -1
- package/dist/{pointer → core/pointer}/world.d.ts +13 -9
- package/dist/{pointer → core/pointer}/world.js +31 -16
- package/dist/{proof → core/proof}/contracts.d.ts +6 -2
- package/dist/{proof → core/proof}/contracts.js +11 -10
- package/dist/core/proof/index.d.ts +3 -0
- package/dist/{proof → core/proof}/index.js +2 -2
- package/dist/core/proof/law.d.ts +25 -0
- package/dist/core/proof/law.js +715 -0
- package/dist/{tcp → core/tcp}/index.d.ts +7 -4
- package/dist/{tcp → core/tcp}/index.js +11 -62
- package/dist/{ward/ward.d.ts → core/ward/house.d.ts} +24 -10
- package/dist/core/ward/house.js +473 -0
- package/dist/core/ward/index.d.ts +5 -0
- package/dist/core/ward/index.js +7 -0
- package/dist/{ward → core/ward}/partition.d.ts +1 -0
- package/dist/{ward → core/ward}/stance.d.ts +2 -2
- package/dist/{ward → core/ward}/stance.js +5 -2
- package/dist/{ward/ward-being.d.ts → core/ward/ward.d.ts} +14 -6
- package/dist/core/ward/ward.js +140 -0
- package/dist/core.d.ts +10 -0
- package/dist/core.js +19 -0
- package/dist/defaults/dock/index.d.ts +4 -0
- package/dist/defaults/dock/index.js +11 -0
- package/dist/defaults/index.d.ts +5 -0
- package/dist/defaults/index.js +10 -0
- package/dist/defaults/memory/index.d.ts +12 -0
- package/dist/defaults/memory/index.js +39 -0
- package/dist/defaults/tcp/index.d.ts +16 -0
- package/dist/defaults/tcp/index.js +82 -0
- package/dist/defaults/ward/index.d.ts +4 -0
- package/dist/defaults/ward/index.js +11 -0
- package/dist/defaults/web/index.d.ts +15 -0
- package/dist/defaults/web/index.js +90 -0
- package/dist/edge.js +4 -3
- package/dist/index.d.ts +1 -8
- package/dist/index.js +13 -18
- package/dist/kit.d.ts +4 -0
- package/dist/kit.js +12 -0
- package/dist/node.js +4 -3
- package/package.json +23 -18
- package/src/browser.ts +4 -3
- package/src/cli.ts +15 -0
- package/src/{being → core/being}/being.ts +4 -0
- package/src/{being → core/being}/faculty.ts +5 -2
- package/src/{being → core/being}/index.ts +1 -1
- package/src/{being → core/being}/kind.ts +7 -0
- package/src/{being → core/being}/types.ts +1 -1
- package/src/{browser → core/browser}/index.ts +16 -13
- package/src/{browser → core/browser}/worker.ts +11 -14
- package/src/{cli → core/cli}/command.ts +113 -66
- package/src/{cli → core/cli}/edge.ts +4 -2
- package/src/{cli → core/cli}/harbor.ts +48 -31
- package/src/{contract → core/contract}/index.ts +14 -14
- package/src/core/contract/link.ts +58 -0
- package/src/{crypto → core/crypto}/ed25519.ts +22 -14
- package/src/core/crypto/subtle.ts +13 -0
- package/src/core/crypto/x25519.ts +23 -0
- package/src/core/edge/index.ts +865 -0
- package/src/core/git/http.ts +103 -0
- package/src/core/git/index.ts +10 -0
- package/src/core/git/object.ts +116 -0
- package/src/core/git/pack.ts +147 -0
- package/src/core/git/store.ts +122 -0
- package/src/core/git/zlib.ts +197 -0
- package/src/core/harbor/carrying.ts +124 -0
- package/src/core/harbor/catalogue.ts +386 -0
- package/src/core/harbor/dna.ts +116 -0
- package/src/core/harbor/dock.ts +420 -0
- package/src/core/harbor/harbor.ts +433 -0
- package/src/core/harbor/index.ts +14 -0
- package/src/core/harbor/memory.ts +31 -0
- package/src/{harbor → core/harbor}/package.ts +15 -15
- package/src/core/harbor/probe.ts +39 -0
- package/src/{harbor → core/harbor}/registry.ts +28 -11
- package/src/core/harbor/root-line.ts +19 -0
- package/src/{harbor → core/harbor}/terrain.ts +14 -7
- package/src/{http → core/http}/index.ts +5 -8
- package/src/{line → core/line}/answer.ts +3 -2
- package/src/{line → core/line}/frame.ts +0 -5
- package/src/core/line/ground.ts +18 -0
- package/src/core/line/index.ts +8 -0
- package/src/{line → core/line}/web.ts +1 -105
- package/src/core/node/index.ts +139 -0
- package/src/core/pointer/bodies.ts +122 -0
- package/src/core/pointer/index.ts +4 -0
- package/src/{pointer → core/pointer}/world.ts +45 -21
- package/src/{proof → core/proof}/contracts.ts +18 -13
- package/src/{proof → core/proof}/index.ts +3 -3
- package/src/core/proof/law.ts +742 -0
- package/src/{stand → core/stand}/stand.ts +2 -2
- package/src/{tcp → core/tcp}/index.ts +17 -74
- package/src/core/ward/house.ts +524 -0
- package/src/core/ward/index.ts +7 -0
- package/src/{ward → core/ward}/partition.ts +5 -1
- package/src/{ward → core/ward}/stance.ts +5 -2
- package/src/core/ward/ward.ts +166 -0
- package/src/core.ts +55 -0
- package/src/defaults/dock/index.ts +12 -0
- package/src/defaults/index.ts +10 -0
- package/src/defaults/memory/index.ts +50 -0
- package/src/defaults/tcp/index.ts +89 -0
- package/src/defaults/ward/index.ts +12 -0
- package/src/defaults/web/index.ts +97 -0
- package/src/edge.ts +4 -3
- package/src/index.ts +13 -50
- package/src/kit.ts +15 -0
- package/src/node.ts +4 -3
- package/dist/cli/harbor.d.ts +0 -16
- package/dist/cli/main.js +0 -14
- package/dist/crypto/subtle.d.ts +0 -10
- package/dist/crypto/subtle.js +0 -29
- package/dist/crypto/x25519.js +0 -21
- package/dist/edge/index.d.ts +0 -81
- package/dist/edge/index.js +0 -400
- package/dist/harbor/carrying.d.ts +0 -17
- package/dist/harbor/carrying.js +0 -38
- package/dist/harbor/catalogue.d.ts +0 -28
- package/dist/harbor/catalogue.js +0 -109
- package/dist/harbor/dock.js +0 -236
- package/dist/harbor/harbor.d.ts +0 -45
- package/dist/harbor/harbor.js +0 -347
- package/dist/harbor/index.d.ts +0 -11
- package/dist/harbor/probe.d.ts +0 -18
- package/dist/harbor/probe.js +0 -15
- package/dist/harbor/registry.d.ts +0 -10
- package/dist/harbor/relay.d.ts +0 -15
- package/dist/harbor/relay.js +0 -406
- package/dist/harbor/root-line.d.ts +0 -9
- package/dist/harbor/root-line.js +0 -38
- package/dist/harbor/store.d.ts +0 -13
- package/dist/harbor/store.js +0 -53
- package/dist/http/index.d.ts +0 -4
- package/dist/line/ground.js +0 -9
- package/dist/line/index.d.ts +0 -5
- package/dist/line/index.js +0 -9
- package/dist/line/push.d.ts +0 -7
- package/dist/line/push.js +0 -92
- package/dist/line/web.d.ts +0 -30
- package/dist/node/index.js +0 -236
- package/dist/pointer/bodies.js +0 -80
- package/dist/pointer/index.d.ts +0 -2
- package/dist/proof/index.d.ts +0 -3
- package/dist/proof/law.d.ts +0 -90
- package/dist/proof/law.js +0 -591
- package/dist/tcp/frame.d.ts +0 -25
- package/dist/tcp/frame.js +0 -64
- package/dist/ward/index.d.ts +0 -6
- package/dist/ward/index.js +0 -8
- package/dist/ward/pilot.d.ts +0 -8
- package/dist/ward/pilot.js +0 -50
- package/dist/ward/ward-being.js +0 -82
- package/dist/ward/ward.js +0 -290
- package/src/cli/main.ts +0 -13
- package/src/crypto/subtle.ts +0 -33
- package/src/crypto/x25519.ts +0 -21
- package/src/edge/index.ts +0 -490
- package/src/harbor/carrying.ts +0 -56
- package/src/harbor/catalogue.ts +0 -134
- package/src/harbor/dock.ts +0 -265
- package/src/harbor/harbor.ts +0 -381
- package/src/harbor/index.ts +0 -14
- package/src/harbor/probe.ts +0 -34
- package/src/harbor/relay.ts +0 -418
- package/src/harbor/root-line.ts +0 -39
- package/src/harbor/store.ts +0 -69
- package/src/line/ground.ts +0 -19
- package/src/line/index.ts +0 -9
- package/src/line/push.ts +0 -112
- package/src/node/index.ts +0 -241
- package/src/pointer/bodies.ts +0 -82
- package/src/pointer/index.ts +0 -4
- package/src/proof/law.ts +0 -591
- package/src/ward/index.ts +0 -8
- package/src/ward/pilot.ts +0 -50
- package/src/ward/ward-being.ts +0 -103
- package/src/ward/ward.ts +0 -328
- /package/dist/{cli/main.d.ts → cli.d.ts} +0 -0
- /package/dist/{being → core/being}/being.d.ts +0 -0
- /package/dist/{being → core/being}/digest.d.ts +0 -0
- /package/dist/{being → core/being}/digest.js +0 -0
- /package/dist/{being → core/being}/faculty.d.ts +0 -0
- /package/dist/{being → core/being}/types.d.ts +0 -0
- /package/dist/{being → core/being}/words.d.ts +0 -0
- /package/dist/{being → core/being}/words.js +0 -0
- /package/dist/{cli → core/cli}/edge.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/aes.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/aes.js +0 -0
- /package/dist/{crypto → core/crypto}/bytes.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/bytes.js +0 -0
- /package/dist/{crypto → core/crypto}/ed25519.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/hash.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/hash.js +0 -0
- /package/dist/{crypto → core/crypto}/index.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/index.js +0 -0
- /package/dist/{crypto → core/crypto}/json.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/json.js +0 -0
- /package/dist/{crypto → core/crypto}/mlkem.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/mlkem.js +0 -0
- /package/dist/{crypto → core/crypto}/x25519.d.ts +0 -0
- /package/dist/{folder → core/folder}/index.d.ts +0 -0
- /package/dist/{folder → core/folder}/index.js +0 -0
- /package/dist/{http → core/http}/websocket.d.ts +0 -0
- /package/dist/{http → core/http}/websocket.js +0 -0
- /package/dist/{line → core/line}/answer.js +0 -0
- /package/dist/{line → core/line}/ground.d.ts +0 -0
- /package/dist/{proof → core/proof}/expect.d.ts +0 -0
- /package/dist/{proof → core/proof}/expect.js +0 -0
- /package/dist/{quo → core/quo}/address.d.ts +0 -0
- /package/dist/{quo → core/quo}/address.js +0 -0
- /package/dist/{quo → core/quo}/door.d.ts +0 -0
- /package/dist/{quo → core/quo}/door.js +0 -0
- /package/dist/{quo → core/quo}/index.d.ts +0 -0
- /package/dist/{quo → core/quo}/index.js +0 -0
- /package/dist/{quo → core/quo}/invitation.d.ts +0 -0
- /package/dist/{quo → core/quo}/invitation.js +0 -0
- /package/dist/{quo → core/quo}/keys.d.ts +0 -0
- /package/dist/{quo → core/quo}/keys.js +0 -0
- /package/dist/{quo → core/quo}/payload.d.ts +0 -0
- /package/dist/{quo → core/quo}/payload.js +0 -0
- /package/dist/{quo → core/quo}/relations.d.ts +0 -0
- /package/dist/{quo → core/quo}/relations.js +0 -0
- /package/dist/{quo → core/quo}/reply.d.ts +0 -0
- /package/dist/{quo → core/quo}/reply.js +0 -0
- /package/dist/{quo → core/quo}/seal.d.ts +0 -0
- /package/dist/{quo → core/quo}/seal.js +0 -0
- /package/dist/{quo → core/quo}/standing.d.ts +0 -0
- /package/dist/{quo → core/quo}/standing.js +0 -0
- /package/dist/{ward → core/ward}/allowance.d.ts +0 -0
- /package/dist/{ward → core/ward}/allowance.js +0 -0
- /package/dist/{ward → core/ward}/cells.d.ts +0 -0
- /package/dist/{ward → core/ward}/cells.js +0 -0
- /package/dist/{ward → core/ward}/partition.js +0 -0
- /package/src/{being → core/being}/digest.ts +0 -0
- /package/src/{being → core/being}/words.ts +0 -0
- /package/src/{crypto → core/crypto}/aes.ts +0 -0
- /package/src/{crypto → core/crypto}/bytes.ts +0 -0
- /package/src/{crypto → core/crypto}/hash.ts +0 -0
- /package/src/{crypto → core/crypto}/index.ts +0 -0
- /package/src/{crypto → core/crypto}/json.ts +0 -0
- /package/src/{crypto → core/crypto}/mlkem.ts +0 -0
- /package/src/{folder → core/folder}/index.ts +0 -0
- /package/src/{http → core/http}/websocket.ts +0 -0
- /package/src/{proof → core/proof}/expect.ts +0 -0
- /package/src/{quo → core/quo}/address.ts +0 -0
- /package/src/{quo → core/quo}/door.ts +0 -0
- /package/src/{quo → core/quo}/index.ts +0 -0
- /package/src/{quo → core/quo}/invitation.ts +0 -0
- /package/src/{quo → core/quo}/keys.ts +0 -0
- /package/src/{quo → core/quo}/payload.ts +0 -0
- /package/src/{quo → core/quo}/relations.ts +0 -0
- /package/src/{quo → core/quo}/reply.ts +0 -0
- /package/src/{quo → core/quo}/seal.ts +0 -0
- /package/src/{quo → core/quo}/standing.ts +0 -0
- /package/src/{stand → core/stand}/main.ts +0 -0
- /package/src/{ward → core/ward}/allowance.ts +0 -0
- /package/src/{ward → core/ward}/cells.ts +0 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Git's objects, byte for byte as git writes them: a blob, a tree and a
|
|
3
|
+
// commit, each named by the SHA-1 of `<type> <size>\0` and its body.
|
|
4
|
+
//
|
|
5
|
+
// tree one entry after another, `<mode> <name>\0` and the 20 bytes of
|
|
6
|
+
// its id, sorted by name as git sorts, a tree's name read with
|
|
7
|
+
// a `/` after it
|
|
8
|
+
// commit `tree`, each `parent`, `author` and `committer` lines, a blank
|
|
9
|
+
// line, and the message
|
|
10
|
+
import { concat, hex, unhex, utf8 } from '../crypto/bytes.js';
|
|
11
|
+
import { own, subtle } from '../crypto/subtle.js';
|
|
12
|
+
import { deflate, inflate } from './zlib.js';
|
|
13
|
+
export const TYPES = ['blob', 'tree', 'commit', 'tag'];
|
|
14
|
+
// The tree with no entry, which every empty commit names.
|
|
15
|
+
export const EMPTY_TREE = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
|
|
16
|
+
const decoder = new TextDecoder('utf-8', { fatal: true });
|
|
17
|
+
export const text = (bytes) => decoder.decode(bytes);
|
|
18
|
+
export const sha1 = async (bytes) => hex(new Uint8Array(await subtle().digest('SHA-1', own(bytes))));
|
|
19
|
+
export const isId = (value) => typeof value === 'string' && /^[0-9a-f]{40}$/.test(value);
|
|
20
|
+
// An object as git keeps it loose, before it is deflated.
|
|
21
|
+
export const loose = (o) => concat(utf8(`${o.type} ${String(o.body.length)}\0`), o.body);
|
|
22
|
+
export const idOf = (o) => sha1(loose(o));
|
|
23
|
+
export const readLoose = (bytes) => {
|
|
24
|
+
const nul = bytes.indexOf(0);
|
|
25
|
+
const head = nul < 0 ? '' : text(bytes.subarray(0, nul));
|
|
26
|
+
const [type, size] = head.split(' ');
|
|
27
|
+
const body = bytes.subarray(nul + 1);
|
|
28
|
+
if (!TYPES.includes(type) || String(body.length) !== size)
|
|
29
|
+
throw new Error('no loose object');
|
|
30
|
+
return { type: type, body: body.slice() };
|
|
31
|
+
};
|
|
32
|
+
// The file git writes under `.git/objects/`, and the object it holds.
|
|
33
|
+
export const deflated = (o) => deflate(loose(o));
|
|
34
|
+
export const inflated = async (bytes) => readLoose(await inflate(bytes));
|
|
35
|
+
export const blob = (source) => ({ type: 'blob', body: utf8(source) });
|
|
36
|
+
export const FILE = '100644';
|
|
37
|
+
export const DIRECTORY = '40000';
|
|
38
|
+
const sortName = (e) => (e.mode === DIRECTORY ? `${e.name}/` : e.name);
|
|
39
|
+
const byName = (a, b) => {
|
|
40
|
+
const [x, y] = [utf8(sortName(a)), utf8(sortName(b))];
|
|
41
|
+
for (let k = 0; k < Math.min(x.length, y.length); k += 1)
|
|
42
|
+
if (x[k] !== y[k])
|
|
43
|
+
return x[k] - y[k];
|
|
44
|
+
return x.length - y.length;
|
|
45
|
+
};
|
|
46
|
+
export const tree = (entries) => ({
|
|
47
|
+
type: 'tree',
|
|
48
|
+
body: concat(...[...entries].sort(byName).flatMap((e) => [utf8(`${e.mode} ${e.name}\0`), unhex(e.id)])),
|
|
49
|
+
});
|
|
50
|
+
export const readTree = (o) => {
|
|
51
|
+
if (o.type !== 'tree')
|
|
52
|
+
throw new Error('no tree');
|
|
53
|
+
const entries = [];
|
|
54
|
+
for (let at = 0; at < o.body.length;) {
|
|
55
|
+
const space = o.body.indexOf(0x20, at);
|
|
56
|
+
const nul = o.body.indexOf(0, space);
|
|
57
|
+
if (space < 0 || nul < 0 || nul + 21 > o.body.length)
|
|
58
|
+
throw new Error('a tree cut short');
|
|
59
|
+
entries.push({ mode: text(o.body.subarray(at, space)), name: text(o.body.subarray(space + 1, nul)), id: hex(o.body.subarray(nul + 1, nul + 21)) });
|
|
60
|
+
at = nul + 21;
|
|
61
|
+
}
|
|
62
|
+
return entries;
|
|
63
|
+
};
|
|
64
|
+
const signed = (s) => `${s.name} <${s.email}> ${String(s.seconds)} ${s.zone}`;
|
|
65
|
+
const readSigned = (line) => {
|
|
66
|
+
const m = /^(.*) <([^>]*)> (\d+) ([+-]\d{4})$/.exec(line);
|
|
67
|
+
if (!m)
|
|
68
|
+
throw new Error('a signature git does not write');
|
|
69
|
+
return { name: m[1], email: m[2], seconds: Number(m[3]), zone: m[4] };
|
|
70
|
+
};
|
|
71
|
+
export const commit = (c) => ({
|
|
72
|
+
type: 'commit',
|
|
73
|
+
body: utf8([`tree ${c.tree}`, ...c.parents.map((p) => `parent ${p}`), `author ${signed(c.author)}`, `committer ${signed(c.committer)}`, '', c.message].join('\n')),
|
|
74
|
+
});
|
|
75
|
+
// A commit's own headers, read; a header it does not name, a signature
|
|
76
|
+
// among them, is kept in the bytes and read past.
|
|
77
|
+
export const readCommit = (o) => {
|
|
78
|
+
if (o.type !== 'commit')
|
|
79
|
+
throw new Error('no commit');
|
|
80
|
+
const all = text(o.body);
|
|
81
|
+
const blank = all.indexOf('\n\n');
|
|
82
|
+
const head = blank < 0 ? all : all.slice(0, blank);
|
|
83
|
+
const message = blank < 0 ? '' : all.slice(blank + 2);
|
|
84
|
+
let root;
|
|
85
|
+
const parents = [];
|
|
86
|
+
let author;
|
|
87
|
+
let committer;
|
|
88
|
+
for (const line of head.split('\n')) {
|
|
89
|
+
const space = line.indexOf(' ');
|
|
90
|
+
const [key, value] = [line.slice(0, space), line.slice(space + 1)];
|
|
91
|
+
if (key === 'tree')
|
|
92
|
+
root = value;
|
|
93
|
+
else if (key === 'parent')
|
|
94
|
+
parents.push(value);
|
|
95
|
+
else if (key === 'author')
|
|
96
|
+
author = readSigned(value);
|
|
97
|
+
else if (key === 'committer')
|
|
98
|
+
committer = readSigned(value);
|
|
99
|
+
}
|
|
100
|
+
if (!isId(root) || !author || !committer || !parents.every(isId))
|
|
101
|
+
throw new Error('a commit git does not write');
|
|
102
|
+
return { tree: root, parents, author, committer, message };
|
|
103
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type GitObject } from './object.ts';
|
|
2
|
+
export declare const applyDelta: (base: Uint8Array, delta: Uint8Array) => Uint8Array;
|
|
3
|
+
export declare const readPack: (pack: Uint8Array, outside?: (id: string) => Promise<GitObject | null>) => Promise<Map<string, GitObject>>;
|
|
4
|
+
export declare const pkt: (line: string) => Uint8Array;
|
|
5
|
+
export declare const FLUSH: Uint8Array<ArrayBufferLike>;
|
|
6
|
+
export declare const readPkts: (bytes: Uint8Array, at?: number, stop?: (_line: string) => boolean) => {
|
|
7
|
+
lines: string[];
|
|
8
|
+
end: number;
|
|
9
|
+
};
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// A packfile, version 2, read into its objects: each entry a header of its
|
|
3
|
+
// type and size, then a zlib stream, and a SHA-1 of it all at the end. A
|
|
4
|
+
// delta names its base by the distance back to it in the pack, OFS_DELTA,
|
|
5
|
+
// or by its id, REF_DELTA, which may name an object the reader holds
|
|
6
|
+
// already.
|
|
7
|
+
import { hex, utf8 } from '../crypto/bytes.js';
|
|
8
|
+
import { idOf, sha1 } from './object.js';
|
|
9
|
+
import { inflateAt } from './zlib.js';
|
|
10
|
+
const KINDS = { 1: 'commit', 2: 'tree', 3: 'blob', 4: 'tag' };
|
|
11
|
+
const OFS_DELTA = 6;
|
|
12
|
+
const REF_DELTA = 7;
|
|
13
|
+
// A delta's instructions laid over its base.
|
|
14
|
+
export const applyDelta = (base, delta) => {
|
|
15
|
+
let at = 0;
|
|
16
|
+
const size = () => {
|
|
17
|
+
let n = 0;
|
|
18
|
+
let shift = 0;
|
|
19
|
+
for (let b = 0x80; b & 0x80; shift += 7) {
|
|
20
|
+
b = delta[at++];
|
|
21
|
+
n += (b & 0x7f) * 2 ** shift;
|
|
22
|
+
}
|
|
23
|
+
return n;
|
|
24
|
+
};
|
|
25
|
+
if (size() !== base.length)
|
|
26
|
+
throw new Error('a delta for another base');
|
|
27
|
+
const out = new Uint8Array(size());
|
|
28
|
+
let written = 0;
|
|
29
|
+
while (at < delta.length) {
|
|
30
|
+
const op = delta[at++];
|
|
31
|
+
if (op & 0x80) {
|
|
32
|
+
let offset = 0;
|
|
33
|
+
let length = 0;
|
|
34
|
+
for (let k = 0; k < 4; k += 1)
|
|
35
|
+
if (op & (1 << k))
|
|
36
|
+
offset |= delta[at++] << (8 * k);
|
|
37
|
+
for (let k = 0; k < 3; k += 1)
|
|
38
|
+
if (op & (0x10 << k))
|
|
39
|
+
length |= delta[at++] << (8 * k);
|
|
40
|
+
if (length === 0)
|
|
41
|
+
length = 0x10000;
|
|
42
|
+
offset >>>= 0;
|
|
43
|
+
if (offset + length > base.length || written + length > out.length)
|
|
44
|
+
throw new Error('a delta copy past its bounds');
|
|
45
|
+
out.set(base.subarray(offset, offset + length), written);
|
|
46
|
+
written += length;
|
|
47
|
+
}
|
|
48
|
+
else if (op !== 0) {
|
|
49
|
+
if (at + op > delta.length || written + op > out.length)
|
|
50
|
+
throw new Error('a delta insert past its bounds');
|
|
51
|
+
out.set(delta.subarray(at, at + op), written);
|
|
52
|
+
written += op;
|
|
53
|
+
at += op;
|
|
54
|
+
}
|
|
55
|
+
else
|
|
56
|
+
throw new Error('a delta op of nothing');
|
|
57
|
+
}
|
|
58
|
+
if (written !== out.length)
|
|
59
|
+
throw new Error('a delta short of its size');
|
|
60
|
+
return out;
|
|
61
|
+
};
|
|
62
|
+
// Every object a pack holds, by id. `outside` finds a REF_DELTA's base the
|
|
63
|
+
// pack does not carry.
|
|
64
|
+
export const readPack = async (pack, outside = () => Promise.resolve(null)) => {
|
|
65
|
+
if (pack.length < 32 || new TextDecoder().decode(pack.subarray(0, 4)) !== 'PACK')
|
|
66
|
+
throw new Error('no pack');
|
|
67
|
+
const word = (at) => ((pack[at] << 24) | (pack[at + 1] << 16) | (pack[at + 2] << 8) | pack[at + 3]) >>> 0;
|
|
68
|
+
if (word(4) !== 2)
|
|
69
|
+
throw new Error('a pack of another version');
|
|
70
|
+
const count = word(8);
|
|
71
|
+
const body = pack.subarray(0, pack.length - 20);
|
|
72
|
+
if ((await sha1(body)) !== hex(pack.subarray(pack.length - 20)))
|
|
73
|
+
throw new Error('a pack whose sum does not check');
|
|
74
|
+
const entries = new Map();
|
|
75
|
+
let at = 12;
|
|
76
|
+
for (let n = 0; n < count; n += 1) {
|
|
77
|
+
const start = at;
|
|
78
|
+
let b = pack[at++];
|
|
79
|
+
const type = (b >> 4) & 7;
|
|
80
|
+
let size = b & 15;
|
|
81
|
+
for (let shift = 4; b & 0x80; shift += 7) {
|
|
82
|
+
b = pack[at++];
|
|
83
|
+
size += (b & 0x7f) * 2 ** shift;
|
|
84
|
+
}
|
|
85
|
+
let base;
|
|
86
|
+
if (type === OFS_DELTA) {
|
|
87
|
+
b = pack[at++];
|
|
88
|
+
let back = b & 0x7f;
|
|
89
|
+
while (b & 0x80) {
|
|
90
|
+
b = pack[at++];
|
|
91
|
+
back = (back + 1) * 128 + (b & 0x7f);
|
|
92
|
+
}
|
|
93
|
+
base = start - back;
|
|
94
|
+
}
|
|
95
|
+
else if (type === REF_DELTA) {
|
|
96
|
+
base = hex(pack.subarray(at, at + 20));
|
|
97
|
+
at += 20;
|
|
98
|
+
}
|
|
99
|
+
else if (!KINDS[type])
|
|
100
|
+
throw new Error(`a pack entry of type ${String(type)}`);
|
|
101
|
+
const { out, end } = inflateAt(body, at);
|
|
102
|
+
if (out.length !== size)
|
|
103
|
+
throw new Error('a pack entry of another size');
|
|
104
|
+
at = end;
|
|
105
|
+
entries.set(start, { type, data: out, ...(base === undefined ? {} : { base }) });
|
|
106
|
+
}
|
|
107
|
+
if (at !== body.length)
|
|
108
|
+
throw new Error('a pack with bytes past its objects');
|
|
109
|
+
// Pass after pass, every entry whose base stands now is laid over it,
|
|
110
|
+
// until every entry stands or a pass stands none.
|
|
111
|
+
const byOffset = new Map();
|
|
112
|
+
const byId = new Map();
|
|
113
|
+
const outsiders = new Map();
|
|
114
|
+
const baseOf = async (base) => {
|
|
115
|
+
if (typeof base === 'number')
|
|
116
|
+
return byOffset.get(base);
|
|
117
|
+
const inside = byId.get(base);
|
|
118
|
+
if (inside)
|
|
119
|
+
return inside;
|
|
120
|
+
if (!outsiders.has(base))
|
|
121
|
+
outsiders.set(base, await outside(base));
|
|
122
|
+
return outsiders.get(base) ?? undefined;
|
|
123
|
+
};
|
|
124
|
+
while (byOffset.size < entries.size) {
|
|
125
|
+
const before = byOffset.size;
|
|
126
|
+
for (const [offset, e] of entries) {
|
|
127
|
+
if (byOffset.has(offset))
|
|
128
|
+
continue;
|
|
129
|
+
let o;
|
|
130
|
+
if (e.base === undefined)
|
|
131
|
+
o = { type: KINDS[e.type], body: e.data };
|
|
132
|
+
else {
|
|
133
|
+
const base = await baseOf(e.base);
|
|
134
|
+
if (!base)
|
|
135
|
+
continue;
|
|
136
|
+
o = { type: base.type, body: applyDelta(base.body, e.data) };
|
|
137
|
+
}
|
|
138
|
+
byOffset.set(offset, o);
|
|
139
|
+
byId.set(await idOf(o), o);
|
|
140
|
+
}
|
|
141
|
+
if (byOffset.size === before)
|
|
142
|
+
throw new Error('a delta whose base is nowhere');
|
|
143
|
+
}
|
|
144
|
+
return byId;
|
|
145
|
+
};
|
|
146
|
+
// pkt-lines, as git's protocols frame them: four hex digits of length,
|
|
147
|
+
// itself counted, and `0000` for a flush.
|
|
148
|
+
export const pkt = (line) => {
|
|
149
|
+
const bytes = utf8(line);
|
|
150
|
+
return new Uint8Array([...utf8((bytes.length + 4).toString(16).padStart(4, '0')), ...bytes]);
|
|
151
|
+
};
|
|
152
|
+
export const FLUSH = utf8('0000');
|
|
153
|
+
// The lines of a pkt-line stream up to its first flush, and where it ends.
|
|
154
|
+
export const readPkts = (bytes, at = 0, stop = (_line) => false) => {
|
|
155
|
+
const lines = [];
|
|
156
|
+
while (at + 4 <= bytes.length) {
|
|
157
|
+
const length = parseInt(new TextDecoder().decode(bytes.subarray(at, at + 4)), 16);
|
|
158
|
+
if (Number.isNaN(length))
|
|
159
|
+
throw new Error('no pkt-line');
|
|
160
|
+
if (length === 0)
|
|
161
|
+
return { lines, end: at + 4 };
|
|
162
|
+
if (length < 4 || at + length > bytes.length)
|
|
163
|
+
throw new Error('a pkt-line cut short');
|
|
164
|
+
const line = new TextDecoder().decode(bytes.subarray(at + 4, at + length));
|
|
165
|
+
lines.push(line);
|
|
166
|
+
at += length;
|
|
167
|
+
if (stop(line))
|
|
168
|
+
return { lines, end: at };
|
|
169
|
+
}
|
|
170
|
+
return { lines, end: at };
|
|
171
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Commit, type GitObject } from './object.ts';
|
|
2
|
+
export interface ObjectStore {
|
|
3
|
+
get(id: string): Promise<GitObject | null>;
|
|
4
|
+
put(objects: readonly GitObject[]): Promise<string[]>;
|
|
5
|
+
}
|
|
6
|
+
export declare const need: (store: ObjectStore, id: string, type: GitObject['type']) => Promise<GitObject>;
|
|
7
|
+
export declare const files: (store: ObjectStore, id: string) => Promise<Map<string, string>>;
|
|
8
|
+
export declare const writeTree: (store: ObjectStore, paths: ReadonlyMap<string, string>) => Promise<string>;
|
|
9
|
+
export declare const writeCommit: (store: ObjectStore, c: Commit) => Promise<string>;
|
|
10
|
+
export declare const reachable: (store: ObjectStore, from: string) => Promise<string[]>;
|
|
11
|
+
export declare class HeldObjects implements ObjectStore {
|
|
12
|
+
#private;
|
|
13
|
+
objects(): GitObject[];
|
|
14
|
+
get(id: string): Promise<GitObject | null>;
|
|
15
|
+
put(objects: readonly GitObject[]): Promise<string[]>;
|
|
16
|
+
}
|
|
17
|
+
export declare class StagedObjects implements ObjectStore {
|
|
18
|
+
#private;
|
|
19
|
+
constructor(under: ObjectStore);
|
|
20
|
+
get(id: string): Promise<GitObject | null>;
|
|
21
|
+
put(objects: readonly GitObject[]): Promise<string[]>;
|
|
22
|
+
flush(): Promise<void>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Where objects are kept, and what a repository reads out of them: the
|
|
3
|
+
// files a commit holds, a tree written from files, and every object a
|
|
4
|
+
// commit reaches.
|
|
5
|
+
import { commit, DIRECTORY, FILE, idOf, readCommit, readTree, tree } from './object.js';
|
|
6
|
+
// An object the store must hold, of the type named.
|
|
7
|
+
export const need = async (store, id, type) => {
|
|
8
|
+
const o = await store.get(id);
|
|
9
|
+
if (!o)
|
|
10
|
+
throw new Error(`${id} is no object this harbor holds`);
|
|
11
|
+
if (o.type !== type)
|
|
12
|
+
throw new Error(`${id} is a ${o.type}, not a ${type}`);
|
|
13
|
+
return o;
|
|
14
|
+
};
|
|
15
|
+
// Every file of a commit's tree, by its path, with its blob's id.
|
|
16
|
+
export const files = async (store, id) => {
|
|
17
|
+
const out = new Map();
|
|
18
|
+
const walk = async (treeId, at) => {
|
|
19
|
+
for (const e of readTree(await need(store, treeId, 'tree'))) {
|
|
20
|
+
if (e.mode === DIRECTORY)
|
|
21
|
+
await walk(e.id, `${at}${e.name}/`);
|
|
22
|
+
else
|
|
23
|
+
out.set(`${at}${e.name}`, e.id);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
await walk(readCommit(await need(store, id, 'commit')).tree, '');
|
|
27
|
+
return out;
|
|
28
|
+
};
|
|
29
|
+
// Files by path, each a blob's id, written as trees; the root's id.
|
|
30
|
+
export const writeTree = async (store, paths) => {
|
|
31
|
+
const level = async (under) => {
|
|
32
|
+
const entries = [];
|
|
33
|
+
const dirs = new Map();
|
|
34
|
+
for (const [path, id] of under) {
|
|
35
|
+
const slash = path.indexOf('/');
|
|
36
|
+
if (slash < 0)
|
|
37
|
+
entries.push({ mode: FILE, name: path, id });
|
|
38
|
+
else {
|
|
39
|
+
const name = path.slice(0, slash);
|
|
40
|
+
if (!dirs.has(name))
|
|
41
|
+
dirs.set(name, new Map());
|
|
42
|
+
dirs.get(name).set(path.slice(slash + 1), id);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
for (const [name, inner] of dirs)
|
|
46
|
+
entries.push({ mode: DIRECTORY, name, id: await level(inner) });
|
|
47
|
+
const [id] = await store.put([tree(entries)]);
|
|
48
|
+
return id;
|
|
49
|
+
};
|
|
50
|
+
return level(paths);
|
|
51
|
+
};
|
|
52
|
+
export const writeCommit = async (store, c) => {
|
|
53
|
+
const [id] = await store.put([commit(c)]);
|
|
54
|
+
return id;
|
|
55
|
+
};
|
|
56
|
+
// Every object a commit reaches, itself first: its ancestors, their trees
|
|
57
|
+
// and every blob.
|
|
58
|
+
export const reachable = async (store, from) => {
|
|
59
|
+
const seen = new Set();
|
|
60
|
+
const walkTree = async (id) => {
|
|
61
|
+
if (seen.has(id))
|
|
62
|
+
return;
|
|
63
|
+
seen.add(id);
|
|
64
|
+
for (const e of readTree(await need(store, id, 'tree'))) {
|
|
65
|
+
if (e.mode === DIRECTORY)
|
|
66
|
+
await walkTree(e.id);
|
|
67
|
+
else
|
|
68
|
+
seen.add(e.id);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const commits = [from];
|
|
72
|
+
while (commits.length > 0) {
|
|
73
|
+
const id = commits.pop();
|
|
74
|
+
if (seen.has(id))
|
|
75
|
+
continue;
|
|
76
|
+
seen.add(id);
|
|
77
|
+
const c = readCommit(await need(store, id, 'commit'));
|
|
78
|
+
await walkTree(c.tree);
|
|
79
|
+
commits.push(...c.parents);
|
|
80
|
+
}
|
|
81
|
+
return [...seen];
|
|
82
|
+
};
|
|
83
|
+
// Objects held in this process alone.
|
|
84
|
+
export class HeldObjects {
|
|
85
|
+
#objects = new Map();
|
|
86
|
+
// Every object held, in the order first put.
|
|
87
|
+
objects() {
|
|
88
|
+
return [...this.#objects.values()];
|
|
89
|
+
}
|
|
90
|
+
get(id) {
|
|
91
|
+
return Promise.resolve(this.#objects.get(id) ?? null);
|
|
92
|
+
}
|
|
93
|
+
async put(objects) {
|
|
94
|
+
const ids = [];
|
|
95
|
+
for (const o of objects) {
|
|
96
|
+
const id = await idOf(o);
|
|
97
|
+
this.#objects.set(id, o);
|
|
98
|
+
ids.push(id);
|
|
99
|
+
}
|
|
100
|
+
return ids;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Objects written over a store and kept aside until `flush` puts them in
|
|
104
|
+
// it: what a store reads through, and what it writes nowhere yet.
|
|
105
|
+
export class StagedObjects {
|
|
106
|
+
#under;
|
|
107
|
+
#staged = new HeldObjects();
|
|
108
|
+
constructor(under) {
|
|
109
|
+
this.#under = under;
|
|
110
|
+
}
|
|
111
|
+
async get(id) {
|
|
112
|
+
return (await this.#staged.get(id)) ?? this.#under.get(id);
|
|
113
|
+
}
|
|
114
|
+
put(objects) {
|
|
115
|
+
return this.#staged.put(objects);
|
|
116
|
+
}
|
|
117
|
+
async flush() {
|
|
118
|
+
await this.#under.put(this.#staged.objects());
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// zlib, as git keeps an object. A loose object is deflated and inflated by
|
|
3
|
+
// the engine's own CompressionStream and DecompressionStream. A pack holds
|
|
4
|
+
// its objects one after another with no length before each stream, and a
|
|
5
|
+
// stream API never says how much of its input one stream took, so a pack
|
|
6
|
+
// is read by `inflateAt`, an inflater of RFC 1950 and 1951 that says where
|
|
7
|
+
// the stream it read ends.
|
|
8
|
+
import { own } from '../crypto/subtle.js';
|
|
9
|
+
const through = async (bytes, stream) => {
|
|
10
|
+
const writer = stream.writable.getWriter();
|
|
11
|
+
void writer.write(own(bytes)).catch(() => undefined);
|
|
12
|
+
void writer.close().catch(() => undefined);
|
|
13
|
+
return new Uint8Array(await new Response(stream.readable).arrayBuffer());
|
|
14
|
+
};
|
|
15
|
+
export const deflate = (bytes) => through(bytes, new CompressionStream('deflate'));
|
|
16
|
+
export const inflate = async (bytes) => {
|
|
17
|
+
try {
|
|
18
|
+
return await through(bytes, new DecompressionStream('deflate'));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
throw new Error('bytes that do not inflate');
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const LENGTH_BASE = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258];
|
|
25
|
+
const LENGTH_EXTRA = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0];
|
|
26
|
+
const DISTANCE_BASE = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577];
|
|
27
|
+
const DISTANCE_EXTRA = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13];
|
|
28
|
+
const ORDER = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
|
|
29
|
+
const BITS = 15;
|
|
30
|
+
const huffman = (lengths) => {
|
|
31
|
+
const count = new Uint16Array(BITS + 1);
|
|
32
|
+
for (let s = 0; s < lengths.length; s += 1)
|
|
33
|
+
count[lengths[s]] += 1;
|
|
34
|
+
const offsets = new Uint16Array(BITS + 1);
|
|
35
|
+
for (let len = 1; len < BITS; len += 1)
|
|
36
|
+
offsets[len + 1] = offsets[len] + count[len];
|
|
37
|
+
const symbol = new Uint16Array(lengths.length);
|
|
38
|
+
for (let s = 0; s < lengths.length; s += 1)
|
|
39
|
+
if (lengths[s] !== 0)
|
|
40
|
+
symbol[offsets[lengths[s]]++] = s;
|
|
41
|
+
count[0] = 0;
|
|
42
|
+
return { count, symbol };
|
|
43
|
+
};
|
|
44
|
+
const FIXED_LENGTHS = huffman(Array.from({ length: 288 }, (_, s) => (s < 144 ? 8 : s < 256 ? 9 : s < 280 ? 7 : 8)));
|
|
45
|
+
const FIXED_DISTANCES = huffman(Array.from({ length: 30 }, () => 5));
|
|
46
|
+
class Reader {
|
|
47
|
+
#bytes;
|
|
48
|
+
at;
|
|
49
|
+
#buffer = 0;
|
|
50
|
+
#held = 0;
|
|
51
|
+
constructor(bytes, at) {
|
|
52
|
+
this.#bytes = bytes;
|
|
53
|
+
this.at = at;
|
|
54
|
+
}
|
|
55
|
+
bits(n) {
|
|
56
|
+
while (this.#held < n) {
|
|
57
|
+
if (this.at >= this.#bytes.length)
|
|
58
|
+
throw new Error('a stream cut short');
|
|
59
|
+
this.#buffer |= this.#bytes[this.at++] << this.#held;
|
|
60
|
+
this.#held += 8;
|
|
61
|
+
}
|
|
62
|
+
const out = this.#buffer & ((1 << n) - 1);
|
|
63
|
+
this.#buffer >>>= n;
|
|
64
|
+
this.#held -= n;
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
// The rest of this byte let go, as a stored block and the end ask.
|
|
68
|
+
align() {
|
|
69
|
+
this.#buffer = 0;
|
|
70
|
+
this.#held = 0;
|
|
71
|
+
}
|
|
72
|
+
byte() {
|
|
73
|
+
if (this.at >= this.#bytes.length)
|
|
74
|
+
throw new Error('a stream cut short');
|
|
75
|
+
return this.#bytes[this.at++];
|
|
76
|
+
}
|
|
77
|
+
decode(h) {
|
|
78
|
+
let code = 0;
|
|
79
|
+
let first = 0;
|
|
80
|
+
let index = 0;
|
|
81
|
+
for (let len = 1; len <= BITS; len += 1) {
|
|
82
|
+
code |= this.bits(1);
|
|
83
|
+
const count = h.count[len];
|
|
84
|
+
if (code - count < first)
|
|
85
|
+
return h.symbol[index + (code - first)];
|
|
86
|
+
index += count;
|
|
87
|
+
first += count;
|
|
88
|
+
first <<= 1;
|
|
89
|
+
code <<= 1;
|
|
90
|
+
}
|
|
91
|
+
throw new Error('a code no table holds');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
class Output {
|
|
95
|
+
bytes = new Uint8Array(1024);
|
|
96
|
+
length = 0;
|
|
97
|
+
#room(n) {
|
|
98
|
+
if (this.length + n <= this.bytes.length)
|
|
99
|
+
return;
|
|
100
|
+
let size = this.bytes.length * 2;
|
|
101
|
+
while (size < this.length + n)
|
|
102
|
+
size *= 2;
|
|
103
|
+
const grown = new Uint8Array(size);
|
|
104
|
+
grown.set(this.bytes.subarray(0, this.length));
|
|
105
|
+
this.bytes = grown;
|
|
106
|
+
}
|
|
107
|
+
push(byte) {
|
|
108
|
+
this.#room(1);
|
|
109
|
+
this.bytes[this.length++] = byte;
|
|
110
|
+
}
|
|
111
|
+
copy(distance, length) {
|
|
112
|
+
if (distance > this.length)
|
|
113
|
+
throw new Error('a distance before the start');
|
|
114
|
+
this.#room(length);
|
|
115
|
+
for (let k = 0; k < length; k += 1)
|
|
116
|
+
this.bytes[this.length] = this.bytes[this.length++ - distance];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const dynamic = (r) => {
|
|
120
|
+
const nlen = r.bits(5) + 257;
|
|
121
|
+
const ndist = r.bits(5) + 1;
|
|
122
|
+
const ncode = r.bits(4) + 4;
|
|
123
|
+
const codeLengths = new Uint8Array(19);
|
|
124
|
+
for (let k = 0; k < ncode; k += 1)
|
|
125
|
+
codeLengths[ORDER[k]] = r.bits(3);
|
|
126
|
+
const codes = huffman(codeLengths);
|
|
127
|
+
const lengths = new Uint8Array(nlen + ndist);
|
|
128
|
+
for (let k = 0; k < nlen + ndist;) {
|
|
129
|
+
const sym = r.decode(codes);
|
|
130
|
+
if (sym < 16) {
|
|
131
|
+
lengths[k++] = sym;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
let repeat;
|
|
135
|
+
let value = 0;
|
|
136
|
+
if (sym === 16) {
|
|
137
|
+
if (k === 0)
|
|
138
|
+
throw new Error('a repeat with nothing before it');
|
|
139
|
+
value = lengths[k - 1];
|
|
140
|
+
repeat = 3 + r.bits(2);
|
|
141
|
+
}
|
|
142
|
+
else if (sym === 17)
|
|
143
|
+
repeat = 3 + r.bits(3);
|
|
144
|
+
else
|
|
145
|
+
repeat = 11 + r.bits(7);
|
|
146
|
+
if (k + repeat > nlen + ndist)
|
|
147
|
+
throw new Error('too many lengths');
|
|
148
|
+
while (repeat-- > 0)
|
|
149
|
+
lengths[k++] = value;
|
|
150
|
+
}
|
|
151
|
+
return [huffman(lengths.subarray(0, nlen)), huffman(lengths.subarray(nlen))];
|
|
152
|
+
};
|
|
153
|
+
const adler32 = (bytes) => {
|
|
154
|
+
let a = 1;
|
|
155
|
+
let b = 0;
|
|
156
|
+
for (let k = 0; k < bytes.length; k += 1) {
|
|
157
|
+
a = (a + bytes[k]) % 65521;
|
|
158
|
+
b = (b + a) % 65521;
|
|
159
|
+
}
|
|
160
|
+
return ((b << 16) | a) >>> 0;
|
|
161
|
+
};
|
|
162
|
+
// One zlib stream that starts at `at`: its bytes, and where it ends.
|
|
163
|
+
export const inflateAt = (bytes, at) => {
|
|
164
|
+
const r = new Reader(bytes, at);
|
|
165
|
+
const cmf = r.byte();
|
|
166
|
+
const flg = r.byte();
|
|
167
|
+
if ((cmf & 15) !== 8 || ((cmf << 8) | flg) % 31 !== 0 || (flg & 32) !== 0)
|
|
168
|
+
throw new Error('no zlib stream');
|
|
169
|
+
const out = new Output();
|
|
170
|
+
for (let last = 0; last === 0;) {
|
|
171
|
+
last = r.bits(1);
|
|
172
|
+
const type = r.bits(2);
|
|
173
|
+
if (type === 0) {
|
|
174
|
+
r.align();
|
|
175
|
+
const len = r.byte() | (r.byte() << 8);
|
|
176
|
+
const nlen = r.byte() | (r.byte() << 8);
|
|
177
|
+
if ((len ^ 0xffff) !== nlen)
|
|
178
|
+
throw new Error('a stored block whose length does not check');
|
|
179
|
+
for (let k = 0; k < len; k += 1)
|
|
180
|
+
out.push(r.byte());
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (type === 3)
|
|
184
|
+
throw new Error('a block of no type');
|
|
185
|
+
const [lengths, distances] = type === 1 ? [FIXED_LENGTHS, FIXED_DISTANCES] : dynamic(r);
|
|
186
|
+
for (;;) {
|
|
187
|
+
const sym = r.decode(lengths);
|
|
188
|
+
if (sym < 256)
|
|
189
|
+
out.push(sym);
|
|
190
|
+
else if (sym === 256)
|
|
191
|
+
break;
|
|
192
|
+
else {
|
|
193
|
+
const l = sym - 257;
|
|
194
|
+
if (l >= 29)
|
|
195
|
+
throw new Error('a length of no code');
|
|
196
|
+
const length = LENGTH_BASE[l] + r.bits(LENGTH_EXTRA[l]);
|
|
197
|
+
const d = r.decode(distances);
|
|
198
|
+
if (d >= 30)
|
|
199
|
+
throw new Error('a distance of no code');
|
|
200
|
+
out.copy(DISTANCE_BASE[d] + r.bits(DISTANCE_EXTRA[d]), length);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
r.align();
|
|
205
|
+
const sum = ((r.byte() << 24) | (r.byte() << 16) | (r.byte() << 8) | r.byte()) >>> 0;
|
|
206
|
+
const result = out.bytes.slice(0, out.length);
|
|
207
|
+
if (sum !== adler32(result))
|
|
208
|
+
throw new Error('a stream whose sum does not check');
|
|
209
|
+
return { out: result, end: r.at };
|
|
210
|
+
};
|