@milkio/astra 1.0.0-alpha.0

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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "enableReleases": false,
3
+ "githubOwner": "akirarika",
4
+ "githubRepo": "milkio",
5
+ "giteeOwner": "akirarika",
6
+ "giteeRepo": "milkio"
7
+ }
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # milkio-test
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ bun run index.ts
13
+ ```
14
+
15
+ This project was created using `bun init` in bun v1.1.29. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
package/index.ts ADDED
@@ -0,0 +1,204 @@
1
+ import { join, dirname } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { format } from "date-fns";
4
+ import { existsSync } from "node:fs";
5
+ import { readFile } from "node:fs/promises";
6
+ import { cwd } from "node:process";
7
+ import { load } from "js-toml";
8
+ import typia from "typia";
9
+ import { TSON } from "@southern-aurora/tson";
10
+
11
+ export type AstraOptionsInit = {
12
+ stargate: { $types: any; execute: any; ping: any; cookbook: any };
13
+ bootstrap: () => Promise<Record<string, any>>;
14
+ };
15
+
16
+ export type GeneratorGeneric<T> = T extends AsyncGenerator<infer I> ? I : never;
17
+
18
+ export type Mixin<T, U> = U & Omit<T, keyof U>;
19
+
20
+ export type ExecuteOptions = {
21
+ headers?: Record<string, string>;
22
+ timeout?: number;
23
+ type?: "action" | "stream";
24
+ };
25
+
26
+ export type ExecuteResultsOption = { executeId: string };
27
+
28
+ export type Reject = (description: string, ...params: Array<unknown>) => Error;
29
+
30
+ export const createAstra = async <AstraOptions extends AstraOptionsInit, Generated extends AstraOptions["stargate"]["$types"]["generated"]>(astraOptions: AstraOptions) => {
31
+ let cookbookOptions: any = undefined;
32
+ if (!existsSync(join(cwd(), "cookbook.toml"))) throw new Error(`The "cookbook.toml" file does not exist in the current directory. If you are running the test with the VS Code extension, make sure it exists in the root directory of the folder you are opening with VS Code.`);
33
+ cookbookOptions = load((await readFile(join(cwd(), "cookbook.toml"))).toString());
34
+ // wait for all milkio projects to start and can be accessed
35
+ // the reason why stargate's ping method is not used directly is that even if only one project is tested, it is necessary to wait for all milkio projects to start
36
+ await Promise.all([
37
+ ...(() => {
38
+ const projectStatus = new Map<string, { promise: Promise<undefined>; resolve: (value?: undefined | PromiseLike<undefined>) => void; reject: (reason?: any) => void }>();
39
+ for (const projectName in cookbookOptions.projects) {
40
+ const project = cookbookOptions.projects[projectName];
41
+ if (project.type !== "milkio") continue;
42
+ projectStatus.set(projectName, withResolvers());
43
+ let counter = 256;
44
+ let timer: Timer | null = setInterval(async () => {
45
+ if (--counter <= 0) {
46
+ clearInterval(timer!);
47
+ timer = null;
48
+ console.warn(`[cookbook] Your project ${projectName} (http://localhost:${project.port}/) HTTP server hasn't started for too long.`);
49
+ projectStatus.get(projectName)!.resolve(undefined);
50
+ return;
51
+ }
52
+ try {
53
+ const response = await fetchWithTimeout(`http://localhost:${project.port}/generate_204`, { method: "HEAD", timeout: 1024 });
54
+ if (response.status === 204) {
55
+ if (timer) clearTimeout(timer);
56
+ timer = null;
57
+ return projectStatus.get(projectName)!.resolve(undefined);
58
+ }
59
+ } catch (error) {}
60
+ }, 42);
61
+ }
62
+ return Array.from(projectStatus.values()).map((v) => v.promise);
63
+ })(),
64
+ ]);
65
+
66
+ type Execute = <Path extends keyof Generated["routeSchema"]["$types"]>(
67
+ path: Path,
68
+ options?: Mixin<
69
+ ExecuteOptions,
70
+ | {
71
+ params?: Generated["routeSchema"]["$types"][Path]["params"];
72
+ }
73
+ | {
74
+ params?: Partial<Generated["routeSchema"]["$types"][Path]["params"]>;
75
+ generateParams: true;
76
+ }
77
+ >,
78
+ ) => Promise<
79
+ Generated["routeSchema"]["$types"][Path]["🐣"] extends boolean
80
+ ? // action
81
+ [Partial<Generated["rejectCode"]>, null, ExecuteResultsOption] | [null, Generated["routeSchema"]["$types"][Path]["result"], ExecuteResultsOption]
82
+ : // stream
83
+ [Partial<Generated["rejectCode"]>, null, ExecuteResultsOption] | [null, AsyncGenerator<[Partial<Generated["rejectCode"]>, null] | [null, GeneratorGeneric<Generated["routeSchema"]["$types"][Path]["result"]>], ExecuteResultsOption>]
84
+ >;
85
+
86
+ type MirrorWorld = Mixin<
87
+ Awaited<ReturnType<AstraOptions["bootstrap"]>>,
88
+ {
89
+ paths: { cwd: string; milkio: string; generated: string };
90
+ execute: Execute;
91
+ }
92
+ >;
93
+
94
+ return {
95
+ options: astraOptions,
96
+ async createMirrorWorld(importMetaUrl: string): Promise<[MirrorWorld, Reject]> {
97
+ const thisFilePath = join(fileURLToPath(importMetaUrl));
98
+ const thisFileDirPath = join(dirname(thisFilePath)).replaceAll("\\", "/");
99
+ const thisFileDirPathArr = thisFileDirPath.split("/");
100
+ let projectName: string = "";
101
+
102
+ await (async () => {
103
+ let isProjectsDirectory = false;
104
+ for (let i = 0; i < thisFileDirPathArr.length; i++) {
105
+ if (thisFileDirPathArr[i] === "projects") {
106
+ isProjectsDirectory = true;
107
+ continue;
108
+ }
109
+ if (isProjectsDirectory === false) continue;
110
+ projectName = thisFileDirPathArr[i];
111
+ break;
112
+ }
113
+ if (projectName === "") throw new Error("Unable to determine the path of the current test, make sure the test is under a milkio project.");
114
+ let projectNameChecked = false;
115
+ for (const projectNameForCookbookOptions in cookbookOptions.projects) {
116
+ if (projectNameForCookbookOptions === projectName) {
117
+ projectNameChecked = true;
118
+ break;
119
+ }
120
+ }
121
+ if (projectNameChecked === false) throw new Error(`Project name "${projectName}" not found in "cookbook.toml" in "projects.${projectName}".`);
122
+ })();
123
+
124
+ const paths = {
125
+ cwd: join(cwd(), "projects", projectName),
126
+ milkio: join(cwd(), "projects", projectName, ".milkio"),
127
+ generated: join(cwd(), "projects", projectName, ".milkio", "generated"),
128
+ };
129
+
130
+ const execute = async (path: Parameters<MirrorWorld["execute"]>[0], optionsInit?: Parameters<MirrorWorld["execute"]>[1]) => {
131
+ let options = (optionsInit as any) ?? {};
132
+ if (options?.generateParams === true) {
133
+ if (!options?.params) options.params = {};
134
+ options.params.$milkioGenerateParams = "enable";
135
+ }
136
+
137
+ const results = await this.options.stargate.cookbook.subscribe(`http://localhost:${cookbookOptions.general.cookbookPort}`);
138
+ console.log("[MILKIO]", "--- server logs start ---");
139
+ void (async () => {
140
+ for await (const result of results) {
141
+ if (result.type !== "milkio@logger") continue;
142
+ console.log("[MILKIO]", ...(result.log ?? []));
143
+ }
144
+ })();
145
+
146
+ const response = await this.options.stargate.execute(path, options);
147
+
148
+ await new Promise((resolve) => setTimeout(resolve, 40));
149
+ results.return();
150
+
151
+ console.log("[MILKIO]", "--- server logs end ---");
152
+
153
+ return response;
154
+ };
155
+
156
+ const world = {
157
+ ...(await astraOptions.bootstrap()),
158
+ paths,
159
+ execute,
160
+ } as any;
161
+
162
+ const reject = (...params: Array<unknown>): Error => {
163
+ const output: Array<any> = ["[REJECT]", ...params];
164
+ console.log(...output);
165
+ for (let index = 1; index < output.length; index++) {
166
+ if (output[index] !== null && typeof output[index] === "object") {
167
+ if (output[index] instanceof Error || (output[index].message && output[index].stack)) {
168
+ output[index] = output[index].toString();
169
+ } else {
170
+ output[index] = TSON.stringify(output[index]);
171
+ }
172
+ }
173
+ }
174
+ const message = output.join(" ");
175
+ return new Error(message);
176
+ };
177
+
178
+ return [world, reject];
179
+ },
180
+ };
181
+ };
182
+
183
+ export async function fetchWithTimeout(url: string, options: FetchRequestInit & { timeout?: number } = {}) {
184
+ const { timeout = 8000 } = options;
185
+
186
+ const controller = new AbortController();
187
+ const id = setTimeout(() => controller.abort(), timeout);
188
+ const response = await fetch(url, {
189
+ ...options,
190
+ signal: controller.signal,
191
+ });
192
+ clearTimeout(id);
193
+ return response;
194
+ }
195
+
196
+ function withResolvers<T = any>(): PromiseWithResolvers<T> {
197
+ let resolve: PromiseWithResolvers<T>["resolve"];
198
+ let reject: PromiseWithResolvers<T>["reject"];
199
+ const promise = new Promise<T>((res, rej) => {
200
+ resolve = res;
201
+ reject = rej;
202
+ });
203
+ return { promise, resolve: resolve!, reject: reject! };
204
+ }
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@milkio/astra",
3
+ "module": "index.ts",
4
+ "version": "1.0.0-alpha.0",
5
+ "type": "module",
6
+ "devDependencies": {
7
+ "@types/bun": "latest"
8
+ },
9
+ "peerDependencies": {
10
+ "typescript": "5.6.0"
11
+ },
12
+ "dependencies": {
13
+ "@southern-aurora/tson": "^2.0.2",
14
+ "date-fns": "^4.1.0",
15
+ "js-toml": "^1.0.0"
16
+ }
17
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Enable latest features
4
+ "lib": ["ESNext", "DOM"],
5
+ "target": "ESNext",
6
+ "module": "ESNext",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+
11
+ // Bundler mode
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "noEmit": true,
16
+
17
+ // Best practices
18
+ "strict": true,
19
+ "skipLibCheck": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+
22
+ // Some stricter flags (disabled by default)
23
+ "noUnusedLocals": false,
24
+ "noUnusedParameters": false,
25
+ "noPropertyAccessFromIndexSignature": false
26
+ }
27
+ }