@milkio/stargate 1.0.0-alpha.92 → 1.0.0-alpha.94

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 (2) hide show
  1. package/index.ts +557 -377
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -1,112 +1,112 @@
1
- import { TSON } from '@southern-aurora/tson'
1
+ import { TSON } from "@southern-aurora/tson";
2
2
 
3
3
  export type MilkioStargateOptions = {
4
- baseUrl: string | (() => string) | (() => Promise<string>)
5
- timeout?: number
6
- fetch?: typeof fetch
7
- abort?: typeof AbortController
8
- }
4
+ baseUrl: string | (() => string) | (() => Promise<string>);
5
+ timeout?: number;
6
+ fetch?: typeof fetch;
7
+ abort?: typeof AbortController;
8
+ };
9
9
 
10
- export type Mixin<T, U> = U & Omit<T, keyof U>
10
+ export type Mixin<T, U> = U & Omit<T, keyof U>;
11
11
 
12
12
  export type ExecuteOptions = {
13
- params?: Record<any, any>
14
- headers?: Record<string, string>
15
- timeout?: number
16
- type?: 'action' | 'stream'
17
- baseUrl?: string | (() => string) | (() => Promise<string>)
18
- }
13
+ params?: Record<any, any>;
14
+ headers?: Record<string, string>;
15
+ timeout?: number;
16
+ type?: "action" | "stream";
17
+ baseUrl?: string | (() => string) | (() => Promise<string>);
18
+ };
19
19
 
20
- export type ExecuteResultsOption = { executeId: string }
20
+ export type ExecuteResultsOption = { executeId: string };
21
21
 
22
22
  export type Ping =
23
23
  | [
24
- {
25
- connect: false
26
- delay: number
27
- error: any
28
- },
29
- null,
30
- ]
24
+ {
25
+ connect: false;
26
+ delay: number;
27
+ error: any;
28
+ },
29
+ null,
30
+ ]
31
31
  | [
32
- null,
33
- {
34
- connect: true
35
- delay: number
36
- serverTimestamp: number
37
- },
38
- ]
39
- export async function createStargate<Generated extends { routeSchema: any, rejectCode: any }>(stargateOptions: MilkioStargateOptions) {
40
- const $fetch = stargateOptions.fetch ?? fetch
41
- const $abort = stargateOptions.abort ?? AbortController
32
+ null,
33
+ {
34
+ connect: true;
35
+ delay: number;
36
+ serverTimestamp: number;
37
+ },
38
+ ];
39
+ export async function createStargate<Generated extends { routeSchema: any; rejectCode: any }>(stargateOptions: MilkioStargateOptions) {
40
+ const $fetch = stargateOptions.fetch ?? fetch;
41
+ const $abort = stargateOptions.abort ?? AbortController;
42
42
 
43
43
  type StargateEvents = {
44
- 'milkio:executeBefore': { path: string, options: Mixin<ExecuteOptions, { headers: Record<string, string>, baseUrl: string }> }
45
- 'milkio:fetchBefore': { path: string, options: Mixin<ExecuteOptions, { headers: Record<string, string>, baseUrl: string }>, body: string }
46
- 'milkio:executeError': {
47
- path: string
48
- options: Mixin<ExecuteOptions, { headers: Record<string, string>, baseUrl: string }>
49
- error: Partial<Generated['rejectCode']>
50
- handleError: <K extends keyof Partial<Generated['rejectCode']>>(error: any, key: K, handler: (error: Partial<Generated['rejectCode'][K]>) => boolean | Promise<boolean>) => Promise<void>
51
- }
52
- }
44
+ "milkio:executeBefore": { path: string; options: Mixin<ExecuteOptions, { headers: Record<string, string>; baseUrl: string }> };
45
+ "milkio:fetchBefore": { path: string; options: Mixin<ExecuteOptions, { headers: Record<string, string>; baseUrl: string }>; body: string };
46
+ "milkio:executeError": {
47
+ path: string;
48
+ options: Mixin<ExecuteOptions, { headers: Record<string, string>; baseUrl: string }>;
49
+ error: Partial<Generated["rejectCode"]>;
50
+ handleError: <K extends keyof Partial<Generated["rejectCode"]>>(error: any, key: K, handler: (error: Partial<Generated["rejectCode"][K]>) => boolean | Promise<boolean>) => Promise<void>;
51
+ };
52
+ };
53
53
 
54
54
  const handleError: any = async (error: any, key: string, handler: (error: any) => boolean | Promise<boolean>) => {
55
55
  if (key in error) {
56
- const handled = await handler(error[key])
57
- if (handled) delete error[key]
56
+ const handled = await handler(error[key]);
57
+ if (handled) delete error[key];
58
58
  }
59
- }
59
+ };
60
60
 
61
61
  const __initEventManager = () => {
62
- const handlers = new Map<(event: any) => void, string>()
63
- const indexed = new Map<string, Set<(event: any) => void>>()
62
+ const handlers = new Map<(event: any) => void, string>();
63
+ const indexed = new Map<string, Set<(event: any) => void>>();
64
64
 
65
65
  const eventManager = {
66
66
  on: <Key extends keyof StargateEvents, Handler extends (event: StargateEvents[Key]) => void>(key: Key, handler: Handler) => {
67
- handlers.set(handler, key as string)
67
+ handlers.set(handler, key as string);
68
68
  if (indexed.has(key as string) === false) {
69
- indexed.set(key as string, new Set())
69
+ indexed.set(key as string, new Set());
70
70
  }
71
- const set = indexed.get(key as string)!
72
- set.add(handler)
73
- handlers.set(handler, key as string)
71
+ const set = indexed.get(key as string)!;
72
+ set.add(handler);
73
+ handlers.set(handler, key as string);
74
74
 
75
75
  return () => {
76
- handlers.delete(handler)
77
- set.delete(handler)
78
- }
76
+ handlers.delete(handler);
77
+ set.delete(handler);
78
+ };
79
79
  },
80
80
  off: <Key extends keyof StargateEvents, Handler extends (event: StargateEvents[Key]) => void>(key: Key, handler: Handler) => {
81
- const set = indexed.get(key as string)
82
- if (!set) return
83
- handlers.delete(handler)
84
- set.delete(handler)
81
+ const set = indexed.get(key as string);
82
+ if (!set) return;
83
+ handlers.delete(handler);
84
+ set.delete(handler);
85
85
  },
86
86
  emit: async <Key extends keyof StargateEvents, Value extends StargateEvents[Key]>(key: Key, value: Value): Promise<void> => {
87
- const h = indexed.get(key as string)
87
+ const h = indexed.get(key as string);
88
88
  if (h) {
89
89
  for (const handler of h) {
90
- await handler(value)
90
+ await handler(value);
91
91
  }
92
92
  }
93
93
  },
94
- }
94
+ };
95
95
 
96
- return eventManager
97
- }
96
+ return eventManager;
97
+ };
98
98
 
99
- const eventManager = __initEventManager()
99
+ const eventManager = __initEventManager();
100
100
 
