@warp-drive/holodeck 0.0.0-beta.15 → 0.0.0-beta.17
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/LICENSE.md +19 -5
- package/README.md +2 -2
- package/dist/index.js.map +1 -1
- package/dist/mock.js.map +1 -1
- package/logos/NCC-1701-a-gold.svg +4 -0
- package/logos/NCC-1701-a-gold_100.svg +1 -0
- package/logos/NCC-1701-a-gold_base-64.txt +1 -0
- package/logos/README.md +4 -0
- package/logos/docs-badge.svg +2 -0
- package/logos/ember-data-logo-dark.svg +12 -0
- package/logos/ember-data-logo-light.svg +12 -0
- package/logos/github-header.svg +444 -0
- package/logos/social1.png +0 -0
- package/logos/social2.png +0 -0
- package/logos/warp-drive-logo-dark.svg +4 -0
- package/logos/warp-drive-logo-gold.svg +4 -0
- package/package.json +19 -28
- package/server/index.js +151 -95
- package/server/start-node.js +3 -0
- package/server/tsconfig.json +12 -0
- package/server/worker.js +3 -0
- /package/{NCC-1701-a-blue.svg → logos/NCC-1701-a-blue.svg} +0 -0
- /package/{NCC-1701-a.svg → logos/NCC-1701-a.svg} +0 -0
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 324 32">
|
|
2
|
+
<path fill="#110819"
|
|
3
|
+
d="M321.58 29.54a41.7 41.7 0 0 1-7.26 1.72c-2.4.36-4.87.53-7.4.53-3.21 0-6.09-.34-8.6-1.03a18.5 18.5 0 0 1-6.34-3.03 13.07 13.07 0 0 1-3.94-4.83c-.9-1.9-1.35-4.06-1.35-6.47a14.32 14.32 0 0 1 5.22-11.19 18.14 18.14 0 0 1 6.06-3.3c2.36-.81 5-1.21 7.9-1.21 2.68 0 5.13.36 7.35 1.1 2.24.71 4.15 1.78 5.74 3.2a14.28 14.28 0 0 1 3.72 5.24 18.12 18.12 0 0 1 1.33 7.17v1.98h-29.1a7.5 7.5 0 0 0 1.28 2.56c.6.77 1.4 1.43 2.42 1.97 1.02.55 2.27.97 3.74 1.27 1.5.3 3.27.45 5.33.45a35.35 35.35 0 0 0 8.23-.96c1.22-.3 2.31-.64 3.29-1 .99-.35 1.78-.7 2.38-1.07v6.9Zm-5.5-15.96a6.73 6.73 0 0 0-.66-2.26 5.82 5.82 0 0 0-1.72-2.13 9.46 9.46 0 0 0-3.1-1.54 15.6 15.6 0 0 0-4.77-.63c-1.79 0-3.33.23-4.64.67-1.3.44-2.4 1-3.29 1.65a8.37 8.37 0 0 0-2.04 2.13c-.48.76-.8 1.46-.94 2.1h21.16ZM271.84 31h-9.28L247.63 1.48h8.9l10.74 22.22 10.72-22.22h8.9L271.83 31ZM234.8 31V1.48h7.97V31h-7.97ZM229.73 8.16l-.94-.28c-.4-.13-.88-.25-1.42-.36a17.88 17.88 0 0 0-3.8-.45c-1.44 0-2.78.18-4.02.53-1.23.35-2.39.81-3.46 1.4a19.48 19.48 0 0 0-3 1.98c-.92.73-1.77 1.48-2.54 2.25V31h-7.97V1.48h7.97v4.8c.96-.72 1.94-1.41 2.94-2.07a25.36 25.36 0 0 1 3.16-1.78 18.9 18.9 0 0 1 3.48-1.23 15.39 15.39 0 0 1 5.44-.39 25 25 0 0 1 4.16.67v6.68ZM197.05 16.22c0 1.89-.2 3.57-.62 5.05a12.7 12.7 0 0 1-1.76 3.82 11.07 11.07 0 0 1-2.7 2.77 13.77 13.77 0 0 1-3.51 1.83c-1.29.46-2.68.8-4.17 1-1.49.21-3.04.31-4.66.31H160.9V1.48h18.69c1.62 0 3.17.1 4.66.32 1.49.2 2.88.53 4.17 1 1.3.45 2.48 1.06 3.54 1.82 1.06.74 1.96 1.67 2.7 2.77a12.7 12.7 0 0 1 1.77 3.82c.42 1.46.62 3.13.62 5Zm-8.03 0c0-1.42-.19-2.65-.56-3.7a5.64 5.64 0 0 0-1.76-2.57 7.66 7.66 0 0 0-3.16-1.53c-1.3-.34-2.9-.52-4.77-.52h-9.9v16.68h9.9c1.88 0 3.47-.17 4.77-.5a7.86 7.86 0 0 0 3.16-1.54c.81-.7 1.4-1.58 1.76-2.63.37-1.04.56-2.27.56-3.7ZM153.98 10.55c0 1.47-.25 2.78-.73 3.9a6.82 6.82 0 0 1-2.26 2.86 10.95 10.95 0 0 1-4 1.77 25.6 25.6 0 0 1-5.86.58h-13.26V31h-2.68V1.48h15.94c2.3 0 4.25.2 5.87.6 1.63.39 2.96.96 4 1.72a6.67 6.67 0 0 1 2.25 2.84c.48 1.13.73 2.43.73 3.9Zm-2.77 0c0-1.4-.24-2.54-.71-3.4a4.53 4.53 0 0 0-2.15-1.97c-.96-.48-2.19-.8-3.68-.95a50.43 50.43 0 0 0-5.26-.24h-11.54v13.15h11.54l2.51.02c.9 0 1.8-.04 2.67-.12.87-.1 1.7-.27 2.5-.5.8-.24 1.5-.6 2.1-1.1a5.05 5.05 0 0 0 1.46-1.9 7 7 0 0 0 .56-3ZM119.76 3.76c-.41-.13-1-.27-1.74-.41-.73-.16-1.67-.24-2.83-.24-1.6 0-3.12.2-4.54.6a17.94 17.94 0 0 0-7.28 3.96 23.73 23.73 0 0 0-2.8 2.83V31H97.9V1.48h2.69V7.5c.96-1 2-1.9 3.11-2.73a21.54 21.54 0 0 1 7.48-3.53 17.47 17.47 0 0 1 5.6-.47c.4.02.77.04 1.1.09a16.6 16.6 0 0 1 1.9.26v2.64ZM85.52 31v-3.27c-1.03.56-2.2 1.08-3.53 1.55a40.4 40.4 0 0 1-13.13 2.3c-1.91 0-3.64-.17-5.17-.52a12.2 12.2 0 0 1-3.87-1.52A7.38 7.38 0 0 1 57.37 27a7.06 7.06 0 0 1-.86-3.52c0-1.32.33-2.48 1-3.48a8.81 8.81 0 0 1 2.85-2.64c1.23-.76 2.71-1.4 4.45-1.91 1.74-.53 3.7-.98 5.84-1.34 2.15-.37 4.47-.67 6.96-.9 2.5-.24 5.14-.44 7.9-.6v-2.26c0-.91-.16-1.72-.5-2.42a5.54 5.54 0 0 0-1.45-1.83 7.97 7.97 0 0 0-2.17-1.31c-.83-.36-1.73-.65-2.7-.86a33.97 33.97 0 0 0-13.54.21c-1.03.25-2.02.53-2.96.86-.95.33-1.9.68-2.86 1.06V2.92c1.99-.53 4.1-.99 6.36-1.38 2.26-.4 4.66-.6 7.2-.6 2.14 0 4.15.19 6.01.56 1.86.36 3.48.94 4.86 1.74A9.16 9.16 0 0 1 87 6.36a8.55 8.55 0 0 1 1.18 4.62V31h-2.66Zm0-16c-4.69.25-8.69.62-12.01 1.09-3.31.47-6.02 1.05-8.12 1.74-2.1.69-3.66 1.49-4.64 2.4a4.18 4.18 0 0 0-1.46 3.12c0 .95.23 1.78.7 2.52a5.86 5.86 0 0 0 2.09 1.84c.9.49 2 .86 3.29 1.12 1.28.24 2.73.37 4.34.37a29.36 29.36 0 0 0 5.95-.6 36.6 36.6 0 0 0 5.71-1.57c.86-.32 1.64-.66 2.34-1.01a11.3 11.3 0 0 0 1.8-1.1v-9.93ZM28.65 1.48l10.53 27.37L50.09 1.48h2.99L41.2 31h-4L26.84 4.34 16.51 31h-4L.63 1.48h2.99l10.91 27.37 10.5-27.37h3.62Z" />
|
|
4
|
+
</svg>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 324 32">
|
|
2
|
+
<path fill="#FFC474"
|
|
3
|
+
d="M321.58 29.54a41.7 41.7 0 0 1-7.26 1.72c-2.4.36-4.87.53-7.4.53-3.21 0-6.09-.34-8.6-1.03a18.5 18.5 0 0 1-6.34-3.03 13.07 13.07 0 0 1-3.94-4.83c-.9-1.9-1.35-4.06-1.35-6.47a14.32 14.32 0 0 1 5.22-11.19 18.14 18.14 0 0 1 6.06-3.3c2.36-.81 5-1.21 7.9-1.21 2.68 0 5.13.36 7.35 1.1 2.24.71 4.15 1.78 5.74 3.2a14.28 14.28 0 0 1 3.72 5.24 18.12 18.12 0 0 1 1.33 7.17v1.98h-29.1a7.5 7.5 0 0 0 1.28 2.56c.6.77 1.4 1.43 2.42 1.97 1.02.55 2.27.97 3.74 1.27 1.5.3 3.27.45 5.33.45a35.35 35.35 0 0 0 8.23-.96c1.22-.3 2.31-.64 3.29-1 .99-.35 1.78-.7 2.38-1.07v6.9Zm-5.5-15.96a6.73 6.73 0 0 0-.66-2.26 5.82 5.82 0 0 0-1.72-2.13 9.46 9.46 0 0 0-3.1-1.54 15.6 15.6 0 0 0-4.77-.63c-1.79 0-3.33.23-4.64.67-1.3.44-2.4 1-3.29 1.65a8.37 8.37 0 0 0-2.04 2.13c-.48.76-.8 1.46-.94 2.1h21.16ZM271.84 31h-9.28L247.63 1.48h8.9l10.74 22.22 10.72-22.22h8.9L271.83 31ZM234.8 31V1.48h7.97V31h-7.97ZM229.73 8.16l-.94-.28c-.4-.13-.88-.25-1.42-.36a17.88 17.88 0 0 0-3.8-.45c-1.44 0-2.78.18-4.02.53-1.23.35-2.39.81-3.46 1.4a19.48 19.48 0 0 0-3 1.98c-.92.73-1.77 1.48-2.54 2.25V31h-7.97V1.48h7.97v4.8c.96-.72 1.94-1.41 2.94-2.07a25.36 25.36 0 0 1 3.16-1.78 18.9 18.9 0 0 1 3.48-1.23 15.39 15.39 0 0 1 5.44-.39 25 25 0 0 1 4.16.67v6.68ZM197.05 16.22c0 1.89-.2 3.57-.62 5.05a12.7 12.7 0 0 1-1.76 3.82 11.07 11.07 0 0 1-2.7 2.77 13.77 13.77 0 0 1-3.51 1.83c-1.29.46-2.68.8-4.17 1-1.49.21-3.04.31-4.66.31H160.9V1.48h18.69c1.62 0 3.17.1 4.66.32 1.49.2 2.88.53 4.17 1 1.3.45 2.48 1.06 3.54 1.82 1.06.74 1.96 1.67 2.7 2.77a12.7 12.7 0 0 1 1.77 3.82c.42 1.46.62 3.13.62 5Zm-8.03 0c0-1.42-.19-2.65-.56-3.7a5.64 5.64 0 0 0-1.76-2.57 7.66 7.66 0 0 0-3.16-1.53c-1.3-.34-2.9-.52-4.77-.52h-9.9v16.68h9.9c1.88 0 3.47-.17 4.77-.5a7.86 7.86 0 0 0 3.16-1.54c.81-.7 1.4-1.58 1.76-2.63.37-1.04.56-2.27.56-3.7ZM153.98 10.55c0 1.47-.25 2.78-.73 3.9a6.82 6.82 0 0 1-2.26 2.86 10.95 10.95 0 0 1-4 1.77 25.6 25.6 0 0 1-5.86.58h-13.26V31h-2.68V1.48h15.94c2.3 0 4.25.2 5.87.6 1.63.39 2.96.96 4 1.72a6.67 6.67 0 0 1 2.25 2.84c.48 1.13.73 2.43.73 3.9Zm-2.77 0c0-1.4-.24-2.54-.71-3.4a4.53 4.53 0 0 0-2.15-1.97c-.96-.48-2.19-.8-3.68-.95a50.43 50.43 0 0 0-5.26-.24h-11.54v13.15h11.54l2.51.02c.9 0 1.8-.04 2.67-.12.87-.1 1.7-.27 2.5-.5.8-.24 1.5-.6 2.1-1.1a5.05 5.05 0 0 0 1.46-1.9 7 7 0 0 0 .56-3ZM119.76 3.76c-.41-.13-1-.27-1.74-.41-.73-.16-1.67-.24-2.83-.24-1.6 0-3.12.2-4.54.6a17.94 17.94 0 0 0-7.28 3.96 23.73 23.73 0 0 0-2.8 2.83V31H97.9V1.48h2.69V7.5c.96-1 2-1.9 3.11-2.73a21.54 21.54 0 0 1 7.48-3.53 17.47 17.47 0 0 1 5.6-.47c.4.02.77.04 1.1.09a16.6 16.6 0 0 1 1.9.26v2.64ZM85.52 31v-3.27c-1.03.56-2.2 1.08-3.53 1.55a40.4 40.4 0 0 1-13.13 2.3c-1.91 0-3.64-.17-5.17-.52a12.2 12.2 0 0 1-3.87-1.52A7.38 7.38 0 0 1 57.37 27a7.06 7.06 0 0 1-.86-3.52c0-1.32.33-2.48 1-3.48a8.81 8.81 0 0 1 2.85-2.64c1.23-.76 2.71-1.4 4.45-1.91 1.74-.53 3.7-.98 5.84-1.34 2.15-.37 4.47-.67 6.96-.9 2.5-.24 5.14-.44 7.9-.6v-2.26c0-.91-.16-1.72-.5-2.42a5.54 5.54 0 0 0-1.45-1.83 7.97 7.97 0 0 0-2.17-1.31c-.83-.36-1.73-.65-2.7-.86a33.97 33.97 0 0 0-13.54.21c-1.03.25-2.02.53-2.96.86-.95.33-1.9.68-2.86 1.06V2.92c1.99-.53 4.1-.99 6.36-1.38 2.26-.4 4.66-.6 7.2-.6 2.14 0 4.15.19 6.01.56 1.86.36 3.48.94 4.86 1.74A9.16 9.16 0 0 1 87 6.36a8.55 8.55 0 0 1 1.18 4.62V31h-2.66Zm0-16c-4.69.25-8.69.62-12.01 1.09-3.31.47-6.02 1.05-8.12 1.74-2.1.69-3.66 1.49-4.64 2.4a4.18 4.18 0 0 0-1.46 3.12c0 .95.23 1.78.7 2.52a5.86 5.86 0 0 0 2.09 1.84c.9.49 2 .86 3.29 1.12 1.28.24 2.73.37 4.34.37a29.36 29.36 0 0 0 5.95-.6 36.6 36.6 0 0 0 5.71-1.57c.86-.32 1.64-.66 2.34-1.01a11.3 11.3 0 0 0 1.8-1.1v-9.93ZM28.65 1.48l10.53 27.37L50.09 1.48h2.99L41.2 31h-4L26.84 4.34 16.51 31h-4L.63 1.48h2.99l10.91 27.37 10.5-27.37h3.62Z" />
|
|
4
|
+
</svg>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@warp-drive/holodeck",
|
|
3
3
|
"description": "⚡️ Simple, Fast HTTP Mocking for Tests",
|
|
4
|
-
"version": "0.0.0-beta.
|
|
4
|
+
"version": "0.0.0-beta.17",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Chris Thoburn <runspired@users.noreply.github.com>",
|
|
7
7
|
"repository": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"homepage": "https://github.com/emberjs/data",
|
|
13
13
|
"bugs": "https://github.com/emberjs/data/issues",
|
|
14
14
|
"engines": {
|
|
15
|
-
"node": ">= 18.20.
|
|
15
|
+
"node": ">= 18.20.7"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"http-mock"
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"extends": "../../package.json"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@hono/node-server": "^1.11.1",
|
|
25
24
|
"chalk": "^5.3.0",
|
|
26
|
-
"hono": "^4.
|
|
25
|
+
"hono": "^4.7.2",
|
|
26
|
+
"@hono/node-server": "^1.13.8"
|
|
27
27
|
},
|
|
28
28
|
"type": "module",
|
|
29
29
|
"files": [
|
|
@@ -32,28 +32,25 @@
|
|
|
32
32
|
"README.md",
|
|
33
33
|
"LICENSE.md",
|
|
34
34
|
"server",
|
|
35
|
-
"
|
|
36
|
-
"NCC-1701-a-blue.svg"
|
|
35
|
+
"logos"
|
|
37
36
|
],
|
|
38
37
|
"bin": {
|
|
39
38
|
"ensure-cert": "./server/ensure-cert.js"
|
|
40
39
|
},
|
|
41
40
|
"peerDependencies": {
|
|
42
|
-
"@ember-data/request": "5.4.0-beta.
|
|
43
|
-
"@warp-drive/core-types": "0.0.0-beta.
|
|
41
|
+
"@ember-data/request": "5.4.0-beta.17",
|
|
42
|
+
"@warp-drive/core-types": "0.0.0-beta.17"
|
|
44
43
|
},
|
|
45
44
|
"devDependencies": {
|
|
46
|
-
"@babel/core": "^7.
|
|
47
|
-
"@babel/plugin-transform-typescript": "^7.
|
|
48
|
-
"@babel/preset-env": "^7.
|
|
49
|
-
"@babel/preset-typescript": "^7.
|
|
50
|
-
"@babel/runtime": "^7.
|
|
51
|
-
"@ember-data/request": "5.4.0-beta.
|
|
52
|
-
"@warp-drive/core-types": "0.0.0-beta.
|
|
53
|
-
"@warp-drive/internal-config": "5.4.0-beta.
|
|
54
|
-
"
|
|
55
|
-
"typescript": "^5.7.2",
|
|
56
|
-
"vite": "^5.2.11"
|
|
45
|
+
"@babel/core": "^7.26.9",
|
|
46
|
+
"@babel/plugin-transform-typescript": "^7.26.8",
|
|
47
|
+
"@babel/preset-env": "^7.26.9",
|
|
48
|
+
"@babel/preset-typescript": "^7.26.0",
|
|
49
|
+
"@babel/runtime": "^7.26.9",
|
|
50
|
+
"@ember-data/request": "5.4.0-beta.17",
|
|
51
|
+
"@warp-drive/core-types": "0.0.0-beta.17",
|
|
52
|
+
"@warp-drive/internal-config": "5.4.0-beta.17",
|
|
53
|
+
"vite": "^5.4.14"
|
|
57
54
|
},
|
|
58
55
|
"exports": {
|
|
59
56
|
".": {
|
|
@@ -72,17 +69,11 @@
|
|
|
72
69
|
"default": "./dist/mock.js"
|
|
73
70
|
}
|
|
74
71
|
},
|
|
75
|
-
"dependenciesMeta": {
|
|
76
|
-
"@ember-data/request": {
|
|
77
|
-
"injected": true
|
|
78
|
-
},
|
|
79
|
-
"@warp-drive/core-types": {
|
|
80
|
-
"injected": true
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
72
|
"scripts": {
|
|
84
73
|
"check:pkg-types": "tsc --noEmit",
|
|
85
74
|
"build:pkg": "vite build;",
|
|
86
|
-
"sync
|
|
75
|
+
"sync": "echo \"syncing\"",
|
|
76
|
+
"_temporarily_deactivated_lint": "eslint . --quiet --cache --cache-strategy=content",
|
|
77
|
+
"start": "vite"
|
|
87
78
|
}
|
|
88
79
|
}
|
package/server/index.js
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
/* global Bun */
|
|
2
|
-
import { serve } from '@hono/node-server';
|
|
3
2
|
import chalk from 'chalk';
|
|
4
3
|
import { Hono } from 'hono';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { serve } from '@hono/node-server';
|
|
5
|
+
import { createSecureServer } from 'node:http2';
|
|
7
6
|
import { logger } from 'hono/logger';
|
|
7
|
+
import { HTTPException } from 'hono/http-exception';
|
|
8
|
+
import { cors } from 'hono/cors';
|
|
8
9
|
import crypto from 'node:crypto';
|
|
9
10
|
import fs from 'node:fs';
|
|
10
|
-
import http2 from 'node:http2';
|
|
11
11
|
import zlib from 'node:zlib';
|
|
12
12
|
import { homedir } from 'os';
|
|
13
13
|
import path from 'path';
|
|
14
14
|
|
|
15
|
-
/** @type {import('bun-types')} */
|
|
16
15
|
const isBun = typeof Bun !== 'undefined';
|
|
17
|
-
const DEBUG =
|
|
18
|
-
|
|
16
|
+
const DEBUG =
|
|
17
|
+
process.env.DEBUG?.includes('wd:holodeck') || process.env.DEBUG === '*' || process.env.DEBUG?.includes('wd:*');
|
|
19
18
|
|
|
20
|
-
function getCertInfo() {
|
|
19
|
+
async function getCertInfo() {
|
|
21
20
|
let CERT_PATH = process.env.HOLODECK_SSL_CERT_PATH;
|
|
22
21
|
let KEY_PATH = process.env.HOLODECK_SSL_KEY_PATH;
|
|
23
22
|
|
|
@@ -39,16 +38,36 @@ function getCertInfo() {
|
|
|
39
38
|
);
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
if (isBun) {
|
|
42
|
+
const CERT = Bun.file(CERT_PATH);
|
|
43
|
+
const KEY = Bun.file(KEY_PATH);
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
if (!(await CERT.exists()) || !(await KEY.exists())) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
'SSL certificate or key not found, you may need to run `pnpm dlx @warp-drive/holodeck ensure-cert`'
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
CERT_PATH,
|
|
53
|
+
KEY_PATH,
|
|
54
|
+
CERT: await CERT.text(),
|
|
55
|
+
KEY: await KEY.text(),
|
|
56
|
+
};
|
|
57
|
+
} else {
|
|
58
|
+
if (!fs.existsSync(CERT_PATH) || !fs.existsSync(KEY_PATH)) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
'SSL certificate or key not found, you may need to run `pnpm dlx @warp-drive/holodeck ensure-cert`'
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
CERT_PATH,
|
|
66
|
+
KEY_PATH,
|
|
67
|
+
CERT: fs.readFileSync(CERT_PATH, 'utf8'),
|
|
68
|
+
KEY: fs.readFileSync(KEY_PATH, 'utf8'),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
52
71
|
}
|
|
53
72
|
|
|
54
73
|
const DEFAULT_PORT = 1135;
|
|
@@ -85,7 +104,7 @@ function getNiceUrl(url) {
|
|
|
85
104
|
*/
|
|
86
105
|
function generateFilepath(options) {
|
|
87
106
|
const { body } = options;
|
|
88
|
-
const bodyHash = body ? crypto.createHash('md5').update(body).digest('hex') : null;
|
|
107
|
+
const bodyHash = body ? crypto.createHash('md5').update(JSON.stringify(body)).digest('hex') : null;
|
|
89
108
|
const cacheDir = generateFileDir(options);
|
|
90
109
|
return `${cacheDir}/${bodyHash ? `${bodyHash}-` : 'res'}`;
|
|
91
110
|
}
|
|
@@ -94,10 +113,14 @@ function generateFileDir(options) {
|
|
|
94
113
|
return `${projectRoot}/.mock-cache/${testId}/${method}-${testRequestNumber}-${url}`;
|
|
95
114
|
}
|
|
96
115
|
|
|
97
|
-
function replayRequest(context, cacheKey) {
|
|
98
|
-
let
|
|
116
|
+
async function replayRequest(context, cacheKey) {
|
|
117
|
+
let metaJson;
|
|
99
118
|
try {
|
|
100
|
-
|
|
119
|
+
if (isBun) {
|
|
120
|
+
metaJson = await Bun.file(`${cacheKey}.meta.json`).json();
|
|
121
|
+
} else {
|
|
122
|
+
metaJson = JSON.parse(fs.readFileSync(`${cacheKey}.meta.json`, 'utf8'));
|
|
123
|
+
}
|
|
101
124
|
} catch (e) {
|
|
102
125
|
context.header('Content-Type', 'application/vnd.api+json');
|
|
103
126
|
context.status(400);
|
|
@@ -108,18 +131,23 @@ function replayRequest(context, cacheKey) {
|
|
|
108
131
|
status: '400',
|
|
109
132
|
code: 'MOCK_NOT_FOUND',
|
|
110
133
|
title: 'Mock not found',
|
|
111
|
-
detail: `No
|
|
134
|
+
detail: `No meta was found for ${context.req.method} ${context.req.url}. You may need to record a mock for this request.`,
|
|
112
135
|
},
|
|
113
136
|
],
|
|
114
137
|
})
|
|
115
138
|
);
|
|
116
139
|
}
|
|
117
140
|
|
|
118
|
-
const metaJson = JSON.parse(meta);
|
|
119
141
|
const bodyPath = `${cacheKey}.body.br`;
|
|
142
|
+
const bodyInit =
|
|
143
|
+
metaJson.status !== 204 && metaJson.status < 500
|
|
144
|
+
? isBun
|
|
145
|
+
? Bun.file(bodyPath)
|
|
146
|
+
: fs.createReadStream(bodyPath)
|
|
147
|
+
: '';
|
|
120
148
|
|
|
121
149
|
const headers = new Headers(metaJson.headers || {});
|
|
122
|
-
|
|
150
|
+
// @ts-expect-error - createReadStream is supported in node
|
|
123
151
|
const response = new Response(bodyInit, {
|
|
124
152
|
status: metaJson.status,
|
|
125
153
|
statusText: metaJson.statusText,
|
|
@@ -191,12 +219,15 @@ function createTestHandler(projectRoot) {
|
|
|
191
219
|
body: body ? JSON.stringify(body) : null,
|
|
192
220
|
testRequestNumber,
|
|
193
221
|
});
|
|
222
|
+
const compressedResponse = compress(JSON.stringify(response));
|
|
194
223
|
// allow Content-Type to be overridden
|
|
195
224
|
headers['Content-Type'] = headers['Content-Type'] || 'application/vnd.api+json';
|
|
196
225
|
// We always compress and chunk the response
|
|
197
226
|
headers['Content-Encoding'] = 'br';
|
|
198
227
|
// we don't cache since tests will often reuse similar urls for different payload
|
|
199
228
|
headers['Cache-Control'] = 'no-store';
|
|
229
|
+
// streaming requires Content-Length
|
|
230
|
+
headers['Content-Length'] = compressedResponse.length;
|
|
200
231
|
|
|
201
232
|
const cacheDir = generateFileDir({
|
|
202
233
|
projectRoot,
|
|
@@ -207,21 +238,30 @@ function createTestHandler(projectRoot) {
|
|
|
207
238
|
});
|
|
208
239
|
|
|
209
240
|
fs.mkdirSync(cacheDir, { recursive: true });
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
241
|
+
|
|
242
|
+
if (isBun) {
|
|
243
|
+
const newMetaFile = Bun.file(`${cacheKey}.meta.json`);
|
|
244
|
+
await newMetaFile.write(JSON.stringify({ url, status, statusText, headers, method, requestBody: body }));
|
|
245
|
+
const newBodyFile = Bun.file(`${cacheKey}.body.br`);
|
|
246
|
+
await newBodyFile.write(compressedResponse);
|
|
247
|
+
} else {
|
|
248
|
+
fs.writeFileSync(
|
|
249
|
+
`${cacheKey}.meta.json`,
|
|
250
|
+
JSON.stringify({ url, status, statusText, headers, method, requestBody: body })
|
|
251
|
+
);
|
|
252
|
+
fs.writeFileSync(`${cacheKey}.body.br`, compressedResponse);
|
|
253
|
+
}
|
|
254
|
+
|
|
215
255
|
context.status(204);
|
|
216
256
|
return context.body(null);
|
|
217
257
|
} else {
|
|
218
|
-
const body =
|
|
258
|
+
const body = req.body;
|
|
219
259
|
const cacheKey = generateFilepath({
|
|
220
260
|
projectRoot,
|
|
221
261
|
testId,
|
|
222
262
|
url: niceUrl,
|
|
223
263
|
method: req.method,
|
|
224
|
-
body,
|
|
264
|
+
body: body ? JSON.stringify(body) : null,
|
|
225
265
|
testRequestNumber,
|
|
226
266
|
});
|
|
227
267
|
return replayRequest(context, cacheKey);
|
|
@@ -250,10 +290,68 @@ function createTestHandler(projectRoot) {
|
|
|
250
290
|
return TestHandler;
|
|
251
291
|
}
|
|
252
292
|
|
|
293
|
+
export function startNodeServer() {
|
|
294
|
+
const args = process.argv.slice();
|
|
295
|
+
|
|
296
|
+
if (!isBun && args.length) {
|
|
297
|
+
const options = JSON.parse(args[2]);
|
|
298
|
+
_createServer(options);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export function startWorker() {
|
|
303
|
+
// listen for launch message
|
|
304
|
+
globalThis.onmessage = async (event) => {
|
|
305
|
+
const { options } = event.data;
|
|
306
|
+
|
|
307
|
+
const { server } = await _createServer(options);
|
|
308
|
+
|
|
309
|
+
// listen for messages
|
|
310
|
+
globalThis.onmessage = (event) => {
|
|
311
|
+
const message = event.data;
|
|
312
|
+
if (message === 'end') {
|
|
313
|
+
server.close();
|
|
314
|
+
globalThis.close();
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
253
320
|
/*
|
|
254
321
|
{ port?: number, projectRoot: string }
|
|
255
322
|
*/
|
|
256
|
-
export function createServer(options) {
|
|
323
|
+
export async function createServer(options, useBun = false) {
|
|
324
|
+
if (!useBun) {
|
|
325
|
+
const CURRENT_FILE = new URL(import.meta.url).pathname;
|
|
326
|
+
const START_FILE = path.join(CURRENT_FILE, '../start-node.js');
|
|
327
|
+
const server = Bun.spawn(['node', '--experimental-default-type=module', START_FILE, JSON.stringify(options)], {
|
|
328
|
+
env: process.env,
|
|
329
|
+
cwd: process.cwd(),
|
|
330
|
+
stdin: 'inherit',
|
|
331
|
+
stdout: 'inherit',
|
|
332
|
+
stderr: 'inherit',
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
return {
|
|
336
|
+
terminate() {
|
|
337
|
+
server.kill();
|
|
338
|
+
// server.unref();
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' });
|
|
344
|
+
|
|
345
|
+
worker.postMessage({
|
|
346
|
+
type: 'launch',
|
|
347
|
+
options,
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
return worker;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async function _createServer(options) {
|
|
354
|
+
const { CERT, KEY } = await getCertInfo();
|
|
257
355
|
const app = new Hono();
|
|
258
356
|
if (DEBUG) {
|
|
259
357
|
app.use('*', logger());
|
|
@@ -272,38 +370,26 @@ export function createServer(options) {
|
|
|
272
370
|
);
|
|
273
371
|
app.all('*', createTestHandler(options.projectRoot));
|
|
274
372
|
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
serve({
|
|
373
|
+
const server = serve({
|
|
374
|
+
overrideGlobalObjects: !isBun,
|
|
278
375
|
fetch: app.fetch,
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
{
|
|
283
|
-
key: KEY,
|
|
284
|
-
cert: CERT,
|
|
285
|
-
},
|
|
286
|
-
requestListener
|
|
287
|
-
);
|
|
288
|
-
} catch (e) {
|
|
289
|
-
console.log(chalk.yellow(`Failed to create secure server, falling back to http server. Error: ${e.message}`));
|
|
290
|
-
return http2.createServer(requestListener);
|
|
291
|
-
}
|
|
376
|
+
serverOptions: {
|
|
377
|
+
key: KEY,
|
|
378
|
+
cert: CERT,
|
|
292
379
|
},
|
|
380
|
+
createServer: createSecureServer,
|
|
293
381
|
port: options.port ?? DEFAULT_PORT,
|
|
294
|
-
hostname: 'localhost',
|
|
295
|
-
// bun uses TLS options
|
|
296
|
-
// tls: {
|
|
297
|
-
// key: Bun.file(KEY_PATH),
|
|
298
|
-
// cert: Bun.file(CERT_PATH),
|
|
299
|
-
// },
|
|
382
|
+
hostname: options.hostname ?? 'localhost',
|
|
300
383
|
});
|
|
301
384
|
|
|
302
385
|
console.log(
|
|
303
|
-
`\tMock server running at ${chalk.
|
|
386
|
+
`\tMock server running at ${chalk.yellow('https://') + chalk.magenta((options.hostname ?? 'localhost') + ':') + chalk.yellow(options.port ?? DEFAULT_PORT)}`
|
|
304
387
|
);
|
|
388
|
+
|
|
389
|
+
return { app, server };
|
|
305
390
|
}
|
|
306
391
|
|
|
392
|
+
/** @type {Map<string, Awaited<ReturnType<typeof createServer>>>} */
|
|
307
393
|
const servers = new Map();
|
|
308
394
|
|
|
309
395
|
export default {
|
|
@@ -325,59 +411,29 @@ export default {
|
|
|
325
411
|
)}`
|
|
326
412
|
)
|
|
327
413
|
);
|
|
328
|
-
console.log(chalk.grey(`\n\tStarting Subroutines (mode:${chalk.cyan(isBun ? 'bun' : 'node')})`));
|
|
329
|
-
|
|
330
|
-
if (isBun) {
|
|
331
|
-
const serverProcess = Bun.spawn(
|
|
332
|
-
['node', '--experimental-default-type=module', CURRENT_FILE, JSON.stringify(options)],
|
|
333
|
-
{
|
|
334
|
-
env: process.env,
|
|
335
|
-
cwd: process.cwd(),
|
|
336
|
-
stdout: 'inherit',
|
|
337
|
-
stderr: 'inherit',
|
|
338
|
-
}
|
|
339
|
-
);
|
|
340
|
-
servers.set(projectRoot, serverProcess);
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
414
|
+
console.log(chalk.grey(`\n\tStarting Holodeck Subroutines (mode:${chalk.cyan(isBun ? 'bun' : 'node')})`));
|
|
343
415
|
|
|
344
416
|
if (servers.has(projectRoot)) {
|
|
345
417
|
throw new Error(`Holodeck is already running for project '${name}' at '${projectRoot}'`);
|
|
346
418
|
}
|
|
347
419
|
|
|
348
|
-
|
|
420
|
+
// toggle to true if Bun fixes CORS support for HTTP/2
|
|
421
|
+
const project = await createServer(options, false);
|
|
422
|
+
servers.set(projectRoot, project);
|
|
349
423
|
},
|
|
350
424
|
async endProgram() {
|
|
351
|
-
console.log(chalk.grey(`\n\tEnding Subroutines (mode:${chalk.cyan(isBun ? 'bun' : 'node')})`));
|
|
425
|
+
console.log(chalk.grey(`\n\tEnding Holodeck Subroutines (mode:${chalk.cyan(isBun ? 'bun' : 'node')})`));
|
|
352
426
|
const projectRoot = process.cwd();
|
|
353
427
|
|
|
354
428
|
if (!servers.has(projectRoot)) {
|
|
355
|
-
const name =
|
|
356
|
-
|
|
357
|
-
);
|
|
358
|
-
throw new Error(`Holodeck was not running for project '${name}' at '${projectRoot}'`);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
if (isBun) {
|
|
362
|
-
const serverProcess = servers.get(projectRoot);
|
|
363
|
-
serverProcess.kill();
|
|
429
|
+
const name = require(path.join(projectRoot, 'package.json')).name;
|
|
430
|
+
console.log(chalk.red(`\n\nHolodeck was not running for project '${name}' at '${projectRoot}'\n\n`));
|
|
364
431
|
return;
|
|
365
432
|
}
|
|
366
433
|
|
|
367
|
-
servers.get(projectRoot)
|
|
434
|
+
const project = servers.get(projectRoot);
|
|
368
435
|
servers.delete(projectRoot);
|
|
436
|
+
project.terminate();
|
|
437
|
+
console.log(chalk.grey(`\n\tHolodeck program ended`));
|
|
369
438
|
},
|
|
370
439
|
};
|
|
371
|
-
|
|
372
|
-
function main() {
|
|
373
|
-
const args = process.argv.slice();
|
|
374
|
-
if (!isBun && args.length) {
|
|
375
|
-
if (args[1] !== CURRENT_FILE) {
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
const options = JSON.parse(args[2]);
|
|
379
|
-
createServer(options);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
main();
|
package/server/worker.js
ADDED
|
File without changes
|
|
File without changes
|