@milkio/stargate 1.0.0-alpha.0 → 1.0.0-alpha.10

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.
File without changes
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # milkio-world
1
+ # milkio-starter
2
2
 
3
3
  To install dependencies:
4
4
 
package/index.ts CHANGED
@@ -3,15 +3,8 @@ import { TSON } from "@southern-aurora/tson";
3
3
  export type MilkioStargateOptions = {
4
4
  baseUrl: string | (() => string) | (() => Promise<string>);
5
5
  timeout?: number;
6
- // middlewares?: () => Array<MiddlewareOptions & { isMiddleware: true }>;
7
6
  fetch?: typeof fetch;
8
7
  abort?: typeof AbortController;
9
- // storage?: {
10
- // getItem: (key: string) => string | null | Promise<string | null>;
11
- // setItem: (key: string, value: string) => void | Promise<void>;
12
- // removeItem: (key: string) => void | Promise<void>;
13
- // };
14
- // memoryStorage?: boolean;
15
8
  };
16
9
 
17
10
  export type Mixin<T, U> = U & Omit<T, keyof U>;
@@ -47,50 +40,76 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
47
40
  const $fetch = stargateOptions.fetch ?? fetch;
48
41
  const $abort = stargateOptions.abort ?? AbortController;
49
42
 
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
+ };
53
+
54
+ const handleError: any = async (error: any, key: string, handler: (error: any) => boolean | Promise<boolean>) => {
55
+ if (key in error) {
56
+ const handled = await handler(error[key]);
57
+ if (handled) delete error[key];
58
+ }
59
+ };
60
+
61
+ const __initEventManager = () => {
62
+ const handlers = new Map<(event: any) => void, string>();
63
+ const indexed = new Map<string, Set<(event: any) => void>>();
64
+
65
+ const eventManager = {
66
+ on: <Key extends keyof StargateEvents, Handler extends (event: StargateEvents[Key]) => void>(key: Key, handler: Handler) => {
67
+ handlers.set(handler, key as string);
68
+ if (indexed.has(key as string) === false) {
69
+ indexed.set(key as string, new Set());
70
+ }
71
+ const set = indexed.get(key as string)!;
72
+ set.add(handler);
73
+ handlers.set(handler, key as string);
74
+
75
+ return () => {
76
+ handlers.delete(handler);
77
+ set.delete(handler);
78
+ };
79
+ },
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);
85
+ },
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);
88
+ if (h) {
89
+ for (const handler of h) {
90
+ await handler(value);
91
+ }
92
+ }
93
+ },
94
+ };
95
+
96
+ return eventManager;
97
+ };
98
+
99
+ const eventManager = __initEventManager();
100
+
50
101
  const bootstrap = async () => {
51
102
  let baseUrl = stargateOptions.baseUrl;
52
103
  if (typeof baseUrl === "function") baseUrl = await baseUrl();
53
104
  if (baseUrl.endsWith("/")) baseUrl = baseUrl.slice(0, -1);
54
105
 
55
- // if (options.middlewares) {
56
- // const middlewares = [...builtinMiddlewares, ...options.middlewares()];
57
-
58
- // const push = (index: number, middlewares: Array<any>, middleware: any) => {
59
- // const id = ++guid;
60
- // middlewares.push({ id, index, middleware });
61
- // return () =>
62
- // middlewares.splice(
63
- // middlewares.findIndex((v) => v.id === id),
64
- // 1,
65
- // );
66
- // };
67
-
68
- // const _middlewareHandler = (index: number, options: MiddlewareOptions) => {
69
- // if (options.bootstrap) push(index, _bootstrapMiddlewares, options.bootstrap);
70
- // if (options.beforeExecute) push(index, _beforeExecuteMiddlewares, options.beforeExecute);
71
- // if (options.afterExecute) push(index, _afterExecuteMiddlewares, options.afterExecute);
72
- // };
73
-
74
- // for (let index = 0; index < middlewares.length; index++) {
75
- // const middlewareOptions = middlewares[index];
76
- // _middlewareHandler(index, middlewareOptions);
77
- // }
78
-
79
- // _bootstrapMiddlewares.sort((a, b) => a.index - b.index);
80
- // _beforeExecuteMiddlewares.sort((a, b) => a.index - b.index);
81
- // _afterExecuteMiddlewares.sort((a, b) => b.index - a.index);
82
-
83
- // for (const m of _bootstrapMiddlewares) {
84
- // await m.middleware({ storage: options.storage as ClientStorage });
85
- // }
86
- // }
87
-
88
106
  return baseUrl;
89
107
  };