101
101
  const bootstrap = async () => {
102
- let baseUrl = stargateOptions.baseUrl
103
- if (typeof baseUrl === 'function') baseUrl = await baseUrl()
104
- if (baseUrl.endsWith('/')) baseUrl = baseUrl.slice(0, -1)
102
+ let baseUrl = stargateOptions.baseUrl;
103
+ if (typeof baseUrl === "function") baseUrl = await baseUrl();
104
+ if (baseUrl.endsWith("/")) baseUrl = baseUrl.slice(0, -1);
105
105
 
106
- return baseUrl
107
- }
106
+ return baseUrl;
107
+ };
108
108
 
109
- const baseUrl: Promise<string> = bootstrap()
109
+ const baseUrl: Promise<string> = bootstrap();
110
110
 
111
111
  const stargate = {
112
112
  ...eventManager,
@@ -114,412 +114,601 @@ export async function createStargate<Generated extends { routeSchema: any, rejec
114
114
  generated: void 0 as unknown as Generated,
115
115
  },
116
116
  options: stargateOptions,
117
- async execute<Path extends keyof Generated['routeSchema']>(
117
+ async execute<Path extends keyof Generated["routeSchema"]>(
118
118
  path: Path,
119
119
  options?: Mixin<
120
120
  ExecuteOptions,
121
121
  {
122
- params?: Generated['routeSchema'][Path]['types']['params']
122
+ params?: Generated["routeSchema"][Path]["types"]["params"];
123
123
  }
124
124
  >,
125
125
  ): Promise<
126
- Generated['routeSchema'][Path]['types']['🐣'] extends boolean
127
- ? // action
128
- [Partial<Generated['rejectCode']>, null, ExecuteResultsOption] | [null, Generated['routeSchema'][Path]['types']['result'], ExecuteResultsOption]
129
- : // stream
130
- [Partial<Generated['rejectCode']>, null, ExecuteResultsOption] | [null, AsyncGenerator<[Partial<Generated['rejectCode']>, null] | [null, GeneratorGeneric<Generated['routeSchema'][Path]['types']['result']>], ExecuteResultsOption>]
131
- > {
132
- if (!options) options = {}
133
- if (options.headers === undefined) options.headers = {}
134
-
135
- let url: string
126
+ Generated["routeSchema"][Path]["types"]["🐣"] extends boolean
127
+ ? // action
128
+ [Partial<Generated["rejectCode"]>, null, ExecuteResultsOption] | [null, Generated["routeSchema"][Path]["types"]["result"], ExecuteResultsOption]
129
+ : // stream
130
+ [Partial<Generated["rejectCode"]>, null, ExecuteResultsOption] | [null, AsyncGenerator<[Partial<Generated["rejectCode"]>, null] | [null, GeneratorGeneric<Generated["routeSchema"][Path]["types"]["result"]>], ExecuteResultsOption>]
131
+ > {
132
+ // biome-ignore lint/style/noParameterAssign: <explanation>
133
+ if (!options) options = {};
134
+ if (options.headers === undefined) options.headers = {};
135
+
136
+ let url: string;
136
137
  if (options.baseUrl) {
137
- let baseUrl = options.baseUrl
138
- if (typeof baseUrl === 'function') baseUrl = await baseUrl()
139
- if (baseUrl.endsWith('/')) baseUrl = baseUrl.slice(0, -1)
140
- url = baseUrl + (path as string)
141
- }
142
- else {
143
- url = (await baseUrl) + (path as string)
138
+ let baseUrl = options.baseUrl;
139
+ if (typeof baseUrl === "function") baseUrl = await baseUrl();
140
+ if (baseUrl.endsWith("/")) baseUrl = baseUrl.slice(0, -1);
141
+ url = baseUrl + (path as string);
142
+ } else {
143
+ url = (await baseUrl) + (path as string);
144
144
  }
145
145
 
146
- if (options.type !== 'stream') {
146
+ if (options.type !== "stream") {
147
147
  // action
148
- if (options.headers.Accept === undefined) options.headers.Accept = 'application/json'
149
- if (options.headers['Content-Type'] === undefined) options.headers['Content-Type'] = 'application/json'
150
- let result: { value: Record<any, any> }
148
+ if (options.headers.Accept === undefined) options.headers.Accept = "application/json";
149
+ if (options.headers["Content-Type"] === undefined) options.headers["Content-Type"] = "application/json";
150
+ let result: { value: Record<any, any> };
151
151
 
152
152
  try {
153
- await eventManager.emit('milkio:executeBefore', { path: path as string, options: options as any })
153
+ await eventManager.emit("milkio:executeBefore", { path: path as string, options: options as any });
154
154
 
155
- const body = TSON.stringify(options.params) ?? ''
156
- await eventManager.emit('milkio:fetchBefore', { path: path as string, options: options as any, body })
155
+ const body = TSON.stringify(options.params) ?? "";
156
+ await eventManager.emit("milkio:fetchBefore", { path: path as string, options: options as any, body });
157
157
 
158
+ // biome-ignore lint/suspicious/noAsyncPromiseExecutor: <explanation>
158
159
  const response = await new Promise<string>(async (resolve, reject) => {
159
- const timeout = options?.timeout ?? options?.timeout ?? 6000
160
+ const timeout = options?.timeout ?? options?.timeout ?? 6000;
160
161
  const timer = setTimeout(() => {
161
- reject([{ REQUEST_TIMEOUT: { timeout, message: `Execute timeout after ${timeout}ms.` } }, null])
162
- }, timeout)
162
+ reject([{ REQUEST_TIMEOUT: { timeout, message: `Execute timeout after ${timeout}ms.` } }, null]);
163
+ }, timeout);
163
164
 
164
165
  try {
165
- const value = await (await $fetch(url, { method: 'POST', body, headers: options.headers })).text()
166
- clearTimeout(timer)
167
- resolve(value)
168
- }
169
- catch (error) {
170
- reject(error)
166
+ const value = await (await $fetch(url, { method: "POST", body, headers: options.headers })).text();
167
+ clearTimeout(timer);
168
+ resolve(value);
169
+ } catch (error) {
170
+ reject(error);
171
171
  }
172
- })
173
- result = { value: TSON.parse(response) }
174
- }
175
- catch (error: any) {
172
+ });
173
+ result = { value: TSON.parse(response) };
174
+ } catch (error: any) {
176
175
  if (error?.[0]?.REQUEST_TIMEOUT) {
177
- await eventManager.emit('milkio:executeError', { handleError, path: path as string, options: options as any, error })
178
- return error
176
+ await eventManager.emit("milkio:executeError", { handleError, path: path as string, options: options as any, error });
177
+ return error;
179
178
  }
180
- const errorPined = { REQUEST_FAIL: error }
181
- await eventManager.emit('milkio:executeError', { handleError, path: path as string, options: options as any, error: errorPined })
182
- return [errorPined, null, { executeId: 'unknown' }]
179
+ const errorPined = { REQUEST_FAIL: error };
180
+ await eventManager.emit("milkio:executeError", { handleError, path: path as string, options: options as any, error: errorPined });
181
+ return [errorPined, null, { executeId: "unknown" }];
183
182
  }
184
183
  if (result.value.success !== true) {
185
- const error: any = {}
186
- error[result.value.code] = result.value.reject ?? null
187
- await eventManager.emit('milkio:executeError', { handleError, path: path as string, options: options as any, error })
188
- return [error, null, { executeId: 'unknown' }]
184
+ const error: any = {};
185
+ error[result.value.code] = result.value.reject ?? null;
186
+ await eventManager.emit("milkio:executeError", { handleError, path: path as string, options: options as any, error });
187
+ return [error, null, { executeId: "unknown" }];
189
188
  }
190
189
 
191
- return [null, result.value.data, { executeId: result.value.executeId }] as any
192
- }
193
- else {
190
+ return [null, result.value.data, { executeId: result.value.executeId }] as any;
191
+ } else {
194
192
  // stream
195
- if (options.headers.Accept === undefined) options.headers.Accept = 'text/event-stream'
196
- if (options.headers['Content-Type'] === undefined) options.headers['Content-Type'] = 'application/json'
193
+ if (options.headers.Accept === undefined) options.headers.Accept = "text/event-stream";
194
+ if (options.headers["Content-Type"] === undefined) options.headers["Content-Type"] = "application/json";
197
195
 
198
196
  const stacks: Map<
199
197
  number,
200
198
  {
201
- done: boolean
202
- promise: Promise<IteratorResult<any>>
203
- resolve: (value: IteratorResult<any>) => void
204
- reject: (reason: any) => void
199
+ done: boolean;
200
+ promise: Promise<IteratorResult<any>>;
201
+ resolve: (value: IteratorResult<any>) => void;
202
+ reject: (reason: any) => void;
205
203
  }
206
- > = new Map()
207
- let stacksIndex: number = 0
208
- let iteratorIndex: number = 0
209
- let streamResult: any
210
- const streamResultFetched = withResolvers<undefined>()
204
+ > = new Map();
205
+ let stacksIndex = 0;
206
+ let iteratorIndex = 0;
207
+ let streamResult: any;
208
+ const streamResultFetched = withResolvers<undefined>();
211
209
 
212
- const timeout = stargateOptions?.timeout ?? options?.timeout ?? 6000
210
+ const timeout = stargateOptions?.timeout ?? options?.timeout ?? 6000;
213
211
  const timer = setTimeout(() => {
214
- streamResultFetched.reject([{ REQUEST_TIMEOUT: { timeout, message: `Execute timeout after ${timeout}ms.` } }, null, { executeId: 'unknown' }])
215
- }, timeout)
212
+ streamResultFetched.reject([{ REQUEST_TIMEOUT: { timeout, message: `Execute timeout after ${timeout}ms.` } }, null, { executeId: "unknown" }]);
213
+ }, timeout);
216
214
 
