@curless/hotel-storefront 0.37.1 → 0.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend.d.ts +43 -0
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js.map +1 -1
- package/dist/card.generated.d.ts +1 -1
- package/dist/card.generated.js +2 -2
- package/dist/card.generated.js.map +1 -1
- package/dist/config.d.ts +16 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -1
- package/dist/huazhu/backend.d.ts +7 -0
- package/dist/huazhu/backend.d.ts.map +1 -1
- package/dist/huazhu/backend.js +306 -7
- package/dist/huazhu/backend.js.map +1 -1
- package/dist/huazhu/bookings.d.ts +9 -0
- package/dist/huazhu/bookings.d.ts.map +1 -1
- package/dist/huazhu/bookings.js.map +1 -1
- package/dist/huazhu/fake.d.ts.map +1 -1
- package/dist/huazhu/fake.js +5 -0
- package/dist/huazhu/fake.js.map +1 -1
- package/dist/huazhu/make.d.ts.map +1 -1
- package/dist/huazhu/make.js +28 -1
- package/dist/huazhu/make.js.map +1 -1
- package/dist/huazhu/wire.d.ts +17 -0
- package/dist/huazhu/wire.d.ts.map +1 -1
- package/dist/huazhu/wire.js.map +1 -1
- package/dist/legal.d.ts.map +1 -1
- package/dist/legal.js +23 -4
- package/dist/legal.js.map +1 -1
- package/dist/lib.d.ts +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js.map +1 -1
- package/dist/payments/fake-unionpay.d.ts +22 -0
- package/dist/payments/fake-unionpay.d.ts.map +1 -0
- package/dist/payments/fake-unionpay.js +89 -0
- package/dist/payments/fake-unionpay.js.map +1 -0
- package/dist/payments/unionpay.d.ts +125 -0
- package/dist/payments/unionpay.d.ts.map +1 -0
- package/dist/payments/unionpay.js +192 -0
- package/dist/payments/unionpay.js.map +1 -0
- package/dist/server.d.ts +2 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +12 -3
- package/dist/server.js.map +1 -1
- package/dist/tools.d.ts +24 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +124 -2
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +14 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
package/dist/lib.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export { buildTools, withheldTools } from './tools.js';
|
|
|
20
20
|
export { INSTRUCTS, listingProblems } from './listing.js';
|
|
21
21
|
export { resolveBrand, DEMO_NOTE } from './vocab.js';
|
|
22
22
|
export { FULL_CAPABILITIES, MAX_PAGE } from './backend.js';
|
|
23
|
-
export type { BackendCapabilities, HotelBackend, PaymentReturn, SupplierInfo } from './backend.js';
|
|
23
|
+
export type { BackendCapabilities, HotelBackend, PaymentReturn, SupplierInfo, UnionPayStep, } from './backend.js';
|
|
24
24
|
export type { ApiSource, HotelConfig, ToolNames } from './config.js';
|
|
25
25
|
export { HUAZHU_CAPABILITIES, createHuazhuHotels } from './huazhu/backend.js';
|
|
26
26
|
export { checkHuazhu } from './huazhu/check.js';
|
package/dist/lib.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EACL,UAAU,EACV,WAAW,EACX,UAAU,EACV,cAAc,EACd,QAAQ,EACR,UAAU,EACV,SAAS,EACT,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC3D,YAAY,
|
|
1
|
+
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EACL,UAAU,EACV,WAAW,EACX,UAAU,EACV,cAAc,EACd,QAAQ,EACR,UAAU,EACV,SAAS,EACT,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC3D,YAAY,EACV,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,YAAY,GACb,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9E,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC5D,YAAY,EACV,OAAO,EACP,aAAa,EACb,UAAU,EACV,KAAK,EACL,KAAK,EACL,WAAW,EACX,WAAW,EACX,QAAQ,EACR,MAAM,EACN,KAAK,EACL,WAAW,EACX,WAAW,EACX,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,QAAQ,GACT,MAAM,YAAY,CAAC"}
|
package/dist/lib.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EACL,UAAU,EACV,WAAW,EACX,UAAU,EACV,cAAc,EACd,QAAQ,EACR,UAAU,EACV,SAAS,EACT,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,4EAA4E;AAC5E,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACvD,8EAA8E;AAC9E,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EACL,UAAU,EACV,WAAW,EACX,UAAU,EACV,cAAc,EACd,QAAQ,EACR,UAAU,EACV,SAAS,EACT,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,4EAA4E;AAC5E,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACvD,8EAA8E;AAC9E,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAS3D,qEAAqE;AACrE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { OneTimeCard, UnionPayHandoff, UnionPayState } from './unionpay.js';
|
|
2
|
+
type Session = {
|
|
3
|
+
state: UnionPayState;
|
|
4
|
+
card?: OneTimeCard;
|
|
5
|
+
taken: number;
|
|
6
|
+
input: Parameters<UnionPayHandoff['open']>[0];
|
|
7
|
+
};
|
|
8
|
+
/** Stripe's published UnionPay test card number - a test value, never a real card. */
|
|
9
|
+
export declare const TEST_ONE_TIME_CARD: OneTimeCard;
|
|
10
|
+
export declare const createFakeUnionPay: () => {
|
|
11
|
+
handoff: UnionPayHandoff;
|
|
12
|
+
calls: string[];
|
|
13
|
+
sessions: Map<string, Session>;
|
|
14
|
+
/** The gateway or UnionPay not answering. */
|
|
15
|
+
down: boolean;
|
|
16
|
+
/** The guest finished UnionPay's page for binding a card. */
|
|
17
|
+
bind(email: string, lastFour?: string): void;
|
|
18
|
+
/** The guest confirmed on UnionPay's page, and UnionPay issued the one-time card. */
|
|
19
|
+
confirm(id: string, card?: OneTimeCard): void;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=fake-unionpay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-unionpay.d.ts","sourceRoot":"","sources":["../../src/payments/fake-unionpay.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGjF,KAAK,OAAO,GAAG;IACb,KAAK,EAAE,aAAa,CAAC;IACrB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/C,CAAC;AAEF,sFAAsF;AACtF,eAAO,MAAM,kBAAkB,EAAE,WAKhC,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;IAuD3B,6CAA6C;UACjC,OAAO;IAGnB,6DAA6D;gBACjD,MAAM;IAKlB,qFAAqF;gBACzE,MAAM,SAAQ,WAAW;CAOxC,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// UnionPay's APOP, in memory - what `UnionPayHandoff` stands for - so paying a
|
|
2
|
+
// stay with a UnionPay one-time card can be run through in a test with no
|
|
3
|
+
// gateway, no UnionPay and no card. It keeps the rules that matter: a card is
|
|
4
|
+
// bound only when the guest finishes UnionPay's page, a confirmation is the
|
|
5
|
+
// guest's to make, and the one-time card is handed over once.
|
|
6
|
+
import { UnionPayError } from './unionpay.js';
|
|
7
|
+
/** Stripe's published UnionPay test card number - a test value, never a real card. */
|
|
8
|
+
export const TEST_ONE_TIME_CARD = {
|
|
9
|
+
number: '6200000000000005',
|
|
10
|
+
expMonth: '12',
|
|
11
|
+
expYear: '2030',
|
|
12
|
+
securityCode: '123',
|
|
13
|
+
};
|
|
14
|
+
export const createFakeUnionPay = () => {
|
|
15
|
+
const cards = new Map();
|
|
16
|
+
const sessions = new Map();
|
|
17
|
+
const calls = [];
|
|
18
|
+
const state = { down: false };
|
|
19
|
+
let seq = 0;
|
|
20
|
+
const k = (email) => email.trim().toLowerCase();
|
|
21
|
+
const reachable = () => {
|
|
22
|
+
if (state.down)
|
|
23
|
+
throw new UnionPayError('the gateway did not answer (fake: down)');
|
|
24
|
+
};
|
|
25
|
+
const handoff = {
|
|
26
|
+
async cardsOf(email) {
|
|
27
|
+
calls.push('cards');
|
|
28
|
+
reachable();
|
|
29
|
+
return [...(cards.get(k(email)) ?? [])];
|
|
30
|
+
},
|
|
31
|
+
async enroll(email) {
|
|
32
|
+
calls.push('enroll');
|
|
33
|
+
reachable();
|
|
34
|
+
return { url: `https://unionpay.test/enroll/${encodeURIComponent(k(email))}/${++seq}` };
|
|
35
|
+
},
|
|
36
|
+
async open(o) {
|
|
37
|
+
calls.push('open');
|
|
38
|
+
reachable();
|
|
39
|
+
if (!(cards.get(k(o.email)) ?? []).some((c) => c.id === o.cardId))
|
|
40
|
+
throw new UnionPayError('Card not found or does not belong to agent', 404);
|
|
41
|
+
const id = `pi_up_${++seq}`;
|
|
42
|
+
sessions.set(id, { state: 'open', taken: 0, input: o });
|
|
43
|
+
return { sessionId: id, url: `https://unionpay.test/confirm/${id}` };
|
|
44
|
+
},
|
|
45
|
+
async state(id) {
|
|
46
|
+
calls.push('state');
|
|
47
|
+
reachable();
|
|
48
|
+
return sessions.get(id)?.state ?? 'closed';
|
|
49
|
+
},
|
|
50
|
+
async card(id) {
|
|
51
|
+
calls.push('card');
|
|
52
|
+
reachable();
|
|
53
|
+
const s = sessions.get(id);
|
|
54
|
+
if (!s || s.state !== 'issued')
|
|
55
|
+
return undefined;
|
|
56
|
+
s.taken += 1;
|
|
57
|
+
// Once: the gateway forgets it after handing it over.
|
|
58
|
+
return s.taken === 1 ? s.card : undefined;
|
|
59
|
+
},
|
|
60
|
+
async close(id) {
|
|
61
|
+
calls.push('close');
|
|
62
|
+
return sessions.get(id)?.state ?? 'closed';
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
handoff,
|
|
67
|
+
calls,
|
|
68
|
+
sessions,
|
|
69
|
+
/** The gateway or UnionPay not answering. */
|
|
70
|
+
set down(v) {
|
|
71
|
+
state.down = v;
|
|
72
|
+
},
|
|
73
|
+
/** The guest finished UnionPay's page for binding a card. */
|
|
74
|
+
bind(email, lastFour = '0005') {
|
|
75
|
+
const list = cards.get(k(email)) ?? [];
|
|
76
|
+
list.push({ id: `uaagcard_${++seq}`, lastFour });
|
|
77
|
+
cards.set(k(email), list);
|
|
78
|
+
},
|
|
79
|
+
/** The guest confirmed on UnionPay's page, and UnionPay issued the one-time card. */
|
|
80
|
+
confirm(id, card = TEST_ONE_TIME_CARD) {
|
|
81
|
+
const s = sessions.get(id);
|
|
82
|
+
if (!s)
|
|
83
|
+
throw new Error(`no UnionPay page ${id}`);
|
|
84
|
+
s.state = 'issued';
|
|
85
|
+
s.card = card;
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=fake-unionpay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-unionpay.js","sourceRoot":"","sources":["../../src/payments/fake-unionpay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/** A one-time UnionPay card, as UnionPay issued it for one order. */
|
|
2
|
+
export type OneTimeCard = {
|
|
3
|
+
/** The card number - a UnionPay token in a card number's shape. */
|
|
4
|
+
number: string;
|
|
5
|
+
/** Two digits. */
|
|
6
|
+
expMonth: string;
|
|
7
|
+
/** Four digits. */
|
|
8
|
+
expYear: string;
|
|
9
|
+
/**
|
|
10
|
+
* The one-time security code, when UnionPay sent one. Huazhu's booking has
|
|
11
|
+
* nowhere to put it (2026-10-15) - kept here only so a hotel system that
|
|
12
|
+
* takes one can be given it.
|
|
13
|
+
*/
|
|
14
|
+
securityCode?: string;
|
|
15
|
+
};
|
|
16
|
+
/** Where a UnionPay confirmation stands. */
|
|
17
|
+
export type UnionPayState =
|
|
18
|
+
/** UnionPay's page is waiting for the cardholder. */
|
|
19
|
+
'open'
|
|
20
|
+
/** The cardholder confirmed and UnionPay issued the one-time card. */
|
|
21
|
+
| 'issued'
|
|
22
|
+
/** Closed or lapsed without a card being issued: nothing can come of it. */
|
|
23
|
+
| 'closed';
|
|
24
|
+
export type OpenedUnionPay = {
|
|
25
|
+
/** Ours to follow it by - not a secret, and never a card. */
|
|
26
|
+
sessionId: string;
|
|
27
|
+
/** UnionPay's own page, where the guest confirms (and adds a card first, if they have none). */
|
|
28
|
+
url: string;
|
|
29
|
+
};
|
|
30
|
+
export declare class UnionPayError extends Error {
|
|
31
|
+
readonly status?: number | undefined;
|
|
32
|
+
constructor(message: string, status?: number | undefined);
|
|
33
|
+
}
|
|
34
|
+
export interface UnionPayHandoff {
|
|
35
|
+
/** The guest's cards UnionPay has bound for them - active ones only. */
|
|
36
|
+
cardsOf(email: string): Promise<{
|
|
37
|
+
id: string;
|
|
38
|
+
lastFour: string;
|
|
39
|
+
}[]>;
|
|
40
|
+
/** UnionPay's page for binding a card. The card exists once UnionPay says so, not when this answers. */
|
|
41
|
+
enroll(email: string): Promise<{
|
|
42
|
+
url: string;
|
|
43
|
+
}>;
|
|
44
|
+
/** For one stay: UnionPay's page, for the total the guest was shown. */
|
|
45
|
+
open(o: {
|
|
46
|
+
/** The booking's own key with the hotel - Huazhu's `distributorResId`. */
|
|
47
|
+
ref: string;
|
|
48
|
+
code?: string;
|
|
49
|
+
title: string;
|
|
50
|
+
/** What UnionPay's page calls the stay - ASCII only, UnionPay's rule. */
|
|
51
|
+
label?: string;
|
|
52
|
+
amountMinor: number;
|
|
53
|
+
currency: string;
|
|
54
|
+
/** The guest's, who UnionPay files their cards under. */
|
|
55
|
+
email: string;
|
|
56
|
+
name?: string;
|
|
57
|
+
/** One of `cardsOf`'s. */
|
|
58
|
+
cardId: string;
|
|
59
|
+
}): Promise<OpenedUnionPay>;
|
|
60
|
+
state(sessionId: string): Promise<UnionPayState>;
|
|
61
|
+
/**
|
|
62
|
+
* The one-time card UnionPay issued, once it has - undefined before, or when
|
|
63
|
+
* it cannot be read. ⚠️ The caller hands it on and drops it.
|
|
64
|
+
*/
|
|
65
|
+
card(sessionId: string): Promise<OneTimeCard | undefined>;
|
|
66
|
+
/** Stops a confirmation nobody finished; one already issued answers `issued`. */
|
|
67
|
+
close(sessionId: string): Promise<UnionPayState>;
|
|
68
|
+
}
|
|
69
|
+
/** The last four digits - all of a one-time card that may ever be said or logged. */
|
|
70
|
+
export declare const lastFour: (c: OneTimeCard) => string;
|
|
71
|
+
/** `MMyy`, as Huazhu's `paymentCard.expireDate` takes it. */
|
|
72
|
+
export declare const expiryMMyy: (c: OneTimeCard) => string;
|
|
73
|
+
export type GatewayUnionPayOptions = {
|
|
74
|
+
/** The agentbank gateway, e.g. https://mcp.curless.ai. */
|
|
75
|
+
baseUrl: string;
|
|
76
|
+
/** The Curless merchant the stays are sold as - a test-mode one. */
|
|
77
|
+
merchantId: string;
|
|
78
|
+
/** Its key (`merchant:write`): opens the payment, binds and lists members' cards, takes the one-time card. */
|
|
79
|
+
merchantKey: string;
|
|
80
|
+
/** An agent key (`agent:execute`) in the same organisation: registers the order with UnionPay. */
|
|
81
|
+
agentKey: string;
|
|
82
|
+
/** On UnionPay's page as whose order it is - ASCII only, UnionPay's rule. */
|
|
83
|
+
merchantName: string;
|
|
84
|
+
merchantUrl: string;
|
|
85
|
+
fetch?: typeof fetch;
|
|
86
|
+
timeoutMs?: number;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* The guest, as UnionPay files their cards: a merchant member keyed by their
|
|
90
|
+
* email (robin, 2026-10-15: no Huazhu member sign-in yet - the email until
|
|
91
|
+
* there is one). Hashed, so the gateway holds no address it does not need.
|
|
92
|
+
*/
|
|
93
|
+
export declare const memberRefOf: (email: string) => string;
|
|
94
|
+
export declare class GatewayUnionPay implements UnionPayHandoff {
|
|
95
|
+
private readonly opts;
|
|
96
|
+
private readonly fetch;
|
|
97
|
+
private readonly base;
|
|
98
|
+
constructor(opts: GatewayUnionPayOptions);
|
|
99
|
+
private call;
|
|
100
|
+
/** The guest's cards UnionPay has bound - active ones only. */
|
|
101
|
+
cardsOf(email: string): Promise<{
|
|
102
|
+
id: string;
|
|
103
|
+
lastFour: string;
|
|
104
|
+
}[]>;
|
|
105
|
+
/** UnionPay's page for binding a card. Bound only once UnionPay says so - never by this answer. */
|
|
106
|
+
enroll(email: string): Promise<{
|
|
107
|
+
url: string;
|
|
108
|
+
}>;
|
|
109
|
+
open(o: Parameters<UnionPayHandoff['open']>[0]): Promise<OpenedUnionPay>;
|
|
110
|
+
state(sessionId: string): Promise<UnionPayState>;
|
|
111
|
+
/**
|
|
112
|
+
* The one-time card, from the gateway - which gives it once and then forgets
|
|
113
|
+
* it. ⚠️ THE GATEWAY'S SIDE IS NOT BUILT YET (总线程 asked to route it to the
|
|
114
|
+
* gateway, 2026-10-15): the path is the one proposed in
|
|
115
|
+
* docs/huazhu-unionpay-apop.md.
|
|
116
|
+
*/
|
|
117
|
+
card(sessionId: string): Promise<OneTimeCard | undefined>;
|
|
118
|
+
/**
|
|
119
|
+
* A payment handed to UnionPay cannot be cancelled at the gateway - and need
|
|
120
|
+
* not be: nothing is charged unless its card is handed on, which a lapsed
|
|
121
|
+
* booking never does. Says where it stands.
|
|
122
|
+
*/
|
|
123
|
+
close(sessionId: string): Promise<UnionPayState>;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=unionpay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unionpay.d.ts","sourceRoot":"","sources":["../../src/payments/unionpay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// Paying in advance with a UnionPay card, the APOP way (robin, 2026-10-15:
|
|
2
|
+
// "OPN 走stripe, 信用卡走银联,两个都接上" - "我们要把一次性卡号给华住的,
|
|
3
|
+
// 我们,银联,华住"): the guest confirms on UnionPay's own page, UnionPay
|
|
4
|
+
// issues a one-time card for this order, and that card goes to the hotel's
|
|
5
|
+
// system, which charges it (Huazhu's CCPN). The money never passes through
|
|
6
|
+
// here - nor does the guest's card number, which is only ever typed on
|
|
7
|
+
// UnionPay's page.
|
|
8
|
+
//
|
|
9
|
+
// ⚠️ THE ONE-TIME CARD IS CARD DATA. It is a UnionPay-BIN card number, its
|
|
10
|
+
// expiry and a one-time security code, good for this order once (see
|
|
11
|
+
// docs/unionpay-uaag.md). It is read once, handed to the hotel's system in the
|
|
12
|
+
// same breath, and forgotten: never written to disk, never in a log (its last
|
|
13
|
+
// four digits at most), never in an answer or a payment's metadata.
|
|
14
|
+
//
|
|
15
|
+
// The gateway (UnionPay's UAAG behind it) is one implementation; a test's
|
|
16
|
+
// fake is the other.
|
|
17
|
+
import { createHash } from 'node:crypto';
|
|
18
|
+
import { checkoutState, startUaagCheckoutForLines } from '@curless/agentbank-protocols/uaag';
|
|
19
|
+
export class UnionPayError extends Error {
|
|
20
|
+
status;
|
|
21
|
+
constructor(message, status) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.status = status;
|
|
24
|
+
this.name = 'UnionPayError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** The last four digits - all of a one-time card that may ever be said or logged. */
|
|
28
|
+
export const lastFour = (c) => c.number.slice(-4);
|
|
29
|
+
/** `MMyy`, as Huazhu's `paymentCard.expireDate` takes it. */
|
|
30
|
+
export const expiryMMyy = (c) => `${c.expMonth.padStart(2, '0').slice(-2)}${c.expYear.slice(-2)}`;
|
|
31
|
+
/**
|
|
32
|
+
* The guest, as UnionPay files their cards: a merchant member keyed by their
|
|
33
|
+
* email (robin, 2026-10-15: no Huazhu member sign-in yet - the email until
|
|
34
|
+
* there is one). Hashed, so the gateway holds no address it does not need.
|
|
35
|
+
*/
|
|
36
|
+
export const memberRefOf = (email) => `hz-${createHash('sha256').update(email.trim().toLowerCase()).digest('hex').slice(0, 40)}`;
|
|
37
|
+
/** UnionPay shows ASCII only - anything else is dropped by the gateway anyway. */
|
|
38
|
+
const ascii = (s, fallback) => {
|
|
39
|
+
const t = s
|
|
40
|
+
.normalize('NFKD')
|
|
41
|
+
.replace(/[^\x20-\x7E]/g, '')
|
|
42
|
+
.replace(/\s+/g, ' ')
|
|
43
|
+
.trim();
|
|
44
|
+
return (t || fallback).slice(0, 120);
|
|
45
|
+
};
|
|
46
|
+
export class GatewayUnionPay {
|
|
47
|
+
opts;
|
|
48
|
+
fetch;
|
|
49
|
+
base;
|
|
50
|
+
constructor(opts) {
|
|
51
|
+
this.opts = opts;
|
|
52
|
+
this.fetch = opts.fetch ?? globalThis.fetch;
|
|
53
|
+
this.base = opts.baseUrl.replace(/\/$/, '');
|
|
54
|
+
}
|
|
55
|
+
async call(method, path, body) {
|
|
56
|
+
let res;
|
|
57
|
+
try {
|
|
58
|
+
res = await this.fetch(`${this.base}${path}`, {
|
|
59
|
+
method,
|
|
60
|
+
headers: {
|
|
61
|
+
authorization: `Bearer ${this.opts.merchantKey}`,
|
|
62
|
+
...(body !== undefined ? { 'content-type': 'application/json' } : {}),
|
|
63
|
+
},
|
|
64
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
65
|
+
signal: AbortSignal.timeout(this.opts.timeoutMs ?? 15_000),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
throw new UnionPayError(`the gateway did not answer (${err.message})`);
|
|
70
|
+
}
|
|
71
|
+
const text = await res.text();
|
|
72
|
+
if (!res.ok) {
|
|
73
|
+
// Its own message, never the request - and never a card: a key rides in
|
|
74
|
+
// a header, and a one-time card only ever in an answer we read once.
|
|
75
|
+
let said = text.slice(0, 300).replace(/\d{12,19}/g, '****');
|
|
76
|
+
try {
|
|
77
|
+
const j = JSON.parse(text);
|
|
78
|
+
said = (j.error?.message ?? said).replace(/\d{12,19}/g, '****');
|
|
79
|
+
}
|
|
80
|
+
catch { }
|
|
81
|
+
throw new UnionPayError(`the gateway answered ${res.status}: ${said}`, res.status);
|
|
82
|
+
}
|
|
83
|
+
return (text ? JSON.parse(text) : {});
|
|
84
|
+
}
|
|
85
|
+
/** The guest's cards UnionPay has bound - active ones only. */
|
|
86
|
+
async cardsOf(email) {
|
|
87
|
+
const r = await this.call('GET', `/v1/merchant-wallet/cards?memberRef=${encodeURIComponent(memberRefOf(email))}`);
|
|
88
|
+
return (r.cards ?? []).map((c) => ({ id: c.id, lastFour: c.panLastFour ?? '' }));
|
|
89
|
+
}
|
|
90
|
+
/** UnionPay's page for binding a card. Bound only once UnionPay says so - never by this answer. */
|
|
91
|
+
async enroll(email) {
|
|
92
|
+
const r = await this.call('POST', '/v1/merchant-wallet/cards', {
|
|
93
|
+
memberRef: memberRefOf(email),
|
|
94
|
+
});
|
|
95
|
+
if (!r.enrollUrl)
|
|
96
|
+
throw new UnionPayError('UnionPay gave no page to bind a card on');
|
|
97
|
+
return { url: r.enrollUrl };
|
|
98
|
+
}
|
|
99
|
+
async open(o) {
|
|
100
|
+
if (!o.cardId)
|
|
101
|
+
throw new UnionPayError('no UnionPay card to pay with - bind one first');
|
|
102
|
+
// The payment UnionPay's confirmation hangs on: priced by us as the
|
|
103
|
+
// merchant, at the total the guest was shown. It is never captured here -
|
|
104
|
+
// the hotel charges the one-time card (docs/huazhu-unionpay-apop.md).
|
|
105
|
+
const created = await this.call('POST', `/acp/${encodeURIComponent(this.opts.merchantId)}/checkout_sessions`, {
|
|
106
|
+
items: [{ id: o.ref, quantity: 1, unitPrice: o.amountMinor, name: o.title }],
|
|
107
|
+
currency: o.currency,
|
|
108
|
+
display: { merchantName: this.opts.merchantName, merchantUrl: this.opts.merchantUrl },
|
|
109
|
+
});
|
|
110
|
+
if (!created.id)
|
|
111
|
+
throw new UnionPayError('the gateway opened no payment');
|
|
112
|
+
let started;
|
|
113
|
+
try {
|
|
114
|
+
started = await startUaagCheckoutForLines({ apiBase: this.base, agentToken: this.opts.agentKey, fetch: this.fetch }, {
|
|
115
|
+
paymentIntentId: created.id,
|
|
116
|
+
cardId: o.cardId,
|
|
117
|
+
merchantName: ascii(this.opts.merchantName, 'Curless'),
|
|
118
|
+
merchantUrl: this.opts.merchantUrl,
|
|
119
|
+
amount: o.amountMinor,
|
|
120
|
+
items: [
|
|
121
|
+
{
|
|
122
|
+
name: ascii(o.label ?? o.title, 'Hotel stay'),
|
|
123
|
+
url: this.opts.merchantUrl,
|
|
124
|
+
unitPrice: o.amountMinor,
|
|
125
|
+
currency: o.currency,
|
|
126
|
+
quantity: 1,
|
|
127
|
+
sku: o.ref,
|
|
128
|
+
// A stay: nothing is shipped, so UnionPay asks for no address.
|
|
129
|
+
deliveryMethod: 'DIGITAL',
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
buyer: { email: o.email, ...(o.name ? { name: ascii(o.name, '') || undefined } : {}) },
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
throw new UnionPayError(`UnionPay did not take the order (${err.message})`);
|
|
137
|
+
}
|
|
138
|
+
if (!started.checkoutUrl)
|
|
139
|
+
throw new UnionPayError('UnionPay gave no page to confirm on');
|
|
140
|
+
return { sessionId: created.id, url: started.checkoutUrl };
|
|
141
|
+
}
|
|
142
|
+
async state(sessionId) {
|
|
143
|
+
let s;
|
|
144
|
+
try {
|
|
145
|
+
s = await checkoutState({ baseUrl: this.base, token: this.opts.agentKey, fetch: this.fetch }, sessionId);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
throw new UnionPayError(`the gateway did not say (${err.message})`);
|
|
149
|
+
}
|
|
150
|
+
if (s.issued)
|
|
151
|
+
return 'issued';
|
|
152
|
+
return ['canceled', 'cancelled', 'expired', 'failed'].includes(s.paymentIntentStatus)
|
|
153
|
+
? 'closed'
|
|
154
|
+
: 'open';
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The one-time card, from the gateway - which gives it once and then forgets
|
|
158
|
+
* it. ⚠️ THE GATEWAY'S SIDE IS NOT BUILT YET (总线程 asked to route it to the
|
|
159
|
+
* gateway, 2026-10-15): the path is the one proposed in
|
|
160
|
+
* docs/huazhu-unionpay-apop.md.
|
|
161
|
+
*/
|
|
162
|
+
async card(sessionId) {
|
|
163
|
+
let r;
|
|
164
|
+
try {
|
|
165
|
+
r = await this.call('POST', `/v1/merchant/payment-intents/${encodeURIComponent(sessionId)}/uaag/credential`, {});
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
// Taken already, or not issued: there is no card to hand on.
|
|
169
|
+
if (err instanceof UnionPayError &&
|
|
170
|
+
(err.status === 404 || err.status === 409 || err.status === 410))
|
|
171
|
+
return undefined;
|
|
172
|
+
throw err;
|
|
173
|
+
}
|
|
174
|
+
if (!r.cardNumber || !/^\d{12,19}$/.test(r.cardNumber) || !r.expMonth || !r.expYear)
|
|
175
|
+
return undefined;
|
|
176
|
+
return {
|
|
177
|
+
number: r.cardNumber,
|
|
178
|
+
expMonth: String(r.expMonth).padStart(2, '0'),
|
|
179
|
+
expYear: String(r.expYear).length === 2 ? `20${r.expYear}` : String(r.expYear),
|
|
180
|
+
...(r.securityCode ? { securityCode: r.securityCode } : {}),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* A payment handed to UnionPay cannot be cancelled at the gateway - and need
|
|
185
|
+
* not be: nothing is charged unless its card is handed on, which a lapsed
|
|
186
|
+
* booking never does. Says where it stands.
|
|
187
|
+
*/
|
|
188
|
+
async close(sessionId) {
|
|
189
|
+
return this.state(sessionId);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=unionpay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unionpay.js","sourceRoot":"","sources":["../../src/payments/unionpay.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export declare const INITIALIZE_PER_MINUTE = 300;
|
|
|
28
28
|
* number. Found by reading the boot banner of a container that had just been
|
|
29
29
|
* deployed (2026-09-22): seventeen tools listed, and "0.7.0" above them.
|
|
30
30
|
*/
|
|
31
|
-
export declare const VERSION = "0.
|
|
31
|
+
export declare const VERSION = "0.38.0";
|
|
32
32
|
/**
|
|
33
33
|
* The card's resource URI.
|
|
34
34
|
*
|
|
@@ -37,7 +37,7 @@ export declare const VERSION = "0.37.1";
|
|
|
37
37
|
* connector went storefront-v35 → v40 in a single day of UI work for exactly
|
|
38
38
|
* this reason.
|
|
39
39
|
*/
|
|
40
|
-
export declare const CARD_URI = "ui://curless/hotel/booking-
|
|
40
|
+
export declare const CARD_URI = "ui://curless/hotel/booking-v73.html";
|
|
41
41
|
/**
|
|
42
42
|
* The URI one deployment names its card by: `CARD_URI` with a short hash of
|
|
43
43
|
* everything a host caches under it - the card itself, and the hosts it may
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAYA,OAAO,EAAgB,IAAI,EAAE,MAAM,MAAM,CAAC;AAK1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAIzC,OAAO,EACL,KAAK,UAAU,EACf,KAAK,QAAQ,EAOd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,SAAS,EAAW,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,KAAK,aAAa,EAAgB,MAAM,YAAY,CAAC;AAS9D,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAC7C;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAc,CAAC;AAC1C;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO,WAAW,CAAC;AAEhC;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,wCAAwC,CAAC;AAK9D;;;;;;;;;;;;GAYG;AACH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,OAAO,GAClB,OAAO,WAAW,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACrC,MAAM,MAAM,KACX,UAAU,GAAG,SAkCf,CAAC;AAgBF,eAAO,MAAM,UAAU,GAAI,cAAc,MAAM,EAAE,EAAE,cAAU,KAAG,MAW7D,CAAC;AAEJ;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO;IAC/B,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,KAAG,MAsBH,CAAC;AACF;;;;;GAKG;AACH,eAAO,MAAM,SAAS,8BAA8B,CAAC;AAErD;;;;;GAKG;AACH,eAAO,MAAM,MAAM,GAAI,KAAK,MAAM;;;;;;;CAMrB,CAAC;AAEd;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,GAAI,cAAc,MAAM,EAAE,EAAE,cAAU;;;;;;;;;;;;;;CAO5D,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,aAAa,iBAAiB,CAAC;AAE5C,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,IAAI,CAAC;IACV,yEAAyE;IACzE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB;;;;OAIG;IACH,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,WAAW,CAAC;IACpB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,uFAAuF;IACvF,YAAY,CAAC,EAAE,OAAO,KAAK,CAAC;IAC5B,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAoBF,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,eAAO,MAAM,WAAW,GAAI,MAAM,aAAa,KAAG,WA6hBjD,CAAC;AAcF,eAAO,MAAM,QAAQ,GAAI,QAAQ,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAG9D,CAAC;AAEF,yFAAyF;AACzF,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAGlF,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -47,7 +47,7 @@ export const INITIALIZE_PER_MINUTE = 300;
|
|
|
47
47
|
* number. Found by reading the boot banner of a container that had just been
|
|
48
48
|
* deployed (2026-09-22): seventeen tools listed, and "0.7.0" above them.
|
|
49
49
|
*/
|
|
50
|
-
export const VERSION = '0.
|
|
50
|
+
export const VERSION = '0.38.0';
|
|
51
51
|
/**
|
|
52
52
|
* The card's resource URI.
|
|
53
53
|
*
|
|
@@ -56,7 +56,7 @@ export const VERSION = '0.37.1';
|
|
|
56
56
|
* connector went storefront-v35 → v40 in a single day of UI work for exactly
|
|
57
57
|
* this reason.
|
|
58
58
|
*/
|
|
59
|
-
export const CARD_URI = 'ui://curless/hotel/booking-
|
|
59
|
+
export const CARD_URI = 'ui://curless/hotel/booking-v73.html';
|
|
60
60
|
/** The card as it ships, hashed once - what a host caches under the URI. */
|
|
61
61
|
const CARD_HTML_SHA = createHash('sha256').update(HOTEL_CARD_HTML).digest('hex');
|
|
62
62
|
/**
|
|
@@ -308,6 +308,15 @@ export const buildServer = (opts) => {
|
|
|
308
308
|
// booking card over "can I bring a dog" puts a storefront in front of someone
|
|
309
309
|
// who asked a question.
|
|
310
310
|
const CARDLESS = new Set([brand.tools.policies, brand.tools.lookUp]);
|
|
311
|
+
// The card's own steps, which the host keeps from the model: paying with
|
|
312
|
+
// UnionPay is a press on the payment screen, never an assistant's decision.
|
|
313
|
+
// MCP Apps hosts read `ui.visibility`; ChatGPT reads `openai/visibility`.
|
|
314
|
+
const APP_ONLY = new Set([brand.tools.payWithUnionPay]);
|
|
315
|
+
const appOnly = (m) => ({
|
|
316
|
+
...m,
|
|
317
|
+
ui: { ...m.ui, visibility: ['app'] },
|
|
318
|
+
'openai/visibility': 'private',
|
|
319
|
+
});
|
|
311
320
|
// Worked out per answer: an API backend's photographs arrive with its hotel
|
|
312
321
|
// list, which is still filling in on a first boot.
|
|
313
322
|
//
|
|
@@ -548,7 +557,7 @@ export const buildServer = (opts) => {
|
|
|
548
557
|
return c.body(null, 202);
|
|
549
558
|
if (method === 'tools/list') {
|
|
550
559
|
return ok(c, id, {
|
|
551
|
-
tools: listTools(TOOLS, OUTPUT_SCHEMAS, (name) => (CARDLESS.has(name) ? {} : meta()), TRIP_TOOLS),
|
|
560
|
+
tools: listTools(TOOLS, OUTPUT_SCHEMAS, (name) => (CARDLESS.has(name) ? {} : APP_ONLY.has(name) ? appOnly(meta()) : meta()), TRIP_TOOLS),
|
|
552
561
|
});
|
|
553
562
|
}
|
|
554
563
|
if (method === 'resources/list') {
|