@agoric/internal 0.4.0 → 0.4.1-upgrade-23-dev-bd79330.0.bd79330

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.
Files changed (131) hide show
  1. package/README.md +1 -4
  2. package/package.json +13 -11
  3. package/src/action-types.d.ts +47 -20
  4. package/src/action-types.d.ts.map +1 -1
  5. package/src/action-types.js +19 -19
  6. package/src/ava-force-exit.d.mts +2 -0
  7. package/src/ava-force-exit.d.mts.map +1 -0
  8. package/src/ava-force-exit.mjs +6 -0
  9. package/src/batched-deliver.d.ts +6 -2
  10. package/src/batched-deliver.d.ts.map +1 -1
  11. package/src/batched-deliver.js +7 -3
  12. package/src/build-cache-types.d.ts +33 -0
  13. package/src/build-cache-types.d.ts.map +1 -0
  14. package/src/build-cache-types.js +42 -0
  15. package/src/build-cache.d.ts +12 -0
  16. package/src/build-cache.d.ts.map +1 -0
  17. package/src/build-cache.js +184 -0
  18. package/src/callback.d.ts +9 -11
  19. package/src/callback.d.ts.map +1 -1
  20. package/src/callback.js +16 -10
  21. package/src/chain-storage-paths.d.ts.map +1 -1
  22. package/src/chain-storage-paths.js +0 -2
  23. package/src/chain-utils.d.ts +3 -1
  24. package/src/chain-utils.d.ts.map +1 -1
  25. package/src/chain-utils.js +6 -1
  26. package/src/config.d.ts +22 -3
  27. package/src/config.d.ts.map +1 -1
  28. package/src/config.js +25 -3
  29. package/src/debug.d.ts +4 -1
  30. package/src/debug.d.ts.map +1 -1
  31. package/src/debug.js +26 -15
  32. package/src/index.d.ts +2 -1
  33. package/src/index.js +10 -3
  34. package/src/js-utils.d.ts +7 -3
  35. package/src/js-utils.d.ts.map +1 -1
  36. package/src/js-utils.js +24 -3
  37. package/src/keyMirror.d.ts +3 -0
  38. package/src/keyMirror.d.ts.map +1 -0
  39. package/src/keyMirror.js +45 -0
  40. package/src/kv-store.d.ts +33 -0
  41. package/src/kv-store.d.ts.map +1 -0
  42. package/src/kv-store.js +257 -0
  43. package/src/lib-chainStorage.d.ts +23 -12
  44. package/src/lib-chainStorage.d.ts.map +1 -1
  45. package/src/lib-chainStorage.js +18 -18
  46. package/src/lib-nodejs/ava-unhandled-rejection.d.ts +18 -3
  47. package/src/lib-nodejs/ava-unhandled-rejection.d.ts.map +1 -1
  48. package/src/lib-nodejs/ava-unhandled-rejection.js +211 -20
  49. package/src/lib-nodejs/engine-gc.js +2 -2
  50. package/src/lib-nodejs/spawnSubprocessWorker.d.ts +0 -2
  51. package/src/lib-nodejs/spawnSubprocessWorker.d.ts.map +1 -1
  52. package/src/lib-nodejs/spawnSubprocessWorker.js +8 -7
  53. package/src/lib-nodejs/waitUntilQuiescent.d.ts +3 -0
  54. package/src/lib-nodejs/waitUntilQuiescent.d.ts.map +1 -1
  55. package/src/lib-nodejs/waitUntilQuiescent.js +5 -1
  56. package/src/lib-nodejs/worker-protocol.d.ts +1 -1
  57. package/src/lib-nodejs/worker-protocol.d.ts.map +1 -1
  58. package/src/lib-nodejs/worker-protocol.js +5 -5
  59. package/src/magic-cookie-test-only.d.ts.map +1 -1
  60. package/src/magic-cookie-test-only.js +0 -2
  61. package/src/marshal/board-client-utils.d.ts +19 -0
  62. package/src/marshal/board-client-utils.d.ts.map +1 -0
  63. package/src/{marshal.js → marshal/board-client-utils.js} +27 -52
  64. package/src/marshal/cap-data.d.ts +11 -0
  65. package/src/marshal/cap-data.d.ts.map +1 -0
  66. package/src/marshal/cap-data.js +19 -0
  67. package/src/marshal/inaccessible-val.d.ts +2 -0
  68. package/src/marshal/inaccessible-val.d.ts.map +1 -0
  69. package/src/marshal/inaccessible-val.js +15 -0
  70. package/src/marshal/pure-data.d.ts +8 -0
  71. package/src/marshal/pure-data.d.ts.map +1 -0
  72. package/src/marshal/pure-data.js +14 -0
  73. package/src/marshal/wrap-marshaller.d.ts +60 -0
  74. package/src/marshal/wrap-marshaller.d.ts.map +1 -0
  75. package/src/marshal/wrap-marshaller.js +432 -0
  76. package/src/module-utils.d.ts +1 -0
  77. package/src/module-utils.d.ts.map +1 -1
  78. package/src/module-utils.js +16 -0
  79. package/src/natural-sort.d.ts.map +1 -1
  80. package/src/natural-sort.js +48 -13
  81. package/src/netstring.d.ts +1 -1
  82. package/src/netstring.d.ts.map +1 -1
  83. package/src/netstring.js +5 -5
  84. package/src/node/buffer-line-transform.d.ts +10 -5
  85. package/src/node/buffer-line-transform.d.ts.map +1 -1
  86. package/src/node/buffer-line-transform.js +8 -4
  87. package/src/node/createBundles.d.ts.map +1 -1
  88. package/src/node/createBundles.js +3 -5
  89. package/src/node/fs-stream.d.ts +4 -1
  90. package/src/node/fs-stream.d.ts.map +1 -1
  91. package/src/node/fs-stream.js +58 -9
  92. package/src/node/read-json.d.ts +2 -0
  93. package/src/node/read-json.d.ts.map +1 -0
  94. package/src/node/read-json.js +18 -0
  95. package/src/node/shutdown.js +1 -1
  96. package/src/priority-senders.d.ts +2 -1
  97. package/src/priority-senders.d.ts.map +1 -1
  98. package/src/priority-senders.js +6 -4
  99. package/src/queue.d.ts.map +1 -1
  100. package/src/queue.js +0 -2
  101. package/src/ses-utils.d.ts +27 -5
  102. package/src/ses-utils.d.ts.map +1 -1
  103. package/src/ses-utils.js +115 -20
  104. package/src/storage-test-utils.d.ts +15 -5
  105. package/src/storage-test-utils.d.ts.map +1 -1
  106. package/src/storage-test-utils.js +62 -8
  107. package/src/tagged.d.ts +18 -1
  108. package/src/testing-utils.d.ts +4 -0
  109. package/src/testing-utils.d.ts.map +1 -1
  110. package/src/testing-utils.js +88 -2
  111. package/src/typeGuards.d.ts +6 -2
  112. package/src/typeGuards.d.ts.map +1 -1
  113. package/src/typeGuards.js +7 -4
  114. package/src/types-index.d.ts +1 -0
  115. package/src/types.d.ts +34 -19
  116. package/src/types.d.ts.map +1 -1
  117. package/src/types.js +173 -0
  118. package/src/upgrade-api.d.ts.map +1 -1
  119. package/src/upgrade-api.js +4 -3
  120. package/src/work-pool.d.ts +13 -0
  121. package/src/work-pool.d.ts.map +1 -0
  122. package/src/work-pool.js +233 -0
  123. package/vendor/anylogger.d.ts +98 -0
  124. package/vendor/anylogger.d.ts.map +1 -0
  125. package/vendor/anylogger.js +60 -0
  126. package/vendor/anylogger.ts +160 -0
  127. package/vendor/tsconfig.anylogger.json +15 -0
  128. package/exported.js +0 -2
  129. package/src/marshal.d.ts +0 -33
  130. package/src/marshal.d.ts.map +0 -1
  131. package/src/types.ts +0 -129