217
215
  const onmessage = (event: EventSourceMessage) => {
218
- if (event.data.startsWith('@')) {
216
+ if (event.data.startsWith("@")) {
219
217
  try {
220
- streamResult = TSON.parse(event.data.slice(1))
221
- streamResultFetched.resolve(undefined)
222
- clearTimeout(timer)
218
+ streamResult = TSON.parse(event.data.slice(1));
219
+ streamResultFetched.resolve(undefined);
220
+ clearTimeout(timer);
221
+ } catch (error) {
222
+ streamResultFetched.reject([{ REQUEST_FAIL: error }, null, { executeId: "unknown" }]);
223
+ clearTimeout(timer);
223
224
  }
224
- catch (error) {
225
- streamResultFetched.reject([{ REQUEST_FAIL: error }, null, { executeId: 'unknown' }])
226
- clearTimeout(timer)
227
- }
228
- }
229
- else {
230
- const index = ++stacksIndex
225
+ } else {
226
+ const index = ++stacksIndex;
231
227
  if (stacks.has(index)) {
232
- const stack = stacks.get(index)
233
- stack!.done = true
234
- stack!.resolve({ done: false, value: TSON.parse(event.data) })
235
- }
236
- else {
237
- const stack = withResolvers<IteratorResult<any>>()
238
- stack.resolve({ done: false, value: TSON.parse(event.data) })
239
- stacks.set(index, { ...stack, done: false })
228
+ const stack = stacks.get(index);
229
+ stack!.done = true;
230
+ stack!.resolve({ done: false, value: TSON.parse(event.data) });
231
+ } else {
232
+ const stack = withResolvers<IteratorResult<any>>();
233
+ stack.resolve({ done: false, value: TSON.parse(event.data) });
234
+ stacks.set(index, { ...stack, done: false });
240
235
  }
241
236
  }
242
- }
237
+ };
243
238
 
244
- let curRequestController: AbortController
239
+ let curRequestController: AbortController;
245
240
 
246
241
  async function create() {
247
- curRequestController = new $abort()
248
- curRequestController.signal.addEventListener('abort', () => {
249
- iterator.return()
250
- })
242
+ curRequestController = new $abort();
243
+ curRequestController.signal.addEventListener("abort", () => {
244
+ iterator.return();
245
+ });
251
246
  try {
252
- await eventManager.emit('milkio:executeBefore', { path: path as string, options: options as any })
247
+ await eventManager.emit("milkio:executeBefore", { path: path as string, options: options as any });
253
248
 
254
- const body = TSON.stringify(options!.params) ?? ''
255
- await eventManager.emit('milkio:fetchBefore', { path: path as string, options: options as any, body })
249
+ const body = TSON.stringify(options!.params) ?? "";
250
+ await eventManager.emit("milkio:fetchBefore", { path: path as string, options: options as any, body });
256
251
 
257
252
  const response = await $fetch(url, {
258
- method: 'POST',
253
+ method: "POST",
259
254
  headers: options!.headers,
260
255
  body,
261
256
  signal: curRequestController.signal,
262
- })
257
+ });
263
258
 
264
- const contentType = response.headers.get('Content-Type')
265
- if (!contentType?.startsWith('text/event-stream')) {
266
- throw new Error(`Expected content-type to be ${'text/event-stream'}, Actual: ${contentType}`)
259
+ const contentType = response.headers.get("Content-Type");
260
+ if (!contentType?.startsWith("text/event-stream")) {
261
+ throw new Error(`Expected content-type to be ${"text/event-stream"}, Actual: ${contentType}`);
267
262
  }
268
263
 
269
- await getBytes(response.body!, getLines(getMessages(onmessage)))
264
+ await getBytes(response.body!, getLines(getMessages(onmessage)));
270
265
 
271
- await iterator.return()
272
- }
273
- catch (err) {
274
- if (!curRequestController.signal.aborted) curRequestController.abort()
275
- const error = { REQUEST_FAIL: err }
276
- await eventManager.emit('milkio:executeError', { handleError, path: path as string, options: options as any, error })
277
- await iterator.throw(err)
278
- streamResultFetched.reject([error, null, { executeId: 'unknown' }])
266
+ await iterator.return();
267
+ } catch (err) {
268
+ if (!curRequestController.signal.aborted) curRequestController.abort();
269
+ const error = { REQUEST_FAIL: err };
270
+ await eventManager.emit("milkio:executeError", { handleError, path: path as string, options: options as any, error });
271
+ await iterator.throw(err);
272
+ streamResultFetched.reject([error, null, { executeId: "unknown" }]);
279
273
  }
