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