n3-sdk 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-VR66RLVO.js +126 -0
- package/dist/chunk-VR66RLVO.js.map +1 -0
- package/dist/index.d.ts +1 -24
- package/dist/index.js +14 -132
- package/dist/index.js.map +1 -1
- package/dist/publisher.d.ts +24 -0
- package/dist/publisher.js +11 -0
- package/dist/publisher.js.map +1 -0
- package/package.json +5 -1
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// src/lib/utils/redis.ts
|
|
8
|
+
var IS_BROWSER = typeof window !== "undefined";
|
|
9
|
+
function flattenFields(obj) {
|
|
10
|
+
const out = [];
|
|
11
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
12
|
+
out.push(k, typeof v === "string" ? v : JSON.stringify(v));
|
|
13
|
+
}
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
var NodeRedisPublisher = class {
|
|
17
|
+
stream;
|
|
18
|
+
url;
|
|
19
|
+
client;
|
|
20
|
+
// redis.RedisClientType
|
|
21
|
+
connected = false;
|
|
22
|
+
constructor(url, streamPrefix) {
|
|
23
|
+
this.url = url;
|
|
24
|
+
this.stream = `${streamPrefix}:intents`;
|
|
25
|
+
}
|
|
26
|
+
async start() {
|
|
27
|
+
if (this.connected) return;
|
|
28
|
+
const { createClient } = await import("redis");
|
|
29
|
+
this.client = createClient({ url: this.url });
|
|
30
|
+
this.client.on("error", (e) => {
|
|
31
|
+
console.warn("[publisher] redis error:", e?.message || e);
|
|
32
|
+
});
|
|
33
|
+
await this.client.connect();
|
|
34
|
+
this.connected = true;
|
|
35
|
+
}
|
|
36
|
+
async stop() {
|
|
37
|
+
if (!this.connected) return;
|
|
38
|
+
try {
|
|
39
|
+
await this.client.quit();
|
|
40
|
+
} catch {
|
|
41
|
+
} finally {
|
|
42
|
+
this.connected = false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async publishIntent(intent) {
|
|
46
|
+
if (!this.connected) await this.start();
|
|
47
|
+
const fields = flattenFields(intent);
|
|
48
|
+
return this.client.xAdd(this.stream, "*", fields);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var HttpIngressPublisher = class {
|
|
52
|
+
constructor(ingressUrl = "/api/intents", fetchImpl = fetch) {
|
|
53
|
+
this.ingressUrl = ingressUrl;
|
|
54
|
+
this.fetchImpl = fetchImpl;
|
|
55
|
+
}
|
|
56
|
+
async start() {
|
|
57
|
+
}
|
|
58
|
+
async stop() {
|
|
59
|
+
}
|
|
60
|
+
async publishIntent(intent) {
|
|
61
|
+
const r = await this.fetchImpl(this.ingressUrl, {
|
|
62
|
+
method: "POST",
|
|
63
|
+
headers: { "content-type": "application/json" },
|
|
64
|
+
body: JSON.stringify(intent),
|
|
65
|
+
// keepalive is nice to reduce aborted posts on unload
|
|
66
|
+
keepalive: true
|
|
67
|
+
});
|
|
68
|
+
if (!r.ok) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`HTTP ingress failed: ${r.status} ${await r.text().catch(() => "")}`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
const j = await r.json().catch(() => ({}));
|
|
74
|
+
return j?.id ?? "ok";
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
function createPublisher(config = {}) {
|
|
78
|
+
const streamPrefix = config.streamPrefix ?? (IS_BROWSER ? process.env.NEXT_PUBLIC_REDIS_STREAM_PREFIX || "n3" : process.env.REDIS_STREAM_PREFIX || "n3");
|
|
79
|
+
if (!IS_BROWSER) {
|
|
80
|
+
const redisUrl = config.redisUrl || process.env.REDIS_URL;
|
|
81
|
+
if (!redisUrl) {
|
|
82
|
+
throw new Error("createPublisher: REDIS_URL is required on server runtime.");
|
|
83
|
+
}
|
|
84
|
+
return new NodeRedisPublisher(redisUrl, streamPrefix);
|
|
85
|
+
}
|
|
86
|
+
const ingress = config.httpIngressUrl || "/api/intents";
|
|
87
|
+
return new HttpIngressPublisher(ingress);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/lib/utils/publisher.ts
|
|
91
|
+
var _pub = null;
|
|
92
|
+
var _started = false;
|
|
93
|
+
function getPublisher() {
|
|
94
|
+
if (_pub) return _pub;
|
|
95
|
+
_pub = createPublisher({
|
|
96
|
+
// Optional override; your publisher.ts already reads from env inside.
|
|
97
|
+
streamPrefix: (typeof window === "undefined" ? process.env.REDIS_STREAM_PREFIX : process.env.NEXT_PUBLIC_REDIS_STREAM_PREFIX) || "n3",
|
|
98
|
+
// Node/server fast path (TCP):
|
|
99
|
+
redisUrl: typeof window === "undefined" ? process.env.REDIS_URL : void 0,
|
|
100
|
+
// Browser fallback → your app’s ingress (default `/api/intents`)
|
|
101
|
+
httpIngressUrl: typeof window !== "undefined" ? process.env.NEXT_PUBLIC_INTENT_INGRESS || "/api/intents" : void 0
|
|
102
|
+
});
|
|
103
|
+
return _pub;
|
|
104
|
+
}
|
|
105
|
+
async function startPublisher() {
|
|
106
|
+
if (_started) return;
|
|
107
|
+
await getPublisher().start();
|
|
108
|
+
_started = true;
|
|
109
|
+
}
|
|
110
|
+
async function publishIntent(intent) {
|
|
111
|
+
if (!_started) await startPublisher();
|
|
112
|
+
return getPublisher().publishIntent(intent);
|
|
113
|
+
}
|
|
114
|
+
async function stopPublisher() {
|
|
115
|
+
if (!_started) return;
|
|
116
|
+
await getPublisher().stop();
|
|
117
|
+
_started = false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export {
|
|
121
|
+
__export,
|
|
122
|
+
startPublisher,
|
|
123
|
+
publishIntent,
|
|
124
|
+
stopPublisher
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=chunk-VR66RLVO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils/redis.ts","../src/lib/utils/publisher.ts"],"sourcesContent":["// src/publisher.ts\n// Universal publisher: Node -> Redis TCP (official \"redis\" pkg), Browser -> HTTP ingress.\n// No ioredis, no Upstash.\n\ntype JSONish = Record<string, unknown>;\n\nexport interface Publisher {\n start(): Promise<void>;\n stop(): Promise<void>;\n publishIntent(intent: JSONish): Promise<string>; // returns XADD id (or server-provided id)\n}\n\nconst IS_BROWSER = typeof window !== 'undefined';\n\n/* ----------------------------\n * helpers\n * ---------------------------- */\nfunction flattenFields(obj: JSONish): string[] {\n const out: string[] = [];\n for (const [k, v] of Object.entries(obj)) {\n out.push(k, typeof v === 'string' ? v : JSON.stringify(v));\n }\n return out;\n}\n\n/* ----------------------------\n * Node runtime (official redis)\n * ---------------------------- */\nclass NodeRedisPublisher implements Publisher {\n private stream: string;\n private url: string;\n private client: any; // redis.RedisClientType\n private connected = false;\n\n constructor(url: string, streamPrefix: string) {\n this.url = url;\n this.stream = `${streamPrefix}:intents`;\n }\n\n async start() {\n if (this.connected) return;\n const { createClient } = await import('redis'); // dynamic, not bundled client-side\n this.client = createClient({ url: this.url });\n this.client.on('error', (e: any) => {\n // keep logs terse\n console.warn('[publisher] redis error:', e?.message || e);\n });\n await this.client.connect();\n this.connected = true;\n }\n\n async stop() {\n if (!this.connected) return;\n try {\n await this.client.quit();\n } catch {\n // ignore\n } finally {\n this.connected = false;\n }\n }\n\n async publishIntent(intent: JSONish): Promise<string> {\n if (!this.connected) await this.start();\n const fields = flattenFields(intent);\n return this.client.xAdd(this.stream, '*', fields);\n }\n}\n\n/* ----------------------------\n * Browser runtime -> HTTP ingress\n * ---------------------------- */\nclass HttpIngressPublisher implements Publisher {\n constructor(\n private ingressUrl: string = '/api/intents',\n private fetchImpl: typeof fetch = fetch\n ) {}\n\n async start() {}\n async stop() {}\n\n async publishIntent(intent: JSONish): Promise<string> {\n const r = await this.fetchImpl(this.ingressUrl, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(intent),\n // keepalive is nice to reduce aborted posts on unload\n keepalive: true,\n });\n if (!r.ok) {\n throw new Error(\n `HTTP ingress failed: ${r.status} ${await r.text().catch(() => '')}`\n );\n }\n const j = await r.json().catch(() => ({}));\n // Expect your API to return { id } for the XADD id\n return (j?.id as string) ?? 'ok';\n }\n}\n\n/* ----------------------------\n * Factory\n * ---------------------------- */\nexport type PublisherConfig = {\n /** Redis Stream prefix (final stream is `${prefix}:intents`) */\n streamPrefix?: string;\n /** Node/server: e.g. 'redis://localhost:6379' */\n redisUrl?: string;\n /** Browser fallback: your API route to publish intents */\n httpIngressUrl?: string; // e.g. '/api/intents'\n};\n\nexport function createPublisher(config: PublisherConfig = {}): Publisher {\n const streamPrefix =\n config.streamPrefix ??\n (IS_BROWSER\n ? (process.env.NEXT_PUBLIC_REDIS_STREAM_PREFIX as string) || 'n3'\n : process.env.REDIS_STREAM_PREFIX || 'n3');\n\n if (!IS_BROWSER) {\n const redisUrl = config.redisUrl || process.env.REDIS_URL;\n if (!redisUrl) {\n throw new Error('createPublisher: REDIS_URL is required on server runtime.');\n }\n return new NodeRedisPublisher(redisUrl, streamPrefix);\n }\n\n // Browser -> your own ingress\n const ingress = config.httpIngressUrl || '/api/intents';\n return new HttpIngressPublisher(ingress);\n}","// src/publisherSingleton.ts\nimport { createPublisher, type Publisher } from './redis';\n\nlet _pub: Publisher | null = null;\nlet _started = false;\n\n/** Lazily build the unified publisher once (server or browser). */\nfunction getPublisher(): Publisher {\n if (_pub) return _pub;\n\n _pub = createPublisher({\n // Optional override; your publisher.ts already reads from env inside.\n streamPrefix:\n (typeof window === 'undefined'\n ? process.env.REDIS_STREAM_PREFIX\n : process.env.NEXT_PUBLIC_REDIS_STREAM_PREFIX) || 'n3',\n\n // Node/server fast path (TCP):\n redisUrl: typeof window === 'undefined' ? process.env.REDIS_URL : undefined,\n\n // Browser fallback → your app’s ingress (default `/api/intents`)\n httpIngressUrl:\n typeof window !== 'undefined'\n ? process.env.NEXT_PUBLIC_INTENT_INGRESS || '/api/intents'\n : undefined,\n });\n\n return _pub;\n}\n\n/** Optional: warm it up early on servers/CLIs to shave first-publish latency. */\nexport async function startPublisher() {\n if (_started) return;\n await getPublisher().start();\n _started = true;\n}\n\n/** The single function your actions should call. */\nexport async function publishIntent(intent: Record<string, unknown>) {\n if (!_started) await startPublisher(); // lazy init on first use\n return getPublisher().publishIntent(intent); // returns XADD id or server id\n}\n\n/** Optional graceful shutdown for Node jobs. */\nexport async function stopPublisher() {\n if (!_started) return;\n await getPublisher().stop();\n _started = false;\n}"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -723,29 +723,6 @@ declare class Receiver {
|
|
|
723
723
|
reconcile(fromBlock?: number): Promise<void>;
|
|
724
724
|
}
|
|
725
725
|
|
|
726
|
-
type JSONish = Record<string, unknown>;
|
|
727
|
-
interface Publisher {
|
|
728
|
-
start(): Promise<void>;
|
|
729
|
-
stop(): Promise<void>;
|
|
730
|
-
publishIntent(intent: JSONish): Promise<string>;
|
|
731
|
-
}
|
|
732
|
-
type PublisherConfig = {
|
|
733
|
-
/** Redis Stream prefix (final stream is `${prefix}:intents`) */
|
|
734
|
-
streamPrefix?: string;
|
|
735
|
-
/** Node/server: e.g. 'redis://localhost:6379' */
|
|
736
|
-
redisUrl?: string;
|
|
737
|
-
/** Browser fallback: your API route to publish intents */
|
|
738
|
-
httpIngressUrl?: string;
|
|
739
|
-
};
|
|
740
|
-
declare function createPublisher(config?: PublisherConfig): Publisher;
|
|
741
|
-
|
|
742
|
-
/** Optional: warm it up early on servers/CLIs to shave first-publish latency. */
|
|
743
|
-
declare function startPublisher(): Promise<void>;
|
|
744
|
-
/** The single function your actions should call. */
|
|
745
|
-
declare function publishIntent(intent: Record<string, unknown>): Promise<string>;
|
|
746
|
-
/** Optional graceful shutdown for Node jobs. */
|
|
747
|
-
declare function stopPublisher(): Promise<void>;
|
|
748
|
-
|
|
749
726
|
type InfoAPI = {
|
|
750
727
|
indicatives: ReturnType<typeof makeIndicativesInfo>;
|
|
751
728
|
candles: ReturnType<typeof makeCandlesInfo>;
|
|
@@ -813,4 +790,4 @@ declare class N3SDK {
|
|
|
813
790
|
startReceiverSync(store: NoteStore, clients?: N3Clients, fromBlock?: number | bigint): () => void;
|
|
814
791
|
}
|
|
815
792
|
|
|
816
|
-
export { type AssetId, index as Exchange, index$2 as Info, type N3Clients, type N3Env, N3SDK, NoteStore, NoteStore as NoteStoreT,
|
|
793
|
+
export { type AssetId, index as Exchange, index$2 as Info, type N3Clients, type N3Env, N3SDK, NoteStore, NoteStore as NoteStoreT, Receiver, index$1 as Subscription, type TopicName, Topics, N3SDK as default, toReceiverFromBlock, toViemFromBlock };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
__export,
|
|
3
|
+
publishIntent
|
|
4
|
+
} from "./chunk-VR66RLVO.js";
|
|
6
5
|
|
|
7
6
|
// src/data/ws.ts
|
|
8
7
|
var MarketWS = class {
|
|
@@ -183,7 +182,7 @@ function makeGraphQL(env) {
|
|
|
183
182
|
const d = await gql(q, { assetId: String(assetId), sinceSec });
|
|
184
183
|
return d.indicatives;
|
|
185
184
|
},
|
|
186
|
-
async candles(assetId,
|
|
185
|
+
async candles(assetId, window, limit = 300) {
|
|
187
186
|
const q = (
|
|
188
187
|
/* GraphQL */
|
|
189
188
|
`
|
|
@@ -193,7 +192,7 @@ function makeGraphQL(env) {
|
|
|
193
192
|
}
|
|
194
193
|
}`
|
|
195
194
|
);
|
|
196
|
-
const d = await gql(q, { assetId: String(assetId), window
|
|
195
|
+
const d = await gql(q, { assetId: String(assetId), window, limit });
|
|
197
196
|
return d.candles;
|
|
198
197
|
}
|
|
199
198
|
};
|
|
@@ -259,22 +258,22 @@ function makeCandlesInfo(env) {
|
|
|
259
258
|
const { gql } = makeInfra(env);
|
|
260
259
|
return {
|
|
261
260
|
/** Paginated/limited candles (server decides ordering; usually oldest->newest). */
|
|
262
|
-
list(assetId,
|
|
263
|
-
return gql.candles(assetId,
|
|
261
|
+
list(assetId, window, limit = 300) {
|
|
262
|
+
return gql.candles(assetId, window, limit);
|
|
264
263
|
},
|
|
265
264
|
/**
|
|
266
265
|
* Optional: range query if your GraphQL supports it.
|
|
267
266
|
* If not implemented server-side, remove this or let it throw.
|
|
268
267
|
*/
|
|
269
|
-
async range(assetId,
|
|
268
|
+
async range(assetId, window, start, end) {
|
|
270
269
|
if (typeof gql.candlesRange !== "function") {
|
|
271
270
|
throw new Error("candles.range not supported by server GraphQL");
|
|
272
271
|
}
|
|
273
|
-
return gql.candlesRange(assetId,
|
|
272
|
+
return gql.candlesRange(assetId, window, start, end);
|
|
274
273
|
},
|
|
275
274
|
/** Convenience: last candle (null if missing). */
|
|
276
|
-
async latest(assetId,
|
|
277
|
-
const rows = await gql.candles(assetId,
|
|
275
|
+
async latest(assetId, window) {
|
|
276
|
+
const rows = await gql.candles(assetId, window, 1);
|
|
278
277
|
return rows.length ? rows[rows.length - 1] : null;
|
|
279
278
|
}
|
|
280
279
|
};
|
|
@@ -375,8 +374,8 @@ function makeCandles(env, WSImpl) {
|
|
|
375
374
|
const { gql, ws } = makeInfra(env, WSImpl);
|
|
376
375
|
return {
|
|
377
376
|
/** Historical candles from GraphQL. */
|
|
378
|
-
list(assetId,
|
|
379
|
-
return gql.candles(assetId,
|
|
377
|
+
list(assetId, window, limit = 300) {
|
|
378
|
+
return gql.candles(assetId, window, limit);
|
|
380
379
|
},
|
|
381
380
|
/**
|
|
382
381
|
* Live candles via WS fanout.
|
|
@@ -471,119 +470,6 @@ __export(exchange_exports, {
|
|
|
471
470
|
withdrawAuto: () => withdrawAuto
|
|
472
471
|
});
|
|
473
472
|
|
|
474
|
-
// src/lib/utils/redis.ts
|
|
475
|
-
var IS_BROWSER = typeof window !== "undefined";
|
|
476
|
-
function flattenFields(obj) {
|
|
477
|
-
const out = [];
|
|
478
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
479
|
-
out.push(k, typeof v === "string" ? v : JSON.stringify(v));
|
|
480
|
-
}
|
|
481
|
-
return out;
|
|
482
|
-
}
|
|
483
|
-
var NodeRedisPublisher = class {
|
|
484
|
-
stream;
|
|
485
|
-
url;
|
|
486
|
-
client;
|
|
487
|
-
// redis.RedisClientType
|
|
488
|
-
connected = false;
|
|
489
|
-
constructor(url, streamPrefix) {
|
|
490
|
-
this.url = url;
|
|
491
|
-
this.stream = `${streamPrefix}:intents`;
|
|
492
|
-
}
|
|
493
|
-
async start() {
|
|
494
|
-
if (this.connected) return;
|
|
495
|
-
const { createClient } = await import("redis");
|
|
496
|
-
this.client = createClient({ url: this.url });
|
|
497
|
-
this.client.on("error", (e) => {
|
|
498
|
-
console.warn("[publisher] redis error:", e?.message || e);
|
|
499
|
-
});
|
|
500
|
-
await this.client.connect();
|
|
501
|
-
this.connected = true;
|
|
502
|
-
}
|
|
503
|
-
async stop() {
|
|
504
|
-
if (!this.connected) return;
|
|
505
|
-
try {
|
|
506
|
-
await this.client.quit();
|
|
507
|
-
} catch {
|
|
508
|
-
} finally {
|
|
509
|
-
this.connected = false;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
async publishIntent(intent) {
|
|
513
|
-
if (!this.connected) await this.start();
|
|
514
|
-
const fields = flattenFields(intent);
|
|
515
|
-
return this.client.xAdd(this.stream, "*", fields);
|
|
516
|
-
}
|
|
517
|
-
};
|
|
518
|
-
var HttpIngressPublisher = class {
|
|
519
|
-
constructor(ingressUrl = "/api/intents", fetchImpl = fetch) {
|
|
520
|
-
this.ingressUrl = ingressUrl;
|
|
521
|
-
this.fetchImpl = fetchImpl;
|
|
522
|
-
}
|
|
523
|
-
async start() {
|
|
524
|
-
}
|
|
525
|
-
async stop() {
|
|
526
|
-
}
|
|
527
|
-
async publishIntent(intent) {
|
|
528
|
-
const r = await this.fetchImpl(this.ingressUrl, {
|
|
529
|
-
method: "POST",
|
|
530
|
-
headers: { "content-type": "application/json" },
|
|
531
|
-
body: JSON.stringify(intent),
|
|
532
|
-
// keepalive is nice to reduce aborted posts on unload
|
|
533
|
-
keepalive: true
|
|
534
|
-
});
|
|
535
|
-
if (!r.ok) {
|
|
536
|
-
throw new Error(
|
|
537
|
-
`HTTP ingress failed: ${r.status} ${await r.text().catch(() => "")}`
|
|
538
|
-
);
|
|
539
|
-
}
|
|
540
|
-
const j = await r.json().catch(() => ({}));
|
|
541
|
-
return j?.id ?? "ok";
|
|
542
|
-
}
|
|
543
|
-
};
|
|
544
|
-
function createPublisher(config = {}) {
|
|
545
|
-
const streamPrefix = config.streamPrefix ?? (IS_BROWSER ? process.env.NEXT_PUBLIC_REDIS_STREAM_PREFIX || "n3" : process.env.REDIS_STREAM_PREFIX || "n3");
|
|
546
|
-
if (!IS_BROWSER) {
|
|
547
|
-
const redisUrl = config.redisUrl || process.env.REDIS_URL;
|
|
548
|
-
if (!redisUrl) {
|
|
549
|
-
throw new Error("createPublisher: REDIS_URL is required on server runtime.");
|
|
550
|
-
}
|
|
551
|
-
return new NodeRedisPublisher(redisUrl, streamPrefix);
|
|
552
|
-
}
|
|
553
|
-
const ingress = config.httpIngressUrl || "/api/intents";
|
|
554
|
-
return new HttpIngressPublisher(ingress);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// src/lib/utils/publisher.ts
|
|
558
|
-
var _pub = null;
|
|
559
|
-
var _started = false;
|
|
560
|
-
function getPublisher() {
|
|
561
|
-
if (_pub) return _pub;
|
|
562
|
-
_pub = createPublisher({
|
|
563
|
-
// Optional override; your publisher.ts already reads from env inside.
|
|
564
|
-
streamPrefix: (typeof window === "undefined" ? process.env.REDIS_STREAM_PREFIX : process.env.NEXT_PUBLIC_REDIS_STREAM_PREFIX) || "n3",
|
|
565
|
-
// Node/server fast path (TCP):
|
|
566
|
-
redisUrl: typeof window === "undefined" ? process.env.REDIS_URL : void 0,
|
|
567
|
-
// Browser fallback → your app’s ingress (default `/api/intents`)
|
|
568
|
-
httpIngressUrl: typeof window !== "undefined" ? process.env.NEXT_PUBLIC_INTENT_INGRESS || "/api/intents" : void 0
|
|
569
|
-
});
|
|
570
|
-
return _pub;
|
|
571
|
-
}
|
|
572
|
-
async function startPublisher() {
|
|
573
|
-
if (_started) return;
|
|
574
|
-
await getPublisher().start();
|
|
575
|
-
_started = true;
|
|
576
|
-
}
|
|
577
|
-
async function publishIntent(intent) {
|
|
578
|
-
if (!_started) await startPublisher();
|
|
579
|
-
return getPublisher().publishIntent(intent);
|
|
580
|
-
}
|
|
581
|
-
async function stopPublisher() {
|
|
582
|
-
if (!_started) return;
|
|
583
|
-
await getPublisher().stop();
|
|
584
|
-
_started = false;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
473
|
// src/lib/utils/stripForHyperliquid.ts
|
|
588
474
|
function stripForHyperliquid(intent) {
|
|
589
475
|
const { n3: _omit, ...rest } = intent;
|
|
@@ -4261,11 +4147,7 @@ export {
|
|
|
4261
4147
|
Receiver,
|
|
4262
4148
|
subscription_exports as Subscription,
|
|
4263
4149
|
Topics,
|
|
4264
|
-
createPublisher,
|
|
4265
4150
|
src_default as default,
|
|
4266
|
-
publishIntent,
|
|
4267
|
-
startPublisher,
|
|
4268
|
-
stopPublisher,
|
|
4269
4151
|
toReceiverFromBlock,
|
|
4270
4152
|
toViemFromBlock
|
|
4271
4153
|
};
|