OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-sync commits / cf284f4

Initial hyper-sync — bare repo management over Hyperswarm
Manages a collection of bare git repos: scan, status, serve over punch://, pull from remotes. CommonJS, Holepunch module standards. API: HyperSync class (ReadyResource) - scan() — discover bare repos in directory - status() — repo count, sizes, branches, serving state - info(name) — detailed single repo info - serve() / unserve() — announce/unannounce on DHT - addRemote() / removeRemote() — register federation peers - pull(remote, repo) — git fetch from remote via punch:// 484 lines source, 133 lines tests, 10/10 pass. Direct ref reading (2ms/repo vs 28ms/repo with git subprocess). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cf284f43d1906fb3a6d50993305ae3c7e6a7ff5b
by plankatron <fleeky@gmail.com> · 2026-04-09T21:25:18.000Z

Changed files (7) +1910 -0

.gitignore +1 -0
……@@ -0,0 +1 @@
1node_modules/
index.js +351 -0
……@@ -0,0 +1,351 @@
1const ReadyResource = require('ready-resource');
2const safetyCatch = require('safety-catch');
3const Hyperswarm = require('hyperswarm');
4const crypto = require('hypercore-crypto');
5const fs = require('fs');
6const path = require('path');
7const { spawn } = require('child_process');
8
9const { scanRepos, repoInfo, readRefs } = require('./lib/repos');
10const { deriveTopic } = require('./lib/topics');
11
12module.exports = class HyperSync extends ReadyResource {
13 constructor (opts = {}) {
14 super();
15
16 this._reposDir = opts.repos || path.join(require('os').homedir(), 'git-repos');
17 this._swarm = opts.swarm || null;
18 this._ownSwarm = !this._swarm;
19 this._keypair = opts.keypair || null;
20
21 this.repos = new Map();
22 this.remotes = new Map();
23 this._topics = new Map();
24 this._serving = false;
25
26 this.ready().catch(safetyCatch);
27 }
28
29 async _open () {
30 // Generate or load keypair for server identity
31 if (!this._keypair) {
32 this._keypair = crypto.keyPair();
33 }
34
35 // Scan repos
36 this.repos = scanRepos(this._reposDir);
37 this.emit('scan', this.repos);
38
39 // Create swarm if not injected
40 if (!this._swarm) {
41 this._swarm = new Hyperswarm({ keyPair: this._keypair });
42 }
43
44 this._swarm.on('connection', (conn, info) => this._onConnection(conn, info));
45 }
46
47 async _close () {
48 // Unannounce all topics
49 for (const [name, entry] of this._topics) {
50 try {
51 await entry.discovery.destroy();
52 } catch {}
53 }
54 this._topics.clear();
55
56 if (this._ownSwarm && this._swarm) {
57 await this._swarm.destroy();
58 this._swarm = null;
59 }
60 }
61
62 // ── Properties ────────────────────────────────────────────
63
64 get serverKey () {
65 return this._keypair ? this._keypair.publicKey.toString('hex') : null;
66 }
67
68 get serving () {
69 return this._topics.size;
70 }
71
72 // ── Repo Management ───────────────────────────────────────
73
74 async scan () {
75 this.repos = scanRepos(this._reposDir);
76 this.emit('scan', this.repos);
77 return this.repos;
78 }
79
80 status () {
81 const repoList = [];
82 for (const [name, info] of this.repos) {
83 repoList.push({
84 name,
85 branches: info.branchCount,
86 packSize: info.packSize,
87 head: info.head ? info.head.slice(0, 12) : null,
88 serving: this._topics.has(name),
89 lastUpdated: info.lastUpdated
90 });
91 }
92
93 return {
94 repos: repoList,
95 repoCount: this.repos.size,
96 serving: this._topics.size,
97 remotes: this.remotes.size,
98 serverKey: this.serverKey
99 };
100 }
101
102 info (name) {
103 const repo = this.repos.get(name);
104 if (!repo) return null;
105
106 // Re-read refs for fresh data
107 const refs = readRefs(repo.path);
108
109 return {
110 ...repo,
111 refs,
112 serving: this._topics.has(name),
113 topic: this._topics.has(name)
114 ? this._topics.get(name).topic.toString('hex')
115 : null
116 };
117 }
118
119 // ── Serving ───────────────────────────────────────────────
120
121 async serve (name) {
122 if (name) return this._serveOne(name);
123
124 // Serve all repos
125 const names = [...this.repos.keys()];
126 for (const n of names) {
127 await this._serveOne(n);
128 }
129
130 // Single flush for all topics
131 await this._swarm.flush();
132 this._serving = true;
133 this.emit('serving', this._topics.size);
134 }
135
136 async _serveOne (name) {
137 if (this._topics.has(name)) return;
138
139 const repo = this.repos.get(name);
140 if (!repo) throw new Error('Repo not found: ' + name);
141
142 const topic = deriveTopic(this._keypair.publicKey, name);
143 const discovery = this._swarm.join(topic, { server: true, client: false });
144
145 this._topics.set(name, { topic, discovery, name });
146 this.emit('serve', name, topic.toString('hex'));
147 }
148
149 async unserve (name) {
150 if (name) {
151 const entry = this._topics.get(name);
152 if (entry) {
153 await entry.discovery.destroy();
154 this._topics.delete(name);
155 }
156 return;
157 }
158
159 // Unserve all
160 for (const [n, entry] of this._topics) {
161 await entry.discovery.destroy();
162 }
163 this._topics.clear();
164 this._serving = false;
165 }
166
167 // ── Remotes ───────────────────────────────────────────────
168
169 addRemote (name, serverKey) {
170 this.remotes.set(name, {
171 name,
172 serverKey: typeof serverKey === 'string' ? serverKey : serverKey.toString('hex')
173 });
174 }
175
176 removeRemote (name) {
177 this.remotes.delete(name);
178 }
179
180 // ── Sync (Pull) ───────────────────────────────────────────
181
182 async pull (remoteName, repoName) {
183 const remote = this.remotes.get(remoteName);
184 if (!remote) throw new Error('Remote not found: ' + remoteName);
185
186 const repos = repoName
187 ? [repoName]
188 : [...this.repos.keys()];
189
190 const result = { synced: [], failed: [], skipped: [], elapsed: 0 };
191 const start = Date.now();
192
193 for (const name of repos) {
194 const repoPath = path.join(this._reposDir, name + '.git');
195
196 // Ensure repo exists locally
197 if (!fs.existsSync(repoPath)) {
198 try {
199 await this._exec('git', ['init', '--bare', repoPath]);
200 } catch (err) {
201 result.failed.push({ name, error: err.message });
202 continue;
203 }
204 }
205
206 const fetchUrl = 'punch://' + remote.serverKey + '/' + name;
207
208 this.emit('pull', remoteName, name, 'start');
209
210 try {
211 await this._gitFetch(repoPath, fetchUrl);
212 result.synced.push(name);
213 this.emit('pull', remoteName, name, 'complete');
214 } catch (err) {
215 result.failed.push({ name, error: err.message });
216 this.emit('pull', remoteName, name, 'failed');
217 }
218 }
219
220 result.elapsed = Date.now() - start;
221 return result;
222 }
223
224 // ── Connection Handler ────────────────────────────────────
225
226 _onConnection (conn, info) {
227 const peerKey = conn.remotePublicKey
228 ? conn.remotePublicKey.toString('hex').slice(0, 12)
229 : 'unknown';
230
231 // Determine which repo this connection is for
232 // by matching the topic against our announced topics
233 let repoName = null;
234 for (const [name, entry] of this._topics) {
235 // Topics match by the swarm's internal routing
236 repoName = name;
237 break;
238 }
239
240 conn.on('error', safetyCatch);
241
242 this.emit('connection', peerKey, repoName);
243
244 // Handle git protocol — read header, spawn git-upload-pack
245 let headerReceived = false;
246 let buffer = Buffer.alloc(0);
247
248 const headerHandler = (chunk) => {
249 if (headerReceived) return;
250
251 buffer = Buffer.concat([buffer, chunk]);
252
253 const firstNull = buffer.indexOf(0);
254 if (firstNull === -1) return;
255
256 const secondNull = buffer.indexOf(0, firstNull + 1);
257 if (secondNull === -1) return;
258
259 headerReceived = true;
260 conn.off('data', headerHandler);
261
262 const service = buffer.slice(0, firstNull).toString('utf-8');
263 const repo = buffer.slice(firstNull + 1, secondNull).toString('utf-8');
264 const remaining = buffer.slice(secondNull + 1);
265
266 const repoPath = path.join(this._reposDir, repo + '.git');
267
268 if (!fs.existsSync(repoPath)) {
269 conn.destroy();
270 return;
271 }
272
273 // Only allow git-upload-pack (read-only) for now
274 if (service !== 'git-upload-pack') {
275 conn.destroy();
276 return;
277 }
278
279 this._spawnGitService(conn, service, repoPath, remaining);
280 };
281
282 conn.on('data', headerHandler);
283 }
284
285 _spawnGitService (conn, service, repoPath, initialData) {
286 const proc = spawn(service, [repoPath], {
287 stdio: ['pipe', 'pipe', 'pipe']
288 });
289
290 if (initialData.length > 0) {
291 proc.stdin.write(initialData);
292 }
293
294 // Bidirectional proxy with backpressure
295 conn.on('data', (chunk) => {
296 if (!proc.stdin.write(chunk)) conn.pause();
297 });
298 proc.stdin.on('drain', () => conn.resume());
299
300 proc.stdout.on('data', (chunk) => {
301 if (!conn.write(chunk)) proc.stdout.pause();
302 });
303 conn.on('drain', () => proc.stdout.resume());
304
305 if (typeof conn.resume === 'function') conn.resume();
306
307 conn.on('end', () => { try { proc.stdin.end(); } catch {} });
308 proc.stdin.on('error', safetyCatch);
309 proc.stdout.on('error', safetyCatch);
310
311 proc.on('exit', () => {
312 if (!conn.destroyed) conn.end();
313 });
314
315 conn.on('close', () => {
316 if (proc.exitCode === null) proc.kill();
317 });
318 }
319
320 // ── Helpers ───────────────────────────────────────────────
321
322 _gitFetch (repoPath, fetchUrl) {
323 return new Promise((resolve, reject) => {
324 const proc = spawn('git', [
325 '-C', repoPath, 'fetch', fetchUrl, 'refs/*:refs/*', '--no-tags'
326 ], { stdio: ['ignore', 'pipe', 'pipe'] });
327
328 const errChunks = [];
329 proc.stderr.on('data', (d) => errChunks.push(d));
330
331 proc.on('exit', (code) => {
332 if (code === 0) resolve();
333 else reject(new Error('git fetch exit ' + code + ': ' + Buffer.concat(errChunks).toString('utf-8').trim()));
334 });
335 proc.on('error', reject);
336 });
337 }
338
339 _exec (cmd, args) {
340 return new Promise((resolve, reject) => {
341 const proc = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'] });
342 const chunks = [];
343 proc.stdout.on('data', (c) => chunks.push(c));
344 proc.on('exit', (code) => {
345 if (code === 0) resolve(Buffer.concat(chunks).toString('utf-8'));
346 else reject(new Error(cmd + ' exited with code ' + code));
347 });
348 proc.on('error', reject);
349 });
350 }
351};
lib/repos.js +118 -0
……@@ -0,0 +1,118 @@
1const fs = require('fs');
2const path = require('path');
3
4/**
5 * Scan a directory for bare git repos.
6 * Returns a Map of repo name → info.
7 */
8function scanRepos (dir) {
9 const repos = new Map();
10 let entries;
11
12 try {
13 entries = fs.readdirSync(dir);
14 } catch {
15 return repos;
16 }
17
18 for (const entry of entries) {
19 if (!entry.endsWith('.git')) continue;
20
21 const repoPath = path.join(dir, entry);
22 const name = entry.slice(0, -4);
23
24 try {
25 const stat = fs.statSync(repoPath);
26 if (!stat.isDirectory()) continue;
27 } catch {
28 continue;
29 }
30
31 const info = repoInfo(repoPath, name);
32 if (info) repos.set(name, info);
33 }
34
35 return repos;
36}
37
38/**
39 * Get info for a single bare repo.
40 */
41function repoInfo (repoPath, name) {
42 const refs = readRefs(repoPath);
43 const branches = Object.keys(refs);
44 const head = refs.master || refs.main || refs[branches[0]] || null;
45
46 let size = 0;
47 try {
48 const packDir = path.join(repoPath, 'objects', 'pack');
49 const packs = fs.readdirSync(packDir);
50 for (const p of packs) {
51 if (p.endsWith('.pack')) {
52 size += fs.statSync(path.join(packDir, p)).size;
53 }
54 }
55 } catch {}
56
57 let lastUpdated = null;
58 try {
59 // Check HEAD file mtime as proxy for last activity
60 const headStat = fs.statSync(path.join(repoPath, 'HEAD'));
61 lastUpdated = headStat.mtimeMs;
62
63 // Better: check packed-refs mtime if it exists
64 try {
65 const prStat = fs.statSync(path.join(repoPath, 'packed-refs'));
66 if (prStat.mtimeMs > lastUpdated) lastUpdated = prStat.mtimeMs;
67 } catch {}
68 } catch {}
69
70 return {
71 name,
72 path: repoPath,
73 branches,
74 branchCount: branches.length,
75 head,
76 packSize: size,
77 lastUpdated
78 };
79}
80
81/**
82 * Read refs from a bare repo — direct file read, no subprocess.
83 * Returns { refShortName: sha }
84 */
85function readRefs (repoPath) {
86 const refs = {};
87
88 // Read packed-refs (most repos have this)
89 try {
90 const packed = fs.readFileSync(path.join(repoPath, 'packed-refs'), 'utf-8');
91 for (const line of packed.split('\n')) {
92 if (line.startsWith('#') || line.startsWith('^')) continue;
93 const parts = line.trim().split(' ');
94 if (parts.length < 2) continue;
95 const sha = parts[0];
96 const ref = parts[1];
97 if (ref.startsWith('refs/heads/')) {
98 refs[ref.slice('refs/heads/'.length)] = sha;
99 }
100 }
101 } catch {}
102
103 // Read loose refs (override packed)
104 try {
105 const headsDir = path.join(repoPath, 'refs', 'heads');
106 const entries = fs.readdirSync(headsDir);
107 for (const entry of entries) {
108 try {
109 const sha = fs.readFileSync(path.join(headsDir, entry), 'utf-8').trim();
110 refs[entry] = sha;
111 } catch {}
112 }
113 } catch {}
114
115 return refs;
116}
117
118module.exports = { scanRepos, repoInfo, readRefs };
lib/topics.js +15 -0
……@@ -0,0 +1,15 @@
1const crypto = require('hypercore-crypto');
2
3/**
4 * Derive a DHT topic for a repo.
5 * topic = hash(serverPublicKey + repoName)
6 * Deterministic — same key+name = same topic on all machines.
7 */
8function deriveTopic (serverKey, repoName) {
9 const keyBuf = typeof serverKey === 'string'
10 ? Buffer.from(serverKey, 'hex')
11 : serverKey;
12 return crypto.data(Buffer.concat([keyBuf, Buffer.from(repoName)]));
13}
14
15module.exports = { deriveTopic };
package-lock.json +1266 -0
……@@ -0,0 +1,1266 @@
1{
2 "name": "hyper-sync",
3 "version": "0.1.0",
4 "lockfileVersion": 3,
5 "requires": true,
6 "packages": {
7 "": {
8 "name": "hyper-sync",
9 "version": "0.1.0",
10 "dependencies": {
11 "compact-encoding": "^2.0.0",
12 "hypercore-crypto": "^3.0.0",
13 "hyperswarm": "^4.0.0",
14 "protomux": "^3.0.0",
15 "ready-resource": "^1.0.0",
16 "safety-catch": "^1.0.0"
17 },
18 "devDependencies": {
19 "brittle": "^3.0.0"
20 }
21 },
22 "node_modules/@hyperswarm/secret-stream": {
23 "version": "6.9.1",
24 "resolved": "https://registry.npmjs.org/@hyperswarm/secret-stream/-/secret-stream-6.9.1.tgz",
25 "integrity": "sha512-xb0S5y3YJwBakD77JOGBHlBxdp63mHClZoXBYoLv+9wH8e054ESKlmQptWqjJK5dv5VMUIVYOJB4MaOpB0JdGw==",
26 "license": "Apache-2.0",
27 "dependencies": {
28 "b4a": "^1.1.0",
29 "hypercore-crypto": "^3.3.1",
30 "noise-curve-ed": "^2.0.1",
31 "noise-handshake": "^4.0.0",
32 "sodium-secretstream": "^1.1.0",
33 "sodium-universal": "^5.0.0",
34 "streamx": "^2.14.0",
35 "timeout-refresh": "^2.0.0",
36 "unslab": "^1.3.0"
37 }
38 },
39 "node_modules/@jridgewell/resolve-uri": {
40 "version": "3.1.2",
41 "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
42 "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
43 "dev": true,
44 "license": "MIT",
45 "engines": {
46 "node": ">=6.0.0"
47 }
48 },
49 "node_modules/@jridgewell/sourcemap-codec": {
50 "version": "1.5.5",
51 "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
52 "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
53 "dev": true,
54 "license": "MIT"
55 },
56 "node_modules/@jridgewell/trace-mapping": {
57 "version": "0.3.31",
58 "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
59 "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
60 "dev": true,
61 "license": "MIT",
62 "dependencies": {
63 "@jridgewell/resolve-uri": "^3.1.0",
64 "@jridgewell/sourcemap-codec": "^1.4.14"
65 }
66 },
67 "node_modules/@types/istanbul-lib-coverage": {
68 "version": "2.0.6",
69 "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
70 "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
71 "dev": true,
72 "license": "MIT"
73 },
74 "node_modules/adaptive-timeout": {
75 "version": "1.0.1",
76 "resolved": "https://registry.npmjs.org/adaptive-timeout/-/adaptive-timeout-1.0.1.tgz",
77 "integrity": "sha512-+seGiBtHqbnyZ0Quq/ZGxxwP66153WBABawa07/QeyuPFzbduPBjiGQAyCiriiLDzt3dkbMBskSlfqtRwblK8Q==",
78 "license": "Apache-2.0",
79 "dependencies": {
80 "xache": "^1.2.1"
81 }
82 },
83 "node_modules/b4a": {
84 "version": "1.8.0",
85 "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz",
86 "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==",
87 "license": "Apache-2.0",
88 "peerDependencies": {
89 "react-native-b4a": "*"
90 },
91 "peerDependenciesMeta": {
92 "react-native-b4a": {
93 "optional": true
94 }
95 }
96 },
97 "node_modules/bare-abort": {
98 "version": "2.0.13",
99 "resolved": "https://registry.npmjs.org/bare-abort/-/bare-abort-2.0.13.tgz",
100 "integrity": "sha512-zdc8l88eB11Jsz5rDd6sCAgv2kUFXgdrZWoMlgU6JMkfAi1/uuGFC3IEHswKbIRQTk5H3T5CMuechsXYxiaHlQ==",
101 "dev": true,
102 "license": "Apache-2.0"
103 },
104 "node_modules/bare-addon-resolve": {
105 "version": "1.10.0",
106 "resolved": "https://registry.npmjs.org/bare-addon-resolve/-/bare-addon-resolve-1.10.0.tgz",
107 "integrity": "sha512-sSd0jieRJlDaODOzj0oe0RjFVC1QI0ZIjGIdPkbrTXsdVVtENg14c+lHHAhHwmWCZ2nQlMhy8jA3Y5LYPc/isA==",
108 "license": "Apache-2.0",
109 "dependencies": {
110 "bare-module-resolve": "^1.10.0",
111 "bare-semver": "^1.0.0"
112 },
113 "peerDependencies": {
114 "bare-url": "*"
115 },
116 "peerDependenciesMeta": {
117 "bare-url": {
118 "optional": true
119 }
120 }
121 },
122 "node_modules/bare-ansi-escapes": {
123 "version": "2.2.3",
124 "resolved": "https://registry.npmjs.org/bare-ansi-escapes/-/bare-ansi-escapes-2.2.3.tgz",
125 "integrity": "sha512-02ES4/E2RbrtZSnHJ9LntBhYkLA6lPpSEeP8iqS3MccBIVhVBlEmruF1I7HZqx5Q8aiTeYfQVeqmrU9YO2yYoQ==",
126 "license": "Apache-2.0",
127 "dependencies": {
128 "bare-stream": "^2.6.5"
129 },
130 "peerDependencies": {
131 "bare-buffer": "*"
132 },
133 "peerDependenciesMeta": {
134 "bare-buffer": {
135 "optional": true
136 }
137 }
138 },
139 "node_modules/bare-assert": {
140 "version": "1.2.0",
141 "resolved": "https://registry.npmjs.org/bare-assert/-/bare-assert-1.2.0.tgz",
142 "integrity": "sha512-c6uvgvTJBspTDxtVnPgrBKmLgcpW3Fp72NVKDLg6oT4QjQbhGtvrkHMhGYMK1sh4vjBHOBmuUalyt9hSzV37fQ==",
143 "license": "Apache-2.0",
144 "dependencies": {
145 "bare-inspect": "^3.1.2"
146 }
147 },
148 "node_modules/bare-bundle": {
149 "version": "1.10.0",
150 "resolved": "https://registry.npmjs.org/bare-bundle/-/bare-bundle-1.10.0.tgz",
151 "integrity": "sha512-4LVlnJAHr00Hh6Vu6ZUJS38rcEtJT3b3vChXSsBsJ2mk1TN0lQ+gzd+Dw5L0aV7uqDZv84smuwW+O02X7PfDlw==",
152 "dev": true,
153 "license": "Apache-2.0",
154 "peerDependencies": {
155 "bare-buffer": "*",
156 "bare-url": "*"
157 },
158 "peerDependenciesMeta": {
159 "bare-buffer": {
160 "optional": true
161 },
162 "bare-url": {
163 "optional": true
164 }
165 }
166 },
167 "node_modules/bare-cov": {
168 "version": "1.2.1",
169 "resolved": "https://registry.npmjs.org/bare-cov/-/bare-cov-1.2.1.tgz",
170 "integrity": "sha512-SHNqb/WG9udUEj8m5qGSehoUQ9o0Xzv8nrf4HIdmG+KNU/XdhPLhTP5VPrHnSAMAXhAzEB4Q+2IYZ0x9qPzN1g==",
171 "dev": true,
172 "license": "Apache-2.0",
173 "dependencies": {
174 "bare-fs": "^4.1.2",
175 "bare-inspector": "^4.0.1",
176 "bare-path": "^3.0.0",
177 "bare-process": "^4.2.1",
178 "bare-url": "^2.1.5",
179 "bare-v8-to-istanbul": "^1.0.2",
180 "picomatch": "^4.0.2",
181 "which-runtime": "^1.2.1"
182 }
183 },
184 "node_modules/bare-crypto": {
185 "version": "1.13.4",
186 "resolved": "https://registry.npmjs.org/bare-crypto/-/bare-crypto-1.13.4.tgz",
187 "integrity": "sha512-JiCZ5l2YOG1y8J7yy1BCAKTCZrPnHLb7pDRIdurBTOn5oIwBQDIv8iH5Pl2V85vzjl1NZXRfNY4HZLsE942jJA==",
188 "dev": true,
189 "license": "Apache-2.0",
190 "dependencies": {
191 "bare-assert": "^1.2.0",
192 "bare-stream": "^2.6.3"
193 },
194 "peerDependencies": {
195 "bare-buffer": "*"
196 },
197 "peerDependenciesMeta": {
198 "bare-buffer": {
199 "optional": true
200 }
201 }
202 },
203 "node_modules/bare-debug-log": {
204 "version": "2.0.0",
205 "resolved": "https://registry.npmjs.org/bare-debug-log/-/bare-debug-log-2.0.0.tgz",
206 "integrity": "sha512-Vi42PkMQsNV9PUpx2Gl1hikshx5O9FzMJ6o9Nnopseg7qLBBK7Nl31d0RHcfwLEAfmcPApytpc0ZFfq68u22FQ==",
207 "dev": true,
208 "license": "Apache-2.0",
209 "dependencies": {
210 "bare-os": "^3.0.1"
211 }
212 },
213 "node_modules/bare-dns": {
214 "version": "2.1.4",
215 "resolved": "https://registry.npmjs.org/bare-dns/-/bare-dns-2.1.4.tgz",
216 "integrity": "sha512-abwjHmpWqSRNB7V5615QxPH92L71AVzFm/kKTs8VYiNTAi2xVdonpv0BjJ0hwXLwomoW+xsSOPjW6PZPO14asg==",
217 "dev": true,
218 "license": "Apache-2.0",
219 "engines": {
220 "bare": ">=1.7.0"
221 }
222 },
223 "node_modules/bare-encoding": {
224 "version": "1.0.3",
225 "resolved": "https://registry.npmjs.org/bare-encoding/-/bare-encoding-1.0.3.tgz",
226 "integrity": "sha512-Kqf+t/azs13lUeyK4Tb7ha4wdLRXKWCXQ8w1rVmt7KtoPCPdHD/Xwt7LBIsCSwwGglrcmblo5VOLa5avkJqULA==",
227 "dev": true,
228 "license": "Apache-2.0",
229 "peerDependencies": {
230 "bare-buffer": "*"
231 },
232 "peerDependenciesMeta": {
233 "bare-buffer": {
234 "optional": true
235 }
236 }
237 },
238 "node_modules/bare-env": {
239 "version": "3.0.0",
240 "resolved": "https://registry.npmjs.org/bare-env/-/bare-env-3.0.0.tgz",
241 "integrity": "sha512-0u964P5ZLAxTi+lW4Kjp7YRJQ5gZr9ycYOtjLxsSrupgMz3sn5Z9n4SH/JIifHwvadsf1brA2JAjP+9IOWwTiw==",
242 "dev": true,
243 "license": "Apache-2.0",
244 "dependencies": {
245 "bare-os": "^3.0.1"
246 }
247 },
248 "node_modules/bare-events": {
249 "version": "2.8.2",
250 "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz",
251 "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==",
252 "license": "Apache-2.0",
253 "peerDependencies": {
254 "bare-abort-controller": "*"
255 },
256 "peerDependenciesMeta": {
257 "bare-abort-controller": {
258 "optional": true
259 }
260 }
261 },
262 "node_modules/bare-format": {
263 "version": "1.0.2",
264 "resolved": "https://registry.npmjs.org/bare-format/-/bare-format-1.0.2.tgz",
265 "integrity": "sha512-GswdhnOnP9QtwRbrf4wLApw5widkaLMsLe2XOs35fQD2YfEN1ApoGka+cZ7PfvzxMgfYXmMhj/2OGlVn5/Dxgw==",
266 "dev": true,
267 "license": "Apache-2.0",
268 "dependencies": {
269 "bare-inspect": "^3.0.0"
270 }
271 },
272 "node_modules/bare-fs": {
273 "version": "4.7.0",
274 "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.0.tgz",
275 "integrity": "sha512-xzqKsCFxAek9aezYhjJuJRXBIaYlg/0OGDTZp+T8eYmYMlm66cs6cYko02drIyjN2CBbi+I6L7YfXyqpqtKRXA==",
276 "dev": true,
277 "license": "Apache-2.0",
278 "dependencies": {
279 "bare-events": "^2.5.4",
280 "bare-path": "^3.0.0",
281 "bare-stream": "^2.6.4",
282 "bare-url": "^2.2.2",
283 "fast-fifo": "^1.3.2"
284 },
285 "engines": {
286 "bare": ">=1.16.0"
287 },
288 "peerDependencies": {
289 "bare-buffer": "*"
290 },
291 "peerDependenciesMeta": {
292 "bare-buffer": {
293 "optional": true
294 }
295 }
296 },
297 "node_modules/bare-hrtime": {
298 "version": "2.1.1",
299 "resolved": "https://registry.npmjs.org/bare-hrtime/-/bare-hrtime-2.1.1.tgz",
300 "integrity": "sha512-VMb3tHo05gsnbu3OXTmkDiwTjMlOsbQmKoysKqKEyR09m77TuDrYFbj3Q5GGk10dAKsUHrnXmwCaeJqzVpB5ZA==",
301 "dev": true,
302 "license": "Apache-2.0"
303 },
304 "node_modules/bare-http-parser": {
305 "version": "1.1.3",
306 "resolved": "https://registry.npmjs.org/bare-http-parser/-/bare-http-parser-1.1.3.tgz",
307 "integrity": "sha512-+dhVvQi6brHq14L/XHNRQ+TLuVE76VjRmMt61wVEtS+Od8xUslfMHWJN/ZjIIt3RtTG6vPuA+x9cOh7KrkBJsA==",
308 "dev": true,
309 "license": "Apache-2.0"
310 },
311 "node_modules/bare-http1": {
312 "version": "4.5.5",
313 "resolved": "https://registry.npmjs.org/bare-http1/-/bare-http1-4.5.5.tgz",
314 "integrity": "sha512-ADITiRo0huP76JGMbv6Arsh9KehHqjEBoYcmjvAo67IY78+/9mV2MeKLLCkiJSFxA85T/m8cTaE44OwJQCcwdw==",
315 "dev": true,
316 "license": "Apache-2.0",
317 "dependencies": {
318 "bare-events": "^2.6.0",
319 "bare-http-parser": "^1.1.1",
320 "bare-stream": "^2.10.0",
321 "bare-tcp": "^2.2.0"
322 },
323 "peerDependencies": {
324 "bare-buffer": "*",
325 "bare-url": "*"
326 },
327 "peerDependenciesMeta": {
328 "bare-buffer": {
329 "optional": true
330 },
331 "bare-url": {
332 "optional": true
333 }
334 }
335 },
336 "node_modules/bare-https": {
337 "version": "2.1.3",
338 "resolved": "https://registry.npmjs.org/bare-https/-/bare-https-2.1.3.tgz",
339 "integrity": "sha512-0TI/mJXQGYXmG7UUyWEG+KCJusayIAQLywUjFAskDoKuxfqVnGF+M/mTMrEV8J64DaIdU+5x761FvgmT7M68tA==",
340 "dev": true,
341 "license": "Apache-2.0",
342 "dependencies": {
343 "bare-http1": "^4.4.0",
344 "bare-tcp": "^2.2.0",
345 "bare-tls": "^2.0.0"
346 }
347 },
348 "node_modules/bare-inspect": {
349 "version": "3.1.4",
350 "resolved": "https://registry.npmjs.org/bare-inspect/-/bare-inspect-3.1.4.tgz",
351 "integrity": "sha512-jfW5KRA84o3REpI6Vr4nbvMn+hqVAw8GU1mMdRwUsY5yJovQamxYeKGVKGqdzs+8ZbG4jRzGUXP/3Ji/DnqfPg==",
352 "license": "Apache-2.0",
353 "dependencies": {
354 "bare-ansi-escapes": "^2.1.0",
355 "bare-type": "^1.0.0"
356 },
357 "engines": {
358 "bare": ">=1.18.0"
359 }
360 },
361 "node_modules/bare-inspector": {
362 "version": "4.0.3",
363 "resolved": "https://registry.npmjs.org/bare-inspector/-/bare-inspector-4.0.3.tgz",
364 "integrity": "sha512-yYk6+7tTVKJKHOja5+QBn989ETv8oVsmwoH0nCM+QYC6w5MC03GC4aQNK+lipAZSz1EaAj42WZ8Wewjpy0L9TA==",
365 "dev": true,
366 "license": "Apache-2.0",
367 "dependencies": {
368 "bare-events": "^2.1.0",
369 "bare-http1": "^4.0.0",
370 "bare-stream": "^2.0.0",
371 "bare-url": "^2.0.0",
372 "bare-ws": "^2.0.0"
373 },
374 "engines": {
375 "bare": ">=1.2.0"
376 },
377 "peerDependencies": {
378 "bare-tcp": "*"
379 },
380 "peerDependenciesMeta": {
381 "bare-tcp": {
382 "optional": true
383 }
384 }
385 },
386 "node_modules/bare-module": {
387 "version": "6.1.3",
388 "resolved": "https://registry.npmjs.org/bare-module/-/bare-module-6.1.3.tgz",
389 "integrity": "sha512-5XWsVHsvtWMH4tK4DQWgpNTV0t/sg3ZrAaQLIxrwjrS5+u8Q9vEgc/zQ4QaDPWDse/y/5h+d+YG1Q0JfSMt0zA==",
390 "dev": true,
391 "license": "Apache-2.0",
392 "dependencies": {
393 "bare-bundle": "^1.3.0",
394 "bare-module-lexer": "^1.0.0",
395 "bare-module-resolve": "^1.8.0",
396 "bare-path": "^3.0.0",
397 "bare-url": "^2.0.1"
398 },
399 "engines": {
400 "bare": ">=1.23.0"
401 },
402 "peerDependencies": {
403 "bare-buffer": "*"
404 },
405 "peerDependenciesMeta": {
406 "bare-buffer": {
407 "optional": true
408 }
409 }
410 },
411 "node_modules/bare-module-lexer": {
412 "version": "1.4.7",
413 "resolved": "https://registry.npmjs.org/bare-module-lexer/-/bare-module-lexer-1.4.7.tgz",
414 "integrity": "sha512-0klU4eMsjh/wcxi8FdHmNom2j2F4kmkXOhyJFL9qTaSFp2lE3m6BtbKgMHY8R5miqC9r8/IfA8wzXnC5Os14WA==",
415 "dev": true,
416 "license": "Apache-2.0",
417 "dependencies": {
418 "require-addon": "^1.0.2"
419 },
420 "peerDependencies": {
421 "bare-buffer": "*"
422 },
423 "peerDependenciesMeta": {
424 "bare-buffer": {
425 "optional": true
426 }
427 }
428 },
429 "node_modules/bare-module-resolve": {
430 "version": "1.12.1",
431 "resolved": "https://registry.npmjs.org/bare-module-resolve/-/bare-module-resolve-1.12.1.tgz",
432 "integrity": "sha512-hbmAPyFpEq8FoZMd5sFO3u6MC5feluWoGE8YKlA8fCrl6mNtx68Wjg4DTiDJcqRJaovTvOYKfYngoBUnbaT7eg==",
433 "license": "Apache-2.0",
434 "dependencies": {
435 "bare-semver": "^1.0.0"
436 },
437 "peerDependencies": {
438 "bare-url": "*"
439 },
440 "peerDependenciesMeta": {
441 "bare-url": {
442 "optional": true
443 }
444 }
445 },
446 "node_modules/bare-net": {
447 "version": "2.3.1",
448 "resolved": "https://registry.npmjs.org/bare-net/-/bare-net-2.3.1.tgz",
449 "integrity": "sha512-MypSqDKpDU2Xt7FIfazn5yGvRnV09gFcIPHGWstW0gxuzA4tucTcwJSZeos97C4F89vtU5oGwXDN/HrGN6Y4Jw==",
450 "dev": true,
451 "license": "Apache-2.0",
452 "dependencies": {
453 "bare-events": "^2.2.2",
454 "bare-pipe": "^4.0.0",
455 "bare-stream": "^2.0.0",
456 "bare-tcp": "^2.0.0"
457 }
458 },
459 "node_modules/bare-os": {
460 "version": "3.8.7",
461 "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.7.tgz",
462 "integrity": "sha512-G4Gr1UsGeEy2qtDTZwL7JFLo2wapUarz7iTMcYcMFdS89AIQuBoyjgXZz0Utv7uHs3xA9LckhVbeBi8lEQrC+w==",
463 "devOptional": true,
464 "license": "Apache-2.0",
465 "engines": {
466 "bare": ">=1.14.0"
467 }
468 },
469 "node_modules/bare-path": {
470 "version": "3.0.0",
471 "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz",
472 "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==",
473 "devOptional": true,
474 "license": "Apache-2.0",
475 "dependencies": {
476 "bare-os": "^3.0.1"
477 }
478 },
479 "node_modules/bare-pipe": {
480 "version": "4.1.5",
481 "resolved": "https://registry.npmjs.org/bare-pipe/-/bare-pipe-4.1.5.tgz",
482 "integrity": "sha512-6OfxaG8JSkRh3Gc4hzHRsxNt+yu2PpN7lrv1V+T78GdknWQkVGwiEvu4m+1nbfk8cMVQ0TGxRvQ90XA4rhnTuw==",
483 "dev": true,
484 "license": "Apache-2.0",
485 "dependencies": {
486 "bare-events": "^2.0.0",
487 "bare-stream": "^2.0.0"
488 },
489 "engines": {
490 "bare": ">=1.16.0"
491 }
492 },
493 "node_modules/bare-process": {
494 "version": "4.4.1",
495 "resolved": "https://registry.npmjs.org/bare-process/-/bare-process-4.4.1.tgz",
496 "integrity": "sha512-JfcTtymq6akqM2bdyTsP4A4GYJceBzb91k/ECmFps75uFf6uO33SM1bOZsRAqyRXExabsQJLn5S41NBl8HTM4A==",
497 "dev": true,
498 "license": "Apache-2.0",
499 "dependencies": {
500 "bare-abort": "^2.0.13",
501 "bare-env": "^3.0.0",
502 "bare-events": "^2.3.1",
503 "bare-hrtime": "^2.0.0",
504 "bare-os": "^3.7.1",
505 "bare-signals": "^4.0.0",
506 "bare-stdio": "^1.0.1"
507 }
508 },
509 "node_modules/bare-semver": {
510 "version": "1.0.3",
511 "resolved": "https://registry.npmjs.org/bare-semver/-/bare-semver-1.0.3.tgz",
512 "integrity": "sha512-HS/A30bi2+PiRJfU6R4+Kp+6KeLSCSByjYM2iiobOKzLAvtu1CT+S8xWfiU7wz0erknjkUoC+yXy108tzIuP5Q==",
513 "license": "Apache-2.0"
514 },
515 "node_modules/bare-signals": {
516 "version": "4.2.0",
517 "resolved": "https://registry.npmjs.org/bare-signals/-/bare-signals-4.2.0.tgz",
518 "integrity": "sha512-fNHMOdQIlYuTvMB3Oh9Apk99hLKn351+Ir8vz+khiPTcOqIyGG4uWWjdLTzxWdYGsA0eT+We3y0K74hjj2nq7A==",
519 "dev": true,
520 "license": "Apache-2.0",
521 "dependencies": {
522 "bare-events": "^2.5.3",
523 "bare-os": "^3.3.1"
524 },
525 "engines": {
526 "bare": ">=1.7.0"
527 }
528 },
529 "node_modules/bare-stdio": {
530 "version": "1.0.2",
531 "resolved": "https://registry.npmjs.org/bare-stdio/-/bare-stdio-1.0.2.tgz",
532 "integrity": "sha512-3WJDqtvVGP4f+j68kyEC05umOYNwKJ1xG+YAXL8yZ605WgNqiRhVaFq+mVIhBt2eKNp7pa5vCQdhOt1pNh79SA==",
533 "dev": true,
534 "license": "Apache-2.0",
535 "dependencies": {
536 "bare-fs": "^4.5.2",
537 "bare-pipe": "^4.1.5",
538 "bare-tty": "^5.0.3"
539 }
540 },
541 "node_modules/bare-stream": {
542 "version": "2.12.0",
543 "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.12.0.tgz",
544 "integrity": "sha512-w28i8lkBgREV3rPXGbgK+BO66q+ZpKqRWrZLiCdmmUlLPrQ45CzkvRhN+7lnv00Gpi2zy5naRxnUFAxCECDm9g==",
545 "license": "Apache-2.0",
546 "dependencies": {
547 "streamx": "^2.25.0",
548 "teex": "^1.0.1"
549 },
550 "peerDependencies": {
551 "bare-abort-controller": "*",
552 "bare-buffer": "*",
553 "bare-events": "*"
554 },
555 "peerDependenciesMeta": {
556 "bare-abort-controller": {
557 "optional": true
558 },
559 "bare-buffer": {
560 "optional": true
561 },
562 "bare-events": {
563 "optional": true
564 }
565 }
566 },
567 "node_modules/bare-stylize": {
568 "version": "0.0.1",
569 "resolved": "https://registry.npmjs.org/bare-stylize/-/bare-stylize-0.0.1.tgz",
570 "integrity": "sha512-l3MjmIl476bWijYWf3RbE+osl4iuXSOMudzp0vAqzIK7gPgn/+G3oAxp8Oin9CFF911KBP0LO9kts8Ci8mGZaQ==",
571 "dev": true,
572 "license": "Apache-2.0",
573 "dependencies": {
574 "bare-ansi-escapes": "^2.2.3",
575 "bare-process": "^4.2.1"
576 }
577 },
578 "node_modules/bare-subprocess": {
579 "version": "5.2.3",
580 "resolved": "https://registry.npmjs.org/bare-subprocess/-/bare-subprocess-5.2.3.tgz",
581 "integrity": "sha512-07wwswlV7M3sC9IykbZRZ/jHAkrXFWVLqdBWGv1y0ojCimtRD9hGwxdHmR5FUFmDUZLNsBmTYJNQqgio5+A85Q==",
582 "dev": true,
583 "license": "Apache-2.0",
584 "dependencies": {
585 "bare-env": "^3.0.0",
586 "bare-events": "^2.5.4",
587 "bare-os": "^3.0.1",
588 "bare-pipe": "^4.0.0",
589 "bare-url": "^2.2.2"
590 },
591 "engines": {
592 "bare": ">=1.7.0"
593 },
594 "peerDependencies": {
595 "bare-buffer": "*"
596 },
597 "peerDependenciesMeta": {
598 "bare-buffer": {
599 "optional": true
600 }
601 }
602 },
603 "node_modules/bare-tcp": {
604 "version": "2.2.7",
605 "resolved": "https://registry.npmjs.org/bare-tcp/-/bare-tcp-2.2.7.tgz",
606 "integrity": "sha512-rjpqNQ2cOCkNo3NeYA/W4GTK3DRkl8sDHO3uos+AEswUjLC8XXMQF8WrJCSjlIowCbS6NUVxKE92X5RGXjyefg==",
607 "dev": true,
608 "license": "Apache-2.0",
609 "dependencies": {
610 "bare-dns": "^2.0.4",
611 "bare-events": "^2.5.4",
612 "bare-stream": "^2.6.4"
613 },
614 "engines": {
615 "bare": ">=1.16.0"
616 }
617 },
618 "node_modules/bare-tls": {
619 "version": "2.2.1",
620 "resolved": "https://registry.npmjs.org/bare-tls/-/bare-tls-2.2.1.tgz",
621 "integrity": "sha512-hZ+ZqwrUO4dyH7/6WYkYWjgAFNJKjzwEYJiDaMnMs+eRleBDjQ3CvNZawpkw0Ar9jnM9NZK6+f6GqjkZ2FLGmQ==",
622 "dev": true,
623 "license": "Apache-2.0",
624 "dependencies": {
625 "bare-net": "^2.0.1",
626 "bare-stream": "^2.6.4"
627 },
628 "engines": {
629 "bare": ">=1.7.0"
630 }
631 },
632 "node_modules/bare-tty": {
633 "version": "5.1.0",
634 "resolved": "https://registry.npmjs.org/bare-tty/-/bare-tty-5.1.0.tgz",
635 "integrity": "sha512-EZLvW4A+XiJgI3TW+e1pMME9PIJsfEXe/DA/WSKzIkq/v7Yarpv/rvG6Z5pGnpo4V/Bd+qopwnCLSR71hMMBYA==",
636 "dev": true,
637 "license": "Apache-2.0",
638 "dependencies": {
639 "bare-events": "^2.2.0",
640 "bare-signals": "^4.0.0",
641 "bare-stream": "^2.0.0"
642 },
643 "engines": {
644 "bare": ">=1.16.0"
645 }
646 },
647 "node_modules/bare-type": {
648 "version": "1.1.0",
649 "resolved": "https://registry.npmjs.org/bare-type/-/bare-type-1.1.0.tgz",
650 "integrity": "sha512-LdtnnEEYldOc87Dr4GpsKnStStZk3zfgoEMXy8yvEZkXrcCv9RtYDrUYWFsBQHtaB0s1EUWmcvS6XmEZYIj3Bw==",
651 "license": "Apache-2.0",
652 "engines": {
653 "bare": ">=1.2.0"
654 }
655 },
656 "node_modules/bare-url": {
657 "version": "2.4.0",
658 "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.0.tgz",
659 "integrity": "sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==",
660 "devOptional": true,
661 "license": "Apache-2.0",
662 "peer": true,
663 "dependencies": {
664 "bare-path": "^3.0.0"
665 }
666 },
667 "node_modules/bare-utils": {
668 "version": "1.6.0",
669 "resolved": "https://registry.npmjs.org/bare-utils/-/bare-utils-1.6.0.tgz",
670 "integrity": "sha512-WhQEIkkAxkSnW7u1QgrI0AfNm5JpMruETXeYsb5qnkBJ0TTfNKygZmsh6rkoHBANaV+C/7Jed7bJP9OmEHG7rQ==",
671 "dev": true,
672 "license": "Apache-2.0",
673 "dependencies": {
674 "bare-debug-log": "^2.0.0",
675 "bare-encoding": "^1.0.0",
676 "bare-format": "^1.0.0",
677 "bare-inspect": "^3.0.0",
678 "bare-stylize": "^0.0.1",
679 "bare-type": "^1.0.6"
680 }
681 },
682 "node_modules/bare-v8-to-istanbul": {
683 "version": "1.0.2",
684 "resolved": "https://registry.npmjs.org/bare-v8-to-istanbul/-/bare-v8-to-istanbul-1.0.2.tgz",
685 "integrity": "sha512-CM0wPgyQtXTQ7h4q8NjbTZ/FH5he0Jkiwgpq0lFZZA5tkVZzmQ/9ul4R7E+cNlGZJIZlQZ9v4CwbgVaFG3zOAA==",
686 "dev": true,
687 "license": "Apache-2.0",
688 "dependencies": {
689 "bare-assert": "^1.0.2",
690 "bare-fs": "^4.1.2",
691 "bare-module": "^6.1.2",
692 "bare-path": "^3.0.0",
693 "bare-process": "^4.2.0",
694 "bare-url": "^2.1.5",
695 "bare-utils": "^1.2.0",
696 "v8-to-istanbul": "^9.3.0",
697 "which-runtime": "^1.2.1"
698 }
699 },
700 "node_modules/bare-ws": {
701 "version": "2.1.0",
702 "resolved": "https://registry.npmjs.org/bare-ws/-/bare-ws-2.1.0.tgz",
703 "integrity": "sha512-2gEWlPK9iyBchACdIY6oQXgmDz3KLrChdwrPgmU3IVXOFTnxTqSUT27WE/+izd4QojHj/SsqDkQiD2HDvuTdAA==",
704 "dev": true,
705 "license": "Apache-2.0",
706 "dependencies": {
707 "bare-crypto": "^1.2.0",
708 "bare-events": "^2.3.1",
709 "bare-http1": "^4.0.0",
710 "bare-https": "^2.0.0",
711 "bare-stream": "^2.1.2"
712 },
713 "peerDependencies": {
714 "bare-buffer": "*",
715 "bare-url": "*"
716 },
717 "peerDependenciesMeta": {
718 "bare-buffer": {
719 "optional": true
720 },
721 "bare-url": {
722 "optional": true
723 }
724 }
725 },
726 "node_modules/bits-to-bytes": {
727 "version": "1.3.0",
728 "resolved": "https://registry.npmjs.org/bits-to-bytes/-/bits-to-bytes-1.3.0.tgz",
729 "integrity": "sha512-OJoHTpFXS9bXHBCekGTByf3MqM8CGblBDIduKQeeVVeiU9dDWywSSirXIBYGgg3d1zbVuvnMa1vD4r6PA0kOKg==",
730 "license": "ISC",
731 "dependencies": {
732 "b4a": "^1.5.0"
733 }
734 },
735 "node_modules/blind-relay": {
736 "version": "1.4.0",
737 "resolved": "https://registry.npmjs.org/blind-relay/-/blind-relay-1.4.0.tgz",
738 "integrity": "sha512-6xt7fDfCs6eGmNNym6I9N42jmjcMQn2qwwOVnkP9ZnrkXFk6c4/tdO1xqRmDEzKzV8gigd+DVdCUG/RUYnen7Q==",
739 "license": "Apache-2.0",
740 "dependencies": {
741 "b4a": "^1.6.4",
742 "bare-events": "^2.2.0",
743 "bits-to-bytes": "^1.3.0",
744 "compact-encoding": "^2.12.0",
745 "compact-encoding-bitfield": "^1.0.0",
746 "protomux": "^3.5.1",
747 "sodium-universal": "^5.0.0",
748 "streamx": "^2.15.1"
749 }
750 },
751 "node_modules/bogon": {
752 "version": "1.2.0",
753 "resolved": "https://registry.npmjs.org/bogon/-/bogon-1.2.0.tgz",
754 "integrity": "sha512-FqOBr/1VMzCOsoJd+fzNUMarUYki2+TKt07A2+xaulsNx4r53iJ7MV5k0jbqg7W2U0CsLqxCZOrFibdG6h6HSg==",
755 "license": "MIT",
756 "dependencies": {
757 "compact-encoding": "^2.11.0",
758 "compact-encoding-net": "^1.2.0"
759 }
760 },
761 "node_modules/brittle": {
762 "version": "3.19.1",
763 "resolved": "https://registry.npmjs.org/brittle/-/brittle-3.19.1.tgz",
764 "integrity": "sha512-4Ted1Mt9o9B6oIA6ImJJCtB/Fv++ZO3IDNQgRcHOXWSYGRUidgxchaGrUBaRn+4mlneXrgInPkCPzi0jO8qKbA==",
765 "dev": true,
766 "license": "Apache-2.0",
767 "dependencies": {
768 "b4a": "^1.6.0",
769 "bare-assert": "^1.0.2",
770 "bare-cov": "^1.1.0",
771 "bare-fs": "^4.1.6",
772 "bare-os": "^3.6.1",
773 "bare-path": "^3.0.0",
774 "bare-process": "^4.2.1",
775 "bare-subprocess": "^5.0.0",
776 "bare-url": "^2.1.6",
777 "error-stack-parser": "^2.1.4",
778 "globbie": "^1.0.2",
779 "paparam": "^1.6.2",
780 "same-object": "^1.0.2",
781 "test-tmp": "^1.4.0",
782 "tmatch": "^5.0.0"
783 },
784 "bin": {
785 "brittle": "bin/node.js",
786 "brittle-bare": "bin/bare.js",
787 "brittle-node": "bin/node.js",
788 "brittle-pear": "bin/pear.js"
789 }
790 },
791 "node_modules/compact-encoding": {
792 "version": "2.19.2",
793 "resolved": "https://registry.npmjs.org/compact-encoding/-/compact-encoding-2.19.2.tgz",
794 "integrity": "sha512-/YjhHQE/5L4F7l5Bht69dRbP9RV6zoJPeowi8bMKQxNKe3Nh6hOY8pBGoVE9fz5GaWfEd8fWJ2aU9sB4KZuMYg==",
795 "license": "Apache-2.0",
796 "dependencies": {
797 "b4a": "^1.3.0"
798 }
799 },
800 "node_modules/compact-encoding-bitfield": {
801 "version": "1.0.0",
802 "resolved": "https://registry.npmjs.org/compact-encoding-bitfield/-/compact-encoding-bitfield-1.0.0.tgz",
803 "integrity": "sha512-3nMVKUg+PF72UHfainmCL8uKvyWfxsjqOtUY+HiMPGLPCTjnwzoKfFAMo1Ad7nwTPdjBqtGK5b3BOFTFW4EBTg==",
804 "license": "ISC",
805 "dependencies": {
806 "compact-encoding": "^2.4.1"
807 }
808 },
809 "node_modules/compact-encoding-net": {
810 "version": "1.2.0",
811 "resolved": "https://registry.npmjs.org/compact-encoding-net/-/compact-encoding-net-1.2.0.tgz",
812 "integrity": "sha512-LVXpNpF7PGQeHRVVLGgYWzuVoYAaDZvKUsUxRioGfkotzvOh4AzoQF1HBH3zMNaSnx7gJXuUr3hkjnijaH/Eng==",
813 "license": "ISC",
814 "dependencies": {
815 "compact-encoding": "^2.4.1"
816 }
817 },
818 "node_modules/convert-source-map": {
819 "version": "2.0.0",
820 "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
821 "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
822 "dev": true,
823 "license": "MIT"
824 },
825 "node_modules/dht-rpc": {
826 "version": "6.26.3",
827 "resolved": "https://registry.npmjs.org/dht-rpc/-/dht-rpc-6.26.3.tgz",
828 "integrity": "sha512-KuLfRv/hecUHipQcTXHpVv4/N4Jhpww5sLdsrn3Edm5oHwzK9SgNV34hNt7a2aVZCOcG5SfP4AvcQ7pI+y9YNg==",
829 "license": "MIT",
830 "dependencies": {
831 "adaptive-timeout": "^1.0.1",
832 "b4a": "^1.6.1",
833 "bare-events": "^2.2.0",
834 "compact-encoding": "^2.11.0",
835 "compact-encoding-net": "^1.2.0",
836 "fast-fifo": "^1.1.0",
837 "kademlia-routing-table": "^1.0.1",
838 "nat-sampler": "^1.0.1",
839 "sodium-universal": "^5.0.0",
840 "streamx": "^2.13.2",
841 "time-ordered-set": "^2.0.0",
842 "udx-native": "^1.5.3"
843 }
844 },
845 "node_modules/error-stack-parser": {
846 "version": "2.1.4",
847 "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
848 "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
849 "dev": true,
850 "license": "MIT",
851 "dependencies": {
852 "stackframe": "^1.3.4"
853 }
854 },
855 "node_modules/events-universal": {
856 "version": "1.0.1",
857 "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
858 "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==",
859 "license": "Apache-2.0",
860 "dependencies": {
861 "bare-events": "^2.7.0"
862 }
863 },
864 "node_modules/fast-fifo": {
865 "version": "1.3.2",
866 "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
867 "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
868 "license": "MIT"
869 },
870 "node_modules/globbie": {
871 "version": "1.0.3",
872 "resolved": "https://registry.npmjs.org/globbie/-/globbie-1.0.3.tgz",
873 "integrity": "sha512-hcryJmKcftf82xfBWTWxuUITWIIoYO3ec104V17SMHGFl6VLbm1d1Ju9LX9L+jyJTwICpemX/dmPI/HGYoKr1A==",
874 "dev": true,
875 "license": "Apache-2.0",
876 "dependencies": {
877 "bare-fs": "^4.1.2",
878 "bare-path": "^3.0.0",
879 "bare-process": "^4.2.1",
880 "picomatch": "^4.0.2"
881 }
882 },
883 "node_modules/hypercore-crypto": {
884 "version": "3.6.1",
885 "resolved": "https://registry.npmjs.org/hypercore-crypto/-/hypercore-crypto-3.6.1.tgz",
886 "integrity": "sha512-ltIz2uDwy9pO/ZGTvqcjzyBkvt6O4cVm4r/nNxh0GFs/RbQtqP/i4wCvLEdmU7ptgtnw7fI67WYD1aHPuv4OVA==",
887 "license": "MIT",
888 "dependencies": {
889 "b4a": "^1.6.6",
890 "compact-encoding": "^2.15.0",
891 "sodium-universal": "^5.0.0"
892 }
893 },
894 "node_modules/hypercore-id-encoding": {
895 "version": "1.3.0",
896 "resolved": "https://registry.npmjs.org/hypercore-id-encoding/-/hypercore-id-encoding-1.3.0.tgz",
897 "integrity": "sha512-W6sHdGo5h7LXEsoWfKf/KfuROZmZRQDlGqJF2EPHW+noCK66Vvr0+zE6cL0vqQi18s0kQPeN7Sq3QyR0Ytc2VQ==",
898 "license": "Apache-2.0",
899 "dependencies": {
900 "b4a": "^1.5.3",
901 "z32": "^1.0.0"
902 }
903 },
904 "node_modules/hyperdht": {
905 "version": "6.29.6",
906 "resolved": "https://registry.npmjs.org/hyperdht/-/hyperdht-6.29.6.tgz",
907 "integrity": "sha512-bMMtw02fhiALdsTVLNZ/VFmMZuEY8kxb0/Rprl6oYF4/TCS653i3FDjtJeRbqtnAzwAj6dVZ/EwhoNOSCFGaYQ==",
908 "license": "MIT",
909 "dependencies": {
910 "@hyperswarm/secret-stream": "^6.6.2",
911 "b4a": "^1.3.1",
912 "bare-events": "^2.2.0",
913 "blind-relay": "^1.3.0",
914 "bogon": "^1.0.0",
915 "compact-encoding": "^2.4.1",
916 "dht-rpc": "^6.15.1",
917 "hypercore-crypto": "^3.3.0",
918 "hypercore-id-encoding": "^1.2.0",
919 "noise-curve-ed": "^2.0.0",
920 "noise-handshake": "^4.0.0",
921 "record-cache": "^1.1.1",
922 "safety-catch": "^1.0.1",
923 "signal-promise": "^1.0.3",
924 "sodium-universal": "^5.0.1",
925 "streamx": "^2.16.1",
926 "unslab": "^1.3.0",
927 "xache": "^1.1.0"
928 },
929 "bin": {
930 "hyperdht": "bin.js"
931 }
932 },
933 "node_modules/hyperswarm": {
934 "version": "4.17.0",
935 "resolved": "https://registry.npmjs.org/hyperswarm/-/hyperswarm-4.17.0.tgz",
936 "integrity": "sha512-oe86sK961Ueg7rvDN/veFwG8xH+Iv6vObPhGDkPJcDVxk/NduW41ZhAcVDnHzRbm7S0eLU7WaDUvehOYoKSpRQ==",
937 "license": "MIT",
938 "dependencies": {
939 "b4a": "^1.3.1",
940 "bare-events": "^2.2.0",
941 "hyperdht": "^6.21.0",
942 "safety-catch": "^1.0.2",
943 "shuffled-priority-queue": "^2.1.0",
944 "streamx": "^2.22.1",
945 "unslab": "^1.3.0"
946 }
947 },
948 "node_modules/kademlia-routing-table": {
949 "version": "1.0.6",
950 "resolved": "https://registry.npmjs.org/kademlia-routing-table/-/kademlia-routing-table-1.0.6.tgz",
951 "integrity": "sha512-Ve6jwIlUCYvUzBnXnzVRHDZCFgXURW9gmF3r7n05kZs/2rNbLHXwGdcq0qIaSwdmJCvtosgR4JensnVU65hzNQ==",
952 "license": "MIT",
953 "dependencies": {
954 "bare-events": "^2.2.0"
955 }
956 },
957 "node_modules/nanoassert": {
958 "version": "2.0.0",
959 "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz",
960 "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==",
961 "license": "ISC"
962 },
963 "node_modules/nat-sampler": {
964 "version": "1.0.1",
965 "resolved": "https://registry.npmjs.org/nat-sampler/-/nat-sampler-1.0.1.tgz",
966 "integrity": "sha512-yQvyNN7xbqR8crTKk3U8gRgpcV1Az+vfCEijiHu9oHHsnIl8n3x+yXNHl42M6L3czGynAVoOT9TqBfS87gDdcw==",
967 "license": "MIT"
968 },
969 "node_modules/noise-curve-ed": {
970 "version": "2.1.0",
971 "resolved": "https://registry.npmjs.org/noise-curve-ed/-/noise-curve-ed-2.1.0.tgz",
972 "integrity": "sha512-zAzJx+VwZM3w6EA1hTmDhJfvAnCeBQn/1FAeZ0LtGxCcCtlAK/uJXQVF/eDVUOaAZ286lHlx77WJ+qj9SmsRRg==",
973 "license": "ISC",
974 "dependencies": {
975 "b4a": "^1.1.0",
976 "nanoassert": "^2.0.0",
977 "sodium-universal": "^5.0.0"
978 }
979 },
980 "node_modules/noise-handshake": {
981 "version": "4.2.0",
982 "resolved": "https://registry.npmjs.org/noise-handshake/-/noise-handshake-4.2.0.tgz",
983 "integrity": "sha512-9O/VTNX/E2/AToyMTTDU0J/4WhaXMTdqc2DHs9vf+snoZ0cenSBq0dNYTVV1snYYEkmo6QeRrYMxtqtoYnY+LA==",
984 "license": "Apache-2.0",
985 "dependencies": {
986 "b4a": "^1.1.0",
987 "nanoassert": "^2.0.0",
988 "sodium-universal": "^5.0.0"
989 }
990 },
991 "node_modules/paparam": {
992 "version": "1.10.1",
993 "resolved": "https://registry.npmjs.org/paparam/-/paparam-1.10.1.tgz",
994 "integrity": "sha512-viyQI64VIja0Za3njIzhoEP8ZVkgPowhZPuG0E96NwBfYJ6ZIyrrlhWGtFPkdN7eYLl2L8CTWL+wla0evm1KKQ==",
995 "dev": true,
996 "license": "Apache-2.0"
997 },
998 "node_modules/picomatch": {
999 "version": "4.0.4",
1000 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
1001 "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
1002 "dev": true,
1003 "license": "MIT",
1004 "engines": {
1005 "node": ">=12"
1006 },
1007 "funding": {
1008 "url": "https://github.com/sponsors/jonschlinkert"
1009 }
1010 },
1011 "node_modules/protomux": {
1012 "version": "3.10.1",
1013 "resolved": "https://registry.npmjs.org/protomux/-/protomux-3.10.1.tgz",
1014 "integrity": "sha512-jgBqx8ZyaBWea/DFG4eOu1scOaeBwcnagiRC1XFVrjeGt7oAb0Pk5udPpBUpJ4DJBRjra50jD6YcZiQQTRqaaA==",
1015 "license": "MIT",
1016 "dependencies": {
1017 "b4a": "^1.3.1",
1018 "compact-encoding": "^2.5.1",
1019 "queue-tick": "^1.0.0",
1020 "safety-catch": "^1.0.1",
1021 "unslab": "^1.3.0"
1022 }
1023 },
1024 "node_modules/queue-tick": {
1025 "version": "1.0.1",
1026 "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
1027 "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
1028 "license": "MIT"
1029 },
1030 "node_modules/ready-resource": {
1031 "version": "1.2.0",
1032 "resolved": "https://registry.npmjs.org/ready-resource/-/ready-resource-1.2.0.tgz",
1033 "integrity": "sha512-nfcco/8iAFV0M+2PYnmIc+/xY0iRb35d42HFHQ7AfjulbGEAFa+XWpByfwSyeVeiBoMLLFVMv1HixxNCqzSQ1g==",
1034 "license": "MIT",
1035 "dependencies": {
1036 "bare-events": "^2.2.0"
1037 }
1038 },
1039 "node_modules/record-cache": {
1040 "version": "1.2.0",
1041 "resolved": "https://registry.npmjs.org/record-cache/-/record-cache-1.2.0.tgz",
1042 "integrity": "sha512-kyy3HWCez2WrotaL3O4fTn0rsIdfRKOdQQcEJ9KpvmKmbffKVvwsloX063EgRUlpJIXHiDQFhJcTbZequ2uTZw==",
1043 "license": "MIT",
1044 "dependencies": {
1045 "b4a": "^1.3.1"
1046 }
1047 },
1048 "node_modules/require-addon": {
1049 "version": "1.2.0",
1050 "resolved": "https://registry.npmjs.org/require-addon/-/require-addon-1.2.0.tgz",
1051 "integrity": "sha512-VNPDZlYgIYQwWp9jMTzljx+k0ZtatKlcvOhktZ/anNPI3dQ9NXk7cq2U4iJ1wd9IrytRnYhyEocFWbkdPb+MYA==",
1052 "license": "Apache-2.0",
1053 "dependencies": {
1054 "bare-addon-resolve": "^1.3.0"
1055 },
1056 "engines": {
1057 "bare": ">=1.10.0"
1058 }
1059 },
1060 "node_modules/safety-catch": {
1061 "version": "1.0.3",
1062 "resolved": "https://registry.npmjs.org/safety-catch/-/safety-catch-1.0.3.tgz",
1063 "integrity": "sha512-Zq+J1TefpoEq/HTUabo0YXX5MNvttjWYODGohgPBO2jfko8Wqx3JYMgE823szDFVamdH5PlpByvfiWScTdSYDA==",
1064 "license": "MIT"
1065 },
1066 "node_modules/same-object": {
1067 "version": "1.0.2",
1068 "resolved": "https://registry.npmjs.org/same-object/-/same-object-1.0.2.tgz",
1069 "integrity": "sha512-csHWhvUsLbIOHDM/nP+KHWM+BLPsIzWkFa8HbzaI0G7BqKXgx+7FJpKTGgLXyz5amfdY2OVBcmXTqYOMEk04og==",
1070 "dev": true,
1071 "license": "MIT"
1072 },
1073 "node_modules/shuffled-priority-queue": {
1074 "version": "2.1.0",
1075 "resolved": "https://registry.npmjs.org/shuffled-priority-queue/-/shuffled-priority-queue-2.1.0.tgz",
1076 "integrity": "sha512-xhdh7fHyMsr0m/w2kDfRJuBFRS96b9l8ZPNWGaQ+PMvnUnZ/Eh+gJJ9NsHBd7P9k0399WYlCLzsy18EaMfyadA==",
1077 "license": "MIT",
1078 "dependencies": {
1079 "unordered-set": "^2.0.1"
1080 }
1081 },
1082 "node_modules/signal-promise": {
1083 "version": "1.0.3",
1084 "resolved": "https://registry.npmjs.org/signal-promise/-/signal-promise-1.0.3.tgz",
1085 "integrity": "sha512-WBgv0UnIq2C+Aeh0/n+IRpP6967eIx9WpynTUoiW3isPpfe1zu2LJzyfXdo9Tgef8yR/sGjcMvoUXD7EYdiz+g==",
1086 "license": "MIT"
1087 },
1088 "node_modules/sodium-native": {
1089 "version": "5.1.0",
1090 "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-5.1.0.tgz",
1091 "integrity": "sha512-3RxgyWyJlhTsABPnJVpCI5CoTDANZTqqFrEPqr+kjfnRaBihpVtMUE3yTF40ukdoB1APXeoBNKF3MzZAIHg39g==",
1092 "license": "MIT",
1093 "dependencies": {
1094 "bare-assert": "^1.2.0",
1095 "require-addon": "^1.1.0",
1096 "which-runtime": "^1.2.1"
1097 },
1098 "engines": {
1099 "bare": ">=1.16.0"
1100 }
1101 },
1102 "node_modules/sodium-secretstream": {
1103 "version": "1.2.0",
1104 "resolved": "https://registry.npmjs.org/sodium-secretstream/-/sodium-secretstream-1.2.0.tgz",
1105 "integrity": "sha512-q/DbraNFXm1KfCiiZvapmz5UC3OlpirYFIvBK2MhGaOFSb3gRyk8OXTi17UI9SGfshQNCpsVvlopogbzZNyW6Q==",
1106 "license": "MIT",
1107 "dependencies": {
1108 "b4a": "^1.1.1",
1109 "sodium-universal": "^5.0.0"
1110 }
1111 },
1112 "node_modules/sodium-universal": {
1113 "version": "5.0.1",
1114 "resolved": "https://registry.npmjs.org/sodium-universal/-/sodium-universal-5.0.1.tgz",
1115 "integrity": "sha512-rv+aH+tnKB5H0MAc2UadHShLMslpJsc4wjdnHRtiSIEYpOetCgu8MS4ExQRia+GL/MK3uuCyZPeEsi+J3h+Q+Q==",
1116 "license": "MIT",
1117 "dependencies": {
1118 "sodium-native": "^5.0.1"
1119 },
1120 "peerDependencies": {
1121 "sodium-javascript": "~0.8.0"
1122 },
1123 "peerDependenciesMeta": {
1124 "sodium-javascript": {
1125 "optional": true
1126 }
1127 }
1128 },
1129 "node_modules/stackframe": {
1130 "version": "1.3.4",
1131 "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
1132 "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==",
1133 "dev": true,
1134 "license": "MIT"
1135 },
1136 "node_modules/streamx": {
1137 "version": "2.25.0",
1138 "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz",
1139 "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==",
1140 "license": "MIT",
1141 "dependencies": {
1142 "events-universal": "^1.0.0",
1143 "fast-fifo": "^1.3.2",
1144 "text-decoder": "^1.1.0"
1145 }
1146 },
1147 "node_modules/teex": {
1148 "version": "1.0.1",
1149 "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz",
1150 "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==",
1151 "license": "MIT",
1152 "dependencies": {
1153 "streamx": "^2.12.5"
1154 }
1155 },
1156 "node_modules/test-tmp": {
1157 "version": "1.4.0",
1158 "resolved": "https://registry.npmjs.org/test-tmp/-/test-tmp-1.4.0.tgz",
1159 "integrity": "sha512-GVggxGg+jXqP2Wbju50JVLo+9E+nIOPPyWqgr63EbOnNItIKu1cEbJpTWAJeflnyGqXOtcMI7ijHRp88GUkfDA==",
1160 "dev": true,
1161 "license": "MIT",
1162 "dependencies": {
1163 "bare-fs": "^4.0.1",
1164 "bare-os": "^3.3.0",
1165 "bare-path": "^3.0.0"
1166 }
1167 },
1168 "node_modules/text-decoder": {
1169 "version": "1.2.7",
1170 "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz",
1171 "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==",
1172 "license": "Apache-2.0",
1173 "dependencies": {
1174 "b4a": "^1.6.4"
1175 }
1176 },
1177 "node_modules/time-ordered-set": {
1178 "version": "2.0.1",
1179 "resolved": "https://registry.npmjs.org/time-ordered-set/-/time-ordered-set-2.0.1.tgz",
1180 "integrity": "sha512-VJEKmgSN2UiOLB8BpN8Sh2b9LGMHTP5OPrQRpnKjvOheOyzk0mufbjzjKTIG2gO4A+Y+vDJ+0TcLbpUmMLsg8A==",
1181 "license": "MIT"
1182 },
1183 "node_modules/timeout-refresh": {
1184 "version": "2.0.1",
1185 "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-2.0.1.tgz",
1186 "integrity": "sha512-SVqEcMZBsZF9mA78rjzCrYrUs37LMJk3ShZ851ygZYW1cMeIjs9mL57KO6Iv5mmjSQnOe/29/VAfGXo+oRCiVw==",
1187 "license": "MIT"
1188 },
1189 "node_modules/tmatch": {
1190 "version": "5.0.0",
1191 "resolved": "https://registry.npmjs.org/tmatch/-/tmatch-5.0.0.tgz",
1192 "integrity": "sha512-Ib9OtBkpHn07tXP04SlN1SYRxFgTk6wSM2EBmjjxug4u5RXPRVLkdFJSS1PmrQidaSB8Lru9nRtViQBsbxzE5Q==",
1193 "dev": true,
1194 "license": "ISC",
1195 "engines": {
1196 "node": ">=8"
1197 }
1198 },
1199 "node_modules/udx-native": {
1200 "version": "1.19.2",
1201 "resolved": "https://registry.npmjs.org/udx-native/-/udx-native-1.19.2.tgz",
1202 "integrity": "sha512-RNYh+UhfryCsF5hE2ZOuIqcZ+qdipXK3UsarwxWJwsUQZFE3ybwz0mPjwb5ev1PMBcjFahWiepS/q0wwL51c2g==",
1203 "license": "Apache-2.0",
1204 "dependencies": {
1205 "b4a": "^1.5.0",
1206 "bare-events": "^2.2.0",
1207 "require-addon": "^1.1.0",
1208 "streamx": "^2.22.0"
1209 },
1210 "engines": {
1211 "bare": ">=1.17.4"
1212 }
1213 },
1214 "node_modules/unordered-set": {
1215 "version": "2.0.1",
1216 "resolved": "https://registry.npmjs.org/unordered-set/-/unordered-set-2.0.1.tgz",
1217 "integrity": "sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==",
1218 "license": "MIT"
1219 },
1220 "node_modules/unslab": {
1221 "version": "1.3.0",
1222 "resolved": "https://registry.npmjs.org/unslab/-/unslab-1.3.0.tgz",
1223 "integrity": "sha512-YATkfKAFj47kTzmiQrWXMyRvaVrHsW6MEALa4bm+FhiA2YG4oira+Z3DXN6LrYOYn2Y8eO94Lwl9DOHjs1FpoQ==",
1224 "license": "Apache-2.0",
1225 "dependencies": {
1226 "b4a": "^1.6.6"
1227 }
1228 },
1229 "node_modules/v8-to-istanbul": {
1230 "version": "9.3.0",
1231 "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
1232 "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
1233 "dev": true,
1234 "license": "ISC",
1235 "dependencies": {
1236 "@jridgewell/trace-mapping": "^0.3.12",
1237 "@types/istanbul-lib-coverage": "^2.0.1",
1238 "convert-source-map": "^2.0.0"
1239 },
1240 "engines": {
1241 "node": ">=10.12.0"
1242 }
1243 },
1244 "node_modules/which-runtime": {
1245 "version": "1.3.2",
1246 "resolved": "https://registry.npmjs.org/which-runtime/-/which-runtime-1.3.2.tgz",
1247 "integrity": "sha512-5kwCfWml7+b2NO7KrLMhYihjRx0teKkd3yGp1Xk5Vaf2JGdSh+rgVhEALAD9c/59dP+YwJHXoEO7e8QPy7gOkw==",
1248 "license": "Apache-2.0"
1249 },
1250 "node_modules/xache": {
1251 "version": "1.2.1",
1252 "resolved": "https://registry.npmjs.org/xache/-/xache-1.2.1.tgz",
1253 "integrity": "sha512-igRS6jPreJ54ABdzhh4mCDXcz+XMaWO2q1ABRV2yWYuk29jlp8VT7UBdCqNkX7rpYBbXsebVVKkwIuYZjyZNqA==",
1254 "license": "MIT"
1255 },
1256 "node_modules/z32": {
1257 "version": "1.1.0",
1258 "resolved": "https://registry.npmjs.org/z32/-/z32-1.1.0.tgz",
1259 "integrity": "sha512-1WUHy+VS6d0HPNspDxvLssBbeQjXMjSnpv0vH82vRAUfg847NmX3OXozp/hRP5jPhxBbrVzrgvAt+UsGNzRFQQ==",
1260 "license": "MIT",
1261 "dependencies": {
1262 "b4a": "^1.5.3"
1263 }
1264 }
1265 }
1266}
package.json +26 -0
……@@ -0,0 +1,26 @@
1{
2 "name": "hyper-sync",
3 "version": "0.1.0",
4 "description": "Manage and sync bare git repos over Hyperswarm",
5 "main": "index.js",
6 "imports": {
7 "fs": { "bare": "bare-fs", "default": "fs" },
8 "path": { "bare": "bare-path", "default": "path" },
9 "os": { "bare": "bare-os", "default": "os" },
10 "child_process": { "bare": "bare-subprocess", "default": "child_process" }
11 },
12 "scripts": {
13 "test": "brittle test/*.test.js"
14 },
15 "dependencies": {
16 "hypercore-crypto": "^3.0.0",
17 "hyperswarm": "^4.0.0",
18 "protomux": "^3.0.0",
19 "compact-encoding": "^2.0.0",
20 "ready-resource": "^1.0.0",
21 "safety-catch": "^1.0.0"
22 },
23 "devDependencies": {
24 "brittle": "^3.0.0"
25 }
26}
test/basic.test.js +133 -0
……@@ -0,0 +1,133 @@
1const test = require('brittle');
2const path = require('path');
3const fs = require('fs');
4const os = require('os');
5const HyperSync = require('../');
6const { scanRepos, repoInfo, readRefs } = require('../lib/repos');
7const { deriveTopic } = require('../lib/topics');
8
9const REPOS_DIR = path.join(os.homedir(), 'git-repos');
10const tmpdir = os.tmpdir();
11
12// ── Repo Scanner ────────────────────────────────────────────
13
14test('scanRepos finds bare repos', async (t) => {
15 const repos = scanRepos(REPOS_DIR);
16 t.ok(repos.size > 0, 'found ' + repos.size + ' repos');
17 t.ok(repos.has('pear-git'), 'found pear-git');
18});
19
20test('repoInfo returns branches and size', async (t) => {
21 const repoPath = path.join(REPOS_DIR, 'pear-git.git');
22 const info = repoInfo(repoPath, 'pear-git');
23
24 t.ok(info, 'info returned');
25 t.is(info.name, 'pear-git');
26 t.ok(info.branchCount > 0, info.branchCount + ' branches');
27 t.ok(info.packSize > 0, 'pack size: ' + info.packSize);
28 t.ok(info.head, 'has head: ' + (info.head ? info.head.slice(0, 12) : 'none'));
29});
30
31test('readRefs returns branch shas', async (t) => {
32 const refs = readRefs(path.join(REPOS_DIR, 'pear-git.git'));
33 t.ok(refs.master || refs.main, 'has master or main');
34
35 const sha = refs.master || refs.main;
36 t.is(sha.length, 40, 'sha is 40 chars');
37 t.ok(/^[0-9a-f]{40}$/.test(sha), 'valid hex sha');
38});
39
40test('scanRepos handles missing directory', async (t) => {
41 const repos = scanRepos('/nonexistent/path');
42 t.is(repos.size, 0, 'empty map for missing dir');
43});
44
45// ── Topic Derivation ────────────────────────────────────────
46
47test('deriveTopic is deterministic', async (t) => {
48 const key = Buffer.alloc(32, 0x42);
49 const t1 = deriveTopic(key, 'my-repo');
50 const t2 = deriveTopic(key, 'my-repo');
51 const t3 = deriveTopic(key, 'other-repo');
52
53 t.alike(t1, t2, 'same key+name = same topic');
54 t.unlike(t1, t3, 'different name = different topic');
55});
56
57test('deriveTopic accepts hex string', async (t) => {
58 const key = Buffer.alloc(32, 0x42);
59 const hex = key.toString('hex');
60 const t1 = deriveTopic(key, 'repo');
61 const t2 = deriveTopic(hex, 'repo');
62
63 t.alike(t1, t2, 'buffer and hex produce same topic');
64});
65
66// ── HyperSync Lifecycle ─────────────────────────────────────
67
68test('HyperSync scan and status', async (t) => {
69 const sync = new HyperSync({ repos: REPOS_DIR });
70 await sync.ready();
71
72 t.ok(sync.repos.size > 0, 'scanned ' + sync.repos.size + ' repos');
73 t.ok(sync.serverKey, 'has server key');
74
75 const status = sync.status();
76 t.is(status.repoCount, sync.repos.size);
77 t.is(status.serving, 0, 'not serving yet');
78 t.is(status.remotes, 0, 'no remotes');
79 t.ok(status.serverKey, 'status has server key');
80
81 await sync.close();
82});
83
84test('HyperSync info for specific repo', async (t) => {
85 const sync = new HyperSync({ repos: REPOS_DIR });
86 await sync.ready();
87
88 const info = sync.info('pear-git');
89 t.ok(info, 'got info');
90 t.is(info.name, 'pear-git');
91 t.ok(info.refs, 'has refs');
92 t.is(info.serving, false, 'not serving');
93
94 const missing = sync.info('nonexistent');
95 t.is(missing, null, 'null for missing repo');
96
97 await sync.close();
98});
99
100test('HyperSync remotes', async (t) => {
101 const sync = new HyperSync({ repos: REPOS_DIR });
102 await sync.ready();
103
104 sync.addRemote('stortron', Buffer.alloc(32, 0x01).toString('hex'));
105 t.is(sync.remotes.size, 1);
106 t.ok(sync.remotes.has('stortron'));
107
108 sync.removeRemote('stortron');
109 t.is(sync.remotes.size, 0);
110
111 await sync.close();
112});
113
114test('HyperSync rescan detects changes', async (t) => {
115 // Create a temp repos directory with one repo
116 const tmpRepos = path.join(tmpdir, 'hyper-sync-test-' + Date.now());
117 fs.mkdirSync(tmpRepos, { recursive: true });
118
119 const sync = new HyperSync({ repos: tmpRepos });
120 await sync.ready();
121 t.is(sync.repos.size, 0, 'empty initially');
122
123 // Create a bare repo
124 const { execSync } = require('child_process');
125 execSync('git init --bare ' + path.join(tmpRepos, 'test.git'), { stdio: 'pipe' });
126
127 await sync.scan();
128 t.is(sync.repos.size, 1, 'found new repo after rescan');
129 t.ok(sync.repos.has('test'), 'found test repo');
130
131 await sync.close();
132 fs.rmSync(tmpRepos, { recursive: true });
133});