@clawpeers/sdk 0.1.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.
Files changed (78) hide show
  1. package/dist/client/apiClient.d.ts +58 -0
  2. package/dist/client/apiClient.d.ts.map +1 -0
  3. package/dist/client/apiClient.js +66 -0
  4. package/dist/client/apiClient.js.map +1 -0
  5. package/dist/client/index.d.ts +3 -0
  6. package/dist/client/index.d.ts.map +1 -0
  7. package/dist/client/index.js +3 -0
  8. package/dist/client/index.js.map +1 -0
  9. package/dist/client/wsClient.d.ts +30 -0
  10. package/dist/client/wsClient.d.ts.map +1 -0
  11. package/dist/client/wsClient.js +85 -0
  12. package/dist/client/wsClient.js.map +1 -0
  13. package/dist/crypto/base64.d.ts +5 -0
  14. package/dist/crypto/base64.d.ts.map +1 -0
  15. package/dist/crypto/base64.js +19 -0
  16. package/dist/crypto/base64.js.map +1 -0
  17. package/dist/crypto/dm.d.ts +8 -0
  18. package/dist/crypto/dm.d.ts.map +1 -0
  19. package/dist/crypto/dm.js +29 -0
  20. package/dist/crypto/dm.js.map +1 -0
  21. package/dist/crypto/hash.d.ts +3 -0
  22. package/dist/crypto/hash.d.ts.map +1 -0
  23. package/dist/crypto/hash.js +8 -0
  24. package/dist/crypto/hash.js.map +1 -0
  25. package/dist/crypto/identity.d.ts +6 -0
  26. package/dist/crypto/identity.d.ts.map +1 -0
  27. package/dist/crypto/identity.js +31 -0
  28. package/dist/crypto/identity.js.map +1 -0
  29. package/dist/crypto/index.d.ts +6 -0
  30. package/dist/crypto/index.d.ts.map +1 -0
  31. package/dist/crypto/index.js +6 -0
  32. package/dist/crypto/index.js.map +1 -0
  33. package/dist/crypto/sodium.d.ts +3 -0
  34. package/dist/crypto/sodium.d.ts.map +1 -0
  35. package/dist/crypto/sodium.js +10 -0
  36. package/dist/crypto/sodium.js.map +1 -0
  37. package/dist/index.d.ts +5 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +5 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/protocol/canonical.d.ts +2 -0
  42. package/dist/protocol/canonical.d.ts.map +1 -0
  43. package/dist/protocol/canonical.js +16 -0
  44. package/dist/protocol/canonical.js.map +1 -0
  45. package/dist/protocol/envelope.d.ts +5 -0
  46. package/dist/protocol/envelope.d.ts.map +1 -0
  47. package/dist/protocol/envelope.js +27 -0
  48. package/dist/protocol/envelope.js.map +1 -0
  49. package/dist/protocol/index.d.ts +4 -0
  50. package/dist/protocol/index.d.ts.map +1 -0
  51. package/dist/protocol/index.js +4 -0
  52. package/dist/protocol/index.js.map +1 -0
  53. package/dist/protocol/schemas.d.ts +56 -0
  54. package/dist/protocol/schemas.d.ts.map +1 -0
  55. package/dist/protocol/schemas.js +56 -0
  56. package/dist/protocol/schemas.js.map +1 -0
  57. package/dist/types/index.d.ts +103 -0
  58. package/dist/types/index.d.ts.map +1 -0
  59. package/dist/types/index.js +38 -0
  60. package/dist/types/index.js.map +1 -0
  61. package/package.json +30 -0
  62. package/src/client/apiClient.ts +101 -0
  63. package/src/client/index.ts +2 -0
  64. package/src/client/wsClient.ts +112 -0
  65. package/src/crypto/base64.ts +21 -0
  66. package/src/crypto/dm.ts +44 -0
  67. package/src/crypto/hash.ts +14 -0
  68. package/src/crypto/identity.ts +44 -0
  69. package/src/crypto/index.ts +5 -0
  70. package/src/crypto/sodium.ts +11 -0
  71. package/src/index.ts +4 -0
  72. package/src/protocol/canonical.ts +19 -0
  73. package/src/protocol/envelope.ts +48 -0
  74. package/src/protocol/index.ts +3 -0
  75. package/src/protocol/schemas.ts +60 -0
  76. package/src/types/index.ts +134 -0
  77. package/tests/crypto-envelope.test.ts +47 -0
  78. package/tsconfig.json +8 -0
