Skip to content

Commit 7b2ccf6

Browse files
committed
refactor: restructure file tree & add .npmignore
1 parent 848653e commit 7b2ccf6

File tree

23 files changed

+396
-113
lines changed

23 files changed

+396
-113
lines changed

README.md

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,19 @@ Example (Node 18+):
9393
import { LoroWebsocketClient } from "loro-websocket/client";
9494
import { EloLoroAdaptor } from "loro-adaptors";
9595
import { WebSocket } from "ws";
96-
(globalThis as any).WebSocket = WebSocket as unknown as typeof globalThis.WebSocket;
96+
(globalThis as any).WebSocket =
97+
WebSocket as unknown as typeof globalThis.WebSocket;
9798

9899
const key = new Uint8Array([
99-
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
100-
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
100+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
101+
22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
101102
]);
102103

103104
const client = new LoroWebsocketClient({ url: "ws://localhost:8787" });
104105
await client.waitConnected();
105-
const adaptor = new EloLoroAdaptor({ getPrivateKey: async () => ({ keyId: "k1", key }) });
106+
const adaptor = new EloLoroAdaptor({
107+
getPrivateKey: async () => ({ keyId: "k1", key }),
108+
});
106109
const room = await client.join({ roomId: "elo-room", crdtAdaptor: adaptor });
107110

108111
// Edit the encrypted doc
@@ -114,6 +117,7 @@ await room.destroy();
114117
```
115118

116119
Notes:
120+
117121
- Use a unique, non‑repeating 12‑byte IV per encryption for security (the adaptor accepts an optional `ivFactory()` for testing); the examples may fix IVs for determinism in tests only.
118122
- Keys and key agreement are application‑provided and out of scope.
119123

@@ -128,14 +132,16 @@ pnpm run test:cross-lang
128132
```
129133

130134
This will:
135+
131136
- Run the Rust cross‑lang e2e test (`rust/loro-websocket-server/tests/elo_cross_lang.rs`) with logs.
132137
- Spawn thin TS test-wrappers via `pnpm exec tsx`:
133-
- `packages/loro-websocket/src/test-wrappers/start-simple-server.ts`
134-
- `packages/loro-websocket/src/test-wrappers/send-elo-normative.ts`
135-
- `packages/loro-websocket/src/test-wrappers/recv-elo-doc.ts`
138+
- `packages/loro-websocket/test-wrappers/start-simple-server.ts`
139+
- `packages/loro-websocket/test-wrappers/send-elo-normative.ts`
140+
- `packages/loro-websocket/test-wrappers/recv-elo-doc.ts`
136141
- Use the Rust example `rust/loro-websocket-client/examples/elo_index_client.rs` which encrypts/decrypts real `%ELO` containers.
137142

138143
Requirements:
144+
139145
- Node 18+, pnpm (or npx fallback), Rust toolchain.
140146
- For CI stability, you can run with a single test thread:
141147
`cargo test -p loro-websocket-server --test elo_cross_lang -- --ignored --nocapture --test-threads=1`.

packages/loro-adaptors/.npmignore

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Ignore development artifacts and configs. Keep built output (and TS sources if desired) via package.json "files".
2+
# TODO: REVIEW: This package currently whitelists "src/**/*" in package.json.
3+
# NPM's "files" allowlist overrides .npmignore exclusions; thus test files under src will still be published.
4+
# If you want to exclude tests from the published tarball, update package.json "files" to omit tests (e.g. only "dist").
5+
6+
# VCS / OS
7+
.git
8+
.gitignore
9+
.gitattributes
10+
.DS_Store
11+
.idea/
12+
.vscode/
13+
14+
# Package manager locks
15+
pnpm-lock.yaml
16+
yarn.lock
17+
package-lock.json
18+
19+
# Node
20+
node_modules/
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*
24+
25+
# Tests (not shipped)
26+
__tests__/
27+
test/
28+
tests/
29+
*.test.*
30+
*.spec.*
31+
32+
# Coverage / reports
33+
coverage/
34+
.nyc_output/
35+
36+
# Build/tooling configs
37+
tsconfig.json
38+
tsconfig.*.json
39+
tsdown.config.ts
40+
vitest.config.ts
41+
jest.config.*
42+
rollup.config.*
43+
vite.config.*
44+
babel.config.*
45+
postcss.config.*
46+
tailwind.config.*
47+
48+
# Local scripts and examples
49+
scripts/
50+
examples/
51+
demo/
52+
53+
# Project docs not needed in tarball
54+
AGENTS.md
55+
PLAN.md

packages/loro-adaptors/src/adaptors.test.ts renamed to packages/loro-adaptors/tests/adaptors.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
LoroAdaptor,
55
LoroEphemeralAdaptor,
66
createLoroAdaptor,
7-
} from "./adaptors";
7+
} from "../src/adaptors";
88
import { CrdtType, JoinResponseOk, MessageType } from "loro-protocol";
99

