@fireproof/core 0.20.0-dev-preview-41 → 0.20.0-dev-preview-51

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.
@@ -1,12 +1,11 @@
1
- import { bs, ensureSuperThis, PARAM, rt } from "@fireproof/core";
1
+ import { bs, ensureSuperThis, PARAM, rt, StoreType, storeType2DataMetaWal } from "@fireproof/core";
2
2
  import { BuildURI, runtimeFn, toCryptoRuntime, URI } from "@adviser/cement";
3
3
  import { base58btc } from "multiformats/bases/base58";
4
- import { sha256 as hasher } from "multiformats/hashes/sha2";
5
- import * as dagCodec from "@ipld/dag-cbor";
4
+ // import { sha256 as hasher } from "multiformats/hashes/sha2";
5
+ // import * as dagCodec from "@ipld/dag-cbor";
6
+ import * as cborg from "cborg";
6
7
  import type { KeyBagProviderIndexedDB } from "@fireproof/core/indexeddb";
7
8
  import { mockLoader, MockSuperThis, mockSuperThis } from "../helpers.js";
8
- import { KeyWithFingerPrint } from "../../src/blockstore/types.js";
9
- import { toKeyWithFingerPrint } from "../../src/runtime/key-bag.js";
10
9
 
11
10
  describe("KeyBag", () => {
12
11
  let url: URI;
@@ -113,10 +112,10 @@ describe("KeyBag", () => {
113
112
  return JSON.parse(sthis.txt.decode(data)) as rt.kb.KeysItem;
114
113
  });
115
114
  }
116
- expect((await toKeyWithFingerPrint(kb, Object.values(diskBag.keys)[0].key)).Ok().fingerPrint).toEqual(
115
+ expect((await rt.toKeyWithFingerPrint(kb, Object.values(diskBag.keys)[0].key)).Ok().fingerPrint).toEqual(
117
116
  (await res.Ok().get())?.fingerPrint,
118
117
  );
119
- expect((await toKeyWithFingerPrint(kb, Object.values(diskBag2.keys)[0].key)).Ok().fingerPrint).toEqual(
118
+ expect((await rt.toKeyWithFingerPrint(kb, Object.values(diskBag2.keys)[0].key)).Ok().fingerPrint).toEqual(
120
119
  (await created.Ok().get())?.fingerPrint,
121
120
  );
122
121
  const algo = {
@@ -129,7 +128,7 @@ describe("KeyBag", () => {
129
128
  expect(await kb.rt.crypto.encrypt(algo, (await res.Ok().get())!.key, data))
130
129
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
131
130
  .toEqual(await kb.rt.crypto.encrypt(algo, (await created.Ok().get())!.key, data));
132
- const kf = (await created.Ok().get()) as KeyWithFingerPrint;
131
+ const kf = (await created.Ok().get()) as bs.KeyWithFingerPrint;
133
132
  expect(await kb.rt.crypto.encrypt(algo, await kb.subtleKey(Object.values(diskBag.keys)[0].key), data)).toEqual(
134
133
  await kb.rt.crypto.encrypt(algo, kf.key, data),
135
134
  );
@@ -150,11 +149,11 @@ describe("KeyBag", () => {
150
149
  }
151
150
  expect(Object.keys((await kb.getNamedKey(name).then((i) => i.Ok().asKeysItem())).keys).length).toBe(1);
152
151
 
153
- const myKey = (await rMyKey.Ok().get()) as KeyWithFingerPrint;
152
+ const myKey = (await rMyKey.Ok().get()) as bs.KeyWithFingerPrint;
154
153
  expect(myKey.fingerPrint).toMatch(/^z/);
155
154
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
156
155
  await rMyKey.Ok().upsert((await myKey.extract())!.key);
157
- const myKey1 = (await rMyKey.Ok().get()) as KeyWithFingerPrint;
156
+ const myKey1 = (await rMyKey.Ok().get()) as bs.KeyWithFingerPrint;
158
157
  expect(myKey.fingerPrint).toEqual(myKey1.fingerPrint);
159
158
 
160
159
  expect(Object.keys((await kb.getNamedKey(name).then((i) => i.Ok().asKeysItem())).keys).length).toBe(1);
@@ -164,13 +163,13 @@ describe("KeyBag", () => {
164
163
  const res1 = await rMyKey1.Ok().upsert(kb.rt.crypto.randomBytes(kb.rt.keyLength));
165
164
  expect(res1.isOk()).toBeTruthy();
166
165
 
167
- const myKey2 = (await rMyKey1.Ok().get()) as KeyWithFingerPrint;
166
+ const myKey2 = (await rMyKey1.Ok().get()) as bs.KeyWithFingerPrint;
168
167
  expect(myKey.fingerPrint).toEqual(myKey2.fingerPrint);
169
168
  expect(Object.keys((await kb.getNamedKey(name).then((i) => i.Ok().asKeysItem())).keys).length).toBe(2);
170
169
 
171
170
  const res = await rMyKey1.Ok().upsert(kb.rt.crypto.randomBytes(kb.rt.keyLength), true);
172
171
  expect(res.isOk()).toBeTruthy();
173
- const myKey3 = (await rMyKey.Ok().get()) as KeyWithFingerPrint;
172
+ const myKey3 = (await rMyKey.Ok().get()) as bs.KeyWithFingerPrint;
174
173
  expect(Object.keys((await kb.getNamedKey(name).then((i) => i.Ok().asKeysItem())).keys).length).toBe(3);
175
174
 
176
175
  expect(myKey.fingerPrint).not.toEqual(myKey3.fingerPrint);
@@ -185,7 +184,7 @@ describe("KeyBag", () => {
185
184
  });
186
185
  const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
187
186
  const name = "default-key" + Math.random();
188
- const fpr = (await toKeyWithFingerPrint(kb, key)).Ok().fingerPrint;
187
+ const fpr = (await rt.toKeyWithFingerPrint(kb, key)).Ok().fingerPrint;
189
188
  const rMyKey = await kb.getNamedKey(name, false, key);
190
189
  expect(rMyKey.isOk()).toBeTruthy();
191
190
  const myKey = rMyKey.Ok();
@@ -199,7 +198,7 @@ describe("KeyBag", () => {
199
198
  const keys = [{ key, fpr }];
200
199
  for (let i = 0; i < 10; ++i) {
201
200
  const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
202
- const fpr = (await toKeyWithFingerPrint(kb, key)).Ok().fingerPrint;
201
+ const fpr = (await rt.toKeyWithFingerPrint(kb, key)).Ok().fingerPrint;
203
202
  keys.push({ key, fpr });
204
203
  const rUpsert = await myKey.upsert(key, true);
205
204
  expect(rUpsert.Ok().modified).toBeTruthy();
@@ -278,7 +277,9 @@ describe("KeyedCryptoStore", () => {
278
277
  const kc = await store.keyedCrypto();
279
278
  expect(kc.constructor.name).toBe("cryptoAction");
280
279
  // expect(kc.isEncrypting).toBe(true);
281
- expect(store.url().getParam(PARAM.STORE_KEY)).toBe(`@test:${store.url().getParam(PARAM.STORE)}@`);
280
+ expect(store.url().getParam(PARAM.STORE_KEY)).toBe(
281
+ `@test-${storeType2DataMetaWal(store.url().getParam(PARAM.STORE) as StoreType)}@`,
282
+ );
282
283
  }
283
284
  });
284
285
 
@@ -297,7 +298,7 @@ describe("KeyedCryptoStore", () => {
297
298
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
298
299
  const blk = await kc._encrypt({ bytes: testData, key: (await kc.key.get())!.key, iv });
299
300
  expect(blk).not.toEqual(testData);
300
- const fpkey = (await genKey.Ok().get()) as KeyWithFingerPrint;
301
+ const fpkey = (await genKey.Ok().get()) as bs.KeyWithFingerPrint;
301
302
  expect(fpkey.fingerPrint).toEqual(fpkey.fingerPrint);
302
303
  const dec = new Uint8Array(await kc.crypto.decrypt(kc.algo(iv), fpkey.key, blk));
303
304
  expect(dec).toEqual(testData);
@@ -316,7 +317,7 @@ describe("KeyedCryptoStore", () => {
316
317
  expect(kc.constructor.name).toBe("cryptoAction");
317
318
  const testData = kb.rt.crypto.randomBytes(1024);
318
319
  const iv = kb.rt.crypto.randomBytes(12);
319
- const ks = (await kc.key.get()) as KeyWithFingerPrint;
320
+ const ks = (await kc.key.get()) as bs.KeyWithFingerPrint;
320
321
  const blk = await kc._encrypt({ bytes: testData, key: ks.key, iv });
321
322
  expect(blk).not.toEqual(testData);
322
323
  const dec = await kc._decrypt({ bytes: blk, key: ks.key, iv });
@@ -348,12 +349,12 @@ describe("KeyedCrypto", () => {
348
349
  const iv = kb.rt.crypto.randomBytes(12);
349
350
  const codec = kycr.codec(iv, { noIVVerify: true });
350
351
  const blk = (await codec.encode(testData)) as Uint8Array;
351
- const myDec = await rt.mf.block.decode<bs.IvKeyIdData, number, number>({ bytes: blk, hasher, codec: dagCodec });
352
- expect(myDec.value.iv).toEqual(iv);
353
- const kc = (await kycr.key.get()) as KeyWithFingerPrint;
354
- expect(base58btc.encode(myDec.value.keyId)).toEqual(kc.fingerPrint);
352
+ const myDec = cborg.decode(blk) as bs.IvKeyIdData;
353
+ expect(myDec.iv).toEqual(iv);
354
+ const kc = (await kycr.key.get()) as bs.KeyWithFingerPrint;
355
+ expect(base58btc.encode(myDec.keyId)).toEqual(kc.fingerPrint);
355
356
  const dec = await codec.decode(blk);
356
- expect(dec).toEqual(testData);
357
+ expect(dec.data).toEqual(testData);
357
358
  });
358
359
 
359
360
  it("codec implict iv", async () => {
@@ -362,7 +363,7 @@ describe("KeyedCrypto", () => {
362
363
  const blk = await codec.encode(testData);
363
364
  expect(blk.length).toBeGreaterThanOrEqual(12 + testData.length);
364
365
  const dec = await codec.decode(blk);
365
- expect(dec).toEqual(testData);
366
+ expect(dec.data).toEqual(testData);
366
367
  });
367
368
 
368
369
  it("codec implict iv same for multiple clients", async () => {
@@ -154,8 +154,8 @@ describe("basic Loader with two commits", function () {
154
154
 
155
155
  it("should have a car log", function () {
156
156
  expect(loader.carLog.length).toBe(2);
157
- expect(loader.carLog[0].toString()).toBe(carCid.toString());
158
- expect(loader.carLog[1].toString()).toBe(carCid0.toString());
157
+ expect(loader.carLog.asArray()[0].toString()).toBe(carCid.toString());
158
+ expect(loader.carLog.asArray()[1].toString()).toBe(carCid0.toString());
159
159
  });
160
160
 
161
161
  it("should commit", async () => {
@@ -1,7 +1,6 @@
1
1
  import { CID } from "multiformats";
2
2
  import { rt, bs, NotFoundError, PARAM, ensureSuperThis } from "@fireproof/core";
3
3
  import { Result } from "@adviser/cement";
4
- import { createAttachedStores } from "../../src/blockstore/attachable-store.js";
5
4
  import { mockLoader, noopUrl } from "../helpers.js";
6
5
 
7
6
  // function runtime(sthis: SuperThis) {
@@ -17,8 +16,8 @@ import { mockLoader, noopUrl } from "../helpers.js";
17
16
  // };
18
17
  // }
19
18
 
20
- describe("DataStore", function () {
21
- let store: bs.DataStore;
19
+ describe("CarStore", function () {
20
+ let store: bs.CarStore;
22
21
  const sthis = ensureSuperThis();
23
22
  const loader = mockLoader(sthis);
24
23
 
@@ -29,7 +28,7 @@ describe("DataStore", function () {
29
28
 
30
29
  beforeEach(async () => {
31
30
  await sthis.start();
32
- const at = await createAttachedStores(noopUrl("test"), loader);
31
+ const at = await bs.createAttachedStores(noopUrl("test"), loader);
33
32
  store = at.stores.car;
34
33
  await store.start(at.stores);
35
34
  });
@@ -49,8 +48,8 @@ describe("DataStore", function () {
49
48
  });
50
49
  });
51
50
 
52
- describe("DataStore with a saved car", function () {
53
- let store: bs.DataStore;
51
+ describe("CarStore with a saved car", function () {
52
+ let store: bs.CarStore;
54
53
  let car: bs.AnyBlock;
55
54
 
56
55
  const sthis = ensureSuperThis();
@@ -64,7 +63,7 @@ describe("DataStore with a saved car", function () {
64
63
  beforeEach(async () => {
65
64
  await sthis.start();
66
65
 
67
- const at = await createAttachedStores(noopUrl("test2"), loader);
66
+ const at = await bs.createAttachedStores(noopUrl("test2"), loader);
68
67
  store = at.stores.car;
69
68
  await store.start(at.stores);
70
69
  car = {
@@ -105,7 +104,7 @@ describe("MetaStore", function () {
105
104
 
106
105
  beforeEach(async () => {
107
106
  await sthis.start();
108
- const at = await createAttachedStores(noopUrl("test"), loader);
107
+ const at = await bs.createAttachedStores(noopUrl("test"), loader);
109
108
  store = at.stores.meta;
110
109
  await store.start(at.stores);
111
110
  });
@@ -145,7 +144,7 @@ describe("MetaStore with a saved header", function () {
145
144
 
146
145
  beforeEach(async () => {
147
146
  await sthis.start();
148
- const at = await createAttachedStores(noopUrl("test3-meta"), loader);
147
+ const at = await bs.createAttachedStores(noopUrl("test3-meta"), loader);
149
148
  store = at.stores.meta;
150
149
  await store.start(at.stores);
151
150
  cid = CID.parse("bafybeia4luuns6dgymy5kau5rm7r4qzrrzg6cglpzpogussprpy42cmcn4");
@@ -32,9 +32,9 @@ import { Future } from "@adviser/cement";
32
32
 
33
33
  describe("noop Gateway", function () {
34
34
  let db: Ledger;
35
- let carStore: bs.DataStore;
35
+ let carStore: bs.CarStore;
36
36
  let metaStore: bs.MetaStore;
37
- let fileStore: bs.DataStore;
37
+ let fileStore: bs.FileStore;
38
38
  let walStore: bs.WALStore;
39
39
  let carGateway: bs.SerdeGateway;
40
40
  let metaGateway: bs.SerdeGateway;
@@ -90,10 +90,10 @@ describe("noop Gateway", function () {
90
90
 
91
91
  it("should have correct store types in URLs", async () => {
92
92
  // Check that all stores have the correct store type in their URL
93
- expect(carStore.url().toString()).toContain("store=data");
93
+ expect(carStore.url().toString()).toContain("store=car");
94
94
  expect(carStore.url().toString()).toContain("suffix=.car");
95
95
  expect(metaStore.url().toString()).toContain("store=meta");
96
- expect(fileStore.url().toString()).toContain("store=data");
96
+ expect(fileStore.url().toString()).toContain("store=file");
97
97
  expect(walStore.url().toString()).toContain("store=wal");
98
98
  });
99
99
 
@@ -1,6 +1,207 @@
1
- import { Attachable, Database, fireproof, GatewayUrlsParam } from "@fireproof/core";
1
+ import { URI } from "@adviser/cement";
2
+ import { stripper } from "@adviser/cement/utils";
3
+ import { Attachable, Database, ensureSuperThis, fireproof, GatewayUrlsParam, PARAM, rt, Attached, bs } from "@fireproof/core";
4
+ import { CarReader } from "@ipld/car/reader";
5
+ import * as dagCbor from "@ipld/dag-cbor";
6
+ import { sleep } from "../helpers.js";
7
+ import { mockLoader } from "../helpers.js";
8
+
9
+ describe("meta check", () => {
10
+ const sthis = ensureSuperThis();
11
+ it("empty Database", async () => {
12
+ const name = `remote-db-${sthis.nextId().str}`;
13
+ const db = fireproof(name, {
14
+ storeUrls: {
15
+ base: `memory://${name}`,
16
+ },
17
+ });
18
+ await db.ready();
19
+ const gws = db.ledger.crdt.blockstore.loader.attachedStores.local();
20
+ await db.close();
21
+ expect(
22
+ Array.from(((gws.active.car.realGateway as rt.gw.DefSerdeGateway).gw as rt.gw.memory.MemoryGateway).memorys.entries()).filter(
23
+ ([k]) => k.startsWith(`memory://${name}`),
24
+ ),
25
+ ).toEqual([]);
26
+ });
27
+
28
+ it("one record Database", async () => {
29
+ const name = `remote-db-${sthis.nextId().str}`;
30
+ const db = fireproof(name, {
31
+ storeUrls: {
32
+ base: `memory://${name}`,
33
+ },
34
+ });
35
+ await db.put({ _id: `id-${0}`, value: `value-${0}` });
36
+ await db.close();
37
+
38
+ const db1 = fireproof(name, {
39
+ storeUrls: {
40
+ base: `memory://${name}`,
41
+ },
42
+ });
43
+ await db1.close();
44
+ });
45
+
46
+ it("multiple record Database", async () => {
47
+ const name = `remote-db-${sthis.nextId().str}`;
48
+ const base = `memory://${name}?storekey=insecure`;
49
+ const db = fireproof(name, {
50
+ storeUrls: {
51
+ base,
52
+ },
53
+ });
54
+ await db.ready();
55
+ await db.put({ _id: `id-${0}`, value: `value-${0}` });
56
+ const gws = db.ledger.crdt.blockstore.loader.attachedStores.local();
57
+ expect(db.ledger.crdt.blockstore.loader.carLog.asArray().map((i) => i.map((i) => i.toString()))).toEqual([
58
+ ["baembeieldbalgnyxqp7rmj4cbrot75gweavqy3aw22km43zsfufrihfn7e"],
59
+ ["baembeig2is4vdgz4gyiadfh5uutxxeiuqtacnesnytrnilpwcu7q5m5tmu"],
60
+ ]);
61
+ await db.close();
62
+ expect(
63
+ Array.from(((gws.active.car.realGateway as rt.gw.DefSerdeGateway).gw as rt.gw.memory.MemoryGateway).memorys.entries())
64
+ .filter(([k]) => k.startsWith(`memory://${name}`))
65
+ .map(([k]) =>
66
+ stripper(
67
+ ["name", "storekey", "version"],
68
+ Array.from(URI.from(k).getParams).reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {}),
69
+ ),
70
+ ),
71
+ ).toEqual([
72
+ {
73
+ key: "baembeig2is4vdgz4gyiadfh5uutxxeiuqtacnesnytrnilpwcu7q5m5tmu",
74
+ store: "car",
75
+ suffix: ".car",
76
+ },
77
+ {
78
+ key: "main",
79
+ store: "wal",
80
+ },
81
+ {
82
+ key: "main",
83
+ store: "meta",
84
+ },
85
+ {
86
+ key: "baembeieldbalgnyxqp7rmj4cbrot75gweavqy3aw22km43zsfufrihfn7e",
87
+ store: "car",
88
+ suffix: ".car",
89
+ },
90
+ ]);
91
+
92
+ const db1 = fireproof(name, {
93
+ storeUrls: {
94
+ base,
95
+ },
96
+ });
97
+ expect(db1.ledger).not.equal(db.ledger);
98
+ await db1.ready();
99
+ expect(db1.ledger.crdt.blockstore.loader.carLog.asArray().map((i) => i.map((i) => i.toString()))).toEqual([
100
+ ["baembeieldbalgnyxqp7rmj4cbrot75gweavqy3aw22km43zsfufrihfn7e"],
101
+ ["baembeig2is4vdgz4gyiadfh5uutxxeiuqtacnesnytrnilpwcu7q5m5tmu"],
102
+ ]);
103
+
104
+ const gensis = await db1.get(PARAM.GENESIS_CID);
105
+ expect(gensis).toEqual({ _id: PARAM.GENESIS_CID });
106
+
107
+ const val = await db1.allDocs();
108
+ expect(val.rows).toEqual([
109
+ {
110
+ key: "id-0",
111
+ value: {
112
+ _id: "id-0",
113
+ value: "value-0",
114
+ },
115
+ },
116
+ ]);
117
+ const car = Array.from(
118
+ ((gws.active.car.realGateway as rt.gw.DefSerdeGateway).gw as rt.gw.memory.MemoryGateway).memorys.entries(),
119
+ )
120
+ .filter(([k]) => k.startsWith(`memory://${name}`))
121
+ .map(([k, v]) => [URI.from(k).getParam(PARAM.KEY), v])
122
+ .find(([k]) => k === "baembeig2is4vdgz4gyiadfh5uutxxeiuqtacnesnytrnilpwcu7q5m5tmu") as [string, Uint8Array];
123
+ const rawReader = await CarReader.fromBytes(car[1]);
124
+ const blocks = [];
125
+ for await (const block of rawReader.blocks()) {
126
+ blocks.push(block);
127
+ }
128
+ expect(dagCbor.decode(blocks[1].bytes)).toEqual({
129
+ doc: {
130
+ _id: "baembeiarootfireproofgenesisblockaaaafireproofgenesisblocka",
131
+ },
132
+ });
133
+
134
+ expect(blocks.map((i) => i.cid.toString())).toEqual([
135
+ "bafyreibxibqhi6wh5klrje7ne4htffeqyyqfd6y7x2no6wnhid4nixizau",
136
+ "bafyreidnvv4mwvweup5w52ddre2sl4syhvczm6ejqsmuekajowdl2cf2q4",
137
+ "bafyreihh6nbfbhgkf5lz7hhsscjgiquw426rxzr3fprbgonekzmyvirrhe",
138
+ "bafyreiejg3twlaxr7gfvvhtxrhvwaydytdv4guidmtvaz5dskm6gp73ryi",
139
+ "bafyreiblui55o25dopc5faol3umsnuohb5carto7tot4kicnkfc37he4h4",
140
+ ]);
141
+ });
142
+ });
143
+
144
+ describe("activate store", () => {
145
+ // activate(store: DataAndMetaStore | CoerceURI): ActiveStore {
146
+ // if (isCoerceURI(store)) {
147
+ // throw this.loadable.sthis.logger.Error().Msg("store must be an object").AsError();
148
+ // }
149
+ // return new ActiveStoreImpl(store as DataAndMetaStore, this);
150
+ // }
151
+
152
+ const sthis = ensureSuperThis();
153
+ let attach: bs.AttachedStores;
154
+ let firstAttached: Attached;
155
+ let secondAttached: Attached;
156
+ beforeEach(async () => {
157
+ attach = new bs.AttachedRemotesImpl(mockLoader(sthis));
158
+ firstAttached = await attach.attach({
159
+ name: "first",
160
+ prepare: async () => ({
161
+ car: { url: "memory://first?store=car" },
162
+ meta: { url: "memory://first?store=meta" },
163
+ file: { url: "memory://first" },
164
+ wal: { url: "memory://first?store=wal" },
165
+ }),
166
+ });
167
+
168
+ secondAttached = await attach.attach({
169
+ name: "second",
170
+ prepare: async () => ({
171
+ car: { url: "memory://second?store=car" },
172
+ meta: { url: "memory://second?store=meta" },
173
+ file: { url: "memory://second?store=file" },
174
+ }),
175
+ });
176
+ });
177
+
178
+ it("activate by store", async () => {
179
+ expect(attach.activate(secondAttached.stores).active.car.url().toString()).toBe(
180
+ "memory://second?name=second&store=car&storekey=%40second-data%40&suffix=.car&version=v0.19-memory",
181
+ );
182
+ expect(attach.activate(firstAttached.stores).local().active.car.url().toString()).toBe(
183
+ "memory://first?name=first&store=car&storekey=%40first-data%40&suffix=.car&version=v0.19-memory",
184
+ );
185
+ expect(attach.activate(firstAttached.stores).active.meta.url().toString()).toBe(
186
+ "memory://first?name=first&store=meta&storekey=%40first-meta%40&version=v0.19-memory",
187
+ );
188
+ });
189
+
190
+ it("activate by store", async () => {
191
+ expect(attach.activate("memory://second").active.car.url().toString()).toBe(
192
+ "memory://second?name=second&store=car&storekey=%40second-data%40&suffix=.car&version=v0.19-memory",
193
+ );
194
+ expect(attach.activate("memory://second").remotes()[0].active.car.url().toString()).toEqual(
195
+ "memory://second?name=second&store=car&storekey=%40second-data%40&suffix=.car&version=v0.19-memory",
196
+ );
197
+ expect(attach.activate("memory://first?store=meta").active.car.url().toString()).toBe(
198
+ "memory://first?name=first&store=car&storekey=%40first-data%40&suffix=.car&version=v0.19-memory",
199
+ );
200
+ });
201
+ });
2
202
 
3
203
  describe("join function", () => {
204
+ const sthis = ensureSuperThis();
4
205
  // export const connect: ConnectFunction = (
5
206
  // db: Database,
6
207
  // remoteDbName = "",
@@ -29,9 +230,9 @@ describe("join function", () => {
29
230
  }
30
231
  prepare(): Promise<GatewayUrlsParam> {
31
232
  return Promise.resolve({
32
- car: { url: "memory://${this.name}" },
33
- meta: { url: "memory://${this.name}" },
34
- file: { url: "memory://${this.name}" },
233
+ car: { url: `memory://car/${this.name}` },
234
+ meta: { url: `memory://meta/${this.name}` },
235
+ file: { url: `memory://file/${this.name}` },
35
236
  });
36
237
  }
37
238
  }
@@ -40,43 +241,116 @@ describe("join function", () => {
40
241
  }
41
242
 
42
243
  let db: Database;
244
+ let joinableDBs: string[] = [];
43
245
  beforeAll(async () => {
44
- const set = Math.random().toString(16);
45
- await Promise.all(
46
- Array.from({ length: 10 }).map(async (_, i) => {
47
- const db = fireproof(`remote-db-${i}-${set}`, {
246
+ const set = sthis.nextId().str;
247
+ joinableDBs = await Promise.all(
248
+ new Array(10).fill(1).map(async (_, i) => {
249
+ const name = `remote-db-${i}-${set}`;
250
+ const db = fireproof(name, {
48
251
  storeUrls: {
49
- base: `memory://remote-db-${i}-${set}`,
252
+ // base: `memory://${name}`,
253
+ data: {
254
+ car: `memory://car/${name}`,
255
+ meta: `memory://meta/${name}`,
256
+ file: `memory://file/${name}`,
257
+ wal: `memory://wal/${name}`,
258
+ },
50
259
  },
51
260
  });
261
+ // await db.put({ _id: `genesis`, value: `genesis` });
262
+ // await db.ready();
52
263
  for (let j = 0; j < 10; j++) {
53
- await db.put({ _id: `${i}-${j}`, value: `${i}-${set}` });
264
+ await db.put({ _id: `${i}-${j}`, value: `${i}-${j}` });
54
265
  }
266
+ expect(await db.get(PARAM.GENESIS_CID)).toEqual({ _id: PARAM.GENESIS_CID });
55
267
  await db.close();
56
- return db;
268
+ return name;
57
269
  }),
58
270
  );
271
+ // await new Promise((resolve) => setTimeout(resolve, 1000));
59
272
 
60
273
  db = fireproof(`db-${set}`, {
61
274
  storeUrls: {
62
275
  base: `memory://db-${set}`,
63
276
  },
64
277
  });
278
+ // await db.put({ _id: `genesis`, value: `genesis` });
279
+ for (let j = 0; j < 10; j++) {
280
+ await db.put({ _id: `db-${j}`, value: `db-${set}` });
281
+ }
282
+ expect(await db.get(PARAM.GENESIS_CID)).toEqual({ _id: PARAM.GENESIS_CID });
65
283
  });
66
284
  afterAll(async () => {
67
285
  await db.close();
68
286
  });
69
287
 
70
- it("it is joinable", async () => {
71
- for (let i = 0; i < 10; i++) {
72
- // create meta/car/files store from aJoinable
73
- // retrieve meta from attachable and subscribe to it
74
- // merge incoming meta with local
75
- // the attach meta includes source url's which ref back to aJoinable Attachable
288
+ it("it is joinable detachable", async () => {
289
+ const my = fireproof("my", {
290
+ storeUrls: {
291
+ base: "memory://my",
292
+ },
293
+ });
294
+ await my.put({ _id: "genesis", value: "genesis" });
295
+ await Promise.all(
296
+ joinableDBs.map(async (name) => {
297
+ const tmp = fireproof(name, {
298
+ storeUrls: {
299
+ data: {
300
+ car: `memory://car/${name}`,
301
+ meta: `memory://meta/${name}`,
302
+ file: `memory://file/${name}`,
303
+ wal: `memory://wal/${name}`,
304
+ },
305
+ },
306
+ });
307
+ const res = await tmp.allDocs();
308
+ expect(res.rows.length).toBe(10);
309
+ await tmp.close();
310
+ const attached = await my.attach(aJoinable(name));
311
+ expect(attached).toBeDefined();
312
+ }),
313
+ );
314
+ expect(my.ledger.crdt.blockstore.loader.attachedStores.remotes().length).toBe(joinableDBs.length);
315
+ await my.close();
316
+ expect(my.ledger.crdt.blockstore.loader.attachedStores.remotes().length).toBe(0);
317
+ });
318
+
319
+ it("it is inbound syncing", async () => {
320
+ await Promise.all(
321
+ joinableDBs.map(async (name) => {
322
+ const attached = await db.attach(aJoinable(name));
323
+ expect(attached).toBeDefined();
324
+ }),
325
+ );
326
+ await sleep(100);
327
+ expect(db.ledger.crdt.blockstore.loader.attachedStores.remotes().length).toBe(joinableDBs.length);
328
+ const res = await db.allDocs();
329
+ expect(res.rows.length).toBe(10 + 10 * joinableDBs.length);
330
+ });
76
331
 
77
- const attached = await db.attach(aJoinable("i" + i));
78
- expect(attached).toBeDefined();
79
- await attached.detach();
80
- }
332
+ it("it empty inbound syncing", async () => {
333
+ const name = `empty-db-${sthis.nextId().str}`;
334
+ const db = fireproof(name, {
335
+ storeUrls: {
336
+ // base: `memory://${name}`,
337
+ data: {
338
+ car: `memory://car/${name}`,
339
+ meta: `memory://meta/${name}`,
340
+ file: `memory://file/${name}`,
341
+ wal: `memory://wal/${name}`,
342
+ },
343
+ },
344
+ });
345
+ await Promise.all(
346
+ joinableDBs.map(async (name) => {
347
+ const attached = await db.attach(aJoinable(name));
348
+ expect(attached).toBeDefined();
349
+ }),
350
+ );
351
+ await sleep(100);
352
+ expect(db.ledger.crdt.blockstore.loader.attachedStores.remotes().length).toBe(joinableDBs.length);
353
+ const res = await db.allDocs();
354
+ expect(res.rows.length).toBe(10 * joinableDBs.length);
81
355
  });
82
356
  });