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.
Files changed (85) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +176 -0
  3. package/README.md +165 -0
  4. package/SECURITY.md +46 -0
  5. package/dist/agent/index.d.ts +112 -0
  6. package/dist/agent/index.d.ts.map +1 -0
  7. package/dist/agent/index.js +225 -0
  8. package/dist/agent/index.js.map +1 -0
  9. package/dist/client/index.d.ts +29 -0
  10. package/dist/client/index.d.ts.map +1 -0
  11. package/dist/client/index.js +41 -0
  12. package/dist/client/index.js.map +1 -0
  13. package/dist/contributions/index.d.ts +41 -0
  14. package/dist/contributions/index.d.ts.map +1 -0
  15. package/dist/contributions/index.js +48 -0
  16. package/dist/contributions/index.js.map +1 -0
  17. package/dist/crypto/canonicalize.d.ts +31 -0
  18. package/dist/crypto/canonicalize.d.ts.map +1 -0
  19. package/dist/crypto/canonicalize.js +36 -0
  20. package/dist/crypto/canonicalize.js.map +1 -0
  21. package/dist/crypto/did.d.ts +39 -0
  22. package/dist/crypto/did.d.ts.map +1 -0
  23. package/dist/crypto/did.js +82 -0
  24. package/dist/crypto/did.js.map +1 -0
  25. package/dist/crypto/encode.d.ts +34 -0
  26. package/dist/crypto/encode.d.ts.map +1 -0
  27. package/dist/crypto/encode.js +98 -0
  28. package/dist/crypto/encode.js.map +1 -0
  29. package/dist/crypto/fingerprint.d.ts +43 -0
  30. package/dist/crypto/fingerprint.d.ts.map +1 -0
  31. package/dist/crypto/fingerprint.js +61 -0
  32. package/dist/crypto/fingerprint.js.map +1 -0
  33. package/dist/crypto/nonce.d.ts +44 -0
  34. package/dist/crypto/nonce.d.ts.map +1 -0
  35. package/dist/crypto/nonce.js +69 -0
  36. package/dist/crypto/nonce.js.map +1 -0
  37. package/dist/crypto/sign.d.ts +52 -0
  38. package/dist/crypto/sign.d.ts.map +1 -0
  39. package/dist/crypto/sign.js +78 -0
  40. package/dist/crypto/sign.js.map +1 -0
  41. package/dist/crypto/sweep.d.ts +24 -0
  42. package/dist/crypto/sweep.d.ts.map +1 -0
  43. package/dist/crypto/sweep.js +40 -0
  44. package/dist/crypto/sweep.js.map +1 -0
  45. package/dist/crypto/verify.d.ts +27 -0
  46. package/dist/crypto/verify.d.ts.map +1 -0
  47. package/dist/crypto/verify.js +118 -0
  48. package/dist/crypto/verify.js.map +1 -0
  49. package/dist/errors/index.d.ts +86 -0
  50. package/dist/errors/index.d.ts.map +1 -0
  51. package/dist/errors/index.js +131 -0
  52. package/dist/errors/index.js.map +1 -0
  53. package/dist/identity/index.d.ts +100 -0
  54. package/dist/identity/index.d.ts.map +1 -0
  55. package/dist/identity/index.js +143 -0
  56. package/dist/identity/index.js.map +1 -0
  57. package/dist/index.d.ts +37 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +35 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/notes/index.d.ts +108 -0
  62. package/dist/notes/index.d.ts.map +1 -0
  63. package/dist/notes/index.js +251 -0
  64. package/dist/notes/index.js.map +1 -0
  65. package/dist/rooms/index.d.ts +138 -0
  66. package/dist/rooms/index.d.ts.map +1 -0
  67. package/dist/rooms/index.js +325 -0
  68. package/dist/rooms/index.js.map +1 -0
  69. package/dist/streaming/index.d.ts +72 -0
  70. package/dist/streaming/index.d.ts.map +1 -0
  71. package/dist/streaming/index.js +125 -0
  72. package/dist/streaming/index.js.map +1 -0
  73. package/dist/transport/http.d.ts +51 -0
  74. package/dist/transport/http.d.ts.map +1 -0
  75. package/dist/transport/http.js +132 -0
  76. package/dist/transport/http.js.map +1 -0
  77. package/dist/types/index.d.ts +148 -0
  78. package/dist/types/index.d.ts.map +1 -0
  79. package/dist/types/index.js +56 -0
  80. package/dist/types/index.js.map +1 -0
  81. package/dist/verification/index.d.ts +40 -0
  82. package/dist/verification/index.d.ts.map +1 -0
  83. package/dist/verification/index.js +69 -0
  84. package/dist/verification/index.js.map +1 -0
  85. 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"}