280
274
  }
281
275
 
282
- void create()
276
+ void create();
283
277
 
284
278
  const iterator = {
285
279
  ...({
286
280
  next(): Promise<IteratorResult<unknown>> {
287
- const index = ++iteratorIndex
288
- if (stacks.has(index - 2)) stacks.delete(index - 2)
281
+ const index = ++iteratorIndex;
282
+ if (stacks.has(index - 2)) stacks.delete(index - 2);
289
283
  if (!stacks.has(index) && !curRequestController.signal.aborted) {
290
- const stack = withResolvers<IteratorResult<any>>()
291
- stacks.set(index, { ...stack, done: false })
292
- return stack.promise
284
+ const stack = withResolvers<IteratorResult<any>>();
285
+ stacks.set(index, { ...stack, done: false });
286
+ return stack.promise;
293
287
  }
294
288
  if (!stacks.has(index) && curRequestController.signal.aborted) {
295
- const stack = withResolvers<IteratorResult<any>>()
296
- stack.resolve({ done: true, value: undefined })
297
- return stack.promise
289
+ const stack = withResolvers<IteratorResult<any>>();
290
+ stack.resolve({ done: true, value: undefined });
291
+ return stack.promise;
298
292
  }
299
- return stacks.get(index)!.promise
293
+ return stacks.get(index)!.promise;
300
294
  },
301
295
  async return(): Promise<IteratorResult<void>> {
302
- if (!curRequestController.signal.aborted) curRequestController.abort()
303
- for (const [_, iterator] of stacks) iterator.resolve({ done: true, value: undefined })
304
- return { done: true, value: undefined }
296
+ if (!curRequestController.signal.aborted) curRequestController.abort();
297
+ for (const [_, iterator] of stacks) iterator.resolve({ done: true, value: undefined });
298
+ return { done: true, value: undefined };
305
299
  },
306
300
  async throw(err: any): Promise<IteratorResult<void>> {
307
301
  streamResult = {
308
302
  success: false,
309
- executeId: streamResult?.executeId ?? '',
303
+ executeId: streamResult?.executeId ?? "",
310
304
  fail: {
311
- code: 'NETWORK_ERROR',
312
- message: 'Network Error',
305
+ code: "NETWORK_ERROR",
306
+ message: "Network Error",
313
307
  fromClient: true,
314
308
  data: err,
315
309
  },
316
- }
310
+ };
317
311
  for (const [_index, stack] of stacks) {
318
- if (stack.done) continue
319
- stack.done = true
320
- stack.resolve({ done: true, value: undefined })
312
+ if (stack.done) continue;
313
+ stack.done = true;
314
+ stack.resolve({ done: true, value: undefined });
321
315
  }
322
- if (!curRequestController.signal.aborted) curRequestController.abort()
323
- for (const [_, iterator] of stacks) iterator.resolve({ done: true, value: undefined })
324
- return { done: true, value: undefined }
316
+ if (!curRequestController.signal.aborted) curRequestController.abort();
317
+ for (const [_, iterator] of stacks) iterator.resolve({ done: true, value: undefined });
318
+ return { done: true, value: undefined };
325
319
  },
326
320
  } satisfies AsyncIterator<unknown>),
327
321
  [Symbol.asyncIterator]() {
328
- return this
322
+ return this;
329
323
  },
330
- }
324
+ };
331
325
 
332
326
  try {
333
- await streamResultFetched.promise
334
- return [null, iterator, { executeId: streamResult.executeId }] as any
335
- }
336
- catch (error) {
337
- return error as any
327
+ await streamResultFetched.promise;
328
+ return [null, iterator, { executeId: streamResult.executeId }] as any;
329
+ } catch (error) {
330
+ return error as any;
338
331
  }
339
332
  }
340
333
  },
341
334
  cookbook: {
342
335
  subscribe: async (baseUrl: string) => {
343
336
  const headers = {
344
- 'Content-Type': 'application/json',
345
- 'Accept': 'text/event-stream',
346
- }
347
- const params = {}
337
+ "Content-Type": "application/json",
338
+ Accept: "text/event-stream",
339
+ };
340
+ const params = {};
348
341
 
349
- const body = TSON.stringify(params) ?? ''
342
+ const body = TSON.stringify(params) ?? "";
350
343
  const stacks: Map<
351
344
  number,
352
345
  {
353
- done: boolean
354
- promise: Promise<IteratorResult<any>>
355
- resolve: (value: IteratorResult<any>) => void
356
- reject: (reason: any) => void
346
+ done: boolean;
347
+ promise: Promise<IteratorResult<any>>;
348
+ resolve: (value: IteratorResult<any>) => void;
349
+ reject: (reason: any) => void;
357
350
  }
358
- > = new Map()
359
- let stacksIndex: number = 0
360
- let iteratorIndex: number = 0
351
+ > = new Map();
352
+ let stacksIndex = 0;
353
+ let iteratorIndex = 0;
361
354
 
362
355
  const onmessage = (event: EventSourceMessage) => {
363
- const index = ++stacksIndex
356
+ const index = ++stacksIndex;
364
357
  if (stacks.has(index)) {
365
- const stack = stacks.get(index)
366
- stack!.resolve({ done: false, value: TSON.parse(event.data) })
367
- }
368
- else {
369
- const stack = withResolvers<IteratorResult<any>>()
370
- stack.resolve({ done: false, value: TSON.parse(event.data) })
371
- stacks.set(index, { ...stack, done: false })
358
+ const stack = stacks.get(index);
359
+ stack!.resolve({ done: false, value: TSON.parse(event.data) });
360
+ } else {
361
+ const stack = withResolvers<IteratorResult<any>>();
362
+ stack.resolve({ done: false, value: TSON.parse(event.data) });
363
+ stacks.set(index, { ...stack, done: false });
372
364
  }
373
- }
365
+ };
374
366
 
375
- let curRequestController: AbortController
367
+ let curRequestController: AbortController;
376
368
 
377
369
  async function create() {
378
- curRequestController = new $abort()
379
- curRequestController.signal.addEventListener('abort', () => {
380
- iterator.return()
381
- })
370
+ curRequestController = new $abort();
371
+ curRequestController.signal.addEventListener("abort", () => {
372
+ iterator.return();
373
+ });
382
374
  try {
383
375
  const response = await $fetch(`${baseUrl}/$subscribe`, {
384
- method: 'POST',
376
+ method: "POST",
385
377
  headers,
386
378
  body,
387
379
  signal: curRequestController.signal,
388
- })
380
+ });
389
381
 
