@dxos/timeframe 0.1.57-main.e87098f → 0.1.57

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.
@@ -3,11 +3,9 @@ import "@dxos/node-std/globals";
3
3
  // packages/common/timeframe/src/timeframe.ts
4
4
  import { inspect } from "@dxos/node-std/util";
5
5
  import { equalsSymbol } from "@dxos/debug";
6
- import { PublicKey } from "@dxos/keys";
7
- import { ComplexMap } from "@dxos/util";
8
6
  var Timeframe = class _Timeframe {
9
7
  constructor(frames = []) {
10
- this._frames = new ComplexMap(PublicKey.hash);
8
+ this._frames = /* @__PURE__ */ new Map();
11
9
  for (const [key, seq] of frames) {
12
10
  this.set(key, seq);
13
11
  }
@@ -26,15 +24,22 @@ var Timeframe = class _Timeframe {
26
24
  }
27
25
  // TODO(burdon): Rename getFrame.
28
26
  get(key) {
29
- return this._frames.get(key);
27
+ return this._frames.get(key.toHex())?.seq;
30
28
  }
31
29
  // TODO(burdon): Rename setFrame.
32
- set(key, value) {
33
- this._frames.set(key, value);
30
+ set(key, seq) {
31
+ const hex = key.toHex();
32
+ this._frames.set(hex, {
33
+ key,
34
+ seq
35
+ });
34
36
  }
35
37
  // TODO(burdon): Change to getter.
36
38
  frames() {
37
- return Array.from(this._frames.entries()).filter((frame) => !!frame);
39
+ return Array.from(this._frames.values()).map(({ key, seq }) => [
40
+ key,
41
+ seq
42
+ ]);
38
43
  }
39
44
  // TODO(burdon): Change to getter.
40
45
  size() {
@@ -49,7 +54,7 @@ var Timeframe = class _Timeframe {
49
54
  * @param keys
50
55
  */
51
56
  withoutKeys(keys) {
52
- return new _Timeframe(this.frames().filter(([frameKey]) => keys.every((key) => Buffer.compare(key.asBuffer(), frameKey.asBuffer()) !== 0)));
57
+ return new _Timeframe(this.frames().filter(([frameKey]) => keys.every((key) => !key.equals(frameKey))));
53
58
  }
54
59
  map(fn) {
55
60
  return new _Timeframe(this.frames().map(fn));
@@ -58,13 +63,13 @@ var Timeframe = class _Timeframe {
58
63
  * Returns a total amount of messages represented by this timeframe.
59
64
  */
60
65
  totalMessages() {
61
- return Array.from(this._frames.values()).reduce((result, seq) => result + seq + 1, 0);
66
+ return Array.from(this._frames.values()).reduce((result, { seq }) => result + seq + 1, 0);
62
67
  }
63
68
  /**
64
69
  * Returns a total amount of messages that are present in this timeframe but are missing in `base`.
65
70
  */
66
71
  newMessages(base) {
67
- return Array.from(this._frames.entries()).reduce((result, [key, seq]) => result + Math.max(seq - (base.get(key) ?? -1), 0), 0);
72
+ return Array.from(this._frames.entries()).reduce((result, [hex, { seq }]) => result + Math.max(seq - (base._frames.get(hex)?.seq ?? -1), 0), 0);
68
73
  }
69
74
  /**
70
75
  * Used by NodeJS to get textual representation of this object in `console.log`.
@@ -85,10 +90,10 @@ var Timeframe = class _Timeframe {
85
90
  static merge(...timeframes) {
86
91
  const result = new _Timeframe();
87
92
  for (const timeframe of timeframes) {
88
- for (const [key, seq] of timeframe.frames()) {
89
- const current = result.get(key);
90
- if (current === void 0 || seq > current) {
91
- result.set(key, seq);
93
+ for (const [hex, entry] of timeframe._frames) {
94
+ const currentEntry = result._frames.get(hex);
95
+ if (currentEntry === void 0 || entry.seq > currentEntry.seq) {
96
+ result._frames.set(hex, entry);
92
97
  }
93
98
  }
94
99
  }
@@ -100,10 +105,10 @@ var Timeframe = class _Timeframe {
100
105
  */
101
106
  static dependencies(tf1, tf2) {
102
107
  const result = new _Timeframe();
103
- for (const [key, seq] of tf1.frames()) {
104
- const otherSeq = tf2.get(key);
105
- if (otherSeq === void 0 || otherSeq < seq) {
106
- result.set(key, seq);
108
+ for (const [hex, entry] of tf1._frames) {
109
+ const otherEntry = tf2._frames.get(hex);
110
+ if (otherEntry === void 0 || otherEntry.seq < entry.seq) {
111
+ result._frames.set(hex, entry);
107
112
  }
108
113
  }
109
114
  return result;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/timeframe.ts"],
4
- "sourcesContent": ["//\n// Copyright 2020 DXOS.org\n//\n\nimport { inspect } from 'node:util';\n\nimport { equalsSymbol, Equatable } from '@dxos/debug';\nimport { PublicKey } from '@dxos/keys';\nimport { ComplexMap } from '@dxos/util';\n\n/**\n * A vector clock that implements ordering over a set of feed messages.\n */\nexport class Timeframe implements Equatable {\n private readonly _frames = new ComplexMap<PublicKey, number>(PublicKey.hash);\n\n constructor(frames: [PublicKey, number][] = []) {\n for (const [key, seq] of frames) {\n this.set(key, seq);\n }\n }\n\n toJSON() {\n return this.frames().reduce((frames: Record<string, number>, [key, seq]) => {\n frames[key.truncate()] = seq;\n return frames;\n }, {});\n }\n\n toString() {\n return `(${this.frames()\n .map(([key, seq]) => `${key.truncate()}[${seq}]`)\n .join(', ')})`;\n }\n\n equals(object: Timeframe) {\n return this.size() === object.size() && this.frames().every(([key, seq]) => object.get(key) === seq);\n }\n\n // TODO(burdon): Rename getFrame.\n get(key: PublicKey) {\n return this._frames.get(key);\n }\n\n // TODO(burdon): Rename setFrame.\n set(key: PublicKey, value: number) {\n this._frames.set(key, value);\n }\n\n // TODO(burdon): Change to getter.\n frames(): [PublicKey, number][] {\n return Array.from(this._frames.entries()).filter((frame): frame is [PublicKey, number] => !!frame);\n }\n\n // TODO(burdon): Change to getter.\n size() {\n return this._frames.size;\n }\n\n // TODO(burdon): Change to getter (empty).\n isEmpty() {\n return this.size() === 0;\n }\n\n /**\n * Returns a new timeframe with specified keys removed.\n * @param keys\n */\n withoutKeys(keys: PublicKey[]): Timeframe {\n return new Timeframe(\n this.frames().filter(([frameKey]) =>\n keys.every((key) => Buffer.compare(key.asBuffer(), frameKey.asBuffer()) !== 0),\n ),\n );\n }\n\n map(fn: (frame: [key: PublicKey, seq: number]) => [PublicKey, number]): Timeframe {\n return new Timeframe(this.frames().map(fn));\n }\n\n /**\n * Returns a total amount of messages represented by this timeframe.\n */\n totalMessages(): number {\n return Array.from(this._frames.values()).reduce((result, seq) => result + seq + 1, 0);\n }\n\n /**\n * Returns a total amount of messages that are present in this timeframe but are missing in `base`.\n */\n newMessages(base: Timeframe) {\n return Array.from(this._frames.entries()).reduce(\n (result, [key, seq]) => result + Math.max(seq - (base.get(key) ?? -1), 0),\n 0,\n );\n }\n\n /**\n * Used by NodeJS to get textual representation of this object in `console.log`.\n */\n [inspect.custom]() {\n return `Timeframe${this.toString()}`;\n }\n\n [equalsSymbol](other: any) {\n if (!(other instanceof Timeframe)) {\n return false;\n }\n\n return this.equals(other);\n }\n\n /**\n * Merges the values, updating the highest sequence numbers.\n * @param timeframes\n */\n static merge(...timeframes: Timeframe[]): Timeframe {\n const result = new Timeframe();\n for (const timeframe of timeframes) {\n for (const [key, seq] of timeframe.frames()) {\n const current = result.get(key);\n if (current === undefined || seq > current) {\n result.set(key, seq);\n }\n }\n }\n\n return result;\n }\n\n /**\n * Compares two timeframes and returns an array of frames from the first timeframe where the sequence number\n * is greater than the associated sequence number from the second timeframe.\n */\n static dependencies(tf1: Timeframe, tf2: Timeframe): Timeframe {\n const result = new Timeframe();\n for (const [key, seq] of tf1.frames()) {\n const otherSeq = tf2.get(key);\n if (otherSeq === undefined || otherSeq < seq) {\n result.set(key, seq);\n }\n }\n\n return result;\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["inspect", "equalsSymbol", "PublicKey", "ComplexMap", "Timeframe", "constructor", "frames", "_frames", "ComplexMap", "PublicKey", "hash", "key", "seq", "set", "toJSON", "reduce", "truncate", "toString", "map", "join", "equals", "object", "size", "every", "get", "value", "Array", "from", "entries", "filter", "frame", "isEmpty", "withoutKeys", "keys", "frameKey", "Buffer", "compare", "asBuffer", "fn", "totalMessages", "values", "result", "newMessages", "base", "Math", "max", "inspect", "custom", "equalsSymbol", "other", "merge", "timeframes", "timeframe", "current", "undefined", "dependencies", "tf1", "tf2", "otherSeq"]
4
+ "sourcesContent": ["//\n// Copyright 2020 DXOS.org\n//\n\nimport { inspect } from 'node:util';\n\nimport { equalsSymbol, Equatable } from '@dxos/debug';\nimport { PublicKey } from '@dxos/keys';\n\ntype Entry = {\n key: PublicKey;\n seq: number;\n};\n\n/**\n * A vector clock that implements ordering over a set of feed messages.\n */\nexport class Timeframe implements Equatable {\n private readonly _frames = new Map<string, Entry>();\n\n constructor(frames: [PublicKey, number][] = []) {\n for (const [key, seq] of frames) {\n this.set(key, seq);\n }\n }\n\n toJSON() {\n return this.frames().reduce((frames: Record<string, number>, [key, seq]) => {\n frames[key.truncate()] = seq;\n return frames;\n }, {});\n }\n\n toString() {\n return `(${this.frames()\n .map(([key, seq]) => `${key.truncate()}[${seq}]`)\n .join(', ')})`;\n }\n\n equals(object: Timeframe) {\n return this.size() === object.size() && this.frames().every(([key, seq]) => object.get(key) === seq);\n }\n\n // TODO(burdon): Rename getFrame.\n get(key: PublicKey): number | undefined {\n return this._frames.get(key.toHex())?.seq;\n }\n\n // TODO(burdon): Rename setFrame.\n set(key: PublicKey, seq: number) {\n const hex = key.toHex();\n this._frames.set(hex, { key, seq });\n }\n\n // TODO(burdon): Change to getter.\n frames(): [PublicKey, number][] {\n return Array.from(this._frames.values()).map(({ key, seq }) => [key, seq]);\n }\n\n // TODO(burdon): Change to getter.\n size() {\n return this._frames.size;\n }\n\n // TODO(burdon): Change to getter (empty).\n isEmpty() {\n return this.size() === 0;\n }\n\n /**\n * Returns a new timeframe with specified keys removed.\n * @param keys\n */\n withoutKeys(keys: PublicKey[]): Timeframe {\n return new Timeframe(this.frames().filter(([frameKey]) => keys.every((key) => !key.equals(frameKey))));\n }\n\n map(fn: (frame: [key: PublicKey, seq: number]) => [PublicKey, number]): Timeframe {\n return new Timeframe(this.frames().map(fn));\n }\n\n /**\n * Returns a total amount of messages represented by this timeframe.\n */\n totalMessages(): number {\n return Array.from(this._frames.values()).reduce((result, { seq }) => result + seq + 1, 0);\n }\n\n /**\n * Returns a total amount of messages that are present in this timeframe but are missing in `base`.\n */\n newMessages(base: Timeframe) {\n return Array.from(this._frames.entries()).reduce(\n (result, [hex, { seq }]) => result + Math.max(seq - (base._frames.get(hex)?.seq ?? -1), 0),\n 0,\n );\n }\n\n /**\n * Used by NodeJS to get textual representation of this object in `console.log`.\n */\n [inspect.custom]() {\n return `Timeframe${this.toString()}`;\n }\n\n [equalsSymbol](other: any) {\n if (!(other instanceof Timeframe)) {\n return false;\n }\n\n return this.equals(other);\n }\n\n /**\n * Merges the values, updating the highest sequence numbers.\n * @param timeframes\n */\n static merge(...timeframes: Timeframe[]): Timeframe {\n const result = new Timeframe();\n for (const timeframe of timeframes) {\n for (const [hex, entry] of timeframe._frames) {\n const currentEntry = result._frames.get(hex);\n if (currentEntry === undefined || entry.seq > currentEntry.seq) {\n result._frames.set(hex, entry);\n }\n }\n }\n\n return result;\n }\n\n /**\n * Compares two timeframes and returns an array of frames from the first timeframe where the sequence number\n * is greater than the associated sequence number from the second timeframe.\n */\n static dependencies(tf1: Timeframe, tf2: Timeframe): Timeframe {\n const result = new Timeframe();\n for (const [hex, entry] of tf1._frames) {\n const otherEntry = tf2._frames.get(hex);\n if (otherEntry === undefined || otherEntry.seq < entry.seq) {\n result._frames.set(hex, entry);\n }\n }\n\n return result;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["inspect", "equalsSymbol", "Timeframe", "constructor", "frames", "_frames", "Map", "key", "seq", "set", "toJSON", "reduce", "truncate", "toString", "map", "join", "equals", "object", "size", "every", "get", "toHex", "hex", "Array", "from", "values", "isEmpty", "withoutKeys", "keys", "filter", "frameKey", "fn", "totalMessages", "result", "newMessages", "base", "entries", "Math", "max", "inspect", "custom", "equalsSymbol", "other", "merge", "timeframes", "timeframe", "entry", "currentEntry", "undefined", "dependencies", "tf1", "tf2", "otherEntry"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/common/timeframe/src/timeframe.ts":{"bytes":13404,"imports":[{"path":"@dxos/node-std/util","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/common/timeframe/src/index.ts":{"bytes":470,"imports":[{"path":"packages/common/timeframe/src/timeframe.ts","kind":"import-statement","original":"./timeframe"}],"format":"esm"}},"outputs":{"packages/common/timeframe/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":7007},"packages/common/timeframe/dist/lib/browser/index.mjs":{"imports":[{"path":"@dxos/node-std/util","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["Timeframe"],"entryPoint":"packages/common/timeframe/src/index.ts","inputs":{"packages/common/timeframe/src/timeframe.ts":{"bytesInOutput":3212},"packages/common/timeframe/src/index.ts":{"bytesInOutput":0}},"bytes":3351}}}
1
+ {"inputs":{"packages/common/timeframe/src/timeframe.ts":{"bytes":13703,"imports":[{"path":"@dxos/node-std/util","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true}],"format":"esm"},"packages/common/timeframe/src/index.ts":{"bytes":460,"imports":[{"path":"packages/common/timeframe/src/timeframe.ts","kind":"import-statement","original":"./timeframe"}],"format":"esm"}},"outputs":{"packages/common/timeframe/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":7066},"packages/common/timeframe/dist/lib/browser/index.mjs":{"imports":[{"path":"@dxos/node-std/util","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true}],"exports":["Timeframe"],"entryPoint":"packages/common/timeframe/src/index.ts","inputs":{"packages/common/timeframe/src/timeframe.ts":{"bytesInOutput":3277},"packages/common/timeframe/src/index.ts":{"bytesInOutput":0}},"bytes":3416}}}
@@ -27,11 +27,9 @@ module.exports = __toCommonJS(src_exports);
27
27
  // packages/common/timeframe/src/timeframe.ts
28
28
  var import_node_util = require("node:util");
29
29
  var import_debug = require("@dxos/debug");
30
- var import_keys = require("@dxos/keys");
31
- var import_util = require("@dxos/util");
32
30
  var Timeframe = class _Timeframe {
33
31
  constructor(frames = []) {
34
- this._frames = new import_util.ComplexMap(import_keys.PublicKey.hash);
32
+ this._frames = /* @__PURE__ */ new Map();
35
33
  for (const [key, seq] of frames) {
36
34
  this.set(key, seq);
37
35
  }
@@ -50,15 +48,22 @@ var Timeframe = class _Timeframe {
50
48
  }
51
49
  // TODO(burdon): Rename getFrame.
52
50
  get(key) {
53
- return this._frames.get(key);
51
+ return this._frames.get(key.toHex())?.seq;
54
52
  }
55
53
  // TODO(burdon): Rename setFrame.
56
- set(key, value) {
57
- this._frames.set(key, value);
54
+ set(key, seq) {
55
+ const hex = key.toHex();
56
+ this._frames.set(hex, {
57
+ key,
58
+ seq
59
+ });
58
60
  }
59
61
  // TODO(burdon): Change to getter.
60
62
  frames() {
61
- return Array.from(this._frames.entries()).filter((frame) => !!frame);
63
+ return Array.from(this._frames.values()).map(({ key, seq }) => [
64
+ key,
65
+ seq
66
+ ]);
62
67
  }
63
68
  // TODO(burdon): Change to getter.
64
69
  size() {
@@ -73,7 +78,7 @@ var Timeframe = class _Timeframe {
73
78
  * @param keys
74
79
  */
75
80
  withoutKeys(keys) {
76
- return new _Timeframe(this.frames().filter(([frameKey]) => keys.every((key) => Buffer.compare(key.asBuffer(), frameKey.asBuffer()) !== 0)));
81
+ return new _Timeframe(this.frames().filter(([frameKey]) => keys.every((key) => !key.equals(frameKey))));
77
82
  }
78
83
  map(fn) {
79
84
  return new _Timeframe(this.frames().map(fn));
@@ -82,13 +87,13 @@ var Timeframe = class _Timeframe {
82
87
  * Returns a total amount of messages represented by this timeframe.
83
88
  */
84
89
  totalMessages() {
85
- return Array.from(this._frames.values()).reduce((result, seq) => result + seq + 1, 0);
90
+ return Array.from(this._frames.values()).reduce((result, { seq }) => result + seq + 1, 0);
86
91
  }
87
92
  /**
88
93
  * Returns a total amount of messages that are present in this timeframe but are missing in `base`.
89
94
  */
90
95
  newMessages(base) {
91
- return Array.from(this._frames.entries()).reduce((result, [key, seq]) => result + Math.max(seq - (base.get(key) ?? -1), 0), 0);
96
+ return Array.from(this._frames.entries()).reduce((result, [hex, { seq }]) => result + Math.max(seq - (base._frames.get(hex)?.seq ?? -1), 0), 0);
92
97
  }
93
98
  /**
94
99
  * Used by NodeJS to get textual representation of this object in `console.log`.
@@ -109,10 +114,10 @@ var Timeframe = class _Timeframe {
109
114
  static merge(...timeframes) {
110
115
  const result = new _Timeframe();
111
116
  for (const timeframe of timeframes) {
112
- for (const [key, seq] of timeframe.frames()) {
113
- const current = result.get(key);
114
- if (current === void 0 || seq > current) {
115
- result.set(key, seq);
117
+ for (const [hex, entry] of timeframe._frames) {
118
+ const currentEntry = result._frames.get(hex);
119
+ if (currentEntry === void 0 || entry.seq > currentEntry.seq) {
120
+ result._frames.set(hex, entry);
116
121
  }
117
122
  }
118
123
  }
@@ -124,10 +129,10 @@ var Timeframe = class _Timeframe {
124
129
  */
125
130
  static dependencies(tf1, tf2) {
126
131
  const result = new _Timeframe();
127
- for (const [key, seq] of tf1.frames()) {
128
- const otherSeq = tf2.get(key);
129
- if (otherSeq === void 0 || otherSeq < seq) {
130
- result.set(key, seq);
132
+ for (const [hex, entry] of tf1._frames) {
133
+ const otherEntry = tf2._frames.get(hex);
134
+ if (otherEntry === void 0 || otherEntry.seq < entry.seq) {
135
+ result._frames.set(hex, entry);
131
136
  }
132
137
  }
133
138
  return result;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/index.ts", "../../../src/timeframe.ts"],
4
- "sourcesContent": ["//\n// Copyright 2021 DXOS.org\n//\n\nexport * from './timeframe';\n", "//\n// Copyright 2020 DXOS.org\n//\n\nimport { inspect } from 'node:util';\n\nimport { equalsSymbol, Equatable } from '@dxos/debug';\nimport { PublicKey } from '@dxos/keys';\nimport { ComplexMap } from '@dxos/util';\n\n/**\n * A vector clock that implements ordering over a set of feed messages.\n */\nexport class Timeframe implements Equatable {\n private readonly _frames = new ComplexMap<PublicKey, number>(PublicKey.hash);\n\n constructor(frames: [PublicKey, number][] = []) {\n for (const [key, seq] of frames) {\n this.set(key, seq);\n }\n }\n\n toJSON() {\n return this.frames().reduce((frames: Record<string, number>, [key, seq]) => {\n frames[key.truncate()] = seq;\n return frames;\n }, {});\n }\n\n toString() {\n return `(${this.frames()\n .map(([key, seq]) => `${key.truncate()}[${seq}]`)\n .join(', ')})`;\n }\n\n equals(object: Timeframe) {\n return this.size() === object.size() && this.frames().every(([key, seq]) => object.get(key) === seq);\n }\n\n // TODO(burdon): Rename getFrame.\n get(key: PublicKey) {\n return this._frames.get(key);\n }\n\n // TODO(burdon): Rename setFrame.\n set(key: PublicKey, value: number) {\n this._frames.set(key, value);\n }\n\n // TODO(burdon): Change to getter.\n frames(): [PublicKey, number][] {\n return Array.from(this._frames.entries()).filter((frame): frame is [PublicKey, number] => !!frame);\n }\n\n // TODO(burdon): Change to getter.\n size() {\n return this._frames.size;\n }\n\n // TODO(burdon): Change to getter (empty).\n isEmpty() {\n return this.size() === 0;\n }\n\n /**\n * Returns a new timeframe with specified keys removed.\n * @param keys\n */\n withoutKeys(keys: PublicKey[]): Timeframe {\n return new Timeframe(\n this.frames().filter(([frameKey]) =>\n keys.every((key) => Buffer.compare(key.asBuffer(), frameKey.asBuffer()) !== 0),\n ),\n );\n }\n\n map(fn: (frame: [key: PublicKey, seq: number]) => [PublicKey, number]): Timeframe {\n return new Timeframe(this.frames().map(fn));\n }\n\n /**\n * Returns a total amount of messages represented by this timeframe.\n */\n totalMessages(): number {\n return Array.from(this._frames.values()).reduce((result, seq) => result + seq + 1, 0);\n }\n\n /**\n * Returns a total amount of messages that are present in this timeframe but are missing in `base`.\n */\n newMessages(base: Timeframe) {\n return Array.from(this._frames.entries()).reduce(\n (result, [key, seq]) => result + Math.max(seq - (base.get(key) ?? -1), 0),\n 0,\n );\n }\n\n /**\n * Used by NodeJS to get textual representation of this object in `console.log`.\n */\n [inspect.custom]() {\n return `Timeframe${this.toString()}`;\n }\n\n [equalsSymbol](other: any) {\n if (!(other instanceof Timeframe)) {\n return false;\n }\n\n return this.equals(other);\n }\n\n /**\n * Merges the values, updating the highest sequence numbers.\n * @param timeframes\n */\n static merge(...timeframes: Timeframe[]): Timeframe {\n const result = new Timeframe();\n for (const timeframe of timeframes) {\n for (const [key, seq] of timeframe.frames()) {\n const current = result.get(key);\n if (current === undefined || seq > current) {\n result.set(key, seq);\n }\n }\n }\n\n return result;\n }\n\n /**\n * Compares two timeframes and returns an array of frames from the first timeframe where the sequence number\n * is greater than the associated sequence number from the second timeframe.\n */\n static dependencies(tf1: Timeframe, tf2: Timeframe): Timeframe {\n const result = new Timeframe();\n for (const [key, seq] of tf1.frames()) {\n const otherSeq = tf2.get(key);\n if (otherSeq === undefined || otherSeq < seq) {\n result.set(key, seq);\n }\n }\n\n return result;\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["Timeframe", "constructor", "frames", "_frames", "ComplexMap", "PublicKey", "hash", "key", "seq", "set", "toJSON", "reduce", "truncate", "toString", "map", "join", "equals", "object", "size", "every", "get", "value", "Array", "from", "entries", "filter", "frame", "isEmpty", "withoutKeys", "keys", "frameKey", "Buffer", "compare", "asBuffer", "fn", "totalMessages", "values", "result", "newMessages", "base", "Math", "max", "inspect", "custom", "equalsSymbol", "other", "merge", "timeframes", "timeframe", "current", "undefined", "dependencies", "tf1", "tf2", "otherSeq"]
4
+ "sourcesContent": ["//\n// Copyright 2021 DXOS.org\n//\n\nexport * from './timeframe';\n", "//\n// Copyright 2020 DXOS.org\n//\n\nimport { inspect } from 'node:util';\n\nimport { equalsSymbol, Equatable } from '@dxos/debug';\nimport { PublicKey } from '@dxos/keys';\n\ntype Entry = {\n key: PublicKey;\n seq: number;\n};\n\n/**\n * A vector clock that implements ordering over a set of feed messages.\n */\nexport class Timeframe implements Equatable {\n private readonly _frames = new Map<string, Entry>();\n\n constructor(frames: [PublicKey, number][] = []) {\n for (const [key, seq] of frames) {\n this.set(key, seq);\n }\n }\n\n toJSON() {\n return this.frames().reduce((frames: Record<string, number>, [key, seq]) => {\n frames[key.truncate()] = seq;\n return frames;\n }, {});\n }\n\n toString() {\n return `(${this.frames()\n .map(([key, seq]) => `${key.truncate()}[${seq}]`)\n .join(', ')})`;\n }\n\n equals(object: Timeframe) {\n return this.size() === object.size() && this.frames().every(([key, seq]) => object.get(key) === seq);\n }\n\n // TODO(burdon): Rename getFrame.\n get(key: PublicKey): number | undefined {\n return this._frames.get(key.toHex())?.seq;\n }\n\n // TODO(burdon): Rename setFrame.\n set(key: PublicKey, seq: number) {\n const hex = key.toHex();\n this._frames.set(hex, { key, seq });\n }\n\n // TODO(burdon): Change to getter.\n frames(): [PublicKey, number][] {\n return Array.from(this._frames.values()).map(({ key, seq }) => [key, seq]);\n }\n\n // TODO(burdon): Change to getter.\n size() {\n return this._frames.size;\n }\n\n // TODO(burdon): Change to getter (empty).\n isEmpty() {\n return this.size() === 0;\n }\n\n /**\n * Returns a new timeframe with specified keys removed.\n * @param keys\n */\n withoutKeys(keys: PublicKey[]): Timeframe {\n return new Timeframe(this.frames().filter(([frameKey]) => keys.every((key) => !key.equals(frameKey))));\n }\n\n map(fn: (frame: [key: PublicKey, seq: number]) => [PublicKey, number]): Timeframe {\n return new Timeframe(this.frames().map(fn));\n }\n\n /**\n * Returns a total amount of messages represented by this timeframe.\n */\n totalMessages(): number {\n return Array.from(this._frames.values()).reduce((result, { seq }) => result + seq + 1, 0);\n }\n\n /**\n * Returns a total amount of messages that are present in this timeframe but are missing in `base`.\n */\n newMessages(base: Timeframe) {\n return Array.from(this._frames.entries()).reduce(\n (result, [hex, { seq }]) => result + Math.max(seq - (base._frames.get(hex)?.seq ?? -1), 0),\n 0,\n );\n }\n\n /**\n * Used by NodeJS to get textual representation of this object in `console.log`.\n */\n [inspect.custom]() {\n return `Timeframe${this.toString()}`;\n }\n\n [equalsSymbol](other: any) {\n if (!(other instanceof Timeframe)) {\n return false;\n }\n\n return this.equals(other);\n }\n\n /**\n * Merges the values, updating the highest sequence numbers.\n * @param timeframes\n */\n static merge(...timeframes: Timeframe[]): Timeframe {\n const result = new Timeframe();\n for (const timeframe of timeframes) {\n for (const [hex, entry] of timeframe._frames) {\n const currentEntry = result._frames.get(hex);\n if (currentEntry === undefined || entry.seq > currentEntry.seq) {\n result._frames.set(hex, entry);\n }\n }\n }\n\n return result;\n }\n\n /**\n * Compares two timeframes and returns an array of frames from the first timeframe where the sequence number\n * is greater than the associated sequence number from the second timeframe.\n */\n static dependencies(tf1: Timeframe, tf2: Timeframe): Timeframe {\n const result = new Timeframe();\n for (const [hex, entry] of tf1._frames) {\n const otherEntry = tf2._frames.get(hex);\n if (otherEntry === undefined || otherEntry.seq < entry.seq) {\n result._frames.set(hex, entry);\n }\n }\n\n return result;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["Timeframe", "constructor", "frames", "_frames", "Map", "key", "seq", "set", "toJSON", "reduce", "truncate", "toString", "map", "join", "equals", "object", "size", "every", "get", "toHex", "hex", "Array", "from", "values", "isEmpty", "withoutKeys", "keys", "filter", "frameKey", "fn", "totalMessages", "result", "newMessages", "base", "entries", "Math", "max", "inspect", "custom", "equalsSymbol", "other", "merge", "timeframes", "timeframe", "entry", "currentEntry", "undefined", "dependencies", "tf1", "tf2", "otherEntry"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/common/timeframe/src/timeframe.ts":{"bytes":13404,"imports":[{"path":"node:util","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/common/timeframe/src/index.ts":{"bytes":470,"imports":[{"path":"packages/common/timeframe/src/timeframe.ts","kind":"import-statement","original":"./timeframe"}],"format":"esm"}},"outputs":{"packages/common/timeframe/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":7060},"packages/common/timeframe/dist/lib/node/index.cjs":{"imports":[{"path":"node:util","kind":"require-call","external":true},{"path":"@dxos/debug","kind":"require-call","external":true},{"path":"@dxos/keys","kind":"require-call","external":true},{"path":"@dxos/util","kind":"require-call","external":true}],"exports":[],"entryPoint":"packages/common/timeframe/src/index.ts","inputs":{"packages/common/timeframe/src/index.ts":{"bytesInOutput":123},"packages/common/timeframe/src/timeframe.ts":{"bytesInOutput":3264}},"bytes":4414}}}
1
+ {"inputs":{"packages/common/timeframe/src/timeframe.ts":{"bytes":13703,"imports":[{"path":"node:util","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true}],"format":"esm"},"packages/common/timeframe/src/index.ts":{"bytes":460,"imports":[{"path":"packages/common/timeframe/src/timeframe.ts","kind":"import-statement","original":"./timeframe"}],"format":"esm"}},"outputs":{"packages/common/timeframe/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":7156},"packages/common/timeframe/dist/lib/node/index.cjs":{"imports":[{"path":"node:util","kind":"require-call","external":true},{"path":"@dxos/debug","kind":"require-call","external":true}],"exports":[],"entryPoint":"packages/common/timeframe/src/index.ts","inputs":{"packages/common/timeframe/src/index.ts":{"bytesInOutput":123},"packages/common/timeframe/src/timeframe.ts":{"bytesInOutput":3304}},"bytes":4454}}}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bench.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bench.test.d.ts","sourceRoot":"","sources":["../../../src/bench.test.ts"],"names":[],"mappings":""}
@@ -12,7 +12,7 @@ export declare class Timeframe implements Equatable {
12
12
  toString(): string;
13
13
  equals(object: Timeframe): boolean;
14
14
  get(key: PublicKey): number | undefined;
15
- set(key: PublicKey, value: number): void;
15
+ set(key: PublicKey, seq: number): void;
16
16
  frames(): [PublicKey, number][];
17
17
  size(): number;
18
18
  isEmpty(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"timeframe.d.ts","sourceRoot":"","sources":["../../../src/timeframe.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC;;GAEG;AACH,qBAAa,SAAU,YAAW,SAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqD;gBAEjE,MAAM,GAAE,CAAC,SAAS,EAAE,MAAM,CAAC,EAAO;IAM9C,MAAM;IAON,QAAQ;IAMR,MAAM,CAAC,MAAM,EAAE,SAAS;IAKxB,GAAG,CAAC,GAAG,EAAE,SAAS;IAKlB,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM;IAKjC,MAAM,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE;IAK/B,IAAI;IAKJ,OAAO;IAIP;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,SAAS;IAQzC,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,SAAS;IAIjF;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,SAAS;IAO3B;;OAEG;IACH,CAAC,OAAO,CAAC,MAAM,CAAC;IAIhB,CAAC,YAAY,CAAC,CAAC,KAAK,EAAE,GAAG;IAQzB;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,GAAG,UAAU,EAAE,SAAS,EAAE,GAAG,SAAS;IAcnD;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,SAAS;CAW/D"}
1
+ {"version":3,"file":"timeframe.d.ts","sourceRoot":"","sources":["../../../src/timeframe.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAOvC;;GAEG;AACH,qBAAa,SAAU,YAAW,SAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;gBAExC,MAAM,GAAE,CAAC,SAAS,EAAE,MAAM,CAAC,EAAO;IAM9C,MAAM;IAON,QAAQ;IAMR,MAAM,CAAC,MAAM,EAAE,SAAS;IAKxB,GAAG,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS;IAKvC,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM;IAM/B,MAAM,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE;IAK/B,IAAI;IAKJ,OAAO;IAIP;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,SAAS;IAIzC,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,SAAS;IAIjF;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,SAAS;IAO3B;;OAEG;IACH,CAAC,OAAO,CAAC,MAAM,CAAC;IAIhB,CAAC,YAAY,CAAC,CAAC,KAAK,EAAE,GAAG;IAQzB;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,GAAG,UAAU,EAAE,SAAS,EAAE,GAAG,SAAS;IAcnD;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,SAAS;CAW/D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/timeframe",
3
- "version": "0.1.57-main.e87098f",
3
+ "version": "0.1.57",
4
4
  "description": "Timeframe vector clock.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -16,11 +16,11 @@
16
16
  "src"
17
17
  ],
18
18
  "dependencies": {
19
- "@dxos/debug": "0.1.57-main.e87098f",
20
- "@dxos/keys": "0.1.57-main.e87098f",
21
- "@dxos/log": "0.1.57-main.e87098f",
22
- "@dxos/node-std": "0.1.57-main.e87098f",
23
- "@dxos/util": "0.1.57-main.e87098f"
19
+ "@dxos/debug": "0.1.57",
20
+ "@dxos/keys": "0.1.57",
21
+ "@dxos/log": "0.1.57",
22
+ "@dxos/node-std": "0.1.57",
23
+ "@dxos/util": "0.1.57"
24
24
  },
25
25
  "publishConfig": {
26
26
  "access": "public"
@@ -0,0 +1,107 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { PublicKey } from '@dxos/keys';
6
+ import { describe, test } from '@dxos/test';
7
+ import { isNotNullOrUndefined, numericalValues, range } from '@dxos/util';
8
+
9
+ import { Timeframe } from './timeframe';
10
+
11
+ type RandomTimeframeOpts = {
12
+ keys: PublicKey[];
13
+ base?: Timeframe;
14
+ occupancy?: number;
15
+ similarity?: number;
16
+ };
17
+
18
+ const createRandomTimeframe = ({ keys, base, similarity = 0.1, occupancy = 0.05 }: RandomTimeframeOpts) => {
19
+ const frames = keys
20
+ .map((key): [PublicKey, number] | undefined => {
21
+ if (base && Math.random() < similarity) {
22
+ const seq = base.get(key);
23
+ return seq !== undefined ? [key, base.get(key)!] : undefined;
24
+ }
25
+
26
+ if (Math.random() < occupancy) {
27
+ return undefined;
28
+ }
29
+
30
+ return [key, Math.floor(Math.random() * 10_000)];
31
+ })
32
+ .filter(isNotNullOrUndefined);
33
+ return new Timeframe(frames);
34
+ };
35
+
36
+ describe('Bench', () => {
37
+ const NUM_KEYS = 500;
38
+ const NUM_ITERS = 100;
39
+
40
+ const keys = range(NUM_KEYS).map(() => PublicKey.random());
41
+
42
+ test.only('dependencies', async () => {
43
+ const timeframe1 = createRandomTimeframe({ keys });
44
+ const timeframe2 = createRandomTimeframe({ keys, base: timeframe1, similarity: 0.6 });
45
+
46
+ console.log(
47
+ await bench(() => {
48
+ for (let i = 0; i < NUM_ITERS; i++) {
49
+ Timeframe.dependencies(timeframe1, timeframe2);
50
+ }
51
+ }, NUM_ITERS),
52
+ );
53
+ });
54
+ });
55
+
56
+ const bench = async (fn: () => void, factor = 1) => {
57
+ const runs: number[] = [];
58
+
59
+ const benchBegin = performance.now();
60
+ while (true) {
61
+ const begin = performance.now();
62
+ fn();
63
+ const end = performance.now();
64
+ const elapsed = end - begin;
65
+ const totalElapsed = end - benchBegin;
66
+ runs.push(elapsed / factor);
67
+
68
+ if (totalElapsed > 1_000) {
69
+ break;
70
+ }
71
+
72
+ await new Promise((resolve) => setImmediate(resolve));
73
+ }
74
+
75
+ return numericalValues(runs, (x) => x);
76
+ };
77
+
78
+ /*
79
+
80
+ baseline {
81
+ total: 10.049405800029636,
82
+ count: 36,
83
+ min: 0.27159708000719546,
84
+ max: 0.40789625003933905,
85
+ mean: 0.2791501611119343,
86
+ median: 0.27534582998603585
87
+ }
88
+
89
+ unwrap map {
90
+ total: 9.89743632942438,
91
+ count: 275,
92
+ min: 0.03528792001307011,
93
+ max: 0.08000333003699779,
94
+ mean: 0.0359906775615432,
95
+ median: 0.03549625001847744
96
+ }
97
+
98
+ collocate maps {
99
+ total: 9.782685480117792,
100
+ count: 305,
101
+ min: 0.03119667001068592,
102
+ max: 0.0767849999666214,
103
+ mean: 0.03207437862333702,
104
+ median: 0.03168250001966953
105
+ }
106
+
107
+ */
package/src/timeframe.ts CHANGED
@@ -6,13 +6,17 @@ import { inspect } from 'node:util';
6
6
 
7
7
  import { equalsSymbol, Equatable } from '@dxos/debug';
8
8
  import { PublicKey } from '@dxos/keys';
9
- import { ComplexMap } from '@dxos/util';
9
+
10
+ type Entry = {
11
+ key: PublicKey;
12
+ seq: number;
13
+ };
10
14
 
11
15
  /**
12
16
  * A vector clock that implements ordering over a set of feed messages.
13
17
  */
14
18
  export class Timeframe implements Equatable {
15
- private readonly _frames = new ComplexMap<PublicKey, number>(PublicKey.hash);
19
+ private readonly _frames = new Map<string, Entry>();
16
20
 
17
21
  constructor(frames: [PublicKey, number][] = []) {
18
22
  for (const [key, seq] of frames) {
@@ -38,18 +42,19 @@ export class Timeframe implements Equatable {
38
42
  }
39
43
 
40
44
  // TODO(burdon): Rename getFrame.
41
- get(key: PublicKey) {
42
- return this._frames.get(key);
45
+ get(key: PublicKey): number | undefined {
46
+ return this._frames.get(key.toHex())?.seq;
43
47
  }
44
48
 
45
49
  // TODO(burdon): Rename setFrame.
46
- set(key: PublicKey, value: number) {
47
- this._frames.set(key, value);
50
+ set(key: PublicKey, seq: number) {
51
+ const hex = key.toHex();
52
+ this._frames.set(hex, { key, seq });
48
53
  }
49
54
 
50
55
  // TODO(burdon): Change to getter.
51
56
  frames(): [PublicKey, number][] {
52
- return Array.from(this._frames.entries()).filter((frame): frame is [PublicKey, number] => !!frame);
57
+ return Array.from(this._frames.values()).map(({ key, seq }) => [key, seq]);
53
58
  }
54
59
 
55
60
  // TODO(burdon): Change to getter.
@@ -67,11 +72,7 @@ export class Timeframe implements Equatable {
67
72
  * @param keys
68
73
  */
69
74
  withoutKeys(keys: PublicKey[]): Timeframe {
70
- return new Timeframe(
71
- this.frames().filter(([frameKey]) =>
72
- keys.every((key) => Buffer.compare(key.asBuffer(), frameKey.asBuffer()) !== 0),
73
- ),
74
- );
75
+ return new Timeframe(this.frames().filter(([frameKey]) => keys.every((key) => !key.equals(frameKey))));
75
76
  }
76
77
 
77
78
  map(fn: (frame: [key: PublicKey, seq: number]) => [PublicKey, number]): Timeframe {
@@ -82,7 +83,7 @@ export class Timeframe implements Equatable {
82
83
  * Returns a total amount of messages represented by this timeframe.
83
84
  */
84
85
  totalMessages(): number {
85
- return Array.from(this._frames.values()).reduce((result, seq) => result + seq + 1, 0);
86
+ return Array.from(this._frames.values()).reduce((result, { seq }) => result + seq + 1, 0);
86
87
  }
87
88
 
88
89
  /**
@@ -90,7 +91,7 @@ export class Timeframe implements Equatable {
90
91
  */
91
92
  newMessages(base: Timeframe) {
92
93
  return Array.from(this._frames.entries()).reduce(
93
- (result, [key, seq]) => result + Math.max(seq - (base.get(key) ?? -1), 0),
94
+ (result, [hex, { seq }]) => result + Math.max(seq - (base._frames.get(hex)?.seq ?? -1), 0),
94
95
  0,
95
96
  );
96
97
  }
@@ -117,10 +118,10 @@ export class Timeframe implements Equatable {
117
118
  static merge(...timeframes: Timeframe[]): Timeframe {
118
119
  const result = new Timeframe();
119
120
  for (const timeframe of timeframes) {
120
- for (const [key, seq] of timeframe.frames()) {
121
- const current = result.get(key);
122
- if (current === undefined || seq > current) {
123
- result.set(key, seq);
121
+ for (const [hex, entry] of timeframe._frames) {
122
+ const currentEntry = result._frames.get(hex);
123
+ if (currentEntry === undefined || entry.seq > currentEntry.seq) {
124
+ result._frames.set(hex, entry);
124
125
  }
125
126
  }
126
127
  }
@@ -134,10 +135,10 @@ export class Timeframe implements Equatable {
134
135
  */
135
136
  static dependencies(tf1: Timeframe, tf2: Timeframe): Timeframe {
136
137
  const result = new Timeframe();
137
- for (const [key, seq] of tf1.frames()) {
138
- const otherSeq = tf2.get(key);
139
- if (otherSeq === undefined || otherSeq < seq) {
140
- result.set(key, seq);
138
+ for (const [hex, entry] of tf1._frames) {
139
+ const otherEntry = tf2._frames.get(hex);
140
+ if (otherEntry === undefined || otherEntry.seq < entry.seq) {
141
+ result._frames.set(hex, entry);
141
142
  }
142
143
  }
143
144