@cursorpool-dev/cli 0.5.6
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/bin/cursor-pool.mjs +9 -0
- package/bin/cursor-pool.ts +169 -0
- package/node_modules/@cursor-pool/extension/dist/extension.js +2910 -0
- package/node_modules/@cursor-pool/extension/package.json +64 -0
- package/node_modules/@cursor-pool/extension/resources/cursor-pool.svg +6 -0
- package/node_modules/@cursor-pool/extension/src/api.ts +545 -0
- package/node_modules/@cursor-pool/extension/src/extension.ts +104 -0
- package/node_modules/@cursor-pool/extension/src/index.ts +1 -0
- package/node_modules/@cursor-pool/extension/src/panel.ts +569 -0
- package/node_modules/@cursor-pool/extension/src/runtime.ts +22 -0
- package/node_modules/@cursor-pool/extension/test/panel.test.ts +1785 -0
- package/node_modules/@cursor-pool/patcher/package.json +17 -0
- package/node_modules/@cursor-pool/patcher/src/alwaysLocalMarker.ts +86 -0
- package/node_modules/@cursor-pool/patcher/src/hash.ts +7 -0
- package/node_modules/@cursor-pool/patcher/src/index.ts +55 -0
- package/node_modules/@cursor-pool/patcher/src/marker.ts +159 -0
- package/node_modules/@cursor-pool/patcher/src/patchCursorAgentExec.ts +154 -0
- package/node_modules/@cursor-pool/patcher/src/patchCursorAlwaysLocal.ts +142 -0
- package/node_modules/@cursor-pool/patcher/src/patchCursorWorkbenchAuthGate.ts +140 -0
- package/node_modules/@cursor-pool/patcher/src/restoreCursorAgentExec.ts +52 -0
- package/node_modules/@cursor-pool/patcher/src/restoreCursorAlwaysLocal.ts +52 -0
- package/node_modules/@cursor-pool/patcher/src/restoreCursorWorkbenchAuthGate.ts +70 -0
- package/node_modules/@cursor-pool/patcher/src/workbenchAuthGateMarker.ts +243 -0
- package/node_modules/@cursor-pool/patcher/test/patchCursorAgentExec.test.ts +630 -0
- package/node_modules/@cursor-pool/patcher/test/patchCursorAlwaysLocal.test.ts +144 -0
- package/node_modules/@cursor-pool/patcher/test/patchCursorWorkbench.test.ts +770 -0
- package/node_modules/@cursor-pool/patcher/test/restoreCursorAgentExec.test.ts +139 -0
- package/node_modules/@cursor-pool/service/package.json +17 -0
- package/node_modules/@cursor-pool/service/src/canary.ts +61 -0
- package/node_modules/@cursor-pool/service/src/diagnostics.ts +385 -0
- package/node_modules/@cursor-pool/service/src/entry.ts +161 -0
- package/node_modules/@cursor-pool/service/src/health.ts +10 -0
- package/node_modules/@cursor-pool/service/src/index.ts +29 -0
- package/node_modules/@cursor-pool/service/src/metadata.ts +22 -0
- package/node_modules/@cursor-pool/service/src/platformSession.ts +1178 -0
- package/node_modules/@cursor-pool/service/src/requestCheck.ts +81 -0
- package/node_modules/@cursor-pool/service/src/requestGate.ts +100 -0
- package/node_modules/@cursor-pool/service/src/requestGateway.ts +441 -0
- package/node_modules/@cursor-pool/service/src/runtime.ts +48 -0
- package/node_modules/@cursor-pool/service/src/server.ts +939 -0
- package/node_modules/@cursor-pool/service/src/takeover.ts +111 -0
- package/node_modules/@cursor-pool/service/test/canary.test.ts +140 -0
- package/node_modules/@cursor-pool/service/test/diagnostics.test.ts +506 -0
- package/node_modules/@cursor-pool/service/test/metadata.test.ts +63 -0
- package/node_modules/@cursor-pool/service/test/platformSession.test.ts +2428 -0
- package/node_modules/@cursor-pool/service/test/requestCheck.test.ts +152 -0
- package/node_modules/@cursor-pool/service/test/requestGate.test.ts +207 -0
- package/node_modules/@cursor-pool/service/test/requestGateway.test.ts +466 -0
- package/node_modules/@cursor-pool/service/test/runtime.test.ts +47 -0
- package/node_modules/@cursor-pool/service/test/server.test.ts +2570 -0
- package/node_modules/@cursor-pool/shared/package.json +17 -0
- package/node_modules/@cursor-pool/shared/src/clientConfig.ts +49 -0
- package/node_modules/@cursor-pool/shared/src/index.ts +14 -0
- package/node_modules/@cursor-pool/shared/src/manifest.ts +36 -0
- package/node_modules/@cursor-pool/shared/src/metadata.ts +19 -0
- package/node_modules/@cursor-pool/shared/src/paths.ts +5 -0
- package/node_modules/@cursor-pool/shared/src/runtime.ts +3 -0
- package/node_modules/@cursor-pool/shared/test/index.test.ts +56 -0
- package/node_modules/@cursor-pool/shared/test/manifest.test.ts +65 -0
- package/node_modules/@cursor-pool/shared/test/metadata.test.ts +25 -0
- package/node_modules/@cursor-pool/shared/test/runtime.test.ts +8 -0
- package/package.json +28 -0
- package/src/adHocResign.ts +65 -0
- package/src/autostart.ts +240 -0
- package/src/compat.ts +282 -0
- package/src/confirm.ts +76 -0
- package/src/cursor.ts +94 -0
- package/src/diagnostics.ts +558 -0
- package/src/environment.ts +18 -0
- package/src/extensionBundle.ts +111 -0
- package/src/extensionLink.ts +168 -0
- package/src/index.ts +23 -0
- package/src/install.ts +614 -0
- package/src/installRecord.ts +105 -0
- package/src/launch.ts +182 -0
- package/src/patchSet.ts +182 -0
- package/src/platform.ts +132 -0
- package/src/repair.ts +383 -0
- package/src/restore.ts +153 -0
- package/src/serviceCommands.ts +79 -0
- package/src/serviceProcess.ts +188 -0
- package/src/status.ts +241 -0
- package/src/target.ts +37 -0
- package/src/trial.ts +133 -0
- package/src/uninstall.ts +213 -0
- package/test/autostart.test.ts +151 -0
- package/test/compat.test.ts +192 -0
- package/test/confirm.test.ts +114 -0
- package/test/cursor-pool-bin.test.ts +658 -0
- package/test/cursor.test.ts +20 -0
- package/test/diagnostics.test.ts +709 -0
- package/test/e2e-install.test.ts +773 -0
- package/test/extensionBundle.test.ts +161 -0
- package/test/extensionLink.test.ts +209 -0
- package/test/install.test.ts +862 -0
- package/test/installRecord.test.ts +107 -0
- package/test/launch.test.ts +138 -0
- package/test/platform.test.ts +226 -0
- package/test/repair.test.ts +575 -0
- package/test/restore.test.ts +211 -0
- package/test/serviceCommands.test.ts +135 -0
- package/test/serviceProcess.test.ts +280 -0
- package/test/status.test.ts +615 -0
- package/test/target.test.ts +49 -0
- package/test/trial.test.ts +146 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
import {
|
|
4
|
+
createRequestCheckStore,
|
|
5
|
+
sanitizeAgentRequestCheck,
|
|
6
|
+
type AgentRequestCheck,
|
|
7
|
+
} from '../src/requestCheck';
|
|
8
|
+
|
|
9
|
+
const allowedDecision = {
|
|
10
|
+
state: 'allowed' as const,
|
|
11
|
+
productId: 'prod_basic',
|
|
12
|
+
modeStartedAt: '2026-05-31T00:05:00.000Z',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
test('sanitizeAgentRequestCheck keeps only safe metadata fields', () => {
|
|
16
|
+
const check = sanitizeAgentRequestCheck(
|
|
17
|
+
{
|
|
18
|
+
requestId: 'req-1',
|
|
19
|
+
requestType: 'other',
|
|
20
|
+
source: 'cursor-agent-exec',
|
|
21
|
+
model: 'gpt-4.1-mini',
|
|
22
|
+
prompt: 'discard this',
|
|
23
|
+
messages: [{ role: 'user', content: 'discard this too' }],
|
|
24
|
+
headers: { authorization: 'Bearer secret' },
|
|
25
|
+
cookie: 'secret',
|
|
26
|
+
authorization: 'Bearer secret',
|
|
27
|
+
apiKey: 'secret',
|
|
28
|
+
cursorAuthToken: 'secret',
|
|
29
|
+
providerSecret: 'secret',
|
|
30
|
+
body: { hidden: true },
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
runtimeId: 'runtime-1',
|
|
34
|
+
decision: allowedDecision,
|
|
35
|
+
now: () => '2026-05-31T00:10:00.000Z',
|
|
36
|
+
requestId: () => 'generated-request-id',
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
assert.deepEqual(check, {
|
|
41
|
+
requestId: 'req-1',
|
|
42
|
+
requestType: 'agent',
|
|
43
|
+
source: 'cursor-agent-exec',
|
|
44
|
+
model: 'gpt-4.1-mini',
|
|
45
|
+
receivedAt: '2026-05-31T00:10:00.000Z',
|
|
46
|
+
runtimeId: 'runtime-1',
|
|
47
|
+
decision: allowedDecision,
|
|
48
|
+
route: { state: 'missing' },
|
|
49
|
+
});
|
|
50
|
+
assert.equal(Object.hasOwn(check, 'prompt'), false);
|
|
51
|
+
assert.equal(Object.hasOwn(check, 'messages'), false);
|
|
52
|
+
assert.equal(Object.hasOwn(check, 'headers'), false);
|
|
53
|
+
assert.equal(Object.hasOwn(check, 'cookie'), false);
|
|
54
|
+
assert.equal(Object.hasOwn(check, 'authorization'), false);
|
|
55
|
+
assert.equal(Object.hasOwn(check, 'apiKey'), false);
|
|
56
|
+
assert.equal(Object.hasOwn(check, 'cursorAuthToken'), false);
|
|
57
|
+
assert.equal(Object.hasOwn(check, 'providerSecret'), false);
|
|
58
|
+
assert.equal(Object.hasOwn(check, 'body'), false);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('sanitizeAgentRequestCheck normalizes unsafe request metadata', () => {
|
|
62
|
+
const check = sanitizeAgentRequestCheck(
|
|
63
|
+
{
|
|
64
|
+
requestId: '',
|
|
65
|
+
source: 'extension',
|
|
66
|
+
model: 'sk-live-secret-token',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
runtimeId: 'runtime-1',
|
|
70
|
+
decision: { state: 'blocked', reason: 'logged-out' },
|
|
71
|
+
now: () => '2026-05-31T00:10:00.000Z',
|
|
72
|
+
requestId: () => 'generated-request-id',
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
assert.deepEqual(check, {
|
|
77
|
+
requestId: 'generated-request-id',
|
|
78
|
+
requestType: 'agent',
|
|
79
|
+
source: 'manual-check',
|
|
80
|
+
model: 'unknown',
|
|
81
|
+
receivedAt: '2026-05-31T00:10:00.000Z',
|
|
82
|
+
runtimeId: 'runtime-1',
|
|
83
|
+
decision: { state: 'blocked', reason: 'logged-out' },
|
|
84
|
+
route: { state: 'missing' },
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('sanitizeAgentRequestCheck keeps safe route state without route token', () => {
|
|
89
|
+
const check = sanitizeAgentRequestCheck(
|
|
90
|
+
{
|
|
91
|
+
requestId: 'req-route',
|
|
92
|
+
source: 'manual-check',
|
|
93
|
+
model: 'gpt-test',
|
|
94
|
+
routeToken: 'rt_secret_value',
|
|
95
|
+
token: 'discard this',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
runtimeId: 'runtime-1',
|
|
99
|
+
decision: allowedDecision,
|
|
100
|
+
route: { state: 'ready', expiresAt: '2026-05-31T00:10:00.000Z' },
|
|
101
|
+
now: () => '2026-05-31T00:05:00.000Z',
|
|
102
|
+
},
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
assert.deepEqual(check.route, { state: 'ready', expiresAt: '2026-05-31T00:10:00.000Z' });
|
|
106
|
+
assert.equal(Object.hasOwn(check, 'routeToken'), false);
|
|
107
|
+
assert.equal(Object.hasOwn(check, 'token'), false);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('sanitizeAgentRequestCheck accepts manual-check source and short safe model tokens', () => {
|
|
111
|
+
const check = sanitizeAgentRequestCheck(
|
|
112
|
+
{
|
|
113
|
+
requestId: 'req-2',
|
|
114
|
+
source: 'manual-check',
|
|
115
|
+
model: 'claude-3.7-sonnet_test',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
runtimeId: 'runtime-1',
|
|
119
|
+
decision: { state: 'blocked', reason: 'mode-inactive' },
|
|
120
|
+
now: () => '2026-05-31T00:10:00.000Z',
|
|
121
|
+
},
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
assert.equal(check.requestId, 'req-2');
|
|
125
|
+
assert.equal(check.source, 'manual-check');
|
|
126
|
+
assert.equal(check.model, 'claude-3.7-sonnet_test');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('createRequestCheckStore records and returns only the latest check', () => {
|
|
130
|
+
const first: AgentRequestCheck = {
|
|
131
|
+
requestId: 'req-1',
|
|
132
|
+
requestType: 'agent',
|
|
133
|
+
source: 'manual-check',
|
|
134
|
+
model: 'unknown',
|
|
135
|
+
receivedAt: '2026-05-31T00:10:00.000Z',
|
|
136
|
+
runtimeId: 'runtime-1',
|
|
137
|
+
decision: { state: 'blocked', reason: 'logged-out' },
|
|
138
|
+
route: { state: 'missing' },
|
|
139
|
+
};
|
|
140
|
+
const second: AgentRequestCheck = {
|
|
141
|
+
...first,
|
|
142
|
+
requestId: 'req-2',
|
|
143
|
+
decision: allowedDecision,
|
|
144
|
+
};
|
|
145
|
+
const store = createRequestCheckStore();
|
|
146
|
+
|
|
147
|
+
assert.equal(store.latest(), null);
|
|
148
|
+
assert.deepEqual(store.record(first), first);
|
|
149
|
+
assert.deepEqual(store.latest(), first);
|
|
150
|
+
assert.deepEqual(store.record(second), second);
|
|
151
|
+
assert.deepEqual(store.latest(), second);
|
|
152
|
+
});
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import test from 'node:test';
|
|
6
|
+
import { evaluateRequestGate, evaluateRouteState } from '../src/requestGate';
|
|
7
|
+
import type { PlatformSession } from '../src/platformSession';
|
|
8
|
+
|
|
9
|
+
const baseSession: PlatformSession = {
|
|
10
|
+
apiBaseUrl: 'http://127.0.0.1:9',
|
|
11
|
+
deviceToken: 'device-token',
|
|
12
|
+
createdAt: '2026-05-31T00:00:00.000Z',
|
|
13
|
+
user: { id: 'usr_1', email: 'dev@example.com' },
|
|
14
|
+
device: { id: 'dev_1', status: 'active', lastHeartbeatAt: '2026-05-31T00:00:00.000Z' },
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
async function withSessionFile(run: (sessionFile: string) => Promise<void>) {
|
|
18
|
+
const tempDir = await mkdtemp(join(tmpdir(), 'cursor-pool-request-gate-'));
|
|
19
|
+
const sessionFile = join(tempDir, 'session.json');
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
await run(sessionFile);
|
|
23
|
+
} finally {
|
|
24
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function writeSession(sessionFile: string, session: Record<string, unknown>) {
|
|
29
|
+
await writeFile(sessionFile, `${JSON.stringify(session, null, 2)}\n`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
test('evaluateRequestGate blocks logged-out requests when there is no session', async () => {
|
|
33
|
+
await withSessionFile(async (sessionFile) => {
|
|
34
|
+
assert.deepEqual(await evaluateRequestGate({ sessionFile }), {
|
|
35
|
+
state: 'blocked',
|
|
36
|
+
reason: 'logged-out',
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('evaluateRequestGate blocks invalid requests for corrupt JSON and incomplete sessions', async () => {
|
|
42
|
+
await withSessionFile(async (sessionFile) => {
|
|
43
|
+
await writeFile(sessionFile, '{not-json');
|
|
44
|
+
|
|
45
|
+
assert.deepEqual(await evaluateRequestGate({ sessionFile }), {
|
|
46
|
+
state: 'blocked',
|
|
47
|
+
reason: 'invalid-session',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await writeSession(sessionFile, { ...baseSession, deviceToken: undefined });
|
|
51
|
+
|
|
52
|
+
assert.deepEqual(await evaluateRequestGate({ sessionFile }), {
|
|
53
|
+
state: 'blocked',
|
|
54
|
+
reason: 'invalid-session',
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('evaluateRequestGate returns fresh invalid-session decisions', async () => {
|
|
60
|
+
await withSessionFile(async (sessionFile) => {
|
|
61
|
+
await writeFile(sessionFile, '{not-json');
|
|
62
|
+
|
|
63
|
+
const first = await evaluateRequestGate({ sessionFile });
|
|
64
|
+
(first as { reason: string }).reason = 'mode-inactive';
|
|
65
|
+
|
|
66
|
+
assert.deepEqual(await evaluateRequestGate({ sessionFile }), {
|
|
67
|
+
state: 'blocked',
|
|
68
|
+
reason: 'invalid-session',
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('evaluateRequestGate blocks requests when device is inactive', async () => {
|
|
74
|
+
await withSessionFile(async (sessionFile) => {
|
|
75
|
+
await writeSession(sessionFile, {
|
|
76
|
+
...baseSession,
|
|
77
|
+
device: { ...baseSession.device, status: 'removed' },
|
|
78
|
+
platformMode: 'active',
|
|
79
|
+
activeProductId: 'prod_basic',
|
|
80
|
+
platformModeStartedAt: '2026-05-31T00:01:00.000Z',
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
assert.deepEqual(await evaluateRequestGate({ sessionFile }), {
|
|
84
|
+
state: 'blocked',
|
|
85
|
+
reason: 'device-inactive',
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('evaluateRequestGate blocks requests when mode is inactive', async () => {
|
|
91
|
+
await withSessionFile(async (sessionFile) => {
|
|
92
|
+
await writeSession(sessionFile, {
|
|
93
|
+
...baseSession,
|
|
94
|
+
platformMode: 'inactive',
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
assert.deepEqual(await evaluateRequestGate({ sessionFile }), {
|
|
98
|
+
state: 'blocked',
|
|
99
|
+
reason: 'mode-inactive',
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('evaluateRequestGate includes release fields when inactive mode has release metadata', async () => {
|
|
105
|
+
await withSessionFile(async (sessionFile) => {
|
|
106
|
+
await writeSession(sessionFile, {
|
|
107
|
+
...baseSession,
|
|
108
|
+
platformMode: 'inactive',
|
|
109
|
+
lastModeReleaseReason: 'insufficient-credits',
|
|
110
|
+
lastModeReleasedAt: '2026-05-31T00:02:00.000Z',
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
assert.deepEqual(await evaluateRequestGate({ sessionFile }), {
|
|
114
|
+
state: 'blocked',
|
|
115
|
+
reason: 'mode-released',
|
|
116
|
+
releaseReason: 'insufficient-credits',
|
|
117
|
+
releasedAt: '2026-05-31T00:02:00.000Z',
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('evaluateRequestGate allows active mode requests with product and start metadata', async () => {
|
|
123
|
+
await withSessionFile(async (sessionFile) => {
|
|
124
|
+
await writeSession(sessionFile, {
|
|
125
|
+
...baseSession,
|
|
126
|
+
platformMode: 'active',
|
|
127
|
+
activeProductId: 'prod_basic',
|
|
128
|
+
platformModeStartedAt: '2026-05-31T00:01:00.000Z',
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
assert.deepEqual(await evaluateRequestGate({ sessionFile }), {
|
|
132
|
+
state: 'allowed',
|
|
133
|
+
productId: 'prod_basic',
|
|
134
|
+
modeStartedAt: '2026-05-31T00:01:00.000Z',
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('evaluateRequestGate blocks active mode requests with empty string active fields', async () => {
|
|
140
|
+
await withSessionFile(async (sessionFile) => {
|
|
141
|
+
await writeSession(sessionFile, {
|
|
142
|
+
...baseSession,
|
|
143
|
+
platformMode: 'active',
|
|
144
|
+
activeProductId: '',
|
|
145
|
+
platformModeStartedAt: '',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
assert.deepEqual(await evaluateRequestGate({ sessionFile }), {
|
|
149
|
+
state: 'blocked',
|
|
150
|
+
reason: 'mode-inactive',
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('evaluateRouteState reports ready route without exposing token', async () => {
|
|
156
|
+
await withSessionFile(async (sessionFile) => {
|
|
157
|
+
await writeSession(sessionFile, {
|
|
158
|
+
...baseSession,
|
|
159
|
+
platformMode: 'active',
|
|
160
|
+
activeProductId: 'prod_basic',
|
|
161
|
+
platformModeStartedAt: '2026-05-31T00:05:00.000Z',
|
|
162
|
+
routeToken: {
|
|
163
|
+
token: 'rt_secret_value',
|
|
164
|
+
expiresAt: '2026-05-31T00:10:00.000Z',
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
assert.deepEqual(
|
|
169
|
+
await evaluateRouteState({
|
|
170
|
+
sessionFile,
|
|
171
|
+
now: () => '2026-05-31T00:06:00.000Z',
|
|
172
|
+
}),
|
|
173
|
+
{ state: 'ready', expiresAt: '2026-05-31T00:10:00.000Z' },
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('evaluateRouteState reports missing and expired route states', async () => {
|
|
179
|
+
await withSessionFile(async (sessionFile) => {
|
|
180
|
+
const expiredSessionFile = join(sessionFile, '../expired-route.json');
|
|
181
|
+
await writeSession(sessionFile, {
|
|
182
|
+
...baseSession,
|
|
183
|
+
platformMode: 'active',
|
|
184
|
+
activeProductId: 'prod_basic',
|
|
185
|
+
platformModeStartedAt: '2026-05-31T00:05:00.000Z',
|
|
186
|
+
});
|
|
187
|
+
await writeSession(expiredSessionFile, {
|
|
188
|
+
...baseSession,
|
|
189
|
+
platformMode: 'active',
|
|
190
|
+
activeProductId: 'prod_basic',
|
|
191
|
+
platformModeStartedAt: '2026-05-31T00:05:00.000Z',
|
|
192
|
+
routeToken: {
|
|
193
|
+
token: 'rt_secret_value',
|
|
194
|
+
expiresAt: '2026-05-31T00:04:00.000Z',
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
assert.deepEqual(await evaluateRouteState({ sessionFile }), { state: 'missing' });
|
|
199
|
+
assert.deepEqual(
|
|
200
|
+
await evaluateRouteState({
|
|
201
|
+
sessionFile: expiredSessionFile,
|
|
202
|
+
now: () => '2026-05-31T00:06:00.000Z',
|
|
203
|
+
}),
|
|
204
|
+
{ state: 'expired', expiresAt: '2026-05-31T00:04:00.000Z' },
|
|
205
|
+
);
|
|
206
|
+
});
|
|
207
|
+
});
|