@dxos/keys 0.8.3 → 0.8.4-main.1da679c
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/dist/lib/browser/index.mjs +292 -223
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +290 -221
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/dxn.d.ts +34 -16
- package/dist/types/src/dxn.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/public-key.d.ts +2 -2
- package/dist/types/src/public-key.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -10
- package/src/dxn.ts +100 -74
- package/src/index.ts +1 -1
- package/src/object-id.ts +2 -2
- package/src/public-key.ts +4 -3
- package/src/random-bytes.ts +1 -1
- package/dist/lib/node/index.cjs +0 -866
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/keys",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4-main.1da679c",
|
|
4
4
|
"description": "Key utils and definitions.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -10,12 +10,10 @@
|
|
|
10
10
|
"type": "module",
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
|
+
"source": "./src/index.ts",
|
|
14
|
+
"types": "./dist/types/src/index.d.ts",
|
|
13
15
|
"browser": "./dist/lib/browser/index.mjs",
|
|
14
|
-
"node":
|
|
15
|
-
"require": "./dist/lib/node/index.cjs",
|
|
16
|
-
"default": "./dist/lib/node-esm/index.mjs"
|
|
17
|
-
},
|
|
18
|
-
"types": "./dist/types/src/index.d.ts"
|
|
16
|
+
"node": "./dist/lib/node-esm/index.mjs"
|
|
19
17
|
}
|
|
20
18
|
},
|
|
21
19
|
"types": "dist/types/src/index.d.ts",
|
|
@@ -27,11 +25,11 @@
|
|
|
27
25
|
"src"
|
|
28
26
|
],
|
|
29
27
|
"dependencies": {
|
|
30
|
-
"effect": "3.
|
|
28
|
+
"effect": "3.17.7",
|
|
31
29
|
"ulidx": "^2.3.0",
|
|
32
|
-
"@dxos/
|
|
33
|
-
"@dxos/
|
|
34
|
-
"@dxos/node-std": "0.8.
|
|
30
|
+
"@dxos/debug": "0.8.4-main.1da679c",
|
|
31
|
+
"@dxos/invariant": "0.8.4-main.1da679c",
|
|
32
|
+
"@dxos/node-std": "0.8.4-main.1da679c"
|
|
35
33
|
},
|
|
36
34
|
"devDependencies": {
|
|
37
35
|
"base32-decode": "^1.0.0",
|
package/src/dxn.ts
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import type { InspectOptionsStylized, inspect } from 'node:util';
|
|
6
|
+
|
|
5
7
|
import { Schema } from 'effect';
|
|
6
|
-
import type { inspect, InspectOptionsStylized } from 'node:util';
|
|
7
8
|
|
|
8
|
-
import {
|
|
9
|
-
import { invariant } from '@dxos/invariant';
|
|
9
|
+
import { type DevtoolsFormatter, devtoolsFormatter, inspectCustom } from '@dxos/debug';
|
|
10
|
+
import { assertArgument, invariant } from '@dxos/invariant';
|
|
10
11
|
|
|
11
12
|
import { ObjectId } from './object-id';
|
|
12
13
|
import { SpaceId } from './space-id';
|
|
@@ -18,6 +19,8 @@ import { SpaceId } from './space-id';
|
|
|
18
19
|
// TODO(dmaretskyi): "@" is a separator character in the URI spec.
|
|
19
20
|
export const LOCAL_SPACE_TAG = '@';
|
|
20
21
|
|
|
22
|
+
export const DXN_ECHO_REGEXP = /@(dxn:[a-zA-Z0-p:@]+)/;
|
|
23
|
+
|
|
21
24
|
// TODO(burdon): Namespace for.
|
|
22
25
|
export const QueueSubspaceTags = Object.freeze({
|
|
23
26
|
DATA: 'data',
|
|
@@ -26,6 +29,12 @@ export const QueueSubspaceTags = Object.freeze({
|
|
|
26
29
|
|
|
27
30
|
export type QueueSubspaceTag = (typeof QueueSubspaceTags)[keyof typeof QueueSubspaceTags];
|
|
28
31
|
|
|
32
|
+
// TODO(burdon): Refactor.
|
|
33
|
+
// Consider: https://github.com/multiformats/multiaddr
|
|
34
|
+
// dxn:echo:[<space-id>:[<queue-id>:]]<object-id>
|
|
35
|
+
// dxn:echo:[S/<space-id>:[Q/<queue-id>:]]<object-id>
|
|
36
|
+
// dxn:type:dxos.org/markdown/Contact
|
|
37
|
+
|
|
29
38
|
/**
|
|
30
39
|
* DXN unambiguously names a resource like an ECHO object, schema definition, plugin, etc.
|
|
31
40
|
* Each DXN starts with a dxn prefix, followed by a resource kind.
|
|
@@ -43,6 +52,7 @@ export type QueueSubspaceTag = (typeof QueueSubspaceTags)[keyof typeof QueueSubs
|
|
|
43
52
|
* ```
|
|
44
53
|
*/
|
|
45
54
|
export class DXN {
|
|
55
|
+
// TODO(burdon): Rename to DXN (i.e., DXN.DXN).
|
|
46
56
|
// TODO(dmaretskyi): Should this be a transformation into the DXN type?
|
|
47
57
|
static Schema = Schema.NonEmptyString.pipe(
|
|
48
58
|
Schema.pattern(/^dxn:([^:]+):(?:[^:]+:?)+[^:]$/),
|
|
@@ -64,16 +74,16 @@ export class DXN {
|
|
|
64
74
|
*/
|
|
65
75
|
static kind = Object.freeze({
|
|
66
76
|
/**
|
|
67
|
-
* dxn:type:<
|
|
77
|
+
* dxn:type:<type_name>[:<version>]
|
|
68
78
|
*/
|
|
69
79
|
TYPE: 'type',
|
|
70
80
|
|
|
71
81
|
/**
|
|
72
|
-
* dxn:echo:<
|
|
73
|
-
* dxn:echo:@:<
|
|
82
|
+
* dxn:echo:<space_id>:<echo_id>
|
|
83
|
+
* dxn:echo:@:<echo_id>
|
|
74
84
|
*/
|
|
75
|
-
// TODO(burdon): Rename to OBJECT? (BREAKING CHANGE).
|
|
76
|
-
// TODO(burdon): Add separate Kind for space
|
|
85
|
+
// TODO(burdon): Rename to OBJECT? (BREAKING CHANGE to update "echo").
|
|
86
|
+
// TODO(burdon): Add separate Kind for space?
|
|
77
87
|
ECHO: 'echo',
|
|
78
88
|
|
|
79
89
|
/**
|
|
@@ -85,14 +95,19 @@ export class DXN {
|
|
|
85
95
|
QUEUE: 'queue',
|
|
86
96
|
});
|
|
87
97
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Exactly equals.
|
|
100
|
+
*/
|
|
92
101
|
static equals(a: DXN, b: DXN): boolean {
|
|
93
102
|
return a.kind === b.kind && a.parts.length === b.parts.length && a.parts.every((part, i) => part === b.parts[i]);
|
|
94
103
|
}
|
|
95
104
|
|
|
105
|
+
static equalsEchoId(a: DXN, b: DXN): boolean {
|
|
106
|
+
const a1 = a.asEchoDXN();
|
|
107
|
+
const b1 = b.asEchoDXN();
|
|
108
|
+
return !!a1 && !!b1 && a1.echoId === b1.echoId;
|
|
109
|
+
}
|
|
110
|
+
|
|
96
111
|
// TODO(burdon): Rename isValid.
|
|
97
112
|
static isDXNString(dxn: string): boolean {
|
|
98
113
|
return dxn.startsWith('dxn:');
|
|
@@ -119,7 +134,7 @@ export class DXN {
|
|
|
119
134
|
static tryParse(dxn: string): DXN | undefined {
|
|
120
135
|
try {
|
|
121
136
|
return DXN.parse(dxn);
|
|
122
|
-
} catch
|
|
137
|
+
} catch {
|
|
123
138
|
return undefined;
|
|
124
139
|
}
|
|
125
140
|
}
|
|
@@ -139,17 +154,27 @@ export class DXN {
|
|
|
139
154
|
return new DXN(DXN.kind.TYPE, [typename, version]);
|
|
140
155
|
}
|
|
141
156
|
|
|
157
|
+
/**
|
|
158
|
+
* @example `dxn:echo:BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE:01J00J9B45YHYSGZQTQMSKMGJ6`
|
|
159
|
+
*/
|
|
160
|
+
static fromSpaceAndObjectId(spaceId: SpaceId, objectId: ObjectId): DXN {
|
|
161
|
+
assertArgument(SpaceId.isValid(spaceId), `Invalid space ID: ${spaceId}`);
|
|
162
|
+
assertArgument(ObjectId.isValid(objectId), 'objectId', `Invalid object ID: ${objectId}`);
|
|
163
|
+
return new DXN(DXN.kind.ECHO, [spaceId, objectId]);
|
|
164
|
+
}
|
|
165
|
+
|
|
142
166
|
/**
|
|
143
167
|
* @example `dxn:echo:@:01J00J9B45YHYSGZQTQMSKMGJ6`
|
|
144
168
|
*/
|
|
145
169
|
static fromLocalObjectId(id: string): DXN {
|
|
170
|
+
assertArgument(ObjectId.isValid(id), 'id', `Invalid object ID: ${id}`);
|
|
146
171
|
return new DXN(DXN.kind.ECHO, [LOCAL_SPACE_TAG, id]);
|
|
147
172
|
}
|
|
148
173
|
|
|
149
174
|
static fromQueue(subspaceTag: QueueSubspaceTag, spaceId: SpaceId, queueId: ObjectId, objectId?: ObjectId) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
175
|
+
assertArgument(SpaceId.isValid(spaceId), `Invalid space ID: ${spaceId}`);
|
|
176
|
+
assertArgument(ObjectId.isValid(queueId), 'queueId', `Invalid queue ID: ${queueId}`);
|
|
177
|
+
assertArgument(!objectId || ObjectId.isValid(objectId), 'objectId', `Invalid object ID: ${objectId}`);
|
|
153
178
|
|
|
154
179
|
return new DXN(DXN.kind.QUEUE, [subspaceTag, spaceId, queueId, ...(objectId ? [objectId] : [])]);
|
|
155
180
|
}
|
|
@@ -158,19 +183,23 @@ export class DXN {
|
|
|
158
183
|
#parts: string[];
|
|
159
184
|
|
|
160
185
|
constructor(kind: string, parts: string[]) {
|
|
161
|
-
|
|
162
|
-
|
|
186
|
+
assertArgument(parts.length > 0, 'parts', `Invalid DXN: ${parts}`);
|
|
187
|
+
assertArgument(
|
|
188
|
+
parts.every((part) => typeof part === 'string' && part.length > 0 && part.indexOf(':') === -1),
|
|
189
|
+
'parts',
|
|
190
|
+
`Invalid DXN: ${parts}`,
|
|
191
|
+
);
|
|
163
192
|
|
|
164
193
|
// Per-type validation.
|
|
165
194
|
switch (kind) {
|
|
166
195
|
case DXN.kind.TYPE:
|
|
167
196
|
if (parts.length > 2) {
|
|
168
|
-
throw new Error('Invalid
|
|
197
|
+
throw new Error('Invalid DXN.kind.TYPE');
|
|
169
198
|
}
|
|
170
199
|
break;
|
|
171
200
|
case DXN.kind.ECHO:
|
|
172
201
|
if (parts.length !== 2) {
|
|
173
|
-
throw new Error('Invalid
|
|
202
|
+
throw new Error('Invalid DXN.kind.ECHO');
|
|
174
203
|
}
|
|
175
204
|
break;
|
|
176
205
|
}
|
|
@@ -179,6 +208,39 @@ export class DXN {
|
|
|
179
208
|
this.#parts = parts;
|
|
180
209
|
}
|
|
181
210
|
|
|
211
|
+
toString(): DXN.String {
|
|
212
|
+
return `dxn:${this.#kind}:${this.#parts.join(':')}` as DXN.String;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
toJSON(): string {
|
|
216
|
+
return this.toString();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Used by Node.js to get textual representation of this object when it's printed with a `console.log` statement.
|
|
221
|
+
*/
|
|
222
|
+
[inspectCustom](depth: number, options: InspectOptionsStylized, inspectFn: typeof inspect): string {
|
|
223
|
+
const printControlCode = (code: number) => {
|
|
224
|
+
return `\x1b[${code}m`;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
printControlCode(inspectFn.colors.blueBright![0]) + this.toString() + printControlCode(inspectFn.colors.reset![0])
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
get [devtoolsFormatter](): DevtoolsFormatter {
|
|
233
|
+
return {
|
|
234
|
+
header: () => {
|
|
235
|
+
return ['span', { style: 'font-weight: bold;' }, this.toString()];
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
get kind() {
|
|
241
|
+
return this.#kind;
|
|
242
|
+
}
|
|
243
|
+
|
|
182
244
|
get parts() {
|
|
183
245
|
return this.#parts;
|
|
184
246
|
}
|
|
@@ -189,6 +251,10 @@ export class DXN {
|
|
|
189
251
|
return this.#parts[0];
|
|
190
252
|
}
|
|
191
253
|
|
|
254
|
+
equals(other: DXN): boolean {
|
|
255
|
+
return DXN.equals(this, other);
|
|
256
|
+
}
|
|
257
|
+
|
|
192
258
|
hasTypenameOf(typename: string): boolean {
|
|
193
259
|
return this.#kind === DXN.kind.TYPE && this.#parts.length === 1 && this.#parts[0] === typename;
|
|
194
260
|
}
|
|
@@ -204,6 +270,7 @@ export class DXN {
|
|
|
204
270
|
|
|
205
271
|
const [type, version] = this.#parts;
|
|
206
272
|
return {
|
|
273
|
+
// TODO(wittjosiah): Should be `typename` for consistency.
|
|
207
274
|
type,
|
|
208
275
|
version: version as string | undefined,
|
|
209
276
|
};
|
|
@@ -217,6 +284,7 @@ export class DXN {
|
|
|
217
284
|
const [spaceId, echoId] = this.#parts;
|
|
218
285
|
return {
|
|
219
286
|
spaceId: spaceId === LOCAL_SPACE_TAG ? undefined : (spaceId as SpaceId | undefined),
|
|
287
|
+
// TODO(burdon): objectId.
|
|
220
288
|
echoId,
|
|
221
289
|
};
|
|
222
290
|
}
|
|
@@ -239,59 +307,26 @@ export class DXN {
|
|
|
239
307
|
};
|
|
240
308
|
}
|
|
241
309
|
|
|
242
|
-
toString(): DXN.String {
|
|
243
|
-
return `dxn:${this.#kind}:${this.#parts.join(':')}` as DXN.String;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
310
|
/**
|
|
247
|
-
*
|
|
311
|
+
* Produces a new DXN with the given parts appended.
|
|
248
312
|
*/
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
return `\x1b[${code}m`;
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
return (
|
|
255
|
-
printControlCode(inspectFn.colors.blueBright![0]) + this.toString() + printControlCode(inspectFn.colors.reset![0])
|
|
256
|
-
);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
get [devtoolsFormatter](): DevtoolsFormatter {
|
|
260
|
-
return {
|
|
261
|
-
header: () => {
|
|
262
|
-
return ['span', { style: 'font-weight: bold;' }, this.toString()];
|
|
263
|
-
},
|
|
264
|
-
};
|
|
313
|
+
extend(parts: string[]): DXN {
|
|
314
|
+
return new DXN(this.#kind, [...this.#parts, ...parts]);
|
|
265
315
|
}
|
|
266
316
|
}
|
|
267
317
|
|
|
268
|
-
// TODO(dmaretskyi): Fluent API:
|
|
269
|
-
/*
|
|
270
|
-
class DXN {
|
|
271
|
-
...
|
|
272
|
-
isEchoDXN(): this is EchoDXN {
|
|
273
|
-
return this.#kind === DXN.kind.ECHO;
|
|
274
|
-
}
|
|
275
|
-
...
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
interface EchoDXN extends DXN {
|
|
279
|
-
objectId: ObjectId;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
declare const dxn: DXN;
|
|
283
|
-
|
|
284
|
-
dxn.objectId
|
|
285
|
-
|
|
286
|
-
if(dxn.isEchoDXN()) {
|
|
287
|
-
dxn.objectId
|
|
288
|
-
}
|
|
289
|
-
```
|
|
290
|
-
|
|
291
318
|
/**
|
|
292
319
|
* API namespace.
|
|
293
320
|
*/
|
|
294
321
|
export declare namespace DXN {
|
|
322
|
+
/**
|
|
323
|
+
* DXN represented as a javascript string.
|
|
324
|
+
*/
|
|
325
|
+
// TODO(burdon): Use Effect branded string?
|
|
326
|
+
// export const String = S.String.pipe(S.brand('DXN'));
|
|
327
|
+
// export type String = S.To(typoeof String);
|
|
328
|
+
export type String = string & { __DXNString: never };
|
|
329
|
+
|
|
295
330
|
export type TypeDXN = {
|
|
296
331
|
type: string;
|
|
297
332
|
version?: string;
|
|
@@ -299,8 +334,7 @@ export declare namespace DXN {
|
|
|
299
334
|
|
|
300
335
|
export type EchoDXN = {
|
|
301
336
|
spaceId?: SpaceId;
|
|
302
|
-
// TODO(
|
|
303
|
-
echoId: string; // TODO(dmaretskyi): ObjectId.
|
|
337
|
+
echoId: string; // TODO(dmaretskyi): Rename to `objectId` and use `ObjectId` for the type.
|
|
304
338
|
};
|
|
305
339
|
|
|
306
340
|
export type QueueDXN = {
|
|
@@ -309,12 +343,4 @@ export declare namespace DXN {
|
|
|
309
343
|
queueId: string; // TODO(dmaretskyi): ObjectId.
|
|
310
344
|
objectId?: string; // TODO(dmaretskyi): ObjectId.
|
|
311
345
|
};
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* DXN represented as a javascript string.
|
|
315
|
-
*/
|
|
316
|
-
export type String = string & { __DXNString: never };
|
|
317
|
-
// TODO(burdon): Make brand.
|
|
318
|
-
// export const String = S.String.pipe(S.brand('DXN'));
|
|
319
|
-
// export type String = S.To(typoeof String);
|
|
320
346
|
}
|
package/src/index.ts
CHANGED
package/src/object-id.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { ulid } from 'ulidx';
|
|
|
9
9
|
// export const ObjectIdBrand: unique symbol = Symbol('@dxos/echo/ObjectId');
|
|
10
10
|
// export const ObjectIdSchema = Schema.ULID.pipe(S.brand(ObjectIdBrand));
|
|
11
11
|
const ObjectIdSchema = Schema.String.pipe(Schema.pattern(/^[0-7][0-9A-HJKMNP-TV-Z]{25}$/i)).annotations({
|
|
12
|
-
description: '
|
|
12
|
+
description: 'A Universally Unique Lexicographically Sortable Identifier',
|
|
13
13
|
pattern: '^[0-7][0-9A-HJKMNP-TV-Z]{25}$',
|
|
14
14
|
});
|
|
15
15
|
|
|
@@ -31,7 +31,7 @@ export const ObjectId: ObjectIdClass = class extends ObjectIdSchema {
|
|
|
31
31
|
try {
|
|
32
32
|
Schema.decodeSync(ObjectId)(id);
|
|
33
33
|
return true;
|
|
34
|
-
} catch
|
|
34
|
+
} catch {
|
|
35
35
|
return false;
|
|
36
36
|
}
|
|
37
37
|
}
|
package/src/public-key.ts
CHANGED
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type InspectOptionsStylized, type inspect } from 'node:util';
|
|
6
|
+
|
|
5
7
|
import base32Decode from 'base32-decode';
|
|
6
8
|
import base32Encode from 'base32-encode';
|
|
7
|
-
import { type inspect, type InspectOptionsStylized } from 'node:util';
|
|
8
9
|
|
|
9
10
|
import {
|
|
10
|
-
devtoolsFormatter,
|
|
11
11
|
type DevtoolsFormatter,
|
|
12
|
-
equalsSymbol,
|
|
13
12
|
type Equatable,
|
|
13
|
+
devtoolsFormatter,
|
|
14
|
+
equalsSymbol,
|
|
14
15
|
inspectCustom,
|
|
15
16
|
truncateKey,
|
|
16
17
|
} from '@dxos/debug';
|
package/src/random-bytes.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
export const randomBytes = (length: number) => {
|
|
6
6
|
// globalThis.crypto is not available in Node.js when running in vitest even though the documentation says it should be.
|
|
7
|
-
// eslint-disable-next-line @typescript-eslint/no-
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
8
8
|
const webCrypto = globalThis.crypto ?? require('node:crypto').webcrypto;
|
|
9
9
|
|
|
10
10
|
const bytes = new Uint8Array(length);
|