390
- const contentType = response.headers.get('Content-Type')
391
- if (!contentType?.startsWith('text/event-stream')) {
392
- throw new Error(`Expected content-type to be ${'text/event-stream'}, Actual: ${contentType}`)
382
+ const contentType = response.headers.get("Content-Type");
383
+ if (!contentType?.startsWith("text/event-stream")) {
384
+ throw new Error(`Expected content-type to be ${"text/event-stream"}, Actual: ${contentType}`);
393
385
  }
394
386
 
395
- await getBytes(response.body!, getLines(getMessages(onmessage)))
387
+ await getBytes(response.body!, getLines(getMessages(onmessage)));
396
388
 
397
- await iterator.return()
398
- }
399
- catch (err) {
400
- if (!curRequestController.signal.aborted) curRequestController.abort()
401
- await iterator.throw(err)
389
+ await iterator.return();
390
+ } catch (err) {
391
+ if (!curRequestController.signal.aborted) curRequestController.abort();
392
+ await iterator.throw(err);
402
393
  }
403
394
  }
404
395
 
405
- void create()
396
+ void create();
406
397
 
407
398
  const iterator = {
408
399
  ...({
409
400
  next(): Promise<IteratorResult<unknown>> {
410
- const index = ++iteratorIndex
411
- if (stacks.has(index - 2)) stacks.delete(index - 2)
401
+ const index = ++iteratorIndex;
402
+ if (stacks.has(index - 2)) stacks.delete(index - 2);
412
403
  if (!stacks.has(index) && !curRequestController.signal.aborted) {
413
- const stack = withResolvers<IteratorResult<any>>()
414
- stacks.set(index, { ...stack, done: false })
415
- return stack.promise
404
+ const stack = withResolvers<IteratorResult<any>>();
405
+ stacks.set(index, { ...stack, done: false });
406
+ return stack.promise;
416
407
  }
417
408
  if (!stacks.has(index) && curRequestController.signal.aborted) {
418
- const stack = withResolvers<IteratorResult<any>>()
419
- stack.resolve({ done: true, value: undefined })
420
- return stack.promise
409
+ const stack = withResolvers<IteratorResult<any>>();
410
+ stack.resolve({ done: true, value: undefined });
411
+ return stack.promise;
421
412
  }
422
- return stacks.get(index)!.promise
413
+ return stacks.get(index)!.promise;
423
414
  },
424
415
  async return(): Promise<IteratorResult<void>> {
425
- if (!curRequestController.signal.aborted) curRequestController.abort()
426
- for (const [_, iterator] of stacks) iterator.resolve({ done: true, value: undefined })
427
- return { done: true, value: undefined }
416
+ if (!curRequestController.signal.aborted) curRequestController.abort();
417
+ for (const [_, iterator] of stacks) iterator.resolve({ done: true, value: undefined });
418
+ return { done: true, value: undefined };
428
419
  },
429
420
  async throw(err: any): Promise<IteratorResult<void>> {
430
- if (!curRequestController.signal.aborted) curRequestController.abort()
431
- for (const [_, iterator] of stacks) iterator.resolve({ done: true, value: undefined })
432
- return { done: true, value: undefined }
421
+ if (!curRequestController.signal.aborted) curRequestController.abort();
422
+ for (const [_, iterator] of stacks) iterator.resolve({ done: true, value: undefined });
423
+ return { done: true, value: undefined };
433
424
  },
434
425
  } satisfies AsyncIterator<unknown>),
435
426
  [Symbol.asyncIterator]() {
436
- return this
427
+ return this;
437
428
  },
438
- }
429
+ };
439
430
 
440
431
  try {
441
- return iterator
442
- }
443
- catch (error) {
444
- return error as any
432
+ return iterator;
433
+ } catch (error) {
434
+ return error as any;
445
435
  }
446
436
  },
447
437
  },