1010
describe("LoroAdaptor", () => {

packages/loro-adaptors/src/elo-adaptor.test.ts renamed to packages/loro-adaptors/tests/elo-adaptor.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { describe, it, expect, vi, beforeEach } from "vitest";
22
import { LoroDoc } from "loro-crdt";
3-
import { EloLoroAdaptor } from "./adaptors";
3+
import { EloLoroAdaptor } from "../src/adaptors";
44
import { CrdtType, MessageType } from "loro-protocol";
55
import { parseEloRecordHeader, decodeEloContainer } from "loro-protocol";
66
import { encryptDeltaSpan, encodeEloContainer } from "loro-protocol";

packages/loro-protocol/.npmignore

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Ignore development artifacts and configs. Publish only built output via package.json "files".
2+
3+
# VCS / OS
4+
.git
5+
.gitignore
6+
.gitattributes
7+
.DS_Store
8+
.idea/
9+
.vscode/
10+
11+
# Package manager locks
12+
pnpm-lock.yaml
13+
yarn.lock
14+
package-lock.json
15+
16+
# Node
17+
node_modules/
18+
npm-debug.log*
19+
yarn-debug.log*
20+
yarn-error.log*
21+
22+
# Tests (not shipped)
23+
__tests__/
24+
test/
25+
tests/
26+
*.test.*
27+
*.spec.*
28+
29+
# Coverage / reports
30+
coverage/
31+
.nyc_output/
32+
33+
# Build/tooling configs
34+
tsconfig.json
35+
tsconfig.*.json
36+
tsdown.config.ts
37+
vitest.config.ts
38+
jest.config.*
39+
rollup.config.*
40+
vite.config.*
41+
babel.config.*
42+
postcss.config.*
43+
tailwind.config.*
44+
45+
# Local scripts and examples
46+
scripts/
47+
examples/
48+
demo/
49+
50+
# Project docs not needed in tarball
51+
AGENTS.md
52+
PLAN.md

packages/loro-protocol/src/__snapshots__/encoding.snap.test.ts.snap renamed to packages/loro-protocol/tests/__snapshots__/encoding.snap.test.ts.snap

File renamed without changes.

packages/loro-protocol/src/bytes.test.ts renamed to packages/loro-protocol/tests/bytes.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from "vitest";
2-
import { BytesReader, BytesWriter } from "./bytes";
2+
import { BytesReader, BytesWriter } from "../src/bytes";
33

44
describe("BytesWriter/BytesReader", () => {
55
it("round-trips ULEB128 for typical bounds", () => {
Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import {
66
encryptDeltaSpan,
77
encryptSnapshot,
88
parseEloRecordHeader,
9-
} from "./e2ee";
10-
import { bytesToHex, hexToBytes } from "./protocol";
9+
} from "../src/e2ee";
10+
import { bytesToHex, hexToBytes } from "../src/protocol";
1111

1212
describe("%ELO container codec", () => {
1313
it("encodes and decodes container", () => {
@@ -29,7 +29,11 @@ describe("%ELO record header parsing", () => {
2929
const iv = hexToBytes("0x86bcad09d5e7e3d70503a57e");
3030
const plaintext = hexToBytes("0x01026869");
3131
const meta = { peerId, start: 1, end: 3, keyId: "k1", iv };
32-
const { record, headerBytes } = await encryptDeltaSpan(plaintext, meta, key);
32+
const { record, headerBytes } = await encryptDeltaSpan(
33+
plaintext,
34+
meta,
35+
key
36+
);
3337
const parsed = parseEloRecordHeader(record);
3438
expect(parsed.kind).toBe(EloRecordKind.DeltaSpan);
3539
expect(bytesToHex(parsed.headerBytes)).toEqual(bytesToHex(headerBytes));
@@ -78,18 +82,18 @@ describe("%ELO Snapshot header vv sorting", () => {
7882
{ peerId: hexToBytes("0x01ff"), counter: 9 },
7983
{ peerId: hexToBytes("0x01"), counter: 7 },
8084
];
81-
const { record } = await encryptSnapshot(plaintext, { vv: vvUnsorted, keyId: "k1", iv }, key);
85+
const { record } = await encryptSnapshot(
86+
plaintext,
87+
{ vv: vvUnsorted, keyId: "k1", iv },
88+
key
89+
);
8290
const parsed = parseEloRecordHeader(record);
8391
expect(parsed.kind).toBe(EloRecordKind.Snapshot);
8492
const hdr = parsed.header;
8593
if (hdr.kind === EloRecordKind.Snapshot) {
8694
// Expected lexicographic order: 0x01, 0x01ff, 0x02
87-
const order = hdr.vv.map((e) => bytesToHex(e.peerId));
88-
expect(order).toEqual([
89-
"0x01",
90-
"0x01ff",
91-
"0x02",
92-
]);
95+
const order = hdr.vv.map(e => bytesToHex(e.peerId));
96+
expect(order).toEqual(["0x01", "0x01ff", "0x02"]);
9397
}
9498
});
9599
});

packages/loro-protocol/src/encoding.snap.test.ts renamed to packages/loro-protocol/tests/encoding.snap.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, it, expect } from "vitest";
2-
import { encode } from "./encoding";
2+
import { encode } from "../src/encoding";
33
import {
44
CrdtType,
55
MessageType,
@@ -14,7 +14,7 @@ import {
1414
type DocUpdateFragment,
1515
type UpdateError,
1616
type Leave,
17-
} from "./protocol";
17+
} from "../src/protocol";
1818

1919
// TODO: REVIEW ensure binary snapshots stay stable across changes to protocol
2020

@@ -174,4 +174,3 @@ describe("encoding snapshots", () => {
174174
expect(bytesToHex(encode(msg))).toMatchSnapshot();
175175
});
176176
});
177-

packages/loro-protocol/src/encoding.test.ts renamed to packages/loro-protocol/tests/encoding.test.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from "vitest";
2-
import { encode, decode, tryDecode } from "./encoding";
2+
import { encode, decode, tryDecode } from "../src/encoding";
33
import {
44
CrdtType,
55
MessageType,
@@ -13,7 +13,7 @@ import {
1313
type DocUpdateFragment,
1414
type UpdateError,
1515
type Leave,
16-
} from "./protocol";
16+
} from "../src/protocol";
1717

1818
describe("Message Encoding and Decoding", () => {
1919
const roomId = new Uint8Array([1, 2, 3, 4, 5]);
@@ -78,7 +78,8 @@ describe("Message Encoding and Decoding", () => {
7878

7979
expect(decoded.type).toBe(MessageType.JoinResponseOk);
8080
expect(decoded.crdt).toBe(CrdtType.Yjs);
81-
if (decoded.type !== MessageType.JoinResponseOk) throw new Error("bad type");
81+
if (decoded.type !== MessageType.JoinResponseOk)
82+
throw new Error("bad type");
8283
expect(decoded.permission).toBe("read");
8384
expect(Array.from(decoded.version)).toEqual([11, 22, 33]);
8485
expect(decoded.extra).toStrictEqual(new Uint8Array([]));
@@ -98,7 +99,8 @@ describe("Message Encoding and Decoding", () => {
9899
const decoded = decode(encoded);
99100

100101
expect(decoded.type).toBe(MessageType.JoinResponseOk);
101-
if (decoded.type !== MessageType.JoinResponseOk) throw new Error("bad type");
102+
if (decoded.type !== MessageType.JoinResponseOk)
103+
throw new Error("bad type");
102104
expect(decoded.permission).toBe("write");
103105
expect(Array.from(decoded.version)).toEqual([44, 55]);
104106
expect(decoded.extra).toBeDefined();
@@ -241,7 +243,8 @@ describe("Message Encoding and Decoding", () => {
241243
const decoded = decode(encoded);
242244

243245
expect(decoded.type).toBe(MessageType.DocUpdateFragmentHeader);
244-
if (decoded.type !== MessageType.DocUpdateFragmentHeader) throw new Error("bad type");
246+
if (decoded.type !== MessageType.DocUpdateFragmentHeader)
247+
throw new Error("bad type");
245248
expect(decoded.batchId).toBe("0xff11223344556677");
246249
expect(decoded.fragmentCount).toBe(10);
247250
expect(decoded.totalSizeBytes).toBe(1024000);
@@ -261,7 +264,8 @@ describe("Message Encoding and Decoding", () => {
261264
const decoded = decode(encoded);
262265

263266
expect(decoded.type).toBe(MessageType.DocUpdateFragmentHeader);
264-
if (decoded.type !== MessageType.DocUpdateFragmentHeader) throw new Error("bad type");
267+
if (decoded.type !== MessageType.DocUpdateFragmentHeader)
268+
throw new Error("bad type");
265269
expect(decoded.batchId).toBe("0x0000000000000000");
266270
expect(decoded.fragmentCount).toBe(1);
267271
expect(decoded.totalSizeBytes).toBe(100);
@@ -288,7 +292,8 @@ describe("Message Encoding and Decoding", () => {
288292
const decoded = decode(encoded);
289293

290294
expect(decoded.type).toBe(MessageType.DocUpdateFragment);
291-
if (decoded.type !== MessageType.DocUpdateFragment) throw new Error("bad type");
295+
if (decoded.type !== MessageType.DocUpdateFragment)
296+
throw new Error("bad type");
292297
expect(decoded.batchId).toBe("0x0000000000000000");
293298
expect(decoded.index).toBe(3);
294299
expect(Array.from(decoded.fragment)).toEqual(Array.from(fragmentData));
@@ -376,7 +381,8 @@ describe("Message Encoding and Decoding", () => {
376381
const encoded = encode(message);
377382
const decoded = decode(encoded);
378383
expect(decoded.type).toBe(MessageType.UpdateError);
379-
if (decoded.type !== MessageType.UpdateError) throw new Error("bad type");
384+
if (decoded.type !== MessageType.UpdateError)
385+
throw new Error("bad type");
380386
expect(decoded.code).toBe(code);
381387
expect(decoded.message).toBe(`Error with code ${code}`);
382388
}

0 commit comments

Comments
 (0)