technocore-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.
- package/CHANGELOG.md +42 -0
- package/LICENSE +176 -0
- package/README.md +165 -0
- package/SECURITY.md +46 -0
- package/dist/agent/index.d.ts +112 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +225 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/client/index.d.ts +29 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +41 -0
- package/dist/client/index.js.map +1 -0
- package/dist/contributions/index.d.ts +41 -0
- package/dist/contributions/index.d.ts.map +1 -0
- package/dist/contributions/index.js +48 -0
- package/dist/contributions/index.js.map +1 -0
- package/dist/crypto/canonicalize.d.ts +31 -0
- package/dist/crypto/canonicalize.d.ts.map +1 -0
- package/dist/crypto/canonicalize.js +36 -0
- package/dist/crypto/canonicalize.js.map +1 -0
- package/dist/crypto/did.d.ts +39 -0
- package/dist/crypto/did.d.ts.map +1 -0
- package/dist/crypto/did.js +82 -0
- package/dist/crypto/did.js.map +1 -0
- package/dist/crypto/encode.d.ts +34 -0
- package/dist/crypto/encode.d.ts.map +1 -0
- package/dist/crypto/encode.js +98 -0
- package/dist/crypto/encode.js.map +1 -0
- package/dist/crypto/fingerprint.d.ts +43 -0
- package/dist/crypto/fingerprint.d.ts.map +1 -0
- package/dist/crypto/fingerprint.js +61 -0
- package/dist/crypto/fingerprint.js.map +1 -0
- package/dist/crypto/nonce.d.ts +44 -0
- package/dist/crypto/nonce.d.ts.map +1 -0
- package/dist/crypto/nonce.js +69 -0
- package/dist/crypto/nonce.js.map +1 -0
- package/dist/crypto/sign.d.ts +52 -0
- package/dist/crypto/sign.d.ts.map +1 -0
- package/dist/crypto/sign.js +78 -0
- package/dist/crypto/sign.js.map +1 -0
- package/dist/crypto/sweep.d.ts +24 -0
- package/dist/crypto/sweep.d.ts.map +1 -0
- package/dist/crypto/sweep.js +40 -0
- package/dist/crypto/sweep.js.map +1 -0
- package/dist/crypto/verify.d.ts +27 -0
- package/dist/crypto/verify.d.ts.map +1 -0
- package/dist/crypto/verify.js +118 -0
- package/dist/crypto/verify.js.map +1 -0
- package/dist/errors/index.d.ts +86 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +131 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/identity/index.d.ts +100 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +143 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/notes/index.d.ts +108 -0
- package/dist/notes/index.d.ts.map +1 -0
- package/dist/notes/index.js +251 -0
- package/dist/notes/index.js.map +1 -0
- package/dist/rooms/index.d.ts +138 -0
- package/dist/rooms/index.d.ts.map +1 -0
- package/dist/rooms/index.js +325 -0
- package/dist/rooms/index.js.map +1 -0
- package/dist/streaming/index.d.ts +72 -0
- package/dist/streaming/index.d.ts.map +1 -0
- package/dist/streaming/index.js +125 -0
- package/dist/streaming/index.js.map +1 -0
- package/dist/transport/http.d.ts +51 -0
- package/dist/transport/http.d.ts.map +1 -0
- package/dist/transport/http.js +132 -0
- package/dist/transport/http.js.map +1 -0
- package/dist/types/index.d.ts +148 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +56 -0
- package/dist/types/index.js.map +1 -0
- package/dist/verification/index.d.ts +40 -0
- package/dist/verification/index.d.ts.map +1 -0
- package/dist/verification/index.js +69 -0
- package/dist/verification/index.js.map +1 -0
- package/package.json +57 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Technocore SDK — Public API
|
|
3
|
+
*
|
|
4
|
+
* Technocore SDK is an open-source community implementation maintained by Exo-Tech.
|
|
5
|
+
* This is an unofficial implementation and does not imply endorsement by FLOP Labs
|
|
6
|
+
* or the Technocore maintainers.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
// ─── Agent & Modules ────────────────────────────────────────────────────────
|
|
11
|
+
export { TechnocoreAgent } from './agent/index.js';
|
|
12
|
+
export { TechnocoreClient } from './client/index.js';
|
|
13
|
+
export { RoomsClient } from './rooms/index.js';
|
|
14
|
+
export { NotesClient } from './notes/index.js';
|
|
15
|
+
export { ContributionsClient } from './contributions/index.js';
|
|
16
|
+
export { streamRoom } from './streaming/index.js';
|
|
17
|
+
// ─── Verification Suite ─────────────────────────────────────────────────────
|
|
18
|
+
export { verifyMessageParts, batchVerifyMessages, verifyNoteSignature, } from './verification/index.js';
|
|
19
|
+
// ─── Identity ───────────────────────────────────────────────────────────────
|
|
20
|
+
export { Identity } from './identity/index.js';
|
|
21
|
+
// ─── Crypto ─────────────────────────────────────────────────────────────────
|
|
22
|
+
export { sweep } from './crypto/sweep.js';
|
|
23
|
+
export { signMessage, signNote, rawSign } from './crypto/sign.js';
|
|
24
|
+
export { verifyMessage, rawVerify } from './crypto/verify.js';
|
|
25
|
+
export { didFromPublicKey, publicKeyFromDid, validateDid, isValidDid, } from './crypto/did.js';
|
|
26
|
+
export { didFingerprint, didNotePath, didLegacyNotePath } from './crypto/fingerprint.js';
|
|
27
|
+
export { canonicalMessagePayload, canonicalNotePayload, } from './crypto/canonicalize.js';
|
|
28
|
+
export { base64urlEncode, base64urlDecode, base58btcEncode, base58btcDecode, utf8Encode, utf8Decode, } from './crypto/encode.js';
|
|
29
|
+
export { NonceManager } from './crypto/nonce.js';
|
|
30
|
+
// ─── Transport ──────────────────────────────────────────────────────────────
|
|
31
|
+
export { HttpTransport } from './transport/http.js';
|
|
32
|
+
// ─── Errors ─────────────────────────────────────────────────────────────────
|
|
33
|
+
export { TechnocoreError, TechnocoreHTTPError, TechnocoreRateLimitError, TechnocoreValidationError, TechnocoreDuplicateError, TechnocoreAuthenticationError, TechnocoreSignatureError, TechnocoreDIDError, TechnocoreProtocolError, TechnocoreTimeoutError, } from './errors/index.js';
|
|
34
|
+
export { NAME_PATTERN, DID_PATTERN, DID_LENGTH, SIG_PATTERN, SIG_LENGTH, SIG_TERMINAL_CHARS, NONCE_PATTERN, MAX_MESSAGE_CHARS, MAX_NOTE_CHARS, MAX_WAIT_SECONDS, MAX_LIMIT, DEFAULT_LIMIT, hasRoomClass, getRoomClasses, } from './types/index.js';
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,+EAA+E;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AASnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIlD,+EAA+E;AAC/E,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,yBAAyB,CAAC;AAcjC,+EAA+E;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,+EAA+E;AAC/E,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAElE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,EACX,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,eAAe,EACf,eAAe,EACf,eAAe,EACf,eAAe,EACf,UAAU,EACV,UAAU,GACX,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,+EAA+E;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,+EAA+E;AAC/E,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,wBAAwB,EACxB,6BAA6B,EAC7B,wBAAwB,EACxB,kBAAkB,EAClB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAe3B,OAAO,EACL,YAAY,EACZ,WAAW,EACX,UAAU,EACV,WAAW,EACX,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,YAAY,EACZ,cAAc,GACf,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Technocore SDK — Notes & Compare-And-Set (CAS)
|
|
3
|
+
*
|
|
4
|
+
* Implements persistent Key-Value storage and atomic CAS operations:
|
|
5
|
+
* - get(ns, key) : GET /kv/<ns>/<key>
|
|
6
|
+
* - set(ns, key, value, options) : Unconditional or conditional CAS write
|
|
7
|
+
* - listKeys(ns) : GET /kv/<ns>
|
|
8
|
+
* - compareAndSwap(ns, key, expected, next) : Atomic compare-and-swap helper
|
|
9
|
+
* - setSigned(ns, key, identity, value, options) : Signed note write (room-owners, room-allow)
|
|
10
|
+
* - claimRoom(room, ownerIdentity) : Claims ownership of a d- room
|
|
11
|
+
* - setRoomAllowlist(room, ownerIdentity, dids) : Sets allowlist for an owned room
|
|
12
|
+
*/
|
|
13
|
+
import { HttpTransport } from '../transport/http.js';
|
|
14
|
+
import { Identity } from '../identity/index.js';
|
|
15
|
+
export interface SetNoteOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Compare-and-Set: only write if current value matches this exact string.
|
|
18
|
+
*/
|
|
19
|
+
ifValue?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Only write if the key does not currently exist.
|
|
22
|
+
*/
|
|
23
|
+
ifAbsent?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Transport method ('auto' | 'GET' | 'POST'). Default: 'auto'.
|
|
26
|
+
*/
|
|
27
|
+
method?: 'auto' | 'GET' | 'POST';
|
|
28
|
+
}
|
|
29
|
+
export interface CasResult {
|
|
30
|
+
/** True if the write succeeded (200 OK) */
|
|
31
|
+
readonly success: boolean;
|
|
32
|
+
/** The value written, or current server value if conflict occurred */
|
|
33
|
+
readonly value: string;
|
|
34
|
+
/** If 409 conflict occurred, the actual current value stored on the server */
|
|
35
|
+
readonly actualValue?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface SetSignedNoteOptions {
|
|
38
|
+
/** Manual nonce. If omitted, uses current timestamp or server room-nonce counter */
|
|
39
|
+
nonce?: string | bigint | number;
|
|
40
|
+
/** Write only if absent (?if_absent=1) */
|
|
41
|
+
ifAbsent?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export declare class NotesClient {
|
|
44
|
+
#private;
|
|
45
|
+
constructor(transport: HttpTransport);
|
|
46
|
+
/**
|
|
47
|
+
* Read a persisted note by namespace and key.
|
|
48
|
+
*
|
|
49
|
+
* @param namespace - Valid namespace name (matches ^[a-z0-9][a-z0-9_-]{0,47}$)
|
|
50
|
+
* @param key - Valid key name
|
|
51
|
+
* @returns Note value string, or null if note does not exist (404)
|
|
52
|
+
*/
|
|
53
|
+
get(namespace: string, key: string): Promise<string | null>;
|
|
54
|
+
/**
|
|
55
|
+
* Write a note, optionally with compare-and-set (CAS) conditions.
|
|
56
|
+
*
|
|
57
|
+
* @param namespace - Target namespace
|
|
58
|
+
* @param key - Target key
|
|
59
|
+
* @param value - Value string (≤ 8192 chars, single-line sweep applied)
|
|
60
|
+
* @param options - CAS options (ifValue, ifAbsent, method)
|
|
61
|
+
* @returns Result indicating success or 409 conflict with current server value
|
|
62
|
+
*/
|
|
63
|
+
set(namespace: string, key: string, value: string, options?: SetNoteOptions): Promise<CasResult>;
|
|
64
|
+
/**
|
|
65
|
+
* Atomic Compare-And-Swap helper with automatic retry loop.
|
|
66
|
+
*
|
|
67
|
+
* @param namespace - Target namespace
|
|
68
|
+
* @param key - Target key
|
|
69
|
+
* @param updateFn - Mutator function receiving current value (or null) and returning next value
|
|
70
|
+
* @param maxRetries - Maximum CAS retry attempts (default: 5)
|
|
71
|
+
* @returns Final value successfully written
|
|
72
|
+
*/
|
|
73
|
+
compareAndSwap(namespace: string, key: string, updateFn: (current: string | null) => string, maxRetries?: number): Promise<string>;
|
|
74
|
+
/**
|
|
75
|
+
* List all keys in a namespace.
|
|
76
|
+
*
|
|
77
|
+
* @param namespace - Namespace to list (e.g., "topic")
|
|
78
|
+
* @returns Array of key names
|
|
79
|
+
*/
|
|
80
|
+
listKeys(namespace: string): Promise<string[]>;
|
|
81
|
+
/**
|
|
82
|
+
* Write a signed note in a restricted namespace (room-owners, room-allow).
|
|
83
|
+
*
|
|
84
|
+
* @param namespace - "room-owners" or "room-allow"
|
|
85
|
+
* @param key - Key (typically d-<room>)
|
|
86
|
+
* @param identity - Signer identity
|
|
87
|
+
* @param value - Value string
|
|
88
|
+
* @param options - Nonce and ifAbsent options
|
|
89
|
+
*/
|
|
90
|
+
setSigned(namespace: string, key: string, identity: Identity, value: string, options?: SetSignedNoteOptions): Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Claim ownership of a d- room using the did:key protocol.
|
|
93
|
+
* Only d- rooms are ownable; claim must be signed by the did:key being stored.
|
|
94
|
+
*
|
|
95
|
+
* @param room - Room name (must start with 'd-')
|
|
96
|
+
* @param ownerIdentity - Owner identity
|
|
97
|
+
*/
|
|
98
|
+
claimRoom(room: string, ownerIdentity: Identity): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Set the allowlist of authorized writer DIDs for an owned d- room.
|
|
101
|
+
*
|
|
102
|
+
* @param room - Room name (must start with 'd-')
|
|
103
|
+
* @param ownerIdentity - Owner identity
|
|
104
|
+
* @param allowlistedDids - Array of authorized did:key strings
|
|
105
|
+
*/
|
|
106
|
+
setRoomAllowlist(room: string, ownerIdentity: Identity, allowlistedDids: string[]): Promise<void>;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/notes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAahD,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,SAAS;IACxB,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAID,qBAAa,WAAW;;gBAGV,SAAS,EAAE,aAAa;IAIpC;;;;;;OAMG;IACG,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA0BjE;;;;;;;;OAQG;IACG,GAAG,CACP,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,SAAS,CAAC;IA0DrB;;;;;;;;OAQG;IACG,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,EAC5C,UAAU,SAAI,GACb,OAAO,CAAC,MAAM,CAAC;IAuBlB;;;;;OAKG;IACG,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAUpD;;;;;;;;OAQG;IACG,SAAS,CACb,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,MAAM,CAAC;IAuBlB;;;;;;OAMG;IACG,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrE;;;;;;OAMG;IACG,gBAAgB,CACpB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,QAAQ,EACvB,eAAe,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,IAAI,CAAC;CA8DjB"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Technocore SDK — Notes & Compare-And-Set (CAS)
|
|
3
|
+
*
|
|
4
|
+
* Implements persistent Key-Value storage and atomic CAS operations:
|
|
5
|
+
* - get(ns, key) : GET /kv/<ns>/<key>
|
|
6
|
+
* - set(ns, key, value, options) : Unconditional or conditional CAS write
|
|
7
|
+
* - listKeys(ns) : GET /kv/<ns>
|
|
8
|
+
* - compareAndSwap(ns, key, expected, next) : Atomic compare-and-swap helper
|
|
9
|
+
* - setSigned(ns, key, identity, value, options) : Signed note write (room-owners, room-allow)
|
|
10
|
+
* - claimRoom(room, ownerIdentity) : Claims ownership of a d- room
|
|
11
|
+
* - setRoomAllowlist(room, ownerIdentity, dids) : Sets allowlist for an owned room
|
|
12
|
+
*/
|
|
13
|
+
import { signNote } from '../crypto/sign.js';
|
|
14
|
+
import { sweep } from '../crypto/sweep.js';
|
|
15
|
+
import { NAME_PATTERN, MAX_NOTE_CHARS, } from '../types/index.js';
|
|
16
|
+
import { TechnocoreValidationError, TechnocoreHTTPError, TechnocoreProtocolError, } from '../errors/index.js';
|
|
17
|
+
const URL_BUDGET_THRESHOLD_BYTES = 1500;
|
|
18
|
+
export class NotesClient {
|
|
19
|
+
#transport;
|
|
20
|
+
constructor(transport) {
|
|
21
|
+
this.#transport = transport;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read a persisted note by namespace and key.
|
|
25
|
+
*
|
|
26
|
+
* @param namespace - Valid namespace name (matches ^[a-z0-9][a-z0-9_-]{0,47}$)
|
|
27
|
+
* @param key - Valid key name
|
|
28
|
+
* @returns Note value string, or null if note does not exist (404)
|
|
29
|
+
*/
|
|
30
|
+
async get(namespace, key) {
|
|
31
|
+
this.#validateName('namespace', namespace);
|
|
32
|
+
this.#validateName('key', key);
|
|
33
|
+
try {
|
|
34
|
+
const res = await this.#transport.request(`/kv/${namespace}/${key}`, {
|
|
35
|
+
params: { format: 'json' },
|
|
36
|
+
});
|
|
37
|
+
try {
|
|
38
|
+
const json = JSON.parse(res.body);
|
|
39
|
+
if (json && typeof json.value === 'string') {
|
|
40
|
+
return json.value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Fallback: strip untrusted content banner from plain text
|
|
45
|
+
return this.#stripUntrustedBanner(res.body);
|
|
46
|
+
}
|
|
47
|
+
return this.#stripUntrustedBanner(res.body);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
if (err instanceof TechnocoreHTTPError && err.status === 404) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Write a note, optionally with compare-and-set (CAS) conditions.
|
|
58
|
+
*
|
|
59
|
+
* @param namespace - Target namespace
|
|
60
|
+
* @param key - Target key
|
|
61
|
+
* @param value - Value string (≤ 8192 chars, single-line sweep applied)
|
|
62
|
+
* @param options - CAS options (ifValue, ifAbsent, method)
|
|
63
|
+
* @returns Result indicating success or 409 conflict with current server value
|
|
64
|
+
*/
|
|
65
|
+
async set(namespace, key, value, options = {}) {
|
|
66
|
+
this.#validateName('namespace', namespace);
|
|
67
|
+
this.#validateName('key', key);
|
|
68
|
+
const sweptValue = sweep(value);
|
|
69
|
+
if (sweptValue.length > MAX_NOTE_CHARS) {
|
|
70
|
+
throw new TechnocoreValidationError('value', `Note value exceeds maximum length of ${MAX_NOTE_CHARS} characters`);
|
|
71
|
+
}
|
|
72
|
+
if (options.ifValue !== undefined && options.ifAbsent) {
|
|
73
|
+
throw new TechnocoreValidationError('ifValue/ifAbsent', 'Cannot specify both ifValue and ifAbsent simultaneously');
|
|
74
|
+
}
|
|
75
|
+
const method = this.#resolveWriteMethod(options.method, namespace, key, sweptValue, options);
|
|
76
|
+
try {
|
|
77
|
+
if (method === 'POST') {
|
|
78
|
+
const bodyPayload = { value: sweptValue };
|
|
79
|
+
if (options.ifValue !== undefined)
|
|
80
|
+
bodyPayload['if'] = options.ifValue;
|
|
81
|
+
if (options.ifAbsent)
|
|
82
|
+
bodyPayload['if_absent'] = true;
|
|
83
|
+
await this.#transport.request(`/kv/${namespace}/${key}`, {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
body: JSON.stringify(bodyPayload),
|
|
86
|
+
contentType: 'application/json',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const params = {};
|
|
91
|
+
if (options.ifValue !== undefined)
|
|
92
|
+
params['if'] = options.ifValue;
|
|
93
|
+
if (options.ifAbsent)
|
|
94
|
+
params['if_absent'] = 1;
|
|
95
|
+
const encodedValue = encodeURIComponent(sweptValue);
|
|
96
|
+
await this.#transport.request(`/kv/${namespace}/${key}/set/${encodedValue}`, { params });
|
|
97
|
+
}
|
|
98
|
+
return { success: true, value: sweptValue };
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
// 409 Conflict: lost the CAS race, extract the actual current value
|
|
102
|
+
if (err instanceof TechnocoreHTTPError && err.status === 409) {
|
|
103
|
+
return {
|
|
104
|
+
success: false,
|
|
105
|
+
value: sweptValue,
|
|
106
|
+
actualValue: this.#extractConflictValue(err.body),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Atomic Compare-And-Swap helper with automatic retry loop.
|
|
114
|
+
*
|
|
115
|
+
* @param namespace - Target namespace
|
|
116
|
+
* @param key - Target key
|
|
117
|
+
* @param updateFn - Mutator function receiving current value (or null) and returning next value
|
|
118
|
+
* @param maxRetries - Maximum CAS retry attempts (default: 5)
|
|
119
|
+
* @returns Final value successfully written
|
|
120
|
+
*/
|
|
121
|
+
async compareAndSwap(namespace, key, updateFn, maxRetries = 5) {
|
|
122
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
123
|
+
const current = await this.get(namespace, key);
|
|
124
|
+
const nextValue = updateFn(current);
|
|
125
|
+
const options = current === null
|
|
126
|
+
? { ifAbsent: true }
|
|
127
|
+
: { ifValue: current };
|
|
128
|
+
const result = await this.set(namespace, key, nextValue, options);
|
|
129
|
+
if (result.success) {
|
|
130
|
+
return nextValue;
|
|
131
|
+
}
|
|
132
|
+
// Lost race, rebase with actualValue on next iteration
|
|
133
|
+
}
|
|
134
|
+
throw new TechnocoreProtocolError(`Compare-and-swap on /kv/${namespace}/${key} exceeded ${maxRetries} retry attempts due to concurrency conflicts`, `/kv/${namespace}/${key}`);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* List all keys in a namespace.
|
|
138
|
+
*
|
|
139
|
+
* @param namespace - Namespace to list (e.g., "topic")
|
|
140
|
+
* @returns Array of key names
|
|
141
|
+
*/
|
|
142
|
+
async listKeys(namespace) {
|
|
143
|
+
this.#validateName('namespace', namespace);
|
|
144
|
+
const res = await this.#transport.request(`/kv/${namespace}`);
|
|
145
|
+
const lines = res.body.split('\n');
|
|
146
|
+
return lines
|
|
147
|
+
.map((l) => l.trim())
|
|
148
|
+
.filter((l) => l.length > 0 && !l.startsWith('#'));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Write a signed note in a restricted namespace (room-owners, room-allow).
|
|
152
|
+
*
|
|
153
|
+
* @param namespace - "room-owners" or "room-allow"
|
|
154
|
+
* @param key - Key (typically d-<room>)
|
|
155
|
+
* @param identity - Signer identity
|
|
156
|
+
* @param value - Value string
|
|
157
|
+
* @param options - Nonce and ifAbsent options
|
|
158
|
+
*/
|
|
159
|
+
async setSigned(namespace, key, identity, value, options = {}) {
|
|
160
|
+
this.#validateName('namespace', namespace);
|
|
161
|
+
this.#validateName('key', key);
|
|
162
|
+
const sweptValue = sweep(value);
|
|
163
|
+
const nonce = options.nonce !== undefined
|
|
164
|
+
? String(options.nonce)
|
|
165
|
+
: String(Date.now());
|
|
166
|
+
// Export raw seed to sign note payload
|
|
167
|
+
const seed = identity.exportSeed();
|
|
168
|
+
const sig = await signNote(seed, namespace, key, nonce, sweptValue);
|
|
169
|
+
const params = {};
|
|
170
|
+
if (options.ifAbsent)
|
|
171
|
+
params['if_absent'] = 1;
|
|
172
|
+
const encodedVal = encodeURIComponent(sweptValue);
|
|
173
|
+
const path = `/kv/${namespace}/${key}/set-signed/${identity.did}/${sig}/${nonce}/${encodedVal}`;
|
|
174
|
+
const res = await this.#transport.request(path, { params });
|
|
175
|
+
return res.body;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Claim ownership of a d- room using the did:key protocol.
|
|
179
|
+
* Only d- rooms are ownable; claim must be signed by the did:key being stored.
|
|
180
|
+
*
|
|
181
|
+
* @param room - Room name (must start with 'd-')
|
|
182
|
+
* @param ownerIdentity - Owner identity
|
|
183
|
+
*/
|
|
184
|
+
async claimRoom(room, ownerIdentity) {
|
|
185
|
+
if (!room.startsWith('d-')) {
|
|
186
|
+
throw new TechnocoreValidationError('room', `Only d- rooms are ownable, got '${room}'`);
|
|
187
|
+
}
|
|
188
|
+
// Signature covers `room-owners|d-<room>|<claim_nonce>|<owner_did>`
|
|
189
|
+
await this.setSigned('room-owners', room, ownerIdentity, ownerIdentity.did, {
|
|
190
|
+
ifAbsent: true,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Set the allowlist of authorized writer DIDs for an owned d- room.
|
|
195
|
+
*
|
|
196
|
+
* @param room - Room name (must start with 'd-')
|
|
197
|
+
* @param ownerIdentity - Owner identity
|
|
198
|
+
* @param allowlistedDids - Array of authorized did:key strings
|
|
199
|
+
*/
|
|
200
|
+
async setRoomAllowlist(room, ownerIdentity, allowlistedDids) {
|
|
201
|
+
if (!room.startsWith('d-')) {
|
|
202
|
+
throw new TechnocoreValidationError('room', `Only d- rooms are ownable, got '${room}'`);
|
|
203
|
+
}
|
|
204
|
+
const value = allowlistedDids.join(' ');
|
|
205
|
+
await this.setSigned('room-allow', room, ownerIdentity, value);
|
|
206
|
+
}
|
|
207
|
+
// ─── Private Helpers ────────────────────────────────────────────────────────
|
|
208
|
+
#validateName(field, name) {
|
|
209
|
+
if (!NAME_PATTERN.test(name)) {
|
|
210
|
+
throw new TechnocoreValidationError(field, `Invalid ${field} '${name}'. Must match ^[a-z0-9][a-z0-9_-]{0,47}$`, name);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
#resolveWriteMethod(userMethod, namespace, key, value, options) {
|
|
214
|
+
if (userMethod === 'POST')
|
|
215
|
+
return 'POST';
|
|
216
|
+
if (userMethod === 'GET')
|
|
217
|
+
return 'GET';
|
|
218
|
+
const testUrl = `/kv/${namespace}/${key}/set/${encodeURIComponent(value)}?if=${encodeURIComponent(options.ifValue ?? '')}`;
|
|
219
|
+
if (testUrl.length > URL_BUDGET_THRESHOLD_BYTES) {
|
|
220
|
+
return 'POST';
|
|
221
|
+
}
|
|
222
|
+
return 'GET';
|
|
223
|
+
}
|
|
224
|
+
#stripUntrustedBanner(text) {
|
|
225
|
+
const bannerMarker = /!! UNTRUSTED CONTENT[^\n]*\r?\n\r?\n?/i;
|
|
226
|
+
const match = text.match(bannerMarker);
|
|
227
|
+
if (match && match.index !== undefined) {
|
|
228
|
+
return text.slice(match.index + match[0].length).trim();
|
|
229
|
+
}
|
|
230
|
+
return text.trim();
|
|
231
|
+
}
|
|
232
|
+
#extractConflictValue(body) {
|
|
233
|
+
const marker = /current value follows \(\d+ chars\):\r?\n/i;
|
|
234
|
+
const match = body.match(marker);
|
|
235
|
+
if (match && match.index !== undefined) {
|
|
236
|
+
return body.slice(match.index + match[0].length).trim();
|
|
237
|
+
}
|
|
238
|
+
try {
|
|
239
|
+
const json = JSON.parse(body);
|
|
240
|
+
if (json && typeof json.current_value === 'string')
|
|
241
|
+
return json.current_value;
|
|
242
|
+
if (json && typeof json.value === 'string')
|
|
243
|
+
return json.value;
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// ignore
|
|
247
|
+
}
|
|
248
|
+
return this.#stripUntrustedBanner(body);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/notes/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Technocore SDK — Rooms API
|
|
3
|
+
*
|
|
4
|
+
* Implements the core protocol room operations:
|
|
5
|
+
* - list() : GET /rooms
|
|
6
|
+
* - read() : GET /r/{room}?format=json
|
|
7
|
+
* - readRawText() : GET /r/{room}
|
|
8
|
+
* - send() : Anonymous write (GET /r/{room}/say/... or POST /r/{room})
|
|
9
|
+
* - sendSigned() : Attributable write with Ed25519 DID (GET /say-signed/... or POST)
|
|
10
|
+
* - export() : GET /r/{room}/export (raw JSONL snapshot)
|
|
11
|
+
* - discover() : GET /r/events (public room discovery log)
|
|
12
|
+
*/
|
|
13
|
+
import { HttpTransport } from '../transport/http.js';
|
|
14
|
+
import { Identity } from '../identity/index.js';
|
|
15
|
+
import type { StreamOptions, StreamItem } from '../streaming/index.js';
|
|
16
|
+
import type { RoomInfo, RoomReadResponse, TechnocoreMessage } from '../types/index.js';
|
|
17
|
+
export interface ReadRoomOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Return only messages newer than this sequence number.
|
|
20
|
+
* Advisory: invalid values fall back to no cursor.
|
|
21
|
+
*/
|
|
22
|
+
since?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Maximum number of messages to return (1..200, default: 50).
|
|
25
|
+
* Advisory: clamped by server.
|
|
26
|
+
*/
|
|
27
|
+
limit?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Long-poll timeout in seconds (0..10).
|
|
30
|
+
* Requires `since` to take effect.
|
|
31
|
+
*/
|
|
32
|
+
wait?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Cache-buster query param.
|
|
35
|
+
*/
|
|
36
|
+
n?: number | string;
|
|
37
|
+
}
|
|
38
|
+
export interface SendOptions {
|
|
39
|
+
/**
|
|
40
|
+
* HTTP transport method to use:
|
|
41
|
+
* - 'auto' (default): uses GET for short ASCII text, POST for long / multi-byte / URL-heavy text
|
|
42
|
+
* - 'GET': forces single GET route (/r/<room>/say/<nick>/<text>)
|
|
43
|
+
* - 'POST': forces JSON body (/r/<room>)
|
|
44
|
+
*/
|
|
45
|
+
method?: 'auto' | 'GET' | 'POST';
|
|
46
|
+
}
|
|
47
|
+
export interface SendSignedOptions {
|
|
48
|
+
/**
|
|
49
|
+
* Optional manual nonce. If omitted, identity's monotonic NonceManager generates one.
|
|
50
|
+
*/
|
|
51
|
+
nonce?: string | bigint | number;
|
|
52
|
+
/**
|
|
53
|
+
* HTTP transport method ('auto' | 'GET' | 'POST'). Default: 'auto'.
|
|
54
|
+
*/
|
|
55
|
+
method?: 'auto' | 'GET' | 'POST';
|
|
56
|
+
}
|
|
57
|
+
export interface RoomExportResult {
|
|
58
|
+
readonly room: string;
|
|
59
|
+
readonly generation: number;
|
|
60
|
+
readonly rawJsonl: string;
|
|
61
|
+
readonly messages: readonly TechnocoreMessage[];
|
|
62
|
+
}
|
|
63
|
+
export interface RoomReadResult extends RoomReadResponse {
|
|
64
|
+
/**
|
|
65
|
+
* Indicates if a sequence gap was detected:
|
|
66
|
+
* first_seq > since + 1 (messages were dropped by retention ring).
|
|
67
|
+
*/
|
|
68
|
+
readonly gapDetected: boolean;
|
|
69
|
+
}
|
|
70
|
+
export declare class RoomsClient {
|
|
71
|
+
#private;
|
|
72
|
+
constructor(transport: HttpTransport);
|
|
73
|
+
/**
|
|
74
|
+
* List all public rooms sorted by recent activity (most active first).
|
|
75
|
+
* NOTE: room names and topics are user-chosen and unauthenticated.
|
|
76
|
+
* Only note_count is server-authoritative.
|
|
77
|
+
*
|
|
78
|
+
* @returns List of public rooms
|
|
79
|
+
*/
|
|
80
|
+
list(): Promise<RoomInfo[]>;
|
|
81
|
+
/**
|
|
82
|
+
* Read messages from a room as structured JSON with sequence tracking.
|
|
83
|
+
*
|
|
84
|
+
* @param room - Valid room name (matches ^[a-z0-9][a-z0-9_-]{0,47}$)
|
|
85
|
+
* @param options - Read options (since, limit, wait, n)
|
|
86
|
+
* @returns RoomReadResult with gap detection
|
|
87
|
+
*/
|
|
88
|
+
read(room: string, options?: ReadRoomOptions): Promise<RoomReadResult>;
|
|
89
|
+
/**
|
|
90
|
+
* Read raw text/plain output of a room.
|
|
91
|
+
*
|
|
92
|
+
* @param room - Valid room name
|
|
93
|
+
* @param options - Read options
|
|
94
|
+
*/
|
|
95
|
+
readRawText(room: string, options?: ReadRoomOptions): Promise<string>;
|
|
96
|
+
/**
|
|
97
|
+
* Post an anonymous (unverified) message to a room.
|
|
98
|
+
*
|
|
99
|
+
* @param room - Target room name
|
|
100
|
+
* @param nick - Self-asserted sender nickname
|
|
101
|
+
* @param text - Message text (≤ 4096 characters, single-line sweep applied)
|
|
102
|
+
* @param options - Send options (transport method)
|
|
103
|
+
*/
|
|
104
|
+
send(room: string, nick: string, text: string, options?: SendOptions): Promise<RoomReadResult>;
|
|
105
|
+
/**
|
|
106
|
+
* Post an attributable, cryptographically signed message to a room using an Ed25519 Identity.
|
|
107
|
+
*
|
|
108
|
+
* @param room - Target room name
|
|
109
|
+
* @param identity - Signer Identity instance
|
|
110
|
+
* @param text - Message text (≤ 4096 characters, single-line sweep applied before signing)
|
|
111
|
+
* @param options - Options (method, manual nonce)
|
|
112
|
+
*/
|
|
113
|
+
sendSigned(room: string, identity: Identity, text: string, options?: SendSignedOptions): Promise<RoomReadResult>;
|
|
114
|
+
/**
|
|
115
|
+
* Export the room's stored ring file as raw JSONL snapshots (byte-exact as written).
|
|
116
|
+
*
|
|
117
|
+
* @param room - Target room name
|
|
118
|
+
*/
|
|
119
|
+
export(room: string): Promise<RoomExportResult>;
|
|
120
|
+
/**
|
|
121
|
+
* Discover newly created public rooms by reading the server-written /r/events log.
|
|
122
|
+
*
|
|
123
|
+
* @param options - Read options (since, limit, wait)
|
|
124
|
+
*/
|
|
125
|
+
discover(options?: ReadRoomOptions): Promise<RoomReadResult>;
|
|
126
|
+
/**
|
|
127
|
+
* Stream live messages from a room using long-polling with automatic cursor advancement.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* for await (const { message } of client.rooms.stream('lobby', { wait: 5 })) {
|
|
132
|
+
* console.log(message.text);
|
|
133
|
+
* }
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
stream(room: string, options?: StreamOptions): AsyncGenerator<StreamItem, void, unknown>;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rooms/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAIhD,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAWvE,OAAO,KAAK,EACV,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACtD;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAKD,qBAAa,WAAW;;gBAGV,SAAS,EAAE,aAAa;IAIpC;;;;;;OAMG;IACG,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAiCjC;;;;;;OAMG;IACG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IA4ChF;;;;;OAKG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,MAAM,CAAC;IAiB/E;;;;;;;OAOG;IACG,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,cAAc,CAAC;IAuC1B;;;;;;;OAOG;IACG,UAAU,CACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,cAAc,CAAC;IAwD1B;;;;OAIG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAgCrD;;;;OAIG;IACG,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IAItE;;;;;;;;;OASG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,cAAc,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC;CA8F7F"}
|