@@ -0,0 +1,60 @@
1
+ export function wrapRemoteMarshallerSendSlotsOnly<Slot = unknown>(marshaller: ERemote<Pick<EMarshaller<Slot>, "fromCapData" | "toCapData">>, { serializeBodyFormat, errorTagging, ...otherMarshalOptions }?: MakeMarshalOptions, { valToSlot, slotToVal, cacheSeveredVal, }?: {
2
+ valToSlot?: WeakMapAPI<any, Slot> | null | undefined;
3
+ slotToVal?: WeakMapAPI<Slot, any> | null | undefined;
4
+ cacheSeveredVal?: boolean | undefined;
5
+ }): ReturnType<typeof Far<EMarshaller<Slot>>>;
6
+ export function wrapRemoteMarshallerDirectSend<Slot = unknown>(marshaller: ERemote<Pick<EMarshaller<Slot>, "fromCapData" | "toCapData">>): ReturnType<typeof Far<EMarshaller<Slot>>>;
7
+ export function wrapRemoteMarshaller<Slot = unknown>(marshaller: ERemote<Pick<EMarshaller<Slot>, "fromCapData" | "toCapData">>, { serializeBodyFormat, errorTagging, ...otherMarshalOptions }?: MakeMarshalOptions, { valToSlot, slotToVal, cacheSeveredVal, }?: {
8
+ valToSlot?: WeakMapAPI<any, Slot> | null | undefined;
9
+ slotToVal?: WeakMapAPI<Slot, any> | null | undefined;
10
+ cacheSeveredVal?: boolean | undefined;
11
+ }): ReturnType<typeof Far<EMarshaller<Slot>>>;
12
+ /**
13
+ * A Marshaller which methods may be async. Use this type to indicate accepting
14
+ * either a sync or async marshaller, usually through `E` eventual-sends.
15
+ */
16
+ export type EMarshaller<Slot = unknown> = Simplify<EOnly<Marshal<Slot>>>;
17
+ export type InterfaceSpec = "Remotable" | `Alleged: ${string}`;
18
+ export type RemotableSlotWrapper<Slot = unknown> = SlotWrapper<Slot> & PassStyled<"remotable", InterfaceSpec>;
19
+ import type { ERemote } from '../types.js';
20
+ import type { MakeMarshalOptions } from '@endo/marshal';
21
+ import type { WeakMapAPI } from '@endo/cache-map';
22
+ import { Far } from '@endo/far';
23
+ import type { Marshal } from '@endo/marshal';
24
+ import type { EOnly } from '@endo/eventual-send';
25
+ import type { Simplify } from '@endo/pass-style';
26
+ /**
27
+ * @import {WeakMapAPI} from '@endo/cache-map';
28
+ * @import {EOnly} from '@endo/eventual-send';
29
+ * @import {PassStyled, Simplify} from '@endo/pass-style';
30
+ * @import {CapData, Passable, Marshal, MakeMarshalOptions} from '@endo/marshal';
31
+ * @import {ERemote} from '../types.js';
32
+ */
33
+ /**
34
+ * A Marshaller which methods may be async. Use this type to indicate accepting
35
+ * either a sync or async marshaller, usually through `E` eventual-sends.
36
+ *
37
+ * @template [Slot=unknown]
38
+ * @typedef {Simplify<EOnly<Marshal<Slot>>>} EMarshaller
39
+ */
40
+ /** @typedef {'Remotable' | `Alleged: ${string}`} InterfaceSpec */
41
+ /** @template [Slot=unknown] */
42
+ declare class SlotWrapper<Slot = unknown> {
43
+ /**
44
+ * @template [Slot=unknown]
45
+ * @param {SlotWrapper<Slot>} wrapper
46
+ * @returns {Slot}
47
+ */
48
+ static getSlot<Slot_1 = unknown>(wrapper: SlotWrapper<Slot_1>): Slot_1;
49
+ /**
50
+ * @param {Slot} slot
51
+ * @param {string} [iface]
52
+ */
53
+ constructor(slot: Slot, iface?: string);
54
+ /** @type {InterfaceSpec} */
55
+ [Symbol.toStringTag]: InterfaceSpec;
56
+ #private;
57
+ }
58
+ import type { PassStyled } from '@endo/pass-style';
59
+ export {};
60
+ //# sourceMappingURL=wrap-marshaller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap-marshaller.d.ts","sourceRoot":"","sources":["wrap-marshaller.js"],"names":[],"mappings":"AAqHO,kDATO,IAAI,wBACP,QAAQ,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,WAAW,CAAC,CAAC,kEAC7D,kBAAkB,+CAE1B;IAAiD,SAAS;IACT,SAAS;IACjC,eAAe;CACxC,GAAU,UAAU,CAAC,OAAO,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CA4RrD;AAOM,+CAJO,IAAI,wBACP,QAAQ,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,WAAW,CAAC,CAAC,GAC3D,UAAU,CAAC,OAAO,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAyBrD;AAxTM,qCATO,IAAI,wBACP,QAAQ,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,WAAW,CAAC,CAAC,kEAC7D,kBAAkB,+CAE1B;IAAiD,SAAS;IACT,SAAS;IACjC,eAAe;CACxC,GAAU,UAAU,CAAC,OAAO,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CA4RrD;;;;;wBA1Xa,IAAI,cACL,SAAS,MAAM,QAAQ,IAAI,CAAC,CAAC,CAAC;4BAG7B,WAAW,GAAG,YAAY,MAAM,EAAE;iCAyClC,IAAI,cACL,WAAW,CAAC,IAAI,CAAC,GAAG,WAAW,WAAW,EAAE,aAAa,CAAC;6BArD7C,aAAa;wCAD0B,eAAe;gCAHnD,iBAAiB;oBAN1B,WAAW;6BASkC,eAAe;2BAFxD,qBAAqB;8BACN,kBAAkB;AAHzD;;;;;;GAMG;AAEH;;;;;;GAMG;AAEH,kEAAkE;AAElE,+BAA+B;AAC/B,0BADe,IAAI;IAsBjB;;;;OAIG;IACH,0CAHW,WAAW,CAAC,MAAI,CAAC,GACf,MAAI,CAIhB;IArBD;;;OAGG;IACH,kBAHW,IAAI,UACJ,MAAM,EAUhB;IAfD,4BAA4B;IAC5B,sBADW,aAAa,CACsB;;CAwB/C;gCA7CsC,kBAAkB"}
@@ -0,0 +1,432 @@
1
+ // @ts-check
2
+ import { makeCacheMapKit } from '@endo/cache-map';
3
+ import { Fail, q } from '@endo/errors';
4
+ import { E } from '@endo/eventual-send';
5
+ import { Far } from '@endo/far';
6
+ import { PASS_STYLE } from '@endo/pass-style';
7
+ import { makeMarshal } from '@endo/marshal';
8
+ import { makeInaccessibleVal } from './inaccessible-val.js';
9
+
10
+ /**
11
+ * @import {WeakMapAPI} from '@endo/cache-map';
12
+ * @import {EOnly} from '@endo/eventual-send';
13
+ * @import {PassStyled, Simplify} from '@endo/pass-style';
14
+ * @import {CapData, Passable, Marshal, MakeMarshalOptions} from '@endo/marshal';
15
+ * @import {ERemote} from '../types.js';
16
+ */
17
+
18
+ /**
19
+ * A Marshaller which methods may be async. Use this type to indicate accepting
20
+ * either a sync or async marshaller, usually through `E` eventual-sends.
21
+ *
22
+ * @template [Slot=unknown]
23
+ * @typedef {Simplify<EOnly<Marshal<Slot>>>} EMarshaller
24
+ */
25
+
26
+ /** @typedef {'Remotable' | `Alleged: ${string}`} InterfaceSpec */
27
+
28
+ /** @template [Slot=unknown] */
29
+ class SlotWrapper {
30
+ /** @type {Slot} */
31
+ #slot;
32
+
33
+ /** @type {InterfaceSpec} */
34
+ [Symbol.toStringTag] = 'Alleged: SlotWrapper';
35
+
36
+ /**
37
+ * @param {Slot} slot
38
+ * @param {string} [iface]
39
+ */
40
+ constructor(slot, iface) {
41
+ if (iface == null || iface === 'Remotable') {
42
+ iface = 'Remotable';
43
+ } else if (!iface.startsWith('Alleged: ')) {
44
+ iface = `Alleged: ${iface}`;
45
+ }
46
+ this.#slot = slot;
47
+ this[Symbol.toStringTag] = /** @type {InterfaceSpec} */ (iface);
48
+ }
49
+
50
+ /**
51
+ * @template [Slot=unknown]
52
+ * @param {SlotWrapper<Slot>} wrapper
53
+ * @returns {Slot}
54
+ */
55
+ static getSlot(wrapper) {
56
+ return wrapper.#slot;
57
+ }
58
+ }
59
+ Object.defineProperties(SlotWrapper.prototype, {
60
+ [PASS_STYLE]: { value: 'remotable' },
61
+ [Symbol.toStringTag]: { value: 'Alleged: SlotWrapper' },
62
+ });
63
+ Reflect.deleteProperty(SlotWrapper.prototype, 'constructor');
64
+ harden(SlotWrapper);
65
+
66
+ /**
67
+ * @template [Slot=unknown]
68
+ * @typedef {SlotWrapper<Slot> & PassStyled<'remotable', InterfaceSpec>} RemotableSlotWrapper
69
+ */
70
+
71
+ /**
72
+ * @template [Slot=unknown]
73
+ * @param {Slot} slot
74
+ * @param {string} [iface]
75
+ */
76
+ const slotToWrapper = (slot, iface) =>
77
+ /** @type {RemotableSlotWrapper<Slot>} */ (
78
+ harden(new SlotWrapper(slot, iface))
79
+ );
80
+
81
+ const wrapperToSlot = SlotWrapper.getSlot;
82
+
83
+ const capacityOfDefaultCache = 50;
84
+
85
+ // TODO(https://github.com/Agoric/agoric-sdk/issues/12111)
86
+ // Check cost of using virtual-aware WeakMap in liveslots
87
+ /**
88
+ * @template K
89
+ * @template V
90
+ * @param {boolean} [weakKey]
91
+ */
92
+ const makeDefaultCacheMap = weakKey =>
93
+ /** @type {WeakMapAPI<K, V>} */ (
94
+ makeCacheMapKit(capacityOfDefaultCache, {
95
+ makeMap: weakKey ? WeakMap : Map,
96
+ }).cache
97
+ );
98
+
99
+ /**
100
+ * Wraps a marshaller, either sync or async, local or remote, into a local async
101
+ * marshaller which only sends slots for resolution to the wrapped marshaller.
102
+ * Optionally and by default, caches the resolution of slots.
103
+ *
104
+ * Assumes that a null-ish slot value is a severed presence that can be resolved
105
+ * locally. By default if a presence is mapped to a null-ish slot by the wrapped
106
+ * marshaller, that mapping is not cached, allowing the wrapped marshaller to
107
+ * create a mapping in the future.
108
+ *
109
+ * @template [Slot=unknown]
110
+ * @param {ERemote<Pick<EMarshaller<Slot>, 'fromCapData' | 'toCapData'>>} marshaller
111
+ * @param {MakeMarshalOptions} [marshalOptions]
112
+ * @param {object} [caches]
113
+ * @param {WeakMapAPI<object, Slot> | null} [caches.valToSlot]
114
+ * @param {WeakMapAPI<Slot, object> | null} [caches.slotToVal]
115
+ * @param {boolean} [caches.cacheSeveredVal]
116
+ * @returns {ReturnType<typeof Far<EMarshaller<Slot>>>}
117
+ */
118
+ export const wrapRemoteMarshallerSendSlotsOnly = (
119
+ marshaller,
120
+ {
121
+ serializeBodyFormat = 'smallcaps',
122
+ errorTagging = 'off', // Disable error tagging by default
123
+ ...otherMarshalOptions
124
+ } = {},
125
+ {
126
+ valToSlot = makeDefaultCacheMap(true),
127
+ slotToVal = makeDefaultCacheMap(false),
128
+ cacheSeveredVal = false,
129
+ } = {},
130
+ ) => {
131
+ const marshalOptions = harden({
132
+ serializeBodyFormat,
133
+ errorTagging,
134
+ ...otherMarshalOptions,
135
+ });
136
+ // The implementation of this wrapped marshaller internally uses 2 marshallers
137
+ // to transform the CapData into a Passable structure and vice-versa:
138
+ // - A cap pass-through marshaller which places capabilities as-is in the slots.
139
+ // When unserializing CapData with null-ish slots, a severed presence is created.
140
+ // This pass-through marshaller is used to locally process the structure, and
141
+ // separate capabilities into a slots array for potential resolution by the
142
+ // wrapped marshaller.
143
+ // - A "SlotWrapper" marshaller used to wrap into remotables the slots of the
144
+ // wrapped marshaller. When unserializing CapData, it is used to recreate
145
+ // CapData of a simple array of non-severed capabilities for resolution by
146
+ // the wrapped marshaller. When serializing to CapData, it allows extracting
147
+ // the slots from the capabilities array serialized by the wrapped marshaller.
148
+
149
+ /** @type {Marshal<object | null>} */
150
+ const passThroughMarshaller = makeMarshal(
151
+ undefined,
152
+ (slot, iface) => slot ?? makeInaccessibleVal(iface),
153
+ marshalOptions,
154
+ );
155
+
156
+ /** @type {Map<Slot, RemotableSlotWrapper<NonNullable<Slot>>>} */
157
+ const currentSlotToWrapper = new Map();
158
+
159
+ const convertWrapperToSlot = /** @type {typeof wrapperToSlot<Slot>} */ (
160
+ wrapperToSlot
161
+ );
162
+ /**
163
+ * @param {Slot} slot
164
+ * @param {string | undefined} [iface]
165
+ */
166
+ const convertSlotToWrapper = (slot, iface) => {
167
+ if (slot == null) {
168
+ // The wrapped marshaller may send us CapData with a null slot. These are not
169
+ // meant to be considered equivalent with each other, so bypass mapping.
170
+ return slotToWrapper(slot, iface);
171
+ }
172
+ let wrapper = currentSlotToWrapper.get(slot);
173
+ if (!wrapper) {
174
+ wrapper = slotToWrapper(slot, iface);
175
+ currentSlotToWrapper.set(slot, wrapper);
176
+ }
177
+
178
+ return wrapper;
179
+ };
180
+
181
+ /** @type {Pick<Marshal<Slot>, 'toCapData' | 'fromCapData'>} */
182
+ const slotWrapperMarshaller = makeMarshal(
183
+ convertWrapperToSlot,
184
+ convertSlotToWrapper,
185
+ marshalOptions,
186
+ );
187
+
188
+ /**
189
+ * Resolves an array of wrapped marshaller's slots to an array of
190
+ * capabilities.
191
+ *
192
+ * This is used by `fromCapData` to map slots before using the pass-through
193
+ * marshaller to recreate the passable data.
194
+ *
195
+ * @param {Slot[]} slots
196
+ * @param {(index: number) => RemotableSlotWrapper<NonNullable<Slot>>} getWrapper
197
+ * @returns {Promise<(object | null)[]>}
198
+ */
199
+ const mapSlotsToCaps = async (slots, getWrapper) => {
200
+ let hasRemoteCap = false;
201
+ const { length } = slots;
202
+ /** @type {(RemotableSlotWrapper<NonNullable<Slot>> | null | undefined)[]} */
203
+ const slotWrapperMappedSlots = Array.from({ length });
204
+ /** @type {(object | null | undefined)[]} */
205
+ const locallyResolvedCapSlots = Array.from({ length });
206
+
207
+ for (const [index, slot] of slots.entries()) {
208
+ if (slot === null) {
209
+ const nullSlot = /** @type {null} */ (slot);
210
+ slotWrapperMappedSlots[index] = nullSlot;
211
+ locallyResolvedCapSlots[index] = nullSlot;
212
+ } else if (slot !== undefined) {
213
+ const cachedCap = slotToVal?.get(slot);
214
+ if (cachedCap !== undefined) {
215
+ valToSlot?.set(cachedCap, slot);
216
+ locallyResolvedCapSlots[index] = cachedCap;
217
+ } else {
218
+ hasRemoteCap = true;
219
+ slotWrapperMappedSlots[index] = getWrapper(index);
220
+ }
221
+ }
222
+ }
223
+
224
+ await null;
225
+ if (hasRemoteCap) {
226
+ harden(slotWrapperMappedSlots);
227
+ const slotsOnlyCapData = slotWrapperMarshaller.toCapData(
228
+ slotWrapperMappedSlots,
229
+ );
230
+
231
+ /** @type {(object | null | undefined)[]} */
232
+ const remotelyResolvedCapSlots =
233
+ await E(marshaller).fromCapData(slotsOnlyCapData);
234
+
235
+ for (const [index, val] of remotelyResolvedCapSlots.entries()) {
236
+ if (val != null) {
237
+ const slot = slots[index];
238
+ slotToVal?.set(slot, val);
239
+ valToSlot?.set(val, slot);
240
+ locallyResolvedCapSlots[index] = val;
241
+ } else if (locallyResolvedCapSlots[index] === undefined) {
242
+ const slot = slots[index];
243
+ console.warn('⚠️ Unresolved local slot in wrapped marshaller', {
244
+ index,
245
+ slot,
246
+ });
247
+ }
248
+ }
249
+ }
250
+
251
+ return harden(locallyResolvedCapSlots);
252
+ };
253
+
254
+ /**
255
+ * Resolves an array of capabilities into an array of slots of the wrapped
256
+ * marshaller.
257
+ *
258
+ * This is used by `toCapData` to map slots after the pass-through marshaller
259
+ * has serialized the passable data.
260
+ *
261
+ * @param {object[]} caps
262
+ * @returns {Promise<Slot[]>}
263
+ */
264
+ const mapCapsToSlots = async caps => {
265
+ if (caps.length === 0) {
266
+ return caps;
267
+ }
268
+ let hasRemoteCap = false;
269
+ const { length } = caps;
270
+ /** @type {(Slot | null | undefined)[]} */
271
+ const locallyResolvedSlots = Array.from({ length });
272
+ /** @type {(object | null | undefined)[]} */
273
+ const remoteCapsToResolve = Array.from({ length });
274
+
275
+ for (const [index, cap] of caps.entries()) {
276
+ if (cap === null) {
277
+ // We shouldn't get null caps here, but we mirror handle them anyway
278
+ const nullCap = /** @type {null} */ (cap);
279
+ remoteCapsToResolve[index] = nullCap;
280
+ locallyResolvedSlots[index] = nullCap;
281
+ } else if (cap !== undefined) {
282
+ const cachedSlot = valToSlot?.get(cap);
283
+ if (cachedSlot !== undefined) {
284
+ if (cachedSlot !== null) {
285
+ slotToVal?.set(cachedSlot, cap);
286
+ }
287
+ locallyResolvedSlots[index] = cachedSlot;
288
+ } else {
289
+ hasRemoteCap = true;
290
+ remoteCapsToResolve[index] = cap;
291
+ }
292
+ }
293
+ }
294
+
295
+ await null;
296
+ if (hasRemoteCap) {
297
+ const remotelyResolvedSlotsCapData =
298
+ await E(marshaller).toCapData(remoteCapsToResolve);
299
+ try {
300
+ /** @type {(RemotableSlotWrapper<Slot> | null | undefined)[]} */
301
+ const slotWrapperMappedSlots = slotWrapperMarshaller.fromCapData(
302
+ remotelyResolvedSlotsCapData,
303
+ );
304
+ for (const [index, slotWrapper] of slotWrapperMappedSlots.entries()) {
305
+ if (slotWrapper != null) {
306
+ const slot = convertWrapperToSlot(slotWrapper);
307
+ const val = caps[index];
308
+ locallyResolvedSlots[index] = slot;
309
+ if (slot != null) {
310
+ slotToVal?.set(slot, val);
311
+ }
312
+ if (slot != null || cacheSeveredVal) {
313
+ valToSlot?.set(val, slot);
314
+ }
315
+ } else if (locallyResolvedSlots[index] === undefined) {
316
+ const cap = caps[index];
317
+ console.warn('⚠️ Unresolved local slot in wrapped marshaller', {
318
+ index,
319
+ cap,
320
+ });
321
+ }
322
+ }
323
+ } finally {
324
+ // We're done with the slotWrapperMarshaller, clear its state
325
+ currentSlotToWrapper.clear();
326
+ }
327
+ }
328
+
329
+ // All slots should have been resolved by now (or warned about)
330
+ return /** @type {Slot[]} */ (harden(locallyResolvedSlots));
331
+ };
332
+
333
+ /**
334
+ * Unfortunately CapData only contains iface information for slotted
335
+ * capabilities nested inside the body, which means we need to process the
336
+ * body to extract it. Maybe in the future CapData could be extended to carry
337
+ * this separately. See https://github.com/endojs/endo/issues/2991
338
+ *
339
+ * Since this helper is used internally to ultimately provide SlotWrapper
340
+ * objects to the corresponding marshaller, and that we use the same
341
+ * marshaller to extract the iface information, directly return the full
342
+ * SlotWrapper object instead of just the iface.
343
+ *
344
+ * @param {CapData<Slot>} data
345
+ */
346
+ const makeIfaceExtractor = data => {
347
+ const { slots } = data;
348
+ /** @param {number} index */
349
+ const getWrapper = index => {
350
+ const slot = slots[index];
351
+ let wrapper = currentSlotToWrapper.get(slot);
352
+ if (!wrapper) {
353
+ void slotWrapperMarshaller.fromCapData(data);
354
+ }
355
+ wrapper = currentSlotToWrapper.get(slot);
356
+ if (!wrapper) {
357
+ throw Fail`Marshaller didn't create wrapper for slot ${q(slot)} (index=${q(index)})`;
358
+ }
359
+ return wrapper;
360
+ };
361
+
362
+ return getWrapper;
363
+ };
364
+
365
+ /**
366
+ * @param {Passable} val
367
+ * @returns {Promise<CapData<Slot>>}
368
+ */
369
+ const toCapData = async val => {
370
+ const capData = passThroughMarshaller.toCapData(val);
371
+ const mappedSlots = await mapCapsToSlots(capData.slots);
372
+ return harden({ ...capData, slots: mappedSlots });
373
+ };
374
+
375
+ /**
376
+ * @param {CapData<Slot>} data
377
+ * @returns {Promise<Passable>}
378
+ */
379
+ const fromCapData = async data => {
380
+ const getWrapper = makeIfaceExtractor(data);
381
+ await null;
382
+ try {
383
+ const mappedSlots = await mapSlotsToCaps(data.slots, getWrapper);
384
+ return passThroughMarshaller.fromCapData({ ...data, slots: mappedSlots });
385
+ } finally {
386
+ currentSlotToWrapper.clear();
387
+ }
388
+ };
389
+
390
+ return Far('wrapped remote marshaller', {
391
+ toCapData,
392
+ fromCapData,
393
+
394
+ // for backwards compatibility
395
+ /** @deprecated use toCapData */
396
+ serialize: toCapData,
397
+ /** @deprecated use fromCapData */
398
+ unserialize: fromCapData,
399
+ });
400
+ };
401
+
402
+ /**
403
+ * @template [Slot=unknown]
404
+ * @param {ERemote<Pick<EMarshaller<Slot>, 'fromCapData' | 'toCapData'>>} marshaller
405
+ * @returns {ReturnType<typeof Far<EMarshaller<Slot>>>}
406
+ */
407
+ export const wrapRemoteMarshallerDirectSend = marshaller => {
408
+ /**
409
+ * @param {Passable} val
410
+ * @returns {Promise<CapData<Slot>>}
411
+ */
412
+ const toCapData = val => E(marshaller).toCapData(val);
413
+
414
+ /**
415
+ * @param {CapData<Slot>} data
416
+ * @returns {Promise<Passable>}
417
+ */
418
+ const fromCapData = data => E(marshaller).fromCapData(data);
419
+
420
+ return Far('wrapped remote marshaller', {
421
+ toCapData,
422
+ fromCapData,
423
+
424
+ // for backwards compatibility
425
+ /** @deprecated use toCapData */
426
+ serialize: toCapData,
427
+ /** @deprecated use fromCapData */
428
+ unserialize: fromCapData,
429
+ });
430
+ };
431
+
432
+ export const wrapRemoteMarshaller = wrapRemoteMarshallerSendSlotsOnly;
@@ -1,2 +1,3 @@
1
1
  export function getSpecifier(fileUrl: string): Promise<string>;
