@chevre/domain 28.0.0 → 28.1.0-alpha.1
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/lib/chevre/repo/adminAcceptedOffer.d.ts +2 -13
- package/lib/chevre/repo/adminAcceptedOffer.js +26 -31
- package/lib/chevre/repo/factory/reservation/minimizeReservationFor.js +0 -5
- package/lib/chevre/repo/mongoose/schemas/setting.d.ts +4 -0
- package/lib/chevre/service/notification/triggerWebhook/getGoogleIdTokenClient.d.ts +5 -0
- package/lib/chevre/service/notification/triggerWebhook/getGoogleIdTokenClient.js +39 -0
- package/lib/chevre/service/notification/triggerWebhook.js +33 -16
- package/lib/chevre/service/transaction/placeOrder/confirm/validation.d.ts +3 -1
- package/lib/chevre/service/transaction/placeOrder/confirm/validation.js +7 -1
- package/lib/chevre/service/transaction/placeOrder/confirm.d.ts +5 -0
- package/lib/chevre/service/transaction/placeOrder/confirm.js +1 -1
- package/package.json +2 -1
|
@@ -34,12 +34,6 @@ export declare class AdminAcceptedOfferRepo extends AcceptedOfferInReserveRepo {
|
|
|
34
34
|
* 索条件を最小化(2026-06-05~)
|
|
35
35
|
*/
|
|
36
36
|
params: Pick<factory.order.ISearchConditions, 'limit' | 'orderNumbers' | 'page' | 'project' | 'provider' | 'sort' | 'orderDate'>, projection: IProjection4searchWithUnwoundAcceptedOffers, options: {
|
|
37
|
-
/**
|
|
38
|
-
* reservationForをid属性のみにするオプション
|
|
39
|
-
* 2026-08-31~
|
|
40
|
-
* always true(2026-10-08~)
|
|
41
|
-
*/
|
|
42
|
-
minimizeReservationFor: true;
|
|
43
37
|
/**
|
|
44
38
|
* reservedTicket以外の属性を除外するオプション
|
|
45
39
|
* 2026-10-08~
|
|
@@ -67,17 +61,12 @@ export declare class AdminAcceptedOfferRepo extends AcceptedOfferInReserveRepo {
|
|
|
67
61
|
id: string;
|
|
68
62
|
};
|
|
69
63
|
}, options: {
|
|
70
|
-
/**
|
|
71
|
-
* reservationForをid属性のみにするオプション
|
|
72
|
-
* 2026-08-31~
|
|
73
|
-
* always true(2026-10-08~)
|
|
74
|
-
*/
|
|
75
|
-
minimizeReservationFor: true;
|
|
76
64
|
/**
|
|
77
65
|
* reservedTicket以外の属性を除外するオプション
|
|
78
66
|
* 2026-10-08~
|
|
67
|
+
* always true(2026-10-23~)
|
|
79
68
|
*/
|
|
80
|
-
onlyReservedTicket:
|
|
69
|
+
onlyReservedTicket: true;
|
|
81
70
|
/**
|
|
82
71
|
* reservedTicketからticketTypeを除外するオプション
|
|
83
72
|
* 2026-10-23~
|
|
@@ -7,45 +7,40 @@ const settings_1 = require("../settings");
|
|
|
7
7
|
const acceptedOfferInReserve_1 = require("./acceptedOfferInReserve");
|
|
8
8
|
const order_2 = require("./order");
|
|
9
9
|
function minimizeItemOffered(itemOffered, options) {
|
|
10
|
-
const {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
return {
|
|
34
|
-
id, reservationNumber, reservedTicket,
|
|
35
|
-
typeOf: itemOfferedWithoutEvent.typeOf,
|
|
36
|
-
reservationFor: { id: reservationFor.id, typeOf: reservationFor.typeOf }
|
|
37
|
-
};
|
|
38
|
-
}
|
|
10
|
+
const { onlyReservedTicket, minimizeReservedTicket } = options;
|
|
11
|
+
const { reservationFor, ...itemOfferedWithoutEvent } = itemOffered;
|
|
12
|
+
if (onlyReservedTicket) {
|
|
13
|
+
const { id, reservationNumber, reservedTicket } = itemOfferedWithoutEvent;
|
|
14
|
+
// support minimizeReservedTicket(2026-10-23~)
|
|
15
|
+
if (minimizeReservedTicket) {
|
|
16
|
+
const { coaReserveAmount, coaTicketInfo, ticketToken, identifier, ticketedSeat } = reservedTicket;
|
|
17
|
+
return {
|
|
18
|
+
id, reservationNumber,
|
|
19
|
+
reservedTicket: {
|
|
20
|
+
typeOf: reservedTicket.typeOf,
|
|
21
|
+
identifier,
|
|
22
|
+
...(typeof ticketedSeat?.typeOf === 'string') && { ticketedSeat },
|
|
23
|
+
...(coaReserveAmount !== undefined) && { coaReserveAmount },
|
|
24
|
+
...(coaTicketInfo !== undefined) && { coaTicketInfo },
|
|
25
|
+
...(typeof ticketToken === 'string') && { ticketToken },
|
|
26
|
+
},
|
|
27
|
+
typeOf: itemOfferedWithoutEvent.typeOf,
|
|
28
|
+
reservationFor: { id: reservationFor.id, typeOf: reservationFor.typeOf }
|
|
29
|
+
};
|
|
39
30
|
}
|
|
40
31
|
else {
|
|
41
32
|
return {
|
|
42
|
-
|
|
33
|
+
id, reservationNumber, reservedTicket,
|
|
34
|
+
typeOf: itemOfferedWithoutEvent.typeOf,
|
|
43
35
|
reservationFor: { id: reservationFor.id, typeOf: reservationFor.typeOf }
|
|
44
36
|
};
|
|
45
37
|
}
|
|
46
38
|
}
|
|
47
39
|
else {
|
|
48
|
-
return
|
|
40
|
+
return {
|
|
41
|
+
...itemOfferedWithoutEvent,
|
|
42
|
+
reservationFor: { id: reservationFor.id, typeOf: reservationFor.typeOf }
|
|
43
|
+
};
|
|
49
44
|
}
|
|
50
45
|
}
|
|
51
46
|
/**
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.minimizeReservationFor = minimizeReservationFor;
|
|
4
|
-
const USE_DEPRECATED_RESERVATION_FOR = process.env.USE_DEPRECATED_RESERVATION_FOR === '1';
|
|
5
4
|
function minimizeWorkPerformed(params) {
|
|
6
5
|
const { identifier, id, typeOf, version } = params;
|
|
7
6
|
return {
|
|
@@ -29,10 +28,6 @@ function minimizeRoom(params) {
|
|
|
29
28
|
return { branchCode, typeOf };
|
|
30
29
|
}
|
|
31
30
|
function minimizeReservationFor(params) {
|
|
32
|
-
if (USE_DEPRECATED_RESERVATION_FOR) {
|
|
33
|
-
// 互換性維持対応として
|
|
34
|
-
return { minimizedReservationFor: params }; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
35
|
-
}
|
|
36
31
|
const { name: _name, doorTime: _doorTime, superEvent, location, ...reservationForNoName } = params;
|
|
37
32
|
const minimizedReservationFor = {
|
|
38
33
|
...reservationForNoName,
|
|
@@ -69,6 +69,10 @@ interface ITriggerWebhookSettings {
|
|
|
69
69
|
headerIdentifier?: string;
|
|
70
70
|
retryCountMax?: number;
|
|
71
71
|
retryIntervalInMS?: number;
|
|
72
|
+
/**
|
|
73
|
+
* support(2026-10-30~)
|
|
74
|
+
*/
|
|
75
|
+
googleTargetAudience?: string;
|
|
72
76
|
}
|
|
73
77
|
export interface IWaiterSettings {
|
|
74
78
|
disabled?: boolean;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getGoogleIdTokenClient = getGoogleIdTokenClient;
|
|
4
|
+
const google_auth_library_1 = require("google-auth-library");
|
|
5
|
+
// GoogleAuth のベースインスタンスは 1 つで共有
|
|
6
|
+
let auth;
|
|
7
|
+
// Audience ごとに生成したクライアントを保持するキャッシュ
|
|
8
|
+
const idTokenClients = new Map();
|
|
9
|
+
const initPromises = new Map();
|
|
10
|
+
/**
|
|
11
|
+
* 指定した targetAudience に対応する IdTokenClient を取得(キャッシュ対応)
|
|
12
|
+
*/
|
|
13
|
+
async function getGoogleIdTokenClient(targetAudience) {
|
|
14
|
+
if (typeof targetAudience !== 'string' || targetAudience === '') {
|
|
15
|
+
throw new Error('targetAudience is required.');
|
|
16
|
+
}
|
|
17
|
+
// 1. 既に生成済みのインスタンスがあれば即座に返す(メモリ参照のみ、負荷ゼロ)
|
|
18
|
+
const cachedClient = idTokenClients.get(targetAudience);
|
|
19
|
+
if (cachedClient !== undefined) {
|
|
20
|
+
return cachedClient;
|
|
21
|
+
}
|
|
22
|
+
if (auth === undefined) {
|
|
23
|
+
auth = new google_auth_library_1.GoogleAuth();
|
|
24
|
+
}
|
|
25
|
+
// 2. 起動直後など、同一 Audience への多重初期化を防ぐ(Promise キャッシュ)
|
|
26
|
+
let promise = initPromises.get(targetAudience);
|
|
27
|
+
if (promise === undefined) {
|
|
28
|
+
promise = auth.getIdTokenClient(targetAudience)
|
|
29
|
+
.then((client) => {
|
|
30
|
+
idTokenClients.set(targetAudience, client);
|
|
31
|
+
return client;
|
|
32
|
+
}).finally(() => {
|
|
33
|
+
// 成功・失敗にかかわらず進行中フラグ(Promise)を掃除する
|
|
34
|
+
initPromises.delete(targetAudience);
|
|
35
|
+
});
|
|
36
|
+
initPromises.set(targetAudience, promise);
|
|
37
|
+
}
|
|
38
|
+
return promise;
|
|
39
|
+
}
|
|
@@ -37,6 +37,7 @@ exports.triggerWebhook = triggerWebhook;
|
|
|
37
37
|
const crypto = __importStar(require("crypto"));
|
|
38
38
|
const http_status_1 = require("http-status");
|
|
39
39
|
const factory_1 = require("../../factory");
|
|
40
|
+
const getGoogleIdTokenClient_1 = require("./triggerWebhook/getGoogleIdTokenClient");
|
|
40
41
|
const USERNAME_ARGUMENT_REQUIRED_MESSAGE = 'Missing required key \'Username\' in params';
|
|
41
42
|
function triggerWebhook(params) {
|
|
42
43
|
return async (repos) => {
|
|
@@ -141,11 +142,40 @@ function signRequest(params) {
|
|
|
141
142
|
.update(payload)
|
|
142
143
|
.digest('hex');
|
|
143
144
|
}
|
|
145
|
+
async function makeRequestHeaders(action, options, requestBody) {
|
|
146
|
+
const secretKey = options?.triggerWebhook?.secretKey;
|
|
147
|
+
const headerIdentifier = options?.triggerWebhook?.headerIdentifier;
|
|
148
|
+
const googleTargetAudience = options?.triggerWebhook?.googleTargetAudience;
|
|
149
|
+
const timestamp = action.startDate.valueOf();
|
|
150
|
+
// sign request(2024-10-28~)
|
|
151
|
+
let signature;
|
|
152
|
+
if (typeof secretKey === 'string' && secretKey !== ''
|
|
153
|
+
&& typeof headerIdentifier === 'string' && headerIdentifier !== '') {
|
|
154
|
+
signature = signRequest({ requestBody, timestamp, secretKey });
|
|
155
|
+
}
|
|
156
|
+
const headers = new Headers({ 'Content-Type': 'application/json' });
|
|
157
|
+
if (typeof headerIdentifier === 'string' && headerIdentifier !== '') {
|
|
158
|
+
headers.append(`X-${headerIdentifier}-Webhook-Timestamp`, String(timestamp));
|
|
159
|
+
if (typeof signature === 'string') {
|
|
160
|
+
headers.append(`X-${headerIdentifier}-Webhook-Signature`, signature);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// support googleAuth(2026-10-30~)
|
|
164
|
+
if (typeof googleTargetAudience === 'string' && googleTargetAudience !== '') {
|
|
165
|
+
const idTokenClient = await (0, getGoogleIdTokenClient_1.getGoogleIdTokenClient)(googleTargetAudience);
|
|
166
|
+
// getRequestHeaders() からキャッシュ済みの "Bearer eyJhbG..." を取得
|
|
167
|
+
const requestHeaders = await idTokenClient.getRequestHeaders();
|
|
168
|
+
const idToken = requestHeaders.get('authorization'); // "Bearer eyJhbG..."
|
|
169
|
+
if (typeof idToken === 'string') {
|
|
170
|
+
// IAPを通過するための認証(Googleが認識するヘッダー)
|
|
171
|
+
headers.append('Proxy-Authorization', idToken);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return headers;
|
|
175
|
+
}
|
|
144
176
|
function processInformAction(params, options) {
|
|
145
177
|
return async (repos) => {
|
|
146
178
|
const timeout = options?.triggerWebhook?.timeout;
|
|
147
|
-
const secretKey = options?.triggerWebhook?.secretKey;
|
|
148
|
-
const headerIdentifier = options?.triggerWebhook?.headerIdentifier;
|
|
149
179
|
const { identifier } = params;
|
|
150
180
|
const informActionAttributes = await createInformActionAttributes(params)(repos);
|
|
151
181
|
const action = await repos.actions.inform.startInformAction(informActionAttributes);
|
|
@@ -161,20 +191,7 @@ function processInformAction(params, options) {
|
|
|
161
191
|
? { identifier }
|
|
162
192
|
: undefined
|
|
163
193
|
});
|
|
164
|
-
const
|
|
165
|
-
// sign request(2024-10-28~)
|
|
166
|
-
let signature;
|
|
167
|
-
if (typeof secretKey === 'string' && secretKey !== ''
|
|
168
|
-
&& typeof headerIdentifier === 'string' && headerIdentifier !== '') {
|
|
169
|
-
signature = signRequest({ requestBody, timestamp, secretKey });
|
|
170
|
-
}
|
|
171
|
-
const headers = new Headers({ 'Content-Type': 'application/json' });
|
|
172
|
-
if (typeof headerIdentifier === 'string' && headerIdentifier !== '') {
|
|
173
|
-
headers.append(`X-${headerIdentifier}-Webhook-Timestamp`, String(timestamp));
|
|
174
|
-
if (typeof signature === 'string') {
|
|
175
|
-
headers.append(`X-${headerIdentifier}-Webhook-Signature`, signature);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
194
|
+
const headers = await makeRequestHeaders(action, options, requestBody);
|
|
178
195
|
const res = await fetch(urlTemplate, {
|
|
179
196
|
method: 'POST',
|
|
180
197
|
headers,
|
|
@@ -18,7 +18,9 @@ export declare function validateAcceptedOffers(params: {
|
|
|
18
18
|
result: {
|
|
19
19
|
order: PlaceOrderFactory.IResultOrderParams;
|
|
20
20
|
};
|
|
21
|
-
acceptedOffers: (Pick<factory.acceptedOffer.IAcceptedOffer, 'itemOffered' | 'offeredThrough' | 'serialNumber'>)[];
|
|
21
|
+
acceptedOffers: (Pick<factory.acceptedOffer.IAcceptedOffer, 'itemOffered' | 'offeredThrough' | 'serialNumber' | 'id'>)[];
|
|
22
|
+
}, options: {
|
|
23
|
+
maxNumUnitPriceOffers: number;
|
|
22
24
|
}): void;
|
|
23
25
|
export declare function validateOrderedItem(params: {
|
|
24
26
|
order: Pick<factory.order.IOrder, 'orderedItem'>;
|
|
@@ -196,7 +196,7 @@ function validatePaymentUrl(params) {
|
|
|
196
196
|
/**
|
|
197
197
|
* 注文オファー数検証
|
|
198
198
|
*/
|
|
199
|
-
function validateAcceptedOffers(params) {
|
|
199
|
+
function validateAcceptedOffers(params, options) {
|
|
200
200
|
if (!Array.isArray(params.acceptedOffers)) {
|
|
201
201
|
throw new factory_1.factory.errors.Argument('order.acceptedOffers', 'must be array');
|
|
202
202
|
}
|
|
@@ -266,6 +266,12 @@ function validateAcceptedOffers(params) {
|
|
|
266
266
|
throw new factory_1.factory.errors.Argument('Transaction', 'ticketNumbers must be unique');
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
|
+
// 単価オファー数検証(2026-10-26~)
|
|
270
|
+
const { maxNumUnitPriceOffers } = options;
|
|
271
|
+
const numUnitPriceOffers = [...new Set(params.acceptedOffers.map(({ id }) => String(id)))].length;
|
|
272
|
+
if (numUnitPriceOffers > maxNumUnitPriceOffers) {
|
|
273
|
+
throw new factory_1.factory.errors.Argument('Transaction', (0, util_1.format)('Number of unitPriceOffers must be less than or equal to %s', maxNumUnitPriceOffers));
|
|
274
|
+
}
|
|
269
275
|
}
|
|
270
276
|
function validateOrderedItem(params) {
|
|
271
277
|
if (!Array.isArray(params.order.orderedItem)) {
|
|
@@ -40,6 +40,11 @@ interface IConfirmOptions {
|
|
|
40
40
|
* 注文における最大CreditCardIF決済方法数
|
|
41
41
|
*/
|
|
42
42
|
maxNumCreditCardPaymentMethod: number;
|
|
43
|
+
/**
|
|
44
|
+
* ユニークな単価オファー最大数
|
|
45
|
+
* 2026-10-26~
|
|
46
|
+
*/
|
|
47
|
+
maxNumUnitPriceOffers: number;
|
|
43
48
|
}
|
|
44
49
|
type IConfirmParams = PlaceOrderFactory.IConfirmParams & {
|
|
45
50
|
/**
|
|
@@ -327,7 +327,7 @@ function createResult(params, options) {
|
|
|
327
327
|
(0, validation_1.validateAcceptedOffers)({
|
|
328
328
|
result: params.result,
|
|
329
329
|
acceptedOffers: params.acceptedOffers
|
|
330
|
-
});
|
|
330
|
+
}, options);
|
|
331
331
|
// 注文アイテム検証(2024-01-20~)
|
|
332
332
|
(0, validation_1.validateOrderedItem)({
|
|
333
333
|
order: { orderedItem },
|
package/package.json
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"@sendgrid/client": "8.1.4",
|
|
18
18
|
"@surfrock/sdk": "2.0.0",
|
|
19
19
|
"debug": "4.4.3",
|
|
20
|
+
"google-auth-library": "11.3.2",
|
|
20
21
|
"http-status": "2.1.0",
|
|
21
22
|
"jsonwebtoken": "9.0.0",
|
|
22
23
|
"libphonenumber-js": "1.13.8",
|
|
@@ -88,5 +89,5 @@
|
|
|
88
89
|
"postversion": "git push origin --tags",
|
|
89
90
|
"prepublishOnly": "npm run clean && npm run build"
|
|
90
91
|
},
|
|
91
|
-
"version": "28.0.
|
|
92
|
+
"version": "28.1.0-alpha.1"
|
|
92
93
|
}
|