@bcts/hubert 1.0.0-alpha.17

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 (104) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +18 -0
  3. package/dist/arid-derivation-1CJuU-kZ.cjs +150 -0
  4. package/dist/arid-derivation-1CJuU-kZ.cjs.map +1 -0
  5. package/dist/arid-derivation-CbqACjdg.mjs +126 -0
  6. package/dist/arid-derivation-CbqACjdg.mjs.map +1 -0
  7. package/dist/bin/hubert.cjs +384 -0
  8. package/dist/bin/hubert.cjs.map +1 -0
  9. package/dist/bin/hubert.d.cts +1 -0
  10. package/dist/bin/hubert.d.mts +1 -0
  11. package/dist/bin/hubert.mjs +383 -0
  12. package/dist/bin/hubert.mjs.map +1 -0
  13. package/dist/chunk-CbDLau6x.cjs +34 -0
  14. package/dist/hybrid/index.cjs +14 -0
  15. package/dist/hybrid/index.d.cts +3 -0
  16. package/dist/hybrid/index.d.mts +3 -0
  17. package/dist/hybrid/index.mjs +6 -0
  18. package/dist/hybrid-BZhumygj.mjs +356 -0
  19. package/dist/hybrid-BZhumygj.mjs.map +1 -0
  20. package/dist/hybrid-dX5JLumO.cjs +410 -0
  21. package/dist/hybrid-dX5JLumO.cjs.map +1 -0
  22. package/dist/index-BEzpUC7r.d.mts +380 -0
  23. package/dist/index-BEzpUC7r.d.mts.map +1 -0
  24. package/dist/index-C2F6ugLL.d.mts +210 -0
  25. package/dist/index-C2F6ugLL.d.mts.map +1 -0
  26. package/dist/index-CUnDouMb.d.mts +215 -0
  27. package/dist/index-CUnDouMb.d.mts.map +1 -0
  28. package/dist/index-CV6lZJqY.d.cts +380 -0
  29. package/dist/index-CV6lZJqY.d.cts.map +1 -0
  30. package/dist/index-CY3TCzIm.d.cts +217 -0
  31. package/dist/index-CY3TCzIm.d.cts.map +1 -0
  32. package/dist/index-DEr4SR1J.d.cts +215 -0
  33. package/dist/index-DEr4SR1J.d.cts.map +1 -0
  34. package/dist/index-T1LHanIb.d.mts +217 -0
  35. package/dist/index-T1LHanIb.d.mts.map +1 -0
  36. package/dist/index-jyzuOhFB.d.cts +210 -0
  37. package/dist/index-jyzuOhFB.d.cts.map +1 -0
  38. package/dist/index.cjs +60 -0
  39. package/dist/index.d.cts +161 -0
  40. package/dist/index.d.cts.map +1 -0
  41. package/dist/index.d.mts +161 -0
  42. package/dist/index.d.mts.map +1 -0
  43. package/dist/index.mjs +10 -0
  44. package/dist/ipfs/index.cjs +13 -0
  45. package/dist/ipfs/index.d.cts +3 -0
  46. package/dist/ipfs/index.d.mts +3 -0
  47. package/dist/ipfs/index.mjs +5 -0
  48. package/dist/ipfs-BRMMCBjv.mjs +1 -0
  49. package/dist/ipfs-CetOVQcO.cjs +0 -0
  50. package/dist/kv-BAmhmMOo.cjs +425 -0
  51. package/dist/kv-BAmhmMOo.cjs.map +1 -0
  52. package/dist/kv-C-emxv0w.mjs +375 -0
  53. package/dist/kv-C-emxv0w.mjs.map +1 -0
  54. package/dist/kv-DJiKvypY.mjs +403 -0
  55. package/dist/kv-DJiKvypY.mjs.map +1 -0
  56. package/dist/kv-store-DmngWWuw.d.mts +183 -0
  57. package/dist/kv-store-DmngWWuw.d.mts.map +1 -0
  58. package/dist/kv-store-ww-AUyLd.d.cts +183 -0
  59. package/dist/kv-store-ww-AUyLd.d.cts.map +1 -0
  60. package/dist/kv-yjvQa_LH.cjs +457 -0
  61. package/dist/kv-yjvQa_LH.cjs.map +1 -0
  62. package/dist/logging-hmzNzifq.mjs +158 -0
  63. package/dist/logging-hmzNzifq.mjs.map +1 -0
  64. package/dist/logging-qc9uMgil.cjs +212 -0
  65. package/dist/logging-qc9uMgil.cjs.map +1 -0
  66. package/dist/mainline/index.cjs +12 -0
  67. package/dist/mainline/index.d.cts +3 -0
  68. package/dist/mainline/index.d.mts +3 -0
  69. package/dist/mainline/index.mjs +5 -0
  70. package/dist/mainline-D_jfeFMh.cjs +0 -0
  71. package/dist/mainline-cFIuXbo-.mjs +1 -0
  72. package/dist/server/index.cjs +14 -0
  73. package/dist/server/index.d.cts +3 -0
  74. package/dist/server/index.d.mts +3 -0
  75. package/dist/server/index.mjs +3 -0
  76. package/dist/server-BBNRZ30D.cjs +912 -0
  77. package/dist/server-BBNRZ30D.cjs.map +1 -0
  78. package/dist/server-DVyk9gqU.mjs +836 -0
  79. package/dist/server-DVyk9gqU.mjs.map +1 -0
  80. package/package.json +125 -0
  81. package/src/arid-derivation.ts +155 -0
  82. package/src/bin/hubert.ts +667 -0
  83. package/src/error.ts +89 -0
  84. package/src/hybrid/error.ts +77 -0
  85. package/src/hybrid/index.ts +24 -0
  86. package/src/hybrid/kv.ts +236 -0
  87. package/src/hybrid/reference.ts +176 -0
  88. package/src/index.ts +145 -0
  89. package/src/ipfs/error.ts +83 -0
  90. package/src/ipfs/index.ts +24 -0
  91. package/src/ipfs/kv.ts +476 -0
  92. package/src/ipfs/value.ts +85 -0
  93. package/src/kv-store.ts +128 -0
  94. package/src/logging.ts +88 -0
  95. package/src/mainline/error.ts +108 -0
  96. package/src/mainline/index.ts +23 -0
  97. package/src/mainline/kv.ts +411 -0
  98. package/src/server/error.ts +83 -0
  99. package/src/server/index.ts +29 -0
  100. package/src/server/kv.ts +211 -0
  101. package/src/server/memory-kv.ts +191 -0
  102. package/src/server/server-kv.ts +92 -0
  103. package/src/server/server.ts +369 -0
  104. package/src/server/sqlite-kv.ts +295 -0
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Server module for Hubert distributed storage.
3
+ *
4
+ * This module provides server-side storage implementations and the HTTP server.
5
+ *
6
+ * Port of server/mod.rs from hubert-rust.
7
+ *
8
+ * @module
9
+ */
10
+
11
+ // Error types
12
+ export {
13
+ ServerError,
14
+ ServerGeneralError,
15
+ ServerNetworkError,
16
+ ServerParseError,
17
+ SqliteError,
18
+ } from "./error.js";
19
+
20
+ // Storage backends
21
+ export { MemoryKv } from "./memory-kv.js";
22
+ export { SqliteKv } from "./sqlite-kv.js";
23
+ export { type ServerKv, createMemoryKv, createSqliteKv } from "./server-kv.js";
24
+
25
+ // HTTP server
26
+ export { Server, type ServerConfig, defaultServerConfig } from "./server.js";
27
+
28
+ // HTTP client
29
+ export { ServerKvClient } from "./kv.js";
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Server-backed key-value store using HTTP API.
3
+ *
4
+ * Port of server/kv.rs from hubert-rust.
5
+ *
6
+ * @module
7
+ */
8
+
9
+ import { type ARID } from "@bcts/components";
10
+ import { Envelope } from "@bcts/envelope";
11
+
12
+ import { AlreadyExistsError } from "../error.js";
13
+ import { type KvStore } from "../kv-store.js";
14
+ import { verboseNewline, verbosePrintDot, verbosePrintln } from "../logging.js";
15
+ import { ServerGeneralError, ServerNetworkError, ServerParseError } from "./error.js";
16
+
17
+ /**
18
+ * Server-backed key-value store using HTTP API.
19
+ *
20
+ * This implementation communicates with a Hubert server via HTTP POST requests.
21
+ *
22
+ * Port of `struct ServerKvClient` from server/kv.rs lines 6-37.
23
+ *
24
+ * @category Server Backend
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const store = new ServerKvClient("http://127.0.0.1:45678");
29
+ * const arid = ARID.new();
30
+ * const envelope = Envelope.new("Hello, Server!");
31
+ *
32
+ * // Put envelope (write-once)
33
+ * await store.put(arid, envelope);
34
+ *
35
+ * // Get envelope with verbose logging
36
+ * const retrieved = await store.get(arid, undefined, true);
37
+ * ```
38
+ */
39
+ export class ServerKvClient implements KvStore {
40
+ private readonly baseUrl: string;
41
+
42
+ /**
43
+ * Create a new server KV store client.
44
+ *
45
+ * Port of `ServerKvClient::new()` from server/kv.rs lines 39-46.
46
+ *
47
+ * @param baseUrl - Base URL of the Hubert server (e.g., "http://127.0.0.1:45678")
48
+ */
49
+ constructor(baseUrl: string) {
50
+ this.baseUrl = baseUrl;
51
+ }
52
+
53
+ /**
54
+ * Store an envelope at the given ARID.
55
+ *
56
+ * Port of `KvStore::put()` implementation from server/kv.rs lines 67-122.
57
+ */
58
+ async put(
59
+ arid: ARID,
60
+ envelope: Envelope,
61
+ ttlSeconds?: number,
62
+ verbose?: boolean,
63
+ ): Promise<string> {
64
+ if (verbose) {
65
+ verbosePrintln("Starting server put operation");
66
+ }
67
+
68
+ // Format body with optional TTL on third line
69
+ let body: string;
70
+ if (ttlSeconds !== undefined) {
71
+ body = `${arid.urString()}\n${envelope.urString()}\n${ttlSeconds}`;
72
+ } else {
73
+ body = `${arid.urString()}\n${envelope.urString()}`;
74
+ }
75
+
76
+ if (verbose) {
77
+ verbosePrintln("Sending PUT request to server");
78
+ }
79
+
80
+ try {
81
+ const response = await fetch(`${this.baseUrl}/put`, {
82
+ method: "POST",
83
+ body,
84
+ headers: {
85
+ "Content-Type": "text/plain",
86
+ },
87
+ });
88
+
89
+ if (response.status === 200) {
90
+ if (verbose) {
91
+ verbosePrintln("Server put operation completed");
92
+ }
93
+ return "Stored successfully";
94
+ } else if (response.status === 409) {
95
+ if (verbose) {
96
+ verbosePrintln("Server put operation failed");
97
+ }
98
+ throw new AlreadyExistsError(arid.urString());
99
+ } else {
100
+ if (verbose) {
101
+ verbosePrintln("Server put operation failed");
102
+ }
103
+ const errorMsg = await response.text();
104
+ throw new ServerGeneralError(errorMsg);
105
+ }
106
+ } catch (error) {
107
+ if (error instanceof AlreadyExistsError || error instanceof ServerGeneralError) {
108
+ throw error;
109
+ }
110
+ throw new ServerNetworkError(error instanceof Error ? error.message : String(error));
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Retrieve an envelope for the given ARID.
116
+ *
117
+ * Port of `KvStore::get()` implementation from server/kv.rs lines 124-212.
118
+ */
119
+ async get(arid: ARID, timeoutSeconds?: number, verbose?: boolean): Promise<Envelope | null> {
120
+ let printedDot = false;
121
+
122
+ if (verbose) {
123
+ verbosePrintln("Starting server get operation");
124
+ }
125
+
126
+ const timeout = timeoutSeconds ?? 30; // Default 30 seconds
127
+ const deadline = Date.now() + timeout * 1000;
128
+ // Changed to 1000ms for verbose mode polling
129
+ const pollInterval = 1000;
130
+
131
+ if (verbose) {
132
+ verbosePrintln("Polling server for value");
133
+ }
134
+
135
+ while (true) {
136
+ const body = arid.urString();
137
+
138
+ try {
139
+ const response = await fetch(`${this.baseUrl}/get`, {
140
+ method: "POST",
141
+ body,
142
+ headers: {
143
+ "Content-Type": "text/plain",
144
+ },
145
+ });
146
+
147
+ if (response.status === 200) {
148
+ if (verbose && printedDot) {
149
+ verboseNewline();
150
+ }
151
+ if (verbose) {
152
+ verbosePrintln("Value found on server");
153
+ }
154
+
155
+ const envelopeStr = await response.text();
156
+ try {
157
+ const envelope = Envelope.fromUrString(envelopeStr);
158
+
159
+ if (verbose) {
160
+ verbosePrintln("Server get operation completed");
161
+ }
162
+
163
+ return envelope;
164
+ } catch (error) {
165
+ throw new ServerParseError(error instanceof Error ? error.message : String(error));
166
+ }
167
+ } else if (response.status === 404) {
168
+ // Not found yet - check if we should keep polling
169
+ if (Date.now() >= deadline) {
170
+ // Timeout reached
171
+ if (verbose && printedDot) {
172
+ verboseNewline();
173
+ }
174
+ if (verbose) {
175
+ verbosePrintln("Timeout reached, value not found");
176
+ }
177
+ return null;
178
+ }
179
+
180
+ // Print polling dot if verbose
181
+ if (verbose) {
182
+ verbosePrintDot();
183
+ printedDot = true;
184
+ }
185
+
186
+ // Wait before retrying (now 1000ms)
187
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
188
+ } else {
189
+ const errorMsg = await response.text();
190
+ throw new ServerGeneralError(errorMsg);
191
+ }
192
+ } catch (error) {
193
+ if (error instanceof ServerGeneralError || error instanceof ServerParseError) {
194
+ throw error;
195
+ }
196
+ throw new ServerNetworkError(error instanceof Error ? error.message : String(error));
197
+ }
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Check if an envelope exists at the given ARID.
203
+ *
204
+ * Port of `KvStore::exists()` implementation from server/kv.rs lines 214-218.
205
+ */
206
+ async exists(arid: ARID): Promise<boolean> {
207
+ // Use a short timeout for exists check (1 second), no verbose
208
+ const result = await this.get(arid, 1, false);
209
+ return result !== null;
210
+ }
211
+ }
@@ -0,0 +1,191 @@
1
+ /**
2
+ * In-memory key-value store for Gordian Envelopes.
3
+ *
4
+ * Port of server/memory_kv.rs from hubert-rust.
5
+ *
6
+ * @module
7
+ */
8
+
9
+ import { type ARID } from "@bcts/components";
10
+ import { type Envelope } from "@bcts/envelope";
11
+
12
+ import { AlreadyExistsError } from "../error.js";
13
+ import { type KvStore } from "../kv-store.js";
14
+ import { verbosePrintln } from "../logging.js";
15
+
16
+ /**
17
+ * Storage entry with envelope data and optional expiration.
18
+ * @internal
19
+ */
20
+ interface StorageEntry {
21
+ /** CBOR-encoded envelope data */
22
+ envelopeCbor: Uint8Array;
23
+ /** Expiration timestamp in milliseconds, or undefined for no expiration */
24
+ expiresAt?: number;
25
+ }
26
+
27
+ /**
28
+ * In-memory key-value store for Gordian Envelopes.
29
+ *
30
+ * Provides volatile storage with TTL support and automatic cleanup of
31
+ * expired entries.
32
+ *
33
+ * Port of `struct MemoryKv` from server/memory_kv.rs lines 14-21.
34
+ *
35
+ * @category Server Backend
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const store = new MemoryKv();
40
+ * const arid = ARID.new();
41
+ * const envelope = Envelope.new("Hello, Memory!");
42
+ *
43
+ * await store.put(arid, envelope, 3600); // 1 hour TTL
44
+ * const result = await store.get(arid);
45
+ * ```
46
+ */
47
+ export class MemoryKv implements KvStore {
48
+ private readonly storage: Map<string, StorageEntry>;
49
+
50
+ /**
51
+ * Create a new in-memory key-value store.
52
+ *
53
+ * Port of `MemoryKv::new()` from server/memory_kv.rs lines 29-33.
54
+ */
55
+ constructor() {
56
+ this.storage = new Map();
57
+ }
58
+
59
+ /**
60
+ * Check if an ARID exists and is not expired.
61
+ *
62
+ * Port of `check_exists()` from server/memory_kv.rs lines 36-53.
63
+ *
64
+ * @internal
65
+ */
66
+ private checkExists(arid: ARID): boolean {
67
+ const key = arid.urString();
68
+ const entry = this.storage.get(key);
69
+
70
+ if (entry) {
71
+ if (entry.expiresAt !== undefined && Date.now() >= entry.expiresAt) {
72
+ // Entry is expired, remove it
73
+ this.storage.delete(key);
74
+ return false;
75
+ }
76
+ return true;
77
+ }
78
+ return false;
79
+ }
80
+
81
+ /**
82
+ * Store an envelope at the given ARID.
83
+ *
84
+ * Port of `KvStore::put()` implementation from server/memory_kv.rs lines 62-102.
85
+ */
86
+ // eslint-disable-next-line @typescript-eslint/require-await
87
+ async put(
88
+ arid: ARID,
89
+ envelope: Envelope,
90
+ ttlSeconds?: number,
91
+ verbose?: boolean,
92
+ ): Promise<string> {
93
+ const key = arid.urString();
94
+
95
+ // Check if already exists
96
+ if (this.storage.has(key)) {
97
+ if (verbose) {
98
+ verbosePrintln(`PUT ${key} ALREADY_EXISTS`);
99
+ }
100
+ throw new AlreadyExistsError(key);
101
+ }
102
+
103
+ const expiresAt = ttlSeconds !== undefined ? Date.now() + ttlSeconds * 1000 : undefined;
104
+ const envelopeCbor = envelope.taggedCborData();
105
+
106
+ const entry: StorageEntry = { envelopeCbor };
107
+ if (expiresAt !== undefined) {
108
+ entry.expiresAt = expiresAt;
109
+ }
110
+ this.storage.set(key, entry);
111
+
112
+ if (verbose) {
113
+ const ttlMsg = ttlSeconds !== undefined ? ` (TTL ${ttlSeconds}s)` : "";
114
+ verbosePrintln(`PUT ${key}${ttlMsg} OK (Memory)`);
115
+ }
116
+
117
+ return "Stored in memory";
118
+ }
119
+
120
+ /**
121
+ * Retrieve an envelope for the given ARID.
122
+ *
123
+ * Port of `KvStore::get()` implementation from server/memory_kv.rs lines 104-181.
124
+ */
125
+ async get(arid: ARID, timeoutSeconds?: number, verbose?: boolean): Promise<Envelope | null> {
126
+ const timeout = timeoutSeconds ?? 30;
127
+ const start = Date.now();
128
+ let firstAttempt = true;
129
+ const key = arid.urString();
130
+
131
+ // Dynamic import to avoid circular dependencies
132
+ const { EnvelopeDecoder } = await import("@bcts/envelope");
133
+
134
+ while (true) {
135
+ const entry = this.storage.get(key);
136
+
137
+ if (entry) {
138
+ // Check if expired
139
+ if (entry.expiresAt !== undefined && Date.now() >= entry.expiresAt) {
140
+ // Entry is expired, remove it
141
+ this.storage.delete(key);
142
+ if (verbose) {
143
+ verbosePrintln(`GET ${key} EXPIRED`);
144
+ }
145
+ return null;
146
+ }
147
+
148
+ // Parse CBOR bytes back to Envelope
149
+ try {
150
+ const envelope = EnvelopeDecoder.tryFromCborData(entry.envelopeCbor);
151
+ if (verbose) {
152
+ verbosePrintln(`GET ${key} OK (Memory)`);
153
+ }
154
+ return envelope;
155
+ } catch {
156
+ // If parsing fails, treat as not found
157
+ return null;
158
+ }
159
+ }
160
+
161
+ // Not found yet
162
+ const elapsed = (Date.now() - start) / 1000;
163
+ if (elapsed >= timeout) {
164
+ if (verbose) {
165
+ verbosePrintln(`GET ${key} NOT_FOUND (timeout after ${timeout}s)`);
166
+ }
167
+ return null;
168
+ }
169
+
170
+ if (firstAttempt && verbose) {
171
+ verbosePrintln(`Polling for ${key} (timeout: ${timeout}s)`);
172
+ firstAttempt = false;
173
+ } else if (verbose) {
174
+ process.stdout.write(".");
175
+ }
176
+
177
+ // Wait 500ms before polling again
178
+ await new Promise((resolve) => setTimeout(resolve, 500));
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Check if an envelope exists at the given ARID.
184
+ *
185
+ * Port of `KvStore::exists()` implementation from server/memory_kv.rs lines 183-186.
186
+ */
187
+ // eslint-disable-next-line @typescript-eslint/require-await
188
+ async exists(arid: ARID): Promise<boolean> {
189
+ return this.checkExists(arid);
190
+ }
191
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Server-side key-value storage backend union type.
3
+ *
4
+ * Port of server/server_kv.rs from hubert-rust.
5
+ *
6
+ * @module
7
+ */
8
+
9
+ import { type ARID } from "@bcts/components";
10
+ import { type Envelope } from "@bcts/envelope";
11
+
12
+ import { type KvStore } from "../kv-store.js";
13
+ import { MemoryKv } from "./memory-kv.js";
14
+ import { type SqliteKv } from "./sqlite-kv.js";
15
+
16
+ /**
17
+ * Server-side key-value storage backend.
18
+ *
19
+ * This type allows selecting between in-memory and SQLite storage
20
+ * at server setup time.
21
+ *
22
+ * Port of `enum ServerKv` from server/server_kv.rs lines 7-15.
23
+ *
24
+ * @category Server Backend
25
+ */
26
+ export type ServerKv = MemoryKv | SqliteKv;
27
+
28
+ /**
29
+ * Create a new in-memory server KV store.
30
+ *
31
+ * Port of `ServerKv::memory()` from server/server_kv.rs line 19.
32
+ *
33
+ * @returns A new MemoryKv instance
34
+ * @category Server Backend
35
+ */
36
+ export function createMemoryKv(): MemoryKv {
37
+ return new MemoryKv();
38
+ }
39
+
40
+ /**
41
+ * Create a new SQLite-backed server KV store.
42
+ *
43
+ * Port of `ServerKv::sqlite()` from server/server_kv.rs line 22.
44
+ *
45
+ * @param store - The SqliteKv instance to use
46
+ * @returns The same SqliteKv instance
47
+ * @category Server Backend
48
+ */
49
+ export function createSqliteKv(store: SqliteKv): SqliteKv {
50
+ return store;
51
+ }
52
+
53
+ /**
54
+ * Synchronously put an envelope into the store.
55
+ *
56
+ * This function wraps the async KvStore trait implementation for use
57
+ * in synchronous HTTP handlers.
58
+ *
59
+ * Port of `put_sync()` from server/server_kv.rs lines 27-52.
60
+ *
61
+ * @param store - The KvStore to use
62
+ * @param arid - The ARID to store at
63
+ * @param envelope - The envelope to store
64
+ * @param ttlSeconds - TTL in seconds
65
+ * @returns Promise that resolves when storage is complete
66
+ * @internal
67
+ */
68
+ export async function putSync(
69
+ store: KvStore,
70
+ arid: ARID,
71
+ envelope: Envelope,
72
+ ttlSeconds: number,
73
+ ): Promise<void> {
74
+ await store.put(arid, envelope, ttlSeconds, false);
75
+ }
76
+
77
+ /**
78
+ * Synchronously get an envelope from the store.
79
+ *
80
+ * This function wraps the async KvStore trait implementation for use
81
+ * in synchronous HTTP handlers.
82
+ *
83
+ * Port of `get_sync()` from server/server_kv.rs lines 58-71.
84
+ *
85
+ * @param store - The KvStore to use
86
+ * @param arid - The ARID to retrieve
87
+ * @returns The envelope if found, or null
88
+ * @internal
89
+ */
90
+ export async function getSync(store: KvStore, arid: ARID): Promise<Envelope | null> {
91
+ return await store.get(arid, 0, false);
92
+ }