@cimplify/sdk 0.104.0 → 0.105.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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-D1jkpGcr.d.ts} +415 -763
- package/dist/{client-D5AoobFc.d.mts → catalogue-DjutZ0FC.d.mts} +415 -763
- package/dist/{payment-g0HFkEDU.d.mts → checkout-XoV4HNg2.d.mts} +4156 -1498
- package/dist/{payment-g0HFkEDU.d.ts → checkout-XoV4HNg2.d.ts} +4156 -1498
- package/dist/{chunk-GOHSXBKW.mjs → chunk-33VCYWVL.mjs} +25 -1
- package/dist/{chunk-OKADBZAI.mjs → chunk-37ZZCE7P.mjs} +808 -574
- package/dist/{chunk-5BDYDZ4U.js → chunk-3IMPJEUI.js} +892 -657
- package/dist/{chunk-YVAEY3VC.js → chunk-7PMMV5X4.js} +1040 -364
- package/dist/{chunk-H3RATH4B.mjs → chunk-AVXA4F6G.js} +293 -2
- package/dist/{chunk-CNN7Z2IP.js → chunk-EV2EVOYS.js} +27 -0
- package/dist/{chunk-4BKOKHE3.js → chunk-NJYR6GGM.mjs} +244 -19
- package/dist/{chunk-DYIAX3WI.mjs → chunk-NYDVVNZI.mjs} +11 -2
- package/dist/{chunk-E4K2VQDD.js → chunk-PDTXSUHZ.js} +559 -16
- package/dist/{chunk-2WPVUIHX.mjs → chunk-Q5HX7LVE.mjs} +1036 -360
- package/dist/{chunk-5RT4HYMP.mjs → chunk-TINYV5E2.mjs} +542 -15
- package/dist/{chunk-7PDEX54K.js → chunk-UYFTOIFW.js} +13 -3
- package/dist/{chunk-OCCNG6MO.mjs → chunk-X7RPMALQ.mjs} +1310 -722
- package/dist/{chunk-IQFFSKE2.js → chunk-XHVQDEVO.js} +1345 -746
- package/dist/{client-BVNWjk6W.d.ts → client-BBZj15JJ.d.ts} +2 -2
- package/dist/{client-fM716k7G.d.mts → client-CZ8MjJ_o.d.mts} +2 -2
- package/dist/index-CZjNWbQf.d.ts +8 -0
- package/dist/index-DNxWfRHF.d.mts +8 -0
- package/dist/{index-BtcoqrY1.d.ts → index-DRMBo26v.d.mts} +9 -4
- package/dist/{index-D7Tf3v7c.d.mts → index-DweR60Cv.d.ts} +9 -4
- package/dist/index.d.mts +31 -14
- package/dist/index.d.ts +31 -14
- package/dist/index.js +325 -133
- package/dist/index.mjs +6 -6
- package/dist/mock/cli.mjs +1450 -386
- package/dist/mock/library.js +1176 -352
- package/dist/mock/library.mjs +1176 -352
- package/dist/mock/msw.js +1176 -352
- package/dist/mock/msw.mjs +1176 -352
- package/dist/{price-BLIeAb8K.d.ts → price-CUGIYRtD.d.mts} +1 -1
- package/dist/{price-Czq_cTC_.d.mts → price-De-sxcuj.d.ts} +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-Byr4d0hL.d.mts} +31 -57
- package/dist/{server-BkVhOIwn.d.mts → server-C_RIDnHU.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 +2478 -14
- package/dist/testing.d.ts +2478 -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,91 @@ 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_PROTECTION_STATUS = {
|
|
2407
|
+
PROTECTED: "protected"};
|
|
2408
|
+
var CHECKOUT_TERMS_COMPONENT = {
|
|
2409
|
+
DUE_NOW: "due_now"};
|
|
2410
|
+
var CHECKOUT_TERMS_DELTA_KIND = {
|
|
2411
|
+
MONEY: "money",
|
|
2412
|
+
PAYMENT_OPTION: "payment_option"
|
|
2413
|
+
};
|
|
2414
|
+
var CHECKOUT_INVALIDATION_REASON = {
|
|
2415
|
+
PAYMENT_OPTION_CHANGED: "payment_option_changed"
|
|
2416
|
+
};
|
|
2417
|
+
var PURCHASE_INTENT_CONFIRM_STATUS = {
|
|
2418
|
+
ORDER_CREATED: "order_created",
|
|
2419
|
+
CARD_POPUP_REQUIRED: "card_popup_required",
|
|
2420
|
+
AUTHORIZATION_REQUIRED: "authorization_required",
|
|
2421
|
+
TERMS_CHANGED: "terms_changed",
|
|
2422
|
+
SELECTION_UNAVAILABLE: "selection_unavailable",
|
|
2423
|
+
SOURCE_UNAVAILABLE: "source_unavailable"
|
|
2424
|
+
};
|
|
2254
2425
|
|
|
2255
2426
|
// src/mock/routes/v1.ts
|
|
2427
|
+
var PURCHASE_INTENT_ROUTE = {
|
|
2428
|
+
COLLECTION: "/purchase-intents",
|
|
2429
|
+
MEMBER: "/purchase-intents/:intent_id",
|
|
2430
|
+
REFRESH: "/purchase-intents/:intent_id/refresh",
|
|
2431
|
+
CONFIRM: "/purchase-intents/:intent_id/confirm",
|
|
2432
|
+
ACTION: "/purchase-intents/:intent_id/attempts/:attempt_id/actions"
|
|
2433
|
+
};
|
|
2434
|
+
var PURCHASE_INTENT_ROUTE_PARAM = {
|
|
2435
|
+
INTENT_ID: "intent_id",
|
|
2436
|
+
ATTEMPT_ID: "attempt_id"
|
|
2437
|
+
};
|
|
2438
|
+
var PAYMENT_ROUTE = {
|
|
2439
|
+
COLLECTION_OPTIONS: "/payments/collection-options",
|
|
2440
|
+
AUTHORIZATION: "/payments/authorization"
|
|
2441
|
+
};
|
|
2256
2442
|
function buildV1(deps) {
|
|
2257
2443
|
const app = new Hono2();
|
|
2258
2444
|
app.use("*", chaosMiddleware(deps));
|
|
@@ -2625,28 +2811,81 @@ function buildV1(deps) {
|
|
|
2625
2811
|
"/subscriptions/:subscription_id/skip",
|
|
2626
2812
|
(c) => tryRoute(c, () => deps.subscriptions.skipNext(c.req.param("subscription_id")))
|
|
2627
2813
|
);
|
|
2628
|
-
app.get(
|
|
2814
|
+
app.get(PAYMENT_ROUTE.COLLECTION_OPTIONS, async (c) => {
|
|
2629
2815
|
const currency = c.req.query("currency")?.trim().toUpperCase();
|
|
2630
2816
|
if (!currency || !/^[A-Z]{3}$/.test(currency)) {
|
|
2631
2817
|
return fail(c, validation("currency must be a canonical three-letter code"));
|
|
2632
2818
|
}
|
|
2633
2819
|
return tryRoute(c, () => ({
|
|
2634
2820
|
presentment_currency: currency,
|
|
2635
|
-
options: currency ===
|
|
2821
|
+
options: currency === DEFAULT_CURRENCY ? [
|
|
2636
2822
|
{ method: PAYMENT_METHOD.CARD, network: null },
|
|
2637
|
-
{
|
|
2638
|
-
|
|
2639
|
-
|
|
2823
|
+
{
|
|
2824
|
+
method: PAYMENT_METHOD.MOBILE_MONEY,
|
|
2825
|
+
network: PURCHASE_INTENT_MOBILE_MONEY_NETWORK.MTN
|
|
2826
|
+
},
|
|
2827
|
+
{
|
|
2828
|
+
method: PAYMENT_METHOD.MOBILE_MONEY,
|
|
2829
|
+
network: PURCHASE_INTENT_MOBILE_MONEY_NETWORK.TELECEL
|
|
2830
|
+
},
|
|
2831
|
+
{
|
|
2832
|
+
method: PAYMENT_METHOD.MOBILE_MONEY,
|
|
2833
|
+
network: PURCHASE_INTENT_MOBILE_MONEY_NETWORK.AIRTEL
|
|
2834
|
+
}
|
|
2640
2835
|
] : currency === "USD" ? [{ method: PAYMENT_METHOD.CARD, network: null }] : []
|
|
2641
2836
|
}));
|
|
2642
2837
|
});
|
|
2643
|
-
app.post(
|
|
2838
|
+
app.post(PURCHASE_INTENT_ROUTE.COLLECTION, async (c) => {
|
|
2839
|
+
const body = await c.req.json().catch(() => ({}));
|
|
2840
|
+
return tryRoute(c, () => deps.purchaseIntents.mint(c.var.session, body));
|
|
2841
|
+
});
|
|
2842
|
+
app.get(
|
|
2843
|
+
PURCHASE_INTENT_ROUTE.MEMBER,
|
|
2844
|
+
(c) => tryRoute(
|
|
2845
|
+
c,
|
|
2846
|
+
() => deps.purchaseIntents.get(
|
|
2847
|
+
c.var.session,
|
|
2848
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.INTENT_ID)
|
|
2849
|
+
)
|
|
2850
|
+
)
|
|
2851
|
+
);
|
|
2852
|
+
app.post(PURCHASE_INTENT_ROUTE.REFRESH, async (c) => {
|
|
2644
2853
|
const body = await c.req.json().catch(() => ({}));
|
|
2645
|
-
return tryRoute(
|
|
2854
|
+
return tryRoute(
|
|
2855
|
+
c,
|
|
2856
|
+
() => deps.purchaseIntents.refresh(
|
|
2857
|
+
c.var.session,
|
|
2858
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.INTENT_ID),
|
|
2859
|
+
body.expected_intent_revision
|
|
2860
|
+
)
|
|
2861
|
+
);
|
|
2646
2862
|
});
|
|
2647
|
-
app.post(
|
|
2863
|
+
app.post(PURCHASE_INTENT_ROUTE.CONFIRM, async (c) => {
|
|
2648
2864
|
const body = await c.req.json().catch(() => ({}));
|
|
2649
|
-
return tryRoute(
|
|
2865
|
+
return tryRoute(
|
|
2866
|
+
c,
|
|
2867
|
+
() => deps.purchaseIntents.confirm(
|
|
2868
|
+
c.var.session,
|
|
2869
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.INTENT_ID),
|
|
2870
|
+
body
|
|
2871
|
+
)
|
|
2872
|
+
);
|
|
2873
|
+
});
|
|
2874
|
+
app.post(PURCHASE_INTENT_ROUTE.ACTION, async (c) => {
|
|
2875
|
+
const body = await c.req.json().catch(() => ({}));
|
|
2876
|
+
return tryRoute(
|
|
2877
|
+
c,
|
|
2878
|
+
() => deps.purchaseIntents.submitAction(
|
|
2879
|
+
c.var.session,
|
|
2880
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.INTENT_ID),
|
|
2881
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.ATTEMPT_ID),
|
|
2882
|
+
body
|
|
2883
|
+
)
|
|
2884
|
+
);
|
|
2885
|
+
});
|
|
2886
|
+
app.post(PAYMENT_ROUTE.AUTHORIZATION, async (c) => {
|
|
2887
|
+
const body = await c.req.json().catch(() => ({}));
|
|
2888
|
+
return tryRoute(c, () => deps.payments.authorize(body));
|
|
2650
2889
|
});
|
|
2651
2890
|
app.get("/auth/status", (c) => tryRoute(c, () => deps.auth.status(c.var.session.token)));
|
|
2652
2891
|
app.post("/auth/request-otp", async (c) => {
|
|
@@ -2952,6 +3191,7 @@ function createStateRegistry() {
|
|
|
2952
3191
|
collections: createMemoryStore(),
|
|
2953
3192
|
carts: createMemoryStore(),
|
|
2954
3193
|
orders: createMemoryStore(),
|
|
3194
|
+
purchaseIntents: createMemoryStore(),
|
|
2955
3195
|
subscriptions: createMemoryStore(),
|
|
2956
3196
|
bookings: createMemoryStore(),
|
|
2957
3197
|
services: createMemoryStore(),
|
|
@@ -3101,9 +3341,9 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3101
3341
|
// injected into the HTML page served by the mock. Edit this file directly \u2014
|
|
3102
3342
|
// type-check via tsgo + the IframeToParentMessage shape from the SDK.
|
|
3103
3343
|
(function () {
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3344
|
+
const TYPE = window.__CIMPLIFY_MOCK_ELEMENT__;
|
|
3345
|
+
const DEFAULT_BUSINESS = window.__CIMPLIFY_MOCK_BUSINESS__;
|
|
3346
|
+
const MSG = {
|
|
3107
3347
|
INIT: "init", SET_TOKEN: "set_token", SET_CART: "set_cart", GET_DATA: "get_data",
|
|
3108
3348
|
REFRESH_TOKEN: "refresh_token", LOGOUT: "logout",
|
|
3109
3349
|
PROCESS_CHECKOUT: "process_checkout", ABORT_CHECKOUT: "abort_checkout",
|
|
@@ -3116,12 +3356,36 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3116
3356
|
CHECKOUT_STATUS: "checkout_status", CHECKOUT_COMPLETE: "checkout_complete",
|
|
3117
3357
|
ORDER_TYPE_CHANGED: "order_type_changed", REQUEST_SUBMIT: "request_submit"
|
|
3118
3358
|
};
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3359
|
+
const PURCHASE_INTENT = {
|
|
3360
|
+
PATH: "/api/v1/purchase-intents",
|
|
3361
|
+
ORDER_CREATED: "order_created",
|
|
3362
|
+
CARD_POPUP_REQUIRED: "card_popup_required",
|
|
3363
|
+
AUTHORIZATION_REQUIRED: "authorization_required",
|
|
3364
|
+
ELIGIBLE: "eligible"
|
|
3365
|
+
};
|
|
3366
|
+
const CHECKOUT_STATUS = {
|
|
3367
|
+
PROCESSING: "processing",
|
|
3368
|
+
SUCCESS: "success",
|
|
3369
|
+
FAILED: "failed"
|
|
3370
|
+
};
|
|
3371
|
+
const CHECKOUT_ERROR = { FAILED: "CHECKOUT_FAILED" };
|
|
3372
|
+
const ORDER_STATUS = { CONFIRMED: "confirmed" };
|
|
3373
|
+
const TENDER = {
|
|
3374
|
+
CARD: "card",
|
|
3375
|
+
MOBILE_MONEY: "mobile_money",
|
|
3376
|
+
AUTHORITY_TRANSIENT: "transient",
|
|
3377
|
+
MTN: "mtn"
|
|
3378
|
+
};
|
|
3379
|
+
const PAYMENT_PROVIDER = { PAYSTACK: "paystack" };
|
|
3380
|
+
const SOURCE_KIND = { CART: "cart" };
|
|
3381
|
+
const AUTHORIZATION = { OTP: "otp" };
|
|
3382
|
+
const EXACT_ZERO_MONEY = /^[+-]?0+(?:\\.0+)?(?:[eE][+-]?\\d+)?$/;
|
|
3383
|
+
const qs = new URLSearchParams(location.search);
|
|
3384
|
+
const AUTO = qs.get("auto") === "true";
|
|
3385
|
+
const DEMO_OTP = qs.get("otp") || "123456";
|
|
3386
|
+
const ORIGIN = qs.get("origin") || "*";
|
|
3387
|
+
const NONCE = qs.get("nonce");
|
|
3388
|
+
const state = {
|
|
3125
3389
|
businessId: DEFAULT_BUSINESS,
|
|
3126
3390
|
token: null,
|
|
3127
3391
|
cart: null,
|
|
@@ -3132,15 +3396,33 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3132
3396
|
contact: null,
|
|
3133
3397
|
pendingOtp: null
|
|
3134
3398
|
};
|
|
3135
|
-
|
|
3136
|
-
|
|
3399
|
+
const content = document.getElementById("content");
|
|
3400
|
+
const title = document.getElementById("title");
|
|
3137
3401
|
|
|
3138
3402
|
function send(msg) {
|
|
3139
3403
|
if (NONCE) msg.nonce = NONCE;
|
|
3140
3404
|
parent.postMessage(msg, ORIGIN);
|
|
3141
3405
|
}
|
|
3406
|
+
function isExactlyZeroMoney(value) {
|
|
3407
|
+
return typeof value === "number"
|
|
3408
|
+
? Object.is(value, 0) || Object.is(value, -0)
|
|
3409
|
+
: EXACT_ZERO_MONEY.test(String(value).trim());
|
|
3410
|
+
}
|
|
3142
3411
|
function reportHeight() { send({ type: MSG.HEIGHT_CHANGE, height: document.documentElement.scrollHeight }); }
|
|
3143
3412
|
function ready() { send({ type: MSG.READY, height: document.documentElement.scrollHeight }); }
|
|
3413
|
+
function responseWithBody(response) {
|
|
3414
|
+
return response.json().then(function (body) {
|
|
3415
|
+
return { status: response.status, body: body };
|
|
3416
|
+
});
|
|
3417
|
+
}
|
|
3418
|
+
function assertSuccessfulResponse(response, fallbackMessage) {
|
|
3419
|
+
if (response.status >= 400) {
|
|
3420
|
+
throw new Error(
|
|
3421
|
+
(response.body && response.body.error && response.body.error.message) || fallbackMessage
|
|
3422
|
+
);
|
|
3423
|
+
}
|
|
3424
|
+
return response.body;
|
|
3425
|
+
}
|
|
3144
3426
|
|
|
3145
3427
|
function defaultAddress() {
|
|
3146
3428
|
return {
|
|
@@ -3150,9 +3432,20 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3150
3432
|
};
|
|
3151
3433
|
}
|
|
3152
3434
|
function defaultPayment(type) {
|
|
3153
|
-
if (type ===
|
|
3154
|
-
|
|
3155
|
-
|
|
3435
|
+
if (type === TENDER.CARD) {
|
|
3436
|
+
return {
|
|
3437
|
+
type: TENDER.CARD,
|
|
3438
|
+
provider: PAYMENT_PROVIDER.PAYSTACK,
|
|
3439
|
+
last_four: "4242",
|
|
3440
|
+
label: "Visa \u2022\u2022\u2022\u2022 4242"
|
|
3441
|
+
};
|
|
3442
|
+
}
|
|
3443
|
+
return {
|
|
3444
|
+
type: TENDER.MOBILE_MONEY,
|
|
3445
|
+
provider: TENDER.MTN,
|
|
3446
|
+
phone_number: "+233244000000",
|
|
3447
|
+
label: "MTN Mobile Money"
|
|
3448
|
+
};
|
|
3156
3449
|
}
|
|
3157
3450
|
|
|
3158
3451
|
function renderAuth() {
|
|
@@ -3177,12 +3470,12 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3177
3470
|
' <div class="option" data-key="lagos">5 Allen Ave, Ikeja, Lagos</div>' +
|
|
3178
3471
|
'</div>' +
|
|
3179
3472
|
'<button id="confirm">Use this address</button>';
|
|
3180
|
-
|
|
3473
|
+
const options = {
|
|
3181
3474
|
"default": defaultAddress(),
|
|
3182
3475
|
"east-legon": { street_address: "8 Ring Road", city: "Accra", region: "Greater Accra", country: "GH", latitude: 5.65, longitude: -0.16 },
|
|
3183
3476
|
"lagos": { street_address: "5 Allen Avenue", city: "Lagos", region: "Lagos", country: "NG", latitude: 6.5244, longitude: 3.3792 }
|
|
3184
3477
|
};
|
|
3185
|
-
|
|
3478
|
+
let picked = "default";
|
|
3186
3479
|
Array.prototype.forEach.call(document.querySelectorAll(".option"), function (el) {
|
|
3187
3480
|
el.onclick = function () {
|
|
3188
3481
|
picked = el.getAttribute("data-key");
|
|
@@ -3205,10 +3498,9 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3205
3498
|
'<div class="options" id="pay-options">' +
|
|
3206
3499
|
' <div class="option selected" data-method="mobile_money">\u{1F4F1} MTN Mobile Money</div>' +
|
|
3207
3500
|
' <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
3501
|
'</div>' +
|
|
3210
3502
|
'<button id="confirm">Use this method</button>';
|
|
3211
|
-
|
|
3503
|
+
let picked = TENDER.MOBILE_MONEY;
|
|
3212
3504
|
Array.prototype.forEach.call(document.querySelectorAll(".option"), function (el) {
|
|
3213
3505
|
el.onclick = function () {
|
|
3214
3506
|
picked = el.getAttribute("data-method");
|
|
@@ -3252,7 +3544,6 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3252
3544
|
'</div>' +
|
|
3253
3545
|
'<label>Payment method</label>' +
|
|
3254
3546
|
'<select id="pay-method">' +
|
|
3255
|
-
' <option value="cash">Cash</option>' +
|
|
3256
3547
|
' <option value="mobile_money">Mobile Money (MTN)</option>' +
|
|
3257
3548
|
' <option value="card">Card (Paystack)</option>' +
|
|
3258
3549
|
'</select>' +
|
|
@@ -3269,65 +3560,139 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3269
3560
|
}
|
|
3270
3561
|
|
|
3271
3562
|
function runCheckout() {
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3563
|
+
const statusEl = document.getElementById("status");
|
|
3564
|
+
const errEl = document.getElementById("err");
|
|
3565
|
+
const resultEl = document.getElementById("result");
|
|
3275
3566
|
if (errEl) errEl.textContent = "";
|
|
3276
3567
|
if (!state.cart) { errEl.textContent = "No cart provided"; return; }
|
|
3277
|
-
|
|
3568
|
+
const customer = {
|
|
3278
3569
|
name: document.getElementById("cust-name").value.trim() || "Customer",
|
|
3279
3570
|
email: document.getElementById("cust-email").value.trim() || "noemail@example.com",
|
|
3280
3571
|
phone: document.getElementById("cust-phone").value.trim() || "+233000000000",
|
|
3281
3572
|
save_details: false
|
|
3282
3573
|
};
|
|
3283
|
-
|
|
3284
|
-
|
|
3574
|
+
const paymentMethod = document.getElementById("pay-method").value;
|
|
3575
|
+
const orderType = document.getElementById("order-type").value;
|
|
3285
3576
|
statusEl.textContent = "Processing\u2026";
|
|
3286
|
-
send({ type: MSG.CHECKOUT_STATUS, status:
|
|
3577
|
+
send({ type: MSG.CHECKOUT_STATUS, status: CHECKOUT_STATUS.PROCESSING, context: {} });
|
|
3287
3578
|
|
|
3288
|
-
|
|
3579
|
+
const headers = { "content-type": "application/json" };
|
|
3289
3580
|
if (state.token) headers["x-session-token"] = state.token;
|
|
3290
3581
|
|
|
3291
|
-
|
|
3582
|
+
const preference = paymentMethod === TENDER.MOBILE_MONEY
|
|
3583
|
+
? {
|
|
3584
|
+
method_kind: TENDER.MOBILE_MONEY,
|
|
3585
|
+
authority: {
|
|
3586
|
+
authority_kind: TENDER.AUTHORITY_TRANSIENT,
|
|
3587
|
+
phone_number: customer.phone,
|
|
3588
|
+
network: TENDER.MTN
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3591
|
+
: { method_kind: TENDER.CARD };
|
|
3592
|
+
const intentKey = "mock-element:" + state.cart.id;
|
|
3593
|
+
fetch(PURCHASE_INTENT.PATH, {
|
|
3292
3594
|
method: "POST",
|
|
3293
3595
|
headers: headers,
|
|
3294
3596
|
body: JSON.stringify({
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3597
|
+
client_intent_key: intentKey,
|
|
3598
|
+
source: { kind: SOURCE_KIND.CART, cart_id: state.cart.id },
|
|
3599
|
+
checkout: {
|
|
3600
|
+
customer: customer,
|
|
3601
|
+
order_type: orderType,
|
|
3602
|
+
address_info: state.address || {},
|
|
3603
|
+
tender_preference: preference
|
|
3604
|
+
}
|
|
3300
3605
|
})
|
|
3301
3606
|
})
|
|
3302
|
-
.then(
|
|
3607
|
+
.then(responseWithBody)
|
|
3303
3608
|
.then(function (resp) {
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3609
|
+
const intent = assertSuccessfulResponse(resp, "Intent creation failed");
|
|
3610
|
+
const terms = intent.current_terms;
|
|
3611
|
+
const option = terms && terms.payment_options && terms.payment_options.filter(function (candidate) {
|
|
3612
|
+
return candidate.status === PURCHASE_INTENT.ELIGIBLE && candidate.method_kind === preference.method_kind;
|
|
3613
|
+
})[0];
|
|
3614
|
+
if (!terms || (!option && !isExactlyZeroMoney(terms.money.rail_amount))) {
|
|
3615
|
+
throw new Error("No eligible payment option");
|
|
3310
3616
|
}
|
|
3311
|
-
|
|
3312
|
-
|
|
3617
|
+
const confirmationPath = PURCHASE_INTENT.PATH + "/" + encodeURIComponent(intent.id) + "/confirm";
|
|
3618
|
+
const confirmationBody = JSON.stringify({
|
|
3619
|
+
accepted_intent_revision: terms.intent_revision,
|
|
3620
|
+
accepted_terms_version: terms.terms_version,
|
|
3621
|
+
accepted_due_now: terms.money.due_now,
|
|
3622
|
+
accepted_customer_debit_amount: option
|
|
3623
|
+
? option.customer_debit_amount
|
|
3624
|
+
: terms.money.rail_amount,
|
|
3625
|
+
currency: terms.money.currency,
|
|
3626
|
+
payment_option_id: option ? option.id : null,
|
|
3627
|
+
idempotency_key: "mock-confirm:" + intent.id
|
|
3628
|
+
});
|
|
3629
|
+
function confirmIntent() {
|
|
3630
|
+
return fetch(confirmationPath, {
|
|
3631
|
+
method: "POST",
|
|
3632
|
+
headers: headers,
|
|
3633
|
+
body: confirmationBody
|
|
3634
|
+
})
|
|
3635
|
+
.then(responseWithBody)
|
|
3636
|
+
.then(function (response) {
|
|
3637
|
+
return assertSuccessfulResponse(response, "Intent confirmation failed");
|
|
3638
|
+
});
|
|
3639
|
+
}
|
|
3640
|
+
|
|
3641
|
+
return confirmIntent().then(function (outcome) {
|
|
3642
|
+
// This mock has no external provider window. Replaying the exact
|
|
3643
|
+
// idempotent confirmation models the provider-approved callback.
|
|
3644
|
+
return outcome.status === PURCHASE_INTENT.CARD_POPUP_REQUIRED
|
|
3645
|
+
? confirmIntent()
|
|
3646
|
+
: outcome;
|
|
3647
|
+
});
|
|
3648
|
+
})
|
|
3649
|
+
.then(function (outcome) {
|
|
3650
|
+
if (outcome.status !== PURCHASE_INTENT.AUTHORIZATION_REQUIRED) return outcome;
|
|
3651
|
+
return fetch(
|
|
3652
|
+
PURCHASE_INTENT.PATH + "/" + encodeURIComponent(outcome.intent_id) +
|
|
3653
|
+
"/attempts/" + encodeURIComponent(outcome.attempt_id) + "/actions",
|
|
3654
|
+
{
|
|
3655
|
+
method: "POST",
|
|
3656
|
+
headers: headers,
|
|
3657
|
+
body: JSON.stringify({ authorization: { type: AUTHORIZATION.OTP, value: DEMO_OTP } })
|
|
3658
|
+
}
|
|
3659
|
+
)
|
|
3660
|
+
.then(responseWithBody)
|
|
3661
|
+
.then(function (response) {
|
|
3662
|
+
return assertSuccessfulResponse(response, "Authorization failed");
|
|
3663
|
+
});
|
|
3664
|
+
})
|
|
3665
|
+
.then(function (outcome) {
|
|
3666
|
+
if (outcome.status !== PURCHASE_INTENT.ORDER_CREATED) {
|
|
3667
|
+
throw new Error("Checkout requires " + outcome.status.replace(/_/g, " "));
|
|
3668
|
+
}
|
|
3669
|
+
send({
|
|
3670
|
+
type: MSG.CHECKOUT_STATUS,
|
|
3671
|
+
status: CHECKOUT_STATUS.SUCCESS,
|
|
3672
|
+
context: { order_id: outcome.order_id }
|
|
3673
|
+
});
|
|
3313
3674
|
send({
|
|
3314
3675
|
type: MSG.CHECKOUT_COMPLETE,
|
|
3315
3676
|
success: true,
|
|
3316
3677
|
order: {
|
|
3317
|
-
id:
|
|
3318
|
-
order_number:
|
|
3319
|
-
status:
|
|
3678
|
+
id: outcome.order_id,
|
|
3679
|
+
order_number: outcome.order_number || outcome.order_id,
|
|
3680
|
+
status: ORDER_STATUS.CONFIRMED,
|
|
3320
3681
|
total: (state.cart && state.cart.total_price) || "0.00",
|
|
3321
3682
|
currency: (state.cart && state.cart.currency) || "GHS"
|
|
3322
3683
|
}
|
|
3323
3684
|
});
|
|
3324
|
-
statusEl.textContent = "Success \u2014 order " +
|
|
3685
|
+
statusEl.textContent = "Success \u2014 order " + outcome.order_id;
|
|
3325
3686
|
resultEl.style.display = "block";
|
|
3326
|
-
resultEl.textContent = JSON.stringify(
|
|
3687
|
+
resultEl.textContent = JSON.stringify(outcome, null, 2);
|
|
3327
3688
|
})
|
|
3328
3689
|
.catch(function (e) {
|
|
3329
|
-
send({
|
|
3330
|
-
|
|
3690
|
+
send({
|
|
3691
|
+
type: MSG.CHECKOUT_COMPLETE,
|
|
3692
|
+
success: false,
|
|
3693
|
+
error: { code: CHECKOUT_ERROR.FAILED, message: String(e), recoverable: true }
|
|
3694
|
+
});
|
|
3695
|
+
statusEl.textContent = "Failed";
|
|
3331
3696
|
errEl.textContent = String(e);
|
|
3332
3697
|
});
|
|
3333
3698
|
}
|
|
@@ -3344,7 +3709,7 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3344
3709
|
break;
|
|
3345
3710
|
case MSG.SET_CART:
|
|
3346
3711
|
state.cart = msg.cart;
|
|
3347
|
-
|
|
3712
|
+
const s = document.getElementById("status");
|
|
3348
3713
|
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
3714
|
reportHeight();
|
|
3350
3715
|
break;
|
|
@@ -3368,7 +3733,7 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
3368
3733
|
}
|
|
3369
3734
|
break;
|
|
3370
3735
|
case MSG.ABORT_CHECKOUT:
|
|
3371
|
-
send({ type: MSG.CHECKOUT_STATUS, status:
|
|
3736
|
+
send({ type: MSG.CHECKOUT_STATUS, status: CHECKOUT_STATUS.FAILED, context: {} });
|
|
3372
3737
|
break;
|
|
3373
3738
|
}
|
|
3374
3739
|
}
|
|
@@ -3982,6 +4347,7 @@ function createAuthService(opts) {
|
|
|
3982
4347
|
token: id,
|
|
3983
4348
|
business_id: options.defaultBusinessId,
|
|
3984
4349
|
is_authenticated: authenticated,
|
|
4350
|
+
account_id: authenticated ? ids.raw("account") : void 0,
|
|
3985
4351
|
customer_id: authenticated ? ids.customer() : void 0,
|
|
3986
4352
|
customer_name: profile?.name,
|
|
3987
4353
|
customer_email: profile?.email,
|
|
@@ -4064,7 +4430,7 @@ function createAuthService(opts) {
|
|
|
4064
4430
|
if (!s) return { is_authenticated: false, user_type: "guest" };
|
|
4065
4431
|
return {
|
|
4066
4432
|
is_authenticated: s.is_authenticated,
|
|
4067
|
-
account_id: s.
|
|
4433
|
+
account_id: s.account_id,
|
|
4068
4434
|
user_type: s.is_authenticated ? "customer" : "guest",
|
|
4069
4435
|
session_expires_at: s.expires_at ? Math.floor(new Date(s.expires_at).getTime() / 1e3) : void 0,
|
|
4070
4436
|
session: s
|
|
@@ -5362,88 +5728,10 @@ function createCartService(opts) {
|
|
|
5362
5728
|
};
|
|
5363
5729
|
}
|
|
5364
5730
|
|
|
5365
|
-
// src/mock/domain/
|
|
5366
|
-
function
|
|
5367
|
-
const { registry, clock,
|
|
5731
|
+
// src/mock/domain/payment.ts
|
|
5732
|
+
function createPaymentService(options) {
|
|
5733
|
+
const { registry, clock, bus } = options;
|
|
5368
5734
|
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
5735
|
authorize(body) {
|
|
5448
5736
|
if (!body.payment_id?.trim()) throw validation("payment_id required");
|
|
5449
5737
|
if (!body.authorization) throw validation("authorization required");
|
|
@@ -5454,7 +5742,7 @@ function createCheckoutService(opts) {
|
|
|
5454
5742
|
const updated = {
|
|
5455
5743
|
...order,
|
|
5456
5744
|
payment_state: "paid",
|
|
5457
|
-
status:
|
|
5745
|
+
status: CHECKOUT_ORDER_RESULT_STATUS.CONFIRMED,
|
|
5458
5746
|
updated_at: clock.iso()
|
|
5459
5747
|
};
|
|
5460
5748
|
registry.orders.put(order.id, updated);
|
|
@@ -5465,10 +5753,544 @@ function createCheckoutService(opts) {
|
|
|
5465
5753
|
order_number: order.user_friendly_id,
|
|
5466
5754
|
payment_id: body.payment_id,
|
|
5467
5755
|
payment_reference: order.payment_reference,
|
|
5468
|
-
payment_status:
|
|
5756
|
+
payment_status: LEGACY_CHECKOUT_PAYMENT_STATUS.SUCCEEDED,
|
|
5469
5757
|
requires_authorization: false,
|
|
5470
|
-
next_action: { type:
|
|
5758
|
+
next_action: { type: CHECKOUT_NEXT_ACTION.NONE }
|
|
5759
|
+
};
|
|
5760
|
+
}
|
|
5761
|
+
};
|
|
5762
|
+
}
|
|
5763
|
+
|
|
5764
|
+
// src/mock/domain/purchase-intent.ts
|
|
5765
|
+
var INTENT_LIFETIME_MS = 15 * 60 * 1e3;
|
|
5766
|
+
var ZERO_MONEY = "0.00";
|
|
5767
|
+
var MOCK_PROTECTION = {
|
|
5768
|
+
status: CHECKOUT_PROTECTION_STATUS.PROTECTED,
|
|
5769
|
+
message: "Covered by Cimplify Protection"
|
|
5770
|
+
};
|
|
5771
|
+
var PURCHASE_INTENT_MOBILE_MONEY_NETWORKS = new Set(
|
|
5772
|
+
Object.values(PURCHASE_INTENT_MOBILE_MONEY_NETWORK)
|
|
5773
|
+
);
|
|
5774
|
+
var MOCK_PURCHASE_INTENT = {
|
|
5775
|
+
OWNER_KIND: { ACCOUNT: "account", STOREFRONT_SESSION: "storefront_session" },
|
|
5776
|
+
CART_STATUS: { ACTIVE: "active", CONVERTED: "converted" },
|
|
5777
|
+
ORDER_STATUS: { PENDING: "pending", CONFIRMED: "confirmed" },
|
|
5778
|
+
PAYMENT_STATE: { NOT_PAID: "not_paid", PAID: "paid" },
|
|
5779
|
+
EVENT: {
|
|
5780
|
+
ORDER_CREATED: "order.created",
|
|
5781
|
+
PAYMENT_CAPTURED: "order.payment.captured",
|
|
5782
|
+
ORDER_CONFIRMED: "order.confirmed"
|
|
5783
|
+
},
|
|
5784
|
+
ID_PREFIX: { INTENT: "pi", ATTEMPT: "attempt" },
|
|
5785
|
+
DEFAULT_LOCATION_ID: "mock-location",
|
|
5786
|
+
MOCK_PAYSTACK_PUBLIC_KEY: "pk_test_mock_paystack",
|
|
5787
|
+
COMPLIANCE: {
|
|
5788
|
+
POLICY_NAME: "mock-storefront-commerce"
|
|
5789
|
+
}
|
|
5790
|
+
};
|
|
5791
|
+
var DECIMAL_WIRE_VALUE = /^([+-]?)(\d+)(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
|
|
5792
|
+
function isExactlyZero(value) {
|
|
5793
|
+
if (typeof value === "number") return Object.is(value, 0) || Object.is(value, -0);
|
|
5794
|
+
const match2 = DECIMAL_WIRE_VALUE.exec(value.trim());
|
|
5795
|
+
return Boolean(match2 && [...match2[2], ...match2[3] ?? ""].every((digit) => digit === "0"));
|
|
5796
|
+
}
|
|
5797
|
+
function sameDecimal(left, right) {
|
|
5798
|
+
const canonical = (value) => {
|
|
5799
|
+
const wire = typeof value === "number" ? String(value) : value.trim();
|
|
5800
|
+
const match2 = DECIMAL_WIRE_VALUE.exec(wire);
|
|
5801
|
+
if (!match2) return null;
|
|
5802
|
+
let digits = `${match2[2]}${match2[3] ?? ""}`.replace(/^0+/, "");
|
|
5803
|
+
if (!digits) return "0";
|
|
5804
|
+
let scale = BigInt((match2[3] ?? "").length) - BigInt(match2[4] ?? "0");
|
|
5805
|
+
while (digits.endsWith("0")) {
|
|
5806
|
+
digits = digits.slice(0, -1);
|
|
5807
|
+
scale -= 1n;
|
|
5808
|
+
}
|
|
5809
|
+
const sign = match2[1] === "-" ? "-" : "";
|
|
5810
|
+
return `${sign}${digits}:${scale}`;
|
|
5811
|
+
};
|
|
5812
|
+
const normalizedLeft = canonical(left);
|
|
5813
|
+
return normalizedLeft !== null && normalizedLeft === canonical(right);
|
|
5814
|
+
}
|
|
5815
|
+
function wireMoney(value) {
|
|
5816
|
+
return typeof value === "string" ? value.trim() : String(value);
|
|
5817
|
+
}
|
|
5818
|
+
function decimal(value) {
|
|
5819
|
+
return wireMoney(value.toFixed(2));
|
|
5820
|
+
}
|
|
5821
|
+
function paymentOptions(intentId, currency, amount, expiresAt) {
|
|
5822
|
+
const normalizedCurrency = currencyCode(currency);
|
|
5823
|
+
const normalizedAmount = wireMoney(amount);
|
|
5824
|
+
return [
|
|
5825
|
+
{
|
|
5826
|
+
id: `${intentId}:${PURCHASE_INTENT_PAYMENT_METHOD.CARD}`,
|
|
5827
|
+
rank: 0,
|
|
5828
|
+
method_kind: PURCHASE_INTENT_PAYMENT_METHOD.CARD,
|
|
5829
|
+
collection_mode: PAYMENT_COLLECTION_MODE.CREDENTIAL_CHARGE,
|
|
5830
|
+
provider: PURCHASE_INTENT_PAYMENT_PROVIDER.PAYSTACK,
|
|
5831
|
+
principal_amount: normalizedAmount,
|
|
5832
|
+
fee_amount: wireMoney(ZERO_MONEY),
|
|
5833
|
+
customer_debit_amount: normalizedAmount,
|
|
5834
|
+
currency: normalizedCurrency,
|
|
5835
|
+
protection: MOCK_PROTECTION,
|
|
5836
|
+
status: PAYMENT_OPTION_STATUS.ELIGIBLE,
|
|
5837
|
+
expected_next_action: PAYMENT_OPTION_NEXT_ACTION.PROVIDER_APPROVAL,
|
|
5838
|
+
expires_at: expiresAt
|
|
5839
|
+
},
|
|
5840
|
+
{
|
|
5841
|
+
id: `${intentId}:${PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY}`,
|
|
5842
|
+
rank: 1,
|
|
5843
|
+
method_kind: PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY,
|
|
5844
|
+
collection_mode: PAYMENT_COLLECTION_MODE.REQUEST_TO_PAY,
|
|
5845
|
+
provider: PURCHASE_INTENT_PAYMENT_PROVIDER.PAYSTACK,
|
|
5846
|
+
principal_amount: normalizedAmount,
|
|
5847
|
+
fee_amount: wireMoney(ZERO_MONEY),
|
|
5848
|
+
customer_debit_amount: normalizedAmount,
|
|
5849
|
+
currency: normalizedCurrency,
|
|
5850
|
+
protection: MOCK_PROTECTION,
|
|
5851
|
+
status: PAYMENT_OPTION_STATUS.ELIGIBLE,
|
|
5852
|
+
expected_next_action: PAYMENT_OPTION_NEXT_ACTION.PROVIDER_APPROVAL,
|
|
5853
|
+
expires_at: expiresAt
|
|
5854
|
+
}
|
|
5855
|
+
];
|
|
5856
|
+
}
|
|
5857
|
+
function termsForCart(input) {
|
|
5858
|
+
const total = wireMoney(input.total);
|
|
5859
|
+
return {
|
|
5860
|
+
id: `${input.intentId}:terms:${input.version}`,
|
|
5861
|
+
intent_revision: input.revision,
|
|
5862
|
+
terms_version: input.version,
|
|
5863
|
+
terms_digest: `mock:${input.intentId}:${input.revision}:${input.version}`,
|
|
5864
|
+
money: {
|
|
5865
|
+
currency: currencyCode(input.currency),
|
|
5866
|
+
subtotal: wireMoney(input.subtotal),
|
|
5867
|
+
discount_total: wireMoney(input.discount),
|
|
5868
|
+
tax_total: wireMoney(input.tax),
|
|
5869
|
+
delivery_total: wireMoney(input.delivery),
|
|
5870
|
+
statutory_total: wireMoney(ZERO_MONEY),
|
|
5871
|
+
total_obligation: total,
|
|
5872
|
+
due_now: total,
|
|
5873
|
+
rail_amount: total,
|
|
5874
|
+
store_credit_consumed: wireMoney(ZERO_MONEY),
|
|
5875
|
+
voucher_credit_consumed: wireMoney(ZERO_MONEY)
|
|
5876
|
+
},
|
|
5877
|
+
material: {
|
|
5878
|
+
line_digest: `mock-lines:${input.intentId}`,
|
|
5879
|
+
destination_digest: `mock-destination:${input.intentId}`,
|
|
5880
|
+
delivery_promise_digest: `mock-delivery:${input.intentId}`,
|
|
5881
|
+
entitlement_digest: `mock-entitlement:${input.intentId}`,
|
|
5882
|
+
cancellation_terms_digest: `mock-cancellation:${input.intentId}`
|
|
5883
|
+
},
|
|
5884
|
+
compliance: {
|
|
5885
|
+
policy_name: MOCK_PURCHASE_INTENT.COMPLIANCE.POLICY_NAME,
|
|
5886
|
+
policy_version: 1,
|
|
5887
|
+
lane: CHECKOUT_COMPLIANCE_LANE.NATIVE,
|
|
5888
|
+
reason_code: CHECKOUT_COMPLIANCE_REASON.PHYSICAL_GOODS_NATIVE,
|
|
5889
|
+
evidence_digest: `mock-compliance:${input.intentId}`
|
|
5890
|
+
},
|
|
5891
|
+
payment_options: isExactlyZero(input.total) ? [] : paymentOptions(input.intentId, input.currency, input.total, input.validUntil),
|
|
5892
|
+
valid_until: input.validUntil,
|
|
5893
|
+
created_at: input.now
|
|
5894
|
+
};
|
|
5895
|
+
}
|
|
5896
|
+
function intentView(intent) {
|
|
5897
|
+
const {
|
|
5898
|
+
intent_owner: _owner,
|
|
5899
|
+
mint_request: _request,
|
|
5900
|
+
last_confirmation: _confirmation,
|
|
5901
|
+
...view
|
|
5902
|
+
} = intent;
|
|
5903
|
+
return view;
|
|
5904
|
+
}
|
|
5905
|
+
function purchasingPrincipal(session) {
|
|
5906
|
+
if (!session.is_authenticated) {
|
|
5907
|
+
return { kind: PURCHASING_PRINCIPAL_KIND.GUEST };
|
|
5908
|
+
}
|
|
5909
|
+
if (!session.account_id) throw validation("Authenticated mock session has no account authority");
|
|
5910
|
+
return {
|
|
5911
|
+
kind: PURCHASING_PRINCIPAL_KIND.ACCOUNT,
|
|
5912
|
+
account_id: session.account_id
|
|
5913
|
+
};
|
|
5914
|
+
}
|
|
5915
|
+
function assertSupportedTenderPreference(request) {
|
|
5916
|
+
if (request.source.kind !== PURCHASE_INTENT_SOURCE_KIND.CART) return;
|
|
5917
|
+
const checkout = request.checkout;
|
|
5918
|
+
if (!checkout) throw validation("Cart checkout input is required");
|
|
5919
|
+
const preference = checkout.tender_preference;
|
|
5920
|
+
if (preference?.method_kind !== PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY || preference.authority.authority_kind !== MOBILE_MONEY_TENDER_AUTHORITY_KIND.TRANSIENT) {
|
|
5921
|
+
return;
|
|
5922
|
+
}
|
|
5923
|
+
if (!PURCHASE_INTENT_MOBILE_MONEY_NETWORKS.has(preference.authority.network)) {
|
|
5924
|
+
throw validation("Mobile Money network is not available for PurchaseIntent checkout");
|
|
5925
|
+
}
|
|
5926
|
+
}
|
|
5927
|
+
function intentOwner(session) {
|
|
5928
|
+
if (!session.is_authenticated) {
|
|
5929
|
+
return { kind: MOCK_PURCHASE_INTENT.OWNER_KIND.STOREFRONT_SESSION, id: session.id };
|
|
5930
|
+
}
|
|
5931
|
+
if (!session.account_id) throw validation("Authenticated mock session has no account authority");
|
|
5932
|
+
return { kind: MOCK_PURCHASE_INTENT.OWNER_KIND.ACCOUNT, id: session.account_id };
|
|
5933
|
+
}
|
|
5934
|
+
function createPurchaseIntentMockService(options) {
|
|
5935
|
+
const { registry, clock, ids, bus } = options;
|
|
5936
|
+
function stored(session, intentId) {
|
|
5937
|
+
const intent = registry.purchaseIntents.get(intentId);
|
|
5938
|
+
if (!intent) throw notFound(`Purchase intent ${intentId} not found`);
|
|
5939
|
+
const owner = intentOwner(session);
|
|
5940
|
+
if (intent.intent_owner.kind !== owner.kind || intent.intent_owner.id !== owner.id) {
|
|
5941
|
+
throw notFound(`Purchase intent ${intentId} not found`);
|
|
5942
|
+
}
|
|
5943
|
+
return intent;
|
|
5944
|
+
}
|
|
5945
|
+
function completeProviderOrder(intent, order, attemptId) {
|
|
5946
|
+
const updated = {
|
|
5947
|
+
...order,
|
|
5948
|
+
payment_state: MOCK_PURCHASE_INTENT.PAYMENT_STATE.PAID,
|
|
5949
|
+
status: MOCK_PURCHASE_INTENT.ORDER_STATUS.CONFIRMED,
|
|
5950
|
+
updated_at: clock.iso()
|
|
5951
|
+
};
|
|
5952
|
+
registry.orders.put(order.id, updated);
|
|
5953
|
+
bus.emit(
|
|
5954
|
+
MOCK_PURCHASE_INTENT.EVENT.PAYMENT_CAPTURED,
|
|
5955
|
+
{ order_id: order.id, reference: order.payment_reference },
|
|
5956
|
+
order.business_id
|
|
5957
|
+
);
|
|
5958
|
+
bus.emit(MOCK_PURCHASE_INTENT.EVENT.ORDER_CONFIRMED, { order_id: order.id }, order.business_id);
|
|
5959
|
+
const completed = {
|
|
5960
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED,
|
|
5961
|
+
intent_id: intent.id,
|
|
5962
|
+
attempt_id: attemptId,
|
|
5963
|
+
order_id: order.id,
|
|
5964
|
+
order_number: order.user_friendly_id,
|
|
5965
|
+
payment_id: order.payment_id
|
|
5966
|
+
};
|
|
5967
|
+
registry.purchaseIntents.put(intent.id, {
|
|
5968
|
+
...intent,
|
|
5969
|
+
updated_at: clock.iso(),
|
|
5970
|
+
last_confirmation: completed
|
|
5971
|
+
});
|
|
5972
|
+
return completed;
|
|
5973
|
+
}
|
|
5974
|
+
return {
|
|
5975
|
+
mint(session, request) {
|
|
5976
|
+
if (!request.client_intent_key.trim()) throw validation("client_intent_key required");
|
|
5977
|
+
if (request.source.kind !== PURCHASE_INTENT_SOURCE_KIND.CART) {
|
|
5978
|
+
throw validation("The mock currently prepares cart purchase intents only");
|
|
5979
|
+
}
|
|
5980
|
+
const checkoutInput = request.checkout;
|
|
5981
|
+
if (!checkoutInput) throw validation("Cart checkout input is required");
|
|
5982
|
+
assertSupportedTenderPreference(request);
|
|
5983
|
+
const cart = registry.carts.get(request.source.cart_id);
|
|
5984
|
+
if (!cart) throw notFound(`Cart ${request.source.cart_id} not found`);
|
|
5985
|
+
if (cart.items.length === 0) {
|
|
5986
|
+
throw validation("Cart is empty", { code: ErrorCode.CART_EMPTY });
|
|
5987
|
+
}
|
|
5988
|
+
const principal = purchasingPrincipal(session);
|
|
5989
|
+
const owner = intentOwner(session);
|
|
5990
|
+
const existing = registry.purchaseIntents.list(
|
|
5991
|
+
(candidate) => candidate.mint_request.client_intent_key === request.client_intent_key && candidate.intent_owner.kind === owner.kind && candidate.intent_owner.id === owner.id
|
|
5992
|
+
)[0];
|
|
5993
|
+
if (existing) return intentView(existing);
|
|
5994
|
+
const now = clock.iso();
|
|
5995
|
+
const expiresAt = new Date(clock.nowMs() + INTENT_LIFETIME_MS).toISOString();
|
|
5996
|
+
const intentId = ids.raw(MOCK_PURCHASE_INTENT.ID_PREFIX.INTENT);
|
|
5997
|
+
const terms = termsForCart({
|
|
5998
|
+
intentId,
|
|
5999
|
+
revision: 1,
|
|
6000
|
+
version: 1,
|
|
6001
|
+
currency: cart.currency,
|
|
6002
|
+
subtotal: cart.subtotal,
|
|
6003
|
+
discount: cart.total_discounts,
|
|
6004
|
+
tax: cart.tax_amount,
|
|
6005
|
+
delivery: cart.delivery_fee,
|
|
6006
|
+
total: cart.total_price,
|
|
6007
|
+
now,
|
|
6008
|
+
validUntil: expiresAt
|
|
6009
|
+
});
|
|
6010
|
+
const intent = {
|
|
6011
|
+
id: intentId,
|
|
6012
|
+
seller_business_id: cart.business_id,
|
|
6013
|
+
principal,
|
|
6014
|
+
revision: 1,
|
|
6015
|
+
status: PURCHASE_INTENT_STATUS.OPEN,
|
|
6016
|
+
source: {
|
|
6017
|
+
kind: PURCHASE_INTENT_SOURCE_KIND.CART,
|
|
6018
|
+
source_id: cart.id,
|
|
6019
|
+
source_version: cart.updated_at,
|
|
6020
|
+
seller_business_id: cart.business_id,
|
|
6021
|
+
subject: {
|
|
6022
|
+
kind: PURCHASING_PRINCIPAL_KIND.BUSINESS,
|
|
6023
|
+
business_id: cart.business_id
|
|
6024
|
+
},
|
|
6025
|
+
binding_digest: `mock-cart:${cart.id}:${cart.updated_at}`
|
|
6026
|
+
},
|
|
6027
|
+
lines: cart.items.map((line, ordinal) => ({
|
|
6028
|
+
id: line.id,
|
|
6029
|
+
ordinal,
|
|
6030
|
+
sellable: {
|
|
6031
|
+
kind: line.variant_id ? PURCHASE_INTENT_SELLABLE_KIND.VARIANT : PURCHASE_INTENT_SELLABLE_KIND.PRODUCT,
|
|
6032
|
+
product_id: line.item_id,
|
|
6033
|
+
variant_id: line.variant_id,
|
|
6034
|
+
location_id: checkoutInput.location_id || MOCK_PURCHASE_INTENT.DEFAULT_LOCATION_ID
|
|
6035
|
+
},
|
|
6036
|
+
quantity: line.quantity,
|
|
6037
|
+
configuration: {
|
|
6038
|
+
kind: PURCHASE_INTENT_LINE_CONFIGURATION_KIND.SIMPLE,
|
|
6039
|
+
variant_id: line.variant_id,
|
|
6040
|
+
customer_inputs: line.customer_inputs
|
|
6041
|
+
}
|
|
6042
|
+
})),
|
|
6043
|
+
line_pricing: cart.items.map((line) => {
|
|
6044
|
+
const unitPrice = Number(line.price) + Number(line.add_ons_price);
|
|
6045
|
+
const lineSubtotal = unitPrice * line.quantity - Number(line.item_discount_amount);
|
|
6046
|
+
return {
|
|
6047
|
+
intent_line_id: line.id,
|
|
6048
|
+
quantity: line.quantity,
|
|
6049
|
+
unit_price: decimal(unitPrice),
|
|
6050
|
+
line_subtotal: decimal(lineSubtotal),
|
|
6051
|
+
currency: currencyCode(cart.currency)
|
|
6052
|
+
};
|
|
6053
|
+
}),
|
|
6054
|
+
current_terms: terms,
|
|
6055
|
+
expires_at: expiresAt,
|
|
6056
|
+
created_at: now,
|
|
6057
|
+
updated_at: now,
|
|
6058
|
+
intent_owner: owner,
|
|
6059
|
+
mint_request: request
|
|
6060
|
+
};
|
|
6061
|
+
registry.purchaseIntents.put(intentId, intent);
|
|
6062
|
+
return intentView(intent);
|
|
6063
|
+
},
|
|
6064
|
+
get(session, intentId) {
|
|
6065
|
+
return intentView(stored(session, intentId));
|
|
6066
|
+
},
|
|
6067
|
+
refresh(session, intentId, expectedRevision) {
|
|
6068
|
+
const intent = stored(session, intentId);
|
|
6069
|
+
if (intent.revision !== expectedRevision) {
|
|
6070
|
+
throw validation("expected_intent_revision does not match current intent revision");
|
|
6071
|
+
}
|
|
6072
|
+
if (!intent.current_terms) throw validation("Purchase intent has no current terms");
|
|
6073
|
+
const previous = intent.current_terms;
|
|
6074
|
+
const nextDelivery = Number(previous.money.delivery_total) + 1;
|
|
6075
|
+
const nextTotal = Number(previous.money.total_obligation) + 1;
|
|
6076
|
+
const now = clock.iso();
|
|
6077
|
+
const replacement = termsForCart({
|
|
6078
|
+
intentId,
|
|
6079
|
+
revision: intent.revision,
|
|
6080
|
+
version: previous.terms_version + 1,
|
|
6081
|
+
currency: previous.money.currency,
|
|
6082
|
+
subtotal: String(previous.money.subtotal),
|
|
6083
|
+
discount: String(previous.money.discount_total),
|
|
6084
|
+
tax: String(previous.money.tax_total),
|
|
6085
|
+
delivery: nextDelivery.toFixed(2),
|
|
6086
|
+
total: nextTotal.toFixed(2),
|
|
6087
|
+
now,
|
|
6088
|
+
validUntil: intent.expires_at
|
|
6089
|
+
});
|
|
6090
|
+
const updated = { ...intent, current_terms: replacement, updated_at: now };
|
|
6091
|
+
registry.purchaseIntents.put(intentId, updated);
|
|
6092
|
+
return intentView(updated);
|
|
6093
|
+
},
|
|
6094
|
+
confirm(session, intentId, request) {
|
|
6095
|
+
const intent = stored(session, intentId);
|
|
6096
|
+
if (intent.status === PURCHASE_INTENT_STATUS.CONVERTED && intent.last_confirmation) {
|
|
6097
|
+
const orderId2 = "order_id" in intent.last_confirmation ? intent.last_confirmation.order_id : void 0;
|
|
6098
|
+
const order2 = orderId2 ? registry.orders.get(orderId2) : void 0;
|
|
6099
|
+
if (order2?.payment_state === MOCK_PURCHASE_INTENT.PAYMENT_STATE.PAID) {
|
|
6100
|
+
return {
|
|
6101
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED,
|
|
6102
|
+
intent_id: intent.id,
|
|
6103
|
+
attempt_id: "attempt_id" in intent.last_confirmation ? intent.last_confirmation.attempt_id : ids.raw(MOCK_PURCHASE_INTENT.ID_PREFIX.ATTEMPT),
|
|
6104
|
+
order_id: order2.id
|
|
6105
|
+
};
|
|
6106
|
+
}
|
|
6107
|
+
if (order2?.payment_id && intent.last_confirmation.status === PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED) {
|
|
6108
|
+
return completeProviderOrder(intent, order2, intent.last_confirmation.attempt_id);
|
|
6109
|
+
}
|
|
6110
|
+
return intent.last_confirmation;
|
|
6111
|
+
}
|
|
6112
|
+
const terms = intent.current_terms;
|
|
6113
|
+
if (!terms) throw validation("Purchase intent has no current terms");
|
|
6114
|
+
const zeroRail = isExactlyZero(terms.money.rail_amount);
|
|
6115
|
+
const option = request.payment_option_id ? terms.payment_options.find(
|
|
6116
|
+
(candidate) => candidate.id === request.payment_option_id && candidate.status === PAYMENT_OPTION_STATUS.ELIGIBLE
|
|
6117
|
+
) : void 0;
|
|
6118
|
+
const acceptedBaseTermsChanged = !sameDecimal(request.accepted_due_now, terms.money.due_now) || request.currency !== terms.money.currency;
|
|
6119
|
+
if (request.accepted_intent_revision !== intent.revision || request.accepted_terms_version !== terms.terms_version || acceptedBaseTermsChanged) {
|
|
6120
|
+
const deltas = acceptedBaseTermsChanged ? [
|
|
6121
|
+
{
|
|
6122
|
+
kind: CHECKOUT_TERMS_DELTA_KIND.MONEY,
|
|
6123
|
+
component: CHECKOUT_TERMS_COMPONENT.DUE_NOW,
|
|
6124
|
+
accepted: request.accepted_due_now,
|
|
6125
|
+
replacement: terms.money.due_now
|
|
6126
|
+
}
|
|
6127
|
+
] : [
|
|
6128
|
+
{
|
|
6129
|
+
kind: CHECKOUT_TERMS_DELTA_KIND.PAYMENT_OPTION,
|
|
6130
|
+
accepted_option_id: request.payment_option_id ?? null,
|
|
6131
|
+
accepted_customer_debit_amount: request.accepted_customer_debit_amount,
|
|
6132
|
+
replacement_option_id: option?.id ?? null,
|
|
6133
|
+
replacement_customer_debit_amount: option?.customer_debit_amount ?? null
|
|
6134
|
+
}
|
|
6135
|
+
];
|
|
6136
|
+
return {
|
|
6137
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED,
|
|
6138
|
+
intent_id: intent.id,
|
|
6139
|
+
replacement: terms,
|
|
6140
|
+
deltas
|
|
6141
|
+
};
|
|
6142
|
+
}
|
|
6143
|
+
if (!zeroRail && !option || zeroRail && request.payment_option_id != null) {
|
|
6144
|
+
return {
|
|
6145
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE,
|
|
6146
|
+
intent_id: intent.id,
|
|
6147
|
+
lines: intent.lines.map((line) => ({
|
|
6148
|
+
line_id: line.id,
|
|
6149
|
+
reason: CHECKOUT_INVALIDATION_REASON.PAYMENT_OPTION_CHANGED
|
|
6150
|
+
}))
|
|
6151
|
+
};
|
|
6152
|
+
}
|
|
6153
|
+
const acceptedCustomerDebitMatches = zeroRail ? isExactlyZero(request.accepted_customer_debit_amount) : Boolean(
|
|
6154
|
+
option && sameDecimal(request.accepted_customer_debit_amount, option.customer_debit_amount)
|
|
6155
|
+
);
|
|
6156
|
+
if (!acceptedCustomerDebitMatches) {
|
|
6157
|
+
return {
|
|
6158
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED,
|
|
6159
|
+
intent_id: intent.id,
|
|
6160
|
+
replacement: terms,
|
|
6161
|
+
deltas: [
|
|
6162
|
+
{
|
|
6163
|
+
kind: CHECKOUT_TERMS_DELTA_KIND.PAYMENT_OPTION,
|
|
6164
|
+
accepted_option_id: request.payment_option_id ?? null,
|
|
6165
|
+
accepted_customer_debit_amount: request.accepted_customer_debit_amount,
|
|
6166
|
+
replacement_option_id: option?.id ?? null,
|
|
6167
|
+
replacement_customer_debit_amount: option?.customer_debit_amount ?? null
|
|
6168
|
+
}
|
|
6169
|
+
]
|
|
6170
|
+
};
|
|
6171
|
+
}
|
|
6172
|
+
if (intent.mint_request.source.kind !== PURCHASE_INTENT_SOURCE_KIND.CART) {
|
|
6173
|
+
throw validation("The mock currently confirms cart purchase intents only");
|
|
6174
|
+
}
|
|
6175
|
+
const checkoutInput = intent.mint_request.checkout;
|
|
6176
|
+
if (!checkoutInput) throw validation("Cart checkout input is required");
|
|
6177
|
+
const cart = registry.carts.get(intent.mint_request.source.cart_id);
|
|
6178
|
+
if (!cart || cart.status !== MOCK_PURCHASE_INTENT.CART_STATUS.ACTIVE) {
|
|
6179
|
+
return { status: PURCHASE_INTENT_CONFIRM_STATUS.SOURCE_UNAVAILABLE, intent_id: intent.id };
|
|
6180
|
+
}
|
|
6181
|
+
const attemptId = ids.raw(MOCK_PURCHASE_INTENT.ID_PREFIX.ATTEMPT);
|
|
6182
|
+
const orderId = ids.order();
|
|
6183
|
+
const orderNumber = ids.orderNumber();
|
|
6184
|
+
const paymentId = zeroRail ? void 0 : ids.payment();
|
|
6185
|
+
const paymentReference = zeroRail ? void 0 : ids.payment();
|
|
6186
|
+
const needsProvider = option?.method_kind === PURCHASE_INTENT_PAYMENT_METHOD.CARD || option?.method_kind === PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY;
|
|
6187
|
+
const paid = zeroRail;
|
|
6188
|
+
const order = {
|
|
6189
|
+
id: orderId,
|
|
6190
|
+
business_id: cart.business_id,
|
|
6191
|
+
user_friendly_id: orderNumber,
|
|
6192
|
+
channel: cart.channel,
|
|
6193
|
+
status: paid ? MOCK_PURCHASE_INTENT.ORDER_STATUS.CONFIRMED : MOCK_PURCHASE_INTENT.ORDER_STATUS.PENDING,
|
|
6194
|
+
payment_state: paid ? MOCK_PURCHASE_INTENT.PAYMENT_STATE.PAID : MOCK_PURCHASE_INTENT.PAYMENT_STATE.NOT_PAID,
|
|
6195
|
+
order_type: checkoutInput.order_type,
|
|
6196
|
+
customer_id: session.customer_id,
|
|
6197
|
+
customer_name: checkoutInput.customer.name,
|
|
6198
|
+
customer_email: checkoutInput.customer.email,
|
|
6199
|
+
customer_phone: checkoutInput.customer.phone,
|
|
6200
|
+
delivery_address: checkoutInput.address_info.street_address,
|
|
6201
|
+
delivery_fee: cart.delivery_fee,
|
|
6202
|
+
subtotal: cart.subtotal,
|
|
6203
|
+
tax_amount: cart.tax_amount,
|
|
6204
|
+
service_charge: cart.service_charge,
|
|
6205
|
+
total_discounts: cart.total_discounts,
|
|
6206
|
+
total_price: cart.total_price,
|
|
6207
|
+
currency: cart.currency,
|
|
6208
|
+
items: cart.items,
|
|
6209
|
+
applied_discount_ids: cart.applied_discount_ids,
|
|
6210
|
+
applied_discount_codes: cart.applied_discount_codes,
|
|
6211
|
+
payment_id: paymentId,
|
|
6212
|
+
payment_reference: paymentReference,
|
|
6213
|
+
metadata: checkoutInput.metadata,
|
|
6214
|
+
created_at: clock.iso(),
|
|
6215
|
+
updated_at: clock.iso()
|
|
5471
6216
|
};
|
|
6217
|
+
registry.orders.put(orderId, order);
|
|
6218
|
+
registry.carts.put(cart.id, {
|
|
6219
|
+
...cart,
|
|
6220
|
+
status: MOCK_PURCHASE_INTENT.CART_STATUS.CONVERTED,
|
|
6221
|
+
updated_at: clock.iso()
|
|
6222
|
+
});
|
|
6223
|
+
bus.emit(
|
|
6224
|
+
MOCK_PURCHASE_INTENT.EVENT.ORDER_CREATED,
|
|
6225
|
+
{ order_id: orderId, order_number: orderNumber },
|
|
6226
|
+
cart.business_id
|
|
6227
|
+
);
|
|
6228
|
+
if (paid) {
|
|
6229
|
+
if (paymentReference) {
|
|
6230
|
+
bus.emit(
|
|
6231
|
+
MOCK_PURCHASE_INTENT.EVENT.PAYMENT_CAPTURED,
|
|
6232
|
+
{ order_id: orderId, reference: paymentReference },
|
|
6233
|
+
cart.business_id
|
|
6234
|
+
);
|
|
6235
|
+
}
|
|
6236
|
+
bus.emit(
|
|
6237
|
+
MOCK_PURCHASE_INTENT.EVENT.ORDER_CONFIRMED,
|
|
6238
|
+
{ order_id: orderId },
|
|
6239
|
+
cart.business_id
|
|
6240
|
+
);
|
|
6241
|
+
}
|
|
6242
|
+
let confirmation;
|
|
6243
|
+
if (option?.method_kind === PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY) {
|
|
6244
|
+
confirmation = {
|
|
6245
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED,
|
|
6246
|
+
intent_id: intent.id,
|
|
6247
|
+
attempt_id: attemptId,
|
|
6248
|
+
order_id: orderId,
|
|
6249
|
+
authorization_type: AUTHORIZATION_TYPE.OTP,
|
|
6250
|
+
display_text: "Approve on your mobile money app"
|
|
6251
|
+
};
|
|
6252
|
+
} else if (option?.method_kind === PURCHASE_INTENT_PAYMENT_METHOD.CARD) {
|
|
6253
|
+
confirmation = {
|
|
6254
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED,
|
|
6255
|
+
intent_id: intent.id,
|
|
6256
|
+
attempt_id: attemptId,
|
|
6257
|
+
order_id: orderId,
|
|
6258
|
+
provider: PURCHASE_INTENT_PAYMENT_PROVIDER.PAYSTACK,
|
|
6259
|
+
client_secret: `access_${paymentReference}`,
|
|
6260
|
+
public_key: MOCK_PURCHASE_INTENT.MOCK_PAYSTACK_PUBLIC_KEY
|
|
6261
|
+
};
|
|
6262
|
+
} else {
|
|
6263
|
+
confirmation = {
|
|
6264
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED,
|
|
6265
|
+
intent_id: intent.id,
|
|
6266
|
+
attempt_id: attemptId,
|
|
6267
|
+
order_id: orderId
|
|
6268
|
+
};
|
|
6269
|
+
}
|
|
6270
|
+
if (needsProvider && !paymentId) {
|
|
6271
|
+
throw validation("Provider-backed purchase intent has no payment authority");
|
|
6272
|
+
}
|
|
6273
|
+
registry.purchaseIntents.put(intent.id, {
|
|
6274
|
+
...intent,
|
|
6275
|
+
status: PURCHASE_INTENT_STATUS.CONVERTED,
|
|
6276
|
+
converted_order_id: orderId,
|
|
6277
|
+
updated_at: clock.iso(),
|
|
6278
|
+
last_confirmation: confirmation
|
|
6279
|
+
});
|
|
6280
|
+
return confirmation;
|
|
6281
|
+
},
|
|
6282
|
+
submitAction(session, intentId, attemptId, request) {
|
|
6283
|
+
const intent = stored(session, intentId);
|
|
6284
|
+
const previous = intent.last_confirmation;
|
|
6285
|
+
if (!previous || previous.status !== PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED || previous.attempt_id !== attemptId) {
|
|
6286
|
+
throw validation("Purchase-intent attempt is not awaiting authorization");
|
|
6287
|
+
}
|
|
6288
|
+
if (!request.authorization) throw validation("authorization required");
|
|
6289
|
+
const order = registry.orders.get(previous.order_id);
|
|
6290
|
+
if (!order || !order.payment_id) {
|
|
6291
|
+
throw notFound(`Purchase-intent attempt ${attemptId} not found`);
|
|
6292
|
+
}
|
|
6293
|
+
return completeProviderOrder(intent, order, attemptId);
|
|
5472
6294
|
}
|
|
5473
6295
|
};
|
|
5474
6296
|
}
|
|
@@ -10784,7 +11606,7 @@ var ID_PREFIX = {
|
|
|
10784
11606
|
product: "prod_",
|
|
10785
11607
|
service: "svc_"
|
|
10786
11608
|
};
|
|
10787
|
-
var
|
|
11609
|
+
var DEFAULT_CURRENCY2 = "GHS";
|
|
10788
11610
|
function slugify(value) {
|
|
10789
11611
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
10790
11612
|
}
|
|
@@ -10819,7 +11641,7 @@ function makeSeedContext(registry) {
|
|
|
10819
11641
|
const business = {
|
|
10820
11642
|
business_type: "other",
|
|
10821
11643
|
email: `hello@${handle}.test`,
|
|
10822
|
-
default_currency:
|
|
11644
|
+
default_currency: DEFAULT_CURRENCY2,
|
|
10823
11645
|
default_offers_table_service: false,
|
|
10824
11646
|
default_accepts_online_orders: true,
|
|
10825
11647
|
status: "active",
|
|
@@ -10998,7 +11820,8 @@ function createDeps(options = {}) {
|
|
|
10998
11820
|
const inventory = createInventoryService({ registry });
|
|
10999
11821
|
const cart = createCartService({ registry, clock, ids, bus, inventory });
|
|
11000
11822
|
const orders = createOrderService({ registry, clock, bus });
|
|
11001
|
-
const
|
|
11823
|
+
const payments = createPaymentService({ registry, clock, bus });
|
|
11824
|
+
const purchaseIntents = createPurchaseIntentMockService({ registry, clock, ids, bus });
|
|
11002
11825
|
const subscriptions = createSubscriptionService({ registry, clock, bus });
|
|
11003
11826
|
const scheduling = createSchedulingService({ registry, clock, bus });
|
|
11004
11827
|
const fx = createFxService({ registry, clock, ids });
|
|
@@ -11019,7 +11842,8 @@ function createDeps(options = {}) {
|
|
|
11019
11842
|
business,
|
|
11020
11843
|
catalogue,
|
|
11021
11844
|
cart,
|
|
11022
|
-
|
|
11845
|
+
payments,
|
|
11846
|
+
purchaseIntents,
|
|
11023
11847
|
orders,
|
|
11024
11848
|
subscriptions,
|
|
11025
11849
|
scheduling,
|