2
+ export function resolveToPath(specifier: string, baseURL: string): string;
2
3
  //# sourceMappingURL=module-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"module-utils.d.ts","sourceRoot":"","sources":["module-utils.js"],"names":[],"mappings":"AAaO,sCAHI,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,CAc3B"}
1
+ {"version":3,"file":"module-utils.d.ts","sourceRoot":"","sources":["module-utils.js"],"names":[],"mappings":"AAcO,sCAHI,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,CAc3B;AAWM,yCAJI,MAAM,WACN,MAAM,GACJ,MAAM,CAMlB"}
@@ -1,5 +1,6 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { fileURLToPath } from 'node:url';
3
+ import { resolve as importMetaResolve } from 'import-meta-resolve';
3
4
  import { search } from '@endo/compartment-mapper';
4
5
  import { Fail } from '@endo/errors';
5
6
 
@@ -25,3 +26,18 @@ export const getSpecifier = async fileUrl => {
25
26
  return `${name}/${moduleSpecifier.replace(/^\.\//, '')}`;
26
27
  };
27
28
  harden(getSpecifier);
29
+
30
+ /**
31
+ * Given an import specifier and importer URL (usually import.meta.url), return
32
+ * a file system path corresponding with the specifier for the importer.
33
+ *
34
+ * @param {string} specifier
35
+ * @param {string} baseURL
36
+ * @returns {string}
37
+ */
38
+ export const resolveToPath = (specifier, baseURL) => {
39
+ const resolved = importMetaResolve(specifier, baseURL);
40
+ const resolvedURL = new URL(resolved);
41
+ return fileURLToPath(resolvedURL);
42
+ };
43
+ harden(resolveToPath);
@@ -1 +1 @@
1
- {"version":3,"file":"natural-sort.d.ts","sourceRoot":"","sources":["natural-sort.js"],"names":[],"mappings":"AAqCO,kCAJI,MAAM,KACN,MAAM,GACJ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAWtB"}
1
+ {"version":3,"file":"natural-sort.d.ts","sourceRoot":"","sources":["natural-sort.js"],"names":[],"mappings":"AAgDO,kCAJI,MAAM,KACN,MAAM,GACJ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAmCtB"}
@@ -1,3 +1,5 @@
1
+ import { provideLazyMap } from './js-utils.js';
2
+
1
3
  /**
2
4
  * @param {string} a
3
5
  * @param {string} b
@@ -19,30 +21,63 @@ const compareNats = (a, b) => {
19
21
 
20
22
  // TODO: compareByCodePoints
21
23
  // https://github.com/endojs/endo/pull/2008
22
- // eslint-disable-next-line no-nested-ternary
24
+
23
25
  const compareStrings = (a, b) => (a > b ? 1 : a < b ? -1 : 0);
24
26
 
25
- const rPrefixedDigits = /^(\D*)(\d+)(\D.*|)/s;
27
+ const rCaptureDigits = /([0-9]+)/;
26
28
 
27
29
  /**
28
- * Perform a single-level natural-sort comparison, finding the first decimal
29
- * digit sequence in each operand and comparing first by the (possibly empty)
30
- * preceding prefix as strings, then by the digits as integers, then by any
31
- * following suffix (e.g., sorting 'ko42' before 'ko100' as ['ko', 42] vs.
32
- * ['ko', 100]).
30
+ * Splitting by regular expression can be expensive; we don't want to repeat
31
+ * that for every comparison against the same string.
32
+ *
33
+ * @type {Map<string, string[]>}
34
+ */
35
+ const partsCache = new Map();
36
+
37
+ /**
38
+ * Perform a multi-level natural-sort comparison, finding the decimal digit
39
+ * sequences in each operand and comparing first by each ([possibly empty]
40
+ * string prefix, integer) pair in turn, with a final comparision by string
41
+ * suffix as necessary (e.g., sorting 'ko42' before 'ko100' as ['ko', 42] vs.
42
+ * ['ko', 100] and 'parent1.child8' before 'parent1.child10' as ['parent', 1,
43
+ * 'child', 8] vs. ['parent', 1, 'child', 10]).
33
44
  *
34
45
  * @param {string} a
35
46
  * @param {string} b
36
47
  * @returns {-1 | 0 | 1}
37
48
  */