448
438
  async ping(options?: { timeout?: number }): Promise<Ping> {
439
+ // biome-ignore lint/suspicious/noAsyncPromiseExecutor: <explanation>
449
440
  return await new Promise<Ping>(async (resolve) => {
450
- const url = `${await baseUrl}/generate_204`
451
- const timeout = stargateOptions?.timeout ?? options?.timeout ?? 6000
452
- const startsTime = Date.now()
441
+ const url = `${await baseUrl}/generate_204`;
442
+ const timeout = stargateOptions?.timeout ?? options?.timeout ?? 6000;
443
+ const startsTime = Date.now();
453
444
  const timer = setTimeout(() => {
454
- const endsTime = Date.now()
455
- resolve([{ connect: false, delay: endsTime - startsTime, error: { REQUEST_TIMEOUT: { timeout, message: `Execute timeout after ${timeout}ms.` } } }, null])
456
- }, timeout)
445
+ const endsTime = Date.now();
446
+ resolve([{ connect: false, delay: endsTime - startsTime, error: { REQUEST_TIMEOUT: { timeout, message: `Execute timeout after ${timeout}ms.` } } }, null]);
447
+ }, timeout);
457
448
 
458
449
  try {
459
- const response = await await $fetch(url, { method: 'HEAD' })
460
- const endsTime = Date.now()
461
- clearTimeout(timer)
450
+ const response = await await $fetch(url, { method: "HEAD" });
451
+ const endsTime = Date.now();
452
+ clearTimeout(timer);
462
453
  if (response.status !== 204) {
463
- resolve([{ connect: false, delay: endsTime - startsTime, error: { REQUEST_FAIL: { response, status: response.status, message: `Status code not 204` } } }, null])
454
+ resolve([{ connect: false, delay: endsTime - startsTime, error: { REQUEST_FAIL: { response, status: response.status, message: "Status code not 204" } } }, null]);
464
455
  }
465
456
 
466
- resolve([null, { connect: true, delay: endsTime - startsTime, serverTimestamp: Number(response.headers.get('Content-Type')!.substring(17)) }])
457
+ resolve([null, { connect: true, delay: endsTime - startsTime, serverTimestamp: Number(response.headers.get("Content-Type")!.substring(17)) }]);
458
+ } catch (error: any) {
459
+ const endsTime = Date.now();
460
+ return [{ connect: false, delay: endsTime - startsTime, error }, null];
467
461
  }
468
- catch (error: any) {
469
- const endsTime = Date.now()
470
- return [{ connect: false, delay: endsTime - startsTime, error }, null]
462
+ });
463
+ },
464
+ async requestRaw<
465
+ T,
466
+ Options extends {
467
+ method: string;
468
+ type?: "action" | "stream";
469
+ params?: Record<any, any> | string;
470
+ headers?: Record<string, string>;
471
+ timeout?: number;
472
+ },
473
+ >(
474
+ path: string,
475
+ options: Options,
476
+ ): Promise<
477
+ Options["type"] extends "stream"
478
+ ? // stream
479
+ [Partial<Generated["rejectCode"]>, null, ExecuteResultsOption] | [null, AsyncGenerator<[Partial<Generated["rejectCode"]>, null] | [null, T], ExecuteResultsOption>]
480
+ : // action
481
+ [Partial<Generated["rejectCode"]>, null, ExecuteResultsOption] | [null, T, ExecuteResultsOption]
482
+ > {
483
+ if (options.headers === undefined) options.headers = {};
484
+
485
+ const url = path;
486
+
487
+ if (options.type !== "stream") {
488
+ // action
489
+ if (options.headers.Accept === undefined) options.headers.Accept = "application/json";
490
+ if (options.headers["Content-Type"] === undefined) options.headers["Content-Type"] = "application/json";
491
+ let result: { value: Record<any, any> };
492
+
493
+ try {
494
+ const body = TSON.stringify(options.params) ?? "";
495
+ // biome-ignore lint/suspicious/noAsyncPromiseExecutor: <explanation>
496
+ const response = await new Promise<string>(async (resolve, reject) => {
497
+ const timeout = options?.timeout ?? options?.timeout ?? 6000;
498
+ const timer = setTimeout(() => {
499
+ reject([{ REQUEST_TIMEOUT: { timeout, message: `Execute timeout after ${timeout}ms.` } }, null]);
500
+ }, timeout);
501
+
502
+ try {
503
+ const value = await (await $fetch(url, { method: "POST", body, headers: options.headers })).text();
504
+ clearTimeout(timer);
505
+ resolve(value);
506
+ } catch (error) {
507
+ reject(error);
508
+ }
509
+ });
510
+ result = { value: TSON.parse(response) };
511
+ } catch (error: any) {
512
+ if (error?.[0]?.REQUEST_TIMEOUT) {
513
+ return error;
514
+ }
515
+ const errorPined = { REQUEST_FAIL: error };
516
+ return [errorPined, null, { executeId: "unknown" }];
517
+ }
518
+ if (result.value.success !== true) {
519
+ const error: any = {};
520
+ error[result.value.code] = result.value.reject ?? null;
521
+ return [error, null, { executeId: "unknown" }];
471
522
  }
472
- })
523
+
524
+ return [null, result.value.data, { executeId: result.value.executeId }] as any;
525
+ } else {
526
+ // stream
527
+ if (options.headers.Accept === undefined) options.headers.Accept = "text/event-stream";
528
+ if (options.headers["Content-Type"] === undefined) options.headers["Content-Type"] = "application/json";
529
+
530
+ const stacks: Map<
531
+ number,
532
+ {
533
+ done: boolean;
534
+ promise: Promise<IteratorResult<any>>;
535
+ resolve: (value: IteratorResult<any>) => void;
536
+ reject: (reason: any) => void;
537
+ }
538
+ > = new Map();
539
+ let stacksIndex = 0;
540
+ let iteratorIndex = 0;
541
+ let streamResult: any;
542
+ const streamResultFetched = withResolvers<undefined>();
543
+
544
+ const timeout = stargateOptions?.timeout ?? options?.timeout ?? 6000;
545
+ const timer = setTimeout(() => {
546
+ streamResultFetched.reject([{ REQUEST_TIMEOUT: { timeout, message: `Execute timeout after ${timeout}ms.` } }, null, { executeId: "unknown" }]);
547
+ }, timeout);
548
+
549
+ const onmessage = (event: EventSourceMessage) => {
550
+ if (event.data.startsWith("@")) {
551
+ try {
552
+ streamResult = TSON.parse(event.data.slice(1));
553
+ streamResultFetched.resolve(undefined);
554
+ clearTimeout(timer);
555
+ } catch (error) {
556
+ streamResultFetched.reject([{ REQUEST_FAIL: error }, null, { executeId: "unknown" }]);
557
+ clearTimeout(timer);
558
+ }
559
+ } else {
560
+ const index = ++stacksIndex;
561
+ if (stacks.has(index)) {
562
+ const stack = stacks.get(index);
563
+ stack!.done = true;
564
+ stack!.resolve({ done: false, value: TSON.parse(event.data) });
565
+ } else {
566
+ const stack = withResolvers<IteratorResult<any>>();
567
+ stack.resolve({ done: false, value: TSON.parse(event.data) });
568
+ stacks.set(index, { ...stack, done: false });
569
+ }
570
+ }
571
+ };
572
+
573
+ let curRequestController: AbortController;
574
+
575
+ async function create() {
576
+ curRequestController = new $abort();
577
+ curRequestController.signal.addEventListener("abort", () => {
578
+ iterator.return();
579
+ });
580
+ try {
581
+ const body = TSON.stringify(options!.params) ?? "";
582
+ const response = await $fetch(url, {
583
+ method: "POST",
584
+ headers: options!.headers,
585
+ body,
586
+ signal: curRequestController.signal,
587
+ });
588
+
589
+ const contentType = response.headers.get("Content-Type");
590
+ if (!contentType?.startsWith("text/event-stream")) {
591
+ throw new Error(`Expected content-type to be ${"text/event-stream"}, Actual: ${contentType}`);
592
+ }
593
+
594
+ await getBytes(response.body!, getLines(getMessages(onmessage)));
595
+
596
+ await iterator.return();
597
+ } catch (err) {
598
+ if (!curRequestController.signal.aborted) curRequestController.abort();
599
+ const error = { REQUEST_FAIL: err };
600
+ await iterator.throw(err);
601
+ streamResultFetched.reject([error, null, { executeId: "unknown" }]);
602
+ }
603
+ }
604
+
605
+ void create();
606
+
607
+ const iterator = {
608
+ ...({
609
+ next(): Promise<IteratorResult<unknown>> {
610
+ const index = ++iteratorIndex;
611
+ if (stacks.has(index - 2)) stacks.delete(index - 2);
612
+ if (!stacks.has(index) && !curRequestController.signal.aborted) {
613
+ const stack = withResolvers<IteratorResult<any>>();
614
+ stacks.set(index, { ...stack, done: false });
615
+ return stack.promise;
616
+ }
617
+ if (!stacks.has(index) && curRequestController.signal.aborted) {
618
+ const stack = withResolvers<IteratorResult<any>>();
619
+ stack.resolve({ done: true, value: undefined });
620
+ return stack.promise;
621
+ }
622
+ return stacks.get(index)!.promise;
623
+ },
624
+ async return(): Promise<IteratorResult<void>> {
625
+ if (!curRequestController.signal.aborted) curRequestController.abort();
626
+ for (const [_, iterator] of stacks) iterator.resolve({ done: true, value: undefined });
627
+ return { done: true, value: undefined };
628
+ },
629
+ async throw(err: any): Promise<IteratorResult<void>> {
630
+ streamResult = {
631
+ success: false,
632
+ executeId: streamResult?.executeId ?? "",
633
+ fail: {
634
+ code: "NETWORK_ERROR",
635
+ message: "Network Error",
636
+ fromClient: true,
637
+ data: err,
638
+ },
639
+ };
640
+ for (const [_index, stack] of stacks) {
641
+ if (stack.done) continue;
642
+ stack.done = true;
643
+ stack.resolve({ done: true, value: undefined });
644
+ }
645
+ if (!curRequestController.signal.aborted) curRequestController.abort();
646
+ for (const [_, iterator] of stacks) iterator.resolve({ done: true, value: undefined });
647
+ return { done: true, value: undefined };
648
+ },
649
+ } satisfies AsyncIterator<unknown>),
650
+ [Symbol.asyncIterator]() {
651
+ return this;
652
+ },
653
+ };
654
+
655
+ try {
656
+ await streamResultFetched.promise;
657
+ return [null, iterator, { executeId: streamResult.executeId }] as any;
658
+ } catch (error) {
659
+ return error as any;
660
+ }
661
+ }
473
662
  },
