@danceiny/gotry 0.2.0-rc.31 → 0.2.0-rc.32
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 +2 -2
- package/README.zh-CN.md +2 -2
- package/bin/gotry-bootstrap.js +63 -53
- package/bin/gotry-hbcli-release.d.ts +3 -0
- package/bin/gotry-hbcli-release.js +4 -0
- package/client/client.js +66 -21
- package/dist/capabilities/doctor.js +7 -8
- package/dist/capabilities/effect.js +45 -12
- package/dist/capabilities/flyai-config.js +12 -10
- package/dist/capabilities/flyai.js +87 -56
- package/dist/capabilities/hbcli-config.js +156 -0
- package/dist/capabilities/hbcli.js +29 -2
- package/dist/capabilities/resilience.js +6 -6
- package/dist/capabilities/session/adapters/ctrip-flight.js +42 -7
- package/dist/capabilities/session/adapters/ctrip-hotel.js +52 -3
- package/dist/capabilities/session/ctrip-city.js +186 -0
- package/dist/capabilities/session/extension-bridge.js +8 -1
- package/dist/capabilities/session/gui-flight.js +737 -0
- package/dist/capabilities/session/gui-hotel.js +413 -0
- package/dist/capabilities/session-search.js +98 -11
- package/dist/scripts/bootstrap-tests.js +23 -6
- package/dist/scripts/ctrip-city-tests.js +80 -0
- package/dist/scripts/effect-tests.js +602 -504
- package/dist/scripts/extension-tests.js +14 -8
- package/dist/scripts/flight-malformed-tests.js +1 -1
- package/dist/scripts/flyai-setup-tests.js +19 -4
- package/dist/scripts/flyai-tests.js +768 -653
- package/dist/scripts/gotry-web-api-tests.js +5 -0
- package/dist/scripts/gotry-web-client-tests.js +20 -1
- package/dist/scripts/gui-flight-live.js +27 -0
- package/dist/scripts/hbcli-tests.js +1 -1
- package/dist/scripts/hbcli-upgrade-tests.js +107 -0
- package/dist/scripts/hbcli-web-setup-tests.js +114 -0
- package/dist/scripts/hotel-date-gate-tests.js +1 -1
- package/dist/scripts/hotel-result-tests.js +169 -0
- package/dist/scripts/issue-271-liveness-tests.js +1 -1
- package/dist/scripts/session-tests.js +177 -6
- package/dist/src/gotry-web-api.js +64 -2
- package/dist/src/index.js +40 -18
- package/extension/manifest.json +2 -2
- package/package.json +2 -1
- package/ts/capabilities/flyai-config.ts +12 -10
- package/ts/capabilities/flyai.ts +91 -50
- package/ts/capabilities/hbcli-config.ts +128 -0
- package/ts/capabilities/hbcli.ts +30 -3
- package/ts/capabilities/session/adapters/ctrip-flight.ts +43 -7
- package/ts/capabilities/session/adapters/ctrip-hotel.ts +51 -4
- package/ts/capabilities/session/ctrip-city.ts +158 -0
- package/ts/capabilities/session/extension-bridge.ts +9 -2
- package/ts/capabilities/session/gui-flight.ts +792 -0
- package/ts/capabilities/session/gui-hotel.ts +451 -0
- package/ts/capabilities/session-search.ts +115 -15
- package/ts/src/gotry-web-api.ts +51 -2
- package/ts/src/index.ts +41 -19
|
@@ -699,7 +699,7 @@ async function main() {
|
|
|
699
699
|
__resetRateLimiterForTest();
|
|
700
700
|
const cookiePoll = claimOnce(lane.port, null);
|
|
701
701
|
await waitForParkedCount(lane.port, 1);
|
|
702
|
-
const search = sessionFlightSearch({ from: '上海', to: '丽江', date: '2026-12-01', timeoutMs: 3_000 });
|
|
702
|
+
const search = sessionFlightSearch({ from: '上海', to: '丽江', fromCityCode: 'SHA', toCityCode: 'LJG', date: '2026-12-01', timeoutMs: 3_000 });
|
|
703
703
|
const cookieClaim = await cookiePoll;
|
|
704
704
|
assert.equal(cookieClaim.job?.kind, 'cookie-names');
|
|
705
705
|
// 商店版先候在桥上;它不得接走另一 Origin 已验证登录态后的 search。
|
|
@@ -751,7 +751,7 @@ async function main() {
|
|
|
751
751
|
__resetRateLimiterForTest();
|
|
752
752
|
const cookiePoll = claimOnce(lane.port, null, undefined, ['ctrip-flight'], EXTENSION_ORIGIN, clientA);
|
|
753
753
|
await waitForParkedCount(lane.port, 1);
|
|
754
|
-
const search = sessionFlightSearch({ from: '上海', to: '丽江', date: '2026-12-01', timeoutMs: 3_000, auditPath: shapeAudit });
|
|
754
|
+
const search = sessionFlightSearch({ from: '上海', to: '丽江', fromCityCode: 'SHA', toCityCode: 'LJG', date: '2026-12-01', timeoutMs: 3_000, auditPath: shapeAudit });
|
|
755
755
|
const cookieClaim = await cookiePoll;
|
|
756
756
|
assert.equal(cookieClaim.job?.kind, 'cookie-names');
|
|
757
757
|
otherPoll = claimOnce(lane.port, (job) => {
|
|
@@ -820,7 +820,7 @@ async function main() {
|
|
|
820
820
|
})();
|
|
821
821
|
try {
|
|
822
822
|
__resetRateLimiterForTest();
|
|
823
|
-
const result = await sessionFlightSearch({ from: '上海', to: '丽江', date: '2026-12-01', timeoutMs: 3_000 });
|
|
823
|
+
const result = await sessionFlightSearch({ from: '上海', to: '丽江', fromCityCode: 'SHA', toCityCode: 'LJG', date: '2026-12-01', timeoutMs: 3_000 });
|
|
824
824
|
assert.equal(result.verdict, 'error');
|
|
825
825
|
assert.equal(result.transportShape, 'sniff_timeout');
|
|
826
826
|
assert.match(result.error ?? '', /嗅探超时|未收到.*回包/);
|
|
@@ -859,7 +859,7 @@ async function main() {
|
|
|
859
859
|
})();
|
|
860
860
|
try {
|
|
861
861
|
__resetRateLimiterForTest();
|
|
862
|
-
const result = await sessionFlightSearch({ from: '上海', to: '丽江', date: '2026-12-01', timeoutMs: 3_000 });
|
|
862
|
+
const result = await sessionFlightSearch({ from: '上海', to: '丽江', fromCityCode: 'SHA', toCityCode: 'LJG', date: '2026-12-01', timeoutMs: 3_000 });
|
|
863
863
|
assert.equal(result.verdict, 'error');
|
|
864
864
|
assert.equal(result.transportShape, failedKind === 'search' ? 'search_job_unavailable' : 'precheck_unavailable');
|
|
865
865
|
assert.doesNotMatch(JSON.stringify(result), /PRIVATE_ROUTE_DATE_COOKIE_VALUE/);
|
|
@@ -882,12 +882,18 @@ async function main() {
|
|
|
882
882
|
const blockers = [];
|
|
883
883
|
try {
|
|
884
884
|
for (const port of [8791, 8792, 8793, 8794, 8795]) {
|
|
885
|
-
const s = createServer()
|
|
886
|
-
await new Promise((
|
|
887
|
-
|
|
885
|
+
const s = createServer();
|
|
886
|
+
const owned = await new Promise((resolve, reject) => {
|
|
887
|
+
s.once('listening', () => resolve(true));
|
|
888
|
+
s.once('error', (error) => error.code === 'EADDRINUSE' ? resolve(false) : reject(error));
|
|
889
|
+
s.listen(port, '127.0.0.1');
|
|
890
|
+
});
|
|
891
|
+
// An active user bridge already occupies this port; never stop it.
|
|
892
|
+
if (owned)
|
|
893
|
+
blockers.push({ close: () => new Promise((r) => s.close(() => r())) });
|
|
888
894
|
}
|
|
889
895
|
await __resetSessionBridgeForTest();
|
|
890
|
-
const r = await sessionFlightSearch({ from: '上海', to: '丽江', date: '2026-12-01' });
|
|
896
|
+
const r = await sessionFlightSearch({ from: '上海', to: '丽江', fromCityCode: 'SHA', toCityCode: 'LJG', date: '2026-12-01' });
|
|
891
897
|
assert.equal(r.verdict, 'error', `端口池全占应 error(环境故障),实 ${r.verdict}:${r.error}`);
|
|
892
898
|
assert.ok(r.error?.includes('端口池'), '错误面必须点明端口池环境问题');
|
|
893
899
|
assert.ok(!r.error?.includes('一次性安装'), 'error 路径不应诱导用户去装扩展');
|
|
@@ -90,7 +90,7 @@ async function main() {
|
|
|
90
90
|
const expectVerdict = async (label, body, title, expected, extra) => {
|
|
91
91
|
__resetRateLimiterForTest();
|
|
92
92
|
testCase = { body, title };
|
|
93
|
-
const r = await sessionFlightSearch({ from: '上海', to: '丽江', date: '2026-12-01', timeoutMs: 5_000 });
|
|
93
|
+
const r = await sessionFlightSearch({ from: '上海', to: '丽江', fromCityCode: 'SHA', toCityCode: 'LJG', date: '2026-12-01', timeoutMs: 5_000 });
|
|
94
94
|
await check(label, () => {
|
|
95
95
|
assert.equal(r.verdict, expected, `verdict 期望 ${expected},实 ${r.verdict} (${r.error ?? ''})`);
|
|
96
96
|
if (extra)
|
|
@@ -39,7 +39,7 @@ chmodSync(fakeVerifier, 0o700);
|
|
|
39
39
|
// that the npm package exposes for `gotry setup ...` dispatch.
|
|
40
40
|
const packageFixture = join(sandbox, 'package-shaped');
|
|
41
41
|
mkdirSync(join(packageFixture, 'bin'), { recursive: true });
|
|
42
|
-
for (const file of ['gotry-inner.js', 'gotry-bootstrap.js', 'gotry-flyai-verification.js', 'gotry-extension-status.js', 'gotry-process-liveness.js', 'gotry-runtime-resolution.js']) {
|
|
42
|
+
for (const file of ['gotry-inner.js', 'gotry-bootstrap.js', 'gotry-hbcli-release.js', 'gotry-flyai-verification.js', 'gotry-extension-status.js', 'gotry-process-liveness.js', 'gotry-runtime-resolution.js']) {
|
|
43
43
|
copyFileSync(join(repoRoot, 'bin', file), join(packageFixture, 'bin', file));
|
|
44
44
|
}
|
|
45
45
|
writeFileSync(join(packageFixture, 'package.json'), JSON.stringify({ type: 'module', version: 'test' }) + '\n');
|
|
@@ -133,7 +133,7 @@ assert.ok(symlinkRun.stdout.includes('配置目录不安全'));
|
|
|
133
133
|
assert.ok(!existsSync(join(symlinkTarget, 'config.json')), 'symlink target must not receive credentials');
|
|
134
134
|
console.log('1c. symlink .flyai rejected without following target OK');
|
|
135
135
|
// The TypeScript config writer shares the same compatibility rule; the
|
|
136
|
-
// verification
|
|
136
|
+
// verification receipts use the same safe directory migration.
|
|
137
137
|
const tsConfigHome = mkdtempSync(join(sandbox, 'ts-config-'));
|
|
138
138
|
writeOfficialFlyaiDir(tsConfigHome, 'device-ts');
|
|
139
139
|
const tsSave = saveFlyaiKey('sk-ts-config-key-1234', { homeDir: tsConfigHome, env: {} });
|
|
@@ -203,15 +203,30 @@ assert.notEqual(verifyFail.status, 0);
|
|
|
203
203
|
assert.deepEqual(readFileSync(configPath(verifyFailHome)), verifyBefore);
|
|
204
204
|
assert.ok(verifyFail.stdout.includes('配置未改动'));
|
|
205
205
|
console.log('4. bad JSON + verifier failure preserve old config bytes/key OK');
|
|
206
|
+
// Existing doctor/runtime state must be secured without losing its contents.
|
|
207
|
+
const legacyHome = mkdtempSync(join(sandbox, 'legacy-receipt-'));
|
|
208
|
+
mkdirSync(join(legacyHome, '.gotry'), { mode: 0o755 });
|
|
209
|
+
chmodSync(join(legacyHome, '.gotry'), 0o755);
|
|
210
|
+
writeFileSync(join(legacyHome, '.gotry', 'doctor-report.md'), 'existing report');
|
|
211
|
+
const legacyRun = runPackageEntry(legacyHome, ['setup', 'flyai', '--stdin'], `${key}\n`);
|
|
212
|
+
assert.equal(legacyRun.status, 0, legacyRun.stdout + legacyRun.stderr);
|
|
213
|
+
assert.equal(mode(join(legacyHome, '.gotry')), 0o700);
|
|
214
|
+
assert.equal(mode(receiptPath(legacyHome)), 0o600);
|
|
215
|
+
assert.equal(readFileSync(join(legacyHome, '.gotry', 'doctor-report.md'), 'utf8'), 'existing report');
|
|
216
|
+
console.log('5a. existing 0755 state directory secured without losing contents OK');
|
|
206
217
|
// 5. receipt write failure is visible and rolls back the newly attempted key.
|
|
207
218
|
const receiptFailHome = mkdtempSync(join(sandbox, 'receipt-fail-'));
|
|
208
219
|
writeConfig(receiptFailHome, { FLYAI_API_KEY: oldKey, keep: 'yes' });
|
|
209
|
-
|
|
210
|
-
|
|
220
|
+
const receiptTarget = join(receiptFailHome, 'outside-state');
|
|
221
|
+
mkdirSync(receiptTarget, { mode: 0o755 });
|
|
222
|
+
chmodSync(receiptTarget, 0o755);
|
|
223
|
+
symlinkSync(receiptTarget, join(receiptFailHome, '.gotry'), 'dir');
|
|
211
224
|
const receiptFail = run(receiptFailHome, ['setup', 'flyai', '--stdin'], `${key}\n`);
|
|
212
225
|
assert.notEqual(receiptFail.status, 0);
|
|
213
226
|
assert.ok(receiptFail.stdout.includes('验证回执写入失败'));
|
|
214
227
|
assert.equal(JSON.parse(readFileSync(configPath(receiptFailHome), 'utf8')).FLYAI_API_KEY, oldKey);
|
|
228
|
+
assert.equal(mode(receiptTarget), 0o755);
|
|
229
|
+
assert.ok(!existsSync(join(receiptTarget, 'flyai-verification.json')));
|
|
215
230
|
console.log('5. receipt write failure reports non-success and preserves old key OK');
|
|
216
231
|
// The verifier may echo its input credentials. Public diagnostics must not.
|
|
217
232
|
for (const failure of ['leak-403', 'leak-exit']) {
|