@agoric/swingset-liveslots 0.10.3-u14.0 → 0.10.3-u16.1
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/README.md +2 -0
- package/package.json +27 -19
- package/src/cache.js +2 -1
- package/src/capdata.js +0 -1
- package/src/collectionManager.js +154 -72
- package/src/index.js +4 -1
- package/src/liveslots.js +52 -81
- package/src/message.js +4 -4
- package/src/types.js +8 -2
- package/src/vatDataTypes.d.ts +271 -0
- package/src/vatDataTypes.js +2 -0
- package/src/vatstore-iterators.js +2 -0
- package/src/virtualObjectManager.js +189 -70
- package/src/virtualReferences.js +51 -0
- package/src/watchedPromises.js +61 -16
- package/test/{test-baggage.js → baggage.test.js} +1 -2
- package/test/{test-cache.js → cache.test.js} +0 -1
- package/test/{test-collection-schema-refcount.js → collection-schema-refcount.test.js} +1 -2
- package/test/{test-collection-upgrade.js → collection-upgrade.test.js} +1 -3
- package/test/{test-collections.js → collections.test.js} +117 -14
- package/test/{test-dropped-collection-weakrefs.js → dropped-collection-weakrefs.test.js} +1 -2
- package/test/{test-durabilityChecks.js → durabilityChecks.test.js} +3 -3
- package/test/{test-facetiousness.js → facetiousness.test.js} +1 -2
- package/test/gc-and-finalize.js +30 -1
- package/test/gc-helpers.js +2 -3
- package/test/{test-gc-sensitivity.js → gc-sensitivity.test.js} +2 -2
- package/test/{test-handled-promises.js → handled-promises.test.js} +5 -7
- package/test/{test-initial-vrefs.js → initial-vrefs.test.js} +2 -3
- package/test/liveslots-helpers.js +6 -6
- package/test/{test-liveslots-mock-gc.js → liveslots-mock-gc.test.js} +2 -2
- package/test/{test-liveslots-real-gc.js → liveslots-real-gc.test.js} +44 -35
- package/test/{test-liveslots.js → liveslots.test.js} +13 -14
- package/test/mock-gc.js +1 -0
- package/test/storeGC/{test-lifecycle.js → lifecycle.test.js} +2 -2
- package/test/storeGC/{test-refcount-management.js → refcount-management.test.js} +1 -2
- package/test/storeGC/{test-scalar-store-kind.js → scalar-store-kind.test.js} +0 -1
- package/test/storeGC/{test-weak-key.js → weak-key.test.js} +1 -2
- package/test/util.js +2 -2
- package/test/vat-util.js +1 -1
- package/test/virtual-objects/{test-cease-recognition.js → cease-recognition.test.js} +2 -2
- package/test/virtual-objects/{test-cross-facet.js → cross-facet.test.js} +5 -4
- package/test/virtual-objects/{test-empty-data.js → empty-data.test.js} +1 -2
- package/test/virtual-objects/{test-facets.js → facets.test.js} +1 -2
- package/test/virtual-objects/{test-kind-changes.js → kind-changes.test.js} +2 -2
- package/test/virtual-objects/{test-reachable-vrefs.js → reachable-vrefs.test.js} +2 -2
- package/test/virtual-objects/{test-rep-tostring.js → rep-tostring.test.js} +2 -3
- package/test/virtual-objects/{test-retain-remotable.js → retain-remotable.test.js} +25 -24
- package/test/virtual-objects/{test-state-shape.js → state-shape.test.js} +2 -2
- package/test/virtual-objects/{test-virtualObjectGC.js → virtualObjectGC.test.js} +2 -2
- package/test/virtual-objects/{test-virtualObjectManager.js → virtualObjectManager.test.js} +6 -2
- package/test/virtual-objects/{test-vo-real-gc.js → vo-real-gc.test.js} +8 -8
- package/test/virtual-objects/{test-weakcollections-vref-handling.js → weakcollections-vref-handling.test.js} +1 -2
- package/test/{test-vo-test-harness.js → vo-test-harness.test.js} +0 -1
- package/test/{test-vpid-liveslots.js → vpid-liveslots.test.js} +4 -5
- package/test/waitUntilQuiescent.js +2 -1
- package/tools/fakeVirtualSupport.js +41 -24
- package/tools/prepare-test-env.js +13 -0
- package/tools/setup-vat-data.js +62 -0
- package/CHANGELOG.md +0 -93
- package/test/kmarshal.js +0 -79
package/src/liveslots.js
CHANGED
|
@@ -33,7 +33,7 @@ const { details: X } = assert;
|
|
|
33
33
|
* @param {*} syscall Kernel syscall interface that the vat will have access to
|
|
34
34
|
* @param {*} forVatID Vat ID label, for use in debug diagnostics
|
|
35
35
|
* @param {*} vatPowers
|
|
36
|
-
* @param {import('./types').LiveSlotsOptions} liveSlotsOptions
|
|
36
|
+
* @param {import('./types.js').LiveSlotsOptions} liveSlotsOptions
|
|
37
37
|
* @param {*} gcTools { WeakRef, FinalizationRegistry, waitUntilQuiescent, gcAndFinalize,
|
|
38
38
|
* meterControl }
|
|
39
39
|
* @param {Pick<Console, 'debug' | 'log' | 'info' | 'warn' | 'error'>} console
|
|
@@ -251,13 +251,10 @@ function build(
|
|
|
251
251
|
const importsToRetire = new Set();
|
|
252
252
|
const exportsToRetire = new Set();
|
|
253
253
|
let doMore;
|
|
254
|
+
await null;
|
|
254
255
|
do {
|
|
255
256
|
doMore = false;
|
|
256
257
|
|
|
257
|
-
// Yes, we know this is an await inside a loop. Too bad. (Also, it's a
|
|
258
|
-
// `do {} while` loop, which means there's no conditional bypass of the
|
|
259
|
-
// await.)
|
|
260
|
-
// eslint-disable-next-line no-await-in-loop, @jessie.js/no-nested-await
|
|
261
258
|
await gcTools.gcAndFinalize();
|
|
262
259
|
|
|
263
260
|
// possiblyDeadSet contains a baseref for everything (Presences,
|
|
@@ -270,7 +267,6 @@ function build(
|
|
|
270
267
|
const deadSet = new Set();
|
|
271
268
|
|
|
272
269
|
for (const baseRef of possiblyDeadSet) {
|
|
273
|
-
// eslint-disable-next-line no-use-before-define
|
|
274
270
|
if (slotToVal.has(baseRef)) {
|
|
275
271
|
continue; // RAM pillar remains
|
|
276
272
|
}
|
|
@@ -500,54 +496,6 @@ function build(
|
|
|
500
496
|
return Remotable(iface);
|
|
501
497
|
}
|
|
502
498
|
|
|
503
|
-
/**
|
|
504
|
-
* Counters to track the next number for various categories of allocation.
|
|
505
|
-
* `exportID` starts at 1 because 'o+0' is always automatically
|
|
506
|
-
* pre-assigned to the root object.
|
|
507
|
-
* `promiseID` starts at 5 as a very minor aid to debugging: when puzzling
|
|
508
|
-
* over trace logs and the like, it helps for the numbers in various species
|
|
509
|
-
* of IDs that are jumbled together to be a little out of sync and thus a
|
|
510
|
-
* little less similar to each other.
|
|
511
|
-
*/
|
|
512
|
-
const initialIDCounters = { exportID: 1, collectionID: 1, promiseID: 5 };
|
|
513
|
-
/** @type {Record<string, number>} */
|
|
514
|
-
let idCounters;
|
|
515
|
-
let idCountersAreDirty = false;
|
|
516
|
-
|
|
517
|
-
function initializeIDCounters() {
|
|
518
|
-
if (!idCounters) {
|
|
519
|
-
// the saved value might be missing, or from an older liveslots
|
|
520
|
-
// (with fewer counters), so merge it with our initial values
|
|
521
|
-
const saved = JSON.parse(syscall.vatstoreGet('idCounters') || '{}');
|
|
522
|
-
idCounters = { ...initialIDCounters, ...saved };
|
|
523
|
-
idCountersAreDirty = true;
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
function allocateNextID(name) {
|
|
528
|
-
if (!idCounters) {
|
|
529
|
-
// Normally `initializeIDCounters` would be called from startVat, but some
|
|
530
|
-
// tests bypass that so this is a backstop. Note that the invocation from
|
|
531
|
-
// startVat is there to make vatStore access patterns a bit more
|
|
532
|
-
// consistent from one vat to another, principally as a confusion
|
|
533
|
-
// reduction measure in service of debugging; it is not a correctness
|
|
534
|
-
// issue.
|
|
535
|
-
initializeIDCounters();
|
|
536
|
-
}
|
|
537
|
-
const result = idCounters[name];
|
|
538
|
-
result !== undefined || Fail`unknown idCounters[${name}]`;
|
|
539
|
-
idCounters[name] += 1;
|
|
540
|
-
idCountersAreDirty = true;
|
|
541
|
-
return result;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
function flushIDCounters() {
|
|
545
|
-
if (idCountersAreDirty) {
|
|
546
|
-
syscall.vatstoreSet('idCounters', JSON.stringify(idCounters));
|
|
547
|
-
idCountersAreDirty = false;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
499
|
// TODO: fix awkward non-orthogonality: allocateExportID() returns a number,
|
|
552
500
|
// allocatePromiseID() returns a slot, registerPromise() uses the slot from
|
|
553
501
|
// allocatePromiseID(), exportPassByPresence() generates a slot itself using
|
|
@@ -556,15 +504,18 @@ function build(
|
|
|
556
504
|
// use a slot from the corresponding allocateX
|
|
557
505
|
|
|
558
506
|
function allocateExportID() {
|
|
559
|
-
|
|
507
|
+
// eslint-disable-next-line no-use-before-define
|
|
508
|
+
return vrm.allocateNextID('exportID');
|
|
560
509
|
}
|
|
561
510
|
|
|
562
511
|
function allocateCollectionID() {
|
|
563
|
-
|
|
512
|
+
// eslint-disable-next-line no-use-before-define
|
|
513
|
+
return vrm.allocateNextID('collectionID');
|
|
564
514
|
}
|
|
565
515
|
|
|
566
516
|
function allocatePromiseID() {
|
|
567
|
-
|
|
517
|
+
// eslint-disable-next-line no-use-before-define
|
|
518
|
+
const promiseID = vrm.allocateNextID('promiseID');
|
|
568
519
|
return makeVatSlot('promise', true, promiseID);
|
|
569
520
|
}
|
|
570
521
|
|
|
@@ -612,7 +563,7 @@ function build(
|
|
|
612
563
|
serializeBodyFormat: 'smallcaps',
|
|
613
564
|
// TODO Temporary hack.
|
|
614
565
|
// See https://github.com/Agoric/agoric-sdk/issues/2780
|
|
615
|
-
errorIdNum:
|
|
566
|
+
errorIdNum: 70_000,
|
|
616
567
|
marshalSaveError: err =>
|
|
617
568
|
// By sending this to `console.warn`, under cosmic-swingset this is
|
|
618
569
|
// controlled by the `console` option given to makeLiveSlots.
|
|
@@ -759,9 +710,9 @@ function build(
|
|
|
759
710
|
Fail`registerValue(${baseRef} should not receive individual facets`;
|
|
760
711
|
slotToVal.set(baseRef, new WeakRef(val));
|
|
761
712
|
if (valIsCohort) {
|
|
762
|
-
vrm.getFacetNames(id).
|
|
713
|
+
for (const [index, name] of vrm.getFacetNames(id).entries()) {
|
|
763
714
|
valToSlot.set(val[name], `${baseRef}:${index}`);
|
|
764
|
-
}
|
|
715
|
+
}
|
|
765
716
|
} else {
|
|
766
717
|
valToSlot.set(val, baseRef);
|
|
767
718
|
}
|
|
@@ -983,12 +934,20 @@ function build(
|
|
|
983
934
|
return null;
|
|
984
935
|
}
|
|
985
936
|
syscall.resolve(resolutions);
|
|
986
|
-
|
|
987
|
-
resolutionCD
|
|
988
|
-
|
|
989
|
-
|
|
937
|
+
for (const resolution of resolutions) {
|
|
938
|
+
const [_xvpid, _isReject, resolutionCD] = resolution;
|
|
939
|
+
for (const vref of resolutionCD.slots) {
|
|
940
|
+
maybeNewVPIDs.add(vref);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
for (const resolution of resolutions) {
|
|
944
|
+
const [xvpid] = resolution;
|
|
945
|
+
maybeNewVPIDs.delete(xvpid);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
for (const newVPID of Array.from(maybeNewVPIDs).sort()) {
|
|
949
|
+
maybeExportPromise(newVPID);
|
|
990
950
|
}
|
|
991
|
-
Array.from(maybeNewVPIDs).sort().forEach(maybeExportPromise);
|
|
992
951
|
|
|
993
952
|
// ideally we'd wait until .then is called on p before subscribing, but
|
|
994
953
|
// the current Promise API doesn't give us a way to discover this, so we
|
|
@@ -1190,13 +1149,21 @@ function build(
|
|
|
1190
1149
|
|
|
1191
1150
|
const maybeNewVPIDs = new Set();
|
|
1192
1151
|
// if we mention a vpid, we might need to track it
|
|
1193
|
-
|
|
1194
|
-
resolutionCD
|
|
1195
|
-
|
|
1152
|
+
for (const resolution of resolutions) {
|
|
1153
|
+
const [_xvpid, _isReject, resolutionCD] = resolution;
|
|
1154
|
+
for (const vref of resolutionCD.slots) {
|
|
1155
|
+
maybeNewVPIDs.add(vref);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1196
1158
|
// but not if we just resolved it (including the primary)
|
|
1197
|
-
|
|
1159
|
+
for (const resolution of resolutions) {
|
|
1160
|
+
const [xvpid] = resolution;
|
|
1161
|
+
maybeNewVPIDs.delete(xvpid);
|
|
1162
|
+
}
|
|
1198
1163
|
// track everything that's left
|
|
1199
|
-
Array.from(maybeNewVPIDs).sort()
|
|
1164
|
+
for (const newVPID of Array.from(maybeNewVPIDs).sort()) {
|
|
1165
|
+
maybeExportPromise(newVPID);
|
|
1166
|
+
}
|
|
1200
1167
|
|
|
1201
1168
|
// only the primary can possibly be newly resolved
|
|
1202
1169
|
unregisterUnreferencedVPID(vpid);
|
|
@@ -1254,11 +1221,11 @@ function build(
|
|
|
1254
1221
|
// 'imports' is an exclusively-owned Set that holds all new
|
|
1255
1222
|
// promise vpids, both resolved and unresolved
|
|
1256
1223
|
const imports = finishCollectingPromiseImports();
|
|
1257
|
-
|
|
1224
|
+
for (const vpid of retiredVPIDs) {
|
|
1258
1225
|
unregisterUnreferencedVPID(vpid); // unregisters if not in vdata
|
|
1259
1226
|
importedVPIDs.delete(vpid);
|
|
1260
1227
|
imports.delete(vpid); // resolved, so don't subscribe()
|
|
1261
|
-
}
|
|
1228
|
+
}
|
|
1262
1229
|
for (const vpid of Array.from(imports).sort()) {
|
|
1263
1230
|
syscall.subscribe(vpid);
|
|
1264
1231
|
}
|
|
@@ -1298,14 +1265,18 @@ function build(
|
|
|
1298
1265
|
|
|
1299
1266
|
function retireExports(vrefs) {
|
|
1300
1267
|
assert(Array.isArray(vrefs));
|
|
1301
|
-
vrefs
|
|
1268
|
+
for (const vref of vrefs) {
|
|
1269
|
+
retireOneExport(vref);
|
|
1270
|
+
}
|
|
1302
1271
|
}
|
|
1303
1272
|
|
|
1304
1273
|
function retireImports(vrefs) {
|
|
1305
1274
|
assert(Array.isArray(vrefs));
|
|
1306
1275
|
vrefs.map(vref => insistVatType('object', vref));
|
|
1307
1276
|
vrefs.map(vref => assert(!parseVatSlot(vref).allocatedByVat));
|
|
1308
|
-
vrefs
|
|
1277
|
+
for (const vref of vrefs) {
|
|
1278
|
+
vrm.ceaseRecognition(vref);
|
|
1279
|
+
}
|
|
1309
1280
|
}
|
|
1310
1281
|
|
|
1311
1282
|
// TODO: when we add notifyForward, guard against cycles
|
|
@@ -1450,7 +1421,7 @@ function build(
|
|
|
1450
1421
|
}
|
|
1451
1422
|
harden(vpow);
|
|
1452
1423
|
|
|
1453
|
-
initializeIDCounters();
|
|
1424
|
+
vrm.initializeIDCounters();
|
|
1454
1425
|
vom.initializeKindHandleKind();
|
|
1455
1426
|
collectionManager.initializeStoreKindInfo();
|
|
1456
1427
|
|
|
@@ -1496,7 +1467,7 @@ function build(
|
|
|
1496
1467
|
}
|
|
1497
1468
|
|
|
1498
1469
|
/**
|
|
1499
|
-
* @param {import('./types').VatDeliveryObject} delivery
|
|
1470
|
+
* @param {import('./types.js').VatDeliveryObject} delivery
|
|
1500
1471
|
* @returns {void | Promise<void>}
|
|
1501
1472
|
*/
|
|
1502
1473
|
function dispatchToUserspace(delivery) {
|
|
@@ -1561,7 +1532,7 @@ function build(
|
|
|
1561
1532
|
}
|
|
1562
1533
|
|
|
1563
1534
|
/**
|
|
1564
|
-
* @param { import('./types').SwingSetCapData } _disconnectObjectCapData
|
|
1535
|
+
* @param { import('./types.js').SwingSetCapData } _disconnectObjectCapData
|
|
1565
1536
|
* @returns {Promise<void>}
|
|
1566
1537
|
*/
|
|
1567
1538
|
async function stopVat(_disconnectObjectCapData) {
|
|
@@ -1573,7 +1544,7 @@ function build(
|
|
|
1573
1544
|
* dispatch has completed and user code has relinquished agency.
|
|
1574
1545
|
*/
|
|
1575
1546
|
function afterDispatchActions() {
|
|
1576
|
-
flushIDCounters();
|
|
1547
|
+
vrm.flushIDCounters();
|
|
1577
1548
|
collectionManager.flushSchemaCache();
|
|
1578
1549
|
vom.flushStateCache();
|
|
1579
1550
|
}
|
|
@@ -1613,7 +1584,7 @@ function build(
|
|
|
1613
1584
|
* terminate the vat). Userspace should not be able to cause the delivery
|
|
1614
1585
|
* to fail: only a bug in liveslots should trigger a failure.
|
|
1615
1586
|
*
|
|
1616
|
-
* @param {import('./types').VatDeliveryObject} delivery
|
|
1587
|
+
* @param {import('./types.js').VatDeliveryObject} delivery
|
|
1617
1588
|
* @returns {Promise<void>}
|
|
1618
1589
|
*/
|
|
1619
1590
|
async function dispatch(delivery) {
|
|
@@ -1629,7 +1600,7 @@ function build(
|
|
|
1629
1600
|
// *not* directly wait for the userspace function to complete, nor for
|
|
1630
1601
|
// any promise it returns to fire.
|
|
1631
1602
|
const p = Promise.resolve(delivery).then(unmeteredDispatch);
|
|
1632
|
-
p.finally(() => (complete = true));
|
|
1603
|
+
void p.finally(() => (complete = true));
|
|
1633
1604
|
|
|
1634
1605
|
// Instead, we wait for userspace to become idle by draining the
|
|
1635
1606
|
// promise queue. We clean up and then examine/return 'p' so any
|
|
@@ -1664,7 +1635,7 @@ function build(
|
|
|
1664
1635
|
* @param {*} syscall Kernel syscall interface that the vat will have access to
|
|
1665
1636
|
* @param {*} forVatID Vat ID label, for use in debug diagostics
|
|
1666
1637
|
* @param {*} vatPowers
|
|
1667
|
-
* @param {import('./types').LiveSlotsOptions} liveSlotsOptions
|
|
1638
|
+
* @param {import('./types.js').LiveSlotsOptions} liveSlotsOptions
|
|
1668
1639
|
* @param {*} gcTools { WeakRef, FinalizationRegistry, waitUntilQuiescent }
|
|
1669
1640
|
* @param {Pick<Console, 'debug' | 'log' | 'info' | 'warn' | 'error'>} [liveSlotsConsole]
|
|
1670
1641
|
* @param {*} [buildVatNamespace]
|
package/src/message.js
CHANGED
|
@@ -3,7 +3,7 @@ import { insistCapData } from './capdata.js';
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @typedef {{
|
|
6
|
-
* methargs: import('./types').SwingSetCapData, // of [method, args]
|
|
6
|
+
* methargs: import('./types.js').SwingSetCapData, // of [method, args]
|
|
7
7
|
* result: string | undefined | null,
|
|
8
8
|
* }} Message
|
|
9
9
|
*/
|
|
@@ -32,7 +32,7 @@ export function insistMessage(message) {
|
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* @param {unknown} vdo
|
|
35
|
-
* @returns {asserts vdo is VatDeliveryObject}
|
|
35
|
+
* @returns {asserts vdo is import('./types').VatDeliveryObject}
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
38
|
export function insistVatDeliveryObject(vdo) {
|
|
@@ -114,7 +114,7 @@ export function insistVatDeliveryResult(vdr) {
|
|
|
114
114
|
|
|
115
115
|
/**
|
|
116
116
|
* @param {unknown} vso
|
|
117
|
-
* @returns {asserts vso is VatSyscallObject}
|
|
117
|
+
* @returns {asserts vso is import('./types').VatSyscallObject}
|
|
118
118
|
*/
|
|
119
119
|
|
|
120
120
|
export function insistVatSyscallObject(vso) {
|
|
@@ -194,7 +194,7 @@ export function insistVatSyscallObject(vso) {
|
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
196
|
* @param {unknown} vsr
|
|
197
|
-
* @returns {asserts vsr is VatSyscallResult}
|
|
197
|
+
* @returns {asserts vsr is import('./types').VatSyscallResult}
|
|
198
198
|
*/
|
|
199
199
|
|
|
200
200
|
export function insistVatSyscallResult(vsr) {
|
package/src/types.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Ensure this is a module.
|
|
2
|
+
export {};
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* @callback makeLiveSlots
|
|
3
6
|
*/
|
|
@@ -79,5 +82,8 @@
|
|
|
79
82
|
*
|
|
80
83
|
*/
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
/**
|
|
86
|
+
* @template V fulfilled value
|
|
87
|
+
* @template {any[]} [A=unknown[]] arguments
|
|
88
|
+
* @typedef { {onFulfilled?: (value: V, ...args: A) => void, onRejected?: (reason: unknown, ...args: A) => void} } PromiseWatcher
|
|
89
|
+
*/
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Types for vat-data
|
|
3
|
+
*
|
|
4
|
+
* Facet is a single object with methods.
|
|
5
|
+
* Behavior is a description when defining a kind of what facets it will have.
|
|
6
|
+
* For the non-multi defineKind, there is just one facet so it doesn't have a key.
|
|
7
|
+
*/
|
|
8
|
+
import type {
|
|
9
|
+
MapStore,
|
|
10
|
+
SetStore,
|
|
11
|
+
StoreOptions,
|
|
12
|
+
WeakMapStore,
|
|
13
|
+
WeakSetStore,
|
|
14
|
+
} from '@agoric/store';
|
|
15
|
+
import type { Amplify, IsInstance, ReceivePower, StateShape } from '@endo/exo';
|
|
16
|
+
import type { RemotableObject } from '@endo/pass-style';
|
|
17
|
+
import type { InterfaceGuard, Pattern } from '@endo/patterns';
|
|
18
|
+
import type { makeWatchedPromiseManager } from './watchedPromises.js';
|
|
19
|
+
|
|
20
|
+
// TODO should be moved into @endo/patterns and eventually imported here
|
|
21
|
+
// instead of this local definition.
|
|
22
|
+
export type InterfaceGuardKit = Record<string, InterfaceGuard>;
|
|
23
|
+
export type { MapStore, Pattern };
|
|
24
|
+
|
|
25
|
+
// This needs `any` values. If they were `unknown`, code that uses Baggage
|
|
26
|
+
// would need explicit runtime checks or casts for every fetch, which is
|
|
27
|
+
// onerous.
|
|
28
|
+
export type Baggage = MapStore<string, any>;
|
|
29
|
+
|
|
30
|
+
type WatchedPromisesManager = ReturnType<typeof makeWatchedPromiseManager>;
|
|
31
|
+
|
|
32
|
+
type Tail<T extends any[]> = T extends [head: any, ...rest: infer Rest]
|
|
33
|
+
? Rest
|
|
34
|
+
: [];
|
|
35
|
+
|
|
36
|
+
// used to omit the 'context' parameter
|
|
37
|
+
type OmitFirstArg<F> = F extends (x: any, ...args: infer P) => infer R
|
|
38
|
+
? (...args: P) => R
|
|
39
|
+
: never;
|
|
40
|
+
|
|
41
|
+
export type KindFacet<O> = RemotableObject & {
|
|
42
|
+
[K in keyof O]: OmitFirstArg<O[K]>; // omit the 'context' parameter
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type KindFacets<B> = {
|
|
46
|
+
[FacetKey in keyof B]: KindFacet<B[FacetKey]>;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type KindContext<S, F> = { state: S; self: KindFacet<F> };
|
|
50
|
+
export type MultiKindContext<S, B> = { state: S; facets: KindFacets<B> };
|
|
51
|
+
|
|
52
|
+
export type PlusContext<C, M extends (...args: any[]) => any> = (
|
|
53
|
+
c: C,
|
|
54
|
+
...args: Parameters<M>
|
|
55
|
+
) => ReturnType<M>;
|
|
56
|
+
|
|
57
|
+
export type FunctionsPlusContext<
|
|
58
|
+
C,
|
|
59
|
+
O extends Record<string, (...args: any[]) => any>,
|
|
60
|
+
> = {
|
|
61
|
+
[K in keyof O]: PlusContext<C, O[K]>;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
declare class DurableKindHandleClass {
|
|
65
|
+
private descriptionTag: string;
|
|
66
|
+
}
|
|
67
|
+
export type DurableKindHandle = DurableKindHandleClass;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Grab bag of options that can be provided to `defineDurableKind` and its
|
|
71
|
+
* siblings. Not all options are meaningful in all contexts. See the
|
|
72
|
+
* doc-comments on each option.
|
|
73
|
+
*/
|
|
74
|
+
export type DefineKindOptions<C> = {
|
|
75
|
+
/**
|
|
76
|
+
* If provided, the `finish` function will be called after the instance is
|
|
77
|
+
* made and internally registered, but before it is returned. The finish
|
|
78
|
+
* function is to do any post-intantiation initialization that should be
|
|
79
|
+
* done before exposing the object to its clients.
|
|
80
|
+
*/
|
|
81
|
+
finish?: (context: C) => void;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* If provided, it describes the shape of all state records of instances
|
|
85
|
+
* of this kind.
|
|
86
|
+
*/
|
|
87
|
+
stateShape?: StateShape;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* If a `receiveAmplifier` function is provided to an exo class kit definition,
|
|
91
|
+
* it will be called with an `Amplify` function. If provided to the definition
|
|
92
|
+
* of a normal exo or exo class, the definition will throw, since only
|
|
93
|
+
* exo kits can be amplified.
|
|
94
|
+
* An `Amplify` function is a function that takes a facet instance of
|
|
95
|
+
* this class kit as an argument, in which case it will return the facets
|
|
96
|
+
* record, giving access to all the facet instances of the same cohort.
|
|
97
|
+
*/
|
|
98
|
+
receiveAmplifier?: ReceivePower<Amplify>;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* If a `receiveInstanceTester` function is provided, it will be called
|
|
102
|
+
* during the definition of the exo class or exo class kit with an
|
|
103
|
+
* `IsInstance` function. The first argument of `IsInstance`
|
|
104
|
+
* is the value to be tested. When it may be a facet instance of an
|
|
105
|
+
* exo class kit, the optional second argument, if provided, is
|
|
106
|
+
* a `facetName`. In that case, the function tests only if the first
|
|
107
|
+
* argument is an instance of that facet of the associated exo class kit.
|
|
108
|
+
*/
|
|
109
|
+
receiveInstanceTester?: ReceivePower<IsInstance>;
|
|
110
|
+
|
|
111
|
+
// TODO properties above are identical to those in FarClassOptions.
|
|
112
|
+
// These are the only options that should be exposed by
|
|
113
|
+
// vat-data's public virtual/durable exo APIs. This DefineKindOptions
|
|
114
|
+
// should explicitly be a subtype, where the methods below are only for
|
|
115
|
+
// internal use, i.e., below the exo level.
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* As a kind option, intended for internal use only.
|
|
119
|
+
* Meaningful to `makeScalarBigMapStore` and its siblings. These maker
|
|
120
|
+
* fuctions will make either virtual or durable stores, depending on
|
|
121
|
+
* this flag. Defaults to off, making virtual but not durable collections.
|
|
122
|
+
*
|
|
123
|
+
* Generally, durable collections are provided with `provideDurableMapStore`
|
|
124
|
+
* and its sibling, which use this flag internally. If you do not make
|
|
125
|
+
* durable collections by other means, you can consider this as
|
|
126
|
+
* intended for internal use only.
|
|
127
|
+
*/
|
|
128
|
+
durable?: boolean;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Intended for internal use only.
|
|
132
|
+
* Should the raw methods receive their `context` argument as their first
|
|
133
|
+
* argument or as their `this` binding? For `defineDurableKind` and its
|
|
134
|
+
* siblings (including `prepareSingleton`), this defaults to off, meaning that
|
|
135
|
+
* their behavior methods receive `context` as their first argument.
|
|
136
|
+
* `prepareExoClass` and its siblings (including `prepareExo`) use
|
|
137
|
+
* this flag internally to indicate that their methods receive `context`
|
|
138
|
+
* as their `this` binding.
|
|
139
|
+
*/
|
|
140
|
+
thisfulMethods?: boolean;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Intended for internal use only.
|
|
144
|
+
* Only applicable if this is a class kind. A class kit kind should use
|
|
145
|
+
* `interfaceGuardKit` instead.
|
|
146
|
+
*
|
|
147
|
+
* If an `interfaceGuard` is provided, then the raw methods passed alongside
|
|
148
|
+
* it are wrapped by a function that first checks that this method's guard
|
|
149
|
+
* pattern is satisfied before calling the raw method.
|
|
150
|
+
*
|
|
151
|
+
* In `defineDurableKind` and its siblings, this defaults to `undefined`.
|
|
152
|
+
* Exo classes use this internally to protect their raw class methods
|
|
153
|
+
* using the provided interface.
|
|
154
|
+
* In absence, an exo is protected anyway, while a bare kind is
|
|
155
|
+
* not (detected by `!thisfulMethods`),
|
|
156
|
+
*/
|
|
157
|
+
interfaceGuard?: InterfaceGuard;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Intended for internal use only.
|
|
161
|
+
* Only applicable if this is a class kit kind. A class kind should use
|
|
162
|
+
* `interfaceGuard` instead.
|
|
163
|
+
*
|
|
164
|
+
* If an `interfaceGuardKit` is provided, then each member of the
|
|
165
|
+
* interfaceGuardKit is used to guard the corresponding facet of the
|
|
166
|
+
* class kit.
|
|
167
|
+
*
|
|
168
|
+
* In `defineDurableKindMulti` and its siblings, this defaults to `undefined`.
|
|
169
|
+
* Exo class kits use this internally to protect their facets.
|
|
170
|
+
* In absence, an exo is protected anyway, while a bare kind is
|
|
171
|
+
* not (detected by `!thisfulMethods`),
|
|
172
|
+
*/
|
|
173
|
+
interfaceGuardKit?: InterfaceGuardKit;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export type VatData = {
|
|
177
|
+
// virtual kinds
|
|
178
|
+
/** @deprecated Use defineVirtualExoClass instead */
|
|
179
|
+
defineKind: <P extends Array<any>, S, F>(
|
|
180
|
+
tag: string,
|
|
181
|
+
init: (...args: P) => S,
|
|
182
|
+
facet: F,
|
|
183
|
+
options?: DefineKindOptions<KindContext<S, F>>,
|
|
184
|
+
) => (...args: P) => KindFacet<F>;
|
|
185
|
+
|
|
186
|
+
/** @deprecated Use defineVirtualExoClassKit instead */
|
|
187
|
+
defineKindMulti: <P extends Array<any>, S, B>(
|
|
188
|
+
tag: string,
|
|
189
|
+
init: (...args: P) => S,
|
|
190
|
+
behavior: B,
|
|
191
|
+
options?: DefineKindOptions<MultiKindContext<S, B>>,
|
|
192
|
+
) => (...args: P) => KindFacets<B>;
|
|
193
|
+
|
|
194
|
+
// durable kinds
|
|
195
|
+
makeKindHandle: (descriptionTag: string) => DurableKindHandle;
|
|
196
|
+
|
|
197
|
+
/** @deprecated Use defineDurableExoClass instead */
|
|
198
|
+
defineDurableKind: <P extends Array<any>, S, F>(
|
|
199
|
+
kindHandle: DurableKindHandle,
|
|
200
|
+
init: (...args: P) => S,
|
|
201
|
+
facet: F,
|
|
202
|
+
options?: DefineKindOptions<KindContext<S, F>>,
|
|
203
|
+
) => (...args: P) => KindFacet<F>;
|
|
204
|
+
|
|
205
|
+
/** @deprecated Use defineDurableExoClassKit instead */
|
|
206
|
+
defineDurableKindMulti: <P extends Array<any>, S, B>(
|
|
207
|
+
kindHandle: DurableKindHandle,
|
|
208
|
+
init: (...args: P) => S,
|
|
209
|
+
behavior: B,
|
|
210
|
+
options?: DefineKindOptions<MultiKindContext<S, B>>,
|
|
211
|
+
) => (...args: P) => KindFacets<B>;
|
|
212
|
+
|
|
213
|
+
providePromiseWatcher: WatchedPromisesManager['providePromiseWatcher'];
|
|
214
|
+
watchPromise: WatchedPromisesManager['watchPromise'];
|
|
215
|
+
|
|
216
|
+
makeScalarBigMapStore: <K, V>(
|
|
217
|
+
label: string,
|
|
218
|
+
options?: StoreOptions,
|
|
219
|
+
) => MapStore<K, V>;
|
|
220
|
+
makeScalarBigWeakMapStore: <K, V>(
|
|
221
|
+
label: string,
|
|
222
|
+
options?: StoreOptions,
|
|
223
|
+
) => WeakMapStore<K, V>;
|
|
224
|
+
|
|
225
|
+
makeScalarBigSetStore: <K>(
|
|
226
|
+
label: string,
|
|
227
|
+
options?: StoreOptions,
|
|
228
|
+
) => SetStore<K>;
|
|
229
|
+
makeScalarBigWeakSetStore: <K>(
|
|
230
|
+
label: string,
|
|
231
|
+
options?: StoreOptions,
|
|
232
|
+
) => WeakSetStore<K>;
|
|
233
|
+
canBeDurable: (specimen: unknown) => boolean;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// The JSDoc is repeated here and at the function definition so it appears
|
|
237
|
+
// in IDEs where it's used, regardless of type resolution.
|
|
238
|
+
export interface PickFacet {
|
|
239
|
+
/**
|
|
240
|
+
* When making a multi-facet kind, it's common to pick one facet to
|
|
241
|
+
* expose. E.g.,
|
|
242
|
+
*
|
|
243
|
+
* const makeFoo = (a, b, c, d) => makeFooBase(a, b, c, d).self;
|
|
244
|
+
*
|
|
245
|
+
* This helper reduces the duplication:
|
|
246
|
+
*
|
|
247
|
+
* const makeFoo = pickFacet(makeFooBase, 'self');
|
|
248
|
+
*/
|
|
249
|
+
<M extends (...args: any[]) => any, F extends keyof ReturnType<M>>(
|
|
250
|
+
maker: M,
|
|
251
|
+
facetName: F,
|
|
252
|
+
): (...args: Parameters<M>) => ReturnType<M>[F];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** @deprecated Use prepareExoClass instead */
|
|
256
|
+
export type PrepareKind = <P extends Array<any>, S, F>(
|
|
257
|
+
baggage: Baggage,
|
|
258
|
+
tag: string,
|
|
259
|
+
init: (...args: P) => S,
|
|
260
|
+
facet: F,
|
|
261
|
+
options?: DefineKindOptions<KindContext<S, F>>,
|
|
262
|
+
) => (...args: P) => KindFacet<F>;
|
|
263
|
+
|
|
264
|
+
/** @deprecated Use prepareExoClassKit instead */
|
|
265
|
+
export type PrepareKindMulti = <P extends Array<any>, S, B>(
|
|
266
|
+
baggage: Baggage,
|
|
267
|
+
tag: string,
|
|
268
|
+
init: (...args: P) => S,
|
|
269
|
+
behavior: B,
|
|
270
|
+
options?: DefineKindOptions<MultiKindContext<S, B>>,
|
|
271
|
+
) => (...args: P) => KindFacets<B>;
|
|
@@ -18,6 +18,7 @@ export function* enumerateKeysStartEnd(syscall, start, end, checkF) {
|
|
|
18
18
|
dbKey = syscall.vatstoreGetNextKey(dbKey);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
harden(enumerateKeysStartEnd);
|
|
21
22
|
|
|
22
23
|
// return an iterator of all existing keys that start with 'prefix'
|
|
23
24
|
// (excluding the prefix itself)
|
|
@@ -32,6 +33,7 @@ export function* enumerateKeysWithPrefix(syscall, prefix) {
|
|
|
32
33
|
yield key;
|
|
33
34
|
}
|
|
34
35
|
}
|
|
36
|
+
harden(enumerateKeysWithPrefix);
|
|
35
37
|
|
|
36
38
|
export function prefixedKeysExist(syscall, prefix) {
|
|
37
39
|
const nextKey = syscall.vatstoreGetNextKey(prefix);
|