@cimplify/sdk 0.104.0 → 0.104.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/dist/advanced.d.mts +3 -7
- package/dist/advanced.d.ts +3 -7
- package/dist/advanced.js +23 -23
- package/dist/advanced.mjs +4 -4
- package/dist/{client-BuLcOWLv.d.ts → catalogue-BlQ85Uma.d.mts} +415 -763
- package/dist/{client-D5AoobFc.d.mts → catalogue-C8TqOj9K.d.ts} +415 -763
- package/dist/{payment-g0HFkEDU.d.mts → checkout-BqK9XUz5.d.mts} +3824 -1446
- package/dist/{payment-g0HFkEDU.d.ts → checkout-BqK9XUz5.d.ts} +3824 -1446
- package/dist/{chunk-GOHSXBKW.mjs → chunk-33VCYWVL.mjs} +25 -1
- package/dist/{chunk-2WPVUIHX.mjs → chunk-6G3ANKQA.mjs} +1030 -360
- package/dist/{chunk-E4K2VQDD.js → chunk-BWEIMKLF.js} +541 -16
- package/dist/{chunk-IQFFSKE2.js → chunk-DQEXY542.js} +1345 -746
- package/dist/{chunk-CNN7Z2IP.js → chunk-EV2EVOYS.js} +27 -0
- package/dist/{chunk-YVAEY3VC.js → chunk-HYFA67A7.js} +1034 -364
- package/dist/{chunk-5RT4HYMP.mjs → chunk-L5SNEU2O.mjs} +524 -15
- package/dist/{chunk-4BKOKHE3.js → chunk-RBNBSQI7.mjs} +217 -19
- package/dist/{chunk-H3RATH4B.mjs → chunk-SFUJMS5E.js} +261 -2
- package/dist/{chunk-DYIAX3WI.mjs → chunk-U54CWUUT.mjs} +11 -2
- package/dist/{chunk-OKADBZAI.mjs → chunk-UFOWPN3D.mjs} +808 -574
- package/dist/{chunk-OCCNG6MO.mjs → chunk-V4457OKB.mjs} +1310 -722
- package/dist/{chunk-5BDYDZ4U.js → chunk-WXREIBFW.js} +892 -657
- package/dist/{chunk-7PDEX54K.js → chunk-XAUSDMMZ.js} +13 -3
- package/dist/{client-BVNWjk6W.d.ts → client-DhXeiUrf.d.ts} +2 -2
- package/dist/{client-fM716k7G.d.mts → client-mXiUrV4X.d.mts} +2 -2
- package/dist/{index-BtcoqrY1.d.ts → index-B0AdZvrM.d.mts} +9 -4
- package/dist/{index-D7Tf3v7c.d.mts → index-CK8Nk5uQ.d.ts} +9 -4
- package/dist/index-DPWI5XcU.d.ts +8 -0
- package/dist/index-DVfUh-ci.d.mts +8 -0
- package/dist/index.d.mts +31 -14
- package/dist/index.d.ts +31 -14
- package/dist/index.js +305 -133
- package/dist/index.mjs +6 -6
- package/dist/mock/cli.mjs +1442 -386
- package/dist/mock/library.js +1168 -352
- package/dist/mock/library.mjs +1168 -352
- package/dist/mock/msw.js +1168 -352
- package/dist/mock/msw.mjs +1168 -352
- package/dist/{price-BLIeAb8K.d.ts → price-6hQIIac9.d.ts} +1 -1
- package/dist/{price-Czq_cTC_.d.mts → price-BUDv1rI7.d.mts} +1 -1
- package/dist/react.d.mts +10 -5
- package/dist/react.d.ts +10 -5
- package/dist/react.js +227 -197
- package/dist/react.mjs +90 -60
- package/dist/{server-DKK_D-PP.d.ts → server-DJ0mSs9i.d.mts} +31 -57
- package/dist/{server-BkVhOIwn.d.mts → server-DSTX76Ki.d.ts} +31 -57
- package/dist/server.d.mts +3 -4
- package/dist/server.d.ts +3 -4
- package/dist/server.js +11 -11
- package/dist/server.mjs +5 -5
- package/dist/styles.css +2 -2
- package/dist/testing/msw.d.mts +2 -2
- package/dist/testing/msw.d.ts +2 -2
- package/dist/testing/msw.js +4 -4
- package/dist/testing/msw.mjs +3 -3
- package/dist/testing/suite.d.mts +5 -6
- package/dist/testing/suite.d.ts +5 -6
- package/dist/testing/suite.js +29 -28
- package/dist/testing/suite.mjs +10 -9
- package/dist/testing.d.mts +2177 -14
- package/dist/testing.d.ts +2177 -14
- package/dist/testing.js +167 -89
- package/dist/testing.mjs +24 -10
- package/dist/utils.d.mts +3 -4
- package/dist/utils.d.ts +3 -4
- package/dist/utils.js +35 -31
- package/dist/utils.mjs +2 -2
- package/package.json +9 -9
- package/registry/order-history.json +1 -1
- package/registry/order-summary.json +1 -1
- package/dist/link-D9iSVxt5.d.mts +0 -308
- package/dist/link-D9iSVxt5.d.ts +0 -308
package/dist/mock/msw.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// ../node_modules/.bun/hono@4.
|
|
3
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/compose.js
|
|
4
4
|
var compose = (middleware, onError, onNotFound) => {
|
|
5
5
|
return (context, next) => {
|
|
6
6
|
let index = -1;
|
|
@@ -44,21 +44,46 @@ var compose = (middleware, onError, onNotFound) => {
|
|
|
44
44
|
};
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
// ../node_modules/.bun/hono@4.
|
|
47
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/request/constants.js
|
|
48
48
|
var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
|
|
49
49
|
|
|
50
|
-
// ../node_modules/.bun/hono@4.
|
|
50
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/utils/buffer.js
|
|
51
|
+
var bufferToFormData = (arrayBuffer, contentType) => {
|
|
52
|
+
const response = new Response(arrayBuffer, {
|
|
53
|
+
headers: {
|
|
54
|
+
// Normalize the media type (case-insensitive) while keeping parameters like the boundary
|
|
55
|
+
"Content-Type": contentType.replace(/^[^;]+/, (mediaType) => mediaType.toLowerCase())
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return response.formData();
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/utils/body.js
|
|
62
|
+
var isRawRequest = (request) => "headers" in request;
|
|
51
63
|
var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
|
|
52
64
|
const { all = false, dot = false } = options;
|
|
53
|
-
const headers = request
|
|
65
|
+
const headers = isRawRequest(request) ? request.headers : request.raw.headers;
|
|
54
66
|
const contentType = headers.get("Content-Type");
|
|
55
|
-
|
|
67
|
+
const mediaType = contentType?.split(";")[0].trim().toLowerCase();
|
|
68
|
+
if (mediaType === "multipart/form-data" || mediaType === "application/x-www-form-urlencoded") {
|
|
56
69
|
return parseFormData(request, { all, dot });
|
|
57
70
|
}
|
|
58
71
|
return {};
|
|
59
72
|
};
|
|
60
73
|
async function parseFormData(request, options) {
|
|
61
|
-
|
|
74
|
+
if (!isRawRequest(request) && request.bodyCache.formData) {
|
|
75
|
+
return convertFormDataToBodyData(
|
|
76
|
+
await request.bodyCache.formData,
|
|
77
|
+
options
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
const headers = isRawRequest(request) ? request.headers : request.raw.headers;
|
|
81
|
+
const arrayBuffer = await request.arrayBuffer();
|
|
82
|
+
const formDataPromise = bufferToFormData(arrayBuffer, headers.get("Content-Type") || "");
|
|
83
|
+
if (!isRawRequest(request)) {
|
|
84
|
+
request.bodyCache.formData = formDataPromise;
|
|
85
|
+
}
|
|
86
|
+
const formData = await formDataPromise;
|
|
62
87
|
if (formData) {
|
|
63
88
|
return convertFormDataToBodyData(formData, options);
|
|
64
89
|
}
|
|
@@ -118,7 +143,7 @@ var handleParsingNestedValues = (form, key, value) => {
|
|
|
118
143
|
});
|
|
119
144
|
};
|
|
120
145
|
|
|
121
|
-
// ../node_modules/.bun/hono@4.
|
|
146
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/utils/url.js
|
|
122
147
|
var splitPath = (path) => {
|
|
123
148
|
const paths = path.split("/");
|
|
124
149
|
if (paths[0] === "") {
|
|
@@ -224,13 +249,13 @@ var checkOptionalParameter = (path) => {
|
|
|
224
249
|
if (segment !== "" && !/\:/.test(segment)) {
|
|
225
250
|
basePath += "/" + segment;
|
|
226
251
|
} else if (/\:/.test(segment)) {
|
|
227
|
-
if (
|
|
252
|
+
if (segment.charCodeAt(segment.length - 1) === 63) {
|
|
228
253
|
if (results.length === 0 && basePath === "") {
|
|
229
254
|
results.push("/");
|
|
230
255
|
} else {
|
|
231
256
|
results.push(basePath);
|
|
232
257
|
}
|
|
233
|
-
const optionalSegment = segment.
|
|
258
|
+
const optionalSegment = segment.slice(0, -1);
|
|
234
259
|
basePath += "/" + optionalSegment;
|
|
235
260
|
results.push(basePath);
|
|
236
261
|
} else {
|
|
@@ -240,18 +265,16 @@ var checkOptionalParameter = (path) => {
|
|
|
240
265
|
});
|
|
241
266
|
return results.filter((v, i, a) => a.indexOf(v) === i);
|
|
242
267
|
};
|
|
268
|
+
var tryDecodeURIComponent = (str) => str.indexOf("%") !== -1 ? tryDecode(str, decodeURIComponent_) : str;
|
|
243
269
|
var _decodeURI = (value) => {
|
|
244
|
-
if (!/[%+]/.test(value)) {
|
|
245
|
-
return value;
|
|
246
|
-
}
|
|
247
270
|
if (value.indexOf("+") !== -1) {
|
|
248
271
|
value = value.replace(/\+/g, " ");
|
|
249
272
|
}
|
|
250
|
-
return
|
|
273
|
+
return tryDecodeURIComponent(value);
|
|
251
274
|
};
|
|
252
275
|
var _getQueryParam = (url, key, multiple) => {
|
|
253
276
|
let encoded;
|
|
254
|
-
if (!multiple && key &&
|
|
277
|
+
if (!multiple && key && key.indexOf("%") === -1 && key.indexOf("+") === -1) {
|
|
255
278
|
let keyIndex2 = url.indexOf("?", 8);
|
|
256
279
|
if (keyIndex2 === -1) {
|
|
257
280
|
return void 0;
|
|
@@ -275,7 +298,7 @@ var _getQueryParam = (url, key, multiple) => {
|
|
|
275
298
|
return void 0;
|
|
276
299
|
}
|
|
277
300
|
}
|
|
278
|
-
const results =
|
|
301
|
+
const results = /* @__PURE__ */ Object.create(null);
|
|
279
302
|
encoded ??= /[%+]/.test(url);
|
|
280
303
|
let keyIndex = url.indexOf("?", 8);
|
|
281
304
|
while (keyIndex !== -1) {
|
|
@@ -321,8 +344,7 @@ var getQueryParams = (url, key) => {
|
|
|
321
344
|
};
|
|
322
345
|
var decodeURIComponent_ = decodeURIComponent;
|
|
323
346
|
|
|
324
|
-
// ../node_modules/.bun/hono@4.
|
|
325
|
-
var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_);
|
|
347
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/request.js
|
|
326
348
|
var HonoRequest = class {
|
|
327
349
|
/**
|
|
328
350
|
* `.raw` can get the raw Request object.
|
|
@@ -361,7 +383,6 @@ var HonoRequest = class {
|
|
|
361
383
|
this.raw = request;
|
|
362
384
|
this.path = path;
|
|
363
385
|
this.#matchResult = matchResult;
|
|
364
|
-
this.#validatedData = {};
|
|
365
386
|
}
|
|
366
387
|
param(key) {
|
|
367
388
|
return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
|
|
@@ -369,7 +390,7 @@ var HonoRequest = class {
|
|
|
369
390
|
#getDecodedParam(key) {
|
|
370
391
|
const paramKey = this.#matchResult[0][this.routeIndex][1][key];
|
|
371
392
|
const param = this.#getParamValue(paramKey);
|
|
372
|
-
return param &&
|
|
393
|
+
return param && tryDecodeURIComponent(param);
|
|
373
394
|
}
|
|
374
395
|
#getAllDecodedParams() {
|
|
375
396
|
const decoded = {};
|
|
@@ -377,7 +398,7 @@ var HonoRequest = class {
|
|
|
377
398
|
for (const key of keys) {
|
|
378
399
|
const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
|
|
379
400
|
if (value !== void 0) {
|
|
380
|
-
decoded[key] =
|
|
401
|
+
decoded[key] = tryDecodeURIComponent(value);
|
|
381
402
|
}
|
|
382
403
|
}
|
|
383
404
|
return decoded;
|
|
@@ -395,7 +416,7 @@ var HonoRequest = class {
|
|
|
395
416
|
if (name) {
|
|
396
417
|
return this.raw.headers.get(name) ?? void 0;
|
|
397
418
|
}
|
|
398
|
-
const headerData =
|
|
419
|
+
const headerData = /* @__PURE__ */ Object.create(null);
|
|
399
420
|
this.raw.headers.forEach((value, key) => {
|
|
400
421
|
headerData[key] = value;
|
|
401
422
|
});
|
|
@@ -410,8 +431,7 @@ var HonoRequest = class {
|
|
|
410
431
|
if (cachedBody) {
|
|
411
432
|
return cachedBody;
|
|
412
433
|
}
|
|
413
|
-
const anyCachedKey
|
|
414
|
-
if (anyCachedKey) {
|
|
434
|
+
for (const anyCachedKey in bodyCache) {
|
|
415
435
|
return bodyCache[anyCachedKey].then((body) => {
|
|
416
436
|
if (anyCachedKey === "json") {
|
|
417
437
|
body = JSON.stringify(body);
|
|
@@ -514,10 +534,10 @@ var HonoRequest = class {
|
|
|
514
534
|
* @param data - The validated data to add.
|
|
515
535
|
*/
|
|
516
536
|
addValidatedData(target, data) {
|
|
517
|
-
this.#validatedData[target] = data;
|
|
537
|
+
(this.#validatedData ??= {})[target] = data;
|
|
518
538
|
}
|
|
519
539
|
valid(target) {
|
|
520
|
-
return this.#validatedData[target];
|
|
540
|
+
return this.#validatedData?.[target];
|
|
521
541
|
}
|
|
522
542
|
/**
|
|
523
543
|
* `.url()` can get the request url strings.
|
|
@@ -604,7 +624,7 @@ var HonoRequest = class {
|
|
|
604
624
|
}
|
|
605
625
|
};
|
|
606
626
|
|
|
607
|
-
// ../node_modules/.bun/hono@4.
|
|
627
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/utils/html.js
|
|
608
628
|
var HtmlEscapedCallbackPhase = {
|
|
609
629
|
Stringify: 1};
|
|
610
630
|
var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
|
|
@@ -635,7 +655,7 @@ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) =>
|
|
|
635
655
|
}
|
|
636
656
|
};
|
|
637
657
|
|
|
638
|
-
// ../node_modules/.bun/hono@4.
|
|
658
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/context.js
|
|
639
659
|
var TEXT_PLAIN = "text/plain; charset=UTF-8";
|
|
640
660
|
var setDefaultContentType = (contentType, headers) => {
|
|
641
661
|
return {
|
|
@@ -908,11 +928,11 @@ var Context = class {
|
|
|
908
928
|
return Object.fromEntries(this.#var);
|
|
909
929
|
}
|
|
910
930
|
#newResponse(data, arg, headers) {
|
|
911
|
-
|
|
912
|
-
if (typeof arg === "object" &&
|
|
913
|
-
|
|
914
|
-
for (const [key, value] of
|
|
915
|
-
if (key
|
|
931
|
+
let responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders;
|
|
932
|
+
if (typeof arg === "object" && arg.headers) {
|
|
933
|
+
responseHeaders ??= new Headers();
|
|
934
|
+
for (const [key, value] of new Headers(arg.headers)) {
|
|
935
|
+
if (key === "set-cookie") {
|
|
916
936
|
responseHeaders.append(key, value);
|
|
917
937
|
} else {
|
|
918
938
|
responseHeaders.set(key, value);
|
|
@@ -920,19 +940,34 @@ var Context = class {
|
|
|
920
940
|
}
|
|
921
941
|
}
|
|
922
942
|
if (headers) {
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
943
|
+
if (!responseHeaders) {
|
|
944
|
+
let count = 0;
|
|
945
|
+
for (const k in headers) {
|
|
946
|
+
if (++count > 1 || typeof headers[k] !== "string") {
|
|
947
|
+
responseHeaders = new Headers();
|
|
948
|
+
break;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
if (responseHeaders) {
|
|
953
|
+
for (const k in headers) {
|
|
954
|
+
const v = headers[k];
|
|
955
|
+
if (typeof v === "string") {
|
|
956
|
+
responseHeaders.set(k, v);
|
|
957
|
+
} else {
|
|
958
|
+
responseHeaders.delete(k);
|
|
959
|
+
for (const v2 of v) {
|
|
960
|
+
responseHeaders.append(k, v2);
|
|
961
|
+
}
|
|
930
962
|
}
|
|
931
963
|
}
|
|
932
964
|
}
|
|
933
965
|
}
|
|
934
966
|
const status = typeof arg === "number" ? arg : arg?.status ?? this.#status;
|
|
935
|
-
return createResponseInstance(data, {
|
|
967
|
+
return createResponseInstance(data, {
|
|
968
|
+
status,
|
|
969
|
+
headers: responseHeaders ?? headers
|
|
970
|
+
});
|
|
936
971
|
}
|
|
937
972
|
newResponse = (...args) => this.#newResponse(...args);
|
|
938
973
|
/**
|
|
@@ -1042,18 +1077,18 @@ var Context = class {
|
|
|
1042
1077
|
};
|
|
1043
1078
|
};
|
|
1044
1079
|
|
|
1045
|
-
// ../node_modules/.bun/hono@4.
|
|
1080
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router.js
|
|
1046
1081
|
var METHOD_NAME_ALL = "ALL";
|
|
1047
1082
|
var METHOD_NAME_ALL_LOWERCASE = "all";
|
|
1048
|
-
var METHODS = ["get", "post", "put", "delete", "options", "patch"];
|
|
1083
|
+
var METHODS = ["get", "post", "put", "delete", "options", "patch", "query"];
|
|
1049
1084
|
var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
|
|
1050
1085
|
var UnsupportedPathError = class extends Error {
|
|
1051
1086
|
};
|
|
1052
1087
|
|
|
1053
|
-
// ../node_modules/.bun/hono@4.
|
|
1088
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/utils/constants.js
|
|
1054
1089
|
var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
|
|
1055
1090
|
|
|
1056
|
-
// ../node_modules/.bun/hono@4.
|
|
1091
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/hono-base.js
|
|
1057
1092
|
var notFoundHandler = (c) => {
|
|
1058
1093
|
return c.text("404 Not Found", 404);
|
|
1059
1094
|
};
|
|
@@ -1072,6 +1107,7 @@ var Hono = class _Hono {
|
|
|
1072
1107
|
delete;
|
|
1073
1108
|
options;
|
|
1074
1109
|
patch;
|
|
1110
|
+
query;
|
|
1075
1111
|
all;
|
|
1076
1112
|
on;
|
|
1077
1113
|
use;
|
|
@@ -1371,8 +1407,8 @@ var Hono = class _Hono {
|
|
|
1371
1407
|
* @see {@link https://hono.dev/docs/api/hono#fetch}
|
|
1372
1408
|
*
|
|
1373
1409
|
* @param {Request} request - request Object of request
|
|
1374
|
-
* @param {Env}
|
|
1375
|
-
* @param {ExecutionContext} - context of execution
|
|
1410
|
+
* @param {Env} env - env Object
|
|
1411
|
+
* @param {ExecutionContext} executionCtx - context of execution
|
|
1376
1412
|
* @returns {Response | Promise<Response>} response of request
|
|
1377
1413
|
*
|
|
1378
1414
|
*/
|
|
@@ -1429,7 +1465,7 @@ var Hono = class _Hono {
|
|
|
1429
1465
|
};
|
|
1430
1466
|
};
|
|
1431
1467
|
|
|
1432
|
-
// ../node_modules/.bun/hono@4.
|
|
1468
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/reg-exp-router/matcher.js
|
|
1433
1469
|
var emptyParam = [];
|
|
1434
1470
|
function match(method, path) {
|
|
1435
1471
|
const matchers = this.buildAllMatchers();
|
|
@@ -1450,7 +1486,7 @@ function match(method, path) {
|
|
|
1450
1486
|
return match2(method, path);
|
|
1451
1487
|
}
|
|
1452
1488
|
|
|
1453
|
-
// ../node_modules/.bun/hono@4.
|
|
1489
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/reg-exp-router/node.js
|
|
1454
1490
|
var LABEL_REG_EXP_STR = "[^/]+";
|
|
1455
1491
|
var ONLY_WILDCARD_REG_EXP_STR = ".*";
|
|
1456
1492
|
var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
|
|
@@ -1464,7 +1500,7 @@ function compareKey(a, b) {
|
|
|
1464
1500
|
return 1;
|
|
1465
1501
|
}
|
|
1466
1502
|
if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) {
|
|
1467
|
-
return 1;
|
|
1503
|
+
return b === TAIL_WILDCARD_REG_EXP_STR ? -1 : 1;
|
|
1468
1504
|
} else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) {
|
|
1469
1505
|
return -1;
|
|
1470
1506
|
}
|
|
@@ -1476,76 +1512,75 @@ function compareKey(a, b) {
|
|
|
1476
1512
|
return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length;
|
|
1477
1513
|
}
|
|
1478
1514
|
var Node = class _Node {
|
|
1515
|
+
// handler index of a dynamic path, or -1 for a static path terminal
|
|
1479
1516
|
#index;
|
|
1480
1517
|
#varIndex;
|
|
1481
1518
|
#children = /* @__PURE__ */ Object.create(null);
|
|
1482
|
-
insert(tokens, index, paramMap, context,
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
}
|
|
1503
|
-
regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
|
|
1504
|
-
if (/\((?!\?:)/.test(regexpStr)) {
|
|
1505
|
-
throw PATH_ERROR;
|
|
1506
|
-
}
|
|
1507
|
-
}
|
|
1508
|
-
node = this.#children[regexpStr];
|
|
1509
|
-
if (!node) {
|
|
1510
|
-
if (Object.keys(this.#children).some(
|
|
1511
|
-
(k) => k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
|
|
1512
|
-
)) {
|
|
1513
|
-
throw PATH_ERROR;
|
|
1519
|
+
insert(tokens, index, paramMap, context, isStatic) {
|
|
1520
|
+
let node = this;
|
|
1521
|
+
for (let i = 0, len = tokens.length; i < len; i++) {
|
|
1522
|
+
const token = tokens[i];
|
|
1523
|
+
const pattern = token.length === 1 ? token === "*" ? i === len - 1 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : null : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
1524
|
+
let nextNode;
|
|
1525
|
+
if (pattern) {
|
|
1526
|
+
const name = pattern[1];
|
|
1527
|
+
let regexpStr = pattern[2] || LABEL_REG_EXP_STR;
|
|
1528
|
+
if (name && pattern[2]) {
|
|
1529
|
+
if (regexpStr === ".*") {
|
|
1530
|
+
throw PATH_ERROR;
|
|
1531
|
+
}
|
|
1532
|
+
regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
|
|
1533
|
+
if (/\((?!\?:)/.test(regexpStr)) {
|
|
1534
|
+
throw PATH_ERROR;
|
|
1535
|
+
}
|
|
1536
|
+
if (regexpStr.length === 1 && regExpMetaChars.has(regexpStr)) {
|
|
1537
|
+
throw PATH_ERROR;
|
|
1538
|
+
}
|
|
1514
1539
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1540
|
+
nextNode = node.#children[regexpStr];
|
|
1541
|
+
if (!nextNode) {
|
|
1542
|
+
if (regexpStr !== ONLY_WILDCARD_REG_EXP_STR && regexpStr !== TAIL_WILDCARD_REG_EXP_STR) {
|
|
1543
|
+
for (const k in node.#children) {
|
|
1544
|
+
if (
|
|
1545
|
+
// a single-char pattern coexists with single-char literals as a literal does
|
|
1546
|
+
(regexpStr.length > 1 || k.length > 1) && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
|
|
1547
|
+
) {
|
|
1548
|
+
throw PATH_ERROR;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
nextNode = node.#children[regexpStr] = new _Node();
|
|
1517
1553
|
}
|
|
1518
|
-
node = this.#children[regexpStr] = new _Node();
|
|
1519
1554
|
if (name !== "") {
|
|
1520
|
-
|
|
1555
|
+
nextNode.#varIndex ??= context.varIndex++;
|
|
1556
|
+
paramMap.push([name, nextNode.#varIndex]);
|
|
1521
1557
|
}
|
|
1522
|
-
}
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
)) {
|
|
1532
|
-
throw PATH_ERROR;
|
|
1533
|
-
}
|
|
1534
|
-
if (pathErrorCheckOnly) {
|
|
1535
|
-
return;
|
|
1558
|
+
} else {
|
|
1559
|
+
nextNode = node.#children[token];
|
|
1560
|
+
if (!nextNode) {
|
|
1561
|
+
for (const k in node.#children) {
|
|
1562
|
+
if (k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR) {
|
|
1563
|
+
throw PATH_ERROR;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
nextNode = node.#children[token] = new _Node();
|
|
1536
1567
|
}
|
|
1537
|
-
node = this.#children[token] = new _Node();
|
|
1538
1568
|
}
|
|
1569
|
+
node = nextNode;
|
|
1570
|
+
}
|
|
1571
|
+
if (node.#index !== void 0) {
|
|
1572
|
+
throw PATH_ERROR;
|
|
1539
1573
|
}
|
|
1540
|
-
node
|
|
1574
|
+
node.#index = isStatic ? -1 : index;
|
|
1541
1575
|
}
|
|
1542
1576
|
buildRegExpStr() {
|
|
1543
1577
|
const childKeys = Object.keys(this.#children).sort(compareKey);
|
|
1544
1578
|
const strList = childKeys.map((k) => {
|
|
1545
1579
|
const c = this.#children[k];
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1580
|
+
const childStr = c.buildRegExpStr();
|
|
1581
|
+
return childStr === "" ? "" : (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + childStr;
|
|
1582
|
+
}).filter(Boolean);
|
|
1583
|
+
if (typeof this.#index === "number" && this.#index !== -1) {
|
|
1549
1584
|
strList.unshift(`#${this.#index}`);
|
|
1550
1585
|
}
|
|
1551
1586
|
if (strList.length === 0) {
|
|
@@ -1558,16 +1593,24 @@ var Node = class _Node {
|
|
|
1558
1593
|
}
|
|
1559
1594
|
};
|
|
1560
1595
|
|
|
1561
|
-
// ../node_modules/.bun/hono@4.
|
|
1596
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/reg-exp-router/trie.js
|
|
1562
1597
|
var Trie = class {
|
|
1563
1598
|
#context = { varIndex: 0 };
|
|
1564
1599
|
#root = new Node();
|
|
1565
|
-
|
|
1600
|
+
#index = 0;
|
|
1601
|
+
// dynamic path -> [handler index, param assoc]; static paths are not registered
|
|
1602
|
+
paths = /* @__PURE__ */ Object.create(null);
|
|
1603
|
+
insert(path, isStatic) {
|
|
1604
|
+
if (isStatic) {
|
|
1605
|
+
this.#root.insert(path.split(""), 0, [], this.#context, true);
|
|
1606
|
+
return;
|
|
1607
|
+
}
|
|
1566
1608
|
const paramAssoc = [];
|
|
1567
1609
|
const groups = [];
|
|
1610
|
+
let markedPath = path;
|
|
1568
1611
|
for (let i = 0; ; ) {
|
|
1569
1612
|
let replaced = false;
|
|
1570
|
-
|
|
1613
|
+
markedPath = markedPath.replace(/\{[^}]+\}/g, (m) => {
|
|
1571
1614
|
const mark = `@\\${i}`;
|
|
1572
1615
|
groups[i] = [mark, m];
|
|
1573
1616
|
i++;
|
|
@@ -1578,7 +1621,7 @@ var Trie = class {
|
|
|
1578
1621
|
break;
|
|
1579
1622
|
}
|
|
1580
1623
|
}
|
|
1581
|
-
const tokens =
|
|
1624
|
+
const tokens = markedPath.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
|
|
1582
1625
|
for (let i = groups.length - 1; i >= 0; i--) {
|
|
1583
1626
|
const [mark] = groups[i];
|
|
1584
1627
|
for (let j = tokens.length - 1; j >= 0; j--) {
|
|
@@ -1588,8 +1631,8 @@ var Trie = class {
|
|
|
1588
1631
|
}
|
|
1589
1632
|
}
|
|
1590
1633
|
}
|
|
1591
|
-
this.#root.insert(tokens, index, paramAssoc, this.#context,
|
|
1592
|
-
|
|
1634
|
+
this.#root.insert(tokens, this.#index, paramAssoc, this.#context, false);
|
|
1635
|
+
this.paths[path] = [this.#index++, paramAssoc];
|
|
1593
1636
|
}
|
|
1594
1637
|
buildRegExp() {
|
|
1595
1638
|
let regexp = this.#root.buildRegExpStr();
|
|
@@ -1614,8 +1657,7 @@ var Trie = class {
|
|
|
1614
1657
|
}
|
|
1615
1658
|
};
|
|
1616
1659
|
|
|
1617
|
-
// ../node_modules/.bun/hono@4.
|
|
1618
|
-
var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
|
|
1660
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/reg-exp-router/router.js
|
|
1619
1661
|
var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
|
|
1620
1662
|
function buildWildcardRegExp(path) {
|
|
1621
1663
|
return wildcardRegExpCache[path] ??= new RegExp(
|
|
@@ -1628,63 +1670,6 @@ function buildWildcardRegExp(path) {
|
|
|
1628
1670
|
function clearWildcardRegExpCache() {
|
|
1629
1671
|
wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
|
|
1630
1672
|
}
|
|
1631
|
-
function buildMatcherFromPreprocessedRoutes(routes) {
|
|
1632
|
-
const trie = new Trie();
|
|
1633
|
-
const handlerData = [];
|
|
1634
|
-
if (routes.length === 0) {
|
|
1635
|
-
return nullMatcher;
|
|
1636
|
-
}
|
|
1637
|
-
const routesWithStaticPathFlag = routes.map(
|
|
1638
|
-
(route) => [!/\*|\/:/.test(route[0]), ...route]
|
|
1639
|
-
).sort(
|
|
1640
|
-
([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length
|
|
1641
|
-
);
|
|
1642
|
-
const staticMap = /* @__PURE__ */ Object.create(null);
|
|
1643
|
-
for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) {
|
|
1644
|
-
const [pathErrorCheckOnly, path, handlers] = routesWithStaticPathFlag[i];
|
|
1645
|
-
if (pathErrorCheckOnly) {
|
|
1646
|
-
staticMap[path] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
|
|
1647
|
-
} else {
|
|
1648
|
-
j++;
|
|
1649
|
-
}
|
|
1650
|
-
let paramAssoc;
|
|
1651
|
-
try {
|
|
1652
|
-
paramAssoc = trie.insert(path, j, pathErrorCheckOnly);
|
|
1653
|
-
} catch (e) {
|
|
1654
|
-
throw e === PATH_ERROR ? new UnsupportedPathError(path) : e;
|
|
1655
|
-
}
|
|
1656
|
-
if (pathErrorCheckOnly) {
|
|
1657
|
-
continue;
|
|
1658
|
-
}
|
|
1659
|
-
handlerData[j] = handlers.map(([h, paramCount]) => {
|
|
1660
|
-
const paramIndexMap = /* @__PURE__ */ Object.create(null);
|
|
1661
|
-
paramCount -= 1;
|
|
1662
|
-
for (; paramCount >= 0; paramCount--) {
|
|
1663
|
-
const [key, value] = paramAssoc[paramCount];
|
|
1664
|
-
paramIndexMap[key] = value;
|
|
1665
|
-
}
|
|
1666
|
-
return [h, paramIndexMap];
|
|
1667
|
-
});
|
|
1668
|
-
}
|
|
1669
|
-
const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
|
|
1670
|
-
for (let i = 0, len = handlerData.length; i < len; i++) {
|
|
1671
|
-
for (let j = 0, len2 = handlerData[i].length; j < len2; j++) {
|
|
1672
|
-
const map = handlerData[i][j]?.[1];
|
|
1673
|
-
if (!map) {
|
|
1674
|
-
continue;
|
|
1675
|
-
}
|
|
1676
|
-
const keys = Object.keys(map);
|
|
1677
|
-
for (let k = 0, len3 = keys.length; k < len3; k++) {
|
|
1678
|
-
map[keys[k]] = paramReplacementMap[map[keys[k]]];
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
}
|
|
1682
|
-
const handlerMap = [];
|
|
1683
|
-
for (const i in indexReplacementMap) {
|
|
1684
|
-
handlerMap[i] = handlerData[indexReplacementMap[i]];
|
|
1685
|
-
}
|
|
1686
|
-
return [regexp, handlerMap, staticMap];
|
|
1687
|
-
}
|
|
1688
1673
|
function findMiddleware(middleware, path) {
|
|
1689
1674
|
if (!middleware) {
|
|
1690
1675
|
return void 0;
|
|
@@ -1700,9 +1685,18 @@ var RegExpRouter = class {
|
|
|
1700
1685
|
name = "RegExpRouter";
|
|
1701
1686
|
#middleware;
|
|
1702
1687
|
#routes;
|
|
1688
|
+
#tries;
|
|
1703
1689
|
constructor() {
|
|
1704
1690
|
this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
|
|
1705
1691
|
this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
|
|
1692
|
+
this.#tries = { [METHOD_NAME_ALL]: new Trie() };
|
|
1693
|
+
}
|
|
1694
|
+
#insertPath(method, path) {
|
|
1695
|
+
try {
|
|
1696
|
+
this.#tries[method].insert(path, !/\*|\/:/.test(path));
|
|
1697
|
+
} catch (e) {
|
|
1698
|
+
throw e === PATH_ERROR ? new UnsupportedPathError(path) : e;
|
|
1699
|
+
}
|
|
1706
1700
|
}
|
|
1707
1701
|
add(method, path, handler) {
|
|
1708
1702
|
const middleware = this.#middleware;
|
|
@@ -1711,10 +1705,12 @@ var RegExpRouter = class {
|
|
|
1711
1705
|
throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
|
|
1712
1706
|
}
|
|
1713
1707
|
if (!middleware[method]) {
|
|
1708
|
+
this.#tries[method] = new Trie();
|
|
1714
1709
|
[middleware, routes].forEach((handlerMap) => {
|
|
1715
1710
|
handlerMap[method] = /* @__PURE__ */ Object.create(null);
|
|
1716
1711
|
Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p) => {
|
|
1717
1712
|
handlerMap[method][p] = [...handlerMap[METHOD_NAME_ALL][p]];
|
|
1713
|
+
this.#insertPath(method, p);
|
|
1718
1714
|
});
|
|
1719
1715
|
});
|
|
1720
1716
|
}
|
|
@@ -1724,13 +1720,12 @@ var RegExpRouter = class {
|
|
|
1724
1720
|
const paramCount = (path.match(/\/:/g) || []).length;
|
|
1725
1721
|
if (/\*$/.test(path)) {
|
|
1726
1722
|
const re = buildWildcardRegExp(path);
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
}
|
|
1723
|
+
Object.keys(middleware).forEach((m) => {
|
|
1724
|
+
if ((method === METHOD_NAME_ALL || method === m) && !middleware[m][path]) {
|
|
1725
|
+
this.#insertPath(m, path);
|
|
1726
|
+
middleware[m][path] = findMiddleware(middleware[m], path) || findMiddleware(middleware[METHOD_NAME_ALL], path) || [];
|
|
1727
|
+
}
|
|
1728
|
+
});
|
|
1734
1729
|
Object.keys(middleware).forEach((m) => {
|
|
1735
1730
|
if (method === METHOD_NAME_ALL || method === m) {
|
|
1736
1731
|
Object.keys(middleware[m]).forEach((p) => {
|
|
@@ -1752,9 +1747,12 @@ var RegExpRouter = class {
|
|
|
1752
1747
|
const path2 = paths[i];
|
|
1753
1748
|
Object.keys(routes).forEach((m) => {
|
|
1754
1749
|
if (method === METHOD_NAME_ALL || method === m) {
|
|
1755
|
-
routes[m][path2]
|
|
1756
|
-
|
|
1757
|
-
|
|
1750
|
+
if (!routes[m][path2]) {
|
|
1751
|
+
this.#insertPath(m, path2);
|
|
1752
|
+
routes[m][path2] = [
|
|
1753
|
+
...findMiddleware(middleware[m], path2) || findMiddleware(middleware[METHOD_NAME_ALL], path2) || []
|
|
1754
|
+
];
|
|
1755
|
+
}
|
|
1758
1756
|
routes[m][path2].push([handler, paramCount - len + i + 1]);
|
|
1759
1757
|
}
|
|
1760
1758
|
});
|
|
@@ -1766,33 +1764,58 @@ var RegExpRouter = class {
|
|
|
1766
1764
|
Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => {
|
|
1767
1765
|
matchers[method] ||= this.#buildMatcher(method);
|
|
1768
1766
|
});
|
|
1769
|
-
this.#middleware = this.#routes = void 0;
|
|
1767
|
+
this.#middleware = this.#routes = this.#tries = void 0;
|
|
1770
1768
|
clearWildcardRegExpCache();
|
|
1771
1769
|
return matchers;
|
|
1772
1770
|
}
|
|
1773
1771
|
#buildMatcher(method) {
|
|
1774
|
-
const
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1772
|
+
const middleware = this.#middleware[method];
|
|
1773
|
+
const routes = this.#routes[method];
|
|
1774
|
+
const trie = this.#tries[method];
|
|
1775
|
+
const staticMap = /* @__PURE__ */ Object.create(null);
|
|
1776
|
+
const handlerData = [];
|
|
1777
|
+
[middleware, routes].forEach((r) => {
|
|
1778
|
+
for (const path in r) {
|
|
1779
|
+
const handlers = r[path];
|
|
1780
|
+
const pathData = trie.paths[path];
|
|
1781
|
+
if (!pathData) {
|
|
1782
|
+
staticMap[path] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
|
|
1783
|
+
continue;
|
|
1784
|
+
}
|
|
1785
|
+
const paramAssoc = pathData[1];
|
|
1786
|
+
handlerData[pathData[0]] = handlers.map(([h, paramCount]) => {
|
|
1787
|
+
const paramIndexMap = /* @__PURE__ */ Object.create(null);
|
|
1788
|
+
paramCount -= 1;
|
|
1789
|
+
for (; paramCount >= 0; paramCount--) {
|
|
1790
|
+
const [key, value] = paramAssoc[paramCount];
|
|
1791
|
+
paramIndexMap[key] = value;
|
|
1792
|
+
}
|
|
1793
|
+
return [h, paramIndexMap];
|
|
1794
|
+
});
|
|
1785
1795
|
}
|
|
1786
1796
|
});
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1797
|
+
const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
|
|
1798
|
+
for (let i = 0, len = handlerData.length; i < len; i++) {
|
|
1799
|
+
for (let j = 0, len2 = handlerData[i].length; j < len2; j++) {
|
|
1800
|
+
const map = handlerData[i][j]?.[1];
|
|
1801
|
+
if (!map) {
|
|
1802
|
+
continue;
|
|
1803
|
+
}
|
|
1804
|
+
const keys = Object.keys(map);
|
|
1805
|
+
for (let k = 0, len3 = keys.length; k < len3; k++) {
|
|
1806
|
+
map[keys[k]] = paramReplacementMap[map[keys[k]]];
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
const handlerMap = [];
|
|
1811
|
+
for (const i in indexReplacementMap) {
|
|
1812
|
+
handlerMap[i] = handlerData[indexReplacementMap[i]];
|
|
1791
1813
|
}
|
|
1814
|
+
return [regexp, handlerMap, staticMap];
|
|
1792
1815
|
}
|
|
1793
1816
|
};
|
|
1794
1817
|
|
|
1795
|
-
// ../node_modules/.bun/hono@4.
|
|
1818
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/smart-router/router.js
|
|
1796
1819
|
var SmartRouter = class {
|
|
1797
1820
|
name = "SmartRouter";
|
|
1798
1821
|
#routers = [];
|
|
@@ -1847,7 +1870,7 @@ var SmartRouter = class {
|
|
|
1847
1870
|
}
|
|
1848
1871
|
};
|
|
1849
1872
|
|
|
1850
|
-
// ../node_modules/.bun/hono@4.
|
|
1873
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/trie-router/node.js
|
|
1851
1874
|
var emptyParams = /* @__PURE__ */ Object.create(null);
|
|
1852
1875
|
var hasChildren = (children) => {
|
|
1853
1876
|
for (const _ in children) {
|
|
@@ -1981,9 +2004,18 @@ var Node2 = class _Node2 {
|
|
|
1981
2004
|
if (m) {
|
|
1982
2005
|
params[name] = m[0];
|
|
1983
2006
|
this.#pushHandlerSets(handlerSets, child, method, node.#params, params);
|
|
2007
|
+
if (m[0].length === restPathString.length && child.#children["*"]) {
|
|
2008
|
+
this.#pushHandlerSets(
|
|
2009
|
+
handlerSets,
|
|
2010
|
+
child.#children["*"],
|
|
2011
|
+
method,
|
|
2012
|
+
node.#params,
|
|
2013
|
+
params
|
|
2014
|
+
);
|
|
2015
|
+
}
|
|
1984
2016
|
if (hasChildren(child.#children)) {
|
|
1985
2017
|
child.#params = params;
|
|
1986
|
-
const componentCount = m[0].match(/\//)?.length ?? 0;
|
|
2018
|
+
const componentCount = m[0].match(/\//g)?.length ?? 0;
|
|
1987
2019
|
const targetCurNodes = curNodesQueue[componentCount] ||= [];
|
|
1988
2020
|
targetCurNodes.push(child);
|
|
1989
2021
|
}
|
|
@@ -2022,7 +2054,7 @@ var Node2 = class _Node2 {
|
|
|
2022
2054
|
}
|
|
2023
2055
|
};
|
|
2024
2056
|
|
|
2025
|
-
// ../node_modules/.bun/hono@4.
|
|
2057
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/trie-router/router.js
|
|
2026
2058
|
var TrieRouter = class {
|
|
2027
2059
|
name = "TrieRouter";
|
|
2028
2060
|
#node;
|
|
@@ -2044,7 +2076,7 @@ var TrieRouter = class {
|
|
|
2044
2076
|
}
|
|
2045
2077
|
};
|
|
2046
2078
|
|
|
2047
|
-
// ../node_modules/.bun/hono@4.
|
|
2079
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/hono.js
|
|
2048
2080
|
var Hono2 = class extends Hono {
|
|
2049
2081
|
/**
|
|
2050
2082
|
* Creates an instance of the Hono class.
|
|
@@ -2060,9 +2092,75 @@ var Hono2 = class extends Hono {
|
|
|
2060
2092
|
};
|
|
2061
2093
|
|
|
2062
2094
|
// src/types/common.ts
|
|
2095
|
+
var SUPPORTED_CURRENCY_CODES = /* @__PURE__ */ new Set([
|
|
2096
|
+
"USD",
|
|
2097
|
+
"EUR",
|
|
2098
|
+
"GBP",
|
|
2099
|
+
"JPY",
|
|
2100
|
+
"CNY",
|
|
2101
|
+
"CHF",
|
|
2102
|
+
"CAD",
|
|
2103
|
+
"AUD",
|
|
2104
|
+
"GHS",
|
|
2105
|
+
"NGN",
|
|
2106
|
+
"KES",
|
|
2107
|
+
"ZAR",
|
|
2108
|
+
"XOF",
|
|
2109
|
+
"XAF",
|
|
2110
|
+
"EGP",
|
|
2111
|
+
"TZS",
|
|
2112
|
+
"UGX",
|
|
2113
|
+
"RWF",
|
|
2114
|
+
"ETB",
|
|
2115
|
+
"ZMW",
|
|
2116
|
+
"BWP",
|
|
2117
|
+
"MUR",
|
|
2118
|
+
"NAD",
|
|
2119
|
+
"MWK",
|
|
2120
|
+
"AOA",
|
|
2121
|
+
"CDF",
|
|
2122
|
+
"GMD",
|
|
2123
|
+
"GNF",
|
|
2124
|
+
"LRD",
|
|
2125
|
+
"SLL",
|
|
2126
|
+
"MZN",
|
|
2127
|
+
"BIF",
|
|
2128
|
+
"INR",
|
|
2129
|
+
"BRL",
|
|
2130
|
+
"COP",
|
|
2131
|
+
"MXN",
|
|
2132
|
+
"KRW",
|
|
2133
|
+
"TRY",
|
|
2134
|
+
"THB",
|
|
2135
|
+
"MYR",
|
|
2136
|
+
"PHP",
|
|
2137
|
+
"IDR",
|
|
2138
|
+
"VND",
|
|
2139
|
+
"SGD",
|
|
2140
|
+
"HKD",
|
|
2141
|
+
"TWD",
|
|
2142
|
+
"AED",
|
|
2143
|
+
"SAR",
|
|
2144
|
+
"ILS"
|
|
2145
|
+
]);
|
|
2146
|
+
function isSupportedCurrency(code) {
|
|
2147
|
+
return SUPPORTED_CURRENCY_CODES.has(code);
|
|
2148
|
+
}
|
|
2149
|
+
var warnedCurrencies = /* @__PURE__ */ new Set();
|
|
2150
|
+
function currencyCode(value) {
|
|
2151
|
+
const normalized = value.trim().toUpperCase();
|
|
2152
|
+
if (!isSupportedCurrency(normalized) && !warnedCurrencies.has(normalized)) {
|
|
2153
|
+
warnedCurrencies.add(normalized);
|
|
2154
|
+
console.warn(
|
|
2155
|
+
`[Cimplify] Unrecognized currency code "${normalized}". It may not format correctly.`
|
|
2156
|
+
);
|
|
2157
|
+
}
|
|
2158
|
+
return normalized;
|
|
2159
|
+
}
|
|
2063
2160
|
var ErrorCode = {
|
|
2064
2161
|
NOT_FOUND: "NOT_FOUND",
|
|
2065
|
-
VALIDATION_ERROR: "VALIDATION_ERROR"
|
|
2162
|
+
VALIDATION_ERROR: "VALIDATION_ERROR",
|
|
2163
|
+
CART_EMPTY: "CART_EMPTY"};
|
|
2066
2164
|
var DOCS_ERROR_BASE_URL = "https://docs.cimplify.io/reference/error-codes";
|
|
2067
2165
|
function docsUrlForCode(code) {
|
|
2068
2166
|
return `${DOCS_ERROR_BASE_URL}#${code.toLowerCase().replace(/_/g, "-")}`;
|
|
@@ -2120,6 +2218,10 @@ var ERROR_SUGGESTIONS = {
|
|
|
2120
2218
|
CHECKOUT_NOT_READY: "Checkout elements are still initializing. Wait for readiness before submit.",
|
|
2121
2219
|
CANCELLED: "Checkout was cancelled. Preserve cart state and allow shopper to retry.",
|
|
2122
2220
|
REQUEST_TIMEOUT: "Provider call timed out. Poll payment/order status before issuing another charge attempt.",
|
|
2221
|
+
CHECKOUT_AUTHORITY_REQUIRED: "Provide an exact cart or purchase-intent authority before starting checkout.",
|
|
2222
|
+
AUTH_CONFIG_REQUIRED: "Configure the OAuth client and redirect URI before mounting embedded authentication.",
|
|
2223
|
+
AUTH_CALLBACK_MISSING_TOKEN: "The authentication callback returned no access token. Restart sign-in before checkout.",
|
|
2224
|
+
AUTH_START_FAILED: "Embedded authentication could not start. Verify the OAuth configuration and retry.",
|
|
2123
2225
|
POPUP_BLOCKED: "Browser blocked provider popup. Ask shopper to enable popups and retry.",
|
|
2124
2226
|
FX_QUOTE_FAILED: "Failed to lock FX quote. Retry currency quote or fallback to base currency."
|
|
2125
2227
|
};
|
|
@@ -2163,7 +2265,7 @@ function authMiddleware(deps) {
|
|
|
2163
2265
|
await next();
|
|
2164
2266
|
};
|
|
2165
2267
|
}
|
|
2166
|
-
var IDEMPOTENT_PATH_RE = /\/(cart\/items|cart\/coupons|checkout|payments\/authorization|auth\/(request-otp|verify-otp|profile|logout))(\/|$)/;
|
|
2268
|
+
var IDEMPOTENT_PATH_RE = /\/(cart\/items|cart\/coupons|checkout|purchase-intents|payments\/authorization|auth\/(request-otp|verify-otp|profile|logout))(\/|$)/;
|
|
2167
2269
|
var IDEMPOTENCY_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2168
2270
|
function idempotencyMiddleware(deps) {
|
|
2169
2271
|
return async (c, next) => {
|
|
@@ -2173,7 +2275,8 @@ function idempotencyMiddleware(deps) {
|
|
|
2173
2275
|
const key = c.req.header("idempotency-key") ?? c.req.header("Idempotency-Key");
|
|
2174
2276
|
if (!key || key.length > 200) return next();
|
|
2175
2277
|
const session = c.var.session;
|
|
2176
|
-
const
|
|
2278
|
+
const routeScope = c.req.path.includes("/purchase-intents") ? `:${c.req.path}` : "";
|
|
2279
|
+
const recordId = `${session.id}${routeScope}:${key}`;
|
|
2177
2280
|
const existing = deps.registry.idempotency.get(recordId);
|
|
2178
2281
|
if (existing) {
|
|
2179
2282
|
const expiresAt = Date.parse(existing.expires_at);
|
|
@@ -2251,8 +2354,89 @@ var PAYMENT_METHOD = {
|
|
|
2251
2354
|
MOBILE_MONEY: "mobile_money",
|
|
2252
2355
|
CARD: "card"
|
|
2253
2356
|
};
|
|
2357
|
+
var CHECKOUT_NEXT_ACTION = {
|
|
2358
|
+
NONE: "none"};
|
|
2359
|
+
var CHECKOUT_ORDER_RESULT_STATUS = {
|
|
2360
|
+
CONFIRMED: "confirmed"};
|
|
2361
|
+
var AUTHORIZATION_TYPE = {
|
|
2362
|
+
OTP: "otp"};
|
|
2363
|
+
var DEFAULT_CURRENCY = "GHS";
|
|
2364
|
+
|
|
2365
|
+
// src/types/purchase-intent.ts
|
|
2366
|
+
var PURCHASE_INTENT_SOURCE_KIND = {
|
|
2367
|
+
CART: "cart"};
|
|
2368
|
+
var PURCHASING_PRINCIPAL_KIND = {
|
|
2369
|
+
ACCOUNT: "account",
|
|
2370
|
+
BUSINESS: "business",
|
|
2371
|
+
GUEST: "guest"};
|
|
2372
|
+
var PURCHASE_INTENT_STATUS = {
|
|
2373
|
+
OPEN: "open",
|
|
2374
|
+
CONVERTED: "converted"};
|
|
2375
|
+
var PURCHASE_INTENT_SELLABLE_KIND = {
|
|
2376
|
+
PRODUCT: "product",
|
|
2377
|
+
VARIANT: "variant"
|
|
2378
|
+
};
|
|
2379
|
+
var PURCHASE_INTENT_LINE_CONFIGURATION_KIND = {
|
|
2380
|
+
SIMPLE: "simple"};
|
|
2381
|
+
var MOBILE_MONEY_TENDER_AUTHORITY_KIND = {
|
|
2382
|
+
TRANSIENT: "transient"};
|
|
2383
|
+
var PURCHASE_INTENT_MOBILE_MONEY_NETWORK = {
|
|
2384
|
+
MTN: "mtn",
|
|
2385
|
+
TELECEL: "telecel",
|
|
2386
|
+
AIRTEL: "airtel"
|
|
2387
|
+
};
|
|
2388
|
+
var CHECKOUT_COMPLIANCE_LANE = {
|
|
2389
|
+
NATIVE: "native"};
|
|
2390
|
+
var CHECKOUT_COMPLIANCE_REASON = {
|
|
2391
|
+
PHYSICAL_GOODS_NATIVE: "physical_goods_native"};
|
|
2392
|
+
var PURCHASE_INTENT_PAYMENT_METHOD = {
|
|
2393
|
+
CARD: "card",
|
|
2394
|
+
MOBILE_MONEY: "mobile_money"};
|
|
2395
|
+
var PAYMENT_COLLECTION_MODE = {
|
|
2396
|
+
REQUEST_TO_PAY: "request_to_pay",
|
|
2397
|
+
CREDENTIAL_CHARGE: "credential_charge"};
|
|
2398
|
+
var PURCHASE_INTENT_PAYMENT_PROVIDER = {
|
|
2399
|
+
PAYSTACK: "paystack"};
|
|
2400
|
+
var PAYMENT_OPTION_STATUS = {
|
|
2401
|
+
ELIGIBLE: "eligible"};
|
|
2402
|
+
var PAYMENT_OPTION_NEXT_ACTION = {
|
|
2403
|
+
PROVIDER_APPROVAL: "provider_approval"};
|
|
2404
|
+
var LEGACY_CHECKOUT_PAYMENT_STATUS = {
|
|
2405
|
+
SUCCEEDED: "succeeded"};
|
|
2406
|
+
var CHECKOUT_TERMS_COMPONENT = {
|
|
2407
|
+
DUE_NOW: "due_now"};
|
|
2408
|
+
var CHECKOUT_TERMS_DELTA_KIND = {
|
|
2409
|
+
MONEY: "money",
|
|
2410
|
+
PAYMENT_OPTION: "payment_option"
|
|
2411
|
+
};
|
|
2412
|
+
var CHECKOUT_INVALIDATION_REASON = {
|
|
2413
|
+
PAYMENT_OPTION_CHANGED: "payment_option_changed"
|
|
2414
|
+
};
|
|
2415
|
+
var PURCHASE_INTENT_CONFIRM_STATUS = {
|
|
2416
|
+
ORDER_CREATED: "order_created",
|
|
2417
|
+
CARD_POPUP_REQUIRED: "card_popup_required",
|
|
2418
|
+
AUTHORIZATION_REQUIRED: "authorization_required",
|
|
2419
|
+
TERMS_CHANGED: "terms_changed",
|
|
2420
|
+
SELECTION_UNAVAILABLE: "selection_unavailable",
|
|
2421
|
+
SOURCE_UNAVAILABLE: "source_unavailable"
|
|
2422
|
+
};
|
|
2254
2423
|
|
|
2255
2424
|
// src/mock/routes/v1.ts
|
|
2425
|
+
var PURCHASE_INTENT_ROUTE = {
|
|
2426
|
+
COLLECTION: "/purchase-intents",
|
|
2427
|
+
MEMBER: "/purchase-intents/:intent_id",
|
|
2428
|
+
REFRESH: "/purchase-intents/:intent_id/refresh",
|
|
2429
|
+
CONFIRM: "/purchase-intents/:intent_id/confirm",
|
|
2430
|
+
ACTION: "/purchase-intents/:intent_id/attempts/:attempt_id/actions"
|
|
2431
|
+
};
|
|
2432
|
+
var PURCHASE_INTENT_ROUTE_PARAM = {
|
|
2433
|
+
INTENT_ID: "intent_id",
|
|
2434
|
+
ATTEMPT_ID: "attempt_id"
|
|
2435
|
+
};
|
|
2436
|
+
var PAYMENT_ROUTE = {
|
|
2437
|
+
COLLECTION_OPTIONS: "/payments/collection-options",
|
|
2438
|
+
AUTHORIZATION: "/payments/authorization"
|
|
2439
|
+
};
|
|
2256
2440
|
function buildV1(deps) {
|
|
2257
2441
|
const app = new Hono2();
|
|
2258
2442
|
app.use("*", chaosMiddleware(deps));
|
|
@@ -2625,28 +2809,81 @@ function buildV1(deps) {
|
|
|
2625
2809
|
"/subscriptions/:subscription_id/skip",
|
|
2626
2810
|
(c) => tryRoute(c, () => deps.subscriptions.skipNext(c.req.param("subscription_id")))
|
|
2627
2811
|
);
|
|
2628
|
-
app.get(
|
|
2812
|
+
app.get(PAYMENT_ROUTE.COLLECTION_OPTIONS, async (c) => {
|
|
2629
2813
|
const currency = c.req.query("currency")?.trim().toUpperCase();
|
|
2630
2814
|
if (!currency || !/^[A-Z]{3}$/.test(currency)) {
|
|
2631
2815
|
return fail(c, validation("currency must be a canonical three-letter code"));
|
|
2632
2816
|
}
|
|
2633
2817
|
return tryRoute(c, () => ({
|
|
2634
2818
|
presentment_currency: currency,
|
|
2635
|
-
options: currency ===
|
|
2819
|
+
options: currency === DEFAULT_CURRENCY ? [
|
|
2636
2820
|
{ method: PAYMENT_METHOD.CARD, network: null },
|
|
2637
|
-
{
|
|
2638
|
-
|
|
2639
|
-
|
|
2821
|
+
{
|
|
2822
|
+
method: PAYMENT_METHOD.MOBILE_MONEY,
|
|
2823
|
+
network: PURCHASE_INTENT_MOBILE_MONEY_NETWORK.MTN
|
|
2824
|
+
},
|
|
2825
|
+
{
|
|
2826
|
+
method: PAYMENT_METHOD.MOBILE_MONEY,
|
|
2827
|
+
network: PURCHASE_INTENT_MOBILE_MONEY_NETWORK.TELECEL
|
|
2828
|
+
},
|
|
2829
|
+
{
|
|
2830
|
+
method: PAYMENT_METHOD.MOBILE_MONEY,
|
|
2831
|
+
network: PURCHASE_INTENT_MOBILE_MONEY_NETWORK.AIRTEL
|
|
2832
|
+
}
|
|
2640
2833
|
] : currency === "USD" ? [{ method: PAYMENT_METHOD.CARD, network: null }] : []
|
|
2641
2834
|
}));
|
|
2642
2835
|
});
|
|
2643
|
-
app.post(
|
|
2836
|
+
app.post(PURCHASE_INTENT_ROUTE.COLLECTION, async (c) => {
|
|
2837
|
+
const body = await c.req.json().catch(() => ({}));
|
|
2838
|
+
return tryRoute(c, () => deps.purchaseIntents.mint(c.var.session, body));
|
|
2839
|
+
});
|
|
2840
|
+
app.get(
|
|
2841
|
+
PURCHASE_INTENT_ROUTE.MEMBER,
|
|
2842
|
+
(c) => tryRoute(
|
|
2843
|
+
c,
|
|
2844
|
+
() => deps.purchaseIntents.get(
|
|
2845
|
+
c.var.session,
|
|
2846
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.INTENT_ID)
|
|
2847
|
+
)
|
|
2848
|
+
)
|
|
2849
|
+
);
|
|
2850
|
+
app.post(PURCHASE_INTENT_ROUTE.REFRESH, async (c) => {
|
|
2644
2851
|
const body = await c.req.json().catch(() => ({}));
|
|
2645
|
-
return tryRoute(
|
|
2852
|
+
return tryRoute(
|
|
2853
|
+
c,
|
|
2854
|
+
() => deps.purchaseIntents.refresh(
|
|
2855
|
+
c.var.session,
|
|
2856
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.INTENT_ID),
|
|
2857
|
+
body.expected_intent_revision
|
|
2858
|
+
)
|
|
2859
|
+
);
|
|
2646
2860
|
});
|
|
2647
|
-
app.post(
|
|
2861
|
+
app.post(PURCHASE_INTENT_ROUTE.CONFIRM, async (c) => {
|
|
2648
2862
|
const body = await c.req.json().catch(() => ({}));
|
|
2649
|
-
return tryRoute(
|
|
2863
|
+
return tryRoute(
|
|
2864
|
+
c,
|
|
2865
|
+
() => deps.purchaseIntents.confirm(
|
|
2866
|
+
c.var.session,
|
|
2867
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.INTENT_ID),
|
|
2868
|
+
body
|
|
2869
|
+
)
|
|
2870
|
+
);
|
|
2871
|
+
});
|
|
2872
|
+
app.post(PURCHASE_INTENT_ROUTE.ACTION, async (c) => {
|
|
2873
|
+
const body = await c.req.json().catch(() => ({}));
|
|
2874
|
+
return tryRoute(
|
|
2875
|
+
c,
|
|
2876
|
+
() => deps.purchaseIntents.submitAction(
|
|
2877
|
+
c.var.session,
|
|
2878
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.INTENT_ID),
|
|
2879
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.ATTEMPT_ID),
|
|
2880
|
+
body
|
|
2881
|
+
)
|
|
2882
|
+
);
|
|
2883
|
+
});
|
|
2884
|
+
app.post(PAYMENT_ROUTE.AUTHORIZATION, async (c) => {
|
|
2885
|
+
const body = await c.req.json().catch(() => ({}));
|
|
2886
|
+
return tryRoute(c, () => deps.payments.authorize(body));
|
|
2650
2887
|
});
|
|
2651
2888
|
app.get("/auth/status", (c) => tryRoute(c, () => deps.auth.status(c.var.session.token)));
|
|
2652
2889
|
app.post("/auth/request-otp", async (c) => {
|
|
@@ -2952,6 +3189,7 @@ function createStateRegistry() {
|
|
|
2952
3189
|
collections: createMemoryStore(),
|
|
2953
3190
|
carts: createMemoryStore(),
|
|
2954
3191
|
orders: createMemoryStore(),
|
|
3192
|
+
purchaseIntents: createMemoryStore(),
|
|
2955
3193
|
subscriptions: createMemoryStore(),
|
|
2956
3194
|
bookings: createMemoryStore(),
|
|
2957
3195
|
services: createMemoryStore(),
|
|
@@ -3101,9 +3339,9 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3101
3339
|
// injected into the HTML page served by the mock. Edit this file directly \u2014
|
|
3102
3340
|
// type-check via tsgo + the IframeToParentMessage shape from the SDK.
|
|
3103
3341
|
(function () {
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3342
|
+
const TYPE = window.__CIMPLIFY_MOCK_ELEMENT__;
|
|
3343
|
+
const DEFAULT_BUSINESS = window.__CIMPLIFY_MOCK_BUSINESS__;
|
|
3344
|
+
const MSG = {
|
|
3107
3345
|
INIT: "init", SET_TOKEN: "set_token", SET_CART: "set_cart", GET_DATA: "get_data",
|
|
3108
3346
|
REFRESH_TOKEN: "refresh_token", LOGOUT: "logout",
|
|
3109
3347
|
PROCESS_CHECKOUT: "process_checkout", ABORT_CHECKOUT: "abort_checkout",
|
|
@@ -3116,12 +3354,36 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3116
3354
|
CHECKOUT_STATUS: "checkout_status", CHECKOUT_COMPLETE: "checkout_complete",
|
|
3117
3355
|
ORDER_TYPE_CHANGED: "order_type_changed", REQUEST_SUBMIT: "request_submit"
|
|
3118
3356
|
};
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3357
|
+
const PURCHASE_INTENT = {
|
|
3358
|
+
PATH: "/api/v1/purchase-intents",
|
|
3359
|
+
ORDER_CREATED: "order_created",
|
|
3360
|
+
CARD_POPUP_REQUIRED: "card_popup_required",
|
|
3361
|
+
AUTHORIZATION_REQUIRED: "authorization_required",
|
|
3362
|
+
ELIGIBLE: "eligible"
|
|
3363
|
+
};
|
|
3364
|
+
const CHECKOUT_STATUS = {
|
|
3365
|
+
PROCESSING: "processing",
|
|
3366
|
+
SUCCESS: "success",
|
|
3367
|
+
FAILED: "failed"
|
|
3368
|
+
};
|
|
3369
|
+
const CHECKOUT_ERROR = { FAILED: "CHECKOUT_FAILED" };
|
|
3370
|
+
const ORDER_STATUS = { CONFIRMED: "confirmed" };
|
|
3371
|
+
const TENDER = {
|
|
3372
|
+
CARD: "card",
|
|
3373
|
+
MOBILE_MONEY: "mobile_money",
|
|
3374
|
+
AUTHORITY_TRANSIENT: "transient",
|
|
3375
|
+
MTN: "mtn"
|
|
3376
|
+
};
|
|
3377
|
+
const PAYMENT_PROVIDER = { PAYSTACK: "paystack" };
|
|
3378
|
+
const SOURCE_KIND = { CART: "cart" };
|
|
3379
|
+
const AUTHORIZATION = { OTP: "otp" };
|
|
3380
|
+
const EXACT_ZERO_MONEY = /^[+-]?0+(?:\\.0+)?(?:[eE][+-]?\\d+)?$/;
|
|
3381
|
+
const qs = new URLSearchParams(location.search);
|
|
3382
|
+
const AUTO = qs.get("auto") === "true";
|
|
3383
|
+
const DEMO_OTP = qs.get("otp") || "123456";
|
|
3384
|
+
const ORIGIN = qs.get("origin") || "*";
|
|
3385
|
+
const NONCE = qs.get("nonce");
|
|
3386
|
+
const state = {
|
|
3125
3387
|
businessId: DEFAULT_BUSINESS,
|
|
3126
3388
|
token: null,
|
|
3127
3389
|
cart: null,
|
|
@@ -3132,15 +3394,33 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3132
3394
|
contact: null,
|
|
3133
3395
|
pendingOtp: null
|
|
3134
3396
|
};
|
|
3135
|
-
|
|
3136
|
-
|
|
3397
|
+
const content = document.getElementById("content");
|
|
3398
|
+
const title = document.getElementById("title");
|
|
3137
3399
|
|
|
3138
3400
|
function send(msg) {
|
|
3139
3401
|
if (NONCE) msg.nonce = NONCE;
|
|
3140
3402
|
parent.postMessage(msg, ORIGIN);
|
|
3141
3403
|
}
|
|
3404
|
+
function isExactlyZeroMoney(value) {
|
|
3405
|
+
return typeof value === "number"
|
|
3406
|
+
? Object.is(value, 0) || Object.is(value, -0)
|
|
3407
|
+
: EXACT_ZERO_MONEY.test(String(value).trim());
|
|
3408
|
+
}
|
|
3142
3409
|
function reportHeight() { send({ type: MSG.HEIGHT_CHANGE, height: document.documentElement.scrollHeight }); }
|
|
3143
3410
|
function ready() { send({ type: MSG.READY, height: document.documentElement.scrollHeight }); }
|
|
3411
|
+
function responseWithBody(response) {
|
|
3412
|
+
return response.json().then(function (body) {
|
|
3413
|
+
return { status: response.status, body: body };
|
|
3414
|
+
});
|
|
3415
|
+
}
|
|
3416
|
+
function assertSuccessfulResponse(response, fallbackMessage) {
|
|
3417
|
+
if (response.status >= 400) {
|
|
3418
|
+
throw new Error(
|
|
3419
|
+
(response.body && response.body.error && response.body.error.message) || fallbackMessage
|
|
3420
|
+
);
|
|
3421
|
+
}
|
|
3422
|
+
return response.body;
|
|
3423
|
+
}
|
|
3144
3424
|
|
|
3145
3425
|
function defaultAddress() {
|
|
3146
3426
|
return {
|
|
@@ -3150,9 +3430,20 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3150
3430
|
};
|
|
3151
3431
|
}
|
|
3152
3432
|
function defaultPayment(type) {
|
|
3153
|
-
if (type ===
|
|
3154
|
-
|
|
3155
|
-
|
|
3433
|
+
if (type === TENDER.CARD) {
|
|
3434
|
+
return {
|
|
3435
|
+
type: TENDER.CARD,
|
|
3436
|
+
provider: PAYMENT_PROVIDER.PAYSTACK,
|
|
3437
|
+
last_four: "4242",
|
|
3438
|
+
label: "Visa \u2022\u2022\u2022\u2022 4242"
|
|
3439
|
+
};
|
|
3440
|
+
}
|
|
3441
|
+
return {
|
|
3442
|
+
type: TENDER.MOBILE_MONEY,
|
|
3443
|
+
provider: TENDER.MTN,
|
|
3444
|
+
phone_number: "+233244000000",
|
|
3445
|
+
label: "MTN Mobile Money"
|
|
3446
|
+
};
|
|
3156
3447
|
}
|
|
3157
3448
|
|
|
3158
3449
|
function renderAuth() {
|
|
@@ -3177,12 +3468,12 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3177
3468
|
' <div class="option" data-key="lagos">5 Allen Ave, Ikeja, Lagos</div>' +
|
|
3178
3469
|
'</div>' +
|
|
3179
3470
|
'<button id="confirm">Use this address</button>';
|
|
3180
|
-
|
|
3471
|
+
const options = {
|
|
3181
3472
|
"default": defaultAddress(),
|
|
3182
3473
|
"east-legon": { street_address: "8 Ring Road", city: "Accra", region: "Greater Accra", country: "GH", latitude: 5.65, longitude: -0.16 },
|
|
3183
3474
|
"lagos": { street_address: "5 Allen Avenue", city: "Lagos", region: "Lagos", country: "NG", latitude: 6.5244, longitude: 3.3792 }
|
|
3184
3475
|
};
|
|
3185
|
-
|
|
3476
|
+
let picked = "default";
|
|
3186
3477
|
Array.prototype.forEach.call(document.querySelectorAll(".option"), function (el) {
|
|
3187
3478
|
el.onclick = function () {
|
|
3188
3479
|
picked = el.getAttribute("data-key");
|
|
@@ -3205,10 +3496,9 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3205
3496
|
'<div class="options" id="pay-options">' +
|
|
3206
3497
|
' <div class="option selected" data-method="mobile_money">\u{1F4F1} MTN Mobile Money</div>' +
|
|
3207
3498
|
' <div class="option" data-method="card">\u{1F4B3} Card (Paystack)</div>' +
|
|
3208
|
-
' <div class="option" data-method="cash">\u{1F4B5} Cash on delivery</div>' +
|
|
3209
3499
|
'</div>' +
|
|
3210
3500
|
'<button id="confirm">Use this method</button>';
|
|
3211
|
-
|
|
3501
|
+
let picked = TENDER.MOBILE_MONEY;
|
|
3212
3502
|
Array.prototype.forEach.call(document.querySelectorAll(".option"), function (el) {
|
|
3213
3503
|
el.onclick = function () {
|
|
3214
3504
|
picked = el.getAttribute("data-method");
|
|
@@ -3252,7 +3542,6 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3252
3542
|
'</div>' +
|
|
3253
3543
|
'<label>Payment method</label>' +
|
|
3254
3544
|
'<select id="pay-method">' +
|
|
3255
|
-
' <option value="cash">Cash</option>' +
|
|
3256
3545
|
' <option value="mobile_money">Mobile Money (MTN)</option>' +
|
|
3257
3546
|
' <option value="card">Card (Paystack)</option>' +
|
|
3258
3547
|
'</select>' +
|
|
@@ -3269,65 +3558,139 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3269
3558
|
}
|
|
3270
3559
|
|
|
3271
3560
|
function runCheckout() {
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3561
|
+
const statusEl = document.getElementById("status");
|
|
3562
|
+
const errEl = document.getElementById("err");
|
|
3563
|
+
const resultEl = document.getElementById("result");
|
|
3275
3564
|
if (errEl) errEl.textContent = "";
|
|
3276
3565
|
if (!state.cart) { errEl.textContent = "No cart provided"; return; }
|
|
3277
|
-
|
|
3566
|
+
const customer = {
|
|
3278
3567
|
name: document.getElementById("cust-name").value.trim() || "Customer",
|
|
3279
3568
|
email: document.getElementById("cust-email").value.trim() || "noemail@example.com",
|
|
3280
3569
|
phone: document.getElementById("cust-phone").value.trim() || "+233000000000",
|
|
3281
3570
|
save_details: false
|
|
3282
3571
|
};
|
|
3283
|
-
|
|
3284
|
-
|
|
3572
|
+
const paymentMethod = document.getElementById("pay-method").value;
|
|
3573
|
+
const orderType = document.getElementById("order-type").value;
|
|
3285
3574
|
statusEl.textContent = "Processing\u2026";
|
|
3286
|
-
send({ type: MSG.CHECKOUT_STATUS, status:
|
|
3575
|
+
send({ type: MSG.CHECKOUT_STATUS, status: CHECKOUT_STATUS.PROCESSING, context: {} });
|
|
3287
3576
|
|
|
3288
|
-
|
|
3577
|
+
const headers = { "content-type": "application/json" };
|
|
3289
3578
|
if (state.token) headers["x-session-token"] = state.token;
|
|
3290
3579
|
|
|
3291
|
-
|
|
3580
|
+
const preference = paymentMethod === TENDER.MOBILE_MONEY
|
|
3581
|
+
? {
|
|
3582
|
+
method_kind: TENDER.MOBILE_MONEY,
|
|
3583
|
+
authority: {
|
|
3584
|
+
authority_kind: TENDER.AUTHORITY_TRANSIENT,
|
|
3585
|
+
phone_number: customer.phone,
|
|
3586
|
+
network: TENDER.MTN
|
|
3587
|
+
}
|
|
3588
|
+
}
|
|
3589
|
+
: { method_kind: TENDER.CARD };
|
|
3590
|
+
const intentKey = "mock-element:" + state.cart.id;
|
|
3591
|
+
fetch(PURCHASE_INTENT.PATH, {
|
|
3292
3592
|
method: "POST",
|
|
3293
3593
|
headers: headers,
|
|
3294
3594
|
body: JSON.stringify({
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3595
|
+
client_intent_key: intentKey,
|
|
3596
|
+
source: { kind: SOURCE_KIND.CART, cart_id: state.cart.id },
|
|
3597
|
+
checkout: {
|
|
3598
|
+
customer: customer,
|
|
3599
|
+
order_type: orderType,
|
|
3600
|
+
address_info: state.address || {},
|
|
3601
|
+
tender_preference: preference
|
|
3602
|
+
}
|
|
3300
3603
|
})
|
|
3301
3604
|
})
|
|
3302
|
-
.then(
|
|
3605
|
+
.then(responseWithBody)
|
|
3303
3606
|
.then(function (resp) {
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3607
|
+
const intent = assertSuccessfulResponse(resp, "Intent creation failed");
|
|
3608
|
+
const terms = intent.current_terms;
|
|
3609
|
+
const option = terms && terms.payment_options && terms.payment_options.filter(function (candidate) {
|
|
3610
|
+
return candidate.status === PURCHASE_INTENT.ELIGIBLE && candidate.method_kind === preference.method_kind;
|
|
3611
|
+
})[0];
|
|
3612
|
+
if (!terms || (!option && !isExactlyZeroMoney(terms.money.rail_amount))) {
|
|
3613
|
+
throw new Error("No eligible payment option");
|
|
3310
3614
|
}
|
|
3311
|
-
|
|
3312
|
-
|
|
3615
|
+
const confirmationPath = PURCHASE_INTENT.PATH + "/" + encodeURIComponent(intent.id) + "/confirm";
|
|
3616
|
+
const confirmationBody = JSON.stringify({
|
|
3617
|
+
accepted_intent_revision: terms.intent_revision,
|
|
3618
|
+
accepted_terms_version: terms.terms_version,
|
|
3619
|
+
accepted_due_now: terms.money.due_now,
|
|
3620
|
+
accepted_customer_debit_amount: option
|
|
3621
|
+
? option.customer_debit_amount
|
|
3622
|
+
: terms.money.rail_amount,
|
|
3623
|
+
currency: terms.money.currency,
|
|
3624
|
+
payment_option_id: option ? option.id : null,
|
|
3625
|
+
idempotency_key: "mock-confirm:" + intent.id
|
|
3626
|
+
});
|
|
3627
|
+
function confirmIntent() {
|
|
3628
|
+
return fetch(confirmationPath, {
|
|
3629
|
+
method: "POST",
|
|
3630
|
+
headers: headers,
|
|
3631
|
+
body: confirmationBody
|
|
3632
|
+
})
|
|
3633
|
+
.then(responseWithBody)
|
|
3634
|
+
.then(function (response) {
|
|
3635
|
+
return assertSuccessfulResponse(response, "Intent confirmation failed");
|
|
3636
|
+
});
|
|
3637
|
+
}
|
|
3638
|
+
|
|
3639
|
+
return confirmIntent().then(function (outcome) {
|
|
3640
|
+
// This mock has no external provider window. Replaying the exact
|
|
3641
|
+
// idempotent confirmation models the provider-approved callback.
|
|
3642
|
+
return outcome.status === PURCHASE_INTENT.CARD_POPUP_REQUIRED
|
|
3643
|
+
? confirmIntent()
|
|
3644
|
+
: outcome;
|
|
3645
|
+
});
|
|
3646
|
+
})
|
|
3647
|
+
.then(function (outcome) {
|
|
3648
|
+
if (outcome.status !== PURCHASE_INTENT.AUTHORIZATION_REQUIRED) return outcome;
|
|
3649
|
+
return fetch(
|
|
3650
|
+
PURCHASE_INTENT.PATH + "/" + encodeURIComponent(outcome.intent_id) +
|
|
3651
|
+
"/attempts/" + encodeURIComponent(outcome.attempt_id) + "/actions",
|
|
3652
|
+
{
|
|
3653
|
+
method: "POST",
|
|
3654
|
+
headers: headers,
|
|
3655
|
+
body: JSON.stringify({ authorization: { type: AUTHORIZATION.OTP, value: DEMO_OTP } })
|
|
3656
|
+
}
|
|
3657
|
+
)
|
|
3658
|
+
.then(responseWithBody)
|
|
3659
|
+
.then(function (response) {
|
|
3660
|
+
return assertSuccessfulResponse(response, "Authorization failed");
|
|
3661
|
+
});
|
|
3662
|
+
})
|
|
3663
|
+
.then(function (outcome) {
|
|
3664
|
+
if (outcome.status !== PURCHASE_INTENT.ORDER_CREATED) {
|
|
3665
|
+
throw new Error("Checkout requires " + outcome.status.replace(/_/g, " "));
|
|
3666
|
+
}
|
|
3667
|
+
send({
|
|
3668
|
+
type: MSG.CHECKOUT_STATUS,
|
|
3669
|
+
status: CHECKOUT_STATUS.SUCCESS,
|
|
3670
|
+
context: { order_id: outcome.order_id }
|
|
3671
|
+
});
|
|
3313
3672
|
send({
|
|
3314
3673
|
type: MSG.CHECKOUT_COMPLETE,
|
|
3315
3674
|
success: true,
|
|
3316
3675
|
order: {
|
|
3317
|
-
id:
|
|
3318
|
-
order_number:
|
|
3319
|
-
status:
|
|
3676
|
+
id: outcome.order_id,
|
|
3677
|
+
order_number: outcome.order_number || outcome.order_id,
|
|
3678
|
+
status: ORDER_STATUS.CONFIRMED,
|
|
3320
3679
|
total: (state.cart && state.cart.total_price) || "0.00",
|
|
3321
3680
|
currency: (state.cart && state.cart.currency) || "GHS"
|
|
3322
3681
|
}
|
|
3323
3682
|
});
|
|
3324
|
-
statusEl.textContent = "Success \u2014 order " +
|
|
3683
|
+
statusEl.textContent = "Success \u2014 order " + outcome.order_id;
|
|
3325
3684
|
resultEl.style.display = "block";
|
|
3326
|
-
resultEl.textContent = JSON.stringify(
|
|
3685
|
+
resultEl.textContent = JSON.stringify(outcome, null, 2);
|
|
3327
3686
|
})
|
|
3328
3687
|
.catch(function (e) {
|
|
3329
|
-
send({
|
|
3330
|
-
|
|
3688
|
+
send({
|
|
3689
|
+
type: MSG.CHECKOUT_COMPLETE,
|
|
3690
|
+
success: false,
|
|
3691
|
+
error: { code: CHECKOUT_ERROR.FAILED, message: String(e), recoverable: true }
|
|
3692
|
+
});
|
|
3693
|
+
statusEl.textContent = "Failed";
|
|
3331
3694
|
errEl.textContent = String(e);
|
|
3332
3695
|
});
|
|
3333
3696
|
}
|
|
@@ -3344,7 +3707,7 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3344
3707
|
break;
|
|
3345
3708
|
case MSG.SET_CART:
|
|
3346
3709
|
state.cart = msg.cart;
|
|
3347
|
-
|
|
3710
|
+
const s = document.getElementById("status");
|
|
3348
3711
|
if (s) s.textContent = "Cart loaded \u2014 " + (msg.cart && msg.cart.items ? msg.cart.items.length : 0) + " item(s), " + ((msg.cart && msg.cart.currency) || "GHS") + " " + ((msg.cart && msg.cart.total_price) || "0.00");
|
|
3349
3712
|
reportHeight();
|
|
3350
3713
|
break;
|
|
@@ -3368,7 +3731,7 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3368
3731
|
}
|
|
3369
3732
|
break;
|
|
3370
3733
|
case MSG.ABORT_CHECKOUT:
|
|
3371
|
-
send({ type: MSG.CHECKOUT_STATUS, status:
|
|
3734
|
+
send({ type: MSG.CHECKOUT_STATUS, status: CHECKOUT_STATUS.FAILED, context: {} });
|
|
3372
3735
|
break;
|
|
3373
3736
|
}
|
|
3374
3737
|
}
|
|
@@ -3982,6 +4345,7 @@ function createAuthService(opts) {
|
|
|
3982
4345
|
token: id,
|
|
3983
4346
|
business_id: options.defaultBusinessId,
|
|
3984
4347
|
is_authenticated: authenticated,
|
|
4348
|
+
account_id: authenticated ? ids.raw("account") : void 0,
|
|
3985
4349
|
customer_id: authenticated ? ids.customer() : void 0,
|
|
3986
4350
|
customer_name: profile?.name,
|
|
3987
4351
|
customer_email: profile?.email,
|
|
@@ -4064,7 +4428,7 @@ function createAuthService(opts) {
|
|
|
4064
4428
|
if (!s) return { is_authenticated: false, user_type: "guest" };
|
|
4065
4429
|
return {
|
|
4066
4430
|
is_authenticated: s.is_authenticated,
|
|
4067
|
-
account_id: s.
|
|
4431
|
+
account_id: s.account_id,
|
|
4068
4432
|
user_type: s.is_authenticated ? "customer" : "guest",
|
|
4069
4433
|
session_expires_at: s.expires_at ? Math.floor(new Date(s.expires_at).getTime() / 1e3) : void 0,
|
|
4070
4434
|
session: s
|
|
@@ -5362,88 +5726,10 @@ function createCartService(opts) {
|
|
|
5362
5726
|
};
|
|
5363
5727
|
}
|
|
5364
5728
|
|
|
5365
|
-
// src/mock/domain/
|
|
5366
|
-
function
|
|
5367
|
-
const { registry, clock,
|
|
5729
|
+
// src/mock/domain/payment.ts
|
|
5730
|
+
function createPaymentService(options) {
|
|
5731
|
+
const { registry, clock, bus } = options;
|
|
5368
5732
|
return {
|
|
5369
|
-
process(session, body) {
|
|
5370
|
-
if (!body.cart_id) throw validation("cart_id required");
|
|
5371
|
-
const c = registry.carts.get(body.cart_id);
|
|
5372
|
-
if (!c) throw notFound(`Cart ${body.cart_id} not found`);
|
|
5373
|
-
if (c.items.length === 0) throw validation("Cart is empty", { code: "CART_EMPTY" });
|
|
5374
|
-
const orderId = ids.order();
|
|
5375
|
-
const orderNumber = ids.orderNumber();
|
|
5376
|
-
const paymentId = ids.payment();
|
|
5377
|
-
const reference = ids.payment();
|
|
5378
|
-
const requiresAuth = body.payment_method === "mobile_money";
|
|
5379
|
-
const isCard = body.payment_method === "card" || body.payment_method === "stripe";
|
|
5380
|
-
const cardProvider = body.payment_method === "stripe" || body.pay_currency?.toUpperCase() === "USD" ? "stripe" : "paystack";
|
|
5381
|
-
const order = {
|
|
5382
|
-
id: orderId,
|
|
5383
|
-
business_id: c.business_id,
|
|
5384
|
-
user_friendly_id: orderNumber,
|
|
5385
|
-
channel: c.channel,
|
|
5386
|
-
status: requiresAuth ? "pending" : "confirmed",
|
|
5387
|
-
payment_state: requiresAuth ? "not_paid" : "paid",
|
|
5388
|
-
order_type: body.order_type,
|
|
5389
|
-
customer_id: session.customer_id,
|
|
5390
|
-
customer_name: body.customer.name,
|
|
5391
|
-
customer_email: body.customer.email,
|
|
5392
|
-
customer_phone: body.customer.phone,
|
|
5393
|
-
delivery_address: body.address_info?.street_address,
|
|
5394
|
-
delivery_fee: c.delivery_fee,
|
|
5395
|
-
subtotal: c.subtotal,
|
|
5396
|
-
tax_amount: c.tax_amount,
|
|
5397
|
-
service_charge: c.service_charge,
|
|
5398
|
-
total_discounts: c.total_discounts,
|
|
5399
|
-
total_price: c.total_price,
|
|
5400
|
-
currency: c.currency,
|
|
5401
|
-
items: c.items,
|
|
5402
|
-
applied_discount_ids: c.applied_discount_ids,
|
|
5403
|
-
applied_discount_codes: c.applied_discount_codes,
|
|
5404
|
-
payment_id: paymentId,
|
|
5405
|
-
payment_reference: reference,
|
|
5406
|
-
metadata: body.metadata,
|
|
5407
|
-
created_at: clock.iso(),
|
|
5408
|
-
updated_at: clock.iso()
|
|
5409
|
-
};
|
|
5410
|
-
registry.orders.put(orderId, order);
|
|
5411
|
-
registry.carts.put(c.id, { ...c, status: "converted", updated_at: clock.iso() });
|
|
5412
|
-
bus.emit("order.created", { order_id: orderId, order_number: orderNumber }, c.business_id);
|
|
5413
|
-
if (!requiresAuth) {
|
|
5414
|
-
bus.emit("order.payment.captured", { order_id: orderId, reference }, c.business_id);
|
|
5415
|
-
bus.emit("order.confirmed", { order_id: orderId }, c.business_id);
|
|
5416
|
-
}
|
|
5417
|
-
const billToken = `bt_${reference.slice(-12)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
5418
|
-
const result = {
|
|
5419
|
-
order_id: orderId,
|
|
5420
|
-
order_number: orderNumber,
|
|
5421
|
-
payment_id: paymentId,
|
|
5422
|
-
payment_status: requiresAuth || isCard ? "pending" : "succeeded",
|
|
5423
|
-
payment_reference: reference,
|
|
5424
|
-
requires_authorization: requiresAuth,
|
|
5425
|
-
authorization_type: requiresAuth ? "otp" : void 0,
|
|
5426
|
-
next_action: requiresAuth ? {
|
|
5427
|
-
type: "authorization",
|
|
5428
|
-
authorization_type: "otp",
|
|
5429
|
-
display_text: "Approve on your mobile money app"
|
|
5430
|
-
} : { type: "none" },
|
|
5431
|
-
provider: isCard ? cardProvider : body.payment_method,
|
|
5432
|
-
bill_token: billToken
|
|
5433
|
-
};
|
|
5434
|
-
if (isCard) {
|
|
5435
|
-
const proc = globalThis.process;
|
|
5436
|
-
result.client_secret = cardProvider === "stripe" ? `pi_${orderId.slice(-12)}_secret_${Math.random().toString(36).slice(2, 18)}` : `access_${reference}`;
|
|
5437
|
-
result.public_key = cardProvider === "stripe" ? proc?.env?.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ?? "pk_test_mock_stripe" : proc?.env?.NEXT_PUBLIC_PAYSTACK_PUBLIC_KEY ?? "pk_test_mock_paystack";
|
|
5438
|
-
result.next_action = {
|
|
5439
|
-
type: "card_popup",
|
|
5440
|
-
provider: cardProvider,
|
|
5441
|
-
client_secret: result.client_secret,
|
|
5442
|
-
public_key: result.public_key
|
|
5443
|
-
};
|
|
5444
|
-
}
|
|
5445
|
-
return result;
|
|
5446
|
-
},
|
|
5447
5733
|
authorize(body) {
|
|
5448
5734
|
if (!body.payment_id?.trim()) throw validation("payment_id required");
|
|
5449
5735
|
if (!body.authorization) throw validation("authorization required");
|
|
@@ -5454,7 +5740,7 @@ function createCheckoutService(opts) {
|
|
|
5454
5740
|
const updated = {
|
|
5455
5741
|
...order,
|
|
5456
5742
|
payment_state: "paid",
|
|
5457
|
-
status:
|
|
5743
|
+
status: CHECKOUT_ORDER_RESULT_STATUS.CONFIRMED,
|
|
5458
5744
|
updated_at: clock.iso()
|
|
5459
5745
|
};
|
|
5460
5746
|
registry.orders.put(order.id, updated);
|
|
@@ -5465,14 +5751,542 @@ function createCheckoutService(opts) {
|
|
|
5465
5751
|
order_number: order.user_friendly_id,
|
|
5466
5752
|
payment_id: body.payment_id,
|
|
5467
5753
|
payment_reference: order.payment_reference,
|
|
5468
|
-
payment_status:
|
|
5754
|
+
payment_status: LEGACY_CHECKOUT_PAYMENT_STATUS.SUCCEEDED,
|
|
5469
5755
|
requires_authorization: false,
|
|
5470
|
-
next_action: { type:
|
|
5756
|
+
next_action: { type: CHECKOUT_NEXT_ACTION.NONE }
|
|
5471
5757
|
};
|
|
5472
5758
|
}
|
|
5473
5759
|
};
|
|
5474
5760
|
}
|
|
5475
5761
|
|
|
5762
|
+
// src/mock/domain/purchase-intent.ts
|
|
5763
|
+
var INTENT_LIFETIME_MS = 15 * 60 * 1e3;
|
|
5764
|
+
var ZERO_MONEY = "0.00";
|
|
5765
|
+
var PURCHASE_INTENT_MOBILE_MONEY_NETWORKS = new Set(
|
|
5766
|
+
Object.values(PURCHASE_INTENT_MOBILE_MONEY_NETWORK)
|
|
5767
|
+
);
|
|
5768
|
+
var MOCK_PURCHASE_INTENT = {
|
|
5769
|
+
OWNER_KIND: { ACCOUNT: "account", STOREFRONT_SESSION: "storefront_session" },
|
|
5770
|
+
CART_STATUS: { ACTIVE: "active", CONVERTED: "converted" },
|
|
5771
|
+
ORDER_STATUS: { PENDING: "pending", CONFIRMED: "confirmed" },
|
|
5772
|
+
PAYMENT_STATE: { NOT_PAID: "not_paid", PAID: "paid" },
|
|
5773
|
+
EVENT: {
|
|
5774
|
+
ORDER_CREATED: "order.created",
|
|
5775
|
+
PAYMENT_CAPTURED: "order.payment.captured",
|
|
5776
|
+
ORDER_CONFIRMED: "order.confirmed"
|
|
5777
|
+
},
|
|
5778
|
+
ID_PREFIX: { INTENT: "pi", ATTEMPT: "attempt" },
|
|
5779
|
+
DEFAULT_LOCATION_ID: "mock-location",
|
|
5780
|
+
MOCK_PAYSTACK_PUBLIC_KEY: "pk_test_mock_paystack",
|
|
5781
|
+
COMPLIANCE: {
|
|
5782
|
+
POLICY_NAME: "mock-storefront-commerce"
|
|
5783
|
+
}
|
|
5784
|
+
};
|
|
5785
|
+
var DECIMAL_WIRE_VALUE = /^([+-]?)(\d+)(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
|
|
5786
|
+
function isExactlyZero(value) {
|
|
5787
|
+
if (typeof value === "number") return Object.is(value, 0) || Object.is(value, -0);
|
|
5788
|
+
const match2 = DECIMAL_WIRE_VALUE.exec(value.trim());
|
|
5789
|
+
return Boolean(match2 && [...match2[2], ...match2[3] ?? ""].every((digit) => digit === "0"));
|
|
5790
|
+
}
|
|
5791
|
+
function sameDecimal(left, right) {
|
|
5792
|
+
const canonical = (value) => {
|
|
5793
|
+
const wire = typeof value === "number" ? String(value) : value.trim();
|
|
5794
|
+
const match2 = DECIMAL_WIRE_VALUE.exec(wire);
|
|
5795
|
+
if (!match2) return null;
|
|
5796
|
+
let digits = `${match2[2]}${match2[3] ?? ""}`.replace(/^0+/, "");
|
|
5797
|
+
if (!digits) return "0";
|
|
5798
|
+
let scale = BigInt((match2[3] ?? "").length) - BigInt(match2[4] ?? "0");
|
|
5799
|
+
while (digits.endsWith("0")) {
|
|
5800
|
+
digits = digits.slice(0, -1);
|
|
5801
|
+
scale -= 1n;
|
|
5802
|
+
}
|
|
5803
|
+
const sign = match2[1] === "-" ? "-" : "";
|
|
5804
|
+
return `${sign}${digits}:${scale}`;
|
|
5805
|
+
};
|
|
5806
|
+
const normalizedLeft = canonical(left);
|
|
5807
|
+
return normalizedLeft !== null && normalizedLeft === canonical(right);
|
|
5808
|
+
}
|
|
5809
|
+
function wireMoney(value) {
|
|
5810
|
+
return typeof value === "string" ? value.trim() : String(value);
|
|
5811
|
+
}
|
|
5812
|
+
function decimal(value) {
|
|
5813
|
+
return wireMoney(value.toFixed(2));
|
|
5814
|
+
}
|
|
5815
|
+
function paymentOptions(intentId, currency, amount, expiresAt) {
|
|
5816
|
+
const normalizedCurrency = currencyCode(currency);
|
|
5817
|
+
const normalizedAmount = wireMoney(amount);
|
|
5818
|
+
return [
|
|
5819
|
+
{
|
|
5820
|
+
id: `${intentId}:${PURCHASE_INTENT_PAYMENT_METHOD.CARD}`,
|
|
5821
|
+
rank: 0,
|
|
5822
|
+
method_kind: PURCHASE_INTENT_PAYMENT_METHOD.CARD,
|
|
5823
|
+
collection_mode: PAYMENT_COLLECTION_MODE.CREDENTIAL_CHARGE,
|
|
5824
|
+
provider: PURCHASE_INTENT_PAYMENT_PROVIDER.PAYSTACK,
|
|
5825
|
+
principal_amount: normalizedAmount,
|
|
5826
|
+
fee_amount: wireMoney(ZERO_MONEY),
|
|
5827
|
+
customer_debit_amount: normalizedAmount,
|
|
5828
|
+
currency: normalizedCurrency,
|
|
5829
|
+
status: PAYMENT_OPTION_STATUS.ELIGIBLE,
|
|
5830
|
+
expected_next_action: PAYMENT_OPTION_NEXT_ACTION.PROVIDER_APPROVAL,
|
|
5831
|
+
expires_at: expiresAt
|
|
5832
|
+
},
|
|
5833
|
+
{
|
|
5834
|
+
id: `${intentId}:${PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY}`,
|
|
5835
|
+
rank: 1,
|
|
5836
|
+
method_kind: PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY,
|
|
5837
|
+
collection_mode: PAYMENT_COLLECTION_MODE.REQUEST_TO_PAY,
|
|
5838
|
+
provider: PURCHASE_INTENT_PAYMENT_PROVIDER.PAYSTACK,
|
|
5839
|
+
principal_amount: normalizedAmount,
|
|
5840
|
+
fee_amount: wireMoney(ZERO_MONEY),
|
|
5841
|
+
customer_debit_amount: normalizedAmount,
|
|
5842
|
+
currency: normalizedCurrency,
|
|
5843
|
+
status: PAYMENT_OPTION_STATUS.ELIGIBLE,
|
|
5844
|
+
expected_next_action: PAYMENT_OPTION_NEXT_ACTION.PROVIDER_APPROVAL,
|
|
5845
|
+
expires_at: expiresAt
|
|
5846
|
+
}
|
|
5847
|
+
];
|
|
5848
|
+
}
|
|
5849
|
+
function termsForCart(input) {
|
|
5850
|
+
const total = wireMoney(input.total);
|
|
5851
|
+
return {
|
|
5852
|
+
id: `${input.intentId}:terms:${input.version}`,
|
|
5853
|
+
intent_revision: input.revision,
|
|
5854
|
+
terms_version: input.version,
|
|
5855
|
+
terms_digest: `mock:${input.intentId}:${input.revision}:${input.version}`,
|
|
5856
|
+
money: {
|
|
5857
|
+
currency: currencyCode(input.currency),
|
|
5858
|
+
subtotal: wireMoney(input.subtotal),
|
|
5859
|
+
discount_total: wireMoney(input.discount),
|
|
5860
|
+
tax_total: wireMoney(input.tax),
|
|
5861
|
+
delivery_total: wireMoney(input.delivery),
|
|
5862
|
+
statutory_total: wireMoney(ZERO_MONEY),
|
|
5863
|
+
total_obligation: total,
|
|
5864
|
+
due_now: total,
|
|
5865
|
+
rail_amount: total,
|
|
5866
|
+
store_credit_consumed: wireMoney(ZERO_MONEY),
|
|
5867
|
+
voucher_credit_consumed: wireMoney(ZERO_MONEY)
|
|
5868
|
+
},
|
|
5869
|
+
material: {
|
|
5870
|
+
line_digest: `mock-lines:${input.intentId}`,
|
|
5871
|
+
destination_digest: `mock-destination:${input.intentId}`,
|
|
5872
|
+
delivery_promise_digest: `mock-delivery:${input.intentId}`,
|
|
5873
|
+
entitlement_digest: `mock-entitlement:${input.intentId}`,
|
|
5874
|
+
cancellation_terms_digest: `mock-cancellation:${input.intentId}`
|
|
5875
|
+
},
|
|
5876
|
+
compliance: {
|
|
5877
|
+
policy_name: MOCK_PURCHASE_INTENT.COMPLIANCE.POLICY_NAME,
|
|
5878
|
+
policy_version: 1,
|
|
5879
|
+
lane: CHECKOUT_COMPLIANCE_LANE.NATIVE,
|
|
5880
|
+
reason_code: CHECKOUT_COMPLIANCE_REASON.PHYSICAL_GOODS_NATIVE,
|
|
5881
|
+
evidence_digest: `mock-compliance:${input.intentId}`
|
|
5882
|
+
},
|
|
5883
|
+
payment_options: isExactlyZero(input.total) ? [] : paymentOptions(input.intentId, input.currency, input.total, input.validUntil),
|
|
5884
|
+
valid_until: input.validUntil,
|
|
5885
|
+
created_at: input.now
|
|
5886
|
+
};
|
|
5887
|
+
}
|
|
5888
|
+
function intentView(intent) {
|
|
5889
|
+
const {
|
|
5890
|
+
intent_owner: _owner,
|
|
5891
|
+
mint_request: _request,
|
|
5892
|
+
last_confirmation: _confirmation,
|
|
5893
|
+
...view
|
|
5894
|
+
} = intent;
|
|
5895
|
+
return view;
|
|
5896
|
+
}
|
|
5897
|
+
function purchasingPrincipal(session) {
|
|
5898
|
+
if (!session.is_authenticated) {
|
|
5899
|
+
return { kind: PURCHASING_PRINCIPAL_KIND.GUEST };
|
|
5900
|
+
}
|
|
5901
|
+
if (!session.account_id) throw validation("Authenticated mock session has no account authority");
|
|
5902
|
+
return {
|
|
5903
|
+
kind: PURCHASING_PRINCIPAL_KIND.ACCOUNT,
|
|
5904
|
+
account_id: session.account_id
|
|
5905
|
+
};
|
|
5906
|
+
}
|
|
5907
|
+
function assertSupportedTenderPreference(request) {
|
|
5908
|
+
if (request.source.kind !== PURCHASE_INTENT_SOURCE_KIND.CART) return;
|
|
5909
|
+
const checkout = request.checkout;
|
|
5910
|
+
if (!checkout) throw validation("Cart checkout input is required");
|
|
5911
|
+
const preference = checkout.tender_preference;
|
|
5912
|
+
if (preference?.method_kind !== PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY || preference.authority.authority_kind !== MOBILE_MONEY_TENDER_AUTHORITY_KIND.TRANSIENT) {
|
|
5913
|
+
return;
|
|
5914
|
+
}
|
|
5915
|
+
if (!PURCHASE_INTENT_MOBILE_MONEY_NETWORKS.has(preference.authority.network)) {
|
|
5916
|
+
throw validation("Mobile Money network is not available for PurchaseIntent checkout");
|
|
5917
|
+
}
|
|
5918
|
+
}
|
|
5919
|
+
function intentOwner(session) {
|
|
5920
|
+
if (!session.is_authenticated) {
|
|
5921
|
+
return { kind: MOCK_PURCHASE_INTENT.OWNER_KIND.STOREFRONT_SESSION, id: session.id };
|
|
5922
|
+
}
|
|
5923
|
+
if (!session.account_id) throw validation("Authenticated mock session has no account authority");
|
|
5924
|
+
return { kind: MOCK_PURCHASE_INTENT.OWNER_KIND.ACCOUNT, id: session.account_id };
|
|
5925
|
+
}
|
|
5926
|
+
function createPurchaseIntentMockService(options) {
|
|
5927
|
+
const { registry, clock, ids, bus } = options;
|
|
5928
|
+
function stored(session, intentId) {
|
|
5929
|
+
const intent = registry.purchaseIntents.get(intentId);
|
|
5930
|
+
if (!intent) throw notFound(`Purchase intent ${intentId} not found`);
|
|
5931
|
+
const owner = intentOwner(session);
|
|
5932
|
+
if (intent.intent_owner.kind !== owner.kind || intent.intent_owner.id !== owner.id) {
|
|
5933
|
+
throw notFound(`Purchase intent ${intentId} not found`);
|
|
5934
|
+
}
|
|
5935
|
+
return intent;
|
|
5936
|
+
}
|
|
5937
|
+
function completeProviderOrder(intent, order, attemptId) {
|
|
5938
|
+
const updated = {
|
|
5939
|
+
...order,
|
|
5940
|
+
payment_state: MOCK_PURCHASE_INTENT.PAYMENT_STATE.PAID,
|
|
5941
|
+
status: MOCK_PURCHASE_INTENT.ORDER_STATUS.CONFIRMED,
|
|
5942
|
+
updated_at: clock.iso()
|
|
5943
|
+
};
|
|
5944
|
+
registry.orders.put(order.id, updated);
|
|
5945
|
+
bus.emit(
|
|
5946
|
+
MOCK_PURCHASE_INTENT.EVENT.PAYMENT_CAPTURED,
|
|
5947
|
+
{ order_id: order.id, reference: order.payment_reference },
|
|
5948
|
+
order.business_id
|
|
5949
|
+
);
|
|
5950
|
+
bus.emit(MOCK_PURCHASE_INTENT.EVENT.ORDER_CONFIRMED, { order_id: order.id }, order.business_id);
|
|
5951
|
+
const completed = {
|
|
5952
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED,
|
|
5953
|
+
intent_id: intent.id,
|
|
5954
|
+
attempt_id: attemptId,
|
|
5955
|
+
order_id: order.id,
|
|
5956
|
+
order_number: order.user_friendly_id,
|
|
5957
|
+
payment_id: order.payment_id
|
|
5958
|
+
};
|
|
5959
|
+
registry.purchaseIntents.put(intent.id, {
|
|
5960
|
+
...intent,
|
|
5961
|
+
updated_at: clock.iso(),
|
|
5962
|
+
last_confirmation: completed
|
|
5963
|
+
});
|
|
5964
|
+
return completed;
|
|
5965
|
+
}
|
|
5966
|
+
return {
|
|
5967
|
+
mint(session, request) {
|
|
5968
|
+
if (!request.client_intent_key.trim()) throw validation("client_intent_key required");
|
|
5969
|
+
if (request.source.kind !== PURCHASE_INTENT_SOURCE_KIND.CART) {
|
|
5970
|
+
throw validation("The mock currently prepares cart purchase intents only");
|
|
5971
|
+
}
|
|
5972
|
+
const checkoutInput = request.checkout;
|
|
5973
|
+
if (!checkoutInput) throw validation("Cart checkout input is required");
|
|
5974
|
+
assertSupportedTenderPreference(request);
|
|
5975
|
+
const cart = registry.carts.get(request.source.cart_id);
|
|
5976
|
+
if (!cart) throw notFound(`Cart ${request.source.cart_id} not found`);
|
|
5977
|
+
if (cart.items.length === 0) {
|
|
5978
|
+
throw validation("Cart is empty", { code: ErrorCode.CART_EMPTY });
|
|
5979
|
+
}
|
|
5980
|
+
const principal = purchasingPrincipal(session);
|
|
5981
|
+
const owner = intentOwner(session);
|
|
5982
|
+
const existing = registry.purchaseIntents.list(
|
|
5983
|
+
(candidate) => candidate.mint_request.client_intent_key === request.client_intent_key && candidate.intent_owner.kind === owner.kind && candidate.intent_owner.id === owner.id
|
|
5984
|
+
)[0];
|
|
5985
|
+
if (existing) return intentView(existing);
|
|
5986
|
+
const now = clock.iso();
|
|
5987
|
+
const expiresAt = new Date(clock.nowMs() + INTENT_LIFETIME_MS).toISOString();
|
|
5988
|
+
const intentId = ids.raw(MOCK_PURCHASE_INTENT.ID_PREFIX.INTENT);
|
|
5989
|
+
const terms = termsForCart({
|
|
5990
|
+
intentId,
|
|
5991
|
+
revision: 1,
|
|
5992
|
+
version: 1,
|
|
5993
|
+
currency: cart.currency,
|
|
5994
|
+
subtotal: cart.subtotal,
|
|
5995
|
+
discount: cart.total_discounts,
|
|
5996
|
+
tax: cart.tax_amount,
|
|
5997
|
+
delivery: cart.delivery_fee,
|
|
5998
|
+
total: cart.total_price,
|
|
5999
|
+
now,
|
|
6000
|
+
validUntil: expiresAt
|
|
6001
|
+
});
|
|
6002
|
+
const intent = {
|
|
6003
|
+
id: intentId,
|
|
6004
|
+
seller_business_id: cart.business_id,
|
|
6005
|
+
principal,
|
|
6006
|
+
revision: 1,
|
|
6007
|
+
status: PURCHASE_INTENT_STATUS.OPEN,
|
|
6008
|
+
source: {
|
|
6009
|
+
kind: PURCHASE_INTENT_SOURCE_KIND.CART,
|
|
6010
|
+
source_id: cart.id,
|
|
6011
|
+
source_version: cart.updated_at,
|
|
6012
|
+
seller_business_id: cart.business_id,
|
|
6013
|
+
subject: {
|
|
6014
|
+
kind: PURCHASING_PRINCIPAL_KIND.BUSINESS,
|
|
6015
|
+
business_id: cart.business_id
|
|
6016
|
+
},
|
|
6017
|
+
binding_digest: `mock-cart:${cart.id}:${cart.updated_at}`
|
|
6018
|
+
},
|
|
6019
|
+
lines: cart.items.map((line, ordinal) => ({
|
|
6020
|
+
id: line.id,
|
|
6021
|
+
ordinal,
|
|
6022
|
+
sellable: {
|
|
6023
|
+
kind: line.variant_id ? PURCHASE_INTENT_SELLABLE_KIND.VARIANT : PURCHASE_INTENT_SELLABLE_KIND.PRODUCT,
|
|
6024
|
+
product_id: line.item_id,
|
|
6025
|
+
variant_id: line.variant_id,
|
|
6026
|
+
location_id: checkoutInput.location_id || MOCK_PURCHASE_INTENT.DEFAULT_LOCATION_ID
|
|
6027
|
+
},
|
|
6028
|
+
quantity: line.quantity,
|
|
6029
|
+
configuration: {
|
|
6030
|
+
kind: PURCHASE_INTENT_LINE_CONFIGURATION_KIND.SIMPLE,
|
|
6031
|
+
variant_id: line.variant_id,
|
|
6032
|
+
customer_inputs: line.customer_inputs
|
|
6033
|
+
}
|
|
6034
|
+
})),
|
|
6035
|
+
line_pricing: cart.items.map((line) => {
|
|
6036
|
+
const unitPrice = Number(line.price) + Number(line.add_ons_price);
|
|
6037
|
+
const lineSubtotal = unitPrice * line.quantity - Number(line.item_discount_amount);
|
|
6038
|
+
return {
|
|
6039
|
+
intent_line_id: line.id,
|
|
6040
|
+
quantity: line.quantity,
|
|
6041
|
+
unit_price: decimal(unitPrice),
|
|
6042
|
+
line_subtotal: decimal(lineSubtotal),
|
|
6043
|
+
currency: currencyCode(cart.currency)
|
|
6044
|
+
};
|
|
6045
|
+
}),
|
|
6046
|
+
current_terms: terms,
|
|
6047
|
+
expires_at: expiresAt,
|
|
6048
|
+
created_at: now,
|
|
6049
|
+
updated_at: now,
|
|
6050
|
+
intent_owner: owner,
|
|
6051
|
+
mint_request: request
|
|
6052
|
+
};
|
|
6053
|
+
registry.purchaseIntents.put(intentId, intent);
|
|
6054
|
+
return intentView(intent);
|
|
6055
|
+
},
|
|
6056
|
+
get(session, intentId) {
|
|
6057
|
+
return intentView(stored(session, intentId));
|
|
6058
|
+
},
|
|
6059
|
+
refresh(session, intentId, expectedRevision) {
|
|
6060
|
+
const intent = stored(session, intentId);
|
|
6061
|
+
if (intent.revision !== expectedRevision) {
|
|
6062
|
+
throw validation("expected_intent_revision does not match current intent revision");
|
|
6063
|
+
}
|
|
6064
|
+
if (!intent.current_terms) throw validation("Purchase intent has no current terms");
|
|
6065
|
+
const previous = intent.current_terms;
|
|
6066
|
+
const nextDelivery = Number(previous.money.delivery_total) + 1;
|
|
6067
|
+
const nextTotal = Number(previous.money.total_obligation) + 1;
|
|
6068
|
+
const now = clock.iso();
|
|
6069
|
+
const replacement = termsForCart({
|
|
6070
|
+
intentId,
|
|
6071
|
+
revision: intent.revision,
|
|
6072
|
+
version: previous.terms_version + 1,
|
|
6073
|
+
currency: previous.money.currency,
|
|
6074
|
+
subtotal: String(previous.money.subtotal),
|
|
6075
|
+
discount: String(previous.money.discount_total),
|
|
6076
|
+
tax: String(previous.money.tax_total),
|
|
6077
|
+
delivery: nextDelivery.toFixed(2),
|
|
6078
|
+
total: nextTotal.toFixed(2),
|
|
6079
|
+
now,
|
|
6080
|
+
validUntil: intent.expires_at
|
|
6081
|
+
});
|
|
6082
|
+
const updated = { ...intent, current_terms: replacement, updated_at: now };
|
|
6083
|
+
registry.purchaseIntents.put(intentId, updated);
|
|
6084
|
+
return intentView(updated);
|
|
6085
|
+
},
|
|
6086
|
+
confirm(session, intentId, request) {
|
|
6087
|
+
const intent = stored(session, intentId);
|
|
6088
|
+
if (intent.status === PURCHASE_INTENT_STATUS.CONVERTED && intent.last_confirmation) {
|
|
6089
|
+
const orderId2 = "order_id" in intent.last_confirmation ? intent.last_confirmation.order_id : void 0;
|
|
6090
|
+
const order2 = orderId2 ? registry.orders.get(orderId2) : void 0;
|
|
6091
|
+
if (order2?.payment_state === MOCK_PURCHASE_INTENT.PAYMENT_STATE.PAID) {
|
|
6092
|
+
return {
|
|
6093
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED,
|
|
6094
|
+
intent_id: intent.id,
|
|
6095
|
+
attempt_id: "attempt_id" in intent.last_confirmation ? intent.last_confirmation.attempt_id : ids.raw(MOCK_PURCHASE_INTENT.ID_PREFIX.ATTEMPT),
|
|
6096
|
+
order_id: order2.id
|
|
6097
|
+
};
|
|
6098
|
+
}
|
|
6099
|
+
if (order2?.payment_id && intent.last_confirmation.status === PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED) {
|
|
6100
|
+
return completeProviderOrder(intent, order2, intent.last_confirmation.attempt_id);
|
|
6101
|
+
}
|
|
6102
|
+
return intent.last_confirmation;
|
|
6103
|
+
}
|
|
6104
|
+
const terms = intent.current_terms;
|
|
6105
|
+
if (!terms) throw validation("Purchase intent has no current terms");
|
|
6106
|
+
const zeroRail = isExactlyZero(terms.money.rail_amount);
|
|
6107
|
+
const option = request.payment_option_id ? terms.payment_options.find(
|
|
6108
|
+
(candidate) => candidate.id === request.payment_option_id && candidate.status === PAYMENT_OPTION_STATUS.ELIGIBLE
|
|
6109
|
+
) : void 0;
|
|
6110
|
+
const acceptedBaseTermsChanged = !sameDecimal(request.accepted_due_now, terms.money.due_now) || request.currency !== terms.money.currency;
|
|
6111
|
+
if (request.accepted_intent_revision !== intent.revision || request.accepted_terms_version !== terms.terms_version || acceptedBaseTermsChanged) {
|
|
6112
|
+
const deltas = acceptedBaseTermsChanged ? [
|
|
6113
|
+
{
|
|
6114
|
+
kind: CHECKOUT_TERMS_DELTA_KIND.MONEY,
|
|
6115
|
+
component: CHECKOUT_TERMS_COMPONENT.DUE_NOW,
|
|
6116
|
+
accepted: request.accepted_due_now,
|
|
6117
|
+
replacement: terms.money.due_now
|
|
6118
|
+
}
|
|
6119
|
+
] : [
|
|
6120
|
+
{
|
|
6121
|
+
kind: CHECKOUT_TERMS_DELTA_KIND.PAYMENT_OPTION,
|
|
6122
|
+
accepted_option_id: request.payment_option_id ?? null,
|
|
6123
|
+
accepted_customer_debit_amount: request.accepted_customer_debit_amount,
|
|
6124
|
+
replacement_option_id: option?.id ?? null,
|
|
6125
|
+
replacement_customer_debit_amount: option?.customer_debit_amount ?? null
|
|
6126
|
+
}
|
|
6127
|
+
];
|
|
6128
|
+
return {
|
|
6129
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED,
|
|
6130
|
+
intent_id: intent.id,
|
|
6131
|
+
replacement: terms,
|
|
6132
|
+
deltas
|
|
6133
|
+
};
|
|
6134
|
+
}
|
|
6135
|
+
if (!zeroRail && !option || zeroRail && request.payment_option_id != null) {
|
|
6136
|
+
return {
|
|
6137
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE,
|
|
6138
|
+
intent_id: intent.id,
|
|
6139
|
+
lines: intent.lines.map((line) => ({
|
|
6140
|
+
line_id: line.id,
|
|
6141
|
+
reason: CHECKOUT_INVALIDATION_REASON.PAYMENT_OPTION_CHANGED
|
|
6142
|
+
}))
|
|
6143
|
+
};
|
|
6144
|
+
}
|
|
6145
|
+
const acceptedCustomerDebitMatches = zeroRail ? isExactlyZero(request.accepted_customer_debit_amount) : Boolean(
|
|
6146
|
+
option && sameDecimal(request.accepted_customer_debit_amount, option.customer_debit_amount)
|
|
6147
|
+
);
|
|
6148
|
+
if (!acceptedCustomerDebitMatches) {
|
|
6149
|
+
return {
|
|
6150
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED,
|
|
6151
|
+
intent_id: intent.id,
|
|
6152
|
+
replacement: terms,
|
|
6153
|
+
deltas: [
|
|
6154
|
+
{
|
|
6155
|
+
kind: CHECKOUT_TERMS_DELTA_KIND.PAYMENT_OPTION,
|
|
6156
|
+
accepted_option_id: request.payment_option_id ?? null,
|
|
6157
|
+
accepted_customer_debit_amount: request.accepted_customer_debit_amount,
|
|
6158
|
+
replacement_option_id: option?.id ?? null,
|
|
6159
|
+
replacement_customer_debit_amount: option?.customer_debit_amount ?? null
|
|
6160
|
+
}
|
|
6161
|
+
]
|
|
6162
|
+
};
|
|
6163
|
+
}
|
|
6164
|
+
if (intent.mint_request.source.kind !== PURCHASE_INTENT_SOURCE_KIND.CART) {
|
|
6165
|
+
throw validation("The mock currently confirms cart purchase intents only");
|
|
6166
|
+
}
|
|
6167
|
+
const checkoutInput = intent.mint_request.checkout;
|
|
6168
|
+
if (!checkoutInput) throw validation("Cart checkout input is required");
|
|
6169
|
+
const cart = registry.carts.get(intent.mint_request.source.cart_id);
|
|
6170
|
+
if (!cart || cart.status !== MOCK_PURCHASE_INTENT.CART_STATUS.ACTIVE) {
|
|
6171
|
+
return { status: PURCHASE_INTENT_CONFIRM_STATUS.SOURCE_UNAVAILABLE, intent_id: intent.id };
|
|
6172
|
+
}
|
|
6173
|
+
const attemptId = ids.raw(MOCK_PURCHASE_INTENT.ID_PREFIX.ATTEMPT);
|
|
6174
|
+
const orderId = ids.order();
|
|
6175
|
+
const orderNumber = ids.orderNumber();
|
|
6176
|
+
const paymentId = zeroRail ? void 0 : ids.payment();
|
|
6177
|
+
const paymentReference = zeroRail ? void 0 : ids.payment();
|
|
6178
|
+
const needsProvider = option?.method_kind === PURCHASE_INTENT_PAYMENT_METHOD.CARD || option?.method_kind === PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY;
|
|
6179
|
+
const paid = zeroRail;
|
|
6180
|
+
const order = {
|
|
6181
|
+
id: orderId,
|
|
6182
|
+
business_id: cart.business_id,
|
|
6183
|
+
user_friendly_id: orderNumber,
|
|
6184
|
+
channel: cart.channel,
|
|
6185
|
+
status: paid ? MOCK_PURCHASE_INTENT.ORDER_STATUS.CONFIRMED : MOCK_PURCHASE_INTENT.ORDER_STATUS.PENDING,
|
|
6186
|
+
payment_state: paid ? MOCK_PURCHASE_INTENT.PAYMENT_STATE.PAID : MOCK_PURCHASE_INTENT.PAYMENT_STATE.NOT_PAID,
|
|
6187
|
+
order_type: checkoutInput.order_type,
|
|
6188
|
+
customer_id: session.customer_id,
|
|
6189
|
+
customer_name: checkoutInput.customer.name,
|
|
6190
|
+
customer_email: checkoutInput.customer.email,
|
|
6191
|
+
customer_phone: checkoutInput.customer.phone,
|
|
6192
|
+
delivery_address: checkoutInput.address_info.street_address,
|
|
6193
|
+
delivery_fee: cart.delivery_fee,
|
|
6194
|
+
subtotal: cart.subtotal,
|
|
6195
|
+
tax_amount: cart.tax_amount,
|
|
6196
|
+
service_charge: cart.service_charge,
|
|
6197
|
+
total_discounts: cart.total_discounts,
|
|
6198
|
+
total_price: cart.total_price,
|
|
6199
|
+
currency: cart.currency,
|
|
6200
|
+
items: cart.items,
|
|
6201
|
+
applied_discount_ids: cart.applied_discount_ids,
|
|
6202
|
+
applied_discount_codes: cart.applied_discount_codes,
|
|
6203
|
+
payment_id: paymentId,
|
|
6204
|
+
payment_reference: paymentReference,
|
|
6205
|
+
metadata: checkoutInput.metadata,
|
|
6206
|
+
created_at: clock.iso(),
|
|
6207
|
+
updated_at: clock.iso()
|
|
6208
|
+
};
|
|
6209
|
+
registry.orders.put(orderId, order);
|
|
6210
|
+
registry.carts.put(cart.id, {
|
|
6211
|
+
...cart,
|
|
6212
|
+
status: MOCK_PURCHASE_INTENT.CART_STATUS.CONVERTED,
|
|
6213
|
+
updated_at: clock.iso()
|
|
6214
|
+
});
|
|
6215
|
+
bus.emit(
|
|
6216
|
+
MOCK_PURCHASE_INTENT.EVENT.ORDER_CREATED,
|
|
6217
|
+
{ order_id: orderId, order_number: orderNumber },
|
|
6218
|
+
cart.business_id
|
|
6219
|
+
);
|
|
6220
|
+
if (paid) {
|
|
6221
|
+
if (paymentReference) {
|
|
6222
|
+
bus.emit(
|
|
6223
|
+
MOCK_PURCHASE_INTENT.EVENT.PAYMENT_CAPTURED,
|
|
6224
|
+
{ order_id: orderId, reference: paymentReference },
|
|
6225
|
+
cart.business_id
|
|
6226
|
+
);
|
|
6227
|
+
}
|
|
6228
|
+
bus.emit(
|
|
6229
|
+
MOCK_PURCHASE_INTENT.EVENT.ORDER_CONFIRMED,
|
|
6230
|
+
{ order_id: orderId },
|
|
6231
|
+
cart.business_id
|
|
6232
|
+
);
|
|
6233
|
+
}
|
|
6234
|
+
let confirmation;
|
|
6235
|
+
if (option?.method_kind === PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY) {
|
|
6236
|
+
confirmation = {
|
|
6237
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED,
|
|
6238
|
+
intent_id: intent.id,
|
|
6239
|
+
attempt_id: attemptId,
|
|
6240
|
+
order_id: orderId,
|
|
6241
|
+
authorization_type: AUTHORIZATION_TYPE.OTP,
|
|
6242
|
+
display_text: "Approve on your mobile money app"
|
|
6243
|
+
};
|
|
6244
|
+
} else if (option?.method_kind === PURCHASE_INTENT_PAYMENT_METHOD.CARD) {
|
|
6245
|
+
confirmation = {
|
|
6246
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED,
|
|
6247
|
+
intent_id: intent.id,
|
|
6248
|
+
attempt_id: attemptId,
|
|
6249
|
+
order_id: orderId,
|
|
6250
|
+
provider: PURCHASE_INTENT_PAYMENT_PROVIDER.PAYSTACK,
|
|
6251
|
+
client_secret: `access_${paymentReference}`,
|
|
6252
|
+
public_key: MOCK_PURCHASE_INTENT.MOCK_PAYSTACK_PUBLIC_KEY
|
|
6253
|
+
};
|
|
6254
|
+
} else {
|
|
6255
|
+
confirmation = {
|
|
6256
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED,
|
|
6257
|
+
intent_id: intent.id,
|
|
6258
|
+
attempt_id: attemptId,
|
|
6259
|
+
order_id: orderId
|
|
6260
|
+
};
|
|
6261
|
+
}
|
|
6262
|
+
if (needsProvider && !paymentId) {
|
|
6263
|
+
throw validation("Provider-backed purchase intent has no payment authority");
|
|
6264
|
+
}
|
|
6265
|
+
registry.purchaseIntents.put(intent.id, {
|
|
6266
|
+
...intent,
|
|
6267
|
+
status: PURCHASE_INTENT_STATUS.CONVERTED,
|
|
6268
|
+
converted_order_id: orderId,
|
|
6269
|
+
updated_at: clock.iso(),
|
|
6270
|
+
last_confirmation: confirmation
|
|
6271
|
+
});
|
|
6272
|
+
return confirmation;
|
|
6273
|
+
},
|
|
6274
|
+
submitAction(session, intentId, attemptId, request) {
|
|
6275
|
+
const intent = stored(session, intentId);
|
|
6276
|
+
const previous = intent.last_confirmation;
|
|
6277
|
+
if (!previous || previous.status !== PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED || previous.attempt_id !== attemptId) {
|
|
6278
|
+
throw validation("Purchase-intent attempt is not awaiting authorization");
|
|
6279
|
+
}
|
|
6280
|
+
if (!request.authorization) throw validation("authorization required");
|
|
6281
|
+
const order = registry.orders.get(previous.order_id);
|
|
6282
|
+
if (!order || !order.payment_id) {
|
|
6283
|
+
throw notFound(`Purchase-intent attempt ${attemptId} not found`);
|
|
6284
|
+
}
|
|
6285
|
+
return completeProviderOrder(intent, order, attemptId);
|
|
6286
|
+
}
|
|
6287
|
+
};
|
|
6288
|
+
}
|
|
6289
|
+
|
|
5476
6290
|
// src/mock/domain/orders.ts
|
|
5477
6291
|
function createOrderService(opts) {
|
|
5478
6292
|
const { registry, clock, bus } = opts;
|
|
@@ -10784,7 +11598,7 @@ var ID_PREFIX = {
|
|
|
10784
11598
|
product: "prod_",
|
|
10785
11599
|
service: "svc_"
|
|
10786
11600
|
};
|
|
10787
|
-
var
|
|
11601
|
+
var DEFAULT_CURRENCY2 = "GHS";
|
|
10788
11602
|
function slugify(value) {
|
|
10789
11603
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
10790
11604
|
}
|
|
@@ -10819,7 +11633,7 @@ function makeSeedContext(registry) {
|
|
|
10819
11633
|
const business = {
|
|
10820
11634
|
business_type: "other",
|
|
10821
11635
|
email: `hello@${handle}.test`,
|
|
10822
|
-
default_currency:
|
|
11636
|
+
default_currency: DEFAULT_CURRENCY2,
|
|
10823
11637
|
default_offers_table_service: false,
|
|
10824
11638
|
default_accepts_online_orders: true,
|
|
10825
11639
|
status: "active",
|
|
@@ -10998,7 +11812,8 @@ function createDeps(options = {}) {
|
|
|
10998
11812
|
const inventory = createInventoryService({ registry });
|
|
10999
11813
|
const cart = createCartService({ registry, clock, ids, bus, inventory });
|
|
11000
11814
|
const orders = createOrderService({ registry, clock, bus });
|
|
11001
|
-
const
|
|
11815
|
+
const payments = createPaymentService({ registry, clock, bus });
|
|
11816
|
+
const purchaseIntents = createPurchaseIntentMockService({ registry, clock, ids, bus });
|
|
11002
11817
|
const subscriptions = createSubscriptionService({ registry, clock, bus });
|
|
11003
11818
|
const scheduling = createSchedulingService({ registry, clock, bus });
|
|
11004
11819
|
const fx = createFxService({ registry, clock, ids });
|
|
@@ -11019,7 +11834,8 @@ function createDeps(options = {}) {
|
|
|
11019
11834
|
business,
|
|
11020
11835
|
catalogue,
|
|
11021
11836
|
cart,
|
|
11022
|
-
|
|
11837
|
+
payments,
|
|
11838
|
+
purchaseIntents,
|
|
11023
11839
|
orders,
|
|
11024
11840
|
subscriptions,
|
|
11025
11841
|
scheduling,
|