90
108
 
91
109
  const baseUrl: Promise<string> = bootstrap();
92
110
 
93
111
  const stargate = {
112
+ ...eventManager,
94
113
  $types: {
95
114
  generated: void 0 as unknown as Generated,
96
115
  },
@@ -125,15 +144,14 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
125
144
  // action
126
145
  if (options.headers["Accept"] === undefined) options.headers["Accept"] = "application/json";
127
146
  if (options.headers["Content-Type"] === undefined) options.headers["Content-Type"] = "application/json";
147
+ let result: { value: Record<any, any> };
128
148
 
129
- // for (const m of _beforeExecuteMiddlewares) {
130
- // await m.middleware({ path: path as string, params: options.params, headers: options.headers, storage: options.storage as ClientStorage });
131
- // }
149
+ try {
150
+ await eventManager.emit("milkio:executeBefore", { path: path as string, options: options as any });
132
151
 
133
- const body = TSON.stringify(options.params) ?? "";
152
+ const body = TSON.stringify(options.params) ?? "";
153
+ await eventManager.emit("milkio:fetchBefore", { path: path as string, options: options as any, body: body });
134
154
 
135
- let result: { value: Record<any, any> };
136
- try {
137
155
  const response = await new Promise<string>(async (resolve, reject) => {
138
156
  const timeout = options?.timeout ?? options?.timeout ?? 6000;
139
157
  const timer = setTimeout(() => {
@@ -150,29 +168,31 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
150
168
  });
151
169
  result = { value: TSON.parse(response) };
152
170
  } catch (error: any) {
153
- if (error?.[0]?.REQUEST_TIMEOUT) return error;
154
- return [{ REQUEST_FAIL: error }, null, { executeId: "unknown" }];
171
+ if (error?.[0]?.REQUEST_TIMEOUT) {
172
+ await eventManager.emit("milkio:executeError", { handleError, path: path as string, options: options as any, error: error });
173
+ return error;
174
+ }
175
+ let errorPined = { REQUEST_FAIL: error };
176
+ await eventManager.emit("milkio:executeError", { handleError, path: path as string, options: options as any, error: errorPined });
177
+ return [errorPined, null, { executeId: "unknown" }];
155
178
  }
156
179
  if (result.value.success !== true) {
157
180
  const error: any = {};
158
- error[result.value.code] = result.value.reject;
181
+ error[result.value.code] = result.value.reject ?? null;
182
+ await eventManager.emit("milkio:executeError", { handleError, path: path as string, options: options as any, error: error });
159
183
  return [error, null, { executeId: "unknown" }];
160
184
  }
161
185
 
162
- // for (const m of _afterExecuteMiddlewares) {
163
- // await m.middleware({ path: path as string, storage: options.storage as ClientStorage, result });
164
- // }
165
-
166
186
  return [null, result.value.data, { executeId: result.value.executeId }] as any;
167
187
  } else {
168
188
  // stream
169
189
  if (options.headers["Accept"] === undefined) options.headers["Accept"] = "text/event-stream";
170
190
  if (options.headers["Content-Type"] === undefined) options.headers["Content-Type"] = "application/json";
171
191
 
172
- const body = TSON.stringify(options.params) ?? "";
173
192
  const stacks: Map<
174
193
  number,
175
194
  {
195
+ done: boolean;
176
196
  promise: Promise<IteratorResult<any>>;
177
197
  resolve: (value: IteratorResult<any>) => void;
178
198
  reject: (reason: any) => void;
@@ -201,11 +221,14 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
201
221
  return;
202
222
  } else {
203
223
  const index = ++stacksIndex;
204
- if (stacks.has(index)) stacks.get(index)!.resolve({ done: false, value: TSON.parse(event.data) });
205
- else {
224
+ if (stacks.has(index)) {
225
+ const stack = stacks.get(index);
226
+ stack!.done = true;
227
+ stack!.resolve({ done: false, value: TSON.parse(event.data) });
228
+ } else {
206
229
  const stack = withResolvers<IteratorResult<any>>();
207
230
  stack.resolve({ done: false, value: TSON.parse(event.data) });
208
- stacks.set(index, stack);
231
+ stacks.set(index, { ...stack, done: false });
209
232
  }
210
233
  }
211
234
  };
@@ -214,11 +237,14 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
214
237
 
215
238
  async function create() {
216
239
  curRequestController = new $abort();
217
- curRequestController.signal.addEventListener("abort", () => iterator.return());
240
+ curRequestController.signal.addEventListener("abort", () => {
241
+ iterator.return();
242
+ });
218
243
  try {
219
- // for (const m of _beforeExecuteMiddlewares) {
220
- // await m.middleware({ path: path as string, params: eventOptions.params, headers: eventOptions.headers!, storage: options.storage as ClientStorage });
221
- // }
244
+ await eventManager.emit("milkio:executeBefore", { path: path as string, options: options as any });
245
+
246
+ const body = TSON.stringify(options!.params) ?? "";
247
+ await eventManager.emit("milkio:fetchBefore", { path: path as string, options: options as any, body: body });
222
248
 
223
249
  const response = await $fetch(url, {
224
250
  method: "POST",
@@ -234,15 +260,13 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
234
260
 
235
261
  await getBytes(response.body!, getLines(getMessages(onmessage)));
236
262
 
237
- // for (const m of _afterExecuteMiddlewares) {
238
- // await m.middleware({ path: path as string, storage: options.storage as ClientStorage, result: { value: undefined } });
239
- // }
240
-
241
263
  await iterator.return();
242
264
  } catch (err) {
243
265
  if (!curRequestController.signal.aborted) curRequestController.abort();
266
+ const error = { REQUEST_FAIL: err };
267
+ await eventManager.emit("milkio:executeError", { handleError, path: path as string, options: options as any, error: error });
244
268
  await iterator.throw(err);
245
- streamResultFetched.reject([{ REQUEST_FAIL: err }, null, { executeId: "unknown" }]);
269
+ streamResultFetched.reject([error, null, { executeId: "unknown" }]);
246
270
  }
247
271
  }
248
272
 
@@ -253,13 +277,17 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
253
277
  next(): Promise<IteratorResult<unknown>> {
254
278
  const index = ++iteratorIndex;
255
279
  if (stacks.has(index - 2)) stacks.delete(index - 2);
256
- if (stacks.has(index)) {
257
- return stacks.get(index)!.promise;
258
- } else {
280
+ if (!stacks.has(index) && !curRequestController.signal.aborted) {
281
+ const stack = withResolvers<IteratorResult<any>>();
282
+ stacks.set(index, { ...stack, done: false });
283
+ return stack.promise;
284
+ }
285
+ if (!stacks.has(index) && curRequestController.signal.aborted) {
259
286
  const stack = withResolvers<IteratorResult<any>>();
260
- stacks.set(index, stack);
287
+ stack.resolve({ done: true, value: undefined });
261
288
  return stack.promise;
262
289
  }
290
+ return stacks.get(index)!.promise;
263
291
  },
264
292
  async return(): Promise<IteratorResult<void>> {
265
293
  if (!curRequestController.signal.aborted) curRequestController.abort();
@@ -277,6 +305,11 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
277
305
  data: err,
278
306
  },
279
307
  };
308
+ for (const [_index, stack] of stacks) {
309
+ if (stack.done) continue;
310
+ stack.done = true;
311
+ stack.resolve({ done: true, value: undefined });
312
+ }
280
313
  if (!curRequestController.signal.aborted) curRequestController.abort();
281
314
  for (const [_, iterator] of stacks) iterator.resolve({ done: true, value: undefined });
282
315
  return { done: true, value: undefined };
@@ -307,6 +340,7 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
307
340
  const stacks: Map<
308
341
  number,
309
342
  {
343
+ done: boolean;
310
344
  promise: Promise<IteratorResult<any>>;
311
345
  resolve: (value: IteratorResult<any>) => void;
312
346
  reject: (reason: any) => void;
@@ -314,15 +348,16 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
314
348
  > = new Map();
315
349
  let stacksIndex: number = 0;
316
350
  let iteratorIndex: number = 0;
317
- let streamResult: any = undefined;
318
351
 
319
352
  const onmessage = (event: EventSourceMessage) => {
320
353
  const index = ++stacksIndex;
321
- if (stacks.has(index)) stacks.get(index)!.resolve({ done: false, value: TSON.parse(event.data) });
322
- else {
354
+ if (stacks.has(index)) {
355
+ const stack = stacks.get(index);
356
+ stack!.resolve({ done: false, value: TSON.parse(event.data) });
357
+ } else {
323
358
  const stack = withResolvers<IteratorResult<any>>();
324
359
  stack.resolve({ done: false, value: TSON.parse(event.data) });
325
- stacks.set(index, stack);
360
+ stacks.set(index, { ...stack, done: false });
326
361
  }
327
362
  };
328
363
 
@@ -330,7 +365,9 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
330
365
 
331
366
  async function create() {
332
367
  curRequestController = new $abort();
333
- curRequestController.signal.addEventListener("abort", () => iterator.return());
368
+ curRequestController.signal.addEventListener("abort", () => {
369
+ iterator.return();
370
+ });
334
371
  try {
335
372
  const response = await $fetch(`${baseUrl}/$subscribe`, {
336
373
  method: "POST",
@@ -360,13 +397,17 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
360
397
  next(): Promise<IteratorResult<unknown>> {
361
398
  const index = ++iteratorIndex;
362
399
  if (stacks.has(index - 2)) stacks.delete(index - 2);
363
- if (stacks.has(index)) {
364
- return stacks.get(index)!.promise;
365
- } else {
400
+ if (!stacks.has(index) && !curRequestController.signal.aborted) {
401
+ const stack = withResolvers<IteratorResult<any>>();
402
+ stacks.set(index, { ...stack, done: false });
403
+ return stack.promise;
404
+ }
405
+ if (!stacks.has(index) && curRequestController.signal.aborted) {
366
406
  const stack = withResolvers<IteratorResult<any>>();
367
- stacks.set(index, stack);
407
+ stack.resolve({ done: true, value: undefined });
368
408
  return stack.promise;
369
409
  }
410
+ return stacks.get(index)!.promise;
370
411
  },
371
412
  async return(): Promise<IteratorResult<void>> {
372
413
  if (!curRequestController.signal.aborted) curRequestController.abort();
@@ -374,15 +415,6 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
374
415
  return { done: true, value: undefined };
375
416
  },
376
417
  async throw(err: any): Promise<IteratorResult<void>> {
377
- streamResult = {
378
- success: false,
379
- fail: {
380
- code: "NETWORK_ERROR",
381
- message: "Network Error",
382
- fromClient: true,
383
- data: err,
384
- },
385
- };
386
418
  if (!curRequestController.signal.aborted) curRequestController.abort();
387
419
  for (const [_, iterator] of stacks) iterator.resolve({ done: true, value: undefined });
388
420
  return { done: true, value: undefined };
@@ -430,15 +462,6 @@ export async function createStargate<Generated extends { routeSchema: any; rejec
430
462
  return stargate;
431
463
  }
432
464
 
433
- // export function defineMiddleware(options: MiddlewareOptions): () => MiddlewareOptions & { isMiddleware: true } {
434
- // return () => ({
435
- // ...options,
436
- // isMiddleware: true,
437
- // });
438
- // }
439
-
440
- let guid = 0;
441
-
442
465
  export type ExecuteStreamOptions = {
443
466
  headers?: Record<string, string>;
444
467
  timeout?: number;
package/package.json CHANGED
@@ -1,15 +1,12 @@
1
1
  {
2
2
  "name": "@milkio/stargate",
3
3
  "module": "index.ts",
4
- "version": "1.0.0-alpha.0",
4
+ "version": "1.0.0-alpha.10",
5
5
  "type": "module",
6
6
  "dependencies": {
7
7
  "@southern-aurora/tson": "^2.0.2"
8
8
  },
9
9
  "devDependencies": {
10
10
  "@types/bun": "latest"
11
- },
12
- "peerDependencies": {
13
- "typescript": "5.6.0"
14
11
  }
15
12
  }
package/tsconfig.json CHANGED
File without changes