474
- }
663
+ };
475
664
 
476
- return stargate
665
+ return stargate;
477
666
  }
478
667
 
479
668
  export interface ExecuteStreamOptions {
480
- headers?: Record<string, string>
481
- timeout?: number
669
+ headers?: Record<string, string>;
670
+ timeout?: number;
482
671
  }
483
672
 
484
673
  export interface ApiSchemaExtend {
485
674
  apiValidator: {
486
- generatedAt: number
487
- validate: Record<any, any>
488
- }
489
- apiMethodsSchema: Record<any, any>
490
- apiMethodsTypeSchema: Record<any, any>
491
- apiTestsSchema: Record<any, any>
675
+ generatedAt: number;
676
+ validate: Record<any, any>;
677
+ };
678
+ apiMethodsSchema: Record<any, any>;
679
+ apiMethodsTypeSchema: Record<any, any>;
680
+ apiTestsSchema: Record<any, any>;
492
681
  }
493
682
 
494
- export type FailCodeExtend = Record<any, (...args: Array<any>) => any>
683
+ export type FailCodeExtend = Record<any, (...args: Array<any>) => any>;
495
684
 
496
- export type BootstrapMiddleware = (data: { storage: ClientStorage }) => Promise<void> | void
497
- export type BeforeExecuteMiddleware = (data: { path: string, params: any, headers: Record<string, string>, storage: ClientStorage }) => Promise<void> | void
498
- export type AfterExecuteMiddleware = (data: { path: string, result: { value: any }, storage: ClientStorage }) => Promise<void> | void
685
+ export type BootstrapMiddleware = (data: { storage: ClientStorage }) => Promise<void> | void;
686
+ export type BeforeExecuteMiddleware = (data: { path: string; params: any; headers: Record<string, string>; storage: ClientStorage }) => Promise<void> | void;
687
+ export type AfterExecuteMiddleware = (data: { path: string; result: { value: any }; storage: ClientStorage }) => Promise<void> | void;
499
688
 
500
689
  export interface MiddlewareOptions {
501
- bootstrap?: BootstrapMiddleware
502
- beforeExecute?: BeforeExecuteMiddleware
503
- afterExecute?: AfterExecuteMiddleware
690
+ bootstrap?: BootstrapMiddleware;
691
+ beforeExecute?: BeforeExecuteMiddleware;
692
+ afterExecute?: AfterExecuteMiddleware;
504
693
  }
505
694
 
506
695
  export interface ClientStorage {
507
- getItem: (key: string) => Promise<string | null>
508
- setItem: (key: string, value: string) => Promise<void>
509
- removeItem: (key: string) => Promise<void>
696
+ getItem: (key: string) => Promise<string | null>;
697
+ setItem: (key: string, value: string) => Promise<void>;
698
+ removeItem: (key: string) => Promise<void>;
510
699
  }
511
700
 
512
701
  export interface ExecuteResultSuccess<Result> {
513
- executeId: string
514
- success: true
515
- data: Result
702
+ executeId: string;
703
+ success: true;
704
+ data: Result;
516
705
  }
517
706
 
518
- export type GeneratorGeneric<T> = T extends AsyncGenerator<infer I> ? I : never
707
+ export type GeneratorGeneric<T> = T extends AsyncGenerator<infer I> ? I : never;
519
708
 
520
- export type FlattenKeys<T extends any, Prefix extends string = ''> = {
709
+ export type FlattenKeys<T, Prefix extends string = ""> = {
521
710
  [K in keyof T]: T[K] extends object ? FlattenKeys<T[K], `${Prefix}${Exclude<K, symbol>}.`> : `$input.${Prefix}${Exclude<K, symbol>}`;
522
- }[keyof T]
711
+ }[keyof T];
523
712
 
524
713
  // *** This part of the code is based on `@microsoft/fetch-event-source` rewrite, thanks to the work of Microsoft *** //
525
714
  // *** https://github.com/Azure/fetch-event-source/blob/main/src/parse.ts *** //
