@warp-drive/holodeck 0.0.0-alpha.12 → 0.0.0-alpha.120
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/README.md +157 -6
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/dist/mock.js.map +1 -1
- package/package.json +23 -30
- package/server/ensure-cert.js +63 -0
- package/server/index.js +244 -89
- package/bin/cmd/_start.js +0 -3
- package/bin/cmd/_stop.js +0 -3
- package/bin/cmd/pm2.js +0 -38
- package/bin/cmd/run.js +0 -50
- package/bin/cmd/spawn.js +0 -40
- package/bin/holodeck.js +0 -63
- package/dist/index.d.ts +0 -12
- package/dist/index.d.ts.map +0 -1
- package/dist/mock.d.ts +0 -37
- package/dist/mock.d.ts.map +0 -1
- package/server/CERT.md +0 -3
- package/server/localhost-key.pem +0 -28
- package/server/localhost.pem +0 -27
package/README.md
CHANGED
|
@@ -40,16 +40,21 @@
|
|
|
40
40
|
|
|
41
41
|
## Installation
|
|
42
42
|
|
|
43
|
-
> ⚠️ Private
|
|
44
|
-
|
|
45
|
-
This package may currently only be used within EmberData. A public version is coming soon 💜
|
|
46
43
|
|
|
47
44
|
```json
|
|
48
|
-
|
|
49
|
-
"@warp-drive/holodeck": "workspace:*"
|
|
50
|
-
}
|
|
45
|
+
pnpm install @warp-drive/holodeck
|
|
51
46
|
```
|
|
52
47
|
|
|
48
|
+
**Tagged Releases**
|
|
49
|
+
|
|
50
|
+
- 
|
|
51
|
+
- 
|
|
52
|
+
- 
|
|
53
|
+
- 
|
|
54
|
+
- 
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
53
58
|
## Usage
|
|
54
59
|
#### Mocking from Within a Test
|
|
55
60
|
|
|
@@ -89,6 +94,152 @@ and `brotli` minification in a way that can be replayed over and over again.
|
|
|
89
94
|
|
|
90
95
|
Basically, pay the cost when you write the test. Forever after skip the cost until you need to edit the test again.
|
|
91
96
|
|
|
97
|
+
## Setup
|
|
98
|
+
|
|
99
|
+
### Use with WarpDrive
|
|
100
|
+
|
|
101
|
+
First, you will need to add the holodeck handler to the request manager chain prior to `Fetch` (or any equivalent handler that proceeds to network).
|
|
102
|
+
|
|
103
|
+
For instance:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import RequestManager from '@ember-data/request';
|
|
107
|
+
import Fetch from '@ember-data/request/fetch';
|
|
108
|
+
import { MockServerHandler } from '@warp-drive/holodeck';
|
|
109
|
+
|
|
110
|
+
const manager = new RequestManager()
|
|
111
|
+
.use([new MockServerHandler(testContext), Fetch]);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
From within a test this might look like:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import RequestManager from '@ember-data/request';
|
|
118
|
+
import Fetch from '@ember-data/request/fetch';
|
|
119
|
+
import { MockServerHandler } from '@warp-drive/holodeck';
|
|
120
|
+
import { module, test } from 'qunit';
|
|
121
|
+
|
|
122
|
+
module('my module', function() {
|
|
123
|
+
test('my test', async function() {
|
|
124
|
+
const manager = new RequestManager()
|
|
125
|
+
.use([new MockServerHandler(this), Fetch]);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Next, you will need to configure holodeck to understand your tests contexts. For qunit and diagnostic
|
|
131
|
+
in a project using Ember this is typically done in `tests/test-helper.js`
|
|
132
|
+
|
|
133
|
+
#### With Diagnostic
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
import { setupGlobalHooks } from '@warp-drive/diagnostic';
|
|
137
|
+
import { setConfig, setTestId } from '@warp-drive/holodeck';
|
|
138
|
+
|
|
139
|
+
// if not proxying the port / set port to the correct value here
|
|
140
|
+
const MockHost = `https://${window.location.hostname}:${Number(window.location.port) + 1}`;
|
|
141
|
+
|
|
142
|
+
setConfig({ host: MockHost });
|
|
143
|
+
|
|
144
|
+
setupGlobalHooks((hooks) => {
|
|
145
|
+
hooks.beforeEach(function (assert) {
|
|
146
|
+
setTestId(this, assert.test.testId);
|
|
147
|
+
});
|
|
148
|
+
hooks.afterEach(function () {
|
|
149
|
+
setTestId(this, null);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### With QUnit
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
import * as QUnit from 'qunit';
|
|
158
|
+
import { setConfig, setTestId } from '@warp-drive/holodeck';
|
|
159
|
+
|
|
160
|
+
// if not proxying the port / set port to the correct value here
|
|
161
|
+
const MockHost = `https://${window.location.hostname}:${Number(window.location.port) + 1}`;
|
|
162
|
+
|
|
163
|
+
setConfig({ host: MockHost });
|
|
164
|
+
|
|
165
|
+
QUnit.hooks.beforeEach(function (assert) {
|
|
166
|
+
setTestId(assert.test.testId);
|
|
167
|
+
});
|
|
168
|
+
QUnit.hooks.afterEach(function (assert) {
|
|
169
|
+
setTestId(null);
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Testem
|
|
174
|
+
|
|
175
|
+
You can integrate holodeck with Testem using testem's [async config capability](https://github.com/testem/testem/blob/master/docs/config_file.md#returning-a-promise-from-testemjs):
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
module.exports = async function () {
|
|
179
|
+
const holodeck = (await import('@warp-drive/holodeck')).default;
|
|
180
|
+
await holodeck.launchProgram({
|
|
181
|
+
port: 7373,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
process.on('beforeExit', async () => {
|
|
185
|
+
await holodeck.endProgram();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
// ... testem config
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
If you need the API mock to run on the same port as the test suite, you can use Testem's [API Proxy](https://github.com/testem/testem/tree/master?tab=readme-ov-file#api-proxy)
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
module.exports = async function () {
|
|
198
|
+
const holodeck = (await import('@warp-drive/holodeck')).default;
|
|
199
|
+
await holodeck.launchProgram({
|
|
200
|
+
port: 7373,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
process.on('beforeExit', async () => {
|
|
204
|
+
await holodeck.endProgram();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
"proxies": {
|
|
209
|
+
"/api": {
|
|
210
|
+
// holodeck always runs on https
|
|
211
|
+
// the proxy is transparent so this means /api/v1 will route to https://localhost:7373/api/v1
|
|
212
|
+
"target": "https://localhost:7373",
|
|
213
|
+
// "onlyContentTypes": ["xml", "json"],
|
|
214
|
+
// if test suite is on http, set this to false
|
|
215
|
+
// "secure": false,
|
|
216
|
+
},
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Diagnostic
|
|
223
|
+
|
|
224
|
+
holodeck can be launched and cleaned up using the lifecycle hooks in the launch config
|
|
225
|
+
for diagnostic in `diagnostic.js`:
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
import launch from '@warp-drive/diagnostic/server/default-setup.js';
|
|
229
|
+
import holodeck from '@warp-drive/holodeck';
|
|
230
|
+
|
|
231
|
+
await launch({
|
|
232
|
+
async setup(options) {
|
|
233
|
+
await holodeck.launchProgram({
|
|
234
|
+
port: options.port + 1,
|
|
235
|
+
});
|
|
236
|
+
},
|
|
237
|
+
async cleanup() {
|
|
238
|
+
await holodeck.endProgram();
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
92
243
|
### ♥️ Credits
|
|
93
244
|
|
|
94
245
|
<details>
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
const TEST_IDS = new WeakMap();
|
|
2
|
+
let HOST = 'https://localhost:1135/';
|
|
3
|
+
function setConfig({
|
|
4
|
+
host
|
|
5
|
+
}) {
|
|
6
|
+
HOST = host.endsWith('/') ? host : `${host}/`;
|
|
7
|
+
}
|
|
2
8
|
function setTestId(context, str) {
|
|
3
9
|
if (str && TEST_IDS.has(context)) {
|
|
4
10
|
throw new Error(`MockServerHandler is already configured with a testId.`);
|
|
@@ -38,7 +44,9 @@ class MockServerHandler {
|
|
|
38
44
|
request.credentials = 'omit';
|
|
39
45
|
request.referrerPolicy = '';
|
|
40
46
|
try {
|
|
41
|
-
|
|
47
|
+
const future = next(request);
|
|
48
|
+
context.setStream(future.getStream());
|
|
49
|
+
return await future;
|
|
42
50
|
} catch (e) {
|
|
43
51
|
if (e instanceof Error && !(e instanceof DOMException)) {
|
|
44
52
|
e.message = e.message.replace(queryForTest, '');
|
|
@@ -54,7 +62,7 @@ async function mock(owner, generate, isRecording) {
|
|
|
54
62
|
}
|
|
55
63
|
const testMockNum = test.mock++;
|
|
56
64
|
if (getIsRecording() || isRecording) {
|
|
57
|
-
const url =
|
|
65
|
+
const url = `${HOST}__record?__xTestId=${test.id}&__xTestRequestNumber=${testMockNum}`;
|
|
58
66
|
await fetch(url, {
|
|
59
67
|
method: 'POST',
|
|
60
68
|
body: JSON.stringify(generate()),
|
|
@@ -65,5 +73,5 @@ async function mock(owner, generate, isRecording) {
|
|
|
65
73
|
}
|
|
66
74
|
}
|
|
67
75
|
|
|
68
|
-
export { MockServerHandler, getIsRecording, mock, setIsRecording, setTestId };
|
|
76
|
+
export { MockServerHandler, getIsRecording, mock, setConfig, setIsRecording, setTestId };
|
|
69
77
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import type { Handler, NextFn, RequestContext, RequestInfo, StructuredDataDocument } from '@ember-data/request';\n\nimport type { ScaffoldGenerator } from './mock';\n\nconst TEST_IDS = new WeakMap<object, { id: string; request: number; mock: number }>();\n\nlet HOST = 'https://localhost:1135/';\nexport function setConfig({ host }: { host: string }) {\n HOST = host.endsWith('/') ? host : `${host}/`;\n}\n\nexport function setTestId(context: object, str: string | null) {\n if (str && TEST_IDS.has(context)) {\n throw new Error(`MockServerHandler is already configured with a testId.`);\n }\n if (str) {\n TEST_IDS.set(context, { id: str, request: 0, mock: 0 });\n } else {\n TEST_IDS.delete(context);\n }\n}\n\nlet IS_RECORDING = false;\nexport function setIsRecording(value: boolean) {\n IS_RECORDING = Boolean(value);\n}\nexport function getIsRecording() {\n return IS_RECORDING;\n}\n\nexport class MockServerHandler implements Handler {\n declare owner: object;\n constructor(owner: object) {\n this.owner = owner;\n }\n async request<T>(context: RequestContext, next: NextFn<T>): Promise<StructuredDataDocument<T>> {\n const test = TEST_IDS.get(this.owner);\n if (!test) {\n throw new Error(\n `MockServerHandler is not configured with a testId. Use setTestId to set the testId for each test`\n );\n }\n\n const request: RequestInfo = Object.assign({}, context.request);\n const isRecording = request.url!.endsWith('/__record');\n const firstChar = request.url!.includes('?') ? '&' : '?';\n const queryForTest = `${firstChar}__xTestId=${test.id}&__xTestRequestNumber=${\n isRecording ? test.mock++ : test.request++\n }`;\n request.url = request.url + queryForTest;\n\n request.mode = 'cors';\n request.credentials = 'omit';\n request.referrerPolicy = '';\n\n try {\n const future = next(request);\n context.setStream(future.getStream());\n return await future;\n } catch (e) {\n if (e instanceof Error && !(e instanceof DOMException)) {\n e.message = e.message.replace(queryForTest, '');\n }\n throw e;\n }\n }\n}\n\nexport async function mock(owner: object, generate: ScaffoldGenerator, isRecording?: boolean) {\n const test = TEST_IDS.get(owner);\n if (!test) {\n throw new Error(`Cannot call \"mock\" before configuring a testId. Use setTestId to set the testId for each test`);\n }\n const testMockNum = test.mock++;\n if (getIsRecording() || isRecording) {\n const port = window.location.port ? `:${window.location.port}` : '';\n const url = `${HOST}__record?__xTestId=${test.id}&__xTestRequestNumber=${testMockNum}`;\n await fetch(url, {\n method: 'POST',\n body: JSON.stringify(generate()),\n mode: 'cors',\n credentials: 'omit',\n referrerPolicy: '',\n });\n }\n}\n"],"names":["TEST_IDS","WeakMap","HOST","setConfig","host","endsWith","setTestId","context","str","has","Error","set","id","request","mock","delete","IS_RECORDING","setIsRecording","value","Boolean","getIsRecording","MockServerHandler","constructor","owner","next","test","get","Object","assign","isRecording","url","firstChar","includes","queryForTest","mode","credentials","referrerPolicy","future","setStream","getStream","e","DOMException","message","replace","generate","testMockNum","fetch","method","body","JSON","stringify"],"mappings":"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"}
|
package/dist/mock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock.js","sources":["../
|
|
1
|
+
{"version":3,"file":"mock.js","sources":["../src/mock.ts"],"sourcesContent":["import { getIsRecording, mock } from '.';\n\nexport interface Scaffold {\n status: number;\n statusText?: string;\n headers: Record<string, string>;\n body: Record<string, string> | string | null;\n method: string;\n url: string;\n response: Record<string, unknown>;\n}\n\nexport type ScaffoldGenerator = () => Scaffold;\nexport type ResponseGenerator = () => Record<string, unknown>;\n\n/**\n * Sets up Mocking for a GET request on the mock server\n * for the supplied url.\n *\n * The response body is generated by the supplied response function.\n *\n * Available options:\n * - status: the status code to return (default: 200)\n * - headers: the headers to return (default: {})\n * - body: the body to match against for the request (default: null)\n * - RECORD: whether to record the request (default: false)\n *\n * @param url the url to mock, relative to the mock server host (e.g. `users/1`)\n * @param response a function which generates the response to return\n * @param options status, headers for the response, body to match against for the request, and whether to record the request\n * @return\n */\nexport function GET(\n owner: object,\n url: string,\n response: ResponseGenerator,\n options?: Partial<Omit<Scaffold, 'response' | 'url' | 'method'>> & { RECORD?: boolean }\n): Promise<void> {\n return mock(\n owner,\n () => ({\n status: options?.status ?? 200,\n statusText: options?.statusText ?? 'OK',\n headers: options?.headers ?? {},\n body: options?.body ?? null,\n method: 'GET',\n url,\n response: response(),\n }),\n getIsRecording() || (options?.RECORD ?? false)\n );\n}\nexport function POST() {}\nexport function PUT() {}\nexport function PATCH() {}\nexport function DELETE() {}\nexport function QUERY() {}\n"],"names":["GET","owner","url","response","options","mock","status","statusText","headers","body","method","getIsRecording","RECORD","POST","PUT","PATCH","DELETE","QUERY"],"mappings":";;AAeA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,GAAGA,CACjBC,KAAa,EACbC,GAAW,EACXC,QAA2B,EAC3BC,OAAuF,EACxE;AACf,EAAA,OAAOC,IAAI,CACTJ,KAAK,EACL,OAAO;AACLK,IAAAA,MAAM,EAAEF,OAAO,EAAEE,MAAM,IAAI,GAAG;AAC9BC,IAAAA,UAAU,EAAEH,OAAO,EAAEG,UAAU,IAAI,IAAI;AACvCC,IAAAA,OAAO,EAAEJ,OAAO,EAAEI,OAAO,IAAI,EAAE;AAC/BC,IAAAA,IAAI,EAAEL,OAAO,EAAEK,IAAI,IAAI,IAAI;AAC3BC,IAAAA,MAAM,EAAE,KAAK;IACbR,GAAG;IACHC,QAAQ,EAAEA,QAAQ,EAAC;AACrB,GAAC,CAAC,EACFQ,cAAc,EAAE,KAAKP,OAAO,EAAEQ,MAAM,IAAI,KAAK,CAC/C,CAAC,CAAA;AACH,CAAA;AACO,SAASC,IAAIA,GAAG,EAAC;AACjB,SAASC,GAAGA,GAAG,EAAC;AAChB,SAASC,KAAKA,GAAG,EAAC;AAClB,SAASC,MAAMA,GAAG,EAAC;AACnB,SAASC,KAAKA,GAAG;;;;"}
|
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-alpha.
|
|
4
|
+
"version": "0.0.0-alpha.120",
|
|
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.
|
|
15
|
+
"node": ">= 18.20.4"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"http-mock"
|
|
@@ -21,12 +21,11 @@
|
|
|
21
21
|
"extends": "../../package.json"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@hono/node-server": "^1.
|
|
25
|
-
"chalk": "^
|
|
26
|
-
"hono": "^
|
|
27
|
-
"pm2": "^5.3.1",
|
|
28
|
-
"pnpm-sync-dependencies-meta-injected": "0.0.10"
|
|
24
|
+
"@hono/node-server": "^1.11.1",
|
|
25
|
+
"chalk": "^5.3.0",
|
|
26
|
+
"hono": "^4.6.5"
|
|
29
27
|
},
|
|
28
|
+
"type": "module",
|
|
30
29
|
"files": [
|
|
31
30
|
"bin",
|
|
32
31
|
"dist",
|
|
@@ -37,29 +36,25 @@
|
|
|
37
36
|
"NCC-1701-a-blue.svg"
|
|
38
37
|
],
|
|
39
38
|
"bin": {
|
|
40
|
-
"
|
|
39
|
+
"ensure-cert": "./server/ensure-cert.js"
|
|
41
40
|
},
|
|
42
41
|
"peerDependencies": {
|
|
43
|
-
"@ember-data/request": "5.4.0-alpha.
|
|
42
|
+
"@ember-data/request": "5.4.0-alpha.134",
|
|
43
|
+
"@warp-drive/core-types": "5.4.0-alpha.134"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@babel/
|
|
47
|
-
"@babel/
|
|
48
|
-
"@babel/
|
|
49
|
-
"@babel/preset-
|
|
50
|
-
"@babel/
|
|
51
|
-
"@
|
|
52
|
-
"@
|
|
53
|
-
"@
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"@warp-drive/internal-config": "5.4.0-alpha.26",
|
|
58
|
-
"rollup": "^4.9.6",
|
|
59
|
-
"typescript": "^5.3.3",
|
|
60
|
-
"walk-sync": "^3.0.0"
|
|
46
|
+
"@babel/core": "^7.24.5",
|
|
47
|
+
"@babel/plugin-transform-typescript": "^7.24.5",
|
|
48
|
+
"@babel/preset-env": "^7.24.5",
|
|
49
|
+
"@babel/preset-typescript": "^7.24.1",
|
|
50
|
+
"@babel/runtime": "^7.24.5",
|
|
51
|
+
"@ember-data/request": "5.4.0-alpha.134",
|
|
52
|
+
"@warp-drive/core-types": "5.4.0-alpha.134",
|
|
53
|
+
"@warp-drive/internal-config": "5.4.0-alpha.134",
|
|
54
|
+
"pnpm-sync-dependencies-meta-injected": "0.0.14",
|
|
55
|
+
"typescript": "^5.7.2",
|
|
56
|
+
"vite": "^5.2.11"
|
|
61
57
|
},
|
|
62
|
-
"type": "module",
|
|
63
58
|
"exports": {
|
|
64
59
|
".": {
|
|
65
60
|
"node": "./server/index.js",
|
|
@@ -86,10 +81,8 @@
|
|
|
86
81
|
}
|
|
87
82
|
},
|
|
88
83
|
"scripts": {
|
|
89
|
-
"
|
|
90
|
-
"build:
|
|
91
|
-
"
|
|
92
|
-
"start": "rollup --config --watch",
|
|
93
|
-
"_syncPnpm": "bun run sync-dependencies-meta-injected"
|
|
84
|
+
"check:pkg-types": "tsc --noEmit",
|
|
85
|
+
"build:pkg": "vite build;",
|
|
86
|
+
"sync-hardlinks": "bun run sync-dependencies-meta-injected"
|
|
94
87
|
}
|
|
95
88
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import { homedir, userInfo } from 'os';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
|
|
7
|
+
function getShellConfigFilePath() {
|
|
8
|
+
const shell = userInfo().shell;
|
|
9
|
+
switch (shell) {
|
|
10
|
+
case '/bin/zsh':
|
|
11
|
+
return path.join(homedir(), '.zshrc');
|
|
12
|
+
case '/bin/bash':
|
|
13
|
+
return path.join(homedir(), '.bashrc');
|
|
14
|
+
default:
|
|
15
|
+
throw Error(
|
|
16
|
+
`Unable to determine configuration file for shell: ${shell}. Manual SSL Cert Setup Required for Holodeck.`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function main() {
|
|
22
|
+
let CERT_PATH = process.env.HOLODECK_SSL_CERT_PATH;
|
|
23
|
+
let KEY_PATH = process.env.HOLODECK_SSL_KEY_PATH;
|
|
24
|
+
const configFilePath = getShellConfigFilePath();
|
|
25
|
+
|
|
26
|
+
if (!CERT_PATH || !KEY_PATH) {
|
|
27
|
+
console.log(`Environment variables not found, updating the environment config file...\n`);
|
|
28
|
+
|
|
29
|
+
if (!CERT_PATH) {
|
|
30
|
+
CERT_PATH = path.join(homedir(), 'holodeck-localhost.pem');
|
|
31
|
+
process.env.HOLODECK_SSL_CERT_PATH = CERT_PATH;
|
|
32
|
+
execSync(`echo '\nexport HOLODECK_SSL_CERT_PATH="${CERT_PATH}"' >> ${configFilePath}`);
|
|
33
|
+
console.log(`Added HOLODECK_SSL_CERT_PATH to ${configFilePath}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!KEY_PATH) {
|
|
37
|
+
KEY_PATH = path.join(homedir(), 'holodeck-localhost-key.pem');
|
|
38
|
+
process.env.HOLODECK_SSL_KEY_PATH = KEY_PATH;
|
|
39
|
+
execSync(`echo '\nexport HOLODECK_SSL_KEY_PATH="${KEY_PATH}"' >> ${configFilePath}`);
|
|
40
|
+
console.log(`Added HOLODECK_SSL_KEY_PATH to ${configFilePath}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log(
|
|
44
|
+
`\n*** Please restart your terminal session to apply the changes or run \`source ${configFilePath}\`. ***\n`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!fs.existsSync(CERT_PATH) || !fs.existsSync(KEY_PATH)) {
|
|
49
|
+
console.log('SSL certificate or key not found, generating new ones...');
|
|
50
|
+
|
|
51
|
+
execSync(`mkcert -install`);
|
|
52
|
+
execSync(`mkcert -key-file ${KEY_PATH} -cert-file ${CERT_PATH} localhost`);
|
|
53
|
+
|
|
54
|
+
console.log('SSL certificate and key generated.');
|
|
55
|
+
} else {
|
|
56
|
+
console.log('SSL certificate and key found, using existing.');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(`Certificate path: ${CERT_PATH}`);
|
|
60
|
+
console.log(`Key path: ${KEY_PATH}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
main();
|
package/server/index.js
CHANGED
|
@@ -1,16 +1,55 @@
|
|
|
1
|
+
/* global Bun */
|
|
1
2
|
import { serve } from '@hono/node-server';
|
|
3
|
+
import chalk from 'chalk';
|
|
2
4
|
import { Hono } from 'hono';
|
|
3
5
|
import { cors } from 'hono/cors';
|
|
6
|
+
import { HTTPException } from 'hono/http-exception';
|
|
4
7
|
import { logger } from 'hono/logger';
|
|
5
8
|
import crypto from 'node:crypto';
|
|
6
9
|
import fs from 'node:fs';
|
|
7
10
|
import http2 from 'node:http2';
|
|
8
|
-
import { dirname } from 'node:path';
|
|
9
11
|
import zlib from 'node:zlib';
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
+
import { homedir } from 'os';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
|
|
15
|
+
/** @type {import('bun-types')} */
|
|
16
|
+
const isBun = typeof Bun !== 'undefined';
|
|
17
|
+
const DEBUG = process.env.DEBUG?.includes('holodeck') || process.env.DEBUG === '*';
|
|
18
|
+
const CURRENT_FILE = new URL(import.meta.url).pathname;
|
|
12
19
|
|
|
13
|
-
|
|
20
|
+
function getCertInfo() {
|
|
21
|
+
let CERT_PATH = process.env.HOLODECK_SSL_CERT_PATH;
|
|
22
|
+
let KEY_PATH = process.env.HOLODECK_SSL_KEY_PATH;
|
|
23
|
+
|
|
24
|
+
if (!CERT_PATH) {
|
|
25
|
+
CERT_PATH = path.join(homedir(), 'holodeck-localhost.pem');
|
|
26
|
+
process.env.HOLODECK_SSL_CERT_PATH = CERT_PATH;
|
|
27
|
+
|
|
28
|
+
console.log(
|
|
29
|
+
`HOLODECK_SSL_CERT_PATH was not found in the current environment. Setting it to default value of ${CERT_PATH}`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!KEY_PATH) {
|
|
34
|
+
KEY_PATH = path.join(homedir(), 'holodeck-localhost-key.pem');
|
|
35
|
+
process.env.HOLODECK_SSL_KEY_PATH = KEY_PATH;
|
|
36
|
+
|
|
37
|
+
console.log(
|
|
38
|
+
`HOLODECK_SSL_KEY_PATH was not found in the current environment. Setting it to default value of ${KEY_PATH}`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!fs.existsSync(CERT_PATH) || !fs.existsSync(KEY_PATH)) {
|
|
43
|
+
throw new Error('SSL certificate or key not found, you may need to run `pnpx @warp-drive/holodeck ensure-cert`');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
CERT_PATH,
|
|
48
|
+
KEY_PATH,
|
|
49
|
+
CERT: fs.readFileSync(CERT_PATH),
|
|
50
|
+
KEY: fs.readFileSync(KEY_PATH),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
14
53
|
|
|
15
54
|
const DEFAULT_PORT = 1135;
|
|
16
55
|
const BROTLI_OPTIONS = {
|
|
@@ -96,96 +135,116 @@ function replayRequest(context, cacheKey) {
|
|
|
96
135
|
|
|
97
136
|
function createTestHandler(projectRoot) {
|
|
98
137
|
const TestHandler = async (context) => {
|
|
99
|
-
|
|
138
|
+
try {
|
|
139
|
+
const { req } = context;
|
|
100
140
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
141
|
+
const testId = req.query('__xTestId');
|
|
142
|
+
const testRequestNumber = req.query('__xTestRequestNumber');
|
|
143
|
+
const niceUrl = getNiceUrl(req.url);
|
|
104
144
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
145
|
+
if (!testId) {
|
|
146
|
+
context.header('Content-Type', 'application/vnd.api+json');
|
|
147
|
+
context.status(400);
|
|
148
|
+
return context.body(
|
|
149
|
+
JSON.stringify({
|
|
150
|
+
errors: [
|
|
151
|
+
{
|
|
152
|
+
status: '400',
|
|
153
|
+
code: 'MISSING_X_TEST_ID_HEADER',
|
|
154
|
+
title: 'Request to the http mock server is missing the `X-Test-Id` header',
|
|
155
|
+
detail:
|
|
156
|
+
"The `X-Test-Id` header is used to identify the test that is making the request to the mock server. This is used to ensure that the mock server is only used for the test that is currently running. If using @ember-data/request add import { MockServerHandler } from '@warp-drive/holodeck'; to your request handlers.",
|
|
157
|
+
source: { header: 'X-Test-Id' },
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
})
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (!testRequestNumber) {
|
|
165
|
+
context.header('Content-Type', 'application/vnd.api+json');
|
|
166
|
+
context.status(400);
|
|
167
|
+
return context.body(
|
|
168
|
+
JSON.stringify({
|
|
169
|
+
errors: [
|
|
170
|
+
{
|
|
171
|
+
status: '400',
|
|
172
|
+
code: 'MISSING_X_TEST_REQUEST_NUMBER_HEADER',
|
|
173
|
+
title: 'Request to the http mock server is missing the `X-Test-Request-Number` header',
|
|
174
|
+
detail:
|
|
175
|
+
"The `X-Test-Request-Number` header is used to identify the request number for the current test. This is used to ensure that the mock server response is deterministic for the test that is currently running. If using @ember-data/request add import { MockServerHandler } from '@warp-drive/holodeck'; to your request handlers.",
|
|
176
|
+
source: { header: 'X-Test-Request-Number' },
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (req.method === 'POST' || niceUrl === '__record') {
|
|
184
|
+
const payload = await req.json();
|
|
185
|
+
const { url, headers, method, status, statusText, body, response } = payload;
|
|
186
|
+
const cacheKey = generateFilepath({
|
|
187
|
+
projectRoot,
|
|
188
|
+
testId,
|
|
189
|
+
url,
|
|
190
|
+
method,
|
|
191
|
+
body: body ? JSON.stringify(body) : null,
|
|
192
|
+
testRequestNumber,
|
|
193
|
+
});
|
|
194
|
+
// allow Content-Type to be overridden
|
|
195
|
+
headers['Content-Type'] = headers['Content-Type'] || 'application/vnd.api+json';
|
|
196
|
+
// We always compress and chunk the response
|
|
197
|
+
headers['Content-Encoding'] = 'br';
|
|
198
|
+
// we don't cache since tests will often reuse similar urls for different payload
|
|
199
|
+
headers['Cache-Control'] = 'no-store';
|
|
200
|
+
|
|
201
|
+
const cacheDir = generateFileDir({
|
|
202
|
+
projectRoot,
|
|
203
|
+
testId,
|
|
204
|
+
url,
|
|
205
|
+
method,
|
|
206
|
+
testRequestNumber,
|
|
207
|
+
});
|
|
123
208
|
|
|
124
|
-
|
|
209
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
210
|
+
fs.writeFileSync(
|
|
211
|
+
`${cacheKey}.meta.json`,
|
|
212
|
+
JSON.stringify({ url, status, statusText, headers, method, requestBody: body }, null, 2)
|
|
213
|
+
);
|
|
214
|
+
fs.writeFileSync(`${cacheKey}.body.br`, compress(JSON.stringify(response)));
|
|
215
|
+
context.status(204);
|
|
216
|
+
return context.body(null);
|
|
217
|
+
} else {
|
|
218
|
+
const body = await req.text();
|
|
219
|
+
const cacheKey = generateFilepath({
|
|
220
|
+
projectRoot,
|
|
221
|
+
testId,
|
|
222
|
+
url: niceUrl,
|
|
223
|
+
method: req.method,
|
|
224
|
+
body,
|
|
225
|
+
testRequestNumber,
|
|
226
|
+
});
|
|
227
|
+
return replayRequest(context, cacheKey);
|
|
228
|
+
}
|
|
229
|
+
} catch (e) {
|
|
230
|
+
if (e instanceof HTTPException) {
|
|
231
|
+
throw e;
|
|
232
|
+
}
|
|
125
233
|
context.header('Content-Type', 'application/vnd.api+json');
|
|
126
|
-
context.status(
|
|
234
|
+
context.status(500);
|
|
127
235
|
return context.body(
|
|
128
236
|
JSON.stringify({
|
|
129
237
|
errors: [
|
|
130
238
|
{
|
|
131
|
-
status: '
|
|
132
|
-
code: '
|
|
133
|
-
title: '
|
|
134
|
-
detail:
|
|
135
|
-
"The `X-Test-Request-Number` header is used to identify the request number for the current test. This is used to ensure that the mock server response is deterministic for the test that is currently running. If using @ember-data/request add import { MockServerHandler } from '@warp-drive/holodeck'; to your request handlers.",
|
|
136
|
-
source: { header: 'X-Test-Request-Number' },
|
|
239
|
+
status: '500',
|
|
240
|
+
code: 'MOCK_SERVER_ERROR',
|
|
241
|
+
title: 'Mock Server Error during Request',
|
|
242
|
+
detail: e.message,
|
|
137
243
|
},
|
|
138
244
|
],
|
|
139
245
|
})
|
|
140
246
|
);
|
|
141
247
|
}
|
|
142
|
-
|
|
143
|
-
if (req.method === 'POST' || niceUrl === '__record') {
|
|
144
|
-
const payload = await req.json();
|
|
145
|
-
const { url, headers, method, status, statusText, body, response } = payload;
|
|
146
|
-
const cacheKey = generateFilepath({
|
|
147
|
-
projectRoot,
|
|
148
|
-
testId,
|
|
149
|
-
url,
|
|
150
|
-
method,
|
|
151
|
-
body: body ? JSON.stringify(body) : null,
|
|
152
|
-
testRequestNumber,
|
|
153
|
-
});
|
|
154
|
-
// allow Content-Type to be overridden
|
|
155
|
-
headers['Content-Type'] = headers['Content-Type'] || 'application/vnd.api+json';
|
|
156
|
-
// We always compress and chunk the response
|
|
157
|
-
headers['Content-Encoding'] = 'br';
|
|
158
|
-
// we don't cache since tests will often reuse similar urls for different payload
|
|
159
|
-
headers['Cache-Control'] = 'no-store';
|
|
160
|
-
|
|
161
|
-
const cacheDir = generateFileDir({
|
|
162
|
-
projectRoot,
|
|
163
|
-
testId,
|
|
164
|
-
url,
|
|
165
|
-
method,
|
|
166
|
-
testRequestNumber,
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
fs.mkdirSync(cacheDir, { recursive: true });
|
|
170
|
-
fs.writeFileSync(
|
|
171
|
-
`${cacheKey}.meta.json`,
|
|
172
|
-
JSON.stringify({ url, status, statusText, headers, method, requestBody: body }, null, 2)
|
|
173
|
-
);
|
|
174
|
-
fs.writeFileSync(`${cacheKey}.body.br`, compress(JSON.stringify(response)));
|
|
175
|
-
context.status(204);
|
|
176
|
-
return context.body(null);
|
|
177
|
-
} else {
|
|
178
|
-
const body = await req.text();
|
|
179
|
-
const cacheKey = generateFilepath({
|
|
180
|
-
projectRoot,
|
|
181
|
-
testId,
|
|
182
|
-
url: niceUrl,
|
|
183
|
-
method: req.method,
|
|
184
|
-
body,
|
|
185
|
-
testRequestNumber,
|
|
186
|
-
});
|
|
187
|
-
return replayRequest(context, cacheKey);
|
|
188
|
-
}
|
|
189
248
|
};
|
|
190
249
|
|
|
191
250
|
return TestHandler;
|
|
@@ -196,7 +255,9 @@ function createTestHandler(projectRoot) {
|
|
|
196
255
|
*/
|
|
197
256
|
export function createServer(options) {
|
|
198
257
|
const app = new Hono();
|
|
199
|
-
|
|
258
|
+
if (DEBUG) {
|
|
259
|
+
app.use('*', logger());
|
|
260
|
+
}
|
|
200
261
|
app.use(
|
|
201
262
|
'*',
|
|
202
263
|
cors({
|
|
@@ -211,18 +272,112 @@ export function createServer(options) {
|
|
|
211
272
|
);
|
|
212
273
|
app.all('*', createTestHandler(options.projectRoot));
|
|
213
274
|
|
|
275
|
+
const { CERT, KEY } = getCertInfo();
|
|
276
|
+
|
|
214
277
|
serve({
|
|
215
278
|
fetch: app.fetch,
|
|
216
279
|
createServer: (_, requestListener) => {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
280
|
+
try {
|
|
281
|
+
return http2.createSecureServer(
|
|
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
|
+
}
|
|
224
292
|
},
|
|
225
293
|
port: options.port ?? DEFAULT_PORT,
|
|
226
294
|
hostname: 'localhost',
|
|
295
|
+
// bun uses TLS options
|
|
296
|
+
// tls: {
|
|
297
|
+
// key: Bun.file(KEY_PATH),
|
|
298
|
+
// cert: Bun.file(CERT_PATH),
|
|
299
|
+
// },
|
|
227
300
|
});
|
|
301
|
+
|
|
302
|
+
console.log(
|
|
303
|
+
`\tMock server running at ${chalk.magenta('https://localhost:') + chalk.yellow(options.port ?? DEFAULT_PORT)}`
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const servers = new Map();
|
|
308
|
+
|
|
309
|
+
export default {
|
|
310
|
+
async launchProgram(config = {}) {
|
|
311
|
+
const projectRoot = process.cwd();
|
|
312
|
+
const name = await import(path.join(projectRoot, 'package.json'), { with: { type: 'json' } }).then(
|
|
313
|
+
(pkg) => pkg.name
|
|
314
|
+
);
|
|
315
|
+
const options = { name, projectRoot, ...config };
|
|
316
|
+
console.log(
|
|
317
|
+
chalk.grey(
|
|
318
|
+
`\n\t@${chalk.greenBright('warp-drive')}/${chalk.magentaBright(
|
|
319
|
+
'holodeck'
|
|
320
|
+
)} 🌅\n\t=================================\n`
|
|
321
|
+
) +
|
|
322
|
+
chalk.grey(
|
|
323
|
+
`\n\tHolodeck Access Granted\n\t\tprogram: ${chalk.magenta(name)}\n\t\tsettings: ${chalk.green(JSON.stringify(config).split('\n').join(' '))}\n\t\tdirectory: ${chalk.cyan(projectRoot)}\n\t\tengine: ${chalk.cyan(
|
|
324
|
+
isBun ? 'bun@' + Bun.version : 'node'
|
|
325
|
+
)}`
|
|
326
|
+
)
|
|
327
|
+
);
|
|
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
|
+
}
|
|
343
|
+
|
|
344
|
+
if (servers.has(projectRoot)) {
|
|
345
|
+
throw new Error(`Holodeck is already running for project '${name}' at '${projectRoot}'`);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
servers.set(projectRoot, createServer(options));
|
|
349
|
+
},
|
|
350
|
+
async endProgram() {
|
|
351
|
+
console.log(chalk.grey(`\n\tEnding Subroutines (mode:${chalk.cyan(isBun ? 'bun' : 'node')})`));
|
|
352
|
+
const projectRoot = process.cwd();
|
|
353
|
+
|
|
354
|
+
if (!servers.has(projectRoot)) {
|
|
355
|
+
const name = await import(path.join(projectRoot, 'package.json'), { with: { type: 'json' } }).then(
|
|
356
|
+
(pkg) => pkg.name
|
|
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();
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
servers.get(projectRoot).close();
|
|
368
|
+
servers.delete(projectRoot);
|
|
369
|
+
},
|
|
370
|
+
};
|
|
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
|
+
}
|
|
228
381
|
}
|
|
382
|
+
|
|
383
|
+
main();
|
package/bin/cmd/_start.js
DELETED
package/bin/cmd/_stop.js
DELETED
package/bin/cmd/pm2.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
/* global Bun, globalThis */
|
|
3
|
-
const { process } = globalThis;
|
|
4
|
-
import pm2 from 'pm2';
|
|
5
|
-
import fs from 'fs';
|
|
6
|
-
|
|
7
|
-
export default async function pm2Delegate(cmd, _args) {
|
|
8
|
-
const pkg = JSON.parse(fs.readFileSync('./package.json'), 'utf8');
|
|
9
|
-
|
|
10
|
-
return new Promise((resolve, reject) => {
|
|
11
|
-
pm2.connect((err) => {
|
|
12
|
-
if (err) {
|
|
13
|
-
console.log('not able to connect to pm2');
|
|
14
|
-
console.error(err);
|
|
15
|
-
process.exit(2);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const options = {
|
|
19
|
-
script: './holodeck.mjs',
|
|
20
|
-
name: pkg.name + '::holodeck',
|
|
21
|
-
cwd: process.cwd(),
|
|
22
|
-
args: cmd === 'start' ? '-f' : '',
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
pm2[cmd](cmd === 'start' ? options : options.name, (err, apps) => {
|
|
26
|
-
pm2.disconnect(); // Disconnects from PM2
|
|
27
|
-
if (err) {
|
|
28
|
-
console.log(`not able to ${cmd} pm2 for ${options.name}`);
|
|
29
|
-
console.error(err);
|
|
30
|
-
reject(err);
|
|
31
|
-
} else {
|
|
32
|
-
console.log(`pm2 ${cmd} successful for ${options.name}`);
|
|
33
|
-
resolve();
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
}
|
package/bin/cmd/run.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
/* global Bun, globalThis */
|
|
3
|
-
const isBun = typeof Bun !== 'undefined';
|
|
4
|
-
const { process } = globalThis;
|
|
5
|
-
import { spawn } from './spawn.js';
|
|
6
|
-
import fs from 'fs';
|
|
7
|
-
|
|
8
|
-
export default async function run(args) {
|
|
9
|
-
const pkg = JSON.parse(fs.readFileSync('./package.json'), 'utf8');
|
|
10
|
-
const cmd = args[0];
|
|
11
|
-
const isPkgScript = pkg.scripts[cmd];
|
|
12
|
-
|
|
13
|
-
if (isBun) {
|
|
14
|
-
await spawn(['bun', 'run', 'holodeck:start-program']);
|
|
15
|
-
|
|
16
|
-
let exitCode = 0;
|
|
17
|
-
try {
|
|
18
|
-
await spawn(['bun', 'run', ...args]);
|
|
19
|
-
} catch (e) {
|
|
20
|
-
exitCode = e;
|
|
21
|
-
}
|
|
22
|
-
await spawn(['bun', 'run', 'holodeck:end-program']);
|
|
23
|
-
if (exitCode !== 0) {
|
|
24
|
-
process.exit(exitCode);
|
|
25
|
-
}
|
|
26
|
-
return;
|
|
27
|
-
} else {
|
|
28
|
-
await spawn(['pnpm', 'run', 'holodeck:start-program']);
|
|
29
|
-
|
|
30
|
-
let exitCode = 0;
|
|
31
|
-
try {
|
|
32
|
-
if (isPkgScript) {
|
|
33
|
-
const cmdArgs = pkg.scripts[cmd].split(' ');
|
|
34
|
-
if (args.length > 1) {
|
|
35
|
-
cmdArgs.push(...args.slice(1));
|
|
36
|
-
}
|
|
37
|
-
console.log({ cmdArgs });
|
|
38
|
-
await spawn(cmdArgs);
|
|
39
|
-
} else {
|
|
40
|
-
await spawn(['pnpm', 'exec', ...args]);
|
|
41
|
-
}
|
|
42
|
-
} catch (e) {
|
|
43
|
-
exitCode = e;
|
|
44
|
-
}
|
|
45
|
-
await spawn(['pnpm', 'run', 'holodeck:end-program']);
|
|
46
|
-
if (exitCode !== 0) {
|
|
47
|
-
process.exit(exitCode);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
package/bin/cmd/spawn.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
/* global Bun, globalThis */
|
|
3
|
-
const isBun = typeof Bun !== 'undefined';
|
|
4
|
-
|
|
5
|
-
export async function spawn(args, options) {
|
|
6
|
-
if (isBun) {
|
|
7
|
-
const proc = Bun.spawn(args, {
|
|
8
|
-
env: process.env,
|
|
9
|
-
cwd: process.cwd(),
|
|
10
|
-
stdout: 'inherit',
|
|
11
|
-
stderr: 'inherit',
|
|
12
|
-
});
|
|
13
|
-
await proc.exited;
|
|
14
|
-
if (proc.exitCode !== 0) {
|
|
15
|
-
throw proc.exitCode;
|
|
16
|
-
}
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const { spawn } = await import('node:child_process');
|
|
21
|
-
|
|
22
|
-
// eslint-disable-next-line no-inner-declarations
|
|
23
|
-
function pSpawn(cmd, args, opts) {
|
|
24
|
-
return new Promise((resolve, reject) => {
|
|
25
|
-
const proc = spawn(cmd, args, opts);
|
|
26
|
-
proc.on('exit', (code) => {
|
|
27
|
-
if (code === 0) {
|
|
28
|
-
resolve();
|
|
29
|
-
} else {
|
|
30
|
-
reject(code);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
await pSpawn(args.shift(), args, {
|
|
37
|
-
stdio: 'inherit',
|
|
38
|
-
shell: true,
|
|
39
|
-
});
|
|
40
|
-
}
|
package/bin/holodeck.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
#!/bin/sh -
|
|
2
|
-
':'; /*-
|
|
3
|
-
test1=$(bun --version 2>&1) && exec bun "$0" "$@"
|
|
4
|
-
test2=$(node --version 2>&1) && exec node "$0" "$@"
|
|
5
|
-
exec printf '%s\n' "$test1" "$test2" 1>&2
|
|
6
|
-
*/
|
|
7
|
-
/* eslint-disable no-console */
|
|
8
|
-
/* global Bun, globalThis */
|
|
9
|
-
|
|
10
|
-
import chalk from 'chalk';
|
|
11
|
-
import { spawn } from './cmd/spawn.js';
|
|
12
|
-
|
|
13
|
-
const isBun = typeof Bun !== 'undefined';
|
|
14
|
-
const { process } = globalThis;
|
|
15
|
-
|
|
16
|
-
const args = isBun ? Bun.argv.slice(2) : process.argv.slice(2);
|
|
17
|
-
const command = args.shift();
|
|
18
|
-
|
|
19
|
-
const BUN_SUPPORTS_PM2 = false;
|
|
20
|
-
const BUN_SUPPORTS_HTTP2 = false;
|
|
21
|
-
|
|
22
|
-
if (command === 'run') {
|
|
23
|
-
console.log(
|
|
24
|
-
chalk.grey(
|
|
25
|
-
`\n\t@${chalk.greenBright('warp-drive')}/${chalk.magentaBright(
|
|
26
|
-
'holodeck'
|
|
27
|
-
)} 🌅\n\t=================================}\n`
|
|
28
|
-
) +
|
|
29
|
-
chalk.grey(
|
|
30
|
-
`\n\tHolodeck Access Granted\n\t\tprogram: ${chalk.green(args.join(' '))}\n\t\tengine: ${chalk.cyan(
|
|
31
|
-
isBun ? 'bun@' + Bun.version : 'node'
|
|
32
|
-
)}`
|
|
33
|
-
)
|
|
34
|
-
);
|
|
35
|
-
const run = await import('./cmd/run.js');
|
|
36
|
-
await run.default(args);
|
|
37
|
-
} else if (command === 'start') {
|
|
38
|
-
console.log(chalk.grey(`\n\tStarting Subroutines (mode:${chalk.cyan(isBun ? 'bun' : 'node')})`));
|
|
39
|
-
|
|
40
|
-
if (!isBun || (BUN_SUPPORTS_HTTP2 && BUN_SUPPORTS_PM2)) {
|
|
41
|
-
const pm2 = await import('./cmd/pm2.js');
|
|
42
|
-
await pm2.default('start', args);
|
|
43
|
-
} else {
|
|
44
|
-
console.log(`Downgrading to node to run pm2 due lack of http/2 or pm2 support in Bun`);
|
|
45
|
-
const __dirname = import.meta.dir;
|
|
46
|
-
const programPath = __dirname + '/cmd/_start.js';
|
|
47
|
-
await spawn(['node', programPath, ...args]);
|
|
48
|
-
}
|
|
49
|
-
} else if (command === 'end') {
|
|
50
|
-
console.log(chalk.grey(`\n\tEnding Subroutines (mode:${chalk.cyan(isBun ? 'bun' : 'node')})`));
|
|
51
|
-
|
|
52
|
-
if (!isBun || (BUN_SUPPORTS_HTTP2 && BUN_SUPPORTS_PM2)) {
|
|
53
|
-
const pm2 = await import('./cmd/pm2.js');
|
|
54
|
-
await pm2.default('stop', args);
|
|
55
|
-
} else {
|
|
56
|
-
console.log(`Downgrading to node to run pm2 due lack of http/2 or pm2 support in Bun`);
|
|
57
|
-
const __dirname = import.meta.dir;
|
|
58
|
-
const programPath = __dirname + '/cmd/_stop.js';
|
|
59
|
-
await spawn(['node', programPath, ...args]);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
console.log(`\n\t${chalk.grey('The Computer has ended the program')}\n`);
|
|
63
|
-
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { Handler, NextFn, RequestContext, StructuredDataDocument } from '@ember-data/request';
|
|
2
|
-
import type { ScaffoldGenerator } from './mock';
|
|
3
|
-
export declare function setTestId(context: object, str: string | null): void;
|
|
4
|
-
export declare function setIsRecording(value: boolean): void;
|
|
5
|
-
export declare function getIsRecording(): boolean;
|
|
6
|
-
export declare class MockServerHandler implements Handler {
|
|
7
|
-
owner: object;
|
|
8
|
-
constructor(owner: object);
|
|
9
|
-
request<T>(context: RequestContext, next: NextFn<T>): Promise<StructuredDataDocument<T>>;
|
|
10
|
-
}
|
|
11
|
-
export declare function mock(owner: object, generate: ScaffoldGenerator, isRecording?: boolean): Promise<void>;
|
|
12
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAe,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAEhH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAIhD,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,QAS5D;AAGD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,QAE5C;AACD,wBAAgB,cAAc,YAE7B;AAED,qBAAa,iBAAkB,YAAW,OAAO;IACvC,KAAK,EAAE,MAAM,CAAC;gBACV,KAAK,EAAE,MAAM;IAGnB,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;CA6B/F;AAED,wBAAsB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,WAAW,CAAC,EAAE,OAAO,iBAgB3F"}
|
package/dist/mock.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
export interface Scaffold {
|
|
2
|
-
status: number;
|
|
3
|
-
statusText?: string;
|
|
4
|
-
headers: Record<string, string>;
|
|
5
|
-
body: Record<string, string> | string | null;
|
|
6
|
-
method: string;
|
|
7
|
-
url: string;
|
|
8
|
-
response: Record<string, unknown>;
|
|
9
|
-
}
|
|
10
|
-
export type ScaffoldGenerator = () => Scaffold;
|
|
11
|
-
export type ResponseGenerator = () => Record<string, unknown>;
|
|
12
|
-
/**
|
|
13
|
-
* Sets up Mocking for a GET request on the mock server
|
|
14
|
-
* for the supplied url.
|
|
15
|
-
*
|
|
16
|
-
* The response body is generated by the supplied response function.
|
|
17
|
-
*
|
|
18
|
-
* Available options:
|
|
19
|
-
* - status: the status code to return (default: 200)
|
|
20
|
-
* - headers: the headers to return (default: {})
|
|
21
|
-
* - body: the body to match against for the request (default: null)
|
|
22
|
-
* - RECORD: whether to record the request (default: false)
|
|
23
|
-
*
|
|
24
|
-
* @param url the url to mock, relative to the mock server host (e.g. `users/1`)
|
|
25
|
-
* @param response a function which generates the response to return
|
|
26
|
-
* @param options status, headers for the response, body to match against for the request, and whether to record the request
|
|
27
|
-
* @return
|
|
28
|
-
*/
|
|
29
|
-
export declare function GET(owner: object, url: string, response: ResponseGenerator, options?: Partial<Omit<Scaffold, 'response' | 'url' | 'method'>> & {
|
|
30
|
-
RECORD?: boolean;
|
|
31
|
-
}): Promise<void>;
|
|
32
|
-
export declare function POST(): void;
|
|
33
|
-
export declare function PUT(): void;
|
|
34
|
-
export declare function PATCH(): void;
|
|
35
|
-
export declare function DELETE(): void;
|
|
36
|
-
export declare function QUERY(): void;
|
|
37
|
-
//# sourceMappingURL=mock.d.ts.map
|
package/dist/mock.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../client/mock.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,QAAQ,CAAC;AAC/C,MAAM,MAAM,iBAAiB,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE9D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,GAAG,CACjB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,GAAG,KAAK,GAAG,QAAQ,CAAC,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACtF,OAAO,CAAC,IAAI,CAAC,CAcf;AACD,wBAAgB,IAAI,SAAK;AACzB,wBAAgB,GAAG,SAAK;AACxB,wBAAgB,KAAK,SAAK;AAC1B,wBAAgB,MAAM,SAAK;AAC3B,wBAAgB,KAAK,SAAK"}
|
package/server/CERT.md
DELETED
package/server/localhost-key.pem
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
-----BEGIN PRIVATE KEY-----
|
|
2
|
-
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCz8yulPBPYYZH+
|
|
3
|
-
M+kBVOCSj4EmN7Texxd/DXjOJTTpDI8aophZhfaXZSnTFhLxTEuAUVboU7yGR/JJ
|
|
4
|
-
JzL1nTVujR/gjJFrc4PVDeLzWMTJsTQcagdtku9suKC6M74/GlTI4yQC5p+IKRuv
|
|
5
|
-
ZisQhacyjpj5s4RoBR2n2aOscIncYtuKTJ570CIt9SFxEaV/WW3PlAG5LGEuqqJR
|
|
6
|
-
MwFTXz10IaKOVc/sxV2sYVS1tARydAx27IHKf23FilAu30nnc0ipGZNqFvHNvNed
|
|
7
|
-
Ggye+aaCh0WtX99HXs+JKPTfvV4sCDb7KIZq3WjRk7PAaSr6e999kvHuhZpXDUJL
|
|
8
|
-
Ynu0FYBZAgMBAAECggEBAJXcluWWAeT7ZO0x6AOe3yPPdTwRuoSpg4zg+FGdtNG9
|
|
9
|
-
DtScwooTwchVjJ5pzL69zkb/9oOncOLXuhRoG81m7l+yEfEcv+KfohPl67LDo6dg
|
|
10
|
-
90gOmT8M1m5R2DEZ9H9y+1cNqyjrTcLEkXTifkzVMegtz4JsmYFTeV4XJ3LtijJJ
|
|
11
|
-
j0b8X4d22DiNtQrx2zrcUF64UJSAxdRHW3nYlnjVxiXjUCO6TcrZvA+rqYNhX+QJ
|
|
12
|
-
lX9EwyVOdBtGsNMMECviFgrr4DPxkh77WptO6suIZ1X//UOAYEQp7rOsAf6sXRkp
|
|
13
|
-
seVp/TvhbjDk/XuRiv8zLaf0W4pFwt90XsCmkEzsH10CgYEA6beK8o2r5CA+mTJO
|
|
14
|
-
fb4MyqKhv6v5RXfG69IXf01gvARcXwjOMD5cV38UsI7YEw9RCXGRXzeH3MvW28aD
|
|
15
|
-
ADJYd+516vb0VwZwFYrUVKuBcjvvShPCk9HtOCqCEbRPBPJE7/mODHmL8u+61Rq/
|
|
16
|
-
l1n6GmYGLmJy2HaVDDnWi9jb0I8CgYEAxRtOKrkkdt36iUYlQ7wkWtDcN1gYVpuB
|
|
17
|
-
e2G/6BmDwIBTX/WoVlJrL9S3hFTjFc+0UJBpmmfFGFtp0tZFtjY7SaTj2whK4ZU7
|
|
18
|
-
VI90CUgExdsjf7yw+OeCgqdkiuRoFn39tL0h/pM4UcAKz9UB9yxvrfQRCXD3O6w2
|
|
19
|
-
TzbEv3VAxJcCgYBlnHvXeoqqEu7EUh/YAWG0U8K4/37PmgStEFlQ6oZNGCRE2SIz
|
|
20
|
-
zVj+XWzUWjZNCxKzZWHLoOv7rc/LG2JnGnxmIBG6RwXyNAVVCFfKPAp6bN5bOX4W
|
|
21
|
-
IGXfTnPgWKEmSGJ6ZuhAOjQDOgDjl86GcgMPqR202u6Nd/jTKO5DPNRMtwKBgHNu
|
|
22
|
-
JjzG6B/kp5A00CX2zKOSpSSUJsyxjQagnC5kos/dVvZfexHyemsse7y3qbVgSgzU
|
|
23
|
-
RcPy+W3mOvcKHRE0eUwLkJT5KkEpj/FZgW7eCk2EpClua4WYrsmtFihw0rQ5XJa4
|
|
24
|
-
HGxl8xmNCcfkyp3iHBUXVdLdoSwFElkZjedB14hJAoGAeeX+Rg4Y5a9/GNgxgsBU
|
|
25
|
-
o9MM/6qmjAJAb4iln9jHaEYZBd7EyogYuzqiKlASutIovGHj+P0RH3kvVlmVt1g/
|
|
26
|
-
45zmwVVrobCi5dqGQ1oPYvZpGCi85aYciTlfuH0mJqouXEkcO8kZQbc8ylR7WZS/
|
|
27
|
-
U9Mf1mB0yw8kupDasZ+uJ5c=
|
|
28
|
-
-----END PRIVATE KEY-----
|
package/server/localhost.pem
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
-----BEGIN CERTIFICATE-----
|
|
2
|
-
MIIEfzCCAuegAwIBAgIQWxpBRFaerCiZ6Gh6L9VAqjANBgkqhkiG9w0BAQsFADCB
|
|
3
|
-
qzEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMUAwPgYDVQQLDDdjdGhv
|
|
4
|
-
YnVybkBDaHJpcy1UaG9idXJuLUs1MFEzMEQ3NjEubG9jYWwgKENocmlzIFRob2J1
|
|
5
|
-
cm4pMUcwRQYDVQQDDD5ta2NlcnQgY3Rob2J1cm5AQ2hyaXMtVGhvYnVybi1LNTBR
|
|
6
|
-
MzBENzYxLmxvY2FsIChDaHJpcyBUaG9idXJuKTAeFw0yMzEwMDkwOTE1MDZaFw0y
|
|
7
|
-
NjAxMDkxMDE1MDZaMGsxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0
|
|
8
|
-
aWZpY2F0ZTFAMD4GA1UECww3Y3Rob2J1cm5AQ2hyaXMtVGhvYnVybi1LNTBRMzBE
|
|
9
|
-
NzYxLmxvY2FsIChDaHJpcyBUaG9idXJuKTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
|
10
|
-
ADCCAQoCggEBALPzK6U8E9hhkf4z6QFU4JKPgSY3tN7HF38NeM4lNOkMjxqimFmF
|
|
11
|
-
9pdlKdMWEvFMS4BRVuhTvIZH8kknMvWdNW6NH+CMkWtzg9UN4vNYxMmxNBxqB22S
|
|
12
|
-
72y4oLozvj8aVMjjJALmn4gpG69mKxCFpzKOmPmzhGgFHafZo6xwidxi24pMnnvQ
|
|
13
|
-
Ii31IXERpX9Zbc+UAbksYS6qolEzAVNfPXQhoo5Vz+zFXaxhVLW0BHJ0DHbsgcp/
|
|
14
|
-
bcWKUC7fSedzSKkZk2oW8c28150aDJ75poKHRa1f30dez4ko9N+9XiwINvsohmrd
|
|
15
|
-
aNGTs8BpKvp7332S8e6FmlcNQktie7QVgFkCAwEAAaNeMFwwDgYDVR0PAQH/BAQD
|
|
16
|
-
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQYMBaAFPvg1+9/Kqq1KAXH
|
|
17
|
-
lhQsaJhmqOd1MBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOC
|
|
18
|
-
AYEAx2seTuq9JRa2sdio17IJO+9ns35zl8TymSIV9U6YGgiW3m/bsfmZic6Kzn9R
|
|
19
|
-
+lj6rBAGIefrQEmfF3RGL3n7FOW0gwSXSeKmG1r7TBXYrkKF9i41C/VRUZ8iKZfl
|
|
20
|
-
ja5P9BFXWUeMQDLv6p3X/ynZMsw1HOIy2r5OJoxLjfN4NvnAnQxbMtVSsCHMesj1
|
|
21
|
-
U44mT09CeGTLTsbqFNZ7TX/Gm1I4ic7z8PGFpWDgliNARNH5Yf6Quh/ryY+jXc4F
|
|
22
|
-
yoC3JwhmRfi4vNCP6wmUzpLmS+psJkCjU1SnUmzjX219F22Y5vFUJrWhQq+qs/yx
|
|
23
|
-
t9PPlf+dt2MfoPsNIE096E9z8yBWcyggCQvyH0kv+a7HKOOHORtd8SuCNGtTEl4Q
|
|
24
|
-
Q8eheMGoIa4dsiMyJeWUOtxdInPkZNBxjQLkC2wCqSuN5+3iTuFfniRSoamqSVYo
|
|
25
|
-
/TtgXWM5tTUOHHisy+u9HR6fZpSlvplYIjVcmK5bObIlRx7MCOFiyXjJf7Xjv1ji
|
|
26
|
-
6JQn
|
|
27
|
-
-----END CERTIFICATE-----
|