@arkade-os/sdk 0.3.1-alpha.0 → 0.3.1-alpha.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.
- package/dist/cjs/providers/expoArk.js +5 -5
- package/dist/cjs/providers/expoIndexer.js +3 -3
- package/dist/cjs/providers/expoUtils.js +124 -0
- package/dist/cjs/providers/utils.js +0 -122
- package/dist/esm/providers/expoArk.js +1 -1
- package/dist/esm/providers/expoIndexer.js +1 -1
- package/dist/esm/providers/expoUtils.js +87 -0
- package/dist/esm/providers/utils.js +0 -87
- package/dist/types/providers/expoUtils.d.ts +18 -0
- package/dist/types/providers/utils.d.ts +0 -18
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ExpoArkProvider = void 0;
|
|
4
4
|
const ark_1 = require("./ark");
|
|
5
|
-
const
|
|
5
|
+
const expoUtils_1 = require("./expoUtils");
|
|
6
6
|
/**
|
|
7
7
|
* Expo-compatible Ark provider implementation using expo/fetch for SSE support.
|
|
8
8
|
* This provider works specifically in React Native/Expo environments where
|
|
@@ -21,14 +21,14 @@ class ExpoArkProvider extends ark_1.RestArkProvider {
|
|
|
21
21
|
super(serverUrl);
|
|
22
22
|
}
|
|
23
23
|
async *getEventStream(signal, topics) {
|
|
24
|
-
const expoFetch = await (0,
|
|
24
|
+
const expoFetch = await (0, expoUtils_1.getExpoFetch)();
|
|
25
25
|
const url = `${this.serverUrl}/v1/batch/events`;
|
|
26
26
|
const queryParams = topics.length > 0
|
|
27
27
|
? `?${topics.map((topic) => `topics=${encodeURIComponent(topic)}`).join("&")}`
|
|
28
28
|
: "";
|
|
29
29
|
while (!signal?.aborted) {
|
|
30
30
|
try {
|
|
31
|
-
yield* (0,
|
|
31
|
+
yield* (0, expoUtils_1.sseStreamIterator)(url + queryParams, signal, expoFetch, {}, (data) => {
|
|
32
32
|
// Handle different response structures
|
|
33
33
|
// v8 mesh API might wrap in {result: ...} or send directly
|
|
34
34
|
const eventData = data.result || data;
|
|
@@ -55,11 +55,11 @@ class ExpoArkProvider extends ark_1.RestArkProvider {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
async *getTransactionsStream(signal) {
|
|
58
|
-
const expoFetch = await (0,
|
|
58
|
+
const expoFetch = await (0, expoUtils_1.getExpoFetch)();
|
|
59
59
|
const url = `${this.serverUrl}/v1/txs`;
|
|
60
60
|
while (!signal?.aborted) {
|
|
61
61
|
try {
|
|
62
|
-
yield* (0,
|
|
62
|
+
yield* (0, expoUtils_1.sseStreamIterator)(url, signal, expoFetch, {}, (data) => {
|
|
63
63
|
return this.parseTransactionNotification(data.result);
|
|
64
64
|
});
|
|
65
65
|
}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ExpoIndexerProvider = void 0;
|
|
4
4
|
const indexer_1 = require("./indexer");
|
|
5
5
|
const ark_1 = require("./ark");
|
|
6
|
-
const
|
|
6
|
+
const expoUtils_1 = require("./expoUtils");
|
|
7
7
|
// Helper function to convert Vtxo to VirtualCoin (same as in indexer.ts)
|
|
8
8
|
function convertVtxo(vtxo) {
|
|
9
9
|
return {
|
|
@@ -53,7 +53,7 @@ class ExpoIndexerProvider extends indexer_1.RestIndexerProvider {
|
|
|
53
53
|
// Detect if we're running in React Native/Expo environment
|
|
54
54
|
const isReactNative = typeof navigator !== "undefined" &&
|
|
55
55
|
navigator.product === "ReactNative";
|
|
56
|
-
const expoFetch = await (0,
|
|
56
|
+
const expoFetch = await (0, expoUtils_1.getExpoFetch)().catch((error) => {
|
|
57
57
|
// In React Native/Expo, expo/fetch is required for proper streaming support
|
|
58
58
|
if (isReactNative) {
|
|
59
59
|
throw new Error("expo/fetch is unavailable in React Native environment. " +
|
|
@@ -65,7 +65,7 @@ class ExpoIndexerProvider extends indexer_1.RestIndexerProvider {
|
|
|
65
65
|
const url = `${this.serverUrl}/v1/indexer/script/subscription/${subscriptionId}`;
|
|
66
66
|
while (!abortSignal.aborted) {
|
|
67
67
|
try {
|
|
68
|
-
yield* (0,
|
|
68
|
+
yield* (0, expoUtils_1.sseStreamIterator)(url, abortSignal, expoFetch, { "Content-Type": "application/json" }, (data) => {
|
|
69
69
|
// Handle new v8 proto format with heartbeat or event
|
|
70
70
|
if (data.heartbeat !== undefined) {
|
|
71
71
|
// Skip heartbeat messages
|
|
@@ -0,0 +1,124 @@
|
|
|
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.getExpoFetch = getExpoFetch;
|
|
37
|
+
exports.sseStreamIterator = sseStreamIterator;
|
|
38
|
+
/**
|
|
39
|
+
* Dynamically imports expo/fetch with fallback to standard fetch.
|
|
40
|
+
* @returns A fetch function suitable for SSE streaming
|
|
41
|
+
*/
|
|
42
|
+
async function getExpoFetch(options) {
|
|
43
|
+
const requireExpo = options?.requireExpo ?? false;
|
|
44
|
+
try {
|
|
45
|
+
const expoFetchModule = await Promise.resolve().then(() => __importStar(require("expo/fetch")));
|
|
46
|
+
console.debug("Using expo/fetch for streaming");
|
|
47
|
+
return expoFetchModule.fetch;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (requireExpo) {
|
|
51
|
+
throw new Error("expo/fetch is unavailable in this environment. " +
|
|
52
|
+
"Please ensure expo/fetch is installed and properly configured.");
|
|
53
|
+
}
|
|
54
|
+
console.warn("Using standard fetch instead of expo/fetch. " +
|
|
55
|
+
"Streaming may not be fully supported in some environments.", error);
|
|
56
|
+
return fetch;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Generic SSE stream processor using fetch API with ReadableStream.
|
|
61
|
+
* Handles SSE format parsing, buffer management, and abort signals.
|
|
62
|
+
*
|
|
63
|
+
* @param url - The SSE endpoint URL
|
|
64
|
+
* @param abortSignal - Signal to abort the stream
|
|
65
|
+
* @param fetchFn - Fetch function to use (defaults to standard fetch)
|
|
66
|
+
* @param headers - Additional headers to send
|
|
67
|
+
* @param parseData - Function to parse and yield data from SSE events
|
|
68
|
+
*/
|
|
69
|
+
async function* sseStreamIterator(url, abortSignal, fetchFn, headers, parseData) {
|
|
70
|
+
const fetchController = new AbortController();
|
|
71
|
+
const cleanup = () => fetchController.abort();
|
|
72
|
+
abortSignal?.addEventListener("abort", cleanup, { once: true });
|
|
73
|
+
try {
|
|
74
|
+
const response = await fetchFn(url, {
|
|
75
|
+
headers: {
|
|
76
|
+
Accept: "text/event-stream",
|
|
77
|
+
...headers,
|
|
78
|
+
},
|
|
79
|
+
signal: fetchController.signal,
|
|
80
|
+
});
|
|
81
|
+
if (!response.ok) {
|
|
82
|
+
throw new Error(`Unexpected status ${response.status} when fetching SSE stream`);
|
|
83
|
+
}
|
|
84
|
+
if (!response.body) {
|
|
85
|
+
throw new Error("Response body is null");
|
|
86
|
+
}
|
|
87
|
+
const reader = response.body.getReader();
|
|
88
|
+
const decoder = new TextDecoder();
|
|
89
|
+
let buffer = "";
|
|
90
|
+
while (!abortSignal?.aborted) {
|
|
91
|
+
const { done, value } = await reader.read();
|
|
92
|
+
if (done) {
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
buffer += decoder.decode(value, { stream: true });
|
|
96
|
+
const lines = buffer.split("\n");
|
|
97
|
+
for (let i = 0; i < lines.length - 1; i++) {
|
|
98
|
+
const line = lines[i].trim();
|
|
99
|
+
if (!line)
|
|
100
|
+
continue;
|
|
101
|
+
if (line.startsWith("data:")) {
|
|
102
|
+
const jsonStr = line.substring(5).trim();
|
|
103
|
+
if (!jsonStr)
|
|
104
|
+
continue;
|
|
105
|
+
try {
|
|
106
|
+
const data = JSON.parse(jsonStr);
|
|
107
|
+
const parsed = parseData(data);
|
|
108
|
+
if (parsed !== null) {
|
|
109
|
+
yield parsed;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (parseError) {
|
|
113
|
+
console.error("Failed to parse SSE data:", parseError);
|
|
114
|
+
throw parseError;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
buffer = lines[lines.length - 1];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
abortSignal?.removeEventListener("abort", cleanup);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -1,41 +1,6 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
3
|
exports.eventSourceIterator = eventSourceIterator;
|
|
37
|
-
exports.getExpoFetch = getExpoFetch;
|
|
38
|
-
exports.sseStreamIterator = sseStreamIterator;
|
|
39
4
|
async function* eventSourceIterator(eventSource) {
|
|
40
5
|
const messageQueue = [];
|
|
41
6
|
const errorQueue = [];
|
|
@@ -93,90 +58,3 @@ async function* eventSourceIterator(eventSource) {
|
|
|
93
58
|
eventSource.removeEventListener("error", errorHandler);
|
|
94
59
|
}
|
|
95
60
|
}
|
|
96
|
-
/**
|
|
97
|
-
* Dynamically imports expo/fetch with fallback to standard fetch.
|
|
98
|
-
* @returns A fetch function suitable for SSE streaming
|
|
99
|
-
*/
|
|
100
|
-
async function getExpoFetch(options) {
|
|
101
|
-
const requireExpo = options?.requireExpo ?? false;
|
|
102
|
-
try {
|
|
103
|
-
const expoFetchModule = await Promise.resolve().then(() => __importStar(require("expo/fetch")));
|
|
104
|
-
console.debug("Using expo/fetch for streaming");
|
|
105
|
-
return expoFetchModule.fetch;
|
|
106
|
-
}
|
|
107
|
-
catch (error) {
|
|
108
|
-
if (requireExpo) {
|
|
109
|
-
throw new Error("expo/fetch is unavailable in this environment. " +
|
|
110
|
-
"Please ensure expo/fetch is installed and properly configured.");
|
|
111
|
-
}
|
|
112
|
-
console.warn("Using standard fetch instead of expo/fetch. " +
|
|
113
|
-
"Streaming may not be fully supported in some environments.", error);
|
|
114
|
-
return fetch;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Generic SSE stream processor using fetch API with ReadableStream.
|
|
119
|
-
* Handles SSE format parsing, buffer management, and abort signals.
|
|
120
|
-
*
|
|
121
|
-
* @param url - The SSE endpoint URL
|
|
122
|
-
* @param abortSignal - Signal to abort the stream
|
|
123
|
-
* @param fetchFn - Fetch function to use (defaults to standard fetch)
|
|
124
|
-
* @param headers - Additional headers to send
|
|
125
|
-
* @param parseData - Function to parse and yield data from SSE events
|
|
126
|
-
*/
|
|
127
|
-
async function* sseStreamIterator(url, abortSignal, fetchFn, headers, parseData) {
|
|
128
|
-
const fetchController = new AbortController();
|
|
129
|
-
const cleanup = () => fetchController.abort();
|
|
130
|
-
abortSignal?.addEventListener("abort", cleanup, { once: true });
|
|
131
|
-
try {
|
|
132
|
-
const response = await fetchFn(url, {
|
|
133
|
-
headers: {
|
|
134
|
-
Accept: "text/event-stream",
|
|
135
|
-
...headers,
|
|
136
|
-
},
|
|
137
|
-
signal: fetchController.signal,
|
|
138
|
-
});
|
|
139
|
-
if (!response.ok) {
|
|
140
|
-
throw new Error(`Unexpected status ${response.status} when fetching SSE stream`);
|
|
141
|
-
}
|
|
142
|
-
if (!response.body) {
|
|
143
|
-
throw new Error("Response body is null");
|
|
144
|
-
}
|
|
145
|
-
const reader = response.body.getReader();
|
|
146
|
-
const decoder = new TextDecoder();
|
|
147
|
-
let buffer = "";
|
|
148
|
-
while (!abortSignal?.aborted) {
|
|
149
|
-
const { done, value } = await reader.read();
|
|
150
|
-
if (done) {
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
buffer += decoder.decode(value, { stream: true });
|
|
154
|
-
const lines = buffer.split("\n");
|
|
155
|
-
for (let i = 0; i < lines.length - 1; i++) {
|
|
156
|
-
const line = lines[i].trim();
|
|
157
|
-
if (!line)
|
|
158
|
-
continue;
|
|
159
|
-
if (line.startsWith("data:")) {
|
|
160
|
-
const jsonStr = line.substring(5).trim();
|
|
161
|
-
if (!jsonStr)
|
|
162
|
-
continue;
|
|
163
|
-
try {
|
|
164
|
-
const data = JSON.parse(jsonStr);
|
|
165
|
-
const parsed = parseData(data);
|
|
166
|
-
if (parsed !== null) {
|
|
167
|
-
yield parsed;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
catch (parseError) {
|
|
171
|
-
console.error("Failed to parse SSE data:", parseError);
|
|
172
|
-
throw parseError;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
buffer = lines[lines.length - 1];
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
finally {
|
|
180
|
-
abortSignal?.removeEventListener("abort", cleanup);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RestArkProvider, isFetchTimeoutError, } from './ark.js';
|
|
2
|
-
import { getExpoFetch, sseStreamIterator } from './
|
|
2
|
+
import { getExpoFetch, sseStreamIterator } from './expoUtils.js';
|
|
3
3
|
/**
|
|
4
4
|
* Expo-compatible Ark provider implementation using expo/fetch for SSE support.
|
|
5
5
|
* This provider works specifically in React Native/Expo environments where
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RestIndexerProvider } from './indexer.js';
|
|
2
2
|
import { isFetchTimeoutError } from './ark.js';
|
|
3
|
-
import { getExpoFetch, sseStreamIterator } from './
|
|
3
|
+
import { getExpoFetch, sseStreamIterator } from './expoUtils.js';
|
|
4
4
|
// Helper function to convert Vtxo to VirtualCoin (same as in indexer.ts)
|
|
5
5
|
function convertVtxo(vtxo) {
|
|
6
6
|
return {
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamically imports expo/fetch with fallback to standard fetch.
|
|
3
|
+
* @returns A fetch function suitable for SSE streaming
|
|
4
|
+
*/
|
|
5
|
+
export async function getExpoFetch(options) {
|
|
6
|
+
const requireExpo = options?.requireExpo ?? false;
|
|
7
|
+
try {
|
|
8
|
+
const expoFetchModule = await import("expo/fetch");
|
|
9
|
+
console.debug("Using expo/fetch for streaming");
|
|
10
|
+
return expoFetchModule.fetch;
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (requireExpo) {
|
|
14
|
+
throw new Error("expo/fetch is unavailable in this environment. " +
|
|
15
|
+
"Please ensure expo/fetch is installed and properly configured.");
|
|
16
|
+
}
|
|
17
|
+
console.warn("Using standard fetch instead of expo/fetch. " +
|
|
18
|
+
"Streaming may not be fully supported in some environments.", error);
|
|
19
|
+
return fetch;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Generic SSE stream processor using fetch API with ReadableStream.
|
|
24
|
+
* Handles SSE format parsing, buffer management, and abort signals.
|
|
25
|
+
*
|
|
26
|
+
* @param url - The SSE endpoint URL
|
|
27
|
+
* @param abortSignal - Signal to abort the stream
|
|
28
|
+
* @param fetchFn - Fetch function to use (defaults to standard fetch)
|
|
29
|
+
* @param headers - Additional headers to send
|
|
30
|
+
* @param parseData - Function to parse and yield data from SSE events
|
|
31
|
+
*/
|
|
32
|
+
export async function* sseStreamIterator(url, abortSignal, fetchFn, headers, parseData) {
|
|
33
|
+
const fetchController = new AbortController();
|
|
34
|
+
const cleanup = () => fetchController.abort();
|
|
35
|
+
abortSignal?.addEventListener("abort", cleanup, { once: true });
|
|
36
|
+
try {
|
|
37
|
+
const response = await fetchFn(url, {
|
|
38
|
+
headers: {
|
|
39
|
+
Accept: "text/event-stream",
|
|
40
|
+
...headers,
|
|
41
|
+
},
|
|
42
|
+
signal: fetchController.signal,
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error(`Unexpected status ${response.status} when fetching SSE stream`);
|
|
46
|
+
}
|
|
47
|
+
if (!response.body) {
|
|
48
|
+
throw new Error("Response body is null");
|
|
49
|
+
}
|
|
50
|
+
const reader = response.body.getReader();
|
|
51
|
+
const decoder = new TextDecoder();
|
|
52
|
+
let buffer = "";
|
|
53
|
+
while (!abortSignal?.aborted) {
|
|
54
|
+
const { done, value } = await reader.read();
|
|
55
|
+
if (done) {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
buffer += decoder.decode(value, { stream: true });
|
|
59
|
+
const lines = buffer.split("\n");
|
|
60
|
+
for (let i = 0; i < lines.length - 1; i++) {
|
|
61
|
+
const line = lines[i].trim();
|
|
62
|
+
if (!line)
|
|
63
|
+
continue;
|
|
64
|
+
if (line.startsWith("data:")) {
|
|
65
|
+
const jsonStr = line.substring(5).trim();
|
|
66
|
+
if (!jsonStr)
|
|
67
|
+
continue;
|
|
68
|
+
try {
|
|
69
|
+
const data = JSON.parse(jsonStr);
|
|
70
|
+
const parsed = parseData(data);
|
|
71
|
+
if (parsed !== null) {
|
|
72
|
+
yield parsed;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (parseError) {
|
|
76
|
+
console.error("Failed to parse SSE data:", parseError);
|
|
77
|
+
throw parseError;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
buffer = lines[lines.length - 1];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
abortSignal?.removeEventListener("abort", cleanup);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -55,90 +55,3 @@ export async function* eventSourceIterator(eventSource) {
|
|
|
55
55
|
eventSource.removeEventListener("error", errorHandler);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
/**
|
|
59
|
-
* Dynamically imports expo/fetch with fallback to standard fetch.
|
|
60
|
-
* @returns A fetch function suitable for SSE streaming
|
|
61
|
-
*/
|
|
62
|
-
export async function getExpoFetch(options) {
|
|
63
|
-
const requireExpo = options?.requireExpo ?? false;
|
|
64
|
-
try {
|
|
65
|
-
const expoFetchModule = await import("expo/fetch");
|
|
66
|
-
console.debug("Using expo/fetch for streaming");
|
|
67
|
-
return expoFetchModule.fetch;
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
if (requireExpo) {
|
|
71
|
-
throw new Error("expo/fetch is unavailable in this environment. " +
|
|
72
|
-
"Please ensure expo/fetch is installed and properly configured.");
|
|
73
|
-
}
|
|
74
|
-
console.warn("Using standard fetch instead of expo/fetch. " +
|
|
75
|
-
"Streaming may not be fully supported in some environments.", error);
|
|
76
|
-
return fetch;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Generic SSE stream processor using fetch API with ReadableStream.
|
|
81
|
-
* Handles SSE format parsing, buffer management, and abort signals.
|
|
82
|
-
*
|
|
83
|
-
* @param url - The SSE endpoint URL
|
|
84
|
-
* @param abortSignal - Signal to abort the stream
|
|
85
|
-
* @param fetchFn - Fetch function to use (defaults to standard fetch)
|
|
86
|
-
* @param headers - Additional headers to send
|
|
87
|
-
* @param parseData - Function to parse and yield data from SSE events
|
|
88
|
-
*/
|
|
89
|
-
export async function* sseStreamIterator(url, abortSignal, fetchFn, headers, parseData) {
|
|
90
|
-
const fetchController = new AbortController();
|
|
91
|
-
const cleanup = () => fetchController.abort();
|
|
92
|
-
abortSignal?.addEventListener("abort", cleanup, { once: true });
|
|
93
|
-
try {
|
|
94
|
-
const response = await fetchFn(url, {
|
|
95
|
-
headers: {
|
|
96
|
-
Accept: "text/event-stream",
|
|
97
|
-
...headers,
|
|
98
|
-
},
|
|
99
|
-
signal: fetchController.signal,
|
|
100
|
-
});
|
|
101
|
-
if (!response.ok) {
|
|
102
|
-
throw new Error(`Unexpected status ${response.status} when fetching SSE stream`);
|
|
103
|
-
}
|
|
104
|
-
if (!response.body) {
|
|
105
|
-
throw new Error("Response body is null");
|
|
106
|
-
}
|
|
107
|
-
const reader = response.body.getReader();
|
|
108
|
-
const decoder = new TextDecoder();
|
|
109
|
-
let buffer = "";
|
|
110
|
-
while (!abortSignal?.aborted) {
|
|
111
|
-
const { done, value } = await reader.read();
|
|
112
|
-
if (done) {
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
buffer += decoder.decode(value, { stream: true });
|
|
116
|
-
const lines = buffer.split("\n");
|
|
117
|
-
for (let i = 0; i < lines.length - 1; i++) {
|
|
118
|
-
const line = lines[i].trim();
|
|
119
|
-
if (!line)
|
|
120
|
-
continue;
|
|
121
|
-
if (line.startsWith("data:")) {
|
|
122
|
-
const jsonStr = line.substring(5).trim();
|
|
123
|
-
if (!jsonStr)
|
|
124
|
-
continue;
|
|
125
|
-
try {
|
|
126
|
-
const data = JSON.parse(jsonStr);
|
|
127
|
-
const parsed = parseData(data);
|
|
128
|
-
if (parsed !== null) {
|
|
129
|
-
yield parsed;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
catch (parseError) {
|
|
133
|
-
console.error("Failed to parse SSE data:", parseError);
|
|
134
|
-
throw parseError;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
buffer = lines[lines.length - 1];
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
finally {
|
|
142
|
-
abortSignal?.removeEventListener("abort", cleanup);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamically imports expo/fetch with fallback to standard fetch.
|
|
3
|
+
* @returns A fetch function suitable for SSE streaming
|
|
4
|
+
*/
|
|
5
|
+
export declare function getExpoFetch(options?: {
|
|
6
|
+
requireExpo?: boolean;
|
|
7
|
+
}): Promise<typeof fetch>;
|
|
8
|
+
/**
|
|
9
|
+
* Generic SSE stream processor using fetch API with ReadableStream.
|
|
10
|
+
* Handles SSE format parsing, buffer management, and abort signals.
|
|
11
|
+
*
|
|
12
|
+
* @param url - The SSE endpoint URL
|
|
13
|
+
* @param abortSignal - Signal to abort the stream
|
|
14
|
+
* @param fetchFn - Fetch function to use (defaults to standard fetch)
|
|
15
|
+
* @param headers - Additional headers to send
|
|
16
|
+
* @param parseData - Function to parse and yield data from SSE events
|
|
17
|
+
*/
|
|
18
|
+
export declare function sseStreamIterator<T>(url: string, abortSignal: AbortSignal, fetchFn: typeof fetch, headers: Record<string, string>, parseData: (data: any) => T | null): AsyncGenerator<T, void, unknown>;
|
|
@@ -1,19 +1 @@
|
|
|
1
1
|
export declare function eventSourceIterator(eventSource: EventSource): AsyncGenerator<MessageEvent, void, unknown>;
|
|
2
|
-
/**
|
|
3
|
-
* Dynamically imports expo/fetch with fallback to standard fetch.
|
|
4
|
-
* @returns A fetch function suitable for SSE streaming
|
|
5
|
-
*/
|
|
6
|
-
export declare function getExpoFetch(options?: {
|
|
7
|
-
requireExpo?: boolean;
|
|
8
|
-
}): Promise<typeof fetch>;
|
|
9
|
-
/**
|
|
10
|
-
* Generic SSE stream processor using fetch API with ReadableStream.
|
|
11
|
-
* Handles SSE format parsing, buffer management, and abort signals.
|
|
12
|
-
*
|
|
13
|
-
* @param url - The SSE endpoint URL
|
|
14
|
-
* @param abortSignal - Signal to abort the stream
|
|
15
|
-
* @param fetchFn - Fetch function to use (defaults to standard fetch)
|
|
16
|
-
* @param headers - Additional headers to send
|
|
17
|
-
* @param parseData - Function to parse and yield data from SSE events
|
|
18
|
-
*/
|
|
19
|
-
export declare function sseStreamIterator<T>(url: string, abortSignal: AbortSignal, fetchFn: typeof fetch, headers: Record<string, string>, parseData: (data: any) => T | null): AsyncGenerator<T, void, unknown>;
|