@agoric/time 0.3.2 → 0.3.3-calypso-dev-84eb287.0

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/index.js CHANGED
@@ -1,2 +1,4 @@
1
1
  export * from './src/timeMath.js';
2
2
  export * from './src/typeGuards.js';
3
+ // eslint-disable-next-line import/export -- just types
4
+ export * from './src/types.js';
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "@agoric/time",
3
- "version": "0.3.2",
3
+ "version": "0.3.3-calypso-dev-84eb287.0+84eb287",
4
4
  "description": "Timestamps, time math, timer service API definition",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
+ "types": "index.js",
7
8
  "engines": {
8
- "node": ">=14.15.0"
9
+ "node": "^18.12 || ^20.9"
9
10
  },
10
11
  "scripts": {
11
12
  "build": "exit 0",
12
13
  "test": "ava",
13
14
  "test:xs": "exit 0",
14
15
  "lint": "run-s --continue-on-error lint:*",
15
- "lint:types": "tsc -p jsconfig.json",
16
+ "lint:types": "tsc",
16
17
  "lint:eslint": "eslint .",
17
18
  "lint-fix": "yarn lint:eslint --fix"
18
19
  },
@@ -30,21 +31,33 @@
30
31
  },
31
32
  "homepage": "https://github.com/Agoric/agoric-sdk#readme",
32
33
  "dependencies": {
33
- "@agoric/assert": "^0.6.0",
34
- "@agoric/store": "^0.9.2",
35
- "@endo/nat": "^4.1.27"
34
+ "@agoric/assert": "0.6.1-calypso-dev-84eb287.0+84eb287",
35
+ "@endo/nat": "^5.0.7",
36
+ "@endo/patterns": "^1.4.0"
36
37
  },
37
38
  "devDependencies": {
38
- "@endo/far": "^0.2.18",
39
- "@endo/init": "^0.5.56",
40
- "ava": "^5.2.0"
39
+ "@endo/far": "^1.1.2",
40
+ "@endo/init": "^1.1.2",
41
+ "ava": "^5.3.0"
42
+ },
43
+ "ava": {
44
+ "require": [
45
+ "@endo/init/debug.js"
46
+ ],
47
+ "files": [
48
+ "test/**/*.test.*"
49
+ ]
41
50
  },
42
51
  "files": [
43
52
  "*.js",
44
- "NEWS.md"
53
+ "NEWS.md",
54
+ "src"
45
55
  ],
46
56
  "publishConfig": {
47
57
  "access": "public"
48
58
  },
49
- "gitHead": "b66bf7c881ae462fcb617cd6e8d41b5c40ec58ef"
59
+ "typeCoverage": {
60
+ "atLeast": 87.29
61
+ },
62
+ "gitHead": "84eb287915c8255d68e845a9b6e10c790f0d54cb"
50
63
  }
