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