chore(repo): initialize WebDrop monorepo

Signed-off-by: JustMe <mr.toing@outlook.com>
This commit is contained in:
justme committed 2026-10-02 00:59:22 +08:00
commit 53768a195d
39 files changed
+9063

No files matched your search

+90
View File
@@ -0,0 +1,90 @@
import { readFileSync } from 'node:fs';
import { fromHex, toBase64Url, toHex, type Bytes } from '../src/bytes.js';
import { ChannelSession, collectFrames, type EncodedFrame, type ItemPlan } from '../src/index.js';
/* eslint-disable @typescript-eslint/no-explicit-any */
export const vectors: any = JSON.parse(readFileSync(new URL('../../../test-vectors/vectors.json', import.meta.url), 'utf8'));
export const h = (s: string): Bytes => fromHex(s);
export { toHex };
/** 向量里的固定输入。 */
export const inputs = {
channelId: h(vectors.inputs.channel_id),
channelIdB64: vectors.inputs.channel_id_b64 as string,
k: h(vectors.inputs.k),
a: h(vectors.inputs.a),
w: h(vectors.inputs.w),
endpointSecret: h(vectors.inputs.endpoint_secret),
itemA: h(vectors.inputs.item_a),
itemB: h(vectors.inputs.item_b),
itemC: h(vectors.inputs.item_c),
};
export const ORIGIN = 'https://app.example.test';
/** 用向量里的 channel_id / K(/A) 打开一个会话,终端密钥也取向量值。 */
export function openVectorSession(opts: { owner?: boolean } = {}): Promise<ChannelSession> {
const parts = [`k=${toBase64Url(inputs.k)}`];
if (opts.owner) parts.push(`a=${toBase64Url(inputs.a)}`);
return ChannelSession.open(`${ORIGIN}/c/${inputs.channelIdB64}#${parts.join('&')}`, { endpointSecret: inputs.endpointSecret });
}
export async function framesOf(plan: ItemPlan): Promise<EncodedFrame[]> {
return collectFrames(plan);
}
/** 随机但可复现的字节(线性同余),测试里需要「看起来随机」的内容时用。 */
export function pseudoRandom(length: number, seed = 1): Bytes {
const out = new Uint8Array(length);
let x = seed >>> 0 || 1;
for (let i = 0; i < length; i++) {
x = (Math.imul(x, 1664525) + 1013904223) >>> 0;
out[i] = x >>> 24;
}
return out;
}
/** 把字节流在随机位置切成小块,模拟网络分片。 */
export function* splitAt(bytes: Uint8Array, seed = 7): Generator<Uint8Array> {
let x = seed >>> 0 || 1;
let offset = 0;
while (offset < bytes.length) {
x = (Math.imul(x, 1664525) + 1013904223) >>> 0;
const size = 1 + (x >>> 8) % 4096;
yield bytes.subarray(offset, offset + size);
offset += size;
}
}
export async function* asyncChunks(chunks: Iterable<Uint8Array>): AsyncGenerator<Uint8Array> {
for (const c of chunks) yield c;
}
export async function readAll(stream: ReadableStream<Uint8Array>): Promise<Bytes> {
const parts: Uint8Array[] = [];
const reader = stream.getReader();
for (;;) {
const { done, value } = await reader.read();
if (done) break;
parts.push(value);
}
const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
let o = 0;
for (const p of parts) {
out.set(p, o);
o += p.length;
}
return out;
}
export function concatAll(parts: Uint8Array[]): Bytes {
const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
let o = 0;
for (const p of parts) {
out.set(p, o);
o += p.length;
}
return out;
}