@tier0/sdk-v2 0.8.0 → 0.9.1

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 (106) hide show
  1. package/NOTICE.md +3 -1
  2. package/README.md +45 -11
  3. package/dist/cjs/capabilities.d.ts +8 -17
  4. package/dist/cjs/capabilities.js +17 -28
  5. package/dist/cjs/capabilities.js.map +1 -1
  6. package/dist/cjs/client.d.ts +524 -3
  7. package/dist/cjs/client.js +29 -6
  8. package/dist/cjs/client.js.map +1 -1
  9. package/dist/cjs/cloud-transport.d.ts +4 -2
  10. package/dist/cjs/cloud-transport.js +27 -18
  11. package/dist/cjs/cloud-transport.js.map +1 -1
  12. package/dist/cjs/files.d.ts +26 -6
  13. package/dist/cjs/files.js +151 -28
  14. package/dist/cjs/files.js.map +1 -1
  15. package/dist/cjs/index.d.ts +2 -1
  16. package/dist/cjs/index.js +3 -1
  17. package/dist/cjs/index.js.map +1 -1
  18. package/dist/cjs/openapi/api.generated.d.ts +1 -1
  19. package/dist/cjs/openapi/codecs.generated.d.ts +30 -161
  20. package/dist/cjs/openapi/codecs.generated.js +1 -1
  21. package/dist/cjs/openapi/codecs.generated.js.map +1 -1
  22. package/dist/cjs/openapi/types.generated.d.ts +33 -85
  23. package/dist/cjs/openapi/types.generated.js.map +1 -1
  24. package/dist/cjs/runtime.d.ts +13 -0
  25. package/dist/cjs/runtime.js +51 -0
  26. package/dist/cjs/runtime.js.map +1 -0
  27. package/dist/cjs/streams/capabilities.d.ts +8 -0
  28. package/dist/cjs/streams/capabilities.js +19 -0
  29. package/dist/cjs/streams/capabilities.js.map +1 -0
  30. package/dist/cjs/streams/contract.generated.d.ts +802 -0
  31. package/dist/cjs/streams/contract.generated.js +7 -0
  32. package/dist/cjs/streams/contract.generated.js.map +1 -0
  33. package/dist/cjs/streams/index.d.ts +3 -0
  34. package/dist/cjs/streams/index.js +20 -0
  35. package/dist/cjs/streams/index.js.map +1 -0
  36. package/dist/cjs/streams/messages.d.ts +42 -0
  37. package/dist/cjs/streams/messages.js +514 -0
  38. package/dist/cjs/streams/messages.js.map +1 -0
  39. package/dist/cjs/streams/requests.d.ts +93 -0
  40. package/dist/cjs/streams/requests.js +167 -0
  41. package/dist/cjs/streams/requests.js.map +1 -0
  42. package/dist/cjs/streams/transport.d.ts +16 -0
  43. package/dist/cjs/streams/transport.js +24 -0
  44. package/dist/cjs/streams/transport.js.map +1 -0
  45. package/dist/cjs/uns-v2/generated.d.ts +87 -22
  46. package/dist/cjs/uns-v2/generated.js +43 -8
  47. package/dist/cjs/uns-v2/generated.js.map +1 -1
  48. package/dist/esm/capabilities.d.ts +8 -17
  49. package/dist/esm/capabilities.js +17 -28
  50. package/dist/esm/capabilities.js.map +1 -1
  51. package/dist/esm/client.d.ts +524 -3
  52. package/dist/esm/client.js +27 -5
  53. package/dist/esm/client.js.map +1 -1
  54. package/dist/esm/cloud-transport.d.ts +4 -2
  55. package/dist/esm/cloud-transport.js +27 -18
  56. package/dist/esm/cloud-transport.js.map +1 -1
  57. package/dist/esm/files.d.ts +26 -6
  58. package/dist/esm/files.js +151 -28
  59. package/dist/esm/files.js.map +1 -1
  60. package/dist/esm/index.d.ts +2 -1
  61. package/dist/esm/index.js +2 -1
  62. package/dist/esm/index.js.map +1 -1
  63. package/dist/esm/openapi/api.generated.d.ts +1 -1
  64. package/dist/esm/openapi/codecs.generated.d.ts +30 -161
  65. package/dist/esm/openapi/codecs.generated.js +1 -1
  66. package/dist/esm/openapi/codecs.generated.js.map +1 -1
  67. package/dist/esm/openapi/types.generated.d.ts +33 -85
  68. package/dist/esm/openapi/types.generated.js.map +1 -1
  69. package/dist/esm/runtime.d.ts +13 -0
  70. package/dist/esm/runtime.js +46 -0
  71. package/dist/esm/runtime.js.map +1 -0
  72. package/dist/esm/streams/capabilities.d.ts +8 -0
  73. package/dist/esm/streams/capabilities.js +15 -0
  74. package/dist/esm/streams/capabilities.js.map +1 -0
  75. package/dist/esm/streams/contract.generated.d.ts +802 -0
  76. package/dist/esm/streams/contract.generated.js +6 -0
  77. package/dist/esm/streams/contract.generated.js.map +1 -0
  78. package/dist/esm/streams/index.d.ts +3 -0
  79. package/dist/esm/streams/index.js +4 -0
  80. package/dist/esm/streams/index.js.map +1 -0
  81. package/dist/esm/streams/messages.d.ts +42 -0
  82. package/dist/esm/streams/messages.js +475 -0
  83. package/dist/esm/streams/messages.js.map +1 -0
  84. package/dist/esm/streams/requests.d.ts +93 -0
  85. package/dist/esm/streams/requests.js +161 -0
  86. package/dist/esm/streams/requests.js.map +1 -0
  87. package/dist/esm/streams/transport.d.ts +16 -0
  88. package/dist/esm/streams/transport.js +20 -0
  89. package/dist/esm/streams/transport.js.map +1 -0
  90. package/dist/esm/uns-v2/generated.d.ts +87 -22
  91. package/dist/esm/uns-v2/generated.js +43 -8
  92. package/dist/esm/uns-v2/generated.js.map +1 -1
  93. package/package.json +46 -12
  94. package/skills/tier0-sdk-v2/SKILL.md +3 -2
  95. package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/multipart.md +23 -8
  96. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/SKILL.md +3 -3
  97. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/create.md +9 -3
  98. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/state.md +1 -1
  99. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/update.md +1 -1
  100. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/SKILL.md +2 -1
  101. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/create.md +13 -4
  102. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/deploy.md +1 -1
  103. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/update.md +1 -1
  104. package/skills/tier0-sdk-v2/tier0-sdk-v2-streams/SKILL.md +67 -0
  105. package/skills/tier0-sdk-v2/tier0-sdk-v2-system/SKILL.md +5 -9
  106. package/skills/tier0-sdk-v2/tier0-sdk-v2-system/references/info.md +1 -1
