@dxos/util 0.10.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/util",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "description": "Temporary bucket for misc functions, which should graduate into separate packages.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -16,11 +16,7 @@
16
16
  ".": {
17
17
  "source": "./src/index.ts",
18
18
  "types": "./dist/types/src/index.d.ts",
19
- "browser": "./dist/lib/browser/index.mjs",
20
- "node": {
21
- "require": "./dist/lib/node/index.cjs",
22
- "default": "./dist/lib/node-esm/index.mjs"
23
- }
19
+ "import": "./dist/lib/index.mjs"
24
20
  }
25
21
  },
26
22
  "types": "dist/types/src/index.d.ts",
@@ -30,13 +26,13 @@
30
26
  ],
31
27
  "dependencies": {
32
28
  "@hazae41/symbol-dispose-polyfill": "^1.0.2",
33
- "@dxos/debug": "0.10.0",
34
- "@dxos/keys": "0.10.0",
35
- "@dxos/invariant": "0.10.0",
36
- "@dxos/node-std": "0.10.0"
29
+ "@dxos/invariant": "0.11.1",
30
+ "@dxos/keys": "0.11.1",
31
+ "@dxos/debug": "0.11.1",
32
+ "@dxos/node-std": "0.11.1"
37
33
  },
38
34
  "devDependencies": {
39
- "@dxos/crypto": "0.10.0"
35
+ "@dxos/crypto": "0.11.1"
40
36
  },
41
37
  "publishConfig": {
42
38
  "access": "public"
@@ -60,6 +60,37 @@ export const idHue = [
60
60
  'rose' as const,
61
61
  ];
62
62
 
63
+ /** FNV-1a hash of an arbitrary string, as an unsigned 32-bit integer. */
64
+ const fnv1a = (id: string): number => {
65
+ let hash = 0x811c9dc5;
66
+ for (let index = 0; index < id.length; index++) {
67
+ hash ^= id.charCodeAt(index);
68
+ hash = Math.imul(hash, 0x01000193);
69
+ }
70
+ return Math.abs(hash);
71
+ };
72
+
73
+ /**
74
+ * Deterministic palette hue for an arbitrary id string that isn't hex-parseable (e.g. an identity
75
+ * DID). Seeds the shared {@link idHue} palette via FNV-1a so the same id always maps to the same hue,
76
+ * matching the colouring used for avatars/tags elsewhere. Prefer {@link hexToHue} when a hex
77
+ * identity key is available (it aligns with the awareness-cursor palette).
78
+ */
79
+ export const stringToHue = (id: string): (typeof idHue)[number] => idHue[fnv1a(id) % idHue.length];
80
+
81
+ /**
82
+ * Deterministic avatar fallback (emoji + hue) for an arbitrary id string (e.g. an identity DID).
83
+ * Shares {@link stringToHue}'s FNV-1a seed, so `stringToFallback(id).hue === stringToHue(id)` — an
84
+ * avatar seeded from an id and a tag coloured by {@link stringToHue} for the same id agree.
85
+ */
86
+ export const stringToFallback = (id: string): FallbackValue => {
87
+ const hash = fnv1a(id);
88
+ return {
89
+ emoji: idEmoji[Math.floor(hash / idHue.length) % idEmoji.length],
90
+ hue: idHue[hash % idHue.length],
91
+ };
92
+ };
93
+
63
94
  export const keyToEmoji = (key: PublicKey) => keyToFallback(key).emoji;
64
95
  export const hexToEmoji = (hex: string) => hexToFallback(hex).emoji;
65
96
  export const toEmoji = (hash: number) => toFallback(hash).emoji;
package/src/unit.test.ts CHANGED
@@ -2,12 +2,17 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { describe, it } from 'vitest';
5
+ import { describe, test } from 'vitest';
6
6
 
7
7
  import { Unit } from './unit';
8
8
 
9
9
  describe('url', () => {
10
- it('duration', ({ expect }) => {
10
+ test('magnitudes', ({ expect }) => {
11
+ expect(Unit.Thousand(42_154, 1).toString()).toBe('42.2k');
12
+ expect(Unit.Million(36_200_000, 1).toString()).toBe('36.2M');
13
+ });
14
+
15
+ test('duration', ({ expect }) => {
11
16
  const tests: [number, string][] = [
12
17
  [0, '0ms'],
13
18
  [1, '1ms'],
package/src/unit.ts CHANGED
@@ -39,13 +39,14 @@ const MS_HOURS = 60 * MS_MINUTES;
39
39
 
40
40
  export const Unit: Record<string, UnitFormat> = {
41
41
  // General.
42
- Percent: createFormat({ symbol: '%', quotient: 1 / 100, precision: 2 }),
43
- Thousand: createFormat({ symbol: 'k', quotient: 1_000, precision: 2 }),
42
+ Percent: createFormat({ symbol: '%', quotient: 1 / 100, precision: 1 }),
43
+ Thousand: createFormat({ symbol: 'k', quotient: 1_000, precision: 1 }),
44
+ Million: createFormat({ symbol: 'M', quotient: 1_000_000, precision: 1 }),
44
45
 
45
46
  // Bytes (note KB vs KiB).
46
- Gigabyte: createFormat({ symbol: 'GB', quotient: 1_000 * 1_000 * 1_000, precision: 2 }),
47
- Megabyte: createFormat({ symbol: 'MB', quotient: 1_000 * 1_000, precision: 2 }),
48
- Kilobyte: createFormat({ symbol: 'KB', quotient: 1_000, precision: 2 }),
47
+ Gigabyte: createFormat({ symbol: 'GB', quotient: 1_000 * 1_000 * 1_000, precision: 1 }),
48
+ Megabyte: createFormat({ symbol: 'MB', quotient: 1_000 * 1_000, precision: 1 }),
49
+ Kilobyte: createFormat({ symbol: 'KB', quotient: 1_000, precision: 1 }),
49
50
  Byte: createFormat({ symbol: 'B', quotient: 1 }),
50
51
 
51
52
  // Time.