@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.
- package/.publish/publish.json +0 -0
- package/README.md +1 -1
- package/index.ts +120 -97
- package/package.json +1 -4
- package/tsconfig.json +0 -0
package/.publish/publish.json
CHANGED
|
File without changes
|
package/README.md
CHANGED
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
|
-
|
|
130
|
-
|
|
131
|
-
// }
|
|
149
|
+
try {
|
|
150
|
+
await eventManager.emit("milkio:executeBefore", { path: path as string, options: options as any });
|
|
132
151
|
|
|
133
|
-
|
|
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)
|
|
154
|
-
|
|
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))
|
|
205
|
-
|
|
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", () =>
|
|
240
|
+
curRequestController.signal.addEventListener("abort", () => {
|
|
241
|
+
iterator.return();
|
|
242
|
+
});
|
|
218
243
|
try {
|
|
219
|
-
|
|
220
|
-
|
|
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([
|
|
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
|
-
|
|
258
|
-
|
|
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
|
-
|
|
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))
|
|
322
|
-
|
|
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", () =>
|
|
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
|
-
|
|
365
|
-
|
|
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
|
-
|
|
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.
|
|
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
|