@@ -0,0 +1,514 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.StreamMessagesClient = exports.StreamMessageError = void 0;
37
+ const runtime_context_js_1 = require("../runtime-context.js");
38
+ const runtime_js_1 = require("../runtime.js");
39
+ const transport_js_1 = require("./transport.js");
40
+ class StreamMessageError extends Error {
41
+ errorCode;
42
+ retryable = false;
43
+ constructor(errorCode, message) {
44
+ super(message);
45
+ this.errorCode = errorCode;
46
+ this.name = 'StreamMessageError';
47
+ }
48
+ }
49
+ exports.StreamMessageError = StreamMessageError;
50
+ const encoder = new TextEncoder();
51
+ const uuid = /^(?!00000000-0000-0000-0000-000000000000$)[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
52
+ const MAX_PAYLOAD = 60 * 1024;
53
+ const MAX_ENVELOPE = 64 * 1024;
54
+ const MAX_FLUSH_TIMEOUT_MS = 10_000;
55
+ function plain(value) {
56
+ return value !== null && typeof value === 'object' && !Array.isArray(value) &&
57
+ [Object.prototype, null].includes(Object.getPrototypeOf(value));
58
+ }
59
+ function json(value, seen = new Set()) {
60
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
61
+ return true;
62
+ if (typeof value === 'number')
63
+ return Number.isFinite(value);
64
+ if ((!plain(value) && !Array.isArray(value)) || seen.has(value))
65
+ return false;
66
+ seen.add(value);
67
+ const valid = (Array.isArray(value) ? Array.from(value) : Object.values(value)).every(v => json(v, seen));
68
+ seen.delete(value);
69
+ return valid;
70
+ }
71
+ function fail(code, message) {
72
+ return new StreamMessageError(`STREAM_MESSAGE_${code}`, message);
73
+ }
74
+ function envelope(value, maxPayload) {
75
+ if (!plain(value) || Object.keys(value).some(k => !['version', 'messageId', 'correlationId', 'payload'].includes(k)) ||
76
+ value.version !== 'stream-messages/v1' || typeof value.messageId !== 'string' || !uuid.test(value.messageId) ||
77
+ (value.correlationId !== undefined && (typeof value.correlationId !== 'string' ||
78
+ encoder.encode(value.correlationId).length > 128 || /[\u0000\r\n]/.test(value.correlationId))) ||
79
+ !json(value.payload))
80
+ return false;
81
+ return encoder.encode(JSON.stringify(value.payload)).length <= maxPayload;
82
+ }
83
+ /** One permission-scoped session. Every connection gets a fresh key and JWT. */
84
+ class MessageSession {
85
+ transport;
86
+ topic;
87
+ mode;
88
+ report;
89
+ remove;
90
+ handler;
91
+ disposed = false;
92
+ runtime;
93
+ connection;
94
+ subscription;
95
+ connecting;
96
+ watching;
97
+ abort = new AbortController();
98
+ reconnectTimer;
99
+ expiryTimer;
100
+ started = false;
101
+ connected = false;
102
+ attempts = 0;
103
+ subject = '';
104
+ payloadLimit = MAX_PAYLOAD;
105
+ expiresAt = 0;
106
+ brokerError;
107
+ disposing;
108
+ removeRuntimeListener;
109
+ constructor(transport, topic, mode, report, remove, handler) {
110
+ this.transport = transport;
111
+ this.topic = topic;
112
+ this.mode = mode;
113
+ this.report = report;
114
+ this.remove = remove;
115
+ this.handler = handler;
116
+ this.runtime = transport.runtime();
117
+ if (this.runtime)
118
+ this.removeRuntimeListener = (0, runtime_js_1.onAppRuntimeDispose)(this.runtime, () => { void this.dispose(); });
119
+ }
120
+ async ready() {
121
+ if (this.disposed)
122
+ throw fail('DISPOSED', 'Stream messages session disposed.');
123
+ if (this.connected)
124
+ return;
125
+ if (this.connecting)
126
+ return this.connecting;
127
+ if (this.started)
128
+ throw fail('DISCONNECTED', 'Stream messages disconnected.');
129
+ this.started = true;
130
+ try {
131
+ await this.connect();
132
+ if (this.disposed)
133
+ throw fail('DISPOSED', 'Stream messages session disposed.');
134
+ }
135
+ catch (error) {
136
+ await this.dispose();
137
+ throw error;
138
+ }
139
+ }
140
+ connect() {
141
+ const operation = this.open();
142
+ this.connecting = operation;
143
+ return operation.finally(() => { if (this.connecting === operation)
144
+ this.connecting = undefined; });
145
+ }
146
+ async open() {
147
+ let nc;
148
+ let key;
149
+ let watched = false;
150
+ try {
151
+ // HTTP-only Cloud Apps must not load broker libraries or require their dependencies.
152
+ const [{ jwtAuthenticator, wsconnect }, { createUser }] = await Promise.all([
153
+ Promise.resolve().then(() => __importStar(require('@nats-io/nats-core'))),
154
+ Promise.resolve().then(() => __importStar(require('@nats-io/nkeys'))),
155
+ ]);
156
+ if (this.disposed)
157
+ return;
158
+ const connectionKey = createUser();
159
+ key = connectionKey;
160
+ const appId = this.transport.runtime()?.appId ?? (0, runtime_context_js_1.getCurrentAppId)();
161
+ const request = {
162
+ appId, topics: [{ topic: this.topic, publish: this.mode === 'publish', subscribe: this.mode === 'subscribe' }],
163
+ clientPublicKey: connectionKey.getPublicKey(),
164
+ };
165
+ const { value, ok } = await this.transport.post('/openapi/v2/stream-messages/connect', request, this.abort.signal);
166
+ const ticket = this.ticket(value, ok);
167
+ if (this.disposed)
168
+ return;
169
+ const expiresAt = Date.parse(ticket.expiresAt);
170
+ const permission = ticket.permissions[0];
171
+ this.subject = (this.mode === 'publish' ? permission.publishSubject : permission.subscribeSubject);
172
+ this.payloadLimit = ticket.maxPayloadBytes;
173
+ // Disable library reconnection so it cannot buffer writes or reuse expired JWTs.
174
+ nc = await wsconnect({
175
+ servers: [ticket.url], reconnect: false, waitOnFirstConnect: false,
176
+ ignoreClusterUpdates: true, timeout: Math.max(1, Math.min(MAX_FLUSH_TIMEOUT_MS, expiresAt - Date.now())),
177
+ authenticator: jwtAuthenticator(ticket.userJwt, () => connectionKey.getSeed()),
178
+ });
179
+ if (this.disposed) {
180
+ await nc.close();
181
+ return;
182
+ }
183
+ this.connection = nc;
184
+ this.expiresAt = expiresAt;
185
+ this.brokerError = undefined;
186
+ watched = true;
187
+ this.watching = this.watch(nc, connectionKey);
188
+ // Renewal also bounds the initial handshake; it must not wait for its first PONG.
189
+ const untilExpiry = expiresAt - Date.now();
190
+ this.expiryTimer = setTimeout(() => {
191
+ if (this.connection !== nc)
192
+ return;
193
+ this.connected = false;
194
+ void nc.close();
195
+ }, Math.max(1, Math.min(2_147_483_647, untilExpiry - Math.min(5_000, untilExpiry / 10))));
196
+ if (this.mode === 'subscribe') {
197
+ this.subscription = nc.subscribe(this.subject, { callback: (error, msg) => {
198
+ if (this.disposed || this.connection !== nc || Date.now() >= expiresAt)
199
+ return;
200
+ if (error) {
201
+ this.report(fail('SUBSCRIBE_FAILED', 'Stream subscription failed.'));
202
+ return;
203
+ }
204
+ try {
205
+ if (msg.data.length > MAX_ENVELOPE)
206
+ throw fail('INVALID_ENVELOPE', 'Stream message envelope exceeds limit.');
207
+ const value = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(msg.data));
208
+ if (!envelope(value, this.payloadLimit))
209
+ throw fail('INVALID_ENVELOPE', 'Invalid Stream message envelope.');
210
+ // Identity comes from the authorized physical subject; never accept identity fields in the envelope.
211
+ const prefix = this.subject.slice(0, -1);
212
+ if (!msg.subject.startsWith(prefix) || !/^[^.\s*>]+$/.test(msg.subject.slice(prefix.length))) {
213
+ throw fail('INVALID_SUBJECT', 'Invalid Stream message subject.');
214
+ }
215
+ let result;
216
+ try {
217
+ result = this.handler(value);
218
+ }
219
+ catch {
220
+ this.report(fail('HANDLER_FAILED', 'Stream message handler failed.'));
221
+ return;
222
+ }
223
+ Promise.resolve(result).catch(() => {
224
+ if (!this.disposed)
225
+ this.report(fail('HANDLER_FAILED', 'Stream message handler failed.'));
226
+ });
227
+ }
228
+ catch (error) {
229
+ this.report(error instanceof StreamMessageError ? error : fail('INVALID_ENVELOPE', 'Invalid Stream message envelope.'));
230
+ }
231
+ } });
232
+ }
233
+ await this.flush(nc, false);
234
+ if (this.disposed)
235
+ return;
236
+ if (nc.isClosed() || this.connection !== nc)
237
+ throw fail('CONNECT_FAILED', 'Stream messages connection failed.');
238
+ this.connected = true;
239
+ this.attempts = 0;
240
+ }
241
+ catch (error) {
242
+ if (nc)
243
+ await nc.close();
244
+ if (this.disposed)
245
+ return;
246
+ throw error instanceof StreamMessageError ? error : fail('CONNECT_FAILED', 'Stream messages connection failed.');
247
+ }
248
+ finally {
249
+ // Before a successful handoff, this attempt owns its key, including when
250
+ // the issuer or dial fails. A live connection's watcher owns later wiping.
251
+ if (!watched) {
252
+ await nc?.close();
253
+ key?.clear();
254
+ }
255
+ }
256
+ }
257
+ async flush(nc, publishing) {
258
+ const failure = () => publishing
259
+ ? fail('RESULT_UNKNOWN', 'Stream publish result unknown; do not automatically retry.')
260
+ : fail('CONNECT_FAILED', 'Stream messages connection failed.');
261
+ let timer;
262
+ let stopped;
263
+ try {
264
+ if (this.disposed || nc.isClosed() || this.expiresAt <= Date.now())
265
+ throw failure();
266
+ const deadline = new Promise((_resolve, reject) => {
267
+ stopped = () => reject(failure());
268
+ this.abort.signal.addEventListener('abort', stopped, { once: true });
269
+ if (this.abort.signal.aborted)
270
+ stopped();
271
+ timer = setTimeout(stopped, Math.max(1, Math.min(MAX_FLUSH_TIMEOUT_MS, this.expiresAt - Date.now())));
272
+ });
273
+ await Promise.race([nc.flush(), deadline, nc.closed().then(() => { throw failure(); })]);
274
+ }
275
+ catch {
276
+ const watching = this.connection === nc ? this.watching : undefined;
277
+ if (this.connection === nc)
278
+ this.connected = false;
279
+ // Stop the transport and wipe its key before reporting a failed/unknown operation.
280
+ await nc.close();
281
+ await watching;
282
+ throw failure();
283
+ }
284
+ finally {
285
+ clearTimeout(timer);
286
+ if (stopped)
287
+ this.abort.signal.removeEventListener('abort', stopped);
288
+ }
289
+ }
290
+ ticket(value, ok) {
291
+ if (!ok)
292
+ throw fail('CONNECT_DENIED', 'Stream messages connection denied.');
293
+ if (!plain(value) || value.contractVersion !== 'stream-messages/v1' ||
294
+ typeof value.url !== 'string' || typeof value.userJwt !== 'string' || !value.userJwt ||
295
+ typeof value.expiresAt !== 'string' || !/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.\d+)?(?:Z|[+-]\d\d:\d\d)$/.test(value.expiresAt) ||
296
+ !(Date.parse(value.expiresAt) > Date.now()) ||
297
+ !Number.isSafeInteger(value.maxPayloadBytes) || value.maxPayloadBytes < 1 || value.maxPayloadBytes > MAX_PAYLOAD ||
298
+ !Array.isArray(value.permissions) || value.permissions.length !== 1) {
299
+ throw fail('CONNECT_PROTOCOL_ERROR', 'Invalid Stream messages connection response.');
300
+ }
301
+ const url = new URL(value.url);
302
+ if (url.protocol !== 'wss:' || url.username || url.password || url.hash || url.search) {
303
+ throw fail('CONNECT_PROTOCOL_ERROR', 'Stream messages requires a credential-free WSS URL.');
304
+ }
305
+ const permission = value.permissions[0];
306
+ if (!plain(permission) || permission.topic !== this.topic)
307
+ throw fail('CONNECT_PROTOCOL_ERROR', 'Invalid topic permission.');
308
+ // Subject layout belongs to SYS. Only check NATS syntax and requested access.
309
+ const validSubject = (subject, mode) => {
310
+ if (typeof subject !== 'string' || !subject)
311
+ return false;
312
+ if (mode === 'subscribe' && !subject.endsWith('.*'))
313
+ return false;
314
+ const parts = subject.split('.');
315
+ return parts.every((part, index) => !!part &&
316
+ (mode === 'subscribe' && index === parts.length - 1 && part === '*' || !/[\s*>]/.test(part)));
317
+ };
318
+ const publish = permission.publishSubject;
319
+ const subscribe = permission.subscribeSubject;
320
+ if ((publish !== undefined && !validSubject(publish, 'publish')) ||
321
+ (subscribe !== undefined && !validSubject(subscribe, 'subscribe')) ||
322
+ (this.mode === 'publish' ? !publish || !!subscribe : !subscribe || !!publish)) {
323
+ throw fail('CONNECT_PROTOCOL_ERROR', 'Invalid scoped topic subjects.');
324
+ }
325
+ return value;
326
+ }
327
+ async watch(nc, key) {
328
+ try {
329
+ for await (const status of nc.status()) {
330
+ if (this.disposed || this.connection !== nc)
331
+ break;
332
+ if (status.type === 'disconnect' || status.type === 'close' || status.type === 'staleConnection')
333
+ this.connected = false;
334
+ if (status.type === 'error' || status.type === 'slowConsumer') {
335
+ this.brokerError = fail(status.type === 'error' ? 'BROKER_ERROR' : 'SLOW_CONSUMER', 'Stream messages asynchronous broker error.');
336
+ this.report(this.brokerError);
337
+ }
338
+ }
339
+ const error = await nc.closed();
340
+ if (error && !this.disposed)
341
+ this.report(fail('CONNECTION_LOST', 'Stream messages connection lost.'));
342
+ }
343
+ catch {
344
+ if (!this.disposed)
345
+ this.report(fail('CONNECTION_LOST', 'Stream messages connection lost.'));
346
+ }
347
+ finally {
348
+ // Close even if the status iterator failed. A replacement must never be
349
+ // issued while the prior, potentially wider, authenticated socket is live.
350
+ await nc.close();
351
+ key.clear();
352
+ if (this.connection === nc) {
353
+ this.connection = undefined;
354
+ this.connected = false;
355
+ this.subscription = undefined;
356
+ clearTimeout(this.expiryTimer);
357
+ this.scheduleReconnect();
358
+ }
359
+ }
360
+ }
361
+ scheduleReconnect() {
362
+ if (this.disposed || this.reconnectTimer)
363
+ return;
364
+ this.reconnectTimer = setTimeout(() => {
365
+ this.reconnectTimer = undefined;
366
+ if (this.disposed)
367
+ return;
368
+ void this.connect().catch(error => {
369
+ this.report(error instanceof StreamMessageError ? error : fail('CONNECT_FAILED', 'Stream messages reconnection failed.'));
370
+ this.scheduleReconnect();
371
+ });
372
+ }, Math.min(30_000, 500 * 2 ** Math.min(this.attempts++, 6)));
373
+ }
374
+ async publish(value) {
375
+ // Only the very first publish may establish a connection. Subsequent disconnected writes fail.
376
+ if (!this.started)
377
+ await this.ready();
378
+ const nc = this.connection;
379
+ if (this.disposed || !this.connected || !nc || nc.isClosed())
380
+ throw fail('DISCONNECTED', 'Stream messages disconnected.');
381
+ if (!envelope(value, this.payloadLimit))
382
+ throw fail('INVALID_ENVELOPE', 'Invalid Stream message envelope or payload limit exceeded.');
383
+ const bytes = encoder.encode(JSON.stringify(value));
384
+ if (bytes.length > MAX_ENVELOPE)
385
+ throw fail('PAYLOAD_TOO_LARGE', 'Stream message envelope exceeds limit.');
386
+ this.brokerError = undefined;
387
+ try {
388
+ nc.publish(this.subject, bytes);
389
+ await this.flush(nc, true);
390
+ if (this.brokerError)
391
+ throw this.brokerError;
392
+ if (!this.connected || this.connection !== nc)
393
+ throw fail('RESULT_UNKNOWN', 'Stream publish result unknown.');
394
+ }
395
+ catch (error) {
396
+ throw error instanceof StreamMessageError ? error : fail('RESULT_UNKNOWN', 'Stream publish result unknown; do not automatically retry.');
397
+ }
398
+ }
399
+ dispose() {
400
+ if (this.disposing)
401
+ return this.disposing;
402
+ this.disposed = true;
403
+ this.connected = false;
404
+ this.abort.abort();
405
+ this.removeRuntimeListener?.();
406
+ clearTimeout(this.reconnectTimer);
407
+ clearTimeout(this.expiryTimer);
408
+ this.subscription?.unsubscribe();
409
+ this.disposing = (async () => {
410
+ await this.connection?.close();
411
+ await this.connecting?.catch(() => undefined);
412
+ await this.watching;
413
+ this.connection = undefined;
414
+ this.remove();
415
+ })();
416
+ return this.disposing;
417
+ }
418
+ }
419
+ class StreamMessagesClient {
420
+ transport;
421
+ sessions = new Set();
422
+ listeners = new Set();
423
+ disposed = false;
424
+ disposing;
425
+ constructor(transport = new transport_js_1.StreamTransport()) {
426
+ this.transport = transport;
427
+ }
428
+ onError(handler) {
429
+ if (this.disposed)
430
+ throw fail('DISPOSED', 'Stream messages client disposed.');
431
+ this.listeners.add(handler);
432
+ return () => { this.listeners.delete(handler); };
433
+ }
434
+ use(selector) {
435
+ if (!plain(selector) || Object.keys(selector).some(k => k !== 'topic') ||
436
+ typeof selector.topic !== 'string' || !/^[a-zA-Z0-9][a-zA-Z0-9._/-]{0,127}$/.test(selector.topic)) {
437
+ throw new TypeError('Tier0 SDK: invalid logical Stream topic.');
438
+ }
439
+ const topic = selector.topic;
440
+ let publisher;
441
+ const session = (mode, handler, onError) => {
442
+ if (this.disposed)
443
+ throw fail('DISPOSED', 'Stream messages client disposed.');
444
+ const report = (error) => {
445
+ const listeners = new Set(this.listeners);
446
+ if (onError)
447
+ listeners.add(onError);
448
+ if (!listeners.size)
449
+ console.error(error);
450
+ for (const listener of listeners) {
451
+ try {
452
+ listener(error);
453
+ }
454
+ catch {
455
+ console.error(fail('ERROR_HANDLER_FAILED', 'Stream messages error handler failed.'));
456
+ }
457
+ }
458
+ };
459
+ const value = new MessageSession(this.transport, topic, mode, report, () => this.sessions.delete(value), handler);
460
+ this.sessions.add(value);
461
+ return value;
462
+ };
463
+ return {
464
+ publish: async (payload, options = {}) => {
465
+ if (this.disposed)
466
+ throw fail('DISPOSED', 'Stream messages client disposed.');
467
+ if (!plain(options) || Object.keys(options).some(k => !['messageId', 'correlationId'].includes(k)) ||
468
+ (options.messageId !== undefined && typeof options.messageId !== 'string') ||
469
+ (options.correlationId !== undefined && typeof options.correlationId !== 'string')) {
470
+ throw new TypeError('Tier0 SDK: unsupported Stream publish option.');
471
+ }
472
+ const message = {
473
+ version: 'stream-messages/v1', messageId: options.messageId ?? crypto.randomUUID(),
474
+ ...(options.correlationId === undefined ? {} : { correlationId: options.correlationId }), payload,
475
+ };
476
+ if (!envelope(message, MAX_PAYLOAD))
477
+ throw fail('INVALID_ENVELOPE', 'Invalid Stream message envelope.');
478
+ if (encoder.encode(JSON.stringify(message)).length > MAX_ENVELOPE)
479
+ throw fail('PAYLOAD_TOO_LARGE', 'Stream message envelope exceeds limit.');
480
+ if (publisher?.disposed) {
481
+ const previous = publisher;
482
+ await previous.dispose();
483
+ if (previous.runtime !== this.transport.runtime())
484
+ throw fail('DISCONNECTED', 'Stream messages disconnected.');
485
+ if (publisher === previous)
486
+ publisher = undefined;
487
+ }
488
+ if (!publisher)
489
+ publisher = session('publish');
490
+ await publisher.publish(message);
491
+ return message;
492
+ },
493
+ subscribe: async (handler, options = {}) => {
494
+ if (typeof handler !== 'function' || !plain(options) || Object.keys(options).some(k => k !== 'onError') ||
495
+ (options.onError !== undefined && typeof options.onError !== 'function'))
496
+ throw new TypeError('Tier0 SDK: invalid Stream subscription.');
497
+ const value = session('subscribe', handler, options.onError);
498
+ await value.ready();
499
+ return value;
500
+ },
501
+ };
502
+ }
503
+ dispose() {
504
+ if (this.disposing)
505
+ return this.disposing;
506
+ this.disposed = true;
507
+ this.disposing = Promise.all([...this.sessions].map(session => session.dispose())).then(() => {
508
+ this.listeners.clear();
509
+ });
510
+ return this.disposing;
511
+ }
512
+ }
513
+ exports.StreamMessagesClient = StreamMessagesClient;
514
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/streams/messages.ts"],"names":[],"mappings":"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","sourcesContent":["import type { NatsConnection, Subscription } from '@nats-io/nats-core';\nimport type { KeyPair } from '@nats-io/nkeys';\nimport { getCurrentAppId } from '../runtime-context.js';\nimport { onAppRuntimeDispose } from '../runtime.js';\nimport type { StreamJSON } from './requests.js';\nimport { StreamTransport } from './transport.js';\nimport type { components } from './contract.generated.js';\n\nexport interface StreamMessage<Payload = StreamJSON> {\n version: 'stream-messages/v1';\n messageId: string;\n correlationId?: string;\n payload: Payload;\n}\nexport interface StreamMessagePublishOptions {\n messageId?: string;\n correlationId?: string;\n}\nexport interface StreamMessageSubscription {\n readonly disposed: boolean;\n dispose(): Promise<void>;\n}\nexport type StreamMessageErrorHandler = (error: StreamMessageError) => void;\nexport interface StreamMessageHandle<Payload = StreamJSON> {\n /** Resolves after broker flush, not after receiver acknowledgement. No retry or offline queue. */\n publish(payload: Payload, options?: StreamMessagePublishOptions): Promise<StreamMessage<Payload>>;\n subscribe(handler: (message: StreamMessage<Payload>) => void | Promise<void>, options?: {\n onError?: StreamMessageErrorHandler;\n }): Promise<StreamMessageSubscription>;\n}\nexport class StreamMessageError extends Error {\n readonly retryable = false;\n constructor(readonly errorCode: string, message: string) {\n super(message);\n this.name = 'StreamMessageError';\n }\n}\n\n// SYS omits the ungranted direction; Swagger currently marks both fields required.\ninterface Permission extends Partial<Omit<components['schemas']['StreamMessageGrantedTopic'], 'topic'>> {\n topic: string;\n}\ninterface Ticket extends Omit<components['schemas']['StreamMessagesConnectResp'], 'contractVersion' | 'permissions'> {\n contractVersion: 'stream-messages/v1';\n url: string;\n userJwt: string;\n expiresAt: string;\n permissions: Permission[];\n maxPayloadBytes: number;\n}\nconst encoder = new TextEncoder();\nconst uuid = /^(?!00000000-0000-0000-0000-000000000000$)[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;\nconst MAX_PAYLOAD = 60 * 1024;\nconst MAX_ENVELOPE = 64 * 1024;\nconst MAX_FLUSH_TIMEOUT_MS = 10_000;\n\nfunction plain(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value) &&\n [Object.prototype, null].includes(Object.getPrototypeOf(value));\n}\nfunction json(value: unknown, seen = new Set<unknown>()): boolean {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if ((!plain(value) && !Array.isArray(value)) || seen.has(value)) return false;\n seen.add(value);\n const valid = (Array.isArray(value) ? Array.from(value) : Object.values(value)).every(v => json(v, seen));\n seen.delete(value);\n return valid;\n}\nfunction fail(code: string, message: string): StreamMessageError {\n return new StreamMessageError(`STREAM_MESSAGE_${code}`, message);\n}\nfunction envelope(value: unknown, maxPayload: number): value is StreamMessage {\n if (!plain(value) || Object.keys(value).some(k => !['version', 'messageId', 'correlationId', 'payload'].includes(k)) ||\n value.version !== 'stream-messages/v1' || typeof value.messageId !== 'string' || !uuid.test(value.messageId) ||\n (value.correlationId !== undefined && (typeof value.correlationId !== 'string' ||\n encoder.encode(value.correlationId).length > 128 || /[\\u0000\\r\\n]/.test(value.correlationId))) ||\n !json(value.payload)) return false;\n return encoder.encode(JSON.stringify(value.payload)).length <= maxPayload;\n}\n\n/** One permission-scoped session. Every connection gets a fresh key and JWT. */\nclass MessageSession implements StreamMessageSubscription {\n disposed = false;\n readonly runtime: ReturnType<StreamTransport['runtime']>;\n private connection?: NatsConnection;\n private subscription?: Subscription;\n private connecting?: Promise<void>;\n private watching?: Promise<void>;\n private abort = new AbortController();\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n private expiryTimer?: ReturnType<typeof setTimeout>;\n private started = false;\n private connected = false;\n private attempts = 0;\n private subject = '';\n private payloadLimit = MAX_PAYLOAD;\n private expiresAt = 0;\n private brokerError?: StreamMessageError;\n private disposing?: Promise<void>;\n private removeRuntimeListener?: () => void;\n\n constructor(\n private transport: StreamTransport,\n private topic: string,\n private mode: 'publish' | 'subscribe',\n private report: StreamMessageErrorHandler,\n private remove: () => void,\n private handler?: (value: StreamMessage) => void | Promise<void>,\n ) {\n this.runtime = transport.runtime();\n if (this.runtime) this.removeRuntimeListener = onAppRuntimeDispose(this.runtime, () => { void this.dispose(); });\n }\n\n async ready(): Promise<void> {\n if (this.disposed) throw fail('DISPOSED', 'Stream messages session disposed.');\n if (this.connected) return;\n if (this.connecting) return this.connecting;\n if (this.started) throw fail('DISCONNECTED', 'Stream messages disconnected.');\n this.started = true;\n try {\n await this.connect();\n if (this.disposed) throw fail('DISPOSED', 'Stream messages session disposed.');\n }\n catch (error) { await this.dispose(); throw error; }\n }\n\n private connect(): Promise<void> {\n const operation = this.open();\n this.connecting = operation;\n return operation.finally(() => { if (this.connecting === operation) this.connecting = undefined; });\n }\n\n private async open(): Promise<void> {\n let nc: NatsConnection | undefined;\n let key: KeyPair | undefined;\n let watched = false;\n try {\n // HTTP-only Cloud Apps must not load broker libraries or require their dependencies.\n const [{ jwtAuthenticator, wsconnect }, { createUser }] = await Promise.all([\n import('@nats-io/nats-core'), import('@nats-io/nkeys'),\n ]);\n if (this.disposed) return;\n const connectionKey = createUser();\n key = connectionKey;\n const appId = this.transport.runtime()?.appId ?? getCurrentAppId();\n const request: components['schemas']['StreamMessagesConnectReq'] = {\n appId, topics: [{ topic: this.topic, publish: this.mode === 'publish', subscribe: this.mode === 'subscribe' }],\n clientPublicKey: connectionKey.getPublicKey(),\n };\n const { value, ok } = await this.transport.post('/openapi/v2/stream-messages/connect', request, this.abort.signal);\n const ticket = this.ticket(value, ok);\n if (this.disposed) return;\n const expiresAt = Date.parse(ticket.expiresAt);\n const permission = ticket.permissions[0];\n this.subject = (this.mode === 'publish' ? permission.publishSubject : permission.subscribeSubject)!;\n this.payloadLimit = ticket.maxPayloadBytes;\n // Disable library reconnection so it cannot buffer writes or reuse expired JWTs.\n nc = await wsconnect({\n servers: [ticket.url], reconnect: false, waitOnFirstConnect: false,\n ignoreClusterUpdates: true, timeout: Math.max(1, Math.min(MAX_FLUSH_TIMEOUT_MS, expiresAt - Date.now())),\n authenticator: jwtAuthenticator(ticket.userJwt, () => connectionKey.getSeed()),\n });\n if (this.disposed) { await nc.close(); return; }\n this.connection = nc;\n this.expiresAt = expiresAt;\n this.brokerError = undefined;\n watched = true;\n this.watching = this.watch(nc, connectionKey);\n // Renewal also bounds the initial handshake; it must not wait for its first PONG.\n const untilExpiry = expiresAt - Date.now();\n this.expiryTimer = setTimeout(() => {\n if (this.connection !== nc) return;\n this.connected = false;\n void nc!.close();\n }, Math.max(1, Math.min(2_147_483_647, untilExpiry - Math.min(5_000, untilExpiry / 10))));\n if (this.mode === 'subscribe') {\n this.subscription = nc.subscribe(this.subject, { callback: (error, msg) => {\n if (this.disposed || this.connection !== nc || Date.now() >= expiresAt) return;\n if (error) { this.report(fail('SUBSCRIBE_FAILED', 'Stream subscription failed.')); return; }\n try {\n if (msg.data.length > MAX_ENVELOPE) throw fail('INVALID_ENVELOPE', 'Stream message envelope exceeds limit.');\n const value: unknown = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(msg.data));\n if (!envelope(value, this.payloadLimit)) throw fail('INVALID_ENVELOPE', 'Invalid Stream message envelope.');\n // Identity comes from the authorized physical subject; never accept identity fields in the envelope.\n const prefix = this.subject.slice(0, -1);\n if (!msg.subject.startsWith(prefix) || !/^[^.\\s*>]+$/.test(msg.subject.slice(prefix.length))) {\n throw fail('INVALID_SUBJECT', 'Invalid Stream message subject.');\n }\n let result: void | Promise<void>;\n try { result = this.handler!(value); }\n catch { this.report(fail('HANDLER_FAILED', 'Stream message handler failed.')); return; }\n Promise.resolve(result).catch(() => {\n if (!this.disposed) this.report(fail('HANDLER_FAILED', 'Stream message handler failed.'));\n });\n } catch (error) {\n this.report(error instanceof StreamMessageError ? error : fail('INVALID_ENVELOPE', 'Invalid Stream message envelope.'));\n }\n } });\n }\n await this.flush(nc, false);\n if (this.disposed) return;\n if (nc.isClosed() || this.connection !== nc) throw fail('CONNECT_FAILED', 'Stream messages connection failed.');\n this.connected = true;\n this.attempts = 0;\n } catch (error) {\n if (nc) await nc.close();\n if (this.disposed) return;\n throw error instanceof StreamMessageError ? error : fail('CONNECT_FAILED', 'Stream messages connection failed.');\n } finally {\n // Before a successful handoff, this attempt owns its key, including when\n // the issuer or dial fails. A live connection's watcher owns later wiping.\n if (!watched) {\n await nc?.close();\n key?.clear();\n }\n }\n }\n\n private async flush(nc: NatsConnection, publishing: boolean): Promise<void> {\n const failure = () => publishing\n ? fail('RESULT_UNKNOWN', 'Stream publish result unknown; do not automatically retry.')\n : fail('CONNECT_FAILED', 'Stream messages connection failed.');\n let timer: ReturnType<typeof setTimeout> | undefined;\n let stopped: (() => void) | undefined;\n try {\n if (this.disposed || nc.isClosed() || this.expiresAt <= Date.now()) throw failure();\n const deadline = new Promise<never>((_resolve, reject) => {\n stopped = () => reject(failure());\n this.abort.signal.addEventListener('abort', stopped, { once: true });\n if (this.abort.signal.aborted) stopped();\n timer = setTimeout(stopped, Math.max(1, Math.min(MAX_FLUSH_TIMEOUT_MS, this.expiresAt - Date.now())));\n });\n await Promise.race([nc.flush(), deadline, nc.closed().then(() => { throw failure(); })]);\n } catch {\n const watching = this.connection === nc ? this.watching : undefined;\n if (this.connection === nc) this.connected = false;\n // Stop the transport and wipe its key before reporting a failed/unknown operation.\n await nc.close();\n await watching;\n throw failure();\n } finally {\n clearTimeout(timer);\n if (stopped) this.abort.signal.removeEventListener('abort', stopped);\n }\n }\n\n private ticket(value: unknown, ok: boolean): Ticket {\n if (!ok) throw fail('CONNECT_DENIED', 'Stream messages connection denied.');\n if (!plain(value) || value.contractVersion !== 'stream-messages/v1' ||\n typeof value.url !== 'string' || typeof value.userJwt !== 'string' || !value.userJwt ||\n typeof value.expiresAt !== 'string' || !/^\\d{4}-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d(?:\\.\\d+)?(?:Z|[+-]\\d\\d:\\d\\d)$/.test(value.expiresAt) ||\n !(Date.parse(value.expiresAt) > Date.now()) ||\n !Number.isSafeInteger(value.maxPayloadBytes) || (value.maxPayloadBytes as number) < 1 || (value.maxPayloadBytes as number) > MAX_PAYLOAD ||\n !Array.isArray(value.permissions) || value.permissions.length !== 1) {\n throw fail('CONNECT_PROTOCOL_ERROR', 'Invalid Stream messages connection response.');\n }\n const url = new URL(value.url);\n if (url.protocol !== 'wss:' || url.username || url.password || url.hash || url.search) {\n throw fail('CONNECT_PROTOCOL_ERROR', 'Stream messages requires a credential-free WSS URL.');\n }\n const permission: unknown = value.permissions[0];\n if (!plain(permission) || permission.topic !== this.topic) throw fail('CONNECT_PROTOCOL_ERROR', 'Invalid topic permission.');\n // Subject layout belongs to SYS. Only check NATS syntax and requested access.\n const validSubject = (subject: unknown, mode: 'publish' | 'subscribe') => {\n if (typeof subject !== 'string' || !subject) return false;\n if (mode === 'subscribe' && !subject.endsWith('.*')) return false;\n const parts = subject.split('.');\n return parts.every((part, index) => !!part &&\n (mode === 'subscribe' && index === parts.length - 1 && part === '*' || !/[\\s*>]/.test(part)));\n };\n const publish = permission.publishSubject;\n const subscribe = permission.subscribeSubject;\n if ((publish !== undefined && !validSubject(publish, 'publish')) ||\n (subscribe !== undefined && !validSubject(subscribe, 'subscribe')) ||\n (this.mode === 'publish' ? !publish || !!subscribe : !subscribe || !!publish)) {\n throw fail('CONNECT_PROTOCOL_ERROR', 'Invalid scoped topic subjects.');\n }\n return value as unknown as Ticket;\n }\n\n private async watch(nc: NatsConnection, key: KeyPair): Promise<void> {\n try {\n for await (const status of nc.status()) {\n if (this.disposed || this.connection !== nc) break;\n if (status.type === 'disconnect' || status.type === 'close' || status.type === 'staleConnection') this.connected = false;\n if (status.type === 'error' || status.type === 'slowConsumer') {\n this.brokerError = fail(status.type === 'error' ? 'BROKER_ERROR' : 'SLOW_CONSUMER', 'Stream messages asynchronous broker error.');\n this.report(this.brokerError);\n }\n }\n const error = await nc.closed();\n if (error && !this.disposed) this.report(fail('CONNECTION_LOST', 'Stream messages connection lost.'));\n } catch {\n if (!this.disposed) this.report(fail('CONNECTION_LOST', 'Stream messages connection lost.'));\n } finally {\n // Close even if the status iterator failed. A replacement must never be\n // issued while the prior, potentially wider, authenticated socket is live.\n await nc.close();\n key.clear();\n if (this.connection === nc) {\n this.connection = undefined;\n this.connected = false;\n this.subscription = undefined;\n clearTimeout(this.expiryTimer);\n this.scheduleReconnect();\n }\n }\n }\n\n private scheduleReconnect(): void {\n if (this.disposed || this.reconnectTimer) return;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = undefined;\n if (this.disposed) return;\n void this.connect().catch(error => {\n this.report(error instanceof StreamMessageError ? error : fail('CONNECT_FAILED', 'Stream messages reconnection failed.'));\n this.scheduleReconnect();\n });\n }, Math.min(30_000, 500 * 2 ** Math.min(this.attempts++, 6)));\n }\n\n async publish(value: StreamMessage): Promise<void> {\n // Only the very first publish may establish a connection. Subsequent disconnected writes fail.\n if (!this.started) await this.ready();\n const nc = this.connection;\n if (this.disposed || !this.connected || !nc || nc.isClosed()) throw fail('DISCONNECTED', 'Stream messages disconnected.');\n if (!envelope(value, this.payloadLimit)) throw fail('INVALID_ENVELOPE', 'Invalid Stream message envelope or payload limit exceeded.');\n const bytes = encoder.encode(JSON.stringify(value));\n if (bytes.length > MAX_ENVELOPE) throw fail('PAYLOAD_TOO_LARGE', 'Stream message envelope exceeds limit.');\n this.brokerError = undefined;\n try {\n nc.publish(this.subject, bytes);\n await this.flush(nc, true);\n if (this.brokerError) throw this.brokerError;\n if (!this.connected || this.connection !== nc) throw fail('RESULT_UNKNOWN', 'Stream publish result unknown.');\n } catch (error) {\n throw error instanceof StreamMessageError ? error : fail('RESULT_UNKNOWN', 'Stream publish result unknown; do not automatically retry.');\n }\n }\n\n dispose(): Promise<void> {\n if (this.disposing) return this.disposing;\n this.disposed = true;\n this.connected = false;\n this.abort.abort();\n this.removeRuntimeListener?.();\n clearTimeout(this.reconnectTimer);\n clearTimeout(this.expiryTimer);\n this.subscription?.unsubscribe();\n this.disposing = (async () => {\n await this.connection?.close();\n await this.connecting?.catch(() => undefined);\n await this.watching;\n this.connection = undefined;\n this.remove();\n })();\n return this.disposing;\n }\n}\n\nexport class StreamMessagesClient {\n private sessions = new Set<MessageSession>();\n private listeners = new Set<StreamMessageErrorHandler>();\n private disposed = false;\n private disposing?: Promise<void>;\n constructor(private readonly transport = new StreamTransport()) {}\n\n onError(handler: StreamMessageErrorHandler): () => void {\n if (this.disposed) throw fail('DISPOSED', 'Stream messages client disposed.');\n this.listeners.add(handler);\n return () => { this.listeners.delete(handler); };\n }\n\n use<Payload = StreamJSON>(selector: { topic: string }): StreamMessageHandle<Payload> {\n if (!plain(selector) || Object.keys(selector).some(k => k !== 'topic') ||\n typeof selector.topic !== 'string' || !/^[a-zA-Z0-9][a-zA-Z0-9._/-]{0,127}$/.test(selector.topic)) {\n throw new TypeError('Tier0 SDK: invalid logical Stream topic.');\n }\n const topic = selector.topic;\n let publisher: MessageSession | undefined;\n const session = (mode: 'publish' | 'subscribe', handler?: (value: StreamMessage) => void | Promise<void>, onError?: StreamMessageErrorHandler) => {\n if (this.disposed) throw fail('DISPOSED', 'Stream messages client disposed.');\n const report = (error: StreamMessageError) => {\n const listeners = new Set(this.listeners);\n if (onError) listeners.add(onError);\n if (!listeners.size) console.error(error);\n for (const listener of listeners) {\n try { listener(error); } catch { console.error(fail('ERROR_HANDLER_FAILED', 'Stream messages error handler failed.')); }\n }\n };\n const value = new MessageSession(this.transport, topic, mode, report, () => this.sessions.delete(value), handler);\n this.sessions.add(value);\n return value;\n };\n return {\n publish: async (payload, options = {}) => {\n if (this.disposed) throw fail('DISPOSED', 'Stream messages client disposed.');\n if (!plain(options) || Object.keys(options).some(k => !['messageId', 'correlationId'].includes(k)) ||\n (options.messageId !== undefined && typeof options.messageId !== 'string') ||\n (options.correlationId !== undefined && typeof options.correlationId !== 'string')) {\n throw new TypeError('Tier0 SDK: unsupported Stream publish option.');\n }\n const message: StreamMessage<Payload> = {\n version: 'stream-messages/v1', messageId: options.messageId ?? crypto.randomUUID(),\n ...(options.correlationId === undefined ? {} : { correlationId: options.correlationId }), payload,\n };\n if (!envelope(message, MAX_PAYLOAD)) throw fail('INVALID_ENVELOPE', 'Invalid Stream message envelope.');\n if (encoder.encode(JSON.stringify(message)).length > MAX_ENVELOPE) throw fail('PAYLOAD_TOO_LARGE', 'Stream message envelope exceeds limit.');\n if (publisher?.disposed) {\n const previous = publisher;\n await previous.dispose();\n if (previous.runtime !== this.transport.runtime()) throw fail('DISCONNECTED', 'Stream messages disconnected.');\n if (publisher === previous) publisher = undefined;\n }\n if (!publisher) publisher = session('publish');\n await publisher.publish(message as StreamMessage);\n return message;\n },\n subscribe: async (handler, options = {}) => {\n if (typeof handler !== 'function' || !plain(options) || Object.keys(options).some(k => k !== 'onError') ||\n (options.onError !== undefined && typeof options.onError !== 'function')) throw new TypeError('Tier0 SDK: invalid Stream subscription.');\n const value = session('subscribe', handler as (value: StreamMessage) => void | Promise<void>, options.onError);\n await value.ready();\n return value;\n },\n };\n }\n\n dispose(): Promise<void> {\n if (this.disposing) return this.disposing;\n this.disposed = true;\n this.disposing = Promise.all([...this.sessions].map(session => session.dispose())).then(() => {\n this.listeners.clear();\n });\n return this.disposing;\n }\n}\n"]}