38
49
  export const naturalCompare = (a, b) => {
39
- const [_a, aPrefix, aDigits, aSuffix] = rPrefixedDigits.exec(a) || [];
40
- if (aPrefix !== undefined) {
41
- const [_b, bPrefix, bDigits, bSuffix] = rPrefixedDigits.exec(b) || [];
42
- if (bPrefix === aPrefix) {
43
- return compareNats(aDigits, bDigits) || compareStrings(aSuffix, bSuffix);
50
+ // We want to maintain a cache only for the duration of each call to
51
+ // array.sort, and leverage the synchronous nature of that method in the first
52
+ // invocation of each turn (indicated by an empty cache) to schedule cache
53
+ // clearing in the *next* turn.
54
+ if (!partsCache.size) void Promise.resolve().then(() => partsCache.clear());
55
+
56
+ const aParts = provideLazyMap(partsCache, a, () => a.split(rCaptureDigits));
57
+ const bParts = provideLazyMap(partsCache, b, () => b.split(rCaptureDigits));
58
+
59
+ // An even index corresponds with a string part; an odd one with a digit part.
60
+ let i = 0;
61
+ for (; i + 1 < aParts.length; i += 2) {
62
+ if (i + 1 < bParts.length) {
63
+ // Both `a` and `b` have a digit part here, but we compare the preceding
64
+ // string part first in case those are unequal.
65
+ const result =
66
+ compareStrings(aParts[i], bParts[i]) ||
67
+ compareNats(aParts[i + 1], bParts[i + 1]);
68
+ if (result) return result;
69
+ } else {
70
+ // After a (possibly empty) common prefix, `a` has digits where `b` does
71
+ // not, so we use string comparison of `${aString}${aDigits}` vs.
72
+ // `${bString}`.
73
+ return compareStrings(`${aParts[i]}${aParts[i + 1]}`, bParts[i]);
44
74
  }
45
75
  }
46
- return compareStrings(a, b);
76
+ if (bParts.length > aParts.length) {
77
+ // `b` has digits where `a` does not.
78
+ return compareStrings(aParts[i], `${bParts[i]}${bParts[i + 1]}`);
79
+ }
80
+ // If `a` and `b` differ, it's only in the final string suffix.
81
+ return compareStrings(aParts[i], bParts[i]);
47
82
  };
48
83
  harden(naturalCompare);
@@ -20,5 +20,5 @@ export function decode(data: Buffer, optMaxChunkSize?: number): {
20
20
  * @returns {Transform}
21
21
  */
22
22
  export function netstringDecoderStream(optMaxChunkSize?: number): Transform;
23
- import { Transform } from 'stream';
23
+ import { Transform } from 'node:stream';
24
24
  //# sourceMappingURL=netstring.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"netstring.d.ts","sourceRoot":"","sources":["netstring.js"],"names":[],"mappings":"AASA;;;GAGG;AACH,6BAHW,MAAM,GACJ,MAAM,CAMlB;AAGD,oDAsBC;AAED;;;;;;GAMG;AACH,6BANW,MAAM,oBAEN,MAAM,GACJ;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAmCpD;AAED;;;GAGG;AAEH,yDAJW,MAAM,GACJ,SAAS,CAqCrB;0BAxHyB,QAAQ"}
1
+ {"version":3,"file":"netstring.d.ts","sourceRoot":"","sources":["netstring.js"],"names":[],"mappings":"AASA;;;GAGG;AACH,6BAHW,MAAM,GACJ,MAAM,CAMlB;AAGD,oDAsBC;AAED;;;;;;GAMG;AACH,6BANW,MAAM,oBAEN,MAAM,GACJ;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAmCpD;AAED;;;GAGG;AAEH,yDAJW,MAAM,GACJ,SAAS,CAqCrB;0BAxHyB,aAAa"}
package/src/netstring.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { Fail } from '@endo/errors';
3
3
 
4
4
  // adapted from 'netstring-stream', https://github.com/tlivings/netstring-stream/
5
- import { Transform } from 'stream';
5
+ import { Transform } from 'node:stream';
6
6
 
7
7
  const COLON = 58;
8
8
  const COMMA = 44;
@@ -21,11 +21,11 @@ export function encode(data) {
21
21
  export function netstringEncoderStream() {
22
22
  /**
23
23
  * @param {Buffer} chunk
24
- * @param {BufferEncoding} encoding
24
+ * @param {BufferEncoding} _encoding
25
25
  * @param {any} callback
26
26
  * @this {{ push: (b: Buffer) => void }}
27
27
  */
28
- function transform(chunk, encoding, callback) {
28
+ function transform(chunk, _encoding, callback) {
29
29
  if (!Buffer.isBuffer(chunk)) {
30
30
  throw Error('stream requires Buffers');
31
31
  }
@@ -93,11 +93,11 @@ export function netstringDecoderStream(optMaxChunkSize) {
93
93
  let buffered = Buffer.from('');
94
94
  /**
95
95
  * @param {Buffer} chunk
96
- * @param {BufferEncoding} encoding
96
+ * @param {BufferEncoding} _encoding
97
97
  * @param {any} callback
98
98
  * @this {{ push: (b: Buffer) => void }}
99
99
  */
100
- function transform(chunk, encoding, callback) {
100
+ function transform(chunk, _encoding, callback) {
101
101
  if (!Buffer.isBuffer(chunk)) {
102
102
  throw Error('stream requires Buffers');
103
103
  }