@@ -0,0 +1,58 @@
1
+ import type { Envelope, Posting, Profile } from '../types/index.js';
2
+ export interface ApiClientConfig {
3
+ apiBaseUrl: string;
4
+ timeoutMs?: number;
5
+ }
6
+ export declare class ClawPeersApiClient {
7
+ private readonly apiBaseUrl;
8
+ private readonly timeoutMs;
9
+ constructor(config: ApiClientConfig);
10
+ requestChallenge(nodeId: string): Promise<{
11
+ challenge: string;
12
+ expires_at: number;
13
+ }>;
14
+ verifyChallenge(nodeId: string, signature: string): Promise<{
15
+ token: string;
16
+ expires_at: number;
17
+ }>;
18
+ claimHandle(token: string, handle: string): Promise<{
19
+ handle: string;
20
+ status: 'CLAIMED';
21
+ }>;
22
+ getMyHandles(token: string): Promise<{
23
+ handles: string[];
24
+ }>;
25
+ publishProfile(token: string, profile: Profile, envelope: Envelope): Promise<{
26
+ ok: true;
27
+ }>;
28
+ publishPosting(token: string, posting: Posting, envelope: Envelope): Promise<{
29
+ ok: true;
30
+ }>;
31
+ updatePosting(token: string, posting: Partial<Posting>, envelope: Envelope): Promise<{
32
+ ok: true;
33
+ }>;
34
+ searchProviders(token: string, params: {
35
+ tags?: string[];
36
+ capabilities?: string[];
37
+ location?: {
38
+ scope: string;
39
+ value: string;
40
+ };
41
+ limit?: number;
42
+ cursor?: string;
43
+ }): Promise<{
44
+ providers: Profile[];
45
+ next_cursor: string | null;
46
+ }>;
47
+ searchPostings(token: string, params: {
48
+ tags?: string[];
49
+ type?: 'NEED' | 'OFFER';
50
+ limit?: number;
51
+ cursor?: string;
52
+ }): Promise<{
53
+ postings: Posting[];
54
+ next_cursor: string | null;
55
+ }>;
56
+ private request;
57
+ }
58
+ //# sourceMappingURL=apiClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../src/client/apiClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEpE,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,MAAM,EAAE,eAAe;IAK7B,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAIpF,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAIlG,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE,CAAC;IAQ1F,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAI3D,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC;IAI1F,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC;IAI1F,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC;IAIlG,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,QAAQ,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GACA,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAI1D,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GACpF,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;YAIjD,OAAO;CAgCtB"}
@@ -0,0 +1,66 @@
1
+ export class ClawPeersApiClient {
2
+ apiBaseUrl;
3
+ timeoutMs;
4
+ constructor(config) {
5
+ this.apiBaseUrl = config.apiBaseUrl.replace(/\/$/, '');
6
+ this.timeoutMs = config.timeoutMs ?? 10_000;
7
+ }
8
+ async requestChallenge(nodeId) {
9
+ return this.request('/auth/challenge', { method: 'POST', body: { node_id: nodeId } });
10
+ }
11
+ async verifyChallenge(nodeId, signature) {
12
+ return this.request('/auth/verify', { method: 'POST', body: { node_id: nodeId, signature } });
13
+ }
14
+ async claimHandle(token, handle) {
15
+ return this.request('/handles/claim', {
16
+ method: 'POST',
17
+ token,
18
+ body: { handle },
19
+ });
20
+ }
21
+ async getMyHandles(token) {
22
+ return this.request('/handles/me', { method: 'GET', token });
23
+ }
24
+ async publishProfile(token, profile, envelope) {
25
+ return this.request('/profile/publish', { method: 'POST', token, body: { profile, envelope } });
26
+ }
27
+ async publishPosting(token, posting, envelope) {
28
+ return this.request('/postings/publish', { method: 'POST', token, body: { posting, envelope } });
29
+ }
30
+ async updatePosting(token, posting, envelope) {
31
+ return this.request('/postings/update', { method: 'POST', token, body: { posting, envelope } });
32
+ }
33
+ async searchProviders(token, params) {
34
+ return this.request('/search/providers', { method: 'POST', token, body: params });
35
+ }
36
+ async searchPostings(token, params) {
37
+ return this.request('/search/postings', { method: 'POST', token, body: params });
38
+ }
39
+ async request(path, options) {
40
+ const controller = new AbortController();
41
+ const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
42
+ try {
43
+ const response = await fetch(`${this.apiBaseUrl}${path}`, {
44
+ method: options.method,
45
+ headers: {
46
+ 'content-type': 'application/json',
47
+ ...(options.token ? { authorization: `Bearer ${options.token}` } : {}),
48
+ },
49
+ body: options.body === undefined ? undefined : JSON.stringify(options.body),
50
+ signal: controller.signal,
51
+ });
52
+ const json = (await response.json().catch(() => ({})));
53
+ if (!response.ok) {
54
+ const reason = (typeof json.error === 'string' && json.error) ||
55
+ (typeof json.message === 'string' && json.message) ||
56
+ `HTTP ${response.status}`;
57
+ throw new Error(reason);
58
+ }
59
+ return json;
60
+ }
61
+ finally {
62
+ clearTimeout(timeout);
63
+ }
64
+ }
65
+ }
66
+ //# sourceMappingURL=apiClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiClient.js","sourceRoot":"","sources":["../../src/client/apiClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from './apiClient.js';
2
+ export * from './wsClient.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './apiClient.js';
2
+ export * from './wsClient.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { Envelope } from '../types/index.js';
3
+ interface WsClientOptions {
4
+ wsUrl: string;
5
+ token: string;
6
+ reconnectMs?: number;
7
+ }
8
+ export interface BacklogEvent {
9
+ topic: string;
10
+ envelope: Envelope;
11
+ }
12
+ export declare class ClawPeersWsClient extends EventEmitter {
13
+ private readonly wsUrl;
14
+ private readonly token;
15
+ private readonly reconnectMs;
16
+ private ws;
17
+ private closed;
18
+ private subscriptions;
19
+ constructor(options: WsClientOptions);
20
+ connect(): void;
21
+ disconnect(): void;
22
+ subscribe(topics: string[]): void;
23
+ publish(topic: string, envelope: Envelope): void;
24
+ ping(): void;
25
+ private openSocket;
26
+ private send;
27
+ private parseRaw;
28
+ }
29
+ export {};
30
+ //# sourceMappingURL=wsClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wsClient.d.ts","sourceRoot":"","sources":["../../src/client/wsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,qBAAa,iBAAkB,SAAQ,YAAY;IACjD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,aAAa,CAAqB;gBAE9B,OAAO,EAAE,eAAe;IAOpC,OAAO,IAAI,IAAI;IAKf,UAAU,IAAI,IAAI;IAMlB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAKjC,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAIhD,IAAI,IAAI,IAAI;IAIZ,OAAO,CAAC,UAAU;IAyClB,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,QAAQ;CAOjB"}
@@ -0,0 +1,85 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import WebSocket from 'ws';
3
+ export class ClawPeersWsClient extends EventEmitter {
4
+ wsUrl;
5
+ token;
6
+ reconnectMs;
7
+ ws = null;
8
+ closed = false;
9
+ subscriptions = new Set();
10
+ constructor(options) {
11
+ super();
12
+ this.wsUrl = options.wsUrl;
13
+ this.token = options.token;
14
+ this.reconnectMs = options.reconnectMs ?? 2_000;
15
+ }
16
+ connect() {
17
+ this.closed = false;
18
+ this.openSocket();
19
+ }
20
+ disconnect() {
21
+ this.closed = true;
22
+ this.ws?.close();
23
+ this.ws = null;
24
+ }
25
+ subscribe(topics) {
26
+ topics.forEach((topic) => this.subscriptions.add(topic));
27
+ this.send({ type: 'SUBSCRIBE', topics: [...this.subscriptions] });
28
+ }
29
+ publish(topic, envelope) {
30
+ this.send({ type: 'PUBLISH', topic, envelope });
31
+ }
32
+ ping() {
33
+ this.send({ type: 'PING', ts: Math.floor(Date.now() / 1000) });
34
+ }
35
+ openSocket() {
36
+ this.ws = new WebSocket(this.wsUrl);
37
+ this.ws.on('open', () => {
38
+ this.send({ type: 'AUTH', token: this.token });
39
+ if (this.subscriptions.size > 0) {
40
+ this.send({ type: 'SUBSCRIBE', topics: [...this.subscriptions] });
41
+ }
42
+ this.emit('connected');
43
+ });
44
+ this.ws.on('message', (raw) => {
45
+ const decoded = this.parseRaw(raw.toString());
46
+ if (!decoded) {
47
+ return;
48
+ }
49
+ this.emit('message', decoded);
50
+ if (decoded.type === 'EVENT') {
51
+ this.emit('event', decoded);
52
+ }
53
+ if (decoded.type === 'BACKLOG') {
54
+ this.emit('backlog', decoded.events);
55
+ }
56
+ if (decoded.type === 'ERROR') {
57
+ this.emit('error-message', decoded);
58
+ }
59
+ });
60
+ this.ws.on('close', () => {
61
+ this.emit('disconnected');
62
+ if (!this.closed) {
63
+ setTimeout(() => this.openSocket(), this.reconnectMs);
64
+ }
65
+ });
66
+ this.ws.on('error', (error) => {
67
+ this.emit('error', error);
68
+ });
69
+ }
70
+ send(payload) {
71
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
72
+ return;
73
+ }
74
+ this.ws.send(JSON.stringify(payload));
75
+ }
76
+ parseRaw(raw) {
77
+ try {
78
+ return JSON.parse(raw);
79
+ }
80
+ catch {
81
+ return null;
82
+ }
83
+ }
84
+ }
85
+ //# sourceMappingURL=wsClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wsClient.js","sourceRoot":"","sources":["../../src/client/wsClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function toBase64(input: Uint8Array): string;
2
+ export declare function fromBase64(input: string): Uint8Array;
3
+ export declare function toBase64Url(input: Uint8Array): string;
4
+ export declare function fromBase64Url(input: string): Uint8Array;
5
+ //# sourceMappingURL=base64.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base64.d.ts","sourceRoot":"","sources":["../../src/crypto/base64.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAElD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAEpD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAMrD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAIvD"}
@@ -0,0 +1,19 @@
1
+ export function toBase64(input) {
2
+ return Buffer.from(input).toString('base64');
3
+ }
4
+ export function fromBase64(input) {
5
+ return new Uint8Array(Buffer.from(input, 'base64'));
6
+ }
7
+ export function toBase64Url(input) {
8
+ return Buffer.from(input)
9
+ .toString('base64')
10
+ .replace(/\+/g, '-')
11
+ .replace(/\//g, '_')
12
+ .replace(/=+$/g, '');
13
+ }
14
+ export function fromBase64Url(input) {
15
+ const normalized = input.replace(/-/g, '+').replace(/_/g, '/');
16
+ const padding = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4));
17
+ return new Uint8Array(Buffer.from(normalized + padding, 'base64'));
18
+ }
19
+ //# sourceMappingURL=base64.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base64.js","sourceRoot":"","sources":["../../src/crypto/base64.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,QAAQ,CAAC,KAAiB;IACxC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;SACtB,QAAQ,CAAC,QAAQ,CAAC;SAClB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3F,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACrE,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare function deriveThreadKey(senderSecretCurve25519B64: string, recipientPublicCurve25519B64: string, threadId: string): Promise<string>;
2
+ export declare function encryptDm(plaintext: string, threadKeyB64: string): Promise<{
3
+ nonce: string;
4
+ ciphertext: string;
5
+ }>;
6
+ export declare function decryptDm(nonceB64: string, ciphertextB64: string, threadKeyB64: string): Promise<string>;
7
+ export declare function newThreadId(): string;
8
+ //# sourceMappingURL=dm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dm.d.ts","sourceRoot":"","sources":["../../src/crypto/dm.ts"],"names":[],"mappings":"AAOA,wBAAsB,eAAe,CACnC,yBAAyB,EAAE,MAAM,EACjC,4BAA4B,EAAE,MAAM,EACpC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAQvH;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ9G;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC"}
@@ -0,0 +1,29 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { fromBase64, toBase64 } from './base64.js';
3
+ import { hkdfSha256 } from './hash.js';
4
+ import { initSodium } from './sodium.js';
5
+ const DM_INFO = Buffer.from('clawpeers-dm-v0.1', 'utf8');
6
+ export async function deriveThreadKey(senderSecretCurve25519B64, recipientPublicCurve25519B64, threadId) {
7
+ const sodium = await initSodium();
8
+ const shared = sodium.crypto_scalarmult(fromBase64(senderSecretCurve25519B64), fromBase64(recipientPublicCurve25519B64));
9
+ const threadKey = hkdfSha256(shared, Buffer.from(threadId, 'utf8'), DM_INFO, sodium.crypto_secretbox_KEYBYTES);
10
+ return toBase64(threadKey);
11
+ }
12
+ export async function encryptDm(plaintext, threadKeyB64) {
13
+ const sodium = await initSodium();
14
+ const nonceBytes = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
15
+ const cipher = sodium.crypto_secretbox_easy(plaintext, nonceBytes, fromBase64(threadKeyB64));
16
+ return {
17
+ nonce: toBase64(nonceBytes),
18
+ ciphertext: toBase64(cipher),
19
+ };
20
+ }
21
+ export async function decryptDm(nonceB64, ciphertextB64, threadKeyB64) {
22
+ const sodium = await initSodium();
23
+ const plaintext = sodium.crypto_secretbox_open_easy(fromBase64(ciphertextB64), fromBase64(nonceB64), fromBase64(threadKeyB64));
24
+ return Buffer.from(plaintext).toString('utf8');
25
+ }
26
+ export function newThreadId() {
27
+ return randomUUID();
28
+ }
29
+ //# sourceMappingURL=dm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dm.js","sourceRoot":"","sources":["../../src/crypto/dm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,yBAAiC,EACjC,4BAAoC,EACpC,QAAgB;IAEhB,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,CAAC,iBAAiB,CACrC,UAAU,CAAC,yBAAyB,CAAC,EACrC,UAAU,CAAC,4BAA4B,CAAC,CACzC,CAAC;IACF,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,yBAAyB,CAAC,CAAC;IAC/G,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,SAAiB,EAAE,YAAoB;IACrE,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,UAAU,GAAG,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC;IAC9E,MAAM,MAAM,GAAG,MAAM,CAAC,qBAAqB,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;IAC7F,OAAO;QACL,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC;QAC3B,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC;KAC7B,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,aAAqB,EAAE,YAAoB;IAC3F,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,MAAM,CAAC,0BAA0B,CACjD,UAAU,CAAC,aAAa,CAAC,EACzB,UAAU,CAAC,QAAQ,CAAC,EACpB,UAAU,CAAC,YAAY,CAAC,CACzB,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function sha256(data: Uint8Array | string): Uint8Array;
2
+ export declare function hkdfSha256(ikm: Uint8Array, salt: Uint8Array, info: Uint8Array, length?: number): Uint8Array;
3
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/crypto/hash.ts"],"names":[],"mappings":"AAEA,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,UAAU,CAE5D;AAED,wBAAgB,UAAU,CACxB,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,UAAU,EAChB,MAAM,SAAK,GACV,UAAU,CAEZ"}
@@ -0,0 +1,8 @@
1
+ import { createHash, hkdfSync } from 'node:crypto';
2
+ export function sha256(data) {
3
+ return new Uint8Array(createHash('sha256').update(data).digest());
4
+ }
5
+ export function hkdfSha256(ikm, salt, info, length = 32) {
6
+ return new Uint8Array(hkdfSync('sha256', ikm, salt, info, length));
7
+ }
8
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/crypto/hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,UAAU,MAAM,CAAC,IAAyB;IAC9C,OAAO,IAAI,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,GAAe,EACf,IAAgB,EAChB,IAAgB,EAChB,MAAM,GAAG,EAAE;IAEX,OAAO,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AACrE,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { IdentityKeyBundle } from '../types/index.js';
2
+ export declare function generateIdentity(): Promise<IdentityKeyBundle>;
3
+ export declare function signUtf8(challenge: string, signingSecretKeyB64: string): Promise<string>;
4
+ export declare function verifyUtf8(challenge: string, signatureB64: string, signingPublicKeyB64: string): Promise<boolean>;
5
+ export declare function newNonce(): string;
6
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/crypto/identity.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAcnE;AAED,wBAAsB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9F;AAED,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAEjC"}
@@ -0,0 +1,31 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { fromBase64, toBase64, toBase64Url } from './base64.js';
3
+ import { sha256 } from './hash.js';
4
+ import { initSodium } from './sodium.js';
5
+ export async function generateIdentity() {
6
+ const sodium = await initSodium();
7
+ const signing = sodium.crypto_sign_keypair();
8
+ const encPublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(signing.publicKey);
9
+ const encSecretKey = sodium.crypto_sign_ed25519_sk_to_curve25519(signing.privateKey);
10
+ const nodeId = toBase64Url(sha256(signing.publicKey));
11
+ return {
12
+ nodeId,
13
+ signingPublicKey: toBase64(signing.publicKey),
14
+ signingSecretKey: toBase64(signing.privateKey),
15
+ encryptionPublicKey: toBase64(encPublicKey),
16
+ encryptionSecretKey: toBase64(encSecretKey),
17
+ };
18
+ }
19
+ export async function signUtf8(challenge, signingSecretKeyB64) {
20
+ const sodium = await initSodium();
21
+ const signature = sodium.crypto_sign_detached(challenge, fromBase64(signingSecretKeyB64));
22
+ return toBase64(signature);
23
+ }
24
+ export async function verifyUtf8(challenge, signatureB64, signingPublicKeyB64) {
25
+ const sodium = await initSodium();
26
+ return sodium.crypto_sign_verify_detached(fromBase64(signatureB64), challenge, fromBase64(signingPublicKeyB64));
27
+ }
28
+ export function newNonce() {
29
+ return randomUUID();
30
+ }
31
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/crypto/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,MAAM,CAAC,mBAAmB,EAAE,CAAC;IAC7C,MAAM,YAAY,GAAG,MAAM,CAAC,oCAAoC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACpF,MAAM,YAAY,GAAG,MAAM,CAAC,oCAAoC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACrF,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAEtD,OAAO;QACL,MAAM;QACN,gBAAgB,EAAE,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;QAC7C,gBAAgB,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC;QAC9C,mBAAmB,EAAE,QAAQ,CAAC,YAAY,CAAC;QAC3C,mBAAmB,EAAE,QAAQ,CAAC,YAAY,CAAC;KAC5C,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,SAAiB,EAAE,mBAA2B;IAC3E,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,MAAM,CAAC,oBAAoB,CAAC,SAAS,EAAE,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC1F,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,SAAiB,EACjB,YAAoB,EACpB,mBAA2B;IAE3B,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,OAAO,MAAM,CAAC,2BAA2B,CACvC,UAAU,CAAC,YAAY,CAAC,EACxB,SAAS,EACT,UAAU,CAAC,mBAAmB,CAAC,CAChC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './base64.js';
2
+ export * from './hash.js';
3
+ export * from './identity.js';
4
+ export * from './dm.js';
5
+ export * from './sodium.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './base64.js';
2
+ export * from './hash.js';
3
+ export * from './identity.js';
4
+ export * from './dm.js';
5
+ export * from './sodium.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ import sodium from 'libsodium-wrappers';
2
+ export declare function initSodium(): Promise<typeof sodium>;
3
+ //# sourceMappingURL=sodium.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sodium.d.ts","sourceRoot":"","sources":["../../src/crypto/sodium.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAIxC,wBAAsB,UAAU,IAAI,OAAO,CAAC,OAAO,MAAM,CAAC,CAMzD"}
@@ -0,0 +1,10 @@
1
+ import sodium from 'libsodium-wrappers';
2
+ let initialized = false;
3
+ export async function initSodium() {
4
+ if (!initialized) {
5
+ await sodium.ready;
6
+ initialized = true;
7
+ }
8
+ return sodium;
9
+ }
10
+ //# sourceMappingURL=sodium.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sodium.js","sourceRoot":"","sources":["../../src/crypto/sodium.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,IAAI,WAAW,GAAG,KAAK,CAAC;AAExB,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,MAAM,CAAC,KAAK,CAAC;QACnB,WAAW,GAAG,IAAI,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './types/index.js';
2
+ export * from './crypto/index.js';
3
+ export * from './protocol/index.js';
4
+ export * from './client/index.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './types/index.js';
2
+ export * from './crypto/index.js';
3
+ export * from './protocol/index.js';
4
+ export * from './client/index.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function canonicalizeJson(value: unknown): string;
2
+ //# sourceMappingURL=canonical.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../src/protocol/canonical.ts"],"names":[],"mappings":"AAgBA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEvD"}
@@ -0,0 +1,16 @@
1
+ function sortValue(value) {
2
+ if (Array.isArray(value)) {
3
+ return value.map((entry) => sortValue(entry));
4
+ }
5
+ if (value !== null && typeof value === 'object') {
6
+ const entries = Object.entries(value)
7
+ .sort(([a], [b]) => a.localeCompare(b))
8
+ .map(([key, nested]) => [key, sortValue(nested)]);
9
+ return Object.fromEntries(entries);
10
+ }
11
+ return value;
12
+ }
13
+ export function canonicalizeJson(value) {
14
+ return JSON.stringify(sortValue(value));
15
+ }
16
+ //# sourceMappingURL=canonical.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../src/protocol/canonical.ts"],"names":[],"mappings":"AAAA,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;aAC7D,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;aACtC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAEpD,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Envelope, UnsignedEnvelope } from '../types/index.js';
2
+ export declare function buildSignatureInput<TPayload extends Record<string, unknown>>(envelope: UnsignedEnvelope<TPayload>): Uint8Array;
3
+ export declare function signEnvelope<TPayload extends Record<string, unknown>>(envelope: UnsignedEnvelope<TPayload>, signingSecretKeyB64: string): Promise<Envelope<TPayload>>;
4
+ export declare function verifyEnvelope<TPayload extends Record<string, unknown>>(envelope: Envelope<TPayload>, signingPublicKeyB64: string): Promise<boolean>;
5
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/protocol/envelope.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAIpE,wBAAgB,mBAAmB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1E,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAC,GACnC,UAAU,CAGZ;AAED,wBAAsB,YAAY,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzE,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EACpC,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAW7B;AAED,wBAAsB,cAAc,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3E,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAC5B,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC,CAclB"}
@@ -0,0 +1,27 @@
1
+ import { fromBase64, toBase64 } from '../crypto/base64.js';
2
+ import { sha256 } from '../crypto/hash.js';
3
+ import { initSodium } from '../crypto/sodium.js';
4
+ import { canonicalizeJson } from './canonical.js';
5
+ import { envelopeSchema } from './schemas.js';
6
+ export function buildSignatureInput(envelope) {
7
+ const canonical = canonicalizeJson(envelope);
8
+ return sha256(Buffer.from(canonical, 'utf8'));
9
+ }
10
+ export async function signEnvelope(envelope, signingSecretKeyB64) {
11
+ const sodium = await initSodium();
12
+ const signature = sodium.crypto_sign_detached(buildSignatureInput(envelope), fromBase64(signingSecretKeyB64));
13
+ return {
14
+ ...envelope,
15
+ sig: toBase64(signature),
16
+ };
17
+ }
18
+ export async function verifyEnvelope(envelope, signingPublicKeyB64) {
19
+ const parsed = envelopeSchema.safeParse(envelope);
20
+ if (!parsed.success) {
21
+ return false;
22
+ }
23
+ const sodium = await initSodium();
24
+ const { sig, ...unsignedEnvelope } = envelope;
25
+ return sodium.crypto_sign_verify_detached(fromBase64(sig), buildSignatureInput(unsignedEnvelope), fromBase64(signingPublicKeyB64));
26
+ }
27
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/protocol/envelope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,UAAU,mBAAmB,CACjC,QAAoC;IAEpC,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAoC,EACpC,mBAA2B;IAE3B,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,MAAM,CAAC,oBAAoB,CAC3C,mBAAmB,CAAC,QAAQ,CAAC,EAC7B,UAAU,CAAC,mBAAmB,CAAC,CAChC,CAAC;IAEF,OAAO;QACL,GAAG,QAAQ;QACX,GAAG,EAAE,QAAQ,CAAC,SAAS,CAAC;KACzB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAA4B,EAC5B,mBAA2B;IAE3B,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,EAAE,GAAG,EAAE,GAAG,gBAAgB,EAAE,GAAG,QAAQ,CAAC;IAE9C,OAAO,MAAM,CAAC,2BAA2B,CACvC,UAAU,CAAC,GAAG,CAAC,EACf,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,UAAU,CAAC,mBAAmB,CAAC,CAChC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './canonical.js';
2
+ export * from './envelope.js';
3
+ export * from './schemas.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/protocol/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './canonical.js';
2
+ export * from './envelope.js';
3
+ export * from './schemas.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/protocol/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}