@@ -529,7 +718,7 @@ export type FlattenKeys<T extends any, Prefix extends string = ''> = {
529
718
  * https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format
530
719
  */
531
720
  export interface EventSourceMessage {
532
- data: string
721
+ data: string;
533
722
  }
534
723
 
535
724
  /**
@@ -539,20 +728,14 @@ export interface EventSourceMessage {
539
728
  * @returns {Promise<void>} A promise that will be resolved when the stream closes.
540
729
  */
541
730
  export async function getBytes(stream: ReadableStream<Uint8Array>, onChunk: (arr: Uint8Array) => void) {
542
- const reader = stream.getReader()
543
- let result: ReadableStreamReadResult<Uint8Array>
731
+ const reader = stream.getReader();
732
+ let result: ReadableStreamReadResult<Uint8Array>;
733
+ // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>
544
734
  while (!(result = await reader.read()).done) {
545
- onChunk(result.value)
735
+ onChunk(result.value);
546
736
  }
547
737
  }
548
738
 
549
- const enum ControlChars {
550
- NewLine = 10,
551
- CarriageReturn = 13,
552
- Space = 32,
553
- Colon = 58,
554
- }
555
-
556
739
  /**
557
740
  * Parses arbitary byte chunks into EventSource line buffers.
558
741
  * Each line should be of the format "field: value" and ends with \r, \n, or \r\n.
@@ -560,75 +743,73 @@ const enum ControlChars {
560
743
  * @returns A function that should be called for each incoming byte chunk.
561
744
  */
562
745
  export function getLines(onLine: (line: Uint8Array, fieldLength: number) => void) {
563
- let buffer: Uint8Array | undefined
564
- let position: number // current read position
565
- let fieldLength: number // length of the `field` portion of the line
566
- let discardTrailingNewline = false
746
+ let buffer: Uint8Array | undefined;
747
+ let position: number; // current read position
748
+ let fieldLength: number; // length of the `field` portion of the line
749
+ let discardTrailingNewline = false;
567
750
 
568
751
  // return a function that can process each incoming byte chunk:
569
752
  return function onChunk(arr: Uint8Array) {
570
753
  if (buffer === undefined) {
571
- buffer = arr
572
- position = 0
573
- fieldLength = -1
574
- }
575
- else {
754
+ buffer = arr;
755
+ position = 0;
756
+ fieldLength = -1;
757
+ } else {
576
758
  // we're still parsing the old line. Append the new bytes into buffer:
577
- buffer = concat(buffer, arr)
759
+ buffer = concat(buffer, arr);
578
760
  }
579
761
 
580
- const bufLength = buffer.length
581
- let lineStart = 0 // index where the current line starts
762
+ const bufLength = buffer.length;
763
+ let lineStart = 0; // index where the current line starts
582
764
  while (position < bufLength) {
583
765
  if (discardTrailingNewline) {
584
- if (buffer[position] === ControlChars.NewLine) {
585
- lineStart = ++position // skip to next char
766
+ if (buffer[position] === 10) {
767
+ lineStart = ++position; // skip to next char
586
768
  }
587
769
 
588
- discardTrailingNewline = false
770
+ discardTrailingNewline = false;
589
771
  }
590
772
 
591
773
  // start looking forward till the end of line:
592
- let lineEnd = -1 // index of the \r or \n char
774
+ let lineEnd = -1; // index of the \r or \n char
593
775
  for (; position < bufLength && lineEnd === -1; ++position) {
594
776
  switch (buffer[position]) {
595
- case ControlChars.Colon:
777
+ case 58:
596
778
  if (fieldLength === -1) {
597
779
  // first colon in line
598
- fieldLength = position - lineStart
780
+ fieldLength = position - lineStart;
599
781
  }
600
- break
601
- // @ts-ignore:7029 \r case below should fallthrough to \n:
602
- case ControlChars.CarriageReturn:
603
- discardTrailingNewline = true
604
- case ControlChars.NewLine:
605
- lineEnd = position
606
- break
782
+ break;
783
+ // biome-ignore lint/suspicious/noFallthroughSwitchClause: <explanation>
784
+ case 13:
785
+ discardTrailingNewline = true;
786
+ case 10:
787
+ lineEnd = position;
788
+ break;
607
789
  }
608
790
  }
609
791
 
610
792
  if (lineEnd === -1) {
611
793
  // We reached the end of the buffer but the line hasn't ended.
612
794
  // Wait for the next arr and then continue parsing:
613
- break
795
+ break;
614
796
  }
615
797
 
616
798
  // we've reached the line end, send it out:
617
- onLine(buffer.subarray(lineStart, lineEnd), fieldLength)
618
- lineStart = position // we're now on the next line
619
- fieldLength = -1
799
+ onLine(buffer.subarray(lineStart, lineEnd), fieldLength);
800
+ lineStart = position; // we're now on the next line
801
+ fieldLength = -1;
620
802
  }
621
803
 
622
804
  if (lineStart === bufLength) {
623
- buffer = undefined // we've finished reading it
624
- }
625
- else if (lineStart !== 0) {
805
+ buffer = undefined; // we've finished reading it
806
+ } else if (lineStart !== 0) {
626
807
  // Create a new view into buffer beginning at lineStart so we don't
627
808
  // need to copy over the previous lines when we get the new arr:
628
- buffer = buffer.subarray(lineStart)
629
- position -= lineStart
809
+ buffer = buffer.subarray(lineStart);
810
+ position -= lineStart;
630
811
  }
631
- }
812
+ };
632
813
  }
633
814
 
634
815
  /**
@@ -639,54 +820,53 @@ export function getLines(onLine: (line: Uint8Array, fieldLength: number) => void
639
820
  * @returns A function that should be called for each incoming line buffer.
640
821
  */
641
822
  export function getMessages(onMessage?: (msg: EventSourceMessage) => void) {
642
- let message = newMessage()
643
- const decoder = new TextDecoder()
823
+ let message = newMessage();
824
+ const decoder = new TextDecoder();
644
825
 
645
826
  // return a function that can process each incoming line buffer:
646
827
  return function onLine(line: Uint8Array, fieldLength: number) {
647
828
  if (line.length === 0) {
648
829
  // empty line denotes end of message. Trigger the callback and start a new message:
649
- onMessage?.(message)
650
- message = newMessage()
651
- }
652
- else if (fieldLength > 0) {
830
+ onMessage?.(message);
831
+ message = newMessage();
832
+ } else if (fieldLength > 0) {
653
833
  // exclude comments and lines with no values
654
834
  // line is of format "<field>:<value>" or "<field>: <value>"
655
835
  // https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
656
- const field = decoder.decode(line.subarray(0, fieldLength))
657
- const valueOffset = fieldLength + (line[fieldLength + 1] === ControlChars.Space ? 2 : 1)
658
- const value = decoder.decode(line.subarray(valueOffset))
836
+ const field = decoder.decode(line.subarray(0, fieldLength));
837
+ const valueOffset = fieldLength + (line[fieldLength + 1] === 32 ? 2 : 1);
838
+ const value = decoder.decode(line.subarray(valueOffset));
659
839
 
660
840
  switch (field) {
661
- case 'data':
841
+ case "data":
662
842
  // if this message already has data, append the new value to the old.
663
843
  // otherwise, just set to the new value:
664
- message.data = message.data ? `${message.data}\n${value}` : value // otherwise,
665
- break
844
+ message.data = message.data ? `${message.data}\n${value}` : value; // otherwise,
845
+ break;
666
846
  }
667
847
  }
668
- }
848
+ };
669
849
  }
670
850
 
671
851
  function concat(a: Uint8Array, b: Uint8Array) {
672
- const res = new Uint8Array(a.length + b.length)
673
- res.set(a)
674
- res.set(b, a.length)
675
- return res
852
+ const res = new Uint8Array(a.length + b.length);
853
+ res.set(a);
854
+ res.set(b, a.length);
855
+ return res;
676
856
  }
677
857
 
678
858
  function newMessage(): EventSourceMessage {
679
859
  return {
680
- data: '',
681
- }
860
+ data: "",
861
+ };
682
862
  }
683
863
 
684
864
  export function withResolvers<T = any>(): PromiseWithResolvers<T> {
685
- let resolve: PromiseWithResolvers<T>['resolve']
686
- let reject: PromiseWithResolvers<T>['reject']
865
+ let resolve: PromiseWithResolvers<T>["resolve"];
866
+ let reject: PromiseWithResolvers<T>["reject"];
687
867
  const promise = new Promise<T>((res, rej) => {
688
- resolve = res
689
- reject = rej
690
- })
691
- return { promise, resolve: resolve!, reject: reject! }
868
+ resolve = res;
869
+ reject = rej;
870
+ });
871
+ return { promise, resolve: resolve!, reject: reject! };
692
872
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@milkio/stargate",
3
3
  "type": "module",
4
- "version": "1.0.0-alpha.92",
4
+ "version": "1.0.0-alpha.94",
5
5
  "module": "index.ts",
6
6
  "dependencies": {
7
7
  "@southern-aurora/tson": "^2.0.2"