@dopamint-fun/open-sdk 0.2.0-dev.10 → 0.2.0-dev.12
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/bytes.d.ts +9 -0
- package/dist/bytes.js +17 -0
- package/dist/identity.d.ts +1 -1
- package/dist/identity.js +17 -19
- package/package.json +1 -1
package/dist/bytes.d.ts
CHANGED
|
@@ -4,6 +4,15 @@ export declare function toHex0x(bytes: Uint8Array): string;
|
|
|
4
4
|
/** Length-aware equality. `every()` on an empty left-hand side is vacuously
|
|
5
5
|
* true, which would accept a truncated hex decode as a matching key. */
|
|
6
6
|
export declare function equalBytes(left: Uint8Array, right: Uint8Array): boolean;
|
|
7
|
+
/** One `label:value` line per field, under a line naming the domain.
|
|
8
|
+
*
|
|
9
|
+
* What an owner's wallet is asked to approve is text, not a frame: a Sui
|
|
10
|
+
* wallet renders a personal message as characters, and a framed payload
|
|
11
|
+
* reached a person as NUL bytes and junk they could not check. The order of
|
|
12
|
+
* the fields is signed, and so is the absence of a trailing newline. */
|
|
13
|
+
export declare function signedMessage(domain: string, fields: readonly (readonly [label: string, value: string])[]): Uint8Array;
|
|
14
|
+
/** An id or address at the one width the message renders it, or a throw. */
|
|
15
|
+
export declare function fixedHex0x(value: string, length: number, field: string): string;
|
|
7
16
|
/** An append-only byte buffer with the wire's own vocabulary. */
|
|
8
17
|
export declare class ByteWriter {
|
|
9
18
|
private chunks;
|
package/dist/bytes.js
CHANGED
|
@@ -37,6 +37,23 @@ export function equalBytes(left, right) {
|
|
|
37
37
|
return false;
|
|
38
38
|
return left.every((byte, index) => byte === right[index]);
|
|
39
39
|
}
|
|
40
|
+
/** One `label:value` line per field, under a line naming the domain.
|
|
41
|
+
*
|
|
42
|
+
* What an owner's wallet is asked to approve is text, not a frame: a Sui
|
|
43
|
+
* wallet renders a personal message as characters, and a framed payload
|
|
44
|
+
* reached a person as NUL bytes and junk they could not check. The order of
|
|
45
|
+
* the fields is signed, and so is the absence of a trailing newline. */
|
|
46
|
+
export function signedMessage(domain, fields) {
|
|
47
|
+
const lines = fields.map(([label, value]) => `${label}:${value}`);
|
|
48
|
+
return textBytes([domain, ...lines].join("\n"));
|
|
49
|
+
}
|
|
50
|
+
/** An id or address at the one width the message renders it, or a throw. */
|
|
51
|
+
export function fixedHex0x(value, length, field) {
|
|
52
|
+
const bytes = fromHex(value);
|
|
53
|
+
if (bytes.length !== length)
|
|
54
|
+
throw new Error(`${field} must be ${length} bytes, got ${bytes.length}`);
|
|
55
|
+
return toHex0x(bytes);
|
|
56
|
+
}
|
|
40
57
|
/** An append-only byte buffer with the wire's own vocabulary. */
|
|
41
58
|
export class ByteWriter {
|
|
42
59
|
chunks = [];
|
package/dist/identity.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface AgentIdentityFields {
|
|
|
9
9
|
}
|
|
10
10
|
/** The form the product stores, which is the form the signature covers. */
|
|
11
11
|
export declare function parseIdentityFields(fields: AgentIdentityFields): Required<AgentIdentityFields>;
|
|
12
|
-
/** The exact
|
|
12
|
+
/** The exact message the owning address signs to name an agent. */
|
|
13
13
|
export declare function canonicalIdentityPayload(edit: {
|
|
14
14
|
agentId: string;
|
|
15
15
|
owner: string;
|
package/dist/identity.js
CHANGED
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
* and names it. After a claim the same route belongs to the claiming wallet,
|
|
7
7
|
* and this key can no longer sign for it -- which is the point of a claim.
|
|
8
8
|
*
|
|
9
|
-
* The
|
|
9
|
+
* The message mirrors `AgentIdentityEdit::canonical_message` in
|
|
10
10
|
* `backend/dopa-open/product/src/domain/custodial/key_rotation.rs`: the two
|
|
11
|
-
* ids
|
|
12
|
-
* and "a"/"bc" cannot sign the same
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* the
|
|
16
|
-
import {
|
|
11
|
+
* ids render at a fixed 32 bytes and every named field is quoted, so "ab"/"c"
|
|
12
|
+
* and "a"/"bc" cannot sign the same text and a newline inside a name cannot
|
|
13
|
+
* forge a line of its own. The product parses before it verifies -- it trims
|
|
14
|
+
* each field and lower-cases the handle -- so this signs the parsed form, or
|
|
15
|
+
* the signature is over text the store never holds. */
|
|
16
|
+
import { fixedHex0x, signedMessage } from "./bytes.js";
|
|
17
17
|
import { signOwnerAuthenticator } from "./keypair.js";
|
|
18
18
|
import { refusalMessageFromText } from "./refusal.js";
|
|
19
19
|
const IDENTITY_DOMAIN = "dopa_open::agent_identity::v1";
|
|
@@ -27,20 +27,18 @@ export function parseIdentityFields(fields) {
|
|
|
27
27
|
bio: fields.bio?.trim() || null,
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
/** The exact
|
|
30
|
+
/** The exact message the owning address signs to name an agent. */
|
|
31
31
|
export function canonicalIdentityPayload(edit) {
|
|
32
|
-
const domain = textBytes(IDENTITY_DOMAIN);
|
|
33
32
|
const parsed = parseIdentityFields(edit.fields);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
.
|
|
37
|
-
.
|
|
38
|
-
.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return writer.pushU64(edit.issuedAtMs).pushU64(edit.expiresAtMs).bytes();
|
|
33
|
+
return signedMessage(IDENTITY_DOMAIN, [
|
|
34
|
+
["agent", fixedHex0x(edit.agentId, 32, "agent id")],
|
|
35
|
+
["owner", fixedHex0x(edit.owner, 32, "owner")],
|
|
36
|
+
["name", JSON.stringify(parsed.name ?? "")],
|
|
37
|
+
["handle", JSON.stringify(parsed.handle ?? "")],
|
|
38
|
+
["bio", JSON.stringify(parsed.bio ?? "")],
|
|
39
|
+
["issued_at_ms", String(edit.issuedAtMs)],
|
|
40
|
+
["expires_at_ms", String(edit.expiresAtMs)],
|
|
41
|
+
]);
|
|
44
42
|
}
|
|
45
43
|
/** Name an agent, as the address that owns it. Answers what the arena stored. */
|
|
46
44
|
export async function nameAgent(args) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dopamint-fun/open-sdk",
|
|
3
|
-
"version": "0.2.0-dev.
|
|
3
|
+
"version": "0.2.0-dev.12",
|
|
4
4
|
"description": "DOPA-OPEN client SDK: generate and hold your own agent key, sign registrations, and play a Participant Session",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|