@@ -0,0 +1,267 @@
1
+ import { Nat } from '@endo/nat';
2
+ import { mustMatch } from '@endo/patterns';
3
+ import { RelativeTimeRecordShape, TimestampRecordShape } from './typeGuards.js';
4
+
5
+ /** @import {RelativeTime, RelativeTimeValue, TimerBrand, TimeMathType, Timestamp, TimestampRecord, TimestampValue} from './types.js' */
6
+
7
+ const { Fail, quote: q } = assert;
8
+
9
+ /**
10
+ * `agreedTimerBrand` is internal to this module.
11
+ *
12
+ * @param {TimerBrand | undefined} leftBrand
13
+ * @param {TimerBrand | undefined} rightBrand
14
+ * @returns {TimerBrand | undefined}
15
+ */
16
+ const agreedTimerBrand = (leftBrand, rightBrand) => {
17
+ if (leftBrand === undefined) {
18
+ if (rightBrand === undefined) {
19
+ return undefined;
20
+ } else {
21
+ return rightBrand;
22
+ }
23
+ } else if (rightBrand === undefined) {
24
+ return leftBrand;
25
+ } else {
26
+ leftBrand === rightBrand ||
27
+ Fail`TimerBrands must match: ${q(leftBrand)} vs ${q(rightBrand)}`;
28
+ return leftBrand;
29
+ }
30
+ };
31
+
32
+ /**
33
+ * `sharedTimerBrand` is internal to this module, and implements the
34
+ * transitional brand checking and contaigion logic explained in the `TimeMath`
35
+ * comment. It is used to define the binary operators that should follow
36
+ * this logic. It does the error checking between the operands, and returns
37
+ * the brand, if any, that should label the resulting time value.
38
+ *
39
+ * @param {Timestamp | RelativeTime} left
40
+ * @param {Timestamp | RelativeTime} right
41
+ * @returns {TimerBrand | undefined}
42
+ */
43
+ const sharedTimerBrand = (left, right) => {
44
+ const leftBrand = typeof left === 'bigint' ? undefined : left.timerBrand;
45
+ const rightBrand = typeof right === 'bigint' ? undefined : right.timerBrand;
46
+ return agreedTimerBrand(leftBrand, rightBrand);
47
+ };
48
+
49
+ /**
50
+ * `absLike` is internal to this module, and used to implement the binary
51
+ * operators in the case where the returned time should be a `Timestamp`
52
+ * rather than a `RelativeTime`.
53
+ *
54
+ * @param {Timestamp | RelativeTime} left
55
+ * @param {Timestamp | RelativeTime} right
56
+ * @param {TimestampValue} absValue
57
+ * @returns {Timestamp}
58
+ */
59
+ const absLike = (left, right, absValue) => {
60
+ Nat(absValue);
61
+ const timerBrand = sharedTimerBrand(left, right);
62
+ if (timerBrand) {
63
+ return harden({
64
+ timerBrand,
65
+ absValue,
66
+ });
67
+ } else {
68
+ return absValue;
69
+ }
70
+ };
71
+
72
+ /**
73
+ * `relLike` is internal to this module, and used to implement the binary
74
+ * operators in the case where the returned time should be a `RelativeTime`
75
+ * rather than a `Timestamp`.
76
+ *
77
+ * @param {Timestamp | RelativeTime} left
78
+ * @param {Timestamp | RelativeTime} right
79
+ * @param {RelativeTimeValue} relValue
80
+ * @returns {RelativeTime}
81
+ */
82
+ const relLike = (left, right, relValue) => {
83
+ Nat(relValue);
84
+ const timerBrand = sharedTimerBrand(left, right);
85
+ if (timerBrand) {
86
+ return harden({
87
+ timerBrand,
88
+ relValue,
89
+ });
90
+ } else {
91
+ return relValue;
92
+ }
93
+ };
94
+
95
+ // For all the following time operators, their documentation is in
96
+ // the `TimeMathType`, since that is the documentation that shows up
97
+ // in the IDE. Well, at least the vscode IDE.
98
+
99
+ const absValue = abs => {
100
+ if (typeof abs === 'bigint') {
101
+ return Nat(abs);
102
+ }
103
+ mustMatch(abs, TimestampRecordShape, 'timestamp');
104
+ return Nat(abs.absValue);
105
+ };
106
+
107
+ const relValue = rel => {
108
+ if (typeof rel === 'bigint') {
109
+ return Nat(rel);
110
+ }
111
+ mustMatch(rel, RelativeTimeRecordShape, 'relative');
112
+ return Nat(rel.relValue);
113
+ };
114
+
115
+ const makeTimestampRecord = (abs, timerBrand) =>
116
+ harden({ absValue: abs, timerBrand });
117
+ const makeRelativeTimeRecord = (rel, timerBrand) =>
118
+ harden({ relValue: rel, timerBrand });
119
+
120
+ const coerceTimestampRecord = (ts, brand) => {
121
+ brand || Fail`must have a brand`;
122
+ if (typeof ts === 'number') {
123
+ ts = Nat(ts);
124
+ }
125
+ if (typeof ts === 'bigint') {
126
+ return makeTimestampRecord(ts, brand);
127
+ } else {
128
+ const { timerBrand } = ts;
129
+ mustMatch(ts, TimestampRecordShape, 'timestamp');
130
+ agreedTimerBrand(timerBrand, brand);
131
+ return ts;
132
+ }
133
+ };
134
+
135
+ const coerceRelativeTimeRecord = (rt, brand) => {
136
+ brand || Fail`must have a brand`;
137
+ if (typeof rt === 'number') {
138
+ rt = Nat(rt);
139
+ }
140
+ if (typeof rt === 'bigint') {
141
+ return makeRelativeTimeRecord(rt, brand);
142
+ } else {
143
+ const { timerBrand } = rt;
144
+ mustMatch(rt, RelativeTimeRecordShape, 'relativeTime');
145
+ agreedTimerBrand(timerBrand, brand);
146
+ return rt;
147
+ }
148
+ };
149
+
150
+ const addAbsRel = (abs, rel) =>
151
+ absLike(abs, rel, absValue(abs) + relValue(rel));
152
+
153
+ const addRelRel = (rel1, rel2) =>
154
+ relLike(rel1, rel2, relValue(rel1) + relValue(rel2));
155
+
156
+ const subtractAbsAbs = (abs1, abs2) =>
157
+ relLike(abs1, abs2, absValue(abs1) - absValue(abs2));
158
+
159
+ const clampedSubtractAbsAbs = (abs1, abs2) => {
160
+ const val1 = absValue(abs1);
161
+ const val2 = absValue(abs2);
162
+ return relLike(abs1, abs2, val1 > val2 ? val1 - val2 : 0n);
163
+ };
164
+
165
+ const subtractAbsRel = (abs, rel) =>
166
+ absLike(abs, rel, absValue(abs) - relValue(rel));
167
+
168
+ const subtractRelRel = (rel1, rel2) =>
169
+ relLike(rel1, rel2, relValue(rel1) - relValue(rel2));
170
+
171
+ const isRelZero = rel => relValue(rel) === 0n;
172
+
173
+ const multiplyRelNat = (rel, nat) => relLike(rel, nat, relValue(rel) * nat);
174
+
175
+ const divideRelNat = (rel, nat) => relLike(rel, nat, relValue(rel) / nat);
176
+
177
+ const divideRelRel = (rel1, rel2) => {
178
+ sharedTimerBrand(rel1, rel2); // just error check
179
+ return relValue(rel1) / relValue(rel2);
180
+ };
181
+
182
+ const modAbsRel = (abs, step) =>
183
+ relLike(abs, step, absValue(abs) % relValue(step));
184
+
185
+ const modRelRel = (rel, step) =>
186
+ relLike(rel, step, relValue(rel) % relValue(step));
187
+
188
+ /**
189
+ * `compareValues` is internal to this module, and used to implement
190
+ * the time comparison operators.
191
+ *
192
+ * @param {Timestamp | RelativeTime} left
193
+ * @param {Timestamp | RelativeTime} right
194
+ * @param {bigint} v1
195
+ * @param {bigint} v2
196
+ * @returns {import('@endo/marshal').RankComparison}
197
+ */
198
+ const compareValues = (left, right, v1, v2) => {
199
+ sharedTimerBrand(left, right);
200
+ if (v1 < v2) {
201
+ return -1;
202
+ } else if (v1 === v2) {
203
+ return 0;
204
+ } else {
205
+ assert(v1 > v2);
206
+ return 1;
207
+ }
208
+ };
209
+
210
+ /**
211
+ * The `TimeMath` object provides helper methods to do arithmetic on labeled
212
+ * time values, much like `AmountMath` provides helper methods to do arithmetic
213
+ * on labeled asset/money values. Both check for consistency of labels: a
214
+ * binary operation on two labeled objects ensures that the both carry
215
+ * the same label. If they produce another object from the same domain, it
216
+ * will carry the same label. If the operands have incompatible labels,
217
+ * an error is thrown.
218
+ *
219
+ * Unlike amount arithmetic, time arithmetic deals in two kinds of time objects:
220
+ * Timestamps, which represent absolute time, and RelativeTime, which represents
221
+ * the duration between two absolute times. Both kinds of time object
222
+ * are labeled by a `TimerBrand`. For a Timestamp object, the value is
223
+ * a bigint in an `absValue` property. For a RelativeTime object, the value
224
+ * is a bigint in a `relValue` property. Thus we have a runtime safety check
225
+ * to ensure that we don't confused the two, even if we have managed to fool
226
+ * the (unsound) static type system.
227
+ *
228
+ * As a transitional measure, currently many Timestamps and RelativeTimes are
229
+ * still represented by unlabeled bigints. During this transitional period,
230
+ * we allow this, both statically and dynamically. For a normal binary
231
+ * operation, if both inputs are labeled, then we do the full checking as
232
+ * explained above and return a labeled result. If both inputs are unlabeled
233
+ * bigints, we *assume* that they indicate a time of the right kind
234
+ * (Timestamp vs RelativeTime) and timer brand. Since we don't know what
235
+ * brand was intended, we can only return yet another unlabeled bigint.
236
+ *
237
+ * If one operand is labeled and the other is not, we check the labeled operand,
238
+ * *assume* the unlabeled bigint represents the value needed for the other
239
+ * operand, and return a labeled time object with the brand of the labeled
240
+ * operand.
241
+ *
242
+ * @type {TimeMathType}
243
+ */
244
+ export const TimeMath = harden({
245
+ absValue,
246
+ relValue,
247
+ coerceTimestampRecord,
248
+ coerceRelativeTimeRecord,
249
+ // @ts-expect-error xxx dynamic typing
250
+ addAbsRel,
251
+ // @ts-expect-error xxx dynamic typing
252
+ addRelRel,
253
+ subtractAbsAbs,
254
+ clampedSubtractAbsAbs,
255
+ subtractAbsRel,
256
+ subtractRelRel,
257
+ isRelZero,
258
+ multiplyRelNat,
259
+ divideRelNat,
260
+ divideRelRel,
261
+ modAbsRel,
262
+ modRelRel,
263
+ compareAbs: (abs1, abs2) =>
264
+ compareValues(abs1, abs2, absValue(abs1), absValue(abs2)),
265
+ compareRel: (rel1, rel2) =>
266
+ compareValues(rel1, rel2, relValue(rel1), relValue(rel2)),
267
+ });
@@ -0,0 +1,23 @@
1
+ import { M } from '@endo/patterns';
2
+
3
+ export const TimerBrandShape = M.remotable('TimerBrand');
4
+ export const TimestampValueShape = M.nat();
5
+ export const RelativeTimeValueShape = M.nat(); // Should we allow negatives?
6
+
7
+ export const TimestampRecordShape = harden({
8
+ timerBrand: TimerBrandShape,
9
+ absValue: TimestampValueShape,
10
+ });
11
+
12
+ export const RelativeTimeRecordShape = harden({
13
+ timerBrand: TimerBrandShape,
14
+ relValue: RelativeTimeValueShape,
15
+ });
16
+
17
+ export const TimestampShape = M.or(TimestampRecordShape, TimestampValueShape);
18
+ export const RelativeTimeShape = M.or(
19
+ RelativeTimeRecordShape,
20
+ RelativeTimeValueShape,
21
+ );
22
+
23
+ export const TimerServiceShape = M.remotable('TimerService');
package/src/types.d.ts ADDED
@@ -0,0 +1,360 @@
1
+ import type { ERef, RemotableBrand } from '@endo/eventual-send';
2
+
3
+ import type { RankComparison, RemotableObject } from '@endo/marshal';
4
+
5
+ /// <reference types="@agoric/notifier/src/types.js" />
6
+
7
+ // These aren't in the global runtime environment. They are just types that are
8
+ // meant to be globally accessible as a side-effect of importing this module.
9
+ /**
10
+ * The TimerBrand is a unique object that represents the kind of Time
11
+ * used in Timestamp/RelativeTime records. Times from different sources
12
+ * are not comparable.
13
+ *
14
+ * Do not call `isMyTimerService(myTimerService)` on an untrusted
15
+ * brand, because that will leak your closely-held timer authority. If
16
+ * the goal is to check the suitability of a client-provided
17
+ * Timestamp, use coerceTimestampRecord() or add/subtract it to a
18
+ * known-good Timestamp, or extract its brand and === against
19
+ * `timerService.getTimerBrand()`.
20
+ *
21
+ * TODO Not all Timestamps are labeled with the TimerBrand (in much
22
+ * the same way that `Amounts` are asset/money values labeled by
23
+ * `Brands`), but the SwingSet vat-timer TimerService will use branded
24
+ * TimestampRecord/RelativeTimeRecord in all messages it emits. Also,
25
+ * a `TimerService` is still used everywhere a `TimerBrand` is called
26
+ * for.
27
+ *
28
+ * See https://github.com/Agoric/agoric-sdk/issues/5798
29
+ * and https://github.com/Agoric/agoric-sdk/pull/5821
30
+ */
31
+ export type TimerBrand = RemotableObject & {
32
+ isMyTimerService: (timer: TimerService) => ERef<boolean>;
33
+ isMyClock: (clock: Clock) => ERef<boolean>;
34
+ };
35
+
36
+ /**
37
+ * @deprecated use TimestampRecord
38
+ *
39
+ * An absolute time returned by a TimerService. Note that different timer
40
+ * services may have different interpretations of actual TimestampValue values.
41
+ * Will generally be a count of some number of units starting at some starting
42
+ * point. But what the starting point is and what units are counted is purely up
43
+ * to the meaning of that particular TimerService
44
+ */
45
+ export type TimestampValue = bigint;
46
+
47
+ /**
48
+ * @deprecated use RelativeTimeRecord
49
+ *
50
+ * Difference between two TimestampValues. Note that different timer services
51
+ * may have different interpretations of TimestampValues values.
52
+ */
53
+ export type RelativeTimeValue = bigint;
54
+
55
+ /**
56
+ * The canonical representation of a typed absolute time. It bundles the brand
57
+ * with the time, as represented by a TimerService, which might represent time
58
+ * since the epoch, or blockheight on a particular chain.
59
+ */
60
+ export type TimestampRecord = {
61
+ timerBrand: TimerBrand;
62
+ absValue: bigint;
63
+ };
64
+
65
+ /**
66
+ * The canonical representation of a typed relative time. It bundles the brand
67
+ * with an elapsed time, as represented by a TimerService, which might represent
68
+ * time since the epoch, or blockheight on a particular chain.
69
+ */
70
+ export type RelativeTimeRecord = {
71
+ timerBrand: TimerBrand;
72
+ relValue: bigint;
73
+ };
74
+
75
+ /**
76
+ * @deprecated use TimestampRecord
77
+ *
78
+ * Transitional measure until all are converted to TimestampRecord.
79
+ * See `TimeMath` comment for an explanation of the representation
80
+ * during this transition. After the transition, `Timestamp` will simplify
81
+ * to the current definition of `TimestampRecord`, which will itself
82
+ * be deleted. All Timestamps will then be labeled by TimerBrands.
83
+ */
84
+ export type Timestamp = TimestampRecord | TimestampValue;
85
+
86
+ /**
87
+ * @deprecated use RelativeTimeRecord
88
+ *
89
+ * Transitional measure until all are converted to RelativeTimeRecord
90
+ * See `TimeMath` comment for an explanation of the representation
91
+ * during this transition. After the transition, `RelativeTime` will simplify
92
+ * to the current definition of `RelativeTimeRecord`, which will itself
93
+ * be deleted. All RelativeTimes will then be labeled by TimerBrands.
94
+ */
95
+ export type RelativeTime = RelativeTimeRecord | RelativeTimeValue;
96
+
97
+ /**
98
+ * A CancelToken is an arbitrary marker object, passed in with
99
+ * each API call that creates a wakeup or repeater, and passed to
100
+ * cancel() to cancel them all. Multiple wakeups can rely on the same
101
+ * CancelToken so they can be cancelled collectively.
102
+ */
103
+ export type CancelToken = object;
104
+
105
+ /**
106
+ * Gives the ability to get the current time,
107
+ * schedule a single wake() call, create a repeater that will allow scheduling
108
+ * of events at regular intervals, or remove scheduled calls.
109
+ */
110
+ export interface TimerServiceI {
111
+ /**
112
+ * Retrieve the latest timestamp
113
+ */
114
+ getCurrentTimestamp: () => TimestampRecord;
115
+ /**
116
+ * Return value is the time at which the call is scheduled to take place
117
+ */
118
+ setWakeup: (
119
+ baseTime: Timestamp,
120
+ waker: ERef<TimerWaker>,
121
+ cancelToken?: CancelToken,
122
+ ) => TimestampRecord;
123
+ /**
124
+ * Create and return a promise that will resolve after the absolute
125
+ * time has passed.
126
+ */
127
+ wakeAt: (
128
+ baseTime: Timestamp,
129
+ cancelToken?: CancelToken,
130
+ ) => Promise<TimestampRecord>;
131
+ /**
132
+ * Create and return a promise that will resolve after the relative time has
133
+ * passed.
134
+ */
135
+ delay: (
136
+ delay: RelativeTime,
137
+ cancelToken?: CancelToken,
138
+ ) => Promise<TimestampRecord>;
139
+ /**
140
+ * Create and return a repeater that will schedule `wake()` calls
141
+ * repeatedly at times that are a multiple of interval following delay.
142
+ * Interval is the difference between successive times at which wake will be
143
+ * called. When `schedule(w)` is called, `w.wake()` will be scheduled to be
144
+ * called after the next multiple of interval from the base. Since times can be
145
+ * coarse-grained, the actual call may occur later, but this won't change when
146
+ * the next event will be called.
147
+ */
148
+ makeRepeater: (
149
+ delay: RelativeTime,
150
+ interval: RelativeTime,
151
+ cancelToken?: CancelToken,
152
+ ) => TimerRepeater;
153
+ /**
154
+ * Create a repeater with a handler directly.
155
+ */
156
+ repeatAfter: (
157
+ delay: RelativeTime,
158
+ interval: RelativeTime,
159
+ handler: TimerWaker,
160
+ cancelToken?: CancelToken,
161
+ ) => void;
162
+ /**
163
+ * Create and return a Notifier that will deliver updates repeatedly at times
164
+ * that are a multiple of interval following delay.
165
+ */
166
+ makeNotifier: (
167
+ delay: RelativeTime,
168
+ interval: RelativeTime,
169
+ cancelToken?: CancelToken,
170
+ ) => import('@agoric/notifier').Notifier<TimestampRecord>;
171
+ /**
172
+ * Cancel a previously-established wakeup or repeater.
173
+ */
174
+ cancel: (cancelToken: CancelToken) => void;
175
+ /**
176
+ * Retrieve the read-only Clock facet.
177
+ */
178
+ getClock: () => Clock;
179
+ /**
180
+ * Retrieve the Brand for this timer service.
181
+ */
182
+ getTimerBrand: () => TimerBrand;
183
+ }
184
+ // XXX copied from Remotable helper return type
185
+ export type TimerService = TimerServiceI &
186
+ RemotableObject<'TimerService'> &
187
+ RemotableBrand<{}, TimerServiceI>;
188
+
189
+ /**
190
+ * Read-only access to a TimeService's current time. This allows reading the
191
+ * current time (e.g. to see if a deadline has passed) without the ability to
192
+ * schedule events.
193
+ */
194
+ export interface Clock {
195
+ /**
196
+ * Retrieve the latest timestamp
197
+ */
198
+ getCurrentTimestamp: () => TimestampRecord;
199
+ /**
200
+ * Retrieve the Brand for this timer service.
201
+ */
202
+ getTimerBrand: () => TimerBrand;
203
+ }
204
+
205
+ /**
206
+ * The interface that must be implemented by objects which are to be invoked at
207
+ * scheduled times. Used by `TimerService.repeatAfter()`,
208
+ * `TimerService.setWakeup()`, and `TimerRepeater.schedule()`.
209
+ */
210
+ export interface TimerWaker {
211
+ /**
212
+ * The timestamp passed to `wake()` is the time that the call was scheduled
213
+ * to occur.
214
+ */
215
+ wake: (timestamp: TimestampRecord) => void;
216
+ }
217
+
218
+ /**
219
+ * Provides the ability to schedule wake() calls repeatedly at a regular
220
+ * interval, or to disable all future use of this TimerRepeater. Created by the
221
+ * deprecated makeRepeater(), new code should use repeatAfter(), which doesn't
222
+ * have a control object and doesn't require a second schedule step
223
+ */
224
+ export interface TimerRepeater {
225
+ /**
226
+ * Returns the time scheduled for
227
+ * the first call to `E(waker).wake()`. The waker will continue to be scheduled
228
+ * every interval until the repeater is disabled.
229
+ */
230
+ schedule: (waker: ERef<TimerWaker>) => TimestampRecord;
231
+ /**
232
+ * Disable this repeater, so `schedule(w)` can't
233
+ * be called, and wakers already scheduled with this repeater won't be
234
+ * rescheduled again after `E(waker).wake()` is next called on them.
235
+ */
236
+ disable: () => void;
237
+ }
238
+
239
+ /**
240
+ * TimeMath supports simple arithmetic on typed Time values, enforcing that
241
+ * values are combined in type-compatible ways. You can add 3 minutes to 3pm,
242
+ * or 5 minutes to a half hour, but it makes no sense to add 3pm and 5pm.
243
+ * Subtracting two Timestamps does produce a useful difference.
244
+ *
245
+ * The brands prevent you from accidentally combining time values from different
246
+ * TimerServices. Some chains track time in blocks, others follow wall clock
247
+ * time, some do both. Every local computer has its own unique notion of wall
248
+ * clock time. Even when these clocks are talking about the same thing (UTC),
249
+ * they can all drift in different ways. Using the correct brands lets you be
250
+ * precise about which particular source of time you mean, preventing confusion
251
+ * or attacks when the clocks diverge. Thus it is an error to e.g. use a time
252
+ * you got from chain A to schedule an event on chain B.
253
+ *
254
+ * The basic types are `RelativeTimeRecord` (durations) and `TimestampRecord`. The numeric
255
+ * values can be extracted from the typed values, but it's usually better to
256
+ * maintain values as their canonical typed form so these operations can be
257
+ * applied.
258
+ */
259
+ export type TimeMathType = {
260
+ /**
261
+ * Validates that the operand represents a `Timestamp` and returns the bigint
262
+ * representing its absolute time value.
263
+ * During the transition explained in the`TimeMath` comment,
264
+ * `absValue` will also accept a bigint which it then just returns.
265
+ */
266
+ absValue: (abs: Timestamp) => TimestampValue;
267
+ /**
268
+ * Validates that the operand represents a `RelativeTime` and returns the
269
+ * bigint representing its relative time value.
270
+ * During the transition explained in the`TimeMath` comment,
271
+ * `relValue` will also accept a bigint which it then just returns.
272
+ */
273
+ relValue: (rel: RelativeTime) => RelativeTimeValue;
274
+
275
+ /**
276
+ * Coerces to a TimestampRecord if possible, else throws. If the value has a brand, ensure it matches.
277
+ * Return a Timestamp labeled with that brand.
278
+ */
279
+ coerceTimestampRecord: (
280
+ abs: TimestampRecord | TimestampValue | number,
281
+ brand: TimerBrand,
282
+ ) => TimestampRecord;
283
+ /**
284
+ * Coerces to a RelativeTime if possible. If a brand is provided, ensure it
285
+ * matches and return a RelativeTime labeled with that brand.
286
+ */
287
+ coerceRelativeTimeRecord: (
288
+ rel: RelativeTimeRecord | RelativeTimeValue | number,
289
+ brand: TimerBrand,
290
+ ) => RelativeTimeRecord;
291
+ /**
292
+ * An absolute time + a relative time gives a new absolute time.
293
+ */
294
+ addAbsRel: <T extends Timestamp>(
295
+ abs: T,
296
+ rel: RelativeTime,
297
+ ) => T extends TimestampRecord ? TimestampRecord : TimestampValue;
298
+ /**
299
+ * A relative time (i.e., a duration) + another relative time
300
+ * gives a new relative time.
301
+ */
302
+ addRelRel: <T extends RelativeTime>(
303
+ rel1: T,
304
+ rel2: T,
305
+ ) => T extends RelativeTimeRecord ? RelativeTimeRecord : RelativeTimeValue;
306
+ /**
307
+ * The difference between two absolute times is a relative time. If abs1 > abs2
308
+ * the difference would be negative, so this method throws instead.
309
+ */
310
+ subtractAbsAbs: (abs1: Timestamp, abs2: Timestamp) => RelativeTime;
311
+ /**
312
+ * The difference between two absolute times is a relative time. If abs1 > abs2
313
+ * the difference would be negative, so this method returns a zero
314
+ * relative time instead.
315
+ */
316
+ clampedSubtractAbsAbs: (abs1: Timestamp, abs2: Timestamp) => RelativeTime;
317
+ /**
318
+ * An absolute time - a relative time gives a new absolute time
319
+ */
320
+ subtractAbsRel: (abs: Timestamp, rel: RelativeTime) => Timestamp;
321
+ /**
322
+ * The difference between two relative times.
323
+ */
324
+ subtractRelRel: (rel1: RelativeTime, rel2: RelativeTime) => RelativeTime;
325
+ /**
326
+ * Does it represent a zero relative time, i.e., the difference
327
+ * of an absolute time with itself? (We choose not to define a similar
328
+ * isAbsZero, even though we could, because it is much less likely to be
329
+ * meaningful.)
330
+ */
331
+ isRelZero: (rel: RelativeTime) => boolean;
332
+ multiplyRelNat: (rel: RelativeTime, nat: bigint) => RelativeTime;
333
+ divideRelNat: (rel: RelativeTime, nat: bigint) => RelativeTime;
334
+ divideRelRel: (rel1: RelativeTime, rel2: RelativeTime) => bigint;
335
+ /**
336
+ * An absolute time modulo a relative time is a relative time. For example,
337
+ * 20:17 on July 20, 1969 modulo 1 day is just 20:17, a relative time that
338
+ * can be added to the beginning of any day.
339
+ */
340
+ modAbsRel: (abs: Timestamp, step: RelativeTime) => RelativeTime;
341
+ /**
342
+ * A relative time modulo a relative time is a relative time. For example,
343
+ * 3.5 hours modulo an hour is 30 minutes.
344
+ */
345
+ modRelRel: (rel: RelativeTime, step: RelativeTime) => RelativeTime;
346
+ /**
347
+ * Compares two absolute times. This comparison function is compatible
348
+ * with JavaScript's `Array.prototype.sort` and so can be used to sort an
349
+ * array of absolute times. The result is -1, 0, or 1 indicating whether
350
+ * the first argument is less than, equal, or greater than the second.
351
+ */
352
+ compareAbs: (abs1: Timestamp, abs2: Timestamp) => RankComparison;
353
+ /**
354
+ * Compares two relative times. This comparison function is compatible
355
+ * with JavaScript's `Array.prototype.sort` and so can be used to sort an
356
+ * array of relative times. The result is -1, 0, or 1 indicating whether
357
+ * the first argument is less than, equal, or greater than the second.
358
+ */
359
+ compareRel: (rel1: RelativeTime, rel2: RelativeTime) => RankComparison;
360
+ };
package/src/types.js ADDED
@@ -0,0 +1,2 @@
1
+ // Empty JS file to correspond with types.d.ts
2
+ export {};
package/CHANGELOG.md DELETED
@@ -1,37 +0,0 @@
1
- # Change Log
2
-
3
- All notable changes to this project will be documented in this file.
4
- See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
-
6
- ### [0.3.2](https://github.com/Agoric/agoric-sdk/compare/@agoric/time@0.3.1...@agoric/time@0.3.2) (2023-06-02)
7
-
8
- **Note:** Version bump only for package @agoric/time
9
-
10
-
11
-
12
-
13
-
14
- ### [0.3.1](https://github.com/Agoric/agoric-sdk/compare/@agoric/time@0.3.0...@agoric/time@0.3.1) (2023-05-24)
15
-
16
- **Note:** Version bump only for package @agoric/time
17
-
18
-
19
-
20
-
21
-
22
- ## 0.3.0 (2023-05-19)
23
-
24
-
25
- ### Features
26
-
27
- * **auction:** add an auctioneer to manage vault liquidation ([#7000](https://github.com/Agoric/agoric-sdk/issues/7000)) ([398b70f](https://github.com/Agoric/agoric-sdk/commit/398b70f7e028f957afc1582f0ee31eb2574c94d0)), closes [#6992](https://github.com/Agoric/agoric-sdk/issues/6992) [#7047](https://github.com/Agoric/agoric-sdk/issues/7047) [#7074](https://github.com/Agoric/agoric-sdk/issues/7074)
28
- * create new @agoric/time package ([a61a3fb](https://github.com/Agoric/agoric-sdk/commit/a61a3fbb7a5ccfe07c715a310baa88ada8e572b2)), closes [#6003](https://github.com/Agoric/agoric-sdk/issues/6003)
29
-
30
-
31
- ### Bug Fixes
32
-
33
- * **time:** TimerService now returns branded TimestampRecord ([9137e9c](https://github.com/Agoric/agoric-sdk/commit/9137e9cab6f459c876b1a2ad8e681be7224749ce)), closes [#6003](https://github.com/Agoric/agoric-sdk/issues/6003)
34
- * clean up types ([6f53f19](https://github.com/Agoric/agoric-sdk/commit/6f53f1915ce21e65fefc2fff900b7d4b947be6b1))
35
- * move timer files to new package ([c105bde](https://github.com/Agoric/agoric-sdk/commit/c105bdefff2527a90b3c6b9d80d0462944dd51c3))
36
- * TimerBrand has isMyTimerService(), not isMyTimer() ([9f4e867](https://github.com/Agoric/agoric-sdk/commit/9f4e8670694504ebbd451c8840f900a1a24b902f))
37
- * **time:** fix the code/test to work in its new home ([504d333](https://github.com/Agoric/agoric-sdk/commit/504d3335cf632cc50e079fb27a82db604318bd4a))