amalgm 0.1.255 → 0.1.257
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/shared-realtime-tunnel.js +1 -1
- package/package.json +1 -1
- package/runtime/scripts/amalgm-mcp/registration/entity-cloud.js +33 -11
- package/runtime/scripts/amalgm-mcp/registration/service.js +6 -9
- package/runtime/scripts/amalgm-mcp/server/routes/entities.js +7 -4
- package/runtime/scripts/amalgm-mcp/tests/entity-cloud.test.js +22 -15
- package/runtime/scripts/amalgm-mcp/tests/entity-content.test.js +1 -1
- package/runtime/scripts/amalgm-mcp/tests/entity-materialization.test.js +4 -4
- package/runtime/scripts/amalgm-mcp/tests/registration.service.test.js +36 -2
|
@@ -20,7 +20,7 @@ const REAUTHORIZE_MS = 30_000;
|
|
|
20
20
|
const REPO_OBJECT_REQUEST_TIMEOUT_MS = 15_000;
|
|
21
21
|
const COOKIE_PRIVATE_CONTRACT = 'browser-cookie-jar@1';
|
|
22
22
|
const USER_HOME_PRIVATE_CONTRACT = 'amalgm-user-home@1';
|
|
23
|
-
const ENTITY_REGISTRY_PRIVATE_CONTRACT = 'amalgm-entity-registry@
|
|
23
|
+
const ENTITY_REGISTRY_PRIVATE_CONTRACT = 'amalgm-entity-registry@2';
|
|
24
24
|
|
|
25
25
|
function createSharedRealtimeTunnel({
|
|
26
26
|
send,
|
package/package.json
CHANGED
|
@@ -11,7 +11,12 @@
|
|
|
11
11
|
|
|
12
12
|
const crypto = require('crypto');
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// `@1` was an unreleased bootstrap experiment which could project arbitrary
|
|
15
|
+
// pre-cloud local registrations into the first private head. A resource
|
|
16
|
+
// contract names immutable authority semantics, so it is quarantined rather
|
|
17
|
+
// than interpreted or overwritten. `@2` begins with only the verified user
|
|
18
|
+
// home; later user ground enters exclusively through `amalgm register`.
|
|
19
|
+
const ENTITY_CLOUD_CONTRACT = 'amalgm-entity-registry@2';
|
|
15
20
|
const ENTITY_CLOUD_SCHEMA_VERSION = 1;
|
|
16
21
|
const BOOTSTRAP_RECONCILIATION_STATE = 'reconciling-bootstrap';
|
|
17
22
|
const SNAPSHOT_REPLACE_OPERATION = 'entity.snapshot.replace';
|
|
@@ -424,14 +429,23 @@ function createEntityCloud({ db, userId, deviceId, content = null, repoStates =
|
|
|
424
429
|
}
|
|
425
430
|
}
|
|
426
431
|
|
|
427
|
-
|
|
432
|
+
/**
|
|
433
|
+
* Create the first private entity-resource snapshot from the *already
|
|
434
|
+
* verified* bootstrap graph. This deliberately accepts records rather than
|
|
435
|
+
* a registry: login owns the declared user-home graph, but an older device
|
|
436
|
+
* can also hold unrelated local registrations which have never had cloud
|
|
437
|
+
* authority. Publishing those as an implicit local-wins merge would make
|
|
438
|
+
* sign-in a hidden `register` command.
|
|
439
|
+
*/
|
|
440
|
+
function bootstrap(records) {
|
|
428
441
|
const currentIdentity = identity();
|
|
429
442
|
if (!currentIdentity.enabled) return currentIdentity;
|
|
430
443
|
const existing = replica();
|
|
431
444
|
if (existing?.state === 'active') {
|
|
432
445
|
throw new Error('entity cloud registry already exists locally; cloud lookup must not create it again');
|
|
433
446
|
}
|
|
434
|
-
|
|
447
|
+
if (!Array.isArray(records)) throw new Error('entity cloud bootstrap requires verified records');
|
|
448
|
+
const snapshot = cloudSnapshot(records);
|
|
435
449
|
const cutoff = db.prepare('SELECT COALESCE(MAX(sequence), 0) AS sequence FROM entity_cloud_mutations').get().sequence;
|
|
436
450
|
saveReplica({
|
|
437
451
|
resourceId: currentIdentity.resourceId,
|
|
@@ -471,7 +485,6 @@ function createEntityCloud({ db, userId, deviceId, content = null, repoStates =
|
|
|
471
485
|
|| !Number.isInteger(Number(headVersion)) || Number(headVersion) < 0) {
|
|
472
486
|
throw new Error('entity cloud registry authority is invalid');
|
|
473
487
|
}
|
|
474
|
-
const local = cloudSnapshot(registry.syncRecords());
|
|
475
488
|
const current = replica();
|
|
476
489
|
const bootstrapping = current?.state === 'bootstrapping';
|
|
477
490
|
const reconciling = current?.state === BOOTSTRAP_RECONCILIATION_STATE;
|
|
@@ -486,7 +499,12 @@ function createEntityCloud({ db, userId, deviceId, content = null, repoStates =
|
|
|
486
499
|
// exactly the already-verified declared user home. This is not a general
|
|
487
500
|
// local-wins merge: user-selected ground remains refused until an active
|
|
488
501
|
// authoritative snapshot exists.
|
|
489
|
-
|
|
502
|
+
// The first entity resource contains only declared user-home truth. An
|
|
503
|
+
// old installation may also have local, pre-cloud user ground; that is
|
|
504
|
+
// deliberately excluded here and will join only through an explicit
|
|
505
|
+
// later `amalgm register`. The empty cloud resource is therefore repaired
|
|
506
|
+
// from the trusted bootstrap records, never from the whole local registry.
|
|
507
|
+
if (emptyCloudGraph && trustedBootstrap && (!current || bootstrapping)) {
|
|
490
508
|
const next = {
|
|
491
509
|
resourceId,
|
|
492
510
|
deviceId: currentIdentity.deviceId,
|
|
@@ -515,8 +533,8 @@ function createEntityCloud({ db, userId, deviceId, content = null, repoStates =
|
|
|
515
533
|
}
|
|
516
534
|
|
|
517
535
|
if (reconciling) {
|
|
518
|
-
if (!trustedBootstrap
|
|
519
|
-
throw new Error('entity bootstrap reconciliation
|
|
536
|
+
if (!trustedBootstrap) {
|
|
537
|
+
throw new Error('entity bootstrap reconciliation requires the verified user-home graph');
|
|
520
538
|
}
|
|
521
539
|
if (current.resourceId !== resourceId || Number(authorityEpoch) !== current.authorityEpoch
|
|
522
540
|
|| Number(headVersion) < current.headVersion || !recordsAreSubset(snapshot.records, trustedBootstrap)) {
|
|
@@ -547,13 +565,17 @@ function createEntityCloud({ db, userId, deviceId, content = null, repoStates =
|
|
|
547
565
|
reconciling: !complete,
|
|
548
566
|
};
|
|
549
567
|
}
|
|
550
|
-
if (bootstrapping
|
|
551
|
-
|
|
568
|
+
if (bootstrapping) {
|
|
569
|
+
const expected = trustedBootstrap ?? cloudSnapshot(registry.syncRecords()).records;
|
|
570
|
+
if (!sameRecords(expected, snapshot.records)) {
|
|
571
|
+
throw new Error('first cloud entity snapshot does not match the locally bootstrapped identity graph');
|
|
572
|
+
}
|
|
552
573
|
}
|
|
553
574
|
if (!bootstrapping) {
|
|
554
575
|
const cloudByUuid = new Map(snapshot.records.map((record) => [record.uuid, record]));
|
|
555
|
-
for (const
|
|
556
|
-
|
|
576
|
+
for (const local of registry.syncRecords()) {
|
|
577
|
+
const remote = cloudByUuid.get(local.uuid);
|
|
578
|
+
if (remote && !sameRecord(cloudRecord(local), remote)) {
|
|
557
579
|
throw new Error('cloud entity graph conflicts with locally bound ground; resolve the local mutation before importing a new cloud head');
|
|
558
580
|
}
|
|
559
581
|
}
|
|
@@ -381,10 +381,10 @@ function createRegistrationService({
|
|
|
381
381
|
};
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
-
/** The only local graph
|
|
385
|
-
* the exact home that the user-home handshake has already verified.
|
|
386
|
-
*
|
|
387
|
-
*
|
|
384
|
+
/** The only local graph eligible to repair an old empty entity resource is
|
|
385
|
+
* the exact home that the user-home handshake has already verified. Extra
|
|
386
|
+
* local entities are deliberately excluded rather than treated as a login
|
|
387
|
+
* merge: they become cloud-backed only through a later explicit register. */
|
|
388
388
|
async function exactUserHomeCloudRecords() {
|
|
389
389
|
const home = await bootstrapUserHome();
|
|
390
390
|
const expected = new Map();
|
|
@@ -395,12 +395,9 @@ function createRegistrationService({
|
|
|
395
395
|
// containers, with the registry's sync representation.
|
|
396
396
|
expected.set(entry.record.uuid, boundary.current.registry.syncRecord(entry.record.uuid));
|
|
397
397
|
}
|
|
398
|
-
const records =
|
|
399
|
-
if (records.length !== expected.size) {
|
|
400
|
-
throw new Error('local entity graph contains ground outside the declared user home');
|
|
401
|
-
}
|
|
398
|
+
const records = [...expected.values()];
|
|
402
399
|
for (const record of records) {
|
|
403
|
-
const declared =
|
|
400
|
+
const declared = boundary.current.registry.syncRecord(record.uuid);
|
|
404
401
|
if (!declared || ![
|
|
405
402
|
'uuid', 'type', 'parentUUID', 'name', 'status', 'version', 'payloadVersion',
|
|
406
403
|
].every((field) => record[field] === declared[field])) {
|
|
@@ -135,9 +135,11 @@ async function handleEntityRoutes(ctx) {
|
|
|
135
135
|
return true;
|
|
136
136
|
}
|
|
137
137
|
// A missing entity resource is first created from the same declared
|
|
138
|
-
// user-home graph that login owns. This is not an alternate registrar
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
// user-home graph that login owns. This is not an alternate registrar:
|
|
139
|
+
// pre-cloud user registrations are deliberately excluded until their
|
|
140
|
+
// caller explicitly registers them after the bootstrap head is active.
|
|
141
|
+
const bootstrapRecords = await service.exactUserHomeCloudRecords();
|
|
142
|
+
ctx.sendJson(200, service.entityCloud.bootstrap(bootstrapRecords));
|
|
141
143
|
return true;
|
|
142
144
|
}
|
|
143
145
|
|
|
@@ -147,7 +149,8 @@ async function handleEntityRoutes(ctx) {
|
|
|
147
149
|
const service = registrationService();
|
|
148
150
|
try {
|
|
149
151
|
const existing = service.entityCloud.replica();
|
|
150
|
-
let requiresBootstrapProof = existing?.state === '
|
|
152
|
+
let requiresBootstrapProof = existing?.state === 'bootstrapping'
|
|
153
|
+
|| existing?.state === 'reconciling-bootstrap';
|
|
151
154
|
try {
|
|
152
155
|
const snapshot = JSON.parse(Buffer.from(String(body?.snapshotBase64 || ''), 'base64').toString('utf8'));
|
|
153
156
|
requiresBootstrapProof ||= Number(body?.headVersion) === 0
|
|
@@ -25,7 +25,7 @@ test('the entity cloud snapshot establishes identity, then each later entity com
|
|
|
25
25
|
assert.equal(db.prepare('SELECT COUNT(*) AS count FROM entity_cloud_mutations').get().count, 0,
|
|
26
26
|
'initial bootstrap identity is carried by the first immutable snapshot, not an unscoped tail');
|
|
27
27
|
|
|
28
|
-
const bootstrap = cloud.bootstrap(registry);
|
|
28
|
+
const bootstrap = cloud.bootstrap(registry.syncRecords());
|
|
29
29
|
const snapshot = parseSnapshot(Buffer.from(bootstrap.snapshotBase64, 'base64'));
|
|
30
30
|
assert.deepEqual(snapshot.records.map((record) => record.uuid), [root.uuid]);
|
|
31
31
|
cloud.install({
|
|
@@ -64,7 +64,7 @@ test('a signed-in registration is refused until the cloud entity resource is act
|
|
|
64
64
|
const registry = createRegistry({ db, ephemeral: true, emit: () => {}, journal: cloud.journal });
|
|
65
65
|
assert.throws(() => cloud.assertRegistrationReady(), /entity cloud registry is not ready/);
|
|
66
66
|
registry.enrollRoot({ type: 'workspace', name: 'bootstrap-only' });
|
|
67
|
-
const bootstrap = cloud.bootstrap(registry);
|
|
67
|
+
const bootstrap = cloud.bootstrap(registry.syncRecords());
|
|
68
68
|
cloud.install({
|
|
69
69
|
registry,
|
|
70
70
|
resourceId: bootstrap.resourceId,
|
|
@@ -81,7 +81,7 @@ test('a large registration replaces the complete graph in one cloud operation an
|
|
|
81
81
|
const cloud = createEntityCloud({ db, userId: 'user-1', deviceId: 'device-1' });
|
|
82
82
|
const registry = createRegistry({ db, ephemeral: true, emit: () => {}, journal: cloud.journal });
|
|
83
83
|
const root = registry.enrollRoot({ type: 'workspace', name: 'large-ground' });
|
|
84
|
-
const bootstrap = cloud.bootstrap(registry);
|
|
84
|
+
const bootstrap = cloud.bootstrap(registry.syncRecords());
|
|
85
85
|
cloud.install({
|
|
86
86
|
registry,
|
|
87
87
|
resourceId: bootstrap.resourceId,
|
|
@@ -126,7 +126,7 @@ test('a large registration replaces the complete graph in one cloud operation an
|
|
|
126
126
|
recipientDb.close();
|
|
127
127
|
});
|
|
128
128
|
|
|
129
|
-
test('
|
|
129
|
+
test('a legacy empty entity resource repairs only the verified home and excludes unrelated local ground', () => {
|
|
130
130
|
const db = new Database(':memory:');
|
|
131
131
|
const cloud = createEntityCloud({ db, userId: 'user-1', deviceId: 'device-1' });
|
|
132
132
|
const registry = createRegistry({ db, ephemeral: true, emit: () => {}, journal: cloud.journal });
|
|
@@ -172,21 +172,28 @@ test('only an exact verified bootstrap graph can repair a legacy empty entity re
|
|
|
172
172
|
assert.equal(cloud.replica().state, 'active');
|
|
173
173
|
assert.doesNotThrow(() => cloud.assertRegistrationReady());
|
|
174
174
|
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
const
|
|
178
|
-
const safeRoot =
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
175
|
+
const legacyDb = new Database(':memory:');
|
|
176
|
+
const legacyCloud = createEntityCloud({ db: legacyDb, userId: 'user-1', deviceId: 'legacy-device' });
|
|
177
|
+
const legacyRegistry = createRegistry({ db: legacyDb, ephemeral: true, emit: () => {}, journal: legacyCloud.journal });
|
|
178
|
+
const safeRoot = legacyRegistry.enrollRoot({ type: 'workspace', name: 'agents' });
|
|
179
|
+
const legacyRepo = legacyRegistry.create({ type: 'repo.git', parentUUID: safeRoot.uuid, name: 'old-local-repo' });
|
|
180
|
+
const verifiedHome = legacyRegistry.syncRecords().filter((record) => record.uuid === safeRoot.uuid);
|
|
181
|
+
const repaired = legacyCloud.install({
|
|
182
|
+
registry: legacyRegistry,
|
|
182
183
|
resourceId,
|
|
183
184
|
authorityEpoch: 1,
|
|
184
185
|
headVersion: 0,
|
|
185
186
|
snapshotBase64: empty.toString('base64'),
|
|
186
187
|
snapshotChecksum: require('crypto').createHash('sha256').update(empty).digest('hex'),
|
|
187
|
-
bootstrapRecords:
|
|
188
|
-
})
|
|
189
|
-
|
|
188
|
+
bootstrapRecords: verifiedHome,
|
|
189
|
+
});
|
|
190
|
+
assert.equal(repaired.reconciling, true);
|
|
191
|
+
const repair = legacyCloud.claim();
|
|
192
|
+
assert.equal(repair.length, 1);
|
|
193
|
+
assert.equal(repair[0].operation.record.uuid, safeRoot.uuid,
|
|
194
|
+
'only the verified home node is queued into the automatic cloud graph');
|
|
195
|
+
assert.equal(legacyRegistry.syncRecord(legacyRepo.uuid).uuid, legacyRepo.uuid,
|
|
196
|
+
'unrelated local ground remains local until its caller explicitly registers it');
|
|
190
197
|
});
|
|
191
198
|
|
|
192
199
|
test('a compacted remote snapshot enters the cloud catalog, not locally watched identity, and add claims its immutable content', () => {
|
|
@@ -270,7 +277,7 @@ test('add accepts only a catalog installed by the active compacted snapshot, nev
|
|
|
270
277
|
envelope: {
|
|
271
278
|
resourceId,
|
|
272
279
|
mutationId: 'ent_remote_change',
|
|
273
|
-
contract: 'amalgm-entity-registry@
|
|
280
|
+
contract: 'amalgm-entity-registry@2',
|
|
274
281
|
schemaVersion: 1,
|
|
275
282
|
operationKind: 'entity.upsert',
|
|
276
283
|
operation: { kind: 'entity.upsert', record: changed },
|
|
@@ -32,7 +32,7 @@ test('file bytes are captured as bounded immutable chunks, then acknowledged bef
|
|
|
32
32
|
const cloud = createEntityCloud({ db, userId: 'user-1', deviceId: 'device-1', content });
|
|
33
33
|
const registry = createRegistry({ db, ephemeral: true, emit: () => {}, journal: cloud.journal });
|
|
34
34
|
const root = registry.enrollRoot({ type: 'workspace', name: 'ground' });
|
|
35
|
-
const bootstrap = cloud.bootstrap(registry);
|
|
35
|
+
const bootstrap = cloud.bootstrap(registry.syncRecords());
|
|
36
36
|
cloud.install({
|
|
37
37
|
registry,
|
|
38
38
|
resourceId: bootstrap.resourceId,
|
|
@@ -189,7 +189,7 @@ test('an added ordinary workspace stays live: a later cloud file head replaces l
|
|
|
189
189
|
envelope: {
|
|
190
190
|
resourceId: sourceCloud.identity().resourceId,
|
|
191
191
|
mutationId: 'ent_remote_file_change',
|
|
192
|
-
contract: 'amalgm-entity-registry@
|
|
192
|
+
contract: 'amalgm-entity-registry@2',
|
|
193
193
|
schemaVersion: 1,
|
|
194
194
|
operationKind: 'entity.upsert',
|
|
195
195
|
operation: { kind: 'entity.upsert', record: remoteRecord },
|
|
@@ -296,7 +296,7 @@ test('add preserves a symlink UUID and later retargets the same literal link wit
|
|
|
296
296
|
const ingested = target.ingestCloudMutation({
|
|
297
297
|
envelope: {
|
|
298
298
|
resourceId: sourceCloud.identity().resourceId, mutationId: 'ent_remote_link_change',
|
|
299
|
-
contract: 'amalgm-entity-registry@
|
|
299
|
+
contract: 'amalgm-entity-registry@2', schemaVersion: 1,
|
|
300
300
|
operationKind: 'entity.upsert', operation: { kind: 'entity.upsert', record: sourceRegistry.syncRecord(changed.uuid) },
|
|
301
301
|
},
|
|
302
302
|
version: 42, committedAt: '2026-08-05T00:00:00.000Z',
|
|
@@ -344,7 +344,7 @@ test('add recreates an actual Git repository from verified Repocard cargo, then
|
|
|
344
344
|
cloudUserId: 'user-1', cloudDeviceId: 'target-device',
|
|
345
345
|
});
|
|
346
346
|
try {
|
|
347
|
-
const bootstrap = source.entityCloud.bootstrap(source.registration.registry);
|
|
347
|
+
const bootstrap = source.entityCloud.bootstrap(source.registration.registry.syncRecords());
|
|
348
348
|
source.entityCloud.install({
|
|
349
349
|
registry: source.registration.registry, resourceId: bootstrap.resourceId,
|
|
350
350
|
authorityEpoch: 1, headVersion: 0, snapshotBase64: bootstrap.snapshotBase64,
|
|
@@ -420,7 +420,7 @@ test('add recreates an actual Git repository from verified Repocard cargo, then
|
|
|
420
420
|
const ingested = target.ingestCloudMutation({
|
|
421
421
|
envelope: {
|
|
422
422
|
resourceId: bootstrap.resourceId, mutationId: 'ent_remote_repo_change',
|
|
423
|
-
contract: 'amalgm-entity-registry@
|
|
423
|
+
contract: 'amalgm-entity-registry@2', schemaVersion: 1,
|
|
424
424
|
operationKind: 'entity.upsert', operation: { kind: 'entity.upsert', record: remoteRecord },
|
|
425
425
|
},
|
|
426
426
|
version: 2, committedAt: '2026-08-05T00:00:00.000Z',
|
|
@@ -233,6 +233,40 @@ test('user-home bootstrap creates only declared roots and registers them through
|
|
|
233
233
|
);
|
|
234
234
|
});
|
|
235
235
|
|
|
236
|
+
test('entity-cloud bootstrap publishes only the verified user home when an old local repo exists', async () => {
|
|
237
|
+
const service = createRegistrationService({
|
|
238
|
+
dir: path.join(tempRoot, 'state-user-home-cloud-boundary'),
|
|
239
|
+
homeDir: path.join(tempRoot, 'user-home-cloud-boundary'),
|
|
240
|
+
cloudUserId: 'user-home-cloud-boundary',
|
|
241
|
+
cloudDeviceId: 'computer-user-home-cloud-boundary',
|
|
242
|
+
});
|
|
243
|
+
services.push(service);
|
|
244
|
+
const home = await service.bootstrapUserHome();
|
|
245
|
+
const workspaces = home.roots.find((entry) => entry.key === 'workspaces').record;
|
|
246
|
+
const oldRepo = service.registration.registry.create({
|
|
247
|
+
type: 'repo.git', parentUUID: workspaces.uuid, name: 'old-local-repo', payloadVersion: null,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const records = await service.exactUserHomeCloudRecords();
|
|
251
|
+
assert.equal(records.length, 9);
|
|
252
|
+
assert.equal(records.some((record) => record.uuid === oldRepo.uuid), false,
|
|
253
|
+
'login never turns existing user-selected ground into an implicit cloud registration');
|
|
254
|
+
|
|
255
|
+
const bootstrap = service.entityCloud.bootstrap(records);
|
|
256
|
+
const snapshot = JSON.parse(Buffer.from(bootstrap.snapshotBase64, 'base64').toString('utf8'));
|
|
257
|
+
assert.equal(snapshot.records.length, 9);
|
|
258
|
+
service.entityCloud.install({
|
|
259
|
+
registry: service.registration.registry,
|
|
260
|
+
resourceId: bootstrap.resourceId,
|
|
261
|
+
authorityEpoch: 1,
|
|
262
|
+
headVersion: 1,
|
|
263
|
+
snapshotBase64: bootstrap.snapshotBase64,
|
|
264
|
+
snapshotChecksum: bootstrap.snapshotChecksum,
|
|
265
|
+
bootstrapRecords: records,
|
|
266
|
+
});
|
|
267
|
+
assert.doesNotThrow(() => service.entityCloud.assertRegistrationReady());
|
|
268
|
+
});
|
|
269
|
+
|
|
236
270
|
test('a fresh machine binds existing user-home UUIDs before it starts watching', async () => {
|
|
237
271
|
const first = createRegistrationService({
|
|
238
272
|
dir: path.join(tempRoot, 'state-user-home-origin'),
|
|
@@ -326,7 +360,7 @@ test('a signed-in register call writes every entity delivery intent in identity.
|
|
|
326
360
|
cloudDeviceId: 'computer-cloud-register',
|
|
327
361
|
});
|
|
328
362
|
const home = await service.bootstrapUserHome();
|
|
329
|
-
const bootstrap = service.entityCloud.bootstrap(service.registration.registry);
|
|
363
|
+
const bootstrap = service.entityCloud.bootstrap(service.registration.registry.syncRecords());
|
|
330
364
|
service.entityCloud.install({
|
|
331
365
|
registry: service.registration.registry,
|
|
332
366
|
resourceId: bootstrap.resourceId,
|
|
@@ -366,7 +400,7 @@ test('a large signed-in register call publishes one complete cloud graph before
|
|
|
366
400
|
cloudUserId: 'user-cloud-register-large',
|
|
367
401
|
cloudDeviceId: 'computer-cloud-register-large',
|
|
368
402
|
});
|
|
369
|
-
const bootstrap = service.entityCloud.bootstrap(service.registration.registry);
|
|
403
|
+
const bootstrap = service.entityCloud.bootstrap(service.registration.registry.syncRecords());
|
|
370
404
|
service.entityCloud.install({
|
|
371
405
|
registry: service.registration.registry,
|
|
372
406
|
resourceId: bootstrap.resourceId,
|